mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-02-10 03:39:55 +00:00
Modernize NiPixelData
This commit is contained in:
parent
523e7e8228
commit
5e8f9e7dd9
@ -224,58 +224,61 @@ namespace Nif
|
||||
mKeyList->read(nif);
|
||||
}
|
||||
|
||||
void NiPixelFormat::read(NIFStream* nif)
|
||||
{
|
||||
mFormat = static_cast<Format>(nif->get<uint32_t>());
|
||||
if (nif->getVersion() <= NIFStream::generateVersion(10, 4, 0, 1))
|
||||
{
|
||||
nif->readArray(mColorMasks);
|
||||
nif->read(mBitsPerPixel);
|
||||
nif->readArray(mCompareBits);
|
||||
if (nif->getVersion() >= NIFStream::generateVersion(10, 1, 0, 0))
|
||||
nif->read(mPixelTiling);
|
||||
}
|
||||
else
|
||||
{
|
||||
mBitsPerPixel = nif->get<uint8_t>();
|
||||
nif->read(mRendererHint);
|
||||
nif->read(mExtraData);
|
||||
nif->read(mFlags);
|
||||
nif->read(mPixelTiling);
|
||||
if (nif->getVersion() >= NIFStream::generateVersion(20, 3, 0, 4))
|
||||
nif->read(mUseSrgb);
|
||||
for (int i = 0; i < 4; i++)
|
||||
mChannels[i].read(nif);
|
||||
}
|
||||
}
|
||||
|
||||
void NiPixelFormat::ChannelData::read(NIFStream* nif)
|
||||
{
|
||||
mType = static_cast<Type>(nif->get<uint32_t>());
|
||||
mConvention = static_cast<Convention>(nif->get<uint32_t>());
|
||||
nif->read(mBitsPerChannel);
|
||||
nif->read(mSigned);
|
||||
}
|
||||
|
||||
void NiPixelData::read(NIFStream* nif)
|
||||
{
|
||||
fmt = (Format)nif->getUInt();
|
||||
|
||||
if (nif->getVersion() < NIFStream::generateVersion(10, 4, 0, 2))
|
||||
mPixelFormat.read(nif);
|
||||
mPalette.read(nif);
|
||||
mMipmaps.resize(nif->get<uint32_t>());
|
||||
nif->read(mBytesPerPixel);
|
||||
for (Mipmap& mip : mMipmaps)
|
||||
{
|
||||
for (unsigned int i = 0; i < 4; ++i)
|
||||
colorMask[i] = 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();
|
||||
nif->read(mip.mWidth);
|
||||
nif->read(mip.mHeight);
|
||||
nif->read(mip.mOffset);
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
palette.read(nif);
|
||||
|
||||
numberOfMipmaps = nif->getUInt();
|
||||
|
||||
// Bytes per pixel, should be bpp / 8
|
||||
/* int bytes = */ nif->getUInt();
|
||||
|
||||
for (unsigned int i = 0; i < numberOfMipmaps; i++)
|
||||
{
|
||||
// Image size and offset in the following data field
|
||||
Mipmap m;
|
||||
m.width = nif->getUInt();
|
||||
m.height = nif->getUInt();
|
||||
m.dataOffset = nif->getUInt();
|
||||
mipmaps.push_back(m);
|
||||
}
|
||||
|
||||
// Read the data
|
||||
unsigned int numPixels = nif->getUInt();
|
||||
bool hasFaces = nif->getVersion() >= NIFStream::generateVersion(10, 4, 0, 2);
|
||||
unsigned int numFaces = hasFaces ? nif->getUInt() : 1;
|
||||
nif->readVector(data, numPixels * numFaces);
|
||||
uint32_t numPixels;
|
||||
nif->read(numPixels);
|
||||
if (nif->getVersion() >= NIFStream::generateVersion(10, 4, 0, 2))
|
||||
nif->read(mNumFaces);
|
||||
nif->readVector(mData, numPixels * mNumFaces);
|
||||
}
|
||||
|
||||
void NiPixelData::post(Reader& nif)
|
||||
{
|
||||
palette.post(nif);
|
||||
mPalette.post(nif);
|
||||
}
|
||||
|
||||
void NiColorData::read(NIFStream* nif)
|
||||
|
@ -116,37 +116,94 @@ namespace Nif
|
||||
void read(NIFStream* nif) override;
|
||||
};
|
||||
|
||||
struct NiPixelFormat
|
||||
{
|
||||
enum class Format : uint32_t
|
||||
{
|
||||
RGB = 0,
|
||||
RGBA = 1,
|
||||
Palette = 2,
|
||||
PaletteAlpha = 3,
|
||||
BGR = 4,
|
||||
BGRA = 5,
|
||||
DXT1 = 6,
|
||||
DXT3 = 7,
|
||||
DXT5 = 8,
|
||||
};
|
||||
|
||||
struct ChannelData
|
||||
{
|
||||
enum class Type : uint32_t
|
||||
{
|
||||
Red = 0,
|
||||
Green = 1,
|
||||
Blue = 2,
|
||||
Alpha = 3,
|
||||
Compressed = 4,
|
||||
OffsetU = 5,
|
||||
OffsetV = 6,
|
||||
OffsetW = 7,
|
||||
OffsetQ = 8,
|
||||
Luma = 9,
|
||||
Height = 10,
|
||||
VectorX = 11,
|
||||
VectorY = 12,
|
||||
VectorZ = 13,
|
||||
Padding = 14,
|
||||
Intensity = 15,
|
||||
Index = 16,
|
||||
Depth = 17,
|
||||
Stencil = 18,
|
||||
Empty = 19,
|
||||
};
|
||||
|
||||
enum class Convention : uint32_t
|
||||
{
|
||||
NormInt = 0,
|
||||
Half = 1,
|
||||
Float = 2,
|
||||
Index = 3,
|
||||
Compressed = 4,
|
||||
Unknown = 5,
|
||||
Int = 6,
|
||||
};
|
||||
|
||||
Type mType;
|
||||
Convention mConvention;
|
||||
uint8_t mBitsPerChannel;
|
||||
bool mSigned;
|
||||
|
||||
void read(NIFStream* nif);
|
||||
};
|
||||
|
||||
Format mFormat{ Format::RGB };
|
||||
std::array<uint32_t, 4> mColorMasks;
|
||||
uint32_t mBitsPerPixel{ 0 };
|
||||
uint32_t mPixelTiling{ 0 };
|
||||
std::array<uint32_t, 2> mCompareBits;
|
||||
uint32_t mRendererHint{ 0 };
|
||||
uint32_t mExtraData{ 0 };
|
||||
uint8_t mFlags{ 0 };
|
||||
bool mUseSrgb{ false };
|
||||
std::array<ChannelData, 4> mChannels;
|
||||
|
||||
void read(NIFStream* nif);
|
||||
};
|
||||
|
||||
struct NiPixelData : public Record
|
||||
{
|
||||
enum Format
|
||||
{
|
||||
NIPXFMT_RGB8,
|
||||
NIPXFMT_RGBA8,
|
||||
NIPXFMT_PAL8,
|
||||
NIPXFMT_PALA8,
|
||||
NIPXFMT_BGR8,
|
||||
NIPXFMT_BGRA8,
|
||||
NIPXFMT_DXT1,
|
||||
NIPXFMT_DXT3,
|
||||
NIPXFMT_DXT5
|
||||
};
|
||||
Format fmt{ NIPXFMT_RGB8 };
|
||||
|
||||
unsigned int colorMask[4]{ 0 };
|
||||
unsigned int bpp{ 0 }, pixelTiling{ 0 };
|
||||
bool sRGB{ false };
|
||||
|
||||
NiPalettePtr palette;
|
||||
unsigned int numberOfMipmaps{ 0 };
|
||||
|
||||
struct Mipmap
|
||||
{
|
||||
int width, height;
|
||||
int dataOffset;
|
||||
uint32_t mWidth, mHeight;
|
||||
uint32_t mOffset;
|
||||
};
|
||||
std::vector<Mipmap> mipmaps;
|
||||
|
||||
std::vector<unsigned char> data;
|
||||
NiPixelFormat mPixelFormat;
|
||||
NiPalettePtr mPalette;
|
||||
uint32_t mBytesPerPixel;
|
||||
std::vector<Mipmap> mMipmaps;
|
||||
uint32_t mNumFaces{ 1 };
|
||||
std::vector<uint8_t> mData;
|
||||
|
||||
void read(NIFStream* nif) override;
|
||||
void post(Reader& nif) override;
|
||||
|
@ -1680,71 +1680,76 @@ namespace NifOsg
|
||||
|
||||
osg::ref_ptr<osg::Image> handleInternalTexture(const Nif::NiPixelData* pixelData)
|
||||
{
|
||||
osg::ref_ptr<osg::Image> image(new osg::Image);
|
||||
if (pixelData->mMipmaps.empty())
|
||||
return nullptr;
|
||||
|
||||
// Pixel row alignment, defining it to be consistent with OSG DDS plugin
|
||||
int packing = 1;
|
||||
// Not fatal, but warn the user
|
||||
if (pixelData->mNumFaces != 1)
|
||||
Log(Debug::Info) << "Unsupported multifaceted internal texture in " << mFilename;
|
||||
|
||||
using Nif::NiPixelFormat;
|
||||
NiPixelFormat niPixelFormat = pixelData->mPixelFormat;
|
||||
GLenum pixelformat = 0;
|
||||
switch (pixelData->fmt)
|
||||
// Pixel row alignment. Defining it to be consistent with OSG DDS plugin
|
||||
int packing = 1;
|
||||
switch (niPixelFormat.mFormat)
|
||||
{
|
||||
case Nif::NiPixelData::NIPXFMT_RGB8:
|
||||
case NiPixelFormat::Format::RGB:
|
||||
pixelformat = GL_RGB;
|
||||
break;
|
||||
case Nif::NiPixelData::NIPXFMT_RGBA8:
|
||||
case NiPixelFormat::Format::RGBA:
|
||||
pixelformat = GL_RGBA;
|
||||
break;
|
||||
case Nif::NiPixelData::NIPXFMT_PAL8:
|
||||
case Nif::NiPixelData::NIPXFMT_PALA8:
|
||||
case NiPixelFormat::Format::Palette:
|
||||
case NiPixelFormat::Format::PaletteAlpha:
|
||||
pixelformat = GL_RED; // Each color is defined by a byte.
|
||||
break;
|
||||
case Nif::NiPixelData::NIPXFMT_BGR8:
|
||||
case NiPixelFormat::Format::BGR:
|
||||
pixelformat = GL_BGR;
|
||||
break;
|
||||
case Nif::NiPixelData::NIPXFMT_BGRA8:
|
||||
case NiPixelFormat::Format::BGRA:
|
||||
pixelformat = GL_BGRA;
|
||||
break;
|
||||
case Nif::NiPixelData::NIPXFMT_DXT1:
|
||||
case NiPixelFormat::Format::DXT1:
|
||||
pixelformat = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
|
||||
packing = 2;
|
||||
break;
|
||||
case Nif::NiPixelData::NIPXFMT_DXT3:
|
||||
case NiPixelFormat::Format::DXT3:
|
||||
pixelformat = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
|
||||
packing = 4;
|
||||
break;
|
||||
case Nif::NiPixelData::NIPXFMT_DXT5:
|
||||
case NiPixelFormat::Format::DXT5:
|
||||
pixelformat = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
|
||||
packing = 4;
|
||||
break;
|
||||
default:
|
||||
Log(Debug::Info) << "Unhandled internal pixel format " << pixelData->fmt << " in " << mFilename;
|
||||
Log(Debug::Info) << "Unhandled internal pixel format "
|
||||
<< static_cast<uint32_t>(niPixelFormat.mFormat) << " in " << mFilename;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (pixelData->mipmaps.empty())
|
||||
return nullptr;
|
||||
|
||||
int width = 0;
|
||||
int height = 0;
|
||||
|
||||
std::vector<unsigned int> mipmapVector;
|
||||
for (unsigned int i = 0; i < pixelData->mipmaps.size(); ++i)
|
||||
std::vector<unsigned int> mipmapOffsets;
|
||||
for (unsigned int i = 0; i < pixelData->mMipmaps.size(); ++i)
|
||||
{
|
||||
const Nif::NiPixelData::Mipmap& mip = pixelData->mipmaps[i];
|
||||
const Nif::NiPixelData::Mipmap& mip = pixelData->mMipmaps[i];
|
||||
|
||||
size_t mipSize = osg::Image::computeImageSizeInBytes(
|
||||
mip.width, mip.height, 1, pixelformat, GL_UNSIGNED_BYTE, packing);
|
||||
if (mipSize + mip.dataOffset > pixelData->data.size())
|
||||
mip.mWidth, mip.mHeight, 1, pixelformat, GL_UNSIGNED_BYTE, packing);
|
||||
if (mipSize + mip.mOffset > pixelData->mData.size())
|
||||
{
|
||||
Log(Debug::Info) << "Internal texture's mipmap data out of bounds, ignoring texture";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (i != 0)
|
||||
mipmapVector.push_back(mip.dataOffset);
|
||||
mipmapOffsets.push_back(mip.mOffset);
|
||||
else
|
||||
{
|
||||
width = mip.width;
|
||||
height = mip.height;
|
||||
width = mip.mWidth;
|
||||
height = mip.mHeight;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1754,16 +1759,17 @@ namespace NifOsg
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const std::vector<unsigned char>& pixels = pixelData->data;
|
||||
switch (pixelData->fmt)
|
||||
osg::ref_ptr<osg::Image> image(new osg::Image);
|
||||
const std::vector<unsigned char>& pixels = pixelData->mData;
|
||||
switch (niPixelFormat.mFormat)
|
||||
{
|
||||
case Nif::NiPixelData::NIPXFMT_RGB8:
|
||||
case Nif::NiPixelData::NIPXFMT_RGBA8:
|
||||
case Nif::NiPixelData::NIPXFMT_BGR8:
|
||||
case Nif::NiPixelData::NIPXFMT_BGRA8:
|
||||
case Nif::NiPixelData::NIPXFMT_DXT1:
|
||||
case Nif::NiPixelData::NIPXFMT_DXT3:
|
||||
case Nif::NiPixelData::NIPXFMT_DXT5:
|
||||
case NiPixelFormat::Format::RGB:
|
||||
case NiPixelFormat::Format::RGBA:
|
||||
case NiPixelFormat::Format::BGR:
|
||||
case NiPixelFormat::Format::BGRA:
|
||||
case NiPixelFormat::Format::DXT1:
|
||||
case NiPixelFormat::Format::DXT3:
|
||||
case NiPixelFormat::Format::DXT5:
|
||||
{
|
||||
unsigned char* data = new unsigned char[pixels.size()];
|
||||
memcpy(data, pixels.data(), pixels.size());
|
||||
@ -1771,18 +1777,18 @@ namespace NifOsg
|
||||
osg::Image::USE_NEW_DELETE, packing);
|
||||
break;
|
||||
}
|
||||
case Nif::NiPixelData::NIPXFMT_PAL8:
|
||||
case Nif::NiPixelData::NIPXFMT_PALA8:
|
||||
case NiPixelFormat::Format::Palette:
|
||||
case NiPixelFormat::Format::PaletteAlpha:
|
||||
{
|
||||
if (pixelData->palette.empty() || pixelData->bpp != 8)
|
||||
if (pixelData->mPalette.empty() || niPixelFormat.mBitsPerPixel != 8)
|
||||
{
|
||||
Log(Debug::Info) << "Palettized texture in " << mFilename << " is invalid, ignoring";
|
||||
return nullptr;
|
||||
}
|
||||
pixelformat = pixelData->fmt == Nif::NiPixelData::NIPXFMT_PAL8 ? GL_RGB : GL_RGBA;
|
||||
pixelformat = niPixelFormat.mFormat == NiPixelFormat::Format::PaletteAlpha ? GL_RGBA : GL_RGB;
|
||||
// We're going to convert the indices that pixel data contains
|
||||
// into real colors using the palette.
|
||||
const auto& palette = pixelData->palette->mColors;
|
||||
const auto& palette = pixelData->mPalette->mColors;
|
||||
const int numChannels = pixelformat == GL_RGBA ? 4 : 3;
|
||||
unsigned char* data = new unsigned char[pixels.size() * numChannels];
|
||||
unsigned char* pixel = data;
|
||||
@ -1791,7 +1797,7 @@ namespace NifOsg
|
||||
memcpy(pixel, &palette[index], sizeof(unsigned char) * numChannels);
|
||||
pixel += numChannels;
|
||||
}
|
||||
for (unsigned int& offset : mipmapVector)
|
||||
for (unsigned int& offset : mipmapOffsets)
|
||||
offset *= numChannels;
|
||||
image->setImage(width, height, 1, pixelformat, pixelformat, GL_UNSIGNED_BYTE, data,
|
||||
osg::Image::USE_NEW_DELETE, packing);
|
||||
@ -1801,7 +1807,7 @@ namespace NifOsg
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
image->setMipmapLevels(mipmapVector);
|
||||
image->setMipmapLevels(mipmapOffsets);
|
||||
image->flipVertical();
|
||||
|
||||
return image;
|
||||
|
Loading…
x
Reference in New Issue
Block a user