A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita audio rust zig deno mpris rockbox mpd
at master 1255 lines 40 kB view raw
1/* Emacs style mode select -*- C++ -*- 2 *----------------------------------------------------------------------------- 3 * 4 * 5 * PrBoom a Doom port merged with LxDoom and LSDLDoom 6 * based on BOOM, a modified and improved DOOM engine 7 * Copyright (C) 1999 by 8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman 9 * Copyright (C) 1999-2000 by 10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze 11 * 12 * This program is free software; you can redistribute it and/or 13 * modify it under the terms of the GNU General Public License 14 * as published by the Free Software Foundation; either version 2 15 * of the License, or (at your option) any later version. 16 * 17 * This program is distributed in the hope that it will be useful, 18 * but WITHOUT ANY WARRANTY; without even the implied warranty of 19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 * GNU General Public License for more details. 21 * 22 * You should have received a copy of the GNU General Public License 23 * along with this program; if not, write to the Free Software 24 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 25 * 02111-1307, USA. 26 * 27 * DESCRIPTION: 28 * Do all the WAD I/O, get map description, 29 * set up initial state and misc. LUTs. 30 * 31 *-----------------------------------------------------------------------------*/ 32 33#include <math.h> 34 35#include "doomstat.h" 36#include "m_bbox.h" 37#include "m_argv.h" 38#include "g_game.h" 39#include "w_wad.h" 40#include "r_main.h" 41#include "r_things.h" 42#include "p_maputl.h" 43#include "p_map.h" 44#include "p_setup.h" 45#include "p_spec.h" 46#include "p_tick.h" 47#include "p_enemy.h" 48#include "s_sound.h" 49#include "i_system.h" 50#include "m_swap.h" 51 52#include "rockmacros.h" 53// 54// MAP related Lookup tables. 55// Store VERTEXES, LINEDEFS, SIDEDEFS, etc. 56// 57 58int numvertexes; 59vertex_t *vertexes; 60 61int numsegs; 62seg_t *segs; 63 64int numsectors; 65sector_t *sectors; 66 67int numsubsectors; 68subsector_t *subsectors; 69 70int numnodes; 71node_t *nodes; 72 73int numlines; 74line_t *lines; 75 76int numsides; 77side_t *sides; 78 79 80//////////////////////////////////////////////////////////////////////////////////////////// 81// figgi 08/21/00 -- constants and globals for glBsp support 82#define gNd2 0x32644E67 // figgi -- suppport for new GL_VERT format v2.0 83#define GL_VERT_OFFSET 4 84 85int firstglvertex = 0; 86boolean usingGLNodes = false; 87boolean forceOldBsp = false; 88 89enum 90{ 91 ML_GL_LABEL=0, // A separator name, GL_ExMx or GL_MAPxx 92 ML_GL_VERTS, // Extra Vertices 93 ML_GL_SEGS, // Segs, from linedefs & minisegs 94 ML_GL_SSECT, // SubSectors, list of segs 95 ML_GL_NODES // GL BSP nodes 96}; 97//////////////////////////////////////////////////////////////////////////////////////////// 98 99 100// BLOCKMAP 101// Created from axis aligned bounding box 102// of the map, a rectangular array of 103// blocks of size ... 104// Used to speed up collision detection 105// by spatial subdivision in 2D. 106// 107// Blockmap size. 108 109int bmapwidth, bmapheight; // size in mapblocks 110 111// killough 3/1/98: remove blockmap limit internally: 112long *blockmap; // was short -- killough 113 114// offsets in blockmap are from here 115long *blockmaplump; // was short -- killough 116 117fixed_t bmaporgx, bmaporgy; // origin of block map 118 119mobj_t **blocklinks; // for thing chains 120 121// 122// REJECT 123// For fast sight rejection. 124// Speeds up enemy AI by skipping detailed 125// LineOf Sight calculation. 126// Without the special effect, this could 127// be used as a PVS lookup as well. 128// 129 130static int rejectlump = -1;// cph - store reject lump num if cached 131const byte *rejectmatrix; // cph - const* 132 133// Maintain single and multi player starting spots. 134 135// 1/11/98 killough: Remove limit on deathmatch starts 136mapthing_t *deathmatchstarts; // killough 137size_t num_deathmatchstarts; // killough 138 139mapthing_t *deathmatch_p; 140mapthing_t playerstarts[MAXPLAYERS]; 141 142// 143// P_LoadVertexes 144// 145// killough 5/3/98: reformatted, cleaned up 146// 147static void P_LoadVertexes (int lump) 148{ 149 const byte *data; // cph - const 150 int i; 151 152 // Determine number of lumps: 153 // total lump length / vertex record length. 154 numvertexes = W_LumpLength(lump) / sizeof(mapvertex_t); 155 156 // Allocate zone memory for buffer. 157 vertexes = Z_Malloc(numvertexes*sizeof(vertex_t),PU_LEVEL,0); 158 159 // Load data into cache. 160 data = W_CacheLumpNum(lump); // cph - wad handling updated 161 162 // Copy and convert vertex coordinates, 163 // internal representation as fixed. 164 for (i=0; i<numvertexes; i++) 165 { 166 vertexes[i].x = SHORT(((mapvertex_t *) data)[i].x)<<FRACBITS; 167 vertexes[i].y = SHORT(((mapvertex_t *) data)[i].y)<<FRACBITS; 168 } 169 170 // Free buffer memory. 171 W_UnlockLumpNum(lump); 172} 173 174// 175// P_LoadSegs 176// 177// killough 5/3/98: reformatted, cleaned up 178 179static void P_LoadSegs (int lump) 180{ 181 int i; 182 const byte *data; // cph - const 183 184 numsegs = W_LumpLength(lump) / sizeof(mapseg_t); 185 segs = Z_Calloc(numsegs,sizeof(seg_t),PU_LEVEL,0); 186 data = W_CacheLumpNum(lump); // cph - wad lump handling updated 187 188 for (i=0; i<numsegs; i++) 189 { 190 seg_t *li = segs+i; 191 mapseg_t *ml = (mapseg_t *) data + i; 192 193 int side, linedef; 194 line_t *ldef; 195 196 li->v1 = &vertexes[SHORT(ml->v1)]; 197 li->v2 = &vertexes[SHORT(ml->v2)]; 198 199 li->miniseg = false; // figgi -- there are no minisegs in classic BSP nodes 200 201 li->angle = (SHORT(ml->angle))<<16; 202 li->offset =(SHORT(ml->offset))<<16; 203 linedef = SHORT(ml->linedef); 204 ldef = &lines[linedef]; 205 li->linedef = ldef; 206 side = SHORT(ml->side); 207 li->sidedef = &sides[ldef->sidenum[side]]; 208 li->frontsector = sides[ldef->sidenum[side]].sector; 209 210 // killough 5/3/98: ignore 2s flag if second sidedef missing: 211 if (ldef->flags & ML_TWOSIDED && ldef->sidenum[side^1]!=-1) 212 li->backsector = sides[ldef->sidenum[side^1]].sector; 213 else 214 li->backsector = 0; 215 } 216 217 W_UnlockLumpNum(lump); // cph - release the data 218} 219 220 221// 222// P_LoadSubsectors 223// 224// killough 5/3/98: reformatted, cleaned up 225 226static void P_LoadSubsectors (int lump) 227{ 228 const byte *data; // cph - const* 229 int i; 230 231 numsubsectors = W_LumpLength (lump) / sizeof(mapsubsector_t); 232 subsectors = Z_Calloc(numsubsectors,sizeof(subsector_t),PU_LEVEL,0); 233 data = W_CacheLumpNum(lump); // cph - wad lump handling updated 234 235 for (i=0; i<numsubsectors; i++) 236 { 237 subsectors[i].numlines = (unsigned short)SHORT(((mapsubsector_t *) data)[i].numsegs ); 238 subsectors[i].firstline = (unsigned short)SHORT(((mapsubsector_t *) data)[i].firstseg); 239 } 240 241 W_UnlockLumpNum(lump); // cph - release the data 242} 243 244// 245// P_LoadSectors 246// 247// killough 5/3/98: reformatted, cleaned up 248 249static void P_LoadSectors (int lump) 250{ 251 const byte *data; // cph - const* 252 int i; 253 254 numsectors = W_LumpLength (lump) / sizeof(mapsector_t); 255 sectors = Z_Calloc (numsectors,sizeof(sector_t),PU_LEVEL,0); 256 data = W_CacheLumpNum (lump); // cph - wad lump handling updated 257 258 for (i=0; i<numsectors; i++) 259 { 260 sector_t *ss = sectors + i; 261 const mapsector_t *ms = (mapsector_t *) data + i; 262 263 ss->floorheight = SHORT(ms->floorheight)<<FRACBITS; 264 ss->ceilingheight = SHORT(ms->ceilingheight)<<FRACBITS; 265 ss->floorpic = R_FlatNumForName(ms->floorpic); 266 ss->ceilingpic = R_FlatNumForName(ms->ceilingpic); 267 ss->lightlevel = SHORT(ms->lightlevel); 268 ss->special = SHORT(ms->special); 269 ss->oldspecial = SHORT(ms->special); 270 ss->tag = SHORT(ms->tag); 271 ss->thinglist = NULL; 272 ss->touching_thinglist = NULL; // phares 3/14/98 273 274 ss->nextsec = -1; //jff 2/26/98 add fields to support locking out 275 ss->prevsec = -1; // stair retriggering until build completes 276 277 // killough 3/7/98: 278 ss->floor_xoffs = 0; 279 ss->floor_yoffs = 0; // floor and ceiling flats offsets 280 ss->ceiling_xoffs = 0; 281 ss->ceiling_yoffs = 0; 282 ss->heightsec = -1; // sector used to get floor and ceiling height 283 ss->floorlightsec = -1; // sector used to get floor lighting 284 // killough 3/7/98: end changes 285 286 // killough 4/11/98 sector used to get ceiling lighting: 287 ss->ceilinglightsec = -1; 288 289 // killough 4/4/98: colormaps: 290 ss->bottommap = ss->midmap = ss->topmap = 0; 291 292 // killough 10/98: sky textures coming from sidedefs: 293 ss->sky = 0; 294 } 295 296 W_UnlockLumpNum(lump); // cph - release the data 297} 298 299 300// 301// P_LoadNodes 302// 303// killough 5/3/98: reformatted, cleaned up 304 305static void P_LoadNodes (int lump) 306{ 307 const byte *data; // cph - const* 308 int i; 309 310 numnodes = W_LumpLength (lump) / sizeof(mapnode_t); 311 nodes = Z_Malloc (numnodes*sizeof(node_t),PU_LEVEL,0); 312 data = W_CacheLumpNum (lump); // cph - wad lump handling updated 313 314 for (i=0; i<numnodes; i++) 315 { 316 node_t *no = nodes + i; 317 mapnode_t *mn = (mapnode_t *) data + i; 318 int j; 319 320 no->x = SHORT(mn->x)<<FRACBITS; 321 no->y = SHORT(mn->y)<<FRACBITS; 322 no->dx = SHORT(mn->dx)<<FRACBITS; 323 no->dy = SHORT(mn->dy)<<FRACBITS; 324 325 for (j=0 ; j<2 ; j++) 326 { 327 int k; 328 no->children[j] = SHORT(mn->children[j]); 329 for (k=0 ; k<4 ; k++) 330 no->bbox[j][k] = SHORT(mn->bbox[j][k])<<FRACBITS; 331 } 332 } 333 334 W_UnlockLumpNum(lump); // cph - release the data 335} 336 337 338// 339// P_LoadThings 340// 341// killough 5/3/98: reformatted, cleaned up 342 343static void P_LoadThings (int lump) 344{ 345 mapthing_t tempthing; // this needed to be added as the SHORT calls were overwriting eachother on reload 346 int i, numthings = W_LumpLength (lump) / sizeof(mapthing_t); 347 const byte *data = W_CacheLumpNum (lump); // cph - wad lump handling updated, const* 348 349 for (i=0; i<numthings; i++) 350 { 351 mapthing_t *mt = (mapthing_t *) data + i; 352 353 // Do not spawn cool, new monsters if !commercial 354 if (gamemode != commercial) 355 switch(mt->type) 356 { 357 case 68: // Arachnotron 358 case 64: // Archvile 359 case 88: // Boss Brain 360 case 89: // Boss Shooter 361 case 69: // Hell Knight 362 case 67: // Mancubus 363 case 71: // Pain Elemental 364 case 65: // Former Human Commando 365 case 66: // Revenant 366 case 84: // Wolf SS 367 continue; 368 } 369 370 // Do spawn all other stuff. 371 tempthing.x = SHORT(mt->x); 372 tempthing.y = SHORT(mt->y); 373 tempthing.angle = SHORT(mt->angle); 374 tempthing.type = SHORT(mt->type); 375 tempthing.options = SHORT(mt->options); 376 377 P_SpawnMapThing (&tempthing); 378 } 379 380 W_UnlockLumpNum(lump); // cph - release the data 381} 382 383// 384// P_LoadLineDefs 385// Also counts secret lines for intermissions. 386// ^^^ 387// ??? killough ??? 388// Does this mean secrets used to be linedef-based, rather than sector-based? 389// 390// killough 4/4/98: split into two functions, to allow sidedef overloading 391// 392// killough 5/3/98: reformatted, cleaned up 393 394static void P_LoadLineDefs (int lump) 395{ 396 const byte *data; // cph - const* 397 int i; 398 399 numlines = W_LumpLength (lump) / sizeof(maplinedef_t); 400 lines = Z_Calloc (numlines,sizeof(line_t),PU_LEVEL,0); 401 data = W_CacheLumpNum (lump); // cph - wad lump handling updated 402 403 for (i=0; i<numlines; i++) 404 { 405 maplinedef_t *mld = (maplinedef_t *) data + i; 406 line_t *ld = lines+i; 407 vertex_t *v1, *v2; 408 409 ld->flags = SHORT(mld->flags); 410 ld->special = SHORT(mld->special); 411 ld->tag = SHORT(mld->tag); 412 v1 = ld->v1 = &vertexes[SHORT(mld->v1)]; 413 v2 = ld->v2 = &vertexes[SHORT(mld->v2)]; 414 ld->dx = v2->x - v1->x; 415 ld->dy = v2->y - v1->y; 416 417 ld->tranlump = -1; // killough 4/11/98: no translucency by default 418 419 ld->slopetype = !ld->dx ? ST_VERTICAL : !ld->dy ? ST_HORIZONTAL : 420 FixedDiv(ld->dy, ld->dx) > 0 ? ST_POSITIVE : ST_NEGATIVE; 421 422 if (v1->x < v2->x) 423 { 424 ld->bbox[BOXLEFT] = v1->x; 425 ld->bbox[BOXRIGHT] = v2->x; 426 } 427 else 428 { 429 ld->bbox[BOXLEFT] = v2->x; 430 ld->bbox[BOXRIGHT] = v1->x; 431 } 432 433 if (v1->y < v2->y) 434 { 435 ld->bbox[BOXBOTTOM] = v1->y; 436 ld->bbox[BOXTOP] = v2->y; 437 } 438 else 439 { 440 ld->bbox[BOXBOTTOM] = v2->y; 441 ld->bbox[BOXTOP] = v1->y; 442 } 443 444 ld->sidenum[0] = SHORT(mld->sidenum[0]); 445 ld->sidenum[1] = SHORT(mld->sidenum[1]); 446 447 // killough 4/4/98: support special sidedef interpretation below 448 if (ld->sidenum[0] != -1 && ld->special) 449 sides[*ld->sidenum].special = ld->special; 450 } 451 452 W_UnlockLumpNum(lump); // cph - release the lump 453} 454 455// killough 4/4/98: delay using sidedefs until they are loaded 456// killough 5/3/98: reformatted, cleaned up 457 458static void P_LoadLineDefs2(int lump) 459{ 460 (void)lump; 461 int i = numlines; 462 register line_t *ld = lines; 463 for (;i--;ld++) 464 { 465 { // cph 2002/07/20 - these errors are fatal if not fixed, so apply them in compatibility mode - a desync is better than a crash! 466 // killough 11/98: fix common wad errors (missing sidedefs): 467 468 if (ld->sidenum[0] == -1) { 469 ld->sidenum[0] = 0; // Substitute dummy sidedef for missing right side 470 // cph - print a warning about the bug 471 printf("P_LoadSegs: linedef %d missing first sidedef\n",numlines-i); 472 } 473 474 if ((ld->sidenum[1] == -1) && (ld->flags & ML_TWOSIDED)) { 475 ld->flags &= ~ML_TWOSIDED; // Clear 2s flag for missing left side 476 // cph - print a warning about the bug 477 printf("P_LoadSegs: linedef %d has two-sided flag set, but no second sidedef\n",numlines-i); 478 } 479 } 480 481 ld->frontsector = ld->sidenum[0]!=-1 ? sides[ld->sidenum[0]].sector : 0; 482 ld->backsector = ld->sidenum[1]!=-1 ? sides[ld->sidenum[1]].sector : 0; 483 switch (ld->special) 484 { // killough 4/11/98: handle special types 485 int lump, j; 486 487 case 260: // killough 4/11/98: translucent 2s textures 488 lump = sides[*ld->sidenum].special; // translucency from sidedef 489 if (!ld->tag) // if tag==0, 490 ld->tranlump = lump; // affect this linedef only 491 else 492 for (j=0;j<numlines;j++) // if tag!=0, 493 if (lines[j].tag == ld->tag) // affect all matching linedefs 494 lines[j].tranlump = lump; 495 break; 496 } 497 } 498} 499 500// 501// P_LoadSideDefs 502// 503// killough 4/4/98: split into two functions 504 505static void P_LoadSideDefs (int lump) 506{ 507 numsides = W_LumpLength(lump) / sizeof(mapsidedef_t); 508 sides = Z_Calloc(numsides,sizeof(side_t),PU_LEVEL,0); 509} 510 511// killough 4/4/98: delay using texture names until 512// after linedefs are loaded, to allow overloading. 513// killough 5/3/98: reformatted, cleaned up 514 515static void P_LoadSideDefs2(int lump) 516{ 517 const byte *data = W_CacheLumpNum(lump); // cph - const*, wad lump handling updated 518 int i; 519 520 for (i=0; i<numsides; i++) 521 { 522 register mapsidedef_t *msd = (mapsidedef_t *) data + i; 523 register side_t *sd = sides + i; 524 register sector_t *sec; 525 526 sd->textureoffset = SHORT(msd->textureoffset)<<FRACBITS; 527 sd->rowoffset = SHORT(msd->rowoffset)<<FRACBITS; 528 529 // killough 4/4/98: allow sidedef texture names to be overloaded 530 // killough 4/11/98: refined to allow colormaps to work as wall 531 // textures if invalid as colormaps but valid as textures. 532 533 sd->sector = sec = &sectors[SHORT(msd->sector)]; 534 switch (sd->special) 535 { 536 case 242: // variable colormap via 242 linedef 537 sd->bottomtexture = 538 (sec->bottommap = R_ColormapNumForName(msd->bottomtexture)) < 0 ? 539 sec->bottommap = 0, R_TextureNumForName(msd->bottomtexture): 0 ; 540 sd->midtexture = 541 (sec->midmap = R_ColormapNumForName(msd->midtexture)) < 0 ? 542 sec->midmap = 0, R_TextureNumForName(msd->midtexture) : 0 ; 543 sd->toptexture = 544 (sec->topmap = R_ColormapNumForName(msd->toptexture)) < 0 ? 545 sec->topmap = 0, R_TextureNumForName(msd->toptexture) : 0 ; 546 break; 547 548 case 260: // killough 4/11/98: apply translucency to 2s normal texture 549 sd->midtexture = strncasecmp("TRANMAP", msd->midtexture, 8) ? 550 (sd->special = W_CheckNumForName(msd->midtexture)) < 0 || 551 W_LumpLength(sd->special) != 65536 ? 552 sd->special=0, R_TextureNumForName(msd->midtexture) : 553 (sd->special++, 0) : (sd->special=0); 554 sd->toptexture = R_TextureNumForName(msd->toptexture); 555 sd->bottomtexture = R_TextureNumForName(msd->bottomtexture); 556 break; 557 558 default: // normal cases 559 sd->midtexture = R_TextureNumForName(msd->midtexture); 560 sd->toptexture = R_TextureNumForName(msd->toptexture); 561 sd->bottomtexture = R_TextureNumForName(msd->bottomtexture); 562 break; 563 } 564 } 565 566 W_UnlockLumpNum(lump); // cph - release the lump 567} 568 569// 570// jff 10/6/98 571// New code added to speed up calculation of internal blockmap 572// Algorithm is order of nlines*(ncols+nrows) not nlines*ncols*nrows 573// 574 575#define blkshift 7 /* places to shift rel position for cell num */ 576#define blkmask ((1<<blkshift)-1)/* mask for rel position within cell */ 577#define blkmargin 0 /* size guardband around map used */ 578// jff 10/8/98 use guardband>0 579// jff 10/12/98 0 ok with + 1 in rows,cols 580 581typedef struct linelist_t // type used to list lines in each block 582{ 583 long num; 584 struct linelist_t *next; 585} linelist_t; 586 587// 588// Subroutine to add a line number to a block list 589// It simply returns if the line is already in the block 590// 591 592static void AddBlockLine 593( 594 linelist_t **lists, 595 int *count, 596 int *done, 597 int blockno, 598 long lineno 599) 600{ 601 linelist_t *l; 602 603 if (done[blockno]) 604 return; 605 606 l = malloc(sizeof(linelist_t)); 607 l->num = lineno; 608 l->next = lists[blockno]; 609 lists[blockno] = l; 610 count[blockno]++; 611 done[blockno] = 1; 612} 613 614// 615// Actually construct the blockmap lump from the level data 616// 617// This finds the intersection of each linedef with the column and 618// row lines at the left and bottom of each blockmap cell. It then 619// adds the line to all block lists touching the intersection. 620// 621 622void P_CreateBlockMap() 623{ 624 int xorg,yorg; // blockmap origin (lower left) 625 int nrows,ncols; // blockmap dimensions 626 linelist_t **blocklists=NULL; // array of pointers to lists of lines 627 int *blockcount=NULL; // array of counters of line lists 628 int *blockdone=NULL; // array keeping track of blocks/line 629 int NBlocks; // number of cells = nrows*ncols 630 long linetotal=0; // total length of all blocklists 631 int i,j; 632 int map_minx=INT_MAX; // init for map limits search 633 int map_miny=INT_MAX; 634 int map_maxx=INT_MIN; 635 int map_maxy=INT_MIN; 636 637 // scan for map limits, which the blockmap must enclose 638 639 for (i=0;i<numvertexes;i++) 640 { 641 fixed_t t; 642 643 if ((t=vertexes[i].x) < map_minx) 644 map_minx = t; 645 else if (t > map_maxx) 646 map_maxx = t; 647 if ((t=vertexes[i].y) < map_miny) 648 map_miny = t; 649 else if (t > map_maxy) 650 map_maxy = t; 651 } 652 map_minx >>= FRACBITS; // work in map coords, not fixed_t 653 map_maxx >>= FRACBITS; 654 map_miny >>= FRACBITS; 655 map_maxy >>= FRACBITS; 656 657 // set up blockmap area to enclose level plus margin 658 659 xorg = map_minx-blkmargin; 660 yorg = map_miny-blkmargin; 661 ncols = (map_maxx+blkmargin-xorg+1+blkmask)>>blkshift; //jff 10/12/98 662 nrows = (map_maxy+blkmargin-yorg+1+blkmask)>>blkshift; //+1 needed for 663 NBlocks = ncols*nrows; //map exactly 1 cell 664 665 // create the array of pointers on NBlocks to blocklists 666 // also create an array of linelist counts on NBlocks 667 // finally make an array in which we can mark blocks done per line 668 669 // CPhipps - calloc's 670 blocklists = calloc(NBlocks,sizeof(linelist_t *)); 671 blockcount = calloc(NBlocks,sizeof(int)); 672 blockdone = malloc(NBlocks*sizeof(int)); 673 674 // initialize each blocklist, and enter the trailing -1 in all blocklists 675 // note the linked list of lines grows backwards 676 677 for (i=0;i<NBlocks;i++) 678 { 679 blocklists[i] = malloc(sizeof(linelist_t)); 680 blocklists[i]->num = -1; 681 blocklists[i]->next = NULL; 682 blockcount[i]++; 683 } 684 685 // For each linedef in the wad, determine all blockmap blocks it touches, 686 // and add the linedef number to the blocklists for those blocks 687 688 for (i=0;i<numlines;i++) 689 { 690 int x1 = lines[i].v1->x>>FRACBITS; // lines[i] map coords 691 int y1 = lines[i].v1->y>>FRACBITS; 692 int x2 = lines[i].v2->x>>FRACBITS; 693 int y2 = lines[i].v2->y>>FRACBITS; 694 int dx = x2-x1; 695 int dy = y2-y1; 696 int vert = !dx; // lines[i] slopetype 697 int horiz = !dy; 698 int spos = (dx^dy) > 0; 699 int sneg = (dx^dy) < 0; 700 int bx,by; // block cell coords 701 int minx = x1>x2? x2 : x1; // extremal lines[i] coords 702 int maxx = x1>x2? x1 : x2; 703 int miny = y1>y2? y2 : y1; 704 int maxy = y1>y2? y1 : y2; 705 706 // no blocks done for this linedef yet 707 708 memset(blockdone,0,NBlocks*sizeof(int)); 709 710 // The line always belongs to the blocks containing its endpoints 711 712 bx = (x1-xorg)>>blkshift; 713 by = (y1-yorg)>>blkshift; 714 AddBlockLine(blocklists,blockcount,blockdone,by*ncols+bx,i); 715 bx = (x2-xorg)>>blkshift; 716 by = (y2-yorg)>>blkshift; 717 AddBlockLine(blocklists,blockcount,blockdone,by*ncols+bx,i); 718 719 720 // For each column, see where the line along its left edge, which 721 // it contains, intersects the Linedef i. Add i to each corresponding 722 // blocklist. 723 724 if (!vert) // don't interesect vertical lines with columns 725 { 726 for (j=0;j<ncols;j++) 727 { 728 // intersection of Linedef with x=xorg+(j<<blkshift) 729 // (y-y1)*dx = dy*(x-x1) 730 // y = dy*(x-x1)+y1*dx; 731 732 int x = xorg+(j<<blkshift); // (x,y) is intersection 733 int y = (dy*(x-x1))/dx+y1; 734 int yb = (y-yorg)>>blkshift; // block row number 735 int yp = (y-yorg)&blkmask; // y position within block 736 737 if (yb<0 || yb>nrows-1) // outside blockmap, continue 738 continue; 739 740 if (x<minx || x>maxx) // line doesn't touch column 741 continue; 742 743 // The cell that contains the intersection point is always added 744 745 AddBlockLine(blocklists,blockcount,blockdone,ncols*yb+j,i); 746 747 // if the intersection is at a corner it depends on the slope 748 // (and whether the line extends past the intersection) which 749 // blocks are hit 750 751 if (yp==0) // intersection at a corner 752 { 753 if (sneg) // \ - blocks x,y-, x-,y 754 { 755 if (yb>0 && miny<y) 756 AddBlockLine(blocklists,blockcount,blockdone,ncols*(yb-1)+j,i); 757 if (j>0 && minx<x) 758 AddBlockLine(blocklists,blockcount,blockdone,ncols*yb+j-1,i); 759 } 760 else if (spos) // / - block x-,y- 761 { 762 if (yb>0 && j>0 && minx<x) 763 AddBlockLine(blocklists,blockcount,blockdone,ncols*(yb-1)+j-1,i); 764 } 765 else if (horiz) // - - block x-,y 766 { 767 if (j>0 && minx<x) 768 AddBlockLine(blocklists,blockcount,blockdone,ncols*yb+j-1,i); 769 } 770 } 771 else if (j>0 && minx<x) // else not at corner: x-,y 772 AddBlockLine(blocklists,blockcount,blockdone,ncols*yb+j-1,i); 773 } 774 } 775 776 // For each row, see where the line along its bottom edge, which 777 // it contains, intersects the Linedef i. Add i to all the corresponding 778 // blocklists. 779 780 if (!horiz) 781 { 782 for (j=0;j<nrows;j++) 783 { 784 // intersection of Linedef with y=yorg+(j<<blkshift) 785 // (x,y) on Linedef i satisfies: (y-y1)*dx = dy*(x-x1) 786 // x = dx*(y-y1)/dy+x1; 787 788 int y = yorg+(j<<blkshift); // (x,y) is intersection 789 int x = (dx*(y-y1))/dy+x1; 790 int xb = (x-xorg)>>blkshift; // block column number 791 int xp = (x-xorg)&blkmask; // x position within block 792 793 if (xb<0 || xb>ncols-1) // outside blockmap, continue 794 continue; 795 796 if (y<miny || y>maxy) // line doesn't touch row 797 continue; 798 799 // The cell that contains the intersection point is always added 800 801 AddBlockLine(blocklists,blockcount,blockdone,ncols*j+xb,i); 802 803 // if the intersection is at a corner it depends on the slope 804 // (and whether the line extends past the intersection) which 805 // blocks are hit 806 807 if (xp==0) // intersection at a corner 808 { 809 if (sneg) // \ - blocks x,y-, x-,y 810 { 811 if (j>0 && miny<y) 812 AddBlockLine(blocklists,blockcount,blockdone,ncols*(j-1)+xb,i); 813 if (xb>0 && minx<x) 814 AddBlockLine(blocklists,blockcount,blockdone,ncols*j+xb-1,i); 815 } 816 else if (vert) // | - block x,y- 817 { 818 if (j>0 && miny<y) 819 AddBlockLine(blocklists,blockcount,blockdone,ncols*(j-1)+xb,i); 820 } 821 else if (spos) // / - block x-,y- 822 { 823 if (xb>0 && j>0 && miny<y) 824 AddBlockLine(blocklists,blockcount,blockdone,ncols*(j-1)+xb-1,i); 825 } 826 } 827 else if (j>0 && miny<y) // else not on a corner: x,y- 828 AddBlockLine(blocklists,blockcount,blockdone,ncols*(j-1)+xb,i); 829 } 830 } 831 } 832 833 // Add initial 0 to all blocklists 834 // count the total number of lines (and 0's and -1's) 835 836 memset(blockdone,0,NBlocks*sizeof(int)); 837 for (i=0,linetotal=0;i<NBlocks;i++) 838 { 839 AddBlockLine(blocklists,blockcount,blockdone,i,0); 840 linetotal += blockcount[i]; 841 } 842 843 // Create the blockmap lump 844 845 blockmaplump = Z_Malloc(sizeof(*blockmaplump) * (4+NBlocks+linetotal), 846 PU_LEVEL, 0); 847 // blockmap header 848 849 blockmaplump[0] = bmaporgx = xorg << FRACBITS; 850 blockmaplump[1] = bmaporgy = yorg << FRACBITS; 851 blockmaplump[2] = bmapwidth = ncols; 852 blockmaplump[3] = bmapheight = nrows; 853 854 // offsets to lists and block lists 855 856 for (i=0;i<NBlocks;i++) 857 { 858 linelist_t *bl = blocklists[i]; 859 long offs = blockmaplump[4+i] = // set offset to block's list 860 (i? blockmaplump[4+i-1] : 4+NBlocks) + (i? blockcount[i-1] : 0); 861 862 // add the lines in each block's list to the blockmaplump 863 // delete each list node as we go 864 865 while (bl) 866 { 867 linelist_t *tmp = bl->next; 868 blockmaplump[offs++] = bl->num; 869 free(bl); 870 bl = tmp; 871 } 872 } 873 874 // free all temporary storage 875 876 free (blocklists); 877 free (blockcount); 878 free (blockdone); 879} 880 881// jff 10/6/98 882// End new code added to speed up calculation of internal blockmap 883 884// 885// P_LoadBlockMap 886// 887// killough 3/1/98: substantially modified to work 888// towards removing blockmap limit (a wad limitation) 889// 890// killough 3/30/98: Rewritten to remove blockmap limit, 891// though current algorithm is brute-force and unoptimal. 892// 893 894static void P_LoadBlockMap (int lump) 895{ 896 long count; 897 898 if (M_CheckParm("-blockmap") || (count = W_LumpLength(lump)/2) >= 0x10000) 899 P_CreateBlockMap(); 900 else 901 { 902 long i; 903 // cph - const*, wad lump handling updated 904 const short *wadblockmaplump = W_CacheLumpNum(lump); 905 blockmaplump = Z_Malloc(sizeof(*blockmaplump) * count, PU_LEVEL, 0); 906 907 // killough 3/1/98: Expand wad blockmap into larger internal one, 908 // by treating all offsets except -1 as unsigned and zero-extending 909 // them. This potentially doubles the size of blockmaps allowed, 910 // because Doom originally considered the offsets as always signed. 911 912 blockmaplump[0] = SHORT(wadblockmaplump[0]); 913 blockmaplump[1] = SHORT(wadblockmaplump[1]); 914 blockmaplump[2] = (long)(SHORT(wadblockmaplump[2])) & 0xffff; 915 blockmaplump[3] = (long)(SHORT(wadblockmaplump[3])) & 0xffff; 916 917 for (i=4 ; i<count ; i++) 918 { 919 short t = SHORT(wadblockmaplump[i]); // killough 3/1/98 920 blockmaplump[i] = t == -1 ? -1l : (long) t & 0xffff; 921 } 922 923 W_UnlockLumpNum(lump); // cph - unlock the lump 924 925 bmaporgx = blockmaplump[0]<<FRACBITS; 926 bmaporgy = blockmaplump[1]<<FRACBITS; 927 bmapwidth = blockmaplump[2]; 928 bmapheight = blockmaplump[3]; 929 } 930 931 // clear out mobj chains - CPhipps - use calloc 932 blocklinks = Z_Calloc (bmapwidth*bmapheight,sizeof(*blocklinks),PU_LEVEL,0); 933 blockmap = blockmaplump+4; 934} 935 936// 937// P_GroupLines 938// Builds sector line lists and subsector sector numbers. 939// Finds block bounding boxes for sectors. 940// 941// killough 5/3/98: reformatted, cleaned up 942// cph 18/8/99: rewritten to avoid O(numlines * numsectors) section 943// It makes things more complicated, but saves seconds on big levels 944// figgi 09/18/00 -- adapted for gl-nodes 945 946// cph - convenient sub-function 947static void P_AddLineToSector(line_t* li, sector_t* sector) 948{ 949 fixed_t *bbox = (void*)sector->blockbox; 950 951 sector->lines[sector->linecount++] = li; 952 M_AddToBox (bbox, li->v1->x, li->v1->y); 953 M_AddToBox (bbox, li->v2->x, li->v2->y); 954} 955 956void P_GroupLines (void) 957{ 958 register line_t *li; 959 register sector_t *sector; 960 int i,j, total = numlines; 961 962 // figgi 963 for (i=0 ; i<numsubsectors ; i++) 964 { 965 seg_t *seg = &segs[subsectors[i].firstline]; 966 subsectors[i].sector = NULL; 967 for(j=0; j<subsectors[i].numlines; j++) 968 { 969 if(seg->sidedef) 970 { 971 subsectors[i].sector = seg->sidedef->sector; 972 break; 973 } 974 seg++; 975 } 976 if(subsectors[i].sector == NULL) 977 I_Error("P_GroupLines: Subsector a part of no sector!\n"); 978 } 979 980 // count number of lines in each sector 981 for (i=0,li=lines; i<numlines; i++, li++) 982 { 983 li->frontsector->linecount++; 984 if (li->backsector && li->backsector != li->frontsector) 985 { 986 li->backsector->linecount++; 987 total++; 988 } 989 } 990 991 { // allocate line tables for each sector 992 line_t **linebuffer = Z_Malloc(total*sizeof(line_t *), PU_LEVEL, 0); 993 994 for (i=0, sector = sectors; i<numsectors; i++, sector++) 995 { 996 sector->lines = linebuffer; 997 linebuffer += sector->linecount; 998 sector->linecount = 0; 999 M_ClearBox(sector->blockbox); 1000 } 1001 } 1002 1003 // Enter those lines 1004 for (i=0,li=lines; i<numlines; i++, li++) 1005 { 1006 P_AddLineToSector(li, li->frontsector); 1007 if (li->backsector && li->backsector != li->frontsector) 1008 P_AddLineToSector(li, li->backsector); 1009 } 1010 1011 for (i=0, sector = sectors; i<numsectors; i++, sector++) 1012 { 1013 fixed_t *bbox = (void*)sector->blockbox; // cph - For convenience, so 1014 // I can sue the old code unchanged 1015 int block; 1016 1017 // set the degenmobj_t to the middle of the bounding box 1018 sector->soundorg.x = (bbox[BOXRIGHT]+bbox[BOXLEFT])/2; 1019 sector->soundorg.y = (bbox[BOXTOP]+bbox[BOXBOTTOM])/2; 1020 1021 // adjust bounding box to map blocks 1022 block = (bbox[BOXTOP]-bmaporgy+MAXRADIUS)>>MAPBLOCKSHIFT; 1023 block = block >= bmapheight ? bmapheight-1 : block; 1024 sector->blockbox[BOXTOP]=block; 1025 1026 block = (bbox[BOXBOTTOM]-bmaporgy-MAXRADIUS)>>MAPBLOCKSHIFT; 1027 block = block < 0 ? 0 : block; 1028 sector->blockbox[BOXBOTTOM]=block; 1029 1030 block = (bbox[BOXRIGHT]-bmaporgx+MAXRADIUS)>>MAPBLOCKSHIFT; 1031 block = block >= bmapwidth ? bmapwidth-1 : block; 1032 sector->blockbox[BOXRIGHT]=block; 1033 1034 block = (bbox[BOXLEFT]-bmaporgx-MAXRADIUS)>>MAPBLOCKSHIFT; 1035 block = block < 0 ? 0 : block; 1036 sector->blockbox[BOXLEFT]=block; 1037 } 1038 1039} 1040 1041// 1042// killough 10/98 1043// 1044// Remove slime trails. 1045// 1046// Slime trails are inherent to Doom's coordinate system -- i.e. there is 1047// nothing that a node builder can do to prevent slime trails ALL of the time, 1048// because it's a product of the integer coodinate system, and just because 1049// two lines pass through exact integer coordinates, doesn't necessarily mean 1050// that they will intersect at integer coordinates. Thus we must allow for 1051// fractional coordinates if we are to be able to split segs with node lines, 1052// as a node builder must do when creating a BSP tree. 1053// 1054// A wad file does not allow fractional coordinates, so node builders are out 1055// of luck except that they can try to limit the number of splits (they might 1056// also be able to detect the degree of roundoff error and try to avoid splits 1057// with a high degree of roundoff error). But we can use fractional coordinates 1058// here, inside the engine. It's like the difference between square inches and 1059// square miles, in terms of granularity. 1060// 1061// For each vertex of every seg, check to see whether it's also a vertex of 1062// the linedef associated with the seg (i.e, it's an endpoint). If it's not 1063// an endpoint, and it wasn't already moved, move the vertex towards the 1064// linedef by projecting it using the law of cosines. Formula: 1065// 1066// 2 2 2 2 1067// dx x0 + dy x1 + dx dy (y0 - y1) dy y0 + dx y1 + dx dy (x0 - x1) 1068// {---------------------------------, ---------------------------------} 1069// 2 2 2 2 1070// dx + dy dx + dy 1071// 1072// (x0,y0) is the vertex being moved, and (x1,y1)-(x1+dx,y1+dy) is the 1073// reference linedef. 1074// 1075// Segs corresponding to orthogonal linedefs (exactly vertical or horizontal 1076// linedefs), which comprise at least half of all linedefs in most wads, don't 1077// need to be considered, because they almost never contribute to slime trails 1078// (because then any roundoff error is parallel to the linedef, which doesn't 1079// cause slime). Skipping simple orthogonal lines lets the code finish quicker. 1080// 1081// Please note: This section of code is not interchangable with TeamTNT's 1082// code which attempts to fix the same problem. 1083// 1084// Firelines (TM) is a Rezistered Trademark of MBF Productions 1085// 1086 1087void P_RemoveSlimeTrails(void) // killough 10/98 1088{ 1089 byte *hit = calloc(1, numvertexes); // Hitlist for vertices 1090 int i; 1091 for (i=0; i<numsegs; i++) // Go through each seg 1092 { 1093 const line_t *l; 1094 1095 if (segs[i].miniseg == true) //figgi -- skip minisegs 1096 return; 1097 1098 l = segs[i].linedef; // The parent linedef 1099 if (l->dx && l->dy) // We can ignore orthogonal lines 1100 { 1101 vertex_t *v = segs[i].v1; 1102 do 1103 if (!hit[v - vertexes]) // If we haven't processed vertex 1104 { 1105 hit[v - vertexes] = 1; // Mark this vertex as processed 1106 if (v != l->v1 && v != l->v2) // Exclude endpoints of linedefs 1107 { // Project the vertex back onto the parent linedef 1108 int_64_t dx2 = (l->dx >> FRACBITS) * (l->dx >> FRACBITS); 1109 int_64_t dy2 = (l->dy >> FRACBITS) * (l->dy >> FRACBITS); 1110 int_64_t dxy = (l->dx >> FRACBITS) * (l->dy >> FRACBITS); 1111 int_64_t s = dx2 + dy2; 1112 int x0 = v->x, y0 = v->y, x1 = l->v1->x, y1 = l->v1->y; 1113 v->x = (int)((dx2 * x0 + dy2 * x1 + dxy * (y0 - y1)) / s); 1114 v->y = (int)((dy2 * y0 + dx2 * y1 + dxy * (x0 - x1)) / s); 1115 } 1116 } // Obsfucated C contest entry: :) 1117 while ((v != segs[i].v2) && (v = segs[i].v2)); 1118 } 1119 } 1120 free(hit); 1121} 1122 1123// 1124// P_SetupLevel 1125// 1126// killough 5/3/98: reformatted, cleaned up 1127 1128void P_SetupLevel(int episode, int map, int playermask, skill_t skill) 1129{ 1130 (void)playermask; 1131 (void)skill; 1132 int i; 1133 char lumpname[9]; 1134 int lumpnum; 1135 1136 1137 totalkills = totalitems = totalsecret = wminfo.maxfrags = 0; 1138 wminfo.partime = 180; 1139 1140 for (i=0; i<MAXPLAYERS; i++) 1141 players[i].killcount = players[i].secretcount = players[i].itemcount = 0; 1142 1143 // Initial height of PointOfView will be set by player think. 1144 players[consoleplayer].viewz = 1; 1145 1146 // Make sure all sounds are stopped before Z_FreeTags. 1147 S_Start(); 1148 1149 Z_FreeTags(PU_LEVEL, PU_PURGELEVEL-1); 1150 if (rejectlump != -1) { // cph - unlock the reject table 1151 W_UnlockLumpNum(rejectlump); 1152 rejectlump = -1; 1153 } 1154 1155 P_InitThinkers(); 1156 1157 // if working with a devlopment map, reload it 1158 // W_Reload (); killough 1/31/98: W_Reload obsolete 1159 1160 // find map name 1161 if (gamemode == commercial) 1162 { 1163 if (map<10) 1164 snprintf (lumpname,sizeof(lumpname),"map0%d", map); 1165 else 1166 snprintf (lumpname,sizeof(lumpname),"map%d", map); 1167 } 1168 else 1169 { 1170 snprintf(lumpname,sizeof(lumpname), "E%dM%d", episode, map); // killough 1/24/98: simplify 1171 } 1172 1173 lumpnum = W_GetNumForName(lumpname); 1174 1175 leveltime = 0; 1176 1177 // note: most of this ordering is important 1178 1179 // killough 3/1/98: P_LoadBlockMap call moved down to below 1180 // killough 4/4/98: split load of sidedefs into two parts, 1181 // to allow texture names to be used in special linedefs 1182 1183 usingGLNodes = false; 1184 P_LoadVertexes (lumpnum+ML_VERTEXES); 1185 P_LoadSectors (lumpnum+ML_SECTORS); 1186 P_LoadSideDefs (lumpnum+ML_SIDEDEFS); 1187 P_LoadLineDefs (lumpnum+ML_LINEDEFS); 1188 P_LoadSideDefs2 (lumpnum+ML_SIDEDEFS); 1189 P_LoadLineDefs2 (lumpnum+ML_LINEDEFS); 1190 P_LoadBlockMap (lumpnum+ML_BLOCKMAP); 1191 1192 P_LoadSubsectors(lumpnum + ML_SSECTORS); 1193 P_LoadNodes(lumpnum + ML_NODES); 1194 P_LoadSegs(lumpnum + ML_SEGS); 1195 1196 if (rejectlump != -1) 1197 W_UnlockLumpNum(rejectlump); 1198 rejectlump = lumpnum+ML_REJECT; 1199 { 1200 int rjlen = W_LumpLength(rejectlump); 1201 int rjreq = (numsectors*numsectors+7)/8; 1202 if (rjlen < rjreq) { 1203 printf("P_SetupLevel: REJECT too short (%d<%d) - padded\n",rjlen,rjreq); 1204 rejectmatrix = W_CacheLumpNumPadded(rejectlump,rjreq,0xff); 1205 } else { 1206 rejectmatrix = W_CacheLumpNum(rejectlump); 1207 } 1208 } 1209 P_GroupLines(); 1210 1211 P_RemoveSlimeTrails(); // killough 10/98: remove slime trails from wad 1212 1213 // Note: you don't need to clear player queue slots -- 1214 // a much simpler fix is in g_game.c -- killough 10/98 1215 1216 bodyqueslot = 0; 1217 deathmatch_p = deathmatchstarts; 1218 P_MapStart(); 1219 P_LoadThings(lumpnum+ML_THINGS); 1220 1221 // if deathmatch, randomly spawn the active players 1222 if (deathmatch) 1223 for (i=0; i<MAXPLAYERS; i++) 1224 if (playeringame[i]) 1225 { 1226 players[i].mo = NULL; 1227 G_DeathMatchSpawnPlayer(i); 1228 } 1229 1230 // killough 3/26/98: Spawn icon landings: 1231 if (gamemode==commercial) 1232 P_SpawnBrainTargets(); 1233 1234 // clear special respawning que 1235 iquehead = iquetail = 0; 1236 1237 // set up world state 1238 P_SpawnSpecials(); 1239 1240 P_MapEnd(); 1241 1242 // preload graphics 1243 if (precache) 1244 R_PrecacheLevel(); 1245} 1246 1247// 1248// P_Init 1249// 1250void P_Init (void) 1251{ 1252 P_InitSwitchList(); 1253 P_InitPicAnims(); 1254 R_InitSprites(sprnames); 1255}