From 59d3b63c6ad6dc73373b308abe4a5b3b330efbfb Mon Sep 17 00:00:00 2001 From: braxi Date: Sat, 10 May 2025 16:02:56 +0200 Subject: [PATCH 1/9] q3map changes to support pragma --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index c3ce012c..bd8ae2cb 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ install .vscode .idea /.cache +/.vs From 6a4662f887341713de7f1f343134f2cf151fe12e Mon Sep 17 00:00:00 2001 From: braxi Date: Sat, 10 May 2025 16:05:27 +0200 Subject: [PATCH 2/9] pragma support --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index bd8ae2cb..cb63908b 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ install .idea /.cache /.vs +/icons From 4fc5258aed13885d3dbc30cece8a10f1d3922030 Mon Sep 17 00:00:00 2001 From: braxi Date: Sat, 10 May 2025 16:05:32 +0200 Subject: [PATCH 3/9] . --- radiant/patchmodule.cpp | 4 +- tools/quake3/q3map2/bsp.cpp | 21 ++++++++ tools/quake3/q3map2/games.cpp | 90 +++++++++++++++++++++++++++-------- tools/quake3/q3map2/games.h | 1 - tools/quake3/q3map2/q3map2.h | 16 +++++-- 5 files changed, 106 insertions(+), 26 deletions(-) diff --git a/radiant/patchmodule.cpp b/radiant/patchmodule.cpp index 371ec8e7..35710aa7 100644 --- a/radiant/patchmodule.cpp +++ b/radiant/patchmodule.cpp @@ -55,7 +55,9 @@ void Patch_Construct( EPatchType type ){ } else { - MAX_PATCH_WIDTH = MAX_PATCH_HEIGHT = 31; // matching q3map2 + //MAX_PATCH_WIDTH = MAX_PATCH_HEIGHT = 31; // matching q3map2 + + MAX_PATCH_WIDTH = MAX_PATCH_HEIGHT = 9999; // braxi -- for large patch terrains } } diff --git a/tools/quake3/q3map2/bsp.cpp b/tools/quake3/q3map2/bsp.cpp index 56ff189a..b4da1b0a 100644 --- a/tools/quake3/q3map2/bsp.cpp +++ b/tools/quake3/q3map2/bsp.cpp @@ -654,6 +654,21 @@ int BSPMain( Args& args ){ Error( "usage: q3map2 [options] mapfile" ); } +#ifdef PRAGMA_MAP + // write light and misc_model entities + keepLights = true; + keepModels = true; + + // emit flare surfs + emitFlares = true; + + // create meta surfaces + meta = true; + patchMeta = true; + + // disable celshader +#endif + const char *fileName = args.takeBack(); auto argsToInject = args.getVector(); { @@ -668,6 +683,7 @@ int BSPMain( Args& args ){ Sys_Printf( "Disabling water\n" ); nowater = true; } +#ifndef PRAGMA_MAP while ( args.takeArg( "-keeplights" ) ) { keepLights = true; Sys_Printf( "Leaving light entities on map after compile\n" ); @@ -676,6 +692,7 @@ int BSPMain( Args& args ){ keepModels = true; Sys_Printf( "Leaving misc_model entities on map after compile\n" ); } +#endif while ( args.takeArg( "-nodetail" ) ) { Sys_Printf( "Ignoring detail brushes\n" ); nodetail = true; @@ -773,6 +790,7 @@ int BSPMain( Args& args ){ Sys_Printf( "Flatshading enabled\n" ); flat = true; } +#ifndef PRAGMA_MAP while ( args.takeArg( "-celshader" ) ) { globalCelShader( "textures/", args.takeNext() ); Sys_Printf( "Global cel shader set to \"%s\"\n", globalCelShader.c_str() ); @@ -781,6 +799,7 @@ int BSPMain( Args& args ){ Sys_Printf( "Creating meta surfaces from brush faces\n" ); meta = true; } +#endif while ( args.takeArg( "-metaadequatescore" ) ) { metaAdequateScore = std::max( -1, atoi( args.takeNext() ) ); if ( metaAdequateScore >= 0 ) { @@ -793,6 +812,7 @@ int BSPMain( Args& args ){ Sys_Printf( "Setting GOOD meta score to %d (see surface_meta.c)\n", metaGoodScore ); } } +#ifndef PRAGMA_MAP while ( args.takeArg( "-patchmeta" ) ) { Sys_Printf( "Creating meta surfaces from patches\n" ); patchMeta = true; @@ -805,6 +825,7 @@ int BSPMain( Args& args ){ Sys_Printf( "Flare surfaces disabled\n" ); emitFlares = false; } +#endif while ( args.takeArg( "-skyfix" ) ) { Sys_Printf( "GL_CLAMP sky fix/hack/workaround enabled\n" ); skyFixHack = true; diff --git a/tools/quake3/q3map2/games.cpp b/tools/quake3/q3map2/games.cpp index c2ba2890..e06c3771 100644 --- a/tools/quake3/q3map2/games.cpp +++ b/tools/quake3/q3map2/games.cpp @@ -32,6 +32,8 @@ #include "qstringops.h" #include "inout.h" +#define PRAGMA_MAP 1 // braxi -- pragma support + struct game_default : game_t { /* game flags */ @@ -918,26 +920,74 @@ struct game_ja : game_sof2 } }; +#ifdef PRAGMA_MAP +struct game_pragma : game_default +{ + game_pragma() + { + arg = "pragma"; + + gamePath = "main"; + homeBasePath = ".pragma"; + magic = "pragma"; + + shaderPath = "materials"; + + maxLMSurfaceVerts = 4096; + maxSurfaceVerts = 4096; + maxSurfaceIndexes = 4096 * 6; + + emitFlares = true; + flareShader = "gfx_flare"; + + lightmapSize = 1024; + lightmapsRGB = false; + + //texturesRGB = true; + //colorsRGB = true; + + lightAngleHL = true; + noStyles = true; + + keepLights = true; + + patchSubdivisions = 4; + patchShadows = false; + + miniMapBorder = 1.0f / 66.0f; + miniMapNameFormat = "../minimaps/%s.tga"; + bspIdent = "BBSP"; + bspVersion = 1; + } +}; +#endif + +const std::vector g_games = +{ +#ifdef PRAGMA_MAP + game_pragma(), +#else + game_quake3(), + game_quakelive(), + game_nexuiz(), + game_xonotic(), + game_tremulous(), + game_unvanquished(), + game_tenebrae(), + game_wolf(), + game_wolfet(), + game_etut(), + game_ef(), + game_qfusion(), + game_reaction(), + game_darkplaces(), + game_dq(), + game_prophecy(), + game_sof2(), + game_jk2(), + game_ja(), +#endif +}; -const std::vector g_games = { game_quake3(), - game_quakelive(), - game_nexuiz(), - game_xonotic(), - game_tremulous(), - game_unvanquished(), - game_tenebrae(), - game_wolf(), - game_wolfet(), - game_etut(), - game_ef(), - game_qfusion(), - game_reaction(), - game_darkplaces(), - game_dq(), - game_prophecy(), - game_sof2(), - game_jk2(), - game_ja(), - }; const game_t *g_game = &g_games[0]; diff --git a/tools/quake3/q3map2/games.h b/tools/quake3/q3map2/games.h index f2eeff3b..6ce1855d 100644 --- a/tools/quake3/q3map2/games.h +++ b/tools/quake3/q3map2/games.h @@ -27,7 +27,6 @@ #include - /* ydnar: compiler flags, because games have widely varying content/surface flags */ const int C_SOLID = 0x00000001; const int C_TRANSLUCENT = 0x00000002; diff --git a/tools/quake3/q3map2/q3map2.h b/tools/quake3/q3map2/q3map2.h index 531578b5..5ac06cf4 100644 --- a/tools/quake3/q3map2/q3map2.h +++ b/tools/quake3/q3map2/q3map2.h @@ -34,11 +34,14 @@ #ifndef Q3MAP_VERSION #error no Q3MAP_VERSION defined #endif -#define Q3MAP_MOTD "Your map saw the pretty lights from q3map2's BFG" - - +#define PRAGMA_MAP 1 // braxi -- pragma support +#ifdef PRAGMA_MAP + #define Q3MAP_MOTD "Your map is coughing, hopefuly not due to virus infection?" +#else + #define Q3MAP_MOTD "Your map saw the pretty lights from q3map2's BFG" +#endif /* ------------------------------------------------------------------------------- dependencies @@ -120,7 +123,12 @@ /* bsp */ -#define MAX_PATCH_SIZE 32 +#ifdef PRAGMA_MAP + #define MAX_PATCH_SIZE 2048 // braxi -- [pragma] to allow large terrains out of patches +#else + #define MAX_PATCH_SIZE 32 +#endif + #define MAX_BRUSH_SIDES 1024 #define MAX_BUILD_SIDES 1024 From 19be5704757cb0484240d25492414f739e187944 Mon Sep 17 00:00:00 2001 From: braxi Date: Sun, 11 May 2025 18:12:09 +0200 Subject: [PATCH 4/9] Generate deluxemap for BBSP --- tools/quake3/q3map2/games.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tools/quake3/q3map2/games.cpp b/tools/quake3/q3map2/games.cpp index e06c3771..18239fde 100644 --- a/tools/quake3/q3map2/games.cpp +++ b/tools/quake3/q3map2/games.cpp @@ -946,13 +946,16 @@ struct game_pragma : game_default //texturesRGB = true; //colorsRGB = true; + delux`eMap = true; + deluxeMode = 0; // 0 - modelspace, 1 - tangentspace with renormalization, 2 - tangentspace without renormalization + lightAngleHL = true; noStyles = true; keepLights = true; patchSubdivisions = 4; - patchShadows = false; + patchShadows = true; miniMapBorder = 1.0f / 66.0f; miniMapNameFormat = "../minimaps/%s.tga"; From 3fcdf9e94ddd8d591dffb72a87f2025818b6a2b1 Mon Sep 17 00:00:00 2001 From: braxi Date: Sun, 11 May 2025 23:44:19 +0200 Subject: [PATCH 5/9] typo --- tools/quake3/q3map2/games.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/quake3/q3map2/games.cpp b/tools/quake3/q3map2/games.cpp index 18239fde..bc8e60d2 100644 --- a/tools/quake3/q3map2/games.cpp +++ b/tools/quake3/q3map2/games.cpp @@ -946,7 +946,7 @@ struct game_pragma : game_default //texturesRGB = true; //colorsRGB = true; - delux`eMap = true; + deluxeMap = true; deluxeMode = 0; // 0 - modelspace, 1 - tangentspace with renormalization, 2 - tangentspace without renormalization lightAngleHL = true; From ec0ee4b775fe3854f89b4da4fac892df019f4344 Mon Sep 17 00:00:00 2001 From: BraXi <6434152+BraXi@users.noreply.github.com> Date: Thu, 31 Jul 2025 00:18:25 +0200 Subject: [PATCH 6/9] change paths --- .gitignore | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.gitignore b/.gitignore index cb63908b..9ef9de41 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,7 @@ install /.cache /.vs /icons +/tools/quake3/q3map2/.vs +/radiant/radiant.aps +/nrc-ncftu.rar +/nrc.rar From e86ad1f505baa9b851796c8e4bea5770d179549e Mon Sep 17 00:00:00 2001 From: BraXi <6434152+BraXi@users.noreply.github.com> Date: Thu, 31 Jul 2025 00:22:43 +0200 Subject: [PATCH 7/9] . --- tools/quake3/q3map2/games.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tools/quake3/q3map2/games.cpp b/tools/quake3/q3map2/games.cpp index bc8e60d2..16b93e4a 100644 --- a/tools/quake3/q3map2/games.cpp +++ b/tools/quake3/q3map2/games.cpp @@ -927,11 +927,11 @@ struct game_pragma : game_default { arg = "pragma"; - gamePath = "main"; - homeBasePath = ".pragma"; - magic = "pragma"; + gamePath = "ncftu"; + homeBasePath = ".ncftu"; + magic = "ncftu"; - shaderPath = "materials"; + shaderPath = "devtools_scripts"; maxLMSurfaceVerts = 4096; maxSurfaceVerts = 4096; From 037e0a7bac5e8c3524424dfd1be9b1e128d8596f Mon Sep 17 00:00:00 2001 From: BraXi <6434152+BraXi@users.noreply.github.com> Date: Thu, 31 Jul 2025 00:57:12 +0200 Subject: [PATCH 8/9] initial decal support --- include/iglrender.h | 7 +++++-- include/irender.h | 1 + include/ishaders.h | 1 + plugins/shaders/shaders.cpp | 26 ++++++++++++++++++++++++++ radiant/renderstate.cpp | 26 +++++++++++++++++++++++++- 5 files changed, 58 insertions(+), 3 deletions(-) diff --git a/include/iglrender.h b/include/iglrender.h index 6e6f015e..2866837a 100644 --- a/include/iglrender.h +++ b/include/iglrender.h @@ -61,8 +61,11 @@ class OpenGLState eSortOverbrighten = 1024, eSortFullbright = 1025, eSortTranslucent = 1026, - eSortHighlight = 1027, - eSortOverlayFirst = 1028, + // BRAXI BEGIN + eSortDecal = 1027, + eSortHighlight = 1028, // was 1027 + eSortOverlayFirst = 1029, // was 1028 + // BRAXI END eSortOverlayLast = 2047, eSortText = 2048, eSortControlFirst = 2050, diff --git a/include/irender.h b/include/irender.h index 65facc58..35fb9f93 100644 --- a/include/irender.h +++ b/include/irender.h @@ -52,6 +52,7 @@ const unsigned int RENDER_PROGRAM = 1 << 18; const unsigned int RENDER_SCREEN = 1 << 19; const unsigned int RENDER_TEXT = 1 << 20; // override: globalstate |= RENDER_TEXTURE | RENDER_BLEND | RENDER_FILL const unsigned int RENDER_OVERRIDE = 1 << 21; // override: globalstate |= RENDER_FILL +const unsigned int RENDER_POLYGONOFFSET = 1 << 22; // braxi -- for decals : glEnable( GL_POLYGON_OFFSET_FILL ) typedef unsigned int RenderStateFlags; diff --git a/include/ishaders.h b/include/ishaders.h index 04ffe5aa..faeea2cf 100644 --- a/include/ishaders.h +++ b/include/ishaders.h @@ -38,6 +38,7 @@ enum QER_CLIP = 1 << 9, QER_BOTCLIP = 1 << 10, QER_SKY = 1 << 11, + QER_DECAL = 1 << 12, // BRAXI }; struct qtexture_t; diff --git a/plugins/shaders/shaders.cpp b/plugins/shaders/shaders.cpp index 8a01c0d7..17c41132 100644 --- a/plugins/shaders/shaders.cpp +++ b/plugins/shaders/shaders.cpp @@ -1302,6 +1302,32 @@ bool ShaderTemplate::parseQuake3( Tokeniser& tokeniser ){ m_nFlags |= QER_BOTCLIP; } } + // BRAXI BEGIN + else if (string_equal_nocase(token, "sort")) { + const char* sort = tokeniser.getToken(); + + if (sort == 0) { + Tokeniser_unexpectedError(tokeniser, sort, "#sort"); + return false; + } + + if (string_equal_nocase(sort, "decal")) { + m_nFlags |= QER_TRANS; + m_nFlags |= QER_DECAL; + if (m_fTrans == 1.0f) { // has not been explicitly set by qer_trans + m_fTrans = 0.99f; + } + } + } + // BRAXI BEGIN + else if (string_equal_nocase(token, "polygonOffset")) { + m_nFlags |= QER_TRANS; + m_nFlags |= QER_DECAL; + if (m_fTrans == 1.0f) { // has not been explicitly set by qer_trans + m_fTrans = 0.99f; + } + } + // BRAXI END } } diff --git a/radiant/renderstate.cpp b/radiant/renderstate.cpp index caad8864..89ffbb20 100644 --- a/radiant/renderstate.cpp +++ b/radiant/renderstate.cpp @@ -1338,6 +1338,19 @@ void OpenGLState_apply( const OpenGLState& self, OpenGLState& current, unsigned g_texcoordArray_enabled = false; } + // BRAXI BEGIN + if (delta & state & RENDER_POLYGONOFFSET) { + gl().glEnable(GL_POLYGON_OFFSET_FILL); + gl().glPolygonOffset(-1, -2); // values match retail quake3 + GlobalOpenGL_debugAssertNoErrors(); + } + else if (delta & ~state & RENDER_POLYGONOFFSET) { + gl().glDisable(GL_POLYGON_OFFSET_FILL); + gl().glPolygonOffset(0,0); // not too neseccasy but "in case" someone ever does offsets somewhere else + GlobalOpenGL_debugAssertNoErrors(); + } + // BRAXI END + if ( delta & state & RENDER_BLEND ) { // FIXME: some .TGA are buggy, have a completely empty alpha channel // if such brushes are rendered in this loop they would be totally transparent with GL_MODULATE @@ -2044,10 +2057,21 @@ void OpenGLShader::construct( const char* name ){ } state.m_colour = Vector4( m_shader->getTexture()->color, 1 ); + if ( ( m_shader->getFlags() & QER_TRANS ) != 0 ) { state.m_state |= RENDER_BLEND; + + // BRAXI BEGIN + if ((m_shader->getFlags() & QER_DECAL) != 0) { + state.m_sort = OpenGLState::eSortDecal; + state.m_state |= RENDER_POLYGONOFFSET; + } + else { + state.m_sort = OpenGLState::eSortTranslucent; + } + //BRAXI END + state.m_colour[3] = m_shader->getTrans(); - state.m_sort = OpenGLState::eSortTranslucent; BlendFunc blendFunc = m_shader->getBlendFunc(); state.m_blend_src = convertBlendFactor( blendFunc.m_src ); state.m_blend_dst = convertBlendFactor( blendFunc.m_dst ); From c8bfc7f5c401c387b594da755b4ef0335f570c5f Mon Sep 17 00:00:00 2001 From: BraXi <6434152+BraXi@users.noreply.github.com> Date: Thu, 31 Jul 2025 01:23:05 +0200 Subject: [PATCH 9/9] rookie mistake? --- radiant/camwindow.cpp | 1 + radiant/renderstate.cpp | 26 +++++++++++++++++++++++++- 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/radiant/camwindow.cpp b/radiant/camwindow.cpp index 8773a8fe..5168068c 100644 --- a/radiant/camwindow.cpp +++ b/radiant/camwindow.cpp @@ -1996,6 +1996,7 @@ void CamWnd::Cam_Draw(){ | RENDER_DEPTHWRITE | RENDER_ALPHATEST | RENDER_BLEND + | RENDER_POLYGONOFFSET // braxi -- is this necessary? (without it decals zfight) | RENDER_CULLFACE | RENDER_COLOURARRAY | RENDER_OFFSETLINE diff --git a/radiant/renderstate.cpp b/radiant/renderstate.cpp index 89ffbb20..07fc379c 100644 --- a/radiant/renderstate.cpp +++ b/radiant/renderstate.cpp @@ -2069,7 +2069,7 @@ void OpenGLShader::construct( const char* name ){ else { state.m_sort = OpenGLState::eSortTranslucent; } - //BRAXI END + state.m_colour[3] = m_shader->getTrans(); BlendFunc blendFunc = m_shader->getBlendFunc(); @@ -2080,6 +2080,30 @@ void OpenGLShader::construct( const char* name ){ // state.m_state |= RENDER_DEPTHWRITE; // } } + + if ((m_shader->getFlags() & QER_DECAL) != 0) { + + if (!(state.m_state & RENDER_BLEND)) { + state.m_state |= RENDER_BLEND; + } + + if (!(state.m_state & RENDER_POLYGONOFFSET)) { + state.m_state |= RENDER_POLYGONOFFSET; + } + + state.m_sort = OpenGLState::eSortDecal; + + state.m_colour[3] = m_shader->getTrans(); + BlendFunc blendFunc = m_shader->getBlendFunc(); + state.m_blend_src = GL_SRC_ALPHA; + state.m_blend_dst = GL_ONE_MINUS_SRC_ALPHA; + state.m_depthfunc = GL_LEQUAL; + // if ( state.m_blend_src == GL_SRC_ALPHA || state.m_blend_dst == GL_SRC_ALPHA ) { + // state.m_state |= RENDER_DEPTHWRITE; + // } + } + //BRAXI END + else { state.m_state |= RENDER_DEPTHWRITE;