Pull request #2: CONGE-2 SDL WINDOW

Merge in CONGE/conjure-engine from CONGE-2-SDL-WINDOW to main

* commit 'b4a706ca12766ef09d17b0987835e3e53d08c086':
  CONGE-2 UPDATED CMAKE CONFIG
  CONGE-2 MADE THE MAC COMPILATION WORK
  CONGE-2 ADDED THE SHADER COMPILATION FROM GLSL TO SPIRV
  CONGE-2 Added better login in Demo1 and added error handling in VulkanContext.cpp
  CONGE-2 Reworked the API for the application to move more of the logic and initialization to the Engine and just have the application specifics in Demo1
  CONGE-2 Tweaked the logic to handle cases where presentation queue is not available instead of using #ifndef
  CONGE-2 REMOVED PRESENTATION QUEUE ON MAC
  CONGE-2 working window on windows. Need to test on mac
  CONGE-2 BUG with windows
  CONGE-2 added the basic setup to open a windows on mac and windows
  CONGE-2 : (WIP) adding the basic structure for the engine
  CONGE-1 fixed mac version
  CONGE-1 Special case between windows and mac. Will have to test if it's the case on other machines
  CONGE-1 This work in mac
  CONGE-1 Fixed some issues to make it cross compatible with clion, vscode and vs studio
  CONGE-1 Made it work for windows and mac for both release and debug
  CONGE-1 - added support for bat files and README.md
  CONGE-1 - Setup that works with conan and cmake
This commit is contained in:
Jimmy Tremblay-Bernier 01 2025-01-08 18:01:38 +00:00
commit 2f7176759f
29 changed files with 864 additions and 66 deletions

4
.gitignore vendored
View File

@ -10,4 +10,6 @@ CMakeCache.txt
build.ninja build.ninja
cmake_install.cmake cmake_install.cmake
CMakeCache.txt CMakeCache.txt
.ninja* CMakeUserPresets.json
.ninja*
.vs/

View File

@ -1,19 +1,37 @@
cmake_minimum_required(VERSION 3.29) cmake_minimum_required(VERSION 3.26)
project(ConjureEngineProject) project(ConjureEngineProject)
set(CMAKE_CXX_STANDARD 20)
# Set the default build type to Debug if not specified by the user # Set the default build type to Debug if not specified by the user
if(NOT CMAKE_BUILD_TYPE) if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Debug CACHE STRING "Build type (default Debug)" FORCE) set(CMAKE_BUILD_TYPE Debug CACHE STRING "Build type (default Debug)" FORCE)
endif() endif()
set(CONAN_DEPENDENCIES_DIR ${CMAKE_BINARY_DIR}/Conan) message(${CMAKE_BUILD_TYPE})
execute_process(COMMAND conan install ${CMAKE_SOURCE_DIR}/ConjureEngine --output-folder=${CONAN_DEPENDENCIES_DIR} --build=missing) # Set architecture
execute_process(COMMAND conan install ${CMAKE_SOURCE_DIR}/Demo1 --output-folder=${CONAN_DEPENDENCIES_DIR} --build=missing) if(NOT DEFINED ARCH)
set(ARCH x64) # Default to x64 architecture
endif()
set(CMAKE_TOOLCHAIN_FILE "${CONAN_DEPENDENCIES_DIR}/build/Release/generators/conan_toolchain.cmake" CACHE FILEPATH "Conan toolchain file") set(CMAKE_BINARY_DIR ${CMAKE_SOURCE_DIR}/build)
set(CMAKE_PREFIX_PATH "${CONAN_DEPENDENCIES_DIR}/build/Release/generators" ${CMAKE_PREFIX_PATH})
set(CMAKE_MODULE_PATH "${CONAN_DEPENDENCIES_DIR}/build/Release/generators" ${CMAKE_MODULE_PATH})
# Include the Conan-generated files
IF (WIN32)
list(APPEND CMAKE_PREFIX_PATH "${CMAKE_BINARY_DIR}/generators")
include("${CMAKE_BINARY_DIR}/generators/conan_toolchain.cmake")
ELSE()
list(APPEND CMAKE_PREFIX_PATH "${CMAKE_BINARY_DIR}/${CMAKE_BUILD_TYPE}/generators")
include("${CMAKE_BINARY_DIR}/${CMAKE_BUILD_TYPE}/generators/conan_toolchain.cmake")
ENDIF()
# Set common output directories
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/intermediates/${CMAKE_BUILD_TYPE}/${ARCH}/${PROJECT_NAME})
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/bin/${CMAKE_BUILD_TYPE}/${ARCH}/${PROJECT_NAME})
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/bin/${CMAKE_BUILD_TYPE}/${ARCH}/${PROJECT_NAME})
# Add subdirectories for engine and demo
add_subdirectory(./ConjureEngine) add_subdirectory(./ConjureEngine)
add_subdirectory(./Demo1) add_subdirectory(./Demo1)

