440 lines
13 KiB
Objective-C
440 lines
13 KiB
Objective-C
#pragma once
|
|
|
|
#include "log.h"
|
|
#include "shader.h"
|
|
#include "shape.h"
|
|
#include "texture.h"
|
|
#include "layout.h"
|
|
#include "font.h"
|
|
#include "rtt.h"
|
|
#include "image.h"
|
|
#include "mp4enc.h"
|
|
#include "node_message_box.h"
|
|
#include "node_settings.h"
|
|
#include "node_popup_menu.h"
|
|
#include "node_panel_brush.h"
|
|
#include "node_panel_layer.h"
|
|
#include "node_panel_color.h"
|
|
#include "node_panel_stroke.h"
|
|
#include "node_scroll.h"
|
|
#include "node_canvas.h"
|
|
#include "node_dialog_layer_rename.h"
|
|
#include "node_progress_bar.h"
|
|
#include "node_panel_grid.h"
|
|
#include "node_panel_quick.h"
|
|
#include "node_input_box.h"
|
|
#include "node_panel_animation.h"
|
|
|
|
#if defined(__OBJC__) && defined(__IOS__)
|
|
#import <Foundation/Foundation.h>
|
|
#import "GameViewController.h"
|
|
#import "AppDelegate.h"
|
|
#endif
|
|
|
|
#if defined(__OBJC__) && defined(__OSX__)
|
|
#import "main.h"
|
|
#endif
|
|
|
|
#ifdef __ANDROID__
|
|
#include "main.h"
|
|
#endif
|
|
|
|
#ifdef __LINUX__
|
|
#include <GLFW/glfw3.h>
|
|
#endif
|
|
|
|
struct VRController
|
|
{
|
|
enum class kButton : uint8_t
|
|
{
|
|
Pad,
|
|
Trigger,
|
|
Menu,
|
|
Grip,
|
|
A,
|
|
COUNT,
|
|
};
|
|
enum class kAction
|
|
{
|
|
Press,
|
|
Release,
|
|
};
|
|
std::array<bool, (int)kButton::COUNT> m_buttons;
|
|
std::array<bool, (int)kButton::COUNT> m_analog_buttons;
|
|
glm::mat4 m_mat;
|
|
bool m_valid = false;
|
|
glm::vec3 get_pos() const { return m_mat[3]; }
|
|
glm::vec3 get_pos_n() const { return glm::normalize(xyz(m_mat[3])); }
|
|
virtual float get_trigger_value() const { return 1.f; }
|
|
};
|
|
|
|
struct AppTask : public std::packaged_task<void()>
|
|
{
|
|
size_t task_id;
|
|
#ifdef _DEBUG
|
|
std::string name;
|
|
#endif
|
|
template<typename F> AppTask(F f) : std::packaged_task<void()>(f)
|
|
{
|
|
task_id = typeid(f).hash_code();
|
|
#ifdef _DEBUG
|
|
name = typeid(f).name();
|
|
#endif
|
|
}
|
|
};
|
|
|
|
class App
|
|
{
|
|
public:
|
|
static App* I;
|
|
std::string data_path{ "." };
|
|
std::string work_path{ "." };
|
|
std::string rec_path{ "." };
|
|
std::string tmp_path{ "." };
|
|
std::thread rec_thread;
|
|
bool rec_running = false;
|
|
int rec_count = 0;
|
|
std::mutex rec_mutex;
|
|
std::condition_variable rec_cv;
|
|
std::deque<std::unique_ptr<PBO>> rec_frames;
|
|
|
|
RTT uirtt;
|
|
Sampler sampler;
|
|
Sampler sampler_stencil;
|
|
Sampler sampler_linear;
|
|
Plane m_face_plane;
|
|
Sphere sphere;
|
|
LayoutManager layout;
|
|
LayoutManager layout_designer;
|
|
NodeMessageBox* msgbox;
|
|
NodeSettings* settings;
|
|
NodeBorder* sidebar = nullptr;
|
|
std::shared_ptr<NodePanelLayer> layers;
|
|
std::shared_ptr<NodePanelColor> color;
|
|
std::shared_ptr<NodePanelStroke> stroke;
|
|
std::shared_ptr<NodePanelGrid> grid;
|
|
std::shared_ptr<NodePanelBrushPreset> presets;
|
|
std::shared_ptr<NodePanelAnimation> animation;
|
|
NodePanelQuick* quick;
|
|
std::map<kCanvasMode, NodePanelQuick::MiniState> quick_mode_state;
|
|
Node* floatings_container;
|
|
std::shared_ptr<NodePanelColor> floating_color;
|
|
std::shared_ptr<NodeColorPicker> floating_picker;
|
|
std::shared_ptr<NodePanelBrushPreset> floating_presets;
|
|
std::shared_ptr<NodePanelLayer> floating_layers;
|
|
NodeCanvas* canvas;
|
|
const uint16_t main_id = const_hash("main");
|
|
const std::array<int, 6> res_map{ 512, 1024, 1536, 2048, 4096, 8192 };
|
|
const std::array<std::string, 6> res_map_str{ "2K", "4K", "6K", "8K", "16K", "32K" };
|
|
std::string doc_name = "no-name";
|
|
std::string doc_path;
|
|
std::string doc_dir;
|
|
std::string doc_filename;
|
|
bool has_stylus = false;
|
|
bool has_vr = false;
|
|
float off_x = 0;
|
|
float off_y = 0;
|
|
float width;
|
|
float height;
|
|
bool keys[256]{false};
|
|
bool redraw = true;
|
|
bool animate = false;
|
|
bool ui_visible = true;
|
|
bool ui_rtl = false;
|
|
bool vr_active = false;
|
|
bool vr_only = false;
|
|
VRController vr_controllers[2];
|
|
glm::mat4 vr_head;
|
|
float vr_pressure = 1.f;
|
|
glm::mat4 vr_rot{ 0 };
|
|
glm::mat4 vr_uirot{ 0 };
|
|
glm::vec2 cursor{ 0, 0 };
|
|
glm::vec2 gesture_p0;
|
|
glm::vec2 gesture_p1;
|
|
float display_density = 1.f;
|
|
float zoom = 1.f;
|
|
int idle_ms = 100;
|
|
|
|
#if defined(__IOS__) && defined(__OBJC__)
|
|
GameViewController* ios_view;
|
|
AppDelegate* ios_app;
|
|
#elif defined(__OSX__) && defined(__OBJC__)
|
|
View* osx_view;
|
|
AppOSX* osx_app;
|
|
#elif __LINUX__ || __WEB__
|
|
GLFWwindow* glfw_window;
|
|
#endif
|
|
|
|
#ifdef __ANDROID__
|
|
struct android_app* and_app;
|
|
struct engine* and_engine;
|
|
#endif
|
|
std::string clipboard_get_text();
|
|
bool clipboard_set_text(const std::string& s);
|
|
void pick_image(std::function<void(std::string path)> callback);
|
|
void pick_file(std::vector<std::string> types, std::function<void(std::string path)> callback);
|
|
#if __IOS__ || __WEB__
|
|
void pick_file_save(const std::string& type, const std::string& default_name,
|
|
std::function<void(std::string path)> writer, std::function<void(const std::string& path, bool saved)> callback);
|
|
#else
|
|
void pick_file_save(std::vector<std::string> types, std::function<void(std::string path)> callback);
|
|
#endif
|
|
void pick_dir(std::function<void(std::string path)> callback);
|
|
void display_file(std::string path);
|
|
void share_file(std::string path);
|
|
void showKeyboard();
|
|
void hideKeyboard();
|
|
void initLog();
|
|
void init();
|
|
void initShaders();
|
|
void initAssets();
|
|
void initLayout();
|
|
void open_document(std::string path);
|
|
void create();
|
|
bool request_close();
|
|
void terminate();
|
|
void clear();
|
|
void tick(float dt);
|
|
void draw(float dt);
|
|
void update(float dt);
|
|
bool update_ui_observer(Node* n);
|
|
bool vr_start();
|
|
void vr_stop();
|
|
void vr_update(float dt);
|
|
void vr_draw(const glm::mat4& proj, const glm::mat4& view, const glm::mat4& pose);
|
|
void vr_analog(const VRController& c, VRController::kButton b, VRController::kAction a, glm::vec2 force);
|
|
void vr_digital(const VRController& c, VRController::kButton b, VRController::kAction a, glm::vec2 axis);
|
|
void vr_draw_ui();
|
|
void async_start();
|
|
void async_redraw();
|
|
void async_swap();
|
|
void async_end();
|
|
void resize(float w, float h);
|
|
void show_cursor();
|
|
void hide_cursor();
|
|
bool mouse_down(int button, float x, float y, float pressure, kEventSource source, bool eraser);
|
|
bool mouse_move(float x, float y, float pressure, kEventSource source, bool eraser);
|
|
bool mouse_up(int button, float x, float y, kEventSource source, bool eraser);
|
|
bool mouse_scroll(float x, float y, float delta);
|
|
bool mouse_cancel(int button);
|
|
bool gesture_start(const glm::vec2& p0, const glm::vec2& p1);
|
|
bool gesture_move(const glm::vec2& p0, const glm::vec2& p1);
|
|
bool gesture_end();
|
|
bool key_down(kKey key);
|
|
bool key_up(kKey key);
|
|
bool key_char(char key);
|
|
void toggle_ui();
|
|
void set_stylus();
|
|
|
|
void rec_clear();
|
|
void rec_loop();
|
|
void rec_start();
|
|
void rec_stop();
|
|
void rec_export(std::string path);
|
|
|
|
void init_toolbar_main();
|
|
void init_toolbar_draw();
|
|
void init_sidebar();
|
|
void init_menu_file();
|
|
void init_menu_edit();
|
|
void init_menu_layer();
|
|
void init_menu_tools();
|
|
void init_menu_about();
|
|
void dialog_usermanual();
|
|
void dialog_changelog();
|
|
void dialog_about();
|
|
void dialog_newdoc();
|
|
void dialog_save();
|
|
void dialog_save_ver();
|
|
void dialog_open();
|
|
void dialog_browse();
|
|
void dialog_export(std::string ext);
|
|
void dialog_export_layers();
|
|
void dialog_export_depth();
|
|
void dialog_export_cube_faces();
|
|
void dialog_layer_rename();
|
|
void dialog_resize();
|
|
void dialog_preset_download();
|
|
void dialog_ppbr_export();
|
|
void dialog_export_mp4();
|
|
void dialog_timelapse_export();
|
|
|
|
void cloud_upload();
|
|
void cloud_upload_all();
|
|
void cloud_browse();
|
|
void upload(std::string filename, std::string name = "",
|
|
std::function<void(float)> progress = nullptr);
|
|
void download(std::string url, std::string dest_filepath,
|
|
std::function<void(float)> progress = nullptr);
|
|
bool check_license();
|
|
|
|
std::shared_ptr<NodeProgressBar> show_progress(const std::string& title, int total = 0);
|
|
std::shared_ptr<NodeMessageBox> message_box(const std::string& title,
|
|
const std::string& text, bool cancel_button = false);
|
|
std::shared_ptr<NodeInputBox> input_box(const std::string& title,
|
|
const std::string& field_name, const std::string& ok_caption = "Ok");
|
|
|
|
void brush_update(bool update_color, bool update_brush);
|
|
void title_update();
|
|
void update_memory_usage(size_t bytes);
|
|
void update_rec_frames();
|
|
int res_from_index(int i);
|
|
int res_to_index(int res);
|
|
std::string res_to_string(int res);
|
|
void crash_test();
|
|
void stacktrace();
|
|
|
|
void ui_save();
|
|
void ui_restore();
|
|
void set_ui_rtl(bool rtl);
|
|
bool get_ui_rtl() const;
|
|
void set_ui_scale(float scale);
|
|
|
|
void cmd_convert(std::string pano_path, std::string out_path);
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// RENDER THREAD
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
static std::deque<AppTask> render_tasklist;
|
|
static std::mutex render_task_mutex;
|
|
static std::condition_variable render_cv;
|
|
static std::thread render_thread;
|
|
static std::thread::id render_thread_id;
|
|
static bool render_running;
|
|
void render_thread_tick();
|
|
void render_thread_main();
|
|
void render_thread_start();
|
|
void render_thread_stop();
|
|
|
|
bool is_render_thread()
|
|
{
|
|
return std::this_thread::get_id() == render_thread_id;
|
|
}
|
|
|
|
// don't capture a reference to this ptr as the object may be destroyed
|
|
// by the time the task is executed
|
|
template<typename T>
|
|
std::future<void> render_task_async(T task, bool unique = false)
|
|
{
|
|
AppTask pt(task);
|
|
auto f = pt.get_future();
|
|
if (is_render_thread())
|
|
{
|
|
pt();
|
|
}
|
|
else
|
|
{
|
|
{
|
|
std::lock_guard<std::mutex> lock(render_task_mutex);
|
|
// remove any previously queued task from the same lambda
|
|
if (unique && !render_tasklist.empty())
|
|
render_tasklist.erase(std::remove_if(render_tasklist.begin(), render_tasklist.end(),
|
|
[id = pt.task_id](AppTask const& t){ return t.task_id == id; }), render_tasklist.end());
|
|
render_tasklist.push_back(std::move(pt));
|
|
}
|
|
render_cv.notify_all();
|
|
}
|
|
return f;
|
|
}
|
|
|
|
template<typename T>
|
|
void render_task(T task)
|
|
{
|
|
AppTask pt(task);
|
|
auto f = pt.get_future();
|
|
if (is_render_thread())
|
|
{
|
|
pt();
|
|
}
|
|
else
|
|
{
|
|
{
|
|
std::lock_guard<std::mutex> lock(render_task_mutex);
|
|
render_tasklist.push_back(std::move(pt));
|
|
}
|
|
render_cv.notify_all();
|
|
}
|
|
if (render_running)
|
|
f.get();
|
|
}
|
|
|
|
void render_sync()
|
|
{
|
|
render_task([] {});
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// UI THREAD
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
static std::deque<AppTask> ui_tasklist;
|
|
static std::mutex ui_task_mutex;
|
|
static std::condition_variable ui_cv;
|
|
static std::thread ui_thread;
|
|
static std::thread::id ui_thread_id;
|
|
static bool ui_running;
|
|
void ui_thread_tick();
|
|
void ui_thread_main();
|
|
void ui_thread_start();
|
|
void ui_thread_stop();
|
|
|
|
bool is_ui_thread()
|
|
{
|
|
return std::this_thread::get_id() == ui_thread_id;
|
|
}
|
|
|
|
// don't capture a reference to this ptr as the object may be destroyed
|
|
// by the time the task is executed
|
|
template<typename T>
|
|
std::future<void> ui_task_async(T task, bool unique = false)
|
|
{
|
|
AppTask pt(task);
|
|
auto f = pt.get_future();
|
|
if (is_ui_thread())
|
|
{
|
|
pt();
|
|
}
|
|
else
|
|
{
|
|
{
|
|
std::lock_guard<std::mutex> lock(ui_task_mutex);
|
|
// remove any previously queued task from the same lambda
|
|
if (unique && !ui_tasklist.empty())
|
|
ui_tasklist.erase(std::remove_if(ui_tasklist.begin(), ui_tasklist.end(),
|
|
[id = pt.task_id](AppTask const& t){ return t.task_id == id; }), ui_tasklist.end());
|
|
ui_tasklist.push_back(std::move(pt));
|
|
}
|
|
ui_cv.notify_all();
|
|
}
|
|
return f;
|
|
}
|
|
|
|
template<typename T>
|
|
void ui_task(T task)
|
|
{
|
|
AppTask pt(task);
|
|
auto f = pt.get_future();
|
|
if (is_ui_thread())
|
|
{
|
|
pt();
|
|
}
|
|
else
|
|
{
|
|
{
|
|
std::lock_guard<std::mutex> lock(ui_task_mutex);
|
|
ui_tasklist.push_back(std::move(pt));
|
|
}
|
|
ui_cv.notify_all();
|
|
}
|
|
if (ui_running)
|
|
f.get();
|
|
redraw = true;
|
|
}
|
|
|
|
void ui_sync()
|
|
{
|
|
ui_task([] {});
|
|
}
|
|
};
|