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;
}