Skip to content
Merged
Show file tree
Hide file tree
Changes from 54 commits
Commits
Show all changes
63 commits
Select commit Hold shift + click to select a range
bc41e17
Initial move of files
FiniteReality Jun 16, 2025
c1b08c9
Switch to using pragma once
FiniteReality Jun 16, 2025
04154fb
Slowly working through fixing compile errors
FiniteReality Jun 17, 2025
38a0854
Refactor Configurator to improve modularity
FiniteReality Jun 19, 2025
d628f3d
It now supposedly compiles?
FiniteReality Jun 19, 2025
454da95
Things I missed from the CMakeLists
FiniteReality Jun 29, 2025
1a58d06
Part one of cmdlist concurrency upgrade. TODO: Update contexts to be …
RubyNova Aug 11, 2025
d062e98
Fix issue in VulkanGraphicsCmdList where chack was inverted for some …
RubyNova Aug 12, 2025
a0e4d25
Push for Monica.
RubyNova Aug 12, 2025
60a7367
Make context creatable from swapchain image, and render pass creatabl…
FiniteReality Aug 12, 2025
28c1f69
Add new ObjectPool type. Add missing memory.hpp header to CMakeLists.…
RubyNova Aug 12, 2025
a744afb
More cleanup and hooking up the new context doohickery
FiniteReality Aug 12, 2025
3e58d79
checkpoint before implementing render targets.
RubyNova Aug 12, 2025
516c652
This is as good as its gonna get for now.
RubyNova Aug 19, 2025
47c8e95
Fix a few linux build failures, fail to fix resize lag
FiniteReality Nov 3, 2025
b3249cd
Allow command lists to be created independently
FiniteReality Nov 3, 2025
76ec68c
Orchestrator attempt 1
FiniteReality Nov 3, 2025
e1dd843
Actually sort the entities beforehand
FiniteReality Nov 3, 2025
23a03e0
Allow creation of independent graphics contexts
FiniteReality Nov 3, 2025
05e2951
Sample sprite system
FiniteReality Nov 4, 2025
4276cc3
Refactor types a little
FiniteReality Nov 4, 2025
7f201cf
Fix some errors, add a container for efficient(?) render pass mapping
FiniteReality Nov 4, 2025
0da68fb
Make command lists able to be created from the context
FiniteReality Nov 6, 2025
1778f67
Get intellisense working again idk. Add Vulkan cmdlist dispatch support.
RubyNova Nov 6, 2025
68001cd
Add indexed square to SpriteRendererSystem.
RubyNova Nov 6, 2025
c3821f0
Taking a break. TODO: Add pipeline, make new shaders for sprite rende…
RubyNova Nov 6, 2025
a0ed504
Port resource loading code. I have no idea if any of it works. It pro…
RubyNova Nov 7, 2025
2040b72
Update resource loading code targets.
RubyNova Nov 20, 2025
695562c
Add ECS graphics sample for future testing
FiniteReality Mar 6, 2026
6eb83c2
Make it link
FiniteReality Mar 6, 2026
dd4c939
Make new sample app be reasonable on Windows under MSVC.
RubyNova Mar 6, 2026
83d82de
Get the core orchestrator mostly fleshed out. TODO: fix cmdlist cachi…
RubyNova Mar 6, 2026
fac250f
Code now compiles. VkDevice is getting memstomped. I think it's becau…
RubyNova Mar 7, 2026
8eb1de4
The clobbering continues. I think.
RubyNova Mar 7, 2026
72e6b52
Fix recursive swapchain bug, improve ECS builders, begin sample refactor
FiniteReality Mar 7, 2026
187b6dc
un-destroy the sample system. TODO: Now getting FileNotFound as planned.
RubyNova Mar 8, 2026
e100c69
Add SPV resources.
RubyNova Mar 8, 2026
5c343bb
Fix missing linked list component.
RubyNova Mar 8, 2026
63cfe6f
Vulkan API update. GEt secondary cmdlists working.
RubyNova Mar 12, 2026
ea0b12d
Triangle get! Removes some extraneous logging, indentation changes, etc.
FiniteReality Mar 13, 2026
e603283
Enable maintenance7/nested command buffers
FiniteReality Mar 13, 2026
1163c5f
Minor tweaks.
RubyNova Mar 13, 2026
2ebf8a8
Fix VkCommandBuffer memleak.
RubyNova Mar 13, 2026
8d5fe47
Fix memory leak two.
RubyNova Mar 13, 2026
2e042ac
Skip RemoveComponent, it's causing issues
FiniteReality Mar 13, 2026
92017de
Fix sync issue.
RubyNova Mar 13, 2026
2250b78
fix vulkanrender sample.
RubyNova Mar 13, 2026
cf28d60
Try to make macOS CI cooperate.
RubyNova Mar 14, 2026
0a65a45
Enable verbose clang-format
capnkenny Mar 14, 2026
c9697d3
Fix verbose flag
capnkenny Mar 14, 2026
ee709bc
Additional param
capnkenny Mar 14, 2026
82454ab
Apply clang-format to all source files
FiniteReality Mar 14, 2026
f4a5c5c
Ignore some clang-tidy warnings
FiniteReality Mar 14, 2026
fc76b03
Ignore imgui sample entirely for now
FiniteReality Mar 14, 2026
a3a036a
Add nolint regex to clang-format, respond to nits
FiniteReality Mar 14, 2026
19ee981
Use a different workaround instead
FiniteReality Mar 14, 2026
d6206b4
Revert "Fix sync issue."
FiniteReality Mar 14, 2026
60cf844
Fix swapchain :sync issues once and for all
FiniteReality Mar 14, 2026
ce484af
Override the thread-count to require single-threaded operation
FiniteReality Mar 15, 2026
2e4ce3d
Add missing include.
RubyNova Mar 16, 2026
8f4e91e
Fix sizing issue that clang missed for some reason. Swap extension na…
RubyNova Mar 17, 2026
2a961f7
Fix validation and compile errors in VulkanRender sample
FiniteReality Mar 17, 2026
2af06f5
Apply clang-format to files
FiniteReality Mar 17, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions .clang-tidy
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ Checks: >

