mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2025-02-17 01:11:45 +00:00
[gl] Use a scrap for lightmaps
This gives a rather significant speed boost to timedemo demo1: from about 2300-2360fps up to 2520-2600fps, at least when using multi-texture. Since it was necessary for testing the scrap, gl got the ability to set the console background texture, too.
This commit is contained in:
parent
7ed452027c
commit
1e65ec22f9
9 changed files with 418 additions and 232 deletions
|
@ -154,6 +154,7 @@ QFGL_NEED (void, glFogfv, (GLenum pname, const GLfloat * params))
|
|||
QFGL_NEED (void, glFogi, (GLenum pname, GLint param))
|
||||
QFGL_DONT_NEED (void, glFogiv, (GLenum pname, const GLint * params))
|
||||
QFGL_NEED (void, glFrontFace, (GLenum mode))
|
||||
QFGL_NEED (void, glGenerateMipmap, (GLenum target))
|
||||
QFGL_NEED (void, glFrustum, (GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble near_val, GLdouble far_val))
|
||||
QFGL_NEED (GLuint, glGenLists, (GLsizei range))
|
||||
QFGL_NEED (void, glGenTextures, (GLsizei n, GLuint * textures))
|
||||
|
|
|
@ -44,7 +44,7 @@ extern model_t *gl_currentmodel;
|
|||
|
||||
extern GLuint gl_lightmap_textures[MAX_LIGHTMAPS];
|
||||
extern qboolean gl_lightmap_modified[MAX_LIGHTMAPS];
|
||||
extern instsurf_t *gl_lightmap_polys[MAX_LIGHTMAPS];
|
||||
extern instsurf_t *gl_lightmap_polys;
|
||||
extern glRect_t gl_lightmap_rectchange[MAX_LIGHTMAPS];
|
||||
|
||||
void gl_lightmap_init (void);
|
||||
|
@ -54,5 +54,8 @@ void gl_R_CalcLightmaps (void);
|
|||
struct transform_s;
|
||||
extern void (*gl_R_BuildLightMap) (const struct transform_s *transform,
|
||||
mod_brush_t *brush, msurface_t *surf);
|
||||
int gl_R_LightmapTexture (void) __attribute__((pure));
|
||||
void gl_R_FlushLightmaps (void);
|
||||
|
||||
|
||||
#endif // __QF_GL_lightmap_h
|
||||
|
|
|
@ -48,7 +48,22 @@ int GL_LoadTexture (const char *identifier, int width, int height, const byte *d
|
|||
int GL_FindTexture (const char *identifier);
|
||||
|
||||
void GL_TextureMode_f (void);
|
||||
|
||||
void GL_ReleaseTexture (int tex);
|
||||
void GDT_Init (void);
|
||||
|
||||
void GL_TextureInit (void);
|
||||
|
||||
typedef struct scrap_s scrap_t;
|
||||
|
||||
scrap_t *GL_CreateScrap (int size, int format, int linear);
|
||||
void GL_DestroyScrap (scrap_t *scrap);
|
||||
void GL_ScrapClear (scrap_t *scrap);
|
||||
int GL_ScrapTexture (scrap_t *scrap) __attribute__((pure));
|
||||
//XXX slow!
|
||||
struct subpic_s *GL_ScrapSubpic (scrap_t *scrap, int width, int height);
|
||||
//XXX slow!
|
||||
void GL_SubpicDelete (struct subpic_s *subpic);
|
||||
void GL_SubpicUpdate (struct subpic_s *subpic, byte *data, int batch);
|
||||
void GL_ScrapFlush (scrap_t *scrap);
|
||||
|
||||
#endif // __gl_textures_h
|
||||
|
|
|
@ -152,17 +152,8 @@ typedef struct msurface_s {
|
|||
struct {
|
||||
glpoly_t *polys; // multiple if warped
|
||||
instsurf_t *instsurf;///< null if not part of world model/sub-model
|
||||
union {
|
||||
struct {
|
||||
struct subpic_s *lightpic;///< light map texture ref (glsl)
|
||||
byte *base;
|
||||
};
|
||||
struct {
|
||||
int light_s;
|
||||
int light_t;
|
||||
int lightmaptexturenum;
|
||||
};
|
||||
};
|
||||
struct subpic_s *lightpic;///< light map texture ref (glsl)
|
||||
byte *base;
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
@ -85,6 +85,15 @@ static cc_cell_t char_cells[256];
|
|||
static GLuint translate_texture;
|
||||
static int char_texture;
|
||||
static int cs_texture; // crosshair texturea
|
||||
static int gl_conback_texnum;
|
||||
static cvar_t gl_conback_texnum_cvar = {
|
||||
.name = "gl_conback_texnum",
|
||||
.description =
|
||||
"bind conback to this texture for debugging",
|
||||
.default_value = "0",
|
||||
.flags = CVAR_NONE,
|
||||
.value = { .type = &cexpr_int, .value = &gl_conback_texnum },
|
||||
};
|
||||
|
||||
static byte color_0_8[4] = { 204, 204, 204, 255 };
|
||||
|
||||
|
@ -418,6 +427,8 @@ gl_Draw_Init (void)
|
|||
draw_backtile = gl_Draw_PicFromWad ("backtile");
|
||||
|
||||
Draw_InitText ();
|
||||
|
||||
Cvar_Register (&gl_conback_texnum_cvar, 0, 0);
|
||||
}
|
||||
|
||||
static inline void
|
||||
|
@ -817,7 +828,11 @@ gl_Draw_ConsoleBackground (int lines, byte alpha)
|
|||
qfglColor4ubv (color_0_8);
|
||||
|
||||
// draw the console texture
|
||||
qfglBindTexture (GL_TEXTURE_2D, gl->texnum);
|
||||
if (gl_conback_texnum) {
|
||||
qfglBindTexture (GL_TEXTURE_2D, gl_conback_texnum);
|
||||
} else {
|
||||
qfglBindTexture (GL_TEXTURE_2D, gl->texnum);
|
||||
}
|
||||
qfglBegin (GL_QUADS);
|
||||
qfglTexCoord2f (0, 0 + ofs);
|
||||
qfglVertex2f (0, 0);
|
||||
|
|
|
@ -57,6 +57,7 @@
|
|||
#include "compat.h"
|
||||
#include "r_internal.h"
|
||||
|
||||
static scrap_t *light_scrap;
|
||||
static int dlightdivtable[8192];
|
||||
static int gl_internalformat; // 1 or 3
|
||||
static int lightmap_bytes; // 1, 3, or 4
|
||||
|
@ -66,11 +67,12 @@ GLuint gl_lightmap_textures[MAX_LIGHTMAPS];
|
|||
// LordHavoc: changed to be allocated at runtime (typically lower memory usage)
|
||||
static byte *lightmaps[MAX_LIGHTMAPS];
|
||||
|
||||
static unsigned int blocklights[34 * 34 * 3]; //FIXME make dynamic
|
||||
static unsigned *blocklights;
|
||||
static int bl_extents[2];
|
||||
static int allocated[MAX_LIGHTMAPS][BLOCK_WIDTH];
|
||||
|
||||
qboolean gl_lightmap_modified[MAX_LIGHTMAPS];
|
||||
instsurf_t *gl_lightmap_polys[MAX_LIGHTMAPS];
|
||||
instsurf_t *gl_lightmap_polys;
|
||||
glRect_t gl_lightmap_rectchange[MAX_LIGHTMAPS];
|
||||
|
||||
static int lmshift = 7;
|
||||
|
@ -238,7 +240,7 @@ R_BuildLightMap_1 (const transform_t *transform, mod_brush_t *brush,
|
|||
msurface_t *surf)
|
||||
{
|
||||
byte *dest;
|
||||
int maps, size, stride, smax, tmax, i, j;
|
||||
int maps, size, smax, tmax, i;
|
||||
unsigned int scale;
|
||||
unsigned int *bl;
|
||||
|
||||
|
@ -279,19 +281,14 @@ R_BuildLightMap_1 (const transform_t *transform, mod_brush_t *brush,
|
|||
store:
|
||||
// bound and shift
|
||||
// Also, invert because we're using a diff blendfunc now
|
||||
|
||||
stride = (BLOCK_WIDTH - smax) * lightmap_bytes;
|
||||
bl = blocklights;
|
||||
|
||||
dest = lightmaps[surf->lightmaptexturenum]
|
||||
+ (surf->light_t * BLOCK_WIDTH + surf->light_s) * lightmap_bytes;
|
||||
|
||||
for (i = 0; i < tmax; i++, dest += stride) {
|
||||
for (j = smax; j; j--) {
|
||||
*dest++ = min (*bl >> lmshift, 255);
|
||||
bl++;
|
||||
}
|
||||
dest = (byte *) blocklights;
|
||||
for (i = 0; i < tmax * smax; i++) {
|
||||
*dest++ = min (*bl >> lmshift, 255);
|
||||
bl++;
|
||||
}
|
||||
|
||||
GL_SubpicUpdate (surf->lightpic, (byte *) blocklights, 1);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -299,7 +296,7 @@ R_BuildLightMap_3 (const transform_t *transform, mod_brush_t *brush,
|
|||
msurface_t *surf)
|
||||
{
|
||||
byte *dest;
|
||||
int maps, size, stride, smax, tmax, i, j;
|
||||
int maps, size, smax, tmax, i;
|
||||
unsigned int scale;
|
||||
unsigned int *bl;
|
||||
|
||||
|
@ -342,22 +339,18 @@ R_BuildLightMap_3 (const transform_t *transform, mod_brush_t *brush,
|
|||
store:
|
||||
// bound and shift
|
||||
// and invert too
|
||||
stride = (BLOCK_WIDTH - smax) * lightmap_bytes;
|
||||
bl = blocklights;
|
||||
|
||||
dest = lightmaps[surf->lightmaptexturenum]
|
||||
+ (surf->light_t * BLOCK_WIDTH + surf->light_s) * lightmap_bytes;
|
||||
|
||||
for (i = 0; i < tmax; i++, dest += stride) {
|
||||
for (j = 0; j < smax; j++) {
|
||||
*dest++ = min (*bl >> lmshift, 255);
|
||||
bl++;
|
||||
*dest++ = min (*bl >> lmshift, 255);
|
||||
bl++;
|
||||
*dest++ = min (*bl >> lmshift, 255);
|
||||
bl++;
|
||||
}
|
||||
dest = (byte *) blocklights;
|
||||
for (i = 0; i < tmax * smax; i++) {
|
||||
*dest++ = min (*bl >> lmshift, 255);
|
||||
bl++;
|
||||
*dest++ = min (*bl >> lmshift, 255);
|
||||
bl++;
|
||||
*dest++ = min (*bl >> lmshift, 255);
|
||||
bl++;
|
||||
}
|
||||
|
||||
GL_SubpicUpdate (surf->lightpic, (byte *) blocklights, 1);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -365,7 +358,7 @@ R_BuildLightMap_4 (const transform_t *transform, mod_brush_t *brush,
|
|||
msurface_t *surf)
|
||||
{
|
||||
byte *dest;
|
||||
int maps, size, smax, tmax, i, j, stride;
|
||||
int maps, size, smax, tmax, i;
|
||||
unsigned int scale;
|
||||
unsigned int *bl;
|
||||
|
||||
|
@ -408,23 +401,19 @@ R_BuildLightMap_4 (const transform_t *transform, mod_brush_t *brush,
|
|||
store:
|
||||
// bound and shift
|
||||
// and invert too
|
||||
stride = (BLOCK_WIDTH - smax) * lightmap_bytes;
|
||||
bl = blocklights;
|
||||
|
||||
dest = lightmaps[surf->lightmaptexturenum]
|
||||
+ (surf->light_t * BLOCK_WIDTH + surf->light_s) * lightmap_bytes;
|
||||
|
||||
for (i = 0; i < tmax; i++, dest += stride) {
|
||||
for (j = 0; j < smax; j++) {
|
||||
*dest++ = min (*bl >> lmshift, 255);
|
||||
bl++;
|
||||
*dest++ = min (*bl >> lmshift, 255);
|
||||
bl++;
|
||||
*dest++ = min (*bl >> lmshift, 255);
|
||||
bl++;
|
||||
*dest++ = 255;
|
||||
}
|
||||
dest = (byte *) blocklights;
|
||||
for (i = 0; i < tmax * smax; i++) {
|
||||
*dest++ = min (*bl >> lmshift, 255);
|
||||
bl++;
|
||||
*dest++ = min (*bl >> lmshift, 255);
|
||||
bl++;
|
||||
*dest++ = min (*bl >> lmshift, 255);
|
||||
bl++;
|
||||
*dest++ = 255;
|
||||
}
|
||||
|
||||
GL_SubpicUpdate (surf->lightpic, (byte *) blocklights, 1);
|
||||
}
|
||||
|
||||
// BRUSH MODELS ===============================================================
|
||||
|
@ -449,75 +438,33 @@ do_subimage_2 (int i)
|
|||
gl_lightmap_format, GL_UNSIGNED_BYTE, block);
|
||||
}
|
||||
|
||||
static void
|
||||
GL_UploadLightmap (int i)
|
||||
{
|
||||
switch (gl_lightmap_subimage) {
|
||||
case 2:
|
||||
do_subimage_2 (i);
|
||||
break;
|
||||
case 1:
|
||||
qfglTexSubImage2D (GL_TEXTURE_2D, 0, 0, gl_lightmap_rectchange[i].t,
|
||||
BLOCK_WIDTH, gl_lightmap_rectchange[i].h,
|
||||
gl_lightmap_format, GL_UNSIGNED_BYTE,
|
||||
lightmaps[i] + (gl_lightmap_rectchange[i].t *
|
||||
BLOCK_WIDTH) * lightmap_bytes);
|
||||
break;
|
||||
default:
|
||||
case 0:
|
||||
qfglTexImage2D (GL_TEXTURE_2D, 0, gl_internalformat, BLOCK_WIDTH,
|
||||
BLOCK_HEIGHT, 0, gl_lightmap_format, GL_UNSIGNED_BYTE,
|
||||
lightmaps[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
gl_R_CalcLightmaps (void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < MAX_LIGHTMAPS; i++) {
|
||||
if (!gl_lightmap_polys[i])
|
||||
continue;
|
||||
if (gl_lightmap_modified[i]) {
|
||||
qfglBindTexture (GL_TEXTURE_2D, gl_lightmap_textures[i]);
|
||||
GL_UploadLightmap (i);
|
||||
gl_lightmap_modified[i] = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
gl_R_BlendLightmaps (void)
|
||||
{
|
||||
float *v;
|
||||
int i, j;
|
||||
instsurf_t *sc;
|
||||
glpoly_t *p;
|
||||
|
||||
qfglDepthMask (GL_FALSE); // don't bother writing Z
|
||||
qfglBlendFunc (lm_src_blend, lm_dest_blend);
|
||||
|
||||
for (i = 0; i < MAX_LIGHTMAPS; i++) {
|
||||
for (sc = gl_lightmap_polys[i]; sc; sc = sc->lm_chain) {
|
||||
qfglBindTexture (GL_TEXTURE_2D, gl_lightmap_textures[i]);
|
||||
if (sc->transform) {
|
||||
qfglPushMatrix ();
|
||||
qfglLoadMatrixf (sc->transform);
|
||||
}
|
||||
for (p = sc->surface->polys; p; p = p->next) {
|
||||
qfglBegin (GL_POLYGON);
|
||||
v = p->verts[0];
|
||||
for (j = 0; j < p->numverts; j++, v += VERTEXSIZE) {
|
||||
qfglTexCoord2fv (&v[5]);
|
||||
qfglVertex3fv (v);
|
||||
}
|
||||
qfglEnd ();
|
||||
}
|
||||
if (sc->transform)
|
||||
qfglPopMatrix ();
|
||||
qfglBindTexture (GL_TEXTURE_2D, gl_R_LightmapTexture ());
|
||||
for (sc = gl_lightmap_polys; sc; sc = sc->lm_chain) {
|
||||
if (sc->transform) {
|
||||
qfglPushMatrix ();
|
||||
qfglLoadMatrixf (sc->transform);
|
||||
}
|
||||
for (p = sc->surface->polys; p; p = p->next) {
|
||||
qfglBegin (GL_POLYGON);
|
||||
v = p->verts[0];
|
||||
for (int j = 0; j < p->numverts; j++, v += VERTEXSIZE) {
|
||||
qfglTexCoord2fv (&v[5]);
|
||||
qfglVertex3fv (v);
|
||||
}
|
||||
qfglEnd ();
|
||||
}
|
||||
if (sc->transform)
|
||||
qfglPopMatrix ();
|
||||
}
|
||||
|
||||
// Return to normal blending --KB
|
||||
|
@ -528,7 +475,6 @@ gl_R_BlendLightmaps (void)
|
|||
void
|
||||
gl_overbright_f (void *data, const cvar_t *cvar)
|
||||
{
|
||||
int num;
|
||||
mod_brush_t *brush;
|
||||
|
||||
if (!cvar)
|
||||
|
@ -579,61 +525,12 @@ gl_overbright_f (void *data, const cvar_t *cvar)
|
|||
if (surf->flags & (SURF_DRAWTURB | SURF_DRAWSKY))
|
||||
continue;
|
||||
|
||||
num = surf->lightmaptexturenum;
|
||||
gl_lightmap_modified[num] = true;
|
||||
gl_lightmap_rectchange[num].l = 0;
|
||||
gl_lightmap_rectchange[num].t = 0;
|
||||
gl_lightmap_rectchange[num].w = BLOCK_WIDTH;
|
||||
gl_lightmap_rectchange[num].h = BLOCK_HEIGHT;
|
||||
|
||||
gl_R_BuildLightMap (0, brush, surf);
|
||||
}
|
||||
}
|
||||
|
||||
// LIGHTMAP ALLOCATION ========================================================
|
||||
|
||||
// returns a texture number and the position inside it
|
||||
static int
|
||||
AllocBlock (int w, int h, int *x, int *y)
|
||||
{
|
||||
int best, best2, texnum, i, j;
|
||||
|
||||
for (texnum = 0; texnum < MAX_LIGHTMAPS; texnum++) {
|
||||
best = BLOCK_HEIGHT;
|
||||
|
||||
for (i = 0; i < BLOCK_WIDTH - w; i++) {
|
||||
best2 = 0;
|
||||
|
||||
for (j = 0; j < w; j++) {
|
||||
if (allocated[texnum][i + j] >= best)
|
||||
break;
|
||||
if (allocated[texnum][i + j] > best2)
|
||||
best2 = allocated[texnum][i + j];
|
||||
}
|
||||
if (j == w) {
|
||||
// this is a valid spot
|
||||
*x = i;
|
||||
*y = best = best2;
|
||||
}
|
||||
}
|
||||
|
||||
if (best + h > BLOCK_HEIGHT)
|
||||
continue;
|
||||
|
||||
// LordHavoc: allocate lightmaps only as needed
|
||||
if (!lightmaps[texnum])
|
||||
lightmaps[texnum] = calloc (BLOCK_WIDTH * BLOCK_HEIGHT,
|
||||
lightmap_bytes);
|
||||
for (i = 0; i < w; i++)
|
||||
allocated[texnum][*x + i] = best + h;
|
||||
|
||||
return texnum;
|
||||
}
|
||||
|
||||
Sys_Error ("AllocBlock: full");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
GL_CreateSurfaceLightmap (mod_brush_t *brush, msurface_t *surf)
|
||||
{
|
||||
|
@ -645,9 +542,16 @@ GL_CreateSurfaceLightmap (mod_brush_t *brush, msurface_t *surf)
|
|||
smax = (surf->extents[0] >> 4) + 1;
|
||||
tmax = (surf->extents[1] >> 4) + 1;
|
||||
|
||||
surf->lightmaptexturenum =
|
||||
AllocBlock (smax, tmax, &surf->light_s, &surf->light_t);
|
||||
gl_R_BuildLightMap (0, brush, surf);
|
||||
surf->lightpic = GL_ScrapSubpic (light_scrap, smax, tmax);
|
||||
if (!surf->lightpic) {
|
||||
Sys_Error ("FIXME taniwha is being lazy");
|
||||
}
|
||||
if (smax > bl_extents[0]) {
|
||||
bl_extents[0] = smax;
|
||||
}
|
||||
if (tmax > bl_extents[1]) {
|
||||
bl_extents[1] = tmax;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -665,10 +569,6 @@ GL_BuildLightmaps (model_t **models, int num_models)
|
|||
|
||||
r_framecount = 1; // no dlightcache
|
||||
|
||||
if (!gl_lightmap_textures[0]) {
|
||||
qfglGenTextures (MAX_LIGHTMAPS, gl_lightmap_textures);
|
||||
}
|
||||
|
||||
switch (r_lightmap_components) {
|
||||
case 1:
|
||||
gl_internalformat = 1;
|
||||
|
@ -697,6 +597,13 @@ GL_BuildLightmaps (model_t **models, int num_models)
|
|||
break;
|
||||
}
|
||||
|
||||
if (!light_scrap) {
|
||||
light_scrap = GL_CreateScrap (2048, gl_lightmap_format, 1);
|
||||
} else {
|
||||
GL_ScrapClear (light_scrap);
|
||||
}
|
||||
|
||||
bl_extents[1] = bl_extents[0] = 0;
|
||||
for (int j = 1; j < num_models; j++) {
|
||||
m = models[j];
|
||||
if (!m)
|
||||
|
@ -716,23 +623,37 @@ GL_BuildLightmaps (model_t **models, int num_models)
|
|||
}
|
||||
}
|
||||
|
||||
int size = bl_extents[0] * bl_extents[1] * 3; // * 3 for rgb support
|
||||
blocklights = realloc (blocklights, size * sizeof (blocklights[0]));
|
||||
|
||||
// upload all lightmaps that were filled
|
||||
for (int i = 0; i < MAX_LIGHTMAPS; i++) {
|
||||
if (!allocated[i][0])
|
||||
break; // no more used
|
||||
gl_lightmap_modified[i] = false;
|
||||
gl_lightmap_rectchange[i].l = BLOCK_WIDTH;
|
||||
gl_lightmap_rectchange[i].t = BLOCK_HEIGHT;
|
||||
gl_lightmap_rectchange[i].w = 0;
|
||||
gl_lightmap_rectchange[i].h = 0;
|
||||
qfglBindTexture (GL_TEXTURE_2D, gl_lightmap_textures[i]);
|
||||
qfglTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
qfglTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
if (gl_Anisotropy)
|
||||
qfglTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT,
|
||||
gl_aniso);
|
||||
qfglTexImage2D (GL_TEXTURE_2D, 0, lightmap_bytes, BLOCK_WIDTH,
|
||||
BLOCK_HEIGHT, 0, gl_lightmap_format,
|
||||
GL_UNSIGNED_BYTE, lightmaps[i]);
|
||||
for (int j = 1; j < num_models; j++) {
|
||||
m = models[j];
|
||||
if (!m)
|
||||
break;
|
||||
if (m->path[0] == '*' || m->type != mod_brush) {
|
||||
// sub model surfaces are processed as part of the main model
|
||||
continue;
|
||||
}
|
||||
brush = &m->brush;
|
||||
// non-bsp models don't have surfaces.
|
||||
for (unsigned i = 0; i < brush->numsurfaces; i++) {
|
||||
msurface_t *surf = brush->surfaces + i;
|
||||
if (surf->lightpic) {
|
||||
gl_R_BuildLightMap (0, brush, surf);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
gl_R_LightmapTexture (void)
|
||||
{
|
||||
return GL_ScrapTexture (light_scrap);
|
||||
}
|
||||
|
||||
void
|
||||
gl_R_FlushLightmaps (void)
|
||||
{
|
||||
GL_ScrapFlush (light_scrap);
|
||||
}
|
||||
|
|
|
@ -277,12 +277,11 @@ R_RenderBrushPoly_1 (msurface_t *surf)
|
|||
static inline void
|
||||
R_AddToLightmapChain (glbspctx_t *bctx, msurface_t *surf, instsurf_t *sc)
|
||||
{
|
||||
int maps, smax, tmax;
|
||||
glRect_t *theRect;
|
||||
int maps;
|
||||
|
||||
// add the poly to the proper lightmap chain
|
||||
sc->lm_chain = gl_lightmap_polys[surf->lightmaptexturenum];
|
||||
gl_lightmap_polys[surf->lightmaptexturenum] = sc;
|
||||
sc->lm_chain = gl_lightmap_polys;
|
||||
gl_lightmap_polys = sc;
|
||||
|
||||
// check for lightmap modification
|
||||
for (maps = 0; maps < MAXLIGHTMAPS && surf->styles[maps] != 255; maps++)
|
||||
|
@ -292,24 +291,6 @@ R_AddToLightmapChain (glbspctx_t *bctx, msurface_t *surf, instsurf_t *sc)
|
|||
if ((surf->dlightframe == r_framecount) || surf->cached_dlight) {
|
||||
dynamic:
|
||||
if (r_dynamic) {
|
||||
gl_lightmap_modified[surf->lightmaptexturenum] = true;
|
||||
theRect = &gl_lightmap_rectchange[surf->lightmaptexturenum];
|
||||
if (surf->light_t < theRect->t) {
|
||||
if (theRect->h)
|
||||
theRect->h += theRect->t - surf->light_t;
|
||||
theRect->t = surf->light_t;
|
||||
}
|
||||
if (surf->light_s < theRect->l) {
|
||||
if (theRect->w)
|
||||
theRect->w += theRect->l - surf->light_s;
|
||||
theRect->l = surf->light_s;
|
||||
}
|
||||
smax = (surf->extents[0] >> 4) + 1;
|
||||
tmax = (surf->extents[1] >> 4) + 1;
|
||||
if ((theRect->w + theRect->l) < (surf->light_s + smax))
|
||||
theRect->w = (surf->light_s - theRect->l) + smax;
|
||||
if ((theRect->h + theRect->t) < (surf->light_t + tmax))
|
||||
theRect->h = (surf->light_t - theRect->t) + tmax;
|
||||
gl_R_BuildLightMap (bctx->entity->transform, bctx->brush, surf);
|
||||
}
|
||||
}
|
||||
|
@ -372,6 +353,7 @@ DrawTextureChains (int disable_blend, int do_bind)
|
|||
// Lightmaps
|
||||
qglActiveTexture (gl_mtex_enum + 1);
|
||||
qfglEnable (GL_TEXTURE_2D);
|
||||
qfglBindTexture (GL_TEXTURE_2D, gl_R_LightmapTexture ());
|
||||
|
||||
// Base Texture
|
||||
qglActiveTexture (gl_mtex_enum + 0);
|
||||
|
@ -388,7 +370,6 @@ DrawTextureChains (int disable_blend, int do_bind)
|
|||
qfglEnable (GL_TEXTURE_2D);
|
||||
qfglBindTexture (GL_TEXTURE_2D, tex->gl_fb_texturenum);
|
||||
|
||||
qglActiveTexture (gl_mtex_enum + 1);
|
||||
for (s = tex->tex_chain; s; s = s->tex_chain) {
|
||||
surf = s->surface;
|
||||
if (s->transform) {
|
||||
|
@ -397,8 +378,6 @@ DrawTextureChains (int disable_blend, int do_bind)
|
|||
}
|
||||
if (s->color && do_bind)
|
||||
qfglColor4fv (s->color);
|
||||
qfglBindTexture (GL_TEXTURE_2D,
|
||||
gl_lightmap_textures[surf->lightmaptexturenum]);
|
||||
|
||||
R_RenderBrushPoly_3 (surf);
|
||||
|
||||
|
@ -413,11 +392,8 @@ DrawTextureChains (int disable_blend, int do_bind)
|
|||
|
||||
qglActiveTexture (gl_mtex_enum + 0);
|
||||
} else {
|
||||
qglActiveTexture (gl_mtex_enum + 1);
|
||||
for (s = tex->tex_chain; s; s = s->tex_chain) {
|
||||
surf = s->surface;
|
||||
qfglBindTexture (GL_TEXTURE_2D,
|
||||
gl_lightmap_textures[surf->lightmaptexturenum]);
|
||||
|
||||
if (s->transform) {
|
||||
qfglPushMatrix ();
|
||||
|
@ -489,7 +465,7 @@ clear_texture_chains (void)
|
|||
tex->tex_chain_tail = &tex->tex_chain;
|
||||
release_instsurfs ();
|
||||
|
||||
memset (gl_lightmap_polys, 0, sizeof (gl_lightmap_polys));
|
||||
gl_lightmap_polys = 0;
|
||||
}
|
||||
|
||||
static inline void
|
||||
|
@ -743,7 +719,7 @@ gl_R_DrawWorld (void)
|
|||
}
|
||||
}
|
||||
|
||||
gl_R_CalcLightmaps ();
|
||||
gl_R_FlushLightmaps ();
|
||||
|
||||
if (!Fog_GetDensity ()
|
||||
|| (gl_fb_bmodels && gl_mtex_fullbright)
|
||||
|
@ -859,19 +835,15 @@ GL_BuildSurfaceDisplayList (mod_brush_t *brush, msurface_t *surf)
|
|||
|
||||
// lightmap texture coordinates
|
||||
s = DotProduct (vec, texinfo->vecs[0]) + texinfo->vecs[0][3];
|
||||
s -= surf->texturemins[0];
|
||||
s += surf->light_s * 16;
|
||||
s += 8;
|
||||
s /= BLOCK_WIDTH * 16;
|
||||
|
||||
t = DotProduct (vec, texinfo->vecs[1]) + texinfo->vecs[1][3];
|
||||
s -= surf->texturemins[0];
|
||||
t -= surf->texturemins[1];
|
||||
t += surf->light_t * 16;
|
||||
t += 8;
|
||||
t /= BLOCK_HEIGHT * 16;
|
||||
|
||||
poly->verts[i][5] = s;
|
||||
poly->verts[i][6] = t;
|
||||
s += surf->lightpic->rect->x * 16 + 8;
|
||||
t += surf->lightpic->rect->y * 16 + 8;
|
||||
s /= 16;
|
||||
t /= 16;
|
||||
poly->verts[i][5] = s * surf->lightpic->size;
|
||||
poly->verts[i][6] = t * surf->lightpic->size;
|
||||
}
|
||||
|
||||
// remove co-linear points - Ed
|
||||
|
|
|
@ -48,12 +48,28 @@
|
|||
#include "QF/GL/funcs.h"
|
||||
#include "QF/GL/qf_textures.h"
|
||||
#include "QF/GL/qf_vid.h"
|
||||
#include "QF/ui/vrect.h"
|
||||
|
||||
#include "compat.h"
|
||||
#include "r_internal.h"
|
||||
#include "r_scrap.h"
|
||||
#include "sbar.h"
|
||||
#include "vid_internal.h"
|
||||
|
||||
struct scrap_s {
|
||||
rscrap_t rscrap;
|
||||
GLuint tnum;
|
||||
int format;
|
||||
int bpp;
|
||||
byte *data; // local copy of the texture so updates can be batched
|
||||
vrect_t *batch;
|
||||
subpic_t *subpics;
|
||||
struct scrap_s *next;
|
||||
};
|
||||
|
||||
static scrap_t *scrap_list;
|
||||
static int max_tex_size;
|
||||
|
||||
typedef struct {
|
||||
GLuint texnum;
|
||||
char identifier[64];
|
||||
|
@ -625,3 +641,252 @@ SetupTexture:
|
|||
|
||||
return glt->texnum;
|
||||
}
|
||||
|
||||
void
|
||||
GL_ReleaseTexture (int tex)
|
||||
{
|
||||
GLuint tnum = tex;
|
||||
qfglDeleteTextures (1, &tnum);
|
||||
}
|
||||
|
||||
static void
|
||||
gl_scraps_f (void)
|
||||
{
|
||||
scrap_t *scrap;
|
||||
int area;
|
||||
int size;
|
||||
|
||||
if (!scrap_list) {
|
||||
Sys_Printf ("No scraps\n");
|
||||
return;
|
||||
}
|
||||
for (scrap = scrap_list; scrap; scrap = scrap->next) {
|
||||
area = R_ScrapArea (&scrap->rscrap);
|
||||
// always square
|
||||
size = scrap->rscrap.width;
|
||||
Sys_Printf ("tnum=%u size=%d format=%04x bpp=%d free=%d%%\n",
|
||||
scrap->tnum, size, scrap->format, scrap->bpp,
|
||||
area * 100 / (size * size));
|
||||
if (Cmd_Argc () > 1) {
|
||||
R_ScrapDump (&scrap->rscrap);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
GL_TextureInit (void)
|
||||
{
|
||||
qfglGetIntegerv (GL_MAX_TEXTURE_SIZE, &max_tex_size);
|
||||
Sys_MaskPrintf (SYS_glt, "max texture size: %d\n", max_tex_size);
|
||||
|
||||
Cmd_AddCommand ("gl_scraps", gl_scraps_f, "Dump GL scrap stats");
|
||||
}
|
||||
|
||||
scrap_t *
|
||||
GL_CreateScrap (int size, int format, int linear)
|
||||
{
|
||||
int i;
|
||||
int bpp;
|
||||
scrap_t *scrap;
|
||||
|
||||
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);
|
||||
R_ScrapInit (&scrap->rscrap, size, size);
|
||||
scrap->format = format;
|
||||
scrap->bpp = bpp;
|
||||
scrap->subpics = 0;
|
||||
scrap->next = scrap_list;
|
||||
scrap_list = scrap;
|
||||
|
||||
scrap->data = calloc (1, size * size * bpp);
|
||||
scrap->batch = 0;
|
||||
|
||||
qfglBindTexture (GL_TEXTURE_2D, scrap->tnum);
|
||||
qfglTexImage2D (GL_TEXTURE_2D, 0, format,
|
||||
size, size, 0, format, GL_UNSIGNED_BYTE, scrap->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);
|
||||
if (linear) {
|
||||
qfglTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
qfglTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
} else {
|
||||
qfglTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
qfglTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
}
|
||||
qfglGenerateMipmap (GL_TEXTURE_2D);
|
||||
|
||||
return scrap;
|
||||
}
|
||||
|
||||
void
|
||||
GL_ScrapClear (scrap_t *scrap)
|
||||
{
|
||||
subpic_t *sp;
|
||||
while (scrap->subpics) {
|
||||
sp = scrap->subpics;
|
||||
scrap->subpics = (subpic_t *) sp->next;
|
||||
free (sp);
|
||||
}
|
||||
R_ScrapClear (&scrap->rscrap);
|
||||
}
|
||||
|
||||
void
|
||||
GL_DestroyScrap (scrap_t *scrap)
|
||||
{
|
||||
scrap_t **s;
|
||||
|
||||
for (s = &scrap_list; *s; s = &(*s)->next) {
|
||||
if (*s == scrap) {
|
||||
*s = scrap->next;
|
||||
break;
|
||||
}
|
||||
}
|
||||
GL_ScrapClear (scrap);
|
||||
R_ScrapDelete (&scrap->rscrap);
|
||||
GL_ReleaseTexture (scrap->tnum);
|
||||
free (scrap->data);
|
||||
free (scrap);
|
||||
}
|
||||
|
||||
int
|
||||
GL_ScrapTexture (scrap_t *scrap)
|
||||
{
|
||||
return scrap->tnum;
|
||||
}
|
||||
|
||||
subpic_t *
|
||||
GL_ScrapSubpic (scrap_t *scrap, int width, int height)
|
||||
{
|
||||
vrect_t *rect;
|
||||
subpic_t *subpic;
|
||||
|
||||
rect = R_ScrapAlloc (&scrap->rscrap, width, height);
|
||||
if (!rect) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
subpic = malloc (sizeof (subpic_t));
|
||||
*((subpic_t **) &subpic->next) = scrap->subpics;
|
||||
scrap->subpics = subpic;
|
||||
*((scrap_t **) &subpic->scrap) = scrap;
|
||||
*((vrect_t **) &subpic->rect) = rect;
|
||||
*((int *) &subpic->width) = width;
|
||||
*((int *) &subpic->height) = height;
|
||||
*((float *) &subpic->size) = 1.0 / scrap->rscrap.width;
|
||||
return subpic;
|
||||
}
|
||||
|
||||
void
|
||||
GL_SubpicDelete (subpic_t *subpic)
|
||||
{
|
||||
scrap_t *scrap = (scrap_t *) subpic->scrap;
|
||||
vrect_t *rect = (vrect_t *) subpic->rect;
|
||||
subpic_t **sp;
|
||||
|
||||
for (sp = &scrap->subpics; *sp; sp = (subpic_t **) &(*sp)->next)
|
||||
if (*sp == subpic)
|
||||
break;
|
||||
if (*sp != subpic)
|
||||
Sys_Error ("GL_ScrapDelSubpic: broken subpic");
|
||||
*sp = (subpic_t *) subpic->next;
|
||||
free (subpic);
|
||||
R_ScrapFree (&scrap->rscrap, rect);
|
||||
}
|
||||
|
||||
void
|
||||
GL_SubpicUpdate (subpic_t *subpic, byte *data, int batch)
|
||||
{
|
||||
scrap_t *scrap = (scrap_t *) subpic->scrap;
|
||||
vrect_t *rect = (vrect_t *) subpic->rect;
|
||||
byte *dest;
|
||||
int step, sbytes;
|
||||
int i;
|
||||
|
||||
if (batch) {
|
||||
/*if (scrap->batch) {
|
||||
vrect_t *r = scrap->batch;
|
||||
scrap->batch = VRect_Union (r, rect);
|
||||
VRect_Delete (r);
|
||||
} else {
|
||||
scrap->batch = VRect_New (rect->x, rect->y,
|
||||
rect->width, rect->height);
|
||||
}*/
|
||||
vrect_t *r = VRect_New (rect->x, rect->y,
|
||||
rect->width, rect->height);
|
||||
r->next = scrap->batch;
|
||||
scrap->batch = r;
|
||||
|
||||
step = scrap->rscrap.width * scrap->bpp;
|
||||
sbytes = subpic->width * scrap->bpp;
|
||||
dest = scrap->data + rect->y * step + rect->x * scrap->bpp;
|
||||
for (i = 0; i < subpic->height; i++, dest += step, data += sbytes)
|
||||
memcpy (dest, data, sbytes);
|
||||
} else {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
GL_ScrapFlush (scrap_t *scrap)
|
||||
{
|
||||
vrect_t *rect = scrap->batch;
|
||||
int size = scrap->rscrap.width;
|
||||
|
||||
if (!rect)
|
||||
return;
|
||||
//FIXME: it seems gl (as opposed to egl) allows row step to be specified.
|
||||
//should update to not update the entire horizontal block
|
||||
qfglBindTexture (GL_TEXTURE_2D, scrap->tnum);
|
||||
qfglPixelStorei(GL_UNPACK_ROW_LENGTH, size);
|
||||
//qfglPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
while (rect) {
|
||||
vrect_t *next = rect->next;
|
||||
#if 1
|
||||
int x = rect->x;
|
||||
int y = rect->y;
|
||||
int w = rect->width;
|
||||
int h = rect->height;
|
||||
qfglTexSubImage2D (GL_TEXTURE_2D, 0, x, y, w, h, scrap->format,
|
||||
GL_UNSIGNED_BYTE,
|
||||
scrap->data + (y * size + x) * scrap->bpp);
|
||||
#else
|
||||
for (int i = 0; i < rect->height; i++) {
|
||||
int y = rect->y + i;
|
||||
qfglTexSubImage2D (GL_TEXTURE_2D, 0, rect->x, y,
|
||||
rect->width, 1, scrap->format,
|
||||
GL_UNSIGNED_BYTE,
|
||||
scrap->data + (y * size + rect->x) * scrap->bpp);
|
||||
}
|
||||
#endif
|
||||
VRect_Delete (rect);
|
||||
rect = next;
|
||||
}
|
||||
qfglPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
|
||||
//qfglPixelStorei(GL_UNPACK_ALIGNMENT, 4);
|
||||
scrap->batch = 0;
|
||||
}
|
||||
|
|
|
@ -49,6 +49,7 @@
|
|||
#include "QF/GL/extensions.h"
|
||||
#include "QF/GL/funcs.h"
|
||||
#include "QF/GL/qf_rmain.h"
|
||||
#include "QF/GL/qf_textures.h"
|
||||
#include "QF/GL/qf_vid.h"
|
||||
|
||||
#include "compat.h"
|
||||
|
@ -1031,6 +1032,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