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;
}
Exemplo n.º 2
0
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);
   }
}