]> icculus.org git repositories - taylor/freespace2.git/blob - src/graphics/grgl1texture.cpp
fix crash in tcache_flush() when tcache hasn't been initted yet
[taylor/freespace2.git] / src / graphics / grgl1texture.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 #include "SDL_opengl.h"
10
11 #include "pstypes.h"
12 #include "2d.h"
13 #include "gropengl.h"
14 #include "gropenglinternal.h"
15 #include "grgl1.h"
16 #include "bmpman.h"
17 #include "grinternal.h"
18 #include "systemvars.h"
19 #include "osregistry.h"
20
21
22 static int vram_full = 0;
23
24 typedef struct tcache_slot_opengl {
25         GLuint  texture_handle;
26         float   u_scale, v_scale;
27         int     bitmap_id;
28         int     size;
29         int     used_this_frame;
30         int     time_created;
31         ushort  w,h;
32
33         // sections
34         tcache_slot_opengl      *data_sections[MAX_BMAP_SECTIONS_X][MAX_BMAP_SECTIONS_Y];
35         tcache_slot_opengl      *parent;
36
37         gr_texture_source       texture_mode;
38 } tcache_slot_opengl;
39
40 static void *Texture_sections = NULL;
41 static tcache_slot_opengl *Textures = NULL;
42
43 static tcache_slot_opengl *GL_bound_texture;
44
45 static int GL_frame_count = 0;
46 static int GL_last_bitmap_id = -1;
47 static int GL_last_detail = -1;
48 static int GL_last_bitmap_type = -1;
49 static int GL_last_section_x = -1;
50 static int GL_last_section_y = -1;
51 static int GL_should_preload = 0;
52
53 extern int Gr_textures_in;
54
55 static gr_texture_source GL_current_texture_source = (gr_texture_source) -1;
56
57 static ubyte GL_xlat[256] = { 0 };
58
59 extern int bm_get_cache_slot( int bitmap_id, int separate_ani_frames );
60
61
62 void opengl1_set_texture_state(gr_texture_source ts)
63 {
64         if (ts == TEXTURE_SOURCE_NONE) {
65                 GL_bound_texture = NULL;
66
67                 glBindTexture(GL_TEXTURE_2D, 0);
68                 opengl1_tcache_set(-1, -1, NULL, NULL, 0, -1, -1, 0 );
69         } else if (GL_bound_texture &&
70                 GL_bound_texture->texture_mode != ts) {
71                 switch (ts) {
72                         case TEXTURE_SOURCE_DECAL:
73                                 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
74                                 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
75                                 break;
76                         case TEXTURE_SOURCE_NO_FILTERING:
77                                 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
78                                 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
79                                 break;
80                         default:
81                                 break;
82                 }
83
84                 GL_bound_texture->texture_mode = ts;
85         }
86
87         GL_current_texture_source = ts;
88 }
89
90
91 void opengl1_tcache_init()
92 {
93         int i, idx, s_idx;
94
95         if ( os_config_read_uint("Video", "PreloadTextures", 1) ) {
96                 GL_should_preload = 1;
97         } else {
98                 GL_should_preload = 0;
99         }
100
101         Textures = (tcache_slot_opengl *)malloc(MAX_BITMAPS*sizeof(tcache_slot_opengl));
102         if ( !Textures )        {
103                 exit(1);
104         }
105
106         if (gr_screen.use_sections) {
107                 Texture_sections = (tcache_slot_opengl*)malloc(MAX_BITMAPS * MAX_BMAP_SECTIONS_X * MAX_BMAP_SECTIONS_Y * sizeof(tcache_slot_opengl));
108                 if(!Texture_sections){
109                         exit(1);
110                 }
111                 memset(Texture_sections, 0, MAX_BITMAPS * MAX_BMAP_SECTIONS_X * MAX_BMAP_SECTIONS_Y * sizeof(tcache_slot_opengl));
112         }
113
114         // Init the texture structures
115         int section_count = 0;
116         for( i=0; i<MAX_BITMAPS; i++ )  {
117                 Textures[i].texture_handle = 0;
118
119                 Textures[i].bitmap_id = -1;
120                 Textures[i].size = 0;
121                 Textures[i].used_this_frame = 0;
122
123                 Textures[i].parent = NULL;
124
125                 // allocate sections
126                 if (gr_screen.use_sections) {
127                         for(idx=0; idx<MAX_BMAP_SECTIONS_X; idx++){
128                                 for(s_idx=0; s_idx<MAX_BMAP_SECTIONS_Y; s_idx++){
129                                         Textures[i].data_sections[idx][s_idx] = &((tcache_slot_opengl*)Texture_sections)[section_count++];
130                                         Textures[i].data_sections[idx][s_idx]->parent = &Textures[i];
131                                         Textures[i].data_sections[idx][s_idx]->texture_handle = 0;
132                                         Textures[i].data_sections[idx][s_idx]->bitmap_id = -1;
133                                         Textures[i].data_sections[idx][s_idx]->size = 0;
134                                         Textures[i].data_sections[idx][s_idx]->used_this_frame = 0;
135                                 }
136                         }
137                 } else {
138                         for(idx=0; idx<MAX_BMAP_SECTIONS_X; idx++){
139                                 for(s_idx=0; s_idx<MAX_BMAP_SECTIONS_Y; s_idx++){
140                                         Textures[i].data_sections[idx][s_idx] = NULL;
141                                 }
142                         }
143                 }
144         }
145
146         GL_last_detail = Detail.hardware_textures;
147         GL_last_bitmap_id = -1;
148         GL_last_bitmap_type = -1;
149
150         GL_last_section_x = -1;
151         GL_last_section_y = -1;
152
153         memset(GL_xlat, 0, sizeof(GL_xlat));
154 }
155
156 static int opengl1_free_texture ( tcache_slot_opengl *t )
157 {
158         int idx, s_idx;
159
160
161         // Bitmap changed!!
162         if ( t->bitmap_id > -1 )        {
163                 // if I, or any of my children have been used this frame, bail
164                 if(t->used_this_frame == GL_frame_count){
165                         return 0;
166                 }
167
168                 if (gr_screen.use_sections) {
169                         for(idx=0; idx<MAX_BMAP_SECTIONS_X; idx++){
170                                 for(s_idx=0; s_idx<MAX_BMAP_SECTIONS_Y; s_idx++){
171                                         if((t->data_sections[idx][s_idx] != NULL) && (t->data_sections[idx][s_idx]->used_this_frame == GL_frame_count)){
172                                                 return 0;
173                                         }
174                                 }
175                         }
176                 }
177
178                 // ok, now we know its legal to free everything safely
179                 t->texture_mode = (gr_texture_source) -1;
180                 glDeleteTextures (1, &t->texture_handle);
181                 t->texture_handle = 0;
182
183                 if ( GL_last_bitmap_id == t->bitmap_id )       {
184                         GL_last_bitmap_id = -1;
185                 }
186
187                 // if this guy has children, free them too, since the children
188                 // actually make up his size
189                 if (gr_screen.use_sections) {
190                         for(idx=0; idx<MAX_BMAP_SECTIONS_X; idx++){
191                                 for(s_idx=0; s_idx<MAX_BMAP_SECTIONS_Y; s_idx++){
192                                         if(t->data_sections[idx][s_idx] != NULL){
193                                                 opengl1_free_texture(t->data_sections[idx][s_idx]);
194                                         }
195                                 }
196                         }
197                 }
198
199                 t->bitmap_id = -1;
200                 t->used_this_frame = 0;
201                 Gr_textures_in -= t->size;
202                 t->size = 0;
203         }
204
205         return 1;
206 }
207
208 void opengl1_tcache_flush()
209 {
210         int i;
211
212         if (Textures == NULL) {
213                 return;
214         }
215
216         for( i=0; i<MAX_BITMAPS; i++ )  {
217                 opengl1_free_texture ( &Textures[i] );
218         }
219         if (Gr_textures_in != 0) {
220                 mprintf(( "WARNING: VRAM is at %d instead of zero after flushing!\n", Gr_textures_in ));
221                 Gr_textures_in = 0;
222         }
223
224         GL_last_bitmap_id = -1;
225         GL_last_section_x = -1;
226         GL_last_section_y = -1;
227 }
228
229 void opengl1_tcache_cleanup()
230 {
231         opengl1_tcache_flush ();
232
233         if ( Textures ) {
234                 free(Textures);
235                 Textures = NULL;
236         }
237
238         if( Texture_sections != NULL ){
239                 free(Texture_sections);
240                 Texture_sections = NULL;
241         }
242 }
243
244 void opengl1_tcache_frame()
245 {
246         GL_last_bitmap_id = -1;
247
248         GL_frame_count++;
249
250         /*
251         int idx, s_idx;
252         int i;
253         for( i=0; i<MAX_BITMAPS; i++ )  {
254                 Textures[i].used_this_frame = 0;
255
256                 // data sections
257                 if(Textures[i].data_sections[0][0] != NULL){
258                         SDL_assert(GL_texture_sections);
259                         if(GL_texture_sections){
260                                 for(idx=0; idx<MAX_BMAP_SECTIONS_X; idx++){
261                                         for(s_idx=0; s_idx<MAX_BMAP_SECTIONS_Y; s_idx++){
262                                                 if(Textures[i].data_sections[idx][s_idx] != NULL){
263                                                         Textures[i].data_sections[idx][s_idx]->used_this_frame = 0;
264                                                 }
265                                         }
266                                 }
267                         }
268                 }
269         }
270         */
271
272         if ( vram_full )        {
273                 opengl1_tcache_flush();
274                 vram_full = 0;
275         }
276 }
277
278 static void opengl1_tcache_get_adjusted_texture_size(int w_in, int h_in, int *w_out, int *h_out)
279 {
280         int tex_w, tex_h;
281         int i;
282
283         // bogus
284         if((w_out == NULL) ||  (h_out == NULL)){
285                 return;
286         }
287
288         // starting size
289         tex_w = w_in;
290         tex_h = h_in;
291
292         // set height and width to a power of 2
293         for (i=0; i<16; i++ )   {
294                 if ( (tex_w > (1<<i)) && (tex_w <= (1<<(i+1))) )        {
295                         tex_w = 1 << (i+1);
296                         break;
297                 }
298         }
299
300         for (i=0; i<16; i++ )   {
301                 if ( (tex_h > (1<<i)) && (tex_h <= (1<<(i+1))) )        {
302                         tex_h = 1 << (i+1);
303                         break;
304                 }
305         }
306
307         // try to keep an 8:1 size ratio
308         if (tex_w/tex_h > 8)
309                 tex_h = tex_w/8;
310         if (tex_h/tex_w > 8)
311                 tex_w = tex_h/8;
312
313         if ( tex_w < GL_min_texture_width ) {
314                 tex_w = GL_min_texture_width;
315         } else if ( tex_w > GL_max_texture_width )     {
316                 tex_w = GL_max_texture_width;
317         }
318
319         if ( tex_h < GL_min_texture_height ) {
320                 tex_h = GL_min_texture_height;
321         } else if ( tex_h > GL_max_texture_height )    {
322                 tex_h = GL_max_texture_height;
323         }
324
325         // store the outgoing size
326         *w_out = tex_w;
327         *h_out = tex_h;
328 }
329
330 // bmp == bitmap structure with w, h, and data
331 // sx == x offset into bitmap
332 // sy == y offset into bitmap
333 // src_w == absolute width of section on source bitmap
334 // src_h == absolute height of section on source bitmap
335 // bmap_w == width of source bitmap
336 // bmap_h == height of source bitmap
337 // tex_w == width of final texture
338 // tex_h == height of final texture
339 static int opengl1_create_texture_sub(int bitmap_handle, int bitmap_type, bitmap *bmp, tcache_slot_opengl *t, int sx, int sy, int src_w, int src_h, int tex_w, int tex_h, bool reload, bool resize, int fail_on_full)
340 {
341         // bogus
342         if ( (bmp == NULL) || (t == NULL) ) {
343                 return 0;
344         }
345
346         if (t->used_this_frame == GL_frame_count) {
347                 mprintf(("ARGHH!!! Texture already used this frame! Cannot free it!\n"));
348                 return 0;
349         }
350
351         if ( !reload ) {
352                 if ( !opengl1_free_texture(t) ) {
353                         return 0;
354                 }
355
356                 glGenTextures(1, &t->texture_handle);
357
358                 if ( !t->texture_handle ) {
359                         nprintf(("Error", "!!DEBUG!! t->texture_handle == 0"));
360                         return 0;
361                 }
362         }
363
364         switch (bitmap_type) {
365                 case TCACHE_TYPE_AABITMAP:
366                         t->u_scale = (float)bmp->w / (float)tex_w;
367                         t->v_scale = (float)bmp->h / (float)tex_h;
368                         break;
369
370                 case TCACHE_TYPE_BITMAP_INTERFACE:
371                 case TCACHE_TYPE_BITMAP_SECTION:
372                         t->u_scale = (float)src_w / (float)tex_w;
373                         t->v_scale = (float)src_h / (float)tex_h;
374                         break;
375
376                 default:
377                         t->u_scale = 1.0f;
378                         t->v_scale = 1.0f;
379                         break;
380         }
381
382         t->texture_mode = TEXTURE_SOURCE_NO_FILTERING;
383
384         glBindTexture(GL_TEXTURE_2D, t->texture_handle);
385
386         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
387         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
388
389         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
390         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
391
392         glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
393
394         ubyte *bmp_data = (ubyte*)bmp->data;
395         ubyte *texmem = NULL, *texmemp;
396         int i, j;
397         int size = 0;
398
399         switch (bitmap_type) {
400                 case TCACHE_TYPE_AABITMAP: {
401                         texmem = (ubyte *) malloc(tex_w * tex_h);
402                         texmemp = texmem;
403
404                         for (i = 0; i < tex_h; i++) {
405                                 for (j = 0;j < tex_w; j++) {
406                                         if ( (i < bmp->h) && (j < bmp->w) ) {
407                                                 *texmemp++ = GL_xlat[bmp_data[i*bmp->w+j]];
408                                         } else {
409                                                 *texmemp++ = 0;
410                                         }
411                                 }
412                         }
413
414                         size = tex_w * tex_h;
415
416                         if (reload) {
417                                 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, tex_w, tex_h, GL_ALPHA, GL_UNSIGNED_BYTE, texmem);
418                         } else {
419                                 glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, tex_w, tex_h, 0, GL_ALPHA, GL_UNSIGNED_BYTE, texmem);
420                         }
421
422                         free (texmem);
423
424                         break;
425                 }
426
427                 case TCACHE_TYPE_BITMAP_INTERFACE:
428                 case TCACHE_TYPE_BITMAP_SECTION: {
429                         // if we aren't resizing in any way then we can just use bmp_data directly
430                         if (resize) {
431                                 texmem = (ubyte *) malloc(tex_w * tex_h * 2);
432                                 texmemp = texmem;
433
434                                 for (i = 0;i < tex_h; i++) {
435                                         for (j = 0; j < tex_w; j++) {
436                                                 if ( (i < src_h) && (j < src_w) ) {
437                                                         *texmemp++ = bmp_data[((i+sy)*bmp->w+(j+sx))*2+0];
438                                                         *texmemp++ = bmp_data[((i+sy)*bmp->w+(j+sx))*2+1];
439                                                 } else {
440                                                         *texmemp++ = 0;
441                                                         *texmemp++ = 0;
442                                                 }
443                                         }
444                                 }
445                         }
446
447                         size = tex_w * tex_h * 2;
448
449                         if (reload) {
450                                 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, tex_w, tex_h, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, (resize) ? texmem : bmp_data);
451                         } else {
452                                 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex_w, tex_h, 0, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, (resize) ? texmem : bmp_data);
453                         }
454
455                         if (texmem) {
456                                 free(texmem);
457                         }
458
459                         break;
460                 }
461
462                 default: {
463                         // if we aren't resizing then we can just use bmp_data directly
464                         if (resize) {
465                                 texmem = (ubyte *) malloc (tex_w * tex_h * 2);
466                                 texmemp = texmem;
467
468                                 SDL_assert(texmem);
469
470                                 fix u = 0, utmp, v = 0, du, dv;
471
472                                 du = ((bmp->w - 1) * F1_0) / tex_w;
473                                 dv = ((bmp->h - 1) * F1_0) / tex_h;
474
475                                 for (j = 0; j < tex_h; j++) {
476                                         utmp = u;
477
478                                         for (i = 0; i < tex_w; i++) {
479                                                 *texmemp++ = bmp_data[(f2i(v)*bmp->w+f2i(utmp))*2+0];
480                                                 *texmemp++ = bmp_data[(f2i(v)*bmp->w+f2i(utmp))*2+1];
481
482                                                 utmp += du;
483                                         }
484
485                                         v += dv;
486                                 }
487                         }
488
489                         size = tex_w * tex_h * 2;
490
491                         if (reload) {
492                                 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, tex_w, tex_h, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, (resize) ? texmem : bmp_data);
493                         } else {
494                                 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex_w, tex_h, 0, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, (resize) ? texmem : bmp_data);
495                         }
496
497                         if (texmem) {
498                                 free(texmem);
499                         }
500
501                         break;
502                 }
503         }
504
505         t->bitmap_id = bitmap_handle;
506         t->time_created = GL_frame_count;
507         t->used_this_frame = 0;
508         t->size = size;
509         t->w = (ushort)tex_w;
510         t->h = (ushort)tex_h;
511
512         if (!reload) {
513                 Gr_textures_in += t->size;
514         }
515
516         return 1;
517 }
518
519 static int opengl1_create_texture(int bitmap_handle, int bitmap_type, tcache_slot_opengl *tslot, int fail_on_full)
520 {
521         ubyte flags = 0;
522         int final_w, final_h;
523         ubyte bpp = 16;
524         bool resize = false;
525         bool cull_size = false;
526
527         // setup texture/bitmap flags
528         switch(bitmap_type){
529                 case TCACHE_TYPE_AABITMAP:
530                         flags |= BMP_AABITMAP;
531                         bpp = 8;
532                         break;
533                 case TCACHE_TYPE_NORMAL:
534                         flags |= BMP_TEX_OTHER;
535                         cull_size = true;
536                         break;
537                 case TCACHE_TYPE_BITMAP_INTERFACE:
538                 case TCACHE_TYPE_XPARENT:
539                         flags |= BMP_TEX_XPARENT;
540                         break;
541                 default:
542                         Int3();
543                         return 0;
544         }
545
546         // lock the bitmap into the proper format
547         bitmap *bmp = bm_lock(bitmap_handle, bpp, flags);
548         if ( bmp == NULL ) {
549                 mprintf(("Couldn't lock bitmap %d.\n", bitmap_handle ));
550                 return 0;
551         }
552
553         int max_w = bmp->w;
554         int max_h = bmp->h;
555
556         if ( cull_size && (Detail.hardware_textures < 4) ) {
557                 // if we are going to cull the size then we need to force a resize
558                 resize = true;
559
560                 // Detail.hardware_textures goes form 0 to 4
561                 int val = 16 >> Detail.hardware_textures;
562
563                 max_w /= val;
564                 max_h /= val;
565         }
566
567         // get final texture size as it will be allocated as a DD surface
568         opengl1_tcache_get_adjusted_texture_size(max_w, max_h, &final_w, &final_h);
569
570         if ( (final_w < 1) || (final_h < 1) ) {
571                 mprintf(("Bitmap is too small at %dx%d.\n", final_w, final_h));
572                 return 0;
573         }
574
575         // if we don't have to resize the image (to get power of 2, etc.) then skip that extra work
576         if ( (max_w != final_w) || (max_h != final_h) ) {
577                 resize = true;
578         }
579
580         bool reload = false;
581
582         // see if we can reuse this slot for a new bitmap
583         if ( tslot->texture_handle && (tslot->bitmap_id != bitmap_handle) ) {
584                 if ( (final_w == tslot->w) && (final_h == tslot->h) ) {
585                         reload = true;
586                 }
587         }
588
589         // call the helper
590         int ret_val = opengl1_create_texture_sub(bitmap_handle, bitmap_type, bmp, tslot, 0, 0, bmp->w, bmp->h, final_w, final_h, reload, resize, fail_on_full);
591
592         // unlock the bitmap
593         bm_unlock(bitmap_handle);
594
595         return ret_val;
596 }
597
598 static int opengl1_create_texture_sectioned(int bitmap_handle, int bitmap_type, tcache_slot_opengl *tslot, int sx, int sy, int fail_on_full)
599 {
600         int final_w, final_h;
601         int section_x, section_y;
602         bool resize = true;
603
604         SDL_assert( gr_screen.use_sections );
605
606         // setup texture/bitmap flags
607         SDL_assert(bitmap_type == TCACHE_TYPE_BITMAP_SECTION);
608         if(bitmap_type != TCACHE_TYPE_BITMAP_SECTION){
609                 bitmap_type = TCACHE_TYPE_BITMAP_SECTION;
610         }
611
612         // lock the bitmap in the proper format
613         bitmap *bmp = bm_lock(bitmap_handle, 16, BMP_TEX_XPARENT);
614         if ( bmp == NULL ) {
615                 mprintf(("Couldn't lock bitmap %d.\n", bitmap_handle ));
616                 return 0;
617         }
618         // determine the width and height of this section
619         bm_get_section_size(bitmap_handle, sx, sy, &section_x, &section_y);
620
621         // get final texture size as it will be allocated as an opengl texture
622         opengl1_tcache_get_adjusted_texture_size(section_x, section_y, &final_w, &final_h);
623
624         if ( (final_w < 1) || (final_h < 1) ) {
625                 mprintf(("Bitmap is too small at %dx%d.\n", final_w, final_h));
626                 return 0;
627         }
628
629         // if we don't have to resize the image (to get power of 2, etc.) then skip that extra work
630         if ( (bmp->sections.num_x == 1) && (bmp->sections.num_y == 1) && (section_x == final_w) && (section_y == final_h) ) {
631                 resize = false;
632         }
633
634         bool reload = false;
635
636         // see if we can reuse this slot for a new bitmap
637         if ( tslot->texture_handle && (tslot->bitmap_id != bitmap_handle) ) {
638                 if ( (final_w == tslot->w) && (final_h == tslot->h) ) {
639                         reload = true;
640                 }
641         }
642
643         // call the helper
644         int ret_val = opengl1_create_texture_sub(bitmap_handle, bitmap_type, bmp, tslot, bmp->sections.sx[sx], bmp->sections.sy[sy], section_x, section_y, final_w, final_h, reload, resize, fail_on_full);
645
646         // unlock the bitmap
647         bm_unlock(bitmap_handle);
648
649         return ret_val;
650 }
651
652 int opengl1_tcache_set(int bitmap_id, int bitmap_type, float *u_scale, float *v_scale, int fail_on_full, int sx, int sy, int force)
653 {
654         bitmap *bmp = NULL;
655
656         int idx, s_idx;
657         int ret_val = 1;
658
659         if (bitmap_id < 0)
660         {
661                 GL_last_bitmap_id = -1;
662                 return 0;
663         }
664
665         if ( GL_last_detail != Detail.hardware_textures )      {
666                 GL_last_detail = Detail.hardware_textures;
667                 opengl1_tcache_flush();
668         }
669
670         if (vram_full) {
671                 return 0;
672         }
673
674         int n = bm_get_cache_slot (bitmap_id, 1);
675         tcache_slot_opengl *t = &Textures[n];
676
677         if ( (GL_last_bitmap_id == bitmap_id) && (GL_last_bitmap_type==bitmap_type) && (t->bitmap_id == bitmap_id) && (GL_last_section_x == sx) && (GL_last_section_y == sy))       {
678                 t->used_this_frame = GL_frame_count;
679
680                 // mark all children as used
681                 if (gr_screen.use_sections) {
682                         for(idx=0; idx<MAX_BMAP_SECTIONS_X; idx++){
683                                 for(s_idx=0; s_idx<MAX_BMAP_SECTIONS_Y; s_idx++){
684                                         if(t->data_sections[idx][s_idx] != NULL){
685                                                 t->data_sections[idx][s_idx]->used_this_frame = GL_frame_count;
686                                         }
687                                 }
688                         }
689                 }
690
691                 *u_scale = t->u_scale;
692                 *v_scale = t->v_scale;
693                 return 1;
694         }
695
696         if (bitmap_type == TCACHE_TYPE_BITMAP_SECTION){
697                 SDL_assert( gr_screen.use_sections );
698                 SDL_assert((sx >= 0) && (sy >= 0) && (sx < MAX_BMAP_SECTIONS_X) && (sy < MAX_BMAP_SECTIONS_Y));
699                 if(!((sx >= 0) && (sy >= 0) && (sx < MAX_BMAP_SECTIONS_X) && (sy < MAX_BMAP_SECTIONS_Y))){
700                         return 0;
701                 }
702
703                 ret_val = 1;
704
705                 // if the texture sections haven't been created yet
706                 if((t->bitmap_id < 0) || (t->bitmap_id != bitmap_id)){
707
708                         // lock the bitmap in the proper format
709                         bmp = bm_lock(bitmap_id, 16, BMP_TEX_XPARENT);
710                         bm_unlock(bitmap_id);
711
712                         // now lets do something for each texture
713
714                         for(idx=0; idx<bmp->sections.num_x; idx++){
715                                 for(s_idx=0; s_idx<bmp->sections.num_y; s_idx++){
716                                         // hmm. i'd rather we didn't have to do it this way...
717                                         if(!opengl1_create_texture_sectioned(bitmap_id, bitmap_type, t->data_sections[idx][s_idx], idx, s_idx, fail_on_full)){
718                                                 ret_val = 0;
719                                         }
720
721                                         // not used this frame
722                                         t->data_sections[idx][s_idx]->used_this_frame = 0;
723                                 }
724                         }
725
726                         // zero out pretty much everything in the parent struct since he's just the root
727                         t->bitmap_id = bitmap_id;
728                         t->texture_handle = 0;
729                         t->time_created = t->data_sections[sx][sy]->time_created;
730                         t->used_this_frame = 0;
731                 }
732
733                 // argh. we failed to upload. free anything we can
734                 if(!ret_val){
735                         opengl1_free_texture(t);
736                 }
737                 // swap in the texture we want
738                 else {
739                         t = t->data_sections[sx][sy];
740                 }
741         }
742         // all other "normal" textures
743         else if((bitmap_id < 0) || (bitmap_id != t->bitmap_id)){
744                 ret_val = opengl1_create_texture( bitmap_id, bitmap_type, t, fail_on_full );
745         }
746
747         // everything went ok
748         if(ret_val && (t->texture_handle) && !vram_full){
749                 *u_scale = t->u_scale;
750                 *v_scale = t->v_scale;
751
752                 GL_bound_texture = t;
753
754                 glBindTexture (GL_TEXTURE_2D, t->texture_handle );
755
756                 GL_last_bitmap_id = t->bitmap_id;
757                 GL_last_bitmap_type = bitmap_type;
758                 GL_last_section_x = sx;
759                 GL_last_section_y = sy;
760
761                 t->used_this_frame = GL_frame_count;
762         }
763         // gah
764         else {
765                 GL_last_bitmap_id = -1;
766                 GL_last_bitmap_type = -1;
767
768                 GL_last_section_x = -1;
769                 GL_last_section_y = -1;
770
771                 GL_bound_texture = NULL;
772
773                 glBindTexture (GL_TEXTURE_2D, 0);       // test - DDOI
774                 return 0;
775         }
776
777         return 1;
778 }
779
780 void gr_opengl1_preload_init()
781 {
782         opengl1_tcache_flush();
783 }
784
785 int gr_opengl1_preload(int bitmap_num, int is_aabitmap)
786 {
787         if ( !GL_should_preload )      {
788                 return 0;
789         }
790
791         float u_scale, v_scale;
792         int retval;
793         int bitmap_type = TCACHE_TYPE_NORMAL;
794
795         if ( is_aabitmap )      {
796                 bitmap_type = TCACHE_TYPE_AABITMAP;
797         }
798
799         retval = opengl1_tcache_set(bitmap_num, bitmap_type, &u_scale, &v_scale, 1, -1, -1, 0 );
800
801         if ( !retval )  {
802                 mprintf(("Texture upload failed!\n" ));
803         }
804
805         return retval;
806 }
807
808 void gr_opengl1_set_gamma(float)
809 {
810         int i;
811
812         // set the alpha gamma settings (for fonts)
813         for (i = 0; i < 16; i++) {
814                 GL_xlat[i] = (ubyte)Gr_gamma_lookup[(i*255)/15];
815         }
816
817         GL_xlat[15] = GL_xlat[1];
818
819         // Flush any existing textures
820         opengl1_tcache_flush();
821 }
822
823 void gr_opengl1_release_texture(int handle)
824 {
825         for(int i=0; i<MAX_BITMAPS; i++ )  {
826                 if (Textures[i].bitmap_id == handle) {
827                         Textures[i].used_this_frame = 0; // this bmp doesn't even exist any longer...
828                         opengl1_free_texture( &Textures[i] );
829                 }
830         }
831 }