From f69fb7299e4c784a0f3e88949929a129c6d06edd Mon Sep 17 00:00:00 2001 From: lisyarus Date: Fri, 28 Aug 2020 11:01:56 +0300 Subject: [PATCH] Add app library --- libs/app/CMakeLists.txt | 8 + libs/app/include/psemek/app/app.hpp | 44 ++++++ libs/app/include/psemek/app/main.hpp | 32 ++++ libs/app/source/app.cpp | 215 +++++++++++++++++++++++++++ libs/gfx/include/psemek/gfx/gl.hpp | 3 + libs/gfx/source/gfx/gl.cpp | 10 ++ todo.md | 2 +- 7 files changed, 313 insertions(+), 1 deletion(-) create mode 100644 libs/app/CMakeLists.txt create mode 100644 libs/app/include/psemek/app/app.hpp create mode 100644 libs/app/include/psemek/app/main.hpp create mode 100644 libs/app/source/app.cpp diff --git a/libs/app/CMakeLists.txt b/libs/app/CMakeLists.txt new file mode 100644 index 00000000..f76ebe55 --- /dev/null +++ b/libs/app/CMakeLists.txt @@ -0,0 +1,8 @@ +find_package(SDL2 REQUIRED) + +file(GLOB_RECURSE PSEMEK_APP_HEADERS RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "include/*.hpp") +file(GLOB_RECURSE PSEMEK_APP_SOURCES RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "source/*.cpp") + +add_library(app ${PSEMEK_APP_HEADERS} ${PSEMEK_APP_SOURCES}) +target_include_directories(app PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" "${SDL2_INCLUDE_DIRS}") +target_link_libraries(app PUBLIC log util gfx ${SDL2_LIBRARIES}) diff --git a/libs/app/include/psemek/app/app.hpp b/libs/app/include/psemek/app/app.hpp new file mode 100644 index 00000000..1fb962c1 --- /dev/null +++ b/libs/app/include/psemek/app/app.hpp @@ -0,0 +1,44 @@ +#pragma once + +#include +#include + +namespace psemek::app +{ + + struct app + : util::pimpl::dynamic + { + app(std::string const & name); + virtual ~app(); + + virtual bool running() const; + + virtual void on_resize(int width, int height); + virtual void on_focus_gained(); + virtual void on_focus_lost(); + virtual void on_quit(); + + virtual void on_mouse_move(int x, int y); + virtual void on_mouse_wheel(int delta); + virtual void on_left_button_down(); + virtual void on_left_button_up(); + virtual void on_middle_button_down(); + virtual void on_middle_button_up(); + virtual void on_right_button_down(); + virtual void on_right_button_up(); + + virtual void on_key_down(SDL_Keycode key); + virtual void on_key_up(SDL_Keycode key); + + void poll_events(); + + virtual void update(); + virtual void draw(); + + void run(); + + void show_cursor(bool show); + }; + +} diff --git a/libs/app/include/psemek/app/main.hpp b/libs/app/include/psemek/app/main.hpp new file mode 100644 index 00000000..6bf5c3c0 --- /dev/null +++ b/libs/app/include/psemek/app/main.hpp @@ -0,0 +1,32 @@ +#pragma once + +#include + +namespace psemek::app +{ + + template + int main() try + { + log::register_thread("main"); + + App app; + + log::info() << "Running"; + app.run(); + log::info() << "Quitting"; + + return EXIT_SUCCESS; + } + catch (std::exception const & e) + { + log::error() << e.what(); + return EXIT_FAILURE; + } + catch (...) + { + log::error() << "unknown exception"; + return EXIT_FAILURE; + } + +} diff --git a/libs/app/source/app.cpp b/libs/app/source/app.cpp new file mode 100644 index 00000000..1bbaeb52 --- /dev/null +++ b/libs/app/source/app.cpp @@ -0,0 +1,215 @@ +#include +#include +#include + +#include + +namespace +{ + + [[noreturn]] void sdl_fail(std::string const & message) + { + throw std::runtime_error(message + SDL_GetError()); + } + + struct sdl_initializer + { + sdl_initializer() + { + if (SDL_Init(SDL_INIT_VIDEO) != 0) + sdl_fail("Failed to initialize SDL2: "); + } + + ~sdl_initializer() + { + SDL_Quit(); + } + }; + +} + +namespace psemek::util::pimpl +{ + + template <> + struct impl + { + sdl_initializer init; + SDL_Window * window = nullptr; + SDL_GLContext gl_context = nullptr; + + bool running = false; + + ~impl() + { + if (gl_context) SDL_GL_DeleteContext(gl_context); + if (window) SDL_DestroyWindow(window); + } + }; + +} + +namespace psemek::app +{ + + + app::app(std::string const & name) + { + SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, gl::sys::GetLeastMajorVersion()); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, gl::sys::GetLeastMinorVersion()); + SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8); + SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8); + SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8); + SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8); + + impl().window = SDL_CreateWindow(name.data(), SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 800, 600, SDL_WINDOW_RESIZABLE | SDL_WINDOW_OPENGL | SDL_WINDOW_MAXIMIZED); + if (!impl().window) + sdl_fail("Failed to create window: "); + + impl().gl_context = SDL_GL_CreateContext(impl().window); + if (!impl().gl_context) + sdl_fail("Failed to create OpenGL context: "); + + SDL_GL_MakeCurrent(impl().window, impl().gl_context); + + if (!gl::sys::LoadFunctions()) + throw std::runtime_error("Failed to load OpenGL functions"); + + log::info() << "Initialized OpenGL " << gl::sys::GetMajorVersion() << '.' << gl::sys::GetMinorVersion(); + } + + app::~app() + {} + + bool app::running() const + { + return impl().running; + } + + void app::on_resize(int width, int height) + { + gl::Viewport(0, 0, width, height); + } + + void app::on_focus_gained() {} + + void app::on_focus_lost() {} + + void app::on_quit() + { + impl().running = false; + } + + void app::on_mouse_move(int, int) {} + + void app::on_mouse_wheel(int) {} + + void app::on_left_button_down() {} + + void app::on_left_button_up() {} + + void app::on_middle_button_down() {} + + void app::on_middle_button_up() {} + + void app::on_right_button_down() {} + + void app::on_right_button_up() {} + + void app::on_key_down(SDL_Keycode) {} + + void app::on_key_up(SDL_Keycode) {} + + void app::poll_events() + { + for (SDL_Event e; SDL_PollEvent(&e);) switch (e.type) + { + case SDL_QUIT: + on_quit(); + break; + case SDL_WINDOWEVENT: switch (e.window.event) + { + case SDL_WINDOWEVENT_RESIZED: + on_resize(e.window.data1, e.window.data2); + break; + case SDL_WINDOWEVENT_FOCUS_GAINED: + on_focus_gained(); + break; + case SDL_WINDOWEVENT_FOCUS_LOST: + on_focus_lost(); + break; + } + break; + case SDL_MOUSEMOTION: + on_mouse_move(e.motion.x, e.motion.y); + break; + case SDL_MOUSEWHEEL: + on_mouse_wheel(e.wheel.y); + break; + case SDL_MOUSEBUTTONDOWN: + switch (e.button.button) + { + case SDL_BUTTON_LEFT: + on_left_button_down(); + break; + case SDL_BUTTON_MIDDLE: + on_middle_button_down(); + break; + case SDL_BUTTON_RIGHT: + on_right_button_down(); + break; + } + break; + case SDL_MOUSEBUTTONUP: + switch (e.button.button) + { + case SDL_BUTTON_LEFT: + on_left_button_up(); + break; + case SDL_BUTTON_MIDDLE: + on_middle_button_up(); + break; + case SDL_BUTTON_RIGHT: + on_right_button_up(); + break; + } + break; + case SDL_KEYDOWN: + on_key_down(e.key.keysym.sym); + break; + case SDL_KEYUP: + on_key_up(e.key.keysym.sym); + break; + } + } + + void app::update() + {} + + void app::draw() + { + gl::ClearColor(0.7f, 0.7f, 1.f, 1.f); + gl::Clear(gl::COLOR_BUFFER_BIT); + } + + void app::run() + { + impl().running = true; + while (running()) + { + poll_events(); + if (!running()) break; + update(); + draw(); + + SDL_GL_SwapWindow(impl().window); + } + } + + void app::show_cursor(bool show) + { + SDL_ShowCursor(show ? SDL_TRUE : SDL_FALSE); + } + +} diff --git a/libs/gfx/include/psemek/gfx/gl.hpp b/libs/gfx/include/psemek/gfx/gl.hpp index 655b61c9..83f0e8ac 100644 --- a/libs/gfx/include/psemek/gfx/gl.hpp +++ b/libs/gfx/include/psemek/gfx/gl.hpp @@ -1732,6 +1732,9 @@ namespace gl { exts::LoadTest LoadFunctions(); + + int GetLeastMinorVersion(); + int GetLeastMajorVersion(); int GetMinorVersion(); int GetMajorVersion(); diff --git a/libs/gfx/source/gfx/gl.cpp b/libs/gfx/source/gfx/gl.cpp index 42f622de..4c8d5a1f 100644 --- a/libs/gfx/source/gfx/gl.cpp +++ b/libs/gfx/source/gfx/gl.cpp @@ -1578,6 +1578,16 @@ namespace gl int numFailed = _detail::LoadCoreFunctions(); return exts::LoadTest(true, numFailed); } + + int GetLeastMinorVersion() + { + return 3; + } + + int GetLeastMajorVersion() + { + return 3; + } static int g_major_version = 0; static int g_minor_version = 0; diff --git a/todo.md b/todo.md index 11698137..e0cd4ff1 100644 --- a/todo.md +++ b/todo.md @@ -1,6 +1,6 @@ * Remove gfx::vertex, setup mesh using attributes directly * Design affine transforms in geom & use them instead of matrices when appropriate -* Create an 'app' module that simplifies application creation * Implement pixmap font rendering * Create a simple generic primive painter * Design ui system +* Add platform deployment tools