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