/** * We do not know in advance which objects will share geometries. * And we do not know either if the objects which share geometries * come along with different materials. So we first create the objects * and assign the materials to Object, then in a later cleanup we decide * which materials shall be moved to the created geometries. Also see * optimize_material_assignements() above. */ MTFace *MeshImporter::assign_material_to_geom(COLLADAFW::MaterialBinding cmaterial, std::map<COLLADAFW::UniqueId, Material *>& uid_material_map, Object *ob, const COLLADAFW::UniqueId *geom_uid, char *layername, MTFace *texture_face, std::map<Material *, TexIndexTextureArrayMap>& material_texture_mapping_map, short mat_index) { MTex *color_texture = NULL; Mesh *me = (Mesh *)ob->data; const COLLADAFW::UniqueId& ma_uid = cmaterial.getReferencedMaterial(); // do we know this material? if (uid_material_map.find(ma_uid) == uid_material_map.end()) { fprintf(stderr, "Cannot find material by UID.\n"); return NULL; } // first time we get geom_uid, ma_uid pair. Save for later check. materials_mapped_to_geom.insert(std::pair<COLLADAFW::UniqueId, COLLADAFW::UniqueId>(*geom_uid, ma_uid)); Material *ma = uid_material_map[ma_uid]; // Attention! This temporaly assigns material to object on purpose! // See note above. ob->actcol=0; assign_material(ob, ma, mat_index + 1, BKE_MAT_ASSIGN_OBJECT); COLLADAFW::TextureCoordinateBindingArray& tex_array = cmaterial.getTextureCoordinateBindingArray(); TexIndexTextureArrayMap texindex_texarray_map = material_texture_mapping_map[ma]; unsigned int i; // loop through <bind_vertex_inputs> for (i = 0; i < tex_array.getCount(); i++) { color_texture = assign_textures_to_uvlayer(tex_array[i], me, texindex_texarray_map, color_texture); } // set texture face if (color_texture && strlen((color_texture)->uvname) && !STREQ(layername, color_texture->uvname)) { texture_face = (MTFace *)CustomData_get_layer_named(&me->fdata, CD_MTFACE, color_texture->uvname); strcpy(layername, color_texture->uvname); } MaterialIdPrimitiveArrayMap& mat_prim_map = geom_uid_mat_mapping_map[*geom_uid]; COLLADAFW::MaterialId mat_id = cmaterial.getMaterialId(); // assign material indices to mesh faces if (mat_prim_map.find(mat_id) != mat_prim_map.end()) { std::vector<Primitive>& prims = mat_prim_map[mat_id]; std::vector<Primitive>::iterator it; for (it = prims.begin(); it != prims.end(); it++) { Primitive& prim = *it; MPoly *mpoly = prim.mpoly; for (i = 0; i < prim.totpoly; i++, mpoly++) { mpoly->mat_nr = mat_index; // bind texture images to faces if (texture_face && color_texture) { texture_face->tpage = (Image *)color_texture->tex->ima; texture_face++; } } } } return texture_face; }
void get_texture_coords(MappingInfoModifierData *dmd, Object *ob, DerivedMesh *dm, float (*co)[3], float (*texco)[3], int numVerts) { int i; int texmapping = dmd->texmapping; float mapob_imat[4][4]; if(texmapping == MOD_DISP_MAP_OBJECT) { if(dmd->map_object) invert_m4_m4(mapob_imat, dmd->map_object->obmat); else /* if there is no map object, default to local */ texmapping = MOD_DISP_MAP_LOCAL; } /* UVs need special handling, since they come from faces */ if(texmapping == MOD_DISP_MAP_UV) { if(CustomData_has_layer(&dm->faceData, CD_MTFACE)) { MFace *mface = dm->getFaceArray(dm); MFace *mf; char *done = MEM_callocN(sizeof(*done) * numVerts, "get_texture_coords done"); int numFaces = dm->getNumFaces(dm); char uvname[32]; MTFace *tf; validate_layer_name(&dm->faceData, CD_MTFACE, dmd->uvlayer_name, uvname); tf = CustomData_get_layer_named(&dm->faceData, CD_MTFACE, uvname); /* verts are given the UV from the first face that uses them */ for(i = 0, mf = mface; i < numFaces; ++i, ++mf, ++tf) { if(!done[mf->v1]) { texco[mf->v1][0] = tf->uv[0][0]; texco[mf->v1][1] = tf->uv[0][1]; texco[mf->v1][2] = 0; done[mf->v1] = 1; } if(!done[mf->v2]) { texco[mf->v2][0] = tf->uv[1][0]; texco[mf->v2][1] = tf->uv[1][1]; texco[mf->v2][2] = 0; done[mf->v2] = 1; } if(!done[mf->v3]) { texco[mf->v3][0] = tf->uv[2][0]; texco[mf->v3][1] = tf->uv[2][1]; texco[mf->v3][2] = 0; done[mf->v3] = 1; } if(!done[mf->v4]) { texco[mf->v4][0] = tf->uv[3][0]; texco[mf->v4][1] = tf->uv[3][1]; texco[mf->v4][2] = 0; done[mf->v4] = 1; } } /* remap UVs from [0, 1] to [-1, 1] */ for(i = 0; i < numVerts; ++i) { texco[i][0] = texco[i][0] * 2 - 1; texco[i][1] = texco[i][1] * 2 - 1; } MEM_freeN(done); return; } else /* if there are no UVs, default to local */ texmapping = MOD_DISP_MAP_LOCAL; } for(i = 0; i < numVerts; ++i, ++co, ++texco) { switch(texmapping) { case MOD_DISP_MAP_LOCAL: copy_v3_v3(*texco, *co); break; case MOD_DISP_MAP_GLOBAL: mul_v3_m4v3(*texco, ob->obmat, *co); break; case MOD_DISP_MAP_OBJECT: mul_v3_m4v3(*texco, ob->obmat, *co); mul_m4_v3(mapob_imat, *texco); break; } } }
static DerivedMesh *explodeMesh(ExplodeModifierData *emd, ParticleSystemModifierData *psmd, Scene *scene, Object *ob, DerivedMesh *to_explode) { DerivedMesh *explode, *dm = to_explode; MFace *mf = NULL, *mface; /* ParticleSettings *part=psmd->psys->part; */ /* UNUSED */ ParticleSimulationData sim = {NULL}; ParticleData *pa = NULL, *pars = psmd->psys->particles; ParticleKey state, birth; EdgeHash *vertpahash; EdgeHashIterator *ehi; float *vertco = NULL, imat[4][4]; float rot[4]; float cfra; /* float timestep; */ const int *facepa = emd->facepa; int totdup = 0, totvert = 0, totface = 0, totpart = 0, delface = 0; int i, v, u; unsigned int ed_v1, ed_v2, mindex = 0; MTFace *mtface = NULL, *mtf; totface = dm->getNumTessFaces(dm); totvert = dm->getNumVerts(dm); mface = dm->getTessFaceArray(dm); totpart = psmd->psys->totpart; sim.scene = scene; sim.ob = ob; sim.psys = psmd->psys; sim.psmd = psmd; /* timestep = psys_get_timestep(&sim); */ cfra = BKE_scene_frame_get(scene); /* hash table for vertice <-> particle relations */ vertpahash = BLI_edgehash_new(__func__); for (i = 0; i < totface; i++) { if (facepa[i] != totpart) { pa = pars + facepa[i]; if ((pa->alive == PARS_UNBORN && (emd->flag & eExplodeFlag_Unborn) == 0) || (pa->alive == PARS_ALIVE && (emd->flag & eExplodeFlag_Alive) == 0) || (pa->alive == PARS_DEAD && (emd->flag & eExplodeFlag_Dead) == 0)) { delface++; continue; } } /* do mindex + totvert to ensure the vertex index to be the first * with BLI_edgehashIterator_getKey */ if (facepa[i] == totpart || cfra < (pars + facepa[i])->time) mindex = totvert + totpart; else mindex = totvert + facepa[i]; mf = &mface[i]; /* set face vertices to exist in particle group */ BLI_edgehash_reinsert(vertpahash, mf->v1, mindex, NULL); BLI_edgehash_reinsert(vertpahash, mf->v2, mindex, NULL); BLI_edgehash_reinsert(vertpahash, mf->v3, mindex, NULL); if (mf->v4) BLI_edgehash_reinsert(vertpahash, mf->v4, mindex, NULL); } /* make new vertice indexes & count total vertices after duplication */ ehi = BLI_edgehashIterator_new(vertpahash); for (; !BLI_edgehashIterator_isDone(ehi); BLI_edgehashIterator_step(ehi)) { BLI_edgehashIterator_setValue(ehi, SET_INT_IN_POINTER(totdup)); totdup++; } BLI_edgehashIterator_free(ehi); /* the final duplicated vertices */ explode = CDDM_from_template_ex(dm, totdup, 0, totface - delface, 0, 0, CD_MASK_DERIVEDMESH | CD_MASK_FACECORNERS); mtface = CustomData_get_layer_named(&explode->faceData, CD_MTFACE, emd->uvname); /*dupvert = CDDM_get_verts(explode);*/ /* getting back to object space */ invert_m4_m4(imat, ob->obmat); psmd->psys->lattice_deform_data = psys_create_lattice_deform_data(&sim); /* duplicate & displace vertices */ ehi = BLI_edgehashIterator_new(vertpahash); for (; !BLI_edgehashIterator_isDone(ehi); BLI_edgehashIterator_step(ehi)) { MVert source; MVert *dest; /* get particle + vertex from hash */ BLI_edgehashIterator_getKey(ehi, &ed_v1, &ed_v2); ed_v2 -= totvert; v = GET_INT_FROM_POINTER(BLI_edgehashIterator_getValue(ehi)); dm->getVert(dm, ed_v1, &source); dest = CDDM_get_vert(explode, v); DM_copy_vert_data(dm, explode, ed_v1, v, 1); *dest = source; if (ed_v2 != totpart) { /* get particle */ pa = pars + ed_v2; psys_get_birth_coords(&sim, pa, &birth, 0, 0); state.time = cfra; psys_get_particle_state(&sim, ed_v2, &state, 1); vertco = CDDM_get_vert(explode, v)->co; mul_m4_v3(ob->obmat, vertco); sub_v3_v3(vertco, birth.co); /* apply rotation, size & location */ sub_qt_qtqt(rot, state.rot, birth.rot); mul_qt_v3(rot, vertco); if (emd->flag & eExplodeFlag_PaSize) mul_v3_fl(vertco, pa->size); add_v3_v3(vertco, state.co); mul_m4_v3(imat, vertco); } } BLI_edgehashIterator_free(ehi); /*map new vertices to faces*/ for (i = 0, u = 0; i < totface; i++) { MFace source; int orig_v4; if (facepa[i] != totpart) { pa = pars + facepa[i]; if (pa->alive == PARS_UNBORN && (emd->flag & eExplodeFlag_Unborn) == 0) continue; if (pa->alive == PARS_ALIVE && (emd->flag & eExplodeFlag_Alive) == 0) continue; if (pa->alive == PARS_DEAD && (emd->flag & eExplodeFlag_Dead) == 0) continue; } dm->getTessFace(dm, i, &source); mf = CDDM_get_tessface(explode, u); orig_v4 = source.v4; if (facepa[i] != totpart && cfra < pa->time) mindex = totvert + totpart; else mindex = totvert + facepa[i]; source.v1 = edgecut_get(vertpahash, source.v1, mindex); source.v2 = edgecut_get(vertpahash, source.v2, mindex); source.v3 = edgecut_get(vertpahash, source.v3, mindex); if (source.v4) source.v4 = edgecut_get(vertpahash, source.v4, mindex); DM_copy_tessface_data(dm, explode, i, u, 1); *mf = source; /* override uv channel for particle age */ if (mtface) { float age = (cfra - pa->time) / pa->lifetime; /* Clamp to this range to avoid flipping to the other side of the coordinates. */ CLAMP(age, 0.001f, 0.999f); mtf = mtface + u; mtf->uv[0][0] = mtf->uv[1][0] = mtf->uv[2][0] = mtf->uv[3][0] = age; mtf->uv[0][1] = mtf->uv[1][1] = mtf->uv[2][1] = mtf->uv[3][1] = 0.5f; } test_index_face(mf, &explode->faceData, u, (orig_v4 ? 4 : 3)); u++; } /* cleanup */ BLI_edgehash_free(vertpahash, NULL); /* finalization */ CDDM_calc_edges_tessface(explode); CDDM_tessfaces_to_faces(explode); explode->dirty |= DM_DIRTY_NORMALS; if (psmd->psys->lattice_deform_data) { end_latt_deform(psmd->psys->lattice_deform_data); psmd->psys->lattice_deform_data = NULL; } return explode; }
void get_texture_coords(MappingInfoModifierData *dmd, Object *ob, DerivedMesh *dm, float (*co)[3], float (*texco)[3], int numVerts) { int i; int texmapping = dmd->texmapping; float mapob_imat[4][4]; if (texmapping == MOD_DISP_MAP_OBJECT) { if (dmd->map_object) invert_m4_m4(mapob_imat, dmd->map_object->obmat); else /* if there is no map object, default to local */ texmapping = MOD_DISP_MAP_LOCAL; } /* UVs need special handling, since they come from faces */ if (texmapping == MOD_DISP_MAP_UV) { if (CustomData_has_layer(&dm->loopData, CD_MLOOPUV)) { MPoly *mpoly = dm->getPolyArray(dm); MPoly *mp; MLoop *mloop = dm->getLoopArray(dm); char *done = MEM_calloc_arrayN(numVerts, sizeof(*done), "get_texture_coords done"); int numPolys = dm->getNumPolys(dm); char uvname[MAX_CUSTOMDATA_LAYER_NAME]; MLoopUV *mloop_uv; CustomData_validate_layer_name(&dm->loopData, CD_MLOOPUV, dmd->uvlayer_name, uvname); mloop_uv = CustomData_get_layer_named(&dm->loopData, CD_MLOOPUV, uvname); /* verts are given the UV from the first face that uses them */ for (i = 0, mp = mpoly; i < numPolys; ++i, ++mp) { unsigned int fidx = mp->totloop - 1; do { unsigned int lidx = mp->loopstart + fidx; unsigned int vidx = mloop[lidx].v; if (done[vidx] == 0) { /* remap UVs from [0, 1] to [-1, 1] */ texco[vidx][0] = (mloop_uv[lidx].uv[0] * 2.0f) - 1.0f; texco[vidx][1] = (mloop_uv[lidx].uv[1] * 2.0f) - 1.0f; done[vidx] = 1; } } while (fidx--); } MEM_freeN(done); return; } else /* if there are no UVs, default to local */ texmapping = MOD_DISP_MAP_LOCAL; } for (i = 0; i < numVerts; ++i, ++co, ++texco) { switch (texmapping) { case MOD_DISP_MAP_LOCAL: copy_v3_v3(*texco, *co); break; case MOD_DISP_MAP_GLOBAL: mul_v3_m4v3(*texco, ob->obmat, *co); break; case MOD_DISP_MAP_OBJECT: mul_v3_m4v3(*texco, ob->obmat, *co); mul_m4_v3(mapob_imat, *texco); break; } } }
// ======================================================================= // 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()); 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}; COLLADAFW::IndexListArray& index_list_array = mp->getUVCoordIndicesArray(); // 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; 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.getCount(); uvset_index++) { // get mtface by face index and uv set index COLLADAFW::IndexList& index_list = *index_list_array[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].", me->id.name, index_list.getName().c_str() ); } else { set_face_uv(mloopuv+loop_index, uvs, start_index, *index_list_array[uvset_index], vcount); } } if (mp_has_normals) { if (!is_flat_face(normal_indices, nor, vcount)) mpoly->flag |= ME_SMOOTH; } 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; }