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