1#include "utility/aglParameter.h"
2#include <codec/seadHashCRC32.h>
3#include <gfx/seadColor.h>
4#include <math/seadQuatCalcCommon.h>
5#include <math/seadVector.h>
6#include <prim/seadFormatPrint.h>
7#include <prim/seadMemUtil.h>
8#include "utility/aglParameterObj.h"
9#include "utility/aglParameterStringMgr.h"
10
11namespace agl::utl {
12
13static constexpr const char* sParameterTypeNames[] = {
14 "bool", "f32", "int", "vec2", "vec3", "vec4", "color",
15 "string32", "string64", "curve1", "curve2", "curve3", "curve4", "buffer_int",
16 "buffer_f32", "string256", "quat", "u32", "buffer_u32", "buffer_binary", "stringRef",
17};
18
19u32 ParameterBase::calcHash(const sead::SafeString& key) {
20 return sead::HashCRC32::calcStringHash(str: key);
21}
22
23ParameterBase::ParameterBase() {
24 initializeListNode(name: "default", label: "parameter", meta: "", param_obj: nullptr);
25}
26
27ParameterBase::ParameterBase(const sead::SafeString& name, const sead::SafeString& label,
28 IParameterObj* param_obj) {
29 initializeListNode(name, label, meta: "", param_obj);
30}
31
32ParameterBase::ParameterBase(const sead::SafeString& name, const sead::SafeString& label,
33 const sead::SafeString& meta, IParameterObj* param_obj) {
34 initializeListNode(name, label, meta, param_obj);
35}
36
37void ParameterBase::initializeListNode(const sead::SafeString& name, const sead::SafeString& label,
38 const sead::SafeString& meta, IParameterObj* param_obj) {
39 mNext = nullptr;
40
41#ifdef SEAD_DEBUG
42 if (ParameterStringMgr::instance()) {
43 mName = ParameterStringMgr::instance()->appendString(name);
44 mLabel = ParameterStringMgr::instance()->appendString(label);
45 mMeta = ParameterStringMgr::instance()->appendString(meta);
46 } else {
47 mName = nullptr;
48 mLabel = nullptr;
49 mMeta = nullptr;
50 }
51#endif
52
53 mNameHash = calcHash(key: name);
54
55 if (param_obj)
56 param_obj->pushBackListNode(p_node: this);
57}
58
59sead::SafeString ParameterBase::getParameterName() const {
60#ifdef SEAD_DEBUG
61 return mName;
62#else
63 return sead::SafeString::cEmptyString;
64#endif
65}
66
67sead::SafeString ParameterBase::getLabel() const {
68#ifdef SEAD_DEBUG
69 return mLabel;
70#else
71 return sead::SafeString::cEmptyString;
72#endif
73}
74
75sead::SafeString ParameterBase::getMeta() const {
76#ifdef SEAD_DEBUG
77 return mMeta;
78#else
79 return sead::SafeString::cEmptyString;
80#endif
81}
82
83const char* ParameterBase::getTagName() {
84 return "param";
85}
86
87const char* ParameterBase::getAttributeNameString() {
88 return "name";
89}
90
91const char* ParameterBase::getAttributeTypeString() {
92 return "type";
93}
94
95const char* ParameterBase::getAttributeValueString() {
96 return "value";
97}
98
99const char* ParameterBase::getParameterTypeName(ParameterType type) {
100 return sParameterTypeNames[u32(type)];
101}
102
103// NON_MATCHING: Clang emits a switch...
104bool ParameterBase::isSafeType(ParameterType type) const {
105 if (getParameterType() == type)
106 return true;
107
108 constexpr std::pair<ParameterType, ParameterType> pairs[] = {
109 {ParameterType::String64, ParameterType::String32},
110 {ParameterType::String32, ParameterType::String64},
111 {ParameterType::String256, ParameterType::String32},
112 {ParameterType::String256, ParameterType::String64},
113 {ParameterType::String32, ParameterType::String256},
114 {ParameterType::String64, ParameterType::String256},
115 };
116
117 for (const auto pair : pairs) {
118 if (type == pair.first && getParameterType() == pair.second)
119 return true;
120 }
121
122 if (getParameterType() == ParameterType::StringRef &&
123 (type == ParameterType::String32 || type == ParameterType::String64 ||
124 type == ParameterType::String256)) {
125 return true;
126 }
127
128 return false;
129}
130
131bool ParameterBase::verifyType(ParameterType type) const {
132 if (isSafeType(type))
133 return true;
134
135 sead::BufferingPrintFormatter ss;
136 ss << "!!! AGL ERROR !!! Instance ParameterType = %s Resource ParameterType = %s\n"
137 << sParameterTypeNames[u32(getParameterType())] << sParameterTypeNames[u32(type)]
138 << sead::flush;
139 return false;
140}
141
142bool ParameterBase::copy(const ParameterBase& other) {
143 if (getParameterType() != other.getParameterType() || mNameHash != other.mNameHash)
144 return false;
145
146 copyUnsafe(other);
147 return true;
148}
149
150void ParameterBase::copyUnsafe(const ParameterBase& other) {
151 if (other.getParameterType() == ParameterType::StringRef) {
152 auto* source = static_cast<const sead::SafeString*>(other.typePtr());
153 auto* dest = static_cast<sead::SafeString*>(typePtr());
154 *dest = *source;
155 return;
156 }
157
158 auto* dest = ptrT<u8>();
159 auto* src = other.ptrT<u8>();
160 const s32 n = size();
161 for (s32 i = 0; i < n; ++i)
162 *dest++ = *src++;
163}
164
165template <>
166void ParameterBase::copyLerp_<f32>(const ParameterBase& param1, const ParameterBase& param2,
167 f32 t) {
168 *ptrT<f32>() = sead::lerp(a: *param1.ptrT<f32>(), b: *param2.ptrT<f32>(), t);
169}
170
171template <>
172void ParameterBase::copyLerp_<sead::Quatf>(const ParameterBase& param1, const ParameterBase& param2,
173 f32 t) {
174 sead::QuatCalcCommon<f32>::slerpTo(out&: *ptrT<sead::Quatf>(), q1: *param1.ptrT<sead::Quatf>(),
175 q2: *param2.ptrT<sead::Quatf>(), t);
176}
177
178template <typename T>
179static void lerpVec_(T& v_dest, const T& v1, const T& v2, f32 t) {
180 for (size_t i = 0; i < v_dest.e.size(); ++i)
181 v_dest.e[i] = sead::lerp(v1.e[i], v2.e[i], t);
182}
183
184template <typename T>
185static void copyLerpVec_(ParameterBase& dest, const ParameterBase& param1,
186 const ParameterBase& param2, f32 t) {
187 lerpVec_(*dest.ptrT<T>(), *param1.ptrT<T>(), *param2.ptrT<T>(), t);
188}
189
190bool ParameterBase::copyLerp(const ParameterBase& param1, const ParameterBase& param2, f32 t) {
191 if (getParameterType() != param1.getParameterType() || mNameHash != param1.mNameHash)
192 return false;
193
194 if (getParameterType() != param2.getParameterType() || mNameHash != param2.mNameHash)
195 return false;
196
197 switch (getParameterType()) {
198 case ParameterType::Bool:
199 case ParameterType::Int:
200 case ParameterType::String32:
201 case ParameterType::String64:
202 case ParameterType::String256:
203 case ParameterType::U32:
204 copyUnsafe(other: param1);
205 return true;
206 case ParameterType::F32:
207 copyLerp_<f32>(param1, param2, t);
208 return true;
209 case ParameterType::Vec2:
210 copyLerpVec_<sead::Vector2f>(dest&: *this, param1, param2, t);
211 return true;
212 case ParameterType::Vec3:
213 copyLerpVec_<sead::Vector3f>(dest&: *this, param1, param2, t);
214 return true;
215 case ParameterType::Vec4:
216 copyLerpVec_<sead::Vector4f>(dest&: *this, param1, param2, t);
217 return true;
218 case ParameterType::Color: {
219 auto& color = *ptrT<sead::Color4f>();
220 color.setLerp(color1: *param1.ptrT<sead::Color4f>(), color2: *param2.ptrT<sead::Color4f>(), t);
221 return true;
222 }
223 case ParameterType::Curve1:
224 case ParameterType::Curve2:
225 case ParameterType::Curve3:
226 case ParameterType::Curve4:
227 case ParameterType::BufferInt:
228 case ParameterType::BufferF32:
229 case ParameterType::BufferU32:
230 case ParameterType::BufferBinary:
231 case ParameterType::StringRef:
232 case ParameterType::Special:
233 return true;
234 case ParameterType::Quat:
235 copyLerp_<sead::Quatf>(param1, param2, t);
236 return true;
237 default:
238 SEAD_ASSERT_MSG(false, "%d", int(getParameterType()));
239 return true;
240 }
241}
242
243static void applyResourceSimple_(ParameterBase& param, const ResParameter& res) {
244 void* dest = param.ptr();
245 const void* src = res.getData<void>();
246
247 const size_t data_size = param.size();
248 const size_t res_data_size = res.getDataSize();
249 const auto copy_size = data_size < res_data_size ? data_size : res_data_size;
250
251 sead::MemUtil::copy(dest, src, size: copy_size);
252}
253
254void ParameterBase::applyResource(ResParameter res) {
255#ifdef SEAD_DEBUG
256 if (!verifyType(ParameterType(res.ptr()->getType())))
257 return;
258#endif
259
260 if (getParameterType() == ParameterType::Bool) {
261 const bool value = *res.getData<u32>() != 0;
262 *ptrT<bool>() = value;
263 } else if (isBinaryInternalBuffer()) {
264 if (getParameterType() == ParameterType::StringRef)
265 *static_cast<sead::SafeString*>(typePtr()) = res.getData<char>();
266 else
267 applyResourceSimple_(param&: *this, res);
268 }
269
270 postApplyResource_(res.getData<void>(), res.getDataSize());
271}
272
273void ParameterBase::applyResource(ResParameter res, f32 t) {
274#ifdef SEAD_DEBUG
275 if (!verifyType(ParameterType(res.ptr()->getType())))
276 return;
277#endif
278
279 switch (getParameterType()) {
280 case ParameterType::Bool:
281 *ptrT<bool>() = *res.getData<u32>() != 0;
282 break;
283 case ParameterType::F32: {
284 f32 x;
285 sead::MemUtil::copy(dest: &x, src: res.getData<void>(), size: size());
286 *ptrT<f32>() += x * t;
287 break;
288 }
289 case ParameterType::Int:
290 case ParameterType::String32:
291 case ParameterType::String64:
292 case ParameterType::String256:
293 case ParameterType::U32:
294 applyResourceSimple_(param&: *this, res);
295 break;
296 case ParameterType::Vec2: {
297 sead::Vector2f vec;
298 sead::MemUtil::copy(dest: &vec, src: res.getData<void>(), size: size());
299 *ptrT<sead::Vector2f>() += vec * t;
300 break;
301 }
302 case ParameterType::Vec3: {
303 sead::Vector3f vec;
304 sead::MemUtil::copy(dest: &vec, src: res.getData<void>(), size: size());
305 *ptrT<sead::Vector3f>() += vec * t;
306 break;
307 }
308 case ParameterType::Vec4: {
309 sead::Vector4f vec;
310 sead::MemUtil::copy(dest: &vec, src: res.getData<void>(), size: size());
311 *ptrT<sead::Vector4f>() += vec * t;
312 break;
313 }
314 case ParameterType::Color: {
315 sead::Color4f color;
316 sead::MemUtil::copy(dest: &color, src: res.getData<void>(), size: size());
317 *ptrT<sead::Color4f>() += color * sead::Color4f{t, t, t, t};
318 break;
319 }
320 case ParameterType::Curve1:
321 case ParameterType::Curve2:
322 case ParameterType::Curve3:
323 case ParameterType::Curve4:
324 case ParameterType::Special:
325 break;
326 case ParameterType::BufferInt:
327 case ParameterType::BufferF32:
328 case ParameterType::BufferU32:
329 case ParameterType::BufferBinary:
330 if (isBinaryInternalBuffer())
331 applyResourceSimple_(param&: *this, res);
332 break;
333 case ParameterType::Quat: {
334 sead::Quatf quat;
335 sead::MemUtil::copy(dest: &quat, src: res.getData<void>(), size: size());
336 auto* target = ptrT<sead::Quatf>();
337 sead::QuatCalcCommon<f32>::slerpTo(out&: *target, q1: *target, q2: quat, t);
338 break;
339 }
340 case ParameterType::StringRef:
341 *static_cast<sead::SafeString*>(typePtr()) = res.getData<char>();
342 break;
343 default:
344 SEAD_ASSERT_MSG(false, "%d", int(getParameterType()));
345 break;
346 }
347
348 postApplyResource_(res.getData<void>(), res.getDataSize());
349}
350
351bool ParameterBase::isInterpolatable() const {
352 const auto type = getParameterType();
353 return type == ParameterType::F32 || type == ParameterType::Vec2 ||
354 type == ParameterType::Vec3 || type == ParameterType::Vec4 ||
355 type == ParameterType::Color || type == ParameterType::Quat;
356}
357
358size_t ParameterBase::binarize(void* binary) const {
359 SEAD_ASSERT(binary != nullptr);
360
361 size_t binary_size;
362 if (getParameterType() != ParameterType::Bool) {
363 binary_size = calcBinarizeSize();
364 sead::MemUtil::copy(dest: binary, src: ptr(), size: binary_size);
365 } else {
366 binary_size = sizeof(u32);
367 *static_cast<u32*>(binary) = *ptrT<bool>();
368 }
369 return binary_size;
370}
371
372bool ParameterBase::makeZero() {
373 switch (getParameterType()) {
374 case ParameterType::F32:
375 *ptrT<f32>() = 0;
376 return true;
377 case ParameterType::Vec2:
378 *ptrT<sead::Vector2f>() = {0, 0};
379 return true;
380 case ParameterType::Vec3:
381 *ptrT<sead::Vector3f>() = {0, 0, 0};
382 return true;
383 case ParameterType::Vec4:
384 *ptrT<sead::Vector4f>() = {0, 0, 0, 0};
385 return true;
386 case ParameterType::Color:
387 *ptrT<sead::Color4f>() = {0, 0, 0, 0};
388 return true;
389 case ParameterType::Quat: {
390 auto* quat = ptrT<sead::Quatf>();
391 quat->z = 0;
392 quat->w = 1;
393 quat->x = quat->y = 0;
394 return true;
395 }
396 case ParameterType::Bool:
397 case ParameterType::Int:
398 case ParameterType::String32:
399 case ParameterType::String64:
400 case ParameterType::Curve1:
401 case ParameterType::Curve2:
402 case ParameterType::Curve3:
403 case ParameterType::Curve4:
404 case ParameterType::BufferInt:
405 case ParameterType::BufferF32:
406 case ParameterType::String256:
407 case ParameterType::U32:
408 case ParameterType::BufferU32:
409 case ParameterType::BufferBinary:
410 case ParameterType::StringRef:
411 case ParameterType::Special:
412 return false;
413 }
414 return false;
415}
416
417// TODO: Remove these explicit instantiations once ParameterBase::createByTypeName is implemented.
418template class Parameter<bool>;
419template class Parameter<f32>;
420template class Parameter<s32>;
421template class Parameter<sead::Vector2f>;
422template class Parameter<sead::Vector3f>;
423template class Parameter<sead::Vector4f>;
424template class Parameter<sead::Color4f>;
425template class Parameter<sead::FixedSafeString<32>>;
426template class Parameter<sead::FixedSafeString<64>>;
427template class Parameter<sead::FixedSafeString<256>>;
428template class Parameter<sead::Quatf>;
429template class Parameter<u32>;
430template class Parameter<sead::SafeString>;
431template class ParameterCurve<1>;
432template class ParameterCurve<2>;
433template class ParameterCurve<3>;
434template class ParameterCurve<4>;
435
436} // namespace agl::utl
437