17
0
mirror of https://github.com/MaSzyna-EU07/maszyna.git synced 2026-10-17 02:49:19 +02:00

feat(terrain): binary terrain (BTF2) keeps the sweeps and the //$ lines of its text file and loads them with the terrain; a sweep in the text file no longer stops the conversion; binary files of the version before made again from the text

This commit is contained in:
maj00r
2026-10-08 00:51:29 +02:00
parent ca208b3ed1
commit b451f80c6d
3 changed files with 71 additions and 2 deletions

View File

@@ -81,7 +81,7 @@ namespace
{
std::uint32_t const EU07_FILEHEADER{MAKE_ID4('E', 'U', '0', '7')};
std::uint32_t const EU07_FILEVERSION_TERRAIN{MAKE_ID4('B', 'T', 'F', '1')};
std::uint32_t const EU07_FILEVERSION_TERRAIN{MAKE_ID4('B', 'T', 'F', '2')};
std::uint32_t const EU07_TERRAINBLOCK{MAKE_ID4('B', 'T', 'F', 'S')};
std::size_t const EU07_TERRAINVERTEXSIZE{8 * sizeof(float)};
@@ -92,6 +92,8 @@ struct file_header
std::uint32_t materialcount{0};
std::uint32_t sectioncount{0};
std::uint64_t vertexcount{0};
std::uint64_t extraoffset{0};
std::uint32_t extrasize{0};
};
// adds value to the data in the byte order of the file
@@ -215,7 +217,7 @@ bool read_file(std::string const &Filename, std::string &Data)
// loads the fixed part of binary terrain file header. returns: true if the file can be used, false otherwise
bool read_header(std::istream &Input, file_header &Header)
{
char bytes[48];
char bytes[60];
Input.read(bytes, sizeof(bytes));
if (Input.gcount() != static_cast<std::streamsize>(sizeof(bytes)))
{
@@ -238,6 +240,8 @@ bool read_header(std::istream &Input, file_header &Header)
Header.materialcount = data.get<std::uint32_t>();
Header.sectioncount = data.get<std::uint32_t>();
Header.vertexcount = data.get<std::uint64_t>();
Header.extraoffset = data.get<std::uint64_t>();
Header.extrasize = data.get<std::uint32_t>();
return data.good();
}
@@ -395,6 +399,24 @@ bool terrain_file::write(std::string const &Text, std::string const &Binaryfile,
conversion_scope scope;
auto region{std::make_unique<basic_region>()};
scratch_data scratchpad{};
std::string extra;
{
std::size_t begin{0};
while (begin < Text.size())
{
auto end{Text.find('\n', begin)};
end = (end == std::string::npos ? Text.size() : end + 1);
auto const first{Text.find_first_not_of(" \t", begin)};
if (first < end && Text.compare(first, 3, "//$") == 0)
{
auto line{Text.substr(first, end - first)};
while (false == line.empty() && (line.back() == '\n' || line.back() == '\r'))
line.pop_back();
extra += line + "\n";
}
begin = end;
}
}
{
cParser input{Text, cParser::buffer_TEXT};
@@ -405,9 +427,26 @@ bool terrain_file::write(std::string const &Text, std::string const &Binaryfile,
{
if (token == "node")
{
auto const begin{static_cast<std::size_t>(input.TokenBegin())};
node_data nodedata;
input.getTokens(4);
input >> nodedata.range_max >> nodedata.range_min >> nodedata.name >> nodedata.type;
if (nodedata.type == "sweep")
{
auto rest{input.getToken<std::string>()};
while (false == rest.empty() && rest != "endsweep")
rest = input.getToken<std::string>();
auto const end{static_cast<std::size_t>(input.TokenEnd())};
auto const offset{scratchpad.location.offset.empty() ? glm::dvec3{0.0} : scratchpad.location.offset.top()};
auto const placed{offset != glm::dvec3{0.0}};
if (placed)
extra += "origin " + std::to_string(offset.x) + ' ' + std::to_string(offset.y) + ' ' + std::to_string(offset.z) + "\n";
extra += Text.substr(begin, end - begin) + "\n";
if (placed)
extra += "endorigin\n";
token = input.getToken<std::string>();
continue;
}
if (nodedata.type != "triangles" && nodedata.type != "triangle_strip" && nodedata.type != "triangle_fan")
{
Message = "node of type \"" + nodedata.type + "\" (line " + std::to_string(input.Line()) + ") can't be a part of binary terrain";
@@ -485,6 +524,9 @@ bool terrain_file::write(std::string const &Text, std::string const &Binaryfile,
put(data, static_cast<std::uint32_t>(sections.size()));
auto const vertexcountposition{data.size()};
put(data, vertexcount); // filled in when the count is known
auto const extraposition{data.size()};
put(data, std::uint64_t{0});
put(data, std::uint32_t{0});
for (auto const &material : scope.materials())
{
data.append(material.c_str(), material.size() + 1);
@@ -562,6 +604,12 @@ bool terrain_file::write(std::string const &Text, std::string const &Binaryfile,
put(directory, section->m_area.radius);
offset += data.size();
}
output.write(extra.data(), static_cast<std::streamsize>(extra.size()));
data.clear();
put(data, static_cast<std::uint64_t>(offset));
put(data, static_cast<std::uint32_t>(extra.size()));
output.seekp(static_cast<std::streamoff>(extraposition));
output.write(data.data(), static_cast<std::streamsize>(data.size()));
// fill in the parts left for later
output.seekp(static_cast<std::streamoff>(directoryposition));
output.write(directory.data(), static_cast<std::streamsize>(directory.size()));
@@ -672,6 +720,25 @@ terrain_file::state terrain_file::prepare(std::string const &Textfile, std::stri
return state::text;
}
std::string terrain_file::extra(std::string const &Binaryfile)
{
std::ifstream input{Binaryfile, std::ios::binary};
file_header header;
if (input.fail() || false == read_header(input, header) || header.extrasize == 0)
{
return {};
}
std::string text(header.extrasize, '\0');
input.seekg(static_cast<std::streamoff>(header.extraoffset));
input.read(text.data(), static_cast<std::streamsize>(text.size()));
if (static_cast<std::size_t>(std::max<std::streamsize>(0, input.gcount())) != text.size())
{
ErrorLog("Bad file: \"" + Binaryfile + "\" is damaged, the editor data it holds can't be read");
return {};
}
return text;
}
// makes content of specified binary terrain file a part of provided region
bool terrain_file::attach(std::string const &Binaryfile, basic_region &Region, bool Deferred)
{

View File

@@ -46,6 +46,7 @@ class terrain_file
static bool attach(std::string const &Binaryfile, basic_region &Region, bool Deferred);
// loads specified piece of a binary terrain file into provided section
static void load(basic_section &Section, terrain_block const &Block);
static std::string extra(std::string const &Binaryfile);
private:
// converts provided content of a text terrain file to binary format and stores it in specified file. returns: true on success, false otherwise

View File

@@ -1235,6 +1235,7 @@ include_terrain_file( std::string File, std::string &Includes, scene::scratch_da
else {
binary.terrain_binaryfiles.emplace_back( binaryfile );
}
Includes += scene::terrain_file::extra( binaryfile ) + ' ';
break;
}
case scene::terrain_file::state::text: {