]> icculus.org git repositories - taylor/freespace2.git/blob - src/graphics/tmapper.cpp
Screenshot function filled, will output into ~/.freespace(2)/Data
[taylor/freespace2.git] / src / graphics / tmapper.cpp
1 /*
2  * Copyright (C) Volition, Inc. 1999.  All rights reserved.
3  *
4  * All source code herein is the property of Volition, Inc. You may not sell 
5  * or otherwise commercially exploit the source or things you created based on
6  * the source.
7  */
8
9 /*
10  * $Logfile: /Freespace2/code/Graphics/Tmapper.cpp $
11  * $Revision$
12  * $Date$
13  * $Author$
14  *
15  * Routines to draw a texture map.
16  *
17  * $Log$
18  * Revision 1.4  2002/06/09 04:41:18  relnev
19  * added copyright header
20  *
21  * Revision 1.3  2002/06/09 03:16:04  relnev
22  * added _splitpath.
23  *
24  * removed unneeded asm, old sdl 2d setup.
25  *
26  * fixed crash caused by opengl_get_region.
27  *
28  * Revision 1.2  2002/05/28 08:52:03  relnev
29  * implemented two assembly stubs.
30  *
31  * cleaned up a few warnings.
32  *
33  * added a little demo hackery to make it progress a little farther.
34  *
35  * Revision 1.1.1.1  2002/05/03 03:28:09  root
36  * Initial import.
37  *
38  * 
39  * 3     12/06/98 3:08p Dave
40  * Fixed grx_tmapper to handle pixel fog flag. First run fog support for
41  * D3D.
42  * 
43  * 2     10/07/98 10:53a Dave
44  * Initial checkin.
45  * 
46  * 1     10/07/98 10:49a Dave
47  * 
48  * 78    5/13/98 2:53p John
49  * Made subspace effect work under software.  Had to add new inner loop to
50  * tmapper.  Added glows to end of subspace effect.  Made subspace effect
51  * levels use gamepalette-subspace palette.
52  * 
53  * 77    4/10/98 5:20p John
54  * Changed RGB in lighting structure to be ubytes.  Removed old
55  * not-necessary 24 bpp software stuff.
56  * 
57  * 76    4/09/98 7:58p John
58  * Cleaned up tmapper code a bit.   Put NDEBUG around some ndebug stuff.
59  * Took out XPARENT flag settings in all the alpha-blended texture stuff.
60  * 
61  * 75    4/09/98 7:16p John
62  * Fixed bug causing software to not render
63  * 
64  * 74    3/27/98 8:34p Mike
65  * Minor optimization.
66  * 
67  * 73    3/25/98 8:08p John
68  * Restructured software rendering into two modules; One for windowed
69  * debug mode and one for DirectX fullscreen.   
70  * 
71  * 72    3/23/98 5:00p John
72  * Improved missile trails.  Made smooth alpha under hardware.  Made end
73  * taper.  Made trail touch weapon.
74  * 
75  * 71    3/22/98 2:33p John
76  * Took out fx_v/v_right.  Made fx_u etc get calculated in tmapper.
77  * 
78  * 70    3/10/98 4:19p John
79  * Cleaned up graphics lib.  Took out most unused gr functions.   Made D3D
80  * & Glide have popups and print screen.  Took out all >8bpp software
81  * support.  Made Fred zbuffer.  Made zbuffer allocate dynamically to
82  * support Fred.  Made zbuffering key off of functions rather than one
83  * global variable.
84  * 
85  * 69    2/10/98 5:34p John
86  * 
87  * 68    2/05/98 9:21p John
88  * Some new Direct3D code.   Added code to monitor a ton of stuff in the
89  * game.
90  * 
91  * 67    1/29/98 8:18a John
92  * Put in some commented out hooks for RGB lighting
93  * 
94  * 66    1/28/98 1:27p John
95  * Really fixed bug with exception on mov al, [esi]
96  * 
97  * 65    1/28/98 1:22p John
98  * Fixed bug with unitialized dwdx_wide.
99  * 
100  * 64    1/27/98 5:13p John
101  * Moved all float to int conversions out of inner loops and into outer.
102  * Made outer loop use FISTP instead of ftol, saved about 10%.
103  * 
104  * 63    1/23/98 5:08p John
105  * Took L out of vertex structure used B (blue) instead.   Took all small
106  * fireballs out of fireball types and used particles instead.  Fixed some
107  * debris explosion things.  Restructured fireball code.   Restructured
108  * some lighting code.   Made dynamic lighting on by default. Made groups
109  * of lasers only cast one light.  Made fireballs not cast light.
110  * 
111  * 62    1/19/98 6:15p John
112  * Fixed all my Optimized Build compiler warnings
113  * 
114  * 61    12/15/97 11:32a John
115  * New Laser Code
116  * 
117  * 60    12/02/97 4:00p John
118  * Added first rev of thruster glow, along with variable levels of
119  * translucency, which retquired some restructing of palman.
120  * 
121  * 59    11/30/97 4:40p John
122  * made 32-bpp tiled tmapper call scanline
123  * 
124  * 58    11/30/97 3:57p John
125  * Made fixed 32-bpp translucency.  Made BmpMan always map translucent
126  * color into 255 even if you aren't supposed to remap and make it's
127  * palette black.
128  * 
129  * 57    11/30/97 12:18p John
130  * added more 24 & 32-bpp primitives
131  * 
132  * 56    11/29/97 2:06p John
133  * added mode 16-bpp support
134  * 
135  * 55    11/21/97 11:32a John
136  * Added nebulas.   Fixed some warpout bugs.
137  * 
138  * 54    11/14/97 12:30p John
139  * Fixed some DirectX bugs.  Moved the 8-16 xlat tables into Graphics
140  * libs.  Made 16-bpp DirectX modes know what bitmap format they're in.
141  * 
142  * 53    11/06/97 11:18a John
143  * added 16-bpp gouraud flat shader
144  * 
145  * 52    10/19/97 12:55p John
146  * new code to lock / unlock surfaces for smooth directx integration.
147  * 
148  * 51    10/16/97 10:55a John
149  * added tmapper to draw a monochrome alpha blended bitmap.
150  * 
151  * 50    10/14/97 8:08a John
152  * added a bunch more 16 bit support
153  * 
154  * 49    10/09/97 5:23p John
155  * Added support for more 16-bpp functions
156  * 
157  * 48    9/30/97 2:30p John
158  * test code for texture fading
159  * 
160  * 47    9/24/97 10:37a John
161  * made tmapper not trash uv values anymore.
162  * 
163  * 46    9/09/97 11:01a Sandeep
164  * fixed warning level 4 bugs
165  * 
166  * 45    7/11/97 11:54a John
167  * added rotated 3d bitmaps.
168  * 
169  * 44    6/18/97 5:02p John
170  * fixed bug with 32x32 and 16x16 tmapper
171  * 
172  * 43    6/12/97 5:04p John
173  * Initial rev of Glide support
174  * 
175  * 42    6/12/97 2:50a Lawrance
176  * bm_unlock() now passed bitmap number, not pointer
177  * 
178  * 41    6/02/97 11:45a John
179  * fixed bugs with 64x64 and 128x128 tmappers.
180  * 
181  * 40    6/01/97 3:41p John
182  * made non-tilable textures on tilable models bash uvs to 0-1.
183  * 
184  * 39    5/12/97 12:27p John
185  * Restructured Graphics Library to add support for multiple renderers.
186  * 
187  * 38    5/07/97 4:14p John
188  * Reenabled calls to gr_start/end_frame.
189  * 
190  * 37    4/21/97 10:06a John
191  * Got capital ships working again.
192  * 
193  * 36    4/17/97 6:06p John
194  * New code/data for v19 of BSPGEN with smoothing and zbuffer
195  * optimizations.
196  * 
197  * 35    4/08/97 5:18p John
198  * First rev of decent (dynamic, correct) lighting in FreeSpace.
199  * 
200  * 34    3/18/97 9:42a John
201  * 
202  * 33    3/15/97 2:44p John
203  * got scanline sorting method working.  Bummer it is slower than zbuffer!
204  * 
205  * 32    3/14/97 3:55p John
206  * Made tiled tmapper not always be zbuffered.
207  * 
208  * 31    3/13/97 10:32a John
209  * Added code for tiled 256x256 textures in certain models.
210  * 
211  * 30    3/12/97 2:51p John
212  * Added some test code for tmapper.  
213  * 
214  * 29    3/12/97 9:25a John
215  * fixed a bug with zbuffering.  Reenabled it by default.
216  * 
217  * 28    3/11/97 4:36p John
218  * added zbuffering to textest.  Made zbuffered tmapper a bit faster by
219  * rearranging some instructions.
220  * 
221  * 27    3/10/97 5:20p John
222  * Differentiated between Gouraud and Flat shading.  Since we only do flat
223  * shading as of now, we don't need to interpolate L in the outer loop.
224  * This should save a few percent.
225  * 
226  * 26    3/10/97 2:24p John
227  * added some commets about precompiled inner loop
228  * 
229  * 25    3/05/97 7:15p John
230  * took out the old z stop tmapper used for briefing. 
231  * 
232  * 24    1/20/97 4:17p John
233  * 
234  * 23    1/06/97 2:44p John
235  * Added in slow (but correct) zbuffering
236  * 
237  * 22    12/30/96 3:46p John
238  * 
239  * 21    12/23/96 10:56a John
240  * Totally restructured the POF stuff to support multiple 
241  * detail levels in one POF file.
242  *  
243  * 
244  * 20    12/10/96 10:37a John
245  * Restructured texture mapper to remove some overhead from each scanline
246  * setup.  This gave about a 30% improvement drawing trans01.pof, which is
247  * a really complex model.  In the process, I cleaned up the scanline
248  * functions and separated them into different modules for each pixel
249  * depth.   
250  * 
251  * 19    11/26/96 6:50p John
252  * Added some more hicolor primitives.  Made windowed mode run as current
253  * bpp, if bpp is 8,16,or 32.
254  * 
255  * 18    11/07/96 6:19p John
256  * Added a bunch of 16bpp primitives so the game sort of runs in 16bpp
257  * mode.
258  * 
259  * 17    11/07/96 3:08p John
260  * Inlined more Tmapper functions in preparation for cleaning up the Tmap1
261  * interface to the assembly.
262  * 
263  * 16    11/07/96 2:17p John
264  * Took out the OldTmapper stuff.
265  * 
266  * 15    11/07/96 12:04p John
267  * Sped up outer loop by 35% by inlining the incrementing of the variables
268  * for each scanline step and inlined the calculation for deltas at the
269  * start of each scanline.
270  * 
271  * 14    11/06/96 2:33p John
272  * Added more asserts for checking that non-tiled UV's are between 0 and
273  * 1.0.    Put code in the model_init code that checks for polys that have
274  * a vertex duplicated and throws them out.
275  * 
276  * 13    11/05/96 4:05p John
277  * Added roller.  Added code to draw a distant planet.  Made bm_load
278  * return -1 if invalid bitmap.
279  * 
280  * 12    10/31/96 7:20p John
281  * Added per,tiled tmapper.  Made models tile if they use 64x64 textures.
282  * 
283  * 11    10/26/96 1:40p John
284  * Added some now primitives to the 2d library and
285  * cleaned up some old ones.
286  *
287  * $NoKeywords: $
288  */
289
290 #include <math.h>
291 #include <limits.h>
292 #include <stdio.h>
293 #ifndef PLAT_UNIX
294 #include <conio.h>
295 #endif
296 #include <stdlib.h>
297
298 #include "2d.h"
299 #include "grinternal.h"
300 #include "3d.h"
301 #include "tmapper.h"
302 #include "bmpman.h"
303 #include "tmapscanline.h"
304 #include "key.h"
305 #include "floating.h"
306 #include "palman.h"
307
308 typedef void (* pscanline)();
309
310 pscanline tmap_scanline;
311
312 int Tmap_screen_flags = -1;
313 int Tmap_npolys=0;
314 int Tmap_nverts=0;
315 int Tmap_nscanlines=0;
316 int Tmap_npixels=0;
317 tmapper_data Tmap;
318 int Tmap_show_layers=0;
319
320 typedef struct tmap_scan_desc {
321         uint                    flags;
322         pscanline       scan_func;
323 } tmap_scan_desc;
324
325 // Convert from a 0-255 byte to a 0-1.0 float.
326 float Light_table[256];
327
328
329 //====================== 8-BPP SCANLINES ========================
330 tmap_scan_desc tmap_scanlines8[] = {
331         { 0, tmapscan_flat8 },
332         { TMAP_FLAG_TEXTURED, tmapscan_lnn8 },
333         { TMAP_FLAG_TEXTURED|TMAP_FLAG_XPARENT, tmapscan_lnt8 },
334         { TMAP_FLAG_TEXTURED|TMAP_FLAG_RAMP, tmapscan_lln8 },
335         { TMAP_FLAG_TEXTURED|TMAP_FLAG_RAMP|TMAP_FLAG_CORRECT, tmapscan_pln8 },
336         
337         { TMAP_FLAG_RAMP|TMAP_FLAG_GOURAUD, tmapscan_flat_gouraud },
338
339         { TMAP_FLAG_TEXTURED|TMAP_FLAG_RAMP|TMAP_FLAG_GOURAUD, tmapscan_lln8 },
340         { TMAP_FLAG_TEXTURED|TMAP_FLAG_RAMP|TMAP_FLAG_GOURAUD|TMAP_FLAG_CORRECT, tmapscan_pln8 },
341
342         { TMAP_FLAG_TEXTURED|TMAP_FLAG_RAMP|TMAP_FLAG_CORRECT|TMAP_FLAG_TILED, tmapscan_pln8_tiled },
343         { TMAP_FLAG_TEXTURED|TMAP_FLAG_RAMP|TMAP_FLAG_CORRECT|TMAP_FLAG_GOURAUD|TMAP_FLAG_TILED, tmapscan_pln8_tiled },
344
345         { TMAP_FLAG_RAMP|TMAP_FLAG_GOURAUD|TMAP_FLAG_NEBULA, tmapscan_nebula8 },
346
347 //      { TMAP_FLAG_TEXTURED|TMAP_FLAG_TILED, tmapscan_lnn8_tiled_256x256 },
348         // Totally non-general specific inner loop for subspace effect
349         { TMAP_FLAG_TEXTURED|TMAP_FLAG_CORRECT|TMAP_FLAG_TILED, tmapscan_pnn8_tiled_256x256_subspace },
350         
351
352         { 0, NULL },    // Dummy element to mark the end of fast scanlines.
353 };
354
355
356 pscanline tmap_scanline_table[TMAP_MAX_SCANLINES];
357
358
359 // -------------------------------------------------------------------------------------
360 // This sets up the tmapper at the start of a given frame, so everything
361 // can can be pre-calculated should be calculated in here.
362 // This just fills in the tmap_scanline_table for the
363 // appropriate scan lines.
364
365 void tmapper_setup()
366 {
367         int i;
368         tmap_scan_desc * func_table = NULL;
369
370         Tmap_screen_flags = gr_screen.mode;
371
372         // Some constants for the inner loop
373         Tmap.FixedScale = 65536.0f;
374         Tmap.FixedScale8 =      2048.0f;        //8192.0f;      // 2^16 / 8
375         Tmap.One = 1.0f;
376
377         // Set tmap_scanline to not call a function
378         for (i=0; i<TMAP_MAX_SCANLINES; i++ )   {
379                 tmap_scanline_table[i] = NULL;
380         }
381
382         func_table = tmap_scanlines8;
383
384         while(func_table->scan_func != NULL)    {
385                 tmap_scanline_table[func_table->flags] = func_table->scan_func;
386                 func_table++;
387         }
388
389         for (i=0; i<256; i++ )  {
390                 Light_table[i] = i2fl(i)/255.0f;
391         }
392
393
394 }
395
396 // Sets up flat-shaded lighting
397 void tmapper_set_light(vertex *v, uint flags)
398 {
399         if ( flags & TMAP_FLAG_GOURAUD ) return;
400
401         if ( (flags & (TMAP_FLAG_RAMP|TMAP_FLAG_RGB))==(TMAP_FLAG_RAMP|TMAP_FLAG_RGB))  {
402                 Int3();         // You're doing RGB and RAMP lighting!!!
403         }
404
405         if ( flags & TMAP_FLAG_RAMP )   {
406                 Tmap.l.b = Tmap.r.b = i2fl(v->b)/255.0f;
407                 Tmap.deltas.b = 0.0f;
408         }
409 }
410
411 void tmapper_show_layers()
412 {
413         int i;
414         ubyte * ptr = (ubyte *)Tmap.dest_row_data;
415
416         for (i=0; i<Tmap.loop_count; i++, ptr++ )       {
417                 *ptr = (unsigned char)(*ptr + 1);
418         }
419
420 }
421
422 /*
423 void tmap_scan_generic()
424 {
425         int ui,vi,i;
426         ubyte * dptr,c;
427         float l, dl;
428         float u, v, w, du, dv, dw;
429         
430         dptr = (ubyte *)Tmap.dest_row_data;
431
432         Tmap.fx_w = fl2i(Tmap.l.sw * GR_Z_RANGE)+gr_zoffset;
433         Tmap.fx_dwdx = fl2i(Tmap.deltas.sw * GR_Z_RANGE);
434
435         l = Tmap.l.b;
436         dl = Tmap.deltas.b;
437
438         u = Tmap.l.u;
439         v = Tmap.l.v;
440         w = Tmap.l.sw;
441         du = Tmap.deltas.u;
442         dv = Tmap.deltas.v;
443         dw = Tmap.deltas.sw;
444         
445         for (i=0; i<Tmap.loop_count; i++ )      {
446                 int tmp = (uint)dptr-Tmap.pScreenBits;
447                 if ( Tmap.fx_w > (int)gr_zbuffer[tmp] ) {
448                         gr_zbuffer[tmp] = Tmap.fx_w;
449
450                         ui = fl2i( u / w ) % Tmap.bp->w;
451                         vi = fl2i( v / w ) % Tmap.bp->h;
452
453                         c = Tmap.pixptr[vi*Tmap.bp->w+ui];
454                         *dptr = gr_fade_table[fl2i(l*31)*256+c];
455
456                 }
457                 Tmap.fx_w += Tmap.fx_dwdx;
458                 l+=dl;
459                 u+=du;
460                 v+=dv;
461                 w+=dw;
462                 dptr++;
463         }
464 }
465 */
466
467
468 // Same as ftol except that it might round up or down, 
469 // unlike C's ftol, which must always round down.  
470 // But, in the tmapper, we don't care, since this is
471 // just for Z and L.
472 inline int tmap_ftol(float f)
473 {
474 #ifdef PLAT_UNIX
475         STUB_FUNCTION;
476
477         return 0;
478 #else
479         int x;
480         
481         _asm fld f
482         _asm fistp x
483
484         return x;
485 #endif
486 }
487
488 /*
489 #define tmap_ftol(f) ((int)(f))
490
491 __ftol:
492 004569c0   push      ebp
493 004569c1   mov       ebp,esp
494 004569c3   add       esp,fffffff4
495 004569c6   wait
496 004569c7   fnstcw    [ebp-02]
497 004569ca   wait
498 004569cb   mov       ax,word ptr [ebp-02]
499 004569cf   or        ah,0c
500 004569d2   mov       word ptr [ebp-04],ax
501 004569d6   fldcw     [ebp-04]
502 004569d9   fistp     qword ptr [ebp-0c]
503 004569dc   fldcw     [ebp-02]
504 004569df   mov       eax,dword ptr [ebp-0c]
505 004569e2   mov       edx,dword ptr [ebp-08]
506 004569e5   leave
507 004569e6   ret
508 */
509
510 #ifdef RGB_LIGHTING
511
512 extern ubyte gr_palette[768];
513
514 uint last_code = 0xf;
515 void change_fade_table(uint code)
516 {
517         int i,l;
518
519         if ( last_code == code ) return;
520         last_code = code;
521         
522         int r1=0, g1=0, b1=0;
523
524         for (i=0; i<256; i++ )  {
525                 int r, g, b;
526                 int ur, ug, ub;
527                 r = gr_palette[i*3+0];
528                 g = gr_palette[i*3+1];
529                 b = gr_palette[i*3+2];
530
531                 if ( (r == 255) && (g == 255) && (b == 255) )   {
532                         // Make pure white not fade
533                         for (l=0; l<32; l++ )   {
534                                 gr_fade_table[((l+1)*256)+i] = (unsigned char)i;
535                         }
536                 } else {
537                         for (l=24; l<32; l++ )  {
538
539                                 int x,y;
540                                 int gi, gr, gg, gb;
541         
542                                 gi = (r+g+b)/3;
543
544                                 //gr = r*2;
545                                 //gg = g*2;
546                                 //gb = b*2;
547
548                                 if ( code & 4 ) gr = gi*2; else gr = r;
549                                 if ( code & 2 ) gg = gi*2; else gg = g;
550                                 if ( code & 1 ) gb = gi*2; else gb = b;
551
552 //                              gr = r1;
553 //                              gg = g1;
554 //                              gb = b1;        //gi*2;
555                 
556                                 x = l-24;                       // x goes from 0 to 7
557                                 y = 31-l;                       // y goes from 7 to 0
558
559                                 ur = ((gr*x)+(r*y))/7; if ( ur > 255 ) ur = 255;
560                                 ug = ((gg*x)+(g*y))/7; if ( ug > 255 ) ug = 255;
561                                 ub = ((gb*x)+(b*y))/7; if ( ub > 255 ) ub = 255;
562
563                                 gr_fade_table[((l+1)*256)+i] = (unsigned char)palette_find( ur, ug, ub );
564
565                         }
566                 }
567                 gr_fade_table[ (0*256)+i ] = gr_fade_table[ (1*256)+i ];
568                 gr_fade_table[ (33*256)+i ] = gr_fade_table[ (32*256)+i ];
569         }
570
571         // Mirror the fade table
572         for (i=0; i<34; i++ )   {
573                 for ( l = 0; l < 256; l++ )     {
574                         gr_fade_table[ ((67-i)*256)+l ] = gr_fade_table[ (i*256)+l ];
575                 }
576         }
577
578 }
579 #endif
580
581
582 void grx_tmapper( int nverts, vertex **verts, uint flags )      
583 {
584         int i, y, li, ri, ly, ry, top, rem;
585         float ymin;
586         int next_break;
587         float ulist[TMAP_MAX_VERTS], vlist[TMAP_MAX_VERTS], llist[TMAP_MAX_VERTS];
588
589         flags &= (~TMAP_FLAG_ALPHA);
590         flags &= (~TMAP_FLAG_NONDARKENING);
591         flags &= (~TMAP_FLAG_PIXEL_FOG);
592
593         // Check for invalid flags
594 #ifndef NDEBUG
595         if ( (flags & (TMAP_FLAG_RAMP|TMAP_FLAG_RGB))==(TMAP_FLAG_RAMP|TMAP_FLAG_RGB))  {
596                 Int3();         // You're doing RGB and RAMP lighting!!!
597         }
598
599         if ( flags & TMAP_FLAG_RGB )    {
600                 Int3();         // RGB not supported!
601         }
602
603         if ( (flags & TMAP_FLAG_GOURAUD) && (!(flags & TMAP_FLAG_RAMP)) )       {
604                 Int3();         // Ramp mode required for gouraud!
605         }
606
607         if ( gr_screen.bits_per_pixel != 8 )    {
608                 Int3();                 // Only 8-bpp tmapper supported
609         }
610
611         Tmap_npolys++;
612         Tmap_nverts += nverts;
613
614         Assert(nverts <= TMAP_MAX_VERTS );
615
616 #endif
617         
618         if ( flags & (TMAP_FLAG_RAMP|TMAP_FLAG_GOURAUD) )       {
619                 for (i=0; i<nverts; i++ )       {
620                         llist[i] = Light_table[verts[i]->b];
621                 }
622         }
623
624         if ( Tmap_screen_flags != gr_screen.mode )      {
625                 tmapper_setup();
626         }
627
628         tmap_scanline = tmap_scanline_table[flags];
629 //      tmap_scanline = tmap_scan_generic;
630
631 #ifndef NDEBUG
632         Assert( tmap_scanline != NULL );
633
634         if (Tmap_show_layers)
635                 tmap_scanline = tmapper_show_layers;
636 #endif
637
638         if ( tmap_scanline == NULL ) return;
639
640         Tmap.FadeLookup = (uint)palette_get_fade_table();
641         Tmap.BlendLookup = (uint)palette_get_blend_table(gr_screen.current_alpha);
642
643         if ( flags & TMAP_FLAG_TEXTURED )       {
644
645                 Tmap.bp  = bm_lock( gr_screen.current_bitmap, 8, 0 );
646
647                 int was_tiled = 0, can_tile = 0;
648                 if ( flags & TMAP_FLAG_TILED )  {
649                         if ( (Tmap.bp->w==16) && (Tmap.bp->h==16) ) can_tile = 1;
650                         if ( (Tmap.bp->w==32) && (Tmap.bp->h==32) ) can_tile = 1;
651                         if ( (Tmap.bp->w==64) && (Tmap.bp->h==64) ) can_tile = 1;
652                         if ( (Tmap.bp->w==128) && (Tmap.bp->h==128) ) can_tile = 1;
653                         if ( (Tmap.bp->w==256) && (Tmap.bp->h==256) ) can_tile = 1;
654                 
655                         if ( !can_tile )        {
656                                 was_tiled = 1;
657                                 flags &= (~TMAP_FLAG_TILED);
658                         }
659                 }
660
661                 float max_u = i2fl(Tmap.bp->w) - 0.5f;
662                 float max_v = i2fl(Tmap.bp->h) - 0.5f;
663
664                 for (i=0; i<nverts; i++ )       {
665                         ulist[i] = verts[i]->u * Tmap.bp->w;
666                         vlist[i] = verts[i]->v * Tmap.bp->h;
667
668                         if ( !(flags & TMAP_FLAG_TILED) )       {
669                                 if ( ulist[i] < 1.0f ) ulist[i] = 1.0f;
670                                 if ( vlist[i] < 1.0f ) vlist[i] = 1.0f;
671                                 if ( ulist[i] > max_u ) ulist[i] = max_u;
672                                 if ( vlist[i] > max_v ) vlist[i] = max_v;
673                         }
674         
675                         // Multiply all u,v's by sw for perspective correction
676                         if ( flags & TMAP_FLAG_CORRECT )        {
677                                 ulist[i] *= verts[i]->sw;
678                                 vlist[i] *= verts[i]->sw;
679                         }
680                 }
681
682                 Tmap.pixptr = (unsigned char *)Tmap.bp->data;
683                 Tmap.src_offset = Tmap.bp->rowsize;
684         }
685         
686         // Find the topmost vertex
687         //top = -1;                     // Initialize to dummy value to avoid compiler warning
688         //ymin = 0.0f;          // Initialize to dummy value to avoid compiler warning
689         //      Instead of initializing to avoid compiler warnings, set to first value outside loop and remove (i==0)
690         //      comparison, which otherwise happens nverts times.  MK, 3/20/98 (was tracing code figuring out my shield effect bug...)
691         ymin = verts[0]->sy;
692         top = 0;
693         for (i=1; i<nverts; i++ ) {
694                 if (verts[i]->sy < ymin) {
695                         ymin = verts[i]->sy;
696                         top = i;
697                 }
698         }       
699
700         li = ri = top;
701         rem = nverts;
702         y = fl_round_2048(ymin);                //(int)floor(ymin + 0.5);
703         ly = ry = y - 1;
704
705         gr_lock();
706         Tmap.pScreenBits = (uint)gr_screen.offscreen_buffer_base;
707
708         while( rem > 0 )        {
709                 while ( ly<=y && rem>0 )        {       // Advance left edge?
710                         float dy, frac, recip;
711                         rem--;
712                         i = li-1;       
713                         if ( i<0 ) i = nverts-1;
714                         ly = fl_round_2048(verts[i]->sy);       //(int)floor(verts[i]->sy+0.5);
715
716                         dy = verts[i]->sy - verts[li]->sy;
717                         if ( dy == 0.0f ) dy = 1.0f;
718
719                         frac = y + 0.5f - verts[li]->sy;
720                         recip = 1.0f / dy;
721
722                         Tmap.dl.sx = (verts[i]->sx - verts[li]->sx)*recip; 
723                         Tmap.l.sx = verts[li]->sx + Tmap.dl.sx*frac;
724
725                         if ( flags & TMAP_FLAG_TEXTURED )       {
726                                 Tmap.dl.u = (ulist[i] - ulist[li])*recip; 
727                                 Tmap.l.u = ulist[li] + Tmap.dl.u*frac;
728                                 Tmap.dl.v = (vlist[i] - vlist[li])*recip; 
729                                 Tmap.l.v = vlist[li] + Tmap.dl.v*frac;
730                         }
731
732                         if ( (flags & TMAP_FLAG_CORRECT) || gr_zbuffering  )    {
733                                 Tmap.dl.sw = (verts[i]->sw - verts[li]->sw)*recip;
734                                 Tmap.l.sw = verts[li]->sw + Tmap.dl.sw*frac;
735                         }
736
737                         if ( flags & TMAP_FLAG_GOURAUD )        {
738                                 if ( flags & TMAP_FLAG_RAMP )   {
739                                         Tmap.dl.b = (llist[i] - llist[li])*recip;
740                                         Tmap.l.b = llist[li]  + Tmap.dl.b*frac;
741                                 }
742                         }
743
744                         li = i;
745                 }
746                 while ( ry<=y && rem>0 )        {       // Advance right edge?
747                         float dy, frac, recip;
748                         rem--;
749                         i = ri+1;
750                         if ( i>=nverts ) i = 0;
751                         ry = fl_round_2048(verts[i]->sy);       //(int)floor(verts[i]->sy+0.5);
752
753                         dy = verts[i]->sy - verts[ri]->sy;
754                         if ( dy == 0.0f ) dy = 1.0f;
755
756                         frac = y + 0.5f - verts[ri]->sy;
757                         recip = 1.0f / dy;
758
759                         Tmap.dr.sx = (verts[i]->sx - verts[ri]->sx)*recip; 
760                         Tmap.r.sx = verts[ri]->sx + Tmap.dr.sx*frac;
761
762                         if ( flags & TMAP_FLAG_TEXTURED )       {
763                                 Tmap.dr.u = (ulist[i] - ulist[ri])*recip;
764                                 Tmap.r.u = ulist[ri] + Tmap.dr.u*frac;
765                                 Tmap.dr.v = (vlist[i] - vlist[ri])*recip;
766                                 Tmap.r.v = vlist[ri] + Tmap.dr.v*frac;
767                         }
768
769                         if ( (flags & TMAP_FLAG_CORRECT) || gr_zbuffering  )    {
770                                 Tmap.dr.sw = (verts[i]->sw - verts[ri]->sw)*recip;
771                                 Tmap.r.sw = verts[ri]->sw + Tmap.dr.sw*frac;
772                         }
773
774                         if ( flags & TMAP_FLAG_GOURAUD )        {
775                                 if ( flags & TMAP_FLAG_RAMP )   {
776                                         Tmap.dr.b = (llist[i] - llist[ri])*recip;
777                                         Tmap.r.b = llist[ri] + Tmap.dr.b*frac;
778                                 }
779                         }
780
781                         ri = i;
782                 }
783
784                 if ( ly < ry )  
785                         next_break = ly;
786                 else
787                         next_break = ry;
788
789                 for ( ; y<next_break; y++ )     {
790                         if ( (y >= gr_screen.clip_top) && ( y<=gr_screen.clip_bottom) ) {
791                                 int lx, rx;
792
793
794                                 lx = fl_round_2048(Tmap.l.sx);
795                                 if ( lx < gr_screen.clip_left ) {       
796                                         Tmap.clipped_left = i2fl(gr_screen.clip_left) - Tmap.l.sx;
797                                         lx = gr_screen.clip_left;
798                                 } else {
799                                         Tmap.clipped_left = 0.0f;
800                                 }
801                                 rx = fl_round_2048(Tmap.r.sx-1.0f);
802         
803                                 if ( rx > gr_screen.clip_right ) rx = gr_screen.clip_right;
804                                 if ( lx <= rx ) {
805                                         float dx, recip;        //frac;
806
807                                         dx = Tmap.r.sx - Tmap.l.sx;
808                                         if ( dx == 0.0f ) dx = 1.0f;
809
810                                         //frac = lx + 0.5f - Tmap.l.sx;
811                                         recip = 1.0f / dx;
812
813                                         Tmap.y = y;
814                                         Tmap.rx = rx;
815                                         Tmap.lx = lx;
816                                         Tmap.loop_count = rx - lx + 1;
817                                         #ifndef NDEBUG
818                                                 Tmap_npixels += Tmap.loop_count;
819                                                 Tmap_nscanlines++;
820                                         #endif
821                                         
822                                         if ( (flags & TMAP_FLAG_CORRECT) || gr_zbuffering  )    {
823                                                 Tmap.deltas.sw = (Tmap.r.sw - Tmap.l.sw)*recip;
824                                                 Tmap.fl_dwdx_wide = Tmap.deltas.sw*32.0f;
825                                         }
826         
827                                         if ( flags & TMAP_FLAG_TEXTURED )       {
828                                                 Tmap.deltas.u = (Tmap.r.u - Tmap.l.u)*recip;
829                                                 Tmap.deltas.v = (Tmap.r.v - Tmap.l.v)*recip;
830
831                                                 if ( flags & TMAP_FLAG_CORRECT )        {
832                                                         Tmap.fl_dudx_wide = Tmap.deltas.u*32.0f;
833                                                         Tmap.fl_dvdx_wide = Tmap.deltas.v*32.0f;
834                                                 } else {
835                                                         Tmap.fx_u = tmap_ftol((Tmap.l.u+Tmap.clipped_left*Tmap.deltas.u)*65536.0f);
836                                                         Tmap.fx_v = tmap_ftol((Tmap.l.v+Tmap.clipped_left*Tmap.deltas.v)*65536.0f);
837                                                         Tmap.fx_du_dx = tmap_ftol(Tmap.deltas.u*65536.0f);
838                                                         Tmap.fx_dv_dx = tmap_ftol(Tmap.deltas.v*65536.0f);
839                                                 }
840                                         }
841
842                                         if ( flags & TMAP_FLAG_GOURAUD )        {
843                                                 if ( flags & TMAP_FLAG_RAMP )   {
844                                                         Tmap.deltas.b = (Tmap.r.b - Tmap.l.b)*recip;
845
846                                                         Tmap.fx_l = tmap_ftol(Tmap.l.b*32.0f*65536.0f); 
847                                                         Tmap.fx_l_right = tmap_ftol(Tmap.r.b*32.0f*65536.0f); 
848                                                         Tmap.fx_dl_dx = tmap_ftol(Tmap.deltas.b*32.0f*65536.0f);
849
850                                                         if ( Tmap.fx_dl_dx < 0 )        {
851                                                                 Tmap.fx_dl_dx = -Tmap.fx_dl_dx;
852                                                                 Tmap.fx_l = (67*F1_0)-Tmap.fx_l;
853                                                                 Tmap.fx_l_right = (67*F1_0)-Tmap.fx_l_right;
854                                                 //              Assert( Tmap.fx_l > 31*F1_0 );
855                                                 //              Assert( Tmap.fx_l < 66*F1_0 );
856                                                 //              Assert( Tmap.fx_dl_dx >= 0 );
857                                                 //              Assert( Tmap.fx_dl_dx < 31*F1_0 );
858                                                         }
859                                                 }
860                                         }
861
862                                         if ( gr_zbuffering )    {
863                                                 Tmap.fx_w = tmap_ftol(Tmap.l.sw * GR_Z_RANGE)+gr_zoffset;
864                                                 Tmap.fx_dwdx = tmap_ftol(Tmap.deltas.sw * GR_Z_RANGE);
865                                         }
866
867                                         Tmap.dest_row_data = GR_SCREEN_PTR_SIZE(gr_screen.bytes_per_pixel,Tmap.lx,Tmap.y);
868         
869                                         (*tmap_scanline)();
870
871                                 } 
872
873                         }
874
875                         Tmap.l.sx += Tmap.dl.sx;
876                         Tmap.r.sx += Tmap.dr.sx;
877
878                         if ( flags & TMAP_FLAG_TEXTURED )       {
879                                 Tmap.l.u += Tmap.dl.u;
880                                 Tmap.l.v += Tmap.dl.v;
881
882                                 Tmap.r.u += Tmap.dr.u;
883                                 Tmap.r.v += Tmap.dr.v;
884                         }
885
886                         if ( (flags & TMAP_FLAG_CORRECT) || gr_zbuffering  )    {
887                                 Tmap.l.sw += Tmap.dl.sw;
888                                 Tmap.r.sw += Tmap.dr.sw;
889                         }
890
891                         if ( flags & TMAP_FLAG_GOURAUD )        {
892                                 if ( flags & TMAP_FLAG_RAMP )   {
893                                         Tmap.l.b += Tmap.dl.b;
894                                         Tmap.r.b += Tmap.dr.b;
895                                 }
896                         }
897                 }
898         }
899
900         gr_unlock();
901
902         if ( flags & TMAP_FLAG_TEXTURED )       {
903                 bm_unlock(gr_screen.current_bitmap);
904         }
905
906
907 }