Skip to content

Commit

Permalink
📚 preserve .TOBJ comment lines when editing in-game.
Browse files Browse the repository at this point in the history
Only works for:
* static object lines
* procedural points
* procedural points imported from old-style (rortoolkit) roads.
  • Loading branch information
ohlidalp committed Dec 15, 2024
1 parent b223869 commit 15df6ae
Show file tree
Hide file tree
Showing 6 changed files with 73 additions and 7 deletions.
66 changes: 60 additions & 6 deletions source/main/resources/tobj_fileformat/TObjFileFormat.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -72,15 +72,29 @@ void TObjParser::Prepare()
bool TObjParser::ProcessLine(const char* line)
{
bool result = true;
if ((line != nullptr) && (line[0] != 0) && (line[0] != '/') && (line[0] != ';'))
if ((line != nullptr) && (line[0] != 0))
{
m_cur_line = line; // No trimming by design.
m_cur_line_trimmed = line;
while (m_cur_line_trimmed[0] == ' ' || m_cur_line_trimmed[0] == '\t')
bool is_comment = (line[0] == '/') || (line[0] == ';');
if (is_comment)
{
m_cur_line_trimmed++;
int text_start = 1;
while (line[text_start] == '/')
{
text_start++;
}
m_preceding_line_comments += std::string(line + text_start) + "\n";
}
else
{
m_cur_line = line; // No trimming by design.
m_cur_line_trimmed = line;
while (m_cur_line_trimmed[0] == ' ' || m_cur_line_trimmed[0] == '\t')
{
m_cur_line_trimmed++;
}
result = this->ProcessCurrentLine();
m_preceding_line_comments = "";
}
result = this->ProcessCurrentLine();
}
m_line_number++;
return result;
Expand Down Expand Up @@ -250,6 +264,9 @@ void TObjParser::ProcessProceduralLine()
else if (obj_name == "bridge_no_pillars") { point.type = RoadType::ROAD_BRIDGE; point.pillartype = 0; }
else { point.type = RoadType::ROAD_AUTOMATIC; point.pillartype = 1; }

// Attach comments
point.comments = m_preceding_line_comments;

m_cur_procedural_obj->points.push_back(new ProceduralPoint(point));
}