8
Configure.bat Normal file
View File

@ -0,0 +1,8 @@
@REM Run Conan to install dependencies
rmdir build /s /q
@REM DEBUG
conan install . -s build_type=Debug --build=missing
@REM RELEASE
conan install . -s build_type=Release --build=missing

10
Configure.sh Executable file
View File

@ -0,0 +1,10 @@
#!/bin/bash
# Run Conan to install dependencies
rm -Rf build
# DEBUG
conan install . -s build_type=Debug --build=missing
# RELEASE
conan install . -s build_type=Release --build=missing

View File

@ -1,27 +1,36 @@
cmake_minimum_required(VERSION 3.29) cmake_minimum_required(VERSION 3.26)
set(CMAKE_CXX_STANDARD 20)
project(ConjureEngine) project(ConjureEngine)
set(CMAKE_CXX_STANDARD 17) set(HEADER_FILES
src/ConjureEngine/Application.h
src/ConjureEngine/ConjureEngine.h
src/ConjureEngine/VulkanContext.h
src/ConjureEngine/Window.h
)
# Set the architecture (assuming you're passing the architecture as a CMake variable) set(SOURCES_FILES
# Replace 'x64' with your system's architecture, or set this dynamically based on the system src/ConjureEngine/Application.cpp
if(NOT DEFINED ARCH) src/ConjureEngine/VulkanContext.cpp
set(ARCH x64) # You can change this to x86 or any other architecture you are targeting src/ConjureEngine/Window.cpp
endif() )
# Set common output directories
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/intermediates/${ARCH}/${PROJECT_NAME})
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/bin/${ARCH}/${PROJECT_NAME})
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/bin/${ARCH}/${PROJECT_NAME})
find_package(glm REQUIRED) find_package(glm REQUIRED)
find_package(SDL2 REQUIRED)
find_package(Vulkan REQUIRED) find_package(Vulkan REQUIRED)
add_library(${PROJECT_NAME} STATIC src/ConjureEngine/ConjureEngine.h src/ConjureEngine/ConjureEngine.cpp) add_library(${PROJECT_NAME} STATIC ${HEADER_FILES} ${SOURCES_FILES})
target_link_libraries(${PROJECT_NAME} ${CONAN_LIBS})
# Specify include directories # Specify include directories
target_include_directories(ConjureEngine PUBLIC include) target_include_directories(${PROJECT_NAME} PUBLIC include)
target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_BINARY_DIR}/include)
target_link_libraries(${PROJECT_NAME} SDL2::SDL2 glm::glm Vulkan::Vulkan)
target_precompile_headers(
${PROJECT_NAME}
PRIVATE
src/ConjureEngine/PCH.h
)

View File

@ -0,0 +1,41 @@
---
title: Rendering Pipeline Steps
---
stateDiagram-v2
direction LR
state "Data" as Data1
state "Vertex Shader" as VertexShader1
state "Tesselation Shader" as TesselationShader1
state "Rasterization" as Rasterization1
state "Fragment Shader" as FragmentShader1
state "Blending" as Blending1
state "Texture" as Texture1
state "Texture" as Texture2
state "Vertex Shader" as VertexShader2
state "Tesselation Shader" as TesselationShader2
state "Rasterization" as Rasterization2
state "Fragment Shader" as FragmentShader2
state "Blending" as Blending2
state "Frame Buffer" as FrameBuffer2
Data1 --> VertexShader1
state "Pass 1" as Pass1{
direction LR
VertexShader1 --> TesselationShader1
TesselationShader1 --> Rasterization1
Rasterization1 --> FragmentShader1
FragmentShader1 --> Blending1
}
Blending1 --> Texture1
Texture2 --> VertexShader2
state "Pass 2" as Pass2{
direction LR
VertexShader2 --> TesselationShader2
TesselationShader2 --> Rasterization2
Rasterization2 --> FragmentShader2
FragmentShader2 --> Blending2
}
Blending2 --> FrameBuffer2

