16
0
mirror of https://github.com/MaSzyna-EU07/maszyna.git synced 2026-07-17 23:39:18 +02:00

Merge branch 'nodecloner' into sim

This commit is contained in:
milek7
2019-03-15 01:18:07 +01:00
23 changed files with 396 additions and 157 deletions

View File

@@ -25,11 +25,10 @@ http://mozilla.org/MPL/2.0/.
#include "Logs.h"
#include "renderer.h"
TAnimContainer *TAnimModel::acAnimList = NULL;
std::list<std::weak_ptr<TAnimContainer>> TAnimModel::acAnimList;
TAnimContainer::TAnimContainer()
{
pNext = NULL;
vRotateAngles = Math3D::vector3(0.0f, 0.0f, 0.0f); // aktualne kąty obrotu
vDesiredAngles = Math3D::vector3(0.0f, 0.0f, 0.0f); // docelowe kąty obrotu
fRotateSpeed = 0.0;
@@ -39,15 +38,7 @@ TAnimContainer::TAnimContainer()
fAngleSpeed = 0.0;
pSubModel = NULL;
iAnim = 0; // położenie początkowe
mAnim = NULL; // nie ma macierzy obrotu dla submodelu
evDone = NULL; // powiadamianie o zakończeniu animacji
acAnimNext = NULL; // na razie jest poza listą
}
TAnimContainer::~TAnimContainer()
{
SafeDelete(pNext);
delete mAnim; // AnimContainer jest właścicielem takich macierzy
evDone = NULL; // powiadamianie o zakończeniu animacji
}
bool TAnimContainer::Init(TSubModel *pNewSubModel)
@@ -73,9 +64,8 @@ void TAnimContainer::SetRotateAnim( Math3D::vector3 vNewRotateAngles, double fNe
// wyświetlania
if (iAnim >= 0)
{ // jeśli nie jest jeszcze na liście animacyjnej
acAnimNext = TAnimModel::acAnimList; // pozostałe doklić sobie jako ogon
TAnimModel::acAnimList = this; // a wstawić się na początek
iAnim |= 0x80000000; // dodany do listy
TAnimModel::acAnimList.push_back(shared_from_this());
iAnim |= 0x80000000; // dodany do listy
}
}
}
@@ -96,8 +86,7 @@ void TAnimContainer::SetTranslateAnim( Math3D::vector3 vNewTranslate, double fNe
// wyświetlania
if (iAnim >= 0)
{ // jeśli nie jest jeszcze na liście animacyjnej
acAnimNext = TAnimModel::acAnimList; // pozostałe doklić sobie jako ogon
TAnimModel::acAnimList = this; // a wstawić się na początek
TAnimModel::acAnimList.push_back(shared_from_this());
iAnim |= 0x80000000; // dodany do listy
}
}
@@ -264,11 +253,6 @@ TAnimModel::TAnimModel( scene::node_data const &Nodedata ) : basic_node( Nodedat
m_lightopacities.fill( 1.f );
}
TAnimModel::~TAnimModel()
{
SafeDelete(pRoot);
}
bool TAnimModel::Init(std::string const &asName, std::string const &asReplacableTexture)
{
if( asReplacableTexture.substr( 0, 1 ) == "*" ) {
@@ -383,32 +367,32 @@ bool TAnimModel::Load(cParser *parser, bool ter)
return true;
}
TAnimContainer * TAnimModel::AddContainer(std::string const &Name)
std::shared_ptr<TAnimContainer> TAnimModel::AddContainer(std::string const &Name)
{ // dodanie sterowania submodelem dla egzemplarza
if (!pModel)
return NULL;
return nullptr;
TSubModel *tsb = pModel->GetFromName(Name);
if (tsb)
{
TAnimContainer *tmp = new TAnimContainer();
auto tmp = std::make_shared<TAnimContainer>();
tmp->Init(tsb);
tmp->pNext = pRoot;
pRoot = tmp;
return tmp;
m_animlist.push_back(tmp);
return tmp;
}
return NULL;
return nullptr;
}
TAnimContainer * TAnimModel::GetContainer(std::string const &Name)
std::shared_ptr<TAnimContainer> TAnimModel::GetContainer(std::string const &Name)
{ // szukanie/dodanie sterowania submodelem dla egzemplarza
if (true == Name.empty())
return pRoot; // pobranie pierwszego (dla obrotnicy)
TAnimContainer *pCurrent;
for (pCurrent = pRoot; pCurrent != NULL; pCurrent = pCurrent->pNext)
// if (pCurrent->GetName()==pName)
if (Name == pCurrent->NameGet())
return pCurrent;
return AddContainer(Name);
if (true == Name.empty())
return (!m_animlist.empty()) ? m_animlist.front() : nullptr; // pobranie pierwszego (dla obrotnicy)
for (auto entry : m_animlist) {
if (entry->NameGet() == Name)
return entry;
}
return AddContainer(Name);
}
// przeliczenie animacji - jednorazowo na klatkę
@@ -485,13 +469,13 @@ void TAnimModel::RaAnimate( unsigned int const Framestamp ) {
}
// Ra 2F1I: to by można pomijać dla modeli bez animacji, których jest większość
TAnimContainer *pCurrent;
for (pCurrent = pRoot; pCurrent != nullptr; pCurrent = pCurrent->pNext)
if (!pCurrent->evDone) // jeśli jest bez eventu
pCurrent->UpdateModel(); // przeliczenie animacji każdego submodelu
for (auto entry : m_animlist) {
if (!entry->evDone) // jeśli jest bez eventu
entry->UpdateModel(); // przeliczenie animacji każdego submodelu
}
m_framestamp = Framestamp;
};
}
void TAnimModel::RaPrepare()
{ // ustawia światła i animacje we wzorcu modelu przed renderowaniem egzemplarza
@@ -555,12 +539,10 @@ void TAnimModel::RaPrepare()
}
TSubModel::iInstance = reinterpret_cast<std::uintptr_t>( this ); //żeby nie robić cudzych animacji
TSubModel::pasText = &asText; // przekazanie tekstu do wyświetlacza (!!!! do przemyślenia)
TAnimContainer *pCurrent;
for (pCurrent = pRoot; pCurrent != NULL; pCurrent = pCurrent->pNext)
pCurrent->PrepareModel(); // ustawienie animacji egzemplarza dla każdego submodelu
// if () //tylko dla modeli z IK !!!!
// for (pCurrent=pRoot;pCurrent!=NULL;pCurrent=pCurrent->pNext) //albo osobny łańcuch
// pCurrent->UpdateModelIK(); //przeliczenie odwrotnej kinematyki
for (auto entry : m_animlist) {
entry->PrepareModel();
}
}
int TAnimModel::Flags()
@@ -569,18 +551,19 @@ int TAnimModel::Flags()
if( m_materialdata.replacable_skins[ 1 ] > 0 ) // jeśli ma wymienną teksturę 0
i |= (i & 0x01010001) * ((m_materialdata.textures_alpha & 1) ? 0x20 : 0x10);
return i;
};
}
//---------------------------------------------------------------------------
int TAnimModel::TerrainCount()
{ // zliczanie kwadratów kilometrowych (główna linia po Next) do tworznia tablicy
return pModel ? pModel->TerrainCount() : 0;
};
}
TSubModel * TAnimModel::TerrainSquare(int n)
{ // pobieranie wskaźników do pierwszego submodelu
return pModel ? pModel->TerrainSquare(n) : 0;
};
}
//---------------------------------------------------------------------------
void TAnimModel::LightSet(int const n, float const v)
@@ -589,7 +572,7 @@ void TAnimModel::LightSet(int const n, float const v)
return; // przekroczony zakres
}
lsLights[ n ] = v;
};
}
std::optional<std::tuple<float, float, std::optional<glm::vec3>> > TAnimModel::LightGet(const int n)
{
@@ -611,13 +594,16 @@ std::optional<std::tuple<float, float, std::optional<glm::vec3>> > TAnimModel::L
void TAnimModel::AnimUpdate(double dt)
{ // wykonanie zakolejkowanych animacji, nawet gdy modele nie są aktualnie wyświetlane
TAnimContainer *p = TAnimModel::acAnimList;
while( p ) {
acAnimList.remove_if([](std::weak_ptr<TAnimContainer> ptr)
{
std::shared_ptr<TAnimContainer> container = ptr.lock();
if (!container)
return true;
p->UpdateModel();
p = p->acAnimNext; // na razie bez usuwania z listy, bo głównie obrotnica na nią wchodzi
}
};
container->UpdateModel(); // na razie bez usuwania z listy, bo głównie obrotnica na nią wchodzi
return false;
});
}
// radius() subclass details, calculates node's bounding radius
float

