Skip to content

Commit

Permalink
#5565: Lots of refactoring and moving stuff from the particle export …
Browse files Browse the repository at this point in the history
…algorithm to libs/, to be re-used by the MaterialManager.
  • Loading branch information
codereader committed Mar 28, 2021
1 parent 6daa204 commit 3056efd
Show file tree
Hide file tree
Showing 8 changed files with 176 additions and 61 deletions.
75 changes: 75 additions & 0 deletions libs/decl/SpliceHelper.h
@@ -0,0 +1,75 @@
#pragma once

#include <iostream>
#include <regex>

namespace decl
{

// Helper class which is able to cut out an existing declaration from the given
// input stream. The first line of the declaration is identified using the given regex.
// The part of the input stream leading up to the def is piped to the output stream in unmodified form,
// excluding the declaration block itself.
// Piping will either stop once the declaration is found (and omitted) or the input stream is exhausted.
class SpliceHelper
{
public:
static void PipeStreamUntilInsertionPoint(std::istream& input, std::ostream& output, const std::regex& patternToFind)
{
std::string line;

while (std::getline(input, line))
{
std::smatch matches;

// See if this line contains the def in question
if (std::regex_match(line, matches, patternToFind))
{
// Line matches, march from opening brace to the other one
std::size_t openBraces = 0;
bool blockStarted = false;

if (!matches[1].str().empty())
{
// We've had an opening brace in the first line
openBraces++;
blockStarted = true;
}

while (std::getline(input, line))
{
for (std::size_t i = 0; i < line.length(); ++i)
{
if (line[i] == '{')
{
openBraces++;
blockStarted = true;
}
else if (line[i] == '}')
{
openBraces--;
}
}

if (blockStarted && openBraces == 0)
{
break;
}
}

return; // stop right here, return to caller
}
else
{
// No particular match, add line to output
output << line;
}

// Append a newline in any case
output << std::endl;
}
}

};

}
24 changes: 24 additions & 0 deletions libs/stream/TemporaryOutputStream.h
Expand Up @@ -32,6 +32,30 @@ class TemporaryOutputStream
}
}

~TemporaryOutputStream()
{
// Remove the temporary file if it still existing at the End Of Life of this object
if (_stream.is_open())
{
_stream.close();
}

if (fs::exists(_temporaryPath))
{
rMessage() << "Cleaning up temporary file " << _temporaryPath << std::endl;

try
{
fs::remove(_temporaryPath);
}
catch (fs::filesystem_error& e)
{
rError() << "Could not remove the temporary file " << _temporaryPath << std::endl
<< e.what() << std::endl;
}
}
}

std::ostream& getStream()
{
return _stream;
Expand Down
63 changes: 4 additions & 59 deletions radiantcore/particles/ParticlesManager.cpp
Expand Up @@ -15,6 +15,7 @@
#include "i18n.h"

#include "parser/DefTokeniser.h"
#include "decl/SpliceHelper.h"
#include "stream/TemporaryOutputStream.h"
#include "math/Vector4.h"
#include "os/fs.h"
Expand Down Expand Up @@ -364,7 +365,9 @@ void ParticlesManager::saveParticleDef(const std::string& particleName)
}

// Write the file to the output stream, up to the point the particle def should be written to
stripParticleDefFromStream(inheritStream, stream, particleName);
std::regex pattern("^[\\s]*particle[\\s]+" + particleName + "\\s*(\\{)*\\s*$");

decl::SpliceHelper::PipeStreamUntilInsertionPoint(inheritStream, stream, pattern);

if (inheritStream.eof())
{
Expand Down Expand Up @@ -395,64 +398,6 @@ void ParticlesManager::saveParticleDef(const std::string& particleName)
tempStream.closeAndReplaceTargetFile();
}

void ParticlesManager::stripParticleDefFromStream(std::istream& input,
std::ostream& output, const std::string& particleName)
{
std::string line;
std::regex pattern("^[\\s]*particle[\\s]+" + particleName + "\\s*(\\{)*\\s*$");

while (std::getline(input, line))
{
std::smatch matches;

// See if this line contains the particle def in question
if (std::regex_match(line, matches, pattern))
{
// Line matches, march from opening brace to the other one
std::size_t openBraces = 0;
bool blockStarted = false;

if (!matches[1].str().empty())
{
// We've had an opening brace in the first line
openBraces++;
blockStarted = true;
}

while (std::getline(input, line))
{
for (std::size_t i = 0; i < line.length(); ++i)
{
if (line[i] == '{')
{
openBraces++;
blockStarted = true;
}
else if (line[i] == '}')
{
openBraces--;
}
}

if (blockStarted && openBraces == 0)
{
break;
}
}

return; // stop right here, return to caller
}
else
{
// No particular match, add line to output
output << line;
}

// Append a newline in any case
output << std::endl;
}
}

module::StaticModule<ParticlesManager> particlesManagerModule;

} // namespace particles
52 changes: 50 additions & 2 deletions radiantcore/shaders/Doom3ShaderSystem.cpp
@@ -1,5 +1,6 @@
#include "Doom3ShaderSystem.h"
#include "ShaderFileLoader.h"
#include "MaterialSourceGenerator.h"

