mirror of
https://github.com/ZDoom/qzdoom.git
synced 2025-03-10 11:11:51 +00:00
- Add support for loading lightmap data generated by ZDRay
- Initialize lightmap texture in the hardware abstract parts of the engine
This commit is contained in:
parent
3ef60a40a5
commit
39481f0d07
8 changed files with 221 additions and 0 deletions
|
@ -220,6 +220,8 @@ public:
|
||||||
virtual int GetClientHeight() = 0;
|
virtual int GetClientHeight() = 0;
|
||||||
virtual void BlurScene(float amount) {}
|
virtual void BlurScene(float amount) {}
|
||||||
|
|
||||||
|
virtual void InitLightmap() {}
|
||||||
|
|
||||||
// Interface to hardware rendering resources
|
// Interface to hardware rendering resources
|
||||||
virtual IVertexBuffer *CreateVertexBuffer() { return nullptr; }
|
virtual IVertexBuffer *CreateVertexBuffer() { return nullptr; }
|
||||||
virtual IIndexBuffer *CreateIndexBuffer() { return nullptr; }
|
virtual IIndexBuffer *CreateIndexBuffer() { return nullptr; }
|
||||||
|
|
|
@ -62,6 +62,7 @@ enum
|
||||||
ML_BEHAVIOR, // [RH] Hexen-style scripts. If present, THINGS
|
ML_BEHAVIOR, // [RH] Hexen-style scripts. If present, THINGS
|
||||||
// and LINEDEFS are also Hexen-style.
|
// and LINEDEFS are also Hexen-style.
|
||||||
ML_CONVERSATION, // Strife dialog (only for TEXTMAP format)
|
ML_CONVERSATION, // Strife dialog (only for TEXTMAP format)
|
||||||
|
ML_LIGHTMAP, // ZDRay generated lightmap
|
||||||
ML_MAX,
|
ML_MAX,
|
||||||
|
|
||||||
// [RH] These are compressed (and extended) nodes. They combine the data from
|
// [RH] These are compressed (and extended) nodes. They combine the data from
|
||||||
|
|
|
@ -451,6 +451,13 @@ public:
|
||||||
TArray<FSectorPortal> sectorPortals;
|
TArray<FSectorPortal> sectorPortals;
|
||||||
TArray<FLinePortal> linePortals;
|
TArray<FLinePortal> linePortals;
|
||||||
|
|
||||||
|
// Lightmaps
|
||||||
|
TArray<LightmapSurface> LMSurfaces;
|
||||||
|
TArray<float> LMTexCoords;
|
||||||
|
int LMTextureCount = 0;
|
||||||
|
int LMTextureSize = 0;
|
||||||
|
TArray<uint8_t> LMTextureData;
|
||||||
|
|
||||||
// Portal information.
|
// Portal information.
|
||||||
FDisplacementTable Displacements;
|
FDisplacementTable Displacements;
|
||||||
FPortalBlockmap PortalBlockmap;
|
FPortalBlockmap PortalBlockmap;
|
||||||
|
|
|
@ -58,6 +58,7 @@ struct sector_t;
|
||||||
class AActor;
|
class AActor;
|
||||||
struct FSection;
|
struct FSection;
|
||||||
struct FLevelLocals;
|
struct FLevelLocals;
|
||||||
|
struct LightmapSurface;
|
||||||
|
|
||||||
const uint16_t NO_INDEX = 0xffffu;
|
const uint16_t NO_INDEX = 0xffffu;
|
||||||
const uint32_t NO_SIDE = 0xffffffffu;
|
const uint32_t NO_SIDE = 0xffffffffu;
|
||||||
|
@ -707,6 +708,8 @@ struct sector_t
|
||||||
int vbocount[2]; // Total count of vertices belonging to this sector's planes. This is used when a sector height changes and also contains all attached planes.
|
int vbocount[2]; // Total count of vertices belonging to this sector's planes. This is used when a sector height changes and also contains all attached planes.
|
||||||
int ibocount; // number of indices per plane (identical for all planes.) If this is -1 the index buffer is not in use.
|
int ibocount; // number of indices per plane (identical for all planes.) If this is -1 the index buffer is not in use.
|
||||||
|
|
||||||
|
bool HasLightmaps = false; // Sector has lightmaps, each subsector vertex needs its own unique lightmap UV data
|
||||||
|
|
||||||
// Below are all properties which are not used by the renderer.
|
// Below are all properties which are not used by the renderer.
|
||||||
|
|
||||||
TObjPtr<AActor*> SoundTarget;
|
TObjPtr<AActor*> SoundTarget;
|
||||||
|
@ -1458,6 +1461,8 @@ struct line_t
|
||||||
int healthgroup; // [ZZ] this is the "destructible object" id
|
int healthgroup; // [ZZ] this is the "destructible object" id
|
||||||
int linenum;
|
int linenum;
|
||||||
|
|
||||||
|
LightmapSurface *lightmap[4];
|
||||||
|
|
||||||
DVector2 Delta() const
|
DVector2 Delta() const
|
||||||
{
|
{
|
||||||
return delta;
|
return delta;
|
||||||
|
@ -1615,6 +1620,8 @@ struct subsector_t
|
||||||
int Index() const { return subsectornum; }
|
int Index() const { return subsectornum; }
|
||||||
// 2: has one-sided walls
|
// 2: has one-sided walls
|
||||||
FPortalCoverage portalcoverage[2];
|
FPortalCoverage portalcoverage[2];
|
||||||
|
|
||||||
|
LightmapSurface *lightmap[2];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -1659,6 +1666,28 @@ struct FMiniBSP
|
||||||
TArray<vertex_t> Verts;
|
TArray<vertex_t> Verts;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Lightmap data
|
||||||
|
|
||||||
|
enum SurfaceType
|
||||||
|
{
|
||||||
|
ST_NULL,
|
||||||
|
ST_MIDDLEWALL,
|
||||||
|
ST_UPPERWALL,
|
||||||
|
ST_LOWERWALL,
|
||||||
|
ST_CEILING,
|
||||||
|
ST_FLOOR
|
||||||
|
};
|
||||||
|
|
||||||
|
struct LightmapSurface
|
||||||
|
{
|
||||||
|
SurfaceType Type;
|
||||||
|
subsector_t *Subsector;
|
||||||
|
line_t *Line;
|
||||||
|
sector_t *ControlSector;
|
||||||
|
uint32_t LightmapNum;
|
||||||
|
float *TexCoords;
|
||||||
|
};
|
||||||
|
|
||||||
//
|
//
|
||||||
// OTHER TYPES
|
// OTHER TYPES
|
||||||
//
|
//
|
||||||
|
|
|
@ -3206,6 +3206,12 @@ void MapLoader::LoadLevel(MapData *map, const char *lumpname, int position)
|
||||||
|
|
||||||
SpawnThings(position);
|
SpawnThings(position);
|
||||||
|
|
||||||
|
// Load and link lightmaps - must be done after P_Spawn3DFloors (and SpawnThings? Potentially for baking static model actors?)
|
||||||
|
if (!ForceNodeBuild)
|
||||||
|
{
|
||||||
|
LoadLightmap(map);
|
||||||
|
}
|
||||||
|
|
||||||
for (int i = 0; i < MAXPLAYERS; ++i)
|
for (int i = 0; i < MAXPLAYERS; ++i)
|
||||||
{
|
{
|
||||||
if (Level->PlayerInGame(i) && Level->Players[i]->mo != nullptr)
|
if (Level->PlayerInGame(i) && Level->Players[i]->mo != nullptr)
|
||||||
|
@ -3241,6 +3247,8 @@ void MapLoader::LoadLevel(MapData *map, const char *lumpname, int position)
|
||||||
Level->ClearDynamic3DFloorData(); // CreateVBO must be run on the plain 3D floor data.
|
Level->ClearDynamic3DFloorData(); // CreateVBO must be run on the plain 3D floor data.
|
||||||
CreateVBO(screen->mVertexData, Level->sectors);
|
CreateVBO(screen->mVertexData, Level->sectors);
|
||||||
|
|
||||||
|
screen->InitLightmap();
|
||||||
|
|
||||||
for (auto &sec : Level->sectors)
|
for (auto &sec : Level->sectors)
|
||||||
{
|
{
|
||||||
P_Recalculate3DFloors(&sec);
|
P_Recalculate3DFloors(&sec);
|
||||||
|
@ -3258,3 +3266,163 @@ void MapLoader::LoadLevel(MapData *map, const char *lumpname, int position)
|
||||||
Level->aabbTree = new DoomLevelAABBTree(Level);
|
Level->aabbTree = new DoomLevelAABBTree(Level);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
void MapLoader::SetSubsectorLightmap(const LightmapSurface &surface)
|
||||||
|
{
|
||||||
|
int index = surface.Type == ST_CEILING ? 1 : 0;
|
||||||
|
if (!surface.ControlSector)
|
||||||
|
{
|
||||||
|
surface.Subsector->lightmap[index][0] = surface;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const auto& ffloors = surface.Subsector->sector->e->XFloor.ffloors;
|
||||||
|
for (unsigned int i = 0; i < ffloors.Size(); i++)
|
||||||
|
{
|
||||||
|
if (ffloors[i]->model == surface.ControlSector)
|
||||||
|
{
|
||||||
|
surface.Subsector->lightmap[index][i + 1] = surface;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MapLoader::SetLineLightmap(const LightmapSurface &surface)
|
||||||
|
{
|
||||||
|
int index = 0;
|
||||||
|
switch (surface.Type)
|
||||||
|
{
|
||||||
|
default:
|
||||||
|
case ST_MIDDLEWALL: index = 1; break;
|
||||||
|
case ST_UPPERWALL: index = 0; break;
|
||||||
|
case ST_LOWERWALL: index = 3; break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!surface.ControlSector)
|
||||||
|
{
|
||||||
|
surface.Line->lightmap[index][0] = surface;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const auto& ffloors = surface.Line->frontsector->e->XFloor.ffloors;
|
||||||
|
for (unsigned int i = 0; i < ffloors.Size(); i++)
|
||||||
|
{
|
||||||
|
if (ffloors[i]->model == surface.ControlSector)
|
||||||
|
{
|
||||||
|
surface.Line->lightmap[index][i + 1] = surface;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MapLoader::LoadLightmap(MapData *map)
|
||||||
|
{
|
||||||
|
if (!map->Size(ML_LIGHTMAP))
|
||||||
|
return;
|
||||||
|
|
||||||
|
FileReader fr;
|
||||||
|
if (!fr.OpenDecompressor(map->Reader(ML_LIGHTMAP), -1, METHOD_ZLIB, false, [](const char* err) { I_Error("%s", err); }))
|
||||||
|
return;
|
||||||
|
|
||||||
|
int version = fr.ReadInt32();
|
||||||
|
if (version != 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
uint16_t textureSize = fr.ReadUInt16();
|
||||||
|
uint16_t numTextures = fr.ReadUInt16();
|
||||||
|
uint32_t numSurfaces = fr.ReadUInt32();
|
||||||
|
uint32_t numTexCoords = fr.ReadUInt32();
|
||||||
|
uint32_t numTexBytes = numSurfaces * numTextures * textureSize * 2;
|
||||||
|
|
||||||
|
if (numSurfaces == 0 || numTexCoords == 0 || numTexBytes == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Level->LMTexCoords.Resize(numTexCoords * 2);
|
||||||
|
|
||||||
|
// Allocate room for all surfaces
|
||||||
|
|
||||||
|
unsigned int allSurfaces = 0;
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < Level->lines.Size(); i++)
|
||||||
|
allSurfaces += 3 + Level->lines[i].frontsector->e->XFloor.ffloors.Size() * 3;
|
||||||
|
|
||||||
|
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[0], 0, sizeof(LightmapSurface) * allSurfaces);
|
||||||
|
|
||||||
|
// Link the surfaces to sectors, lines and their 3D floors
|
||||||
|
|
||||||
|
unsigned int offset = 0;
|
||||||
|
for (unsigned int i = 0; i < Level->lines.Size(); i++)
|
||||||
|
{
|
||||||
|
auto& line = Level->lines[i];
|
||||||
|
unsigned int count = 1 + line.frontsector->e->XFloor.ffloors.Size();
|
||||||
|
line.lightmap[0] = &Level->LMSurfaces[offset];
|
||||||
|
line.lightmap[1] = &Level->LMSurfaces[offset + count];
|
||||||
|
line.lightmap[2] = line.lightmap[1];
|
||||||
|
line.lightmap[3] = &Level->LMSurfaces[offset + count * 2];
|
||||||
|
offset += count * 3;
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load the surfaces we have lightmap data for
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < numSurfaces; i++)
|
||||||
|
{
|
||||||
|
LightmapSurface surface;
|
||||||
|
memset(&surface, 0, sizeof(LightmapSurface));
|
||||||
|
|
||||||
|
SurfaceType type = (SurfaceType)fr.ReadUInt32();
|
||||||
|
uint32_t typeIndex = fr.ReadUInt32();
|
||||||
|
uint32_t controlSector = fr.ReadUInt32();
|
||||||
|
uint32_t lightmapNum = fr.ReadUInt32();
|
||||||
|
uint32_t firstTexCoord = fr.ReadUInt32();
|
||||||
|
|
||||||
|
if (controlSector != 0xffffffff)
|
||||||
|
surface.ControlSector = &Level->sectors[controlSector];
|
||||||
|
|
||||||
|
surface.Type = type;
|
||||||
|
surface.LightmapNum = lightmapNum;
|
||||||
|
surface.TexCoords = &Level->LMTexCoords[firstTexCoord];
|
||||||
|
|
||||||
|
if (type == ST_CEILING || type == ST_FLOOR)
|
||||||
|
{
|
||||||
|
surface.Subsector = &Level->subsectors[typeIndex];
|
||||||
|
surface.Subsector->firstline->sidedef->sector->HasLightmaps = true;
|
||||||
|
SetSubsectorLightmap(surface);
|
||||||
|
}
|
||||||
|
else if (type != ST_NULL)
|
||||||
|
{
|
||||||
|
surface.Line = &Level->lines[typeIndex];
|
||||||
|
SetLineLightmap(surface);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load texture coordinates
|
||||||
|
|
||||||
|
fr.Read(&Level->LMTexCoords[0], numTexCoords * 2 * sizeof(float));
|
||||||
|
|
||||||
|
// Load lightmap textures
|
||||||
|
|
||||||
|
Level->LMTextureCount = numTextures;
|
||||||
|
Level->LMTextureSize = textureSize;
|
||||||
|
Level->LMTextureData.Resize(numTexBytes);
|
||||||
|
uint8_t* data = &Level->LMTextureData[0];
|
||||||
|
fr.Read(data, numTexBytes);
|
||||||
|
for (uint32_t i = 1; i < numTexBytes; i++)
|
||||||
|
data[i] += data[i - 1];
|
||||||
|
}
|
||||||
|
|
|
@ -304,6 +304,10 @@ public:
|
||||||
void SetSlopes();
|
void SetSlopes();
|
||||||
void CopySlopes();
|
void CopySlopes();
|
||||||
|
|
||||||
|
void SetSubsectorLightmap(const LightmapSurface &surface);
|
||||||
|
void SetLineLightmap(const LightmapSurface &surface);
|
||||||
|
void LoadLightmap(MapData *map);
|
||||||
|
|
||||||
void LoadLevel(MapData *map, const char *lumpname, int position);
|
void LoadLevel(MapData *map, const char *lumpname, int position);
|
||||||
|
|
||||||
MapLoader(FLevelLocals *lev)
|
MapLoader(FLevelLocals *lev)
|
||||||
|
|
|
@ -81,6 +81,7 @@ static int GetMapIndex(const char *mapname, int lastindex, const char *lumpname,
|
||||||
{"REJECT", false},
|
{"REJECT", false},
|
||||||
{"BLOCKMAP", false},
|
{"BLOCKMAP", false},
|
||||||
{"BEHAVIOR", false},
|
{"BEHAVIOR", false},
|
||||||
|
{"LIGHTMAP", false },
|
||||||
//{"SCRIPTS", false},
|
//{"SCRIPTS", false},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -235,6 +236,10 @@ MapData *P_OpenMapData(const char * mapname, bool justcheck)
|
||||||
index = ML_BEHAVIOR;
|
index = ML_BEHAVIOR;
|
||||||
map->HasBehavior = true;
|
map->HasBehavior = true;
|
||||||
}
|
}
|
||||||
|
else if (!stricmp(lumpname, "LIGHTMAP"))
|
||||||
|
{
|
||||||
|
index = ML_LIGHTMAP;
|
||||||
|
}
|
||||||
else if (!stricmp(lumpname, "ENDMAP"))
|
else if (!stricmp(lumpname, "ENDMAP"))
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
|
@ -312,6 +317,10 @@ MapData *P_OpenMapData(const char * mapname, bool justcheck)
|
||||||
index = ML_BEHAVIOR;
|
index = ML_BEHAVIOR;
|
||||||
map->HasBehavior = true;
|
map->HasBehavior = true;
|
||||||
}
|
}
|
||||||
|
else if (!strnicmp(lumpname, "LIGHTMAP", 8))
|
||||||
|
{
|
||||||
|
index = ML_LIGHTMAP;
|
||||||
|
}
|
||||||
else if (!strnicmp(lumpname, "ENDMAP",8))
|
else if (!strnicmp(lumpname, "ENDMAP",8))
|
||||||
{
|
{
|
||||||
return map;
|
return map;
|
||||||
|
|
|
@ -141,6 +141,7 @@ MapData * P_OpenMapData(const char * mapname, bool justcheck);
|
||||||
bool P_CheckMapData(const char * mapname);
|
bool P_CheckMapData(const char * mapname);
|
||||||
|
|
||||||
void P_SetupLevel (FLevelLocals *Level, int position, bool newGame);
|
void P_SetupLevel (FLevelLocals *Level, int position, bool newGame);
|
||||||
|
void P_LoadLightmap(MapData *map);
|
||||||
|
|
||||||
void P_FreeLevelData();
|
void P_FreeLevelData();
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue