1 /* $Id: ntmap.c,v 1.9 2004-08-28 23:17:45 schaffner Exp $ */
3 THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
4 SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO
5 END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
6 ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
7 IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
8 SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
9 FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
10 CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS
11 AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.
12 COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED.
17 * Start of conversion to new texture mapper.
26 static char rcsid[] = "$Id: ntmap.c,v 1.9 2004-08-28 23:17:45 schaffner Exp $";
32 #define HEADLIGHT_LIGHTING 0
50 #define EDITOR_TMAP 1 //if in, include extra stuff
53 #define F15_5 (F1_0*15 + F0_5)
55 // Temporary texture map, interface from Matt's 3d system to Mike's texture mapper.
58 grs_bitmap Texmap_ptrs[NUM_TMAPS];
59 grs_bitmap Texmap4_ptrs[NUM_TMAPS];
61 fix Range_max=0; // debug, kill me
63 int Interpolation_method=0; // 0 = choose best method
64 int Lighting_on=1; // initialize to no lighting
65 int Tmap_flat_flag = 0; // 1 = render texture maps as flat shaded polygons.
66 int Current_seg_depth; // HACK INTERFACE: how far away the current segment (& thus texture) is
67 int Max_perspective_depth;
71 extern int Window_clip_left, Window_clip_bot, Window_clip_right, Window_clip_top;
73 // These variables are the interface to assembler. They get set for each texture map, which is a real waste of time.
74 // They should be set only when they change, which is generally when the window bounds change. And, even still, it's
75 // a pretty bad interface.
77 unsigned char *write_buffer;
85 #define MAX_Y_POINTERS 1024
87 int y_pointers[MAX_Y_POINTERS];
89 fix fix_recip[FIX_RECIP_TABLE_SIZE];
92 int Fix_recip_table_computed=0;
94 fix fx_l, fx_u, fx_v, fx_z, fx_du_dx, fx_dv_dx, fx_dz_dx, fx_dl_dx;
95 int fx_xleft, fx_xright, fx_y;
96 unsigned char * pixptr;
98 int Transparency_on = 0;
99 int dither_intensity_lighting = 0;
101 ubyte * tmap_flat_cthru_table;
102 ubyte tmap_flat_color;
103 ubyte tmap_flat_shade_value;
107 // -------------------------------------------------------------------------------------
108 void init_fix_recip_table(void)
114 for (i=1; i<FIX_RECIP_TABLE_SIZE; i++)
115 fix_recip[i] = F1_0/i;
117 Fix_recip_table_computed = 1;
120 // -------------------------------------------------------------------------------------
121 // Initialize interface variables to assembler.
122 // These things used to be constants. This routine is now (10/6/93) getting called for
123 // every texture map. It should get called whenever the window changes, or, preferably,
124 // not at all. I'm pretty sure these variables are only being used for range checking.
125 void init_interface_vars_to_assembler(void)
129 bp = &grd_curcanv->cv_bitmap;
132 Assert(bp->bm_data!=NULL);
133 Assert(bp->bm_h <= MAX_Y_POINTERS);
135 // If bytes_per_row has changed, create new table of pointers.
136 if (bytes_per_row != (int) bp->bm_rowsize) {
139 bytes_per_row = (int) bp->bm_rowsize;
142 for (i=0; i<MAX_Y_POINTERS; i++) {
143 y_pointers[i] = y_val;
144 y_val += bytes_per_row;
148 write_buffer = (unsigned char *) bp->bm_data;
151 window_right = (int) bp->bm_w-1;
153 window_bottom = (int) bp->bm_h-1;
155 Window_clip_left = window_left;
156 Window_clip_right = window_right;
157 Window_clip_top = window_top;
158 Window_clip_bot = window_bottom;
160 window_width = bp->bm_w;
161 window_height = bp->bm_h;
163 if (!Fix_recip_table_computed)
164 init_fix_recip_table();
167 // -------------------------------------------------------------------------------------
169 extern g3ds_tmap Tmap1;
171 // -------------------------------------------------------------------------------------
172 // Returns number preceding val modulo modulus.
175 int prevmod(int val,int modulus)
181 // return (val + modulus - 1) % modulus;
185 // Returns number succeeding val modulo modulus.
188 int succmod(int val,int modulus)
195 // return (val + 1) % modulus;
198 // -------------------------------------------------------------------------------------
199 // Select topmost vertex (minimum y coordinate) and bottommost (maximum y coordinate) in
200 // texture map. If either is part of a horizontal edge, then select leftmost vertex for
201 // top, rightmost vertex for bottom.
202 // Important: Vertex is selected with integer precision. So, if there are vertices at
203 // (0.0,0.7) and (0.5,0.3), the first vertex is selected, because they y coordinates are
204 // considered the same, so the smaller x is favored.
206 // nv number of vertices
207 // v3d pointer to 3d vertices containing u,v,x2d,y2d coordinates
211 // -------------------------------------------------------------------------------------
212 void compute_y_bounds(g3ds_tmap *t, int *vlt, int *vlb, int *vrt, int *vrb,int *bottom_y_ind)
220 // Scan all vertices, set min_y_ind to vertex with smallest y coordinate.
221 min_y = f2i(t->verts[0].y2d);
224 min_x = f2i(t->verts[0].x2d);
227 for (i=1; i<t->nv; i++) {
228 if (f2i(t->verts[i].y2d) < min_y) {
229 min_y = f2i(t->verts[i].y2d);
231 min_x = f2i(t->verts[i].x2d);
232 } else if (f2i(t->verts[i].y2d) == min_y) {
233 if (f2i(t->verts[i].x2d) < min_x) {
235 min_x = f2i(t->verts[i].x2d);
238 if (f2i(t->verts[i].y2d) > max_y) {
239 max_y = f2i(t->verts[i].y2d);
244 //--removed mk, 11/27/94-- // Check for a non-upright-hourglass polygon and fix, if necessary, by bashing a y coordinate.
245 //--removed mk, 11/27/94-- // min_y_ind = index of minimum y coordinate, *bottom_y_ind = index of maximum y coordinate
246 //--removed mk, 11/27/94--{
247 //--removed mk, 11/27/94-- int max_temp, min_temp;
248 //--removed mk, 11/27/94--
249 //--removed mk, 11/27/94-- max_temp = *bottom_y_ind;
250 //--removed mk, 11/27/94-- if (*bottom_y_ind < min_y_ind)
251 //--removed mk, 11/27/94-- max_temp += t->nv;
252 //--removed mk, 11/27/94--
253 //--removed mk, 11/27/94-- for (i=min_y_ind; i<max_temp; i++) {
254 //--removed mk, 11/27/94-- if (f2i(t->verts[i%t->nv].y2d) > f2i(t->verts[(i+1)%t->nv].y2d)) {
255 //--removed mk, 11/27/94-- Int3();
256 //--removed mk, 11/27/94-- t->verts[(i+1)%t->nv].y2d = t->verts[i%t->nv].y2d;
257 //--removed mk, 11/27/94-- }
258 //--removed mk, 11/27/94-- }
259 //--removed mk, 11/27/94--
260 //--removed mk, 11/27/94-- min_temp = min_y_ind;
261 //--removed mk, 11/27/94-- if (min_y_ind < *bottom_y_ind)
262 //--removed mk, 11/27/94-- min_temp += t->nv;
263 //--removed mk, 11/27/94--
264 //--removed mk, 11/27/94-- for (i=*bottom_y_ind; i<min_temp; i++) {
265 //--removed mk, 11/27/94-- if (f2i(t->verts[i%t->nv].y2d) < f2i(t->verts[(i+1)%t->nv].y2d)) {
266 //--removed mk, 11/27/94-- Int3();
267 //--removed mk, 11/27/94-- t->verts[(i+1)%t->nv].y2d = t->verts[i%t->nv].y2d;
268 //--removed mk, 11/27/94-- }
269 //--removed mk, 11/27/94-- }
270 //--removed mk, 11/27/94--}
272 // Set "vertex left top", etc. based on vertex with topmost y coordinate
275 *vlb = prevmod(*vlt,t->nv);
276 *vrb = succmod(*vrt,t->nv);
278 // If right edge is horizontal, then advance along polygon bound until it no longer is or until all
279 // vertices have been examined.
280 // (Left edge cannot be horizontal, because *vlt is set to leftmost point with highest y coordinate.)
284 while (f2i(t->verts[*vrt].y2d) == f2i(t->verts[*vrb].y2d)) {
285 if (succmod(*vrt,t->nv) == original_vrt) {
288 *vrt = succmod(*vrt,t->nv);
289 *vrb = succmod(*vrt,t->nv);
293 // -------------------------------------------------------------------------------------
294 // Returns dx/dy given two vertices.
295 // If dy == 0, returns 0.0
296 // -------------------------------------------------------------------------------------
297 //--fix compute_dx_dy_lin(g3ds_tmap *t, int top_vertex,int bottom_vertex)
301 //-- // compute delta x with respect to y for any edge
302 //-- dy = f2i(t->verts[bottom_vertex].y2d - t->verts[top_vertex].y2d) + 1;
304 //-- return (t->verts[bottom_vertex].x2d - t->verts[top_vertex].x2d) / dy;
310 fix compute_du_dy_lin(g3ds_tmap *t, int top_vertex,int bottom_vertex, fix recip_dy)
312 return fixmul(t->verts[bottom_vertex].u - t->verts[top_vertex].u, recip_dy);
316 fix compute_dv_dy_lin(g3ds_tmap *t, int top_vertex,int bottom_vertex, fix recip_dy)
318 return fixmul(t->verts[bottom_vertex].v - t->verts[top_vertex].v, recip_dy);
321 fix compute_dl_dy_lin(g3ds_tmap *t, int top_vertex,int bottom_vertex, fix recip_dy)
323 return fixmul(t->verts[bottom_vertex].l - t->verts[top_vertex].l, recip_dy);
327 fix compute_dx_dy(g3ds_tmap *t, int top_vertex,int bottom_vertex, fix recip_dy)
329 return fixmul(t->verts[bottom_vertex].x2d - t->verts[top_vertex].x2d, recip_dy);
332 fix compute_du_dy(g3ds_tmap *t, int top_vertex,int bottom_vertex, fix recip_dy)
334 return fixmul(fixmul(t->verts[bottom_vertex].u,t->verts[bottom_vertex].z) - fixmul(t->verts[top_vertex].u,t->verts[top_vertex].z), recip_dy);
338 fix compute_dv_dy(g3ds_tmap *t, int top_vertex,int bottom_vertex, fix recip_dy)
340 return fixmul(fixmul(t->verts[bottom_vertex].v,t->verts[bottom_vertex].z) - fixmul(t->verts[top_vertex].v,t->verts[top_vertex].z), recip_dy);
344 fix compute_dz_dy(g3ds_tmap *t, int top_vertex,int bottom_vertex, fix recip_dy)
346 return fixmul(t->verts[bottom_vertex].z - t->verts[top_vertex].z, recip_dy);
349 int Skip_short_flag=0;
351 // -------------------------------------------------------------------------------------
352 // Texture map current scanline in perspective.
353 // -------------------------------------------------------------------------------------
354 void ntmap_scanline_lighted(grs_bitmap *srcb, int y, fix xleft, fix xright, fix uleft, fix uright, fix vleft, fix vright, fix zleft, fix zright, fix lleft, fix lright)
358 fx_xright = f2i(xright);
359 //edited 06/27/99 Matt Mueller - moved these tests up from within the switch so as not to do a bunch of needless calculations when we are just gonna return anyway. Slight fps boost?
360 if (fx_xright < Window_clip_left)
362 fx_xleft = f2i(xleft);
363 if (fx_xleft > Window_clip_right)
367 dx = fx_xright - fx_xleft;
368 if ((dx < 0) || (xright < 0) || (xleft > xright)) // the (xleft > xright) term is not redundant with (dx < 0) because dx is computed using integers
371 // setup to call assembler scanline renderer
372 if (dx < FIX_RECIP_TABLE_SIZE)
373 recip_dx = fix_recip[dx];
381 fx_du_dx = fixmul(uright - uleft,recip_dx);
382 fx_dv_dx = fixmul(vright - vleft,recip_dx);
383 fx_dz_dx = fixmul(zright - zleft,recip_dx);
385 pixptr = srcb->bm_data;
387 switch (Lighting_enabled) {
389 //added 05/17/99 Matt Mueller - prevent writing before the buffer
390 if ((fx_y == 0) && (fx_xleft < 0))
393 if (fx_xright > Window_clip_right)
394 fx_xright = Window_clip_right;
396 cur_tmap_scanline_per();
401 if (lleft < 0) lleft = 0;
402 if (lright < 0) lright = 0;
403 if (lleft > (NUM_LIGHTING_LEVELS*F1_0-F1_0/2)) lleft = (NUM_LIGHTING_LEVELS*F1_0-F1_0/2);
404 if (lright > (NUM_LIGHTING_LEVELS*F1_0-F1_0/2)) lright = (NUM_LIGHTING_LEVELS*F1_0-F1_0/2);
407 fx_dl_dx = fixmul(lright - lleft,recip_dx);
409 // This is a pretty ugly hack to prevent lighting overflows.
410 mul_thing = dx * fx_dl_dx;
411 if (lleft + mul_thing < 0)
413 else if (lleft + mul_thing > (NUM_LIGHTING_LEVELS*F1_0-F1_0/2))
416 //added 05/17/99 Matt Mueller - prevent writing before the buffer
417 if ((fx_y == 0) && (fx_xleft < 0))
420 if (fx_xright > Window_clip_right)
421 fx_xright = Window_clip_right;
423 cur_tmap_scanline_per();
428 fx_xright = f2i(xright);
429 fx_xleft = f2i(xleft);
432 cur_tmap_scanline_flat();
434 Int3(); // Illegal, called an editor only routine!
441 int Do_vertical_scan=0;
445 // -------------------------------------------------------------------------------------
446 // Render a texture map with lighting using perspective interpolation in inner and outer loops.
447 // -------------------------------------------------------------------------------------
448 void ntexture_map_lighted(grs_bitmap *srcb, g3ds_tmap *t)
450 int vlt,vrt,vlb,vrb; // vertex left top, vertex right top, vertex left bottom, vertex right bottom
452 fix dx_dy_left,dx_dy_right;
453 fix du_dy_left,du_dy_right;
454 fix dv_dy_left,dv_dy_right;
455 fix dz_dy_left,dz_dy_right;
456 fix dl_dy_left,dl_dy_right;
457 fix recip_dyl, recip_dyr;
459 fix xleft,xright,uleft,vleft,uright,vright,zleft,zright,lleft,lright;
460 int next_break_left, next_break_right;
464 //remove stupid warnings in compile
472 // Determine top and bottom y coords.
473 compute_y_bounds(t,&vlt,&vlb,&vrt,&vrb,&max_y_vertex);
475 // Set top and bottom (of entire texture map) y coordinates.
476 topy = f2i(v3d[vlt].y2d);
477 boty = f2i(v3d[max_y_vertex].y2d);
478 if (topy > Window_clip_bot)
480 if (boty > Window_clip_bot)
481 boty = Window_clip_bot;
483 // Set amount to change x coordinate for each advance to next scanline.
484 dy = f2i(t->verts[vlb].y2d) - f2i(t->verts[vlt].y2d);
485 if (dy < FIX_RECIP_TABLE_SIZE)
486 recip_dyl = fix_recip[dy];
490 dx_dy_left = compute_dx_dy(t,vlt,vlb, recip_dyl);
491 du_dy_left = compute_du_dy(t,vlt,vlb, recip_dyl);
492 dv_dy_left = compute_dv_dy(t,vlt,vlb, recip_dyl);
493 dz_dy_left = compute_dz_dy(t,vlt,vlb, recip_dyl);
495 dy = f2i(t->verts[vrb].y2d) - f2i(t->verts[vrt].y2d);
496 if (dy < FIX_RECIP_TABLE_SIZE)
497 recip_dyr = fix_recip[dy];
501 du_dy_right = compute_du_dy(t,vrt,vrb, recip_dyr);
502 dx_dy_right = compute_dx_dy(t,vrt,vrb, recip_dyr);
503 dv_dy_right = compute_dv_dy(t,vrt,vrb, recip_dyr);
504 dz_dy_right = compute_dz_dy(t,vrt,vrb, recip_dyr);
506 if (Lighting_enabled) {
507 dl_dy_left = compute_dl_dy_lin(t,vlt,vlb, recip_dyl);
508 dl_dy_right = compute_dl_dy_lin(t,vrt,vrb, recip_dyr);
514 // Set initial values for x, u, v
515 xleft = v3d[vlt].x2d;
516 xright = v3d[vrt].x2d;
521 uleft = fixmul(v3d[vlt].u,zleft);
522 uright = fixmul(v3d[vrt].u,zright);
523 vleft = fixmul(v3d[vlt].v,zleft);
524 vright = fixmul(v3d[vrt].v,zright);
526 // scan all rows in texture map from top through first break.
527 next_break_left = f2i(v3d[vlb].y2d);
528 next_break_right = f2i(v3d[vrb].y2d);
530 for (y = topy; y < boty; y++) {
532 // See if we have reached the end of the current left edge, and if so, set
533 // new values for dx_dy and x,u,v
534 if (y == next_break_left) {
537 // Handle problem of double points. Search until y coord is different. Cannot get
538 // hung in an infinite loop because we know there is a vertex with a lower y coordinate
539 // because in the for loop, we don't scan all spanlines.
540 while (y == f2i(v3d[vlb].y2d)) {
542 vlb = prevmod(vlb,t->nv);
544 next_break_left = f2i(v3d[vlb].y2d);
546 dy = f2i(t->verts[vlb].y2d) - f2i(t->verts[vlt].y2d);
547 if (dy < FIX_RECIP_TABLE_SIZE)
548 recip_dy = fix_recip[dy];
552 dx_dy_left = compute_dx_dy(t,vlt,vlb, recip_dy);
554 xleft = v3d[vlt].x2d;
556 uleft = fixmul(v3d[vlt].u,zleft);
557 vleft = fixmul(v3d[vlt].v,zleft);
560 du_dy_left = compute_du_dy(t,vlt,vlb, recip_dy);
561 dv_dy_left = compute_dv_dy(t,vlt,vlb, recip_dy);
562 dz_dy_left = compute_dz_dy(t,vlt,vlb, recip_dy);
564 if (Lighting_enabled) {
565 dl_dy_left = compute_dl_dy_lin(t,vlt,vlb, recip_dy);
570 // See if we have reached the end of the current left edge, and if so, set
571 // new values for dx_dy and x. Not necessary to set new values for u,v.
572 if (y == next_break_right) {
575 while (y == f2i(v3d[vrb].y2d)) {
577 vrb = succmod(vrb,t->nv);
580 next_break_right = f2i(v3d[vrb].y2d);
582 dy = f2i(t->verts[vrb].y2d) - f2i(t->verts[vrt].y2d);
583 if (dy < FIX_RECIP_TABLE_SIZE)
584 recip_dy = fix_recip[dy];
588 dx_dy_right = compute_dx_dy(t,vrt,vrb, recip_dy);
590 xright = v3d[vrt].x2d;
592 uright = fixmul(v3d[vrt].u,zright);
593 vright = fixmul(v3d[vrt].v,zright);
595 du_dy_right = compute_du_dy(t,vrt,vrb, recip_dy);
596 dv_dy_right = compute_dv_dy(t,vrt,vrb, recip_dy);
597 dz_dy_right = compute_dz_dy(t,vrt,vrb, recip_dy);
599 if (Lighting_enabled) {
600 dl_dy_right = compute_dl_dy_lin(t,vrt,vrb, recip_dy);
605 if (Lighting_enabled) {
606 if (y >= Window_clip_top)
607 ntmap_scanline_lighted(srcb,y,xleft,xright,uleft,uright,vleft,vright,zleft,zright,lleft,lright);
609 lright += dl_dy_right;
611 if (y >= Window_clip_top)
612 ntmap_scanline_lighted(srcb,y,xleft,xright,uleft,uright,vleft,vright,zleft,zright,lleft,lright);
617 uright += du_dy_right;
618 vright += dv_dy_right;
621 xright += dx_dy_right;
624 zright += dz_dy_right;
628 // We can get lleft or lright out of bounds here because we compute dl_dy using fixed point values,
629 // but we plot an integer number of scanlines, therefore doing an integer number of additions of the delta.
632 // mprintf(0, "[%i %i %i] ", y, f2i(xleft), f2i(xright));
634 ntmap_scanline_lighted(srcb,y,xleft,xright,uleft,uright,vleft,vright,zleft,zright,lleft,lright);
638 // -------------------------------------------------------------------------------------
639 // Texture map current scanline using linear interpolation.
640 // -------------------------------------------------------------------------------------
641 void ntmap_scanline_lighted_linear(grs_bitmap *srcb, int y, fix xleft, fix xright, fix uleft, fix uright, fix vleft, fix vright, fix lleft, fix lright)
646 fix du_dx,dv_dx,dl_dx;
652 dx = f2i(xright) - f2i(xleft);
653 if ((dx < 0) || (xright < 0) || (xleft > xright)) // the (xleft > xright) term is not redundant with (dx < 0) because dx is computed using integers
656 // setup to call assembler scanline renderer
657 if (dx < FIX_RECIP_TABLE_SIZE)
658 recip_dx = fix_recip[dx];
662 du_dx = fixmul(uright - uleft,recip_dx);
663 dv_dx = fixmul(vright - vleft,recip_dx);
670 fx_xright = f2i(xright);
671 fx_xleft = f2i(xleft);
672 pixptr = srcb->bm_data;
674 switch (Lighting_enabled) {
676 //added 07/11/99 adb - prevent writing before the buffer
681 cur_tmap_scanline_lin_nolight();
689 if (lleft > MAX_LIGHTING_VALUE*NUM_LIGHTING_LEVELS)
690 lleft = MAX_LIGHTING_VALUE*NUM_LIGHTING_LEVELS;
691 if (lright > MAX_LIGHTING_VALUE*NUM_LIGHTING_LEVELS)
692 lright = MAX_LIGHTING_VALUE*NUM_LIGHTING_LEVELS;
694 //added 07/11/99 adb - prevent writing before the buffer
703 fx_dl_dx = fixmul(lright - lleft,recip_dx);
705 // This is a pretty ugly hack to prevent lighting overflows.
706 mul_thing = dx * fx_dl_dx;
707 if (lleft + mul_thing < 0)
709 else if (lleft + mul_thing > (NUM_LIGHTING_LEVELS*F1_0-F1_0/2))
714 dl_dx = fixmul(lright - lleft,recip_dx);
716 cur_tmap_scanline_lin();
720 fx_xright = f2i(xright);
721 fx_xleft = f2i(xleft);
723 cur_tmap_scanline_flat();
725 Int3(); // Illegal, called an editor only routine!
731 // -------------------------------------------------------------------------------------
732 // Render a texture map with lighting using perspective interpolation in inner and outer loops.
733 // -------------------------------------------------------------------------------------
734 void ntexture_map_lighted_linear(grs_bitmap *srcb, g3ds_tmap *t)
736 int vlt,vrt,vlb,vrb; // vertex left top, vertex right top, vertex left bottom, vertex right bottom
738 fix dx_dy_left,dx_dy_right;
739 fix du_dy_left,du_dy_right;
740 fix dv_dy_left,dv_dy_right;
741 fix dl_dy_left,dl_dy_right;
743 fix xleft,xright,uleft,vleft,uright,vright,lleft,lright;
744 int next_break_left, next_break_right;
745 fix recip_dyl, recip_dyr;
749 //remove stupid warnings in compile
757 // Determine top and bottom y coords.
758 compute_y_bounds(t,&vlt,&vlb,&vrt,&vrb,&max_y_vertex);
760 // Set top and bottom (of entire texture map) y coordinates.
761 topy = f2i(v3d[vlt].y2d);
762 boty = f2i(v3d[max_y_vertex].y2d);
764 if (topy > Window_clip_bot)
766 if (boty > Window_clip_bot)
767 boty = Window_clip_bot;
769 dy = f2i(t->verts[vlb].y2d) - f2i(t->verts[vlt].y2d);
770 if (dy < FIX_RECIP_TABLE_SIZE)
771 recip_dyl = fix_recip[dy];
775 dy = f2i(t->verts[vrb].y2d) - f2i(t->verts[vrt].y2d);
776 if (dy < FIX_RECIP_TABLE_SIZE)
777 recip_dyr = fix_recip[dy];
781 // Set amount to change x coordinate for each advance to next scanline.
782 dx_dy_left = compute_dx_dy(t,vlt,vlb, recip_dyl);
783 dx_dy_right = compute_dx_dy(t,vrt,vrb, recip_dyr);
785 du_dy_left = compute_du_dy_lin(t,vlt,vlb, recip_dyl);
786 du_dy_right = compute_du_dy_lin(t,vrt,vrb, recip_dyr);
788 dv_dy_left = compute_dv_dy_lin(t,vlt,vlb, recip_dyl);
789 dv_dy_right = compute_dv_dy_lin(t,vrt,vrb, recip_dyr);
791 if (Lighting_enabled) {
792 dl_dy_left = compute_dl_dy_lin(t,vlt,vlb, recip_dyl);
793 dl_dy_right = compute_dl_dy_lin(t,vrt,vrb, recip_dyr);
799 // Set initial values for x, u, v
800 xleft = v3d[vlt].x2d;
801 xright = v3d[vrt].x2d;
808 // scan all rows in texture map from top through first break.
809 next_break_left = f2i(v3d[vlb].y2d);
810 next_break_right = f2i(v3d[vrb].y2d);
812 for (y = topy; y < boty; y++) {
814 // See if we have reached the end of the current left edge, and if so, set
815 // new values for dx_dy and x,u,v
816 if (y == next_break_left) {
819 // Handle problem of double points. Search until y coord is different. Cannot get
820 // hung in an infinite loop because we know there is a vertex with a lower y coordinate
821 // because in the for loop, we don't scan all spanlines.
822 while (y == f2i(v3d[vlb].y2d)) {
824 vlb = prevmod(vlb,t->nv);
826 next_break_left = f2i(v3d[vlb].y2d);
828 dy = f2i(t->verts[vlb].y2d) - f2i(t->verts[vlt].y2d);
829 if (dy < FIX_RECIP_TABLE_SIZE)
830 recip_dy = fix_recip[dy];
834 dx_dy_left = compute_dx_dy(t,vlt,vlb, recip_dy);
836 xleft = v3d[vlt].x2d;
841 du_dy_left = compute_du_dy_lin(t,vlt,vlb, recip_dy);
842 dv_dy_left = compute_dv_dy_lin(t,vlt,vlb, recip_dy);
844 if (Lighting_enabled) {
845 dl_dy_left = compute_dl_dy_lin(t,vlt,vlb, recip_dy);
850 // See if we have reached the end of the current left edge, and if so, set
851 // new values for dx_dy and x. Not necessary to set new values for u,v.
852 if (y == next_break_right) {
855 while (y == f2i(v3d[vrb].y2d)) {
857 vrb = succmod(vrb,t->nv);
860 dy = f2i(t->verts[vrb].y2d) - f2i(t->verts[vrt].y2d);
861 if (dy < FIX_RECIP_TABLE_SIZE)
862 recip_dy = fix_recip[dy];
866 next_break_right = f2i(v3d[vrb].y2d);
867 dx_dy_right = compute_dx_dy(t,vrt,vrb, recip_dy);
869 xright = v3d[vrt].x2d;
873 du_dy_right = compute_du_dy_lin(t,vrt,vrb, recip_dy);
874 dv_dy_right = compute_dv_dy_lin(t,vrt,vrb, recip_dy);
876 if (Lighting_enabled) {
877 dl_dy_right = compute_dl_dy_lin(t,vrt,vrb, recip_dy);
882 if (Lighting_enabled) {
883 ntmap_scanline_lighted_linear(srcb,y,xleft,xright,uleft,uright,vleft,vright,lleft,lright);
885 lright += dl_dy_right;
887 ntmap_scanline_lighted_linear(srcb,y,xleft,xright,uleft,uright,vleft,vright,lleft,lright);
892 uright += du_dy_right;
893 vright += dv_dy_right;
896 xright += dx_dy_right;
900 // We can get lleft or lright out of bounds here because we compute dl_dy using fixed point values,
901 // but we plot an integer number of scanlines, therefore doing an integer number of additions of the delta.
903 ntmap_scanline_lighted_linear(srcb,y,xleft,xright,uleft,uright,vleft,vright,lleft,lright);
906 // fix DivNum = F1_0*12;
908 extern void draw_tmap_flat(grs_bitmap *bp,int nverts,g3s_point **vertbuf);
910 // -------------------------------------------------------------------------------------
911 // Interface from Matt's data structures to Mike's texture mapper.
912 // -------------------------------------------------------------------------------------
913 void draw_tmap(grs_bitmap *bp,int nverts,g3s_point **vertbuf)
917 // These variables are used in system which renders texture maps which lie on one scanline as a line.
918 // fix div_numerator;
919 int lighting_on_save = Lighting_on;
921 Assert(nverts <= MAX_TMAP_VERTS);
925 if ( !divide_table_filled ) fill_divide_table();
928 // -- now called from g3_start_frame -- init_interface_vars_to_assembler();
930 // If no transparency and seg depth is large, render as flat shaded.
931 if ((Current_seg_depth > Max_linear_depth) && ((bp->bm_flags & 3) == 0)) {
932 draw_tmap_flat(bp, nverts, vertbuf);
936 if ( bp->bm_flags & BM_FLAG_RLE )
937 bp = rle_expand_texture( bp ); // Expand if rle'd
939 Transparency_on = bp->bm_flags & BM_FLAG_TRANSPARENT;
940 if (bp->bm_flags & BM_FLAG_NO_LIGHTING)
944 // Setup texture map in Tmap1
945 Tmap1.nv = nverts; // Initialize number of vertices
947 // div_numerator = DivNum; //f1_0*3;
949 for (i=0; i<nverts; i++) {
950 g3ds_vertex *tvp = &Tmap1.verts[i];
951 g3s_point *vp = vertbuf[i];
953 tvp->x2d = vp->p3_sx;
954 tvp->y2d = vp->p3_sy;
956 // Check for overflow on fixdiv. Will overflow on vp->z <= something small. Allow only as low as 256.
957 if (vp->p3_z < 256) {
959 // Int3(); // we would overflow if we divided!
962 tvp->z = fixdiv(F1_0*12, vp->p3_z);
963 tvp->u = vp->p3_u << 6; //* bp->bm_w;
964 tvp->v = vp->p3_v << 6; //* bp->bm_h;
966 Assert(Lighting_on < 3);
969 tvp->l = vp->p3_l * NUM_LIGHTING_LEVELS;
973 Lighting_enabled = Lighting_on;
975 // Now, call my texture mapper.
977 switch (Interpolation_method) { // 0 = choose, 1 = linear, 2 = /8 perspective, 3 = full perspective
978 case 0: // choose best interpolation
980 if (Current_seg_depth > Max_perspective_depth)
981 ntexture_map_lighted_linear(bp, &Tmap1);
983 ntexture_map_lighted(bp, &Tmap1);
985 case 1: // linear interpolation
987 ntexture_map_lighted_linear(bp, &Tmap1);
989 case 2: // perspective every 8th pixel interpolation
991 ntexture_map_lighted(bp, &Tmap1);
993 case 3: // perspective every pixel interpolation
994 per2_flag = 0; // this hack means do divide every pixel
995 ntexture_map_lighted(bp, &Tmap1);
998 Assert(0); // Illegal value for Interpolation_method, must be 0,1,2,3
1001 switch (Interpolation_method) { // 0 = choose, 1 = linear, 2 = /8 perspective, 3 = full perspective
1002 case 0: // choose best interpolation
1004 if (Current_seg_depth > Max_perspective_depth)
1005 ntexture_map_lighted_linear(bp, &Tmap1);
1007 ntexture_map_lighted(bp, &Tmap1);
1009 case 1: // linear interpolation
1011 ntexture_map_lighted_linear(bp, &Tmap1);
1013 case 2: // perspective every 8th pixel interpolation
1015 ntexture_map_lighted(bp, &Tmap1);
1017 case 3: // perspective every pixel interpolation
1018 per2_flag = 0; // this hack means do divide every pixel
1019 ntexture_map_lighted(bp, &Tmap1);
1022 Assert(0); // Illegal value for Interpolation_method, must be 0,1,2,3
1026 Lighting_on = lighting_on_save;