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