/** * $Id$ * * ***** BEGIN GPL LICENSE BLOCK ***** * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. * All rights reserved. * * The Original Code is: all of this file. * * Contributor(s): none yet. * * ***** END GPL LICENSE BLOCK ***** */ #include #include #ifdef HAVE_CONFIG_H #include #endif #include "MEM_guardedalloc.h" #include "BLI_blenlib.h" #include "BLI_arithb.h" #include "BLI_rand.h" #include "DNA_screen_types.h" #include "DNA_space_types.h" #include "DNA_meta_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" #include "DNA_view3d_types.h" #include "DNA_userdef_types.h" #include "BKE_utildefines.h" #include "BKE_depsgraph.h" #include "BKE_global.h" #include "BKE_object.h" #include "BIF_gl.h" #include "BIF_graphics.h" #include "BIF_screen.h" #include "BIF_toolbox.h" #include "BIF_space.h" #include "BIF_editmode_undo.h" #include "BIF_transform.h" #include "BDR_editobject.h" #include "BDR_editmball.h" #include "BSE_edit.h" #include "BSE_view.h" #include "blendef.h" #include "mydevice.h" extern short editbutflag; ListBase editelems= {0, 0}; MetaElem *lastelem; /* this function is called, when MetaBall Object is * switched from object mode to edit mode */ void make_editMball() { MetaBall *mb; MetaElem *ml, *newmb; BLI_freelistN(&editelems); lastelem= 0; mb= G.obedit->data; ml= mb->elems.first; while(ml) { newmb= MEM_dupallocN(ml); BLI_addtail(&editelems, newmb); if(ml->flag & SELECT) lastelem= newmb; ml= ml->next; } allqueue(REDRAWBUTSEDIT, 0); countall(); } /* this function is called, when MetaBall Object switched from * edit mode to object mode. List od MetaElements is copied * from editelems to to object->data structure (mb->elems) */ void load_editMball() { /* load mball in object */ MetaBall *mb; MetaElem *ml, *newml; if(G.obedit==NULL) return; mb= G.obedit->data; BLI_freelistN(&(mb->elems)); ml= editelems.first; while(ml) { newml= MEM_dupallocN(ml); BLI_addtail(&(mb->elems), newml); ml= ml->next; } } /* add new MetaElement primitive */ void add_primitiveMball(int dummy_argument) { MetaElem *ml; float *curs, mat[3][3], cent[3], imat[3][3], cmat[3][3]; short newob= 0; if(G.scene->id.lib) return; /* this function also comes from an info window */ if ELEM(curarea->spacetype, SPACE_VIEW3D, SPACE_INFO); else return; check_editmode(OB_MBALL); /* if no obedit: new object and enter editmode */ if(G.obedit==NULL) { add_object_draw(OB_MBALL); base_init_from_view3d(BASACT, G.vd); G.obedit= BASACT->object; where_is_object(G.obedit); // need now, for imat make_editMball(); setcursor_space(SPACE_VIEW3D, CURSOR_EDIT); newob= 1; } /* deselect */ ml= editelems.first; while(ml) { ml->flag &= ~SELECT; ml= ml->next; } /* imat and center and size */ Mat3CpyMat4(mat, G.obedit->obmat); curs= give_cursor(); VECCOPY(cent, curs); cent[0]-= G.obedit->obmat[3][0]; cent[1]-= G.obedit->obmat[3][1]; cent[2]-= G.obedit->obmat[3][2]; if (G.vd) { Mat3CpyMat4(imat, G.vd->viewmat); Mat3MulVecfl(imat, cent); Mat3MulMat3(cmat, imat, mat); Mat3Inv(imat,cmat); Mat3MulVecfl(imat, cent); } ml= MEM_callocN(sizeof(MetaElem), "metaelem"); BLI_addtail(&editelems, ml); ml->x= cent[0]; ml->y= cent[1]; ml->z= cent[2]; ml->quat[0]= 1.0; ml->quat[1]= 0.0; ml->quat[2]= 0.0; ml->quat[3]= 0.0; ml->rad= 2.0; ml->s= 2.0; ml->flag= SELECT | MB_SCALE_RAD; switch(dummy_argument) { case 1: ml->type = MB_BALL; ml->expx= ml->expy= ml->expz= 1.0; break; case 2: ml->type = MB_TUBE; ml->expx= ml->expy= ml->expz= 1.0; break; case 3: ml->type = MB_PLANE; ml->expx= ml->expy= ml->expz= 1.0; break; case 4: ml->type = MB_ELIPSOID; ml->expx= 1.2f; ml->expy= 0.8f; ml->expz= 1.0; break; case 5: ml->type = MB_CUBE; ml->expx= ml->expy= ml->expz= 1.0; break; default: break; } lastelem= ml; DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA); // added ball can influence others countall(); /* if a new object was created, it stores it in Mball, for reload original data and undo */ if ( !(newob) || (U.flag & USER_ADD_EDITMODE)) { if(newob) load_editMball(); } else { exit_editmode(2); } allqueue(REDRAWALL, 0); BIF_undo_push("Add MetaElem"); } /* deselect all MetaElements */ void deselectall_mball() { MetaElem *ml; int sel= 0; ml= editelems.first; while(ml) { if(ml->flag & SELECT) break; ml= ml->next; } if(ml) sel= 1; ml= editelems.first; while(ml) { if(sel) ml->flag &= ~SELECT; else ml->flag |= SELECT; ml= ml->next; } allqueue(REDRAWVIEW3D, 0); countall(); BIF_undo_push("Deselect MetaElem"); } /* inverts metaball selection */ void selectinverse_mball() { MetaElem *ml; ml= editelems.first; while(ml) { if(ml->flag & SELECT) ml->flag &= ~SELECT; else ml->flag |= SELECT; ml= ml->next; } allqueue(REDRAWVIEW3D, 0); countall(); BIF_undo_push("Invert MetaElem"); } /* select random metaball selection */ void selectrandom_mball() { MetaElem *ml; static short randfac= 50; if(!button(&randfac,0, 100,"Percentage:")) return; ml= editelems.first; BLI_srand( BLI_rand() ); /* random seed */ while(ml) { if((BLI_frand() * 100) < randfac) ml->flag |= SELECT; ml= ml->next; } allqueue(REDRAWVIEW3D, 0); countall(); BIF_undo_push("Random MetaElem"); } /* select MetaElement with mouse click (user can select radius circle or * stiffness circle) */ void mouse_mball() { static MetaElem *startelem=0; MetaElem *ml, *act=0; int a, hits; unsigned int buffer[MAXPICKBUF]; hits= view3d_opengl_select(buffer, MAXPICKBUF, 0, 0, 0, 0); /* does startelem exist? */ ml= editelems.first; while(ml) { if(ml==startelem) break; ml= ml->next; } if(ml==NULL) startelem= editelems.first; if(hits>0) { ml= startelem; while(ml) { for(a=0; aselcol1==buffer[ 4 * a + 3 ]){ ml->flag |= MB_SCALE_RAD; act= ml; } if(ml->selcol2==buffer[ 4 * a + 3 ]){ ml->flag &= ~MB_SCALE_RAD; act= ml; } } if(act) break; ml= ml->next; if(ml==NULL) ml= editelems.first; if(ml==startelem) break; } if(act) { if((G.qual & LR_SHIFTKEY)==0) { deselectall_mball(); if(act->flag & SELECT) deselectall_mball(); act->flag |= SELECT; } else { if(act->flag & SELECT) { act->flag &= ~SELECT; } else act->flag |= SELECT; } lastelem= act; allqueue(REDRAWVIEW3D, 0); allqueue(REDRAWBUTSEDIT, 0); } } allqueue(REDRAWBUTSOBJECT, 0); countall(); rightmouse_transform(); } /* duplicate selected MetaElements */ void adduplicate_mball() { MetaElem *ml, *newml; ml= editelems.last; while(ml) { if(ml->flag & SELECT) { newml= MEM_dupallocN(ml); BLI_addtail(&editelems, newml); lastelem= newml; ml->flag &= ~SELECT; } ml= ml->prev; } BIF_TransformSetUndo("Add Duplicate"); countall(); initTransform(TFM_TRANSLATION, CTX_NO_PET); Transform(); allqueue(REDRAWBUTSEDIT, 0); } /* Delete all selected MetaElems (not MetaBall) */ void delete_mball() { MetaElem *ml, *next; if(okee("Erase selected")==0) return; ml= editelems.first; while(ml) { next= ml->next; if(ml->flag & SELECT) { if(lastelem==ml) lastelem= 0; BLI_remlink(&editelems, ml); MEM_freeN(ml); } ml= next; } DAG_scene_sort(G.scene); DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA); allqueue(REDRAWVIEW3D, 0); allqueue(REDRAWBUTSEDIT, 0); countall(); BIF_undo_push("Delete MetaElem"); } /* free all MetaElems from ListBase */ void freeMetaElemlist(ListBase *lb) { MetaElem *ml, *next; if(lb==NULL) return; ml= lb->first; while(ml){ next= ml->next; BLI_remlink(lb, ml); MEM_freeN(ml); ml= next; } lb->first= lb->last= NULL; } /* ************* undo for MetaBalls ************* */ static void undoMball_to_editMball(void *lbv) { ListBase *lb= lbv; MetaElem *ml, *newml; unsigned int nr, lastmlnr= 0; /* we try to restore lastelem, which used in for example in button window */ for(ml= editelems.first; ml; ml= ml->next, lastmlnr++) if(lastelem==ml) break; freeMetaElemlist(&editelems); /* copy 'undo' MetaElems to 'edit' MetaElems */ ml= lb->first; while(ml){ newml= MEM_dupallocN(ml); BLI_addtail(&editelems, newml); ml= ml->next; } for(nr=0, lastelem= editelems.first; lastelem; lastelem= lastelem->next, nr++) if(nr==lastmlnr) break; countall(); } static void *editMball_to_undoMball(void) { ListBase *lb; MetaElem *ml, *newml; /* allocate memory for undo ListBase */ lb= MEM_callocN(sizeof(ListBase), "listbase undo"); lb->first= lb->last= NULL; /* copy contents of current ListBase to the undo ListBase */ ml= editelems.first; while(ml){ newml= MEM_dupallocN(ml); BLI_addtail(lb, newml); ml= ml->next; } return lb; } /* free undo ListBase of MetaElems */ static void free_undoMball(void *lbv) { ListBase *lb= lbv; freeMetaElemlist(lb); MEM_freeN(lb); } /* this is undo system for MetaBalls */ void undo_push_mball(char *name) { undo_editmode_push(name, free_undoMball, undoMball_to_editMball, editMball_to_undoMball, NULL); } /* Hide selected/unselected MetaElems */ void hide_mball(char hide) { MetaElem *ml; ml= editelems.first; while(ml){ if(hide){ if(!(ml->flag & SELECT)) ml->flag |= MB_HIDE; } else{ if(ml->flag & SELECT) ml->flag |= MB_HIDE; } ml= ml->next; } DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA); allqueue(REDRAWVIEW3D, 0); allqueue(REDRAWBUTSEDIT, 0); countall(); BIF_undo_push("Hide MetaElems"); } /* Unhide all edited MetaElems */ void reveal_mball(void) { MetaElem *ml; ml= editelems.first; while(ml){ ml->flag &= ~MB_HIDE; ml= ml->next; } DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA); allqueue(REDRAWVIEW3D, 0); allqueue(REDRAWBUTSEDIT, 0); countall(); BIF_undo_push("Unhide MetaElems"); }