bool HasDynamicBuffers(Model* model, unsigned lodLevel) { unsigned numGeometries = model->GetNumGeometries(); for (unsigned i = 0; i < numGeometries; ++i) { Geometry* geometry = model->GetGeometry(i, lodLevel); if (!geometry) continue; unsigned numVertexBuffers = geometry->GetNumVertexBuffers(); for (unsigned j = 0; j < numVertexBuffers; ++j) { VertexBuffer* buffer = geometry->GetVertexBuffer(j); if (!buffer) continue; if (buffer->IsDynamic()) return true; } IndexBuffer* buffer = geometry->GetIndexBuffer(); if (buffer && buffer->IsDynamic()) return true; } return false; }
void CollisionShape::SetMesh(Mesh *mesh, SkeletonNode &skeletonNode, mat4 transformation) { mat4 modelTransformation = transformation * skeletonNode.transformation; for (auto meshIndex : skeletonNode.meshes) { Geometry *geometry = mesh->GetGeometries()[meshIndex]; VertexBuffer *vertexBuffer = geometry->GetVertexBuffer(); IndexBuffer *indexBuffer = geometry->GetIndexBuffer(); auto &vertexData = vertexBuffer->GetShadowData(); auto &indexData = indexBuffer->GetShadowData(); if (indexData.empty() == false && vertexData.empty() == false) { unsigned int positionOffset = vertexBuffer->GetVertexAttributeOffset(VertexAttributeType::POSITION); for (unsigned int i = 0; i < indexData.size() / sizeof(unsigned int); i += 3) { unsigned int i0 = *((unsigned int *)&indexData[(i + 0) * sizeof(unsigned int)]); unsigned int i1 = *((unsigned int *)&indexData[(i + 1) * sizeof(unsigned int)]); unsigned int i2 = *((unsigned int *)&indexData[(i + 2) * sizeof(unsigned int)]); vec3 pos0 = modelTransformation * *((vec3 *)&vertexData[i0 * vertexBuffer->GetVertexSize() + positionOffset]); vec3 pos1 = modelTransformation * *((vec3 *)&vertexData[i1 * vertexBuffer->GetVertexSize() + positionOffset]); vec3 pos2 = modelTransformation * *((vec3 *)&vertexData[i2 * vertexBuffer->GetVertexSize() + positionOffset]); collisionMesh->triangles.push_back(CollisionTriangle(pos0, pos1, pos2)); collisionMesh->boundingBox.Expand(pos0); collisionMesh->boundingBox.Expand(pos1); collisionMesh->boundingBox.Expand(pos2); } } } for (auto &c : skeletonNode.children) { SetMesh(mesh, c, modelTransformation); } }
SharedPtr<Model> Model::Clone(const String& cloneName) const { SharedPtr<Model> ret(new Model(context_)); ret->SetName(cloneName); ret->boundingBox_ = boundingBox_; ret->skeleton_ = skeleton_; ret->geometryBoneMappings_ = geometryBoneMappings_; ret->geometryCenters_ = geometryCenters_; ret->morphs_ = morphs_; ret->morphRangeStarts_ = morphRangeStarts_; ret->morphRangeCounts_ = morphRangeCounts_; // Deep copy vertex/index buffers HashMap<VertexBuffer*, VertexBuffer*> vbMapping; for (Vector<SharedPtr<VertexBuffer> >::ConstIterator i = vertexBuffers_.Begin(); i != vertexBuffers_.End(); ++i) { VertexBuffer* origBuffer = *i; SharedPtr<VertexBuffer> cloneBuffer; if (origBuffer) { cloneBuffer = new VertexBuffer(context_); cloneBuffer->SetSize(origBuffer->GetVertexCount(), origBuffer->GetElementMask(), origBuffer->IsDynamic()); cloneBuffer->SetShadowed(origBuffer->IsShadowed()); if (origBuffer->IsShadowed()) cloneBuffer->SetData(origBuffer->GetShadowData()); else { void* origData = origBuffer->Lock(0, origBuffer->GetVertexCount()); if (origData) cloneBuffer->SetData(origData); else URHO3D_LOGERROR("Failed to lock original vertex buffer for copying"); } vbMapping[origBuffer] = cloneBuffer; } ret->vertexBuffers_.Push(cloneBuffer); } HashMap<IndexBuffer*, IndexBuffer*> ibMapping; for (Vector<SharedPtr<IndexBuffer> >::ConstIterator i = indexBuffers_.Begin(); i != indexBuffers_.End(); ++i) { IndexBuffer* origBuffer = *i; SharedPtr<IndexBuffer> cloneBuffer; if (origBuffer) { cloneBuffer = new IndexBuffer(context_); cloneBuffer->SetSize(origBuffer->GetIndexCount(), origBuffer->GetIndexSize() == sizeof(unsigned), origBuffer->IsDynamic()); cloneBuffer->SetShadowed(origBuffer->IsShadowed()); if (origBuffer->IsShadowed()) cloneBuffer->SetData(origBuffer->GetShadowData()); else { void* origData = origBuffer->Lock(0, origBuffer->GetIndexCount()); if (origData) cloneBuffer->SetData(origData); else URHO3D_LOGERROR("Failed to lock original index buffer for copying"); } ibMapping[origBuffer] = cloneBuffer; } ret->indexBuffers_.Push(cloneBuffer); } // Deep copy all the geometry LOD levels and refer to the copied vertex/index buffers ret->geometries_.Resize(geometries_.Size()); for (unsigned i = 0; i < geometries_.Size(); ++i) { ret->geometries_[i].Resize(geometries_[i].Size()); for (unsigned j = 0; j < geometries_[i].Size(); ++j) { SharedPtr<Geometry> cloneGeometry; Geometry* origGeometry = geometries_[i][j]; if (origGeometry) { cloneGeometry = new Geometry(context_); cloneGeometry->SetIndexBuffer(ibMapping[origGeometry->GetIndexBuffer()]); unsigned numVbs = origGeometry->GetNumVertexBuffers(); for (unsigned k = 0; k < numVbs; ++k) { cloneGeometry->SetVertexBuffer(k, vbMapping[origGeometry->GetVertexBuffer(k)]); } cloneGeometry->SetDrawRange(origGeometry->GetPrimitiveType(), origGeometry->GetIndexStart(), origGeometry->GetIndexCount(), origGeometry->GetVertexStart(), origGeometry->GetVertexCount(), false); cloneGeometry->SetLodDistance(origGeometry->GetLodDistance()); } ret->geometries_[i][j] = cloneGeometry; } } // Deep copy the morph data (if any) to allow modifying it for (Vector<ModelMorph>::Iterator i = ret->morphs_.Begin(); i != ret->morphs_.End(); ++i) { ModelMorph& morph = *i; for (HashMap<unsigned, VertexBufferMorph>::Iterator j = morph.buffers_.Begin(); j != morph.buffers_.End(); ++j) { VertexBufferMorph& vbMorph = j->second_; if (vbMorph.dataSize_) { SharedArrayPtr<unsigned char> cloneData(new unsigned char[vbMorph.dataSize_]); memcpy(cloneData.Get(), vbMorph.morphData_.Get(), vbMorph.dataSize_); vbMorph.morphData_ = cloneData; } } } ret->SetMemoryUse(GetMemoryUse()); return ret; }
bool Model::Save(Serializer& dest) const { // Write ID if (!dest.WriteFileID("UMD2")) return false; // Write vertex buffers dest.WriteUInt(vertexBuffers_.Size()); for (unsigned i = 0; i < vertexBuffers_.Size(); ++i) { VertexBuffer* buffer = vertexBuffers_[i]; dest.WriteUInt(buffer->GetVertexCount()); const PODVector<VertexElement>& elements = buffer->GetElements(); dest.WriteUInt(elements.Size()); for (unsigned j = 0; j < elements.Size(); ++j) { unsigned elementDesc = ((unsigned)elements[j].type_) | (((unsigned)elements[j].semantic_) << 8) | (((unsigned)elements[j].index_) << 16); dest.WriteUInt(elementDesc); } dest.WriteUInt(morphRangeStarts_[i]); dest.WriteUInt(morphRangeCounts_[i]); dest.Write(buffer->GetShadowData(), buffer->GetVertexCount() * buffer->GetVertexSize()); } // Write index buffers dest.WriteUInt(indexBuffers_.Size()); for (unsigned i = 0; i < indexBuffers_.Size(); ++i) { IndexBuffer* buffer = indexBuffers_[i]; dest.WriteUInt(buffer->GetIndexCount()); dest.WriteUInt(buffer->GetIndexSize()); dest.Write(buffer->GetShadowData(), buffer->GetIndexCount() * buffer->GetIndexSize()); } // Write geometries dest.WriteUInt(geometries_.Size()); for (unsigned i = 0; i < geometries_.Size(); ++i) { // Write bone mappings dest.WriteUInt(geometryBoneMappings_[i].Size()); for (unsigned j = 0; j < geometryBoneMappings_[i].Size(); ++j) dest.WriteUInt(geometryBoneMappings_[i][j]); // Write the LOD levels dest.WriteUInt(geometries_[i].Size()); for (unsigned j = 0; j < geometries_[i].Size(); ++j) { Geometry* geometry = geometries_[i][j]; dest.WriteFloat(geometry->GetLodDistance()); dest.WriteUInt(geometry->GetPrimitiveType()); dest.WriteUInt(LookupVertexBuffer(geometry->GetVertexBuffer(0), vertexBuffers_)); dest.WriteUInt(LookupIndexBuffer(geometry->GetIndexBuffer(), indexBuffers_)); dest.WriteUInt(geometry->GetIndexStart()); dest.WriteUInt(geometry->GetIndexCount()); } } // Write morphs dest.WriteUInt(morphs_.Size()); for (unsigned i = 0; i < morphs_.Size(); ++i) { dest.WriteString(morphs_[i].name_); dest.WriteUInt(morphs_[i].buffers_.Size()); // Write morph vertex buffers for (HashMap<unsigned, VertexBufferMorph>::ConstIterator j = morphs_[i].buffers_.Begin(); j != morphs_[i].buffers_.End(); ++j) { dest.WriteUInt(j->first_); dest.WriteUInt(j->second_.elementMask_); dest.WriteUInt(j->second_.vertexCount_); // Base size: size of each vertex index unsigned vertexSize = sizeof(unsigned); // Add size of individual elements if (j->second_.elementMask_ & MASK_POSITION) vertexSize += sizeof(Vector3); if (j->second_.elementMask_ & MASK_NORMAL) vertexSize += sizeof(Vector3); if (j->second_.elementMask_ & MASK_TANGENT) vertexSize += sizeof(Vector3); dest.Write(j->second_.morphData_.Get(), vertexSize * j->second_.vertexCount_); } } // Write skeleton skeleton_.Save(dest); // Write bounding box dest.WriteBoundingBox(boundingBox_); // Write geometry centers for (unsigned i = 0; i < geometryCenters_.Size(); ++i) dest.WriteVector3(geometryCenters_[i]); // Write metadata if (HasMetadata()) { File* destFile = dynamic_cast<File*>(&dest); if (destFile) { String xmlName = ReplaceExtension(destFile->GetName(), ".xml"); SharedPtr<XMLFile> xml(new XMLFile(context_)); XMLElement rootElem = xml->CreateRoot("model"); SaveMetadataToXML(rootElem); File xmlFile(context_, xmlName, FILE_WRITE); xml->Save(xmlFile); } else URHO3D_LOGWARNING("Can not save model metadata when not saving into a file"); } return true; }
void DecalSet::GetFaces(Vector<PODVector<DecalVertex> >& faces, Drawable* target, unsigned batchIndex, const Frustum& frustum, const Vector3& decalNormal, float normalCutoff) { // Try to use the most accurate LOD level if possible Geometry* geometry = target->GetLodGeometry(batchIndex, 0); if (!geometry || geometry->GetPrimitiveType() != TRIANGLE_LIST) return; const unsigned char* positionData = 0; const unsigned char* normalData = 0; const unsigned char* skinningData = 0; const unsigned char* indexData = 0; unsigned positionStride = 0; unsigned normalStride = 0; unsigned skinningStride = 0; unsigned indexStride = 0; IndexBuffer* ib = geometry->GetIndexBuffer(); if (ib) { indexData = ib->GetShadowData(); indexStride = ib->GetIndexSize(); } // For morphed models positions, normals and skinning may be in different buffers for (unsigned i = 0; i < geometry->GetNumVertexBuffers(); ++i) { VertexBuffer* vb = geometry->GetVertexBuffer(i); if (!vb) continue; unsigned elementMask = vb->GetElementMask(); unsigned char* data = vb->GetShadowData(); if (!data) continue; if (elementMask & MASK_POSITION) { positionData = data; positionStride = vb->GetVertexSize(); } if (elementMask & MASK_NORMAL) { normalData = data + vb->GetElementOffset(SEM_NORMAL); normalStride = vb->GetVertexSize(); } if (elementMask & MASK_BLENDWEIGHTS) { skinningData = data + vb->GetElementOffset(SEM_BLENDWEIGHTS); skinningStride = vb->GetVertexSize(); } } // Positions and indices are needed if (!positionData) { // As a fallback, try to get the geometry's raw vertex/index data const PODVector<VertexElement>* elements; geometry->GetRawData(positionData, positionStride, indexData, indexStride, elements); if (!positionData) { URHO3D_LOGWARNING("Can not add decal, target drawable has no CPU-side geometry data"); return; } } if (indexData) { unsigned indexStart = geometry->GetIndexStart(); unsigned indexCount = geometry->GetIndexCount(); // 16-bit indices if (indexStride == sizeof(unsigned short)) { const unsigned short* indices = ((const unsigned short*)indexData) + indexStart; const unsigned short* indicesEnd = indices + indexCount; while (indices < indicesEnd) { GetFace(faces, target, batchIndex, indices[0], indices[1], indices[2], positionData, normalData, skinningData, positionStride, normalStride, skinningStride, frustum, decalNormal, normalCutoff); indices += 3; } } else // 32-bit indices { const unsigned* indices = ((const unsigned*)indexData) + indexStart; const unsigned* indicesEnd = indices + indexCount; while (indices < indicesEnd) { GetFace(faces, target, batchIndex, indices[0], indices[1], indices[2], positionData, normalData, skinningData, positionStride, normalStride, skinningStride, frustum, decalNormal, normalCutoff); indices += 3; } } } else { // Non-indexed geometry unsigned indices = geometry->GetVertexStart(); unsigned indicesEnd = indices + geometry->GetVertexCount(); while (indices + 2 < indicesEnd) { GetFace(faces, target, batchIndex, indices, indices + 1, indices + 2, positionData, normalData, skinningData, positionStride, normalStride, skinningStride, frustum, decalNormal, normalCutoff); indices += 3; } } }
bool Model::Save(Serializer& dest) const { // Write ID if (!dest.WriteFileID("AMDL")) // atomic model specifier return false; // Write vertex buffers dest.WriteUInt(vertexBuffers_.Size()); for (unsigned i = 0; i < vertexBuffers_.Size(); ++i) { VertexBuffer* buffer = vertexBuffers_[i]; dest.WriteUInt(buffer->GetVertexCount()); dest.WriteUInt(buffer->GetElementMask()); dest.WriteUInt(morphRangeStarts_[i]); dest.WriteUInt(morphRangeCounts_[i]); dest.Write(buffer->GetShadowData(), buffer->GetVertexCount() * buffer->GetVertexSize()); } // Write index buffers dest.WriteUInt(indexBuffers_.Size()); for (unsigned i = 0; i < indexBuffers_.Size(); ++i) { IndexBuffer* buffer = indexBuffers_[i]; dest.WriteUInt(buffer->GetIndexCount()); dest.WriteUInt(buffer->GetIndexSize()); dest.Write(buffer->GetShadowData(), buffer->GetIndexCount() * buffer->GetIndexSize()); } // Write geometries dest.WriteUInt(geometries_.Size()); for (unsigned i = 0; i < geometries_.Size(); ++i) { // Write bone mappings dest.WriteUInt(geometryBoneMappings_[i].Size()); for (unsigned j = 0; j < geometryBoneMappings_[i].Size(); ++j) dest.WriteUInt(geometryBoneMappings_[i][j]); // Write the LOD levels dest.WriteUInt(geometries_[i].Size()); for (unsigned j = 0; j < geometries_[i].Size(); ++j) { Geometry* geometry = geometries_[i][j]; dest.WriteFloat(geometry->GetLodDistance()); dest.WriteUInt(geometry->GetPrimitiveType()); dest.WriteUInt(LookupVertexBuffer(geometry->GetVertexBuffer(0), vertexBuffers_)); dest.WriteUInt(LookupIndexBuffer(geometry->GetIndexBuffer(), indexBuffers_)); dest.WriteUInt(geometry->GetIndexStart()); dest.WriteUInt(geometry->GetIndexCount()); } } // Write morphs dest.WriteUInt(morphs_.Size()); for (unsigned i = 0; i < morphs_.Size(); ++i) { dest.WriteString(morphs_[i].name_); dest.WriteUInt(morphs_[i].buffers_.Size()); // Write morph vertex buffers for (HashMap<unsigned, VertexBufferMorph>::ConstIterator j = morphs_[i].buffers_.Begin(); j != morphs_[i].buffers_.End(); ++j) { dest.WriteUInt(j->first_); dest.WriteUInt(j->second_.elementMask_); dest.WriteUInt(j->second_.vertexCount_); // Base size: size of each vertex index unsigned vertexSize = sizeof(unsigned); // Add size of individual elements if (j->second_.elementMask_ & MASK_POSITION) vertexSize += sizeof(Vector3); if (j->second_.elementMask_ & MASK_NORMAL) vertexSize += sizeof(Vector3); if (j->second_.elementMask_ & MASK_TANGENT) vertexSize += sizeof(Vector3); dest.Write(j->second_.morphData_.Get(), vertexSize * j->second_.vertexCount_); } } // Write skeleton skeleton_.Save(dest); // Write bounding box dest.WriteBoundingBox(boundingBox_); // Write geometry centers for (unsigned i = 0; i < geometryCenters_.Size(); ++i) dest.WriteVector3(geometryCenters_[i]); // ATOMIC BEGIN dest.WriteUInt(MODEL_VERSION); // animation resources ResourceRefList animList(Animation::GetTypeStatic()); animList.names_.Resize(animationsResources_.Size()); for (unsigned i = 0; i < animationsResources_.Size(); ++i) animList.names_[i] = GetResourceName(animationsResources_[i]); dest.WriteResourceRefList(animList); // ATOMIC END return true; }
//============================================================================= //============================================================================= void StaticModelPoolMgr::AddStaticModelData(Node *pNode, StaticModel *pStaticModel) { NvMeshData nvMeshData; StaticModelData staticModelData; Model *pModel = pStaticModel->GetModel(); // only one geom currently supprted assert( pModel && pModel->GetNumGeometries() == 1 && "multiple gemoetries currently NOT supported" ); Matrix3x4 objMatrix = pNode->GetTransform(); Quaternion objRotation = pNode->GetRotation(); Geometry *pGeometry = pModel->GetGeometry(0, 0); VertexBuffer *pVbuffer = pGeometry->GetVertexBuffer(0); unsigned uElementMask = pVbuffer->GetElementMask(); unsigned vertexSize = pVbuffer->GetVertexSize(); const unsigned char *pVertexData = (const unsigned char*)pVbuffer->Lock(0, pVbuffer->GetVertexCount()); // get verts, normals, uv, etc. if ( pVertexData ) { unsigned numVertices = pVbuffer->GetVertexCount(); for ( unsigned i = 0; i < numVertices; ++i ) { unsigned char *pDataAlign = (unsigned char *)(pVertexData + i * vertexSize); if ( uElementMask & MASK_POSITION ) { const Vector3 vPos = *reinterpret_cast<Vector3*>( pDataAlign ); pDataAlign += sizeof( Vector3 ); Vector3 vxformPos = objMatrix * vPos; // xform // verts list staticModelData.listVerts.Push( vxformPos ); nvMeshData.listVerts.push_back( Vec3f( vxformPos.x_, vxformPos.y_, vxformPos.z_ ) ); } if ( uElementMask & MASK_NORMAL ) { const Vector3 vNorm = *reinterpret_cast<Vector3*>( pDataAlign ); pDataAlign += sizeof( Vector3 ); // normal list Vector3 vxformNorm = objRotation * vNorm; // xform staticModelData.listNormals.Push( vxformNorm ); nvMeshData.listNormals.push_back( Vec3f( vxformNorm.x_, vxformNorm.y_, vxformNorm.z_ ) ); } if ( uElementMask & MASK_COLOR ) { const unsigned uColor = *reinterpret_cast<unsigned*>( pDataAlign ); pDataAlign += sizeof( unsigned ); } if ( uElementMask & MASK_TEXCOORD1 ) { const Vector2 vUV = *reinterpret_cast<Vector2*>( pDataAlign ); pDataAlign += sizeof( Vector2 ); // uv list staticModelData.listUVs.Push( vUV ); } // skip other mask elements - we got what we wanted } //unlock pVbuffer->Unlock(); } else { // error assert( false && "failed to unlock vertex buffer" ); } // get indeces IndexBuffer *pIbuffer = pGeometry->GetIndexBuffer(); const unsigned *pIndexData = (const unsigned *)pIbuffer->Lock( 0, pIbuffer->GetIndexCount() ); const unsigned short *pUShortData = (const unsigned short *)pIndexData; if ( pUShortData ) { unsigned numIndeces = pIbuffer->GetIndexCount(); unsigned indexSize = pIbuffer->GetIndexSize(); assert( indexSize == sizeof(unsigned short) ); for( unsigned i = 0; i < numIndeces; i += 3 ) { int idx0 = (int)pUShortData[i ]; int idx1 = (int)pUShortData[i+1]; int idx2 = (int)pUShortData[i+2]; staticModelData.listTris.Push( IntVector3( idx0, idx1, idx2 ) ); nvMeshData.listTris.push_back( Vec3i( idx0, idx1, idx2 ) ); } //unlock pIbuffer->Unlock(); } else { // error assert( false && "failed to unlock index buffer" ); } // rest of the static model data staticModelData.node = pNode; staticModelData.drawable = pStaticModel; staticModelData.begVertex = m_pNvScene->getNumVertices(); staticModelData.begTriList = m_pNvScene->getNumTriangles(); // resize coeff lists staticModelData.listVertexUnshadoweCoeff.Resize( staticModelData.listVerts.Size() ); staticModelData.listVertexShadowCoeff.Resize( staticModelData.listVerts.Size() ); staticModelData.listVertexDiffuseColor.Resize( staticModelData.listVerts.Size() ); staticModelData.listVertexSampleOcclude.resize( staticModelData.listVerts.Size() ); // find material matcolor VertexUtil *pVertexUtil = GetScene()->GetComponent<VertexUtil>(); staticModelData.materialColor = pVertexUtil->GetModelMaterialColor( pStaticModel ); // save model m_vStaticModelPool.Push( staticModelData ); // push it to nv Scene m_pNvScene->AddTriangleMesh( nvMeshData ); }