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