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