mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-02-01 06:45:32 +00:00
Merge branch 'nifdefinitions' into 'master'
Introduce some extended NIF definitions See merge request OpenMW/openmw!319
This commit is contained in:
commit
72ab340374
15 changed files with 505 additions and 107 deletions
|
@ -244,6 +244,7 @@ namespace
|
||||||
void init(Nif::Named& value)
|
void init(Nif::Named& value)
|
||||||
{
|
{
|
||||||
value.extra = Nif::ExtraPtr(nullptr);
|
value.extra = Nif::ExtraPtr(nullptr);
|
||||||
|
value.extralist = Nif::ExtraList();
|
||||||
value.controller = Nif::ControllerPtr(nullptr);
|
value.controller = Nif::ControllerPtr(nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,13 +14,19 @@ namespace Nif
|
||||||
class Extra : public Record
|
class Extra : public Record
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
std::string name;
|
||||||
ExtraPtr next; // Next extra data record in the list
|
ExtraPtr next; // Next extra data record in the list
|
||||||
|
|
||||||
void read(NIFStream *nif)
|
void read(NIFStream *nif)
|
||||||
|
{
|
||||||
|
if (nif->getVersion() >= NIFStream::generateVersion(10,0,1,0))
|
||||||
|
name = nif->getString();
|
||||||
|
else if (nif->getVersion() <= NIFStream::generateVersion(4,2,2,0))
|
||||||
{
|
{
|
||||||
next.read(nif);
|
next.read(nif);
|
||||||
nif->getUInt(); // Size of the record
|
nif->getUInt(); // Size of the record
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void post(NIFFile *nif) { next.post(nif); }
|
void post(NIFFile *nif) { next.post(nif); }
|
||||||
};
|
};
|
||||||
|
@ -44,18 +50,23 @@ class Named : public Record
|
||||||
public:
|
public:
|
||||||
std::string name;
|
std::string name;
|
||||||
ExtraPtr extra;
|
ExtraPtr extra;
|
||||||
|
ExtraList extralist;
|
||||||
ControllerPtr controller;
|
ControllerPtr controller;
|
||||||
|
|
||||||
void read(NIFStream *nif)
|
void read(NIFStream *nif)
|
||||||
{
|
{
|
||||||
name = nif->getString();
|
name = nif->getString();
|
||||||
|
if (nif->getVersion() < NIFStream::generateVersion(10,0,1,0))
|
||||||
extra.read(nif);
|
extra.read(nif);
|
||||||
|
else
|
||||||
|
extralist.read(nif);
|
||||||
controller.read(nif);
|
controller.read(nif);
|
||||||
}
|
}
|
||||||
|
|
||||||
void post(NIFFile *nif)
|
void post(NIFFile *nif)
|
||||||
{
|
{
|
||||||
extra.post(nif);
|
extra.post(nif);
|
||||||
|
extralist.post(nif);
|
||||||
controller.post(nif);
|
controller.post(nif);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -14,16 +14,31 @@ namespace Nif
|
||||||
if (external)
|
if (external)
|
||||||
filename = nif->getString();
|
filename = nif->getString();
|
||||||
else
|
else
|
||||||
|
{
|
||||||
|
if (nif->getVersion() <= NIFStream::generateVersion(10,0,1,3))
|
||||||
internal = nif->getChar();
|
internal = nif->getChar();
|
||||||
|
if (nif->getVersion() >= NIFStream::generateVersion(10,1,0,0))
|
||||||
|
filename = nif->getString(); // Original file path of the internal texture
|
||||||
|
}
|
||||||
|
if (nif->getVersion() <= NIFStream::generateVersion(10,0,1,3))
|
||||||
|
{
|
||||||
if (!external && internal)
|
if (!external && internal)
|
||||||
data.read(nif);
|
data.read(nif);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
data.read(nif);
|
||||||
|
}
|
||||||
|
|
||||||
pixel = nif->getUInt();
|
pixel = nif->getUInt();
|
||||||
mipmap = nif->getUInt();
|
mipmap = nif->getUInt();
|
||||||
alpha = nif->getUInt();
|
alpha = nif->getUInt();
|
||||||
|
|
||||||
nif->getChar(); // always 1
|
nif->getChar(); // always 1
|
||||||
|
if (nif->getVersion() >= NIFStream::generateVersion(10,1,0,103))
|
||||||
|
nif->getBoolean(); // Direct rendering
|
||||||
|
if (nif->getVersion() >= NIFStream::generateVersion(20,2,0,4))
|
||||||
|
nif->getBoolean(); // NiPersistentSrcTextureRendererData is used instead of NiPixelData
|
||||||
}
|
}
|
||||||
|
|
||||||
void NiSourceTexture::post(NIFFile *nif)
|
void NiSourceTexture::post(NIFFile *nif)
|
||||||
|
@ -79,6 +94,12 @@ namespace Nif
|
||||||
NiParticleModifier::read(nif);
|
NiParticleModifier::read(nif);
|
||||||
|
|
||||||
mBounceFactor = nif->getFloat();
|
mBounceFactor = nif->getFloat();
|
||||||
|
if (nif->getVersion() >= NIFStream::generateVersion(4,2,2,0))
|
||||||
|
{
|
||||||
|
// Unused in NifSkope. Need to figure out what these do.
|
||||||
|
/*bool spawnOnCollision = */nif->getBoolean();
|
||||||
|
/*bool dieOnCollision = */nif->getBoolean();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void NiPlanarCollider::read(NIFStream *nif)
|
void NiPlanarCollider::read(NIFStream *nif)
|
||||||
|
|
|
@ -97,6 +97,9 @@ namespace Nif
|
||||||
// 01: Diffuse
|
// 01: Diffuse
|
||||||
// 10: Specular
|
// 10: Specular
|
||||||
// 11: Emissive
|
// 11: Emissive
|
||||||
|
if (nif->getVersion() >= NIFStream::generateVersion(10,1,0,0))
|
||||||
|
targetColor = nif->getUShort() & 3;
|
||||||
|
else
|
||||||
targetColor = (flags >> 4) & 3;
|
targetColor = (flags >> 4) & 3;
|
||||||
data.read(nif);
|
data.read(nif);
|
||||||
}
|
}
|
||||||
|
@ -110,6 +113,8 @@ namespace Nif
|
||||||
void NiLookAtController::read(NIFStream *nif)
|
void NiLookAtController::read(NIFStream *nif)
|
||||||
{
|
{
|
||||||
Controller::read(nif);
|
Controller::read(nif);
|
||||||
|
if (nif->getVersion() >= NIFStream::generateVersion(10,1,0,0))
|
||||||
|
lookAtFlags = nif->getUShort();
|
||||||
target.read(nif);
|
target.read(nif);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -192,6 +197,8 @@ namespace Nif
|
||||||
void NiGeomMorpherController::read(NIFStream *nif)
|
void NiGeomMorpherController::read(NIFStream *nif)
|
||||||
{
|
{
|
||||||
Controller::read(nif);
|
Controller::read(nif);
|
||||||
|
if (nif->getVersion() >= NIFFile::NIFVersion::VER_OB_OLD)
|
||||||
|
/*bool updateNormals = !!*/nif->getUShort();
|
||||||
data.read(nif);
|
data.read(nif);
|
||||||
if (nif->getVersion() >= NIFFile::NIFVersion::VER_MW)
|
if (nif->getVersion() >= NIFFile::NIFVersion::VER_MW)
|
||||||
/*bool alwaysActive = */nif->getChar(); // Always 0
|
/*bool alwaysActive = */nif->getChar(); // Always 0
|
||||||
|
@ -219,8 +226,11 @@ namespace Nif
|
||||||
{
|
{
|
||||||
Controller::read(nif);
|
Controller::read(nif);
|
||||||
mTexSlot = nif->getUInt();
|
mTexSlot = nif->getUInt();
|
||||||
/*unknown=*/nif->getUInt();/*0?*/
|
if (nif->getVersion() <= NIFStream::generateVersion(10,1,0,103))
|
||||||
|
{
|
||||||
|
timeStart = nif->getFloat();
|
||||||
mDelta = nif->getFloat();
|
mDelta = nif->getFloat();
|
||||||
|
}
|
||||||
mSources.read(nif);
|
mSources.read(nif);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -118,6 +118,7 @@ class NiLookAtController : public Controller
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
NodePtr target;
|
NodePtr target;
|
||||||
|
unsigned short lookAtFlags{0};
|
||||||
|
|
||||||
void read(NIFStream *nif);
|
void read(NIFStream *nif);
|
||||||
void post(NIFFile *nif);
|
void post(NIFFile *nif);
|
||||||
|
|
|
@ -33,13 +33,33 @@ void NiSkinInstance::post(NIFFile *nif)
|
||||||
|
|
||||||
void NiGeometryData::read(NIFStream *nif)
|
void NiGeometryData::read(NIFStream *nif)
|
||||||
{
|
{
|
||||||
|
if (nif->getVersion() >= NIFStream::generateVersion(10,1,0,114))
|
||||||
|
nif->getInt(); // Group ID. (Almost?) always 0.
|
||||||
|
|
||||||
int verts = nif->getUShort();
|
int verts = nif->getUShort();
|
||||||
|
|
||||||
|
if (nif->getVersion() >= NIFStream::generateVersion(10,1,0,0))
|
||||||
|
nif->skip(2); // Keep flags and compress flags
|
||||||
|
|
||||||
if (nif->getBoolean())
|
if (nif->getBoolean())
|
||||||
nif->getVector3s(vertices, verts);
|
nif->getVector3s(vertices, verts);
|
||||||
|
|
||||||
|
unsigned int dataFlags = 0;
|
||||||
|
if (nif->getVersion() >= NIFStream::generateVersion(10,0,1,0))
|
||||||
|
dataFlags = nif->getUShort();
|
||||||
|
|
||||||
|
if (nif->getVersion() == NIFFile::NIFVersion::VER_BGS && nif->getBethVersion() > NIFFile::BethVersion::BETHVER_FO3)
|
||||||
|
nif->getUInt(); // Material CRC
|
||||||
|
|
||||||
if (nif->getBoolean())
|
if (nif->getBoolean())
|
||||||
|
{
|
||||||
nif->getVector3s(normals, verts);
|
nif->getVector3s(normals, verts);
|
||||||
|
if (dataFlags & 0x1000)
|
||||||
|
{
|
||||||
|
nif->getVector3s(tangents, verts);
|
||||||
|
nif->getVector3s(bitangents, verts);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
center = nif->getVector3();
|
center = nif->getVector3();
|
||||||
radius = nif->getFloat();
|
radius = nif->getFloat();
|
||||||
|
@ -47,14 +67,27 @@ void NiGeometryData::read(NIFStream *nif)
|
||||||
if (nif->getBoolean())
|
if (nif->getBoolean())
|
||||||
nif->getVector4s(colors, verts);
|
nif->getVector4s(colors, verts);
|
||||||
|
|
||||||
|
// Only the first 6 bits are used as a count. I think the rest are
|
||||||
|
// flags of some sort.
|
||||||
|
unsigned int numUVs = dataFlags;
|
||||||
|
if (nif->getVersion() <= NIFStream::generateVersion(4,2,2,0))
|
||||||
|
{
|
||||||
|
numUVs = nif->getUShort();
|
||||||
// In Morrowind this field only corresponds to the number of UV sets.
|
// In Morrowind this field only corresponds to the number of UV sets.
|
||||||
// NifTools research is inaccurate.
|
// NifTools research is inaccurate.
|
||||||
int uvs = nif->getUShort();
|
if (nif->getVersion() > NIFFile::NIFVersion::VER_MW)
|
||||||
|
numUVs &= 0x3f;
|
||||||
|
}
|
||||||
|
if (nif->getVersion() == NIFFile::NIFVersion::VER_BGS && nif->getBethVersion() > 0)
|
||||||
|
numUVs &= 0x1;
|
||||||
|
|
||||||
if(nif->getInt())
|
bool hasUVs = true;
|
||||||
|
if (nif->getVersion() <= NIFFile::NIFVersion::VER_MW)
|
||||||
|
hasUVs = nif->getBoolean();
|
||||||
|
if (hasUVs)
|
||||||
{
|
{
|
||||||
uvlist.resize(uvs);
|
uvlist.resize(numUVs);
|
||||||
for(int i = 0;i < uvs;i++)
|
for (unsigned int i = 0; i < numUVs; i++)
|
||||||
{
|
{
|
||||||
nif->getVector2s(uvlist[i], verts);
|
nif->getVector2s(uvlist[i], verts);
|
||||||
// flip the texture coordinates to convert them to the OpenGL convention of bottom-left image origin
|
// flip the texture coordinates to convert them to the OpenGL convention of bottom-left image origin
|
||||||
|
@ -64,6 +97,12 @@ void NiGeometryData::read(NIFStream *nif)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (nif->getVersion() >= NIFStream::generateVersion(10,0,1,0))
|
||||||
|
nif->getUShort(); // Consistency flags
|
||||||
|
|
||||||
|
if (nif->getVersion() >= NIFStream::generateVersion(20,0,0,4))
|
||||||
|
nif->skip(4); // Additional data
|
||||||
}
|
}
|
||||||
|
|
||||||
void NiTriShapeData::read(NIFStream *nif)
|
void NiTriShapeData::read(NIFStream *nif)
|
||||||
|
@ -75,13 +114,17 @@ void NiTriShapeData::read(NIFStream *nif)
|
||||||
// We have three times as many vertices as triangles, so this
|
// We have three times as many vertices as triangles, so this
|
||||||
// is always equal to tris*3.
|
// is always equal to tris*3.
|
||||||
int cnt = nif->getInt();
|
int cnt = nif->getInt();
|
||||||
|
bool hasTriangles = true;
|
||||||
|
if (nif->getVersion() > NIFFile::NIFVersion::VER_OB_OLD)
|
||||||
|
hasTriangles = nif->getBoolean();
|
||||||
|
if (hasTriangles)
|
||||||
nif->getUShorts(triangles, cnt);
|
nif->getUShorts(triangles, cnt);
|
||||||
|
|
||||||
// Read the match list, which lists the vertices that are equal to
|
// Read the match list, which lists the vertices that are equal to
|
||||||
// vertices. We don't actually need need this for anything, so
|
// vertices. We don't actually need need this for anything, so
|
||||||
// just skip it.
|
// just skip it.
|
||||||
int verts = nif->getUShort();
|
unsigned short verts = nif->getUShort();
|
||||||
for(int i=0;i < verts;i++)
|
for (unsigned short i=0; i < verts; i++)
|
||||||
{
|
{
|
||||||
// Number of vertices matching vertex 'i'
|
// Number of vertices matching vertex 'i'
|
||||||
int num = nif->getUShort();
|
int num = nif->getUShort();
|
||||||
|
@ -101,7 +144,11 @@ void NiTriStripsData::read(NIFStream *nif)
|
||||||
std::vector<unsigned short> lengths;
|
std::vector<unsigned short> lengths;
|
||||||
nif->getUShorts(lengths, numStrips);
|
nif->getUShorts(lengths, numStrips);
|
||||||
|
|
||||||
if (!numStrips)
|
// "Has Strips" flag. Exceptionally useful.
|
||||||
|
bool hasStrips = false;
|
||||||
|
if (nif->getVersion() > NIFFile::NIFVersion::VER_OB_OLD)
|
||||||
|
hasStrips = nif->getBoolean();
|
||||||
|
if (!hasStrips || !numStrips)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
strips.resize(numStrips);
|
strips.resize(numStrips);
|
||||||
|
@ -140,28 +187,38 @@ void NiAutoNormalParticlesData::read(NIFStream *nif)
|
||||||
NiGeometryData::read(nif);
|
NiGeometryData::read(nif);
|
||||||
|
|
||||||
// Should always match the number of vertices
|
// Should always match the number of vertices
|
||||||
|
if (nif->getVersion() <= NIFFile::NIFVersion::VER_MW)
|
||||||
numParticles = nif->getUShort();
|
numParticles = nif->getUShort();
|
||||||
|
|
||||||
particleRadius = nif->getFloat();
|
if (nif->getVersion() <= NIFStream::generateVersion(10,0,1,0))
|
||||||
|
std::fill(particleRadii.begin(), particleRadii.end(), nif->getFloat());
|
||||||
|
else if (nif->getBoolean())
|
||||||
|
nif->getFloats(particleRadii, vertices.size());
|
||||||
activeCount = nif->getUShort();
|
activeCount = nif->getUShort();
|
||||||
|
|
||||||
if (nif->getBoolean())
|
|
||||||
{
|
|
||||||
// Particle sizes
|
// Particle sizes
|
||||||
|
if (nif->getBoolean())
|
||||||
nif->getFloats(sizes, vertices.size());
|
nif->getFloats(sizes, vertices.size());
|
||||||
|
|
||||||
|
if (nif->getVersion() >= NIFStream::generateVersion(10,0,1,0) && nif->getBoolean())
|
||||||
|
nif->getQuaternions(rotations, vertices.size());
|
||||||
|
if (nif->getVersion() >= NIFStream::generateVersion(20,0,0,4))
|
||||||
|
{
|
||||||
|
if (nif->getBoolean())
|
||||||
|
nif->getFloats(rotationAngles, vertices.size());
|
||||||
|
if (nif->getBoolean())
|
||||||
|
nif->getVector3s(rotationAxes, vertices.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void NiRotatingParticlesData::read(NIFStream *nif)
|
void NiRotatingParticlesData::read(NIFStream *nif)
|
||||||
{
|
{
|
||||||
NiAutoNormalParticlesData::read(nif);
|
NiAutoNormalParticlesData::read(nif);
|
||||||
|
|
||||||
if (nif->getBoolean())
|
if (nif->getVersion() <= NIFStream::generateVersion(4,2,2,0) && nif->getBoolean())
|
||||||
{
|
|
||||||
// Rotation quaternions.
|
|
||||||
nif->getQuaternions(rotations, vertices.size());
|
nif->getQuaternions(rotations, vertices.size());
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void NiPosData::read(NIFStream *nif)
|
void NiPosData::read(NIFStream *nif)
|
||||||
{
|
{
|
||||||
|
@ -188,12 +245,27 @@ void NiPixelData::read(NIFStream *nif)
|
||||||
{
|
{
|
||||||
fmt = (Format)nif->getUInt();
|
fmt = (Format)nif->getUInt();
|
||||||
|
|
||||||
|
if (nif->getVersion() < NIFStream::generateVersion(10,4,0,2))
|
||||||
|
{
|
||||||
for (unsigned int i = 0; i < 4; ++i)
|
for (unsigned int i = 0; i < 4; ++i)
|
||||||
colorMask[i] = nif->getUInt();
|
colorMask[i] = nif->getUInt();
|
||||||
bpp = nif->getUInt();
|
bpp = nif->getUInt();
|
||||||
|
nif->skip(8); // "Old Fast Compare". Whatever that means.
|
||||||
|
if (nif->getVersion() >= NIFStream::generateVersion(10,1,0,0))
|
||||||
|
pixelTiling = nif->getUInt();
|
||||||
|
}
|
||||||
|
else // TODO: see if anything from here needs to be implemented
|
||||||
|
{
|
||||||
|
bpp = nif->getChar();
|
||||||
|
nif->skip(4); // Renderer hint
|
||||||
|
nif->skip(4); // Extra data
|
||||||
|
nif->skip(4); // Flags
|
||||||
|
pixelTiling = nif->getUInt();
|
||||||
|
if (nif->getVersion() >= NIFStream::generateVersion(20,3,0,4))
|
||||||
|
sRGB = nif->getBoolean();
|
||||||
|
nif->skip(4*10); // Channel data
|
||||||
|
}
|
||||||
|
|
||||||
// 8 bytes of "Old Fast Compare". Whatever that means.
|
|
||||||
nif->skip(8);
|
|
||||||
palette.read(nif);
|
palette.read(nif);
|
||||||
|
|
||||||
numberOfMipmaps = nif->getUInt();
|
numberOfMipmaps = nif->getUInt();
|
||||||
|
@ -213,8 +285,10 @@ void NiPixelData::read(NIFStream *nif)
|
||||||
|
|
||||||
// Read the data
|
// Read the data
|
||||||
unsigned int numPixels = nif->getUInt();
|
unsigned int numPixels = nif->getUInt();
|
||||||
if (numPixels)
|
bool hasFaces = nif->getVersion() >= NIFStream::generateVersion(10,4,0,2);
|
||||||
nif->getUChars(data, numPixels);
|
unsigned int numFaces = hasFaces ? nif->getUInt() : 1;
|
||||||
|
if (numPixels && numFaces)
|
||||||
|
nif->getUChars(data, numPixels * numFaces);
|
||||||
}
|
}
|
||||||
|
|
||||||
void NiPixelData::post(NIFFile *nif)
|
void NiPixelData::post(NIFFile *nif)
|
||||||
|
@ -249,6 +323,10 @@ void NiSkinData::read(NIFStream *nif)
|
||||||
if (nif->getVersion() >= NIFFile::NIFVersion::VER_MW && nif->getVersion() <= NIFStream::generateVersion(10,1,0,0))
|
if (nif->getVersion() >= NIFFile::NIFVersion::VER_MW && nif->getVersion() <= NIFStream::generateVersion(10,1,0,0))
|
||||||
nif->skip(4); // NiSkinPartition link
|
nif->skip(4); // NiSkinPartition link
|
||||||
|
|
||||||
|
// Has vertex weights flag
|
||||||
|
if (nif->getVersion() > NIFStream::generateVersion(4,2,1,0) && !nif->getBoolean())
|
||||||
|
return;
|
||||||
|
|
||||||
bones.resize(boneNum);
|
bones.resize(boneNum);
|
||||||
for (BoneInfo &bi : bones)
|
for (BoneInfo &bi : bones)
|
||||||
{
|
{
|
||||||
|
@ -272,7 +350,7 @@ void NiMorphData::read(NIFStream *nif)
|
||||||
{
|
{
|
||||||
int morphCount = nif->getInt();
|
int morphCount = nif->getInt();
|
||||||
int vertCount = nif->getInt();
|
int vertCount = nif->getInt();
|
||||||
/*relative targets?*/nif->getChar();
|
nif->getChar(); // Relative targets, always 1
|
||||||
|
|
||||||
mMorphs.resize(morphCount);
|
mMorphs.resize(morphCount);
|
||||||
for(int i = 0;i < morphCount;i++)
|
for(int i = 0;i < morphCount;i++)
|
||||||
|
@ -290,6 +368,7 @@ void NiKeyframeData::read(NIFStream *nif)
|
||||||
if(mRotations->mInterpolationType == InterpolationType_XYZ)
|
if(mRotations->mInterpolationType == InterpolationType_XYZ)
|
||||||
{
|
{
|
||||||
//Chomp unused float
|
//Chomp unused float
|
||||||
|
if (nif->getVersion() <= NIFStream::generateVersion(10,1,0,0))
|
||||||
nif->getFloat();
|
nif->getFloat();
|
||||||
mXRotations = std::make_shared<FloatKeyMap>();
|
mXRotations = std::make_shared<FloatKeyMap>();
|
||||||
mYRotations = std::make_shared<FloatKeyMap>();
|
mYRotations = std::make_shared<FloatKeyMap>();
|
||||||
|
|
|
@ -35,7 +35,7 @@ namespace Nif
|
||||||
class NiGeometryData : public Record
|
class NiGeometryData : public Record
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
std::vector<osg::Vec3f> vertices, normals;
|
std::vector<osg::Vec3f> vertices, normals, tangents, bitangents;
|
||||||
std::vector<osg::Vec4f> colors;
|
std::vector<osg::Vec4f> colors;
|
||||||
std::vector< std::vector<osg::Vec2f> > uvlist;
|
std::vector< std::vector<osg::Vec2f> > uvlist;
|
||||||
osg::Vec3f center;
|
osg::Vec3f center;
|
||||||
|
@ -73,13 +73,15 @@ struct NiLinesData : public NiGeometryData
|
||||||
class NiAutoNormalParticlesData : public NiGeometryData
|
class NiAutoNormalParticlesData : public NiGeometryData
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
int numParticles;
|
int numParticles{0};
|
||||||
|
|
||||||
float particleRadius;
|
float particleRadius;
|
||||||
|
|
||||||
int activeCount;
|
int activeCount;
|
||||||
|
|
||||||
std::vector<float> sizes;
|
std::vector<float> particleRadii, sizes, rotationAngles;
|
||||||
|
std::vector<osg::Quat> rotations;
|
||||||
|
std::vector<osg::Vec3f> rotationAxes;
|
||||||
|
|
||||||
void read(NIFStream *nif);
|
void read(NIFStream *nif);
|
||||||
};
|
};
|
||||||
|
@ -87,8 +89,6 @@ public:
|
||||||
class NiRotatingParticlesData : public NiAutoNormalParticlesData
|
class NiRotatingParticlesData : public NiAutoNormalParticlesData
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
std::vector<osg::Quat> rotations;
|
|
||||||
|
|
||||||
void read(NIFStream *nif);
|
void read(NIFStream *nif);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -133,7 +133,8 @@ public:
|
||||||
Format fmt;
|
Format fmt;
|
||||||
|
|
||||||
unsigned int colorMask[4];
|
unsigned int colorMask[4];
|
||||||
unsigned int bpp;
|
unsigned int bpp, pixelTiling{0};
|
||||||
|
bool sRGB{false};
|
||||||
|
|
||||||
NiPalettePtr palette;
|
NiPalettePtr palette;
|
||||||
unsigned int numberOfMipmaps;
|
unsigned int numberOfMipmaps;
|
||||||
|
|
|
@ -28,6 +28,10 @@ void NiTextureEffect::read(NIFStream *nif)
|
||||||
// Texture Filtering
|
// Texture Filtering
|
||||||
nif->skip(4);
|
nif->skip(4);
|
||||||
|
|
||||||
|
// Max anisotropy samples
|
||||||
|
if (nif->getVersion() >= NIFStream::generateVersion(20,5,0,4))
|
||||||
|
nif->skip(2);
|
||||||
|
|
||||||
clamp = nif->getUInt();
|
clamp = nif->getUInt();
|
||||||
|
|
||||||
textureType = (TextureType)nif->getUInt();
|
textureType = (TextureType)nif->getUInt();
|
||||||
|
@ -36,14 +40,12 @@ void NiTextureEffect::read(NIFStream *nif)
|
||||||
|
|
||||||
texture.read(nif);
|
texture.read(nif);
|
||||||
|
|
||||||
/*
|
nif->skip(1); // Use clipping plane
|
||||||
byte = 0
|
nif->skip(16); // Clipping plane dimensions vector
|
||||||
vector4 = [1,0,0,0]
|
if (nif->getVersion() <= NIFStream::generateVersion(10,2,0,0))
|
||||||
short = 0
|
nif->skip(4); // PS2-specific shorts
|
||||||
short = -75
|
if (nif->getVersion() <= NIFStream::generateVersion(4,1,0,12))
|
||||||
short = 0
|
nif->skip(2); // Unknown short
|
||||||
*/
|
|
||||||
nif->skip(23);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void NiTextureEffect::post(NIFFile *nif)
|
void NiTextureEffect::post(NIFFile *nif)
|
||||||
|
|
|
@ -34,6 +34,9 @@ struct NiDynamicEffect : public Node
|
||||||
void read(NIFStream *nif)
|
void read(NIFStream *nif)
|
||||||
{
|
{
|
||||||
Node::read(nif);
|
Node::read(nif);
|
||||||
|
if (nif->getVersion() >= nif->generateVersion(10,1,0,106)
|
||||||
|
&& nif->getBethVersion() < NIFFile::BethVersion::BETHVER_FO4)
|
||||||
|
nif->getBoolean(); // Switch state
|
||||||
unsigned int numAffectedNodes = nif->getUInt();
|
unsigned int numAffectedNodes = nif->getUInt();
|
||||||
for (unsigned int i=0; i<numAffectedNodes; ++i)
|
for (unsigned int i=0; i<numAffectedNodes; ++i)
|
||||||
nif->getUInt(); // ref to another Node
|
nif->getUInt(); // ref to another Node
|
||||||
|
|
|
@ -139,15 +139,77 @@ void NIFFile::parse(Files::IStreamPtr stream)
|
||||||
// It's not used by Morrowind assets but Morrowind supports it.
|
// It's not used by Morrowind assets but Morrowind supports it.
|
||||||
if(ver != NIFStream::generateVersion(4,0,0,0) && ver != VER_MW)
|
if(ver != NIFStream::generateVersion(4,0,0,0) && ver != VER_MW)
|
||||||
fail("Unsupported NIF version: " + printVersion(ver));
|
fail("Unsupported NIF version: " + printVersion(ver));
|
||||||
|
|
||||||
|
// NIF data endianness
|
||||||
|
if (ver >= NIFStream::generateVersion(20,0,0,4))
|
||||||
|
{
|
||||||
|
unsigned char endianness = nif.getChar();
|
||||||
|
if (endianness == 0)
|
||||||
|
fail("Big endian NIF files are unsupported");
|
||||||
|
}
|
||||||
|
|
||||||
|
// User version
|
||||||
|
if (ver > NIFStream::generateVersion(10,0,1,8))
|
||||||
|
userVer = nif.getUInt();
|
||||||
|
|
||||||
// Number of records
|
// Number of records
|
||||||
size_t recNum = nif.getUInt();
|
size_t recNum = nif.getUInt();
|
||||||
records.resize(recNum);
|
records.resize(recNum);
|
||||||
|
|
||||||
|
// Bethesda stream header
|
||||||
|
// It contains Bethesda format version and (useless) export information
|
||||||
|
if (ver == VER_OB_OLD ||
|
||||||
|
(userVer >= 3 && ((ver == VER_OB || ver == VER_BGS)
|
||||||
|
|| (ver >= NIFStream::generateVersion(10,1,0,0) && ver <= NIFStream::generateVersion(20,0,0,4) && userVer <= 11))))
|
||||||
|
{
|
||||||
|
bethVer = nif.getUInt();
|
||||||
|
nif.getExportString(); // Author
|
||||||
|
if (bethVer > BETHVER_FO4)
|
||||||
|
nif.getUInt(); // Unknown
|
||||||
|
nif.getExportString(); // Process script
|
||||||
|
nif.getExportString(); // Export script
|
||||||
|
if (bethVer == BETHVER_FO4)
|
||||||
|
nif.getExportString(); // Max file path
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> recTypes;
|
||||||
|
std::vector<unsigned short> recTypeIndices;
|
||||||
|
|
||||||
|
const bool hasRecTypeListings = ver >= NIFStream::generateVersion(5,0,0,1);
|
||||||
|
if (hasRecTypeListings)
|
||||||
|
{
|
||||||
|
unsigned short recTypeNum = nif.getUShort();
|
||||||
|
if (recTypeNum) // Record type list
|
||||||
|
nif.getSizedStrings(recTypes, recTypeNum);
|
||||||
|
if (recNum) // Record type mapping for each record
|
||||||
|
nif.getUShorts(recTypeIndices, recNum);
|
||||||
|
if (ver >= NIFStream::generateVersion(5,0,0,6)) // Groups
|
||||||
|
{
|
||||||
|
if (ver >= NIFStream::generateVersion(20,1,0,1)) // String table
|
||||||
|
{
|
||||||
|
if (ver >= NIFStream::generateVersion(20,2,0,5) && recNum) // Record sizes
|
||||||
|
{
|
||||||
|
std::vector<unsigned int> recSizes; // Currently unused
|
||||||
|
nif.getUInts(recSizes, recNum);
|
||||||
|
}
|
||||||
|
unsigned int stringNum = nif.getUInt();
|
||||||
|
nif.getUInt(); // Max string length
|
||||||
|
if (stringNum)
|
||||||
|
nif.getSizedStrings(strings, stringNum);
|
||||||
|
}
|
||||||
|
std::vector<unsigned int> groups; // Currently unused
|
||||||
|
unsigned int groupNum = nif.getUInt();
|
||||||
|
if (groupNum)
|
||||||
|
nif.getUInts(groups, groupNum);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const bool hasRecordSeparators = ver >= NIFStream::generateVersion(10,0,0,0) && ver < NIFStream::generateVersion(10,2,0,0);
|
||||||
for(size_t i = 0;i < recNum;i++)
|
for(size_t i = 0;i < recNum;i++)
|
||||||
{
|
{
|
||||||
Record *r = nullptr;
|
Record *r = nullptr;
|
||||||
|
|
||||||
std::string rec = nif.getString();
|
std::string rec = hasRecTypeListings ? recTypes[recTypeIndices[i]] : nif.getString();
|
||||||
if(rec.empty())
|
if(rec.empty())
|
||||||
{
|
{
|
||||||
std::stringstream error;
|
std::stringstream error;
|
||||||
|
@ -155,6 +217,17 @@ void NIFFile::parse(Files::IStreamPtr stream)
|
||||||
fail(error.str());
|
fail(error.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Record separator. Some Havok records in Oblivion do not have it.
|
||||||
|
if (hasRecordSeparators && rec.compare(0, 3, "bhk"))
|
||||||
|
{
|
||||||
|
if (nif.getInt())
|
||||||
|
{
|
||||||
|
std::stringstream warning;
|
||||||
|
warning << "Record number " << i << " out of " << recNum << " is preceded by a non-zero separator.";
|
||||||
|
warn(warning.str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
std::map<std::string,RecordFactoryEntry>::const_iterator entry = factories.find(rec);
|
std::map<std::string,RecordFactoryEntry>::const_iterator entry = factories.find(rec);
|
||||||
|
|
||||||
if (entry != factories.end())
|
if (entry != factories.end())
|
||||||
|
|
|
@ -25,18 +25,19 @@ namespace Nif
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
///Currently specific for 4.0.0.2 and earlier
|
///Booleans in 4.0.0.2 (Morrowind format) and earlier are 4 byte, while in 4.1.0.0+ they're 1 byte.
|
||||||
bool NIFStream::getBoolean()
|
bool NIFStream::getBoolean()
|
||||||
{
|
{
|
||||||
return getInt() != 0;
|
return getVersion() < generateVersion(4,1,0,0) ? getInt() != 0 : getChar() != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
///Read in a string, either from the string table using the index (currently absent) or from the stream using the specified length
|
///Read in a string, either from the string table using the index or from the stream using the specified length
|
||||||
std::string NIFStream::getString()
|
std::string NIFStream::getString()
|
||||||
{
|
{
|
||||||
return getSizedString();
|
return getVersion() < generateVersion(20,1,0,1) ? getSizedString() : file->getString(getUInt());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Convenience utility functions: get the versions of the currently read file
|
// Convenience utility functions: get the versions of the currently read file
|
||||||
unsigned int NIFStream::getVersion() const { return file->getVersion(); }
|
unsigned int NIFStream::getVersion() const { return file->getVersion(); }
|
||||||
unsigned int NIFStream::getUserVersion() const { return file->getBethVersion(); }
|
unsigned int NIFStream::getUserVersion() const { return file->getBethVersion(); }
|
||||||
|
|
|
@ -30,7 +30,7 @@ public:
|
||||||
PropertyList props;
|
PropertyList props;
|
||||||
|
|
||||||
// Bounding box info
|
// Bounding box info
|
||||||
bool hasBounds;
|
bool hasBounds{false};
|
||||||
osg::Vec3f boundPos;
|
osg::Vec3f boundPos;
|
||||||
Matrix3 boundRot;
|
Matrix3 boundRot;
|
||||||
osg::Vec3f boundXYZ; // Box size
|
osg::Vec3f boundXYZ; // Box size
|
||||||
|
@ -39,11 +39,14 @@ public:
|
||||||
{
|
{
|
||||||
Named::read(nif);
|
Named::read(nif);
|
||||||
|
|
||||||
flags = nif->getUShort();
|
flags = nif->getBethVersion() <= 26 ? nif->getUShort() : nif->getUInt();
|
||||||
trafo = nif->getTrafo();
|
trafo = nif->getTrafo();
|
||||||
|
if (nif->getVersion() <= NIFStream::generateVersion(4,2,2,0))
|
||||||
velocity = nif->getVector3();
|
velocity = nif->getVector3();
|
||||||
|
if (nif->getBethVersion() <= NIFFile::BethVersion::BETHVER_FO3)
|
||||||
props.read(nif);
|
props.read(nif);
|
||||||
|
|
||||||
|
if (nif->getVersion() <= NIFStream::generateVersion(4,2,2,0))
|
||||||
hasBounds = nif->getBoolean();
|
hasBounds = nif->getBoolean();
|
||||||
if(hasBounds)
|
if(hasBounds)
|
||||||
{
|
{
|
||||||
|
@ -52,6 +55,9 @@ public:
|
||||||
boundRot = nif->getMatrix3();
|
boundRot = nif->getMatrix3();
|
||||||
boundXYZ = nif->getVector3();
|
boundXYZ = nif->getVector3();
|
||||||
}
|
}
|
||||||
|
// Reference to the collision object in Gamebryo files.
|
||||||
|
if (nif->getVersion() >= NIFStream::generateVersion(10,0,1,0))
|
||||||
|
nif->skip(4);
|
||||||
|
|
||||||
parent = nullptr;
|
parent = nullptr;
|
||||||
|
|
||||||
|
@ -102,6 +108,7 @@ struct NiNode : Node
|
||||||
{
|
{
|
||||||
Node::read(nif);
|
Node::read(nif);
|
||||||
children.read(nif);
|
children.read(nif);
|
||||||
|
if (nif->getBethVersion() < NIFFile::BethVersion::BETHVER_FO4)
|
||||||
effects.read(nif);
|
effects.read(nif);
|
||||||
|
|
||||||
// Discard transformations for the root node, otherwise some meshes
|
// Discard transformations for the root node, otherwise some meshes
|
||||||
|
@ -130,7 +137,39 @@ struct NiNode : Node
|
||||||
|
|
||||||
struct NiGeometry : Node
|
struct NiGeometry : Node
|
||||||
{
|
{
|
||||||
|
struct MaterialData
|
||||||
|
{
|
||||||
|
std::vector<std::string> materialNames;
|
||||||
|
std::vector<int> materialExtraData;
|
||||||
|
unsigned int activeMaterial{0};
|
||||||
|
bool materialNeedsUpdate{false};
|
||||||
|
void read(NIFStream *nif)
|
||||||
|
{
|
||||||
|
if (nif->getVersion() <= NIFStream::generateVersion(10,0,1,0))
|
||||||
|
return;
|
||||||
|
unsigned int numMaterials = 0;
|
||||||
|
if (nif->getVersion() <= NIFStream::generateVersion(20,1,0,3))
|
||||||
|
numMaterials = nif->getBoolean(); // Has Shader
|
||||||
|
else if (nif->getVersion() >= NIFStream::generateVersion(20,2,0,5))
|
||||||
|
numMaterials = nif->getUInt();
|
||||||
|
if (numMaterials)
|
||||||
|
{
|
||||||
|
nif->getStrings(materialNames, numMaterials);
|
||||||
|
nif->getInts(materialExtraData, numMaterials);
|
||||||
|
}
|
||||||
|
if (nif->getVersion() >= NIFStream::generateVersion(20,2,0,5))
|
||||||
|
activeMaterial = nif->getUInt();
|
||||||
|
if (nif->getVersion() >= NIFFile::NIFVersion::VER_BGS)
|
||||||
|
{
|
||||||
|
materialNeedsUpdate = nif->getBoolean();
|
||||||
|
if (nif->getVersion() == NIFFile::NIFVersion::VER_BGS && nif->getBethVersion() > NIFFile::BethVersion::BETHVER_FO3)
|
||||||
|
nif->skip(8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
NiSkinInstancePtr skin;
|
NiSkinInstancePtr skin;
|
||||||
|
MaterialData materialData;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct NiTriShape : NiGeometry
|
struct NiTriShape : NiGeometry
|
||||||
|
@ -149,6 +188,7 @@ struct NiTriShape : NiGeometry
|
||||||
Node::read(nif);
|
Node::read(nif);
|
||||||
data.read(nif);
|
data.read(nif);
|
||||||
skin.read(nif);
|
skin.read(nif);
|
||||||
|
materialData.read(nif);
|
||||||
}
|
}
|
||||||
|
|
||||||
void post(NIFFile *nif)
|
void post(NIFFile *nif)
|
||||||
|
@ -170,6 +210,7 @@ struct NiTriStrips : NiGeometry
|
||||||
Node::read(nif);
|
Node::read(nif);
|
||||||
data.read(nif);
|
data.read(nif);
|
||||||
skin.read(nif);
|
skin.read(nif);
|
||||||
|
materialData.read(nif);
|
||||||
}
|
}
|
||||||
|
|
||||||
void post(NIFFile *nif)
|
void post(NIFFile *nif)
|
||||||
|
@ -207,6 +248,8 @@ struct NiCamera : Node
|
||||||
{
|
{
|
||||||
struct Camera
|
struct Camera
|
||||||
{
|
{
|
||||||
|
unsigned short cameraFlags{0};
|
||||||
|
|
||||||
// Camera frustrum
|
// Camera frustrum
|
||||||
float left, right, top, bottom, nearDist, farDist;
|
float left, right, top, bottom, nearDist, farDist;
|
||||||
|
|
||||||
|
@ -216,15 +259,21 @@ struct NiCamera : Node
|
||||||
// Level of detail modifier
|
// Level of detail modifier
|
||||||
float LOD;
|
float LOD;
|
||||||
|
|
||||||
|
// Orthographic projection usage flag
|
||||||
|
bool orthographic{false};
|
||||||
|
|
||||||
void read(NIFStream *nif)
|
void read(NIFStream *nif)
|
||||||
{
|
{
|
||||||
|
if (nif->getVersion() >= NIFStream::generateVersion(10,1,0,0))
|
||||||
|
cameraFlags = nif->getUShort();
|
||||||
left = nif->getFloat();
|
left = nif->getFloat();
|
||||||
right = nif->getFloat();
|
right = nif->getFloat();
|
||||||
top = nif->getFloat();
|
top = nif->getFloat();
|
||||||
bottom = nif->getFloat();
|
bottom = nif->getFloat();
|
||||||
nearDist = nif->getFloat();
|
nearDist = nif->getFloat();
|
||||||
farDist = nif->getFloat();
|
farDist = nif->getFloat();
|
||||||
|
if (nif->getVersion() >= NIFStream::generateVersion(10,1,0,0))
|
||||||
|
orthographic = nif->getBoolean();
|
||||||
vleft = nif->getFloat();
|
vleft = nif->getFloat();
|
||||||
vright = nif->getFloat();
|
vright = nif->getFloat();
|
||||||
vtop = nif->getFloat();
|
vtop = nif->getFloat();
|
||||||
|
@ -243,6 +292,8 @@ struct NiCamera : Node
|
||||||
|
|
||||||
nif->getInt(); // -1
|
nif->getInt(); // -1
|
||||||
nif->getInt(); // 0
|
nif->getInt(); // 0
|
||||||
|
if (nif->getVersion() >= NIFStream::generateVersion(4,2,1,0))
|
||||||
|
nif->getInt(); // 0
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -285,11 +336,14 @@ struct NiRotatingParticles : Node
|
||||||
// A node used as the base to switch between child nodes, such as for LOD levels.
|
// A node used as the base to switch between child nodes, such as for LOD levels.
|
||||||
struct NiSwitchNode : public NiNode
|
struct NiSwitchNode : public NiNode
|
||||||
{
|
{
|
||||||
|
unsigned int switchFlags{0};
|
||||||
unsigned int initialIndex;
|
unsigned int initialIndex;
|
||||||
|
|
||||||
void read(NIFStream *nif)
|
void read(NIFStream *nif)
|
||||||
{
|
{
|
||||||
NiNode::read(nif);
|
NiNode::read(nif);
|
||||||
|
if (nif->getVersion() >= NIFStream::generateVersion(10,1,0,0))
|
||||||
|
switchFlags = nif->getUShort();
|
||||||
initialIndex = nif->getUInt();
|
initialIndex = nif->getUInt();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -310,6 +364,12 @@ struct NiLODNode : public NiSwitchNode
|
||||||
NiSwitchNode::read(nif);
|
NiSwitchNode::read(nif);
|
||||||
if (nif->getVersion() >= NIFFile::NIFVersion::VER_MW && nif->getVersion() <= NIFStream::generateVersion(10,0,1,0))
|
if (nif->getVersion() >= NIFFile::NIFVersion::VER_MW && nif->getVersion() <= NIFStream::generateVersion(10,0,1,0))
|
||||||
lodCenter = nif->getVector3();
|
lodCenter = nif->getVector3();
|
||||||
|
else if (nif->getVersion() > NIFStream::generateVersion(10,0,1,0))
|
||||||
|
{
|
||||||
|
nif->skip(4); // NiLODData, unsupported at the moment
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
unsigned int numLodLevels = nif->getUInt();
|
unsigned int numLodLevels = nif->getUInt();
|
||||||
for (unsigned int i=0; i<numLodLevels; ++i)
|
for (unsigned int i=0; i<numLodLevels; ++i)
|
||||||
{
|
{
|
||||||
|
|
|
@ -6,25 +6,44 @@
|
||||||
namespace Nif
|
namespace Nif
|
||||||
{
|
{
|
||||||
|
|
||||||
void Property::read(NIFStream *nif)
|
|
||||||
{
|
|
||||||
Named::read(nif);
|
|
||||||
flags = nif->getUShort();
|
|
||||||
}
|
|
||||||
|
|
||||||
void NiTexturingProperty::Texture::read(NIFStream *nif)
|
void NiTexturingProperty::Texture::read(NIFStream *nif)
|
||||||
{
|
{
|
||||||
inUse = nif->getBoolean();
|
inUse = nif->getBoolean();
|
||||||
if(!inUse) return;
|
if(!inUse) return;
|
||||||
|
|
||||||
texture.read(nif);
|
texture.read(nif);
|
||||||
clamp = nif->getUInt();
|
if (nif->getVersion() <= NIFFile::NIFVersion::VER_OB)
|
||||||
|
{
|
||||||
|
clamp = nif->getInt();
|
||||||
nif->skip(4); // Filter mode. Ignoring because global filtering settings are more sensible
|
nif->skip(4); // Filter mode. Ignoring because global filtering settings are more sensible
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
clamp = nif->getUShort() & 0xF;
|
||||||
|
}
|
||||||
|
// Max anisotropy. I assume we'll always only use the global anisotropy setting.
|
||||||
|
if (nif->getVersion() >= NIFStream::generateVersion(20,5,0,4))
|
||||||
|
nif->getUShort();
|
||||||
|
|
||||||
|
if (nif->getVersion() <= NIFFile::NIFVersion::VER_OB)
|
||||||
uvSet = nif->getUInt();
|
uvSet = nif->getUInt();
|
||||||
|
|
||||||
// Two PS2-specific shorts.
|
// Two PS2-specific shorts.
|
||||||
|
if (nif->getVersion() < NIFStream::generateVersion(10,4,0,2))
|
||||||
nif->skip(4);
|
nif->skip(4);
|
||||||
|
if (nif->getVersion() <= NIFStream::generateVersion(4,1,0,18))
|
||||||
nif->skip(2); // Unknown short
|
nif->skip(2); // Unknown short
|
||||||
|
else if (nif->getVersion() >= NIFStream::generateVersion(10,1,0,0))
|
||||||
|
{
|
||||||
|
if (nif->getBoolean()) // Has texture transform
|
||||||
|
{
|
||||||
|
nif->getVector2(); // UV translation
|
||||||
|
nif->getVector2(); // UV scale
|
||||||
|
nif->getFloat(); // W axis rotation
|
||||||
|
nif->getUInt(); // Transform method
|
||||||
|
nif->getVector2(); // Texture rotation origin
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void NiTexturingProperty::Texture::post(NIFFile *nif)
|
void NiTexturingProperty::Texture::post(NIFFile *nif)
|
||||||
|
@ -35,6 +54,9 @@ void NiTexturingProperty::Texture::post(NIFFile *nif)
|
||||||
void NiTexturingProperty::read(NIFStream *nif)
|
void NiTexturingProperty::read(NIFStream *nif)
|
||||||
{
|
{
|
||||||
Property::read(nif);
|
Property::read(nif);
|
||||||
|
if (nif->getVersion() <= NIFFile::NIFVersion::VER_OB_OLD || nif->getVersion() >= NIFStream::generateVersion(20,1,0,2))
|
||||||
|
flags = nif->getUShort();
|
||||||
|
if (nif->getVersion() <= NIFStream::generateVersion(20,1,0,1))
|
||||||
apply = nif->getUInt();
|
apply = nif->getUInt();
|
||||||
|
|
||||||
unsigned int numTextures = nif->getUInt();
|
unsigned int numTextures = nif->getUInt();
|
||||||
|
@ -51,32 +73,53 @@ void NiTexturingProperty::read(NIFStream *nif)
|
||||||
envMapLumaBias = nif->getVector2();
|
envMapLumaBias = nif->getVector2();
|
||||||
bumpMapMatrix = nif->getVector4();
|
bumpMapMatrix = nif->getVector4();
|
||||||
}
|
}
|
||||||
|
else if (i == 7 && textures[7].inUse && nif->getVersion() >= NIFStream::generateVersion(20,2,0,5))
|
||||||
|
/*float parallaxOffset = */nif->getFloat();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nif->getVersion() >= NIFStream::generateVersion(10,0,1,0))
|
||||||
|
{
|
||||||
|
unsigned int numShaderTextures = nif->getUInt();
|
||||||
|
shaderTextures.resize(numShaderTextures);
|
||||||
|
for (unsigned int i = 0; i < numShaderTextures; i++)
|
||||||
|
{
|
||||||
|
shaderTextures[i].read(nif);
|
||||||
|
if (shaderTextures[i].inUse)
|
||||||
|
nif->getUInt(); // Unique identifier
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void NiTexturingProperty::post(NIFFile *nif)
|
void NiTexturingProperty::post(NIFFile *nif)
|
||||||
{
|
{
|
||||||
Property::post(nif);
|
Property::post(nif);
|
||||||
for(int i = 0;i < 7;i++)
|
for (size_t i = 0; i < textures.size(); i++)
|
||||||
textures[i].post(nif);
|
textures[i].post(nif);
|
||||||
|
for (size_t i = 0; i < shaderTextures.size(); i++)
|
||||||
|
shaderTextures[i].post(nif);
|
||||||
}
|
}
|
||||||
|
|
||||||
void NiFogProperty::read(NIFStream *nif)
|
void NiFogProperty::read(NIFStream *nif)
|
||||||
{
|
{
|
||||||
Property::read(nif);
|
Property::read(nif);
|
||||||
|
mFlags = nif->getUShort();
|
||||||
mFogDepth = nif->getFloat();
|
mFogDepth = nif->getFloat();
|
||||||
mColour = nif->getVector3();
|
mColour = nif->getVector3();
|
||||||
}
|
}
|
||||||
|
|
||||||
void S_MaterialProperty::read(NIFStream *nif)
|
void S_MaterialProperty::read(NIFStream *nif)
|
||||||
|
{
|
||||||
|
if (nif->getBethVersion() < 26)
|
||||||
{
|
{
|
||||||
ambient = nif->getVector3();
|
ambient = nif->getVector3();
|
||||||
diffuse = nif->getVector3();
|
diffuse = nif->getVector3();
|
||||||
|
}
|
||||||
specular = nif->getVector3();
|
specular = nif->getVector3();
|
||||||
emissive = nif->getVector3();
|
emissive = nif->getVector3();
|
||||||
glossiness = nif->getFloat();
|
glossiness = nif->getFloat();
|
||||||
alpha = nif->getFloat();
|
alpha = nif->getFloat();
|
||||||
|
if (nif->getBethVersion() > 21)
|
||||||
|
emissive *= nif->getFloat();
|
||||||
}
|
}
|
||||||
|
|
||||||
void S_VertexColorProperty::read(NIFStream *nif)
|
void S_VertexColorProperty::read(NIFStream *nif)
|
||||||
|
@ -91,6 +134,8 @@ void S_AlphaProperty::read(NIFStream *nif)
|
||||||
}
|
}
|
||||||
|
|
||||||
void S_StencilProperty::read(NIFStream *nif)
|
void S_StencilProperty::read(NIFStream *nif)
|
||||||
|
{
|
||||||
|
if (nif->getVersion() <= NIFFile::NIFVersion::VER_OB)
|
||||||
{
|
{
|
||||||
enabled = nif->getChar();
|
enabled = nif->getChar();
|
||||||
compareFunc = nif->getInt();
|
compareFunc = nif->getInt();
|
||||||
|
@ -101,6 +146,19 @@ void S_StencilProperty::read(NIFStream *nif)
|
||||||
zPassAction = nif->getInt();
|
zPassAction = nif->getInt();
|
||||||
drawMode = nif->getInt();
|
drawMode = nif->getInt();
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
unsigned short flags = nif->getUShort();
|
||||||
|
enabled = flags & 0x1;
|
||||||
|
failAction = (flags >> 1) & 0x7;
|
||||||
|
zFailAction = (flags >> 4) & 0x7;
|
||||||
|
zPassAction = (flags >> 7) & 0x7;
|
||||||
|
drawMode = (flags >> 10) & 0x3;
|
||||||
|
compareFunc = (flags >> 12) & 0x7;
|
||||||
|
stencilRef = nif->getUInt();
|
||||||
|
stencilMask = nif->getUInt();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -29,18 +29,13 @@
|
||||||
namespace Nif
|
namespace Nif
|
||||||
{
|
{
|
||||||
|
|
||||||
class Property : public Named
|
class Property : public Named { };
|
||||||
{
|
|
||||||
public:
|
|
||||||
// The meaning of these depends on the actual property type.
|
|
||||||
unsigned int flags;
|
|
||||||
|
|
||||||
void read(NIFStream *nif);
|
|
||||||
};
|
|
||||||
|
|
||||||
class NiTexturingProperty : public Property
|
class NiTexturingProperty : public Property
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
unsigned short flags{0u};
|
||||||
|
|
||||||
// A sub-texture
|
// A sub-texture
|
||||||
struct Texture
|
struct Texture
|
||||||
{
|
{
|
||||||
|
@ -92,6 +87,7 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
std::vector<Texture> textures;
|
std::vector<Texture> textures;
|
||||||
|
std::vector<Texture> shaderTextures;
|
||||||
|
|
||||||
osg::Vec2f envMapLumaBias;
|
osg::Vec2f envMapLumaBias;
|
||||||
osg::Vec4f bumpMapMatrix;
|
osg::Vec4f bumpMapMatrix;
|
||||||
|
@ -103,28 +99,81 @@ public:
|
||||||
class NiFogProperty : public Property
|
class NiFogProperty : public Property
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
unsigned short mFlags;
|
||||||
float mFogDepth;
|
float mFogDepth;
|
||||||
osg::Vec3f mColour;
|
osg::Vec3f mColour;
|
||||||
|
|
||||||
void read(NIFStream *nif);
|
void read(NIFStream *nif);
|
||||||
};
|
};
|
||||||
|
|
||||||
// These contain no other data than the 'flags' field in Property
|
// These contain no other data than the 'flags' field
|
||||||
class NiShadeProperty : public Property { };
|
struct NiShadeProperty : public Property
|
||||||
class NiDitherProperty : public Property { };
|
{
|
||||||
class NiZBufferProperty : public Property { };
|
unsigned short flags{0u};
|
||||||
class NiSpecularProperty : public Property { };
|
void read(NIFStream *nif)
|
||||||
class NiWireframeProperty : public Property { };
|
{
|
||||||
|
Property::read(nif);
|
||||||
|
if (nif->getBethVersion() <= NIFFile::BethVersion::BETHVER_FO3)
|
||||||
|
flags = nif->getUShort();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct NiDitherProperty : public Property
|
||||||
|
{
|
||||||
|
unsigned short flags;
|
||||||
|
void read(NIFStream* nif)
|
||||||
|
{
|
||||||
|
Property::read(nif);
|
||||||
|
flags = nif->getUShort();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct NiZBufferProperty : public Property
|
||||||
|
{
|
||||||
|
unsigned short flags;
|
||||||
|
unsigned int testFunction;
|
||||||
|
void read(NIFStream *nif)
|
||||||
|
{
|
||||||
|
Property::read(nif);
|
||||||
|
flags = nif->getUShort();
|
||||||
|
testFunction = (flags >> 2) & 0x7;
|
||||||
|
if (nif->getVersion() >= NIFStream::generateVersion(4,1,0,12) && nif->getVersion() <= NIFFile::NIFVersion::VER_OB)
|
||||||
|
testFunction = nif->getUInt();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct NiSpecularProperty : public Property
|
||||||
|
{
|
||||||
|
unsigned short flags;
|
||||||
|
void read(NIFStream* nif)
|
||||||
|
{
|
||||||
|
Property::read(nif);
|
||||||
|
flags = nif->getUShort();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct NiWireframeProperty : public Property
|
||||||
|
{
|
||||||
|
unsigned short flags;
|
||||||
|
void read(NIFStream* nif)
|
||||||
|
{
|
||||||
|
Property::read(nif);
|
||||||
|
flags = nif->getUShort();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
// The rest are all struct-based
|
// The rest are all struct-based
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct StructPropT : Property
|
struct StructPropT : Property
|
||||||
{
|
{
|
||||||
T data;
|
T data;
|
||||||
|
unsigned short flags;
|
||||||
|
|
||||||
void read(NIFStream *nif)
|
void read(NIFStream *nif)
|
||||||
{
|
{
|
||||||
Property::read(nif);
|
Property::read(nif);
|
||||||
|
flags = nif->getUShort();
|
||||||
data.read(nif);
|
data.read(nif);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -132,7 +181,8 @@ struct StructPropT : Property
|
||||||
struct S_MaterialProperty
|
struct S_MaterialProperty
|
||||||
{
|
{
|
||||||
// The vector components are R,G,B
|
// The vector components are R,G,B
|
||||||
osg::Vec3f ambient, diffuse, specular, emissive;
|
osg::Vec3f ambient{1.f,1.f,1.f}, diffuse{1.f,1.f,1.f};
|
||||||
|
osg::Vec3f specular, emissive;
|
||||||
float glossiness, alpha;
|
float glossiness, alpha;
|
||||||
|
|
||||||
void read(NIFStream *nif);
|
void read(NIFStream *nif);
|
||||||
|
@ -246,9 +296,35 @@ struct S_StencilProperty
|
||||||
};
|
};
|
||||||
|
|
||||||
class NiAlphaProperty : public StructPropT<S_AlphaProperty> { };
|
class NiAlphaProperty : public StructPropT<S_AlphaProperty> { };
|
||||||
class NiMaterialProperty : public StructPropT<S_MaterialProperty> { };
|
|
||||||
class NiVertexColorProperty : public StructPropT<S_VertexColorProperty> { };
|
class NiVertexColorProperty : public StructPropT<S_VertexColorProperty> { };
|
||||||
class NiStencilProperty : public StructPropT<S_StencilProperty> { };
|
struct NiStencilProperty : public Property
|
||||||
|
{
|
||||||
|
S_StencilProperty data;
|
||||||
|
unsigned short flags{0u};
|
||||||
|
|
||||||
|
void read(NIFStream *nif)
|
||||||
|
{
|
||||||
|
Property::read(nif);
|
||||||
|
if (nif->getVersion() <= NIFFile::NIFVersion::VER_OB_OLD)
|
||||||
|
flags = nif->getUShort();
|
||||||
|
data.read(nif);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct NiMaterialProperty : public Property
|
||||||
|
{
|
||||||
|
S_MaterialProperty data;
|
||||||
|
unsigned short flags{0u};
|
||||||
|
|
||||||
|
void read(NIFStream *nif)
|
||||||
|
{
|
||||||
|
Property::read(nif);
|
||||||
|
if (nif->getVersion() >= NIFStream::generateVersion(3,0,0,0)
|
||||||
|
&& nif->getVersion() <= NIFFile::NIFVersion::VER_OB_OLD)
|
||||||
|
flags = nif->getUShort();
|
||||||
|
data.read(nif);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
} // Namespace
|
} // Namespace
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1732,7 +1732,7 @@ namespace NifOsg
|
||||||
osg::StateSet* stateset = node->getOrCreateStateSet();
|
osg::StateSet* stateset = node->getOrCreateStateSet();
|
||||||
|
|
||||||
// Specular lighting is enabled by default, but there's a quirk...
|
// Specular lighting is enabled by default, but there's a quirk...
|
||||||
int specFlags = 1;
|
bool specEnabled = true;
|
||||||
osg::ref_ptr<osg::Material> mat (new osg::Material);
|
osg::ref_ptr<osg::Material> mat (new osg::Material);
|
||||||
mat->setColorMode(hasVertexColors ? osg::Material::AMBIENT_AND_DIFFUSE : osg::Material::OFF);
|
mat->setColorMode(hasVertexColors ? osg::Material::AMBIENT_AND_DIFFUSE : osg::Material::OFF);
|
||||||
|
|
||||||
|
@ -1751,7 +1751,8 @@ namespace NifOsg
|
||||||
case Nif::RC_NiSpecularProperty:
|
case Nif::RC_NiSpecularProperty:
|
||||||
{
|
{
|
||||||
// Specular property can turn specular lighting off.
|
// Specular property can turn specular lighting off.
|
||||||
specFlags = property->flags;
|
auto specprop = static_cast<const Nif::NiSpecularProperty*>(property);
|
||||||
|
specEnabled = specprop->flags & 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Nif::RC_NiMaterialProperty:
|
case Nif::RC_NiMaterialProperty:
|
||||||
|
@ -1835,7 +1836,7 @@ namespace NifOsg
|
||||||
}
|
}
|
||||||
|
|
||||||
// While NetImmerse and Gamebryo support specular lighting, Morrowind has its support disabled.
|
// While NetImmerse and Gamebryo support specular lighting, Morrowind has its support disabled.
|
||||||
if (mVersion <= Nif::NIFFile::NIFVersion::VER_MW || specFlags == 0)
|
if (mVersion <= Nif::NIFFile::NIFVersion::VER_MW || !specEnabled)
|
||||||
mat->setSpecular(osg::Material::FRONT_AND_BACK, osg::Vec4f(0.f,0.f,0.f,0.f));
|
mat->setSpecular(osg::Material::FRONT_AND_BACK, osg::Vec4f(0.f,0.f,0.f,0.f));
|
||||||
|
|
||||||
if (lightmode == 0)
|
if (lightmode == 0)
|
||||||
|
|
Loading…
Reference in a new issue