Files
DoomRTX/neo/engine/renderer/tr_skydome.cpp
T
2026-05-24 11:54:07 -07:00

239 lines
5.0 KiB
C++

#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);
}