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