Implement NiPalette support (feature #4882)

pull/2491/head
capostrophic 5 years ago
parent 043231737d
commit 9c7474f88c

@ -148,6 +148,7 @@
Feature #4812: Support NiSwitchNode
Feature #4836: Daytime node switch
Feature #4859: Make water reflections more configurable
Feature #4882: Support for NiPalette node
Feature #4887: Add openmw command option to set initial random seed
Feature #4890: Make Distant Terrain configurable
Feature #4958: Support eight blood types

@ -163,22 +163,23 @@ void NiPixelData::read(NIFStream *nif)
{
fmt = (Format)nif->getUInt();
rmask = nif->getInt(); // usually 0xff
gmask = nif->getInt(); // usually 0xff00
bmask = nif->getInt(); // usually 0xff0000
amask = nif->getInt(); // usually 0xff000000 or zero
rmask = nif->getUInt(); // usually 0xff
gmask = nif->getUInt(); // usually 0xff00
bmask = nif->getUInt(); // usually 0xff0000
amask = nif->getUInt(); // usually 0xff000000 or zero
bpp = nif->getInt();
bpp = nif->getUInt();
// Unknown
nif->skip(12);
// 8 bytes of "Old Fast Compare". Whatever that means.
nif->skip(8);
palette.read(nif);
numberOfMipmaps = nif->getInt();
numberOfMipmaps = nif->getUInt();
// Bytes per pixel, should be bpp * 8
/* int bytes = */ nif->getInt();
/* int bytes = */ nif->getUInt();
for(int i=0; i<numberOfMipmaps; i++)
for(unsigned int i=0; i<numberOfMipmaps; i++)
{
// Image size and offset in the following data field
Mipmap m;
@ -189,12 +190,17 @@ void NiPixelData::read(NIFStream *nif)
}
// Read the data
unsigned int dataSize = nif->getInt();
unsigned int dataSize = nif->getUInt();
data.reserve(dataSize);
for (unsigned i=0; i<dataSize; ++i)
data.push_back((unsigned char)nif->getChar());
}
void NiPixelData::post(NIFFile *nif)
{
palette.post(nif);
}
void NiColorData::read(NIFStream *nif)
{
mKeyMap = std::make_shared<Vector4KeyMap>();
@ -278,4 +284,14 @@ void NiKeyframeData::read(NIFStream *nif)
mScales->read(nif);
}
void NiPalette::read(NIFStream *nif)
{
unsigned int alphaMask = !nif->getChar() ? 0xFF000000 : 0;
// Fill the entire palette with black even if there isn't enough entries.
colors.resize(256);
unsigned int numEntries = nif->getUInt();
for (unsigned int i = 0; i < numEntries; i++)
colors[i] = nif->getUInt() | alphaMask;
}
} // Namespace

@ -116,6 +116,7 @@ public:
NIPXFMT_RGB8,
NIPXFMT_RGBA8,
NIPXFMT_PAL8,
NIPXFMT_PALA8,
NIPXFMT_DXT1,
NIPXFMT_DXT3,
NIPXFMT_DXT5,
@ -123,8 +124,10 @@ public:
};
Format fmt;
unsigned int rmask, gmask, bmask, amask;
int bpp, numberOfMipmaps;
unsigned int rmask, gmask, bmask, amask, bpp;
NiPalettePtr palette;
unsigned int numberOfMipmaps;
struct Mipmap
{
@ -136,6 +139,7 @@ public:
std::vector<unsigned char> data;
void read(NIFStream *nif);
void post(NIFFile *nif);
};
class NiColorData : public Record
@ -219,5 +223,14 @@ struct NiKeyframeData : public Record
void read(NIFStream *nif);
};
class NiPalette : public Record
{
public:
// 32-bit RGBA colors that correspond to 8-bit indices
std::vector<unsigned int> colors;
void read(NIFStream *nif);
};
} // Namespace
#endif

@ -112,6 +112,7 @@ static std::map<std::string,RecordFactoryEntry> makeFactory()
newFactory.insert(makeEntry("NiSourceTexture", &construct <NiSourceTexture> , RC_NiSourceTexture ));
newFactory.insert(makeEntry("NiSkinInstance", &construct <NiSkinInstance> , RC_NiSkinInstance ));
newFactory.insert(makeEntry("NiLookAtController", &construct <NiLookAtController> , RC_NiLookAtController ));
newFactory.insert(makeEntry("NiPalette", &construct <NiPalette> , RC_NiPalette ));
return newFactory;
}

@ -97,7 +97,8 @@ enum RecordType
RC_NiSkinInstance,
RC_RootCollisionNode,
RC_NiSphericalCollider,
RC_NiLookAtController
RC_NiLookAtController,
RC_NiPalette
};
/// Base class for all records