Expand Down Expand Up @@ -364,6 +381,9 @@ void TObjParser::ImportProceduralPoint(Ogre::Vector3 const& pos, Ogre::Vector3 c
pp.type = (special == TObj::SpecialObject::ROAD) ? RoadType::ROAD_FLAT : RoadType::ROAD_AUTOMATIC;
pp.width = 8;

// Attach comments
pp.comments = m_preceding_line_comments;

m_cur_procedural_obj->points.push_back(new ProceduralPoint(pp));
if (m_cur_procedural_obj_start_line == -1)
{
Expand Down Expand Up @@ -417,6 +437,10 @@ bool TObjParser::ParseObjectLine(TObjEntry& object)

object = TObjEntry(pos, rot, odef.ToCStr(), special, type, name);
object.rendering_distance = m_default_rendering_distance;

// Attach comments
object.comments = m_preceding_line_comments;

return true;
}

Expand Down Expand Up @@ -510,6 +534,16 @@ void TObj::WriteToStream(TObjDocumentPtr doc, Ogre::DataStreamPtr stream)
WriteTObjDelimiter(stream, "vehicles/loads/machines", doc->vehicles.size());
for (TObjVehicle& vehicle : doc->vehicles)
{
// Handle preceding comments
if (vehicle.comments != "")
{
for (Ogre::String& commenttext : Ogre::StringUtil::split(vehicle.comments, "\n"))
{
std::string commentline = fmt::format("// {}\n", commenttext);
stream->write(commentline.c_str(), commentline.length());
}
}

std::string line = fmt::format("{:9f}, {:9f}, {:9f}, {:9f}, {:9f}, {:9f}, {} {}\n",
vehicle.position.x, vehicle.position.y, vehicle.position.z,
vehicle.rotation.getRoll().valueDegrees(), vehicle.rotation.getYaw().valueDegrees(), vehicle.rotation.getPitch().valueDegrees(),
Expand Down Expand Up @@ -544,6 +578,16 @@ void TObj::WriteToStream(TObjDocumentPtr doc, Ogre::DataStreamPtr stream)
case RoadType::ROAD_MONORAIL: type_str = (point->pillartype == 2) ? "monorail" : "monorail2"; break;
}

// Handle preceding comments
if (point->comments != "")
{
for (Ogre::String& commenttext : Ogre::StringUtil::split(point->comments, "\n"))
{
std::string commentline = fmt::format("// {}\n", commenttext);
stream->write(commentline.c_str(), commentline.length());
}
}

std::string line = fmt::format(
"\t{:13f}, {:13f}, {:13f}, 0, {:13f}, 0, {:13f}, {:13f}, {:13f}, {}\n",
point->position.x, point->position.y, point->position.z,
Expand All @@ -560,6 +604,16 @@ void TObj::WriteToStream(TObjDocumentPtr doc, Ogre::DataStreamPtr stream)
WriteTObjDelimiter(stream, "static objects", doc->objects.size());
for (TObjEntry& entry : doc->objects)
{
// Handle preceding comments
if (entry.comments != "")
{
for (Ogre::String& commenttext : Ogre::StringUtil::split(entry.comments, "\n"))
{
std::string commentline = fmt::format("// {}\n", commenttext);
stream->write(commentline.c_str(), commentline.length());
}
}

std::string line = fmt::format("{:8.3f}, {:8.3f}, {:8.3f}, {:9f}, {:9f}, {:9f}, {} {} {}\n",
entry.position.x, entry.position.y, entry.position.z,
entry.rotation.x, entry.rotation.y, entry.rotation.z,
Expand Down
3 changes: 3 additions & 0 deletions source/main/resources/tobj_fileformat/TObjFileFormat.h
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ struct TObjVehicle
Ogre::Quaternion rotation;
char name[TObj::STR_LEN];
TObj::SpecialObject type;
std::string comments; //!< Comment line(s) preceding the vehicle-line in the .TOBJ file.
};

// -----------------------------------------------------------------------------
Expand All @@ -152,6 +153,7 @@ struct TObjEntry
char instance_name[TObj::STR_LEN] = {};
char odef_name[TObj::STR_LEN] = {};
float rendering_distance = 0.f; // 0 means 'always rendered', see https://ogrecave.github.io/ogre/api/1.11/class_ogre_1_1_movable_object.html#afe1f2a1009e3f14f36e1bcc9b1b9557e
std::string comments; //!< Comment line(s) preceding the object-line in the .TOBJ file.
};

// -----------------------------------------------------------------------------
Expand Down Expand Up @@ -203,6 +205,7 @@ class TObjParser
const char* m_cur_line;
const char* m_cur_line_trimmed;
float m_default_rendering_distance;
std::string m_preceding_line_comments;

// Procedural roads
bool m_in_procedural_road;
Expand Down
4 changes: 3 additions & 1 deletion source/main/terrain/ProceduralManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,8 @@ struct ProceduralPoint: public RefCountingObject<ProceduralPoint>
width(orig.width),
bwidth(orig.bwidth),
bheight(orig.bheight),
pillartype(orig.pillartype) {}
pillartype(orig.pillartype),
comments(orig.comments){}

virtual ~ProceduralPoint() override {};

Expand All @@ -54,6 +55,7 @@ struct ProceduralPoint: public RefCountingObject<ProceduralPoint>
float bwidth = 0.f;
float bheight = 0.f;
int pillartype = 0;
std::string comments; //!< Comment line(s) preceding the point-line in the .TOBJ file.
};

struct ProceduralObject: public RefCountingObject<ProceduralObject>
Expand Down
1 change: 1 addition & 0 deletions source/main/terrain/TerrainEditor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,7 @@ void TerrainEditor::WriteOutputFile()
// TBD: reconstruct 'set_default_rendering_distance'.
dst.position = src.position;
dst.rotation = src.rotation;
dst.comments = src.tobj_comments;

tobj->objects.push_back(dst);
}
Expand Down
5 changes: 5 additions & 0 deletions source/main/terrain/TerrainObjectManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -264,8 +264,13 @@ void TerrainObjectManager::LoadTObjFile(Ogre::String tobj_name)
try
{
m_tobj_cache_active_id = (int)m_tobj_cache.size() - 1;
size_t num_editor_objects = m_editor_objects.size();
this->LoadTerrainObject(entry.odef_name, entry.position, entry.rotation, entry.instance_name, entry.type, entry.rendering_distance);
m_tobj_cache_active_id = -1;
if (m_editor_objects.size() > num_editor_objects)
{
m_editor_objects.back().tobj_comments = entry.comments;
}
}
catch (...)
{
Expand Down
1 change: 1 addition & 0 deletions source/main/terrain/TerrainObjectManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ class TerrainObjectManager
bool enable_collisions = true;
int script_handler = -1;
int tobj_cache_id = -1;
std::string tobj_comments;
};

TerrainObjectManager(Terrain* terrainManager);
Expand Down

0 comments on commit 15df6ae

Please sign in to comment.