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;
36 gr_texture_source texture_mode;
39 static tcache_slot_opengl2 *Textures = NULL;
41 static tcache_slot_opengl2 *GL_bound_texture;
43 static int GL_frame_count = 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_should_preload = 0;
49 static ubyte GL_xlat[256] = { 0 };
51 extern int Gr_textures_in;
52 extern int bm_get_cache_slot( int bitmap_id, int separate_ani_frames );
54 extern bool Use_mipmaps;
57 void opengl2_set_texture_state(gr_texture_source ts)
59 if (ts == TEXTURE_SOURCE_NONE) {
60 GL_bound_texture = NULL;
62 glBindTexture(GL_TEXTURE_2D, 0);
63 opengl2_tcache_set(-1, -1, NULL, NULL, 0);
64 } else if (GL_bound_texture && GL_bound_texture->texture_mode != ts) {
66 case TEXTURE_SOURCE_DECAL:
67 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
68 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
71 case TEXTURE_SOURCE_NO_FILTERING: {
72 if (GL_bound_texture->is_mipmaped) {
73 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_LINEAR);
75 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
78 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
87 GL_bound_texture->texture_mode = ts;
91 void opengl2_tcache_init()
93 GL_should_preload = os_config_read_uint("Video", "PreloadTextures", 1);
95 Textures = (tcache_slot_opengl2 *) malloc(MAX_BITMAPS * sizeof(tcache_slot_opengl2));
97 if (Textures == NULL) {
101 SDL_assert(gr_screen.use_sections == 0);
105 for (int i = 0; i < MAX_BITMAPS; i++) {
106 Textures[i].bitmap_id = -1;
109 GL_last_detail = Detail.hardware_textures;
110 GL_last_bitmap_id = -1;
111 GL_last_bitmap_type = -1;
116 static int opengl2_free_texture(tcache_slot_opengl2 *t)
118 if (t->bitmap_id < 0) {
122 // if I have been used this frame, bail
123 if (t->used_this_frame == GL_frame_count) {
127 glDeleteTextures(1, &t->texture_handle);
129 if (GL_last_bitmap_id == t->bitmap_id) {
130 GL_last_bitmap_id = -1;
133 Gr_textures_in -= t->size;
135 t->texture_handle = 0;
137 t->used_this_frame = 0;
144 void opengl2_tcache_flush()
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"));
209 t->texture_mode = TEXTURE_SOURCE_NO_FILTERING;
211 glBindTexture(GL_TEXTURE_2D, t->texture_handle);
213 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
214 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
216 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
217 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
219 ubyte *bmp_data = (ubyte*)bmp->data;
220 ubyte *texmem = NULL, *texmemp;
224 switch (bitmap_type) {
225 case TCACHE_TYPE_AABITMAP: {
226 SDL_assert(tex_w == bmp->w);
227 SDL_assert(tex_h == bmp->h);
229 texmem = (ubyte *) malloc(tex_w * tex_h);
232 for (i = 0; i < tex_h; i++) {
233 for (j = 0; j < tex_w; j++) {
234 *texmemp++ = GL_xlat[bmp_data[i*bmp->w+j]];
238 size = tex_w * tex_h;
241 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, tex_w, tex_h, GL_ALPHA, GL_UNSIGNED_BYTE, texmem);
243 glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, tex_w, tex_h, 0, GL_ALPHA, GL_UNSIGNED_BYTE, texmem);
251 case TCACHE_TYPE_BITMAP_INTERFACE:
252 case TCACHE_TYPE_BITMAP_SECTION: {
253 size = tex_w * tex_h * 2;
256 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, tex_w, tex_h, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, bmp_data);
258 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex_w, tex_h, 0, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, bmp_data);
266 texmem = (ubyte *) malloc(tex_w * tex_h * 2);
271 fix u = 0, utmp, v = 0, du, dv;
273 du = ((bmp->w - 1) * F1_0) / tex_w;
274 dv = ((bmp->h - 1) * F1_0) / tex_h;
276 for (j = 0; j < tex_h; j++) {
279 for (i = 0; i < tex_w; i++) {
280 *texmemp++ = bmp_data[(f2i(v)*bmp->w+f2i(utmp))*2+0];
281 *texmemp++ = bmp_data[(f2i(v)*bmp->w+f2i(utmp))*2+1];
291 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, tex_w, tex_h, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, (resize) ? texmem : bmp_data);
293 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);
301 glGenerateMipmap(GL_TEXTURE_2D);
303 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_LINEAR);
306 size = fl2i(tex_w * tex_h * 2.0f * 1.3333333f);
308 size = tex_w * tex_h * 2;
315 t->bitmap_id = bitmap_handle;
316 t->time_created = GL_frame_count;
317 t->used_this_frame = 0;
319 t->w = (ushort)tex_w;
320 t->h = (ushort)tex_h;
323 Gr_textures_in += t->size;
329 static int opengl2_create_texture(int bitmap_handle, int bitmap_type, tcache_slot_opengl2 *tslot, int fail_on_full)
332 bool cull_size = false;
336 switch (bitmap_type) {
337 case TCACHE_TYPE_AABITMAP: {
338 flags |= BMP_AABITMAP;
344 case TCACHE_TYPE_NORMAL: {
345 flags |= BMP_TEX_OTHER;
351 case TCACHE_TYPE_BITMAP_INTERFACE:
352 case TCACHE_TYPE_XPARENT: {
353 flags |= BMP_TEX_XPARENT;
363 bitmap *bmp = bm_lock(bitmap_handle, bpp, flags);
366 mprintf(("Couldn't lock bitmap %d\n", bitmap_handle));
373 if ( cull_size && (Detail.hardware_textures < 4) ) {
374 // if we are going to cull the size then we need to force a resize
377 // Detail.hardware_textures goes form 0 to 4
378 int val = 16 >> Detail.hardware_textures;
384 if ( (max_w < 1) || (max_h < 1) ) {
385 mprintf(("Bitmap %d is too small at %dx%d\n", bitmap_handle, max_w, max_h));
391 // see if we can reuse this slot for a new bitmap
392 if ( tslot->texture_handle && (tslot->bitmap_id != bitmap_handle) ) {
393 if ( (max_w == tslot->w) && (max_h == tslot->h) ) {
399 int ret_val = opengl2_create_texture_sub(bitmap_handle, bitmap_type, bmp, tslot, max_w, max_h, reload, resize, fail_on_full);
402 bm_unlock(bitmap_handle);
407 int opengl2_tcache_set(int bitmap_id, int bitmap_type, float *u_scale, float *v_scale, int fail_on_full)
410 GL_last_bitmap_id = -1;
415 if (GL_last_detail != Detail.hardware_textures) {
416 opengl2_tcache_flush();
417 GL_last_detail = Detail.hardware_textures;
424 int n = bm_get_cache_slot(bitmap_id, 1);
425 tcache_slot_opengl2 *t = &Textures[n];
427 if ( (GL_last_bitmap_id == bitmap_id) && (GL_last_bitmap_type == bitmap_type) && (t->bitmap_id == bitmap_id) ) {
428 t->used_this_frame = GL_frame_count;
430 *u_scale = t->u_scale;
431 *v_scale = t->v_scale;
438 if (bitmap_id != t->bitmap_id) {
439 ret_val = opengl2_create_texture(bitmap_id, bitmap_type, t, fail_on_full);
442 if (ret_val && t->texture_handle && !vram_full) {
443 glBindTexture(GL_TEXTURE_2D, t->texture_handle);
445 *u_scale = t->u_scale;
446 *v_scale = t->v_scale;
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;
480 float u_scale, v_scale;
482 int retval = opengl2_tcache_set(bitmap_num, bitmap_type, &u_scale, &v_scale, 1);
485 mprintf(("Texture upload failed bit bitmap %d!\n", bitmap_num));
491 void gr_opengl2_set_gamma(float)
493 // set the alpha gamma settings (for fonts)
494 for (int i = 0; i < 16; i++) {
495 GL_xlat[i] = (ubyte)Gr_gamma_lookup[(i*255)/15];
498 GL_xlat[15] = GL_xlat[1];
500 // Flush any existing textures
501 opengl2_tcache_flush();
504 void gr_opengl2_release_texture(int handle)
506 for (int i = 0; i < MAX_BITMAPS; i++) {
507 tcache_slot_opengl2 *t = &Textures[i];
509 if (t->bitmap_id == handle) {
510 t->used_this_frame = 0;
511 opengl2_free_texture(t);