diff --git a/gameenv/data/shaders/lightmap.glsl b/gameenv/data/shaders/lightmap.glsl new file mode 100644 index 0000000..e69de29 diff --git a/mpfw/MPFW_Quake.cpp b/mpfw/MPFW_Quake.cpp index 01465bc..0b71494 100644 --- a/mpfw/MPFW_Quake.cpp +++ b/mpfw/MPFW_Quake.cpp @@ -307,6 +307,11 @@ void MPFW::Quake::Maps::MapFile::LoadBSPMap(std::string path) + for (int i = 0; i < data.lightMaps.size(); i++) { + rlUnloadTexture(data.lightMaps[i].glTextureID); + } + data.lightMaps.clear(); + std::print("Loading mip textures manually for now\n"); @@ -368,8 +373,22 @@ void MPFW::Quake::Maps::MapFile::LoadBSPMap(std::string path) data.renderFaces.clear(); + data.lightmap.clear(); + + data.lightmap.resize(data.header.lightmaps.size); + std::memcpy(data.lightmap.data(), Utils::Strings::IterativeStringExcerpt(buffer, data.header.lightmaps.offset, data.header.lightmaps.size).data(), data.header.lightmaps.size); + std::print("Precalculating faces and texture coordinates\n"); + data.planes.clear(); + data.planes.resize(data.header.planes.size / sizeof(Plane)); + + std::memcpy( + data.planes.data(), + Utils::Strings::IterativeStringExcerpt(buffer, data.header.planes.offset, data.header.planes.size).data(), + data.header.planes.size + ); + for (int i = 0; i < data.faces.size(); i++) { CalculatedFace cface; @@ -425,20 +444,87 @@ void MPFW::Quake::Maps::MapFile::LoadBSPMap(std::string path) } if (data.textures[data.texInfo[data.faces[i].texinfoId].textureId].name == "clip") cface.clipFace = true; if (data.textures[data.texInfo[data.faces[i].texinfoId].textureId].name == "trigger") cface.triggerFace = true; + int lmbase = data.faces[i].lightmap; + if (lmbase != -1) { + + // int lmw = data.textures[data.texInfo[data.faces[i].texinfoId].textureId].width; + // int lmh = data.textures[data.texInfo[data.faces[i].texinfoId].textureId].height; + + + std::vector polygon; + + for (int v = 0; v < cface.vertices.size(); v++) { + polygon.push_back(RLVec2qVec(cface.vertices[v])); + } + + BoundingBox faceBB = GenerateBoundingBoxPolygon(polygon); + + int planeType = data.planes[data.faces[i].planeId].type; + int valueForgotten = + planeType == 0 || planeType == 3 ? 0 : + planeType == 1 || planeType == 4 ? 1 : + 2; + + int lmw, lmh; + + switch (valueForgotten) { + case 0: // forgetting x + + lmw = static_cast((faceBB.max.y - faceBB.min.y) / 16); + lmh = static_cast((faceBB.max.z - faceBB.min.z) / 16); + + break; + case 1: // forgetting y + + lmw = static_cast((faceBB.max.x - faceBB.min.x) / 16); + lmh = static_cast((faceBB.max.z - faceBB.min.z) / 16); + + break; + case 2: // forgetting z + + lmw = static_cast((faceBB.max.x - faceBB.min.x) / 16); + lmh = static_cast((faceBB.max.y - faceBB.min.y) / 16); + + break; + default: + throw; + } + + Image lightmap = GenImageColor(lmw, lmh, WHITE); + cface.hasLightMap = true; + for (int y = 0; y < lmh; y++) { + for (int x = 0; x < lmw; x++) { + unsigned char lightValue = data.lightmap[y*lmw+x + lmbase]; + ImageDrawPixel(&lightmap, x, y, { + lightValue, + lightValue, + lightValue, + 255 + }); + } + } + + Texture lightmapTexture = LoadTextureFromImage(lightmap); + + rlMipTex lightmapRLMipTex; + lightmapRLMipTex.glTextureID = lightmapTexture.id; + lightmapRLMipTex.width = lightmapTexture.width; + lightmapRLMipTex.height = lightmapTexture.height; + lightmapRLMipTex.type = lightmapTexture.format; + data.lightMaps.push_back(lightmapRLMipTex); + + cface.glLightmapTextureId = lightmapTexture.id; + + UnloadImage(lightmap); + + } data.renderFaces.push_back(cface); } - data.planes.clear(); - data.planes.resize(data.header.planes.size / sizeof(Plane)); - - std::memcpy( - data.planes.data(), - Utils::Strings::IterativeStringExcerpt(buffer, data.header.planes.offset, data.header.planes.size).data(), - data.header.planes.size - ); + @@ -455,6 +541,20 @@ Vector3 MPFW::Quake::Maps::RLVec2qVec(Vector3 q) { return { q.z * 2, q.x * 2, q.y * 2 }; } +BoundingBox MPFW::Quake::Maps::GenerateBoundingBoxPolygon(std::vector poly) +{ + std::vector polyCopy = poly; + + std::sort(polyCopy.begin(), polyCopy.end(), [](Vector3 a, Vector3 b) { + return Vector3Distance({ 0,0,0 }, a) < Vector3Distance({ 0,0,0 }, b); + }); + + BoundingBox retval; + retval.min = polyCopy[0]; + retval.max = polyCopy[polyCopy.size() - 1]; + return retval; +} + void MPFW::Quake::Maps::Palette::LoadPalette(std::string path) { std::ifstream i(path, std::ios::binary); diff --git a/mpfw/MPFW_Quake.h b/mpfw/MPFW_Quake.h index 577b33d..f1a3568 100644 --- a/mpfw/MPFW_Quake.h +++ b/mpfw/MPFW_Quake.h @@ -103,11 +103,12 @@ namespace MPFW { struct CalculatedFace { std::vector vertices; std::vector texCoords; - int glTextureId, glTextureWidth, glTextureHeight; + int glTextureId, glTextureWidth, glTextureHeight, glLightmapTextureId; + bool hasLightMap = false; bool skyFace = false; bool triggerFace = false; bool clipFace = false; - + unsigned char baselight; }; @@ -172,7 +173,7 @@ namespace MPFW { struct MapData { BSPHeader header; - + std::vector lightmap; std::vector vertices; std::vector edges; std::vector models; @@ -186,7 +187,7 @@ namespace MPFW { std::vector renderFaces; - + std::vector lightMaps; // purely for unloading <3 }; class MapFile { @@ -211,6 +212,8 @@ namespace MPFW { void LoadBSPMap(std::string path); ~MapFile(){} }; + + BoundingBox GenerateBoundingBoxPolygon(std::vector poly); } } } diff --git a/mpfw/main.cpp b/mpfw/main.cpp index 9bb61f5..b896d5b 100644 --- a/mpfw/main.cpp +++ b/mpfw/main.cpp @@ -306,22 +306,41 @@ int main() { if (chr.cvars["vid_2d_background"] == "true") DrawRectangleGradientV(0, 0, GetScreenWidth(), GetScreenHeight(), WHITE, LIGHTGRAY); if (chr.cvars["vid_3d_renderer"] == "true") { - bool cullSky = chr.cvars["vid_3d_cull_sky"] == "true"; - bool cullClips = chr.cvars["vid_3d_cull_clips"] == "true"; - bool cullTriggers = chr.cvars["vid_3d_cull_triggers"] == "true"; + + // Grab booleans once at the start of rendering instead of continuously grabbing them + // 66->536 FPS on Quake start.bsp + // 500->8000 on test pre-lightmapping + + bool cullSky = chr.cvars["vid_3d_cull_sky"] == "true"; // if texture name starts by "sky" + bool cullClips = chr.cvars["vid_3d_cull_clips"] == "true"; // if texture name == "clip" + bool cullTriggers = chr.cvars["vid_3d_cull_triggers"] == "true"; // if texture name == "trigger" + BeginMode3D(camera); if(chr.cvars["vid_3d_grid"] == "true") DrawGrid(10000, 10); - rlColor4ub(255, 255, 255, 255); for (int i = 0; i < map.data.renderFaces.size(); i++) { + + // verify culling parameters before rendering if ( !(cullSky && map.data.renderFaces[i].skyFace) && !(cullClips && map.data.renderFaces[i].clipFace) && !(cullTriggers && map.data.renderFaces[i].triggerFace) ){ - - rlSetTexture(map.data.renderFaces[i].glTextureId); + + rlColor4ub( + 255,// - (unsigned char)map.data.renderFaces[i].baselight, + 255,// - (unsigned char)map.data.renderFaces[i].baselight, + 255,// - (unsigned char)map.data.renderFaces[i].baselight, + 255); + + if (map.data.renderFaces[i].hasLightMap) rlSetTexture(map.data.renderFaces[i].glLightmapTextureId); + else rlSetTexture(map.data.renderFaces[i].glTextureId); + + + + + for (int j = 1; j < map.data.renderFaces[i].vertices.size(); j++) { rlBegin(RL_QUADS); // for texturing reasons because rlgl @@ -341,7 +360,7 @@ int main() { rlVertex3f(b.x, b.y, b.z); rlTexCoord2f(ct.x, ct.y); rlVertex3f(c.x, c.y, c.z); - rlVertex3f(c.x, c.y, c.z); + rlVertex3f(c.x, c.y, c.z); // why does RLGL fuck up triangles? is there something i'm missing? rlEnd(); @@ -352,7 +371,10 @@ int main() { } EndMode3D(); } - DrawFPS(0, 0); + + + + DrawFPS(0, 0); // draw fps behind console for readability if (consoleOn) { DrawRectangle(0, 0, GetScreenWidth(), GetScreenHeight() / 2, {0,0,0,200}); @@ -379,6 +401,7 @@ int main() { } uiRenderer.Render(); + EndDrawing(); }