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