1 /* $Id: ntmap.c,v 1.7 2003-02-18 20:15:48 btb Exp $ */
3 THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
4 SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO
5 END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
6 ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
7 IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
8 SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
9 FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
10 CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS
11 AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.
12 COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED.
17 * Start of conversion to new texture mapper.
20 * Revision 1.52 1995/03/14 15:13:06 john
21 * Increased MAX_Y_Pointers to 480.
23 * Revision 1.51 1995/02/23 14:25:09 john
26 * Revision 1.50 1995/02/20 18:22:58 john
27 * Put all the externs in the assembly modules into tmap_inc.asm.
28 * Also, moved all the C versions of the inner loops into a new module,
31 * Revision 1.49 1995/02/20 17:09:11 john
32 * Added code so that you can build the tmapper with no assembly!
34 * Revision 1.48 1995/01/06 11:11:30 mike
35 * even when not in editor, have 400 lines in texture map scanline table.
37 * Revision 1.47 1994/12/15 16:43:25 matt
38 * Took out code only needed by editor
40 * Revision 1.46 1994/12/09 22:35:37 mike
41 * fix bug in before call to asm_tmap_scanline_per causing write of pixel onto past right border onto left.
43 * Revision 1.45 1994/12/06 16:31:06 mike
44 * fix bug in asm_tmap_scanline_matt interface.
46 * Revision 1.44 1994/12/04 20:37:18 mike
47 * *** empty log message ***
49 * Revision 1.43 1994/12/02 23:30:04 mike
52 * Revision 1.42 1994/11/30 00:57:43 mike
55 * Revision 1.41 1994/11/28 13:34:27 mike
58 * Revision 1.40 1994/11/28 01:30:01 mike
61 * Revision 1.39 1994/11/28 01:28:59 mike
64 * Revision 1.38 1994/11/21 14:08:07 john
65 * Took out all multiple instead of divide code.
67 * Revision 1.37 1994/11/19 15:21:52 mike
68 * rip out unused code.
70 * Revision 1.36 1994/11/14 11:42:51 mike
73 * Revision 1.35 1994/11/12 16:41:36 mike
74 * *** empty log message ***
76 * Revision 1.34 1994/11/10 21:28:41 mike
77 * remove call to init_interface_vars_to_assembler.
79 * Revision 1.33 1994/11/10 11:08:59 mike
82 * Revision 1.32 1994/11/09 22:55:52 matt
83 * Added variable Current_seg_depth for detail level optimization
85 * Revision 1.31 1994/11/09 19:57:31 john
86 * Added texture rle caching.
88 * Revision 1.30 1994/11/09 19:54:48 mike
89 * Call flat shader if Tmap_flat_flag set.
91 * Revision 1.29 1994/11/02 21:33:31 john
92 * Added Burger Bill's optimization, ie.. 2 muls per 8 pixels.
94 * Revision 1.28 1994/11/02 11:32:16 john
95 * Added code for c callable inner loop and code to
96 * test dividing out z0.
98 * Revision 1.27 1994/10/28 20:54:32 matt
99 * Added error checking
101 * Revision 1.26 1994/10/25 11:20:20 mike
102 * fix bug in lighting overflow checking for one scanline tall linear texture maps.
104 * Revision 1.25 1994/08/03 15:40:33 mike
105 * Prevent divide overflows, decrease occurrence of precision-caused glitches.
107 * Revision 1.24 1994/07/27 09:31:16 mike
108 * Fix concave texture map problem, decrease occurrence of unimportant int 3.
110 * Revision 1.23 1994/06/17 12:23:31 mike
111 * Support non-lighted texture maps.
113 * Revision 1.22 1994/06/11 08:10:24 mike
114 * Fix mysterious hang bug, lighting value was out of range.
116 * Revision 1.21 1994/06/09 16:10:16 mike
117 * Change SC2000 from constant to variable.
126 static char rcsid[] = "$Id: ntmap.c,v 1.7 2003-02-18 20:15:48 btb Exp $";
132 #define HEADLIGHT_LIGHTING 0
135 #define PERSPECTIVE 1
147 #include "scanline.h"
149 //#include "../main/textures.h"
152 #define EDITOR_TMAP 1 //if in, include extra stuff
155 #define F15_5 (F1_0*15 + F0_5)
157 // Temporary texture map, interface from Matt's 3d system to Mike's texture mapper.
160 grs_bitmap Texmap_ptrs[NUM_TMAPS];
161 grs_bitmap Texmap4_ptrs[NUM_TMAPS];
163 fix Range_max=0; // debug, kill me
165 int Interpolation_method=0; // 0 = choose best method
166 int Lighting_on=1; // initialize to no lighting
167 int Tmap_flat_flag = 0; // 1 = render texture maps as flat shaded polygons.
168 int Current_seg_depth; // HACK INTERFACE: how far away the current segment (& thus texture) is
169 int Max_perspective_depth;
170 int Max_linear_depth;
173 extern int Window_clip_left, Window_clip_bot, Window_clip_right, Window_clip_top;
175 // These variables are the interface to assembler. They get set for each texture map, which is a real waste of time.
176 // They should be set only when they change, which is generally when the window bounds change. And, even still, it's
177 // a pretty bad interface.
178 int bytes_per_row=-1;
179 unsigned char *write_buffer;
187 #define MAX_Y_POINTERS 1024
189 int y_pointers[MAX_Y_POINTERS];
191 fix fix_recip[FIX_RECIP_TABLE_SIZE];
193 int Lighting_enabled;
194 int Fix_recip_table_computed=0;
196 fix fx_l, fx_u, fx_v, fx_z, fx_du_dx, fx_dv_dx, fx_dz_dx, fx_dl_dx;
197 int fx_xleft, fx_xright, fx_y;
198 unsigned char * pixptr;
200 int Transparency_on = 0;
201 int dither_intensity_lighting = 0;
203 ubyte * tmap_flat_cthru_table;
204 ubyte tmap_flat_color;
205 ubyte tmap_flat_shade_value;
209 // -------------------------------------------------------------------------------------
210 void init_fix_recip_table(void)
216 for (i=1; i<FIX_RECIP_TABLE_SIZE; i++)
217 fix_recip[i] = F1_0/i;
219 Fix_recip_table_computed = 1;
222 // -------------------------------------------------------------------------------------
223 // Initialize interface variables to assembler.
224 // These things used to be constants. This routine is now (10/6/93) getting called for
225 // every texture map. It should get called whenever the window changes, or, preferably,
226 // not at all. I'm pretty sure these variables are only being used for range checking.
227 void init_interface_vars_to_assembler(void)
231 bp = &grd_curcanv->cv_bitmap;
234 Assert(bp->bm_data!=NULL);
235 Assert(bp->bm_h <= MAX_Y_POINTERS);
237 // If bytes_per_row has changed, create new table of pointers.
238 if (bytes_per_row != (int) bp->bm_rowsize) {
241 bytes_per_row = (int) bp->bm_rowsize;
244 for (i=0; i<MAX_Y_POINTERS; i++) {
245 y_pointers[i] = y_val;
246 y_val += bytes_per_row;
250 write_buffer = (unsigned char *) bp->bm_data;
253 window_right = (int) bp->bm_w-1;
255 window_bottom = (int) bp->bm_h-1;
257 Window_clip_left = window_left;
258 Window_clip_right = window_right;
259 Window_clip_top = window_top;
260 Window_clip_bot = window_bottom;
262 window_width = bp->bm_w;
263 window_height = bp->bm_h;
265 if (!Fix_recip_table_computed)
266 init_fix_recip_table();
269 // -------------------------------------------------------------------------------------
271 extern g3ds_tmap Tmap1;
273 // -------------------------------------------------------------------------------------
274 // Returns number preceding val modulo modulus.
277 int prevmod(int val,int modulus)
283 // return (val + modulus - 1) % modulus;
287 // Returns number succeeding val modulo modulus.
290 int succmod(int val,int modulus)
297 // return (val + 1) % modulus;
300 // -------------------------------------------------------------------------------------
301 // Select topmost vertex (minimum y coordinate) and bottommost (maximum y coordinate) in
302 // texture map. If either is part of a horizontal edge, then select leftmost vertex for
303 // top, rightmost vertex for bottom.
304 // Important: Vertex is selected with integer precision. So, if there are vertices at
305 // (0.0,0.7) and (0.5,0.3), the first vertex is selected, because they y coordinates are
306 // considered the same, so the smaller x is favored.
308 // nv number of vertices
309 // v3d pointer to 3d vertices containing u,v,x2d,y2d coordinates
313 // -------------------------------------------------------------------------------------
314 void compute_y_bounds(g3ds_tmap *t, int *vlt, int *vlb, int *vrt, int *vrb,int *bottom_y_ind)
322 // Scan all vertices, set min_y_ind to vertex with smallest y coordinate.
323 min_y = f2i(t->verts[0].y2d);
326 min_x = f2i(t->verts[0].x2d);
329 for (i=1; i<t->nv; i++) {
330 if (f2i(t->verts[i].y2d) < min_y) {
331 min_y = f2i(t->verts[i].y2d);
333 min_x = f2i(t->verts[i].x2d);
334 } else if (f2i(t->verts[i].y2d) == min_y) {
335 if (f2i(t->verts[i].x2d) < min_x) {
337 min_x = f2i(t->verts[i].x2d);
340 if (f2i(t->verts[i].y2d) > max_y) {
341 max_y = f2i(t->verts[i].y2d);
346 //--removed mk, 11/27/94-- // Check for a non-upright-hourglass polygon and fix, if necessary, by bashing a y coordinate.
347 //--removed mk, 11/27/94-- // min_y_ind = index of minimum y coordinate, *bottom_y_ind = index of maximum y coordinate
348 //--removed mk, 11/27/94--{
349 //--removed mk, 11/27/94-- int max_temp, min_temp;
350 //--removed mk, 11/27/94--
351 //--removed mk, 11/27/94-- max_temp = *bottom_y_ind;
352 //--removed mk, 11/27/94-- if (*bottom_y_ind < min_y_ind)
353 //--removed mk, 11/27/94-- max_temp += t->nv;
354 //--removed mk, 11/27/94--
355 //--removed mk, 11/27/94-- for (i=min_y_ind; i<max_temp; i++) {
356 //--removed mk, 11/27/94-- if (f2i(t->verts[i%t->nv].y2d) > f2i(t->verts[(i+1)%t->nv].y2d)) {
357 //--removed mk, 11/27/94-- Int3();
358 //--removed mk, 11/27/94-- t->verts[(i+1)%t->nv].y2d = t->verts[i%t->nv].y2d;
359 //--removed mk, 11/27/94-- }
360 //--removed mk, 11/27/94-- }
361 //--removed mk, 11/27/94--
362 //--removed mk, 11/27/94-- min_temp = min_y_ind;
363 //--removed mk, 11/27/94-- if (min_y_ind < *bottom_y_ind)
364 //--removed mk, 11/27/94-- min_temp += t->nv;
365 //--removed mk, 11/27/94--
366 //--removed mk, 11/27/94-- for (i=*bottom_y_ind; i<min_temp; i++) {
367 //--removed mk, 11/27/94-- if (f2i(t->verts[i%t->nv].y2d) < f2i(t->verts[(i+1)%t->nv].y2d)) {
368 //--removed mk, 11/27/94-- Int3();
369 //--removed mk, 11/27/94-- t->verts[(i+1)%t->nv].y2d = t->verts[i%t->nv].y2d;
370 //--removed mk, 11/27/94-- }
371 //--removed mk, 11/27/94-- }
372 //--removed mk, 11/27/94--}
374 // Set "vertex left top", etc. based on vertex with topmost y coordinate
377 *vlb = prevmod(*vlt,t->nv);
378 *vrb = succmod(*vrt,t->nv);
380 // If right edge is horizontal, then advance along polygon bound until it no longer is or until all
381 // vertices have been examined.
382 // (Left edge cannot be horizontal, because *vlt is set to leftmost point with highest y coordinate.)
386 while (f2i(t->verts[*vrt].y2d) == f2i(t->verts[*vrb].y2d)) {
387 if (succmod(*vrt,t->nv) == original_vrt) {
390 *vrt = succmod(*vrt,t->nv);
391 *vrb = succmod(*vrt,t->nv);
395 // -------------------------------------------------------------------------------------
396 // Returns dx/dy given two vertices.
397 // If dy == 0, returns 0.0
398 // -------------------------------------------------------------------------------------
399 //--fix compute_dx_dy_lin(g3ds_tmap *t, int top_vertex,int bottom_vertex)
403 //-- // compute delta x with respect to y for any edge
404 //-- dy = f2i(t->verts[bottom_vertex].y2d - t->verts[top_vertex].y2d) + 1;
406 //-- return (t->verts[bottom_vertex].x2d - t->verts[top_vertex].x2d) / dy;
412 fix compute_du_dy_lin(g3ds_tmap *t, int top_vertex,int bottom_vertex, fix recip_dy)
414 return fixmul(t->verts[bottom_vertex].u - t->verts[top_vertex].u, recip_dy);
418 fix compute_dv_dy_lin(g3ds_tmap *t, int top_vertex,int bottom_vertex, fix recip_dy)
420 return fixmul(t->verts[bottom_vertex].v - t->verts[top_vertex].v, recip_dy);
423 fix compute_dl_dy_lin(g3ds_tmap *t, int top_vertex,int bottom_vertex, fix recip_dy)
425 return fixmul(t->verts[bottom_vertex].l - t->verts[top_vertex].l, recip_dy);
429 fix compute_dx_dy(g3ds_tmap *t, int top_vertex,int bottom_vertex, fix recip_dy)
431 return fixmul(t->verts[bottom_vertex].x2d - t->verts[top_vertex].x2d, recip_dy);
434 fix compute_du_dy(g3ds_tmap *t, int top_vertex,int bottom_vertex, fix recip_dy)
436 return fixmul(fixmul(t->verts[bottom_vertex].u,t->verts[bottom_vertex].z) - fixmul(t->verts[top_vertex].u,t->verts[top_vertex].z), recip_dy);
440 fix compute_dv_dy(g3ds_tmap *t, int top_vertex,int bottom_vertex, fix recip_dy)
442 return fixmul(fixmul(t->verts[bottom_vertex].v,t->verts[bottom_vertex].z) - fixmul(t->verts[top_vertex].v,t->verts[top_vertex].z), recip_dy);
446 fix compute_dz_dy(g3ds_tmap *t, int top_vertex,int bottom_vertex, fix recip_dy)
448 return fixmul(t->verts[bottom_vertex].z - t->verts[top_vertex].z, recip_dy);
451 int Skip_short_flag=0;
453 // -------------------------------------------------------------------------------------
454 // Texture map current scanline in perspective.
455 // -------------------------------------------------------------------------------------
456 void ntmap_scanline_lighted(grs_bitmap *srcb, int y, fix xleft, fix xright, fix uleft, fix uright, fix vleft, fix vright, fix zleft, fix zright, fix lleft, fix lright)
460 fx_xright = f2i(xright);
461 //edited 06/27/99 Matt Mueller - moved these tests up from within the switch so as not to do a bunch of needless calculations when we are just gonna return anyway. Slight fps boost?
462 if (fx_xright < Window_clip_left)
464 fx_xleft = f2i(xleft);
465 if (fx_xleft > Window_clip_right)
469 dx = fx_xright - fx_xleft;
470 if ((dx < 0) || (xright < 0) || (xleft > xright)) // the (xleft > xright) term is not redundant with (dx < 0) because dx is computed using integers
473 // setup to call assembler scanline renderer
474 if (dx < FIX_RECIP_TABLE_SIZE)
475 recip_dx = fix_recip[dx];
483 fx_du_dx = fixmul(uright - uleft,recip_dx);
484 fx_dv_dx = fixmul(vright - vleft,recip_dx);
485 fx_dz_dx = fixmul(zright - zleft,recip_dx);
487 pixptr = srcb->bm_data;
489 switch (Lighting_enabled) {
491 //added 05/17/99 Matt Mueller - prevent writing before the buffer
492 if ((fx_y == 0) && (fx_xleft < 0))
495 if (fx_xright > Window_clip_right)
496 fx_xright = Window_clip_right;
498 cur_tmap_scanline_per();
503 if (lleft < 0) lleft = 0;
504 if (lright < 0) lright = 0;
505 if (lleft > (NUM_LIGHTING_LEVELS*F1_0-F1_0/2)) lleft = (NUM_LIGHTING_LEVELS*F1_0-F1_0/2);
506 if (lright > (NUM_LIGHTING_LEVELS*F1_0-F1_0/2)) lright = (NUM_LIGHTING_LEVELS*F1_0-F1_0/2);
509 fx_dl_dx = fixmul(lright - lleft,recip_dx);
511 // This is a pretty ugly hack to prevent lighting overflows.
512 mul_thing = dx * fx_dl_dx;
513 if (lleft + mul_thing < 0)
515 else if (lleft + mul_thing > (NUM_LIGHTING_LEVELS*F1_0-F1_0/2))
518 //added 05/17/99 Matt Mueller - prevent writing before the buffer
519 if ((fx_y == 0) && (fx_xleft < 0))
522 if (fx_xright > Window_clip_right)
523 fx_xright = Window_clip_right;
525 cur_tmap_scanline_per();
530 fx_xright = f2i(xright);
531 fx_xleft = f2i(xleft);
534 cur_tmap_scanline_flat();
536 Int3(); // Illegal, called an editor only routine!
543 int Do_vertical_scan=0;
547 // -------------------------------------------------------------------------------------
548 // Render a texture map with lighting using perspective interpolation in inner and outer loops.
549 // -------------------------------------------------------------------------------------
550 void ntexture_map_lighted(grs_bitmap *srcb, g3ds_tmap *t)
552 int vlt,vrt,vlb,vrb; // vertex left top, vertex right top, vertex left bottom, vertex right bottom
554 fix dx_dy_left,dx_dy_right;
555 fix du_dy_left,du_dy_right;
556 fix dv_dy_left,dv_dy_right;
557 fix dz_dy_left,dz_dy_right;
558 fix dl_dy_left,dl_dy_right;
559 fix recip_dyl, recip_dyr;
561 fix xleft,xright,uleft,vleft,uright,vright,zleft,zright,lleft,lright;
562 int next_break_left, next_break_right;
566 //remove stupid warnings in compile
574 // Determine top and bottom y coords.
575 compute_y_bounds(t,&vlt,&vlb,&vrt,&vrb,&max_y_vertex);
577 // Set top and bottom (of entire texture map) y coordinates.
578 topy = f2i(v3d[vlt].y2d);
579 boty = f2i(v3d[max_y_vertex].y2d);
580 if (topy > Window_clip_bot)
582 if (boty > Window_clip_bot)
583 boty = Window_clip_bot;
585 // Set amount to change x coordinate for each advance to next scanline.
586 dy = f2i(t->verts[vlb].y2d) - f2i(t->verts[vlt].y2d);
587 if (dy < FIX_RECIP_TABLE_SIZE)
588 recip_dyl = fix_recip[dy];
592 dx_dy_left = compute_dx_dy(t,vlt,vlb, recip_dyl);
593 du_dy_left = compute_du_dy(t,vlt,vlb, recip_dyl);
594 dv_dy_left = compute_dv_dy(t,vlt,vlb, recip_dyl);
595 dz_dy_left = compute_dz_dy(t,vlt,vlb, recip_dyl);
597 dy = f2i(t->verts[vrb].y2d) - f2i(t->verts[vrt].y2d);
598 if (dy < FIX_RECIP_TABLE_SIZE)
599 recip_dyr = fix_recip[dy];
603 du_dy_right = compute_du_dy(t,vrt,vrb, recip_dyr);
604 dx_dy_right = compute_dx_dy(t,vrt,vrb, recip_dyr);
605 dv_dy_right = compute_dv_dy(t,vrt,vrb, recip_dyr);
606 dz_dy_right = compute_dz_dy(t,vrt,vrb, recip_dyr);
608 if (Lighting_enabled) {
609 dl_dy_left = compute_dl_dy_lin(t,vlt,vlb, recip_dyl);
610 dl_dy_right = compute_dl_dy_lin(t,vrt,vrb, recip_dyr);
616 // Set initial values for x, u, v
617 xleft = v3d[vlt].x2d;
618 xright = v3d[vrt].x2d;
623 uleft = fixmul(v3d[vlt].u,zleft);
624 uright = fixmul(v3d[vrt].u,zright);
625 vleft = fixmul(v3d[vlt].v,zleft);
626 vright = fixmul(v3d[vrt].v,zright);
628 // scan all rows in texture map from top through first break.
629 next_break_left = f2i(v3d[vlb].y2d);
630 next_break_right = f2i(v3d[vrb].y2d);
632 for (y = topy; y < boty; y++) {
634 // See if we have reached the end of the current left edge, and if so, set
635 // new values for dx_dy and x,u,v
636 if (y == next_break_left) {
639 // Handle problem of double points. Search until y coord is different. Cannot get
640 // hung in an infinite loop because we know there is a vertex with a lower y coordinate
641 // because in the for loop, we don't scan all spanlines.
642 while (y == f2i(v3d[vlb].y2d)) {
644 vlb = prevmod(vlb,t->nv);
646 next_break_left = f2i(v3d[vlb].y2d);
648 dy = f2i(t->verts[vlb].y2d) - f2i(t->verts[vlt].y2d);
649 if (dy < FIX_RECIP_TABLE_SIZE)
650 recip_dy = fix_recip[dy];
654 dx_dy_left = compute_dx_dy(t,vlt,vlb, recip_dy);
656 xleft = v3d[vlt].x2d;
658 uleft = fixmul(v3d[vlt].u,zleft);
659 vleft = fixmul(v3d[vlt].v,zleft);
662 du_dy_left = compute_du_dy(t,vlt,vlb, recip_dy);
663 dv_dy_left = compute_dv_dy(t,vlt,vlb, recip_dy);
664 dz_dy_left = compute_dz_dy(t,vlt,vlb, recip_dy);
666 if (Lighting_enabled) {
667 dl_dy_left = compute_dl_dy_lin(t,vlt,vlb, recip_dy);
672 // See if we have reached the end of the current left edge, and if so, set
673 // new values for dx_dy and x. Not necessary to set new values for u,v.
674 if (y == next_break_right) {
677 while (y == f2i(v3d[vrb].y2d)) {
679 vrb = succmod(vrb,t->nv);
682 next_break_right = f2i(v3d[vrb].y2d);
684 dy = f2i(t->verts[vrb].y2d) - f2i(t->verts[vrt].y2d);
685 if (dy < FIX_RECIP_TABLE_SIZE)
686 recip_dy = fix_recip[dy];
690 dx_dy_right = compute_dx_dy(t,vrt,vrb, recip_dy);
692 xright = v3d[vrt].x2d;
694 uright = fixmul(v3d[vrt].u,zright);
695 vright = fixmul(v3d[vrt].v,zright);
697 du_dy_right = compute_du_dy(t,vrt,vrb, recip_dy);
698 dv_dy_right = compute_dv_dy(t,vrt,vrb, recip_dy);
699 dz_dy_right = compute_dz_dy(t,vrt,vrb, recip_dy);
701 if (Lighting_enabled) {
702 dl_dy_right = compute_dl_dy_lin(t,vrt,vrb, recip_dy);
707 if (Lighting_enabled) {
708 if (y >= Window_clip_top)
709 ntmap_scanline_lighted(srcb,y,xleft,xright,uleft,uright,vleft,vright,zleft,zright,lleft,lright);
711 lright += dl_dy_right;
713 if (y >= Window_clip_top)
714 ntmap_scanline_lighted(srcb,y,xleft,xright,uleft,uright,vleft,vright,zleft,zright,lleft,lright);
719 uright += du_dy_right;
720 vright += dv_dy_right;
723 xright += dx_dy_right;
726 zright += dz_dy_right;
730 // We can get lleft or lright out of bounds here because we compute dl_dy using fixed point values,
731 // but we plot an integer number of scanlines, therefore doing an integer number of additions of the delta.
734 // mprintf(0, "[%i %i %i] ", y, f2i(xleft), f2i(xright));
736 ntmap_scanline_lighted(srcb,y,xleft,xright,uleft,uright,vleft,vright,zleft,zright,lleft,lright);
740 // -------------------------------------------------------------------------------------
741 // Texture map current scanline using linear interpolation.
742 // -------------------------------------------------------------------------------------
743 void ntmap_scanline_lighted_linear(grs_bitmap *srcb, int y, fix xleft, fix xright, fix uleft, fix uright, fix vleft, fix vright, fix lleft, fix lright)
748 fix du_dx,dv_dx,dl_dx;
754 dx = f2i(xright) - f2i(xleft);
755 if ((dx < 0) || (xright < 0) || (xleft > xright)) // the (xleft > xright) term is not redundant with (dx < 0) because dx is computed using integers
758 // setup to call assembler scanline renderer
759 if (dx < FIX_RECIP_TABLE_SIZE)
760 recip_dx = fix_recip[dx];
764 du_dx = fixmul(uright - uleft,recip_dx);
765 dv_dx = fixmul(vright - vleft,recip_dx);
772 fx_xright = f2i(xright);
773 fx_xleft = f2i(xleft);
774 pixptr = srcb->bm_data;
776 switch (Lighting_enabled) {
778 //added 07/11/99 adb - prevent writing before the buffer
783 cur_tmap_scanline_lin_nolight();
791 if (lleft > MAX_LIGHTING_VALUE*NUM_LIGHTING_LEVELS)
792 lleft = MAX_LIGHTING_VALUE*NUM_LIGHTING_LEVELS;
793 if (lright > MAX_LIGHTING_VALUE*NUM_LIGHTING_LEVELS)
794 lright = MAX_LIGHTING_VALUE*NUM_LIGHTING_LEVELS;
796 //added 07/11/99 adb - prevent writing before the buffer
805 fx_dl_dx = fixmul(lright - lleft,recip_dx);
807 // This is a pretty ugly hack to prevent lighting overflows.
808 mul_thing = dx * fx_dl_dx;
809 if (lleft + mul_thing < 0)
811 else if (lleft + mul_thing > (NUM_LIGHTING_LEVELS*F1_0-F1_0/2))
816 dl_dx = fixmul(lright - lleft,recip_dx);
818 cur_tmap_scanline_lin();
822 fx_xright = f2i(xright);
823 fx_xleft = f2i(xleft);
825 cur_tmap_scanline_flat();
827 Int3(); // Illegal, called an editor only routine!
833 // -------------------------------------------------------------------------------------
834 // Render a texture map with lighting using perspective interpolation in inner and outer loops.
835 // -------------------------------------------------------------------------------------
836 void ntexture_map_lighted_linear(grs_bitmap *srcb, g3ds_tmap *t)
838 int vlt,vrt,vlb,vrb; // vertex left top, vertex right top, vertex left bottom, vertex right bottom
840 fix dx_dy_left,dx_dy_right;
841 fix du_dy_left,du_dy_right;
842 fix dv_dy_left,dv_dy_right;
843 fix dl_dy_left,dl_dy_right;
845 fix xleft,xright,uleft,vleft,uright,vright,lleft,lright;
846 int next_break_left, next_break_right;
847 fix recip_dyl, recip_dyr;
851 //remove stupid warnings in compile
859 // Determine top and bottom y coords.
860 compute_y_bounds(t,&vlt,&vlb,&vrt,&vrb,&max_y_vertex);
862 // Set top and bottom (of entire texture map) y coordinates.
863 topy = f2i(v3d[vlt].y2d);
864 boty = f2i(v3d[max_y_vertex].y2d);
866 if (topy > Window_clip_bot)
868 if (boty > Window_clip_bot)
869 boty = Window_clip_bot;
871 dy = f2i(t->verts[vlb].y2d) - f2i(t->verts[vlt].y2d);
872 if (dy < FIX_RECIP_TABLE_SIZE)
873 recip_dyl = fix_recip[dy];
877 dy = f2i(t->verts[vrb].y2d) - f2i(t->verts[vrt].y2d);
878 if (dy < FIX_RECIP_TABLE_SIZE)
879 recip_dyr = fix_recip[dy];
883 // Set amount to change x coordinate for each advance to next scanline.
884 dx_dy_left = compute_dx_dy(t,vlt,vlb, recip_dyl);
885 dx_dy_right = compute_dx_dy(t,vrt,vrb, recip_dyr);
887 du_dy_left = compute_du_dy_lin(t,vlt,vlb, recip_dyl);
888 du_dy_right = compute_du_dy_lin(t,vrt,vrb, recip_dyr);
890 dv_dy_left = compute_dv_dy_lin(t,vlt,vlb, recip_dyl);
891 dv_dy_right = compute_dv_dy_lin(t,vrt,vrb, recip_dyr);
893 if (Lighting_enabled) {
894 dl_dy_left = compute_dl_dy_lin(t,vlt,vlb, recip_dyl);
895 dl_dy_right = compute_dl_dy_lin(t,vrt,vrb, recip_dyr);
901 // Set initial values for x, u, v
902 xleft = v3d[vlt].x2d;
903 xright = v3d[vrt].x2d;
910 // scan all rows in texture map from top through first break.
911 next_break_left = f2i(v3d[vlb].y2d);
912 next_break_right = f2i(v3d[vrb].y2d);
914 for (y = topy; y < boty; y++) {
916 // See if we have reached the end of the current left edge, and if so, set
917 // new values for dx_dy and x,u,v
918 if (y == next_break_left) {
921 // Handle problem of double points. Search until y coord is different. Cannot get
922 // hung in an infinite loop because we know there is a vertex with a lower y coordinate
923 // because in the for loop, we don't scan all spanlines.
924 while (y == f2i(v3d[vlb].y2d)) {
926 vlb = prevmod(vlb,t->nv);
928 next_break_left = f2i(v3d[vlb].y2d);
930 dy = f2i(t->verts[vlb].y2d) - f2i(t->verts[vlt].y2d);
931 if (dy < FIX_RECIP_TABLE_SIZE)
932 recip_dy = fix_recip[dy];
936 dx_dy_left = compute_dx_dy(t,vlt,vlb, recip_dy);
938 xleft = v3d[vlt].x2d;
943 du_dy_left = compute_du_dy_lin(t,vlt,vlb, recip_dy);
944 dv_dy_left = compute_dv_dy_lin(t,vlt,vlb, recip_dy);
946 if (Lighting_enabled) {
947 dl_dy_left = compute_dl_dy_lin(t,vlt,vlb, recip_dy);
952 // See if we have reached the end of the current left edge, and if so, set
953 // new values for dx_dy and x. Not necessary to set new values for u,v.
954 if (y == next_break_right) {
957 while (y == f2i(v3d[vrb].y2d)) {
959 vrb = succmod(vrb,t->nv);
962 dy = f2i(t->verts[vrb].y2d) - f2i(t->verts[vrt].y2d);
963 if (dy < FIX_RECIP_TABLE_SIZE)
964 recip_dy = fix_recip[dy];
968 next_break_right = f2i(v3d[vrb].y2d);
969 dx_dy_right = compute_dx_dy(t,vrt,vrb, recip_dy);
971 xright = v3d[vrt].x2d;
975 du_dy_right = compute_du_dy_lin(t,vrt,vrb, recip_dy);
976 dv_dy_right = compute_dv_dy_lin(t,vrt,vrb, recip_dy);
978 if (Lighting_enabled) {
979 dl_dy_right = compute_dl_dy_lin(t,vrt,vrb, recip_dy);
984 if (Lighting_enabled) {
985 ntmap_scanline_lighted_linear(srcb,y,xleft,xright,uleft,uright,vleft,vright,lleft,lright);
987 lright += dl_dy_right;
989 ntmap_scanline_lighted_linear(srcb,y,xleft,xright,uleft,uright,vleft,vright,lleft,lright);
994 uright += du_dy_right;
995 vright += dv_dy_right;
998 xright += dx_dy_right;
1002 // We can get lleft or lright out of bounds here because we compute dl_dy using fixed point values,
1003 // but we plot an integer number of scanlines, therefore doing an integer number of additions of the delta.
1005 ntmap_scanline_lighted_linear(srcb,y,xleft,xright,uleft,uright,vleft,vright,lleft,lright);
1008 // fix DivNum = F1_0*12;
1010 extern void draw_tmap_flat(grs_bitmap *bp,int nverts,g3s_point **vertbuf);
1012 // -------------------------------------------------------------------------------------
1013 // Interface from Matt's data structures to Mike's texture mapper.
1014 // -------------------------------------------------------------------------------------
1015 void draw_tmap(grs_bitmap *bp,int nverts,g3s_point **vertbuf)
1019 // These variables are used in system which renders texture maps which lie on one scanline as a line.
1020 // fix div_numerator;
1021 int lighting_on_save = Lighting_on;
1023 Assert(nverts <= MAX_TMAP_VERTS);
1026 #ifdef USE_MULT_CODE
1027 if ( !divide_table_filled ) fill_divide_table();
1030 // -- now called from g3_start_frame -- init_interface_vars_to_assembler();
1032 // If no transparency and seg depth is large, render as flat shaded.
1033 if ((Current_seg_depth > Max_linear_depth) && ((bp->bm_flags & 3) == 0)) {
1034 draw_tmap_flat(bp, nverts, vertbuf);
1038 if ( bp->bm_flags & BM_FLAG_RLE )
1039 bp = rle_expand_texture( bp ); // Expand if rle'd
1041 Transparency_on = bp->bm_flags & BM_FLAG_TRANSPARENT;
1042 if (bp->bm_flags & BM_FLAG_NO_LIGHTING)
1046 // Setup texture map in Tmap1
1047 Tmap1.nv = nverts; // Initialize number of vertices
1049 // div_numerator = DivNum; //f1_0*3;
1051 for (i=0; i<nverts; i++) {
1052 g3ds_vertex *tvp = &Tmap1.verts[i];
1053 g3s_point *vp = vertbuf[i];
1055 tvp->x2d = vp->p3_sx;
1056 tvp->y2d = vp->p3_sy;
1058 // Check for overflow on fixdiv. Will overflow on vp->z <= something small. Allow only as low as 256.
1059 if (vp->p3_z < 256) {
1061 // Int3(); // we would overflow if we divided!
1064 tvp->z = fixdiv(F1_0*12, vp->p3_z);
1065 tvp->u = vp->p3_u << 6; //* bp->bm_w;
1066 tvp->v = vp->p3_v << 6; //* bp->bm_h;
1068 Assert(Lighting_on < 3);
1071 tvp->l = vp->p3_l * NUM_LIGHTING_LEVELS;
1075 Lighting_enabled = Lighting_on;
1077 // Now, call my texture mapper.
1079 switch (Interpolation_method) { // 0 = choose, 1 = linear, 2 = /8 perspective, 3 = full perspective
1080 case 0: // choose best interpolation
1082 if (Current_seg_depth > Max_perspective_depth)
1083 ntexture_map_lighted_linear(bp, &Tmap1);
1085 ntexture_map_lighted(bp, &Tmap1);
1087 case 1: // linear interpolation
1089 ntexture_map_lighted_linear(bp, &Tmap1);
1091 case 2: // perspective every 8th pixel interpolation
1093 ntexture_map_lighted(bp, &Tmap1);
1095 case 3: // perspective every pixel interpolation
1096 per2_flag = 0; // this hack means do divide every pixel
1097 ntexture_map_lighted(bp, &Tmap1);
1100 Assert(0); // Illegal value for Interpolation_method, must be 0,1,2,3
1103 switch (Interpolation_method) { // 0 = choose, 1 = linear, 2 = /8 perspective, 3 = full perspective
1104 case 0: // choose best interpolation
1106 if (Current_seg_depth > Max_perspective_depth)
1107 ntexture_map_lighted_linear(bp, &Tmap1);
1109 ntexture_map_lighted(bp, &Tmap1);
1111 case 1: // linear interpolation
1113 ntexture_map_lighted_linear(bp, &Tmap1);
1115 case 2: // perspective every 8th pixel interpolation
1117 ntexture_map_lighted(bp, &Tmap1);
1119 case 3: // perspective every pixel interpolation
1120 per2_flag = 0; // this hack means do divide every pixel
1121 ntexture_map_lighted(bp, &Tmap1);
1124 Assert(0); // Illegal value for Interpolation_method, must be 0,1,2,3
1128 Lighting_on = lighting_on_save;