#include "lc_global.h" #include "lc_objectproperty.h" #include "lc_math.h" #define LC_OBJECT_PROPERTY(T) \ template void lcObjectProperty::Update(lcStep Step); \ template bool lcObjectProperty::ChangeKey(const T& Value, lcStep Step, bool AddKey); \ template void lcObjectProperty::InsertTime(lcStep Start, lcStep Time); \ template void lcObjectProperty::RemoveTime(lcStep Start, lcStep Time); \ template bool lcObjectProperty::HasKeyFrame(lcStep Time) const; \ template bool lcObjectProperty::SetKeyFrame(lcStep Time, bool KeyFrame); \ template void lcObjectProperty::Save(QTextStream& Stream, const char* ObjectName, const char* VariableName, bool SaveEmpty) const; \ template bool lcObjectProperty::Load(QTextStream& Stream, const QString& Token, const char* VariableName); LC_OBJECT_PROPERTY(float) LC_OBJECT_PROPERTY(int) LC_OBJECT_PROPERTY(lcVector2i) LC_OBJECT_PROPERTY(lcVector2) LC_OBJECT_PROPERTY(lcVector3) LC_OBJECT_PROPERTY(lcVector4) LC_OBJECT_PROPERTY(lcMatrix33) template static void lcObjectPropertySaveValue(QTextStream& Stream, const T& Value) { constexpr int Count = sizeof(T) / sizeof(float); for (int ValueIndex = 0; ValueIndex < Count; ValueIndex++) Stream << ((const float*)&Value)[ValueIndex] << ' '; } template<> void lcObjectPropertySaveValue(QTextStream& Stream, const int& Value) { constexpr int Count = sizeof(int) / sizeof(int); for (int ValueIndex = 0; ValueIndex < Count; ValueIndex++) Stream << ((const int*)&Value)[ValueIndex] << ' '; } template<> void lcObjectPropertySaveValue(QTextStream& Stream, const lcVector2i& Value) { constexpr int Count = sizeof(lcVector2i) / sizeof(int); for (int ValueIndex = 0; ValueIndex < Count; ValueIndex++) Stream << ((const int*)&Value)[ValueIndex] << ' '; } template static void lcObjectPropertyLoadValue(QTextStream& Stream, T& Value) { constexpr int Count = sizeof(T) / sizeof(float); for (int ValueIdx = 0; ValueIdx < Count; ValueIdx++) Stream >> ((float*)&Value)[ValueIdx]; } template<> void lcObjectPropertyLoadValue(QTextStream& Stream, int& Value) { constexpr int Count = sizeof(int) / sizeof(int); for (int ValueIdx = 0; ValueIdx < Count; ValueIdx++) Stream >> ((int*)&Value)[ValueIdx]; } template<> void lcObjectPropertyLoadValue(QTextStream& Stream, lcVector2i& Value) { constexpr int Count = sizeof(lcVector2i) / sizeof(int); for (int ValueIdx = 0; ValueIdx < Count; ValueIdx++) Stream >> ((int*)&Value)[ValueIdx]; } template void lcObjectProperty::Update(lcStep Step) { if (mKeys.empty()) return; const lcObjectPropertyKey* PreviousKey = &mKeys[0]; for (const lcObjectPropertyKey& Key : mKeys) { if (Key.Step > Step) break; PreviousKey = &Key; } mValue = PreviousKey->Value; } template bool lcObjectProperty::ChangeKey(const T& Value, lcStep Step, bool AddKey) { if (!AddKey && mKeys.empty()) { if (mValue == Value) return false; mValue = Value; return true; } for (typename std::vector>::iterator KeyIt = mKeys.begin(); KeyIt != mKeys.end(); KeyIt++) { if (KeyIt->Step < Step) continue; if (KeyIt->Step == Step) { if (KeyIt->Value == Value) return false; KeyIt->Value = Value; } else if (AddKey) mKeys.insert(KeyIt, lcObjectPropertyKey{ Step, Value }); else if (KeyIt == mKeys.begin()) { if (KeyIt->Value == Value) return false; KeyIt->Value = Value; } else { KeyIt = KeyIt - 1; if (KeyIt->Value == Value) return false; KeyIt->Value = Value; } return true; } if (AddKey || mKeys.empty()) mKeys.emplace_back(lcObjectPropertyKey{ Step, Value }); else mKeys.back().Value = Value; return true; } template void lcObjectProperty::InsertTime(lcStep Start, lcStep Time) { bool EndKey = false; for (typename std::vector>::iterator KeyIt = mKeys.begin(); KeyIt != mKeys.end();) { if ((KeyIt->Step < Start) || (KeyIt->Step == 1)) { KeyIt++; continue; } if (EndKey) { KeyIt = mKeys.erase(KeyIt); continue; } if (KeyIt->Step >= LC_STEP_MAX - Time) { KeyIt->Step = LC_STEP_MAX; EndKey = true; } else KeyIt->Step += Time; KeyIt++; } } template void lcObjectProperty::RemoveTime(lcStep Start, lcStep Time) { for (typename std::vector>::iterator KeyIt = mKeys.begin(); KeyIt != mKeys.end();) { if ((KeyIt->Step < Start) || (KeyIt->Step == 1)) { KeyIt++; continue; } if (KeyIt->Step < Start + Time) { KeyIt = mKeys.erase(KeyIt); continue; } KeyIt->Step -= Time; KeyIt++; } } template bool lcObjectProperty::HasKeyFrame(lcStep Time) const { for (typename std::vector>::const_iterator KeyIt = mKeys.begin(); KeyIt != mKeys.end(); KeyIt++) { if (KeyIt->Step == Time) return true; else if (KeyIt->Step > Time) return false; } return false; } template bool lcObjectProperty::SetKeyFrame(lcStep Time, bool KeyFrame) { if (KeyFrame) { typename std::vector>::const_iterator KeyIt; for (KeyIt = mKeys.begin(); KeyIt != mKeys.end(); KeyIt++) { if (KeyIt->Step == Time) return false; else if (KeyIt->Step > Time) break; } mKeys.insert(KeyIt, lcObjectPropertyKey{ Time, mValue }); return true; } else { for (typename std::vector>::const_iterator KeyIt = mKeys.begin(); KeyIt != mKeys.end(); KeyIt++) { if (KeyIt->Step == Time) { if (mKeys.size() == 1) mValue = KeyIt->Value; mKeys.erase(KeyIt); return true; } else if (KeyIt->Step > Time) return false; } } return false; } template void lcObjectProperty::Save(QTextStream& Stream, const char* ObjectName, const char* VariableName, bool SaveEmpty) const { if (mKeys.empty()) { if (SaveEmpty) { Stream << QLatin1String("0 !LEOCAD ") << ObjectName << ' ' << VariableName << ' '; lcObjectPropertySaveValue(Stream, mValue); Stream << QLatin1String("\r\n"); } } else { for (const lcObjectPropertyKey& Key : mKeys) { Stream << QLatin1String("0 !LEOCAD ") << ObjectName << ' ' << VariableName << "_KEY " << Key.Step << ' '; lcObjectPropertySaveValue(Stream, Key.Value); Stream << QLatin1String("\r\n"); } } } template bool lcObjectProperty::Load(QTextStream& Stream, const QString& Token, const char* VariableName) { if (Token == VariableName) { lcObjectPropertyLoadValue(Stream, mValue); return true; } if (Token.endsWith(QLatin1String("_KEY")) && Token.left(Token.size() - 4) == VariableName) { QString StepString; Stream >> StepString; const int Step = StepString.toInt(); T Value; constexpr int Count = sizeof(T) / sizeof(float); for (int ValueIdx = 0; ValueIdx < Count; ValueIdx++) Stream >> ((float*)&Value)[ValueIdx]; ChangeKey(Value, Step, true); return true; } return false; }