View File

@ -0,0 +1,24 @@
classDiagram
namespace ConjureEngine {
class Application {
+ Run() int
+ Tick(double deltaTime) void
}
class Window {
+ std::shared_ptr~SDL_Window~ m_window;
+ std::shared_ptr~VulkanContext~ m_vulkanContext;
}
class VulkanContext {
- uint32_t m_extensionCount
- char** m_extensionNames
- VkInstance m_vkInst
- uint32_t m_physicalDeviceCount
- std::vector~VkPhysicalDevice~ m_physicalDevices
- VkPhysicalDevice m_selectedDevice
- uint32_t m_queueFamilyCount
}
}
Window "1" *-- "1" VulkanContext

View File

@ -0,0 +1,28 @@
---
title: Rendering Pipeline
---
classDiagram
class VAO
class VBO
class Shader
class Pipeline0
class Pipeline1
class Pipeline2
class Entity0
class Entity1
class Entity2
Entity0 -- Pipeline0
Entity0 -- Pipeline1
Entity0 -- Pipeline2
Entity1 -- Pipeline0
Entity1 -- Pipeline1
Entity2 -- Pipeline1
Entity2 -- Pipeline2
Pipeline0 -- Shader
Pipeline1 -- Shader
Pipeline2 -- Shader

View File

@ -0,0 +1,62 @@
//
// Created by calap on 11/21/2024.
//
#include "Application.h"
#include "VulkanContext.h"
namespace ConjureEngine {
Application::Application(const ApplicationInfo &applicationInfo): m_applicationInfo(applicationInfo) {
// Fill the application information
m_vkAppInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
m_vkAppInfo.pApplicationName = applicationInfo.title.c_str();
m_vkAppInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0);
m_vkAppInfo.pEngineName = "Conjure Engine";
m_vkAppInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0);
m_vkAppInfo.apiVersion = VK_API_VERSION_1_0;
}
int Application::Run()
{
// CREATE SDL WINDOW
Window window(this->m_applicationInfo.title.c_str(), m_applicationInfo.window);
// INIT VULKAN
VulkanContext vulkanContext;
vulkanContext.AttachTo(window.GetWindow(), this->m_vkAppInfo);
// INITIALIZATION OF THE WORLD
this->Awake();
this->Start();
// MAIN LOOP
bool running = true;
static uint64_t lastTick = SDL_GetTicks64(); // TIME IS IN MS
while (running) {
// HANDLE INPUTS HERE (CODE BELOW IS FROM A TUTORIAL)
SDL_Event windowEvent;
while (SDL_PollEvent(&windowEvent)) {
if (windowEvent.type == SDL_QUIT) {
running = false;
break;
}
}
// TICK SCENE HERE
const uint64_t currentTick = SDL_GetTicks64(); // TIME IS IN MS
const uint64_t deltaTime = currentTick - lastTick; // TIME IS IN MS
this->Tick(static_cast<double>(deltaTime)/1000.f);
// HANDLE PHYSICS HERE
lastTick = currentTick;
}
// CLEANUP HERE
this->Destroy();
return 0;
}
} // ConjureEngine

View File

@ -0,0 +1,56 @@
//
// Created by calap on 11/21/2024.
//
#pragma once
#include "PCH.h"
#include "Window.h"
namespace ConjureEngine {
struct ApplicationInfo {
std::string title;
WindowInfo window{
0,
0,
0,
0
};
};
class Application {
public:
explicit Application(const ApplicationInfo &applicationInfo);
virtual ~Application() = default;
int Run();
/**
* First function call right after SDL and VULKAN are init
*/
virtual inline void Awake() {};
/**
* Called after awake is done
*/
virtual inline void Start() {};
/**
* Called every frame after Start
* @param deltaTime Time in seconds since last call to Tick
*/
virtual inline void Tick(double deltaTime) {}
/**
* Call when the application is being closed
*/
virtual inline void Destroy() {};
protected:
public:
protected:
ApplicationInfo m_applicationInfo;
VkApplicationInfo m_vkAppInfo{};
};
} // ConjureEngine

View File

@ -1,10 +0,0 @@
//
// Created by Jimmy Tremblay-bernier on 2024-11-14.
//
#include "ConjureEngine.h"
#include <cstdio>
void ConjureEngine::SayHello()
{
printf("Hello World\n");
}

View File

