]> icculus.org git repositories - theoddone33/hheretic.git/blob - base/p_setup.c
Menu fonts working, drawpatch fix
[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 carver.\n");
657
658                 // Make room for the new vertex.
659                 memmove(edgepoints+endIdx+1, edgepoints+endIdx,
660                     (numedgepoints-endIdx-1)*sizeof(fvertex_t));
661                 memcpy(edgepoints+endIdx, &newvert, sizeof(newvert));
662
663                 memmove(sidelist+endIdx+1, sidelist+endIdx,
664 numedgepoints-endIdx-1);
665                 sidelist[endIdx] = 1;
666
667                 // Skip over the new vertex.
668                 k++;
669             }
670         }
671
672         // Now we must discard the points that are on the wrong side.
673         for(k=0; k<numedgepoints; k++)
674             if(!sidelist[k])
675             {
676                 memmove(edgepoints+k, edgepoints+k+1,
677 (numedgepoints-k-1)*sizeof(fvertex_t));
678                 memmove(sidelist+k, sidelist+k+1, numedgepoints-k-1);
679                 numedgepoints--;
680                 k--;
681             }
682     }
683
684     if(!numedgepoints)
685     {
686         //I_Error("All carved away!\n");
687         printf( "All carved away: subsector %p\n", ssec);
688         ssec->numedgeverts = 0;
689         ssec->edgeverts = 0;
690         ssec->origedgeverts = 0;
691     }
692     else
693     {
694         // Screen out consecutive identical points.
695         for(i=0; i<numedgepoints; i++)
696         {
697             int previdx = i-1;
698             if(previdx < 0) previdx = numedgepoints-1;
699             if(edgepoints[i].x == edgepoints[previdx].x
700                 && edgepoints[i].y == edgepoints[previdx].y)
701             {
702                 // This point (i) must be removed.
703                 memmove(edgepoints+i, edgepoints+i+1,
704 sizeof(fvertex_t)*(numedgepoints-i-1));
705                 numedgepoints--;
706                 i--;
707             }
708         }
709         // We need these with dynamic lights.
710         ssec->origedgeverts =
711 (fvertex_t*)Z_Malloc(sizeof(fvertex_t)*numedgepoints, PU_LEVEL, 0);
712         memcpy(ssec->origedgeverts, edgepoints, sizeof(fvertex_t)*numedgepoints);
713
714         // Find the center point. Do this by first finding the bounding box.
715         ssec->bbox[0].x = ssec->bbox[1].x = edgepoints[0].x;
716         ssec->bbox[0].y = ssec->bbox[1].y = edgepoints[0].y;
717         for(i=1; i<numedgepoints; i++)
718         {
719             if(edgepoints[i].x < ssec->bbox[0].x) ssec->bbox[0].x =
720 edgepoints[i].x;
721             if(edgepoints[i].y < ssec->bbox[0].y) ssec->bbox[0].y =
722 edgepoints[i].y;
723             if(edgepoints[i].x > ssec->bbox[1].x) ssec->bbox[1].x =
724 edgepoints[i].x;
725             if(edgepoints[i].y > ssec->bbox[1].y) ssec->bbox[1].y =
726 edgepoints[i].y;
727         }
728         ssec->midpoint.x = (ssec->bbox[1].x+ssec->bbox[0].x)/2;
729         ssec->midpoint.y = (ssec->bbox[1].y+ssec->bbox[0].y)/2;
730
731         // Make slight adjustments to patch up those ugly, small gaps.
732         for(i=0; i<numedgepoints; i++)
733         {
734             float dx = edgepoints[i].x - ssec->midpoint.x,
735                 dy = edgepoints[i].y - ssec->midpoint.y;
736             float dlen = (float) sqrt(dx*dx + dy*dy) * 3;
737             if(dlen)
738             {
739                 edgepoints[i].x += dx/dlen;
740                 edgepoints[i].y += dy/dlen;
741             }
742         }
743
744         ssec->numedgeverts = numedgepoints;
745         ssec->edgeverts =
746 (fvertex_t*)Z_Malloc(sizeof(fvertex_t)*numedgepoints,PU_LEVEL,0);
747         memcpy(ssec->edgeverts, edgepoints, sizeof(fvertex_t)*numedgepoints);
748     }
749
750     // We're done, free the edgepoints memory.
751     free(edgepoints);
752     Z_Free(clippers);
753 }
754
755
756 void P_CreateFloorsAndCeilings( int bspnode, int numdivlines,
757                                 divline_t* divlines )
758 {
759     node_t      *nod;
760     divline_t   *childlist, *dl;
761     int         childlistsize = numdivlines+1;
762
763     // If this is a subsector we are dealing with, begin carving with the
764     // given list.
765     if(bspnode & NF_SUBSECTOR)
766     {
767
768         // We have arrived at a subsector. The divline list contains all
769         // the partition lines that carve out the subsector.
770
771         //printf( "subsector %d: %d
772         //divlines\n",bspnode&(~NF_SUBSECTOR),numdivlines);
773
774         int ssidx = bspnode & (~NF_SUBSECTOR);
775         //if(ssidx < 10)
776         P_ConvexCarver(subsectors+ssidx, numdivlines, divlines);
777
778         //printf( "subsector %d: %d edgeverts\n", ssidx,
779         //subsectors[ssidx].numedgeverts);
780         // This leaf is done.
781         return;
782     }
783
784     // Get a pointer to the node.
785     nod = nodes + bspnode;
786
787     // Allocate a new list for each child.
788     childlist = (divline_t*)malloc(childlistsize*sizeof(divline_t));
789
790     // Copy the previous lines.
791     if(divlines) memcpy(childlist,divlines,numdivlines*sizeof(divline_t));
792
793     dl = childlist + numdivlines;
794     dl->x = nod->x;
795     dl->y = nod->y;
796     // The right child gets the original line (LEFT side clipped).
797     dl->dx = nod->dx;
798     dl->dy = nod->dy;
799     P_CreateFloorsAndCeilings(nod->children[0],childlistsize,childlist);
800
801     // The left side. We must reverse the line, otherwise the wrong
802     // side would get clipped.
803     dl->dx = -nod->dx;
804     dl->dy = -nod->dy;
805     P_CreateFloorsAndCeilings(nod->children[1],childlistsize,childlist);
806
807     // We are finishing with this node, free the allocated list.
808     free(childlist);
809 }
810
811
812 void P_SkyFix()
813 {
814     int         i;
815
816     // We need to check all the linedefs.
817     for(i=0; i<numlines; i++)
818     {
819         line_t *line = lines + i;
820         sector_t *front = line->frontsector, *back = line->backsector;
821         int fix = 0;
822         // The conditions!
823         if(!front || !back) continue;
824         // Both the front and back sectors must have the sky ceiling.
825         if(front->ceilingpic != skyflatnum || back->ceilingpic != skyflatnum)
826             continue;
827         // Operate on the lower sector.
828         /*ST_Message("Line %d (f:%d, b:%d).\n", i, front->ceilingheight >>
829          * FRACBITS,
830             back->ceilingheight >> FRACBITS);*/
831         if(front->ceilingheight < back->ceilingheight)
832         {
833             fix = (back->ceilingheight-front->ceilingheight) >> FRACBITS;
834             if(fix > front->skyfix) front->skyfix = fix;
835         }
836         else if(front->ceilingheight > back->ceilingheight)
837         {
838             fix = (front->ceilingheight-back->ceilingheight) >> FRACBITS;
839             if(fix > back->skyfix) back->skyfix = fix;
840         }
841     }
842 }
843 #endif
844
845 //=============================================================================
846
847
848 /*
849 =================
850 =
851 = P_SetupLevel
852 =
853 =================
854 */
855
856 void P_SetupLevel (int episode, int map, int playermask, skill_t skill)
857 {
858         int i;
859         int parm;
860         char    lumpname[9];
861         int             lumpnum;
862         mobj_t  *mobj;
863         
864         totalkills = totalitems = totalsecret = 0;
865         for (i=0 ; i<MAXPLAYERS ; i++)
866         {
867                 players[i].killcount = players[i].secretcount 
868                 = players[i].itemcount = 0;
869         }
870         players[consoleplayer].viewz = 1; // will be set by player think
871         
872         S_Start ();                     // make sure all sounds are stopped before Z_FreeTags
873         
874         Z_FreeTags (PU_LEVEL, PU_PURGELEVEL-1);
875
876 #ifdef RENDER3D
877     OGL_ResetData();
878 #endif
879         
880         P_InitThinkers ();
881         
882 //
883 // look for a regular (development) map first
884 //
885         lumpname[0] = 'E';
886         lumpname[1] = '0' + episode;
887         lumpname[2] = 'M';
888         lumpname[3] = '0' + map;
889         lumpname[4] = 0;
890         leveltime = 0;
891         
892         lumpnum = W_GetNumForName (lumpname);
893         
894 // note: most of this ordering is important     
895         P_LoadBlockMap (lumpnum+ML_BLOCKMAP);
896         P_LoadVertexes (lumpnum+ML_VERTEXES);
897         P_LoadSectors (lumpnum+ML_SECTORS);
898         P_LoadSideDefs (lumpnum+ML_SIDEDEFS);
899
900         P_LoadLineDefs (lumpnum+ML_LINEDEFS);
901         P_LoadSubsectors (lumpnum+ML_SSECTORS);
902         P_LoadNodes (lumpnum+ML_NODES);
903         P_LoadSegs (lumpnum+ML_SEGS);
904
905 #ifdef RENDER3D
906     // We need to carve out the floor/ceiling polygons of each subsector.
907     // Walk the tree to do this.
908     //ST_Message( "Floor/ceiling creation: begin at %d, ", ticcount);
909     P_CreateFloorsAndCeilings(numnodes-1, 0, 0);
910     // Also check if the sky needs a fix.
911     P_SkyFix();
912 #endif
913         
914         rejectmatrix = W_CacheLumpNum (lumpnum+ML_REJECT,PU_LEVEL);
915         P_GroupLines ();
916
917         bodyqueslot = 0;
918         deathmatch_p = deathmatchstarts;
919         P_InitAmbientSound();
920         P_InitMonsters();
921         P_OpenWeapons();
922         P_LoadThings(lumpnum+ML_THINGS);
923         P_CloseWeapons();
924
925 //
926 // if deathmatch, randomly spawn the active players
927 //
928         TimerGame = 0;
929         if(deathmatch)
930         {
931                 for (i=0 ; i<MAXPLAYERS ; i++)
932                 {
933                         if (playeringame[i])
934                         {       // must give a player spot before deathmatchspawn
935                                 mobj = P_SpawnMobj (playerstarts[i].x<<16,
936                                 playerstarts[i].y<<16,0, MT_PLAYER);
937                                 players[i].mo = mobj;
938                                 G_DeathMatchSpawnPlayer (i);
939                                 P_RemoveMobj (mobj);
940                         }
941                 }
942                 parm = M_CheckParm("-timer");
943                 if(parm && parm < myargc-1)
944                 {
945                         TimerGame = atoi(myargv[parm+1])*35*60;
946                 }
947         }
948
949 // set up world state
950         P_SpawnSpecials ();
951         
952 // build subsector connect matrix
953 //      P_ConnectSubsectors ();
954
955 // preload graphics
956         if (precache)
957                 R_PrecacheLevel ();
958
959 //printf ("free memory: 0x%x\n", Z_FreeMemory());
960
961 }
962
963
964 /*
965 =================
966 =
967 = P_Init
968 =
969 =================
970 */
971
972 void P_Init (void)
973 {       
974         P_InitSwitchList();
975         P_InitPicAnims();
976         P_InitTerrainTypes();
977         P_InitLava();
978         R_InitSprites(sprnames);
979 }