/* turns Mesh into editmesh */ void make_editMesh(Scene *scene, Object *ob) { Mesh *me= ob->data; MFace *mface; MVert *mvert; MSelect *mselect; KeyBlock *actkey; EditMesh *em; EditVert *eve, **evlist, *eve1, *eve2, *eve3, *eve4; EditFace *efa, *efa_last_sel= NULL; EditEdge *eed; EditSelection *ese; float *co, (*keyco)[3]= NULL; int tot, a, eekadoodle= 0; const short is_paint_face_sel= paint_facesel_test(ob); const short is_paint_vert_sel= is_paint_face_sel ? FALSE : paint_vertsel_test(ob); if(me->edit_mesh==NULL) me->edit_mesh= MEM_callocN(sizeof(EditMesh), "editmesh"); else /* because of reload */ free_editMesh(me->edit_mesh); em= me->edit_mesh; em->selectmode= scene->toolsettings->selectmode; // warning needs to be synced em->act_face = NULL; em->totvert= tot= me->totvert; em->totedge= me->totedge; em->totface= me->totface; if(tot==0) { return; } if(ob->actcol > 0) em->mat_nr= ob->actcol-1; /* initialize fastmalloc for editmesh */ init_editmesh_fastmalloc(em, me->totvert, me->totedge, me->totface); actkey = ob_get_keyblock(ob); if(actkey) { /* undo-ing in past for previous editmode sessions gives corrupt 'keyindex' values */ undo_editmode_clear(); keyco= actkey->data; em->shapenr= ob->shapenr; } /* make editverts */ CustomData_copy(&me->vdata, &em->vdata, CD_MASK_EDITMESH, CD_CALLOC, 0); mvert= me->mvert; evlist= (EditVert **)MEM_mallocN(tot*sizeof(void *),"evlist"); for(a=0; a<tot; a++, mvert++) { co= mvert->co; /* edit the shape key coordinate if available */ if(keyco && a < actkey->totelem) co= keyco[a]; eve= addvertlist(em, co, NULL); evlist[a]= eve; /* face select sets selection in next loop */ if(!is_paint_face_sel) eve->f |= (mvert->flag & SELECT); if (mvert->flag & ME_HIDE) eve->h= 1; normal_short_to_float_v3(eve->no, mvert->no); eve->bweight= ((float)mvert->bweight)/255.0f; /* lets overwrite the keyindex of the editvert * with the order it used to be in before * editmode */ eve->keyindex = a; CustomData_to_em_block(&me->vdata, &em->vdata, a, &eve->data); } if(actkey && actkey->totelem!=me->totvert); else { MEdge *medge= me->medge; CustomData_copy(&me->edata, &em->edata, CD_MASK_EDITMESH, CD_CALLOC, 0); /* make edges */ for(a=0; a<me->totedge; a++, medge++) { eed= addedgelist(em, evlist[medge->v1], evlist[medge->v2], NULL); /* eed can be zero when v1 and v2 are identical, dxf import does this... */ if(eed) { int is_sel; if (is_paint_vert_sel) { /* when from vertex select, flush flags to edges, * allow selection, code below handles editmode selection conversion */ is_sel= (eed->v1->f & SELECT) && (eed->v2->f & SELECT); } else { is_sel= (medge->flag & SELECT); } eed->crease= ((float)medge->crease)/255.0f; eed->bweight= ((float)medge->bweight)/255.0f; if(medge->flag & ME_SEAM) eed->seam= 1; if(medge->flag & ME_SHARP) eed->sharp = 1; if(medge->flag & ME_FGON) eed->h= EM_FGON; // 2 different defines! if(medge->flag & ME_HIDE) eed->h |= 1; if(is_sel) eed->f |= SELECT; if(em->selectmode==SCE_SELECT_EDGE) EM_select_edge(eed, eed->f & SELECT); // force edge selection to vertices, seems to be needed ... CustomData_to_em_block(&me->edata,&em->edata, a, &eed->data); } } CustomData_copy(&me->fdata, &em->fdata, CD_MASK_EDITMESH, CD_CALLOC, 0); /* make faces */ mface= me->mface; for(a=0; a<me->totface; a++, mface++) { eve1= evlist[mface->v1]; eve2= evlist[mface->v2]; if(!mface->v3) eekadoodle= 1; eve3= evlist[mface->v3]; if(mface->v4) eve4= evlist[mface->v4]; else eve4= NULL; efa= addfacelist(em, eve1, eve2, eve3, eve4, NULL, NULL); if(efa) { CustomData_to_em_block(&me->fdata, &em->fdata, a, &efa->data); efa->mat_nr= mface->mat_nr; efa->flag= mface->flag & ~ME_HIDE; /* select and hide face flag */ if(mface->flag & ME_HIDE) { efa->h= 1; } else { int is_sel; if (!is_paint_vert_sel) { is_sel= (mface->flag & ME_FACE_SEL); } else { /* when from vertex select, flush flags to edges, * allow selection, code below handles editmode selection conversion */ is_sel= ( (efa->v1->f & SELECT) && (efa->v2->f & SELECT) && (efa->v3->f & SELECT) && (efa->v4 == NULL || efa->v4->f & SELECT) ); } if (a==me->act_face) { EM_set_actFace(em, efa); } /* dont allow hidden and selected */ if(is_sel) { efa->f |= SELECT; if(is_paint_face_sel) { EM_select_face(efa, 1); /* flush down */ } efa_last_sel= efa; } } } } } if(EM_get_actFace(em, 0)==NULL && efa_last_sel) { EM_set_actFace(em, efa_last_sel); } if(eekadoodle) error("This Mesh has old style edgecodes, please put it in the bugtracker!"); MEM_freeN(evlist); end_editmesh_fastmalloc(); // resets global function pointers if(me->mselect){ //restore editselections EM_init_index_arrays(em, 1,1,1); mselect = me->mselect; for(a=0; a<me->totselect; a++, mselect++){ /*check if recorded selection is still valid, if so copy into editmesh*/ if ( (mselect->type == EDITVERT && me->mvert[mselect->index].flag & SELECT) || (mselect->type == EDITEDGE && me->medge[mselect->index].flag & SELECT) || (mselect->type == EDITFACE && me->mface[mselect->index].flag & ME_FACE_SEL) ) { ese = MEM_callocN(sizeof(EditSelection), "Edit Selection"); ese->type = mselect->type; if(ese->type == EDITVERT) ese->data = EM_get_vert_for_index(mselect->index); else if(ese->type == EDITEDGE) ese->data = EM_get_edge_for_index(mselect->index); else if(ese->type == EDITFACE) ese->data = EM_get_face_for_index(mselect->index); BLI_addtail(&(em->selected),ese); } } EM_free_index_arrays(); } /* this creates coherent selections. also needed for older files */ EM_selectmode_set(em); /* paranoia check to enforce hide rules */ EM_hide_reset(em); /* sets helper flags which arent saved */ EM_fgon_flags(em); if (EM_get_actFace(em, 0)==NULL) { EM_set_actFace(em, em->faces.first ); /* will use the first face, this is so we alwats have an active face */ } }
/* frees all editmode stuff */ void ED_editors_exit(bContext *C) { Main *bmain= CTX_data_main(C); Scene *sce; if(!bmain) return; /* frees all editmode undos */ undo_editmode_clear(); ED_undo_paint_free(); for(sce=bmain->scene.first; sce; sce= sce->id.next) { if(sce->obedit) { Object *ob= sce->obedit; /* global in meshtools... */ mesh_octree_table(NULL, NULL, NULL, 'e'); mesh_mirrtopo_table(NULL, 'e'); if(ob) { if(ob->type==OB_MESH) { Mesh *me= ob->data; if(me->edit_mesh) { free_editMesh(me->edit_mesh); MEM_freeN(me->edit_mesh); me->edit_mesh= NULL; } } else if(ob->type==OB_ARMATURE) { ED_armature_edit_free(ob); } else if(ob->type==OB_FONT) { // free_editText(); } // else if(ob->type==OB_MBALL) // BLI_freelistN(&editelems); // free_editLatt(); // free_posebuf(); // XXX this is still a global... } } else if(sce->basact && sce->basact->object) { Object *ob= sce->basact->object; /* if weight-painting is on, free mesh octree data */ if(ob->mode & OB_MODE_WEIGHT_PAINT) { mesh_octree_table(NULL, NULL, NULL, 'e'); mesh_mirrtopo_table(NULL, 'e'); } } } }
/* frees all editmode stuff */ void ED_editors_exit(bContext *C) { Main *bmain = CTX_data_main(C); Scene *sce; if (!bmain) return; /* frees all editmode undos */ undo_editmode_clear(); ED_undo_paint_free(); for (sce = bmain->scene.first; sce; sce = sce->id.next) { if (sce->obedit) { Object *ob = sce->obedit; if (ob) { if (ob->type == OB_MESH) { Mesh *me = ob->data; if (me->edit_btmesh) { EDBM_mesh_free(me->edit_btmesh); MEM_freeN(me->edit_btmesh); me->edit_btmesh = NULL; } } else if (ob->type == OB_ARMATURE) { ED_armature_edit_free(ob->data); } } } } /* global in meshtools... */ ED_mesh_mirror_spatial_table(NULL, NULL, NULL, 'e'); ED_mesh_mirror_topo_table(NULL, 'e'); }
/* note: also check undo_history_exec() in bottom if you change notifiers */ static int ed_undo_step(bContext *C, int step, const char *undoname) { wmWindowManager *wm = CTX_wm_manager(C); wmWindow *win = CTX_wm_window(C); Scene *scene = CTX_data_scene(C); Object *obedit = CTX_data_edit_object(C); Object *obact = CTX_data_active_object(C); ScrArea *sa = CTX_wm_area(C); /* undo during jobs are running can easily lead to freeing data using by jobs, * or they can just lead to freezing job in some other cases */ if (WM_jobs_test(wm, scene, WM_JOB_TYPE_ANY)) { return OPERATOR_CANCELLED; } /* grease pencil can be can be used in plenty of spaces, so check it first */ if (ED_gpencil_session_active()) { return ED_undo_gpencil_step(C, step, undoname); } if (sa && (sa->spacetype == SPACE_IMAGE)) { SpaceImage *sima = (SpaceImage *)sa->spacedata.first; if ((obact && (obact->mode & OB_MODE_TEXTURE_PAINT)) || (sima->mode == SI_MODE_PAINT)) { if (!ED_undo_paint_step(C, UNDO_PAINT_IMAGE, step, undoname) && undoname) { if (U.uiflag & USER_GLOBALUNDO) { ED_viewport_render_kill_jobs(C, true); BKE_undo_name(C, undoname); } } WM_event_add_notifier(C, NC_WINDOW, NULL); return OPERATOR_FINISHED; } } if (sa && (sa->spacetype == SPACE_TEXT)) { ED_text_undo_step(C, step); } else if (obedit) { if (OB_TYPE_SUPPORT_EDITMODE(obedit->type)) { if (undoname) undo_editmode_name(C, undoname); else undo_editmode_step(C, step); WM_event_add_notifier(C, NC_GEOM | ND_DATA, NULL); } } else { /* Note: we used to do a fall-through here where if the * mode-specific undo system had no more steps to undo (or * redo), the global undo would run. * * That was inconsistent with editmode, and also makes for * unecessarily tricky interaction with the other undo * systems. */ if (obact && obact->mode & OB_MODE_TEXTURE_PAINT) { ED_undo_paint_step(C, UNDO_PAINT_IMAGE, step, undoname); } else if (obact && obact->mode & OB_MODE_SCULPT) { ED_undo_paint_step(C, UNDO_PAINT_MESH, step, undoname); } else if (obact && obact->mode & OB_MODE_PARTICLE_EDIT) { if (step == 1) PE_undo(scene); else PE_redo(scene); } else if (U.uiflag & USER_GLOBALUNDO) { // note python defines not valid here anymore. //#ifdef WITH_PYTHON // XXX BPY_scripts_clear_pyobjects(); //#endif /* for global undo/redo we should just clear the editmode stack */ /* for example, texface stores image pointers */ undo_editmode_clear(); ED_viewport_render_kill_jobs(C, true); if (undoname) BKE_undo_name(C, undoname); else BKE_undo_step(C, step); scene = CTX_data_scene(C); WM_event_add_notifier(C, NC_SCENE | ND_LAYER_CONTENT, scene); } } WM_event_add_notifier(C, NC_WINDOW, NULL); if (win) { win->addmousemove = true; } return OPERATOR_FINISHED; }