Merge pull request #4849 from Web-eWorks/modelviewer-refactor
Refactor the ModelViewer to use PiGuimaster
commit
08386499a9
|
@ -9,10 +9,17 @@
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
|
|
||||||
void Input::Init(GameConfig *config)
|
Input::Input(IniConfig *config) :
|
||||||
|
m_config(config),
|
||||||
|
m_capturingMouse(false),
|
||||||
|
mouseYInvert(false),
|
||||||
|
joystickEnabled(true),
|
||||||
|
keyModState(0),
|
||||||
|
mouseButton(),
|
||||||
|
mouseMotion()
|
||||||
{
|
{
|
||||||
joystickEnabled = (config->Int("EnableJoystick")) ? true : false;
|
joystickEnabled = (m_config->Int("EnableJoystick")) ? true : false;
|
||||||
mouseYInvert = (config->Int("InvertMouseY")) ? true : false;
|
mouseYInvert = (m_config->Int("InvertMouseY")) ? true : false;
|
||||||
|
|
||||||
InitJoysticks();
|
InitJoysticks();
|
||||||
}
|
}
|
||||||
|
@ -22,8 +29,8 @@ void Input::InitGame()
|
||||||
//reset input states
|
//reset input states
|
||||||
keyState.clear();
|
keyState.clear();
|
||||||
keyModState = 0;
|
keyModState = 0;
|
||||||
std::fill(mouseButton, mouseButton + COUNTOF(mouseButton), 0);
|
mouseButton.fill(0);
|
||||||
std::fill(mouseMotion, mouseMotion + COUNTOF(mouseMotion), 0);
|
mouseMotion.fill(0);
|
||||||
for (std::map<SDL_JoystickID, JoystickState>::iterator stick = joysticks.begin(); stick != joysticks.end(); ++stick) {
|
for (std::map<SDL_JoystickID, JoystickState>::iterator stick = joysticks.begin(); stick != joysticks.end(); ++stick) {
|
||||||
JoystickState &state = stick->second;
|
JoystickState &state = stick->second;
|
||||||
std::fill(state.buttons.begin(), state.buttons.end(), false);
|
std::fill(state.buttons.begin(), state.buttons.end(), false);
|
||||||
|
@ -32,6 +39,25 @@ void Input::InitGame()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Input::NewFrame()
|
||||||
|
{
|
||||||
|
mouseMotion.fill(0);
|
||||||
|
mouseWheel = 0;
|
||||||
|
for (auto &k : keyState) {
|
||||||
|
auto &val = keyState[k.first];
|
||||||
|
switch (k.second) {
|
||||||
|
case 1: // if we were just pressed last frame, migrate to held state
|
||||||
|
val = 2;
|
||||||
|
break;
|
||||||
|
case 4: // if we were just released last frame, migrate to empty state
|
||||||
|
val = 0;
|
||||||
|
break;
|
||||||
|
default: // otherwise, no need to do anything
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
InputResponse Input::InputFrame::ProcessSDLEvent(SDL_Event &event)
|
InputResponse Input::InputFrame::ProcessSDLEvent(SDL_Event &event)
|
||||||
{
|
{
|
||||||
bool matched = false;
|
bool matched = false;
|
||||||
|
@ -95,7 +121,7 @@ KeyBindings::ActionBinding *Input::AddActionBinding(std::string id, BindingGroup
|
||||||
group->bindings[id] = BindingGroup::ENTRY_ACTION;
|
group->bindings[id] = BindingGroup::ENTRY_ACTION;
|
||||||
|
|
||||||
// Load from the config
|
// Load from the config
|
||||||
std::string config_str = Pi::config->String(id.c_str());
|
std::string config_str = m_config->String(id.c_str());
|
||||||
if (config_str.length() > 0) binding.SetFromString(config_str);
|
if (config_str.length() > 0) binding.SetFromString(config_str);
|
||||||
|
|
||||||
return &(actionBindings[id] = binding);
|
return &(actionBindings[id] = binding);
|
||||||
|
@ -110,7 +136,7 @@ KeyBindings::AxisBinding *Input::AddAxisBinding(std::string id, BindingGroup *gr
|
||||||
group->bindings[id] = BindingGroup::ENTRY_AXIS;
|
group->bindings[id] = BindingGroup::ENTRY_AXIS;
|
||||||
|
|
||||||
// Load from the config
|
// Load from the config
|
||||||
std::string config_str = Pi::config->String(id.c_str());
|
std::string config_str = m_config->String(id.c_str());
|
||||||
if (config_str.length() > 0) binding.SetFromString(config_str);
|
if (config_str.length() > 0) binding.SetFromString(config_str);
|
||||||
|
|
||||||
return &(axisBindings[id] = binding);
|
return &(axisBindings[id] = binding);
|
||||||
|
@ -120,30 +146,33 @@ void Input::HandleSDLEvent(SDL_Event &event)
|
||||||
{
|
{
|
||||||
switch (event.type) {
|
switch (event.type) {
|
||||||
case SDL_KEYDOWN:
|
case SDL_KEYDOWN:
|
||||||
keyState[event.key.keysym.sym] = true;
|
// Set key state to "just pressed"
|
||||||
|
keyState[event.key.keysym.sym] = 1;
|
||||||
keyModState = event.key.keysym.mod;
|
keyModState = event.key.keysym.mod;
|
||||||
onKeyPress.emit(&event.key.keysym);
|
onKeyPress.emit(&event.key.keysym);
|
||||||
break;
|
break;
|
||||||
case SDL_KEYUP:
|
case SDL_KEYUP:
|
||||||
keyState[event.key.keysym.sym] = false;
|
// Set key state to "just released"
|
||||||
|
keyState[event.key.keysym.sym] = 4;
|
||||||
keyModState = event.key.keysym.mod;
|
keyModState = event.key.keysym.mod;
|
||||||
onKeyRelease.emit(&event.key.keysym);
|
onKeyRelease.emit(&event.key.keysym);
|
||||||
break;
|
break;
|
||||||
case SDL_MOUSEBUTTONDOWN:
|
case SDL_MOUSEBUTTONDOWN:
|
||||||
if (event.button.button < COUNTOF(mouseButton)) {
|
if (event.button.button < mouseButton.size()) {
|
||||||
mouseButton[event.button.button] = 1;
|
mouseButton[event.button.button] = 1;
|
||||||
onMouseButtonDown.emit(event.button.button,
|
onMouseButtonDown.emit(event.button.button,
|
||||||
event.button.x, event.button.y);
|
event.button.x, event.button.y);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SDL_MOUSEBUTTONUP:
|
case SDL_MOUSEBUTTONUP:
|
||||||
if (event.button.button < COUNTOF(mouseButton)) {
|
if (event.button.button < mouseButton.size()) {
|
||||||
mouseButton[event.button.button] = 0;
|
mouseButton[event.button.button] = 0;
|
||||||
onMouseButtonUp.emit(event.button.button,
|
onMouseButtonUp.emit(event.button.button,
|
||||||
event.button.x, event.button.y);
|
event.button.x, event.button.y);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SDL_MOUSEWHEEL:
|
case SDL_MOUSEWHEEL:
|
||||||
|
mouseWheel = event.wheel.y;
|
||||||
onMouseWheel.emit(event.wheel.y > 0); // true = up
|
onMouseWheel.emit(event.wheel.y > 0); // true = up
|
||||||
break;
|
break;
|
||||||
case SDL_MOUSEMOTION:
|
case SDL_MOUSEMOTION:
|
||||||
|
|
35
src/Input.h
35
src/Input.h
|
@ -8,18 +8,16 @@
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <array>
|
||||||
|
|
||||||
class GameConfig;
|
class IniConfig;
|
||||||
|
|
||||||
class Input {
|
class Input {
|
||||||
// TODO: better decouple these two classes.
|
|
||||||
friend class Pi;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Input() = default;
|
Input(IniConfig *config);
|
||||||
void Init(GameConfig *config);
|
|
||||||
void InitGame();
|
void InitGame();
|
||||||
void HandleSDLEvent(SDL_Event &ev);
|
void HandleSDLEvent(SDL_Event &ev);
|
||||||
|
void NewFrame();
|
||||||
|
|
||||||
// The Page->Group->Binding system serves as a thin veneer for the UI to make
|
// The Page->Group->Binding system serves as a thin veneer for the UI to make
|
||||||
// sane reasonings about how to structure the Options dialog.
|
// sane reasonings about how to structure the Options dialog.
|
||||||
|
@ -94,7 +92,17 @@ public:
|
||||||
return axisBindings.count(id) ? &axisBindings[id] : nullptr;
|
return axisBindings.count(id) ? &axisBindings[id] : nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool KeyState(SDL_Keycode k) { return keyState[k]; }
|
bool KeyState(SDL_Keycode k) { return IsKeyDown(k); }
|
||||||
|
|
||||||
|
// returns true if key K is currently pressed
|
||||||
|
bool IsKeyDown(SDL_Keycode k) { return keyState[k] & 0x3; }
|
||||||
|
|
||||||
|
// returns true if key K was pressed this frame
|
||||||
|
bool IsKeyPressed(SDL_Keycode k) { return keyState[k] == 1; }
|
||||||
|
|
||||||
|
// returns true if key K was released this frame
|
||||||
|
bool IsKeyReleased(SDL_Keycode k) { return keyState[k] == 4; }
|
||||||
|
|
||||||
int KeyModState() { return keyModState; }
|
int KeyModState() { return keyModState; }
|
||||||
|
|
||||||
int JoystickButtonState(int joystick, int button);
|
int JoystickButtonState(int joystick, int button);
|
||||||
|
@ -132,9 +140,11 @@ public:
|
||||||
|
|
||||||
void GetMouseMotion(int motion[2])
|
void GetMouseMotion(int motion[2])
|
||||||
{
|
{
|
||||||
memcpy(motion, mouseMotion, sizeof(int) * 2);
|
std::copy_n(mouseMotion.data(), mouseMotion.size(), motion);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int GetMouseWheel() { return mouseWheel; }
|
||||||
|
|
||||||
// Capturing the mouse hides the cursor, puts the mouse into relative mode,
|
// Capturing the mouse hides the cursor, puts the mouse into relative mode,
|
||||||
// and passes all mouse inputs to the input system, regardless of whether
|
// and passes all mouse inputs to the input system, regardless of whether
|
||||||
// ImGui is using them or not.
|
// ImGui is using them or not.
|
||||||
|
@ -154,10 +164,13 @@ public:
|
||||||
private:
|
private:
|
||||||
void InitJoysticks();
|
void InitJoysticks();
|
||||||
|
|
||||||
std::map<SDL_Keycode, bool> keyState;
|
IniConfig *m_config;
|
||||||
|
|
||||||
|
std::map<SDL_Keycode, uint8_t> keyState;
|
||||||
int keyModState;
|
int keyModState;
|
||||||
char mouseButton[6];
|
std::array<char, 6> mouseButton;
|
||||||
int mouseMotion[2];
|
std::array<int, 2> mouseMotion;
|
||||||
|
int mouseWheel;
|
||||||
bool m_capturingMouse;
|
bool m_capturingMouse;
|
||||||
|
|
||||||
bool joystickEnabled;
|
bool joystickEnabled;
|
||||||
|
|
1397
src/ModelViewer.cpp
1397
src/ModelViewer.cpp
File diff suppressed because it is too large
Load Diff
|
@ -3,66 +3,114 @@
|
||||||
|
|
||||||
#ifndef MODELVIEWER_H
|
#ifndef MODELVIEWER_H
|
||||||
#define MODELVIEWER_H
|
#define MODELVIEWER_H
|
||||||
|
|
||||||
|
#include "Input.h"
|
||||||
#include "NavLights.h"
|
#include "NavLights.h"
|
||||||
#include "Shields.h"
|
#include "Shields.h"
|
||||||
|
#include "core/GuiApplication.h"
|
||||||
#include "graphics/Drawables.h"
|
#include "graphics/Drawables.h"
|
||||||
#include "graphics/Renderer.h"
|
#include "graphics/Renderer.h"
|
||||||
#include "graphics/Texture.h"
|
#include "graphics/Texture.h"
|
||||||
#include "libs.h"
|
#include "libs.h"
|
||||||
#include "lua/LuaManager.h"
|
#include "lua/LuaManager.h"
|
||||||
|
#include "pigui/PiGui.h"
|
||||||
#include "scenegraph/SceneGraph.h"
|
#include "scenegraph/SceneGraph.h"
|
||||||
#include "ui/Context.h"
|
#include "ui/Context.h"
|
||||||
|
|
||||||
class ModelViewer {
|
#include <memory>
|
||||||
public:
|
|
||||||
ModelViewer(Graphics::Renderer *r, LuaManager *l);
|
|
||||||
~ModelViewer();
|
|
||||||
|
|
||||||
static void Run(const std::string &modelName);
|
class Input;
|
||||||
|
class ModelViewer;
|
||||||
|
|
||||||
|
class ModelViewerApp : public GuiApplication {
|
||||||
|
public:
|
||||||
|
ModelViewerApp() :
|
||||||
|
GuiApplication("Model Viewer")
|
||||||
|
{}
|
||||||
|
|
||||||
|
void SetInitialModel(std::string &modelName) { m_modelName = modelName; }
|
||||||
|
std::string &GetModelName() { return m_modelName; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void Startup() override;
|
||||||
|
void Shutdown() override;
|
||||||
|
|
||||||
|
void PreUpdate() override;
|
||||||
|
void PostUpdate() override;
|
||||||
|
|
||||||
|
friend class ModelViewer;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string m_modelName;
|
||||||
|
std::unique_ptr<Input> m_input;
|
||||||
|
std::shared_ptr<ModelViewer> m_modelViewer;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ModelViewer : public Application::Lifecycle {
|
||||||
|
public:
|
||||||
|
enum class CameraPreset : uint8_t {
|
||||||
|
Front,
|
||||||
|
Back,
|
||||||
|
Left,
|
||||||
|
Right,
|
||||||
|
Top,
|
||||||
|
Bottom
|
||||||
|
};
|
||||||
|
|
||||||
|
ModelViewer(ModelViewerApp *app, LuaManager *l);
|
||||||
|
|
||||||
|
void SetModel(const std::string &modelName);
|
||||||
|
bool SetRandomColor();
|
||||||
|
void ResetCamera();
|
||||||
|
void ChangeCameraPreset(CameraPreset preset);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void Start() override;
|
||||||
|
void Update(float deltaTime) override;
|
||||||
|
void End() override;
|
||||||
|
void SetupAxes();
|
||||||
|
void HandleInput();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool OnPickModel(UI::List *);
|
|
||||||
bool OnQuit();
|
|
||||||
bool OnReloadModel(UI::Widget *);
|
|
||||||
bool OnToggleCollMesh(UI::CheckBox *);
|
|
||||||
bool OnToggleShowShields(UI::CheckBox *);
|
|
||||||
bool OnToggleGrid(UI::Widget *);
|
|
||||||
bool OnToggleGuns(UI::CheckBox *);
|
|
||||||
bool OnRandomColor(UI::Widget *);
|
|
||||||
void UpdateShield();
|
|
||||||
bool OnHitIt(UI::Widget *);
|
|
||||||
void HitImpl();
|
|
||||||
void AddLog(const std::string &line);
|
void AddLog(const std::string &line);
|
||||||
void ChangeCameraPreset(SDL_Keycode, SDL_Keymod);
|
|
||||||
|
void UpdateModelList();
|
||||||
|
void UpdateDecalList();
|
||||||
|
void UpdateShield();
|
||||||
|
|
||||||
|
void UpdateCamera(float deltaTime);
|
||||||
|
void UpdateLights();
|
||||||
|
|
||||||
|
void ReloadModel();
|
||||||
|
void SetAnimation(SceneGraph::Animation *anim);
|
||||||
|
void SetDecals(const std::string &file);
|
||||||
|
|
||||||
|
void OnModelChanged();
|
||||||
|
|
||||||
|
void ToggleCollMesh();
|
||||||
|
void ToggleShowShields();
|
||||||
|
void ToggleGrid();
|
||||||
|
void ToggleGuns();
|
||||||
|
void HitIt();
|
||||||
|
|
||||||
void ToggleViewControlMode();
|
void ToggleViewControlMode();
|
||||||
void ClearLog();
|
|
||||||
void ClearModel();
|
void ClearModel();
|
||||||
void CreateTestResources();
|
void CreateTestResources();
|
||||||
void DrawBackground();
|
void DrawBackground();
|
||||||
void DrawGrid(const matrix4x4f &trans, float radius);
|
void DrawGrid(const matrix4x4f &trans, float radius);
|
||||||
void DrawModel(const matrix4x4f &mv);
|
void DrawModel(const matrix4x4f &mv);
|
||||||
void MainLoop();
|
|
||||||
void OnAnimChanged(unsigned int, const std::string &);
|
|
||||||
void OnAnimSliderChanged(float);
|
|
||||||
void OnDecalChanged(unsigned int, const std::string &);
|
|
||||||
void OnLightPresetChanged(unsigned int index, const std::string &);
|
|
||||||
void OnModelColorsChanged(float);
|
|
||||||
void OnPatternChanged(unsigned int, const std::string &);
|
|
||||||
void OnThrustChanged(float);
|
|
||||||
void PollEvents();
|
|
||||||
void PopulateFilePicker();
|
|
||||||
void ResetCamera();
|
|
||||||
void ResetThrusters();
|
void ResetThrusters();
|
||||||
void Screenshot();
|
void Screenshot();
|
||||||
void SaveModelToBinary();
|
void SaveModelToBinary();
|
||||||
void SetModel(const std::string &name);
|
|
||||||
void SetupFilePicker();
|
|
||||||
void SetupUI();
|
|
||||||
void UpdateAnimList();
|
|
||||||
void UpdateCamera();
|
|
||||||
void UpdateLights();
|
|
||||||
void UpdatePatternList();
|
|
||||||
|
|
||||||
|
void DrawModelSelector();
|
||||||
|
void DrawModelOptions();
|
||||||
|
void DrawShipControls();
|
||||||
|
void DrawLog();
|
||||||
|
void DrawPiGui();
|
||||||
|
|
||||||
|
private:
|
||||||
//toggleable options
|
//toggleable options
|
||||||
struct Options {
|
struct Options {
|
||||||
bool attachGuns;
|
bool attachGuns;
|
||||||
|
@ -77,17 +125,69 @@ private:
|
||||||
bool wireframe;
|
bool wireframe;
|
||||||
bool mouselookEnabled;
|
bool mouselookEnabled;
|
||||||
float gridInterval;
|
float gridInterval;
|
||||||
int lightPreset;
|
uint32_t lightPreset;
|
||||||
bool orthoView;
|
bool orthoView;
|
||||||
|
|
||||||
Options();
|
Options();
|
||||||
};
|
};
|
||||||
bool m_done;
|
|
||||||
|
private:
|
||||||
|
ModelViewerApp *m_app;
|
||||||
|
Input *m_input;
|
||||||
|
PiGui::Instance *m_pigui;
|
||||||
|
|
||||||
|
KeyBindings::AxisBinding *m_moveForward;
|
||||||
|
KeyBindings::AxisBinding *m_moveLeft;
|
||||||
|
KeyBindings::AxisBinding *m_moveUp;
|
||||||
|
KeyBindings::AxisBinding *m_zoomAxis;
|
||||||
|
|
||||||
|
KeyBindings::AxisBinding *m_rotateViewLeft;
|
||||||
|
KeyBindings::AxisBinding *m_rotateViewUp;
|
||||||
|
|
||||||
|
KeyBindings::ActionBinding *m_viewTop;
|
||||||
|
KeyBindings::ActionBinding *m_viewLeft;
|
||||||
|
KeyBindings::ActionBinding *m_viewFront;
|
||||||
|
|
||||||
|
vector2f m_windowSize;
|
||||||
|
vector2f m_logWindowSize;
|
||||||
|
vector2f m_animWindowSize;
|
||||||
|
std::vector<std::string> m_log;
|
||||||
|
bool m_resetLogScroll = false;
|
||||||
|
|
||||||
|
vector3f m_linearThrust = {};
|
||||||
|
vector3f m_angularThrust = {};
|
||||||
|
|
||||||
|
// Model pattern colors
|
||||||
|
std::vector<Color> m_colors;
|
||||||
|
|
||||||
|
std::vector<std::string> m_fileNames;
|
||||||
|
std::string m_modelName;
|
||||||
|
std::string m_requestedModelName;
|
||||||
|
|
||||||
|
std::unique_ptr<SceneGraph::Model> m_model;
|
||||||
|
bool m_modelIsShip = false;
|
||||||
|
|
||||||
|
std::vector<SceneGraph::Animation *> m_animations;
|
||||||
|
SceneGraph::Animation *m_currentAnimation = nullptr;
|
||||||
|
|
||||||
|
bool m_modelSupportsPatterns = false;
|
||||||
|
std::vector<std::string> m_patterns;
|
||||||
|
uint32_t m_currentPattern = 0;
|
||||||
|
|
||||||
|
bool m_modelSupportsDecals = false;
|
||||||
|
std::vector<std::string> m_decals;
|
||||||
|
uint32_t m_currentDecal = 0;
|
||||||
|
|
||||||
|
bool m_modelHasShields = false;
|
||||||
|
std::unique_ptr<Shields> m_shields;
|
||||||
|
std::unique_ptr<NavLights> m_navLights;
|
||||||
|
std::unique_ptr<SceneGraph::Model> m_gunModel;
|
||||||
|
std::unique_ptr<SceneGraph::Model> m_scaleModel;
|
||||||
|
|
||||||
bool m_screenshotQueued;
|
bool m_screenshotQueued;
|
||||||
bool m_shieldIsHit;
|
bool m_shieldIsHit;
|
||||||
bool m_settingColourSliders;
|
bool m_settingColourSliders;
|
||||||
float m_shieldHitPan;
|
float m_shieldHitPan;
|
||||||
double m_frameTime;
|
|
||||||
Graphics::Renderer *m_renderer;
|
Graphics::Renderer *m_renderer;
|
||||||
Graphics::Texture *m_decalTexture;
|
Graphics::Texture *m_decalTexture;
|
||||||
vector3f m_viewPos;
|
vector3f m_viewPos;
|
||||||
|
@ -95,41 +195,13 @@ private:
|
||||||
float m_rotX, m_rotY, m_zoom;
|
float m_rotX, m_rotY, m_zoom;
|
||||||
float m_baseDistance;
|
float m_baseDistance;
|
||||||
Random m_rng;
|
Random m_rng;
|
||||||
SceneGraph::Animation *m_currentAnimation;
|
|
||||||
SceneGraph::Model *m_model;
|
|
||||||
Options m_options;
|
Options m_options;
|
||||||
float m_landingMinOffset;
|
float m_landingMinOffset;
|
||||||
std::unique_ptr<NavLights> m_navLights;
|
|
||||||
std::unique_ptr<Shields> m_shields;
|
|
||||||
std::unique_ptr<SceneGraph::Model> m_gunModel;
|
|
||||||
std::unique_ptr<SceneGraph::Model> m_scaleModel;
|
|
||||||
std::string m_modelName;
|
|
||||||
std::string m_requestedModelName;
|
|
||||||
RefCountedPtr<UI::Context> m_ui;
|
|
||||||
Graphics::RenderState *m_bgState;
|
Graphics::RenderState *m_bgState;
|
||||||
RefCountedPtr<Graphics::VertexBuffer> m_bgBuffer;
|
RefCountedPtr<Graphics::VertexBuffer> m_bgBuffer;
|
||||||
|
|
||||||
//undecided on this input stuff
|
|
||||||
//updating the states of all inputs during PollEvents
|
|
||||||
std::map<SDL_Keycode, bool> m_keyStates;
|
|
||||||
bool m_mouseButton[SDL_BUTTON_RIGHT + 1]; //buttons start at 1
|
|
||||||
int m_mouseMotion[2];
|
|
||||||
bool m_mouseWheelUp, m_mouseWheelDown;
|
|
||||||
|
|
||||||
//interface stuff that needs to be accessed later (unorganized)
|
|
||||||
UI::MultiLineText *m_log;
|
|
||||||
RefCountedPtr<UI::Scroller> m_logScroller;
|
|
||||||
|
|
||||||
UI::List *m_fileList;
|
|
||||||
UI::DropDown *animSelector;
|
|
||||||
UI::DropDown *patternSelector;
|
|
||||||
UI::DropDown *decalSelector;
|
|
||||||
UI::Label *nameLabel;
|
|
||||||
UI::Slider *animSlider;
|
|
||||||
UI::Label *animValue;
|
|
||||||
UI::Slider *colorSliders[9];
|
|
||||||
UI::Slider *thrustSliders[2 * 3]; //thruster sliders 2*xyz (linear & angular)
|
|
||||||
|
|
||||||
sigc::signal<void> onModelChanged;
|
sigc::signal<void> onModelChanged;
|
||||||
|
|
||||||
Graphics::Drawables::Lines m_gridLines;
|
Graphics::Drawables::Lines m_gridLines;
|
||||||
|
|
171
src/Pi.cpp
171
src/Pi.cpp
|
@ -25,9 +25,11 @@
|
||||||
#include "NavLights.h"
|
#include "NavLights.h"
|
||||||
#include "OS.h"
|
#include "OS.h"
|
||||||
#include "core/GuiApplication.h"
|
#include "core/GuiApplication.h"
|
||||||
|
#include "graphics/opengl/RendererGL.h"
|
||||||
#include "lua/Lua.h"
|
#include "lua/Lua.h"
|
||||||
#include "lua/LuaConsole.h"
|
#include "lua/LuaConsole.h"
|
||||||
#include "lua/LuaEvent.h"
|
#include "lua/LuaEvent.h"
|
||||||
|
#include "lua/LuaPiGui.h"
|
||||||
#include "lua/LuaTimer.h"
|
#include "lua/LuaTimer.h"
|
||||||
#include "profiler/Profiler.h"
|
#include "profiler/Profiler.h"
|
||||||
#include "sound/AmbientSounds.h"
|
#include "sound/AmbientSounds.h"
|
||||||
|
@ -133,7 +135,7 @@ float Pi::amountOfBackgroundStarsDisplayed = 1.0f;
|
||||||
bool Pi::DrawGUI = true;
|
bool Pi::DrawGUI = true;
|
||||||
Graphics::Renderer *Pi::renderer;
|
Graphics::Renderer *Pi::renderer;
|
||||||
RefCountedPtr<UI::Context> Pi::ui;
|
RefCountedPtr<UI::Context> Pi::ui;
|
||||||
RefCountedPtr<PiGui> Pi::pigui;
|
PiGui::Instance *Pi::pigui = nullptr;
|
||||||
ModelCache *Pi::modelCache;
|
ModelCache *Pi::modelCache;
|
||||||
Intro *Pi::intro;
|
Intro *Pi::intro;
|
||||||
SDLGraphics *Pi::sdl;
|
SDLGraphics *Pi::sdl;
|
||||||
|
@ -361,8 +363,7 @@ void Pi::App::Startup()
|
||||||
Pi::rng.IncRefCount(); // so nothing tries to free it
|
Pi::rng.IncRefCount(); // so nothing tries to free it
|
||||||
Pi::rng.seed(time(0));
|
Pi::rng.seed(time(0));
|
||||||
|
|
||||||
Pi::input = new Input();
|
Pi::input = StartupInput(config);
|
||||||
Pi::input->Init(Pi::config);
|
|
||||||
Pi::input->onKeyPress.connect(sigc::ptr_fun(&Pi::HandleKeyDown));
|
Pi::input->onKeyPress.connect(sigc::ptr_fun(&Pi::HandleKeyDown));
|
||||||
|
|
||||||
// we can only do bindings once joysticks are initialised.
|
// we can only do bindings once joysticks are initialised.
|
||||||
|
@ -371,6 +372,8 @@ void Pi::App::Startup()
|
||||||
|
|
||||||
RegisterInputBindings();
|
RegisterInputBindings();
|
||||||
|
|
||||||
|
Pi::pigui = StartupPiGui();
|
||||||
|
|
||||||
// FIXME: move these into the appropriate class!
|
// FIXME: move these into the appropriate class!
|
||||||
navTunnelDisplayed = (config->Int("DisplayNavTunnel")) ? true : false;
|
navTunnelDisplayed = (config->Int("DisplayNavTunnel")) ? true : false;
|
||||||
speedLinesDisplayed = (config->Int("SpeedLines")) ? true : false;
|
speedLinesDisplayed = (config->Int("SpeedLines")) ? true : false;
|
||||||
|
@ -438,9 +441,11 @@ void Pi::App::Shutdown()
|
||||||
BaseSphere::Uninit();
|
BaseSphere::Uninit();
|
||||||
FaceParts::Uninit();
|
FaceParts::Uninit();
|
||||||
Graphics::Uninit();
|
Graphics::Uninit();
|
||||||
Pi::pigui->Uninit();
|
|
||||||
|
PiGUI::Lua::Uninit();
|
||||||
|
ShutdownPiGui();
|
||||||
|
Pi::pigui = nullptr;
|
||||||
Pi::ui.Reset(0);
|
Pi::ui.Reset(0);
|
||||||
Pi::pigui.Reset(0);
|
|
||||||
Lua::UninitModules();
|
Lua::UninitModules();
|
||||||
Lua::Uninit();
|
Lua::Uninit();
|
||||||
Gui::Uninit();
|
Gui::Uninit();
|
||||||
|
@ -452,6 +457,9 @@ void Pi::App::Shutdown()
|
||||||
ShutdownRenderer();
|
ShutdownRenderer();
|
||||||
Pi::renderer = nullptr;
|
Pi::renderer = nullptr;
|
||||||
|
|
||||||
|
ShutdownInput();
|
||||||
|
Pi::input = nullptr;
|
||||||
|
|
||||||
delete Pi::config;
|
delete Pi::config;
|
||||||
delete Pi::planner;
|
delete Pi::planner;
|
||||||
asyncJobQueue.reset();
|
asyncJobQueue.reset();
|
||||||
|
@ -489,14 +497,12 @@ void LoadStep::Start()
|
||||||
// TODO: Get the lua state responsible for drawing the init progress up as fast as possible
|
// TODO: Get the lua state responsible for drawing the init progress up as fast as possible
|
||||||
// Investigate using a pigui-only Lua state that we can initialize without depending on
|
// Investigate using a pigui-only Lua state that we can initialize without depending on
|
||||||
// normal init flow, or drawing the init screen in C++ instead?
|
// normal init flow, or drawing the init screen in C++ instead?
|
||||||
// Ideally we can initialize the ImGui related parts of pigui as soon as the renderer is online,
|
// Loads just the PiGui class and PiGui-related modules
|
||||||
// and then load all the lua-related state once Lua's registered and online...
|
PiGUI::Lua::Init();
|
||||||
Pi::pigui.Reset(new PiGui);
|
|
||||||
Pi::pigui->Init(Pi::renderer->GetSDLWindow());
|
|
||||||
|
|
||||||
// Don't render the first frame, just make sure all of our fonts are loaded
|
// Don't render the first frame, just make sure all of our fonts are loaded
|
||||||
Pi::pigui->NewFrame(Pi::renderer->GetSDLWindow());
|
Pi::pigui->NewFrame();
|
||||||
Pi::pigui->RunHandler(0.01, "INIT");
|
PiGUI::RunHandler(0.01, "INIT");
|
||||||
Pi::pigui->EndFrame();
|
Pi::pigui->EndFrame();
|
||||||
|
|
||||||
AddStep("UI::AddContext", []() {
|
AddStep("UI::AddContext", []() {
|
||||||
|
@ -608,8 +614,8 @@ void LoadStep::Update(float deltaTime)
|
||||||
Output("Loading [%02.f%%]: %s took %.2fms\n", progress * 100.,
|
Output("Loading [%02.f%%]: %s took %.2fms\n", progress * 100.,
|
||||||
loader.name.c_str(), timer.milliseconds());
|
loader.name.c_str(), timer.milliseconds());
|
||||||
|
|
||||||
Pi::pigui->NewFrame(Pi::renderer->GetSDLWindow());
|
Pi::pigui->NewFrame();
|
||||||
Pi::pigui->RunHandler(progress, "INIT");
|
PiGUI::RunHandler(progress, "INIT");
|
||||||
Pi::pigui->Render();
|
Pi::pigui->Render();
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
@ -643,43 +649,12 @@ void MainMenu::Start()
|
||||||
|
|
||||||
void MainMenu::Update(float deltaTime)
|
void MainMenu::Update(float deltaTime)
|
||||||
{
|
{
|
||||||
SDL_Event event;
|
Pi::GetApp()->HandleEvents();
|
||||||
while (SDL_PollEvent(&event)) {
|
|
||||||
if (event.type == SDL_QUIT)
|
|
||||||
Pi::RequestQuit();
|
|
||||||
else {
|
|
||||||
Pi::pigui->ProcessEvent(&event);
|
|
||||||
|
|
||||||
if (Pi::pigui->WantCaptureMouse()) {
|
|
||||||
// don't process mouse event any further, imgui already handled it
|
|
||||||
switch (event.type) {
|
|
||||||
case SDL_MOUSEBUTTONDOWN:
|
|
||||||
case SDL_MOUSEBUTTONUP:
|
|
||||||
case SDL_MOUSEWHEEL:
|
|
||||||
case SDL_MOUSEMOTION:
|
|
||||||
continue;
|
|
||||||
default: break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (Pi::pigui->WantCaptureKeyboard()) {
|
|
||||||
// don't process keyboard event any further, imgui already handled it
|
|
||||||
switch (event.type) {
|
|
||||||
case SDL_KEYDOWN:
|
|
||||||
case SDL_KEYUP:
|
|
||||||
case SDL_TEXTINPUT:
|
|
||||||
continue;
|
|
||||||
default: break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Pi::input->HandleSDLEvent(event);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Pi::intro->Draw(deltaTime);
|
Pi::intro->Draw(deltaTime);
|
||||||
|
|
||||||
Pi::pigui->NewFrame(Pi::renderer->GetSDLWindow());
|
Pi::pigui->NewFrame();
|
||||||
Pi::pigui->RunHandler(deltaTime, "MAINMENU");
|
PiGUI::RunHandler(deltaTime, "MAINMENU");
|
||||||
|
|
||||||
Pi::pigui->Render();
|
Pi::pigui->Render();
|
||||||
|
|
||||||
|
@ -847,12 +822,13 @@ void Pi::HandleEscKey()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Pi::App::HandleEvents()
|
// Return true if the event has been handled and shouldn't be passed through
|
||||||
|
// to the normal input system.
|
||||||
|
bool Pi::App::HandleEvent(SDL_Event &event)
|
||||||
{
|
{
|
||||||
PROFILE_SCOPED()
|
PROFILE_SCOPED()
|
||||||
SDL_Event event;
|
|
||||||
|
|
||||||
// XXX for most keypresses SDL will generate KEYUP/KEYDOWN and TEXTINPUT
|
// HACK for most keypresses SDL will generate KEYUP/KEYDOWN and TEXTINPUT
|
||||||
// events. keybindings run off KEYUP/KEYDOWN. the console is opened/closed
|
// events. keybindings run off KEYUP/KEYDOWN. the console is opened/closed
|
||||||
// via keybinding. the console TextInput widget uses TEXTINPUT events. thus
|
// via keybinding. the console TextInput widget uses TEXTINPUT events. thus
|
||||||
// after switching the console, the stray TEXTINPUT event causes the
|
// after switching the console, the stray TEXTINPUT event causes the
|
||||||
|
@ -860,64 +836,37 @@ void Pi::App::HandleEvents()
|
||||||
// this by setting this flag if the console was switched. if its set, we
|
// this by setting this flag if the console was switched. if its set, we
|
||||||
// swallow the TEXTINPUT event this hack must remain until we have a
|
// swallow the TEXTINPUT event this hack must remain until we have a
|
||||||
// unified input system
|
// unified input system
|
||||||
bool skipTextInput = false;
|
// This is safely able to be removed once GUI and newUI are gone
|
||||||
|
static bool skipTextInput = false;
|
||||||
|
|
||||||
Pi::input->mouseMotion[0] = Pi::input->mouseMotion[1] = 0;
|
if (skipTextInput && event.type == SDL_TEXTINPUT) {
|
||||||
while (SDL_PollEvent(&event)) {
|
skipTextInput = false;
|
||||||
if (event.type == SDL_QUIT) {
|
return true;
|
||||||
Pi::RequestQuit();
|
|
||||||
}
|
|
||||||
|
|
||||||
Pi::pigui->ProcessEvent(&event);
|
|
||||||
|
|
||||||
// Input system takes priority over mouse events when capturing the mouse
|
|
||||||
if (Pi::pigui->WantCaptureMouse() && !Pi::input->IsCapturingMouse()) {
|
|
||||||
// don't process mouse event any further, imgui already handled it
|
|
||||||
switch (event.type) {
|
|
||||||
case SDL_MOUSEBUTTONDOWN:
|
|
||||||
case SDL_MOUSEBUTTONUP:
|
|
||||||
case SDL_MOUSEWHEEL:
|
|
||||||
case SDL_MOUSEMOTION:
|
|
||||||
continue;
|
|
||||||
default: break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (Pi::pigui->WantCaptureKeyboard()) {
|
|
||||||
// don't process keyboard event any further, imgui already handled it
|
|
||||||
switch (event.type) {
|
|
||||||
case SDL_KEYDOWN:
|
|
||||||
case SDL_KEYUP:
|
|
||||||
case SDL_TEXTINPUT:
|
|
||||||
continue;
|
|
||||||
default: break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (skipTextInput && event.type == SDL_TEXTINPUT) {
|
|
||||||
skipTextInput = false;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (ui->DispatchSDLEvent(event))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
bool consoleActive = Pi::IsConsoleActive();
|
|
||||||
if (!consoleActive) {
|
|
||||||
KeyBindings::DispatchSDLEvent(&event);
|
|
||||||
if (currentView)
|
|
||||||
currentView->HandleSDLEvent(event);
|
|
||||||
} else
|
|
||||||
KeyBindings::toggleLuaConsole.CheckSDLEventAndDispatch(&event);
|
|
||||||
if (consoleActive != Pi::IsConsoleActive()) {
|
|
||||||
skipTextInput = true;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Pi::IsConsoleActive())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
Gui::HandleSDLEvent(&event);
|
|
||||||
input->HandleSDLEvent(event);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ui->DispatchSDLEvent(event))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
bool consoleActive = Pi::IsConsoleActive();
|
||||||
|
if (!consoleActive) {
|
||||||
|
KeyBindings::DispatchSDLEvent(&event);
|
||||||
|
if (currentView)
|
||||||
|
currentView->HandleSDLEvent(event);
|
||||||
|
} else {
|
||||||
|
KeyBindings::toggleLuaConsole.CheckSDLEventAndDispatch(&event);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (consoleActive != Pi::IsConsoleActive()) {
|
||||||
|
skipTextInput = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Pi::IsConsoleActive())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
Gui::HandleSDLEvent(&event);
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Pi::App::HandleRequests()
|
void Pi::App::HandleRequests()
|
||||||
|
@ -1126,10 +1075,16 @@ void GameLoop::Update(float deltaTime)
|
||||||
Pi::ui->Draw();
|
Pi::ui->Draw();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Ask ImGui to hide OS cursor if we're capturing it for input:
|
||||||
|
// it will do this if GetMouseCursor == ImGuiMouseCursor_None.
|
||||||
|
if (Pi::input->IsCapturingMouse()) {
|
||||||
|
ImGui::SetMouseCursor(ImGuiMouseCursor_None);
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: the escape menu depends on HandleEvents() being called before NewFrame()
|
// TODO: the escape menu depends on HandleEvents() being called before NewFrame()
|
||||||
// Move HandleEvents to either the end of the loop or the very start of the loop
|
// Move HandleEvents to either the end of the loop or the very start of the loop
|
||||||
// The goal is to be able to call imgui functions for debugging inside C++ code
|
// The goal is to be able to call imgui functions for debugging inside C++ code
|
||||||
Pi::pigui->NewFrame(Pi::renderer->GetSDLWindow());
|
Pi::pigui->NewFrame();
|
||||||
|
|
||||||
if (Pi::game && !Pi::player->IsDead()) {
|
if (Pi::game && !Pi::player->IsDead()) {
|
||||||
// FIXME: Always begin a camera frame because WorldSpaceToScreenSpace
|
// FIXME: Always begin a camera frame because WorldSpaceToScreenSpace
|
||||||
|
@ -1137,7 +1092,7 @@ void GameLoop::Update(float deltaTime)
|
||||||
Pi::game->GetWorldView()->BeginCameraFrame();
|
Pi::game->GetWorldView()->BeginCameraFrame();
|
||||||
// FIXME: major hack to work around the fact that the console is in newUI and not pigui
|
// FIXME: major hack to work around the fact that the console is in newUI and not pigui
|
||||||
if (!Pi::IsConsoleActive())
|
if (!Pi::IsConsoleActive())
|
||||||
Pi::pigui->RunHandler(deltaTime, "GAME");
|
PiGUI::RunHandler(deltaTime, "GAME");
|
||||||
Pi::game->GetWorldView()->EndCameraFrame();
|
Pi::game->GetWorldView()->EndCameraFrame();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
9
src/Pi.h
9
src/Pi.h
|
@ -16,6 +16,10 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
namespace PiGui {
|
||||||
|
class Instance;
|
||||||
|
} //namespace PiGui
|
||||||
|
|
||||||
class Game;
|
class Game;
|
||||||
|
|
||||||
class GameConfig;
|
class GameConfig;
|
||||||
|
@ -26,7 +30,6 @@ class LuaNameGen;
|
||||||
class LuaTimer;
|
class LuaTimer;
|
||||||
class ModelCache;
|
class ModelCache;
|
||||||
class ObjectViewerView;
|
class ObjectViewerView;
|
||||||
class PiGui;
|
|
||||||
class Player;
|
class Player;
|
||||||
class SystemPath;
|
class SystemPath;
|
||||||
class TransferPlanner;
|
class TransferPlanner;
|
||||||
|
@ -101,7 +104,7 @@ public:
|
||||||
void RunJobs();
|
void RunJobs();
|
||||||
|
|
||||||
void HandleRequests();
|
void HandleRequests();
|
||||||
void HandleEvents();
|
bool HandleEvent(SDL_Event &ev) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// msgs/requests that can be posted which the game processes at the end of a game loop in HandleRequests
|
// msgs/requests that can be posted which the game processes at the end of a game loop in HandleRequests
|
||||||
|
@ -170,7 +173,7 @@ public:
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static RefCountedPtr<UI::Context> ui;
|
static RefCountedPtr<UI::Context> ui;
|
||||||
static RefCountedPtr<PiGui> pigui;
|
static PiGui::Instance *pigui;
|
||||||
|
|
||||||
static Random rng;
|
static Random rng;
|
||||||
static int statSceneTris;
|
static int statSceneTris;
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#include "Application.h"
|
#include "Application.h"
|
||||||
#include "FileSystem.h"
|
#include "FileSystem.h"
|
||||||
#include "OS.h"
|
#include "OS.h"
|
||||||
|
#include "SDL.h"
|
||||||
#include "profiler/Profiler.h"
|
#include "profiler/Profiler.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
|
||||||
|
@ -33,11 +34,14 @@ void Application::Startup()
|
||||||
#ifdef PIONEER_PROFILER
|
#ifdef PIONEER_PROFILER
|
||||||
FileSystem::userFiles.MakeDirectory("profiler");
|
FileSystem::userFiles.MakeDirectory("profiler");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
SDL_Init(SDL_INIT_EVENTS);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::Shutdown()
|
void Application::Shutdown()
|
||||||
{
|
{
|
||||||
FileSystem::Uninit();
|
FileSystem::Uninit();
|
||||||
|
SDL_Quit();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Application::StartLifecycle()
|
bool Application::StartLifecycle()
|
||||||
|
@ -138,7 +142,7 @@ void Application::Run()
|
||||||
|
|
||||||
EndFrame();
|
EndFrame();
|
||||||
|
|
||||||
if (m_activeLifecycle->m_endLifecycle) {
|
if (m_activeLifecycle->m_endLifecycle || !m_applicationRunning) {
|
||||||
EndLifecycle();
|
EndLifecycle();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -40,8 +40,6 @@ public:
|
||||||
m_nextLifecycle = l;
|
m_nextLifecycle = l;
|
||||||
}
|
}
|
||||||
|
|
||||||
Application *GetApp();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// set to true when you want to accumulate all updates in a lifecycle into a single profile frame
|
// set to true when you want to accumulate all updates in a lifecycle into a single profile frame
|
||||||
bool m_profilerAccumulate = false;
|
bool m_profilerAccumulate = false;
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
#include "graphics/RenderTarget.h"
|
#include "graphics/RenderTarget.h"
|
||||||
#include "graphics/Renderer.h"
|
#include "graphics/Renderer.h"
|
||||||
#include "graphics/Texture.h"
|
#include "graphics/Texture.h"
|
||||||
|
#include "pigui/PiGui.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "versioningInfo.h"
|
#include "versioningInfo.h"
|
||||||
|
|
||||||
|
@ -31,7 +32,8 @@ void GuiApplication::BeginFrame()
|
||||||
void GuiApplication::DrawRenderTarget()
|
void GuiApplication::DrawRenderTarget()
|
||||||
{
|
{
|
||||||
#if RTT
|
#if RTT
|
||||||
m_renderer->BeginFrame();
|
m_renderer->SetRenderTarget(nullptr);
|
||||||
|
m_renderer->ClearScreen();
|
||||||
m_renderer->SetViewport(0, 0, Graphics::GetScreenWidth(), Graphics::GetScreenHeight());
|
m_renderer->SetViewport(0, 0, Graphics::GetScreenWidth(), Graphics::GetScreenHeight());
|
||||||
m_renderer->SetTransform(matrix4x4f::Identity());
|
m_renderer->SetTransform(matrix4x4f::Identity());
|
||||||
|
|
||||||
|
@ -60,9 +62,9 @@ void GuiApplication::DrawRenderTarget()
|
||||||
void GuiApplication::EndFrame()
|
void GuiApplication::EndFrame()
|
||||||
{
|
{
|
||||||
#if RTT
|
#if RTT
|
||||||
m_renderer->SetRenderTarget(nullptr);
|
|
||||||
DrawRenderTarget();
|
DrawRenderTarget();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
m_renderer->EndFrame();
|
m_renderer->EndFrame();
|
||||||
m_renderer->SwapBuffers();
|
m_renderer->SwapBuffers();
|
||||||
}
|
}
|
||||||
|
@ -100,7 +102,55 @@ Graphics::RenderTarget *GuiApplication::CreateRenderTarget(const Graphics::Setti
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
Graphics::Renderer *GuiApplication::StartupRenderer(const GameConfig *config, bool hidden)
|
void GuiApplication::HandleEvents()
|
||||||
|
{
|
||||||
|
PROFILE_SCOPED()
|
||||||
|
SDL_Event event;
|
||||||
|
|
||||||
|
// FIXME: input state is right before handling updates because
|
||||||
|
// legacy UI code needs to run before input does.
|
||||||
|
// When HandleEvents() is moved to BeginFrame / PreUpdate, this call should go with it
|
||||||
|
m_input->NewFrame();
|
||||||
|
|
||||||
|
while (SDL_PollEvent(&event)) {
|
||||||
|
if (event.type == SDL_QUIT) {
|
||||||
|
RequestQuit();
|
||||||
|
}
|
||||||
|
|
||||||
|
m_pigui->ProcessEvent(&event);
|
||||||
|
|
||||||
|
// Input system takes priority over mouse events when capturing the mouse
|
||||||
|
if (PiGui::WantCaptureMouse() && !m_input->IsCapturingMouse()) {
|
||||||
|
// don't process mouse event any further, imgui already handled it
|
||||||
|
switch (event.type) {
|
||||||
|
case SDL_MOUSEBUTTONDOWN:
|
||||||
|
case SDL_MOUSEBUTTONUP:
|
||||||
|
case SDL_MOUSEWHEEL:
|
||||||
|
case SDL_MOUSEMOTION:
|
||||||
|
continue;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (PiGui::WantCaptureKeyboard()) {
|
||||||
|
// don't process keyboard event any further, imgui already handled it
|
||||||
|
switch (event.type) {
|
||||||
|
case SDL_KEYDOWN:
|
||||||
|
case SDL_KEYUP:
|
||||||
|
case SDL_TEXTINPUT:
|
||||||
|
continue;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: virtual method dispatch for each event isn't great. Let's find a better solution
|
||||||
|
if (HandleEvent(event))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
m_input->HandleSDLEvent(event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Graphics::Renderer *GuiApplication::StartupRenderer(IniConfig *config, bool hidden)
|
||||||
{
|
{
|
||||||
PROFILE_SCOPED()
|
PROFILE_SCOPED()
|
||||||
// Initialize SDL
|
// Initialize SDL
|
||||||
|
@ -145,3 +195,28 @@ void GuiApplication::ShutdownRenderer()
|
||||||
|
|
||||||
SDL_QuitSubSystem(SDL_INIT_VIDEO);
|
SDL_QuitSubSystem(SDL_INIT_VIDEO);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Input *GuiApplication::StartupInput(IniConfig *config)
|
||||||
|
{
|
||||||
|
m_input.reset(new Input(config));
|
||||||
|
|
||||||
|
return m_input.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GuiApplication::ShutdownInput()
|
||||||
|
{
|
||||||
|
m_input.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
PiGui::Instance *GuiApplication::StartupPiGui()
|
||||||
|
{
|
||||||
|
m_pigui.Reset(new PiGui::Instance());
|
||||||
|
m_pigui->Init(GetRenderer());
|
||||||
|
return m_pigui.Get();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GuiApplication::ShutdownPiGui()
|
||||||
|
{
|
||||||
|
m_pigui->Uninit();
|
||||||
|
m_pigui.Reset();
|
||||||
|
}
|
||||||
|
|
|
@ -4,32 +4,51 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "Application.h"
|
#include "Application.h"
|
||||||
#include "GameConfig.h"
|
#include "Input.h"
|
||||||
#include "RefCounted.h"
|
#include "RefCounted.h"
|
||||||
|
#include "SDL_events.h"
|
||||||
|
#include "pigui/PiGui.h"
|
||||||
|
|
||||||
#include "graphics/RenderState.h"
|
#include "graphics/RenderState.h"
|
||||||
#include "graphics/RenderTarget.h"
|
#include "graphics/RenderTarget.h"
|
||||||
#include "graphics/Renderer.h"
|
#include "graphics/Renderer.h"
|
||||||
|
|
||||||
|
class IniConfig;
|
||||||
|
|
||||||
class GuiApplication : public Application {
|
class GuiApplication : public Application {
|
||||||
public:
|
public:
|
||||||
GuiApplication(std::string title) :
|
GuiApplication(std::string title) :
|
||||||
Application(), m_applicationTitle(title)
|
Application(), m_applicationTitle(title)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
protected:
|
|
||||||
Graphics::Renderer *GetRenderer() { return m_renderer.get(); }
|
Graphics::Renderer *GetRenderer() { return m_renderer.get(); }
|
||||||
|
Input *GetInput() { return m_input.get(); }
|
||||||
|
PiGui::Instance *GetPiGui() { return m_pigui.Get(); }
|
||||||
|
|
||||||
|
protected:
|
||||||
// Called at the end of the frame automatically, blits the RT onto the application
|
// Called at the end of the frame automatically, blits the RT onto the application
|
||||||
// framebuffer
|
// framebuffer
|
||||||
void DrawRenderTarget();
|
void DrawRenderTarget();
|
||||||
|
|
||||||
|
// TODO: unify config handling, possibly make the config an Application member
|
||||||
// Call this from your Startup() method
|
// Call this from your Startup() method
|
||||||
Graphics::Renderer *StartupRenderer(const GameConfig *config, bool hidden = false);
|
Graphics::Renderer *StartupRenderer(IniConfig *config, bool hidden = false);
|
||||||
|
|
||||||
|
// Call this from your Startup() method
|
||||||
|
Input *StartupInput(IniConfig *config);
|
||||||
|
|
||||||
|
// Call this from your Startup() method
|
||||||
|
PiGui::Instance *StartupPiGui();
|
||||||
|
|
||||||
// Call this from your Shutdown() method
|
// Call this from your Shutdown() method
|
||||||
void ShutdownRenderer();
|
void ShutdownRenderer();
|
||||||
|
|
||||||
|
// Call this from your Shutdown() method
|
||||||
|
void ShutdownInput();
|
||||||
|
|
||||||
|
// Call this from your shutdown() method
|
||||||
|
void ShutdownPiGui();
|
||||||
|
|
||||||
// Hook to bind the RT and clear the screen.
|
// Hook to bind the RT and clear the screen.
|
||||||
// If you override BeginFrame, make sure you call this.
|
// If you override BeginFrame, make sure you call this.
|
||||||
void BeginFrame() override;
|
void BeginFrame() override;
|
||||||
|
@ -38,9 +57,21 @@ protected:
|
||||||
// If you override EndFrame, make sure you call this.
|
// If you override EndFrame, make sure you call this.
|
||||||
void EndFrame() override;
|
void EndFrame() override;
|
||||||
|
|
||||||
|
// Consume events from SDL and dispatch to pigui / input
|
||||||
|
void HandleEvents();
|
||||||
|
|
||||||
|
// Override point for classes to add custom event handling
|
||||||
|
virtual bool HandleEvent(SDL_Event &ev) { return false; }
|
||||||
|
|
||||||
|
// Override point to handle an application quit notification
|
||||||
|
virtual void HandleQuit(SDL_QuitEvent &ev) { RequestQuit(); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Graphics::RenderTarget *CreateRenderTarget(const Graphics::Settings &settings);
|
Graphics::RenderTarget *CreateRenderTarget(const Graphics::Settings &settings);
|
||||||
|
|
||||||
|
RefCountedPtr<PiGui::Instance> m_pigui;
|
||||||
|
std::unique_ptr<Input> m_input;
|
||||||
|
|
||||||
std::string m_applicationTitle;
|
std::string m_applicationTitle;
|
||||||
|
|
||||||
std::unique_ptr<Graphics::Renderer> m_renderer;
|
std::unique_ptr<Graphics::Renderer> m_renderer;
|
||||||
|
|
|
@ -109,9 +109,6 @@ namespace Lua {
|
||||||
GameUI::Lua::Init();
|
GameUI::Lua::Init();
|
||||||
SceneGraph::Lua::Init();
|
SceneGraph::Lua::Init();
|
||||||
|
|
||||||
LuaObject<PiGui>::RegisterClass();
|
|
||||||
PiGUI::Lua::Init();
|
|
||||||
|
|
||||||
// XXX load everything. for now, just modules
|
// XXX load everything. for now, just modules
|
||||||
lua_State *l = Lua::manager->GetLuaState();
|
lua_State *l = Lua::manager->GetLuaState();
|
||||||
pi_lua_dofile(l, "libs/autoload.lua");
|
pi_lua_dofile(l, "libs/autoload.lua");
|
||||||
|
|
|
@ -24,11 +24,12 @@
|
||||||
#include "Ship.h"
|
#include "Ship.h"
|
||||||
#include "SpaceStation.h"
|
#include "SpaceStation.h"
|
||||||
#include "Star.h"
|
#include "Star.h"
|
||||||
#include "HyperspaceCloud.h"
|
|
||||||
|
|
||||||
// Defined in LuaPiGui.h
|
namespace PiGUI {
|
||||||
extern bool first_body_is_more_important_than(Body*, Body*);
|
// Defined in LuaPiGui.h
|
||||||
extern int pushOnScreenPositionDirection(lua_State *l, vector3d position);
|
extern bool first_body_is_more_important_than(Body *, Body *);
|
||||||
|
extern int pushOnScreenPositionDirection(lua_State *l, vector3d position);
|
||||||
|
} // namespace PiGUI
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Class: Body
|
* Class: Body
|
||||||
|
@ -246,7 +247,7 @@ static int l_body_is_more_important_than(lua_State *l)
|
||||||
LuaPush<bool>(l, false);
|
LuaPush<bool>(l, false);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
LuaPush<bool>(l, first_body_is_more_important_than(body, other));
|
LuaPush<bool>(l, PiGUI::first_body_is_more_important_than(body, other));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
|
@ -653,7 +654,7 @@ static int l_body_get_projected_screen_position(lua_State *l)
|
||||||
Body *b = LuaObject<Body>::CheckFromLua(1);
|
Body *b = LuaObject<Body>::CheckFromLua(1);
|
||||||
WorldView *wv = Pi::game->GetWorldView();
|
WorldView *wv = Pi::game->GetWorldView();
|
||||||
vector3d p = wv->WorldSpaceToScreenSpace(b);
|
vector3d p = wv->WorldSpaceToScreenSpace(b);
|
||||||
return pushOnScreenPositionDirection(l, p);
|
return PiGUI::pushOnScreenPositionDirection(l, p);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int l_body_get_atmospheric_state(lua_State *l)
|
static int l_body_get_atmospheric_state(lua_State *l)
|
||||||
|
@ -685,7 +686,7 @@ static int l_body_get_target_indicator_screen_position(lua_State *l)
|
||||||
Body *b = LuaObject<Body>::CheckFromLua(1);
|
Body *b = LuaObject<Body>::CheckFromLua(1);
|
||||||
WorldView *wv = Pi::game->GetWorldView();
|
WorldView *wv = Pi::game->GetWorldView();
|
||||||
vector3d p = wv->GetTargetIndicatorScreenPosition(b);
|
vector3d p = wv->GetTargetIndicatorScreenPosition(b);
|
||||||
return pushOnScreenPositionDirection(l, p);
|
return PiGUI::pushOnScreenPositionDirection(l, p);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool push_body_to_lua(Body *body)
|
static bool push_body_to_lua(Body *body)
|
||||||
|
|
|
@ -117,7 +117,7 @@ static int l_engine_attr_ui(lua_State *l)
|
||||||
*/
|
*/
|
||||||
static int l_engine_attr_pigui(lua_State *l)
|
static int l_engine_attr_pigui(lua_State *l)
|
||||||
{
|
{
|
||||||
LuaObject<PiGui>::PushToLua(Pi::pigui.Get());
|
LuaObject<PiGui::Instance>::PushToLua(Pi::pigui);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -794,7 +794,7 @@ static int l_engine_world_space_to_screen_space(lua_State *l)
|
||||||
{
|
{
|
||||||
vector3d pos = LuaPull<vector3d>(l, 1);
|
vector3d pos = LuaPull<vector3d>(l, 1);
|
||||||
|
|
||||||
TScreenSpace res = lua_world_space_to_screen_space(pos); // defined in LuaPiGui.cpp
|
PiGUI::TScreenSpace res = PiGUI::lua_world_space_to_screen_space(pos); // defined in LuaPiGui.cpp
|
||||||
|
|
||||||
LuaPush<bool>(l, res._onScreen);
|
LuaPush<bool>(l, res._onScreen);
|
||||||
LuaPush<vector2d>(l, res._screenPosition);
|
LuaPush<vector2d>(l, res._screenPosition);
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
#include "graphics/Graphics.h"
|
#include "graphics/Graphics.h"
|
||||||
#include "pigui/LuaFlags.h"
|
#include "pigui/LuaFlags.h"
|
||||||
#include "pigui/PiGui.h"
|
#include "pigui/PiGui.h"
|
||||||
|
#include "pigui/PiGuiLua.h"
|
||||||
#include "ship/PlayerShipController.h"
|
#include "ship/PlayerShipController.h"
|
||||||
#include "sound/Sound.h"
|
#include "sound/Sound.h"
|
||||||
#include "ui/Context.h"
|
#include "ui/Context.h"
|
||||||
|
@ -77,7 +78,7 @@ void pi_lua_generic_pull(lua_State *l, int index, ImVec2 &vec)
|
||||||
vec = ImVec2(tr.x, tr.y);
|
vec = ImVec2(tr.x, tr.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
int pushOnScreenPositionDirection(lua_State *l, vector3d position)
|
int PiGUI::pushOnScreenPositionDirection(lua_State *l, vector3d position)
|
||||||
{
|
{
|
||||||
PROFILE_SCOPED()
|
PROFILE_SCOPED()
|
||||||
const int width = Graphics::GetScreenWidth();
|
const int width = Graphics::GetScreenWidth();
|
||||||
|
@ -1381,7 +1382,7 @@ static int l_pigui_is_mouse_clicked(lua_State *l)
|
||||||
static int l_pigui_push_font(lua_State *l)
|
static int l_pigui_push_font(lua_State *l)
|
||||||
{
|
{
|
||||||
PROFILE_SCOPED()
|
PROFILE_SCOPED()
|
||||||
PiGui *pigui = LuaObject<PiGui>::CheckFromLua(1);
|
PiGui::Instance *pigui = LuaObject<PiGui::Instance>::CheckFromLua(1);
|
||||||
std::string fontname = LuaPull<std::string>(l, 2);
|
std::string fontname = LuaPull<std::string>(l, 2);
|
||||||
int size = LuaPull<int>(l, 3);
|
int size = LuaPull<int>(l, 3);
|
||||||
ImFont *font = pigui->GetFont(fontname, size);
|
ImFont *font = pigui->GetFont(fontname, size);
|
||||||
|
@ -1560,7 +1561,7 @@ static int l_pigui_get_mouse_clicked_pos(lua_State *l)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
TScreenSpace lua_world_space_to_screen_space(const vector3d &pos)
|
PiGUI::TScreenSpace PiGUI::lua_world_space_to_screen_space(const vector3d &pos)
|
||||||
{
|
{
|
||||||
PROFILE_SCOPED()
|
PROFILE_SCOPED()
|
||||||
const WorldView *wv = Pi::game->GetWorldView();
|
const WorldView *wv = Pi::game->GetWorldView();
|
||||||
|
@ -1569,13 +1570,13 @@ TScreenSpace lua_world_space_to_screen_space(const vector3d &pos)
|
||||||
const int height = Graphics::GetScreenHeight();
|
const int height = Graphics::GetScreenHeight();
|
||||||
const vector3d direction = (p - vector3d(width / 2, height / 2, 0)).Normalized();
|
const vector3d direction = (p - vector3d(width / 2, height / 2, 0)).Normalized();
|
||||||
if (vector3d(0, 0, 0) == p || p.x < 0 || p.y < 0 || p.x > width || p.y > height || p.z > 0) {
|
if (vector3d(0, 0, 0) == p || p.x < 0 || p.y < 0 || p.x > width || p.y > height || p.z > 0) {
|
||||||
return TScreenSpace(false, vector2d(0, 0), direction * (p.z > 0 ? -1 : 1));
|
return PiGUI::TScreenSpace(false, vector2d(0, 0), direction * (p.z > 0 ? -1 : 1));
|
||||||
} else {
|
} else {
|
||||||
return TScreenSpace(true, vector2d(p.x, p.y), direction);
|
return PiGUI::TScreenSpace(true, vector2d(p.x, p.y), direction);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TScreenSpace lua_world_space_to_screen_space(const Body *body)
|
PiGUI::TScreenSpace lua_world_space_to_screen_space(const Body *body)
|
||||||
{
|
{
|
||||||
PROFILE_SCOPED()
|
PROFILE_SCOPED()
|
||||||
const WorldView *wv = Pi::game->GetWorldView();
|
const WorldView *wv = Pi::game->GetWorldView();
|
||||||
|
@ -1584,13 +1585,13 @@ TScreenSpace lua_world_space_to_screen_space(const Body *body)
|
||||||
const int height = Graphics::GetScreenHeight();
|
const int height = Graphics::GetScreenHeight();
|
||||||
const vector3d direction = (p - vector3d(width / 2, height / 2, 0)).Normalized();
|
const vector3d direction = (p - vector3d(width / 2, height / 2, 0)).Normalized();
|
||||||
if (vector3d(0, 0, 0) == p || p.x < 0 || p.y < 0 || p.x > width || p.y > height || p.z > 0) {
|
if (vector3d(0, 0, 0) == p || p.x < 0 || p.y < 0 || p.x > width || p.y > height || p.z > 0) {
|
||||||
return TScreenSpace(false, vector2d(0, 0), direction * (p.z > 0 ? -1 : 1));
|
return PiGUI::TScreenSpace(false, vector2d(0, 0), direction * (p.z > 0 ? -1 : 1));
|
||||||
} else {
|
} else {
|
||||||
return TScreenSpace(true, vector2d(p.x, p.y), direction);
|
return PiGUI::TScreenSpace(true, vector2d(p.x, p.y), direction);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool first_body_is_more_important_than(Body *body, Body *other)
|
bool PiGUI::first_body_is_more_important_than(Body *body, Body *other)
|
||||||
{
|
{
|
||||||
|
|
||||||
Object::Type a = body->GetType();
|
Object::Type a = body->GetType();
|
||||||
|
@ -1720,7 +1721,7 @@ static int l_pigui_get_projected_bodies_grouped(lua_State *l)
|
||||||
const double cluster_size = LuaPull<double>(l, 1);
|
const double cluster_size = LuaPull<double>(l, 1);
|
||||||
const double ship_max_distance = LuaPull<double>(l, 2);
|
const double ship_max_distance = LuaPull<double>(l, 2);
|
||||||
|
|
||||||
TSS_vector filtered;
|
PiGUI::TSS_vector filtered;
|
||||||
filtered.reserve(Pi::game->GetSpace()->GetNumBodies());
|
filtered.reserve(Pi::game->GetSpace()->GetNumBodies());
|
||||||
|
|
||||||
for (Body *body : Pi::game->GetSpace()->GetBodies()) {
|
for (Body *body : Pi::game->GetSpace()->GetBodies()) {
|
||||||
|
@ -1728,7 +1729,7 @@ static int l_pigui_get_projected_bodies_grouped(lua_State *l)
|
||||||
if (body->GetType() == Object::PROJECTILE) continue;
|
if (body->GetType() == Object::PROJECTILE) continue;
|
||||||
if (body->GetType() == Object::SHIP &&
|
if (body->GetType() == Object::SHIP &&
|
||||||
body->GetPositionRelTo(Pi::player).Length() > ship_max_distance) continue;
|
body->GetPositionRelTo(Pi::player).Length() > ship_max_distance) continue;
|
||||||
const TScreenSpace res = lua_world_space_to_screen_space(body); // defined in LuaPiGui.cpp
|
const PiGUI::TScreenSpace res = lua_world_space_to_screen_space(body); // defined in LuaPiGui.cpp
|
||||||
if (!res._onScreen) continue;
|
if (!res._onScreen) continue;
|
||||||
filtered.emplace_back(res);
|
filtered.emplace_back(res);
|
||||||
filtered.back()._body = body;
|
filtered.back()._body = body;
|
||||||
|
@ -1757,7 +1758,7 @@ static int l_pigui_get_projected_bodies_grouped(lua_State *l)
|
||||||
const Body *combat_target = Pi::game->GetPlayer()->GetCombatTarget();
|
const Body *combat_target = Pi::game->GetPlayer()->GetCombatTarget();
|
||||||
const Body *setspeed_target = Pi::game->GetPlayer()->GetSetSpeedTarget();
|
const Body *setspeed_target = Pi::game->GetPlayer()->GetSetSpeedTarget();
|
||||||
|
|
||||||
for (TScreenSpace &obj : filtered) {
|
for (PiGUI::TScreenSpace &obj : filtered) {
|
||||||
bool inserted = false;
|
bool inserted = false;
|
||||||
|
|
||||||
// never collapse combat target
|
// never collapse combat target
|
||||||
|
@ -1773,7 +1774,7 @@ static int l_pigui_get_projected_bodies_grouped(lua_State *l)
|
||||||
group.m_hasNavTarget = true;
|
group.m_hasNavTarget = true;
|
||||||
group.m_mainBody = obj._body;
|
group.m_mainBody = obj._body;
|
||||||
group.m_screenCoords = obj._screenPosition;
|
group.m_screenCoords = obj._screenPosition;
|
||||||
} else if (!group.m_hasNavTarget && first_body_is_more_important_than(obj._body, group.m_mainBody)) {
|
} else if (!group.m_hasNavTarget && PiGUI::first_body_is_more_important_than(obj._body, group.m_mainBody)) {
|
||||||
group.m_mainBody = obj._body;
|
group.m_mainBody = obj._body;
|
||||||
group.m_screenCoords = obj._screenPosition;
|
group.m_screenCoords = obj._screenPosition;
|
||||||
}
|
}
|
||||||
|
@ -1797,7 +1798,7 @@ static int l_pigui_get_projected_bodies_grouped(lua_State *l)
|
||||||
for (GroupInfo &group : groups) {
|
for (GroupInfo &group : groups) {
|
||||||
std::sort(begin(group.m_bodies), end(group.m_bodies),
|
std::sort(begin(group.m_bodies), end(group.m_bodies),
|
||||||
[](Body *a, Body *b) {
|
[](Body *a, Body *b) {
|
||||||
return first_body_is_more_important_than(a, b);
|
return PiGUI::first_body_is_more_important_than(a, b);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1826,19 +1827,19 @@ static int l_pigui_get_projected_bodies_grouped(lua_State *l)
|
||||||
static int l_pigui_get_projected_bodies(lua_State *l)
|
static int l_pigui_get_projected_bodies(lua_State *l)
|
||||||
{
|
{
|
||||||
PROFILE_SCOPED()
|
PROFILE_SCOPED()
|
||||||
TSS_vector filtered;
|
PiGUI::TSS_vector filtered;
|
||||||
filtered.reserve(Pi::game->GetSpace()->GetNumBodies());
|
filtered.reserve(Pi::game->GetSpace()->GetNumBodies());
|
||||||
for (Body *body : Pi::game->GetSpace()->GetBodies()) {
|
for (Body *body : Pi::game->GetSpace()->GetBodies()) {
|
||||||
if (body == Pi::game->GetPlayer()) continue;
|
if (body == Pi::game->GetPlayer()) continue;
|
||||||
if (body->GetType() == Object::PROJECTILE) continue;
|
if (body->GetType() == Object::PROJECTILE) continue;
|
||||||
const TScreenSpace res = lua_world_space_to_screen_space(body); // defined in LuaPiGui.cpp
|
const PiGUI::TScreenSpace res = lua_world_space_to_screen_space(body); // defined in LuaPiGui.cpp
|
||||||
if (!res._onScreen) continue;
|
if (!res._onScreen) continue;
|
||||||
filtered.emplace_back(res);
|
filtered.emplace_back(res);
|
||||||
filtered.back()._body = body;
|
filtered.back()._body = body;
|
||||||
}
|
}
|
||||||
|
|
||||||
LuaTable result(l, 0, filtered.size());
|
LuaTable result(l, 0, filtered.size());
|
||||||
for (TScreenSpace &res : filtered) {
|
for (PiGUI::TScreenSpace &res : filtered) {
|
||||||
LuaTable object(l, 0, 3);
|
LuaTable object(l, 0, 3);
|
||||||
|
|
||||||
object.Set("onscreen", res._onScreen);
|
object.Set("onscreen", res._onScreen);
|
||||||
|
@ -1941,23 +1942,23 @@ static int l_pigui_should_show_labels(lua_State *l)
|
||||||
static int l_attr_handlers(lua_State *l)
|
static int l_attr_handlers(lua_State *l)
|
||||||
{
|
{
|
||||||
PROFILE_SCOPED()
|
PROFILE_SCOPED()
|
||||||
PiGui *pigui = LuaObject<PiGui>::CheckFromLua(1);
|
PiGui::Instance *pigui = LuaObject<PiGui::Instance>::CheckFromLua(1);
|
||||||
pigui->GetHandlers().PushCopyToStack();
|
PiGUI::GetHandlers().PushCopyToStack();
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int l_attr_keys(lua_State *l)
|
static int l_attr_keys(lua_State *l)
|
||||||
{
|
{
|
||||||
PROFILE_SCOPED()
|
PROFILE_SCOPED()
|
||||||
PiGui *pigui = LuaObject<PiGui>::CheckFromLua(1);
|
PiGui::Instance *pigui = LuaObject<PiGui::Instance>::CheckFromLua(1);
|
||||||
pigui->GetKeys().PushCopyToStack();
|
PiGUI::GetKeys().PushCopyToStack();
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int l_attr_screen_width(lua_State *l)
|
static int l_attr_screen_width(lua_State *l)
|
||||||
{
|
{
|
||||||
PROFILE_SCOPED()
|
PROFILE_SCOPED()
|
||||||
// PiGui *pigui = LuaObject<PiGui>::CheckFromLua(1);
|
// PiGui::Instance *pigui = LuaObject<PiGui::Instance>::CheckFromLua(1);
|
||||||
LuaPush<int>(l, Graphics::GetScreenWidth());
|
LuaPush<int>(l, Graphics::GetScreenWidth());
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -1993,7 +1994,7 @@ static int l_attr_key_alt(lua_State *l)
|
||||||
static int l_attr_screen_height(lua_State *l)
|
static int l_attr_screen_height(lua_State *l)
|
||||||
{
|
{
|
||||||
PROFILE_SCOPED()
|
PROFILE_SCOPED()
|
||||||
// PiGui *pigui = LuaObject<PiGui>::CheckFromLua(1);
|
// PiGui::Instance *pigui = LuaObject<PiGui::Instance>::CheckFromLua(1);
|
||||||
LuaPush<int>(l, Graphics::GetScreenHeight());
|
LuaPush<int>(l, Graphics::GetScreenHeight());
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -2365,11 +2366,11 @@ static int l_pigui_add_convex_poly_filled(lua_State *l)
|
||||||
static int l_pigui_load_texture_from_svg(lua_State *l)
|
static int l_pigui_load_texture_from_svg(lua_State *l)
|
||||||
{
|
{
|
||||||
PROFILE_SCOPED()
|
PROFILE_SCOPED()
|
||||||
PiGui *pigui = LuaObject<PiGui>::CheckFromLua(1);
|
PiGui::Instance *pigui = LuaObject<PiGui::Instance>::CheckFromLua(1);
|
||||||
std::string svg_filename = LuaPull<std::string>(l, 2);
|
std::string svg_filename = LuaPull<std::string>(l, 2);
|
||||||
int width = LuaPull<int>(l, 3);
|
int width = LuaPull<int>(l, 3);
|
||||||
int height = LuaPull<int>(l, 4);
|
int height = LuaPull<int>(l, 4);
|
||||||
ImTextureID id = pigui->RenderSVG(svg_filename, width, height);
|
ImTextureID id = PiGui::RenderSVG(Pi::renderer, svg_filename, width, height);
|
||||||
// LuaPush(l, id);
|
// LuaPush(l, id);
|
||||||
lua_pushlightuserdata(l, id);
|
lua_pushlightuserdata(l, id);
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -2467,11 +2468,21 @@ static int l_pigui_push_text_wrap_pos(lua_State *l)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <>
|
void PiGUI::RunHandler(double delta, std::string handler)
|
||||||
const char *LuaObject<PiGui>::s_type = "PiGui";
|
{
|
||||||
|
PROFILE_SCOPED()
|
||||||
|
ScopedTable t(GetHandlers());
|
||||||
|
if (t.Get<bool>(handler)) {
|
||||||
|
t.Call<bool>(handler, delta);
|
||||||
|
Pi::renderer->CheckRenderErrors(__FUNCTION__, __LINE__);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
void LuaObject<PiGui>::RegisterClass()
|
const char *LuaObject<PiGui::Instance>::s_type = "PiGui";
|
||||||
|
|
||||||
|
template <>
|
||||||
|
void LuaObject<PiGui::Instance>::RegisterClass()
|
||||||
{
|
{
|
||||||
static const luaL_Reg l_methods[] = {
|
static const luaL_Reg l_methods[] = {
|
||||||
{ "Begin", l_pigui_begin },
|
{ "Begin", l_pigui_begin },
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
#ifndef _LUAPIGUI_H
|
#ifndef _LUAPIGUI_H
|
||||||
#define _LUAPIGUI_H
|
#define _LUAPIGUI_H
|
||||||
|
|
||||||
#include "LuaObject.h"
|
#include "LuaObject.h"
|
||||||
#include "LuaPushPull.h"
|
#include "LuaPushPull.h"
|
||||||
|
|
||||||
|
@ -11,19 +12,25 @@
|
||||||
|
|
||||||
class Body;
|
class Body;
|
||||||
|
|
||||||
bool first_body_is_more_important_than(Body* body, Body* other);
|
namespace PiGUI {
|
||||||
|
bool first_body_is_more_important_than(Body *body, Body *other);
|
||||||
|
|
||||||
struct TScreenSpace
|
struct TScreenSpace {
|
||||||
{
|
TScreenSpace(const bool onScreen, const vector2d &screenPos, const vector3d &direction) :
|
||||||
TScreenSpace(const bool onScreen, const vector2d &screenPos, const vector3d &direction) : _onScreen(onScreen), _screenPosition(screenPos), _direction(direction) {}
|
_onScreen(onScreen), _screenPosition(screenPos), _direction(direction) {}
|
||||||
bool _onScreen;
|
bool _onScreen;
|
||||||
vector2d _screenPosition;
|
vector2d _screenPosition;
|
||||||
vector3d _direction;
|
vector3d _direction;
|
||||||
Body *_body;
|
Body *_body;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::vector<TScreenSpace> TSS_vector;
|
typedef std::vector<TScreenSpace> TSS_vector;
|
||||||
|
|
||||||
|
int pushOnScreenPositionDirection(lua_State *l, vector3d position);
|
||||||
|
TScreenSpace lua_world_space_to_screen_space(const vector3d &pos);
|
||||||
|
|
||||||
|
// Run a lua PiGui handler.
|
||||||
|
void RunHandler(double delta, std::string handler = "GAME");
|
||||||
|
} // namespace PiGUI
|
||||||
|
|
||||||
int pushOnScreenPositionDirection(lua_State *l, vector3d position);
|
|
||||||
TScreenSpace lua_world_space_to_screen_space(const vector3d &pos);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -205,7 +205,9 @@ start:
|
||||||
std::string modelName;
|
std::string modelName;
|
||||||
if (argc > 2)
|
if (argc > 2)
|
||||||
modelName = argv[2];
|
modelName = argv[2];
|
||||||
ModelViewer::Run(modelName);
|
auto modelViewer = ModelViewerApp();
|
||||||
|
modelViewer.SetInitialModel(modelName);
|
||||||
|
modelViewer.Run();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,9 @@
|
||||||
#include "Input.h"
|
#include "Input.h"
|
||||||
#include "Pi.h"
|
#include "Pi.h"
|
||||||
|
|
||||||
|
#include "graphics/Graphics.h"
|
||||||
|
#include "graphics/Texture.h"
|
||||||
|
#include "graphics/opengl/RendererGL.h"
|
||||||
#include "graphics/opengl/TextureGL.h" // nasty, usage of GL is implementation specific
|
#include "graphics/opengl/TextureGL.h" // nasty, usage of GL is implementation specific
|
||||||
#include "imgui/imgui.h"
|
#include "imgui/imgui.h"
|
||||||
|
|
||||||
|
@ -12,9 +15,6 @@
|
||||||
#define IMGUI_IMPL_OPENGL_LOADER_GLEW 1
|
#define IMGUI_IMPL_OPENGL_LOADER_GLEW 1
|
||||||
#include "imgui/examples/imgui_impl_opengl3.h"
|
#include "imgui/examples/imgui_impl_opengl3.h"
|
||||||
#include "imgui/examples/imgui_impl_sdl.h"
|
#include "imgui/examples/imgui_impl_sdl.h"
|
||||||
// to get ImVec2 + ImVec2
|
|
||||||
#define IMGUI_DEFINE_MATH_OPERATORS true
|
|
||||||
#include "imgui/imgui_internal.h"
|
|
||||||
|
|
||||||
#include <float.h>
|
#include <float.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
@ -24,38 +24,36 @@
|
||||||
#define NANOSVGRAST_IMPLEMENTATION
|
#define NANOSVGRAST_IMPLEMENTATION
|
||||||
#include "nanosvg/nanosvgrast.h"
|
#include "nanosvg/nanosvgrast.h"
|
||||||
|
|
||||||
std::vector<Graphics::Texture *> PiGui::m_svg_textures;
|
using namespace PiGui;
|
||||||
|
|
||||||
static int to_keycode(int key)
|
std::vector<Graphics::Texture *> m_svg_textures;
|
||||||
|
|
||||||
|
std::vector<Graphics::Texture *> &PiGui::GetSVGTextures()
|
||||||
{
|
{
|
||||||
/*if(key & SDLK_SCANCODE_MASK) {
|
return m_svg_textures;
|
||||||
return (key & ~SDLK_SCANCODE_MASK) | 0x100;
|
|
||||||
}*/
|
|
||||||
return key;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::vector<std::pair<std::string, int>> keycodes = {
|
static ImTextureID makeTexture(Graphics::Renderer *renderer, unsigned char *pixels, int width, int height)
|
||||||
{ "left", to_keycode(SDLK_LEFT) },
|
{
|
||||||
{ "right", to_keycode(SDLK_RIGHT) },
|
PROFILE_SCOPED()
|
||||||
{ "up", to_keycode(SDLK_UP) },
|
// this is not very pretty code
|
||||||
{ "down", to_keycode(SDLK_DOWN) },
|
// Texture descriptor defines the size, type.
|
||||||
{ "escape", to_keycode(SDLK_ESCAPE) },
|
// Gone for LINEAR_CLAMP here and RGBA like the original code
|
||||||
{ "f1", to_keycode(SDLK_F1) },
|
const vector2f texSize(1.0f, 1.0f);
|
||||||
{ "f2", to_keycode(SDLK_F2) },
|
const vector3f dataSize(width, height, 0.0f);
|
||||||
{ "f3", to_keycode(SDLK_F3) },
|
const Graphics::TextureDescriptor texDesc(Graphics::TEXTURE_RGBA_8888,
|
||||||
{ "f4", to_keycode(SDLK_F4) },
|
dataSize, texSize, Graphics::LINEAR_CLAMP,
|
||||||
{ "f5", to_keycode(SDLK_F5) },
|
false, false, false, 0, Graphics::TEXTURE_2D);
|
||||||
{ "f6", to_keycode(SDLK_F6) },
|
// Create the texture, calling it via renderer directly avoids the caching call of TextureBuilder
|
||||||
{ "f7", to_keycode(SDLK_F7) },
|
// However interestingly this gets called twice which would have been a WIN for the TextureBuilder :/
|
||||||
{ "f8", to_keycode(SDLK_F8) },
|
Graphics::Texture *pTex = renderer->CreateTexture(texDesc);
|
||||||
{ "f9", to_keycode(SDLK_F9) },
|
// Update it with the actual pixels, this is a two step process due to legacy code
|
||||||
{ "f10", to_keycode(SDLK_F10) },
|
pTex->Update(pixels, dataSize, Graphics::TEXTURE_RGBA_8888);
|
||||||
{ "f11", to_keycode(SDLK_F11) },
|
PiGui::GetSVGTextures().push_back(pTex); // store for cleanup later
|
||||||
{ "f12", to_keycode(SDLK_F12) },
|
return reinterpret_cast<ImTextureID>(uintptr_t(pTex->GetTextureID()));
|
||||||
{ "tab", to_keycode(SDLK_TAB) },
|
}
|
||||||
};
|
|
||||||
|
|
||||||
ImTextureID PiGui::RenderSVG(std::string svgFilename, int width, int height)
|
ImTextureID PiGui::RenderSVG(Graphics::Renderer *renderer, std::string svgFilename, int width, int height)
|
||||||
{
|
{
|
||||||
PROFILE_SCOPED()
|
PROFILE_SCOPED()
|
||||||
Output("nanosvg: %s %dx%d\n", svgFilename.c_str(), width, height);
|
Output("nanosvg: %s %dx%d\n", svgFilename.c_str(), width, height);
|
||||||
|
@ -111,10 +109,44 @@ ImTextureID PiGui::RenderSVG(std::string svgFilename, int width, int height)
|
||||||
}
|
}
|
||||||
nsvgDeleteRasterizer(rast);
|
nsvgDeleteRasterizer(rast);
|
||||||
nsvgDelete(image);
|
nsvgDelete(image);
|
||||||
return makeTexture(img, W, H);
|
return makeTexture(renderer, img, W, H);
|
||||||
}
|
}
|
||||||
|
|
||||||
ImFont *PiGui::GetFont(const std::string &name, int size)
|
//
|
||||||
|
// PiGui::Instance
|
||||||
|
//
|
||||||
|
|
||||||
|
Instance::Instance() :
|
||||||
|
m_should_bake_fonts(true)
|
||||||
|
{
|
||||||
|
// TODO: clang-format doesn't like list initializers inside function calls
|
||||||
|
// clang-format off
|
||||||
|
PiFont uiheading("orbiteer", {
|
||||||
|
PiFace("DejaVuSans.ttf", /*18.0/20.0*/ 1.2),
|
||||||
|
PiFace("wqy-microhei.ttc", 1.0),
|
||||||
|
PiFace("Orbiteer-Bold.ttf", 1.0) // imgui only supports 0xffff, not 0x10ffff
|
||||||
|
});
|
||||||
|
AddFontDefinition(uiheading);
|
||||||
|
|
||||||
|
PiFont guifont("pionillium", {
|
||||||
|
PiFace("DejaVuSans.ttf", 13.0 / 14.0),
|
||||||
|
PiFace("wqy-microhei.ttc", 1.0),
|
||||||
|
PiFace("PionilliumText22L-Medium.ttf", 1.0)
|
||||||
|
});
|
||||||
|
AddFontDefinition(guifont);
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
// Output("Fonts:\n");
|
||||||
|
for (auto entry : m_font_definitions) {
|
||||||
|
// Output(" entry %s:\n", entry.first.c_str());
|
||||||
|
entry.second.describe();
|
||||||
|
}
|
||||||
|
|
||||||
|
// ensure the tooltip font exists
|
||||||
|
GetFont("pionillium", 14);
|
||||||
|
};
|
||||||
|
|
||||||
|
ImFont *Instance::GetFont(const std::string &name, int size)
|
||||||
{
|
{
|
||||||
PROFILE_SCOPED()
|
PROFILE_SCOPED()
|
||||||
auto iter = m_fonts.find(std::make_pair(name, size));
|
auto iter = m_fonts.find(std::make_pair(name, size));
|
||||||
|
@ -126,7 +158,7 @@ ImFont *PiGui::GetFont(const std::string &name, int size)
|
||||||
return font;
|
return font;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PiGui::AddGlyph(ImFont *font, unsigned short glyph)
|
void Instance::AddGlyph(ImFont *font, unsigned short glyph)
|
||||||
{
|
{
|
||||||
PROFILE_SCOPED()
|
PROFILE_SCOPED()
|
||||||
// range glyph..glyph
|
// range glyph..glyph
|
||||||
|
@ -151,7 +183,7 @@ void PiGui::AddGlyph(ImFont *font, unsigned short glyph)
|
||||||
Error("No face in font %s handles glyph %i\n", pifont.name().c_str(), glyph);
|
Error("No face in font %s handles glyph %i\n", pifont.name().c_str(), glyph);
|
||||||
}
|
}
|
||||||
|
|
||||||
ImFont *PiGui::AddFont(const std::string &name, int size)
|
ImFont *Instance::AddFont(const std::string &name, int size)
|
||||||
{
|
{
|
||||||
PROFILE_SCOPED()
|
PROFILE_SCOPED()
|
||||||
auto iter = m_font_definitions.find(name);
|
auto iter = m_font_definitions.find(name);
|
||||||
|
@ -175,7 +207,7 @@ ImFont *PiGui::AddFont(const std::string &name, int size)
|
||||||
return m_fonts[std::make_pair(name, size)];
|
return m_fonts[std::make_pair(name, size)];
|
||||||
}
|
}
|
||||||
|
|
||||||
void PiGui::RefreshFontsTexture()
|
void Instance::RefreshFontsTexture()
|
||||||
{
|
{
|
||||||
PROFILE_SCOPED()
|
PROFILE_SCOPED()
|
||||||
// TODO: fix this, do the right thing, don't just re-create *everything* :)
|
// TODO: fix this, do the right thing, don't just re-create *everything* :)
|
||||||
|
@ -189,21 +221,11 @@ void PiDefaultStyle(ImGuiStyle &style)
|
||||||
style.WindowBorderSize = 0.0f; // Thickness of border around windows. Generally set to 0.0f or 1.0f. Other values not well tested.
|
style.WindowBorderSize = 0.0f; // Thickness of border around windows. Generally set to 0.0f or 1.0f. Other values not well tested.
|
||||||
}
|
}
|
||||||
|
|
||||||
void PiGui::Init(SDL_Window *window)
|
// TODO: this isn't very RAII friendly, are we sure we need to call Init() seperately from creating the instance?
|
||||||
|
void Instance::Init(Graphics::Renderer *renderer)
|
||||||
{
|
{
|
||||||
PROFILE_SCOPED()
|
PROFILE_SCOPED()
|
||||||
m_handlers.Unref();
|
m_renderer = renderer;
|
||||||
|
|
||||||
lua_State *l = Lua::manager->GetLuaState();
|
|
||||||
lua_newtable(l);
|
|
||||||
m_handlers = LuaRef(l, -1);
|
|
||||||
|
|
||||||
lua_newtable(l);
|
|
||||||
m_keys = LuaRef(l, -1);
|
|
||||||
LuaTable keys(l, -1);
|
|
||||||
for (auto p : keycodes) {
|
|
||||||
keys.Set(p.first, p.second);
|
|
||||||
}
|
|
||||||
|
|
||||||
IMGUI_CHECKVERSION();
|
IMGUI_CHECKVERSION();
|
||||||
ImGui::CreateContext();
|
ImGui::CreateContext();
|
||||||
|
@ -211,8 +233,8 @@ void PiGui::Init(SDL_Window *window)
|
||||||
// TODO: FIXME before upgrading! The sdl_gl_context parameter is currently
|
// TODO: FIXME before upgrading! The sdl_gl_context parameter is currently
|
||||||
// unused, but that is slated to change very soon.
|
// unused, but that is slated to change very soon.
|
||||||
// We will need to fill this with a valid pointer to the OpenGL context.
|
// We will need to fill this with a valid pointer to the OpenGL context.
|
||||||
ImGui_ImplSDL2_InitForOpenGL(window, NULL);
|
ImGui_ImplSDL2_InitForOpenGL(m_renderer->GetSDLWindow(), NULL);
|
||||||
switch (Pi::renderer->GetRendererType()) {
|
switch (m_renderer->GetRendererType()) {
|
||||||
default:
|
default:
|
||||||
case Graphics::RENDERER_DUMMY:
|
case Graphics::RENDERER_DUMMY:
|
||||||
Error("RENDERER_DUMMY is not a valid renderer, aborting.");
|
Error("RENDERER_DUMMY is not a valid renderer, aborting.");
|
||||||
|
@ -241,156 +263,18 @@ void PiGui::Init(SDL_Window *window)
|
||||||
io.IniFilename = ioIniFilename;
|
io.IniFilename = ioIniFilename;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PiGui::RadialPopupSelectMenu(const ImVec2 ¢er, std::string popup_id, int mouse_button, std::vector<ImTextureID> tex_ids, std::vector<std::pair<ImVec2, ImVec2>> uvs, unsigned int size, std::vector<std::string> tooltips)
|
bool Instance::ProcessEvent(SDL_Event *event)
|
||||||
{
|
|
||||||
PROFILE_SCOPED()
|
|
||||||
// return:
|
|
||||||
// 0 - n for item selected
|
|
||||||
// -1 for nothing chosen, but menu open
|
|
||||||
// -2 for menu closed without an icon chosen
|
|
||||||
// -3 for menu not open
|
|
||||||
int ret = -3;
|
|
||||||
|
|
||||||
// FIXME: Missing a call to query if Popup is open so we can move the PushStyleColor inside the BeginPopupBlock (e.g. IsPopupOpen() in imgui.cpp)
|
|
||||||
// FIXME: Our PathFill function only handle convex polygons, so we can't have items spanning an arc too large else inner concave edge artifact is too visible, hence the ImMax(7,items_count)
|
|
||||||
ImGui::PushStyleColor(ImGuiCol_WindowBg, ImVec4(0, 0, 0, 0));
|
|
||||||
ImGui::PushStyleColor(ImGuiCol_PopupBg, ImVec4(0, 0, 0, 0));
|
|
||||||
ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(0, 0, 0, 0));
|
|
||||||
if (ImGui::BeginPopup(popup_id.c_str())) {
|
|
||||||
ret = -1;
|
|
||||||
const ImVec2 drag_delta = ImVec2(ImGui::GetIO().MousePos.x - center.x, ImGui::GetIO().MousePos.y - center.y);
|
|
||||||
const float drag_dist2 = drag_delta.x * drag_delta.x + drag_delta.y * drag_delta.y;
|
|
||||||
|
|
||||||
const ImGuiStyle &style = ImGui::GetStyle();
|
|
||||||
const float RADIUS_MIN = 20.0f;
|
|
||||||
const float RADIUS_MAX = 90.0f;
|
|
||||||
const float RADIUS_INTERACT_MIN = 20.0f;
|
|
||||||
const int ITEMS_MIN = 4;
|
|
||||||
const float border_inout = 12.0f;
|
|
||||||
const float border_thickness = 4.0f;
|
|
||||||
ImDrawList *draw_list = ImGui::GetWindowDrawList();
|
|
||||||
draw_list->PushClipRectFullScreen();
|
|
||||||
draw_list->PathArcTo(center, (RADIUS_MIN + RADIUS_MAX) * 0.5f, 0.0f, IM_PI * 2.0f * 0.99f, 64); // FIXME: 0.99f look like full arc with closed thick stroke has a bug now
|
|
||||||
draw_list->PathStroke(ImColor(18, 44, 67, 210), true, RADIUS_MAX - RADIUS_MIN);
|
|
||||||
|
|
||||||
const float item_arc_span = 2 * IM_PI / ImMax<int>(ITEMS_MIN, tex_ids.size());
|
|
||||||
float drag_angle = atan2f(drag_delta.y, drag_delta.x);
|
|
||||||
if (drag_angle < -0.5f * item_arc_span)
|
|
||||||
drag_angle += 2.0f * IM_PI;
|
|
||||||
|
|
||||||
int item_hovered = -1;
|
|
||||||
int item_n = 0;
|
|
||||||
for (ImTextureID tex_id : tex_ids) {
|
|
||||||
const char *tooltip = tooltips.at(item_n).c_str();
|
|
||||||
const float inner_spacing = style.ItemInnerSpacing.x / RADIUS_MIN / 2;
|
|
||||||
const float item_inner_ang_min = item_arc_span * (item_n - 0.5f + inner_spacing);
|
|
||||||
const float item_inner_ang_max = item_arc_span * (item_n + 0.5f - inner_spacing);
|
|
||||||
const float item_outer_ang_min = item_arc_span * (item_n - 0.5f + inner_spacing * (RADIUS_MIN / RADIUS_MAX));
|
|
||||||
const float item_outer_ang_max = item_arc_span * (item_n + 0.5f - inner_spacing * (RADIUS_MIN / RADIUS_MAX));
|
|
||||||
|
|
||||||
bool hovered = false;
|
|
||||||
if (drag_dist2 >= RADIUS_INTERACT_MIN * RADIUS_INTERACT_MIN) {
|
|
||||||
if (drag_angle >= item_inner_ang_min && drag_angle < item_inner_ang_max)
|
|
||||||
hovered = true;
|
|
||||||
}
|
|
||||||
bool selected = false;
|
|
||||||
|
|
||||||
int arc_segments = static_cast<int>((64 * item_arc_span / (2 * IM_PI))) + 1;
|
|
||||||
draw_list->PathArcTo(center, RADIUS_MAX - border_inout, item_outer_ang_min, item_outer_ang_max, arc_segments);
|
|
||||||
draw_list->PathArcTo(center, RADIUS_MIN + border_inout, item_inner_ang_max, item_inner_ang_min, arc_segments);
|
|
||||||
|
|
||||||
draw_list->PathFillConvex(hovered ? ImColor(102, 147, 189) : selected ? ImColor(48, 81, 111) : ImColor(48, 81, 111));
|
|
||||||
if (hovered) {
|
|
||||||
// draw outer / inner extra segments
|
|
||||||
draw_list->PathArcTo(center, RADIUS_MAX - border_thickness, item_outer_ang_min, item_outer_ang_max, arc_segments);
|
|
||||||
draw_list->PathStroke(ImColor(102, 147, 189), false, border_thickness);
|
|
||||||
draw_list->PathArcTo(center, RADIUS_MIN + border_thickness, item_outer_ang_min, item_outer_ang_max, arc_segments);
|
|
||||||
draw_list->PathStroke(ImColor(102, 147, 189), false, border_thickness);
|
|
||||||
}
|
|
||||||
ImVec2 text_size = ImVec2(size, size);
|
|
||||||
ImVec2 text_pos = ImVec2(
|
|
||||||
center.x + cosf((item_inner_ang_min + item_inner_ang_max) * 0.5f) * (RADIUS_MIN + RADIUS_MAX) * 0.5f - text_size.x * 0.5f,
|
|
||||||
center.y + sinf((item_inner_ang_min + item_inner_ang_max) * 0.5f) * (RADIUS_MIN + RADIUS_MAX) * 0.5f - text_size.y * 0.5f);
|
|
||||||
draw_list->AddImage(tex_id, text_pos, ImVec2(text_pos.x + size, text_pos.y + size), uvs[item_n].first, uvs[item_n].second);
|
|
||||||
ImGui::SameLine();
|
|
||||||
if (hovered) {
|
|
||||||
item_hovered = item_n;
|
|
||||||
ImGui::SetTooltip("%s", tooltip);
|
|
||||||
}
|
|
||||||
item_n++;
|
|
||||||
}
|
|
||||||
draw_list->PopClipRect();
|
|
||||||
|
|
||||||
if (ImGui::IsMouseReleased(mouse_button)) {
|
|
||||||
ImGui::CloseCurrentPopup();
|
|
||||||
if (item_hovered == -1)
|
|
||||||
ret = -2;
|
|
||||||
else
|
|
||||||
ret = item_hovered;
|
|
||||||
}
|
|
||||||
ImGui::EndPopup();
|
|
||||||
} else {
|
|
||||||
// Output("WARNING: RadialPopupSelectMenu BeginPopup failed: %s\n", popup_id.c_str());
|
|
||||||
}
|
|
||||||
ImGui::PopStyleColor(3);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool PiGui::CircularSlider(const ImVec2 ¢er, float *v, float v_min, float v_max)
|
|
||||||
{
|
|
||||||
PROFILE_SCOPED()
|
|
||||||
ImDrawList *draw_list = ImGui::GetWindowDrawList();
|
|
||||||
ImGuiWindow *window = ImGui::GetCurrentWindow();
|
|
||||||
const ImGuiID id = window->GetID("circularslider");
|
|
||||||
draw_list->AddCircle(center, 17, ImColor(100, 100, 100), 128, 12.0);
|
|
||||||
draw_list->PathArcTo(center, 17, 0, M_PI * 2.0 * (*v - v_min) / (v_max - v_min), 64);
|
|
||||||
draw_list->PathStroke(ImColor(200, 200, 200), false, 12.0);
|
|
||||||
ImRect grab_bb;
|
|
||||||
return ImGui::SliderBehavior(ImRect(center.x - 17, center.y - 17, center.x + 17, center.y + 17),
|
|
||||||
id, ImGuiDataType_Float, v, &v_min, &v_max, "%.4f", 1.0, ImGuiSliderFlags_None, &grab_bb);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool PiGui::ProcessEvent(SDL_Event *event)
|
|
||||||
{
|
{
|
||||||
PROFILE_SCOPED()
|
PROFILE_SCOPED()
|
||||||
ImGui_ImplSDL2_ProcessEvent(event);
|
ImGui_ImplSDL2_ProcessEvent(event);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void *PiGui::makeTexture(unsigned char *pixels, int width, int height)
|
void Instance::NewFrame()
|
||||||
{
|
|
||||||
PROFILE_SCOPED()
|
|
||||||
// this is not very pretty code and uses the Graphics::TextureGL class directly
|
|
||||||
// Texture descriptor defines the size, type.
|
|
||||||
// Gone for LINEAR_CLAMP here and RGBA like the original code
|
|
||||||
const vector2f texSize(1.0f, 1.0f);
|
|
||||||
const vector3f dataSize(width, height, 0.0f);
|
|
||||||
const Graphics::TextureDescriptor texDesc(Graphics::TEXTURE_RGBA_8888,
|
|
||||||
dataSize, texSize, Graphics::LINEAR_CLAMP,
|
|
||||||
false, false, false, 0, Graphics::TEXTURE_2D);
|
|
||||||
// Create the texture, calling it via renderer directly avoids the caching call of TextureBuilder
|
|
||||||
// However interestingly this gets called twice which would have been a WIN for the TextureBuilder :/
|
|
||||||
Graphics::Texture *pTex = Pi::renderer->CreateTexture(texDesc);
|
|
||||||
// Update it with the actual pixels, this is a two step process due to legacy code
|
|
||||||
pTex->Update(pixels, dataSize, Graphics::TEXTURE_RGBA_8888);
|
|
||||||
// nasty bit as I invoke the TextureGL
|
|
||||||
Graphics::OGL::TextureGL *pGLTex = reinterpret_cast<Graphics::OGL::TextureGL *>(pTex);
|
|
||||||
Uint32 result = pGLTex->GetTextureID();
|
|
||||||
m_svg_textures.push_back(pTex); // store for cleanup later
|
|
||||||
return reinterpret_cast<void *>(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
void PiGui::NewFrame(SDL_Window *window)
|
|
||||||
{
|
{
|
||||||
PROFILE_SCOPED()
|
PROFILE_SCOPED()
|
||||||
|
|
||||||
// Ask ImGui to hide OS cursor if we're capturing it for input:
|
switch (m_renderer->GetRendererType()) {
|
||||||
// it will do this if GetMouseCursor == ImGuiMouseCursor_None.
|
|
||||||
if (Pi::input->IsCapturingMouse()) {
|
|
||||||
ImGui::SetMouseCursor(ImGuiMouseCursor_None);
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (Pi::renderer->GetRendererType()) {
|
|
||||||
default:
|
default:
|
||||||
case Graphics::RENDERER_DUMMY:
|
case Graphics::RENDERER_DUMMY:
|
||||||
Error("RENDERER_DUMMY is not a valid renderer, aborting.");
|
Error("RENDERER_DUMMY is not a valid renderer, aborting.");
|
||||||
|
@ -399,24 +283,14 @@ void PiGui::NewFrame(SDL_Window *window)
|
||||||
ImGui_ImplOpenGL3_NewFrame();
|
ImGui_ImplOpenGL3_NewFrame();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
ImGui_ImplSDL2_NewFrame(window);
|
ImGui_ImplSDL2_NewFrame(m_renderer->GetSDLWindow());
|
||||||
ImGui::NewFrame();
|
ImGui::NewFrame();
|
||||||
|
|
||||||
Pi::renderer->CheckRenderErrors(__FUNCTION__, __LINE__);
|
m_renderer->CheckRenderErrors(__FUNCTION__, __LINE__);
|
||||||
ImGui::SetMouseCursor(ImGuiMouseCursor_Arrow);
|
ImGui::SetMouseCursor(ImGuiMouseCursor_Arrow);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PiGui::RunHandler(double delta, std::string handler)
|
void Instance::EndFrame()
|
||||||
{
|
|
||||||
PROFILE_SCOPED()
|
|
||||||
ScopedTable t(m_handlers);
|
|
||||||
if (t.Get<bool>(handler)) {
|
|
||||||
t.Call<bool>(handler, delta);
|
|
||||||
Pi::renderer->CheckRenderErrors(__FUNCTION__, __LINE__);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void PiGui::EndFrame()
|
|
||||||
{
|
{
|
||||||
PROFILE_SCOPED()
|
PROFILE_SCOPED()
|
||||||
|
|
||||||
|
@ -443,14 +317,14 @@ void PiGui::EndFrame()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PiGui::Render()
|
void Instance::Render()
|
||||||
{
|
{
|
||||||
PROFILE_SCOPED()
|
PROFILE_SCOPED()
|
||||||
EndFrame();
|
EndFrame();
|
||||||
|
|
||||||
ImGui::Render();
|
ImGui::Render();
|
||||||
|
|
||||||
switch (Pi::renderer->GetRendererType()) {
|
switch (m_renderer->GetRendererType()) {
|
||||||
default:
|
default:
|
||||||
case Graphics::RENDERER_DUMMY:
|
case Graphics::RENDERER_DUMMY:
|
||||||
return;
|
return;
|
||||||
|
@ -460,7 +334,7 @@ void PiGui::Render()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PiGui::ClearFonts()
|
void Instance::ClearFonts()
|
||||||
{
|
{
|
||||||
PROFILE_SCOPED()
|
PROFILE_SCOPED()
|
||||||
ImGuiIO &io = ImGui::GetIO();
|
ImGuiIO &io = ImGui::GetIO();
|
||||||
|
@ -470,7 +344,7 @@ void PiGui::ClearFonts()
|
||||||
io.Fonts->Clear();
|
io.Fonts->Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void PiGui::BakeFont(PiFont &font)
|
void Instance::BakeFont(PiFont &font)
|
||||||
{
|
{
|
||||||
PROFILE_SCOPED()
|
PROFILE_SCOPED()
|
||||||
ImGuiIO &io = ImGui::GetIO();
|
ImGuiIO &io = ImGui::GetIO();
|
||||||
|
@ -511,7 +385,7 @@ void PiGui::BakeFont(PiFont &font)
|
||||||
imfont->MissingGlyphs.clear();
|
imfont->MissingGlyphs.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void PiGui::BakeFonts()
|
void Instance::BakeFonts()
|
||||||
{
|
{
|
||||||
PROFILE_SCOPED()
|
PROFILE_SCOPED()
|
||||||
// Output("Baking fonts\n");
|
// Output("Baking fonts\n");
|
||||||
|
@ -538,199 +412,14 @@ void PiGui::BakeFonts()
|
||||||
RefreshFontsTexture();
|
RefreshFontsTexture();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void drawThrust(ImDrawList *draw_list, const ImVec2 ¢er, const ImVec2 &up, float value, const ImColor &fg, const ImColor &bg)
|
void Instance::Uninit()
|
||||||
{
|
|
||||||
PROFILE_SCOPED()
|
|
||||||
float factor = 0.1; // how much to offset from center
|
|
||||||
const ImVec2 step(up.x * 0.5, up.y * 0.5);
|
|
||||||
const ImVec2 left(-step.y * (1.0 - factor), step.x * (1.0 - factor));
|
|
||||||
const ImVec2 u(up.x * (1.0 - factor), up.y * (1.0 - factor));
|
|
||||||
const ImVec2 c(center + ImVec2(u.x * factor, u.y * factor));
|
|
||||||
const ImVec2 right(-left.x, -left.y);
|
|
||||||
const ImVec2 leftmiddle = c + step + left;
|
|
||||||
const ImVec2 rightmiddle = c + step + right;
|
|
||||||
const ImVec2 bb_lowerright = c + right;
|
|
||||||
const ImVec2 bb_upperleft = c + left + ImVec2(u.x * value, u.y * value);
|
|
||||||
const ImVec2 lefttop = c + u + left;
|
|
||||||
const ImVec2 righttop = c + u + right;
|
|
||||||
const ImVec2 minimum(fmin(bb_upperleft.x, bb_lowerright.x), fmin(bb_upperleft.y, bb_lowerright.y));
|
|
||||||
const ImVec2 maximum(fmax(bb_upperleft.x, bb_lowerright.x), fmax(bb_upperleft.y, bb_lowerright.y));
|
|
||||||
ImVec2 points[] = { c, leftmiddle, lefttop, righttop, rightmiddle };
|
|
||||||
draw_list->AddConvexPolyFilled(points, 5, bg);
|
|
||||||
draw_list->PushClipRect(minimum - ImVec2(1, 1), maximum + ImVec2(1, 1));
|
|
||||||
draw_list->AddConvexPolyFilled(points, 5, fg);
|
|
||||||
draw_list->PopClipRect();
|
|
||||||
}
|
|
||||||
|
|
||||||
void PiGui::ThrustIndicator(const std::string &id_string, const ImVec2 &size_arg, const ImVec4 &thrust, const ImVec4 &velocity, const ImVec4 &bg_col, int frame_padding, ImColor vel_fg, ImColor vel_bg, ImColor thrust_fg, ImColor thrust_bg)
|
|
||||||
{
|
|
||||||
PROFILE_SCOPED()
|
|
||||||
ImGuiWindow *window = ImGui::GetCurrentWindow();
|
|
||||||
if (window->SkipItems)
|
|
||||||
return;
|
|
||||||
|
|
||||||
ImGuiContext &g = *GImGui;
|
|
||||||
const ImGuiStyle &style = g.Style;
|
|
||||||
const ImGuiID id = window->GetID(id_string.c_str());
|
|
||||||
|
|
||||||
ImVec2 pos = window->DC.CursorPos;
|
|
||||||
// if ((flags & ImGuiButtonFlags_AlignTextBaseLine) && style.FramePadding.y < window->DC.CurrentLineTextBaseOffset) // Try to vertically align buttons that are smaller/have no padding so that text baseline matches (bit hacky, since it shouldn't be a flag)
|
|
||||||
// pos.y += window->DC.CurrentLineTextBaseOffset - style.FramePadding.y;
|
|
||||||
ImVec2 size = ImGui::CalcItemSize(size_arg, style.FramePadding.x * 2.0f, style.FramePadding.y * 2.0f);
|
|
||||||
|
|
||||||
const ImVec2 padding = (frame_padding >= 0) ? ImVec2(static_cast<float>(frame_padding), static_cast<float>(frame_padding)) : style.FramePadding;
|
|
||||||
const ImRect bb(pos, pos + size + padding * 2);
|
|
||||||
const ImRect inner_bb(pos + padding, pos + padding + size);
|
|
||||||
|
|
||||||
ImGui::ItemSize(bb, style.FramePadding.y);
|
|
||||||
if (!ImGui::ItemAdd(bb, id))
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Render
|
|
||||||
const ImU32 col = ImGui::GetColorU32(static_cast<ImGuiCol>(ImGuiCol_Button));
|
|
||||||
ImGui::RenderFrame(bb.Min, bb.Max, col, true, style.FrameRounding);
|
|
||||||
ImDrawList *draw_list = ImGui::GetWindowDrawList();
|
|
||||||
if (bg_col.w > 0.0f)
|
|
||||||
draw_list->AddRectFilled(inner_bb.Min, inner_bb.Max, ImGui::GetColorU32(bg_col));
|
|
||||||
const ImVec2 leftupper = inner_bb.Min;
|
|
||||||
const ImVec2 rightlower = inner_bb.Max;
|
|
||||||
const ImVec2 rightcenter((rightlower.x - leftupper.x) * 0.8 + leftupper.x, (rightlower.y + leftupper.y) / 2);
|
|
||||||
const ImVec2 leftcenter((rightlower.x - leftupper.x) * 0.35 + leftupper.x, (rightlower.y + leftupper.y) / 2);
|
|
||||||
const ImVec2 up(0, -std::abs(leftupper.y - rightlower.y) * 0.4);
|
|
||||||
const ImVec2 left(-up.y, up.x);
|
|
||||||
float thrust_fwd = fmax(thrust.z, 0);
|
|
||||||
float thrust_bwd = fmax(-thrust.z, 0);
|
|
||||||
float thrust_left = fmax(-thrust.x, 0);
|
|
||||||
float thrust_right = fmax(thrust.x, 0);
|
|
||||||
float thrust_up = fmax(-thrust.y, 0);
|
|
||||||
float thrust_down = fmax(thrust.y, 0);
|
|
||||||
// actual thrust
|
|
||||||
drawThrust(draw_list, rightcenter, up, thrust_fwd, thrust_fg, thrust_bg);
|
|
||||||
drawThrust(draw_list, rightcenter, ImVec2(-up.x, -up.y), thrust_bwd, thrust_fg, thrust_bg);
|
|
||||||
drawThrust(draw_list, leftcenter, up, thrust_up, thrust_fg, thrust_bg);
|
|
||||||
drawThrust(draw_list, leftcenter, ImVec2(-up.x, -up.y), thrust_down, thrust_fg, thrust_bg);
|
|
||||||
drawThrust(draw_list, leftcenter, left, thrust_left, thrust_fg, thrust_bg);
|
|
||||||
drawThrust(draw_list, leftcenter, ImVec2(-left.x, -left.y), thrust_right, thrust_fg, thrust_bg);
|
|
||||||
// forward/back velocity
|
|
||||||
draw_list->AddLine(rightcenter + up, rightcenter - up, vel_bg, 3);
|
|
||||||
draw_list->AddLine(rightcenter, rightcenter - up * velocity.z, vel_fg, 3);
|
|
||||||
// left/right velocity
|
|
||||||
draw_list->AddLine(leftcenter + left, leftcenter - left, vel_bg, 3);
|
|
||||||
draw_list->AddLine(leftcenter, leftcenter + left * velocity.x, vel_fg, 3);
|
|
||||||
// up/down velocity
|
|
||||||
draw_list->AddLine(leftcenter + up, leftcenter - up, vel_bg, 3);
|
|
||||||
draw_list->AddLine(leftcenter, leftcenter + up * velocity.y, vel_fg, 3);
|
|
||||||
// Automatically close popups
|
|
||||||
//if (pressed && !(flags & ImGuiButtonFlags_DontClosePopups) && (window->Flags & ImGuiWindowFlags_Popup))
|
|
||||||
// CloseCurrentPopup();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool PiGui::LowThrustButton(const char *id_string, const ImVec2 &size_arg, int thrust_level, const ImVec4 &bg_col, int frame_padding, ImColor gauge_fg, ImColor gauge_bg)
|
|
||||||
{
|
|
||||||
PROFILE_SCOPED()
|
|
||||||
std::string label = std::to_string(thrust_level);
|
|
||||||
ImGuiWindow *window = ImGui::GetCurrentWindow();
|
|
||||||
if (window->SkipItems)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
ImGuiContext &g = *GImGui;
|
|
||||||
const ImGuiStyle &style = g.Style;
|
|
||||||
const ImGuiID id = window->GetID(id_string);
|
|
||||||
const ImVec2 label_size = ImGui::CalcTextSize(label.c_str(), NULL, true);
|
|
||||||
|
|
||||||
ImVec2 pos = window->DC.CursorPos;
|
|
||||||
// if ((flags & ImGuiButtonFlags_AlignTextBaseLine) && style.FramePadding.y < window->DC.CurrentLineTextBaseOffset) // Try to vertically align buttons that are smaller/have no padding so that text baseline matches (bit hacky, since it shouldn't be a flag)
|
|
||||||
// pos.y += window->DC.CurrentLineTextBaseOffset - style.FramePadding.y;
|
|
||||||
ImVec2 size = ImGui::CalcItemSize(size_arg, label_size.x + style.FramePadding.x * 2.0f, label_size.y + style.FramePadding.y * 2.0f);
|
|
||||||
|
|
||||||
const ImVec2 padding = (frame_padding >= 0) ? ImVec2(static_cast<float>(frame_padding), static_cast<float>(frame_padding)) : style.FramePadding;
|
|
||||||
const ImRect bb(pos, pos + size + padding * 2);
|
|
||||||
const ImRect inner_bb(pos + padding, pos + padding + size);
|
|
||||||
|
|
||||||
ImGui::ItemSize(bb, style.FramePadding.y);
|
|
||||||
if (!ImGui::ItemAdd(bb, id))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// if (window->DC.ButtonRepeat) flags |= ImGuiButtonFlags_Repeat;
|
|
||||||
bool hovered, held;
|
|
||||||
bool pressed = ImGui::ButtonBehavior(bb, id, &hovered, &held, 0); // flags
|
|
||||||
|
|
||||||
// Render
|
|
||||||
const ImU32 col = ImGui::GetColorU32(static_cast<ImGuiCol>((hovered && held) ? ImGuiCol_ButtonActive : (hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button)));
|
|
||||||
ImGui::RenderFrame(bb.Min, bb.Max, col, true, style.FrameRounding);
|
|
||||||
const ImVec2 center = (inner_bb.Min + inner_bb.Max) / 2;
|
|
||||||
float radius = (inner_bb.Max.x - inner_bb.Min.x) * 0.4;
|
|
||||||
float thickness = 4;
|
|
||||||
ImDrawList *draw_list = ImGui::GetWindowDrawList();
|
|
||||||
if (bg_col.w > 0.0f)
|
|
||||||
draw_list->AddRectFilled(inner_bb.Min, inner_bb.Max, ImGui::GetColorU32(bg_col));
|
|
||||||
|
|
||||||
draw_list->PathArcTo(center, radius, 0, IM_PI * 2, 16);
|
|
||||||
draw_list->PathStroke(gauge_bg, false, thickness);
|
|
||||||
|
|
||||||
draw_list->PathArcTo(center, radius, IM_PI, IM_PI + IM_PI * 2 * (thrust_level / 100.0), 16);
|
|
||||||
draw_list->PathStroke(gauge_fg, false, thickness);
|
|
||||||
ImGui::RenderTextClipped(bb.Min + style.FramePadding, bb.Max - style.FramePadding, label.c_str(), NULL, &label_size, style.ButtonTextAlign, &bb);
|
|
||||||
|
|
||||||
// Automatically close popups
|
|
||||||
//if (pressed && !(flags & ImGuiButtonFlags_DontClosePopups) && (window->Flags & ImGuiWindowFlags_Popup))
|
|
||||||
// CloseCurrentPopup();
|
|
||||||
|
|
||||||
return pressed;
|
|
||||||
}
|
|
||||||
|
|
||||||
// frame_padding < 0: uses FramePadding from style (default)
|
|
||||||
// frame_padding = 0: no framing
|
|
||||||
// frame_padding > 0: set framing size
|
|
||||||
// The color used are the button colors.
|
|
||||||
bool PiGui::ButtonImageSized(ImTextureID user_texture_id, const ImVec2 &size, const ImVec2 &imgSize, const ImVec2 &uv0, const ImVec2 &uv1, int frame_padding, const ImVec4 &bg_col, const ImVec4 &tint_col)
|
|
||||||
{
|
|
||||||
ImGuiWindow *window = ImGui::GetCurrentWindow();
|
|
||||||
if (window->SkipItems)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
ImGuiContext &g = *GImGui;
|
|
||||||
const ImGuiStyle &style = g.Style;
|
|
||||||
|
|
||||||
// Default to using texture ID as ID. User can still push string/integer prefixes.
|
|
||||||
// We could hash the size/uv to create a unique ID but that would prevent the user from animating UV.
|
|
||||||
ImGui::PushID((void *)user_texture_id);
|
|
||||||
const ImGuiID id = window->GetID("#image");
|
|
||||||
ImGui::PopID();
|
|
||||||
|
|
||||||
ImVec2 imgPadding = (size - imgSize) / 2;
|
|
||||||
imgPadding.x = imgPadding.x < 0 || imgSize.x <= 0 ? 0 : imgPadding.x;
|
|
||||||
imgPadding.y = imgPadding.y < 0 || imgSize.y <= 0 ? 0 : imgPadding.y;
|
|
||||||
|
|
||||||
const ImVec2 padding = (frame_padding >= 0) ? ImVec2((float)frame_padding, (float)frame_padding) : style.FramePadding;
|
|
||||||
const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + size + padding * 2);
|
|
||||||
const ImRect image_bb(window->DC.CursorPos + padding + imgPadding, window->DC.CursorPos + padding + size - imgPadding);
|
|
||||||
ImGui::ItemSize(bb);
|
|
||||||
if (!ImGui::ItemAdd(bb, id))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
bool hovered, held;
|
|
||||||
bool pressed = ImGui::ButtonBehavior(bb, id, &hovered, &held);
|
|
||||||
|
|
||||||
// Render
|
|
||||||
const ImU32 col = ImGui::GetColorU32((held && hovered) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button);
|
|
||||||
ImGui::RenderNavHighlight(bb, id);
|
|
||||||
ImGui::RenderFrame(bb.Min, bb.Max, col, true, ImClamp((float)ImMin(padding.x, padding.y), 0.0f, style.FrameRounding));
|
|
||||||
if (bg_col.w > 0.0f)
|
|
||||||
window->DrawList->AddRectFilled(image_bb.Min, image_bb.Max, ImGui::GetColorU32(bg_col));
|
|
||||||
window->DrawList->AddImage(user_texture_id, image_bb.Min, image_bb.Max, uv0, uv1, ImGui::GetColorU32(tint_col));
|
|
||||||
|
|
||||||
return pressed;
|
|
||||||
}
|
|
||||||
|
|
||||||
void PiGui::Cleanup()
|
|
||||||
{
|
{
|
||||||
PROFILE_SCOPED()
|
PROFILE_SCOPED()
|
||||||
for (auto tex : m_svg_textures) {
|
for (auto tex : m_svg_textures) {
|
||||||
delete tex;
|
delete tex;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (Pi::renderer->GetRendererType()) {
|
switch (m_renderer->GetRendererType()) {
|
||||||
default:
|
default:
|
||||||
case Graphics::RENDERER_DUMMY:
|
case Graphics::RENDERER_DUMMY:
|
||||||
return;
|
return;
|
||||||
|
@ -743,25 +432,9 @@ void PiGui::Cleanup()
|
||||||
ImGui::DestroyContext();
|
ImGui::DestroyContext();
|
||||||
}
|
}
|
||||||
|
|
||||||
PiGui::PiGui() :
|
//
|
||||||
m_should_bake_fonts(true)
|
// PiGui::PiFace
|
||||||
{
|
//
|
||||||
PiFont uiheading("orbiteer", {
|
|
||||||
PiFace("DejaVuSans.ttf", /*18.0/20.0*/ 1.2), PiFace("wqy-microhei.ttc", 1.0), PiFace("Orbiteer-Bold.ttf", 1.0) // imgui only supports 0xffff, not 0x10ffff
|
|
||||||
});
|
|
||||||
PiFont guifont("pionillium", { PiFace("DejaVuSans.ttf", 13.0 / 14.0), PiFace("wqy-microhei.ttc", 1.0), PiFace("PionilliumText22L-Medium.ttf", 1.0) });
|
|
||||||
AddFontDefinition(uiheading);
|
|
||||||
AddFontDefinition(guifont);
|
|
||||||
|
|
||||||
// Output("Fonts:\n");
|
|
||||||
for (auto entry : m_font_definitions) {
|
|
||||||
// Output(" entry %s:\n", entry.first.c_str());
|
|
||||||
entry.second.describe();
|
|
||||||
}
|
|
||||||
|
|
||||||
// ensure the tooltip font exists
|
|
||||||
GetFont("pionillium", 14);
|
|
||||||
};
|
|
||||||
|
|
||||||
const bool PiFace::isValidGlyph(unsigned short glyph) const
|
const bool PiFace::isValidGlyph(unsigned short glyph) const
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,140 +1,149 @@
|
||||||
// Copyright © 2008-2020 Pioneer Developers. See AUTHORS.txt for details
|
// Copyright © 2008-2020 Pioneer Developers. See AUTHORS.txt for details
|
||||||
// Licensed under the terms of the GPL v3. See licenses/GPL-3.txt
|
// Licensed under the terms of the GPL v3. See licenses/GPL-3.txt
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
#include "FileSystem.h"
|
#include "FileSystem.h"
|
||||||
#include "RefCounted.h"
|
#include "RefCounted.h"
|
||||||
#include "graphics/opengl/RendererGL.h"
|
|
||||||
#include "imgui/imgui.h"
|
#include "imgui/imgui.h"
|
||||||
#include "lua/Lua.h"
|
|
||||||
#include "lua/LuaRef.h"
|
#include "utils.h"
|
||||||
#include "lua/LuaTable.h"
|
|
||||||
#include <unordered_set>
|
#include <unordered_set>
|
||||||
|
|
||||||
class PiFace {
|
namespace Graphics {
|
||||||
friend class PiGui; // need acces to some private data
|
class Texture;
|
||||||
std::string m_ttfname; // only the ttf name, it is automatically sought in data/fonts/
|
class Renderer;
|
||||||
float m_sizefactor; // the requested pixelsize is multiplied by this factor
|
} // namespace Graphics
|
||||||
std::unordered_set<unsigned short> m_invalid_glyphs;
|
|
||||||
mutable std::vector<std::pair<unsigned short, unsigned short>> m_used_ranges;
|
|
||||||
ImVector<ImWchar> m_imgui_ranges;
|
|
||||||
|
|
||||||
public:
|
namespace PiGui {
|
||||||
PiFace(const std::string &ttfname, float sizefactor) :
|
|
||||||
m_ttfname(ttfname),
|
|
||||||
m_sizefactor(sizefactor) {}
|
|
||||||
const std::string &ttfname() const { return m_ttfname; }
|
|
||||||
const float sizefactor() const { return m_sizefactor; }
|
|
||||||
//std::unordered_map<unsigned short, unsigned short> &invalid_glyphs() const { return m_invalid_glyphs; }
|
|
||||||
const std::vector<std::pair<unsigned short, unsigned short>> &used_ranges() const { return m_used_ranges; }
|
|
||||||
const bool isValidGlyph(unsigned short glyph) const;
|
|
||||||
void addGlyph(unsigned short glyph);
|
|
||||||
void sortUsedRanges() const;
|
|
||||||
};
|
|
||||||
|
|
||||||
class PiFont {
|
class PiFace {
|
||||||
std::string m_name;
|
public:
|
||||||
std::vector<PiFace> m_faces;
|
using UsedRange = std::pair<uint16_t, uint16_t>;
|
||||||
int m_pixelsize;
|
PiFace(const std::string &ttfname, float sizefactor) :
|
||||||
|
m_ttfname(ttfname),
|
||||||
|
m_sizefactor(sizefactor) {}
|
||||||
|
|
||||||
public:
|
const std::string &ttfname() const { return m_ttfname; }
|
||||||
PiFont(const std::string &name) :
|
|
||||||
m_name(name) {}
|
const float sizefactor() const { return m_sizefactor; }
|
||||||
PiFont(const std::string &name, const std::vector<PiFace> &faces) :
|
|
||||||
m_name(name),
|
//std::unordered_map<unsigned short, unsigned short> &invalid_glyphs() const { return m_invalid_glyphs; }
|
||||||
m_faces(faces) {}
|
const std::vector<UsedRange> &used_ranges() const { return m_used_ranges; }
|
||||||
PiFont(const PiFont &other) :
|
|
||||||
m_name(other.name()),
|
const bool isValidGlyph(unsigned short glyph) const;
|
||||||
m_faces(other.faces()) {}
|
void addGlyph(unsigned short glyph);
|
||||||
PiFont() :
|
void sortUsedRanges() const;
|
||||||
m_name("unknown") {}
|
|
||||||
const std::vector<PiFace> &faces() const { return m_faces; }
|
private:
|
||||||
std::vector<PiFace> &faces() { return m_faces; }
|
friend class Instance; // need access to some private data
|
||||||
const std::string &name() const { return m_name; }
|
|
||||||
int pixelsize() const { return m_pixelsize; }
|
std::string m_ttfname; // only the ttf name, it is automatically sought in data/fonts/
|
||||||
void setPixelsize(int pixelsize) { m_pixelsize = pixelsize; }
|
float m_sizefactor; // the requested pixelsize is multiplied by this factor
|
||||||
void describe() const
|
|
||||||
{
|
std::unordered_set<unsigned short> m_invalid_glyphs;
|
||||||
Output("font %s:\n", name().c_str());
|
mutable std::vector<UsedRange> m_used_ranges;
|
||||||
for (const PiFace &face : faces()) {
|
|
||||||
Output("- %s %f\n", face.ttfname().c_str(), face.sizefactor());
|
ImVector<ImWchar> m_imgui_ranges;
|
||||||
|
};
|
||||||
|
|
||||||
|
class PiFont {
|
||||||
|
public:
|
||||||
|
PiFont(const std::string &name) :
|
||||||
|
m_name(name) {}
|
||||||
|
PiFont(const std::string &name, const std::vector<PiFace> &faces) :
|
||||||
|
m_name(name),
|
||||||
|
m_faces(faces) {}
|
||||||
|
PiFont(const PiFont &other) :
|
||||||
|
m_name(other.name()),
|
||||||
|
m_faces(other.faces()) {}
|
||||||
|
PiFont() :
|
||||||
|
m_name("unknown") {}
|
||||||
|
|
||||||
|
const std::vector<PiFace> &faces() const { return m_faces; }
|
||||||
|
std::vector<PiFace> &faces() { return m_faces; }
|
||||||
|
|
||||||
|
const std::string &name() const { return m_name; }
|
||||||
|
|
||||||
|
int pixelsize() const { return m_pixelsize; }
|
||||||
|
void setPixelsize(int pixelsize) { m_pixelsize = pixelsize; }
|
||||||
|
|
||||||
|
void describe() const
|
||||||
|
{
|
||||||
|
Output("font %s:\n", name().c_str());
|
||||||
|
for (const PiFace &face : faces()) {
|
||||||
|
Output("- %s %f\n", face.ttfname().c_str(), face.sizefactor());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Class to wrap ImGui. */
|
private:
|
||||||
class PiGui : public RefCounted {
|
std::string m_name;
|
||||||
std::map<std::pair<std::string, int>, ImFont *> m_fonts;
|
std::vector<PiFace> m_faces;
|
||||||
std::map<ImFont *, std::pair<std::string, int>> m_im_fonts;
|
int m_pixelsize;
|
||||||
std::map<std::pair<std::string, int>, PiFont> m_pi_fonts;
|
};
|
||||||
bool m_should_bake_fonts;
|
|
||||||
|
|
||||||
std::map<std::string, PiFont> m_font_definitions;
|
/* Class to wrap ImGui. */
|
||||||
|
class Instance : public RefCounted {
|
||||||
|
public:
|
||||||
|
Instance();
|
||||||
|
|
||||||
void BakeFonts();
|
void Init(Graphics::Renderer *renderer);
|
||||||
void BakeFont(PiFont &font);
|
void Uninit();
|
||||||
void AddFontDefinition(const PiFont &font) { m_font_definitions[font.name()] = font; }
|
|
||||||
void ClearFonts();
|
|
||||||
|
|
||||||
public:
|
// Call at the start of every frame. Calls ImGui::NewFrame() internally.
|
||||||
PiGui();
|
void NewFrame();
|
||||||
|
|
||||||
LuaRef GetHandlers() const { return m_handlers; }
|
// Call at the end of a frame that you're not going to render the results of
|
||||||
|
void EndFrame();
|
||||||
|
|
||||||
LuaRef GetKeys() const { return m_keys; }
|
// Calls ImGui::EndFrame() internally and does book-keeping before rendering.
|
||||||
|
void Render();
|
||||||
|
|
||||||
void RunHandler(double delta, std::string handler = "GAME");
|
ImFont *AddFont(const std::string &name, int size);
|
||||||
|
ImFont *GetFont(const std::string &name, int size);
|
||||||
|
|
||||||
// Call at the start of every frame. Calls ImGui::NewFrame() internally.
|
void AddGlyph(ImFont *font, unsigned short glyph);
|
||||||
void NewFrame(SDL_Window *window);
|
|
||||||
|
|
||||||
// Call at the end of a frame that you're not going to render the results of
|
bool ProcessEvent(SDL_Event *event);
|
||||||
void EndFrame();
|
|
||||||
|
|
||||||
// Calls ImGui::EndFrame() internally and does book-keeping before rendering.
|
void RefreshFontsTexture();
|
||||||
void Render();
|
|
||||||
|
|
||||||
void Init(SDL_Window *window);
|
private:
|
||||||
|
Graphics::Renderer *m_renderer;
|
||||||
|
|
||||||
ImFont *GetFont(const std::string &name, int size);
|
std::map<std::pair<std::string, int>, ImFont *> m_fonts;
|
||||||
|
std::map<ImFont *, std::pair<std::string, int>> m_im_fonts;
|
||||||
|
std::map<std::pair<std::string, int>, PiFont> m_pi_fonts;
|
||||||
|
bool m_should_bake_fonts;
|
||||||
|
|
||||||
void Uninit()
|
std::map<std::string, PiFont> m_font_definitions;
|
||||||
{
|
|
||||||
Cleanup();
|
|
||||||
m_handlers.Unref();
|
|
||||||
m_keys.Unref();
|
|
||||||
}
|
|
||||||
ImFont *AddFont(const std::string &name, int size);
|
|
||||||
|
|
||||||
void AddGlyph(ImFont *font, unsigned short glyph);
|
void BakeFonts();
|
||||||
|
void BakeFont(PiFont &font);
|
||||||
|
void AddFontDefinition(const PiFont &font) { m_font_definitions[font.name()] = font; }
|
||||||
|
void ClearFonts();
|
||||||
|
};
|
||||||
|
|
||||||
static ImTextureID RenderSVG(std::string svgFilename, int width, int height);
|
int RadialPopupSelectMenu(const ImVec2 ¢er, std::string popup_id, int mouse_button, std::vector<ImTextureID> tex_ids, std::vector<std::pair<ImVec2, ImVec2>> uvs, unsigned int size, std::vector<std::string> tooltips);
|
||||||
|
bool CircularSlider(const ImVec2 ¢er, float *v, float v_min, float v_max);
|
||||||
|
|
||||||
static bool ProcessEvent(SDL_Event *event);
|
bool LowThrustButton(const char *label, const ImVec2 &size_arg, int thrust_level, const ImVec4 &bg_col, int frame_padding, ImColor gauge_fg, ImColor gauge_bg);
|
||||||
|
bool ButtonImageSized(ImTextureID user_texture_id, const ImVec2 &size, const ImVec2 &imgSize, const ImVec2 &uv0, const ImVec2 &uv1, int frame_padding, const ImVec4 &bg_col, const ImVec4 &tint_col);
|
||||||
|
|
||||||
void RefreshFontsTexture();
|
void ThrustIndicator(const std::string &id_string, const ImVec2 &size, const ImVec4 &thrust, const ImVec4 &velocity, const ImVec4 &bg_col, int frame_padding, ImColor vel_fg, ImColor vel_bg, ImColor thrust_fg, ImColor thrust_bg);
|
||||||
|
|
||||||
static void *makeTexture(unsigned char *pixels, int width, int height);
|
inline bool WantCaptureMouse()
|
||||||
|
|
||||||
static bool WantCaptureMouse()
|
|
||||||
{
|
{
|
||||||
return ImGui::GetIO().WantCaptureMouse;
|
return ImGui::GetIO().WantCaptureMouse;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool WantCaptureKeyboard()
|
inline bool WantCaptureKeyboard()
|
||||||
{
|
{
|
||||||
return ImGui::GetIO().WantCaptureKeyboard;
|
return ImGui::GetIO().WantCaptureKeyboard;
|
||||||
}
|
}
|
||||||
static int RadialPopupSelectMenu(const ImVec2 ¢er, std::string popup_id, int mouse_button, std::vector<ImTextureID> tex_ids, std::vector<std::pair<ImVec2, ImVec2>> uvs, unsigned int size, std::vector<std::string> tooltips);
|
|
||||||
static bool CircularSlider(const ImVec2 ¢er, float *v, float v_min, float v_max);
|
|
||||||
|
|
||||||
void Cleanup();
|
std::vector<Graphics::Texture *> &GetSVGTextures();
|
||||||
static bool LowThrustButton(const char *label, const ImVec2 &size_arg, int thrust_level, const ImVec4 &bg_col, int frame_padding, ImColor gauge_fg, ImColor gauge_bg);
|
ImTextureID RenderSVG(Graphics::Renderer *renderer, std::string svgFilename, int width, int height);
|
||||||
static bool ButtonImageSized(ImTextureID user_texture_id, const ImVec2 &size, const ImVec2 &imgSize, const ImVec2 &uv0, const ImVec2 &uv1, int frame_padding, const ImVec4 &bg_col, const ImVec4 &tint_col);
|
|
||||||
|
|
||||||
static void ThrustIndicator(const std::string &id_string, const ImVec2 &size, const ImVec4 &thrust, const ImVec4 &velocity, const ImVec4 &bg_col, int frame_padding, ImColor vel_fg, ImColor vel_bg, ImColor thrust_fg, ImColor thrust_bg);
|
} //namespace PiGui
|
||||||
|
|
||||||
private:
|
|
||||||
LuaRef m_handlers;
|
|
||||||
LuaRef m_keys;
|
|
||||||
static std::vector<Graphics::Texture *> m_svg_textures;
|
|
||||||
};
|
|
||||||
|
|
|
@ -5,17 +5,65 @@
|
||||||
#include "Face.h"
|
#include "Face.h"
|
||||||
#include "Image.h"
|
#include "Image.h"
|
||||||
#include "ModelSpinner.h"
|
#include "ModelSpinner.h"
|
||||||
|
#include "lua/LuaTable.h"
|
||||||
|
|
||||||
|
static std::vector<std::pair<std::string, int>> m_keycodes = {
|
||||||
|
{ "left", SDLK_LEFT },
|
||||||
|
{ "right", SDLK_RIGHT },
|
||||||
|
{ "up", SDLK_UP },
|
||||||
|
{ "down", SDLK_DOWN },
|
||||||
|
{ "escape", SDLK_ESCAPE },
|
||||||
|
{ "f1", SDLK_F1 },
|
||||||
|
{ "f2", SDLK_F2 },
|
||||||
|
{ "f3", SDLK_F3 },
|
||||||
|
{ "f4", SDLK_F4 },
|
||||||
|
{ "f5", SDLK_F5 },
|
||||||
|
{ "f6", SDLK_F6 },
|
||||||
|
{ "f7", SDLK_F7 },
|
||||||
|
{ "f8", SDLK_F8 },
|
||||||
|
{ "f9", SDLK_F9 },
|
||||||
|
{ "f10", SDLK_F10 },
|
||||||
|
{ "f11", SDLK_F11 },
|
||||||
|
{ "f12", SDLK_F12 },
|
||||||
|
{ "tab", SDLK_TAB },
|
||||||
|
};
|
||||||
|
|
||||||
|
static LuaRef m_handlers;
|
||||||
|
static LuaRef m_keys;
|
||||||
|
|
||||||
namespace PiGUI {
|
namespace PiGUI {
|
||||||
|
|
||||||
namespace Lua {
|
namespace Lua {
|
||||||
|
|
||||||
void Init()
|
void Init()
|
||||||
{
|
{
|
||||||
|
LuaObject<PiGui::Instance>::RegisterClass();
|
||||||
|
|
||||||
|
lua_State *l = ::Lua::manager->GetLuaState();
|
||||||
|
lua_newtable(l);
|
||||||
|
m_handlers = LuaRef(l, -1);
|
||||||
|
|
||||||
|
lua_newtable(l);
|
||||||
|
m_keys = LuaRef(l, -1);
|
||||||
|
LuaTable keys(l, -1);
|
||||||
|
for (auto p : m_keycodes) {
|
||||||
|
keys.Set(p.first, p.second);
|
||||||
|
}
|
||||||
|
|
||||||
LuaObject<PiGUI::Image>::RegisterClass();
|
LuaObject<PiGUI::Image>::RegisterClass();
|
||||||
LuaObject<PiGUI::Face>::RegisterClass();
|
LuaObject<PiGUI::Face>::RegisterClass();
|
||||||
LuaObject<PiGUI::ModelSpinner>::RegisterClass();
|
LuaObject<PiGUI::ModelSpinner>::RegisterClass();
|
||||||
RegisterSandbox();
|
RegisterSandbox();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Uninit()
|
||||||
|
{
|
||||||
|
m_handlers.Unref();
|
||||||
|
m_keys.Unref();
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Lua
|
} // namespace Lua
|
||||||
|
|
||||||
|
LuaRef GetHandlers() { return m_handlers; }
|
||||||
|
LuaRef GetKeys() { return m_keys; }
|
||||||
} // namespace PiGUI
|
} // namespace PiGUI
|
||||||
|
|
|
@ -7,12 +7,18 @@
|
||||||
#include "lua/LuaObject.h"
|
#include "lua/LuaObject.h"
|
||||||
|
|
||||||
namespace PiGUI {
|
namespace PiGUI {
|
||||||
void RegisterSandbox();
|
|
||||||
|
// Get registered PiGui handlers.
|
||||||
|
LuaRef GetHandlers();
|
||||||
|
// Get a table of key name to SDL-keycode mappings
|
||||||
|
LuaRef GetKeys();
|
||||||
|
|
||||||
namespace Lua {
|
namespace Lua {
|
||||||
|
void RegisterSandbox();
|
||||||
|
|
||||||
void Init();
|
void Init();
|
||||||
}
|
void Uninit();
|
||||||
|
} // namespace Lua
|
||||||
} // namespace PiGUI
|
} // namespace PiGUI
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -132,7 +132,7 @@ luaL_Reg l_stack_functions[] = {
|
||||||
{ NULL, NULL }
|
{ NULL, NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
void PiGUI::RegisterSandbox()
|
void PiGUI::Lua::RegisterSandbox()
|
||||||
{
|
{
|
||||||
lua_State *L = ::Lua::manager->GetLuaState();
|
lua_State *L = ::Lua::manager->GetLuaState();
|
||||||
LUA_DEBUG_START(L);
|
LUA_DEBUG_START(L);
|
||||||
|
|
|
@ -0,0 +1,303 @@
|
||||||
|
// Copyright © 2008-2020 Pioneer Developers. See AUTHORS.txt for details
|
||||||
|
// Licensed under the terms of the GPL v3. See licenses/GPL-3.txt
|
||||||
|
|
||||||
|
#include "PiGui.h"
|
||||||
|
#include "imgui/imgui.h"
|
||||||
|
|
||||||
|
// to get ImVec2 + ImVec2
|
||||||
|
#define IMGUI_DEFINE_MATH_OPERATORS true
|
||||||
|
#include "imgui/imgui_internal.h"
|
||||||
|
|
||||||
|
int PiGui::RadialPopupSelectMenu(const ImVec2 ¢er, std::string popup_id, int mouse_button, std::vector<ImTextureID> tex_ids, std::vector<std::pair<ImVec2, ImVec2>> uvs, unsigned int size, std::vector<std::string> tooltips)
|
||||||
|
{
|
||||||
|
PROFILE_SCOPED()
|
||||||
|
// return:
|
||||||
|
// 0 - n for item selected
|
||||||
|
// -1 for nothing chosen, but menu open
|
||||||
|
// -2 for menu closed without an icon chosen
|
||||||
|
// -3 for menu not open
|
||||||
|
int ret = -3;
|
||||||
|
|
||||||
|
// FIXME: Missing a call to query if Popup is open so we can move the PushStyleColor inside the BeginPopupBlock (e.g. IsPopupOpen() in imgui.cpp)
|
||||||
|
// FIXME: Our PathFill function only handle convex polygons, so we can't have items spanning an arc too large else inner concave edge artifact is too visible, hence the ImMax(7,items_count)
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_WindowBg, ImVec4(0, 0, 0, 0));
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_PopupBg, ImVec4(0, 0, 0, 0));
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(0, 0, 0, 0));
|
||||||
|
if (ImGui::BeginPopup(popup_id.c_str())) {
|
||||||
|
ret = -1;
|
||||||
|
const ImVec2 drag_delta = ImVec2(ImGui::GetIO().MousePos.x - center.x, ImGui::GetIO().MousePos.y - center.y);
|
||||||
|
const float drag_dist2 = drag_delta.x * drag_delta.x + drag_delta.y * drag_delta.y;
|
||||||
|
|
||||||
|
const ImGuiStyle &style = ImGui::GetStyle();
|
||||||
|
const float RADIUS_MIN = 20.0f;
|
||||||
|
const float RADIUS_MAX = 90.0f;
|
||||||
|
const float RADIUS_INTERACT_MIN = 20.0f;
|
||||||
|
const int ITEMS_MIN = 4;
|
||||||
|
const float border_inout = 12.0f;
|
||||||
|
const float border_thickness = 4.0f;
|
||||||
|
ImDrawList *draw_list = ImGui::GetWindowDrawList();
|
||||||
|
draw_list->PushClipRectFullScreen();
|
||||||
|
draw_list->PathArcTo(center, (RADIUS_MIN + RADIUS_MAX) * 0.5f, 0.0f, IM_PI * 2.0f * 0.99f, 64); // FIXME: 0.99f look like full arc with closed thick stroke has a bug now
|
||||||
|
draw_list->PathStroke(ImColor(18, 44, 67, 210), true, RADIUS_MAX - RADIUS_MIN);
|
||||||
|
|
||||||
|
const float item_arc_span = 2 * IM_PI / ImMax<int>(ITEMS_MIN, tex_ids.size());
|
||||||
|
float drag_angle = atan2f(drag_delta.y, drag_delta.x);
|
||||||
|
if (drag_angle < -0.5f * item_arc_span)
|
||||||
|
drag_angle += 2.0f * IM_PI;
|
||||||
|
|
||||||
|
int item_hovered = -1;
|
||||||
|
int item_n = 0;
|
||||||
|
for (ImTextureID tex_id : tex_ids) {
|
||||||
|
const char *tooltip = tooltips.at(item_n).c_str();
|
||||||
|
const float inner_spacing = style.ItemInnerSpacing.x / RADIUS_MIN / 2;
|
||||||
|
const float item_inner_ang_min = item_arc_span * (item_n - 0.5f + inner_spacing);
|
||||||
|
const float item_inner_ang_max = item_arc_span * (item_n + 0.5f - inner_spacing);
|
||||||
|
const float item_outer_ang_min = item_arc_span * (item_n - 0.5f + inner_spacing * (RADIUS_MIN / RADIUS_MAX));
|
||||||
|
const float item_outer_ang_max = item_arc_span * (item_n + 0.5f - inner_spacing * (RADIUS_MIN / RADIUS_MAX));
|
||||||
|
|
||||||
|
bool hovered = false;
|
||||||
|
if (drag_dist2 >= RADIUS_INTERACT_MIN * RADIUS_INTERACT_MIN) {
|
||||||
|
if (drag_angle >= item_inner_ang_min && drag_angle < item_inner_ang_max)
|
||||||
|
hovered = true;
|
||||||
|
}
|
||||||
|
bool selected = false;
|
||||||
|
|
||||||
|
int arc_segments = static_cast<int>((64 * item_arc_span / (2 * IM_PI))) + 1;
|
||||||
|
draw_list->PathArcTo(center, RADIUS_MAX - border_inout, item_outer_ang_min, item_outer_ang_max, arc_segments);
|
||||||
|
draw_list->PathArcTo(center, RADIUS_MIN + border_inout, item_inner_ang_max, item_inner_ang_min, arc_segments);
|
||||||
|
|
||||||
|
draw_list->PathFillConvex(hovered ? ImColor(102, 147, 189) : selected ? ImColor(48, 81, 111) : ImColor(48, 81, 111));
|
||||||
|
if (hovered) {
|
||||||
|
// draw outer / inner extra segments
|
||||||
|
draw_list->PathArcTo(center, RADIUS_MAX - border_thickness, item_outer_ang_min, item_outer_ang_max, arc_segments);
|
||||||
|
draw_list->PathStroke(ImColor(102, 147, 189), false, border_thickness);
|
||||||
|
draw_list->PathArcTo(center, RADIUS_MIN + border_thickness, item_outer_ang_min, item_outer_ang_max, arc_segments);
|
||||||
|
draw_list->PathStroke(ImColor(102, 147, 189), false, border_thickness);
|
||||||
|
}
|
||||||
|
ImVec2 text_size = ImVec2(size, size);
|
||||||
|
ImVec2 text_pos = ImVec2(
|
||||||
|
center.x + cosf((item_inner_ang_min + item_inner_ang_max) * 0.5f) * (RADIUS_MIN + RADIUS_MAX) * 0.5f - text_size.x * 0.5f,
|
||||||
|
center.y + sinf((item_inner_ang_min + item_inner_ang_max) * 0.5f) * (RADIUS_MIN + RADIUS_MAX) * 0.5f - text_size.y * 0.5f);
|
||||||
|
draw_list->AddImage(tex_id, text_pos, ImVec2(text_pos.x + size, text_pos.y + size), uvs[item_n].first, uvs[item_n].second);
|
||||||
|
ImGui::SameLine();
|
||||||
|
if (hovered) {
|
||||||
|
item_hovered = item_n;
|
||||||
|
ImGui::SetTooltip("%s", tooltip);
|
||||||
|
}
|
||||||
|
item_n++;
|
||||||
|
}
|
||||||
|
draw_list->PopClipRect();
|
||||||
|
|
||||||
|
if (ImGui::IsMouseReleased(mouse_button)) {
|
||||||
|
ImGui::CloseCurrentPopup();
|
||||||
|
if (item_hovered == -1)
|
||||||
|
ret = -2;
|
||||||
|
else
|
||||||
|
ret = item_hovered;
|
||||||
|
}
|
||||||
|
ImGui::EndPopup();
|
||||||
|
} else {
|
||||||
|
// Output("WARNING: RadialPopupSelectMenu BeginPopup failed: %s\n", popup_id.c_str());
|
||||||
|
}
|
||||||
|
ImGui::PopStyleColor(3);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PiGui::CircularSlider(const ImVec2 ¢er, float *v, float v_min, float v_max)
|
||||||
|
{
|
||||||
|
PROFILE_SCOPED()
|
||||||
|
ImDrawList *draw_list = ImGui::GetWindowDrawList();
|
||||||
|
ImGuiWindow *window = ImGui::GetCurrentWindow();
|
||||||
|
const ImGuiID id = window->GetID("circularslider");
|
||||||
|
draw_list->AddCircle(center, 17, ImColor(100, 100, 100), 128, 12.0);
|
||||||
|
draw_list->PathArcTo(center, 17, 0, M_PI * 2.0 * (*v - v_min) / (v_max - v_min), 64);
|
||||||
|
draw_list->PathStroke(ImColor(200, 200, 200), false, 12.0);
|
||||||
|
ImRect grab_bb;
|
||||||
|
return ImGui::SliderBehavior(ImRect(center.x - 17, center.y - 17, center.x + 17, center.y + 17),
|
||||||
|
id, ImGuiDataType_Float, v, &v_min, &v_max, "%.4f", 1.0, ImGuiSliderFlags_None, &grab_bb);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void drawThrust(ImDrawList *draw_list, const ImVec2 ¢er, const ImVec2 &up, float value, const ImColor &fg, const ImColor &bg)
|
||||||
|
{
|
||||||
|
PROFILE_SCOPED()
|
||||||
|
float factor = 0.1; // how much to offset from center
|
||||||
|
const ImVec2 step(up.x * 0.5, up.y * 0.5);
|
||||||
|
const ImVec2 left(-step.y * (1.0 - factor), step.x * (1.0 - factor));
|
||||||
|
const ImVec2 u(up.x * (1.0 - factor), up.y * (1.0 - factor));
|
||||||
|
const ImVec2 c(center + ImVec2(u.x * factor, u.y * factor));
|
||||||
|
const ImVec2 right(-left.x, -left.y);
|
||||||
|
const ImVec2 leftmiddle = c + step + left;
|
||||||
|
const ImVec2 rightmiddle = c + step + right;
|
||||||
|
const ImVec2 bb_lowerright = c + right;
|
||||||
|
const ImVec2 bb_upperleft = c + left + ImVec2(u.x * value, u.y * value);
|
||||||
|
const ImVec2 lefttop = c + u + left;
|
||||||
|
const ImVec2 righttop = c + u + right;
|
||||||
|
const ImVec2 minimum(fmin(bb_upperleft.x, bb_lowerright.x), fmin(bb_upperleft.y, bb_lowerright.y));
|
||||||
|
const ImVec2 maximum(fmax(bb_upperleft.x, bb_lowerright.x), fmax(bb_upperleft.y, bb_lowerright.y));
|
||||||
|
ImVec2 points[] = { c, leftmiddle, lefttop, righttop, rightmiddle };
|
||||||
|
draw_list->AddConvexPolyFilled(points, 5, bg);
|
||||||
|
draw_list->PushClipRect(minimum - ImVec2(1, 1), maximum + ImVec2(1, 1));
|
||||||
|
draw_list->AddConvexPolyFilled(points, 5, fg);
|
||||||
|
draw_list->PopClipRect();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PiGui::ThrustIndicator(const std::string &id_string, const ImVec2 &size_arg, const ImVec4 &thrust, const ImVec4 &velocity, const ImVec4 &bg_col, int frame_padding, ImColor vel_fg, ImColor vel_bg, ImColor thrust_fg, ImColor thrust_bg)
|
||||||
|
{
|
||||||
|
PROFILE_SCOPED()
|
||||||
|
ImGuiWindow *window = ImGui::GetCurrentWindow();
|
||||||
|
if (window->SkipItems)
|
||||||
|
return;
|
||||||
|
|
||||||
|
ImGuiContext &g = *GImGui;
|
||||||
|
const ImGuiStyle &style = g.Style;
|
||||||
|
const ImGuiID id = window->GetID(id_string.c_str());
|
||||||
|
|
||||||
|
ImVec2 pos = window->DC.CursorPos;
|
||||||
|
// if ((flags & ImGuiButtonFlags_AlignTextBaseLine) && style.FramePadding.y < window->DC.CurrentLineTextBaseOffset) // Try to vertically align buttons that are smaller/have no padding so that text baseline matches (bit hacky, since it shouldn't be a flag)
|
||||||
|
// pos.y += window->DC.CurrentLineTextBaseOffset - style.FramePadding.y;
|
||||||
|
ImVec2 size = ImGui::CalcItemSize(size_arg, style.FramePadding.x * 2.0f, style.FramePadding.y * 2.0f);
|
||||||
|
|
||||||
|
const ImVec2 padding = (frame_padding >= 0) ? ImVec2(static_cast<float>(frame_padding), static_cast<float>(frame_padding)) : style.FramePadding;
|
||||||
|
const ImRect bb(pos, pos + size + padding * 2);
|
||||||
|
const ImRect inner_bb(pos + padding, pos + padding + size);
|
||||||
|
|
||||||
|
ImGui::ItemSize(bb, style.FramePadding.y);
|
||||||
|
if (!ImGui::ItemAdd(bb, id))
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Render
|
||||||
|
const ImU32 col = ImGui::GetColorU32(static_cast<ImGuiCol>(ImGuiCol_Button));
|
||||||
|
ImGui::RenderFrame(bb.Min, bb.Max, col, true, style.FrameRounding);
|
||||||
|
ImDrawList *draw_list = ImGui::GetWindowDrawList();
|
||||||
|
if (bg_col.w > 0.0f)
|
||||||
|
draw_list->AddRectFilled(inner_bb.Min, inner_bb.Max, ImGui::GetColorU32(bg_col));
|
||||||
|
const ImVec2 leftupper = inner_bb.Min;
|
||||||
|
const ImVec2 rightlower = inner_bb.Max;
|
||||||
|
const ImVec2 rightcenter((rightlower.x - leftupper.x) * 0.8 + leftupper.x, (rightlower.y + leftupper.y) / 2);
|
||||||
|
const ImVec2 leftcenter((rightlower.x - leftupper.x) * 0.35 + leftupper.x, (rightlower.y + leftupper.y) / 2);
|
||||||
|
const ImVec2 up(0, -std::abs(leftupper.y - rightlower.y) * 0.4);
|
||||||
|
const ImVec2 left(-up.y, up.x);
|
||||||
|
float thrust_fwd = fmax(thrust.z, 0);
|
||||||
|
float thrust_bwd = fmax(-thrust.z, 0);
|
||||||
|
float thrust_left = fmax(-thrust.x, 0);
|
||||||
|
float thrust_right = fmax(thrust.x, 0);
|
||||||
|
float thrust_up = fmax(-thrust.y, 0);
|
||||||
|
float thrust_down = fmax(thrust.y, 0);
|
||||||
|
// actual thrust
|
||||||
|
drawThrust(draw_list, rightcenter, up, thrust_fwd, thrust_fg, thrust_bg);
|
||||||
|
drawThrust(draw_list, rightcenter, ImVec2(-up.x, -up.y), thrust_bwd, thrust_fg, thrust_bg);
|
||||||
|
drawThrust(draw_list, leftcenter, up, thrust_up, thrust_fg, thrust_bg);
|
||||||
|
drawThrust(draw_list, leftcenter, ImVec2(-up.x, -up.y), thrust_down, thrust_fg, thrust_bg);
|
||||||
|
drawThrust(draw_list, leftcenter, left, thrust_left, thrust_fg, thrust_bg);
|
||||||
|
drawThrust(draw_list, leftcenter, ImVec2(-left.x, -left.y), thrust_right, thrust_fg, thrust_bg);
|
||||||
|
// forward/back velocity
|
||||||
|
draw_list->AddLine(rightcenter + up, rightcenter - up, vel_bg, 3);
|
||||||
|
draw_list->AddLine(rightcenter, rightcenter - up * velocity.z, vel_fg, 3);
|
||||||
|
// left/right velocity
|
||||||
|
draw_list->AddLine(leftcenter + left, leftcenter - left, vel_bg, 3);
|
||||||
|
draw_list->AddLine(leftcenter, leftcenter + left * velocity.x, vel_fg, 3);
|
||||||
|
// up/down velocity
|
||||||
|
draw_list->AddLine(leftcenter + up, leftcenter - up, vel_bg, 3);
|
||||||
|
draw_list->AddLine(leftcenter, leftcenter + up * velocity.y, vel_fg, 3);
|
||||||
|
// Automatically close popups
|
||||||
|
//if (pressed && !(flags & ImGuiButtonFlags_DontClosePopups) && (window->Flags & ImGuiWindowFlags_Popup))
|
||||||
|
// CloseCurrentPopup();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PiGui::LowThrustButton(const char *id_string, const ImVec2 &size_arg, int thrust_level, const ImVec4 &bg_col, int frame_padding, ImColor gauge_fg, ImColor gauge_bg)
|
||||||
|
{
|
||||||
|
PROFILE_SCOPED()
|
||||||
|
std::string label = std::to_string(thrust_level);
|
||||||
|
ImGuiWindow *window = ImGui::GetCurrentWindow();
|
||||||
|
if (window->SkipItems)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
ImGuiContext &g = *GImGui;
|
||||||
|
const ImGuiStyle &style = g.Style;
|
||||||
|
const ImGuiID id = window->GetID(id_string);
|
||||||
|
const ImVec2 label_size = ImGui::CalcTextSize(label.c_str(), NULL, true);
|
||||||
|
|
||||||
|
ImVec2 pos = window->DC.CursorPos;
|
||||||
|
// if ((flags & ImGuiButtonFlags_AlignTextBaseLine) && style.FramePadding.y < window->DC.CurrentLineTextBaseOffset) // Try to vertically align buttons that are smaller/have no padding so that text baseline matches (bit hacky, since it shouldn't be a flag)
|
||||||
|
// pos.y += window->DC.CurrentLineTextBaseOffset - style.FramePadding.y;
|
||||||
|
ImVec2 size = ImGui::CalcItemSize(size_arg, label_size.x + style.FramePadding.x * 2.0f, label_size.y + style.FramePadding.y * 2.0f);
|
||||||
|
|
||||||
|
const ImVec2 padding = (frame_padding >= 0) ? ImVec2(static_cast<float>(frame_padding), static_cast<float>(frame_padding)) : style.FramePadding;
|
||||||
|
const ImRect bb(pos, pos + size + padding * 2);
|
||||||
|
const ImRect inner_bb(pos + padding, pos + padding + size);
|
||||||
|
|
||||||
|
ImGui::ItemSize(bb, style.FramePadding.y);
|
||||||
|
if (!ImGui::ItemAdd(bb, id))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// if (window->DC.ButtonRepeat) flags |= ImGuiButtonFlags_Repeat;
|
||||||
|
bool hovered, held;
|
||||||
|
bool pressed = ImGui::ButtonBehavior(bb, id, &hovered, &held, 0); // flags
|
||||||
|
|
||||||
|
// Render
|
||||||
|
const ImU32 col = ImGui::GetColorU32(static_cast<ImGuiCol>((hovered && held) ? ImGuiCol_ButtonActive : (hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button)));
|
||||||
|
ImGui::RenderFrame(bb.Min, bb.Max, col, true, style.FrameRounding);
|
||||||
|
const ImVec2 center = (inner_bb.Min + inner_bb.Max) / 2;
|
||||||
|
float radius = (inner_bb.Max.x - inner_bb.Min.x) * 0.4;
|
||||||
|
float thickness = 4;
|
||||||
|
ImDrawList *draw_list = ImGui::GetWindowDrawList();
|
||||||
|
if (bg_col.w > 0.0f)
|
||||||
|
draw_list->AddRectFilled(inner_bb.Min, inner_bb.Max, ImGui::GetColorU32(bg_col));
|
||||||
|
|
||||||
|
draw_list->PathArcTo(center, radius, 0, IM_PI * 2, 16);
|
||||||
|
draw_list->PathStroke(gauge_bg, false, thickness);
|
||||||
|
|
||||||
|
draw_list->PathArcTo(center, radius, IM_PI, IM_PI + IM_PI * 2 * (thrust_level / 100.0), 16);
|
||||||
|
draw_list->PathStroke(gauge_fg, false, thickness);
|
||||||
|
ImGui::RenderTextClipped(bb.Min + style.FramePadding, bb.Max - style.FramePadding, label.c_str(), NULL, &label_size, style.ButtonTextAlign, &bb);
|
||||||
|
|
||||||
|
// Automatically close popups
|
||||||
|
//if (pressed && !(flags & ImGuiButtonFlags_DontClosePopups) && (window->Flags & ImGuiWindowFlags_Popup))
|
||||||
|
// CloseCurrentPopup();
|
||||||
|
|
||||||
|
return pressed;
|
||||||
|
}
|
||||||
|
|
||||||
|
// frame_padding < 0: uses FramePadding from style (default)
|
||||||
|
// frame_padding = 0: no framing
|
||||||
|
// frame_padding > 0: set framing size
|
||||||
|
// The color used are the button colors.
|
||||||
|
bool PiGui::ButtonImageSized(ImTextureID user_texture_id, const ImVec2 &size, const ImVec2 &imgSize, const ImVec2 &uv0, const ImVec2 &uv1, int frame_padding, const ImVec4 &bg_col, const ImVec4 &tint_col)
|
||||||
|
{
|
||||||
|
ImGuiWindow *window = ImGui::GetCurrentWindow();
|
||||||
|
if (window->SkipItems)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
ImGuiContext &g = *GImGui;
|
||||||
|
const ImGuiStyle &style = g.Style;
|
||||||
|
|
||||||
|
// Default to using texture ID as ID. User can still push string/integer prefixes.
|
||||||
|
// We could hash the size/uv to create a unique ID but that would prevent the user from animating UV.
|
||||||
|
ImGui::PushID((void *)user_texture_id);
|
||||||
|
const ImGuiID id = window->GetID("#image");
|
||||||
|
ImGui::PopID();
|
||||||
|
|
||||||
|
ImVec2 imgPadding = (size - imgSize) / 2;
|
||||||
|
imgPadding.x = imgPadding.x < 0 || imgSize.x <= 0 ? 0 : imgPadding.x;
|
||||||
|
imgPadding.y = imgPadding.y < 0 || imgSize.y <= 0 ? 0 : imgPadding.y;
|
||||||
|
|
||||||
|
const ImVec2 padding = (frame_padding >= 0) ? ImVec2((float)frame_padding, (float)frame_padding) : style.FramePadding;
|
||||||
|
const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + size + padding * 2);
|
||||||
|
const ImRect image_bb(window->DC.CursorPos + padding + imgPadding, window->DC.CursorPos + padding + size - imgPadding);
|
||||||
|
ImGui::ItemSize(bb);
|
||||||
|
if (!ImGui::ItemAdd(bb, id))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
bool hovered, held;
|
||||||
|
bool pressed = ImGui::ButtonBehavior(bb, id, &hovered, &held);
|
||||||
|
|
||||||
|
// Render
|
||||||
|
const ImU32 col = ImGui::GetColorU32((held && hovered) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button);
|
||||||
|
ImGui::RenderNavHighlight(bb, id);
|
||||||
|
ImGui::RenderFrame(bb.Min, bb.Max, col, true, ImClamp((float)ImMin(padding.x, padding.y), 0.0f, style.FrameRounding));
|
||||||
|
if (bg_col.w > 0.0f)
|
||||||
|
window->DrawList->AddRectFilled(image_bb.Min, image_bb.Max, ImGui::GetColorU32(bg_col));
|
||||||
|
window->DrawList->AddImage(user_texture_id, image_bb.Min, image_bb.Max, uv0, uv1, ImGui::GetColorU32(tint_col));
|
||||||
|
|
||||||
|
return pressed;
|
||||||
|
}
|
|
@ -488,6 +488,7 @@
|
||||||
<ClCompile Include="..\..\src\pigui\PiGuiLua.cpp" />
|
<ClCompile Include="..\..\src\pigui\PiGuiLua.cpp" />
|
||||||
<ClCompile Include="..\..\src\pigui\LuaFace.cpp" />
|
<ClCompile Include="..\..\src\pigui\LuaFace.cpp" />
|
||||||
<ClCompile Include="..\..\src\pigui\PiGuiSandbox.cpp" />
|
<ClCompile Include="..\..\src\pigui\PiGuiSandbox.cpp" />
|
||||||
|
<ClCompile Include="..\..\src\pigui\Widgets.cpp" />
|
||||||
<ClCompile Include="..\..\src\Plane.cpp" />
|
<ClCompile Include="..\..\src\Plane.cpp" />
|
||||||
<ClCompile Include="..\..\src\Planet.cpp" />
|
<ClCompile Include="..\..\src\Planet.cpp" />
|
||||||
<ClCompile Include="..\..\src\Player.cpp" />
|
<ClCompile Include="..\..\src\Player.cpp" />
|
||||||
|
@ -679,10 +680,12 @@
|
||||||
<ClInclude Include="..\..\src\Pi.h" />
|
<ClInclude Include="..\..\src\Pi.h" />
|
||||||
<ClInclude Include="..\..\src\pigui\Face.h" />
|
<ClInclude Include="..\..\src\pigui\Face.h" />
|
||||||
<ClInclude Include="..\..\src\pigui\Image.h" />
|
<ClInclude Include="..\..\src\pigui\Image.h" />
|
||||||
|
<ClInclude Include="..\..\src\pigui\LuaFlags.h" />
|
||||||
<ClInclude Include="..\..\src\pigui\ModelSpinner.h" />
|
<ClInclude Include="..\..\src\pigui\ModelSpinner.h" />
|
||||||
<ClInclude Include="..\..\src\pigui\PerfInfo.h" />
|
<ClInclude Include="..\..\src\pigui\PerfInfo.h" />
|
||||||
<ClInclude Include="..\..\src\pigui\PiGui.h" />
|
<ClInclude Include="..\..\src\pigui\PiGui.h" />
|
||||||
<ClInclude Include="..\..\src\pigui\PiGuiLua.h" />
|
<ClInclude Include="..\..\src\pigui\PiGuiLua.h" />
|
||||||
|
<ClInclude Include="..\..\src\pigui\View.h" />
|
||||||
<ClInclude Include="..\..\src\Plane.h" />
|
<ClInclude Include="..\..\src\Plane.h" />
|
||||||
<ClInclude Include="..\..\src\Planet.h" />
|
<ClInclude Include="..\..\src\Planet.h" />
|
||||||
<ClInclude Include="..\..\src\Player.h" />
|
<ClInclude Include="..\..\src\Player.h" />
|
||||||
|
|
|
@ -561,6 +561,9 @@
|
||||||
<ClCompile Include="..\..\src\core\Application.cpp">
|
<ClCompile Include="..\..\src\core\Application.cpp">
|
||||||
<Filter>src\core</Filter>
|
<Filter>src\core</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\src\pigui\Widgets.cpp">
|
||||||
|
<Filter>src\pigui</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="..\..\src\Aabb.h">
|
<ClInclude Include="..\..\src\Aabb.h">
|
||||||
|
@ -1106,6 +1109,12 @@
|
||||||
<ClInclude Include="..\..\src\core\GuiApplication.h">
|
<ClInclude Include="..\..\src\core\GuiApplication.h">
|
||||||
<Filter>src\core</Filter>
|
<Filter>src\core</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\src\pigui\View.h">
|
||||||
|
<Filter>src\pigui</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\src\pigui\LuaFlags.h">
|
||||||
|
<Filter>src\pigui</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ResourceCompile Include="..\..\src\win32\pioneer.rc">
|
<ResourceCompile Include="..\..\src\win32\pioneer.rc">
|
||||||
|
|
Loading…
Reference in New Issue