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