From 029fd186dcd47db62f398f81ae2b5963f386f84b Mon Sep 17 00:00:00 2001 From: Justin Marshall Date: Sun, 24 May 2026 11:54:07 -0700 Subject: [PATCH] Added skydome support. --- base/guis/loadscreenbeta.gui | 11 - neo/doom3/game/Game_local.cpp | 2 +- neo/doom3/game/PlayerView.cpp | 1 + neo/doom3/game/WorldSpawn.cpp | 2 + neo/doom3/game/WorldSpawn.h | 2 + neo/doom3/game/gamesys/TypeInfoGen.cpp | 6 + neo/doom3/game/gamesys/TypeInfoGen.h | 2 + neo/engine/doomdll.vcxproj | 4 +- neo/engine/doomdll.vcxproj.filters | 6 + neo/engine/opengl/x64/Debug/opengl.log | 3 +- neo/engine/renderer/RenderSystem_init.cpp | 22 +- neo/engine/renderer/RenderWorld.h | 1 + neo/engine/renderer/draw_common.cpp | 3 + neo/engine/renderer/tr_local.h | 2 + neo/engine/renderer/tr_skydome.cpp | 239 ++++++++++++++++++++++ neo/engine/tools/radiant/CamWnd.cpp | 2 +- neo/engine/tools/radiant/EditorEntity.cpp | 9 + neo/engine/tools/radiant/EditorEntity.h | 1 + 18 files changed, 281 insertions(+), 37 deletions(-) delete mode 100644 base/guis/loadscreenbeta.gui create mode 100644 neo/engine/renderer/tr_skydome.cpp diff --git a/base/guis/loadscreenbeta.gui b/base/guis/loadscreenbeta.gui deleted file mode 100644 index 2076edd4..00000000 --- a/base/guis/loadscreenbeta.gui +++ /dev/null @@ -1,11 +0,0 @@ -windowDef Desktop { - rect 0, 0, 1280, 720 - backcolor 0, 0, 0, 1 - - windowDef Background { - rect 0, 0, 1280, 720 - background "guis/assets/splash/launch" - matcolor 1 ,1, 1, 1 - visible 1 - } -} \ No newline at end of file diff --git a/neo/doom3/game/Game_local.cpp b/neo/doom3/game/Game_local.cpp index 60b2ace7..723d6aea 100644 --- a/neo/doom3/game/Game_local.cpp +++ b/neo/doom3/game/Game_local.cpp @@ -4430,7 +4430,7 @@ idGameLocal::GetMapLoadingGUI =============== */ void idGameLocal::GetMapLoadingGUI( char gui[ MAX_STRING_CHARS ] ) { - sprintf(gui, "guis/loadscreenbeta.gui"); + sprintf(gui, "guis/map/loading.gui"); } /* diff --git a/neo/doom3/game/PlayerView.cpp b/neo/doom3/game/PlayerView.cpp index 63f47677..ecfaa1a2 100644 --- a/neo/doom3/game/PlayerView.cpp +++ b/neo/doom3/game/PlayerView.cpp @@ -445,6 +445,7 @@ void idPlayerView::SingleView( idUserInterface *hud, const renderView_t *view ) // hack the shake in at the very last moment, so it can't cause any consistency problems renderView_t hackedView = *view; + hackedView.skyDomeMaterial = gameLocal.world->GetSkydomeMaterial(); hackedView.viewaxis = hackedView.viewaxis * ShakeAxis(); gameRenderWorld->RenderScene( &hackedView ); diff --git a/neo/doom3/game/WorldSpawn.cpp b/neo/doom3/game/WorldSpawn.cpp index 5e871f00..fe9ac99f 100644 --- a/neo/doom3/game/WorldSpawn.cpp +++ b/neo/doom3/game/WorldSpawn.cpp @@ -102,6 +102,8 @@ void idWorldspawn::Spawn( void ) { pm_stamina.SetFloat( 0.0f ); } + skydomeMaterial = declManager->FindMaterial(spawnArgs.GetString("skydome", "textures/skies/mars1")); + // load script scriptname = gameLocal.GetMapName(); scriptname.SetFileExtension( ".script" ); diff --git a/neo/doom3/game/WorldSpawn.h b/neo/doom3/game/WorldSpawn.h index 754ddabe..284177b5 100644 --- a/neo/doom3/game/WorldSpawn.h +++ b/neo/doom3/game/WorldSpawn.h @@ -48,10 +48,12 @@ public: void Save( idRestoreGame *savefile ); void Restore( idRestoreGame *savefile ); + const idMaterial* GetSkydomeMaterial() { return skydomeMaterial; } private: ID_SCRIPT_EVENT( "", 0 ) ID_SCRIPT_EVENT( "remove", 0 ) void Event_Remove( void ); + const idMaterial* skydomeMaterial; }; #endif /* !__GAME_WORLDSPAWN_H__ */ diff --git a/neo/doom3/game/gamesys/TypeInfoGen.cpp b/neo/doom3/game/gamesys/TypeInfoGen.cpp index e16cd8eb..a0316699 100644 --- a/neo/doom3/game/gamesys/TypeInfoGen.cpp +++ b/neo/doom3/game/gamesys/TypeInfoGen.cpp @@ -4277,6 +4277,9 @@ intptr_t idWorldspawn::Invoke(const char *functionName, void *param1) { Spawn(); return 0; }; + if(functionNameHash == 234239) { // GetSkydomeMaterial + return (intptr_t)GetSkydomeMaterial(); + }; if(functionNameHash == 153439) { // Event_Remove Event_Remove(); return 0; @@ -4290,6 +4293,9 @@ bool idWorldspawn::HasNativeFunction(const char *functionName) { if(functionNameHash == 63102) { // Spawn return true; }; + if(functionNameHash == 234239) { // GetSkydomeMaterial + return true; + }; if(functionNameHash == 153439) { // Event_Remove return true; }; diff --git a/neo/doom3/game/gamesys/TypeInfoGen.h b/neo/doom3/game/gamesys/TypeInfoGen.h index 90d2d21f..e688623d 100644 --- a/neo/doom3/game/gamesys/TypeInfoGen.h +++ b/neo/doom3/game/gamesys/TypeInfoGen.h @@ -4562,6 +4562,7 @@ static classVariableInfo_t renderView_t_typeInfo[] = { { "float[12]", "shaderParms", (intptr_t)(&((renderView_t *)0)->shaderParms), sizeof( ((renderView_t *)0)->shaderParms ) }, { "const idMaterial *", "globalMaterial", (intptr_t)(&((renderView_t *)0)->globalMaterial), sizeof( ((renderView_t *)0)->globalMaterial ) }, { "renderGlobalFog_t", "globalFog", (intptr_t)(&((renderView_t *)0)->globalFog), sizeof( ((renderView_t *)0)->globalFog ) }, + { "const idMaterial *", "skyDomeMaterial", (intptr_t)(&((renderView_t *)0)->skyDomeMaterial), sizeof( ((renderView_t *)0)->skyDomeMaterial ) }, { NULL, 0 } }; @@ -7064,6 +7065,7 @@ classVariableInfo_t idLight::typeInfo[] = { }; classVariableInfo_t idWorldspawn::typeInfo[] = { + { "const idMaterial *", "skydomeMaterial", (intptr_t)(&((idWorldspawn *)0)->skydomeMaterial), sizeof( ((idWorldspawn *)0)->skydomeMaterial ) }, { NULL, 0 } }; diff --git a/neo/engine/doomdll.vcxproj b/neo/engine/doomdll.vcxproj index 99526bde..b12890c5 100644 --- a/neo/engine/doomdll.vcxproj +++ b/neo/engine/doomdll.vcxproj @@ -408,6 +408,7 @@ + @@ -1616,6 +1617,7 @@ + @@ -3182,4 +3184,4 @@ - + \ No newline at end of file diff --git a/neo/engine/doomdll.vcxproj.filters b/neo/engine/doomdll.vcxproj.filters index 45cb73fb..a7118dfd 100644 --- a/neo/engine/doomdll.vcxproj.filters +++ b/neo/engine/doomdll.vcxproj.filters @@ -633,6 +633,9 @@ Framework + + Renderer + @@ -1808,6 +1811,9 @@ External\Detour + + Renderer + diff --git a/neo/engine/opengl/x64/Debug/opengl.log b/neo/engine/opengl/x64/Debug/opengl.log index af38cd63..0ec71399 100644 --- a/neo/engine/opengl/x64/Debug/opengl.log +++ b/neo/engine/opengl/x64/Debug/opengl.log @@ -1,5 +1,4 @@ - gl_d3d12raylight.cpp -priorityq-heap.obj : warning LNK4006: __gl_pqHeapNewPriorityQ already defined in priorityq.obj; second definition ignored +priorityq-heap.obj : warning LNK4006: __gl_pqHeapNewPriorityQ already defined in priorityq.obj; second definition ignored priorityq-heap.obj : warning LNK4006: __gl_pqHeapDeletePriorityQ already defined in priorityq.obj; second definition ignored priorityq-heap.obj : warning LNK4006: __gl_pqHeapInit already defined in priorityq.obj; second definition ignored priorityq-heap.obj : warning LNK4006: __gl_pqHeapInsert already defined in priorityq.obj; second definition ignored diff --git a/neo/engine/renderer/RenderSystem_init.cpp b/neo/engine/renderer/RenderSystem_init.cpp index 9dafb4e5..df0086e1 100644 --- a/neo/engine/renderer/RenderSystem_init.cpp +++ b/neo/engine/renderer/RenderSystem_init.cpp @@ -532,27 +532,7 @@ void R_InitOpenGL( void ) { tr.dxrWorldHandles[i] = glRaytracingCreateScene(); } -#ifdef _WIN32 - static bool glCheck = false; - if ( !glCheck && win32.osversion.dwMajorVersion == 6 ) { - glCheck = true; - if ( !idStr::Icmp( glConfig.vendor_string, "Microsoft" ) && idStr::FindText( glConfig.renderer_string, "OpenGL-D3D" ) != -1 ) { - if ( cvarSystem->GetCVarBool( "r_fullscreen" ) ) { - cmdSystem->BufferCommandText( CMD_EXEC_NOW, "vid_restart partial windowed\n" ); - Sys_GrabMouseCursor( false ); - } - int ret = MessageBox( NULL, "Please install OpenGL drivers from your graphics hardware vendor to run " GAME_NAME ".\nYour OpenGL functionality is limited.", - "Insufficient OpenGL capabilities", MB_OKCANCEL | MB_ICONWARNING | MB_TASKMODAL ); - if ( ret == IDCANCEL ) { - cmdSystem->BufferCommandText( CMD_EXEC_APPEND, "quit\n" ); - cmdSystem->ExecuteCommandBuffer(); - } - if ( cvarSystem->GetCVarBool( "r_fullscreen" ) ) { - cmdSystem->BufferCommandText( CMD_EXEC_APPEND, "vid_restart\n" ); - } - } - } -#endif + R_InitSkyDome(); } /* diff --git a/neo/engine/renderer/RenderWorld.h b/neo/engine/renderer/RenderWorld.h index 6dc11ee7..2ee7245c 100644 --- a/neo/engine/renderer/RenderWorld.h +++ b/neo/engine/renderer/RenderWorld.h @@ -534,6 +534,7 @@ typedef struct renderView_s { const idMaterial* globalMaterial; // used to override everything draw renderGlobalFog_t globalFog; // fixed-function global depth fog + const idMaterial* skyDomeMaterial; #ifdef QUAKE4 // RAVEN BEGIN // mwhitlock: Xenon texture streaming. diff --git a/neo/engine/renderer/draw_common.cpp b/neo/engine/renderer/draw_common.cpp index e6db97a2..7f004241 100644 --- a/neo/engine/renderer/draw_common.cpp +++ b/neo/engine/renderer/draw_common.cpp @@ -1524,6 +1524,9 @@ void RB_STD_DrawView( void ) { // clear the z buffer, set the projection matrix, etc RB_BeginDrawingView(); + // Draw the sky. + RB_DrawSkyDome(backEnd.viewDef); + // fill the depth buffer and clear color buffer to black except on // subviews RB_STD_FillDepthBuffer( drawSurfs, numDrawSurfs ); diff --git a/neo/engine/renderer/tr_local.h b/neo/engine/renderer/tr_local.h index 247afa7a..a9823710 100644 --- a/neo/engine/renderer/tr_local.h +++ b/neo/engine/renderer/tr_local.h @@ -1665,4 +1665,6 @@ static void RB_CopyModelMatrixToDXRTransform(const float* modelMatrix, float out void RB_PrepareStageTexturing(const shaderStage_t* pStage, const drawSurf_t* surf, idDrawVert* ac); +#include "tr_skydome.h" + #endif /* !__TR_LOCAL_H__ */ diff --git a/neo/engine/renderer/tr_skydome.cpp b/neo/engine/renderer/tr_skydome.cpp new file mode 100644 index 00000000..38dca686 --- /dev/null +++ b/neo/engine/renderer/tr_skydome.cpp @@ -0,0 +1,239 @@ +#include "precompiled.h" +#pragma hdrstop + +#include "tr_local.h" + +static srfTriangles_t* g_skyDomeTri = NULL; +static const idMaterial* g_skyDomeMat = NULL; + +static idCVar r_skyDome("r_skyDome", "1", CVAR_RENDERER | CVAR_BOOL, "render procedural skydome"); +static idCVar r_skyDomeRadius("r_skyDomeRadius", "8192", CVAR_RENDERER | CVAR_FLOAT, "skydome radius (world units)"); +static idCVar r_skyDomeRings("r_skyDomeRings", "24", CVAR_RENDERER | CVAR_INTEGER, "skydome vertical subdivisions"); +static idCVar r_skyDomeSegments("r_skyDomeSegments", "48", CVAR_RENDERER | CVAR_INTEGER, "skydome horizontal subdivisions"); + +static void R_UploadSkyDomeMeshToVertexCache(srfTriangles_t* tri) { + if (!tri) { + return; + } + + if (tri->ambientCache) { + vertexCache.Free(tri->ambientCache); + tri->ambientCache = 0; + } + + if (tri->indexCache) { + vertexCache.Free(tri->indexCache); + tri->indexCache = 0; + } + + vertexCache.Alloc( + tri->verts, + tri->numVerts * sizeof(tri->verts[0]), + &tri->ambientCache + ); + + vertexCache.Alloc( + tri->indexes, + tri->numIndexes * sizeof(tri->indexes[0]), + &tri->indexCache + ); +} + +// Build a hemisphere, top half. Inside-facing draw. +static srfTriangles_t* R_BuildSkyDomeMesh(int rings, int segs, float radius) { + rings = Max(rings, 4); + segs = Max(segs, 8); + + const int vertsPerRing = segs + 1; + const int numVerts = (rings + 1) * vertsPerRing; + + const int numQuads = rings * segs; + const int numTris = numQuads * 2; + const int numIndexes = numTris * 3; + + srfTriangles_t* tri = R_AllocStaticTriSurf(); + R_AllocStaticTriSurfVerts(tri, numVerts); + R_AllocStaticTriSurfIndexes(tri, numIndexes); + + idDrawVert* v = tri->verts; + glIndex_t* idx = tri->indexes; + + int vi = 0; + + for (int r = 0; r <= rings; r++) { + const float t = (float)r / (float)rings; + const float phi = t * idMath::HALF_PI; + + const float sinPhi = idMath::Sin(phi); + const float cosPhi = idMath::Cos(phi); + + for (int s = 0; s <= segs; s++) { + const float u = (float)s / (float)segs; + const float theta = u * idMath::TWO_PI; + + const float sinTheta = idMath::Sin(theta); + const float cosTheta = idMath::Cos(theta); + + idVec3 dir; + dir.x = cosTheta * cosPhi; + dir.y = sinTheta * cosPhi; + dir.z = sinPhi; + + v[vi].xyz = dir * radius; + + float uu = idMath::ATan(dir.y, dir.x) / idMath::TWO_PI + 0.5f; + float vv = idMath::ASin(idMath::ClampFloat(-1.0f, 1.0f, dir.z)) / idMath::PI + 0.5f; + + vv = 1.0f - vv; + + v[vi].st.x = uu; + v[vi].st.y = vv; + + v[vi].normal = dir; + v[vi].tangents[0].Set(-sinTheta, cosTheta, 0.0f); + v[vi].tangents[1].Set(0.0f, 0.0f, 1.0f); + + v[vi].color[0] = 255; + v[vi].color[1] = 255; + v[vi].color[2] = 255; + v[vi].color[3] = 255; + + vi++; + } + } + + int ii = 0; + + for (int r = 0; r < rings; r++) { + for (int s = 0; s < segs; s++) { + const int i0 = r * vertsPerRing + s; + const int i1 = i0 + 1; + const int i2 = (r + 1) * vertsPerRing + s; + const int i3 = i2 + 1; + + idx[ii++] = i0; + idx[ii++] = i2; + idx[ii++] = i1; + + idx[ii++] = i1; + idx[ii++] = i2; + idx[ii++] = i3; + } + } + + tri->numVerts = numVerts; + tri->numIndexes = numIndexes; + + R_BoundTriSurf(tri); + + R_UploadSkyDomeMeshToVertexCache(tri); + + return tri; +} + +void R_InitSkyDome() { + if (g_skyDomeTri) { + return; + } + + g_skyDomeTri = R_BuildSkyDomeMesh( + r_skyDomeRings.GetInteger(), + r_skyDomeSegments.GetInteger(), + r_skyDomeRadius.GetFloat() + ); +} + +void R_ShutdownSkyDome() { + if (g_skyDomeTri) { + if (g_skyDomeTri->ambientCache) { + vertexCache.Free(g_skyDomeTri->ambientCache); + g_skyDomeTri->ambientCache = 0; + } + + if (g_skyDomeTri->indexCache) { + vertexCache.Free(g_skyDomeTri->indexCache); + g_skyDomeTri->indexCache = 0; + } + + R_FreeStaticTriSurf(g_skyDomeTri); + g_skyDomeTri = NULL; + } + + g_skyDomeMat = NULL; +} + +static const idMaterial* R_GetSkyDomeMaterial() { + return backEnd.viewDef->renderView.skyDomeMaterial; +} + +void RB_DrawSkyDome(const viewDef_t* viewDef) { + if (!r_skyDome.GetBool()) { + return; + } + + if (!g_skyDomeTri || !g_skyDomeTri->ambientCache || !g_skyDomeTri->indexCache) { + return; + } + + g_skyDomeMat = R_GetSkyDomeMaterial(); + + if (!g_skyDomeMat) { + return; + } + + glDepthMask(GL_FALSE); + glDisable(GL_CULL_FACE); + + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + + float mv[16]; + memcpy(mv, backEnd.viewDef->worldSpace.modelViewMatrix, sizeof(mv)); + + mv[12] = 0.0f; + mv[13] = 0.0f; + mv[14] = 0.0f; + + glLoadMatrixf(mv); + + GL_SelectTexture(0); + + const shaderStage_t* stage = g_skyDomeMat->GetStage(0); + + if (stage && stage->texture.image) { + stage->texture.image->Bind(); + } + else { + globalImages->whiteImage->Bind(); + } + + idDrawVert* verts = (idDrawVert*)vertexCache.Position(g_skyDomeTri->ambientCache); + + glEnableClientState(GL_VERTEX_ARRAY); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + + glVertexPointer( + 3, + GL_FLOAT, + sizeof(idDrawVert), + verts->xyz.ToFloatPtr() + ); + + glTexCoordPointer( + 2, + GL_FLOAT, + sizeof(idDrawVert), + verts->st.ToFloatPtr() + ); + + glGeometryFlagf(GEOMETRY_FLAG_UNLIT); + RB_DrawElementsWithCounters(g_skyDomeTri); + glGeometryFlagf(GEOMETRY_FLAG_NONE); + + glPopMatrix(); + + glDepthMask(GL_TRUE); + glEnable(GL_CULL_FACE); + + glClear(GL_DEPTH_BUFFER_BIT); +} \ No newline at end of file diff --git a/neo/engine/tools/radiant/CamWnd.cpp b/neo/engine/tools/radiant/CamWnd.cpp index 4145953c..657946e7 100644 --- a/neo/engine/tools/radiant/CamWnd.cpp +++ b/neo/engine/tools/radiant/CamWnd.cpp @@ -6139,7 +6139,7 @@ void CCamWnd::Cam_Render() { // the editor uses opposite pitch convention refdef.viewaxis = idAngles(-m_Camera.angles.pitch, m_Camera.angles.yaw, m_Camera.angles.roll).ToMat3(); - + refdef.skyDomeMaterial = world_entity->GetKeyMaterial("skydome", "textures/skies/mars1"); refdef.width = SCREEN_WIDTH; refdef.height = SCREEN_HEIGHT; refdef.fov_x = 90; diff --git a/neo/engine/tools/radiant/EditorEntity.cpp b/neo/engine/tools/radiant/EditorEntity.cpp index c0b3233e..3478023d 100644 --- a/neo/engine/tools/radiant/EditorEntity.cpp +++ b/neo/engine/tools/radiant/EditorEntity.cpp @@ -68,6 +68,15 @@ const char *idEditorEntity::GetKeyString(int iIndex) return NULL; } +const idMaterial* idEditorEntity::GetKeyMaterial(const char* key, const char* defaultMaterial) { + const char* value = ValueForKey(key); + + if (value == NULL || value[0] == 0) { + value = defaultMaterial; + } + + return declManager->FindMaterial(value, false); +} /* ======================================================================================================================= diff --git a/neo/engine/tools/radiant/EditorEntity.h b/neo/engine/tools/radiant/EditorEntity.h index 36e0122b..cf0b2b8a 100644 --- a/neo/engine/tools/radiant/EditorEntity.h +++ b/neo/engine/tools/radiant/EditorEntity.h @@ -51,6 +51,7 @@ public: const char *ValueForKey(const char *key); int GetNumKeys(); const char *GetKeyString(int iIndex); + const idMaterial* GetKeyMaterial(const char* key, const char *defaultMaterial); void SetKeyValue(const char *key, const char *value, bool trackAngles = true); void DeleteKey(const char *key); float FloatForKey(const char *key);