| 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 | |
| 11 | namespace agl::utl { |
| 12 | |
| 13 | static 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 | |
| 19 | u32 ParameterBase::calcHash(const sead::SafeString& key) { |
| 20 | return sead::HashCRC32::calcStringHash(str: key); |
| 21 | } |
| 22 | |
| 23 | ParameterBase::ParameterBase() { |
| 24 | initializeListNode(name: "default" , label: "parameter" , meta: "" , param_obj: nullptr); |
| 25 | } |
| 26 | |
| 27 | ParameterBase::ParameterBase(const sead::SafeString& name, const sead::SafeString& label, |
| 28 | IParameterObj* param_obj) { |
| 29 | initializeListNode(name, label, meta: "" , param_obj); |
| 30 | } |
| 31 | |
| 32 | ParameterBase::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 | |
| 37 | void 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 | |
| 59 | sead::SafeString ParameterBase::getParameterName() const { |
| 60 | #ifdef SEAD_DEBUG |
| 61 | return mName; |
| 62 | #else |
| 63 | return sead::SafeString::cEmptyString; |
| 64 | #endif |
| 65 | } |
| 66 | |
| 67 | sead::SafeString ParameterBase::getLabel() const { |
| 68 | #ifdef SEAD_DEBUG |
| 69 | return mLabel; |
| 70 | #else |
| 71 | return sead::SafeString::cEmptyString; |
| 72 | #endif |
| 73 | } |
| 74 | |
| 75 | sead::SafeString ParameterBase::getMeta() const { |
| 76 | #ifdef SEAD_DEBUG |
| 77 | return mMeta; |
| 78 | #else |
| 79 | return sead::SafeString::cEmptyString; |
| 80 | #endif |
| 81 | } |
| 82 | |
| 83 | const char* ParameterBase::getTagName() { |
| 84 | return "param" ; |
| 85 | } |
| 86 | |
| 87 | const char* ParameterBase::getAttributeNameString() { |
| 88 | return "name" ; |
| 89 | } |
| 90 | |
| 91 | const char* ParameterBase::getAttributeTypeString() { |
| 92 | return "type" ; |
| 93 | } |
| 94 | |
| 95 | const char* ParameterBase::getAttributeValueString() { |
| 96 | return "value" ; |
| 97 | } |
| 98 | |
| 99 | const char* ParameterBase::getParameterTypeName(ParameterType type) { |
| 100 | return sParameterTypeNames[u32(type)]; |
| 101 | } |
| 102 | |
| 103 | // NON_MATCHING: Clang emits a switch... |
| 104 | bool 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 | |
| 131 | bool 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 | |
| 142 | bool 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 | |
| 150 | void 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 | |
| 165 | template <> |
| 166 | void 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 | |
| 171 | template <> |
| 172 | void 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 | |
| 178 | template <typename T> |
| 179 | static 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 | |
| 184 | template <typename T> |
| 185 | static 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 | |
| 190 | bool 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 | |
| 243 | static 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 | |
| 254 | void 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 | |
| 273 | void 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 | |
| 351 | bool 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 | |
| 358 | size_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 | |
| 372 | bool 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. |
| 418 | template class Parameter<bool>; |
| 419 | template class Parameter<f32>; |
| 420 | template class Parameter<s32>; |
| 421 | template class Parameter<sead::Vector2f>; |
| 422 | template class Parameter<sead::Vector3f>; |
| 423 | template class Parameter<sead::Vector4f>; |
| 424 | template class Parameter<sead::Color4f>; |
| 425 | template class Parameter<sead::FixedSafeString<32>>; |
| 426 | template class Parameter<sead::FixedSafeString<64>>; |
| 427 | template class Parameter<sead::FixedSafeString<256>>; |
| 428 | template class Parameter<sead::Quatf>; |
| 429 | template class Parameter<u32>; |
| 430 | template class Parameter<sead::SafeString>; |
| 431 | template class ParameterCurve<1>; |
| 432 | template class ParameterCurve<2>; |
| 433 | template class ParameterCurve<3>; |
| 434 | template class ParameterCurve<4>; |
| 435 | |
| 436 | } // namespace agl::utl |
| 437 | |