@ -1,4 +1,5 @@
#pragma once #pragma once
namespace ConjureEngine {
void SayHello(); #include "Application.h"
} #include "VulkanContext.h"
#include "Window.h"

View File

@ -0,0 +1,22 @@
//
// Created by calap on 11/21/2024.
//
#pragma once
// STANDARD LIBS
#include <memory>
#include <string>
#include <vector>
// GLM
#include "glm/glm.hpp"
// SDL2
#include "SDL2/SDL.h"
#include "SDL2/SDL_vulkan.h"
#include "SDL2/SDL_video.h"
// VULKAN
#include "vulkan/vulkan.h"
#include "vulkan/vulkan_core.h"

View File

@ -0,0 +1,201 @@
//
// Created by Jimmy Tremblay-bernier on 2024-11-22.
//
#include "VulkanContext.h"
#include "Window.h"
#ifdef __APPLE__
#include "vulkan/vulkan_metal.h"
#endif
namespace ConjureEngine {
VulkanContext::VulkanContext()= default;
void VulkanContext::AttachTo(SDL_Window* window, const VkApplicationInfo& appInfo)
{
// LOAD THE EXTENSIONS
SDL_bool sdlSuccess;
VkResult vk_result;
// FETCH NUMBER OF EXTENSIONS TO RESERVE SPACE IN VECTOR
sdlSuccess = SDL_Vulkan_GetInstanceExtensions(window, &m_extensionCount, nullptr);
if(sdlSuccess != SDL_TRUE)
{
SDL_LogError(SDL_LOG_CATEGORY_SYSTEM, "Error Getting Extensions: %s", SDL_GetError());
exit(1);
}
m_extensionNames.reserve(m_extensionCount);
// FILLING UP THE VECTOR
sdlSuccess = SDL_Vulkan_GetInstanceExtensions(window, &m_extensionCount, m_extensionNames.data());
if(sdlSuccess != SDL_TRUE)
{
SDL_LogError(SDL_LOG_CATEGORY_SYSTEM, "Error Getting Extensions: %s", SDL_GetError());
exit(1);
}
else
{
SDL_LogDebug(SDL_LOG_CATEGORY_SYSTEM,"FETCHING OF EXTENSION FINISHED SUCCESSFULLY");
}
// Fill the instance create info struct using appInfo
VkInstanceCreateInfo vulkanInfos{};
vulkanInfos.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
vulkanInfos.pApplicationInfo = &appInfo;
// ENABLE THE REQUIRED EXTENSIONS
this->EnableGlobalExtentions(window, vulkanInfos);
// CREATE THE VULKAN INSTANCE
vk_result = vkCreateInstance(&vulkanInfos, nullptr, &m_vkInst);
if(vk_result != VkResult::VK_SUCCESS) {
SDL_LogError(SDL_LOG_CATEGORY_SYSTEM, "Error while creating the device: CODE = %d", static_cast<int>(vk_result));
exit(1);
}
else {
SDL_LogDebug(SDL_LOG_CATEGORY_SYSTEM,"VULKAN INSTANCE CREATED SUCCESSFULLY");
}
// FETCH THE NUMBER OF PHYSICAL DEVICES (GPUs) TO RESERVE SPACE INTHE VECTOR
vk_result = vkEnumeratePhysicalDevices(m_vkInst, &m_physicalDeviceCount, nullptr);
if(vk_result != VkResult::VK_SUCCESS) {
SDL_LogError(SDL_LOG_CATEGORY_SYSTEM, "Error while enumerating physical devices: CODE = %d", static_cast<int>(vk_result));
exit(1);
}
m_physicalDevices = std::vector<VkPhysicalDevice>(m_physicalDeviceCount);
// FILL THE VECTOR WITH ACTUAL DEVICES DATA
vk_result = vkEnumeratePhysicalDevices(m_vkInst, &m_physicalDeviceCount, m_physicalDevices.data());
if(vk_result != VkResult::VK_SUCCESS) {
SDL_LogError(SDL_LOG_CATEGORY_SYSTEM, "Error while enumerating physical devices: CODE = %d", static_cast<int>(vk_result));
exit(1);
}
else {
SDL_LogDebug(SDL_LOG_CATEGORY_SYSTEM, "VULKAN ENUMERATION OF PHYSICAL DEVICES FINISHED SUCCESSFULLY");
}
// SELECT THE MAIN GPU (WE COULD HAVE A SMARTER SELECTION LATER. FOR NOW, WE SELECT THE FIRST ONE WE SEE)
m_selectedPhysicalDevice = m_physicalDevices[0];
// FETCH THE QUANTITY OF FAMILY QUEUE TO RESERVE SPACE IN THE VECTOR
vkGetPhysicalDeviceQueueFamilyProperties(m_selectedPhysicalDevice, &m_queueFamilyCount, nullptr);
std::vector<VkQueueFamilyProperties> queueFamilies(m_queueFamilyCount);
// FILL THE VECTOR WITH ACTUAL QUEUE DATA
vkGetPhysicalDeviceQueueFamilyProperties(m_selectedPhysicalDevice, &m_queueFamilyCount, queueFamilies.data());
// CREATE THE SURFACE FOR RENDERING
sdlSuccess = SDL_Vulkan_CreateSurface(window, m_vkInst, &m_surface);
if(sdlSuccess != SDL_TRUE)
{
SDL_LogError(SDL_LOG_CATEGORY_SYSTEM, "Error Getting Extensions: %s", SDL_GetError());
exit(1);
}
else
{
SDL_LogDebug(SDL_LOG_CATEGORY_SYSTEM, "VULKAN SURFACE CREATED SUCCESSFULLY");
}
// NOT SURE WHAT THIS DOES YET, WILL CHECK IN THE TUTORIAL
uint32_t graphicsQueueIndex = UINT32_MAX;
uint32_t presentQueueIndex = UINT32_MAX;
VkBool32 support;
uint32_t i = 0;
for (VkQueueFamilyProperties queueFamily: queueFamilies) {
if (graphicsQueueIndex == UINT32_MAX && queueFamily.queueCount > 0 && queueFamily.queueFlags &
VK_QUEUE_GRAPHICS_BIT)
graphicsQueueIndex = i;
if (presentQueueIndex == UINT32_MAX) {
vk_result = vkGetPhysicalDeviceSurfaceSupportKHR(m_selectedPhysicalDevice, i, m_surface, &support);
if(vk_result != VkResult::VK_SUCCESS) {
SDL_LogError(SDL_LOG_CATEGORY_SYSTEM, "Error while checking the surface capability: CODE = %d", static_cast<int>(vk_result));
}
if (support)
presentQueueIndex = i;
}
++i;
}
//
float queuePriority = 1.0f;
m_deviceQueueCreateInfo = {
VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, // sType
nullptr, // pNext
0, // flags
graphicsQueueIndex, // graphicsQueueIndex
1, // queueCount
&queuePriority, // pQueuePriorities
};
// FETCH THE PHYSICAL DEVICES FEATURES
VkPhysicalDeviceFeatures deviceFeatures = {};
const char *deviceExtensionNames[] = {VK_KHR_SWAPCHAIN_EXTENSION_NAME};
m_deviceCreateInfo = {
VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, // sType
nullptr, // pNext
0, // flags
1, // queueCreateInfoCount
&m_deviceQueueCreateInfo, // pQueueCreateInfos
0, // enabledLayerCount
nullptr, // ppEnabledLayerNames
1, // enabledExtensionCount
deviceExtensionNames, // ppEnabledExtensionNames
&deviceFeatures, // pEnabledFeatures
};
// CREATE VIRTUAL DEVICE FOR RENDERING
vk_result = vkCreateDevice(m_selectedPhysicalDevice, &m_deviceCreateInfo, nullptr, &m_device);
if(vk_result != VkResult::VK_SUCCESS) {
SDL_LogError(SDL_LOG_CATEGORY_VIDEO, "Error while creating the device: %d", static_cast<int>(vk_result));
exit(1);
}
else {
SDL_LogDebug(SDL_LOG_CATEGORY_SYSTEM, "DEVICE CREATED SUCCESSFULLY");
}
vkGetDeviceQueue(m_device, graphicsQueueIndex, 0, &m_graphicQueue);
// WHEN POSSIBLE, WE WANT TO USE THE PRESENTATION QUEUE, BUT MAC DOESN'T SUPPORT IT
if(presentQueueIndex != UINT32_MAX) {
m_supportsPresentationQueue = true;
vkGetDeviceQueue(m_device, presentQueueIndex, 0, &m_presentQueue);
}
const std::string error = SDL_GetError();
if(!error.empty()) {
SDL_Log("Initialized with errors: %s", error.c_str());
}
else {
SDL_Log("Initialized without errors");
}
}
void VulkanContext::EnableGlobalExtentions(SDL_Window* window, VkInstanceCreateInfo &vulkanInfos) {
SDL_Vulkan_GetInstanceExtensions(window, &m_extensionCount, nullptr);
this->m_extensionNames.reserve(m_extensionCount);
SDL_Vulkan_GetInstanceExtensions(window, &m_extensionCount, m_extensionNames.data());
#ifdef __APPLE__
this->m_extensionNames.push_back(VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME);
this->m_extensionNames.push_back(VK_EXT_METAL_SURFACE_EXTENSION_NAME);
vulkanInfos.flags |= VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR;
#endif
#ifdef __WIN32__
this->m_extensionNames.push_back("VK_KHR_win32_surface");
#endif
vulkanInfos.enabledExtensionCount = static_cast<uint32_t>(this->m_extensionNames.size());
vulkanInfos.ppEnabledExtensionNames = this->m_extensionNames.data();
}
VulkanContext::~VulkanContext() {
vkDestroyDevice(m_device, nullptr);
vkDestroyInstance(m_vkInst, nullptr);
}
} // ConjureEngine

