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 );
53 void opengl2_set_texture_state(gr_texture_source ts)
55 if (ts == TEXTURE_SOURCE_NONE) {
56 GL_bound_texture = NULL;
58 glBindTexture(GL_TEXTURE_2D, 0);
59 opengl2_tcache_set(-1, -1);
60 } else if (GL_bound_texture && GL_bound_texture->texture_mode != ts) {
62 case TEXTURE_SOURCE_DECAL:
63 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
64 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
67 case TEXTURE_SOURCE_NO_FILTERING: {
68 if (GL_bound_texture->is_mipmaped) {
69 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_LINEAR);
71 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
74 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
83 GL_bound_texture->texture_mode = ts;
87 void opengl2_tcache_init()
89 GL_should_preload = os_config_read_uint("Video", "PreloadTextures", 1);
91 Textures = (tcache_slot_opengl2 *) malloc(MAX_BITMAPS * sizeof(tcache_slot_opengl2));
93 if (Textures == NULL) {
97 SDL_assert(gr_screen.use_sections == 0);
99 memset(Textures, 0, MAX_BITMAPS * sizeof(tcache_slot_opengl2));
101 for (int i = 0; i < MAX_BITMAPS; i++) {
102 Textures[i].bitmap_id = -1;
105 GL_last_detail = Detail.hardware_textures;
106 GL_last_bitmap_id = -1;
107 GL_last_bitmap_type = -1;
112 static int opengl2_free_texture(tcache_slot_opengl2 *t)
114 if (t->bitmap_id < 0) {
118 // if I have been used this frame, bail
119 if (t->used_this_frame == GL_frame_count) {
123 glDeleteTextures(1, &t->texture_handle);
125 if (GL_last_bitmap_id == t->bitmap_id) {
126 GL_last_bitmap_id = -1;
129 Gr_textures_in -= t->size;
131 t->texture_handle = 0;
133 t->used_this_frame = 0;
140 void opengl2_tcache_flush()
142 if (Textures == NULL) {
146 for (int i = 0; i < MAX_BITMAPS; i++) {
147 opengl2_free_texture(&Textures[i]);
150 if (Gr_textures_in != 0) {
151 mprintf(("WARNING: VRAM is at %d instead of zero after flushing!\n", Gr_textures_in));
155 GL_last_bitmap_id = -1;
160 void opengl2_tcache_cleanup()
162 opengl2_tcache_flush();
170 void opengl2_tcache_frame()
172 GL_last_bitmap_id = -1;
176 opengl2_tcache_flush();
181 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)
184 if ( (bmp == NULL) || (t == NULL) ) {
188 if (t->used_this_frame == GL_frame_count) {
189 mprintf(("ARGHH!!! Texture already used this frame! Cannot free it!\n"));
194 if ( !opengl2_free_texture(t) ) {
198 glGenTextures(1, &t->texture_handle);
200 if ( !t->texture_handle ) {
201 nprintf(("Error", "!!DEBUG!! t->texture_handle == 0"));
206 t->texture_mode = TEXTURE_SOURCE_NO_FILTERING;
208 glBindTexture(GL_TEXTURE_2D, t->texture_handle);
210 GLint wrap_mode = GL_CLAMP_TO_EDGE;
212 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
213 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
215 ubyte *bmp_data = (ubyte*)bmp->data;
216 ubyte *texmem = NULL, *texmemp;
220 switch (bitmap_type) {
221 case TCACHE_TYPE_AABITMAP: {
222 SDL_assert(tex_w == bmp->w);
223 SDL_assert(tex_h == bmp->h);
225 texmem = (ubyte *) malloc(tex_w * tex_h);
228 for (i = 0; i < tex_h; i++) {
229 for (j = 0; j < tex_w; j++) {
230 *texmemp++ = GL_xlat[bmp_data[i*bmp->w+j]];
234 size = tex_w * tex_h;
237 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, tex_w, tex_h, GL_ALPHA, GL_UNSIGNED_BYTE, texmem);
239 glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, tex_w, tex_h, 0, GL_ALPHA, GL_UNSIGNED_BYTE, texmem);
247 case TCACHE_TYPE_BITMAP_INTERFACE:
248 case TCACHE_TYPE_BITMAP_SECTION: {
249 size = tex_w * tex_h * 2;
252 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, tex_w, tex_h, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, bmp_data);
254 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex_w, tex_h, 0, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, bmp_data);
261 wrap_mode = GL_REPEAT;
264 texmem = (ubyte *) malloc(tex_w * tex_h * 2);
269 fix u = 0, utmp, v = 0, du, dv;
271 du = ((bmp->w - 1) * F1_0) / tex_w;
272 dv = ((bmp->h - 1) * F1_0) / tex_h;
274 for (j = 0; j < tex_h; j++) {
277 for (i = 0; i < tex_w; i++) {
278 *texmemp++ = bmp_data[(f2i(v)*bmp->w+f2i(utmp))*2+0];
279 *texmemp++ = bmp_data[(f2i(v)*bmp->w+f2i(utmp))*2+1];
289 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, tex_w, tex_h, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, (resize) ? texmem : bmp_data);
291 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);
298 glGenerateMipmap(GL_TEXTURE_2D);
300 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_LINEAR);
303 size = fl2i(tex_w * tex_h * 2.0f * 1.3333333f);
309 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrap_mode);
310 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrap_mode);
312 t->bitmap_id = bitmap_handle;
313 t->time_created = GL_frame_count;
314 t->used_this_frame = 0;
316 t->w = (ushort)tex_w;
317 t->h = (ushort)tex_h;
320 Gr_textures_in += t->size;
326 static int opengl2_create_texture(int bitmap_handle, int bitmap_type, tcache_slot_opengl2 *tslot, int fail_on_full)
329 bool cull_size = false;
333 switch (bitmap_type) {
334 case TCACHE_TYPE_AABITMAP: {
335 flags |= BMP_AABITMAP;
341 case TCACHE_TYPE_NORMAL: {
342 flags |= BMP_TEX_OTHER;
348 case TCACHE_TYPE_BITMAP_INTERFACE:
349 case TCACHE_TYPE_XPARENT: {
350 flags |= BMP_TEX_XPARENT;
360 bitmap *bmp = bm_lock(bitmap_handle, bpp, flags);
363 mprintf(("Couldn't lock bitmap %d\n", bitmap_handle));
370 if ( cull_size && (Detail.hardware_textures < 4) ) {
371 // if we are going to cull the size then we need to force a resize
374 // Detail.hardware_textures goes form 0 to 4
375 int val = 16 >> Detail.hardware_textures;
381 if ( (bitmap_type == TCACHE_TYPE_NORMAL) || (bitmap_type == TCACHE_TYPE_XPARENT) ) {
382 if ( !is_pow2(max_w) || !is_pow2(max_h) ) {
385 max_w = next_pow2(max_w);
386 max_h = next_pow2(max_h);
390 if ( (max_w < 1) || (max_h < 1) ) {
391 mprintf(("Bitmap %d is too small at %dx%d\n", bitmap_handle, max_w, max_h));
397 // see if we can reuse this slot for a new bitmap
398 if ( tslot->texture_handle && (tslot->bitmap_id != bitmap_handle) ) {
399 if ( (max_w == tslot->w) && (max_h == tslot->h) ) {
405 int ret_val = opengl2_create_texture_sub(bitmap_handle, bitmap_type, bmp, tslot, max_w, max_h, reload, resize, fail_on_full);
408 bm_unlock(bitmap_handle);
413 int opengl2_tcache_set(int bitmap_id, int bitmap_type, int fail_on_full)
416 GL_last_bitmap_id = -1;
421 if (GL_last_detail != Detail.hardware_textures) {
422 opengl2_tcache_flush();
423 GL_last_detail = Detail.hardware_textures;
430 int n = bm_get_cache_slot(bitmap_id, 1);
431 tcache_slot_opengl2 *t = &Textures[n];
433 if ( (GL_last_bitmap_id == bitmap_id) && (GL_last_bitmap_type == bitmap_type) && (t->bitmap_id == bitmap_id) ) {
434 t->used_this_frame = GL_frame_count;
441 if (bitmap_id != t->bitmap_id) {
442 ret_val = opengl2_create_texture(bitmap_id, bitmap_type, t, fail_on_full);
445 if (ret_val && t->texture_handle && !vram_full) {
446 glBindTexture(GL_TEXTURE_2D, t->texture_handle);
448 GL_bound_texture = t;
450 GL_last_bitmap_id = t->bitmap_id;
451 GL_last_bitmap_type = bitmap_type;
453 t->used_this_frame = GL_frame_count;
455 GL_last_bitmap_id = -1;
456 GL_last_bitmap_type = -1;
458 GL_bound_texture = NULL;
460 glBindTexture(GL_TEXTURE_2D, 0);
468 void gr_opengl2_preload_init()
470 opengl2_tcache_flush();
473 int gr_opengl2_preload(int bitmap_num, int is_aabitmap)
475 if ( !GL_should_preload ) {
479 int bitmap_type = (is_aabitmap) ? TCACHE_TYPE_AABITMAP : TCACHE_TYPE_NORMAL;
481 int retval = opengl2_tcache_set(bitmap_num, bitmap_type, 1);
484 mprintf(("Texture upload failed bit bitmap %d!\n", bitmap_num));
490 void gr_opengl2_set_gamma(float)
492 // set the alpha gamma settings (for fonts)
493 for (int i = 0; i < 16; i++) {
494 GL_xlat[i] = (ubyte)Gr_gamma_lookup[(i*255)/15];
497 GL_xlat[15] = GL_xlat[1];
499 // Flush any existing textures
500 opengl2_tcache_flush();
503 void gr_opengl2_release_texture(int handle)
505 for (int i = 0; i < MAX_BITMAPS; i++) {
506 tcache_slot_opengl2 *t = &Textures[i];
508 if (t->bitmap_id == handle) {
509 t->used_this_frame = 0;
510 opengl2_free_texture(t);