This commit was manufactured by cvs2svn to create tag 'd2x-0_1_2'.
[btb/d2x.git] / texmap / ntmap.c
1 /*
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.
12 */
13 /*
14  * $Source: /cvs/cvsroot/d2x/texmap/ntmap.c,v $
15  * $Revision: 1.5 $
16  * $Author: bradleyb $
17  * $Date: 2001-10-25 09:12:16 $
18  * 
19  * Start of conversion to new texture mapper.
20  * 
21  * $Log: not supported by cvs2svn $
22  * Revision 1.4  2001/10/25 02:22:46  bradleyb
23  * adding support for runtime selection of tmap funcs
24  *
25  * Revision 1.3  2001/01/31 15:18:04  bradleyb
26  * Makefile and conf.h fixes
27  *
28  * Revision 1.2  2001/01/31 14:04:46  bradleyb
29  * Fix compiler warnings
30  *
31  * Revision 1.1.1.1  2001/01/19 03:30:16  bradleyb
32  * Import of d2x-0.0.8
33  *
34  * Revision 1.4  1999/10/18 00:31:55  donut
35  * allow FP_TMAP to be used without NO_ASM
36  *
37  * Revision 1.3  1999/08/05 22:53:41  sekmu
38  *
39  * D3D patch(es) from ADB
40  *
41  * Revision 1.2  1999/07/07 21:31:09  donut
42  * removed unused vars from ntmap_scanline_lighted and slightly optomized it
43  *
44  * Revision 1.1.1.1  1999/06/14 22:14:06  donut
45  * Import of d1x 1.37 source.
46  *
47  * Revision 1.52  1995/03/14  15:13:06  john
48  * Increased MAX_Y_Pointers to 480.
49  * 
50  * Revision 1.51  1995/02/23  14:25:09  john
51  * Added editor tmap.
52  * 
53  * Revision 1.50  1995/02/20  18:22:58  john
54  * Put all the externs in the assembly modules into tmap_inc.asm.
55  * Also, moved all the C versions of the inner loops into a new module, 
56  * scanline.c.
57  * 
58  * Revision 1.49  1995/02/20  17:09:11  john
59  * Added code so that you can build the tmapper with no assembly!
60  * 
61  * Revision 1.48  1995/01/06  11:11:30  mike
62  * even when not in editor, have 400 lines in texture map scanline table.
63  * 
64  * Revision 1.47  1994/12/15  16:43:25  matt
65  * Took out code only needed by editor
66  * 
67  * Revision 1.46  1994/12/09  22:35:37  mike
68  * fix bug in before call to asm_tmap_scanline_per causing write of pixel onto past right border onto left.
69  * 
70  * Revision 1.45  1994/12/06  16:31:06  mike
71  * fix bug in asm_tmap_scanline_matt interface.
72  * 
73  * Revision 1.44  1994/12/04  20:37:18  mike
74  * *** empty log message ***
75  * 
76  * Revision 1.43  1994/12/02  23:30:04  mike
77  * optimizations.
78  * 
79  * Revision 1.42  1994/11/30  00:57:43  mike
80  * optimizations.
81  * 
82  * Revision 1.41  1994/11/28  13:34:27  mike
83  * optimizations.
84  * 
85  * Revision 1.40  1994/11/28  01:30:01  mike
86  * kill warning.
87  * 
88  * Revision 1.39  1994/11/28  01:28:59  mike
89  * optimizations.
90  * 
91  * Revision 1.38  1994/11/21  14:08:07  john
92  * Took out all multiple instead of divide code.
93  * 
94  * Revision 1.37  1994/11/19  15:21:52  mike
95  * rip out unused code.
96  * 
97  * Revision 1.36  1994/11/14  11:42:51  mike
98  * optimization.
99  * 
100  * Revision 1.35  1994/11/12  16:41:36  mike
101  * *** empty log message ***
102  * 
103  * Revision 1.34  1994/11/10  21:28:41  mike
104  * remove call to init_interface_vars_to_assembler.
105  * 
106  * Revision 1.33  1994/11/10  11:08:59  mike
107  * detail level stuff.
108  * 
109  * Revision 1.32  1994/11/09  22:55:52  matt
110  * Added variable Current_seg_depth for detail level optimization
111  * 
112  * Revision 1.31  1994/11/09  19:57:31  john
113  * Added texture rle caching.
114  * 
115  * Revision 1.30  1994/11/09  19:54:48  mike
116  * Call flat shader if Tmap_flat_flag set.
117  * 
118  * Revision 1.29  1994/11/02  21:33:31  john
119  * Added Burger Bill's optimization, ie.. 2 muls per 8 pixels.
120  * 
121  * Revision 1.28  1994/11/02  11:32:16  john
122  * Added code for c callable inner loop and code to 
123  * test dividing out z0.
124  * 
125  * Revision 1.27  1994/10/28  20:54:32  matt
126  * Added error checking
127  * 
128  * Revision 1.26  1994/10/25  11:20:20  mike
129  * fix bug in lighting overflow checking for one scanline tall linear texture maps.
130  * 
131  * Revision 1.25  1994/08/03  15:40:33  mike
132  * Prevent divide overflows, decrease occurrence of precision-caused glitches.
133  * 
134  * Revision 1.24  1994/07/27  09:31:16  mike
135  * Fix concave texture map problem, decrease occurrence of unimportant int 3.
136  * 
137  * Revision 1.23  1994/06/17  12:23:31  mike
138  * Support non-lighted texture maps.
139  * 
140  * Revision 1.22  1994/06/11  08:10:24  mike
141  * Fix mysterious hang bug, lighting value was out of range.
142  * 
143  * Revision 1.21  1994/06/09  16:10:16  mike
144  * Change SC2000 from constant to variable.
145  * 
146  */
147
148 #ifdef HAVE_CONFIG_H
149 #include <conf.h>
150 #endif
151
152 #ifdef RCS
153 static char rcsid[] = "$Id: ntmap.c,v 1.5 2001-10-25 09:12:16 bradleyb Exp $";
154 #endif
155
156 #define VESA 0
157 #define NUM_TMAPS 16
158
159 #define HEADLIGHT_LIGHTING 0
160
161 #define WIREFRAME 0
162 #define PERSPECTIVE 1
163
164 #include "pstypes.h"
165 #include "fix.h"
166 #include "vecmat.h"
167 #include "gr.h"
168 #include "3d.h"
169 #include "error.h"
170
171 #include "texmap.h"
172 #include "texmapl.h"
173 #include "rle.h"
174 #include "scanline.h"
175
176 //#include "../main/textures.h"
177
178 #ifdef EDITOR
179 #define EDITOR_TMAP 1       //if in, include extra stuff
180 #endif
181
182 #define F15_5 (F1_0*15 + F0_5)
183
184 // Temporary texture map, interface from Matt's 3d system to Mike's texture mapper.
185 g3ds_tmap Tmap1;
186
187 grs_bitmap Texmap_ptrs[NUM_TMAPS];
188 grs_bitmap Texmap4_ptrs[NUM_TMAPS];
189
190 fix Range_max=0; // debug, kill me
191
192 int     Interpolation_method=0; // 0 = choose best method
193 int     Lighting_on=1;                  // initialize to no lighting
194 int     Tmap_flat_flag = 0;             //      1 = render texture maps as flat shaded polygons.
195 int     Current_seg_depth;              // HACK INTERFACE: how far away the current segment (& thus texture) is
196 int     Max_perspective_depth;
197 int     Max_linear_depth;
198 int     Max_flat_depth;
199
200 extern int Window_clip_left, Window_clip_bot, Window_clip_right, Window_clip_top;
201
202 // These variables are the interface to assembler.  They get set for each texture map, which is a real waste of time.
203 //      They should be set only when they change, which is generally when the window bounds change.  And, even still, it's
204 //      a pretty bad interface.
205 int     bytes_per_row=-1;
206 unsigned char *write_buffer;
207 int     window_left;
208 int     window_right;
209 int     window_top;
210 int     window_bottom;
211 int     window_width;
212 int     window_height;
213
214 #ifdef EDITOR_TMAP
215 #define MAX_Y_POINTERS  600
216 #else
217 #define MAX_Y_POINTERS  600
218 #endif
219 int     y_pointers[MAX_Y_POINTERS];
220
221 fix fix_recip[FIX_RECIP_TABLE_SIZE];
222
223 int     Lighting_enabled;
224 int     Fix_recip_table_computed=0;
225
226 fix fx_l, fx_u, fx_v, fx_z, fx_du_dx, fx_dv_dx, fx_dz_dx, fx_dl_dx;
227 int fx_xleft, fx_xright, fx_y;
228 unsigned char * pixptr;
229 int per2_flag = 0;
230 int Transparency_on = 0;
231 int dither_intensity_lighting = 0;
232
233 ubyte * tmap_flat_cthru_table;
234 ubyte tmap_flat_color;
235 ubyte tmap_flat_shade_value;
236
237
238
239 // -------------------------------------------------------------------------------------
240 void init_fix_recip_table(void)
241 {
242         int     i;
243
244         fix_recip[0] = F1_0;
245
246         for (i=1; i<FIX_RECIP_TABLE_SIZE; i++)
247                 fix_recip[i] = F1_0/i;
248
249         Fix_recip_table_computed = 1;
250 }
251
252 // -------------------------------------------------------------------------------------
253 //      Initialize interface variables to assembler.
254 //      These things used to be constants.  This routine is now (10/6/93) getting called for
255 //      every texture map.  It should get called whenever the window changes, or, preferably,
256 //      not at all.  I'm pretty sure these variables are only being used for range checking.
257 void init_interface_vars_to_assembler(void)
258 {
259         grs_bitmap      *bp;
260
261         bp = &grd_curcanv->cv_bitmap;
262
263         Assert(bp!=NULL);
264         Assert(bp->bm_data!=NULL);
265         Assert(bp->bm_h <= MAX_Y_POINTERS);
266
267         //      If bytes_per_row has changed, create new table of pointers.
268         if (bytes_per_row != (int) bp->bm_rowsize) {
269                 int     y_val, i;
270
271                 bytes_per_row = (int) bp->bm_rowsize;
272
273                 y_val = 0;
274                 for (i=0; i<MAX_Y_POINTERS; i++) {
275                         y_pointers[i] = y_val;
276                         y_val += bytes_per_row;
277                 }
278         }
279
280         write_buffer = (unsigned char *) bp->bm_data;
281
282         window_left = 0;
283         window_right = (int) bp->bm_w-1;
284         window_top = 0;
285         window_bottom = (int) bp->bm_h-1;
286
287         Window_clip_left = window_left;
288         Window_clip_right = window_right;
289         Window_clip_top = window_top;
290         Window_clip_bot = window_bottom;
291
292         window_width = bp->bm_w;
293         window_height = bp->bm_h;
294
295         if (!Fix_recip_table_computed)
296                 init_fix_recip_table();
297 }
298
299 // -------------------------------------------------------------------------------------
300 //                             VARIABLES
301 extern g3ds_tmap Tmap1;
302
303 // -------------------------------------------------------------------------------------
304 //      Returns number preceding val modulo modulus.
305 //      prevmod(3,4) = 2
306 //      prevmod(0,4) = 3
307 int prevmod(int val,int modulus)
308 {
309         if (val > 0)
310                 return val-1;
311         else
312                 return modulus-1;
313 //      return (val + modulus - 1) % modulus;
314 }
315
316
317 //      Returns number succeeding val modulo modulus.
318 //      succmod(3,4) = 0
319 //      succmod(0,4) = 1
320 int succmod(int val,int modulus)
321 {
322         if (val < modulus-1)
323                 return val+1;
324         else
325                 return 0;
326
327 //      return (val + 1) % modulus;
328 }
329
330 // -------------------------------------------------------------------------------------
331 //      Select topmost vertex (minimum y coordinate) and bottommost (maximum y coordinate) in
332 //      texture map.  If either is part of a horizontal edge, then select leftmost vertex for
333 //      top, rightmost vertex for bottom.
334 //      Important: Vertex is selected with integer precision.  So, if there are vertices at
335 //      (0.0,0.7) and (0.5,0.3), the first vertex is selected, because they y coordinates are
336 //      considered the same, so the smaller x is favored.
337 //      Parameters:
338 //              nv              number of vertices
339 //              v3d     pointer to 3d vertices containing u,v,x2d,y2d coordinates
340 //      Results in:
341 //              *min_y_ind
342 //              *max_y_ind
343 // -------------------------------------------------------------------------------------
344 void compute_y_bounds(g3ds_tmap *t, int *vlt, int *vlb, int *vrt, int *vrb,int *bottom_y_ind)
345 {
346         int     i;
347         int     min_y,max_y;
348         int     min_y_ind;
349         int     original_vrt;
350         fix     min_x;
351
352         // Scan all vertices, set min_y_ind to vertex with smallest y coordinate.
353         min_y = f2i(t->verts[0].y2d);
354         max_y = min_y;
355         min_y_ind = 0;
356         min_x = f2i(t->verts[0].x2d);
357         *bottom_y_ind = 0;
358
359         for (i=1; i<t->nv; i++) {
360                 if (f2i(t->verts[i].y2d) < min_y) {
361                         min_y = f2i(t->verts[i].y2d);
362                         min_y_ind = i;
363                         min_x = f2i(t->verts[i].x2d);
364                 } else if (f2i(t->verts[i].y2d) == min_y) {
365                         if (f2i(t->verts[i].x2d) < min_x) {
366                                 min_y_ind = i;
367                                 min_x = f2i(t->verts[i].x2d);
368                         }
369                 }
370                 if (f2i(t->verts[i].y2d) > max_y) {
371                         max_y = f2i(t->verts[i].y2d);
372                         *bottom_y_ind = i;
373                 }
374         }
375
376 //--removed mk, 11/27/94--      //      Check for a non-upright-hourglass polygon and fix, if necessary, by bashing a y coordinate.
377 //--removed mk, 11/27/94--      //      min_y_ind = index of minimum y coordinate, *bottom_y_ind = index of maximum y coordinate
378 //--removed mk, 11/27/94--{
379 //--removed mk, 11/27/94--      int     max_temp, min_temp;
380 //--removed mk, 11/27/94--
381 //--removed mk, 11/27/94--      max_temp = *bottom_y_ind;
382 //--removed mk, 11/27/94--      if (*bottom_y_ind < min_y_ind)
383 //--removed mk, 11/27/94--              max_temp += t->nv;
384 //--removed mk, 11/27/94--
385 //--removed mk, 11/27/94--      for (i=min_y_ind; i<max_temp; i++) {
386 //--removed mk, 11/27/94--              if (f2i(t->verts[i%t->nv].y2d) > f2i(t->verts[(i+1)%t->nv].y2d)) {
387 //--removed mk, 11/27/94--                      Int3();
388 //--removed mk, 11/27/94--                      t->verts[(i+1)%t->nv].y2d = t->verts[i%t->nv].y2d;
389 //--removed mk, 11/27/94--              }
390 //--removed mk, 11/27/94--      }
391 //--removed mk, 11/27/94--
392 //--removed mk, 11/27/94--      min_temp = min_y_ind;
393 //--removed mk, 11/27/94--      if (min_y_ind < *bottom_y_ind)
394 //--removed mk, 11/27/94--              min_temp += t->nv;
395 //--removed mk, 11/27/94--
396 //--removed mk, 11/27/94--      for (i=*bottom_y_ind; i<min_temp; i++) {
397 //--removed mk, 11/27/94--              if (f2i(t->verts[i%t->nv].y2d) < f2i(t->verts[(i+1)%t->nv].y2d)) {
398 //--removed mk, 11/27/94--                      Int3();
399 //--removed mk, 11/27/94--                      t->verts[(i+1)%t->nv].y2d = t->verts[i%t->nv].y2d;
400 //--removed mk, 11/27/94--              }
401 //--removed mk, 11/27/94--      }
402 //--removed mk, 11/27/94--}
403
404         // Set "vertex left top", etc. based on vertex with topmost y coordinate
405         *vlt = min_y_ind;
406         *vrt = *vlt;
407         *vlb = prevmod(*vlt,t->nv);
408         *vrb = succmod(*vrt,t->nv);
409
410         // If right edge is horizontal, then advance along polygon bound until it no longer is or until all
411         // vertices have been examined.
412         // (Left edge cannot be horizontal, because *vlt is set to leftmost point with highest y coordinate.)
413
414         original_vrt = *vrt;
415
416         while (f2i(t->verts[*vrt].y2d) == f2i(t->verts[*vrb].y2d)) {
417                 if (succmod(*vrt,t->nv) == original_vrt) {
418                         break;
419                 }
420                 *vrt = succmod(*vrt,t->nv);
421                 *vrb = succmod(*vrt,t->nv);
422         }
423 }
424
425 // -------------------------------------------------------------------------------------
426 //      Returns dx/dy given two vertices.
427 //      If dy == 0, returns 0.0
428 // -------------------------------------------------------------------------------------
429 //--fix compute_dx_dy_lin(g3ds_tmap *t, int top_vertex,int bottom_vertex)
430 //--{
431 //--    int     dy;
432 //--
433 //--    // compute delta x with respect to y for any edge
434 //--    dy = f2i(t->verts[bottom_vertex].y2d - t->verts[top_vertex].y2d) + 1;
435 //--    if (dy)
436 //--            return (t->verts[bottom_vertex].x2d - t->verts[top_vertex].x2d) / dy;
437 //--    else
438 //--            return 0;
439 //--
440 //--}
441
442 fix compute_du_dy_lin(g3ds_tmap *t, int top_vertex,int bottom_vertex, fix recip_dy)
443 {
444         return fixmul(t->verts[bottom_vertex].u - t->verts[top_vertex].u, recip_dy);
445 }
446
447
448 fix compute_dv_dy_lin(g3ds_tmap *t, int top_vertex,int bottom_vertex, fix recip_dy)
449 {
450         return fixmul(t->verts[bottom_vertex].v - t->verts[top_vertex].v, recip_dy);
451 }
452
453 fix compute_dl_dy_lin(g3ds_tmap *t, int top_vertex,int bottom_vertex, fix recip_dy)
454 {
455         return fixmul(t->verts[bottom_vertex].l - t->verts[top_vertex].l, recip_dy);
456
457 }
458
459 fix compute_dx_dy(g3ds_tmap *t, int top_vertex,int bottom_vertex, fix recip_dy)
460 {
461         return fixmul(t->verts[bottom_vertex].x2d - t->verts[top_vertex].x2d, recip_dy);
462 }
463
464 fix compute_du_dy(g3ds_tmap *t, int top_vertex,int bottom_vertex, fix recip_dy)
465 {
466         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);
467 }
468
469
470 fix compute_dv_dy(g3ds_tmap *t, int top_vertex,int bottom_vertex, fix recip_dy)
471 {
472         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);
473
474 }
475
476 fix compute_dz_dy(g3ds_tmap *t, int top_vertex,int bottom_vertex, fix recip_dy)
477 {
478         return fixmul(t->verts[bottom_vertex].z - t->verts[top_vertex].z, recip_dy);
479
480 }
481 int Skip_short_flag=0;
482
483 // -------------------------------------------------------------------------------------
484 //      Texture map current scanline in perspective.
485 // -------------------------------------------------------------------------------------
486 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)
487 {
488         fix     dx,recip_dx;
489
490         fx_xright = f2i(xright);
491         //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?
492         if (fx_xright < Window_clip_left)
493                 return;
494         fx_xleft = f2i(xleft);
495         if (fx_xleft > Window_clip_right)
496                 return;
497         //end edit -MM
498
499         dx = fx_xright - fx_xleft;
500         if ((dx < 0) || (xright < 0) || (xleft > xright))               // the (xleft > xright) term is not redundant with (dx < 0) because dx is computed using integers
501                 return;
502
503         // setup to call assembler scanline renderer
504         if (dx < FIX_RECIP_TABLE_SIZE)
505                 recip_dx = fix_recip[dx];
506         else
507                 recip_dx = F1_0/dx;
508
509         fx_u = uleft;
510         fx_v = vleft;
511         fx_z = zleft;
512         
513         fx_du_dx = fixmul(uright - uleft,recip_dx);
514         fx_dv_dx = fixmul(vright - vleft,recip_dx);
515         fx_dz_dx = fixmul(zright - zleft,recip_dx);
516         fx_y = y;
517         pixptr = srcb->bm_data;
518
519         switch (Lighting_enabled) {
520                 case 0:
521                         //added 05/17/99 Matt Mueller - prevent writing before the buffer
522             if ((fx_y == 0) && (fx_xleft < 0))
523                                 fx_xleft = 0;
524                         //end addition -MM
525                         if (fx_xright > Window_clip_right)
526                                 fx_xright = Window_clip_right;
527                         
528                         cur_tmap_scanline_per();
529                         break;
530                 case 1: {
531                         fix     mul_thing;
532
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);
537
538                         fx_l = lleft;
539                         fx_dl_dx = fixmul(lright - lleft,recip_dx);
540
541                         //      This is a pretty ugly hack to prevent lighting overflows.
542                         mul_thing = dx * fx_dl_dx;
543                         if (lleft + mul_thing < 0)
544                                 fx_dl_dx += 12;
545                         else if (lleft + mul_thing > (NUM_LIGHTING_LEVELS*F1_0-F1_0/2))
546                                 fx_dl_dx -= 12;
547
548                         //added 05/17/99 Matt Mueller - prevent writing before the buffer
549             if ((fx_y == 0) && (fx_xleft < 0))
550                                 fx_xleft = 0;
551                         //end addition -MM
552                         if (fx_xright > Window_clip_right)
553                                 fx_xright = Window_clip_right;
554
555                         cur_tmap_scanline_per();
556                         break;
557                 }
558                 case 2:
559 #ifdef EDITOR_TMAP
560                         fx_xright = f2i(xright);
561                         fx_xleft = f2i(xleft);
562
563                         tmap_flat_color = 1;
564                         cur_tmap_scanline_flat();
565 #else
566                         Int3(); //      Illegal, called an editor only routine!
567 #endif
568                         break;
569         }
570
571 }
572
573 int Do_vertical_scan=0;
574
575 int     Break_on_flat=0;
576
577 // -------------------------------------------------------------------------------------
578 //      Render a texture map with lighting using perspective interpolation in inner and outer loops.
579 // -------------------------------------------------------------------------------------
580 void ntexture_map_lighted(grs_bitmap *srcb, g3ds_tmap *t)
581 {
582         int     vlt,vrt,vlb,vrb;        // vertex left top, vertex right top, vertex left bottom, vertex right bottom
583         int     topy,boty,y, dy;
584         fix     dx_dy_left,dx_dy_right;
585         fix     du_dy_left,du_dy_right;
586         fix     dv_dy_left,dv_dy_right;
587         fix     dz_dy_left,dz_dy_right;
588         fix     dl_dy_left,dl_dy_right;
589         fix     recip_dyl, recip_dyr;
590         int     max_y_vertex;
591         fix     xleft,xright,uleft,vleft,uright,vright,zleft,zright,lleft,lright;
592         int     next_break_left, next_break_right;
593
594         g3ds_vertex *v3d;
595
596         //remove stupid warnings in compile
597         dl_dy_left = F1_0;
598         dl_dy_right = F1_0;
599         lleft = F1_0;
600         lright = F1_0;
601
602         v3d = t->verts;
603
604         // Determine top and bottom y coords.
605         compute_y_bounds(t,&vlt,&vlb,&vrt,&vrb,&max_y_vertex);
606
607         // Set top and bottom (of entire texture map) y coordinates.
608         topy = f2i(v3d[vlt].y2d);
609         boty = f2i(v3d[max_y_vertex].y2d);
610         if (topy > Window_clip_bot)
611                 return;
612         if (boty > Window_clip_bot)
613                 boty = Window_clip_bot;
614
615         // Set amount to change x coordinate for each advance to next scanline.
616         dy = f2i(t->verts[vlb].y2d) - f2i(t->verts[vlt].y2d);
617         if (dy < FIX_RECIP_TABLE_SIZE)
618                 recip_dyl = fix_recip[dy];
619         else
620                 recip_dyl = F1_0/dy;
621
622         dx_dy_left = compute_dx_dy(t,vlt,vlb, recip_dyl);
623         du_dy_left = compute_du_dy(t,vlt,vlb, recip_dyl);
624         dv_dy_left = compute_dv_dy(t,vlt,vlb, recip_dyl);
625         dz_dy_left = compute_dz_dy(t,vlt,vlb, recip_dyl);
626
627         dy = f2i(t->verts[vrb].y2d) - f2i(t->verts[vrt].y2d);
628         if (dy < FIX_RECIP_TABLE_SIZE)
629                 recip_dyr = fix_recip[dy];
630         else
631                 recip_dyr = F1_0/dy;
632
633         du_dy_right = compute_du_dy(t,vrt,vrb, recip_dyr);
634         dx_dy_right = compute_dx_dy(t,vrt,vrb, recip_dyr);
635         dv_dy_right = compute_dv_dy(t,vrt,vrb, recip_dyr);
636         dz_dy_right = compute_dz_dy(t,vrt,vrb, recip_dyr);
637
638         if (Lighting_enabled) {
639                 dl_dy_left = compute_dl_dy_lin(t,vlt,vlb, recip_dyl);
640                 dl_dy_right = compute_dl_dy_lin(t,vrt,vrb, recip_dyr);
641
642                 lleft = v3d[vlt].l;
643                 lright = v3d[vrt].l;
644         }
645
646         // Set initial values for x, u, v
647         xleft = v3d[vlt].x2d;
648         xright = v3d[vrt].x2d;
649
650         zleft = v3d[vlt].z;
651         zright = v3d[vrt].z;
652
653         uleft = fixmul(v3d[vlt].u,zleft);
654         uright = fixmul(v3d[vrt].u,zright);
655         vleft = fixmul(v3d[vlt].v,zleft);
656         vright = fixmul(v3d[vrt].v,zright);
657
658         // scan all rows in texture map from top through first break.
659         next_break_left = f2i(v3d[vlb].y2d);
660         next_break_right = f2i(v3d[vrb].y2d);
661
662         for (y = topy; y < boty; y++) {
663
664                 // See if we have reached the end of the current left edge, and if so, set
665                 // new values for dx_dy and x,u,v
666                 if (y == next_break_left) {
667                         fix     recip_dy;
668
669                         // Handle problem of double points.  Search until y coord is different.  Cannot get
670                         // hung in an infinite loop because we know there is a vertex with a lower y coordinate
671                         // because in the for loop, we don't scan all spanlines.
672                         while (y == f2i(v3d[vlb].y2d)) {
673                                 vlt = vlb;
674                                 vlb = prevmod(vlb,t->nv);
675                         }
676                         next_break_left = f2i(v3d[vlb].y2d);
677
678                         dy = f2i(t->verts[vlb].y2d) - f2i(t->verts[vlt].y2d);
679                         if (dy < FIX_RECIP_TABLE_SIZE)
680                                 recip_dy = fix_recip[dy];
681                         else
682                                 recip_dy = F1_0/dy;
683
684                         dx_dy_left = compute_dx_dy(t,vlt,vlb, recip_dy);
685
686                         xleft = v3d[vlt].x2d;
687                         zleft = v3d[vlt].z;
688                         uleft = fixmul(v3d[vlt].u,zleft);
689                         vleft = fixmul(v3d[vlt].v,zleft);
690                         lleft = v3d[vlt].l;
691
692                         du_dy_left = compute_du_dy(t,vlt,vlb, recip_dy);
693                         dv_dy_left = compute_dv_dy(t,vlt,vlb, recip_dy);
694                         dz_dy_left = compute_dz_dy(t,vlt,vlb, recip_dy);
695
696                         if (Lighting_enabled) {
697                                 dl_dy_left = compute_dl_dy_lin(t,vlt,vlb, recip_dy);
698                                 lleft = v3d[vlt].l;
699                         }
700                 }
701
702                 // See if we have reached the end of the current left edge, and if so, set
703                 // new values for dx_dy and x.  Not necessary to set new values for u,v.
704                 if (y == next_break_right) {
705                         fix     recip_dy;
706
707                         while (y == f2i(v3d[vrb].y2d)) {
708                                 vrt = vrb;
709                                 vrb = succmod(vrb,t->nv);
710                         }
711
712                         next_break_right = f2i(v3d[vrb].y2d);
713
714                         dy = f2i(t->verts[vrb].y2d) - f2i(t->verts[vrt].y2d);
715                         if (dy < FIX_RECIP_TABLE_SIZE)
716                                 recip_dy = fix_recip[dy];
717                         else
718                                 recip_dy = F1_0/dy;
719
720                         dx_dy_right = compute_dx_dy(t,vrt,vrb, recip_dy);
721
722                         xright = v3d[vrt].x2d;
723                         zright = v3d[vrt].z;
724                         uright = fixmul(v3d[vrt].u,zright);
725                         vright = fixmul(v3d[vrt].v,zright);
726
727                         du_dy_right = compute_du_dy(t,vrt,vrb, recip_dy);
728                         dv_dy_right = compute_dv_dy(t,vrt,vrb, recip_dy);
729                         dz_dy_right = compute_dz_dy(t,vrt,vrb, recip_dy);
730
731                         if (Lighting_enabled) {
732                                 dl_dy_right = compute_dl_dy_lin(t,vrt,vrb, recip_dy);
733                                 lright = v3d[vrt].l;
734                         }
735                 }
736
737                 if (Lighting_enabled) {
738                         if (y >= Window_clip_top)
739                                 ntmap_scanline_lighted(srcb,y,xleft,xright,uleft,uright,vleft,vright,zleft,zright,lleft,lright);
740                         lleft += dl_dy_left;
741                         lright += dl_dy_right;
742                 } else
743                         if (y >= Window_clip_top)
744                                 ntmap_scanline_lighted(srcb,y,xleft,xright,uleft,uright,vleft,vright,zleft,zright,lleft,lright);
745
746                 uleft += du_dy_left;
747                 vleft += dv_dy_left;
748
749                 uright += du_dy_right;
750                 vright += dv_dy_right;
751
752                 xleft += dx_dy_left;
753                 xright += dx_dy_right;
754
755                 zleft += dz_dy_left;
756                 zright += dz_dy_right;
757
758         }
759
760         // We can get lleft or lright out of bounds here because we compute dl_dy using fixed point values,
761         //      but we plot an integer number of scanlines, therefore doing an integer number of additions of the delta.
762
763 //if (Break_on_flat)
764 //      mprintf(0, "[%i %i %i] ", y, f2i(xleft), f2i(xright));
765
766         ntmap_scanline_lighted(srcb,y,xleft,xright,uleft,uright,vleft,vright,zleft,zright,lleft,lright);
767 }
768
769
770 // -------------------------------------------------------------------------------------
771 //      Texture map current scanline using linear interpolation.
772 // -------------------------------------------------------------------------------------
773 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)
774 {
775         fix     u,v,l;
776         fix     dx,recip_dx;
777
778         fix     du_dx,dv_dx,dl_dx;
779
780         u = uleft;
781         v = vleft;
782         l = lleft;
783
784         dx = f2i(xright) - f2i(xleft);
785         if ((dx < 0) || (xright < 0) || (xleft > xright))               // the (xleft > xright) term is not redundant with (dx < 0) because dx is computed using integers
786                 return;
787
788                 // setup to call assembler scanline renderer
789                 if (dx < FIX_RECIP_TABLE_SIZE)
790                         recip_dx = fix_recip[dx];
791                 else
792                         recip_dx = F1_0/dx;
793
794                 du_dx = fixmul(uright - uleft,recip_dx);
795                 dv_dx = fixmul(vright - vleft,recip_dx);
796
797                 fx_u = uleft;
798                 fx_v = vleft;
799                 fx_du_dx = du_dx;
800                 fx_dv_dx = dv_dx;
801                 fx_y = y;
802                 fx_xright = f2i(xright);
803                 fx_xleft = f2i(xleft);
804                 pixptr = srcb->bm_data;
805
806                 switch (Lighting_enabled) {
807                         case 0:
808                                 //added 07/11/99 adb - prevent writing before the buffer
809                                 if (fx_xleft < 0)
810                                         fx_xleft = 0;
811                                 //end addition -adb
812                                 
813                                 cur_tmap_scanline_lin_nolight();
814                                 break;
815                         case 1:
816                                 if (lleft < F1_0/2)
817                                         lleft = F1_0/2;
818                                 if (lright < F1_0/2)
819                                         lright = F1_0/2;
820
821                                 if (lleft > MAX_LIGHTING_VALUE*NUM_LIGHTING_LEVELS)
822                                         lleft = MAX_LIGHTING_VALUE*NUM_LIGHTING_LEVELS;
823                                 if (lright > MAX_LIGHTING_VALUE*NUM_LIGHTING_LEVELS)
824                                         lright = MAX_LIGHTING_VALUE*NUM_LIGHTING_LEVELS;
825
826                                 //added 07/11/99 adb - prevent writing before the buffer
827                                 if (fx_xleft < 0)
828                                         fx_xleft = 0;
829                                 //end addition -adb
830
831 {
832                         fix mul_thing;
833
834                         fx_l = lleft;
835                         fx_dl_dx = fixmul(lright - lleft,recip_dx);
836
837                         //      This is a pretty ugly hack to prevent lighting overflows.
838                         mul_thing = dx * fx_dl_dx;
839                         if (lleft + mul_thing < 0)
840                                 fx_dl_dx += 12;
841                         else if (lleft + mul_thing > (NUM_LIGHTING_LEVELS*F1_0-F1_0/2))
842                                 fx_dl_dx -= 12;
843 }
844
845                                 fx_l = lleft;
846                                 dl_dx = fixmul(lright - lleft,recip_dx);
847                                 fx_dl_dx = dl_dx;
848                                 cur_tmap_scanline_lin();
849                                 break;
850                         case 2:
851 #ifdef EDITOR_TMAP
852                                 fx_xright = f2i(xright);
853                                 fx_xleft = f2i(xleft);
854                                 tmap_flat_color = 1;
855                                 cur_tmap_scanline_flat();
856 #else
857                                 Int3(); //      Illegal, called an editor only routine!
858 #endif
859                                 break;
860                 }
861 }
862
863 // -------------------------------------------------------------------------------------
864 //      Render a texture map with lighting using perspective interpolation in inner and outer loops.
865 // -------------------------------------------------------------------------------------
866 void ntexture_map_lighted_linear(grs_bitmap *srcb, g3ds_tmap *t)
867 {
868         int     vlt,vrt,vlb,vrb;        // vertex left top, vertex right top, vertex left bottom, vertex right bottom
869         int     topy,boty,y, dy;
870         fix     dx_dy_left,dx_dy_right;
871         fix     du_dy_left,du_dy_right;
872         fix     dv_dy_left,dv_dy_right;
873         fix     dl_dy_left,dl_dy_right;
874         int     max_y_vertex;
875         fix     xleft,xright,uleft,vleft,uright,vright,lleft,lright;
876         int     next_break_left, next_break_right;
877         fix     recip_dyl, recip_dyr;
878
879         g3ds_vertex *v3d;
880
881         //remove stupid warnings in compile
882         dl_dy_left = F1_0;
883         dl_dy_right = F1_0;
884         lleft = F1_0;
885         lright = F1_0;
886
887         v3d = t->verts;
888
889         // Determine top and bottom y coords.
890         compute_y_bounds(t,&vlt,&vlb,&vrt,&vrb,&max_y_vertex);
891
892         // Set top and bottom (of entire texture map) y coordinates.
893         topy = f2i(v3d[vlt].y2d);
894         boty = f2i(v3d[max_y_vertex].y2d);
895
896         if (topy > Window_clip_bot)
897                 return;
898         if (boty > Window_clip_bot)
899                 boty = Window_clip_bot;
900
901         dy = f2i(t->verts[vlb].y2d) - f2i(t->verts[vlt].y2d);
902         if (dy < FIX_RECIP_TABLE_SIZE)
903                 recip_dyl = fix_recip[dy];
904         else
905                 recip_dyl = F1_0/dy;
906
907         dy = f2i(t->verts[vrb].y2d) - f2i(t->verts[vrt].y2d);
908         if (dy < FIX_RECIP_TABLE_SIZE)
909                 recip_dyr = fix_recip[dy];
910         else
911                 recip_dyr = F1_0/dy;
912
913         // Set amount to change x coordinate for each advance to next scanline.
914         dx_dy_left = compute_dx_dy(t,vlt,vlb, recip_dyl);
915         dx_dy_right = compute_dx_dy(t,vrt,vrb, recip_dyr);
916
917         du_dy_left = compute_du_dy_lin(t,vlt,vlb, recip_dyl);
918         du_dy_right = compute_du_dy_lin(t,vrt,vrb, recip_dyr);
919
920         dv_dy_left = compute_dv_dy_lin(t,vlt,vlb, recip_dyl);
921         dv_dy_right = compute_dv_dy_lin(t,vrt,vrb, recip_dyr);
922
923         if (Lighting_enabled) {
924                 dl_dy_left = compute_dl_dy_lin(t,vlt,vlb, recip_dyl);
925                 dl_dy_right = compute_dl_dy_lin(t,vrt,vrb, recip_dyr);
926
927                 lleft = v3d[vlt].l;
928                 lright = v3d[vrt].l;
929         }
930
931         // Set initial values for x, u, v
932         xleft = v3d[vlt].x2d;
933         xright = v3d[vrt].x2d;
934
935         uleft = v3d[vlt].u;
936         uright = v3d[vrt].u;
937         vleft = v3d[vlt].v;
938         vright = v3d[vrt].v;
939
940         // scan all rows in texture map from top through first break.
941         next_break_left = f2i(v3d[vlb].y2d);
942         next_break_right = f2i(v3d[vrb].y2d);
943
944         for (y = topy; y < boty; y++) {
945
946                 // See if we have reached the end of the current left edge, and if so, set
947                 // new values for dx_dy and x,u,v
948                 if (y == next_break_left) {
949                         fix     recip_dy;
950
951                         // Handle problem of double points.  Search until y coord is different.  Cannot get
952                         // hung in an infinite loop because we know there is a vertex with a lower y coordinate
953                         // because in the for loop, we don't scan all spanlines.
954                         while (y == f2i(v3d[vlb].y2d)) {
955                                 vlt = vlb;
956                                 vlb = prevmod(vlb,t->nv);
957                         }
958                         next_break_left = f2i(v3d[vlb].y2d);
959
960                         dy = f2i(t->verts[vlb].y2d) - f2i(t->verts[vlt].y2d);
961                         if (dy < FIX_RECIP_TABLE_SIZE)
962                                 recip_dy = fix_recip[dy];
963                         else
964                                 recip_dy = F1_0/dy;
965
966                         dx_dy_left = compute_dx_dy(t,vlt,vlb, recip_dy);
967
968                         xleft = v3d[vlt].x2d;
969                         uleft = v3d[vlt].u;
970                         vleft = v3d[vlt].v;
971                         lleft = v3d[vlt].l;
972
973                         du_dy_left = compute_du_dy_lin(t,vlt,vlb, recip_dy);
974                         dv_dy_left = compute_dv_dy_lin(t,vlt,vlb, recip_dy);
975
976                         if (Lighting_enabled) {
977                                 dl_dy_left = compute_dl_dy_lin(t,vlt,vlb, recip_dy);
978                                 lleft = v3d[vlt].l;
979                         }
980                 }
981
982                 // See if we have reached the end of the current left edge, and if so, set
983                 // new values for dx_dy and x.  Not necessary to set new values for u,v.
984                 if (y == next_break_right) {
985                         fix     recip_dy;
986
987                         while (y == f2i(v3d[vrb].y2d)) {
988                                 vrt = vrb;
989                                 vrb = succmod(vrb,t->nv);
990                         }
991
992                         dy = f2i(t->verts[vrb].y2d) - f2i(t->verts[vrt].y2d);
993                         if (dy < FIX_RECIP_TABLE_SIZE)
994                                 recip_dy = fix_recip[dy];
995                         else
996                                 recip_dy = F1_0/dy;
997
998                         next_break_right = f2i(v3d[vrb].y2d);
999                         dx_dy_right = compute_dx_dy(t,vrt,vrb, recip_dy);
1000
1001                         xright = v3d[vrt].x2d;
1002                         uright = v3d[vrt].u;
1003                         vright = v3d[vrt].v;
1004
1005                         du_dy_right = compute_du_dy_lin(t,vrt,vrb, recip_dy);
1006                         dv_dy_right = compute_dv_dy_lin(t,vrt,vrb, recip_dy);
1007
1008                         if (Lighting_enabled) {
1009                                 dl_dy_right = compute_dl_dy_lin(t,vrt,vrb, recip_dy);
1010                                 lright = v3d[vrt].l;
1011                         }
1012                 }
1013
1014                 if (Lighting_enabled) {
1015                         ntmap_scanline_lighted_linear(srcb,y,xleft,xright,uleft,uright,vleft,vright,lleft,lright);
1016                         lleft += dl_dy_left;
1017                         lright += dl_dy_right;
1018                 } else
1019                         ntmap_scanline_lighted_linear(srcb,y,xleft,xright,uleft,uright,vleft,vright,lleft,lright);
1020
1021                 uleft += du_dy_left;
1022                 vleft += dv_dy_left;
1023
1024                 uright += du_dy_right;
1025                 vright += dv_dy_right;
1026
1027                 xleft += dx_dy_left;
1028                 xright += dx_dy_right;
1029
1030         }
1031
1032         // We can get lleft or lright out of bounds here because we compute dl_dy using fixed point values,
1033         //      but we plot an integer number of scanlines, therefore doing an integer number of additions of the delta.
1034
1035         ntmap_scanline_lighted_linear(srcb,y,xleft,xright,uleft,uright,vleft,vright,lleft,lright);
1036 }
1037
1038 // fix  DivNum = F1_0*12;
1039
1040 extern void draw_tmap_flat(grs_bitmap *bp,int nverts,g3s_point **vertbuf);
1041
1042 // -------------------------------------------------------------------------------------
1043 // Interface from Matt's data structures to Mike's texture mapper.
1044 // -------------------------------------------------------------------------------------
1045 void draw_tmap(grs_bitmap *bp,int nverts,g3s_point **vertbuf)
1046 {
1047         int     i;
1048
1049         //      These variables are used in system which renders texture maps which lie on one scanline as a line.
1050         // fix  div_numerator;
1051         int     lighting_on_save = Lighting_on;
1052
1053         Assert(nverts <= MAX_TMAP_VERTS);
1054
1055
1056 #ifdef USE_MULT_CODE
1057         if ( !divide_table_filled ) fill_divide_table();
1058 #endif
1059
1060         // -- now called from g3_start_frame -- init_interface_vars_to_assembler();
1061
1062         //      If no transparency and seg depth is large, render as flat shaded.
1063         if ((Current_seg_depth > Max_linear_depth) && ((bp->bm_flags & 3) == 0)) {
1064                 draw_tmap_flat(bp, nverts, vertbuf);
1065                 return;
1066         }
1067
1068         if ( bp->bm_flags & BM_FLAG_RLE )
1069                 bp = rle_expand_texture( bp );          // Expand if rle'd
1070
1071         Transparency_on = bp->bm_flags & BM_FLAG_TRANSPARENT;
1072         if (bp->bm_flags & BM_FLAG_NO_LIGHTING)
1073                 Lighting_on = 0;
1074
1075
1076         // Setup texture map in Tmap1
1077         Tmap1.nv = nverts;                                              // Initialize number of vertices
1078
1079 //      div_numerator = DivNum; //f1_0*3;
1080
1081         for (i=0; i<nverts; i++) {
1082                 g3ds_vertex     *tvp = &Tmap1.verts[i];
1083                 g3s_point       *vp = vertbuf[i];
1084
1085                 tvp->x2d = vp->p3_sx;
1086                 tvp->y2d = vp->p3_sy;
1087
1088                 //      Check for overflow on fixdiv.  Will overflow on vp->z <= something small.  Allow only as low as 256.
1089                 if (vp->p3_z < 256) {
1090                         vp->p3_z = 256;
1091                         // Int3();              // we would overflow if we divided!
1092                 }
1093
1094                 tvp->z = fixdiv(F1_0*12, vp->p3_z);
1095                 tvp->u = vp->p3_u << 6; //* bp->bm_w;
1096                 tvp->v = vp->p3_v << 6; //* bp->bm_h;
1097
1098                 Assert(Lighting_on < 3);
1099
1100                 if (Lighting_on)
1101                         tvp->l = vp->p3_l * NUM_LIGHTING_LEVELS;
1102         }
1103
1104
1105         Lighting_enabled = Lighting_on;
1106
1107         // Now, call my texture mapper.
1108         if (Lighting_on) {
1109                 switch (Interpolation_method) { // 0 = choose, 1 = linear, 2 = /8 perspective, 3 = full perspective
1110                         case 0:                                                         // choose best interpolation
1111                                 per2_flag = 1;
1112                                 if (Current_seg_depth > Max_perspective_depth)
1113                                         ntexture_map_lighted_linear(bp, &Tmap1);
1114                                 else
1115                                         ntexture_map_lighted(bp, &Tmap1);
1116                                 break;
1117                         case 1:                                                         // linear interpolation
1118                                 per2_flag = 1;
1119                                 ntexture_map_lighted_linear(bp, &Tmap1);
1120                                 break;
1121                         case 2:                                                         // perspective every 8th pixel interpolation
1122                                 per2_flag = 1;
1123                                 ntexture_map_lighted(bp, &Tmap1);
1124                                 break;
1125                         case 3:                                                         // perspective every pixel interpolation
1126                                 per2_flag = 0;                                  // this hack means do divide every pixel
1127                                 ntexture_map_lighted(bp, &Tmap1);
1128                                 break;
1129                         default:
1130                                 Assert(0);                              // Illegal value for Interpolation_method, must be 0,1,2,3
1131                 }
1132         } else {
1133                 switch (Interpolation_method) { // 0 = choose, 1 = linear, 2 = /8 perspective, 3 = full perspective
1134                         case 0:                                                         // choose best interpolation
1135                                 per2_flag = 1;
1136                                 if (Current_seg_depth > Max_perspective_depth)
1137                                         ntexture_map_lighted_linear(bp, &Tmap1);
1138                                 else
1139                                         ntexture_map_lighted(bp, &Tmap1);
1140                                 break;
1141                         case 1:                                                         // linear interpolation
1142                                 per2_flag = 1;
1143                                 ntexture_map_lighted_linear(bp, &Tmap1);
1144                                 break;
1145                         case 2:                                                         // perspective every 8th pixel interpolation
1146                                 per2_flag = 1;
1147                                 ntexture_map_lighted(bp, &Tmap1);
1148                                 break;
1149                         case 3:                                                         // perspective every pixel interpolation
1150                                 per2_flag = 0;                                  // this hack means do divide every pixel
1151                                 ntexture_map_lighted(bp, &Tmap1);
1152                                 break;
1153                         default:
1154                                 Assert(0);                              // Illegal value for Interpolation_method, must be 0,1,2,3
1155                 }
1156         }
1157
1158         Lighting_on = lighting_on_save;
1159
1160 }
1161