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