WE GOT TEXTURES BABY

This commit is contained in:
2026-01-08 02:43:34 +01:00
parent e306c5e23f
commit 10b00b0525
24 changed files with 828 additions and 272 deletions

View File

@@ -34,6 +34,7 @@ protected:
CPUMesh testMesh{};
MeshID testMeshID;
MaterialID testMaterialID;
GfxDevice gfxDevice;
GameRenderer renderer;
@@ -41,8 +42,7 @@ protected:
Camera camera{glm::vec3(0.f, 0.f, -5.f), glm::vec3(0, 1, 0)};
MeshCache meshCache;
InputManager inputManager;
MaterialCache materialCache;
bool isRunning{false};
bool gamePaused{false};

View File

@@ -0,0 +1,33 @@
#ifndef BINDLESSSETMANAGER_H
#define BINDLESSSETMANAGER_H
#include <cstdint>
#include <vulkan/vulkan.h>
struct GPUImage;
class BindlessSetManager {
public:
void init(VkDevice device, float maxAnisotropy);
void cleanup(VkDevice device);
VkDescriptorSetLayout getDescSetLayout() const { return descSetLayout; }
const VkDescriptorSet& getDescSet() const { return descSet; }
void addImage(VkDevice device, std::uint32_t id, const VkImageView imageView);
void addSampler(VkDevice device, std::uint32_t id, VkSampler sampler);
private:
void initDefaultSamplers(VkDevice device, float maxAnisotropy);
VkDescriptorPool descPool;
VkDescriptorSetLayout descSetLayout;
VkDescriptorSet descSet;
VkSampler nearestSampler;
VkSampler linearSampler;
VkSampler shadowMapSampler;
};
#endif //BINDLESSSETMANAGER_H

View File

@@ -57,6 +57,11 @@ public:
void waitIdle();
BindlessSetManager& getBindlessSetManager();
VkDescriptorSetLayout getBindlessDescSetLayout() const;
const VkDescriptorSet& getBindlessDescSet() const;
void bindBindlessDescSet(VkCommandBuffer cmd, VkPipelineLayout layout) const;
void immediateSubmit(ImmediateExecuteFunction&& f) const;
vkb::Device getDevice() const { return device; }
@@ -96,6 +101,8 @@ public:
GPUImage loadImageFromFileRaw(const std::filesystem::path& path, VkFormat format, VkImageUsageFlags usage, bool mipMap) const;
void destroyImage(const GPUImage& image) const;
ImageID getWhiteTextureID() { return whiteImageId; }
private:
vkb::Instance instance;
vkb::PhysicalDevice physicalDevice;

View File

@@ -9,6 +9,7 @@
#include <destrum/Graphics/ids.h>
#include <destrum/Graphics/GPUImage.h>
#include <destrum/Graphics/BindlessSetManager.h>
// #include <destrum/Graphics/Vulkan/BindlessSetManager.h>
@@ -34,7 +35,7 @@ public:
void destroyImages();
// BindlessSetManager bindlessSetManager;
BindlessSetManager bindlessSetManager;
void setErrorImageId(ImageID id) { errorImageId = id; }

View File

@@ -5,7 +5,7 @@
#include <glm/glm.hpp>
struct MaterialData {
glm::vec3 baseColor;
glm::vec4 baseColor;
glm::vec4 metalRoughnessEmissive;
std::uint32_t diffuseTex;
std::uint32_t normalTex;

View File

@@ -17,11 +17,11 @@ public:
void init(GfxDevice& gfxDevice);
void cleanup(GfxDevice& gfxDevice);
MaterialId addMaterial(GfxDevice& gfxDevice, Material material);
const Material& getMaterial(MaterialId id) const;
MaterialID addMaterial(GfxDevice& gfxDevice, Material material);
const Material& getMaterial(MaterialID id) const;
MaterialId getFreeMaterialId() const;
MaterialId getPlaceholderMaterialId() const;
MaterialID getFreeMaterialId() const;
MaterialID getPlaceholderMaterialId() const;
const GPUBuffer& getMaterialDataBuffer() const { return materialDataBuffer; }
VkDeviceAddress getMaterialDataBufferAddress() const { return materialDataBuffer.address; }
@@ -33,7 +33,7 @@ private:
GPUBuffer materialDataBuffer;
// material which is used for meshes without materials
MaterialId placeholderMaterialId{NULL_MATERIAL_ID};
MaterialID placeholderMaterialId{NULL_MATERIAL_ID};
ImageID defaultNormalMapTextureID{NULL_IMAGE_ID};
};

View File

