From 3dde0d58590ea17b97b1a605d6d23d008b3e502f Mon Sep 17 00:00:00 2001 From: Jaime Moreira Date: Tue, 23 Apr 2024 12:21:40 -0400 Subject: [PATCH 1/6] Texture chains working properly Somehow, R_TextureAnimation() returns different results for the same surface when called consecutively. We force it to be called once, so the chains in R_DrawTextureChains() are getting respected now. --- src/client/refresh/gl1/gl1_surf.c | 22 ++++++---------------- 1 file changed, 6 insertions(+), 16 deletions(-) diff --git a/src/client/refresh/gl1/gl1_surf.c b/src/client/refresh/gl1/gl1_surf.c index ac67df9d..92febf2b 100644 --- a/src/client/refresh/gl1/gl1_surf.c +++ b/src/client/refresh/gl1/gl1_surf.c @@ -418,17 +418,12 @@ static void R_RenderBrushPoly(entity_t *currententity, msurface_t *fa) { int maps; - image_t *image; qboolean is_dynamic = false; c_brush_polys++; - image = R_TextureAnimation(currententity, fa->texinfo); - if (fa->flags & SURF_DRAWTURB) { - R_Bind(image->texnum); - /* This is a hack ontop of a hack. Warping surfaces like those generated by R_EmitWaterPolys() don't have a lightmap. Original Quake II therefore negated the global intensity on those surfaces, because otherwise they @@ -459,12 +454,8 @@ R_RenderBrushPoly(entity_t *currententity, msurface_t *fa) return; } - else - { - R_Bind(image->texnum); - R_TexEnv(GL_REPLACE); - } + R_TexEnv(GL_REPLACE); if (fa->texinfo->flags & SURF_FLOWING) { @@ -625,6 +616,7 @@ R_DrawTextureChains(entity_t *currententity) for ( ; s; s = s->texturechain) { + R_Bind(image->texnum); // may reset because of dynamic lighting in R_RenderBrushPoly R_RenderBrushPoly(currententity, s); } @@ -642,6 +634,7 @@ R_DrawInlineBModel(entity_t *currententity, const model_t *currentmodel) float dot; msurface_t *psurf; dlight_t *lt; + image_t *image; /* calculate dynamic lighting for bmodel */ if (!gl1_flashblend->value) @@ -685,6 +678,8 @@ R_DrawInlineBModel(entity_t *currententity, const model_t *currentmodel) } else { + image = R_TextureAnimation(currententity, psurf->texinfo); + R_Bind(image->texnum); R_RenderBrushPoly(currententity, psurf); } } @@ -692,7 +687,6 @@ R_DrawInlineBModel(entity_t *currententity, const model_t *currentmodel) if (!(currententity->flags & RF_TRANSLUCENT)) { - R_BlendLightmaps(currentmodel); } else @@ -917,7 +911,6 @@ void R_DrawWorld(void) { entity_t ent; - const model_t *currentmodel; if (!r_drawworld->value) { @@ -929,8 +922,6 @@ R_DrawWorld(void) return; } - currentmodel = r_worldmodel; - VectorCopy(r_newrefdef.vieworg, modelorg); /* auto cycle the world frame for texture animation */ @@ -945,7 +936,7 @@ R_DrawWorld(void) R_ClearSkyBox(); R_RecursiveWorldNode(&ent, r_worldmodel->nodes); R_DrawTextureChains(&ent); - R_BlendLightmaps(currentmodel); + R_BlendLightmaps(r_worldmodel); R_DrawSkyBox(); R_DrawTriangleOutlines(); } @@ -1045,4 +1036,3 @@ R_MarkLeaves(void) } } } - From 79bb13d3a7da201f681392100766f01762e07389 Mon Sep 17 00:00:00 2001 From: Jaime Moreira Date: Tue, 23 Apr 2024 12:23:00 -0400 Subject: [PATCH 2/6] Updated OpenGL definitions in qgl.h Using GL 1.4 declarations in code, although 'point parameters' will use legacy extensions if they're the only ones found. Moved stuff out of local.h; better to have definitions in one place. Extracted from . --- src/client/refresh/gl1/gl1_main.c | 20 +++++-- src/client/refresh/gl1/gl1_misc.c | 6 +- src/client/refresh/gl1/gl1_sdl.c | 6 -- src/client/refresh/gl1/gl1_surf.c | 16 +++--- src/client/refresh/gl1/header/local.h | 18 ------ src/client/refresh/gl1/header/qgl.h | 81 +++++++++++---------------- src/client/refresh/gl1/qgl.c | 13 ++--- 7 files changed, 65 insertions(+), 95 deletions(-) diff --git a/src/client/refresh/gl1/gl1_main.c b/src/client/refresh/gl1/gl1_main.c index a328f16e..5928d97f 100644 --- a/src/client/refresh/gl1/gl1_main.c +++ b/src/client/refresh/gl1/gl1_main.c @@ -1468,17 +1468,29 @@ RI_Init(void) /* Point parameters */ R_Printf(PRINT_ALL, " - Point parameters: "); - if (strstr(gl_config.extensions_string, "GL_ARB_point_parameters")) + if ( strstr(gl_config.extensions_string, "GL_ARB_point_parameters") || + strstr(gl_config.extensions_string, "GL_EXT_point_parameters") ) // should exist for all OGL 1.4 hw... { - qglPointParameterfARB = (void (APIENTRY *)(GLenum, GLfloat))RI_GetProcAddress ( "glPointParameterfARB" ); - qglPointParameterfvARB = (void (APIENTRY *)(GLenum, const GLfloat *))RI_GetProcAddress ( "glPointParameterfvARB" ); + qglPointParameterf = (void (APIENTRY *)(GLenum, GLfloat))RI_GetProcAddress ( "glPointParameterf" ); + qglPointParameterfv = (void (APIENTRY *)(GLenum, const GLfloat *))RI_GetProcAddress ( "glPointParameterfv" ); + + if (!qglPointParameterf || !qglPointParameterfv) + { + qglPointParameterf = (void (APIENTRY *)(GLenum, GLfloat))RI_GetProcAddress ( "glPointParameterfARB" ); + qglPointParameterfv = (void (APIENTRY *)(GLenum, const GLfloat *))RI_GetProcAddress ( "glPointParameterfvARB" ); + } + if (!qglPointParameterf || !qglPointParameterfv) + { + qglPointParameterf = (void (APIENTRY *)(GLenum, GLfloat))RI_GetProcAddress ( "glPointParameterfEXT" ); + qglPointParameterfv = (void (APIENTRY *)(GLenum, const GLfloat *))RI_GetProcAddress ( "glPointParameterfvEXT" ); + } } gl_config.pointparameters = false; if (gl1_pointparameters->value) { - if (qglPointParameterfARB && qglPointParameterfvARB) + if (qglPointParameterf && qglPointParameterfv) { gl_config.pointparameters = true; R_Printf(PRINT_ALL, "Okay\n"); diff --git a/src/client/refresh/gl1/gl1_misc.c b/src/client/refresh/gl1/gl1_misc.c index 9f52e6d2..1885b0af 100644 --- a/src/client/refresh/gl1/gl1_misc.c +++ b/src/client/refresh/gl1/gl1_misc.c @@ -208,9 +208,9 @@ R_SetDefaultState(void) attenuations[1] = gl1_particle_att_b->value; attenuations[2] = gl1_particle_att_c->value; - qglPointParameterfARB(GL_POINT_SIZE_MIN_EXT, gl1_particle_min_size->value); - qglPointParameterfARB(GL_POINT_SIZE_MAX_EXT, gl1_particle_max_size->value); - qglPointParameterfvARB(GL_DISTANCE_ATTENUATION_EXT, attenuations); + qglPointParameterf(GL_POINT_SIZE_MIN, gl1_particle_min_size->value); + qglPointParameterf(GL_POINT_SIZE_MAX, gl1_particle_max_size->value); + qglPointParameterfv(GL_POINT_DISTANCE_ATTENUATION, attenuations); /* GL_POINT_SMOOTH is not implemented by some OpenGL drivers, especially the crappy Mesa3D backends like diff --git a/src/client/refresh/gl1/gl1_sdl.c b/src/client/refresh/gl1/gl1_sdl.c index ab1543bf..7623ea32 100644 --- a/src/client/refresh/gl1/gl1_sdl.c +++ b/src/client/refresh/gl1/gl1_sdl.c @@ -33,12 +33,6 @@ #include #endif -#if defined(__APPLE__) -#include -#else -#include -#endif - static SDL_Window* window = NULL; static SDL_GLContext context = NULL; qboolean IsHighDPIaware = false; diff --git a/src/client/refresh/gl1/gl1_surf.c b/src/client/refresh/gl1/gl1_surf.c index 92febf2b..53e4a01e 100644 --- a/src/client/refresh/gl1/gl1_surf.c +++ b/src/client/refresh/gl1/gl1_surf.c @@ -294,8 +294,8 @@ R_BlendLightmaps(const model_t *currentmodel) // Apply overbright bits to the static lightmaps if (gl1_overbrightbits->value) { - R_TexEnv(GL_COMBINE_EXT); - glTexEnvi(GL_TEXTURE_ENV, GL_RGB_SCALE_EXT, gl1_overbrightbits->value); + R_TexEnv(GL_COMBINE); + glTexEnvi(GL_TEXTURE_ENV, GL_RGB_SCALE, gl1_overbrightbits->value); } R_DrawGLPolyChain(surf->polys, 0, 0); @@ -353,8 +353,8 @@ R_BlendLightmaps(const model_t *currentmodel) // Apply overbright bits to the dynamic lightmaps if (gl1_overbrightbits->value) { - R_TexEnv(GL_COMBINE_EXT); - glTexEnvi(GL_TEXTURE_ENV, GL_RGB_SCALE_EXT, gl1_overbrightbits->value); + R_TexEnv(GL_COMBINE); + glTexEnvi(GL_TEXTURE_ENV, GL_RGB_SCALE, gl1_overbrightbits->value); } R_DrawGLPolyChain(drawsurf->polys, @@ -397,8 +397,8 @@ R_BlendLightmaps(const model_t *currentmodel) // Apply overbright bits to the remainder lightmaps if (gl1_overbrightbits->value) { - R_TexEnv(GL_COMBINE_EXT); - glTexEnvi(GL_TEXTURE_ENV, GL_RGB_SCALE_EXT, gl1_overbrightbits->value); + R_TexEnv(GL_COMBINE); + glTexEnvi(GL_TEXTURE_ENV, GL_RGB_SCALE, gl1_overbrightbits->value); } R_DrawGLPolyChain(surf->polys, @@ -439,8 +439,8 @@ R_RenderBrushPoly(entity_t *currententity, msurface_t *fa) They oversaturate otherwise. */ if (gl1_overbrightbits->value) { - R_TexEnv(GL_COMBINE_EXT); - glTexEnvi(GL_TEXTURE_ENV, GL_RGB_SCALE_EXT, 1); + R_TexEnv(GL_COMBINE); + glTexEnvi(GL_TEXTURE_ENV, GL_RGB_SCALE, 1); } else { diff --git a/src/client/refresh/gl1/header/local.h b/src/client/refresh/gl1/header/local.h index e98e9655..d2891110 100644 --- a/src/client/refresh/gl1/header/local.h +++ b/src/client/refresh/gl1/header/local.h @@ -39,24 +39,6 @@ #define GL_COLOR_INDEX8_EXT GL_COLOR_INDEX #endif -#ifndef GL_EXT_texture_filter_anisotropic - #define GL_TEXTURE_MAX_ANISOTROPY_EXT 0x84FE - #define GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT 0x84FF -#endif - -#ifndef GL_VERSION_1_3 - #define GL_TEXTURE0 0x84C0 - #define GL_TEXTURE1 0x84C1 -#endif - -#ifndef GL_MULTISAMPLE -#define GL_MULTISAMPLE 0x809D -#endif - -#ifndef GL_MULTISAMPLE_FILTER_HINT_NV -#define GL_MULTISAMPLE_FILTER_HINT_NV 0x8534 -#endif - #define TEXNUM_LIGHTMAPS 1024 #define TEXNUM_SCRAPS 1152 #define TEXNUM_IMAGES 1153 diff --git a/src/client/refresh/gl1/header/qgl.h b/src/client/refresh/gl1/header/qgl.h index 81f5ea47..076ab9e5 100644 --- a/src/client/refresh/gl1/header/qgl.h +++ b/src/client/refresh/gl1/header/qgl.h @@ -44,54 +44,37 @@ #define APIENTRY #endif -#define GL_SHARED_TEXTURE_PALETTE_EXT 0x81FB +// Extracted from +#ifndef GL_VERSION_1_4 +#define GL_POINT_SIZE_MIN 0x8126 +#define GL_POINT_SIZE_MAX 0x8127 +#define GL_POINT_DISTANCE_ATTENUATION 0x8129 +#endif -#define GL_POINT_SIZE_MIN_EXT 0x8126 -#define GL_POINT_SIZE_MAX_EXT 0x8127 -#define GL_DISTANCE_ATTENUATION_EXT 0x8129 +#ifndef GL_VERSION_1_3 +#define GL_MULTISAMPLE 0x809D +#define GL_COMBINE 0x8570 +#define GL_COMBINE_RGB 0x8571 +#define GL_COMBINE_ALPHA 0x8572 +#define GL_SOURCE0_RGB 0x8580 +#define GL_SOURCE1_RGB 0x8581 +#define GL_SOURCE0_ALPHA 0x8588 +#define GL_SOURCE1_ALPHA 0x8589 +#define GL_RGB_SCALE 0x8573 +#define GL_PREVIOUS 0x8578 +#endif -#ifndef GL_EXT_texture_env_combine -#define GL_COMBINE_EXT 0x8570 -#define GL_COMBINE_RGB_EXT 0x8571 -#define GL_COMBINE_ALPHA_EXT 0x8572 -#define GL_RGB_SCALE_EXT 0x8573 -#define GL_ADD_SIGNED_EXT 0x8574 -#define GL_INTERPOLATE_EXT 0x8575 -#define GL_CONSTANT_EXT 0x8576 -#define GL_PRIMARY_COLOR_EXT 0x8577 -#define GL_PREVIOUS_EXT 0x8578 -#define GL_SOURCE0_RGB_EXT 0x8580 -#define GL_SOURCE1_RGB_EXT 0x8581 -#define GL_SOURCE2_RGB_EXT 0x8582 -#define GL_SOURCE3_RGB_EXT 0x8583 -#define GL_SOURCE4_RGB_EXT 0x8584 -#define GL_SOURCE5_RGB_EXT 0x8585 -#define GL_SOURCE6_RGB_EXT 0x8586 -#define GL_SOURCE7_RGB_EXT 0x8587 -#define GL_SOURCE0_ALPHA_EXT 0x8588 -#define GL_SOURCE1_ALPHA_EXT 0x8589 -#define GL_SOURCE2_ALPHA_EXT 0x858A -#define GL_SOURCE3_ALPHA_EXT 0x858B -#define GL_SOURCE4_ALPHA_EXT 0x858C -#define GL_SOURCE5_ALPHA_EXT 0x858D -#define GL_SOURCE6_ALPHA_EXT 0x858E -#define GL_SOURCE7_ALPHA_EXT 0x858F -#define GL_OPERAND0_RGB_EXT 0x8590 -#define GL_OPERAND1_RGB_EXT 0x8591 -#define GL_OPERAND2_RGB_EXT 0x8592 -#define GL_OPERAND3_RGB_EXT 0x8593 -#define GL_OPERAND4_RGB_EXT 0x8594 -#define GL_OPERAND5_RGB_EXT 0x8595 -#define GL_OPERAND6_RGB_EXT 0x8596 -#define GL_OPERAND7_RGB_EXT 0x8597 -#define GL_OPERAND0_ALPHA_EXT 0x8598 -#define GL_OPERAND1_ALPHA_EXT 0x8599 -#define GL_OPERAND2_ALPHA_EXT 0x859A -#define GL_OPERAND3_ALPHA_EXT 0x859B -#define GL_OPERAND4_ALPHA_EXT 0x859C -#define GL_OPERAND5_ALPHA_EXT 0x859D -#define GL_OPERAND6_ALPHA_EXT 0x859E -#define GL_OPERAND7_ALPHA_EXT 0x859F +#ifndef GL_EXT_shared_texture_palette +#define GL_SHARED_TEXTURE_PALETTE_EXT 0x81FB +#endif + +#ifndef GL_EXT_texture_filter_anisotropic +#define GL_TEXTURE_MAX_ANISOTROPY_EXT 0x84FE +#define GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT 0x84FF +#endif + +#ifndef GL_NV_multisample_filter_hint +#define GL_MULTISAMPLE_FILTER_HINT_NV 0x8534 #endif // ======================================================================= @@ -99,7 +82,7 @@ /* * This is responsible for setting up our QGL extension pointers */ -qboolean QGL_Init ( void ); +void QGL_Init ( void ); /* * Unloads the specified DLL then nulls out all the proc pointers. @@ -107,8 +90,8 @@ qboolean QGL_Init ( void ); void QGL_Shutdown ( void ); /* GL extensions */ -extern void ( APIENTRY *qglPointParameterfARB ) ( GLenum param, GLfloat value ); -extern void ( APIENTRY *qglPointParameterfvARB ) ( GLenum param, +extern void ( APIENTRY *qglPointParameterf ) ( GLenum param, GLfloat value ); +extern void ( APIENTRY *qglPointParameterfv ) ( GLenum param, const GLfloat *value ); extern void ( APIENTRY *qglColorTableEXT ) ( GLenum, GLenum, GLsizei, GLenum, GLenum, const GLvoid * ); diff --git a/src/client/refresh/gl1/qgl.c b/src/client/refresh/gl1/qgl.c index 78d991e7..d176ae08 100644 --- a/src/client/refresh/gl1/qgl.c +++ b/src/client/refresh/gl1/qgl.c @@ -38,8 +38,8 @@ /* * GL extensions */ -void (APIENTRY *qglPointParameterfARB)(GLenum param, GLfloat value); -void (APIENTRY *qglPointParameterfvARB)(GLenum param, const GLfloat *value); +void (APIENTRY *qglPointParameterf)(GLenum param, GLfloat value); +void (APIENTRY *qglPointParameterfv)(GLenum param, const GLfloat *value); void (APIENTRY *qglColorTableEXT)(GLenum, GLenum, GLsizei, GLenum, GLenum, const GLvoid *); @@ -47,9 +47,9 @@ void (APIENTRY *qglColorTableEXT)(GLenum, GLenum, GLsizei, GLenum, GLenum, void QGL_EXT_Reset ( void ) { - qglPointParameterfARB = NULL; - qglPointParameterfvARB = NULL; - qglColorTableEXT = NULL; + qglPointParameterf = NULL; + qglPointParameterfv = NULL; + qglColorTableEXT = NULL; } /* ========================================================================= */ @@ -63,11 +63,10 @@ QGL_Shutdown ( void ) /* ========================================================================= */ -qboolean +void QGL_Init (void) { // Reset GL extension pointers QGL_EXT_Reset(); - return true; } From 3faa3db1677e653977ccad06614072ba04b8e320 Mon Sep 17 00:00:00 2001 From: Jaime Moreira Date: Tue, 23 Apr 2024 12:24:20 -0400 Subject: [PATCH 3/6] GL1 multitexture, initialization While it is based on the old, buggy multitexture implementation (removed in 68a12d4e & 8fe8f832), rework will be done to make it function as intended this time. For this commit, just init and function declarations. --- src/client/refresh/gl1/gl1_image.c | 113 +++++++++++++++++++++++++- src/client/refresh/gl1/gl1_main.c | 61 ++++++++++++++ src/client/refresh/gl1/gl1_surf.c | 2 - src/client/refresh/gl1/header/local.h | 6 ++ src/client/refresh/gl1/header/qgl.h | 4 + src/client/refresh/gl1/qgl.c | 4 + 6 files changed, 187 insertions(+), 3 deletions(-) diff --git a/src/client/refresh/gl1/gl1_image.c b/src/client/refresh/gl1/gl1_image.c index 196667a4..f8303713 100644 --- a/src/client/refresh/gl1/gl1_image.c +++ b/src/client/refresh/gl1/gl1_image.c @@ -144,6 +144,30 @@ R_SetTexturePalette(unsigned palette[256]) } } +void +R_SelectTexture(GLenum texture) +{ + int tmu; + + if (!gl_config.multitexture) + { + return; + } + + tmu = texture - GL_TEXTURE0; + + if (tmu == gl_state.currenttmu) + { + return; + } + + gl_state.currenttmu = tmu; + gl_state.currenttarget = texture; + + qglActiveTexture(texture); + qglClientActiveTexture(texture); +} + void R_TexEnv(GLenum mode) { @@ -151,7 +175,7 @@ R_TexEnv(GLenum mode) if (mode != lastmodes[gl_state.currenttmu]) { - glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, mode); // FIXME: shouldn't this be glTexEnvi() ? + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, mode); lastmodes[gl_state.currenttmu] = mode; } } @@ -175,6 +199,93 @@ R_Bind(int texnum) glBindTexture(GL_TEXTURE_2D, texnum); } +void +R_MBind(GLenum target, int texnum) +{ + const int tmu = target - GL_TEXTURE0; + + if (target != gl_state.currenttarget) + { + R_SelectTexture(target); + } + + if (gl_state.currenttextures[tmu] == texnum) + { + return; + } + + R_Bind(texnum); +} + +void +R_EnableMultitexture(qboolean enable) +{ + static qboolean active; + + if (!gl_config.multitexture || enable == active) + { + return; // current state is the right one + } + + active = enable; + R_SelectTexture(GL_TEXTURE1); + + if (active && !r_fullbright->value) + { + glEnable(GL_TEXTURE_2D); + + if (gl_config.mtexcombine) + { + R_TexEnv(GL_COMBINE); + + if (gl_lightmap->value) + { + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_REPLACE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_TEXTURE); + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_TEXTURE); + } + else + { + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_TEXTURE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_PREVIOUS); + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_TEXTURE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_PREVIOUS); + } + + R_SelectTexture(GL_TEXTURE0); + R_TexEnv(GL_COMBINE); + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_REPLACE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_TEXTURE); + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_TEXTURE); + return; + } + else + { + if (gl_lightmap->value) + { + R_TexEnv(GL_REPLACE); + } + else + { + R_TexEnv(GL_MODULATE); + } + } + + } + else // disable multitexturing + { + glDisable(GL_TEXTURE_2D); + R_TexEnv(GL_REPLACE); + } + + R_SelectTexture(GL_TEXTURE0); + R_TexEnv(GL_REPLACE); +} + void R_TextureMode(char *string) { diff --git a/src/client/refresh/gl1/gl1_main.c b/src/client/refresh/gl1/gl1_main.c index 5928d97f..6fcda10d 100644 --- a/src/client/refresh/gl1/gl1_main.c +++ b/src/client/refresh/gl1/gl1_main.c @@ -90,6 +90,7 @@ cvar_t *gl1_particle_square; cvar_t *gl1_palettedtexture; cvar_t *gl1_pointparameters; +cvar_t *gl1_multitexture; cvar_t *gl_drawbuffer; cvar_t *gl_lightmap; @@ -1211,6 +1212,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); gl_drawbuffer = ri.Cvar_Get("gl_drawbuffer", "GL_BACK", 0); r_vsync = ri.Cvar_Get("r_vsync", "1", CVAR_ARCHIVE); @@ -1574,6 +1576,65 @@ RI_Init(void) // ---- + /* Multitexturing */ + gl_config.multitexture = gl_config.mtexcombine = false; + + R_Printf(PRINT_ALL, " - Multitexturing: "); + + if (strstr(gl_config.extensions_string, "GL_ARB_multitexture")) + { + qglActiveTexture = (void (APIENTRY *)(GLenum))RI_GetProcAddress ("glActiveTexture"); + qglClientActiveTexture = (void (APIENTRY *)(GLenum))RI_GetProcAddress ("glClientActiveTexture"); + + if (!qglActiveTexture || !qglClientActiveTexture) + { + qglActiveTexture = (void (APIENTRY *)(GLenum))RI_GetProcAddress ("glActiveTextureARB"); + qglClientActiveTexture = (void (APIENTRY *)(GLenum))RI_GetProcAddress ("glClientActiveTextureARB"); + } + } + + if (gl1_multitexture->value) + { + if (qglActiveTexture && qglClientActiveTexture) + { + gl_config.multitexture = true; + R_Printf(PRINT_ALL, "Okay\n"); + } + else + { + R_Printf(PRINT_ALL, "Failed\n"); + } + } + else + { + R_Printf(PRINT_ALL, "Disabled\n"); + } + + // ---- + + /* Multi texturing combine */ + R_Printf(PRINT_ALL, " - Multitexturing combine: "); + + if ( ( strstr(gl_config.extensions_string, "GL_ARB_texture_env_combine") + || strstr(gl_config.extensions_string, "GL_EXT_texture_env_combine") ) ) + { + if (gl_config.multitexture && gl1_multitexture->value > 1) + { + gl_config.mtexcombine = true; + R_Printf(PRINT_ALL, "Okay\n"); + } + else + { + R_Printf(PRINT_ALL, "Disabled\n"); + } + } + else + { + R_Printf(PRINT_ALL, "Failed\n"); + } + + // ---- + R_SetDefaultState(); R_InitImages(); diff --git a/src/client/refresh/gl1/gl1_surf.c b/src/client/refresh/gl1/gl1_surf.c index 53e4a01e..db7bc8c3 100644 --- a/src/client/refresh/gl1/gl1_surf.c +++ b/src/client/refresh/gl1/gl1_surf.c @@ -762,8 +762,6 @@ R_DrawBrushModel(entity_t *currententity, const model_t *currentmodel) currententity->angles[0] = -currententity->angles[0]; currententity->angles[2] = -currententity->angles[2]; - R_TexEnv(GL_REPLACE); - if (gl_lightmap->value) { R_TexEnv(GL_REPLACE); diff --git a/src/client/refresh/gl1/header/local.h b/src/client/refresh/gl1/header/local.h index d2891110..0e5be2d8 100644 --- a/src/client/refresh/gl1/header/local.h +++ b/src/client/refresh/gl1/header/local.h @@ -162,6 +162,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_particle_min_size; extern cvar_t *gl1_particle_max_size; @@ -230,6 +231,9 @@ void R_TranslatePlayerSkin(int playernum); void R_Bind(int texnum); void R_TexEnv(GLenum value); +void R_SelectTexture(GLenum); +void R_MBind(GLenum target, int texnum); +void R_EnableMultitexture(qboolean enable); void R_LightPoint(entity_t *currententity, vec3_t p, vec3_t color); void R_PushDlights(void); @@ -359,6 +363,8 @@ typedef struct qboolean npottextures; qboolean palettedtexture; qboolean pointparameters; + qboolean multitexture; + qboolean mtexcombine; // ---- diff --git a/src/client/refresh/gl1/header/qgl.h b/src/client/refresh/gl1/header/qgl.h index 076ab9e5..cf4a04c2 100644 --- a/src/client/refresh/gl1/header/qgl.h +++ b/src/client/refresh/gl1/header/qgl.h @@ -52,6 +52,8 @@ #endif #ifndef GL_VERSION_1_3 +#define GL_TEXTURE0 0x84C0 +#define GL_TEXTURE1 0x84C1 #define GL_MULTISAMPLE 0x809D #define GL_COMBINE 0x8570 #define GL_COMBINE_RGB 0x8571 @@ -95,5 +97,7 @@ extern void ( APIENTRY *qglPointParameterfv ) ( GLenum param, const GLfloat *value ); extern void ( APIENTRY *qglColorTableEXT ) ( GLenum, GLenum, GLsizei, GLenum, GLenum, const GLvoid * ); +extern void ( APIENTRY *qglActiveTexture ) ( GLenum texture ); +extern void ( APIENTRY *qglClientActiveTexture ) ( GLenum texture ); #endif diff --git a/src/client/refresh/gl1/qgl.c b/src/client/refresh/gl1/qgl.c index d176ae08..913283a9 100644 --- a/src/client/refresh/gl1/qgl.c +++ b/src/client/refresh/gl1/qgl.c @@ -42,6 +42,8 @@ void (APIENTRY *qglPointParameterf)(GLenum param, GLfloat value); void (APIENTRY *qglPointParameterfv)(GLenum param, const GLfloat *value); void (APIENTRY *qglColorTableEXT)(GLenum, GLenum, GLsizei, GLenum, GLenum, const GLvoid *); +void (APIENTRY *qglActiveTexture) (GLenum texture); +void (APIENTRY *qglClientActiveTexture) (GLenum texture); /* ========================================================================= */ @@ -50,6 +52,8 @@ void QGL_EXT_Reset ( void ) qglPointParameterf = NULL; qglPointParameterfv = NULL; qglColorTableEXT = NULL; + qglActiveTexture = NULL; + qglClientActiveTexture = NULL; } /* ========================================================================= */ From 86528d7812278fe0e502206dd1bf694bd27c4bb1 Mon Sep 17 00:00:00 2001 From: Jaime Moreira Date: Tue, 23 Apr 2024 12:25:38 -0400 Subject: [PATCH 4/6] GL1 multitexture, first version Unlike the old, buggy one, this implementation follows the texture chain, just like the standard execution path. It also avoids doing the lightmap chains, since it has already done it in the second TMU; there's no duplicated work for lightmaps. No errors appear in the lava on the "boss1" map either. It's still slow when having an overdraw of dynamic lights. Further work is needed. --- doc/040_cvarlist.md | 6 + src/client/refresh/gl1/gl1_main.c | 1 + src/client/refresh/gl1/gl1_mesh.c | 1 + src/client/refresh/gl1/gl1_surf.c | 260 ++++++++++++++++++++++++++---- 4 files changed, 238 insertions(+), 30 deletions(-) diff --git a/doc/040_cvarlist.md b/doc/040_cvarlist.md index 9bbca845..2cad40a8 100644 --- a/doc/040_cvarlist.md +++ b/doc/040_cvarlist.md @@ -464,6 +464,12 @@ Set `0` by default. value, at least `1.0` - default is `2.0`. Applied when textures are loaded, so it needs a `vid_restart`. +* **gl1_multitexture**: Enables (`1`) the blending of color and light + textures on a single drawing pass; disabling this (`0`) does one pass + for color and another for light. Default is `2`, which also enables + texture combine mode (`GL_ARB_texture_env_combine`) when supported. + Requires a `vid_restart` when changed. + * **gl1_overbrightbits**: Enables overbright bits, brightness scaling of lightmaps and models. Higher values make shadows less dark. Possible values are `0` (no overbright bits), `1` (more correct lighting for diff --git a/src/client/refresh/gl1/gl1_main.c b/src/client/refresh/gl1/gl1_main.c index 6fcda10d..2a1028d5 100644 --- a/src/client/refresh/gl1/gl1_main.c +++ b/src/client/refresh/gl1/gl1_main.c @@ -164,6 +164,7 @@ R_DrawSpriteModel(entity_t *currententity, const model_t *currentmodel) dsprite_t *psprite; image_t *skin; + R_EnableMultitexture(false); /* don't even bother culling, because it's just a single polygon without a surface cache */ psprite = (dsprite_t *)currentmodel->extradata; diff --git a/src/client/refresh/gl1/gl1_mesh.c b/src/client/refresh/gl1/gl1_mesh.c index e7b257b1..1c3f5d13 100644 --- a/src/client/refresh/gl1/gl1_mesh.c +++ b/src/client/refresh/gl1/gl1_mesh.c @@ -557,6 +557,7 @@ R_DrawAliasModel(entity_t *currententity, const model_t *currentmodel) } } + R_EnableMultitexture(false); paliashdr = (dmdl_t *)currentmodel->extradata; /* get lighting information */ diff --git a/src/client/refresh/gl1/gl1_surf.c b/src/client/refresh/gl1/gl1_surf.c index db7bc8c3..2795603b 100644 --- a/src/client/refresh/gl1/gl1_surf.c +++ b/src/client/refresh/gl1/gl1_surf.c @@ -238,13 +238,8 @@ R_BlendLightmaps(const model_t *currentmodel) int i; msurface_t *surf, *newdrawsurf = 0; - /* don't bother if we're set to fullbright */ - if (r_fullbright->value) - { - return; - } - - if (!r_worldmodel->lightdata) + /* don't bother if we're set to fullbright or multitexture is enabled */ + if (gl_config.multitexture || r_fullbright->value || !r_worldmodel->lightdata) { return; } @@ -466,6 +461,11 @@ R_RenderBrushPoly(entity_t *currententity, msurface_t *fa) R_DrawGLPoly(fa->polys); } + if (gl_config.multitexture) + { + return; // lighting already done at this point for mtex + } + /* check for lightmap modification */ for (maps = 0; maps < MAXLIGHTMAPS && fa->styles[maps] != 255; maps++) { @@ -589,6 +589,149 @@ R_DrawAlphaSurfaces(void) r_alpha_surfaces = NULL; } +static qboolean +R_HasDynamicLights(msurface_t *surf, int *mapNum) +{ + int map; + qboolean is_dynamic = false; + + if ( r_fullbright->value || !gl1_dynamic->value || + (surf->texinfo->flags & (SURF_SKY | SURF_TRANS33 | SURF_TRANS66 | SURF_WARP)) ) + { + return false; + } + + // Any dynamic lights on this surface? + for (map = 0; map < MAXLIGHTMAPS && surf->styles[map] != 255; map++) + { + if (r_newrefdef.lightstyles[surf->styles[map]].white != surf->cached_light[map]) + { + is_dynamic = true; + break; + } + } + + if ( !is_dynamic && surf->dlightframe == r_framecount ) + { + is_dynamic = true; + } + + if (mapNum) + { + *mapNum = map; + } + return is_dynamic; +} + +static void +R_RenderLightmappedPoly(entity_t *currententity, msurface_t *surf) +{ + int i, map, smax, tmax; + int nv = surf->polys->numverts; + float scroll; + float *v; + unsigned lmtex = surf->lightmaptexturenum; + unsigned temp[128 * 128]; + + if ( R_HasDynamicLights(surf, &map) ) + { + smax = (surf->extents[0] >> 4) + 1; + tmax = (surf->extents[1] >> 4) + 1; + R_BuildLightMap(surf, (void *) temp, smax * 4); + + // Dynamic lights on a surface + if (((surf->styles[map] >= 32) || (surf->styles[map] == 0)) && (surf->dlightframe != r_framecount)) + { + R_SetCacheState(surf); + } + else // Normal dynamic lights + { + lmtex = 0; + } + + R_MBind(GL_TEXTURE1, gl_state.lightmap_textures + lmtex); + glTexSubImage2D(GL_TEXTURE_2D, 0, surf->light_s, surf->light_t, smax, + tmax, GL_LIGHTMAP_FORMAT, GL_UNSIGNED_BYTE, temp); + } + else + { + R_MBind(GL_TEXTURE1, gl_state.lightmap_textures + lmtex); + } + + // Apply overbrightbits to TMU 1 (lightmap) + if (gl1_overbrightbits->value) + { + R_TexEnv(GL_COMBINE); + glTexEnvi(GL_TEXTURE_ENV, GL_RGB_SCALE, gl1_overbrightbits->value); + } + + c_brush_polys++; + v = surf->polys->verts[0]; + + if (surf->texinfo->flags & SURF_FLOWING) + { + scroll = -64 * ((r_newrefdef.time / 40.0) - (int) (r_newrefdef.time / 40.0)); + + if (scroll == 0.0) + { + scroll = -64.0; + } + + YQ2_VLA(GLfloat, tex, 4 * nv); + unsigned int index_tex = 0; + + for (i = 0; i < nv; i++, v += VERTEXSIZE) + { + tex[index_tex++] = v[3] + scroll; + tex[index_tex++] = v[4]; + tex[index_tex++] = v[5]; + tex[index_tex++] = v[6]; + } + v = surf->polys->verts[0]; + + // Polygon + glEnableClientState(GL_VERTEX_ARRAY); + glVertexPointer(3, GL_FLOAT, VERTEXSIZE * sizeof(GLfloat), v); + + // Texture + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + qglClientActiveTexture(GL_TEXTURE0); + glTexCoordPointer(2, GL_FLOAT, 4 * sizeof(GLfloat), tex); + + // Lightmap + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + qglClientActiveTexture(GL_TEXTURE1); + glTexCoordPointer(2, GL_FLOAT, 4 * sizeof(GLfloat), tex + 2); + + // Draw the thing + glDrawArrays(GL_TRIANGLE_FAN, 0, nv); + + YQ2_VLAFREE(tex); + } + else + { + // Polygon + glEnableClientState(GL_VERTEX_ARRAY); + glVertexPointer(3, GL_FLOAT, VERTEXSIZE * sizeof(GLfloat), v); + + // Texture + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + qglClientActiveTexture(GL_TEXTURE0); + glTexCoordPointer(2, GL_FLOAT, VERTEXSIZE * sizeof(GLfloat), v + 3); + + // Lightmap + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + qglClientActiveTexture(GL_TEXTURE1); + glTexCoordPointer(2, GL_FLOAT, VERTEXSIZE * sizeof(GLfloat), v + 5); + + // Draw it + glDrawArrays(GL_TRIANGLE_FAN, 0, nv); + } + + glDisableClientState(GL_VERTEX_ARRAY); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); +} + static void R_DrawTextureChains(entity_t *currententity) { @@ -598,32 +741,78 @@ R_DrawTextureChains(entity_t *currententity) c_visible_textures = 0; - for (i = 0, image = gltextures; i < numgltextures; i++, image++) + if (!gl_config.multitexture) // classic path { - if (!image->registration_sequence) + for (i = 0, image = gltextures; i < numgltextures; i++, image++) { - continue; + if (!image->registration_sequence) + { + continue; + } + + s = image->texturechain; + + if (!s) + { + continue; + } + + c_visible_textures++; + + for ( ; s; s = s->texturechain) + { + R_Bind(image->texnum); // may reset because of dynamic lighting in R_RenderBrushPoly + R_RenderBrushPoly(currententity, s); + } + + image->texturechain = NULL; } - - s = image->texturechain; - - if (!s) - { - continue; - } - - c_visible_textures++; - - for ( ; s; s = s->texturechain) - { - R_Bind(image->texnum); // may reset because of dynamic lighting in R_RenderBrushPoly - R_RenderBrushPoly(currententity, s); - } - - image->texturechain = NULL; } + else // multitexture + { + R_EnableMultitexture(true); - R_TexEnv(GL_REPLACE); + for (i = 0, image = gltextures; i < numgltextures; i++, image++) + { + if (!image->registration_sequence || !image->texturechain) + { + continue; + } + + R_MBind(GL_TEXTURE0, image->texnum); // setting it only once + c_visible_textures++; + + for (s = image->texturechain; s; s = s->texturechain) + { + if (!(s->flags & SURF_DRAWTURB)) + { + R_RenderLightmappedPoly(currententity, s); + } + } + } + + R_EnableMultitexture(false); + + for (i = 0, image = gltextures; i < numgltextures; i++, image++) + { + if (!image->registration_sequence || !image->texturechain) + { + continue; + } + + R_Bind(image->texnum); // no danger of resetting in R_RenderBrushPoly + + for (s = image->texturechain; s; s = s->texturechain) + { + if (s->flags & SURF_DRAWTURB) + { + R_RenderBrushPoly(currententity, s); + } + } + + image->texturechain = NULL; + } + } } static void @@ -679,8 +868,19 @@ R_DrawInlineBModel(entity_t *currententity, const model_t *currentmodel) else { image = R_TextureAnimation(currententity, psurf->texinfo); - R_Bind(image->texnum); - R_RenderBrushPoly(currententity, psurf); + + if (gl_config.multitexture && !(psurf->flags & SURF_DRAWTURB)) + { + R_EnableMultitexture(true); + R_MBind(GL_TEXTURE0, image->texnum); + R_RenderLightmappedPoly(currententity, psurf); + } + else + { + R_EnableMultitexture(false); + R_Bind(image->texnum); + R_RenderBrushPoly(currententity, psurf); + } } } } From ba71af2af83fc2536cc9e773d0b925baa0cf02a3 Mon Sep 17 00:00:00 2001 From: Jaime Moreira Date: Tue, 23 Apr 2024 12:26:44 -0400 Subject: [PATCH 5/6] GL1 multitexture: fast dynamic lighting Using MH's solution, which is keeping all lightmaps in memory to modify and upload them as a batch when possible. lightmap_buffer is now an array; index 0 is used as the legacy lightmap buffer (when no mtex), and the rest of the indexes are to store the different lightmaps (only when using mtex). --- src/client/refresh/gl1/gl1_lightmap.c | 54 ++++++--- src/client/refresh/gl1/gl1_surf.c | 163 +++++++++++++++++++++----- src/client/refresh/gl1/header/local.h | 2 +- src/client/refresh/gl1/header/model.h | 1 + 4 files changed, 173 insertions(+), 47 deletions(-) diff --git a/src/client/refresh/gl1/gl1_lightmap.c b/src/client/refresh/gl1/gl1_lightmap.c index 5e81fc4e..6ff92ff5 100644 --- a/src/client/refresh/gl1/gl1_lightmap.c +++ b/src/client/refresh/gl1/gl1_lightmap.c @@ -35,23 +35,19 @@ void LM_InitBlock(void) { memset(gl_lms.allocated, 0, sizeof(gl_lms.allocated)); + + if (gl_config.multitexture && !gl_lms.lightmap_buffer[gl_lms.current_lightmap_texture]) { + gl_lms.lightmap_buffer[gl_lms.current_lightmap_texture] = malloc (BLOCK_WIDTH*BLOCK_HEIGHT*LIGHTMAP_BYTES); + } } void LM_UploadBlock(qboolean dynamic) { - int texture; + const int texture = (dynamic)? 0 : gl_lms.current_lightmap_texture; + const int buffer = (gl_config.multitexture)? gl_lms.current_lightmap_texture : 0; int height = 0; - if (dynamic) - { - texture = 0; - } - else - { - texture = gl_lms.current_lightmap_texture; - } - R_Bind(gl_state.lightmap_textures + texture); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); @@ -70,14 +66,14 @@ LM_UploadBlock(qboolean dynamic) glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, BLOCK_WIDTH, height, GL_LIGHTMAP_FORMAT, GL_UNSIGNED_BYTE, - gl_lms.lightmap_buffer); + gl_lms.lightmap_buffer[buffer]); } else { 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); + GL_UNSIGNED_BYTE, gl_lms.lightmap_buffer[buffer]); if (++gl_lms.current_lightmap_texture == MAX_LIGHTMAPS) { @@ -207,7 +203,7 @@ LM_BuildPolygonFromSurface(model_t *currentmodel, msurface_t *fa) void LM_CreateSurfaceLightmap(msurface_t *surf) { - int smax, tmax; + int smax, tmax, buffer; byte *base; if (surf->flags & (SURF_DRAWSKY | SURF_DRAWTURB)) @@ -231,8 +227,9 @@ LM_CreateSurfaceLightmap(msurface_t *surf) } surf->lightmaptexturenum = gl_lms.current_lightmap_texture; + buffer = (gl_config.multitexture)? surf->lightmaptexturenum : 0; - base = gl_lms.lightmap_buffer; + base = gl_lms.lightmap_buffer[buffer]; base += (surf->light_t * BLOCK_WIDTH + surf->light_s) * LIGHTMAP_BYTES; R_SetCacheState(surf); @@ -242,12 +239,22 @@ LM_CreateSurfaceLightmap(msurface_t *surf) void LM_BeginBuildingLightmaps(model_t *m) { + static const unsigned int lightmap_size = BLOCK_WIDTH*BLOCK_HEIGHT*LIGHTMAP_BYTES; static lightstyle_t lightstyles[MAX_LIGHTSTYLES]; int i; - unsigned dummy[128 * 128] = {0}; memset(gl_lms.allocated, 0, sizeof(gl_lms.allocated)); + // free lightmap update buffers + for (i=0; idlight_s, &surf->dlight_t)) { - base = gl_lms.lightmap_buffer; + base = gl_lms.lightmap_buffer[0]; base += (surf->dlight_t * BLOCK_WIDTH + surf->dlight_s) * LIGHTMAP_BYTES; @@ -371,7 +371,7 @@ R_BlendLightmaps(const model_t *currentmodel) smax, tmax); } - base = gl_lms.lightmap_buffer; + base = gl_lms.lightmap_buffer[0]; base += (surf->dlight_t * BLOCK_WIDTH + surf->dlight_s) * LIGHTMAP_BYTES; @@ -611,7 +611,8 @@ R_HasDynamicLights(msurface_t *surf, int *mapNum) } } - if ( !is_dynamic && surf->dlightframe == r_framecount ) + // No matter if it is this frame or was in the previous one: has dynamic lights + if ( !is_dynamic && (surf->dlightframe == r_framecount || surf->dirty_lightmap) ) { is_dynamic = true; } @@ -623,40 +624,26 @@ R_HasDynamicLights(msurface_t *surf, int *mapNum) return is_dynamic; } +static void +R_UpdateSurfCache(msurface_t *surf, int map) +{ + if ( ((surf->styles[map] >= 32) || (surf->styles[map] == 0)) + && (surf->dlightframe != r_framecount) ) + { + R_SetCacheState(surf); + } + surf->dirty_lightmap = (surf->dlightframe == r_framecount); +} + static void R_RenderLightmappedPoly(entity_t *currententity, msurface_t *surf) { - int i, map, smax, tmax; + int i; int nv = surf->polys->numverts; float scroll; float *v; - unsigned lmtex = surf->lightmaptexturenum; - unsigned temp[128 * 128]; - if ( R_HasDynamicLights(surf, &map) ) - { - smax = (surf->extents[0] >> 4) + 1; - tmax = (surf->extents[1] >> 4) + 1; - R_BuildLightMap(surf, (void *) temp, smax * 4); - - // Dynamic lights on a surface - if (((surf->styles[map] >= 32) || (surf->styles[map] == 0)) && (surf->dlightframe != r_framecount)) - { - R_SetCacheState(surf); - } - else // Normal dynamic lights - { - lmtex = 0; - } - - R_MBind(GL_TEXTURE1, gl_state.lightmap_textures + lmtex); - glTexSubImage2D(GL_TEXTURE_2D, 0, surf->light_s, surf->light_t, smax, - tmax, GL_LIGHTMAP_FORMAT, GL_UNSIGNED_BYTE, temp); - } - else - { - R_MBind(GL_TEXTURE1, gl_state.lightmap_textures + lmtex); - } + R_MBind(GL_TEXTURE1, gl_state.lightmap_textures + surf->lightmaptexturenum); // Apply overbrightbits to TMU 1 (lightmap) if (gl1_overbrightbits->value) @@ -732,6 +719,114 @@ R_RenderLightmappedPoly(entity_t *currententity, msurface_t *surf) glDisableClientState(GL_TEXTURE_COORD_ARRAY); } +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; + } + + smax = (surf->extents[0] >> 4) + 1; + tmax = (surf->extents[1] >> 4) + 1; + R_BuildLightMap(surf, (void *) temp, smax * LIGHTMAP_BYTES); + R_UpdateSurfCache(surf, map); + + 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); +} + +/* Upload dynamic lights to each lightmap texture (multitexture path only) */ +static void +R_RegenAllLightmaps() +{ + int i, map, smax, tmax, top, bottom, left, right, bt, bb, bl, br; + qboolean affected_lightmap; + msurface_t *surf; + byte *base; + + if ( !gl_config.multitexture ) + { + return; + } + + glPixelStorei(GL_UNPACK_ROW_LENGTH, BLOCK_WIDTH); + + for (i = 1; i < MAX_LIGHTMAPS; i++) + { + if (!gl_lms.lightmap_surfaces[i] || !gl_lms.lightmap_buffer[i]) + { + continue; + } + + affected_lightmap = false; + bt = BLOCK_HEIGHT; + bl = BLOCK_WIDTH; + bb = br = 0; + + for (surf = gl_lms.lightmap_surfaces[i]; + surf != 0; + surf = surf->lightmapchain) + { + if ( !R_HasDynamicLights(surf, &map) ) + { + continue; + } + + affected_lightmap = true; + smax = (surf->extents[0] >> 4) + 1; + tmax = (surf->extents[1] >> 4) + 1; + + left = surf->light_s; + right = surf->light_s + smax; + top = surf->light_t; + bottom = surf->light_t + tmax; + + base = gl_lms.lightmap_buffer[i]; + base += (top * BLOCK_WIDTH + left) * LIGHTMAP_BYTES; + + R_BuildLightMap(surf, base, BLOCK_WIDTH * LIGHTMAP_BYTES); + R_UpdateSurfCache(surf, map); + + if (left < bl) + { + bl = left; + } + if (right > br) + { + br = right; + } + if (top < bt) + { + bt = top; + } + if (bottom > bb) + { + bb = bottom; + } + } + + if (!affected_lightmap) + { + continue; + } + + base = gl_lms.lightmap_buffer[i]; + base += (bt * BLOCK_WIDTH + bl) * LIGHTMAP_BYTES; + + // upload changes + R_Bind(gl_state.lightmap_textures + i); + glTexSubImage2D(GL_TEXTURE_2D, 0, bl, bt, br - bl, bb - bt, + GL_LIGHTMAP_FORMAT, GL_UNSIGNED_BYTE, base); + } + + glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); +} + static void R_DrawTextureChains(entity_t *currententity) { @@ -871,6 +966,7 @@ R_DrawInlineBModel(entity_t *currententity, const model_t *currentmodel) if (gl_config.multitexture && !(psurf->flags & SURF_DRAWTURB)) { + R_UploadDynamicLights(psurf); R_EnableMultitexture(true); R_MBind(GL_TEXTURE0, image->texnum); R_RenderLightmappedPoly(currententity, psurf); @@ -1098,6 +1194,12 @@ R_RecursiveWorldNode(entity_t *currententity, mnode_t *node) image = R_TextureAnimation(currententity, surf->texinfo); surf->texturechain = image->texturechain; image->texturechain = surf; + + if (gl_config.multitexture && !(surf->texinfo->flags & SURF_WARP)) // needed for R_RegenAllLightmaps() + { + surf->lightmapchain = gl_lms.lightmap_surfaces[surf->lightmaptexturenum]; + gl_lms.lightmap_surfaces[surf->lightmaptexturenum] = surf; + } } } @@ -1133,6 +1235,7 @@ R_DrawWorld(void) R_ClearSkyBox(); R_RecursiveWorldNode(&ent, r_worldmodel->nodes); + R_RegenAllLightmaps(); R_DrawTextureChains(&ent); R_BlendLightmaps(r_worldmodel); R_DrawSkyBox(); diff --git a/src/client/refresh/gl1/header/local.h b/src/client/refresh/gl1/header/local.h index 0e5be2d8..1e60b092 100644 --- a/src/client/refresh/gl1/header/local.h +++ b/src/client/refresh/gl1/header/local.h @@ -403,7 +403,7 @@ typedef struct /* the lightmap texture data needs to be kept in main memory so texsubimage can update properly */ - byte lightmap_buffer[4 * BLOCK_WIDTH * BLOCK_HEIGHT]; + byte *lightmap_buffer[MAX_LIGHTMAPS]; } gllightmapstate_t; extern glconfig_t gl_config; diff --git a/src/client/refresh/gl1/header/model.h b/src/client/refresh/gl1/header/model.h index 36d57dfe..2eda331d 100644 --- a/src/client/refresh/gl1/header/model.h +++ b/src/client/refresh/gl1/header/model.h @@ -65,6 +65,7 @@ typedef struct msurface_s /* lighting info */ int dlightframe; int dlightbits; + qboolean dirty_lightmap; // lightmap has dynamic lights from previous frame (mtex only) int lightmaptexturenum; byte styles[MAXLIGHTMAPS]; From b81e9109291d13323e6cfaacaf45ebd2924b77f1 Mon Sep 17 00:00:00 2001 From: Jaime Moreira Date: Wed, 24 Apr 2024 19:43:24 -0400 Subject: [PATCH 6/6] GL1 multitexture, refactored memory allocation It was missing error checking and cleanup at shutdown. Also, reset state when needed. Fixes "death by laser" in boss1 map. --- src/client/refresh/gl1/gl1_lightmap.c | 61 ++++++++++++++++++--------- src/client/refresh/gl1/gl1_main.c | 5 +++ 2 files changed, 45 insertions(+), 21 deletions(-) diff --git a/src/client/refresh/gl1/gl1_lightmap.c b/src/client/refresh/gl1/gl1_lightmap.c index 6ff92ff5..2ee2dedc 100644 --- a/src/client/refresh/gl1/gl1_lightmap.c +++ b/src/client/refresh/gl1/gl1_lightmap.c @@ -31,13 +31,48 @@ extern gllightmapstate_t gl_lms; void R_SetCacheState(msurface_t *surf); void R_BuildLightMap(msurface_t *surf, byte *dest, int stride); +void +LM_FreeLightmapBuffers(void) +{ + for (int i=0; iorigin, shadelight); } + R_EnableMultitexture(false); glPushMatrix(); R_RotateForEntity(currententity); @@ -1654,6 +1657,7 @@ RI_Shutdown(void) ri.Cmd_RemoveCommand("imagelist"); ri.Cmd_RemoveCommand("gl_strings"); + LM_FreeLightmapBuffers(); Mod_FreeAll(); R_ShutdownImages(); @@ -1909,6 +1913,7 @@ R_DrawBeam(entity_t *e) VectorAdd(start_points[i], direction, end_points[i]); } + R_EnableMultitexture(false); glDisable(GL_TEXTURE_2D); glEnable(GL_BLEND); glDepthMask(GL_FALSE);