Ogre::SceneNode *TutorialApplication::loadBSP(std::shared_ptr<l2p::UModel> m, bool ignoreNonVisible) { l2p::Name name = m->package->name; std::vector<float> vertex_data; std::vector<uint32_t> index_buf; l2p::Box bounds; // Build vertex and index buffer. for (auto ni = m->nodes.begin(), ne = m->nodes.end(); ni != ne; ++ni) { l2p::BSPNode &n = *ni; l2p::BSPSurface &s = m->surfaces[n.surface]; if (ignoreNonVisible && ignoreNode(m.get(), n, s)) continue; uint32_t vert_start = vertex_data.size() / 8; const Ogre::Vector3 uvec = ogre_cast(m->vectors[s.U]); const Ogre::Vector3 vvec = ogre_cast(m->vectors[s.V]); const Ogre::Vector3 base = ogre_cast(m->points[s.base]); int usize = 0; int vsize = 0; std::shared_ptr<l2p::UTexture> mat = s.material; if (mat) { usize = mat->USize; vsize = mat->VSize; } if (usize == 0 || vsize == 0) usize = vsize = 64; // Vertex buffer. if (n.num_verticies > 0) { l2p::Vector Normal = m->vectors[s.normal]; for (uint32_t vert_index = 0; vert_index < n.num_verticies; ++vert_index) { const l2p::Vector &pos = m->points[m->vertexes[n.vert_pool + vert_index].vertex]; const Ogre::Vector3 dist(ogre_cast(pos) - base); const Ogre::Vector2 tcoord((dist | uvec) / float(usize), (dist | vvec) / float(vsize)); bounds += pos; vertex_data.push_back(pos.X); vertex_data.push_back(pos.Y); vertex_data.push_back(pos.Z); vertex_data.push_back(Normal.X); vertex_data.push_back(Normal.Y); vertex_data.push_back(Normal.Z); vertex_data.push_back(tcoord.x); vertex_data.push_back(tcoord.y); } if (s.flags & l2p::PF_TwoSided) { for (uint32_t vert_index = 0; vert_index < n.num_verticies; ++vert_index) { const l2p::Vector &pos = m->points[m->vertexes[n.vert_pool + vert_index].vertex]; const Ogre::Vector3 dist(ogre_cast(pos) - base); const Ogre::Vector2 tcoord((dist | uvec) / float(usize), (dist | vvec) / float(vsize)); vertex_data.push_back(pos.X); vertex_data.push_back(pos.Y); vertex_data.push_back(pos.Z); vertex_data.push_back(Normal.X); vertex_data.push_back(Normal.Y); vertex_data.push_back(-Normal.Z); vertex_data.push_back(tcoord.x); vertex_data.push_back(tcoord.y); } } } // Index buffer. for (int verti = 2; verti < n.num_verticies; ++verti) { index_buf.push_back(vert_start); index_buf.push_back(vert_start + verti - 1); index_buf.push_back(vert_start + verti); } if (s.flags & l2p::PF_TwoSided) { for (int verti = 2; verti < n.num_verticies; ++verti) { index_buf.push_back(vert_start); index_buf.push_back(vert_start + verti); index_buf.push_back(vert_start + verti - 1); } } } if (vertex_data.size() == 0 || index_buf.size() == 0) return nullptr; Ogre::MeshPtr mesh = Ogre::MeshManager::getSingleton().createManual(Ogre::String(name) + Ogre::String(m->name), "General"); Ogre::VertexData *data = new Ogre::VertexData(); mesh->sharedVertexData = data; data->vertexCount = vertex_data.size() / 8; Ogre::VertexDeclaration *decl = data->vertexDeclaration; uint32_t offset = 0; decl->addElement(0, offset, Ogre::VET_FLOAT3, Ogre::VES_POSITION); offset += Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3); decl->addElement(0, offset, Ogre::VET_FLOAT3, Ogre::VES_NORMAL); offset += Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3); decl->addElement(0, offset, Ogre::VET_FLOAT2, Ogre::VES_TEXTURE_COORDINATES); offset += Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT2); Ogre::HardwareVertexBufferSharedPtr vbuf = Ogre::HardwareBufferManager::getSingleton().createVertexBuffer( offset, data->vertexCount, Ogre::HardwareBuffer::HBU_STATIC_WRITE_ONLY); vbuf->writeData(0, vbuf->getSizeInBytes(), &vertex_data.front(), true); data->vertexBufferBinding->setBinding(0, vbuf); // Setup index buffer. Ogre::HardwareIndexBufferSharedPtr ibuf = Ogre::HardwareBufferManager::getSingleton().createIndexBuffer( Ogre::HardwareIndexBuffer::IT_32BIT, index_buf.size(), Ogre::HardwareBuffer::HBU_STATIC_WRITE_ONLY); ibuf->writeData(0, ibuf->getSizeInBytes(), &index_buf.front(), true); Ogre::SubMesh *subMesh = mesh->createSubMesh(); subMesh->useSharedVertices = true; subMesh->indexData->indexBuffer = ibuf; subMesh->indexData->indexCount = index_buf.size(); subMesh->indexData->indexStart = 0; mesh->_setBounds(Ogre::AxisAlignedBox(bounds.min.X, bounds.min.Y, bounds.min.Z, bounds.max.X, bounds.max.Y, bounds.max.Z)); mesh->_setBoundingSphereRadius((std::max(bounds.max.X - bounds.min.X, std::max(bounds.max.Y - bounds.min.Y, bounds.max.Z - bounds.min.Z))) / 2.0); mesh->load(); Ogre::Entity *ent = mSceneMgr->createEntity(Ogre::String(name) + Ogre::String(m->name) + "E", Ogre::String(name) + Ogre::String(m->name)); ent->setUserAny(Ogre::Any(static_cast<l2p::UObject*>(m.get()))); ent->setMaterialName("StaticMesh/Default"); Ogre::SceneNode *node = mUnrealCordNode->createChildSceneNode(); node->attachObject(ent); return node; }
void TSShapeLoader::recurseSubshape(AppNode* appNode, S32 parentIndex, bool recurseChildren) { // Ignore local bounds nodes if (appNode->isBounds()) return; S32 subShapeNum = shape->subShapeFirstNode.size()-1; Subshape* subshape = subshapes[subShapeNum]; // Check if we should collapse this node S32 myIndex; if (ignoreNode(appNode->getName())) { myIndex = parentIndex; } else { // Check that adding this node will not exceed the maximum node count if (shape->nodes.size() >= MAX_TS_SET_SIZE) return; myIndex = shape->nodes.size(); String nodeName = getUniqueName(appNode->getName(), cmpShapeName, shape->names); // Create the 3space node shape->nodes.increment(); shape->nodes.last().nameIndex = shape->addName(nodeName); shape->nodes.last().parentIndex = parentIndex; shape->nodes.last().firstObject = -1; shape->nodes.last().firstChild = -1; shape->nodes.last().nextSibling = -1; // Add the AppNode to a matching list (so AppNodes can be accessed using 3space // node indices) appNodes.push_back(appNode); appNodes.last()->mParentIndex = parentIndex; // Check for NULL detail or AutoBillboard nodes (no children or geometry) if ((appNode->getNumChildNodes() == 0) && (appNode->getNumMesh() == 0)) { S32 size = 0x7FFFFFFF; String dname(String::GetTrailingNumber(appNode->getName(), size)); if (dStrEqual(dname, "nulldetail") && (size != 0x7FFFFFFF)) { shape->addDetail("detail", size, subShapeNum); } else if (appNode->isBillboard() && (size != 0x7FFFFFFF)) { // AutoBillboard detail S32 numEquatorSteps = 4; S32 numPolarSteps = 0; F32 polarAngle = 0.0f; S32 dl = 0; S32 dim = 64; bool includePoles = true; appNode->getInt("BB::EQUATOR_STEPS", numEquatorSteps); appNode->getInt("BB::POLAR_STEPS", numPolarSteps); appNode->getFloat("BB::POLAR_ANGLE", polarAngle); appNode->getInt("BB::DL", dl); appNode->getInt("BB::DIM", dim); appNode->getBool("BB::INCLUDE_POLES", includePoles); S32 detIndex = shape->addDetail( "bbDetail", size, -1 ); shape->details[detIndex].bbEquatorSteps = numEquatorSteps; shape->details[detIndex].bbPolarSteps = numPolarSteps; shape->details[detIndex].bbDetailLevel = dl; shape->details[detIndex].bbDimension = dim; shape->details[detIndex].bbIncludePoles = includePoles; shape->details[detIndex].bbPolarAngle = polarAngle; } } } // Collect geometry for (U32 iMesh = 0; iMesh < appNode->getNumMesh(); iMesh++) { AppMesh* mesh = appNode->getMesh(iMesh); if (!ignoreMesh(mesh->getName())) { subshape->objMeshes.push_back(mesh); subshape->objNodes.push_back(mesh->isSkin() ? -1 : myIndex); } } // Create children if (recurseChildren) { for (int iChild = 0; iChild < appNode->getNumChildNodes(); iChild++) recurseSubshape(appNode->getChildNode(iChild), myIndex, true); } }