mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2025-01-31 05:00:35 +00:00
Add texture sub-image management.
The planned uses are lightmaps and 2d icons.
This commit is contained in:
parent
c25327f4ed
commit
0993803006
3 changed files with 228 additions and 3 deletions
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -137,6 +137,8 @@ GL_Init_Common (void)
|
|||
|
||||
GL_Common_Init_Cvars ();
|
||||
|
||||
GL_TextureInit ();
|
||||
|
||||
qfglClearColor (0, 0, 0, 0);
|
||||
|
||||
qfglEnable (GL_TEXTURE_2D);
|
||||
|
|
Loading…
Reference in a new issue