Add texture sub-image management.

The planned uses are lightmaps and 2d icons.
This commit is contained in:
Bill Currie 2012-01-06 16:24:13 +09:00
parent c25327f4ed
commit 0993803006
3 changed files with 228 additions and 3 deletions

View file

@ -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

View file

@ -39,12 +39,30 @@ static __attribute__ ((used)) const char rcsid[] =
# include <strings.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#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);
}

View file

@ -137,6 +137,8 @@ GL_Init_Common (void)
GL_Common_Init_Cvars ();
GL_TextureInit ();
qfglClearColor (0, 0, 0, 0);
qfglEnable (GL_TEXTURE_2D);