commit 4e86a202383683aae19db8ce8ec6f3fb6206f6de Author: Joshua Ashton Date: Sun Jun 12 16:33:55 2022 +0100 Initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..67f0073 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +build +.cache + diff --git a/include/Orange/Core/AlignedStorage.h b/include/Orange/Core/AlignedStorage.h new file mode 100644 index 0000000..567afd0 --- /dev/null +++ b/include/Orange/Core/AlignedStorage.h @@ -0,0 +1,12 @@ +#pragma once + +#include + +namespace orange +{ + template + struct AlignedStorage + { + alignas(Alignment) unsigned char data[Length]; + }; +} diff --git a/include/Orange/Core/FileSystem.h b/include/Orange/Core/FileSystem.h new file mode 100644 index 0000000..e26986a --- /dev/null +++ b/include/Orange/Core/FileSystem.h @@ -0,0 +1,12 @@ +#pragma once + +#include + +namespace orange::fs +{ + class File + { + + }; + //Result +} diff --git a/include/Orange/Core/Hash.h b/include/Orange/Core/Hash.h new file mode 100644 index 0000000..1ff1a3d --- /dev/null +++ b/include/Orange/Core/Hash.h @@ -0,0 +1,16 @@ +#pragma once + +#include + +namespace orange +{ + constexpr uint32_t HashString(const char* s, size_t count) + { + return ((count ? HashString(s, count - 1) : 2166136261u) ^ s[count]) * 16777619u; + } + + constexpr uint32_t operator"" _hash(const char* s, size_t count) + { + return HashString(s, count); + } +} diff --git a/include/Orange/Core/Log.h b/include/Orange/Core/Log.h new file mode 100644 index 0000000..0090052 --- /dev/null +++ b/include/Orange/Core/Log.h @@ -0,0 +1,6 @@ +#pragma once + +namespace orange +{ + #define Assert(...) +} \ No newline at end of file diff --git a/include/Orange/Core/Result.h b/include/Orange/Core/Result.h new file mode 100644 index 0000000..399db29 --- /dev/null +++ b/include/Orange/Core/Result.h @@ -0,0 +1,82 @@ +#pragma once + +#include +#include +#include + +namespace orange +{ + enum class BasicErrorCode : int32_t + { + Invalid = -1, + Failed = -2, + + Success = 0, + }; + + template + class Result + { + public: + ~Result() { Destroy(); } + + T* Get() + { + Assert(IsSuccess()); + if (!IsSuccess()) + return nullptr; + + return &RefUnsafe(); + } + + const T* Get() const + { + Assert(IsSuccess()); + if (!IsSuccess()) + return nullptr; + + return &RefUnsafe(); + } + + bool IsSuccess() const { return static_cast(m_error) >= 0; } + + operator bool() const { return IsSuccess(); } + + T* operator ->() { return Get(); } + const T* operator ->() const { return Get(); } + + T& operator *() { return *Get(); } + const T& operator *() const { return *Get(); } + protected: + Result() = default; + + template + T& Create(Args&&... args) + { + Assert(!m_created); + m_created = true; + new(&m_data) T(Forward(args)...); + return RefUnsafe(); + } + + void Destroy() + { + if (m_created) + { + RefUnsafe().~T(); + m_created = false; + } + } + + Result& Error(ErrorCode code) { m_error = code; return *this; } + Result& Success() { m_error = ErrorCode::Success; return *this; } + + T& RefUnsafe() { return *reinterpret_cast< T*>(&m_data); } + const T& RefUnsafe() const { return *reinterpret_cast(&m_data); } + + friend T; + AlignedStorage m_data; + ErrorCode m_error = ErrorCode::Invalid; + bool m_created = false; + }; +} \ No newline at end of file diff --git a/include/Orange/Core/SmallVector.h b/include/Orange/Core/SmallVector.h new file mode 100644 index 0000000..ad511e3 --- /dev/null +++ b/include/Orange/Core/SmallVector.h @@ -0,0 +1,148 @@ +#pragma once + +#include + +namespace orange +{ + template + class SmallVector + { + public: + + SmallVector() {} + SmallVector(size_t size) { Resize(size); } + + SmallVector (const SmallVector&) = delete; + SmallVector& operator = (const SmallVector&) = delete; + + ~SmallVector() + { + for (size_t i = 0; i < m_size; i++) + Ptr(i)->~T(); + + if (m_capacity > N) + delete[] u.m_ptr; + } + + size_t Size() const + { + return m_size; + } + + void Reserve(size_t n) + { + n = PickCapacity(n); + + if (n <= m_capacity) + return; + + Storage* data = new Storage[n]; + + for (size_t i = 0; i < m_size; i++) + { + new (&data[i]) T(Move(*Ptr(i))); + Ptr(i)->~T(); + } + + if (m_capacity > N) + delete[] u.m_ptr; + + m_capacity = n; + u.m_ptr = data; + } + + const T* Data() const { return Ptr(0); } + T* Data() { return Ptr(0); } + + void Resize(size_t n) + { + Reserve(n); + + for (size_t i = n; i < m_size; i++) + Ptr(i)->~T(); + + for (size_t i = m_size; i < n; i++) + new (Ptr(i)) T(); + } + + void PushBack(const T& object) + { + Reserve(m_size + 1); + new (Ptr(m_size++)) T(object); + } + + void PushBack(T&& object) + { + Reserve(m_size + 1); + new (Ptr(m_size++)) T(Move(object)); + } + + template + void EmplaceBack(Args... args) + { + Reserve(m_size + 1); + new (Ptr(m_size++)) T(Forward(args)...); + } + + void Erase(size_t idx) + { + Ptr(idx)->~T(); + + for (size_t i = idx; i < m_size - 1; i++) + { + new (Ptr(i)) T(Move(*Ptr(i + 1))); + Ptr(i + 1)->~T(); + } + } + + void PopBack() + { + Ptr(--m_size)->~T(); + } + + T& operator [] (size_t idx) { return *Ptr(idx); } + const T& operator [] (size_t idx) const { return *Ptr(idx); } + + T& front() { return *Ptr(0); } + const T& front() const { return *Ptr(0); } + + T& back() { return *Ptr(m_size - 1); } + const T& back() const { return *Ptr(m_size - 1); } + + private: + using Storage = AlignedStorage; + + size_t m_capacity = N; + size_t m_size = 0; + + union + { + Storage* m_ptr; + Storage m_data[sizeof(T) * N]; + } u; + + size_t PickCapacity(size_t n) { + size_t capacity = m_capacity; + + while (capacity < n) + capacity *= 2; + + return capacity; + } + + T* Ptr(size_t idx) { + return m_capacity == N + ? reinterpret_cast(&u.m_data[idx]) + : reinterpret_cast(&u.m_ptr[idx]); + } + + const T* Ptr(size_t idx) const + { + return m_capacity == N + ? reinterpret_cast(&u.m_data[idx]) + : reinterpret_cast(&u.m_ptr[idx]); + } + + }; + +} diff --git a/include/Orange/Core/Span.h b/include/Orange/Core/Span.h new file mode 100644 index 0000000..a8334bf --- /dev/null +++ b/include/Orange/Core/Span.h @@ -0,0 +1,32 @@ +#pragma once + +#include + +namespace orange +{ + template + struct Span + { + Span(T* data, size_t size) : data(data), size(size) {} + + template + Span(T (&array)[Count]) : data(array), size(Count) {} + + explicit Span(T* data) : data(data), size(1) {} + explicit Span(T& data) : data(&data), size(1) {} + + T& operator [] (size_t idx) { return data[idx]; } + const T& operator [] (size_t idx) const { return data[idx]; } + + bool IsEmpty() const { return size == 0; } + + T& front() { return *data[idx]; } + const T& front() const { return *data[idx]; } + + T& back() { return *data[size - 1]; } + const T& back() const { return *data[size - 1]; } + + T* data; + size_t size; + }; +} diff --git a/include/Orange/Core/Traits.h b/include/Orange/Core/Traits.h new file mode 100644 index 0000000..473cfb5 --- /dev/null +++ b/include/Orange/Core/Traits.h @@ -0,0 +1,33 @@ +#pragma once + +namespace orange +{ + struct FalseType { static constexpr bool Value = false; }; + struct TrueType { static constexpr bool Value = true; }; + + template struct IsLValueReference : FalseType {}; + template struct IsLValueReference : TrueType {}; + + template struct RemoveReference_ { using Type = T; }; + template struct RemoveReference_ { using Type = T; }; + template struct RemoveReference_ { using Type = T; }; + + template + using RemoveReference = typename RemoveReference_::Type; + + template + constexpr T&& Forward(RemoveReference& t) { return static_cast(t); } + + template + constexpr T&& Forward(RemoveReference&& t) + { + static_assert(!IsLValueReference::Value, "Can not forward an rvalue as an lvalue."); + return static_cast(t); + } + + template + constexpr RemoveReference&& Move(T&& arg) + { + return static_cast&&>(arg); + } +} \ No newline at end of file diff --git a/include/Orange/Core/Types.h b/include/Orange/Core/Types.h new file mode 100644 index 0000000..e0c95a5 --- /dev/null +++ b/include/Orange/Core/Types.h @@ -0,0 +1,4 @@ +#pragma once + +#include +#include diff --git a/include/Orange/Formats/BSP/Quake2.h b/include/Orange/Formats/BSP/Quake2.h new file mode 100644 index 0000000..0456088 --- /dev/null +++ b/include/Orange/Formats/BSP/Quake2.h @@ -0,0 +1,109 @@ +#pragma once + +#include + +namespace orange +{ + class Quake2BSP + { + public: + Quake2BSP(const void* data, size_t size); + private: + static constexpr uint32_t LumpCount = 19; + static constexpr uint32_t MaxLightmapStyles = 4; + + struct LumpType + { + enum + { + Entities, + Planes, + Vertices, + Visibility, + Nodes, + TextureInfo, + Faces, + Lightmaps, + Leaves, + LeafFaceTable, + LeafBrushTable, + Edges, + FaceEdgeTable, + Models, + Brushes, + BrushSides, + Pop, + Areas, + AreaPortals, + }; + }; + + struct LumpPointer + { + uint32_t offset; + uint32_t length; + }; + + struct BSPHeader + { + uint32_t magic; + uint32_t version; + + LumpPointer lumps[LumpCount]; + }; + + struct BSPFace + { + uint16_t plane; + uint16_t planeSide; + + uint32_t firstEdge; + uint16_t numEdges; + + uint16_t textureInfoIdx; + + uint8_t lightmapStyles[MaxLightmapStyles]; + uint32_t lightmapOffset; + }; + + struct BSPPlane + { + float normal[3]; + float distance; + uint32_t type; + }; + + struct BSPNode + { + uint32_t plane; + + int32_t frontChild; + int32_t backChild; + + int16_t bboxMins[3]; + int16_t bboxMaxs[3]; + + uint16_t firstLeafFace; + uint16_t numLeafFaces; + + uint16_t firstLeafBrush; + uint16_t numLeafBrushes; + }; + + struct BSPTexInfo + { + float uAxis[3]; + float uOffset; + + float vAxis[3]; + float vOffset; + + uint32_t flags; + uint32_t value; + + char textureName[32]; + + uint32_t nextTexInfo; + }; + }; +} diff --git a/include/Orange/Render/ForwardRenderer.h b/include/Orange/Render/ForwardRenderer.h new file mode 100644 index 0000000..2627af6 --- /dev/null +++ b/include/Orange/Render/ForwardRenderer.h @@ -0,0 +1,28 @@ +#pragma once + +#include +#include + +namespace orange +{ + class ForwardRenderer : public Renderer + { + public: + ~ForwardRenderer() = default; + + static Result create(SDL_Window* window, const char* name) + { + Result result; + + ForwardRenderer& renderer = result.Create(); + + if ((renderer.m_instance = createInstance(window, name)) == VK_NULL_HANDLE) + return result.Error(BasicErrorCode::Failed); + + return result.Success(); + } + protected: + friend Result; + ForwardRenderer() = default; + }; +} \ No newline at end of file diff --git a/include/Orange/Render/Renderer.h b/include/Orange/Render/Renderer.h new file mode 100644 index 0000000..8ab9166 --- /dev/null +++ b/include/Orange/Render/Renderer.h @@ -0,0 +1,71 @@ +#pragma once + +#include +#include + +#include +#include +#include + +namespace orange +{ + + class Renderer + { + public: + ~Renderer() = default; + + protected: + Renderer() = default; + + static VkInstance createInstance(SDL_Window* window, const char* name) + { + uint32_t instanceExtensionCount = {}; + if (SDL_Vulkan_GetInstanceExtensions(window, &instanceExtensionCount, nullptr) != SDL_TRUE) + { + //std::cerr << "Failed to get SDL instance extension count.\n"; + return VK_NULL_HANDLE; + } + + SmallVector instanceExtensions{ instanceExtensionCount }; + if (SDL_Vulkan_GetInstanceExtensions(window, &instanceExtensionCount, instanceExtensions.Data()) != SDL_TRUE) + { + //std::cerr << "Failed to get SDL instance extensions.\n"; + return VK_NULL_HANDLE; + } + + VkApplicationInfo appInfo = + { + .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO, + .pApplicationName = name, + .applicationVersion = VK_MAKE_VERSION(1, 0, 0), + .pEngineName = "Orange", + .engineVersion = VK_MAKE_VERSION(1, 0, 0), + .apiVersion = VK_API_VERSION_1_3, + }; + + VkInstanceCreateInfo instanceInfo = + { + .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, + .pApplicationInfo = &appInfo, + .enabledExtensionCount = instanceExtensionCount, + .ppEnabledExtensionNames = instanceExtensions.Data(), + }; + + VkResult result = VK_SUCCESS; + VkInstance instance; + if ((result = vkCreateInstance(&instanceInfo, nullptr, &instance)) != VK_SUCCESS) + { + //std::cerr << "Failed to create Vulkan instance.\n"; + return VK_NULL_HANDLE; + } + + return instance; + } + + VkInstance m_instance = VK_NULL_HANDLE; + VkPhysicalDevice m_physicalDevice = VK_NULL_HANDLE; + VkDevice m_device = VK_NULL_HANDLE; + }; + +} \ No newline at end of file diff --git a/meson.build b/meson.build new file mode 100644 index 0000000..520f4eb --- /dev/null +++ b/meson.build @@ -0,0 +1,16 @@ +project('orange', ['cpp'], version : '0.0.1', meson_version : '>= 0.49', default_options : [ + 'warning_level=2', + 'c_std=c11', + 'cpp_std=c++20' +]) + +orange_compiler = meson.get_compiler('cpp') +add_project_arguments(orange_compiler.get_supported_arguments([ + '-Wno-missing-field-initializers', +]), language : 'cpp') + +orange_include = include_directories(['include']) +sdl2_dep = dependency('SDL2') +vulkan_dep = dependency('vulkan') # get rid of me! + +subdir('src') diff --git a/src/Apps/Tools/BSPViewer.cpp b/src/Apps/Tools/BSPViewer.cpp new file mode 100644 index 0000000..0b3f3fd --- /dev/null +++ b/src/Apps/Tools/BSPViewer.cpp @@ -0,0 +1,7 @@ +#include +#include + +int main(int argc, char** argv) +{ + +} diff --git a/src/Apps/Tools/meson.build b/src/Apps/Tools/meson.build new file mode 100644 index 0000000..662667b --- /dev/null +++ b/src/Apps/Tools/meson.build @@ -0,0 +1,3 @@ +executable('BSPViewer', 'BSPViewer.cpp', + dependencies : [sdl2_dep, vulkan_dep], + include_directories : [orange_include]) diff --git a/src/Apps/meson.build b/src/Apps/meson.build new file mode 100644 index 0000000..6750ddd --- /dev/null +++ b/src/Apps/meson.build @@ -0,0 +1 @@ +subdir('Tools') diff --git a/src/meson.build b/src/meson.build new file mode 100644 index 0000000..9cf7eec --- /dev/null +++ b/src/meson.build @@ -0,0 +1 @@ +subdir('Apps') \ No newline at end of file