#pragma once #include #include #include #include namespace fxn { struct Vector4 { float x; float y; float z; float w; }; struct alignas(16) Vector3 // input { float x; float y; float z; }; struct scrVector3 // output { alignas(8) float x; alignas(8) float y; alignas(8) float z; }; struct Vector2 { float x; float y; }; struct alignas(16) scrVector3N { float x; float y; float z; }; struct VectorSpace { scrVector3* outVectors[4]; scrVector3N inVectors[4]; }; struct NativeContext { private: void* m_ReturnBuffer; std::uint32_t m_ArgumentCount; void* m_Arguments; std::uint32_t m_DataCount; VectorSpace m_VectorSpace; scrVector3 m_Vectors[4]; enum { MAX_ARGUMENTS = 32, ARGUMENT_SIZE = sizeof(void*) }; std::uint8_t m_Stack[MAX_ARGUMENTS * ARGUMENT_SIZE]; std::uint64_t m_NativeHash; std::atomic_bool m_Executed; public: inline NativeContext() : m_ReturnBuffer(nullptr), m_ArgumentCount(0), m_Arguments(nullptr), m_DataCount(0), m_NativeHash(0), m_VectorSpace{}, m_Vectors{}, m_Stack{}, m_Executed(false) { for (std::size_t i = 0; i < sizeof(m_Stack); i++) { m_Stack[i] = 0; } m_Arguments = &m_Stack; m_ReturnBuffer = &m_Stack; m_ArgumentCount = 0; m_DataCount = 0; } inline NativeContext(std::uint64_t hash) : NativeContext() { m_NativeHash = hash; } public: template inline void PushArgument(const T& arg) { if (m_ArgumentCount >= MAX_ARGUMENTS) { throw std::runtime_error("Exceeded maximum number of arguments."); } if constexpr (sizeof(T) < ARGUMENT_SIZE) { // Zero out the memory to avoid garbage values *reinterpret_cast(m_Stack + (m_ArgumentCount * ARGUMENT_SIZE)) = 0; } *reinterpret_cast(m_Stack + (m_ArgumentCount * ARGUMENT_SIZE)) = arg; m_ArgumentCount++; } template<> inline void PushArgument(const Vector3& arg) { PushArgument(arg.x); PushArgument(arg.y); PushArgument(arg.z); } template inline T GetResult() { return *reinterpret_cast(m_ReturnBuffer); } template<> inline Vector3 GetResult() { auto vec = *reinterpret_cast(m_ReturnBuffer); return Vector3{ vec.x, vec.y, vec.z }; // fix for alignment issues } inline void SetExecuted(bool executed) { m_Executed.store(executed, std::memory_order_release); } inline bool IsExecuted() const { return m_Executed.load(std::memory_order_acquire); } inline void SetVectorResults() { for (size_t i = 0; i < m_DataCount; i++) { auto outVector = m_VectorSpace.outVectors[i]; const auto& inVector = m_VectorSpace.inVectors[i]; outVector->x = inVector.x; outVector->y = inVector.y; outVector->z = inVector.z; } } template inline const T& GetArgument(std::size_t index) const { if (index >= m_ArgumentCount) { throw std::out_of_range("Argument index out of range."); } auto functionData = reinterpret_cast(m_Arguments); return *reinterpret_cast(&functionData[index]); } inline std::uint64_t GetNativeHash() const { return m_NativeHash; } }; }