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