|
Blender
V2.59
|
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