//----------------------------------------------------------------------------- MeshPtr ManualObject::convertToMesh(const String& meshName, const String& groupName) { if (mCurrentSection) { OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "You cannot call convertToMesh() whilst you are in the middle of " "defining the object; call end() first.", "ManualObject::convertToMesh"); } if (mSectionList.empty()) { OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "No data defined to convert to a mesh.", "ManualObject::convertToMesh"); } MeshPtr m = MeshManager::getSingleton().createManual(meshName, groupName); for (SectionList::iterator i = mSectionList.begin(); i != mSectionList.end(); ++i) { ManualObjectSection* sec = *i; RenderOperation* rop = sec->getRenderOperation(); SubMesh* sm = m->createSubMesh(); sm->useSharedVertices = false; sm->operationType = rop->operationType; sm->setMaterialName(sec->getMaterialName(), groupName); // Copy vertex data; replicate buffers too sm->vertexData = rop->vertexData->clone(true); // Copy index data; replicate buffers too; delete the default, old one to avoid memory leaks // check if index data is present if (rop->indexData) { // Copy index data; replicate buffers too; delete the default, old one to avoid memory leaks OGRE_DELETE sm->indexData; sm->indexData = rop->indexData->clone(true); } } // update bounds m->_setBounds(mAABB); m->_setBoundingSphereRadius(mRadius); m->load(); return m; }
void GeomUtils::createCone(const Ogre::String& strName , float radius , float height, int nVerticesInBase) { MeshPtr pCone = MeshManager::getSingleton().createManual(strName, ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME); SubMesh *pConeVertex = pCone->createSubMesh(); pCone->sharedVertexData = new VertexData(); createCone(pCone->sharedVertexData, pConeVertex->indexData , radius , height , nVerticesInBase); // Generate face list pConeVertex->useSharedVertices = true; // the original code was missing this line: pCone->_setBounds( AxisAlignedBox( Vector3(-radius, 0, -radius), Vector3(radius, height, radius) ), false ); pCone->_setBoundingSphereRadius(Math::Sqrt(height*height + radius*radius)); // this line makes clear the mesh is loaded (avoids memory leaks) pCone->load(); }
void _prepareMesh() { int i,lvl ; mesh = MeshManager::getSingleton().createManual(name, ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME) ; subMesh = mesh->createSubMesh(); subMesh->useSharedVertices=false; int numVertices = 4 ; if (first) { // first Circle, create some static common data first = false ; // static buffer for position and normals posnormVertexBuffer = HardwareBufferManager::getSingleton().createVertexBuffer( 6*sizeof(float), // size of one vertex data 4, // number of vertices HardwareBuffer::HBU_STATIC_WRITE_ONLY, // usage false); // no shadow buffer float *posnormBufData = (float*) posnormVertexBuffer-> lock(HardwareBuffer::HBL_DISCARD); for(i=0;i<numVertices;i++) { posnormBufData[6*i+0]=((Real)(i%2)-0.5f)*CIRCLE_SIZE; // pos X posnormBufData[6*i+1]=0; // pos Y posnormBufData[6*i+2]=((Real)(i/2)-0.5f)*CIRCLE_SIZE; // pos Z posnormBufData[6*i+3]=0 ; // normal X posnormBufData[6*i+4]=1 ; // normal Y posnormBufData[6*i+5]=0 ; // normal Z } posnormVertexBuffer->unlock(); // static buffers for 16 sets of texture coordinates texcoordsVertexBuffers = new HardwareVertexBufferSharedPtr[16]; for(lvl=0;lvl<16;lvl++) { texcoordsVertexBuffers[lvl] = HardwareBufferManager::getSingleton().createVertexBuffer( 2*sizeof(float), // size of one vertex data numVertices, // number of vertices HardwareBuffer::HBU_STATIC_WRITE_ONLY, // usage false); // no shadow buffer float *texcoordsBufData = (float*) texcoordsVertexBuffers[lvl]-> lock(HardwareBuffer::HBL_DISCARD); float x0 = (Real)(lvl % 4) * 0.25 ; float y0 = (Real)(lvl / 4) * 0.25 ; y0 = 0.75-y0 ; // upside down for(i=0;i<4;i++) { texcoordsBufData[i*2 + 0]= x0 + 0.25 * (Real)(i%2) ; texcoordsBufData[i*2 + 1]= y0 + 0.25 * (Real)(i/2) ; } texcoordsVertexBuffers[lvl]->unlock(); } // Index buffer for 2 faces unsigned short faces[6] = {2,1,0, 2,3,1}; indexBuffer = HardwareBufferManager::getSingleton().createIndexBuffer( HardwareIndexBuffer::IT_16BIT, 6, HardwareBuffer::HBU_STATIC_WRITE_ONLY); indexBuffer->writeData(0, indexBuffer->getSizeInBytes(), faces, true); // true? } // Initialize vertex data subMesh->vertexData = new VertexData(); subMesh->vertexData->vertexStart = 0; subMesh->vertexData->vertexCount = 4; // first, set vertex buffer bindings VertexBufferBinding *vbind = subMesh->vertexData->vertexBufferBinding ; vbind->setBinding(0, posnormVertexBuffer); vbind->setBinding(1, texcoordsVertexBuffers[0]); // now, set vertex buffer declaration VertexDeclaration *vdecl = subMesh->vertexData->vertexDeclaration ; vdecl->addElement(0, 0, VET_FLOAT3, VES_POSITION); vdecl->addElement(0, 3*sizeof(float), VET_FLOAT3, VES_NORMAL); vdecl->addElement(1, 0, VET_FLOAT2, VES_TEXTURE_COORDINATES); // Initialize index data subMesh->indexData->indexBuffer = indexBuffer; subMesh->indexData->indexStart = 0; subMesh->indexData->indexCount = 6; // set mesh bounds AxisAlignedBox circleBounds(-CIRCLE_SIZE/2.0f, 0, -CIRCLE_SIZE/2.0f, CIRCLE_SIZE/2.0f, 0, CIRCLE_SIZE/2.0f); mesh->_setBounds(circleBounds); mesh->load(); mesh->touch(); }
/* ******************************************************************************* | implement of CGrassSticks ******************************************************************************* */ void CGrassSticks::createGrassMesh() { MeshPtr mesh = MeshManager::getSingleton().createManual(GRASS_MESH_NAME, ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME); // create a submesh with the grass material SubMesh* sm = mesh->createSubMesh(); sm->setMaterialName("Examples/GrassBlades"); sm->useSharedVertices = false; sm->vertexData = OGRE_NEW VertexData(); sm->vertexData->vertexStart = 0; sm->vertexData->vertexCount = 12; sm->indexData->indexCount = 18; // specify a vertex format declaration for our mesh: 3 floats for position, 3 floats for normal, 2 floats for UV VertexDeclaration* decl = sm->vertexData->vertexDeclaration; decl->addElement(0, 0, VET_FLOAT3, VES_POSITION); decl->addElement(0, sizeof(float) * 3, VET_FLOAT3, VES_NORMAL); decl->addElement(0, sizeof(float) * 6, VET_FLOAT2, VES_TEXTURE_COORDINATES, 0); // create a vertex buffer HardwareVertexBufferSharedPtr vb = HardwareBufferManager::getSingleton().createVertexBuffer (decl->getVertexSize(0), sm->vertexData->vertexCount, HardwareBuffer::HBU_STATIC_WRITE_ONLY); GrassVertex* verts = (GrassVertex*)vb->lock(HardwareBuffer::HBL_DISCARD); // start filling in vertex data for (unsigned int i = 0; i < 3; i++) // each grass mesh consists of 3 planes { // planes intersect along the Y axis with 60 degrees between them Real x = Math::Cos(Degree(i * 60)) * GRASS_WIDTH / 2; Real z = Math::Sin(Degree(i * 60)) * GRASS_WIDTH / 2; for (unsigned int j = 0; j < 4; j++) // each plane has 4 vertices { GrassVertex& vert = verts[i * 4 + j]; vert.x = j < 2 ? -x : x; vert.y = j % 2 ? 0 : GRASS_HEIGHT; vert.z = j < 2 ? -z : z; // all normals point straight up vert.nx = 0; vert.ny = 1; vert.nz = 0; vert.u = j < 2 ? 0 : 1; vert.v = j % 2; } } vb->unlock(); // commit vertex changes sm->vertexData->vertexBufferBinding->setBinding(0, vb); // bind vertex buffer to our submesh // create an index buffer sm->indexData->indexBuffer = HardwareBufferManager::getSingleton().createIndexBuffer (HardwareIndexBuffer::IT_16BIT, sm->indexData->indexCount, HardwareBuffer::HBU_STATIC_WRITE_ONLY); // start filling in index data Ogre::uint16* indices = (Ogre::uint16*)sm->indexData->indexBuffer->lock(HardwareBuffer::HBL_DISCARD); for (unsigned int i = 0; i < 3; i++) // each grass mesh consists of 3 planes { unsigned int off = i * 4; // each plane consists of 2 triangles *indices++ = 0 + off; *indices++ = 3 + off; *indices++ = 1 + off; *indices++ = 0 + off; *indices++ = 2 + off; *indices++ = 3 + off; } sm->indexData->indexBuffer->unlock(); // commit index changes // update mesh AABB Ogre::AxisAlignedBox aabb; aabb.setExtents(-1,-1,-1,1,1,1); mesh->_setBounds(aabb); // Ogre::MeshSerializer serial; // serial.exportMesh(mesh.getPointer(), "grass.mesh"); }
Mesh *GrassLoader::generateGrass_SPRITE(PageInfo &page, GrassLayer *layer, float *grassPositions, unsigned int grassCount) { //Calculate the number of quads to be added unsigned int quadCount; quadCount = grassCount; // check for overflows of the uint16's unsigned int maxUInt16 = std::numeric_limits<uint16>::max(); if(grassCount > maxUInt16) { LogManager::getSingleton().logMessage("grass count overflow: you tried to use more than " + StringConverter::toString(maxUInt16) + " (thats the maximum) grass meshes for one page"); return 0; } if(quadCount > maxUInt16) { LogManager::getSingleton().logMessage("quad count overflow: you tried to use more than " + StringConverter::toString(maxUInt16) + " (thats the maximum) grass meshes for one page"); return 0; } //Create manual mesh to store grass quads MeshPtr mesh = MeshManager::getSingleton().createManual(getUniqueID(), ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME); SubMesh *subMesh = mesh->createSubMesh(); subMesh->useSharedVertices = false; //Setup vertex format information subMesh->vertexData = new VertexData; subMesh->vertexData->vertexStart = 0; subMesh->vertexData->vertexCount = 4 * quadCount; VertexDeclaration* dcl = subMesh->vertexData->vertexDeclaration; size_t offset = 0; dcl->addElement(0, offset, VET_FLOAT3, VES_POSITION); offset += VertexElement::getTypeSize(VET_FLOAT3); dcl->addElement(0, offset, VET_FLOAT4, VES_NORMAL); offset += VertexElement::getTypeSize(VET_FLOAT4); dcl->addElement(0, offset, VET_COLOUR, VES_DIFFUSE); offset += VertexElement::getTypeSize(VET_COLOUR); dcl->addElement(0, offset, VET_FLOAT2, VES_TEXTURE_COORDINATES); offset += VertexElement::getTypeSize(VET_FLOAT2); //Populate a new vertex buffer with grass HardwareVertexBufferSharedPtr vbuf = HardwareBufferManager::getSingleton() .createVertexBuffer(offset, subMesh->vertexData->vertexCount, HardwareBuffer::HBU_STATIC_WRITE_ONLY, false); float* pReal = static_cast<float*>(vbuf->lock(HardwareBuffer::HBL_DISCARD)); //Calculate size variance float rndWidth = layer->maxWidth - layer->minWidth; float rndHeight = layer->maxHeight - layer->minHeight; float minY = Math::POS_INFINITY, maxY = Math::NEG_INFINITY; float *posPtr = grassPositions; //Position array "iterator" for (uint16 i = 0; i < grassCount; ++i) { //Get the x and z positions from the position array float x = *posPtr++; float z = *posPtr++; //Calculate height float y; if (heightFunction){ y = heightFunction(x, z, heightFunctionUserData); } else { y = 0; } float x1 = (x - page.centerPoint.x); float z1 = (z - page.centerPoint.z); //Get the color at the grass position uint32 color; if (layer->colorMap) color = layer->colorMap->getColorAt(x, z, layer->mapBounds); else color = 0xFFFFFFFF; //Calculate size float rnd = *posPtr++; //The same rnd value is used for width and height to maintain aspect ratio float halfXScale = (layer->minWidth + rndWidth * rnd) * 0.5f; float scaleY = (layer->minHeight + rndHeight * rnd); //Randomly mirror grass textures float uvLeft, uvRight; if (*posPtr++ > 0.5f){ uvLeft = 0; uvRight = 1; } else { uvLeft = 1; uvRight = 0; } //Add vertices *pReal++ = x1; *pReal++ = y; *pReal++ = z1; //center position *pReal++ = -halfXScale; *pReal++ = scaleY; *pReal++ = 0; *pReal++ = 0; //normal (used to store relative corner positions) *((uint32*)pReal++) = color; //color *pReal++ = uvLeft; *pReal++ = 0; //uv *pReal++ = x1; *pReal++ = y; *pReal++ = z1; //center position *pReal++ = +halfXScale; *pReal++ = scaleY; *pReal++ = 0; *pReal++ = 0; //normal (used to store relative corner positions) *((uint32*)pReal++) = color; //color *pReal++ = uvRight; *pReal++ = 0; //uv *pReal++ = x1; *pReal++ = y; *pReal++ = z1; //center position *pReal++ = -halfXScale; *pReal++ = 0.0f; *pReal++ = 0; *pReal++ = 0; //normal (used to store relative corner positions) *((uint32*)pReal++) = color; //color *pReal++ = uvLeft; *pReal++ = 1; //uv *pReal++ = x1; *pReal++ = y; *pReal++ = z1; //center position *pReal++ = +halfXScale; *pReal++ = 0.0f; *pReal++ = 0; *pReal++ = 0; //normal (used to store relative corner positions) *((uint32*)pReal++) = color; //color *pReal++ = uvRight; *pReal++ = 1; //uv //Update bounds if (y < minY) minY = y; if (y + scaleY > maxY) maxY = y + scaleY; } vbuf->unlock(); subMesh->vertexData->vertexBufferBinding->setBinding(0, vbuf); //Populate index buffer subMesh->indexData->indexStart = 0; subMesh->indexData->indexCount = 6 * quadCount; subMesh->indexData->indexBuffer = HardwareBufferManager::getSingleton() .createIndexBuffer(HardwareIndexBuffer::IT_16BIT, subMesh->indexData->indexCount, HardwareBuffer::HBU_STATIC_WRITE_ONLY); uint16* pI = static_cast<uint16*>(subMesh->indexData->indexBuffer->lock(HardwareBuffer::HBL_DISCARD)); for (uint16 i = 0; i < quadCount; ++i) { uint16 offset = i * 4; *pI++ = 0 + offset; *pI++ = 2 + offset; *pI++ = 1 + offset; *pI++ = 1 + offset; *pI++ = 2 + offset; *pI++ = 3 + offset; } subMesh->indexData->indexBuffer->unlock(); //subMesh->setBuildEdgesEnabled(autoEdgeBuildEnabled); //Finish up mesh AxisAlignedBox bounds(page.bounds.left - page.centerPoint.x, minY, page.bounds.top - page.centerPoint.z, page.bounds.right - page.centerPoint.x, maxY, page.bounds.bottom - page.centerPoint.z); mesh->_setBounds(bounds); Vector3 temp = bounds.getMaximum() - bounds.getMinimum(); mesh->_setBoundingSphereRadius(temp.length() * 0.5f); LogManager::getSingleton().setLogDetail(static_cast<LoggingLevel>(0)); mesh->setAutoBuildEdgeLists(autoEdgeBuildEnabled); mesh->load(); LogManager::getSingleton().setLogDetail(LL_NORMAL); //Apply grass material to mesh subMesh->setMaterialName(layer->material->getName()); //Return the mesh return mesh.getPointer(); }
void createSphere(const std::string& strName, const float r, const int nRings = 16, const int nSegments = 16) { MeshPtr pSphere = MeshManager::getSingleton().createManual(strName, ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME); SubMesh *pSphereVertex = pSphere->createSubMesh(); pSphere->sharedVertexData = new VertexData(); VertexData* vertexData = pSphere->sharedVertexData; // define the vertex format VertexDeclaration* vertexDecl = vertexData->vertexDeclaration; size_t currOffset = 0; // positions vertexDecl->addElement(0, currOffset, VET_FLOAT3, VES_POSITION); currOffset += VertexElement::getTypeSize(VET_FLOAT3); // normals vertexDecl->addElement(0, currOffset, VET_FLOAT3, VES_NORMAL); currOffset += VertexElement::getTypeSize(VET_FLOAT3); // two dimensional texture coordinates vertexDecl->addElement(0, currOffset, VET_FLOAT2, VES_TEXTURE_COORDINATES, 0); currOffset += VertexElement::getTypeSize(VET_FLOAT2); // allocate the vertex buffer vertexData->vertexCount = (nRings + 1) * (nSegments + 1); HardwareVertexBufferSharedPtr vBuf = HardwareBufferManager::getSingleton().createVertexBuffer(vertexDecl->getVertexSize(0), vertexData->vertexCount, HardwareBuffer::HBU_STATIC_WRITE_ONLY, false); VertexBufferBinding* binding = vertexData->vertexBufferBinding; binding->setBinding(0, vBuf); float* pVertex = static_cast<float*>(vBuf->lock(HardwareBuffer::HBL_DISCARD)); // allocate index buffer pSphereVertex->indexData->indexCount = 6 * nRings * (nSegments + 1); pSphereVertex->indexData->indexBuffer = HardwareBufferManager::getSingleton().createIndexBuffer(HardwareIndexBuffer::IT_16BIT, pSphereVertex->indexData->indexCount, HardwareBuffer::HBU_STATIC_WRITE_ONLY, false); HardwareIndexBufferSharedPtr iBuf = pSphereVertex->indexData->indexBuffer; unsigned short* pIndices = static_cast<unsigned short*>(iBuf->lock(HardwareBuffer::HBL_DISCARD)); float fDeltaRingAngle = (Math::PI / nRings); float fDeltaSegAngle = (2 * Math::PI / nSegments); unsigned short wVerticeIndex = 0; // Generate the group of rings for the sphere for (int ring = 0; ring <= nRings; ring++) { float r0 = r * sinf(ring * fDeltaRingAngle); float y0 = r * cosf(ring * fDeltaRingAngle); // Generate the group of segments for the current ring for (int seg = 0; seg <= nSegments; seg++) { float x0 = r0 * sinf(seg * fDeltaSegAngle); float z0 = r0 * cosf(seg * fDeltaSegAngle); // Add one vertex to the strip which makes up the sphere *pVertex++ = x0; *pVertex++ = y0; *pVertex++ = z0; Vector3 vNormal = Vector3(x0, y0, z0).normalisedCopy(); *pVertex++ = vNormal.x; *pVertex++ = vNormal.y; *pVertex++ = vNormal.z; *pVertex++ = (float)seg / (float)nSegments; *pVertex++ = (float)ring / (float)nRings; if (ring != nRings) { // each vertex (except the last) has six indices pointing to it *pIndices++ = wVerticeIndex + nSegments + 1; *pIndices++ = wVerticeIndex; *pIndices++ = wVerticeIndex + nSegments; *pIndices++ = wVerticeIndex + nSegments + 1; *pIndices++ = wVerticeIndex + 1; *pIndices++ = wVerticeIndex; wVerticeIndex++; } }; // end for seg } // end for ring // Unlock vBuf->unlock(); iBuf->unlock(); // Generate face list pSphereVertex->useSharedVertices = true; // the original code was missing this line: pSphere->_setBounds(AxisAlignedBox(Vector3(-r, -r, -r), Vector3(r, r, r)), false); pSphere->_setBoundingSphereRadius(r); // this line makes clear the mesh is loaded (avoids memory leaks) pSphere->load(); }
MeshPtr MeshMergeTool::merge(const Ogre::String& name, const Ogre::String& resourceGroupName) { print("Baking: New Mesh started", V_HIGH); MeshPtr mp = MeshManager::getSingleton().createManual(name, resourceGroupName); if (!mBaseSkeleton.isNull()) { mp->setSkeletonName(mBaseSkeleton->getName()); } AxisAlignedBox totalBounds = AxisAlignedBox(); for (std::vector<Ogre::MeshPtr>::iterator it = mMeshes.begin(); it != mMeshes.end(); ++it) { print("Baking: adding submeshes for " + (*it)->getName(), V_HIGH); // insert all submeshes for (Ogre::ushort sid = 0; sid < (*it)->getNumSubMeshes(); ++sid) { SubMesh* sub = (*it)->getSubMesh(sid); const String name = findSubmeshName((*it), sid); // create submesh with correct name SubMesh* newsub; if (name.length() == 0) { newsub = mp->createSubMesh(); } else { /// @todo check if a submesh with this name has been created before newsub = mp->createSubMesh(name); } newsub->useSharedVertices = sub->useSharedVertices; // add index newsub->indexData = sub->indexData->clone(); // add geometry if (!newsub->useSharedVertices) { newsub->vertexData = sub->vertexData->clone(); if (!mBaseSkeleton.isNull()) { // build bone assignments SubMesh::BoneAssignmentIterator bit = sub->getBoneAssignmentIterator(); while (bit.hasMoreElements()) { VertexBoneAssignment vba = bit.getNext(); newsub->addBoneAssignment(vba); } } } newsub->setMaterialName(sub->getMaterialName()); // Add vertex animations for this submesh Animation *anim = 0; for (unsigned short i = 0; i < (*it)->getNumAnimations(); ++i) { anim = (*it)->getAnimation(i); // get or create the animation for the new mesh Animation *newanim; if (mp->hasAnimation(anim->getName())) { newanim = mp->getAnimation(anim->getName()); } else { newanim = mp->createAnimation(anim->getName(), anim->getLength()); } print("Baking: adding vertex animation " + anim->getName() + " for " + (*it)->getName(), V_HIGH); Animation::VertexTrackIterator vti=anim->getVertexTrackIterator(); while (vti.hasMoreElements()) { VertexAnimationTrack *vt = vti.getNext(); // handle=0 targets the main mesh, handle i (where i>0) targets submesh i-1. // In this case there are only submeshes so index 0 will not be used. unsigned short handle = mp->getNumSubMeshes(); VertexAnimationTrack* newvt = newanim->createVertexTrack( handle, vt->getAssociatedVertexData()->clone(), vt->getAnimationType()); for (int keyFrameIndex = 0; keyFrameIndex < vt->getNumKeyFrames(); ++keyFrameIndex) { switch (vt->getAnimationType()) { case VAT_MORPH: { // copy the keyframe vertex buffer VertexMorphKeyFrame *kf = vt->getVertexMorphKeyFrame(keyFrameIndex); VertexMorphKeyFrame *newkf = newvt->createVertexMorphKeyFrame(kf->getTime()); // This creates a ref to the buffer in the original model // so don't delete it until the export is completed. newkf->setVertexBuffer(kf->getVertexBuffer()); break; } case VAT_POSE: { /// @todo implement pose amination merge break; } case VAT_NONE: default: { break; } } } } } print("Baking: adding submesh '" + name + "' with material " + sub->getMaterialName(), V_HIGH); } // sharedvertices if ((*it)->sharedVertexData) { /// @todo merge with existing sharedVertexData if (!mp->sharedVertexData) { mp->sharedVertexData = (*it)->sharedVertexData->clone(); } if (!mBaseSkeleton.isNull()) { Mesh::BoneAssignmentIterator bit = (*it)->getBoneAssignmentIterator(); while (bit.hasMoreElements()) { VertexBoneAssignment vba = bit.getNext(); mp->addBoneAssignment(vba); } } } print("Baking: adding bounds for " + (*it)->getName(), V_HIGH); // add bounds totalBounds.merge((*it)->getBounds()); } mp->_setBounds(totalBounds); /// @todo merge submeshes with same material /// @todo add parameters mp->buildEdgeList(); print("Baking: Finished", V_HIGH); reset(); return mp; }
void SplineRoad::RebuildRoadInt(bool editorAlign) { if (!rebuild && !editorAlign) return; rebuild = false; // segments range int segs = getNumPoints(); if (segs == 0 || segs == 1) return; using std::vector; using std::min; using std::max; UpdRot(); // if (vSegs.size() != segs || editorAlign) iDirtyId = -1; // force full int sMin = 0, sMax = segs; // update 4 segs only (fast) if (iDirtyId != -1 && segs >= 4) { // else !isLooped case ... sMin =/* max(0,*/ iDirtyId-2; sMax =/* min(segs,*/ iDirtyId+2; } // full rebuild QTimer ti; ti.update(); /// time if (iDirtyId == -1) { DestroyRoad(); for (int seg=0; seg < segs; ++seg) { RoadSeg rs; rs.empty = true; vSegs.push_back(rs); } } /// Auto angles prepass ... if (segs > 2) for (int seg=0; seg < segs; ++seg) { //int seg1 = (seg+1) % segs; // next int seg0 = (seg-1+segs) % segs; // prev if (mP[seg].aType == AT_Manual) { mP[seg].aYaw = mP[seg].mYaw; mP[seg].aRoll = mP[seg].mRoll; } else { mP[seg].aRoll = 0.f; /// ... roll getangle?, +180 loops?, len const Real dist = 0.1f; Vector3 vl = GetLenDir(seg, 0.f, dist) + GetLenDir(seg0, 1.f-dist, 1.f); //vl.normalise(); Vector3 vw = Vector3(vl.z, 0.f, -vl.x); //vw.normalise(); mP[seg].aYaw = GetAngle(vw.x, vw.z) *180.f/PI_d; if (mP[seg].aType == AT_Both) { mP[seg].aYaw += mP[seg].mYaw; mP[seg].aRoll += mP[seg].mRoll; } } } ///-------------------------------------------------------------------------------------------------------------------------- /// LOD ///-------------------------------------------------------------------------------------------------------------------------- //> data at lod 0 vector<int> viLSteps0; vector<Real> vSegTc0; vector<Vector3> vnSeg0; // normals const int lodDivs[LODs] = {1,2,4,8}; for (int lod = 0; lod < LODs; ++lod) { int lodDiv = lodDivs[lod]; Real lenDiv = lenDiv0 * lodDiv; LogR("LOD: "+toStr(lod)+" ---"); /// segment data pre pass //--------------------------------------------------------------------------------------- //> data at cur lod vector<int> viL, viW; // vi num steps for seg Length/Width vector<int> vbSegMrg; // bool 0 if seg merged, 1 if new vector<Real> vSegTc, vSegLen; vector<Vector3> vwSeg; vector<vector <int> > viwLS; // width steps per length point, for each seg vector<int> viwEq; // 1 if equal width steps at whole length, in seg Real sumLenMrg = 0.f, ltc = 0.f; int mrgGrp = 0; //# stats Real roadLen = 0.f, rdOnT = 0.f, rdPipe = 0.f, avgWidth = 0.f, stMaxH = FLT_MIN, stMinH = FLT_MAX; //if (lod == 0)? LogR("--- seg prepass ---"); for (int seg=0; seg < segs; ++seg) { int seg1 = (seg+1) % segs; // next int seg0 = (seg-1+segs) % segs; // prev // width steps -- Real sp = mP[seg].pipe, sp1 = mP[seg1].pipe, sp0 = mP[seg0].pipe; Real p = sp * iwPmul, pl = max(sp, sp1)* iwPmul/4; if (p < 0.f) p = 1.f; else p = 1.f + p; if (pl< 0.f) pl= 1.f; else pl= 1.f + pl; int iw = max(1, (int)(p * iw0 / lodDiv)); //* wid/widDiv.. viW.push_back(iw); int iwl = max(1, (int)(pl * iw0 / lodDiv)); // length steps | Real len = GetSegLen(seg); int il = int(len / lenDiv) / iwl * iwl + iwl; Real la = 1.f / il; viL.push_back(il); vSegLen.push_back(len); roadLen += len; //# if (sp > 0.f || sp1 > 0.f) rdPipe += len; //# ///- Merge conditions sumLenMrg += len; // mtr changes int hid = mP[seg].idMtr, hid1 = mP[seg1].idMtr, hid0 = mP[seg0].idMtr; LogR(toStr(sp0) + " " + toStr(sp) + " " + toStr(sp1)); // merge road and pipe segs, don't merge transitions if (sp != sp1 || sp != sp0 || hid != hid1 || hid != hid0) { sumLenMrg = 0.f; ++mrgGrp; vbSegMrg.push_back(1); } else // onTer change if (mP[seg].onTer != mP[seg1].onTer || mP[seg].onTer != mP[seg0].onTer) { sumLenMrg = 0.f; ++mrgGrp; vbSegMrg.push_back(1); } else if (sumLenMrg >= setMrgLen) { sumLenMrg -= setMrgLen; ++mrgGrp; vbSegMrg.push_back(1); // bNew }else vbSegMrg.push_back(0); // merged LogR("seg "+toStr(seg)+" iw "+toStr(iw)+" il "+toStr(il)+" pp "+toStr(sp)); if (lod==0) viLSteps0.push_back(il); /// length <dir> | Vector3 vl = GetLenDir(seg, 0, la), vw; vl.normalise(); Real ay = mP[seg].aYaw, ar = mP[seg].aRoll; /// width <dir> --- if (mP[seg].onTer && mP[seg1].onTer) // perpendicular on xz { vw = Vector3(vl.z, 0, -vl.x); vw.normalise(); //mP[seg].angle = atan2(vl.z, -vl.x)*180.f/PI_d+90.f; // set yaw.. }else vw = GetRot(ay,ar); // from angles /// normal <dir> / if (lod == 0) { Vector3 vn = vl.crossProduct(vw); vn.normalise(); //if (vn.y < 0.f) vn = -vn; // always up y+ vnSeg0.push_back(vn); } Real wiMul = mP[seg].width; if (editorAlign) // wider road for align terrain tool wiMul = wiMul*edWmul + edWadd; vw *= wiMul; vwSeg.push_back(vw); avgWidth += mP[seg].width * len; //# if (!mP[seg].onTer || !mP[seg1].onTer) rdOnT += len; //# // tcs seg il* len Real l = 0.f; for (int i = 0; i < il; ++i) // length +1 { // length dir Vector3 vl = GetLenDir(seg, l, l+la); l += la; ltc += vl.length(); } vSegTc.push_back(ltc); if (lod == 0) vSegTc0.push_back(ltc); } LogR("--- seg prepass2 viwLS ---"); for (int seg=0; seg < segs; ++seg) { int seg1 = (seg+1) % segs; // next int il = viL[seg]; vector<int> viwL; // width steps per lenght point in cur seg int iw0 = viW[seg], iw1 = viW[seg1]; //String ss=""; for (int i = -1; i <= il+1; ++i) // length +1 +2-gap { int ii = max(0, min(il, i)); int iw = iw0 + (int)( Real(ii)/Real(il) * (iw1-iw0) ); //if (i==0 || i == il) // ss += toStr(iw)+" "; viwL.push_back(iw); } int eq = iw1==iw0 ? 1 : 0; viwEq.push_back(eq); viwLS.push_back(viwL); //if (!eq) vbSegMrg[seg] = 1; //LogR("seg "+toStr(seg)+" >> "+ss); } //# stats at lod0, whole road bool stats = lod == 0 && iDirtyId == -1; if (stats) { st.Length = roadLen; st.WidthAvg = avgWidth / roadLen; st.OnTer = rdOnT / roadLen * 100.f; st.Pipes = rdPipe / roadLen * 100.f; segsMrg = mrgGrp; } //-------------------------------------------------------------------------------------------------------------------------- /// segment //-------------------------------------------------------------------------------------------------------------------------- //> mesh data W-wall C-column vector<Vector4> clr0/*empty*/, clr; vector<Vector3> pos,norm, posW,normW, posC,normC, posLod; vector<Vector2> tcs, tcsW, tcsC; Real tc1 = 0; ltc = 0; int iLmrg = 0, iLmrgW = 0, iLmrgC = 0; Vector3 vlOld; int sNum = sMax - sMin, segM = sMin;//, sNumO = sNum; while (sNum > 0) { int seg = (segM + segs) % segs; // iterator int seg1 = (seg+1) % segs; // next //if (lod == 0) //LogR("[Seg] cur: " + toStr(seg) + "/" + toStr(sNumO) + " all:" + toStr(segs));/**/ // on terrain (whole seg) bool onTer = mP[seg].onTer && mP[seg1].onTer; // on merging segs only for game in whole road rebuild // off for editor (partial, 4segs rebuild) bool bNew = true, bNxt = true; if (bMerge) { bNew = (segM == sMin/*1st*/) || vbSegMrg[seg]; bNxt = (segM+1 == sMax/*last*/) || vbSegMrg[seg1]; // next is new } if (bNew) //> new seg data { iLmrg = 0; iLmrgW = 0; iLmrgC = 0; pos.clear(); norm.clear(); tcs.clear(); clr.clear(); posW.clear(); normW.clear(); tcsW.clear(); posC.clear(); normC.clear(); tcsC.clear(); } // bullet create bool blt = true; // game always #ifdef ROAD_EDITOR // editor only sel segs for align ter tool blt = editorAlign && vSel.find(seg) != vSel.end(); #endif /// destroy old RoadSeg& rs = vSegs[seg]; if (!rs.empty && lod == 0) DestroySeg(seg); const int iwW = 7; // wall width steps - types.. const int iwC = colN; // column polygon steps // steps len int il = viL[seg]; Real la = 1.f / il; int il0= viLSteps0[seg]; Real la0= 1.f / il0 * skLen; Real l = -la0; // width //Real wi1 = abs(mP[seg].width), wi2 = abs(mP[seg1].width), wi12 = wi2-wi1; /// angles ()__ Real ay1 = mP[seg].aYaw, ay2 = mP[seg1].aYaw, ay21 = ay2-ay1; Real ar1 = mP[seg].aRoll,ar2 = mP[seg1].aRoll,ar21 = ar2-ar1; const Real asw = 180; // more than 180 swirl - wrong at start/end while (ay21 > asw) ay21 -= 2*asw; while (ay21 <-asw) ay21 += 2*asw; while (ar21 > asw) ar21 -= 2*asw; while (ar21 <-asw) ar21 += 2*asw; // tc begin,range Real tcBeg = (seg > 0) ? vSegTc[seg-1] : 0.f, tcEnd = vSegTc[seg], tcRng = tcEnd - tcBeg; Real tcBeg0= (seg > 0) ? vSegTc0[seg-1]: 0.f, tcEnd0 = vSegTc0[seg], tcRng0 = tcEnd0 - tcBeg0; Real tcRmul = tcRng0 / tcRng; //------------------------------------------------------------------------------------ // Length vertices //------------------------------------------------------------------------------------ //LogR( " __len"); if (mP[seg].idMtr >= 0) // -1 hides segment for (int i = -1; i <= il+1; ++i) // length +1 +2-gap { ++iLmrg; /// length <dir> | Vector3 vL0 = interpolate(seg, l); Vector3 vl = GetLenDir(seg, l, l+la), vw; Real len = vl.length(); vl.normalise(); // len tc if (i <= 0) ltc = 0; Real tc = ltc * tcRmul + tcBeg0; // skirt tc if (i == -1) tc =-skLen* tcRmul + tcBeg0; if (i == il+1) tc = skLen* tcRmul + tcEnd0; /// width <dir> -- if (mP[seg].onTer && mP[seg1].onTer) { vw = Vector3(vl.z, 0, -vl.x); } else /// angles ()__ { Real ay = ay1 + ay21 * l; // linear- Real ar = ar1 + ar21 * l; //Real ay = interpAYaw(seg,l); // spline~ //Real ar = interpARoll(seg,l); // err swirl.. vw = GetRot(ay,ar); // from angles } vw.normalise(); Vector3 vwn = vw; //Real wiMul = wi1 + wi12 * l; // linear- Real wiMul = interpWidth(seg, l); // spline~ if (editorAlign) // wider road for align terrain tool wiMul = wiMul*edWmul + edWadd; vw *= wiMul; // last vw = 1st form next seg if (i==il && seg < segs-1) vw = vwSeg[seg+1]; // on terrain ~~ bool onTer1 = onTer || mP[seg].onTer && i==0 || mP[seg1].onTer && i==il; /// normal <dir> / Vector3 vn = vl.crossProduct(vw); vn.normalise(); if (i==0) vn = vnSeg0[seg]; // seg start=end if (i==il) vn = vnSeg0[seg1]; //Vector3 vnu = vn; if (vnu.y < 0) vnu = -vnu; // always up y+ // width steps <-> //int iw = viW[seg]; int iw = viwLS[seg][i+1]; //i = -1 .. il+1 // pipe width Real l01 = max(0.f, min(1.f, Real(i)/Real(il) )); Real p1 = mP[seg].pipe, p2 = mP[seg1].pipe; Real pipe = p1 + (p2-p1)*l01; bool trans = (p1 == 0.f || p2 == 0.f) && !viwEq[seg]; Real trp = (p1 == 0.f) ? 1.f - l01 : l01; //LogR(" il="+toStr(i)+"/"+toStr(il)+" iw="+toStr(iw) // /*+(bNew?" New ":"") +(bNxt?" Nxt ":"")/**/); /// road ~ Width vertices //----------------------------------------------------------------------------------------------------------------- for (int w=0; w <= iw; ++w) // width +1 { // pos create Vector3 vP,vN; Real tcw = Real(w)/Real(iw); Real yTer = 0.f; if (pipe == 0.f) { // flat -- vP = vL0 + vw * (tcw - 0.5); vN = vn; yTer = mTerrain ? mTerrain->getHeightAtWorldPosition(vP.x, 0, vP.z) : 0.f; if (onTer1) // onTerrain { vP.y = yTer + fHeight * ((w==0 || w==iw) ? 0.15f : 1.f); vN = mTerrain ? getNormalAtWorldPosition(mTerrain, vP.x, vP.z, lenDiv*0.5f /*0.5f*/) : Vector3::UNIT_Y; } }else { /// pipe (_) Real oo = (tcw - 0.5)/0.5 * PI_d * pipe, so = sinf(oo), co = cosf(oo); vP = vL0 + vw * 0.5 * so + + vn * (0.5 - 0.5 * co) * wiMul; vN = vn * co + vwn * so; if (vN.y < 0.f) vN.y = -vN.y; if (trans) // transition from flat to pipe { vP += vw * (tcw - 0.5) * trp; } yTer = mTerrain ? mTerrain->getHeightAtWorldPosition(vP.x, 0, vP.z) : 0.f; } // skirt, gap patch_ if (i == -1 || i == il+1) vP -= vn * skH; // color - for minimap preview // ---~~~====~~~--- Real brdg = min(1.f, abs(vP.y - yTer) * 0.4f); //par ] height diff mul Real h = max(0.f, 1.f - abs(vP.y - yTer) / 30.f); // for grass dens tex Real blend = 0.f; //rand()%1000/1000.f; // TODO: blend 2materials...? Vector4 c(brdg,pipe, blend, h); //> data road pos.push_back(vP); norm.push_back(vN); tcs.push_back(Vector2(tcw * 1.f /**2p..*/, tc * tcMul)); clr.push_back(c); //# if (vP.y < stMinH) stMinH = vP.y; if (vP.y > stMaxH) stMaxH = vP.y; } /// wall ] //------------------------------------------------------------------------------------ struct stWiPntW { Real x,y, uv, nx,ny; }; // wall width points const static stWiPntW wiPntW[iwW+1][2] = { // section shape // normal road // pipe wall {{-0.5f, -0.1f, 0.0f, 1.0f, 0.0f}, {-0.28f, 0.7f, 0.0f, -1.0f, 0.0f}}, {{-0.5f, 1.2f, 0.5f, 0.5f, 0.5f}, {-0.28f, 0.5f, 0.2f, -0.5f, 0.5f}}, {{-0.56f, 1.2f, 0.2f, -0.5f, 0.5f}, {-0.28f, 0.0f, 0.2f, -0.5f, 0.0f}}, {{-0.56f,-0.9f, 1.6f, -0.5f,-0.5f}, {-0.2f, -0.9f, 0.5f, -0.1f,-0.5f}}, {{ 0.56f,-0.9f, 3.0f, 0.5f,-0.5f}, { 0.2f, -0.9f, 0.5f, 0.1f,-0.5f}}, {{ 0.56f, 1.2f, 1.6f, 0.5f, 0.5f}, { 0.28f, 0.0f, 0.2f, 0.5f, 0.0f}}, {{ 0.5f, 1.2f, 0.2f, -0.5f, 0.5f}, { 0.28f, 0.5f, 0.2f, 0.5f, 0.5f}}, {{ 0.5f, -0.1f, 0.5f, -1.0f, 0.0f}, { 0.28f, 0.7f, 0.2f, 1.0f, 0.0f}}}; Real uv = 0.f; // tc long if (!onTer) if (i >= 0 && i <= il) // length +1 { ++iLmrgW; for (int w=0; w <= iwW; ++w) // width +1 { int pp = (p1 > 0.f || p2 > 0.f) ? 1 : 0; // pipe wall stWiPntW wP = wiPntW[w][pp]; if (trans /*&& (w <= 3 || w >= iwW-3)*/) { wP.x *= 1 + trp; wP.y *= 1 - trp; } uv += wP.uv; Vector3 vP = vL0 + vw * wP.x + vn * wP.y; Vector3 vN = vwn * wP.nx + vn * wP.ny; vN.normalise(); //> data Wall posW.push_back(vP); normW.push_back(vN); tcsW.push_back(0.25f * Vector2(uv, tc * tcMul)); //pars } } /// columns | //------------------------------------------------------------------------------------ if (!onTer && mP[seg].cols > 0) if (i == il/2) // middle- { ++iLmrgC; const Real r = colR; // column radius for (int h=0; h <= 1; ++h) // height for (int w=0; w <= iwC; ++w) // width +1 { Real ht = (h==0) ? 0.f : vL0.y - (mTerrain ? mTerrain->getHeightAtWorldPosition(vL0) : 0.f); Real a = Real(w)/iwC *2*PI_d, //+PI_d/4.f x = r*cosf(a), y = r*sinf(a); Vector3 vlXZ(vl.x,0,vl.z); Real fl = 1.f/max(0.01f, vlXZ.length()); Vector3 vP = vL0 + fl * vl * x + vwn * y; Real yy; if (h==0) // top below road { yy = vn.y * -0.8f; //pars vP.y += yy; ht += yy; } else // bottom below ground { yy = (mTerrain ? mTerrain->getHeightAtWorldPosition(vP) : 0.f) - 0.3f; vP.y = yy; } ht += yy; Vector3 vN(vP.x-vL0.x,0,vP.z-vL0.z); vN.normalise(); //> data Col posC.push_back(vP); normC.push_back(vN); tcsC.push_back(Vector2( Real(w)/iwC * 4, ht * 0.2f )); //pars } } if (i == -1 || i == il) // add len { l += la0; ltc += len; } else { l += la; ltc += len; } } // Length vertices //------------------------------------------------------------------------------------ // lod vis points if (lod == 0) { int lps = max(2, (int)(vSegLen[seg] / lposLen)); for (int p=0; p <= lps; ++p) { Vector3 vp = interpolate(seg, Real(p)/Real(lps)); posLod.push_back(vp); } } //--------------------------------------------------------------------------------------------------------- /// create mesh indices //--------------------------------------------------------------------------------------------------------- if (bNxt && !pos.empty()) /*Merging*/ { String sEnd = toStr(idStr); ++idStr; String sMesh = "rd.mesh." + sEnd, sMeshW = sMesh + "W", sMeshC = sMesh + "C"; posBt.clear(); idx.clear(); // set for addTri at_pos = &pos; at_size = pos.size(); at_ilBt = iLmrg-2; /// road ~ int iiw = 0; //LogR( " __idx"); // equal width steps if (viwEq[seg]==1) for (int i = 0; i < iLmrg-1; ++i) // length-1 +2gap { int iw = viW[seg]; // grid w-1 x l-1 x2 tris for (int w=0; w < iw; ++w) // width-1 { //LogR( " il="+toStr(i)+"/"+toStr(il)+" iw="+toStr(iw)); int f0 = iiw + w, f1 = f0 + (iw+1); addTri(f0+0,f1+1,f0+1,i, blt); addTri(f0+0,f1+0,f1+1,i, blt); } iiw += iw+1; } else // pipe, diff width_ for (int i = 0; i < iLmrg-1; ++i) // length-1 +2gap { int iw = viwLS[seg][i], iw1 = viwLS[seg][i+1]; int sw = iw1 < iw ? 1 : 0; //LogR( " il="+toStr(i)+"/"+toStr(il)+" iw="+toStr(iw)); //int w=0; // test fans for (int w=0; w < iw -sw; ++w) // width-1 { int f0 = iiw + w, f1 = f0 + (iw+1); // |\ | f0+0 f0+1 // | \| f1+0 f1+1 if (sw==0) { addTri(f0+0,f1+1,f0+1,i, blt); addTri(f0+0,f1+0,f1+1,i, blt); } else { // |/| addTri(f0+0,f1+0,f0+1,i, blt); addTri(f0+1,f1+0,f1+1,i, blt); } } ///>>> fix gaps when iw changes - fan tris int ma = iw1 - iw, ms = -ma, m; for (m=0; m < ma; ++m) { int f0 = iiw + iw-1, f1 = f0 + (iw+2)+m; addTri(f0+1,f1+0,f1+1,i, blt); } for (m=0; m < ms; ++m) { int f0 = iiw + iw-sw -m, f1 = f0 + (iw+1); addTri(f0+0,f1+0,f0+1,i, blt); } iiw += iw + 1; } vSegs[seg].nTri[lod] = idx.size()/3; // create Ogre Mesh //----------------------------------------- MeshPtr meshOld = MeshManager::getSingleton().getByName(sMesh); if (!meshOld.isNull()) LogR("Mesh exists !!!" + sMesh); AxisAlignedBox aabox; MeshPtr mesh = MeshManager::getSingleton().createManual(sMesh,"General"); SubMesh* sm = mesh->createSubMesh(); int id = max(0,mP[seg].idMtr); if (isPipe(seg)) rs.sMtrRd = sMtrPipe[id]; else rs.sMtrRd = sMtrRoad[id] + (onTer ? "_ter" :""); CreateMesh(sm, aabox, pos,norm,clr,tcs, idx, rs.sMtrRd); MeshPtr meshW, meshC; // ] | bool wall = !posW.empty(); if (wall) { meshW = MeshManager::getSingleton().createManual(sMeshW,"General"); meshW->createSubMesh(); } bool cols = !posC.empty() && lod == 0; // cols have no lods if (cols) { meshC = MeshManager::getSingleton().createManual(sMeshC,"General"); meshC->createSubMesh(); } //*=*/wall = 0; cols = 0; // test /// wall ] //------------------------------------------------------------------------------------ // wall pipe glass mtr bool wPglass = isPipe(seg) && mP[seg].idMtr >= 1; // wall pipe glass mtr //bool wPglass = isPipe(seg) && StringUtil::match(sMtrPipe[mP[seg].idMtr], "*lass*"); if (wall) { idx.clear(); for (int i = 0; i < iLmrgW-1; ++i) // length { int iiW = (i+0)*(iwW+1); for (int w=0; w < iwW; ++w) // width { int f0 = iiW + w, f1 = f0 + (iwW+1); idx.push_back(f0+1); idx.push_back(f1+1); idx.push_back(f0+0); idx.push_back(f1+1); idx.push_back(f1+0); idx.push_back(f0+0); } } // front plates start,end const int Wid[4/*6*/][3] = {{2,1,0},{3,2,0},{5,4,7},{6,5,7}/*,{7,3,0},{4,3,7}*/}; int i,f, b = posW.size()-iwW-1; if (!isPipe(seg)) // no fronts in pipes for (f=0; f < 4; ++f) { for (i=0; i<=2; ++i) idx.push_back( Wid[f][i] ); for (i=0; i<=2; ++i) idx.push_back( Wid[f][2-i]+b ); } vSegs[seg].nTri[lod] += idx.size()/3; sm = meshW->getSubMesh(0); // for glass only.. rs.sMtrWall = !wPglass ? sMtrWall : sMtrWallPipe; if (!posW.empty()) CreateMesh(sm, aabox, posW,normW,clr0,tcsW, idx, rs.sMtrWall); } /// columns | //------------------------------------------------------------------------------------ if (cols) { idx.clear(); at_pos = &posC; for (int l=0; l < iLmrgC; ++l) for (int w=0; w < iwC; ++w) { int f0 = w + l*(iwC+1)*2, f1 = f0 + iwC+1; addTri(f0+0, f1+1, f0+1, 1, blt); addTri(f0+0, f1+0, f1+1, 1, blt); } vSegs[seg].nTri[lod] += idx.size()/3; sm = meshC->getSubMesh(0); //if (!posC.empty()) CreateMesh(sm, aabox, posC,normC,clr0,tcsC, idx, sMtrCol); } // add Mesh to Scene ----------------------------------------- Entity* ent = 0, *entW = 0, *entC = 0; SceneNode* node = 0, *nodeW = 0, *nodeC = 0; AddMesh(mesh, sMesh, aabox, &ent, &node, "."+sEnd); if (wPglass) { ent->setRenderQueueGroup(RQG_PipeGlass); //ent->setCastShadows(true); } if (wall /*&& !posW.empty()*/) { AddMesh(meshW, sMeshW, aabox, &entW, &nodeW, "W."+sEnd); entW->setCastShadows(true); // only cast } if (cols /*&& !posC.empty()*/) { AddMesh(meshC, sMeshC, aabox, &entC, &nodeC, "C."+sEnd); entC->setVisible(true); if (bCastShadow) entC->setCastShadows(true); } if (bCastShadow && !onTer) ent->setCastShadows(true); //>> store ogre data ------------ rs.road[lod].node = node; rs.wall[lod].node = nodeW; rs.road[lod].ent = ent; rs.wall[lod].ent = entW; rs.road[lod].mesh = mesh; rs.wall[lod].mesh = meshW; rs.road[lod].smesh = sMesh; rs.wall[lod].smesh = sMeshW; if (lod==0) { rs.col.node = nodeC; rs.col.ent = entC; rs.col.mesh = meshC; rs.col.smesh = sMeshC; } rs.empty = false; // new // copy lod points if (lod == 0) { for (size_t p=0; p < posLod.size(); ++p) rs.lpos.push_back(posLod[p]); posLod.clear(); } //# stats-- if (stats) { rs.mrgLod = (iMrgSegs % 2)*2+1; //- iMrgSegs++; // count, full } /// bullet trimesh at lod 0 ///------------------------------------------------------------------------------------ if (lod == 0 && blt) { btTriangleMesh* trimesh = new btTriangleMesh(); vbtTriMesh.push_back(trimesh); #define vToBlt(v) btVector3(v.x, -v.z, v.y) #define addTriB(a,b,c) trimesh->addTriangle(vToBlt(a), vToBlt(b), vToBlt(c), blt); size_t si = posBt.size(), a=0; // %3! for (size_t i=0; i < si/3; ++i,a+=3) addTriB(posBt[a], posBt[a+1], posBt[a+2]); // if (cols) // add columns^.. // Road ~ btCollisionShape* shape = new btBvhTriangleMeshShape(trimesh, true); shape->setUserPointer(isPipe(seg) ? (void*)7788 : (void*)7777); // mark as road, + mtrId.. //btRigidBody::btRigidBodyConstructionInfo infoT(0.f, 0, shape); //infoT.m_restitution = 0.0f; //infoT.m_friction = 0.8f; // 1 like terrain //pGame->collision.AddRigidBody(infoT); // old btCollisionObject* bco = new btCollisionObject(); btTransform tr; tr.setIdentity(); //tr.setOrigin(pc); bco->setActivationState(DISABLE_SIMULATION); bco->setCollisionShape(shape); bco->setWorldTransform(tr); bco->setFriction(0.8f); bco->setRestitution(0.f); //` bco->setCollisionFlags(bco->getCollisionFlags() | btCollisionObject::CF_STATIC_OBJECT | btCollisionObject::CF_DISABLE_VISUALIZE_OBJECT/**/); #ifdef ROAD_EDITOR pApp->world->addCollisionObject(bco); #else pGame->collision.world->addCollisionObject(bco); pGame->collision.shapes.push_back(shape); #endif // Wall ] #ifndef ROAD_EDITOR // in Game if (wall) { trimesh = new btTriangleMesh(); vbtTriMesh.push_back(trimesh); for (int i = 0; i < iLmrgW-1; ++i) // length { int iiW = i* (iwW+1); for (int w=0; w < iwW; ++w) // width if (bRoadWFullCol || w==0 || w == iwW-1) // only 2 sides|_| optym+ { int f = iiW + w, f1 = f + (iwW+1); addTriB(posW[f+0], posW[f1+1], posW[f+1]); addTriB(posW[f+0], posW[f1+0], posW[f1+1]); } } btCollisionShape* shape = new btBvhTriangleMeshShape(trimesh, true); shape->setUserPointer((void*)7777); //- + road mtr id todo... btCollisionObject* bco = new btCollisionObject(); bco->setActivationState(DISABLE_SIMULATION); bco->setCollisionShape(shape); bco->setWorldTransform(tr); bco->setFriction(0.1f); bco->setRestitution(0.f); //` bco->setCollisionFlags(bco->getCollisionFlags() | btCollisionObject::CF_STATIC_OBJECT | btCollisionObject::CF_DISABLE_VISUALIZE_OBJECT/**/); pGame->collision.world->addCollisionObject(bco); pGame->collision.shapes.push_back(shape); } #endif } }/*bNxt Merging*/ sNum--; segM++; // next } /// segment end //-------------------------------------------------------------------------------------------------------------------------- //# stats if (stats) st.HeightDiff = max(0.f, stMaxH - stMinH); } // lod end UpdLodVis(fLodBias); if (iDirtyId == -1) iOldHide = -1; if (iDirtyId == -1) //if (segs <= 4 || sMax - sMin > 4) { ti.update(); /// time float dt = ti.dt * 1000.f; LogO(String("::: Time Road Rebuild: ") + toStr(dt) + " ms"); } }
MeshPtr MergeMesh::bake() { log( "Baking: New Mesh started" ); MeshPtr mp = MeshManager::getSingleton(). createManual( "mergedMesh", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME ); mp->setSkeletonName( m_BaseSkeleton->getName() ); AxisAlignedBox totalBounds = AxisAlignedBox(); for( std::vector< Ogre::MeshPtr >::iterator it = m_Meshes.begin(); it != m_Meshes.end(); ++it ) { log( "Baking: adding submeshes for " + (*it)->getName() ); // insert all submeshes for( Ogre::ushort sid = 0; sid < (*it)->getNumSubMeshes(); ++sid ) { SubMesh* sub = (*it)->getSubMesh( sid ); const String name = findSubmeshName( (*it), sid ); // create submesh with correct name SubMesh* newsub; if( name.length() == 0 ) newsub = mp->createSubMesh( ); else /// @todo check if a submesh with this name has been created before newsub = mp->createSubMesh( name ); newsub->useSharedVertices = sub->useSharedVertices; // add index newsub->indexData = sub->indexData->clone(); // add geometry if( !newsub->useSharedVertices ) { newsub->vertexData = sub->vertexData->clone(); // build bone assignments SubMesh::BoneAssignmentIterator bit = sub->getBoneAssignmentIterator(); while (bit.hasMoreElements()) { VertexBoneAssignment vba = bit.getNext(); newsub->addBoneAssignment(vba); } } newsub->setMaterialName( sub->getMaterialName() ); log("Baking: adding submesh '" + name + "' with material " + sub->getMaterialName()); } // sharedvertices if ((*it)->sharedVertexData) { /// @todo merge with existing sharedVertexData if (!mp->sharedVertexData) { mp->sharedVertexData = (*it)->sharedVertexData->clone(); } Mesh::BoneAssignmentIterator bit = (*it)->getBoneAssignmentIterator(); while (bit.hasMoreElements()) { VertexBoneAssignment vba = bit.getNext(); mp->addBoneAssignment(vba); } } log("Baking: adding bounds for " + (*it)->getName()); // add bounds totalBounds.merge((*it)->getBounds()); } mp->_setBounds( totalBounds ); /// @todo merge submeshes with same material /// @todo add parameters mp->buildEdgeList(); log( "Baking: Finished" ); return mp; }
void Tile::_generateSubMesh(MeshPtr& mesh) { // Create a submesh to the given mesh. SubMesh* tileMesh = mesh->createSubMesh(); // Define the vertices. size_t index = 0; size_t vertCount = this->mCorners.size() + 1; // corner count + center corner Real* vertices = new Real[vertCount*3*2]; // (number of verts)*(x, y, z)*(coord, normal) -or- vertCount*3*2 // Manually add center vertex. // -- Position (ord: x, y, z) vertices[index++] = this->mPosition.x; vertices[index++] = (Ogre::Real)(this->elevation); vertices[index++] = this->mPosition.y; // -- Normal (ord: x, y, z) Vector3 norm = Vector3::UNIT_Y; vertices[index++] = norm.x; vertices[index++] = norm.y; vertices[index++] = norm.z; // Add the rest of the vertices to data buffer. for(std::vector<Corner*>::iterator it = this->mCorners.begin(); it != this->mCorners.end(); ++it) { // Add to the next point to the array. // -- Position Vector3 vector = (*it)->vec3(); vertices[index++] = vector.x; vertices[index++] = vector.y; vertices[index++] = vector.z; // -- Normal Vector3 normal = Vector3::UNIT_Y; vertices[index++] = normal.x; vertices[index++] = normal.y; vertices[index++] = normal.z; } // Define vertices color. RenderSystem* rs = Root::getSingleton().getRenderSystem(); RGBA* colors = new RGBA[vertCount]; for(size_t i = 0; i < vertCount; ++i) rs->convertColourValue(ColourValue(0.0f + 0.175f*i, 0.2f, 1.0f - 0.175f*i), colors + i); // Define the triangles. size_t faceCount = vertCount - 1; // Face count = vertCount - cent size_t center = 0; size_t last = 1; //collin was here size_t curr = 2; unsigned short* faces = new unsigned short[faceCount*3]; index = 0; for(size_t i = 0; i < faceCount; ++i) { assert(last < vertCount && curr < vertCount); // Panic check faces[index++] = center; faces[index++] = curr; faces[index++] = last; last = curr++; if(curr >= vertCount) curr = 1; } // All information has been generated, move into mesh structures. // Note: Currently does not implement or used any sort of shared // vertices. This is intentional and should be changed at the // soonest conveienence. IE -- Never. ;P tileMesh->useSharedVertices = false; tileMesh->vertexData = new VertexData(); tileMesh->vertexData->vertexCount = vertCount; // Create memory footprint for vertex data. size_t offset = 0; VertexDeclaration* decl = tileMesh->vertexData->vertexDeclaration; // Position and normal buffer. // -- Position decl->addElement(0, offset, VET_FLOAT3, VES_POSITION); offset += VertexElement::getTypeSize(VET_FLOAT3); // -- Normal decl->addElement(0, offset, VET_FLOAT3, VES_NORMAL); offset += VertexElement::getTypeSize(VET_FLOAT3); // Allocate a vertex buffer for a number of vertices and vertex size. HardwareVertexBufferSharedPtr vertBuff = HardwareBufferManager::getSingleton().createVertexBuffer( offset, // Size of a vertex, in bytes. tileMesh->vertexData->vertexCount, HardwareBuffer::HBU_STATIC_WRITE_ONLY); // Write our data to vertex buffer. vertBuff->writeData(0, vertBuff->getSizeInBytes(), vertices, true); // Set the buffer's bind location. VertexBufferBinding* vertBind = tileMesh->vertexData->vertexBufferBinding; vertBind->setBinding(0, vertBuff); // Color buffer for vertices offset = 0; decl->addElement(1, offset, VET_COLOUR, VES_DIFFUSE); offset += VertexElement::getTypeSize(VET_COLOUR); // Allocate a new buffer for colors. vertBuff = HardwareBufferManager::getSingleton().createVertexBuffer( offset, // Size of a vertex, in bytes. tileMesh->vertexData->vertexCount, HardwareBuffer::HBU_STATIC_WRITE_ONLY); // Write color data to buffer. vertBuff->writeData(0, vertBuff->getSizeInBytes(), colors, true); // Set the color buffer's bind location vertBind->setBinding(1, vertBuff); // Allocate a buffer for the index information HardwareIndexBufferSharedPtr indexBuff = HardwareBufferManager::getSingleton().createIndexBuffer( HardwareIndexBuffer::IT_16BIT, faceCount*3, HardwareBuffer::HBU_STATIC_WRITE_ONLY); // Write data to the buffer. indexBuff->writeData(0, indexBuff->getSizeInBytes(), faces, true); // Finalize submesh. tileMesh->indexData->indexBuffer = indexBuff; tileMesh->indexData->indexCount = faceCount*3; tileMesh->indexData->indexStart = 0; // Deallocate the vertex and face arrays. if(vertices) delete[] vertices; if(faces) delete[] faces; }
Ogre::MeshPtr LodOutsideMarker::createConvexHullMesh(const String& meshName, const String& resourceGroupName) { // Based on the wiki sample: http://www.ogre3d.org/tikiwiki/tiki-index.php?page=Generating+A+Mesh // Resource with given name should not exist! assert(MeshManager::getSingleton().getByName(meshName).isNull()); generateHull(); // calculate mHull triangles. // Convex hull can't be empty! assert(!mHull.empty()); MeshPtr mesh = MeshManager::getSingleton().createManual(meshName, resourceGroupName, NULL); SubMesh* subMesh = mesh->createSubMesh(); vector<Real>::type vertexBuffer; vector<unsigned short>::type indexBuffer; // 3 position/triangle * 3 Real/position vertexBuffer.reserve(mHull.size() * 9); // 3 index / triangle indexBuffer.reserve(mHull.size() * 3); int id=0; // min & max position Vector3 minBounds(std::numeric_limits<Real>::max(), std::numeric_limits<Real>::max(), std::numeric_limits<Real>::max()); Vector3 maxBounds(std::numeric_limits<Real>::min(), std::numeric_limits<Real>::min(), std::numeric_limits<Real>::min()); for (size_t i = 0; i < mHull.size(); i++) { assert(!mHull[i].removed); for(size_t n = 0; n < 3; n++){ indexBuffer.push_back(id++); vertexBuffer.push_back(mHull[i].vertex[n]->position.x); vertexBuffer.push_back(mHull[i].vertex[n]->position.y); vertexBuffer.push_back(mHull[i].vertex[n]->position.z); minBounds.x = std::min<Real>(minBounds.x, mHull[i].vertex[n]->position.x); minBounds.y = std::min<Real>(minBounds.y, mHull[i].vertex[n]->position.y); minBounds.z = std::min<Real>(minBounds.z, mHull[i].vertex[n]->position.z); maxBounds.x = std::max<Real>(maxBounds.x, mHull[i].vertex[n]->position.x); maxBounds.y = std::max<Real>(maxBounds.y, mHull[i].vertex[n]->position.y); maxBounds.z = std::max<Real>(maxBounds.z, mHull[i].vertex[n]->position.z); } } /// Create vertex data structure for 8 vertices shared between submeshes mesh->sharedVertexData = new VertexData(); mesh->sharedVertexData->vertexCount = mHull.size() * 3; /// Create declaration (memory format) of vertex data VertexDeclaration* decl = mesh->sharedVertexData->vertexDeclaration; size_t offset = 0; // 1st buffer decl->addElement(0, offset, VET_FLOAT3, VES_POSITION); offset += VertexElement::getTypeSize(VET_FLOAT3); /// Allocate vertex buffer of the requested number of vertices (vertexCount) /// and bytes per vertex (offset) HardwareVertexBufferSharedPtr vbuf = HardwareBufferManager::getSingleton().createVertexBuffer( offset, mesh->sharedVertexData->vertexCount, HardwareBuffer::HBU_STATIC_WRITE_ONLY); /// Upload the vertex data to the card vbuf->writeData(0, vbuf->getSizeInBytes(), &vertexBuffer[0], true); /// Set vertex buffer binding so buffer 0 is bound to our vertex buffer VertexBufferBinding* bind = mesh->sharedVertexData->vertexBufferBinding; bind->setBinding(0, vbuf); /// Allocate index buffer of the requested number of vertices (ibufCount) HardwareIndexBufferSharedPtr ibuf = HardwareBufferManager::getSingleton(). createIndexBuffer( HardwareIndexBuffer::IT_16BIT, indexBuffer.size(), HardwareBuffer::HBU_STATIC_WRITE_ONLY); /// Upload the index data to the card ibuf->writeData(0, ibuf->getSizeInBytes(), &indexBuffer[0], true); /// Set parameters of the submesh subMesh->useSharedVertices = true; subMesh->indexData->indexBuffer = ibuf; subMesh->indexData->indexCount = indexBuffer.size(); subMesh->indexData->indexStart = 0; /// Set bounding information (for culling) mesh->_setBounds(AxisAlignedBox(minBounds, maxBounds)); mesh->_setBoundingSphereRadius(maxBounds.distance(minBounds) / 2.0f); /// Set material to transparent blue subMesh->setMaterialName("Examples/TransparentBlue50"); /// Notify -Mesh object that it has been loaded mesh->load(); return mesh; }
static MeshPtr importObject(QDataStream &stream) { using namespace Ogre; QVector4D bbMin, bbMax; stream >> bbMin >> bbMax; float distance, distanceSquared; // Here's a bug for you: writes "double"'s instead of floats stream >> distanceSquared >> distance; MeshPtr ogreMesh = MeshManager::getSingleton().createManual("conversion", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME); int vertexCount, indexCount; stream >> vertexCount >> indexCount; VertexData *vertexData = new VertexData(); ogreMesh->sharedVertexData = vertexData; LogManager::getSingleton().logMessage("Reading geometry..."); VertexDeclaration* decl = vertexData->vertexDeclaration; VertexBufferBinding* bind = vertexData->vertexBufferBinding; unsigned short bufferId = 0; // Information for calculating bounds Vector3 min = Vector3::ZERO, max = Vector3::UNIT_SCALE, pos = Vector3::ZERO; Real maxSquaredRadius = -1; bool firstVertex = true; /* Create a vertex definition for our buffer */ size_t offset = 0; const VertexElement &positionElement = decl->addElement(bufferId, offset, VET_FLOAT3, VES_POSITION); offset += VertexElement::getTypeSize(VET_FLOAT3); const VertexElement &normalElement = decl->addElement(bufferId, offset, VET_FLOAT3, VES_NORMAL); offset += VertexElement::getTypeSize(VET_FLOAT3); // calculate how many vertexes there actually are vertexData->vertexCount = vertexCount; // Now create the vertex buffer HardwareVertexBufferSharedPtr vbuf = HardwareBufferManager::getSingleton(). createVertexBuffer(offset, vertexData->vertexCount, HardwareBuffer::HBU_STATIC_WRITE_ONLY, false); // Bind it bind->setBinding(bufferId, vbuf); // Lock it unsigned char *pVert = static_cast<unsigned char*>(vbuf->lock(HardwareBuffer::HBL_DISCARD)); unsigned char *pVertStart = pVert; QVector<float> positions; positions.reserve(vertexCount * 3); // Iterate over all children (vertexbuffer entries) for (int i = 0; i < vertexCount; ++i) { float *pFloat; QVector4D vertex; stream >> vertex; vertex.setZ(vertex.z() * -1); /* Copy over the position */ positionElement.baseVertexPointerToElement(pVert, &pFloat); *(pFloat++) = (float)vertex.x(); *(pFloat++) = (float)vertex.y(); *(pFloat++) = (float)vertex.z(); positions.append(vertex.x()); positions.append(vertex.y()); positions.append(vertex.z()); /* While we're at it, calculate the bounding sphere */ pos.x = vertex.x(); pos.y = vertex.y(); pos.z = vertex.z(); if (firstVertex) { min = max = pos; maxSquaredRadius = pos.squaredLength(); firstVertex = false; } else { min.makeFloor(pos); max.makeCeil(pos); maxSquaredRadius = qMax(pos.squaredLength(), maxSquaredRadius); } pVert += vbuf->getVertexSize(); } // Set bounds const AxisAlignedBox& currBox = ogreMesh->getBounds(); Real currRadius = ogreMesh->getBoundingSphereRadius(); if (currBox.isNull()) { //do not pad the bounding box ogreMesh->_setBounds(AxisAlignedBox(min, max), false); ogreMesh->_setBoundingSphereRadius(Math::Sqrt(maxSquaredRadius)); } else { AxisAlignedBox newBox(min, max); newBox.merge(currBox); //do not pad the bounding box ogreMesh->_setBounds(newBox, false); ogreMesh->_setBoundingSphereRadius(qMax(Math::Sqrt(maxSquaredRadius), currRadius)); } /* Create faces */ // All children should be submeshes SubMesh* sm = ogreMesh->createSubMesh(); sm->setMaterialName("clippingMaterial"); sm->operationType = RenderOperation::OT_TRIANGLE_LIST; sm->useSharedVertices = true; // tri list sm->indexData->indexCount = indexCount; // Allocate space HardwareIndexBufferSharedPtr ibuf = HardwareBufferManager::getSingleton(). createIndexBuffer( HardwareIndexBuffer::IT_16BIT, sm->indexData->indexCount, HardwareBuffer::HBU_DYNAMIC, false); sm->indexData->indexBuffer = ibuf; unsigned short *pShort = static_cast<unsigned short*>(ibuf->lock(HardwareBuffer::HBL_DISCARD)); QVector<EdgeData::Triangle> triangles(indexCount / 3); for (int i = 0; i < indexCount / 3; ++i) { quint16 i1, i2, i3; stream >> i1 >> i2 >> i3; *pShort++ = i1; *pShort++ = i2; *pShort++ = i3; triangles[i].vertIndex[0] = i1; triangles[i].vertIndex[1] = i2; triangles[i].vertIndex[2] = i3; } /* Recalculate the vertex normals */ Vector4 *faceNormals = (Vector4*)_aligned_malloc(sizeof(Vector4) * triangles.size(), 16); OptimisedUtil *util = OptimisedUtil::getImplementation(); util->calculateFaceNormals(positions.constData(), triangles.data(), faceNormals, indexCount / 3); // Iterate over all children (vertexbuffer entries) pVert = pVertStart; for (int i = 0; i < vertexCount; ++i) { float *pFloat; Vector3 normal = Vector3::ZERO; int count = 0; /* Search for all faces that use this vertex */ for (int j = 0; j < triangles.size(); ++j) { if (triangles[j].vertIndex[0] == i || triangles[j].vertIndex[1] == i || triangles[j].vertIndex[2] == i) { normal.x += faceNormals[j].x / faceNormals[j].w; normal.y += faceNormals[j].y / faceNormals[j].w; normal.z += faceNormals[j].z / faceNormals[j].w; count++; } } normal.normalise(); /* Copy over the position */ normalElement.baseVertexPointerToElement(pVert, &pFloat); *(pFloat++) = normal.x; *(pFloat++) = normal.y; *(pFloat++) = normal.z; pVert += vbuf->getVertexSize(); } _aligned_free(faceNormals); vbuf->unlock(); ibuf->unlock(); return ogreMesh; }
// Generate normals for polygon meshes void IndexedGeometry::createIndexedFaceSet() { if (_coords.empty()) throw std::runtime_error("No coordinates given."); if (_coordIndex.empty()) throw std::runtime_error("No coordinate index given."); MeshPtr mesh = MeshManager::getSingleton().createManual(_name, ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME); SubMesh *sub = mesh->createSubMesh(); bool hasTextureCoordinates = !_texCoords.empty(); bool hasPointColors = !_colors.empty() && _colorPerVertex; bool hasPointNormals = !_normals.empty() && _normalPerVertex; bool hasCellColors = !_colors.empty() && !hasPointColors; bool hasCellNormals = !_normals.empty() && !hasPointNormals; bool calcPointNormals = _normals.empty() && _normalPerVertex; std::vector<face> faces; face f; for (std::vector<int>::const_iterator I=_coordIndex.begin(); I !=_coordIndex.end(); ++I) { if (*I == -1) { faces.resize(faces.size()+1); faces.back().indices.swap(f.indices); } else f.indices.push_back(I - _coordIndex.begin()); } if (!f.indices.empty()) { faces.resize(faces.size()+1); faces.back().indices.swap(f.indices); } std::vector<vertex> vertices; std::vector<triangle> triangles; VertMap vertexMap; // triangulate and expand vertices for (std::vector<face>::const_iterator f=faces.begin(), e=faces.end(); f!=e; ++f) { int faceNr = f - faces.begin(); int triVertNr = 0; int triVerts[2] = { -1, -1 }; for (std::vector<int>::const_iterator i = f->indices.begin(), e=f->indices.end(); i!=e; ++i, ++triVertNr) { int triVertNr = i - f->indices.begin(); int index = *i; vertex vert; // get full indices for vertex data vert.pos = _coordIndex[index]; vert.normal = !_normals.empty() ? getIndex(_coordIndex, _normalIndex, _normalPerVertex, faceNr, index) : 0; vert.colour = !_colors.empty() ? getIndex(_coordIndex, _colorIndex, _colorPerVertex, faceNr, index) : 0; vert.tc = hasTextureCoordinates ? getIndex(_coordIndex, _texCoordIndex, true, faceNr, index) : 0; // avoid duplication //int nvert = vertexMap.size(); //int &vpos = vertexMap[vert]; //if (nvert != vertexMap.size()) { int vpos = vertices.size(); vertices.push_back(vert); //} // emit triangle (maybe) if (triVertNr == 0) triVerts[0] = vpos; else if (triVertNr == 1) triVerts[1] = vpos; else { triangle t; t.vertices[0] = triVerts[0]; t.vertices[1] = triVerts[1]; t.vertices[2] = vpos; if (!_ccw) std::swap(t.vertices[1], t.vertices[2]); triangles.push_back(t); triVerts[1] = vpos; } } } // createOgreMesh int nvertices = vertices.size(); int nfaces = triangles.size(); VertexData* vertexData = new VertexData(); sub->vertexData = vertexData; IndexData* indexData = sub->indexData; VertexDeclaration* vertexDecl = vertexData->vertexDeclaration; size_t currOffset = 0; // positions vertexDecl->addElement(0, currOffset, VET_FLOAT3, VES_POSITION); currOffset += VertexElement::getTypeSize(VET_FLOAT3); if (hasPointNormals) { // normals vertexDecl->addElement(0, currOffset, VET_FLOAT3, VES_NORMAL); currOffset += VertexElement::getTypeSize(VET_FLOAT3); } // two dimensional texture coordinates if (hasTextureCoordinates) { vertexDecl->addElement(0, currOffset, VET_FLOAT2, VES_TEXTURE_COORDINATES, 0); currOffset += VertexElement::getTypeSize(VET_FLOAT2); } std::cout << std::endl; // allocate index buffer indexData->indexCount = nfaces * 3; indexData->indexBuffer = HardwareBufferManager::getSingleton().createIndexBuffer(HardwareIndexBuffer::IT_16BIT, indexData->indexCount, HardwareBuffer::HBU_STATIC_WRITE_ONLY, false); HardwareIndexBufferSharedPtr iBuf = indexData->indexBuffer; unsigned short* pIndices = static_cast<unsigned short*>(iBuf->lock(HardwareBuffer::HBL_DISCARD)); std::cout << triangles.size() << ": "; for(std::vector<triangle>::const_iterator T = triangles.begin(); T != triangles.end(); T++) { const triangle &t = (*T); *pIndices++ = t.vertices[0]; *pIndices++ = t.vertices[1]; *pIndices++ = t.vertices[2]; std::cout << t.vertices[0] << " " << t.vertices[1] << " " << t.vertices[2] << " "; } std::cout << std::endl; // allocate the vertex buffer vertexData->vertexCount = nvertices; HardwareVertexBufferSharedPtr vBuf = HardwareBufferManager::getSingleton().createVertexBuffer(vertexDecl->getVertexSize(0), vertexData->vertexCount, HardwareBuffer::HBU_STATIC_WRITE_ONLY, false); VertexBufferBinding* binding = vertexData->vertexBufferBinding; binding->setBinding(0, vBuf); float* pVertex = static_cast<float*>(vBuf->lock(HardwareBuffer::HBL_DISCARD)); AxisAlignedBox aabox; std::cout << vertices.size() << ": "; for(std::vector<vertex>::const_iterator V = vertices.begin(); V != vertices.end(); V++) { const vertex &v = (*V); SFVec3f pos = _coords.at(v.pos); *pVertex++ = pos.x; *pVertex++ = pos.y; *pVertex++ = pos.z; aabox.merge(Vector3(pos.x, pos.y, pos.z)); std::cout << pos.x << " " << pos.y << " " << pos.z << " " << std::endl; //std::cout << v.pos << " "; if (hasPointNormals) { const SFVec3f normal = _normals.at(v.normal); *pVertex++ = normal.x; *pVertex++ = normal.y; *pVertex++ = normal.z; } } std::cout << std::endl; // Unlock vBuf->unlock(); iBuf->unlock(); sub->useSharedVertices = false; // the original code was missing this line: mesh->_setBounds(aabox); mesh->_setBoundingSphereRadius((aabox.getMaximum()-aabox.getMinimum()).length()/2.0); // this line makes clear the mesh is loaded (avoids memory leaks) mesh->load(); }
void createSphereMesh(const String &name, const float radius, const int slices, const int stacks) { MeshPtr mesh = MeshManager::getSingleton().createManual(name, ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME); mesh->sharedVertexData = new VertexData(); mesh->_setBounds(AxisAlignedBox(Vector3(-radius, -radius, -radius), Vector3(radius, radius, radius))); mesh->_setBoundingSphereRadius(radius); VertexData *vertexData = mesh->sharedVertexData; vertexData->vertexDeclaration->addElement(0, 0, VET_FLOAT3, VES_POSITION); vertexData->vertexDeclaration->addElement(1, 0, VET_FLOAT3, VES_NORMAL); vertexData->vertexCount = slices * (stacks + 1); HardwareVertexBufferSharedPtr positionBuffer = HardwareBufferManager::getSingleton().createVertexBuffer( vertexData->vertexDeclaration->getVertexSize(0), vertexData->vertexCount, HardwareBuffer::HBU_STATIC_WRITE_ONLY); HardwareVertexBufferSharedPtr normalBuffer = HardwareBufferManager::getSingleton().createVertexBuffer( vertexData->vertexDeclaration->getVertexSize(1), vertexData->vertexCount, HardwareBuffer::HBU_STATIC_WRITE_ONLY); float *position = static_cast<float *>(positionBuffer->lock(HardwareBuffer::HBL_DISCARD)); float *normal = static_cast<float *>(normalBuffer->lock(HardwareBuffer::HBL_DISCARD)); for (int ring = 0; ring <= stacks; ring++) { float r = radius * sinf(ring * Math::PI / stacks); float y = radius * cosf(ring * Math::PI / stacks); for (int segment = 0; segment < slices; segment++) { float x = r * sinf(segment * 2 * Math::PI / slices); float z = r * cosf(segment * 2 * Math::PI / slices); *position++ = x; *position++ = y; *position++ = z; Vector3 tmp = Vector3(x, y, z).normalisedCopy(); *normal++ = tmp.x; *normal++ = tmp.y; *normal++ = tmp.z; } } positionBuffer->unlock(); normalBuffer->unlock(); vertexData->vertexBufferBinding->setBinding(0, positionBuffer); vertexData->vertexBufferBinding->setBinding(1, normalBuffer); SubMesh *subMesh = mesh->createSubMesh(); subMesh->useSharedVertices = true; IndexData *indexData = subMesh->indexData; indexData->indexCount = 6 * slices * stacks; HardwareIndexBufferSharedPtr indexBuffer = HardwareBufferManager::getSingleton().createIndexBuffer( HardwareIndexBuffer::IT_16BIT, indexData->indexCount, HardwareBuffer::HBU_STATIC_WRITE_ONLY); unsigned short *index = static_cast<unsigned short *>(indexBuffer->lock(HardwareBuffer::HBL_DISCARD)); unsigned short i = 0; for (int ring = 0; ring < stacks; ring++) { for (int segment = 0; segment < slices - 1; segment++) { *index++ = i; *index++ = i + slices; *index++ = i + slices + 1; *index++ = i; *index++ = i + slices + 1; *index++ = i + 1; i++; } *index++ = i; *index++ = i + slices; *index++ = i + 1; *index++ = i; *index++ = i + 1; *index++ = i + 1 - slices; i++; } indexBuffer->unlock(); indexData->indexBuffer = indexBuffer; mesh->load(); }