]> icculus.org git repositories - theoddone33/hheretic.git/blob - base/p_setup.c
Fix stupid wadfile problem
[theoddone33/hheretic.git] / base / p_setup.c
1
2 // P_main.c
3
4 #include <math.h>
5 #include <stdlib.h>
6 #include "doomdef.h"
7 #include "p_local.h"
8 #include "soundst.h"
9 #ifdef RENDER3D
10 #include "ogl_def.h"
11 float AccurateDistance(fixed_t dx,fixed_t dy);
12 #endif
13
14 void    P_SpawnMapThing (mapthing_t *mthing);
15
16 int                     numvertexes;
17 vertex_t        *vertexes;
18
19 int                     numsegs;
20 seg_t           *segs;
21
22 int                     numsectors;
23 sector_t        *sectors;
24
25 int                     numsubsectors;
26 subsector_t     *subsectors;
27
28 int                     numnodes;
29 node_t          *nodes;
30
31 int                     numlines;
32 line_t          *lines;
33
34 int                     numsides;
35 side_t          *sides;
36
37 short           *blockmaplump;                  // offsets in blockmap are from here
38 short           *blockmap;
39 int                     bmapwidth, bmapheight;  // in mapblocks
40 fixed_t         bmaporgx, bmaporgy;             // origin of block map
41 mobj_t          **blocklinks;                   // for thing chains
42
43 byte            *rejectmatrix;                  // for fast sight rejection
44
45 mapthing_t      deathmatchstarts[10], *deathmatch_p;
46 mapthing_t      playerstarts[MAXPLAYERS];
47
48 /*
49 =================
50 =
51 = P_LoadVertexes
52 =
53 =================
54 */
55
56 void P_LoadVertexes (int lump)
57 {
58         byte            *data;
59         int                     i;
60         mapvertex_t     *ml;
61         vertex_t        *li;
62         
63         numvertexes = W_LumpLength (lump) / sizeof(mapvertex_t);
64         vertexes = Z_Malloc (numvertexes*sizeof(vertex_t),PU_LEVEL,0);  
65         data = W_CacheLumpNum (lump,PU_STATIC);
66         
67         ml = (mapvertex_t *)data;
68         li = vertexes;
69         for (i=0 ; i<numvertexes ; i++, li++, ml++)
70         {
71                 li->x = SHORT(ml->x)<<FRACBITS;
72                 li->y = SHORT(ml->y)<<FRACBITS;
73         }
74         
75         Z_Free (data);
76 }
77
78
79 /*
80 =================
81 =
82 = P_LoadSegs
83 =
84 =================
85 */
86
87 void P_LoadSegs (int lump)
88 {
89         byte            *data;
90         int                     i;
91         mapseg_t        *ml;
92         seg_t           *li;
93         line_t  *ldef;
94         int                     linedef, side;
95         
96         numsegs = W_LumpLength (lump) / sizeof(mapseg_t);
97         segs = Z_Malloc (numsegs*sizeof(seg_t),PU_LEVEL,0);     
98         memset (segs, 0, numsegs*sizeof(seg_t));
99         data = W_CacheLumpNum (lump,PU_STATIC);
100         
101         ml = (mapseg_t *)data;
102         li = segs;
103         for (i=0 ; i<numsegs ; i++, li++, ml++)
104         {
105                 li->v1 = &vertexes[SHORT(ml->v1)];
106                 li->v2 = &vertexes[SHORT(ml->v2)];
107                                         
108                 li->angle = (SHORT(ml->angle))<<16;
109                 li->offset = (SHORT(ml->offset))<<16;
110                 linedef = SHORT(ml->linedef);
111                 ldef = &lines[linedef];
112                 li->linedef = ldef;
113                 side = SHORT(ml->side);
114                 li->sidedef = &sides[ldef->sidenum[side]];
115                 li->frontsector = sides[ldef->sidenum[side]].sector;
116                 if (ldef-> flags & ML_TWOSIDED)
117                         li->backsector = sides[ldef->sidenum[side^1]].sector;
118                 else
119                         li->backsector = 0;
120 #ifdef RENDER3D
121         // Calculate the length of the segment. We need this for
122         // the texture coordinates. -jk
123         li->len = AccurateDistance( li->v2->x - li->v1->x,
124                                     li->v2->y - li->v1->y );
125 #endif
126         }
127         
128         Z_Free (data);
129 }
130
131
132 /*
133 =================
134 =
135 = P_LoadSubsectors
136 =
137 =================
138 */
139
140 void P_LoadSubsectors (int lump)
141 {
142         byte                    *data;
143         int                             i;
144         mapsubsector_t  *ms;
145         subsector_t             *ss;
146         
147         numsubsectors = W_LumpLength (lump) / sizeof(mapsubsector_t);
148         subsectors = Z_Malloc (numsubsectors*sizeof(subsector_t),PU_LEVEL,0);   
149         data = W_CacheLumpNum (lump,PU_STATIC);
150         
151         ms = (mapsubsector_t *)data;
152         memset (subsectors,0, numsubsectors*sizeof(subsector_t));
153         ss = subsectors;
154         for (i=0 ; i<numsubsectors ; i++, ss++, ms++)
155         {
156                 ss->numlines = SHORT(ms->numsegs);
157                 ss->firstline = SHORT(ms->firstseg);
158         }
159         
160         Z_Free (data);
161 }
162
163
164 /*
165 =================
166 =
167 = P_LoadSectors
168 =
169 =================
170 */
171
172 void P_LoadSectors (int lump)
173 {
174         byte                    *data;
175         int                             i;
176         mapsector_t             *ms;
177         sector_t                *ss;
178         
179         numsectors = W_LumpLength (lump) / sizeof(mapsector_t);
180         sectors = Z_Malloc (numsectors*sizeof(sector_t),PU_LEVEL,0);    
181         memset (sectors, 0, numsectors*sizeof(sector_t));
182         data = W_CacheLumpNum (lump,PU_STATIC);
183         
184         ms = (mapsector_t *)data;
185         ss = sectors;
186         for (i=0 ; i<numsectors ; i++, ss++, ms++)
187         {
188                 ss->floorheight = SHORT(ms->floorheight)<<FRACBITS;
189                 ss->ceilingheight = SHORT(ms->ceilingheight)<<FRACBITS;
190                 ss->floorpic = R_FlatNumForName(ms->floorpic);
191                 ss->ceilingpic = R_FlatNumForName(ms->ceilingpic);
192                 ss->lightlevel = SHORT(ms->lightlevel);
193                 ss->special = SHORT(ms->special);
194                 ss->tag = SHORT(ms->tag);
195                 ss->thinglist = NULL;
196 #ifdef RENDER3D
197         ss->flatoffx = ss->flatoffy = 0;    // Flat scrolling.
198         ss->skyfix = 0;     // Set if needed.
199 #endif
200         }
201         
202         Z_Free (data);
203 }
204
205
206 /*
207 =================
208 =
209 = P_LoadNodes
210 =
211 =================
212 */
213
214 void P_LoadNodes (int lump)
215 {
216         byte            *data;
217         int                     i,j,k;
218         mapnode_t       *mn;
219         node_t          *no;
220         
221         numnodes = W_LumpLength (lump) / sizeof(mapnode_t);
222         nodes = Z_Malloc (numnodes*sizeof(node_t),PU_LEVEL,0);  
223         data = W_CacheLumpNum (lump,PU_STATIC);
224         
225         mn = (mapnode_t *)data;
226         no = nodes;
227         for (i=0 ; i<numnodes ; i++, no++, mn++)
228         {
229                 no->x = SHORT(mn->x)<<FRACBITS;
230                 no->y = SHORT(mn->y)<<FRACBITS;
231                 no->dx = SHORT(mn->dx)<<FRACBITS;
232                 no->dy = SHORT(mn->dy)<<FRACBITS;
233                 for (j=0 ; j<2 ; j++)
234                 {
235                         no->children[j] = SHORT(mn->children[j]);
236                         for (k=0 ; k<4 ; k++)
237                                 no->bbox[j][k] = SHORT(mn->bbox[j][k])<<FRACBITS;
238                 }
239         }
240         
241         Z_Free (data);
242 }
243
244
245
246 /*
247 =================
248 =
249 = P_LoadThings
250 =
251 =================
252 */
253
254 void P_LoadThings (int lump)
255 {
256         byte                    *data;
257         int                             i;
258         mapthing_t              *mt;
259         int                             numthings;
260         
261         data = W_CacheLumpNum (lump,PU_STATIC);
262         numthings = W_LumpLength (lump) / sizeof(mapthing_t);
263         
264         mt = (mapthing_t *)data;
265         for (i=0 ; i<numthings ; i++, mt++)
266         {
267                 mt->x = SHORT(mt->x);
268                 mt->y = SHORT(mt->y);
269                 mt->angle = SHORT(mt->angle);
270                 mt->type = SHORT(mt->type);
271                 mt->options = SHORT(mt->options);
272                 P_SpawnMapThing (mt);
273         }
274         
275         Z_Free (data);
276 }
277
278
279
280 /*
281 =================
282 =
283 = P_LoadLineDefs
284 =
285 = Also counts secret lines for intermissions
286 =================
287 */
288
289 void P_LoadLineDefs (int lump)
290 {
291         byte                    *data;
292         int                             i;
293         maplinedef_t    *mld;
294         line_t                  *ld;
295         vertex_t                *v1, *v2;
296         
297         numlines = W_LumpLength (lump) / sizeof(maplinedef_t);
298         lines = Z_Malloc (numlines*sizeof(line_t),PU_LEVEL,0);  
299         memset (lines, 0, numlines*sizeof(line_t));
300         data = W_CacheLumpNum (lump,PU_STATIC);
301         
302         mld = (maplinedef_t *)data;
303         ld = lines;
304         for (i=0 ; i<numlines ; i++, mld++, ld++)
305         {
306                 ld->flags = SHORT(mld->flags);
307                 ld->special = SHORT(mld->special);
308                 ld->tag = SHORT(mld->tag);
309                 v1 = ld->v1 = &vertexes[SHORT(mld->v1)];
310                 v2 = ld->v2 = &vertexes[SHORT(mld->v2)];
311                 ld->dx = v2->x - v1->x;
312                 ld->dy = v2->y - v1->y;
313                 if (!ld->dx)
314                         ld->slopetype = ST_VERTICAL;
315                 else if (!ld->dy)
316                         ld->slopetype = ST_HORIZONTAL;
317                 else
318                 {
319                         if (FixedDiv (ld->dy , ld->dx) > 0)
320                                 ld->slopetype = ST_POSITIVE;
321                         else
322                                 ld->slopetype = ST_NEGATIVE;
323                 }
324                 
325                 if (v1->x < v2->x)
326                 {
327                         ld->bbox[BOXLEFT] = v1->x;
328                         ld->bbox[BOXRIGHT] = v2->x;
329                 }
330                 else
331                 {
332                         ld->bbox[BOXLEFT] = v2->x;
333                         ld->bbox[BOXRIGHT] = v1->x;
334                 }
335                 if (v1->y < v2->y)
336                 {
337                         ld->bbox[BOXBOTTOM] = v1->y;
338                         ld->bbox[BOXTOP] = v2->y;
339                 }
340                 else
341                 {
342                         ld->bbox[BOXBOTTOM] = v2->y;
343                         ld->bbox[BOXTOP] = v1->y;
344                 }
345                 ld->sidenum[0] = SHORT(mld->sidenum[0]);
346                 ld->sidenum[1] = SHORT(mld->sidenum[1]);
347                 if (ld->sidenum[0] != -1)
348                         ld->frontsector = sides[ld->sidenum[0]].sector;
349                 else
350                         ld->frontsector = 0;
351                 if (ld->sidenum[1] != -1)
352                         ld->backsector = sides[ld->sidenum[1]].sector;
353                 else
354                         ld->backsector = 0;
355         }
356         
357         Z_Free (data);
358 }
359
360
361 /*
362 =================
363 =
364 = P_LoadSideDefs
365 =
366 =================
367 */
368
369 void P_LoadSideDefs (int lump)
370 {
371         byte                    *data;
372         int                             i;
373         mapsidedef_t    *msd;
374         side_t                  *sd;
375         
376         numsides = W_LumpLength (lump) / sizeof(mapsidedef_t);
377         sides = Z_Malloc (numsides*sizeof(side_t),PU_LEVEL,0);  
378         memset (sides, 0, numsides*sizeof(side_t));
379         data = W_CacheLumpNum (lump,PU_STATIC);
380         
381         msd = (mapsidedef_t *)data;
382         sd = sides;
383         for (i=0 ; i<numsides ; i++, msd++, sd++)
384         {
385                 sd->textureoffset = SHORT(msd->textureoffset)<<FRACBITS;
386                 sd->rowoffset = SHORT(msd->rowoffset)<<FRACBITS;
387                 sd->toptexture = R_TextureNumForName(msd->toptexture);
388                 sd->bottomtexture = R_TextureNumForName(msd->bottomtexture);
389                 sd->midtexture = R_TextureNumForName(msd->midtexture);
390                 sd->sector = &sectors[SHORT(msd->sector)];
391         }
392         
393         Z_Free (data);
394 }
395
396
397
398 /*
399 =================
400 =
401 = P_LoadBlockMap
402 =
403 =================
404 */
405
406 void P_LoadBlockMap (int lump)
407 {
408         int             i, count;
409         
410         blockmaplump = W_CacheLumpNum (lump,PU_LEVEL);
411         blockmap = blockmaplump+4;
412         count = W_LumpLength (lump)/2;
413         for (i=0 ; i<count ; i++)
414                 blockmaplump[i] = SHORT(blockmaplump[i]);
415                 
416         bmaporgx = blockmaplump[0]<<FRACBITS;
417         bmaporgy = blockmaplump[1]<<FRACBITS;
418         bmapwidth = blockmaplump[2];
419         bmapheight = blockmaplump[3];
420         
421 // clear out mobj chains
422         count = sizeof(*blocklinks)* bmapwidth*bmapheight;
423         blocklinks = Z_Malloc (count,PU_LEVEL, 0);
424         memset (blocklinks, 0, count);
425 }
426
427
428
429
430 /*
431 =================
432 =
433 = P_GroupLines
434 =
435 = Builds sector line lists and subsector sector numbers
436 = Finds block bounding boxes for sectors
437 =================
438 */
439
440 void P_GroupLines (void)
441 {
442         line_t          **linebuffer;
443         int                     i, j, total;
444         line_t          *li;
445         sector_t        *sector;
446         subsector_t     *ss;
447         seg_t           *seg;
448         fixed_t         bbox[4];
449         int                     block;
450         
451 // look up sector number for each subsector
452         ss = subsectors;
453         for (i=0 ; i<numsubsectors ; i++, ss++)
454         {
455                 seg = &segs[ss->firstline];
456                 ss->sector = seg->sidedef->sector;
457         }
458
459 // count number of lines in each sector
460         li = lines;
461         total = 0;
462         for (i=0 ; i<numlines ; i++, li++)
463         {
464                 total++;
465                 li->frontsector->linecount++;
466                 if (li->backsector && li->backsector != li->frontsector)
467                 {
468                         li->backsector->linecount++;
469                         total++;
470                 }
471         }
472         
473 // build line tables for each sector    
474         linebuffer = Z_Malloc (total*4, PU_LEVEL, 0);
475         sector = sectors;
476         for (i=0 ; i<numsectors ; i++, sector++)
477         {
478                 M_ClearBox (bbox);
479                 sector->lines = linebuffer;
480                 li = lines;
481                 for (j=0 ; j<numlines ; j++, li++)
482                 {
483                         if (li->frontsector == sector || li->backsector == sector)
484                         {
485                                 *linebuffer++ = li;
486                                 M_AddToBox (bbox, li->v1->x, li->v1->y);
487                                 M_AddToBox (bbox, li->v2->x, li->v2->y);
488                         }
489                 }
490                 if (linebuffer - sector->lines != sector->linecount)
491                         I_Error ("P_GroupLines: miscounted");
492                         
493                 // set the degenmobj_t to the middle of the bounding box
494                 sector->soundorg.x = (bbox[BOXRIGHT]+bbox[BOXLEFT])/2;
495                 sector->soundorg.y = (bbox[BOXTOP]+bbox[BOXBOTTOM])/2;
496                 
497                 // adjust bounding box to map blocks
498                 block = (bbox[BOXTOP]-bmaporgy+MAXRADIUS)>>MAPBLOCKSHIFT;
499                 block = block >= bmapheight ? bmapheight-1 : block;
500                 sector->blockbox[BOXTOP]=block;
501
502                 block = (bbox[BOXBOTTOM]-bmaporgy-MAXRADIUS)>>MAPBLOCKSHIFT;
503                 block = block < 0 ? 0 : block;
504                 sector->blockbox[BOXBOTTOM]=block;
505
506                 block = (bbox[BOXRIGHT]-bmaporgx+MAXRADIUS)>>MAPBLOCKSHIFT;
507                 block = block >= bmapwidth ? bmapwidth-1 : block;
508                 sector->blockbox[BOXRIGHT]=block;
509
510                 block = (bbox[BOXLEFT]-bmaporgx-MAXRADIUS)>>MAPBLOCKSHIFT;
511                 block = block < 0 ? 0 : block;
512                 sector->blockbox[BOXLEFT]=block;
513         }
514         
515 }
516 #ifdef RENDER3D
517 float AccurateDistance(fixed_t dx,fixed_t dy)
518 {
519     float fx = FIX2FLT(dx), fy = FIX2FLT(dy);
520
521     return (float)sqrt(fx*fx + fy*fy);
522 }
523
524
525 #define MAX_CC_SIDES    64
526
527 int detSideFloat(fvertex_t *pnt, fdivline_t *dline)
528 {
529 /*
530             (AY-CY)(BX-AX)-(AX-CX)(BY-AY)
531         s = -----------------------------
532                         L**2
533
534     If s<0      C is left of AB (you can just check the numerator)
535     If s>0      C is right of AB
536     If s=0      C is on AB
537 */
538     // We'll return false if the point c is on the left side.
539 /*  float ax = FIX2FLT(a->x), ay = FIX2FLT(a->y);
540     float bx = FIX2FLT(b->x), by = FIX2FLT(b->y);
541     float cx = FIX2FLT(c->x), cy = FIX2FLT(c->y);*/
542     //float ax = dline->x, ay = dline->y;
543     //float bx = ax + dline->dx, by = ay + dline->dy;
544
545     // REWRITE using dline->dx and dline->dy for (bx-ax) and (by-ay).
546
547     //float s = /*(*/(ay-pnt->y)*(bx-ax)-(ax-pnt->x)*(by-ay);//)/l2;
548     float s = (dline->y-pnt->y)*dline->dx-(dline->x-pnt->x)*dline->dy;
549
550     if(s<0) return 0;
551     return 1;
552 }
553
554
555 // Lines start-end and fdiv must intersect.
556 float findIntersectionVertex( fvertex_t *start, fvertex_t *end,
557                               fdivline_t *fdiv, fvertex_t *inter )
558 {
559     float ax = start->x, ay = start->y, bx = end->x, by = end->y;
560     float cx = fdiv->x, cy = fdiv->y, dx = cx+fdiv->dx, dy = cy+fdiv->dy;
561
562     /*
563             (YA-YC)(XD-XC)-(XA-XC)(YD-YC)
564         r = -----------------------------  (eqn 1)
565             (XB-XA)(YD-YC)-(YB-YA)(XD-XC)
566     */
567
568     float r = ((ay-cy)*(dx-cx)-(ax-cx)*(dy-cy)) /
569               ((bx-ax)*(dy-cy)-(by-ay)*(dx-cx));
570     /*
571         XI=XA+r(XB-XA)
572         YI=YA+r(YB-YA)
573     */
574     inter->x = ax + r*(bx-ax);
575     inter->y = ay + r*(by-ay);
576     return r;
577 }
578
579
580 void P_ConvexCarver(subsector_t *ssec, int num, divline_t *list)
581 {
582     int         numclippers = num+ssec->numlines;
583     fdivline_t  *clippers = (fdivline_t*) Z_Malloc(numclippers*sizeof(fdivline_t), PU_STATIC, 0);
584     int         i, k, numedgepoints;
585     fvertex_t   *edgepoints;
586     unsigned char sidelist[MAX_CC_SIDES];
587
588     // Convert the divlines to float, in reverse order.
589     for(i=0; i<numclippers; i++)
590     {
591         if(i<num)
592         {
593             clippers[i].x = FIX2FLT(list[num-i-1].x);
594             clippers[i].y = FIX2FLT(list[num-i-1].y);
595             clippers[i].dx = FIX2FLT(list[num-i-1].dx);
596             clippers[i].dy = FIX2FLT(list[num-i-1].dy);
597         }
598         else
599         {
600             seg_t *seg = segs+(ssec->firstline+i-num);
601             clippers[i].x = FIX2FLT(seg->v1->x);
602             clippers[i].y = FIX2FLT(seg->v1->y);
603             clippers[i].dx = FIX2FLT(seg->v2->x - seg->v1->x);
604             clippers[i].dy = FIX2FLT(seg->v2->y - seg->v1->y);
605         }
606     }
607
608     // Setup the 'worldwide' polygon.
609     numedgepoints = 4;
610     edgepoints = (fvertex_t*)malloc(numedgepoints*sizeof(fvertex_t));
611
612     edgepoints[0].x = -32768;
613     edgepoints[0].y = 32768;
614
615     edgepoints[1].x = 32768;
616     edgepoints[1].y = 32768;
617
618     edgepoints[2].x = 32768;
619     edgepoints[2].y = -32768;
620
621     edgepoints[3].x = -32768;
622     edgepoints[3].y = -32768;
623
624
625     // We'll now clip the polygon with each of the divlines. The left side of
626     // each divline is discarded.
627     for(i=0; i<numclippers; i++)
628     {
629         fdivline_t *curclip = clippers+i;
630
631         // First we'll determine the side of each vertex. Points are allowed
632         // to be on the line.
633         for(k=0; k<numedgepoints; k++)
634         {
635             sidelist[k] = detSideFloat(edgepoints+k, curclip);
636         }
637
638         for(k=0; k<numedgepoints; k++)
639         {
640             int startIdx = k, endIdx = k+1;
641
642             // Check the end index.
643             if(endIdx == numedgepoints) endIdx = 0; // Wrap-around.
644
645             // Clipping will happen when the ends are on different sides.
646             if(sidelist[startIdx] != sidelist[endIdx])
647             {
648                 fvertex_t newvert;
649                 // Find the intersection point of intersecting lines.
650                 findIntersectionVertex(edgepoints+startIdx, edgepoints+endIdx,
651                     curclip, &newvert);
652
653                 // Add the new vertex. Also modify the sidelist.
654                 edgepoints =
655 (fvertex_t*)realloc(edgepoints,(++numedgepoints)*sizeof(fvertex_t));
656                 if(numedgepoints >= MAX_CC_SIDES) I_Error("Too many points in
657 carver.\n");
658
659                 // Make room for the new vertex.
660                 memmove(edgepoints+endIdx+1, edgepoints+endIdx,
661                     (numedgepoints-endIdx-1)*sizeof(fvertex_t));
662                 memcpy(edgepoints+endIdx, &newvert, sizeof(newvert));
663
664                 memmove(sidelist+endIdx+1, sidelist+endIdx,
665 numedgepoints-endIdx-1);
666                 sidelist[endIdx] = 1;
667
668                 // Skip over the new vertex.
669                 k++;
670             }
671         }
672
673         // Now we must discard the points that are on the wrong side.
674         for(k=0; k<numedgepoints; k++)
675             if(!sidelist[k])
676             {
677                 memmove(edgepoints+k, edgepoints+k+1,
678 (numedgepoints-k-1)*sizeof(fvertex_t));
679                 memmove(sidelist+k, sidelist+k+1, numedgepoints-k-1);
680                 numedgepoints--;
681                 k--;
682             }
683     }
684
685     if(!numedgepoints)
686     {
687         //I_Error("All carved away!\n");
688         printf( "All carved away: subsector %p\n", ssec);
689         ssec->numedgeverts = 0;
690         ssec->edgeverts = 0;
691         ssec->origedgeverts = 0;
692     }
693     else
694     {
695         // Screen out consecutive identical points.
696         for(i=0; i<numedgepoints; i++)
697         {
698             int previdx = i-1;
699             if(previdx < 0) previdx = numedgepoints-1;
700             if(edgepoints[i].x == edgepoints[previdx].x
701                 && edgepoints[i].y == edgepoints[previdx].y)
702             {
703                 // This point (i) must be removed.
704                 memmove(edgepoints+i, edgepoints+i+1,
705 sizeof(fvertex_t)*(numedgepoints-i-1));
706                 numedgepoints--;
707                 i--;
708             }
709         }
710         // We need these with dynamic lights.
711         ssec->origedgeverts =
712 (fvertex_t*)Z_Malloc(sizeof(fvertex_t)*numedgepoints, PU_LEVEL, 0);
713         memcpy(ssec->origedgeverts, edgepoints, sizeof(fvertex_t)*numedgepoints);
714
715         // Find the center point. Do this by first finding the bounding box.
716         ssec->bbox[0].x = ssec->bbox[1].x = edgepoints[0].x;
717         ssec->bbox[0].y = ssec->bbox[1].y = edgepoints[0].y;
718         for(i=1; i<numedgepoints; i++)
719         {
720             if(edgepoints[i].x < ssec->bbox[0].x) ssec->bbox[0].x =
721 edgepoints[i].x;
722             if(edgepoints[i].y < ssec->bbox[0].y) ssec->bbox[0].y =
723 edgepoints[i].y;
724             if(edgepoints[i].x > ssec->bbox[1].x) ssec->bbox[1].x =
725 edgepoints[i].x;
726             if(edgepoints[i].y > ssec->bbox[1].y) ssec->bbox[1].y =
727 edgepoints[i].y;
728         }
729         ssec->midpoint.x = (ssec->bbox[1].x+ssec->bbox[0].x)/2;
730         ssec->midpoint.y = (ssec->bbox[1].y+ssec->bbox[0].y)/2;
731
732         // Make slight adjustments to patch up those ugly, small gaps.
733         for(i=0; i<numedgepoints; i++)
734         {
735             float dx = edgepoints[i].x - ssec->midpoint.x,
736                 dy = edgepoints[i].y - ssec->midpoint.y;
737             float dlen = (float) sqrt(dx*dx + dy*dy) * 3;
738             if(dlen)
739             {
740                 edgepoints[i].x += dx/dlen;
741                 edgepoints[i].y += dy/dlen;
742             }
743         }
744
745         ssec->numedgeverts = numedgepoints;
746         ssec->edgeverts =
747 (fvertex_t*)Z_Malloc(sizeof(fvertex_t)*numedgepoints,PU_LEVEL,0);
748         memcpy(ssec->edgeverts, edgepoints, sizeof(fvertex_t)*numedgepoints);
749     }
750
751     // We're done, free the edgepoints memory.
752     free(edgepoints);
753     Z_Free(clippers);
754 }
755
756
757 void P_CreateFloorsAndCeilings( int bspnode, int numdivlines,
758                                 divline_t* divlines )
759 {
760     node_t      *nod;
761     divline_t   *childlist, *dl;
762     int         childlistsize = numdivlines+1;
763
764     // If this is a subsector we are dealing with, begin carving with the
765     // given list.
766     if(bspnode & NF_SUBSECTOR)
767     {
768
769         // We have arrived at a subsector. The divline list contains all
770         // the partition lines that carve out the subsector.
771
772         //printf( "subsector %d: %d
773         //divlines\n",bspnode&(~NF_SUBSECTOR),numdivlines);
774
775         int ssidx = bspnode & (~NF_SUBSECTOR);
776         //if(ssidx < 10)
777         P_ConvexCarver(subsectors+ssidx, numdivlines, divlines);
778
779         //printf( "subsector %d: %d edgeverts\n", ssidx,
780         //subsectors[ssidx].numedgeverts);
781         // This leaf is done.
782         return;
783     }
784
785     // Get a pointer to the node.
786     nod = nodes + bspnode;
787
788     // Allocate a new list for each child.
789     childlist = (divline_t*)malloc(childlistsize*sizeof(divline_t));
790
791     // Copy the previous lines.
792     if(divlines) memcpy(childlist,divlines,numdivlines*sizeof(divline_t));
793
794     dl = childlist + numdivlines;
795     dl->x = nod->x;
796     dl->y = nod->y;
797     // The right child gets the original line (LEFT side clipped).
798     dl->dx = nod->dx;
799     dl->dy = nod->dy;
800     P_CreateFloorsAndCeilings(nod->children[0],childlistsize,childlist);
801
802     // The left side. We must reverse the line, otherwise the wrong
803     // side would get clipped.
804     dl->dx = -nod->dx;
805     dl->dy = -nod->dy;
806     P_CreateFloorsAndCeilings(nod->children[1],childlistsize,childlist);
807
808     // We are finishing with this node, free the allocated list.
809     free(childlist);
810 }
811
812
813 void P_SkyFix()
814 {
815     int         i;
816
817     // We need to check all the linedefs.
818     for(i=0; i<numlines; i++)
819     {
820         line_t *line = lines + i;
821         sector_t *front = line->frontsector, *back = line->backsector;
822         int fix = 0;
823         // The conditions!
824         if(!front || !back) continue;
825         // Both the front and back sectors must have the sky ceiling.
826         if(front->ceilingpic != skyflatnum || back->ceilingpic != skyflatnum)
827             continue;
828         // Operate on the lower sector.
829         /*ST_Message("Line %d (f:%d, b:%d).\n", i, front->ceilingheight >>
830          * FRACBITS,
831             back->ceilingheight >> FRACBITS);*/
832         if(front->ceilingheight < back->ceilingheight)
833         {
834             fix = (back->ceilingheight-front->ceilingheight) >> FRACBITS;
835             if(fix > front->skyfix) front->skyfix = fix;
836         }
837         else if(front->ceilingheight > back->ceilingheight)
838         {
839             fix = (front->ceilingheight-back->ceilingheight) >> FRACBITS;
840             if(fix > back->skyfix) back->skyfix = fix;
841         }
842     }
843 }
844 #endif
845
846 //=============================================================================
847
848
849 /*
850 =================
851 =
852 = P_SetupLevel
853 =
854 =================
855 */
856
857 void P_SetupLevel (int episode, int map, int playermask, skill_t skill)
858 {
859         int i;
860         int parm;
861         char    lumpname[9];
862         int             lumpnum;
863         mobj_t  *mobj;
864         
865         totalkills = totalitems = totalsecret = 0;
866         for (i=0 ; i<MAXPLAYERS ; i++)
867         {
868                 players[i].killcount = players[i].secretcount 
869                 = players[i].itemcount = 0;
870         }
871         players[consoleplayer].viewz = 1; // will be set by player think
872         
873         S_Start ();                     // make sure all sounds are stopped before Z_FreeTags
874         
875         Z_FreeTags (PU_LEVEL, PU_PURGELEVEL-1);
876
877 #ifdef RENDER3D
878     OGL_ResetData();
879 #endif
880         
881         P_InitThinkers ();
882         
883 //
884 // look for a regular (development) map first
885 //
886         lumpname[0] = 'E';
887         lumpname[1] = '0' + episode;
888         lumpname[2] = 'M';
889         lumpname[3] = '0' + map;
890         lumpname[4] = 0;
891         leveltime = 0;
892         
893         lumpnum = W_GetNumForName (lumpname);
894         
895 // note: most of this ordering is important     
896         P_LoadBlockMap (lumpnum+ML_BLOCKMAP);
897         P_LoadVertexes (lumpnum+ML_VERTEXES);
898         P_LoadSectors (lumpnum+ML_SECTORS);
899         P_LoadSideDefs (lumpnum+ML_SIDEDEFS);
900
901         P_LoadLineDefs (lumpnum+ML_LINEDEFS);
902         P_LoadSubsectors (lumpnum+ML_SSECTORS);
903         P_LoadNodes (lumpnum+ML_NODES);
904         P_LoadSegs (lumpnum+ML_SEGS);
905
906 #ifdef RENDER3D
907     // We need to carve out the floor/ceiling polygons of each subsector.
908     // Walk the tree to do this.
909     //ST_Message( "Floor/ceiling creation: begin at %d, ", ticcount);
910     P_CreateFloorsAndCeilings(numnodes-1, 0, 0);
911     // Also check if the sky needs a fix.
912     P_SkyFix();
913 #endif
914         
915         rejectmatrix = W_CacheLumpNum (lumpnum+ML_REJECT,PU_LEVEL);
916         P_GroupLines ();
917
918         bodyqueslot = 0;
919         deathmatch_p = deathmatchstarts;
920         P_InitAmbientSound();
921         P_InitMonsters();
922         P_OpenWeapons();
923         P_LoadThings(lumpnum+ML_THINGS);
924         P_CloseWeapons();
925
926 //
927 // if deathmatch, randomly spawn the active players
928 //
929         TimerGame = 0;
930         if(deathmatch)
931         {
932                 for (i=0 ; i<MAXPLAYERS ; i++)
933                 {
934                         if (playeringame[i])
935                         {       // must give a player spot before deathmatchspawn
936                                 mobj = P_SpawnMobj (playerstarts[i].x<<16,
937                                 playerstarts[i].y<<16,0, MT_PLAYER);
938                                 players[i].mo = mobj;
939                                 G_DeathMatchSpawnPlayer (i);
940                                 P_RemoveMobj (mobj);
941                         }
942                 }
943                 parm = M_CheckParm("-timer");
944                 if(parm && parm < myargc-1)
945                 {
946                         TimerGame = atoi(myargv[parm+1])*35*60;
947                 }
948         }
949
950 // set up world state
951         P_SpawnSpecials ();
952         
953 // build subsector connect matrix
954 //      P_ConnectSubsectors ();
955
956 // preload graphics
957         if (precache)
958                 R_PrecacheLevel ();
959
960 //printf ("free memory: 0x%x\n", Z_FreeMemory());
961
962 }
963
964
965 /*
966 =================
967 =
968 = P_Init
969 =
970 =================
971 */
972
973 void P_Init (void)
974 {       
975         P_InitSwitchList();
976         P_InitPicAnims();
977         P_InitTerrainTypes();
978         P_InitLava();
979         R_InitSprites(sprnames);
980 }