diff --git a/.gitignore b/.gitignore index c3ce012c..9ef9de41 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,9 @@ install .vscode .idea /.cache +/.vs +/icons +/tools/quake3/q3map2/.vs +/radiant/radiant.aps +/nrc-ncftu.rar +/nrc.rar 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/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/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/radiant/renderstate.cpp b/radiant/renderstate.cpp index caad8864..07fc379c 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; + } + + 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 ); @@ -2056,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; 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..16b93e4a 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,77 @@ struct game_ja : game_sof2 } }; +#ifdef PRAGMA_MAP +struct game_pragma : game_default +{ + game_pragma() + { + arg = "pragma"; + + gamePath = "ncftu"; + homeBasePath = ".ncftu"; + magic = "ncftu"; + + shaderPath = "devtools_scripts"; + + maxLMSurfaceVerts = 4096; + maxSurfaceVerts = 4096; + maxSurfaceIndexes = 4096 * 6; + + emitFlares = true; + flareShader = "gfx_flare"; + + lightmapSize = 1024; + lightmapsRGB = false; + + //texturesRGB = true; + //colorsRGB = true; + + deluxeMap = true; + deluxeMode = 0; // 0 - modelspace, 1 - tangentspace with renormalization, 2 - tangentspace without renormalization + + lightAngleHL = true; + noStyles = true; + + keepLights = true; + + patchSubdivisions = 4; + patchShadows = true; + + 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