Compare commits

...

5 Commits

Author SHA1 Message Date
2c240ad7e3 isloate sdl logic to window class 2026-04-12 16:41:27 -05:00
779c51c2f8 fix sdl3 linking + comments 2026-04-12 14:18:55 -05:00
f032f152a9 bugfix: debug mask 2026-04-12 11:08:32 -05:00
6d34dfc58f test vulkan instance creation 2026-04-12 00:19:38 -05:00
b196c97cf0 checkpoint 2026-04-11 23:57:57 -05:00
11 changed files with 174 additions and 25 deletions

1
.gitignore vendored
View File

@@ -1,2 +1,3 @@
.vscode/*
build/* build/*

View File

@@ -15,7 +15,12 @@ endif()
set(CMAKE_INSTALL_PREFIX ${PROJECT_SOURCE_DIR}) set(CMAKE_INSTALL_PREFIX ${PROJECT_SOURCE_DIR})
#add_subdirectory(src) #add_subdirectory(src)
set(SDL3_DIR "${SDL3_PATH}/cmake")
set(Vulkan_INCLUDE_DIR "${VULKAN_PATH}/Include")
set(Vulkan_LIBRARY "${VULKAN_PATH}/Lib/vulkan-1.lib")
find_package(Vulkan REQUIRED)
set(SDL3_DIR "${VULKAN_PATH}/cmake")
find_package(SDL3 REQUIRED) find_package(SDL3 REQUIRED)
# TODO: cascade cmakelists.txt # TODO: cascade cmakelists.txt
@@ -23,15 +28,17 @@ add_executable(ouros
src/main.cpp src/main.cpp
src/app/App.cpp src/app/App.cpp
src/app/Window.cpp src/app/Window.cpp
src/engine/Engine.cpp
) )
target_include_directories(ouros PRIVATE target_include_directories(ouros PRIVATE
"${CMAKE_CURRENT_SOURCE_DIR}/" "${CMAKE_CURRENT_SOURCE_DIR}/"
"${CMAKE_CURRENT_SOURCE_DIR}/src" "${CMAKE_CURRENT_SOURCE_DIR}/src"
"${VULKAN_PATH}/Include"
) )
if(WIN32) if(WIN32)
set(SDL3_DLL "${SDL3_PATH}/lib/x64/SDL3.dll") # assuming youre not arm or 32 bit set(SDL3_DLL "${VULKAN_PATH}/Bin/SDL3.dll")
add_custom_command(TARGET ouros POST_BUILD add_custom_command(TARGET ouros POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different COMMAND ${CMAKE_COMMAND} -E copy_if_different
"${SDL3_DLL}" "${SDL3_DLL}"
@@ -41,4 +48,5 @@ endif()
target_link_libraries(ouros PRIVATE target_link_libraries(ouros PRIVATE
SDL3::SDL3 SDL3::SDL3
Vulkan::Vulkan
) )

View File

@@ -43,16 +43,22 @@ Below is beyond Sascha's guide, but available elsewhere on his github. These are
- CMake (im using 4.0.0) - CMake (im using 4.0.0)
- C++20 compatible compiler (I use g++12 or MSVC++17) (probably works with mingw but I haven't tested it myself) - C++20 compatible compiler (I use g++12 or MSVC++17) (probably works with mingw but I haven't tested it myself)
- Vulkan compatible gpu drivers (tested with an RTX3070 and an R9700) - Vulkan compatible gpu drivers (tested with an RTX3070 and an R9700)
- SDL3 (im using version 3.4.4) - Vulkan SDK (https://vulkan.lunarg.com/sdk/home)
- SDL3*
- VOC*
- GLM*
- Will add more as the project grows - Will add more as the project grows
*packaged with the Vulkan SDK
### Clone respository: ### Clone respository:
```bash ```bash
$ git clone https://git.vxbard.net/homeburger/ouros.git --recursive $ git clone https://git.vxbard.net/homeburger/ouros.git --recursive
``` ```
### Configure and build project: ### Configure and build project:
```bash ```bash
$ cmake -S . -B build -DSDL3_PATH="${SDL3_INSTALL_PATH}" # either set this variable or substitute it in $ cmake -S . -B build \
-DVULKAN_PATH="${VULKAN_INSTALL_PATH}" # either set this variable or substitute it in
$ cmake --build build -j $ cmake --build build -j
``` ```
### Execute application: ### Execute application:
@@ -63,10 +69,11 @@ $ ./build/ouros
``` ```
For control on debugging: For control on debugging:
```bash ```bash
$ ./build/ouros --debug 0b00111111 $ ./build/ouros --debug=0b00111111
``` ```
where each bit in the mask corresponds to a debug level, in order: unused, unused, fatal, trace, error, warning, notice, and info. `0b1111111` enables all debug messages. where each bit in the mask corresponds to a debug level, in order: unused, unused, fatal, trace, error, warning, notice, and info. `0b1111111` enables all debug messages.
## Additional Resources ## Additional Resources
- https://howtovulkan.com/ - https://howtovulkan.com/, primary guide, most up-to-date (2026, Vulkan v1.4)
- https://vkguide.dev/, Vulkan v1.3, but provides a lot of guidance on a more robustly architectured Vulkan app
- Will add more as I use them - Will add more as I use them

View File

@@ -1,6 +1,9 @@
#include "App.hpp" #include "App.hpp"
#include <thread>
#include <chrono>
#include "utils/utils.hpp" #include "utils/utils.hpp"
App::App() { App::App() {
@@ -16,6 +19,7 @@ void App::init() {
utils::debugPrint(__FUNCTION__, __LINE__, "Init app.", utils::DebugLevel::Trace); utils::debugPrint(__FUNCTION__, __LINE__, "Init app.", utils::DebugLevel::Trace);
window_ = new Window(); window_ = new Window();
engine_ = new Engine(window_);
} }
@@ -23,17 +27,25 @@ int App::run() {
utils::debugPrint(__FUNCTION__, __LINE__, "Run app.", utils::DebugLevel::Trace); utils::debugPrint(__FUNCTION__, __LINE__, "Run app.", utils::DebugLevel::Trace);
bool quit = false;
while (!quit) {
// app loop for as long as the window is open
// other threads might be able to change quit to true to auto close
SDL_Event event; SDL_Event event;
while(SDL_PollEvent(&event)) { // TODO: pass event handling to window while (window_->open()) {
if(event.type == SDL_EVENT_QUIT ) { // app loop for as long as the window is open
quit = true;
// pass events to the window
while(SDL_PollEvent(&event) != 0) {
window_->handleEvent(event);
} }
// pass vulkan handling to engine
// call engine.render() or something
// engine has a pointer to window so can handle pushing to the screen
if(window_->rendering()) {
engine_->draw();
} else {
std::this_thread::sleep_for(std::chrono::milliseconds(100)); // wait until the window is visible again
} }
} }
// SDL teardown handled in window destructor // SDL teardown handled in window destructor

View File

@@ -2,6 +2,7 @@
#pragma once #pragma once
#include "Window.hpp" #include "Window.hpp"
#include "engine/Engine.hpp"
class App { class App {
@@ -10,7 +11,7 @@ public:
App(); App();
~App() = default; ~App() = default;
// excecute, called from main() // excecute, called from main(). returns after window closes
int run(); int run();
private: private:
@@ -19,5 +20,8 @@ private:
void init(); void init();
Window* window_; Window* window_;
Engine* engine_;
bool rendering_ = true;
}; };

View File

@@ -1,6 +1,8 @@
#include "Window.hpp" #include "Window.hpp"
#include <SDL3/SDL_events.h>
Window::Window() { Window::Window() {
(void)init(); (void)init();
@@ -9,15 +11,34 @@ Window::Window() {
Window::~Window() { Window::~Window() {
SDL_DestroyWindow(window_); SDL_DestroyWindow(sdlWindow_);
SDL_Quit(); SDL_Quit();
} }
int Window::init() { int Window::init() {
window_ = SDL_CreateWindow("How to Vulkan", 1280u, 720u, SDL_WINDOW_VULKAN | SDL_WINDOW_RESIZABLE); sdlWindow_ = SDL_CreateWindow("Ouros: Vulkan", 1280u, 720u, SDL_WINDOW_VULKAN | SDL_WINDOW_RESIZABLE);
return (window_ == nullptr); if(sdlWindow_ != nullptr) {
rendering_ = true;
open_ = true;
return 0;
} else {
return -1;
}
} }
void Window::handleEvent(SDL_Event& event) {
if(event.type == SDL_EVENT_QUIT ) {
open_ = false;
}
if(event.type == SDL_EVENT_WINDOW_MINIMIZED) {
rendering_ = false;
} else if(event.type == SDL_EVENT_WINDOW_RESTORED) {
rendering_ = true;
}
}

View File

@@ -2,7 +2,7 @@
#pragma once #pragma once
#include "SDL3/SDL.h" #include "SDL3/SDL.h"
#include "SDL3/SDL_Vulkan.h" #include "SDL3/SDL_vulkan.h"
// reference: https://wiki.libsdl.org/SDL3/SDL_CreateWindow // reference: https://wiki.libsdl.org/SDL3/SDL_CreateWindow
@@ -13,10 +13,22 @@ public:
Window(); Window();
~Window(); ~Window();
void handleEvent(SDL_Event& event);
bool rendering() { return rendering_; }
bool open() { return open_; }
private: private:
// launches window
int init(); int init();
SDL_Window* window_; // this window class will eventually hold mouse, keyboard, audio, etc. interfaces, like an SDL3 hub
// app will be able to attach callbacks for mouse and keyboard events
SDL_Window* sdlWindow_;
bool rendering_ = false;
bool open_ = false;
}; };

50
src/engine/Engine.cpp Normal file
View File

@@ -0,0 +1,50 @@
#include "Engine.hpp"
#include "vulkan/vulkan.h"
#include "utils/utils.hpp"
Engine::Engine(Window* window): window_(window) {
init();
}
void Engine::init() {
VkApplicationInfo appInfo {
.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,
.pApplicationName = "How to Vulkan",
.apiVersion = VK_API_VERSION_1_3
};
uint32_t instanceExtensionsCount = 0;
char const* const* instanceExtensions{ SDL_Vulkan_GetInstanceExtensions(&instanceExtensionsCount) };
VkInstanceCreateInfo instanceCI {
.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
.pApplicationInfo = &appInfo,
.enabledExtensionCount = instanceExtensionsCount,
.ppEnabledExtensionNames = instanceExtensions,
};
VkInstance instance;
if(vkCreateInstance(&instanceCI, nullptr, &instance) == VK_SUCCESS) {
utils::debugPrint(__FUNCTION__, __LINE__, "Vulkan instance successfully created.", utils::DebugLevel::Info);
} else {
utils::debugPrint(__FUNCTION__, __LINE__, "Error creating Vulkan instance", utils::DebugLevel::Error);
}
// next steps:
// device selection and setup
// queue creation
// vulkan memory allocator
// create vulkan surface
// attach surface to window
}
void Engine::draw() {
}

27
src/engine/Engine.hpp Normal file
View File

@@ -0,0 +1,27 @@
#pragma once
#include "app/Window.hpp"
#define VK_USE_PLATFORM_WIN32_KHR 1
class Engine {
public:
Engine(Window* window);
~Engine() = default;
void init();
// draw is called every render iteration in that while loop
void draw();
private:
// might get rid of this
// TODO: smart pointers probably would be smart
Window* window_;
};

View File

@@ -22,6 +22,7 @@ int main(int argc, char *argv[]) {
// maybe do some exceptions here // maybe do some exceptions here
App app = App(); App app = App();
// executes for as long as the window is open
return app.run(); return app.run();
} }

View File

@@ -5,9 +5,10 @@
#include <iomanip> #include <iomanip>
#include <string> #include <string>
// TODO: might move a lot of this into a debug.h file // TODO: might move a lot of this into a debug.hpp file
// TODO: logging ? but i dont care enough // TODO: logging ? but i dont care enough
// do i classify this up? global static functions kinda scare me but i mean otrherwise itll be a global singleton so idk
namespace utils { namespace utils {
enum DebugLevel : size_t { enum DebugLevel : size_t {
@@ -31,27 +32,32 @@ namespace utils {
"Extra1", "Extra1",
"Extra2" "Extra2"
}; };
// the idea is to have a debug bitmask, maybe 8 bits wide, where the bits can be set via compiler flags
// stores the input that determines which debug statements to filter
inline uint8_t debugMask; inline uint8_t debugMask;
// print to standard output in a normalized format, includes the trace and debug level
static void debugPrint(const char* function, int line, std::string message, size_t debugLevel) { static void debugPrint(const char* function, int line, std::string message, size_t debugLevel) {
if(!(debugMask >> debugLevel)) return; // then ignore this debug level if(!((debugMask >> debugLevel) & 1)) return; // then ignore this debug level
std::cout << "[ " << std::left << std::setw(16) << function << ": " << std::right << std::setw(4) << line << ", " << std::left << std::setw(8) << debugTypeStrings[debugLevel] << " ] " << message << std::endl; std::cout << "[ " << std::left << std::setw(16) << function << ": " << std::right << std::setw(4) << line << ", " << std::left << std::setw(8) << debugTypeStrings[debugLevel] << " ] " << message << std::endl;
// TODO: add timestamps
return; return;
} }
// process the input from the executable (0bxxxxxxxx)
static void parseDebugMaskString(std::string& debugMaskString) { static void parseDebugMaskString(std::string& debugMaskString) {
std::string value = debugMaskString; std::string value = debugMaskString;
if(value.rfind("0b", 0) == 0) { if(value.rfind("0b", 0) == 0) { // may allow other inputs in the future, this is just a binary byte
value = value.substr(2); // strip the binary literal identifier value = value.substr(2); // strip the binary literal identifier
debugMask = static_cast<uint8_t>(std::stoul(value, nullptr, 2)); // interpret a string as a uint
} else { } else {
std::cout << "Unsupported debug key." << std::endl; std::cout << "Unsupported debug key." << std::endl;
debugMask = 0; // disable debug statements
} }
debugMask = static_cast<uint8_t>(std::stoul(value, nullptr, 2)); // interpret a string as a uint
} }
} }