diff --git a/src/maploader/maploader.cpp b/src/maploader/maploader.cpp index 4272a4dfb..a683b3e76 100644 --- a/src/maploader/maploader.cpp +++ b/src/maploader/maploader.cpp @@ -2979,51 +2979,45 @@ void MapLoader::InitLevelMesh(MapData* map) Level->lightmaps = Level->lightmaps || *genlightmaps; // Allow lightmapping in non-lightmapped levels. } - // Levelmesh and lightmap binding/loading + // Allocate room for surface arrays on sectors, sides and their 3D floors + + unsigned int allSurfaces = 0; + + for (unsigned int i = 0; i < Level->sides.Size(); i++) + allSurfaces += 4 + Level->sides[i].sector->e->XFloor.ffloors.Size(); + + for (unsigned int i = 0; i < Level->subsectors.Size(); i++) + allSurfaces += 2 + Level->subsectors[i].sector->e->XFloor.ffloors.Size() * 2; + + Level->LMSurfaces.Resize(allSurfaces); + memset(Level->LMSurfaces.Data(), 0, sizeof(DoomLevelMeshSurface*) * allSurfaces); + + unsigned int offset = 0; + for (unsigned int i = 0; i < Level->sides.Size(); i++) + { + auto& side = Level->sides[i]; + side.lightmap = &Level->LMSurfaces[offset]; + offset += 4 + side.sector->e->XFloor.ffloors.Size(); + } + for (unsigned int i = 0; i < Level->subsectors.Size(); i++) + { + auto& subsector = Level->subsectors[i]; + unsigned int count = 1 + subsector.sector->e->XFloor.ffloors.Size(); + subsector.lightmap[0] = &Level->LMSurfaces[offset]; + subsector.lightmap[1] = &Level->LMSurfaces[offset + count]; + offset += count * 2; + } + + // Create the levelmesh Level->levelMesh = new DoomLevelMesh(*Level); + // Lightmap binding/loading if (Level->lightmaps) { if (!LoadLightmap(map)) { Level->levelMesh->PackLightmapAtlas(); } - - // Allocate room for lightmap arrays on sectors, sides and their 3D floors - - unsigned int allSurfaces = 0; - - for (unsigned int i = 0; i < Level->sides.Size(); i++) - allSurfaces += 4 + Level->sides[i].sector->e->XFloor.ffloors.Size(); - - for (unsigned int i = 0; i < Level->subsectors.Size(); i++) - allSurfaces += 2 + Level->subsectors[i].sector->e->XFloor.ffloors.Size() * 2; - - Level->LMSurfaces.Resize(allSurfaces); - memset(Level->LMSurfaces.Data(), 0, sizeof(DoomLevelMeshSurface*) * allSurfaces); - - unsigned int offset = 0; - for (unsigned int i = 0; i < Level->sides.Size(); i++) - { - auto& side = Level->sides[i]; - int count = 4 + side.sector->e->XFloor.ffloors.Size(); - side.lightmap = TArrayView(&Level->LMSurfaces[offset], count); - offset += count; - } - for (unsigned int i = 0; i < Level->subsectors.Size(); i++) - { - auto& subsector = Level->subsectors[i]; - unsigned int count = 1 + subsector.sector->e->XFloor.ffloors.Size(); - subsector.lightmap[0] = TArrayView(&Level->LMSurfaces[offset], count); - subsector.lightmap[1] = TArrayView(&Level->LMSurfaces[offset + count], count); - offset += count * 2; - } - - Level->levelMesh->BindLightmapSurfacesToGeometry(*Level); - } - else - { - Level->levelMesh->DisableLightmaps(); } } diff --git a/src/rendering/hwrenderer/doom_levelmesh.cpp b/src/rendering/hwrenderer/doom_levelmesh.cpp index 788082c60..4061589c5 100644 --- a/src/rendering/hwrenderer/doom_levelmesh.cpp +++ b/src/rendering/hwrenderer/doom_levelmesh.cpp @@ -167,21 +167,6 @@ void DoomLevelMesh::PackLightmapAtlas() static_cast(StaticMesh.get())->PackLightmapAtlas(0); } -void DoomLevelMesh::BindLightmapSurfacesToGeometry(FLevelLocals& doomMap) -{ - static_cast(StaticMesh.get())->BindLightmapSurfacesToGeometry(doomMap); -} - -void DoomLevelMesh::DisableLightmaps() -{ - static_cast(StaticMesh.get())->DisableLightmaps(); -} - -void DoomLevelMesh::DumpMesh(const FString& objFilename, const FString& mtlFilename) const -{ - static_cast(StaticMesh.get())->DumpMesh(objFilename, mtlFilename); -} - int DoomLevelMesh::AddSurfaceLights(const LevelMeshSurface* surface, LevelMeshLight* list, int listMaxSize) { const DoomLevelMeshSurface* doomsurf = static_cast(surface); @@ -260,3 +245,114 @@ int DoomLevelMesh::AddSurfaceLights(const LevelMeshSurface* surface, LevelMeshLi return listpos; } + +void DoomLevelMesh::DumpMesh(const FString& objFilename, const FString& mtlFilename) const +{ + DoomLevelSubmesh* submesh = static_cast(StaticMesh.get()); + + auto f = fopen(objFilename.GetChars(), "w"); + + fprintf(f, "# DoomLevelMesh debug export\n"); + fprintf(f, "# MeshVertices: %u, MeshElements: %u, Surfaces: %u\n", submesh->MeshVertices.Size(), submesh->MeshElements.Size(), submesh->Surfaces.Size()); + fprintf(f, "mtllib %s\n", mtlFilename.GetChars()); + + double scale = 1 / 10.0; + + for (const auto& v : submesh->MeshVertices) + { + fprintf(f, "v %f %f %f\n", v.x * scale, v.y * scale, v.z * scale); + } + + for (const auto& v : submesh->MeshVertices) + { + fprintf(f, "vt %f %f\n", v.lu, v.lv); + } + + auto name = [](DoomLevelMeshSurfaceType type) -> const char* { + switch (type) + { + case ST_CEILING: + return "ceiling"; + case ST_FLOOR: + return "floor"; + case ST_LOWERSIDE: + return "lowerside"; + case ST_UPPERSIDE: + return "upperside"; + case ST_MIDDLESIDE: + return "middleside"; + case ST_UNKNOWN: + return "unknown"; + default: + break; + } + return "error"; + }; + + + uint32_t lastSurfaceIndex = -1; + + + bool useErrorMaterial = false; + int highestUsedAtlasPage = -1; + + for (unsigned i = 0, count = submesh->MeshElements.Size(); i + 2 < count; i += 3) + { + auto index = submesh->MeshSurfaceIndexes[i / 3]; + + if (index != lastSurfaceIndex) + { + lastSurfaceIndex = index; + + if (unsigned(index) >= submesh->Surfaces.Size()) + { + fprintf(f, "o Surface[%d] (bad index)\n", index); + fprintf(f, "usemtl error\n"); + + useErrorMaterial = true; + } + else + { + const auto& surface = submesh->Surfaces[index]; + fprintf(f, "o Surface[%d] %s %d%s\n", index, name(surface.Type), surface.TypeIndex, surface.bSky ? " sky" : ""); + fprintf(f, "usemtl lightmap%d\n", surface.AtlasTile.ArrayIndex); + + if (surface.AtlasTile.ArrayIndex > highestUsedAtlasPage) + { + highestUsedAtlasPage = surface.AtlasTile.ArrayIndex; + } + } + } + + // fprintf(f, "f %d %d %d\n", MeshElements[i] + 1, MeshElements[i + 1] + 1, MeshElements[i + 2] + 1); + fprintf(f, "f %d/%d %d/%d %d/%d\n", + submesh->MeshElements[i + 0] + 1, submesh->MeshElements[i + 0] + 1, + submesh->MeshElements[i + 1] + 1, submesh->MeshElements[i + 1] + 1, + submesh->MeshElements[i + 2] + 1, submesh->MeshElements[i + 2] + 1); + + } + + fclose(f); + + // material + + f = fopen(mtlFilename.GetChars(), "w"); + + fprintf(f, "# DoomLevelMesh debug export\n"); + + if (useErrorMaterial) + { + fprintf(f, "# Surface indices that are referenced, but do not exists in the 'Surface' array\n"); + fprintf(f, "newmtl error\nKa 1 0 0\nKd 1 0 0\nKs 1 0 0\n"); + } + + for (int page = 0; page <= highestUsedAtlasPage; ++page) + { + fprintf(f, "newmtl lightmap%d\n", page); + fprintf(f, "Ka 1 1 1\nKd 1 1 1\nKs 0 0 0\n"); + fprintf(f, "map_Ka lightmap%d.png\n", page); + fprintf(f, "map_Kd lightmap%d.png\n", page); + } + + fclose(f); +} diff --git a/src/rendering/hwrenderer/doom_levelmesh.h b/src/rendering/hwrenderer/doom_levelmesh.h index 66e412048..fba2c067e 100644 --- a/src/rendering/hwrenderer/doom_levelmesh.h +++ b/src/rendering/hwrenderer/doom_levelmesh.h @@ -14,7 +14,5 @@ public: void BeginFrame(FLevelLocals& doomMap); bool TraceSky(const FVector3& start, FVector3 direction, float dist); void PackLightmapAtlas(); - void BindLightmapSurfacesToGeometry(FLevelLocals& doomMap); - void DisableLightmaps(); void DumpMesh(const FString& objFilename, const FString& mtlFilename) const; }; diff --git a/src/rendering/hwrenderer/doom_levelsubmesh.cpp b/src/rendering/hwrenderer/doom_levelsubmesh.cpp index 00b3e07e5..9a75df8e5 100644 --- a/src/rendering/hwrenderer/doom_levelsubmesh.cpp +++ b/src/rendering/hwrenderer/doom_levelsubmesh.cpp @@ -37,6 +37,7 @@ void DoomLevelSubmesh::CreateStatic(FLevelLocals& doomMap) } CreateSubsectorSurfaces(doomMap); + LinkSurfaces(doomMap); CreateIndexes(); SetupLightmapUvs(doomMap); @@ -79,13 +80,13 @@ void DoomLevelSubmesh::UpdateDynamic(FLevelLocals& doomMap, int lightmapStartInd } } + LinkSurfaces(doomMap); CreateIndexes(); SetupLightmapUvs(doomMap); BuildTileSurfaceLists(); UpdateCollision(); PackLightmapAtlas(lightmapStartIndex); - BindLightmapSurfacesToGeometry(doomMap); } void DoomLevelSubmesh::CreateIndexes() @@ -97,6 +98,7 @@ void DoomLevelSubmesh::CreateIndexes() unsigned int pos = s.startVertIndex; FFlatVertex* verts = &MeshVertices[pos]; + s.Vertices = verts; s.startElementIndex = MeshElements.Size(); s.numElements = 0; @@ -309,17 +311,12 @@ void DoomLevelSubmesh::CreatePortals() } } -void DoomLevelSubmesh::BindLightmapSurfacesToGeometry(FLevelLocals& doomMap) +void DoomLevelSubmesh::LinkSurfaces(FLevelLocals& doomMap) { - // Link surfaces for (auto& surface : Surfaces) { - surface.Vertices = &MeshVertices[surface.startVertIndex]; - if (surface.Type == ST_FLOOR || surface.Type == ST_CEILING) { - if (surface.Subsector->firstline && surface.Subsector->firstline->sidedef) - surface.Subsector->firstline->sidedef->sector->HasLightmaps = true; SetSubsectorLightmap(&surface); } else @@ -331,6 +328,9 @@ void DoomLevelSubmesh::BindLightmapSurfacesToGeometry(FLevelLocals& doomMap) void DoomLevelSubmesh::SetSubsectorLightmap(DoomLevelMeshSurface* surface) { + if (surface->Subsector->firstline && surface->Subsector->firstline->sidedef) + surface->Subsector->firstline->sidedef->sector->HasLightmaps = true; + if (!surface->ControlSector) { int index = surface->Type == ST_CEILING ? 1 : 0; @@ -1148,118 +1148,9 @@ bool DoomLevelSubmesh::IsDegenerate(const FVector3 &v0, const FVector3 &v1, cons return crosslengthsqr <= 1.e-6f; } -void DoomLevelSubmesh::DumpMesh(const FString& objFilename, const FString& mtlFilename) const -{ - auto f = fopen(objFilename.GetChars(), "w"); - - fprintf(f, "# DoomLevelMesh debug export\n"); - fprintf(f, "# MeshVertices: %u, MeshElements: %u, Surfaces: %u\n", MeshVertices.Size(), MeshElements.Size(), Surfaces.Size()); - fprintf(f, "mtllib %s\n", mtlFilename.GetChars()); - - double scale = 1 / 10.0; - - for (const auto& v : MeshVertices) - { - fprintf(f, "v %f %f %f\n", v.x * scale, v.y * scale, v.z * scale); - } - - for (const auto& v : MeshVertices) - { - fprintf(f, "vt %f %f\n", v.lu, v.lv); - } - - auto name = [](DoomLevelMeshSurfaceType type) -> const char* { - switch (type) - { - case ST_CEILING: - return "ceiling"; - case ST_FLOOR: - return "floor"; - case ST_LOWERSIDE: - return "lowerside"; - case ST_UPPERSIDE: - return "upperside"; - case ST_MIDDLESIDE: - return "middleside"; - case ST_UNKNOWN: - return "unknown"; - default: - break; - } - return "error"; - }; - - - uint32_t lastSurfaceIndex = -1; - - - bool useErrorMaterial = false; - int highestUsedAtlasPage = -1; - - for (unsigned i = 0, count = MeshElements.Size(); i + 2 < count; i += 3) - { - auto index = MeshSurfaceIndexes[i / 3]; - - if(index != lastSurfaceIndex) - { - lastSurfaceIndex = index; - - if (unsigned(index) >= Surfaces.Size()) - { - fprintf(f, "o Surface[%d] (bad index)\n", index); - fprintf(f, "usemtl error\n"); - - useErrorMaterial = true; - } - else - { - const auto& surface = Surfaces[index]; - fprintf(f, "o Surface[%d] %s %d%s\n", index, name(surface.Type), surface.TypeIndex, surface.bSky ? " sky" : ""); - fprintf(f, "usemtl lightmap%d\n", surface.AtlasTile.ArrayIndex); - - if (surface.AtlasTile.ArrayIndex > highestUsedAtlasPage) - { - highestUsedAtlasPage = surface.AtlasTile.ArrayIndex; - } - } - } - - // fprintf(f, "f %d %d %d\n", MeshElements[i] + 1, MeshElements[i + 1] + 1, MeshElements[i + 2] + 1); - fprintf(f, "f %d/%d %d/%d %d/%d\n", - MeshElements[i + 0] + 1, MeshElements[i + 0] + 1, - MeshElements[i + 1] + 1, MeshElements[i + 1] + 1, - MeshElements[i + 2] + 1, MeshElements[i + 2] + 1); - - } - - fclose(f); - - // material - - f = fopen(mtlFilename.GetChars(), "w"); - - fprintf(f, "# DoomLevelMesh debug export\n"); - - if (useErrorMaterial) - { - fprintf(f, "# Surface indices that are referenced, but do not exists in the 'Surface' array\n"); - fprintf(f, "newmtl error\nKa 1 0 0\nKd 1 0 0\nKs 1 0 0\n"); - } - - for (int page = 0; page <= highestUsedAtlasPage; ++page) - { - fprintf(f, "newmtl lightmap%d\n", page); - fprintf(f, "Ka 1 1 1\nKd 1 1 1\nKs 0 0 0\n"); - fprintf(f, "map_Ka lightmap%d.png\n", page); - fprintf(f, "map_Kd lightmap%d.png\n", page); - } - - fclose(f); -} - void DoomLevelSubmesh::SetupLightmapUvs(FLevelLocals& doomMap) { - LMTextureSize = 1024; // TODO cvar + LMTextureSize = 1024; for (auto& surface : Surfaces) { diff --git a/src/rendering/hwrenderer/doom_levelsubmesh.h b/src/rendering/hwrenderer/doom_levelsubmesh.h index 0abc535fc..04ffab10d 100644 --- a/src/rendering/hwrenderer/doom_levelsubmesh.h +++ b/src/rendering/hwrenderer/doom_levelsubmesh.h @@ -47,13 +47,10 @@ public: unsigned int GetSurfaceIndex(const LevelMeshSurface* surface) const override { return (unsigned int)(ptrdiff_t)(static_cast(surface) - Surfaces.Data()); } int GetSurfaceCount() override { return Surfaces.Size(); } - void DumpMesh(const FString& objFilename, const FString& mtlFilename) const; - // Used by Maploader - void BindLightmapSurfacesToGeometry(FLevelLocals& doomMap); + void LinkSurfaces(FLevelLocals& doomMap); void PackLightmapAtlas(int lightmapStartIndex); void CreatePortals(); - void DisableLightmaps() { /*Surfaces.Clear();*/ } // Temp hack that disables lightmapping TArray Surfaces; TArray sectorGroup; // index is sector, value is sectorGroup