// Copyright (C) 2009-present, Panagiotis Christopoulos Charitos and contributors. // All rights reserved. // Code licensed under the BSD License. // http://www.anki3d.org/LICENSE #pragma once #include #include namespace anki { constexpr U32 kSceneBinaryVersion = 1; #define ANKI_SERIALIZE(var, version) \ { \ static_assert(version <= kSceneBinaryVersion); \ ANKI_CHECK(serializer.serialize(#var, version, false, var)); \ } #define ANKI_SERIALIZE_ALIAS(varName, var, version) \ { \ static_assert(version <= kSceneBinaryVersion); \ ANKI_CHECK(serializer.serialize(varName, version, false, var)); \ } #define ANKI_SERIALIZE_DEPRECATED(var, version) \ { \ static_assert(version <= kSceneBinaryVersion); \ ANKI_CHECK(serializer.serialize(#var, version, true, var)); \ } // Interface class for scene serialization class SceneSerializer { public: SceneSerializer(Bool writingMode) : m_writeMode(writingMode) { } virtual Error write(CString name, ConstWeakArray values) = 0; virtual Error read(CString name, WeakArray values) = 0; virtual Error write(CString name, ConstWeakArray values) = 0; virtual Error read(CString name, WeakArray values) = 0; virtual Error write(CString name, ConstWeakArray values) = 0; virtual Error read(CString name, WeakArray values) = 0; Error write(CString name, ConstWeakArray values); Error read(CString name, WeakArray values); virtual Error write(CString name, CString value) = 0; virtual Error read(CString name, SceneString& value) = 0; // For resources template Error serialize(String varName, U32 varVersion, Bool varDeprecated, ResourcePtr& rsrc) { SceneString filename; if(m_writeMode && rsrc) { filename = rsrc->getFilename(); } ANKI_CHECK(serializeInternal(varName, varVersion, varDeprecated, filename)); if(!m_writeMode && filename.getLength()) { ANKI_CHECK(ResourceManager::getSingleton().loadResource(filename, rsrc)); } return Error::kNone; } // For regular arithmetic template Error serialize(String varName, U32 varVersion, Bool varDeprecated, T& varValue) requires(std::is_arithmetic_v) { WeakArray arr(&varValue, 1); return serializeInternal(varName, varVersion, varDeprecated, arr); } // SceneDynamicArray of numbers template Error serialize(String varName, U32 varVersion, Bool varDeprecated, SceneDynamicArray& array) requires(std::is_arithmetic_v) { WeakArray arr(array); return serializeInternal(varName, varVersion, varDeprecated, arr); } // Vector 3 template Error serialize(String varName, U32 varVersion, Bool varDeprecated, TVec& varValue) { WeakArray arr(&varValue[0], 3); return serializeInternal(varName, varVersion, varDeprecated, arr); } // Vector 4 template Error serialize(String varName, U32 varVersion, Bool varDeprecated, TVec& varValue) { WeakArray arr(&varValue[0], 4); return serializeInternal(varName, varVersion, varDeprecated, arr); } // Mat template Error serialize(String varName, U32 varVersion, Bool varDeprecated, TMat& varValue) { WeakArray arr(&varValue[0], kTRowCount * kTColumnCount); return serializeInternal(varName, varVersion, varDeprecated, arr); } // Enums template Error serialize(String varName, U32 varVersion, Bool varDeprecated, T& varValue) requires(std::is_enum_v) { static_assert(sizeof(T) <= sizeof(U32)); U32 val = U32(varValue); WeakArray arr(&val, 1); ANKI_CHECK(serializeInternal(varName, varVersion, varDeprecated, arr)); varValue = T(val); return Error::kNone; } // Strings Error serialize(String varName, U32 varVersion, Bool varDeprecated, SceneString& varValue) { return serializeInternal(varName, varVersion, varDeprecated, varValue); } Bool isInWriteMode() const { return m_writeMode; } Bool isInReadMode() const { return !m_writeMode; } public: Bool m_writeMode = false; U32 m_crntBinaryVersion = kMaxU32; template Error serializeInternal(CString varName, U32 varVersion, Bool varDeprecated, T& varValue) { ANKI_ASSERT(varVersion <= kSceneBinaryVersion); if(m_writeMode) { // Always writing in the latest version so skip deprecated vars const Bool skip = varDeprecated; if(!skip) { return write(varName, varValue); } } else { // Var is newer than the binary we are reading, skip it Bool skip = varVersion >= m_crntBinaryVersion; // Var is depracated and binary is newer, skip it skip = skip || (varDeprecated && m_crntBinaryVersion > varVersion); if(!skip) { return read(varName, varValue); } } return Error::kNone; } }; // Serialize in a custom text format class TextSceneSerializer : public SceneSerializer { public: TextSceneSerializer(File* file, Bool writingMode) : SceneSerializer(writingMode) , m_file(*file) { } Error write(CString name, ConstWeakArray values) final { if(values.getSize() == 1) { ANKI_CHECK(m_file.writeTextf("%s %u\n", name.cstr(), values[0])); } else { ANKI_CHECK(m_file.writeTextf("%s %u ", name.cstr(), values[0])); for(U32 i = 1; i < values.getSize(); ++i) { ANKI_CHECK(m_file.writeTextf((i < values.getSize() - 1) ? "%u " : "%u\n", values[i])); } } return Error::kNone; } Error read([[maybe_unused]] CString name, [[maybe_unused]] WeakArray values) final { ANKI_ASSERT(!"TODO"); return Error::kNone; } Error write(CString name, ConstWeakArray values) final { if(values.getSize() == 1) { ANKI_CHECK(m_file.writeTextf("%s %d\n", name.cstr(), values[0])); } else { ANKI_CHECK(m_file.writeTextf("%s %d ", name.cstr(), values[0])); for(U32 i = 1; i < values.getSize(); ++i) { ANKI_CHECK(m_file.writeTextf((i < values.getSize() - 1) ? "%d " : "%d\n", values[i])); } } return Error::kNone; } Error read([[maybe_unused]] CString name, [[maybe_unused]] WeakArray values) final { ANKI_ASSERT(!"TODO"); return Error::kNone; } Error write(CString name, ConstWeakArray values) final { if(values.getSize() == 1) { ANKI_CHECK(m_file.writeTextf("%s %f\n", name.cstr(), values[0])); } else { ANKI_CHECK(m_file.writeTextf("%s %f ", name.cstr(), values[0])); for(U32 i = 1; i < values.getSize(); ++i) { ANKI_CHECK(m_file.writeTextf((i < values.getSize() - 1) ? "%f " : "%f\n", values[i])); } } return Error::kNone; } Error read([[maybe_unused]] CString name, [[maybe_unused]] WeakArray values) { ANKI_ASSERT(!"TODO"); return Error::kNone; } Error write(CString name, CString value) final { return m_file.writeTextf("%s %s\n", name.cstr(), value.cstr()); } Error read([[maybe_unused]] CString name, [[maybe_unused]] SceneString& value) final { ANKI_ASSERT(!"TODO"); return Error::kNone; } private: File& m_file; }; } // end namespace anki