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