From a8824972db08d67bb5dafec447087c4bf08e31ef Mon Sep 17 00:00:00 2001 From: Jaime Moreira Date: Sat, 11 May 2024 18:16:38 -0400 Subject: [PATCH 1/3] Fixed potential game crash at shutdown Only happens in Windows. A cvar was being queried just after all cvars were freed, in Qcommon_Shutdown(). GL_GENERATE_MIPMAP definition relocated. scrap_uploads counter deleted, it wasn't being read anywhere. --- src/backends/windows/system.c | 3 ++- src/client/refresh/gl1/gl1_image.c | 5 ----- src/client/refresh/gl1/gl1_scrap.c | 4 +--- src/client/refresh/gl1/header/qgl.h | 1 + 4 files changed, 4 insertions(+), 9 deletions(-) diff --git a/src/backends/windows/system.c b/src/backends/windows/system.c index 6409860f..771a03c0 100644 --- a/src/backends/windows/system.c +++ b/src/backends/windows/system.c @@ -85,6 +85,7 @@ Sys_Error(const char *error, ...) void Sys_Quit(void) { + const qboolean free_console = (dedicated && dedicated->value); timeEndPeriod(1); #ifndef DEDICATED_ONLY @@ -93,7 +94,7 @@ Sys_Quit(void) Qcommon_Shutdown(); - if (dedicated && dedicated->value) + if (free_console) { FreeConsole(); } diff --git a/src/client/refresh/gl1/gl1_image.c b/src/client/refresh/gl1/gl1_image.c index f8303713..1bfd886f 100644 --- a/src/client/refresh/gl1/gl1_image.c +++ b/src/client/refresh/gl1/gl1_image.c @@ -638,11 +638,6 @@ R_BuildPalettedTexture(unsigned char *paletted_texture, unsigned char *scaled, } } -// Windows headers don't define this constant. -#ifndef GL_GENERATE_MIPMAP -#define GL_GENERATE_MIPMAP 0x8191 -#endif - qboolean R_Upload32Native(unsigned *data, int width, int height, qboolean mipmap) { diff --git a/src/client/refresh/gl1/gl1_scrap.c b/src/client/refresh/gl1/gl1_scrap.c index 5cd4e6e6..3a769300 100644 --- a/src/client/refresh/gl1/gl1_scrap.c +++ b/src/client/refresh/gl1/gl1_scrap.c @@ -19,7 +19,7 @@ * * ======================================================================= * - * Allocate all the little status bar obejcts into a single texture + * Allocate all the little status bar objects into a single texture * to crutch up inefficient hardware / drivers. * * ======================================================================= @@ -30,7 +30,6 @@ int scrap_allocated[MAX_SCRAPS][BLOCK_WIDTH]; byte scrap_texels[MAX_SCRAPS][BLOCK_WIDTH * BLOCK_HEIGHT]; qboolean scrap_dirty; -int scrap_uploads; qboolean R_Upload8(byte *data, int width, @@ -93,7 +92,6 @@ Scrap_AllocBlock(int w, int h, int *x, int *y) void Scrap_Upload(void) { - scrap_uploads++; R_Bind(TEXNUM_SCRAPS); R_Upload8(scrap_texels[0], BLOCK_WIDTH, BLOCK_HEIGHT, false, false); scrap_dirty = false; diff --git a/src/client/refresh/gl1/header/qgl.h b/src/client/refresh/gl1/header/qgl.h index cf4a04c2..d3bcc510 100644 --- a/src/client/refresh/gl1/header/qgl.h +++ b/src/client/refresh/gl1/header/qgl.h @@ -49,6 +49,7 @@ #define GL_POINT_SIZE_MIN 0x8126 #define GL_POINT_SIZE_MAX 0x8127 #define GL_POINT_DISTANCE_ATTENUATION 0x8129 +#define GL_GENERATE_MIPMAP 0x8191 #endif #ifndef GL_VERSION_1_3 From 81fd2c102738cf54eb4f6e24c3a242a6cadbfdf7 Mon Sep 17 00:00:00 2001 From: Jaime Moreira Date: Sat, 11 May 2024 18:18:28 -0400 Subject: [PATCH 2/3] Increased lightmap size in GL1 Controlled by new cvar, gl1_biglightmaps. Size is now up to 512x512, for a max quantity of 8 lightmaps. Should reduce rebinding of them, and reduce the number of calls to glTexSubImage2D(), although it may increase data transfer on each call. --- doc/040_cvarlist.md | 4 +++ src/client/refresh/gl1/gl1_lightmap.c | 49 +++++++++++++++++---------- src/client/refresh/gl1/gl1_main.c | 32 ++++++++++++++++- src/client/refresh/gl1/gl1_surf.c | 37 ++++++++++---------- src/client/refresh/gl1/header/local.h | 9 +++-- 5 files changed, 92 insertions(+), 39 deletions(-) diff --git a/doc/040_cvarlist.md b/doc/040_cvarlist.md index 2cad40a8..531521c8 100644 --- a/doc/040_cvarlist.md +++ b/doc/040_cvarlist.md @@ -460,6 +460,10 @@ Set `0` by default. ## Graphics (OpenGL 1.4 only) +* **gl1_biglightmaps**: Enables lightmaps to use a bigger + texture size, which means fewer texture switches, improving + performance. Default is `1` (enabled). Requires a `vid_restart`. + * **gl1_intensity**: Sets the color intensity. Must be a floating point value, at least `1.0` - default is `2.0`. Applied when textures are loaded, so it needs a `vid_restart`. diff --git a/src/client/refresh/gl1/gl1_lightmap.c b/src/client/refresh/gl1/gl1_lightmap.c index 2ee2dedc..4857d6c3 100644 --- a/src/client/refresh/gl1/gl1_lightmap.c +++ b/src/client/refresh/gl1/gl1_lightmap.c @@ -42,13 +42,19 @@ LM_FreeLightmapBuffers(void) } gl_lms.lightmap_buffer[i] = NULL; } + + if (gl_lms.allocated) + { + free(gl_lms.allocated); + gl_lms.allocated = NULL; + } } static void LM_AllocLightmapBuffer(int buffer, qboolean clean) { - static const unsigned int lightmap_size = - BLOCK_WIDTH * BLOCK_HEIGHT * LIGHTMAP_BYTES; + const unsigned int lightmap_size = + gl_state.block_width * gl_state.block_height * LIGHTMAP_BYTES; if (!gl_lms.lightmap_buffer[buffer]) { @@ -68,7 +74,7 @@ LM_AllocLightmapBuffer(int buffer, qboolean clean) void LM_InitBlock(void) { - memset(gl_lms.allocated, 0, sizeof(gl_lms.allocated)); + memset(gl_lms.allocated, 0, gl_state.block_width * sizeof(int)); if (gl_config.multitexture) { @@ -91,7 +97,7 @@ LM_UploadBlock(qboolean dynamic) { int i; - for (i = 0; i < BLOCK_WIDTH; i++) + for (i = 0; i < gl_state.block_width; i++) { if (gl_lms.allocated[i] > height) { @@ -99,7 +105,7 @@ LM_UploadBlock(qboolean dynamic) } } - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, BLOCK_WIDTH, + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, gl_state.block_width, height, GL_LIGHTMAP_FORMAT, GL_UNSIGNED_BYTE, gl_lms.lightmap_buffer[buffer]); } @@ -107,10 +113,11 @@ LM_UploadBlock(qboolean dynamic) { gl_lms.internal_format = GL_LIGHTMAP_FORMAT; glTexImage2D(GL_TEXTURE_2D, 0, gl_lms.internal_format, - BLOCK_WIDTH, BLOCK_HEIGHT, 0, GL_LIGHTMAP_FORMAT, - GL_UNSIGNED_BYTE, gl_lms.lightmap_buffer[buffer]); + gl_state.block_width, gl_state.block_height, + 0, GL_LIGHTMAP_FORMAT, GL_UNSIGNED_BYTE, + gl_lms.lightmap_buffer[buffer]); - if (++gl_lms.current_lightmap_texture == MAX_LIGHTMAPS) + if (++gl_lms.current_lightmap_texture == gl_state.max_lightmaps) { ri.Sys_Error(ERR_DROP, "LM_UploadBlock() - MAX_LIGHTMAPS exceeded\n"); @@ -127,9 +134,9 @@ LM_AllocBlock(int w, int h, int *x, int *y) int i, j; int best, best2; - best = BLOCK_HEIGHT; + best = gl_state.block_height; - for (i = 0; i < BLOCK_WIDTH - w; i++) + for (i = 0; i < gl_state.block_width - w; i++) { best2 = 0; @@ -154,7 +161,7 @@ LM_AllocBlock(int w, int h, int *x, int *y) } } - if (best + h > BLOCK_HEIGHT) + if (best + h > gl_state.block_height) { return false; } @@ -222,13 +229,13 @@ LM_BuildPolygonFromSurface(model_t *currentmodel, msurface_t *fa) s -= fa->texturemins[0]; s += fa->light_s * 16; s += 8; - s /= BLOCK_WIDTH * 16; /* fa->texinfo->texture->width; */ + s /= gl_state.block_width * 16; /* fa->texinfo->texture->width; */ t = DotProduct(vec, fa->texinfo->vecs[1]) + fa->texinfo->vecs[1][3]; t -= fa->texturemins[1]; t += fa->light_t * 16; t += 8; - t /= BLOCK_HEIGHT * 16; /* fa->texinfo->texture->height; */ + t /= gl_state.block_height * 16; /* fa->texinfo->texture->height; */ poly->verts[i][5] = s; poly->verts[i][6] = t; @@ -265,10 +272,10 @@ LM_CreateSurfaceLightmap(msurface_t *surf) buffer = (gl_config.multitexture)? surf->lightmaptexturenum : 0; base = gl_lms.lightmap_buffer[buffer]; - base += (surf->light_t * BLOCK_WIDTH + surf->light_s) * LIGHTMAP_BYTES; + base += (surf->light_t * gl_state.block_width + surf->light_s) * LIGHTMAP_BYTES; R_SetCacheState(surf); - R_BuildLightMap(surf, base, BLOCK_WIDTH * LIGHTMAP_BYTES); + R_BuildLightMap(surf, base, gl_state.block_width * LIGHTMAP_BYTES); } void @@ -277,8 +284,13 @@ LM_BeginBuildingLightmaps(model_t *m) static lightstyle_t lightstyles[MAX_LIGHTSTYLES]; int i; - memset(gl_lms.allocated, 0, sizeof(gl_lms.allocated)); LM_FreeLightmapBuffers(); + gl_lms.allocated = (int*)malloc(gl_state.block_width * sizeof(int)); + if (!gl_lms.allocated) + { + ri.Sys_Error(ERR_FATAL, "Could not create lightmap allocator\n"); + } + memset(gl_lms.allocated, 0, gl_state.block_width * sizeof(int)); r_framecount = 1; /* no dlightcache */ @@ -317,8 +329,9 @@ LM_BeginBuildingLightmaps(model_t *m) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexImage2D(GL_TEXTURE_2D, 0, gl_lms.internal_format, - BLOCK_WIDTH, BLOCK_HEIGHT, 0, GL_LIGHTMAP_FORMAT, - GL_UNSIGNED_BYTE, gl_lms.lightmap_buffer[0]); + gl_state.block_width, gl_state.block_height, + 0, GL_LIGHTMAP_FORMAT, GL_UNSIGNED_BYTE, + gl_lms.lightmap_buffer[0]); } void diff --git a/src/client/refresh/gl1/gl1_main.c b/src/client/refresh/gl1/gl1_main.c index 9f95e83b..914590b9 100644 --- a/src/client/refresh/gl1/gl1_main.c +++ b/src/client/refresh/gl1/gl1_main.c @@ -91,6 +91,7 @@ cvar_t *gl1_particle_square; cvar_t *gl1_palettedtexture; cvar_t *gl1_pointparameters; cvar_t *gl1_multitexture; +cvar_t *gl1_biglightmaps; cvar_t *gl_drawbuffer; cvar_t *gl_lightmap; @@ -1217,6 +1218,7 @@ R_Register(void) gl1_palettedtexture = ri.Cvar_Get("r_palettedtextures", "0", CVAR_ARCHIVE); gl1_pointparameters = ri.Cvar_Get("gl1_pointparameters", "1", CVAR_ARCHIVE); gl1_multitexture = ri.Cvar_Get("gl1_multitexture", "2", CVAR_ARCHIVE); + gl1_biglightmaps = ri.Cvar_Get("gl1_biglightmaps", "1", CVAR_ARCHIVE); gl_drawbuffer = ri.Cvar_Get("gl_drawbuffer", "GL_BACK", 0); r_vsync = ri.Cvar_Get("r_vsync", "1", CVAR_ARCHIVE); @@ -1397,7 +1399,7 @@ R_SetMode(void) qboolean RI_Init(void) { - int j; + int j, max_tex_size; byte *colormap; extern float r_turbsin[256]; @@ -1639,6 +1641,34 @@ RI_Init(void) // ---- + /* Big lightmaps */ + R_Printf(PRINT_ALL, " - Big lightmaps: "); + + gl_state.block_width = BLOCK_WIDTH; + gl_state.block_height = BLOCK_HEIGHT; + gl_state.max_lightmaps = MAX_LIGHTMAPS; + glGetIntegerv (GL_MAX_TEXTURE_SIZE, &max_tex_size); + if (max_tex_size > BLOCK_WIDTH) + { + if (gl1_biglightmaps->value) + { + gl_state.block_width = gl_state.block_height = Q_min(max_tex_size, 512); + gl_state.max_lightmaps = (BLOCK_WIDTH * BLOCK_HEIGHT * MAX_LIGHTMAPS) + / (gl_state.block_width * gl_state.block_height); + R_Printf(PRINT_ALL, "Okay\n"); + } + else + { + R_Printf(PRINT_ALL, "Disabled\n"); + } + } + else + { + R_Printf(PRINT_ALL, "Failed, detected texture size = %d\n", max_tex_size); + } + + // ---- + R_SetDefaultState(); R_InitImages(); diff --git a/src/client/refresh/gl1/gl1_surf.c b/src/client/refresh/gl1/gl1_surf.c index e60d78c2..d0a2fd72 100644 --- a/src/client/refresh/gl1/gl1_surf.c +++ b/src/client/refresh/gl1/gl1_surf.c @@ -117,7 +117,7 @@ R_DrawTriangleOutlines(void) glDisable(GL_DEPTH_TEST); glColor4f(1, 1, 1, 1); - for (i = 0; i < MAX_LIGHTMAPS; i++) + for (i = 0; i < gl_state.max_lightmaps; i++) { msurface_t *surf; @@ -269,7 +269,7 @@ R_BlendLightmaps(const model_t *currentmodel) } /* render static lightmaps first */ - for (i = 1; i < MAX_LIGHTMAPS; i++) + for (i = 1; i < gl_state.max_lightmaps; i++) { if (gl_lms.lightmap_surfaces[i]) { @@ -326,10 +326,10 @@ R_BlendLightmaps(const model_t *currentmodel) if (LM_AllocBlock(smax, tmax, &surf->dlight_s, &surf->dlight_t)) { base = gl_lms.lightmap_buffer[0]; - base += (surf->dlight_t * BLOCK_WIDTH + + base += (surf->dlight_t * gl_state.block_width + surf->dlight_s) * LIGHTMAP_BYTES; - R_BuildLightMap(surf, base, BLOCK_WIDTH * LIGHTMAP_BYTES); + R_BuildLightMap(surf, base, gl_state.block_width * LIGHTMAP_BYTES); } else { @@ -353,8 +353,8 @@ R_BlendLightmaps(const model_t *currentmodel) } R_DrawGLPolyChain(drawsurf->polys, - (drawsurf->light_s - drawsurf->dlight_s) * (1.0 / 128.0), - (drawsurf->light_t - drawsurf->dlight_t) * (1.0 / 128.0)); + (drawsurf->light_s - drawsurf->dlight_s) * (1.0 / (float)gl_state.block_width), + (drawsurf->light_t - drawsurf->dlight_t) * (1.0 / (float)gl_state.block_height)); } } @@ -372,10 +372,10 @@ R_BlendLightmaps(const model_t *currentmodel) } base = gl_lms.lightmap_buffer[0]; - base += (surf->dlight_t * BLOCK_WIDTH + + base += (surf->dlight_t * gl_state.block_width + surf->dlight_s) * LIGHTMAP_BYTES; - R_BuildLightMap(surf, base, BLOCK_WIDTH * LIGHTMAP_BYTES); + R_BuildLightMap(surf, base, gl_state.block_width * LIGHTMAP_BYTES); } } @@ -397,8 +397,8 @@ R_BlendLightmaps(const model_t *currentmodel) } R_DrawGLPolyChain(surf->polys, - (surf->light_s - surf->dlight_s) * (1.0 / 128.0), - (surf->light_t - surf->dlight_t) * (1.0 / 128.0)); + (surf->light_s - surf->dlight_s) * (1.0 / (float)gl_state.block_width), + (surf->light_t - surf->dlight_t) * (1.0 / (float)gl_state.block_height)); } } } @@ -723,12 +723,12 @@ static void R_UploadDynamicLights(msurface_t *surf) { int map, smax, tmax; - byte temp[BLOCK_WIDTH * BLOCK_HEIGHT]; if ( !gl_config.multitexture || !R_HasDynamicLights(surf, &map) ) { return; } + YQ2_VLA(byte, temp, gl_state.block_width * gl_state.block_height); smax = (surf->extents[0] >> 4) + 1; tmax = (surf->extents[1] >> 4) + 1; @@ -738,6 +738,7 @@ R_UploadDynamicLights(msurface_t *surf) R_Bind(gl_state.lightmap_textures + surf->lightmaptexturenum); glTexSubImage2D(GL_TEXTURE_2D, 0, surf->light_s, surf->light_t, smax, tmax, GL_LIGHTMAP_FORMAT, GL_UNSIGNED_BYTE, temp); + YQ2_VLAFREE(temp); } /* Upload dynamic lights to each lightmap texture (multitexture path only) */ @@ -754,9 +755,9 @@ R_RegenAllLightmaps() return; } - glPixelStorei(GL_UNPACK_ROW_LENGTH, BLOCK_WIDTH); + glPixelStorei(GL_UNPACK_ROW_LENGTH, gl_state.block_width); - for (i = 1; i < MAX_LIGHTMAPS; i++) + for (i = 1; i < gl_state.max_lightmaps; i++) { if (!gl_lms.lightmap_surfaces[i] || !gl_lms.lightmap_buffer[i]) { @@ -764,8 +765,8 @@ R_RegenAllLightmaps() } affected_lightmap = false; - bt = BLOCK_HEIGHT; - bl = BLOCK_WIDTH; + bt = gl_state.block_height; + bl = gl_state.block_width; bb = br = 0; for (surf = gl_lms.lightmap_surfaces[i]; @@ -787,9 +788,9 @@ R_RegenAllLightmaps() bottom = surf->light_t + tmax; base = gl_lms.lightmap_buffer[i]; - base += (top * BLOCK_WIDTH + left) * LIGHTMAP_BYTES; + base += (top * gl_state.block_width + left) * LIGHTMAP_BYTES; - R_BuildLightMap(surf, base, BLOCK_WIDTH * LIGHTMAP_BYTES); + R_BuildLightMap(surf, base, gl_state.block_width * LIGHTMAP_BYTES); R_UpdateSurfCache(surf, map); if (left < bl) @@ -816,7 +817,7 @@ R_RegenAllLightmaps() } base = gl_lms.lightmap_buffer[i]; - base += (bt * BLOCK_WIDTH + bl) * LIGHTMAP_BYTES; + base += (bt * gl_state.block_width + bl) * LIGHTMAP_BYTES; // upload changes R_Bind(gl_state.lightmap_textures + i); diff --git a/src/client/refresh/gl1/header/local.h b/src/client/refresh/gl1/header/local.h index 1e60b092..b912543b 100644 --- a/src/client/refresh/gl1/header/local.h +++ b/src/client/refresh/gl1/header/local.h @@ -44,7 +44,7 @@ #define TEXNUM_IMAGES 1153 #define MAX_GLTEXTURES 1024 #define MAX_SCRAPS 1 -#define BLOCK_WIDTH 128 +#define BLOCK_WIDTH 128 // default values; now defined in glstate_t #define BLOCK_HEIGHT 128 #define REF_VERSION "Yamagi Quake II OpenGL Refresher" #define BACKFACE_EPSILON 0.01 @@ -163,6 +163,7 @@ extern cvar_t *gl1_overbrightbits; extern cvar_t *gl1_palettedtexture; extern cvar_t *gl1_pointparameters; extern cvar_t *gl1_multitexture; +extern cvar_t *gl1_biglightmaps; extern cvar_t *gl1_particle_min_size; extern cvar_t *gl1_particle_max_size; @@ -390,6 +391,10 @@ typedef struct enum stereo_modes stereo_mode; qboolean stencil; + + int block_width, // replaces BLOCK_WIDTH + block_height, // replaces BLOCK_HEIGHT + max_lightmaps; // the larger the lightmaps, the fewer the max lightmaps } glstate_t; typedef struct @@ -399,7 +404,7 @@ typedef struct msurface_t *lightmap_surfaces[MAX_LIGHTMAPS]; - int allocated[BLOCK_WIDTH]; + int *allocated; // formerly allocated[BLOCK_WIDTH]; /* the lightmap texture data needs to be kept in main memory so texsubimage can update properly */ From 0f307cc9c1654d8492ca10cc4584d7cf24a383c3 Mon Sep 17 00:00:00 2001 From: Jaime Moreira Date: Sat, 11 May 2024 18:20:13 -0400 Subject: [PATCH 3/3] GL1 scrap/atlas configurable size Controlled by gl1_biglightmaps cvar, works like new lightmaps. Max size is 384x384; a bigger size is not justified. Added a transparent border so colors from one picture don't bleed into the next. --- doc/040_cvarlist.md | 2 +- src/client/refresh/gl1/gl1_image.c | 12 ++--- src/client/refresh/gl1/gl1_main.c | 8 ++++ src/client/refresh/gl1/gl1_scrap.c | 66 ++++++++++++++++++++++++--- src/client/refresh/gl1/header/local.h | 4 +- 5 files changed, 78 insertions(+), 14 deletions(-) diff --git a/doc/040_cvarlist.md b/doc/040_cvarlist.md index 531521c8..eb7bc7d1 100644 --- a/doc/040_cvarlist.md +++ b/doc/040_cvarlist.md @@ -460,7 +460,7 @@ Set `0` by default. ## Graphics (OpenGL 1.4 only) -* **gl1_biglightmaps**: Enables lightmaps to use a bigger +* **gl1_biglightmaps**: Enables lightmaps and scrap to use a bigger texture size, which means fewer texture switches, improving performance. Default is `1` (enabled). Requires a `vid_restart`. diff --git a/src/client/refresh/gl1/gl1_image.c b/src/client/refresh/gl1/gl1_image.c index 1bfd886f..83061cd2 100644 --- a/src/client/refresh/gl1/gl1_image.c +++ b/src/client/refresh/gl1/gl1_image.c @@ -31,7 +31,7 @@ int numgltextures; static int image_max = 0; int base_textureid; /* gltextures[i] = base_textureid+i */ extern qboolean scrap_dirty; -extern byte scrap_texels[MAX_SCRAPS][BLOCK_WIDTH * BLOCK_HEIGHT]; +extern byte *scrap_texels[MAX_SCRAPS]; static byte intensitytable[256]; static unsigned char gammatable[256]; @@ -1040,17 +1040,17 @@ R_LoadPic(const char *name, byte *pic, int width, int realwidth, { for (j = 0; j < image->width; j++, k++) { - scrap_texels[texnum][(y + i) * BLOCK_WIDTH + x + j] = pic[k]; + scrap_texels[texnum][(y + i) * gl_state.scrap_width + x + j] = pic[k]; } } image->texnum = TEXNUM_SCRAPS + 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 / gl_state.scrap_width; + image->sh = (float)(x + image->width) / gl_state.scrap_width; + image->tl = (float)y / gl_state.scrap_height; + image->th = (float)(y + image->height) / gl_state.scrap_height; } else { diff --git a/src/client/refresh/gl1/gl1_main.c b/src/client/refresh/gl1/gl1_main.c index 914590b9..b9f21f39 100644 --- a/src/client/refresh/gl1/gl1_main.c +++ b/src/client/refresh/gl1/gl1_main.c @@ -146,6 +146,8 @@ cvar_t *gl1_stereo_convergence; refimport_t ri; void LM_FreeLightmapBuffers(void); +void Scrap_Free(void); +void Scrap_Init(void); void R_RotateForEntity(entity_t *e) @@ -1647,6 +1649,8 @@ RI_Init(void) gl_state.block_width = BLOCK_WIDTH; gl_state.block_height = BLOCK_HEIGHT; gl_state.max_lightmaps = MAX_LIGHTMAPS; + gl_state.scrap_width = BLOCK_WIDTH; + gl_state.scrap_height = BLOCK_HEIGHT; glGetIntegerv (GL_MAX_TEXTURE_SIZE, &max_tex_size); if (max_tex_size > BLOCK_WIDTH) { @@ -1655,6 +1659,8 @@ RI_Init(void) gl_state.block_width = gl_state.block_height = Q_min(max_tex_size, 512); gl_state.max_lightmaps = (BLOCK_WIDTH * BLOCK_HEIGHT * MAX_LIGHTMAPS) / (gl_state.block_width * gl_state.block_height); + gl_state.scrap_width = gl_state.scrap_height = + (gl_config.npottextures)? Q_min(max_tex_size, 384) : Q_min(max_tex_size, 256); R_Printf(PRINT_ALL, "Okay\n"); } else @@ -1671,6 +1677,7 @@ RI_Init(void) R_SetDefaultState(); + Scrap_Init(); R_InitImages(); Mod_Init(); R_InitParticleTexture(); @@ -1688,6 +1695,7 @@ RI_Shutdown(void) ri.Cmd_RemoveCommand("gl_strings"); LM_FreeLightmapBuffers(); + Scrap_Free(); Mod_FreeAll(); R_ShutdownImages(); diff --git a/src/client/refresh/gl1/gl1_scrap.c b/src/client/refresh/gl1/gl1_scrap.c index 3a769300..0f729683 100644 --- a/src/client/refresh/gl1/gl1_scrap.c +++ b/src/client/refresh/gl1/gl1_scrap.c @@ -27,8 +27,8 @@ #include "header/local.h" -int scrap_allocated[MAX_SCRAPS][BLOCK_WIDTH]; -byte scrap_texels[MAX_SCRAPS][BLOCK_WIDTH * BLOCK_HEIGHT]; +int *scrap_allocated[MAX_SCRAPS]; +byte *scrap_texels[MAX_SCRAPS]; qboolean scrap_dirty; qboolean R_Upload8(byte *data, @@ -44,12 +44,14 @@ Scrap_AllocBlock(int w, int h, int *x, int *y) int i, j; int best, best2; int texnum; + w += 2; // add an empty border to all sides + h += 2; for (texnum = 0; texnum < MAX_SCRAPS; texnum++) { - best = BLOCK_HEIGHT; + best = gl_state.scrap_height; - for (i = 0; i < BLOCK_WIDTH - w; i++) + for (i = 0; i < gl_state.scrap_width - w; i++) { best2 = 0; @@ -73,7 +75,7 @@ Scrap_AllocBlock(int w, int h, int *x, int *y) } } - if (best + h > BLOCK_HEIGHT) + if (best + h > gl_state.scrap_height) { continue; } @@ -82,6 +84,8 @@ Scrap_AllocBlock(int w, int h, int *x, int *y) { scrap_allocated[texnum][*x + i] = best + h; } + (*x)++; // jump the border + (*y)++; return texnum; } @@ -93,7 +97,57 @@ void Scrap_Upload(void) { R_Bind(TEXNUM_SCRAPS); - R_Upload8(scrap_texels[0], BLOCK_WIDTH, BLOCK_HEIGHT, false, false); + R_Upload8(scrap_texels[0], gl_state.scrap_width, + gl_state.scrap_height, false, false); scrap_dirty = false; } +void +Scrap_Free(void) +{ + for (int i = 0; i < MAX_SCRAPS; i++) + { + if (scrap_allocated[i]) + { + free(scrap_allocated[i]); + } + scrap_allocated[i] = NULL; + + if (scrap_texels[i]) + { + free(scrap_texels[i]); + } + scrap_texels[i] = NULL; + } +} + +void +Scrap_Init(void) +{ + const unsigned int allocd_size = gl_state.scrap_width * sizeof(int); + const unsigned int texels_size = gl_state.scrap_width + * gl_state.scrap_height * sizeof(byte); + int i; + + Scrap_Free(); + + for (i = 0; i < MAX_SCRAPS; i++) + { + if (!scrap_allocated[i]) + { + scrap_allocated[i] = malloc (allocd_size) ; + } + if (!scrap_texels[i]) + { + scrap_texels[i] = malloc (texels_size) ; + } + + if (!scrap_allocated[i] || !scrap_texels[i]) + { + ri.Sys_Error(ERR_FATAL, "Could not allocate scrap memory.\n"); + } + memset (scrap_allocated[i], 0, allocd_size); // empty + memset (scrap_texels[i], 255, texels_size); // transparent + } +} + diff --git a/src/client/refresh/gl1/header/local.h b/src/client/refresh/gl1/header/local.h index b912543b..03cfe3d4 100644 --- a/src/client/refresh/gl1/header/local.h +++ b/src/client/refresh/gl1/header/local.h @@ -394,7 +394,9 @@ typedef struct int block_width, // replaces BLOCK_WIDTH block_height, // replaces BLOCK_HEIGHT - max_lightmaps; // the larger the lightmaps, the fewer the max lightmaps + max_lightmaps, // the larger the lightmaps, the fewer the max lightmaps + scrap_width, // size for scrap (atlas of 2D elements) + scrap_height; } glstate_t; typedef struct