From 2f8cff90b63a3f2c543a8d718b26e1b89f9a1ad6 Mon Sep 17 00:00:00 2001 From: nashmuhandes Date: Fri, 24 Sep 2021 16:56:15 +0800 Subject: [PATCH] - Add lightmaps to the main shader (currently only OpenGL) - Create a version of CreateIndexedSectorVertices that works with lightmap sectors --- src/common/rendering/gl/gl_framebuffer.cpp | 23 ++++ src/common/rendering/gl/gl_framebuffer.h | 2 + src/common/rendering/gl/gl_renderer.h | 2 + src/common/rendering/gl/gl_shader.cpp | 1 + .../rendering/hwrenderer/data/buffers.h | 1 + .../hwrenderer/data/flatvertices.cpp | 5 +- .../rendering/hwrenderer/data/flatvertices.h | 15 +++ src/common/rendering/v_video.h | 3 +- src/maploader/maploader.cpp | 2 +- src/rendering/hwrenderer/hw_vertexbuilder.cpp | 111 ++++++++++++++++-- wadsrc/static/shaders/glsl/main.fp | 10 ++ wadsrc/static/shaders/glsl/main.vp | 6 + 12 files changed, 168 insertions(+), 13 deletions(-) diff --git a/src/common/rendering/gl/gl_framebuffer.cpp b/src/common/rendering/gl/gl_framebuffer.cpp index 668965a11..ab72ce6b3 100644 --- a/src/common/rendering/gl/gl_framebuffer.cpp +++ b/src/common/rendering/gl/gl_framebuffer.cpp @@ -364,6 +364,29 @@ void OpenGLFrameBuffer::BlurScene(float amount) GLRenderer->BlurScene(amount); } +void OpenGLFrameBuffer::InitLightmap(FLevelLocals *Level) +{ + if (Level->LMTextureData.Size() > 0) + { + GLint activeTex = 0; + glGetIntegerv(GL_ACTIVE_TEXTURE, &activeTex); + glActiveTexture(GL_TEXTURE0 + 17); + + if (GLRenderer->mLightMapID == 0) + glGenTextures(1, (GLuint*)&GLRenderer->mLightMapID); + + glBindTexture(GL_TEXTURE_2D_ARRAY, GLRenderer->mLightMapID); + glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGB16F, Level->LMTextureSize, Level->LMTextureSize, Level->LMTextureCount, 0, GL_RGB, GL_HALF_FLOAT, &Level->LMTextureData[0]); + glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glGenerateMipmap(GL_TEXTURE_2D_ARRAY); + + glActiveTexture(activeTex); + + Level->LMTextureData.Reset(); // We no longer need this, release the memory + } +} + void OpenGLFrameBuffer::SetViewportRects(IntRect *bounds) { Super::SetViewportRects(bounds); diff --git a/src/common/rendering/gl/gl_framebuffer.h b/src/common/rendering/gl/gl_framebuffer.h index 8f8a139b6..243533862 100644 --- a/src/common/rendering/gl/gl_framebuffer.h +++ b/src/common/rendering/gl/gl_framebuffer.h @@ -50,6 +50,8 @@ public: IIndexBuffer *CreateIndexBuffer() override; IDataBuffer *CreateDataBuffer(int bindingpoint, bool ssbo, bool needsresize) override; + void InitLightmap(FLevelLocals* Level) override; + // Retrieves a buffer containing image data for a screenshot. // Hint: Pitch can be negative for upside-down images, in which case buffer // points to the last row in the buffer, which will be the first row output. diff --git a/src/common/rendering/gl/gl_renderer.h b/src/common/rendering/gl/gl_renderer.h index 3a4c55a70..8c7be3b2f 100644 --- a/src/common/rendering/gl/gl_renderer.h +++ b/src/common/rendering/gl/gl_renderer.h @@ -61,6 +61,8 @@ public: FPresent3DRowShader *mPresent3dRowShader = nullptr; FShadowMapShader *mShadowMapShader = nullptr; + int mLightMapID = 0; + //FRotator mAngles; FGLRenderer(OpenGLFrameBuffer *fb); diff --git a/src/common/rendering/gl/gl_shader.cpp b/src/common/rendering/gl/gl_shader.cpp index 2ef56a288..51a72318e 100644 --- a/src/common/rendering/gl/gl_shader.cpp +++ b/src/common/rendering/gl/gl_shader.cpp @@ -298,6 +298,7 @@ bool FShader::Load(const char * name, const char * vert_prog_lump, const char * // textures uniform sampler2D tex; uniform sampler2D ShadowMap; + uniform sampler2DArray LightMap; uniform sampler2D texture2; uniform sampler2D texture3; uniform sampler2D texture4; diff --git a/src/common/rendering/hwrenderer/data/buffers.h b/src/common/rendering/hwrenderer/data/buffers.h index 586e5caa0..79f7db8c5 100644 --- a/src/common/rendering/hwrenderer/data/buffers.h +++ b/src/common/rendering/hwrenderer/data/buffers.h @@ -24,6 +24,7 @@ enum VATTR_VERTEX2, VATTR_NORMAL, VATTR_NORMAL2, + VATTR_LIGHTMAP, VATTR_MAX }; diff --git a/src/common/rendering/hwrenderer/data/flatvertices.cpp b/src/common/rendering/hwrenderer/data/flatvertices.cpp index 9a34b45ff..72c4504f9 100644 --- a/src/common/rendering/hwrenderer/data/flatvertices.cpp +++ b/src/common/rendering/hwrenderer/data/flatvertices.cpp @@ -93,10 +93,11 @@ FFlatVertexBuffer::FFlatVertexBuffer(int width, int height, int pipelineNbr): static const FVertexBufferAttribute format[] = { { 0, VATTR_VERTEX, VFmt_Float3, (int)myoffsetof(FFlatVertex, x) }, - { 0, VATTR_TEXCOORD, VFmt_Float2, (int)myoffsetof(FFlatVertex, u) } + { 0, VATTR_TEXCOORD, VFmt_Float2, (int)myoffsetof(FFlatVertex, u) }, + { 0, VATTR_LIGHTMAP, VFmt_Float3, (int)myoffsetof(FFlatVertex, lu) }, }; - mVertexBufferPipeline[n]->SetFormat(1, 2, sizeof(FFlatVertex), format); + mVertexBufferPipeline[n]->SetFormat(1, 3, sizeof(FFlatVertex), format); } mVertexBuffer = mVertexBufferPipeline[mPipelinePos]; diff --git a/src/common/rendering/hwrenderer/data/flatvertices.h b/src/common/rendering/hwrenderer/data/flatvertices.h index 619128a33..208adb34c 100644 --- a/src/common/rendering/hwrenderer/data/flatvertices.h +++ b/src/common/rendering/hwrenderer/data/flatvertices.h @@ -14,6 +14,8 @@ struct FFlatVertex { float x, z, y; // world position float u, v; // texture coordinates + float lu, lv; // lightmap texture coordinates + float lindex; // lightmap texture index void Set(float xx, float zz, float yy, float uu, float vv) { @@ -22,6 +24,19 @@ struct FFlatVertex y = yy; u = uu; v = vv; + lindex = -1.0f; + } + + void Set(float xx, float zz, float yy, float uu, float vv, float llu, float llv, float llindex) + { + x = xx; + z = zz; + y = yy; + u = uu; + v = vv; + lu = llu; + lv = llv; + lindex = llindex; } void SetVertex(float _x, float _y, float _z = 0) diff --git a/src/common/rendering/v_video.h b/src/common/rendering/v_video.h index 76bbd07a6..ed2b4238d 100644 --- a/src/common/rendering/v_video.h +++ b/src/common/rendering/v_video.h @@ -44,6 +44,7 @@ #include "intrect.h" #include "hw_shadowmap.h" #include "buffers.h" +#include "g_levellocals.h" struct FPortalSceneState; @@ -220,7 +221,7 @@ public: virtual int GetClientHeight() = 0; virtual void BlurScene(float amount) {} - virtual void InitLightmap() {} + virtual void InitLightmap(FLevelLocals *Level) {} // Interface to hardware rendering resources virtual IVertexBuffer *CreateVertexBuffer() { return nullptr; } diff --git a/src/maploader/maploader.cpp b/src/maploader/maploader.cpp index 8dcccfe8c..d11c892d0 100644 --- a/src/maploader/maploader.cpp +++ b/src/maploader/maploader.cpp @@ -3247,7 +3247,7 @@ void MapLoader::LoadLevel(MapData *map, const char *lumpname, int position) Level->ClearDynamic3DFloorData(); // CreateVBO must be run on the plain 3D floor data. CreateVBO(screen->mVertexData, Level->sectors); - screen->InitLightmap(); + screen->InitLightmap(Level); for (auto &sec : Level->sectors) { diff --git a/src/rendering/hwrenderer/hw_vertexbuilder.cpp b/src/rendering/hwrenderer/hw_vertexbuilder.cpp index bf5dd8bd0..f95f3c356 100644 --- a/src/rendering/hwrenderer/hw_vertexbuilder.cpp +++ b/src/rendering/hwrenderer/hw_vertexbuilder.cpp @@ -160,13 +160,18 @@ TArray BuildVertices(TArray §ors) // //========================================================================== -static F3DFloor* Find3DFloor(sector_t* target, sector_t* model) +static F3DFloor *Find3DFloor(sector_t* target, sector_t* model, int &ffloorIndex) { for (unsigned i = 0; i < target->e->XFloor.ffloors.Size(); i++) { F3DFloor* ffloor = target->e->XFloor.ffloors[i]; - if (ffloor->model == model && !(ffloor->flags & FF_THISINSIDE)) return ffloor; + if (ffloor->model == model && !(ffloor->flags & FF_THISINSIDE)) + { + ffloorIndex = i; + return ffloor; + } } + ffloorIndex = -1; return NULL; } @@ -183,12 +188,99 @@ static void SetFlatVertex(FFlatVertex& ffv, vertex_t* vt, const secplane_t& plan ffv.z = (float)plane.ZatPoint(vt); ffv.u = (float)vt->fX() / 64.f; ffv.v = -(float)vt->fY() / 64.f; + ffv.lindex = -1.0f; } - - -static int CreateIndexedSectorVertices(FFlatVertexBuffer* fvb, sector_t* sec, const secplane_t& plane, int floor, VertexContainer& verts) +static void SetFlatVertex(FFlatVertex& ffv, vertex_t* vt, const secplane_t& plane, float llu, float llv, float llindex) { + ffv.x = (float)vt->fX(); + ffv.y = (float)vt->fY(); + ffv.z = (float)plane.ZatPoint(vt); + ffv.u = (float)vt->fX() / 64.f; + ffv.v = -(float)vt->fY() / 64.f; + ffv.lu = llu; + ffv.lv = llv; + ffv.lindex = llindex; +} + +//========================================================================== +// +// Creates the vertices for one plane in one subsector w/lightmap support. +// Sectors with lightmaps cannot share subsector vertices. +// +//========================================================================== + +static int CreateIndexedSectorVerticesLM(FFlatVertexBuffer* fvb, sector_t* sec, const secplane_t& plane, int floor, int h, int lightmapIndex) +{ + int i, pos; + float diff; + + auto& ibo_data = fvb->ibo_data; + + int rt = ibo_data.Size(); + if (sec->transdoor && floor) diff = -1.f; + else diff = 0.f; + + // Allocate space + for (i = 0, pos = 0; i < sec->subsectorcount; i++) + { + pos += sec->subsectors[i]->numlines; + } + + auto& vbo_shadowdata = fvb->vbo_shadowdata; + int vi = vbo_shadowdata.Reserve(pos); + int idx = ibo_data.Reserve((pos - 2 * sec->subsectorcount) * 3); + + // Create the actual vertices. + for (i = 0, pos = 0; i < sec->subsectorcount; i++) + { + subsector_t* sub = sec->subsectors[i]; + LightmapSurface* lightmap = &sub->lightmap[h][lightmapIndex]; + if (lightmap->Type != ST_NULL) + { + float* luvs = lightmap->TexCoords; + int lindex = lightmap->LightmapNum; + for (unsigned int j = 0; j < sub->numlines; j++) + { + SetFlatVertex(vbo_shadowdata[vi + pos], sub->firstline->v1, plane, luvs[j * 2], luvs[j * 2 + 1], lindex); + vbo_shadowdata[vi + pos].z += diff; + pos++; + } + } + else + { + for (unsigned int j = 0; j < sub->numlines; j++) + { + SetFlatVertex(vbo_shadowdata[vi + pos], sub->firstline->v1, plane); + vbo_shadowdata[vi + pos].z += diff; + pos++; + } + } + } + + // Create the indices for the subsectors + for (int i = 0; i < sec->subsectorcount; i++) + { + subsector_t* sub = sec->subsectors[i]; + int firstndx = vi + pos; + for (unsigned int k = 2; k < sub->numlines; k++) + { + ibo_data[idx++] = firstndx; + ibo_data[idx++] = firstndx + k - 1; + ibo_data[idx++] = firstndx + k; + } + pos += sec->subsectors[i]->numlines; + } + + sec->ibocount = ibo_data.Size() - rt; + return rt; +} + +static int CreateIndexedSectorVertices(FFlatVertexBuffer* fvb, sector_t* sec, const secplane_t& plane, int floor, VertexContainer& verts, int h, int lightmapIndex) +{ + if (sec->HasLightmaps && lightmapIndex != -1) + return CreateIndexedSectorVerticesLM(fvb, sec, plane, floor, h, lightmapIndex); + auto& vbo_shadowdata = fvb->vbo_shadowdata; unsigned vi = vbo_shadowdata.Reserve(verts.vertices.Size()); float diff; @@ -225,14 +317,14 @@ static int CreateIndexedVertices(FFlatVertexBuffer* fvb, int h, sector_t* sec, c for (int n = 0; n < screen->mPipelineNbr; n++) sec->vboheight[n][h] = sec->GetPlaneTexZ(h); sec->ibocount = verts[sec->Index()].indices.Size(); - sec->iboindex[h] = CreateIndexedSectorVertices(fvb, sec, plane, floor, verts[sec->Index()]); + sec->iboindex[h] = CreateIndexedSectorVertices(fvb, sec, plane, floor, verts[sec->Index()], h, 0); // Next are all sectors using this one as heightsec TArray& fakes = sec->e->FakeFloor.Sectors; for (unsigned g = 0; g < fakes.Size(); g++) { sector_t* fsec = fakes[g]; - fsec->iboindex[2 + h] = CreateIndexedSectorVertices(fvb, fsec, plane, false, verts[fsec->Index()]); + fsec->iboindex[2 + h] = CreateIndexedSectorVertices(fvb, fsec, plane, false, verts[fsec->Index()], h, -1); } // and finally all attached 3D floors @@ -240,7 +332,8 @@ static int CreateIndexedVertices(FFlatVertexBuffer* fvb, int h, sector_t* sec, c for (unsigned g = 0; g < xf.Size(); g++) { sector_t* fsec = xf[g]; - F3DFloor* ffloor = Find3DFloor(fsec, sec); + int ffloorIndex; + F3DFloor* ffloor = Find3DFloor(fsec, sec, ffloorIndex); if (ffloor != NULL && ffloor->flags & FF_RENDERPLANES) { @@ -249,7 +342,7 @@ static int CreateIndexedVertices(FFlatVertexBuffer* fvb, int h, sector_t* sec, c if (dotop || dobottom) { - auto ndx = CreateIndexedSectorVertices(fvb, fsec, plane, false, verts[fsec->Index()]); + auto ndx = CreateIndexedSectorVertices(fvb, fsec, plane, false, verts[fsec->Index()], h, ffloorIndex + 1); if (dotop) ffloor->top.vindex = ndx; if (dobottom) ffloor->bottom.vindex = ndx; } diff --git a/wadsrc/static/shaders/glsl/main.fp b/wadsrc/static/shaders/glsl/main.fp index a27f113c0..09b7db863 100644 --- a/wadsrc/static/shaders/glsl/main.fp +++ b/wadsrc/static/shaders/glsl/main.fp @@ -7,10 +7,12 @@ layout(location = 3) in vec3 glowdist; layout(location = 4) in vec3 gradientdist; layout(location = 5) in vec4 vWorldNormal; layout(location = 6) in vec4 vEyeNormal; +layout(location = 7) in vec3 vLightmap; #ifdef NO_CLIPDISTANCE_SUPPORT layout(location = 7) in vec4 ClipDistanceA; layout(location = 8) in vec4 ClipDistanceB; +layout(location = 9) in vec3 vLightmap; #endif layout(location=0) out vec4 FragColor; @@ -655,6 +657,14 @@ vec4 getLightColor(Material material, float fogdist, float fogfactor) // color = ProcessLight(material, color); + // + // apply lightmaps + // + if (vLightmap.z >= 0.0) + { + color.rgb += texture(LightMap, vLightmap).rgb; + } + // // apply dynamic lights // diff --git a/wadsrc/static/shaders/glsl/main.vp b/wadsrc/static/shaders/glsl/main.vp index a410d5a4d..f952e5f21 100644 --- a/wadsrc/static/shaders/glsl/main.vp +++ b/wadsrc/static/shaders/glsl/main.vp @@ -5,6 +5,7 @@ layout(location = 2) in vec4 aColor; layout(location = 0) out vec4 vTexCoord; layout(location = 1) out vec4 vColor; +layout(location = 2) out vec3 vLightmap; #ifndef SIMPLE // we do not need these for simple shaders layout(location = 3) in vec4 aVertex2; @@ -16,11 +17,14 @@ layout(location = 3) out vec3 glowdist; layout(location = 4) out vec3 gradientdist; layout(location = 5) out vec4 vWorldNormal; layout(location = 6) out vec4 vEyeNormal; + +layout(location = 7) in vec3 aLightmap; #endif #ifdef NO_CLIPDISTANCE_SUPPORT layout(location = 7) out vec4 ClipDistanceA; layout(location = 8) out vec4 ClipDistanceB; +layout(location = 9) in vec3 aLightmap; #endif void main() @@ -51,6 +55,8 @@ void main() #endif #ifndef SIMPLE + vLightmap = aLightmap; + pixelpos.xyz = worldcoord.xyz; pixelpos.w = -eyeCoordPos.z/eyeCoordPos.w;