2 THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
3 SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO
4 END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
5 ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
6 IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
7 SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
8 FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
9 CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS
10 AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.
11 COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED.
16 * Start of conversion to new texture mapper.
27 #define HEADLIGHT_LIGHTING 0
43 #define EDITOR_TMAP 1 //if in, include extra stuff
46 #define F15_5 (F1_0*15 + F0_5)
48 // Temporary texture map, interface from Matt's 3d system to Mike's texture mapper.
51 grs_bitmap Texmap_ptrs[NUM_TMAPS];
52 grs_bitmap Texmap4_ptrs[NUM_TMAPS];
54 fix Range_max=0; // debug, kill me
56 int Interpolation_method=0; // 0 = choose best method
57 int Lighting_on=1; // initialize to no lighting
58 int Tmap_flat_flag = 0; // 1 = render texture maps as flat shaded polygons.
59 int Current_seg_depth; // HACK INTERFACE: how far away the current segment (& thus texture) is
60 int Max_perspective_depth;
64 int Window_clip_left, Window_clip_bot, Window_clip_right, Window_clip_top;
66 // These variables are the interface to assembler. They get set for each texture map, which is a real waste of time.
67 // They should be set only when they change, which is generally when the window bounds change. And, even still, it's
68 // a pretty bad interface.
70 unsigned char *write_buffer;
78 #define MAX_Y_POINTERS 1024
80 int y_pointers[MAX_Y_POINTERS];
82 fix fix_recip[FIX_RECIP_TABLE_SIZE];
85 int Fix_recip_table_computed=0;
87 fix fx_l, fx_u, fx_v, fx_z, fx_du_dx, fx_dv_dx, fx_dz_dx, fx_dl_dx;
88 int fx_xleft, fx_xright, fx_y;
89 unsigned char * pixptr;
91 int Transparency_on = 0;
92 int dither_intensity_lighting = 0;
94 ubyte * tmap_flat_cthru_table;
95 ubyte tmap_flat_color;
96 ubyte tmap_flat_shade_value;
100 // -------------------------------------------------------------------------------------
101 void init_fix_recip_table(void)
107 for (i=1; i<FIX_RECIP_TABLE_SIZE; i++)
108 fix_recip[i] = F1_0/i;
110 Fix_recip_table_computed = 1;
113 // -------------------------------------------------------------------------------------
114 // Initialize interface variables to assembler.
115 // These things used to be constants. This routine is now (10/6/93) getting called for
116 // every texture map. It should get called whenever the window changes, or, preferably,
117 // not at all. I'm pretty sure these variables are only being used for range checking.
118 void init_interface_vars_to_assembler(void)
122 bp = &grd_curcanv->cv_bitmap;
125 Assert(bp->bm_data!=NULL);
126 Assert(bp->bm_h <= MAX_Y_POINTERS);
128 // If bytes_per_row has changed, create new table of pointers.
129 if (bytes_per_row != (int) bp->bm_rowsize) {
132 bytes_per_row = (int) bp->bm_rowsize;
135 for (i=0; i<MAX_Y_POINTERS; i++) {
136 y_pointers[i] = y_val;
137 y_val += bytes_per_row;
141 write_buffer = (unsigned char *) bp->bm_data;
144 window_right = (int) bp->bm_w-1;
146 window_bottom = (int) bp->bm_h-1;
148 Window_clip_left = window_left;
149 Window_clip_right = window_right;
150 Window_clip_top = window_top;
151 Window_clip_bot = window_bottom;
153 window_width = bp->bm_w;
154 window_height = bp->bm_h;
156 if (!Fix_recip_table_computed)
157 init_fix_recip_table();
160 // -------------------------------------------------------------------------------------
162 extern g3ds_tmap Tmap1;
164 // -------------------------------------------------------------------------------------
165 // Returns number preceding val modulo modulus.
168 int prevmod(int val,int modulus)
174 // return (val + modulus - 1) % modulus;
178 // Returns number succeeding val modulo modulus.
181 int succmod(int val,int modulus)
188 // return (val + 1) % modulus;
191 // -------------------------------------------------------------------------------------
192 // Select topmost vertex (minimum y coordinate) and bottommost (maximum y coordinate) in
193 // texture map. If either is part of a horizontal edge, then select leftmost vertex for
194 // top, rightmost vertex for bottom.
195 // Important: Vertex is selected with integer precision. So, if there are vertices at
196 // (0.0,0.7) and (0.5,0.3), the first vertex is selected, because they y coordinates are
197 // considered the same, so the smaller x is favored.
199 // nv number of vertices
200 // v3d pointer to 3d vertices containing u,v,x2d,y2d coordinates
204 // -------------------------------------------------------------------------------------
205 void compute_y_bounds(g3ds_tmap *t, int *vlt, int *vlb, int *vrt, int *vrb,int *bottom_y_ind)
213 // Scan all vertices, set min_y_ind to vertex with smallest y coordinate.
214 min_y = f2i(t->verts[0].y2d);
217 min_x = f2i(t->verts[0].x2d);
220 for (i=1; i<t->nv; i++) {
221 if (f2i(t->verts[i].y2d) < min_y) {
222 min_y = f2i(t->verts[i].y2d);
224 min_x = f2i(t->verts[i].x2d);
225 } else if (f2i(t->verts[i].y2d) == min_y) {
226 if (f2i(t->verts[i].x2d) < min_x) {
228 min_x = f2i(t->verts[i].x2d);
231 if (f2i(t->verts[i].y2d) > max_y) {
232 max_y = f2i(t->verts[i].y2d);
237 //--removed mk, 11/27/94-- // Check for a non-upright-hourglass polygon and fix, if necessary, by bashing a y coordinate.
238 //--removed mk, 11/27/94-- // min_y_ind = index of minimum y coordinate, *bottom_y_ind = index of maximum y coordinate
239 //--removed mk, 11/27/94--{
240 //--removed mk, 11/27/94-- int max_temp, min_temp;
241 //--removed mk, 11/27/94--
242 //--removed mk, 11/27/94-- max_temp = *bottom_y_ind;
243 //--removed mk, 11/27/94-- if (*bottom_y_ind < min_y_ind)
244 //--removed mk, 11/27/94-- max_temp += t->nv;
245 //--removed mk, 11/27/94--
246 //--removed mk, 11/27/94-- for (i=min_y_ind; i<max_temp; i++) {
247 //--removed mk, 11/27/94-- if (f2i(t->verts[i%t->nv].y2d) > f2i(t->verts[(i+1)%t->nv].y2d)) {
248 //--removed mk, 11/27/94-- Int3();
249 //--removed mk, 11/27/94-- t->verts[(i+1)%t->nv].y2d = t->verts[i%t->nv].y2d;
250 //--removed mk, 11/27/94-- }
251 //--removed mk, 11/27/94-- }
252 //--removed mk, 11/27/94--
253 //--removed mk, 11/27/94-- min_temp = min_y_ind;
254 //--removed mk, 11/27/94-- if (min_y_ind < *bottom_y_ind)
255 //--removed mk, 11/27/94-- min_temp += t->nv;
256 //--removed mk, 11/27/94--
257 //--removed mk, 11/27/94-- for (i=*bottom_y_ind; i<min_temp; i++) {
258 //--removed mk, 11/27/94-- if (f2i(t->verts[i%t->nv].y2d) < f2i(t->verts[(i+1)%t->nv].y2d)) {
259 //--removed mk, 11/27/94-- Int3();
260 //--removed mk, 11/27/94-- t->verts[(i+1)%t->nv].y2d = t->verts[i%t->nv].y2d;
261 //--removed mk, 11/27/94-- }
262 //--removed mk, 11/27/94-- }
263 //--removed mk, 11/27/94--}
265 // Set "vertex left top", etc. based on vertex with topmost y coordinate
268 *vlb = prevmod(*vlt,t->nv);
269 *vrb = succmod(*vrt,t->nv);
271 // If right edge is horizontal, then advance along polygon bound until it no longer is or until all
272 // vertices have been examined.
273 // (Left edge cannot be horizontal, because *vlt is set to leftmost point with highest y coordinate.)
277 while (f2i(t->verts[*vrt].y2d) == f2i(t->verts[*vrb].y2d)) {
278 if (succmod(*vrt,t->nv) == original_vrt) {
281 *vrt = succmod(*vrt,t->nv);
282 *vrb = succmod(*vrt,t->nv);
286 // -------------------------------------------------------------------------------------
287 // Returns dx/dy given two vertices.
288 // If dy == 0, returns 0.0
289 // -------------------------------------------------------------------------------------
290 //--fix compute_dx_dy_lin(g3ds_tmap *t, int top_vertex,int bottom_vertex)
294 //-- // compute delta x with respect to y for any edge
295 //-- dy = f2i(t->verts[bottom_vertex].y2d - t->verts[top_vertex].y2d) + 1;
297 //-- return (t->verts[bottom_vertex].x2d - t->verts[top_vertex].x2d) / dy;
303 fix compute_du_dy_lin(g3ds_tmap *t, int top_vertex,int bottom_vertex, fix recip_dy)
305 return fixmul(t->verts[bottom_vertex].u - t->verts[top_vertex].u, recip_dy);
309 fix compute_dv_dy_lin(g3ds_tmap *t, int top_vertex,int bottom_vertex, fix recip_dy)
311 return fixmul(t->verts[bottom_vertex].v - t->verts[top_vertex].v, recip_dy);
314 fix compute_dl_dy_lin(g3ds_tmap *t, int top_vertex,int bottom_vertex, fix recip_dy)
316 return fixmul(t->verts[bottom_vertex].l - t->verts[top_vertex].l, recip_dy);
320 fix compute_dx_dy(g3ds_tmap *t, int top_vertex,int bottom_vertex, fix recip_dy)
322 return fixmul(t->verts[bottom_vertex].x2d - t->verts[top_vertex].x2d, recip_dy);
325 fix compute_du_dy(g3ds_tmap *t, int top_vertex,int bottom_vertex, fix recip_dy)
327 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);
331 fix compute_dv_dy(g3ds_tmap *t, int top_vertex,int bottom_vertex, fix recip_dy)
333 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);
337 fix compute_dz_dy(g3ds_tmap *t, int top_vertex,int bottom_vertex, fix recip_dy)
339 return fixmul(t->verts[bottom_vertex].z - t->verts[top_vertex].z, recip_dy);
342 int Skip_short_flag=0;
344 // -------------------------------------------------------------------------------------
345 // Texture map current scanline in perspective.
346 // -------------------------------------------------------------------------------------
347 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)
351 fx_xright = f2i(xright);
352 //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?
353 if (fx_xright < Window_clip_left)
355 fx_xleft = f2i(xleft);
356 if (fx_xleft > Window_clip_right)
360 dx = fx_xright - fx_xleft;
361 if ((dx < 0) || (xright < 0) || (xleft > xright)) // the (xleft > xright) term is not redundant with (dx < 0) because dx is computed using integers
364 // setup to call assembler scanline renderer
365 if (dx < FIX_RECIP_TABLE_SIZE)
366 recip_dx = fix_recip[dx];
374 fx_du_dx = fixmul(uright - uleft,recip_dx);
375 fx_dv_dx = fixmul(vright - vleft,recip_dx);
376 fx_dz_dx = fixmul(zright - zleft,recip_dx);
378 pixptr = srcb->bm_data;
380 switch (Lighting_enabled) {
382 //added 05/17/99 Matt Mueller - prevent writing before the buffer
383 if ((fx_y == 0) && (fx_xleft < 0))
386 if (fx_xright > Window_clip_right)
387 fx_xright = Window_clip_right;
389 cur_tmap_scanline_per();
394 if (lleft < 0) lleft = 0;
395 if (lright < 0) lright = 0;
396 if (lleft > (NUM_LIGHTING_LEVELS*F1_0-F1_0/2)) lleft = (NUM_LIGHTING_LEVELS*F1_0-F1_0/2);
397 if (lright > (NUM_LIGHTING_LEVELS*F1_0-F1_0/2)) lright = (NUM_LIGHTING_LEVELS*F1_0-F1_0/2);
400 fx_dl_dx = fixmul(lright - lleft,recip_dx);
402 // This is a pretty ugly hack to prevent lighting overflows.
403 mul_thing = dx * fx_dl_dx;
404 if (lleft + mul_thing < 0)
406 else if (lleft + mul_thing > (NUM_LIGHTING_LEVELS*F1_0-F1_0/2))
409 //added 05/17/99 Matt Mueller - prevent writing before the buffer
410 if ((fx_y == 0) && (fx_xleft < 0))
413 if (fx_xright > Window_clip_right)
414 fx_xright = Window_clip_right;
416 cur_tmap_scanline_per();
421 fx_xright = f2i(xright);
422 fx_xleft = f2i(xleft);
425 cur_tmap_scanline_flat();
427 Int3(); // Illegal, called an editor only routine!
434 int Do_vertical_scan=0;
438 // -------------------------------------------------------------------------------------
439 // Render a texture map with lighting using perspective interpolation in inner and outer loops.
440 // -------------------------------------------------------------------------------------
441 void ntexture_map_lighted(grs_bitmap *srcb, g3ds_tmap *t)
443 int vlt,vrt,vlb,vrb; // vertex left top, vertex right top, vertex left bottom, vertex right bottom
445 fix dx_dy_left,dx_dy_right;
446 fix du_dy_left,du_dy_right;
447 fix dv_dy_left,dv_dy_right;
448 fix dz_dy_left,dz_dy_right;
449 fix dl_dy_left,dl_dy_right;
450 fix recip_dyl, recip_dyr;
452 fix xleft,xright,uleft,vleft,uright,vright,zleft,zright,lleft,lright;
453 int next_break_left, next_break_right;
457 //remove stupid warnings in compile
465 // Determine top and bottom y coords.
466 compute_y_bounds(t,&vlt,&vlb,&vrt,&vrb,&max_y_vertex);
468 // Set top and bottom (of entire texture map) y coordinates.
469 topy = f2i(v3d[vlt].y2d);
470 boty = f2i(v3d[max_y_vertex].y2d);
471 if (topy > Window_clip_bot)
473 if (boty > Window_clip_bot)
474 boty = Window_clip_bot;
476 // Set amount to change x coordinate for each advance to next scanline.
477 dy = f2i(t->verts[vlb].y2d) - f2i(t->verts[vlt].y2d);
478 if (dy < FIX_RECIP_TABLE_SIZE)
479 recip_dyl = fix_recip[dy];
483 dx_dy_left = compute_dx_dy(t,vlt,vlb, recip_dyl);
484 du_dy_left = compute_du_dy(t,vlt,vlb, recip_dyl);
485 dv_dy_left = compute_dv_dy(t,vlt,vlb, recip_dyl);
486 dz_dy_left = compute_dz_dy(t,vlt,vlb, recip_dyl);
488 dy = f2i(t->verts[vrb].y2d) - f2i(t->verts[vrt].y2d);
489 if (dy < FIX_RECIP_TABLE_SIZE)
490 recip_dyr = fix_recip[dy];
494 du_dy_right = compute_du_dy(t,vrt,vrb, recip_dyr);
495 dx_dy_right = compute_dx_dy(t,vrt,vrb, recip_dyr);
496 dv_dy_right = compute_dv_dy(t,vrt,vrb, recip_dyr);
497 dz_dy_right = compute_dz_dy(t,vrt,vrb, recip_dyr);
499 if (Lighting_enabled) {
500 dl_dy_left = compute_dl_dy_lin(t,vlt,vlb, recip_dyl);
501 dl_dy_right = compute_dl_dy_lin(t,vrt,vrb, recip_dyr);
507 // Set initial values for x, u, v
508 xleft = v3d[vlt].x2d;
509 xright = v3d[vrt].x2d;
514 uleft = fixmul(v3d[vlt].u,zleft);
515 uright = fixmul(v3d[vrt].u,zright);
516 vleft = fixmul(v3d[vlt].v,zleft);
517 vright = fixmul(v3d[vrt].v,zright);
519 // scan all rows in texture map from top through first break.
520 next_break_left = f2i(v3d[vlb].y2d);
521 next_break_right = f2i(v3d[vrb].y2d);
523 for (y = topy; y < boty; y++) {
525 // See if we have reached the end of the current left edge, and if so, set
526 // new values for dx_dy and x,u,v
527 if (y == next_break_left) {
530 // Handle problem of double points. Search until y coord is different. Cannot get
531 // hung in an infinite loop because we know there is a vertex with a lower y coordinate
532 // because in the for loop, we don't scan all spanlines.
533 while (y == f2i(v3d[vlb].y2d)) {
535 vlb = prevmod(vlb,t->nv);
537 next_break_left = f2i(v3d[vlb].y2d);
539 dy = f2i(t->verts[vlb].y2d) - f2i(t->verts[vlt].y2d);
540 if (dy < FIX_RECIP_TABLE_SIZE)
541 recip_dy = fix_recip[dy];
545 dx_dy_left = compute_dx_dy(t,vlt,vlb, recip_dy);
547 xleft = v3d[vlt].x2d;
549 uleft = fixmul(v3d[vlt].u,zleft);
550 vleft = fixmul(v3d[vlt].v,zleft);
553 du_dy_left = compute_du_dy(t,vlt,vlb, recip_dy);
554 dv_dy_left = compute_dv_dy(t,vlt,vlb, recip_dy);
555 dz_dy_left = compute_dz_dy(t,vlt,vlb, recip_dy);
557 if (Lighting_enabled) {
558 dl_dy_left = compute_dl_dy_lin(t,vlt,vlb, recip_dy);
563 // See if we have reached the end of the current left edge, and if so, set
564 // new values for dx_dy and x. Not necessary to set new values for u,v.
565 if (y == next_break_right) {
568 while (y == f2i(v3d[vrb].y2d)) {
570 vrb = succmod(vrb,t->nv);
573 next_break_right = f2i(v3d[vrb].y2d);
575 dy = f2i(t->verts[vrb].y2d) - f2i(t->verts[vrt].y2d);
576 if (dy < FIX_RECIP_TABLE_SIZE)
577 recip_dy = fix_recip[dy];
581 dx_dy_right = compute_dx_dy(t,vrt,vrb, recip_dy);
583 xright = v3d[vrt].x2d;
585 uright = fixmul(v3d[vrt].u,zright);
586 vright = fixmul(v3d[vrt].v,zright);
588 du_dy_right = compute_du_dy(t,vrt,vrb, recip_dy);
589 dv_dy_right = compute_dv_dy(t,vrt,vrb, recip_dy);
590 dz_dy_right = compute_dz_dy(t,vrt,vrb, recip_dy);
592 if (Lighting_enabled) {
593 dl_dy_right = compute_dl_dy_lin(t,vrt,vrb, recip_dy);
598 if (Lighting_enabled) {
599 if (y >= Window_clip_top)
600 ntmap_scanline_lighted(srcb,y,xleft,xright,uleft,uright,vleft,vright,zleft,zright,lleft,lright);
602 lright += dl_dy_right;
604 if (y >= Window_clip_top)
605 ntmap_scanline_lighted(srcb,y,xleft,xright,uleft,uright,vleft,vright,zleft,zright,lleft,lright);
610 uright += du_dy_right;
611 vright += dv_dy_right;
614 xright += dx_dy_right;
617 zright += dz_dy_right;
621 // We can get lleft or lright out of bounds here because we compute dl_dy using fixed point values,
622 // but we plot an integer number of scanlines, therefore doing an integer number of additions of the delta.
625 // mprintf(0, "[%i %i %i] ", y, f2i(xleft), f2i(xright));
627 ntmap_scanline_lighted(srcb,y,xleft,xright,uleft,uright,vleft,vright,zleft,zright,lleft,lright);
631 // -------------------------------------------------------------------------------------
632 // Texture map current scanline using linear interpolation.
633 // -------------------------------------------------------------------------------------
634 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)
639 fix du_dx,dv_dx,dl_dx;
645 dx = f2i(xright) - f2i(xleft);
646 if ((dx < 0) || (xright < 0) || (xleft > xright)) // the (xleft > xright) term is not redundant with (dx < 0) because dx is computed using integers
649 // setup to call assembler scanline renderer
650 if (dx < FIX_RECIP_TABLE_SIZE)
651 recip_dx = fix_recip[dx];
655 du_dx = fixmul(uright - uleft,recip_dx);
656 dv_dx = fixmul(vright - vleft,recip_dx);
663 fx_xright = f2i(xright);
664 fx_xleft = f2i(xleft);
665 pixptr = srcb->bm_data;
667 switch (Lighting_enabled) {
669 //added 07/11/99 adb - prevent writing before the buffer
674 cur_tmap_scanline_lin_nolight();
682 if (lleft > MAX_LIGHTING_VALUE*NUM_LIGHTING_LEVELS)
683 lleft = MAX_LIGHTING_VALUE*NUM_LIGHTING_LEVELS;
684 if (lright > MAX_LIGHTING_VALUE*NUM_LIGHTING_LEVELS)
685 lright = MAX_LIGHTING_VALUE*NUM_LIGHTING_LEVELS;
687 //added 07/11/99 adb - prevent writing before the buffer
696 fx_dl_dx = fixmul(lright - lleft,recip_dx);
698 // This is a pretty ugly hack to prevent lighting overflows.
699 mul_thing = dx * fx_dl_dx;
700 if (lleft + mul_thing < 0)
702 else if (lleft + mul_thing > (NUM_LIGHTING_LEVELS*F1_0-F1_0/2))
707 dl_dx = fixmul(lright - lleft,recip_dx);
709 cur_tmap_scanline_lin();
713 fx_xright = f2i(xright);
714 fx_xleft = f2i(xleft);
716 cur_tmap_scanline_flat();
718 Int3(); // Illegal, called an editor only routine!
724 // -------------------------------------------------------------------------------------
725 // Render a texture map with lighting using perspective interpolation in inner and outer loops.
726 // -------------------------------------------------------------------------------------
727 void ntexture_map_lighted_linear(grs_bitmap *srcb, g3ds_tmap *t)
729 int vlt,vrt,vlb,vrb; // vertex left top, vertex right top, vertex left bottom, vertex right bottom
731 fix dx_dy_left,dx_dy_right;
732 fix du_dy_left,du_dy_right;
733 fix dv_dy_left,dv_dy_right;
734 fix dl_dy_left,dl_dy_right;
736 fix xleft,xright,uleft,vleft,uright,vright,lleft,lright;
737 int next_break_left, next_break_right;
738 fix recip_dyl, recip_dyr;
742 //remove stupid warnings in compile
750 // Determine top and bottom y coords.
751 compute_y_bounds(t,&vlt,&vlb,&vrt,&vrb,&max_y_vertex);
753 // Set top and bottom (of entire texture map) y coordinates.
754 topy = f2i(v3d[vlt].y2d);
755 boty = f2i(v3d[max_y_vertex].y2d);
757 if (topy > Window_clip_bot)
759 if (boty > Window_clip_bot)
760 boty = Window_clip_bot;
762 dy = f2i(t->verts[vlb].y2d) - f2i(t->verts[vlt].y2d);
763 if (dy < FIX_RECIP_TABLE_SIZE)
764 recip_dyl = fix_recip[dy];
768 dy = f2i(t->verts[vrb].y2d) - f2i(t->verts[vrt].y2d);
769 if (dy < FIX_RECIP_TABLE_SIZE)
770 recip_dyr = fix_recip[dy];
774 // Set amount to change x coordinate for each advance to next scanline.
775 dx_dy_left = compute_dx_dy(t,vlt,vlb, recip_dyl);
776 dx_dy_right = compute_dx_dy(t,vrt,vrb, recip_dyr);
778 du_dy_left = compute_du_dy_lin(t,vlt,vlb, recip_dyl);
779 du_dy_right = compute_du_dy_lin(t,vrt,vrb, recip_dyr);
781 dv_dy_left = compute_dv_dy_lin(t,vlt,vlb, recip_dyl);
782 dv_dy_right = compute_dv_dy_lin(t,vrt,vrb, recip_dyr);
784 if (Lighting_enabled) {
785 dl_dy_left = compute_dl_dy_lin(t,vlt,vlb, recip_dyl);
786 dl_dy_right = compute_dl_dy_lin(t,vrt,vrb, recip_dyr);
792 // Set initial values for x, u, v
793 xleft = v3d[vlt].x2d;
794 xright = v3d[vrt].x2d;
801 // scan all rows in texture map from top through first break.
802 next_break_left = f2i(v3d[vlb].y2d);
803 next_break_right = f2i(v3d[vrb].y2d);
805 for (y = topy; y < boty; y++) {
807 // See if we have reached the end of the current left edge, and if so, set
808 // new values for dx_dy and x,u,v
809 if (y == next_break_left) {
812 // Handle problem of double points. Search until y coord is different. Cannot get
813 // hung in an infinite loop because we know there is a vertex with a lower y coordinate
814 // because in the for loop, we don't scan all spanlines.
815 while (y == f2i(v3d[vlb].y2d)) {
817 vlb = prevmod(vlb,t->nv);
819 next_break_left = f2i(v3d[vlb].y2d);
821 dy = f2i(t->verts[vlb].y2d) - f2i(t->verts[vlt].y2d);
822 if (dy < FIX_RECIP_TABLE_SIZE)
823 recip_dy = fix_recip[dy];
827 dx_dy_left = compute_dx_dy(t,vlt,vlb, recip_dy);
829 xleft = v3d[vlt].x2d;
834 du_dy_left = compute_du_dy_lin(t,vlt,vlb, recip_dy);
835 dv_dy_left = compute_dv_dy_lin(t,vlt,vlb, recip_dy);
837 if (Lighting_enabled) {
838 dl_dy_left = compute_dl_dy_lin(t,vlt,vlb, recip_dy);
843 // See if we have reached the end of the current left edge, and if so, set
844 // new values for dx_dy and x. Not necessary to set new values for u,v.
845 if (y == next_break_right) {
848 while (y == f2i(v3d[vrb].y2d)) {
850 vrb = succmod(vrb,t->nv);
853 dy = f2i(t->verts[vrb].y2d) - f2i(t->verts[vrt].y2d);
854 if (dy < FIX_RECIP_TABLE_SIZE)
855 recip_dy = fix_recip[dy];
859 next_break_right = f2i(v3d[vrb].y2d);
860 dx_dy_right = compute_dx_dy(t,vrt,vrb, recip_dy);
862 xright = v3d[vrt].x2d;
866 du_dy_right = compute_du_dy_lin(t,vrt,vrb, recip_dy);
867 dv_dy_right = compute_dv_dy_lin(t,vrt,vrb, recip_dy);
869 if (Lighting_enabled) {
870 dl_dy_right = compute_dl_dy_lin(t,vrt,vrb, recip_dy);
875 if (Lighting_enabled) {
876 ntmap_scanline_lighted_linear(srcb,y,xleft,xright,uleft,uright,vleft,vright,lleft,lright);
878 lright += dl_dy_right;
880 ntmap_scanline_lighted_linear(srcb,y,xleft,xright,uleft,uright,vleft,vright,lleft,lright);
885 uright += du_dy_right;
886 vright += dv_dy_right;
889 xright += dx_dy_right;
893 // We can get lleft or lright out of bounds here because we compute dl_dy using fixed point values,
894 // but we plot an integer number of scanlines, therefore doing an integer number of additions of the delta.
896 ntmap_scanline_lighted_linear(srcb,y,xleft,xright,uleft,uright,vleft,vright,lleft,lright);
899 // fix DivNum = F1_0*12;
901 extern void draw_tmap_flat(grs_bitmap *bp,int nverts,g3s_point **vertbuf);
903 // -------------------------------------------------------------------------------------
904 // Interface from Matt's data structures to Mike's texture mapper.
905 // -------------------------------------------------------------------------------------
906 void draw_tmap(grs_bitmap *bp,int nverts,g3s_point **vertbuf)
910 // These variables are used in system which renders texture maps which lie on one scanline as a line.
911 // fix div_numerator;
912 int lighting_on_save = Lighting_on;
914 Assert(nverts <= MAX_TMAP_VERTS);
918 if ( !divide_table_filled ) fill_divide_table();
921 // -- now called from g3_start_frame -- init_interface_vars_to_assembler();
923 // If no transparency and seg depth is large, render as flat shaded.
924 if ((Current_seg_depth > Max_linear_depth) && ((bp->bm_flags & 3) == 0)) {
925 draw_tmap_flat(bp, nverts, vertbuf);
929 if ( bp->bm_flags & BM_FLAG_RLE )
930 bp = rle_expand_texture( bp ); // Expand if rle'd
932 Transparency_on = bp->bm_flags & BM_FLAG_TRANSPARENT;
933 if (bp->bm_flags & BM_FLAG_NO_LIGHTING)
937 // Setup texture map in Tmap1
938 Tmap1.nv = nverts; // Initialize number of vertices
940 // div_numerator = DivNum; //f1_0*3;
942 for (i=0; i<nverts; i++) {
943 g3ds_vertex *tvp = &Tmap1.verts[i];
944 g3s_point *vp = vertbuf[i];
946 tvp->x2d = vp->p3_sx;
947 tvp->y2d = vp->p3_sy;
949 // Check for overflow on fixdiv. Will overflow on vp->z <= something small. Allow only as low as 256.
950 if (vp->p3_z < 256) {
952 // Int3(); // we would overflow if we divided!
955 tvp->z = fixdiv(F1_0*12, vp->p3_z);
956 tvp->u = vp->p3_u << 6; //* bp->bm_w;
957 tvp->v = vp->p3_v << 6; //* bp->bm_h;
959 Assert(Lighting_on < 3);
962 tvp->l = vp->p3_l * NUM_LIGHTING_LEVELS;
966 Lighting_enabled = Lighting_on;
968 // Now, call my texture mapper.
970 switch (Interpolation_method) { // 0 = choose, 1 = linear, 2 = /8 perspective, 3 = full perspective
971 case 0: // choose best interpolation
973 if (Current_seg_depth > Max_perspective_depth)
974 ntexture_map_lighted_linear(bp, &Tmap1);
976 ntexture_map_lighted(bp, &Tmap1);
978 case 1: // linear interpolation
980 ntexture_map_lighted_linear(bp, &Tmap1);
982 case 2: // perspective every 8th pixel interpolation
984 ntexture_map_lighted(bp, &Tmap1);
986 case 3: // perspective every pixel interpolation
987 per2_flag = 0; // this hack means do divide every pixel
988 ntexture_map_lighted(bp, &Tmap1);
991 Assert(0); // Illegal value for Interpolation_method, must be 0,1,2,3
994 switch (Interpolation_method) { // 0 = choose, 1 = linear, 2 = /8 perspective, 3 = full perspective
995 case 0: // choose best interpolation
997 if (Current_seg_depth > Max_perspective_depth)
998 ntexture_map_lighted_linear(bp, &Tmap1);
1000 ntexture_map_lighted(bp, &Tmap1);
1002 case 1: // linear interpolation
1004 ntexture_map_lighted_linear(bp, &Tmap1);
1006 case 2: // perspective every 8th pixel interpolation
1008 ntexture_map_lighted(bp, &Tmap1);
1010 case 3: // perspective every pixel interpolation
1011 per2_flag = 0; // this hack means do divide every pixel
1012 ntexture_map_lighted(bp, &Tmap1);
1015 Assert(0); // Illegal value for Interpolation_method, must be 0,1,2,3
1019 Lighting_on = lighting_on_save;
1024 void texmap_cmd_tmap(int argc, char **argv)
1026 if (argc < 2 || argc > 2) {
1027 cmd_insertf("help %s", argv[0]);
1031 select_tmap(argv[1]);
1035 void texmap_init(void)
1039 cmd_addcommand("tmap", texmap_cmd_tmap, "tmap <x>\n" " use texture mapper <x>. Available mappers:\n"
1040 #if !defined(NO_ASM) && !defined(OGL)
1048 if ((t = FindArg("-tmap")))
1049 select_tmap(Args[t+1]);