This repository has been archived on 2023-10-09. You can view files and clone it, but cannot push or open issues or pull requests.
Files
blender-archive/source/blender/editors/metaball/mball_edit.c
Campbell Barton 6d3546069c fix [#26713] Video Sequencer: Audio mute after making meta strip copy/paste
was not recursively restoring sound strips on paste.

also found many duplicate functions were defining the transform mode as in int but getting as an enum, use enum for both now.
2011-04-01 08:51:12 +00:00

629 lines
14 KiB
C

/*
* $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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 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 *****
*/
/** \file blender/editors/metaball/mball_edit.c
* \ingroup edmeta
*/
#include <math.h>
#include <string.h>
#include "MEM_guardedalloc.h"
#include "BLI_blenlib.h"
#include "BLI_math.h"
#include "BLI_rand.h"
#include "BLI_utildefines.h"
#include "DNA_meta_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "RNA_define.h"
#include "RNA_access.h"
#include "RNA_enum_types.h"
#include "BKE_depsgraph.h"
#include "BKE_context.h"
#include "BKE_mball.h"
#include "ED_mball.h"
#include "ED_screen.h"
#include "ED_view3d.h"
#include "ED_transform.h"
#include "ED_util.h"
#include "WM_api.h"
#include "WM_types.h"
#include "mball_intern.h"
/* This function is used to free all MetaElems from MetaBall */
void free_editMball(Object *obedit)
{
MetaBall *mb = (MetaBall*)obedit->data;
mb->editelems= NULL;
mb->lastelem= NULL;
}
/* This function is called, when MetaBall Object is
* switched from object mode to edit mode */
void make_editMball(Object *obedit)
{
MetaBall *mb = (MetaBall*)obedit->data;
MetaElem *ml;/*, *newml;*/
ml= mb->elems.first;
while(ml) {
if(ml->flag & SELECT) mb->lastelem = ml;
ml= ml->next;
}
mb->editelems = &mb->elems;
}
/* This function is called, when MetaBall Object switched from
* edit mode to object mode. List od MetaElements is copied
* from object->data->edit_elems to object->data->elems. */
void load_editMball(Object *UNUSED(obedit))
{
}
/* Add metaelem primitive to metaball object (which is in edit mode) */
MetaElem *add_metaball_primitive(bContext *C, float mat[4][4], int type, int UNUSED(newname))
{
Object *obedit= CTX_data_edit_object(C);
MetaBall *mball = (MetaBall*)obedit->data;
MetaElem *ml;
/* Deselect all existing metaelems */
ml= mball->editelems->first;
while(ml) {
ml->flag &= ~SELECT;
ml= ml->next;
}
ml= add_metaball_element(mball, type);
copy_v3_v3(&ml->x, mat[3]);
ml->flag |= SELECT;
mball->lastelem= ml;
return ml;
}
/***************************** Select/Deselect operator *****************************/
/* Select or deselect all MetaElements */
static int select_all_exec(bContext *C, wmOperator *op)
{
//Scene *scene= CTX_data_scene(C);
Object *obedit= CTX_data_edit_object(C);
MetaBall *mb = (MetaBall*)obedit->data;
MetaElem *ml;
int action = RNA_enum_get(op->ptr, "action");
ml= mb->editelems->first;
if(ml) {
if (action == SEL_TOGGLE) {
action = SEL_SELECT;
while(ml) {
if(ml->flag & SELECT) {
action = SEL_DESELECT;
break;
}
ml= ml->next;
}
}
ml= mb->editelems->first;
while(ml) {
switch (action) {
case SEL_SELECT:
ml->flag |= SELECT;
break;
case SEL_DESELECT:
ml->flag &= ~SELECT;
break;
case SEL_INVERT:
ml->flag ^= SELECT;
break;
}
ml= ml->next;
}
WM_event_add_notifier(C, NC_GEOM|ND_SELECT, mb);
}
return OPERATOR_FINISHED;
}
void MBALL_OT_select_all(wmOperatorType *ot)
{
/* identifiers */
ot->name= "Select or Deselect All";
ot->description= "Change selection of all meta elements";
ot->idname= "MBALL_OT_select_all";
/* callback functions */
ot->exec= select_all_exec;
ot->poll= ED_operator_editmball;
/* flags */
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
WM_operator_properties_select_all(ot);
}
/***************************** Select inverse operator *****************************/
/* Invert metaball selection */
static int select_inverse_metaelems_exec(bContext *C, wmOperator *UNUSED(op))
{
Object *obedit= CTX_data_edit_object(C);
MetaBall *mb = (MetaBall*)obedit->data;
MetaElem *ml;
ml= mb->editelems->first;
if(ml) {
while(ml) {
if(ml->flag & SELECT)
ml->flag &= ~SELECT;
else
ml->flag |= SELECT;
ml= ml->next;
}
WM_event_add_notifier(C, NC_GEOM|ND_SELECT, mb);
}
return OPERATOR_FINISHED;
}
void MBALL_OT_select_inverse_metaelems(wmOperatorType *ot)
{
/* identifiers */
ot->name= "Inverse";
ot->description= "Select inverse of (un)selected metaelements";
ot->idname= "MBALL_OT_select_inverse_metaelems";
/* callback functions */
ot->exec= select_inverse_metaelems_exec;
ot->poll= ED_operator_editmball;
/* flags */
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
}
/***************************** Select random operator *****************************/
/* Random metaball selection */
static int select_random_metaelems_exec(bContext *C, wmOperator *op)
{
Object *obedit= CTX_data_edit_object(C);
MetaBall *mb = (MetaBall*)obedit->data;
MetaElem *ml;
float percent= RNA_float_get(op->ptr, "percent");
if(percent == 0.0f)
return OPERATOR_CANCELLED;
ml= mb->editelems->first;
BLI_srand( BLI_rand() ); /* Random seed */
/* Stupid version of random selection. Should be improved. */
while(ml) {
if(BLI_frand() < percent)
ml->flag |= SELECT;
else
ml->flag &= ~SELECT;
ml= ml->next;
}
WM_event_add_notifier(C, NC_GEOM|ND_SELECT, mb);
return OPERATOR_FINISHED;
}
void MBALL_OT_select_random_metaelems(struct wmOperatorType *ot)
{
/* identifiers */
ot->name= "Random...";
ot->description= "Randomly select metaelements";
ot->idname= "MBALL_OT_select_random_metaelems";
/* callback functions */
ot->exec= select_random_metaelems_exec;
ot->invoke= WM_operator_props_popup;
ot->poll= ED_operator_editmball;
/* flags */
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
/* properties */
RNA_def_float_percentage(ot->srna, "percent", 0.5f, 0.0f, 1.0f, "Percent", "Percentage of metaelems to select randomly.", 0.0001f, 1.0f);
}
/***************************** Duplicate operator *****************************/
/* Duplicate selected MetaElements */
static int duplicate_metaelems_exec(bContext *C, wmOperator *UNUSED(op))
{
Object *obedit= CTX_data_edit_object(C);
MetaBall *mb = (MetaBall*)obedit->data;
MetaElem *ml, *newml;
ml= mb->editelems->last;
if(ml) {
while(ml) {
if(ml->flag & SELECT) {
newml= MEM_dupallocN(ml);
BLI_addtail(mb->editelems, newml);
mb->lastelem= newml;
ml->flag &= ~SELECT;
}
ml= ml->prev;
}
WM_event_add_notifier(C, NC_GEOM|ND_DATA, mb);
DAG_id_tag_update(obedit->data, 0);
}
return OPERATOR_FINISHED;
}
static int duplicate_metaelems_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
{
int retv= duplicate_metaelems_exec(C, op);
if (retv == OPERATOR_FINISHED) {
RNA_enum_set(op->ptr, "mode", TFM_TRANSLATION);
WM_operator_name_call(C, "TRANSFORM_OT_transform", WM_OP_INVOKE_REGION_WIN, op->ptr);
}
return retv;
}
void MBALL_OT_duplicate_metaelems(wmOperatorType *ot)
{
/* identifiers */
ot->name= "Duplicate";
ot->description= "Delete selected metaelement(s)";
ot->idname= "MBALL_OT_duplicate_metaelems";
/* callback functions */
ot->exec= duplicate_metaelems_exec;
ot->invoke= duplicate_metaelems_invoke;
ot->poll= ED_operator_editmball;
/* flags */
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
/* to give to transform */
RNA_def_enum(ot->srna, "mode", transform_mode_types, TFM_TRANSLATION, "Mode", "");
}
/***************************** Delete operator *****************************/
/* Delete all selected MetaElems (not MetaBall) */
static int delete_metaelems_exec(bContext *C, wmOperator *UNUSED(op))
{
Object *obedit= CTX_data_edit_object(C);
MetaBall *mb= (MetaBall*)obedit->data;
MetaElem *ml, *next;
ml= mb->editelems->first;
if(ml) {
while(ml) {
next= ml->next;
if(ml->flag & SELECT) {
if(mb->lastelem==ml) mb->lastelem= NULL;
BLI_remlink(mb->editelems, ml);
MEM_freeN(ml);
}
ml= next;
}
WM_event_add_notifier(C, NC_GEOM|ND_DATA, mb);
DAG_id_tag_update(obedit->data, 0);
}
return OPERATOR_FINISHED;
}
void MBALL_OT_delete_metaelems(wmOperatorType *ot)
{
/* identifiers */
ot->name= "Delete";
ot->description= "Delete selected metaelement(s)";
ot->idname= "MBALL_OT_delete_metaelems";
/* callback functions */
ot->exec= delete_metaelems_exec;
ot->poll= ED_operator_editmball;
/* flags */
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
}
/***************************** Hide operator *****************************/
/* Hide selected MetaElems */
static int hide_metaelems_exec(bContext *C, wmOperator *op)
{
Object *obedit= CTX_data_edit_object(C);
MetaBall *mb= (MetaBall*)obedit->data;
MetaElem *ml;
const int invert= RNA_boolean_get(op->ptr, "unselected") ? SELECT : 0;
ml= mb->editelems->first;
if(ml) {
while(ml){
if((ml->flag & SELECT) != invert)
ml->flag |= MB_HIDE;
ml= ml->next;
}
WM_event_add_notifier(C, NC_GEOM|ND_DATA, mb);
DAG_id_tag_update(obedit->data, 0);
}
return OPERATOR_FINISHED;
}
void MBALL_OT_hide_metaelems(wmOperatorType *ot)
{
/* identifiers */
ot->name= "Hide";
ot->description= "Hide (un)selected metaelement(s)";
ot->idname= "MBALL_OT_hide_metaelems";
/* callback functions */
ot->exec= hide_metaelems_exec;
ot->poll= ED_operator_editmball;
/* flags */
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
/* props */
RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected rather than selected.");
}
/***************************** Unhide operator *****************************/
/* Unhide all edited MetaElems */
static int reveal_metaelems_exec(bContext *C, wmOperator *UNUSED(op))
{
Object *obedit= CTX_data_edit_object(C);
MetaBall *mb= (MetaBall*)obedit->data;
MetaElem *ml;
ml= mb->editelems->first;
if(ml) {
while(ml) {
ml->flag &= ~MB_HIDE;
ml= ml->next;
}
WM_event_add_notifier(C, NC_GEOM|ND_DATA, mb);
DAG_id_tag_update(obedit->data, 0);
}
return OPERATOR_FINISHED;
}
void MBALL_OT_reveal_metaelems(wmOperatorType *ot)
{
/* identifiers */
ot->name= "Reveal";
ot->description= "Reveal all hidden metaelements";
ot->idname= "MBALL_OT_reveal_metaelems";
/* callback functions */
ot->exec= reveal_metaelems_exec;
ot->poll= ED_operator_editmball;
/* flags */
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
}
/* Select MetaElement with mouse click (user can select radius circle or
* stiffness circle) */
int mouse_mball(bContext *C, short mval[2], int extend)
{
static MetaElem *startelem=NULL;
Object *obedit= CTX_data_edit_object(C);
ViewContext vc;
MetaBall *mb = (MetaBall*)obedit->data;
MetaElem *ml, *act=NULL;
int a, hits;
unsigned int buffer[4*MAXPICKBUF];
rcti rect;
view3d_set_viewcontext(C, &vc);
rect.xmin= mval[0]-12;
rect.xmax= mval[0]+12;
rect.ymin= mval[1]-12;
rect.ymax= mval[1]+12;
hits= view3d_opengl_select(&vc, buffer, MAXPICKBUF, &rect);
/* does startelem exist? */
ml= mb->editelems->first;
while(ml) {
if(ml==startelem) break;
ml= ml->next;
}
if(ml==NULL) startelem= mb->editelems->first;
if(hits>0) {
ml= startelem;
while(ml) {
for(a=0; a<hits; a++) {
/* index converted for gl stuff */
if(ml->selcol1==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= mb->editelems->first;
if(ml==startelem) break;
}
/* When some metaelem was found, then it is necessary to select or
* deselet it. */
if(act) {
if(extend==0) {
/* Deselect all existing metaelems */
ml= mb->editelems->first;
while(ml) {
ml->flag &= ~SELECT;
ml= ml->next;
}
/* Select only metaelem clicked on */
act->flag |= SELECT;
}
else {
if(act->flag & SELECT)
act->flag &= ~SELECT;
else
act->flag |= SELECT;
}
mb->lastelem= act;
WM_event_add_notifier(C, NC_GEOM|ND_SELECT, mb);
return 1;
}
}
return 0;
}
/* ************* undo for MetaBalls ************* */
/* free all MetaElems from ListBase */
static 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;
}
static void undoMball_to_editMball(void *lbu, void *lbe)
{
ListBase *lb= lbu;
ListBase *editelems= lbe;
MetaElem *ml, *newml;
freeMetaElemlist(editelems);
/* copy 'undo' MetaElems to 'edit' MetaElems */
ml= lb->first;
while(ml){
newml= MEM_dupallocN(ml);
BLI_addtail(editelems, newml);
ml= ml->next;
}
}
static void *editMball_to_undoMball(void *lbe)
{
ListBase *editelems= lbe;
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);
}
static ListBase *metaball_get_editelems(Object *ob)
{
if(ob && ob->type==OB_MBALL) {
struct MetaBall *mb= (struct MetaBall*)ob->data;
return mb->editelems;
}
return NULL;
}
static void *get_data(bContext *C)
{
Object *obedit= CTX_data_edit_object(C);
return metaball_get_editelems(obedit);
}
/* this is undo system for MetaBalls */
void undo_push_mball(bContext *C, const char *name)
{
undo_editmode_push(C, name, get_data, free_undoMball, undoMball_to_editMball, editMball_to_undoMball, NULL);
}