diff --git a/components/nif/data.cpp b/components/nif/data.cpp index 751b15097d..1de7d0966c 100644 --- a/components/nif/data.cpp +++ b/components/nif/data.cpp @@ -175,9 +175,9 @@ void NiPixelData::read(NIFStream *nif) { // Image size and offset in the following data field Mipmap m; - m.width = nif->getInt(); - m.height = nif->getInt(); - m.dataOffset = nif->getInt(); + m.width = nif->getUInt(); + m.height = nif->getUInt(); + m.dataOffset = nif->getUInt(); mipmaps.push_back(m); } diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 9fbee3d4d9..0b49419ff1 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -1210,6 +1210,68 @@ namespace NifOsg } } + osg::ref_ptr handleInternalTexture(const Nif::NiPixelData* pixelData) + { + osg::ref_ptr image (new osg::Image); + + GLenum pixelformat = 0; + switch (pixelData->fmt) + { + case Nif::NiPixelData::NIPXFMT_RGB8: + pixelformat = GL_RGB; + break; + case Nif::NiPixelData::NIPXFMT_RGBA8: + pixelformat = GL_RGBA; + break; + default: + std::cerr << "Unhandled internal pixel format " << pixelData->fmt << " in " << mFilename << std::endl; + return NULL; + } + + if (!pixelData->mipmaps.size()) + return NULL; + + unsigned char* data = new unsigned char[pixelData->data.size()]; + memcpy(data, &pixelData->data[0], pixelData->data.size()); + unsigned int width = 0; + unsigned int height = 0; + + std::vector mipmapVector; + for (unsigned int i=0; imipmaps.size()-3; ++i) + { + const Nif::NiPixelData::Mipmap& mip = pixelData->mipmaps[i]; + + size_t mipSize = mip.height * mip.width * pixelData->bpp / 8; + if (mipSize + mip.dataOffset > pixelData->data.size()) + { + std::cerr << "Internal texture's mipmap data out of bounds" << std::endl; + delete data; + return NULL; + } + + if (i != 0) + mipmapVector.push_back(mip.dataOffset); + else + { + width = mip.width; + height = mip.height; + } + } + + if (width <= 0 || height <= 0) + { + std::cerr << "Width and height must be non zero " << std::endl; + delete data; + return NULL; + } + + image->setImage(width, height, 1, pixelformat, pixelformat, GL_UNSIGNED_BYTE, data, osg::Image::USE_NEW_DELETE); + image->setMipmapLevels(mipmapVector); + image->flipVertical(); + + return image; + } + void handleTextureProperty(const Nif::NiTexturingProperty* texprop, osg::StateSet* stateset, SceneUtil::CompositeStateSetUpdater* composite, Resource::ImageManager* imageManager, std::vector& boundTextures, int animflags) { if (boundTextures.size()) @@ -1256,21 +1318,24 @@ namespace NifOsg std::cerr << "Warning: texture layer " << i << " is in use but empty in " << mFilename << std::endl; continue; } + osg::ref_ptr image; const Nif::NiSourceTexture *st = tex.texture.getPtr(); - if (!st->external) + if (!st->external && !st->data.empty()) { - std::cerr << "Warning: unhandled internal texture in " << mFilename << std::endl; - continue; + image = handleInternalTexture(st->data.getPtr()); + } + else + { + std::string filename = Misc::ResourceHelpers::correctTexturePath(st->filename, imageManager->getVFS()); + image = imageManager->getImage(filename); } - - std::string filename = Misc::ResourceHelpers::correctTexturePath(st->filename, imageManager->getVFS()); unsigned int clamp = static_cast(tex.clamp); int wrapT = (clamp) & 0x1; int wrapS = (clamp >> 1) & 0x1; // create a new texture, will later attempt to share using the SharedStateManager - osg::ref_ptr texture2d (new osg::Texture2D(imageManager->getImage(filename))); + osg::ref_ptr texture2d (new osg::Texture2D(image)); texture2d->setWrap(osg::Texture::WRAP_S, wrapS ? osg::Texture::REPEAT : osg::Texture::CLAMP); texture2d->setWrap(osg::Texture::WRAP_T, wrapT ? osg::Texture::REPEAT : osg::Texture::CLAMP);