View File

@ -0,0 +1,34 @@
//
// Created by Jimmy Tremblay-bernier on 2024-11-22.
//
#pragma once
namespace ConjureEngine {
#include "PCH.h"
class VulkanContext {
public:
explicit VulkanContext();
~VulkanContext();
void AttachTo(SDL_Window* window, const VkApplicationInfo& appInfo);
private:
void EnableGlobalExtentions(SDL_Window* window, VkInstanceCreateInfo &vulkanInfos);
private:
uint32_t m_extensionCount{0};
std::vector<const char*> m_extensionNames;
VkInstance m_vkInst{nullptr};
uint32_t m_physicalDeviceCount{0};
std::vector<VkPhysicalDevice> m_physicalDevices;
VkPhysicalDevice m_selectedPhysicalDevice{nullptr};
uint32_t m_queueFamilyCount{0};
VkSurfaceKHR m_surface{nullptr};
VkDeviceQueueCreateInfo m_deviceQueueCreateInfo{};
VkDeviceCreateInfo m_deviceCreateInfo{};
VkDevice m_device{nullptr};
VkQueue m_graphicQueue{nullptr};
VkQueue m_presentQueue{nullptr};
bool m_supportsPresentationQueue = false;
};
} // ConjureEngine

View File

@ -0,0 +1,33 @@
//
// Created by calap on 11/21/2024.
//
#include "Window.h"
namespace ConjureEngine {
Window::Window(const char* title, const WindowInfo& windowInfo)
{
// INIT WINDOW
SDL_Init(SDL_INIT_VIDEO);
SDL_Vulkan_LoadLibrary(nullptr);
m_window = SDL_CreateWindow(title, 0, 32, windowInfo.width, windowInfo.height, SDL_WINDOW_SHOWN | SDL_WINDOW_VULKAN);
}
Window::~Window() {
SDL_DestroyWindow(m_window);
SDL_Vulkan_UnloadLibrary();
SDL_Quit();
std::string error = SDL_GetError();
if(!error.empty())
{
SDL_Log("Cleaned up with errors: %s", error.c_str());
}
}
SDL_Window* Window::GetWindow() const
{
return m_window;
}
} // ConjureEngine

