diff --git a/.gitignore b/.gitignore index 650b2b9..40e4fa6 100644 --- a/.gitignore +++ b/.gitignore @@ -43,3 +43,10 @@ Thumbs.db steam/content/ steam/output/ steam/steamid\.txt + +linux/.vscode/ +linux/build/ +linux/CMakeFiles/ +linux/cmake_install.cmake +linux/CMakeCache.txt +linux/Makefile diff --git a/libs/glad b/libs/glad index a949664..59febf6 160000 --- a/libs/glad +++ b/libs/glad @@ -1 +1 @@ -Subproject commit a9496640eec1c823315acb8f21df59107224e176 +Subproject commit 59febf6ed6abb284e2f9fb87f27c1789020b9a8c diff --git a/linux/CMakeLists.txt b/linux/CMakeLists.txt new file mode 100644 index 0000000..e56fcdc --- /dev/null +++ b/linux/CMakeLists.txt @@ -0,0 +1,121 @@ +cmake_minimum_required(VERSION 3.4.1) +project(panopainter) + +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14") + +add_executable(panopainter + src/main.cpp + ../libs/glad/src/glad.c + ../libs/glad/src/glad_glx.c + ../libs/yoga/yoga/log.cpp + ../libs/yoga/yoga/Utils.cpp + ../libs/yoga/yoga/YGConfig.cpp + ../libs/yoga/yoga/YGEnums.cpp + ../libs/yoga/yoga/YGLayout.cpp + ../libs/yoga/yoga/YGMarker.cpp + ../libs/yoga/yoga/YGNode.cpp + ../libs/yoga/yoga/YGNodePrint.cpp + ../libs/yoga/yoga/YGStyle.cpp + ../libs/yoga/yoga/YGValue.cpp + ../libs/yoga/yoga/Yoga.cpp + ../libs/tinyxml2/tinyxml2.cpp + ../libs/jpeg/jpgd.cpp + ../libs/jpeg/jpge.cpp + ../libs/poly2tri/poly2tri/common/shapes.cc + ../libs/poly2tri/poly2tri/sweep/advancing_front.cc + ../libs/poly2tri/poly2tri/sweep/cdt.cc + ../libs/poly2tri/poly2tri/sweep/sweep_context.cc + ../libs/poly2tri/poly2tri/sweep/sweep.cc + ../libs/fmt/src/format.cc + ../src/pch.cpp + ../src/util.cpp + ../src/rtt.cpp + ../src/bezier.cpp + ../src/asset.cpp + ../src/image.cpp + ../src/texture.cpp + ../src/font.cpp + ../src/shader.cpp + ../src/shape.cpp + ../src/app.cpp + ../src/app_cloud.cpp + ../src/app_dialogs.cpp + ../src/app_events.cpp + ../src/app_layout.cpp + ../src/app_shaders.cpp + ../src/app_vr.cpp + ../src/brush.cpp + ../src/canvas.cpp + ../src/canvas_layer.cpp + ../src/canvas_actions.cpp + ../src/canvas_modes.cpp + ../src/log.cpp + ../src/action.cpp + ../src/layout.cpp + ../src/version.cpp + ../src/node.cpp + ../src/node_about.cpp + ../src/node_border.cpp + ../src/node_button.cpp + ../src/node_button_custom.cpp + ../src/node_canvas.cpp + ../src/node_checkbox.cpp + ../src/node_color_quad.cpp + ../src/node_colorwheel.cpp + ../src/node_combobox.cpp + ../src/node_changelog.cpp + ../src/node_dialog_browse.cpp + ../src/node_dialog_cloud.cpp + ../src/node_dialog_open.cpp + ../src/node_dialog_picker.cpp + ../src/node_dialog_layer_rename.cpp + ../src/node_dialog_resize.cpp + ../src/node_icon.cpp + ../src/node_image.cpp + ../src/node_image_texture.cpp + ../src/node_message_box.cpp + ../src/node_panel_brush.cpp + ../src/node_panel_color.cpp + ../src/node_panel_grid.cpp + ../src/node_panel_floating.cpp + ../src/node_panel_layer.cpp + ../src/node_panel_stroke.cpp + ../src/node_panel_quick.cpp + ../src/node_popup_menu.cpp + ../src/node_progress_bar.cpp + ../src/node_settings.cpp + ../src/node_slider.cpp + ../src/node_stroke_preview.cpp + ../src/node_text.cpp + ../src/node_text_input.cpp + ../src/node_tool_bucket.cpp + ../src/node_usermanual.cpp + ../src/node_viewport.cpp + ../src/node_scroll.cpp + ../src/abr.cpp + ../src/binary_stream.cpp + ../src/serializer.cpp + ../src/settings.cpp + ../src/node_input_box.cpp + ../src/node_dialog_export_ppbr.cpp +) + +target_include_directories(panopainter PRIVATE + src + ../src + ../libs/glm + ../libs/tinyxml2 + ../libs/yoga + ../libs/stb + ../libs/jpeg + ../libs/poly2tri/poly2tri + ../libs/base64 + ../libs/sqlite3 + ../libs/nanort + ../libs/hash-library + ../libs/fmt/include + ../libs/glad/include +) + +target_link_libraries(panopainter glfw curl GL dl X11 pthread) +target_compile_definitions(panopainter PUBLIC "$<$:_DEBUG>") diff --git a/linux/src/main.cpp b/linux/src/main.cpp new file mode 100644 index 0000000..9f96c96 --- /dev/null +++ b/linux/src/main.cpp @@ -0,0 +1,129 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +static App app; +glm::vec2 g_cursor_pos; + +int mkpath(const std::string& dir, mode_t mode = ALLPERMS) +{ + struct stat sb; + + if (dir.empty()) { + errno = EINVAL; + return 1; + } + + if (!stat(dir.c_str(), &sb)) + return 0; + + mkpath(dirname(strdupa(dir.c_str())), mode); + + int ret = mkdir(dir.c_str(), mode); + if (ret != 0) + LOG("mkdir failed with error %d on %s", errno, dir.c_str()); + return ret; +} + +std::string linux_home_path() +{ + struct passwd *pw = getpwuid(getuid()); + return pw->pw_dir; +} + +void linux_update_fps(int frames) +{ + static char title_fps[512]; + sprintf(title_fps, "PanoPainter - %d fps", frames); + glfwSetWindowTitle(app.glfw_window, title_fps); +} + +void error_log(int code, const char * s) +{ + printf("glfw error: %s", s); +} + +int main(int argc, char** args) +{ + GLFWwindow* wnd = nullptr; + glfwSetErrorCallback(error_log); + if (!glfwInit()) + { + printf("could not initialize glfw\n"); + return 1; + } + + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); + //glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_FORWARD_COMPAT); + + wnd = glfwCreateWindow(800, 600, "PanoPainter", nullptr, nullptr); + if (!wnd) + { + printf("could not create window\n"); + return 1; + } + + glfwSetCursorPosCallback(wnd, [](GLFWwindow* w, double x, double y){ + g_cursor_pos = glm::vec2(x, y); + app.ui_task_async([=]{ + app.mouse_move(x, y, 1.f, kEventSource::Mouse, false); + }); + }); + glfwSetMouseButtonCallback(wnd, [](GLFWwindow* w, int button, int action, int mods){ + app.ui_task_async([=]{ + if (action == GLFW_PRESS) + app.mouse_down(button, g_cursor_pos.x, g_cursor_pos.y, 1.f, kEventSource::Mouse, false); + else if (action == GLFW_RELEASE) + app.mouse_up(button, g_cursor_pos.x, g_cursor_pos.y, kEventSource::Mouse, false); + }); + }); + glfwSetWindowSizeCallback(wnd, [](GLFWwindow* wnd, int width, int height){ + app.ui_task_async([=]{ + app.resize(width, height); + }); + }); + glfwSetWindowCloseCallback(wnd, [](GLFWwindow* wnd){ + app.ui_task([] { + if (!app.request_close()) + glfwSetWindowShouldClose(app.glfw_window, GLFW_FALSE); + }); + }); + + glfwMakeContextCurrent(wnd); + if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) + { + printf("Failed to initialize OpenGL context\n"); + return -1; + } + + printf("GL: %s\n", glGetString(GL_VERSION)); + printf("Renderer: %s\n", glGetString(GL_RENDER)); + printf("Vendor: %s\n", glGetString(GL_VENDOR)); + glfwShowWindow(wnd); + + App::I = &app; + app.initLog(); + app.create(); + app.width = 800; + app.height = 600; + app.glfw_window = wnd; + app.render_thread_start(); + app.ui_thread_start(); + + while (!glfwWindowShouldClose(wnd)) + { + glfwWaitEvents(); + } + + app.ui_thread_stop(); + app.render_thread_stop(); + app.terminate(); + + return 0; +} diff --git a/src/app.cpp b/src/app.cpp index 4f72329..b126558 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -23,6 +23,9 @@ void async_lock(); void win32_async_swap(); void async_unlock(); void destroy_window(); +#elif __LINUX__ +std::string linux_home_path(); +int mkpath(const std::string& dir, mode_t mode = DEFFILEMODE); #endif App* App::I = nullptr; // singleton @@ -131,9 +134,10 @@ bool App::request_close() #ifdef _WIN32 destroy_window(); //PostQuitMessage(0); -#endif -#ifdef __OSX__ +#elif __OSX__ [osx_view close]; +#elif __LINUX__ + glfwSetWindowShouldClose(glfw_window, GLFW_TRUE); #endif Canvas::I->m_unsaved = false; }; @@ -223,6 +227,15 @@ void App::initLog() if (!PathFileExistsA((data_path + "\\settings").c_str())) CreateDirectoryA((data_path + "\\settings").c_str(), NULL); + +#elif __LINUX__ + data_path = linux_home_path() + "/PanoPainter"; + mkpath(data_path + "/brushes"); + mkpath(data_path + "/brushes/thumbs"); + mkpath(data_path + "/patterns"); + mkpath(data_path + "/patterns/thumbs"); + mkpath(data_path + "/settings"); + mkpath(data_path + "/frames"); #endif // TODO: save this path somewhere in the settings, don't overwrite every start @@ -452,6 +465,8 @@ void App::async_start() #elif _WIN32 async_lock(); glBindFramebuffer(GL_FRAMEBUFFER, 0); +#elif __LINUX__ + glfwMakeContextCurrent(glfw_window); #endif } @@ -484,6 +499,8 @@ void App::async_swap() android_async_swap(); #elif _WIN32 win32_async_swap(); +#elif __LINUX__ + glfwSwapBuffers(glfw_window); #endif } @@ -582,7 +599,7 @@ void App::draw(float dt) LOG("rec tick"); rec_timer = 0.f; - auto data = new uint8_t[width * height * 4]; + auto data = new uint8_t[(int)width * (int)height * 4]; #if __IOS__ [ios_view->glview bindDrawable]; #else @@ -913,6 +930,9 @@ void App::ui_thread_main() #ifdef _WIN32 extern void win32_update_fps(int frames); win32_update_fps(rendered_frames); +#elif __LINUX__ + extern void linux_update_fps(int frames); + linux_update_fps(rendered_frames); #endif t_fps_counter = 0; rendered_frames = 0; diff --git a/src/app.h b/src/app.h index eed97c1..1d16046 100644 --- a/src/app.h +++ b/src/app.h @@ -31,6 +31,11 @@ #ifdef __ANDROID__ #include "main.h" #endif + +#ifdef __LINUX__ +#include +#endif + #include "node_panel_grid.h" #include "node_panel_quick.h" #include "node_input_box.h" @@ -147,11 +152,11 @@ public: #if defined(__IOS__) && defined(__OBJC__) GameViewController* ios_view; -#endif - -#if defined(__OSX__) && defined(__OBJC__) +#elif defined(__OSX__) && defined(__OBJC__) View* osx_view; AppOSX* osx_app; +#elif __LINUX__ + GLFWwindow* glfw_window; #endif #ifdef __ANDROID__ diff --git a/src/asset.cpp b/src/asset.cpp index 296ed6d..cd1f04b 100644 --- a/src/asset.cpp +++ b/src/asset.cpp @@ -93,9 +93,7 @@ std::vector Asset::list_files(std::string folder, const std::string std::string abs_path = folder; if (is_asset) { - NSString* bundle_path = [[NSBundle mainBundle] resourcePath]; - std::string base = [bundle_path cStringUsingEncoding : 1]; - abs_path = base + "/" + folder; + abs_path = absolute(folder); } DIR *dp; diff --git a/src/log.h b/src/log.h index 6e7ea00..ef50a03 100644 --- a/src/log.h +++ b/src/log.h @@ -7,7 +7,7 @@ #elif __ANDROID__ #define LOG(...) { ((void)__android_log_print(ANDROID_LOG_INFO, "PanoPainterCPP", __VA_ARGS__)); LogRemote::I.log(__VA_ARGS__); } #define LOGW -#elif _WIN32 +#else #define LOG(M,...) { printf(M"\n", ##__VA_ARGS__); LogRemote::I.log(M, ##__VA_ARGS__); } #define LOGW(M,...) { wprintf(M"\n", ##__VA_ARGS__); LogRemote::I.log(M, ##__VA_ARGS__); } #endif diff --git a/src/pch.h b/src/pch.h index 084f223..483a7c1 100644 --- a/src/pch.h +++ b/src/pch.h @@ -84,6 +84,25 @@ #define PP_OS "win" #define __block +#elif __linux__ + +#ifdef _DEBUG + #define GLAD_DEBUG +#endif + #include + //#include + + #include + #include + #include + + #define __LINUX__ 1 + #define SHADER_VERSION "#version 150\n" + #define PP_OS "linux" + #define __GL__ 1 + #define __block + #define BT_SetTerminate void + #endif #define SIXPLETTE(I) {I, I, I, I, I, I}