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 if (Textures == NULL) {
148 for (int i = 0; i < MAX_BITMAPS; i++) {
149 opengl2_free_texture(&Textures[i]);
152 if (Gr_textures_in != 0) {
153 mprintf(("WARNING: VRAM is at %d instead of zero after flushing!\n", Gr_textures_in));
157 GL_last_bitmap_id = -1;
162 void opengl2_tcache_cleanup()
164 opengl2_tcache_flush();
172 void opengl2_tcache_frame()
174 GL_last_bitmap_id = -1;
178 opengl2_tcache_flush();
183 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)
186 if ( (bmp == NULL) || (t == NULL) ) {
190 if (t->used_this_frame == GL_frame_count) {
191 mprintf(("ARGHH!!! Texture already used this frame! Cannot free it!\n"));
196 if ( !opengl2_free_texture(t) ) {
200 glGenTextures(1, &t->texture_handle);
202 if ( !t->texture_handle ) {
203 nprintf(("Error", "!!DEBUG!! t->texture_handle == 0"));
208 t->texture_mode = TEXTURE_SOURCE_NO_FILTERING;
210 glBindTexture(GL_TEXTURE_2D, t->texture_handle);
212 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
213 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
215 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
216 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
218 ubyte *bmp_data = (ubyte*)bmp->data;
219 ubyte *texmem = NULL, *texmemp;
223 switch (bitmap_type) {
224 case TCACHE_TYPE_AABITMAP: {
225 SDL_assert(tex_w == bmp->w);
226 SDL_assert(tex_h == bmp->h);
228 texmem = (ubyte *) malloc(tex_w * tex_h);
231 for (i = 0; i < tex_h; i++) {
232 for (j = 0; j < tex_w; j++) {
233 *texmemp++ = GL_xlat[bmp_data[i*bmp->w+j]];
237 size = tex_w * tex_h;
240 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, tex_w, tex_h, GL_ALPHA, GL_UNSIGNED_BYTE, texmem);
242 glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, tex_w, tex_h, 0, GL_ALPHA, GL_UNSIGNED_BYTE, texmem);
250 case TCACHE_TYPE_BITMAP_INTERFACE:
251 case TCACHE_TYPE_BITMAP_SECTION: {
252 size = tex_w * tex_h * 2;
255 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, tex_w, tex_h, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, bmp_data);
257 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex_w, tex_h, 0, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, bmp_data);
265 texmem = (ubyte *) malloc(tex_w * tex_h * 2);
270 fix u = 0, utmp, v = 0, du, dv;
272 du = ((bmp->w - 1) * F1_0) / tex_w;
273 dv = ((bmp->h - 1) * F1_0) / tex_h;
275 for (j = 0; j < tex_h; j++) {
278 for (i = 0; i < tex_w; i++) {
279 *texmemp++ = bmp_data[(f2i(v)*bmp->w+f2i(utmp))*2+0];
280 *texmemp++ = bmp_data[(f2i(v)*bmp->w+f2i(utmp))*2+1];
290 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, tex_w, tex_h, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, (resize) ? texmem : bmp_data);
292 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);
300 glGenerateMipmap(GL_TEXTURE_2D);
302 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_LINEAR);
305 size = fl2i(tex_w * tex_h * 2.0f * 1.3333333f);
307 size = tex_w * tex_h * 2;
314 t->bitmap_id = bitmap_handle;
315 t->time_created = GL_frame_count;
316 t->used_this_frame = 0;
318 t->w = (ushort)tex_w;
319 t->h = (ushort)tex_h;
322 Gr_textures_in += t->size;
328 static int opengl2_create_texture(int bitmap_handle, int bitmap_type, tcache_slot_opengl2 *tslot, int fail_on_full)
331 bool cull_size = false;
335 switch (bitmap_type) {
336 case TCACHE_TYPE_AABITMAP: {
337 flags |= BMP_AABITMAP;
343 case TCACHE_TYPE_NORMAL: {
344 flags |= BMP_TEX_OTHER;
350 case TCACHE_TYPE_BITMAP_INTERFACE:
351 case TCACHE_TYPE_XPARENT: {
352 flags |= BMP_TEX_XPARENT;
362 bitmap *bmp = bm_lock(bitmap_handle, bpp, flags);
365 mprintf(("Couldn't lock bitmap %d\n", bitmap_handle));
372 if ( cull_size && (Detail.hardware_textures < 4) ) {
373 // if we are going to cull the size then we need to force a resize
376 // Detail.hardware_textures goes form 0 to 4
377 int val = 16 >> Detail.hardware_textures;
383 if ( (max_w < 1) || (max_h < 1) ) {
384 mprintf(("Bitmap %d is too small at %dx%d\n", bitmap_handle, max_w, max_h));
390 // see if we can reuse this slot for a new bitmap
391 if ( tslot->texture_handle && (tslot->bitmap_id != bitmap_handle) ) {
392 if ( (max_w == tslot->w) && (max_h == tslot->h) ) {
398 int ret_val = opengl2_create_texture_sub(bitmap_handle, bitmap_type, bmp, tslot, max_w, max_h, reload, resize, fail_on_full);
401 bm_unlock(bitmap_handle);
406 int opengl2_tcache_set(int bitmap_id, int bitmap_type, int fail_on_full)
409 GL_last_bitmap_id = -1;
414 if (GL_last_detail != Detail.hardware_textures) {
415 opengl2_tcache_flush();
416 GL_last_detail = Detail.hardware_textures;
423 int n = bm_get_cache_slot(bitmap_id, 1);
424 tcache_slot_opengl2 *t = &Textures[n];
426 if ( (GL_last_bitmap_id == bitmap_id) && (GL_last_bitmap_type == bitmap_type) && (t->bitmap_id == bitmap_id) ) {
427 t->used_this_frame = GL_frame_count;
434 if (bitmap_id != t->bitmap_id) {
435 ret_val = opengl2_create_texture(bitmap_id, bitmap_type, t, fail_on_full);
438 if (ret_val && t->texture_handle && !vram_full) {
439 glBindTexture(GL_TEXTURE_2D, t->texture_handle);
441 GL_bound_texture = t;
443 GL_last_bitmap_id = t->bitmap_id;
444 GL_last_bitmap_type = bitmap_type;
446 t->used_this_frame = GL_frame_count;
448 GL_last_bitmap_id = -1;
449 GL_last_bitmap_type = -1;
451 GL_bound_texture = NULL;
453 glBindTexture(GL_TEXTURE_2D, 0);
461 void gr_opengl2_preload_init()
463 opengl2_tcache_flush();
466 int gr_opengl2_preload(int bitmap_num, int is_aabitmap)
468 if ( !GL_should_preload ) {
472 int bitmap_type = (is_aabitmap) ? TCACHE_TYPE_AABITMAP : TCACHE_TYPE_NORMAL;
474 int retval = opengl2_tcache_set(bitmap_num, bitmap_type, 1);
477 mprintf(("Texture upload failed bit bitmap %d!\n", bitmap_num));
483 void gr_opengl2_set_gamma(float)
485 // set the alpha gamma settings (for fonts)
486 for (int i = 0; i < 16; i++) {
487 GL_xlat[i] = (ubyte)Gr_gamma_lookup[(i*255)/15];
490 GL_xlat[15] = GL_xlat[1];
492 // Flush any existing textures
493 opengl2_tcache_flush();
496 void gr_opengl2_release_texture(int handle)
498 for (int i = 0; i < MAX_BITMAPS; i++) {
499 tcache_slot_opengl2 *t = &Textures[i];
501 if (t->bitmap_id == handle) {
502 t->used_this_frame = 0;
503 opengl2_free_texture(t);