diff --git a/.gitignore b/.gitignore index a7458c2..8614a99 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ build/ +build-wasm/ out/ - +.vs/ +.vscode/ diff --git a/.gitmodules b/.gitmodules index f74caa5..c91f338 100644 --- a/.gitmodules +++ b/.gitmodules @@ -2,3 +2,6 @@ path = external/SDL url = https://github.com/libsdl-org/SDL.git branch = release-2.32.x +[submodule "external/glm"] + path = external/glm + url = https://github.com/g-truc/glm.git diff --git a/CMakeLists.txt b/CMakeLists.txt index b444416..1c03a02 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,19 +6,34 @@ set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) # Add src directory -add_executable(PortalGame src/main.cpp) +add_executable(PortalGame + "src/main.cpp" + "src/app.hpp" + "src/app.cpp" + "src/gl.hpp" +) # Platform-specific SDL2 handling -if(EMSCRIPTEN) +if (CMAKE_SYSTEM_NAME STREQUAL Emscripten) + # Emscripten provides SDL2 via its system libraries message(STATUS "Target platform: WebAssembly (Emscripten)") set(CMAKE_EXECUTABLE_SUFFIX ".html") # Optional: build HTML page + + target_compile_options(PortalGame PRIVATE + "-sUSE_SDL=2" + ) + target_link_options(PortalGame PRIVATE "-sUSE_SDL=2" "-sASYNCIFY" - "--preload-file assets" - ) + "-sUSE_WEBGL2=1" + "--shell-file" "${CMAKE_SOURCE_DIR}/shell.html" + "--preload-file" "${CMAKE_SOURCE_DIR}/assets" + ) + else() + message(STATUS "Target platform: Native") # Native platform # find_package(SDL2 REQUIRED) # SDL2 build options to avoid unwanted components @@ -28,4 +43,9 @@ else() add_subdirectory(external/SDL) target_include_directories(PortalGame PRIVATE "external/SDL/include") target_link_libraries(PortalGame PRIVATE SDL2main SDL2-static) + endif() + +add_subdirectory(external/glm) +# target_include_directories(PortalGame PRIVATE "external/glm") +target_link_libraries(PortalGame PRIVATE glm) \ No newline at end of file diff --git a/CMakeUserPresets.json b/CMakeUserPresets.json new file mode 100644 index 0000000..a53a16c --- /dev/null +++ b/CMakeUserPresets.json @@ -0,0 +1,53 @@ +{ + "version": 3, + "cmakeMinimumRequired": { + "major": 3, + "minor": 21, + "patch": 0 + }, + "configurePresets": [ + { + "name": "emscripten", + "displayName": "Emscripten", + "binaryDir": "build-wasm", + "generator": "Ninja Multi-Config", + "toolchainFile": "c:/dev/emsdk/upstream/emscripten/cmake/Modules/Platform/Emscripten.cmake" + }, + { + "name": "VS", + "displayName": "Visual Studio 17 2022", + "description": "Using compilers for Visual Studio 17 2022 (x64 architecture)", + "generator": "Visual Studio 17 2022", + "toolset": "host=x64", + "architecture": "x64", + "binaryDir": "${sourceDir}/out/build/${presetName}", + "cacheVariables": { + "CMAKE_INSTALL_PREFIX": "${sourceDir}/out/install/${presetName}", + "CMAKE_C_COMPILER": "cl.exe", + "CMAKE_CXX_COMPILER": "cl.exe" + } + } + ], + "buildPresets": [ + { + "name": "Emscripten Debug", + "configurePreset": "emscripten", + "configuration": "Debug" + }, + { + "name": "Emscripten Release", + "configurePreset": "emscripten", + "configuration": "Release" + }, + { + "name": "VS Debug", + "configurePreset": "VS", + "configuration": "Debug" + }, + { + "name": "VS Release", + "configurePreset": "VS", + "configuration": "Release" + } + ] +} \ No newline at end of file diff --git a/assets/test.txt b/assets/test.txt new file mode 100644 index 0000000..8318c86 --- /dev/null +++ b/assets/test.txt @@ -0,0 +1 @@ +Test \ No newline at end of file diff --git a/shell.html b/shell.html new file mode 100644 index 0000000..347c9f3 --- /dev/null +++ b/shell.html @@ -0,0 +1,59 @@ + + + + + + PortalGame + + + + + + + + + + + {{{ SCRIPT }}} + + + \ No newline at end of file diff --git a/src/app.cpp b/src/app.cpp new file mode 100644 index 0000000..e36a80e --- /dev/null +++ b/src/app.cpp @@ -0,0 +1,14 @@ +#include "app.hpp" +#include +#include "gl.hpp" + +App::App() +{ +} + +void App::Frame() +{ + glm::vec3 clear_color(glm::abs(glm::sin(m_time)), 0.2f, 0.3f); + glClearColor(clear_color.r, clear_color.g, clear_color.b, 1.0f); + glClear(GL_COLOR_BUFFER_BIT); +} diff --git a/src/app.hpp b/src/app.hpp new file mode 100644 index 0000000..43d5691 --- /dev/null +++ b/src/app.hpp @@ -0,0 +1,15 @@ +#pragma once + +class App +{ + float m_time = 0.0f; + +public: + App(); + + void Frame(); + + void SetTime(float time) { m_time = time; } + +}; + diff --git a/src/gl.hpp b/src/gl.hpp new file mode 100644 index 0000000..157ea48 --- /dev/null +++ b/src/gl.hpp @@ -0,0 +1,3 @@ +#ifdef EMSCRIPTEN +#include +#endif diff --git a/src/main.cpp b/src/main.cpp index 75e3314..3cf8fdf 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,21 +1,134 @@ #include #include +#include +#include "app.hpp" -int main(int argc, char* argv[]) { - if (SDL_Init(SDL_INIT_VIDEO) != 0) { +#ifdef EMSCRIPTEN +#include +#endif + +static SDL_Window *s_window = nullptr; +static SDL_GLContext s_context = nullptr; +static bool s_quit = false; +static std::unique_ptr s_app; + +static bool InitSDL() +{ + if (SDL_Init(SDL_INIT_VIDEO) != 0) + { std::cerr << "SDL_Init Error: " << SDL_GetError() << std::endl; - return 1; + return false; } - SDL_Window* win = SDL_CreateWindow("Hello SDL2", 100, 100, 640, 480, SDL_WINDOW_SHOWN); - if (!win) { + s_window = SDL_CreateWindow("PortalGame", 100, 100, 640, 480, SDL_WINDOW_SHOWN | SDL_WINDOW_MAXIMIZED | SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE); + if (!s_window) + { std::cerr << "SDL_CreateWindow Error: " << SDL_GetError() << std::endl; SDL_Quit(); + return false; + } + + return true; +} + +static bool InitGL() +{ +#ifdef EMSCRIPTEN + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES); +#else + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); +#endif + + s_context = SDL_GL_CreateContext(s_window); + if (!s_context) + { + std::cerr << "SDL_GL_CreateContext Error: " << SDL_GetError() << std::endl; + return false; + } + + // Make context current + if (SDL_GL_MakeCurrent(s_window, s_context) != 0) + { + std::cerr << "SDL_GL_MakeCurrent Error: " << SDL_GetError() << std::endl; + SDL_GL_DeleteContext(s_context); + return false; + } + + return true; +} + +static void ShutdownGL() +{ + if (s_context) + { + SDL_GL_DeleteContext(s_context); + s_context = nullptr; + } +} + +static void ShutdownSDL() +{ + if (s_window) + { + SDL_DestroyWindow(s_window); + s_window = nullptr; + } + SDL_Quit(); +} + +static void PollEvents() +{ + SDL_Event event; + while (SDL_PollEvent(&event)) + { + if (event.type == SDL_QUIT) + { + s_quit = true; + return; + } + } +} + +static void Frame() +{ + Uint32 current_time = SDL_GetTicks(); + s_app->SetTime(current_time / 1000.0f); // Set time in seconds + PollEvents(); + s_app->Frame(); + SDL_GL_SwapWindow(s_window); +} + +int main(int argc, char *argv[]) +{ + if (!InitSDL()) + { return 1; } - SDL_Delay(2000); - SDL_DestroyWindow(win); - SDL_Quit(); + if (!InitGL()) + { + ShutdownSDL(); + return 1; + } + + s_app = std::make_unique(); + +#ifdef EMSCRIPTEN + emscripten_set_main_loop(Frame, 0, true); +#else + while (!s_quit) + { + Frame(); + } + + s_app.reset(); + + ShutdownGL(); + ShutdownSDL(); +#endif return 0; }