60 assert(ctx.
drawGrid &&
"DrawContext::drawGrid must not be null");
61 assert(ctx.
bgColor &&
"DrawContext::bgColor must not be null");
62 assert(ctx.
camera &&
"DrawContext::camera must not be null");
63 assert(ctx.
renderer &&
"DrawContext::renderer must not be null");
68 if (ImGui::CollapsingHeader(
"Background", ImGuiTreeNodeFlags_DefaultOpen))
70 ImGui::Checkbox(
"Draw Grid", ctx.
drawGrid);
71 ImGui::Checkbox(
"Checkerboard Background", &rs.drawCheckerBg);
72 if (ImGui::Checkbox(
"Gradient Background", &rs.drawGradientBg))
74 if (rs.drawGradientBg)
75 rs.drawCheckerBg =
false;
77 if (rs.drawGradientBg)
79 ImGui::ColorEdit3(
"Gradient Top", &rs.gradientTop.x);
80 ImGui::ColorEdit3(
"Gradient Bottom", &rs.gradientBottom.x);
82 ImGui::ColorEdit3(
"Background Color", &ctx.
bgColor->x);
85 ImGui::Text(
"Palette:");
86 for (
int i = 0; i < g_bgPaletteCount; ++i)
89 if (ImGui::ColorButton(
"##pal",
90 ImVec4(g_bgPalette[i].x, g_bgPalette[i].y, g_bgPalette[i].z, 1.0f),
91 ImGuiColorEditFlags_NoTooltip, ImVec2(20, 20)))
94 if (i < g_bgPaletteCount - 1) ImGui::SameLine();
98 ImGui::Text(
"Camera Presets:");
99 if (ImGui::Button(
"Front"))
102 if (ImGui::Button(
"Side"))
105 if (ImGui::Button(
"Back"))
108 if (ImGui::Button(
"Iso"))
110 if (ImGui::Button(
"Top"))
113 if (ImGui::Button(
"Bottom"))
116 if (ImGui::Button(
"Reset Camera"))
121 if (ImGui::CollapsingHeader(
"Lighting", ImGuiTreeNodeFlags_DefaultOpen))
123 ImGui::Checkbox(
"Enable Lighting", &rs.light.enabled);
125 if (!rs.light.enabled)
126 ImGui::BeginDisabled();
128 static const char* lightTypeNames[] = {
"Directional",
"Point",
"Spot",
"Ambient Only" };
129 ImGui::Combo(
"##LightType",
130 reinterpret_cast<int*
>(&rs.light.type),
131 lightTypeNames, IM_ARRAYSIZE(lightTypeNames));
135 ImGui::DragFloat3(
"Dir XYZ", rs.light.direction, 0.01f, -5.0f, 5.0f,
"%.2f");
139 ImGui::DragFloat3(
"Pos XYZ", rs.light.position, 0.1f, -50.0f, 50.0f,
"%.1f");
143 ImGui::SliderFloat(
"Cutoff Angle", &rs.light.spotCutoff,
144 1.0f, 90.0f,
"%.1f deg");
145 ImGui::SliderFloat(
"Exponent", &rs.light.spotExponent,
146 0.0f, 128.0f,
"%.1f");
149 ImGui::ColorEdit3(
"Diffuse", rs.light.diffuse, ImGuiColorEditFlags_Float);
150 ImGui::ColorEdit3(
"Ambient", rs.light.ambient, ImGuiColorEditFlags_Float);
151 ImGui::ColorEdit3(
"Specular", rs.light.specular, ImGuiColorEditFlags_Float);
152 ImGui::SliderFloat(
"Intensity", &rs.light.intensity, 0.0f, 3.0f,
"%.2f");
154 if (!rs.light.enabled)
155 ImGui::EndDisabled();
158 if (ImGui::Button(
"Default##light", ImVec2(-1, 0)))
160 if (ImGui::Button(
"Bright Daylight", ImVec2(-1, 0)))
163 l.
direction[0] = -0.5f; l.direction[1] = 1.0f;
164 l.direction[2] = -0.3f; l.direction[3] = 0.0f;
165 l.diffuse[0] = 1.0f; l.diffuse[1] = 0.98f; l.diffuse[2] = 0.92f;
166 l.ambient[0] = 0.45f; l.ambient[1] = 0.45f; l.ambient[2] = 0.50f;
167 l.specular[0] = 0.3f; l.specular[1] = 0.3f; l.specular[2] = 0.3f;
171 if (ImGui::Button(
"Warm Sunset", ImVec2(-1, 0)))
174 l.direction[0] = -1.0f; l.direction[1] = 0.3f;
175 l.direction[2] = -0.5f; l.direction[3] = 0.0f;
176 l.diffuse[0] = 1.0f; l.diffuse[1] = 0.65f; l.diffuse[2] = 0.3f;
177 l.ambient[0] = 0.25f; l.ambient[1] = 0.2f; l.ambient[2] = 0.25f;
178 l.specular[0] = 0.1f; l.specular[1] = 0.05f; l.specular[2] = 0.0f;
182 if (ImGui::Button(
"Cool Moonlight", ImVec2(-1, 0)))
185 l.direction[0] = 0.3f; l.direction[1] = 1.0f;
186 l.direction[2] = -0.7f; l.direction[3] = 0.0f;
187 l.diffuse[0] = 0.6f; l.diffuse[1] = 0.65f; l.diffuse[2] = 0.8f;
188 l.ambient[0] = 0.15f; l.ambient[1] = 0.15f; l.ambient[2] = 0.2f;
189 l.specular[0] = 0.0f; l.specular[1] = 0.0f; l.specular[2] = 0.0f;
193 if (ImGui::Button(
"Flat (No Shading)", ImVec2(-1, 0)))
196 l.direction[0] = 0.0f; l.direction[1] = 0.0f;
197 l.direction[2] = -1.0f; l.direction[3] = 0.0f;
198 l.diffuse[0] = 1.0f; l.diffuse[1] = 1.0f; l.diffuse[2] = 1.0f;
199 l.ambient[0] = 1.0f; l.ambient[1] = 1.0f; l.ambient[2] = 1.0f;
200 l.specular[0] = 0.0f; l.specular[1] = 0.0f; l.specular[2] = 0.0f;
207 if (ImGui::CollapsingHeader(
"Model", ImGuiTreeNodeFlags_DefaultOpen))
212 ImGui::Text(
"Name: %s", mModel->
name().c_str());
218 ImGui::Text(
"V:%u B:%u T:%u A:%zu G:%zu",
223 ImGui::Checkbox(
"Render", &mModel->
showModel);
228 ImGui::Checkbox(
"Bones", &mModel->
showBones);
229 ImGui::Checkbox(
"Bounds", &mModel->
showBounds);
233 int alphaPercent =
static_cast<int>(mModel->
alpha_ * 100.0f);
234 if (ImGui::SliderInt(
"Alpha", &alphaPercent, 0, 100))
235 mModel->
alpha_ = alphaPercent / 100.0f;
236 ImGui::SliderFloat(
"Scale", &mModel->
scale_, 0.1f, 3.0f,
"%.2f");
238 ImGui::DragFloat3(
"Position", &mModel->
pos_.x, 0.1f);
239 ImGui::DragFloat3(
"Rotation", &mModel->
rot_.x, 1.0f);
245 ImGui::TextDisabled(
"Geosets (click to toggle)");
248 if (ImGui::TreeNode(group.name.c_str()))
250 for (
auto& ge : group.geosets)
253 ImVec4 color = displayed
254 ? ImVec4(0.3f, 1.0f, 0.3f, 1.0f)
255 : ImVec4(0.5f, 0.5f, 0.5f, 1.0f);
256 ImGui::PushStyleColor(ImGuiCol_Text, color);
257 ImGuiTreeNodeFlags flags =
258 ImGuiTreeNodeFlags_Leaf |
259 ImGuiTreeNodeFlags_NoTreePushOnOpen |
260 ImGuiTreeNodeFlags_SpanAvailWidth;
261 ImGui::TreeNodeEx(ge.label.c_str(), flags);
262 if (ImGui::IsItemClicked())
264 ImGui::PopStyleColor();
275 bool anyPCR = pcr.
hasSet[0] || pcr.hasSet[1] || pcr.hasSet[2];
279 if (ImGui::Checkbox(
"Replace Particle Colors", &pcr.enabled))
282 applyParticleColors(mModel, pcr);
291 static const char* setNames[] = {
"ID 11",
"ID 12",
"ID 13"};
292 static const char* phaseNames[] = {
"Start",
"Mid",
"End"};
293 for (
int s = 0; s < 3; ++s)
295 if (!pcr.hasSet[s])
continue;
296 ImGui::Text(
"%s", setNames[s]);
297 for (
int p = 0; p < 3; ++p)
299 std::string label = std::format(
"{} {}##pcr{}{}",
300 setNames[s], phaseNames[p], s, p);
301 if (ImGui::ColorEdit3(label.c_str(), pcr.colors[s][p]))
304 applyParticleColors(mModel, pcr);
313 ImGui::TextDisabled(
"No model loaded.");