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