From 0497fd111f60b21d7fa400c39428c7fc004b3be4 Mon Sep 17 00:00:00 2001 From: Alexei Kotov Date: Wed, 27 Sep 2023 16:28:04 +0300 Subject: [PATCH] Handle BSTriShape basic geometry --- components/nif/node.cpp | 7 ++- components/nifosg/nifloader.cpp | 96 +++++++++++++++++++++++++++++++++ 2 files changed, 99 insertions(+), 4 deletions(-) diff --git a/components/nif/node.cpp b/components/nif/node.cpp index 860e75671f..62c32f3c15 100644 --- a/components/nif/node.cpp +++ b/components/nif/node.cpp @@ -393,6 +393,8 @@ namespace Nif mShaderProperty.read(nif); mAlphaProperty.read(nif); mVertDesc.read(nif); + if (nif->getBethVersion() == NIFFile::BethVersion::BETHVER_SSE) + mVertDesc.mFlags |= BSVertexDesc::VertexAttribute::Full_Precision; if (nif->getBethVersion() >= NIFFile::BethVersion::BETHVER_FO4) mTriangles.resize(nif->get() * 3); @@ -464,10 +466,7 @@ namespace Nif void BSVertexData::read(NIFStream* nif, uint16_t flags) { - bool fullPrecision = true; - if (nif->getBethVersion() != NIFFile::BethVersion::BETHVER_SSE) - fullPrecision = flags & BSVertexDesc::VertexAttribute::Full_Precision; - + bool fullPrecision = flags & BSVertexDesc::VertexAttribute::Full_Precision; bool hasVertex = flags & BSVertexDesc::VertexAttribute::Vertex; bool hasTangent = flags & BSVertexDesc::VertexAttribute::Tangents; bool hasUV = flags & BSVertexDesc::VertexAttribute::UVs; diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index a5c95fbd67..9c06293adb 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -775,6 +775,8 @@ namespace NifOsg { if (isNiGeometry) handleNiGeometry(nifNode, parent, node, composite, args.mBoundTextures, args.mAnimFlags); + else // isBSGeometry + handleBSGeometry(nifNode, parent, node, composite, args.mBoundTextures, args.mAnimFlags); if (!nifNode->mController.empty()) handleMeshControllers(nifNode, node, composite, args.mBoundTextures, args.mAnimFlags); @@ -1554,6 +1556,100 @@ namespace NifOsg parentNode->addChild(drawable); } + void handleBSGeometry(const Nif::NiAVObject* nifNode, const Nif::Parent* parent, osg::Group* parentNode, + SceneUtil::CompositeStateSetUpdater* composite, const std::vector& boundTextures, + int animflags) + { + assert(isTypeBSGeometry(nifNode->recType)); + + auto bsTriShape = static_cast(nifNode); + const std::vector& triangles = bsTriShape->mTriangles; + if (triangles.empty()) + return; + + osg::ref_ptr geometry(new osg::Geometry); + geometry->addPrimitiveSet(new osg::DrawElementsUShort( + osg::PrimitiveSet::TRIANGLES, triangles.size(), triangles.data())); + + auto normbyteToFloat = [](uint8_t value) { return value / 255.f * 2.f - 1.f; }; + auto halfToFloat = [](uint16_t value) + { + uint32_t bits = static_cast(value & 0x8000) << 16; + + const uint32_t exp16 = (value & 0x7c00) >> 10; + uint32_t frac16 = value & 0x3ff; + if (exp16) + bits |= (exp16 + 0x70) << 23; + else if (frac16) + { + uint8_t offset = 0; + do + { + ++offset; + frac16 <<= 1; + } + while ((frac16 & 0x400) != 0x400); + frac16 &= 0x3ff; + bits |= (0x71 - offset) << 23; + } + bits |= frac16 << 13; + + float result; + std::memcpy(&result, &bits, sizeof(float)); + return result; + }; + + const bool fullPrecision = bsTriShape->mVertDesc.mFlags & Nif::BSVertexDesc::VertexAttribute::Full_Precision; + const bool hasVertices = bsTriShape->mVertDesc.mFlags & Nif::BSVertexDesc::VertexAttribute::Vertex; + const bool hasNormals = bsTriShape->mVertDesc.mFlags & Nif::BSVertexDesc::VertexAttribute::Normals; + const bool hasColors = bsTriShape->mVertDesc.mFlags & Nif::BSVertexDesc::VertexAttribute::Vertex_Colors; + const bool hasUV = bsTriShape->mVertDesc.mFlags & Nif::BSVertexDesc::VertexAttribute::UVs; + + std::vector vertices; + std::vector normals; + std::vector colors; + std::vector uvlist; + for (auto& elem : bsTriShape->mVertData) + { + if (hasVertices) + { + if (fullPrecision) + vertices.emplace_back(elem.mVertex.x(), elem.mVertex.y(), elem.mVertex.z()); + else + vertices.emplace_back(halfToFloat(elem.mHalfVertex[0]), halfToFloat(elem.mHalfVertex[1]), halfToFloat(elem.mHalfVertex[2])); + } + if (hasNormals) + normals.emplace_back(normbyteToFloat(elem.mNormal[0]), normbyteToFloat(elem.mNormal[1]), normbyteToFloat(elem.mNormal[2])); + if (hasColors) + colors.emplace_back(elem.mVertColor[0], elem.mVertColor[1], elem.mVertColor[2], elem.mVertColor[3]); + if (hasUV) + uvlist.emplace_back(halfToFloat(elem.mUV[0]), 1.0 - halfToFloat(elem.mUV[1])); + } + + if (!vertices.empty()) + geometry->setVertexArray(new osg::Vec3Array(vertices.size(), vertices.data())); + if (!normals.empty()) + geometry->setNormalArray( + new osg::Vec3Array(normals.size(), normals.data()), osg::Array::BIND_PER_VERTEX); + if (!colors.empty()) + geometry->setColorArray( + new osg::Vec4ubArray(colors.size(), colors.data()), osg::Array::BIND_PER_VERTEX); + if (!uvlist.empty()) + geometry->setTexCoordArray(0, new osg::Vec2Array(uvlist.size(), uvlist.data()), + osg::Array::BIND_PER_VERTEX); + + std::vector drawableProps; + collectDrawableProperties(nifNode, parent, drawableProps); + if (!bsTriShape->mShaderProperty.empty()) + drawableProps.emplace_back(bsTriShape->mShaderProperty.getPtr()); + if (!bsTriShape->mAlphaProperty.empty()) + drawableProps.emplace_back(bsTriShape->mAlphaProperty.getPtr()); + applyDrawableProperties(parentNode, drawableProps, composite, !colors.empty(), animflags); + + geometry->setName(nifNode->mName); + parentNode->addChild(geometry); + } + osg::BlendFunc::BlendFuncMode getBlendMode(int mode) { switch (mode)