diff --git a/editormode.cpp b/editormode.cpp index 71e14e96..ef9b897f 100644 --- a/editormode.cpp +++ b/editormode.cpp @@ -300,6 +300,7 @@ editor_mode::on_mouse_button( int const Button, int const Action, int const Mods if (!cloned) return; + cloned->mark_dirty(); cloned->location(Camera.Pos + GfxRenderer.Mouse_Position()); simulation::Instances.insert(cloned); simulation::Region->insert(cloned); diff --git a/sceneeditor.cpp b/sceneeditor.cpp index 99513935..6b730a83 100644 --- a/sceneeditor.cpp +++ b/sceneeditor.cpp @@ -40,6 +40,7 @@ basic_editor::translate( scene::basic_node *Node, glm::dvec3 const &Location, bo // NOTE: bit of a waste for single nodes, for the sake of less varied code down the road auto const translation { targetlocation - initiallocation }; + Node->mark_dirty(); if( Node->group() == null_handle ) { translate_node( Node, Node->location() + translation ); } diff --git a/scenenode.h b/scenenode.h index ba5a38c0..18da3158 100644 --- a/scenenode.h +++ b/scenenode.h @@ -345,6 +345,10 @@ public: group( scene::group_handle Group ); scene::group_handle group() const; + void + mark_dirty() { m_dirty = true; } + bool + dirty() const { return m_dirty; } protected: // members @@ -354,6 +358,7 @@ protected: double m_rangesquaredmax { 0.0 }; // visibility range, max bool m_visible { true }; // visibility flag std::string m_name; + bool m_dirty { false }; private: // methods diff --git a/scenenodegroups.cpp b/scenenodegroups.cpp index 58031caf..f45c5ecb 100644 --- a/scenenodegroups.cpp +++ b/scenenodegroups.cpp @@ -119,24 +119,38 @@ node_groups::insert( scene::group_handle const Group, basic_event *Event ) { // sends basic content of the class in legacy (text) format to provided stream void -node_groups::export_as_text( std::ostream &Output ) const { +node_groups::export_as_text( std::ostream &Output, bool Dirty ) const { for( auto const &group : m_groupmap ) { - - Output << "group\n"; + bool any = false; for( auto *node : group.second.nodes ) { + if (node->dirty() != Dirty) + continue; // HACK: auto-generated memory cells aren't exported, so we check for this // TODO: is_exportable as basic_node method if( ( typeid( *node ) == typeid( TMemCell ) ) && ( false == static_cast( node )->is_exportable ) ) { continue; } + + if (!any) + Output << "group\n"; + any = true; + node->export_as_text( Output ); } for( auto *event : group.second.events ) { + if (Dirty) + continue; + + if (!any) + Output << "group\n"; + any = true; + event->export_as_text( Output ); } - Output << "endgroup\n"; + if (any) + Output << "endgroup\n"; } } diff --git a/scenenodegroups.h b/scenenodegroups.h index d0815bae..9f040409 100644 --- a/scenenodegroups.h +++ b/scenenodegroups.h @@ -48,7 +48,7 @@ public: return m_groupmap[ Group ]; } // sends basic content of the class in legacy (text) format to provided stream void - export_as_text( std::ostream &Output ) const; + export_as_text(std::ostream &Output , bool Dirty) const; private: // types diff --git a/simulationstateserializer.cpp b/simulationstateserializer.cpp index a601893c..7294ab27 100644 --- a/simulationstateserializer.cpp +++ b/simulationstateserializer.cpp @@ -952,7 +952,7 @@ state_serializer::transform( glm::dvec3 Location, scene::scratch_data const &Scr // stores class data in specified file, in legacy (text) format void -state_serializer::export_as_text( std::string const &Scenariofile ) const { +state_serializer::export_as_text(std::string const &Scenariofile) const { if( Scenariofile == "$.scn" ) { ErrorLog( "Bad file: scenery export not supported for file \"$.scn\"" ); @@ -961,66 +961,79 @@ state_serializer::export_as_text( std::string const &Scenariofile ) const { WriteLog( "Scenery data export in progress..." ); } - auto filename { Scenariofile }; - while( filename[ 0 ] == '$' ) { + auto filename { Scenariofile }; + while( filename[ 0 ] == '$' ) { // trim leading $ char rainsted utility may add to the base name for modified .scn files - filename.erase( 0, 1 ); + filename.erase( 0, 1 ); } - erase_extension( filename ); - filename = Global.asCurrentSceneryPath + filename + "_export"; + erase_extension( filename ); + auto absfilename = Global.asCurrentSceneryPath + filename + "_export"; - std::ofstream scmfile { filename + ".scm" }; - // groups - scmfile << "// groups\n"; - scene::Groups.export_as_text( scmfile ); - // tracks - scmfile << "// paths\n"; - for( auto const *path : Paths.sequence() ) { - if( path->group() == null_handle ) { - path->export_as_text( scmfile ); - } - } - // traction - scmfile << "// traction\n"; - for( auto const *traction : Traction.sequence() ) { - if( traction->group() == null_handle ) { - traction->export_as_text( scmfile ); - } - } - // power grid - scmfile << "// traction power sources\n"; - for( auto const *powersource : Powergrid.sequence() ) { - if( powersource->group() == null_handle ) { - powersource->export_as_text( scmfile ); - } - } - // models - scmfile << "// instanced models\n"; - for( auto const *instance : Instances.sequence() ) { - if( instance->group() == null_handle ) { - instance->export_as_text( scmfile ); - } - } - // sounds - // NOTE: sounds currently aren't included in groups - scmfile << "// sounds\n"; - Region->export_as_text( scmfile ); + std::ofstream scmdirtyfile { absfilename + "_dirty.scm" }; + export_nodes_to_stream(scmdirtyfile, true); - std::ofstream ctrfile { filename + ".ctr" }; - // mem cells - ctrfile << "// memory cells\n"; - for( auto const *memorycell : Memory.sequence() ) { - if( ( true == memorycell->is_exportable ) - && ( memorycell->group() == null_handle ) ) { - memorycell->export_as_text( ctrfile ); - } - } - // events - Events.export_as_text( ctrfile ); + std::ofstream scmfile { absfilename + ".scm" }; + export_nodes_to_stream(scmfile, false); + + // sounds + // NOTE: sounds currently aren't included in groups + scmfile << "// sounds\n"; + Region->export_as_text( scmfile ); + + scmfile << "// modified objects\ninclude " << filename << "_export_dirty.scm\n"; + + std::ofstream ctrfile { absfilename + ".ctr" }; + // mem cells + ctrfile << "// memory cells\n"; + for( auto const *memorycell : Memory.sequence() ) { + if( ( true == memorycell->is_exportable ) + && ( memorycell->group() == null_handle ) ) { + memorycell->export_as_text( ctrfile ); + } + } + + // events + Events.export_as_text( ctrfile ); WriteLog( "Scenery data export done." ); } +void +state_serializer::export_nodes_to_stream(std::ostream &scmfile, bool Dirty) const { + // groups + scmfile << "// groups\n"; + scene::Groups.export_as_text( scmfile, Dirty ); + + // tracks + scmfile << "// paths\n"; + for( auto const *path : Paths.sequence() ) { + if( path->dirty() == Dirty && path->group() == null_handle ) { + path->export_as_text( scmfile ); + } + } + // traction + scmfile << "// traction\n"; + for( auto const *traction : Traction.sequence() ) { + if( traction->dirty() == Dirty && traction->group() == null_handle ) { + traction->export_as_text( scmfile ); + } + } + // power grid + scmfile << "// traction power sources\n"; + for( auto const *powersource : Powergrid.sequence() ) { + if( powersource->dirty() == Dirty && powersource->group() == null_handle ) { + powersource->export_as_text( scmfile ); + } + } + // models + scmfile << "// instanced models\n"; + for( auto const *instance : Instances.sequence() ) { + if( instance && instance->dirty() == Dirty && instance->group() == null_handle ) { + instance->export_as_text( scmfile ); + } + } +} + } // simulation //--------------------------------------------------------------------------- diff --git a/simulationstateserializer.h b/simulationstateserializer.h index 5a55bfe3..a73b858a 100644 --- a/simulationstateserializer.h +++ b/simulationstateserializer.h @@ -40,7 +40,7 @@ public: deserialize_continue(std::shared_ptr state); // stores class data in specified file, in legacy (text) format void - export_as_text( std::string const &Scenariofile ) const; + export_as_text(std::string const &Scenariofile) const; // temporary public for editor TAnimModel * deserialize_model( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata ); @@ -79,6 +79,7 @@ private: void skip_until( cParser &Input, std::string const &Token ); // transforms provided location by specifed rotation and offset glm::dvec3 transform( glm::dvec3 Location, scene::scratch_data const &Scratchpad ); + void export_nodes_to_stream(std::ostream &, bool Dirty) const; }; } // simulation