diff --git a/CMakeLists.txt b/CMakeLists.txt index 982c2ac6..c9ef8dd2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,11 +14,10 @@ set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake/mod if(NOT DEFINED DAWN_TARGET_SYSTEM) set(DAWN_TARGET_SYSTEM "linux") - # set(DAWN_TARGET_SYSTEM "psp") endif() # Prep cache -set(DAWN_CACHE_TARGET "dusk-target") +set(DAWN_CACHE_TARGET "dawn-target") # Build variables set(DAWN_ROOT_DIR "${CMAKE_SOURCE_DIR}") @@ -30,8 +29,8 @@ set(DAWN_DATA_DIR "${DAWN_ROOT_DIR}/data") set(DAWN_ASSETS_DIR "${DAWN_ROOT_DIR}/assets") set(DAWN_BUILT_ASSETS_DIR "${DAWN_BUILD_DIR}/built_assets" CACHE INTERNAL ${DAWN_CACHE_TARGET}) set(DAWN_GENERATED_HEADERS_DIR "${DAWN_BUILD_DIR}/generated") -set(DAWN_TARGET_NAME "Dusk" CACHE INTERNAL ${DAWN_CACHE_TARGET}) -set(DAWN_BUILD_BINARY ${DAWN_BUILD_DIR}/Dusk CACHE INTERNAL ${DAWN_CACHE_TARGET}) +set(DAWN_TARGET_NAME "Dawn" CACHE INTERNAL ${DAWN_CACHE_TARGET}) +set(DAWN_BUILD_BINARY ${DAWN_BUILD_DIR}/Dawn CACHE INTERNAL ${DAWN_CACHE_TARGET}) set(DAWN_ASSETS "" CACHE INTERNAL ${DAWN_CACHE_TARGET}) # Create directories @@ -64,25 +63,27 @@ add_executable(${DAWN_TARGET_NAME}) if(DAWN_TARGET_SYSTEM STREQUAL "linux") find_package(SDL2 REQUIRED) find_package(OpenGL REQUIRED) - target_link_libraries(${DAWN_TARGET_NAME} PRIVATE - SDL2 - OpenGL::GL - GL + target_link_libraries(${DAWN_TARGET_NAME} + PRIVATE + SDL2 + OpenGL::GL + GL ) elseif(DAWN_TARGET_SYSTEM STREQUAL "psp") find_package(SDL2 REQUIRED) find_package(OpenGL REQUIRED) - target_link_libraries(${DAWN_TARGET_NAME} PUBLIC - ${SDL2_LIBRARIES} - SDL2 - OpenGL::GL - zip - bz2 - z - mbedtls - mbedcrypto - lzma + target_link_libraries(${DAWN_TARGET_NAME} + PUBLIC + ${SDL2_LIBRARIES} + SDL2 + OpenGL::GL + zip + bz2 + z + mbedtls + mbedcrypto + lzma ) target_include_directories(${DAWN_TARGET_NAME} PRIVATE ${SDL2_INCLUDE_DIRS} diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 20a056d4..025d5c5e 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -29,5 +29,21 @@ target_sources(${DAWN_TARGET_NAME} # Subdirs add_subdirectory(assert) add_subdirectory(console) +add_subdirectory(display) add_subdirectory(engine) -add_subdirectory(time) \ No newline at end of file +add_subdirectory(time) + +# Platform-specific settings +if(DAWN_TARGET_SYSTEM STREQUAL "linux") + target_compile_definitions(${DAWN_TARGET_NAME} + PRIVATE + DAWN_SDL2=1 + DAWN_SDL2_GAMEPAD=1 + ) +elseif(DAWN_TARGET_SYSTEM STREQUAL "psp") + target_compile_definitions(${DAWN_TARGET_NAME} + PRIVATE + DAWN_SDL2=1 + DAWN_SDL2_GAMEPAD=1 + ) +endif() \ No newline at end of file diff --git a/src/console/CMakeLists.txt b/src/console/CMakeLists.txt index 8e236bde..09ffc0ad 100644 --- a/src/console/CMakeLists.txt +++ b/src/console/CMakeLists.txt @@ -4,7 +4,7 @@ # https://opensource.org/licenses/MIT # Sources -target_sources(${DUSK_TARGET_NAME} +target_sources(${DAWN_TARGET_NAME} PRIVATE Console.cpp ) \ No newline at end of file diff --git a/src/dawn.hpp b/src/dawn.hpp index 48c024cd..d11645b5 100644 --- a/src/dawn.hpp +++ b/src/dawn.hpp @@ -37,6 +37,14 @@ extern "C" { typedef char char_t; } +#if DAWN_SDL2 + #include + + #define GL_GLEXT_PROTOTYPES + #include + #include +#endif + #include #include #include diff --git a/src/display/CMakeLists.txt b/src/display/CMakeLists.txt new file mode 100644 index 00000000..90611b3a --- /dev/null +++ b/src/display/CMakeLists.txt @@ -0,0 +1,10 @@ +# Copyright (c) 2025 Dominic Masters +# +# This software is released under the MIT License. +# https://opensource.org/licenses/MIT + +# Sources +target_sources(${DAWN_TARGET_NAME} + PRIVATE + Display.cpp +) \ No newline at end of file diff --git a/src/display/Display.cpp b/src/display/Display.cpp new file mode 100644 index 00000000..ba97c46b --- /dev/null +++ b/src/display/Display.cpp @@ -0,0 +1,121 @@ +// Copyright (c) 2025 Dominic Masters +// +// This software is released under the MIT License. +// https://opensource.org/licenses/MIT + +#include "Display.hpp" +#include "engine/Engine.hpp" + +using namespace Dawn; + +Display::Display(void) : + #if DAWN_SDL2 + glContext(nullptr), + window(nullptr) + #endif +{ + #if DAWN_SDL2 + uint32_t flags = SDL_INIT_VIDEO; + #if DAWN_SDL2_GAMEPAD + flags |= SDL_INIT_GAMECONTROLLER | SDL_INIT_JOYSTICK; + #endif + + if(SDL_Init(flags) != 0) { + throw "Failed to initialize SDL2"; + } + + // Set OpenGL Attributes + SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); + + // Create window + this->window = SDL_CreateWindow( + "Dawn", + SDL_WINDOWPOS_CENTERED, + SDL_WINDOWPOS_CENTERED, + DEFAULT_WIDTH, + DEFAULT_HEIGHT, + SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI | + SDL_WINDOW_SHOWN + ); + if(!this->window) { + throw "Failed to create SDL2 window"; + } + + // Create OpenGL context + this->glContext = SDL_GL_CreateContext(this->window); + if(!this->glContext) { + throw "Failed to create OpenGL context"; + } + + // Setup GL + SDL_GL_SetSwapInterval(1);// Enable vsync + glDisable(GL_DEPTH_TEST); + glDisable(GL_CULL_FACE); + glDisable(GL_LIGHTING);// PSP defaults this on? + glShadeModel(GL_SMOOTH);// Fixes color on PSP? + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glPixelStorei(GL_PACK_ALIGNMENT, 1); + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + + glEnableClientState(GL_COLOR_ARRAY);// TODO: every frame on PSP? + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glEnableClientState(GL_VERTEX_ARRAY); + #else + #error "No display platform defined" + #endif +} + +void Display::update(void) { + #if DAWN_SDL2 + SDL_Event event; + while(SDL_PollEvent(&event)) { + switch(event.type) { + case SDL_QUIT: { + Engine::getInstance()->console.exec("exit"); + break; + } + + case SDL_WINDOWEVENT: { + switch(event.window.event) { + case SDL_WINDOWEVENT_CLOSE: { + Engine::getInstance()->console.exec("exit"); + break; + } + + default: { + break; + } + } + break; + } + + default: { + break; + } + } + } + + SDL_GL_MakeCurrent(this->window, this->glContext); + + glViewport(0, 0, DEFAULT_WIDTH, DEFAULT_HEIGHT); + + SDL_GL_SwapWindow(this->window); + #endif +} + +Display::~Display(void) { + #if DAWN_SDL2 + if(this->glContext) { + SDL_GL_DeleteContext(this->glContext); + this->glContext = nullptr; + } + + if(this->window) { + SDL_DestroyWindow(this->window); + this->window = nullptr; + } + + SDL_Quit(); + #endif +} \ No newline at end of file diff --git a/src/display/Display.hpp b/src/display/Display.hpp new file mode 100644 index 00000000..95def75b --- /dev/null +++ b/src/display/Display.hpp @@ -0,0 +1,36 @@ +// Copyright (c) 2025 Dominic Masters +// +// This software is released under the MIT License. +// https://opensource.org/licenses/MIT + +#pragma once +#include "dawn.hpp" + +namespace Dawn { + struct Display { + private: + #if DAWN_SDL2 + SDL_Window* window; + SDL_GLContext glContext; + #endif + + public: + static constexpr uint32_t DEFAULT_WIDTH = 800; + static constexpr uint32_t DEFAULT_HEIGHT = 600; + + /** + * Display constructor + */ + Display(void); + + /** + * Update the display (swap buffers, etc.) + */ + void update(void); + + /** + * Display destructor + */ + ~Display(void); + }; +} \ No newline at end of file diff --git a/src/engine/CMakeLists.txt b/src/engine/CMakeLists.txt index 9970eefb..ccd8a550 100644 --- a/src/engine/CMakeLists.txt +++ b/src/engine/CMakeLists.txt @@ -4,7 +4,7 @@ # https://opensource.org/licenses/MIT # Sources -target_sources(${DUSK_TARGET_NAME} +target_sources(${DAWN_TARGET_NAME} PRIVATE Engine.cpp ) \ No newline at end of file diff --git a/src/engine/Engine.cpp b/src/engine/Engine.cpp index 494630c8..077077c6 100644 --- a/src/engine/Engine.cpp +++ b/src/engine/Engine.cpp @@ -7,25 +7,33 @@ using namespace Dawn; +std::shared_ptr Engine::instance = nullptr; + +std::shared_ptr Engine::getInstance() { + if(!Engine::instance) { + Engine::instance = std::make_shared(); + } + return Engine::instance; +} + Engine::Engine() : time(), - console() + console(), + display() { - // console.registerCommand("echo", [](std::vector &args) { - // if(args.size() == 0) { - // std::cout << "Usage: echo " << std::endl; - // return; - // } + console.registerCommand("exit", [this](std::vector &args) { + this->exitRequested = true; + }); +} - // std::cout << args[0] << std::endl; - // }); - - // console.exec("echo"); +bool_t Engine::isExitRequested() const { + return this->exitRequested; } void Engine::update(void) { time.update(); console.update(); + display.update(); } Engine::~Engine() { diff --git a/src/engine/Engine.hpp b/src/engine/Engine.hpp index 0717aa4e..b2218041 100644 --- a/src/engine/Engine.hpp +++ b/src/engine/Engine.hpp @@ -6,18 +6,39 @@ #pragma once #include "time/Time.hpp" #include "console/Console.hpp" +#include "display/Display.hpp" namespace Dawn { struct Engine { + private: + static std::shared_ptr instance; + + bool_t exitRequested = false; + public: Time time; Console console; + Display display; + + /** + * Get the singleton instance of the engine. + * + * @return A shared pointer to the engine instance. + */ + static std::shared_ptr getInstance(); /** * Constructor for the Dawn engine. */ Engine(); + /** + * Check if an exit has been requested. + * + * @return True if an exit has been requested, false otherwise. + */ + bool_t isExitRequested() const; + /** * Update the engine state. */ diff --git a/src/main.cpp b/src/main.cpp index d78253ee..a187806e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -8,16 +8,12 @@ using namespace Dawn; -static std::shared_ptr engine; - int main(int argc, char **argv) { - engine = std::make_shared(); + auto engine = Engine::getInstance(); - while(1) { + while(!engine->isExitRequested()) { engine->update(); - break; } - engine = nullptr; return 0; } \ No newline at end of file diff --git a/src/time/Time.cpp b/src/time/Time.cpp index 8e9e64e6..a9785f88 100644 --- a/src/time/Time.cpp +++ b/src/time/Time.cpp @@ -20,10 +20,10 @@ Time::Time(void) : void Time::update(void) { float_t delta; - #if TIME_SDL2 + #if DAWN_SDL2 delta = (float_t)SDL_GetTicks() / 1000.0f - this->time; #else - + #error "No time platform defined" #endif this->delta = delta;