]> icculus.org git repositories - taylor/freespace2.git/blob - src/graphics/grglidetexture.cpp
Initial revision
[taylor/freespace2.git] / src / graphics / grglidetexture.cpp
1 /*
2  * $Logfile: /Freespace2/code/Graphics/GrGlideTexture.cpp $
3  * $Revision$
4  * $Date$
5  * $Author$
6  *
7  * Code to manage Glide texture RAM
8  *
9  * $Log$
10  * Revision 1.1  2002/05/03 03:28:09  root
11  * Initial revision
12  *
13  * 
14  * 14    10/13/99 9:22a Daveb
15  * Fixed Fred jumpnode placing bug. Fixed 1024 glide tiled texture problem
16  * related to movies. Fixed launcher spawning from PXO screen.
17  * 
18  * 13    7/16/99 1:49p Dave
19  * 8 bit aabitmaps. yay.
20  * 
21  * 12    7/13/99 1:15p Dave
22  * 32 bit support. Whee!
23  * 
24  * 11    7/09/99 9:51a Dave
25  * Added thick polyline code.
26  * 
27  * 10    7/08/99 8:10a Mikek
28  * Suppress compiler warning.  Now I get an FS2 programming credit! :)
29  * 
30  * 9     6/29/99 4:16p Dave
31  * Temporary speedup for tcache init.
32  * 
33  * 8     6/29/99 10:35a Dave
34  * Interface polygon bitmaps! Whee!
35  * 
36  * 7     6/16/99 4:06p Dave
37  * New pilot info popup. Added new draw-bitmap-as-poly function.
38  * 
39  * 6     2/08/99 5:07p Dave
40  * FS2 chat server support. FS2 specific validated missions.
41  * 
42  * 5     1/15/99 11:29a Neilk
43  * Fixed D3D screen/texture pixel formatting problem. 
44  * 
45  * 4     12/01/98 8:06a Dave
46  * Temporary checkin to fix some texture transparency problems in d3d.
47  * 
48  * 3     11/30/98 1:07p Dave
49  * 16 bit conversion, first run.
50  * 
51  * 2     10/07/98 10:53a Dave
52  * Initial checkin.
53  * 
54  * 1     10/07/98 10:49a Dave
55  * 
56  * 18    5/14/98 5:39p John
57  * Added in code for multiple non-dimming lights.
58  * 
59  * 17    4/27/98 9:33p John
60  * Removed mprintf
61  * 
62  * 16    4/27/98 9:25p John
63  * Made Glide skip any 2MB boundry, not just first one.
64  * 
65  * 15    4/27/98 9:09p John
66  * Fixed bug where texture was crossing a 2MB line on Voodoo2.  Added code
67  * to tell how full VRAM is and how much got paged in each frame.
68  * 
69  * 14    4/27/98 10:44a John
70  * Put in a new texture caching algorithm that doesn't flush everything
71  * every so oftem.
72  * 
73  * 13    4/26/98 12:02p John
74  * Made glide texturing do its own allocation rather than using the gu_
75  * functions.
76  * 
77  * 12    4/26/98 11:14a John
78  * Restructured/Cleaned up the caching code in preparation for the new
79  * improved caching system.
80  * 
81  * 11    4/22/98 9:13p John
82  * Added code to replace frames of animations in vram if so desired.
83  * 
84  * 10    4/21/98 9:16a John
85  * Fixed bug with directives display in Glide.
86  * 
87  * 9     4/20/98 8:41p John
88  * Made debris culling actually reduce Glide texture resolution.
89  * 
90  * 8     4/09/98 4:38p John
91  * Made non-darkening and transparent textures work under Glide.  Fixed
92  * bug with Jim's computer not drawing any bitmaps.
93  * 
94  * 7     4/09/98 2:21p John
95  * Fixed transparency bug with Glide
96  * 
97  * 6     4/08/98 9:16p John
98  * Made transparency work for textures in Glide by using chromakey.  Made
99  * nondarkening colors work.
100  * 
101  * 5     4/08/98 8:47a John
102  * Moved all texture caching into a new module
103  * 
104  * 4     4/06/98 4:45p John
105  * Removed some debug code that made textures 2x too small.
106  * 
107  * 3     3/04/98 5:43p Hoffoss
108  * Fixed warning.
109  * 
110  * 2     3/04/98 3:50p John
111  * Made the Glide texture cache manager of Leighton's work with 256x256
112  * maps.
113  * 
114  * 1     3/03/98 4:42p John
115  * Added in Leighton's code to do texture caching on Glide.
116  *
117  * $NoKeywords: $
118  */
119
120 //#define USE_8BPP_TEXTURES 
121
122 #include <windows.h>
123 #include <windowsx.h>
124 #include "glide.h"
125 #include "glideutl.h"
126
127 #include "osapi.h"
128 #include "2d.h"
129 #include "bmpman.h"
130 #include "floating.h"
131 #include "palman.h"
132 #include "grinternal.h"
133 #include "grglide.h"
134 #include "line.h"
135 #include "font.h"
136 #include "mouse.h"
137 #include "key.h"
138 #include "systemvars.h"
139 #include "grglideinternal.h"
140
141 #define TEXMEM_2MB_EDGE (2*1024*1024)
142
143 // Hardware specific values
144 typedef struct tcache_data {
145         GrLOD_t           lod;
146         GrAspectRatio_t   aspect;
147         GrTextureFormat_t format;
148         uint                                    vram_offset;
149         int                                     vram_size;      
150 } tcache_data;
151
152 typedef struct tcache_slot {
153         int                             bitmap_id;      
154         float                           uscale;
155         float                           vscale;
156         
157         tcache_data             data;
158         tcache_slot             *data_sections[MAX_BMAP_SECTIONS_X][MAX_BMAP_SECTIONS_Y];               // NULL if no subsections are present. 
159         tcache_slot             *parent;
160 } tcache_slot;
161
162 #define MAX_AUX_TEXTURES                                                200
163 #define MAX_TEXTURES                                                            MAX_BITMAPS
164
165 // search for AUX to find all instancees of aux textures which can be put back in.
166
167 // AUX
168 // static tcache_slot *Textures_aux = NULL;                                                                                                             // auxiliary textures for storing sections of a texture
169 static void *Texture_sections = NULL;
170 static tcache_slot *Textures = NULL;
171 ubyte *Glide_tmp_ram = NULL;
172
173 int Glide_last_bitmap_id = -1;
174 int Glide_last_bitmap_type = -1;
175 int Glide_last_section_x = -1;
176 int Glide_last_section_y = -1;
177 float Glide_last_u_ratio, Glide_last_v_ratio;
178
179 static int Glide_last_detail = -1;
180
181 uint Glide_total_memory;
182 uint Glide_start_address;
183 uint Glide_end_address;
184 uint Glide_current_address;
185
186 int Glide_textures_in_frame = 0;
187
188 int Glide_explosion_vram = 0;
189
190 //=======================================================
191 // Code to manage texture memory.   
192 // This basically allocates until out of VRAM, and then starts freeing 
193 // blocks at the start of VRAM to make room for new textures.   
194 // Based on code from Jason Scannell's webpage.
195 // http://members.home.net/jscannell.  
196
197 typedef struct  { 
198         int             next; 
199         uint            start_address; 
200         int             size;
201         tcache_slot             *texture_ptr;
202 } tblock; 
203
204 tblock  *Tblocks = NULL;                // Memory tracking blocks 
205 int             Tblock_num_blocks = 0;          // How many blocks to use
206
207 int Tblock_freelist_start;                              // First block in free list 
208 int Tblock_usedlist_start;                              // First block in allocation list 
209 int Tblock_usedlist_head;                               // Last block in allocation list 
210
211 uint Tblock_min_address;                                // Lowest address in texture memory 
212 uint Tblock_max_address;                                // Highest address in texture memory 
213
214 void FlushBlocks()
215 {
216         int i;
217
218         memset(Tblocks,0,sizeof(tblock)*Tblock_num_blocks); 
219
220         for(i = 0; i < Tblock_num_blocks - 1; i++)      {
221                 Tblocks[i].next = i + 1; 
222         }
223
224         Tblocks[Tblock_num_blocks - 1].next = -1; 
225
226         Tblock_usedlist_start = -1; 
227         Tblock_usedlist_head  = -1; 
228         Tblock_freelist_start  = 0; 
229 }
230
231 void InitBlocks(uint min, uint max, int num_blocks) 
232
233         Tblock_num_blocks = num_blocks;
234         Tblock_min_address = min;
235         Tblock_max_address = max;
236
237         if(Tblocks == NULL){
238                 Tblocks = (tblock *)malloc(Tblock_num_blocks*sizeof(tblock));
239                 Assert(Tblocks!=NULL);
240         }
241
242         FlushBlocks();
243
244
245 void ReleaseBlocks()
246 {
247         if ( Tblocks )  {
248                 free(Tblocks);
249                 Tblocks = NULL;
250         }
251         Tblock_num_blocks = 0;
252 }
253
254 void ReleaseSlotSub(tcache_slot *t)
255 {
256         int idx, s_idx;
257
258         if(t == NULL){
259                 return;
260         }
261
262         t->bitmap_id = -1;
263         for(idx=0; idx<MAX_BMAP_SECTIONS_X; idx++){
264                 for(s_idx=0; s_idx<MAX_BMAP_SECTIONS_Y; s_idx++){
265                         // recurse
266                         if(t->data_sections[idx][s_idx] != NULL){                               
267                                 ReleaseSlotSub(t->data_sections[idx][s_idx]);
268                                 t->data_sections[idx][s_idx] = NULL;
269                         }
270                 }
271         }
272 }
273
274 void ReleaseSlot(int nBlock)
275 {
276         if ( Tblocks[nBlock].texture_ptr != NULL )      {                               
277                 // if this guy has a parent (in the case of a sectioned bitmap), unset his bitmap
278                 if(Tblocks[nBlock].texture_ptr->parent != NULL){
279                         Tblocks[nBlock].texture_ptr->parent->bitmap_id = -1;
280                 }
281                 Tblocks[nBlock].texture_ptr->bitmap_id = -1;
282
283                 // AUX
284                 // ReleaseSlotSub(Tblocks[nBlock].texture_ptr);
285                 Tblocks[nBlock].texture_ptr = NULL;
286                 
287
288                 Glide_textures_in -= Tblocks[nBlock].size;
289         }
290 }
291
292 void FreeBlock(int nBlock) 
293
294         int nFreeNext; 
295
296         ReleaseSlot(nBlock);
297
298         //---- Save next indices ---- 
299         nFreeNext = Tblock_freelist_start; 
300
301         //---- Move alloc list block to start of free list ---- 
302         Tblock_freelist_start = nBlock; 
303         Tblocks[nBlock].next = nFreeNext; 
304
305
306
307 int AllocBlock(void) 
308
309         int     nNewBlock; 
310
311         //---- Get block from free list ---- 
312         nNewBlock = Tblock_freelist_start; 
313
314         //**** DOS NOT HANDLE EMPTY FREE LIST **** 
315         Tblock_freelist_start = Tblocks[Tblock_freelist_start].next; 
316
317         if(Tblock_usedlist_head < 0)    { 
318                 //---- Alloc list is empty, add to start ---- 
319                 Tblock_usedlist_start = nNewBlock; 
320                 Tblocks[nNewBlock].next = -1; 
321         } else { 
322                 //---- Insert at head of alloc list ---- 
323                 Tblocks[nNewBlock].next = Tblocks[Tblock_usedlist_head].next; 
324                 Tblocks[Tblock_usedlist_head].next = nNewBlock; 
325         } 
326
327         //---- Set new head index ---- 
328         Tblock_usedlist_head = nNewBlock; 
329
330         return nNewBlock; 
331
332
333 // Macro to compute ending address of block 
334 #define BLOCK_END(b) (Tblocks[b].start_address + Tblocks[b].size) 
335
336 uint AllocateTexture(uint size, tcache_slot *texture_ptr)
337
338         int     nNewBlock; 
339         int     next; 
340
341         if (Tblock_usedlist_start < 0)  { 
342
343                 //---- Alloc list is empty ---- 
344                 nNewBlock = AllocBlock(); 
345                 Tblocks[nNewBlock].start_address = Tblock_min_address; 
346         } else { 
347
348                 uint dwAddress = BLOCK_END(Tblock_usedlist_head);
349                 if ( dwAddress + size < Tblock_max_address )    {
350                         int a1 = dwAddress / TEXMEM_2MB_EDGE;
351                         int a2 = (dwAddress+size) / TEXMEM_2MB_EDGE;
352         
353                         if ( a2 > a1 )  {
354                                 //mprintf(( "GrGlideTexture: Skipping a 2MB edge!\n" ));
355                                 dwAddress = a2*TEXMEM_2MB_EDGE;
356                         }
357                 }
358
359                 if( (dwAddress + size > Tblock_max_address) || (Tblocks[Tblock_freelist_start].next<0) )        { 
360                         #ifndef NDEBUG
361                         if ( Tblocks[Tblock_freelist_start].next < 0 )  {
362                                 mprintf(( "GrGlideTexture: AllocateTexture out of blocks!  Get John.\n" ));
363                         }
364                         #endif
365
366                         //---- No room left, go back to start ---- 
367                         ReleaseSlot(Tblock_usedlist_start);
368
369                         nNewBlock = Tblock_usedlist_head = Tblock_usedlist_start; 
370                         dwAddress = Tblock_min_address; 
371                 } else { 
372
373                         //---- Make new block ---- 
374                         nNewBlock = AllocBlock(); 
375                 } 
376
377                 next = Tblocks[Tblock_usedlist_head].next; 
378
379                 //---- Unlink blocks being overwritten ---- 
380                 while((next >= 0) && (dwAddress + size > Tblocks[next].start_address)) { 
381
382                         int    nTemp = Tblocks[next].next; 
383
384                         FreeBlock(next); 
385                         next = nTemp; 
386                 } 
387
388                 //---- Init new block ---- 
389                 Tblocks[nNewBlock].next          = next; 
390                 Tblocks[nNewBlock].start_address = dwAddress; 
391         } 
392
393         Tblocks[nNewBlock].size = size; 
394         Tblocks[nNewBlock].texture_ptr = texture_ptr;
395
396         return Tblocks[nNewBlock].start_address; 
397
398
399 void glide_tcache_set_initial_texture_mode()
400 {
401         grTexMipMapMode( GR_TMU0, GR_MIPMAP_DISABLE, FXFALSE);
402         grTexLodBiasValue( GR_TMU0, .5f);
403         grTexClampMode( GR_TMU0, GR_TEXTURECLAMP_WRAP, GR_TEXTURECLAMP_WRAP);
404         grTexFilterMode( GR_TMU0, GR_TEXTUREFILTER_BILINEAR, GR_TEXTUREFILTER_BILINEAR);
405 }
406
407 void glide_tcache_init()
408 {
409         // if we're already inited, allocate nothing new)
410         if(Textures == NULL){
411                 Textures = (tcache_slot *)malloc((MAX_TEXTURES)*sizeof(tcache_slot));
412                 if ( !Textures )        {
413                         exit(1);        
414                 }
415         }
416
417         // AUX  
418         /*
419         Textures_aux = (tcache_slot*)malloc((MAX_TEXTURES) * MAX_BMAP_SECTIONS_X * MAX_BMAP_SECTIONS_Y sizeof(tcache_slot));
420         if( !Textures_aux){
421                 exit(1);
422         }
423         */
424         // if we're already inited, allocate nothing new)
425         if(Texture_sections == NULL){
426                 Texture_sections = malloc(MAX_TEXTURES * MAX_BMAP_SECTIONS_X * MAX_BMAP_SECTIONS_Y * sizeof(tcache_slot));
427                 if(!Texture_sections){
428                         exit(1);
429                 }
430         }
431
432         // if we're already inited, allocate nothing new)
433         if(Glide_tmp_ram == NULL){
434                 Glide_tmp_ram = (ubyte *)malloc(256*256*2);
435                 if ( !Glide_tmp_ram )   {
436                         exit(1);
437                 }
438         }
439
440         Glide_total_memory = guTexMemQueryAvail(GR_TMU0);
441         Glide_start_address = grTexMinAddress(GR_TMU0);
442         Glide_end_address = grTexMaxAddress(GR_TMU0);
443         Glide_current_address = Glide_start_address;
444
445         mprintf(( "Total texture memory on 3dfx card=%d bytes\n", Glide_total_memory ));
446
447         glide_tcache_set_initial_texture_mode();
448         
449         InitBlocks(Glide_start_address,Glide_end_address, MAX_TEXTURES);
450
451         // Init the texture structures  
452         int i, idx, s_idx, count;
453         count = 0;
454         for( i=0; i<MAX_TEXTURES; i++ ) {
455                 Textures[i].bitmap_id = -1;             
456                 Textures[i].parent = NULL;
457                 
458                 for(idx=0; idx<MAX_BMAP_SECTIONS_X; idx++){
459                         for(s_idx=0; s_idx<MAX_BMAP_SECTIONS_Y; s_idx++){
460                                 // AUX
461                                 // Textures[i].data_sections[idx][s_idx] = NULL;
462                                 // Textures[i].data_sections[idx][s_idx] = (tcache_slot*)malloc(sizeof(tcache_slot));
463                                 Textures[i].data_sections[idx][s_idx] = &((tcache_slot*)Texture_sections)[count++];
464                                 Textures[i].data_sections[idx][s_idx]->parent = &Textures[i];
465                         }
466                 }               
467         }
468         
469         // AUX
470         /*
471         for( i=0; i<MAX_AUX_TEXTURES; i++){
472                 Textures_aux[i].bitmap_id = -1;
473                 
474                 for(idx=0; idx<MAX_BMAP_SECTIONS_X; idx++){
475                         for(s_idx=0; s_idx<MAX_BMAP_SECTIONS_Y; s_idx++){
476                                 Textures_aux[i].data_sections[idx][s_idx] = NULL;
477                         }
478                 }
479         }
480         */
481
482         Glide_textures_in = 0;
483         Glide_last_bitmap_id = -1;
484         Glide_last_section_x = -1;
485         Glide_last_section_y = -1;
486
487         Glide_last_detail = Detail.hardware_textures;
488 }
489
490 void glide_tcache_cleanup()
491 {
492         if ( Textures ) {
493                 free(Textures);
494                 Textures = NULL;
495         }
496
497         // AUX
498         /*
499         if ( Textures_aux )     {
500                 free(Textures_aux);
501                 Textures_aux = NULL;
502         }
503         */
504         if(Texture_sections){
505                 free(Texture_sections);
506                 Texture_sections = NULL;
507         }
508
509         if ( Glide_tmp_ram )    {
510                 free(Glide_tmp_ram);
511                 Glide_tmp_ram = NULL;
512         }
513
514         ReleaseBlocks();
515 }
516
517 void glide_tcache_flush()
518 {
519         if ( grSstIsBusy() )    {
520                 //mprintf(( "Pausing until 3DFX is idle before clearing texture RAM...\n" ));
521                 grSstIdle();    // Wait for idle
522         }
523
524         Glide_current_address = Glide_start_address;
525
526         // Init the texture structures
527         int i; //, idx, s_idx;
528         for( i=0; i<MAX_TEXTURES; i++ ) {
529                 Textures[i].bitmap_id = -1;             
530
531                 // AUX
532                 /*
533                 for(idx=0; idx<MAX_BMAP_SECTIONS_X; idx++){
534                         for(s_idx=0; s_idx<MAX_BMAP_SECTIONS_Y; s_idx++){
535                                 Textures[i].data_sections[idx][s_idx] = NULL;
536                         }
537                 }
538                 */
539         }
540         
541         // AUX
542         /*
543         for( i=0; i<MAX_AUX_TEXTURES; i++){
544                 Textures_aux[i].bitmap_id = -1;
545                 
546                 for(idx=0; idx<MAX_BMAP_SECTIONS_X; idx++){
547                         for(s_idx=0; s_idx<MAX_BMAP_SECTIONS_Y; s_idx++){
548                                 Textures_aux[i].data_sections[idx][s_idx] = NULL;
549                         }
550                 }
551         }
552         */
553
554         Glide_textures_in = 0;
555         Glide_last_bitmap_id = -1;      
556         Glide_last_section_x = -1;
557         Glide_last_section_y = -1;
558
559
560         Glide_explosion_vram = 0;
561
562         FlushBlocks();
563 }
564
565 // get a free aux texture
566 // AUX
567 /*
568 int ga_reentrant = 0;
569 tcache_slot *glide_get_aux_slot()
570 {
571         int idx;
572         int index = -1;
573         tcache_slot *ret;
574
575         // never go in here more than twice
576         if(ga_reentrant > 1){
577                 return NULL;
578         }
579
580         ga_reentrant++;
581
582         for(idx=0; idx<MAX_AUX_TEXTURES; idx++){
583                 if(Textures_aux[idx].bitmap_id == -1){
584                         index = idx;
585                         break;
586                 }
587         }
588
589         // OH NO. This means we've run out of slots for bitmap sections. Let's just blast all of them free. whee!
590         if(index == -1){
591                 mprintf(("AIEEEE! FLUSHIN SECTIONED BITMAPS!\n"));
592                 for(idx=0; idx<MAX_TEXTURES; idx++){
593                         if((Textures[idx].bitmap_id > -1) && (Textures[idx].data_sections[0][0] != NULL)){
594                                 ReleaseSlot(&Textures[idx] - Textures);
595                         }
596                 }
597                         
598                 ret = glide_get_aux_slot();
599
600                 ga_reentrant--;
601                 return ret;
602         }
603
604         // hmm
605         int s_idx;
606         Textures_aux[index].bitmap_id = -1;     
607         Textures_aux[index].data.vram_offset = 0;
608         Textures_aux[index].data.vram_size = 0;
609         for(idx=0; idx<MAX_BMAP_SECTIONS_X; idx++){
610                 for(s_idx=0; s_idx<MAX_BMAP_SECTIONS_Y; s_idx++){
611                         Textures_aux[index].data_sections[idx][s_idx] = NULL;                   
612                 }
613         }
614
615         ret = &Textures_aux[index];
616         ga_reentrant--;
617         return ret;     
618 }
619 */
620
621 void glide_tcache_frame()
622 {
623         Glide_textures_in_frame = 0;
624 }
625
626 extern int palman_is_nondarkening(int r,int g, int b);
627
628 // data == start of bitmap data
629 // sx == x offset into bitmap
630 // sy == y offset into bitmap
631 // src_w == absolute width of section on source bitmap
632 // src_h == absolute height of section on source bitmap
633 // bmap_w == width of source bitmap
634 // bmap_h == height of source bitmap
635 // tex_w == width of final texture
636 // tex_h == height of final texture
637 int glide_create_texture_sub(int bitmap_type, int bitmap_handle, ushort *data, int sx, int sy, int src_w, int src_h, int bmap_w, int bmap_h, int tex_w, int tex_h, tcache_slot *tslot)
638 {       
639         int i, j;       
640
641         // sanity - make sure we're not going to run off the end of the bitmap
642 #ifndef NDEBUG
643         Assert(src_w <= (bmap_w - sx));
644         Assert(src_h <= (bmap_h - sy));
645 #endif
646
647         if ( tex_w <= 16 ) tex_w = 16;
648         else if ( tex_w <= 32 ) tex_w = 32;
649         else if ( tex_w <= 64 ) tex_w = 64;
650         else if ( tex_w <= 128 ) tex_w = 128;
651         else {
652                 tex_w = 256;
653         }
654
655         if ( tex_h <= 16 ) tex_h = 16;
656         else if ( tex_h <= 32 ) tex_h = 32;
657         else if ( tex_h <= 64 ) tex_h = 64;
658         else if ( tex_h <= 128 ) tex_h = 128;
659         else {
660                 tex_h = 256;
661         }       
662
663         // these can never be shrunk. meaning, the texture _must_ be big enough to hold every pixel
664         if ( (bitmap_type == TCACHE_TYPE_AABITMAP) || (bitmap_type == TCACHE_TYPE_BITMAP_SECTION) )     {
665                 // W & H must be within 8x of each other.       
666                 if ( (tex_w==16) && (tex_h==256) )      {
667                         tex_w = 32;
668                 } else if ( (tex_w==256) && (tex_h==16) )       {
669                         tex_h = 32;
670                 }
671         } else {
672                 // W & H must be within 8x of each other.       
673                 if ( (tex_w==16) && (tex_h==256) )      {
674                         tex_h = 128;
675                 } else if ( (tex_w==256) && (tex_h==16) )       {
676                         tex_w = 128;
677                 }
678         }
679
680         ushort *bmp_data = data;
681         ubyte *bmp_data_byte = (ubyte*)data;
682
683         GrTextureFormat_t tex_format;
684
685         if ( bitmap_type == TCACHE_TYPE_AABITMAP )      {
686                 tex_format = GR_TEXFMT_ALPHA_8;
687                 
688                 ubyte *lpSP;
689                 ubyte pix;
690                 ubyte xlat[256];
691                 
692                 for (i=0; i<16; i++ )   {
693                         xlat[i] = ubyte(Gr_gamma_lookup[(i*255)/15]);
694                 }
695                 xlat[15] = xlat[1];
696                 pix = 255;
697                 for ( ; i<256; i++ )    {
698                         xlat[i] = pix;
699                 }
700
701                 // upload to temp ram
702                 for (j = 0; j < tex_h; j++) {
703                         // the proper line in the temp ram
704                         lpSP = (ubyte*)(Glide_tmp_ram + tex_w * j);
705
706                         // upload the line of texture from the source bitmap
707                         for (i = 0; i < tex_w; i++) {
708                                 // if we're within the bounds of the section we're copying
709                                 if ( (j < src_h) && (i < src_w) )       {
710                                         *lpSP++ = xlat[(ubyte)bmp_data_byte[(j * bmap_w) + i + sx]];
711                                 }
712                                 // otherwise just copy black
713                                 else {
714                                         *lpSP++ = 0;
715                                 }
716                         }
717                 }
718         } else if(bitmap_type == TCACHE_TYPE_BITMAP_SECTION){
719                 tex_format = GR_TEXFMT_ARGB_1555;                               
720                 ushort *lpSP;                                           
721
722                 for (j = 0; j < src_h; j++) {
723                         // the proper line in the temp ram
724                         lpSP = (unsigned short*)(Glide_tmp_ram + tex_w * 2 * j);
725
726                         // nice and clean
727                         for (i = 0; i < src_w; i++) {                                                                                           
728                                 // stuff the texture into vram
729                                 *lpSP++ = bmp_data[((j+sy) * bmap_w) + sx + i];
730                         }                       
731                 }
732         } else {                
733                 tex_format = GR_TEXFMT_ARGB_1555;               
734                 fix u, utmp, v, du, dv;                         
735                 ushort *lpSP;           
736                 
737                 u = 0;
738
739                 // source line on the bitmap;           
740                 v = i2f(sy);
741
742                 // scale through the texture            
743                 du = (src_w * F1_0) / tex_w;
744                 dv = (src_h * F1_0) / tex_h;
745
746                 for (j = 0; j < tex_h; j++) {
747                         // the proper line in the temp ram
748                         lpSP = (unsigned short*)(Glide_tmp_ram + tex_w * 2 * j);
749
750                         // pixel offset on this individual line of the source bitmap
751                         utmp = u + i2f(sx);
752
753                         // nice and clean
754                         for (i = 0; i < tex_w; i++) {                                                                                           
755                                 // stuff the texture into vram
756                                 *lpSP++ = bmp_data[f2i(v) * bmap_w + f2i(utmp)];
757
758                                 // next pixel
759                                 utmp += du;                             
760                         }
761
762                         // next line in the source bitmap
763                         v += dv;
764                 }
765         }       
766
767         GrLOD_t lod=GR_LOD_16;
768
769         int longest = max(tex_w, tex_h);
770
771         float uscale, vscale;           
772         if ( bitmap_type == TCACHE_TYPE_AABITMAP )      {
773                 uscale = i2fl(bmap_w)*256.0f / i2fl(longest);
774                 vscale = i2fl(bmap_h)*256.0f / i2fl(longest);
775         } else if(bitmap_type == TCACHE_TYPE_BITMAP_SECTION){
776                 uscale = i2fl(src_w)*256.0f / i2fl(longest);
777                 vscale = i2fl(src_h)*256.0f / i2fl(longest);
778         } else {
779                 uscale = i2fl(tex_w)*256.0f / i2fl(longest);
780                 vscale = i2fl(tex_h)*256.0f / i2fl(longest);
781         }
782
783         switch( longest )       {
784         case 16:                lod = GR_LOD_16; break;
785         case 32:                lod = GR_LOD_32; break;
786         case 64:                lod = GR_LOD_64; break;
787         case 128:       lod = GR_LOD_128; break;
788         case 256:       lod = GR_LOD_256; break;
789         default:                Int3();
790         }
791
792         // GR_ASPECT_2x1        
793         GrAspectRatio_t aspect = GR_ASPECT_1x1;         // aspect is widthxheight
794
795         if ( tex_w < tex_h )    {
796                 int ratio = tex_h / tex_w;
797                 switch(ratio)   {
798                 case 1: aspect = GR_ASPECT_1x1; break;
799                 case 2: aspect = GR_ASPECT_1x2; break;
800                 case 4: aspect = GR_ASPECT_1x4; break;
801                 case 8: aspect = GR_ASPECT_1x8; break;
802                 default:        Int3();
803                 }
804         } else {
805                 int ratio = tex_w / tex_h;
806                 switch(ratio)   {
807                 case 1: aspect = GR_ASPECT_1x1; break;
808                 case 2: aspect = GR_ASPECT_2x1; break;
809                 case 4: aspect = GR_ASPECT_4x1; break;
810                 case 8: aspect = GR_ASPECT_8x1; break;
811                 default:        Int3();
812                 }
813         }
814
815
816         GrTexInfo info;
817
818         info.smallLod = lod;                                    //GR_LOD_256;
819         info.largeLod = lod;                                    //GR_LOD_256;
820         info.aspectRatio = aspect;                      //GR_ASPECT_1x1;
821         info.format = tex_format;                               //GR_TEXFMT_ARGB_1555;
822         info.data = Glide_tmp_ram;                                              //source data
823
824         int bytes_needed = grTexTextureMemRequired( GR_MIPMAPLEVELMASK_BOTH, &info );
825
826         // if   ( (tslot->data.vram_offset == 0) || ((tslot->data.vram_offset>0)&&(bytes_needed>tslot->data.vram_size)))        {
827                 tslot->data.vram_offset = AllocateTexture( bytes_needed, tslot );
828                 tslot->data.vram_size = bytes_needed;
829                 Glide_textures_in += bytes_needed;
830         // }
831
832         tslot->data.format = tex_format;
833         tslot->data.lod = lod;
834         tslot->data.aspect = aspect;
835         tslot->bitmap_id = bitmap_handle;
836         tslot->uscale = uscale;
837         tslot->vscale = vscale; 
838         
839         grTexDownloadMipMap(GR_TMU0, tslot->data.vram_offset, GR_MIPMAPLEVELMASK_BOTH, &info); 
840         Glide_textures_in_frame += bytes_needed;        
841
842         return 1;
843 }
844
845 int glide_create_texture( int bitmap_handle, int bitmap_type, tcache_slot *tslot )
846 {
847         int ret;
848         ubyte flags;
849         bitmap *bmp;
850         ubyte bpp = 16;
851
852         // setup texture/bitmap flags
853         flags = 0;
854         switch(bitmap_type){
855         case TCACHE_TYPE_AABITMAP:
856                 flags |= BMP_AABITMAP;
857                 bpp = 8;
858                 break;
859         case TCACHE_TYPE_XPARENT:
860         case TCACHE_TYPE_BITMAP_SECTION:
861                 flags |= BMP_TEX_XPARENT;
862                 break;
863         case TCACHE_TYPE_NORMAL:
864                 flags |= BMP_TEX_OTHER;
865                 break;
866         case TCACHE_TYPE_NONDARKENING:
867                 flags |= BMP_TEX_NONDARK;
868                 break;
869         } 
870                 
871         // lock the bitmap in the proper format
872         bmp = bm_lock(bitmap_handle, bpp, flags);       
873         if ( bmp == NULL ) {
874                 mprintf(("Couldn't lock bitmap %d.\n", bitmap_handle ));
875                 return 0;
876         }
877
878         int max_w = bmp->w;
879         int max_h = bmp->h; 
880
881         if ( bitmap_type != TCACHE_TYPE_AABITMAP )      {
882                 // Detail.debris_culling goes from 0 to 4.
883                 max_w /= 16>>Detail.hardware_textures;
884                 max_h /= 16>>Detail.hardware_textures;
885         }       
886
887         // call the helper
888         ret = glide_create_texture_sub(bitmap_type, bitmap_handle, (ushort*)bmp->data, 0, 0, bmp->w, bmp->h, bmp->w, bmp->h, max_w, max_h, tslot);      
889
890         // unlock the bitmap
891         bm_unlock(bitmap_handle);
892
893         // return
894         return ret;
895 }
896
897 // create a sectioned texture
898 int glide_create_texture_sectioned(int bitmap_handle, int bitmap_type, tcache_slot *tslot, int sx, int sy)
899 {
900         int ret;
901         ubyte flags;
902         bitmap *bmp;
903         int section_x, section_y;
904
905         // setup texture/bitmap flags
906         Assert(bitmap_type == TCACHE_TYPE_BITMAP_SECTION);
907         if(bitmap_type != TCACHE_TYPE_BITMAP_SECTION){
908                 bitmap_type = TCACHE_TYPE_BITMAP_SECTION;
909         }
910         flags = BMP_TEX_XPARENT;        
911                 
912         // lock the bitmap in the proper format
913         bmp = bm_lock(bitmap_handle, 16, flags);        
914         if ( bmp == NULL ) {
915                 mprintf(("Couldn't lock bitmap %d.\n", bitmap_handle ));
916                 return 0;
917         }       
918
919         // determine the width and height of this section
920         bm_get_section_size(bitmap_handle, sx, sy, &section_x, &section_y);     
921
922         // call the helper
923         ret = glide_create_texture_sub(bitmap_type, bitmap_handle, (ushort*)bmp->data, bmp->sections.sx[sx], bmp->sections.sy[sy], section_x, section_y, bmp->w, bmp->h, section_x, section_y, tslot);  
924
925         // unlock the bitmap
926         bm_unlock(bitmap_handle);
927
928         // return
929         return ret;
930 }
931
932
933 DCF(exp_flush, "")
934 {
935         Glide_explosion_vram = 0;
936 }
937
938 extern int bm_get_cache_slot( int bitmap_id, int separate_ani_frames );
939
940 // Returns FALSE if error
941 int glide_tcache_set( int bitmap_id, int bitmap_type, float *u_ratio, float *v_ratio, int fail_on_full, int sx, int sy, int force )
942 {               
943         bitmap *bmp;
944         int idx, s_idx;
945
946         if ( Glide_last_detail != Detail.hardware_textures )    {
947                 Glide_last_detail = Detail.hardware_textures;
948                 glide_tcache_flush();
949         }
950
951         // Check if this is the same as the last one... if so, we don't need to
952         // do anything.
953         if ( (Glide_last_bitmap_id == bitmap_id) && (Glide_last_bitmap_type==bitmap_type) && (Glide_last_section_x == sx) && (Glide_last_section_y == sy) && !force)    {
954                 *u_ratio = Glide_last_u_ratio;
955                 *v_ratio = Glide_last_v_ratio;
956                 return 1;
957         }
958
959         int n;
960         n = bm_get_cache_slot( bitmap_id, 1 );
961
962         tcache_slot * t = &Textures[n];
963
964         // if this is a sectioned bitmap
965         if(bitmap_type == TCACHE_TYPE_BITMAP_SECTION){          
966                 // if the texture sections haven't been created yet
967                 if((t->bitmap_id < 0) || (t->bitmap_id != bitmap_id) || force){
968
969                         if(t->bitmap_id < 0){
970                                 t->data.vram_offset = 0;
971                         }                       
972
973                         // lock the bitmap in the proper format
974                         bmp = bm_lock(bitmap_id, 16, BMP_TEX_XPARENT);  
975                         bm_unlock(bitmap_id);
976
977                         // first we need to get enough free aux textures                        
978                         // AUX
979                         /*
980                         for(idx=0; idx<bmp->sections.num_x; idx++){                             
981                                 for(s_idx=0; s_idx<bmp->sections.num_y; s_idx++){
982                                         // try and get a feww slot
983                                         t->data_sections[idx][s_idx] = glide_get_aux_slot();
984                                         if(t->data_sections[idx][s_idx] == NULL){
985                                                 Int3();
986                                                 return 0;
987                                         }                               
988                                         t->data_sections[idx][s_idx]->bitmap_id = bitmap_id;
989                                 }
990                         }
991                         */
992
993                         // now lets do something for each texture                       
994                         for(idx=0; idx<bmp->sections.num_x; idx++){
995                                 for(s_idx=0; s_idx<bmp->sections.num_y; s_idx++){                                                                               
996                                         if(t->bitmap_id < 0){
997                                                 t->data_sections[idx][s_idx]->data.vram_offset = 0;
998                                         }
999
1000                                         t->data_sections[idx][s_idx]->bitmap_id = bitmap_id;
1001                                         glide_create_texture_sectioned( bitmap_id, bitmap_type, t->data_sections[idx][s_idx], idx, s_idx);
1002                                 }
1003                         }
1004
1005                         t->bitmap_id = bitmap_id;
1006                 }
1007
1008                 // swap in the texture we want                          
1009                 t = t->data_sections[sx][sy];
1010         }
1011         // all other "normal" textures
1012         else {
1013                 // no texture yet
1014                 if ( t->bitmap_id < 0) {
1015                         t->data.vram_offset = 0;                
1016                         glide_create_texture( bitmap_id, bitmap_type, t );
1017                 }
1018                 // different bitmap altogether
1019                 else if ( (t->bitmap_id != bitmap_id) || force) {
1020                         glide_create_texture( bitmap_id, bitmap_type, t );
1021                 }
1022         }               
1023
1024         *u_ratio = t->uscale;
1025         *v_ratio = t->vscale;
1026
1027         GrTexInfo info;
1028
1029         info.smallLod = t->data.lod;                            //GR_LOD_256;
1030         info.largeLod = t->data.lod;                            //GR_LOD_256;
1031         info.aspectRatio = t->data.aspect;              //GR_ASPECT_1x1;
1032         info.format = t->data.format;                           //GR_TEXFMT_ARGB_1555;
1033         info.data = 0;                                                                  //source data
1034
1035         grTexSource( GR_TMU0, t->data.vram_offset, GR_MIPMAPLEVELMASK_BOTH, &info );
1036
1037         // Save current state so we don't have to do anything time consuming next time
1038         // we set this exact same texture
1039         Glide_last_bitmap_id = bitmap_id;
1040         Glide_last_bitmap_type = bitmap_type;
1041         Glide_last_section_x = sx;
1042         Glide_last_section_y = sy;
1043         Glide_last_u_ratio = t->uscale;
1044         Glide_last_v_ratio = t->vscale;
1045
1046         return 1;
1047 }
1048
1049
1050
1051
1052