feat(shaders_lab): uniform annotations → auto-generated ImGui controls
- cpp/functions/gfx/uniform_parser: regex-based parser of @slider/@color/@toggle/@xy annotations (+ inline tests) - cpp/functions/gfx/uniform_panel: ImGui widgets + value store + glUniform* apply - shader_canvas: optional uniforms callback invoked per-frame - gl_loader: +glUniform1i/3f/4f - seed plasma: demo uniforms u_speed + u_color - rebuild Windows .exe Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,91 @@
|
||||
#include "gfx/uniform_panel.h"
|
||||
#include "gfx/gl_loader.h"
|
||||
#include "imgui.h"
|
||||
|
||||
namespace fn::gfx {
|
||||
|
||||
void uniforms_sync(UniformStore& store, const std::vector<UniformDescriptor>& descs) {
|
||||
// Remove keys no longer present
|
||||
for (auto it = store.values.begin(); it != store.values.end(); ) {
|
||||
bool found = false;
|
||||
for (auto& d : descs) if (d.name == it->first) { found = true; break; }
|
||||
it = found ? std::next(it) : store.values.erase(it);
|
||||
}
|
||||
// Add new entries with defaults
|
||||
for (auto& d : descs) {
|
||||
if (store.values.count(d.name)) continue;
|
||||
std::array<float, 4> arr = {
|
||||
d.defaults[0], d.defaults[1], d.defaults[2], d.defaults[3]
|
||||
};
|
||||
store.values[d.name] = arr;
|
||||
}
|
||||
}
|
||||
|
||||
void uniforms_panel(UniformStore& store, const std::vector<UniformDescriptor>& descs) {
|
||||
if (descs.empty()) {
|
||||
ImGui::TextDisabled("Declare uniforms with @slider ... annotations.");
|
||||
return;
|
||||
}
|
||||
|
||||
for (auto& d : descs) {
|
||||
auto it = store.values.find(d.name);
|
||||
if (it == store.values.end()) continue;
|
||||
float* v = it->second.data();
|
||||
|
||||
switch (d.widget) {
|
||||
case WidgetKind::Slider: {
|
||||
if (d.glsl_type == GLSLType::Int) {
|
||||
int tmp = static_cast<int>(v[0]);
|
||||
if (ImGui::SliderInt(d.name.c_str(), &tmp,
|
||||
static_cast<int>(d.min[0]),
|
||||
static_cast<int>(d.max[0]))) {
|
||||
v[0] = static_cast<float>(tmp);
|
||||
}
|
||||
} else {
|
||||
ImGuiSliderFlags flags = d.log_scale ? ImGuiSliderFlags_Logarithmic : 0;
|
||||
ImGui::SliderFloat(d.name.c_str(), &v[0], d.min[0], d.max[0], "%.3f", flags);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case WidgetKind::Color: {
|
||||
if (d.glsl_type == GLSLType::Vec4)
|
||||
ImGui::ColorEdit4(d.name.c_str(), v);
|
||||
else
|
||||
ImGui::ColorEdit3(d.name.c_str(), v);
|
||||
break;
|
||||
}
|
||||
case WidgetKind::Toggle: {
|
||||
bool tmp = v[0] != 0.0f;
|
||||
if (ImGui::Checkbox(d.name.c_str(), &tmp))
|
||||
v[0] = tmp ? 1.0f : 0.0f;
|
||||
break;
|
||||
}
|
||||
case WidgetKind::XY: {
|
||||
ImGui::SliderFloat2(d.name.c_str(), v, d.min[0], d.max[0]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void uniforms_apply(const UniformStore& store, const std::vector<UniformDescriptor>& descs, unsigned int program) {
|
||||
for (auto& d : descs) {
|
||||
auto it = store.values.find(d.name);
|
||||
if (it == store.values.end()) continue;
|
||||
const float* v = it->second.data();
|
||||
|
||||
GLint loc = glGetUniformLocation(program, d.name.c_str());
|
||||
if (loc < 0) continue;
|
||||
|
||||
switch (d.glsl_type) {
|
||||
case GLSLType::Float: glUniform1f(loc, v[0]); break;
|
||||
case GLSLType::Int: glUniform1i(loc, static_cast<GLint>(v[0])); break;
|
||||
case GLSLType::Bool: glUniform1i(loc, v[0] != 0.0f ? 1 : 0); break;
|
||||
case GLSLType::Vec2: glUniform2f(loc, v[0], v[1]); break;
|
||||
case GLSLType::Vec3: glUniform3f(loc, v[0], v[1], v[2]); break;
|
||||
case GLSLType::Vec4: glUniform4f(loc, v[0], v[1], v[2], v[3]); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace fn::gfx
|
||||
Reference in New Issue
Block a user