Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
08796c2f66 |
37
.clang-format
Normal file
@@ -0,0 +1,37 @@
|
||||
---
|
||||
# This configuration requires clang-format 3.8 or higher.
|
||||
Language: Cpp
|
||||
BasedOnStyle: Mozilla
|
||||
AlwaysBreakAfterReturnType: None
|
||||
AlwaysBreakAfterDefinitionReturnType: None
|
||||
BreakConstructorInitializersBeforeComma: false
|
||||
AccessModifierOffset: '0'
|
||||
AlignAfterOpenBracket: Align
|
||||
AlignConsecutiveAssignments: 'true'
|
||||
AlignConsecutiveDeclarations: 'true'
|
||||
AlignEscapedNewlines: Left
|
||||
AlignOperands: 'true'
|
||||
AlignTrailingComments: 'true'
|
||||
AllowAllParametersOfDeclarationOnNextLine: 'false'
|
||||
AllowShortCaseLabelsOnASingleLine: 'false'
|
||||
AllowShortFunctionsOnASingleLine: Empty
|
||||
AllowShortLoopsOnASingleLine: 'false'
|
||||
AlwaysBreakBeforeMultilineStrings: 'false'
|
||||
BreakBeforeBraces: Allman
|
||||
BreakBeforeTernaryOperators: 'true'
|
||||
ColumnLimit: '0'
|
||||
FixNamespaceComments: 'true'
|
||||
IncludeBlocks: Regroup
|
||||
IndentCaseLabels: 'true'
|
||||
IndentPPDirectives: AfterHash
|
||||
IndentWidth: '2'
|
||||
NamespaceIndentation: None
|
||||
PointerAlignment: Right
|
||||
ReflowComments: 'true'
|
||||
SortIncludes: 'true'
|
||||
SortUsingDeclarations: 'true'
|
||||
SpacesBeforeTrailingComments: 5
|
||||
TabWidth: '2'
|
||||
UseTab: Never
|
||||
|
||||
...
|
||||
59
.gitignore
vendored
@@ -1,3 +1,57 @@
|
||||
# ---> C
|
||||
# Prerequisites
|
||||
*.d
|
||||
|
||||
# Object files
|
||||
*.o
|
||||
*.ko
|
||||
*.obj
|
||||
*.elf
|
||||
|
||||
# Linker output
|
||||
*.ilk
|
||||
*.map
|
||||
*.exp
|
||||
|
||||
# Precompiled Headers
|
||||
*.gch
|
||||
*.pch
|
||||
|
||||
# Libraries
|
||||
*.lib
|
||||
*.a
|
||||
*.la
|
||||
*.lo
|
||||
|
||||
# Shared objects (inc. Windows DLLs)
|
||||
*.dll
|
||||
*.so
|
||||
*.so.*
|
||||
*.dylib
|
||||
|
||||
# Executables
|
||||
*.exe
|
||||
*.out
|
||||
*.app
|
||||
*.i*86
|
||||
*.x86_64
|
||||
*.hex
|
||||
|
||||
# Debug files
|
||||
*.dSYM/
|
||||
*.su
|
||||
*.idb
|
||||
*.pdb
|
||||
|
||||
# Kernel Module Compile Results
|
||||
*.mod*
|
||||
*.cmd
|
||||
.tmp_versions/
|
||||
modules.order
|
||||
Module.symvers
|
||||
Mkfile.old
|
||||
dkms.conf
|
||||
|
||||
# ---> C++
|
||||
# Prerequisites
|
||||
*.d
|
||||
@@ -31,4 +85,9 @@
|
||||
*.exe
|
||||
*.out
|
||||
*.app
|
||||
build/
|
||||
|
||||
# Editor's mess
|
||||
.vscode/
|
||||
.vs/
|
||||
|
||||
|
||||
288
CMakeLists.txt
Normal file
@@ -0,0 +1,288 @@
|
||||
cmake_minimum_required (VERSION 3.23)
|
||||
|
||||
#--- v1.0.0 ---
|
||||
#------------------------------------------------
|
||||
#--- Setup compiler settings ---
|
||||
#------------------------------------------------
|
||||
# Set C language standard
|
||||
set(CMAKE_C_STANDARD 17)
|
||||
set(CMAKE_C_STANDARD_REQUIRED ON)
|
||||
set(CMAKE_C_EXTENSIONS OFF) # Only standard features, no compiler-specific extensions
|
||||
|
||||
# Set C++ language standard
|
||||
set(CMAKE_CXX_STANDARD 23)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
set(CMAKE_CXX_EXTENSIONS OFF) # Only standard features, no compiler-specific extensions
|
||||
|
||||
|
||||
#------------------------------------------------
|
||||
#--- Project configuration ---
|
||||
#------------------------------------------------
|
||||
# Define the project settings
|
||||
project("quokkaNoid")
|
||||
|
||||
# Source directory
|
||||
set(SRC_DIR "src")
|
||||
|
||||
# Resource files (add resource files here if needed)
|
||||
set(RESOURCE_FILES "")
|
||||
|
||||
#------------------------------------------------
|
||||
#--- Sanity checks ---
|
||||
#------------------------------------------------
|
||||
# Ensure build type is set (Debug, Release, etc.)
|
||||
if(NOT CMAKE_BUILD_TYPE)
|
||||
message(FATAL_ERROR "CMAKE_BUILD_TYPE must be set")
|
||||
endif()
|
||||
|
||||
# Ensure DEV_LIB environment variable is defined (used for external libraries)
|
||||
if(NOT DEFINED ENV{DEV_LIB})
|
||||
message(FATAL_ERROR "DEV_LIB environment variable must be defined")
|
||||
endif()
|
||||
set(DEV_LIB $ENV{DEV_LIB})
|
||||
|
||||
|
||||
#------------------------------------------------
|
||||
#--- Include directories ---
|
||||
#------------------------------------------------
|
||||
# General include directories (add your common include paths here)
|
||||
set(GENERAL_INCLUDE_DIRS
|
||||
"src"
|
||||
"sdi_toolBox_1.0.x"
|
||||
"${DEV_LIB}/boost_1_87_0"
|
||||
"${DEV_LIB}/SDL2/SDL2-2.30.4/include"
|
||||
)
|
||||
|
||||
# Additional include directories for Debug configuration
|
||||
set(DEBUG_INCLUDE_DIRS
|
||||
# "path/to/debug/include"
|
||||
)
|
||||
|
||||
# Additional include directories for Release configuration
|
||||
set(RELEASE_INCLUDE_DIRS
|
||||
# "path/to/debug/include"
|
||||
)
|
||||
|
||||
|
||||
#------------------------------------------------
|
||||
#--- Library directories ---
|
||||
#------------------------------------------------
|
||||
# General library directories (add your common library paths here)
|
||||
set(GENERAL_LIBRARY_DIRS
|
||||
${CMAKE_BINARY_DIR}
|
||||
"${DEV_LIB}/boost_1_87_0/stage/lib"
|
||||
"${DEV_LIB}/SDL2/SDL2-2.30.4/lib/x64"
|
||||
)
|
||||
|
||||
# Additional library directories for Debug configuration
|
||||
set(DEBUG_LIBRARY_DIRS
|
||||
# "path/to/debug/lib"
|
||||
)
|
||||
|
||||
# Additional library directories for Release configuration
|
||||
set(RELEASE_LIBRARY_DIRS
|
||||
# "path/to/debug/lib"
|
||||
)
|
||||
|
||||
|
||||
#------------------------------------------------
|
||||
#--- Preprocessor definitions ---
|
||||
#------------------------------------------------
|
||||
# General preprocessor definitions (add your common defines here)
|
||||
set(GENERAL_PREPROCESSOR_DEFINITIONS
|
||||
"_CRT_SECURE_NO_DEPRECATE"
|
||||
"_CRT_NONSTDC_NO_DEPRECATE"
|
||||
"_UNICODE"
|
||||
"_WINDOWS"
|
||||
"NOMINMAX"
|
||||
"UNICODE"
|
||||
"WIN32"
|
||||
"WIN32_LEAN_AND_MEAN"
|
||||
|
||||
#"SDL_STATIC"
|
||||
)
|
||||
|
||||
# Additional preprocessor definitions for Debug configuration
|
||||
set(DEBUG_PREPROCESSOR_DEFINITIONS
|
||||
"_DEBUG"
|
||||
"DEBUG"
|
||||
"WXDEBUG"
|
||||
)
|
||||
|
||||
# Additional preprocessor definitions for Release configuration
|
||||
set(RELEASE_PREPROCESSOR_DEFINITIONS
|
||||
"NDEBUG"
|
||||
)
|
||||
|
||||
|
||||
#------------------------------------------------
|
||||
#--- Libraries and DLLs ---
|
||||
#------------------------------------------------
|
||||
# General libraries to link (add your common libraries here)
|
||||
set(GENERAL_LIB
|
||||
"SDL2main.lib"
|
||||
"SDL2.lib"
|
||||
"SDL2_image.lib"
|
||||
"SDL2_ttf.lib"
|
||||
)
|
||||
|
||||
# Additional libraries for Debug configuration
|
||||
set(DEBUG_LIB
|
||||
# "libDebug.lib"
|
||||
)
|
||||
|
||||
# Additional libraries for Release configuration
|
||||
set(RELEASE_LIB
|
||||
# "libRelease.lib"
|
||||
)
|
||||
|
||||
# General DLLs to copy after build (add your common DLLs here)
|
||||
set(GENERAL_BIN
|
||||
"${DEV_LIB}/SDL2/SDL2-2.30.4/lib/x64/SDL2.dll"
|
||||
"${DEV_LIB}/SDL2/SDL2-2.30.4/lib/x64/SDL2_image.dll"
|
||||
"${DEV_LIB}/SDL2/SDL2-2.30.4/lib/x64/SDL2_ttf.dll"
|
||||
)
|
||||
|
||||
# Additional DLLs for Debug configuration
|
||||
set(DEBUG_BIN
|
||||
# "path/to/debug/dll"
|
||||
)
|
||||
|
||||
# Additional DLLs for Release configuration
|
||||
set(RELEASE_BIN
|
||||
# "path/to/release/dll"
|
||||
)
|
||||
|
||||
|
||||
#------------------------------------------------
|
||||
#--- MSVC Debug Information Format Policy ---
|
||||
#------------------------------------------------
|
||||
# Ensure CMake policy CMP0141 is set to NEW to control the MSVC debug information format.
|
||||
# This sets CMAKE_MSVC_DEBUG_INFORMATION_FORMAT to "EditAndContinue" for Debug and RelWithDebInfo configurations,
|
||||
# and to "ProgramDatabase" for other configurations, but only when using the MSVC compiler.
|
||||
if (POLICY CMP0141)
|
||||
cmake_policy(SET CMP0141 NEW)
|
||||
set(CMAKE_MSVC_DEBUG_INFORMATION_FORMAT "$<IF:$<AND:$<C_COMPILER_ID:MSVC>,$<CXX_COMPILER_ID:MSVC>>,$<$<CONFIG:Debug,RelWithDebInfo>:EditAndContinue>,$<$<CONFIG:Debug,RelWithDebInfo>:ProgramDatabase>>")
|
||||
endif()
|
||||
|
||||
|
||||
#------------------------------------------------
|
||||
#--- Source files gathering ---
|
||||
#------------------------------------------------
|
||||
# Collect all C and C++ source files recursively
|
||||
file(GLOB_RECURSE SOURCES_C "${SRC_DIR}/*.c")
|
||||
file(GLOB_RECURSE SOURCES_CPP "${SRC_DIR}/*.cpp")
|
||||
|
||||
|
||||
#------------------------------------------------
|
||||
#--- Target definition ---
|
||||
#------------------------------------------------
|
||||
# Define the main executable target
|
||||
add_executable(${PROJECT_NAME}
|
||||
${SOURCES_C}
|
||||
${SOURCES_CPP}
|
||||
${RESOURCE_FILES}
|
||||
)
|
||||
|
||||
|
||||
#------------------------------------------------
|
||||
#--- Target properties setup ---
|
||||
#------------------------------------------------
|
||||
# Setup include directories
|
||||
target_include_directories(${PROJECT_NAME} PRIVATE
|
||||
${GENERAL_INCLUDE_DIRS}
|
||||
$<$<CONFIG:Debug>:${DEBUG_INCLUDE_DIRS}>
|
||||
$<$<CONFIG:Release>:${RELEASE_INCLUDE_DIRS}>
|
||||
)
|
||||
|
||||
# Setup library directories
|
||||
target_link_directories(${PROJECT_NAME} PRIVATE
|
||||
${GENERAL_LIBRARY_DIRS}
|
||||
$<$<CONFIG:Debug>:${DEBUG_LIBRARY_DIRS}>
|
||||
$<$<CONFIG:Release>:${RELEASE_LIBRARY_DIRS}>
|
||||
)
|
||||
|
||||
# Setup preprocessor definitions
|
||||
target_compile_definitions(${PROJECT_NAME} PRIVATE
|
||||
${GENERAL_PREPROCESSOR_DEFINITIONS}
|
||||
$<$<CONFIG:Debug>:${DEBUG_PREPROCESSOR_DEFINITIONS}>
|
||||
$<$<CONFIG:Release>:${RELEASE_PREPROCESSOR_DEFINITIONS}>
|
||||
)
|
||||
|
||||
# Setup linked libraries
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE
|
||||
${GENERAL_LIB}
|
||||
$<$<CONFIG:Debug>:${DEBUG_LIB}>
|
||||
$<$<CONFIG:Release>:${RELEASE_LIB}>
|
||||
)
|
||||
|
||||
# Setup compiler and linker options (MSVC specific)
|
||||
if(MSVC)
|
||||
target_compile_options(${PROJECT_NAME} PRIVATE /MP)
|
||||
target_link_options(${PROJECT_NAME} PRIVATE "/ignore:4099" /PROFILE)
|
||||
endif()
|
||||
|
||||
|
||||
#------------------------------------------------
|
||||
#--- Post-build: Copy DLLs ---
|
||||
#------------------------------------------------
|
||||
# Copy DLLs to the output directory after build
|
||||
if(GENERAL_BIN OR DEBUG_BIN OR RELEASE_BIN)
|
||||
add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
||||
${GENERAL_BIN}
|
||||
$<$<CONFIG:Debug>:${DEBUG_BIN}>
|
||||
$<$<CONFIG:Release>:${RELEASE_BIN}>
|
||||
${CMAKE_BINARY_DIR}
|
||||
)
|
||||
endif()
|
||||
|
||||
|
||||
#------------------------------------------------
|
||||
#--- Project compilation log ---
|
||||
#------------------------------------------------
|
||||
# Print project and environment information for diagnostics
|
||||
message(STATUS "---------------------------------------------------")
|
||||
message(STATUS "---------------------------------------------------")
|
||||
message(STATUS "---------------------------------------------------")
|
||||
message(STATUS "--- Platform Information --------------------------")
|
||||
message(STATUS "System Name: ${CMAKE_SYSTEM_NAME}")
|
||||
message(STATUS "Processor: ${CMAKE_SYSTEM_PROCESSOR}")
|
||||
message(STATUS "CMake Generator: ${CMAKE_GENERATOR}")
|
||||
message(STATUS "Install Prefix: ${CMAKE_INSTALL_PREFIX}")
|
||||
message(STATUS "---------------------------------------------------")
|
||||
message(STATUS "--- Compiler/Language Settings --------------------")
|
||||
message(STATUS "C++ Standard: ${CMAKE_CXX_STANDARD}")
|
||||
message(STATUS "Compiler ID: ${CMAKE_CXX_COMPILER_ID}")
|
||||
message(STATUS "Build Type: ${CMAKE_BUILD_TYPE}")
|
||||
message(STATUS "Common Compiler Flags: ${CMAKE_CXX_FLAGS}")
|
||||
message(STATUS "Debug Compiler Flags: ${CMAKE_CXX_FLAGS_DEBUG}")
|
||||
message(STATUS "Release Compiler Flags: ${CMAKE_CXX_FLAGS_RELEASE}")
|
||||
message(STATUS "Common Linker Flags: ${CMAKE_EXE_LINKER_FLAGS}")
|
||||
message(STATUS "Debug Linker Flags: ${CMAKE_EXE_LINKER_FLAGS_DEBUG}")
|
||||
message(STATUS "Release Linker Flags: ${CMAKE_EXE_LINKER_FLAGS_RELEASE}")
|
||||
message(STATUS "---------------------------------------------------")
|
||||
message(STATUS "--- Path Information ------------------------------")
|
||||
message(STATUS "Source Dir: ${CMAKE_CURRENT_SOURCE_DIR}")
|
||||
message(STATUS "Binary Dir: ${CMAKE_CURRENT_BINARY_DIR}")
|
||||
if(MSVC)
|
||||
message(STATUS "---------------------------------------------------")
|
||||
message(STATUS "--- Microsoft Visual C++ (MSVC) Information -------")
|
||||
# Check the major compiler version
|
||||
if(MSVC_VERSION GREATER_EQUAL 1950)
|
||||
message(STATUS "MSVC Compiler Version: ${MSVC_VERSION} (Visual Studio 2026 or newer)")
|
||||
elseif(MSVC_VERSION GREATER_EQUAL 1930)
|
||||
message(STATUS "MSVC Compiler Version: ${MSVC_VERSION} (Visual Studio 2022)")
|
||||
endif()
|
||||
message(STATUS "MSVC Toolset Version: ${MSVC_TOOLSET_VERSION}")
|
||||
message(STATUS "CPP Compiler Version: ${CMAKE_CXX_COMPILER_VERSION}")
|
||||
message(STATUS "C Compiler Version: ${CMAKE_C_COMPILER_VERSION}")
|
||||
endif()
|
||||
message(STATUS "---------------------------------------------------")
|
||||
message(STATUS "--- Project Information ---------------------------")
|
||||
message(STATUS "Project Name: ${PROJECT_NAME}")
|
||||
message(STATUS "Preset Name: ${PRESET_NAME}")
|
||||
message(STATUS "---------------------------------------------------")
|
||||
message(STATUS "---------------------------------------------------")
|
||||
message(STATUS "---------------------------------------------------")
|
||||
|
||||
43
CMakePresets.json
Normal file
@@ -0,0 +1,43 @@
|
||||
{
|
||||
"version": 3,
|
||||
"configurePresets": [
|
||||
{
|
||||
"name": "windows-base",
|
||||
"hidden": true,
|
||||
"generator": "Ninja",
|
||||
"binaryDir": "${sourceDir}/out/build/${presetName}",
|
||||
"installDir": "${sourceDir}/out/install/${presetName}",
|
||||
"cacheVariables": {
|
||||
"CMAKE_C_COMPILER": "cl.exe",
|
||||
"CMAKE_CXX_COMPILER": "cl.exe"
|
||||
},
|
||||
"condition": {
|
||||
"type": "equals",
|
||||
"lhs": "${hostSystemName}",
|
||||
"rhs": "Windows"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "x64-debug",
|
||||
"displayName": "x64 Debug",
|
||||
"inherits": "windows-base",
|
||||
"architecture": {
|
||||
"value": "x64",
|
||||
"strategy": "external"
|
||||
},
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": "Debug",
|
||||
"PRESET_NAME": "x64 Debug"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "x64-release",
|
||||
"displayName": "x64 Release",
|
||||
"inherits": "x64-debug",
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": "Release",
|
||||
"PRESET_NAME": "x64 Release"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
BIN
assets/Breakout Tile Set Free/.DS_Store
vendored
Normal file
15
assets/Breakout Tile Set Free/License.txt
Normal file
@@ -0,0 +1,15 @@
|
||||
|
||||
|
||||
Breakout Game Tile Set Free
|
||||
|
||||
From ImagineLabs.Rocks
|
||||
|
||||
------------------------------
|
||||
|
||||
These game assets are being released under the license (Creative Commons Zero, CC0) http://creativecommons.org/publicdomain/zero/1.0/
|
||||
|
||||
You may use these assets in personal and commercial projects.
|
||||
|
||||
------------------------------
|
||||
|
||||
Visit our site http://www.imaginelabs.rocks for more great game assets.
|
||||
BIN
assets/Breakout Tile Set Free/PNG/01-Breakout-Tiles.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
assets/Breakout Tile Set Free/PNG/02-Breakout-Tiles.png
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
assets/Breakout Tile Set Free/PNG/03-Breakout-Tiles.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
assets/Breakout Tile Set Free/PNG/04-Breakout-Tiles.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
assets/Breakout Tile Set Free/PNG/05-Breakout-Tiles.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
assets/Breakout Tile Set Free/PNG/06-Breakout-Tiles.png
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
assets/Breakout Tile Set Free/PNG/07-Breakout-Tiles.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
assets/Breakout Tile Set Free/PNG/08-Breakout-Tiles.png
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
assets/Breakout Tile Set Free/PNG/09-Breakout-Tiles.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
assets/Breakout Tile Set Free/PNG/10-Breakout-Tiles.png
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
assets/Breakout Tile Set Free/PNG/11-Breakout-Tiles.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
assets/Breakout Tile Set Free/PNG/12-Breakout-Tiles.png
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
assets/Breakout Tile Set Free/PNG/13-Breakout-Tiles.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
assets/Breakout Tile Set Free/PNG/14-Breakout-Tiles.png
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
assets/Breakout Tile Set Free/PNG/15-Breakout-Tiles.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
assets/Breakout Tile Set Free/PNG/16-Breakout-Tiles.png
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
assets/Breakout Tile Set Free/PNG/17-Breakout-Tiles.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
assets/Breakout Tile Set Free/PNG/18-Breakout-Tiles.png
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
assets/Breakout Tile Set Free/PNG/19-Breakout-Tiles.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
assets/Breakout Tile Set Free/PNG/20-Breakout-Tiles.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
assets/Breakout Tile Set Free/PNG/21-Breakout-Tiles.png
Normal file
|
After Width: | Height: | Size: 6.6 KiB |
BIN
assets/Breakout Tile Set Free/PNG/22-Breakout-Tiles.png
Normal file
|
After Width: | Height: | Size: 6.6 KiB |
BIN
assets/Breakout Tile Set Free/PNG/23-Breakout-Tiles.png
Normal file
|
After Width: | Height: | Size: 6.7 KiB |
BIN
assets/Breakout Tile Set Free/PNG/24-Breakout-Tiles.png
Normal file
|
After Width: | Height: | Size: 6.6 KiB |
BIN
assets/Breakout Tile Set Free/PNG/25-Breakout-Tiles.png
Normal file
|
After Width: | Height: | Size: 6.7 KiB |
BIN
assets/Breakout Tile Set Free/PNG/26-Breakout-Tiles.png
Normal file
|
After Width: | Height: | Size: 6.7 KiB |
BIN
assets/Breakout Tile Set Free/PNG/27-Breakout-Tiles.png
Normal file
|
After Width: | Height: | Size: 6.6 KiB |
BIN
assets/Breakout Tile Set Free/PNG/28-Breakout-Tiles.png
Normal file
|
After Width: | Height: | Size: 6.7 KiB |
BIN
assets/Breakout Tile Set Free/PNG/29-Breakout-Tiles.png
Normal file
|
After Width: | Height: | Size: 6.5 KiB |
BIN
assets/Breakout Tile Set Free/PNG/30-Breakout-Tiles.png
Normal file
|
After Width: | Height: | Size: 6.6 KiB |
BIN
assets/Breakout Tile Set Free/PNG/31-Breakout-Tiles.png
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
assets/Breakout Tile Set Free/PNG/32-Breakout-Tiles.png
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
assets/Breakout Tile Set Free/PNG/33-Breakout-Tiles.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
assets/Breakout Tile Set Free/PNG/34-Breakout-Tiles.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
assets/Breakout Tile Set Free/PNG/35-Breakout-Tiles.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
assets/Breakout Tile Set Free/PNG/36-Breakout-Tiles.png
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
assets/Breakout Tile Set Free/PNG/37-Breakout-Tiles.png
Normal file
|
After Width: | Height: | Size: 9.5 KiB |
BIN
assets/Breakout Tile Set Free/PNG/38-Breakout-Tiles.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
assets/Breakout Tile Set Free/PNG/39-Breakout-Tiles.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
assets/Breakout Tile Set Free/PNG/40-Breakout-Tiles.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
assets/Breakout Tile Set Free/PNG/41-Breakout-Tiles.png
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
assets/Breakout Tile Set Free/PNG/42-Breakout-Tiles.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
assets/Breakout Tile Set Free/PNG/43-Breakout-Tiles.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
assets/Breakout Tile Set Free/PNG/44-Breakout-Tiles.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
assets/Breakout Tile Set Free/PNG/45-Breakout-Tiles.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
assets/Breakout Tile Set Free/PNG/46-Breakout-Tiles.png
Normal file
|
After Width: | Height: | Size: 10 KiB |
BIN
assets/Breakout Tile Set Free/PNG/47-Breakout-Tiles.png
Normal file
|
After Width: | Height: | Size: 10 KiB |
BIN
assets/Breakout Tile Set Free/PNG/48-Breakout-Tiles.png
Normal file
|
After Width: | Height: | Size: 9.7 KiB |
BIN
assets/Breakout Tile Set Free/PNG/49-Breakout-Tiles.png
Normal file
|
After Width: | Height: | Size: 8.9 KiB |
BIN
assets/Breakout Tile Set Free/PNG/50-Breakout-Tiles.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
assets/Breakout Tile Set Free/PNG/51-Breakout-Tiles.png
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
assets/Breakout Tile Set Free/PNG/52-Breakout-Tiles.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
assets/Breakout Tile Set Free/PNG/53-Breakout-Tiles.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
assets/Breakout Tile Set Free/PNG/54-Breakout-Tiles.png
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
assets/Breakout Tile Set Free/PNG/55-Breakout-Tiles.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
assets/Breakout Tile Set Free/PNG/56-Breakout-Tiles.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
assets/Breakout Tile Set Free/PNG/57-Breakout-Tiles.png
Normal file
|
After Width: | Height: | Size: 8.5 KiB |
BIN
assets/Breakout Tile Set Free/PNG/58-Breakout-Tiles.png
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
assets/Breakout Tile Set Free/PNG/59-Breakout-Tiles.png
Normal file
|
After Width: | Height: | Size: 9.3 KiB |
BIN
assets/Breakout Tile Set Free/PNG/60-Breakout-Tiles.png
Normal file
|
After Width: | Height: | Size: 8.0 KiB |
BIN
assets/Breakout Tile Set Free/PNG/61-Breakout-Tiles.png
Normal file
|
After Width: | Height: | Size: 3.9 KiB |
|
After Width: | Height: | Size: 346 KiB |
@@ -0,0 +1,63 @@
|
||||
<TextureAtlas imagePath="Breakout_Tile_Free.png">
|
||||
<SubTexture name="01-Breakout-Tiles.png" x="772" y="390" width="384" height="128"/>
|
||||
<SubTexture name="02-Breakout-Tiles.png" x="0" y="0" width="384" height="128"/>
|
||||
<SubTexture name="03-Breakout-Tiles.png" x="0" y="130" width="384" height="128"/>
|
||||
<SubTexture name="04-Breakout-Tiles.png" x="0" y="260" width="384" height="128"/>
|
||||
<SubTexture name="05-Breakout-Tiles.png" x="0" y="390" width="384" height="128"/>
|
||||
<SubTexture name="06-Breakout-Tiles.png" x="0" y="520" width="384" height="128"/>
|
||||
<SubTexture name="07-Breakout-Tiles.png" x="772" y="260" width="384" height="128"/>
|
||||
<SubTexture name="08-Breakout-Tiles.png" x="772" y="130" width="384" height="128"/>
|
||||
<SubTexture name="09-Breakout-Tiles.png" x="772" y="0" width="384" height="128"/>
|
||||
<SubTexture name="10-Breakout-Tiles.png" x="772" y="650" width="384" height="128"/>
|
||||
<SubTexture name="11-Breakout-Tiles.png" x="386" y="650" width="384" height="128"/>
|
||||
<SubTexture name="12-Breakout-Tiles.png" x="386" y="520" width="384" height="128"/>
|
||||
<SubTexture name="13-Breakout-Tiles.png" x="386" y="390" width="384" height="128"/>
|
||||
<SubTexture name="14-Breakout-Tiles.png" x="386" y="260" width="384" height="128"/>
|
||||
<SubTexture name="15-Breakout-Tiles.png" x="386" y="130" width="384" height="128"/>
|
||||
<SubTexture name="16-Breakout-Tiles.png" x="386" y="0" width="384" height="128"/>
|
||||
<SubTexture name="17-Breakout-Tiles.png" x="772" y="520" width="384" height="128"/>
|
||||
<SubTexture name="18-Breakout-Tiles.png" x="0" y="650" width="384" height="128"/>
|
||||
<SubTexture name="19-Breakout-Tiles.png" x="386" y="780" width="384" height="128"/>
|
||||
<SubTexture name="20-Breakout-Tiles.png" x="0" y="780" width="384" height="128"/>
|
||||
<SubTexture name="21-Breakout-Tiles.png" x="1533" y="392" width="128" height="128"/>
|
||||
<SubTexture name="22-Breakout-Tiles.png" x="1403" y="132" width="128" height="128"/>
|
||||
<SubTexture name="23-Breakout-Tiles.png" x="1403" y="262" width="128" height="128"/>
|
||||
<SubTexture name="24-Breakout-Tiles.png" x="1403" y="392" width="128" height="128"/>
|
||||
<SubTexture name="25-Breakout-Tiles.png" x="1403" y="522" width="128" height="128"/>
|
||||
<SubTexture name="26-Breakout-Tiles.png" x="1507" y="652" width="128" height="128"/>
|
||||
<SubTexture name="27-Breakout-Tiles.png" x="1533" y="132" width="128" height="128"/>
|
||||
<SubTexture name="28-Breakout-Tiles.png" x="1533" y="262" width="128" height="128"/>
|
||||
<SubTexture name="29-Breakout-Tiles.png" x="1574" y="782" width="128" height="128"/>
|
||||
<SubTexture name="30-Breakout-Tiles.png" x="1533" y="522" width="128" height="128"/>
|
||||
<SubTexture name="31-Breakout-Tiles.png" x="1403" y="66" width="243" height="64"/>
|
||||
<SubTexture name="32-Breakout-Tiles.png" x="1158" y="0" width="243" height="64"/>
|
||||
<SubTexture name="33-Breakout-Tiles.png" x="1084" y="912" width="243" height="64"/>
|
||||
<SubTexture name="34-Breakout-Tiles.png" x="1084" y="846" width="243" height="64"/>
|
||||
<SubTexture name="35-Breakout-Tiles.png" x="1017" y="780" width="243" height="64"/>
|
||||
<SubTexture name="36-Breakout-Tiles.png" x="839" y="912" width="243" height="64"/>
|
||||
<SubTexture name="37-Breakout-Tiles.png" x="1329" y="858" width="243" height="64"/>
|
||||
<SubTexture name="38-Breakout-Tiles.png" x="1329" y="792" width="243" height="64"/>
|
||||
<SubTexture name="39-Breakout-Tiles.png" x="1403" y="0" width="243" height="64"/>
|
||||
<SubTexture name="40-Breakout-Tiles.png" x="1329" y="924" width="243" height="64"/>
|
||||
<SubTexture name="41-Breakout-Tiles.png" x="1158" y="66" width="243" height="64"/>
|
||||
<SubTexture name="42-Breakout-Tiles.png" x="349" y="910" width="243" height="64"/>
|
||||
<SubTexture name="43-Breakout-Tiles.png" x="594" y="910" width="243" height="64"/>
|
||||
<SubTexture name="44-Breakout-Tiles.png" x="1262" y="726" width="243" height="64"/>
|
||||
<SubTexture name="45-Breakout-Tiles.png" x="1158" y="132" width="243" height="64"/>
|
||||
<SubTexture name="46-Breakout-Tiles.png" x="1158" y="198" width="243" height="64"/>
|
||||
<SubTexture name="47-Breakout-Tiles.png" x="1158" y="264" width="243" height="64"/>
|
||||
<SubTexture name="48-Breakout-Tiles.png" x="1158" y="330" width="243" height="64"/>
|
||||
<SubTexture name="49-Breakout-Tiles.png" x="1158" y="396" width="243" height="64"/>
|
||||
<SubTexture name="50-Breakout-Tiles.png" x="1158" y="462" width="243" height="64"/>
|
||||
<SubTexture name="51-Breakout-Tiles.png" x="1158" y="528" width="243" height="64"/>
|
||||
<SubTexture name="52-Breakout-Tiles.png" x="1158" y="594" width="243" height="64"/>
|
||||
<SubTexture name="53-Breakout-Tiles.png" x="1158" y="660" width="243" height="64"/>
|
||||
<SubTexture name="54-Breakout-Tiles.png" x="839" y="846" width="243" height="64"/>
|
||||
<SubTexture name="55-Breakout-Tiles.png" x="772" y="780" width="243" height="64"/>
|
||||
<SubTexture name="56-Breakout-Tiles.png" x="0" y="910" width="347" height="64"/>
|
||||
<SubTexture name="57-Breakout-Tiles.png" x="1574" y="912" width="115" height="64"/>
|
||||
<SubTexture name="58-Breakout-Tiles.png" x="1403" y="652" width="64" height="64"/>
|
||||
<SubTexture name="59-Breakout-Tiles.png" x="772" y="846" width="64" height="61"/>
|
||||
<SubTexture name="60-Breakout-Tiles.png" x="1637" y="652" width="64" height="58"/>
|
||||
<SubTexture name="61-Breakout-Tiles.png" x="0" y="990" width="10" height="21"/>
|
||||
</TextureAtlas>
|
||||
BIN
assets/Breakout Tile Set Free/Vector/.DS_Store
vendored
Normal file
BIN
assets/Breakout Tile Set Free/Vector/Breakout Tile Set Free.eps
Normal file
2535
assets/Breakout Tile Set Free/Vector/Breakout Tile Set Free.svg
Normal file
|
After Width: | Height: | Size: 155 KiB |
BIN
assets/Breakout Tile Set Free/preview.png
Normal file
|
After Width: | Height: | Size: 142 KiB |
BIN
assets/Breakout Tile Set Free/sample.png
Normal file
|
After Width: | Height: | Size: 34 KiB |
BIN
assets/Breakout_Tile_Set_Free.zip
Normal file
BIN
assets/home.jpg
Normal file
|
After Width: | Height: | Size: 201 KiB |
BIN
src/assets/home.jpg
Normal file
|
After Width: | Height: | Size: 201 KiB |
12870
src/assets/home.jpg.h
Normal file
67
src/logger/logger.h
Normal file
@@ -0,0 +1,67 @@
|
||||
#pragma once
|
||||
|
||||
#include "quokka_gfx/core/events/eventBus.h"
|
||||
|
||||
#include <iostream> // For std::cout
|
||||
#include <syncstream> // For std::osyncstream (C++20) to ensure thread-safe output
|
||||
#include <thread> // For std::thread and std::mutex
|
||||
#include <utility> // For std::forward
|
||||
|
||||
//--------------------------------------------------------------
|
||||
class Logger : public quokka_gfx::Listener
|
||||
{
|
||||
public:
|
||||
Logger(); // Default constructor
|
||||
virtual ~Logger() = default; // Default destructor
|
||||
Logger(const Logger &obj) = delete; // Copy constructor
|
||||
Logger(Logger &&obj) = delete; // Move constructor
|
||||
Logger &operator=(const Logger &obj) = delete; // Copy assignment operator
|
||||
Logger &operator=(Logger &&obj) = delete; // Move assignment operator
|
||||
|
||||
template<typename... Args>
|
||||
void log(Args &&...args); // Variadic template function for logging
|
||||
|
||||
protected:
|
||||
std::jthread m_loggerThread; // Waits for events thread
|
||||
|
||||
private:
|
||||
void startThread(); // Start the logger thread
|
||||
};
|
||||
//--------------------------------------------------------------
|
||||
/* Default constructor */
|
||||
inline Logger::Logger()
|
||||
{
|
||||
subscribe(quokka_gfx::toID("log"));
|
||||
startThread();
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Variadic template function for logging */
|
||||
template<typename... Args>
|
||||
void Logger::log(Args &&...args)
|
||||
{
|
||||
std::osyncstream out(std::cout);
|
||||
(out << ... << args) << std::endl;
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Start the logger thread */
|
||||
inline void Logger::startThread()
|
||||
{
|
||||
m_loggerThread = std::jthread([&](const std::stop_token &st)
|
||||
{
|
||||
while (!st.stop_requested())
|
||||
{
|
||||
while (getEventCount() > 0)
|
||||
{
|
||||
const auto event = popEvent();
|
||||
if (event)
|
||||
{
|
||||
if (event->getType() == quokka_gfx::toID("log"))
|
||||
log(event->getType());
|
||||
}
|
||||
}
|
||||
|
||||
// Sleep for a short duration to prevent busy waiting
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||
} });
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
31
src/main.cpp
Normal file
@@ -0,0 +1,31 @@
|
||||
#include "logger/logger.h"
|
||||
#include "quokka_gfx/quokka_gfx.h"
|
||||
#include "screens/home/homeScreen.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
using namespace std;
|
||||
//--------------------------------------------------------------
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
// App initialization
|
||||
Logger logger; // Initialize the logger
|
||||
|
||||
logger.log("Quokkanoid Game Started!");
|
||||
|
||||
// Start the quokka GFX application instance
|
||||
quokka_gfx::Application app("Quokkanoid");
|
||||
try
|
||||
{
|
||||
app.initScreen(make_unique<HomeScreen>(&app));
|
||||
app.run();
|
||||
}
|
||||
catch (const exception &e)
|
||||
{
|
||||
cerr << "Error: " << e.what() << endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
158
src/quokka_gfx/core/application.cpp
Normal file
@@ -0,0 +1,158 @@
|
||||
#include "application.h"
|
||||
|
||||
#include "../utils/color.h"
|
||||
#include "assets/assetManager.h"
|
||||
#include "events/inputManager.h"
|
||||
#include "renderer/rendererManager.h"
|
||||
#include "screens/screenManager.h"
|
||||
|
||||
#include <SDL2/SDL.h>
|
||||
#include <iostream>
|
||||
#include <stdexcept>
|
||||
|
||||
using namespace std;
|
||||
using namespace quokka_gfx;
|
||||
//------------------------------------------------------------
|
||||
/* Constructor */
|
||||
Application::Application(const std::string &title)
|
||||
{
|
||||
init(title);
|
||||
}
|
||||
//------------------------------------------------------------
|
||||
/* Default destructor */
|
||||
Application::~Application()
|
||||
{
|
||||
cleanup();
|
||||
}
|
||||
//------------------------------------------------------------
|
||||
/* Initialize the first screen */
|
||||
void Application::initScreen(std::unique_ptr<Screen> screen) const
|
||||
{
|
||||
m_screenManager->setScreen(std::move(screen));
|
||||
}
|
||||
//------------------------------------------------------------
|
||||
/* Main loop */
|
||||
void Application::run()
|
||||
{
|
||||
auto lastTime = SDL_GetPerformanceCounter();
|
||||
const auto frequency = static_cast<double>(SDL_GetPerformanceFrequency());
|
||||
|
||||
while (m_running)
|
||||
{
|
||||
// Calculate delta time in seconds for smooth updates regardless of frame rate
|
||||
const auto currentTime = SDL_GetPerformanceCounter();
|
||||
const auto deltaTime = static_cast<double>((currentTime - lastTime)) / frequency;
|
||||
lastTime = currentTime;
|
||||
|
||||
handleEvents();
|
||||
update(deltaTime);
|
||||
render();
|
||||
}
|
||||
}
|
||||
//------------------------------------------------------------
|
||||
/* Quit the application */
|
||||
void Application::quit()
|
||||
{
|
||||
m_running = false;
|
||||
}
|
||||
//------------------------------------------------------------
|
||||
AssetManager *Application::assetManager() const
|
||||
{
|
||||
return m_assetManager.get();
|
||||
}
|
||||
//------------------------------------------------------------
|
||||
InputManager *Application::inputManager() const
|
||||
{
|
||||
return m_inputManager.get();
|
||||
}
|
||||
//------------------------------------------------------------
|
||||
RendererManager *Application::rendererManager() const
|
||||
{
|
||||
return m_rendererManager.get();
|
||||
}
|
||||
//------------------------------------------------------------
|
||||
ScreenManager *Application::screenManager() const
|
||||
{
|
||||
return m_screenManager.get();
|
||||
}
|
||||
//------------------------------------------------------------
|
||||
/* Initialisation */
|
||||
void Application::init(const std::string &title)
|
||||
{
|
||||
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER) != 0)
|
||||
throw std::runtime_error("Unable to initialize SDL: " + std::string(SDL_GetError()));
|
||||
|
||||
m_window = SDL_CreateWindow(
|
||||
title.c_str(),
|
||||
SDL_WINDOWPOS_CENTERED,
|
||||
SDL_WINDOWPOS_CENTERED,
|
||||
1200,
|
||||
896,
|
||||
SDL_WINDOW_SHOWN);
|
||||
|
||||
if (!m_window)
|
||||
throw std::runtime_error("Unable to create window: " + std::string(SDL_GetError()));
|
||||
|
||||
m_sdlRenderer = SDL_CreateRenderer(m_window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
|
||||
if (!m_sdlRenderer)
|
||||
throw std::runtime_error("Unable to create renderer: " + std::string(SDL_GetError()));
|
||||
|
||||
// Enable alpha blending for transparency support
|
||||
SDL_SetRenderDrawBlendMode(m_sdlRenderer, SDL_BLENDMODE_BLEND);
|
||||
|
||||
// Initialize subsystems
|
||||
m_assetManager = std::make_unique<AssetManager>(m_sdlRenderer);
|
||||
m_inputManager = std::make_unique<InputManager>();
|
||||
m_rendererManager = std::make_unique<RendererManager>(this);
|
||||
m_screenManager = std::make_unique<ScreenManager>();
|
||||
|
||||
m_running = true;
|
||||
}
|
||||
//------------------------------------------------------------
|
||||
/* Handle SDL events */
|
||||
void Application::handleEvents()
|
||||
{
|
||||
auto eventProcessing = m_inputManager->getEventProcessing();
|
||||
|
||||
SDL_Event event;
|
||||
while (SDL_PollEvent(&event))
|
||||
{
|
||||
if (event.type == SDL_QUIT)
|
||||
{
|
||||
quit();
|
||||
}
|
||||
|
||||
eventProcessing.process(event);
|
||||
}
|
||||
|
||||
m_screenManager->handleEvents();
|
||||
}
|
||||
//------------------------------------------------------------
|
||||
/* Update game state */
|
||||
void Application::update(const double deltaTime) const
|
||||
{
|
||||
m_screenManager->update(deltaTime);
|
||||
}
|
||||
//------------------------------------------------------------
|
||||
/* Render the game */
|
||||
void Application::render() const
|
||||
{
|
||||
m_rendererManager->clear(Color(30, 30, 30));
|
||||
|
||||
m_screenManager->render(m_rendererManager.get()); // Render the current screen
|
||||
|
||||
m_rendererManager->present(); // Present the rendered content to the screen
|
||||
}
|
||||
//------------------------------------------------------------
|
||||
/* Cleanup resources */
|
||||
void Application::cleanup() const
|
||||
{
|
||||
if (m_sdlRenderer)
|
||||
SDL_DestroyRenderer(m_sdlRenderer);
|
||||
|
||||
if (m_window)
|
||||
SDL_DestroyWindow(m_window);
|
||||
|
||||
SDL_Quit();
|
||||
}
|
||||
//------------------------------------------------------------
|
||||
60
src/quokka_gfx/core/application.h
Normal file
@@ -0,0 +1,60 @@
|
||||
#pragma once
|
||||
#include <SDL2/SDL.h>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
namespace quokka_gfx
|
||||
{
|
||||
class Screen;
|
||||
class AssetManager;
|
||||
class InputManager;
|
||||
class RendererManager;
|
||||
class ScreenManager;
|
||||
//------------------------------------------------------------
|
||||
class Application
|
||||
{
|
||||
friend class RendererManager;
|
||||
friend class Screen;
|
||||
|
||||
public:
|
||||
Application() = delete; // Default constructor
|
||||
virtual ~Application(); // Default destructor
|
||||
Application(const Application &obj) = delete; // Copy constructor
|
||||
Application(Application &&obj) = delete; // Move constructor
|
||||
Application &operator=(const Application &obj) = delete; // Copy assignment operator
|
||||
Application &operator=(Application &&obj) = delete; // Move assignment operator
|
||||
|
||||
explicit Application(const std::string &title); // Constructor
|
||||
|
||||
void initScreen(std::unique_ptr<Screen> screen) const; // Initialize the first screen
|
||||
|
||||
void run(); // Main loop
|
||||
void quit(); // Quit the application
|
||||
|
||||
// Accessors for subsystems
|
||||
[[nodiscard]] AssetManager *assetManager() const;
|
||||
[[nodiscard]] InputManager *inputManager() const;
|
||||
[[nodiscard]] RendererManager *rendererManager() const;
|
||||
[[nodiscard]] ScreenManager *screenManager() const;
|
||||
|
||||
protected:
|
||||
SDL_Window *m_window = nullptr;
|
||||
SDL_Renderer *m_sdlRenderer = nullptr;
|
||||
|
||||
bool m_running = false; // Main loop flag
|
||||
|
||||
// Subsystems
|
||||
std::unique_ptr<AssetManager> m_assetManager; // Asset manager
|
||||
std::unique_ptr<InputManager> m_inputManager; // Input manager
|
||||
std::unique_ptr<RendererManager> m_rendererManager; // Renderer manager
|
||||
std::unique_ptr<ScreenManager> m_screenManager; // Screen manager
|
||||
|
||||
private:
|
||||
void init(const std::string &title); // Initialisation
|
||||
void handleEvents(); // Handle SDL events
|
||||
void update(double deltaTime) const; // Update game state
|
||||
void render() const; // Render the game
|
||||
void cleanup() const; // Cleanup resources
|
||||
};
|
||||
//------------------------------------------------------------
|
||||
} // namespace quokka_gfx
|
||||
121
src/quokka_gfx/core/assets/assetManager.cpp
Normal file
@@ -0,0 +1,121 @@
|
||||
#include "assetManager.h"
|
||||
|
||||
#include <SDL2/SDL_image.h>
|
||||
#include <SDL2/SDL_rwops.h>
|
||||
#include <iostream>
|
||||
|
||||
using namespace std;
|
||||
using namespace quokka_gfx;
|
||||
//------------------------------------------------------------
|
||||
AssetManager::AssetManager(SDL_Renderer *renderer)
|
||||
{
|
||||
// Initialization
|
||||
m_renderer = renderer;
|
||||
}
|
||||
//------------------------------------------------------------
|
||||
void AssetManager::clear()
|
||||
{
|
||||
m_textures.clear();
|
||||
m_fonts.clear();
|
||||
}
|
||||
//------------------------------------------------------------
|
||||
bool AssetManager::loadTexture(const HashID &id, const std::filesystem::path &filePath)
|
||||
{
|
||||
// Check if the texture is already loaded
|
||||
if (m_textures.contains(id))
|
||||
return false;
|
||||
|
||||
// Load the texture from the file path
|
||||
SDL_Texture *texture = IMG_LoadTexture(m_renderer, filePath.string().c_str());
|
||||
if (!texture)
|
||||
{
|
||||
cerr << format("Failed to load texture: {}, Error: {}",
|
||||
filePath.string(),
|
||||
SDL_GetError());
|
||||
return false;
|
||||
}
|
||||
|
||||
// Store the texture in the map and return it
|
||||
m_textures.emplace(id, Texture(texture, SDL_DestroyTexture));
|
||||
return true;
|
||||
}
|
||||
//------------------------------------------------------------
|
||||
/* Load a texture from a memory buffer */
|
||||
bool AssetManager::loadTexture(const HashID &id, const std::span<const uint8_t> &buffer)
|
||||
{
|
||||
// Check if the texture is already loaded
|
||||
if (m_textures.contains(id))
|
||||
return false;
|
||||
|
||||
// Load the texture from the memory buffer
|
||||
const auto rw = SDL_RWFromConstMem(buffer.data(), static_cast<int>(buffer.size()));
|
||||
if (!rw)
|
||||
{
|
||||
cerr << format("Failed to create RWops from memory buffer, Error: {}",
|
||||
SDL_GetError());
|
||||
return false;
|
||||
}
|
||||
|
||||
SDL_Texture *texture = IMG_LoadTexture_RW(m_renderer, rw, 1);
|
||||
if (!texture)
|
||||
{
|
||||
cerr << format("Failed to load texture from memory buffer, Error: {}",
|
||||
SDL_GetError());
|
||||
return false;
|
||||
}
|
||||
|
||||
// Store the texture in the map and return it
|
||||
m_textures.emplace(id, Texture(texture, SDL_DestroyTexture));
|
||||
return true;
|
||||
}
|
||||
//------------------------------------------------------------
|
||||
SDL_Texture *AssetManager::getTexture(const HashID &id) const
|
||||
{
|
||||
if (m_textures.contains(id))
|
||||
return m_textures.at(id).get();
|
||||
|
||||
cerr << format("Texture with ID '{}' not found.", id);
|
||||
return nullptr;
|
||||
}
|
||||
//------------------------------------------------------------
|
||||
void AssetManager::unloadTexture(const HashID &id)
|
||||
{
|
||||
m_textures.erase(id);
|
||||
}
|
||||
//------------------------------------------------------------
|
||||
/* Load a font from a file path with a specific size */
|
||||
TTF_Font *AssetManager::loadFont(const HashID &id, const std::filesystem::path &filePath, int fontSize)
|
||||
{
|
||||
// Check if the font is already loaded
|
||||
if (m_fonts.contains(id))
|
||||
return m_fonts.at(id).get();
|
||||
|
||||
// Load the font from the file path
|
||||
TTF_Font *font = TTF_OpenFont(filePath.string().c_str(), fontSize);
|
||||
if (!font)
|
||||
{
|
||||
cerr << format("Failed to load font: {}, Error: {}", filePath.string(), TTF_GetError());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Store the font in the map and return it
|
||||
m_fonts.emplace(id, Font(font, TTF_CloseFont));
|
||||
return font;
|
||||
}
|
||||
//------------------------------------------------------------
|
||||
/* Get a font by its ID */
|
||||
TTF_Font *AssetManager::getFont(const HashID &id) const
|
||||
{
|
||||
if (m_fonts.contains(id))
|
||||
return m_fonts.at(id).get();
|
||||
|
||||
cerr << format("Font with ID '{}' not found.", id);
|
||||
return nullptr;
|
||||
}
|
||||
//------------------------------------------------------------
|
||||
/* Unload a font by its ID */
|
||||
void AssetManager::unloadFont(const HashID &id)
|
||||
{
|
||||
m_fonts.erase(id);
|
||||
}
|
||||
//------------------------------------------------------------
|
||||
46
src/quokka_gfx/core/assets/assetManager.h
Normal file
@@ -0,0 +1,46 @@
|
||||
#pragma once
|
||||
#include "../defs.h"
|
||||
|
||||
#include <SDL2/SDL.h>
|
||||
#include <SDL2/SDL_ttf.h>
|
||||
#include <filesystem>
|
||||
#include <span>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace quokka_gfx
|
||||
{
|
||||
class Application;
|
||||
//------------------------------------------------------------
|
||||
class AssetManager
|
||||
{
|
||||
public:
|
||||
AssetManager() = delete; // Default constructor
|
||||
virtual ~AssetManager() = default; // Default destructor
|
||||
AssetManager(const AssetManager &obj) = delete; // Copy constructor
|
||||
AssetManager(AssetManager &&obj) = delete; // Move constructor
|
||||
AssetManager &operator=(const AssetManager &obj) = delete; // Copy assignment operator
|
||||
AssetManager &operator=(AssetManager &&obj) = delete; // Move assignment operator
|
||||
|
||||
explicit AssetManager(SDL_Renderer *renderer); // Constructor
|
||||
void clear(); // Clear all loaded assets
|
||||
|
||||
// Texture management
|
||||
bool loadTexture(const HashID &id, const std::filesystem::path &filePath); // Load a texture from a file path
|
||||
bool loadTexture(const HashID &id, const std::span<const uint8_t> &buffer); // Load a texture from a memory buffer
|
||||
[[nodiscard]] SDL_Texture *getTexture(const HashID &id) const; // Get a texture by its ID
|
||||
void unloadTexture(const HashID &id); // Unload a texture by its ID
|
||||
|
||||
// Font management
|
||||
TTF_Font *loadFont(const HashID &id, const std::filesystem::path &filePath, int fontSize);
|
||||
[[nodiscard]] TTF_Font *getFont(const HashID &id) const;
|
||||
void unloadFont(const HashID &id);
|
||||
|
||||
protected:
|
||||
SDL_Renderer *m_renderer = nullptr;
|
||||
|
||||
std::unordered_map<HashID, Texture> m_textures;
|
||||
std::unordered_map<HashID, Font> m_fonts;
|
||||
};
|
||||
//------------------------------------------------------------
|
||||
} // namespace quokka_gfx
|
||||
30
src/quokka_gfx/core/defs.h
Normal file
@@ -0,0 +1,30 @@
|
||||
#pragma once
|
||||
|
||||
#include <SDL2/SDL.h>
|
||||
#include <SDL2/SDL_ttf.h>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
namespace quokka_gfx
|
||||
{
|
||||
//------------------------------------------------------------
|
||||
using HashID = uint32_t;
|
||||
using Texture = std::unique_ptr<SDL_Texture, void (*)(SDL_Texture *)>;
|
||||
using Font = std::unique_ptr<TTF_Font, void (*)(TTF_Font *)>;
|
||||
//------------------------------------------------------------
|
||||
// Hash function for IDs using FNV-1a algorithm
|
||||
inline constexpr HashID toID(const std::string &id)
|
||||
{
|
||||
constexpr uint32_t FNV_offset_basis = 2166136261u;
|
||||
constexpr uint32_t FNV_prime = 16777619u;
|
||||
|
||||
uint32_t hash_value = FNV_offset_basis;
|
||||
for (const char c : id)
|
||||
{
|
||||
hash_value ^= static_cast<uint32_t>(static_cast<uint8_t>(c));
|
||||
hash_value *= FNV_prime;
|
||||
}
|
||||
return hash_value;
|
||||
}
|
||||
//------------------------------------------------------------
|
||||
} // namespace quokka_gfx
|
||||
168
src/quokka_gfx/core/events/eventBus.cpp
Normal file
@@ -0,0 +1,168 @@
|
||||
#include "eventBus.h"
|
||||
|
||||
#include <ranges>
|
||||
|
||||
using namespace std;
|
||||
using namespace quokka_gfx;
|
||||
//------------------------------------------------------------
|
||||
/* Constructor */
|
||||
Event::Event(const HashID &type) noexcept
|
||||
{
|
||||
m_type = type;
|
||||
}
|
||||
//------------------------------------------------------------
|
||||
/* Get the type ID of the event */
|
||||
HashID Event::getType() const
|
||||
{
|
||||
return m_type;
|
||||
}
|
||||
//------------------------------------------------------------
|
||||
|
||||
/* --- */
|
||||
|
||||
//------------------------------------------------------------
|
||||
/* Default destructor */
|
||||
Listener::~Listener()
|
||||
{
|
||||
unsubscribeAll();
|
||||
}
|
||||
//------------------------------------------------------------
|
||||
/* Post an event to the listener */
|
||||
void Listener::pushEvent(std::shared_ptr<Event> event)
|
||||
{
|
||||
scoped_lock lock(m_receivedEventsMutex);
|
||||
m_receivedEvents.push(std::move(event));
|
||||
}
|
||||
//------------------------------------------------------------
|
||||
/* Get the number of received events */
|
||||
size_t Listener::getEventCount() const
|
||||
{
|
||||
scoped_lock lock(m_receivedEventsMutex);
|
||||
return m_receivedEvents.size();
|
||||
}
|
||||
//------------------------------------------------------------
|
||||
/* Get the next event from the queue */
|
||||
std::shared_ptr<Event> Listener::popEvent()
|
||||
{
|
||||
scoped_lock lock(m_receivedEventsMutex);
|
||||
if (m_receivedEvents.empty())
|
||||
return nullptr;
|
||||
|
||||
auto event = m_receivedEvents.front();
|
||||
m_receivedEvents.pop();
|
||||
return event;
|
||||
}
|
||||
//------------------------------------------------------------
|
||||
/* Post an event to the event bus */
|
||||
void Listener::postEvent(const std::shared_ptr<Event> &event) const
|
||||
{
|
||||
EventBus::getInstance().notify(event);
|
||||
}
|
||||
//------------------------------------------------------------
|
||||
/* Check if subscribed to a specific event type */
|
||||
bool Listener::isSubscribed(const HashID &eventType) const
|
||||
{
|
||||
return EventBus::getInstance().isSubscribed(eventType, this);
|
||||
}
|
||||
//------------------------------------------------------------
|
||||
/* Subscribe to a specific event type*/
|
||||
void Listener::subscribe(const HashID &eventType)
|
||||
{
|
||||
EventBus::getInstance().subscribe(eventType, this);
|
||||
}
|
||||
//------------------------------------------------------------
|
||||
/* Unsubscribe from a specific event type */
|
||||
void Listener::unsubscribe(const HashID &eventType)
|
||||
{
|
||||
EventBus::getInstance().unsubscribe(eventType, this);
|
||||
}
|
||||
//------------------------------------------------------------
|
||||
/* Unsubscribe from all events */
|
||||
void Listener::unsubscribeAll()
|
||||
{
|
||||
EventBus::getInstance().unsubscribeAll(this);
|
||||
}
|
||||
//------------------------------------------------------------
|
||||
|
||||
/* --- */
|
||||
|
||||
//------------------------------------------------------------
|
||||
/* Get the singleton instance */
|
||||
EventBus &EventBus::getInstance()
|
||||
{
|
||||
static auto instance = std::unique_ptr<EventBus>(new EventBus());
|
||||
return *instance;
|
||||
}
|
||||
//------------------------------------------------------------
|
||||
/* Notify all listeners subscribed to the event type */
|
||||
void EventBus::notify(const std::shared_ptr<Event> &event) const
|
||||
{
|
||||
scoped_lock lock(m_listenersMutex);
|
||||
|
||||
// No listeners subscribed to this event type, nothing to do
|
||||
if (!m_listeners.contains(event->getType()))
|
||||
return;
|
||||
|
||||
// Notify all listeners subscribed to this event type
|
||||
for (const auto listener : m_listeners.at(event->getType()))
|
||||
listener->pushEvent(event);
|
||||
}
|
||||
//------------------------------------------------------------
|
||||
/* Check if a listener is subscribed to a specific event type */
|
||||
bool EventBus::isSubscribed(const HashID &eventType, const Listener *listener) const
|
||||
{
|
||||
scoped_lock lock(m_listenersMutex);
|
||||
|
||||
// Event type not registered, listener cannot be subscribed
|
||||
if (!m_listeners.contains(eventType))
|
||||
return false;
|
||||
|
||||
// Event type already registered, check if the listener is in the list
|
||||
const auto &listeners = m_listeners.at(eventType);
|
||||
return ranges::find(listeners, listener) != listeners.end();
|
||||
}
|
||||
//------------------------------------------------------------
|
||||
/* Subscribe a listener to a specific event type */
|
||||
void EventBus::subscribe(const HashID &eventType, Listener *listener)
|
||||
{
|
||||
scoped_lock lock(m_listenersMutex);
|
||||
|
||||
// Event type not registered yet, create a new entry with the listener
|
||||
if (!m_listeners.contains(eventType))
|
||||
{
|
||||
m_listeners[eventType] = { listener };
|
||||
return;
|
||||
}
|
||||
|
||||
// Event type already registered, add the listener if not already subscribed
|
||||
auto &listeners = m_listeners[eventType];
|
||||
if (ranges::find(listeners, listener) == listeners.end())
|
||||
listeners.push_back(listener);
|
||||
}
|
||||
//------------------------------------------------------------
|
||||
/* Unsubscribe a listener from a specific event type */
|
||||
void EventBus::unsubscribe(const HashID &eventType, Listener *listener)
|
||||
{
|
||||
scoped_lock lock(m_listenersMutex);
|
||||
|
||||
// Event type not registered, nothing to do
|
||||
if (!m_listeners.contains(eventType))
|
||||
return;
|
||||
|
||||
// Event type registered, remove the listener if subscribed
|
||||
auto &listeners = m_listeners[eventType];
|
||||
const auto it = ranges::find(listeners, listener);
|
||||
if (it != listeners.end())
|
||||
listeners.erase(it);
|
||||
}
|
||||
//------------------------------------------------------------
|
||||
/* Unsubscribe a listener from all event types */
|
||||
void EventBus::unsubscribeAll(Listener *listener)
|
||||
{
|
||||
scoped_lock lock(m_listenersMutex);
|
||||
|
||||
// Iterate through all event types and remove the listener from each list
|
||||
for (const auto &eventType : m_listeners | views::keys)
|
||||
unsubscribe(eventType, listener);
|
||||
}
|
||||
//------------------------------------------------------------
|
||||
104
src/quokka_gfx/core/events/eventBus.h
Normal file
@@ -0,0 +1,104 @@
|
||||
#pragma once
|
||||
|
||||
#include "../defs.h"
|
||||
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <queue>
|
||||
#include <typeindex>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
namespace quokka_gfx
|
||||
{
|
||||
class EventBus;
|
||||
|
||||
//------------------------------------------------------------
|
||||
// Base class for all events
|
||||
class Event
|
||||
{
|
||||
public:
|
||||
Event() = delete; // Default constructor
|
||||
virtual ~Event() = default; // Default destructor
|
||||
Event(const Event &obj) = delete; // Copy constructor
|
||||
Event(Event &&obj) = delete; // Move constructor
|
||||
Event &operator=(const Event &obj) = delete; // Copy assignment operator
|
||||
Event &operator=(Event &&obj) = delete; // Move assignment operator
|
||||
|
||||
explicit Event(const HashID &type) noexcept; // Constructor
|
||||
|
||||
[[nodiscard]] HashID getType() const; // Get the type ID of the event
|
||||
|
||||
protected:
|
||||
HashID m_type; // Type ID of the event
|
||||
};
|
||||
//------------------------------------------------------------
|
||||
|
||||
/* --- */
|
||||
|
||||
//------------------------------------------------------------
|
||||
// Base class for all event listeners
|
||||
class Listener
|
||||
{
|
||||
friend class EventBus;
|
||||
|
||||
public:
|
||||
Listener() = default; // Default constructor
|
||||
virtual ~Listener(); // Default destructor
|
||||
Listener(const Listener &obj) = delete; // Copy constructor
|
||||
Listener(Listener &&obj) = delete; // Move constructor
|
||||
Listener &operator=(const Listener &obj) = delete; // Copy assignment operator
|
||||
Listener &operator=(Listener &&obj) = delete; // Move assignment operator
|
||||
|
||||
void pushEvent(std::shared_ptr<Event> event); // Post an event to the listener
|
||||
|
||||
[[nodiscard]] size_t getEventCount() const; // Get the number of received events
|
||||
[[nodiscard]] std::shared_ptr<Event> popEvent(); // Get the next event from the queue
|
||||
|
||||
void postEvent(const std::shared_ptr<Event> &event) const; // Post an event to the event bus
|
||||
|
||||
[[nodiscard]] bool isSubscribed(const HashID &eventType) const; // Check if subscribed to a specific event type
|
||||
void subscribe(const HashID &eventType); // Subscribe to a specific event type
|
||||
void unsubscribe(const HashID &eventType); // Unsubscribe from a specific event type
|
||||
void unsubscribeAll(); // Unsubscribe from all events
|
||||
|
||||
protected:
|
||||
mutable std::mutex m_receivedEventsMutex; // Mutex for thread-safe access to the event queue
|
||||
std::queue<std::shared_ptr<Event>> m_receivedEvents; // Queue of received events
|
||||
};
|
||||
//------------------------------------------------------------
|
||||
|
||||
/* --- */
|
||||
|
||||
//------------------------------------------------------------
|
||||
// Singleton EventBus for managing event distribution
|
||||
class EventBus
|
||||
{
|
||||
friend class Listener;
|
||||
|
||||
public:
|
||||
static EventBus &getInstance(); // Get the singleton instance
|
||||
|
||||
public:
|
||||
virtual ~EventBus() = default; // Default destructor
|
||||
EventBus(const EventBus &obj) = delete; // Copy constructor
|
||||
EventBus(EventBus &&obj) = delete; // Move constructor
|
||||
EventBus &operator=(const EventBus &obj) = delete; // Copy assignment operator
|
||||
EventBus &operator=(EventBus &&obj) = delete; // Move assignment operator
|
||||
|
||||
void notify(const std::shared_ptr<Event> &event) const; // Notify all listeners subscribed to the event type
|
||||
|
||||
protected:
|
||||
mutable std::recursive_mutex m_listenersMutex; // Mutex for thread-safe access to the listeners map
|
||||
std::unordered_map<HashID, std::vector<Listener *>> m_listeners; // Map of event type IDs to lists of subscribed listeners
|
||||
|
||||
private:
|
||||
EventBus() = default; // Default constructor
|
||||
|
||||
[[nodiscard]] bool isSubscribed(const HashID &eventType, const Listener *listener) const; // Check if a listener is subscribed to a specific event type
|
||||
void subscribe(const HashID &eventType, Listener *listener); // Subscribe a listener to a specific event type
|
||||
void unsubscribe(const HashID &eventType, Listener *listener); // Unsubscribe a listener from a specific event type
|
||||
void unsubscribeAll(Listener *listener); // Unsubscribe a listener from all event types
|
||||
};
|
||||
//------------------------------------------------------------
|
||||
} // namespace quokka_gfx
|
||||
318
src/quokka_gfx/core/events/inputManager.cpp
Normal file
@@ -0,0 +1,318 @@
|
||||
#include "inputManager.h"
|
||||
|
||||
#include <ranges>
|
||||
#include <stdexcept>
|
||||
|
||||
using namespace std;
|
||||
using namespace quokka_gfx;
|
||||
//------------------------------------------------------------
|
||||
/* Get event processing session */
|
||||
InputProcessing InputManager::getEventProcessing()
|
||||
{
|
||||
return InputProcessing(this);
|
||||
}
|
||||
//------------------------------------------------------------
|
||||
/* Get the current state of a key */
|
||||
InputManager::KeyState InputManager::getKeyState(const SDL_Scancode key) const
|
||||
{
|
||||
const auto it = m_keys.keyStates.find(key);
|
||||
return it != m_keys.keyStates.end() ? it->second : KeyState::Up;
|
||||
}
|
||||
//------------------------------------------------------------
|
||||
/* Check if a key was pressed this frame */
|
||||
bool InputManager::isKeyPressed(const SDL_Scancode key) const
|
||||
{
|
||||
if (!m_keys.keyStates.contains(key))
|
||||
return false;
|
||||
return m_keys.keyStates.at(key) == KeyState::Pressed;
|
||||
}
|
||||
//------------------------------------------------------------
|
||||
/* Check if a key is currently held down */
|
||||
bool InputManager::isKeyHeld(const SDL_Scancode key) const
|
||||
{
|
||||
if (!m_keys.keyStates.contains(key))
|
||||
return false;
|
||||
return m_keys.keyStates.at(key) == KeyState::Held;
|
||||
}
|
||||
//------------------------------------------------------------
|
||||
/* Check if a key was released this frame */
|
||||
bool InputManager::isKeyReleased(const SDL_Scancode key) const
|
||||
{
|
||||
if (!m_keys.keyStates.contains(key))
|
||||
return false;
|
||||
return m_keys.keyStates.at(key) == KeyState::Released;
|
||||
}
|
||||
//------------------------------------------------------------
|
||||
/* Check if a key is currently down */
|
||||
bool InputManager::isKeyDown(const SDL_Scancode key) const
|
||||
{
|
||||
if (!m_keys.keyStates.contains(key))
|
||||
return false;
|
||||
const auto state = m_keys.keyStates.at(key);
|
||||
return state == KeyState::Pressed || state == KeyState::Held;
|
||||
}
|
||||
//------------------------------------------------------------
|
||||
/* Check if a key is currently up */
|
||||
bool InputManager::isKeyUp(const SDL_Scancode key) const
|
||||
{
|
||||
if (!m_keys.keyStates.contains(key))
|
||||
return false;
|
||||
const auto state = m_keys.keyStates.at(key);
|
||||
return state == KeyState::Up || state == KeyState::Released;
|
||||
}
|
||||
//------------------------------------------------------------
|
||||
/* Check if Shift modifier is currently down */
|
||||
bool InputManager::isShiftDown() const
|
||||
{
|
||||
return isLShiftDown() || isRShiftDown();
|
||||
}
|
||||
//------------------------------------------------------------
|
||||
/* Check if Left Shift modifier is currently down */
|
||||
bool InputManager::isLShiftDown() const
|
||||
{
|
||||
return isKeyDown(SDL_SCANCODE_LSHIFT);
|
||||
}
|
||||
//------------------------------------------------------------
|
||||
/* Check if Right Shift modifier is currently down */
|
||||
bool InputManager::isRShiftDown() const
|
||||
{
|
||||
return isKeyDown(SDL_SCANCODE_RSHIFT);
|
||||
}
|
||||
//------------------------------------------------------------
|
||||
/* Check if Ctrl modifier is currently down */
|
||||
bool InputManager::isCtrlDown() const
|
||||
{
|
||||
return isLCtrlDown() || isRCtrlDown();
|
||||
}
|
||||
//------------------------------------------------------------
|
||||
/* Check if Left Ctrl modifier is currently down */
|
||||
bool InputManager::isLCtrlDown() const
|
||||
{
|
||||
return isKeyDown(SDL_SCANCODE_LCTRL);
|
||||
}
|
||||
//------------------------------------------------------------
|
||||
/* Check if Right Ctrl modifier is currently down */
|
||||
bool InputManager::isRCtrlDown() const
|
||||
{
|
||||
return isKeyDown(SDL_SCANCODE_RCTRL);
|
||||
}
|
||||
//------------------------------------------------------------
|
||||
/* Check if Alt modifier is currently down */
|
||||
bool InputManager::isAltDown() const
|
||||
{
|
||||
return isLAltDown() || isRAltDown();
|
||||
}
|
||||
//------------------------------------------------------------
|
||||
/* Check if Left Alt modifier is currently down */
|
||||
bool InputManager::isLAltDown() const
|
||||
{
|
||||
return isKeyDown(SDL_SCANCODE_LALT);
|
||||
}
|
||||
//------------------------------------------------------------
|
||||
/* Check if Right Alt modifier is currently down */
|
||||
bool InputManager::isRAltDown() const
|
||||
{
|
||||
return isKeyDown(SDL_SCANCODE_RALT);
|
||||
}
|
||||
//------------------------------------------------------------
|
||||
/* Get current mouse X position */
|
||||
int InputManager::getMouseX() const
|
||||
{
|
||||
return m_mouse.posX;
|
||||
}
|
||||
//------------------------------------------------------------
|
||||
/* Get current mouse Y position */
|
||||
int InputManager::getMouseY() const
|
||||
{
|
||||
return m_mouse.posY;
|
||||
}
|
||||
//------------------------------------------------------------
|
||||
/* Get current mouse position */
|
||||
Point InputManager::getMousePosition() const
|
||||
{
|
||||
return Point(m_mouse.posX, m_mouse.posY);
|
||||
}
|
||||
//------------------------------------------------------------
|
||||
/* Get mouse movement delta X since last frame */
|
||||
int InputManager::getMouseDeltaX() const
|
||||
{
|
||||
return m_mouse.deltaX;
|
||||
}
|
||||
//------------------------------------------------------------
|
||||
/* Get mouse movement delta Y since last frame */
|
||||
int InputManager::getMouseDeltaY() const
|
||||
{
|
||||
return m_mouse.deltaY;
|
||||
}
|
||||
//------------------------------------------------------------
|
||||
/* Get the current state of a mouse button */
|
||||
InputManager::KeyState InputManager::getMouseButtonState(const MouseButton button) const
|
||||
{
|
||||
auto it = m_mouse.buttonStates.find(button);
|
||||
return it != m_mouse.buttonStates.end() ? it->second : KeyState::Up;
|
||||
}
|
||||
//------------------------------------------------------------
|
||||
/* Get current mouse X position */
|
||||
bool InputManager::isMouseButtonPressed(const MouseButton button) const
|
||||
{
|
||||
if (!m_mouse.buttonStates.contains(button))
|
||||
return false;
|
||||
return m_mouse.buttonStates.at(button) == KeyState::Pressed;
|
||||
}
|
||||
//------------------------------------------------------------
|
||||
/* Get current mouse Y position */
|
||||
bool InputManager::isMouseButtonHeld(const MouseButton button) const
|
||||
{
|
||||
if (!m_mouse.buttonStates.contains(button))
|
||||
return false;
|
||||
return m_mouse.buttonStates.at(button) == KeyState::Held;
|
||||
}
|
||||
//------------------------------------------------------------
|
||||
/* Get mouse movement delta X since last frame */
|
||||
bool InputManager::isMouseButtonReleased(const MouseButton button) const
|
||||
{
|
||||
if (!m_mouse.buttonStates.contains(button))
|
||||
return false;
|
||||
return m_mouse.buttonStates.at(button) == KeyState::Released;
|
||||
}
|
||||
//------------------------------------------------------------
|
||||
/* Get mouse movement delta Y since last frame */
|
||||
bool InputManager::isMouseButtonDown(const MouseButton button) const
|
||||
{
|
||||
if (!m_mouse.buttonStates.contains(button))
|
||||
return false;
|
||||
const auto state = m_mouse.buttonStates.at(button);
|
||||
return state == KeyState::Pressed || state == KeyState::Held;
|
||||
}
|
||||
//------------------------------------------------------------
|
||||
/* Check if a mouse button is currently up */
|
||||
bool InputManager::isMouseButtonUp(const MouseButton button) const
|
||||
{
|
||||
if (!m_mouse.buttonStates.contains(button))
|
||||
return false;
|
||||
const auto state = m_mouse.buttonStates.at(button);
|
||||
return state == KeyState::Up || state == KeyState::Released;
|
||||
}
|
||||
//------------------------------------------------------------
|
||||
/* Get scroll wheel delta since last frame */
|
||||
int InputManager::getMouseWheelDelta() const
|
||||
{
|
||||
return m_mouse.wheelDelta;
|
||||
}
|
||||
//------------------------------------------------------------
|
||||
|
||||
/* --- */
|
||||
|
||||
//------------------------------------------------------------
|
||||
/* Constructor */
|
||||
InputProcessing::InputProcessing(InputManager *inputEventHandle)
|
||||
{
|
||||
if (!inputEventHandle)
|
||||
throw std::invalid_argument("InputManager pointer cannot be null");
|
||||
m_inputEventHandle = inputEventHandle;
|
||||
|
||||
begin();
|
||||
}
|
||||
//------------------------------------------------------------
|
||||
/* Default destructor */
|
||||
InputProcessing::~InputProcessing()
|
||||
{
|
||||
end();
|
||||
}
|
||||
//------------------------------------------------------------
|
||||
/* Process an SDL event */
|
||||
void InputProcessing::process(const SDL_Event &event) const
|
||||
{
|
||||
switch (event.type)
|
||||
{
|
||||
// ==== KEYBOARD ====
|
||||
case SDL_KEYDOWN:
|
||||
if (!event.key.repeat) // Skip auto-repeated keydown events
|
||||
{
|
||||
m_inputEventHandle->m_keys.keyStates[event.key.keysym.scancode] = InputManager::KeyState::Pressed;
|
||||
m_inputEventHandle->m_keys.keysPressed.insert(event.key.keysym.scancode);
|
||||
}
|
||||
break;
|
||||
|
||||
case SDL_KEYUP:
|
||||
m_inputEventHandle->m_keys.keyStates[event.key.keysym.scancode] = InputManager::KeyState::Released;
|
||||
m_inputEventHandle->m_keys.keysReleased.insert(event.key.keysym.scancode);
|
||||
break;
|
||||
|
||||
// ==== MOUSE - MOTION ====
|
||||
case SDL_MOUSEMOTION:
|
||||
m_inputEventHandle->m_mouse.posX = event.motion.x;
|
||||
m_inputEventHandle->m_mouse.posY = event.motion.y;
|
||||
m_inputEventHandle->m_mouse.deltaX = event.motion.xrel;
|
||||
m_inputEventHandle->m_mouse.deltaY = event.motion.yrel;
|
||||
break;
|
||||
|
||||
// ==== MOUSE - BOUTONS ====
|
||||
case SDL_MOUSEBUTTONDOWN:
|
||||
m_inputEventHandle->m_mouse.buttonStates[static_cast<InputManager::MouseButton>(event.button.button)] = InputManager::KeyState::Pressed;
|
||||
break;
|
||||
|
||||
case SDL_MOUSEBUTTONUP:
|
||||
m_inputEventHandle->m_mouse.buttonStates[static_cast<InputManager::MouseButton>(event.button.button)] = InputManager::KeyState::Released;
|
||||
break;
|
||||
|
||||
// ==== MOUSE - WHEEL ====
|
||||
case SDL_MOUSEWHEEL:
|
||||
m_inputEventHandle->m_mouse.wheelDelta = event.wheel.y; // positive = towards up, negative = towards down
|
||||
break;
|
||||
|
||||
// // ===== SAISIE DE TEXTE =====
|
||||
// case SDL_TEXTINPUT:
|
||||
// if (m_textInputCallback)
|
||||
// {
|
||||
// m_textInputCallback(event.text.text);
|
||||
// }
|
||||
// break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
//------------------------------------------------------------
|
||||
/* Called at the beginning of event processing */
|
||||
void InputProcessing::begin() const
|
||||
{
|
||||
// This function is called at the beginning of event processing to
|
||||
// reset states and prepare for new events
|
||||
|
||||
// Initialize key states for this frame
|
||||
m_inputEventHandle->m_keys.keysPressed.clear();
|
||||
m_inputEventHandle->m_keys.keysReleased.clear();
|
||||
|
||||
// Initialize mouse parameters
|
||||
m_inputEventHandle->m_mouse.lastPosX = m_inputEventHandle->m_mouse.posX;
|
||||
m_inputEventHandle->m_mouse.lastPosY = m_inputEventHandle->m_mouse.posY;
|
||||
m_inputEventHandle->m_mouse.deltaX = 0;
|
||||
m_inputEventHandle->m_mouse.deltaY = 0;
|
||||
m_inputEventHandle->m_mouse.wheelDelta = 0;
|
||||
}
|
||||
//------------------------------------------------------------
|
||||
/* Called at the end of event processing */
|
||||
void InputProcessing::end() const
|
||||
{
|
||||
// This function is called at the end of event processing
|
||||
|
||||
// Update key states
|
||||
for (auto &state : m_inputEventHandle->m_keys.keyStates | views::values)
|
||||
{
|
||||
if (state == InputManager::KeyState::Pressed)
|
||||
state = InputManager::KeyState::Held;
|
||||
else if (state == InputManager::KeyState::Released)
|
||||
state = InputManager::KeyState::Up;
|
||||
}
|
||||
|
||||
// Update mouse button states
|
||||
for (auto &state : m_inputEventHandle->m_mouse.buttonStates | views::values)
|
||||
{
|
||||
if (state == InputManager::KeyState::Pressed)
|
||||
state = InputManager::KeyState::Held;
|
||||
else if (state == InputManager::KeyState::Released)
|
||||
state = InputManager::KeyState::Up;
|
||||
}
|
||||
}
|
||||
//------------------------------------------------------------
|
||||
126
src/quokka_gfx/core/events/inputManager.h
Normal file
@@ -0,0 +1,126 @@
|
||||
#pragma once
|
||||
#include "../../utils/point.h"
|
||||
|
||||
#include <SDL2/SDL.h>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
|
||||
namespace quokka_gfx
|
||||
{
|
||||
class InputProcessing;
|
||||
|
||||
//------------------------------------------------------------
|
||||
class InputManager
|
||||
{
|
||||
friend class InputProcessing;
|
||||
|
||||
public:
|
||||
enum class KeyState : uint8_t
|
||||
{
|
||||
Up = 0, // Released
|
||||
Pressed, // Pressed (this frame only)
|
||||
Held, // Held
|
||||
Released // Released (this frame only)
|
||||
};
|
||||
|
||||
enum class MouseButton : uint8_t
|
||||
{
|
||||
Left = SDL_BUTTON_LEFT,
|
||||
Middle = SDL_BUTTON_MIDDLE,
|
||||
Right = SDL_BUTTON_RIGHT
|
||||
};
|
||||
|
||||
public:
|
||||
InputManager() = default; // Default constructor
|
||||
virtual ~InputManager() = default; // Default destructor
|
||||
InputManager(const InputManager &obj) = delete; // Copy constructor
|
||||
InputManager(InputManager &&obj) = delete; // Move constructor
|
||||
InputManager &operator=(const InputManager &obj) = delete; // Copy assignment operator
|
||||
InputManager &operator=(InputManager &&obj) = delete; // Move assignment operator
|
||||
|
||||
InputProcessing getEventProcessing(); // Get event processing session
|
||||
|
||||
// Keyboard accessors
|
||||
[[nodiscard]] KeyState getKeyState(SDL_Scancode key) const; // Get the current state of a key
|
||||
[[nodiscard]] bool isKeyPressed(SDL_Scancode key) const; // Check if a key was pressed this frame
|
||||
[[nodiscard]] bool isKeyHeld(SDL_Scancode key) const; // Check if a key is currently held down
|
||||
[[nodiscard]] bool isKeyReleased(SDL_Scancode key) const; // Check if a key was released this frame
|
||||
[[nodiscard]] bool isKeyDown(SDL_Scancode key) const; // Check if a key is currently down
|
||||
[[nodiscard]] bool isKeyUp(SDL_Scancode key) const; // Check if a key is currently up
|
||||
|
||||
[[nodiscard]] bool isShiftDown() const; // Check if Shift modifier is currently down
|
||||
[[nodiscard]] bool isLShiftDown() const; // Check if Left Shift modifier is currently down
|
||||
[[nodiscard]] bool isRShiftDown() const; // Check if Right Shift modifier is currently down
|
||||
[[nodiscard]] bool isCtrlDown() const; // Check if Ctrl modifier is currently down
|
||||
[[nodiscard]] bool isLCtrlDown() const; // Check if Left Ctrl modifier is currently down
|
||||
[[nodiscard]] bool isRCtrlDown() const; // Check if Right Ctrl modifier is currently down
|
||||
[[nodiscard]] bool isAltDown() const; // Check if Alt modifier is currently down
|
||||
[[nodiscard]] bool isLAltDown() const; // Check if Left Alt modifier is currently down
|
||||
[[nodiscard]] bool isRAltDown() const; // Check if Right Alt modifier is currently down
|
||||
|
||||
// Mouse accessors
|
||||
[[nodiscard]] int getMouseX() const; // Get current mouse X position
|
||||
[[nodiscard]] int getMouseY() const; // Get current mouse Y position
|
||||
[[nodiscard]] Point getMousePosition() const; // Get current mouse position as a rectangle (1x1)
|
||||
[[nodiscard]] int getMouseDeltaX() const; // Get mouse movement delta X since last frame
|
||||
[[nodiscard]] int getMouseDeltaY() const; // Get mouse movement delta Y since last frame
|
||||
|
||||
[[nodiscard]] KeyState getMouseButtonState(MouseButton button) const; // Get the current state of a mouse button
|
||||
[[nodiscard]] bool isMouseButtonPressed(MouseButton button) const; // Check if a mouse button was pressed this frame
|
||||
[[nodiscard]] bool isMouseButtonHeld(MouseButton button) const; // Check if a mouse button is currently held down
|
||||
[[nodiscard]] bool isMouseButtonReleased(MouseButton button) const; // Check if a mouse button was released this frame
|
||||
[[nodiscard]] bool isMouseButtonDown(MouseButton button) const; // Check if a mouse button is currently down
|
||||
[[nodiscard]] bool isMouseButtonUp(MouseButton button) const; // Check if a mouse button is currently up
|
||||
|
||||
[[nodiscard]] int getMouseWheelDelta() const; // Get scroll wheel delta since last frame
|
||||
|
||||
protected:
|
||||
// Key states
|
||||
struct
|
||||
{
|
||||
std::unordered_map<SDL_Scancode, KeyState> keyStates; // Key states (Pressed, Held, Released)
|
||||
std::unordered_set<SDL_Scancode> keysPressed; // Keys pressed this frame
|
||||
std::unordered_set<SDL_Scancode> keysReleased; // Keys released this frame
|
||||
} m_keys;
|
||||
|
||||
// Mouse states, position and movement
|
||||
struct
|
||||
{
|
||||
std::unordered_map<MouseButton, KeyState> buttonStates; // Button states (Pressed, Held, Released)
|
||||
int posX = 0; // Current X position of the mouse
|
||||
int posY = 0; // Current Y position of the mouse
|
||||
int lastPosX = 0; // Previous X position of the mouse (for delta calculation)
|
||||
int lastPosY = 0; // Previous Y position of the mouse (for delta calculation)
|
||||
int deltaX = 0; // Movement delta X since last frame
|
||||
int deltaY = 0; // Movement delta Y since last frame
|
||||
int wheelDelta = 0; // Scroll wheel delta since last frame
|
||||
} m_mouse;
|
||||
};
|
||||
//------------------------------------------------------------
|
||||
|
||||
/* --- */
|
||||
|
||||
//------------------------------------------------------------
|
||||
class InputProcessing
|
||||
{
|
||||
public:
|
||||
InputProcessing() = delete; // Default constructor
|
||||
virtual ~InputProcessing(); // Default destructor
|
||||
InputProcessing(const InputProcessing &obj) = delete; // Copy constructor
|
||||
InputProcessing(InputProcessing &&obj) = delete; // Move constructor
|
||||
InputProcessing &operator=(const InputProcessing &obj) = delete; // Copy assignment operator
|
||||
InputProcessing &operator=(InputProcessing &&obj) = delete; // Move assignment operator
|
||||
|
||||
explicit InputProcessing(InputManager *inputEventHandle); // Constructor
|
||||
|
||||
void process(const SDL_Event &event) const; // Process an SDL event
|
||||
|
||||
protected:
|
||||
InputManager *m_inputEventHandle = nullptr;
|
||||
|
||||
private:
|
||||
void begin() const; // Called at the beginning of event processing
|
||||
void end() const; // Called at the end of event processing
|
||||
};
|
||||
//------------------------------------------------------------
|
||||
} // namespace quokka_gfx
|
||||
173
src/quokka_gfx/core/renderer/rendererManager.cpp
Normal file
@@ -0,0 +1,173 @@
|
||||
#include "rendererManager.h"
|
||||
|
||||
#include "../application.h"
|
||||
#include "../assets/assetManager.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
using namespace std;
|
||||
using namespace quokka_gfx;
|
||||
//------------------------------------------------------------
|
||||
/* Constructor */
|
||||
RendererManager::RendererManager(Application *app)
|
||||
{
|
||||
m_app = app;
|
||||
}
|
||||
//------------------------------------------------------------
|
||||
/* Get the underlying SDL_Renderer */
|
||||
SDL_Renderer *RendererManager::getSDLRenderer() const
|
||||
{
|
||||
if (!m_app || !m_app->m_sdlRenderer)
|
||||
throw std::runtime_error("SDL Renderer not initialized");
|
||||
|
||||
return m_app->m_sdlRenderer;
|
||||
}
|
||||
//------------------------------------------------------------
|
||||
/* Present the rendered content to the screen */
|
||||
void RendererManager::present() const
|
||||
{
|
||||
SDL_RenderPresent(getSDLRenderer());
|
||||
}
|
||||
//------------------------------------------------------------
|
||||
/* Clear the renderer with a specific color */
|
||||
void RendererManager::clear(const Color &color) const
|
||||
{
|
||||
setDrawColor(color);
|
||||
SDL_RenderClear(getSDLRenderer());
|
||||
}
|
||||
//------------------------------------------------------------
|
||||
/* Draw a rectangle */
|
||||
void RendererManager::drawRect(const Rect &rect, const Color &color, const bool filled) const
|
||||
{
|
||||
setDrawColor(color);
|
||||
const auto sdlRect = rect.toSDL();
|
||||
if (filled)
|
||||
SDL_RenderFillRect(getSDLRenderer(), &sdlRect);
|
||||
else
|
||||
SDL_RenderDrawRect(getSDLRenderer(), &sdlRect);
|
||||
}
|
||||
//------------------------------------------------------------
|
||||
/* Draw a line between two points */
|
||||
void RendererManager::drawLine(const Point &start, const Point &end, const Color &color) const
|
||||
{
|
||||
setDrawColor(color);
|
||||
SDL_RenderDrawLine(getSDLRenderer(), start.x, start.y, end.x, end.y);
|
||||
}
|
||||
//------------------------------------------------------------
|
||||
/* Draw a single point */
|
||||
void RendererManager::drawPoint(const Point &point, const Color &color) const
|
||||
{
|
||||
setDrawColor(color);
|
||||
SDL_RenderDrawPoint(getSDLRenderer(), point.x, point.y);
|
||||
}
|
||||
//------------------------------------------------------------
|
||||
/* Draw text at a specific position */
|
||||
void RendererManager::drawText(const std::string &text, const HashID &fontID, const Point &point, const Color &color, int fontSize) const
|
||||
{
|
||||
const auto font = m_app->m_assetManager->getFont(fontID);
|
||||
|
||||
const auto textTexture = renderTextTexture(text, font, color);
|
||||
if (!textTexture)
|
||||
return;
|
||||
|
||||
int texW, texH;
|
||||
SDL_QueryTexture(textTexture.get(), nullptr, nullptr, &texW, &texH);
|
||||
|
||||
const Rect destRect(point.x, point.y, texW, texH);
|
||||
drawTexture(textTexture.get(), destRect);
|
||||
}
|
||||
//------------------------------------------------------------
|
||||
/* Draw text centered within a rectangle */
|
||||
void RendererManager::drawTextCentered(const std::string &text, const HashID &fontID, const Rect &rect, const Color &color, int fontSize) const
|
||||
{
|
||||
const auto font = m_app->m_assetManager->getFont(fontID);
|
||||
|
||||
const auto textTexture = renderTextTexture(text, font, color);
|
||||
if (!textTexture)
|
||||
return;
|
||||
|
||||
int texW, texH;
|
||||
SDL_QueryTexture(textTexture.get(), nullptr, nullptr, &texW, &texH);
|
||||
|
||||
// Center the text within the given rectangle
|
||||
const int x = rect.x + (rect.w - texW) / 2;
|
||||
const int y = rect.y + (rect.h - texH) / 2;
|
||||
|
||||
const Rect destRect(x, y, texW, texH);
|
||||
drawTexture(textTexture.get(), destRect);
|
||||
}
|
||||
//------------------------------------------------------------
|
||||
/* Draw a texture at a specific position and size */
|
||||
void RendererManager::drawTexture(SDL_Texture *texture, const Rect &dest, const Rect &source) const
|
||||
{
|
||||
if (!texture)
|
||||
return;
|
||||
|
||||
const SDL_Rect sdlDest = dest.toSDL();
|
||||
const SDL_Rect *sdlSrc = nullptr;
|
||||
SDL_Rect srcRect;
|
||||
|
||||
if (source)
|
||||
{
|
||||
srcRect = source.toSDL();
|
||||
sdlSrc = &srcRect;
|
||||
}
|
||||
|
||||
SDL_RenderCopy(getSDLRenderer(), texture, sdlSrc, &sdlDest);
|
||||
}
|
||||
//------------------------------------------------------------
|
||||
/* Set the current drawing color */
|
||||
void RendererManager::setDrawColor(const Color &color) const
|
||||
{
|
||||
SDL_SetRenderDrawColor(getSDLRenderer(),
|
||||
color.r(),
|
||||
color.g(),
|
||||
color.b(),
|
||||
color.a());
|
||||
}
|
||||
//------------------------------------------------------------
|
||||
/* Set the clipping rectangle (nullptr to disable) */
|
||||
void RendererManager::setClipRect(const Rect *rect) const
|
||||
{
|
||||
if (rect)
|
||||
{
|
||||
const SDL_Rect sdlRect = rect->toSDL();
|
||||
SDL_RenderSetClipRect(getSDLRenderer(), &sdlRect);
|
||||
}
|
||||
else
|
||||
{
|
||||
SDL_RenderSetClipRect(getSDLRenderer(), nullptr);
|
||||
}
|
||||
}
|
||||
//------------------------------------------------------------
|
||||
/* Get the current window size in pixels */
|
||||
SDL_Point RendererManager::getWindowSize() const
|
||||
{
|
||||
int w, h;
|
||||
SDL_GetRendererOutputSize(getSDLRenderer(), &w, &h);
|
||||
return { w, h };
|
||||
}
|
||||
//------------------------------------------------------------
|
||||
/* Render text to a texture for drawing */
|
||||
Texture RendererManager::renderTextTexture(const std::string &text, TTF_Font *font, const Color &color) const
|
||||
{
|
||||
if (text.empty())
|
||||
return { nullptr, SDL_DestroyTexture };
|
||||
|
||||
const SDL_Color sdlColor = { color.r(), color.g(), color.b(), color.a() };
|
||||
SDL_Surface *surface = TTF_RenderText_Blended(font, text.c_str(), sdlColor);
|
||||
if (!surface)
|
||||
{
|
||||
std::cerr << "Failed to render text surface: " << TTF_GetError() << std::endl;
|
||||
return { nullptr, SDL_DestroyTexture };
|
||||
}
|
||||
|
||||
SDL_Texture *texture = SDL_CreateTextureFromSurface(getSDLRenderer(), surface);
|
||||
SDL_FreeSurface(surface);
|
||||
|
||||
if (!texture)
|
||||
std::cerr << "Failed to create texture from text: " << SDL_GetError() << std::endl;
|
||||
|
||||
return { texture, SDL_DestroyTexture };
|
||||
}
|
||||
//------------------------------------------------------------
|
||||
64
src/quokka_gfx/core/renderer/rendererManager.h
Normal file
@@ -0,0 +1,64 @@
|
||||
#pragma once
|
||||
#include "../defs.h"
|
||||
#include "../../utils/color.h"
|
||||
#include "../../utils/point.h"
|
||||
#include "../../utils/rect.h"
|
||||
|
||||
#include <SDL2/SDL.h>
|
||||
#include <string>
|
||||
|
||||
namespace quokka_gfx
|
||||
{
|
||||
class Application;
|
||||
//------------------------------------------------------------
|
||||
class RendererManager
|
||||
{
|
||||
public:
|
||||
RendererManager() = delete; // Default constructor
|
||||
virtual ~RendererManager() = default; // Default destructor
|
||||
RendererManager(const RendererManager &obj) = delete; // Copy constructor
|
||||
RendererManager(RendererManager &&obj) = delete; // Move constructor
|
||||
RendererManager &operator=(const RendererManager &obj) = delete; // Copy assignment operator
|
||||
RendererManager &operator=(RendererManager &&obj) = delete; // Move assignment operator
|
||||
|
||||
explicit RendererManager(Application *app); // Constructor
|
||||
|
||||
[[nodiscard]] SDL_Renderer *getSDLRenderer() const; // Get the underlying SDL_Renderer
|
||||
|
||||
void present() const; // Present the rendered content to the screen
|
||||
|
||||
void clear(const Color &color = Black) const; // Clear the renderer with a specific color
|
||||
|
||||
// Drawing primitives
|
||||
void drawRect(const Rect &rect, const Color &color, bool filled = false) const; // Draw a rectangle
|
||||
void drawLine(const Point &start, const Point &end, const Color &color) const; // Draw a line between two points
|
||||
void drawPoint(const Point &point, const Color &color) const; // Draw a single point
|
||||
|
||||
// Text rendering
|
||||
void drawText(const std::string &text, // Draw text at a specific position
|
||||
const HashID &fontID,
|
||||
const Point &point,
|
||||
const Color &color = White,
|
||||
int fontSize = 24) const;
|
||||
void drawTextCentered(const std::string &text, // Draw text centered within a rectangle
|
||||
const HashID &fontID,
|
||||
const Rect &rect,
|
||||
const Color &color = White,
|
||||
int fontSize = 24) const;
|
||||
|
||||
// Texture management
|
||||
void drawTexture(SDL_Texture *texture, const Rect &dest, const Rect &source = {}) const; // Draw a texture at a specific position and size
|
||||
|
||||
// Utilities
|
||||
void setDrawColor(const Color &color) const; // Set the current drawing color
|
||||
void setClipRect(const Rect *rect) const; // Set the clipping rectangle (nullptr to disable)
|
||||
[[nodiscard]] SDL_Point getWindowSize() const; // Get the current window size in pixels
|
||||
|
||||
protected:
|
||||
Application *m_app = nullptr;
|
||||
|
||||
private:
|
||||
Texture renderTextTexture(const std::string &text, TTF_Font *font, const Color &color) const; // Render text to a texture for drawing
|
||||
};
|
||||
//------------------------------------------------------------
|
||||
} // namespace quokka_gfx
|
||||
61
src/quokka_gfx/core/screens/screen.h
Normal file
@@ -0,0 +1,61 @@
|
||||
#pragma once
|
||||
|
||||
#include "../application.h"
|
||||
#include "../events/eventBus.h"
|
||||
#include "../events/inputManager.h"
|
||||
#include "quokka_gfx/utils/rect.h"
|
||||
|
||||
namespace quokka_gfx
|
||||
{
|
||||
class RendererManager;
|
||||
//------------------------------------------------------------
|
||||
class Screen : public Listener
|
||||
{
|
||||
public:
|
||||
Screen() = delete; // Default constructor
|
||||
virtual ~Screen() = default; // Default destructor
|
||||
Screen(const Screen &obj) = delete; // Copy constructor
|
||||
Screen(Screen &&obj) = delete; // Move constructor
|
||||
Screen &operator=(const Screen &obj) = delete; // Copy assignment operator
|
||||
Screen &operator=(Screen &&obj) = delete; // Move assignment operator
|
||||
|
||||
explicit Screen(Application *app); // Constructor
|
||||
|
||||
virtual void on_enter() = 0; // Called when the screen is entered
|
||||
virtual void on_exit() = 0; // Called when the screen is exited
|
||||
virtual void handleEvents() = 0; // Manage events
|
||||
virtual void update(const double deltaTime) = 0; // Update the logic of the screen
|
||||
virtual void render(RendererManager *renderer) = 0; // Render the screen
|
||||
|
||||
[[nodiscard]] InputManager *getInputManager() const; // Get the input manager for handling events
|
||||
|
||||
Rect getScreenRect() const; // Return the window size as a rectangle for easy rendering and event handling
|
||||
|
||||
protected:
|
||||
Application *m_app = nullptr; // Pointer to the application
|
||||
};
|
||||
//------------------------------------------------------------
|
||||
/* Constructor */
|
||||
inline Screen::Screen(Application *app)
|
||||
{
|
||||
m_app = app;
|
||||
}
|
||||
//------------------------------------------------------------
|
||||
/* Get the input manager for handling events */
|
||||
inline InputManager *Screen::getInputManager() const
|
||||
{
|
||||
return m_app->m_inputManager.get();
|
||||
}
|
||||
//------------------------------------------------------------
|
||||
/* Return the window size as a rectangle for easy rendering and event handling */
|
||||
inline Rect Screen::getScreenRect() const
|
||||
{
|
||||
if (!m_app || !m_app->m_window)
|
||||
return {};
|
||||
|
||||
int width, height;
|
||||
SDL_GetWindowSize(m_app->m_window, &width, &height);
|
||||
return Rect(0, 0, width, height);
|
||||
}
|
||||
//------------------------------------------------------------
|
||||
} // namespace quokka_gfx
|
||||
96
src/quokka_gfx/core/screens/screenManager.cpp
Normal file
@@ -0,0 +1,96 @@
|
||||
#include "screenManager.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace quokka_gfx;
|
||||
//------------------------------------------------------------
|
||||
/* Default constructor */
|
||||
ScreenManager::ScreenManager()
|
||||
: m_screenTransition(this)
|
||||
{
|
||||
// Nothing to do
|
||||
}
|
||||
//------------------------------------------------------------
|
||||
/* Set the current screen, replacing any existing screens on the stack */
|
||||
void ScreenManager::setScreen(std::unique_ptr<Screen> screen)
|
||||
{
|
||||
// Clear the stack of screens
|
||||
while (!m_screenStack.empty())
|
||||
{
|
||||
// Call on_exit for the current screen
|
||||
m_screenStack.top()->on_exit();
|
||||
|
||||
// Remove the current screen
|
||||
m_screenStack.pop();
|
||||
}
|
||||
|
||||
// Insert the new screen on the stack
|
||||
m_screenStack.push(std::move(screen));
|
||||
|
||||
// Call on_enter for the new screen
|
||||
if (!m_screenStack.empty())
|
||||
m_screenStack.top()->on_enter();
|
||||
}
|
||||
//------------------------------------------------------------
|
||||
/* Push a new screen onto the stack */
|
||||
void ScreenManager::pushScreen(std::unique_ptr<Screen> screen)
|
||||
{
|
||||
// Insert the new screen on top of the stack
|
||||
m_screenStack.push(std::move(screen));
|
||||
|
||||
// Call on_enter for the new screen
|
||||
if (!m_screenStack.empty())
|
||||
m_screenStack.top()->on_enter();
|
||||
}
|
||||
//------------------------------------------------------------
|
||||
/* Pop the current screen from the stack */
|
||||
void ScreenManager::popScreen()
|
||||
{
|
||||
if (!m_screenStack.empty())
|
||||
{
|
||||
// Call on_exit for the current screen
|
||||
m_screenStack.top()->on_exit();
|
||||
|
||||
// Remove the current screen
|
||||
m_screenStack.pop();
|
||||
}
|
||||
}
|
||||
//------------------------------------------------------------
|
||||
/* Handle events for the current screen */
|
||||
void ScreenManager::handleEvents()
|
||||
{
|
||||
// If a screen transition is in progress, block event handling for the current screen
|
||||
if (m_screenTransition.getState() != ScreenTransition::State::None)
|
||||
return;
|
||||
|
||||
if (!m_screenStack.empty())
|
||||
m_screenStack.top()->handleEvents();
|
||||
}
|
||||
//------------------------------------------------------------
|
||||
/* Update the current screen */
|
||||
void ScreenManager::update(const double deltaTime)
|
||||
{
|
||||
if (!m_screenStack.empty())
|
||||
m_screenStack.top()->update(deltaTime);
|
||||
|
||||
// Update the screen transition
|
||||
m_screenTransition.update(deltaTime);
|
||||
}
|
||||
//------------------------------------------------------------
|
||||
/* Render the current screen */
|
||||
void ScreenManager::render(RendererManager *renderer)
|
||||
{
|
||||
if (!m_screenStack.empty())
|
||||
m_screenStack.top()->render(renderer);
|
||||
|
||||
// Render the screen transition
|
||||
m_screenTransition.render(renderer);
|
||||
}
|
||||
//------------------------------------------------------------
|
||||
/* Get the current screen */
|
||||
Screen *ScreenManager::getCurrentScreen() const
|
||||
{
|
||||
if (!m_screenStack.empty())
|
||||
return m_screenStack.top().get();
|
||||
return nullptr;
|
||||
}
|
||||
//------------------------------------------------------------
|
||||
39
src/quokka_gfx/core/screens/screenManager.h
Normal file
@@ -0,0 +1,39 @@
|
||||
#pragma once
|
||||
#include "screen.h"
|
||||
#include "screenTransition.h"
|
||||
|
||||
#include <memory>
|
||||
#include <stack>
|
||||
|
||||
namespace quokka_gfx
|
||||
{
|
||||
class RendererManager;
|
||||
//------------------------------------------------------------
|
||||
class ScreenManager
|
||||
{
|
||||
friend class ScreenTransition;
|
||||
|
||||
public:
|
||||
ScreenManager(); // Default constructor
|
||||
virtual ~ScreenManager() = default; // Default destructor
|
||||
ScreenManager(const ScreenManager &obj) = delete; // Copy constructor
|
||||
ScreenManager(ScreenManager &&obj) = delete; // Move constructor
|
||||
ScreenManager &operator=(const ScreenManager &obj) = delete; // Copy assignment operator
|
||||
ScreenManager &operator=(ScreenManager &&obj) = delete; // Move assignment operator
|
||||
|
||||
void setScreen(std::unique_ptr<Screen> screen); // Set the current screen, replacing any existing screens on the stack
|
||||
void pushScreen(std::unique_ptr<Screen> screen); // Push a new screen onto the stack
|
||||
void popScreen(); // Pop the current screen from the stack
|
||||
|
||||
void handleEvents(); // Handle events for the current screen
|
||||
void update(double deltaTime); // Update the current screen
|
||||
void render(RendererManager *renderer); // Render the current screen
|
||||
|
||||
[[nodiscard]] Screen *getCurrentScreen() const; // Get the current screen
|
||||
|
||||
protected:
|
||||
ScreenTransition m_screenTransition; // Screen transition manager
|
||||
std::stack<std::unique_ptr<Screen>> m_screenStack; // Stack of screens
|
||||
};
|
||||
//------------------------------------------------------------
|
||||
} // namespace quokka_gfx
|
||||
33
src/quokka_gfx/core/screens/screenTransition.cpp
Normal file
@@ -0,0 +1,33 @@
|
||||
#include "screenManager.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace quokka_gfx;
|
||||
//------------------------------------------------------------
|
||||
/* Constructor */
|
||||
ScreenTransition::ScreenTransition(ScreenManager *screenManager)
|
||||
{
|
||||
m_screenManager = screenManager;
|
||||
}
|
||||
//------------------------------------------------------------
|
||||
/* Get the current state of the screen transition */
|
||||
ScreenTransition::State ScreenTransition::getState() const
|
||||
{
|
||||
return m_state;
|
||||
}
|
||||
//------------------------------------------------------------
|
||||
/* Get the progress of the screen transition (0.0 to 1.0) */
|
||||
float ScreenTransition::getProgress() const
|
||||
{
|
||||
return m_progress;
|
||||
}
|
||||
//------------------------------------------------------------
|
||||
/* Manage the transition between screens, updating the current screen */
|
||||
void ScreenTransition::update(double deltaTime)
|
||||
{
|
||||
}
|
||||
//------------------------------------------------------------
|
||||
/* Render the transition between screens, rendering the current screen */
|
||||
void ScreenTransition::render(RendererManager *renderer)
|
||||
{
|
||||
}
|
||||
//------------------------------------------------------------
|
||||
52
src/quokka_gfx/core/screens/screenTransition.h
Normal file
@@ -0,0 +1,52 @@
|
||||
#pragma once
|
||||
#include "../../utils/color.h"
|
||||
#include "screen.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace quokka_gfx
|
||||
{
|
||||
class RendererManager;
|
||||
//------------------------------------------------------------
|
||||
class ScreenTransition
|
||||
{
|
||||
static constexpr Color BackgroundColor{ 30, 30, 30 };
|
||||
|
||||
public:
|
||||
enum class State : uint8_t
|
||||
{
|
||||
None,
|
||||
TransitioningIn,
|
||||
TransitioningOut
|
||||
};
|
||||
|
||||
public:
|
||||
ScreenTransition() = delete; // Default constructor
|
||||
virtual ~ScreenTransition() = default; // Default destructor
|
||||
ScreenTransition(const ScreenTransition &obj) = delete; // Copy constructor
|
||||
ScreenTransition(ScreenTransition &&obj) = delete; // Move constructor
|
||||
ScreenTransition &operator=(const ScreenTransition &obj) = delete; // Copy assignment operator
|
||||
ScreenTransition &operator=(ScreenTransition &&obj) = delete; // Move assignment operator
|
||||
|
||||
explicit ScreenTransition(ScreenManager *screenManager); // Constructor
|
||||
|
||||
// void setScreen(std::unique_ptr<Screen> screen); // Set the current screen, replacing any existing screens on the stack
|
||||
// void pushScreen(std::unique_ptr<Screen> screen); // Push a new screen onto the stack
|
||||
// void popScreen(); // Pop the current screen from the stack
|
||||
|
||||
[[nodiscard]] State getState() const; // Get the current state of the screen transition
|
||||
[[nodiscard]] float getProgress() const; // Get the progress of the screen transition (0.0 to 1.0)
|
||||
|
||||
void update(double deltaTime); // Manage the transition between screens, updating the current screen
|
||||
void render(RendererManager *renderer); // Render the transition between screens, rendering the current screen
|
||||
|
||||
//[[nodiscard]] Screen *getCurrentScreen() const; // Get the current screen
|
||||
|
||||
protected:
|
||||
ScreenManager *m_screenManager = nullptr; // Pointer to the screen manager
|
||||
|
||||
State m_state = State::None; // Current state of the screen transition
|
||||
float m_progress = 0.0f; // Progress of the screen transition (0.0 to 1.0)
|
||||
};
|
||||
//------------------------------------------------------------
|
||||
} // namespace quokka_gfx
|
||||
26
src/quokka_gfx/quokka_gfx.h
Normal file
@@ -0,0 +1,26 @@
|
||||
/**
|
||||
* QuokkaGFX - Lightweight SDL2 wrapper - umbrella header
|
||||
*
|
||||
* Single header include for easy integration.
|
||||
* Usage: #include "quokka_gfx/quokka_gfx.h"
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
// Core classes
|
||||
#include "core/application.h"
|
||||
#include "core/assets/assetManager.h"
|
||||
#include "core/defs.h"
|
||||
#include "core/events/inputManager.h"
|
||||
#include "core/renderer/rendererManager.h"
|
||||
#include "core/screens/screen.h"
|
||||
#include "core/screens/screenManager.h"
|
||||
|
||||
// Utilities
|
||||
#include "utils/color.h"
|
||||
#include "utils/point.h"
|
||||
#include "utils/rect.h"
|
||||
|
||||
// SDL2 main headers
|
||||
#include <SDL2/SDL.h>
|
||||
#include <SDL2/SDL_ttf.h>
|
||||
92
src/quokka_gfx/utils/color.h
Normal file
@@ -0,0 +1,92 @@
|
||||
#pragma once
|
||||
#include <SDL2/SDL.h>
|
||||
#include <cstdint>
|
||||
|
||||
namespace quokka_gfx
|
||||
{
|
||||
//------------------------------------------------------------
|
||||
class Color
|
||||
{
|
||||
public:
|
||||
constexpr Color() = default; // Default constructor
|
||||
virtual ~Color() = default; // Default destructor
|
||||
Color(const Color &obj) = default; // Copy constructor
|
||||
Color(Color &&obj) = default; // Move constructor
|
||||
Color &operator=(const Color &obj) = default; // Copy assignment operator
|
||||
Color &operator=(Color &&obj) = default; // Move assignment operator
|
||||
|
||||
constexpr explicit Color(uint32_t color = 0xFFFFFFFF); // Constructor
|
||||
constexpr explicit Color(uint8_t red = 255, // Constructor
|
||||
uint8_t green = 255,
|
||||
uint8_t blue = 255,
|
||||
uint8_t alpha = 255);
|
||||
|
||||
[[nodiscard]] uint32_t operator()() const; // Returns the color as a single uint32_t in ARGB format
|
||||
[[nodiscard]] uint8_t r() const; // Returns the red component
|
||||
[[nodiscard]] uint8_t g() const; // Returns the green component
|
||||
[[nodiscard]] uint8_t b() const; // Returns the blue component
|
||||
[[nodiscard]] uint8_t a() const; // Returns the alpha component
|
||||
|
||||
protected:
|
||||
uint32_t m_color = 0xFFFFFFFF; // Color value in ARGB format for fast comparisons and hashing
|
||||
};
|
||||
//------------------------------------------------------------
|
||||
/* Constructor */
|
||||
inline constexpr Color::Color(const uint32_t color)
|
||||
{
|
||||
m_color = color;
|
||||
}
|
||||
//------------------------------------------------------------
|
||||
/* Constructor */
|
||||
inline constexpr Color::Color(const uint8_t red, const uint8_t green, const uint8_t blue, const uint8_t alpha)
|
||||
{
|
||||
m_color = (static_cast<uint32_t>(alpha) << 24) |
|
||||
(static_cast<uint32_t>(red) << 16) |
|
||||
(static_cast<uint32_t>(green) << 8) |
|
||||
static_cast<uint32_t>(blue);
|
||||
}
|
||||
//------------------------------------------------------------
|
||||
/* Returns the color as a single uint32_t in ARGB format */
|
||||
inline uint32_t Color::operator()() const
|
||||
{
|
||||
return m_color;
|
||||
}
|
||||
//------------------------------------------------------------
|
||||
/* Returns the red component */
|
||||
inline uint8_t Color::r() const
|
||||
{
|
||||
return (m_color >> 16) & 0xFF;
|
||||
}
|
||||
//------------------------------------------------------------
|
||||
/* Returns the green component */
|
||||
inline uint8_t Color::g() const
|
||||
{
|
||||
return (m_color >> 8) & 0xFF;
|
||||
}
|
||||
//------------------------------------------------------------
|
||||
/* Returns the blue component */
|
||||
inline uint8_t Color::b() const
|
||||
{
|
||||
return m_color & 0xFF;
|
||||
}
|
||||
//------------------------------------------------------------
|
||||
/* Returns the alpha component */
|
||||
inline uint8_t Color::a() const
|
||||
{
|
||||
return (m_color >> 24) & 0xFF;
|
||||
}
|
||||
//------------------------------------------------------------
|
||||
|
||||
/* --- */
|
||||
|
||||
//------------------------------------------------------------
|
||||
inline constexpr Color White{ 255, 255, 255, 255 };
|
||||
inline constexpr Color Black{ 0, 0, 0, 255 };
|
||||
inline constexpr Color Red{ 255, 0, 0, 255 };
|
||||
inline constexpr Color Green{ 0, 255, 0, 255 };
|
||||
inline constexpr Color Blue{ 0, 0, 255, 255 };
|
||||
inline constexpr Color Yellow{ 255, 255, 0, 255 };
|
||||
inline constexpr Color Gray{ 128, 128, 128, 255 };
|
||||
inline constexpr Color DarkGray{ 64, 64, 64, 255 };
|
||||
//------------------------------------------------------------
|
||||
} // namespace quokka_gfx
|
||||
46
src/quokka_gfx/utils/point.h
Normal file
@@ -0,0 +1,46 @@
|
||||
#pragma once
|
||||
#include <SDL2/SDL.h>
|
||||
|
||||
namespace quokka_gfx
|
||||
{
|
||||
//------------------------------------------------------------
|
||||
class Point
|
||||
{
|
||||
public:
|
||||
Point() = default; // Default constructor
|
||||
virtual ~Point() = default; // Default destructor
|
||||
Point(const Point &obj) = default; // Copy constructor
|
||||
Point(Point &&obj) = default; // Move constructor
|
||||
Point &operator=(const Point &obj) = default; // Copy assignment operator
|
||||
Point &operator=(Point &&obj) = default; // Move assignment operator
|
||||
|
||||
explicit Point(int xPos = 0, // Constructor
|
||||
int yPos = 0);
|
||||
|
||||
bool operator==(const Point &point) const; // Equality operator
|
||||
|
||||
[[nodiscard]] SDL_Point toSDL() const; // Convert to SDL_Point for rendering
|
||||
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
};
|
||||
//------------------------------------------------------------
|
||||
/* Constructor */
|
||||
inline Point::Point(const int xPos, const int yPos)
|
||||
{
|
||||
x = xPos;
|
||||
y = yPos;
|
||||
}
|
||||
//------------------------------------------------------------
|
||||
inline bool Point::operator==(const Point &point) const
|
||||
{
|
||||
return x == point.x && y == point.y;
|
||||
}
|
||||
//------------------------------------------------------------
|
||||
/* Convert to SDL_Point for rendering */
|
||||
inline SDL_Point Point::toSDL() const
|
||||
{
|
||||
return { x, y };
|
||||
}
|
||||
//------------------------------------------------------------
|
||||
} // namespace quokka_gfx
|
||||