2 * Copyright (C) Volition, Inc. 1999. All rights reserved.
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
9 #include "SDL_opengles2.h"
14 #include "gropenglinternal.h"
17 #include "grinternal.h"
18 #include "systemvars.h"
19 #include "osregistry.h"
22 static bool vram_full = false;
24 struct tcache_slot_opengl2 {
25 GLuint texture_handle;
34 gr_texture_source texture_mode;
37 static tcache_slot_opengl2 *Textures = NULL;
39 static tcache_slot_opengl2 *GL_bound_texture;
41 static int GL_frame_count = 0;
42 static int GL_last_bitmap_id = -1;
43 static int GL_last_detail = -1;
44 static int GL_last_bitmap_type = -1;
45 static int GL_should_preload = 0;
47 static ubyte GL_xlat[256] = { 0 };
49 extern int Gr_textures_in;
50 extern int bm_get_cache_slot( int bitmap_id, int separate_ani_frames );
52 extern bool Use_mipmaps;
55 void opengl2_set_texture_state(gr_texture_source ts)
57 if (ts == TEXTURE_SOURCE_NONE) {
58 GL_bound_texture = NULL;
60 glBindTexture(GL_TEXTURE_2D, 0);
61 opengl2_tcache_set(-1, -1);
62 } else if (GL_bound_texture && GL_bound_texture->texture_mode != ts) {
64 case TEXTURE_SOURCE_DECAL:
65 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
66 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
69 case TEXTURE_SOURCE_NO_FILTERING: {
70 if (GL_bound_texture->is_mipmaped) {
71 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_LINEAR);
73 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
76 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
85 GL_bound_texture->texture_mode = ts;
89 void opengl2_tcache_init()
91 GL_should_preload = os_config_read_uint("Video", "PreloadTextures", 1);
93 Textures = (tcache_slot_opengl2 *) malloc(MAX_BITMAPS * sizeof(tcache_slot_opengl2));
95 if (Textures == NULL) {
99 SDL_assert(gr_screen.use_sections == 0);
103 for (int i = 0; i < MAX_BITMAPS; i++) {
104 Textures[i].bitmap_id = -1;
107 GL_last_detail = Detail.hardware_textures;
108 GL_last_bitmap_id = -1;
109 GL_last_bitmap_type = -1;
114 static int opengl2_free_texture(tcache_slot_opengl2 *t)
116 if (t->bitmap_id < 0) {
120 // if I have been used this frame, bail
121 if (t->used_this_frame == GL_frame_count) {
125 glDeleteTextures(1, &t->texture_handle);
127 if (GL_last_bitmap_id == t->bitmap_id) {
128 GL_last_bitmap_id = -1;
131 Gr_textures_in -= t->size;
133 t->texture_handle = 0;
135 t->used_this_frame = 0;
142 void opengl2_tcache_flush()
144 for (int i = 0; i < MAX_BITMAPS; i++) {
145 opengl2_free_texture(&Textures[i]);
148 if (Gr_textures_in != 0) {
149 mprintf(("WARNING: VRAM is at %d instead of zero after flushing!\n", Gr_textures_in));
153 GL_last_bitmap_id = -1;
158 void opengl2_tcache_cleanup()
160 opengl2_tcache_flush();
168 void opengl2_tcache_frame()
170 GL_last_bitmap_id = -1;
174 opengl2_tcache_flush();
179 static int opengl2_create_texture_sub(int bitmap_handle, int bitmap_type, bitmap *bmp, tcache_slot_opengl2 *t, int tex_w, int tex_h, bool reload, bool resize, int fail_on_full)
182 if ( (bmp == NULL) || (t == NULL) ) {
186 if (t->used_this_frame == GL_frame_count) {
187 mprintf(("ARGHH!!! Texture already used this frame! Cannot free it!\n"));
192 if ( !opengl2_free_texture(t) ) {
196 glGenTextures(1, &t->texture_handle);
198 if ( !t->texture_handle ) {
199 nprintf(("Error", "!!DEBUG!! t->texture_handle == 0"));
204 t->texture_mode = TEXTURE_SOURCE_NO_FILTERING;
206 glBindTexture(GL_TEXTURE_2D, t->texture_handle);
208 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
209 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
211 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
212 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
214 ubyte *bmp_data = (ubyte*)bmp->data;
215 ubyte *texmem = NULL, *texmemp;
219 switch (bitmap_type) {
220 case TCACHE_TYPE_AABITMAP: {
221 SDL_assert(tex_w == bmp->w);
222 SDL_assert(tex_h == bmp->h);
224 texmem = (ubyte *) malloc(tex_w * tex_h);
227 for (i = 0; i < tex_h; i++) {
228 for (j = 0; j < tex_w; j++) {
229 *texmemp++ = GL_xlat[bmp_data[i*bmp->w+j]];
233 size = tex_w * tex_h;
236 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, tex_w, tex_h, GL_ALPHA, GL_UNSIGNED_BYTE, texmem);
238 glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, tex_w, tex_h, 0, GL_ALPHA, GL_UNSIGNED_BYTE, texmem);
246 case TCACHE_TYPE_BITMAP_INTERFACE:
247 case TCACHE_TYPE_BITMAP_SECTION: {
248 size = tex_w * tex_h * 2;
251 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, tex_w, tex_h, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, bmp_data);
253 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex_w, tex_h, 0, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, bmp_data);
261 texmem = (ubyte *) malloc(tex_w * tex_h * 2);
266 fix u = 0, utmp, v = 0, du, dv;
268 du = ((bmp->w - 1) * F1_0) / tex_w;
269 dv = ((bmp->h - 1) * F1_0) / tex_h;
271 for (j = 0; j < tex_h; j++) {
274 for (i = 0; i < tex_w; i++) {
275 *texmemp++ = bmp_data[(f2i(v)*bmp->w+f2i(utmp))*2+0];
276 *texmemp++ = bmp_data[(f2i(v)*bmp->w+f2i(utmp))*2+1];
286 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, tex_w, tex_h, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, (resize) ? texmem : bmp_data);
288 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);
296 glGenerateMipmap(GL_TEXTURE_2D);
298 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_LINEAR);
301 size = fl2i(tex_w * tex_h * 2.0f * 1.3333333f);
303 size = tex_w * tex_h * 2;
310 t->bitmap_id = bitmap_handle;
311 t->time_created = GL_frame_count;
312 t->used_this_frame = 0;
314 t->w = (ushort)tex_w;
315 t->h = (ushort)tex_h;
318 Gr_textures_in += t->size;
324 static int opengl2_create_texture(int bitmap_handle, int bitmap_type, tcache_slot_opengl2 *tslot, int fail_on_full)
327 bool cull_size = false;
331 switch (bitmap_type) {
332 case TCACHE_TYPE_AABITMAP: {
333 flags |= BMP_AABITMAP;
339 case TCACHE_TYPE_NORMAL: {
340 flags |= BMP_TEX_OTHER;
346 case TCACHE_TYPE_BITMAP_INTERFACE:
347 case TCACHE_TYPE_XPARENT: {
348 flags |= BMP_TEX_XPARENT;
358 bitmap *bmp = bm_lock(bitmap_handle, bpp, flags);
361 mprintf(("Couldn't lock bitmap %d\n", bitmap_handle));
368 if ( cull_size && (Detail.hardware_textures < 4) ) {
369 // if we are going to cull the size then we need to force a resize
372 // Detail.hardware_textures goes form 0 to 4
373 int val = 16 >> Detail.hardware_textures;
379 if ( (max_w < 1) || (max_h < 1) ) {
380 mprintf(("Bitmap %d is too small at %dx%d\n", bitmap_handle, max_w, max_h));
386 // see if we can reuse this slot for a new bitmap
387 if ( tslot->texture_handle && (tslot->bitmap_id != bitmap_handle) ) {
388 if ( (max_w == tslot->w) && (max_h == tslot->h) ) {
394 int ret_val = opengl2_create_texture_sub(bitmap_handle, bitmap_type, bmp, tslot, max_w, max_h, reload, resize, fail_on_full);
397 bm_unlock(bitmap_handle);
402 int opengl2_tcache_set(int bitmap_id, int bitmap_type, int fail_on_full)
405 GL_last_bitmap_id = -1;
410 if (GL_last_detail != Detail.hardware_textures) {
411 opengl2_tcache_flush();
412 GL_last_detail = Detail.hardware_textures;
419 int n = bm_get_cache_slot(bitmap_id, 1);
420 tcache_slot_opengl2 *t = &Textures[n];
422 if ( (GL_last_bitmap_id == bitmap_id) && (GL_last_bitmap_type == bitmap_type) && (t->bitmap_id == bitmap_id) ) {
423 t->used_this_frame = GL_frame_count;
430 if (bitmap_id != t->bitmap_id) {
431 ret_val = opengl2_create_texture(bitmap_id, bitmap_type, t, fail_on_full);
434 if (ret_val && t->texture_handle && !vram_full) {
435 glBindTexture(GL_TEXTURE_2D, t->texture_handle);
437 GL_bound_texture = t;
439 GL_last_bitmap_id = t->bitmap_id;
440 GL_last_bitmap_type = bitmap_type;
442 t->used_this_frame = GL_frame_count;
444 GL_last_bitmap_id = -1;
445 GL_last_bitmap_type = -1;
447 GL_bound_texture = NULL;
449 glBindTexture(GL_TEXTURE_2D, 0);
457 void gr_opengl2_preload_init()
459 opengl2_tcache_flush();
462 int gr_opengl2_preload(int bitmap_num, int is_aabitmap)
464 if ( !GL_should_preload ) {
468 int bitmap_type = (is_aabitmap) ? TCACHE_TYPE_AABITMAP : TCACHE_TYPE_NORMAL;
470 int retval = opengl2_tcache_set(bitmap_num, bitmap_type, 1);
473 mprintf(("Texture upload failed bit bitmap %d!\n", bitmap_num));
479 void gr_opengl2_set_gamma(float)
481 // set the alpha gamma settings (for fonts)
482 for (int i = 0; i < 16; i++) {
483 GL_xlat[i] = (ubyte)Gr_gamma_lookup[(i*255)/15];
486 GL_xlat[15] = GL_xlat[1];
488 // Flush any existing textures
489 opengl2_tcache_flush();
492 void gr_opengl2_release_texture(int handle)
494 for (int i = 0; i < MAX_BITMAPS; i++) {
495 tcache_slot_opengl2 *t = &Textures[i];
497 if (t->bitmap_id == handle) {
498 t->used_this_frame = 0;
499 opengl2_free_texture(t);