1#include "utility/aglParameterList.h"
2#include <basis/seadRawPrint.h>
3#include <prim/seadFormatPrint.h>
4#include <prim/seadSafeString.h>
5#include "utility/aglParameter.h"
6#include "utility/aglParameterObj.h"
7#include "utility/aglParameterStringMgr.h"
8
9namespace agl::utl {
10
11IParameterList::IParameterList() {
12 setParameterListName_(sead::SafeString::cEmptyString);
13}
14
15void IParameterList::setParameterListName_(const sead::SafeString& name) {
16#ifdef SEAD_DEBUG
17 if (ParameterStringMgr::instance())
18 mName = ParameterStringMgr::instance()->appendString(name);
19 else
20 mName = nullptr;
21#endif
22
23 mNameHash = ParameterBase::calcHash(key: name);
24}
25
26void IParameterList::addList(IParameterList* child, const sead::SafeString& name) {
27 SEAD_ASSERT(child != nullptr);
28 child->setParameterListName_(name);
29
30 (!mpChildListTail ? mpChildListHead : mpChildListTail->mNext) = child;
31 mpChildListTail = child;
32 child->mParent = this;
33}
34
35void IParameterList::addObj(IParameterObj* child, const sead::SafeString& name) {
36 SEAD_ASSERT(child != nullptr);
37
38#ifdef SEAD_DEBUG
39 if (ParameterStringMgr::instance())
40 child->mName = ParameterStringMgr::instance()->appendString(name);
41#endif
42 child->mNameHash = ParameterBase::calcHash(key: name);
43
44 (!mpChildObjTail ? mpChildObjHead : mpChildObjTail->mNext) = child;
45 mpChildObjTail = child;
46}
47
48void IParameterList::clearList() {
49 for (auto* i = mpChildListHead; i;) {
50 auto* next = i->mNext;
51 i->mNext = nullptr;
52 i = next;
53 }
54 mpChildListHead = nullptr;
55 mpChildListTail = nullptr;
56}
57
58void IParameterList::clearObj() {
59 for (auto* i = mpChildObjHead; i;) {
60 auto* next = i->mNext;
61 i->mNext = nullptr;
62 i = next;
63 }
64 mpChildObjHead = nullptr;
65 mpChildObjTail = nullptr;
66}
67
68void IParameterList::removeList(IParameterList* child) {
69 SEAD_ASSERT(child != nullptr);
70 auto* i = mpChildListHead;
71 if (!i)
72 return;
73
74 IParameterList* prev = nullptr;
75 while (true) {
76 if (i == child)
77 break;
78 prev = i;
79 i = i->mNext;
80 if (!i)
81 return;
82 }
83
84 (prev ? prev->mNext : mpChildListHead) = child->mNext;
85 if (!child->mNext) {
86 SEAD_ASSERT(mpChildListTail == child);
87 mpChildListTail = prev;
88 }
89 child->mNext = nullptr;
90}
91
92void IParameterList::removeObj(IParameterObj* child) {
93 SEAD_ASSERT(child != nullptr);
94 auto* i = mpChildObjHead;
95 if (!i)
96 return;
97
98 IParameterObj* prev = nullptr;
99 while (true) {
100 if (i == child)
101 break;
102 prev = i;
103 i = i->mNext;
104 if (!i)
105 return;
106 }
107
108 (prev ? prev->mNext : mpChildObjHead) = child->mNext;
109 if (!child->mNext) {
110 SEAD_ASSERT(mpChildObjTail == child);
111 mpChildObjTail = prev;
112 }
113 child->mNext = nullptr;
114}
115
116void IParameterList::applyResParameterList(ResParameterList list) {
117 return applyResParameterList_(interpolate: false, l1: list, l2: {}, t: 0.0);
118}
119
120void IParameterList::applyResParameterList(ResParameterList list1, ResParameterList list2, f32 t) {
121 if (list1.ptr() && t <= 0.0)
122 return applyResParameterList_(interpolate: false, l1: list1, l2: {}, t: 0.0);
123 if (list2.ptr() && t >= 1.0)
124 return applyResParameterList_(interpolate: false, l1: list2, l2: {}, t: 0.0);
125 return applyResParameterList_(interpolate: true, l1: list1, l2: list2, t);
126}
127
128bool IParameterList::isComplete(ResParameterList res, bool) const {
129 if (!res.ptr())
130 return false;
131
132 s32 obj_count = 0;
133 for (auto* i = mpChildObjHead; i; i = i->mNext) {
134 if (res.searchObjIndex(obj_hash: i->mNameHash) == -1)
135 return false;
136 ++obj_count;
137 }
138
139 s32 list_count = 0;
140 for (auto* i = mpChildListHead; i; i = i->mNext) {
141 if (res.searchListIndex(list_hash: i->mNameHash) == -1)
142 return false;
143 ++list_count;
144 }
145
146 return obj_count == res.getResParameterObjNum() && list_count == res.getResParameterListNum();
147}
148
149sead::SafeString IParameterList::getName() const {
150#ifdef SEAD_DEBUG
151 return mName;
152#else
153 return sead::SafeString::cEmptyString;
154#endif
155}
156
157const char* IParameterList::getTagName() {
158 return "param_list";
159}
160
161bool IParameterList::verify() const {
162 bool ok = true;
163 ok &= verifyList();
164 ok &= verifyObj();
165 for (auto* i = mpChildListHead; i; i = i->mNext)
166 ok &= i->verify();
167 for (auto* i = mpChildObjHead; i; i = i->mNext)
168 ok &= i->verify();
169 return ok;
170}
171
172bool IParameterList::verifyList() const {
173 bool ret = true;
174 for (auto* i = mpChildListHead; i; i = i->mNext)
175 ret &= verifyList(p_check: i, other: i->mNext);
176 return ret;
177}
178
179bool IParameterList::verifyObj() const {
180 bool ret = true;
181 for (auto* i = mpChildObjHead; i; i = i->mNext)
182 ret &= verifyObj(obj1: i, obj2: i->mNext);
183 return ret;
184}
185
186bool IParameterList::verifyList(IParameterList* p_check, IParameterList* other) const {
187 SEAD_ASSERT(p_check != nullptr);
188 auto* list = other;
189 bool ok = true;
190 while (list) {
191 if (p_check->getNameHash() == list->getNameHash()) {
192 sead::BufferingPrintFormatter ss;
193 ss << "Same hash code at [%s] and [%s]. Please change.\n"
194 << p_check->getName().cstr() << list->getName().cstr() << sead::flush;
195 ok = false;
196 }
197 list = list->mNext;
198 }
199 return ok;
200}
201
202bool IParameterList::verifyObj(IParameterObj* p_check, IParameterObj* other) const {
203 SEAD_ASSERT(p_check != nullptr);
204 auto* list = other;
205 bool ok = true;
206 while (list) {
207 if (p_check->getNameHash() == list->getNameHash()) {
208 sead::BufferingPrintFormatter ss;
209 ss << "Same hash code at [%s] and [%s]. Please change.\n"
210 << p_check->getName().cstr() << list->getName().cstr() << sead::flush;
211 ok = false;
212 }
213 list = list->mNext;
214 }
215 return ok;
216}
217
218ResParameterObj IParameterList::searchResParameterObj_(ResParameterList res,
219 const IParameterObj& obj) const {
220 if (!res.ptr())
221 return {};
222 for (auto it = res.objBegin(), end = res.objEnd(); it != end; ++it) {
223 if (obj.isApply_(obj: *it))
224 return *it;
225 }
226 return {};
227}
228
229IParameterObj* IParameterList::searchChildParameterObj_(ResParameterObj res,
230 IParameterObj* obj) const {
231 if (!res.ptr() || !mpChildObjHead)
232 return nullptr;
233
234 auto* start = obj ? obj : mpChildObjHead;
235 auto* child = start;
236 while (!child->isApply_(obj: res)) {
237 child = child->mNext;
238 if (!child)
239 child = mpChildObjHead;
240
241 if (child == start)
242 return nullptr;
243 }
244 return child;
245}
246
247ResParameterList IParameterList::searchResParameterList_(ResParameterList res,
248 const IParameterList& list) const {
249 if (!res.ptr())
250 return {};
251 for (auto it = res.listBegin(), end = res.listEnd(); it != end; ++it) {
252 if (list.isApply_(list: it.getList()))
253 return it.getList();
254 }
255 return {};
256}
257
258IParameterList* IParameterList::searchChildParameterList_(ResParameterList res) const {
259 if (!res.ptr())
260 return nullptr;
261
262 for (auto* child = mpChildListHead; child; child = child->mNext) {
263 if (child->isApply_(list: res))
264 return child;
265 }
266 return nullptr;
267}
268
269void IParameterList::applyResParameterObjB_(bool interpolate, ResParameterList res, f32 t) {
270 if (!res.ptr())
271 return;
272 IParameterObj* obj = nullptr;
273 for (auto it = res.objBegin(), end = res.objEnd(); it != end; ++it) {
274 auto* result = searchChildParameterObj_(res: *it, obj);
275 if (result) {
276 result->applyResParameterObj_(interpolate, obj1: {}, obj2: *it, t, list: this);
277 obj = result;
278 }
279 }
280}
281
282void IParameterList::applyResParameterListB_(bool interpolate, ResParameterList res, f32 t) {
283 if (!res.ptr())
284 return;
285 for (auto it = res.listBegin(), end = res.listEnd(); it != end; ++it) {
286 auto* list = searchChildParameterList_(res: *it);
287 if (list)
288 list->applyResParameterList_(interpolate, l1: {}, l2: *it, t);
289 }
290}
291
292void IParameterList::applyResParameterList_(bool interpolate, ResParameterList l1,
293 ResParameterList l2, f32 t) {
294 if (!preRead_())
295 return;
296
297 // Recursively apply all parameter objects.
298 if (l1.ptr()) {
299 IParameterObj* obj = nullptr;
300 for (auto it = l1.objBegin(), end = l1.objEnd(); it != end; ++it) {
301 auto* child = searchChildParameterObj_(res: *it, obj);
302 if (child) {
303 const auto obj2 = searchResParameterObj_(res: l2, obj: *child);
304 child->applyResParameterObj_(interpolate, obj1: *it, obj2, t, list: this);
305 obj = child;
306 } else {
307 applyResParameterObjB_(interpolate, res: l2, t);
308 }
309 }
310 } else {
311 applyResParameterObjB_(interpolate, res: l2, t);
312 }
313
314 // Now recursively apply all parameter lists.
315 if (l1.ptr()) {
316 for (auto it = l1.listBegin(), end = l1.listEnd(); it != end; ++it) {
317 auto* child = searchChildParameterList_(res: *it);
318 if (l2.ptr()) {
319 if (child) {
320 const auto other_list = searchResParameterList_(res: l2, list: *child);
321 child->applyResParameterList_(interpolate, l1: *it, l2: other_list, t);
322 } else {
323 applyResParameterListB_(interpolate, res: l2, t);
324 }
325 } else {
326 if (child)
327 child->applyResParameterList_(interpolate, l1: *it, l2: {}, t);
328 else
329 applyResParameterListB_(interpolate, res: {}, t);
330 }
331 }
332 } else {
333 applyResParameterListB_(interpolate, res: l2, t);
334 }
335
336 postRead_();
337}
338
339} // namespace agl::utl
340