]> icculus.org git repositories - theoddone33/hheretic.git/blob - base/r_segs.c
Initial revision
[theoddone33/hheretic.git] / base / r_segs.c
1
2 //**************************************************************************
3 //**
4 //** R_SEGS.C
5 //**
6 //** This version has the tall-sector-crossing-precision-bug fixed.
7 //**
8 //**************************************************************************
9
10 #include "doomdef.h"
11 #include "r_local.h"
12
13 // OPTIMIZE: closed two sided lines as single sided
14
15 boolean         segtextured;    // true if any of the segs textures might be vis
16 boolean         markfloor;              // false if the back side is the same plane
17 boolean         markceiling;
18 boolean         maskedtexture;
19 int                     toptexture, bottomtexture, midtexture;
20
21
22 angle_t         rw_normalangle;
23 int                     rw_angle1;              // angle to line origin
24
25 //
26 // wall
27 //
28 int                     rw_x;
29 int                     rw_stopx;
30 angle_t         rw_centerangle;
31 fixed_t         rw_offset;
32 fixed_t         rw_distance;
33 fixed_t         rw_scale;
34 fixed_t         rw_scalestep;
35 fixed_t         rw_midtexturemid;
36 fixed_t         rw_toptexturemid;
37 fixed_t         rw_bottomtexturemid;
38
39 int                     worldtop, worldbottom, worldhigh, worldlow;
40
41 fixed_t         pixhigh, pixlow;
42 fixed_t         pixhighstep, pixlowstep;
43 fixed_t         topfrac, topstep;
44 fixed_t         bottomfrac, bottomstep;
45
46
47 lighttable_t    **walllights;
48
49 short           *maskedtexturecol;
50
51 #ifdef RENDER3D
52 void R_RenderMaskedSegRange (drawseg_t *ds, int x1, int x2) {}
53 void R_RenderSegLoop (void) {}
54 void R_StoreWallRange (int start, int stop) {}
55 #else
56
57 /*
58 ================
59 =
60 = R_RenderMaskedSegRange
61 =
62 ================
63 */
64
65 void R_RenderMaskedSegRange (drawseg_t *ds, int x1, int x2)
66 {
67         unsigned        index;
68         column_t        *col;
69         int                     lightnum;
70         int                     texnum;
71
72 //
73 // calculate light table
74 // use different light tables for horizontal / vertical / diagonal
75 // OPTIMIZE: get rid of LIGHTSEGSHIFT globally
76         curline = ds->curline;
77         frontsector = curline->frontsector;
78         backsector = curline->backsector;
79         texnum = texturetranslation[curline->sidedef->midtexture];
80
81         lightnum = (frontsector->lightlevel >> LIGHTSEGSHIFT)+extralight;
82         if (curline->v1->y == curline->v2->y)
83                 lightnum--;
84         else if (curline->v1->x == curline->v2->x)
85                 lightnum++;
86         if (lightnum < 0)
87                 walllights = scalelight[0];
88         else if (lightnum >= LIGHTLEVELS)
89                 walllights = scalelight[LIGHTLEVELS-1];
90         else
91                 walllights = scalelight[lightnum];
92
93         maskedtexturecol = ds->maskedtexturecol;
94
95         rw_scalestep = ds->scalestep;
96         spryscale = ds->scale1 + (x1 - ds->x1)*rw_scalestep;
97         mfloorclip = ds->sprbottomclip;
98         mceilingclip = ds->sprtopclip;
99
100 //
101 // find positioning
102 //
103         if (curline->linedef->flags & ML_DONTPEGBOTTOM)
104         {
105                 dc_texturemid = frontsector->floorheight > backsector->floorheight
106                 ? frontsector->floorheight : backsector->floorheight;
107                 dc_texturemid = dc_texturemid + textureheight[texnum] - viewz;
108         }
109         else
110         {
111                 dc_texturemid =frontsector->ceilingheight<backsector->ceilingheight
112                 ? frontsector->ceilingheight : backsector->ceilingheight;
113                 dc_texturemid = dc_texturemid - viewz;
114         }
115         dc_texturemid += curline->sidedef->rowoffset;
116
117         if (fixedcolormap)
118                 dc_colormap = fixedcolormap;
119 //
120 // draw the columns
121 //
122         for (dc_x = x1 ; dc_x <= x2 ; dc_x++)
123         {
124         // calculate lighting
125                 if (maskedtexturecol[dc_x] != MAXSHORT)
126                 {
127                         if (!fixedcolormap)
128                         {
129                                 index = spryscale>>LIGHTSCALESHIFT;
130                                 if (index >=  MAXLIGHTSCALE )
131                                         index = MAXLIGHTSCALE-1;
132                                 dc_colormap = walllights[index];
133                         }
134
135                         sprtopscreen = centeryfrac - FixedMul(dc_texturemid, spryscale);
136                         dc_iscale = 0xffffffffu / (unsigned)spryscale;
137
138         //
139         // draw the texture
140         //
141                         col = (column_t *)(
142                                 (byte *)R_GetColumn(texnum,maskedtexturecol[dc_x]) -3);
143
144                         R_DrawMaskedColumn (col, -1);
145                         maskedtexturecol[dc_x] = MAXSHORT;
146                 }
147                 spryscale += rw_scalestep;
148         }
149
150 }
151
152 /*
153 ================
154 =
155 = R_RenderSegLoop
156 =
157 = Draws zero, one, or two textures (and possibly a masked texture) for walls
158 = Can draw or mark the starting pixel of floor and ceiling textures
159 =
160 = CALLED: CORE LOOPING ROUTINE
161 ================
162 */
163
164 #define HEIGHTBITS      12
165 #define HEIGHTUNIT      (1<<HEIGHTBITS)
166
167 void R_RenderSegLoop (void)
168 {
169         angle_t         angle;
170         unsigned        index;
171         int                     yl, yh, mid;
172         fixed_t         texturecolumn=0;
173         int                     top, bottom;
174
175 //      texturecolumn = 0;                              // shut up compiler warning
176
177         for ( ; rw_x < rw_stopx ; rw_x++)
178         {
179 //
180 // mark floor / ceiling areas
181 //
182                 yl = (topfrac+HEIGHTUNIT-1)>>HEIGHTBITS;
183                 if (yl < ceilingclip[rw_x]+1)
184                         yl = ceilingclip[rw_x]+1;       // no space above wall
185                 if (markceiling)
186                 {
187                         top = ceilingclip[rw_x]+1;
188                         bottom = yl-1;
189                         if (bottom >= floorclip[rw_x])
190                                 bottom = floorclip[rw_x]-1;
191                         if (top <= bottom)
192                         {
193                                 ceilingplane->top[rw_x] = top;
194                                 ceilingplane->bottom[rw_x] = bottom;
195                         }
196                 }
197
198                 yh = bottomfrac>>HEIGHTBITS;
199                 if (yh >= floorclip[rw_x])
200                         yh = floorclip[rw_x]-1;
201                 if (markfloor)
202                 {
203                         top = yh+1;
204                         bottom = floorclip[rw_x]-1;
205                         if (top <= ceilingclip[rw_x])
206                                 top = ceilingclip[rw_x]+1;
207                         if (top <= bottom)
208                         {
209                                 floorplane->top[rw_x] = top;
210                                 floorplane->bottom[rw_x] = bottom;
211                         }
212                 }
213
214 //
215 // texturecolumn and lighting are independent of wall tiers
216 //
217                 if (segtextured)
218                 {
219                 // calculate texture offset
220                         angle = (rw_centerangle + xtoviewangle[rw_x])>>ANGLETOFINESHIFT;
221                         texturecolumn = rw_offset-FixedMul(finetangent[angle],rw_distance);
222                         texturecolumn >>= FRACBITS;
223                 // calculate lighting
224                         index = rw_scale>>LIGHTSCALESHIFT;
225                         if (index >=  MAXLIGHTSCALE )
226                                 index = MAXLIGHTSCALE-1;
227                         dc_colormap = walllights[index];
228                         dc_x = rw_x;
229                         dc_iscale = 0xffffffffu / (unsigned)rw_scale;
230                 }
231
232 //
233 // draw the wall tiers
234 //
235                 if (midtexture)
236                 {       // single sided line
237                         dc_yl = yl;
238                         dc_yh = yh;
239                         dc_texturemid = rw_midtexturemid;
240                         dc_source = R_GetColumn(midtexture,texturecolumn);
241                         colfunc ();
242                         ceilingclip[rw_x] = viewheight;
243                         floorclip[rw_x] = -1;
244                 }
245                 else
246                 {       // two sided line
247                         if (toptexture)
248                         {       // top wall
249                                 mid = pixhigh>>HEIGHTBITS;
250                                 pixhigh += pixhighstep;
251                                 if (mid >= floorclip[rw_x])
252                                         mid = floorclip[rw_x]-1;
253                                 if (mid >= yl)
254                                 {
255                                         dc_yl = yl;
256                                         dc_yh = mid;
257                                         dc_texturemid = rw_toptexturemid;
258                                         dc_source = R_GetColumn(toptexture,texturecolumn);
259                                         colfunc ();
260                                         ceilingclip[rw_x] = mid;
261                                 }
262                                 else
263                                         ceilingclip[rw_x] = yl-1;
264                         }
265                         else
266                         {       // no top wall
267                                 if (markceiling)
268                                         ceilingclip[rw_x] = yl-1;
269                         }
270
271                         if (bottomtexture)
272                         {       // bottom wall
273                                 mid = (pixlow+HEIGHTUNIT-1)>>HEIGHTBITS;
274                                 pixlow += pixlowstep;
275                                 if (mid <= ceilingclip[rw_x])
276                                         mid = ceilingclip[rw_x]+1;      // no space above wall
277                                 if (mid <= yh)
278                                 {
279                                         dc_yl = mid;
280                                         dc_yh = yh;
281                                         dc_texturemid = rw_bottomtexturemid;
282                                         dc_source = R_GetColumn(bottomtexture,
283                                                  texturecolumn);
284                                         colfunc ();
285                                         floorclip[rw_x] = mid;
286                                 }
287                                 else
288                                         floorclip[rw_x] = yh+1;
289                         }
290                         else
291                         {       // no bottom wall
292                                 if (markfloor)
293                                         floorclip[rw_x] = yh+1;
294                         }
295
296                         if (maskedtexture)
297                         {       // save texturecol for backdrawing of masked mid texture
298                                 maskedtexturecol[rw_x] = texturecolumn;
299                         }
300                 }
301
302                 rw_scale += rw_scalestep;
303                 topfrac += topstep;
304                 bottomfrac += bottomstep;
305         }
306
307 }
308
309
310
311 /*
312 =====================
313 =
314 = R_StoreWallRange
315 =
316 = A wall segment will be drawn between start and stop pixels (inclusive)
317 =
318 ======================
319 */
320
321 void R_StoreWallRange (int start, int stop)
322 {
323         fixed_t         hyp;
324         fixed_t         sineval;
325         angle_t         distangle, offsetangle;
326         fixed_t         vtop;
327         int                     lightnum;
328
329         if (ds_p == &drawsegs[MAXDRAWSEGS])
330                 return;         // don't overflow and crash
331
332 #ifdef RANGECHECK
333         if (start >=viewwidth || start > stop)
334                 I_Error ("Bad R_RenderWallRange: %i to %i", start , stop);
335 #endif
336 #ifdef __NeXT__
337         RD_DrawLine (curline);
338 #endif
339
340         sidedef = curline->sidedef;
341         linedef = curline->linedef;
342
343 // mark the segment as visible for auto map
344         linedef->flags |= ML_MAPPED;
345
346 //
347 // calculate rw_distance for scale calculation
348 //
349         rw_normalangle = curline->angle + ANG90;
350         offsetangle = abs(rw_normalangle-rw_angle1);
351         if (offsetangle > ANG90)
352                 offsetangle = ANG90;
353         distangle = ANG90 - offsetangle;
354         hyp = R_PointToDist (curline->v1->x, curline->v1->y);
355         sineval = finesine[distangle>>ANGLETOFINESHIFT];
356         rw_distance = FixedMul (hyp, sineval);
357
358
359         ds_p->x1 = rw_x = start;
360         ds_p->x2 = stop;
361         ds_p->curline = curline;
362         rw_stopx = stop+1;
363
364 //
365 // calculate scale at both ends and step
366 //
367         ds_p->scale1 = rw_scale =
368                 R_ScaleFromGlobalAngle (viewangle + xtoviewangle[start]);
369         if (stop > start )
370         {
371                 ds_p->scale2 = R_ScaleFromGlobalAngle (viewangle + xtoviewangle[stop]);
372                 ds_p->scalestep = rw_scalestep =
373                         (ds_p->scale2 - rw_scale) / (stop-start);
374         }
375         else
376         {
377         //
378         // try to fix the stretched line bug
379         //
380 #if 0
381                 if (rw_distance < FRACUNIT/2)
382                 {
383                         fixed_t         trx,try;
384                         fixed_t         gxt,gyt;
385
386                         trx = curline->v1->x - viewx;
387                         try = curline->v1->y - viewy;
388
389                         gxt = FixedMul(trx,viewcos);
390                         gyt = -FixedMul(try,viewsin);
391                         ds_p->scale1 = FixedDiv(projection, gxt-gyt);
392                 }
393 #endif
394                 ds_p->scale2 = ds_p->scale1;
395         }
396
397
398 //
399 // calculate texture boundaries and decide if floor / ceiling marks
400 // are needed
401 //
402         worldtop = frontsector->ceilingheight - viewz;
403         worldbottom = frontsector->floorheight - viewz;
404
405         midtexture = toptexture = bottomtexture = maskedtexture = 0;
406         ds_p->maskedtexturecol = NULL;
407
408         if (!backsector)
409         {
410 //
411 // single sided line
412 //
413                 midtexture = texturetranslation[sidedef->midtexture];
414                 // a single sided line is terminal, so it must mark ends
415                 markfloor = markceiling = true;
416                 if (linedef->flags & ML_DONTPEGBOTTOM)
417                 {
418                         vtop = frontsector->floorheight +
419                          textureheight[sidedef->midtexture];
420                         rw_midtexturemid = vtop - viewz;        // bottom of texture at bottom
421                 }
422                 else
423                         rw_midtexturemid = worldtop;            // top of texture at top
424                 rw_midtexturemid += sidedef->rowoffset;
425                 ds_p->silhouette = SIL_BOTH;
426                 ds_p->sprtopclip = screenheightarray;
427                 ds_p->sprbottomclip = negonearray;
428                 ds_p->bsilheight = MAXINT;
429                 ds_p->tsilheight = MININT;
430         }
431         else
432         {
433 //
434 // two sided line
435 //
436                 ds_p->sprtopclip = ds_p->sprbottomclip = NULL;
437                 ds_p->silhouette = 0;
438                 if (frontsector->floorheight > backsector->floorheight)
439                 {
440                         ds_p->silhouette = SIL_BOTTOM;
441                         ds_p->bsilheight = frontsector->floorheight;
442                 }
443                 else if (backsector->floorheight > viewz)
444                 {
445                         ds_p->silhouette = SIL_BOTTOM;
446                         ds_p->bsilheight = MAXINT;
447 //                      ds_p->sprbottomclip = negonearray;
448                 }
449                 if (frontsector->ceilingheight < backsector->ceilingheight)
450                 {
451                         ds_p->silhouette |= SIL_TOP;
452                         ds_p->tsilheight = frontsector->ceilingheight;
453                 }
454                 else if (backsector->ceilingheight < viewz)
455                 {
456                         ds_p->silhouette |= SIL_TOP;
457                         ds_p->tsilheight = MININT;
458 //                      ds_p->sprtopclip = screenheightarray;
459                 }
460
461                 if (backsector->ceilingheight <= frontsector->floorheight)
462                 {
463                         ds_p->sprbottomclip = negonearray;
464                         ds_p->bsilheight = MAXINT;
465                         ds_p->silhouette |= SIL_BOTTOM;
466                 }
467                 if (backsector->floorheight >= frontsector->ceilingheight)
468                 {
469                         ds_p->sprtopclip = screenheightarray;
470                         ds_p->tsilheight = MININT;
471                         ds_p->silhouette |= SIL_TOP;
472                 }
473                 worldhigh = backsector->ceilingheight - viewz;
474                 worldlow = backsector->floorheight - viewz;
475
476                 // hack to allow height changes in outdoor areas
477                 if (frontsector->ceilingpic == skyflatnum
478                 && backsector->ceilingpic == skyflatnum)
479                         worldtop = worldhigh;
480
481                 if (worldlow != worldbottom
482                 || backsector->floorpic != frontsector->floorpic
483                 || backsector->lightlevel != frontsector->lightlevel)
484                         markfloor = true;
485                 else
486                         markfloor = false;                              // same plane on both sides
487
488                 if (worldhigh != worldtop
489                 || backsector->ceilingpic != frontsector->ceilingpic
490                 || backsector->lightlevel != frontsector->lightlevel)
491                         markceiling = true;
492                 else
493                         markceiling = false;                    // same plane on both sides
494
495                 if (backsector->ceilingheight <= frontsector->floorheight
496                 || backsector->floorheight >= frontsector->ceilingheight)
497                         markceiling = markfloor = true;         // closed door
498
499                 if (worldhigh < worldtop)
500                 {       // top texture
501                         toptexture = texturetranslation[sidedef->toptexture];
502                         if (linedef->flags & ML_DONTPEGTOP)
503                                 rw_toptexturemid = worldtop;            // top of texture at top
504                         else
505                         {
506                                 vtop = backsector->ceilingheight +
507                                         textureheight[sidedef->toptexture];
508                                 rw_toptexturemid = vtop - viewz;        // bottom of texture
509                         }
510                 }
511                 if (worldlow > worldbottom)
512                 {       // bottom texture
513                         bottomtexture = texturetranslation[sidedef->bottomtexture];
514                         if (linedef->flags & ML_DONTPEGBOTTOM )
515                         {               // bottom of texture at bottom
516                                 rw_bottomtexturemid = worldtop;// top of texture at top
517                         }
518                         else    // top of texture at top
519                                 rw_bottomtexturemid = worldlow;
520                 }
521                 rw_toptexturemid += sidedef->rowoffset;
522                 rw_bottomtexturemid += sidedef->rowoffset;
523
524                 //
525                 // allocate space for masked texture tables
526                 //
527                 if (sidedef->midtexture)
528                 {       // masked midtexture
529                         maskedtexture = true;
530                         ds_p->maskedtexturecol = maskedtexturecol = lastopening - rw_x;
531                         lastopening += rw_stopx - rw_x;
532                 }
533         }
534
535 //
536 // calculate rw_offset (only needed for textured lines)
537 //
538         segtextured = midtexture | toptexture | bottomtexture | maskedtexture;
539
540         if (segtextured)
541         {
542                 offsetangle = rw_normalangle-rw_angle1;
543                 if (offsetangle > ANG180)
544                         offsetangle = -offsetangle;
545                 if (offsetangle > ANG90)
546                         offsetangle = ANG90;
547                 sineval = finesine[offsetangle >>ANGLETOFINESHIFT];
548                 rw_offset = FixedMul (hyp, sineval);
549                 if (rw_normalangle-rw_angle1 < ANG180)
550                         rw_offset = -rw_offset;
551                 rw_offset += sidedef->textureoffset + curline->offset;
552                 rw_centerangle = ANG90 + viewangle - rw_normalangle;
553
554         //
555         // calculate light table
556         // use different light tables for horizontal / vertical / diagonal
557         // OPTIMIZE: get rid of LIGHTSEGSHIFT globally
558                 if (!fixedcolormap)
559                 {
560                         lightnum = (frontsector->lightlevel >> LIGHTSEGSHIFT)+extralight;
561                         if (curline->v1->y == curline->v2->y)
562                                 lightnum--;
563                         else if (curline->v1->x == curline->v2->x)
564                                 lightnum++;
565                         if (lightnum < 0)
566                                 walllights = scalelight[0];
567                         else if (lightnum >= LIGHTLEVELS)
568                                 walllights = scalelight[LIGHTLEVELS-1];
569                         else
570                                 walllights = scalelight[lightnum];
571                 }
572         }
573
574
575 //
576 // if a floor / ceiling plane is on the wrong side of the view plane
577 // it is definately invisible and doesn't need to be marked
578 //
579         if (frontsector->floorheight >= viewz)
580                 markfloor = false;                              // above view plane
581         if (frontsector->ceilingheight <= viewz
582         && frontsector->ceilingpic != skyflatnum)
583                 markceiling = false;                    // below view plane
584
585 //
586 // calculate incremental stepping values for texture edges
587 //
588         worldtop >>= 4;
589         worldbottom >>= 4;
590
591         topstep = -FixedMul (rw_scalestep, worldtop);
592         topfrac = (centeryfrac>>4) - FixedMul (worldtop, rw_scale);
593
594         bottomstep = -FixedMul (rw_scalestep,worldbottom);
595         bottomfrac = (centeryfrac>>4) - FixedMul (worldbottom, rw_scale);
596
597         if (backsector)
598         {
599                 worldhigh >>= 4;
600                 worldlow >>= 4;
601
602                 if (worldhigh < worldtop)
603                 {
604                         pixhigh = (centeryfrac>>4) - FixedMul (worldhigh, rw_scale);
605                         pixhighstep = -FixedMul (rw_scalestep,worldhigh);
606                 }
607                 if (worldlow > worldbottom)
608                 {
609                         pixlow = (centeryfrac>>4) - FixedMul (worldlow, rw_scale);
610                         pixlowstep = -FixedMul (rw_scalestep,worldlow);
611                 }
612         }
613
614 //
615 // render it
616 //
617         if (markceiling)
618                 ceilingplane = R_CheckPlane (ceilingplane, rw_x, rw_stopx-1);
619         if (markfloor)
620                 floorplane = R_CheckPlane (floorplane, rw_x, rw_stopx-1);
621
622         R_RenderSegLoop ();
623
624 //
625 // save sprite clipping info
626 //
627         if ( ((ds_p->silhouette & SIL_TOP) || maskedtexture) && !ds_p->sprtopclip)
628         {
629                 memcpy (lastopening, ceilingclip+start, 2*(rw_stopx-start));
630                 ds_p->sprtopclip = lastopening - start;
631                 lastopening += rw_stopx - start;
632         }
633         if ( ((ds_p->silhouette & SIL_BOTTOM) || maskedtexture) && !ds_p->sprbottomclip)
634         {
635                 memcpy (lastopening, floorclip+start, 2*(rw_stopx-start));
636                 ds_p->sprbottomclip = lastopening - start;
637                 lastopening += rw_stopx - start;
638         }
639         if (maskedtexture && !(ds_p->silhouette&SIL_TOP))
640         {
641                 ds_p->silhouette |= SIL_TOP;
642                 ds_p->tsilheight = MININT;
643         }
644         if (maskedtexture && !(ds_p->silhouette&SIL_BOTTOM))
645         {
646                 ds_p->silhouette |= SIL_BOTTOM;
647                 ds_p->bsilheight = MAXINT;
648         }
649         ds_p++;
650 }
651 #endif