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

Add brush mode in editor mode

This commit is contained in:
2026-01-03 18:02:15 +01:00
parent 1cafe15917
commit f9c95e2de0
10 changed files with 2319 additions and 2099 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -21,39 +21,38 @@ http://mozilla.org/MPL/2.0/.
#include "renderer.h" #include "renderer.h"
#include "AnimModel.h" #include "AnimModel.h"
bool bool editor_mode::editormode_input::init()
editor_mode::editormode_input::init() { {
return ( return (mouse.init() && keyboard.init());
mouse.init()
&& keyboard.init() );
} }
void void editor_mode::editormode_input::poll()
editor_mode::editormode_input::poll() { {
keyboard.poll(); keyboard.poll();
} }
editor_mode::editor_mode() { editor_mode::editor_mode()
{
m_userinterface = std::make_shared<editor_ui>(); m_userinterface = std::make_shared<editor_ui>();
} }
// initializes internal data structures of the mode. returns: true on success, false otherwise // initializes internal data structures of the mode. returns: true on success, false otherwise
bool bool editor_mode::init()
editor_mode::init() { {
Camera.Init( { 0, 15, 0 }, { glm::radians( -30.0 ), glm::radians( 180.0 ), 0 }, nullptr ); Camera.Init({0, 15, 0}, {glm::radians(-30.0), glm::radians(180.0), 0}, nullptr);
return m_input.init(); return m_input.init();
} }
// mode-specific update of simulation data. returns: false on error, true otherwise // mode-specific update of simulation data. returns: false on error, true otherwise
bool bool editor_mode::update()
editor_mode::update() { {
Timer::UpdateTimers( true ); Timer::UpdateTimers(true);
simulation::State.update_clocks(); simulation::State.update_clocks();
simulation::Environment.update(); simulation::Environment.update();
@@ -63,35 +62,100 @@ editor_mode::update() {
// fixed step render time routines: // fixed step render time routines:
fTime50Hz += deltarealtime; // w pauzie też trzeba zliczać czas, bo przy dużym FPS będzie problem z odczytem ramek fTime50Hz += deltarealtime; // w pauzie też trzeba zliczać czas, bo przy dużym FPS będzie problem z odczytem ramek
while( fTime50Hz >= 1.0 / 50.0 ) { while (fTime50Hz >= 1.0 / 50.0)
{
#ifdef _WIN32 #ifdef _WIN32
Console::Update(); // to i tak trzeba wywoływać Console::Update(); // to i tak trzeba wywoływać
#endif #endif
m_userinterface->update(); m_userinterface->update();
if (mouseHold)
{
auto const mode = static_cast<editor_ui *>(m_userinterface.get())->mode();
auto const rotation_mode = static_cast<editor_ui *>(m_userinterface.get())->rot_mode();
auto const fixed_rotation_value = static_cast<editor_ui *>(m_userinterface.get())->rot_val();
int Action = GLFW_REPEAT;
int Button = GLFW_MOUSE_BUTTON_LEFT;
{
GfxRenderer->Pick_Node_Callback(
[this, mode, rotation_mode, fixed_rotation_value, Action, Button](scene::basic_node *node)
{
editor_ui *ui = static_cast<editor_ui *>(m_userinterface.get());
if (mode == nodebank_panel::BRUSH)
{
const std::string *src = ui->get_active_node_template();
// std::string name = "editor_" + std::to_string(LocalRandom(0.0, 100000.0));
std::string name = "editor_" + generate_uuid_v4();
if (!src)
return;
glm::vec3 newPos = GfxRenderer->Mouse_Position();
float distance = glm::distance(newPos, oldPos);
if (distance < ui->getSpacing())
return;
TAnimModel *cloned = simulation::State.create_model(*src, name, Camera.Pos + newPos);
oldPos = newPos;
if (!cloned)
return;
// if (!m_dragging)
// return;
m_node = cloned;
if (rotation_mode == functions_panel::RANDOM)
{
auto const rotation{glm::vec3{0, LocalRandom(0.0, 360.0), 0}};
m_editor.rotate(m_node, rotation, 1);
}
else if (rotation_mode == functions_panel::FIXED)
{
auto const rotation{glm::vec3{0, fixed_rotation_value, 0}};
m_editor.rotate(m_node, rotation, 0);
}
// Application.set_cursor( GLFW_CURSOR_DISABLED );
ui->set_node(m_node);
}
});
}
}
// decelerate camera // decelerate camera
Camera.Velocity *= 0.65; Camera.Velocity *= 0.65;
if( std::abs( Camera.Velocity.x ) < 0.01 ) { Camera.Velocity.x = 0.0; } if (std::abs(Camera.Velocity.x) < 0.01)
if( std::abs( Camera.Velocity.y ) < 0.01 ) { Camera.Velocity.y = 0.0; } {
if( std::abs( Camera.Velocity.z ) < 0.01 ) { Camera.Velocity.z = 0.0; } Camera.Velocity.x = 0.0;
}
if (std::abs(Camera.Velocity.y) < 0.01)
{
Camera.Velocity.y = 0.0;
}
if (std::abs(Camera.Velocity.z) < 0.01)
{
Camera.Velocity.z = 0.0;
}
fTime50Hz -= 1.0 / 50.0; fTime50Hz -= 1.0 / 50.0;
} }
// variable step render time routines: // variable step render time routines:
update_camera( deltarealtime ); update_camera(deltarealtime);
simulation::Region->update_sounds(); simulation::Region->update_sounds();
audio::renderer.update( Global.iPause ? 0.0 : deltarealtime ); audio::renderer.update(Global.iPause ? 0.0 : deltarealtime);
GfxRenderer->Update( deltarealtime ); GfxRenderer->Update(deltarealtime);
simulation::is_ready = true; simulation::is_ready = true;
return true; return true;
} }
void void editor_mode::update_camera(double const Deltatime)
editor_mode::update_camera( double const Deltatime ) { {
// uwzględnienie ruchu wywołanego klawiszami // uwzględnienie ruchu wywołanego klawiszami
Camera.Update(); Camera.Update();
@@ -102,26 +166,21 @@ editor_mode::update_camera( double const Deltatime ) {
} }
// maintenance method, called when the mode is activated // maintenance method, called when the mode is activated
void void editor_mode::enter()
editor_mode::enter() { {
m_statebackup = { Global.pCamera, FreeFlyModeFlag, Global.ControlPicking }; m_statebackup = {Global.pCamera, FreeFlyModeFlag, Global.ControlPicking};
Camera = Global.pCamera; Camera = Global.pCamera;
// NOTE: camera placement is effectively a copy of drivermode DistantView( true ) // NOTE: camera placement is effectively a copy of drivermode DistantView( true )
// TBD, TODO: refactor into a common vehicle method? // TBD, TODO: refactor into a common vehicle method?
if( false == FreeFlyModeFlag ) { if (false == FreeFlyModeFlag)
{
auto const *vehicle { Camera.m_owner }; auto const *vehicle{Camera.m_owner};
auto const cab { auto const cab{(vehicle->MoverParameters->CabOccupied == 0 ? 1 : vehicle->MoverParameters->CabOccupied)};
( vehicle->MoverParameters->CabOccupied == 0 ? auto const left{vehicle->VectorLeft() * cab};
1 : Camera.Pos = Math3D::vector3(Camera.Pos.x, vehicle->GetPosition().y, Camera.Pos.z) + left * vehicle->GetWidth() + Math3D::vector3(1.25 * left.x, 1.6, 1.25 * left.z);
vehicle->MoverParameters->CabOccupied ) };
auto const left { vehicle->VectorLeft() * cab };
Camera.Pos =
Math3D::vector3( Camera.Pos.x, vehicle->GetPosition().y, Camera.Pos.z )
+ left * vehicle->GetWidth()
+ Math3D::vector3( 1.25 * left.x, 1.6, 1.25 * left.z );
Camera.m_owner = nullptr; Camera.m_owner = nullptr;
Camera.LookAt = vehicle->GetPosition(); Camera.LookAt = vehicle->GetPosition();
Camera.RaLook(); // jednorazowe przestawienie kamery Camera.RaLook(); // jednorazowe przestawienie kamery
@@ -130,30 +189,28 @@ editor_mode::enter() {
Global.ControlPicking = true; Global.ControlPicking = true;
EditorModeFlag = true; EditorModeFlag = true;
Application.set_cursor( GLFW_CURSOR_NORMAL ); Application.set_cursor(GLFW_CURSOR_NORMAL);
} }
// maintenance method, called when the mode is deactivated // maintenance method, called when the mode is deactivated
void void editor_mode::exit()
editor_mode::exit() { {
EditorModeFlag = false; EditorModeFlag = false;
Global.ControlPicking = m_statebackup.picking; Global.ControlPicking = m_statebackup.picking;
FreeFlyModeFlag = m_statebackup.freefly; FreeFlyModeFlag = m_statebackup.freefly;
Global.pCamera = m_statebackup.camera; Global.pCamera = m_statebackup.camera;
Application.set_cursor( Application.set_cursor((Global.ControlPicking ? GLFW_CURSOR_NORMAL : GLFW_CURSOR_DISABLED));
( Global.ControlPicking ?
GLFW_CURSOR_NORMAL :
GLFW_CURSOR_DISABLED ) );
if( false == Global.ControlPicking ) { if (false == Global.ControlPicking)
Application.set_cursor_pos( 0, 0 ); {
Application.set_cursor_pos(0, 0);
} }
} }
void void editor_mode::on_key(int const Key, int const Scancode, int const Action, int const Mods)
editor_mode::on_key( int const Key, int const Scancode, int const Action, int const Mods ) { {
#ifndef __unix__ #ifndef __unix__
Global.shiftState = (Mods & GLFW_MOD_SHIFT) ? true : false; Global.shiftState = (Mods & GLFW_MOD_SHIFT) ? true : false;
Global.ctrlState = (Mods & GLFW_MOD_CONTROL) ? true : false; Global.ctrlState = (Mods & GLFW_MOD_CONTROL) ? true : false;
@@ -162,88 +219,115 @@ editor_mode::on_key( int const Key, int const Scancode, int const Action, int co
bool anyModifier = Mods & (GLFW_MOD_SHIFT | GLFW_MOD_CONTROL | GLFW_MOD_ALT); bool anyModifier = Mods & (GLFW_MOD_SHIFT | GLFW_MOD_CONTROL | GLFW_MOD_ALT);
// give the ui first shot at the input processing... // give the ui first shot at the input processing...
if( !anyModifier && true == m_userinterface->on_key( Key, Action ) ) { return; } if (!anyModifier && true == m_userinterface->on_key(Key, Action))
{
return;
}
// ...if the input is left untouched, pass it on // ...if the input is left untouched, pass it on
if( true == m_input.keyboard.key( Key, Action ) ) { return; } if (true == m_input.keyboard.key(Key, Action))
{
return;
}
if( Action == GLFW_RELEASE ) { return; } if (Action == GLFW_RELEASE)
{
return;
}
// legacy hardcoded keyboard commands // legacy hardcoded keyboard commands
// TODO: replace with current command system, move to input object(s) // TODO: replace with current command system, move to input object(s)
switch( Key ) { switch (Key)
{
case GLFW_KEY_F11: { case GLFW_KEY_F11:
{
if( Action != GLFW_PRESS ) { break; } if (Action != GLFW_PRESS)
{
break;
}
// mode switch // mode switch
// TODO: unsaved changes warning // TODO: unsaved changes warning
if( ( false == Global.ctrlState ) if ((false == Global.ctrlState) && (false == Global.shiftState))
&& ( false == Global.shiftState ) ) { {
Application.pop_mode(); Application.pop_mode();
} }
// scenery export // scenery export
if( Global.ctrlState if (Global.ctrlState && Global.shiftState)
&& Global.shiftState ) { {
simulation::State.export_as_text( Global.SceneryFile ); simulation::State.export_as_text(Global.SceneryFile);
} }
break; break;
} }
case GLFW_KEY_F12: { case GLFW_KEY_F12:
{
// quick debug mode toggle // quick debug mode toggle
if( Global.ctrlState if (Global.ctrlState && Global.shiftState)
&& Global.shiftState ) { {
DebugModeFlag = !DebugModeFlag; DebugModeFlag = !DebugModeFlag;
} }
break; break;
} }
// TODO: ensure delete method can play nice with history stack // TODO: ensure delete method can play nice with history stack
case GLFW_KEY_DELETE: { case GLFW_KEY_DELETE:
TAnimModel *model = dynamic_cast<TAnimModel*>(m_node); {
TAnimModel *model = dynamic_cast<TAnimModel *>(m_node);
if (!model) if (!model)
break; break;
m_node = nullptr; m_node = nullptr;
m_dragging = false; m_dragging = false;
//Application.set_cursor( GLFW_CURSOR_NORMAL ); // Application.set_cursor( GLFW_CURSOR_NORMAL );
static_cast<editor_ui*>( m_userinterface.get() )->set_node(nullptr); static_cast<editor_ui *>(m_userinterface.get())->set_node(nullptr);
simulation::State.delete_model(model); simulation::State.delete_model(model);
break; break;
} }
default: { default:
{
break; break;
} }
} }
} }
void void editor_mode::on_cursor_pos(double const Horizontal, double const Vertical)
editor_mode::on_cursor_pos( double const Horizontal, double const Vertical ) { {
auto const mousemove { glm::dvec2{ Horizontal, Vertical } - m_input.mouse.position() }; auto const mousemove{glm::dvec2{Horizontal, Vertical} - m_input.mouse.position()};
m_input.mouse.position( Horizontal, Vertical ); m_input.mouse.position(Horizontal, Vertical);
if( m_input.mouse.button( GLFW_MOUSE_BUTTON_LEFT ) == GLFW_RELEASE ) { return; } if (m_input.mouse.button(GLFW_MOUSE_BUTTON_LEFT) == GLFW_RELEASE)
if( m_node == nullptr ) { return; } {
return;
}
if (m_node == nullptr)
{
return;
}
if( m_takesnapshot ) { if (m_takesnapshot)
{
// take a snapshot of selected node(s) // take a snapshot of selected node(s)
// TODO: implement this // TODO: implement this
m_takesnapshot = false; m_takesnapshot = false;
} }
if( mode_translation() ) { if (mode_translation())
{
// move selected node // move selected node
if( mode_translation_vertical() ) { if (mode_translation_vertical())
auto const translation { mousemove.y * -0.01f }; {
m_editor.translate( m_node, translation ); auto const translation{mousemove.y * -0.01f};
m_editor.translate(m_node, translation);
} }
else { else
auto const mouseworldposition { Camera.Pos + GfxRenderer->Mouse_Position() }; {
m_editor.translate( m_node, mouseworldposition, mode_snap() ); auto const mouseworldposition{Camera.Pos + GfxRenderer->Mouse_Position()};
m_editor.translate(m_node, mouseworldposition, mode_snap());
} }
} }
else if (mode_rotationY()) else if (mode_rotationY())
@@ -307,40 +391,47 @@ editor_mode::on_mouse_button( int const Button, int const Action, int const Mods
m_input.mouse.button( Button, Action ); m_input.mouse.button( Button, Action );
} }
*/ */
void void editor_mode::on_mouse_button(int const Button, int const Action, int const Mods)
editor_mode::on_mouse_button( int const Button, int const Action, int const Mods ) { {
// give the ui first shot at the input processing... // give the ui first shot at the input processing...
if( true == m_userinterface->on_mouse_button( Button, Action ) ) { return; }
if( Button == GLFW_MOUSE_BUTTON_LEFT ) { if (Button == GLFW_MOUSE_BUTTON_LEFT)
{
auto const mode = static_cast<editor_ui *>(m_userinterface.get())->mode();
auto const rotation_mode = static_cast<editor_ui *>(m_userinterface.get())->rot_mode();
auto const fixed_rotation_value = static_cast<editor_ui *>(m_userinterface.get())->rot_val();
if( Action == GLFW_PRESS ) { if (true == m_userinterface->on_mouse_button(Button, Action))
{
return;
}
if (Action == GLFW_PRESS)
{
// left button press // left button press
auto const mode = static_cast<editor_ui*>( m_userinterface.get() )->mode(); mouseHold = true;
auto const rotation_mode = static_cast<editor_ui*>( m_userinterface.get() )->rot_mode();
auto const fixed_rotation_value =
static_cast<editor_ui *>(m_userinterface.get())->rot_val();
m_node = nullptr; m_node = nullptr;
GfxRenderer->Pick_Node_Callback([this, mode, rotation_mode, fixed_rotation_value, GfxRenderer->Pick_Node_Callback(
Action, Button](scene::basic_node *node) { [this, mode, rotation_mode, fixed_rotation_value, Action, Button](scene::basic_node *node)
{
editor_ui *ui = static_cast<editor_ui *>(m_userinterface.get()); editor_ui *ui = static_cast<editor_ui *>(m_userinterface.get());
if (mode == nodebank_panel::MODIFY)
if (mode == nodebank_panel::MODIFY) { {
if (!m_dragging) if (!m_dragging)
return; return;
m_node = node; m_node = node;
//if( m_node ) // if( m_node )
//Application.set_cursor( GLFW_CURSOR_DISABLED ); // Application.set_cursor( GLFW_CURSOR_DISABLED );
//else // else
//m_dragging = false; // m_dragging = false;
ui->set_node(m_node); ui->set_node(m_node);
} }
else if (mode == nodebank_panel::COPY) { else if (mode == nodebank_panel::COPY)
if (node && typeid(*node) == typeid(TAnimModel)) { {
if (node && typeid(*node) == typeid(TAnimModel))
{
std::string as_text; std::string as_text;
node->export_as_text(as_text); node->export_as_text(as_text);
@@ -349,9 +440,10 @@ editor_mode::on_mouse_button( int const Button, int const Action, int const Mods
m_dragging = false; m_dragging = false;
} }
else if (mode == nodebank_panel::ADD) { else if (mode == nodebank_panel::ADD)
{
const std::string *src = ui->get_active_node_template(); const std::string *src = ui->get_active_node_template();
std::string name = "editor_" + std::to_string(LocalRandom(0.0, 100000.0)); std::string name = "editor_" + generate_uuid_v4();
if (!src) if (!src)
return; return;
@@ -364,7 +456,6 @@ editor_mode::on_mouse_button( int const Button, int const Action, int const Mods
if (!m_dragging) if (!m_dragging)
return; return;
m_node = cloned; m_node = cloned;
if (rotation_mode == functions_panel::RANDOM) if (rotation_mode == functions_panel::RANDOM)
@@ -379,19 +470,22 @@ editor_mode::on_mouse_button( int const Button, int const Action, int const Mods
auto const rotation{glm::vec3{0, fixed_rotation_value, 0}}; auto const rotation{glm::vec3{0, fixed_rotation_value, 0}};
m_editor.rotate(m_node, rotation, 0); m_editor.rotate(m_node, rotation, 0);
} }
//Application.set_cursor( GLFW_CURSOR_DISABLED ); // Application.set_cursor( GLFW_CURSOR_DISABLED );
ui->set_node( m_node ); ui->set_node(m_node);
} }
}); });
m_dragging = true; m_dragging = true;
} }
else { else
{
if (Action == GLFW_RELEASE)
mouseHold = false;
// left button release // left button release
//if( m_node ) // if( m_node )
//Application.set_cursor( GLFW_CURSOR_NORMAL ); // Application.set_cursor( GLFW_CURSOR_NORMAL );
m_dragging = false; m_dragging = false;
// prime history stack for another snapshot // prime history stack for another snapshot
m_takesnapshot = true; m_takesnapshot = true;
@@ -437,31 +531,31 @@ editor_mode::on_mouse_button( int const Button, int const Action, int const Mods
}*/ }*/
} }
m_input.mouse.button( Button, Action ); m_input.mouse.button(Button, Action);
} }
void void editor_mode::on_event_poll()
editor_mode::on_event_poll() { {
m_input.poll(); m_input.poll();
} }
bool bool editor_mode::is_command_processor() const
editor_mode::is_command_processor() const { {
return false; return false;
} }
bool bool editor_mode::mode_translation() const
editor_mode::mode_translation() const { {
return ( false == Global.altState ); return (false == Global.altState);
} }
bool bool editor_mode::mode_translation_vertical() const
editor_mode::mode_translation_vertical() const { {
return ( true == Global.shiftState ); return (true == Global.shiftState);
} }
bool editor_mode::mode_rotationY() const bool editor_mode::mode_rotationY() const
@@ -480,8 +574,8 @@ bool editor_mode::mode_rotationZ() const
return ((true == Global.altState) && (true == Global.ctrlState) && (true == Global.shiftState)); return ((true == Global.altState) && (true == Global.ctrlState) && (true == Global.shiftState));
} }
bool bool editor_mode::mode_snap() const
editor_mode::mode_snap() const { {
return ((false == Global.altState) && (true == Global.ctrlState) && (false == Global.shiftState)); return ((false == Global.altState) && (true == Global.ctrlState) && (false == Global.shiftState));
} }

View File

@@ -16,12 +16,13 @@ http://mozilla.org/MPL/2.0/.
#include "sceneeditor.h" #include "sceneeditor.h"
#include "scenenode.h" #include "scenenode.h"
class editor_mode : public application_mode { class editor_mode : public application_mode
{
public: public:
// constructors // constructors
editor_mode(); editor_mode();
// methods // methods
// initializes internal data structures of the mode. returns: true on success, false otherwise // initializes internal data structures of the mode. returns: true on success, false otherwise
bool init() override; bool init() override;
// mode-specific update of simulation data. returns: false on error, true otherwise // mode-specific update of simulation data. returns: false on error, true otherwise
@@ -31,17 +32,24 @@ public:
// maintenance method, called when the mode is deactivated // maintenance method, called when the mode is deactivated
void exit() override; void exit() override;
// input handlers // input handlers
void on_key( int Key, int Scancode, int Action, int Mods ) override; void on_key(int Key, int Scancode, int Action, int Mods) override;
void on_cursor_pos( double Horizontal, double Vertical ) override; void on_cursor_pos(double Horizontal, double Vertical) override;
void on_mouse_button( int Button, int Action, int Mods ) override; void on_mouse_button(int Button, int Action, int Mods) override;
void on_scroll( double const Xoffset, double const Yoffset ) override { ; } void on_scroll(double const Xoffset, double const Yoffset) override
void on_window_resize( int w, int h ) override { ; } {
;
}
void on_window_resize(int w, int h) override
{
;
}
void on_event_poll() override; void on_event_poll() override;
bool is_command_processor() const override; bool is_command_processor() const override;
private: private:
// types // types
struct editormode_input { struct editormode_input
{
editormouse_input mouse; editormouse_input mouse;
editorkeyboard_input keyboard; editorkeyboard_input keyboard;
@@ -50,34 +58,30 @@ private:
void poll(); void poll();
}; };
struct state_backup { struct state_backup
{
TCamera camera; TCamera camera;
bool freefly; bool freefly;
bool picking; bool picking;
}; };
// methods // methods
void void update_camera(double const Deltatime);
update_camera( double const Deltatime ); bool mode_translation() const;
bool bool mode_translation_vertical() const;
mode_translation() const; bool mode_rotationY() const;
bool bool mode_rotationX() const;
mode_translation_vertical() const; bool mode_rotationZ() const;
bool bool mode_snap() const;
mode_rotationY() const; // members
bool
mode_rotationX() const;
bool
mode_rotationZ() const;
bool
mode_snap() const;
// members
state_backup m_statebackup; // helper, cached variables to be restored on mode exit state_backup m_statebackup; // helper, cached variables to be restored on mode exit
editormode_input m_input; editormode_input m_input;
TCamera Camera; TCamera Camera;
double fTime50Hz { 0.0 }; // bufor czasu dla komunikacji z PoKeys double fTime50Hz{0.0}; // bufor czasu dla komunikacji z PoKeys
scene::basic_editor m_editor; scene::basic_editor m_editor;
scene::basic_node *m_node; // currently selected scene node scene::basic_node *m_node; // currently selected scene node
bool m_takesnapshot { true }; // helper, hints whether snapshot of selected node(s) should be taken before modification bool m_takesnapshot{true}; // helper, hints whether snapshot of selected node(s) should be taken before modification
bool m_dragging = false; bool m_dragging = false;
glm::vec3 oldPos;
bool mouseHold{false};
}; };

View File

@@ -14,64 +14,68 @@ http://mozilla.org/MPL/2.0/.
#include "scenenode.h" #include "scenenode.h"
#include "renderer.h" #include "renderer.h"
editor_ui::editor_ui() { editor_ui::editor_ui()
{
clear_panels(); clear_panels();
// bind the panels with ui object. maybe not the best place for this but, eh // bind the panels with ui object. maybe not the best place for this but, eh
add_external_panel( &m_itempropertiespanel ); add_external_panel(&m_itempropertiespanel);
add_external_panel( &m_nodebankpanel ); add_external_panel(&m_nodebankpanel);
add_external_panel( &m_functionspanel ); add_external_panel(&m_functionspanel);
} }
// updates state of UI elements // updates state of UI elements
void void editor_ui::update()
editor_ui::update() { {
set_tooltip( "" ); set_tooltip("");
if( Global.ControlPicking && DebugModeFlag ) { if (Global.ControlPicking && DebugModeFlag)
{
const auto sceneryNode = GfxRenderer->Pick_Node(); const auto sceneryNode = GfxRenderer->Pick_Node();
const std::string content = sceneryNode ? sceneryNode->tooltip() : ""; const std::string content = sceneryNode ? sceneryNode->tooltip() : "";
set_tooltip(content); set_tooltip(content);
} }
ui_layer::update(); ui_layer::update();
m_itempropertiespanel.update( m_node ); m_itempropertiespanel.update(m_node);
m_functionspanel.update( m_node ); m_functionspanel.update(m_node);
} }
void void editor_ui::set_node(scene::basic_node *Node)
editor_ui::set_node( scene::basic_node * Node ) { {
m_node = Node; m_node = Node;
} }
void void editor_ui::add_node_template(const std::string &desc)
editor_ui::add_node_template(const std::string &desc) { {
m_nodebankpanel.add_template(desc); m_nodebankpanel.add_template(desc);
} }
std::string const * std::string const *editor_ui::get_active_node_template()
editor_ui::get_active_node_template() { {
return m_nodebankpanel.get_active_template(); return m_nodebankpanel.get_active_template();
} }
nodebank_panel::edit_mode nodebank_panel::edit_mode editor_ui::mode()
editor_ui::mode() { {
return m_nodebankpanel.mode; return m_nodebankpanel.mode;
} }
float editor_ui::getSpacing()
{
return m_nodebankpanel.spacing;
}
functions_panel::rotation_mode functions_panel::rotation_mode editor_ui::rot_mode()
editor_ui::rot_mode() { {
return m_functionspanel.rot_mode; return m_functionspanel.rot_mode;
} }
float float editor_ui::rot_val()
editor_ui::rot_val() { {
return m_functionspanel.rot_value; return m_functionspanel.rot_value;
} }
bool bool editor_ui::rot_from_last()
editor_ui::rot_from_last()
{ {
return m_functionspanel.rot_from_last; return m_functionspanel.rot_from_last;
} }

View File

@@ -12,40 +12,35 @@ http://mozilla.org/MPL/2.0/.
#include "uilayer.h" #include "uilayer.h"
#include "editoruipanels.h" #include "editoruipanels.h"
namespace scene { namespace scene
{
class basic_node; class basic_node;
} }
class editor_ui : public ui_layer { class editor_ui : public ui_layer
{
public: public:
// constructors // constructors
editor_ui(); editor_ui();
// methods // methods
// updates state of UI elements // updates state of UI elements
void void update() override;
update() override; void set_node(scene::basic_node *Node);
void void add_node_template(const std::string &desc);
set_node( scene::basic_node * Node ); float rot_val();
void bool rot_from_last();
add_node_template(const std::string &desc); functions_panel::rotation_mode rot_mode();
float const std::string *get_active_node_template();
rot_val(); nodebank_panel::edit_mode mode();
bool float getSpacing();
rot_from_last();
functions_panel::rotation_mode
rot_mode();
const std::string *
get_active_node_template();
nodebank_panel::edit_mode
mode();
private: private:
// members // members
itemproperties_panel m_itempropertiespanel { "Node Properties", true }; itemproperties_panel m_itempropertiespanel{"Node Properties", true};
functions_panel m_functionspanel { "Functions", true }; functions_panel m_functionspanel{"Functions", true};
nodebank_panel m_nodebankpanel{ "Node Bank", true }; nodebank_panel m_nodebankpanel{"Node Bank", true};
scene::basic_node * m_node { nullptr }; // currently bound scene node, if any scene::basic_node *m_node{nullptr}; // currently bound scene node, if any
}; };

View File

@@ -17,14 +17,18 @@ http://mozilla.org/MPL/2.0/.
#include "Track.h" #include "Track.h"
#include "Event.h" #include "Event.h"
#include "MemCell.h" #include "MemCell.h"
#include "editoruilayer.h"
#include "renderer.h" #include "renderer.h"
#include "utilities.h" #include "utilities.h"
void void itemproperties_panel::update(scene::basic_node const *Node)
itemproperties_panel::update( scene::basic_node const *Node ) { {
m_node = Node; m_node = Node;
if( false == is_open ) { return; } if (false == is_open)
{
return;
}
text_lines.clear(); text_lines.clear();
m_grouplines.clear(); m_grouplines.clear();
@@ -32,16 +36,17 @@ itemproperties_panel::update( scene::basic_node const *Node ) {
std::string textline; std::string textline;
// scenario inspector // scenario inspector
auto const *node { Node }; auto const *node{Node};
auto const &camera { Global.pCamera }; auto const &camera{Global.pCamera};
if( node == nullptr ) { if (node == nullptr)
auto const mouseposition { camera.Pos + GfxRenderer->Mouse_Position() }; {
textline = "mouse location: [" + to_string( mouseposition.x, 2 ) + ", " + to_string( mouseposition.y, 2 ) + ", " + to_string( mouseposition.z, 2 ) + "]"; auto const mouseposition{camera.Pos + GfxRenderer->Mouse_Position()};
text_lines.emplace_back( textline, Global.UITextColor ); textline = "mouse location: [" + to_string(mouseposition.x, 2) + ", " + to_string(mouseposition.y, 2) + ", " + to_string(mouseposition.z, 2) + "]";
text_lines.emplace_back(textline, Global.UITextColor);
return; return;
} }
/* /*
// TODO: bind receiver in the constructor // TODO: bind receiver in the constructor
if( ( m_itemproperties != nullptr ) if( ( m_itemproperties != nullptr )
&& ( m_itemproperties->node != nullptr ) ) { && ( m_itemproperties->node != nullptr ) ) {
@@ -55,236 +60,236 @@ itemproperties_panel::update( scene::basic_node const *Node ) {
m_itemproperties->location.first = node->location(); m_itemproperties->location.first = node->location();
} }
} }
*/ */
textline = textline = "name: " + (node->name().empty() ? "(none)" : Bezogonkow(node->name())) + "\nlocation: [" + to_string(node->location().x, 2) + ", " + to_string(node->location().y, 2) + ", " +
"name: " + ( node->name().empty() ? "(none)" : Bezogonkow( node->name() ) ) to_string(node->location().z, 2) + "]" +
+ "\nlocation: [" + to_string( node->location().x, 2 ) + ", " + to_string( node->location().y, 2 ) + ", " + to_string( node->location().z, 2 ) + "]" " (distance: " + to_string(glm::length(glm::dvec3{node->location().x, 0.0, node->location().z} - glm::dvec3{camera.Pos.x, 0.0, camera.Pos.z}), 1) + " m)";
+ " (distance: " + to_string( glm::length( glm::dvec3{ node->location().x, 0.0, node->location().z } -glm::dvec3{ camera.Pos.x, 0.0, camera.Pos.z } ), 1 ) + " m)"; text_lines.emplace_back(textline, Global.UITextColor);
text_lines.emplace_back( textline, Global.UITextColor );
// subclass-specific data // subclass-specific data
// TBD, TODO: specialized data dump method in each node subclass, or data imports in the panel for provided subclass pointer? // TBD, TODO: specialized data dump method in each node subclass, or data imports in the panel for provided subclass pointer?
if( typeid( *node ) == typeid( TAnimModel ) ) { if (typeid(*node) == typeid(TAnimModel))
{
auto const *subnode = static_cast<TAnimModel const *>( node ); auto const *subnode = static_cast<TAnimModel const *>(node);
textline = "angle_x: " + to_string(clamp_circular(subnode->vAngle.x, 360.f), 2) + " deg, " + textline = "angle_x: " + to_string(clamp_circular(subnode->vAngle.x, 360.f), 2) + " deg, " + "angle_y: " + to_string(clamp_circular(subnode->vAngle.y, 360.f), 2) + " deg, " +
"angle_y: " + to_string(clamp_circular(subnode->vAngle.y, 360.f), 2) + " deg, " +
"angle_z: " + to_string(clamp_circular(subnode->vAngle.z, 360.f), 2) + " deg"; "angle_z: " + to_string(clamp_circular(subnode->vAngle.z, 360.f), 2) + " deg";
textline += ";\nlights: "; textline += ";\nlights: ";
if( subnode->iNumLights > 0 ) { if (subnode->iNumLights > 0)
{
textline += '['; textline += '[';
for( int lightidx = 0; lightidx < subnode->iNumLights; ++lightidx ) { for (int lightidx = 0; lightidx < subnode->iNumLights; ++lightidx)
textline += to_string( subnode->lsLights[ lightidx ] ); {
if( lightidx < subnode->iNumLights - 1 ) { textline += to_string(subnode->lsLights[lightidx]);
if (lightidx < subnode->iNumLights - 1)
{
textline += ", "; textline += ", ";
} }
} }
textline += ']'; textline += ']';
} }
else { else
{
textline += "(none)"; textline += "(none)";
} }
text_lines.emplace_back( textline, Global.UITextColor ); text_lines.emplace_back(textline, Global.UITextColor);
// 3d shape // 3d shape
auto modelfile { ( auto modelfile{((subnode->pModel != nullptr) ? subnode->pModel->NameGet() : "(none)")};
( subnode->pModel != nullptr ) ? if (modelfile.find(szModelPath) == 0)
subnode->pModel->NameGet() : {
"(none)" ) };
if( modelfile.find( szModelPath ) == 0 ) {
// don't include 'models/' in the path // don't include 'models/' in the path
modelfile.erase( 0, std::string{ szModelPath }.size() ); modelfile.erase(0, std::string{szModelPath}.size());
} }
// texture // texture
auto texturefile { ( auto texturefile{((subnode->Material()->replacable_skins[1] != null_handle) ? GfxRenderer->Material(subnode->Material()->replacable_skins[1])->GetName() : "(none)")};
( subnode->Material()->replacable_skins[ 1 ] != null_handle ) ? if (texturefile.find(szTexturePath) == 0)
GfxRenderer->Material( subnode->Material()->replacable_skins[ 1 ] )->GetName() : {
"(none)" ) };
if( texturefile.find( szTexturePath ) == 0 ) {
// don't include 'textures/' in the path // don't include 'textures/' in the path
texturefile.erase( 0, std::string{ szTexturePath }.size() ); texturefile.erase(0, std::string{szTexturePath}.size());
} }
text_lines.emplace_back( "mesh: " + modelfile, Global.UITextColor ); text_lines.emplace_back("mesh: " + modelfile, Global.UITextColor);
text_lines.emplace_back( "skin: " + texturefile, Global.UITextColor ); text_lines.emplace_back("skin: " + texturefile, Global.UITextColor);
} }
else if( typeid( *node ) == typeid( TTrack ) ) { else if (typeid(*node) == typeid(TTrack))
{
auto const *subnode = static_cast<TTrack const *>( node ); auto const *subnode = static_cast<TTrack const *>(node);
std::string isolatedlist; std::string isolatedlist;
for (const TIsolated *iso : subnode->Isolated) { for (const TIsolated *iso : subnode->Isolated)
{
if (!isolatedlist.empty()) if (!isolatedlist.empty())
isolatedlist += ", "; isolatedlist += ", ";
isolatedlist += iso->asName; isolatedlist += iso->asName;
} }
// basic attributes // basic attributes
textline = textline = "isolated: " + (!isolatedlist.empty() ? isolatedlist : "(none)") + "\nvelocity: " + to_string(subnode->SwitchExtension ? subnode->SwitchExtension->fVelocity : subnode->fVelocity) +
"isolated: " + ( !isolatedlist.empty() ? isolatedlist : "(none)" ) "\nwidth: " + to_string(subnode->fTrackWidth) + " m" + "\nfriction: " + to_string(subnode->fFriction, 2) + "\nquality: " + to_string(subnode->iQualityFlag);
+ "\nvelocity: " + to_string( subnode->SwitchExtension ? subnode->SwitchExtension->fVelocity : subnode->fVelocity ) text_lines.emplace_back(textline, Global.UITextColor);
+ "\nwidth: " + to_string( subnode->fTrackWidth ) + " m"
+ "\nfriction: " + to_string( subnode->fFriction, 2 )
+ "\nquality: " + to_string( subnode->iQualityFlag );
text_lines.emplace_back( textline, Global.UITextColor );
// textures // textures
auto texturefile { ( auto texturefile{((subnode->m_material1 != null_handle) ? GfxRenderer->Material(subnode->m_material1)->GetName() : "(none)")};
( subnode->m_material1 != null_handle ) ? if (texturefile.find(szTexturePath) == 0)
GfxRenderer->Material( subnode->m_material1 )->GetName() : {
"(none)" ) }; texturefile.erase(0, std::string{szTexturePath}.size());
if( texturefile.find( szTexturePath ) == 0 ) {
texturefile.erase( 0, std::string{ szTexturePath }.size() );
} }
auto texturefile2{ ( auto texturefile2{((subnode->m_material2 != null_handle) ? GfxRenderer->Material(subnode->m_material2)->GetName() : "(none)")};
( subnode->m_material2 != null_handle ) ? if (texturefile2.find(szTexturePath) == 0)
GfxRenderer->Material( subnode->m_material2 )->GetName() : {
"(none)" ) }; texturefile2.erase(0, std::string{szTexturePath}.size());
if( texturefile2.find( szTexturePath ) == 0 ) {
texturefile2.erase( 0, std::string{ szTexturePath }.size() );
} }
textline = "skins:\n " + texturefile + "\n " + texturefile2; textline = "skins:\n " + texturefile + "\n " + texturefile2;
text_lines.emplace_back( textline, Global.UITextColor ); text_lines.emplace_back(textline, Global.UITextColor);
// paths // paths
textline = "paths: "; textline = "paths: ";
for( auto const &path : subnode->m_paths ) { for (auto const &path : subnode->m_paths)
textline += {
"\n [" textline += "\n [" + to_string(path.points[segment_data::point::start].x, 3) + ", " + to_string(path.points[segment_data::point::start].y, 3) + ", " +
+ to_string( path.points[ segment_data::point::start ].x, 3 ) + ", " to_string(path.points[segment_data::point::start].z, 3) + "]->" + " [" + to_string(path.points[segment_data::point::end].x, 3) + ", " +
+ to_string( path.points[ segment_data::point::start ].y, 3 ) + ", " to_string(path.points[segment_data::point::end].y, 3) + ", " + to_string(path.points[segment_data::point::end].z, 3) + "] ";
+ to_string( path.points[ segment_data::point::start ].z, 3 ) + "]->"
+ " ["
+ to_string( path.points[ segment_data::point::end ].x, 3 ) + ", "
+ to_string( path.points[ segment_data::point::end ].y, 3 ) + ", "
+ to_string( path.points[ segment_data::point::end ].z, 3 ) + "] ";
} }
text_lines.emplace_back( textline, Global.UITextColor ); text_lines.emplace_back(textline, Global.UITextColor);
// events // events
textline.clear(); textline.clear();
std::vector< std::pair< std::string, TTrack::event_sequence const * > > const eventsequences { std::vector<std::pair<std::string, TTrack::event_sequence const *>> const eventsequences{{"ev0", &subnode->m_events0}, {"ev0all", &subnode->m_events0all},
{ "ev0", &subnode->m_events0 }, { "ev0all", &subnode->m_events0all }, {"ev1", &subnode->m_events1}, {"ev1all", &subnode->m_events1all},
{ "ev1", &subnode->m_events1 }, { "ev1all", &subnode->m_events1all }, {"ev2", &subnode->m_events2}, {"ev2all", &subnode->m_events2all}};
{ "ev2", &subnode->m_events2 }, { "ev2all", &subnode->m_events2all } };
for( auto const &eventsequence : eventsequences ) { for (auto const &eventsequence : eventsequences)
{
if( eventsequence.second->empty() ) { continue; } if (eventsequence.second->empty())
{
continue;
}
textline += ( textline.empty() ? "" : "\n" ) + eventsequence.first + ": ["; textline += (textline.empty() ? "" : "\n") + eventsequence.first + ": [";
for( auto const &event : *( eventsequence.second ) ) { for (auto const &event : *(eventsequence.second))
if( textline.back() != '[' ) { {
if (textline.back() != '[')
{
textline += ", "; textline += ", ";
} }
textline += ( textline += (event.second != nullptr ? Bezogonkow(event.second->m_name) : event.first + " (missing)");
event.second != nullptr ?
Bezogonkow( event.second->m_name ) :
event.first + " (missing)" );
} }
textline += "] "; textline += "] ";
} }
text_lines.emplace_back( textline, Global.UITextColor ); text_lines.emplace_back(textline, Global.UITextColor);
} }
else if( typeid( *node ) == typeid( TMemCell ) ) { else if (typeid(*node) == typeid(TMemCell))
{
auto const *subnode = static_cast<TMemCell const *>( node ); auto const *subnode = static_cast<TMemCell const *>(node);
textline = textline = "data: [" + subnode->Text() + "]" + " [" + to_string(subnode->Value1(), 2) + "]" + " [" + to_string(subnode->Value2(), 2) + "]";
"data: [" + subnode->Text() + "]" text_lines.emplace_back(textline, Global.UITextColor);
+ " [" + to_string( subnode->Value1(), 2 ) + "]" textline = "track: " + (subnode->asTrackName.empty() ? "(none)" : Bezogonkow(subnode->asTrackName));
+ " [" + to_string( subnode->Value2(), 2 ) + "]"; text_lines.emplace_back(textline, Global.UITextColor);
text_lines.emplace_back( textline, Global.UITextColor );
textline = "track: " + ( subnode->asTrackName.empty() ? "(none)" : Bezogonkow( subnode->asTrackName ) );
text_lines.emplace_back( textline, Global.UITextColor );
} }
update_group(); update_group();
} }
void void itemproperties_panel::update_group()
itemproperties_panel::update_group() { {
auto const grouphandle { m_node->group() }; auto const grouphandle{m_node->group()};
if( grouphandle == null_handle ) { if (grouphandle == null_handle)
{
m_grouphandle = null_handle; m_grouphandle = null_handle;
m_groupprefix.clear(); m_groupprefix.clear();
return; return;
} }
auto const &nodegroup { scene::Groups.group( grouphandle ) }; auto const &nodegroup{scene::Groups.group(grouphandle)};
if( m_grouphandle != grouphandle ) { if (m_grouphandle != grouphandle)
{
// calculate group name from shared prefix of item names // calculate group name from shared prefix of item names
std::vector<std::reference_wrapper<std::string const>> names; std::vector<std::reference_wrapper<std::string const>> names;
// build list of custom item and event names // build list of custom item and event names
for( auto const *node : nodegroup.nodes ) { for (auto const *node : nodegroup.nodes)
auto const &name { node->name() }; {
if( name.empty() || name == "none" ) { continue; } auto const &name{node->name()};
names.emplace_back( name ); if (name.empty() || name == "none")
{
continue;
} }
for( auto const *event : nodegroup.events ) { names.emplace_back(name);
auto const &name { event->m_name }; }
if( name.empty() || name == "none" ) { continue; } for (auto const *event : nodegroup.events)
names.emplace_back( name ); {
auto const &name{event->m_name};
if (name.empty() || name == "none")
{
continue;
}
names.emplace_back(name);
} }
// find the common prefix // find the common prefix
if( names.size() > 1 ) { if (names.size() > 1)
{
m_groupprefix = names.front(); m_groupprefix = names.front();
for( auto const &name : names ) { for (auto const &name : names)
{
// NOTE: first calculation runs over two instances of the same name, but, eh // NOTE: first calculation runs over two instances of the same name, but, eh
auto const prefixlength{ len_common_prefix( m_groupprefix, name ) }; auto const prefixlength{len_common_prefix(m_groupprefix, name)};
if( prefixlength > 0 ) { if (prefixlength > 0)
m_groupprefix = m_groupprefix.substr( 0, prefixlength ); {
m_groupprefix = m_groupprefix.substr(0, prefixlength);
} }
else { else
{
m_groupprefix.clear(); m_groupprefix.clear();
break; break;
} }
} }
} }
else { else
{
// less than two names to compare means no prefix // less than two names to compare means no prefix
m_groupprefix.clear(); m_groupprefix.clear();
} }
m_grouphandle = grouphandle; m_grouphandle = grouphandle;
} }
m_grouplines.emplace_back( m_grouplines.emplace_back("nodes: " + to_string(static_cast<int>(nodegroup.nodes.size())) + "\nevents: " + to_string(static_cast<int>(nodegroup.events.size())), Global.UITextColor);
"nodes: " + to_string( static_cast<int>( nodegroup.nodes.size() ) ) m_grouplines.emplace_back("names prefix: " + (m_groupprefix.empty() ? "(none)" : m_groupprefix), Global.UITextColor);
+ "\nevents: " + to_string( static_cast<int>( nodegroup.events.size() ) ),
Global.UITextColor );
m_grouplines.emplace_back(
"names prefix: " + ( m_groupprefix.empty() ? "(none)" : m_groupprefix ),
Global.UITextColor );
} }
void itemproperties_panel::render()
{
void if (false == is_open)
itemproperties_panel::render() { {
return;
if( false == is_open ) { return; }
if( true == text_lines.empty() ) { return; }
auto flags =
ImGuiWindowFlags_NoFocusOnAppearing
| ImGuiWindowFlags_NoCollapse
| ( size.x > 0 ? ImGuiWindowFlags_NoResize : 0 );
if( size.x > 0 ) {
ImGui::SetNextWindowSize( ImVec2S( size.x, size.y ) );
} }
if( size_min.x > 0 ) { if (true == text_lines.empty())
ImGui::SetNextWindowSizeConstraints( ImVec2S( size_min.x, size_min.y ), ImVec2( size_max.x, size_max.y ) ); {
return;
} }
auto const panelname { (
title.empty() ? auto flags = ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoCollapse | (size.x > 0 ? ImGuiWindowFlags_NoResize : 0);
m_name :
title ) if (size.x > 0)
+ "###" + m_name }; {
if( true == ImGui::Begin( panelname.c_str(), nullptr, flags ) ) { ImGui::SetNextWindowSize(ImVec2S(size.x, size.y));
}
if (size_min.x > 0)
{
ImGui::SetNextWindowSizeConstraints(ImVec2S(size_min.x, size_min.y), ImVec2(size_max.x, size_max.y));
}
auto const panelname{(title.empty() ? m_name : title) + "###" + m_name};
if (true == ImGui::Begin(panelname.c_str(), nullptr, flags))
{
// header section // header section
for( auto const &line : text_lines ) { for (auto const &line : text_lines)
ImGui::TextColored( ImVec4( line.color.r, line.color.g, line.color.b, line.color.a ), line.data.c_str() ); {
ImGui::TextColored(ImVec4(line.color.r, line.color.g, line.color.b, line.color.a), line.data.c_str());
} }
// group section // group section
render_group(); render_group();
@@ -292,71 +297,66 @@ itemproperties_panel::render() {
ImGui::End(); ImGui::End();
} }
bool bool itemproperties_panel::render_group()
itemproperties_panel::render_group() { {
if( m_node == nullptr ) { return false; } if (m_node == nullptr)
if( m_grouplines.empty() ) { return false; } {
return false;
}
if (m_grouplines.empty())
{
return false;
}
if( false == ImGui::CollapsingHeader( "Parent Group" ) ) { return false; } if (false == ImGui::CollapsingHeader("Parent Group"))
{
return false;
}
for( auto const &line : m_grouplines ) { for (auto const &line : m_grouplines)
ImGui::TextColored( ImVec4( line.color.r, line.color.g, line.color.b, line.color.a ), line.data.c_str() ); {
ImGui::TextColored(ImVec4(line.color.r, line.color.g, line.color.b, line.color.a), line.data.c_str());
} }
return true; return true;
} }
nodebank_panel::nodebank_panel(std::string const &Name, bool const Isopen) : ui_panel(Name, Isopen)
{
size_min = {100, 50};
size_max = {1000, 1000};
memset(m_nodesearch, 0, sizeof(m_nodesearch));
nodebank_panel::nodebank_panel( std::string const &Name, bool const Isopen ) : ui_panel( Name, Isopen ) {
size_min = { 100, 50 };
size_max = { 1000, 1000 };
memset( m_nodesearch, 0, sizeof( m_nodesearch ) );
std::ifstream file; std::ifstream file;
file.open("nodebank.txt", std::ios_base::in | std::ios_base::binary); file.open("nodebank.txt", std::ios_base::in | std::ios_base::binary);
std::string line; std::string line;
while( std::getline( file, line ) ) { while (std::getline(file, line))
if( line.size() < 4 ) { {
if (line.size() < 4)
{
continue; continue;
} }
auto const labelend { line.find( "node" ) }; auto const labelend{line.find("node")};
auto const nodedata { ( auto const nodedata{(labelend == std::string::npos ? "" : labelend == 0 ? line : line.substr(labelend))};
labelend == std::string::npos ? "" : auto const label{(labelend == std::string::npos ? line : labelend == 0 ? generate_node_label(nodedata) : line.substr(0, labelend))};
labelend == 0 ? line :
line.substr( labelend ) ) };
auto const label { (
labelend == std::string::npos ? line :
labelend == 0 ? generate_node_label( nodedata ) :
line.substr( 0, labelend ) ) };
m_nodebank.push_back( { label, std::make_shared<std::string>( nodedata ) } ); m_nodebank.push_back({label, std::make_shared<std::string>(nodedata)});
} }
// sort alphabetically content of each group // sort alphabetically content of each group
auto groupbegin { m_nodebank.begin() }; auto groupbegin{m_nodebank.begin()};
auto groupend { groupbegin }; auto groupend{groupbegin};
while( groupbegin != m_nodebank.end() ) { while (groupbegin != m_nodebank.end())
groupbegin = {
std::find_if( groupbegin = std::find_if(groupend, m_nodebank.end(), [](auto const &Entry) { return (false == Entry.second->empty()); });
groupend, m_nodebank.end(), groupend = std::find_if(groupbegin, m_nodebank.end(), [](auto const &Entry) { return (Entry.second->empty()); });
[]( auto const &Entry ) { std::sort(groupbegin, groupend, [](auto const &Left, auto const &Right) { return (Left.first < Right.first); });
return ( false == Entry.second->empty() ); } );
groupend =
std::find_if(
groupbegin, m_nodebank.end(),
[]( auto const &Entry ) {
return ( Entry.second->empty() ); } );
std::sort(
groupbegin, groupend,
[]( auto const &Left, auto const &Right ) {
return ( Left.first < Right.first ); } );
} }
} }
void void nodebank_panel::nodebank_reload()
nodebank_panel::nodebank_reload(){ {
m_nodebank.clear(); m_nodebank.clear();
std::ifstream file; std::ifstream file;
file.open("nodebank.txt", std::ios_base::in | std::ios_base::binary); file.open("nodebank.txt", std::ios_base::in | std::ios_base::binary);
@@ -368,12 +368,8 @@ nodebank_panel::nodebank_reload(){
continue; continue;
} }
auto const labelend{line.find("node")}; auto const labelend{line.find("node")};
auto const nodedata{ auto const nodedata{(labelend == std::string::npos ? "" : labelend == 0 ? line : line.substr(labelend))};
(labelend == std::string::npos ? "" : labelend == 0 ? line : line.substr(labelend))}; auto const label{(labelend == std::string::npos ? line : labelend == 0 ? generate_node_label(nodedata) : line.substr(0, labelend))};
auto const label{
(labelend == std::string::npos ?
line :
labelend == 0 ? generate_node_label(nodedata) : line.substr(0, labelend))};
m_nodebank.push_back({label, std::make_shared<std::string>(nodedata)}); m_nodebank.push_back({label, std::make_shared<std::string>(nodedata)});
} }
@@ -382,74 +378,79 @@ nodebank_panel::nodebank_reload(){
auto groupend{groupbegin}; auto groupend{groupbegin};
while (groupbegin != m_nodebank.end()) while (groupbegin != m_nodebank.end())
{ {
groupbegin = std::find_if(groupend, m_nodebank.end(), [](auto const &Entry) { groupbegin = std::find_if(groupend, m_nodebank.end(), [](auto const &Entry) { return (false == Entry.second->empty()); });
return (false == Entry.second->empty()); groupend = std::find_if(groupbegin, m_nodebank.end(), [](auto const &Entry) { return (Entry.second->empty()); });
}); std::sort(groupbegin, groupend, [](auto const &Left, auto const &Right) { return (Left.first < Right.first); });
groupend = std::find_if(groupbegin, m_nodebank.end(),
[](auto const &Entry) { return (Entry.second->empty()); });
std::sort(groupbegin, groupend,
[](auto const &Left, auto const &Right) { return (Left.first < Right.first); });
} }
} }
void void nodebank_panel::render()
nodebank_panel::render() { {
if( false == is_open ) { return; } if (false == is_open)
{
auto flags = return;
ImGuiWindowFlags_NoFocusOnAppearing
| ImGuiWindowFlags_NoCollapse
| ( size.x > 0 ? ImGuiWindowFlags_NoResize : 0 );
if( size.x > 0 ) {
ImGui::SetNextWindowSize( ImVec2S( size.x, size.y ) );
} }
if( size_min.x > 0 ) {
ImGui::SetNextWindowSizeConstraints( ImVec2S( size_min.x, size_min.y ), ImVec2S( size_max.x, size_max.y ) ); auto flags = ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoCollapse | (size.x > 0 ? ImGuiWindowFlags_NoResize : 0);
if (size.x > 0)
{
ImGui::SetNextWindowSize(ImVec2S(size.x, size.y));
} }
auto const panelname { ( if (size_min.x > 0)
title.empty() ? {
name() : ImGui::SetNextWindowSizeConstraints(ImVec2S(size_min.x, size_min.y), ImVec2S(size_max.x, size_max.y));
title ) }
+ "###" + name() }; auto const panelname{(title.empty() ? name() : title) + "###" + name()};
if( true == ImGui::Begin( panelname.c_str(), nullptr, flags ) ) { if (true == ImGui::Begin(panelname.c_str(), nullptr, flags))
{
ImGui::RadioButton("Modify node", (int*)&mode, MODIFY); ImGui::RadioButton("Modify node", (int *)&mode, MODIFY);
ImGui::SameLine(); ImGui::SameLine();
ImGui::RadioButton("Insert from bank", (int*)&mode, ADD); ImGui::RadioButton("Insert from bank", (int *)&mode, ADD);
ImGui::SameLine(); ImGui::SameLine();
ImGui::RadioButton( "Copy to bank", (int*)&mode, COPY ); ImGui::RadioButton("Brush mode", (int *)&mode, BRUSH);
ImGui::SameLine();
ImGui::RadioButton("Copy to bank", (int *)&mode, COPY);
ImGui::SameLine(); ImGui::SameLine();
if (ImGui::Button("Reload Nodebank")) if (ImGui::Button("Reload Nodebank"))
{ {
nodebank_reload(); nodebank_reload();
} }
if (mode == BRUSH)
{
ImGui::SliderFloat("Spacing", &spacing, 0.1f, 20.0f, "%.1f m");
}
ImGui::PushItemWidth(-1); ImGui::PushItemWidth(-1);
ImGui::InputTextWithHint( "Search", "Search node bank", m_nodesearch, IM_ARRAYSIZE( m_nodesearch ) ); ImGui::InputTextWithHint("Search", "Search node bank", m_nodesearch, IM_ARRAYSIZE(m_nodesearch));
if (ImGui::ListBoxHeader("##nodebank", ImVec2(-1, -1))) if (ImGui::ListBoxHeader("##nodebank", ImVec2(-1, -1)))
{ {
auto idx { 0 }; auto idx{0};
auto isvisible { false }; auto isvisible{false};
auto const searchfilter { std::string( m_nodesearch ) }; auto const searchfilter{std::string(m_nodesearch)};
for (auto const &entry : m_nodebank) { for (auto const &entry : m_nodebank)
if( entry.second->empty() ) { {
if (entry.second->empty())
{
// special case, header indicator // special case, header indicator
isvisible = ImGui::CollapsingHeader( entry.first.c_str() ); isvisible = ImGui::CollapsingHeader(entry.first.c_str());
} }
else { else
if( false == isvisible ) { {
if (false == isvisible)
{
continue; continue;
} }
if( ( false == searchfilter.empty() ) if ((false == searchfilter.empty()) && (false == contains(entry.first, searchfilter)))
&& ( false == contains( entry.first, searchfilter ) ) ) { {
continue; continue;
} }
auto const label { " " + entry.first + "##" + std::to_string( idx ) }; auto const label{" " + entry.first + "##" + std::to_string(idx)};
if( ImGui::Selectable( label.c_str(), entry.second == m_selectedtemplate ) ) if (ImGui::Selectable(label.c_str(), entry.second == m_selectedtemplate))
m_selectedtemplate = entry.second; m_selectedtemplate = entry.second;
++idx; ++idx;
} }
@@ -461,35 +462,33 @@ nodebank_panel::render() {
ImGui::End(); ImGui::End();
} }
void void nodebank_panel::add_template(const std::string &desc)
nodebank_panel::add_template(const std::string &desc) { {
auto const label { generate_node_label( desc ) }; auto const label{generate_node_label(desc)};
m_nodebank.push_back( { label, std::make_shared<std::string>( desc ) } ); m_nodebank.push_back({label, std::make_shared<std::string>(desc)});
std::ofstream file; std::ofstream file;
file.open("nodebank.txt", std::ios_base::out | std::ios_base::app | std::ios_base::binary); file.open("nodebank.txt", std::ios_base::out | std::ios_base::app | std::ios_base::binary);
file << label << " " << desc; file << label << " " << desc;
} }
const std::string *nodebank_panel::get_active_template() { const std::string *nodebank_panel::get_active_template()
{
return m_selectedtemplate.get(); return m_selectedtemplate.get();
} }
std::string std::string nodebank_panel::generate_node_label(std::string Input) const
nodebank_panel::generate_node_label( std::string Input ) const { {
auto tokenizer{ cParser( Input ) }; auto tokenizer{cParser(Input)};
tokenizer.getTokens( 9, false ); // skip leading tokens tokenizer.getTokens(9, false); // skip leading tokens
auto model{ tokenizer.getToken<std::string>( false ) }; auto model{tokenizer.getToken<std::string>(false)};
auto texture{ tokenizer.getToken<std::string>( false ) }; auto texture{tokenizer.getToken<std::string>(false)};
replace_slashes( model ); replace_slashes(model);
erase_extension( model ); erase_extension(model);
replace_slashes( texture ); replace_slashes(texture);
return ( return (texture == "none" ? model : model + " (" + texture + ")");
texture == "none" ?
model :
model + " (" + texture + ")" );
} }
void functions_panel::update(scene::basic_node const *Node) void functions_panel::update(scene::basic_node const *Node)
@@ -509,45 +508,42 @@ void functions_panel::update(scene::basic_node const *Node)
// scenario inspector // scenario inspector
auto const *node{Node}; auto const *node{Node};
auto const &camera{Global.pCamera}; auto const &camera{Global.pCamera};
} }
void void functions_panel::render()
functions_panel::render() { {
if( false == is_open ) { return; } if (false == is_open)
{
auto flags = return;
ImGuiWindowFlags_NoFocusOnAppearing
| ImGuiWindowFlags_NoCollapse
| ( size.x > 0 ? ImGuiWindowFlags_NoResize : 0 );
if( size.x > 0 ) {
ImGui::SetNextWindowSize( ImVec2S( size.x, size.y ) );
} }
if( size_min.x > 0 ) {
ImGui::SetNextWindowSizeConstraints( ImVec2S( size_min.x, size_min.y ), ImVec2( size_max.x, size_max.y ) ); auto flags = ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoCollapse | (size.x > 0 ? ImGuiWindowFlags_NoResize : 0);
if (size.x > 0)
{
ImGui::SetNextWindowSize(ImVec2S(size.x, size.y));
} }
auto const panelname { ( if (size_min.x > 0)
title.empty() ? {
m_name : ImGui::SetNextWindowSizeConstraints(ImVec2S(size_min.x, size_min.y), ImVec2(size_max.x, size_max.y));
title ) }
+ "###" + m_name }; auto const panelname{(title.empty() ? m_name : title) + "###" + m_name};
if( true == ImGui::Begin( panelname.c_str(), nullptr, flags ) ) { if (true == ImGui::Begin(panelname.c_str(), nullptr, flags))
{
// header section // header section
ImGui::RadioButton("Random rotation", (int *)&rot_mode, RANDOM); ImGui::RadioButton("Random rotation", (int *)&rot_mode, RANDOM);
ImGui::RadioButton("Fixed rotation", (int *)&rot_mode, FIXED); ImGui::RadioButton("Fixed rotation", (int *)&rot_mode, FIXED);
if(rot_mode == FIXED){ if (rot_mode == FIXED)
//ImGui::Checkbox("Get rotation from last object", &rot_from_last); {
// ImGui::Checkbox("Get rotation from last object", &rot_from_last);
ImGui::SliderFloat("Rotation Value", &rot_value, 0.0f, 360.0f, "%.1f"); ImGui::SliderFloat("Rotation Value", &rot_value, 0.0f, 360.0f, "%.1f");
}; };
ImGui::RadioButton("Default rotation", (int *)&rot_mode, DEFAULT); ImGui::RadioButton("Default rotation", (int *)&rot_mode, DEFAULT);
for( auto const &line : text_lines ) { for (auto const &line : text_lines)
ImGui::TextColored( ImVec4( line.color.r, line.color.g, line.color.b, line.color.a ), line.data.c_str() ); {
ImGui::TextColored(ImVec4(line.color.r, line.color.g, line.color.b, line.color.a), line.data.c_str());
} }
} }
ImGui::End(); ImGui::End();

View File

@@ -26,32 +26,33 @@ struct item_properties {
changeable<glm::vec3> rotation {}; changeable<glm::vec3> rotation {};
}; };
*/ */
class itemproperties_panel : public ui_panel { class itemproperties_panel : public ui_panel
{
public: public:
itemproperties_panel( std::string const &Name, bool const Isopen ) itemproperties_panel(std::string const &Name, bool const Isopen) : ui_panel(Name, Isopen) {}
: ui_panel( Name, Isopen )
{}
void update( scene::basic_node const *Node ); void update(scene::basic_node const *Node);
void render() override; void render() override;
private: private:
// methods // methods
void update_group(); void update_group();
bool render_group(); bool render_group();
// members // members
scene::basic_node const *m_node { nullptr }; // scene node bound to the panel scene::basic_node const *m_node{nullptr}; // scene node bound to the panel
scene::group_handle m_grouphandle { null_handle }; // scene group bound to the panel scene::group_handle m_grouphandle{null_handle}; // scene group bound to the panel
std::string m_groupprefix; std::string m_groupprefix;
std::vector<text_line> m_grouplines; std::vector<text_line> m_grouplines;
}; };
class nodebank_panel : public ui_panel { class nodebank_panel : public ui_panel
{
public: public:
enum edit_mode { enum edit_mode
{
MODIFY, MODIFY,
COPY, COPY,
ADD, ADD,
@@ -59,18 +60,20 @@ public:
}; };
edit_mode mode = MODIFY; edit_mode mode = MODIFY;
nodebank_panel( std::string const &Name, bool const Isopen ); float spacing{1.0f};
nodebank_panel(std::string const &Name, bool const Isopen);
void nodebank_reload(); void nodebank_reload();
void render() override; void render() override;
void add_template(const std::string &desc); void add_template(const std::string &desc);
const std::string* get_active_template(); const std::string *get_active_template();
private: private:
// methods: // methods:
std::string generate_node_label( std::string Input ) const; std::string generate_node_label(std::string Input) const;
// members: // members:
std::vector<std::pair<std::string, std::shared_ptr<std::string>>> m_nodebank; std::vector<std::pair<std::string, std::shared_ptr<std::string>>> m_nodebank;
char m_nodesearch[ 128 ]; char m_nodesearch[128];
std::shared_ptr<std::string> m_selectedtemplate; std::shared_ptr<std::string> m_selectedtemplate;
}; };
@@ -94,11 +97,9 @@ class functions_panel : public ui_panel
void update(scene::basic_node const *Node); void update(scene::basic_node const *Node);
void render() override; void render() override;
private: private:
// methods // methods
// members // members
scene::basic_node const *m_node{nullptr}; // scene node bound to the panel scene::basic_node const *m_node{nullptr}; // scene node bound to the panel
scene::group_handle m_grouphandle{null_handle}; // scene group bound to the panel scene::group_handle m_grouphandle{null_handle}; // scene group bound to the panel

View File

@@ -23,7 +23,7 @@ http://mozilla.org/MPL/2.0/.
GLFWwindow *ui_layer::m_window{nullptr}; GLFWwindow *ui_layer::m_window{nullptr};
ImGuiIO *ui_layer::m_imguiio{nullptr}; ImGuiIO *ui_layer::m_imguiio{nullptr};
GLint ui_layer::m_textureunit { GL_TEXTURE0 }; GLint ui_layer::m_textureunit{GL_TEXTURE0};
bool ui_layer::m_cursorvisible; bool ui_layer::m_cursorvisible;
ImFont *ui_layer::font_default{nullptr}; ImFont *ui_layer::font_default{nullptr};
ImFont *ui_layer::font_mono{nullptr}; ImFont *ui_layer::font_mono{nullptr};
@@ -55,13 +55,11 @@ void ui_panel::render()
ImGui::SetNextWindowSizeConstraints(ImVec2S(size_min.x, size_min.y), ImVec2S(size_max.x, size_max.y)); ImGui::SetNextWindowSizeConstraints(ImVec2S(size_min.x, size_min.y), ImVec2S(size_max.x, size_max.y));
auto const panelname{(title.empty() ? m_name : title) + "###" + m_name}; auto const panelname{(title.empty() ? m_name : title) + "###" + m_name};
if (ImGui::Begin(panelname.c_str(), &is_open, flags)) { if (ImGui::Begin(panelname.c_str(), &is_open, flags))
{
render_contents(); render_contents();
popups.remove_if([](const std::unique_ptr<ui::popup> &popup) popups.remove_if([](const std::unique_ptr<ui::popup> &popup) { return popup->render(); });
{
return popup->render();
});
} }
ImGui::End(); ImGui::End();
@@ -102,7 +100,7 @@ ui_layer::ui_layer()
{ {
if (Global.loading_log) if (Global.loading_log)
add_external_panel(&m_logpanel); add_external_panel(&m_logpanel);
m_logpanel.size = { 700, 400 }; m_logpanel.size = {700, 400};
} }
ui_layer::~ui_layer() {} ui_layer::~ui_layer() {}
@@ -138,20 +136,21 @@ void ui_layer::load_random_background()
if (f.is_regular_file()) if (f.is_regular_file())
images.emplace_back(std::filesystem::relative(f.path(), "textures/").string()); images.emplace_back(std::filesystem::relative(f.path(), "textures/").string());
if (!images.empty()) { if (!images.empty())
{
std::string &selected = images[std::lround(LocalRandom(images.size() - 1))]; std::string &selected = images[std::lround(LocalRandom(images.size() - 1))];
set_background(selected); set_background(selected);
} }
} }
static ImVec4 imvec_lerp(const ImVec4& a, const ImVec4& b, float t) static ImVec4 imvec_lerp(const ImVec4 &a, const ImVec4 &b, float t)
{ {
return ImVec4(a.x + (b.x - a.x) * t, a.y + (b.y - a.y) * t, a.z + (b.z - a.z) * t, a.w + (b.w - a.w) * t); return ImVec4(a.x + (b.x - a.x) * t, a.y + (b.y - a.y) * t, a.z + (b.z - a.z) * t, a.w + (b.w - a.w) * t);
} }
void ui_layer::imgui_style() void ui_layer::imgui_style()
{ {
ImVec4* colors = ImGui::GetStyle().Colors; ImVec4 *colors = ImGui::GetStyle().Colors;
colors[ImGuiCol_Text] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f); colors[ImGuiCol_Text] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f);
colors[ImGuiCol_TextDisabled] = ImVec4(0.35f, 0.35f, 0.35f, 1.00f); colors[ImGuiCol_TextDisabled] = ImVec4(0.35f, 0.35f, 0.35f, 1.00f);
@@ -219,8 +218,7 @@ bool ui_layer::init(GLFWwindow *Window)
// m_imguiio->ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // m_imguiio->ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;
// m_imguiio->ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // m_imguiio->ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad;
static const ImWchar ranges[] = static const ImWchar ranges[] = {
{
0x0020, 0x00FF, // Basic Latin + Latin Supplement 0x0020, 0x00FF, // Basic Latin + Latin Supplement
0x0100, 0x017F, // Latin Extended-A 0x0100, 0x017F, // Latin Extended-A
0x2070, 0x2079, // superscript 0x2070, 0x2079, // superscript
@@ -269,27 +267,33 @@ bool ui_layer::on_key(int const Key, int const Action)
{ {
if (Action == GLFW_PRESS) if (Action == GLFW_PRESS)
{ {
if (Key == GLFW_KEY_PRINT_SCREEN) { if (Key == GLFW_KEY_PRINT_SCREEN)
{
Application.queue_screenshot(); Application.queue_screenshot();
return true; return true;
} }
if (Key == GLFW_KEY_F9) { if (Key == GLFW_KEY_F9)
{
m_logpanel.is_open = !m_logpanel.is_open; m_logpanel.is_open = !m_logpanel.is_open;
return true; return true;
} }
if (Key == GLFW_KEY_F10) { if (Key == GLFW_KEY_F10)
{
m_quit_active = !m_quit_active; m_quit_active = !m_quit_active;
return true; return true;
} }
if (m_quit_active) if (m_quit_active)
{ {
if (Key == GLFW_KEY_Y) { if (Key == GLFW_KEY_Y)
{
Application.queue_quit(false); Application.queue_quit(false);
return true; return true;
} else if (Key == GLFW_KEY_N) { }
else if (Key == GLFW_KEY_N)
{
m_quit_active = false; m_quit_active = false;
return true; return true;
} }
@@ -315,13 +319,13 @@ void ui_layer::on_window_resize(int w, int h)
panel->on_window_resize(w, h); panel->on_window_resize(w, h);
} }
void ui_layer::update() void ui_layer::update()
{ {
for (auto *panel : m_panels) for (auto *panel : m_panels)
panel->update(); panel->update();
for (auto it = m_ownedpanels.rbegin(); it != m_ownedpanels.rend(); it++) { for (auto it = m_ownedpanels.rbegin(); it != m_ownedpanels.rend(); it++)
{
(*it)->update(); (*it)->update();
if (!(*it)->is_open) if (!(*it)->is_open)
m_ownedpanels.erase(std::next(it).base()); m_ownedpanels.erase(std::next(it).base());
@@ -408,13 +412,14 @@ void ui_layer::clear_panels()
void ui_layer::add_owned_panel(ui_panel *Panel) void ui_layer::add_owned_panel(ui_panel *Panel)
{ {
for (auto &panel : m_ownedpanels) for (auto &panel : m_ownedpanels)
if (panel->name() == Panel->name()) { if (panel->name() == Panel->name())
{
delete Panel; delete Panel;
return; return;
} }
Panel->is_open = true; Panel->is_open = true;
m_ownedpanels.emplace_back( Panel ); m_ownedpanels.emplace_back(Panel);
} }
void ui_layer::render_panels() void ui_layer::render_panels()
@@ -443,7 +448,8 @@ void ui_layer::render_menu_contents()
if (ImGui::BeginMenu(STR_C("General"))) if (ImGui::BeginMenu(STR_C("General")))
{ {
bool flag = DebugModeFlag; bool flag = DebugModeFlag;
if (ImGui::MenuItem(STR_C("Debug mode"), nullptr, &flag)) { if (ImGui::MenuItem(STR_C("Debug mode"), nullptr, &flag))
{
command_relay relay; command_relay relay;
relay.post(user_command::debugtoggle, 0.0, 0.0, GLFW_RELEASE, 0); relay.post(user_command::debugtoggle, 0.0, 0.0, GLFW_RELEASE, 0);
} }
@@ -467,7 +473,8 @@ void ui_layer::render_menu_contents()
if (ImGui::BeginMenu(STR_C("Windows"))) if (ImGui::BeginMenu(STR_C("Windows")))
{ {
ImGui::MenuItem(STR_C("Log"), "F9", &m_logpanel.is_open); ImGui::MenuItem(STR_C("Log"), "F9", &m_logpanel.is_open);
if (DebugModeFlag) { if (DebugModeFlag)
{
ImGui::MenuItem(STR_C("ImGui Demo"), nullptr, &m_imgui_demo); ImGui::MenuItem(STR_C("ImGui Demo"), nullptr, &m_imgui_demo);
bool ret = ImGui::MenuItem(STR_C("Headlight config"), nullptr, GfxRenderer->Debug_Ui_State(std::nullopt)); bool ret = ImGui::MenuItem(STR_C("Headlight config"), nullptr, GfxRenderer->Debug_Ui_State(std::nullopt));

View File

@@ -53,19 +53,21 @@ double Min0R(double x1, double x2)
// shitty replacement for Borland timestamp function // shitty replacement for Borland timestamp function
// TODO: replace with something sensible // TODO: replace with something sensible
std::string Now() { std::string Now()
{
std::time_t timenow = std::time( nullptr ); std::time_t timenow = std::time(nullptr);
std::tm tm = *std::localtime( &timenow ); std::tm tm = *std::localtime(&timenow);
std::stringstream converter; std::stringstream converter;
converter << std::put_time( &tm, "%c" ); converter << std::put_time(&tm, "%c");
return converter.str(); return converter.str();
} }
// zwraca różnicę czasu // zwraca różnicę czasu
// jeśli pierwsza jest aktualna, a druga rozkładowa, to ujemna oznacza opóżnienie // jeśli pierwsza jest aktualna, a druga rozkładowa, to ujemna oznacza opóżnienie
// na dłuższą metę trzeba uwzględnić datę, jakby opóżnienia miały przekraczać 12h (towarowych) // na dłuższą metę trzeba uwzględnić datę, jakby opóżnienia miały przekraczać 12h (towarowych)
double CompareTime(double t1h, double t1m, double t2h, double t2m) { double CompareTime(double t1h, double t1m, double t2h, double t2m)
{
if ((t2h < 0)) if ((t2h < 0))
return 0; return 0;
@@ -80,28 +82,35 @@ double CompareTime(double t1h, double t1m, double t2h, double t2m) {
} }
} }
bool SetFlag( int &Flag, int const Value ) { bool SetFlag(int &Flag, int const Value)
{
if( Value > 0 ) { if (Value > 0)
if( false == TestFlag( Flag, Value ) ) { {
if (false == TestFlag(Flag, Value))
{
Flag |= Value; Flag |= Value;
return true; // true, gdy było wcześniej 0 i zostało ustawione return true; // true, gdy było wcześniej 0 i zostało ustawione
} }
} }
else if( Value < 0 ) { else if (Value < 0)
{
// Value jest ujemne, czyli zerowanie flagi // Value jest ujemne, czyli zerowanie flagi
return ClearFlag( Flag, -Value ); return ClearFlag(Flag, -Value);
} }
return false; return false;
} }
bool ClearFlag( int &Flag, int const Value ) { bool ClearFlag(int &Flag, int const Value)
{
if( true == TestFlag( Flag, Value ) ) { if (true == TestFlag(Flag, Value))
{
Flag &= ~Value; Flag &= ~Value;
return true; return true;
} }
else { else
{
return false; return false;
} }
} }
@@ -119,6 +128,31 @@ int RandomInt(int min, int max)
return dist(engine); return dist(engine);
} }
std::string generate_uuid_v4()
{
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_int_distribution<int> dist(0, 255);
std::array<uint8_t, 16> bytes;
for (auto &b : bytes)
b = static_cast<uint8_t>(dist(gen));
// UUID v4 (RFC 4122)
bytes[6] = (bytes[6] & 0x0F) | 0x40;
bytes[8] = (bytes[8] & 0x3F) | 0x80;
char buf[37]; // 36 znaków + \0
std::snprintf(buf, sizeof(buf),
"%02x%02x%02x%02x-"
"%02x%02x-"
"%02x%02x-"
"%02x%02x-"
"%02x%02x%02x%02x%02x%02x",
bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7], bytes[8], bytes[9], bytes[10], bytes[11], bytes[12], bytes[13], bytes[14], bytes[15]);
return std::string(buf);
}
double LocalRandom(double a, double b) double LocalRandom(double a, double b)
{ {
@@ -129,8 +163,7 @@ double LocalRandom(double a, double b)
bool FuzzyLogic(double Test, double Threshold, double Probability) bool FuzzyLogic(double Test, double Threshold, double Probability)
{ {
if ((Test > Threshold) && (!DebugModeFlag)) if ((Test > Threshold) && (!DebugModeFlag))
return return (Random() < Probability * Threshold * 1.0 / Test) /*im wiekszy Test tym wieksza szansa*/;
(Random() < Probability * Threshold * 1.0 / Test) /*im wiekszy Test tym wieksza szansa*/;
else else
return false; return false;
} }
@@ -138,15 +171,14 @@ bool FuzzyLogic(double Test, double Threshold, double Probability)
bool FuzzyLogicAI(double Test, double Threshold, double Probability) bool FuzzyLogicAI(double Test, double Threshold, double Probability)
{ {
if ((Test > Threshold)) if ((Test > Threshold))
return return (Random() < Probability * Threshold * 1.0 / Test) /*im wiekszy Test tym wieksza szansa*/;
(Random() < Probability * Threshold * 1.0 / Test) /*im wiekszy Test tym wieksza szansa*/;
else else
return false; return false;
} }
std::string DUE(std::string s) /*Delete Before Equal sign*/ std::string DUE(std::string s) /*Delete Before Equal sign*/
{ {
//DUE = Copy(s, Pos("=", s) + 1, length(s)); // DUE = Copy(s, Pos("=", s) + 1, length(s));
return s.substr(s.find("=") + 1, s.length()); return s.substr(s.find("=") + 1, s.length());
} }
@@ -154,20 +186,28 @@ std::string DWE(std::string s) /*Delete After Equal sign*/
{ {
size_t ep = s.find("="); size_t ep = s.find("=");
if (ep != std::string::npos) if (ep != std::string::npos)
//DWE = Copy(s, 1, ep - 1); // DWE = Copy(s, 1, ep - 1);
return s.substr(0, ep); return s.substr(0, ep);
else else
return s; return s;
} }
std::string ExchangeCharInString( std::string const &Source, char const From, char const To ) std::string ExchangeCharInString(std::string const &Source, char const From, char const To)
{ {
std::string replacement; replacement.reserve( Source.size() ); std::string replacement;
std::for_each( replacement.reserve(Source.size());
std::begin( Source ), std::end( Source ), std::for_each(std::begin(Source), std::end(Source),
[&](char const idx) { [&](char const idx)
if( idx != From ) { replacement += idx; } {
else { replacement += To; } } ); if (idx != From)
{
replacement += idx;
}
else
{
replacement += To;
}
});
return replacement; return replacement;
} }
@@ -203,17 +243,16 @@ std::vector<std::string> Split(const std::string &s)
return elems; return elems;
} }
std::pair<std::string, int> std::pair<std::string, int> split_string_and_number(std::string const &Key)
split_string_and_number( std::string const &Key ) { {
auto const indexstart{ Key.find_first_of( "-1234567890" ) }; auto const indexstart{Key.find_first_of("-1234567890")};
auto const indexend{ Key.find_first_not_of( "-1234567890", indexstart ) }; auto const indexend{Key.find_first_not_of("-1234567890", indexstart)};
if( indexstart != std::string::npos ) { if (indexstart != std::string::npos)
return { {
Key.substr( 0, indexstart ), return {Key.substr(0, indexstart), std::stoi(Key.substr(indexstart, indexend - indexstart))};
std::stoi( Key.substr( indexstart, indexend - indexstart ) ) };
} }
return { Key, 0 }; return {Key, 0};
} }
std::string to_string(int Value) std::string to_string(int Value)
@@ -256,14 +295,14 @@ std::string to_string(double Value, int precision)
std::string to_string(double const Value, int const Precision, int const Width) std::string to_string(double const Value, int const Precision, int const Width)
{ {
std::ostringstream converter; std::ostringstream converter;
converter << std::setw( Width ) << std::fixed << std::setprecision(Precision) << Value; converter << std::setw(Width) << std::fixed << std::setprecision(Precision) << Value;
return converter.str(); return converter.str();
}; };
std::string to_hex_str( int const Value, int const Width ) std::string to_hex_str(int const Value, int const Width)
{ {
std::ostringstream converter; std::ostringstream converter;
converter << "0x" << std::uppercase << std::setfill( '0' ) << std::setw( Width ) << std::hex << Value; converter << "0x" << std::uppercase << std::setfill('0') << std::setw(Width) << std::hex << Value;
return converter.str(); return converter.str();
}; };
@@ -283,77 +322,67 @@ bool string_starts_with(const std::string &string, const std::string &begin)
return string.compare(0, begin.length(), begin) == 0; return string.compare(0, begin.length(), begin) == 0;
} }
std::string const fractionlabels[] = { " ", u8"¹", u8"²", u8"³", u8"", u8"", u8"", u8"", u8"", u8"" }; std::string const fractionlabels[] = {" ", u8"¹", u8"²", u8"³", u8"", u8"", u8"", u8"", u8"", u8""};
std::string to_minutes_str( float const Minutes, bool const Leadingzero, int const Width ) { std::string to_minutes_str(float const Minutes, bool const Leadingzero, int const Width)
{
float minutesintegral; float minutesintegral;
auto const minutesfractional { std::modf( Minutes, &minutesintegral ) }; auto const minutesfractional{std::modf(Minutes, &minutesintegral)};
auto const width { Width - 1 }; auto const width{Width - 1};
auto minutes = ( auto minutes = (std::string(width - 1, ' ') + (Leadingzero ? to_string(100 + minutesintegral).substr(1, 2) : to_string(minutesintegral, 0)));
std::string( width - 1, ' ' ) return (minutes.substr(minutes.size() - width, width) + fractionlabels[static_cast<int>(std::floor(minutesfractional * 10 + 0.1))]);
+ ( Leadingzero ?
to_string( 100 + minutesintegral ).substr( 1, 2 ) :
to_string( minutesintegral, 0 ) ) );
return (
minutes.substr( minutes.size() - width, width )
+ fractionlabels[ static_cast<int>( std::floor( minutesfractional * 10 + 0.1 ) ) ] );
} }
int stol_def(const std::string &str, const int &DefaultValue)
{
int stol_def(const std::string &str, const int &DefaultValue) { int result{DefaultValue};
int result { DefaultValue };
std::stringstream converter; std::stringstream converter;
converter << str; converter << str;
converter >> result; converter >> result;
return result; return result;
} }
std::string ToLower(std::string const &text) { std::string ToLower(std::string const &text)
{
auto lowercase { text }; auto lowercase{text};
std::transform( std::transform(std::begin(text), std::end(text), std::begin(lowercase), [](unsigned char c) { return std::tolower(c); });
std::begin( text ), std::end( text ),
std::begin( lowercase ),
[]( unsigned char c ) { return std::tolower( c ); } );
return lowercase; return lowercase;
} }
std::string ToUpper(std::string const &text) { std::string ToUpper(std::string const &text)
{
auto uppercase { text }; auto uppercase{text};
std::transform( std::transform(std::begin(text), std::end(text), std::begin(uppercase), [](unsigned char c) { return std::toupper(c); });
std::begin( text ), std::end( text ),
std::begin( uppercase ),
[]( unsigned char c ) { return std::toupper( c ); } );
return uppercase; return uppercase;
} }
// replaces polish letters with basic ascii // replaces polish letters with basic ascii
void void win1250_to_ascii(std::string &Input)
win1250_to_ascii( std::string &Input ) { {
std::unordered_map<char, char> const charmap { std::unordered_map<char, char> const charmap{{165, 'A'}, {198, 'C'}, {202, 'E'}, {163, 'L'}, {209, 'N'}, {211, 'O'}, {140, 'S'}, {143, 'Z'}, {175, 'Z'},
{ 165, 'A' }, { 198, 'C' }, { 202, 'E' }, { 163, 'L' }, { 209, 'N' }, { 211, 'O' }, { 140, 'S' }, { 143, 'Z' }, { 175, 'Z' }, {185, 'a'}, {230, 'c'}, {234, 'e'}, {179, 'l'}, {241, 'n'}, {243, 'o'}, {156, 's'}, {159, 'z'}, {191, 'z'}};
{ 185, 'a' }, { 230, 'c' }, { 234, 'e' }, { 179, 'l' }, { 241, 'n' }, { 243, 'o' }, { 156, 's' }, { 159, 'z' }, { 191, 'z' }
};
std::unordered_map<char, char>::const_iterator lookup; std::unordered_map<char, char>::const_iterator lookup;
for( auto &input : Input ) { for (auto &input : Input)
if( ( lookup = charmap.find( input ) ) != charmap.end() ) {
if ((lookup = charmap.find(input)) != charmap.end())
input = lookup->second; input = lookup->second;
} }
} }
std::string win1250_to_utf8(const std::string &Input) { std::string win1250_to_utf8(const std::string &Input)
std::unordered_map<char, std::string> const charmap { {
{ 165, u8"Ą" }, { 198, u8"Ć" }, { 202, u8"Ę" }, { 163, u8"Ł" }, { 209, u8"Ń" }, { 211, u8"Ó" }, { 140, u8"Ś" }, { 143, u8"Ź" }, { 175, u8"Ż" }, std::unordered_map<char, std::string> const charmap{{165, u8"Ą"}, {198, u8"Ć"}, {202, u8"Ę"}, {163, u8"Ł"}, {209, u8"Ń"}, {211, u8"Ó"}, {140, u8"Ś"}, {143, u8"Ź"}, {175, u8"Ż"},
{ 185, u8"ą" }, { 230, u8"ć" }, { 234, u8"ę" }, { 179, u8"ł" }, { 241, u8"ń" }, { 243, u8"ó" }, { 156, u8"ś" }, { 159, u8"ź" }, { 191, u8"ż" } {185, u8"ą"}, {230, u8"ć"}, {234, u8"ę"}, {179, u8"ł"}, {241, u8"ń"}, {243, u8"ó"}, {156, u8"ś"}, {159, u8"ź"}, {191, u8"ż"}};
};
std::string output; std::string output;
std::unordered_map<char, std::string>::const_iterator lookup; std::unordered_map<char, std::string>::const_iterator lookup;
for( auto &input : Input ) { for (auto &input : Input)
if( ( lookup = charmap.find( input ) ) != charmap.end() ) {
if ((lookup = charmap.find(input)) != charmap.end())
output += lookup->second; output += lookup->second;
else else
output += input; output += input;
@@ -362,27 +391,31 @@ std::string win1250_to_utf8(const std::string &Input) {
} }
// Ra: tymczasowe rozwiązanie kwestii zagranicznych (czeskich) napisów // Ra: tymczasowe rozwiązanie kwestii zagranicznych (czeskich) napisów
char charsetconversiontable[] = char charsetconversiontable[] = "E?,?\"_++?%S<STZZ?`'\"\".--??s>stzz"
"E?,?\"_++?%S<STZZ?`'\"\".--??s>stzz"
" ^^L$A|S^CS<--RZo±,l'uP.,as>L\"lz" " ^^L$A|S^CS<--RZo±,l'uP.,as>L\"lz"
"RAAAALCCCEEEEIIDDNNOOOOxRUUUUYTB" "RAAAALCCCEEEEIIDDNNOOOOxRUUUUYTB"
"raaaalccceeeeiiddnnoooo-ruuuuyt?"; "raaaalccceeeeiiddnnoooo-ruuuuyt?";
// wycięcie liter z ogonkami // wycięcie liter z ogonkami
std::string Bezogonkow(std::string Input, bool const Underscorestospaces) { std::string Bezogonkow(std::string Input, bool const Underscorestospaces)
{
char const extendedcharsetbit { static_cast<char>( 0x80 ) }; char const extendedcharsetbit{static_cast<char>(0x80)};
char const space { ' ' }; char const space{' '};
char const underscore { '_' }; char const underscore{'_'};
for( auto &input : Input ) { for (auto &input : Input)
if( input & extendedcharsetbit ) { {
input = charsetconversiontable[ input ^ extendedcharsetbit ]; if (input & extendedcharsetbit)
{
input = charsetconversiontable[input ^ extendedcharsetbit];
} }
else if( input < space ) { else if (input < space)
{
input = space; input = space;
} }
else if( Underscorestospaces && ( input == underscore ) ) { else if (Underscorestospaces && (input == underscore))
{
input = space; input = space;
} }
} }
@@ -390,184 +423,187 @@ std::string Bezogonkow(std::string Input, bool const Underscorestospaces) {
return Input; return Input;
} }
template <> template <> bool extract_value(bool &Variable, std::string const &Key, std::string const &Input, std::string const &Default)
bool {
extract_value( bool &Variable, std::string const &Key, std::string const &Input, std::string const &Default ) {
auto value = extract_value( Key, Input ); auto value = extract_value(Key, Input);
if( false == value.empty() ) { if (false == value.empty())
{
// set the specified variable to retrieved value // set the specified variable to retrieved value
Variable = ( ToLower( value ) == "yes" ); Variable = (ToLower(value) == "yes");
return true; // located the variable return true; // located the variable
} }
else { else
{
// set the variable to provided default value // set the variable to provided default value
if( false == Default.empty() ) { if (false == Default.empty())
Variable = ( ToLower( Default ) == "yes" ); {
Variable = (ToLower(Default) == "yes");
} }
return false; // couldn't locate the variable in provided input return false; // couldn't locate the variable in provided input
} }
} }
bool FileExists( std::string const &Filename ) { bool FileExists(std::string const &Filename)
{
return std::filesystem::exists(Filename); return std::filesystem::exists(Filename);
} }
std::pair<std::string, std::string> std::pair<std::string, std::string> FileExists(std::vector<std::string> const &Names, std::vector<std::string> const &Extensions)
FileExists( std::vector<std::string> const &Names, std::vector<std::string> const &Extensions ) { {
for( auto const &name : Names ) { for (auto const &name : Names)
for( auto const &extension : Extensions ) { {
if( FileExists( name + extension ) ) { for (auto const &extension : Extensions)
return { name, extension }; {
if (FileExists(name + extension))
{
return {name, extension};
} }
} }
} }
// nothing found // nothing found
return { {}, {} }; return {{}, {}};
} }
// returns time of last modification for specified file // returns time of last modification for specified file
std::time_t std::time_t last_modified(std::string const &Filename)
last_modified( std::string const &Filename ) { {
std::string fn = Filename; std::string fn = Filename;
struct stat filestat; struct stat filestat;
if( ::stat( fn.c_str(), &filestat ) == 0 ) if (::stat(fn.c_str(), &filestat) == 0)
return filestat.st_mtime; return filestat.st_mtime;
else else
return 0; return 0;
} }
// potentially erases file extension from provided file name. returns: true if extension was removed, false otherwise // potentially erases file extension from provided file name. returns: true if extension was removed, false otherwise
bool bool erase_extension(std::string &Filename)
erase_extension( std::string &Filename ) { {
auto const extensionpos { Filename.rfind( '.' ) }; auto const extensionpos{Filename.rfind('.')};
if( extensionpos == std::string::npos ) { return false; } if (extensionpos == std::string::npos)
{
return false;
}
if( extensionpos != Filename.rfind( ".." ) + 1 ) { if (extensionpos != Filename.rfind("..") + 1)
{
// we can get extension for .mat or, in legacy files, some image format. just trim it and set it to material file extension // we can get extension for .mat or, in legacy files, some image format. just trim it and set it to material file extension
Filename.erase( extensionpos ); Filename.erase(extensionpos);
return true; return true;
} }
return false; return false;
} }
void void erase_leading_slashes(std::string &Filename)
erase_leading_slashes( std::string &Filename ) { {
while( Filename[ 0 ] == '/' ) { while (Filename[0] == '/')
Filename.erase( 0, 1 ); {
Filename.erase(0, 1);
} }
} }
// potentially replaces backward slashes in provided file path with unix-compatible forward slashes // potentially replaces backward slashes in provided file path with unix-compatible forward slashes
void void replace_slashes(std::string &Filename)
replace_slashes( std::string &Filename ) { {
std::replace( std::replace(std::begin(Filename), std::end(Filename), '\\', '/');
std::begin( Filename ), std::end( Filename ),
'\\', '/' );
} }
// returns potential path part from provided file name // returns potential path part from provided file name
std::string std::string substr_path(std::string const &Filename)
substr_path( std::string const &Filename ) { {
return ( return (Filename.rfind('/') != std::string::npos ? Filename.substr(0, Filename.rfind('/') + 1) : "");
Filename.rfind( '/' ) != std::string::npos ?
Filename.substr( 0, Filename.rfind( '/' ) + 1 ) :
"" );
} }
// returns length of common prefix between two provided strings // returns length of common prefix between two provided strings
std::ptrdiff_t std::ptrdiff_t len_common_prefix(std::string const &Left, std::string const &Right)
len_common_prefix( std::string const &Left, std::string const &Right ) { {
auto const *left { Left.data() }; auto const *left{Left.data()};
auto const *right { Right.data() }; auto const *right{Right.data()};
// compare up to the length of the shorter string // compare up to the length of the shorter string
return ( Right.size() <= Left.size() ? return (Right.size() <= Left.size() ? std::distance(right, std::mismatch(right, right + Right.size(), left).first) : std::distance(left, std::mismatch(left, left + Left.size(), right).first));
std::distance( right, std::mismatch( right, right + Right.size(), left ).first ) :
std::distance( left, std::mismatch( left, left + Left.size(), right ).first ) );
} }
// returns true if provided string ends with another provided string // returns true if provided string ends with another provided string
bool bool ends_with(std::string_view String, std::string_view Suffix)
ends_with( std::string_view String, std::string_view Suffix ) { {
return ( String.size() >= Suffix.size() ) return (String.size() >= Suffix.size()) && (0 == String.compare(String.size() - Suffix.size(), Suffix.size(), Suffix));
&& ( 0 == String.compare( String.size() - Suffix.size(), Suffix.size(), Suffix ) );
} }
// returns true if provided string begins with another provided string // returns true if provided string begins with another provided string
bool bool starts_with(std::string_view const String, std::string_view Prefix)
starts_with( std::string_view const String, std::string_view Prefix ) { {
return ( String.size() >= Prefix.size() ) return (String.size() >= Prefix.size()) && (0 == String.compare(0, Prefix.size(), Prefix));
&& ( 0 == String.compare( 0, Prefix.size(), Prefix ) );
} }
// returns true if provided string contains another provided string // returns true if provided string contains another provided string
bool bool contains(std::string_view const String, std::string_view Substring)
contains( std::string_view const String, std::string_view Substring ) { {
return ( String.find( Substring ) != std::string::npos ); return (String.find(Substring) != std::string::npos);
} }
bool bool contains(std::string_view const String, char Character)
contains( std::string_view const String, char Character ) { {
return ( String.find( Character ) != std::string::npos ); return (String.find(Character) != std::string::npos);
} }
// helper, restores content of a 3d vector from provided input stream // helper, restores content of a 3d vector from provided input stream
// TODO: review and clean up the helper routines, there's likely some redundant ones // TODO: review and clean up the helper routines, there's likely some redundant ones
glm::dvec3 LoadPoint( cParser &Input ) { glm::dvec3 LoadPoint(cParser &Input)
{
// pobranie współrzędnych punktu // pobranie współrzędnych punktu
glm::dvec3 point; glm::dvec3 point;
Input.getTokens( 3 ); Input.getTokens(3);
Input Input >> point.x >> point.y >> point.z;
>> point.x
>> point.y
>> point.z;
return point; return point;
} }
// extracts a group of tokens from provided data stream, returns one of them picked randomly // extracts a group of tokens from provided data stream, returns one of them picked randomly
std::string std::string deserialize_random_set(cParser &Input, char const *Break)
deserialize_random_set( cParser &Input, char const *Break ) { {
auto token { Input.getToken<std::string>( true, Break ) }; auto token{Input.getToken<std::string>(true, Break)};
std::replace(token.begin(), token.end(), '\\', '/'); std::replace(token.begin(), token.end(), '\\', '/');
if( token != "[" ) { if (token != "[")
{
// simple case, single token // simple case, single token
return token; return token;
} }
// if instead of a single token we've encountered '[' this marks a beginning of a random set // if instead of a single token we've encountered '[' this marks a beginning of a random set
// we retrieve all entries, then return a random one // we retrieve all entries, then return a random one
std::vector<std::string> tokens; std::vector<std::string> tokens;
while( ( ( token = deserialize_random_set( Input, Break ) ) != "" ) while (((token = deserialize_random_set(Input, Break)) != "") && (token != "]"))
&& ( token != "]" ) ) { {
tokens.emplace_back( token ); tokens.emplace_back(token);
} }
if( false == tokens.empty() ) { if (false == tokens.empty())
std::shuffle( std::begin( tokens ), std::end( tokens ), Global.random_engine ); {
std::shuffle(std::begin(tokens), std::end(tokens), Global.random_engine);
return tokens.front(); return tokens.front();
} }
else { else
{
// shouldn't ever get here but, eh // shouldn't ever get here but, eh
return ""; return "";
} }
} }
int count_trailing_zeros( uint32_t val ) int count_trailing_zeros(uint32_t val)
{ {
int r = 0; int r = 0;
for( uint32_t shift = 1; !( val & shift ); shift <<= 1 ) for (uint32_t shift = 1; !(val & shift); shift <<= 1)
r++; r++;
return r; return r;

View File

@@ -36,7 +36,7 @@ template <typename T> T sign(T x)
#define szSoundPath "sounds/" #define szSoundPath "sounds/"
#define szDataPath "data/" #define szDataPath "data/"
#define MAKE_ID4(a,b,c,d) (((std::uint32_t)(d)<<24)|((std::uint32_t)(c)<<16)|((std::uint32_t)(b)<<8)|(std::uint32_t)(a)) #define MAKE_ID4(a, b, c, d) (((std::uint32_t)(d) << 24) | ((std::uint32_t)(c) << 16) | ((std::uint32_t)(b) << 8) | (std::uint32_t)(a))
extern bool DebugModeFlag; extern bool DebugModeFlag;
extern bool FreeFlyModeFlag; extern bool FreeFlyModeFlag;
@@ -56,16 +56,17 @@ inline double Sign(double x)
inline long Round(double const f) inline long Round(double const f)
{ {
return (long)(f + 0.5); return (long)(f + 0.5);
//return lround(f); // return lround(f);
} }
double Random(double a, double b); double Random(double a, double b);
int RandomInt(int min, int max); int RandomInt(int min, int max);
std::string generate_uuid_v4();
double LocalRandom(double a, double b); double LocalRandom(double a, double b);
inline double Random() inline double Random()
{ {
return Random(0.0,1.0); return Random(0.0, 1.0);
} }
inline double Random(double b) inline double Random(double b)
@@ -75,39 +76,39 @@ inline double Random(double b)
inline double LocalRandom() inline double LocalRandom()
{ {
return LocalRandom( 0.0, 1.0 ); return LocalRandom(0.0, 1.0);
} }
inline double LocalRandom( double b ) inline double LocalRandom(double b)
{ {
return LocalRandom( 0.0, b ); return LocalRandom(0.0, b);
} }
inline double BorlandTime() inline double BorlandTime()
{ {
auto timesinceepoch = std::time( nullptr ); auto timesinceepoch = std::time(nullptr);
return timesinceepoch / (24.0 * 60 * 60); return timesinceepoch / (24.0 * 60 * 60);
/* /*
// std alternative // std alternative
auto timesinceepoch = std::chrono::system_clock::now().time_since_epoch(); auto timesinceepoch = std::chrono::system_clock::now().time_since_epoch();
return std::chrono::duration_cast<std::chrono::seconds>( timesinceepoch ).count() / (24.0 * 60 * 60); return std::chrono::duration_cast<std::chrono::seconds>( timesinceepoch ).count() / (24.0 * 60 * 60);
*/ */
} }
std::string Now(); std::string Now();
double CompareTime( double t1h, double t1m, double t2h, double t2m ); double CompareTime(double t1h, double t1m, double t2h, double t2m);
/*funkcje logiczne*/ /*funkcje logiczne*/
inline inline bool TestFlag(int const Flag, int const Value)
bool TestFlag( int const Flag, int const Value ) { {
return ( ( Flag & Value ) == Value ); return ((Flag & Value) == Value);
} }
inline inline bool TestFlagAny(int const Flag, int const Value)
bool TestFlagAny( int const Flag, int const Value ) { {
return ( ( Flag & Value ) != 0 ); return ((Flag & Value) != 0);
} }
bool SetFlag( int &Flag, int const Value); bool SetFlag(int &Flag, int const Value);
bool ClearFlag(int &Flag, int const Value); bool ClearFlag(int &Flag, int const Value);
bool FuzzyLogic(double Test, double Threshold, double Probability); bool FuzzyLogic(double Test, double Threshold, double Probability);
@@ -118,11 +119,11 @@ bool FuzzyLogicAI(double Test, double Threshold, double Probability);
/*operacje na stringach*/ /*operacje na stringach*/
std::string DUE(std::string s); /*Delete Until Equal sign*/ std::string DUE(std::string s); /*Delete Until Equal sign*/
std::string DWE(std::string s); /*Delete While Equal sign*/ std::string DWE(std::string s); /*Delete While Equal sign*/
std::string ExchangeCharInString( std::string const &Source, char const From, char const To ); // zamienia jeden znak na drugi std::string ExchangeCharInString(std::string const &Source, char const From, char const To); // zamienia jeden znak na drugi
std::vector<std::string> &Split(const std::string &s, char delim, std::vector<std::string> &elems); std::vector<std::string> &Split(const std::string &s, char delim, std::vector<std::string> &elems);
std::vector<std::string> Split(const std::string &s, char delim); std::vector<std::string> Split(const std::string &s, char delim);
//std::vector<std::string> Split(const std::string &s); // std::vector<std::string> Split(const std::string &s);
std::pair<std::string, int> split_string_and_number( std::string const &Key ); std::pair<std::string, int> split_string_and_number(std::string const &Key);
std::string to_string(int Value); std::string to_string(int Value);
std::string to_string(unsigned int Value); std::string to_string(unsigned int Value);
@@ -130,72 +131,75 @@ std::string to_string(int Value, int width);
std::string to_string(double Value); std::string to_string(double Value);
std::string to_string(double Value, int precision); std::string to_string(double Value, int precision);
std::string to_string(double Value, int precision, int width); std::string to_string(double Value, int precision, int width);
std::string to_hex_str( int const Value, int const width = 4 ); std::string to_hex_str(int const Value, int const width = 4);
std::string to_minutes_str( float const Minutes, bool const Leadingzero, int const Width ); std::string to_minutes_str(float const Minutes, bool const Leadingzero, int const Width);
inline inline std::string to_string(bool Value)
std::string to_string(bool Value) { {
return ( Value == true ? "true" : "false" ); return (Value == true ? "true" : "false");
} }
template <typename Type_, glm::precision Precision_ = glm::defaultp> template <typename Type_, glm::precision Precision_ = glm::defaultp> std::string to_string(glm::tvec3<Type_, Precision_> const &Value)
std::string to_string( glm::tvec3<Type_, Precision_> const &Value ) { {
return to_string( Value.x, 2 ) + ", " + to_string( Value.y, 2 ) + ", " + to_string( Value.z, 2 ); return to_string(Value.x, 2) + ", " + to_string(Value.y, 2) + ", " + to_string(Value.z, 2);
} }
template <typename Type_, glm::precision Precision_ = glm::defaultp> template <typename Type_, glm::precision Precision_ = glm::defaultp> std::string to_string(glm::tvec4<Type_, Precision_> const &Value, int const Width = 2)
std::string to_string( glm::tvec4<Type_, Precision_> const &Value, int const Width = 2 ) { {
return to_string( Value.x, Width ) + ", " + to_string( Value.y, Width ) + ", " + to_string( Value.z, Width ) + ", " + to_string( Value.w, Width ); return to_string(Value.x, Width) + ", " + to_string(Value.y, Width) + ", " + to_string(Value.z, Width) + ", " + to_string(Value.w, Width);
} }
bool string_ends_with(std::string const &string, std::string const &ending); bool string_ends_with(std::string const &string, std::string const &ending);
bool string_starts_with(std::string const &string, std::string const &begin); bool string_starts_with(std::string const &string, std::string const &begin);
int stol_def(const std::string & str, const int & DefaultValue); int stol_def(const std::string &str, const int &DefaultValue);
std::string ToLower(std::string const &text); std::string ToLower(std::string const &text);
std::string ToUpper(std::string const &text); std::string ToUpper(std::string const &text);
// replaces polish letters with basic ascii // replaces polish letters with basic ascii
void win1250_to_ascii( std::string &Input ); void win1250_to_ascii(std::string &Input);
// TODO: unify with win1250_to_ascii() // TODO: unify with win1250_to_ascii()
std::string Bezogonkow( std::string Input, bool const Underscorestospaces = false ); std::string Bezogonkow(std::string Input, bool const Underscorestospaces = false);
std::string win1250_to_utf8(const std::string &input); std::string win1250_to_utf8(const std::string &input);
inline inline std::string extract_value(std::string const &Key, std::string const &Input)
std::string {
extract_value( std::string const &Key, std::string const &Input ) {
// NOTE, HACK: the leading space allows to uniformly look for " variable=" substring // NOTE, HACK: the leading space allows to uniformly look for " variable=" substring
std::string const input { " " + Input }; std::string const input{" " + Input};
std::string value; std::string value;
auto lookup = input.find( " " + Key + "=" ); auto lookup = input.find(" " + Key + "=");
if( lookup != std::string::npos ) { if (lookup != std::string::npos)
value = input.substr( input.find_first_not_of( ' ', lookup + Key.size() + 2 ) ); {
lookup = value.find( ' ' ); value = input.substr(input.find_first_not_of(' ', lookup + Key.size() + 2));
if( lookup != std::string::npos ) { lookup = value.find(' ');
if (lookup != std::string::npos)
{
// trim everything past the value // trim everything past the value
value.erase( lookup ); value.erase(lookup);
} }
} }
return value; return value;
} }
template <typename Type_> template <typename Type_> bool extract_value(Type_ &Variable, std::string const &Key, std::string const &Input, std::string const &Default)
bool {
extract_value( Type_ &Variable, std::string const &Key, std::string const &Input, std::string const &Default ) {
auto value = extract_value( Key, Input ); auto value = extract_value(Key, Input);
if( false == value.empty() ) { if (false == value.empty())
{
// set the specified variable to retrieved value // set the specified variable to retrieved value
std::stringstream converter; std::stringstream converter;
converter << value; converter << value;
converter >> Variable; converter >> Variable;
return true; // located the variable return true; // located the variable
} }
else { else
{
// set the variable to provided default value // set the variable to provided default value
if( false == Default.empty() ) { if (false == Default.empty())
{
std::stringstream converter; std::stringstream converter;
converter << Default; converter << Default;
converter >> Variable; converter >> Variable;
@@ -204,136 +208,130 @@ extract_value( Type_ &Variable, std::string const &Key, std::string const &Input
} }
} }
template <> template <> bool extract_value(bool &Variable, std::string const &Key, std::string const &Input, std::string const &Default);
bool
extract_value( bool &Variable, std::string const &Key, std::string const &Input, std::string const &Default );
bool FileExists( std::string const &Filename ); bool FileExists(std::string const &Filename);
std::pair<std::string, std::string> FileExists( std::vector<std::string> const &Names, std::vector<std::string> const &Extensions ); std::pair<std::string, std::string> FileExists(std::vector<std::string> const &Names, std::vector<std::string> const &Extensions);
// returns time of last modification for specified file // returns time of last modification for specified file
std::time_t last_modified( std::string const &Filename ); std::time_t last_modified(std::string const &Filename);
// potentially erases file extension from provided file name. returns: true if extension was removed, false otherwise // potentially erases file extension from provided file name. returns: true if extension was removed, false otherwise
bool bool erase_extension(std::string &Filename);
erase_extension( std::string &Filename );
// potentially erase leading slashes from provided file path // potentially erase leading slashes from provided file path
void void erase_leading_slashes(std::string &Filename);
erase_leading_slashes( std::string &Filename );
// potentially replaces backward slashes in provided file path with unix-compatible forward slashes // potentially replaces backward slashes in provided file path with unix-compatible forward slashes
void void replace_slashes(std::string &Filename);
replace_slashes( std::string &Filename );
// returns potential path part from provided file name // returns potential path part from provided file name
std::string substr_path( std::string const &Filename ); std::string substr_path(std::string const &Filename);
// returns common prefix of two provided strings // returns common prefix of two provided strings
std::ptrdiff_t len_common_prefix( std::string const &Left, std::string const &Right ); std::ptrdiff_t len_common_prefix(std::string const &Left, std::string const &Right);
// returns true if provided string ends with another provided string // returns true if provided string ends with another provided string
bool ends_with( std::string_view String, std::string_view Suffix ); bool ends_with(std::string_view String, std::string_view Suffix);
// returns true if provided string begins with another provided string // returns true if provided string begins with another provided string
bool starts_with( std::string_view String, std::string_view Prefix ); bool starts_with(std::string_view String, std::string_view Prefix);
// returns true if provided string contains another provided string // returns true if provided string contains another provided string
bool contains( std::string_view const String, std::string_view Substring ); bool contains(std::string_view const String, std::string_view Substring);
bool contains( std::string_view const String, char Character ); bool contains(std::string_view const String, char Character);
template <typename Type_> template <typename Type_> void SafeDelete(Type_ &Pointer)
void SafeDelete( Type_ &Pointer ) { {
delete Pointer; delete Pointer;
Pointer = nullptr; Pointer = nullptr;
} }
template <typename Type_> template <typename Type_> void SafeDeleteArray(Type_ &Pointer)
void SafeDeleteArray( Type_ &Pointer ) { {
delete[] Pointer; delete[] Pointer;
Pointer = nullptr; Pointer = nullptr;
} }
template <typename Type_> template <typename Type_> Type_ is_equal(Type_ const &Left, Type_ const &Right, Type_ const Epsilon = 1e-5)
Type_ {
is_equal( Type_ const &Left, Type_ const &Right, Type_ const Epsilon = 1e-5 ) {
if( Epsilon != 0 ) { if (Epsilon != 0)
return glm::epsilonEqual( Left, Right, Epsilon ); {
return glm::epsilonEqual(Left, Right, Epsilon);
} }
else { else
return ( Left == Right ); {
return (Left == Right);
} }
} }
template <typename Type_> template <typename Type_> Type_ clamp(Type_ const Value, Type_ const Min, Type_ const Max)
Type_ {
clamp( Type_ const Value, Type_ const Min, Type_ const Max ) {
Type_ value = Value; Type_ value = Value;
if( value < Min ) { value = Min; } if (value < Min)
if( value > Max ) { value = Max; } {
value = Min;
}
if (value > Max)
{
value = Max;
}
return value; return value;
} }
// keeps the provided value in specified range 0-Range, as if the range was circular buffer // keeps the provided value in specified range 0-Range, as if the range was circular buffer
template <typename Type_> template <typename Type_> Type_ clamp_circular(Type_ Value, Type_ const Range = static_cast<Type_>(360))
Type_ {
clamp_circular( Type_ Value, Type_ const Range = static_cast<Type_>(360) ) {
Value -= Range * (int)( Value / Range ); // clamp the range to 0-360 Value -= Range * (int)(Value / Range); // clamp the range to 0-360
if( Value < Type_(0) ) Value += Range; if (Value < Type_(0))
Value += Range;
return Value; return Value;
} }
// rounds down provided value to nearest power of two // rounds down provided value to nearest power of two
template <typename Type_> template <typename Type_> Type_ clamp_power_of_two(Type_ Value, Type_ const Min = static_cast<Type_>(1), Type_ const Max = static_cast<Type_>(16384))
Type_ {
clamp_power_of_two( Type_ Value, Type_ const Min = static_cast<Type_>(1), Type_ const Max = static_cast<Type_>(16384) ) {
Type_ p2size{ Min }; Type_ p2size{Min};
Type_ size; Type_ size;
while( ( p2size <= Max ) && ( p2size <= Value ) ) { while ((p2size <= Max) && (p2size <= Value))
{
size = p2size; size = p2size;
p2size = p2size << 1; p2size = p2size << 1;
} }
return size; return size;
} }
template <typename Type_> template <typename Type_> Type_ quantize(Type_ const Value, Type_ const Step)
Type_ {
quantize( Type_ const Value, Type_ const Step ) {
return ( Step * std::round( Value / Step ) ); return (Step * std::round(Value / Step));
} }
template <typename Type_> template <typename Type_> Type_ min_speed(Type_ const Left, Type_ const Right)
Type_ {
min_speed( Type_ const Left, Type_ const Right ) {
if( Left == Right ) { return Left; } if (Left == Right)
{
return Left;
}
return std::min( return std::min((Left != -1 ? Left : std::numeric_limits<Type_>::max()), (Right != -1 ? Right : std::numeric_limits<Type_>::max()));
( Left != -1 ?
Left :
std::numeric_limits<Type_>::max() ),
( Right != -1 ?
Right :
std::numeric_limits<Type_>::max() ) );
} }
template <typename Type_> template <typename Type_> Type_ interpolate(Type_ const &First, Type_ const &Second, float const Factor)
Type_ {
interpolate( Type_ const &First, Type_ const &Second, float const Factor ) {
return static_cast<Type_>( ( First * ( 1.0f - Factor ) ) + ( Second * Factor ) ); return static_cast<Type_>((First * (1.0f - Factor)) + (Second * Factor));
} }
template <typename Type_> template <typename Type_> Type_ interpolate(Type_ const &First, Type_ const &Second, double const Factor)
Type_ {
interpolate( Type_ const &First, Type_ const &Second, double const Factor ) {
return static_cast<Type_>( ( First * ( 1.0 - Factor ) ) + ( Second * Factor ) ); return static_cast<Type_>((First * (1.0 - Factor)) + (Second * Factor));
} }
template <typename Type_> Type_ smoothInterpolate(Type_ const &First, Type_ const &Second, double Factor) template <typename Type_> Type_ smoothInterpolate(Type_ const &First, Type_ const &Second, double Factor)
@@ -345,75 +343,75 @@ template <typename Type_> Type_ smoothInterpolate(Type_ const &First, Type_ cons
} }
// tests whether provided points form a degenerate triangle // tests whether provided points form a degenerate triangle
template <typename VecType_> template <typename VecType_> bool degenerate(VecType_ const &Vertex1, VecType_ const &Vertex2, VecType_ const &Vertex3)
bool {
degenerate( VecType_ const &Vertex1, VecType_ const &Vertex2, VecType_ const &Vertex3 ) {
// degenerate( A, B, C, minarea ) = ( ( B - A ).cross( C - A ) ).lengthSquared() < ( 4.0f * minarea * minarea ); // degenerate( A, B, C, minarea ) = ( ( B - A ).cross( C - A ) ).lengthSquared() < ( 4.0f * minarea * minarea );
return ( glm::length2( glm::cross( Vertex2 - Vertex1, Vertex3 - Vertex1 ) ) == 0.0 ); return (glm::length2(glm::cross(Vertex2 - Vertex1, Vertex3 - Vertex1)) == 0.0);
} }
// calculates bounding box for provided set of points // calculates bounding box for provided set of points
template <class Iterator_, class VecType_> template <class Iterator_, class VecType_> void bounding_box(VecType_ &Mincorner, VecType_ &Maxcorner, Iterator_ First, Iterator_ Last)
void {
bounding_box( VecType_ &Mincorner, VecType_ &Maxcorner, Iterator_ First, Iterator_ Last ) {
Mincorner = VecType_( std::numeric_limits<typename VecType_::value_type>::max() ); Mincorner = VecType_(std::numeric_limits<typename VecType_::value_type>::max());
Maxcorner = VecType_( std::numeric_limits<typename VecType_::value_type>::lowest() ); Maxcorner = VecType_(std::numeric_limits<typename VecType_::value_type>::lowest());
std::for_each( std::for_each(First, Last,
First, Last, [&](typename Iterator_::value_type &point)
[&]( typename Iterator_::value_type &point ) { {
Mincorner = glm::min( Mincorner, VecType_{ point } ); Mincorner = glm::min(Mincorner, VecType_{point});
Maxcorner = glm::max( Maxcorner, VecType_{ point } ); } ); Maxcorner = glm::max(Maxcorner, VecType_{point});
});
} }
// finds point on specified segment closest to specified point in 3d space. returns: point on segment as value in range 0-1 where 0 = start and 1 = end of the segment // finds point on specified segment closest to specified point in 3d space. returns: point on segment as value in range 0-1 where 0 = start and 1 = end of the segment
template <typename VecType_> template <typename VecType_> typename VecType_::value_type nearest_segment_point(VecType_ const &Segmentstart, VecType_ const &Segmentend, VecType_ const &Point)
typename VecType_::value_type {
nearest_segment_point( VecType_ const &Segmentstart, VecType_ const &Segmentend, VecType_ const &Point ) {
auto const v = Segmentend - Segmentstart; auto const v = Segmentend - Segmentstart;
auto const w = Point - Segmentstart; auto const w = Point - Segmentstart;
auto const c1 = glm::dot( w, v ); auto const c1 = glm::dot(w, v);
if( c1 <= 0.0 ) { if (c1 <= 0.0)
{
return 0.0; return 0.0;
} }
auto const c2 = glm::dot( v, v ); auto const c2 = glm::dot(v, v);
if( c2 <= c1 ) { if (c2 <= c1)
{
return 1.0; return 1.0;
} }
return c1 / c2; return c1 / c2;
} }
glm::dvec3 LoadPoint( class cParser &Input ); glm::dvec3 LoadPoint(class cParser &Input);
// extracts a group of tokens from provided data stream // extracts a group of tokens from provided data stream
std::string std::string deserialize_random_set(cParser &Input, char const *Break = "\n\r\t ;");
deserialize_random_set( cParser &Input, char const *Break = "\n\r\t ;" );
int count_trailing_zeros( uint32_t val ); int count_trailing_zeros(uint32_t val);
// extracts a group of <key, value> pairs from provided data stream // extracts a group of <key, value> pairs from provided data stream
// NOTE: expects no more than single pair per line // NOTE: expects no more than single pair per line
template <typename MapType_> template <typename MapType_> void deserialize_map(MapType_ &Map, cParser &Input)
void {
deserialize_map( MapType_ &Map, cParser &Input ) {
while( Input.ok() && !Input.eof() ) { while (Input.ok() && !Input.eof())
auto const key { Input.getToken<typename MapType_::key_type>( false ) }; {
auto const value { Input.getToken<typename MapType_::mapped_type>( false, "\n" ) }; auto const key{Input.getToken<typename MapType_::key_type>(false)};
Map.emplace( key, value ); auto const value{Input.getToken<typename MapType_::mapped_type>(false, "\n")};
Map.emplace(key, value);
} }
} }
namespace threading { namespace threading
{
// simple POD pairing of a data item and a mutex // simple POD pairing of a data item and a mutex
// NOTE: doesn't do any locking itself, it's merely for cleaner argument arrangement and passing // NOTE: doesn't do any locking itself, it's merely for cleaner argument arrangement and passing
template <typename Type_> template <typename Type_> struct lockable
struct lockable { {
Type_ data; Type_ data;
std::mutex mutex; std::mutex mutex;
@@ -421,48 +419,44 @@ struct lockable {
// basic wrapper simplifying use of std::condition_variable for most typical cases. // basic wrapper simplifying use of std::condition_variable for most typical cases.
// has its own mutex and secondary variable to ignore spurious wakeups // has its own mutex and secondary variable to ignore spurious wakeups
class condition_variable { class condition_variable
{
public: public:
// methods // methods
void void wait()
wait() { {
std::unique_lock<std::mutex> lock( m_mutex ); std::unique_lock<std::mutex> lock(m_mutex);
m_condition.wait( m_condition.wait(lock, [this]() { return m_spurious == false; });
lock, }
[ this ]() { template <class Rep_, class Period_> void wait_for(const std::chrono::duration<Rep_, Period_> &Time)
return m_spurious == false; } ); } {
template< class Rep_, class Period_ > std::unique_lock<std::mutex> lock(m_mutex);
void m_condition.wait_for(lock, Time, [this]() { return m_spurious == false; });
wait_for( const std::chrono::duration<Rep_, Period_> &Time ) { }
std::unique_lock<std::mutex> lock( m_mutex ); void notify_one()
m_condition.wait_for( {
lock, spurious(false);
Time,
[ this ]() {
return m_spurious == false; } ); }
void
notify_one() {
spurious( false );
m_condition.notify_one(); m_condition.notify_one();
} }
void void notify_all()
notify_all() { {
spurious( false ); spurious(false);
m_condition.notify_all(); m_condition.notify_all();
} }
void void spurious(bool const Spurious)
spurious( bool const Spurious ) { {
std::lock_guard<std::mutex> lock( m_mutex ); std::lock_guard<std::mutex> lock(m_mutex);
m_spurious = Spurious; } m_spurious = Spurious;
}
private: private:
// members // members
mutable std::mutex m_mutex; mutable std::mutex m_mutex;
std::condition_variable m_condition; std::condition_variable m_condition;
bool m_spurious { true }; bool m_spurious{true};
}; };
} // threading } // namespace threading
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------