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.
14 * $Source: /cvs/cvsroot/d2x/texmap/ntmap.c,v $
17 * $Date: 2001-01-31 15:18:04 $
19 * Start of conversion to new texture mapper.
21 * $Log: not supported by cvs2svn $
22 * Revision 1.2 2001/01/31 14:04:46 bradleyb
23 * Fix compiler warnings
25 * Revision 1.1.1.1 2001/01/19 03:30:16 bradleyb
28 * Revision 1.4 1999/10/18 00:31:55 donut
29 * allow FP_TMAP to be used without NO_ASM
31 * Revision 1.3 1999/08/05 22:53:41 sekmu
33 * D3D patch(es) from ADB
35 * Revision 1.2 1999/07/07 21:31:09 donut
36 * removed unused vars from ntmap_scanline_lighted and slightly optomized it
38 * Revision 1.1.1.1 1999/06/14 22:14:06 donut
39 * Import of d1x 1.37 source.
41 * Revision 1.52 1995/03/14 15:13:06 john
42 * Increased MAX_Y_Pointers to 480.
44 * Revision 1.51 1995/02/23 14:25:09 john
47 * Revision 1.50 1995/02/20 18:22:58 john
48 * Put all the externs in the assembly modules into tmap_inc.asm.
49 * Also, moved all the C versions of the inner loops into a new module,
52 * Revision 1.49 1995/02/20 17:09:11 john
53 * Added code so that you can build the tmapper with no assembly!
55 * Revision 1.48 1995/01/06 11:11:30 mike
56 * even when not in editor, have 400 lines in texture map scanline table.
58 * Revision 1.47 1994/12/15 16:43:25 matt
59 * Took out code only needed by editor
61 * Revision 1.46 1994/12/09 22:35:37 mike
62 * fix bug in before call to asm_tmap_scanline_per causing write of pixel onto past right border onto left.
64 * Revision 1.45 1994/12/06 16:31:06 mike
65 * fix bug in asm_tmap_scanline_matt interface.
67 * Revision 1.44 1994/12/04 20:37:18 mike
68 * *** empty log message ***
70 * Revision 1.43 1994/12/02 23:30:04 mike
73 * Revision 1.42 1994/11/30 00:57:43 mike
76 * Revision 1.41 1994/11/28 13:34:27 mike
79 * Revision 1.40 1994/11/28 01:30:01 mike
82 * Revision 1.39 1994/11/28 01:28:59 mike
85 * Revision 1.38 1994/11/21 14:08:07 john
86 * Took out all multiple instead of divide code.
88 * Revision 1.37 1994/11/19 15:21:52 mike
89 * rip out unused code.
91 * Revision 1.36 1994/11/14 11:42:51 mike
94 * Revision 1.35 1994/11/12 16:41:36 mike
95 * *** empty log message ***
97 * Revision 1.34 1994/11/10 21:28:41 mike
98 * remove call to init_interface_vars_to_assembler.
100 * Revision 1.33 1994/11/10 11:08:59 mike
101 * detail level stuff.
103 * Revision 1.32 1994/11/09 22:55:52 matt
104 * Added variable Current_seg_depth for detail level optimization
106 * Revision 1.31 1994/11/09 19:57:31 john
107 * Added texture rle caching.
109 * Revision 1.30 1994/11/09 19:54:48 mike
110 * Call flat shader if Tmap_flat_flag set.
112 * Revision 1.29 1994/11/02 21:33:31 john
113 * Added Burger Bill's optimization, ie.. 2 muls per 8 pixels.
115 * Revision 1.28 1994/11/02 11:32:16 john
116 * Added code for c callable inner loop and code to
117 * test dividing out z0.
119 * Revision 1.27 1994/10/28 20:54:32 matt
120 * Added error checking
122 * Revision 1.26 1994/10/25 11:20:20 mike
123 * fix bug in lighting overflow checking for one scanline tall linear texture maps.
125 * Revision 1.25 1994/08/03 15:40:33 mike
126 * Prevent divide overflows, decrease occurrence of precision-caused glitches.
128 * Revision 1.24 1994/07/27 09:31:16 mike
129 * Fix concave texture map problem, decrease occurrence of unimportant int 3.
131 * Revision 1.23 1994/06/17 12:23:31 mike
132 * Support non-lighted texture maps.
134 * Revision 1.22 1994/06/11 08:10:24 mike
135 * Fix mysterious hang bug, lighting value was out of range.
137 * Revision 1.21 1994/06/09 16:10:16 mike
138 * Change SC2000 from constant to variable.
147 static char rcsid[] = "$Id: ntmap.c,v 1.3 2001-01-31 15:18:04 bradleyb Exp $";
153 #define HEADLIGHT_LIGHTING 0
156 #define PERSPECTIVE 1
169 #include "scanline.h"
172 //#include "../main/textures.h"
175 #define EDITOR_TMAP 1 //if in, include extra stuff
178 #define F15_5 (F1_0*15 + F0_5)
180 // Temporary texture map, interface from Matt's 3d system to Mike's texture mapper.
183 grs_bitmap Texmap_ptrs[NUM_TMAPS];
184 grs_bitmap Texmap4_ptrs[NUM_TMAPS];
186 fix Range_max=0; // debug, kill me
188 int Interpolation_method=0; // 0 = choose best method
189 int Lighting_on=1; // initialize to no lighting
190 int Tmap_flat_flag = 0; // 1 = render texture maps as flat shaded polygons.
191 int Current_seg_depth; // HACK INTERFACE: how far away the current segment (& thus texture) is
192 int Max_perspective_depth;
193 int Max_linear_depth;
196 extern int Window_clip_left, Window_clip_bot, Window_clip_right, Window_clip_top;
198 // These variables are the interface to assembler. They get set for each texture map, which is a real waste of time.
199 // They should be set only when they change, which is generally when the window bounds change. And, even still, it's
200 // a pretty bad interface.
201 int bytes_per_row=-1;
202 unsigned char *write_buffer;
211 #define MAX_Y_POINTERS 600
213 #define MAX_Y_POINTERS 600
215 int y_pointers[MAX_Y_POINTERS];
217 fix fix_recip[FIX_RECIP_TABLE_SIZE];
219 int Lighting_enabled;
220 int Fix_recip_table_computed=0;
222 fix fx_l, fx_u, fx_v, fx_z, fx_du_dx, fx_dv_dx, fx_dz_dx, fx_dl_dx;
223 int fx_xleft, fx_xright, fx_y;
224 unsigned char * pixptr;
226 int Transparency_on = 0;
227 int dither_intensity_lighting = 0;
229 ubyte * tmap_flat_cthru_table;
230 ubyte tmap_flat_color;
231 ubyte tmap_flat_shade_value;
235 // -------------------------------------------------------------------------------------
236 void init_fix_recip_table(void)
242 for (i=1; i<FIX_RECIP_TABLE_SIZE; i++)
243 fix_recip[i] = F1_0/i;
245 Fix_recip_table_computed = 1;
248 // -------------------------------------------------------------------------------------
249 // Initialize interface variables to assembler.
250 // These things used to be constants. This routine is now (10/6/93) getting called for
251 // every texture map. It should get called whenever the window changes, or, preferably,
252 // not at all. I'm pretty sure these variables are only being used for range checking.
253 void init_interface_vars_to_assembler(void)
257 bp = &grd_curcanv->cv_bitmap;
260 Assert(bp->bm_data!=NULL);
261 Assert(bp->bm_h <= MAX_Y_POINTERS);
263 // If bytes_per_row has changed, create new table of pointers.
264 if (bytes_per_row != (int) bp->bm_rowsize) {
267 bytes_per_row = (int) bp->bm_rowsize;
270 for (i=0; i<MAX_Y_POINTERS; i++) {
271 y_pointers[i] = y_val;
272 y_val += bytes_per_row;
276 write_buffer = (unsigned char *) bp->bm_data;
279 window_right = (int) bp->bm_w-1;
281 window_bottom = (int) bp->bm_h-1;
283 Window_clip_left = window_left;
284 Window_clip_right = window_right;
285 Window_clip_top = window_top;
286 Window_clip_bot = window_bottom;
288 window_width = bp->bm_w;
289 window_height = bp->bm_h;
291 if (!Fix_recip_table_computed)
292 init_fix_recip_table();
295 // -------------------------------------------------------------------------------------
297 extern g3ds_tmap Tmap1;
299 // -------------------------------------------------------------------------------------
300 // Returns number preceding val modulo modulus.
303 int prevmod(int val,int modulus)
309 // return (val + modulus - 1) % modulus;
313 // Returns number succeeding val modulo modulus.
316 int succmod(int val,int modulus)
323 // return (val + 1) % modulus;
326 // -------------------------------------------------------------------------------------
327 // Select topmost vertex (minimum y coordinate) and bottommost (maximum y coordinate) in
328 // texture map. If either is part of a horizontal edge, then select leftmost vertex for
329 // top, rightmost vertex for bottom.
330 // Important: Vertex is selected with integer precision. So, if there are vertices at
331 // (0.0,0.7) and (0.5,0.3), the first vertex is selected, because they y coordinates are
332 // considered the same, so the smaller x is favored.
334 // nv number of vertices
335 // v3d pointer to 3d vertices containing u,v,x2d,y2d coordinates
339 // -------------------------------------------------------------------------------------
340 void compute_y_bounds(g3ds_tmap *t, int *vlt, int *vlb, int *vrt, int *vrb,int *bottom_y_ind)
348 // Scan all vertices, set min_y_ind to vertex with smallest y coordinate.
349 min_y = f2i(t->verts[0].y2d);
352 min_x = f2i(t->verts[0].x2d);
355 for (i=1; i<t->nv; i++) {
356 if (f2i(t->verts[i].y2d) < min_y) {
357 min_y = f2i(t->verts[i].y2d);
359 min_x = f2i(t->verts[i].x2d);
360 } else if (f2i(t->verts[i].y2d) == min_y) {
361 if (f2i(t->verts[i].x2d) < min_x) {
363 min_x = f2i(t->verts[i].x2d);
366 if (f2i(t->verts[i].y2d) > max_y) {
367 max_y = f2i(t->verts[i].y2d);
372 //--removed mk, 11/27/94-- // Check for a non-upright-hourglass polygon and fix, if necessary, by bashing a y coordinate.
373 //--removed mk, 11/27/94-- // min_y_ind = index of minimum y coordinate, *bottom_y_ind = index of maximum y coordinate
374 //--removed mk, 11/27/94--{
375 //--removed mk, 11/27/94-- int max_temp, min_temp;
376 //--removed mk, 11/27/94--
377 //--removed mk, 11/27/94-- max_temp = *bottom_y_ind;
378 //--removed mk, 11/27/94-- if (*bottom_y_ind < min_y_ind)
379 //--removed mk, 11/27/94-- max_temp += t->nv;
380 //--removed mk, 11/27/94--
381 //--removed mk, 11/27/94-- for (i=min_y_ind; i<max_temp; i++) {
382 //--removed mk, 11/27/94-- if (f2i(t->verts[i%t->nv].y2d) > f2i(t->verts[(i+1)%t->nv].y2d)) {
383 //--removed mk, 11/27/94-- Int3();
384 //--removed mk, 11/27/94-- t->verts[(i+1)%t->nv].y2d = t->verts[i%t->nv].y2d;
385 //--removed mk, 11/27/94-- }
386 //--removed mk, 11/27/94-- }
387 //--removed mk, 11/27/94--
388 //--removed mk, 11/27/94-- min_temp = min_y_ind;
389 //--removed mk, 11/27/94-- if (min_y_ind < *bottom_y_ind)
390 //--removed mk, 11/27/94-- min_temp += t->nv;
391 //--removed mk, 11/27/94--
392 //--removed mk, 11/27/94-- for (i=*bottom_y_ind; i<min_temp; i++) {
393 //--removed mk, 11/27/94-- if (f2i(t->verts[i%t->nv].y2d) < f2i(t->verts[(i+1)%t->nv].y2d)) {
394 //--removed mk, 11/27/94-- Int3();
395 //--removed mk, 11/27/94-- t->verts[(i+1)%t->nv].y2d = t->verts[i%t->nv].y2d;
396 //--removed mk, 11/27/94-- }
397 //--removed mk, 11/27/94-- }
398 //--removed mk, 11/27/94--}
400 // Set "vertex left top", etc. based on vertex with topmost y coordinate
403 *vlb = prevmod(*vlt,t->nv);
404 *vrb = succmod(*vrt,t->nv);
406 // If right edge is horizontal, then advance along polygon bound until it no longer is or until all
407 // vertices have been examined.
408 // (Left edge cannot be horizontal, because *vlt is set to leftmost point with highest y coordinate.)
412 while (f2i(t->verts[*vrt].y2d) == f2i(t->verts[*vrb].y2d)) {
413 if (succmod(*vrt,t->nv) == original_vrt) {
416 *vrt = succmod(*vrt,t->nv);
417 *vrb = succmod(*vrt,t->nv);
421 // -------------------------------------------------------------------------------------
422 // Returns dx/dy given two vertices.
423 // If dy == 0, returns 0.0
424 // -------------------------------------------------------------------------------------
425 //--fix compute_dx_dy_lin(g3ds_tmap *t, int top_vertex,int bottom_vertex)
429 //-- // compute delta x with respect to y for any edge
430 //-- dy = f2i(t->verts[bottom_vertex].y2d - t->verts[top_vertex].y2d) + 1;
432 //-- return (t->verts[bottom_vertex].x2d - t->verts[top_vertex].x2d) / dy;
438 fix compute_du_dy_lin(g3ds_tmap *t, int top_vertex,int bottom_vertex, fix recip_dy)
440 return fixmul(t->verts[bottom_vertex].u - t->verts[top_vertex].u, recip_dy);
444 fix compute_dv_dy_lin(g3ds_tmap *t, int top_vertex,int bottom_vertex, fix recip_dy)
446 return fixmul(t->verts[bottom_vertex].v - t->verts[top_vertex].v, recip_dy);
449 fix compute_dl_dy_lin(g3ds_tmap *t, int top_vertex,int bottom_vertex, fix recip_dy)
451 return fixmul(t->verts[bottom_vertex].l - t->verts[top_vertex].l, recip_dy);
455 fix compute_dx_dy(g3ds_tmap *t, int top_vertex,int bottom_vertex, fix recip_dy)
457 return fixmul(t->verts[bottom_vertex].x2d - t->verts[top_vertex].x2d, recip_dy);
460 fix compute_du_dy(g3ds_tmap *t, int top_vertex,int bottom_vertex, fix recip_dy)
462 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);
466 fix compute_dv_dy(g3ds_tmap *t, int top_vertex,int bottom_vertex, fix recip_dy)
468 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);
472 fix compute_dz_dy(g3ds_tmap *t, int top_vertex,int bottom_vertex, fix recip_dy)
474 return fixmul(t->verts[bottom_vertex].z - t->verts[top_vertex].z, recip_dy);
477 int Skip_short_flag=0;
479 // -------------------------------------------------------------------------------------
480 // Texture map current scanline in perspective.
481 // -------------------------------------------------------------------------------------
482 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)
486 fx_xright = f2i(xright);
487 //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?
488 if (fx_xright < Window_clip_left)
490 fx_xleft = f2i(xleft);
491 if (fx_xleft > Window_clip_right)
495 dx = fx_xright - fx_xleft;
496 if ((dx < 0) || (xright < 0) || (xleft > xright)) // the (xleft > xright) term is not redundant with (dx < 0) because dx is computed using integers
499 // setup to call assembler scanline renderer
500 if (dx < FIX_RECIP_TABLE_SIZE)
501 recip_dx = fix_recip[dx];
509 fx_du_dx = fixmul(uright - uleft,recip_dx);
510 fx_dv_dx = fixmul(vright - vleft,recip_dx);
511 fx_dz_dx = fixmul(zright - zleft,recip_dx);
513 pixptr = srcb->bm_data;
515 switch (Lighting_enabled) {
517 //added 05/17/99 Matt Mueller - prevent writing before the buffer
518 if ((fx_y == 0) && (fx_xleft < 0))
521 if (fx_xright > Window_clip_right)
522 fx_xright = Window_clip_right;
524 #if (defined(NO_ASM) && !defined(ASM_PER)) || defined(FP_TMAP)
525 c_tmap_scanline_per_nolight();
527 asm_tmap_scanline_per();
533 if (lleft < 0) lleft = 0;
534 if (lright < 0) lright = 0;
535 if (lleft > (NUM_LIGHTING_LEVELS*F1_0-F1_0/2)) lleft = (NUM_LIGHTING_LEVELS*F1_0-F1_0/2);
536 if (lright > (NUM_LIGHTING_LEVELS*F1_0-F1_0/2)) lright = (NUM_LIGHTING_LEVELS*F1_0-F1_0/2);
539 fx_dl_dx = fixmul(lright - lleft,recip_dx);
541 // This is a pretty ugly hack to prevent lighting overflows.
542 mul_thing = dx * fx_dl_dx;
543 if (lleft + mul_thing < 0)
545 else if (lleft + mul_thing > (NUM_LIGHTING_LEVELS*F1_0-F1_0/2))
548 //added 05/17/99 Matt Mueller - prevent writing before the buffer
549 if ((fx_y == 0) && (fx_xleft < 0))
552 if (fx_xright > Window_clip_right)
553 fx_xright = Window_clip_right;
555 #if (defined(NO_ASM) && !defined(ASM_PER)) || defined(FP_TMAP)
556 c_tmap_scanline_per();
558 asm_tmap_scanline_per();
564 fx_xright = f2i(xright);
565 fx_xleft = f2i(xleft);
567 #if defined(FL1_WITH_FLAT) || defined(NO_ASM)
570 c_tmap_scanline_flat();
572 asm_tmap_scanline_flat();
575 asm_tmap_scanline_matt();
578 Int3(); // Illegal, called an editor only routine!
585 int Do_vertical_scan=0;
589 // -------------------------------------------------------------------------------------
590 // Render a texture map with lighting using perspective interpolation in inner and outer loops.
591 // -------------------------------------------------------------------------------------
592 void ntexture_map_lighted(grs_bitmap *srcb, g3ds_tmap *t)
594 int vlt,vrt,vlb,vrb; // vertex left top, vertex right top, vertex left bottom, vertex right bottom
596 fix dx_dy_left,dx_dy_right;
597 fix du_dy_left,du_dy_right;
598 fix dv_dy_left,dv_dy_right;
599 fix dz_dy_left,dz_dy_right;
600 fix dl_dy_left,dl_dy_right;
601 fix recip_dyl, recip_dyr;
603 fix xleft,xright,uleft,vleft,uright,vright,zleft,zright,lleft,lright;
604 int next_break_left, next_break_right;
608 //remove stupid warnings in compile
616 // Determine top and bottom y coords.
617 compute_y_bounds(t,&vlt,&vlb,&vrt,&vrb,&max_y_vertex);
619 // Set top and bottom (of entire texture map) y coordinates.
620 topy = f2i(v3d[vlt].y2d);
621 boty = f2i(v3d[max_y_vertex].y2d);
622 if (topy > Window_clip_bot)
624 if (boty > Window_clip_bot)
625 boty = Window_clip_bot;
627 // Set amount to change x coordinate for each advance to next scanline.
628 dy = f2i(t->verts[vlb].y2d) - f2i(t->verts[vlt].y2d);
629 if (dy < FIX_RECIP_TABLE_SIZE)
630 recip_dyl = fix_recip[dy];
634 dx_dy_left = compute_dx_dy(t,vlt,vlb, recip_dyl);
635 du_dy_left = compute_du_dy(t,vlt,vlb, recip_dyl);
636 dv_dy_left = compute_dv_dy(t,vlt,vlb, recip_dyl);
637 dz_dy_left = compute_dz_dy(t,vlt,vlb, recip_dyl);
639 dy = f2i(t->verts[vrb].y2d) - f2i(t->verts[vrt].y2d);
640 if (dy < FIX_RECIP_TABLE_SIZE)
641 recip_dyr = fix_recip[dy];
645 du_dy_right = compute_du_dy(t,vrt,vrb, recip_dyr);
646 dx_dy_right = compute_dx_dy(t,vrt,vrb, recip_dyr);
647 dv_dy_right = compute_dv_dy(t,vrt,vrb, recip_dyr);
648 dz_dy_right = compute_dz_dy(t,vrt,vrb, recip_dyr);
650 if (Lighting_enabled) {
651 dl_dy_left = compute_dl_dy_lin(t,vlt,vlb, recip_dyl);
652 dl_dy_right = compute_dl_dy_lin(t,vrt,vrb, recip_dyr);
658 // Set initial values for x, u, v
659 xleft = v3d[vlt].x2d;
660 xright = v3d[vrt].x2d;
665 uleft = fixmul(v3d[vlt].u,zleft);
666 uright = fixmul(v3d[vrt].u,zright);
667 vleft = fixmul(v3d[vlt].v,zleft);
668 vright = fixmul(v3d[vrt].v,zright);
670 // scan all rows in texture map from top through first break.
671 next_break_left = f2i(v3d[vlb].y2d);
672 next_break_right = f2i(v3d[vrb].y2d);
674 for (y = topy; y < boty; y++) {
676 // See if we have reached the end of the current left edge, and if so, set
677 // new values for dx_dy and x,u,v
678 if (y == next_break_left) {
681 // Handle problem of double points. Search until y coord is different. Cannot get
682 // hung in an infinite loop because we know there is a vertex with a lower y coordinate
683 // because in the for loop, we don't scan all spanlines.
684 while (y == f2i(v3d[vlb].y2d)) {
686 vlb = prevmod(vlb,t->nv);
688 next_break_left = f2i(v3d[vlb].y2d);
690 dy = f2i(t->verts[vlb].y2d) - f2i(t->verts[vlt].y2d);
691 if (dy < FIX_RECIP_TABLE_SIZE)
692 recip_dy = fix_recip[dy];
696 dx_dy_left = compute_dx_dy(t,vlt,vlb, recip_dy);
698 xleft = v3d[vlt].x2d;
700 uleft = fixmul(v3d[vlt].u,zleft);
701 vleft = fixmul(v3d[vlt].v,zleft);
704 du_dy_left = compute_du_dy(t,vlt,vlb, recip_dy);
705 dv_dy_left = compute_dv_dy(t,vlt,vlb, recip_dy);
706 dz_dy_left = compute_dz_dy(t,vlt,vlb, recip_dy);
708 if (Lighting_enabled) {
709 dl_dy_left = compute_dl_dy_lin(t,vlt,vlb, recip_dy);
714 // See if we have reached the end of the current left edge, and if so, set
715 // new values for dx_dy and x. Not necessary to set new values for u,v.
716 if (y == next_break_right) {
719 while (y == f2i(v3d[vrb].y2d)) {
721 vrb = succmod(vrb,t->nv);
724 next_break_right = f2i(v3d[vrb].y2d);
726 dy = f2i(t->verts[vrb].y2d) - f2i(t->verts[vrt].y2d);
727 if (dy < FIX_RECIP_TABLE_SIZE)
728 recip_dy = fix_recip[dy];
732 dx_dy_right = compute_dx_dy(t,vrt,vrb, recip_dy);
734 xright = v3d[vrt].x2d;
736 uright = fixmul(v3d[vrt].u,zright);
737 vright = fixmul(v3d[vrt].v,zright);
739 du_dy_right = compute_du_dy(t,vrt,vrb, recip_dy);
740 dv_dy_right = compute_dv_dy(t,vrt,vrb, recip_dy);
741 dz_dy_right = compute_dz_dy(t,vrt,vrb, recip_dy);
743 if (Lighting_enabled) {
744 dl_dy_right = compute_dl_dy_lin(t,vrt,vrb, recip_dy);
749 if (Lighting_enabled) {
750 if (y >= Window_clip_top)
751 ntmap_scanline_lighted(srcb,y,xleft,xright,uleft,uright,vleft,vright,zleft,zright,lleft,lright);
753 lright += dl_dy_right;
755 if (y >= Window_clip_top)
756 ntmap_scanline_lighted(srcb,y,xleft,xright,uleft,uright,vleft,vright,zleft,zright,lleft,lright);
761 uright += du_dy_right;
762 vright += dv_dy_right;
765 xright += dx_dy_right;
768 zright += dz_dy_right;
772 // We can get lleft or lright out of bounds here because we compute dl_dy using fixed point values,
773 // but we plot an integer number of scanlines, therefore doing an integer number of additions of the delta.
776 // mprintf(0, "[%i %i %i] ", y, f2i(xleft), f2i(xright));
778 ntmap_scanline_lighted(srcb,y,xleft,xright,uleft,uright,vleft,vright,zleft,zright,lleft,lright);
782 // -------------------------------------------------------------------------------------
783 // Texture map current scanline using linear interpolation.
784 // -------------------------------------------------------------------------------------
785 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)
790 fix du_dx,dv_dx,dl_dx;
796 dx = f2i(xright) - f2i(xleft);
797 if ((dx < 0) || (xright < 0) || (xleft > xright)) // the (xleft > xright) term is not redundant with (dx < 0) because dx is computed using integers
800 // setup to call assembler scanline renderer
801 if (dx < FIX_RECIP_TABLE_SIZE)
802 recip_dx = fix_recip[dx];
806 du_dx = fixmul(uright - uleft,recip_dx);
807 dv_dx = fixmul(vright - vleft,recip_dx);
814 fx_xright = f2i(xright);
815 fx_xleft = f2i(xleft);
816 pixptr = srcb->bm_data;
818 switch (Lighting_enabled) {
820 //added 07/11/99 adb - prevent writing before the buffer
826 c_tmap_scanline_lin_nolight();
828 #ifdef NO_ASM_NOLIGHT
829 asm_tmap_scanline_lin_lighted();
831 asm_tmap_scanline_lin();
841 if (lleft > MAX_LIGHTING_VALUE*NUM_LIGHTING_LEVELS)
842 lleft = MAX_LIGHTING_VALUE*NUM_LIGHTING_LEVELS;
843 if (lright > MAX_LIGHTING_VALUE*NUM_LIGHTING_LEVELS)
844 lright = MAX_LIGHTING_VALUE*NUM_LIGHTING_LEVELS;
846 //added 07/11/99 adb - prevent writing before the buffer
855 fx_dl_dx = fixmul(lright - lleft,recip_dx);
857 // This is a pretty ugly hack to prevent lighting overflows.
858 mul_thing = dx * fx_dl_dx;
859 if (lleft + mul_thing < 0)
861 else if (lleft + mul_thing > (NUM_LIGHTING_LEVELS*F1_0-F1_0/2))
866 dl_dx = fixmul(lright - lleft,recip_dx);
869 c_tmap_scanline_lin();
871 asm_tmap_scanline_lin_lighted();
876 fx_xright = f2i(xright);
877 fx_xleft = f2i(xleft);
878 #if defined(FL1_WITH_FLAT) || defined(NO_ASM)
881 c_tmap_scanline_flat();
883 asm_tmap_scanline_flat();
886 asm_tmap_scanline_matt();
889 Int3(); // Illegal, called an editor only routine!
895 // -------------------------------------------------------------------------------------
896 // Render a texture map with lighting using perspective interpolation in inner and outer loops.
897 // -------------------------------------------------------------------------------------
898 void ntexture_map_lighted_linear(grs_bitmap *srcb, g3ds_tmap *t)
900 int vlt,vrt,vlb,vrb; // vertex left top, vertex right top, vertex left bottom, vertex right bottom
902 fix dx_dy_left,dx_dy_right;
903 fix du_dy_left,du_dy_right;
904 fix dv_dy_left,dv_dy_right;
905 fix dl_dy_left,dl_dy_right;
907 fix xleft,xright,uleft,vleft,uright,vright,lleft,lright;
908 int next_break_left, next_break_right;
909 fix recip_dyl, recip_dyr;
913 //remove stupid warnings in compile
921 // Determine top and bottom y coords.
922 compute_y_bounds(t,&vlt,&vlb,&vrt,&vrb,&max_y_vertex);
924 // Set top and bottom (of entire texture map) y coordinates.
925 topy = f2i(v3d[vlt].y2d);
926 boty = f2i(v3d[max_y_vertex].y2d);
928 if (topy > Window_clip_bot)
930 if (boty > Window_clip_bot)
931 boty = Window_clip_bot;
933 dy = f2i(t->verts[vlb].y2d) - f2i(t->verts[vlt].y2d);
934 if (dy < FIX_RECIP_TABLE_SIZE)
935 recip_dyl = fix_recip[dy];
939 dy = f2i(t->verts[vrb].y2d) - f2i(t->verts[vrt].y2d);
940 if (dy < FIX_RECIP_TABLE_SIZE)
941 recip_dyr = fix_recip[dy];
945 // Set amount to change x coordinate for each advance to next scanline.
946 dx_dy_left = compute_dx_dy(t,vlt,vlb, recip_dyl);
947 dx_dy_right = compute_dx_dy(t,vrt,vrb, recip_dyr);
949 du_dy_left = compute_du_dy_lin(t,vlt,vlb, recip_dyl);
950 du_dy_right = compute_du_dy_lin(t,vrt,vrb, recip_dyr);
952 dv_dy_left = compute_dv_dy_lin(t,vlt,vlb, recip_dyl);
953 dv_dy_right = compute_dv_dy_lin(t,vrt,vrb, recip_dyr);
955 if (Lighting_enabled) {
956 dl_dy_left = compute_dl_dy_lin(t,vlt,vlb, recip_dyl);
957 dl_dy_right = compute_dl_dy_lin(t,vrt,vrb, recip_dyr);
963 // Set initial values for x, u, v
964 xleft = v3d[vlt].x2d;
965 xright = v3d[vrt].x2d;
972 // scan all rows in texture map from top through first break.
973 next_break_left = f2i(v3d[vlb].y2d);
974 next_break_right = f2i(v3d[vrb].y2d);
976 for (y = topy; y < boty; y++) {
978 // See if we have reached the end of the current left edge, and if so, set
979 // new values for dx_dy and x,u,v
980 if (y == next_break_left) {
983 // Handle problem of double points. Search until y coord is different. Cannot get
984 // hung in an infinite loop because we know there is a vertex with a lower y coordinate
985 // because in the for loop, we don't scan all spanlines.
986 while (y == f2i(v3d[vlb].y2d)) {
988 vlb = prevmod(vlb,t->nv);
990 next_break_left = f2i(v3d[vlb].y2d);
992 dy = f2i(t->verts[vlb].y2d) - f2i(t->verts[vlt].y2d);
993 if (dy < FIX_RECIP_TABLE_SIZE)
994 recip_dy = fix_recip[dy];
998 dx_dy_left = compute_dx_dy(t,vlt,vlb, recip_dy);
1000 xleft = v3d[vlt].x2d;
1005 du_dy_left = compute_du_dy_lin(t,vlt,vlb, recip_dy);
1006 dv_dy_left = compute_dv_dy_lin(t,vlt,vlb, recip_dy);
1008 if (Lighting_enabled) {
1009 dl_dy_left = compute_dl_dy_lin(t,vlt,vlb, recip_dy);
1014 // See if we have reached the end of the current left edge, and if so, set
1015 // new values for dx_dy and x. Not necessary to set new values for u,v.
1016 if (y == next_break_right) {
1019 while (y == f2i(v3d[vrb].y2d)) {
1021 vrb = succmod(vrb,t->nv);
1024 dy = f2i(t->verts[vrb].y2d) - f2i(t->verts[vrt].y2d);
1025 if (dy < FIX_RECIP_TABLE_SIZE)
1026 recip_dy = fix_recip[dy];
1030 next_break_right = f2i(v3d[vrb].y2d);
1031 dx_dy_right = compute_dx_dy(t,vrt,vrb, recip_dy);
1033 xright = v3d[vrt].x2d;
1034 uright = v3d[vrt].u;
1035 vright = v3d[vrt].v;
1037 du_dy_right = compute_du_dy_lin(t,vrt,vrb, recip_dy);
1038 dv_dy_right = compute_dv_dy_lin(t,vrt,vrb, recip_dy);
1040 if (Lighting_enabled) {
1041 dl_dy_right = compute_dl_dy_lin(t,vrt,vrb, recip_dy);
1042 lright = v3d[vrt].l;
1046 if (Lighting_enabled) {
1047 ntmap_scanline_lighted_linear(srcb,y,xleft,xright,uleft,uright,vleft,vright,lleft,lright);
1048 lleft += dl_dy_left;
1049 lright += dl_dy_right;
1051 ntmap_scanline_lighted_linear(srcb,y,xleft,xright,uleft,uright,vleft,vright,lleft,lright);
1053 uleft += du_dy_left;
1054 vleft += dv_dy_left;
1056 uright += du_dy_right;
1057 vright += dv_dy_right;
1059 xleft += dx_dy_left;
1060 xright += dx_dy_right;
1064 // We can get lleft or lright out of bounds here because we compute dl_dy using fixed point values,
1065 // but we plot an integer number of scanlines, therefore doing an integer number of additions of the delta.
1067 ntmap_scanline_lighted_linear(srcb,y,xleft,xright,uleft,uright,vleft,vright,lleft,lright);
1070 // fix DivNum = F1_0*12;
1072 extern void draw_tmap_flat(grs_bitmap *bp,int nverts,g3s_point **vertbuf);
1074 // -------------------------------------------------------------------------------------
1075 // Interface from Matt's data structures to Mike's texture mapper.
1076 // -------------------------------------------------------------------------------------
1077 void draw_tmap(grs_bitmap *bp,int nverts,g3s_point **vertbuf)
1081 // These variables are used in system which renders texture maps which lie on one scanline as a line.
1082 // fix div_numerator;
1083 int lighting_on_save = Lighting_on;
1085 Assert(nverts <= MAX_TMAP_VERTS);
1088 #ifdef USE_MULT_CODE
1089 if ( !divide_table_filled ) fill_divide_table();
1092 // -- now called from g3_start_frame -- init_interface_vars_to_assembler();
1094 // If no transparency and seg depth is large, render as flat shaded.
1095 if ((Current_seg_depth > Max_linear_depth) && ((bp->bm_flags & 3) == 0)) {
1096 draw_tmap_flat(bp, nverts, vertbuf);
1100 if ( bp->bm_flags & BM_FLAG_RLE )
1101 bp = rle_expand_texture( bp ); // Expand if rle'd
1103 Transparency_on = bp->bm_flags & BM_FLAG_TRANSPARENT;
1104 if (bp->bm_flags & BM_FLAG_NO_LIGHTING)
1108 // Setup texture map in Tmap1
1109 Tmap1.nv = nverts; // Initialize number of vertices
1111 // div_numerator = DivNum; //f1_0*3;
1113 for (i=0; i<nverts; i++) {
1114 g3ds_vertex *tvp = &Tmap1.verts[i];
1115 g3s_point *vp = vertbuf[i];
1117 tvp->x2d = vp->p3_sx;
1118 tvp->y2d = vp->p3_sy;
1120 // Check for overflow on fixdiv. Will overflow on vp->z <= something small. Allow only as low as 256.
1121 if (vp->p3_z < 256) {
1123 // Int3(); // we would overflow if we divided!
1126 tvp->z = fixdiv(F1_0*12, vp->p3_z);
1127 tvp->u = vp->p3_u << 6; //* bp->bm_w;
1128 tvp->v = vp->p3_v << 6; //* bp->bm_h;
1130 Assert(Lighting_on < 3);
1133 tvp->l = vp->p3_l * NUM_LIGHTING_LEVELS;
1137 Lighting_enabled = Lighting_on;
1139 // Now, call my texture mapper.
1141 switch (Interpolation_method) { // 0 = choose, 1 = linear, 2 = /8 perspective, 3 = full perspective
1142 case 0: // choose best interpolation
1144 if (Current_seg_depth > Max_perspective_depth)
1145 ntexture_map_lighted_linear(bp, &Tmap1);
1147 ntexture_map_lighted(bp, &Tmap1);
1149 case 1: // linear interpolation
1151 ntexture_map_lighted_linear(bp, &Tmap1);
1153 case 2: // perspective every 8th pixel interpolation
1155 ntexture_map_lighted(bp, &Tmap1);
1157 case 3: // perspective every pixel interpolation
1158 per2_flag = 0; // this hack means do divide every pixel
1159 ntexture_map_lighted(bp, &Tmap1);
1162 Assert(0); // Illegal value for Interpolation_method, must be 0,1,2,3
1165 switch (Interpolation_method) { // 0 = choose, 1 = linear, 2 = /8 perspective, 3 = full perspective
1166 case 0: // choose best interpolation
1168 if (Current_seg_depth > Max_perspective_depth)
1169 ntexture_map_lighted_linear(bp, &Tmap1);
1171 ntexture_map_lighted(bp, &Tmap1);
1173 case 1: // linear interpolation
1175 ntexture_map_lighted_linear(bp, &Tmap1);
1177 case 2: // perspective every 8th pixel interpolation
1179 ntexture_map_lighted(bp, &Tmap1);
1181 case 3: // perspective every pixel interpolation
1182 per2_flag = 0; // this hack means do divide every pixel
1183 ntexture_map_lighted(bp, &Tmap1);
1186 Assert(0); // Illegal value for Interpolation_method, must be 0,1,2,3
1190 Lighting_on = lighting_on_save;