FormatStyle: file

HeaderFilterRegex: '^NovelRT/.*'
HeaderFilterRegex: '^(?!.*ThirdParty).*'

CheckOptions:
- key: readability-identifier-naming.ClassCase
Expand All @@ -33,7 +33,7 @@ CheckOptions:
value: CamelCase

- key: readability-identifier-naming.PublicMemberCase
value: camelBack
value: CamelCase
- key: readability-identifier-naming.PrivateMemberCase
value: camelBack
- key: readability-identifier-naming.PrivateMemberPrefix
Expand All @@ -48,7 +48,7 @@ CheckOptions:
value: CamelCase

- key: readability-identifier-naming.EnumConstantCase
value: UPPER_CASE
value: CamelCase

- key: readability-identifier-naming.FunctionCase
value: CamelCase
Expand Down Expand Up @@ -79,5 +79,5 @@ CheckOptions:
value: CamelCase

- key: readability-identifier-naming.VariableCase
value: camelCase
value: camelBack
...
4 changes: 2 additions & 2 deletions .github/workflows/build-pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ jobs:
legacySrcDir="$(pwd)/LegacySrc"
artefactsDir="$(pwd)/artefacts"
find "$(pwd)" \( -path "$buildDir" -o -path "$legacySrcDir" -o -path "$artefactsDir" \) -prune -o \
-name '*.cpp' -o -name '*.hpp' -exec clang-format --dry-run --Werror --style=file '{}' \+
-name '*.cpp' -o -name '*.hpp' -exec clang-format -i --verbose --dry-run --Werror --style=file '{}' \+

- name: Preinstall dependencies
if: ${{ runner.os == 'Linux' }}
Expand Down Expand Up @@ -64,7 +64,7 @@ jobs:
fail-fast: false
matrix:
configuration: [Debug, RelWithDebInfo]
os: [windows-2025, ubuntu-24.04, macos-15, macos-13]
os: [windows-2025, ubuntu-24.04, macos-15, macos-26]
vulkan: [1.4.313.0]

