#ifndef OPENMW_COMPONENTS_NIF_RECORDPTR_HPP #define OPENMW_COMPONENTS_NIF_RECORDPTR_HPP #include "niffile.hpp" #include "nifstream.hpp" #include namespace Nif { /** A reference to another record. It is read as an index from the NIF, and later looked up in the index table to get an actual pointer. */ template class RecordPtrT { union { intptr_t index; X* ptr; }; public: RecordPtrT() : index(-2) { } RecordPtrT(X* ptr) : ptr(ptr) { } /// Read the index from the nif void read(NIFStream* nif) { // Can only read the index once assert(index == -2); // Store the index for later index = nif->getInt(); assert(index >= -1); } /// Resolve index to pointer void post(Reader& nif) { if (index < 0) ptr = nullptr; else { Record* r = nif.getRecord(index); // And cast it ptr = dynamic_cast(r); assert(ptr != nullptr); } } /// Look up the actual object from the index const X* getPtr() const { assert(ptr != nullptr); return ptr; } X* getPtr() { assert(ptr != nullptr); return ptr; } const X& get() const { return *getPtr(); } X& get() { return *getPtr(); } /// Syntactic sugar const X* operator->() const { return getPtr(); } X* operator->() { return getPtr(); } /// Pointers are allowed to be empty bool empty() const { return ptr == nullptr; } }; /** A list of references to other records. These are read as a list, and later converted to pointers as needed. Not an optimized implementation. */ template using RecordListT = std::vector>; template void readRecordList(NIFStream* nif, RecordListT& list) { const int length = nif->getInt(); if (length < 0) throw std::runtime_error("Negative NIF record list length: " + std::to_string(length)); list.resize(static_cast(length)); for (auto& value : list) value.read(nif); } template void postRecordList(Reader& nif, RecordListT& list) { for (auto& value : list) value.post(nif); } struct Node; struct Extra; struct Property; struct NiUVData; struct NiPosData; struct NiVisData; struct Controller; struct Named; struct NiSkinData; struct NiFloatData; struct NiMorphData; struct NiPixelData; struct NiColorData; struct NiKeyframeData; struct NiTriStripsData; struct NiSkinInstance; struct NiSourceTexture; struct NiPalette; struct NiParticleModifier; struct NiBoolData; struct NiSkinPartition; struct BSShaderTextureSet; struct NiGeometryData; struct BSShaderProperty; struct NiAlphaProperty; struct NiCollisionObject; struct bhkWorldObject; struct bhkShape; struct bhkSerializable; struct hkPackedNiTriStripsData; struct NiAccumulator; struct NiInterpolator; struct NiStringPalette; struct NiControllerManager; struct NiBlendInterpolator; struct NiDefaultAVObjectPalette; struct NiControllerSequence; struct bhkCompressedMeshShapeData; using NodePtr = RecordPtrT; using ExtraPtr = RecordPtrT; using NiUVDataPtr = RecordPtrT; using NiPosDataPtr = RecordPtrT; using NiVisDataPtr = RecordPtrT; using ControllerPtr = RecordPtrT; using NamedPtr = RecordPtrT; using NiSkinDataPtr = RecordPtrT; using NiMorphDataPtr = RecordPtrT; using NiPixelDataPtr = RecordPtrT; using NiFloatDataPtr = RecordPtrT; using NiColorDataPtr = RecordPtrT; using NiKeyframeDataPtr = RecordPtrT; using NiSkinInstancePtr = RecordPtrT; using NiSourceTexturePtr = RecordPtrT; using NiPalettePtr = RecordPtrT; using NiParticleModifierPtr = RecordPtrT; using NiBoolDataPtr = RecordPtrT; using NiSkinPartitionPtr = RecordPtrT; using BSShaderTextureSetPtr = RecordPtrT; using NiGeometryDataPtr = RecordPtrT; using BSShaderPropertyPtr = RecordPtrT; using NiAlphaPropertyPtr = RecordPtrT; using NiCollisionObjectPtr = RecordPtrT; using bhkWorldObjectPtr = RecordPtrT; using bhkShapePtr = RecordPtrT; using hkPackedNiTriStripsDataPtr = RecordPtrT; using NiAccumulatorPtr = RecordPtrT; using NiInterpolatorPtr = RecordPtrT; using NiStringPalettePtr = RecordPtrT; using NiControllerManagerPtr = RecordPtrT; using NiBlendInterpolatorPtr = RecordPtrT; using NiDefaultAVObjectPalettePtr = RecordPtrT; using bhkCompressedMeshShapeDataPtr = RecordPtrT; using NodeList = RecordListT; using PropertyList = RecordListT; using ExtraList = RecordListT; using NiSourceTextureList = RecordListT; using NiInterpolatorList = RecordListT; using NiTriStripsDataList = RecordListT; using bhkShapeList = RecordListT; using bhkSerializableList = RecordListT; using NiControllerSequenceList = RecordListT; } // Namespace #endif