2026-02-02 12:24:50 -08:00
|
|
|
#pragma once
|
|
|
|
|
|
|
|
|
|
#include "pipeline/m2_loader.hpp"
|
2026-02-21 19:41:21 -08:00
|
|
|
#include <vulkan/vulkan.h>
|
|
|
|
|
#include <vk_mem_alloc.h>
|
2026-02-02 12:24:50 -08:00
|
|
|
#include <glm/glm.hpp>
|
|
|
|
|
#include <memory>
|
|
|
|
|
#include <vector>
|
|
|
|
|
#include <unordered_map>
|
|
|
|
|
#include <unordered_set>
|
|
|
|
|
#include <string>
|
2026-02-22 06:21:18 -08:00
|
|
|
#include <utility>
|
2026-02-22 06:32:49 -08:00
|
|
|
#include <future>
|
2026-02-02 12:24:50 -08:00
|
|
|
|
|
|
|
|
namespace wowee {
|
|
|
|
|
namespace pipeline { class AssetManager; }
|
|
|
|
|
namespace rendering {
|
|
|
|
|
|
|
|
|
|
// Forward declarations
|
|
|
|
|
class Camera;
|
2026-02-21 19:41:21 -08:00
|
|
|
class VkContext;
|
|
|
|
|
class VkTexture;
|
2026-02-02 12:24:50 -08:00
|
|
|
|
|
|
|
|
// Weapon attached to a character instance at a bone attachment point
|
|
|
|
|
struct WeaponAttachment {
|
|
|
|
|
uint32_t weaponModelId;
|
|
|
|
|
uint32_t weaponInstanceId;
|
|
|
|
|
uint32_t attachmentId; // 1=RightHand, 2=LeftHand
|
|
|
|
|
uint16_t boneIndex;
|
|
|
|
|
glm::vec3 offset;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Character renderer for M2 models with skeletal animation
|
|
|
|
|
*
|
|
|
|
|
* Features:
|
|
|
|
|
* - Skeletal animation with bone transformations
|
|
|
|
|
* - Keyframe interpolation (linear position/scale, slerp rotation)
|
2026-02-21 19:41:21 -08:00
|
|
|
* - Vertex skinning (GPU-accelerated via bone SSBO)
|
2026-02-02 12:24:50 -08:00
|
|
|
* - Texture loading from BLP via AssetManager
|
|
|
|
|
*/
|
|
|
|
|
class CharacterRenderer {
|
|
|
|
|
public:
|
|
|
|
|
CharacterRenderer();
|
|
|
|
|
~CharacterRenderer();
|
|
|
|
|
|
2026-02-22 05:58:45 -08:00
|
|
|
bool initialize(VkContext* ctx, VkDescriptorSetLayout perFrameLayout, pipeline::AssetManager* am,
|
2026-02-23 10:48:26 -08:00
|
|
|
VkRenderPass renderPassOverride = VK_NULL_HANDLE,
|
|
|
|
|
VkSampleCountFlagBits msaaSamples = VK_SAMPLE_COUNT_1_BIT);
|
2026-02-02 12:24:50 -08:00
|
|
|
void shutdown();
|
|
|
|
|
|
|
|
|
|
void setAssetManager(pipeline::AssetManager* am) { assetManager = am; }
|
|
|
|
|
|
|
|
|
|
bool loadModel(const pipeline::M2Model& model, uint32_t id);
|
|
|
|
|
|
|
|
|
|
uint32_t createInstance(uint32_t modelId, const glm::vec3& position,
|
|
|
|
|
const glm::vec3& rotation = glm::vec3(0.0f),
|
|
|
|
|
float scale = 1.0f);
|
|
|
|
|
|
|
|
|
|
void playAnimation(uint32_t instanceId, uint32_t animationId, bool loop = true);
|
|
|
|
|
|
2026-02-10 19:30:45 -08:00
|
|
|
void update(float deltaTime, const glm::vec3& cameraPos = glm::vec3(0.0f));
|
2026-02-02 12:24:50 -08:00
|
|
|
|
2026-02-21 19:41:21 -08:00
|
|
|
void render(VkCommandBuffer cmd, VkDescriptorSet perFrameSet, const Camera& camera);
|
2026-02-22 02:59:24 -08:00
|
|
|
void recreatePipelines();
|
2026-02-21 19:49:50 -08:00
|
|
|
bool initializeShadow(VkRenderPass shadowRenderPass);
|
2026-02-23 04:59:39 -08:00
|
|
|
void renderShadow(VkCommandBuffer cmd, const glm::mat4& lightSpaceMatrix,
|
|
|
|
|
const glm::vec3& shadowCenter = glm::vec3(0), float shadowRadius = 1e9f);
|
2026-02-02 12:24:50 -08:00
|
|
|
|
|
|
|
|
void setInstancePosition(uint32_t instanceId, const glm::vec3& position);
|
|
|
|
|
void setInstanceRotation(uint32_t instanceId, const glm::vec3& rotation);
|
2026-02-06 13:47:03 -08:00
|
|
|
void moveInstanceTo(uint32_t instanceId, const glm::vec3& destination, float durationSeconds);
|
|
|
|
|
void startFadeIn(uint32_t instanceId, float durationSeconds);
|
|
|
|
|
const pipeline::M2Model* getModelData(uint32_t modelId) const;
|
2026-02-02 12:24:50 -08:00
|
|
|
void setActiveGeosets(uint32_t instanceId, const std::unordered_set<uint16_t>& geosets);
|
2026-02-21 19:41:21 -08:00
|
|
|
void setGroupTextureOverride(uint32_t instanceId, uint16_t geosetGroup, VkTexture* texture);
|
|
|
|
|
void setTextureSlotOverride(uint32_t instanceId, uint16_t textureSlot, VkTexture* texture);
|
2026-02-13 19:40:54 -08:00
|
|
|
void clearTextureSlotOverride(uint32_t instanceId, uint16_t textureSlot);
|
2026-02-03 14:26:08 -08:00
|
|
|
void setInstanceVisible(uint32_t instanceId, bool visible);
|
2026-02-02 12:24:50 -08:00
|
|
|
void removeInstance(uint32_t instanceId);
|
2026-02-03 14:55:32 -08:00
|
|
|
bool getAnimationState(uint32_t instanceId, uint32_t& animationId, float& animationTimeMs, float& animationDurationMs) const;
|
2026-02-03 19:29:11 -08:00
|
|
|
bool hasAnimation(uint32_t instanceId, uint32_t animationId) const;
|
2026-02-05 14:01:26 -08:00
|
|
|
bool getAnimationSequences(uint32_t instanceId, std::vector<pipeline::M2Sequence>& out) const;
|
2026-02-03 19:49:56 -08:00
|
|
|
bool getInstanceModelName(uint32_t instanceId, std::string& modelName) const;
|
2026-02-06 18:34:45 -08:00
|
|
|
bool getInstanceBounds(uint32_t instanceId, glm::vec3& outCenter, float& outRadius) const;
|
2026-02-20 16:02:34 -08:00
|
|
|
bool getInstanceFootZ(uint32_t instanceId, float& outFootZ) const;
|
2026-02-02 12:24:50 -08:00
|
|
|
|
2026-02-10 19:30:45 -08:00
|
|
|
/** Debug: Log all available animations for an instance */
|
|
|
|
|
void dumpAnimations(uint32_t instanceId) const;
|
|
|
|
|
|
2026-02-02 12:24:50 -08:00
|
|
|
/** Attach a weapon model to a character instance at the given attachment point. */
|
|
|
|
|
bool attachWeapon(uint32_t charInstanceId, uint32_t attachmentId,
|
|
|
|
|
const pipeline::M2Model& weaponModel, uint32_t weaponModelId,
|
|
|
|
|
const std::string& texturePath);
|
|
|
|
|
|
|
|
|
|
/** Detach a weapon from the given attachment point. */
|
|
|
|
|
void detachWeapon(uint32_t charInstanceId, uint32_t attachmentId);
|
|
|
|
|
|
2026-02-21 19:41:21 -08:00
|
|
|
/** Get the world-space transform of an attachment point on an instance. */
|
2026-02-10 19:30:45 -08:00
|
|
|
bool getAttachmentTransform(uint32_t instanceId, uint32_t attachmentId, glm::mat4& outTransform);
|
|
|
|
|
|
2026-02-02 12:24:50 -08:00
|
|
|
size_t getInstanceCount() const { return instances.size(); }
|
|
|
|
|
|
2026-02-23 01:40:23 -08:00
|
|
|
// Normal mapping / POM settings
|
|
|
|
|
void setNormalMappingEnabled(bool enabled) { normalMappingEnabled_ = enabled; }
|
|
|
|
|
void setNormalMapStrength(float strength) { normalMapStrength_ = strength; }
|
|
|
|
|
void setPOMEnabled(bool enabled) { pomEnabled_ = enabled; }
|
|
|
|
|
void setPOMQuality(int quality) { pomQuality_ = quality; }
|
|
|
|
|
|
2026-02-21 19:41:21 -08:00
|
|
|
// Fog/lighting/shadow are now in per-frame UBO — keep stubs for callers that haven't been updated
|
|
|
|
|
void setFog(const glm::vec3&, float, float) {}
|
|
|
|
|
void setLighting(const float[3], const float[3], const float[3]) {}
|
|
|
|
|
void setShadowMap(VkTexture*, const glm::mat4&) {}
|
|
|
|
|
void clearShadowMap() {}
|
2026-02-04 15:05:46 -08:00
|
|
|
|
2026-02-02 12:24:50 -08:00
|
|
|
private:
|
|
|
|
|
// GPU representation of M2 model
|
|
|
|
|
struct M2ModelGPU {
|
2026-02-21 19:41:21 -08:00
|
|
|
VkBuffer vertexBuffer = VK_NULL_HANDLE;
|
|
|
|
|
VmaAllocation vertexAlloc = VK_NULL_HANDLE;
|
|
|
|
|
VkBuffer indexBuffer = VK_NULL_HANDLE;
|
|
|
|
|
VmaAllocation indexAlloc = VK_NULL_HANDLE;
|
|
|
|
|
uint32_t indexCount = 0;
|
|
|
|
|
uint32_t vertexCount = 0;
|
2026-02-02 12:24:50 -08:00
|
|
|
|
|
|
|
|
pipeline::M2Model data; // Original model data
|
|
|
|
|
std::vector<glm::mat4> bindPose; // Inverse bind pose matrices
|
|
|
|
|
|
|
|
|
|
// Textures loaded from BLP (indexed by texture array position)
|
2026-02-21 19:41:21 -08:00
|
|
|
std::vector<VkTexture*> textureIds;
|
2026-02-02 12:24:50 -08:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Character instance
|
|
|
|
|
struct CharacterInstance {
|
|
|
|
|
uint32_t id;
|
|
|
|
|
uint32_t modelId;
|
|
|
|
|
|
|
|
|
|
glm::vec3 position;
|
|
|
|
|
glm::vec3 rotation;
|
|
|
|
|
float scale;
|
2026-02-03 14:26:08 -08:00
|
|
|
bool visible = true; // For first-person camera hiding
|
2026-02-02 12:24:50 -08:00
|
|
|
|
|
|
|
|
// Animation state
|
|
|
|
|
uint32_t currentAnimationId = 0;
|
|
|
|
|
int currentSequenceIndex = -1; // Index into M2Model::sequences
|
|
|
|
|
float animationTime = 0.0f;
|
|
|
|
|
bool animationLoop = true;
|
2026-02-06 16:47:07 -08:00
|
|
|
bool isDead = false; // Prevents movement while in death state
|
2026-02-02 12:24:50 -08:00
|
|
|
std::vector<glm::mat4> boneMatrices; // Current bone transforms
|
|
|
|
|
|
|
|
|
|
// Geoset visibility — which submesh IDs to render
|
|
|
|
|
// Empty = render all (for non-character models)
|
|
|
|
|
std::unordered_set<uint16_t> activeGeosets;
|
|
|
|
|
|
2026-02-21 19:41:21 -08:00
|
|
|
// Per-geoset-group texture overrides (group → VkTexture*)
|
|
|
|
|
std::unordered_map<uint16_t, VkTexture*> groupTextureOverrides;
|
2026-02-06 01:02:35 -08:00
|
|
|
|
2026-02-21 19:41:21 -08:00
|
|
|
// Per-texture-slot overrides (slot → VkTexture*)
|
|
|
|
|
std::unordered_map<uint16_t, VkTexture*> textureSlotOverrides;
|
2026-02-13 19:40:54 -08:00
|
|
|
|
2026-02-02 12:24:50 -08:00
|
|
|
// Weapon attachments (weapons parented to this instance's bones)
|
|
|
|
|
std::vector<WeaponAttachment> weaponAttachments;
|
|
|
|
|
|
2026-02-06 13:47:03 -08:00
|
|
|
// Opacity (for fade-in)
|
|
|
|
|
float opacity = 1.0f;
|
|
|
|
|
float fadeInTime = 0.0f; // elapsed fade time (seconds)
|
|
|
|
|
float fadeInDuration = 0.0f; // total fade duration (0 = no fade)
|
|
|
|
|
|
|
|
|
|
// Movement interpolation
|
|
|
|
|
bool isMoving = false;
|
|
|
|
|
glm::vec3 moveStart{0.0f};
|
|
|
|
|
glm::vec3 moveEnd{0.0f};
|
|
|
|
|
float moveDuration = 0.0f; // seconds
|
|
|
|
|
float moveElapsed = 0.0f;
|
|
|
|
|
|
2026-02-02 12:24:50 -08:00
|
|
|
// Override model matrix (used for weapon instances positioned by parent bone)
|
|
|
|
|
bool hasOverrideModelMatrix = false;
|
|
|
|
|
glm::mat4 overrideModelMatrix{1.0f};
|
2026-02-21 19:41:21 -08:00
|
|
|
|
|
|
|
|
// Per-instance bone SSBO (double-buffered per frame)
|
|
|
|
|
VkBuffer boneBuffer[2] = {};
|
|
|
|
|
VmaAllocation boneAlloc[2] = {};
|
|
|
|
|
void* boneMapped[2] = {};
|
|
|
|
|
VkDescriptorSet boneSet[2] = {};
|
2026-02-02 12:24:50 -08:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
void setupModelBuffers(M2ModelGPU& gpuModel);
|
|
|
|
|
void calculateBindPose(M2ModelGPU& gpuModel);
|
|
|
|
|
void updateAnimation(CharacterInstance& instance, float deltaTime);
|
|
|
|
|
void calculateBoneMatrices(CharacterInstance& instance);
|
|
|
|
|
glm::mat4 getBoneTransform(const pipeline::M2Bone& bone, float time, int sequenceIndex);
|
|
|
|
|
glm::mat4 getModelMatrix(const CharacterInstance& instance) const;
|
2026-02-21 19:41:21 -08:00
|
|
|
void destroyModelGPU(M2ModelGPU& gpuModel);
|
|
|
|
|
void destroyInstanceBones(CharacterInstance& inst);
|
2026-02-02 12:24:50 -08:00
|
|
|
|
|
|
|
|
// Keyframe interpolation helpers
|
|
|
|
|
static int findKeyframeIndex(const std::vector<uint32_t>& timestamps, float time);
|
|
|
|
|
static glm::vec3 interpolateVec3(const pipeline::M2AnimationTrack& track,
|
|
|
|
|
int seqIdx, float time, const glm::vec3& defaultVal);
|
|
|
|
|
static glm::quat interpolateQuat(const pipeline::M2AnimationTrack& track,
|
|
|
|
|
int seqIdx, float time);
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
/**
|
|
|
|
|
* Build a composited character skin texture by alpha-blending overlay
|
2026-02-21 19:41:21 -08:00
|
|
|
* layers onto a base skin BLP. Returns the resulting VkTexture*.
|
2026-02-02 12:24:50 -08:00
|
|
|
*/
|
2026-02-21 19:41:21 -08:00
|
|
|
VkTexture* compositeTextures(const std::vector<std::string>& layerPaths);
|
2026-02-02 12:24:50 -08:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Build a composited character skin with explicit region-based equipment overlays.
|
|
|
|
|
*/
|
2026-02-21 19:41:21 -08:00
|
|
|
VkTexture* compositeWithRegions(const std::string& basePath,
|
2026-02-02 12:24:50 -08:00
|
|
|
const std::vector<std::string>& baseLayers,
|
|
|
|
|
const std::vector<std::pair<int, std::string>>& regionLayers);
|
|
|
|
|
|
2026-02-15 20:53:01 -08:00
|
|
|
/** Clear the composite texture cache (forces re-compositing on next call). */
|
|
|
|
|
void clearCompositeCache();
|
|
|
|
|
|
2026-02-21 19:41:21 -08:00
|
|
|
/** Load a BLP texture from MPQ and return VkTexture* (cached). */
|
|
|
|
|
VkTexture* loadTexture(const std::string& path);
|
|
|
|
|
VkTexture* getTransparentTexture() const { return transparentTexture_.get(); }
|
2026-02-02 12:24:50 -08:00
|
|
|
|
2026-02-21 19:41:21 -08:00
|
|
|
/** Replace a loaded model's texture at the given slot. */
|
|
|
|
|
void setModelTexture(uint32_t modelId, uint32_t textureSlot, VkTexture* texture);
|
2026-02-02 12:24:50 -08:00
|
|
|
|
|
|
|
|
/** Reset a model's texture slot back to white fallback. */
|
|
|
|
|
void resetModelTexture(uint32_t modelId, uint32_t textureSlot);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private:
|
2026-02-21 19:41:21 -08:00
|
|
|
VkContext* vkCtx_ = nullptr;
|
2026-02-22 05:58:45 -08:00
|
|
|
VkRenderPass renderPassOverride_ = VK_NULL_HANDLE;
|
2026-02-23 10:48:26 -08:00
|
|
|
VkSampleCountFlagBits msaaSamplesOverride_ = VK_SAMPLE_COUNT_1_BIT;
|
2026-02-02 12:24:50 -08:00
|
|
|
pipeline::AssetManager* assetManager = nullptr;
|
|
|
|
|
|
2026-02-21 19:41:21 -08:00
|
|
|
// Vulkan pipelines (one per blend mode)
|
|
|
|
|
VkPipeline opaquePipeline_ = VK_NULL_HANDLE;
|
|
|
|
|
VkPipeline alphaTestPipeline_ = VK_NULL_HANDLE;
|
|
|
|
|
VkPipeline alphaPipeline_ = VK_NULL_HANDLE;
|
|
|
|
|
VkPipeline additivePipeline_ = VK_NULL_HANDLE;
|
|
|
|
|
VkPipelineLayout pipelineLayout_ = VK_NULL_HANDLE;
|
2026-02-04 15:05:46 -08:00
|
|
|
|
2026-02-21 19:41:21 -08:00
|
|
|
// Descriptor set layouts
|
|
|
|
|
VkDescriptorSetLayout perFrameLayout_ = VK_NULL_HANDLE; // set 0 (owned by Renderer)
|
|
|
|
|
VkDescriptorSetLayout materialSetLayout_ = VK_NULL_HANDLE; // set 1
|
|
|
|
|
VkDescriptorSetLayout boneSetLayout_ = VK_NULL_HANDLE; // set 2
|
Implement WoW-accurate DBC-driven sky system with lore-faithful celestial bodies
Add SkySystem coordinator that follows WoW's actual architecture where skyboxes
are authoritative and procedural elements serve as fallbacks. Integrate lighting
system across all renderers (terrain, WMO, M2, character) with unified parameters.
Sky System:
- SkySystem coordinator manages skybox, celestial bodies, stars, clouds, lens flare
- Skybox is authoritative (baked stars from M2 models, procedural fallback only)
- skyboxHasStars flag gates procedural star rendering (prevents double-star bug)
Celestial Bodies (Lore-Accurate):
- Two moons: White Lady (30-day cycle, pale white) + Blue Child (27-day cycle, pale blue)
- Deterministic moon phases from server gameTime (not deltaTime toys)
- Sun positioning driven by LightingManager directionalDir (DBC-sourced)
- Camera-locked sky dome (translation ignored, rotation applied)
Lighting Integration:
- Apply LightingManager params to WMO, M2, character renderers
- Unified lighting: directional light, diffuse color, ambient color, fog
- Star occlusion by cloud density (70% weight) and fog density (30% weight)
Documentation:
- Add comprehensive SKY_SYSTEM.md technical guide
- Update MEMORY.md with sky system architecture and anti-patterns
- Update README.md with WoW-accurate descriptions
Critical design decisions:
- NO latitude-based star rotation (Azeroth not modeled as spherical planet)
- NO always-on procedural stars (skybox authority prevents zone identity loss)
- NO universal dual-moon setup (map-specific celestial configurations)
2026-02-10 14:36:17 -08:00
|
|
|
|
2026-02-21 19:41:21 -08:00
|
|
|
// Descriptor pool
|
2026-02-22 06:21:18 -08:00
|
|
|
VkDescriptorPool materialDescPools_[2] = {VK_NULL_HANDLE, VK_NULL_HANDLE};
|
2026-02-21 19:41:21 -08:00
|
|
|
VkDescriptorPool boneDescPool_ = VK_NULL_HANDLE;
|
2026-02-22 06:21:18 -08:00
|
|
|
uint32_t lastMaterialPoolResetFrame_ = 0xFFFFFFFFu;
|
|
|
|
|
std::vector<std::pair<VkBuffer, VmaAllocation>> transientMaterialUbos_[2];
|
2026-02-04 15:05:46 -08:00
|
|
|
|
2026-02-02 12:24:50 -08:00
|
|
|
// Texture cache
|
2026-02-12 16:29:36 -08:00
|
|
|
struct TextureCacheEntry {
|
2026-02-21 19:41:21 -08:00
|
|
|
std::unique_ptr<VkTexture> texture;
|
2026-02-23 01:40:23 -08:00
|
|
|
std::unique_ptr<VkTexture> normalHeightMap;
|
|
|
|
|
float heightMapVariance = 0.0f;
|
2026-02-12 16:29:36 -08:00
|
|
|
size_t approxBytes = 0;
|
|
|
|
|
uint64_t lastUse = 0;
|
2026-02-19 02:39:33 -08:00
|
|
|
bool hasAlpha = false;
|
|
|
|
|
bool colorKeyBlack = false;
|
2026-02-12 16:29:36 -08:00
|
|
|
};
|
|
|
|
|
std::unordered_map<std::string, TextureCacheEntry> textureCache;
|
2026-02-21 19:41:21 -08:00
|
|
|
std::unordered_map<VkTexture*, bool> textureHasAlphaByPtr_;
|
|
|
|
|
std::unordered_map<VkTexture*, bool> textureColorKeyBlackByPtr_;
|
|
|
|
|
std::unordered_map<std::string, VkTexture*> compositeCache_; // key → texture for reuse
|
2026-02-23 06:51:06 -08:00
|
|
|
std::unordered_set<std::string> failedTextureCache_; // negative cache for budget exhaustion
|
|
|
|
|
std::unordered_set<std::string> loggedTextureLoadFails_; // dedup warning logs
|
2026-02-12 16:29:36 -08:00
|
|
|
size_t textureCacheBytes_ = 0;
|
|
|
|
|
uint64_t textureCacheCounter_ = 0;
|
2026-02-21 19:41:21 -08:00
|
|
|
size_t textureCacheBudgetBytes_ = 1024ull * 1024 * 1024;
|
2026-02-22 08:12:08 -08:00
|
|
|
uint32_t textureBudgetRejectWarnings_ = 0;
|
2026-02-21 19:41:21 -08:00
|
|
|
std::unique_ptr<VkTexture> whiteTexture_;
|
|
|
|
|
std::unique_ptr<VkTexture> transparentTexture_;
|
2026-02-23 01:40:23 -08:00
|
|
|
std::unique_ptr<VkTexture> flatNormalTexture_;
|
2026-02-02 12:24:50 -08:00
|
|
|
|
|
|
|
|
std::unordered_map<uint32_t, M2ModelGPU> models;
|
|
|
|
|
std::unordered_map<uint32_t, CharacterInstance> instances;
|
|
|
|
|
|
|
|
|
|
uint32_t nextInstanceId = 1;
|
|
|
|
|
|
2026-02-23 01:40:23 -08:00
|
|
|
// Normal map generation (same algorithm as WMO renderer)
|
|
|
|
|
std::unique_ptr<VkTexture> generateNormalHeightMap(
|
|
|
|
|
const uint8_t* pixels, uint32_t width, uint32_t height, float& outVariance);
|
|
|
|
|
|
|
|
|
|
// Normal mapping / POM settings
|
|
|
|
|
bool normalMappingEnabled_ = true;
|
|
|
|
|
float normalMapStrength_ = 0.8f;
|
|
|
|
|
bool pomEnabled_ = true;
|
|
|
|
|
int pomQuality_ = 1; // 0=Low(16), 1=Medium(32), 2=High(64)
|
|
|
|
|
|
2026-02-21 19:41:21 -08:00
|
|
|
// Maximum bones supported
|
2026-02-15 20:53:01 -08:00
|
|
|
static constexpr int MAX_BONES = 240;
|
2026-02-22 06:32:49 -08:00
|
|
|
uint32_t numAnimThreads_ = 1;
|
|
|
|
|
std::vector<std::future<void>> animFutures_;
|
2026-02-21 19:49:50 -08:00
|
|
|
|
|
|
|
|
// Shadow pipeline resources
|
|
|
|
|
VkPipeline shadowPipeline_ = VK_NULL_HANDLE;
|
|
|
|
|
VkPipelineLayout shadowPipelineLayout_ = VK_NULL_HANDLE;
|
|
|
|
|
VkDescriptorSetLayout shadowParamsLayout_ = VK_NULL_HANDLE;
|
|
|
|
|
VkDescriptorPool shadowParamsPool_ = VK_NULL_HANDLE;
|
|
|
|
|
VkDescriptorSet shadowParamsSet_ = VK_NULL_HANDLE;
|
|
|
|
|
VkBuffer shadowParamsUBO_ = VK_NULL_HANDLE;
|
|
|
|
|
VmaAllocation shadowParamsAlloc_ = VK_NULL_HANDLE;
|
2026-02-02 12:24:50 -08:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
} // namespace rendering
|
|
|
|
|
} // namespace wowee
|