View File

@ -0,0 +1,30 @@
//
// Created by calap on 11/21/2024.
//
#pragma once
#include "PCH.h"
namespace ConjureEngine
{
struct WindowInfo {
int x;
int y;
int width;
int height;
};
class Window {
public:
explicit Window(const char* title, const WindowInfo &windowInfo);
~Window();
SDL_Window* GetWindow() const;
private:
public:
private:
SDL_Window* m_window;
};
} // ConjureEngine

4
Demo1/.gitignore vendored
View File

@ -1,3 +1,5 @@
CMakeFiles/ CMakeFiles/
cmake_install.cmake cmake_install.cmake
CMakeUserPresets.json CMakeUserPresets.json
CompileShaders.log
**/*.spv

View File

@ -1,23 +1,30 @@
cmake_minimum_required(VERSION 3.29) cmake_minimum_required(VERSION 3.26)
project(Demo1) project(Demo1)
set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD 20)
# Set the architecture (assuming you're passing the architecture as a CMake variable) find_package(Python3 REQUIRED COMPONENTS Interpreter)
# Replace 'x64' with your system's architecture, or set this dynamically based on the system
if(NOT DEFINED ARCH)
set(ARCH x64) # You can change this to x86 or any other architecture you are targeting
endif()
# Set common output directories add_executable(${PROJECT_NAME}
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/intermediates/${ARCH}/${PROJECT_NAME}) src/main.cpp
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/bin/${ARCH}/${PROJECT_NAME}) src/Demo1.cpp
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/bin/${ARCH}/${PROJECT_NAME}) src/Demo1.h
)
add_executable(${PROJECT_NAME} src/main.cpp) # CREATE CUSTOM TARGET THAT COMPILE SHADERS EVERY BUILD
add_custom_target(shader_compilation ALL
COMMAND ${Python3_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/CompileShaders.py ${CMAKE_CURRENT_SOURCE_DIR}/src/Shaders ${CMAKE_CURRENT_SOURCE_DIR}
COMMENT "Compiling shaders"
)
# ADD THE CUSTOM TARGET AS A DEPENDENCY OF DEMO1
add_dependencies(${PROJECT_NAME} shader_compilation)
target_link_directories(${PROJECT_NAME} PRIVATE ${CMAKE_SOURCE_DIR}/ConjureEngine) target_link_directories(${PROJECT_NAME} PRIVATE ${CMAKE_SOURCE_DIR}/ConjureEngine)
target_link_libraries(${PROJECT_NAME} ${CONAN_LIBS} ConjureEngine) find_package(SDL2 REQUIRED)
target_include_directories(${PROJECT_NAME} PRIVATE include) target_include_directories(${PROJECT_NAME} PRIVATE include)
target_include_directories(${PROJECT_NAME} PRIVATE ${CMAKE_SOURCE_DIR}/ConjureEngine/src) target_include_directories(${PROJECT_NAME} PRIVATE ${CMAKE_SOURCE_DIR}/ConjureEngine/src)
target_link_libraries(${PROJECT_NAME} SDL2::SDL2 ConjureEngine)

46
Demo1/CompileShaders.py Normal file
View File

@ -0,0 +1,46 @@
import os
import sys
import subprocess
import logging
os.chdir(sys.argv[1])
# Configure logging
logging.basicConfig(
filename=os.path.join(sys.argv[2], "CompileShaders.log"), # Log file name
filemode="w", # Append mode (use "w" for overwrite)
format="%(asctime)s - %(levelname)s - %(message)s", # Log format
level=logging.INFO # Logging level
)
def filterFunc(fileName):
params = fileName.split(".")
return params[len(params) - 1] != "spv"
def __main__():
SHADERS_PATH = os.path.join(os.getcwd())
if os.name == "nt":
GLSLC_PATH = os.path.join(os.environ.get("VULKAN_SDK"), "bin", "glslc")
else:
GLSLC_PATH = "/usr/local/bin/glslc"
logging.info(str.join(" ", ["SHADER PATH:", SHADERS_PATH]))
logging.info(str.join(" ", ["GLSLC PATH:", GLSLC_PATH]))
shaders = filter(filterFunc, os.listdir(SHADERS_PATH))
for shader in shaders:
name, ext = shader.split(".")
command = GLSLC_PATH
args = [
os.path.join(SHADERS_PATH, shader),
"-o",
os.path.join(SHADERS_PATH, name + "." + ext + ".spv")
]
logging.info(str.join(" ", ["Compiling:", shader]))
logging.info(str.join(" ", [command] + args))
subprocess.Popen([command] + args)
if __name__ == "__main__":
__main__()

View File

@ -1,8 +0,0 @@
[requires]
[generators]
CMakeDeps
CMakeToolchain
[layout]
cmake_layout

42
Demo1/src/Demo1.cpp Normal file
View File

@ -0,0 +1,42 @@
//
// Created by Jimmy Tremblay-bernier on 2024-11-22.
//
#include "Demo1.h"
#include "ConjureEngine/ConjureEngine.h"
static ConjureEngine::ApplicationInfo appInfo = ConjureEngine::ApplicationInfo
{
"Demo1",
ConjureEngine::WindowInfo {
0,
0,
1920,
1080
}
};
namespace Demo1 {
Demo1::Demo1(): ConjureEngine::Application(appInfo) {}
void Demo1::Awake()
{
SDL_LogDebug(SDL_LOG_CATEGORY_APPLICATION,"AWAKING");
}
void Demo1::Start()
{
SDL_LogDebug(SDL_LOG_CATEGORY_APPLICATION,"STARTING");
}
void Demo1::Tick(double deltaTime)
{
SDL_LogDebug(SDL_LOG_CATEGORY_APPLICATION, "TICKING %f", deltaTime);
}
void Demo1::Destroy()
{
SDL_LogDebug(SDL_LOG_CATEGORY_APPLICATION,"DESTROYING");
}
} // Demo1

19
Demo1/src/Demo1.h Normal file
View File

@ -0,0 +1,19 @@
///
// Created by Jimmy Tremblay-bernier on 2024-11-22.
//
#pragma once
#include "ConjureEngine/ConjureEngine.h"
namespace Demo1 {
class Demo1: public ConjureEngine::Application {
public:
Demo1();
void Awake() override;
void Start() override;
void Tick(double deltaTime) override;
void Destroy() override;
};
} // Demo1

View File

@ -0,0 +1,7 @@
#version 460 core
layout (location = 0) out vec4 oColor;
void main() {
oColor = vec4(1);
}

View File

@ -0,0 +1,5 @@
#version 460 core
void main() {
gl_Position = vec4(0);
}

View File

@ -1,6 +1,92 @@
#include "ConjureEngine/ConjureEngine.h" #define SDL_MAIN_HANDLED
int main(int argc, char** argv) { #include <fstream>
ConjureEngine::SayHello(); #include <iostream>
return 0;
#include "Demo1.h"
static std::ofstream logFile;
void OutputLog(void *userdata, int category, SDL_LogPriority priority, const char *message)
{
(void)userdata;
std::string categoryString;
switch (category)
{
case SDL_LOG_CATEGORY_APPLICATION:
categoryString = "Application";
break;
case SDL_LOG_CATEGORY_ERROR:
categoryString = "Error";
break;
case SDL_LOG_CATEGORY_ASSERT:
categoryString = "Assert";
break;
case SDL_LOG_CATEGORY_SYSTEM:
categoryString = "System";
break;
case SDL_LOG_CATEGORY_AUDIO:
categoryString = "Audio";
break;
case SDL_LOG_CATEGORY_VIDEO:
categoryString = "Video";
break;
case SDL_LOG_CATEGORY_RENDER:
categoryString = "Render";
break;
case SDL_LOG_CATEGORY_INPUT:
categoryString = "Input";
break;
case SDL_LOG_CATEGORY_TEST:
categoryString = "Test";
break;
default:
categoryString = "";
break;
}
std::string priorityString;
switch (priority)
{
case SDL_LOG_PRIORITY_VERBOSE:
priorityString = "VERBOSE";
break;
case SDL_LOG_PRIORITY_DEBUG:
priorityString = "DEBUG";
break;
case SDL_LOG_PRIORITY_INFO:
priorityString = "INFO";
break;
case SDL_LOG_PRIORITY_WARN:
priorityString = "WARN";
break;
case SDL_LOG_PRIORITY_ERROR:
priorityString = "ERROR";
break;
case SDL_LOG_PRIORITY_CRITICAL:
priorityString = "CRITICAL";
break;
default:
std::cout << message << "\n";
break;
}
logFile << "[" << categoryString << " - " << priorityString << "] " << message << "\n";
std::cout << "[" << categoryString << " - " << priorityString << "] " << message << "\n";
}
int main ( int argc, char* argv[] )
{
logFile = std::ofstream{"log.txt"};
SDL_SetMainReady();
SDL_LogSetAllPriority(SDL_LOG_PRIORITY_VERBOSE);
SDL_LogSetOutputFunction(&OutputLog, nullptr);
// I WANT TO CREATE AN APP
Demo1::Demo1 app;
// AND THEN START IT
return app.Run();
} }

23
README.md Normal file
View File

@ -0,0 +1,23 @@
# Conjure Engine
## Installation
### Dependancies
To install this project, it is required that you install the folowind dependancies
on you computer:
- Vulkan SDK: https://vulkan.lunarg.com/sdk/home
- Conan 2: https://docs.conan.io/2/installation.html
### Platforms supported
- Mac 14+
- Windows 10+
- Linux 6+
Those are wide guideline and any version recent enough of your OS should work
as long it supports vulkan and conan.
### Installation step
#### Configure your IDE
1. Execute `./Configure.sh` (LINUX/MAC) or `.\Configure.bat` (WINDOWS). This step installs all the dependencies for both release and debug.
2. Load the generated CMakeUserPresets.json that was generated at step 1.
3. Select an executable project (like Demo1)
4. Build