mirror of
https://github.com/yquake2/yquake2
synced 2026-08-20 00:26:04 -04:00
GL3: Port scrap texture from GL1
so small 2D (UI) textures are merged into one texture, which allows reducing draw calls even further (theoretically all HUD drawcalls can be merged into one now, in practice it seems to be 2 or 3 - good enough) OpenGL3 guarantees that 1024x1024 textures are supported (GLES3 even 2048x2048) so I increased the scrap size to 1024x1024 and increased the limit for "small" textures that go there to 128x128
This commit is contained in:
parent
c9eb2b96dc
commit
afee6e3c37
4 changed files with 166 additions and 106 deletions
|
|
@ -115,6 +115,9 @@ GL3_DrawCurrent2Dbatch()
|
|||
if(numVtx == 0)
|
||||
return;
|
||||
|
||||
if(gl3_scrap_dirty)
|
||||
GL3_Scrap_Upload();
|
||||
|
||||
GL3_UseProgram(gl3state.si2D.shaderProgram);
|
||||
GL3_Bind(lastBatchTexture);
|
||||
|
||||
|
|
@ -193,6 +196,9 @@ drawTexturedRectangleNow(float x, float y, float w, float h,
|
|||
// to preserve draw order
|
||||
GL3_DrawCurrent2Dbatch();
|
||||
|
||||
if (gl3_scrap_dirty)
|
||||
GL3_Scrap_Upload();
|
||||
|
||||
gl3_drawVert2D vBuf[4] = {
|
||||
// X, Y, S, T
|
||||
{ x, y+h, sl, th },
|
||||
|
|
@ -320,6 +326,9 @@ GL3_Draw_PicScaledCol(int x, int y, const char *pic, float factor, const float c
|
|||
return;
|
||||
}
|
||||
|
||||
if (gl3_scrap_dirty)
|
||||
GL3_Scrap_Upload();
|
||||
|
||||
gl3state.uniCommonData.color = HMM_Vec4(color[0], color[1], color[2], 1.0f);
|
||||
GL3_UpdateUBOCommon();
|
||||
|
||||
|
|
|
|||
|
|
@ -49,6 +49,74 @@ gl3image_t gl3textures[MAX_GL3TEXTURES];
|
|||
int numgl3textures = 0;
|
||||
static int image_max = 0;
|
||||
|
||||
enum {
|
||||
SCRAP_WIDTH = 1024,
|
||||
SCRAP_HEIGHT = 1024
|
||||
};
|
||||
|
||||
static int scrap_allocated[SCRAP_WIDTH]; // FIXME: why not short
|
||||
static GLuint gl3_scrap_texnum = 0;
|
||||
static byte scrap_texels[SCRAP_WIDTH * SCRAP_HEIGHT]; // FIXME: [4] ?
|
||||
qboolean gl3_scrap_dirty = false;
|
||||
|
||||
void
|
||||
GL3_Scrap_Init(void)
|
||||
{
|
||||
memset (scrap_allocated, 0, sizeof(scrap_allocated)); // empty
|
||||
memset (scrap_texels, 255, sizeof(scrap_texels)); // transparent
|
||||
|
||||
glGenTextures(1, &gl3_scrap_texnum);
|
||||
}
|
||||
|
||||
/* returns a texture number (relative to g3_scrap_texnum) and the position inside it */
|
||||
static int
|
||||
GL3_Scrap_AllocBlock(int w, int h, int *x, int *y)
|
||||
{
|
||||
w += 2; // add an empty border to all sides
|
||||
h += 2;
|
||||
|
||||
int best = SCRAP_HEIGHT;
|
||||
|
||||
for (int i = 0; i < SCRAP_WIDTH - w; i++)
|
||||
{
|
||||
int j;
|
||||
int best2 = 0;
|
||||
|
||||
for (j = 0; j < w; j++)
|
||||
{
|
||||
if (scrap_allocated[i + j] >= best)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (scrap_allocated[i + j] > best2)
|
||||
{
|
||||
best2 = scrap_allocated[i + j];
|
||||
}
|
||||
}
|
||||
|
||||
if (j == w)
|
||||
{ /* this is a valid spot */
|
||||
*x = i;
|
||||
*y = best = best2;
|
||||
}
|
||||
}
|
||||
|
||||
if (best + h > SCRAP_HEIGHT)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (int i = 0; i < w; i++)
|
||||
{
|
||||
scrap_allocated[*x + i] = best + h;
|
||||
}
|
||||
(*x)++; // jump the border
|
||||
(*y)++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
GL3_TextureMode(char *string)
|
||||
{
|
||||
|
|
@ -254,6 +322,29 @@ GL3_Upload8(const byte *data, size_t width, size_t height, qboolean mipmap)
|
|||
return ret;
|
||||
}
|
||||
|
||||
void
|
||||
GL3_Scrap_Upload(void)
|
||||
{
|
||||
GL3_Bind(gl3_scrap_texnum);
|
||||
|
||||
GL3_Upload8(scrap_texels, SCRAP_WIDTH, SCRAP_HEIGHT, false);
|
||||
if (r_2D_unfiltered->value != 0)
|
||||
{
|
||||
// 2D textures shouldn't be filtered by default (r_2D_unfiltered),
|
||||
// so the scrap shouldn't be filtered
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
}
|
||||
else // 2D textures should be filtered by default => filter the scrap
|
||||
{
|
||||
// we can't use gl_filter_min which might be GL_*_MIPMAP_*
|
||||
// also, there's no anisotropic filtering for textures w/o mipmaps
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_max);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max);
|
||||
}
|
||||
gl3_scrap_dirty = false;
|
||||
}
|
||||
|
||||
/*
|
||||
* This is also used as an entry point for the generated r_notexture
|
||||
*/
|
||||
|
|
@ -267,7 +358,8 @@ GL3_LoadPic(char *name, byte *pic, int width, int realwidth,
|
|||
int i;
|
||||
|
||||
qboolean nolerp = false;
|
||||
if (r_2D_unfiltered->value && type == it_pic)
|
||||
qboolean default2Dnolerp = r_2D_unfiltered->value != 0.0f;
|
||||
if (default2Dnolerp && type == it_pic)
|
||||
{
|
||||
// if r_2D_unfiltered is true(ish), nolerp should usually be true,
|
||||
// *unless* the texture is on the r_lerp_list
|
||||
|
|
@ -351,140 +443,91 @@ GL3_LoadPic(char *name, byte *pic, int width, int realwidth,
|
|||
}
|
||||
}
|
||||
|
||||
image->is_lava = (strstr(name, "lava") != NULL);
|
||||
|
||||
// image->scrap = false; // TODO: reintroduce scrap? would allow optimizations in 2D rendering..
|
||||
|
||||
glGenTextures(1, &texNum);
|
||||
|
||||
image->texnum = texNum;
|
||||
|
||||
GL3_SelectTMU(GL_TEXTURE0);
|
||||
GL3_Bind(texNum);
|
||||
|
||||
if (bits == 8)
|
||||
{
|
||||
// resize 8bit images only when we forced such logic
|
||||
if (r_scale8bittextures->value)
|
||||
{
|
||||
byte *image_converted;
|
||||
int scale = 2;
|
||||
|
||||
// scale 3 times if lerp image
|
||||
if (!nolerp && (vid.height >= 240 * 3))
|
||||
scale = 3;
|
||||
|
||||
image_converted = malloc(width * height * scale * scale);
|
||||
if (!image_converted)
|
||||
return NULL;
|
||||
|
||||
if (scale == 3) {
|
||||
scale3x(pic, image_converted, width, height);
|
||||
} else {
|
||||
scale2x(pic, image_converted, width, height);
|
||||
}
|
||||
|
||||
image->has_alpha = GL3_Upload8(image_converted, width * scale, height * scale,
|
||||
(image->type != it_pic && image->type != it_sky));
|
||||
free(image_converted);
|
||||
}
|
||||
else
|
||||
{
|
||||
image->has_alpha = GL3_Upload8(pic, width, height,
|
||||
(image->type != it_pic && image->type != it_sky));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
image->has_alpha = GL3_Upload32((unsigned *)pic, width, height,
|
||||
(image->type != it_pic && image->type != it_sky));
|
||||
}
|
||||
|
||||
if (realwidth && realheight)
|
||||
{
|
||||
if ((realwidth <= image->width) && (realheight <= image->height))
|
||||
{
|
||||
image->width = realwidth;
|
||||
image->height = realheight;
|
||||
}
|
||||
else
|
||||
{
|
||||
Com_DPrintf(
|
||||
"Warning, image '%s' has hi-res replacement smaller than the original! (%d x %d) < (%d x %d)\n",
|
||||
name, image->width, image->height, realwidth, realheight);
|
||||
}
|
||||
}
|
||||
|
||||
image->sl = 0;
|
||||
image->sh = 1;
|
||||
image->tl = 0;
|
||||
image->th = 1;
|
||||
|
||||
if (nolerp)
|
||||
{
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
}
|
||||
#if 0 // TODO: the scrap could allow batch rendering 2D stuff? not sure it's worth the hassle..
|
||||
/* load little pics into the scrap */
|
||||
if (!nolerp && (image->type == it_pic) && (bits == 8) &&
|
||||
(image->width < 64) && (image->height < 64))
|
||||
if (nolerp == default2Dnolerp && (image->type == it_pic) && (bits == 8) &&
|
||||
(image->width <= 128) && (image->height <= 128))
|
||||
{
|
||||
int x, y;
|
||||
int i, j, k;
|
||||
int texnum;
|
||||
int x=0, y=0;
|
||||
|
||||
texnum = Scrap_AllocBlock(image->width, image->height, &x, &y);
|
||||
|
||||
if (texnum == -1)
|
||||
if (GL3_Scrap_AllocBlock(image->width, image->height, &x, &y) == -1)
|
||||
{
|
||||
goto nonscrap;
|
||||
}
|
||||
|
||||
scrap_dirty = true;
|
||||
gl3_scrap_dirty = true;
|
||||
|
||||
/* copy the texels into the scrap block */
|
||||
k = 0;
|
||||
int k = 0;
|
||||
|
||||
for (i = 0; i < image->height; i++)
|
||||
for (int i = 0; i < image->height; i++)
|
||||
{
|
||||
for (j = 0; j < image->width; j++, k++)
|
||||
for (int j = 0; j < image->width; j++, k++)
|
||||
{
|
||||
scrap_texels[texnum][(y + i) * BLOCK_WIDTH + x + j] = pic[k];
|
||||
// TODO: could do 8->32 conversion here
|
||||
scrap_texels[(y + i) * SCRAP_WIDTH + x + j] = pic[k];
|
||||
}
|
||||
}
|
||||
|
||||
image->texnum = TEXNUM_SCRAPS + texnum;
|
||||
image->texnum = gl3_scrap_texnum;
|
||||
image->scrap = true;
|
||||
image->has_alpha = true;
|
||||
image->sl = (x + 0.01) / (float)BLOCK_WIDTH;
|
||||
image->sh = (x + image->width - 0.01) / (float)BLOCK_WIDTH;
|
||||
image->tl = (y + 0.01) / (float)BLOCK_WIDTH;
|
||||
image->th = (y + image->height - 0.01) / (float)BLOCK_WIDTH;
|
||||
image->sl = (float)x / SCRAP_WIDTH;
|
||||
image->sh = (float)(x + image->width) / SCRAP_WIDTH;
|
||||
image->tl = (float)y / SCRAP_HEIGHT;
|
||||
image->th = (float)(y + image->height) / SCRAP_HEIGHT;
|
||||
}
|
||||
else
|
||||
{
|
||||
nonscrap:
|
||||
|
||||
image->is_lava = (strstr(name, "lava") != NULL);
|
||||
image->scrap = false;
|
||||
image->texnum = TEXNUM_IMAGES + (image - gltextures);
|
||||
R_Bind(image->texnum);
|
||||
|
||||
glGenTextures(1, &texNum);
|
||||
|
||||
image->texnum = texNum;
|
||||
|
||||
GL3_SelectTMU(GL_TEXTURE0);
|
||||
GL3_Bind(texNum);
|
||||
|
||||
if (bits == 8)
|
||||
{
|
||||
image->has_alpha = R_Upload8(pic, width, height,
|
||||
(image->type != it_pic && image->type != it_sky),
|
||||
image->type == it_sky);
|
||||
// resize 8bit images only when we forced such logic
|
||||
if (r_scale8bittextures->value)
|
||||
{
|
||||
byte *image_converted;
|
||||
int scale = 2;
|
||||
|
||||
// scale 3 times if lerp image
|
||||
if (!nolerp && (vid.height >= 240 * 3))
|
||||
scale = 3;
|
||||
|
||||
image_converted = malloc(width * height * scale * scale);
|
||||
if (!image_converted)
|
||||
return NULL;
|
||||
|
||||
if (scale == 3) {
|
||||
scale3x(pic, image_converted, width, height);
|
||||
} else {
|
||||
scale2x(pic, image_converted, width, height);
|
||||
}
|
||||
|
||||
image->has_alpha = GL3_Upload8(image_converted, width * scale, height * scale,
|
||||
(image->type != it_pic && image->type != it_sky));
|
||||
free(image_converted);
|
||||
}
|
||||
else
|
||||
{
|
||||
image->has_alpha = GL3_Upload8(pic, width, height,
|
||||
(image->type != it_pic && image->type != it_sky));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
image->has_alpha = R_Upload32((unsigned *)pic, width, height,
|
||||
image->has_alpha = GL3_Upload32((unsigned *)pic, width, height,
|
||||
(image->type != it_pic && image->type != it_sky));
|
||||
}
|
||||
|
||||
image->upload_width = upload_width; /* after power of 2 and scales */
|
||||
image->upload_height = upload_height;
|
||||
image->paletted = uploaded_paletted;
|
||||
|
||||
if (realwidth && realheight)
|
||||
{
|
||||
if ((realwidth <= image->width) && (realheight <= image->height))
|
||||
|
|
@ -511,7 +554,7 @@ GL3_LoadPic(char *name, byte *pic, int width, int realwidth,
|
|||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
}
|
||||
}
|
||||
#endif // 0
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
|
|
@ -667,6 +710,8 @@ GL3_ShutdownImages(void)
|
|||
glDeleteTextures(1, &image->texnum);
|
||||
memset(image, 0, sizeof(*image));
|
||||
}
|
||||
|
||||
glDeleteTextures(1, &gl3_scrap_texnum);
|
||||
}
|
||||
|
||||
static qboolean IsNPOT(int v)
|
||||
|
|
|
|||
|
|
@ -656,6 +656,8 @@ GL3_Init(void)
|
|||
|
||||
registration_sequence = 1; // from R_InitImages() (everything else from there shouldn't be needed anymore)
|
||||
|
||||
GL3_Scrap_Init();
|
||||
|
||||
GL3_Mod_Init();
|
||||
|
||||
GL3_InitParticleTexture();
|
||||
|
|
|
|||
|
|
@ -304,7 +304,7 @@ typedef struct image_s
|
|||
struct msurface_s *texturechain; /* for sort-by-texture world drawing */
|
||||
GLuint texnum; /* gl texture binding */
|
||||
float sl, tl, sh, th; /* 0,0 - 1,1 unless part of the scrap */
|
||||
// qboolean scrap; // currently unused
|
||||
qboolean scrap;
|
||||
qboolean has_alpha;
|
||||
qboolean is_lava; // DG: added for lava brightness hack
|
||||
|
||||
|
|
@ -456,6 +456,10 @@ extern void GL3_FreeUnusedImages(void);
|
|||
extern qboolean GL3_ImageHasFreeSpace(void);
|
||||
extern void GL3_ImageList_f(void);
|
||||
|
||||
extern void GL3_Scrap_Init(void);
|
||||
extern void GL3_Scrap_Upload(void);
|
||||
extern qboolean gl3_scrap_dirty;
|
||||
|
||||
// gl3_light.c
|
||||
extern int r_dlightframecount;
|
||||
extern void GL3_MarkSurfaceLights(dlight_t *light, int bit, mnode_t *node,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue