/* Create new external mesh */ static void exporter_InitGeomArrays(ExportMeshData *export_data, int num_verts, int num_edges, int num_loops, int num_polys) { DerivedMesh *dm = CDDM_new(num_verts, num_edges, 0, num_loops, num_polys); DerivedMesh *dm_left = export_data->dm_left, *dm_right = export_data->dm_right; /* Mask for custom data layers to be merged from operands. */ CustomDataMask merge_mask = CD_MASK_DERIVEDMESH & ~CD_MASK_ORIGINDEX; export_data->dm = dm; export_data->mvert = dm->getVertArray(dm); export_data->medge = dm->getEdgeArray(dm); export_data->mloop = dm->getLoopArray(dm); export_data->mpoly = dm->getPolyArray(dm); /* Allocate layers for UV layers and vertex colors. * Without this interpolation of those data will not happen. */ allocate_custom_layers(&dm->loopData, CD_MLOOPCOL, num_loops, CustomData_number_of_layers(&dm_left->loopData, CD_MLOOPCOL)); allocate_custom_layers(&dm->loopData, CD_MLOOPUV, num_loops, CustomData_number_of_layers(&dm_left->loopData, CD_MLOOPUV)); allocate_custom_layers(&dm->loopData, CD_MLOOPCOL, num_loops, CustomData_number_of_layers(&dm_right->loopData, CD_MLOOPCOL)); allocate_custom_layers(&dm->loopData, CD_MLOOPUV, num_loops, CustomData_number_of_layers(&dm_right->loopData, CD_MLOOPUV)); /* Merge custom data layers from operands. * * Will only create custom data layers for all the layers which appears in * the operand. Data for those layers will not be allocated or initialized. */ CustomData_merge(&dm_left->polyData, &dm->polyData, merge_mask, CD_DEFAULT, num_polys); CustomData_merge(&dm_right->polyData, &dm->polyData, merge_mask, CD_DEFAULT, num_polys); CustomData_merge(&dm_left->edgeData, &dm->edgeData, merge_mask, CD_DEFAULT, num_edges); CustomData_merge(&dm_right->edgeData, &dm->edgeData, merge_mask, CD_DEFAULT, num_edges); export_data->vert_origindex = dm->getVertDataArray(dm, CD_ORIGINDEX); export_data->edge_origindex = dm->getEdgeDataArray(dm, CD_ORIGINDEX); export_data->poly_origindex = dm->getPolyDataArray(dm, CD_ORIGINDEX); export_data->loop_origindex = dm->getLoopDataArray(dm, CD_ORIGINDEX); }
int join_mesh_exec(bContext *C, wmOperator *op) { Main *bmain= CTX_data_main(C); Scene *scene= CTX_data_scene(C); Object *ob= CTX_data_active_object(C); Material **matar, *ma; Mesh *me; MVert *mvert, *mv; MEdge *medge = NULL; MFace *mface = NULL; Key *key, *nkey=NULL; KeyBlock *kb, *okb, *kbn; float imat[4][4], cmat[4][4], *fp1, *fp2, curpos; int a, b, totcol, totmat=0, totedge=0, totvert=0, totface=0, ok=0; int vertofs, *matmap=NULL; int i, j, index, haskey=0, edgeofs, faceofs; bDeformGroup *dg, *odg; MDeformVert *dvert; CustomData vdata, edata, fdata; if(scene->obedit) { BKE_report(op->reports, RPT_WARNING, "Cant join while in editmode"); return OPERATOR_CANCELLED; } /* ob is the object we are adding geometry to */ if(!ob || ob->type!=OB_MESH) { BKE_report(op->reports, RPT_WARNING, "Active object is not a mesh"); return OPERATOR_CANCELLED; } /* count & check */ CTX_DATA_BEGIN(C, Base*, base, selected_editable_bases) { if(base->object->type==OB_MESH) { me= base->object->data; totvert+= me->totvert; totedge+= me->totedge; totface+= me->totface; totmat+= base->object->totcol; if(base->object == ob) ok= 1; /* check for shapekeys */ if(me->key) haskey++; } } CTX_DATA_END; /* that way the active object is always selected */ if(ok==0) { BKE_report(op->reports, RPT_WARNING, "Active object is not a selected mesh"); return OPERATOR_CANCELLED; } /* only join meshes if there are verts to join, there aren't too many, and we only had one mesh selected */ me= (Mesh *)ob->data; key= me->key; if(totvert==0 || totvert==me->totvert) { BKE_report(op->reports, RPT_WARNING, "No mesh data to join"); return OPERATOR_CANCELLED; } if(totvert > MESH_MAX_VERTS) { BKE_reportf(op->reports, RPT_WARNING, "Joining results in %d vertices, limit is " STRINGIFY(MESH_MAX_VERTS), totvert); return OPERATOR_CANCELLED; } /* new material indices and material array */ matar= MEM_callocN(sizeof(void*)*totmat, "join_mesh matar"); if (totmat) matmap= MEM_callocN(sizeof(int)*totmat, "join_mesh matmap"); totcol= ob->totcol; /* obact materials in new main array, is nicer start! */ for(a=0; a<ob->totcol; a++) { matar[a]= give_current_material(ob, a+1); id_us_plus((ID *)matar[a]); /* increase id->us : will be lowered later */ } /* - if destination mesh had shapekeys, move them somewhere safe, and set up placeholders * with arrays that are large enough to hold shapekey data for all meshes * - if destination mesh didn't have shapekeys, but we encountered some in the meshes we're * joining, set up a new keyblock and assign to the mesh */ if(key) { /* make a duplicate copy that will only be used here... (must remember to free it!) */ nkey= copy_key(key); /* for all keys in old block, clear data-arrays */ for(kb= key->block.first; kb; kb= kb->next) { if(kb->data) MEM_freeN(kb->data); kb->data= MEM_callocN(sizeof(float)*3*totvert, "join_shapekey"); kb->totelem= totvert; kb->weights= NULL; } } else if(haskey) { /* add a new key-block and add to the mesh */ key= me->key= add_key((ID *)me); key->type = KEY_RELATIVE; } /* first pass over objects - copying materials and vertexgroups across */ CTX_DATA_BEGIN(C, Base*, base, selected_editable_bases) { /* only act if a mesh, and not the one we're joining to */ if((ob!=base->object) && (base->object->type==OB_MESH)) { me= base->object->data; /* Join this object's vertex groups to the base one's */ for(dg=base->object->defbase.first; dg; dg=dg->next) { /* See if this group exists in the object (if it doesn't, add it to the end) */ if(!defgroup_find_name(ob, dg->name)) { odg = MEM_callocN(sizeof(bDeformGroup), "join deformGroup"); memcpy(odg, dg, sizeof(bDeformGroup)); BLI_addtail(&ob->defbase, odg); } } if(ob->defbase.first && ob->actdef==0) ob->actdef=1; if(me->totvert) { /* Add this object's materials to the base one's if they don't exist already (but only if limits not exceeded yet) */ if(totcol < MAXMAT) { for(a=1; a<=base->object->totcol; a++) { ma= give_current_material(base->object, a); for(b=0; b<totcol; b++) { if(ma == matar[b]) break; } if(b==totcol) { matar[b]= ma; if(ma) { id_us_plus(&ma->id); } totcol++; } if(totcol >= MAXMAT) break; } } /* if this mesh has shapekeys, check if destination mesh already has matching entries too */ if(me->key && key) { for(kb= me->key->block.first; kb; kb= kb->next) { /* if key doesn't exist in destination mesh, add it */ if(key_get_named_keyblock(key, kb->name) == NULL) { /* copy this existing one over to the new shapekey block */ kbn= MEM_dupallocN(kb); kbn->prev= kbn->next= NULL; /* adjust adrcode and other settings to fit (allocate a new data-array) */ kbn->data= MEM_callocN(sizeof(float)*3*totvert, "joined_shapekey"); kbn->totelem= totvert; kbn->weights= NULL; okb= key->block.last; curpos= (okb) ? okb->pos : -0.1f; if(key->type == KEY_RELATIVE) kbn->pos= curpos + 0.1f; else kbn->pos= curpos; BLI_addtail(&key->block, kbn); kbn->adrcode= key->totkey; key->totkey++; if(key->totkey==1) key->refkey= kbn; // XXX 2.5 Animato #if 0 /* also, copy corresponding ipo-curve to ipo-block if applicable */ if(me->key->ipo && key->ipo) { // FIXME... this is a luxury item! puts("FIXME: ignoring IPO's when joining shapekeys on Meshes for now..."); } #endif } } } } } } CTX_DATA_END; /* setup new data for destination mesh */ memset(&vdata, 0, sizeof(vdata)); memset(&edata, 0, sizeof(edata)); memset(&fdata, 0, sizeof(fdata)); mvert= CustomData_add_layer(&vdata, CD_MVERT, CD_CALLOC, NULL, totvert); medge= CustomData_add_layer(&edata, CD_MEDGE, CD_CALLOC, NULL, totedge); mface= CustomData_add_layer(&fdata, CD_MFACE, CD_CALLOC, NULL, totface); vertofs= 0; edgeofs= 0; faceofs= 0; /* inverse transform for all selected meshes in this object */ invert_m4_m4(imat, ob->obmat); CTX_DATA_BEGIN(C, Base*, base, selected_editable_bases) { /* only join if this is a mesh */ if(base->object->type==OB_MESH) { me= base->object->data; if(me->totvert) { /* standard data */ CustomData_merge(&me->vdata, &vdata, CD_MASK_MESH, CD_DEFAULT, totvert); CustomData_copy_data(&me->vdata, &vdata, 0, vertofs, me->totvert); /* vertex groups */ dvert= CustomData_get(&vdata, vertofs, CD_MDEFORMVERT); /* NB: vertex groups here are new version */ if(dvert) { for(i=0; i<me->totvert; i++) { for(j=0; j<dvert[i].totweight; j++) { /* Find the old vertex group */ odg = BLI_findlink(&base->object->defbase, dvert[i].dw[j].def_nr); if(odg) { /* Search for a match in the new object, and set new index */ for(dg=ob->defbase.first, index=0; dg; dg=dg->next, index++) { if(!strcmp(dg->name, odg->name)) { dvert[i].dw[j].def_nr = index; break; } } } } } } /* if this is the object we're merging into, no need to do anything */ if(base->object != ob) { /* watch this: switch matmul order really goes wrong */ mul_m4_m4m4(cmat, base->object->obmat, imat); /* transform vertex coordinates into new space */ for(a=0, mv=mvert; a < me->totvert; a++, mv++) { mul_m4_v3(cmat, mv->co); } /* for each shapekey in destination mesh: * - if there's a matching one, copy it across (will need to transform vertices into new space...) * - otherwise, just copy own coordinates of mesh (no need to transform vertex coordinates into new space) */ if(key) { /* if this mesh has any shapekeys, check first, otherwise just copy coordinates */ for(kb= key->block.first; kb; kb= kb->next) { /* get pointer to where to write data for this mesh in shapekey's data array */ fp1= ((float *)kb->data) + (vertofs*3); /* check if this mesh has such a shapekey */ okb= key_get_named_keyblock(me->key, kb->name); if(okb) { /* copy this mesh's shapekey to the destination shapekey (need to transform first) */ fp2= ((float *)(okb->data)); for(a=0; a < me->totvert; a++, fp1+=3, fp2+=3) { VECCOPY(fp1, fp2); mul_m4_v3(cmat, fp1); } } else { /* copy this mesh's vertex coordinates to the destination shapekey */ mv= mvert; for(a=0; a < me->totvert; a++, fp1+=3, mv++) { VECCOPY(fp1, mv->co); } } } } } else { /* for each shapekey in destination mesh: * - if it was an 'original', copy the appropriate data from nkey * - otherwise, copy across plain coordinates (no need to transform coordinates) */ if(key) { for(kb= key->block.first; kb; kb= kb->next) { /* get pointer to where to write data for this mesh in shapekey's data array */ fp1= ((float *)kb->data) + (vertofs*3); /* check if this was one of the original shapekeys */ okb= key_get_named_keyblock(nkey, kb->name); if(okb) { /* copy this mesh's shapekey to the destination shapekey */ fp2= ((float *)(okb->data)); for(a=0; a < me->totvert; a++, fp1+=3, fp2+=3) { VECCOPY(fp1, fp2); } } else { /* copy base-coordinates to the destination shapekey */ mv= mvert; for(a=0; a < me->totvert; a++, fp1+=3, mv++) { VECCOPY(fp1, mv->co); } } } } } /* advance mvert pointer to end of base mesh's data */ mvert+= me->totvert; } if(me->totface) { /* make mapping for materials */ for(a=1; a<=base->object->totcol; a++) { ma= give_current_material(base->object, a); for(b=0; b<totcol; b++) { if(ma == matar[b]) { matmap[a-1]= b; break; } } } if(base->object!=ob) multiresModifier_prepare_join(scene, base->object, ob); CustomData_merge(&me->fdata, &fdata, CD_MASK_MESH, CD_DEFAULT, totface); CustomData_copy_data(&me->fdata, &fdata, 0, faceofs, me->totface); for(a=0; a<me->totface; a++, mface++) { mface->v1+= vertofs; mface->v2+= vertofs; mface->v3+= vertofs; if(mface->v4) mface->v4+= vertofs; if (matmap) mface->mat_nr= matmap[(int)mface->mat_nr]; else mface->mat_nr= 0; } faceofs += me->totface; } if(me->totedge) { CustomData_merge(&me->edata, &edata, CD_MASK_MESH, CD_DEFAULT, totedge); CustomData_copy_data(&me->edata, &edata, 0, edgeofs, me->totedge); for(a=0; a<me->totedge; a++, medge++) { medge->v1+= vertofs; medge->v2+= vertofs; } edgeofs += me->totedge; } /* vertofs is used to help newly added verts be reattached to their edge/face * (cannot be set earlier, or else reattaching goes wrong) */ vertofs += me->totvert; /* free base, now that data is merged */ if(base->object != ob) ED_base_object_free_and_unlink(bmain, scene, base); } } CTX_DATA_END; /* return to mesh we're merging to */ me= ob->data; CustomData_free(&me->vdata, me->totvert); CustomData_free(&me->edata, me->totedge); CustomData_free(&me->fdata, me->totface); me->totvert= totvert; me->totedge= totedge; me->totface= totface; me->vdata= vdata; me->edata= edata; me->fdata= fdata; mesh_update_customdata_pointers(me); /* old material array */ for(a=1; a<=ob->totcol; a++) { ma= ob->mat[a-1]; if(ma) ma->id.us--; } for(a=1; a<=me->totcol; a++) { ma= me->mat[a-1]; if(ma) ma->id.us--; } if(ob->mat) MEM_freeN(ob->mat); if(ob->matbits) MEM_freeN(ob->matbits); if(me->mat) MEM_freeN(me->mat); ob->mat= me->mat= NULL; ob->matbits= NULL; if(totcol) { me->mat= matar; ob->mat= MEM_callocN(sizeof(void *)*totcol, "join obmatar"); ob->matbits= MEM_callocN(sizeof(char)*totcol, "join obmatbits"); } else MEM_freeN(matar); ob->totcol= me->totcol= totcol; ob->colbits= 0; if (matmap) MEM_freeN(matmap); /* other mesh users */ test_object_materials((ID *)me); /* free temp copy of destination shapekeys (if applicable) */ if(nkey) { // XXX 2.5 Animato #if 0 /* free it's ipo too - both are not actually freed from memory yet as ID-blocks */ if(nkey->ipo) { free_ipo(nkey->ipo); BLI_remlink(&bmain->ipo, nkey->ipo); MEM_freeN(nkey->ipo); } #endif free_key(nkey); BLI_remlink(&bmain->key, nkey); MEM_freeN(nkey); } DAG_scene_sort(bmain, scene); // removed objects, need to rebuild dag before editmode call #if 0 ED_object_enter_editmode(C, EM_WAITCURSOR); ED_object_exit_editmode(C, EM_FREEDATA|EM_WAITCURSOR|EM_DO_UNDO); #else /* toggle editmode using lower level functions so this can be called from python */ make_editMesh(scene, ob); load_editMesh(scene, ob); free_editMesh(me->edit_mesh); MEM_freeN(me->edit_mesh); me->edit_mesh= NULL; DAG_id_tag_update(&ob->id, OB_RECALC_OB|OB_RECALC_DATA); #endif WM_event_add_notifier(C, NC_SCENE|ND_OB_ACTIVE, scene); return OPERATOR_FINISHED; }
DerivedMesh *BME_bmesh_to_derivedmesh(BME_Mesh *bm, DerivedMesh *dm) { MFace *mface, *mf; MEdge *medge, *me; MVert *mvert, *mv; int *origindex; int totface,totedge,totvert,i,bmeshok,len, numTex, numCol; BME_Vert *v1=NULL; BME_Edge *e=NULL, *oe=NULL; BME_Poly *f=NULL; DerivedMesh *result; EdgeHash *edge_hash = BLI_edgehash_new(); totvert = BLI_countlist(&(bm->verts)); totedge = 0; /*we cannot have double edges in a derived mesh!*/ for(i=0, v1=bm->verts.first; v1; v1=v1->next, i++) v1->tflag1 = i; for(e=bm->edges.first; e; e=e->next){ oe = BLI_edgehash_lookup(edge_hash,e->v1->tflag1, e->v2->tflag1); if(!oe){ totedge++; BLI_edgehash_insert(edge_hash,e->v1->tflag1,e->v2->tflag1,e); e->tflag2 = 1; } else{ e->tflag2 = 0; } } /*count quads and tris*/ totface = 0; bmeshok = 1; for(f=bm->polys.first;f;f=f->next){ len = BME_cycle_length(f->loopbase); if(len == 3 || len == 4) totface++; } /*convert back to mesh*/ result = CDDM_from_template(dm,totvert,totedge,totface); CustomData_merge(&bm->vdata, &result->vertData, CD_MASK_BMESH, CD_CALLOC, totvert); CustomData_merge(&bm->edata, &result->edgeData, CD_MASK_BMESH, CD_CALLOC, totedge); CustomData_merge(&bm->pdata, &result->faceData, CD_MASK_BMESH, CD_CALLOC, totface); CustomData_from_bmeshpoly(&result->faceData, &bm->pdata, &bm->ldata,totface); numTex = CustomData_number_of_layers(&bm->pdata, CD_MTEXPOLY); numCol = CustomData_number_of_layers(&bm->ldata, CD_MLOOPCOL); /*Make Verts*/ mvert = CDDM_get_verts(result); origindex = result->getVertDataArray(result, CD_ORIGINDEX); for(i=0,v1=bm->verts.first,mv=mvert;v1;v1=v1->next,i++,mv++){ VECCOPY(mv->co,v1->co); mv->flag = (unsigned char)v1->flag; mv->bweight = (char)(255.0*v1->bweight); CustomData_from_bmesh_block(&bm->vdata, &result->vertData, &v1->data, i); origindex[i] = ORIGINDEX_NONE; } medge = CDDM_get_edges(result); origindex = result->getEdgeDataArray(result, CD_ORIGINDEX); i=0; for(e=bm->edges.first,me=medge;e;e=e->next){ if(e->tflag2){ if(e->v1->tflag1 < e->v2->tflag1){ me->v1 = e->v1->tflag1; me->v2 = e->v2->tflag1; } else{ me->v1 = e->v2->tflag1; me->v2 = e->v1->tflag1; } me->crease = (char)(255.0*e->crease); me->bweight = (char)(255.0*e->bweight); me->flag = e->flag; CustomData_from_bmesh_block(&bm->edata, &result->edgeData, &e->data, i); origindex[i] = ORIGINDEX_NONE; me++; i++; } } if(totface){ mface = CDDM_get_faces(result); origindex = result->getFaceDataArray(result, CD_ORIGINDEX); /*make faces*/ for(i=0,f=bm->polys.first;f;f=f->next){ mf = &mface[i]; len = BME_cycle_length(f->loopbase); if(len==3 || len==4){ mf->v1 = f->loopbase->v->tflag1; mf->v2 = f->loopbase->next->v->tflag1; mf->v3 = f->loopbase->next->next->v->tflag1; if(len == 4){ mf->v4 = f->loopbase->prev->v->tflag1; } /* test and rotate indexes if necessary so that verts 3 and 4 aren't index 0 */ if(mf->v3 == 0 || (len == 4 && mf->v4 == 0)){ test_index_face(mf, NULL, i, len); } mf->mat_nr = (unsigned char)f->mat_nr; mf->flag = (unsigned char)f->flag; CustomData_from_bmesh_block(&bm->pdata, &result->faceData, &f->data, i); BME_DMloops_to_corners(bm, &result->faceData, i, f,numCol,numTex); origindex[i] = ORIGINDEX_NONE; i++; } } } BLI_edgehash_free(edge_hash, NULL); return result; }
/* Iterate over the CSG Output Descriptors and create a new DerivedMesh from them */ static DerivedMesh *ConvertCSGDescriptorsToDerivedMesh( CSG_FaceIteratorDescriptor *face_it, CSG_VertexIteratorDescriptor *vertex_it, float parinv[][4], float mapmat[][4], Material **mat, int *totmat, DerivedMesh *dm1, Object *ob1, DerivedMesh *dm2, Object *ob2) { DerivedMesh *result, *orig_dm; GHash *material_hash = NULL; Mesh *me1= (Mesh*)ob1->data; Mesh *me2= (Mesh*)ob2->data; int i; // create a new DerivedMesh result = CDDM_new(vertex_it->num_elements, 0, face_it->num_elements); CustomData_merge(&dm1->faceData, &result->faceData, CD_MASK_DERIVEDMESH, CD_DEFAULT, face_it->num_elements); CustomData_merge(&dm2->faceData, &result->faceData, CD_MASK_DERIVEDMESH, CD_DEFAULT, face_it->num_elements); // step through the vertex iterators: for (i = 0; !vertex_it->Done(vertex_it->it); i++) { CSG_IVertex csgvert; MVert *mvert = CDDM_get_vert(result, i); // retrieve a csg vertex from the boolean module vertex_it->Fill(vertex_it->it, &csgvert); vertex_it->Step(vertex_it->it); // we have to map the vertex coordinates back in the coordinate frame // of the resulting object, since it was computed in world space mul_v3_m4v3(mvert->co, parinv, csgvert.position); } // a hash table to remap materials to indices if (mat) { material_hash = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "CSG_mat gh"); *totmat = 0; } // step through the face iterators for(i = 0; !face_it->Done(face_it->it); i++) { Mesh *orig_me; Object *orig_ob; Material *orig_mat; CSG_IFace csgface; MFace *mface; int orig_index, mat_nr; // retrieve a csg face from the boolean module face_it->Fill(face_it->it, &csgface); face_it->Step(face_it->it); // find the original mesh and data orig_ob = (csgface.orig_face < dm1->getNumFaces(dm1))? ob1: ob2; orig_dm = (csgface.orig_face < dm1->getNumFaces(dm1))? dm1: dm2; orig_me = (orig_ob == ob1)? me1: me2; orig_index = (orig_ob == ob1)? csgface.orig_face: csgface.orig_face - dm1->getNumFaces(dm1); // copy all face layers, including mface CustomData_copy_data(&orig_dm->faceData, &result->faceData, orig_index, i, 1); // set mface mface = CDDM_get_face(result, i); mface->v1 = csgface.vertex_index[0]; mface->v2 = csgface.vertex_index[1]; mface->v3 = csgface.vertex_index[2]; mface->v4 = (csgface.vertex_number == 4)? csgface.vertex_index[3]: 0; // set material, based on lookup in hash table orig_mat= give_current_material(orig_ob, mface->mat_nr+1); if (mat && orig_mat) { if (!BLI_ghash_haskey(material_hash, orig_mat)) { mat[*totmat] = orig_mat; mat_nr = mface->mat_nr = (*totmat)++; BLI_ghash_insert(material_hash, orig_mat, SET_INT_IN_POINTER(mat_nr)); } else mface->mat_nr = GET_INT_FROM_POINTER(BLI_ghash_lookup(material_hash, orig_mat)); } else mface->mat_nr = 0; InterpCSGFace(result, orig_dm, i, orig_index, csgface.vertex_number, (orig_me == me2)? mapmat: NULL); test_index_face(mface, &result->faceData, i, csgface.vertex_number); } if (material_hash) BLI_ghash_free(material_hash, NULL, NULL); CDDM_calc_edges(result); CDDM_calc_normals(result); return result; }