c7821c4c99
- 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>
92 lines
3.4 KiB
C++
92 lines
3.4 KiB
C++
#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
|