@ -140,6 +140,7 @@ class NiSkinInstance;
class NiSourceTexture;
class NiRotatingParticlesData;
class NiAutoNormalParticlesData;
class NiPalette;
typedef RecordPtrT<Node> NodePtr;
typedef RecordPtrT<Extra> ExtraPtr;
@ -160,6 +161,7 @@ typedef RecordPtrT<NiSkinInstance> NiSkinInstancePtr;
typedef RecordPtrT<NiSourceTexture> NiSourceTexturePtr;
typedef RecordPtrT<NiRotatingParticlesData> NiRotatingParticlesDataPtr;
typedef RecordPtrT<NiAutoNormalParticlesData> NiAutoNormalParticlesDataPtr;
typedef RecordPtrT<NiPalette> NiPalettePtr;
typedef RecordListT<Node> NodeList;
typedef RecordListT<Property> PropertyList;

@ -1276,9 +1276,11 @@ namespace NifOsg
switch (pixelData->fmt)
{
case Nif::NiPixelData::NIPXFMT_RGB8:
case Nif::NiPixelData::NIPXFMT_PAL8:
pixelformat = GL_RGB;
break;
case Nif::NiPixelData::NIPXFMT_RGBA8:
case Nif::NiPixelData::NIPXFMT_PALA8:
pixelformat = GL_RGBA;
break;
default:
@ -1293,7 +1295,7 @@ namespace NifOsg
int height = 0;
std::vector<unsigned int> mipmapVector;
for (unsigned int i=0; i<pixelData->mipmaps.size()-3; ++i)
for (unsigned int i=0; i<pixelData->mipmaps.size(); ++i)
{
const Nif::NiPixelData::Mipmap& mip = pixelData->mipmaps[i];
@ -1319,10 +1321,59 @@ namespace NifOsg
return nullptr;
}
unsigned char* data = new unsigned char[pixelData->data.size()];
memcpy(data, pixelData->data.data(), pixelData->data.size());
const std::vector<unsigned char>& pixels = pixelData->data;
switch (pixelData->fmt)
{
case Nif::NiPixelData::NIPXFMT_RGB8:
case Nif::NiPixelData::NIPXFMT_RGBA8:
{
unsigned char* data = new unsigned char[pixels.size()];
memcpy(data, pixels.data(), pixels.size());
image->setImage(width, height, 1, pixelformat, pixelformat, GL_UNSIGNED_BYTE, data, osg::Image::USE_NEW_DELETE);
break;
}
case Nif::NiPixelData::NIPXFMT_PAL8:
case Nif::NiPixelData::NIPXFMT_PALA8:
{
if (pixelData->palette.empty() || pixelData->bpp != 8)
{
Log(Debug::Info) << "Palettized texture in " << mFilename << " is invalid, ignoring";
return nullptr;
}
// We're going to convert the indices that pixel data contains
// into real colors using the palette.
const std::vector<unsigned int>& palette = pixelData->palette->colors;
if (pixelData->fmt == Nif::NiPixelData::NIPXFMT_PAL8)
{
unsigned char* data = new unsigned char[pixels.size() * 3];
for (size_t i = 0; i < pixels.size(); i++)
{
unsigned int color = palette[pixels[i]];
data[i * 3 + 0] = (color >> 0) & 0xFF;
data[i * 3 + 1] = (color >> 8) & 0xFF;
data[i * 3 + 2] = (color >> 16) & 0xFF;
}
image->setImage(width, height, 1, pixelformat, pixelformat, GL_UNSIGNED_BYTE, data, osg::Image::USE_NEW_DELETE);
}
else // if (fmt = NIPXFMT_PALA8)
{
unsigned char* data = new unsigned char[pixels.size() * 4];
for (size_t i = 0; i < pixels.size(); i++)
{
unsigned int color = palette[pixels[i]];
data[i * 4 + 0] = (color >> 0) & 0xFF;
data[i * 4 + 1] = (color >> 8) & 0xFF;
data[i * 4 + 2] = (color >> 16) & 0xFF;
data[i * 4 + 3] = (color >> 24) & 0xFF;
}
image->setImage(width, height, 1, pixelformat, pixelformat, GL_UNSIGNED_BYTE, data, osg::Image::USE_NEW_DELETE);
}
break;
}
default:
return nullptr;
}
image->setImage(width, height, 1, pixelformat, pixelformat, GL_UNSIGNED_BYTE, data, osg::Image::USE_NEW_DELETE);
image->setMipmapLevels(mipmapVector);
image->flipVertical();

Loading…
Cancel
Save