From 0993803006699c80371dcabd10caff0c7b048f76 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 6 Jan 2012 16:24:13 +0900 Subject: [PATCH] Add texture sub-image management. The planned uses are lightmaps and 2d icons. --- include/QF/GLSL/qf_textures.h | 21 ++- libs/video/renderer/glsl/glsl_textures.c | 208 ++++++++++++++++++++++- libs/video/targets/vid_common_glsl.c | 2 + 3 files changed, 228 insertions(+), 3 deletions(-) diff --git a/include/QF/GLSL/qf_textures.h b/include/QF/GLSL/qf_textures.h index bb5f7978e..e3eb1a4ef 100644 --- a/include/QF/GLSL/qf_textures.h +++ b/include/QF/GLSL/qf_textures.h @@ -31,13 +31,30 @@ #include "QF/qtypes.h" +typedef struct scrap_s scrap_t; +typedef struct subpic_s { + const scrap_t * const scrap; + const struct vrect_s * const rect; + const int tnum; ///< texture number + const int width; ///< requested width + const int height; ///< requested height + const float size; ///< size factor for tex coords (mult) +} subpic_t; + int GL_LoadQuakeTexture (const char *identifier, int width, int height, byte *data); int GL_LoadRGBTexture (const char *identifier, int width, int height, byte *data); void GL_ReleaseTexture (int tex); -int GL_LoadTexture (const char *identifier, int width, int height, byte *data, qboolean mipmap, qboolean alpha, int bytesperpixel); +void GL_TextureInit (void); -void GDT_Init (void); +scrap_t *GL_CreateScrap (int size, int format); +void GL_DestroyScrap (scrap_t *scrap); +subpic_t *GL_ScrapSubpic (scrap_t *scrap, int width, int height); //XXX slow! +void GL_SubpicDelete (subpic_t *subpic); //XXX slow! +void GL_SubpicUpdate (subpic_t *subpic, byte *data); + +int GL_LoadTexture (const char *identifier, int width, int height, byte *data, + qboolean mipmap, qboolean alpha, int bytesperpixel); #endif//__QF_GLSL_textures_h diff --git a/libs/video/renderer/glsl/glsl_textures.c b/libs/video/renderer/glsl/glsl_textures.c index 15bd9dab4..ac78a77af 100644 --- a/libs/video/renderer/glsl/glsl_textures.c +++ b/libs/video/renderer/glsl/glsl_textures.c @@ -39,12 +39,30 @@ static __attribute__ ((used)) const char rcsid[] = # include #endif -#include +#include + +#include "QF/mathlib.h" +#include "QF/sys.h" +#include "QF/vrect.h" #include "QF/GLSL/defines.h" #include "QF/GLSL/funcs.h" #include "QF/GLSL/qf_textures.h" +struct scrap_s { + GLuint tnum; + int size; // in pixels, for now, always square, power of 2 + int format; + int bpp; + vrect_t *free_rects; + vrect_t *rects; + struct scrap_s *next; +}; + +static scrap_t *scrap_list; + +static int max_tex_size; + int GL_LoadQuakeTexture (const char *identifier, int width, int height, byte *data) { @@ -87,3 +105,191 @@ GL_ReleaseTexture (int tex) GLuint tnum = tex; qfglDeleteTextures (1, &tnum); } + +void +GL_TextureInit (void) +{ + qfglGetIntegerv (GL_MAX_TEXTURE_SIZE, &max_tex_size); + Sys_MaskPrintf (SYS_GLSL, "max texture size: %d\n", max_tex_size); +} + +scrap_t * +GL_CreateScrap (int size, int format) +{ + int i; + int bpp; + scrap_t *scrap; + byte *data; + + for (i = 0; i < 16; i++) + if (size <= 1 << i) + break; + size = 1 << i; + size = min (size, max_tex_size); + switch (format) { + case GL_ALPHA: + case GL_LUMINANCE: + bpp = 1; + break; + case GL_LUMINANCE_ALPHA: + bpp = 2; + break; + case GL_RGB: + bpp = 3; + break; + case GL_RGBA: + bpp = 4; + break; + default: + Sys_Error ("GL_CreateScrap: Invalid texture format"); + } + scrap = malloc (sizeof (scrap_t)); + qfglGenTextures (1, &scrap->tnum); + scrap->size = size; + scrap->format = format; + scrap->bpp = bpp; + scrap->free_rects = VRect_New (0, 0, size, size); + scrap->rects = 0; + scrap->next = scrap_list; + scrap_list = scrap; + + data = calloc (1, size * size * bpp); + + qfglBindTexture (GL_TEXTURE_2D, scrap->tnum); + qfglTexImage2D (GL_TEXTURE_2D, 0, format, + size, size, 0, format, GL_UNSIGNED_BYTE, data); + qfglTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + qfglTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + qfglTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + qfglTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + qfglGenerateMipmap (GL_TEXTURE_2D); + free (data); + + return scrap; +} + +void +GL_DestroyScrap (scrap_t *scrap) +{ + scrap_t **s; + vrect_t *t; + + for (s = &scrap_list; *s; s = &(*s)->next) { + if (*s == scrap) { + *s = scrap->next; + break; + } + } + GL_ReleaseTexture (scrap->tnum); + while (scrap->free_rects) { + t = scrap->free_rects; + scrap->free_rects = t->next; + VRect_Delete (t); + } + while (scrap->rects) { + t = scrap->rects; + scrap->rects = t->next; + VRect_Delete (t); + } + free (scrap); +} + +subpic_t * +GL_ScrapSubpic (scrap_t *scrap, int width, int height) +{ + int i, w, h; + vrect_t **t, **best; + vrect_t *old, *frags, *rect; + subpic_t *subpic; + + for (i = 0; i < 16; i++) + if (width <= 1 << i) + break; + w = 1 << i; + for (i = 0; i < 16; i++) + if (height <= 1 << i) + break; + h = 1 << i; + + best = 0; + for (t = &scrap->free_rects; *t; t = &(*t)->next) { + if ((*t)->width < w || (*t)->height < h) + continue; // won't fit + if (!best) { + best = t; + continue; + } + if ((*t)->width <= (*best)->width || (*t)->height <= (*best)->height) + best = t; + } + if (!best) + return 0; // couldn't find a spot + old = *best; + *best = old->next; + rect = VRect_New (old->x, old->y, width, height); + frags = VRect_Difference (old, rect); + VRect_Delete (old); + if (frags) { + // old was bigger than the requested size + for (old = frags; old->next; old = old->next) + ; + old->next = scrap->free_rects; + scrap->free_rects = frags; + } + rect->next = scrap->rects; + scrap->rects = rect; + + subpic = malloc (sizeof (subpic_t)); + *((scrap_t **) &subpic->scrap) = scrap; + *((vrect_t **) &subpic->rect) = rect; + *((int *) &subpic->tnum) = scrap->tnum; + *((int *) &subpic->width) = width; + *((int *) &subpic->height) = height; + *((float *) &subpic->size) = scrap->size; + return subpic; +} + +void +GL_SubpicDelete (subpic_t *subpic) +{ + scrap_t *scrap = (scrap_t *) subpic->scrap; + vrect_t *rect = (vrect_t *) subpic->rect; + vrect_t *old, *merge; + vrect_t **t; + + free (subpic); + for (t = &scrap->rects; *t; t = &(*t)->next) + if (*t == rect) + break; + if (*t != rect) + Sys_Error ("GL_ScrapDelSubpic: broken subpic"); + *t = rect->next; + + do { + for (t = &scrap->free_rects; *t; t = &(*t)->next) { + merge = VRect_Merge (*t, rect); + if (merge) { + old = *t; + *t = (*t)->next; + VRect_Delete (old); + VRect_Delete (rect); + rect = merge; + break; + } + } + } while (merge); + rect->next = scrap->free_rects; + scrap->free_rects = rect; +} + +void +GL_SubpicUpdate (subpic_t *subpic, byte *data) +{ + scrap_t *scrap = (scrap_t *) subpic->scrap; + vrect_t *rect = (vrect_t *) subpic->rect; + + qfglBindTexture (GL_TEXTURE_2D, scrap->tnum); + qfglTexSubImage2D (GL_TEXTURE_2D, 0, rect->x, rect->y, + subpic->width, subpic->height, scrap->format, + GL_UNSIGNED_BYTE, data); +} diff --git a/libs/video/targets/vid_common_glsl.c b/libs/video/targets/vid_common_glsl.c index 3278824b1..7e3622be6 100644 --- a/libs/video/targets/vid_common_glsl.c +++ b/libs/video/targets/vid_common_glsl.c @@ -137,6 +137,8 @@ GL_Init_Common (void) GL_Common_Init_Cvars (); + GL_TextureInit (); + qfglClearColor (0, 0, 0, 0); qfglEnable (GL_TEXTURE_2D);