View File

@@ -45,7 +45,7 @@ class TAnimVocaloidFrame
class basic_event;
class TAnimContainer
class TAnimContainer : std::enable_shared_from_this<TAnimContainer>
{ // opakowanie submodelu, określające animację egzemplarza - obsługiwane jako lista
friend TAnimModel;
@@ -62,7 +62,7 @@ class TAnimContainer
float fAngleCurrent; // parametr interpolacyjny: 0=start, 1=docelowy
float fAngleSpeed; // zmiana parametru interpolacji w sekundach
TSubModel *pSubModel;
float4x4 *mAnim; // macierz do animacji kwaternionowych
std::shared_ptr<float4x4> mAnim; // macierz do animacji kwaternionowych
// dla kinematyki odwróconej używane są kwaterniony
float fLength; // długość kości dla IK
int iAnim; // animacja: +1-obrót Eulera, +2-przesuw, +4-obrót kwaternionem, +8-IK
@@ -71,11 +71,8 @@ class TAnimContainer
//+0x200: drugi stopień IK - dostosować do pozycji potomnego potomnego (wnuka)
basic_event *evDone; // ewent wykonywany po zakończeniu animacji, np. zapór, obrotnicy
public:
TAnimContainer *pNext;
TAnimContainer *acAnimNext; // lista animacji z eventem, które muszą być przeliczane również bez
// wyświetlania
TAnimContainer();
~TAnimContainer();
TAnimContainer();
bool Init(TSubModel *pNewSubModel);
inline
std::string NameGet() {
@@ -112,14 +109,12 @@ class TAnimModel : public scene::basic_node {
public:
// constructors
explicit TAnimModel( scene::node_data const &Nodedata );
// destructor
~TAnimModel();
// methods
static void AnimUpdate( double dt );
bool Init(std::string const &asName, std::string const &asReplacableTexture);
bool Load(cParser *parser, bool ter = false);
TAnimContainer * AddContainer(std::string const &Name);
TAnimContainer * GetContainer(std::string const &Name = "");
std::shared_ptr<TAnimContainer> AddContainer(std::string const &Name);
std::shared_ptr<TAnimContainer> GetContainer(std::string const &Name = "");
void LightSet( int const n, float const v );
std::optional<std::tuple<float, float, std::optional<glm::vec3> > > LightGet( int const n );
int TerrainCount();
@@ -142,7 +137,10 @@ public:
Angles() const {
return vAngle; }
// members
static TAnimContainer *acAnimList; // lista animacji z eventem, które muszą być przeliczane również bez wyświetlania
std::list<std::shared_ptr<TAnimContainer>> m_animlist;
// lista animacji z eventem, które muszą być przeliczane również bez wyświetlania
static std::list<std::weak_ptr<TAnimContainer>> acAnimList;
private:
// methods
@@ -159,7 +157,7 @@ private:
void export_as_text_( std::ostream &Output ) const;
// members
TAnimContainer *pRoot { nullptr }; // pojemniki sterujące, tylko dla aniomowanych submodeli
std::shared_ptr<TAnimContainer> pRoot; // pojemniki sterujące, tylko dla aniomowanych submodeli
TModel3d *pModel { nullptr };
glm::vec3 vAngle; // bazowe obroty egzemplarza względem osi
material_data m_materialdata;

View File

@@ -1291,8 +1291,8 @@ animation_event::init() {
for( auto &target : m_targets ) {
auto *targetmodel { static_cast<TAnimModel *>( std::get<scene::basic_node *>( target ) ) };
if( targetmodel == nullptr ) { continue; }
auto *targetcontainer{ targetmodel->GetContainer( m_animationsubmodel ) };
if( targetcontainer == nullptr ) {
auto targetcontainer{ targetmodel->GetContainer( m_animationsubmodel ) };
if( !targetcontainer ) {
m_ignored = true;
ErrorLog( "Bad event: \"" + m_name + "\" (type: " + type() + ") can't find submodel " + m_animationsubmodel + " in model instance \"" + targetmodel->name() + "\"" );
break;
@@ -1399,7 +1399,12 @@ animation_event::run_() {
WriteLog( "Type: Animation" );
// animation modes target specific submodels
for( auto *targetcontainer : m_animationcontainers ) {
m_animationcontainers.remove_if([this](std::weak_ptr<TAnimContainer> ptr)
{
auto targetcontainer = ptr.lock();
if (!targetcontainer)
return true;
switch( m_animationtype ) {
case 1: { // rotate
targetcontainer->SetRotateAnim(
@@ -1418,7 +1423,8 @@ animation_event::run_() {
break;
}
}
}
return false;
});
}
// export_as_text() subclass details

View File

@@ -390,7 +390,7 @@ private:
int m_animationtype{ 0 };
std::array<double, 4> m_animationparams{ 0.0 };
std::string m_animationsubmodel;
std::vector<TAnimContainer *> m_animationcontainers;
std::list<std::weak_ptr<TAnimContainer>> m_animationcontainers;
std::string m_animationfilename;
std::size_t m_animationfilesize{ 0 };
char *m_animationfiledata{ nullptr };

View File

@@ -1060,8 +1060,8 @@ void TSubModel::RaAnimation(glm::mat4 &m, TAnimType a)
}
if (mAnimMatrix) // można by to dać np. do at_Translate
{
m *= glm::make_mat4(mAnimMatrix->e);
mAnimMatrix = NULL; // jak animator będzie potrzebował, to ustawi ponownie
m *= glm::make_mat4(mAnimMatrix.get()->e);
mAnimMatrix.reset(); // jak animator będzie potrzebował, to ustawi ponownie
}
};

View File

@@ -137,7 +137,7 @@ public: // chwilowo
float m_boundingradius { 0 };
std::uintptr_t iAnimOwner{ 0 }; // roboczy numer egzemplarza, który ustawił animację
TAnimType b_aAnim{ TAnimType::at_None }; // kody animacji oddzielnie, bo zerowane
float4x4 *mAnimMatrix{ nullptr }; // macierz do animacji kwaternionowych (należy do AnimContainer)
std::shared_ptr<float4x4> mAnimMatrix; // macierz do animacji kwaternionowych
TSubModel **smLetter{ nullptr }; // wskaźnik na tablicę submdeli do generoania tekstu (docelowo zapisać do E3D)
TSubModel *Parent{ nullptr }; // nadrzędny, np. do wymnażania macierzy
int iVisible { 1 }; // roboczy stan widoczności

11
Names.h
View File

@@ -69,6 +69,17 @@ public:
lookup->second :
-1 );
}
void purge (Type_ *Item)
{
for (auto it = m_items.begin(); it != m_items.end(); it++) {
if (*it == Item) {
delete *it;
*it = nullptr;
return;
}
}
}
// locates item with specified name. returns pointer to the item, or nullptr
Type_ *
find( std::string const &Name ) const {

View File

@@ -1101,7 +1101,7 @@ bool TTrack::InMovement()
if (!SwitchExtension->CurrentIndex)
return false; // 0=zablokowana się nie animuje
// trzeba każdorazowo porównywać z kątem modelu
TAnimContainer *ac = (
auto ac = (
SwitchExtension->pModel ?
SwitchExtension->pModel->GetContainer() :
nullptr );
@@ -1883,7 +1883,7 @@ TTrack * TTrack::RaAnimate()
SwitchExtension->CurrentIndex) // 0=zablokowana się nie animuje
{ // trzeba każdorazowo porównywać z kątem modelu
// //pobranie kąta z modelu
TAnimContainer *ac = (
auto ac = (
SwitchExtension->pModel ?
SwitchExtension->pModel->GetContainer() : // pobranie głównego submodelu
nullptr );

View File

@@ -19,6 +19,7 @@ http://mozilla.org/MPL/2.0/.
#include "Timer.h"
#include "Console.h"
#include "renderer.h"
#include "AnimModel.h"
bool
editor_mode::editormode_input::init() {
@@ -179,6 +180,22 @@ editor_mode::on_key( int const Key, int const Scancode, int const Action, int co
break;
}
case GLFW_KEY_DELETE: {
TAnimModel *model = dynamic_cast<TAnimModel*>(m_node);
if (!model)
break;
m_node = nullptr;
m_dragging = false;
Application.set_cursor( GLFW_CURSOR_NORMAL );
static_cast<editor_ui*>( m_userinterface.get() )->set_node(nullptr);
simulation::Region->erase(model);
simulation::Instances.purge(model);
break;
}
default: {
break;
}
@@ -229,19 +246,75 @@ editor_mode::on_mouse_button( int const Button, int const Action, int const Mods
if( Button == GLFW_MOUSE_BUTTON_LEFT ) {
if( Action == GLFW_PRESS ) {
// left button press
GfxRenderer.pick_node([this](scene::basic_node *node)
{
if (!m_dragging)
return;
m_node = node;
if( m_node )
Application.set_cursor( GLFW_CURSOR_DISABLED );
else
m_dragging = false;
dynamic_cast<editor_ui*>( m_userinterface.get() )->set_node( m_node );
});
m_dragging = true;
// left button press
auto const mode = static_cast<editor_ui*>( m_userinterface.get() )->mode();
m_node = nullptr;
GfxRenderer.pick_node([this, mode](scene::basic_node *node)
{
editor_ui *ui = static_cast<editor_ui*>( m_userinterface.get() );
if (mode == nodebank_panel::MODIFY) {
if (!m_dragging)
return;
m_node = node;
if( m_node )
Application.set_cursor( GLFW_CURSOR_DISABLED );
else
m_dragging = false;
ui->set_node( m_node );
}
else if (mode == nodebank_panel::COPY) {
if (node && typeid(*node) == typeid(TAnimModel)) {
std::string as_text;
node->export_as_text(as_text);
ui->add_node_template(as_text);
}
m_dragging = false;
}
else if (mode == nodebank_panel::ADD) {
const std::string *src = ui->get_active_node_template();
if (!src)
return;
cParser parser(*src);
parser.getTokens(); // "node"
parser.getTokens(2); // ranges
scene::node_data nodedata;
parser >> nodedata.range_max >> nodedata.range_min;
parser.getTokens(2); // name, type
nodedata.name = "editor_" + std::to_string(LocalRandom(0.0, 100000.0));
nodedata.type = "model";
scene::scratch_data scratch;
TAnimModel *cloned = simulation::State.deserialize_model(parser, scratch, nodedata);
if (!cloned)
return;
cloned->mark_dirty();
cloned->location(Camera.Pos + GfxRenderer.Mouse_Position());
simulation::Instances.insert(cloned);
simulation::Region->insert(cloned);
if (!m_dragging)
return;
m_node = cloned;
Application.set_cursor( GLFW_CURSOR_DISABLED );
ui->set_node( m_node );
}
});
m_dragging = true;
}
else {
// left button release

View File

@@ -18,6 +18,7 @@ editor_ui::editor_ui() {
clear_panels();
// bind the panels with ui object. maybe not the best place for this but, eh
push_back( &m_itempropertiespanel );
push_back( &m_nodebankpanel );
}
// potentially processes provided input key. returns: true if key was processed, false otherwise
@@ -54,3 +55,28 @@ editor_ui::set_node( scene::basic_node * Node ) {
m_node = Node;
}
nodebank_panel::edit_mode
editor_ui::mode() {
return m_nodebankpanel.mode;
}
void
editor_ui::add_node_template(const std::string &desc) {
m_nodebankpanel.add_template(desc);
}
const std::string *editor_ui::get_active_node_template() {
return m_nodebankpanel.get_active_template();
}
void editor_ui::render_menu_contents() {
ui_layer::render_menu_contents();
if (ImGui::BeginMenu(locale::strings[locale::string::ui_mode_windows].c_str()))
{
ImGui::MenuItem(m_nodebankpanel.title.c_str(), nullptr, &m_nodebankpanel.is_open);
ImGui::EndMenu();
}
}

View File

@@ -32,9 +32,19 @@ public:
update() override;
void
set_node( scene::basic_node * Node );
nodebank_panel::edit_mode
mode();
void
add_node_template(const std::string &desc);
const std::string *
get_active_node_template();
protected:
void render_menu_contents();
private:
// members
itemproperties_panel m_itempropertiespanel { "Node Properties", true };
nodebank_panel m_nodebankpanel;
scene::basic_node * m_node { nullptr }; // currently bound scene node, if any
};

View File

@@ -281,3 +281,50 @@ itemproperties_panel::render_group() {
return true;
}
nodebank_panel::nodebank_panel() : ui_panel("nodebank", true) {
size_min = { 100, 50 };
size_max = { 1000, 1000 };
title = "nodebank";
std::ifstream file;
file.open("nodebank.txt", std::ios_base::in | std::ios_base::binary);
std::string line;
while (std::getline(file, line))
if (line.size() > 2)
m_nodebank.push_back(std::make_unique<std::string>(line));
}
void
nodebank_panel::render_contents() {
ImGui::RadioButton("modify", (int*)&mode, MODIFY);
ImGui::RadioButton("clone", (int*)&mode, COPY);
ImGui::RadioButton("add", (int*)&mode, ADD);
ImGui::PushItemWidth(-1);
if (ImGui::ListBoxHeader("##nodebank", ImVec2(-1, -1)))
{
int i = 0;
for (auto const entry : m_nodebank) {
std::string label = *entry + "##" + std::to_string(i);
if (ImGui::Selectable(label.c_str(), entry == m_selectedtemplate))
m_selectedtemplate = entry;
i++;
}
ImGui::ListBoxFooter();
}
}
void nodebank_panel::add_template(const std::string &desc) {
std::ofstream file;
file.open("nodebank.txt", std::ios_base::out | std::ios_base::app | std::ios_base::binary);
file << desc;
m_nodebank.push_back(std::make_unique<std::string>(desc));
}
const std::string *nodebank_panel::get_active_template() {
return m_selectedtemplate.get();
}

View File

@@ -33,3 +33,23 @@ private:
std::string m_groupprefix;
std::vector<text_line> m_grouplines;
};
class nodebank_panel : public ui_panel {
std::vector<std::shared_ptr<std::string>> m_nodebank;
std::shared_ptr<std::string> m_selectedtemplate;
public:
enum edit_mode {
MODIFY,
COPY,
ADD
};
edit_mode mode = MODIFY;
nodebank_panel();
void render_contents() override;
void add_template(const std::string &desc);
const std::string* get_active_template();
};

View File

@@ -23,7 +23,16 @@ namespace scene {
void
basic_editor::translate( scene::basic_node *Node, glm::dvec3 const &Location, bool const Snaptoground ) {
auto const initiallocation { Node->location() };
auto &initiallocation { Node->location() };
// fixup NaNs
if (std::isnan(initiallocation.x))
initiallocation.x = Location.x;
if (std::isnan(initiallocation.y))
initiallocation.y = Location.y;
if (std::isnan(initiallocation.z))
initiallocation.z = Location.z;
auto targetlocation { Location };
if( false == Snaptoground ) {
targetlocation.y = initiallocation.y;
@@ -31,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 );
}

View File

@@ -743,7 +743,7 @@ basic_node::export_as_text( std::ostream &Output ) const {
<< ' ' << ( m_rangesquaredmax < std::numeric_limits<double>::max() ? std::sqrt( m_rangesquaredmax ) : -1 )
<< ' ' << std::sqrt( m_rangesquaredmin )
// name
<< ' ' << m_name << ' ';
<< ' ' << ((m_name.length() > 0) ? m_name : "none") << ' ';
// template method implementation
export_as_text_( Output );
}

View File

@@ -333,6 +333,8 @@ public:
location( glm::dvec3 const Location );
glm::dvec3 const &
location() const;
glm::dvec3 &
location();
float const &
radius();
void
@@ -343,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
@@ -352,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
@@ -383,6 +390,12 @@ basic_node::location() const {
return m_area.center;
}
inline
glm::dvec3 &
basic_node::location() {
return m_area.center;
}
inline
void
basic_node::visible( bool const Visible ) {

View File

@@ -145,24 +145,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<TMemCell *>( 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";
}
}

View File

@@ -51,7 +51,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

View File

@@ -175,6 +175,11 @@ void state_manager::process_commands() {
}
}
TAnimModel *
state_manager::deserialize_model(cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata) {
return m_serializer.deserialize_model(Input, Scratchpad, Nodedata);
}
void
state_manager::update_clocks() {

View File

@@ -39,6 +39,10 @@ public:
void
process_commands();
// temporary for editor
TAnimModel *
deserialize_model(cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata);
private:
// members
state_serializer m_serializer;

View File

@@ -956,7 +956,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\"" );
@@ -965,66 +965,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
//---------------------------------------------------------------------------

View File

@@ -40,7 +40,10 @@ public:
deserialize_continue(std::shared_ptr<deserializer_state> 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 );
private:
// methods
@@ -56,7 +59,7 @@ private:
void deserialize_group( cParser &Input, scene::scratch_data &Scratchpad );
void deserialize_endgroup( cParser &Input, scene::scratch_data &Scratchpad );
void deserialize_light( cParser &Input, scene::scratch_data &Scratchpad );
void deserialize_node( cParser &Input, scene::scratch_data &Scratchpad );
void deserialize_node( cParser &Input, scene::scratch_data &Scratchpad );
void deserialize_origin( cParser &Input, scene::scratch_data &Scratchpad );
void deserialize_endorigin( cParser &Input, scene::scratch_data &Scratchpad );
void deserialize_rotate( cParser &Input, scene::scratch_data &Scratchpad );
@@ -70,7 +73,6 @@ private:
TTractionPowerSource * deserialize_tractionpowersource( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata );
TMemCell * deserialize_memorycell( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata );
TEventLauncher * deserialize_eventlauncher( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata );
TAnimModel * deserialize_model( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata );
TDynamicObject * deserialize_dynamic( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata );
sound_source * deserialize_sound( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata );
void init_time();
@@ -78,6 +80,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

View File

@@ -39,7 +39,7 @@ void ui_panel::render()
int flags = window_flags;
if (flags == -1)
flags = ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoCollapse |
((size.x > 0 || size_min.x > 0) ? ImGuiWindowFlags_NoResize : 0);
((size.x > 0) ? ImGuiWindowFlags_NoResize : 0);
if (size.x > 0)
ImGui::SetNextWindowSize(ImVec2(size.x, size.y));