Skip to content

Commit

Permalink
Reference the main section's materials and textures if the section do…
Browse files Browse the repository at this point in the history
…esn't have its own Material.c4g to improve memory usage and loading times
  • Loading branch information
Fulgen301 committed Apr 17, 2024
1 parent 50cc7df commit 2b288bd
Show file tree
Hide file tree
Showing 9 changed files with 179 additions and 90 deletions.
23 changes: 18 additions & 5 deletions src/C4Game.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -573,8 +573,10 @@ void C4Game::Clear()
Players.Clear();
Parameters.Clear();
RoundResults.Clear();
Sections.clear();
// Ensure the main section is destroyed last
SectionsPendingDeletion.clear();
Sections.resize(1);
Sections.clear();
C4S.Clear();
GraphicsSystem.Clear();
Defs.Clear();
Expand Down Expand Up @@ -1896,15 +1898,26 @@ bool C4Game::InitGameFirstPart()

SetInitProgress(57);

auto *const front = Sections.front().get();

// Materials
if (!std::ranges::all_of(Sections, &C4Section::InitMaterialTexture))
if (!front->InitMaterialTexture(nullptr))
{
return false;
}

for (auto &section : Sections | std::views::drop(1))
{
if (!section->InitMaterialTexture(front))
{
return false;
}
}

SetInitProgress(58);

// Colorize defs by material
Defs.ColorizeByMaterial(Sections.front()->Material, GBM);
Defs.ColorizeByMaterial(front->Material, GBM);
SetInitProgress(60);

PreloadStatus = PreloadLevel::Basic;
Expand Down Expand Up @@ -2565,7 +2578,7 @@ std::uint32_t C4Game::CreateSection(const char *const name)

const auto &back = Sections.back();

