#ifndef OPENMW_COMPONENTS_NIF_RECORDPTR_HPP #define OPENMW_COMPONENTS_NIF_RECORDPTR_HPP #include #include "niffile.hpp" #include "nifstream.hpp" 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->get(); 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 std::uint32_t length = nif->get(); // No reasonable list can hit this generous limit if (length >= (1 << 24)) throw std::runtime_error("Record list too long: " + std::to_string(length)); list.resize(length); for (auto& value : list) value.read(nif); } template void postRecordList(Reader& nif, RecordListT& list) { for (auto& value : list) value.post(nif); } struct NiAVObject; struct Extra; struct NiProperty; struct NiUVData; struct NiPosData; struct NiVisData; struct NiTimeController; struct NiObjectNET; struct NiSkinData; struct NiFloatData; struct NiMorphData; struct NiPixelData; struct NiColorData; struct NiKeyframeData; struct NiTriStripsData; struct NiSkinInstance; struct NiSourceTexture; struct NiPalette; struct NiParticleModifier; struct BSMasterParticleSystem; struct NiParticleSystem; struct NiPSysCollider; struct NiPSysColliderManager; struct NiPSysEmitterCtlrData; struct NiPSysModifier; struct NiPSysSpawnModifier; struct NiBoolData; struct NiBSplineData; struct NiBSplineBasisData; struct NiSkinPartition; struct BSShaderTextureSet; struct NiTriBasedGeom; struct NiGeometryData; struct BSShaderProperty; struct NiAlphaProperty; struct NiCollisionObject; struct bhkSystem; struct bhkWorldObject; struct bhkShape; struct bhkSerializable; struct bhkEntity; struct bhkConvexShape; struct bhkRigidBody; struct hkPackedNiTriStripsData; struct NiAccumulator; struct NiInterpolator; struct NiStringPalette; struct NiControllerManager; struct NiBlendInterpolator; struct NiDefaultAVObjectPalette; struct NiControllerSequence; struct bhkCompressedMeshShapeData; struct BSMultiBound; struct BSMultiBoundData; struct BSSkinBoneData; struct BSAnimNote; struct BSAnimNotes; using NiAVObjectPtr = RecordPtrT; using ExtraPtr = RecordPtrT; using NiUVDataPtr = RecordPtrT; using NiPosDataPtr = RecordPtrT; using NiVisDataPtr = RecordPtrT; using NiTimeControllerPtr = RecordPtrT; using NiObjectNETPtr = 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 BSMasterParticleSystemPtr = RecordPtrT; using NiParticleSystemPtr = RecordPtrT; using NiPSysColliderPtr = RecordPtrT; using NiPSysColliderManagerPtr = RecordPtrT; using NiPSysEmitterCtlrDataPtr = RecordPtrT; using NiPSysModifierPtr = RecordPtrT; using NiPSysSpawnModifierPtr = RecordPtrT; using NiBoolDataPtr = RecordPtrT; using NiBSplineDataPtr = RecordPtrT; using NiBSplineBasisDataPtr = RecordPtrT; using NiSkinPartitionPtr = RecordPtrT; using BSShaderTextureSetPtr = RecordPtrT; using NiTriBasedGeomPtr = RecordPtrT; using NiGeometryDataPtr = RecordPtrT; using BSShaderPropertyPtr = RecordPtrT; using NiAlphaPropertyPtr = RecordPtrT; using NiCollisionObjectPtr = RecordPtrT; using bhkSystemPtr = RecordPtrT; using bhkWorldObjectPtr = RecordPtrT; using bhkShapePtr = RecordPtrT; using bhkEntityPtr = RecordPtrT; using bhkConvexShapePtr = RecordPtrT; using bhkRigidBodyPtr = 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 BSMultiBoundPtr = RecordPtrT; using BSMultiBoundDataPtr = RecordPtrT; using BSSkinBoneDataPtr = RecordPtrT; using NiAVObjectList = RecordListT; using NiPropertyList = RecordListT; using ExtraList = RecordListT; using NiSourceTextureList = RecordListT; using NiInterpolatorList = RecordListT; using NiTriStripsDataList = RecordListT; using bhkShapeList = RecordListT; using bhkSerializableList = RecordListT; using bhkEntityList = RecordListT; using bhkRigidBodyList = RecordListT; using NiControllerSequenceList = RecordListT; using NiPSysModifierList = RecordListT; using NiTriBasedGeomList = RecordListT; using BSAnimNoteList = RecordListT; using BSAnimNotesList = RecordListT; } // Namespace #endif