// ================================================================= // Read all loose edges. // Important: This function assumes that all edges from existing // faces have allready been generated and added to me->medge // So this function MUST be called after read_faces() (see below) // ================================================================= void MeshImporter::read_lines(COLLADAFW::Mesh *mesh, Mesh *me) { unsigned int loose_edge_count = get_loose_edge_count(mesh); if (loose_edge_count > 0) { unsigned int face_edge_count = me->totedge; /* unsigned int total_edge_count = loose_edge_count + face_edge_count; */ /* UNUSED */ mesh_add_edges(me, loose_edge_count); MEdge *med = me->medge + face_edge_count; COLLADAFW::MeshPrimitiveArray& prim_arr = mesh->getMeshPrimitives(); for (int i = 0; i < prim_arr.getCount(); i++) { COLLADAFW::MeshPrimitive *mp = prim_arr[i]; int type = mp->getPrimitiveType(); if (type == COLLADAFW::MeshPrimitive::LINES) { unsigned int edge_count = mp->getFaceCount(); unsigned int *indices = mp->getPositionIndices().getData(); for (int i = 0; i < edge_count; i++, med++) { med->bweight = 0; med->crease = 0; med->flag |= ME_LOOSEEDGE; med->v1 = indices[2 * i]; med->v2 = indices[2 * i + 1]; } } } } }
bool MeshImporter::is_nice_mesh(COLLADAFW::Mesh *mesh) // checks if mesh has supported primitive types: lines, polylist, triangles, triangle_fans { COLLADAFW::MeshPrimitiveArray& prim_arr = mesh->getMeshPrimitives(); const std::string &name = bc_get_dae_name(mesh); int hole_count = 0; for (unsigned i = 0; i < prim_arr.getCount(); i++) { COLLADAFW::MeshPrimitive *mp = prim_arr[i]; COLLADAFW::MeshPrimitive::PrimitiveType type = mp->getPrimitiveType(); const char *type_str = bc_primTypeToStr(type); // OpenCollada passes POLYGONS type for <polylist> if (type == COLLADAFW::MeshPrimitive::POLYLIST || type == COLLADAFW::MeshPrimitive::POLYGONS) { COLLADAFW::Polygons *mpvc = (COLLADAFW::Polygons *)mp; COLLADAFW::Polygons::VertexCountArray& vca = mpvc->getGroupedVerticesVertexCountArray(); for (unsigned int j = 0; j < vca.getCount(); j++) { int count = vca[j]; if (abs(count) < 3) { fprintf(stderr, "ERROR: Primitive %s in %s has at least one face with vertex count < 3\n", type_str, name.c_str()); return false; } if (count < 0) { hole_count ++; } } if (hole_count > 0) { fprintf(stderr, "WARNING: Primitive %s in %s: %d holes not imported (unsupported)\n", type_str, name.c_str(), hole_count); } } else if (type == COLLADAFW::MeshPrimitive::LINES) { // TODO: Add Checker for line syntax here } else if (type != COLLADAFW::MeshPrimitive::TRIANGLES && type != COLLADAFW::MeshPrimitive::TRIANGLE_FANS) { fprintf(stderr, "ERROR: Primitive type %s is not supported.\n", type_str); return false; } } if (mesh->getPositions().empty()) { fprintf(stderr, "ERROR: Mesh %s has no vertices.\n", name.c_str()); return false; } return true; }
unsigned int MeshImporter::get_loose_edge_count(COLLADAFW::Mesh *mesh) { COLLADAFW::MeshPrimitiveArray& prim_arr = mesh->getMeshPrimitives(); int loose_edge_count = 0; // collect edge_count and face_count from all parts for (int i = 0; i < prim_arr.getCount(); i++) { COLLADAFW::MeshPrimitive *mp = prim_arr[i]; int type = mp->getPrimitiveType(); switch (type) { case COLLADAFW::MeshPrimitive::LINES: { size_t prim_totface = mp->getFaceCount(); loose_edge_count += prim_totface; break; } default: break; } } return loose_edge_count; }
SubMesh* ColladaSubMeshReader::Load( void ) { COLLADAFW::MeshPrimitiveArray& primitives = m_pMesh->getMeshPrimitives(); //若没有几何图元信息 if( 0 == primitives.getCount() ) { return NULL; } COLLADAFW::MeshPrimitive* pPrimitive = primitives[0]; if( COLLADAFW::MeshPrimitive::TRIANGLES != pPrimitive->getPrimitiveType() ) { return NULL; } COLLADAFW::UIntValuesArray& positionIndices = pPrimitive->getPositionIndices(); //若没有位置索引 则直接退出 if( 0 == positionIndices.getCount() ) { return NULL; } COLLADAFW::UIntValuesArray& normalIndices = pPrimitive->getNormalIndices(); m_bHasNormals = ( normalIndices.getCount() != 0 ); COLLADAFW::UIntValuesArray& tangentIndices = pPrimitive->getTangentIndices(); m_bHasTangents = ( tangentIndices.getCount() != 0 ); COLLADAFW::UIntValuesArray& binormalIndices = pPrimitive->getBinormalIndices(); m_bHasBinormals = ( binormalIndices.getCount() != 0 ); COLLADAFW::IndexList* pUVs = NULL; if( pPrimitive->getUVCoordIndicesArray().getCount() ) { pUVs = pPrimitive->getUVCoordIndicesArray()[0]; m_bHasUVs = ( pUVs->getIndices().getCount() != 0 ); } SubMesh* pSubMesh = new SubMesh; pSubMesh->SetName( m_pMesh->getName() ); Resource::Material* pMaterial = Resource::MaterialManager::GetInstance()->CreateOrRetrieveMaterial( m_pMesh->getName() ); pSubMesh->SetMaterial( pMaterial ); Render::VertexBuffer& vertexBuf = pSubMesh->RenderData().VertexBuf(); pSubMesh->RenderData().PrimitiveType( Render::TYPE_TRIANGLES ); vertexBuf.ChannelFlag() = Render::POSITION_CH; if( m_bHasNormals ) { vertexBuf.ChannelFlag() |= Render::NORMAL_CH; } if( m_bHasUVs ) { vertexBuf.ChannelFlag() |= Render::TEXCOORD_CH; } if( m_bHasTangents ) { vertexBuf.ChannelFlag() |= Render::TANGENT_CH; } if( m_bHasBinormals ) { vertexBuf.ChannelFlag() |= Render::BINORMAL_CH; } unsigned int uiCurrIndex = 0; unsigned int uiIndicesCount = positionIndices.getCount(); for( unsigned int uiIndex = 0 ; uiIndex < uiIndicesCount ; uiIndex++ ) { Tuple tuple; tuple.m_posIndex = positionIndices[uiIndex]; if( m_bHasNormals ) { tuple.m_normIndex = normalIndices[uiIndex]; } if( m_bHasUVs ) { tuple.m_uvIndex = pUVs->getIndices()[uiIndex]; } if( m_bHasTangents ) { tuple.m_tangentIndex = tangentIndices[uiIndex]; } if( m_bHasBinormals ) { tuple.m_binormalIndex = binormalIndices[uiIndex]; } indicesTable_t::iterator itIndex = m_indicesMap.find(tuple); if( itIndex == m_indicesMap.end() ) { Render::Vertex newVert; LoadVertexByTuple( tuple , newVert ); vertexBuf.AppendVertex( newVert ); m_indicesMap.insert( std::make_pair( tuple , uiCurrIndex ) ); pSubMesh->RenderData().AppendIndex( uiCurrIndex ); uiCurrIndex++; }else{ pSubMesh->RenderData().AppendIndex( itIndex->second ); } }//for( unsigned int uiIndex = 0 ; uiIndex < uiIndicesCount ; uiIndex++ ) return pSubMesh; }
// ======================================================================= // Read all faces from TRIANGLES, TRIANGLE_FANS, POLYLIST, POLYGON // Important: This function MUST be called before read_lines() // Otherwise we will loose all edges from faces (see read_lines() above) // // TODO: import uv set names // ======================================================================== void MeshImporter::read_polys(COLLADAFW::Mesh *collada_mesh, Mesh *me) { unsigned int i; allocate_poly_data(collada_mesh, me); UVDataWrapper uvs(collada_mesh->getUVCoords()); VCOLDataWrapper vcol(collada_mesh->getColors()); MPoly *mpoly = me->mpoly; MLoop *mloop = me->mloop; int loop_index = 0; MaterialIdPrimitiveArrayMap mat_prim_map; COLLADAFW::MeshPrimitiveArray& prim_arr = collada_mesh->getMeshPrimitives(); COLLADAFW::MeshVertexData& nor = collada_mesh->getNormals(); for (i = 0; i < prim_arr.getCount(); i++) { COLLADAFW::MeshPrimitive *mp = prim_arr[i]; // faces size_t prim_totpoly = mp->getFaceCount(); unsigned int *position_indices = mp->getPositionIndices().getData(); unsigned int *normal_indices = mp->getNormalIndices().getData(); bool mp_has_normals = primitive_has_useable_normals(mp); bool mp_has_faces = primitive_has_faces(mp); int collada_meshtype = mp->getPrimitiveType(); // since we cannot set mpoly->mat_nr here, we store a portion of me->mpoly in Primitive Primitive prim = {mpoly, 0}; // If MeshPrimitive is TRIANGLE_FANS we split it into triangles // The first trifan vertex will be the first vertex in every triangle // XXX The proper function of TRIANGLE_FANS is not tested!!! // XXX In particular the handling of the normal_indices looks very wrong to me if (collada_meshtype == COLLADAFW::MeshPrimitive::TRIANGLE_FANS) { unsigned grouped_vertex_count = mp->getGroupedVertexElementsCount(); for (unsigned int group_index = 0; group_index < grouped_vertex_count; group_index++) { unsigned int first_vertex = position_indices[0]; // Store first trifan vertex unsigned int first_normal = normal_indices[0]; // Store first trifan vertex normal unsigned int vertex_count = mp->getGroupedVerticesVertexCount(group_index); for (unsigned int vertex_index = 0; vertex_index < vertex_count - 2; vertex_index++) { // For each triangle store indeces of its 3 vertices unsigned int triangle_vertex_indices[3] = {first_vertex, position_indices[1], position_indices[2]}; set_poly_indices(mpoly, mloop, loop_index, triangle_vertex_indices, 3); if (mp_has_normals) { // vertex normals, same inplementation as for the triangles // the same for vertces normals unsigned int vertex_normal_indices[3] = {first_normal, normal_indices[1], normal_indices[2]}; if (!is_flat_face(vertex_normal_indices, nor, 3)) mpoly->flag |= ME_SMOOTH; normal_indices++; } mpoly++; mloop += 3; loop_index += 3; prim.totpoly++; } // Moving cursor to the next triangle fan. if (mp_has_normals) normal_indices += 2; position_indices += 2; } } if (collada_meshtype == COLLADAFW::MeshPrimitive::POLYLIST || collada_meshtype == COLLADAFW::MeshPrimitive::POLYGONS || collada_meshtype == COLLADAFW::MeshPrimitive::TRIANGLES) { COLLADAFW::Polygons *mpvc = (COLLADAFW::Polygons *)mp; unsigned int start_index = 0; COLLADAFW::IndexListArray& index_list_array_uvcoord = mp->getUVCoordIndicesArray(); COLLADAFW::IndexListArray& index_list_array_vcolor = mp->getColorIndicesArray(); for (unsigned int j = 0; j < prim_totpoly; j++) { // Vertices in polygon: int vcount = get_vertex_count(mpvc, j); set_poly_indices(mpoly, mloop, loop_index, position_indices, vcount); for (unsigned int uvset_index = 0; uvset_index < index_list_array_uvcoord.getCount(); uvset_index++) { // get mtface by face index and uv set index COLLADAFW::IndexList& index_list = *index_list_array_uvcoord[uvset_index]; MLoopUV *mloopuv = (MLoopUV *)CustomData_get_layer_named(&me->ldata, CD_MLOOPUV, index_list.getName().c_str()); if (mloopuv == NULL) { fprintf(stderr, "Collada import: Mesh [%s] : Unknown reference to TEXCOORD [#%s].\n", me->id.name, index_list.getName().c_str() ); } else { set_face_uv(mloopuv+loop_index, uvs, start_index, *index_list_array_uvcoord[uvset_index], vcount); } } if (mp_has_normals) { if (!is_flat_face(normal_indices, nor, vcount)) mpoly->flag |= ME_SMOOTH; } if (mp->hasColorIndices()) { int vcolor_count = index_list_array_vcolor.getCount(); for (unsigned int vcolor_index = 0; vcolor_index < vcolor_count; vcolor_index++) { COLLADAFW::IndexList& color_index_list = *mp->getColorIndices(vcolor_index); COLLADAFW::String colname = extract_vcolname(color_index_list.getName()); MLoopCol *mloopcol = (MLoopCol *)CustomData_get_layer_named(&me->ldata, CD_MLOOPCOL, colname.c_str()); if (mloopcol == NULL) { fprintf(stderr, "Collada import: Mesh [%s] : Unknown reference to VCOLOR [#%s].\n", me->id.name, color_index_list.getName().c_str()); } else { set_vcol(mloopcol + loop_index, vcol, start_index, color_index_list, vcount); } } } mpoly++; mloop += vcount; loop_index += vcount; start_index += vcount; prim.totpoly++; if (mp_has_normals) normal_indices += vcount; position_indices += vcount; } } else if (collada_meshtype == COLLADAFW::MeshPrimitive::LINES) { continue; // read the lines later after all the rest is done } if (mp_has_faces) mat_prim_map[mp->getMaterialId()].push_back(prim); } geom_uid_mat_mapping_map[collada_mesh->getUniqueId()] = mat_prim_map; }
// ================================================================= // Return the number of faces by summing up // the facecounts of the parts. // hint: This is done because mesh->getFacesCount() does // count loose edges as extra faces, which is not what we want here. // ================================================================= void MeshImporter::allocate_poly_data(COLLADAFW::Mesh *collada_mesh, Mesh *me) { COLLADAFW::MeshPrimitiveArray& prim_arr = collada_mesh->getMeshPrimitives(); int total_poly_count = 0; int total_loop_count = 0; // collect edge_count and face_count from all parts for (int i = 0; i < prim_arr.getCount(); i++) { COLLADAFW::MeshPrimitive *mp = prim_arr[i]; int type = mp->getPrimitiveType(); switch (type) { case COLLADAFW::MeshPrimitive::TRIANGLES: case COLLADAFW::MeshPrimitive::TRIANGLE_FANS: case COLLADAFW::MeshPrimitive::POLYLIST: case COLLADAFW::MeshPrimitive::POLYGONS: { COLLADAFW::Polygons *mpvc = (COLLADAFW::Polygons *)mp; size_t prim_poly_count = mpvc->getFaceCount(); size_t prim_loop_count = 0; for (int index=0; index < prim_poly_count; index++) { prim_loop_count += get_vertex_count(mpvc, index); } total_poly_count += prim_poly_count; total_loop_count += prim_loop_count; break; } default: break; } } // Add the data containers if (total_poly_count > 0) { me->totpoly = total_poly_count; me->totloop = total_loop_count; me->mpoly = (MPoly *)CustomData_add_layer(&me->pdata, CD_MPOLY, CD_CALLOC, NULL, me->totpoly); me->mloop = (MLoop *)CustomData_add_layer(&me->ldata, CD_MLOOP, CD_CALLOC, NULL, me->totloop); unsigned int totuvset = collada_mesh->getUVCoords().getInputInfosArray().getCount(); for (int i = 0; i < totuvset; i++) { if (collada_mesh->getUVCoords().getLength(i) == 0) { totuvset = 0; break; } } if (totuvset > 0) { for (int i = 0; i < totuvset; i++) { COLLADAFW::MeshVertexData::InputInfos *info = collada_mesh->getUVCoords().getInputInfosArray()[i]; COLLADAFW::String &uvname = info->mName; // Allocate space for UV_data CustomData_add_layer_named(&me->pdata, CD_MTEXPOLY, CD_DEFAULT, NULL, me->totpoly, uvname.c_str()); CustomData_add_layer_named(&me->ldata, CD_MLOOPUV, CD_DEFAULT, NULL, me->totloop, uvname.c_str()); } // activate the first uv map me->mtpoly = (MTexPoly *)CustomData_get_layer_n(&me->pdata, CD_MTEXPOLY, 0); me->mloopuv = (MLoopUV *) CustomData_get_layer_n(&me->ldata, CD_MLOOPUV, 0); } int totcolset = collada_mesh->getColors().getInputInfosArray().getCount(); if (totcolset > 0) { for (int i = 0; i < totcolset; i++) { COLLADAFW::MeshVertexData::InputInfos *info = collada_mesh->getColors().getInputInfosArray()[i]; COLLADAFW::String colname = extract_vcolname(info->mName); CustomData_add_layer_named(&me->ldata,CD_MLOOPCOL,CD_DEFAULT,NULL,me->totloop, colname.c_str()); } me->mloopcol = (MLoopCol *) CustomData_get_layer_n(&me->ldata, CD_MLOOPCOL, 0); } } }