2026-02-02 12:24:50 -08:00
|
|
|
#include "rendering/clouds.hpp"
|
2026-02-21 19:41:21 -08:00
|
|
|
#include "rendering/vk_context.hpp"
|
|
|
|
|
#include "rendering/vk_shader.hpp"
|
|
|
|
|
#include "rendering/vk_pipeline.hpp"
|
|
|
|
|
#include "rendering/vk_frame_data.hpp"
|
|
|
|
|
#include "rendering/vk_utils.hpp"
|
2026-02-02 12:24:50 -08:00
|
|
|
#include "core/logger.hpp"
|
|
|
|
|
#include <glm/gtc/matrix_transform.hpp>
|
|
|
|
|
#include <cmath>
|
|
|
|
|
|
|
|
|
|
namespace wowee {
|
|
|
|
|
namespace rendering {
|
|
|
|
|
|
2026-02-21 19:41:21 -08:00
|
|
|
Clouds::Clouds() = default;
|
2026-02-02 12:24:50 -08:00
|
|
|
|
|
|
|
|
Clouds::~Clouds() {
|
2026-02-21 19:41:21 -08:00
|
|
|
shutdown();
|
2026-02-02 12:24:50 -08:00
|
|
|
}
|
|
|
|
|
|
2026-02-21 19:41:21 -08:00
|
|
|
bool Clouds::initialize(VkContext* ctx, VkDescriptorSetLayout perFrameLayout) {
|
|
|
|
|
LOG_INFO("Initializing cloud system (Vulkan)");
|
2026-02-02 12:24:50 -08:00
|
|
|
|
2026-02-21 19:41:21 -08:00
|
|
|
vkCtx_ = ctx;
|
|
|
|
|
VkDevice device = vkCtx_->getDevice();
|
2026-02-02 12:24:50 -08:00
|
|
|
|
2026-02-21 19:41:21 -08:00
|
|
|
// ------------------------------------------------------------------ shaders
|
|
|
|
|
VkShaderModule vertModule;
|
|
|
|
|
if (!vertModule.loadFromFile(device, "assets/shaders/clouds.vert.spv")) {
|
|
|
|
|
LOG_ERROR("Failed to load clouds vertex shader");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2026-02-02 12:24:50 -08:00
|
|
|
|
2026-02-21 19:41:21 -08:00
|
|
|
VkShaderModule fragModule;
|
|
|
|
|
if (!fragModule.loadFromFile(device, "assets/shaders/clouds.frag.spv")) {
|
|
|
|
|
LOG_ERROR("Failed to load clouds fragment shader");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2026-02-02 12:24:50 -08:00
|
|
|
|
2026-02-21 19:41:21 -08:00
|
|
|
VkPipelineShaderStageCreateInfo vertStage = vertModule.stageInfo(VK_SHADER_STAGE_VERTEX_BIT);
|
|
|
|
|
VkPipelineShaderStageCreateInfo fragStage = fragModule.stageInfo(VK_SHADER_STAGE_FRAGMENT_BIT);
|
2026-02-02 12:24:50 -08:00
|
|
|
|
2026-02-21 19:41:21 -08:00
|
|
|
// ------------------------------------------------------------------ push constants
|
|
|
|
|
// Fragment-only push: vec4 cloudColor + float density + float windOffset = 24 bytes
|
|
|
|
|
VkPushConstantRange pushRange{};
|
|
|
|
|
pushRange.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
|
|
|
|
|
pushRange.offset = 0;
|
|
|
|
|
pushRange.size = sizeof(CloudPush); // 24 bytes
|
2026-02-02 12:24:50 -08:00
|
|
|
|
2026-02-21 19:41:21 -08:00
|
|
|
// ------------------------------------------------------------------ pipeline layout
|
|
|
|
|
pipelineLayout_ = createPipelineLayout(device, {perFrameLayout}, {pushRange});
|
|
|
|
|
if (pipelineLayout_ == VK_NULL_HANDLE) {
|
|
|
|
|
LOG_ERROR("Failed to create clouds pipeline layout");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2026-02-02 12:24:50 -08:00
|
|
|
|
2026-02-21 19:41:21 -08:00
|
|
|
// ------------------------------------------------------------------ vertex input
|
|
|
|
|
// Vertex: vec3 pos only, stride = 12 bytes
|
|
|
|
|
VkVertexInputBindingDescription binding{};
|
|
|
|
|
binding.binding = 0;
|
|
|
|
|
binding.stride = sizeof(glm::vec3); // 12 bytes
|
|
|
|
|
binding.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
|
|
|
|
|
|
|
|
|
|
VkVertexInputAttributeDescription posAttr{};
|
|
|
|
|
posAttr.location = 0;
|
|
|
|
|
posAttr.binding = 0;
|
|
|
|
|
posAttr.format = VK_FORMAT_R32G32B32_SFLOAT;
|
|
|
|
|
posAttr.offset = 0;
|
|
|
|
|
|
|
|
|
|
std::vector<VkDynamicState> dynamicStates = {
|
|
|
|
|
VK_DYNAMIC_STATE_VIEWPORT,
|
|
|
|
|
VK_DYNAMIC_STATE_SCISSOR
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------ pipeline
|
|
|
|
|
pipeline_ = PipelineBuilder()
|
|
|
|
|
.setShaders(vertStage, fragStage)
|
|
|
|
|
.setVertexInput({binding}, {posAttr})
|
|
|
|
|
.setTopology(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST)
|
|
|
|
|
.setRasterization(VK_POLYGON_MODE_FILL, VK_CULL_MODE_NONE)
|
|
|
|
|
.setDepthTest(true, false, VK_COMPARE_OP_LESS_OR_EQUAL) // test on, write off (sky layer)
|
|
|
|
|
.setColorBlendAttachment(PipelineBuilder::blendAlpha())
|
2026-02-22 02:59:24 -08:00
|
|
|
.setMultisample(vkCtx_->getMsaaSamples())
|
2026-02-21 19:41:21 -08:00
|
|
|
.setLayout(pipelineLayout_)
|
|
|
|
|
.setRenderPass(vkCtx_->getImGuiRenderPass())
|
|
|
|
|
.setDynamicStates(dynamicStates)
|
|
|
|
|
.build(device);
|
|
|
|
|
|
|
|
|
|
vertModule.destroy();
|
|
|
|
|
fragModule.destroy();
|
|
|
|
|
|
|
|
|
|
if (pipeline_ == VK_NULL_HANDLE) {
|
|
|
|
|
LOG_ERROR("Failed to create clouds pipeline");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2026-02-02 12:24:50 -08:00
|
|
|
|
2026-02-21 19:41:21 -08:00
|
|
|
// ------------------------------------------------------------------ geometry
|
|
|
|
|
generateMesh();
|
|
|
|
|
createBuffers();
|
2026-02-02 12:24:50 -08:00
|
|
|
|
2026-02-21 19:41:21 -08:00
|
|
|
LOG_INFO("Cloud system initialized: ", indexCount_ / 3, " triangles");
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2026-02-02 12:24:50 -08:00
|
|
|
|
2026-02-22 02:59:24 -08:00
|
|
|
void Clouds::recreatePipelines() {
|
|
|
|
|
if (!vkCtx_) return;
|
|
|
|
|
VkDevice device = vkCtx_->getDevice();
|
|
|
|
|
|
|
|
|
|
if (pipeline_ != VK_NULL_HANDLE) { vkDestroyPipeline(device, pipeline_, nullptr); pipeline_ = VK_NULL_HANDLE; }
|
|
|
|
|
|
|
|
|
|
VkShaderModule vertModule;
|
|
|
|
|
if (!vertModule.loadFromFile(device, "assets/shaders/clouds.vert.spv")) {
|
|
|
|
|
LOG_ERROR("Clouds::recreatePipelines: failed to load vertex shader");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
VkShaderModule fragModule;
|
|
|
|
|
if (!fragModule.loadFromFile(device, "assets/shaders/clouds.frag.spv")) {
|
|
|
|
|
LOG_ERROR("Clouds::recreatePipelines: failed to load fragment shader");
|
|
|
|
|
vertModule.destroy();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VkPipelineShaderStageCreateInfo vertStage = vertModule.stageInfo(VK_SHADER_STAGE_VERTEX_BIT);
|
|
|
|
|
VkPipelineShaderStageCreateInfo fragStage = fragModule.stageInfo(VK_SHADER_STAGE_FRAGMENT_BIT);
|
|
|
|
|
|
|
|
|
|
// Vertex input (same as initialize)
|
|
|
|
|
VkVertexInputBindingDescription binding{};
|
|
|
|
|
binding.binding = 0;
|
|
|
|
|
binding.stride = sizeof(glm::vec3);
|
|
|
|
|
binding.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
|
|
|
|
|
|
|
|
|
|
VkVertexInputAttributeDescription posAttr{};
|
|
|
|
|
posAttr.location = 0;
|
|
|
|
|
posAttr.binding = 0;
|
|
|
|
|
posAttr.format = VK_FORMAT_R32G32B32_SFLOAT;
|
|
|
|
|
posAttr.offset = 0;
|
|
|
|
|
|
|
|
|
|
std::vector<VkDynamicState> dynamicStates = {
|
|
|
|
|
VK_DYNAMIC_STATE_VIEWPORT,
|
|
|
|
|
VK_DYNAMIC_STATE_SCISSOR
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
pipeline_ = PipelineBuilder()
|
|
|
|
|
.setShaders(vertStage, fragStage)
|
|
|
|
|
.setVertexInput({binding}, {posAttr})
|
|
|
|
|
.setTopology(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST)
|
|
|
|
|
.setRasterization(VK_POLYGON_MODE_FILL, VK_CULL_MODE_NONE)
|
|
|
|
|
.setDepthTest(true, false, VK_COMPARE_OP_LESS_OR_EQUAL)
|
|
|
|
|
.setColorBlendAttachment(PipelineBuilder::blendAlpha())
|
|
|
|
|
.setMultisample(vkCtx_->getMsaaSamples())
|
|
|
|
|
.setLayout(pipelineLayout_)
|
|
|
|
|
.setRenderPass(vkCtx_->getImGuiRenderPass())
|
|
|
|
|
.setDynamicStates(dynamicStates)
|
|
|
|
|
.build(device);
|
|
|
|
|
|
|
|
|
|
vertModule.destroy();
|
|
|
|
|
fragModule.destroy();
|
|
|
|
|
|
|
|
|
|
if (pipeline_ == VK_NULL_HANDLE) {
|
|
|
|
|
LOG_ERROR("Clouds::recreatePipelines: failed to create pipeline");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-21 19:41:21 -08:00
|
|
|
void Clouds::shutdown() {
|
|
|
|
|
destroyBuffers();
|
2026-02-02 12:24:50 -08:00
|
|
|
|
2026-02-21 19:41:21 -08:00
|
|
|
if (vkCtx_) {
|
|
|
|
|
VkDevice device = vkCtx_->getDevice();
|
|
|
|
|
if (pipeline_ != VK_NULL_HANDLE) {
|
|
|
|
|
vkDestroyPipeline(device, pipeline_, nullptr);
|
|
|
|
|
pipeline_ = VK_NULL_HANDLE;
|
2026-02-02 12:24:50 -08:00
|
|
|
}
|
2026-02-21 19:41:21 -08:00
|
|
|
if (pipelineLayout_ != VK_NULL_HANDLE) {
|
|
|
|
|
vkDestroyPipelineLayout(device, pipelineLayout_, nullptr);
|
|
|
|
|
pipelineLayout_ = VK_NULL_HANDLE;
|
2026-02-02 12:24:50 -08:00
|
|
|
}
|
2026-02-21 19:41:21 -08:00
|
|
|
}
|
2026-02-02 12:24:50 -08:00
|
|
|
|
2026-02-21 19:41:21 -08:00
|
|
|
vkCtx_ = nullptr;
|
|
|
|
|
}
|
2026-02-02 12:24:50 -08:00
|
|
|
|
2026-02-21 19:41:21 -08:00
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
|
// Render
|
|
|
|
|
// ---------------------------------------------------------------------------
|
2026-02-02 12:24:50 -08:00
|
|
|
|
2026-02-21 19:41:21 -08:00
|
|
|
void Clouds::render(VkCommandBuffer cmd, VkDescriptorSet perFrameSet, float timeOfDay) {
|
|
|
|
|
if (!enabled_ || pipeline_ == VK_NULL_HANDLE) {
|
|
|
|
|
return;
|
2026-02-02 12:24:50 -08:00
|
|
|
}
|
|
|
|
|
|
2026-02-21 19:41:21 -08:00
|
|
|
glm::vec3 color = getCloudColor(timeOfDay);
|
2026-02-02 12:24:50 -08:00
|
|
|
|
2026-02-21 19:41:21 -08:00
|
|
|
CloudPush push{};
|
|
|
|
|
push.cloudColor = glm::vec4(color, 1.0f);
|
|
|
|
|
push.density = density_;
|
|
|
|
|
push.windOffset = windOffset_;
|
2026-02-02 12:24:50 -08:00
|
|
|
|
2026-02-21 19:41:21 -08:00
|
|
|
vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_);
|
2026-02-02 12:24:50 -08:00
|
|
|
|
2026-02-21 19:41:21 -08:00
|
|
|
// Bind per-frame UBO (set 0 — vertex shader reads view/projection from here)
|
|
|
|
|
vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout_,
|
|
|
|
|
0, 1, &perFrameSet, 0, nullptr);
|
2026-02-02 12:24:50 -08:00
|
|
|
|
2026-02-21 19:41:21 -08:00
|
|
|
// Push cloud params to fragment shader
|
|
|
|
|
vkCmdPushConstants(cmd, pipelineLayout_,
|
|
|
|
|
VK_SHADER_STAGE_FRAGMENT_BIT,
|
|
|
|
|
0, sizeof(push), &push);
|
2026-02-02 12:24:50 -08:00
|
|
|
|
2026-02-21 19:41:21 -08:00
|
|
|
VkDeviceSize offset = 0;
|
|
|
|
|
vkCmdBindVertexBuffers(cmd, 0, 1, &vertexBuffer_, &offset);
|
|
|
|
|
vkCmdBindIndexBuffer(cmd, indexBuffer_, 0, VK_INDEX_TYPE_UINT32);
|
2026-02-02 12:24:50 -08:00
|
|
|
|
2026-02-21 19:41:21 -08:00
|
|
|
vkCmdDrawIndexed(cmd, static_cast<uint32_t>(indexCount_), 1, 0, 0, 0);
|
2026-02-02 12:24:50 -08:00
|
|
|
}
|
|
|
|
|
|
2026-02-21 19:41:21 -08:00
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
|
// Update
|
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
|
|
2026-02-02 12:24:50 -08:00
|
|
|
void Clouds::update(float deltaTime) {
|
2026-02-21 19:41:21 -08:00
|
|
|
if (!enabled_) {
|
2026-02-02 12:24:50 -08:00
|
|
|
return;
|
|
|
|
|
}
|
2026-02-21 19:41:21 -08:00
|
|
|
windOffset_ += deltaTime * windSpeed_ * 0.05f; // Slow drift
|
2026-02-02 12:24:50 -08:00
|
|
|
}
|
|
|
|
|
|
2026-02-21 19:41:21 -08:00
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
|
// Cloud colour (unchanged logic from GL version)
|
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
|
|
2026-02-02 12:24:50 -08:00
|
|
|
glm::vec3 Clouds::getCloudColor(float timeOfDay) const {
|
|
|
|
|
glm::vec3 dayColor(0.95f, 0.95f, 1.0f);
|
|
|
|
|
|
|
|
|
|
if (timeOfDay >= 5.0f && timeOfDay < 7.0f) {
|
2026-02-21 19:41:21 -08:00
|
|
|
// Dawn — orange tint fading to day
|
2026-02-02 12:24:50 -08:00
|
|
|
float t = (timeOfDay - 5.0f) / 2.0f;
|
2026-02-21 19:41:21 -08:00
|
|
|
return glm::mix(glm::vec3(1.0f, 0.7f, 0.5f), dayColor, t);
|
|
|
|
|
} else if (timeOfDay >= 17.0f && timeOfDay < 19.0f) {
|
|
|
|
|
// Dusk — day fading to orange/pink
|
2026-02-02 12:24:50 -08:00
|
|
|
float t = (timeOfDay - 17.0f) / 2.0f;
|
2026-02-21 19:41:21 -08:00
|
|
|
return glm::mix(dayColor, glm::vec3(1.0f, 0.6f, 0.4f), t);
|
|
|
|
|
} else if (timeOfDay >= 20.0f || timeOfDay < 5.0f) {
|
|
|
|
|
// Night — dark blue-grey
|
2026-02-02 12:24:50 -08:00
|
|
|
return glm::vec3(0.15f, 0.15f, 0.25f);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return dayColor;
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-21 19:41:21 -08:00
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
|
// Density setter
|
|
|
|
|
// ---------------------------------------------------------------------------
|
2026-02-02 12:24:50 -08:00
|
|
|
|
2026-02-21 19:41:21 -08:00
|
|
|
void Clouds::setDensity(float density) {
|
|
|
|
|
density_ = glm::clamp(density, 0.0f, 1.0f);
|
|
|
|
|
}
|
2026-02-02 12:24:50 -08:00
|
|
|
|
2026-02-21 19:41:21 -08:00
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
|
// Mesh generation — identical algorithm to GL version
|
|
|
|
|
// ---------------------------------------------------------------------------
|
2026-02-02 12:24:50 -08:00
|
|
|
|
2026-02-21 19:41:21 -08:00
|
|
|
void Clouds::generateMesh() {
|
|
|
|
|
vertices_.clear();
|
|
|
|
|
indices_.clear();
|
2026-02-02 12:24:50 -08:00
|
|
|
|
2026-02-21 21:57:16 -08:00
|
|
|
// Upper hemisphere — Z-up world: altitude goes into Z, horizontal spread in X/Y
|
2026-02-21 19:41:21 -08:00
|
|
|
for (int ring = 0; ring <= RINGS; ++ring) {
|
|
|
|
|
float phi = (ring / static_cast<float>(RINGS)) * (static_cast<float>(M_PI) * 0.5f);
|
2026-02-21 21:57:16 -08:00
|
|
|
float altZ = RADIUS * std::cos(phi); // altitude → world Z (up)
|
2026-02-21 19:41:21 -08:00
|
|
|
float ringRadius = RADIUS * std::sin(phi);
|
|
|
|
|
|
|
|
|
|
for (int seg = 0; seg <= SEGMENTS; ++seg) {
|
|
|
|
|
float theta = (seg / static_cast<float>(SEGMENTS)) * (2.0f * static_cast<float>(M_PI));
|
|
|
|
|
float x = ringRadius * std::cos(theta);
|
2026-02-21 21:57:16 -08:00
|
|
|
float y = ringRadius * std::sin(theta);
|
|
|
|
|
vertices_.push_back(glm::vec3(x, y, altZ));
|
2026-02-21 19:41:21 -08:00
|
|
|
}
|
|
|
|
|
}
|
2026-02-02 12:24:50 -08:00
|
|
|
|
2026-02-21 19:41:21 -08:00
|
|
|
for (int ring = 0; ring < RINGS; ++ring) {
|
|
|
|
|
for (int seg = 0; seg < SEGMENTS; ++seg) {
|
|
|
|
|
uint32_t current = static_cast<uint32_t>(ring * (SEGMENTS + 1) + seg);
|
|
|
|
|
uint32_t next = current + static_cast<uint32_t>(SEGMENTS + 1);
|
2026-02-02 12:24:50 -08:00
|
|
|
|
2026-02-21 19:41:21 -08:00
|
|
|
indices_.push_back(current);
|
|
|
|
|
indices_.push_back(next);
|
|
|
|
|
indices_.push_back(current + 1);
|
2026-02-02 12:24:50 -08:00
|
|
|
|
2026-02-21 19:41:21 -08:00
|
|
|
indices_.push_back(current + 1);
|
|
|
|
|
indices_.push_back(next);
|
|
|
|
|
indices_.push_back(next + 1);
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-02-02 12:24:50 -08:00
|
|
|
|
2026-02-21 19:41:21 -08:00
|
|
|
indexCount_ = static_cast<int>(indices_.size());
|
2026-02-02 12:24:50 -08:00
|
|
|
}
|
|
|
|
|
|
2026-02-21 19:41:21 -08:00
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
|
// GPU buffer management
|
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
void Clouds::createBuffers() {
|
|
|
|
|
AllocatedBuffer vbuf = uploadBuffer(*vkCtx_,
|
|
|
|
|
vertices_.data(),
|
|
|
|
|
vertices_.size() * sizeof(glm::vec3),
|
|
|
|
|
VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
|
|
|
|
|
vertexBuffer_ = vbuf.buffer;
|
|
|
|
|
vertexAlloc_ = vbuf.allocation;
|
|
|
|
|
|
|
|
|
|
AllocatedBuffer ibuf = uploadBuffer(*vkCtx_,
|
|
|
|
|
indices_.data(),
|
|
|
|
|
indices_.size() * sizeof(uint32_t),
|
|
|
|
|
VK_BUFFER_USAGE_INDEX_BUFFER_BIT);
|
|
|
|
|
indexBuffer_ = ibuf.buffer;
|
|
|
|
|
indexAlloc_ = ibuf.allocation;
|
|
|
|
|
|
|
|
|
|
// CPU data no longer needed
|
|
|
|
|
vertices_.clear();
|
|
|
|
|
vertices_.shrink_to_fit();
|
|
|
|
|
indices_.clear();
|
|
|
|
|
indices_.shrink_to_fit();
|
2026-02-02 12:24:50 -08:00
|
|
|
}
|
|
|
|
|
|
2026-02-21 19:41:21 -08:00
|
|
|
void Clouds::destroyBuffers() {
|
|
|
|
|
if (!vkCtx_) return;
|
|
|
|
|
|
|
|
|
|
VmaAllocator allocator = vkCtx_->getAllocator();
|
|
|
|
|
|
|
|
|
|
if (vertexBuffer_ != VK_NULL_HANDLE) {
|
|
|
|
|
vmaDestroyBuffer(allocator, vertexBuffer_, vertexAlloc_);
|
|
|
|
|
vertexBuffer_ = VK_NULL_HANDLE;
|
|
|
|
|
vertexAlloc_ = VK_NULL_HANDLE;
|
2026-02-02 12:24:50 -08:00
|
|
|
}
|
2026-02-21 19:41:21 -08:00
|
|
|
if (indexBuffer_ != VK_NULL_HANDLE) {
|
|
|
|
|
vmaDestroyBuffer(allocator, indexBuffer_, indexAlloc_);
|
|
|
|
|
indexBuffer_ = VK_NULL_HANDLE;
|
|
|
|
|
indexAlloc_ = VK_NULL_HANDLE;
|
2026-02-02 12:24:50 -08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} // namespace rendering
|
|
|
|
|
} // namespace wowee
|