steps:
Expand Down
86 changes: 45 additions & 41 deletions Audio/Legacy/XAudio2/XAudio2AudioProvider.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,31 +7,33 @@
namespace NovelRT::Audio::XAudio2
{

XAudio2AudioProvider::XAudio2AudioProvider():
_device(nullptr),
_masterVoice(nullptr),
_sources(std::map<uint32_t, IXAudio2SourceVoice*>()),
_sourceCounter(0),
_logger(spdlog::stdout_color_mt("XAudio2")),
_buffers(std::map<uint32_t, XAUDIO2_BUFFER>()),
_bufferCounter(0)
XAudio2AudioProvider::XAudio2AudioProvider()
: _device(nullptr),
_masterVoice(nullptr),
_sources(std::map<uint32_t, IXAudio2SourceVoice*>()),
_sourceCounter(0),
_logger(spdlog::stdout_color_mt("XAudio2")),
_buffers(std::map<uint32_t, XAUDIO2_BUFFER>()),
_bufferCounter(0)
{
//Logger init
// Logger init
_logger->set_level(spdlog::level::debug);

//Device and Context Init
_hr = CoInitializeEx( nullptr, COINIT_MULTITHREADED );
// Device and Context Init
_hr = CoInitializeEx(nullptr, COINIT_MULTITHREADED);
if (FAILED(_hr))
{
throw new Exceptions::InitialisationFailureException("Failed to initialise COM!", _hr);
}

if (FAILED(_hr = XAudio2Create( &_device, 0, XAUDIO2_DEFAULT_PROCESSOR)))
if (FAILED(_hr = XAudio2Create(&_device, 0, XAUDIO2_DEFAULT_PROCESSOR)))
{
throw new Exceptions::InitialisationFailureException("Failed to create an instance of the XAudio2 engine!", _hr);
throw new Exceptions::InitialisationFailureException("Failed to create an instance of the XAudio2 engine!",
_hr);
}

if (FAILED(_hr = _device->CreateMasteringVoice(&_masterVoice, XAUDIO2_DEFAULT_CHANNELS, XAUDIO2_DEFAULT_SAMPLERATE)))
if (FAILED(_hr = _device->CreateMasteringVoice(&_masterVoice, XAUDIO2_DEFAULT_CHANNELS,
XAUDIO2_DEFAULT_SAMPLERATE)))
{
throw new Exceptions::InitialisationFailureException("Failed to create an output voice!", _hr);
}
Expand All @@ -52,7 +54,7 @@ namespace NovelRT::Audio::XAudio2

void XAudio2AudioProvider::Dispose()
{
for(auto [id, source] : _sources)
for (auto [id, source] : _sources)
{
source->FlushSourceBuffers();
source->DestroyVoice();
Expand All @@ -73,11 +75,11 @@ namespace NovelRT::Audio::XAudio2
waveFormatContainer.wBitsPerSample = 32;
waveFormatContainer.nBlockAlign = 8;
waveFormatContainer.nSamplesPerSec = static_cast<long>(context.SampleRate);
waveFormatContainer.nAvgBytesPerSec = static_cast<long>(waveFormatContainer.nSamplesPerSec * waveFormatContainer.nBlockAlign);

waveFormatContainer.nAvgBytesPerSec =
static_cast<long>(waveFormatContainer.nSamplesPerSec * waveFormatContainer.nBlockAlign);

IXAudio2SourceVoice* newVoice;
if(FAILED(_hr = _device->CreateSourceVoice(&newVoice, &waveFormatContainer)))
if (FAILED(_hr = _device->CreateSourceVoice(&newVoice, &waveFormatContainer)))
{
_logger->error("Could not create source voice - Code: {hr}", _hr);
}
Expand All @@ -89,15 +91,15 @@ namespace NovelRT::Audio::XAudio2

void XAudio2AudioProvider::PlaySource(uint32_t sourceId)
{
if(FAILED(_hr = _sources.at(sourceId)->Start(0)))
if (FAILED(_hr = _sources.at(sourceId)->Start(0)))
{
_logger->error("Error when attempting to play source {id} - Code: {hr}", sourceId, _hr);
}
}

void XAudio2AudioProvider::StopSource(uint32_t sourceId)
{
if(FAILED(_hr = _sources.at(sourceId)->Stop(0)))
if (FAILED(_hr = _sources.at(sourceId)->Stop(0)))
{
_logger->error("Error when stopping source {id} - Code: {hr}", sourceId, _hr);
}
Expand All @@ -108,26 +110,26 @@ namespace NovelRT::Audio::XAudio2
StopSource(sourceId);
}

uint32_t XAudio2AudioProvider::SubmitAudioBuffer(const NovelRT::Utilities::Misc::Span<float> buffer, AudioSourceContext& context)
uint32_t XAudio2AudioProvider::SubmitAudioBuffer(const NovelRT::Utilities::Misc::Span<float> buffer,
AudioSourceContext& context)
{
//uint32_t nextBuffer = ++_bufferCounter;
XAUDIO2_BUFFER xABuffer =
{
XAUDIO2_END_OF_STREAM, // Flags
static_cast<uint32_t>(buffer.size()*sizeof(float)), // AudioBytes
static_cast<byte*>(new byte[buffer.size()*sizeof(float)]) //new buffer to copy float* to
// uint32_t nextBuffer = ++_bufferCounter;
XAUDIO2_BUFFER xABuffer = {
XAUDIO2_END_OF_STREAM, // Flags
static_cast<uint32_t>(buffer.size() * sizeof(float)), // AudioBytes
static_cast<byte*>(new byte[buffer.size() * sizeof(float)]) // new buffer to copy float* to
};

//Because XAudio2 expects a BYTE*, we'll have to cast it up and copy the data from the provided span :(
std::memcpy((void*)(xABuffer.pAudioData),
reinterpret_cast<void*>(buffer.data()), buffer.size()*sizeof(float));
if(context.Loop)
// Because XAudio2 expects a BYTE*, we'll have to cast it up and copy the data from the provided span :(
std::memcpy((void*)(xABuffer.pAudioData), reinterpret_cast<void*>(buffer.data()),
buffer.size() * sizeof(float));
if (context.Loop)
{
xABuffer.LoopCount = XAUDIO2_LOOP_INFINITE;
}

uint32_t sourceId = OpenSource(context);
if(FAILED(_hr = _sources.at(sourceId)->SubmitSourceBuffer(&xABuffer)))
if (FAILED(_hr = _sources.at(sourceId)->SubmitSourceBuffer(&xABuffer)))
{
_logger->error("Failed to submit buffer to source {sourceId} - Code: {hr}", sourceId, std::to_string(_hr));
}
Expand All @@ -138,13 +140,13 @@ namespace NovelRT::Audio::XAudio2

void XAudio2AudioProvider::SetSourceProperties(uint32_t sourceId, AudioSourceContext& context)
{
//volume
if(FAILED(_hr = _sources.at(sourceId)->SetVolume(context.Volume)))
// volume
if (FAILED(_hr = _sources.at(sourceId)->SetVolume(context.Volume)))
{
_logger->error("Error when setting volume for source {id} - Code: {hr}", sourceId, _hr);
}
//pitch
if(FAILED(_hr = _sources.at(sourceId)->SetFrequencyRatio(context.Pitch)))
// pitch
if (FAILED(_hr = _sources.at(sourceId)->SetFrequencyRatio(context.Pitch)))
{
_logger->error("Error when setting pitch for source {id} - Code: {hr}", sourceId, _hr);
}
Expand All @@ -155,9 +157,10 @@ namespace NovelRT::Audio::XAudio2
XAUDIO2_VOICE_STATE voiceState;
_sources.at(sourceId)->GetState(&voiceState, 0);
AudioSourceState state = ConvertToAudioSourceState(voiceState);
if(state == AudioSourceState::SOURCE_STOPPED)
if (state == AudioSourceState::SOURCE_STOPPED)
{
if(voiceState.pCurrentBufferContext == NULL && voiceState.BuffersQueued == 0 && voiceState.SamplesPlayed == 0)
if (voiceState.pCurrentBufferContext == NULL && voiceState.BuffersQueued == 0 &&
voiceState.SamplesPlayed == 0)
{
auto source = _sources.at(sourceId);
source->Stop(0);
Expand All @@ -169,9 +172,10 @@ namespace NovelRT::Audio::XAudio2

AudioSourceState XAudio2AudioProvider::ConvertToAudioSourceState(XAUDIO2_VOICE_STATE sourceState)
{
if(sourceState.BuffersQueued == 0)
if (sourceState.BuffersQueued == 0)
{
if(sourceState.SamplesPlayed > 0 || (sourceState.pCurrentBufferContext == NULL && sourceState.SamplesPlayed == 0))
if (sourceState.SamplesPlayed > 0 ||
(sourceState.pCurrentBufferContext == NULL && sourceState.SamplesPlayed == 0))
{
return AudioSourceState::SOURCE_STOPPED;
}
Expand All @@ -182,7 +186,7 @@ namespace NovelRT::Audio::XAudio2
}
else
{
if(sourceState.SamplesPlayed > 0)
if (sourceState.SamplesPlayed > 0)
{
return AudioSourceState::SOURCE_PLAYING;
}
Expand Down
2 changes: 1 addition & 1 deletion Audio/OpenAL/OpenALAudioProvider.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ namespace NovelRT::Audio
static void InstallLogger(const Logging::LoggingService& logger)
{
using CallbackType = void ALC_APIENTRY(void* userptr, char level, const char* message, int length) noexcept;
using FnType = void ALC_APIENTRY(CallbackType* callback, void* userptr);
using FnType = void ALC_APIENTRY(CallbackType * callback, void* userptr);

void* callback = alcGetProcAddress(nullptr, "alsoft_set_log_callback");
if (callback == nullptr)
Expand Down
3 changes: 3 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ add_subdirectory(ThirdParty)
add_subdirectory(Exceptions)
add_subdirectory(Logging)
add_subdirectory(Maths)
add_subdirectory(ResourceManagement)
add_subdirectory(Threading)
add_subdirectory(Timing)
add_subdirectory(Utilities)
Expand All @@ -53,6 +54,8 @@ add_subdirectory(Input)
add_subdirectory(UI)
add_subdirectory(Windowing)

add_subdirectory(Ecs)

add_subdirectory(Samples)

if(NOVELRT_INSTALL)
Expand Down
12 changes: 12 additions & 0 deletions Ecs/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
include(NovelRTBuildSystem)

NovelRTBuildSystem_DeclareModule(LIBRARY NovelRT::Ecs
DEPENDS
NovelRT::Ecs::Core

OPTIONAL_DEPENDS
NovelRT::Ecs::Graphics
)

add_subdirectory(Core)
add_subdirectory(Graphics)
44 changes: 44 additions & 0 deletions Ecs/Core/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
include(NovelRTBuildSystem)

NovelRTBuildSystem_DeclareModule(LIBRARY NovelRT::Ecs::Core
DEPENDS
NovelRT::Maths
NovelRT::Timing
NovelRT::Utilities

SOURCES
PRIVATE
Catalogue.cpp
ComponentBufferMemoryContainer.cpp
ComponentCache.cpp
EcsDefaultsBuilder.cpp
EcsUtils.cpp
EntityCache.cpp
EntityGraphView.cpp
LinkedEntityListView.cpp
SparseSetMemoryContainer.cpp
SystemScheduler.cpp
UnsafeComponentView.cpp

HEADERS
PUBLIC
include/NovelRT/Ecs/Components/EntityGraphComponent.hpp
include/NovelRT/Ecs/Components/LinkedEntityListNodeComponent.hpp
include/NovelRT/Ecs/Components/TransformComponent.hpp
include/NovelRT/Ecs/Catalogue.hpp
include/NovelRT/Ecs/ComponentBuffer.hpp
include/NovelRT/Ecs/ComponentBufferMemoryContainer.hpp
include/NovelRT/Ecs/ComponentCache.hpp
include/NovelRT/Ecs/ComponentView.hpp
include/NovelRT/Ecs/EcsDefaultsBuilder.hpp
include/NovelRT/Ecs/EcsUtils.hpp
include/NovelRT/Ecs/EntityCache.hpp
include/NovelRT/Ecs/EntityGraphView.hpp
include/NovelRT/Ecs/IEcsSystem.hpp
include/NovelRT/Ecs/LinkedEntityListView.hpp
include/NovelRT/Ecs/SparseSet.hpp
include/NovelRT/Ecs/SparseSetMemoryContainer.hpp
include/NovelRT/Ecs/SystemScheduler.hpp
include/NovelRT/Ecs/SystemSchedulerBuilder.hpp
include/NovelRT/Ecs/UnsafeComponentView.hpp
)
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
// Copyright © Matt Jones and Contributors. Licensed under the MIT Licence (MIT). See LICENCE.md in the repository root
// for more information.

#include <NovelRT/Ecs/Ecs.h>
#include <NovelRT/Ecs/Catalogue.hpp>
#include <NovelRT/Ecs/ComponentCache.hpp>
#include <NovelRT/Ecs/EntityCache.hpp>
#include <NovelRT/Ecs/UnsafeComponentView.hpp>

#include <algorithm>

namespace NovelRT::Ecs
{
Expand Down Expand Up @@ -45,4 +50,4 @@ namespace NovelRT::Ecs
{
return UnsafeComponentView(_poolId, _componentCache.GetComponentBufferById(componentTypeId));
}
} // namespace NovelRT::Ecs
} // namespace NovelRT::Ecs
Original file line number Diff line number Diff line change
@@ -1,28 +1,35 @@
// Copyright © Matt Jones and Contributors. Licensed under the MIT Licence (MIT). See LICENCE.md in the repository root
// for more information.

#include <NovelRT/Ecs/Ecs.h>
#include <NovelRT/Ecs/ComponentBufferMemoryContainer.hpp>
#include <NovelRT/Ecs/SparseSetMemoryContainer.hpp>
#include <NovelRT/Exceptions/KeyNotFoundException.hpp>

#include <NovelRT/Utilities/Memory.hpp>

#include <utility>

namespace NovelRT::Ecs
{
ComponentBufferMemoryContainer::ComponentBufferMemoryContainer(
size_t poolSize,
const void* deleteInstructionState,
const std::byte* deleteInstructionState,
size_t sizeOfDataTypeInBytes,
std::function<void(void*, const void*, size_t)> componentUpdateLogic,
std::function<bool(const void*, const void*)> componentComparatorLogic,
const std::string& serialisedTypeName) noexcept
: _rootSet(SparseSetMemoryContainer(sizeOfDataTypeInBytes)),
_updateSets(std::vector<SparseSetMemoryContainer>{}),
_deleteInstructionState(std::vector<uint8_t>(sizeOfDataTypeInBytes)),
_deleteInstructionState(sizeOfDataTypeInBytes),
_sizeOfDataTypeInBytes(sizeOfDataTypeInBytes),
_componentUpdateLogic(std::move(componentUpdateLogic)),
_componentComparatorLogic(std::move(componentComparatorLogic)),
_serialisedTypeName(serialisedTypeName)
{
NovelRT::Utilities::Memory::Copy(_deleteInstructionState.data(), _sizeOfDataTypeInBytes, deleteInstructionState,
_sizeOfDataTypeInBytes);
NovelRT::Utilities::Memory::Copy(
NovelRT::Utilities::Span<const std::byte>{deleteInstructionState, _sizeOfDataTypeInBytes},
NovelRT::Utilities::Span<std::byte>{_deleteInstructionState.data(), _sizeOfDataTypeInBytes});

for (size_t i = 0; i < poolSize; i++)
{
_updateSets.emplace_back(sizeOfDataTypeInBytes);
Expand Down
Loading
Loading