@@ -15,7 +15,7 @@ struct MeshDrawCommand {
// If set - mesh will be drawn with overrideMaterialId
// instead of whatever material the mesh has
MaterialId materialId{NULL_MATERIAL_ID};
MaterialID materialId{NULL_MATERIAL_ID};
bool castShadow{true};

View File

@@ -23,7 +23,7 @@ public:
float fogDensity;
};
explicit GameRenderer(MeshCache& meshCache);
explicit GameRenderer(MeshCache& meshCache, MaterialCache& matCache);
void init(GfxDevice& gfxDevice, const glm::ivec2& drawImageSize);
void beginDrawing(GfxDevice& gfxDevice);
@@ -32,7 +32,7 @@ public:
void draw(VkCommandBuffer cmd, GfxDevice& gfxDevice, const Camera& camera, const SceneData& sceneData);
void cleanup();
void drawMesh(MeshID id, const glm::mat4& transform, MaterialId materialId);
void drawMesh(MeshID id, const glm::mat4& transform, MaterialID materialId);
const GPUImage& getDrawImage(const GfxDevice& gfx_device) const;
void resize(GfxDevice& gfxDevice, const glm::ivec2& newSize) {
@@ -43,7 +43,7 @@ private:
void createDrawImage(GfxDevice& gfxDevice, const glm::ivec2& drawImageSize, bool firstCreate);
MeshCache& meshCache;
// MaterialCache& materialCache;
MaterialCache& materialCache;
std::vector<MeshDrawCommand> meshDrawCommands;
std::vector<std::size_t> sortedMeshDrawCommands;
@@ -77,8 +77,6 @@ private:
NBuffer sceneDataBuffer;
MaterialCache materialCache;
std::unique_ptr<MeshPipeline> meshPipeline;
};

View File

@@ -94,12 +94,12 @@ static std::vector<CPUMesh::Vertex> vertices = {
};
static std::vector<uint32_t> indices = {
0, 1, 2, 2, 3, 0, // Front
4, 5, 6, 6, 7, 4, // Back
8, 9,10, 10,11, 8, // Right
12,13,14, 14,15,12, // Left
16,17,18, 18,19,16, // Top
20,21,22, 22,23,20 // Bottom
0, 1, 2, 2, 3, 0, // Front (+Z)
4, 7, 6, 6, 5, 4, // Back (-Z)
8, 9,10, 10,11, 8, // Right (+X)
12,13,14, 14,15,12, // Left (-X)
16,17,18, 18,19,16, // Top (+Y)
20,21,22, 22,23,20 // Bottom(-Y)
};

View File

@@ -10,8 +10,8 @@ constexpr MeshID NULL_MESH_ID = std::numeric_limits<std::size_t>::max();
using ImageID = std::uint16_t;
constexpr ImageID NULL_IMAGE_ID = std::numeric_limits<std::uint16_t>::max();
using MaterialId = std::uint32_t;
constexpr MaterialId NULL_MATERIAL_ID = std::numeric_limits<std::uint32_t>::max();
using MaterialID = std::uint32_t;
constexpr MaterialID NULL_MATERIAL_ID = std::numeric_limits<std::uint32_t>::max();
using BindlessID = std::uint32_t;
constexpr BindlessID NULL_BINDLESS_ID = std::numeric_limits<std::uint32_t>::max();

View File

