- Fix JsonDataNode::getChildReadOnly() to handle JSON array access by numeric index - Fix test_ui_showcase to use JSON array for children (matching test_single_button pattern) - Add visual test files: test_single_button, test_ui_showcase, test_sprite_debug - Clean up debug logging from SpritePass, SceneCollector, UIButton, BgfxDevice The root cause was that UITree couldn't access array children in JSON layouts. UIButton hover/click now works correctly in both test files. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
154 lines
4.9 KiB
C++
154 lines
4.9 KiB
C++
#include "ShaderManager.h"
|
|
#include "../RHI/RHIDevice.h"
|
|
|
|
// Embedded shader bytecode
|
|
#include "vs_color.bin.h"
|
|
#include "fs_color.bin.h"
|
|
#include "vs_sprite.bin.h"
|
|
#include "fs_sprite.bin.h"
|
|
|
|
namespace grove {
|
|
|
|
ShaderManager::~ShaderManager() {
|
|
// Note: shutdown() must be called explicitly with device before destruction
|
|
// We can't call it here because we don't have the device reference
|
|
}
|
|
|
|
void ShaderManager::init(rhi::IRHIDevice& device, const std::string& rendererName) {
|
|
if (m_initialized) {
|
|
return;
|
|
}
|
|
|
|
loadBuiltinShaders(device, rendererName);
|
|
m_initialized = true;
|
|
}
|
|
|
|
void ShaderManager::shutdown(rhi::IRHIDevice& device) {
|
|
for (auto& [name, handle] : m_programs) {
|
|
if (handle.isValid()) {
|
|
device.destroy(handle);
|
|
}
|
|
}
|
|
m_programs.clear();
|
|
m_initialized = false;
|
|
}
|
|
|
|
rhi::ShaderHandle ShaderManager::getProgram(const std::string& name) const {
|
|
auto it = m_programs.find(name);
|
|
if (it != m_programs.end()) {
|
|
return it->second;
|
|
}
|
|
return rhi::ShaderHandle{}; // Invalid handle
|
|
}
|
|
|
|
bool ShaderManager::hasProgram(const std::string& name) const {
|
|
return m_programs.find(name) != m_programs.end();
|
|
}
|
|
|
|
void ShaderManager::loadBuiltinShaders(rhi::IRHIDevice& device, const std::string& rendererName) {
|
|
// Select shader bytecode based on renderer
|
|
const uint8_t* vsData = nullptr;
|
|
uint32_t vsSize = 0;
|
|
const uint8_t* fsData = nullptr;
|
|
uint32_t fsSize = 0;
|
|
|
|
if (rendererName == "OpenGL") {
|
|
vsData = vs_drawstress_glsl;
|
|
vsSize = sizeof(vs_drawstress_glsl);
|
|
fsData = fs_drawstress_glsl;
|
|
fsSize = sizeof(fs_drawstress_glsl);
|
|
} else if (rendererName == "OpenGL ES") {
|
|
vsData = vs_drawstress_essl;
|
|
vsSize = sizeof(vs_drawstress_essl);
|
|
fsData = fs_drawstress_essl;
|
|
fsSize = sizeof(fs_drawstress_essl);
|
|
} else if (rendererName == "Vulkan") {
|
|
vsData = vs_drawstress_spv;
|
|
vsSize = sizeof(vs_drawstress_spv);
|
|
fsData = fs_drawstress_spv;
|
|
fsSize = sizeof(fs_drawstress_spv);
|
|
} else if (rendererName == "Direct3D 11" || rendererName == "Direct3D 12") {
|
|
vsData = vs_drawstress_dx11;
|
|
vsSize = sizeof(vs_drawstress_dx11);
|
|
fsData = fs_drawstress_dx11;
|
|
fsSize = sizeof(fs_drawstress_dx11);
|
|
} else if (rendererName == "Metal") {
|
|
vsData = vs_drawstress_mtl;
|
|
vsSize = sizeof(vs_drawstress_mtl);
|
|
fsData = fs_drawstress_mtl;
|
|
fsSize = sizeof(fs_drawstress_mtl);
|
|
} else {
|
|
// Fallback to Vulkan (most common in WSL2)
|
|
vsData = vs_drawstress_spv;
|
|
vsSize = sizeof(vs_drawstress_spv);
|
|
fsData = fs_drawstress_spv;
|
|
fsSize = sizeof(fs_drawstress_spv);
|
|
}
|
|
|
|
// Create color shader via RHI
|
|
rhi::ShaderDesc shaderDesc;
|
|
shaderDesc.vsData = vsData;
|
|
shaderDesc.vsSize = vsSize;
|
|
shaderDesc.fsData = fsData;
|
|
shaderDesc.fsSize = fsSize;
|
|
|
|
rhi::ShaderHandle colorProgram = device.createShader(shaderDesc);
|
|
|
|
if (colorProgram.isValid()) {
|
|
m_programs["color"] = colorProgram;
|
|
m_programs["debug"] = colorProgram;
|
|
}
|
|
|
|
// Load sprite instancing shader
|
|
loadSpriteShader(device, rendererName);
|
|
}
|
|
|
|
void ShaderManager::loadSpriteShader(rhi::IRHIDevice& device, const std::string& rendererName) {
|
|
const uint8_t* vsData = nullptr;
|
|
uint32_t vsSize = 0;
|
|
const uint8_t* fsData = nullptr;
|
|
uint32_t fsSize = 0;
|
|
|
|
if (rendererName == "OpenGL") {
|
|
vsData = vs_sprite_glsl;
|
|
vsSize = sizeof(vs_sprite_glsl);
|
|
fsData = fs_sprite_glsl;
|
|
fsSize = sizeof(fs_sprite_glsl);
|
|
} else if (rendererName == "Vulkan") {
|
|
vsData = vs_sprite_spv;
|
|
vsSize = sizeof(vs_sprite_spv);
|
|
fsData = fs_sprite_spv;
|
|
fsSize = sizeof(fs_sprite_spv);
|
|
} else if (rendererName == "Metal") {
|
|
vsData = vs_sprite_mtl;
|
|
vsSize = sizeof(vs_sprite_mtl);
|
|
fsData = fs_sprite_mtl;
|
|
fsSize = sizeof(fs_sprite_mtl);
|
|
} else if (rendererName == "Direct3D 11" || rendererName == "Direct3D 12") {
|
|
vsData = vs_sprite_dx11;
|
|
vsSize = sizeof(vs_sprite_dx11);
|
|
fsData = fs_sprite_dx11;
|
|
fsSize = sizeof(fs_sprite_dx11);
|
|
} else {
|
|
// Fallback to Vulkan (most common in WSL2)
|
|
vsData = vs_sprite_spv;
|
|
vsSize = sizeof(vs_sprite_spv);
|
|
fsData = fs_sprite_spv;
|
|
fsSize = sizeof(fs_sprite_spv);
|
|
}
|
|
|
|
rhi::ShaderDesc shaderDesc;
|
|
shaderDesc.vsData = vsData;
|
|
shaderDesc.vsSize = vsSize;
|
|
shaderDesc.fsData = fsData;
|
|
shaderDesc.fsSize = fsSize;
|
|
|
|
rhi::ShaderHandle spriteProgram = device.createShader(shaderDesc);
|
|
|
|
if (spriteProgram.isValid()) {
|
|
m_programs["sprite"] = spriteProgram;
|
|
}
|
|
}
|
|
|
|
} // namespace grove
|