if (back->InitMaterialTexture()
if (back->InitMaterialTexture(Sections.front().get())
&& back->InitSecondPart()
&& back->InitThirdPart()
)
Expand All @@ -2592,7 +2605,7 @@ std::uint32_t C4Game::CreateEmptySection(const C4SLandscape &landscape)

const auto &back = Sections.back();

if (back->InitMaterialTexture()
if (back->InitMaterialTexture(Sections.front().get())
&& back->InitSecondPart()
&& back->InitThirdPart()
)
Expand Down
7 changes: 7 additions & 0 deletions src/C4Material.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -534,6 +534,13 @@ bool C4MaterialMap::LoadEnumeration(C4Group &hGroup)
return true;
}

void C4MaterialMap::CopyMaterials(const C4MaterialMap &source)
{
Num = source.Num;
Map = new C4Material[Num];
std::ranges::uninitialized_copy_n(source.Map, source.Num, Map, Map + Num);
}

bool C4MaterialMap::SortEnumeration(int32_t iMat, const char *szMatName)
{
// Not enough materials loaded
Expand Down
2 changes: 2 additions & 0 deletions src/C4Material.h
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,8 @@ class C4MaterialMap
bool SaveEnumeration(C4Group &hGroup);
bool LoadEnumeration(C4Group &hGroup);

void CopyMaterials(const C4MaterialMap &source);

C4MaterialReaction *GetReactionUnsafe(int32_t iPXSMat, int32_t iLandscapeMat)
{
assert(ppReactionMap); assert(Inside<int32_t>(iPXSMat, -1, Num - 1)); assert(Inside<int32_t>(iLandscapeMat, -1, Num - 1));
Expand Down
151 changes: 80 additions & 71 deletions src/C4Section.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -130,99 +130,108 @@ bool C4Section::InitFromEmptyLandscape(C4Group &scenario, const C4SLandscape &la
return true;
}

bool C4Section::InitMaterialTexture()
bool C4Section::InitMaterialTexture(C4Section *const fallback)
{
// Clear old data
TextureMap.Clear();
Material.Clear();

// Check for scenario local materials
bool haveSectionMaterials{Group.FindEntry(C4CFN_Material)};
bool haveScenarioFileMaterials{!name.empty() && Game.ScenarioFile.FindEntry(C4CFN_Material)};

// Load all materials
auto matRes = Game.Parameters.GameRes.iterRes(NRT_Material);
bool fFirst = true, fOverloadMaterials = true, fOverloadTextures = true;
long tex_count = 0, mat_count = 0;
while (fOverloadMaterials || fOverloadTextures)
bool haveSectionMaterials{!emptyLandscape && Group.FindEntry(C4CFN_Material)};

if (!haveSectionMaterials && fallback)
{
// Are there any scenario local materials that need to be looked at firs?
C4Group Mats;
if (haveSectionMaterials)
Material.CopyMaterials(fallback->Material);
TextureMap = fallback->TextureMap;
}
else
{
bool haveScenarioFileMaterials{!name.empty() && Game.ScenarioFile.FindEntry(C4CFN_Material)};

// Load all materials
auto matRes = Game.Parameters.GameRes.iterRes(NRT_Material);
bool fFirst = true, fOverloadMaterials = true, fOverloadTextures = true;
long tex_count = 0, mat_count = 0;
while (fOverloadMaterials || fOverloadTextures)
{
if (!Mats.OpenAsChild(&Group, C4CFN_Material))
// Are there any scenario local materials that need to be looked at firs?
C4Group Mats;
if (haveSectionMaterials)
{
LogFatal(FormatString(LoadResStr("IDS_ERR_SCENARIOMATERIALS"), Mats.GetError()).getData());
return false;
if (!Mats.OpenAsChild(&Group, C4CFN_Material))
{
LogFatal(FormatString(LoadResStr("IDS_ERR_SCENARIOMATERIALS"), Mats.GetError()).getData());
return false;
}
// Once only
haveSectionMaterials = false;
}
// Once only
haveSectionMaterials = false;
}
else if (haveScenarioFileMaterials)
{
if (!Mats.OpenAsChild(&Game.ScenarioFile, C4CFN_Material))
else if (haveScenarioFileMaterials)
{
LogFatal(FormatString(LoadResStr("IDS_ERR_SCENARIOMATERIALS"), Mats.GetError()).getData());
return false;
if (!Mats.OpenAsChild(&Game.ScenarioFile, C4CFN_Material))
{
LogFatal(FormatString(LoadResStr("IDS_ERR_SCENARIOMATERIALS"), Mats.GetError()).getData());
return false;
}

haveScenarioFileMaterials = false;
}
else
{
if (matRes == matRes.end()) break;
// Find next external material source
if (!Mats.Open(matRes->getFile()))
{
LogFatal(FormatString(LoadResStr("IDS_ERR_EXTERNALMATERIALS"), matRes->getFile(), Mats.GetError()).getData());
return false;
}
++matRes;
}

haveScenarioFileMaterials = false;
}
else
{
if (matRes == matRes.end()) break;
// Find next external material source
if (!Mats.Open(matRes->getFile()))
// First material file? Load texture map.
bool fNewOverloadMaterials = false, fNewOverloadTextures = false;
if (fFirst)
{
LogFatal(FormatString(LoadResStr("IDS_ERR_EXTERNALMATERIALS"), matRes->getFile(), Mats.GetError()).getData());
return false;
long tme_count = TextureMap.LoadMap(Mats, C4CFN_TexMap, &fNewOverloadMaterials, &fNewOverloadTextures);
LogF(LoadResStr("IDS_PRC_TEXMAPENTRIES"), tme_count);
// Only once
fFirst = false;
}
else
{
// Check overload-flags only
if (!C4TextureMap::LoadFlags(Mats, C4CFN_TexMap, &fNewOverloadMaterials, &fNewOverloadTextures))
fOverloadMaterials = fOverloadTextures = false;
}
++matRes;
}

// First material file? Load texture map.
bool fNewOverloadMaterials = false, fNewOverloadTextures = false;
if (fFirst)
{
long tme_count = TextureMap.LoadMap(Mats, C4CFN_TexMap, &fNewOverloadMaterials, &fNewOverloadTextures);
LogF(LoadResStr("IDS_PRC_TEXMAPENTRIES"), tme_count);
// Only once
fFirst = false;
}
else
{
// Check overload-flags only
if (!C4TextureMap::LoadFlags(Mats, C4CFN_TexMap, &fNewOverloadMaterials, &fNewOverloadTextures))
fOverloadMaterials = fOverloadTextures = false;
}
// Load textures
if (fOverloadTextures)
{
int iTexs = TextureMap.LoadTextures(Mats);
// Automatically continue search if no texture was found
if (!iTexs) fNewOverloadTextures = true;
tex_count += iTexs;
}

// Load textures
if (fOverloadTextures)
{
int iTexs = TextureMap.LoadTextures(Mats);
// Automatically continue search if no texture was found
if (!iTexs) fNewOverloadTextures = true;
tex_count += iTexs;
}
// Load materials
if (fOverloadMaterials)
{
int iMats = Material.Load(Mats);
// Automatically continue search if no material was found
if (!iMats) fNewOverloadMaterials = true;
mat_count += iMats;
}

// Load materials
if (fOverloadMaterials)
{
int iMats = Material.Load(Mats);
// Automatically continue search if no material was found
if (!iMats) fNewOverloadMaterials = true;
mat_count += iMats;
// Set flags
fOverloadTextures = fNewOverloadTextures;
fOverloadMaterials = fNewOverloadMaterials;
}

// Set flags
fOverloadTextures = fNewOverloadTextures;
fOverloadMaterials = fNewOverloadMaterials;
// Logs
LogF(LoadResStr("IDS_PRC_TEXTURES"), tex_count);
LogF(LoadResStr("IDS_PRC_MATERIALS"), mat_count);
}

// Logs
LogF(LoadResStr("IDS_PRC_TEXTURES"), tex_count);
LogF(LoadResStr("IDS_PRC_MATERIALS"), mat_count);

// Load material enumeration
if (!Material.LoadEnumeration(Group))
{
Expand Down
2 changes: 1 addition & 1 deletion src/C4Section.h
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ class C4Section
bool InitFromTemplate(C4Group &scenario);
bool InitFromEmptyLandscape(C4Group &scenario, const C4SLandscape &landscape);

bool InitMaterialTexture();
bool InitMaterialTexture(C4Section *fallback);

bool InitSecondPart();
bool InitThirdPart();
Expand Down
36 changes: 29 additions & 7 deletions src/C4Texture.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,16 +29,16 @@
#include <C4Landscape.h>
#include <C4Wrappers.h>

C4Texture::C4Texture(const char *const name, std::unique_ptr<C4Surface> surface32)
C4Texture::C4Texture(const char *const name, std::shared_ptr<C4Surface> surface32)
: Surface32{std::move(surface32)}
{
SCopy(name, Name, C4M_MaxName);
SCopy(name, Name.data(), C4M_MaxName);
}

C4Texture::C4Texture(const char *const name, std::unique_ptr<CSurface8> surface8)
C4Texture::C4Texture(const char *const name, std::shared_ptr<CSurface8> surface8)
: Surface8{std::move(surface8)}
{
SCopy(name, Name, C4M_MaxName);
SCopy(name, Name.data(), C4M_MaxName);
}

C4TexMapEntry::C4TexMapEntry()
Expand Down Expand Up @@ -110,6 +110,28 @@ C4TextureMap::~C4TextureMap()
Clear();
}

C4TextureMap::C4TextureMap(const C4TextureMap &other)
: section{other.section},
Entry{other.Entry},
textures{other.textures},
fOverloadMaterials{other.fOverloadMaterials},
fOverloadTextures{other.fOverloadTextures},
fInitialized{other.fInitialized},
fEntriesAdded{other.fEntriesAdded}
{
}

C4TextureMap &C4TextureMap::operator=(const C4TextureMap &other)
{
Entry = other.Entry;
textures = other.textures;
fOverloadMaterials = other.fOverloadMaterials;
fOverloadTextures = other.fOverloadTextures;
fInitialized = other.fInitialized;
fEntriesAdded = other.fEntriesAdded;
return *this;
}

bool C4TextureMap::AddEntry(uint8_t byIndex, const char *szMaterial, const char *szTexture)
{
// Security
Expand Down Expand Up @@ -349,7 +371,7 @@ C4Texture *C4TextureMap::GetTexture(const char *szTexture)
{
for (auto &texture : textures)
{
if (SEqualNoCase(texture.Name, szTexture))
if (SEqualNoCase(texture.Name.data(), szTexture))
{
return &texture;
}
Expand All @@ -362,7 +384,7 @@ bool C4TextureMap::CheckTexture(const char *szTexture)
{
for (auto &texture : textures)
{
if (SEqualNoCase(texture.Name, szTexture))
if (SEqualNoCase(texture.Name.data(), szTexture))
{
return true;
}
Expand All @@ -373,7 +395,7 @@ bool C4TextureMap::CheckTexture(const char *szTexture)

const char *C4TextureMap::GetTexture(size_t iIndex)
{
return iIndex < textures.size() ? textures[iIndex].Name : nullptr;
return iIndex < textures.size() ? textures[iIndex].Name.data() : nullptr;
}

void C4TextureMap::Default()
Expand Down
25 changes: 19 additions & 6 deletions src/C4Texture.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,22 @@ class C4Texture
friend class C4TextureMap;

public:
C4Texture(const char *name, std::unique_ptr<C4Surface> surface32);
C4Texture(const char *name, std::unique_ptr<CSurface8> surface8);
C4Texture(const char *name, std::shared_ptr<C4Surface> surface32);
C4Texture(const char *name, std::shared_ptr<CSurface8> surface8);

public:
std::unique_ptr<C4Surface> Surface32;
std::unique_ptr<CSurface8> Surface8;
C4Texture(const C4Texture &) = default;
C4Texture &operator=(const C4Texture &) = default;
C4Texture(C4Texture &&) = default;
C4Texture &operator=(C4Texture &&) = default;


public:
std::shared_ptr<C4Surface> Surface32;
std::shared_ptr<CSurface8> Surface8;

protected:
char Name[C4M_MaxName + 1];
std::array<char, C4M_MaxName + 1> Name;
};

class C4TexMapEntry
Expand Down Expand Up @@ -70,9 +77,15 @@ class C4TextureMap
C4TextureMap(C4Section &section);
~C4TextureMap();

C4TextureMap(const C4TextureMap &other);
C4TextureMap &operator=(const C4TextureMap &other);

C4TextureMap(C4TextureMap &&other);
C4TextureMap &operator=(C4TextureMap &&other);

protected:
C4Section &section;
C4TexMapEntry Entry[C4M_MaxTexIndex];
std::array<C4TexMapEntry, C4M_MaxTexIndex> Entry;
std::vector<C4Texture> textures;
bool fOverloadMaterials;
bool fOverloadTextures;
Expand Down
Loading

0 comments on commit 2b288bd

Please sign in to comment.