Misc surface and lightmapper related cleanup and renaming
This commit is contained in:
parent
75e33c4923
commit
412be46e08
13 changed files with 200 additions and 185 deletions
|
|
@ -32,8 +32,8 @@ LevelMeshSurface* LevelMesh::Trace(const FVector3& start, FVector3 direction, fl
|
|||
}
|
||||
|
||||
hitSurface = hitmesh->GetSurface(hitmesh->Mesh.SurfaceIndexes[hit.triangle]);
|
||||
auto portal = hitSurface->portalIndex;
|
||||
|
||||
int portal = hitSurface->PortalIndex;
|
||||
if (!portal)
|
||||
{
|
||||
break;
|
||||
|
|
@ -100,7 +100,7 @@ void LevelSubmesh::GatherSurfacePixelStats(LevelMeshSurfaceStats& stats)
|
|||
for (int i = 0; i < count; ++i)
|
||||
{
|
||||
const auto* surface = GetSurface(i);
|
||||
auto area = surface->Area();
|
||||
auto area = surface->AtlasTile.Area();
|
||||
|
||||
stats.pixels.total += area;
|
||||
|
||||
|
|
@ -109,7 +109,7 @@ void LevelSubmesh::GatherSurfacePixelStats(LevelMeshSurfaceStats& stats)
|
|||
stats.surfaces.dirty++;
|
||||
stats.pixels.dirty += area;
|
||||
}
|
||||
if (surface->bSky)
|
||||
if (surface->IsSky)
|
||||
{
|
||||
stats.surfaces.sky++;
|
||||
stats.pixels.sky += area;
|
||||
|
|
@ -133,12 +133,12 @@ void LevelSubmesh::BuildTileSurfaceLists()
|
|||
|
||||
for (size_t j = 0; j < SmoothingGroups.Size(); j++)
|
||||
{
|
||||
if (surface->sectorGroup == SmoothingGroups[j].sectorGroup)
|
||||
if (surface->SectorGroup == SmoothingGroups[j].sectorGroup)
|
||||
{
|
||||
float direction = SmoothingGroups[j].plane.XYZ() | surface->plane.XYZ();
|
||||
float direction = SmoothingGroups[j].plane.XYZ() | surface->Plane.XYZ();
|
||||
if (direction >= 0.9999f && direction <= 1.001f)
|
||||
{
|
||||
auto point = (surface->plane.XYZ() * surface->plane.W);
|
||||
auto point = (surface->Plane.XYZ() * surface->Plane.W);
|
||||
auto planeDistance = (SmoothingGroups[j].plane.XYZ() | point) - SmoothingGroups[j].plane.W;
|
||||
|
||||
float dist = std::abs(planeDistance);
|
||||
|
|
@ -157,8 +157,8 @@ void LevelSubmesh::BuildTileSurfaceLists()
|
|||
smoothingGroupIndex = SmoothingGroups.Size();
|
||||
|
||||
LevelMeshSmoothingGroup group;
|
||||
group.plane = surface->plane;
|
||||
group.sectorGroup = surface->sectorGroup;
|
||||
group.plane = surface->Plane;
|
||||
group.sectorGroup = surface->SectorGroup;
|
||||
SmoothingGroups.Push(group);
|
||||
}
|
||||
|
||||
|
|
@ -169,23 +169,23 @@ void LevelSubmesh::BuildTileSurfaceLists()
|
|||
for (int i = 0, count = GetSurfaceCount(); i < count; i++)
|
||||
{
|
||||
auto targetSurface = GetSurface(i);
|
||||
targetSurface->tileSurfaces.Clear();
|
||||
targetSurface->TileSurfaces.Clear();
|
||||
for (LevelMeshSurface* surface : SmoothingGroups[SmoothingGroupIndexes[i]].surfaces)
|
||||
{
|
||||
FVector2 minUV = ToUV(surface->bounds.min, targetSurface);
|
||||
FVector2 maxUV = ToUV(surface->bounds.max, targetSurface);
|
||||
FVector2 minUV = ToUV(surface->Bounds.min, targetSurface);
|
||||
FVector2 maxUV = ToUV(surface->Bounds.max, targetSurface);
|
||||
if (surface != targetSurface && (maxUV.X < 0.0f || maxUV.Y < 0.0f || minUV.X > 1.0f || minUV.Y > 1.0f))
|
||||
continue; // Bounding box not visible
|
||||
|
||||
targetSurface->tileSurfaces.Push(surface);
|
||||
targetSurface->TileSurfaces.Push(surface);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FVector2 LevelSubmesh::ToUV(const FVector3& vert, const LevelMeshSurface* targetSurface)
|
||||
{
|
||||
FVector3 localPos = vert - targetSurface->translateWorldToLocal;
|
||||
float u = (1.0f + (localPos | targetSurface->projLocalToU)) / (targetSurface->AtlasTile.Width + 2);
|
||||
float v = (1.0f + (localPos | targetSurface->projLocalToV)) / (targetSurface->AtlasTile.Height + 2);
|
||||
FVector3 localPos = vert - targetSurface->TileTransform.TranslateWorldToLocal;
|
||||
float u = (1.0f + (localPos | targetSurface->TileTransform.ProjLocalToU)) / (targetSurface->AtlasTile.Width + 2);
|
||||
float v = (1.0f + (localPos | targetSurface->TileTransform.ProjLocalToV)) / (targetSurface->AtlasTile.Height + 2);
|
||||
return FVector2(u, v);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,12 +38,15 @@ struct LevelMeshSurface
|
|||
{
|
||||
LevelSubmesh* Submesh = nullptr;
|
||||
|
||||
int numVerts = 0;
|
||||
unsigned int startVertIndex = 0;
|
||||
unsigned int startElementIndex = 0;
|
||||
unsigned int numElements = 0;
|
||||
FVector4 plane = FVector4(0.0f, 0.0f, 1.0f, 0.0f);
|
||||
bool bSky = false;
|
||||
struct
|
||||
{
|
||||
unsigned int StartVertIndex = 0;
|
||||
int NumVerts = 0;
|
||||
unsigned int StartElementIndex = 0;
|
||||
unsigned int NumElements = 0;
|
||||
} MeshLocation;
|
||||
|
||||
FVector4 Plane = FVector4(0.0f, 0.0f, 1.0f, 0.0f);
|
||||
|
||||
// Surface location in lightmap texture
|
||||
struct
|
||||
|
|
@ -53,30 +56,33 @@ struct LevelMeshSurface
|
|||
int Width = 0;
|
||||
int Height = 0;
|
||||
int ArrayIndex = 0;
|
||||
uint32_t Area() const { return Width * Height; }
|
||||
} AtlasTile;
|
||||
|
||||
// True if the surface needs to be rendered into the lightmap texture before it can be used
|
||||
bool NeedsUpdate = true;
|
||||
bool AlwaysUpdate = false;
|
||||
|
||||
FGameTexture* texture = nullptr;
|
||||
float alpha = 1.0;
|
||||
FGameTexture* Texture = nullptr;
|
||||
float Alpha = 1.0;
|
||||
|
||||
int portalIndex = 0;
|
||||
int sectorGroup = 0;
|
||||
bool IsSky = false;
|
||||
int PortalIndex = 0;
|
||||
int SectorGroup = 0;
|
||||
|
||||
BBox bounds;
|
||||
uint16_t sampleDimension = 0;
|
||||
BBox Bounds;
|
||||
uint16_t SampleDimension = 0;
|
||||
|
||||
// Calculate world coordinates to UV coordinates
|
||||
FVector3 translateWorldToLocal = { 0.f, 0.f, 0.f };
|
||||
FVector3 projLocalToU = { 0.f, 0.f, 0.f };
|
||||
FVector3 projLocalToV = { 0.f, 0.f, 0.f };
|
||||
struct
|
||||
{
|
||||
FVector3 TranslateWorldToLocal = { 0.0f, 0.0f, 0.0f };
|
||||
FVector3 ProjLocalToU = { 0.0f, 0.0f, 0.0f };
|
||||
FVector3 ProjLocalToV = { 0.0f, 0.0f, 0.0f };
|
||||
} TileTransform;
|
||||
|
||||
// Surfaces that are visible within the lightmap tile
|
||||
TArray<LevelMeshSurface*> tileSurfaces;
|
||||
|
||||
uint32_t Area() const { return AtlasTile.Width * AtlasTile.Height; }
|
||||
TArray<LevelMeshSurface*> TileSurfaces;
|
||||
|
||||
// Light list location in the lightmapper GPU buffers
|
||||
struct
|
||||
|
|
|
|||
|
|
@ -638,14 +638,14 @@ void VkLevelMeshUploader::UploadSurfaces()
|
|||
LevelMeshSurface* surface = submesh->GetSurface(j);
|
||||
|
||||
SurfaceInfo info;
|
||||
info.Normal = FVector3(surface->plane.X, surface->plane.Z, surface->plane.Y);
|
||||
info.PortalIndex = surface->portalIndex;
|
||||
info.SamplingDistance = (float)surface->sampleDimension;
|
||||
info.Sky = surface->bSky;
|
||||
info.Alpha = surface->alpha;
|
||||
if (surface->texture)
|
||||
info.Normal = FVector3(surface->Plane.X, surface->Plane.Z, surface->Plane.Y);
|
||||
info.PortalIndex = surface->PortalIndex;
|
||||
info.SamplingDistance = (float)surface->SampleDimension;
|
||||
info.Sky = surface->IsSky;
|
||||
info.Alpha = surface->Alpha;
|
||||
if (surface->Texture)
|
||||
{
|
||||
auto mat = FMaterial::ValidateTexture(surface->texture, 0);
|
||||
auto mat = FMaterial::ValidateTexture(surface->Texture, 0);
|
||||
info.TextureIndex = Mesh->fb->GetBindlessTextureIndex(mat, CLAMP_NONE, 0);
|
||||
}
|
||||
else
|
||||
|
|
|
|||
|
|
@ -200,14 +200,14 @@ void VkLightmapper::Render()
|
|||
pc.TextureSize = (float)bakeImageSize;
|
||||
pc.TileWidth = (float)targetSurface->AtlasTile.Width;
|
||||
pc.TileHeight = (float)targetSurface->AtlasTile.Height;
|
||||
pc.WorldToLocal = SwapYZ(targetSurface->translateWorldToLocal);
|
||||
pc.ProjLocalToU = SwapYZ(targetSurface->projLocalToU);
|
||||
pc.ProjLocalToV = SwapYZ(targetSurface->projLocalToV);
|
||||
pc.WorldToLocal = SwapYZ(targetSurface->TileTransform.TranslateWorldToLocal);
|
||||
pc.ProjLocalToU = SwapYZ(targetSurface->TileTransform.ProjLocalToU);
|
||||
pc.ProjLocalToV = SwapYZ(targetSurface->TileTransform.ProjLocalToV);
|
||||
|
||||
bool buffersFull = false;
|
||||
|
||||
// Paint all surfaces visible in the tile
|
||||
for (LevelMeshSurface* surface : targetSurface->tileSurfaces)
|
||||
for (LevelMeshSurface* surface : targetSurface->TileSurfaces)
|
||||
{
|
||||
if (surface->LightList.ResetCounter != lights.ResetCounter)
|
||||
{
|
||||
|
|
@ -247,9 +247,9 @@ void VkLightmapper::Render()
|
|||
|
||||
#ifdef USE_DRAWINDIRECT
|
||||
VkDrawIndexedIndirectCommand cmd;
|
||||
cmd.indexCount = surface->numElements;
|
||||
cmd.indexCount = surface->MeshLocation.NumElements;
|
||||
cmd.instanceCount = 1;
|
||||
cmd.firstIndex = firstIndexOffset + surface->startElementIndex;
|
||||
cmd.firstIndex = firstIndexOffset + surface->MeshLocation.StartElementIndex;
|
||||
cmd.vertexOffset = 0;
|
||||
cmd.firstInstance = drawindexed.Pos;
|
||||
drawindexed.Constants[drawindexed.Pos] = pc;
|
||||
|
|
@ -419,7 +419,7 @@ void VkLightmapper::CopyResult()
|
|||
}
|
||||
copylists[pageIndex].Push(&selected);
|
||||
|
||||
pixels += selected.Surface->Area();
|
||||
pixels += selected.Surface->AtlasTile.Area();
|
||||
lastSurfaceCount++;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3321,7 +3321,7 @@ bool MapLoader::LoadLightmap(MapData* map)
|
|||
dstX, dstY,
|
||||
dstX + realSurface.AtlasTile.Width, dstY + realSurface.AtlasTile.Height,
|
||||
dstPage,
|
||||
realSurface.Area() * 3);
|
||||
realSurface.AtlasTile.Area() * 3);
|
||||
}
|
||||
|
||||
// copy pixels
|
||||
|
|
@ -3351,7 +3351,7 @@ bool MapLoader::LoadLightmap(MapData* map)
|
|||
{
|
||||
auto& realSurface = *surface.targetSurface;
|
||||
|
||||
auto* vertices = &submesh->Mesh.Vertices[realSurface.startVertIndex];
|
||||
auto* vertices = &submesh->Mesh.Vertices[realSurface.MeshLocation.StartVertIndex];
|
||||
auto* newUVs = &zdrayUvs[surface.uvOffset];
|
||||
|
||||
for (uint32_t i = 0; i < surface.uvCount; ++i)
|
||||
|
|
|
|||
|
|
@ -80,17 +80,17 @@ void PrintSurfaceInfo(const DoomLevelMeshSurface* surface)
|
|||
{
|
||||
if (!RequireLevelMesh()) return;
|
||||
|
||||
auto gameTexture = surface->texture;
|
||||
auto gameTexture = surface->Texture;
|
||||
|
||||
Printf("Surface %d (%p)\n Type: %d, TypeIndex: %d, ControlSector: %d\n", surface->Submesh->GetSurfaceIndex(surface), surface, surface->Type, surface->TypeIndex, surface->ControlSector ? surface->ControlSector->Index() : -1);
|
||||
Printf(" Atlas page: %d, x:%d, y:%d\n", surface->AtlasTile.ArrayIndex, surface->AtlasTile.X, surface->AtlasTile.Y);
|
||||
Printf(" Pixels: %dx%d (area: %d)\n", surface->AtlasTile.Width, surface->AtlasTile.Height, surface->Area());
|
||||
Printf(" Sample dimension: %d\n", surface->sampleDimension);
|
||||
Printf(" Pixels: %dx%d (area: %d)\n", surface->AtlasTile.Width, surface->AtlasTile.Height, surface->AtlasTile.Area());
|
||||
Printf(" Sample dimension: %d\n", surface->SampleDimension);
|
||||
Printf(" Needs update?: %d\n", surface->NeedsUpdate);
|
||||
Printf(" Always update?: %d\n", surface->AlwaysUpdate);
|
||||
Printf(" Sector group: %d\n", surface->sectorGroup);
|
||||
Printf(" Sector group: %d\n", surface->SectorGroup);
|
||||
Printf(" Texture: '%s'\n", gameTexture ? gameTexture->GetName().GetChars() : "<nullptr>");
|
||||
Printf(" Alpha: %f\n", surface->alpha);
|
||||
Printf(" Alpha: %f\n", surface->Alpha);
|
||||
}
|
||||
|
||||
FVector3 RayDir(FAngle angle, FAngle pitch)
|
||||
|
|
@ -144,23 +144,20 @@ DoomLevelMesh::DoomLevelMesh(FLevelLocals& doomMap)
|
|||
BuildSectorGroups(doomMap);
|
||||
CreatePortals(doomMap);
|
||||
|
||||
StaticMesh = std::make_unique<DoomLevelSubmesh>(this);
|
||||
DynamicMesh = std::make_unique<DoomLevelSubmesh>(this);
|
||||
|
||||
static_cast<DoomLevelSubmesh*>(StaticMesh.get())->CreateStatic(doomMap);
|
||||
static_cast<DoomLevelSubmesh*>(DynamicMesh.get())->CreateDynamic(doomMap);
|
||||
StaticMesh = std::make_unique<DoomLevelSubmesh>(this, doomMap, true);
|
||||
DynamicMesh = std::make_unique<DoomLevelSubmesh>(this, doomMap, false);
|
||||
}
|
||||
|
||||
void DoomLevelMesh::BeginFrame(FLevelLocals& doomMap)
|
||||
{
|
||||
static_cast<DoomLevelSubmesh*>(DynamicMesh.get())->UpdateDynamic(doomMap, static_cast<DoomLevelSubmesh*>(StaticMesh.get())->LMTextureCount);
|
||||
static_cast<DoomLevelSubmesh*>(DynamicMesh.get())->Update(doomMap, static_cast<DoomLevelSubmesh*>(StaticMesh.get())->LMTextureCount);
|
||||
}
|
||||
|
||||
bool DoomLevelMesh::TraceSky(const FVector3& start, FVector3 direction, float dist)
|
||||
{
|
||||
FVector3 end = start + direction * dist;
|
||||
auto surface = Trace(start, direction, dist);
|
||||
return surface && surface->bSky;
|
||||
return surface && surface->IsSky;
|
||||
}
|
||||
|
||||
void DoomLevelMesh::PackLightmapAtlas()
|
||||
|
|
@ -170,31 +167,7 @@ void DoomLevelMesh::PackLightmapAtlas()
|
|||
|
||||
int DoomLevelMesh::AddSurfaceLights(const LevelMeshSurface* surface, LevelMeshLight* list, int listMaxSize)
|
||||
{
|
||||
const DoomLevelMeshSurface* doomsurf = static_cast<const DoomLevelMeshSurface*>(surface);
|
||||
|
||||
FLightNode* node = nullptr;
|
||||
if (doomsurf->Type == ST_FLOOR || doomsurf->Type == ST_CEILING)
|
||||
{
|
||||
node = doomsurf->Subsector->section->lighthead;
|
||||
}
|
||||
else if (doomsurf->Type == ST_MIDDLESIDE || doomsurf->Type == ST_UPPERSIDE || doomsurf->Type == ST_LOWERSIDE)
|
||||
{
|
||||
bool isPolyLine = !!(doomsurf->Side->Flags & WALLF_POLYOBJ);
|
||||
if (isPolyLine)
|
||||
{
|
||||
subsector_t* subsector = level.PointInRenderSubsector((doomsurf->Side->V1()->fPos() + doomsurf->Side->V2()->fPos()) * 0.5);
|
||||
node = subsector->section->lighthead;
|
||||
}
|
||||
else if (!doomsurf->ControlSector)
|
||||
{
|
||||
node = doomsurf->Side->lighthead;
|
||||
}
|
||||
else // 3d floor needs light from the sidedef on the other side
|
||||
{
|
||||
int otherside = doomsurf->Side->linedef->sidedef[0] == doomsurf->Side ? 1 : 0;
|
||||
node = doomsurf->Side->linedef->sidedef[otherside]->lighthead;
|
||||
}
|
||||
}
|
||||
FLightNode* node = GetSurfaceLightNode(static_cast<const DoomLevelMeshSurface*>(surface));
|
||||
if (!node)
|
||||
return 0;
|
||||
|
||||
|
|
@ -247,6 +220,34 @@ int DoomLevelMesh::AddSurfaceLights(const LevelMeshSurface* surface, LevelMeshLi
|
|||
return listpos;
|
||||
}
|
||||
|
||||
FLightNode* DoomLevelMesh::GetSurfaceLightNode(const DoomLevelMeshSurface* doomsurf)
|
||||
{
|
||||
FLightNode* node = nullptr;
|
||||
if (doomsurf->Type == ST_FLOOR || doomsurf->Type == ST_CEILING)
|
||||
{
|
||||
node = doomsurf->Subsector->section->lighthead;
|
||||
}
|
||||
else if (doomsurf->Type == ST_MIDDLESIDE || doomsurf->Type == ST_UPPERSIDE || doomsurf->Type == ST_LOWERSIDE)
|
||||
{
|
||||
bool isPolyLine = !!(doomsurf->Side->Flags & WALLF_POLYOBJ);
|
||||
if (isPolyLine)
|
||||
{
|
||||
subsector_t* subsector = level.PointInRenderSubsector((doomsurf->Side->V1()->fPos() + doomsurf->Side->V2()->fPos()) * 0.5);
|
||||
node = subsector->section->lighthead;
|
||||
}
|
||||
else if (!doomsurf->ControlSector)
|
||||
{
|
||||
node = doomsurf->Side->lighthead;
|
||||
}
|
||||
else // 3d floor needs light from the sidedef on the other side
|
||||
{
|
||||
int otherside = doomsurf->Side->linedef->sidedef[0] == doomsurf->Side ? 1 : 0;
|
||||
node = doomsurf->Side->linedef->sidedef[otherside]->lighthead;
|
||||
}
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
void DoomLevelMesh::DumpMesh(const FString& objFilename, const FString& mtlFilename) const
|
||||
{
|
||||
DoomLevelSubmesh* submesh = static_cast<DoomLevelSubmesh*>(StaticMesh.get());
|
||||
|
|
@ -315,7 +316,7 @@ void DoomLevelMesh::DumpMesh(const FString& objFilename, const FString& mtlFilen
|
|||
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, "o Surface[%d] %s %d%s\n", index, name(surface.Type), surface.TypeIndex, surface.IsSky ? " sky" : "");
|
||||
fprintf(f, "usemtl lightmap%d\n", surface.AtlasTile.ArrayIndex);
|
||||
|
||||
if (surface.AtlasTile.ArrayIndex > highestUsedAtlasPage)
|
||||
|
|
|
|||
|
|
@ -22,4 +22,7 @@ public:
|
|||
TArray<int> sectorGroup; // index is sector, value is sectorGroup
|
||||
TArray<int> sectorPortals[2]; // index is sector+plane, value is index into the portal list
|
||||
TArray<int> linePortals; // index is linedef, value is index into the portal list
|
||||
|
||||
private:
|
||||
FLightNode* GetSurfaceLightNode(const DoomLevelMeshSurface* doomsurf);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -21,41 +21,40 @@ void GetTexCoordInfo(FGameTexture* tex, FTexCoordInfo* tci, side_t* side, int te
|
|||
EXTERN_CVAR(Bool, gl_texture)
|
||||
EXTERN_CVAR(Float, lm_scale);
|
||||
|
||||
void DoomLevelSubmesh::CreateStatic(FLevelLocals& doomMap)
|
||||
{
|
||||
LightmapSampleDistance = doomMap.LightmapSampleDistance;
|
||||
|
||||
Reset();
|
||||
|
||||
CreateStaticSurfaces(doomMap);
|
||||
LinkSurfaces(doomMap);
|
||||
|
||||
CreateIndexes();
|
||||
SetupLightmapUvs(doomMap);
|
||||
BuildTileSurfaceLists();
|
||||
UpdateCollision();
|
||||
}
|
||||
|
||||
void DoomLevelSubmesh::CreateDynamic(FLevelLocals& doomMap)
|
||||
DoomLevelSubmesh::DoomLevelSubmesh(DoomLevelMesh* mesh, FLevelLocals& doomMap, bool staticMesh) : LevelMesh(mesh), StaticMesh(staticMesh)
|
||||
{
|
||||
LightmapSampleDistance = doomMap.LightmapSampleDistance;
|
||||
Reset();
|
||||
|
||||
if (StaticMesh)
|
||||
{
|
||||
CreateStaticSurfaces(doomMap);
|
||||
LinkSurfaces(doomMap);
|
||||
|
||||
CreateIndexes();
|
||||
SetupLightmapUvs(doomMap);
|
||||
BuildTileSurfaceLists();
|
||||
UpdateCollision();
|
||||
}
|
||||
}
|
||||
|
||||
void DoomLevelSubmesh::UpdateDynamic(FLevelLocals& doomMap, int lightmapStartIndex)
|
||||
void DoomLevelSubmesh::Update(FLevelLocals& doomMap, int lightmapStartIndex)
|
||||
{
|
||||
Reset();
|
||||
if (!StaticMesh)
|
||||
{
|
||||
Reset();
|
||||
|
||||
CreateDynamicSurfaces(doomMap);
|
||||
LinkSurfaces(doomMap);
|
||||
CreateDynamicSurfaces(doomMap);
|
||||
LinkSurfaces(doomMap);
|
||||
|
||||
CreateIndexes();
|
||||
SetupLightmapUvs(doomMap);
|
||||
BuildTileSurfaceLists();
|
||||
UpdateCollision();
|
||||
CreateIndexes();
|
||||
SetupLightmapUvs(doomMap);
|
||||
BuildTileSurfaceLists();
|
||||
UpdateCollision();
|
||||
|
||||
if (doomMap.lightmaps)
|
||||
PackLightmapAtlas(lightmapStartIndex);
|
||||
if (doomMap.lightmaps)
|
||||
PackLightmapAtlas(lightmapStartIndex);
|
||||
}
|
||||
}
|
||||
|
||||
void DoomLevelSubmesh::Reset()
|
||||
|
|
@ -169,14 +168,14 @@ void DoomLevelSubmesh::CreateStaticSurfaces(FLevelLocals& doomMap)
|
|||
surf.TypeIndex = side->Index();
|
||||
surf.Side = side;
|
||||
surf.AlwaysUpdate = !!(front->Flags & SECF_LM_DYNAMIC);
|
||||
surf.sectorGroup = LevelMesh->sectorGroup[front->Index()];
|
||||
surf.alpha = float(side->linedef->alpha);
|
||||
surf.startVertIndex = startVertIndex;
|
||||
surf.numVerts = Mesh.Vertices.Size() - startVertIndex;
|
||||
surf.plane = ToPlane(Mesh.Vertices[startVertIndex].fPos(), Mesh.Vertices[startVertIndex + 1].fPos(), Mesh.Vertices[startVertIndex + 2].fPos(), Mesh.Vertices[startVertIndex + 3].fPos());
|
||||
surf.texture = wallpart.texture;
|
||||
surf.SectorGroup = LevelMesh->sectorGroup[front->Index()];
|
||||
surf.Alpha = float(side->linedef->alpha);
|
||||
surf.MeshLocation.StartVertIndex = startVertIndex;
|
||||
surf.MeshLocation.NumVerts = Mesh.Vertices.Size() - startVertIndex;
|
||||
surf.Plane = ToPlane(Mesh.Vertices[startVertIndex + 3].fPos(), Mesh.Vertices[startVertIndex + 2].fPos(), Mesh.Vertices[startVertIndex + 1].fPos(), Mesh.Vertices[startVertIndex].fPos());
|
||||
surf.Texture = wallpart.texture;
|
||||
surf.PipelineID = pipelineID;
|
||||
surf.portalIndex = (surf.Type == ST_MIDDLESIDE) ? LevelMesh->linePortals[side->linedef->Index()] : 0;
|
||||
surf.PortalIndex = (surf.Type == ST_MIDDLESIDE) ? LevelMesh->linePortals[side->linedef->Index()] : 0;
|
||||
Surfaces.Push(surf);
|
||||
}
|
||||
|
||||
|
|
@ -242,19 +241,21 @@ void DoomLevelSubmesh::CreateStaticSurfaces(FLevelLocals& doomMap)
|
|||
if (!foundDraw)
|
||||
continue;
|
||||
|
||||
auto plane = sector->GetSecPlane(flatpart.ceiling);
|
||||
|
||||
DoomLevelMeshSurface surf;
|
||||
surf.Submesh = this;
|
||||
surf.Type = flatpart.ceiling ? ST_CEILING : ST_FLOOR;
|
||||
surf.ControlSector = flatpart.controlsector ? flatpart.controlsector->model : nullptr;
|
||||
surf.AlwaysUpdate = !!(sector->Flags & SECF_LM_DYNAMIC);
|
||||
surf.sectorGroup = LevelMesh->sectorGroup[sector->Index()];
|
||||
surf.alpha = flatpart.alpha;
|
||||
surf.texture = flatpart.texture;
|
||||
surf.SectorGroup = LevelMesh->sectorGroup[sector->Index()];
|
||||
surf.Alpha = flatpart.alpha;
|
||||
surf.Texture = flatpart.texture;
|
||||
surf.PipelineID = pipelineID;
|
||||
surf.plane = FVector4((float)plane.Normal().X, (float)plane.Normal().Y, (float)plane.Normal().Z, -(float)plane.D);
|
||||
surf.portalIndex = LevelMesh->sectorPortals[flatpart.ceiling][i];
|
||||
surf.PortalIndex = LevelMesh->sectorPortals[flatpart.ceiling][i];
|
||||
|
||||
auto plane = sector->GetSecPlane(flatpart.ceiling);
|
||||
surf.Plane = FVector4((float)plane.Normal().X, (float)plane.Normal().Y, (float)plane.Normal().Z, -(float)plane.D);
|
||||
//if (flatpart.ceiling)
|
||||
// surf.Plane = -surf.Plane;
|
||||
|
||||
for (subsector_t* sub : section.subsectors)
|
||||
{
|
||||
|
|
@ -280,8 +281,11 @@ void DoomLevelSubmesh::CreateStaticSurfaces(FLevelLocals& doomMap)
|
|||
|
||||
surf.TypeIndex = sub->Index();
|
||||
surf.Subsector = sub;
|
||||
surf.startVertIndex = startVertIndex;
|
||||
surf.numVerts = sub->numlines;
|
||||
surf.MeshLocation.StartVertIndex = startVertIndex;
|
||||
surf.MeshLocation.NumVerts = sub->numlines;
|
||||
|
||||
//surf.Plane = ToPlane(Mesh.Vertices[startVertIndex + 2].fPos(), Mesh.Vertices[startVertIndex + 1].fPos(), Mesh.Vertices[startVertIndex].fPos());
|
||||
|
||||
Surfaces.Push(surf);
|
||||
}
|
||||
}
|
||||
|
|
@ -321,7 +325,7 @@ void DoomLevelSubmesh::CreateIndexes()
|
|||
for (size_t i = 0; i < Surfaces.Size(); i++)
|
||||
{
|
||||
DoomLevelMeshSurface* s = &Surfaces[i];
|
||||
pipelineSurfaces[(int64_t(s->PipelineID) << 32) | int64_t(s->bSky)].Push(i);
|
||||
pipelineSurfaces[(int64_t(s->PipelineID) << 32) | int64_t(s->IsSky)].Push(i);
|
||||
}
|
||||
|
||||
for (const auto& it : pipelineSurfaces)
|
||||
|
|
@ -332,13 +336,12 @@ void DoomLevelSubmesh::CreateIndexes()
|
|||
for (unsigned int i : it.second)
|
||||
{
|
||||
DoomLevelMeshSurface& s = Surfaces[i];
|
||||
int numVerts = s.numVerts;
|
||||
unsigned int pos = s.startVertIndex;
|
||||
int numVerts = s.MeshLocation.NumVerts;
|
||||
unsigned int pos = s.MeshLocation.StartVertIndex;
|
||||
FFlatVertex* verts = &Mesh.Vertices[pos];
|
||||
|
||||
s.Vertices = verts;
|
||||
s.startElementIndex = Mesh.Indexes.Size();
|
||||
s.numElements = 0;
|
||||
s.MeshLocation.StartElementIndex = Mesh.Indexes.Size();
|
||||
s.MeshLocation.NumElements = 0;
|
||||
|
||||
if (s.Type == ST_CEILING)
|
||||
{
|
||||
|
|
@ -350,7 +353,7 @@ void DoomLevelSubmesh::CreateIndexes()
|
|||
Mesh.Indexes.Push(pos + j - 1);
|
||||
Mesh.Indexes.Push(pos + j);
|
||||
Mesh.SurfaceIndexes.Push((int)i);
|
||||
s.numElements += 3;
|
||||
s.MeshLocation.NumElements += 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -364,7 +367,7 @@ void DoomLevelSubmesh::CreateIndexes()
|
|||
Mesh.Indexes.Push(pos + j - 1);
|
||||
Mesh.Indexes.Push(pos);
|
||||
Mesh.SurfaceIndexes.Push((int)i);
|
||||
s.numElements += 3;
|
||||
s.MeshLocation.NumElements += 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -376,7 +379,7 @@ void DoomLevelSubmesh::CreateIndexes()
|
|||
Mesh.Indexes.Push(pos + 1);
|
||||
Mesh.Indexes.Push(pos + 2);
|
||||
Mesh.SurfaceIndexes.Push((int)i);
|
||||
s.numElements += 3;
|
||||
s.MeshLocation.NumElements += 3;
|
||||
}
|
||||
if (!IsDegenerate(verts[0].fPos(), verts[2].fPos(), verts[3].fPos()))
|
||||
{
|
||||
|
|
@ -384,7 +387,7 @@ void DoomLevelSubmesh::CreateIndexes()
|
|||
Mesh.Indexes.Push(pos + 2);
|
||||
Mesh.Indexes.Push(pos + 3);
|
||||
Mesh.SurfaceIndexes.Push((int)i);
|
||||
s.numElements += 3;
|
||||
s.MeshLocation.NumElements += 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -489,7 +492,7 @@ void DoomLevelSubmesh::SetupLightmapUvs(FLevelLocals& doomMap)
|
|||
|
||||
for (auto& surface : Surfaces)
|
||||
{
|
||||
BuildSurfaceParams(LMTextureSize, LMTextureSize, surface);
|
||||
SetupTileTransform(LMTextureSize, LMTextureSize, surface);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -520,9 +523,9 @@ void DoomLevelSubmesh::PackLightmapAtlas(int lightmapStartIndex)
|
|||
surf->AtlasTile.ArrayIndex = lightmapStartIndex + (int)result.pageIndex;
|
||||
|
||||
// calculate final texture coordinates
|
||||
for (int i = 0; i < (int)surf->numVerts; i++)
|
||||
for (int i = 0; i < (int)surf->MeshLocation.NumVerts; i++)
|
||||
{
|
||||
auto& vertex = Mesh.Vertices[surf->startVertIndex + i];
|
||||
auto& vertex = Mesh.Vertices[surf->MeshLocation.StartVertIndex + i];
|
||||
vertex.lu = (vertex.lu + x) / (float)LMTextureSize;
|
||||
vertex.lv = (vertex.lv + y) / (float)LMTextureSize;
|
||||
vertex.lindex = (float)surf->AtlasTile.ArrayIndex;
|
||||
|
|
@ -539,7 +542,7 @@ BBox DoomLevelSubmesh::GetBoundsFromSurface(const LevelMeshSurface& surface) con
|
|||
FVector3 low(M_INFINITY, M_INFINITY, M_INFINITY);
|
||||
FVector3 hi(-M_INFINITY, -M_INFINITY, -M_INFINITY);
|
||||
|
||||
for (int i = int(surface.startVertIndex); i < int(surface.startVertIndex) + surface.numVerts; i++)
|
||||
for (int i = int(surface.MeshLocation.StartVertIndex); i < int(surface.MeshLocation.StartVertIndex) + surface.MeshLocation.NumVerts; i++)
|
||||
{
|
||||
for (int j = 0; j < 3; j++)
|
||||
{
|
||||
|
|
@ -580,41 +583,41 @@ DoomLevelSubmesh::PlaneAxis DoomLevelSubmesh::BestAxis(const FVector4& p)
|
|||
return AXIS_XY;
|
||||
}
|
||||
|
||||
void DoomLevelSubmesh::BuildSurfaceParams(int lightMapTextureWidth, int lightMapTextureHeight, LevelMeshSurface& surface)
|
||||
void DoomLevelSubmesh::SetupTileTransform(int lightMapTextureWidth, int lightMapTextureHeight, LevelMeshSurface& surface)
|
||||
{
|
||||
BBox bounds = GetBoundsFromSurface(surface);
|
||||
surface.bounds = bounds;
|
||||
surface.Bounds = bounds;
|
||||
|
||||
if (surface.sampleDimension <= 0)
|
||||
if (surface.SampleDimension <= 0)
|
||||
{
|
||||
surface.sampleDimension = LightmapSampleDistance;
|
||||
surface.SampleDimension = LightmapSampleDistance;
|
||||
}
|
||||
|
||||
surface.sampleDimension = uint16_t(max(int(roundf(float(surface.sampleDimension) / max(1.0f / 4, float(lm_scale)))), 1));
|
||||
surface.SampleDimension = uint16_t(max(int(roundf(float(surface.SampleDimension) / max(1.0f / 4, float(lm_scale)))), 1));
|
||||
|
||||
{
|
||||
// Round to nearest power of two
|
||||
uint32_t n = uint16_t(surface.sampleDimension);
|
||||
uint32_t n = uint16_t(surface.SampleDimension);
|
||||
n |= n >> 1;
|
||||
n |= n >> 2;
|
||||
n |= n >> 4;
|
||||
n |= n >> 8;
|
||||
n = (n + 1) >> 1;
|
||||
surface.sampleDimension = uint16_t(n) ? uint16_t(n) : uint16_t(0xFFFF);
|
||||
surface.SampleDimension = uint16_t(n) ? uint16_t(n) : uint16_t(0xFFFF);
|
||||
}
|
||||
|
||||
// round off dimensions
|
||||
FVector3 roundedSize;
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
bounds.min[i] = surface.sampleDimension * (floor(bounds.min[i] / surface.sampleDimension) - 1);
|
||||
bounds.max[i] = surface.sampleDimension * (ceil(bounds.max[i] / surface.sampleDimension) + 1);
|
||||
roundedSize[i] = (bounds.max[i] - bounds.min[i]) / surface.sampleDimension;
|
||||
bounds.min[i] = surface.SampleDimension * (floor(bounds.min[i] / surface.SampleDimension) - 1);
|
||||
bounds.max[i] = surface.SampleDimension * (ceil(bounds.max[i] / surface.SampleDimension) + 1);
|
||||
roundedSize[i] = (bounds.max[i] - bounds.min[i]) / surface.SampleDimension;
|
||||
}
|
||||
|
||||
FVector3 tCoords[2] = { FVector3(0.0f, 0.0f, 0.0f), FVector3(0.0f, 0.0f, 0.0f) };
|
||||
|
||||
PlaneAxis axis = BestAxis(surface.plane);
|
||||
PlaneAxis axis = BestAxis(surface.Plane);
|
||||
|
||||
int width;
|
||||
int height;
|
||||
|
|
@ -624,22 +627,22 @@ void DoomLevelSubmesh::BuildSurfaceParams(int lightMapTextureWidth, int lightMap
|
|||
case AXIS_YZ:
|
||||
width = (int)roundedSize.Y;
|
||||
height = (int)roundedSize.Z;
|
||||
tCoords[0].Y = 1.0f / surface.sampleDimension;
|
||||
tCoords[1].Z = 1.0f / surface.sampleDimension;
|
||||
tCoords[0].Y = 1.0f / surface.SampleDimension;
|
||||
tCoords[1].Z = 1.0f / surface.SampleDimension;
|
||||
break;
|
||||
|
||||
case AXIS_XZ:
|
||||
width = (int)roundedSize.X;
|
||||
height = (int)roundedSize.Z;
|
||||
tCoords[0].X = 1.0f / surface.sampleDimension;
|
||||
tCoords[1].Z = 1.0f / surface.sampleDimension;
|
||||
tCoords[0].X = 1.0f / surface.SampleDimension;
|
||||
tCoords[1].Z = 1.0f / surface.SampleDimension;
|
||||
break;
|
||||
|
||||
case AXIS_XY:
|
||||
width = (int)roundedSize.X;
|
||||
height = (int)roundedSize.Y;
|
||||
tCoords[0].X = 1.0f / surface.sampleDimension;
|
||||
tCoords[1].Y = 1.0f / surface.sampleDimension;
|
||||
tCoords[0].X = 1.0f / surface.SampleDimension;
|
||||
tCoords[1].Y = 1.0f / surface.SampleDimension;
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -657,18 +660,19 @@ void DoomLevelSubmesh::BuildSurfaceParams(int lightMapTextureWidth, int lightMap
|
|||
height = (lightMapTextureHeight - 2);
|
||||
}
|
||||
|
||||
surface.translateWorldToLocal = bounds.min;
|
||||
surface.projLocalToU = tCoords[0];
|
||||
surface.projLocalToV = tCoords[1];
|
||||
surface.TileTransform.TranslateWorldToLocal = bounds.min;
|
||||
surface.TileTransform.ProjLocalToU = tCoords[0];
|
||||
surface.TileTransform.ProjLocalToV = tCoords[1];
|
||||
|
||||
for (int i = 0; i < surface.numVerts; i++)
|
||||
for (int i = 0; i < surface.MeshLocation.NumVerts; i++)
|
||||
{
|
||||
FVector3 tDelta = Mesh.Vertices[surface.startVertIndex + i].fPos() - surface.translateWorldToLocal;
|
||||
FVector3 tDelta = Mesh.Vertices[surface.MeshLocation.StartVertIndex + i].fPos() - surface.TileTransform.TranslateWorldToLocal;
|
||||
|
||||
Mesh.Vertices[surface.startVertIndex + i].lu = (tDelta | surface.projLocalToU);
|
||||
Mesh.Vertices[surface.startVertIndex + i].lv = (tDelta | surface.projLocalToV);
|
||||
Mesh.Vertices[surface.MeshLocation.StartVertIndex + i].lu = (tDelta | surface.TileTransform.ProjLocalToU);
|
||||
Mesh.Vertices[surface.MeshLocation.StartVertIndex + i].lv = (tDelta | surface.TileTransform.ProjLocalToV);
|
||||
}
|
||||
|
||||
#if 0
|
||||
// project tCoords so they lie on the plane
|
||||
const FVector4& plane = surface.plane;
|
||||
float d = ((bounds.min | FVector3(plane.X, plane.Y, plane.Z)) - plane.W) / plane[axis]; //d = (plane->PointToDist(bounds.min)) / plane->Normal()[axis];
|
||||
|
|
@ -678,6 +682,7 @@ void DoomLevelSubmesh::BuildSurfaceParams(int lightMapTextureWidth, int lightMap
|
|||
d = (tCoords[i] | FVector3(plane.X, plane.Y, plane.Z)) / plane[axis]; //d = dot(tCoords[i], plane->Normal()) / plane->Normal()[axis];
|
||||
tCoords[i][axis] -= d;
|
||||
}
|
||||
#endif
|
||||
|
||||
surface.AtlasTile.Width = width;
|
||||
surface.AtlasTile.Height = height;
|
||||
|
|
|
|||
|
|
@ -25,18 +25,15 @@ struct DoomLevelMeshSurface : public LevelMeshSurface
|
|||
side_t* Side = nullptr;
|
||||
sector_t* ControlSector = nullptr;
|
||||
|
||||
FFlatVertex* Vertices = nullptr;
|
||||
int PipelineID = 0;
|
||||
};
|
||||
|
||||
class DoomLevelSubmesh : public LevelSubmesh
|
||||
{
|
||||
public:
|
||||
DoomLevelSubmesh(DoomLevelMesh* mesh) : LevelMesh(mesh) { }
|
||||
DoomLevelSubmesh(DoomLevelMesh* mesh, FLevelLocals& doomMap, bool staticMesh);
|
||||
|
||||
void CreateStatic(FLevelLocals& doomMap);
|
||||
void CreateDynamic(FLevelLocals& doomMap);
|
||||
void UpdateDynamic(FLevelLocals& doomMap, int lightmapStartIndex);
|
||||
void Update(FLevelLocals& doomMap, int lightmapStartIndex);
|
||||
|
||||
LevelMeshSurface* GetSurface(int index) override { return &Surfaces[index]; }
|
||||
unsigned int GetSurfaceIndex(const LevelMeshSurface* surface) const override { return (unsigned int)(ptrdiff_t)(static_cast<const DoomLevelMeshSurface*>(surface) - Surfaces.Data()); }
|
||||
|
|
@ -98,7 +95,7 @@ private:
|
|||
static PlaneAxis BestAxis(const FVector4& p);
|
||||
BBox GetBoundsFromSurface(const LevelMeshSurface& surface) const;
|
||||
|
||||
void BuildSurfaceParams(int lightMapTextureWidth, int lightMapTextureHeight, LevelMeshSurface& surface);
|
||||
void SetupTileTransform(int lightMapTextureWidth, int lightMapTextureHeight, LevelMeshSurface& surface);
|
||||
|
||||
static bool IsDegenerate(const FVector3& v0, const FVector3& v1, const FVector3& v2);
|
||||
|
||||
|
|
@ -107,6 +104,7 @@ private:
|
|||
static FVector4 ToFVector4(const DVector4& v) { return FVector4((float)v.X, (float)v.Y, (float)v.Z, (float)v.W); }
|
||||
|
||||
DoomLevelMesh* LevelMesh = nullptr;
|
||||
bool StaticMesh = true;
|
||||
};
|
||||
|
||||
static_assert(alignof(FVector2) == alignof(float[2]) && sizeof(FVector2) == sizeof(float) * 2);
|
||||
|
|
|
|||
|
|
@ -246,7 +246,7 @@ static int CreateIndexedSectorVerticesLM(FRenderState& renderstate, sector_t* se
|
|||
DoomLevelMeshSurface* lightmap = sub->surface[h].Size() > lightmapIndex ? sub->surface[h][lightmapIndex] : nullptr;
|
||||
if (lightmap && lightmap->Type != ST_NONE) // surface may be missing if the subsector is degenerate triangle
|
||||
{
|
||||
FFlatVertex* luvs = lightmap->Vertices;
|
||||
FFlatVertex* luvs = &lightmap->Submesh->Mesh.Vertices[lightmap->MeshLocation.StartVertIndex];
|
||||
for (unsigned int j = 0; j < sub->numlines; j++)
|
||||
{
|
||||
SetFlatVertex(vbo_shadowdata[vi + pos], sub->firstline[j].v1, plane, luvs[j].lu, luvs[j].lv, luvs[j].lindex);
|
||||
|
|
|
|||
|
|
@ -541,7 +541,7 @@ void HWDrawInfo::UpdateLightmaps()
|
|||
{
|
||||
for (auto& e : static_cast<DoomLevelSubmesh*>(level.levelMesh->StaticMesh.get())->Surfaces)
|
||||
{
|
||||
if (e.NeedsUpdate && !e.bSky && !e.portalIndex)
|
||||
if (e.NeedsUpdate && !e.IsSky && !e.PortalIndex)
|
||||
{
|
||||
VisibleSurfaces.Push(&e);
|
||||
|
||||
|
|
|
|||
|
|
@ -241,7 +241,7 @@ public:
|
|||
return;
|
||||
}
|
||||
|
||||
if (surface->NeedsUpdate && !surface->portalIndex && !surface->bSky)
|
||||
if (surface->NeedsUpdate && !surface->PortalIndex && !surface->IsSky)
|
||||
{
|
||||
VisibleSurfaces.Push(surface);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -910,13 +910,14 @@ bool HWWall::SetWallCoordinates(seg_t * seg, FTexCoordInfo *tci, float textureto
|
|||
}
|
||||
|
||||
texcoord srclightuv[4];
|
||||
if (surface && surface->Type != ST_NONE && surface->numVerts != 0)
|
||||
if (surface && surface->Type != ST_NONE && surface->MeshLocation.NumVerts >= 4)
|
||||
{
|
||||
srclightuv[0] = { surface->Vertices[0].lu, surface->Vertices[0].lv };
|
||||
srclightuv[1] = { surface->Vertices[1].lu, surface->Vertices[1].lv };
|
||||
srclightuv[2] = { surface->Vertices[2].lu, surface->Vertices[2].lv };
|
||||
srclightuv[3] = { surface->Vertices[3].lu, surface->Vertices[3].lv };
|
||||
lindex = surface->Vertices[0].lindex;
|
||||
FFlatVertex* vertices = &surface->Submesh->Mesh.Vertices[surface->MeshLocation.StartVertIndex];
|
||||
srclightuv[0] = { vertices[0].lu, vertices[0].lv };
|
||||
srclightuv[1] = { vertices[1].lu, vertices[1].lv };
|
||||
srclightuv[2] = { vertices[2].lu, vertices[2].lv };
|
||||
srclightuv[3] = { vertices[3].lu, vertices[3].lv };
|
||||
lindex = vertices[0].lindex;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -1674,11 +1675,12 @@ void HWWall::BuildFFBlock(HWWallDispatcher *di, FRenderState& state, seg_t * seg
|
|||
texcoord srclightuv[4];
|
||||
if (surface && surface->Type != ST_NONE)
|
||||
{
|
||||
srclightuv[0] = { surface->Vertices[0].lu, surface->Vertices[0].lv };
|
||||
srclightuv[1] = { surface->Vertices[1].lu, surface->Vertices[1].lv };
|
||||
srclightuv[2] = { surface->Vertices[2].lu, surface->Vertices[2].lv };
|
||||
srclightuv[3] = { surface->Vertices[3].lu, surface->Vertices[3].lv };
|
||||
lindex = surface->Vertices[0].lindex;
|
||||
FFlatVertex* vertices = &surface->Submesh->Mesh.Vertices[surface->MeshLocation.StartVertIndex];
|
||||
srclightuv[0] = { vertices[0].lu, vertices[0].lv };
|
||||
srclightuv[1] = { vertices[1].lu, vertices[1].lv };
|
||||
srclightuv[2] = { vertices[2].lu, vertices[2].lv };
|
||||
srclightuv[3] = { vertices[3].lu, vertices[3].lv };
|
||||
lindex = vertices[0].lindex;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue