1 #include "niffile.hpp"
2 #include "effect.hpp"
3
4 #include <array>
5 #include <map>
6 #include <sstream>
7
8 namespace Nif
9 {
10
11 /// Open a NIF stream. The name is used for error messages.
NIFFile(Files::IStreamPtr stream,const std::string & name)12 NIFFile::NIFFile(Files::IStreamPtr stream, const std::string &name)
13 : filename(name)
14 {
15 parse(stream);
16 }
17
~NIFFile()18 NIFFile::~NIFFile()
19 {
20 for (Record* record : records)
21 delete record;
22 }
23
construct()24 template <typename NodeType> static Record* construct() { return new NodeType; }
25
26 struct RecordFactoryEntry {
27
28 using create_t = Record* (*)();
29
30 create_t mCreate;
31 RecordType mType;
32
33 };
34
35 ///These are all the record types we know how to read.
makeFactory()36 static std::map<std::string,RecordFactoryEntry> makeFactory()
37 {
38 std::map<std::string,RecordFactoryEntry> factory;
39 factory["NiNode"] = {&construct <NiNode> , RC_NiNode };
40 factory["NiSwitchNode"] = {&construct <NiSwitchNode> , RC_NiSwitchNode };
41 factory["NiLODNode"] = {&construct <NiLODNode> , RC_NiLODNode };
42 factory["AvoidNode"] = {&construct <NiNode> , RC_AvoidNode };
43 factory["NiCollisionSwitch"] = {&construct <NiNode> , RC_NiCollisionSwitch };
44 factory["NiBSParticleNode"] = {&construct <NiNode> , RC_NiBSParticleNode };
45 factory["NiBSAnimationNode"] = {&construct <NiNode> , RC_NiBSAnimationNode };
46 factory["NiBillboardNode"] = {&construct <NiNode> , RC_NiBillboardNode };
47 factory["NiTriShape"] = {&construct <NiTriShape> , RC_NiTriShape };
48 factory["NiTriStrips"] = {&construct <NiTriStrips> , RC_NiTriStrips };
49 factory["NiLines"] = {&construct <NiLines> , RC_NiLines };
50 factory["NiParticles"] = {&construct <NiParticles> , RC_NiParticles };
51 factory["NiRotatingParticles"] = {&construct <NiParticles> , RC_NiParticles };
52 factory["NiAutoNormalParticles"] = {&construct <NiParticles> , RC_NiParticles };
53 factory["NiCamera"] = {&construct <NiCamera> , RC_NiCamera };
54 factory["RootCollisionNode"] = {&construct <NiNode> , RC_RootCollisionNode };
55 factory["NiTexturingProperty"] = {&construct <NiTexturingProperty> , RC_NiTexturingProperty };
56 factory["NiFogProperty"] = {&construct <NiFogProperty> , RC_NiFogProperty };
57 factory["NiMaterialProperty"] = {&construct <NiMaterialProperty> , RC_NiMaterialProperty };
58 factory["NiZBufferProperty"] = {&construct <NiZBufferProperty> , RC_NiZBufferProperty };
59 factory["NiAlphaProperty"] = {&construct <NiAlphaProperty> , RC_NiAlphaProperty };
60 factory["NiVertexColorProperty"] = {&construct <NiVertexColorProperty> , RC_NiVertexColorProperty };
61 factory["NiShadeProperty"] = {&construct <NiShadeProperty> , RC_NiShadeProperty };
62 factory["NiDitherProperty"] = {&construct <NiDitherProperty> , RC_NiDitherProperty };
63 factory["NiWireframeProperty"] = {&construct <NiWireframeProperty> , RC_NiWireframeProperty };
64 factory["NiSpecularProperty"] = {&construct <NiSpecularProperty> , RC_NiSpecularProperty };
65 factory["NiStencilProperty"] = {&construct <NiStencilProperty> , RC_NiStencilProperty };
66 factory["NiVisController"] = {&construct <NiVisController> , RC_NiVisController };
67 factory["NiGeomMorpherController"] = {&construct <NiGeomMorpherController> , RC_NiGeomMorpherController };
68 factory["NiKeyframeController"] = {&construct <NiKeyframeController> , RC_NiKeyframeController };
69 factory["NiAlphaController"] = {&construct <NiAlphaController> , RC_NiAlphaController };
70 factory["NiRollController"] = {&construct <NiRollController> , RC_NiRollController };
71 factory["NiUVController"] = {&construct <NiUVController> , RC_NiUVController };
72 factory["NiPathController"] = {&construct <NiPathController> , RC_NiPathController };
73 factory["NiMaterialColorController"] = {&construct <NiMaterialColorController> , RC_NiMaterialColorController };
74 factory["NiBSPArrayController"] = {&construct <NiBSPArrayController> , RC_NiBSPArrayController };
75 factory["NiParticleSystemController"] = {&construct <NiParticleSystemController> , RC_NiParticleSystemController };
76 factory["NiFlipController"] = {&construct <NiFlipController> , RC_NiFlipController };
77 factory["NiAmbientLight"] = {&construct <NiLight> , RC_NiLight };
78 factory["NiDirectionalLight"] = {&construct <NiLight> , RC_NiLight };
79 factory["NiPointLight"] = {&construct <NiPointLight> , RC_NiLight };
80 factory["NiSpotLight"] = {&construct <NiSpotLight> , RC_NiLight };
81 factory["NiTextureEffect"] = {&construct <NiTextureEffect> , RC_NiTextureEffect };
82 factory["NiVertWeightsExtraData"] = {&construct <NiVertWeightsExtraData> , RC_NiVertWeightsExtraData };
83 factory["NiTextKeyExtraData"] = {&construct <NiTextKeyExtraData> , RC_NiTextKeyExtraData };
84 factory["NiStringExtraData"] = {&construct <NiStringExtraData> , RC_NiStringExtraData };
85 factory["NiGravity"] = {&construct <NiGravity> , RC_NiGravity };
86 factory["NiPlanarCollider"] = {&construct <NiPlanarCollider> , RC_NiPlanarCollider };
87 factory["NiSphericalCollider"] = {&construct <NiSphericalCollider> , RC_NiSphericalCollider };
88 factory["NiParticleGrowFade"] = {&construct <NiParticleGrowFade> , RC_NiParticleGrowFade };
89 factory["NiParticleColorModifier"] = {&construct <NiParticleColorModifier> , RC_NiParticleColorModifier };
90 factory["NiParticleRotation"] = {&construct <NiParticleRotation> , RC_NiParticleRotation };
91 factory["NiFloatData"] = {&construct <NiFloatData> , RC_NiFloatData };
92 factory["NiTriShapeData"] = {&construct <NiTriShapeData> , RC_NiTriShapeData };
93 factory["NiTriStripsData"] = {&construct <NiTriStripsData> , RC_NiTriStripsData };
94 factory["NiLinesData"] = {&construct <NiLinesData> , RC_NiLinesData };
95 factory["NiVisData"] = {&construct <NiVisData> , RC_NiVisData };
96 factory["NiColorData"] = {&construct <NiColorData> , RC_NiColorData };
97 factory["NiPixelData"] = {&construct <NiPixelData> , RC_NiPixelData };
98 factory["NiMorphData"] = {&construct <NiMorphData> , RC_NiMorphData };
99 factory["NiKeyframeData"] = {&construct <NiKeyframeData> , RC_NiKeyframeData };
100 factory["NiSkinData"] = {&construct <NiSkinData> , RC_NiSkinData };
101 factory["NiUVData"] = {&construct <NiUVData> , RC_NiUVData };
102 factory["NiPosData"] = {&construct <NiPosData> , RC_NiPosData };
103 factory["NiParticlesData"] = {&construct <NiParticlesData> , RC_NiParticlesData };
104 factory["NiRotatingParticlesData"] = {&construct <NiRotatingParticlesData> , RC_NiParticlesData };
105 factory["NiAutoNormalParticlesData"] = {&construct <NiParticlesData> , RC_NiParticlesData };
106 factory["NiSequenceStreamHelper"] = {&construct <NiSequenceStreamHelper> , RC_NiSequenceStreamHelper };
107 factory["NiSourceTexture"] = {&construct <NiSourceTexture> , RC_NiSourceTexture };
108 factory["NiSkinInstance"] = {&construct <NiSkinInstance> , RC_NiSkinInstance };
109 factory["NiLookAtController"] = {&construct <NiLookAtController> , RC_NiLookAtController };
110 factory["NiPalette"] = {&construct <NiPalette> , RC_NiPalette };
111 factory["NiIntegerExtraData"] = {&construct <NiIntegerExtraData> , RC_NiIntegerExtraData };
112 factory["NiIntegersExtraData"] = {&construct <NiIntegersExtraData> , RC_NiIntegersExtraData };
113 factory["NiBinaryExtraData"] = {&construct <NiBinaryExtraData> , RC_NiBinaryExtraData };
114 factory["NiBooleanExtraData"] = {&construct <NiBooleanExtraData> , RC_NiBooleanExtraData };
115 factory["NiVectorExtraData"] = {&construct <NiVectorExtraData> , RC_NiVectorExtraData };
116 factory["NiColorExtraData"] = {&construct <NiVectorExtraData> , RC_NiColorExtraData };
117 factory["NiFloatExtraData"] = {&construct <NiFloatExtraData> , RC_NiFloatExtraData };
118 factory["NiFloatsExtraData"] = {&construct <NiFloatsExtraData> , RC_NiFloatsExtraData };
119 factory["NiStringPalette"] = {&construct <NiStringPalette> , RC_NiStringPalette };
120 factory["NiBoolData"] = {&construct <NiBoolData> , RC_NiBoolData };
121 factory["NiSkinPartition"] = {&construct <NiSkinPartition> , RC_NiSkinPartition };
122 factory["BSXFlags"] = {&construct <NiIntegerExtraData> , RC_BSXFlags };
123 factory["BSBound"] = {&construct <BSBound> , RC_BSBound };
124 factory["NiTransformData"] = {&construct <NiKeyframeData> , RC_NiKeyframeData };
125 factory["BSFadeNode"] = {&construct <NiNode> , RC_NiNode };
126 factory["bhkBlendController"] = {&construct <bhkBlendController> , RC_bhkBlendController };
127 factory["NiFloatInterpolator"] = {&construct <NiFloatInterpolator> , RC_NiFloatInterpolator };
128 factory["NiBoolInterpolator"] = {&construct <NiBoolInterpolator> , RC_NiBoolInterpolator };
129 factory["NiPoint3Interpolator"] = {&construct <NiPoint3Interpolator> , RC_NiPoint3Interpolator };
130 factory["NiTransformController"] = {&construct <NiKeyframeController> , RC_NiKeyframeController };
131 factory["NiTransformInterpolator"] = {&construct <NiTransformInterpolator> , RC_NiTransformInterpolator };
132 factory["NiColorInterpolator"] = {&construct <NiColorInterpolator> , RC_NiColorInterpolator };
133 factory["BSShaderTextureSet"] = {&construct <BSShaderTextureSet> , RC_BSShaderTextureSet };
134 factory["BSLODTriShape"] = {&construct <BSLODTriShape> , RC_BSLODTriShape };
135 factory["BSShaderProperty"] = {&construct <BSShaderProperty> , RC_BSShaderProperty };
136 factory["BSShaderPPLightingProperty"] = {&construct <BSShaderPPLightingProperty> , RC_BSShaderPPLightingProperty };
137 factory["BSShaderNoLightingProperty"] = {&construct <BSShaderNoLightingProperty> , RC_BSShaderNoLightingProperty };
138 return factory;
139 }
140
141 ///Make the factory map used for parsing the file
142 static const std::map<std::string,RecordFactoryEntry> factories = makeFactory();
143
printVersion(unsigned int version)144 std::string NIFFile::printVersion(unsigned int version)
145 {
146 int major = (version >> 24) & 0xFF;
147 int minor = (version >> 16) & 0xFF;
148 int patch = (version >> 8) & 0xFF;
149 int rev = version & 0xFF;
150
151 std::stringstream stream;
152 stream << major << "." << minor << "." << patch << "." << rev;
153 return stream.str();
154 }
155
parse(Files::IStreamPtr stream)156 void NIFFile::parse(Files::IStreamPtr stream)
157 {
158 NIFStream nif (this, stream);
159
160 // Check the header string
161 std::string head = nif.getVersionString();
162 static const std::array<std::string, 2> verStrings =
163 {
164 "NetImmerse File Format",
165 "Gamebryo File Format"
166 };
167 bool supported = false;
168 for (const std::string& verString : verStrings)
169 {
170 supported = (head.compare(0, verString.size(), verString) == 0);
171 if (supported)
172 break;
173 }
174 if (!supported)
175 fail("Invalid NIF header: " + head);
176
177 supported = false;
178
179 // Get BCD version
180 ver = nif.getUInt();
181 // 4.0.0.0 is an older, practically identical version of the format.
182 // It's not used by Morrowind assets but Morrowind supports it.
183 static const std::array<uint32_t, 2> supportedVers =
184 {
185 NIFStream::generateVersion(4,0,0,0),
186 VER_MW
187 };
188 for (uint32_t supportedVer : supportedVers)
189 {
190 supported = (ver == supportedVer);
191 if (supported)
192 break;
193 }
194 if (!supported)
195 {
196 if (sLoadUnsupportedFiles)
197 warn("Unsupported NIF version: " + printVersion(ver) + ". Proceed with caution!");
198 else
199 fail("Unsupported NIF version: " + printVersion(ver));
200 }
201
202 // NIF data endianness
203 if (ver >= NIFStream::generateVersion(20,0,0,4))
204 {
205 unsigned char endianness = nif.getChar();
206 if (endianness == 0)
207 fail("Big endian NIF files are unsupported");
208 }
209
210 // User version
211 if (ver > NIFStream::generateVersion(10,0,1,8))
212 userVer = nif.getUInt();
213
214 // Number of records
215 const std::size_t recNum = nif.getUInt();
216 records.resize(recNum);
217
218 // Bethesda stream header
219 // It contains Bethesda format version and (useless) export information
220 if (ver == VER_OB_OLD ||
221 (userVer >= 3 && ((ver == VER_OB || ver == VER_BGS)
222 || (ver >= NIFStream::generateVersion(10,1,0,0) && ver <= NIFStream::generateVersion(20,0,0,4) && userVer <= 11))))
223 {
224 bethVer = nif.getUInt();
225 nif.getExportString(); // Author
226 if (bethVer > BETHVER_FO4)
227 nif.getUInt(); // Unknown
228 nif.getExportString(); // Process script
229 nif.getExportString(); // Export script
230 if (bethVer == BETHVER_FO4)
231 nif.getExportString(); // Max file path
232 }
233
234 std::vector<std::string> recTypes;
235 std::vector<unsigned short> recTypeIndices;
236
237 const bool hasRecTypeListings = ver >= NIFStream::generateVersion(5,0,0,1);
238 if (hasRecTypeListings)
239 {
240 unsigned short recTypeNum = nif.getUShort();
241 if (recTypeNum) // Record type list
242 nif.getSizedStrings(recTypes, recTypeNum);
243 if (recNum) // Record type mapping for each record
244 nif.getUShorts(recTypeIndices, recNum);
245 if (ver >= NIFStream::generateVersion(5,0,0,6)) // Groups
246 {
247 if (ver >= NIFStream::generateVersion(20,1,0,1)) // String table
248 {
249 if (ver >= NIFStream::generateVersion(20,2,0,5) && recNum) // Record sizes
250 {
251 std::vector<unsigned int> recSizes; // Currently unused
252 nif.getUInts(recSizes, recNum);
253 }
254 const std::size_t stringNum = nif.getUInt();
255 nif.getUInt(); // Max string length
256 if (stringNum)
257 nif.getSizedStrings(strings, stringNum);
258 }
259 std::vector<unsigned int> groups; // Currently unused
260 unsigned int groupNum = nif.getUInt();
261 if (groupNum)
262 nif.getUInts(groups, groupNum);
263 }
264 }
265
266 const bool hasRecordSeparators = ver >= NIFStream::generateVersion(10,0,0,0) && ver < NIFStream::generateVersion(10,2,0,0);
267 for (std::size_t i = 0; i < recNum; i++)
268 {
269 Record *r = nullptr;
270
271 std::string rec = hasRecTypeListings ? recTypes[recTypeIndices[i]] : nif.getString();
272 if(rec.empty())
273 {
274 std::stringstream error;
275 error << "Record number " << i << " out of " << recNum << " is blank.";
276 fail(error.str());
277 }
278
279 // Record separator. Some Havok records in Oblivion do not have it.
280 if (hasRecordSeparators && rec.compare(0, 3, "bhk"))
281 {
282 if (nif.getInt())
283 {
284 std::stringstream warning;
285 warning << "Record number " << i << " out of " << recNum << " is preceded by a non-zero separator.";
286 warn(warning.str());
287 }
288 }
289
290 std::map<std::string,RecordFactoryEntry>::const_iterator entry = factories.find(rec);
291
292 if (entry != factories.end())
293 {
294 r = entry->second.mCreate ();
295 r->recType = entry->second.mType;
296 }
297 else
298 fail("Unknown record type " + rec);
299
300 if (!supported)
301 Log(Debug::Verbose) << "NIF Debug: Reading record of type " << rec << ", index " << i << " (" << filename << ")";
302
303 assert(r != nullptr);
304 assert(r->recType != RC_MISSING);
305 r->recName = rec;
306 r->recIndex = i;
307 records[i] = r;
308 r->read(&nif);
309 }
310
311 const std::size_t rootNum = nif.getUInt();
312 roots.resize(rootNum);
313
314 //Determine which records are roots
315 for (std::size_t i = 0; i < rootNum; i++)
316 {
317 int idx = nif.getInt();
318 if (idx >= 0 && static_cast<std::size_t>(idx) < records.size())
319 {
320 roots[i] = records[idx];
321 }
322 else
323 {
324 roots[i] = nullptr;
325 warn("Root " + std::to_string(i + 1) + " does not point to a record: index " + std::to_string(idx));
326 }
327 }
328
329 // Once parsing is done, do post-processing.
330 for (Record* record : records)
331 record->post(this);
332 }
333
setUseSkinning(bool skinning)334 void NIFFile::setUseSkinning(bool skinning)
335 {
336 mUseSkinning = skinning;
337 }
338
getUseSkinning() const339 bool NIFFile::getUseSkinning() const
340 {
341 return mUseSkinning;
342 }
343
344 bool NIFFile::sLoadUnsupportedFiles = false;
345
setLoadUnsupportedFiles(bool load)346 void NIFFile::setLoadUnsupportedFiles(bool load)
347 {
348 sLoadUnsupportedFiles = load;
349 }
350
351 }
352