@@ -6,59 +6,81 @@
#include <unordered_set>
#include <string>
#include <vector>
#include <array>
#include <cstdint>
class InputManager {
#include <destrum/Singleton.h>
class InputManager: public Singleton<InputManager> {
public:
// Call once at startup (optional, but convenient)
friend class Singleton<InputManager>;
void Init();
// Call at the start of every frame
void BeginFrame();
// Feed SDL events into this (call for each SDL_PollEvent)
void ProcessEvent(const SDL_Event& e);
// Call at end of frame if you want (not required)
void EndFrame() {}
// ---- Queries ----
bool IsKeyDown(SDL_Scancode sc) const; // held
bool WasKeyPressed(SDL_Scancode sc) const; // pressed this frame
bool WasKeyReleased(SDL_Scancode sc) const; // released this frame
bool IsKeyDown(SDL_Scancode sc) const;
bool WasKeyPressed(SDL_Scancode sc) const;
bool WasKeyReleased(SDL_Scancode sc) const;
bool IsMouseDown(Uint8 button) const; // held (SDL_BUTTON_LEFT etc.)
bool WasMousePressed(Uint8 button) const; // pressed this frame
bool WasMouseReleased(Uint8 button) const; // released this frame
bool IsMouseDown(Uint8 button) const;
bool WasMousePressed(Uint8 button) const;
bool WasMouseReleased(Uint8 button) const;
// Mouse position (window space)
int MouseX() const { return m_mouseX; }
int MouseY() const { return m_mouseY; }
int MouseDeltaX() const { return m_mouseDX; }
int MouseDeltaY() const { return m_mouseDY; }
// Mouse wheel (accumulated per frame)
int WheelX() const { return m_wheelX; }
int WheelY() const { return m_wheelY; }
// ---- Text input ----
void StartTextInput();
void StopTextInput();
bool IsTextInputActive() const { return m_textInputActive; }
const std::string& GetTextInput() const { return m_textInput; } // captured this frame
const std::string& GetTextInput() const { return m_textInput; }
// ---- Action mapping ----
enum class Device { Keyboard, MouseButton, MouseWheel };
bool IsPadButtonDown(SDL_JoystickID id, SDL_GameControllerButton btn) const;
bool WasPadButtonPressed(SDL_JoystickID id, SDL_GameControllerButton btn) const;
bool WasPadButtonReleased(SDL_JoystickID id, SDL_GameControllerButton btn) const;
// axis in [-1..1]
float GetPadAxis(SDL_JoystickID id, SDL_GameControllerAxis axis) const;
enum class Device { Keyboard, MouseButton, MouseWheel, GamepadButton, GamepadAxis };
enum class ButtonState { Down, Pressed, Released };
struct Binding {
Device device;
int code; // SDL_Scancode for keyboard, Uint8 for mouse button, wheel axis sign encoding
// For MouseWheel: code = +1/-1 for Y, +2/-2 for X (simple encoding)
// Keyboard: code = SDL_Scancode
// MouseButton: code = Uint8
// MouseWheel: code = +1/-1 => Y, +2/-2 => X
//
// GamepadButton: code = (padIndex<<8) | button (padIndex: 0..255)
// GamepadAxis: code = (padIndex<<8) | axis (axis: SDL_GameControllerAxis)
int code = 0;
// For GamepadAxis "button-like" checks:
// sign: -1 means negative direction, +1 positive direction
// threshold: absolute value in [0..1] that must be exceeded
int sign = 0; // only used for GamepadAxis
float threshold = 0.5f; // only used for GamepadAxis
};
void BindAction(const std::string& action, const Binding& binding);
bool GetAction(const std::string& action, ButtonState state) const;
// Convenience helpers to build controller bindings
static Binding PadButton(uint8_t padIndex, SDL_GameControllerButton btn);
static Binding PadAxis(uint8_t padIndex, SDL_GameControllerAxis axis, int sign, float threshold = 0.5f);
// Which controller is "padIndex 0/1/2..."? (based on connection order)
SDL_JoystickID GetPadInstanceId(uint8_t padIndex) const;
void SetAxisDeadzone(int deadzone) { m_axisDeadzone = deadzone; } // 0..32767
private:
// Key states
std::unordered_set<SDL_Scancode> m_keysDown;
@@ -75,18 +97,42 @@ private:
int m_prevMouseX = 0, m_prevMouseY = 0;
int m_mouseDX = 0, m_mouseDY = 0;
// Wheel (per-frame)
int m_wheelX = 0, m_wheelY = 0;
// Text input (per-frame)
bool m_textInputActive = false;
std::string m_textInput;
// Action bindings
std::unordered_map<std::string, std::vector<Binding>> m_bindings;
struct PadState {
SDL_GameController* controller = nullptr;
SDL_JoystickID instanceId = -1;
std::unordered_set<uint8_t> buttonsDown;
std::unordered_set<uint8_t> buttonsPressed;
std::unordered_set<uint8_t> buttonsReleased;
// raw s16 axes (SDL gives Sint16)
std::array<Sint16, SDL_CONTROLLER_AXIS_MAX> axes{};
std::array<Sint16, SDL_CONTROLLER_AXIS_MAX> prevAxes{};
};
// Map instanceId -> PadState
std::unordered_map<SDL_JoystickID, PadState> m_pads;
// padIndex -> instanceId (connection order list)
std::vector<SDL_JoystickID> m_padOrder;
int m_axisDeadzone = 8000; // typical deadzone
private:
bool QueryBinding(const Binding& b, ButtonState state) const;
void AddController(int deviceIndex);
void RemoveController(SDL_JoystickID instanceId);
uint8_t GetPadIndexFromCode(int code) const { return static_cast<uint8_t>((code >> 8) & 0xFF); }
uint8_t GetLow8FromCode(int code) const { return static_cast<uint8_t>(code & 0xFF); }
};
#endif //INPUTMANAGER_H