16 assert(ctx.
selectedAnimCombo &&
"DrawContext::selectedAnimCombo must not be null");
17 assert(ctx.
animSpeed &&
"DrawContext::animSpeed must not be null");
18 assert(ctx.
loopCount &&
"DrawContext::loopCount must not be null");
19 assert(ctx.
lockAnims &&
"DrawContext::lockAnims must not be null");
21 assert(ctx.
selectedMouthAnim &&
"DrawContext::selectedMouthAnim must not be null");
22 assert(ctx.
mouthSpeed &&
"DrawContext::mouthSpeed must not be null");
27 ImGui::TextDisabled(
"No model loaded.");
41 ImGui::SeparatorText(
"Animation");
42 const char* previewAnim = (selectedAnimCombo >= 0 && selectedAnimCombo < static_cast<int>(animEntries.size()))
43 ? animEntries[selectedAnimCombo].label.c_str() :
"<none>";
44 if (ImGui::BeginCombo(
"##AnimCombo", previewAnim))
46 for (
int i = 0; i < static_cast<int>(animEntries.size()); ++i)
48 bool selected = (i == selectedAnimCombo);
49 if (ImGui::Selectable(animEntries[i].label.c_str(), selected))
51 selectedAnimCombo = i;
52 int idx = animEntries[i].animIndex;
57 if (selected) ImGui::SetItemDefaultFocus();
63 if (ImGui::Button(
"Play"))
66 if (ImGui::Button(
"Pause"))
69 if (ImGui::Button(
"Stop"))
72 if (ImGui::Button(
"<<"))
75 if (ImGui::Button(
">>"))
79 ImGui::TextColored(ImVec4(1.0f, 1.0f, 0.3f, 1.0f),
"Paused");
82 if (ImGui::SliderFloat(
"Speed", &animSpeed, 0.0f, 4.0f,
"%.2f"))
90 if (ImGui::SliderInt(
"Frame", &curFrame, 0, frameCount))
95 ImGui::Text(
"Frame: %d", curFrame);
99 if (ImGui::SliderInt(
"Loops", &loopCount, 0, 9))
102 int idx = animEntries[selectedAnimCombo].animIndex;
106 for (
int i = 1; i < 4; ++i)
108 if (nextAnim >= 0 && nextAnim <
static_cast<int>(aModel->
anims.size()))
110 nextAnim = aModel->
anims[nextAnim].NextAnimation;
112 aModel->
animManager->
AddAnim(
static_cast<unsigned int>(nextAnim),
static_cast<short>(loopCount));
121 ImGui::SetItemTooltip(
"0 = infinite loop");
124 ImGui::SeparatorText(
"Body Animation");
125 if (ImGui::Checkbox(
"Lock animations", &lockAnims))
131 selectedSecondaryAnim = -1;
132 selectedMouthAnim = -1;
135 ImGui::SetItemTooltip(
"Uncheck to enable independent upper body and mouth animations");
141 const char* previewSec = (selectedSecondaryAnim >= 0 && selectedSecondaryAnim < static_cast<int>(animEntries.size()))
142 ? animEntries[selectedSecondaryAnim].label.c_str() :
"<none>";
143 if (ImGui::BeginCombo(
"Upper Body##SecAnim", previewSec))
145 if (ImGui::Selectable(
"<none>", selectedSecondaryAnim < 0))
147 selectedSecondaryAnim = -1;
150 for (
int i = 0; i < static_cast<int>(animEntries.size()); ++i)
152 bool selected = (i == selectedSecondaryAnim);
153 if (ImGui::Selectable(animEntries[i].label.c_str(), selected))
155 selectedSecondaryAnim = i;
158 if (selected) ImGui::SetItemDefaultFocus();
166 const char* previewMouth = (selectedMouthAnim >= 0 && selectedMouthAnim < static_cast<int>(animEntries.size()))
167 ? animEntries[selectedMouthAnim].label.c_str() :
"<none>";
168 if (ImGui::BeginCombo(
"Mouth##MouthAnim", previewMouth))
170 if (ImGui::Selectable(
"<none>", selectedMouthAnim < 0))
172 selectedMouthAnim = -1;
175 for (
int i = 0; i < static_cast<int>(animEntries.size()); ++i)
177 bool selected = (i == selectedMouthAnim);
178 if (ImGui::Selectable(animEntries[i].label.c_str(), selected))
180 selectedMouthAnim = i;
183 if (selected) ImGui::SetItemDefaultFocus();
190 if (ImGui::SliderFloat(
"Mouth Speed", &mouthSpeed, 0.0f, 4.0f,
"%.2f"))
201 ImGui::SeparatorText(
"Skin / Texture");
202 const char* previewSkin = (selectedSkin >= 0 && selectedSkin < static_cast<int>(skinEntries.size()))
203 ? skinEntries[selectedSkin].label.c_str() :
"<none>";
204 if (ImGui::BeginCombo(
"##SkinCombo", previewSkin))
206 for (
int i = 0; i < static_cast<int>(skinEntries.size()); ++i)
208 bool selected = (i == selectedSkin);
209 if (ImGui::Selectable(skinEntries[i].label.c_str(), selected))
215 if (selected) ImGui::SetItemDefaultFocus();
222 for (
const auto& se : skinEntries)
223 if (se.count > maxSlots) maxSlots = se.count;
224 if (maxSlots > 3) maxSlots = 3;
228 const char* slotLabels[3] = {
"Texture 1",
"Texture 2",
"Texture 3" };
229 for (
size_t slot = 0; slot < maxSlots; ++slot)
231 const char* preview = (ctx.
blpSkin[slot] >= 0 && ctx.
blpSkin[slot] <
static_cast<int>(skinEntries.size()))
232 ? skinEntries[ctx.
blpSkin[slot]].label.c_str() :
"(grouped)";
234 snprintf(comboId,
sizeof(comboId),
"##BLPSlot%zu", slot);
235 if (ImGui::BeginCombo(slotLabels[slot], preview))
237 for (
int i = 0; i < static_cast<int>(skinEntries.size()); ++i)
239 if (!skinEntries[i].tex[0])
continue;
240 bool selected = (i == ctx.
blpSkin[slot]);
241 if (ImGui::Selectable(skinEntries[i].label.c_str(), selected))
245 skinEntries[i].base +
static_cast<int>(slot));
247 if (selected) ImGui::SetItemDefaultFocus();