mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-03-22 15:05:03 +01:00
1213
application.cpp
1213
application.cpp
File diff suppressed because it is too large
Load Diff
@@ -444,6 +444,11 @@ driver_mode::on_key( int const Key, int const Scancode, int const Action, int co
|
||||
|
||||
// give the ui first shot at the input processing...
|
||||
if( !anyModifier && true == m_userinterface->on_key( Key, Action ) ) { return; }
|
||||
if (Key == (GLFW_MOD_SHIFT | GLFW_KEY_F12) && Action == GLFW_PRESS)
|
||||
{
|
||||
m_userinterface->showDebugUI();
|
||||
return;
|
||||
}
|
||||
// ...if the input is left untouched, pass it on
|
||||
if( true == m_input.keyboard.key( Key, Action ) ) { return; }
|
||||
|
||||
|
||||
@@ -87,6 +87,11 @@ void driver_ui::render_menu_contents() {
|
||||
}
|
||||
}
|
||||
|
||||
void driver_ui::showDebugUI()
|
||||
{
|
||||
m_debugpanel.is_open = !m_debugpanel.is_open;
|
||||
}
|
||||
|
||||
// potentially processes provided input key. returns: true if key was processed, false otherwise
|
||||
bool
|
||||
driver_ui::on_key( int const Key, int const Action ) {
|
||||
@@ -101,8 +106,7 @@ driver_ui::on_key( int const Key, int const Action ) {
|
||||
case GLFW_KEY_F10:
|
||||
case GLFW_KEY_F12: { // ui mode selectors
|
||||
|
||||
if( ( true == Global.ctrlState )
|
||||
|| ( true == Global.shiftState ) ) {
|
||||
if( ( true == Global.ctrlState )) {
|
||||
// only react to keys without modifiers
|
||||
return false;
|
||||
}
|
||||
@@ -157,10 +161,13 @@ driver_ui::on_key( int const Key, int const Action ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
case GLFW_KEY_F12: {
|
||||
case GLFW_KEY_F12 : {
|
||||
// debug panel
|
||||
m_debugpanel.is_open = !m_debugpanel.is_open;
|
||||
return true;
|
||||
if (Global.shiftState)
|
||||
{
|
||||
m_debugpanel.is_open = !m_debugpanel.is_open;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
default: {
|
||||
|
||||
@@ -27,6 +27,7 @@ public:
|
||||
// constructors
|
||||
driver_ui();
|
||||
// methods
|
||||
void showDebugUI() override;
|
||||
// potentially processes provided input key. returns: true if the input was processed, false otherwise
|
||||
bool
|
||||
on_key( int const Key, int const Action ) override;
|
||||
@@ -43,6 +44,7 @@ public:
|
||||
protected:
|
||||
void render_menu_contents() override;
|
||||
|
||||
|
||||
private:
|
||||
// methods
|
||||
// sets visibility of the cursor
|
||||
|
||||
672
editormode.cpp
672
editormode.cpp
@@ -21,238 +21,322 @@ http://mozilla.org/MPL/2.0/.
|
||||
#include "renderer.h"
|
||||
#include "AnimModel.h"
|
||||
|
||||
bool
|
||||
editor_mode::editormode_input::init() {
|
||||
bool editor_mode::editormode_input::init()
|
||||
{
|
||||
|
||||
return (
|
||||
mouse.init()
|
||||
&& keyboard.init() );
|
||||
return (mouse.init() && keyboard.init());
|
||||
}
|
||||
|
||||
void
|
||||
editor_mode::editormode_input::poll() {
|
||||
void 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
|
||||
bool
|
||||
editor_mode::init() {
|
||||
bool 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
|
||||
bool
|
||||
editor_mode::update() {
|
||||
bool editor_mode::update()
|
||||
{
|
||||
|
||||
Timer::UpdateTimers( true );
|
||||
Timer::UpdateTimers(true);
|
||||
|
||||
simulation::State.update_clocks();
|
||||
simulation::Environment.update();
|
||||
simulation::State.update_clocks();
|
||||
simulation::Environment.update();
|
||||
|
||||
// render time routines follow:
|
||||
auto const deltarealtime = Timer::GetDeltaRenderTime(); // nie uwzględnia pauzowania ani mnożenia czasu
|
||||
// render time routines follow:
|
||||
auto const deltarealtime = Timer::GetDeltaRenderTime(); // nie uwzględnia pauzowania ani mnożenia czasu
|
||||
|
||||
// fixed step render time routines:
|
||||
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 ) {
|
||||
// fixed step render time routines:
|
||||
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)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
Console::Update(); // to i tak trzeba wywoływać
|
||||
Console::Update(); // to i tak trzeba wywoływać
|
||||
#endif
|
||||
m_userinterface->update();
|
||||
// decelerate camera
|
||||
Camera.Velocity *= 0.65;
|
||||
if( std::abs( Camera.Velocity.x ) < 0.01 ) { 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; }
|
||||
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());
|
||||
|
||||
fTime50Hz -= 1.0 / 50.0;
|
||||
}
|
||||
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();
|
||||
|
||||
// variable step render time routines:
|
||||
update_camera( deltarealtime );
|
||||
if (!src)
|
||||
return;
|
||||
|
||||
simulation::Region->update_sounds();
|
||||
audio::renderer.update( Global.iPause ? 0.0 : deltarealtime );
|
||||
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;
|
||||
|
||||
GfxRenderer->Update( deltarealtime );
|
||||
// if (!m_dragging)
|
||||
// return;
|
||||
|
||||
simulation::is_ready = true;
|
||||
m_node = cloned;
|
||||
|
||||
return true;
|
||||
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
|
||||
Camera.Velocity *= 0.65;
|
||||
if (std::abs(Camera.Velocity.x) < 0.01)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
// variable step render time routines:
|
||||
update_camera(deltarealtime);
|
||||
|
||||
simulation::Region->update_sounds();
|
||||
audio::renderer.update(Global.iPause ? 0.0 : deltarealtime);
|
||||
|
||||
GfxRenderer->Update(deltarealtime);
|
||||
|
||||
simulation::is_ready = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
editor_mode::update_camera( double const Deltatime ) {
|
||||
void editor_mode::update_camera(double const Deltatime)
|
||||
{
|
||||
|
||||
// uwzględnienie ruchu wywołanego klawiszami
|
||||
Camera.Update();
|
||||
// reset window state, it'll be set again if applicable in a check below
|
||||
Global.CabWindowOpen = false;
|
||||
// all done, update camera position to the new value
|
||||
Global.pCamera = Camera;
|
||||
// uwzględnienie ruchu wywołanego klawiszami
|
||||
Camera.Update();
|
||||
// reset window state, it'll be set again if applicable in a check below
|
||||
Global.CabWindowOpen = false;
|
||||
// all done, update camera position to the new value
|
||||
Global.pCamera = Camera;
|
||||
}
|
||||
|
||||
// maintenance method, called when the mode is activated
|
||||
void
|
||||
editor_mode::enter() {
|
||||
void editor_mode::enter()
|
||||
{
|
||||
|
||||
m_statebackup = { Global.pCamera, FreeFlyModeFlag, Global.ControlPicking };
|
||||
m_statebackup = {Global.pCamera, FreeFlyModeFlag, Global.ControlPicking};
|
||||
|
||||
Camera = Global.pCamera;
|
||||
// NOTE: camera placement is effectively a copy of drivermode DistantView( true )
|
||||
// TBD, TODO: refactor into a common vehicle method?
|
||||
if( false == FreeFlyModeFlag ) {
|
||||
Camera = Global.pCamera;
|
||||
// NOTE: camera placement is effectively a copy of drivermode DistantView( true )
|
||||
// TBD, TODO: refactor into a common vehicle method?
|
||||
if (false == FreeFlyModeFlag)
|
||||
{
|
||||
|
||||
auto const *vehicle { Camera.m_owner };
|
||||
auto const cab {
|
||||
( vehicle->MoverParameters->CabOccupied == 0 ?
|
||||
1 :
|
||||
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.LookAt = vehicle->GetPosition();
|
||||
Camera.RaLook(); // jednorazowe przestawienie kamery
|
||||
FreeFlyModeFlag = true;
|
||||
}
|
||||
Global.ControlPicking = true;
|
||||
EditorModeFlag = true;
|
||||
auto const *vehicle{Camera.m_owner};
|
||||
auto const cab{(vehicle->MoverParameters->CabOccupied == 0 ? 1 : 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.LookAt = vehicle->GetPosition();
|
||||
Camera.RaLook(); // jednorazowe przestawienie kamery
|
||||
FreeFlyModeFlag = true;
|
||||
}
|
||||
Global.ControlPicking = true;
|
||||
EditorModeFlag = true;
|
||||
|
||||
Application.set_cursor( GLFW_CURSOR_NORMAL );
|
||||
Application.set_cursor(GLFW_CURSOR_NORMAL);
|
||||
}
|
||||
|
||||
// maintenance method, called when the mode is deactivated
|
||||
void
|
||||
editor_mode::exit() {
|
||||
void editor_mode::exit()
|
||||
{
|
||||
|
||||
EditorModeFlag = false;
|
||||
Global.ControlPicking = m_statebackup.picking;
|
||||
FreeFlyModeFlag = m_statebackup.freefly;
|
||||
Global.pCamera = m_statebackup.camera;
|
||||
EditorModeFlag = false;
|
||||
Global.ControlPicking = m_statebackup.picking;
|
||||
FreeFlyModeFlag = m_statebackup.freefly;
|
||||
Global.pCamera = m_statebackup.camera;
|
||||
|
||||
Application.set_cursor(
|
||||
( Global.ControlPicking ?
|
||||
GLFW_CURSOR_NORMAL :
|
||||
GLFW_CURSOR_DISABLED ) );
|
||||
Application.set_cursor((Global.ControlPicking ? GLFW_CURSOR_NORMAL : GLFW_CURSOR_DISABLED));
|
||||
|
||||
if( false == Global.ControlPicking ) {
|
||||
Application.set_cursor_pos( 0, 0 );
|
||||
}
|
||||
if (false == Global.ControlPicking)
|
||||
{
|
||||
Application.set_cursor_pos(0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
editor_mode::on_key( int const Key, int const Scancode, int const Action, int const Mods ) {
|
||||
void editor_mode::on_key(int const Key, int const Scancode, int const Action, int const Mods)
|
||||
{
|
||||
#ifndef __unix__
|
||||
Global.shiftState = (Mods & GLFW_MOD_SHIFT) ? true : false;
|
||||
Global.ctrlState = (Mods & GLFW_MOD_CONTROL) ? true : false;
|
||||
Global.altState = (Mods & GLFW_MOD_ALT) ? true : false;
|
||||
#endif
|
||||
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...
|
||||
if( !anyModifier && true == m_userinterface->on_key( Key, Action ) ) { return; }
|
||||
// ...if the input is left untouched, pass it on
|
||||
if( true == m_input.keyboard.key( Key, Action ) ) { return; }
|
||||
// give the ui first shot at the input processing...
|
||||
if (!anyModifier && true == m_userinterface->on_key(Key, Action))
|
||||
{
|
||||
return;
|
||||
}
|
||||
// ...if the input is left untouched, pass it on
|
||||
if (true == m_input.keyboard.key(Key, Action))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if( Action == GLFW_RELEASE ) { return; }
|
||||
if (Action == GLFW_RELEASE)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// legacy hardcoded keyboard commands
|
||||
// TODO: replace with current command system, move to input object(s)
|
||||
switch( Key ) {
|
||||
// legacy hardcoded keyboard commands
|
||||
// TODO: replace with current command system, move to input object(s)
|
||||
switch (Key)
|
||||
{
|
||||
|
||||
case GLFW_KEY_F11: {
|
||||
|
||||
if( Action != GLFW_PRESS ) { break; }
|
||||
// mode switch
|
||||
// TODO: unsaved changes warning
|
||||
if( ( false == Global.ctrlState )
|
||||
&& ( false == Global.shiftState ) ) {
|
||||
Application.pop_mode();
|
||||
}
|
||||
// scenery export
|
||||
if( Global.ctrlState
|
||||
&& Global.shiftState ) {
|
||||
simulation::State.export_as_text( Global.SceneryFile );
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case GLFW_KEY_F12: {
|
||||
// quick debug mode toggle
|
||||
if( Global.ctrlState
|
||||
&& Global.shiftState ) {
|
||||
DebugModeFlag = !DebugModeFlag;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// TODO: ensure delete method can play nice with history stack
|
||||
case GLFW_KEY_DELETE: {
|
||||
TAnimModel *model = dynamic_cast<TAnimModel*>(m_node);
|
||||
if (!model)
|
||||
break;
|
||||
|
||||
m_node = nullptr;
|
||||
m_dragging = false;
|
||||
//Application.set_cursor( GLFW_CURSOR_NORMAL );
|
||||
static_cast<editor_ui*>( m_userinterface.get() )->set_node(nullptr);
|
||||
|
||||
simulation::State.delete_model(model);
|
||||
case GLFW_KEY_F11:
|
||||
{
|
||||
|
||||
if (Action != GLFW_PRESS)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
// mode switch
|
||||
// TODO: unsaved changes warning
|
||||
if ((false == Global.ctrlState) && (false == Global.shiftState))
|
||||
{
|
||||
Application.pop_mode();
|
||||
}
|
||||
// scenery export
|
||||
if (Global.ctrlState && Global.shiftState)
|
||||
{
|
||||
simulation::State.export_as_text(Global.SceneryFile);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
case GLFW_KEY_F12:
|
||||
{
|
||||
// quick debug mode toggle
|
||||
if (Global.ctrlState && Global.shiftState)
|
||||
{
|
||||
DebugModeFlag = !DebugModeFlag;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// TODO: ensure delete method can play nice with history stack
|
||||
case GLFW_KEY_DELETE:
|
||||
{
|
||||
TAnimModel *model = dynamic_cast<TAnimModel *>(m_node);
|
||||
if (!model)
|
||||
break;
|
||||
|
||||
m_node = nullptr;
|
||||
m_dragging = false;
|
||||
// Application.set_cursor( GLFW_CURSOR_NORMAL );
|
||||
static_cast<editor_ui *>(m_userinterface.get())->set_node(nullptr);
|
||||
|
||||
simulation::State.delete_model(model);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
editor_mode::on_cursor_pos( double const Horizontal, double const Vertical ) {
|
||||
void editor_mode::on_cursor_pos(double const Horizontal, double const Vertical)
|
||||
{
|
||||
|
||||
auto const mousemove { glm::dvec2{ Horizontal, Vertical } - m_input.mouse.position() };
|
||||
m_input.mouse.position( Horizontal, Vertical );
|
||||
auto const mousemove{glm::dvec2{Horizontal, Vertical} - m_input.mouse.position()};
|
||||
m_input.mouse.position(Horizontal, Vertical);
|
||||
|
||||
if( m_input.mouse.button( GLFW_MOUSE_BUTTON_LEFT ) == GLFW_RELEASE ) { return; }
|
||||
if( m_node == nullptr ) { return; }
|
||||
if (m_input.mouse.button(GLFW_MOUSE_BUTTON_LEFT) == GLFW_RELEASE)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (m_node == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if( m_takesnapshot ) {
|
||||
// take a snapshot of selected node(s)
|
||||
// TODO: implement this
|
||||
m_takesnapshot = false;
|
||||
}
|
||||
if (m_takesnapshot)
|
||||
{
|
||||
// take a snapshot of selected node(s)
|
||||
// TODO: implement this
|
||||
m_takesnapshot = false;
|
||||
}
|
||||
|
||||
if( mode_translation() ) {
|
||||
// move selected node
|
||||
if( mode_translation_vertical() ) {
|
||||
auto const translation { mousemove.y * -0.01f };
|
||||
m_editor.translate( m_node, translation );
|
||||
}
|
||||
else {
|
||||
auto const mouseworldposition { Camera.Pos + GfxRenderer->Mouse_Position() };
|
||||
m_editor.translate( m_node, mouseworldposition, mode_snap() );
|
||||
}
|
||||
}
|
||||
if (mode_translation())
|
||||
{
|
||||
// move selected node
|
||||
if (mode_translation_vertical())
|
||||
{
|
||||
auto const translation{mousemove.y * -0.01f};
|
||||
m_editor.translate(m_node, translation);
|
||||
}
|
||||
else
|
||||
{
|
||||
auto const mouseworldposition{Camera.Pos + GfxRenderer->Mouse_Position()};
|
||||
m_editor.translate(m_node, mouseworldposition, mode_snap());
|
||||
}
|
||||
}
|
||||
else if (mode_rotationY())
|
||||
{
|
||||
// rotate selected node
|
||||
// auto const rotation{glm::vec3{mousemove.y, mousemove.x, 0} * 0.25f};
|
||||
auto const rotation{glm::vec3{0, mousemove.x, 0} * 0.25f};
|
||||
auto const quantization{(mode_snap() ? 5.f : // TODO: put quantization value in a variable
|
||||
0.f)};
|
||||
0.f)};
|
||||
m_editor.rotate(m_node, rotation, quantization);
|
||||
}
|
||||
else if (mode_rotationZ())
|
||||
@@ -262,7 +346,7 @@ editor_mode::on_cursor_pos( double const Horizontal, double const Vertical ) {
|
||||
// auto const rotation{glm::vec3{mousemove.y, mousemove.x, 0} * 0.25f};
|
||||
auto const rotation{glm::vec3{0, 0, mousemove.x} * 0.25f};
|
||||
auto const quantization{(mode_snap() ? 5.f : // TODO: put quantization value in a variable
|
||||
0.f)};
|
||||
0.f)};
|
||||
m_editor.rotate(m_node, rotation, quantization);
|
||||
}
|
||||
else if (mode_rotationX())
|
||||
@@ -271,7 +355,7 @@ editor_mode::on_cursor_pos( double const Horizontal, double const Vertical ) {
|
||||
// auto const rotation{glm::vec3{mousemove.y, mousemove.x, 0} * 0.25f};
|
||||
auto const rotation{glm::vec3{mousemove.y, 0, 0} * 0.25f};
|
||||
auto const quantization{(mode_snap() ? 5.f : // TODO: put quantization value in a variable
|
||||
0.f)};
|
||||
0.f)};
|
||||
m_editor.rotate(m_node, rotation, quantization);
|
||||
}
|
||||
}
|
||||
@@ -307,161 +391,171 @@ editor_mode::on_mouse_button( int const Button, int const Action, int const Mods
|
||||
m_input.mouse.button( Button, Action );
|
||||
}
|
||||
*/
|
||||
void
|
||||
editor_mode::on_mouse_button( int const Button, int const Action, int const Mods ) {
|
||||
void editor_mode::on_mouse_button(int const Button, int const Action, int const Mods)
|
||||
{
|
||||
|
||||
// give the ui first shot at the input processing...
|
||||
if( true == m_userinterface->on_mouse_button( Button, Action ) ) { return; }
|
||||
// give the ui first shot at the input processing...
|
||||
|
||||
if( Button == GLFW_MOUSE_BUTTON_LEFT ) {
|
||||
|
||||
if( Action == GLFW_PRESS ) {
|
||||
// left button press
|
||||
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();
|
||||
|
||||
m_node = nullptr;
|
||||
|
||||
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::MODIFY) {
|
||||
if (!m_dragging)
|
||||
return;
|
||||
|
||||
m_node = node;
|
||||
//if( m_node )
|
||||
//Application.set_cursor( GLFW_CURSOR_DISABLED );
|
||||
//else
|
||||
//m_dragging = false;
|
||||
ui->set_node(m_node);
|
||||
}
|
||||
else if (mode == nodebank_panel::COPY) {
|
||||
if (node && typeid(*node) == typeid(TAnimModel)) {
|
||||
std::string as_text;
|
||||
node->export_as_text(as_text);
|
||||
|
||||
ui->add_node_template(as_text);
|
||||
}
|
||||
|
||||
m_dragging = false;
|
||||
}
|
||||
else if (mode == nodebank_panel::ADD) {
|
||||
const std::string *src = ui->get_active_node_template();
|
||||
std::string name = "editor_" + std::to_string(LocalRandom(0.0, 100000.0));
|
||||
|
||||
if (!src)
|
||||
return;
|
||||
|
||||
TAnimModel *cloned = simulation::State.create_model(*src, name, Camera.Pos + GfxRenderer->Mouse_Position());
|
||||
|
||||
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 );
|
||||
}
|
||||
});
|
||||
|
||||
m_dragging = true;
|
||||
}
|
||||
else {
|
||||
// left button release
|
||||
//if( m_node )
|
||||
//Application.set_cursor( GLFW_CURSOR_NORMAL );
|
||||
m_dragging = false;
|
||||
// prime history stack for another snapshot
|
||||
m_takesnapshot = true;
|
||||
}
|
||||
}
|
||||
if (Button == GLFW_MOUSE_BUTTON_RIGHT)
|
||||
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
|
||||
auto const mode = static_cast<editor_ui *>(m_userinterface.get())->mode();
|
||||
|
||||
mouseHold = true;
|
||||
m_node = nullptr;
|
||||
|
||||
GfxRenderer->Pick_Node_Callback([this, mode](scene::basic_node *node) {
|
||||
editor_ui *ui = static_cast<editor_ui *>(m_userinterface.get());
|
||||
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::MODIFY)
|
||||
{
|
||||
if (!m_dragging)
|
||||
return;
|
||||
|
||||
if (mode == nodebank_panel::MODIFY)
|
||||
{
|
||||
if (!m_dragging)
|
||||
return;
|
||||
m_node = node;
|
||||
// if( m_node )
|
||||
// Application.set_cursor( GLFW_CURSOR_DISABLED );
|
||||
// else
|
||||
// m_dragging = false;
|
||||
ui->set_node(m_node);
|
||||
}
|
||||
else if (mode == nodebank_panel::COPY)
|
||||
{
|
||||
if (node && typeid(*node) == typeid(TAnimModel))
|
||||
{
|
||||
std::string as_text;
|
||||
node->export_as_text(as_text);
|
||||
|
||||
m_node = node;
|
||||
if (m_node)
|
||||
Application.set_cursor(GLFW_CURSOR_DISABLED);
|
||||
else
|
||||
m_dragging = false;
|
||||
ui->set_node(m_node);
|
||||
}
|
||||
});
|
||||
ui->add_node_template(as_text);
|
||||
}
|
||||
|
||||
m_dragging = false;
|
||||
}
|
||||
else if (mode == nodebank_panel::ADD)
|
||||
{
|
||||
const std::string *src = ui->get_active_node_template();
|
||||
std::string name = "editor_" + generate_uuid_v4();
|
||||
|
||||
if (!src)
|
||||
return;
|
||||
|
||||
TAnimModel *cloned = simulation::State.create_model(*src, name, Camera.Pos + GfxRenderer->Mouse_Position());
|
||||
|
||||
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);
|
||||
}
|
||||
});
|
||||
|
||||
m_dragging = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Action == GLFW_RELEASE)
|
||||
mouseHold = false;
|
||||
|
||||
// left button release
|
||||
if (m_node)
|
||||
Application.set_cursor(GLFW_CURSOR_NORMAL);
|
||||
// if( m_node )
|
||||
// Application.set_cursor( GLFW_CURSOR_NORMAL );
|
||||
m_dragging = false;
|
||||
// prime history stack for another snapshot
|
||||
m_takesnapshot = true;
|
||||
}
|
||||
}
|
||||
if (Button == GLFW_MOUSE_BUTTON_RIGHT)
|
||||
{
|
||||
|
||||
/*if (Action == GLFW_PRESS)
|
||||
{
|
||||
// left button press
|
||||
auto const mode = static_cast<editor_ui *>(m_userinterface.get())->mode();
|
||||
|
||||
m_node = nullptr;
|
||||
|
||||
GfxRenderer->Pick_Node_Callback([this, mode](scene::basic_node *node) {
|
||||
editor_ui *ui = static_cast<editor_ui *>(m_userinterface.get());
|
||||
|
||||
if (mode == nodebank_panel::MODIFY)
|
||||
{
|
||||
if (!m_dragging)
|
||||
return;
|
||||
|
||||
m_node = node;
|
||||
if (m_node)
|
||||
Application.set_cursor(GLFW_CURSOR_DISABLED);
|
||||
else
|
||||
m_dragging = false;
|
||||
ui->set_node(m_node);
|
||||
}
|
||||
});
|
||||
|
||||
m_dragging = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// left button release
|
||||
if (m_node)
|
||||
Application.set_cursor(GLFW_CURSOR_NORMAL);
|
||||
m_dragging = false;
|
||||
// prime history stack for another snapshot
|
||||
m_takesnapshot = true;
|
||||
}*/
|
||||
}
|
||||
|
||||
m_input.mouse.button( Button, Action );
|
||||
m_input.mouse.button(Button, Action);
|
||||
}
|
||||
|
||||
void
|
||||
editor_mode::on_event_poll() {
|
||||
void editor_mode::on_event_poll()
|
||||
{
|
||||
|
||||
m_input.poll();
|
||||
m_input.poll();
|
||||
}
|
||||
|
||||
bool
|
||||
editor_mode::is_command_processor() const {
|
||||
bool editor_mode::is_command_processor() const
|
||||
{
|
||||
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
editor_mode::mode_translation() const {
|
||||
bool editor_mode::mode_translation() const
|
||||
{
|
||||
|
||||
return ( false == Global.altState );
|
||||
return (false == Global.altState);
|
||||
}
|
||||
|
||||
bool
|
||||
editor_mode::mode_translation_vertical() const {
|
||||
bool editor_mode::mode_translation_vertical() const
|
||||
{
|
||||
|
||||
return ( true == Global.shiftState );
|
||||
return (true == Global.shiftState);
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
bool
|
||||
editor_mode::mode_snap() const {
|
||||
bool 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));
|
||||
}
|
||||
|
||||
120
editormode.h
120
editormode.h
@@ -16,68 +16,72 @@ http://mozilla.org/MPL/2.0/.
|
||||
#include "sceneeditor.h"
|
||||
#include "scenenode.h"
|
||||
|
||||
class editor_mode : public application_mode {
|
||||
class editor_mode : public application_mode
|
||||
{
|
||||
|
||||
public:
|
||||
// constructors
|
||||
editor_mode();
|
||||
// methods
|
||||
// initializes internal data structures of the mode. returns: true on success, false otherwise
|
||||
bool init() override;
|
||||
// mode-specific update of simulation data. returns: false on error, true otherwise
|
||||
bool update() override;
|
||||
// maintenance method, called when the mode is activated
|
||||
void enter() override;
|
||||
// maintenance method, called when the mode is deactivated
|
||||
void exit() override;
|
||||
// input handlers
|
||||
void on_key( int Key, int Scancode, int Action, int Mods ) override;
|
||||
void on_cursor_pos( double Horizontal, double Vertical ) override;
|
||||
void on_mouse_button( int Button, int Action, int Mods ) override;
|
||||
void on_scroll( double const Xoffset, double const Yoffset ) override { ; }
|
||||
void on_window_resize( int w, int h ) override { ; }
|
||||
void on_event_poll() override;
|
||||
bool is_command_processor() const override;
|
||||
public:
|
||||
// constructors
|
||||
editor_mode();
|
||||
// methods
|
||||
// initializes internal data structures of the mode. returns: true on success, false otherwise
|
||||
bool init() override;
|
||||
// mode-specific update of simulation data. returns: false on error, true otherwise
|
||||
bool update() override;
|
||||
// maintenance method, called when the mode is activated
|
||||
void enter() override;
|
||||
// maintenance method, called when the mode is deactivated
|
||||
void exit() override;
|
||||
// input handlers
|
||||
void on_key(int Key, int Scancode, int Action, int Mods) override;
|
||||
void on_cursor_pos(double Horizontal, double Vertical) override;
|
||||
void on_mouse_button(int Button, int Action, int Mods) override;
|
||||
void on_scroll(double const Xoffset, double const Yoffset) override
|
||||
{
|
||||
;
|
||||
}
|
||||
void on_window_resize(int w, int h) override
|
||||
{
|
||||
;
|
||||
}
|
||||
void on_event_poll() override;
|
||||
bool is_command_processor() const override;
|
||||
|
||||
private:
|
||||
// types
|
||||
struct editormode_input {
|
||||
private:
|
||||
// types
|
||||
struct editormode_input
|
||||
{
|
||||
|
||||
editormouse_input mouse;
|
||||
editorkeyboard_input keyboard;
|
||||
editormouse_input mouse;
|
||||
editorkeyboard_input keyboard;
|
||||
|
||||
bool init();
|
||||
void poll();
|
||||
};
|
||||
bool init();
|
||||
void poll();
|
||||
};
|
||||
|
||||
struct state_backup {
|
||||
struct state_backup
|
||||
{
|
||||
|
||||
TCamera camera;
|
||||
bool freefly;
|
||||
bool picking;
|
||||
};
|
||||
// methods
|
||||
void
|
||||
update_camera( double const Deltatime );
|
||||
bool
|
||||
mode_translation() const;
|
||||
bool
|
||||
mode_translation_vertical() const;
|
||||
bool
|
||||
mode_rotationY() const;
|
||||
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
|
||||
editormode_input m_input;
|
||||
TCamera Camera;
|
||||
double fTime50Hz { 0.0 }; // bufor czasu dla komunikacji z PoKeys
|
||||
scene::basic_editor m_editor;
|
||||
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_dragging = false;
|
||||
TCamera camera;
|
||||
bool freefly;
|
||||
bool picking;
|
||||
};
|
||||
// methods
|
||||
void update_camera(double const Deltatime);
|
||||
bool mode_translation() const;
|
||||
bool mode_translation_vertical() const;
|
||||
bool mode_rotationY() const;
|
||||
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
|
||||
editormode_input m_input;
|
||||
TCamera Camera;
|
||||
double fTime50Hz{0.0}; // bufor czasu dla komunikacji z PoKeys
|
||||
scene::basic_editor m_editor;
|
||||
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_dragging = false;
|
||||
glm::vec3 oldPos;
|
||||
bool mouseHold{false};
|
||||
};
|
||||
|
||||
@@ -14,64 +14,68 @@ http://mozilla.org/MPL/2.0/.
|
||||
#include "scenenode.h"
|
||||
#include "renderer.h"
|
||||
|
||||
editor_ui::editor_ui() {
|
||||
editor_ui::editor_ui()
|
||||
{
|
||||
|
||||
clear_panels();
|
||||
// bind the panels with ui object. maybe not the best place for this but, eh
|
||||
clear_panels();
|
||||
// bind the panels with ui object. maybe not the best place for this but, eh
|
||||
|
||||
add_external_panel( &m_itempropertiespanel );
|
||||
add_external_panel( &m_nodebankpanel );
|
||||
add_external_panel( &m_functionspanel );
|
||||
add_external_panel(&m_itempropertiespanel);
|
||||
add_external_panel(&m_nodebankpanel);
|
||||
add_external_panel(&m_functionspanel);
|
||||
}
|
||||
|
||||
// updates state of UI elements
|
||||
void
|
||||
editor_ui::update() {
|
||||
void editor_ui::update()
|
||||
{
|
||||
|
||||
set_tooltip( "" );
|
||||
set_tooltip("");
|
||||
|
||||
if( Global.ControlPicking && DebugModeFlag ) {
|
||||
const auto sceneryNode = GfxRenderer->Pick_Node();
|
||||
if (Global.ControlPicking && DebugModeFlag)
|
||||
{
|
||||
const auto sceneryNode = GfxRenderer->Pick_Node();
|
||||
const std::string content = sceneryNode ? sceneryNode->tooltip() : "";
|
||||
set_tooltip(content);
|
||||
}
|
||||
set_tooltip(content);
|
||||
}
|
||||
|
||||
ui_layer::update();
|
||||
m_itempropertiespanel.update( m_node );
|
||||
m_functionspanel.update( m_node );
|
||||
ui_layer::update();
|
||||
m_itempropertiespanel.update(m_node);
|
||||
m_functionspanel.update(m_node);
|
||||
}
|
||||
|
||||
void
|
||||
editor_ui::set_node( scene::basic_node * Node ) {
|
||||
|
||||
m_node = Node;
|
||||
void editor_ui::set_node(scene::basic_node *Node)
|
||||
{
|
||||
m_node = Node;
|
||||
}
|
||||
|
||||
void
|
||||
editor_ui::add_node_template(const std::string &desc) {
|
||||
void editor_ui::add_node_template(const std::string &desc)
|
||||
{
|
||||
m_nodebankpanel.add_template(desc);
|
||||
}
|
||||
|
||||
std::string const *
|
||||
editor_ui::get_active_node_template() {
|
||||
std::string const *editor_ui::get_active_node_template()
|
||||
{
|
||||
return m_nodebankpanel.get_active_template();
|
||||
}
|
||||
|
||||
nodebank_panel::edit_mode
|
||||
editor_ui::mode() {
|
||||
nodebank_panel::edit_mode editor_ui::mode()
|
||||
{
|
||||
return m_nodebankpanel.mode;
|
||||
}
|
||||
float editor_ui::getSpacing()
|
||||
{
|
||||
return m_nodebankpanel.spacing;
|
||||
}
|
||||
|
||||
functions_panel::rotation_mode
|
||||
editor_ui::rot_mode() {
|
||||
functions_panel::rotation_mode editor_ui::rot_mode()
|
||||
{
|
||||
return m_functionspanel.rot_mode;
|
||||
}
|
||||
float
|
||||
editor_ui::rot_val() {
|
||||
float editor_ui::rot_val()
|
||||
{
|
||||
return m_functionspanel.rot_value;
|
||||
}
|
||||
bool
|
||||
editor_ui::rot_from_last()
|
||||
bool editor_ui::rot_from_last()
|
||||
{
|
||||
return m_functionspanel.rot_from_last;
|
||||
}
|
||||
@@ -12,40 +12,35 @@ http://mozilla.org/MPL/2.0/.
|
||||
#include "uilayer.h"
|
||||
#include "editoruipanels.h"
|
||||
|
||||
namespace scene {
|
||||
namespace scene
|
||||
{
|
||||
|
||||
class basic_node;
|
||||
|
||||
}
|
||||
|
||||
class editor_ui : public ui_layer {
|
||||
class editor_ui : public ui_layer
|
||||
{
|
||||
|
||||
public:
|
||||
// constructors
|
||||
editor_ui();
|
||||
// methods
|
||||
// updates state of UI elements
|
||||
void
|
||||
update() override;
|
||||
void
|
||||
set_node( scene::basic_node * Node );
|
||||
void
|
||||
add_node_template(const std::string &desc);
|
||||
float
|
||||
rot_val();
|
||||
bool
|
||||
rot_from_last();
|
||||
functions_panel::rotation_mode
|
||||
rot_mode();
|
||||
const std::string *
|
||||
get_active_node_template();
|
||||
nodebank_panel::edit_mode
|
||||
mode();
|
||||
public:
|
||||
// constructors
|
||||
editor_ui();
|
||||
// methods
|
||||
// updates state of UI elements
|
||||
void update() override;
|
||||
void set_node(scene::basic_node *Node);
|
||||
void add_node_template(const std::string &desc);
|
||||
float rot_val();
|
||||
bool rot_from_last();
|
||||
functions_panel::rotation_mode rot_mode();
|
||||
const std::string *get_active_node_template();
|
||||
nodebank_panel::edit_mode mode();
|
||||
float getSpacing();
|
||||
|
||||
private:
|
||||
// members
|
||||
itemproperties_panel m_itempropertiespanel { "Node Properties", true };
|
||||
functions_panel m_functionspanel { "Functions", true };
|
||||
nodebank_panel m_nodebankpanel{ "Node Bank", true };
|
||||
scene::basic_node * m_node { nullptr }; // currently bound scene node, if any
|
||||
private:
|
||||
// members
|
||||
itemproperties_panel m_itempropertiespanel{"Node Properties", true};
|
||||
functions_panel m_functionspanel{"Functions", true};
|
||||
nodebank_panel m_nodebankpanel{"Node Bank", true};
|
||||
scene::basic_node *m_node{nullptr}; // currently bound scene node, if any
|
||||
};
|
||||
|
||||
@@ -17,346 +17,346 @@ http://mozilla.org/MPL/2.0/.
|
||||
#include "Track.h"
|
||||
#include "Event.h"
|
||||
#include "MemCell.h"
|
||||
#include "editoruilayer.h"
|
||||
#include "renderer.h"
|
||||
#include "utilities.h"
|
||||
|
||||
void
|
||||
itemproperties_panel::update( scene::basic_node const *Node ) {
|
||||
void itemproperties_panel::update(scene::basic_node const *Node)
|
||||
{
|
||||
m_node = Node;
|
||||
|
||||
if( false == is_open ) { return; }
|
||||
if (false == is_open)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
text_lines.clear();
|
||||
m_grouplines.clear();
|
||||
text_lines.clear();
|
||||
m_grouplines.clear();
|
||||
|
||||
std::string textline;
|
||||
std::string textline;
|
||||
|
||||
// scenario inspector
|
||||
auto const *node { Node };
|
||||
auto const &camera { Global.pCamera };
|
||||
// scenario inspector
|
||||
auto const *node{Node};
|
||||
auto const &camera{Global.pCamera};
|
||||
|
||||
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 ) + "]";
|
||||
text_lines.emplace_back( textline, Global.UITextColor );
|
||||
return;
|
||||
}
|
||||
/*
|
||||
// TODO: bind receiver in the constructor
|
||||
if( ( m_itemproperties != nullptr )
|
||||
&& ( m_itemproperties->node != nullptr ) ) {
|
||||
// fetch node data; skip properties which were changed until they're retrieved by the observer
|
||||
auto const *node { m_itemproperties->node };
|
||||
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) + "]";
|
||||
text_lines.emplace_back(textline, Global.UITextColor);
|
||||
return;
|
||||
}
|
||||
/*
|
||||
// TODO: bind receiver in the constructor
|
||||
if( ( m_itemproperties != nullptr )
|
||||
&& ( m_itemproperties->node != nullptr ) ) {
|
||||
// fetch node data; skip properties which were changed until they're retrieved by the observer
|
||||
auto const *node { m_itemproperties->node };
|
||||
|
||||
if( m_itemproperties->name.second == false ) {
|
||||
m_itemproperties->name.first = ( node->name().empty() ? "(none)" : node->name() );
|
||||
}
|
||||
if( m_itemproperties->location.second == false ) {
|
||||
m_itemproperties->location.first = node->location();
|
||||
}
|
||||
}
|
||||
*/
|
||||
textline =
|
||||
"name: " + ( node->name().empty() ? "(none)" : Bezogonkow( node->name() ) )
|
||||
+ "\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)";
|
||||
text_lines.emplace_back( textline, Global.UITextColor );
|
||||
if( m_itemproperties->name.second == false ) {
|
||||
m_itemproperties->name.first = ( node->name().empty() ? "(none)" : node->name() );
|
||||
}
|
||||
if( m_itemproperties->location.second == false ) {
|
||||
m_itemproperties->location.first = node->location();
|
||||
}
|
||||
}
|
||||
*/
|
||||
textline = "name: " + (node->name().empty() ? "(none)" : Bezogonkow(node->name())) + "\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)";
|
||||
text_lines.emplace_back(textline, Global.UITextColor);
|
||||
|
||||
// subclass-specific data
|
||||
// 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 ) ) {
|
||||
// subclass-specific data
|
||||
// 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))
|
||||
{
|
||||
|
||||
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, " +
|
||||
"angle_y: " + to_string(clamp_circular(subnode->vAngle.y, 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_z: " + to_string(clamp_circular(subnode->vAngle.z, 360.f), 2) + " deg";
|
||||
textline += ";\nlights: ";
|
||||
if( subnode->iNumLights > 0 ) {
|
||||
textline += '[';
|
||||
for( int lightidx = 0; lightidx < subnode->iNumLights; ++lightidx ) {
|
||||
textline += to_string( subnode->lsLights[ lightidx ] );
|
||||
if( lightidx < subnode->iNumLights - 1 ) {
|
||||
textline += ", ";
|
||||
}
|
||||
}
|
||||
textline += ']';
|
||||
}
|
||||
else {
|
||||
textline += "(none)";
|
||||
}
|
||||
text_lines.emplace_back( textline, Global.UITextColor );
|
||||
textline += ";\nlights: ";
|
||||
if (subnode->iNumLights > 0)
|
||||
{
|
||||
textline += '[';
|
||||
for (int lightidx = 0; lightidx < subnode->iNumLights; ++lightidx)
|
||||
{
|
||||
textline += to_string(subnode->lsLights[lightidx]);
|
||||
if (lightidx < subnode->iNumLights - 1)
|
||||
{
|
||||
textline += ", ";
|
||||
}
|
||||
}
|
||||
textline += ']';
|
||||
}
|
||||
else
|
||||
{
|
||||
textline += "(none)";
|
||||
}
|
||||
text_lines.emplace_back(textline, Global.UITextColor);
|
||||
|
||||
// 3d shape
|
||||
auto modelfile { (
|
||||
( subnode->pModel != nullptr ) ?
|
||||
subnode->pModel->NameGet() :
|
||||
"(none)" ) };
|
||||
if( modelfile.find( szModelPath ) == 0 ) {
|
||||
// don't include 'models/' in the path
|
||||
modelfile.erase( 0, std::string{ szModelPath }.size() );
|
||||
}
|
||||
// texture
|
||||
auto texturefile { (
|
||||
( subnode->Material()->replacable_skins[ 1 ] != null_handle ) ?
|
||||
GfxRenderer->Material( subnode->Material()->replacable_skins[ 1 ] )->GetName() :
|
||||
"(none)" ) };
|
||||
if( texturefile.find( szTexturePath ) == 0 ) {
|
||||
// don't include 'textures/' in the path
|
||||
texturefile.erase( 0, std::string{ szTexturePath }.size() );
|
||||
}
|
||||
text_lines.emplace_back( "mesh: " + modelfile, Global.UITextColor );
|
||||
text_lines.emplace_back( "skin: " + texturefile, Global.UITextColor );
|
||||
}
|
||||
else if( typeid( *node ) == typeid( TTrack ) ) {
|
||||
// 3d shape
|
||||
auto modelfile{((subnode->pModel != nullptr) ? subnode->pModel->NameGet() : "(none)")};
|
||||
if (modelfile.find(szModelPath) == 0)
|
||||
{
|
||||
// don't include 'models/' in the path
|
||||
modelfile.erase(0, std::string{szModelPath}.size());
|
||||
}
|
||||
// texture
|
||||
auto texturefile{((subnode->Material()->replacable_skins[1] != null_handle) ? GfxRenderer->Material(subnode->Material()->replacable_skins[1])->GetName() : "(none)")};
|
||||
if (texturefile.find(szTexturePath) == 0)
|
||||
{
|
||||
// don't include 'textures/' in the path
|
||||
texturefile.erase(0, std::string{szTexturePath}.size());
|
||||
}
|
||||
text_lines.emplace_back("mesh: " + modelfile, Global.UITextColor);
|
||||
text_lines.emplace_back("skin: " + texturefile, Global.UITextColor);
|
||||
}
|
||||
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;
|
||||
for (const TIsolated *iso : subnode->Isolated) {
|
||||
if (!isolatedlist.empty())
|
||||
isolatedlist += ", ";
|
||||
isolatedlist += iso->asName;
|
||||
}
|
||||
std::string isolatedlist;
|
||||
for (const TIsolated *iso : subnode->Isolated)
|
||||
{
|
||||
if (!isolatedlist.empty())
|
||||
isolatedlist += ", ";
|
||||
isolatedlist += iso->asName;
|
||||
}
|
||||
|
||||
// basic attributes
|
||||
textline =
|
||||
"isolated: " + ( !isolatedlist.empty() ? isolatedlist : "(none)" )
|
||||
+ "\nvelocity: " + to_string( subnode->SwitchExtension ? subnode->SwitchExtension->fVelocity : subnode->fVelocity )
|
||||
+ "\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
|
||||
auto texturefile { (
|
||||
( subnode->m_material1 != null_handle ) ?
|
||||
GfxRenderer->Material( subnode->m_material1 )->GetName() :
|
||||
"(none)" ) };
|
||||
if( texturefile.find( szTexturePath ) == 0 ) {
|
||||
texturefile.erase( 0, std::string{ szTexturePath }.size() );
|
||||
}
|
||||
auto texturefile2{ (
|
||||
( subnode->m_material2 != null_handle ) ?
|
||||
GfxRenderer->Material( subnode->m_material2 )->GetName() :
|
||||
"(none)" ) };
|
||||
if( texturefile2.find( szTexturePath ) == 0 ) {
|
||||
texturefile2.erase( 0, std::string{ szTexturePath }.size() );
|
||||
}
|
||||
textline = "skins:\n " + texturefile + "\n " + texturefile2;
|
||||
text_lines.emplace_back( textline, Global.UITextColor );
|
||||
// paths
|
||||
textline = "paths: ";
|
||||
for( auto const &path : subnode->m_paths ) {
|
||||
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 ].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 );
|
||||
// events
|
||||
textline.clear();
|
||||
// basic attributes
|
||||
textline = "isolated: " + (!isolatedlist.empty() ? isolatedlist : "(none)") + "\nvelocity: " + to_string(subnode->SwitchExtension ? subnode->SwitchExtension->fVelocity : subnode->fVelocity) +
|
||||
"\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
|
||||
auto texturefile{((subnode->m_material1 != null_handle) ? GfxRenderer->Material(subnode->m_material1)->GetName() : "(none)")};
|
||||
if (texturefile.find(szTexturePath) == 0)
|
||||
{
|
||||
texturefile.erase(0, std::string{szTexturePath}.size());
|
||||
}
|
||||
auto texturefile2{((subnode->m_material2 != null_handle) ? GfxRenderer->Material(subnode->m_material2)->GetName() : "(none)")};
|
||||
if (texturefile2.find(szTexturePath) == 0)
|
||||
{
|
||||
texturefile2.erase(0, std::string{szTexturePath}.size());
|
||||
}
|
||||
textline = "skins:\n " + texturefile + "\n " + texturefile2;
|
||||
text_lines.emplace_back(textline, Global.UITextColor);
|
||||
// paths
|
||||
textline = "paths: ";
|
||||
for (auto const &path : subnode->m_paths)
|
||||
{
|
||||
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].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);
|
||||
// events
|
||||
textline.clear();
|
||||
|
||||
std::vector< std::pair< std::string, TTrack::event_sequence const * > > const eventsequences {
|
||||
{ "ev0", &subnode->m_events0 }, { "ev0all", &subnode->m_events0all },
|
||||
{ "ev1", &subnode->m_events1 }, { "ev1all", &subnode->m_events1all },
|
||||
{ "ev2", &subnode->m_events2 }, { "ev2all", &subnode->m_events2all } };
|
||||
std::vector<std::pair<std::string, TTrack::event_sequence const *>> const eventsequences{{"ev0", &subnode->m_events0}, {"ev0all", &subnode->m_events0all},
|
||||
{"ev1", &subnode->m_events1}, {"ev1all", &subnode->m_events1all},
|
||||
{"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 + ": [";
|
||||
for( auto const &event : *( eventsequence.second ) ) {
|
||||
if( textline.back() != '[' ) {
|
||||
textline += ", ";
|
||||
}
|
||||
textline += (
|
||||
event.second != nullptr ?
|
||||
Bezogonkow( event.second->m_name ) :
|
||||
event.first + " (missing)" );
|
||||
}
|
||||
textline += "] ";
|
||||
}
|
||||
text_lines.emplace_back( textline, Global.UITextColor );
|
||||
}
|
||||
else if( typeid( *node ) == typeid( TMemCell ) ) {
|
||||
textline += (textline.empty() ? "" : "\n") + eventsequence.first + ": [";
|
||||
for (auto const &event : *(eventsequence.second))
|
||||
{
|
||||
if (textline.back() != '[')
|
||||
{
|
||||
textline += ", ";
|
||||
}
|
||||
textline += (event.second != nullptr ? Bezogonkow(event.second->m_name) : event.first + " (missing)");
|
||||
}
|
||||
textline += "] ";
|
||||
}
|
||||
text_lines.emplace_back(textline, Global.UITextColor);
|
||||
}
|
||||
else if (typeid(*node) == typeid(TMemCell))
|
||||
{
|
||||
|
||||
auto const *subnode = static_cast<TMemCell const *>( node );
|
||||
auto const *subnode = static_cast<TMemCell const *>(node);
|
||||
|
||||
textline =
|
||||
"data: [" + subnode->Text() + "]"
|
||||
+ " [" + to_string( subnode->Value1(), 2 ) + "]"
|
||||
+ " [" + to_string( subnode->Value2(), 2 ) + "]";
|
||||
text_lines.emplace_back( textline, Global.UITextColor );
|
||||
textline = "track: " + ( subnode->asTrackName.empty() ? "(none)" : Bezogonkow( subnode->asTrackName ) );
|
||||
text_lines.emplace_back( textline, Global.UITextColor );
|
||||
}
|
||||
textline = "data: [" + subnode->Text() + "]" + " [" + to_string(subnode->Value1(), 2) + "]" + " [" + to_string(subnode->Value2(), 2) + "]";
|
||||
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
|
||||
itemproperties_panel::update_group() {
|
||||
void itemproperties_panel::update_group()
|
||||
{
|
||||
|
||||
auto const grouphandle { m_node->group() };
|
||||
auto const grouphandle{m_node->group()};
|
||||
|
||||
if( grouphandle == null_handle ) {
|
||||
m_grouphandle = null_handle;
|
||||
m_groupprefix.clear();
|
||||
return;
|
||||
}
|
||||
if (grouphandle == null_handle)
|
||||
{
|
||||
m_grouphandle = null_handle;
|
||||
m_groupprefix.clear();
|
||||
return;
|
||||
}
|
||||
|
||||
auto const &nodegroup { scene::Groups.group( grouphandle ) };
|
||||
auto const &nodegroup{scene::Groups.group(grouphandle)};
|
||||
|
||||
if( m_grouphandle != grouphandle ) {
|
||||
// calculate group name from shared prefix of item names
|
||||
std::vector<std::reference_wrapper<std::string const>> names;
|
||||
// build list of custom item and event names
|
||||
for( auto const *node : nodegroup.nodes ) {
|
||||
auto const &name { node->name() };
|
||||
if( name.empty() || name == "none" ) { continue; }
|
||||
names.emplace_back( name );
|
||||
}
|
||||
for( auto const *event : nodegroup.events ) {
|
||||
auto const &name { event->m_name };
|
||||
if( name.empty() || name == "none" ) { continue; }
|
||||
names.emplace_back( name );
|
||||
}
|
||||
// find the common prefix
|
||||
if( names.size() > 1 ) {
|
||||
m_groupprefix = names.front();
|
||||
for( auto const &name : names ) {
|
||||
// NOTE: first calculation runs over two instances of the same name, but, eh
|
||||
auto const prefixlength{ len_common_prefix( m_groupprefix, name ) };
|
||||
if( prefixlength > 0 ) {
|
||||
m_groupprefix = m_groupprefix.substr( 0, prefixlength );
|
||||
}
|
||||
else {
|
||||
m_groupprefix.clear();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
// less than two names to compare means no prefix
|
||||
m_groupprefix.clear();
|
||||
}
|
||||
m_grouphandle = grouphandle;
|
||||
}
|
||||
if (m_grouphandle != grouphandle)
|
||||
{
|
||||
// calculate group name from shared prefix of item names
|
||||
std::vector<std::reference_wrapper<std::string const>> names;
|
||||
// build list of custom item and event names
|
||||
for (auto const *node : nodegroup.nodes)
|
||||
{
|
||||
auto const &name{node->name()};
|
||||
if (name.empty() || name == "none")
|
||||
{
|
||||
continue;
|
||||
}
|
||||
names.emplace_back(name);
|
||||
}
|
||||
for (auto const *event : nodegroup.events)
|
||||
{
|
||||
auto const &name{event->m_name};
|
||||
if (name.empty() || name == "none")
|
||||
{
|
||||
continue;
|
||||
}
|
||||
names.emplace_back(name);
|
||||
}
|
||||
// find the common prefix
|
||||
if (names.size() > 1)
|
||||
{
|
||||
m_groupprefix = names.front();
|
||||
for (auto const &name : names)
|
||||
{
|
||||
// NOTE: first calculation runs over two instances of the same name, but, eh
|
||||
auto const prefixlength{len_common_prefix(m_groupprefix, name)};
|
||||
if (prefixlength > 0)
|
||||
{
|
||||
m_groupprefix = m_groupprefix.substr(0, prefixlength);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_groupprefix.clear();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// less than two names to compare means no prefix
|
||||
m_groupprefix.clear();
|
||||
}
|
||||
m_grouphandle = grouphandle;
|
||||
}
|
||||
|
||||
m_grouplines.emplace_back(
|
||||
"nodes: " + to_string( static_cast<int>( nodegroup.nodes.size() ) )
|
||||
+ "\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 );
|
||||
m_grouplines.emplace_back("nodes: " + to_string(static_cast<int>(nodegroup.nodes.size())) + "\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
|
||||
itemproperties_panel::render() {
|
||||
if (false == is_open)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (true == text_lines.empty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if( false == is_open ) { return; }
|
||||
if( true == text_lines.empty() ) { return; }
|
||||
auto flags = ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoCollapse | (size.x > 0 ? ImGuiWindowFlags_NoResize : 0);
|
||||
|
||||
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 ) {
|
||||
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
|
||||
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() );
|
||||
}
|
||||
// group section
|
||||
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 const panelname{(title.empty() ? m_name : title) + "###" + m_name};
|
||||
if (true == ImGui::Begin(panelname.c_str(), nullptr, flags))
|
||||
{
|
||||
// header section
|
||||
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());
|
||||
}
|
||||
// group section
|
||||
render_group();
|
||||
}
|
||||
ImGui::End();
|
||||
}
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
bool
|
||||
itemproperties_panel::render_group() {
|
||||
bool itemproperties_panel::render_group()
|
||||
{
|
||||
|
||||
if( m_node == nullptr ) { return false; }
|
||||
if( m_grouplines.empty() ) { return false; }
|
||||
if (m_node == nullptr)
|
||||
{
|
||||
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 ) {
|
||||
ImGui::TextColored( ImVec4( line.color.r, line.color.g, line.color.b, line.color.a ), line.data.c_str() );
|
||||
}
|
||||
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());
|
||||
}
|
||||
|
||||
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};
|
||||
|
||||
|
||||
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 ) );
|
||||
memset(m_nodesearch, 0, sizeof(m_nodesearch));
|
||||
|
||||
std::ifstream file;
|
||||
file.open("nodebank.txt", std::ios_base::in | std::ios_base::binary);
|
||||
|
||||
std::string line;
|
||||
while( std::getline( file, line ) ) {
|
||||
if( line.size() < 4 ) {
|
||||
continue;
|
||||
}
|
||||
auto const labelend { line.find( "node" ) };
|
||||
auto const nodedata { (
|
||||
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 ) ) };
|
||||
while (std::getline(file, line))
|
||||
{
|
||||
if (line.size() < 4)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
auto const labelend{line.find("node")};
|
||||
auto const nodedata{(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))};
|
||||
|
||||
m_nodebank.push_back( { label, std::make_shared<std::string>( nodedata ) } );
|
||||
}
|
||||
// sort alphabetically content of each group
|
||||
auto groupbegin { m_nodebank.begin() };
|
||||
auto groupend { groupbegin };
|
||||
while( groupbegin != m_nodebank.end() ) {
|
||||
groupbegin =
|
||||
std::find_if(
|
||||
groupend, m_nodebank.end(),
|
||||
[]( auto const &Entry ) {
|
||||
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 ); } );
|
||||
}
|
||||
m_nodebank.push_back({label, std::make_shared<std::string>(nodedata)});
|
||||
}
|
||||
// sort alphabetically content of each group
|
||||
auto groupbegin{m_nodebank.begin()};
|
||||
auto groupend{groupbegin};
|
||||
while (groupbegin != m_nodebank.end())
|
||||
{
|
||||
groupbegin = std::find_if(groupend, m_nodebank.end(), [](auto const &Entry) { 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
|
||||
nodebank_panel::nodebank_reload(){
|
||||
void nodebank_panel::nodebank_reload()
|
||||
{
|
||||
m_nodebank.clear();
|
||||
std::ifstream file;
|
||||
file.open("nodebank.txt", std::ios_base::in | std::ios_base::binary);
|
||||
@@ -368,12 +368,8 @@ nodebank_panel::nodebank_reload(){
|
||||
continue;
|
||||
}
|
||||
auto const labelend{line.find("node")};
|
||||
auto const nodedata{
|
||||
(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 nodedata{(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))};
|
||||
|
||||
m_nodebank.push_back({label, std::make_shared<std::string>(nodedata)});
|
||||
}
|
||||
@@ -382,114 +378,117 @@ nodebank_panel::nodebank_reload(){
|
||||
auto groupend{groupbegin};
|
||||
while (groupbegin != m_nodebank.end())
|
||||
{
|
||||
groupbegin = std::find_if(groupend, m_nodebank.end(), [](auto const &Entry) {
|
||||
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); });
|
||||
groupbegin = std::find_if(groupend, m_nodebank.end(), [](auto const &Entry) { 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
|
||||
nodebank_panel::render() {
|
||||
void nodebank_panel::render()
|
||||
{
|
||||
|
||||
if( false == is_open ) { return; }
|
||||
if (false == is_open)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
auto flags =
|
||||
ImGuiWindowFlags_NoFocusOnAppearing
|
||||
| ImGuiWindowFlags_NoCollapse
|
||||
| ( size.x > 0 ? ImGuiWindowFlags_NoResize : 0 );
|
||||
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 ) {
|
||||
ImGui::SetNextWindowSizeConstraints( ImVec2S( size_min.x, size_min.y ), ImVec2S( size_max.x, size_max.y ) );
|
||||
}
|
||||
auto const panelname { (
|
||||
title.empty() ?
|
||||
name() :
|
||||
title )
|
||||
+ "###" + name() };
|
||||
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 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::SameLine();
|
||||
ImGui::RadioButton("Insert from bank", (int*)&mode, ADD);
|
||||
ImGui::RadioButton("Modify node", (int *)&mode, MODIFY);
|
||||
ImGui::SameLine();
|
||||
ImGui::RadioButton( "Copy to bank", (int*)&mode, COPY );
|
||||
ImGui::RadioButton("Insert from bank", (int *)&mode, ADD);
|
||||
ImGui::SameLine();
|
||||
ImGui::RadioButton("Brush mode", (int *)&mode, BRUSH);
|
||||
ImGui::SameLine();
|
||||
ImGui::RadioButton("Copy to bank", (int *)&mode, COPY);
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Reload Nodebank"))
|
||||
{
|
||||
nodebank_reload();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
ImGui::PushItemWidth(-1);
|
||||
ImGui::InputTextWithHint( "Search", "Search node bank", m_nodesearch, IM_ARRAYSIZE( m_nodesearch ) );
|
||||
if (ImGui::ListBoxHeader("##nodebank", ImVec2(-1, -1)))
|
||||
{
|
||||
auto idx { 0 };
|
||||
auto isvisible { false };
|
||||
auto const searchfilter { std::string( m_nodesearch ) };
|
||||
for (auto const &entry : m_nodebank) {
|
||||
if( entry.second->empty() ) {
|
||||
// special case, header indicator
|
||||
isvisible = ImGui::CollapsingHeader( entry.first.c_str() );
|
||||
}
|
||||
else {
|
||||
if( false == isvisible ) {
|
||||
continue;
|
||||
}
|
||||
if( ( false == searchfilter.empty() )
|
||||
&& ( false == contains( entry.first, searchfilter ) ) ) {
|
||||
continue;
|
||||
}
|
||||
auto const label { " " + entry.first + "##" + std::to_string( idx ) };
|
||||
if( ImGui::Selectable( label.c_str(), entry.second == m_selectedtemplate ) )
|
||||
m_selectedtemplate = entry.second;
|
||||
++idx;
|
||||
}
|
||||
}
|
||||
ImGui::ListBoxFooter();
|
||||
}
|
||||
}
|
||||
if (mode == BRUSH)
|
||||
{
|
||||
ImGui::SliderFloat("Spacing", &spacing, 0.1f, 20.0f, "%.1f m");
|
||||
}
|
||||
|
||||
ImGui::End();
|
||||
ImGui::PushItemWidth(-1);
|
||||
ImGui::InputTextWithHint("Search", "Search node bank", m_nodesearch, IM_ARRAYSIZE(m_nodesearch));
|
||||
if (ImGui::ListBoxHeader("##nodebank", ImVec2(-1, -1)))
|
||||
{
|
||||
auto idx{0};
|
||||
auto isvisible{false};
|
||||
auto const searchfilter{std::string(m_nodesearch)};
|
||||
for (auto const &entry : m_nodebank)
|
||||
{
|
||||
if (entry.second->empty())
|
||||
{
|
||||
// special case, header indicator
|
||||
isvisible = ImGui::CollapsingHeader(entry.first.c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
if (false == isvisible)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if ((false == searchfilter.empty()) && (false == contains(entry.first, searchfilter)))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
auto const label{" " + entry.first + "##" + std::to_string(idx)};
|
||||
if (ImGui::Selectable(label.c_str(), entry.second == m_selectedtemplate))
|
||||
m_selectedtemplate = entry.second;
|
||||
++idx;
|
||||
}
|
||||
}
|
||||
ImGui::ListBoxFooter();
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
void
|
||||
nodebank_panel::add_template(const std::string &desc) {
|
||||
void nodebank_panel::add_template(const std::string &desc)
|
||||
{
|
||||
|
||||
auto const label { generate_node_label( desc ) };
|
||||
m_nodebank.push_back( { label, std::make_shared<std::string>( desc ) } );
|
||||
auto const label{generate_node_label(desc)};
|
||||
m_nodebank.push_back({label, std::make_shared<std::string>(desc)});
|
||||
|
||||
std::ofstream file;
|
||||
file.open("nodebank.txt", std::ios_base::out | std::ios_base::app | std::ios_base::binary);
|
||||
file << label << " " << desc;
|
||||
}
|
||||
|
||||
const std::string *nodebank_panel::get_active_template() {
|
||||
const std::string *nodebank_panel::get_active_template()
|
||||
{
|
||||
return m_selectedtemplate.get();
|
||||
}
|
||||
|
||||
std::string
|
||||
nodebank_panel::generate_node_label( std::string Input ) const {
|
||||
std::string nodebank_panel::generate_node_label(std::string Input) const
|
||||
{
|
||||
|
||||
auto tokenizer{ cParser( Input ) };
|
||||
tokenizer.getTokens( 9, false ); // skip leading tokens
|
||||
auto model{ tokenizer.getToken<std::string>( false ) };
|
||||
auto texture{ tokenizer.getToken<std::string>( false ) };
|
||||
replace_slashes( model );
|
||||
erase_extension( model );
|
||||
replace_slashes( texture );
|
||||
return (
|
||||
texture == "none" ?
|
||||
model :
|
||||
model + " (" + texture + ")" );
|
||||
auto tokenizer{cParser(Input)};
|
||||
tokenizer.getTokens(9, false); // skip leading tokens
|
||||
auto model{tokenizer.getToken<std::string>(false)};
|
||||
auto texture{tokenizer.getToken<std::string>(false)};
|
||||
replace_slashes(model);
|
||||
erase_extension(model);
|
||||
replace_slashes(texture);
|
||||
return (texture == "none" ? model : model + " (" + texture + ")");
|
||||
}
|
||||
|
||||
void functions_panel::update(scene::basic_node const *Node)
|
||||
@@ -509,46 +508,43 @@ void functions_panel::update(scene::basic_node const *Node)
|
||||
// scenario inspector
|
||||
auto const *node{Node};
|
||||
auto const &camera{Global.pCamera};
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
functions_panel::render() {
|
||||
void functions_panel::render()
|
||||
{
|
||||
|
||||
if( false == is_open ) { return; }
|
||||
if (false == is_open)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
auto flags =
|
||||
ImGuiWindowFlags_NoFocusOnAppearing
|
||||
| ImGuiWindowFlags_NoCollapse
|
||||
| ( size.x > 0 ? ImGuiWindowFlags_NoResize : 0 );
|
||||
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)
|
||||
{
|
||||
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
|
||||
|
||||
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 const panelname { (
|
||||
title.empty() ?
|
||||
m_name :
|
||||
title )
|
||||
+ "###" + m_name };
|
||||
if( true == ImGui::Begin( panelname.c_str(), nullptr, flags ) ) {
|
||||
// header section
|
||||
|
||||
ImGui::RadioButton("Random rotation", (int *)&rot_mode, RANDOM);
|
||||
ImGui::RadioButton("Fixed rotation", (int *)&rot_mode, FIXED);
|
||||
if(rot_mode == FIXED){
|
||||
//ImGui::Checkbox("Get rotation from last object", &rot_from_last);
|
||||
if (rot_mode == FIXED)
|
||||
{
|
||||
// ImGui::Checkbox("Get rotation from last object", &rot_from_last);
|
||||
ImGui::SliderFloat("Rotation Value", &rot_value, 0.0f, 360.0f, "%.1f");
|
||||
};
|
||||
};
|
||||
ImGui::RadioButton("Default rotation", (int *)&rot_mode, DEFAULT);
|
||||
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::End();
|
||||
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::End();
|
||||
}
|
||||
@@ -26,52 +26,55 @@ struct item_properties {
|
||||
changeable<glm::vec3> rotation {};
|
||||
};
|
||||
*/
|
||||
class itemproperties_panel : public ui_panel {
|
||||
class itemproperties_panel : public ui_panel
|
||||
{
|
||||
|
||||
public:
|
||||
itemproperties_panel( std::string const &Name, bool const Isopen )
|
||||
: ui_panel( Name, Isopen )
|
||||
{}
|
||||
public:
|
||||
itemproperties_panel(std::string const &Name, bool const Isopen) : ui_panel(Name, Isopen) {}
|
||||
|
||||
void update( scene::basic_node const *Node );
|
||||
void update(scene::basic_node const *Node);
|
||||
void render() override;
|
||||
|
||||
private:
|
||||
// methods
|
||||
void update_group();
|
||||
private:
|
||||
// methods
|
||||
void update_group();
|
||||
bool render_group();
|
||||
|
||||
// members
|
||||
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
|
||||
std::string m_groupprefix;
|
||||
std::vector<text_line> m_grouplines;
|
||||
// members
|
||||
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
|
||||
std::string m_groupprefix;
|
||||
std::vector<text_line> m_grouplines;
|
||||
};
|
||||
|
||||
class nodebank_panel : public ui_panel {
|
||||
class nodebank_panel : public ui_panel
|
||||
{
|
||||
|
||||
public:
|
||||
enum edit_mode {
|
||||
public:
|
||||
enum edit_mode
|
||||
{
|
||||
MODIFY,
|
||||
COPY,
|
||||
ADD,
|
||||
BRUSH
|
||||
BRUSH
|
||||
};
|
||||
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 render() override;
|
||||
void add_template(const std::string &desc);
|
||||
const std::string* get_active_template();
|
||||
const std::string *get_active_template();
|
||||
|
||||
private:
|
||||
// methods:
|
||||
std::string generate_node_label( std::string Input ) const;
|
||||
// members:
|
||||
std::vector<std::pair<std::string, std::shared_ptr<std::string>>> m_nodebank;
|
||||
char m_nodesearch[ 128 ];
|
||||
std::shared_ptr<std::string> m_selectedtemplate;
|
||||
private:
|
||||
// methods:
|
||||
std::string generate_node_label(std::string Input) const;
|
||||
// members:
|
||||
std::vector<std::pair<std::string, std::shared_ptr<std::string>>> m_nodebank;
|
||||
char m_nodesearch[128];
|
||||
std::shared_ptr<std::string> m_selectedtemplate;
|
||||
};
|
||||
|
||||
class functions_panel : public ui_panel
|
||||
@@ -87,18 +90,16 @@ class functions_panel : public ui_panel
|
||||
rotation_mode rot_mode = DEFAULT;
|
||||
|
||||
float rot_value = 0.0f;
|
||||
bool rot_from_last = false;
|
||||
bool rot_from_last = false;
|
||||
|
||||
functions_panel(std::string const &Name, bool const Isopen) : ui_panel(Name, Isopen) {}
|
||||
|
||||
void update(scene::basic_node const *Node);
|
||||
void render() override;
|
||||
|
||||
|
||||
private:
|
||||
// methods
|
||||
|
||||
|
||||
// members
|
||||
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
|
||||
|
||||
@@ -25,6 +25,7 @@ layout(location = 1) out vec4 out_motion;
|
||||
#include <light_common.glsl>
|
||||
#include <apply_fog.glsl>
|
||||
#include <tonemapping.glsl>
|
||||
#include <random.glsl>
|
||||
|
||||
uniform sampler2D diffuse;
|
||||
uniform sampler2D raindropsatlas;
|
||||
@@ -34,10 +35,6 @@ uniform float specular_intensity = 1.0;
|
||||
uniform float wobble_strength = 0.002;
|
||||
uniform float wobble_speed = 30.0;
|
||||
|
||||
float hash(vec2 p) {
|
||||
return fract(sin(dot(p, vec2(12.9898, 78.233))) * 43758.5453);
|
||||
}
|
||||
|
||||
vec4 getDropTex(float choice, vec2 uv) {
|
||||
vec2 offset;
|
||||
if (choice < 0.25) offset = vec2(0.0, 0.0);
|
||||
@@ -54,13 +51,14 @@ void main() {
|
||||
if (tex_color.a < 0.01) discard;
|
||||
|
||||
vec2 rainCoord = f_coord;
|
||||
float gridSize = ceil(param[2].x);
|
||||
|
||||
const float numDrops = 20000.0;
|
||||
const float cycleDuration = 4.0;
|
||||
const float squareMin = 0.0035;
|
||||
const float squareMax = 0.008;
|
||||
|
||||
float squareMin = 0.5 / gridSize;
|
||||
float squareMax = 1.2 / gridSize;
|
||||
|
||||
float gridSize = ceil(param[2].x);
|
||||
vec2 cell = floor(rainCoord * gridSize);
|
||||
|
||||
vec3 dropLayer = vec3(0.0);
|
||||
@@ -76,37 +74,37 @@ void main() {
|
||||
float side;
|
||||
float mixFactor = GetMixFactor(neighborCenter, side);
|
||||
|
||||
if(mixFactor < hash(neighborCell + vec2(mix(0., .2137, side), 0.))) {
|
||||
uint seed = Hash(uvec3(neighborCell, side));
|
||||
|
||||
if(mixFactor < RandF(seed)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
float i = neighborCell.x + neighborCell.y * gridSize;
|
||||
|
||||
// Show a percentage of droplets given by rain intensity param
|
||||
float activationSeed = hash(vec2(i, 0.333 + side));
|
||||
float activationSeed = RandF(seed);
|
||||
if (activationSeed > rain_params.x)
|
||||
continue; // kropla nieaktywna
|
||||
|
||||
// Randomly modulate droplet center & size
|
||||
vec2 dropCenter = (neighborCell + vec2(hash(vec2(i, 0.12 + side)), hash(vec2(i, 0.34 + side)))) / gridSize;
|
||||
float squareSize = mix(squareMin, squareMax, hash(vec2(i, 0.56 + side)));
|
||||
vec2 dropCenter = (neighborCell + vec2(RandF(seed), RandF(seed))) / gridSize;
|
||||
float squareSize = mix(squareMin, squareMax, RandF(seed));
|
||||
|
||||
float lifeTime = time + hash(vec2(i, 0.78 + side)) * cycleDuration;
|
||||
float lifeTime = time + RandF(seed) * cycleDuration;
|
||||
float phase = fract(lifeTime / cycleDuration);
|
||||
float active = clamp(1.0 - phase, 0.0, 1.0);
|
||||
float actiwe = clamp(1.0 - phase, 0.0, 1.0);
|
||||
|
||||
// Gravity influence (TODO add vehicle speed & wind here!)
|
||||
float gravityStart = 0.5;
|
||||
float gravityPhase = smoothstep(gravityStart, 1.0, phase);
|
||||
float dropMass = mix(0.3, 1.2, hash(vec2(i, 0.21 + side)));
|
||||
float dropMass = mix(0.3, 1.2, RandF(seed));
|
||||
float gravitySpeed = 0.15 * dropMass;
|
||||
vec2 gravityOffset = vec2(0.0, gravityPhase * gravitySpeed * phase);
|
||||
|
||||
// Random wobble
|
||||
bool hasWobble = (hash(vec2(i, 0.91 + side)) < 0.10);
|
||||
bool hasWobble = (RandF(seed) < 0.10);
|
||||
vec2 wobbleOffset = vec2(0.0);
|
||||
if (hasWobble && gravityPhase > 0.0) {
|
||||
float intensity = sin(time * wobble_speed + i) * wobble_strength * gravityPhase;
|
||||
float intensity = sin(time * wobble_speed + RandF(seed) * 100.) * wobble_strength * gravityPhase;
|
||||
wobbleOffset = vec2(intensity, 0.0);
|
||||
}
|
||||
|
||||
@@ -125,7 +123,7 @@ void main() {
|
||||
|
||||
if (mask > 0.001) {
|
||||
vec2 localUV = (diff + squareSize * 0.5) / squareSize;
|
||||
float choice = hash(vec2(i, 0.99 + side));
|
||||
float choice = RandF(seed);
|
||||
vec4 dropTex = getDropTex(choice, localUV);
|
||||
float sharpAlpha = smoothstep(0.3, 0.9, dropTex.a);
|
||||
|
||||
@@ -139,15 +137,15 @@ void main() {
|
||||
|
||||
float sparkle = 0.0;
|
||||
if (hasWobble) {
|
||||
sparkle = pow(abs(sin(f_coord.x * 8.0 + time * 2.0 + hash(vec2(i, 0.9 + side)) * 6.2831)), 40.0)
|
||||
sparkle = pow(abs(sin(f_coord.x * 8.0 + time * 2.0 + RandF(seed) * 6.2831)), 40.0)
|
||||
* mix(0.2, 1.0, sunFactor);
|
||||
}
|
||||
|
||||
vec3 specularColor = vec3(1.0) * specular_intensity * sparkle;
|
||||
vec3 dropLit = dropTex.rgb * dynBright + specularColor * sharpAlpha;
|
||||
|
||||
dropLayer += dropLit * sharpAlpha * active * blackAlpha * mask;
|
||||
dropMaskSum += sharpAlpha * active * blackAlpha * mask;
|
||||
dropLayer += dropLit * sharpAlpha * actiwe * blackAlpha * mask;
|
||||
dropMaskSum += sharpAlpha * actiwe * blackAlpha * mask;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
337
uilayer.cpp
337
uilayer.cpp
@@ -23,7 +23,7 @@ http://mozilla.org/MPL/2.0/.
|
||||
|
||||
GLFWwindow *ui_layer::m_window{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;
|
||||
ImFont *ui_layer::font_default{nullptr};
|
||||
ImFont *ui_layer::font_mono{nullptr};
|
||||
@@ -33,8 +33,8 @@ ui_panel::ui_panel(std::string Identifier, bool const Isopen) : is_open(Isopen),
|
||||
|
||||
void ui_panel::render()
|
||||
{
|
||||
if (false == is_open)
|
||||
return;
|
||||
if (false == is_open)
|
||||
return;
|
||||
|
||||
int flags = window_flags;
|
||||
if (flags == -1)
|
||||
@@ -47,32 +47,30 @@ void ui_panel::render()
|
||||
if (pos.x != -1 && pos.y != -1)
|
||||
ImGui::SetNextWindowPos(ImVec2(pos.x, pos.y), ImGuiCond_Always);
|
||||
if (size.x > 0)
|
||||
ImGui::SetNextWindowSize(ImVec2S(size.x, size.y), ImGuiCond_Always);
|
||||
ImGui::SetNextWindowSize(ImVec2S(size.x, size.y), ImGuiCond_Always);
|
||||
else if (size_min.x == -1)
|
||||
ImGui::SetNextWindowSize(ImVec2(0, 0), ImGuiCond_FirstUseEver);
|
||||
ImGui::SetNextWindowSize(ImVec2(0, 0), ImGuiCond_FirstUseEver);
|
||||
|
||||
if (size_min.x > 0)
|
||||
ImGui::SetNextWindowSizeConstraints(ImVec2S(size_min.x, size_min.y), ImVec2S(size_max.x, size_max.y));
|
||||
if (size_min.x > 0)
|
||||
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};
|
||||
if (ImGui::Begin(panelname.c_str(), &is_open, flags)) {
|
||||
render_contents();
|
||||
if (ImGui::Begin(panelname.c_str(), &is_open, flags))
|
||||
{
|
||||
render_contents();
|
||||
|
||||
popups.remove_if([](const std::unique_ptr<ui::popup> &popup)
|
||||
{
|
||||
return popup->render();
|
||||
});
|
||||
popups.remove_if([](const std::unique_ptr<ui::popup> &popup) { return popup->render(); });
|
||||
}
|
||||
|
||||
ImGui::End();
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
void ui_panel::render_contents()
|
||||
{
|
||||
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());
|
||||
}
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
||||
void ui_panel::register_popup(std::unique_ptr<ui::popup> &&popup)
|
||||
@@ -82,17 +80,17 @@ void ui_panel::register_popup(std::unique_ptr<ui::popup> &&popup)
|
||||
|
||||
void ui_expandable_panel::render_contents()
|
||||
{
|
||||
ImGui::Checkbox(STR_C("expand"), &is_expanded);
|
||||
ui_panel::render_contents();
|
||||
ImGui::Checkbox(STR_C("expand"), &is_expanded);
|
||||
ui_panel::render_contents();
|
||||
}
|
||||
|
||||
void ui_log_panel::render_contents()
|
||||
{
|
||||
ImGui::PushFont(ui_layer::font_mono);
|
||||
|
||||
for (const std::string &s : log_scrollback)
|
||||
ImGui::TextUnformatted(s.c_str());
|
||||
if (ImGui::GetScrollY() == ImGui::GetScrollMaxY())
|
||||
for (const std::string &s : log_scrollback)
|
||||
ImGui::TextUnformatted(s.c_str());
|
||||
if (ImGui::GetScrollY() == ImGui::GetScrollMaxY())
|
||||
ImGui::SetScrollHereY(1.0f);
|
||||
|
||||
ImGui::PopFont();
|
||||
@@ -102,33 +100,33 @@ ui_layer::ui_layer()
|
||||
{
|
||||
if (Global.loading_log)
|
||||
add_external_panel(&m_logpanel);
|
||||
m_logpanel.size = { 700, 400 };
|
||||
m_logpanel.size = {700, 400};
|
||||
}
|
||||
|
||||
ui_layer::~ui_layer() {}
|
||||
|
||||
bool ui_layer::key_callback(int key, int scancode, int action, int mods)
|
||||
{
|
||||
ImGui_ImplGlfw_KeyCallback(m_window, key, scancode, action, mods);
|
||||
return m_imguiio->WantCaptureKeyboard;
|
||||
ImGui_ImplGlfw_KeyCallback(m_window, key, scancode, action, mods);
|
||||
return m_imguiio->WantCaptureKeyboard;
|
||||
}
|
||||
|
||||
bool ui_layer::char_callback(unsigned int c)
|
||||
{
|
||||
ImGui_ImplGlfw_CharCallback(m_window, c);
|
||||
return m_imguiio->WantCaptureKeyboard;
|
||||
ImGui_ImplGlfw_CharCallback(m_window, c);
|
||||
return m_imguiio->WantCaptureKeyboard;
|
||||
}
|
||||
|
||||
bool ui_layer::scroll_callback(double xoffset, double yoffset)
|
||||
{
|
||||
ImGui_ImplGlfw_ScrollCallback(m_window, xoffset, yoffset);
|
||||
return m_imguiio->WantCaptureMouse;
|
||||
ImGui_ImplGlfw_ScrollCallback(m_window, xoffset, yoffset);
|
||||
return m_imguiio->WantCaptureMouse;
|
||||
}
|
||||
|
||||
bool ui_layer::mouse_button_callback(int button, int action, int mods)
|
||||
{
|
||||
ImGui_ImplGlfw_MouseButtonCallback(m_window, button, action, mods);
|
||||
return m_imguiio->WantCaptureMouse;
|
||||
ImGui_ImplGlfw_MouseButtonCallback(m_window, button, action, mods);
|
||||
return m_imguiio->WantCaptureMouse;
|
||||
}
|
||||
|
||||
void ui_layer::load_random_background()
|
||||
@@ -138,20 +136,21 @@ void ui_layer::load_random_background()
|
||||
if (f.is_regular_file())
|
||||
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))];
|
||||
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);
|
||||
}
|
||||
|
||||
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_TextDisabled] = ImVec4(0.35f, 0.35f, 0.35f, 1.00f);
|
||||
@@ -204,29 +203,28 @@ void ui_layer::imgui_style()
|
||||
colors[ImGuiCol_TabUnfocused] = imvec_lerp(colors[ImGuiCol_Tab], colors[ImGuiCol_TitleBg], 0.80f);
|
||||
colors[ImGuiCol_TabUnfocusedActive] = imvec_lerp(colors[ImGuiCol_TabActive], colors[ImGuiCol_TitleBg], 0.40f);
|
||||
|
||||
ImGui::GetStyle().ScaleAllSizes(Global.ui_scale);
|
||||
ImGui::GetStyle().ScaleAllSizes(Global.ui_scale);
|
||||
}
|
||||
|
||||
bool ui_layer::init(GLFWwindow *Window)
|
||||
{
|
||||
m_window = Window;
|
||||
m_window = Window;
|
||||
|
||||
IMGUI_CHECKVERSION();
|
||||
ImGui::CreateContext();
|
||||
m_imguiio = &ImGui::GetIO();
|
||||
IMGUI_CHECKVERSION();
|
||||
ImGui::CreateContext();
|
||||
m_imguiio = &ImGui::GetIO();
|
||||
|
||||
m_imguiio->ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange;
|
||||
// m_imguiio->ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;
|
||||
// m_imguiio->ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad;
|
||||
// m_imguiio->ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;
|
||||
// m_imguiio->ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad;
|
||||
|
||||
static const ImWchar ranges[] =
|
||||
{
|
||||
0x0020, 0x00FF, // Basic Latin + Latin Supplement
|
||||
0x0100, 0x017F, // Latin Extended-A
|
||||
0x2070, 0x2079, // superscript
|
||||
0x2500, 0x256C, // box drawings
|
||||
0,
|
||||
};
|
||||
static const ImWchar ranges[] = {
|
||||
0x0020, 0x00FF, // Basic Latin + Latin Supplement
|
||||
0x0100, 0x017F, // Latin Extended-A
|
||||
0x2070, 0x2079, // superscript
|
||||
0x2500, 0x256C, // box drawings
|
||||
0,
|
||||
};
|
||||
|
||||
if (FileExists("fonts/dejavusans.ttf"))
|
||||
font_default = m_imguiio->Fonts->AddFontFromFileTTF("fonts/dejavusans.ttf", Global.ui_fontsize, nullptr, &ranges[0]);
|
||||
@@ -246,67 +244,73 @@ bool ui_layer::init(GLFWwindow *Window)
|
||||
|
||||
imgui_style();
|
||||
|
||||
ImGui_ImplGlfw_InitForOpenGL(m_window, false);
|
||||
ImGui_ImplGlfw_InitForOpenGL(m_window, false);
|
||||
|
||||
if (!GfxRenderer->GetImguiRenderer() || !GfxRenderer->GetImguiRenderer()->Init())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (!GfxRenderer->GetImguiRenderer() || !GfxRenderer->GetImguiRenderer()->Init())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
void ui_layer::shutdown()
|
||||
{
|
||||
ImGui::EndFrame();
|
||||
ImGui::EndFrame();
|
||||
|
||||
GfxRenderer->GetImguiRenderer()->Shutdown();
|
||||
ImGui_ImplGlfw_Shutdown();
|
||||
ImGui::DestroyContext();
|
||||
GfxRenderer->GetImguiRenderer()->Shutdown();
|
||||
ImGui_ImplGlfw_Shutdown();
|
||||
ImGui::DestroyContext();
|
||||
}
|
||||
|
||||
bool ui_layer::on_key(int const Key, int const Action)
|
||||
{
|
||||
if (Action == GLFW_PRESS)
|
||||
{
|
||||
if (Key == GLFW_KEY_PRINT_SCREEN) {
|
||||
Application.queue_screenshot();
|
||||
return true;
|
||||
}
|
||||
if (Action == GLFW_PRESS)
|
||||
{
|
||||
if (Key == GLFW_KEY_PRINT_SCREEN)
|
||||
{
|
||||
Application.queue_screenshot();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (Key == GLFW_KEY_F9) {
|
||||
m_logpanel.is_open = !m_logpanel.is_open;
|
||||
return true;
|
||||
}
|
||||
if (Key == GLFW_KEY_F9)
|
||||
{
|
||||
m_logpanel.is_open = !m_logpanel.is_open;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (Key == GLFW_KEY_F10) {
|
||||
m_quit_active = !m_quit_active;
|
||||
return true;
|
||||
}
|
||||
if (Key == GLFW_KEY_F10)
|
||||
{
|
||||
m_quit_active = !m_quit_active;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (m_quit_active)
|
||||
{
|
||||
if (Key == GLFW_KEY_Y) {
|
||||
Application.queue_quit(false);
|
||||
return true;
|
||||
} else if (Key == GLFW_KEY_N) {
|
||||
m_quit_active = false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (m_quit_active)
|
||||
{
|
||||
if (Key == GLFW_KEY_Y)
|
||||
{
|
||||
Application.queue_quit(false);
|
||||
return true;
|
||||
}
|
||||
else if (Key == GLFW_KEY_N)
|
||||
{
|
||||
m_quit_active = false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ui_layer::on_cursor_pos(double const Horizontal, double const Vertical)
|
||||
{
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ui_layer::on_mouse_button(int const Button, int const Action)
|
||||
{
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
|
||||
void ui_layer::on_window_resize(int w, int h)
|
||||
@@ -315,13 +319,13 @@ void ui_layer::on_window_resize(int w, int h)
|
||||
panel->on_window_resize(w, h);
|
||||
}
|
||||
|
||||
|
||||
void ui_layer::update()
|
||||
{
|
||||
for (auto *panel : m_panels)
|
||||
panel->update();
|
||||
for (auto *panel : m_panels)
|
||||
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();
|
||||
if (!(*it)->is_open)
|
||||
m_ownedpanels.erase(std::next(it).base());
|
||||
@@ -330,27 +334,27 @@ void ui_layer::update()
|
||||
|
||||
void ui_layer::render()
|
||||
{
|
||||
render_background();
|
||||
render_panels();
|
||||
render_tooltip();
|
||||
render_menu();
|
||||
render_quit_widget();
|
||||
render_background();
|
||||
render_panels();
|
||||
render_tooltip();
|
||||
render_menu();
|
||||
render_quit_widget();
|
||||
|
||||
// template method implementation
|
||||
render_();
|
||||
// template method implementation
|
||||
render_();
|
||||
|
||||
render_internal();
|
||||
render_internal();
|
||||
}
|
||||
|
||||
void ui_layer::render_internal()
|
||||
{
|
||||
ImGui::Render();
|
||||
GfxRenderer->GetImguiRenderer()->Render();
|
||||
ImGui::Render();
|
||||
GfxRenderer->GetImguiRenderer()->Render();
|
||||
}
|
||||
|
||||
void ui_layer::begin_ui_frame()
|
||||
{
|
||||
begin_ui_frame_internal();
|
||||
begin_ui_frame_internal();
|
||||
}
|
||||
|
||||
void ui_layer::begin_ui_frame_internal()
|
||||
@@ -362,25 +366,25 @@ void ui_layer::begin_ui_frame_internal()
|
||||
|
||||
void ui_layer::render_quit_widget()
|
||||
{
|
||||
if (!m_quit_active)
|
||||
return;
|
||||
if (!m_quit_active)
|
||||
return;
|
||||
|
||||
ImGui::SetNextWindowSize(ImVec2(0, 0));
|
||||
ImGui::Begin(STR_C("Quit"), &m_quit_active, ImGuiWindowFlags_NoResize);
|
||||
ImGui::TextUnformatted(STR_C("Quit simulation?"));
|
||||
if (ImGui::Button(STR_C("Yes")))
|
||||
Application.queue_quit(false);
|
||||
ImGui::SetNextWindowSize(ImVec2(0, 0));
|
||||
ImGui::Begin(STR_C("Quit"), &m_quit_active, ImGuiWindowFlags_NoResize);
|
||||
ImGui::TextUnformatted(STR_C("Quit simulation?"));
|
||||
if (ImGui::Button(STR_C("Yes")))
|
||||
Application.queue_quit(false);
|
||||
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button(STR_C("No")))
|
||||
m_quit_active = false;
|
||||
ImGui::End();
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button(STR_C("No")))
|
||||
m_quit_active = false;
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
void ui_layer::set_cursor(int const Mode)
|
||||
{
|
||||
glfwSetInputMode(m_window, GLFW_CURSOR, Mode);
|
||||
m_cursorvisible = (Mode != GLFW_CURSOR_DISABLED);
|
||||
glfwSetInputMode(m_window, GLFW_CURSOR, Mode);
|
||||
m_cursorvisible = (Mode != GLFW_CURSOR_DISABLED);
|
||||
}
|
||||
|
||||
void ui_layer::set_progress(std::string const &Text)
|
||||
@@ -401,25 +405,26 @@ void ui_layer::set_background(std::string const &Filename)
|
||||
|
||||
void ui_layer::clear_panels()
|
||||
{
|
||||
m_panels.clear();
|
||||
m_panels.clear();
|
||||
m_ownedpanels.clear();
|
||||
}
|
||||
|
||||
void ui_layer::add_owned_panel(ui_panel *Panel)
|
||||
{
|
||||
for (auto &panel : m_ownedpanels)
|
||||
if (panel->name() == Panel->name()) {
|
||||
if (panel->name() == Panel->name())
|
||||
{
|
||||
delete Panel;
|
||||
return;
|
||||
}
|
||||
|
||||
Panel->is_open = true;
|
||||
m_ownedpanels.emplace_back( Panel );
|
||||
m_ownedpanels.emplace_back(Panel);
|
||||
}
|
||||
|
||||
void ui_layer::render_panels()
|
||||
{
|
||||
for (auto *panel : m_panels)
|
||||
for (auto *panel : m_panels)
|
||||
panel->render();
|
||||
for (auto &panel : m_ownedpanels)
|
||||
panel->render();
|
||||
@@ -431,64 +436,66 @@ void ui_layer::render_panels()
|
||||
void ui_layer::render_tooltip()
|
||||
{
|
||||
if (!m_cursorvisible || m_imguiio->WantCaptureMouse || m_tooltip.empty())
|
||||
return;
|
||||
return;
|
||||
|
||||
ImGui::BeginTooltip();
|
||||
ImGui::TextUnformatted(m_tooltip.c_str());
|
||||
ImGui::EndTooltip();
|
||||
ImGui::BeginTooltip();
|
||||
ImGui::TextUnformatted(m_tooltip.c_str());
|
||||
ImGui::EndTooltip();
|
||||
}
|
||||
|
||||
void ui_layer::render_menu_contents()
|
||||
{
|
||||
if (ImGui::BeginMenu(STR_C("General")))
|
||||
{
|
||||
bool flag = DebugModeFlag;
|
||||
if (ImGui::MenuItem(STR_C("Debug mode"), nullptr, &flag)) {
|
||||
command_relay relay;
|
||||
relay.post(user_command::debugtoggle, 0.0, 0.0, GLFW_RELEASE, 0);
|
||||
}
|
||||
ImGui::MenuItem(STR_C("Quit"), "F10", &m_quit_active);
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
if (ImGui::BeginMenu(STR_C("Tools")))
|
||||
{
|
||||
static bool log = Global.iWriteLogEnabled & 1;
|
||||
|
||||
ImGui::MenuItem(STR_C("Logging to log.txt"), nullptr, &log);
|
||||
if (log)
|
||||
Global.iWriteLogEnabled |= 1;
|
||||
else
|
||||
Global.iWriteLogEnabled &= ~1;
|
||||
|
||||
if (ImGui::MenuItem(STR_C("Screenshot"), "PrtScr"))
|
||||
Application.queue_screenshot();
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
if (ImGui::BeginMenu(STR_C("Windows")))
|
||||
{
|
||||
ImGui::MenuItem(STR_C("Log"), "F9", &m_logpanel.is_open);
|
||||
if (DebugModeFlag) {
|
||||
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));
|
||||
|
||||
GfxRenderer->Debug_Ui_State(ret);
|
||||
{
|
||||
bool flag = DebugModeFlag;
|
||||
if (ImGui::MenuItem(STR_C("Debug mode"), nullptr, &flag))
|
||||
{
|
||||
command_relay relay;
|
||||
relay.post(user_command::debugtoggle, 0.0, 0.0, GLFW_RELEASE, 0);
|
||||
}
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
ImGui::MenuItem(STR_C("Quit"), "F10", &m_quit_active);
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
if (ImGui::BeginMenu(STR_C("Tools")))
|
||||
{
|
||||
static bool log = Global.iWriteLogEnabled & 1;
|
||||
|
||||
ImGui::MenuItem(STR_C("Logging to log.txt"), nullptr, &log);
|
||||
if (log)
|
||||
Global.iWriteLogEnabled |= 1;
|
||||
else
|
||||
Global.iWriteLogEnabled &= ~1;
|
||||
|
||||
if (ImGui::MenuItem(STR_C("Screenshot"), "PrtScr"))
|
||||
Application.queue_screenshot();
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
if (ImGui::BeginMenu(STR_C("Windows")))
|
||||
{
|
||||
ImGui::MenuItem(STR_C("Log"), "F9", &m_logpanel.is_open);
|
||||
if (DebugModeFlag)
|
||||
{
|
||||
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));
|
||||
|
||||
GfxRenderer->Debug_Ui_State(ret);
|
||||
}
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
}
|
||||
|
||||
void ui_layer::render_menu()
|
||||
{
|
||||
glm::dvec2 mousepos = Global.cursor_pos;
|
||||
glm::dvec2 mousepos = Global.cursor_pos;
|
||||
|
||||
if (!((Global.ControlPicking && mousepos.y < 50.0f) || m_imguiio->WantCaptureMouse) || m_suppress_menu)
|
||||
return;
|
||||
if (!((Global.ControlPicking && mousepos.y < 50.0f) || m_imguiio->WantCaptureMouse) || m_suppress_menu)
|
||||
return;
|
||||
|
||||
if (ImGui::BeginMainMenuBar())
|
||||
{
|
||||
render_menu_contents();
|
||||
ImGui::EndMainMenuBar();
|
||||
}
|
||||
if (ImGui::BeginMainMenuBar())
|
||||
{
|
||||
render_menu_contents();
|
||||
ImGui::EndMainMenuBar();
|
||||
}
|
||||
}
|
||||
|
||||
void ui_layer::render_background()
|
||||
|
||||
@@ -75,13 +75,14 @@ public:
|
||||
// destructor
|
||||
virtual ~ui_layer();
|
||||
|
||||
// methods
|
||||
// methods
|
||||
static bool init( GLFWwindow *Window );
|
||||
static void imgui_style();
|
||||
|
||||
// assign texturing hardware unit
|
||||
static void set_unit( GLint const Textureunit ) { m_textureunit = GL_TEXTURE0 + Textureunit; }
|
||||
static void shutdown();
|
||||
virtual void showDebugUI() {};
|
||||
// potentially processes provided input key. returns: true if the input was processed, false otherwise
|
||||
virtual bool on_key( int Key, int Action );
|
||||
// potentially processes provided mouse movement. returns: true if the input was processed, false otherwise
|
||||
|
||||
608
utilities.cpp
608
utilities.cpp
@@ -37,73 +37,82 @@ bool DebugTractionFlag = false;
|
||||
|
||||
double Max0R(double x1, double x2)
|
||||
{
|
||||
if (x1 > x2)
|
||||
return x1;
|
||||
else
|
||||
return x2;
|
||||
if (x1 > x2)
|
||||
return x1;
|
||||
else
|
||||
return x2;
|
||||
}
|
||||
|
||||
double Min0R(double x1, double x2)
|
||||
{
|
||||
if (x1 < x2)
|
||||
return x1;
|
||||
else
|
||||
return x2;
|
||||
if (x1 < x2)
|
||||
return x1;
|
||||
else
|
||||
return x2;
|
||||
}
|
||||
|
||||
// shitty replacement for Borland timestamp function
|
||||
// TODO: replace with something sensible
|
||||
std::string Now() {
|
||||
std::string Now()
|
||||
{
|
||||
|
||||
std::time_t timenow = std::time( nullptr );
|
||||
std::tm tm = *std::localtime( &timenow );
|
||||
std::stringstream converter;
|
||||
converter << std::put_time( &tm, "%c" );
|
||||
return converter.str();
|
||||
std::time_t timenow = std::time(nullptr);
|
||||
std::tm tm = *std::localtime(&timenow);
|
||||
std::stringstream converter;
|
||||
converter << std::put_time(&tm, "%c");
|
||||
return converter.str();
|
||||
}
|
||||
|
||||
// zwraca różnicę czasu
|
||||
// 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)
|
||||
double CompareTime(double t1h, double t1m, double t2h, double t2m) {
|
||||
double CompareTime(double t1h, double t1m, double t2h, double t2m)
|
||||
{
|
||||
|
||||
if ((t2h < 0))
|
||||
return 0;
|
||||
else
|
||||
{
|
||||
auto t = (t2h - t1h) * 60 + t2m - t1m; // jeśli t2=00:05, a t1=23:50, to różnica wyjdzie ujemna
|
||||
if ((t < -720)) // jeśli różnica przekracza 12h na minus
|
||||
t = t + 1440; // to dodanie doby minut;else
|
||||
if ((t > 720)) // jeśli przekracza 12h na plus
|
||||
t = t - 1440; // to odjęcie doby minut
|
||||
return t;
|
||||
}
|
||||
if ((t2h < 0))
|
||||
return 0;
|
||||
else
|
||||
{
|
||||
auto t = (t2h - t1h) * 60 + t2m - t1m; // jeśli t2=00:05, a t1=23:50, to różnica wyjdzie ujemna
|
||||
if ((t < -720)) // jeśli różnica przekracza 12h na minus
|
||||
t = t + 1440; // to dodanie doby minut;else
|
||||
if ((t > 720)) // jeśli przekracza 12h na plus
|
||||
t = t - 1440; // to odjęcie doby minut
|
||||
return t;
|
||||
}
|
||||
}
|
||||
|
||||
bool SetFlag( int &Flag, int const Value ) {
|
||||
bool SetFlag(int &Flag, int const Value)
|
||||
{
|
||||
|
||||
if( Value > 0 ) {
|
||||
if( false == TestFlag( Flag, Value ) ) {
|
||||
Flag |= Value;
|
||||
return true; // true, gdy było wcześniej 0 i zostało ustawione
|
||||
}
|
||||
}
|
||||
else if( Value < 0 ) {
|
||||
// Value jest ujemne, czyli zerowanie flagi
|
||||
return ClearFlag( Flag, -Value );
|
||||
}
|
||||
return false;
|
||||
if (Value > 0)
|
||||
{
|
||||
if (false == TestFlag(Flag, Value))
|
||||
{
|
||||
Flag |= Value;
|
||||
return true; // true, gdy było wcześniej 0 i zostało ustawione
|
||||
}
|
||||
}
|
||||
else if (Value < 0)
|
||||
{
|
||||
// Value jest ujemne, czyli zerowanie flagi
|
||||
return ClearFlag(Flag, -Value);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ClearFlag( int &Flag, int const Value ) {
|
||||
bool ClearFlag(int &Flag, int const Value)
|
||||
{
|
||||
|
||||
if( true == TestFlag( Flag, Value ) ) {
|
||||
Flag &= ~Value;
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
if (true == TestFlag(Flag, Value))
|
||||
{
|
||||
Flag &= ~Value;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
double Random(double a, double b)
|
||||
@@ -119,6 +128,31 @@ int RandomInt(int min, int max)
|
||||
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)
|
||||
{
|
||||
@@ -128,46 +162,52 @@ double LocalRandom(double a, double b)
|
||||
|
||||
bool FuzzyLogic(double Test, double Threshold, double Probability)
|
||||
{
|
||||
if ((Test > Threshold) && (!DebugModeFlag))
|
||||
return
|
||||
(Random() < Probability * Threshold * 1.0 / Test) /*im wiekszy Test tym wieksza szansa*/;
|
||||
else
|
||||
return false;
|
||||
if ((Test > Threshold) && (!DebugModeFlag))
|
||||
return (Random() < Probability * Threshold * 1.0 / Test) /*im wiekszy Test tym wieksza szansa*/;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
bool FuzzyLogicAI(double Test, double Threshold, double Probability)
|
||||
{
|
||||
if ((Test > Threshold))
|
||||
return
|
||||
(Random() < Probability * Threshold * 1.0 / Test) /*im wiekszy Test tym wieksza szansa*/;
|
||||
else
|
||||
return false;
|
||||
if ((Test > Threshold))
|
||||
return (Random() < Probability * Threshold * 1.0 / Test) /*im wiekszy Test tym wieksza szansa*/;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
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)
|
||||
//DWE = Copy(s, 1, ep - 1);
|
||||
// DWE = Copy(s, 1, ep - 1);
|
||||
return s.substr(0, ep);
|
||||
else
|
||||
return s;
|
||||
else
|
||||
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::for_each(
|
||||
std::begin( Source ), std::end( Source ),
|
||||
[&](char const idx) {
|
||||
if( idx != From ) { replacement += idx; }
|
||||
else { replacement += To; } } );
|
||||
std::string replacement;
|
||||
replacement.reserve(Source.size());
|
||||
std::for_each(std::begin(Source), std::end(Source),
|
||||
[&](char const idx)
|
||||
{
|
||||
if (idx != From)
|
||||
{
|
||||
replacement += idx;
|
||||
}
|
||||
else
|
||||
{
|
||||
replacement += To;
|
||||
}
|
||||
});
|
||||
|
||||
return replacement;
|
||||
}
|
||||
@@ -175,20 +215,20 @@ std::string ExchangeCharInString( std::string const &Source, char const From, ch
|
||||
std::vector<std::string> &Split(const std::string &s, char delim, std::vector<std::string> &elems)
|
||||
{ // dzieli tekst na wektor tekstow
|
||||
|
||||
std::stringstream ss(s);
|
||||
std::string item;
|
||||
while (std::getline(ss, item, delim))
|
||||
{
|
||||
elems.push_back(item);
|
||||
}
|
||||
return elems;
|
||||
std::stringstream ss(s);
|
||||
std::string item;
|
||||
while (std::getline(ss, item, delim))
|
||||
{
|
||||
elems.push_back(item);
|
||||
}
|
||||
return elems;
|
||||
}
|
||||
|
||||
std::vector<std::string> Split(const std::string &s, char delim)
|
||||
{ // dzieli tekst na wektor tekstow
|
||||
std::vector<std::string> elems;
|
||||
Split(s, delim, elems);
|
||||
return elems;
|
||||
std::vector<std::string> elems;
|
||||
Split(s, delim, elems);
|
||||
return elems;
|
||||
}
|
||||
|
||||
std::vector<std::string> Split(const std::string &s)
|
||||
@@ -203,17 +243,16 @@ std::vector<std::string> Split(const std::string &s)
|
||||
return elems;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
|
||||
auto const indexstart{ Key.find_first_of( "-1234567890" ) };
|
||||
auto const indexend{ Key.find_first_not_of( "-1234567890", indexstart ) };
|
||||
if( indexstart != std::string::npos ) {
|
||||
return {
|
||||
Key.substr( 0, indexstart ),
|
||||
std::stoi( Key.substr( indexstart, indexend - indexstart ) ) };
|
||||
}
|
||||
return { Key, 0 };
|
||||
auto const indexstart{Key.find_first_of("-1234567890")};
|
||||
auto const indexend{Key.find_first_not_of("-1234567890", indexstart)};
|
||||
if (indexstart != std::string::npos)
|
||||
{
|
||||
return {Key.substr(0, indexstart), std::stoi(Key.substr(indexstart, indexend - indexstart))};
|
||||
}
|
||||
return {Key, 0};
|
||||
}
|
||||
|
||||
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::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();
|
||||
};
|
||||
|
||||
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;
|
||||
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();
|
||||
};
|
||||
|
||||
@@ -283,77 +322,67 @@ bool string_starts_with(const std::string &string, const std::string &begin)
|
||||
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;
|
||||
auto const minutesfractional { std::modf( Minutes, &minutesintegral ) };
|
||||
auto const width { Width - 1 };
|
||||
auto minutes = (
|
||||
std::string( width - 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 ) ) ] );
|
||||
float minutesintegral;
|
||||
auto const minutesfractional{std::modf(Minutes, &minutesintegral)};
|
||||
auto const width{Width - 1};
|
||||
auto minutes = (std::string(width - 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 };
|
||||
std::stringstream converter;
|
||||
converter << str;
|
||||
converter >> result;
|
||||
return result;
|
||||
int result{DefaultValue};
|
||||
std::stringstream converter;
|
||||
converter << str;
|
||||
converter >> result;
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string ToLower(std::string const &text) {
|
||||
std::string ToLower(std::string const &text)
|
||||
{
|
||||
|
||||
auto lowercase { text };
|
||||
std::transform(
|
||||
std::begin( text ), std::end( text ),
|
||||
std::begin( lowercase ),
|
||||
[]( unsigned char c ) { return std::tolower( c ); } );
|
||||
auto lowercase{text};
|
||||
std::transform(std::begin(text), std::end(text), std::begin(lowercase), [](unsigned char c) { return std::tolower(c); });
|
||||
return lowercase;
|
||||
}
|
||||
|
||||
std::string ToUpper(std::string const &text) {
|
||||
std::string ToUpper(std::string const &text)
|
||||
{
|
||||
|
||||
auto uppercase { text };
|
||||
std::transform(
|
||||
std::begin( text ), std::end( text ),
|
||||
std::begin( uppercase ),
|
||||
[]( unsigned char c ) { return std::toupper( c ); } );
|
||||
return uppercase;
|
||||
auto uppercase{text};
|
||||
std::transform(std::begin(text), std::end(text), std::begin(uppercase), [](unsigned char c) { return std::toupper(c); });
|
||||
return uppercase;
|
||||
}
|
||||
|
||||
// replaces polish letters with basic ascii
|
||||
void
|
||||
win1250_to_ascii( std::string &Input ) {
|
||||
void win1250_to_ascii(std::string &Input)
|
||||
{
|
||||
|
||||
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' },
|
||||
{ 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;
|
||||
for( auto &input : Input ) {
|
||||
if( ( lookup = charmap.find( input ) ) != charmap.end() )
|
||||
input = lookup->second;
|
||||
}
|
||||
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'},
|
||||
{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;
|
||||
for (auto &input : Input)
|
||||
{
|
||||
if ((lookup = charmap.find(input)) != charmap.end())
|
||||
input = lookup->second;
|
||||
}
|
||||
}
|
||||
|
||||
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"Ż" },
|
||||
{ 185, u8"ą" }, { 230, u8"ć" }, { 234, u8"ę" }, { 179, u8"ł" }, { 241, u8"ń" }, { 243, u8"ó" }, { 156, u8"ś" }, { 159, u8"ź" }, { 191, u8"ż" }
|
||||
};
|
||||
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"Ż"},
|
||||
{185, u8"ą"}, {230, u8"ć"}, {234, u8"ę"}, {179, u8"ł"}, {241, u8"ń"}, {243, u8"ó"}, {156, u8"ś"}, {159, u8"ź"}, {191, u8"ż"}};
|
||||
std::string output;
|
||||
std::unordered_map<char, std::string>::const_iterator lookup;
|
||||
for( auto &input : Input ) {
|
||||
if( ( lookup = charmap.find( input ) ) != charmap.end() )
|
||||
for (auto &input : Input)
|
||||
{
|
||||
if ((lookup = charmap.find(input)) != charmap.end())
|
||||
output += lookup->second;
|
||||
else
|
||||
output += input;
|
||||
@@ -362,213 +391,220 @@ std::string win1250_to_utf8(const std::string &Input) {
|
||||
}
|
||||
|
||||
// Ra: tymczasowe rozwiązanie kwestii zagranicznych (czeskich) napisów
|
||||
char charsetconversiontable[] =
|
||||
"E?,?\"_++?%S<STZZ?`'\"\".--??s>stzz"
|
||||
" ^^L$A|S^CS<--RZo±,l'uP.,as>L\"lz"
|
||||
"RAAAALCCCEEEEIIDDNNOOOOxRUUUUYTB"
|
||||
"raaaalccceeeeiiddnnoooo-ruuuuyt?";
|
||||
char charsetconversiontable[] = "E?,?\"_++?%S<STZZ?`'\"\".--??s>stzz"
|
||||
" ^^L$A|S^CS<--RZo±,l'uP.,as>L\"lz"
|
||||
"RAAAALCCCEEEEIIDDNNOOOOxRUUUUYTB"
|
||||
"raaaalccceeeeiiddnnoooo-ruuuuyt?";
|
||||
|
||||
// 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 space { ' ' };
|
||||
char const underscore { '_' };
|
||||
char const extendedcharsetbit{static_cast<char>(0x80)};
|
||||
char const space{' '};
|
||||
char const underscore{'_'};
|
||||
|
||||
for( auto &input : Input ) {
|
||||
if( input & extendedcharsetbit ) {
|
||||
input = charsetconversiontable[ input ^ extendedcharsetbit ];
|
||||
}
|
||||
else if( input < space ) {
|
||||
input = space;
|
||||
}
|
||||
else if( Underscorestospaces && ( input == underscore ) ) {
|
||||
input = space;
|
||||
}
|
||||
}
|
||||
for (auto &input : Input)
|
||||
{
|
||||
if (input & extendedcharsetbit)
|
||||
{
|
||||
input = charsetconversiontable[input ^ extendedcharsetbit];
|
||||
}
|
||||
else if (input < space)
|
||||
{
|
||||
input = space;
|
||||
}
|
||||
else if (Underscorestospaces && (input == underscore))
|
||||
{
|
||||
input = space;
|
||||
}
|
||||
}
|
||||
|
||||
return Input;
|
||||
return Input;
|
||||
}
|
||||
|
||||
template <>
|
||||
bool
|
||||
extract_value( bool &Variable, std::string const &Key, std::string const &Input, std::string const &Default ) {
|
||||
template <> bool extract_value(bool &Variable, std::string const &Key, std::string const &Input, std::string const &Default)
|
||||
{
|
||||
|
||||
auto value = extract_value( Key, Input );
|
||||
if( false == value.empty() ) {
|
||||
// set the specified variable to retrieved value
|
||||
Variable = ( ToLower( value ) == "yes" );
|
||||
return true; // located the variable
|
||||
}
|
||||
else {
|
||||
// set the variable to provided default value
|
||||
if( false == Default.empty() ) {
|
||||
Variable = ( ToLower( Default ) == "yes" );
|
||||
}
|
||||
return false; // couldn't locate the variable in provided input
|
||||
}
|
||||
auto value = extract_value(Key, Input);
|
||||
if (false == value.empty())
|
||||
{
|
||||
// set the specified variable to retrieved value
|
||||
Variable = (ToLower(value) == "yes");
|
||||
return true; // located the variable
|
||||
}
|
||||
else
|
||||
{
|
||||
// set the variable to provided default value
|
||||
if (false == Default.empty())
|
||||
{
|
||||
Variable = (ToLower(Default) == "yes");
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
|
||||
for( auto const &name : Names ) {
|
||||
for( auto const &extension : Extensions ) {
|
||||
if( FileExists( name + extension ) ) {
|
||||
return { name, extension };
|
||||
}
|
||||
}
|
||||
}
|
||||
// nothing found
|
||||
return { {}, {} };
|
||||
for (auto const &name : Names)
|
||||
{
|
||||
for (auto const &extension : Extensions)
|
||||
{
|
||||
if (FileExists(name + extension))
|
||||
{
|
||||
return {name, extension};
|
||||
}
|
||||
}
|
||||
}
|
||||
// nothing found
|
||||
return {{}, {}};
|
||||
}
|
||||
|
||||
// returns time of last modification for specified file
|
||||
std::time_t
|
||||
last_modified( std::string const &Filename ) {
|
||||
std::string fn = Filename;
|
||||
struct stat filestat;
|
||||
if( ::stat( fn.c_str(), &filestat ) == 0 )
|
||||
std::time_t last_modified(std::string const &Filename)
|
||||
{
|
||||
std::string fn = Filename;
|
||||
struct stat filestat;
|
||||
if (::stat(fn.c_str(), &filestat) == 0)
|
||||
return filestat.st_mtime;
|
||||
else
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
// potentially erases file extension from provided file name. returns: true if extension was removed, false otherwise
|
||||
bool
|
||||
erase_extension( std::string &Filename ) {
|
||||
bool 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 ) {
|
||||
// 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 );
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
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
|
||||
Filename.erase(extensionpos);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
erase_leading_slashes( std::string &Filename ) {
|
||||
void erase_leading_slashes(std::string &Filename)
|
||||
{
|
||||
|
||||
while( Filename[ 0 ] == '/' ) {
|
||||
Filename.erase( 0, 1 );
|
||||
}
|
||||
while (Filename[0] == '/')
|
||||
{
|
||||
Filename.erase(0, 1);
|
||||
}
|
||||
}
|
||||
|
||||
// potentially replaces backward slashes in provided file path with unix-compatible forward slashes
|
||||
void
|
||||
replace_slashes( std::string &Filename ) {
|
||||
void replace_slashes(std::string &Filename)
|
||||
{
|
||||
|
||||
std::replace(
|
||||
std::begin( Filename ), std::end( Filename ),
|
||||
'\\', '/' );
|
||||
std::replace(std::begin(Filename), std::end(Filename), '\\', '/');
|
||||
}
|
||||
|
||||
// returns potential path part from provided file name
|
||||
std::string
|
||||
substr_path( std::string const &Filename ) {
|
||||
std::string substr_path(std::string const &Filename)
|
||||
{
|
||||
|
||||
return (
|
||||
Filename.rfind( '/' ) != std::string::npos ?
|
||||
Filename.substr( 0, Filename.rfind( '/' ) + 1 ) :
|
||||
"" );
|
||||
return (Filename.rfind('/') != std::string::npos ? Filename.substr(0, Filename.rfind('/') + 1) : "");
|
||||
}
|
||||
|
||||
// returns length of common prefix between 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)
|
||||
{
|
||||
|
||||
auto const *left { Left.data() };
|
||||
auto const *right { Right.data() };
|
||||
// compare up to the length of the shorter string
|
||||
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 ) );
|
||||
auto const *left{Left.data()};
|
||||
auto const *right{Right.data()};
|
||||
// compare up to the length of the shorter string
|
||||
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));
|
||||
}
|
||||
|
||||
// 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)
|
||||
{
|
||||
|
||||
return ( String.size() >= Suffix.size() )
|
||||
&& ( 0 == String.compare( String.size() - Suffix.size(), Suffix.size(), Suffix ) );
|
||||
return (String.size() >= Suffix.size()) && (0 == String.compare(String.size() - Suffix.size(), Suffix.size(), Suffix));
|
||||
}
|
||||
|
||||
// returns true if provided string begins with another provided string
|
||||
bool
|
||||
starts_with( std::string_view const String, std::string_view Prefix ) {
|
||||
bool starts_with(std::string_view const String, std::string_view Prefix)
|
||||
{
|
||||
|
||||
return ( String.size() >= Prefix.size() )
|
||||
&& ( 0 == String.compare( 0, Prefix.size(), Prefix ) );
|
||||
return (String.size() >= Prefix.size()) && (0 == String.compare(0, Prefix.size(), Prefix));
|
||||
}
|
||||
|
||||
// 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)
|
||||
{
|
||||
|
||||
return ( String.find( Substring ) != std::string::npos );
|
||||
return (String.find(Substring) != std::string::npos);
|
||||
}
|
||||
|
||||
bool
|
||||
contains( std::string_view const String, char Character ) {
|
||||
bool 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
|
||||
// TODO: review and clean up the helper routines, there's likely some redundant ones
|
||||
|
||||
glm::dvec3 LoadPoint( cParser &Input ) {
|
||||
// pobranie współrzędnych punktu
|
||||
glm::dvec3 point;
|
||||
Input.getTokens( 3 );
|
||||
Input
|
||||
>> point.x
|
||||
>> point.y
|
||||
>> point.z;
|
||||
return point;
|
||||
glm::dvec3 LoadPoint(cParser &Input)
|
||||
{
|
||||
// pobranie współrzędnych punktu
|
||||
glm::dvec3 point;
|
||||
Input.getTokens(3);
|
||||
Input >> point.x >> point.y >> point.z;
|
||||
return point;
|
||||
}
|
||||
|
||||
// extracts a group of tokens from provided data stream, returns one of them picked randomly
|
||||
std::string
|
||||
deserialize_random_set( cParser &Input, char const *Break ) {
|
||||
|
||||
auto token { Input.getToken<std::string>( true, Break ) };
|
||||
std::replace(token.begin(), token.end(), '\\', '/');
|
||||
if( token != "[" ) {
|
||||
// simple case, single token
|
||||
return token;
|
||||
}
|
||||
// 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
|
||||
std::vector<std::string> tokens;
|
||||
while( ( ( token = deserialize_random_set( Input, Break ) ) != "" )
|
||||
&& ( token != "]" ) ) {
|
||||
tokens.emplace_back( token );
|
||||
}
|
||||
if( false == tokens.empty() ) {
|
||||
std::shuffle( std::begin( tokens ), std::end( tokens ), Global.random_engine );
|
||||
return tokens.front();
|
||||
}
|
||||
else {
|
||||
// shouldn't ever get here but, eh
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
int count_trailing_zeros( uint32_t val )
|
||||
std::string deserialize_random_set(cParser &Input, char const *Break)
|
||||
{
|
||||
int r = 0;
|
||||
|
||||
for( uint32_t shift = 1; !( val & shift ); shift <<= 1 )
|
||||
r++;
|
||||
|
||||
return r;
|
||||
auto token{Input.getToken<std::string>(true, Break)};
|
||||
std::replace(token.begin(), token.end(), '\\', '/');
|
||||
if (token != "[")
|
||||
{
|
||||
// simple case, single token
|
||||
return token;
|
||||
}
|
||||
// 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
|
||||
std::vector<std::string> tokens;
|
||||
while (((token = deserialize_random_set(Input, Break)) != "") && (token != "]"))
|
||||
{
|
||||
tokens.emplace_back(token);
|
||||
}
|
||||
if (false == tokens.empty())
|
||||
{
|
||||
std::shuffle(std::begin(tokens), std::end(tokens), Global.random_engine);
|
||||
return tokens.front();
|
||||
}
|
||||
else
|
||||
{
|
||||
// shouldn't ever get here but, eh
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
int count_trailing_zeros(uint32_t val)
|
||||
{
|
||||
int r = 0;
|
||||
|
||||
for (uint32_t shift = 1; !(val & shift); shift <<= 1)
|
||||
r++;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
480
utilities.h
480
utilities.h
@@ -36,7 +36,7 @@ template <typename T> T sign(T x)
|
||||
#define szSoundPath "sounds/"
|
||||
#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 FreeFlyModeFlag;
|
||||
@@ -50,22 +50,23 @@ double Min0R(double x1, double x2);
|
||||
|
||||
inline double Sign(double x)
|
||||
{
|
||||
return x >= 0 ? 1.0 : -1.0;
|
||||
return x >= 0 ? 1.0 : -1.0;
|
||||
}
|
||||
|
||||
inline long Round(double const f)
|
||||
{
|
||||
return (long)(f + 0.5);
|
||||
//return lround(f);
|
||||
// return lround(f);
|
||||
}
|
||||
|
||||
double Random(double a, double b);
|
||||
int RandomInt(int min, int max);
|
||||
std::string generate_uuid_v4();
|
||||
double LocalRandom(double a, double b);
|
||||
|
||||
inline double Random()
|
||||
{
|
||||
return Random(0.0,1.0);
|
||||
return Random(0.0, 1.0);
|
||||
}
|
||||
|
||||
inline double Random(double b)
|
||||
@@ -75,39 +76,39 @@ inline double Random(double b)
|
||||
|
||||
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()
|
||||
{
|
||||
auto timesinceepoch = std::time( nullptr );
|
||||
return timesinceepoch / (24.0 * 60 * 60);
|
||||
/*
|
||||
// std alternative
|
||||
auto timesinceepoch = std::chrono::system_clock::now().time_since_epoch();
|
||||
return std::chrono::duration_cast<std::chrono::seconds>( timesinceepoch ).count() / (24.0 * 60 * 60);
|
||||
*/
|
||||
auto timesinceepoch = std::time(nullptr);
|
||||
return timesinceepoch / (24.0 * 60 * 60);
|
||||
/*
|
||||
// std alternative
|
||||
auto timesinceepoch = std::chrono::system_clock::now().time_since_epoch();
|
||||
return std::chrono::duration_cast<std::chrono::seconds>( timesinceepoch ).count() / (24.0 * 60 * 60);
|
||||
*/
|
||||
}
|
||||
|
||||
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*/
|
||||
inline
|
||||
bool TestFlag( int const Flag, int const Value ) {
|
||||
return ( ( Flag & Value ) == Value );
|
||||
inline bool TestFlag(int const Flag, int const Value)
|
||||
{
|
||||
return ((Flag & Value) == Value);
|
||||
}
|
||||
inline
|
||||
bool TestFlagAny( int const Flag, int const Value ) {
|
||||
return ( ( Flag & Value ) != 0 );
|
||||
inline bool TestFlagAny(int const Flag, int const Value)
|
||||
{
|
||||
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 FuzzyLogic(double Test, double Threshold, double Probability);
|
||||
@@ -116,13 +117,13 @@ bool FuzzyLogicAI(double Test, double Threshold, double Probability);
|
||||
/*to samo ale zawsze niezaleznie od DebugFlag*/
|
||||
|
||||
/*operacje na stringach*/
|
||||
std::string DUE(std::string s); /*Delete Until 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 DUE(std::string s); /*Delete Until 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::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);
|
||||
std::pair<std::string, int> split_string_and_number( std::string const &Key );
|
||||
// std::vector<std::string> Split(const std::string &s);
|
||||
std::pair<std::string, int> split_string_and_number(std::string const &Key);
|
||||
|
||||
std::string to_string(int Value);
|
||||
std::string to_string(unsigned int Value);
|
||||
@@ -130,210 +131,207 @@ std::string to_string(int Value, int width);
|
||||
std::string to_string(double Value);
|
||||
std::string to_string(double Value, int precision);
|
||||
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_minutes_str( float const Minutes, bool const Leadingzero, int const Width );
|
||||
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);
|
||||
|
||||
inline
|
||||
std::string to_string(bool Value) {
|
||||
return ( Value == true ? "true" : "false" );
|
||||
inline std::string to_string(bool Value)
|
||||
{
|
||||
return (Value == true ? "true" : "false");
|
||||
}
|
||||
|
||||
template <typename Type_, glm::precision Precision_ = glm::defaultp>
|
||||
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 );
|
||||
template <typename Type_, glm::precision Precision_ = glm::defaultp> 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);
|
||||
}
|
||||
|
||||
template <typename Type_, glm::precision Precision_ = glm::defaultp>
|
||||
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 );
|
||||
template <typename Type_, glm::precision Precision_ = glm::defaultp> 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);
|
||||
}
|
||||
|
||||
bool string_ends_with(std::string const &string, std::string const &ending);
|
||||
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 ToUpper(std::string const &text);
|
||||
|
||||
// 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()
|
||||
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);
|
||||
|
||||
inline
|
||||
std::string
|
||||
extract_value( std::string const &Key, std::string const &Input ) {
|
||||
// NOTE, HACK: the leading space allows to uniformly look for " variable=" substring
|
||||
std::string const input { " " + Input };
|
||||
std::string value;
|
||||
auto lookup = input.find( " " + Key + "=" );
|
||||
if( lookup != std::string::npos ) {
|
||||
value = input.substr( input.find_first_not_of( ' ', lookup + Key.size() + 2 ) );
|
||||
lookup = value.find( ' ' );
|
||||
if( lookup != std::string::npos ) {
|
||||
// trim everything past the value
|
||||
value.erase( lookup );
|
||||
}
|
||||
}
|
||||
return value;
|
||||
inline std::string extract_value(std::string const &Key, std::string const &Input)
|
||||
{
|
||||
// NOTE, HACK: the leading space allows to uniformly look for " variable=" substring
|
||||
std::string const input{" " + Input};
|
||||
std::string value;
|
||||
auto lookup = input.find(" " + Key + "=");
|
||||
if (lookup != std::string::npos)
|
||||
{
|
||||
value = input.substr(input.find_first_not_of(' ', lookup + Key.size() + 2));
|
||||
lookup = value.find(' ');
|
||||
if (lookup != std::string::npos)
|
||||
{
|
||||
// trim everything past the value
|
||||
value.erase(lookup);
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
template <typename Type_>
|
||||
bool
|
||||
extract_value( Type_ &Variable, std::string const &Key, std::string const &Input, std::string const &Default ) {
|
||||
template <typename Type_> bool extract_value(Type_ &Variable, std::string const &Key, std::string const &Input, std::string const &Default)
|
||||
{
|
||||
|
||||
auto value = extract_value( Key, Input );
|
||||
if( false == value.empty() ) {
|
||||
// set the specified variable to retrieved value
|
||||
std::stringstream converter;
|
||||
converter << value;
|
||||
converter >> Variable;
|
||||
return true; // located the variable
|
||||
}
|
||||
else {
|
||||
// set the variable to provided default value
|
||||
if( false == Default.empty() ) {
|
||||
std::stringstream converter;
|
||||
converter << Default;
|
||||
converter >> Variable;
|
||||
}
|
||||
return false; // couldn't locate the variable in provided input
|
||||
}
|
||||
auto value = extract_value(Key, Input);
|
||||
if (false == value.empty())
|
||||
{
|
||||
// set the specified variable to retrieved value
|
||||
std::stringstream converter;
|
||||
converter << value;
|
||||
converter >> Variable;
|
||||
return true; // located the variable
|
||||
}
|
||||
else
|
||||
{
|
||||
// set the variable to provided default value
|
||||
if (false == Default.empty())
|
||||
{
|
||||
std::stringstream converter;
|
||||
converter << Default;
|
||||
converter >> Variable;
|
||||
}
|
||||
return false; // couldn't locate the variable in provided input
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
bool
|
||||
extract_value( bool &Variable, std::string const &Key, std::string const &Input, std::string const &Default );
|
||||
template <> 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
|
||||
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
|
||||
bool
|
||||
erase_extension( std::string &Filename );
|
||||
bool erase_extension(std::string &Filename);
|
||||
|
||||
// potentially erase leading slashes from provided file path
|
||||
void
|
||||
erase_leading_slashes( std::string &Filename );
|
||||
void erase_leading_slashes(std::string &Filename);
|
||||
|
||||
// potentially replaces backward slashes in provided file path with unix-compatible forward slashes
|
||||
void
|
||||
replace_slashes( std::string &Filename );
|
||||
void replace_slashes(std::string &Filename);
|
||||
|
||||
// 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
|
||||
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
|
||||
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
|
||||
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
|
||||
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, std::string_view Substring);
|
||||
bool contains(std::string_view const String, char Character);
|
||||
|
||||
template <typename Type_>
|
||||
void SafeDelete( Type_ &Pointer ) {
|
||||
delete Pointer;
|
||||
Pointer = nullptr;
|
||||
template <typename Type_> void SafeDelete(Type_ &Pointer)
|
||||
{
|
||||
delete Pointer;
|
||||
Pointer = nullptr;
|
||||
}
|
||||
|
||||
template <typename Type_>
|
||||
void SafeDeleteArray( Type_ &Pointer ) {
|
||||
delete[] Pointer;
|
||||
Pointer = nullptr;
|
||||
template <typename Type_> void SafeDeleteArray(Type_ &Pointer)
|
||||
{
|
||||
delete[] Pointer;
|
||||
Pointer = nullptr;
|
||||
}
|
||||
|
||||
template <typename Type_>
|
||||
Type_
|
||||
is_equal( Type_ const &Left, Type_ const &Right, Type_ const Epsilon = 1e-5 ) {
|
||||
template <typename Type_> Type_ is_equal(Type_ const &Left, Type_ const &Right, Type_ const Epsilon = 1e-5)
|
||||
{
|
||||
|
||||
if( Epsilon != 0 ) {
|
||||
return glm::epsilonEqual( Left, Right, Epsilon );
|
||||
}
|
||||
else {
|
||||
return ( Left == Right );
|
||||
}
|
||||
if (Epsilon != 0)
|
||||
{
|
||||
return glm::epsilonEqual(Left, Right, Epsilon);
|
||||
}
|
||||
else
|
||||
{
|
||||
return (Left == Right);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Type_>
|
||||
Type_
|
||||
clamp( Type_ const Value, Type_ const Min, Type_ const Max ) {
|
||||
template <typename Type_> Type_ clamp(Type_ const Value, Type_ const Min, Type_ const Max)
|
||||
{
|
||||
|
||||
Type_ value = Value;
|
||||
if( value < Min ) { value = Min; }
|
||||
if( value > Max ) { value = Max; }
|
||||
return value;
|
||||
Type_ value = Value;
|
||||
if (value < Min)
|
||||
{
|
||||
value = Min;
|
||||
}
|
||||
if (value > Max)
|
||||
{
|
||||
value = Max;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
// keeps the provided value in specified range 0-Range, as if the range was circular buffer
|
||||
template <typename Type_>
|
||||
Type_
|
||||
clamp_circular( Type_ Value, Type_ const Range = static_cast<Type_>(360) ) {
|
||||
template <typename Type_> Type_ clamp_circular(Type_ Value, Type_ const Range = static_cast<Type_>(360))
|
||||
{
|
||||
|
||||
Value -= Range * (int)( Value / Range ); // clamp the range to 0-360
|
||||
if( Value < Type_(0) ) Value += Range;
|
||||
Value -= Range * (int)(Value / Range); // clamp the range to 0-360
|
||||
if (Value < Type_(0))
|
||||
Value += Range;
|
||||
|
||||
return Value;
|
||||
return Value;
|
||||
}
|
||||
|
||||
// rounds down provided value to nearest power of two
|
||||
template <typename Type_>
|
||||
Type_
|
||||
clamp_power_of_two( Type_ Value, Type_ const Min = static_cast<Type_>(1), Type_ const Max = static_cast<Type_>(16384) ) {
|
||||
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_ p2size{ Min };
|
||||
Type_ size;
|
||||
while( ( p2size <= Max ) && ( p2size <= Value ) ) {
|
||||
size = p2size;
|
||||
p2size = p2size << 1;
|
||||
}
|
||||
return size;
|
||||
Type_ p2size{Min};
|
||||
Type_ size;
|
||||
while ((p2size <= Max) && (p2size <= Value))
|
||||
{
|
||||
size = p2size;
|
||||
p2size = p2size << 1;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
template <typename Type_>
|
||||
Type_
|
||||
quantize( Type_ const Value, Type_ const Step ) {
|
||||
template <typename Type_> Type_ quantize(Type_ const Value, Type_ const Step)
|
||||
{
|
||||
|
||||
return ( Step * std::round( Value / Step ) );
|
||||
return (Step * std::round(Value / Step));
|
||||
}
|
||||
|
||||
template <typename Type_>
|
||||
Type_
|
||||
min_speed( Type_ const Left, Type_ const Right ) {
|
||||
template <typename Type_> Type_ min_speed(Type_ const Left, Type_ const Right)
|
||||
{
|
||||
|
||||
if( Left == Right ) { return Left; }
|
||||
if (Left == Right)
|
||||
{
|
||||
return Left;
|
||||
}
|
||||
|
||||
return std::min(
|
||||
( Left != -1 ?
|
||||
Left :
|
||||
std::numeric_limits<Type_>::max() ),
|
||||
( Right != -1 ?
|
||||
Right :
|
||||
std::numeric_limits<Type_>::max() ) );
|
||||
return std::min((Left != -1 ? Left : std::numeric_limits<Type_>::max()), (Right != -1 ? Right : std::numeric_limits<Type_>::max()));
|
||||
}
|
||||
|
||||
template <typename Type_>
|
||||
Type_
|
||||
interpolate( Type_ const &First, Type_ const &Second, float const Factor ) {
|
||||
template <typename Type_> 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_>
|
||||
Type_
|
||||
interpolate( Type_ const &First, Type_ const &Second, double const Factor ) {
|
||||
template <typename Type_> 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)
|
||||
@@ -345,124 +343,120 @@ template <typename Type_> Type_ smoothInterpolate(Type_ const &First, Type_ cons
|
||||
}
|
||||
|
||||
// tests whether provided points form a degenerate triangle
|
||||
template <typename VecType_>
|
||||
bool
|
||||
degenerate( VecType_ const &Vertex1, VecType_ const &Vertex2, VecType_ const &Vertex3 ) {
|
||||
template <typename VecType_> 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 );
|
||||
return ( glm::length2( glm::cross( Vertex2 - Vertex1, Vertex3 - Vertex1 ) ) == 0.0 );
|
||||
// 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);
|
||||
}
|
||||
|
||||
// calculates bounding box for provided set of points
|
||||
template <class Iterator_, class VecType_>
|
||||
void
|
||||
bounding_box( VecType_ &Mincorner, VecType_ &Maxcorner, Iterator_ First, Iterator_ Last ) {
|
||||
template <class Iterator_, class VecType_> void bounding_box(VecType_ &Mincorner, VecType_ &Maxcorner, Iterator_ First, Iterator_ Last)
|
||||
{
|
||||
|
||||
Mincorner = VecType_( std::numeric_limits<typename VecType_::value_type>::max() );
|
||||
Maxcorner = VecType_( std::numeric_limits<typename VecType_::value_type>::lowest() );
|
||||
Mincorner = VecType_(std::numeric_limits<typename VecType_::value_type>::max());
|
||||
Maxcorner = VecType_(std::numeric_limits<typename VecType_::value_type>::lowest());
|
||||
|
||||
std::for_each(
|
||||
First, Last,
|
||||
[&]( typename Iterator_::value_type &point ) {
|
||||
Mincorner = glm::min( Mincorner, VecType_{ point } );
|
||||
Maxcorner = glm::max( Maxcorner, VecType_{ point } ); } );
|
||||
std::for_each(First, Last,
|
||||
[&](typename Iterator_::value_type &point)
|
||||
{
|
||||
Mincorner = glm::min(Mincorner, 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
|
||||
template <typename VecType_>
|
||||
typename VecType_::value_type
|
||||
nearest_segment_point( VecType_ const &Segmentstart, VecType_ const &Segmentend, VecType_ const &Point ) {
|
||||
template <typename VecType_> typename VecType_::value_type nearest_segment_point(VecType_ const &Segmentstart, VecType_ const &Segmentend, VecType_ const &Point)
|
||||
{
|
||||
|
||||
auto const v = Segmentend - Segmentstart;
|
||||
auto const w = Point - Segmentstart;
|
||||
auto const v = Segmentend - Segmentstart;
|
||||
auto const w = Point - Segmentstart;
|
||||
|
||||
auto const c1 = glm::dot( w, v );
|
||||
if( c1 <= 0.0 ) {
|
||||
return 0.0;
|
||||
}
|
||||
auto const c2 = glm::dot( v, v );
|
||||
if( c2 <= c1 ) {
|
||||
return 1.0;
|
||||
}
|
||||
return c1 / c2;
|
||||
auto const c1 = glm::dot(w, v);
|
||||
if (c1 <= 0.0)
|
||||
{
|
||||
return 0.0;
|
||||
}
|
||||
auto const c2 = glm::dot(v, v);
|
||||
if (c2 <= c1)
|
||||
{
|
||||
return 1.0;
|
||||
}
|
||||
return c1 / c2;
|
||||
}
|
||||
|
||||
glm::dvec3 LoadPoint( class cParser &Input );
|
||||
glm::dvec3 LoadPoint(class cParser &Input);
|
||||
|
||||
// extracts a group of tokens from provided data stream
|
||||
std::string
|
||||
deserialize_random_set( cParser &Input, char const *Break = "\n\r\t ;" );
|
||||
std::string 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
|
||||
// NOTE: expects no more than single pair per line
|
||||
template <typename MapType_>
|
||||
void
|
||||
deserialize_map( MapType_ &Map, cParser &Input ) {
|
||||
template <typename MapType_> void deserialize_map(MapType_ &Map, cParser &Input)
|
||||
{
|
||||
|
||||
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" ) };
|
||||
Map.emplace( key, value );
|
||||
}
|
||||
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")};
|
||||
Map.emplace(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
namespace threading {
|
||||
namespace threading
|
||||
{
|
||||
|
||||
// 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
|
||||
template <typename Type_>
|
||||
struct lockable {
|
||||
template <typename Type_> struct lockable
|
||||
{
|
||||
|
||||
Type_ data;
|
||||
std::mutex mutex;
|
||||
Type_ data;
|
||||
std::mutex mutex;
|
||||
};
|
||||
|
||||
// basic wrapper simplifying use of std::condition_variable for most typical cases.
|
||||
// has its own mutex and secondary variable to ignore spurious wakeups
|
||||
class condition_variable {
|
||||
class condition_variable
|
||||
{
|
||||
|
||||
public:
|
||||
// methods
|
||||
void
|
||||
wait() {
|
||||
std::unique_lock<std::mutex> lock( m_mutex );
|
||||
m_condition.wait(
|
||||
lock,
|
||||
[ this ]() {
|
||||
return m_spurious == false; } ); }
|
||||
template< class Rep_, class Period_ >
|
||||
void
|
||||
wait_for( const std::chrono::duration<Rep_, Period_> &Time ) {
|
||||
std::unique_lock<std::mutex> lock( m_mutex );
|
||||
m_condition.wait_for(
|
||||
lock,
|
||||
Time,
|
||||
[ this ]() {
|
||||
return m_spurious == false; } ); }
|
||||
void
|
||||
notify_one() {
|
||||
spurious( false );
|
||||
m_condition.notify_one();
|
||||
}
|
||||
void
|
||||
notify_all() {
|
||||
spurious( false );
|
||||
m_condition.notify_all();
|
||||
}
|
||||
void
|
||||
spurious( bool const Spurious ) {
|
||||
std::lock_guard<std::mutex> lock( m_mutex );
|
||||
m_spurious = Spurious; }
|
||||
public:
|
||||
// methods
|
||||
void wait()
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(m_mutex);
|
||||
m_condition.wait(lock, [this]() { return m_spurious == false; });
|
||||
}
|
||||
template <class Rep_, class Period_> void wait_for(const std::chrono::duration<Rep_, Period_> &Time)
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(m_mutex);
|
||||
m_condition.wait_for(lock, Time, [this]() { return m_spurious == false; });
|
||||
}
|
||||
void notify_one()
|
||||
{
|
||||
spurious(false);
|
||||
m_condition.notify_one();
|
||||
}
|
||||
void notify_all()
|
||||
{
|
||||
spurious(false);
|
||||
m_condition.notify_all();
|
||||
}
|
||||
void spurious(bool const Spurious)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
m_spurious = Spurious;
|
||||
}
|
||||
|
||||
private:
|
||||
// members
|
||||
mutable std::mutex m_mutex;
|
||||
std::condition_variable m_condition;
|
||||
bool m_spurious { true };
|
||||
private:
|
||||
// members
|
||||
mutable std::mutex m_mutex;
|
||||
std::condition_variable m_condition;
|
||||
bool m_spurious{true};
|
||||
};
|
||||
|
||||
} // threading
|
||||
} // namespace threading
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user