#include "i18n.h"
#include "iradiant.h"
Expand All @@ -24,6 +25,8 @@

#include "os/file.h"
#include "os/path.h"
#include "decl/SpliceHelper.h"
#include "stream/TemporaryOutputStream.h"
#include "string/predicate.h"
#include "string/replace.h"
#include "parser/DefBlockTokeniser.h"
Expand Down Expand Up @@ -448,7 +451,7 @@ void Doom3ShaderSystem::saveMaterial(const std::string& name)
return;
}

if (!materialCanBeModified(name))
if (!materialCanBeModified(material->getName()))
{
throw std::runtime_error("Cannot save this material, it's read-only.");
}
Expand All @@ -469,9 +472,54 @@ void Doom3ShaderSystem::saveMaterial(const std::string& name)
fs::create_directories(outputDir);
}

rMessage() << "Saving material " << name << " to " << outputPath << std::endl;
rMessage() << "Saving material " << material->getName() << " to " << outputPath << std::endl;

stream::TemporaryOutputStream tempStream(outputPath);

std::string tempString;
auto& stream = tempStream.getStream();

// If a previous file exists, open it for reading and filter out the material def we'll be writing
if (fs::exists(outputPath))
{
std::ifstream inheritStream(outputPath);

if (!inheritStream.is_open())
{
throw std::runtime_error(
fmt::format(_("Cannot open file for reading: {0}"), outputPath.string()));
}

// Write the file to the output stream, up to the point the material def should be written to
std::regex pattern("^[\\s]*" + material->getName() + "\\s*(\\{)*\\s*$");

decl::SpliceHelper::PipeStreamUntilInsertionPoint(inheritStream, stream, pattern);

if (inheritStream.eof())
{
// Material declaration was not found in the inherited stream, write our comment
stream << std::endl << std::endl;

MaterialSourceGenerator::WriteMaterialGenerationComment(stream);
}

// We're at the insertion point (which might as well be EOF of the inheritStream)

// Write the name, curly braces and block contents
MaterialSourceGenerator::WriteFullMaterialToStream(stream, material);

stream << inheritStream.rdbuf();

inheritStream.close();
}
else
{
// File is empty, just write the comment and the declaration
MaterialSourceGenerator::WriteMaterialGenerationComment(stream);
MaterialSourceGenerator::WriteFullMaterialToStream(stream, material);
}

tempStream.closeAndReplaceTargetFile();
}

ITableDefinition::Ptr Doom3ShaderSystem::getTable(const std::string& name)
Expand Down
15 changes: 15 additions & 0 deletions radiantcore/shaders/MaterialSourceGenerator.cpp
Expand Up @@ -647,4 +647,19 @@ std::string MaterialSourceGenerator::GenerateDefinitionBlock(ShaderTemplate& sha
return output.str();
}

void MaterialSourceGenerator::WriteMaterialGenerationComment(std::ostream& stream)
{
stream << "/*" << std::endl
<< "\tGenerated by DarkRadiant's Material Editor."
<< std::endl << "*/" << std::endl;
}

void MaterialSourceGenerator::WriteFullMaterialToStream(std::ostream& stream, const MaterialPtr& material)
{
stream << material->getName();
stream << "{";
stream << material->getDefinition();
stream << "}" << std::endl << std::endl;
}

}
6 changes: 6 additions & 0 deletions radiantcore/shaders/MaterialSourceGenerator.h
Expand Up @@ -13,6 +13,12 @@ class MaterialSourceGenerator
// Generates the material block contents from the given template
// (the part within the curly braces, but without the braces themselves)
static std::string GenerateDefinitionBlock(ShaderTemplate& shaderTemplate);

// Writes a comment about this material having been created by DarkRadiant
static void WriteMaterialGenerationComment(std::ostream& stream);

// Write the name, opening curly braces, block contents, closing curly braces to the given stream
static void WriteFullMaterialToStream(std::ostream& stream, const MaterialPtr& material);
};

}
1 change: 1 addition & 0 deletions tools/msvc/libs.vcxproj
Expand Up @@ -149,6 +149,7 @@
<ClInclude Include="..\..\libs\debugging\render.h" />
<ClInclude Include="..\..\libs\debugging\ScenegraphUtils.h" />
<ClInclude Include="..\..\libs\debugging\ScopedDebugTimer.h" />
<ClInclude Include="..\..\libs\decl\SpliceHelper.h" />
<ClInclude Include="..\..\libs\DirectoryArchiveFile.h" />
<ClInclude Include="..\..\libs\dragplanes.h" />
<ClInclude Include="..\..\libs\eclass.h" />
Expand Down
1 change: 1 addition & 0 deletions tools/msvc/libs.vcxproj.filters
Expand Up @@ -286,6 +286,7 @@
<ClInclude Include="..\..\libs\stream\TemporaryOutputStream.h">
<Filter>stream</Filter>
</ClInclude>
<ClInclude Include="..\..\libs\decl\SpliceHelper.h" />
</ItemGroup>
<ItemGroup>
<Filter Include="util">
Expand Down

0 comments on commit 3056efd

Please sign in to comment.