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