Blender  V2.59
mball_edit.c
Go to the documentation of this file.
00001 /*
00002  * $Id: mball_edit.c 36644 2011-05-12 16:47:36Z campbellbarton $
00003  *
00004  * ***** BEGIN GPL LICENSE BLOCK *****
00005  *
00006  * This program is free software; you can redistribute it and/or
00007  * modify it under the terms of the GNU General Public License
00008  * as published by the Free Software Foundation; either version 2
00009  * of the License, or (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software Foundation,
00018  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00019  *
00020  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
00021  * All rights reserved.
00022  *
00023  * The Original Code is: all of this file.
00024  
00025  * Contributor(s): none yet.
00026  *
00027  * ***** END GPL LICENSE BLOCK *****
00028  */
00029 
00035 #include <math.h>
00036 #include <string.h>
00037 
00038 #include "MEM_guardedalloc.h"
00039 
00040 #include "BLI_blenlib.h"
00041 #include "BLI_math.h"
00042 #include "BLI_rand.h"
00043 #include "BLI_utildefines.h"
00044 
00045 #include "DNA_meta_types.h"
00046 #include "DNA_object_types.h"
00047 #include "DNA_scene_types.h"
00048 
00049 #include "RNA_define.h"
00050 #include "RNA_access.h"
00051 #include "RNA_enum_types.h"
00052 
00053 #include "BKE_depsgraph.h"
00054 #include "BKE_context.h"
00055 #include "BKE_mball.h"
00056 
00057 #include "ED_mball.h"
00058 #include "ED_screen.h"
00059 #include "ED_view3d.h"
00060 #include "ED_transform.h"
00061 #include "ED_util.h"
00062 
00063 #include "WM_api.h"
00064 #include "WM_types.h"
00065 
00066 #include "mball_intern.h"
00067 
00068 /* This function is used to free all MetaElems from MetaBall */
00069 void free_editMball(Object *obedit)
00070 {
00071         MetaBall *mb = (MetaBall*)obedit->data;
00072 
00073         mb->editelems= NULL;
00074         mb->lastelem= NULL;
00075 }
00076 
00077 /* This function is called, when MetaBall Object is
00078  * switched from object mode to edit mode */
00079 void make_editMball(Object *obedit)
00080 {
00081         MetaBall *mb = (MetaBall*)obedit->data;
00082         MetaElem *ml;/*, *newml;*/
00083 
00084         ml= mb->elems.first;
00085         
00086         while(ml) {
00087                 if(ml->flag & SELECT) mb->lastelem = ml;
00088                 ml= ml->next;
00089         }
00090 
00091         mb->editelems = &mb->elems;
00092 }
00093 
00094 /* This function is called, when MetaBall Object switched from
00095  * edit mode to object mode. List od MetaElements is copied
00096  * from object->data->edit_elems to object->data->elems. */
00097 void load_editMball(Object *UNUSED(obedit))
00098 {
00099 }
00100 
00101 /* Add metaelem primitive to metaball object (which is in edit mode) */
00102 MetaElem *add_metaball_primitive(bContext *C, float mat[4][4], int type, int UNUSED(newname))
00103 {
00104         Object *obedit= CTX_data_edit_object(C);
00105         MetaBall *mball = (MetaBall*)obedit->data;
00106         MetaElem *ml;
00107 
00108         /* Deselect all existing metaelems */
00109         ml= mball->editelems->first;
00110         while(ml) {
00111                 ml->flag &= ~SELECT;
00112                 ml= ml->next;
00113         }
00114         
00115         ml= add_metaball_element(mball, type);
00116         copy_v3_v3(&ml->x, mat[3]);
00117 
00118         ml->flag |= SELECT;
00119         mball->lastelem= ml;
00120         return ml;
00121 }
00122 
00123 /***************************** Select/Deselect operator *****************************/
00124 
00125 /* Select or deselect all MetaElements */
00126 static int select_all_exec(bContext *C, wmOperator *op)
00127 {
00128         //Scene *scene= CTX_data_scene(C);
00129         Object *obedit= CTX_data_edit_object(C);
00130         MetaBall *mb = (MetaBall*)obedit->data;
00131         MetaElem *ml;
00132         int action = RNA_enum_get(op->ptr, "action");
00133 
00134         ml= mb->editelems->first;
00135         if(ml) {
00136                 if (action == SEL_TOGGLE) {
00137                         action = SEL_SELECT;
00138                         while(ml) {
00139                                 if(ml->flag & SELECT) {
00140                                         action = SEL_DESELECT;
00141                                         break;
00142                                 }
00143                                 ml= ml->next;
00144                         }
00145                 }
00146 
00147                 ml= mb->editelems->first;
00148                 while(ml) {
00149                         switch (action) {
00150                         case SEL_SELECT:
00151                                 ml->flag |= SELECT;
00152                                 break;
00153                         case SEL_DESELECT:
00154                                 ml->flag &= ~SELECT;
00155                                 break;
00156                         case SEL_INVERT:
00157                                 ml->flag ^= SELECT;
00158                                 break;
00159                         }
00160                         ml= ml->next;
00161                 }
00162                 WM_event_add_notifier(C, NC_GEOM|ND_SELECT, mb);
00163         }
00164 
00165         return OPERATOR_FINISHED;
00166 }
00167 
00168 void MBALL_OT_select_all(wmOperatorType *ot)
00169 {
00170         /* identifiers */
00171         ot->name= "Select or Deselect All";
00172         ot->description= "Change selection of all meta elements";
00173         ot->idname= "MBALL_OT_select_all";
00174 
00175         /* callback functions */
00176         ot->exec= select_all_exec;
00177         ot->poll= ED_operator_editmball;
00178 
00179         /* flags */
00180         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
00181 
00182         WM_operator_properties_select_all(ot);
00183 }
00184 
00185 /***************************** Select inverse operator *****************************/
00186 
00187 /* Invert metaball selection */
00188 static int select_inverse_metaelems_exec(bContext *C, wmOperator *UNUSED(op))
00189 {
00190         Object *obedit= CTX_data_edit_object(C);
00191         MetaBall *mb = (MetaBall*)obedit->data;
00192         MetaElem *ml;
00193         
00194         ml= mb->editelems->first;
00195         if(ml) {
00196                 while(ml) {
00197                         if(ml->flag & SELECT)
00198                                 ml->flag &= ~SELECT;
00199                         else
00200                                 ml->flag |= SELECT;
00201                         ml= ml->next;
00202                 }
00203                 WM_event_add_notifier(C, NC_GEOM|ND_SELECT, mb);
00204         }
00205         
00206         return OPERATOR_FINISHED;
00207 }
00208 
00209 void MBALL_OT_select_inverse_metaelems(wmOperatorType *ot)
00210 {
00211         /* identifiers */
00212         ot->name= "Inverse";
00213         ot->description= "Select inverse of (un)selected metaelements";
00214         ot->idname= "MBALL_OT_select_inverse_metaelems";
00215 
00216         /* callback functions */
00217         ot->exec= select_inverse_metaelems_exec;
00218         ot->poll= ED_operator_editmball;
00219 
00220         /* flags */
00221         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;  
00222 }
00223 
00224 /***************************** Select random operator *****************************/
00225 
00226 /* Random metaball selection */
00227 static int select_random_metaelems_exec(bContext *C, wmOperator *op)
00228 {
00229         Object *obedit= CTX_data_edit_object(C);
00230         MetaBall *mb = (MetaBall*)obedit->data;
00231         MetaElem *ml;
00232         float percent= RNA_float_get(op->ptr, "percent");
00233         
00234         if(percent == 0.0f)
00235                 return OPERATOR_CANCELLED;
00236         
00237         ml= mb->editelems->first;
00238         BLI_srand( BLI_rand() );        /* Random seed */
00239         
00240         /* Stupid version of random selection. Should be improved. */
00241         while(ml) {
00242                 if(BLI_frand() < percent)
00243                         ml->flag |= SELECT;
00244                 else
00245                         ml->flag &= ~SELECT;
00246                 ml= ml->next;
00247         }
00248         
00249         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, mb);
00250         
00251         return OPERATOR_FINISHED;
00252 }
00253 
00254 
00255 void MBALL_OT_select_random_metaelems(struct wmOperatorType *ot)
00256 {
00257         /* identifiers */
00258         ot->name= "Random...";
00259         ot->description= "Randomly select metaelements";
00260         ot->idname= "MBALL_OT_select_random_metaelems";
00261         
00262         /* callback functions */
00263         ot->exec= select_random_metaelems_exec;
00264         ot->invoke= WM_operator_props_popup;
00265         ot->poll= ED_operator_editmball;
00266         
00267         /* flags */
00268         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
00269         
00270         /* properties */
00271         RNA_def_float_percentage(ot->srna, "percent", 0.5f, 0.0f, 1.0f, "Percent", "Percentage of metaelems to select randomly.", 0.0001f, 1.0f);
00272 }
00273 
00274 /***************************** Duplicate operator *****************************/
00275 
00276 /* Duplicate selected MetaElements */
00277 static int duplicate_metaelems_exec(bContext *C, wmOperator *UNUSED(op))
00278 {
00279         Object *obedit= CTX_data_edit_object(C);
00280         MetaBall *mb = (MetaBall*)obedit->data;
00281         MetaElem *ml, *newml;
00282         
00283         ml= mb->editelems->last;
00284         if(ml) {
00285                 while(ml) {
00286                         if(ml->flag & SELECT) {
00287                                 newml= MEM_dupallocN(ml);
00288                                 BLI_addtail(mb->editelems, newml);
00289                                 mb->lastelem= newml;
00290                                 ml->flag &= ~SELECT;
00291                         }
00292                         ml= ml->prev;
00293                 }
00294                 WM_event_add_notifier(C, NC_GEOM|ND_DATA, mb);
00295                 DAG_id_tag_update(obedit->data, 0);
00296         }
00297 
00298         return OPERATOR_FINISHED;
00299 }
00300 
00301 static int duplicate_metaelems_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
00302 {
00303         int retv= duplicate_metaelems_exec(C, op);
00304         
00305         if (retv == OPERATOR_FINISHED) {
00306                 RNA_enum_set(op->ptr, "mode", TFM_TRANSLATION);
00307                 WM_operator_name_call(C, "TRANSFORM_OT_transform", WM_OP_INVOKE_REGION_WIN, op->ptr);
00308         }
00309         
00310         return retv;
00311 }
00312 
00313 
00314 void MBALL_OT_duplicate_metaelems(wmOperatorType *ot)
00315 {
00316         /* identifiers */
00317         ot->name= "Duplicate Metaelements";
00318         ot->description= "Delete selected metaelement(s)";
00319         ot->idname= "MBALL_OT_duplicate_metaelems";
00320 
00321         /* callback functions */
00322         ot->exec= duplicate_metaelems_exec;
00323         ot->invoke= duplicate_metaelems_invoke;
00324         ot->poll= ED_operator_editmball;
00325 
00326         /* flags */
00327         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
00328         
00329         /* to give to transform */
00330         RNA_def_enum(ot->srna, "mode", transform_mode_types, TFM_TRANSLATION, "Mode", "");
00331 }
00332 
00333 /***************************** Delete operator *****************************/
00334 
00335 /* Delete all selected MetaElems (not MetaBall) */
00336 static int delete_metaelems_exec(bContext *C, wmOperator *UNUSED(op))
00337 {
00338         Object *obedit= CTX_data_edit_object(C);
00339         MetaBall *mb= (MetaBall*)obedit->data;
00340         MetaElem *ml, *next;
00341         
00342         ml= mb->editelems->first;
00343         if(ml) {
00344                 while(ml) {
00345                         next= ml->next;
00346                         if(ml->flag & SELECT) {
00347                                 if(mb->lastelem==ml) mb->lastelem= NULL;
00348                                 BLI_remlink(mb->editelems, ml);
00349                                 MEM_freeN(ml);
00350                         }
00351                         ml= next;
00352                 }
00353                 WM_event_add_notifier(C, NC_GEOM|ND_DATA, mb);
00354                 DAG_id_tag_update(obedit->data, 0);
00355         }
00356 
00357         return OPERATOR_FINISHED;
00358 }
00359 
00360 void MBALL_OT_delete_metaelems(wmOperatorType *ot)
00361 {
00362         /* identifiers */
00363         ot->name= "Delete";
00364         ot->description= "Delete selected metaelement(s)";
00365         ot->idname= "MBALL_OT_delete_metaelems";
00366 
00367         /* callback functions */
00368         ot->exec= delete_metaelems_exec;
00369         ot->poll= ED_operator_editmball;
00370 
00371         /* flags */
00372         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;  
00373 }
00374 
00375 /***************************** Hide operator *****************************/
00376 
00377 /* Hide selected MetaElems */
00378 static int hide_metaelems_exec(bContext *C, wmOperator *op)
00379 {
00380         Object *obedit= CTX_data_edit_object(C);
00381         MetaBall *mb= (MetaBall*)obedit->data;
00382         MetaElem *ml;
00383         const int invert= RNA_boolean_get(op->ptr, "unselected") ? SELECT : 0;
00384 
00385         ml= mb->editelems->first;
00386 
00387         if(ml) {
00388                 while(ml){
00389                         if((ml->flag & SELECT) != invert)
00390                                 ml->flag |= MB_HIDE;
00391                         ml= ml->next;
00392                 }
00393                 WM_event_add_notifier(C, NC_GEOM|ND_DATA, mb);
00394                 DAG_id_tag_update(obedit->data, 0);
00395         }
00396 
00397         return OPERATOR_FINISHED;
00398 }
00399 
00400 void MBALL_OT_hide_metaelems(wmOperatorType *ot)
00401 {
00402         /* identifiers */
00403         ot->name= "Hide";
00404         ot->description= "Hide (un)selected metaelement(s)";
00405         ot->idname= "MBALL_OT_hide_metaelems";
00406 
00407         /* callback functions */
00408         ot->exec= hide_metaelems_exec;
00409         ot->poll= ED_operator_editmball;
00410 
00411         /* flags */
00412         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
00413         
00414         /* props */
00415         RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected rather than selected.");
00416 }
00417 
00418 /***************************** Unhide operator *****************************/
00419 
00420 /* Unhide all edited MetaElems */
00421 static int reveal_metaelems_exec(bContext *C, wmOperator *UNUSED(op))
00422 {
00423         Object *obedit= CTX_data_edit_object(C);
00424         MetaBall *mb= (MetaBall*)obedit->data;
00425         MetaElem *ml;
00426 
00427         ml= mb->editelems->first;
00428 
00429         if(ml) {
00430                 while(ml) {
00431                         ml->flag &= ~MB_HIDE;
00432                         ml= ml->next;
00433                 }
00434                 WM_event_add_notifier(C, NC_GEOM|ND_DATA, mb);
00435                 DAG_id_tag_update(obedit->data, 0);
00436         }
00437         
00438         return OPERATOR_FINISHED;
00439 }
00440 
00441 void MBALL_OT_reveal_metaelems(wmOperatorType *ot)
00442 {
00443         /* identifiers */
00444         ot->name= "Reveal";
00445         ot->description= "Reveal all hidden metaelements";
00446         ot->idname= "MBALL_OT_reveal_metaelems";
00447         
00448         /* callback functions */
00449         ot->exec= reveal_metaelems_exec;
00450         ot->poll= ED_operator_editmball;
00451         
00452         /* flags */
00453         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;  
00454 }
00455 
00456 /* Select MetaElement with mouse click (user can select radius circle or
00457  * stiffness circle) */
00458 int mouse_mball(bContext *C, const int mval[2], int extend)
00459 {
00460         static MetaElem *startelem=NULL;
00461         Object *obedit= CTX_data_edit_object(C);
00462         ViewContext vc;
00463         MetaBall *mb = (MetaBall*)obedit->data;
00464         MetaElem *ml, *act=NULL;
00465         int a, hits;
00466         unsigned int buffer[4*MAXPICKBUF];
00467         rcti rect;
00468 
00469         view3d_set_viewcontext(C, &vc);
00470 
00471         rect.xmin= mval[0]-12;
00472         rect.xmax= mval[0]+12;
00473         rect.ymin= mval[1]-12;
00474         rect.ymax= mval[1]+12;
00475 
00476         hits= view3d_opengl_select(&vc, buffer, MAXPICKBUF, &rect);
00477 
00478         /* does startelem exist? */
00479         ml= mb->editelems->first;
00480         while(ml) {
00481                 if(ml==startelem) break;
00482                 ml= ml->next;
00483         }
00484 
00485         if(ml==NULL) startelem= mb->editelems->first;
00486         
00487         if(hits>0) {
00488                 ml= startelem;
00489                 while(ml) {
00490                         for(a=0; a<hits; a++) {
00491                                 /* index converted for gl stuff */
00492                                 if(ml->selcol1==buffer[ 4 * a + 3 ]){
00493                                         ml->flag |= MB_SCALE_RAD;
00494                                         act= ml;
00495                                 }
00496                                 if(ml->selcol2==buffer[ 4 * a + 3 ]){
00497                                         ml->flag &= ~MB_SCALE_RAD;
00498                                         act= ml;
00499                                 }
00500                         }
00501                         if(act) break;
00502                         ml= ml->next;
00503                         if(ml==NULL) ml= mb->editelems->first;
00504                         if(ml==startelem) break;
00505                 }
00506                 
00507                 /* When some metaelem was found, then it is necessary to select or
00508                  * deselet it. */
00509                 if(act) {
00510                         if(extend==0) {
00511                                 /* Deselect all existing metaelems */
00512                                 ml= mb->editelems->first;
00513                                 while(ml) {
00514                                         ml->flag &= ~SELECT;
00515                                         ml= ml->next;
00516                                 }
00517                                 /* Select only metaelem clicked on */
00518                                 act->flag |= SELECT;
00519                         }
00520                         else {
00521                                 if(act->flag & SELECT)
00522                                         act->flag &= ~SELECT;
00523                                 else
00524                                         act->flag |= SELECT;
00525                         }
00526                         mb->lastelem= act;
00527                         
00528                         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, mb);
00529 
00530                         return 1;
00531                 }
00532         }
00533 
00534         return 0;
00535 }
00536 
00537 
00538 /*  ************* undo for MetaBalls ************* */
00539 
00540 /* free all MetaElems from ListBase */
00541 static void freeMetaElemlist(ListBase *lb)
00542 {
00543         MetaElem *ml, *next;
00544 
00545         if(lb==NULL) return;
00546 
00547         ml= lb->first;
00548         while(ml){
00549                 next= ml->next;
00550                 BLI_remlink(lb, ml);
00551                 MEM_freeN(ml);
00552                 ml= next;
00553         }
00554 
00555         lb->first= lb->last= NULL;
00556 }
00557 
00558 
00559 static void undoMball_to_editMball(void *lbu, void *lbe)
00560 {
00561         ListBase *lb= lbu;
00562         ListBase *editelems= lbe;
00563         MetaElem *ml, *newml;
00564         
00565         freeMetaElemlist(editelems);
00566 
00567         /* copy 'undo' MetaElems to 'edit' MetaElems */
00568         ml= lb->first;
00569         while(ml){
00570                 newml= MEM_dupallocN(ml);
00571                 BLI_addtail(editelems, newml);
00572                 ml= ml->next;
00573         }
00574         
00575 }
00576 
00577 static void *editMball_to_undoMball(void *lbe)
00578 {
00579         ListBase *editelems= lbe;
00580         ListBase *lb;
00581         MetaElem *ml, *newml;
00582 
00583         /* allocate memory for undo ListBase */
00584         lb= MEM_callocN(sizeof(ListBase), "listbase undo");
00585         lb->first= lb->last= NULL;
00586         
00587         /* copy contents of current ListBase to the undo ListBase */
00588         ml= editelems->first;
00589         while(ml){
00590                 newml= MEM_dupallocN(ml);
00591                 BLI_addtail(lb, newml);
00592                 ml= ml->next;
00593         }
00594         
00595         return lb;
00596 }
00597 
00598 /* free undo ListBase of MetaElems */
00599 static void free_undoMball(void *lbv)
00600 {
00601         ListBase *lb= lbv;
00602         
00603         freeMetaElemlist(lb);
00604         MEM_freeN(lb);
00605 }
00606 
00607 static ListBase *metaball_get_editelems(Object *ob)
00608 {
00609         if(ob && ob->type==OB_MBALL) {
00610                 struct MetaBall *mb= (struct MetaBall*)ob->data;
00611                 return mb->editelems;
00612         }
00613         return NULL;
00614 }
00615 
00616 
00617 static void *get_data(bContext *C)
00618 {
00619         Object *obedit= CTX_data_edit_object(C);
00620         return metaball_get_editelems(obedit);
00621 }
00622 
00623 /* this is undo system for MetaBalls */
00624 void undo_push_mball(bContext *C, const char *name)
00625 {
00626         undo_editmode_push(C, name, get_data, free_undoMball, undoMball_to_editMball, editMball_to_undoMball, NULL);
00627 }
00628