diff options
author | Maxime Curioni <maxime.curioni@gmail.com> | 2009-09-28 10:03:55 +0400 |
---|---|---|
committer | Maxime Curioni <maxime.curioni@gmail.com> | 2009-09-28 10:03:55 +0400 |
commit | ca347a1a3d2690e74fc1a36510efa1b793c2a35c (patch) | |
tree | bebaaacc4e0d06d616be7f3364cd242741132d23 /source/blender | |
parent | b24004343f40fddc0ad5e5f6bfbfa2f4245dcc77 (diff) | |
parent | 8ea2904693707209d739928a70072d339c547b84 (diff) |
soc-2008-mxcurioni: merged changes to revision 23516
Diffstat (limited to 'source/blender')
241 files changed, 11340 insertions, 3002 deletions
diff --git a/source/blender/CMakeLists.txt b/source/blender/CMakeLists.txt index e4f80cf3223..478c698ba86 100644 --- a/source/blender/CMakeLists.txt +++ b/source/blender/CMakeLists.txt @@ -40,6 +40,7 @@ ADD_SUBDIRECTORY(makesrna) ADD_SUBDIRECTORY(readblenfile) ADD_SUBDIRECTORY(render) ADD_SUBDIRECTORY(blenfont) +ADD_SUBDIRECTORY(ikplugin) ADD_SUBDIRECTORY(freestyle) IF(WITH_OPENEXR) diff --git a/source/blender/Makefile b/source/blender/Makefile index 31636f838c3..6bc874c3c93 100644 --- a/source/blender/Makefile +++ b/source/blender/Makefile @@ -34,7 +34,7 @@ DIRS = windowmanager editors blenloader readblenfile DIRS += avi imbuf render blenlib blenkernel blenpluginapi DIRS += makesdna makesrna DIRS += python nodes gpu -DIRS += blenfont +DIRS += blenfont ikplugin ifeq ($(WITH_QUICKTIME), true) DIRS += quicktime diff --git a/source/blender/SConscript b/source/blender/SConscript index 504f7a971dd..a28dbc80e53 100644 --- a/source/blender/SConscript +++ b/source/blender/SConscript @@ -17,8 +17,9 @@ SConscript(['avi/SConscript', 'readblenfile/SConscript', 'render/SConscript', 'nodes/SConscript', + 'ikplugin/SConscript', 'windowmanager/SConscript', - 'blenfont/SConscript']) + 'blenfont/SConscript']) diff --git a/source/blender/blenfont/CMakeLists.txt b/source/blender/blenfont/CMakeLists.txt index 844a6899bf5..9b7e950526d 100644 --- a/source/blender/blenfont/CMakeLists.txt +++ b/source/blender/blenfont/CMakeLists.txt @@ -32,6 +32,7 @@ SET(INC IF(WITH_INTERNATIONAL) SET(INC ${INC} ${GETTEXT_INC}) + ADD_DEFINITIONS(-DINTERNATIONAL) ENDIF(WITH_INTERNATIONAL) IF(WIN32) diff --git a/source/blender/blenfont/Makefile b/source/blender/blenfont/Makefile index 70dd2e5052b..43eda027855 100644 --- a/source/blender/blenfont/Makefile +++ b/source/blender/blenfont/Makefile @@ -28,3 +28,7 @@ SOURCEDIR = source/blender/blenfont DIRS = intern include nan_subdirs.mk + +ifeq ($(INTERNATIONAL), true) + CPPFLAGS += -DINTERNATIONAL +endif diff --git a/source/blender/blenfont/SConscript b/source/blender/blenfont/SConscript index d070d985247..91edc46ba8b 100644 --- a/source/blender/blenfont/SConscript +++ b/source/blender/blenfont/SConscript @@ -9,9 +9,13 @@ incs += ' #/extern/glew/include' incs += ' ' + env['BF_FREETYPE_INC'] incs += ' ' + env['BF_GETTEXT_INC'] -defs = '' +defs = [] if sys.platform == 'win32': - defs += ' _WIN32 USE_GETTEXT_DLL' + defs.append('_WIN32') + defs.append('USE_GETTEXT_DLL') + +if env['WITH_BF_INTERNATIONAL']: + defs.append('INTERNATIONAL') env.BlenderLib ( 'bf_blenfont', sources, Split(incs), Split(defs), libtype=['core','player'], priority=[210,210] ) diff --git a/source/blender/blenfont/intern/blf_font.c b/source/blender/blenfont/intern/blf_font.c index 0a3dd259f6c..8721e49f06b 100644 --- a/source/blender/blenfont/intern/blf_font.c +++ b/source/blender/blenfont/intern/blf_font.c @@ -353,8 +353,8 @@ void blf_font_boundbox(FontBLF *font, char *str, rctf *box) pen_x += delta.x >> 6; } - gbox.xmin= g->box.xmin + pen_x; - gbox.xmax= g->box.xmax + pen_x; + gbox.xmin= pen_x; + gbox.xmax= pen_x + g->advance; gbox.ymin= g->box.ymin + pen_y; gbox.ymax= g->box.ymax + pen_y; diff --git a/source/blender/blenfont/intern/blf_lang.c b/source/blender/blenfont/intern/blf_lang.c index 024172d6db4..ed684eda46f 100644 --- a/source/blender/blenfont/intern/blf_lang.c +++ b/source/blender/blenfont/intern/blf_lang.c @@ -60,17 +60,14 @@ char global_messagepath[1024]; char global_language[32]; char global_encoding_name[32]; - -void BLF_lang_init(void) +#if defined(__APPLE__) +void BLF_lang_init(void) /* Apple Only, todo - use BLI_gethome_folder */ { -#ifdef __APPLE__ char *bundlepath; -#endif strcpy(global_encoding_name, SYSTEM_ENCODING_DEFAULT); /* set messagepath directory */ - #ifndef LOCALEDIR #define LOCALEDIR "/usr/share/locale" #endif @@ -81,44 +78,52 @@ void BLF_lang_init(void) BLI_make_file_string("/", global_messagepath, BLI_gethome(), ".blender/locale"); if (!BLI_exist(global_messagepath)) { /* locale not in home dir */ -#ifdef WIN32 - BLI_make_file_string("/", global_messagepath, BLI_gethome(), "/locale"); - if (!BLI_exist(global_messagepath)) { -#endif -#ifdef __APPLE__ /* message catalogs are stored inside the application bundle */ bundlepath= BLI_getbundle(); strcpy(global_messagepath, bundlepath); strcat(global_messagepath, "/Contents/Resources/locale"); if (!BLI_exist(global_messagepath)) { /* locale not in bundle (now that's odd..) */ -#endif strcpy(global_messagepath, LOCALEDIR); if (!BLI_exist(global_messagepath)) { /* locale not in LOCALEDIR */ strcpy(global_messagepath, "message"); /* old compatibility as last */ } -#ifdef WIN32 } -#endif -#ifdef __APPLE__ - } -#endif } } } - -void BLF_lang_set(const char *str) +#elif defined(_WIN32) +void BLF_lang_init(void) /* Windows Only, todo - use BLI_gethome_folder */ { -#if defined (_WIN32) || defined(__APPLE__) - char envstr[12]; + strcpy(global_encoding_name, SYSTEM_ENCODING_DEFAULT); + + strcpy(global_messagepath, ".blender/locale"); + + if (!BLI_exist(global_messagepath)) { /* locale not in current dir */ + BLI_make_file_string("/", global_messagepath, BLI_gethome(), ".blender/locale"); - sprintf(envstr, "LANG=%s", str); - envstr[strlen(envstr)]= '\0'; -#ifdef _WIN32 - gettext_putenv(envstr); + if (!BLI_exist(global_messagepath)) { /* locale not in home dir */ + BLI_make_file_string("/", global_messagepath, BLI_gethome(), "/locale"); + } + } +} #else - putenv(envstr); +void BLF_lang_init(void) /* not win or mac */ +{ + char *messagepath= BLI_gethome_folder("locale", BLI_GETHOME_ALL); + + if(messagepath) + strncpy(global_messagepath, messagepath, sizeof(global_messagepath)); + else + global_messagepath[0]= '\0'; + +} #endif + +void BLF_lang_set(const char *str) +{ +#if defined (_WIN32) || defined(__APPLE__) + BLI_setenv("LANG", str); #else char *locreturn= setlocale(LC_ALL, str); if (locreturn == NULL) { diff --git a/source/blender/blenkernel/BKE_action.h b/source/blender/blenkernel/BKE_action.h index f079cc08281..17b56864d1e 100644 --- a/source/blender/blenkernel/BKE_action.h +++ b/source/blender/blenkernel/BKE_action.h @@ -41,6 +41,7 @@ struct bAction; struct bActionGroup; struct FCurve; struct bPose; +struct bItasc; struct bPoseChannel; struct Object; struct Scene; @@ -154,11 +155,21 @@ struct bPoseChannel *get_active_posechannel(struct Object *ob); */ struct bPoseChannel *verify_pose_channel(struct bPose* pose, const char* name); - +/* Copy the data from the action-pose (src) into the pose */ +void extract_pose_from_pose(struct bPose *pose, const struct bPose *src); /* sets constraint flags */ void update_pose_constraint_flags(struct bPose *pose); +/* return the name of structure pointed by pose->ikparam */ +const char *get_ikparam_name(struct bPose *pose); + +/* allocate and initialize pose->ikparam according to pose->iksolver */ +void init_pose_ikparam(struct bPose *pose); + +/* initialize a bItasc structure with default value */ +void init_pose_itasc(struct bItasc *itasc); + /* clears BONE_UNKEYED flags for frame changing */ // XXX to be depreceated for a more general solution in animsys... void framechange_poses_clear_unkeyed(void); @@ -181,16 +192,6 @@ void copy_pose_result(struct bPose *to, struct bPose *from); /* clear all transforms */ void rest_pose(struct bPose *pose); -/* Game Engine ------------------------- */ - -/* exported for game engine */ -void game_blend_poses(struct bPose *dst, struct bPose *src, float srcweight/*, short mode*/); /* was blend_poses */ -void extract_pose_from_pose(struct bPose *pose, const struct bPose *src); - -/* functions used by the game engine */ -void game_copy_pose(struct bPose **dst, struct bPose *src); -void game_free_pose(struct bPose *pose); - #ifdef __cplusplus }; #endif diff --git a/source/blender/blenkernel/BKE_anim.h b/source/blender/blenkernel/BKE_anim.h index 4b1e758da54..32c5ff81740 100644 --- a/source/blender/blenkernel/BKE_anim.h +++ b/source/blender/blenkernel/BKE_anim.h @@ -39,14 +39,7 @@ struct PartEff; struct Scene; struct ListBase; -typedef struct DupliObject { - struct DupliObject *next, *prev; - struct Object *ob; - unsigned int origlay; - int index, no_draw, type, animated; - float mat[4][4], omat[4][4]; - float orco[3], uv[2]; -} DupliObject; +#include "DNA_object_types.h" void free_path(struct Path *path); void calc_curvepath(struct Object *ob); diff --git a/source/blender/blenkernel/BKE_armature.h b/source/blender/blenkernel/BKE_armature.h index 1cbb2331782..8dbd2721fb9 100644 --- a/source/blender/blenkernel/BKE_armature.h +++ b/source/blender/blenkernel/BKE_armature.h @@ -89,6 +89,7 @@ void where_is_armature (struct bArmature *arm); void where_is_armature_bone(struct Bone *bone, struct Bone *prevbone); void armature_rebuild_pose(struct Object *ob, struct bArmature *arm); void where_is_pose (struct Scene *scene, struct Object *ob); +void where_is_pose_bone(struct Scene *scene, struct Object *ob, struct bPoseChannel *pchan, float ctime); /* get_objectspace_bone_matrix has to be removed still */ void get_objectspace_bone_matrix (struct Bone* bone, float M_accumulatedMatrix[][4], int root, int posed); @@ -102,11 +103,6 @@ void armature_mat_pose_to_bone(struct bPoseChannel *pchan, float inmat[][4], flo void armature_loc_pose_to_bone(struct bPoseChannel *pchan, float *inloc, float *outloc); void armature_mat_pose_to_delta(float delta_mat[][4], float pose_mat[][4], float arm_mat[][4]); -/* Animation functions */ -struct PoseTree *ik_tree_to_posetree(struct Object *ob, struct Bone *bone); -void solve_posetree(PoseTree *tree); -void free_posetree(PoseTree *tree); - /* B-Bone support */ typedef struct Mat4 { float mat[4][4]; diff --git a/source/blender/blenkernel/BKE_brush.h b/source/blender/blenkernel/BKE_brush.h index 01566648557..f302618e60d 100644 --- a/source/blender/blenkernel/BKE_brush.h +++ b/source/blender/blenkernel/BKE_brush.h @@ -60,7 +60,8 @@ typedef enum { BRUSH_PRESET_MAX } BrushCurvePreset; void brush_curve_preset(struct Brush *b, BrushCurvePreset preset); -float brush_curve_strength(struct Brush *br, float p, const float len); +float brush_curve_strength_clamp(struct Brush *br, float p, const float len); +float brush_curve_strength(struct Brush *br, float p, const float len); /* used for sculpt */ /* sampling */ void brush_sample_tex(struct Brush *brush, float *xy, float *rgba); diff --git a/source/blender/blenkernel/BKE_collision.h b/source/blender/blenkernel/BKE_collision.h index e4eed084a3d..e0df75f41b9 100644 --- a/source/blender/blenkernel/BKE_collision.h +++ b/source/blender/blenkernel/BKE_collision.h @@ -139,7 +139,7 @@ void interpolateOnTriangle ( float to[3], float v1[3], float v2[3], float v3[3], ///////////////////////////////////////////////// // used in effect.c ///////////////////////////////////////////////// -CollisionModifierData **get_collisionobjects(struct Scene *scene, Object *self, int *numcollobj); +Object **get_collisionobjects(struct Scene *scene, Object *self, int *numcollobj); ///////////////////////////////////////////////// diff --git a/source/blender/blenkernel/BKE_constraint.h b/source/blender/blenkernel/BKE_constraint.h index a0061173438..126816f5a95 100644 --- a/source/blender/blenkernel/BKE_constraint.h +++ b/source/blender/blenkernel/BKE_constraint.h @@ -38,6 +38,9 @@ struct Scene; struct bPoseChannel; /* ---------------------------------------------------------------------------- */ +#ifdef __cplusplus +extern "C" { +#endif /* special struct for use in constraint evaluation */ typedef struct bConstraintOb { @@ -131,6 +134,9 @@ void constraint_mat_convertspace(struct Object *ob, struct bPoseChannel *pchan, void get_constraint_target_matrix(struct bConstraint *con, int n, short ownertype, void *ownerdata, float mat[][4], float ctime); void solve_constraints(struct ListBase *conlist, struct bConstraintOb *cob, float ctime); +#ifdef __cplusplus +} +#endif #endif diff --git a/source/blender/blenkernel/BKE_fcurve.h b/source/blender/blenkernel/BKE_fcurve.h index cda64c6b241..94d0864024b 100644 --- a/source/blender/blenkernel/BKE_fcurve.h +++ b/source/blender/blenkernel/BKE_fcurve.h @@ -35,6 +35,8 @@ struct DriverTarget; struct BezTriple; +#include "DNA_curve_types.h" + /* ************** Keyframe Tools ***************** */ // XXX this stuff is defined in BKE_ipo.h too, so maybe skip for now? @@ -153,6 +155,11 @@ void copy_fcurves(ListBase *dst, ListBase *src); /* find matching F-Curve in the given list of F-Curves */ struct FCurve *list_find_fcurve(ListBase *list, const char rna_path[], const int array_index); +/* Binary search algorithm for finding where to 'insert' BezTriple with given frame number. + * Returns the index to insert at (data already at that index will be offset if replace is 0) + */ +int binarysearch_bezt_index(struct BezTriple array[], float frame, int arraylen, short *replace); + /* get the time extents for F-Curve */ void calc_fcurve_range(struct FCurve *fcu, float *min, float *max); diff --git a/source/blender/blenkernel/BKE_image.h b/source/blender/blenkernel/BKE_image.h index 816baa20467..47ab6f324d3 100644 --- a/source/blender/blenkernel/BKE_image.h +++ b/source/blender/blenkernel/BKE_image.h @@ -125,6 +125,9 @@ void BKE_image_assign_ibuf(struct Image *ima, struct ImBuf *ibuf); /* called on frame change or before render */ void BKE_image_user_calc_imanr(struct ImageUser *iuser, int cfra, int fieldnr); +/* produce image export path */ +int BKE_get_image_export_path(struct Image *im, const char *dest_dir, char *abs, int abs_size, char *rel, int rel_size); + /* fix things in ImageUser when new image gets assigned */ void BKE_image_user_new_image(struct Image *ima, struct ImageUser *iuser); diff --git a/source/blender/blenkernel/BKE_sound.h b/source/blender/blenkernel/BKE_sound.h index e9f6eb21e36..cbce4663d6f 100644 --- a/source/blender/blenkernel/BKE_sound.h +++ b/source/blender/blenkernel/BKE_sound.h @@ -71,7 +71,7 @@ void sound_update_playing(struct bContext *C); void sound_scrub(struct bContext *C); #ifdef AUD_CAPI -AUD_Device* sound_mixdown(struct Scene *scene, AUD_Specs specs, int start, int end); +AUD_Device* sound_mixdown(struct Scene *scene, AUD_Specs specs, int start, int end, float volume); #endif void sound_stop_all(struct bContext *C); diff --git a/source/blender/blenkernel/BKE_text.h b/source/blender/blenkernel/BKE_text.h index 07e05756ea3..185e32ecdfa 100644 --- a/source/blender/blenkernel/BKE_text.h +++ b/source/blender/blenkernel/BKE_text.h @@ -104,6 +104,14 @@ struct TextMarker *txt_next_marker (struct Text *text, struct TextMarker *marke struct TextMarker *txt_prev_marker_color (struct Text *text, struct TextMarker *marker); struct TextMarker *txt_next_marker_color (struct Text *text, struct TextMarker *marker); +/* utility functions, could be moved somewhere more generic but are python/text related */ +int text_check_bracket(char ch); +int text_check_delim(char ch); +int text_check_digit(char ch); +int text_check_identifier(char ch); +int text_check_whitespace(char ch); + + /* Undo opcodes */ /* Simple main cursor movement */ diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt index 60a69e286f2..079a5411cf2 100644 --- a/source/blender/blenkernel/CMakeLists.txt +++ b/source/blender/blenkernel/CMakeLists.txt @@ -30,12 +30,10 @@ SET(INC . ../../../intern/guardedalloc ../../../intern/memutil ../editors/include ../blenlib ../makesdna ../render/extern/include ../../../intern/decimation/extern ../imbuf ../avi ../../../intern/elbeem/extern ../../../intern/opennl/extern - ../../../intern/iksolver/extern ../blenloader ../freestyle + ../../../intern/iksolver/extern ../blenloader ../ikplugin ../freestyle ../nodes ../../../extern/glew/include ../gpu ../makesrna ../../../intern/smoke/extern ../../../intern/bsp/extern ../blenfont ../../../intern/audaspace/intern - ../../../extern/lzo/minilzo - ../../../extern/lzma ${ZLIB_INC} ) @@ -76,6 +74,16 @@ IF(NOT WITH_ELBEEM) ADD_DEFINITIONS(-DDISABLE_ELBEEM) ENDIF(NOT WITH_ELBEEM) +IF(WITH_LZO) + SET(INC ${INC} ../../../extern/lzo/minilzo) + ADD_DEFINITIONS(-DWITH_LZO) +ENDIF(WITH_LZO) + +IF(WITH_LZMA) + SET(INC ${INC} ../../../extern/lzma) + ADD_DEFINITIONS(-DWITH_LZMA) +ENDIF(WITH_LZMA) + IF(WIN32) SET(INC ${INC} ${PTHREADS_INC}) ENDIF(WIN32) diff --git a/source/blender/blenkernel/SConscript b/source/blender/blenkernel/SConscript index 352e58a3cd6..cceb4c685fa 100644 --- a/source/blender/blenkernel/SConscript +++ b/source/blender/blenkernel/SConscript @@ -5,14 +5,12 @@ sources = env.Glob('intern/*.c') incs = '. #/intern/guardedalloc #/intern/memutil ../editors/include ../blenlib ../blenfont ../makesdna' incs += ' ../render/extern/include #/intern/decimation/extern ../makesrna' -incs += ' ../imbuf ../avi #/intern/elbeem/extern ../nodes' +incs += ' ../imbuf ../ikplugin ../avi #/intern/elbeem/extern ../nodes' incs += ' #/intern/iksolver/extern ../blenloader ../freestyle' incs += ' #/extern/bullet2/src' incs += ' #/intern/opennl/extern #/intern/bsp/extern' incs += ' ../gpu #/extern/glew/include' incs += ' #/intern/smoke/extern' -incs += ' #/extern/lzo/minilzo' -incs += ' #/extern/lzma' incs += ' #/intern/audaspace/intern' incs += ' ' + env['BF_OPENGL_INC'] @@ -61,7 +59,15 @@ if env['BF_NO_ELBEEM']: if env['WITH_BF_LCMS']: defs.append('WITH_LCMS') - + +if env['WITH_BF_LZO']: + incs += ' #/extern/lzo/minilzo' + defs.append('WITH_LZO') + +if env['WITH_BF_LZMA']: + incs += ' #/extern/lzma' + defs.append('WITH_LZMA') + if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc'): incs += ' ' + env['BF_PTHREADS_INC'] diff --git a/source/blender/blenkernel/intern/Makefile b/source/blender/blenkernel/intern/Makefile index 6c2edc9e25f..26b9b9ef0dd 100644 --- a/source/blender/blenkernel/intern/Makefile +++ b/source/blender/blenkernel/intern/Makefile @@ -47,6 +47,7 @@ CPPFLAGS += -I$(NAN_AUDASPACE)/include CPPFLAGS += -I../../makesdna CPPFLAGS += -I../../makesrna CPPFLAGS += -I../../imbuf +CPPFLAGS += -I../../ikplugin # This mod uses the BLI and BLO module CPPFLAGS += -I../../blenlib CPPFLAGS += -I../../blenloader @@ -85,14 +86,24 @@ CPPFLAGS += -I../../gpu # path to our own external headerfiles CPPFLAGS += -I.. -# path to bullet2, for cloth -CPPFLAGS += -I$(NAN_BULLET2)/include CPPFLAGS += -I$(NAN_FREETYPE)/include CPPFLAGS += -I$(NAN_FREETYPE)/include/freetype2 +# path to bullet2, for cloth +ifeq ($(NAN_USE_BULLET), true) + CPPFLAGS += -I$(NAN_BULLET2)/include +endif + # lzo and lzma, for pointcache -CPPFLAGS += -I$(NAN_LZO)/minilzo -CPPFLAGS += -I$(NAN_LZMA) +ifeq ($(WITH_LZO),true) + CPPFLAGS += -I$(NAN_LZO)/minilzo + CPPFLAGS += -DWITH_LZO +endif + +ifeq ($(WITH_LZO),true) + CPPFLAGS += -I$(NAN_LZMA) + CPPFLAGS += -DWITH_LZMA +endif ifeq ($(WITH_FFMPEG),true) CPPFLAGS += -DWITH_FFMPEG diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c index 1ff5d9b5c01..b8dc9fd049d 100644 --- a/source/blender/blenkernel/intern/action.c +++ b/source/blender/blenkernel/intern/action.c @@ -62,6 +62,7 @@ #include "BKE_main.h" #include "BKE_object.h" #include "BKE_utildefines.h" +#include "BIK_api.h" #include "BLI_arithb.h" #include "BLI_blenlib.h" @@ -451,7 +452,7 @@ bPoseChannel *verify_pose_channel(bPose* pose, const char* name) chan->limitmin[0]= chan->limitmin[1]= chan->limitmin[2]= -180.0f; chan->limitmax[0]= chan->limitmax[1]= chan->limitmax[2]= 180.0f; chan->stiffness[0]= chan->stiffness[1]= chan->stiffness[2]= 0.0f; - + chan->ikrotweight = chan->iklinweight = 0.0f; Mat4One(chan->constinv); BLI_addtail(&pose->chanbase, chan); @@ -477,7 +478,18 @@ bPoseChannel *get_active_posechannel (Object *ob) return NULL; } - +const char *get_ikparam_name(bPose *pose) +{ + if (pose) { + switch (pose->iksolver) { + case IKSOLVER_LEGACY: + return NULL; + case IKSOLVER_ITASC: + return "bItasc"; + } + } + return NULL; +} /* dst should be freed already, makes entire duplicate */ void copy_pose (bPose **dst, bPose *src, int copycon) { @@ -499,7 +511,10 @@ void copy_pose (bPose **dst, bPose *src, int copycon) outPose= MEM_callocN(sizeof(bPose), "pose"); BLI_duplicatelist(&outPose->chanbase, &src->chanbase); - + outPose->iksolver = src->iksolver; + outPose->ikdata = NULL; + outPose->ikparam = MEM_dupallocN(src->ikparam); + if (copycon) { for (pchan=outPose->chanbase.first; pchan; pchan=pchan->next) { copy_constraints(&listb, &pchan->constraints); // copy_constraints NULLs listb @@ -511,6 +526,39 @@ void copy_pose (bPose **dst, bPose *src, int copycon) *dst=outPose; } +void init_pose_itasc(bItasc *itasc) +{ + if (itasc) { + itasc->iksolver = IKSOLVER_ITASC; + itasc->minstep = 0.01f; + itasc->maxstep = 0.06f; + itasc->numiter = 100; + itasc->numstep = 4; + itasc->precision = 0.005f; + itasc->flag = ITASC_AUTO_STEP|ITASC_INITIAL_REITERATION|ITASC_SIMULATION; + itasc->feedback = 20.f; + itasc->maxvel = 50.f; + itasc->solver = ITASC_SOLVER_SDLS; + itasc->dampmax = 0.5; + itasc->dampeps = 0.15; + } +} +void init_pose_ikparam(bPose *pose) +{ + bItasc *itasc; + switch (pose->iksolver) { + case IKSOLVER_ITASC: + itasc = MEM_callocN(sizeof(bItasc), "itasc"); + init_pose_itasc(itasc); + pose->ikparam = itasc; + break; + case IKSOLVER_LEGACY: + default: + pose->ikparam = NULL; + break; + } +} + void free_pose_channels(bPose *pose) { bPoseChannel *pchan; @@ -534,133 +582,15 @@ void free_pose(bPose *pose) /* free pose-groups */ if (pose->agroups.first) BLI_freelistN(&pose->agroups); - - /* free pose */ - MEM_freeN(pose); - } -} -void game_copy_pose(bPose **dst, bPose *src) -{ - bPose *out; - bPoseChannel *pchan, *outpchan; - GHash *ghash; - - /* the game engine copies the current armature pose and then swaps - * the object pose pointer. this makes it possible to change poses - * without affecting the original blender data. */ + /* free IK solver state */ + BIK_clear_data(pose); - if (!src) { - *dst=NULL; - return; - } - else if (*dst==src) { - printf("copy_pose source and target are the same\n"); - *dst=NULL; - return; - } - - out= MEM_dupallocN(src); - out->agroups.first= out->agroups.last= NULL; - BLI_duplicatelist(&out->chanbase, &src->chanbase); - - /* remap pointers */ - ghash= BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp); - - pchan= src->chanbase.first; - outpchan= out->chanbase.first; - for (; pchan; pchan=pchan->next, outpchan=outpchan->next) - BLI_ghash_insert(ghash, pchan, outpchan); - - for (pchan=out->chanbase.first; pchan; pchan=pchan->next) { - pchan->parent= BLI_ghash_lookup(ghash, pchan->parent); - pchan->child= BLI_ghash_lookup(ghash, pchan->child); - pchan->path= NULL; - } - - BLI_ghash_free(ghash, NULL, NULL); - - *dst=out; -} - - -/* Only allowed for Poses with identical channels */ -void game_blend_poses(bPose *dst, bPose *src, float srcweight/*, short mode*/) -{ - short mode= ACTSTRIPMODE_BLEND; - - bPoseChannel *dchan; - const bPoseChannel *schan; - bConstraint *dcon, *scon; - float dstweight; - int i; - - switch (mode){ - case ACTSTRIPMODE_BLEND: - dstweight = 1.0F - srcweight; - break; - case ACTSTRIPMODE_ADD: - dstweight = 1.0F; - break; - default : - dstweight = 1.0F; - } - - schan= src->chanbase.first; - for (dchan = dst->chanbase.first; dchan; dchan=dchan->next, schan= schan->next){ - if (schan->flag & (POSE_ROT|POSE_LOC|POSE_SIZE)) { - /* replaced quat->matrix->quat conversion with decent quaternion interpol (ton) */ - - /* Do the transformation blend */ - if (schan->flag & POSE_ROT) { - /* quat interpolation done separate */ - if (schan->rotmode == PCHAN_ROT_QUAT) { - float dquat[4], squat[4]; - - QUATCOPY(dquat, dchan->quat); - QUATCOPY(squat, schan->quat); - if (mode==ACTSTRIPMODE_BLEND) - QuatInterpol(dchan->quat, dquat, squat, srcweight); - else { - QuatMulFac(squat, srcweight); - QuatMul(dchan->quat, dquat, squat); - } - - NormalQuat(dchan->quat); - } - } - - for (i=0; i<3; i++) { - /* blending for loc and scale are pretty self-explanatory... */ - if (schan->flag & POSE_LOC) - dchan->loc[i] = (dchan->loc[i]*dstweight) + (schan->loc[i]*srcweight); - if (schan->flag & POSE_SIZE) - dchan->size[i] = 1.0f + ((dchan->size[i]-1.0f)*dstweight) + ((schan->size[i]-1.0f)*srcweight); - - /* euler-rotation interpolation done here instead... */ - // FIXME: are these results decent? - if ((schan->flag & POSE_ROT) && (schan->rotmode)) - dchan->eul[i] = (dchan->eul[i]*dstweight) + (schan->eul[i]*srcweight); - } - dchan->flag |= schan->flag; - } - for(dcon= dchan->constraints.first, scon= schan->constraints.first; dcon && scon; dcon= dcon->next, scon= scon->next) { - /* no 'add' option for constraint blending */ - dcon->enforce= dcon->enforce*(1.0f-srcweight) + scon->enforce*srcweight; - } - } - - /* this pose is now in src time */ - dst->ctime= src->ctime; -} + /* free IK solver param */ + if (pose->ikparam) + MEM_freeN(pose->ikparam); -void game_free_pose(bPose *pose) -{ - if (pose) { - /* we don't free constraints, those are owned by the original pose */ - if(pose->chanbase.first) - BLI_freelistN(&pose->chanbase); - + /* free pose */ MEM_freeN(pose); } } @@ -917,7 +847,6 @@ void calc_action_range(const bAction *act, float *start, float *end, short incl_ } } - /* Return flags indicating which transforms the given object/posechannel has * - if 'curves' is provided, a list of links to these curves are also returned */ @@ -1252,138 +1181,6 @@ static void blend_pose_offset_bone(bActionStrip *strip, bPose *dst, bPose *src, VecAddf(dst->cyclic_offset, dst->cyclic_offset, src->cyclic_offset); } -typedef struct NlaIpoChannel { - struct NlaIpoChannel *next, *prev; - float val; - void *poin; - int type; -} NlaIpoChannel; - -static void extract_ipochannels_from_action(ListBase *lb, ID *id, bAction *act, const char *name, float ctime) -{ - bActionChannel *achan= get_action_channel(act, name); - IpoCurve *icu; - NlaIpoChannel *nic; - - if(achan==NULL) return; - - if(achan->ipo) { - calc_ipo(achan->ipo, ctime); - - for(icu= achan->ipo->curve.first; icu; icu= icu->next) { - /* skip IPO_BITS, is for layers and cannot be blended */ - if(icu->vartype != IPO_BITS) { - nic= MEM_callocN(sizeof(NlaIpoChannel), "NlaIpoChannel"); - BLI_addtail(lb, nic); - nic->val= icu->curval; - nic->poin= get_ipo_poin(id, icu, &nic->type); - } - } - } - - /* constraint channels only for objects */ - if(GS(id->name)==ID_OB) { - Object *ob= (Object *)id; - bConstraint *con; - bConstraintChannel *conchan; - - for (con=ob->constraints.first; con; con=con->next) { - conchan = get_constraint_channel(&achan->constraintChannels, con->name); - - if(conchan && conchan->ipo) { - calc_ipo(conchan->ipo, ctime); - - icu= conchan->ipo->curve.first; // only one ipo now - if(icu) { - nic= MEM_callocN(sizeof(NlaIpoChannel), "NlaIpoChannel constr"); - BLI_addtail(lb, nic); - nic->val= icu->curval; - nic->poin= &con->enforce; - nic->type= IPO_FLOAT; - } - } - } - } -} - -static NlaIpoChannel *find_nla_ipochannel(ListBase *lb, void *poin) -{ - NlaIpoChannel *nic; - - if(poin) { - for(nic= lb->first; nic; nic= nic->next) { - if(nic->poin==poin) - return nic; - } - } - return NULL; -} - - -static void blend_ipochannels(ListBase *dst, ListBase *src, float srcweight, int mode) -{ - NlaIpoChannel *snic, *dnic, *next; - float dstweight; - - switch (mode){ - case ACTSTRIPMODE_BLEND: - dstweight = 1.0F - srcweight; - break; - case ACTSTRIPMODE_ADD: - dstweight = 1.0F; - break; - default : - dstweight = 1.0F; - } - - for(snic= src->first; snic; snic= next) { - next= snic->next; - - dnic= find_nla_ipochannel(dst, snic->poin); - if(dnic==NULL) { - /* remove from src list, and insert in dest */ - BLI_remlink(src, snic); - BLI_addtail(dst, snic); - } - else { - /* we do the blend */ - dnic->val= dstweight*dnic->val + srcweight*snic->val; - } - } -} - -static int execute_ipochannels(ListBase *lb) -{ - NlaIpoChannel *nic; - int count = 0; - - for(nic= lb->first; nic; nic= nic->next) { - if(nic->poin) { - write_ipo_poin(nic->poin, nic->type, nic->val); - count++; - } - } - return count; -} - -/* nla timing */ - -/* this now only used for repeating cycles, to enable fields and blur. */ -/* the whole time control in blender needs serious thinking... */ -static float nla_time(Scene *scene, float cfra, float unit) -{ - extern float bluroffs; // bad construct, borrowed from object.c for now - extern float fieldoffs; - - /* motion blur & fields */ - cfra+= unit*(bluroffs+fieldoffs); - - /* global time */ - cfra*= scene->r.framelen; - - return cfra; -} - /* added "sizecorr" here, to allow armatures to be scaled and still have striding. Only works for uniform scaling. In general I'd advise against scaling armatures ever though! (ton) */ diff --git a/source/blender/blenkernel/intern/anim_sys.c b/source/blender/blenkernel/intern/anim_sys.c index 522297da1d7..07b7b6dc30c 100644 --- a/source/blender/blenkernel/intern/anim_sys.c +++ b/source/blender/blenkernel/intern/anim_sys.c @@ -40,6 +40,7 @@ #include "BLI_dynstr.h" #include "DNA_anim_types.h" +#include "DNA_scene_types.h" #include "BKE_animsys.h" #include "BKE_action.h" @@ -71,7 +72,7 @@ static short id_has_animdata (ID *id) switch (GS(id->name)) { /* has AnimData */ case ID_OB: - case ID_MB: case ID_CU: + case ID_MB: case ID_CU: case ID_AR: case ID_KE: case ID_PA: case ID_MA: case ID_TE: case ID_NT: @@ -210,26 +211,113 @@ static void make_local_strips(ListBase *strips) { NlaStrip *strip; - for(strip=strips->first; strip; strip=strip->next) { - if(strip->act) make_local_action(strip->act); - if(strip->remap && strip->remap->target) make_local_action(strip->remap->target); - + for (strip=strips->first; strip; strip=strip->next) { + if (strip->act) make_local_action(strip->act); + //if (strip->remap && strip->remap->target) make_local_action(strip->remap->target); + make_local_strips(&strip->strips); } } +/* Use local copy instead of linked copy of various ID-blocks */ void BKE_animdata_make_local(AnimData *adt) { NlaTrack *nlt; + + /* Actions - Active and Temp */ + if (adt->action) make_local_action(adt->action); + if (adt->tmpact) make_local_action(adt->tmpact); + /* Remaps */ + if (adt->remap && adt->remap->target) make_local_action(adt->remap->target); + + /* Drivers */ + // TODO: need to remap the ID-targets too? + + /* NLA Data */ + for (nlt=adt->nla_tracks.first; nlt; nlt=nlt->next) + make_local_strips(&nlt->strips); +} - if(adt->action) make_local_action(adt->action); - if(adt->tmpact) make_local_action(adt->tmpact); - if(adt->remap && adt->remap->target) make_local_action(adt->remap->target); +/* Path Validation -------------------------------------------- */ - for(nlt=adt->nla_tracks.first; nlt; nlt=nlt->next) - make_local_strips(&nlt->strips); +#if 0 +/* Check if some given RNA Path needs fixing - free the given path and set a new one as appropriate */ +static char *rna_path_rename_fix (ID *owner_id, PointerRNA *modPtr, char *newName, char *oldpath) +{ + + + return oldpath; // FIXME!!! } +/* Check RNA-Paths for a list of F-Curves */ +static void fcurves_path_rename_fix (ID *owner_id, PointerRNA *modPtr, char *newName, ListBase *curves) +{ + FCurve *fcu; + + /* we need to check every curve... */ + for (fcu= curves->first; fcu; fcu= fcu->next) { + /* firstly, handle the F-Curve's own path */ + fcu->rna_path= rna_path_rename_fix(owner_id, modPtr, newName, fcu->rna_path); + + /* driver? */ + if (fcu->driver) { + ChannelDriver *driver= fcu->driver; + DriverTarget *dtar; + + /* driver targets */ + for (dtar= driver->targets.first; dtar; dtar=dtar->next) { + dtat->rna_path= rna_path_rename_fix(dtar->id, modPtr, newName, dtar->rna_path); + } + } + } +} + +/* Fix all RNA-Paths for Actions linked to NLA Strips */ +static void nlastrips_path_rename_fix (ID *owner_id, PointerRNA *modPtr, char *newName, ListBase *strips) +{ + NlaStrip *strip; + + /* recursively check strips, fixing only actions... */ + for (strip= strips->first; strip; strip= strip->next) { + /* fix strip's action */ + if (strip->act) + fcurves_path_rename_fix(owner_id, modPtr, newName, &strip->act->curves); + /* ignore own F-Curves, since those are local... */ + + /* check sub-strips (if metas) */ + nlastrips_path_rename_fix(owner_id, modPtr, newName, &strip->strips); + } +} + +/* Fix all RNA-Paths in the AnimData block used by the given ID block + * - the pointer of interest must not have had its new name assigned already, otherwise + * path matching for this will never work + */ +void BKE_animdata_fix_paths_rename (ID *owner_id, PointerRNA *modPtr, char *newName) +{ + AnimData *adt= BKE_animdata_from_id(owner_id); + NlaTrack *nlt; + + /* if no AnimData, no need to proceed */ + if (ELEM4(NULL, owner_id, adt, modPtr, newName)) + return; + + /* Active action and temp action */ + if (adt->action) + fcurves_path_rename_fix(owner_id, modPtr, newName, &adt->action->curves); + if (adt->tmpact) + fcurves_path_rename_fix(owner_id, modPtr, newName, &adt->tmpact->curves); + + /* Drivers - Drivers are really F-Curves */ + fcurves_path_rename_fix(owner_id, modPtr, newName, &adt->drivers); + + /* NLA Data - Animation Data for Strips */ + for (nlt= adt->nla_tracks.first; nlt; nlt= nlt->next) { + + } +} +#endif + /* *********************************** */ /* KeyingSet API */ @@ -1517,10 +1605,16 @@ void BKE_animsys_evaluate_all_animation (Main *main, float ctime) AnimData *adt= BKE_animdata_from_id(id); Curve *cu= (Curve *)id; + /* set ctime variable for curve */ cu->ctime= ctime; + + /* now execute animation data on top of this as per normal */ BKE_animsys_evaluate_animdata(id, adt, ctime, ADT_RECALC_ANIM); } + /* armatures */ + EVAL_ANIM_IDS(main->armature.first, ADT_RECALC_ANIM); + /* meshes */ // TODO... @@ -1537,7 +1631,19 @@ void BKE_animsys_evaluate_all_animation (Main *main, float ctime) EVAL_ANIM_IDS(main->world.first, ADT_RECALC_ANIM); /* scenes */ - EVAL_ANIM_IDS(main->scene.first, ADT_RECALC_ANIM); + for (id= main->scene.first; id; id= id->next) { + AnimData *adt= BKE_animdata_from_id(id); + Scene *scene= (Scene *)id; + + /* do compositing nodes first (since these aren't included in main tree) */ + if (scene->nodetree) { + AnimData *adt2= BKE_animdata_from_id((ID *)scene->nodetree); + BKE_animsys_evaluate_animdata((ID *)scene->nodetree, adt2, ctime, ADT_RECALC_ANIM); + } + + /* now execute scene animation data as per normal */ + BKE_animsys_evaluate_animdata(id, adt, ctime, ADT_RECALC_ANIM); + } } /* ***************************************** */ diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c index c880925aa94..b2368451414 100644 --- a/source/blender/blenkernel/intern/armature.c +++ b/source/blender/blenkernel/intern/armature.c @@ -66,10 +66,9 @@ #include "BKE_object.h" #include "BKE_object.h" #include "BKE_utildefines.h" +#include "BIK_api.h" #include "BKE_sketch.h" -#include "IK_solver.h" - #ifdef HAVE_CONFIG_H #include <config.h> #endif @@ -1569,409 +1568,10 @@ void armature_rebuild_pose(Object *ob, bArmature *arm) DAG_pose_sort(ob); ob->pose->flag &= ~POSE_RECALC; + ob->pose->flag |= POSE_WAS_REBUILT; } -/* ********************** THE IK SOLVER ******************* */ - - - -/* allocates PoseTree, and links that to root bone/channel */ -/* Note: detecting the IK chain is duplicate code... in drawarmature.c and in transform_conversions.c */ -static void initialize_posetree(struct Object *ob, bPoseChannel *pchan_tip) -{ - bPoseChannel *curchan, *pchan_root=NULL, *chanlist[256], **oldchan; - PoseTree *tree; - PoseTarget *target; - bConstraint *con; - bKinematicConstraint *data= NULL; - int a, segcount= 0, size, newsize, *oldparent, parent; - - /* find IK constraint, and validate it */ - for(con= pchan_tip->constraints.first; con; con= con->next) { - if(con->type==CONSTRAINT_TYPE_KINEMATIC) { - data=(bKinematicConstraint*)con->data; - if (data->flag & CONSTRAINT_IK_AUTO) break; - if (data->tar==NULL) continue; - if (data->tar->type==OB_ARMATURE && data->subtarget[0]==0) continue; - if ((con->flag & CONSTRAINT_DISABLE)==0 && (con->enforce!=0.0)) break; - } - } - if(con==NULL) return; - - /* exclude tip from chain? */ - if(!(data->flag & CONSTRAINT_IK_TIP)) - pchan_tip= pchan_tip->parent; - - /* Find the chain's root & count the segments needed */ - for (curchan = pchan_tip; curchan; curchan=curchan->parent){ - pchan_root = curchan; - - curchan->flag |= POSE_CHAIN; // don't forget to clear this - chanlist[segcount]=curchan; - segcount++; - - if(segcount==data->rootbone || segcount>255) break; // 255 is weak - } - if (!segcount) return; - - /* setup the chain data */ - - /* we make tree-IK, unless all existing targets are in this chain */ - for(tree= pchan_root->iktree.first; tree; tree= tree->next) { - for(target= tree->targets.first; target; target= target->next) { - curchan= tree->pchan[target->tip]; - if(curchan->flag & POSE_CHAIN) - curchan->flag &= ~POSE_CHAIN; - else - break; - } - if(target) break; - } - - /* create a target */ - target= MEM_callocN(sizeof(PoseTarget), "posetarget"); - target->con= con; - pchan_tip->flag &= ~POSE_CHAIN; - - if(tree==NULL) { - /* make new tree */ - tree= MEM_callocN(sizeof(PoseTree), "posetree"); - - tree->iterations= data->iterations; - tree->totchannel= segcount; - tree->stretch = (data->flag & CONSTRAINT_IK_STRETCH); - - tree->pchan= MEM_callocN(segcount*sizeof(void*), "ik tree pchan"); - tree->parent= MEM_callocN(segcount*sizeof(int), "ik tree parent"); - for(a=0; a<segcount; a++) { - tree->pchan[a]= chanlist[segcount-a-1]; - tree->parent[a]= a-1; - } - target->tip= segcount-1; - - /* AND! link the tree to the root */ - BLI_addtail(&pchan_root->iktree, tree); - } - else { - tree->iterations= MAX2(data->iterations, tree->iterations); - tree->stretch= tree->stretch && !(data->flag & CONSTRAINT_IK_STRETCH); - - /* skip common pose channels and add remaining*/ - size= MIN2(segcount, tree->totchannel); - for(a=0; a<size && tree->pchan[a]==chanlist[segcount-a-1]; a++); - parent= a-1; - - segcount= segcount-a; - target->tip= tree->totchannel + segcount - 1; - - if (segcount > 0) { - /* resize array */ - newsize= tree->totchannel + segcount; - oldchan= tree->pchan; - oldparent= tree->parent; - - tree->pchan= MEM_callocN(newsize*sizeof(void*), "ik tree pchan"); - tree->parent= MEM_callocN(newsize*sizeof(int), "ik tree parent"); - memcpy(tree->pchan, oldchan, sizeof(void*)*tree->totchannel); - memcpy(tree->parent, oldparent, sizeof(int)*tree->totchannel); - MEM_freeN(oldchan); - MEM_freeN(oldparent); - - /* add new pose channels at the end, in reverse order */ - for(a=0; a<segcount; a++) { - tree->pchan[tree->totchannel+a]= chanlist[segcount-a-1]; - tree->parent[tree->totchannel+a]= tree->totchannel+a-1; - } - tree->parent[tree->totchannel]= parent; - - tree->totchannel= newsize; - } - - /* move tree to end of list, for correct evaluation order */ - BLI_remlink(&pchan_root->iktree, tree); - BLI_addtail(&pchan_root->iktree, tree); - } - - /* add target to the tree */ - BLI_addtail(&tree->targets, target); -} - -/* called from within the core where_is_pose loop, all animsystems and constraints -were executed & assigned. Now as last we do an IK pass */ -static void execute_posetree(Object *ob, PoseTree *tree) -{ - float R_parmat[3][3], identity[3][3]; - float iR_parmat[3][3]; - float R_bonemat[3][3]; - float goalrot[3][3], goalpos[3]; - float rootmat[4][4], imat[4][4]; - float goal[4][4], goalinv[4][4]; - float irest_basis[3][3], full_basis[3][3]; - float end_pose[4][4], world_pose[4][4]; - float length, basis[3][3], rest_basis[3][3], start[3], *ikstretch=NULL; - float resultinf=0.0f; - int a, flag, hasstretch=0, resultblend=0; - bPoseChannel *pchan; - IK_Segment *seg, *parent, **iktree, *iktarget; - IK_Solver *solver; - PoseTarget *target; - bKinematicConstraint *data, *poleangledata=NULL; - Bone *bone; - - if (tree->totchannel == 0) - return; - - iktree= MEM_mallocN(sizeof(void*)*tree->totchannel, "ik tree"); - - for(a=0; a<tree->totchannel; a++) { - pchan= tree->pchan[a]; - bone= pchan->bone; - - /* set DoF flag */ - flag= 0; - if(!(pchan->ikflag & BONE_IK_NO_XDOF) && !(pchan->ikflag & BONE_IK_NO_XDOF_TEMP)) - flag |= IK_XDOF; - if(!(pchan->ikflag & BONE_IK_NO_YDOF) && !(pchan->ikflag & BONE_IK_NO_YDOF_TEMP)) - flag |= IK_YDOF; - if(!(pchan->ikflag & BONE_IK_NO_ZDOF) && !(pchan->ikflag & BONE_IK_NO_ZDOF_TEMP)) - flag |= IK_ZDOF; - - if(tree->stretch && (pchan->ikstretch > 0.0)) { - flag |= IK_TRANS_YDOF; - hasstretch = 1; - } - - seg= iktree[a]= IK_CreateSegment(flag); - - /* find parent */ - if(a == 0) - parent= NULL; - else - parent= iktree[tree->parent[a]]; - - IK_SetParent(seg, parent); - - /* get the matrix that transforms from prevbone into this bone */ - Mat3CpyMat4(R_bonemat, pchan->pose_mat); - - /* gather transformations for this IK segment */ - - if (pchan->parent) - Mat3CpyMat4(R_parmat, pchan->parent->pose_mat); - else - Mat3One(R_parmat); - - /* bone offset */ - if (pchan->parent && (a > 0)) - VecSubf(start, pchan->pose_head, pchan->parent->pose_tail); - else - /* only root bone (a = 0) has no parent */ - start[0]= start[1]= start[2]= 0.0f; - - /* change length based on bone size */ - length= bone->length*VecLength(R_bonemat[1]); - - /* compute rest basis and its inverse */ - Mat3CpyMat3(rest_basis, bone->bone_mat); - Mat3CpyMat3(irest_basis, bone->bone_mat); - Mat3Transp(irest_basis); - - /* compute basis with rest_basis removed */ - Mat3Inv(iR_parmat, R_parmat); - Mat3MulMat3(full_basis, iR_parmat, R_bonemat); - Mat3MulMat3(basis, irest_basis, full_basis); - - /* basis must be pure rotation */ - Mat3Ortho(basis); - - /* transform offset into local bone space */ - Mat3Ortho(iR_parmat); - Mat3MulVecfl(iR_parmat, start); - - IK_SetTransform(seg, start, rest_basis, basis, length); - - if (pchan->ikflag & BONE_IK_XLIMIT) - IK_SetLimit(seg, IK_X, pchan->limitmin[0], pchan->limitmax[0]); - if (pchan->ikflag & BONE_IK_YLIMIT) - IK_SetLimit(seg, IK_Y, pchan->limitmin[1], pchan->limitmax[1]); - if (pchan->ikflag & BONE_IK_ZLIMIT) - IK_SetLimit(seg, IK_Z, pchan->limitmin[2], pchan->limitmax[2]); - - IK_SetStiffness(seg, IK_X, pchan->stiffness[0]); - IK_SetStiffness(seg, IK_Y, pchan->stiffness[1]); - IK_SetStiffness(seg, IK_Z, pchan->stiffness[2]); - - if(tree->stretch && (pchan->ikstretch > 0.0f)) { - float ikstretch = pchan->ikstretch*pchan->ikstretch; - IK_SetStiffness(seg, IK_TRANS_Y, MIN2(1.0f-ikstretch, 0.99f)); - IK_SetLimit(seg, IK_TRANS_Y, 0.001f, 1e10); - } - } - - solver= IK_CreateSolver(iktree[0]); - - /* set solver goals */ - - /* first set the goal inverse transform, assuming the root of tree was done ok! */ - pchan= tree->pchan[0]; - if (pchan->parent) - /* transform goal by parent mat, so this rotation is not part of the - segment's basis. otherwise rotation limits do not work on the - local transform of the segment itself. */ - Mat4CpyMat4(rootmat, pchan->parent->pose_mat); - else - Mat4One(rootmat); - VECCOPY(rootmat[3], pchan->pose_head); - - Mat4MulMat4 (imat, rootmat, ob->obmat); - Mat4Invert (goalinv, imat); - - for (target=tree->targets.first; target; target=target->next) { - float polepos[3]; - int poleconstrain= 0; - - data= (bKinematicConstraint*)target->con->data; - - /* 1.0=ctime, we pass on object for auto-ik (owner-type here is object, even though - * strictly speaking, it is a posechannel) - */ - get_constraint_target_matrix(target->con, 0, CONSTRAINT_OBTYPE_OBJECT, ob, rootmat, 1.0); - - /* and set and transform goal */ - Mat4MulMat4(goal, rootmat, goalinv); - - VECCOPY(goalpos, goal[3]); - Mat3CpyMat4(goalrot, goal); - - /* same for pole vector target */ - if(data->poletar) { - get_constraint_target_matrix(target->con, 1, CONSTRAINT_OBTYPE_OBJECT, ob, rootmat, 1.0); - - if(data->flag & CONSTRAINT_IK_SETANGLE) { - /* don't solve IK when we are setting the pole angle */ - break; - } - else { - Mat4MulMat4(goal, rootmat, goalinv); - VECCOPY(polepos, goal[3]); - poleconstrain= 1; - - /* for pole targets, we blend the result of the ik solver - * instead of the target position, otherwise we can't get - * a smooth transition */ - resultblend= 1; - resultinf= target->con->enforce; - - if(data->flag & CONSTRAINT_IK_GETANGLE) { - poleangledata= data; - data->flag &= ~CONSTRAINT_IK_GETANGLE; - } - } - } - - /* do we need blending? */ - if (!resultblend && target->con->enforce!=1.0f) { - float q1[4], q2[4], q[4]; - float fac= target->con->enforce; - float mfac= 1.0f-fac; - - pchan= tree->pchan[target->tip]; - - /* end effector in world space */ - Mat4CpyMat4(end_pose, pchan->pose_mat); - VECCOPY(end_pose[3], pchan->pose_tail); - Mat4MulSerie(world_pose, goalinv, ob->obmat, end_pose, 0, 0, 0, 0, 0); - - /* blend position */ - goalpos[0]= fac*goalpos[0] + mfac*world_pose[3][0]; - goalpos[1]= fac*goalpos[1] + mfac*world_pose[3][1]; - goalpos[2]= fac*goalpos[2] + mfac*world_pose[3][2]; - - /* blend rotation */ - Mat3ToQuat(goalrot, q1); - Mat4ToQuat(world_pose, q2); - QuatInterpol(q, q1, q2, mfac); - QuatToMat3(q, goalrot); - } - - iktarget= iktree[target->tip]; - - if(data->weight != 0.0f) { - if(poleconstrain) - IK_SolverSetPoleVectorConstraint(solver, iktarget, goalpos, - polepos, data->poleangle*(float)M_PI/180.0f, (poleangledata == data)); - IK_SolverAddGoal(solver, iktarget, goalpos, data->weight); - } - if((data->flag & CONSTRAINT_IK_ROT) && (data->orientweight != 0.0f)) - if((data->flag & CONSTRAINT_IK_AUTO)==0) - IK_SolverAddGoalOrientation(solver, iktarget, goalrot, - data->orientweight); - } - - /* solve */ - IK_Solve(solver, 0.0f, tree->iterations); - - if(poleangledata) - poleangledata->poleangle= IK_SolverGetPoleAngle(solver)*180.0f/(float)M_PI; - - IK_FreeSolver(solver); - - /* gather basis changes */ - tree->basis_change= MEM_mallocN(sizeof(float[3][3])*tree->totchannel, "ik basis change"); - if(hasstretch) - ikstretch= MEM_mallocN(sizeof(float)*tree->totchannel, "ik stretch"); - - for(a=0; a<tree->totchannel; a++) { - IK_GetBasisChange(iktree[a], tree->basis_change[a]); - - if(hasstretch) { - /* have to compensate for scaling received from parent */ - float parentstretch, stretch; - - pchan= tree->pchan[a]; - parentstretch= (tree->parent[a] >= 0)? ikstretch[tree->parent[a]]: 1.0f; - - if(tree->stretch && (pchan->ikstretch > 0.0f)) { - float trans[3], length; - - IK_GetTranslationChange(iktree[a], trans); - length= pchan->bone->length*VecLength(pchan->pose_mat[1]); - - ikstretch[a]= (length == 0.0f)? 1.0f: (trans[1]+length)/length; - } - else - ikstretch[a] = 1.0f; - - stretch= (parentstretch == 0.0f)? 1.0f: ikstretch[a]/parentstretch; - - VecMulf(tree->basis_change[a][0], stretch); - VecMulf(tree->basis_change[a][1], stretch); - VecMulf(tree->basis_change[a][2], stretch); - } - - if(resultblend && resultinf!=1.0f) { - Mat3One(identity); - Mat3BlendMat3(tree->basis_change[a], identity, - tree->basis_change[a], resultinf); - } - - IK_FreeSegment(iktree[a]); - } - - MEM_freeN(iktree); - if(ikstretch) MEM_freeN(ikstretch); -} - -void free_posetree(PoseTree *tree) -{ - BLI_freelistN(&tree->targets); - if(tree->pchan) MEM_freeN(tree->pchan); - if(tree->parent) MEM_freeN(tree->parent); - if(tree->basis_change) MEM_freeN(tree->basis_change); - MEM_freeN(tree); -} - /* ********************** THE POSE SOLVER ******************* */ @@ -2012,41 +1612,6 @@ void chan_calc_mat(bPoseChannel *chan) } } -/* transform from bone(b) to bone(b+1), store in chan_mat */ -static void make_dmats(bPoseChannel *pchan) -{ - if (pchan->parent) { - float iR_parmat[4][4]; - Mat4Invert(iR_parmat, pchan->parent->pose_mat); - Mat4MulMat4(pchan->chan_mat, pchan->pose_mat, iR_parmat); // delta mat - } - else Mat4CpyMat4(pchan->chan_mat, pchan->pose_mat); -} - -/* applies IK matrix to pchan, IK is done separated */ -/* formula: pose_mat(b) = pose_mat(b-1) * diffmat(b-1, b) * ik_mat(b) */ -/* to make this work, the diffmats have to be precalculated! Stored in chan_mat */ -static void where_is_ik_bone(bPoseChannel *pchan, float ik_mat[][3]) // nr = to detect if this is first bone -{ - float vec[3], ikmat[4][4]; - - Mat4CpyMat3(ikmat, ik_mat); - - if (pchan->parent) - Mat4MulSerie(pchan->pose_mat, pchan->parent->pose_mat, pchan->chan_mat, ikmat, NULL, NULL, NULL, NULL, NULL); - else - Mat4MulMat4(pchan->pose_mat, ikmat, pchan->chan_mat); - - /* calculate head */ - VECCOPY(pchan->pose_head, pchan->pose_mat[3]); - /* calculate tail */ - VECCOPY(vec, pchan->pose_mat[1]); - VecMulf(vec, pchan->bone->length); - VecAddf(pchan->pose_tail, pchan->pose_head, vec); - - pchan->flag |= POSE_DONE; -} - /* NLA strip modifiers */ static void do_strip_modifiers(Scene *scene, Object *armob, Bone *bone, bPoseChannel *pchan) { @@ -2172,7 +1737,7 @@ static void do_strip_modifiers(Scene *scene, Object *armob, Bone *bone, bPoseCha /* The main armature solver, does all constraints excluding IK */ /* pchan is validated, as having bone and parent pointer */ -static void where_is_pose_bone(Scene *scene, Object *ob, bPoseChannel *pchan, float ctime) +void where_is_pose_bone(Scene *scene, Object *ob, bPoseChannel *pchan, float ctime) { Bone *bone, *parbone; bPoseChannel *parchan; @@ -2312,48 +1877,27 @@ void where_is_pose (Scene *scene, Object *ob) else { Mat4Invert(ob->imat, ob->obmat); // imat is needed - /* 1. construct the PoseTrees, clear flags */ + /* 1. clear flags */ for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) { - pchan->flag &= ~(POSE_DONE|POSE_CHAIN); - if(pchan->constflag & PCHAN_HAS_IK) // flag is set on editing constraints - initialize_posetree(ob, pchan); // will attach it to root! + pchan->flag &= ~(POSE_DONE|POSE_CHAIN|POSE_IKTREE); } - - /* 2. the main loop, channels are already hierarchical sorted from root to children */ + /* 2. construct the IK tree */ + BIK_initialize_tree(scene, ob, ctime); + + /* 3. the main loop, channels are already hierarchical sorted from root to children */ for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) { - /* 3. if we find an IK root, we handle it separated */ - if(pchan->iktree.first) { - while(pchan->iktree.first) { - PoseTree *tree= pchan->iktree.first; - int a; - - /* 4. walk over the tree for regular solving */ - for(a=0; a<tree->totchannel; a++) { - if(!(tree->pchan[a]->flag & POSE_DONE)) // successive trees can set the flag - where_is_pose_bone(scene, ob, tree->pchan[a], ctime); - } - /* 5. execute the IK solver */ - execute_posetree(ob, tree); - - /* 6. apply the differences to the channels, - we need to calculate the original differences first */ - for(a=0; a<tree->totchannel; a++) - make_dmats(tree->pchan[a]); - - for(a=0; a<tree->totchannel; a++) - /* sets POSE_DONE */ - where_is_ik_bone(tree->pchan[a], tree->basis_change[a]); - - /* 7. and free */ - BLI_remlink(&pchan->iktree, tree); - free_posetree(tree); - } + /* 4. if we find an IK root, we handle it separated */ + if(pchan->flag & POSE_IKTREE) { + BIK_execute_tree(scene, ob, pchan, ctime); } + /* 5. otherwise just call the normal solver */ else if(!(pchan->flag & POSE_DONE)) { where_is_pose_bone(scene, ob, pchan, ctime); } } + /* 6. release the IK tree */ + BIK_release_tree(scene, ob, ctime); } /* calculating deform matrices */ diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c index 6c3c97399e4..115d31b587c 100644 --- a/source/blender/blenkernel/intern/brush.c +++ b/source/blender/blenkernel/intern/brush.c @@ -442,7 +442,7 @@ void brush_imbuf_new(Brush *brush, short flt, short texfall, int size, ImBuf **o dist = sqrt(xy[0]*xy[0] + xy[1]*xy[1]); VECCOPY(dstf, brush->rgb); - dstf[3]= brush->alpha*brush_curve_strength(brush, dist, maxsize); + dstf[3]= brush->alpha*brush_curve_strength_clamp(brush, dist, maxsize); } else if (texfall == 1) { brush_sample_tex(brush, xy, dstf); @@ -455,7 +455,7 @@ void brush_imbuf_new(Brush *brush, short flt, short texfall, int size, ImBuf **o dstf[0] = rgba[0]*brush->rgb[0]; dstf[1] = rgba[1]*brush->rgb[1]; dstf[2] = rgba[2]*brush->rgb[2]; - dstf[3] = rgba[3]*brush->alpha*brush_curve_strength(brush, dist, maxsize); + dstf[3] = rgba[3]*brush->alpha*brush_curve_strength_clamp(brush, dist, maxsize); } } } @@ -494,7 +494,7 @@ void brush_imbuf_new(Brush *brush, short flt, short texfall, int size, ImBuf **o dst[0] = FTOCHAR(rgba[0]*brush->rgb[0]); dst[1] = FTOCHAR(rgba[1]*brush->rgb[1]); dst[2] = FTOCHAR(rgba[2]*brush->rgb[2]); - dst[3] = FTOCHAR(rgba[3]*brush->alpha*brush_curve_strength(brush, dist, maxsize)); + dst[3] = FTOCHAR(rgba[3]*brush->alpha*brush_curve_strength_clamp(brush, dist, maxsize)); } } } @@ -952,12 +952,23 @@ int brush_painter_paint(BrushPainter *painter, BrushFunc func, float *pos, doubl } /* Uses the brush curve control to find a strength value between 0 and 1 */ +float brush_curve_strength_clamp(Brush *br, float p, const float len) +{ + if(p >= len) p= 1.0f; + else p= p/len; + + p= curvemapping_evaluateF(br->curve, 0, p); + if(p < 0.0) p= 0.0f; + else if(p > 1.0f) p= 1.0f; + return p; +} +/* same as above but can return negative values if the curve enables + * used for sculpt only */ float brush_curve_strength(Brush *br, float p, const float len) { - float f; - if(p > len) p= len; - f= curvemapping_evaluateF(br->curve, 0, p/len); - return (f > 0.0f) ? f:0.0f; + if(p >= len) p= 1.0f; + else p= p/len; + return curvemapping_evaluateF(br->curve, 0, p); } /* TODO: should probably be unified with BrushPainter stuff? */ @@ -1024,7 +1035,7 @@ static struct ImBuf *brush_gen_radial_control_imbuf(Brush *br) for(i=0; i<side; ++i) { for(j=0; j<side; ++j) { float magn= sqrt(pow(i - half, 2) + pow(j - half, 2)); - im->rect_float[i*side + j]= brush_curve_strength(br, magn, half); + im->rect_float[i*side + j]= brush_curve_strength_clamp(br, magn, half); } } diff --git a/source/blender/blenkernel/intern/collision.c b/source/blender/blenkernel/intern/collision.c index 8ef1c285370..aa4aae2422c 100644 --- a/source/blender/blenkernel/intern/collision.c +++ b/source/blender/blenkernel/intern/collision.c @@ -1296,15 +1296,15 @@ static int cloth_collision_moving ( ClothModifierData *clmd, CollisionModifierDa // return all collision objects in scene // collision object will exclude self -CollisionModifierData **get_collisionobjects(Scene *scene, Object *self, int *numcollobj) +Object **get_collisionobjects(Scene *scene, Object *self, int *numcollobj) { Base *base=NULL; - CollisionModifierData **objs = NULL; + Object **objs = NULL; Object *coll_ob = NULL; CollisionModifierData *collmd = NULL; int numobj = 0, maxobj = 100; - objs = MEM_callocN(sizeof(CollisionModifierData *)*maxobj, "CollisionObjectsArray"); + objs = MEM_callocN(sizeof(Object *)*maxobj, "CollisionObjectsArray"); // check all collision objects for ( base = scene->base.first; base; base = base->next ) { @@ -1330,16 +1330,16 @@ CollisionModifierData **get_collisionobjects(Scene *scene, Object *self, int *nu { // realloc int oldmax = maxobj; - CollisionModifierData **tmp; + Object **tmp; maxobj *= 2; - tmp = MEM_callocN(sizeof(CollisionModifierData *)*maxobj, "CollisionObjectsArray"); - memcpy(tmp, objs, sizeof(CollisionModifierData *)*oldmax); + tmp = MEM_callocN(sizeof(Object *)*maxobj, "CollisionObjectsArray"); + memcpy(tmp, objs, sizeof(Object *)*oldmax); MEM_freeN(objs); objs = tmp; } - objs[numobj] = collmd; + objs[numobj] = coll_ob; numobj++; } else @@ -1374,15 +1374,15 @@ CollisionModifierData **get_collisionobjects(Scene *scene, Object *self, int *nu { // realloc int oldmax = maxobj; - CollisionModifierData **tmp; + Object **tmp; maxobj *= 2; - tmp = MEM_callocN(sizeof(CollisionModifierData *)*maxobj, "CollisionObjectsArray"); - memcpy(tmp, objs, sizeof(CollisionModifierData *)*oldmax); + tmp = MEM_callocN(sizeof(Object *)*maxobj, "CollisionObjectsArray"); + memcpy(tmp, objs, sizeof(Object *)*oldmax); MEM_freeN(objs); objs = tmp; } - objs[numobj] = collmd; + objs[numobj] = coll_ob; numobj++; } } @@ -1459,7 +1459,7 @@ int cloth_bvh_objcollision (Object *ob, ClothModifierData * clmd, float step, fl int rounds = 0; // result counts applied collisions; ic is for debug output; ClothVertex *verts = NULL; int ret = 0, ret2 = 0; - CollisionModifierData **collobjs = NULL; + Object **collobjs = NULL; int numcollobj = 0; if ( ( clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_COLLOBJ ) || ! ( ( ( Cloth * ) clmd->clothObject )->bvhtree ) ) @@ -1498,7 +1498,8 @@ int cloth_bvh_objcollision (Object *ob, ClothModifierData * clmd, float step, fl // check all collision objects for(i = 0; i < numcollobj; i++) { - CollisionModifierData *collmd = collobjs[i]; + Object *collob= collobjs[i]; + CollisionModifierData *collmd = (CollisionModifierData*)modifiers_findByType(collob, eModifierType_Collision); BVHTreeOverlap *overlap = NULL; int result = 0; diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c index e5c0b3947de..4de6b53d26a 100644 --- a/source/blender/blenkernel/intern/constraint.c +++ b/source/blender/blenkernel/intern/constraint.c @@ -685,9 +685,17 @@ static void default_get_tarmat (bConstraint *con, bConstraintOb *cob, bConstrain ct->flag= CONSTRAINT_TAR_TEMP; \ \ if (ct->tar) { \ - if ((ct->tar->type==OB_ARMATURE) && (ct->subtarget[0])) ct->type = CONSTRAINT_OBTYPE_BONE; \ - else if (ELEM(ct->tar->type, OB_MESH, OB_LATTICE) && (ct->subtarget[0])) ct->type = CONSTRAINT_OBTYPE_VERT; \ - else ct->type = CONSTRAINT_OBTYPE_OBJECT; \ + if ((ct->tar->type==OB_ARMATURE) && (ct->subtarget[0])) { \ + bPoseChannel *pchan= get_pose_channel(ct->tar->pose, ct->subtarget); \ + ct->type = CONSTRAINT_OBTYPE_BONE; \ + ct->rotOrder= (pchan) ? (pchan->rotmode) : EULER_ORDER_DEFAULT; \ + }\ + else if (ELEM(ct->tar->type, OB_MESH, OB_LATTICE) && (ct->subtarget[0])) { \ + ct->type = CONSTRAINT_OBTYPE_VERT; \ + } \ + else {\ + ct->type = CONSTRAINT_OBTYPE_OBJECT; \ + } \ } \ \ BLI_addtail(list, ct); \ @@ -1045,6 +1053,7 @@ static void kinematic_new_data (void *cdata) data->weight= (float)1.0; data->orientweight= (float)1.0; data->iterations = 500; + data->dist= (float)1.0; data->flag= CONSTRAINT_IK_TIP|CONSTRAINT_IK_STRETCH|CONSTRAINT_IK_POS; } @@ -1180,7 +1189,10 @@ static void followpath_get_tarmat (bConstraint *con, bConstraintOb *cob, bConstr if (cu->path && cu->path->data) { if ((data->followflag & FOLLOWPATH_STATIC) == 0) { /* animated position along curve depending on time */ - curvetime= bsystem_time(cob->scene, ct->tar, ctime, 0.0) - data->offset; + if (cob->scene) + curvetime= bsystem_time(cob->scene, ct->tar, ctime, 0.0) - data->offset; + else + curvetime= ctime - data->offset; /* ctime is now a proper var setting of Curve which gets set by Animato like any other var that's animated, * but this will only work if it actually is animated... @@ -1580,7 +1592,8 @@ static void rotlike_evaluate (bConstraint *con, bConstraintOb *cob, ListBase *ta VECCOPY(loc, cob->matrix[3]); Mat4ToSize(cob->matrix, size); - Mat4ToEulO(ct->matrix, eul, ct->rotOrder); + /* to allow compatible rotations, must get both rotations in the order of the owner... */ + Mat4ToEulO(ct->matrix, eul, cob->rotOrder); Mat4ToEulO(cob->matrix, obeul, cob->rotOrder); if ((data->flag & ROTLIKE_X)==0) @@ -3631,7 +3644,7 @@ void solve_constraints (ListBase *conlist, bConstraintOb *cob, float ctime) /* these we can skip completely (invalid constraints...) */ if (cti == NULL) continue; - if (con->flag & CONSTRAINT_DISABLE) continue; + if (con->flag & (CONSTRAINT_DISABLE|CONSTRAINT_OFF)) continue; /* these constraints can't be evaluated anyway */ if (cti->evaluate_constraint == NULL) continue; /* influence == 0 should be ignored */ diff --git a/source/blender/blenkernel/intern/effect.c b/source/blender/blenkernel/intern/effect.c index e3c4f12184e..acf906e3163 100644 --- a/source/blender/blenkernel/intern/effect.c +++ b/source/blender/blenkernel/intern/effect.c @@ -258,10 +258,10 @@ static void eff_tri_ray_hit(void *userdata, int index, const BVHTreeRay *ray, BV // get visibility of a wind ray static float eff_calc_visibility(Scene *scene, Object *ob, float *co, float *dir) { - CollisionModifierData **collobjs = NULL; + Object **collobjs = NULL; int numcollobj = 0, i; float norm[3], len = 0.0; - float visibility = 1.0; + float visibility = 1.0, absorption = 0.0; collobjs = get_collisionobjects(scene, ob, &numcollobj); @@ -275,7 +275,8 @@ static float eff_calc_visibility(Scene *scene, Object *ob, float *co, float *dir // check all collision objects for(i = 0; i < numcollobj; i++) { - CollisionModifierData *collmd = collobjs[i]; + Object *collob= collobjs[i]; + CollisionModifierData *collmd = (CollisionModifierData*)modifiers_findByType(collob, eModifierType_Collision); if(collmd->bvhtree) { @@ -287,8 +288,10 @@ static float eff_calc_visibility(Scene *scene, Object *ob, float *co, float *dir // check if the way is blocked if(BLI_bvhtree_ray_cast(collmd->bvhtree, co, norm, 0.0f, &hit, eff_tri_ray_hit, NULL)>=0) { + absorption= (collob->pd)? collob->pd->absorption: 0.0f; + // visibility is only between 0 and 1, calculated from 1-absorption - visibility *= MAX2(0.0, MIN2(1.0, (1.0-((float)collmd->absorption)*0.01))); + visibility *= CLAMPIS(1.0f-absorption, 0.0f, 1.0f); if(visibility <= 0.0f) break; diff --git a/source/blender/blenkernel/intern/fcurve.c b/source/blender/blenkernel/intern/fcurve.c index f7f79e9772f..0ecd1fe912b 100644 --- a/source/blender/blenkernel/intern/fcurve.c +++ b/source/blender/blenkernel/intern/fcurve.c @@ -200,6 +200,85 @@ FCurve *list_find_fcurve (ListBase *list, const char rna_path[], const int array return NULL; } +/* threshold for binary-searching keyframes - threshold here should be good enough for now, but should become userpref */ +#define BEZT_BINARYSEARCH_THRESH 0.00001f + +/* Binary search algorithm for finding where to insert BezTriple. (for use by insert_bezt_fcurve) + * Returns the index to insert at (data already at that index will be offset if replace is 0) + */ +int binarysearch_bezt_index (BezTriple array[], float frame, int arraylen, short *replace) +{ + int start=0, end=arraylen; + int loopbreaker= 0, maxloop= arraylen * 2; + + /* initialise replace-flag first */ + *replace= 0; + + /* sneaky optimisations (don't go through searching process if...): + * - keyframe to be added is to be added out of current bounds + * - keyframe to be added would replace one of the existing ones on bounds + */ + if ((arraylen <= 0) || (array == NULL)) { + printf("Warning: binarysearch_bezt_index() encountered invalid array \n"); + return 0; + } + else { + /* check whether to add before/after/on */ + float framenum; + + /* 'First' Keyframe (when only one keyframe, this case is used) */ + framenum= array[0].vec[1][0]; + if (IS_EQT(frame, framenum, BEZT_BINARYSEARCH_THRESH)) { + *replace = 1; + return 0; + } + else if (frame < framenum) + return 0; + + /* 'Last' Keyframe */ + framenum= array[(arraylen-1)].vec[1][0]; + if (IS_EQT(frame, framenum, BEZT_BINARYSEARCH_THRESH)) { + *replace= 1; + return (arraylen - 1); + } + else if (frame > framenum) + return arraylen; + } + + + /* most of the time, this loop is just to find where to put it + * 'loopbreaker' is just here to prevent infinite loops + */ + for (loopbreaker=0; (start <= end) && (loopbreaker < maxloop); loopbreaker++) { + /* compute and get midpoint */ + int mid = start + ((end - start) / 2); /* we calculate the midpoint this way to avoid int overflows... */ + float midfra= array[mid].vec[1][0]; + + /* check if exactly equal to midpoint */ + if (IS_EQT(frame, midfra, BEZT_BINARYSEARCH_THRESH)) { + *replace = 1; + return mid; + } + + /* repeat in upper/lower half */ + if (frame > midfra) + start= mid + 1; + else if (frame < midfra) + end= mid - 1; + } + + /* print error if loop-limit exceeded */ + if (loopbreaker == (maxloop-1)) { + printf("Error: binarysearch_bezt_index() was taking too long \n"); + + // include debug info + printf("\tround = %d: start = %d, end = %d, arraylen = %d \n", loopbreaker, start, end, arraylen); + } + + /* not found, so return where to place it */ + return start; +} + /* Calculate the extents of F-Curve's data */ void calc_fcurve_bounds (FCurve *fcu, float *xmin, float *xmax, float *ymin, float *ymax) { diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c index e955f10f3e3..9953540bbcf 100644 --- a/source/blender/blenkernel/intern/image.c +++ b/source/blender/blenkernel/intern/image.c @@ -2175,3 +2175,103 @@ void BKE_image_user_calc_imanr(ImageUser *iuser, int cfra, int fieldnr) } } +/* + Produce image export path. + + Fails returning 0 if image filename is empty or if destination path + matches image path (i.e. both are the same file). + + Trailing slash in dest_dir is optional. + + Logic: + + - if an image is "below" current .blend file directory, rebuild the + same dir structure in dest_dir + + For example //textures/foo/bar.png becomes + [dest_dir]/textures/foo/bar.png. + + - if an image is not "below" current .blend file directory, + disregard it's path and copy it in the same directory where 3D file + goes. + + For example //../foo/bar.png becomes [dest_dir]/bar.png. + + This logic will help ensure that all image paths are relative and + that a user gets his images in one place. It'll also provide + consistent behaviour across exporters. + */ +int BKE_get_image_export_path(struct Image *im, const char *dest_dir, char *abs, int abs_size, char *rel, int rel_size) +{ + char path[FILE_MAX]; + char dir[FILE_MAX]; + char base[FILE_MAX]; + char blend_dir[FILE_MAX]; /* directory, where current .blend file resides */ + char dest_path[FILE_MAX]; + char rel_dir[FILE_MAX]; + int len; + + if (abs) + abs[0]= 0; + + if (rel) + rel[0]= 0; + + BLI_split_dirfile_basic(G.sce, blend_dir, NULL); + + if (!strlen(im->name)) { + if (G.f & G_DEBUG) printf("Invalid image type.\n"); + return 0; + } + + BLI_strncpy(path, im->name, sizeof(path)); + + /* expand "//" in filename and get absolute path */ + BLI_convertstringcode(path, G.sce); + + /* get the directory part */ + BLI_split_dirfile_basic(path, dir, base); + + len= strlen(blend_dir); + + rel_dir[0] = 0; + + /* if image is "below" current .blend file directory */ + if (!strncmp(path, blend_dir, len)) { + + /* if image is _in_ current .blend file directory */ + if (!strcmp(dir, blend_dir)) { + BLI_join_dirfile(dest_path, dest_dir, base); + } + /* "below" */ + else { + /* rel = image_path_dir - blend_dir */ + BLI_strncpy(rel_dir, dir + len, sizeof(rel_dir)); + + BLI_join_dirfile(dest_path, dest_dir, rel_dir); + BLI_join_dirfile(dest_path, dest_path, base); + } + + } + /* image is out of current directory */ + else { + BLI_join_dirfile(dest_path, dest_dir, base); + } + + if (abs) + BLI_strncpy(abs, dest_path, abs_size); + + if (rel) { + strncat(rel, rel_dir, rel_size); + strncat(rel, base, rel_size); + } + + /* return 2 if src=dest */ + if (!strcmp(path, dest_path)) { + if (G.f & G_DEBUG) printf("%s and %s are the same file\n", path, dest_path); + return 2; + } + + return 1; +} + diff --git a/source/blender/blenkernel/intern/ipo.c b/source/blender/blenkernel/intern/ipo.c index 62f44d92d25..dd7904b4782 100644 --- a/source/blender/blenkernel/intern/ipo.c +++ b/source/blender/blenkernel/intern/ipo.c @@ -1214,6 +1214,9 @@ static void icu_to_fcurves (ListBase *groups, ListBase *list, IpoCurve *icu, cha /* interpolation can only be constant... */ dst->ipo= BEZT_IPO_CONST; + /* 'hide' flag is now used for keytype - only 'keyframes' existed before */ + dst->hide= BEZT_KEYTYPE_KEYFRAME; + /* correct values, by checking if the flag of interest is set */ if ( ((int)(dst->vec[1][1])) & (abp->bit) ) dst->vec[0][1]= dst->vec[1][1]= dst->vec[2][1] = 1.0f; @@ -1264,6 +1267,9 @@ static void icu_to_fcurves (ListBase *groups, ListBase *list, IpoCurve *icu, cha if (icu->ipo != IPO_MIXED) dst->ipo= icu->ipo; + /* 'hide' flag is now used for keytype - only 'keyframes' existed before */ + dst->hide= BEZT_KEYTYPE_KEYFRAME; + /* correct values for euler rotation curves - they were degrees/10 */ // XXX for now, just make them into radians as RNA sets/reads directly in that form if ( ((icu->blocktype == ID_OB) && ELEM3(icu->adrcode, OB_ROT_X, OB_ROT_Y, OB_ROT_Z)) || diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c index c92eda6d169..431543f8dbd 100644 --- a/source/blender/blenkernel/intern/mesh.c +++ b/source/blender/blenkernel/intern/mesh.c @@ -542,7 +542,8 @@ void set_mesh(Object *ob, Mesh *me) if(ob->type==OB_MESH) { old= ob->data; - old->id.us--; + if (old) + old->id.us--; ob->data= me; id_us_plus((ID *)me); } diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c index 35514e9697e..c98e2d5970b 100644 --- a/source/blender/blenkernel/intern/object.c +++ b/source/blender/blenkernel/intern/object.c @@ -1553,13 +1553,11 @@ float bsystem_time(struct Scene *scene, Object *ob, float cfra, float ofs) cfra+= bluroffs+fieldoffs; /* global time */ - cfra*= scene->r.framelen; + if (scene) + cfra*= scene->r.framelen; #if 0 // XXX old animation system if (ob) { - if (no_speed_curve==0 && ob->ipo) - cfra= calc_ipo_time(ob->ipo, cfra); - /* ofset frames */ if ((ob->ipoflag & OB_OFFS_PARENT) && (ob->partype & PARSLOW)==0) cfra-= give_timeoffset(ob); @@ -1574,29 +1572,22 @@ float bsystem_time(struct Scene *scene, Object *ob, float cfra, float ofs) void object_scale_to_mat3(Object *ob, float mat[][3]) { float vec[3]; - if(ob->ipo) { - vec[0]= ob->size[0]+ob->dsize[0]; - vec[1]= ob->size[1]+ob->dsize[1]; - vec[2]= ob->size[2]+ob->dsize[2]; - SizeToMat3(vec, mat); - } - else { - SizeToMat3(ob->size, mat); - } + + vec[0]= ob->size[0]+ob->dsize[0]; + vec[1]= ob->size[1]+ob->dsize[1]; + vec[2]= ob->size[2]+ob->dsize[2]; + SizeToMat3(vec, mat); } +// TODO: this should take rotation orders into account later... void object_rot_to_mat3(Object *ob, float mat[][3]) { float vec[3]; - if(ob->ipo) { - vec[0]= ob->rot[0]+ob->drot[0]; - vec[1]= ob->rot[1]+ob->drot[1]; - vec[2]= ob->rot[2]+ob->drot[2]; - EulToMat3(vec, mat); - } - else { - EulToMat3(ob->rot, mat); - } + + vec[0]= ob->rot[0]+ob->drot[0]; + vec[1]= ob->rot[1]+ob->drot[1]; + vec[2]= ob->rot[2]+ob->drot[2]; + EulToMat3(vec, mat); } void object_to_mat3(Object *ob, float mat[][3]) /* no parent */ @@ -1611,13 +1602,8 @@ void object_to_mat3(Object *ob, float mat[][3]) /* no parent */ /* rot */ /* Quats arnt used yet */ /*if(ob->transflag & OB_QUAT) { - if(ob->ipo) { - QuatMul(q1, ob->quat, ob->dquat); - QuatToMat3(q1, rmat); - } - else { - QuatToMat3(ob->quat, rmat); - } + QuatMul(q1, ob->quat, ob->dquat); + QuatToMat3(q1, rmat); } else {*/ object_rot_to_mat3(ob, rmat); @@ -1633,12 +1619,9 @@ void object_to_mat4(Object *ob, float mat[][4]) Mat4CpyMat3(mat, tmat); - VECCOPY(mat[3], ob->loc); - if(ob->ipo) { - mat[3][0]+= ob->dloc[0]; - mat[3][1]+= ob->dloc[1]; - mat[3][2]+= ob->dloc[2]; - } + mat[3][0]= ob->loc[0] + ob->dloc[0]; + mat[3][1]= ob->loc[1] + ob->dloc[1]; + mat[3][2]= ob->loc[2] + ob->dloc[2]; } int enable_cu_speed= 1; diff --git a/source/blender/blenkernel/intern/pointcache.c b/source/blender/blenkernel/intern/pointcache.c index dfc5b4cd770..3915a6901a0 100644 --- a/source/blender/blenkernel/intern/pointcache.c +++ b/source/blender/blenkernel/intern/pointcache.c @@ -56,15 +56,23 @@ #include "BKE_smoke.h" #include "BKE_softbody.h" #include "BKE_utildefines.h" +#include "BIK_api.h" #include "BLI_blenlib.h" /* both in intern */ #include "smoke_API.h" + +#ifdef WITH_LZO #include "minilzo.h" +#else +/* used for non-lzo cases */ +#define LZO_OUT_LEN(size) ((size) + (size) / 16 + 64 + 3) +#endif +#ifdef WITH_LZMA #include "LzmaLib.h" - +#endif /* needed for directory lookup */ /* untitled blend's need getpid for a unique name */ @@ -624,20 +632,25 @@ static int ptcache_file_write(PTCacheFile *pf, void *f, size_t tot, int size); static int ptcache_compress_write(PTCacheFile *pf, unsigned char *in, unsigned int in_len, unsigned char *out, int mode) { int r = 0; - unsigned char compressed; - LZO_HEAP_ALLOC(wrkmem, LZO1X_MEM_COMPRESS); - unsigned int out_len = LZO_OUT_LEN(in_len); + unsigned char compressed = 0; + unsigned int out_len= 0; unsigned char *props = MEM_callocN(16*sizeof(char), "tmp"); size_t sizeOfIt = 5; +#ifdef WITH_LZO + out_len= LZO_OUT_LEN(in_len); if(mode == 1) { + LZO_HEAP_ALLOC(wrkmem, LZO1X_MEM_COMPRESS); + r = lzo1x_1_compress(in, (lzo_uint)in_len, out, (lzo_uint *)&out_len, wrkmem); if (!(r == LZO_E_OK) || (out_len >= in_len)) compressed = 0; else compressed = 1; } - else if(mode == 2) { +#endif +#ifdef WITH_LZMA + if(mode == 2) { r = LzmaCompress(out, (size_t *)&out_len, in, in_len,//assume sizeof(char)==1.... props, &sizeOfIt, 5, 1 << 24, 3, 0, 2, 32, 2); @@ -647,7 +660,8 @@ static int ptcache_compress_write(PTCacheFile *pf, unsigned char *in, unsigned i else compressed = 2; } - +#endif + ptcache_file_write(pf, &compressed, 1, sizeof(unsigned char)); if(compressed) { ptcache_file_write(pf, &out_len, 1, sizeof(unsigned int)); @@ -761,16 +775,19 @@ static int ptcache_compress_read(PTCacheFile *pf, unsigned char *result, unsigne in = (unsigned char *)MEM_callocN(sizeof(unsigned char)*in_len, "pointcache_compressed_buffer"); ptcache_file_read(pf, in, in_len, sizeof(unsigned char)); +#ifdef WITH_LZO if(compressed == 1) r = lzo1x_decompress(in, (lzo_uint)in_len, result, (lzo_uint *)&out_len, NULL); - else if(compressed == 2) +#endif +#ifdef WITH_LZMA + if(compressed == 2) { size_t leni = in_len, leno = out_len; ptcache_file_read(pf, &sizeOfIt, 1, sizeof(unsigned int)); ptcache_file_read(pf, props, sizeOfIt, sizeof(unsigned char)); r = LzmaUncompress(result, &leno, in, &leni, props, sizeOfIt); } - +#endif MEM_freeN(in); } else { @@ -2007,6 +2024,9 @@ int BKE_ptcache_object_reset(Scene *scene, Object *ob, int mode) } } + if (ob->type == OB_ARMATURE) + BIK_clear_cache(ob->pose); + return reset; } diff --git a/source/blender/blenkernel/intern/report.c b/source/blender/blenkernel/intern/report.c index 391adfb762a..e524359d2bc 100644 --- a/source/blender/blenkernel/intern/report.c +++ b/source/blender/blenkernel/intern/report.c @@ -230,7 +230,7 @@ char *BKE_reports_string(ReportList *reports, ReportType level) DynStr *ds; char *cstring; - if(!reports) + if(!reports || !reports->list.first) return NULL; ds= BLI_dynstr_new(); diff --git a/source/blender/blenkernel/intern/sca.c b/source/blender/blenkernel/intern/sca.c index de2118af202..5cd554725ff 100644 --- a/source/blender/blenkernel/intern/sca.c +++ b/source/blender/blenkernel/intern/sca.c @@ -128,6 +128,9 @@ void init_sensor(bSensor *sens) case SENS_PROPERTY: sens->data= MEM_callocN(sizeof(bPropertySensor), "propsens"); break; + case SENS_ARMATURE: + sens->data= MEM_callocN(sizeof(bArmatureSensor), "armsens"); + break; case SENS_ACTUATOR: sens->data= MEM_callocN(sizeof(bActuatorSensor), "actsens"); break; @@ -455,6 +458,9 @@ void init_actuator(bActuator *act) case ACT_STATE: act->data = MEM_callocN(sizeof( bStateActuator ), "state act"); break; + case ACT_ARMATURE: + act->data = MEM_callocN(sizeof( bArmatureActuator ), "armature act"); + break; default: ; /* this is very severe... I cannot make any memory for this */ /* logic brick... */ @@ -596,6 +602,8 @@ void sca_remove_ob_poin(Object *obt, Object *ob) bEditObjectActuator *eoa; bPropertyActuator *pa; bMessageActuator *ma; + bParentActuator *para; + bArmatureActuator *aa; sens= obt->sensors.first; while(sens) { @@ -634,7 +642,15 @@ void sca_remove_ob_poin(Object *obt, Object *ob) ma= act->data; if(ma->toObject==ob) ma->toObject= NULL; break; - + case ACT_PARENT: + para = act->data; + if (para->ob==ob) para->ob = NULL; + break; + case ACT_ARMATURE: + aa = act->data; + if (aa->target == ob) aa->target = NULL; + if (aa->subtarget == ob) aa->subtarget = NULL; + break; } act= act->next; } diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c index 115a69f77c7..f3490446eff 100644 --- a/source/blender/blenkernel/intern/scene.c +++ b/source/blender/blenkernel/intern/scene.c @@ -421,7 +421,11 @@ Scene *add_scene(char *name) pset->brush[PE_BRUSH_CUT].strength= 100; sce->jumpframe = 10; - sce->r.audio.mixrate = 44100; + sce->r.ffcodecdata.audio_mixrate = 44100; + + sce->audio.distance_model = 2.0; + sce->audio.doppler_factor = 1.0; + sce->audio.speed_of_sound = 343.3; strcpy(sce->r.backbuf, "//backbuf"); strcpy(sce->r.pic, U.renderdir); diff --git a/source/blender/blenkernel/intern/sound.c b/source/blender/blenkernel/intern/sound.c index 2d5d8dad7a8..6ac9b020f21 100644 --- a/source/blender/blenkernel/intern/sound.c +++ b/source/blender/blenkernel/intern/sound.c @@ -340,7 +340,7 @@ void sound_update_playing(struct bContext *C) for(handle = scene->sound_handles.first; handle; handle = handle->next) { - if(cfra < handle->startframe || cfra >= handle->endframe || handle->mute) + if(cfra < handle->startframe || cfra >= handle->endframe || handle->mute || (scene->audio.flag & AUDIO_MUTE)) { if(handle->state == AUD_STATUS_PLAYING) { @@ -421,7 +421,7 @@ void sound_scrub(struct bContext *C) int cfra = CFRA; float fps = FPS; - if(scene->r.audio.flag & AUDIO_SCRUB && !CTX_wm_screen(C)->animtimer) + if(scene->audio.flag & AUDIO_SCRUB && !CTX_wm_screen(C)->animtimer) { AUD_lock(); @@ -443,7 +443,7 @@ void sound_scrub(struct bContext *C) } } -AUD_Device* sound_mixdown(struct Scene *scene, AUD_Specs specs, int start, int end) +AUD_Device* sound_mixdown(struct Scene *scene, AUD_Specs specs, int start, int end, float volume) { AUD_Device* mixdown = AUD_openReadDevice(specs); SoundHandle *handle; @@ -453,6 +453,8 @@ AUD_Device* sound_mixdown(struct Scene *scene, AUD_Specs specs, int start, int e end++; + AUD_setDeviceVolume(mixdown, volume); + for(handle = scene->sound_handles.first; handle; handle = handle->next) { if(start < handle->endframe && end > handle->startframe && !handle->mute && handle->source && handle->source->handle) diff --git a/source/blender/blenkernel/intern/text.c b/source/blender/blenkernel/intern/text.c index 270cd873ff5..8bf0f6b8bdf 100644 --- a/source/blender/blenkernel/intern/text.c +++ b/source/blender/blenkernel/intern/text.c @@ -2832,3 +2832,60 @@ TextMarker *txt_next_marker(Text *text, TextMarker *marker) { } return NULL; /* Only if marker==NULL */ } + + +/*******************************/ +/* Character utility functions */ +/*******************************/ + +int text_check_bracket(char ch) +{ + int a; + char opens[] = "([{"; + char close[] = ")]}"; + + for(a=0; a<(sizeof(opens)-1); a++) { + if(ch==opens[a]) + return a+1; + else if(ch==close[a]) + return -(a+1); + } + return 0; +} + +int text_check_delim(char ch) +{ + int a; + char delims[] = "():\"\' ~!%^&*-+=[]{};/<>|.#\t,"; + + for(a=0; a<(sizeof(delims)-1); a++) { + if(ch==delims[a]) + return 1; + } + return 0; +} + +int text_check_digit(char ch) +{ + if(ch < '0') return 0; + if(ch <= '9') return 1; + return 0; +} + +int text_check_identifier(char ch) +{ + if(ch < '0') return 0; + if(ch <= '9') return 1; + if(ch < 'A') return 0; + if(ch <= 'Z' || ch == '_') return 1; + if(ch < 'a') return 0; + if(ch <= 'z') return 1; + return 0; +} + +int text_check_whitespace(char ch) +{ + if(ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n') + return 1; + return 0; +} diff --git a/source/blender/blenkernel/intern/unit.c b/source/blender/blenkernel/intern/unit.c index f8e3b3c5ad2..1f72c894cc8 100644 --- a/source/blender/blenkernel/intern/unit.c +++ b/source/blender/blenkernel/intern/unit.c @@ -75,7 +75,7 @@ static struct bUnitCollection buDummyCollecton = {buDummyDef, 0, 0, sizeof(buDum /* Lengths */ static struct bUnitDef buMetricLenDef[] = { {"kilometer", "kilometers", "km", NULL, "Kilometers", 1000.0, 0.0, B_UNIT_DEF_NONE}, - {"hectometer", "hectometers", "hm", NULL, "10 Meters", 100.0, 0.0, B_UNIT_DEF_SUPPRESS}, + {"hectometer", "hectometers", "hm", NULL, "100 Meters", 100.0, 0.0, B_UNIT_DEF_SUPPRESS}, {"dekameter", "dekameters", "dkm",NULL, "10 Meters", 10.0, 0.0, B_UNIT_DEF_SUPPRESS}, {"meter", "meters", "m", NULL, "Meters", 1.0, 0.0, B_UNIT_DEF_NONE}, /* base unit */ {"decimetre", "decimetres", "dm", NULL, "10 Centimeters", 0.1, 0.0, B_UNIT_DEF_SUPPRESS}, @@ -485,7 +485,7 @@ int bUnit_ReplaceString(char *str, int len_max, char *str_prev, double scale_pre if(unit==NULL) unit= unit_default(usys); - /* add the unit prefic and re-run, use brackets incase there was an expression given */ + /* add the unit prefix and re-run, use brackets incase there was an expression given */ if(snprintf(str_tmp, sizeof(str_tmp), "(%s)%s", str, unit->name) < sizeof(str_tmp)) { strncpy(str, str_tmp, len_max); return bUnit_ReplaceString(str, len_max, NULL, scale_pref, system, type); diff --git a/source/blender/blenkernel/intern/writeffmpeg.c b/source/blender/blenkernel/intern/writeffmpeg.c index a90924055b3..1953058fddf 100644 --- a/source/blender/blenkernel/intern/writeffmpeg.c +++ b/source/blender/blenkernel/intern/writeffmpeg.c @@ -559,7 +559,7 @@ static AVStream* alloc_audio_stream(RenderData *rd, int codec_id, AVFormatContex c->codec_id = codec_id; c->codec_type = CODEC_TYPE_AUDIO; - c->sample_rate = rd->audio.mixrate; + c->sample_rate = rd->ffcodecdata.audio_mixrate; c->bit_rate = ffmpeg_audio_bitrate*1000; c->channels = 2; codec = avcodec_find_encoder(c->codec_id); @@ -734,7 +734,7 @@ static void start_ffmpeg_impl(struct RenderData *rd, int rectx, int recty) if (ffmpeg_type == FFMPEG_DV) { fmt->audio_codec = CODEC_ID_PCM_S16LE; - if (ffmpeg_multiplex_audio && rd->audio.mixrate != 48000) { + if (ffmpeg_multiplex_audio && rd->ffcodecdata.audio_mixrate != 48000) { G.afbreek = 1; //XXX error("FFMPEG only supports 48khz / stereo " // "audio for DV!"); @@ -831,7 +831,6 @@ static void makeffmpegstring(RenderData* rd, char* string) { } } - void start_ffmpeg(struct Scene *scene, RenderData *rd, int rectx, int recty) { ffmpeg_autosplit_count = 0; @@ -844,8 +843,8 @@ void start_ffmpeg(struct Scene *scene, RenderData *rd, int rectx, int recty) AUD_Specs specs; specs.channels = c->channels; specs.format = AUD_FORMAT_S16; - specs.rate = rd->audio.mixrate; - audio_mixdown_device = sound_mixdown(scene, specs, rd->sfra, rd->efra); + specs.rate = rd->ffcodecdata.audio_mixrate; + audio_mixdown_device = sound_mixdown(scene, specs, rd->sfra, rd->efra, rd->ffcodecdata.audio_volume); } } diff --git a/source/blender/blenlib/BLI_bfile.h b/source/blender/blenlib/BLI_bfile.h new file mode 100644 index 00000000000..92543558a19 --- /dev/null +++ b/source/blender/blenlib/BLI_bfile.h @@ -0,0 +1,138 @@ +/* + * $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) 2009 by Stichting Blender Foundation. + * All rights reserved. + * + * ***** END GPL LICENSE BLOCK ***** + * BFILE* based abstraction of file access. + */ + +#ifndef BLI_BFILE_H +#define BLI_BFILE_H + +/* For fopen's FILE */ +#include <stdio.h> + +/** + Defines for the bflags param. + */ +/* Special handling: */ +/* For "symmetry" of flags */ +#define BFILE_NORMAL (0) +/* No supervision, just translate // if needed, RISKY */ +#define BFILE_RAW (1<<0) +/* Path is relative to config dirs */ +#define BFILE_CONFIG (1<<1) +/* Path is for current session temp file */ +#define BFILE_TEMP (1<<2) + +/* Config handling, special cases: */ +#define BFILE_USERONLY (1<<3) +#define BFILE_SYSONLY (1<<4) + +/* Compression to apply on close: */ +#define BFILE_GZIP (1<<5) + +/** + File descriptor for Blender abstracted file access. + */ +typedef struct { + FILE *stream; + int fd; + + /* Anything below should not be touched directly */ + int uflags; /* Special options requested by upper level, copy of bflags */ + char *fpath; /* Final/requested path name */ + char *tpath; /* Temp path name if applicable */ + int type; /* Own flags, common classification of open and fopen */ + int error; /* An op caused an error, unsafe to replace older files */ +} BFILE; + +/** + Open a BFILE* with fopen()-like syntax. + */ +BFILE *BLI_bfile_fopen(const char *path, const char *mode, int bflags); + +/** + Open a BFILE* with open()-like syntax. + */ +BFILE *BLI_bfile_open(const char *pathname, int flags, int bflags); + +/** + Get the FILE* associated with the BFILE*. + */ +FILE *BLI_bfile_file_from_bfile(BFILE *bfile); + +/** + Get the fd associated with the BFILE*. + */ +int BLI_bfile_fd_from_bfile(BFILE *bfile); + +/** + write()-like using BFILE*. + */ +ssize_t BLI_bfile_write(BFILE *f, const void *buf, size_t count); + +/** + read()-like using BFILE*. + */ +ssize_t BLI_bfile_read(BFILE *f, void *buf, size_t count); + +/** + fwrite()-like using BFILE*. + */ +size_t BLI_bfile_fwrite(const void *ptr, size_t size, size_t nmemb, BFILE *f); + +/** + fread()-like using BFILE*. + */ +size_t BLI_bfile_fread(void *ptr, size_t size, size_t nmemb, BFILE *f); + +/** + Close a BFILE, to match close() and fclose(). + */ +void BLI_bfile_close(BFILE *bfile); + +/** + Clear error status. + Call it only if the error has been really handled. + */ +void BLI_bfile_clear_error(BFILE *bfile); + +/** + Set the error status. + Call it to mark writing by a 3rd party failed (libjpeg reported error, ie). + */ +void BLI_bfile_set_error(BFILE *bfile, int error); + +/* +TODO +Maybe also provide more OS/libc things like: +fflush +fprintf and related +fscanf +fgetc/fputc and related +fseek and related + +Probably good to do: +readdir (compacted list showing all files for a "directory" (user versions on top of system's)) +*/ + +#endif /* ifndef BLI_BFILE_H */ diff --git a/source/blender/blenlib/BLI_ghash.h b/source/blender/blenlib/BLI_ghash.h index c77e82f0a2b..c9a8b1b841f 100644 --- a/source/blender/blenlib/BLI_ghash.h +++ b/source/blender/blenlib/BLI_ghash.h @@ -32,6 +32,10 @@ #ifndef BLI_GHASH_H #define BLI_GHASH_H +#ifdef __cplusplus +extern "C" { +#endif + struct GHash; typedef struct GHash GHash; @@ -125,5 +129,9 @@ int BLI_ghashutil_strcmp (void *a, void *b); unsigned int BLI_ghashutil_inthash (void *ptr); int BLI_ghashutil_intcmp(void *a, void *b); +#ifdef __cplusplus +} +#endif + #endif diff --git a/source/blender/blenlib/BLI_util.h b/source/blender/blenlib/BLI_util.h index f9a84e071e7..1ce7a8cdb77 100644 --- a/source/blender/blenlib/BLI_util.h +++ b/source/blender/blenlib/BLI_util.h @@ -42,7 +42,14 @@ struct ListBase; struct direntry; char *BLI_gethome(void); -char *BLI_gethome_folder(char *folder_name); +char *BLI_gethome_folder(char *folder_name, int flag); + +/* BLI_gethome_folder flag */ +#define BLI_GETHOME_LOCAL 1<<1 /* relative location for portable binaries */ +#define BLI_GETHOME_SYSTEM 1<<2 /* system location, or set from the BLENDERPATH env variable (UNIX only) */ +#define BLI_GETHOME_USER 1<<3 /* home folder ~/.blender */ +#define BLI_GETHOME_ALL (BLI_GETHOME_SYSTEM|BLI_GETHOME_LOCAL|BLI_GETHOME_USER) + void BLI_setenv(const char *env, const char *val); void BLI_make_file_string(const char *relabase, char *string, const char *dir, const char *file); diff --git a/source/blender/blenlib/BLI_winstuff.h b/source/blender/blenlib/BLI_winstuff.h index b46ebebacd5..757b3605203 100644 --- a/source/blender/blenlib/BLI_winstuff.h +++ b/source/blender/blenlib/BLI_winstuff.h @@ -28,7 +28,13 @@ * * ***** END GPL LICENSE BLOCK ***** */ + +#ifndef __WINSTUFF_H__ +#define __WINSTUFF_H__ + +#ifndef FREE_WINDOWS #pragma warning(once: 4761 4305 4244 4018) +#endif #define WIN32_LEAN_AND_MEAN @@ -56,10 +62,7 @@ #undef small -#ifndef __WINSTUFF_H__ -#define __WINSTUFF_H__ - - // These definitions are also in arithb for simplicity +// These definitions are also in arithb for simplicity #ifdef __cplusplus extern "C" { @@ -91,6 +94,16 @@ extern "C" { typedef unsigned int mode_t; #endif +/* mingw using _SSIZE_T_ to declare ssize_t type */ +#ifndef _SSIZE_T_ +#define _SSIZE_T_ +/* python uses HAVE_SSIZE_T */ +#ifndef HAVE_SSIZE_T +#define HAVE_SSIZE_T 1 +typedef long ssize_t; +#endif +#endif + struct dirent { int d_ino; int d_off; diff --git a/source/blender/blenlib/intern/BLI_bfile.c b/source/blender/blenlib/intern/BLI_bfile.c new file mode 100644 index 00000000000..a7ce1df5712 --- /dev/null +++ b/source/blender/blenlib/intern/BLI_bfile.c @@ -0,0 +1,236 @@ +/* + * $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) 2009 by Stichting Blender Foundation. + * All rights reserved. + * + * ***** END GPL LICENSE BLOCK ***** + * BFILE* based abstraction for file access. + */ + +#include <string.h> + +#ifndef WIN32 + #include <unistd.h> +#else + #include <io.h> + #include "BLI_winstuff.h" +#endif + +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> + +#include "MEM_guardedalloc.h" + +#include "BLI_bfile.h" + +// This would provide config paths and their oldest viable version +// so if there is an uncompatible change, user's old versions are not loaded +//#include "bfile_tables.h" + +/* Internal bfile type flags */ +#define BTF_OPEN (0) +#define BTF_FOPEN (1<<0) +#define BTF_READ (1<<1) +#define BTF_WRITE (1<<2) +#define BTF_AT_END (1<<3) +#define BTF_DISCARD (1<<4) + + +void fill_paths(BFILE *bfile, const char *path) { + char* source_path = NULL; + int bflags = bfile->uflags; + + if(bflags & BFILE_NORMAL || bflags & BFILE_RAW) { +// bfile->fpath is path with // replaced + } + if(bflags & BFILE_TEMP) { +// bfile->fpath is tempdir+path + } + if(bflags & BFILE_CONFIG) { +// bfile->fpath is userdir+version+path +// source_path is first hit in (if using fallback to older versions) +// userdir+curversion+path (... userdir+limitversion+path) sysdir+path +// (limitversion is based in path, using some kind of regex or "tables") + } + + if(bfile->type & BTF_WRITE && !(bflags & BFILE_RAW)) { + /* Generate temp path */ + // bfile->tpath is fpath+randstring + if(!(bfile->type & BTF_DISCARD)) { + /* Copy data to tpath */ + if(source_path) { + // copy it from older version or sys version + } + } + } else { + bfile->tpath = bfile->fpath; + } +} + +BFILE *BLI_bfile_fopen(const char *path, const char *mode, int bflags) { + BFILE *bfile; + + bfile = MEM_mallocN(sizeof(BFILE), "bfile-fopen"); + bfile->type = BTF_FOPEN; + bfile->uflags = bflags; + + /* From fopen() doc, we can guess some logic: + r BTF_READ + r+ BTF_READ | BTF_WRITE + w BTF_DISCARD | BTF_WRITE + w+ BTF_DISCARD | BTF_WRITE | BTF_READ + a BTF_AT_END | BTF_WRITE + a+ BTF_AT_END | BTF_WRITE | BTF_READ + */ + if(strchr(mode, 'r')) + bfile->type |= BTF_READ; + if(strchr(mode, 'w')) + bfile->type |= (BTF_DISCARD | BTF_WRITE); + if(strchr(mode, 'a')) + bfile->type |= (BTF_AT_END | BTF_WRITE); + if(strchr(mode, '+')) + bfile->type |= (BTF_READ | BTF_WRITE); + + fill_paths(bfile, path); + + bfile->stream = fopen(bfile->tpath, mode); + // detect failed fopen + bfile->fd = fileno(bfile->stream); + return bfile; +} + + +BFILE *BLI_bfile_open(const char *pathname, int flags, int bflags) { + BFILE *bfile; + + bfile = MEM_mallocN(sizeof(BFILE), "bfile-open"); + bfile->type = BTF_OPEN; + bfile->uflags = bflags; + + /* Easy mapping for open() */ + if(flags & O_RDONLY) + bfile->type |= BTF_READ; + if(flags & O_WRONLY) + bfile->type |= BTF_WRITE; + if(flags & O_RDWR) + bfile->type |= (BTF_READ | BTF_WRITE); + if(flags & O_APPEND) + bfile->type |= BTF_AT_END; + if(flags & O_TRUNC) + bfile->type |= BTF_DISCARD; + + fill_paths(bfile, pathname); + + bfile->fd = open(bfile->tpath, flags); + // detect failed open +// bfile->stream = fdopen(bfile->fd, XXX); /* MSWindows _fdopen? */ + return bfile; +} + + +FILE *BLI_bfile_file_from_bfile(BFILE *bfile) { + return bfile->stream; +} + + +int BLI_bfile_fd_from_bfile(BFILE *bfile) { + return bfile->fd; +} + + +ssize_t BLI_bfile_write(BFILE *f, const void *buf, size_t count) { + ssize_t ret; + + ret = write((f->fd), buf, count); + if (ret == -1) { + f->error = 1; + } + + return ret; +} + + +ssize_t BLI_bfile_read(BFILE *f, void *buf, size_t count) { + ssize_t ret; + + ret = read((f->fd), buf, count); + if (ret == -1) { + f->error = 1; + } + + return ret; +} + + +size_t BLI_bfile_fwrite(const void *ptr, size_t size, size_t nmemb, BFILE *f) { + size_t ret; + + ret = fwrite(ptr, size, nmemb, f->stream); + if (ret < 0) { + f->error = 1; + } + + return ret; +} + + +size_t BLI_bfile_fread(void *ptr, size_t size, size_t nmemb, BFILE *f) { + size_t ret; + + ret = fread(ptr, size, nmemb, f->stream); + if ((ret < 0) && ferror(f->stream)) { + f->error = 1; + } + + return ret; +} + + +void BLI_bfile_close(BFILE *bfile) { + if((bfile->type | BTF_WRITE) && + !(bfile->uflags | BFILE_RAW)) { + /* Make sure data is on disk */ + /* Move to final name if no errors */ + } + + /* Normal close */ + + /* Cleanup */ + if(bfile->fpath) { + MEM_freeN(bfile->fpath); + } + if(bfile->tpath) { + MEM_freeN(bfile->tpath); + } +} + + +void BLI_bfile_clear_error(BFILE *bfile) { + bfile->error = 0; +} + + +void BLI_bfile_set_error(BFILE *bfile, int error) { + /* No cheating, use clear_error() for 0 */ + if (error) { + bfile->error = error; + } +} diff --git a/source/blender/blenlib/intern/arithb.c b/source/blender/blenlib/intern/arithb.c index ac79894d827..26bbbf040f3 100644 --- a/source/blender/blenlib/intern/arithb.c +++ b/source/blender/blenlib/intern/arithb.c @@ -4843,7 +4843,7 @@ static float lambda_cp_line(float p[3], float l1[3], float l2[3]) /* useful to calculate an even width shell, by taking the angle between 2 planes. * The return value is a scale on the offset. * no angle between planes is 1.0, as the angle between the 2 planes approches 180d - * the distance gets very hight, 180d would be inf, but this case isnt valid */ + * the distance gets very high, 180d would be inf, but this case isn't valid */ float AngleToLength(const float angle) { return (angle < SMALL_NUMBER) ? 1.0f : fabsf(1.0f / cosf(angle * (M_PI/180.0f))); diff --git a/source/blender/blenlib/intern/util.c b/source/blender/blenlib/intern/util.c index c7bb7a54457..b1539d22909 100644 --- a/source/blender/blenlib/intern/util.c +++ b/source/blender/blenlib/intern/util.c @@ -856,98 +856,123 @@ char *BLI_gethome(void) { #endif } -/* this function returns the path to a blender folder, if it exists, - * trying in this order: - * - * path_to_executable/release/folder_name (in svn) - * ./release/folder_name (in svn) - * $HOME/.blender/folder_name - * path_to_executable/.blender/folder_name - * - * returns NULL if none is found. */ +/* this function returns the path to a blender folder, if it exists + * utility functions for BLI_gethome_folder */ + +/* #define PATH_DEBUG */ /* for testing paths that are checked */ + +static int test_data_path(char *targetpath, char *path_base, char *path_sep, char *folder_name) +{ + char tmppath[FILE_MAXDIR]; + + if(path_sep) BLI_join_dirfile(tmppath, path_base, path_sep); + else BLI_strncpy(tmppath, path_base, sizeof(tmppath)); + + BLI_make_file_string("/", targetpath, tmppath, folder_name); + + if (BLI_exists(targetpath)) { +#ifdef PATH_DEBUG + printf("\tpath found: %s\n", targetpath); +#endif + return 1; + } + else { +#ifdef PATH_DEBUG + printf("\tpath missing: %s\n", targetpath); +#endif + targetpath[0] = '\0'; + return 0; + } +} -char *BLI_gethome_folder(char *folder_name) +static int gethome_path_local(char *targetpath, char *folder_name) { extern char bprogname[]; /* argv[0] from creator.c */ - static char homedir[FILE_MAXDIR] = ""; - static char fulldir[FILE_MAXDIR] = ""; - char tmpdir[FILE_MAXDIR]; char bprogdir[FILE_MAXDIR]; + char cwd[FILE_MAXDIR]; char *s; int i; - + +#ifdef PATH_DEBUG + printf("gethome_path_local...\n"); +#endif + + /* try release/folder_name (binary relative) */ /* use argv[0] (bprogname) to get the path to the executable */ s = BLI_last_slash(bprogname); - i = s - bprogname + 1; BLI_strncpy(bprogdir, bprogname, i); + + /* try ./.blender/folder_name */ + if(test_data_path(targetpath, bprogdir, ".blender", folder_name)) + return 1; + + if(test_data_path(targetpath, bprogdir, "release", folder_name)) + return 1; + + /* try release/folder_name (CWD relative) */ + if(test_data_path(targetpath, BLI_getwdN(cwd), "release", folder_name)) + return 1; + + return 0; +} - /* try path_to_executable/release/folder_name (in svn) */ - if (folder_name) { - BLI_snprintf(tmpdir, sizeof(tmpdir), "release/%s", folder_name); - BLI_make_file_string("/", fulldir, bprogdir, tmpdir); - if (BLI_exists(fulldir)) return fulldir; - else fulldir[0] = '\0'; - } +static int gethome_path_user(char *targetpath, char *folder_name) +{ + char *home_path= BLI_gethome(); - /* try ./release/folder_name (in svn) */ - if(folder_name) { - BLI_snprintf(fulldir, sizeof(fulldir), "./release/%s", folder_name); - if (BLI_exists(fulldir)) return fulldir; - else fulldir[0] = '\0'; - } +#ifdef PATH_DEBUG + printf("gethome_path_user...\n"); +#endif + + /* try $HOME/folder_name */ + return test_data_path(targetpath, home_path, ".blender", folder_name); +} - /* BLI_gethome() can return NULL if env vars are not set */ - s = BLI_gethome(); +static int gethome_path_system(char *targetpath, char *folder_name) +{ + extern char blender_path[]; /* unix prefix eg. /usr/share/blender/2.5 creator.c */ + + if(!blender_path[0]) + return 0; + +#ifdef PATH_DEBUG + printf("gethome_path_system...\n"); +#endif + + /* try $BLENDERPATH/folder_name */ + return test_data_path(targetpath, blender_path, NULL, folder_name); +} - if(!s) { /* bail if no $HOME */ - printf("$HOME is NOT set\n"); - return NULL; +char *BLI_gethome_folder(char *folder_name, int flag) +{ + static char fulldir[FILE_MAXDIR] = ""; + + /* first check if this is a redistributable bundle */ + if(flag & BLI_GETHOME_LOCAL) { + if (gethome_path_local(fulldir, folder_name)) + return fulldir; } - if(strstr(s, ".blender")) - BLI_strncpy(homedir, s, FILE_MAXDIR); - else - BLI_make_file_string("/", homedir, s, ".blender"); - - /* if $HOME/.blender/folder_name exists, return it */ - if(BLI_exists(homedir)) { - if (folder_name) { - BLI_make_file_string("/", fulldir, homedir, folder_name); - if(BLI_exists(fulldir)) - return fulldir; - } - else - return homedir; - } - else - homedir[0] = '\0'; - - /* using tmpdir to preserve homedir (if) found above: - * the ideal is to have a home dir with folder_name dir inside - * it, but if that isn't available, it's possible to - * have a 'broken' home dir somewhere and a folder_name dir in the - * svn sources */ - BLI_make_file_string("/", tmpdir, bprogdir, ".blender"); - - if(BLI_exists(tmpdir)) { - if(folder_name) { - BLI_make_file_string("/", fulldir, tmpdir, folder_name); - if(BLI_exists(fulldir)) { - BLI_strncpy(homedir, tmpdir, FILE_MAXDIR); - return fulldir; - } - else { - homedir[0] = '\0'; - fulldir[0] = '\0'; - } - } - else return homedir; + /* then check if the OS has blender data files installed in a global location */ + if(flag & BLI_GETHOME_SYSTEM) { + if (gethome_path_system(fulldir, folder_name)) + return fulldir; } - + + /* now check the users home dir for data files */ + if(flag & BLI_GETHOME_USER) { + if (gethome_path_user(fulldir, folder_name)) + return fulldir; + } + return NULL; } +#ifdef PATH_DEBUG +#undef PATH_DEBUG +#endif + void BLI_setenv(const char *env, const char*val) { /* SGI or free windows */ diff --git a/source/blender/blenloader/BLO_readfile.h b/source/blender/blenloader/BLO_readfile.h index 6e2772efea4..52295dc3092 100644 --- a/source/blender/blenloader/BLO_readfile.h +++ b/source/blender/blenloader/BLO_readfile.h @@ -211,7 +211,7 @@ void BLO_library_append_named_part(const struct bContext *C, struct Main *mainl, void BLO_library_append_end(const struct bContext *C, struct Main *mainl, BlendHandle** bh, int idcode, short flag); /* deprecated */ -#if 0 +#if 1 void BLO_script_library_append(BlendHandle **bh, char *dir, char *name, int idcode, short flag, struct Main *mainvar, struct Scene *scene, struct ReportList *reports); #endif diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index c5dcf1ce520..204176f64c3 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -2184,6 +2184,8 @@ static void lib_link_constraints(FileData *fd, ID *id, ListBase *conlist) data = ((bKinematicConstraint*)con->data); data->tar = newlibadr(fd, id->lib, data->tar); data->poletar = newlibadr(fd, id->lib, data->poletar); + con->lin_error = 0.f; + con->rot_error = 0.f; } break; case CONSTRAINT_TYPE_TRACKTO: @@ -2331,6 +2333,7 @@ static void lib_link_armature(FileData *fd, Main *main) while(arm) { if(arm->id.flag & LIB_NEEDLINK) { + if (arm->adt) lib_link_animdata(fd, &arm->id, arm->adt); arm->id.flag -= LIB_NEEDLINK; } arm= arm->id.next; @@ -2357,6 +2360,7 @@ static void direct_link_armature(FileData *fd, bArmature *arm) link_list(fd, &arm->bonebase); arm->edbo= NULL; arm->sketch = NULL; + arm->adt= newdataadr(fd, arm->adt); bone=arm->bonebase.first; while (bone) { @@ -3613,6 +3617,11 @@ static void lib_link_object(FileData *fd, Main *main) else if(act->type==ACT_STATE) { /* bStateActuator *statea = act->data; */ } + else if(act->type==ACT_ARMATURE) { + bArmatureActuator *arma= act->data; + arma->target= newlibadr(fd, ob->id.lib, arma->target); + arma->subtarget= newlibadr(fd, ob->id.lib, arma->subtarget); + } act= act->next; } @@ -3674,6 +3683,10 @@ static void direct_link_pose(FileData *fd, bPose *pose) pchan->iktree.first= pchan->iktree.last= NULL; pchan->path= NULL; } + pose->ikdata = NULL; + if (pose->ikparam != NULL) { + pose->ikparam= newdataadr(fd, pose->ikparam); + } } static void direct_link_modifiers(FileData *fd, ListBase *lb) @@ -4686,7 +4699,6 @@ void lib_link_screen_restore(Main *newmain, bScreen *curscreen, Scene *curscene) v3d->layact= v3d->localvd->layact; MEM_freeN(v3d->localvd); v3d->localvd= NULL; - v3d->localview= 0; } */ } @@ -9352,10 +9364,6 @@ static void do_versions(FileData *fd, Library *lib, Main *main) */ //do_versions_ipos_to_animato(main); - /* toolsettings */ - for(scene= main->scene.first; scene; scene= scene->id.next) - scene->r.audio = scene->audio; - /* shader, composit and texture node trees have id.name empty, put something in * to have them show in RNA viewer and accessible otherwise. */ @@ -9369,7 +9377,7 @@ static void do_versions(FileData *fd, Library *lib, Main *main) strcpy(sce->nodetree->id.name, "NTComposit Nodetree"); /* move to cameras */ - if(sce->r.scemode & R_PANORAMA) { + if(sce->r.mode & R_PANORAMA) { for(base=sce->base.first; base; base=base->next) { ob= newlibadr(fd, lib, base->object); @@ -9379,7 +9387,7 @@ static void do_versions(FileData *fd, Library *lib, Main *main) } } - sce->r.scemode &= ~R_PANORAMA; + sce->r.mode &= ~R_PANORAMA; } } /* and texture trees */ @@ -9701,15 +9709,20 @@ static void do_versions(FileData *fd, Library *lib, Main *main) sce->unit.scale_length= 1.0f; for(ob = main->object.first; ob; ob = ob->id.next) { - ModifierData *md; + FluidsimModifierData *fluidmd = (FluidsimModifierData *)modifiers_findByType(ob, eModifierType_Fluidsim); + if (fluidmd) fluidmd->fss->fmd = fluidmd; + } - /* add backwards pointer for fluidsim modifier RNA access */ - for (md=ob->modifiers.first; md; md = md->next) { - if (md->type == eModifierType_Fluidsim) { - FluidsimModifierData *fluidmd= (FluidsimModifierData*) md; - fluidmd->fss->fmd = fluidmd; - } - } + for(sce= main->scene.first; sce; sce= sce->id.next) + { + if(sce->audio.main == 0.0) + sce->audio.main = 1.0; + + sce->r.ffcodecdata.audio_mixrate = sce->audio.mixrate; + sce->r.ffcodecdata.audio_volume = sce->audio.main; + sce->audio.distance_model = 2.0; + sce->audio.doppler_factor = 1.0; + sce->audio.speed_of_sound = 343.3; } } @@ -10426,6 +10439,9 @@ static void expand_armature(FileData *fd, Main *mainvar, bArmature *arm) { Bone *curBone; + if(arm->adt) + expand_animdata(fd, mainvar, arm->adt); + for (curBone = arm->bonebase.first; curBone; curBone=curBone->next) { expand_bones(fd, mainvar, curBone); } @@ -10574,11 +10590,19 @@ static void expand_object(FileData *fd, Main *mainvar, Object *ob) bObjectActuator *oa= act->data; expand_doit(fd, mainvar, oa->reference); } + else if(act->type==ACT_ADD_OBJECT) { + bAddObjectActuator *aoa= act->data; + expand_doit(fd, mainvar, aoa->ob); + } else if(act->type==ACT_SCENE) { bSceneActuator *sa= act->data; expand_doit(fd, mainvar, sa->camera); expand_doit(fd, mainvar, sa->scene); } + else if(act->type==ACT_2DFILTER) { + bTwoDFilterActuator *tdfa= act->data; + expand_doit(fd, mainvar, tdfa->text); + } else if(act->type==ACT_ACTION) { bActionActuator *aa= act->data; expand_doit(fd, mainvar, aa->act); @@ -10595,6 +10619,14 @@ static void expand_object(FileData *fd, Main *mainvar, Object *ob) bMessageActuator *ma= act->data; expand_doit(fd, mainvar, ma->toObject); } + else if(act->type==ACT_PARENT) { + bParentActuator *pa= act->data; + expand_doit(fd, mainvar, pa->ob); + } + else if(act->type==ACT_ARMATURE) { + bArmatureActuator *arma= act->data; + expand_doit(fd, mainvar, arma->target); + } act= act->next; } diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c index 98db27182ab..fda35d28d0e 100644 --- a/source/blender/blenloader/intern/writefile.c +++ b/source/blender/blenloader/intern/writefile.c @@ -712,6 +712,9 @@ static void write_sensors(WriteData *wd, ListBase *lb) case SENS_PROPERTY: writestruct(wd, DATA, "bPropertySensor", 1, sens->data); break; + case SENS_ARMATURE: + writestruct(wd, DATA, "bArmatureSensor", 1, sens->data); + break; case SENS_ACTUATOR: writestruct(wd, DATA, "bActuatorSensor", 1, sens->data); break; @@ -830,6 +833,9 @@ static void write_actuators(WriteData *wd, ListBase *lb) case ACT_STATE: writestruct(wd, DATA, "bStateActuator", 1, act->data); break; + case ACT_ARMATURE: + writestruct(wd, DATA, "bArmatureActuator", 1, act->data); + break; default: ; /* error: don't know how to write this file */ } @@ -1093,8 +1099,16 @@ static void write_pose(WriteData *wd, bPose *pose) for (grp=pose->agroups.first; grp; grp=grp->next) writestruct(wd, DATA, "bActionGroup", 1, grp); + /* write IK param */ + if (pose->ikparam) { + const char *structname = get_ikparam_name(pose); + if (structname) + writestruct(wd, DATA, structname, 1, pose->ikparam); + } + /* Write this pose */ writestruct(wd, DATA, "bPose", 1, pose); + } static void write_defgroups(WriteData *wd, ListBase *defbase) @@ -2116,6 +2130,8 @@ static void write_armatures(WriteData *wd, ListBase *idbase) writestruct(wd, ID_AR, "bArmature", 1, arm); if (arm->id.properties) IDP_WriteProperty(arm->id.properties, wd); + if (arm->adt) write_animdata(wd, arm->adt); + /* Direct data */ bone= arm->bonebase.first; while(bone) { diff --git a/source/blender/editors/CMakeLists.txt b/source/blender/editors/CMakeLists.txt index 066d42e723e..d13d7ce2ff2 100644 --- a/source/blender/editors/CMakeLists.txt +++ b/source/blender/editors/CMakeLists.txt @@ -40,6 +40,7 @@ SET(INC ../windowmanager ../nodes ../gpu ../blenfont + ../ikplugin ) IF(WITH_GAMEENGINE) diff --git a/source/blender/editors/animation/anim_channels_defines.c b/source/blender/editors/animation/anim_channels_defines.c index e3418fa194f..8f8700cc43b 100644 --- a/source/blender/editors/animation/anim_channels_defines.c +++ b/source/blender/editors/animation/anim_channels_defines.c @@ -461,6 +461,9 @@ static void acf_object_name(bAnimListElem *ale, char *name) /* check if some setting exists for this channel */ static short acf_object_setting_valid(bAnimContext *ac, bAnimListElem *ale, int setting) { + Base *base= (Base *)ale->data; + Object *ob= base->object; + switch (setting) { /* muted only in NLA */ case ACHANNEL_SETTING_MUTE: @@ -468,7 +471,7 @@ static short acf_object_setting_valid(bAnimContext *ac, bAnimListElem *ale, int /* visible only in Graph Editor */ case ACHANNEL_SETTING_VISIBLE: - return ((ac) && (ac->spacetype == SPACE_IPO)); + return ((ac) && (ac->spacetype == SPACE_IPO) && (ob->adt)); /* only select and expand supported otherwise */ case ACHANNEL_SETTING_SELECT: @@ -759,7 +762,7 @@ static int acf_fillactd_setting_flag(int setting, short *neg) switch (setting) { case ACHANNEL_SETTING_SELECT: /* selected */ - return ACT_SELECTED; + return ADT_UI_SELECTED; case ACHANNEL_SETTING_EXPAND: /* expanded */ *neg= 1; @@ -774,13 +777,18 @@ static int acf_fillactd_setting_flag(int setting, short *neg) static void *acf_fillactd_setting_ptr(bAnimListElem *ale, int setting, short *type) { bAction *act= (bAction *)ale->data; + AnimData *adt= ale->adt; /* clear extra return data first */ *type= 0; switch (setting) { case ACHANNEL_SETTING_SELECT: /* selected */ - GET_ACF_FLAG_PTR(act->flag); + if (adt) { + GET_ACF_FLAG_PTR(adt->flag); + } + else + return 0; case ACHANNEL_SETTING_EXPAND: /* expanded */ GET_ACF_FLAG_PTR(act->flag); @@ -998,6 +1006,9 @@ static int acf_dsmat_setting_flag(int setting, short *neg) case ACHANNEL_SETTING_VISIBLE: /* visible (only in Graph Editor) */ *neg= 1; return ADT_CURVES_NOT_VISIBLE; + + case ACHANNEL_SETTING_SELECT: /* selected */ + return ADT_UI_SELECTED; default: /* unsupported */ return 0; @@ -1016,6 +1027,7 @@ static void *acf_dsmat_setting_ptr(bAnimListElem *ale, int setting, short *type) case ACHANNEL_SETTING_EXPAND: /* expanded */ GET_ACF_FLAG_PTR(ma->flag); + case ACHANNEL_SETTING_SELECT: /* selected */ case ACHANNEL_SETTING_MUTE: /* muted (for NLA only) */ case ACHANNEL_SETTING_VISIBLE: /* visible (for Graph Editor only) */ if (ma->adt) @@ -1067,6 +1079,9 @@ static int acf_dslam_setting_flag(int setting, short *neg) case ACHANNEL_SETTING_VISIBLE: /* visible (only in Graph Editor) */ *neg= 1; return ADT_CURVES_NOT_VISIBLE; + + case ACHANNEL_SETTING_SELECT: /* selected */ + return ADT_UI_SELECTED; default: /* unsupported */ return 0; @@ -1085,6 +1100,7 @@ static void *acf_dslam_setting_ptr(bAnimListElem *ale, int setting, short *type) case ACHANNEL_SETTING_EXPAND: /* expanded */ GET_ACF_FLAG_PTR(la->flag); + case ACHANNEL_SETTING_SELECT: /* selected */ case ACHANNEL_SETTING_MUTE: /* muted (for NLA only) */ case ACHANNEL_SETTING_VISIBLE: /* visible (for Graph Editor only) */ if (la->adt) @@ -1136,6 +1152,9 @@ static int acf_dscam_setting_flag(int setting, short *neg) case ACHANNEL_SETTING_VISIBLE: /* visible (only in Graph Editor) */ *neg= 1; return ADT_CURVES_NOT_VISIBLE; + + case ACHANNEL_SETTING_SELECT: /* selected */ + return ADT_UI_SELECTED; default: /* unsupported */ return 0; @@ -1154,6 +1173,7 @@ static void *acf_dscam_setting_ptr(bAnimListElem *ale, int setting, short *type) case ACHANNEL_SETTING_EXPAND: /* expanded */ GET_ACF_FLAG_PTR(ca->flag); + case ACHANNEL_SETTING_SELECT: /* selected */ case ACHANNEL_SETTING_MUTE: /* muted (for NLA only) */ case ACHANNEL_SETTING_VISIBLE: /* visible (for Graph Editor only) */ if (ca->adt) @@ -1205,6 +1225,9 @@ static int acf_dscur_setting_flag(int setting, short *neg) case ACHANNEL_SETTING_VISIBLE: /* visible (only in Graph Editor) */ *neg= 1; return ADT_CURVES_NOT_VISIBLE; + + case ACHANNEL_SETTING_SELECT: /* selected */ + return ADT_UI_SELECTED; default: /* unsupported */ return 0; @@ -1223,6 +1246,7 @@ static void *acf_dscur_setting_ptr(bAnimListElem *ale, int setting, short *type) case ACHANNEL_SETTING_EXPAND: /* expanded */ GET_ACF_FLAG_PTR(cu->flag); + case ACHANNEL_SETTING_SELECT: /* selected */ case ACHANNEL_SETTING_MUTE: /* muted (for NLA only) */ case ACHANNEL_SETTING_VISIBLE: /* visible (for Graph Editor only) */ if (cu->adt) @@ -1274,6 +1298,9 @@ static int acf_dsskey_setting_flag(int setting, short *neg) case ACHANNEL_SETTING_VISIBLE: /* visible (only in Graph Editor) */ *neg= 1; return ADT_CURVES_NOT_VISIBLE; + + case ACHANNEL_SETTING_SELECT: /* selected */ + return ADT_UI_SELECTED; default: /* unsupported */ return 0; @@ -1292,6 +1319,7 @@ static void *acf_dsskey_setting_ptr(bAnimListElem *ale, int setting, short *type case ACHANNEL_SETTING_EXPAND: /* expanded */ GET_ACF_FLAG_PTR(key->flag); + case ACHANNEL_SETTING_SELECT: /* selected */ case ACHANNEL_SETTING_MUTE: /* muted (for NLA only) */ case ACHANNEL_SETTING_VISIBLE: /* visible (for Graph Editor only) */ if (key->adt) @@ -1343,6 +1371,9 @@ static int acf_dswor_setting_flag(int setting, short *neg) case ACHANNEL_SETTING_VISIBLE: /* visible (only in Graph Editor) */ *neg= 1; return ADT_CURVES_NOT_VISIBLE; + + case ACHANNEL_SETTING_SELECT: /* selected */ + return ADT_UI_SELECTED; default: /* unsupported */ return 0; @@ -1361,6 +1392,7 @@ static void *acf_dswor_setting_ptr(bAnimListElem *ale, int setting, short *type) case ACHANNEL_SETTING_EXPAND: /* expanded */ GET_ACF_FLAG_PTR(wo->flag); + case ACHANNEL_SETTING_SELECT: /* selected */ case ACHANNEL_SETTING_MUTE: /* muted (for NLA only) */ case ACHANNEL_SETTING_VISIBLE: /* visible (for Graph Editor only) */ if (wo->adt) @@ -1412,6 +1444,9 @@ static int acf_dspart_setting_flag(int setting, short *neg) case ACHANNEL_SETTING_VISIBLE: /* visible (only in Graph Editor) */ *neg= 1; return ADT_CURVES_NOT_VISIBLE; + + case ACHANNEL_SETTING_SELECT: /* selected */ + return ADT_UI_SELECTED; default: /* unsupported */ return 0; @@ -1430,6 +1465,7 @@ static void *acf_dspart_setting_ptr(bAnimListElem *ale, int setting, short *type case ACHANNEL_SETTING_EXPAND: /* expanded */ GET_ACF_FLAG_PTR(part->flag); + case ACHANNEL_SETTING_SELECT: /* selected */ case ACHANNEL_SETTING_MUTE: /* muted (for NLA only) */ case ACHANNEL_SETTING_VISIBLE: /* visible (for Graph Editor only) */ if (part->adt) @@ -1482,6 +1518,9 @@ static int acf_dsmball_setting_flag(int setting, short *neg) *neg= 1; return ADT_CURVES_NOT_VISIBLE; + case ACHANNEL_SETTING_SELECT: /* selected */ + return ADT_UI_SELECTED; + default: /* unsupported */ return 0; } @@ -1499,6 +1538,7 @@ static void *acf_dsmball_setting_ptr(bAnimListElem *ale, int setting, short *typ case ACHANNEL_SETTING_EXPAND: /* expanded */ GET_ACF_FLAG_PTR(mb->flag); + case ACHANNEL_SETTING_SELECT: /* selected */ case ACHANNEL_SETTING_MUTE: /* muted (for NLA only) */ case ACHANNEL_SETTING_VISIBLE: /* visible (for Graph Editor only) */ if (mb->adt) @@ -1526,6 +1566,80 @@ static bAnimChannelType ACF_DSMBALL= acf_dsmball_setting_ptr /* pointer for setting */ }; +/* Armature Expander ------------------------------------------- */ + +// TODO: just get this from RNA? +static int acf_dsarm_icon(bAnimListElem *ale) +{ + return ICON_ARMATURE_DATA; +} + +/* get the appropriate flag(s) for the setting when it is valid */ +static int acf_dsarm_setting_flag(int setting, short *neg) +{ + /* clear extra return data first */ + *neg= 0; + + switch (setting) { + case ACHANNEL_SETTING_EXPAND: /* expanded */ + return ARM_DS_EXPAND; + + case ACHANNEL_SETTING_MUTE: /* mute (only in NLA) */ + return ADT_NLA_EVAL_OFF; + + case ACHANNEL_SETTING_VISIBLE: /* visible (only in Graph Editor) */ + *neg= 1; + return ADT_CURVES_NOT_VISIBLE; + + case ACHANNEL_SETTING_SELECT: /* selected */ + return ADT_UI_SELECTED; + + default: /* unsupported */ + return 0; + } +} + +/* get pointer to the setting */ +static void *acf_dsarm_setting_ptr(bAnimListElem *ale, int setting, short *type) +{ + bArmature *arm= (bArmature *)ale->data; + + /* clear extra return data first */ + *type= 0; + + switch (setting) { + case ACHANNEL_SETTING_EXPAND: /* expanded */ + GET_ACF_FLAG_PTR(arm->flag); + + case ACHANNEL_SETTING_SELECT: /* selected */ + case ACHANNEL_SETTING_MUTE: /* muted (for NLA only) */ + case ACHANNEL_SETTING_VISIBLE: /* visible (for Graph Editor only) */ + if (arm->adt) + GET_ACF_FLAG_PTR(arm->adt->flag) + else + return NULL; + + default: /* unsupported */ + return NULL; + } +} + +/* metaball expander type define */ +static bAnimChannelType ACF_DSARM= +{ + acf_generic_dataexpand_backdrop,/* backdrop */ + acf_generic_indention_1, /* indent level */ + acf_generic_basic_offset, /* offset */ + + acf_generic_idblock_name, /* name */ + acf_dsarm_icon, /* icon */ + + acf_generic_dataexpand_setting_valid, /* has setting */ + acf_dsarm_setting_flag, /* flag for setting */ + acf_dsarm_setting_ptr /* pointer for setting */ +}; + + /* ShapeKey Entry ------------------------------------------- */ // XXX ... this is currently obsolete... @@ -1709,6 +1823,7 @@ void ANIM_init_channel_typeinfo_data (void) animchannelTypeInfo[type++]= &ACF_DSWOR; /* World Channel */ animchannelTypeInfo[type++]= &ACF_DSPART; /* Particle Channel */ animchannelTypeInfo[type++]= &ACF_DSMBALL; /* MetaBall Channel */ + animchannelTypeInfo[type++]= &ACF_DSARM; /* Armature Channel */ animchannelTypeInfo[type++]= NULL; /* ShapeKey */ // XXX this is no longer used for now... diff --git a/source/blender/editors/animation/anim_channels_edit.c b/source/blender/editors/animation/anim_channels_edit.c index 4afecdb55c0..83f5fca5af5 100644 --- a/source/blender/editors/animation/anim_channels_edit.c +++ b/source/blender/editors/animation/anim_channels_edit.c @@ -91,6 +91,7 @@ /* -------------------------- Exposed API ----------------------------------- */ /* Set the given animation-channel as the active one for the active context */ +// TODO: extend for animdata types... void ANIM_set_active_channel (bAnimContext *ac, void *data, short datatype, int filter, void *channel_data, short channel_type) { ListBase anim_data = {NULL, NULL}; @@ -130,11 +131,29 @@ void ANIM_set_active_channel (bAnimContext *ac, void *data, short datatype, int ACHANNEL_SET_FLAG(nlt, ACHANNEL_SETFLAG_CLEAR, NLATRACK_ACTIVE); } break; + + case ANIMTYPE_FILLACTD: /* Action Expander */ + case ANIMTYPE_DSMAT: /* Datablock AnimData Expanders */ + case ANIMTYPE_DSLAM: + case ANIMTYPE_DSCAM: + case ANIMTYPE_DSCUR: + case ANIMTYPE_DSSKEY: + case ANIMTYPE_DSWOR: + case ANIMTYPE_DSPART: + case ANIMTYPE_DSMBALL: + case ANIMTYPE_DSARM: + { + /* need to verify that this data is valid for now */ + if (ale->adt) { + ACHANNEL_SET_FLAG(ale->adt, ACHANNEL_SETFLAG_CLEAR, ADT_UI_ACTIVE); + } + } + break; } } /* set active flag */ - if (channel_data != NULL) { + if (channel_data) { switch (channel_type) { case ANIMTYPE_GROUP: { @@ -154,6 +173,23 @@ void ANIM_set_active_channel (bAnimContext *ac, void *data, short datatype, int nlt->flag |= NLATRACK_ACTIVE; } break; + + case ANIMTYPE_FILLACTD: /* Action Expander */ + case ANIMTYPE_DSMAT: /* Datablock AnimData Expanders */ + case ANIMTYPE_DSLAM: + case ANIMTYPE_DSCAM: + case ANIMTYPE_DSCUR: + case ANIMTYPE_DSSKEY: + case ANIMTYPE_DSWOR: + case ANIMTYPE_DSPART: + case ANIMTYPE_DSMBALL: + case ANIMTYPE_DSARM: + { + /* need to verify that this data is valid for now */ + if (ale->adt) + ale->adt->flag |= ADT_UI_ACTIVE; + } + break; } } @@ -174,7 +210,7 @@ void ANIM_deselect_anim_channels (void *data, short datatype, short test, short int filter; /* filter data */ - filter= ANIMFILTER_VISIBLE; + filter= ANIMFILTER_VISIBLE|ANIMFILTER_CHANNELS; ANIM_animdata_filter(NULL, &anim_data, filter, data, datatype); /* See if we should be selecting or deselecting */ @@ -189,12 +225,10 @@ void ANIM_deselect_anim_channels (void *data, short datatype, short test, short sel= ACHANNEL_SETFLAG_CLEAR; break; case ANIMTYPE_OBJECT: + #if 0 /* for now, do not take object selection into account, since it gets too annoying */ if (ale->flag & SELECT) sel= ACHANNEL_SETFLAG_CLEAR; - break; - case ANIMTYPE_FILLACTD: - if (ale->flag & ACT_SELECTED) - sel= ACHANNEL_SETFLAG_CLEAR; + #endif break; case ANIMTYPE_GROUP: if (ale->flag & AGRP_SELECTED) @@ -208,6 +242,22 @@ void ANIM_deselect_anim_channels (void *data, short datatype, short test, short if (ale->flag & NLATRACK_SELECTED) sel= ACHANNEL_SETFLAG_CLEAR; break; + + case ANIMTYPE_FILLACTD: /* Action Expander */ + case ANIMTYPE_DSMAT: /* Datablock AnimData Expanders */ + case ANIMTYPE_DSLAM: + case ANIMTYPE_DSCAM: + case ANIMTYPE_DSCUR: + case ANIMTYPE_DSSKEY: + case ANIMTYPE_DSWOR: + case ANIMTYPE_DSPART: + case ANIMTYPE_DSMBALL: + case ANIMTYPE_DSARM: + { + if ((ale->adt) && (ale->adt->flag & ADT_UI_SELECTED)) + sel= ACHANNEL_SETFLAG_CLEAR; + } + break; } } } @@ -220,23 +270,26 @@ void ANIM_deselect_anim_channels (void *data, short datatype, short test, short Scene *scene= (Scene *)ale->data; ACHANNEL_SET_FLAG(scene, sel, SCE_DS_SELECTED); + + if (scene->adt) { + ACHANNEL_SET_FLAG(scene, sel, ADT_UI_SELECTED); + } } break; case ANIMTYPE_OBJECT: + #if 0 /* for now, do not take object selection into account, since it gets too annoying */ { Base *base= (Base *)ale->data; Object *ob= base->object; ACHANNEL_SET_FLAG(base, sel, SELECT); ACHANNEL_SET_FLAG(ob, sel, SELECT); - } - break; - case ANIMTYPE_FILLACTD: - { - bAction *act= (bAction *)ale->data; - ACHANNEL_SET_FLAG(act, sel, ACT_SELECTED); + if (ob->adt) { + ACHANNEL_SET_FLAG(ob, sel, ADT_UI_SELECTED); + } } + #endif break; case ANIMTYPE_GROUP: { @@ -262,6 +315,25 @@ void ANIM_deselect_anim_channels (void *data, short datatype, short test, short nlt->flag &= ~NLATRACK_ACTIVE; } break; + + case ANIMTYPE_FILLACTD: /* Action Expander */ + case ANIMTYPE_DSMAT: /* Datablock AnimData Expanders */ + case ANIMTYPE_DSLAM: + case ANIMTYPE_DSCAM: + case ANIMTYPE_DSCUR: + case ANIMTYPE_DSSKEY: + case ANIMTYPE_DSWOR: + case ANIMTYPE_DSPART: + case ANIMTYPE_DSMBALL: + case ANIMTYPE_DSARM: + { + /* need to verify that this data is valid for now */ + if (ale->adt) { + ACHANNEL_SET_FLAG(ale->adt, sel, ADT_UI_SELECTED); + ale->adt->flag &= ~ADT_UI_ACTIVE; + } + } + break; } } @@ -1310,18 +1382,22 @@ static int mouse_anim_channels (bAnimContext *ac, float x, int channel_index, sh } /* action to take depends on what channel we've got */ + // WARNING: must keep this in sync with the equivalent function in nla_channels.c switch (ale->type) { case ANIMTYPE_SCENE: { Scene *sce= (Scene *)ale->data; + AnimData *adt= sce->adt; /* set selection status */ if (selectmode == SELECT_INVERT) { /* swap select */ sce->flag ^= SCE_DS_SELECTED; + if (adt) adt->flag ^= ADT_UI_SELECTED; } else { sce->flag |= SCE_DS_SELECTED; + if (adt) adt->flag |= ADT_UI_SELECTED; } notifierFlags |= ND_ANIMCHAN_SELECT; @@ -1333,34 +1409,75 @@ static int mouse_anim_channels (bAnimContext *ac, float x, int channel_index, sh Scene *sce= (Scene *)ads->source; Base *base= (Base *)ale->data; Object *ob= base->object; + AnimData *adt= ob->adt; /* set selection status */ if (selectmode == SELECT_INVERT) { /* swap select */ base->flag ^= SELECT; ob->flag= base->flag; + + if (adt) adt->flag ^= ADT_UI_SELECTED; } else { Base *b; - /* deleselect all */ + /* deselect all */ + // TODO: should this deselect all other types of channels too? for (b= sce->base.first; b; b= b->next) { b->flag &= ~SELECT; b->object->flag= b->flag; + if (b->object->adt) b->object->adt->flag &= ~(ADT_UI_SELECTED|ADT_UI_ACTIVE); } /* select object now */ base->flag |= SELECT; ob->flag |= SELECT; + if (adt) adt->flag |= ADT_UI_SELECTED; } /* xxx should be ED_base_object_activate(), but we need context pointer for that... */ //set_active_base(base); + if ((adt) && (adt->flag & ADT_UI_SELECTED)) + adt->flag |= ADT_UI_ACTIVE; notifierFlags |= ND_ANIMCHAN_SELECT; } break; + + case ANIMTYPE_FILLACTD: /* Action Expander */ + case ANIMTYPE_DSMAT: /* Datablock AnimData Expanders */ + case ANIMTYPE_DSLAM: + case ANIMTYPE_DSCAM: + case ANIMTYPE_DSCUR: + case ANIMTYPE_DSSKEY: + case ANIMTYPE_DSWOR: + case ANIMTYPE_DSPART: + case ANIMTYPE_DSMBALL: + case ANIMTYPE_DSARM: + { + /* sanity checking... */ + if (ale->adt) { + /* select/deselect */ + if (selectmode == SELECT_INVERT) { + /* inverse selection status of this AnimData block only */ + ale->adt->flag ^= ADT_UI_SELECTED; + } + else { + /* select AnimData block by itself */ + ANIM_deselect_anim_channels(ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR); + ale->adt->flag |= ADT_UI_SELECTED; + } + + /* set active? */ + if ((ale->adt) && (ale->adt->flag & ADT_UI_SELECTED)) + ale->adt->flag |= ADT_UI_ACTIVE; + } + notifierFlags |= ND_ANIMCHAN_SELECT; + } + break; + case ANIMTYPE_GROUP: { bActionGroup *agrp= (bActionGroup *)ale->data; diff --git a/source/blender/editors/animation/anim_draw.c b/source/blender/editors/animation/anim_draw.c index 6388106fdb5..507bf03e7ef 100644 --- a/source/blender/editors/animation/anim_draw.c +++ b/source/blender/editors/animation/anim_draw.c @@ -55,6 +55,7 @@ #include "ED_anim_api.h" #include "ED_keyframes_edit.h" +#include "ED_types.h" #include "ED_util.h" #include "WM_api.h" @@ -316,3 +317,52 @@ void ANIM_nla_mapping_apply_fcurve (AnimData *adt, FCurve *fcu, short restore, s } /* *************************************************** */ +/* ANIMATION EDITOR UI-WIDGETS */ + +/* ui button event */ +#define B_REDR 1 + +/* standard header buttons for Animation Editors */ +short ANIM_headerUI_standard_buttons (const bContext *C, bDopeSheet *ads, uiBlock *block, short xco, short yco) +{ + ScrArea *sa= CTX_wm_area(C); + short nlaActive= ((sa) && (sa->spacetype==SPACE_NLA)); + + /* check if the DopeSheet data exists, just in case... */ + if (ads) { + /* more 'generic' filtering options */ + if (nlaActive) uiBlockBeginAlign(block); + uiDefIconButBitI(block, TOG, ADS_FILTER_ONLYSEL, B_REDR, ICON_RESTRICT_SELECT_OFF, (short)(xco+=XIC),yco,XIC,YIC, &(ads->filterflag), 0, 0, 0, 0, "Only display selected Objects"); + if (nlaActive) uiDefIconButBitI(block, TOGN, ADS_FILTER_NLA_NOACT, B_REDR, ICON_ACTION, (short)(xco+=XIC),yco,XIC,YIC, &(ads->filterflag), 0, 0, 0, 0, "Include AnimData blocks with no NLA Data"); + if (nlaActive) uiBlockEndAlign(block); + xco += 5; + + /* datatype based */ + // TODO: only show the datablocks which exist + uiBlockBeginAlign(block); + uiDefIconButBitI(block, TOGN, ADS_FILTER_NOSCE, B_REDR, ICON_SCENE_DATA, (short)(xco+=XIC),yco,XIC,YIC, &(ads->filterflag), 0, 0, 0, 0, "Display Scene Animation"); + uiDefIconButBitI(block, TOGN, ADS_FILTER_NOWOR, B_REDR, ICON_WORLD_DATA, (short)(xco+=XIC),yco,XIC,YIC, &(ads->filterflag), 0, 0, 0, 0, "Display World Animation"); + uiDefIconButBitI(block, TOGN, ADS_FILTER_NOSHAPEKEYS, B_REDR, ICON_SHAPEKEY_DATA, (short)(xco+=XIC),yco,XIC,YIC, &(ads->filterflag), 0, 0, 0, 0, "Display ShapeKeys"); + uiDefIconButBitI(block, TOGN, ADS_FILTER_NOMAT, B_REDR, ICON_MATERIAL_DATA, (short)(xco+=XIC),yco,XIC,YIC, &(ads->filterflag), 0, 0, 0, 0, "Display Material Data"); + uiDefIconButBitI(block, TOGN, ADS_FILTER_NOLAM, B_REDR, ICON_LAMP_DATA, (short)(xco+=XIC),yco,XIC,YIC, &(ads->filterflag), 0, 0, 0, 0, "Display Lamp Data"); + uiDefIconButBitI(block, TOGN, ADS_FILTER_NOCAM, B_REDR, ICON_CAMERA_DATA, (short)(xco+=XIC),yco,XIC,YIC, &(ads->filterflag), 0, 0, 0, 0, "Display Camera Data"); + uiDefIconButBitI(block, TOGN, ADS_FILTER_NOCUR, B_REDR, ICON_CURVE_DATA, (short)(xco+=XIC),yco,XIC,YIC, &(ads->filterflag), 0, 0, 0, 0, "Display Curve Data"); + uiDefIconButBitI(block, TOGN, ADS_FILTER_NOMBA, B_REDR, ICON_META_DATA, (short)(xco+=XIC),yco,XIC,YIC, &(ads->filterflag), 0, 0, 0, 0, "Display MetaBall Data"); + uiDefIconButBitI(block, TOGN, ADS_FILTER_NOARM, B_REDR, ICON_ARMATURE_DATA, (short)(xco+=XIC),yco,XIC,YIC, &(ads->filterflag), 0, 0, 0, 0, "Display Armature Data"); + uiDefIconButBitI(block, TOGN, ADS_FILTER_NOPART, B_REDR, ICON_PARTICLE_DATA, (short)(xco+=XIC),yco,XIC,YIC, &(ads->filterflag), 0, 0, 0, 0, "Display Particle Data"); + uiBlockEndAlign(block); + xco += 30; + } + else { + // XXX this case shouldn't happen at all... for now, just pad out same amount of space + printf("ERROR: dopesheet data not available when drawing Animation Editor header \n"); + xco += 11*XIC + 30; + } + + // TODO: include auto-snapping menu here too... + + /* return the width of the buttons */ + return xco; +} + +/* *************************************************** */ diff --git a/source/blender/editors/animation/anim_filter.c b/source/blender/editors/animation/anim_filter.c index 55fb1ccace0..13b050e4497 100644 --- a/source/blender/editors/animation/anim_filter.c +++ b/source/blender/editors/animation/anim_filter.c @@ -52,6 +52,7 @@ #include "DNA_ID.h" #include "DNA_anim_types.h" #include "DNA_action_types.h" +#include "DNA_armature_types.h" #include "DNA_constraint_types.h" #include "DNA_camera_types.h" #include "DNA_curve_types.h" @@ -412,7 +413,9 @@ short ANIM_animdata_get_context (const bContext *C, bAnimContext *ac) }\ } - +/* quick macro to test if an anim-channel representing an AnimData block is suitably active */ +#define ANIMCHANNEL_ACTIVEOK(ale) \ + ( !(filter_mode & ANIMFILTER_ACTIVE) || !(ale->adt) || (ale->adt->flag & ADT_UI_ACTIVE) ) /* quick macro to test if an anim-channel (F-Curve, Group, etc.) is selected in an acceptable way */ #define ANIMCHANNEL_SELOK(test_func) \ @@ -979,10 +982,13 @@ static int animdata_filter_dopesheet_mats (ListBase *anim_data, bDopeSheet *ads, /* include material-expand widget? */ // hmm... do we need to store the index of this material in the array anywhere? if (filter_mode & ANIMFILTER_CHANNELS) { - ale= make_new_animlistelem(ma, ANIMTYPE_DSMAT, base, ANIMTYPE_OBJECT, (ID *)ma); - if (ale) { - BLI_addtail(anim_data, ale); - items++; + /* check if filtering by active status */ + if ANIMCHANNEL_ACTIVEOK(ma) { + ale= make_new_animlistelem(ma, ANIMTYPE_DSMAT, base, ANIMTYPE_OBJECT, (ID *)ma); + if (ale) { + BLI_addtail(anim_data, ale); + items++; + } } } @@ -1036,11 +1042,14 @@ static int animdata_filter_dopesheet_particles (ListBase *anim_data, bDopeSheet /* add particle settings? */ if (FILTER_PART_OBJC(ob) || (filter_mode & ANIMFILTER_CURVESONLY)) { - if ((filter_mode & ANIMFILTER_CHANNELS)){ - ale = make_new_animlistelem(psys->part, ANIMTYPE_DSPART, base, ANIMTYPE_OBJECT, (ID *)psys->part); - if (ale) { - BLI_addtail(anim_data, ale); - items++; + if ((filter_mode & ANIMFILTER_CHANNELS)) { + /* check if filtering by active status */ + if ANIMCHANNEL_ACTIVEOK(psys->part) { + ale = make_new_animlistelem(psys->part, ANIMTYPE_DSPART, base, ANIMTYPE_OBJECT, (ID *)psys->part); + if (ale) { + BLI_addtail(anim_data, ale); + items++; + } } } @@ -1101,6 +1110,14 @@ static int animdata_filter_dopesheet_obdata (ListBase *anim_data, bDopeSheet *ad expanded= FILTER_MBALL_OBJD(mb); } break; + case OB_ARMATURE: /* ------- Armature ---------- */ + { + bArmature *arm= (bArmature *)ob->data; + + type= ANIMTYPE_DSARM; + expanded= FILTER_ARM_OBJD(arm); + } + break; } /* special exception for drivers instead of action */ @@ -1108,9 +1125,12 @@ static int animdata_filter_dopesheet_obdata (ListBase *anim_data, bDopeSheet *ad expanded= EXPANDED_DRVD(adt); /* include data-expand widget? */ - if ((filter_mode & ANIMFILTER_CURVESONLY) == 0) { - ale= make_new_animlistelem(iat, type, base, ANIMTYPE_OBJECT, (ID *)iat); - if (ale) BLI_addtail(anim_data, ale); + if ((filter_mode & ANIMFILTER_CURVESONLY) == 0) { + /* check if filtering by active status */ + if ANIMCHANNEL_ACTIVEOK(iat) { + ale= make_new_animlistelem(iat, type, base, ANIMTYPE_OBJECT, (ID *)iat); + if (ale) BLI_addtail(anim_data, ale); + } } /* add object-data animation channels? */ @@ -1140,10 +1160,13 @@ static int animdata_filter_dopesheet_ob (ListBase *anim_data, bDopeSheet *ads, B if ((filter_mode & (ANIMFILTER_CURVESONLY|ANIMFILTER_NLATRACKS)) == 0) { /* check if filtering by selection */ if ANIMCHANNEL_SELOK((base->flag & SELECT)) { - ale= make_new_animlistelem(base, ANIMTYPE_OBJECT, NULL, ANIMTYPE_NONE, NULL); - if (ale) { - BLI_addtail(anim_data, ale); - items++; + /* check if filtering by active status */ + if ANIMCHANNEL_ACTIVEOK(ob) { + ale= make_new_animlistelem(base, ANIMTYPE_OBJECT, NULL, ANIMTYPE_NONE, (ID *)ob); + if (ale) { + BLI_addtail(anim_data, ale); + items++; + } } } } @@ -1203,8 +1226,21 @@ static int animdata_filter_dopesheet_ob (ListBase *anim_data, bDopeSheet *ads, B ANIMDATA_FILTER_CASES(key, { /* AnimData blocks - do nothing... */ }, { /* nla */ - /* add NLA tracks */ - items += animdata_filter_nla(anim_data, adt, filter_mode, ob, ANIMTYPE_OBJECT, (ID *)ob); + /* include shapekey-expand widget? */ + if ((filter_mode & ANIMFILTER_CHANNELS) && !(filter_mode & ANIMFILTER_CURVESONLY)) { + /* check if filtering by active status */ + if ANIMCHANNEL_ACTIVEOK(key) { + ale= make_new_animlistelem(key, ANIMTYPE_DSSKEY, base, ANIMTYPE_OBJECT, (ID *)ob); + if (ale) { + BLI_addtail(anim_data, ale); + items++; + } + } + } + + /* add NLA tracks - only if expanded or so */ + if (FILTER_SKE_OBJD(key) || (filter_mode & ANIMFILTER_CURVESONLY)) + items += animdata_filter_nla(anim_data, adt, filter_mode, ob, ANIMTYPE_OBJECT, (ID *)ob); }, { /* drivers */ /* include shapekey-expand widget? */ @@ -1224,10 +1260,13 @@ static int animdata_filter_dopesheet_ob (ListBase *anim_data, bDopeSheet *ads, B { /* action (keyframes) */ /* include shapekey-expand widget? */ if ((filter_mode & ANIMFILTER_CHANNELS) && !(filter_mode & ANIMFILTER_CURVESONLY)) { - ale= make_new_animlistelem(key, ANIMTYPE_DSSKEY, base, ANIMTYPE_OBJECT, (ID *)ob); - if (ale) { - BLI_addtail(anim_data, ale); - items++; + /* check if filtering by active status */ + if ANIMCHANNEL_ACTIVEOK(key) { + ale= make_new_animlistelem(key, ANIMTYPE_DSSKEY, base, ANIMTYPE_OBJECT, (ID *)ob); + if (ale) { + BLI_addtail(anim_data, ale); + items++; + } } } @@ -1297,6 +1336,19 @@ static int animdata_filter_dopesheet_ob (ListBase *anim_data, bDopeSheet *ads, B } } break; + case OB_ARMATURE: /* ------- Armature ---------- */ + { + bArmature *arm= (bArmature *)ob->data; + + if ((ads->filterflag & ADS_FILTER_NOARM) == 0) { + ANIMDATA_FILTER_CASES(arm, + { /* AnimData blocks - do nothing... */ }, + obdata_ok= 1;, + obdata_ok= 1;, + obdata_ok= 1;) + } + } + break; } if (obdata_ok) items += animdata_filter_dopesheet_obdata(anim_data, ads, base, filter_mode); @@ -1652,6 +1704,23 @@ static int animdata_filter_dopesheet (ListBase *anim_data, bDopeSheet *ads, int dataOk= !(ads->filterflag & ADS_FILTER_NOMBA);) } break; + case OB_ARMATURE: /* ------- Armature ---------- */ + { + bArmature *arm= (bArmature *)ob->data; + dataOk= 0; + ANIMDATA_FILTER_CASES(arm, + if ((ads->filterflag & ADS_FILTER_NOARM)==0) { + /* for the special AnimData blocks only case, we only need to add + * the block if it is valid... then other cases just get skipped (hence ok=0) + */ + ANIMDATA_ADD_ANIMDATA(arm); + dataOk=0; + }, + dataOk= !(ads->filterflag & ADS_FILTER_NOARM);, + dataOk= !(ads->filterflag & ADS_FILTER_NOARM);, + dataOk= !(ads->filterflag & ADS_FILTER_NOARM);) + } + break; default: /* --- other --- */ dataOk= 0; break; @@ -1734,6 +1803,12 @@ static int animdata_filter_dopesheet (ListBase *anim_data, bDopeSheet *ads, int dataOk= ANIMDATA_HAS_KEYS(mb); } break; + case OB_ARMATURE: /* -------- Armature ---------- */ + { + bArmature *arm= (bArmature *)ob->data; + dataOk= ANIMDATA_HAS_KEYS(arm); + } + break; default: /* --- other --- */ dataOk= 0; break; diff --git a/source/blender/editors/animation/anim_ops.c b/source/blender/editors/animation/anim_ops.c index 80077a6d4b3..a4038028062 100644 --- a/source/blender/editors/animation/anim_ops.c +++ b/source/blender/editors/animation/anim_ops.c @@ -193,7 +193,7 @@ static int change_frame_modal(bContext *C, wmOperator *op, wmEvent *event) /* we check for either mouse-button to end, as checking for ACTIONMOUSE (which is used to init * the modal op) doesn't work for some reason */ - if (event->val==0) { + if (event->val==KM_RELEASE) { change_frame_exit(C, op); return OPERATOR_FINISHED; } @@ -399,6 +399,8 @@ void ED_operatortypes_anim(void) WM_operatortype_append(ANIM_OT_add_driver_button); WM_operatortype_append(ANIM_OT_remove_driver_button); + WM_operatortype_append(ANIM_OT_copy_driver_button); + WM_operatortype_append(ANIM_OT_paste_driver_button); WM_operatortype_append(ANIM_OT_add_keyingset_button); WM_operatortype_append(ANIM_OT_remove_keyingset_button); diff --git a/source/blender/editors/animation/drivers.c b/source/blender/editors/animation/drivers.c index 8b9224511ba..363a5a80f00 100644 --- a/source/blender/editors/animation/drivers.c +++ b/source/blender/editors/animation/drivers.c @@ -80,6 +80,10 @@ /* Get (or add relevant data to be able to do so) F-Curve from the driver stack, * for the given Animation Data block. This assumes that all the destinations are valid. + * + * - add: 0 - don't add anything if not found, + * 1 - add new Driver FCurve, + * -1 - add new Driver FCurve without driver stuff (for pasting) */ FCurve *verify_driver_fcurve (ID *id, const char rna_path[], const int array_index, short add) { @@ -115,11 +119,14 @@ FCurve *verify_driver_fcurve (ID *id, const char rna_path[], const int array_ind fcu->rna_path= BLI_strdupn(rna_path, strlen(rna_path)); fcu->array_index= array_index; - /* add some new driver data */ - fcu->driver= MEM_callocN(sizeof(ChannelDriver), "ChannelDriver"); - - /* add simple generator modifier for driver so that there is some visible representation */ - add_fmodifier(&fcu->modifiers, FMODIFIER_TYPE_GENERATOR); + /* if add is negative, don't init this data yet, since it will be filled in by the pasted driver */ + if (add > 0) { + /* add some new driver data */ + fcu->driver= MEM_callocN(sizeof(ChannelDriver), "ChannelDriver"); + + /* add simple generator modifier for driver so that there is some visible representation */ + add_fmodifier(&fcu->modifiers, FMODIFIER_TYPE_GENERATOR); + } /* just add F-Curve to end of driver list */ BLI_addtail(&adt->drivers, fcu); @@ -144,7 +151,7 @@ short ANIM_add_driver (ID *id, const char rna_path[], int array_index, short fla /* validate pointer first - exit if failure */ RNA_id_pointer_create(id, &id_ptr); if ((RNA_path_resolve(&id_ptr, rna_path, &ptr, &prop) == 0) || (prop == NULL)) { - printf("Insert Key: Could not add Driver, as RNA Path is invalid for the given ID (ID = %s, Path = %s)\n", id->name, rna_path); + printf("Add Driver: Could not add Driver, as RNA Path is invalid for the given ID (ID = %s, Path = %s)\n", id->name, rna_path); return 0; } @@ -163,7 +170,7 @@ short ANIM_add_driver (ID *id, const char rna_path[], int array_index, short fla float fval; if (proptype == PROP_BOOLEAN) { - if(!array) val= RNA_property_boolean_get(&ptr, prop); + if (!array) val= RNA_property_boolean_get(&ptr, prop); else val= RNA_property_boolean_get_index(&ptr, prop, array_index); BLI_strncpy(expression, (val)? "True": "False", maxlen); @@ -180,7 +187,6 @@ short ANIM_add_driver (ID *id, const char rna_path[], int array_index, short fla BLI_snprintf(expression, maxlen, "%.3f", fval); } - } } @@ -218,6 +224,127 @@ short ANIM_remove_driver (struct ID *id, const char rna_path[], int array_index, return 0; } +/* ************************************************** */ +/* Driver Management API - Copy/Paste Drivers */ + +/* Copy/Paste Buffer for Driver Data... */ +static FCurve *channeldriver_copypaste_buf = NULL; + +/* This function frees any MEM_calloc'ed copy/paste buffer data */ +// XXX find some header to put this in! +void free_anim_drivers_copybuf (void) +{ + /* free the buffer F-Curve if it exists, as if it were just another F-Curve */ + if (channeldriver_copypaste_buf) + free_fcurve(channeldriver_copypaste_buf); + channeldriver_copypaste_buf= NULL; +} + +/* Checks if there is a driver in the copy/paste buffer */ +short ANIM_driver_can_paste (void) +{ + return (channeldriver_copypaste_buf != NULL); +} + +/* ------------------- */ + +/* Main Driver Management API calls: + * Make a copy of the driver for the specified property on the given ID block + */ +short ANIM_copy_driver (ID *id, const char rna_path[], int array_index, short flag) +{ + PointerRNA id_ptr, ptr; + PropertyRNA *prop; + FCurve *fcu; + + /* validate pointer first - exit if failure */ + RNA_id_pointer_create(id, &id_ptr); + if ((RNA_path_resolve(&id_ptr, rna_path, &ptr, &prop) == 0) || (prop == NULL)) { + printf("Copy Driver: Could not find Driver, as RNA Path is invalid for the given ID (ID = %s, Path = %s)\n", id->name, rna_path); + return 0; + } + + /* try to get F-Curve with Driver */ + fcu= verify_driver_fcurve(id, rna_path, array_index, 0); + + /* clear copy/paste buffer first (for consistency with other copy/paste buffers) */ + free_anim_drivers_copybuf(); + + /* copy this to the copy/paste buf if it exists */ + if (fcu && fcu->driver) { + /* make copies of some info such as the rna_path, then clear this info from the F-Curve temporarily + * so that we don't end up wasting memory storing the path which won't get used ever... + */ + char *tmp_path = fcu->rna_path; + fcu->rna_path= NULL; + + /* make a copy of the F-Curve with */ + channeldriver_copypaste_buf= copy_fcurve(fcu); + + /* restore the path */ + fcu->rna_path= tmp_path; + + /* copied... */ + return 1; + } + + /* done */ + return 0; +} + +/* Main Driver Management API calls: + * Add a new driver for the specified property on the given ID block or replace an existing one + * with the driver + driver-curve data from the buffer + */ +short ANIM_paste_driver (ID *id, const char rna_path[], int array_index, short flag) +{ + PointerRNA id_ptr, ptr; + PropertyRNA *prop; + FCurve *fcu; + + /* validate pointer first - exit if failure */ + RNA_id_pointer_create(id, &id_ptr); + if ((RNA_path_resolve(&id_ptr, rna_path, &ptr, &prop) == 0) || (prop == NULL)) { + printf("Paste Driver: Could not add Driver, as RNA Path is invalid for the given ID (ID = %s, Path = %s)\n", id->name, rna_path); + return 0; + } + + /* if the buffer is empty, cannot paste... */ + if (channeldriver_copypaste_buf == NULL) { + printf("Paste Driver: No Driver to paste. \n"); + return 0; + } + + /* create Driver F-Curve, but without data which will be copied across... */ + fcu= verify_driver_fcurve(id, rna_path, array_index, -1); + + if (fcu) { + /* copy across the curve data from the buffer curve + * NOTE: this step needs care to not miss new settings + */ + /* keyframes/samples */ + fcu->bezt= MEM_dupallocN(channeldriver_copypaste_buf->bezt); + fcu->fpt= MEM_dupallocN(channeldriver_copypaste_buf->fpt); + fcu->totvert= channeldriver_copypaste_buf->totvert; + + /* modifiers */ + copy_fmodifiers(&fcu->modifiers, &channeldriver_copypaste_buf->modifiers); + + /* flags - on a per-relevant-flag basis */ + if (channeldriver_copypaste_buf->flag & FCURVE_AUTO_HANDLES) + fcu->flag |= FCURVE_AUTO_HANDLES; + else + fcu->flag &= ~FCURVE_AUTO_HANDLES; + /* extrapolation mode */ + fcu->extend= channeldriver_copypaste_buf->extend; + + /* the 'juicy' stuff - the driver */ + fcu->driver= fcurve_copy_driver(channeldriver_copypaste_buf->driver); + } + + /* done */ + return (fcu != NULL); +} /* ************************************************** */ /* UI-Button Interface */ @@ -272,10 +399,11 @@ void ANIM_OT_add_driver_button (wmOperatorType *ot) /* identifiers */ ot->name= "Add Driver"; ot->idname= "ANIM_OT_add_driver_button"; + ot->description= "Add driver(s) for the property(s) connected represented by the highlighted button."; /* callbacks */ ot->exec= add_driver_button_exec; - //op->poll= ??? + //op->poll= ??? // TODO: need to have some animateable property to do this /* flags */ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; @@ -335,10 +463,11 @@ void ANIM_OT_remove_driver_button (wmOperatorType *ot) /* identifiers */ ot->name= "Remove Driver"; ot->idname= "ANIM_OT_remove_driver_button"; + ot->description= "Remove the driver(s) for the property(s) connected represented by the highlighted button."; /* callbacks */ ot->exec= remove_driver_button_exec; - //op->poll= ??? + //op->poll= ??? // TODO: need to have some driver to be able to do this... /* flags */ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; @@ -347,4 +476,92 @@ void ANIM_OT_remove_driver_button (wmOperatorType *ot) RNA_def_boolean(ot->srna, "all", 1, "All", "Delete drivers for all elements of the array."); } +/* Copy Driver Button Operator ------------------------ */ + +static int copy_driver_button_exec (bContext *C, wmOperator *op) +{ + PointerRNA ptr; + PropertyRNA *prop= NULL; + char *path; + short success= 0; + int index; + + /* try to create driver using property retrieved from UI */ + memset(&ptr, 0, sizeof(PointerRNA)); + uiAnimContextProperty(C, &ptr, &prop, &index); + + if (ptr.data && prop && RNA_property_animateable(ptr.data, prop)) { + path= RNA_path_from_ID_to_property(&ptr, prop); + + if (path) { + /* only copy the driver for the button that this was involved for */ + success= ANIM_copy_driver(ptr.id.data, path, index, 0); + + MEM_freeN(path); + } + } + + /* since we're just copying, we don't really need to do anything else...*/ + return (success)? OPERATOR_FINISHED: OPERATOR_CANCELLED; +} + +void ANIM_OT_copy_driver_button (wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Copy Driver"; + ot->idname= "ANIM_OT_copy_driver_button"; + ot->description= "Copy the driver for the highlighted button."; + + /* callbacks */ + ot->exec= copy_driver_button_exec; + //op->poll= ??? // TODO: need to have some driver to be able to do this... + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; +} + +/* Paste Driver Button Operator ------------------------ */ + +static int paste_driver_button_exec (bContext *C, wmOperator *op) +{ + PointerRNA ptr; + PropertyRNA *prop= NULL; + char *path; + short success= 0; + int index; + + /* try to create driver using property retrieved from UI */ + memset(&ptr, 0, sizeof(PointerRNA)); + uiAnimContextProperty(C, &ptr, &prop, &index); + + if (ptr.data && prop && RNA_property_animateable(ptr.data, prop)) { + path= RNA_path_from_ID_to_property(&ptr, prop); + + if (path) { + /* only copy the driver for the button that this was involved for */ + success= ANIM_paste_driver(ptr.id.data, path, index, 0); + + MEM_freeN(path); + } + } + + /* since we're just copying, we don't really need to do anything else...*/ + return (success)? OPERATOR_FINISHED: OPERATOR_CANCELLED; +} + +void ANIM_OT_paste_driver_button (wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Paste Driver"; + ot->idname= "ANIM_OT_paste_driver_button"; + ot->description= "Paste the driver in the copy/paste buffer for the highlighted button."; + + /* callbacks */ + ot->exec= paste_driver_button_exec; + //op->poll= ??? // TODO: need to have some driver to be able to do this... + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; +} + /* ************************************************** */ diff --git a/source/blender/editors/animation/keyframes_draw.c b/source/blender/editors/animation/keyframes_draw.c index abea38e129e..e8b25f70b06 100644 --- a/source/blender/editors/animation/keyframes_draw.c +++ b/source/blender/editors/animation/keyframes_draw.c @@ -316,7 +316,7 @@ static void set_touched_actkeyblock (ActKeyBlock *ab) /* *************************** Keyframe Drawing *************************** */ /* helper function - find actkeycolumn that occurs on cframe */ -static ActKeyColumn *cfra_find_actkeycolumn (ActKeyColumn *ak, float cframe) +ActKeyColumn *cfra_find_actkeycolumn (ActKeyColumn *ak, float cframe) { /* sanity checks */ if (ak == NULL) @@ -331,6 +331,29 @@ static ActKeyColumn *cfra_find_actkeycolumn (ActKeyColumn *ak, float cframe) return ak; /* match */ } +/* helper function - find actkeycolumn that occurs on cframe, or the nearest one if not found */ +// FIXME: this is buggy... next() is ignored completely... +ActKeyColumn *cfra_find_nearest_next_ak (ActKeyColumn *ak, float cframe, short next) +{ + ActKeyColumn *akn= NULL; + + /* sanity checks */ + if (ak == NULL) + return NULL; + + /* check if this is a match, or whether it is in some subtree */ + if (cframe < ak->cfra) + akn= cfra_find_nearest_next_ak(ak->left, cframe, next); + else if (cframe > ak->cfra) + akn= cfra_find_nearest_next_ak(ak->right, cframe, next); + + /* if no match found (or found match), just use the current one */ + if (akn == NULL) + return ak; + else + return akn; +} + /* -------- */ /* coordinates for diamond shape */ @@ -396,6 +419,13 @@ void draw_keyframe_shape (float x, float y, float xscale, float hsize, short sel } break; + case BEZT_KEYTYPE_EXTREME: /* redish frames for now */ + { + if (sel) glColor3f(95.0f, 0.5f, 0.5f); + else glColor3f(0.91f, 0.70f, 0.80f); + } + break; + case BEZT_KEYTYPE_KEYFRAME: /* traditional yellowish frames for now */ default: { diff --git a/source/blender/editors/animation/keyframes_edit.c b/source/blender/editors/animation/keyframes_edit.c index ac04dc7d1a8..65f7d845b29 100644 --- a/source/blender/editors/animation/keyframes_edit.c +++ b/source/blender/editors/animation/keyframes_edit.c @@ -461,6 +461,13 @@ static short snap_bezier_horizontal(BeztEditData *bed, BezTriple *bezt) return 0; } +static short snap_bezier_value(BeztEditData *bed, BezTriple *bezt) +{ + /* value to snap to is stored in the custom data -> first float value slot */ + if (bezt->f2 & SELECT) + bezt->vec[1][1]= bed->f1; + return 0; +} BeztEditFunc ANIM_editkeyframes_snap(short type) { @@ -476,6 +483,8 @@ BeztEditFunc ANIM_editkeyframes_snap(short type) return snap_bezier_nearestsec; case SNAP_KEYS_HORIZONTAL: /* snap handles to same value */ return snap_bezier_horizontal; + case SNAP_KEYS_VALUE: /* snap to given value */ + return snap_bezier_value; default: /* just in case */ return snap_bezier_nearest; } @@ -685,6 +694,13 @@ static short set_keytype_breakdown(BeztEditData *bed, BezTriple *bezt) return 0; } +static short set_keytype_extreme(BeztEditData *bed, BezTriple *bezt) +{ + if (bezt->f2 & SELECT) + BEZKEYTYPE(bezt)= BEZT_KEYTYPE_EXTREME; + return 0; +} + /* Set the interpolation type of the selected BezTriples in each F-Curve to the specified one */ BeztEditFunc ANIM_editkeyframes_keytype(short code) { @@ -692,6 +708,9 @@ BeztEditFunc ANIM_editkeyframes_keytype(short code) case BEZT_KEYTYPE_BREAKDOWN: /* breakdown */ return set_keytype_breakdown; + case BEZT_KEYTYPE_EXTREME: /* extreme keyframe */ + return set_keytype_extreme; + case BEZT_KEYTYPE_KEYFRAME: /* proper keyframe */ default: return set_keytype_keyframe; diff --git a/source/blender/editors/animation/keyframing.c b/source/blender/editors/animation/keyframing.c index 7135f8802bc..e3e72a532e2 100644 --- a/source/blender/editors/animation/keyframing.c +++ b/source/blender/editors/animation/keyframing.c @@ -176,85 +176,6 @@ FCurve *verify_fcurve (bAction *act, const char group[], const char rna_path[], /* -------------- BezTriple Insertion -------------------- */ -/* threshold for inserting keyframes - threshold here should be good enough for now, but should become userpref */ -#define BEZT_INSERT_THRESH 0.00001f - -/* Binary search algorithm for finding where to insert BezTriple. (for use by insert_bezt_icu) - * Returns the index to insert at (data already at that index will be offset if replace is 0) - */ -static int binarysearch_bezt_index (BezTriple array[], float frame, int arraylen, short *replace) -{ - int start=0, end=arraylen; - int loopbreaker= 0, maxloop= arraylen * 2; - - /* initialise replace-flag first */ - *replace= 0; - - /* sneaky optimisations (don't go through searching process if...): - * - keyframe to be added is to be added out of current bounds - * - keyframe to be added would replace one of the existing ones on bounds - */ - if ((arraylen <= 0) || (array == NULL)) { - printf("Warning: binarysearch_bezt_index() encountered invalid array \n"); - return 0; - } - else { - /* check whether to add before/after/on */ - float framenum; - - /* 'First' Keyframe (when only one keyframe, this case is used) */ - framenum= array[0].vec[1][0]; - if (IS_EQT(frame, framenum, BEZT_INSERT_THRESH)) { - *replace = 1; - return 0; - } - else if (frame < framenum) - return 0; - - /* 'Last' Keyframe */ - framenum= array[(arraylen-1)].vec[1][0]; - if (IS_EQT(frame, framenum, BEZT_INSERT_THRESH)) { - *replace= 1; - return (arraylen - 1); - } - else if (frame > framenum) - return arraylen; - } - - - /* most of the time, this loop is just to find where to put it - * 'loopbreaker' is just here to prevent infinite loops - */ - for (loopbreaker=0; (start <= end) && (loopbreaker < maxloop); loopbreaker++) { - /* compute and get midpoint */ - int mid = start + ((end - start) / 2); /* we calculate the midpoint this way to avoid int overflows... */ - float midfra= array[mid].vec[1][0]; - - /* check if exactly equal to midpoint */ - if (IS_EQT(frame, midfra, BEZT_INSERT_THRESH)) { - *replace = 1; - return mid; - } - - /* repeat in upper/lower half */ - if (frame > midfra) - start= mid + 1; - else if (frame < midfra) - end= mid - 1; - } - - /* print error if loop-limit exceeded */ - if (loopbreaker == (maxloop-1)) { - printf("Error: binarysearch_bezt_index() was taking too long \n"); - - // include debug info - printf("\tround = %d: start = %d, end = %d, arraylen = %d \n", loopbreaker, start, end, arraylen); - } - - /* not found, so return where to place it */ - return start; -} - /* This function adds a given BezTriple to an F-Curve. It will allocate * memory for the array if needed, and will insert the BezTriple into a * suitable place in chronological order. @@ -286,8 +207,13 @@ int insert_bezt_fcurve (FCurve *fcu, BezTriple *bezt, short flag) // TODO: perform some other operations? } else { + char oldKeyType= BEZKEYTYPE(fcu->bezt + i); + /* just brutally replace the values */ *(fcu->bezt + i) = *bezt; + + /* special exception for keyframe type - copy value back so that this info isn't lost */ + BEZKEYTYPE(fcu->bezt + i)= oldKeyType; } } } diff --git a/source/blender/editors/armature/armature_intern.h b/source/blender/editors/armature/armature_intern.h index 0c8c0e8e644..6f5a5f44d87 100644 --- a/source/blender/editors/armature/armature_intern.h +++ b/source/blender/editors/armature/armature_intern.h @@ -118,12 +118,20 @@ void SKETCH_OT_select(struct wmOperatorType *ot); /* ******************************************************* */ /* PoseLib */ + void POSELIB_OT_pose_add(struct wmOperatorType *ot); void POSELIB_OT_pose_remove(struct wmOperatorType *ot); void POSELIB_OT_pose_rename(struct wmOperatorType *ot); void POSELIB_OT_browse_interactive(struct wmOperatorType *ot); /* ******************************************************* */ +/* Pose Sliding Tools */ + +void POSE_OT_push(struct wmOperatorType *ot); +void POSE_OT_relax(struct wmOperatorType *ot); +void POSE_OT_breakdown(struct wmOperatorType *ot); + +/* ******************************************************* */ /* editarmature.c */ struct bArmature; struct EditBone; diff --git a/source/blender/editors/armature/armature_ops.c b/source/blender/editors/armature/armature_ops.c index 9076b533974..fae0b093551 100644 --- a/source/blender/editors/armature/armature_ops.c +++ b/source/blender/editors/armature/armature_ops.c @@ -196,6 +196,11 @@ void ED_operatortypes_armature(void) WM_operatortype_append(POSELIB_OT_pose_remove); WM_operatortype_append(POSELIB_OT_pose_rename); + /* POSE SLIDING */ + WM_operatortype_append(POSE_OT_push); + WM_operatortype_append(POSE_OT_relax); + WM_operatortype_append(POSE_OT_breakdown); + /* TESTS */ WM_operatortype_append(ARMATURE_OT_test); // XXX temp test for context iterators... to be removed } @@ -293,6 +298,9 @@ void ED_keymap_armature(wmWindowManager *wm) keymap= WM_keymap_find(wm, "Pose", 0, 0); keymap->poll= ED_operator_posemode; + // XXX: set parent is object-based operator, but it should also be available here... + WM_keymap_add_item(keymap, "OBJECT_OT_parent_set", PKEY, KM_PRESS, KM_CTRL, 0); + WM_keymap_add_item(keymap, "POSE_OT_hide", HKEY, KM_PRESS, 0, 0); kmi= WM_keymap_add_item(keymap, "POSE_OT_hide", HKEY, KM_PRESS, KM_SHIFT, 0); RNA_boolean_set(kmi->ptr, "unselected", 1); @@ -305,7 +313,6 @@ void ED_keymap_armature(wmWindowManager *wm) WM_keymap_add_item(keymap, "POSE_OT_loc_clear", GKEY, KM_PRESS, KM_ALT, 0); WM_keymap_add_item(keymap, "POSE_OT_scale_clear", SKEY, KM_PRESS, KM_ALT, 0); - // for now, we include hotkeys for copy/paste WM_keymap_add_item(keymap, "POSE_OT_copy", CKEY, KM_PRESS, KM_CTRL, 0); WM_keymap_add_item(keymap, "POSE_OT_paste", VKEY, KM_PRESS, KM_CTRL, 0); kmi= WM_keymap_add_item(keymap, "POSE_OT_paste", VKEY, KM_PRESS, KM_CTRL|KM_SHIFT, 0); @@ -365,5 +372,11 @@ void ED_keymap_armature(wmWindowManager *wm) WM_keymap_add_item(keymap, "POSELIB_OT_pose_add", LKEY, KM_PRESS, KM_SHIFT, 0); WM_keymap_add_item(keymap, "POSELIB_OT_pose_remove", LKEY, KM_PRESS, KM_ALT, 0); WM_keymap_add_item(keymap, "POSELIB_OT_pose_rename", LKEY, KM_PRESS, KM_CTRL|KM_SHIFT, 0); + + /* Pose -> Pose Sliding ------------- */ + /* only set in posemode, by space_view3d listener */ + WM_keymap_add_item(keymap, "POSE_OT_push", EKEY, KM_PRESS, KM_CTRL, 0); + WM_keymap_add_item(keymap, "POSE_OT_relax", EKEY, KM_PRESS, KM_ALT, 0); + WM_keymap_add_item(keymap, "POSE_OT_breakdown", EKEY, KM_PRESS, KM_SHIFT, 0); } diff --git a/source/blender/editors/armature/editarmature.c b/source/blender/editors/armature/editarmature.c index 7d196d23c98..5f8c503e854 100644 --- a/source/blender/editors/armature/editarmature.c +++ b/source/blender/editors/armature/editarmature.c @@ -1736,7 +1736,7 @@ static int armature_delete_selected_exec(bContext *C, wmOperator *op) ED_armature_sync_selection(arm->edbo); - WM_event_add_notifier(C, NC_OBJECT, obedit); + WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, obedit); return OPERATOR_FINISHED; } @@ -2539,6 +2539,8 @@ EditBone *duplicateEditBoneObjects(EditBone *curBone, char *name, ListBase *edit VECCOPY(channew->limitmax, chanold->limitmax); VECCOPY(channew->stiffness, chanold->stiffness); channew->ikstretch= chanold->ikstretch; + channew->ikrotweight= chanold->ikrotweight; + channew->iklinweight= chanold->iklinweight; /* constraints */ listnew = &channew->constraints; @@ -2630,6 +2632,9 @@ static int armature_duplicate_selected_exec(bContext *C, wmOperator *op) /* copy transform locks */ channew->protectflag = chanold->protectflag; + /* copy rotation mode */ + channew->rotmode = chanold->rotmode; + /* copy bone group */ channew->agrp_index= chanold->agrp_index; @@ -2639,6 +2644,8 @@ static int armature_duplicate_selected_exec(bContext *C, wmOperator *op) VECCOPY(channew->limitmax, chanold->limitmax); VECCOPY(channew->stiffness, chanold->stiffness); channew->ikstretch= chanold->ikstretch; + channew->ikrotweight= chanold->ikrotweight; + channew->iklinweight= chanold->iklinweight; /* constraints */ listnew = &channew->constraints; @@ -3441,7 +3448,8 @@ static int armature_bone_primitive_add_exec(bContext *C, wmOperator *op) else VecAddf(bone->tail, bone->head, imat[2]); // bone with unit length 1, pointing up Z - WM_event_add_notifier(C, NC_OBJECT, obedit); + /* note, notifier might evolve */ + WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, obedit); return OPERATOR_FINISHED; } @@ -3930,7 +3938,7 @@ static int armature_parent_clear_exec(bContext *C, wmOperator *op) ED_armature_sync_selection(arm->edbo); /* note, notifier might evolve */ - WM_event_add_notifier(C, NC_OBJECT, ob); + WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, ob); return OPERATOR_FINISHED; } @@ -4330,7 +4338,7 @@ int ED_do_pose_selectbuffer(Scene *scene, Base *base, unsigned int *buffer, shor } /* in weightpaint we select the associated vertex group too */ - if (ob->mode & OB_MODE_WEIGHT_PAINT) { + if (OBACT && OBACT->mode & OB_MODE_WEIGHT_PAINT) { if (nearBone->flag & BONE_ACTIVE) { ED_vgroup_select_by_name(OBACT, nearBone->name); DAG_id_flush_update(&OBACT->id, OB_RECALC_DATA); diff --git a/source/blender/editors/armature/editarmature_sketch.c b/source/blender/editors/armature/editarmature_sketch.c index 7f2f2a3410c..74876691dac 100644 --- a/source/blender/editors/armature/editarmature_sketch.c +++ b/source/blender/editors/armature/editarmature_sketch.c @@ -2675,7 +2675,7 @@ static int sketch_draw_modal(bContext *C, wmOperator *op, wmEvent *event, short retval = OPERATOR_CANCELLED; break; case LEFTMOUSE: - if (event->val == 0) + if (event->val == KM_RELEASE) { if (gesture == 0) { diff --git a/source/blender/editors/armature/poseSlide.c b/source/blender/editors/armature/poseSlide.c new file mode 100644 index 00000000000..7c63954767f --- /dev/null +++ b/source/blender/editors/armature/poseSlide.c @@ -0,0 +1,936 @@ +/** + * $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) 2009, Blender Foundation, Joshua Leung + * This is a new part of Blender + * + * Contributor(s): Joshua Leung + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include <stdlib.h> +#include <stdio.h> +#include <stddef.h> +#include <string.h> +#include <math.h> +#include <float.h> + +#include "MEM_guardedalloc.h" + +#include "BLI_arithb.h" +#include "BLI_blenlib.h" +#include "BLI_dynstr.h" +#include "BLI_dlrbTree.h" + +#include "DNA_listBase.h" +#include "DNA_anim_types.h" +#include "DNA_action_types.h" +#include "DNA_armature_types.h" +#include "DNA_curve_types.h" +#include "DNA_object_types.h" +#include "DNA_object_force.h" +#include "DNA_scene_types.h" +#include "DNA_userdef_types.h" + +#include "BKE_animsys.h" +#include "BKE_action.h" +#include "BKE_armature.h" +#include "BKE_depsgraph.h" +#include "BKE_fcurve.h" +#include "BKE_object.h" + +#include "BKE_global.h" +#include "BKE_context.h" +#include "BKE_report.h" +#include "BKE_utildefines.h" + +#include "RNA_access.h" +#include "RNA_define.h" +#include "RNA_types.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "UI_interface.h" +#include "UI_resources.h" + +#include "BIF_gl.h" + +#include "ED_anim_api.h" +#include "ED_armature.h" +#include "ED_keyframes_draw.h" +#include "ED_keyframing.h" +#include "ED_keyframes_edit.h" +#include "ED_screen.h" + +#include "armature_intern.h" + +/* **************************************************** */ +/* == POSE 'SLIDING' TOOLS == + * + * A) Push & Relax, Breakdowner + * These tools provide the animator with various capabilities + * for interactively controlling the spacing of poses, but also + * for 'pushing' and/or 'relaxing' extremes as they see fit. + * + * B) Pose Sculpting + * This is yet to be implemented, but the idea here is to use + * sculpting techniques to make it easier to pose rigs by allowing + * rigs to be manipulated using a familiar paint-based interface. + */ +/* **************************************************** */ +/* A) Push & Relax, Breakdowner */ + +/* Temporary data shared between these operators */ +typedef struct tPoseSlideOp { + Scene *scene; /* current scene */ + ARegion *ar; /* region that we're operating in (needed for */ + Object *ob; /* active object that Pose Info comes from */ + bArmature *arm; /* armature for pose */ + + ListBase pfLinks; /* links between posechannels and f-curves */ + DLRBT_Tree keys; /* binary tree for quicker searching for keyframes (when applicable) */ + + KeyingSet *ks_loc; /* builtin KeyingSet for keyframing locations */ + KeyingSet *ks_rot; /* builtin KeyingSet for keyframing rotations */ + KeyingSet *ks_scale;/* builtin KeyingSet for keyframing scale */ + + int cframe; /* current frame number */ + int prevFrame; /* frame before current frame (blend-from) */ + int nextFrame; /* frame after current frame (blend-to) */ + + int mode; /* sliding mode (ePoseSlide_Modes) */ + int flag; // unused for now, but can later get used for storing runtime settings.... + + float percentage; /* 0-1 value for determining the influence of whatever is relevant */ +} tPoseSlideOp; + +/* Pose Sliding Modes */ +typedef enum ePoseSlide_Modes { + POSESLIDE_PUSH = 0, /* exaggerate the pose... */ + POSESLIDE_RELAX, /* soften the pose... */ + POSESLIDE_BREAKDOWN, /* slide between the endpoint poses, finding a 'soft' spot */ +} ePoseSlide_Modes; + +/* Temporary data linking PoseChannels with the F-Curves they affect */ +typedef struct tPChanFCurveLink { + struct tPChanFCurveLink *next, *prev; + + ListBase fcurves; /* F-Curves for this PoseChannel */ + bPoseChannel *pchan; /* Pose Channel which data is attached to */ + + char *pchan_path; /* RNA Path to this Pose Channel (needs to be freed when we're done) */ + + float oldloc[3]; /* transform values at start of operator (to be restored before each modal step) */ + float oldrot[3]; + float oldscale[3]; + float oldquat[4]; +} tPChanFCurveLink; + +/* ------------------------------------ */ + +/* operator init */ +static int pose_slide_init (bContext *C, wmOperator *op, short mode) +{ + tPoseSlideOp *pso; + bAction *act= NULL; + + /* init slide-op data */ + pso= op->customdata= MEM_callocN(sizeof(tPoseSlideOp), "tPoseSlideOp"); + + /* get info from context */ + pso->scene= CTX_data_scene(C); + pso->ob= CTX_data_active_object(C); + pso->arm= (pso->ob)? pso->ob->data : NULL; + pso->ar= CTX_wm_region(C); /* only really needed when doing modal() */ + + pso->cframe= pso->scene->r.cfra; + pso->mode= mode; + + /* set range info from property values - these may get overridden for the invoke() */ + pso->percentage= RNA_float_get(op->ptr, "percentage"); + pso->prevFrame= RNA_int_get(op->ptr, "prev_frame"); + pso->nextFrame= RNA_int_get(op->ptr, "next_frame"); + + /* check the settings from the context */ + if (ELEM4(NULL, pso->ob, pso->arm, pso->ob->adt, pso->ob->adt->action)) + return 0; + else + act= pso->ob->adt->action; + + /* for each Pose-Channel which gets affected, get the F-Curves for that channel + * and set the relevant transform flags... + */ + CTX_DATA_BEGIN(C, bPoseChannel*, pchan, selected_pchans) + { + ListBase curves = {NULL, NULL}; + int transFlags = action_get_item_transforms(act, pso->ob, pchan, &curves); + + pchan->flag &= ~(POSE_LOC|POSE_ROT|POSE_SIZE); + + /* check if any transforms found... */ + if (transFlags) { + /* make new linkage data */ + tPChanFCurveLink *pfl= MEM_callocN(sizeof(tPChanFCurveLink), "tPChanFCurveLink"); + PointerRNA ptr; + + pfl->fcurves= curves; + pfl->pchan= pchan; + + /* get the RNA path to this pchan - this needs to be freed! */ + RNA_pointer_create((ID *)pso->ob, &RNA_PoseChannel, pchan, &ptr); + pfl->pchan_path= RNA_path_from_ID_to_struct(&ptr); + + /* add linkage data to operator data */ + BLI_addtail(&pso->pfLinks, pfl); + + /* set pchan's transform flags */ + if (transFlags & ACT_TRANS_LOC) + pchan->flag |= POSE_LOC; + if (transFlags & ACT_TRANS_ROT) + pchan->flag |= POSE_ROT; + if (transFlags & ACT_TRANS_SCALE) + pchan->flag |= POSE_SIZE; + + /* store current transforms */ + VECCOPY(pfl->oldloc, pchan->loc); + VECCOPY(pfl->oldrot, pchan->eul); + VECCOPY(pfl->oldscale, pchan->size); + QUATCOPY(pfl->oldquat, pchan->quat); + } + } + CTX_DATA_END; + + /* set depsgraph flags */ + /* make sure the lock is set OK, unlock can be accidentally saved? */ + pso->ob->pose->flag |= POSE_LOCKED; + pso->ob->pose->flag &= ~POSE_DO_UNLOCK; + + /* do basic initialise of RB-BST used for finding keyframes, but leave the filling of it up + * to the caller of this (usually only invoke() will do it, to make things more efficient). + */ + BLI_dlrbTree_init(&pso->keys); + + /* get builtin KeyingSets */ + pso->ks_loc= ANIM_builtin_keyingset_get_named(NULL, "Location"); + pso->ks_rot= ANIM_builtin_keyingset_get_named(NULL, "Rotation"); + pso->ks_scale= ANIM_builtin_keyingset_get_named(NULL, "Scaling"); + + /* return status is whether we've got all the data we were requested to get */ + return 1; +} + +/* exiting the operator - free data */ +static void pose_slide_exit (bContext *C, wmOperator *op) +{ + tPoseSlideOp *pso= op->customdata; + + /* if data exists, clear its data and exit */ + if (pso) { + tPChanFCurveLink *pfl, *pfln=NULL; + + /* free the temp pchan links and their data */ + for (pfl= pso->pfLinks.first; pfl; pfl= pfln) { + pfln= pfl->next; + + /* free list of F-Curve reference links */ + BLI_freelistN(&pfl->fcurves); + + /* free pchan RNA Path */ + MEM_freeN(pfl->pchan_path); + + /* free link itself */ + BLI_freelinkN(&pso->pfLinks, pfl); + } + + /* free RB-BST for keyframes (if it contained data) */ + BLI_dlrbTree_free(&pso->keys); + + /* free data itself */ + MEM_freeN(pso); + } + + /* cleanup */ + op->customdata= NULL; +} + +/* ------------------------------------ */ + +/* helper for apply() / reset() - refresh the data */ +static void pose_slide_refresh (bContext *C, tPoseSlideOp *pso) +{ + /* old optimize trick... this enforces to bypass the depgraph + * - note: code copied from transform_generics.c -> recalcData() + */ + // FIXME: shouldn't this use the builtin stuff? + if ((pso->arm->flag & ARM_DELAYDEFORM)==0) + DAG_id_flush_update(&pso->ob->id, OB_RECALC_DATA); /* sets recalc flags */ + else + where_is_pose(pso->scene, pso->ob); + + /* note, notifier might evolve */ + WM_event_add_notifier(C, NC_OBJECT|ND_POSE, pso->ob); + WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, NULL); +} + +/* helper for apply() callabcks - find the next F-Curve with matching path... */ +static LinkData *find_next_fcurve_link (ListBase *fcuLinks, LinkData *prev, char *path) +{ + LinkData *first= (prev)? prev->next : (fcuLinks)? fcuLinks->first : NULL; + LinkData *ld; + + /* check each link to see if the linked F-Curve has a matching path */ + for (ld= first; ld; ld= ld->next) { + FCurve *fcu= (FCurve *)ld->data; + + /* check if paths match */ + if (strcmp(path, fcu->rna_path) == 0) + return ld; + } + + /* none found */ + return NULL; +} + +/* helper for apply() - perform sliding for some 3-element vector */ +static void pose_slide_apply_vec3 (tPoseSlideOp *pso, tPChanFCurveLink *pfl, float vec[3], char *propName) +{ + LinkData *ld=NULL; + char *path=NULL; + float cframe; + + /* get the path to use... */ + path= BLI_sprintfN("%s.%s", pfl->pchan_path, propName); + + /* get the current frame number */ + cframe= (float)pso->cframe; + + /* using this path, find each matching F-Curve for the variables we're interested in */ + while ( (ld= find_next_fcurve_link(&pfl->fcurves, ld, path)) ) { + FCurve *fcu= (FCurve *)ld->data; + float sVal, eVal; + float w1, w2; + int ch; + + /* get keyframe values for endpoint poses to blend with */ + /* previous/start */ + sVal= evaluate_fcurve(fcu, (float)pso->prevFrame); + /* next/end */ + eVal= evaluate_fcurve(fcu, (float)pso->nextFrame); + + /* get channel index */ + ch= fcu->array_index; + + /* calculate the relative weights of the endpoints */ + if (pso->mode == POSESLIDE_BREAKDOWN) { + /* get weights from the percentage control */ + w1= pso->percentage; /* this must come second */ + w2= 1.0f - w1; /* this must come first */ + } + else { + /* - these weights are derived from the relative distance of these + * poses from the current frame + * - they then get normalised so that they only sum up to 1 + */ + float wtot; + + w1 = cframe - (float)pso->prevFrame; + w2 = (float)pso->nextFrame - cframe; + + wtot = w1 + w2; + w1 = (w1/wtot); + w2 = (w2/wtot); + } + + /* depending on the mode, calculate the new value + * - in all of these, the start+end values are multiplied by w2 and w1 (respectively), + * since multiplication in another order would decrease the value the current frame is closer to + */ + switch (pso->mode) { + case POSESLIDE_PUSH: /* make the current pose more pronounced */ + { + /* perform a weighted average here, favouring the middle pose + * - numerator should be larger than denominator to 'expand' the result + * - perform this weighting a number of times given by the percentage... + */ + int iters= (int)ceil(10.0f*pso->percentage); // TODO: maybe a sensitivity ctrl on top of this is needed + + while (iters-- > 0) { + vec[ch]= ( -((sVal * w2) + (eVal * w1)) + (vec[ch] * 6.0f) ) / 5.0f; + } + } + break; + + case POSESLIDE_RELAX: /* make the current pose more like its surrounding ones */ + { + /* perform a weighted average here, favouring the middle pose + * - numerator should be smaller than denominator to 'relax' the result + * - perform this weighting a number of times given by the percentage... + */ + int iters= (int)ceil(10.0f*pso->percentage); // TODO: maybe a sensitivity ctrl on top of this is needed + + while (iters-- > 0) { + vec[ch]= ( ((sVal * w2) + (eVal * w1)) + (vec[ch] * 5.0f) ) / 6.0f; + } + } + break; + + case POSESLIDE_BREAKDOWN: /* make the current pose slide around between the endpoints */ + { + /* perform simple linear interpolation - coefficient for start must come from pso->percentage... */ + // TODO: make this use some kind of spline interpolation instead? + vec[ch]= ((sVal * w2) + (eVal * w1)); + } + break; + } + + } + + /* free the temp path we got */ + MEM_freeN(path); +} + +/* helper for apply() - perform sliding for quaternion rotations (using quat blending) */ +static void pose_slide_apply_quat (tPoseSlideOp *pso, tPChanFCurveLink *pfl) +{ + FCurve *fcu_w=NULL, *fcu_x=NULL, *fcu_y=NULL, *fcu_z=NULL; + bPoseChannel *pchan= pfl->pchan; + LinkData *ld=NULL; + char *path=NULL; + float cframe; + + /* get the path to use - this should be quaternion rotations only (needs care) */ + path= BLI_sprintfN("%s.%s", pfl->pchan_path, "rotation"); + + /* get the current frame number */ + cframe= (float)pso->cframe; + + /* using this path, find each matching F-Curve for the variables we're interested in */ + while ( (ld= find_next_fcurve_link(&pfl->fcurves, ld, path)) ) { + FCurve *fcu= (FCurve *)ld->data; + + /* assign this F-Curve to one of the relevant pointers... */ + switch (fcu->array_index) { + case 3: /* z */ + fcu_z= fcu; + break; + case 2: /* y */ + fcu_y= fcu; + break; + case 1: /* x */ + fcu_x= fcu; + break; + case 0: /* w */ + fcu_w= fcu; + break; + } + } + + /* only if all channels exist, proceed */ + if (fcu_w && fcu_x && fcu_y && fcu_z) { + float quat_prev[4], quat_next[4]; + + /* get 2 quats */ + quat_prev[0] = evaluate_fcurve(fcu_w, pso->prevFrame); + quat_prev[1] = evaluate_fcurve(fcu_x, pso->prevFrame); + quat_prev[2] = evaluate_fcurve(fcu_y, pso->prevFrame); + quat_prev[3] = evaluate_fcurve(fcu_z, pso->prevFrame); + + quat_next[0] = evaluate_fcurve(fcu_w, pso->nextFrame); + quat_next[1] = evaluate_fcurve(fcu_x, pso->nextFrame); + quat_next[2] = evaluate_fcurve(fcu_y, pso->nextFrame); + quat_next[3] = evaluate_fcurve(fcu_z, pso->nextFrame); + + /* perform blending */ + if (pso->mode == POSESLIDE_BREAKDOWN) { + /* just perform the interpol between quat_prev and quat_next using pso->percentage as a guide */ + QuatInterpol(pchan->quat, quat_prev, quat_next, pso->percentage); + } + else { + float quat_interp[4], quat_orig[4]; + int iters= (int)ceil(10.0f*pso->percentage); // TODO: maybe a sensitivity ctrl on top of this is needed + + /* perform this blending several times until a satisfactory result is reached */ + while (iters-- > 0) { + /* calculate the interpolation between the endpoints */ + QuatInterpol(quat_interp, quat_prev, quat_next, (cframe-pso->prevFrame) / (pso->nextFrame-pso->prevFrame) ); + + /* make a copy of the original rotation */ + QUATCOPY(quat_orig, pchan->quat); + + /* tricky interpolations - mode-dependent blending between original and new */ + if (pso->mode == POSESLIDE_RELAX) // xxx this was the original code, so should work fine + QuatInterpol(pchan->quat, quat_orig, quat_interp, 1.0f/6.0f); + else // I'm just guessing here... + QuatInterpol(pchan->quat, quat_orig, quat_interp, 6.0f/5.0f); + } + } + } + + /* free the path now */ + MEM_freeN(path); +} + +/* apply() - perform the pose sliding based on weighting various poses */ +static void pose_slide_apply (bContext *C, wmOperator *op, tPoseSlideOp *pso) +{ + tPChanFCurveLink *pfl; + + /* sanitise the frame ranges */ + if (pso->prevFrame == pso->nextFrame) { + /* move out one step either side */ + pso->prevFrame--; + pso->nextFrame++; + } + + /* for each link, handle each set of transforms */ + for (pfl= pso->pfLinks.first; pfl; pfl= pfl->next) { + /* valid transforms for each PoseChannel should have been noted already + * - sliding the pose should be a straightforward exercise for location+rotation, + * but rotations get more complicated since we may want to use quaternion blending + * for quaternions instead... + */ + bPoseChannel *pchan= pfl->pchan; + + if (pchan->flag & POSE_LOC) { + /* calculate these for the 'location' vector, and use location curves */ + pose_slide_apply_vec3(pso, pfl, pchan->loc, "location"); + } + + if (pchan->flag & POSE_SIZE) { + /* calculate these for the 'scale' vector, and use scale curves */ + pose_slide_apply_vec3(pso, pfl, pchan->size, "scale"); + } + + if (pchan->flag & POSE_ROT) { + /* everything depends on the rotation mode */ + if (pchan->rotmode > 0) { + /* eulers - so calculate these for the 'eul' vector, and use euler_rotation curves */ + pose_slide_apply_vec3(pso, pfl, pchan->eul, "euler_rotation"); + } + else if (pchan->rotmode == PCHAN_ROT_AXISANGLE) { + // TODO: need to figure out how to do this! + } + else { + /* quaternions - use quaternion blending */ + pose_slide_apply_quat(pso, pfl); + } + } + } + + /* depsgraph updates + redraws */ + pose_slide_refresh(C, pso); +} + +/* perform autokeyframing after changes were made + confirmed */ +static void pose_slide_autoKeyframe (bContext *C, tPoseSlideOp *pso) +{ + /* insert keyframes as necessary if autokeyframing */ + if (autokeyframe_cfra_can_key(pso->scene, &pso->ob->id)) { + bCommonKeySrc cks; + ListBase dsources = {&cks, &cks}; + tPChanFCurveLink *pfl; + + /* init common-key-source for use by KeyingSets */ + memset(&cks, 0, sizeof(bCommonKeySrc)); + cks.id= &pso->ob->id; + + /* iterate over each pose-channel affected, applying the changes */ + for (pfl= pso->pfLinks.first; pfl; pfl= pfl->next) { + bPoseChannel *pchan= pfl->pchan; + /* init cks for this PoseChannel, then use the relative KeyingSets to keyframe it */ + cks.pchan= pchan; + + /* insert keyframes */ + if (pchan->flag & POSE_LOC) + modify_keyframes(C, &dsources, NULL, pso->ks_loc, MODIFYKEY_MODE_INSERT, (float)pso->cframe); + if (pchan->flag & POSE_ROT) + modify_keyframes(C, &dsources, NULL, pso->ks_rot, MODIFYKEY_MODE_INSERT, (float)pso->cframe); + if (pchan->flag & POSE_SIZE) + modify_keyframes(C, &dsources, NULL, pso->ks_scale, MODIFYKEY_MODE_INSERT, (float)pso->cframe); + } + } +} + +/* reset changes made to current pose */ +static void pose_slide_reset (bContext *C, tPoseSlideOp *pso) +{ + tPChanFCurveLink *pfl; + + /* iterate over each pose-channel affected, restoring all channels to their original values */ + for (pfl= pso->pfLinks.first; pfl; pfl= pfl->next) { + bPoseChannel *pchan= pfl->pchan; + + /* just copy all the values over regardless of whether they changed or not */ + VECCOPY(pchan->loc, pfl->oldloc); + VECCOPY(pchan->eul, pfl->oldrot); + VECCOPY(pchan->size, pfl->oldscale); + QUATCOPY(pchan->quat, pfl->oldquat); + } +} + +/* ------------------------------------ */ + +/* common code for invoke() methods */ +static int pose_slide_invoke_common (bContext *C, wmOperator *op, tPoseSlideOp *pso) +{ + tPChanFCurveLink *pfl; + AnimData *adt= pso->ob->adt; + wmWindow *win= CTX_wm_window(C); + + /* for each link, add all its keyframes to the search tree */ + for (pfl= pso->pfLinks.first; pfl; pfl= pfl->next) { + LinkData *ld; + + /* do this for each F-Curve */ + for (ld= pfl->fcurves.first; ld; ld= ld->next) { + FCurve *fcu= (FCurve *)ld->data; + fcurve_to_keylist(adt, fcu, &pso->keys, NULL); + } + } + + /* consolidate these keyframes, and figure out the nearest ones */ + BLI_dlrbTree_linkedlist_sync(&pso->keys); + + /* cancel if no keyframes found... */ + if (pso->keys.root) { + ActKeyColumn *ak; + + /* firstly, check if the current frame is a keyframe... */ + ak= cfra_find_actkeycolumn(pso->keys.root, pso->cframe); + + if (ak == NULL) { + /* current frame is not a keyframe, so search */ + ActKeyColumn *pk= cfra_find_nearest_next_ak(pso->keys.root, pso->cframe, 0); + ActKeyColumn *nk= cfra_find_nearest_next_ak(pso->keys.root, pso->cframe, 1); + + /* check if we found good keyframes */ + if ((pk == nk) && (pk != NULL)) { + if (pk->cfra < pso->cframe) + nk= nk->next; + else if (nk->cfra > pso->cframe) + pk= pk->prev; + } + + /* new set the frames */ + /* prev frame */ + pso->prevFrame= (pk)? (pk->cfra) : (pso->cframe - 1); + RNA_int_set(op->ptr, "prev_frame", pso->prevFrame); + /* next frame */ + pso->nextFrame= (nk)? (nk->cfra) : (pso->cframe + 1); + RNA_int_set(op->ptr, "next_frame", pso->nextFrame); + } + else { + /* current frame itself is a keyframe, so just take keyframes on either side */ + /* prev frame */ + pso->prevFrame= (ak->prev)? (ak->prev->cfra) : (pso->cframe - 1); + RNA_int_set(op->ptr, "prev_frame", pso->prevFrame); + /* next frame */ + pso->nextFrame= (ak->next)? (ak->next->cfra) : (pso->cframe + 1); + RNA_int_set(op->ptr, "next_frame", pso->nextFrame); + } + } + else { + BKE_report(op->reports, RPT_ERROR, "No keyframes to slide between."); + return OPERATOR_CANCELLED; + } + + /* initial apply for operator... */ + // TODO: need to calculate percentage for initial round too... + pose_slide_apply(C, op, pso); + + /* depsgraph updates + redraws */ + pose_slide_refresh(C, pso); + + /* set cursor to indicate modal */ + WM_cursor_modal(win, BC_EW_SCROLLCURSOR); + + /* add a modal handler for this operator */ + WM_event_add_modal_handler(C, op); + return OPERATOR_RUNNING_MODAL; +} + +/* common code for modal() */ +static int pose_slide_modal (bContext *C, wmOperator *op, wmEvent *evt) +{ + tPoseSlideOp *pso= op->customdata; + wmWindow *win= CTX_wm_window(C); + + switch (evt->type) { + case LEFTMOUSE: /* confirm */ + { + /* return to normal cursor */ + WM_cursor_restore(win); + + /* insert keyframes as required... */ + pose_slide_autoKeyframe(C, pso); + pose_slide_exit(C, op); + + /* done! */ + return OPERATOR_FINISHED; + } + + case ESCKEY: /* cancel */ + case RIGHTMOUSE: + { + /* return to normal cursor */ + WM_cursor_restore(win); + + /* reset transforms back to original state */ + pose_slide_reset(C, pso); + + /* depsgraph updates + redraws */ + pose_slide_refresh(C, pso); + + /* clean up temp data */ + pose_slide_exit(C, op); + + /* cancelled! */ + return OPERATOR_CANCELLED; + } + + case MOUSEMOVE: /* calculate new position */ + { + /* calculate percentage based on position of mouse (we only use x-axis for now. + * since this is more conveninent for users to do), and store new percentage value + */ + pso->percentage= (evt->x - pso->ar->winrct.xmin) / ((float)pso->ar->winx); + RNA_float_set(op->ptr, "percentage", pso->percentage); + + /* reset transforms (to avoid accumulation errors) */ + pose_slide_reset(C, pso); + + /* apply... */ + pose_slide_apply(C, op, pso); + } + break; + + default: /* unhandled event (maybe it was some view manip? */ + /* allow to pass through */ + return OPERATOR_RUNNING_MODAL|OPERATOR_PASS_THROUGH; + } + + /* still running... */ + return OPERATOR_RUNNING_MODAL; +} + +/* common code for cancel() */ +static int pose_slide_cancel (bContext *C, wmOperator *op) +{ + /* cleanup and done */ + pose_slide_exit(C, op); + return OPERATOR_CANCELLED; +} + +/* common code for exec() methods */ +static int pose_slide_exec_common (bContext *C, wmOperator *op, tPoseSlideOp *pso) +{ + /* settings should have been set up ok for applying, so just apply! */ + pose_slide_apply(C, op, pso); + + /* insert keyframes if needed */ + pose_slide_autoKeyframe(C, pso); + + /* cleanup and done */ + pose_slide_exit(C, op); + + return OPERATOR_FINISHED; +} + +/* common code for defining RNA properties */ +static void pose_slide_opdef_properties (wmOperatorType *ot) +{ + RNA_def_int(ot->srna, "prev_frame", 0, MINAFRAME, MAXFRAME, "Previous Keyframe", "Frame number of keyframe immediately before the current frame.", 0, 50); + RNA_def_int(ot->srna, "next_frame", 0, MINAFRAME, MAXFRAME, "Next Keyframe", "Frame number of keyframe immediately after the current frame.", 0, 50); + RNA_def_float_percentage(ot->srna, "percentage", 0.5f, 0.0f, 1.0f, "Percentage", "Weighting factor for the sliding operation", 0.3, 0.7); +} + +/* ------------------------------------ */ + +/* invoke() - for 'push' mode */ +static int pose_slide_push_invoke (bContext *C, wmOperator *op, wmEvent *evt) +{ + tPoseSlideOp *pso; + + /* initialise data */ + if (pose_slide_init(C, op, POSESLIDE_PUSH) == 0) { + pose_slide_exit(C, op); + return OPERATOR_CANCELLED; + } + else + pso= op->customdata; + + /* do common setup work */ + return pose_slide_invoke_common(C, op, pso); +} + +/* exec() - for push */ +static int pose_slide_push_exec (bContext *C, wmOperator *op) +{ + tPoseSlideOp *pso; + + /* initialise data (from RNA-props) */ + if (pose_slide_init(C, op, POSESLIDE_PUSH) == 0) { + pose_slide_exit(C, op); + return OPERATOR_CANCELLED; + } + else + pso= op->customdata; + + /* do common exec work */ + return pose_slide_exec_common(C, op, pso); +} + +void POSE_OT_push (wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Push Pose"; + ot->idname= "POSE_OT_push"; + ot->description= "Exaggerate the current pose"; + + /* callbacks */ + ot->exec= pose_slide_push_exec; + ot->invoke= pose_slide_push_invoke; + ot->modal= pose_slide_modal; + ot->cancel= pose_slide_cancel; + ot->poll= ED_operator_posemode; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO|OPTYPE_BLOCKING; + + /* Properties */ + pose_slide_opdef_properties(ot); +} + +/* ........................ */ + +/* invoke() - for 'relax' mode */ +static int pose_slide_relax_invoke (bContext *C, wmOperator *op, wmEvent *evt) +{ + tPoseSlideOp *pso; + + /* initialise data */ + if (pose_slide_init(C, op, POSESLIDE_RELAX) == 0) { + pose_slide_exit(C, op); + return OPERATOR_CANCELLED; + } + else + pso= op->customdata; + + /* do common setup work */ + return pose_slide_invoke_common(C, op, pso); +} + +/* exec() - for relax */ +static int pose_slide_relax_exec (bContext *C, wmOperator *op) +{ + tPoseSlideOp *pso; + + /* initialise data (from RNA-props) */ + if (pose_slide_init(C, op, POSESLIDE_RELAX) == 0) { + pose_slide_exit(C, op); + return OPERATOR_CANCELLED; + } + else + pso= op->customdata; + + /* do common exec work */ + return pose_slide_exec_common(C, op, pso); +} + +void POSE_OT_relax (wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Relax Pose"; + ot->idname= "POSE_OT_relax"; + ot->description= "Make the current pose more similar to its surrounding ones."; + + /* callbacks */ + ot->exec= pose_slide_relax_exec; + ot->invoke= pose_slide_relax_invoke; + ot->modal= pose_slide_modal; + ot->cancel= pose_slide_cancel; + ot->poll= ED_operator_posemode; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO|OPTYPE_BLOCKING; + + /* Properties */ + pose_slide_opdef_properties(ot); +} + +/* ........................ */ + +/* invoke() - for 'breakdown' mode */ +static int pose_slide_breakdown_invoke (bContext *C, wmOperator *op, wmEvent *evt) +{ + tPoseSlideOp *pso; + + /* initialise data */ + if (pose_slide_init(C, op, POSESLIDE_BREAKDOWN) == 0) { + pose_slide_exit(C, op); + return OPERATOR_CANCELLED; + } + else + pso= op->customdata; + + /* do common setup work */ + return pose_slide_invoke_common(C, op, pso); +} + +/* exec() - for breakdown */ +static int pose_slide_breakdown_exec (bContext *C, wmOperator *op) +{ + tPoseSlideOp *pso; + + /* initialise data (from RNA-props) */ + if (pose_slide_init(C, op, POSESLIDE_BREAKDOWN) == 0) { + pose_slide_exit(C, op); + return OPERATOR_CANCELLED; + } + else + pso= op->customdata; + + /* do common exec work */ + return pose_slide_exec_common(C, op, pso); +} + +void POSE_OT_breakdown (wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Pose Breakdowner"; + ot->idname= "POSE_OT_breakdown"; + ot->description= "Create a suitable breakdown pose on the current frame."; + + /* callbacks */ + ot->exec= pose_slide_breakdown_exec; + ot->invoke= pose_slide_breakdown_invoke; + ot->modal= pose_slide_modal; + ot->cancel= pose_slide_cancel; + ot->poll= ED_operator_posemode; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO|OPTYPE_BLOCKING; + + /* Properties */ + pose_slide_opdef_properties(ot); +} + +/* **************************************************** */ diff --git a/source/blender/editors/armature/poselib.c b/source/blender/editors/armature/poselib.c index f072f2e980e..386cb6512a3 100644 --- a/source/blender/editors/armature/poselib.c +++ b/source/blender/editors/armature/poselib.c @@ -44,7 +44,6 @@ #include "DNA_action_types.h" #include "DNA_armature_types.h" #include "DNA_curve_types.h" -#include "DNA_ipo_types.h" #include "DNA_object_types.h" #include "DNA_object_force.h" #include "DNA_scene_types.h" @@ -62,8 +61,6 @@ #include "BKE_report.h" #include "BKE_utildefines.h" -#include "PIL_time.h" /* sleep */ - #include "RNA_access.h" #include "RNA_define.h" #include "RNA_types.h" @@ -470,6 +467,7 @@ static int poselib_remove_exec (bContext *C, wmOperator *op) marker= BLI_findlink(&act->markers, RNA_int_get(op->ptr, "index")); if (marker == NULL) { BKE_report(op->reports, RPT_ERROR, "Invalid index for Pose"); + return OPERATOR_CANCELLED; } /* remove relevant keyframes */ @@ -536,6 +534,7 @@ static int poselib_rename_exec (bContext *C, wmOperator *op) marker= BLI_findlink(&act->markers, RNA_int_get(op->ptr, "index")); if (marker == NULL) { BKE_report(op->reports, RPT_ERROR, "Invalid index for Pose"); + return OPERATOR_CANCELLED; } /* get new name */ @@ -769,6 +768,10 @@ static void poselib_keytag_pose (bContext *C, Scene *scene, tPoseLib_PreviewData if (poselib_ks_locrotscale == NULL) poselib_ks_locrotscale= ANIM_builtin_keyingset_get_named(NULL, "LocRotScale"); + /* init cks for this PoseChannel, then use the relative KeyingSets to keyframe it */ + cks.pchan= pchan; + + /* now insert the keyframe */ modify_keyframes(C, &dsources, NULL, poselib_ks_locrotscale, MODIFYKEY_MODE_INSERT, (float)CFRA); /* clear any unkeyed tags */ diff --git a/source/blender/editors/armature/poseobject.c b/source/blender/editors/armature/poseobject.c index bab7111dbd7..f40476f6f59 100644 --- a/source/blender/editors/armature/poseobject.c +++ b/source/blender/editors/armature/poseobject.c @@ -798,6 +798,8 @@ void pose_copy_menu(Scene *scene) VECCOPY(pchan->limitmax, pchanact->limitmax); VECCOPY(pchan->stiffness, pchanact->stiffness); pchan->ikstretch= pchanact->ikstretch; + pchan->ikrotweight= pchanact->ikrotweight; + pchan->iklinweight= pchanact->iklinweight; } break; case 8: /* Custom Bone Shape */ @@ -1084,6 +1086,9 @@ static int pose_paste_exec (bContext *C, wmOperator *op) if (posePaste_ks_locrotscale == NULL) posePaste_ks_locrotscale= ANIM_builtin_keyingset_get_named(NULL, "LocRotScale"); + /* init cks for this PoseChannel, then use the relative KeyingSets to keyframe it */ + cks.pchan= pchan; + modify_keyframes(C, &dsources, NULL, posePaste_ks_locrotscale, MODIFYKEY_MODE_INSERT, (float)CFRA); /* clear any unkeyed tags */ @@ -1939,7 +1944,7 @@ static int armature_bone_layers_invoke (bContext *C, wmOperator *op, wmEvent *ev /* Set the visible layers for the active armature (edit and pose modes) */ static int armature_bone_layers_exec (bContext *C, wmOperator *op) { - Object *ob= CTX_data_active_object(C); + Object *ob= CTX_data_edit_object(C); bArmature *arm= (ob)? ob->data : NULL; PointerRNA ptr; int layers[16]; /* hardcoded for now - we can only have 16 armature layers, so this should be fine... */ @@ -1952,7 +1957,7 @@ static int armature_bone_layers_exec (bContext *C, wmOperator *op) { /* get pointer for pchan, and write flags this way */ RNA_pointer_create((ID *)arm, &RNA_EditBone, ebone, &ptr); - RNA_boolean_set_array(&ptr, "layers", layers); + RNA_boolean_set_array(&ptr, "layer", layers); } CTX_DATA_END; @@ -1983,175 +1988,6 @@ void ARMATURE_OT_bone_layers (wmOperatorType *ot) /* ********************************************** */ -#if 0 -// XXX old sys -/* for use with pose_relax only */ -static int pose_relax_icu(struct IpoCurve *icu, float framef, float *val, float *frame_prev, float *frame_next) -{ - if (!icu) { - return 0; - } - else { - BezTriple *bezt = icu->bezt; - - BezTriple *bezt_prev=NULL, *bezt_next=NULL; - float w1, w2, wtot; - int i; - - for (i=0; i < icu->totvert; i++, bezt++) { - if (bezt->vec[1][0] < framef - 0.5) { - bezt_prev = bezt; - } else { - break; - } - } - - if (bezt_prev==NULL) return 0; - - /* advance to the next, dont need to advance i */ - bezt = bezt_prev+1; - - for (; i < icu->totvert; i++, bezt++) { - if (bezt->vec[1][0] > framef + 0.5) { - bezt_next = bezt; - break; - } - } - - if (bezt_next==NULL) return 0; - - if (val) { - w1 = framef - bezt_prev->vec[1][0]; - w2 = bezt_next->vec[1][0] - framef; - wtot = w1 + w2; - w1=w1/wtot; - w2=w2/wtot; -#if 0 - val = (bezt_prev->vec[1][1] * w2) + (bezt_next->vec[1][1] * w1); -#else - /* apply the value with a hard coded 6th */ - *val = (((bezt_prev->vec[1][1] * w2) + (bezt_next->vec[1][1] * w1)) + (*val * 5.0f)) / 6.0f; -#endif - } - - if (frame_prev) *frame_prev = bezt_prev->vec[1][0]; - if (frame_next) *frame_next = bezt_next->vec[1][0]; - - return 1; - } -} -#endif - -void pose_relax(Scene *scene) -{ - Object *ob = OBACT; - bPose *pose; - bAction *act; - bArmature *arm; - -// IpoCurve *icu_w, *icu_x, *icu_y, *icu_z; - - bPoseChannel *pchan; -// bActionChannel *achan; -// float framef = F_CFRA; -// float frame_prev, frame_next; -// float quat_prev[4], quat_next[4], quat_interp[4], quat_orig[4]; - - int do_scale = 0; - int do_loc = 0; - int do_quat = 0; - int flag = 0; -// int do_x, do_y, do_z; - - if (!ob) return; - - pose = ob->pose; - act = ob->action; - arm = (bArmature *)ob->data; - - if (!pose || !act || !arm) return; - - for (pchan=pose->chanbase.first; pchan; pchan= pchan->next) { - - pchan->bone->flag &= ~BONE_TRANSFORM; - - if (pchan->bone->layer & arm->layer) { - if (pchan->bone->flag & BONE_SELECTED) { - /* do we have an ipo curve? */ -#if 0 // XXX old animation system - achan= get_action_channel(act, pchan->name); - - if (achan && achan->ipo) { - /*calc_ipo(achan->ipo, ctime);*/ - - do_x = pose_relax_icu(find_ipocurve(achan->ipo, AC_LOC_X), framef, &pchan->loc[0], NULL, NULL); - do_y = pose_relax_icu(find_ipocurve(achan->ipo, AC_LOC_Y), framef, &pchan->loc[1], NULL, NULL); - do_z = pose_relax_icu(find_ipocurve(achan->ipo, AC_LOC_Z), framef, &pchan->loc[2], NULL, NULL); - do_loc += do_x + do_y + do_z; - - do_x = pose_relax_icu(find_ipocurve(achan->ipo, AC_SIZE_X), framef, &pchan->size[0], NULL, NULL); - do_y = pose_relax_icu(find_ipocurve(achan->ipo, AC_SIZE_Y), framef, &pchan->size[1], NULL, NULL); - do_z = pose_relax_icu(find_ipocurve(achan->ipo, AC_SIZE_Z), framef, &pchan->size[2], NULL, NULL); - do_scale += do_x + do_y + do_z; - - if( ((icu_w = find_ipocurve(achan->ipo, AC_QUAT_W))) && - ((icu_x = find_ipocurve(achan->ipo, AC_QUAT_X))) && - ((icu_y = find_ipocurve(achan->ipo, AC_QUAT_Y))) && - ((icu_z = find_ipocurve(achan->ipo, AC_QUAT_Z))) ) - { - /* use the quatw keyframe as a basis for others */ - if (pose_relax_icu(icu_w, framef, NULL, &frame_prev, &frame_next)) { - /* get 2 quats */ - quat_prev[0] = eval_icu(icu_w, frame_prev); - quat_prev[1] = eval_icu(icu_x, frame_prev); - quat_prev[2] = eval_icu(icu_y, frame_prev); - quat_prev[3] = eval_icu(icu_z, frame_prev); - - quat_next[0] = eval_icu(icu_w, frame_next); - quat_next[1] = eval_icu(icu_x, frame_next); - quat_next[2] = eval_icu(icu_y, frame_next); - quat_next[3] = eval_icu(icu_z, frame_next); - -#if 0 - /* apply the setting, completely smooth */ - QuatInterpol(pchan->quat, quat_prev, quat_next, (framef-frame_prev) / (frame_next-frame_prev) ); -#else - /* tricky interpolation */ - QuatInterpol(quat_interp, quat_prev, quat_next, (framef-frame_prev) / (frame_next-frame_prev) ); - QUATCOPY(quat_orig, pchan->quat); - QuatInterpol(pchan->quat, quat_orig, quat_interp, 1.0f/6.0f); - /* done */ -#endif - do_quat++; - } - } - - /* apply BONE_TRANSFORM tag so that autokeying will pick it up */ - pchan->bone->flag |= BONE_TRANSFORM; - } - -#endif // XXX old animation system - } - } - } - - ob->pose->flag |= (POSE_LOCKED|POSE_DO_UNLOCK); - - /* do auto-keying */ - if (do_loc) flag |= TFM_TRANSLATION; - if (do_scale) flag |= TFM_RESIZE; - if (do_quat) flag |= TFM_ROTATION; - autokeyframe_pose_cb_func(ob, flag, 0); - - /* clear BONE_TRANSFORM flags */ - for (pchan=pose->chanbase.first; pchan; pchan= pchan->next) - pchan->bone->flag &= ~ BONE_TRANSFORM; - - /* do depsgraph flush */ - DAG_id_flush_update(&ob->id, OB_RECALC_DATA); - BIF_undo_push("Relax Pose"); -} - /* for use in insertkey, ensure rotation goes other way around */ void pose_flipquats(Scene *scene) { diff --git a/source/blender/editors/curve/editcurve.c b/source/blender/editors/curve/editcurve.c index 8dabe24de91..a18815d04a6 100644 --- a/source/blender/editors/curve/editcurve.c +++ b/source/blender/editors/curve/editcurve.c @@ -1078,7 +1078,7 @@ void CURVE_OT_spline_weight_set(wmOperatorType *ot) ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; /* properties */ - RNA_def_float_percentage(ot->srna, "weight", 1.0f, 0.0f, 1.0f, "Weight", "", 0.0f, 1.0f); + RNA_def_float_factor(ot->srna, "weight", 1.0f, 0.0f, 1.0f, "Weight", "", 0.0f, 1.0f); } /******************* set radius operator ******************/ diff --git a/source/blender/editors/curve/editfont.c b/source/blender/editors/curve/editfont.c index 868c5902670..2be567e1921 100644 --- a/source/blender/editors/curve/editfont.c +++ b/source/blender/editors/curve/editfont.c @@ -381,19 +381,19 @@ static int paste_file(bContext *C, ReportList *reports, char *filename) static int paste_file_exec(bContext *C, wmOperator *op) { - char *filename; + char *path; int retval; - filename= RNA_string_get_alloc(op->ptr, "filename", NULL, 0); - retval= paste_file(C, op->reports, filename); - MEM_freeN(filename); + path= RNA_string_get_alloc(op->ptr, "path", NULL, 0); + retval= paste_file(C, op->reports, path); + MEM_freeN(path); return retval; } static int paste_file_invoke(bContext *C, wmOperator *op, wmEvent *event) { - if(RNA_property_is_set(op->ptr, "filename")) + if(RNA_property_is_set(op->ptr, "path")) return paste_file_exec(C, op); WM_event_add_fileselect(C, op); diff --git a/source/blender/editors/include/ED_anim_api.h b/source/blender/editors/include/ED_anim_api.h index 799829a6e87..d9439956569 100644 --- a/source/blender/editors/include/ED_anim_api.h +++ b/source/blender/editors/include/ED_anim_api.h @@ -42,11 +42,14 @@ struct View2D; struct Scene; struct Object; +struct bDopeSheet; + struct bActionGroup; struct FCurve; struct FModifier; struct uiBlock; +struct uiLayout; /* ************************************************ */ /* ANIMATION CHANNEL FILTERING */ @@ -137,6 +140,7 @@ typedef enum eAnim_ChannelType { ANIMTYPE_DSWOR, ANIMTYPE_DSPART, ANIMTYPE_DSMBALL, + ANIMTYPE_DSARM, ANIMTYPE_SHAPEKEY, // XXX probably can become depreceated??? @@ -206,6 +210,7 @@ typedef enum eAnimFilter_Flags { #define FILTER_CUR_OBJD(cu) ((cu->flag & CU_DS_EXPAND)) #define FILTER_PART_OBJD(part) ((part->flag & PART_DS_EXPAND)) #define FILTER_MBALL_OBJD(mb) ((mb->flag2 & MB_DS_EXPAND)) +#define FILTER_ARM_OBJD(arm) ((arm->flag & ARM_DS_EXPAND)) /* 'Sub-object/Action' channels (flags stored in Action) */ #define SEL_ACTC(actc) ((actc->flag & ACT_SELECTED)) #define EXPANDED_ACTC(actc) ((actc->flag & ACT_COLLAPSED)==0) @@ -392,11 +397,14 @@ void ANIM_draw_cfra(const struct bContext *C, struct View2D *v2d, short flag); /* main call to draw preview range curtains */ void ANIM_draw_previewrange(const struct bContext *C, struct View2D *v2d); +/* ------------- Preview Range Drawing -------------- */ + +/* standard header buttons for Animation Editors */ +short ANIM_headerUI_standard_buttons(const struct bContext *C, struct bDopeSheet *ads, struct uiBlock *block, short xco, short yco); + /* ************************************************* */ /* F-MODIFIER TOOLS */ -struct uiLayout; - /* draw a given F-Modifier for some layout/UI-Block */ void ANIM_uiTemplate_fmodifier_draw(struct uiLayout *layout, struct ID *id, ListBase *modifiers, struct FModifier *fcm); diff --git a/source/blender/editors/include/ED_keyframes_draw.h b/source/blender/editors/include/ED_keyframes_draw.h index 0969398f1e2..51d7c664fba 100644 --- a/source/blender/editors/include/ED_keyframes_draw.h +++ b/source/blender/editors/include/ED_keyframes_draw.h @@ -119,5 +119,9 @@ void ob_to_keylist(struct bDopeSheet *ads, struct Object *ob, struct DLRBT_Tree void scene_to_keylist(struct bDopeSheet *ads, struct Scene *sce, struct DLRBT_Tree *keys, struct DLRBT_Tree *blocks); void gpl_to_keylist(struct bDopeSheet *ads, struct bGPDlayer *gpl, struct DLRBT_Tree *keys, struct DLRBT_Tree *blocks); +/* Keyframe Finding */ +ActKeyColumn *cfra_find_actkeycolumn(ActKeyColumn *ak, float cframe); +ActKeyColumn *cfra_find_nearest_next_ak(ActKeyColumn *ak, float cframe, short next); + #endif /* ED_KEYFRAMES_DRAW_H */ diff --git a/source/blender/editors/include/ED_keyframes_edit.h b/source/blender/editors/include/ED_keyframes_edit.h index b2bf05ea5ea..57a6c5fc773 100644 --- a/source/blender/editors/include/ED_keyframes_edit.h +++ b/source/blender/editors/include/ED_keyframes_edit.h @@ -73,6 +73,7 @@ typedef enum eEditKeyframes_Snap { SNAP_KEYS_NEARSEC, SNAP_KEYS_NEARMARKER, SNAP_KEYS_HORIZONTAL, + SNAP_KEYS_VALUE, } eEditKeyframes_Snap; /* mirroring tools */ diff --git a/source/blender/editors/include/ED_keyframing.h b/source/blender/editors/include/ED_keyframing.h index 20c2301d2ac..d30fccfe4de 100644 --- a/source/blender/editors/include/ED_keyframing.h +++ b/source/blender/editors/include/ED_keyframing.h @@ -163,6 +163,9 @@ void ANIM_OT_remove_keyingset_button(struct wmOperatorType *ot); /* ************ Drivers ********************** */ +/* Returns whether there is a driver in the copy/paste buffer to paste */ +short ANIM_driver_can_paste(void); + /* Main Driver Management API calls: * Add a new driver for the specified property on the given ID block */ @@ -171,11 +174,24 @@ short ANIM_add_driver (struct ID *id, const char rna_path[], int array_index, sh /* Main Driver Management API calls: * Remove the driver for the specified property on the given ID block (if available) */ -short ANIM_remove_driver (struct ID *id, const char rna_path[], int array_index, short flag); +short ANIM_remove_driver(struct ID *id, const char rna_path[], int array_index, short flag); + +/* Main Driver Management API calls: + * Make a copy of the driver for the specified property on the given ID block + */ +short ANIM_copy_driver(struct ID *id, const char rna_path[], int array_index, short flag); + +/* Main Driver Management API calls: + * Add a new driver for the specified property on the given ID block or replace an existing one + * with the driver + driver-curve data from the buffer + */ +short ANIM_paste_driver(struct ID *id, const char rna_path[], int array_index, short flag); /* Driver management operators for UI buttons */ void ANIM_OT_add_driver_button(struct wmOperatorType *ot); void ANIM_OT_remove_driver_button(struct wmOperatorType *ot); +void ANIM_OT_copy_driver_button(struct wmOperatorType *ot); +void ANIM_OT_paste_driver_button(struct wmOperatorType *ot); /* ************ Auto-Keyframing ********************** */ /* Notes: diff --git a/source/blender/editors/include/ED_mesh.h b/source/blender/editors/include/ED_mesh.h index a2dba89ec20..634a3bc278b 100644 --- a/source/blender/editors/include/ED_mesh.h +++ b/source/blender/editors/include/ED_mesh.h @@ -118,6 +118,7 @@ void EM_select_face(struct EditFace *efa, int sel); void EM_select_face_fgon(struct EditMesh *em, struct EditFace *efa, int val); void EM_select_swap(struct EditMesh *em); void EM_toggle_select_all(struct EditMesh *em); +void EM_select_all(struct EditMesh *em); void EM_selectmode_flush(struct EditMesh *em); void EM_deselect_flush(struct EditMesh *em); void EM_selectmode_set(struct EditMesh *em); @@ -175,5 +176,13 @@ float ED_vgroup_vert_weight(struct Object *ob, struct bDeformGroup *dg, int ver struct MDeformWeight *ED_vgroup_weight_verify(struct MDeformVert *dv, int defgroup); struct MDeformWeight *ED_vgroup_weight_get(struct MDeformVert *dv, int defgroup); +/*needed by edge slide*/ +struct EditVert *editedge_getOtherVert(struct EditEdge *eed, struct EditVert *eve); +struct EditVert *editedge_getSharedVert(struct EditEdge *eed, struct EditEdge *eed2); +int editedge_containsVert(struct EditEdge *eed, struct EditVert *eve); +int editface_containsVert(struct EditFace *efa, struct EditVert *eve); +int editface_containsEdge(struct EditFace *efa, struct EditEdge *eed); +short sharesFace(struct EditMesh *em, struct EditEdge *e1, struct EditEdge *e2); + #endif /* ED_MESH_H */ diff --git a/source/blender/editors/include/ED_object.h b/source/blender/editors/include/ED_object.h index 67dc6dada5f..363795afeab 100644 --- a/source/blender/editors/include/ED_object.h +++ b/source/blender/editors/include/ED_object.h @@ -88,6 +88,8 @@ void object_test_constraints(struct Object *ob); void ED_object_constraint_rename(struct Object *ob, struct bConstraint *con, char *oldname); void ED_object_constraint_set_active(struct Object *ob, struct bConstraint *con); +void ED_object_constraint_update(struct Object *ob); +void ED_object_constraint_dependency_update(struct Scene *scene, struct Object *ob); /* object_lattice.c */ void mouse_lattice(struct bContext *C, short mval[2], int extend); diff --git a/source/blender/editors/include/ED_transform.h b/source/blender/editors/include/ED_transform.h index 96425f725e9..bf3111de5dc 100644 --- a/source/blender/editors/include/ED_transform.h +++ b/source/blender/editors/include/ED_transform.h @@ -75,7 +75,8 @@ enum { TFM_BAKE_TIME, TFM_BEVEL, TFM_BWEIGHT, - TFM_ALIGN + TFM_ALIGN, + TFM_EDGE_SLIDE } TfmMode; /* TRANSFORM CONTEXTS */ diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h index 848432b5f42..dc4744c9832 100644 --- a/source/blender/editors/include/UI_interface.h +++ b/source/blender/editors/include/UI_interface.h @@ -431,7 +431,7 @@ uiBut *uiDefBlockButN(uiBlock *block, uiBlockCreateFunc func, void *argN, char * uiBut *uiDefIconBlockBut(uiBlock *block, uiBlockCreateFunc func, void *arg, int retval, int icon, short x1, short y1, short x2, short y2, char *tip); uiBut *uiDefIconTextBlockBut(uiBlock *block, uiBlockCreateFunc func, void *arg, int icon, char *str, short x1, short y1, short x2, short y2, char *tip); -void uiDefKeyevtButS(uiBlock *block, int retval, char *str, short x1, short y1, short x2, short y2, short *spoin, char *tip); +uiBut *uiDefKeyevtButS(uiBlock *block, int retval, char *str, short x1, short y1, short x2, short y2, short *spoin, char *tip); uiBut *uiDefHotKeyevtButS(uiBlock *block, int retval, char *str, short x1, short y1, short x2, short y2, short *keypoin, short *modkeypoin, char *tip); uiBut *uiDefSearchBut(uiBlock *block, void *arg, int retval, int icon, int maxlen, short x1, short y1, short x2, short y2, char *tip); diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c index fbc3c859f20..1b05958b679 100644 --- a/source/blender/editors/interface/interface.c +++ b/source/blender/editors/interface/interface.c @@ -2271,8 +2271,9 @@ static uiBut *ui_def_but(uiBlock *block, int type, int retval, char *str, short } } - if(!ELEM7(but->type, BLOCK, BUT, LABEL, PULLDOWN, ROUNDBOX, LISTBOX, SEARCH_MENU)) - but->flag |= UI_BUT_UNDO; + if(ELEM8(but->type, BLOCK, BUT, LABEL, PULLDOWN, ROUNDBOX, LISTBOX, SEARCH_MENU, BUTM)); + else if(ELEM5(but->type, SCROLL, SEPR, LINK, INLINK, FTPREVIEW)); + else but->flag |= UI_BUT_UNDO; BLI_addtail(&block->buttons, but); @@ -3098,10 +3099,11 @@ uiBut *uiDefIconBlockBut(uiBlock *block, uiBlockCreateFunc func, void *arg, int return but; } -void uiDefKeyevtButS(uiBlock *block, int retval, char *str, short x1, short y1, short x2, short y2, short *spoin, char *tip) +uiBut *uiDefKeyevtButS(uiBlock *block, int retval, char *str, short x1, short y1, short x2, short y2, short *spoin, char *tip) { uiBut *but= ui_def_but(block, KEYEVT|SHO, retval, str, x1, y1, x2, y2, spoin, 0.0, 0.0, 0.0, 0.0, tip); ui_check_but(but); + return but; } /* short pointers hardcoded */ diff --git a/source/blender/editors/interface/interface_anim.c b/source/blender/editors/interface/interface_anim.c index 8c41726b81b..8037a609a2f 100644 --- a/source/blender/editors/interface/interface_anim.c +++ b/source/blender/editors/interface/interface_anim.c @@ -209,6 +209,18 @@ void ui_but_anim_remove_driver(bContext *C) WM_operator_name_call(C, "ANIM_OT_remove_driver_button", WM_OP_INVOKE_DEFAULT, NULL); } +void ui_but_anim_copy_driver(bContext *C) +{ + /* this operator calls uiAnimContextProperty above */ + WM_operator_name_call(C, "ANIM_OT_copy_driver_button", WM_OP_INVOKE_DEFAULT, NULL); +} + +void ui_but_anim_paste_driver(bContext *C) +{ + /* this operator calls uiAnimContextProperty above */ + WM_operator_name_call(C, "ANIM_OT_paste_driver_button", WM_OP_INVOKE_DEFAULT, NULL); +} + void ui_but_anim_add_keyingset(bContext *C) { /* this operator calls uiAnimContextProperty above */ @@ -264,6 +276,10 @@ void ui_but_anim_menu(bContext *C, uiBut *but) } else uiItemBooleanO(layout, "Delete Driver", 0, "ANIM_OT_remove_driver_button", "all", 0); + + uiItemO(layout, "Copy Driver", 0, "ANIM_OT_copy_driver_button"); + if (ANIM_driver_can_paste()) + uiItemO(layout, "Paste Driver", 0, "ANIM_OT_paste_driver_button"); } else if(but->flag & UI_BUT_ANIMATED_KEY); else if(RNA_property_animateable(&but->rnapoin, but->rnaprop)) { @@ -275,6 +291,9 @@ void ui_but_anim_menu(bContext *C, uiBut *but) } else uiItemBooleanO(layout, "Add Driver", 0, "ANIM_OT_add_driver_button", "all", 0); + + if (ANIM_driver_can_paste()) + uiItemO(layout, "Paste Driver", 0, "ANIM_OT_paste_driver_button"); } if(RNA_property_animateable(&but->rnapoin, but->rnaprop)) { diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c index e8d813d8ff9..b5de855cb80 100644 --- a/source/blender/editors/interface/interface_handlers.c +++ b/source/blender/editors/interface/interface_handlers.c @@ -855,6 +855,7 @@ static void ui_apply_button(bContext *C, uiBlock *block, uiBut *but, uiHandleBut ui_apply_but_CHARTAB(C, but, data); break; #endif + case KEYEVT: case HOTKEYEVT: ui_apply_but_BUT(C, but, data); break; @@ -1659,7 +1660,7 @@ static void ui_do_but_textedit_select(bContext *C, uiBlock *block, uiBut *but, u break; } case LEFTMOUSE: - if(event->val == 0) + if(event->val == KM_RELEASE) button_activate_state(C, but, BUTTON_STATE_TEXT_EDITING); retval= WM_UI_HANDLER_BREAK; break; diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h index 7ab99a83c4b..885005ba06e 100644 --- a/source/blender/editors/interface/interface_intern.h +++ b/source/blender/editors/interface/interface_intern.h @@ -470,6 +470,8 @@ void ui_but_anim_insert_keyframe(struct bContext *C); void ui_but_anim_delete_keyframe(struct bContext *C); void ui_but_anim_add_driver(struct bContext *C); void ui_but_anim_remove_driver(struct bContext *C); +void ui_but_anim_copy_driver(struct bContext *C); +void ui_but_anim_paste_driver(struct bContext *C); void ui_but_anim_add_keyingset(struct bContext *C); void ui_but_anim_remove_keyingset(struct bContext *C); void ui_but_anim_menu(struct bContext *C, uiBut *but); diff --git a/source/blender/editors/interface/interface_layout.c b/source/blender/editors/interface/interface_layout.c index b957ff83650..e3c392a145e 100644 --- a/source/blender/editors/interface/interface_layout.c +++ b/source/blender/editors/interface/interface_layout.c @@ -480,7 +480,7 @@ static void ui_item_enum_row(uiLayout *layout, uiBlock *block, PointerRNA *ptr, static uiBut *ui_item_with_label(uiLayout *layout, uiBlock *block, char *name, int icon, PointerRNA *ptr, PropertyRNA *prop, int index, int x, int y, int w, int h, int icon_only) { uiLayout *sub; - uiBut *but; + uiBut *but=NULL; PropertyType type; PropertySubType subtype; int labelw; @@ -533,7 +533,7 @@ void uiFileBrowseContextProperty(const bContext *C, PointerRNA *ptr, PropertyRNA prevbut= but->prev; /* find the button before the active one */ - if((but->flag & UI_BUT_LAST_ACTIVE) && prevbut && prevbut->rnapoin.id.data) { + if((but->flag & UI_BUT_LAST_ACTIVE) && prevbut && prevbut->rnapoin.data) { if(RNA_property_type(prevbut->rnaprop) == PROP_STRING) { *ptr= prevbut->rnapoin; *prop= prevbut->rnaprop; diff --git a/source/blender/editors/interface/interface_panel.c b/source/blender/editors/interface/interface_panel.c index cf29a1ddb58..fa24aa72b9f 100644 --- a/source/blender/editors/interface/interface_panel.c +++ b/source/blender/editors/interface/interface_panel.c @@ -963,6 +963,7 @@ static void check_panel_overlap(ARegion *ar, Panel *panel) } } +#if 0 // XXX panel docking/tabbing code that's no longer used static void test_add_new_tabs(ARegion *ar) { Panel *pa, *pasel=NULL, *palap=NULL; @@ -1016,6 +1017,7 @@ static void test_add_new_tabs(ARegion *ar) pa= pa->next; } } +#endif /************************ panel dragging ****************************/ @@ -1382,7 +1384,12 @@ static void panel_activate_state(const bContext *C, Panel *pa, uiHandlePanelStat if(state == PANEL_STATE_EXIT || state == PANEL_STATE_ANIMATION) { if(data && data->state != PANEL_STATE_ANIMATION) { - test_add_new_tabs(ar); // also copies locations of tabs in dragged panel + /* XXX: + * - the panel tabbing function call below (test_add_new_tabs()) has been commented out + * "It is too easy to do by accident when reordering panels, is very hard to control and use, and has no real benefit." - BillRey + * Aligorith, 2009Sep + */ + //test_add_new_tabs(ar); // also copies locations of tabs in dragged panel check_panel_overlap(ar, NULL); // clears } diff --git a/source/blender/editors/interface/interface_regions.c b/source/blender/editors/interface/interface_regions.c index 065d391e6d6..0f04333c6c5 100644 --- a/source/blender/editors/interface/interface_regions.c +++ b/source/blender/editors/interface/interface_regions.c @@ -2226,7 +2226,7 @@ static uiBlock *ui_block_func_POPUP(bContext *C, uiPopupBlockHandle *handle, voi } block->minbounds= minwidth; - uiTextBoundsBlock(block, 40); + uiTextBoundsBlock(block, 50); } /* if menu slides out of other menu, override direction */ diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c index b15ddcfae17..af4a4c13c80 100644 --- a/source/blender/editors/interface/interface_templates.c +++ b/source/blender/editors/interface/interface_templates.c @@ -405,10 +405,12 @@ void uiTemplateID(uiLayout *layout, bContext *C, PointerRNA *ptr, char *propname static void modifiers_setOnCage(bContext *C, void *ob_v, void *md_v) { Object *ob = ob_v; - ModifierData *md; - + ModifierData *md= md_v; int i, cageIndex = modifiers_getCageIndex(ob, NULL ); + /* undo button operation */ + md->mode ^= eModifierMode_OnCage; + for(i = 0, md=ob->modifiers.first; md; ++i, md=md->next) { if(md == md_v) { if(i >= cageIndex) @@ -517,9 +519,10 @@ static uiLayout *draw_modifier(uiLayout *layout, Object *ob, ModifierData *md, i /* XXX uiBlockSetEmboss(block, UI_EMBOSSR); */ if(ob->type==OB_MESH && modifier_couldBeCage(md) && index<=lastCageIndex) { - /* XXX uiBlockSetCol(block, color); */ - but = uiDefIconBut(block, BUT, 0, ICON_MESH_DATA, 0, 0, 16, 20, NULL, 0.0, 0.0, 0.0, 0.0, "Apply modifier to editing cage during Editmode"); + but = uiDefIconButBitI(block, TOG, eModifierMode_OnCage, 0, ICON_MESH_DATA, 0, 0, 16, 20, &md->mode, 0.0, 0.0, 0.0, 0.0, "Apply modifier to editing cage during Editmode"); + if(index < cageIndex) + uiButSetFlag(but, UI_BUT_DISABLED); uiButSetFunc(but, modifiers_setOnCage, ob, md); uiBlockEndAlign(block); /* XXX uiBlockSetCol(block, TH_AUTO); */ @@ -673,6 +676,8 @@ void do_constraint_panels(bContext *C, void *arg, int event) if(ob->type==OB_ARMATURE) DAG_id_flush_update(&ob->id, OB_RECALC_DATA|OB_RECALC_OB); else DAG_id_flush_update(&ob->id, OB_RECALC_OB); + + WM_event_add_notifier(C, NC_OBJECT|ND_CONSTRAINT, ob); // XXX allqueue(REDRAWVIEW3D, 0); // XXX allqueue(REDRAWBUTSOBJECT, 0); @@ -684,19 +689,15 @@ static void constraint_active_func(bContext *C, void *ob_v, void *con_v) ED_object_constraint_set_active(ob_v, con_v); } -static void verify_constraint_name_func (bContext *C, void *con_v, void *name_v) +static void verify_constraint_name_func (bContext *C, void *con_v, void *dummy) { Object *ob= CTX_data_active_object(C); bConstraint *con= con_v; - char oldname[32]; if (!con) return; - /* put on the stack */ - BLI_strncpy(oldname, (char *)name_v, 32); - - ED_object_constraint_rename(ob, con, oldname); + ED_object_constraint_rename(ob, con, NULL); ED_object_constraint_set_active(ob, con); // XXX allqueue(REDRAWACTION, 0); } @@ -901,10 +902,11 @@ static uiLayout *draw_constraint(uiLayout *layout, Object *ob, bConstraint *con) uiDefIconButO(block, BUT, "CONSTRAINT_OT_move_down", WM_OP_INVOKE_DEFAULT, VICON_MOVE_DOWN, xco+width-50+18, yco, 16, 18, "Move constraint down in constraint stack"); uiBlockEndAlign(block); } - - + /* Close 'button' - emboss calls here disable drawing of 'button' behind X */ uiBlockSetEmboss(block, UI_EMBOSSN); + uiDefIconButBitS(block, ICONTOGN, CONSTRAINT_OFF, B_CONSTRAINT_TEST, ICON_CHECKBOX_DEHLT, xco+243, yco, 19, 19, &con->flag, 0.0, 0.0, 0.0, 0.0, "enable/disable constraint"); + uiDefIconButO(block, BUT, "CONSTRAINT_OT_delete", WM_OP_INVOKE_DEFAULT, ICON_X, xco+262, yco, 19, 19, "Delete constraint"); uiBlockSetEmboss(block, UI_EMBOSS); } @@ -1336,7 +1338,7 @@ static void colorband_del_cb(bContext *C, void *cb_v, void *coba_v) /* offset aligns from bottom, standard width 300, height 115 */ static void colorband_buttons_large(uiBlock *block, ColorBand *coba, int xoffs, int yoffs, RNAUpdateCb *cb) { - CBData *cbd; + uiBut *bt; if(coba==NULL) return; @@ -1347,7 +1349,7 @@ static void colorband_buttons_large(uiBlock *block, ColorBand *coba, int xoffs, bt= uiDefBut(block, BUT, 0, "Delete", 60+xoffs,100+yoffs,50,20, 0, 0, 0, 0, 0, "Delete the active position"); uiButSetNFunc(bt, colorband_del_cb, MEM_dupallocN(cb), coba); - uiDefButS(block, NUM, 0, "", 120+xoffs,100+yoffs,80, 20, &coba->cur, 0.0, (float)(coba->tot-1), 0, 0, "Choose active color stop"); + uiDefButS(block, NUM, 0, "", 120+xoffs,100+yoffs,80, 20, &coba->cur, 0.0, (float)(MAX2(0, coba->tot-1)), 0, 0, "Choose active color stop"); bt= uiDefButS(block, MENU, 0, "Interpolation %t|Ease %x1|Cardinal %x3|Linear %x0|B-Spline %x2|Constant %x4", 210+xoffs, 100+yoffs, 90, 20, &coba->ipotype, 0.0, 0.0, 0, 0, "Set interpolation between color stops"); @@ -1357,36 +1359,38 @@ static void colorband_buttons_large(uiBlock *block, ColorBand *coba, int xoffs, bt= uiDefBut(block, BUT_COLORBAND, 0, "", xoffs,65+yoffs,300,30, coba, 0, 0, 0, 0, ""); uiButSetNFunc(bt, rna_update_cb, MEM_dupallocN(cb), NULL); - cbd= coba->data + coba->cur; + if(coba->tot) { + CBData *cbd= coba->data + coba->cur; - bt= uiDefButF(block, NUM, 0, "Pos:", 0+xoffs,40+yoffs,100, 20, &cbd->pos, 0.0, 1.0, 10, 0, "The position of the active color stop"); - uiButSetNFunc(bt, colorband_pos_cb, MEM_dupallocN(cb), coba); - bt= uiDefButF(block, COL, 0, "", 110+xoffs,40+yoffs,80,20, &(cbd->r), 0, 0, 0, B_BANDCOL, "The color value for the active color stop"); - uiButSetNFunc(bt, rna_update_cb, MEM_dupallocN(cb), NULL); - bt= uiDefButF(block, NUMSLI, 0, "A ", 200+xoffs,40+yoffs,100,20, &cbd->a, 0.0, 1.0, 10, 0, "The alpha value of the active color stop"); - uiButSetNFunc(bt, rna_update_cb, MEM_dupallocN(cb), NULL); + bt= uiDefButF(block, NUM, 0, "Pos:", 0+xoffs,40+yoffs,100, 20, &cbd->pos, 0.0, 1.0, 10, 0, "The position of the active color stop"); + uiButSetNFunc(bt, colorband_pos_cb, MEM_dupallocN(cb), coba); + bt= uiDefButF(block, COL, 0, "", 110+xoffs,40+yoffs,80,20, &(cbd->r), 0, 0, 0, B_BANDCOL, "The color value for the active color stop"); + uiButSetNFunc(bt, rna_update_cb, MEM_dupallocN(cb), NULL); + bt= uiDefButF(block, NUMSLI, 0, "A ", 200+xoffs,40+yoffs,100,20, &cbd->a, 0.0, 1.0, 10, 0, "The alpha value of the active color stop"); + uiButSetNFunc(bt, rna_update_cb, MEM_dupallocN(cb), NULL); + } } static void colorband_buttons_small(uiBlock *block, ColorBand *coba, rctf *butr, RNAUpdateCb *cb) { - CBData *cbd; uiBut *bt; float unit= (butr->xmax-butr->xmin)/14.0f; float xs= butr->xmin; - cbd= coba->data + coba->cur; - bt= uiDefBut(block, BUT, 0, "Add", xs,butr->ymin+20.0f,2.0f*unit,20, NULL, 0, 0, 0, 0, "Add a new color stop to the colorband"); uiButSetNFunc(bt, colorband_add_cb, MEM_dupallocN(cb), coba); bt= uiDefBut(block, BUT, 0, "Delete", xs+2.0f*unit,butr->ymin+20.0f,2.0f*unit,20, NULL, 0, 0, 0, 0, "Delete the active position"); uiButSetNFunc(bt, colorband_del_cb, MEM_dupallocN(cb), coba); - bt= uiDefButF(block, COL, 0, "", xs+4.0f*unit,butr->ymin+20.0f,2.0f*unit,20, &(cbd->r), 0, 0, 0, B_BANDCOL, "The color value for the active color stop"); - uiButSetNFunc(bt, rna_update_cb, MEM_dupallocN(cb), NULL); - bt= uiDefButF(block, NUMSLI, 0, "A:", xs+6.0f*unit,butr->ymin+20.0f,4.0f*unit,20, &(cbd->a), 0.0f, 1.0f, 10, 2, "The alpha value of the active color stop"); - uiButSetNFunc(bt, rna_update_cb, MEM_dupallocN(cb), NULL); + if(coba->tot) { + CBData *cbd= coba->data + coba->cur; + bt= uiDefButF(block, COL, 0, "", xs+4.0f*unit,butr->ymin+20.0f,2.0f*unit,20, &(cbd->r), 0, 0, 0, B_BANDCOL, "The color value for the active color stop"); + uiButSetNFunc(bt, rna_update_cb, MEM_dupallocN(cb), NULL); + bt= uiDefButF(block, NUMSLI, 0, "A:", xs+6.0f*unit,butr->ymin+20.0f,4.0f*unit,20, &(cbd->a), 0.0f, 1.0f, 10, 2, "The alpha value of the active color stop"); + uiButSetNFunc(bt, rna_update_cb, MEM_dupallocN(cb), NULL); + } bt= uiDefButS(block, MENU, 0, "Interpolation %t|Ease %x1|Cardinal %x3|Linear %x0|B-Spline %x2|Constant %x4", xs+10.0f*unit, butr->ymin+20.0f, unit*4, 20, &coba->ipotype, 0.0, 0.0, 0, 0, "Set interpolation between color stops"); diff --git a/source/blender/editors/interface/interface_utils.c b/source/blender/editors/interface/interface_utils.c index 00dec9a06c2..1d56ed4fb6a 100644 --- a/source/blender/editors/interface/interface_utils.c +++ b/source/blender/editors/interface/interface_utils.c @@ -73,7 +73,7 @@ uiBut *uiDefAutoButR(uiBlock *block, PointerRNA *ptr, PropertyRNA *prop, int ind if(RNA_property_subtype(prop) == PROP_COLOR) but= uiDefButR(block, COL, 0, name, x1, y1, x2, y2, ptr, propname, 0, 0, 0, -1, -1, NULL); } - else if(RNA_property_subtype(prop) == PROP_PERCENTAGE) + else if(RNA_property_subtype(prop) == PROP_PERCENTAGE || RNA_property_subtype(prop) == PROP_FACTOR) but= uiDefButR(block, NUMSLI, 0, name, x1, y1, x2, y2, ptr, propname, index, 0, 0, -1, -1, NULL); else but= uiDefButR(block, NUM, 0, name, x1, y1, x2, y2, ptr, propname, index, 0, 0, -1, -1, NULL); diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c index 90b2c920613..ac8750f84e6 100644 --- a/source/blender/editors/interface/interface_widgets.c +++ b/source/blender/editors/interface/interface_widgets.c @@ -773,7 +773,8 @@ static void widget_draw_icon(uiBut *but, BIFIconID icon, int blend, rcti *rect) /* sets but->ofs to make sure text is correctly visible */ static void ui_text_leftclip(uiFontStyle *fstyle, uiBut *but, rcti *rect) { - int okwidth= rect->xmax-rect->xmin; + int border= (but->flag & UI_BUT_ALIGN_RIGHT)? 8: 10; + int okwidth= rect->xmax-rect->xmin - border; /* need to set this first */ uiStyleFontSet(fstyle); @@ -842,11 +843,8 @@ static void widget_draw_text(uiFontStyle *fstyle, uiWidgetColors *wcol, uiBut *b but->drawstr[selend_tmp]= ch; - /* if at pos 0, leave a bit more to the left */ - t= (pos == 0)? 0: 1; - glColor3ubv((unsigned char*)wcol->item); - glRects(rect->xmin+selsta_draw+1, rect->ymin+2, rect->xmin+selwidth_draw+1, rect->ymax-2); + glRects(rect->xmin+selsta_draw, rect->ymin+2, rect->xmin+selwidth_draw, rect->ymax-2); } } else { /* text cursor */ @@ -861,9 +859,6 @@ static void widget_draw_text(uiFontStyle *fstyle, uiWidgetColors *wcol, uiBut *b but->drawstr[pos]= ch; } - /* if at pos 0, leave a bit more to the left */ - t += (pos == 0)? 0: 1; - glColor3ub(255,0,0); glRects(rect->xmin+t, rect->ymin+2, rect->xmin+t+2, rect->ymax-2); } diff --git a/source/blender/editors/interface/resources.c b/source/blender/editors/interface/resources.c index c54e09b2b40..87026bd1a5d 100644 --- a/source/blender/editors/interface/resources.c +++ b/source/blender/editors/interface/resources.c @@ -517,10 +517,12 @@ void ui_theme_init_userdef(void) /* space file */ /* to have something initialized */ btheme->tfile= btheme->tv3d; - SETCOL(btheme->tfile.back, 90, 90, 90, 255); + SETCOLF(btheme->tfile.back, 0.3, 0.3, 0.3, 1); + SETCOLF(btheme->tfile.panel, 0.3, 0.3, 0.3, 1); + SETCOLF(btheme->tfile.list, 0.4, 0.4, 0.4, 1); SETCOL(btheme->tfile.text, 250, 250, 250, 255); SETCOL(btheme->tfile.text_hi, 15, 15, 15, 255); - SETCOL(btheme->tfile.panel, 180, 180, 180, 255); // bookmark/ui regions + SETCOL(btheme->tfile.panel, 145, 145, 145, 255); // bookmark/ui regions SETCOL(btheme->tfile.active, 130, 130, 130, 255); // selected files SETCOL(btheme->tfile.hilite, 255, 140, 25, 255); // selected files @@ -604,11 +606,11 @@ void ui_theme_init_userdef(void) /* space node, re-uses syntax color storage */ btheme->tnode= btheme->tv3d; SETCOL(btheme->tnode.edge_select, 255, 255, 255, 255); - SETCOL(btheme->tnode.syntaxl, 150, 150, 150, 255); /* TH_NODE, backdrop */ - SETCOL(btheme->tnode.syntaxn, 129, 131, 144, 255); /* in/output */ - SETCOL(btheme->tnode.syntaxb, 127,127,127, 255); /* operator */ - SETCOL(btheme->tnode.syntaxv, 142, 138, 145, 255); /* generator */ - SETCOL(btheme->tnode.syntaxc, 120, 145, 120, 255); /* group */ + SETCOL(btheme->tnode.syntaxl, 155, 155, 155, 160); /* TH_NODE, backdrop */ + SETCOL(btheme->tnode.syntaxn, 100, 100, 100, 255); /* in/output */ + SETCOL(btheme->tnode.syntaxb, 108, 105, 111, 255); /* operator */ + SETCOL(btheme->tnode.syntaxv, 104, 106, 117, 255); /* generator */ + SETCOL(btheme->tnode.syntaxc, 105, 117, 110, 255); /* group */ /* space logic */ btheme->tlogic= btheme->tv3d; diff --git a/source/blender/editors/interface/view2d.c b/source/blender/editors/interface/view2d.c index f9fb7a9306f..be58a78ca85 100644 --- a/source/blender/editors/interface/view2d.c +++ b/source/blender/editors/interface/view2d.c @@ -1351,7 +1351,7 @@ View2DScrollers *UI_view2d_scrollers_calc(const bContext *C, View2D *v2d, short vert= v2d->vert; hor= v2d->hor; - /* slider rects smaller than region */ + /* slider rects need to be smaller than region */ hor.xmin+=4; hor.xmax-=4; if (scroll & V2D_SCROLL_BOTTOM) @@ -1393,13 +1393,18 @@ View2DScrollers *UI_view2d_scrollers_calc(const bContext *C, View2D *v2d, short else scrollers->hor_max= (int)(hor.xmin + (fac2 * scrollsize)); + /* prevent inverted sliders */ if (scrollers->hor_min > scrollers->hor_max) scrollers->hor_min= scrollers->hor_max; + /* prevent sliders from being too small, and disappearing */ + if ((scrollers->hor_max - scrollers->hor_min) < V2D_SCROLLER_HANDLE_SIZE) + scrollers->hor_max+= V2D_SCROLLER_HANDLE_SIZE; /* check whether sliders can disappear */ - if(v2d->keeptot) + if(v2d->keeptot) { if(fac1 <= 0.0f && fac2 >= 1.0f) scrollers->horfull= 1; + } } /* vertical scrollers */ @@ -1420,13 +1425,18 @@ View2DScrollers *UI_view2d_scrollers_calc(const bContext *C, View2D *v2d, short else scrollers->vert_max= (int)(vert.ymin + (fac2 * scrollsize)); + /* prevent inverted sliders */ if (scrollers->vert_min > scrollers->vert_max) scrollers->vert_min= scrollers->vert_max; + /* prevent sliders from being too small, and disappearing */ + if ((scrollers->vert_max - scrollers->vert_min) < V2D_SCROLLER_HANDLE_SIZE) + scrollers->vert_max+= V2D_SCROLLER_HANDLE_SIZE; /* check whether sliders can disappear */ - if(v2d->keeptot) + if(v2d->keeptot) { if(fac1 <= 0.0f && fac2 >= 1.0f) scrollers->vertfull= 1; + } } /* grid markings on scrollbars */ @@ -1550,14 +1560,6 @@ static void scroll_printstr(View2DScrollers *scrollers, Scene *scene, float x, f BLF_draw_default(x, y, 0.0f, str); } -/* local defines for scrollers drawing */ - /* radius of scroller 'button' caps */ -#define V2D_SCROLLCAP_RAD 5 - /* shading factor for scroller 'bar' */ -#define V2D_SCROLLBAR_SHADE 0.1f - /* shading factor for scroller 'button' caps */ -#define V2D_SCROLLCAP_SHADE 0.2f - /* Draw scrollbars in the given 2d-region */ void UI_view2d_scrollers_draw(const bContext *C, View2D *v2d, View2DScrollers *vs) { @@ -1571,7 +1573,7 @@ void UI_view2d_scrollers_draw(const bContext *C, View2D *v2d, View2DScrollers *v /* horizontal scrollbar */ if (scroll & V2D_SCROLL_HORIZONTAL) { - + /* only draw scrollbar when it doesn't fill the entire space */ if(vs->horfull==0) { bTheme *btheme= U.themes.first; uiWidgetColors wcol= btheme->tui.wcol_scroll; @@ -1584,13 +1586,15 @@ void UI_view2d_scrollers_draw(const bContext *C, View2D *v2d, View2DScrollers *v slider.ymax= hor.ymax; state= (v2d->scroll_ui & V2D_SCROLL_H_ACTIVE)?UI_SCROLL_PRESSED:0; + + // TODO: disable this for button regions... if (!(v2d->keepzoom & V2D_LOCKZOOM_X)) state |= UI_SCROLL_ARROWS; + uiWidgetScrollDraw(&wcol, &hor, &slider, state); } /* scale indicators */ - // XXX will need to update the font drawing when the new stuff comes in if ((scroll & V2D_SCROLL_SCALE_HORIZONTAL) && (vs->grid)) { View2DGrid *grid= vs->grid; float fac, dfac, fac2, val; @@ -1667,7 +1671,7 @@ void UI_view2d_scrollers_draw(const bContext *C, View2D *v2d, View2DScrollers *v /* vertical scrollbar */ if (scroll & V2D_SCROLL_VERTICAL) { - + /* only draw scrollbar when it doesn't fill the entire space */ if(vs->vertfull==0) { bTheme *btheme= U.themes.first; uiWidgetColors wcol= btheme->tui.wcol_scroll; @@ -1680,14 +1684,16 @@ void UI_view2d_scrollers_draw(const bContext *C, View2D *v2d, View2DScrollers *v slider.ymax= vs->vert_max; state= (v2d->scroll_ui & V2D_SCROLL_V_ACTIVE)?UI_SCROLL_PRESSED:0; - if (!(v2d->keepzoom & V2D_LOCKZOOM_Y)) + + // TODO: disable this for button regions... + if (!(v2d->keepzoom & V2D_LOCKZOOM_Y)) state |= UI_SCROLL_ARROWS; + uiWidgetScrollDraw(&wcol, &vert, &slider, state); } /* scale indiators */ - // XXX will need to update the font drawing when the new stuff comes in if ((scroll & V2D_SCROLL_SCALE_VERTICAL) && (vs->grid)) { View2DGrid *grid= vs->grid; float fac, dfac, val; diff --git a/source/blender/editors/interface/view2d_ops.c b/source/blender/editors/interface/view2d_ops.c index ae4fe4eed1b..0af5a5cac97 100644 --- a/source/blender/editors/interface/view2d_ops.c +++ b/source/blender/editors/interface/view2d_ops.c @@ -237,7 +237,7 @@ static int view_pan_modal(bContext *C, wmOperator *op, wmEvent *event) case LEFTMOUSE: case MIDDLEMOUSE: - if (event->val==0) { + if (event->val==KM_RELEASE) { /* calculate overall delta mouse-movement for redo */ RNA_int_set(op->ptr, "deltax", (vpd->startx - vpd->lastx)); RNA_int_set(op->ptr, "deltay", (vpd->starty - vpd->lasty)); @@ -836,7 +836,7 @@ static int view_zoomdrag_modal(bContext *C, wmOperator *op, wmEvent *event) case LEFTMOUSE: case MIDDLEMOUSE: - if (event->val==0) { + if (event->val==KM_RELEASE) { /* for redo, store the overall deltas - need to respect zoom-locks here... */ if ((v2d->keepzoom & V2D_LOCKZOOM_X)==0) RNA_float_set(op->ptr, "deltax", vzd->dx); @@ -1244,7 +1244,7 @@ static int scroller_activate_modal(bContext *C, wmOperator *op, wmEvent *event) break; case LEFTMOUSE: - if (event->val==0) { + if (event->val==KM_RELEASE) { scroller_activate_exit(C, op); return OPERATOR_FINISHED; } diff --git a/source/blender/editors/mesh/editmesh_mods.c b/source/blender/editors/mesh/editmesh_mods.c index 09ea9088a16..325a1aeec99 100644 --- a/source/blender/editors/mesh/editmesh_mods.c +++ b/source/blender/editors/mesh/editmesh_mods.c @@ -2033,6 +2033,9 @@ static void mouse_mesh_loop(bContext *C, short mval[2], short extend, short ring vc.mval[0]= mval[0]; vc.mval[1]= mval[1]; em= vc.em; + + /* no afterqueue (yet), so we check it now, otherwise the em_xxxofs indices are bad */ + view3d_validate_backbuf(&vc); eed= findnearestedge(&vc, &dist); if(eed) { @@ -2110,6 +2113,9 @@ static void mouse_mesh_shortest_path(bContext *C, short mval[2]) vc.mval[1]= mval[1]; em= vc.em; + /* no afterqueue (yet), so we check it now, otherwise the em_xxxofs indices are bad */ + view3d_validate_backbuf(&vc); + eed= findnearestedge(&vc, &dist); if(eed) { Mesh *me= vc.obedit->data; @@ -3287,6 +3293,11 @@ void EM_toggle_select_all(EditMesh *em) /* exported for UV */ EM_set_flag_all(em, SELECT); } +void EM_select_all(EditMesh *em) +{ + EM_set_flag_all(em, SELECT); +} + static int toggle_select_all_exec(bContext *C, wmOperator *op) { Object *obedit= CTX_data_edit_object(C); @@ -3547,7 +3558,7 @@ void MESH_OT_select_random(wmOperatorType *ot) ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; /* props */ - RNA_def_float_percentage(ot->srna, "percent", 0.5f, 0.0f, 1.0f, "Percent", "Percentage of vertices to select randomly.", 0.0001f, 1.0f); + RNA_def_float_percentage(ot->srna, "percent", 50.0f, 0.0f, 100.0f, "Percent", "Percentage of vertices to select randomly.", 0.0001f, 1.0f); } void EM_select_by_material(EditMesh *em, int index) diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c index 46b941f70df..510f6ab464b 100644 --- a/source/blender/editors/mesh/editmesh_tools.c +++ b/source/blender/editors/mesh/editmesh_tools.c @@ -140,7 +140,7 @@ static int vergface(const void *v1, const void *v2) /* *********************************** */ -void convert_to_triface(EditMesh *em, int direction) +static void convert_to_triface(EditMesh *em, int direction) { EditFace *efa, *efan, *next; float fac; @@ -483,9 +483,8 @@ static int removedoublesflag_exec(bContext *C, wmOperator *op) { Object *obedit= CTX_data_edit_object(C); EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data)); - /*char msg[100]; - - int cnt = removedoublesflag(em,1,0,RNA_float_get(op->ptr, "limit"));*/ + /*char msg[100];*/ + int cnt = removedoublesflag(em,1,0,RNA_float_get(op->ptr, "limit")); /*XXX this messes up last operator panel if(cnt) @@ -515,7 +514,7 @@ void MESH_OT_remove_doubles(wmOperatorType *ot) /* flags */ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; - RNA_def_float(ot->srna, "limit", 0.00001f, 0.000001f, 50.0f, "Merge Threshold", "Minimum distance between merged verts", 0.00001f, 10.0f); + RNA_def_float(ot->srna, "limit", 0.0001f, 0.000001f, 50.0f, "Merge Threshold", "Minimum distance between merged verts", 0.00001f, 2.0f); } // XXX is this needed? @@ -3868,11 +3867,11 @@ typedef struct SlideVert { EditVert origvert; } SlideVert; +#if 0 int EdgeSlide(EditMesh *em, wmOperator *op, short immediate, float imperc) { return 0; /* XXX REFACTOR - #if 0'd for now, otherwise can't make 64bit windows builds on 64bit machine */ -#if 0 useless: goto useless // because it doesn't do anything right now @@ -4654,11 +4653,12 @@ useless: } return 1; -#endif // END OF XXX } +#endif // END OF XXX int EdgeLoopDelete(EditMesh *em, wmOperator *op) { +#if 0 //XXX won't work with new edgeslide /* temporal flag setting so we keep UVs when deleting edge loops, * this is a bit of a hack but it works how you would want in almost all cases */ @@ -4677,6 +4677,8 @@ int EdgeLoopDelete(EditMesh *em, wmOperator *op) EM_select_flush(em); // DAG_id_flush_update(obedit->data, OB_RECALC_DATA); return 1; +#endif + return 0; } @@ -5635,7 +5637,7 @@ static void collapseuvs(EditMesh *em, EditVert *mergevert) } } -int collapseEdges(EditMesh *em) +static int collapseEdges(EditMesh *em) { EditVert *eve; EditEdge *eed; @@ -5701,7 +5703,7 @@ int collapseEdges(EditMesh *em) return mergecount; } -int merge_firstlast(EditMesh *em, int first, int uvmerge) +static int merge_firstlast(EditMesh *em, int first, int uvmerge) { EditVert *eve,*mergevert; EditSelection *ese; @@ -5735,7 +5737,7 @@ int merge_firstlast(EditMesh *em, int first, int uvmerge) return removedoublesflag(em, 1, 0, MERGELIMIT); } -void em_snap_to_center(EditMesh *em) +static void em_snap_to_center(EditMesh *em) { EditVert *eve; float cent[3] = {0.0f, 0.0f, 0.0f}; @@ -5760,7 +5762,7 @@ void em_snap_to_center(EditMesh *em) } } -void em_snap_to_cursor(EditMesh *em, bContext *C) +static void em_snap_to_cursor(EditMesh *em, bContext *C) { Scene *scene = CTX_data_scene(C); Object *ob= CTX_data_edit_object(C); @@ -5781,7 +5783,7 @@ void em_snap_to_cursor(EditMesh *em, bContext *C) } } -int merge_target(bContext *C, EditMesh *em, int target, int uvmerge) +static int merge_target(bContext *C, EditMesh *em, int target, int uvmerge) { EditVert *eve; @@ -5924,7 +5926,7 @@ typedef struct PathEdge { #define PATH_SELECT_EDGE_LENGTH 0 #define PATH_SELECT_TOPOLOGICAL 1 -int select_vertex_path_exec(bContext *C, wmOperator *op) +static int select_vertex_path_exec(bContext *C, wmOperator *op) { Object *obedit= CTX_data_edit_object(C); EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data); @@ -7137,7 +7139,7 @@ void MESH_OT_edge_flip(wmOperatorType *ot) /********************** Smooth/Solid Operators *************************/ -void mesh_set_smooth_faces(EditMesh *em, short smooth) +static void mesh_set_smooth_faces(EditMesh *em, short smooth) { EditFace *efa; diff --git a/source/blender/editors/mesh/loopcut.c b/source/blender/editors/mesh/loopcut.c index c322a169679..d1ef4ebc233 100644 --- a/source/blender/editors/mesh/loopcut.c +++ b/source/blender/editors/mesh/loopcut.c @@ -265,7 +265,10 @@ static void ringsel_finish(bContext *C, wmOperator *op) EditMesh *em = BKE_mesh_get_editmesh(lcd->ob->data); esubdivideflag(lcd->ob, em, SELECT, 0.0f, 0.0f, 0, 1, SUBDIV_SELECT_LOOPCUT); + + DAG_id_flush_update(lcd->ob->data, OB_RECALC_DATA); } + WM_event_add_notifier(C, NC_GEOM|ND_DATA, lcd->ob->data); } } @@ -380,7 +383,7 @@ static int ringsel_modal (bContext *C, wmOperator *op, wmEvent *event) switch (event->type) { case RIGHTMOUSE: case LEFTMOUSE: /* confirm */ // XXX hardcoded - if (event->val == 0) { + if (event->val == KM_RELEASE) { /* finish */ ED_region_tag_redraw(lcd->ar); diff --git a/source/blender/editors/mesh/mesh_intern.h b/source/blender/editors/mesh/mesh_intern.h index 11a974f2c49..37a6d0f384f 100644 --- a/source/blender/editors/mesh/mesh_intern.h +++ b/source/blender/editors/mesh/mesh_intern.h @@ -61,12 +61,6 @@ extern struct EditEdge *addedgelist(EditMesh *em, struct EditVert *v1, struct Ed extern struct EditFace *addfacelist(EditMesh *em, struct EditVert *v1, struct EditVert *v2, struct EditVert *v3, struct EditVert *v4, struct EditFace *example, struct EditFace *exampleEdges); extern struct EditEdge *findedgelist(EditMesh *em, struct EditVert *v1, struct EditVert *v2); -EditVert *editedge_getOtherVert(EditEdge *eed, EditVert *eve); -EditVert *editedge_getSharedVert(EditEdge *eed, EditEdge *eed2); -int editedge_containsVert(struct EditEdge *eed, struct EditVert *eve); -int editface_containsVert(struct EditFace *efa, struct EditVert *eve); -int editface_containsEdge(struct EditFace *efa, struct EditEdge *eed); - void em_setup_viewcontext(struct bContext *C, ViewContext *vc); void MESH_OT_separate(struct wmOperatorType *ot); diff --git a/source/blender/editors/mesh/mesh_ops.c b/source/blender/editors/mesh/mesh_ops.c index f22adc597c7..21148e59153 100644 --- a/source/blender/editors/mesh/mesh_ops.c +++ b/source/blender/editors/mesh/mesh_ops.c @@ -113,6 +113,7 @@ static int edge_specials_invoke(bContext *C, wmOperator *op, wmEvent *event) uiItemEnumO(layout, "Rotate Edge CCW", 0, "MESH_OT_edge_rotate", "direction", 2); //uiItemO(layout, "Loopcut", 0, "MESH_OT_loop_cut"); // CutEdgeloop(em, 1); //uiItemO(layout, "Edge Slide", 0, "MESH_OT_edge_slide"); // EdgeSlide(em, 0,0.0); + uiItemO(layout, "Edge Slide", 0, "TFM_OT_edge_slide"); uiItemO(layout, "Edge Loop", 0, "MESH_OT_loop_multi_select"); uiItemBooleanO(layout, "Edge Ring", 0, "MESH_OT_loop_multi_select", "ring", 1); uiItemO(layout, NULL, 0, "MESH_OT_loop_to_region"); @@ -355,7 +356,7 @@ void ED_keymap_mesh(wmWindowManager *wm) keymap= WM_keymap_find(wm, "EditMesh", 0, 0); keymap->poll= ED_operator_editmesh; - WM_keymap_add_item(keymap, "MESH_OT_loopcut", ACTIONMOUSE, KM_PRESS, KM_CTRL, RKEY); + WM_keymap_add_item(keymap, "MESH_OT_loopcut", RKEY, KM_PRESS, KM_CTRL, 0); /* selecting */ /* standard mouse selection goes via space_view3d */ @@ -428,7 +429,7 @@ void ED_keymap_mesh(wmWindowManager *wm) WM_keymap_add_item(keymap, "MESH_OT_edge_face_add", FKEY, KM_PRESS, 0, 0); WM_keymap_add_item(keymap, "MESH_OT_duplicate_move", DKEY, KM_PRESS, KM_SHIFT, 0); WM_keymap_add_item(keymap, "OBJECT_OT_mesh_add", AKEY, KM_PRESS, KM_SHIFT, 0); - WM_keymap_add_item(keymap, "MESH_OT_separate", PKEY, KM_PRESS, KM_SHIFT, 0); + WM_keymap_add_item(keymap, "MESH_OT_separate", PKEY, KM_PRESS, 0, 0); /* use KM_RELEASE because same key is used for tweaks */ WM_keymap_add_item(keymap, "MESH_OT_dupli_extrude_cursor", LEFTMOUSE, KM_RELEASE, KM_CTRL, 0); @@ -437,7 +438,7 @@ void ED_keymap_mesh(wmWindowManager *wm) WM_keymap_add_item(keymap, "MESH_OT_fgon_make", FKEY, KM_PRESS, KM_ALT, 0); WM_keymap_add_item(keymap, "MESH_OT_fgon_clear", FKEY, KM_PRESS, KM_SHIFT|KM_ALT, 0); - WM_keymap_add_item(keymap, "MESH_OT_knife_cut", LEFTMOUSE, KM_PRESS, KM_CTRL, XKEY); + WM_keymap_add_item(keymap, "MESH_OT_knife_cut", LEFTMOUSE, KM_PRESS, 0, KKEY); /* menus */ WM_keymap_add_item(keymap, "MESH_OT_vertex_specials", VKEY, KM_PRESS, KM_CTRL, 0); diff --git a/source/blender/editors/mesh/meshtools.c b/source/blender/editors/mesh/meshtools.c index 4aa99820a6e..00893f10165 100644 --- a/source/blender/editors/mesh/meshtools.c +++ b/source/blender/editors/mesh/meshtools.c @@ -632,7 +632,7 @@ void sort_faces(Scene *scene, View3D *v3d) if (event == 1) Mat4MulMat4(mat, OBACT->obmat, rv3d->viewmat); /* apply the view matrix to the object matrix */ else if (event == 2) { /* sort from cursor */ - if( v3d && v3d->localview ) { + if( v3d && v3d->localvd ) { VECCOPY(cur, v3d->cursor); } else { VECCOPY(cur, scene->cursor); diff --git a/source/blender/editors/object/Makefile b/source/blender/editors/object/Makefile index 70ada46c80f..fd2af305d87 100644 --- a/source/blender/editors/object/Makefile +++ b/source/blender/editors/object/Makefile @@ -47,6 +47,7 @@ CPPFLAGS += -I../../makesdna CPPFLAGS += -I../../makesrna CPPFLAGS += -I../../python CPPFLAGS += -I../../imbuf +CPPFLAGS += -I../../ikplugin # own include diff --git a/source/blender/editors/object/SConscript b/source/blender/editors/object/SConscript index 3371e172a82..6ecc80f2d81 100644 --- a/source/blender/editors/object/SConscript +++ b/source/blender/editors/object/SConscript @@ -6,7 +6,7 @@ sources = env.Glob('*.c') incs = '../include ../../blenlib ../../blenkernel ../../makesdna ../../imbuf' incs += ' ../../windowmanager #/intern/guardedalloc' incs += ' #/intern/guardedalloc' -incs += ' ../../makesrna ../../python' +incs += ' ../../makesrna ../../python ../../ikplugin' defs = [] diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c index ee9af61f516..05905cd42a4 100644 --- a/source/blender/editors/object/object_add.c +++ b/source/blender/editors/object/object_add.c @@ -32,6 +32,7 @@ #include "DNA_action_types.h" #include "DNA_curve_types.h" #include "DNA_group_types.h" +#include "DNA_lamp_types.h" #include "DNA_material_types.h" #include "DNA_mesh_types.h" #include "DNA_meta_types.h" @@ -109,7 +110,7 @@ void ED_object_base_init_from_view(bContext *C, Base *base) VECCOPY(ob->loc, scene->cursor); } else { - if (v3d->localview) { + if (v3d->localvd) { base->lay= ob->lay= v3d->layact | v3d->lay; VECCOPY(ob->loc, v3d->cursor); } @@ -165,7 +166,7 @@ static Object *object_add_type(bContext *C, int type) /* for object add operator */ static int object_add_exec(bContext *C, wmOperator *op) { - object_add_type(C, RNA_int_get(op->ptr, "type")); + object_add_type(C, RNA_enum_get(op->ptr, "type")); return OPERATOR_FINISHED; } @@ -467,7 +468,7 @@ static int object_metaball_add_invoke(bContext *C, wmOperator *op, wmEvent *even void OBJECT_OT_metaball_add(wmOperatorType *ot) { /* identifiers */ - ot->name= "Metaball"; + ot->name= "Add Metaball"; ot->description= "Add an metaball object to the scene."; ot->idname= "OBJECT_OT_metaball_add"; @@ -559,6 +560,45 @@ void OBJECT_OT_armature_add(wmOperatorType *ot) ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; } +static int object_lamp_add_exec(bContext *C, wmOperator *op) +{ + Object *ob; + int type= RNA_enum_get(op->ptr, "type"); + + ob= object_add_type(C, OB_LAMP); + if(ob && ob->data) + ((Lamp*)ob->data)->type= type; + + return OPERATOR_FINISHED; +} + +void OBJECT_OT_lamp_add(wmOperatorType *ot) +{ + static EnumPropertyItem lamp_type_items[] = { + {LA_LOCAL, "POINT", ICON_LAMP_POINT, "Point", "Omnidirectional point light source."}, + {LA_SUN, "SUN", ICON_LAMP_SUN, "Sun", "Constant direction parallel ray light source."}, + {LA_SPOT, "SPOT", ICON_LAMP_SPOT, "Spot", "Directional cone light source."}, + {LA_HEMI, "HEMI", ICON_LAMP_HEMI, "Hemi", "180 degree constant light source."}, + {LA_AREA, "AREA", ICON_LAMP_AREA, "Area", "Directional area light source."}, + {0, NULL, 0, NULL, NULL}}; + + /* identifiers */ + ot->name= "Add Lamp"; + ot->description = "Add a lamp object to the scene."; + ot->idname= "OBJECT_OT_lamp_add"; + + /* api callbacks */ + ot->invoke= WM_menu_invoke; + ot->exec= object_lamp_add_exec; + ot->poll= ED_operator_scene_editable; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; + + /* properties */ + RNA_def_enum(ot->srna, "type", lamp_type_items, 0, "Type", ""); +} + static int object_primitive_add_invoke(bContext *C, wmOperator *op, wmEvent *event) { uiPopupMenu *pup= uiPupMenuBegin(C, "Add Object", 0); @@ -567,7 +607,7 @@ static int object_primitive_add_invoke(bContext *C, wmOperator *op, wmEvent *eve uiItemMenuEnumO(layout, "Mesh", ICON_OUTLINER_OB_MESH, "OBJECT_OT_mesh_add", "type"); uiItemMenuEnumO(layout, "Curve", ICON_OUTLINER_OB_CURVE, "OBJECT_OT_curve_add", "type"); uiItemMenuEnumO(layout, "Surface", ICON_OUTLINER_OB_SURFACE, "OBJECT_OT_surface_add", "type"); - uiItemMenuEnumO(layout, NULL, ICON_OUTLINER_OB_META, "OBJECT_OT_metaball_add", "type"); + uiItemMenuEnumO(layout, "Metaball", ICON_OUTLINER_OB_META, "OBJECT_OT_metaball_add", "type"); uiItemO(layout, "Text", ICON_OUTLINER_OB_FONT, "OBJECT_OT_text_add"); uiItemS(layout); uiItemO(layout, "Armature", ICON_OUTLINER_OB_ARMATURE, "OBJECT_OT_armature_add"); @@ -575,7 +615,7 @@ static int object_primitive_add_invoke(bContext *C, wmOperator *op, wmEvent *eve uiItemEnumO(layout, NULL, ICON_OUTLINER_OB_EMPTY, "OBJECT_OT_add", "type", OB_EMPTY); uiItemS(layout); uiItemEnumO(layout, NULL, ICON_OUTLINER_OB_CAMERA, "OBJECT_OT_add", "type", OB_CAMERA); - uiItemEnumO(layout, NULL, ICON_OUTLINER_OB_LAMP, "OBJECT_OT_add", "type", OB_LAMP); + uiItemMenuEnumO(layout, "Lamp", ICON_OUTLINER_OB_LAMP, "OBJECT_OT_lamp_add", "type"); uiPupMenuEnd(C, pup); diff --git a/source/blender/editors/object/object_constraint.c b/source/blender/editors/object/object_constraint.c index 9b073ed5878..8c0da354938 100644 --- a/source/blender/editors/object/object_constraint.c +++ b/source/blender/editors/object/object_constraint.c @@ -56,6 +56,7 @@ #include "BKE_object.h" #include "BKE_report.h" #include "BKE_utildefines.h" +#include "BIK_api.h" #ifndef DISABLE_PYTHON #include "BPY_extern.h" @@ -334,6 +335,7 @@ static void test_constraints (Object *owner, const char substring[]) * optional... otherwise poletarget must exist too or else * the constraint is deemed invalid */ + /* default IK check ... */ if (exist_object(data->tar) == 0) { data->tar = NULL; curcon->flag |= CONSTRAINT_DISABLE; @@ -355,7 +357,8 @@ static void test_constraints (Object *owner, const char substring[]) } } } - + /* ... can be overwritten here */ + BIK_test_constraint(owner, curcon); /* targets have already been checked for this */ continue; } @@ -702,6 +705,25 @@ void ED_object_constraint_set_active(Object *ob, bConstraint *con) } } +void ED_object_constraint_update(Object *ob) +{ + + if(ob->pose) update_pose_constraint_flags(ob->pose); + + object_test_constraints(ob); + + if(ob->type==OB_ARMATURE) DAG_id_flush_update(&ob->id, OB_RECALC_DATA|OB_RECALC_OB); + else DAG_id_flush_update(&ob->id, OB_RECALC_OB); +} + +void ED_object_constraint_dependency_update(Scene *scene, Object *ob) +{ + ED_object_constraint_update(ob); + + if(ob->pose) ob->pose->flag |= POSE_RECALC; // checks & sorts pose channels + DAG_scene_sort(scene); +} + static int constraint_poll(bContext *C) { PointerRNA ptr= CTX_data_pointer_get_type(C, "constraint", &RNA_Constraint); @@ -717,6 +739,10 @@ static int constraint_delete_exec (bContext *C, wmOperator *op) /* remove constraint itself */ lb= get_active_constraints(ob); + if (BLI_findindex(lb, con) == -1) + /* abnormal situation which happens on bone constraint when the armature is not in pose mode */ + return OPERATOR_CANCELLED; + free_constraint_data(con); BLI_freelinkN(lb, con); @@ -823,17 +849,22 @@ void CONSTRAINT_OT_move_up (wmOperatorType *ot) static int pose_constraints_clear_exec(bContext *C, wmOperator *op) { Object *ob= CTX_data_active_object(C); + Scene *scene= CTX_data_scene(C); /* free constraints for all selected bones */ CTX_DATA_BEGIN(C, bPoseChannel*, pchan, selected_pchans) { free_constraints(&pchan->constraints); + pchan->constflag &= ~(PCHAN_HAS_IK|PCHAN_HAS_CONST); } CTX_DATA_END; + /* force depsgraph to get recalculated since relationships removed */ + DAG_scene_sort(scene); /* sort order of objects */ + /* do updates */ - DAG_id_flush_update(&ob->id, OB_RECALC_OB); - WM_event_add_notifier(C, NC_OBJECT|ND_POSE|ND_CONSTRAINT|NA_REMOVED, ob); + DAG_id_flush_update(&ob->id, OB_RECALC_DATA); + WM_event_add_notifier(C, NC_OBJECT|ND_CONSTRAINT, ob); return OPERATOR_FINISHED; } @@ -854,14 +885,18 @@ void POSE_OT_constraints_clear(wmOperatorType *ot) static int object_constraints_clear_exec(bContext *C, wmOperator *op) { Object *ob= CTX_data_active_object(C); + Scene *scene= CTX_data_scene(C); /* do freeing */ // TODO: we should free constraints for all selected objects instead (to be more consistent with bones) free_constraints(&ob->constraints); + /* force depsgraph to get recalculated since relationships removed */ + DAG_scene_sort(scene); /* sort order of objects */ + /* do updates */ DAG_id_flush_update(&ob->id, OB_RECALC_OB); - WM_event_add_notifier(C, NC_OBJECT|ND_CONSTRAINT|NA_REMOVED, ob); + WM_event_add_notifier(C, NC_OBJECT|ND_CONSTRAINT, ob); return OPERATOR_FINISHED; } @@ -910,7 +945,6 @@ static short get_new_constraint_target(bContext *C, int con_type, Object **tar_o /* restricted target-type constraints -------------- */ /* NOTE: for these, we cannot try to add a target object if no valid ones are found, since that doesn't work */ /* curve-based constraints - set the only_curve and only_ob flags */ - case CONSTRAINT_TYPE_TRACKTO: case CONSTRAINT_TYPE_CLAMPTO: case CONSTRAINT_TYPE_FOLLOWPATH: only_curve= 1; diff --git a/source/blender/editors/object/object_intern.h b/source/blender/editors/object/object_intern.h index 315b6632051..87c4560916d 100644 --- a/source/blender/editors/object/object_intern.h +++ b/source/blender/editors/object/object_intern.h @@ -89,6 +89,7 @@ void OBJECT_OT_surface_add(struct wmOperatorType *ot); void OBJECT_OT_metaball_add(struct wmOperatorType *ot); void OBJECT_OT_text_add(struct wmOperatorType *ot); void OBJECT_OT_armature_add(struct wmOperatorType *ot); +void OBJECT_OT_lamp_add(struct wmOperatorType *ot); void OBJECT_OT_primitive_add(struct wmOperatorType *ot); /* only used as menu */ void OBJECT_OT_duplicates_make_real(struct wmOperatorType *ot); diff --git a/source/blender/editors/object/object_ops.c b/source/blender/editors/object/object_ops.c index fdfe6ed501c..7397cead505 100644 --- a/source/blender/editors/object/object_ops.c +++ b/source/blender/editors/object/object_ops.c @@ -115,6 +115,7 @@ void ED_operatortypes_object(void) WM_operatortype_append(OBJECT_OT_text_add); WM_operatortype_append(OBJECT_OT_surface_add); WM_operatortype_append(OBJECT_OT_armature_add); + WM_operatortype_append(OBJECT_OT_lamp_add); WM_operatortype_append(OBJECT_OT_add); WM_operatortype_append(OBJECT_OT_primitive_add); WM_operatortype_append(OBJECT_OT_mesh_add); @@ -243,6 +244,7 @@ void ED_keymap_object(wmWindowManager *wm) WM_keymap_add_item(keymap, "OBJECT_OT_duplicate_move", DKEY, KM_PRESS, KM_SHIFT, 0); RNA_boolean_set(WM_keymap_add_item(keymap, "OBJECT_OT_duplicate", DKEY, KM_PRESS, KM_ALT, 0)->ptr, "linked", 1); WM_keymap_add_item(keymap, "OBJECT_OT_join", JKEY, KM_PRESS, KM_CTRL, 0); + WM_keymap_add_item(keymap, "OBJECT_OT_convert", CKEY, KM_PRESS, KM_ALT, 0); WM_keymap_add_item(keymap, "OBJECT_OT_proxy_make", PKEY, KM_PRESS, KM_CTRL|KM_ALT, 0); // XXX this should probably be in screen instead... here for testing purposes in the meantime... - Aligorith diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c index 12cb2b95e06..4a0c812f7b1 100644 --- a/source/blender/editors/object/object_relations.c +++ b/source/blender/editors/object/object_relations.c @@ -566,8 +566,9 @@ static int parent_set_exec(bContext *C, wmOperator *op) } else cu->flag |= CU_FOLLOW; - /* fall back on regular parenting now */ - partype= PAR_OBJECT; + /* fall back on regular parenting now (for follow only) */ + if(partype == PAR_FOLLOW) + partype= PAR_OBJECT; } } else if(partype==PAR_BONE) { @@ -593,7 +594,9 @@ static int parent_set_exec(bContext *C, wmOperator *op) /* apply transformation of previous parenting */ ED_object_apply_obmat(ob); - ob->parent= par; + /* set the parent (except for follow-path constraint option) */ + if(partype != PAR_PATH_CONST) + ob->parent= par; /* handle types */ if (pchan) @@ -602,7 +605,7 @@ static int parent_set_exec(bContext *C, wmOperator *op) ob->parsubstr[0]= 0; /* constraint */ - if(partype==PAR_PATH_CONST) { + if(partype == PAR_PATH_CONST) { bConstraint *con; bFollowPathConstraint *data; float cmat[4][4], vec[3]; @@ -620,6 +623,7 @@ static int parent_set_exec(bContext *C, wmOperator *op) ob->loc[0] = vec[0]; ob->loc[1] = vec[1]; + ob->loc[2] = vec[2]; } else if(pararm && ob->type==OB_MESH && par->type == OB_ARMATURE) { if(partype == PAR_ARMATURE_NAME) @@ -645,8 +649,12 @@ static int parent_set_exec(bContext *C, wmOperator *op) ob->recalc |= OB_RECALC_OB|OB_RECALC_DATA; + if(partype == PAR_PATH_CONST) + ; /* don't do anything here, since this is not technically "parenting" */ if( ELEM(partype, PAR_CURVE, PAR_LATTICE) || pararm ) ob->partype= PARSKEL; /* note, dna define, not operator property */ + else if (partype == PAR_BONE) + ob->partype= PARBONE; /* note, dna define, not operator property */ else ob->partype= PAROBJECT; /* note, dna define, not operator property */ } @@ -986,7 +994,7 @@ static int move_to_layer_exec(bContext *C, wmOperator *op) if(lay==0) return OPERATOR_CANCELLED; - if(v3d && v3d->localview) { + if(v3d && v3d->localvd) { /* now we can move out of localview. */ // XXX if (!okee("Move from localview")) return; CTX_DATA_BEGIN(C, Base*, base, selected_editable_bases) { diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c index b7e7fd18547..ae3f74403f2 100644 --- a/source/blender/editors/screen/screen_ops.c +++ b/source/blender/editors/screen/screen_ops.c @@ -604,7 +604,7 @@ static int area_swap_modal(bContext *C, wmOperator *op, wmEvent *event) sad->sa2= screen_areahascursor(CTX_wm_screen(C), event->x, event->y); break; case LEFTMOUSE: /* release LMB */ - if(event->val==0) { + if(event->val==KM_RELEASE) { if(!sad->sa2 || sad->sa1 == sad->sa2) { return area_swap_cancel(C, op); @@ -1225,7 +1225,7 @@ static int area_split_modal(bContext *C, wmOperator *op, wmEvent *event) break; case LEFTMOUSE: - if(event->val==0) { /* mouse up */ + if(event->val==KM_RELEASE) { /* mouse up */ area_split_exit(C, op); return OPERATOR_FINISHED; } @@ -1345,12 +1345,14 @@ static int region_scale_modal(bContext *C, wmOperator *op, wmEvent *event) break; case LEFTMOUSE: - if(event->val==0) { + if(event->val==KM_RELEASE) { if(ABS(event->x - rmd->origx) < 2 && ABS(event->y - rmd->origy) < 2) { - ED_region_toggle_hidden(C, rmd->ar); - WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL); - } + if(rmd->ar->flag & RGN_FLAG_HIDDEN) { + ED_region_toggle_hidden(C, rmd->ar); + WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL); + } + } MEM_freeN(op->customdata); op->customdata = NULL; @@ -1444,29 +1446,6 @@ static void SCREEN_OT_frame_jump(wmOperatorType *ot) /* ************** jump to keyframe operator ***************************** */ -/* helper function - find actkeycolumn that occurs on cframe, or the nearest one if not found */ -// TODO: make this an API func? -static ActKeyColumn *cfra_find_nearest_next_ak (ActKeyColumn *ak, float cframe, short next) -{ - ActKeyColumn *akn= NULL; - - /* sanity checks */ - if (ak == NULL) - return NULL; - - /* check if this is a match, or whether it is in some subtree */ - if (cframe < ak->cfra) - akn= cfra_find_nearest_next_ak(ak->left, cframe, next); - else if (cframe > ak->cfra) - akn= cfra_find_nearest_next_ak(ak->right, cframe, next); - - /* if no match found (or found match), just use the current one */ - if (akn == NULL) - return ak; - else - return akn; -} - /* function to be called outside UI context, or for redo */ static int keyframe_jump_exec(bContext *C, wmOperator *op) { @@ -1595,7 +1574,7 @@ static int screen_full_area_exec(bContext *C, wmOperator *op) static void SCREEN_OT_screen_full_area(wmOperatorType *ot) { - ot->name = "Toggle Make Area Fullscreen"; + ot->name = "Toggle Full Screen"; ot->idname = "SCREEN_OT_screen_full_area"; ot->exec= screen_full_area_exec; @@ -1849,7 +1828,7 @@ static int area_join_modal(bContext *C, wmOperator *op, wmEvent *event) } break; case LEFTMOUSE: - if(event->val==0) { + if(event->val==KM_RELEASE) { area_join_apply(C, op); WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL); area_join_exit(C, op); @@ -2118,7 +2097,7 @@ static int region_foursplit_exec(bContext *C, wmOperator *op) static void SCREEN_OT_region_foursplit(wmOperatorType *ot) { /* identifiers */ - ot->name= "Split Region in 4 Parts"; + ot->name= "Toggle Quad View"; ot->idname= "SCREEN_OT_region_foursplit"; /* api callbacks */ @@ -2197,6 +2176,10 @@ static int match_region_with_redraws(int spacetype, int regiontype, int redraws) if(redraws & (TIME_SEQ|TIME_ALL_ANIM_WIN)) return 1; break; + case SPACE_NODE: + if(redraws & (TIME_NODES)) + return 1; + break; case SPACE_IMAGE: if(redraws & TIME_ALL_IMAGE_WIN) return 1; @@ -2229,7 +2212,7 @@ static int screen_animation_step(bContext *C, wmOperator *op, wmEvent *event) /* sync, don't sync, or follow scene setting */ if(sad->flag & ANIMPLAY_FLAG_SYNC) sync= 1; else if(sad->flag & ANIMPLAY_FLAG_NO_SYNC) sync= 0; - else sync= (scene->r.audio.flag & AUDIO_SYNC); + else sync= (scene->audio.flag & AUDIO_SYNC); if(sync) { /* skip frames */ @@ -2364,7 +2347,7 @@ static int screen_animation_play(bContext *C, wmOperator *op, wmEvent *event) static void SCREEN_OT_animation_play(wmOperatorType *ot) { /* identifiers */ - ot->name= "Animation player"; + ot->name= "Play Animation"; ot->idname= "SCREEN_OT_animation_play"; /* api callbacks */ diff --git a/source/blender/editors/sculpt_paint/paint_image.c b/source/blender/editors/sculpt_paint/paint_image.c index 91ee2fa55d1..d223c423690 100644 --- a/source/blender/editors/sculpt_paint/paint_image.c +++ b/source/blender/editors/sculpt_paint/paint_image.c @@ -3731,7 +3731,7 @@ static void *do_projectpaint_thread(void *ph_v) /*if (dist < s->brush->size) {*/ /* correct but uses a sqrtf */ if (dist_nosqrt < brush_size_sqared && (dist=sqrtf(dist_nosqrt)) < size_half) { - falloff = brush_curve_strength(ps->brush, dist, size_half); + falloff = brush_curve_strength_clamp(ps->brush, dist, size_half); if (falloff > 0.0f) { if (ps->is_texbrush) { brush_sample_tex(ps->brush, projPixel->projCoSS, rgba); diff --git a/source/blender/editors/sculpt_paint/paint_stroke.c b/source/blender/editors/sculpt_paint/paint_stroke.c index bd9ea50e0f8..b83352ae70c 100644 --- a/source/blender/editors/sculpt_paint/paint_stroke.c +++ b/source/blender/editors/sculpt_paint/paint_stroke.c @@ -263,7 +263,7 @@ int paint_stroke_modal(bContext *C, wmOperator *op, wmEvent *event) } /* TODO: fix hardcoded event here */ - if(event->type == LEFTMOUSE && event->val == 0) { + if(event->type == LEFTMOUSE && event->val == KM_RELEASE) { /* Exit stroke, free data */ if(stroke->smooth_stroke_cursor) diff --git a/source/blender/editors/space_action/action_edit.c b/source/blender/editors/space_action/action_edit.c index 9e05c482ecb..865d072d938 100644 --- a/source/blender/editors/space_action/action_edit.c +++ b/source/blender/editors/space_action/action_edit.c @@ -89,6 +89,44 @@ #include "action_intern.h" /* ************************************************************************** */ +/* ACTION MANAGEMENT */ + +/* ******************** New Action Operator *********************** */ + +static int act_new_exec(bContext *C, wmOperator *op) +{ + bAction *action; + + // XXX need to restore behaviour to copy old actions... + action= add_empty_action("Action"); + + /* combined with RNA property, this will assign & increase user, + so decrease here to compensate for that */ + action->id.us--; + + /* set notifier that keyframes have changed */ + WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME_EDIT, NULL); + + return OPERATOR_FINISHED; +} + +void ACT_OT_new (wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "New"; + ot->idname= "ACT_OT_new"; + ot->description= "Create new action."; + + /* api callbacks */ + ot->exec= act_new_exec; + // NOTE: this is used in the NLA too... + //ot->poll= ED_operator_action_active; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; +} + +/* ************************************************************************** */ /* KEYFRAME-RANGE STUFF */ /* *************************** Calculate Range ************************** */ @@ -1331,38 +1369,4 @@ void ACT_OT_mirror (wmOperatorType *ot) RNA_def_enum(ot->srna, "type", prop_actkeys_mirror_types, 0, "Type", ""); } -/* ******************** New Action Operator *********************** */ - -static int act_new_exec(bContext *C, wmOperator *op) -{ - bAction *action; - - // XXX need to restore behaviour to copy old actions... - action= add_empty_action("Action"); - - /* combined with RNA property, this will assign & increase user, - so decrease here to compensate for that */ - action->id.us--; - - /* set notifier that keyframes have changed */ - WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME_EDIT, NULL); - - return OPERATOR_FINISHED; -} - -void ACT_OT_new (wmOperatorType *ot) -{ - /* identifiers */ - ot->name= "New"; - ot->idname= "ACT_OT_new"; - ot->description= "Create new action."; - - /* api callbacks */ - ot->exec= act_new_exec; - ot->poll= ED_operator_action_active; - - /* flags */ - ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; -} - /* ************************************************************************** */ diff --git a/source/blender/editors/space_action/action_header.c b/source/blender/editors/space_action/action_header.c index 4cb02f3f233..25a5123d1b5 100644 --- a/source/blender/editors/space_action/action_header.c +++ b/source/blender/editors/space_action/action_header.c @@ -189,6 +189,7 @@ static void act_edit_keytypesmenu(bContext *C, uiLayout *layout, void *arg_unuse uiLayoutSetOperatorContext(layout, WM_OP_EXEC_DEFAULT); uiItemEnumO(layout, NULL, 0, "ACT_OT_keyframe_type", "type", BEZT_KEYTYPE_KEYFRAME); uiItemEnumO(layout, NULL, 0, "ACT_OT_keyframe_type", "type", BEZT_KEYTYPE_BREAKDOWN); + uiItemEnumO(layout, NULL, 0, "ACT_OT_keyframe_type", "type", BEZT_KEYTYPE_EXTREME); } static void act_edit_handlesmenu(bContext *C, uiLayout *layout, void *arg_unused) @@ -335,23 +336,7 @@ void action_header_buttons(const bContext *C, ARegion *ar) /* FILTERING OPTIONS */ xco -= 10; - //uiBlockBeginAlign(block); - uiDefIconButBitI(block, TOG, ADS_FILTER_ONLYSEL, B_REDR, ICON_RESTRICT_SELECT_OFF, (short)(xco+=XIC),yco,XIC,YIC, &(saction->ads.filterflag), 0, 0, 0, 0, "Only display selected Objects"); - //uiBlockEndAlign(block); - xco += 5; - - uiBlockBeginAlign(block); - uiDefIconButBitI(block, TOGN, ADS_FILTER_NOSCE, B_REDR, ICON_SCENE_DATA, (short)(xco+=XIC),yco,XIC,YIC, &(saction->ads.filterflag), 0, 0, 0, 0, "Display Scene Animation"); - uiDefIconButBitI(block, TOGN, ADS_FILTER_NOWOR, B_REDR, ICON_WORLD_DATA, (short)(xco+=XIC),yco,XIC,YIC, &(saction->ads.filterflag), 0, 0, 0, 0, "Display World Animation"); - uiDefIconButBitI(block, TOGN, ADS_FILTER_NOSHAPEKEYS, B_REDR, ICON_SHAPEKEY_DATA, (short)(xco+=XIC),yco,XIC,YIC, &(saction->ads.filterflag), 0, 0, 0, 0, "Display ShapeKeys"); - uiDefIconButBitI(block, TOGN, ADS_FILTER_NOMAT, B_REDR, ICON_MATERIAL_DATA, (short)(xco+=XIC),yco,XIC,YIC, &(saction->ads.filterflag), 0, 0, 0, 0, "Display Materials"); - uiDefIconButBitI(block, TOGN, ADS_FILTER_NOLAM, B_REDR, ICON_LAMP_DATA, (short)(xco+=XIC),yco,XIC,YIC, &(saction->ads.filterflag), 0, 0, 0, 0, "Display Lamps"); - uiDefIconButBitI(block, TOGN, ADS_FILTER_NOCAM, B_REDR, ICON_CAMERA_DATA, (short)(xco+=XIC),yco,XIC,YIC, &(saction->ads.filterflag), 0, 0, 0, 0, "Display Cameras"); - uiDefIconButBitI(block, TOGN, ADS_FILTER_NOCUR, B_REDR, ICON_CURVE_DATA, (short)(xco+=XIC),yco,XIC,YIC, &(saction->ads.filterflag), 0, 0, 0, 0, "Display Curves"); - uiDefIconButBitI(block, TOGN, ADS_FILTER_NOMBA, B_REDR, ICON_META_DATA, (short)(xco+=XIC),yco,XIC,YIC, &(saction->ads.filterflag), 0, 0, 0, 0, "Display MetaBalls"); - uiDefIconButBitI(block, TOGN, ADS_FILTER_NOPART, B_REDR, ICON_PARTICLE_DATA, (short)(xco+=XIC),yco,XIC,YIC, &(saction->ads.filterflag), 0, 0, 0, 0, "Display Particles"); - uiBlockEndAlign(block); - xco += 30; + xco= ANIM_headerUI_standard_buttons(C, &saction->ads, block, xco, yco); } else if (saction->mode == SACTCONT_ACTION) { uiLayout *layout; diff --git a/source/blender/editors/space_action/space_action.c b/source/blender/editors/space_action/space_action.c index bceee73d5f0..3b275cab814 100644 --- a/source/blender/editors/space_action/space_action.c +++ b/source/blender/editors/space_action/space_action.c @@ -323,6 +323,7 @@ static void action_main_area_listener(ARegion *ar, wmNotifier *wmn) break; case NC_SCENE: switch(wmn->data) { + case ND_RENDER_OPTIONS: case ND_OB_ACTIVE: case ND_FRAME: case ND_MARKERS: diff --git a/source/blender/editors/space_buttons/buttons_context.c b/source/blender/editors/space_buttons/buttons_context.c index 635abd429f6..9333ba9209c 100644 --- a/source/blender/editors/space_buttons/buttons_context.c +++ b/source/blender/editors/space_buttons/buttons_context.c @@ -463,6 +463,7 @@ static int buttons_context_path(const bContext *C, ButsContextPath *path, int ma found= buttons_context_path_texture(C, path); break; case BCONTEXT_BONE: + case BCONTEXT_BONE_CONSTRAINT: found= buttons_context_path_bone(path); if(!found) found= buttons_context_path_data(path, OB_ARMATURE); @@ -553,7 +554,7 @@ int buttons_context(const bContext *C, const char *member, bContextDataResult *r "world", "object", "mesh", "armature", "lattice", "curve", "meta_ball", "lamp", "camera", "material", "material_slot", "texture", "texture_slot", "bone", "edit_bone", "particle_system", - "cloth", "soft_body", "fluid", "smoke", "smoke_hr", "collision", "brush", NULL}; + "cloth", "soft_body", "fluid", "smoke", "collision", "brush", NULL}; CTX_data_dir_set(result, dir); return 1; diff --git a/source/blender/editors/space_buttons/buttons_header.c b/source/blender/editors/space_buttons/buttons_header.c index a1041bc5106..83dd679c543 100644 --- a/source/blender/editors/space_buttons/buttons_header.c +++ b/source/blender/editors/space_buttons/buttons_header.c @@ -114,13 +114,15 @@ void buttons_header_buttons(const bContext *C, ARegion *ar) if(sbuts->pathflag & (1<<BCONTEXT_OBJECT)) uiDefIconButS(block, ROW, B_CONTEXT_SWITCH, ICON_OBJECT_DATA, xco+=BUTS_UI_UNIT, yco, BUTS_UI_UNIT, BUTS_UI_UNIT, &(sbuts->mainb), 0.0, (float)BCONTEXT_OBJECT, 0, 0, "Object"); if(sbuts->pathflag & (1<<BCONTEXT_CONSTRAINT)) - uiDefIconButS(block, ROW, B_CONTEXT_SWITCH, ICON_CONSTRAINT, xco+=BUTS_UI_UNIT, yco, BUTS_UI_UNIT, BUTS_UI_UNIT, &(sbuts->mainb), 0.0, (float)BCONTEXT_CONSTRAINT, 0, 0, "Constraint"); + uiDefIconButS(block, ROW, B_CONTEXT_SWITCH, ICON_CONSTRAINT, xco+=BUTS_UI_UNIT, yco, BUTS_UI_UNIT, BUTS_UI_UNIT, &(sbuts->mainb), 0.0, (float)BCONTEXT_CONSTRAINT, 0, 0, "Object Constraints"); if(sbuts->pathflag & (1<<BCONTEXT_DATA)) uiDefIconButS(block, ROW, B_CONTEXT_SWITCH, sbuts->dataicon, xco+=BUTS_UI_UNIT, yco, BUTS_UI_UNIT, BUTS_UI_UNIT, &(sbuts->mainb), 0.0, (float)BCONTEXT_DATA, 0, 0, "Object Data"); if(sbuts->pathflag & (1<<BCONTEXT_MODIFIER)) - uiDefIconButS(block, ROW, B_CONTEXT_SWITCH, ICON_MODIFIER, xco+=BUTS_UI_UNIT, yco, BUTS_UI_UNIT, BUTS_UI_UNIT, &(sbuts->mainb), 0.0, (float)BCONTEXT_MODIFIER, 0, 0, "Modifier"); + uiDefIconButS(block, ROW, B_CONTEXT_SWITCH, ICON_MODIFIER, xco+=BUTS_UI_UNIT, yco, BUTS_UI_UNIT, BUTS_UI_UNIT, &(sbuts->mainb), 0.0, (float)BCONTEXT_MODIFIER, 0, 0, "Modifiers"); if(sbuts->pathflag & (1<<BCONTEXT_BONE)) uiDefIconButS(block, ROW, B_CONTEXT_SWITCH, ICON_BONE_DATA, xco+=BUTS_UI_UNIT, yco, BUTS_UI_UNIT, BUTS_UI_UNIT, &(sbuts->mainb), 0.0, (float)BCONTEXT_BONE, 0, 0, "Bone"); + if(sbuts->pathflag & (1<<BCONTEXT_BONE_CONSTRAINT)) + uiDefIconButS(block, ROW, B_CONTEXT_SWITCH, ICON_CONSTRAINT, xco+=BUTS_UI_UNIT, yco, BUTS_UI_UNIT, BUTS_UI_UNIT, &(sbuts->mainb), 0.0, (float)BCONTEXT_BONE_CONSTRAINT, 0, 0, "Bone Constraints"); if(sbuts->pathflag & (1<<BCONTEXT_MATERIAL)) uiDefIconButS(block, ROW, B_CONTEXT_SWITCH, ICON_MATERIAL, xco+=BUTS_UI_UNIT, yco, BUTS_UI_UNIT, BUTS_UI_UNIT, &(sbuts->mainb), 0.0, (float)BCONTEXT_MATERIAL, 0, 0, "Material"); if(sbuts->pathflag & (1<<BCONTEXT_TEXTURE)) diff --git a/source/blender/editors/space_buttons/buttons_ops.c b/source/blender/editors/space_buttons/buttons_ops.c index 9b335b86163..4387da19341 100644 --- a/source/blender/editors/space_buttons/buttons_ops.c +++ b/source/blender/editors/space_buttons/buttons_ops.c @@ -738,9 +738,9 @@ void PARTICLE_OT_target_move_down(wmOperatorType *ot) static void disconnect_hair(Scene *scene, Object *ob, ParticleSystem *psys) { ParticleSystemModifierData *psmd = psys_get_modifier(ob,psys); - ParticleData *pa = psys->particles; - PTCacheEdit *edit = psys->edit; - PTCacheEditPoint *point = edit ? edit->points : NULL; + ParticleData *pa; + PTCacheEdit *edit; + PTCacheEditPoint *point; PTCacheEditKey *ekey = NULL; HairKey *key; int i, k; @@ -751,8 +751,11 @@ static void disconnect_hair(Scene *scene, Object *ob, ParticleSystem *psys) if(!psys->part || psys->part->type != PART_HAIR) return; + + edit = psys->edit; + point= edit ? edit->points : NULL; - for(i=0; i<psys->totpart; i++,pa++) { + for(i=0, pa=psys->particles; i<psys->totpart; i++,pa++) { if(point) { ekey = point->keys; point++; @@ -820,9 +823,9 @@ void PARTICLE_OT_disconnect_hair(wmOperatorType *ot) static void connect_hair(Scene *scene, Object *ob, ParticleSystem *psys) { ParticleSystemModifierData *psmd = psys_get_modifier(ob,psys); - ParticleData *pa = psys->particles; - PTCacheEdit *edit = psys->edit; - PTCacheEditPoint *point = edit ? edit->points : NULL; + ParticleData *pa; + PTCacheEdit *edit; + PTCacheEditPoint *point; PTCacheEditKey *ekey; HairKey *key; BVHTreeFromMesh bvhtree; @@ -836,7 +839,10 @@ static void connect_hair(Scene *scene, Object *ob, ParticleSystem *psys) if(!psys || !psys->part || psys->part->type != PART_HAIR) return; - + + edit= psys->edit; + point= edit ? edit->points : NULL; + if(psmd->dm->deformedOnly) dm= psmd->dm; else @@ -852,7 +858,7 @@ static void connect_hair(Scene *scene, Object *ob, ParticleSystem *psys) bvhtree_from_mesh_faces(&bvhtree, dm, 0.0, 2, 6); - for(i=0; i<psys->totpart; i++,pa++) { + for(i=0, pa= psys->particles; i<psys->totpart; i++,pa++) { key = pa->hair; nearest.index = -1; @@ -1107,7 +1113,7 @@ static int file_browse_invoke(bContext *C, wmOperator *op, wmEvent *event) op->customdata= fbo; str= RNA_property_string_get_alloc(&ptr, prop, 0, 0); - RNA_string_set(op->ptr, "filename", str); + RNA_string_set(op->ptr, "path", str); MEM_freeN(str); WM_event_add_fileselect(C, op); diff --git a/source/blender/editors/space_buttons/space_buttons.c b/source/blender/editors/space_buttons/space_buttons.c index 381beaa0295..48acaffd580 100644 --- a/source/blender/editors/space_buttons/space_buttons.c +++ b/source/blender/editors/space_buttons/space_buttons.c @@ -176,6 +176,8 @@ static void buttons_main_area_draw(const bContext *C, ARegion *ar) ED_region_panels(C, ar, vertical, "modifier", sbuts->mainb); else if (sbuts->mainb == BCONTEXT_CONSTRAINT) ED_region_panels(C, ar, vertical, "constraint", sbuts->mainb); + else if(sbuts->mainb == BCONTEXT_BONE_CONSTRAINT) + ED_region_panels(C, ar, vertical, "bone_constraint", sbuts->mainb); sbuts->re_align= 0; sbuts->mainbo= sbuts->mainb; diff --git a/source/blender/editors/space_console/console_ops.c b/source/blender/editors/space_console/console_ops.c index 2120b97becf..ccf7dbff946 100644 --- a/source/blender/editors/space_console/console_ops.c +++ b/source/blender/editors/space_console/console_ops.c @@ -51,6 +51,7 @@ #include "BKE_library.h" #include "BKE_main.h" #include "BKE_report.h" +#include "BKE_text.h" /* only for character utility funcs */ #include "WM_api.h" #include "WM_types.h" @@ -119,6 +120,48 @@ static int console_line_cursor_set(ConsoleLine *cl, int cursor) return 1; } +static char cursor_char(ConsoleLine *cl) +{ + /* assume cursor is clamped */ + return cl->line[cl->cursor]; +} + +static char cursor_char_prev(ConsoleLine *cl) +{ + /* assume cursor is clamped */ + if(cl->cursor <= 0) + return '\0'; + + return cl->line[cl->cursor-1]; +} + +static char cursor_char_next(ConsoleLine *cl) +{ + /* assume cursor is clamped */ + if(cl->cursor + 1 >= cl->len) + return '\0'; + + return cl->line[cl->cursor+1]; +} + +static void console_lb_debug__internal(ListBase *lb) +{ + ConsoleLine *cl; + + printf("%d: ", BLI_countlist(lb)); + for(cl= lb->first; cl; cl= cl->next) + printf("<%s> ", cl->line); + printf("\n"); + +} + +static void console_history_debug(const bContext *C) +{ + SpaceConsole *sc= CTX_wm_space_console(C); + + console_lb_debug__internal(&sc->history); +} + static ConsoleLine *console_lb_add__internal(ListBase *lb, ConsoleLine *from) { ConsoleLine *ci= MEM_callocN(sizeof(ConsoleLine), "ConsoleLine Add"); @@ -251,7 +294,7 @@ static EnumPropertyItem move_type_items[]= { {PREV_WORD, "PREVIOUS_WORD", 0, "Previous Word", ""}, {NEXT_WORD, "NEXT_WORD", 0, "Next Word", ""}, {0, NULL, 0, NULL, NULL}}; - + static int move_exec(bContext *C, wmOperator *op) { ConsoleLine *ci= console_history_verify(C); @@ -272,6 +315,37 @@ static int move_exec(bContext *C, wmOperator *op) case NEXT_CHAR: done= console_line_cursor_set(ci, ci->cursor+1); break; + + /* - if the character is a delimiter then skip delimiters (including white space) + * - when jump over the word */ + case PREV_WORD: + while(text_check_delim(cursor_char_prev(ci))) + if(console_line_cursor_set(ci, ci->cursor-1)==FALSE) + break; + + while(text_check_delim(cursor_char_prev(ci))==FALSE) + if(console_line_cursor_set(ci, ci->cursor-1)==FALSE) + break; + + /* This isnt used for NEXT_WORD because when going back + * its more useful to have the cursor directly after a word then whitespace */ + while(text_check_whitespace(cursor_char_prev(ci))==TRUE) + if(console_line_cursor_set(ci, ci->cursor-1)==FALSE) + break; + + done= 1; /* assume changed */ + break; + case NEXT_WORD: + while(text_check_delim(cursor_char(ci))==TRUE) + if (console_line_cursor_set(ci, ci->cursor+1)==FALSE) + break; + + while(text_check_delim(cursor_char(ci))==FALSE) + if (console_line_cursor_set(ci, ci->cursor+1)==FALSE) + break; + + done= 1; /* assume changed */ + break; } if(done) { @@ -466,7 +540,16 @@ static int history_cycle_exec(bContext *C, wmOperator *op) ConsoleLine *ci= console_history_verify(C); /* TODO - stupid, just prevernts crashes when no command line */ short reverse= RNA_boolean_get(op->ptr, "reverse"); /* assumes down, reverse is up */ - + + /* keep a copy of the line above so when history is cycled + * this is the only function that needs to know about the double-up */ + if(ci->prev) { + ConsoleLine *ci_prev= (ConsoleLine *)ci->prev; + + if(strcmp(ci->line, ci_prev->line)==0) + console_history_free(sc, ci_prev); + } + if(reverse) { /* last item in mistory */ ci= sc->history.last; BLI_remlink(&sc->history, ci); @@ -477,9 +560,17 @@ static int history_cycle_exec(bContext *C, wmOperator *op) BLI_remlink(&sc->history, ci); BLI_addtail(&sc->history, ci); } - + + { /* add a duplicate of the new arg and remove all other instances */ + ConsoleLine *cl; + while((cl= console_history_find(sc, ci->line, ci))) + console_history_free(sc, cl); + + console_history_add(C, (ConsoleLine *)sc->history.last); + } + ED_area_tag_redraw(CTX_wm_area(C)); - + return OPERATOR_FINISHED; } diff --git a/source/blender/editors/space_console/space_console.c b/source/blender/editors/space_console/space_console.c index 6526b569bbb..19fb575ed16 100644 --- a/source/blender/editors/space_console/space_console.c +++ b/source/blender/editors/space_console/space_console.c @@ -174,6 +174,9 @@ static void console_main_area_draw(const bContext *C, ARegion *ar) console_scrollback_add_str(C, "Autocomplete: Ctrl+Space", 0); console_scrollback_add_str(C, "Ctrl +/- Wheel: Zoom", 0); console_scrollback_add_str(C, "Builtin Modules: bpy, bpy.data, bpy.ops, bpy.props, bpy.types, bpy.ui", 0); + + /* This is normally set by python but to start with its easier just to set it like this rather then running python with no args */ + strcpy(sc->prompt, ">>> "); } /* clear and setup matrix */ @@ -233,13 +236,13 @@ void console_keymap(struct wmWindowManager *wm) { wmKeyMap *keymap= WM_keymap_find(wm, "Console", SPACE_CONSOLE, 0); - #ifdef __APPLE__ +#ifdef __APPLE__ RNA_enum_set(WM_keymap_add_item(keymap, "CONSOLE_OT_move", LEFTARROWKEY, KM_PRESS, KM_OSKEY, 0)->ptr, "type", LINE_BEGIN); RNA_enum_set(WM_keymap_add_item(keymap, "CONSOLE_OT_move", RIGHTARROWKEY, KM_PRESS, KM_OSKEY, 0)->ptr, "type", LINE_END); - #endif +#endif - RNA_enum_set(WM_keymap_add_item(keymap, "CONSOLE_OT_move", LEFTARROWKEY, KM_PRESS, KM_CTRL, 0)->ptr, "type", LINE_BEGIN); - RNA_enum_set(WM_keymap_add_item(keymap, "CONSOLE_OT_move", RIGHTARROWKEY, KM_PRESS, KM_CTRL, 0)->ptr, "type", LINE_END); + RNA_enum_set(WM_keymap_add_item(keymap, "CONSOLE_OT_move", LEFTARROWKEY, KM_PRESS, KM_CTRL, 0)->ptr, "type", PREV_WORD); + RNA_enum_set(WM_keymap_add_item(keymap, "CONSOLE_OT_move", RIGHTARROWKEY, KM_PRESS, KM_CTRL, 0)->ptr, "type", NEXT_WORD); RNA_enum_set(WM_keymap_add_item(keymap, "CONSOLE_OT_move", HOMEKEY, KM_PRESS, 0, 0)->ptr, "type", LINE_BEGIN); RNA_enum_set(WM_keymap_add_item(keymap, "CONSOLE_OT_move", ENDKEY, KM_PRESS, 0, 0)->ptr, "type", LINE_END); diff --git a/source/blender/editors/space_file/file_draw.c b/source/blender/editors/space_file/file_draw.c index 00024ffa961..46ed6987752 100644 --- a/source/blender/editors/space_file/file_draw.c +++ b/source/blender/editors/space_file/file_draw.c @@ -189,7 +189,7 @@ void file_draw_buttons(const bContext *C, ARegion *ar) if (available_w > 0) { but = uiDefBut(block, TEX, B_FS_DIRNAME, "", min_x, line1_y, line1_w, btn_h, - params->dir, 0.0, (float)FILE_MAXDIR-1, 0, 0, + params->dir, 0.0, (float)FILE_MAX-1, 0, 0, "File path."); uiButSetCompleteFunc(but, autocomplete_directory, NULL); uiDefBut(block, TEX, B_FS_FILENAME, "", diff --git a/source/blender/editors/space_file/file_ops.c b/source/blender/editors/space_file/file_ops.c index faca6db75bf..c717623696a 100644 --- a/source/blender/editors/space_file/file_ops.c +++ b/source/blender/editors/space_file/file_ops.c @@ -68,25 +68,15 @@ /* ---------- FILE SELECTION ------------ */ -static int find_file_mouse(SpaceFile *sfile, struct ARegion* ar, short x, short y, short clamp) +static int find_file_mouse(SpaceFile *sfile, struct ARegion* ar, short x, short y) { float fx,fy; int active_file = -1; - int numfiles = filelist_numfiles(sfile->files); View2D* v2d = &ar->v2d; UI_view2d_region_to_view(v2d, x, y, &fx, &fy); active_file = ED_fileselect_layout_offset(sfile->layout, v2d->tot.xmin + fx, v2d->tot.ymax - fy); - - if(active_file < 0) { - if(clamp) active_file= 0; - else active_file= -1; - } - else if(active_file >= numfiles) { - if(clamp) active_file= numfiles-1; - else active_file= -1; - } return active_file; } @@ -109,6 +99,31 @@ typedef enum FileSelect { FILE_SELECT_DIR = 1, FILE_SELECT_FILE = 2 } FileSelect; +static void clamp_to_filelist(int numfiles, int *first_file, int *last_file) +{ + /* border select before the first file */ + if ( (*first_file < 0) && (*last_file >=0 ) ) { + *first_file = 0; + } + /* don't select if everything is outside filelist */ + if ( (*first_file >= numfiles) && ((*last_file < 0) || (*last_file >= numfiles)) ) { + *first_file = -1; + *last_file = -1; + } + + /* fix if last file invalid */ + if ( (*first_file > 0) && (*last_file < 0) ) + *last_file = numfiles-1; + + /* clamp */ + if ( (*first_file >= numfiles) ) { + *first_file = numfiles-1; + } + if ( (*last_file >= numfiles) ) { + *last_file = numfiles-1; + } +} + static FileSelect file_select(SpaceFile* sfile, ARegion* ar, const rcti* rect, short val) { int first_file = -1; @@ -123,9 +138,11 @@ static FileSelect file_select(SpaceFile* sfile, ARegion* ar, const rcti* rect, s int numfiles = filelist_numfiles(sfile->files); params->selstate = NOTACTIVE; - first_file = find_file_mouse(sfile, ar, rect->xmin, rect->ymax, 1); - last_file = find_file_mouse(sfile, ar, rect->xmax, rect->ymin, 1); + first_file = find_file_mouse(sfile, ar, rect->xmin, rect->ymax); + last_file = find_file_mouse(sfile, ar, rect->xmax, rect->ymin); + clamp_to_filelist(numfiles, &first_file, &last_file); + /* select all valid files between first and last indicated */ if ( (first_file >= 0) && (first_file < numfiles) && (last_file >= 0) && (last_file < numfiles) ) { for (act_file = first_file; act_file <= last_file; act_file++) { @@ -137,6 +154,9 @@ static FileSelect file_select(SpaceFile* sfile, ARegion* ar, const rcti* rect, s } } + /* Don't act on multiple selected files */ + if (first_file != last_file) selecting= 0; + /* make the last file active */ if (selecting && (last_file >= 0 && last_file < numfiles)) { struct direntry* file = filelist_file(sfile->files, last_file); @@ -168,7 +188,7 @@ static FileSelect file_select(SpaceFile* sfile, ARegion* ar, const rcti* rect, s } } - } + } return retval; } @@ -449,7 +469,7 @@ int file_hilight_set(SpaceFile *sfile, ARegion *ar, int mx, int my) my -= ar->winrct.ymin; if(BLI_in_rcti(&ar->v2d.mask, mx, my)) { - actfile = find_file_mouse(sfile, ar, mx , my, 0); + actfile = find_file_mouse(sfile, ar, mx , my); if((actfile >= 0) && (actfile < numfiles)) params->active_file=actfile; @@ -497,6 +517,7 @@ int file_cancel_exec(bContext *C, wmOperator *unused) sfile->op = NULL; if (sfile->files) { + filelist_freelib(sfile->files); filelist_free(sfile->files); MEM_freeN(sfile->files); sfile->files= NULL; @@ -505,6 +526,16 @@ int file_cancel_exec(bContext *C, wmOperator *unused) return OPERATOR_FINISHED; } +int file_operator_poll(bContext *C) +{ + int poll = ED_operator_file_active(C); + SpaceFile *sfile= CTX_wm_space_file(C); + + if (!sfile || !sfile->op) poll= 0; + + return poll; +} + void FILE_OT_cancel(struct wmOperatorType *ot) { /* identifiers */ @@ -513,7 +544,7 @@ void FILE_OT_cancel(struct wmOperatorType *ot) /* api callbacks */ ot->exec= file_cancel_exec; - ot->poll= ED_operator_file_active; + ot->poll= file_operator_poll; } /* sends events now, so things get handled on windowqueue level */ @@ -575,6 +606,7 @@ int file_exec(bContext *C, wmOperator *unused) fsmenu_write_file(fsmenu_get(), name); WM_event_fileselect_event(C, op, EVT_FILESELECT_EXEC); + filelist_freelib(sfile->files); filelist_free(sfile->files); MEM_freeN(sfile->files); sfile->files= NULL; @@ -591,7 +623,7 @@ void FILE_OT_execute(struct wmOperatorType *ot) /* api callbacks */ ot->exec= file_exec; - ot->poll= ED_operator_file_active; /* <- important, handler is on window level */ + ot->poll= file_operator_poll; } diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c index 582a5997ef5..8257aa5482f 100644 --- a/source/blender/editors/space_file/filelist.c +++ b/source/blender/editors/space_file/filelist.c @@ -804,6 +804,8 @@ static void filelist_read_library(struct FileList* filelist) if(!filelist->libfiledata) { int num; struct direntry *file; + + BLI_make_exist(filelist->dir); filelist_read_dir(filelist); file = filelist->filelist; for(num=0; num<filelist->numfiles; num++, file++) { diff --git a/source/blender/editors/space_file/filesel.c b/source/blender/editors/space_file/filesel.c index a0787ef989d..dd16a426899 100644 --- a/source/blender/editors/space_file/filesel.c +++ b/source/blender/editors/space_file/filesel.c @@ -117,8 +117,6 @@ short ED_fileselect_set_params(SpaceFile *sfile) BLI_strncpy(sfile->params->file, file, sizeof(sfile->params->file)); BLI_make_file_string(G.sce, sfile->params->dir, dir, ""); /* XXX needed ? - also solve G.sce */ } - - ED_fileselect_reset_params(sfile); params = sfile->params; @@ -419,13 +417,16 @@ void autocomplete_directory(struct bContext *C, char *str, void *arg_v) struct direntry* file = filelist_file(sfile->files, i); const char* dir = filelist_dir(sfile->files); if (file && S_ISDIR(file->type)) { - BLI_make_file_string(G.sce, tmp, dir, file->relname); + // BLI_make_file_string(G.sce, tmp, dir, file->relname); + BLI_join_dirfile(tmp, dir, file->relname); autocomplete_do_name(autocpl,tmp); } } autocomplete_end(autocpl, str); if (BLI_exists(str)) { BLI_add_slash(str); + } else { + BLI_make_exist(str); } } } diff --git a/source/blender/editors/space_file/space_file.c b/source/blender/editors/space_file/space_file.c index 99d649b28cc..ca2c145c52b 100644 --- a/source/blender/editors/space_file/space_file.c +++ b/source/blender/editors/space_file/space_file.c @@ -155,17 +155,7 @@ static void file_free(SpaceLink *sl) /* spacetype; init callback, area size changes, screen set, etc */ static void file_init(struct wmWindowManager *wm, ScrArea *sa) { - SpaceFile *sfile= (SpaceFile*)sa->spacedata.first; - if(sfile->params) { - MEM_freeN(sfile->params); - sfile->params = 0; - ED_fileselect_set_params(sfile); - if (sfile->files) { - filelist_free(sfile->files); - MEM_freeN(sfile->files); - sfile->files= NULL; - } - } + //SpaceFile *sfile= (SpaceFile*)sa->spacedata.first; printf("file_init\n"); } @@ -213,6 +203,7 @@ static void file_refresh(const bContext *C, ScrArea *sa) if (filelist_empty(sfile->files)) { filelist_readdir(sfile->files); + BLI_strncpy(params->dir, filelist_dir(sfile->files), FILE_MAX); } if(params->sort!=FILE_SORT_NONE) filelist_sort(sfile->files, params->sort); diff --git a/source/blender/editors/space_graph/graph_draw.c b/source/blender/editors/space_graph/graph_draw.c index 9ae7e8263ee..57e2208f089 100644 --- a/source/blender/editors/space_graph/graph_draw.c +++ b/source/blender/editors/space_graph/graph_draw.c @@ -91,6 +91,26 @@ extern void gl_round_box(int mode, float minx, float miny, float maxx, float maxy, float rad); /* *************************** */ +/* Utility Drawing Defines */ + +/* determine the alpha value that should be used when + * drawing components for some F-Curve (fcu) + * - selected F-Curves should be more visible than partially visible ones + */ +#define drawFCurveFade(fcu) ( ((fcu)->flag & FCURVE_SELECTED)? 1.0f : 0.5f ) + +/* set the colour for some point from some value given packed into an int + * - intV: integer value containing color info packed into an int + * - alpha: float value describing the + */ +#define cpackA(intVC, alpha) \ + { \ + float _cpackCol[3]; \ + cpack_to_rgb(intVC, &_cpackCol[0], &_cpackCol[1], &_cpackCol[2]); \ + glColor4f(_cpackCol[0], _cpackCol[1], _cpackCol[2], alpha); \ + } + +/* *************************** */ /* F-Curve Modifier Drawing */ /* Envelope -------------- */ @@ -258,22 +278,20 @@ static void draw_fcurve_vertices_handles (FCurve *fcu, View2D *v2d, short sel) /* helper func - set color to draw F-Curve data with */ static void set_fcurve_vertex_color (SpaceIpo *sipo, FCurve *fcu, short sel) { -#if 0 - if (sipo->showkey) { - if (sel) UI_ThemeColor(TH_TEXT_HI); - else UI_ThemeColor(TH_TEXT); - } -#endif - if ((fcu->flag & FCURVE_PROTECTED)==0) { - /* Curve's points are being edited */ - if (sel) UI_ThemeColor(TH_VERTEX_SELECT); - else UI_ThemeColor(TH_VERTEX); - } - else { - /* Curve's points cannot be edited */ - if (sel) UI_ThemeColor(TH_TEXT_HI); - else UI_ThemeColor(TH_TEXT); - } + /* Fade the 'intensity' of the vertices based on the selection of the curves too */ + int alphaOffset= (int)((drawFCurveFade(fcu) - 1.0f) * 255); + + /* Set color of curve vertex based on state of curve (i.e. 'Edit' Mode) */ + if ((fcu->flag & FCURVE_PROTECTED)==0) { + /* Curve's points ARE BEING edited */ + if (sel) UI_ThemeColorShadeAlpha(TH_VERTEX_SELECT, 0, alphaOffset); + else UI_ThemeColorShadeAlpha(TH_VERTEX, 0, alphaOffset); + } + else { + /* Curve's points CANNOT BE edited */ + if (sel) UI_ThemeColorShadeAlpha(TH_TEXT_HI, 0, alphaOffset); + else UI_ThemeColorShadeAlpha(TH_TEXT, 0, alphaOffset); + } } @@ -322,7 +340,7 @@ static void draw_fcurve_handles (SpaceIpo *sipo, ARegion *ar, FCurve *fcu) if ((sipo->flag & SIPO_NOHANDLES) || (fcu->flag & FCURVE_PROTECTED) || (fcu->flag & FCURVE_INT_VALUES)) return; - /* slightly hacky, but we want to draw unselected points before selected ones*/ + /* slightly hacky, but we want to draw unselected points before selected ones */ for (sel= 0; sel < 2; sel++) { BezTriple *bezt=fcu->bezt, *prevbezt=NULL; float *fp; @@ -337,7 +355,7 @@ static void draw_fcurve_handles (SpaceIpo *sipo, ARegion *ar, FCurve *fcu) /* only draw first handle if previous segment had handles */ if ( (!prevbezt && (bezt->ipo==BEZT_IPO_BEZ)) || (prevbezt && (prevbezt->ipo==BEZT_IPO_BEZ)) ) { - cpack(col[(unsigned char)bezt->h1]); + cpackA(col[(unsigned char)bezt->h1], drawFCurveFade(fcu)); glBegin(GL_LINE_STRIP); glVertex2fv(fp); glVertex2fv(fp+3); glEnd(); @@ -347,7 +365,7 @@ static void draw_fcurve_handles (SpaceIpo *sipo, ARegion *ar, FCurve *fcu) /* only draw second handle if this segment is bezier */ if (bezt->ipo == BEZT_IPO_BEZ) { - cpack(col[(unsigned char)bezt->h2]); + cpackA(col[(unsigned char)bezt->h2], drawFCurveFade(fcu)); glBegin(GL_LINE_STRIP); glVertex2fv(fp+3); glVertex2fv(fp+6); glEnd(); @@ -359,7 +377,7 @@ static void draw_fcurve_handles (SpaceIpo *sipo, ARegion *ar, FCurve *fcu) ( (!prevbezt && (bezt->ipo==BEZT_IPO_BEZ)) || (prevbezt && (prevbezt->ipo==BEZT_IPO_BEZ)) ) ) { fp= bezt->vec[0]; - cpack(col[(unsigned char)bezt->h1]); + cpackA(col[(unsigned char)bezt->h1], drawFCurveFade(fcu)); glBegin(GL_LINE_STRIP); glVertex2fv(fp); glVertex2fv(fp+3); @@ -371,7 +389,7 @@ static void draw_fcurve_handles (SpaceIpo *sipo, ARegion *ar, FCurve *fcu) (bezt->ipo == BEZT_IPO_BEZ) ) { fp= bezt->vec[1]; - cpack(col[(unsigned char)bezt->h2]); + cpackA(col[(unsigned char)bezt->h2], drawFCurveFade(fcu)); glBegin(GL_LINE_STRIP); glVertex2fv(fp); glVertex2fv(fp+3); @@ -410,7 +428,6 @@ static void draw_fcurve_sample_control (float x, float y, float xscale, float ys glScalef(1.0f/xscale*hsize, 1.0f/yscale*hsize, 1.0f); /* anti-aliased lines for more consistent appearance */ - // XXX needed here? glEnable(GL_LINE_SMOOTH); glEnable(GL_BLEND); @@ -506,7 +523,6 @@ static void draw_fcurve_curve (FCurve *fcu, SpaceIpo *sipo, View2D *v2d, View2DG } /* helper func - draw a samples-based F-Curve */ -// TODO: add offset stuff... static void draw_fcurve_curve_samples (FCurve *fcu, View2D *v2d) { FPoint *prevfpt= fcu->fpt; @@ -647,7 +663,7 @@ static void draw_fcurve_curve_bezts (FCurve *fcu, View2D *v2d, View2DGrid *grid) */ /* resol not depending on horizontal resolution anymore, drivers for example... */ - // XXX need to take into account the scale + // TODO: would be nice to make this depend on the scale of the graph too... if (fcu->driver) resol= 32; else @@ -809,7 +825,7 @@ void graph_draw_curves (bAnimContext *ac, SpaceIpo *sipo, ARegion *ar, View2DGri /* set whatever color the curve has set * - unselected curves draw less opaque to help distinguish the selected ones */ - glColor4f(fcu->color[0], fcu->color[1], fcu->color[2], ((sel) ? 1.0f : 0.5f)); + glColor4f(fcu->color[0], fcu->color[1], fcu->color[2], drawFCurveFade(fcu)); } /* anti-aliased lines for less jagged appearance */ @@ -855,7 +871,10 @@ void graph_draw_curves (bAnimContext *ac, SpaceIpo *sipo, ARegion *ar, View2DGri else if ( ((fcu->bezt) || (fcu->fpt)) && (fcu->totvert) ) { if (fcu->bezt) { /* only draw handles/vertices on keyframes */ - draw_fcurve_handles(sipo, ar, fcu); + glEnable(GL_BLEND); + draw_fcurve_handles(sipo, ar, fcu); + glDisable(GL_BLEND); + draw_fcurve_vertices(sipo, ar, fcu); } else { diff --git a/source/blender/editors/space_graph/graph_edit.c b/source/blender/editors/space_graph/graph_edit.c index d718ef28e99..8c739d68cea 100644 --- a/source/blender/editors/space_graph/graph_edit.c +++ b/source/blender/editors/space_graph/graph_edit.c @@ -1296,8 +1296,7 @@ void GRAPH_OT_handle_type (wmOperatorType *ot) /* set of three euler-rotation F-Curves */ typedef struct tEulerFilter { ID *id; /* ID-block which owns the channels */ - FCurve *fcu1, *fcu2, *fcu3; /* x,y,z rotation curves */ - int i1, i2, i3; /* current index for each curve */ + FCurve (*fcurves)[3]; /* 3 Pointers to F-Curves */ } tEulerFilter; static int graphkeys_euler_filter_exec (bContext *C, wmOperator *op) @@ -1345,12 +1344,30 @@ static int graphkeys_euler_filter_exec (bContext *C, wmOperator *op) * - first check if id-blocks are compatible */ if ((euf) && (ale->id != euf->id)) { + /* if the paths match, add this curve to the set of curves */ + // NOTE: simple string compare for now... could be a bit more fancy... } + else { + /* just add to a new block */ + euf= MEM_callocN(sizeof(tEulerFilter), "tEulerFilter"); + BLI_addtail(&eulers, euf); + + euf->id= ale->id; + euf->fcurves[fcu->array_index]= fcu; + } } + BLI_freelistN(&anim_data); - // XXX for now - return OPERATOR_CANCELLED; + /* step 2: go through each set of curves, processing the values at each keyframe + * - it is assumed that there must be a full set of keyframes at each keyframe position + */ + for (euf= eulers.first; euf; euf= euf->next) { + + } + BLI_freelistN(&eulers); + + return OPERATOR_FINISHED; } void GRAPH_OT_euler_filter (wmOperatorType *ot) @@ -1710,13 +1727,18 @@ static int graph_fmodifier_add_invoke (bContext *C, wmOperator *op, wmEvent *eve /* start from 1 to skip the 'Invalid' modifier type */ for (i = 1; i < FMODIFIER_NUM_TYPES; i++) { FModifierTypeInfo *fmi= get_fmodifier_typeinfo(i); + PointerRNA props_ptr; /* check if modifier is valid for this context */ if (fmi == NULL) continue; - /* add entry to add this type of modifier */ - uiItemEnumO(layout, fmi->name, 0, "GRAPH_OT_fmodifier_add", "type", i); + /* create operator menu item with relevant properties filled in */ + props_ptr= uiItemFullO(layout, fmi->name, 0, "GRAPH_OT_fmodifier_add", NULL, WM_OP_EXEC_REGION_WIN, UI_ITEM_O_RETURN_PROPS); + /* the only thing that gets set from the menu is the type of F-Modifier to add */ + RNA_enum_set(&props_ptr, "type", i); + /* the following properties are just repeats of existing ones... */ + RNA_boolean_set(&props_ptr, "only_active", RNA_boolean_get(op->ptr, "only_active")); } uiItemS(layout); @@ -1728,36 +1750,41 @@ static int graph_fmodifier_add_invoke (bContext *C, wmOperator *op, wmEvent *eve static int graph_fmodifier_add_exec(bContext *C, wmOperator *op) { bAnimContext ac; + ListBase anim_data = {NULL, NULL}; bAnimListElem *ale; - FCurve *fcu; - FModifier *fcm; + int filter; short type; /* get editor data */ if (ANIM_animdata_get_context(C, &ac) == 0) return OPERATOR_CANCELLED; - - // xxx call the raw methods here instead? - ale= get_active_fcurve_channel(&ac); - if (ale == NULL) - return OPERATOR_CANCELLED; - fcu= (FCurve *)ale->data; - MEM_freeN(ale); - if (fcu == NULL) - return OPERATOR_CANCELLED; - /* get type of modifier to add */ type= RNA_enum_get(op->ptr, "type"); - /* add F-Modifier of specified type to active F-Curve, and make it the active one */ - fcm= add_fmodifier(&fcu->modifiers, type); - if (fcm) - set_active_fmodifier(&fcu->modifiers, fcm); - else { - BKE_report(op->reports, RPT_ERROR, "Modifier couldn't be added. See console for details."); - return OPERATOR_CANCELLED; + /* filter data */ + filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVEVISIBLE| ANIMFILTER_FOREDIT | ANIMFILTER_CURVESONLY); + if (RNA_boolean_get(op->ptr, "only_active")) + filter |= ANIMFILTER_ACTIVE; + else + filter |= ANIMFILTER_SEL; + ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype); + + /* smooth keyframes */ + for (ale= anim_data.first; ale; ale= ale->next) { + FCurve *fcu= (FCurve *)ale->data; + FModifier *fcm; + + /* add F-Modifier of specified type to active F-Curve, and make it the active one */ + fcm= add_fmodifier(&fcu->modifiers, type); + if (fcm) + set_active_fmodifier(&fcu->modifiers, fcm); + else { // TODO: stop when this happens? + BKE_report(op->reports, RPT_ERROR, "Modifier couldn't be added. See console for details."); + break; + } } + BLI_freelistN(&anim_data); /* validate keyframes after editing */ ANIM_editkeyframes_refresh(&ac); @@ -1779,13 +1806,14 @@ void GRAPH_OT_fmodifier_add (wmOperatorType *ot) /* api callbacks */ ot->invoke= graph_fmodifier_add_invoke; ot->exec= graph_fmodifier_add_exec; - ot->poll= graphop_active_fcurve_poll; + ot->poll= graphop_selected_fcurve_poll; /* flags */ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; /* id-props */ RNA_def_enum(ot->srna, "type", fmodifier_type_items, 0, "Type", ""); + RNA_def_boolean(ot->srna, "only_active", 1, "Only Active", "Only add F-Modifier to active F-Curve."); } /* ************************************************************************** */ diff --git a/source/blender/editors/space_graph/graph_header.c b/source/blender/editors/space_graph/graph_header.c index dd304cd8cf3..98d58c92da4 100644 --- a/source/blender/editors/space_graph/graph_header.c +++ b/source/blender/editors/space_graph/graph_header.c @@ -298,29 +298,7 @@ void graph_header_buttons(const bContext *C, ARegion *ar) xco+= 120; /* filtering buttons */ - if (sipo->ads) { - //uiBlockBeginAlign(block); - uiDefIconButBitI(block, TOG, ADS_FILTER_ONLYSEL, B_REDR, ICON_RESTRICT_SELECT_OFF, (short)(xco+=XIC),yco,XIC,YIC, &(sipo->ads->filterflag), 0, 0, 0, 0, "Only display selected Objects"); - //uiBlockEndAlign(block); - xco += 5; - - uiBlockBeginAlign(block); - uiDefIconButBitI(block, TOGN, ADS_FILTER_NOSCE, B_REDR, ICON_SCENE_DATA, (short)(xco+=XIC),yco,XIC,YIC, &(sipo->ads->filterflag), 0, 0, 0, 0, "Display Scene Animation"); - uiDefIconButBitI(block, TOGN, ADS_FILTER_NOWOR, B_REDR, ICON_WORLD_DATA, (short)(xco+=XIC),yco,XIC,YIC, &(sipo->ads->filterflag), 0, 0, 0, 0, "Display World Animation"); - uiDefIconButBitI(block, TOGN, ADS_FILTER_NOSHAPEKEYS, B_REDR, ICON_SHAPEKEY_DATA, (short)(xco+=XIC),yco,XIC,YIC, &(sipo->ads->filterflag), 0, 0, 0, 0, "Display ShapeKeys"); - uiDefIconButBitI(block, TOGN, ADS_FILTER_NOMAT, B_REDR, ICON_MATERIAL_DATA, (short)(xco+=XIC),yco,XIC,YIC, &(sipo->ads->filterflag), 0, 0, 0, 0, "Display Materials"); - uiDefIconButBitI(block, TOGN, ADS_FILTER_NOLAM, B_REDR, ICON_LAMP_DATA, (short)(xco+=XIC),yco,XIC,YIC, &(sipo->ads->filterflag), 0, 0, 0, 0, "Display Lamps"); - uiDefIconButBitI(block, TOGN, ADS_FILTER_NOCAM, B_REDR, ICON_CAMERA_DATA, (short)(xco+=XIC),yco,XIC,YIC, &(sipo->ads->filterflag), 0, 0, 0, 0, "Display Cameras"); - uiDefIconButBitI(block, TOGN, ADS_FILTER_NOCUR, B_REDR, ICON_CURVE_DATA, (short)(xco+=XIC),yco,XIC,YIC, &(sipo->ads->filterflag), 0, 0, 0, 0, "Display Curves"); - uiDefIconButBitI(block, TOGN, ADS_FILTER_NOMBA, B_REDR, ICON_META_DATA, (short)(xco+=XIC),yco,XIC,YIC, &(sipo->ads->filterflag), 0, 0, 0, 0, "Display MetaBalls"); - uiDefIconButBitI(block, TOGN, ADS_FILTER_NOPART, B_REDR, ICON_PARTICLE_DATA, (short)(xco+=XIC),yco,XIC,YIC, &(sipo->ads->filterflag), 0, 0, 0, 0, "Display Particles"); - uiBlockEndAlign(block); - xco += 30; - } - else { - // XXX this case shouldn't happen at all... for now, just pad out same amount of space - xco += 10*XIC + 30; - } + xco= ANIM_headerUI_standard_buttons(C, sipo->ads, block, xco, yco); /* auto-snap selector */ if (sipo->flag & SIPO_DRAWTIME) { diff --git a/source/blender/editors/space_graph/graph_intern.h b/source/blender/editors/space_graph/graph_intern.h index 2e8d0655d2d..83a565e485f 100644 --- a/source/blender/editors/space_graph/graph_intern.h +++ b/source/blender/editors/space_graph/graph_intern.h @@ -155,6 +155,7 @@ short fcurve_needs_draw_fmodifier_controls(struct FCurve *fcu, struct FModifier int graphop_visible_keyframes_poll(struct bContext *C); int graphop_editable_keyframes_poll(struct bContext *C); int graphop_active_fcurve_poll(struct bContext *C); +int graphop_selected_fcurve_poll(struct bContext *C); /* ***************************************** */ /* graph_ops.c */ diff --git a/source/blender/editors/space_graph/graph_ops.c b/source/blender/editors/space_graph/graph_ops.c index b7d67c85ab9..b82055064f8 100644 --- a/source/blender/editors/space_graph/graph_ops.c +++ b/source/blender/editors/space_graph/graph_ops.c @@ -221,7 +221,7 @@ static void graphedit_keymap_keyframes (wmWindowManager *wm, wmKeyMap *keymap) WM_keymap_add_item(keymap, "GRAPH_OT_view_all", HOMEKEY, KM_PRESS, 0, 0); /* F-Modifiers */ - WM_keymap_add_item(keymap, "GRAPH_OT_fmodifier_add", MKEY, KM_PRESS, KM_CTRL|KM_SHIFT, 0); + RNA_boolean_set(WM_keymap_add_item(keymap, "GRAPH_OT_fmodifier_add", MKEY, KM_PRESS, KM_CTRL|KM_SHIFT, 0)->ptr, "only_active", 0); /* transform system */ diff --git a/source/blender/editors/space_graph/graph_select.c b/source/blender/editors/space_graph/graph_select.c index 728c9310a47..7eec9f31d86 100644 --- a/source/blender/editors/space_graph/graph_select.c +++ b/source/blender/editors/space_graph/graph_select.c @@ -142,9 +142,13 @@ static void deselect_graph_keys (bAnimContext *ac, short test, short sel) /* Keyframes First */ ANIM_fcurve_keys_bezier_loop(&bed, ale->key_data, NULL, sel_cb, NULL); - /* deactivate the F-Curve, and deselect if deselecting keyframes */ + /* deactivate the F-Curve, and deselect if deselecting keyframes. + * otherwise select the F-Curve too since we've selected all the keyframes + */ if (sel == SELECT_SUBTRACT) fcu->flag &= ~FCURVE_SELECTED; + else + fcu->flag |= FCURVE_SELECTED; fcu->flag &= ~FCURVE_ACTIVE; } @@ -259,8 +263,9 @@ static void borderselect_graphkeys (bAnimContext *ac, rcti rect, short mode, sho /* select the curve too * NOTE: this should really only happen if the curve got touched... */ - if (selectmode == SELECT_ADD) + if (selectmode == SELECT_ADD) { fcu->flag |= FCURVE_SELECTED; + } } /* cleanup */ diff --git a/source/blender/editors/space_graph/graph_utils.c b/source/blender/editors/space_graph/graph_utils.c index f00e7845549..25087441b6a 100644 --- a/source/blender/editors/space_graph/graph_utils.c +++ b/source/blender/editors/space_graph/graph_utils.c @@ -285,4 +285,33 @@ int graphop_active_fcurve_poll (bContext *C) return has_fcurve; } +/* has selected F-Curve that's editable */ +int graphop_selected_fcurve_poll (bContext *C) +{ + bAnimContext ac; + ListBase anim_data = {NULL, NULL}; + ScrArea *sa= CTX_wm_area(C); + int filter, items; + short found = 0; + + /* firstly, check if in Graph Editor */ + // TODO: also check for region? + if ((sa == NULL) || (sa->spacetype != SPACE_IPO)) + return 0; + + /* try to init Anim-Context stuff ourselves and check */ + if (ANIM_animdata_get_context(C, &ac) == 0) + return 0; + + /* get the editable + selected F-Curves, and as long as we got some, we can return */ + filter= (ANIMFILTER_VISIBLE | ANIMFILTER_SEL | ANIMFILTER_FOREDIT | ANIMFILTER_CURVESONLY); + items = ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype); + if (items == 0) + return 0; + + /* cleanup and return findings */ + BLI_freelistN(&anim_data); + return found; +} + /* ************************************************************** */ diff --git a/source/blender/editors/space_graph/space_graph.c b/source/blender/editors/space_graph/space_graph.c index e0b961b38f1..a7ea2294ed4 100644 --- a/source/blender/editors/space_graph/space_graph.c +++ b/source/blender/editors/space_graph/space_graph.c @@ -374,6 +374,7 @@ static void graph_region_listener(ARegion *ar, wmNotifier *wmn) break; case NC_SCENE: switch(wmn->data) { + case ND_RENDER_OPTIONS: case ND_OB_ACTIVE: case ND_FRAME: case ND_MARKERS: diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c index 483d2fc6043..317a058d20e 100644 --- a/source/blender/editors/space_image/image_ops.c +++ b/source/blender/editors/space_image/image_ops.c @@ -224,7 +224,7 @@ static int view_pan_modal(bContext *C, wmOperator *op, wmEvent *event) view_pan_exec(C, op); break; case MIDDLEMOUSE: - if(event->val==0) { + if(event->val==KM_RELEASE) { view_pan_exit(C, op, 0); return OPERATOR_FINISHED; } @@ -339,7 +339,7 @@ static int view_zoom_modal(bContext *C, wmOperator *op, wmEvent *event) ED_area_tag_redraw(CTX_wm_area(C)); break; case MIDDLEMOUSE: - if(event->val==0) { + if(event->val==KM_RELEASE) { view_zoom_exit(C, op, 0); return OPERATOR_FINISHED; } diff --git a/source/blender/editors/space_image/space_image.c b/source/blender/editors/space_image/space_image.c index f222499ba86..f041cb00ee4 100644 --- a/source/blender/editors/space_image/space_image.c +++ b/source/blender/editors/space_image/space_image.c @@ -623,7 +623,7 @@ ImBuf *ED_space_image_buffer(SpaceImage *sima) { ImBuf *ibuf; - if(sima->image) { + if(sima && sima->image) { #if 0 if(sima->image->type==IMA_TYPE_R_RESULT && BIF_show_render_spare()) return BIF_render_spare_imbuf(); diff --git a/source/blender/editors/space_logic/logic_window.c b/source/blender/editors/space_logic/logic_window.c index cd02f2c6304..dc8b111821d 100644 --- a/source/blender/editors/space_logic/logic_window.c +++ b/source/blender/editors/space_logic/logic_window.c @@ -39,6 +39,9 @@ #include "DNA_screen_types.h" #include "DNA_sensor_types.h" #include "DNA_sound_types.h" +#include "DNA_armature_types.h" +#include "DNA_constraint_types.h" +#include "DNA_action_types.h" #include "DNA_windowmanager_types.h" #include "MEM_guardedalloc.h" @@ -608,6 +611,8 @@ static char *sensor_name(int type) return "Keyboard"; case SENS_PROPERTY: return "Property"; + case SENS_ARMATURE: + return "Armature"; case SENS_ACTUATOR: return "Actuator"; case SENS_DELAY: @@ -635,7 +640,7 @@ static char *sensor_pup(void) /* the number needs to match defines in game.h */ return "Sensors %t|Always %x0|Delay %x13|Keyboard %x3|Mouse %x5|" "Touch %x1|Collision %x6|Near %x2|Radar %x7|" - "Property %x4|Random %x8|Ray %x9|Message %x10|Joystick %x11|Actuator %x12"; + "Property %x4|Random %x8|Ray %x9|Message %x10|Joystick %x11|Actuator %x12|Armature %x14"; } static char *controller_name(int type) @@ -709,6 +714,8 @@ static char *actuator_name(int type) return "Parent"; case ACT_STATE: return "State"; + case ACT_ARMATURE: + return "Armature"; } return "unknown"; } @@ -721,7 +728,7 @@ static char *actuator_pup(Object *owner) switch (owner->type) { case OB_ARMATURE: - return "Actuators %t|Action %x15|Motion %x0|Constraint %x9|Ipo %x1" + return "Actuators %t|Action %x15|Armature %x23|Motion %x0|Constraint %x9|Ipo %x1" "|Camera %x3|Sound %x5|Property %x6|Edit Object %x10" "|Scene %x11|Random %x13|Message %x14|Game %x17" "|Visibility %x18|2D Filter %x19|Parent %x20|State %x22"; @@ -936,6 +943,7 @@ static int get_col_sensor(int type) case SENS_NEAR: return TH_PANEL; case SENS_KEYBOARD: return TH_PANEL; case SENS_PROPERTY: return TH_PANEL; + case SENS_ARMATURE: return TH_PANEL; case SENS_ACTUATOR: return TH_PANEL; case SENS_MOUSE: return TH_PANEL; case SENS_RADAR: return TH_PANEL; @@ -1067,6 +1075,19 @@ static void test_scenepoin_but(struct bContext *C, char *name, ID **idpp) *idpp= NULL; } + +static void test_keyboard_event(struct bContext *C, void *arg_ks, void *arg_unused) +{ + bKeyboardSensor *ks= (bKeyboardSensor*)arg_ks; + + if(!ISKEYBOARD(ks->key)) + ks->key= 0; + if(!ISKEYBOARD(ks->qual)) + ks->qual= 0; + if(!ISKEYBOARD(ks->qual2)) + ks->qual2= 0; +} + /** * Draws a toggle for pulse mode, a frequency field and a toggle to invert * the value of this sensor. Operates on the shared data block of sensors. @@ -1116,12 +1137,51 @@ static void draw_default_sensor_header(bSensor *sens, "Invert the level (output) of this sensor"); } -static short draw_sensorbuttons(bSensor *sens, uiBlock *block, short xco, short yco, short width,char* objectname) +static void check_armature_bone_constraint(Object *ob, char *posechannel, char *constraint) +{ + /* check that bone exist in the active object */ + if (ob->type == OB_ARMATURE && ob->pose) { + bPoseChannel *pchan; + bPose *pose = ob->pose; + for (pchan=pose->chanbase.first; pchan; pchan=pchan->next) { + if (!strcmp(pchan->name, posechannel)) { + /* found it, now look for constraint channel */ + bConstraint *con; + for (con=pchan->constraints.first; con; con=con->next) { + if (!strcmp(con->name, constraint)) { + /* found it, all ok */ + return; + } + } + /* didn't find constraint, make empty */ + constraint[0] = 0; + return; + } + } + } + /* didn't find any */ + posechannel[0] = 0; + constraint[0] = 0; +} + +static void check_armature_sensor(bContext *C, void *arg1_but, void *arg2_sens) +{ + bArmatureSensor *sens = arg2_sens; + uiBut *but = arg1_but; + Object *ob= CTX_data_active_object(C); + + /* check that bone exist in the active object */ + but->retval = B_REDR; + check_armature_bone_constraint(ob, sens->posechannel, sens->constraint); +} + +static short draw_sensorbuttons(Object *ob, bSensor *sens, uiBlock *block, short xco, short yco, short width,char* objectname) { bNearSensor *ns = NULL; bTouchSensor *ts = NULL; bKeyboardSensor *ks = NULL; bPropertySensor *ps = NULL; + bArmatureSensor *arm = NULL; bMouseSensor *ms = NULL; bCollisionSensor *cs = NULL; bRadarSensor *rs = NULL; @@ -1131,6 +1191,7 @@ static short draw_sensorbuttons(bSensor *sens, uiBlock *block, short xco, short bJoystickSensor *joy = NULL; bActuatorSensor *as = NULL; bDelaySensor *ds = NULL; + uiBut *but; short ysize; char *str; @@ -1279,12 +1340,15 @@ static short draw_sensorbuttons(bSensor *sens, uiBlock *block, short xco, short if ((ks->type&1)==0) { /* is All Keys option off? */ /* line 2: hotkey and allkeys toggle */ - uiDefKeyevtButS(block, 0, "", xco+40, yco-44, (width)/2, 19, &ks->key, "Key code"); + but= uiDefKeyevtButS(block, 0, "", xco+40, yco-44, (width)/2, 19, &ks->key, "Key code"); + uiButSetFunc(but, test_keyboard_event, ks, NULL); /* line 3: two key modifyers (qual1, qual2) */ uiDefBut(block, LABEL, 0, "Hold", xco, yco-68, 40, 19, NULL, 0, 0, 0, 0, ""); - uiDefKeyevtButS(block, 0, "", xco+40, yco-68, (width-50)/2, 19, &ks->qual, "Modifier key code"); - uiDefKeyevtButS(block, 0, "", xco+40+(width-50)/2, yco-68, (width-50)/2, 19, &ks->qual2, "Second Modifier key code"); + but= uiDefKeyevtButS(block, 0, "", xco+40, yco-68, (width-50)/2, 19, &ks->qual, "Modifier key code"); + uiButSetFunc(but, test_keyboard_event, ks, NULL); + but= uiDefKeyevtButS(block, 0, "", xco+40+(width-50)/2, yco-68, (width-50)/2, 19, &ks->qual2, "Second Modifier key code"); + uiButSetFunc(but, test_keyboard_event, ks, NULL); } /* line 4: toggle property for string logging mode */ @@ -1343,6 +1407,45 @@ static short draw_sensorbuttons(bSensor *sens, uiBlock *block, short xco, short yco-= ysize; break; } + case SENS_ARMATURE: + { + ysize= 70; + + glRects(xco, yco-ysize, xco+width, yco); + uiEmboss((float)xco, (float)yco-ysize, + (float)xco+width, (float)yco, 1); + + draw_default_sensor_header(sens, block, xco, yco, width); + arm= sens->data; + + if (ob->type == OB_ARMATURE) { + uiBlockBeginAlign(block); + but = uiDefBut(block, TEX, 1, "Bone: ", + (xco+10), (yco-44), (width-20)/2, 19, + arm->posechannel, 0, 31, 0, 0, + "Bone on which you want to check a constraint"); + uiButSetFunc(but, check_armature_sensor, but, arm); + but = uiDefBut(block, TEX, 1, "Cons: ", + (xco+10)+(width-20)/2, (yco-44), (width-20)/2, 19, + arm->constraint, 0, 31, 0, 0, + "Name of the constraint you want to control"); + uiButSetFunc(but, check_armature_sensor, but, arm); + uiBlockEndAlign(block); + + str= "Type %t|State changed %x0|Lin error below %x1|Lin error above %x2|Rot error below %x3|Rot error above %x4"; + + uiDefButI(block, MENU, B_REDR, str, xco+10,yco-66,0.4*(width-20), 19, + &arm->type, 0, 31, 0, 0, "Type"); + + if (arm->type != SENS_ARM_STATE_CHANGED) + { + uiDefButF(block, NUM, 1, "Value: ", xco+10+0.4*(width-20),yco-66,0.6*(width-20), 19, + &arm->value, -10000.0, 10000.0, 100, 0, "Test the error against this value"); + } + } + yco-= ysize; + break; + } case SENS_ACTUATOR: { ysize= 48; @@ -1677,6 +1780,7 @@ static int get_col_actuator(int type) case ACT_VISIBILITY: return TH_PANEL; case ACT_CONSTRAINT: return TH_PANEL; case ACT_STATE: return TH_PANEL; + case ACT_ARMATURE: return TH_PANEL; default: return TH_PANEL; } } @@ -1757,6 +1861,18 @@ static void check_state_mask(bContext *C, void *arg1_but, void *arg2_mask) but->retval = B_REDR; } +static void check_armature_actuator(bContext *C, void *arg1_but, void *arg2_act) +{ + bArmatureActuator *act = arg2_act; + uiBut *but = arg1_but; + Object *ob= CTX_data_active_object(C); + + /* check that bone exist in the active object */ + but->retval = B_REDR; + check_armature_bone_constraint(ob, act->posechannel, act->constraint); +} + + static short draw_actuatorbuttons(Object *ob, bActuator *act, uiBlock *block, short xco, short yco, short width) { bSoundActuator *sa = NULL; @@ -1776,6 +1892,7 @@ static short draw_actuatorbuttons(Object *ob, bActuator *act, uiBlock *block, sh bTwoDFilterActuator *tdfa = NULL; bParentActuator *parAct = NULL; bStateActuator *staAct = NULL; + bArmatureActuator *armAct = NULL; float *fp; short ysize = 0, wval; @@ -2803,6 +2920,48 @@ static short draw_actuatorbuttons(Object *ob, bActuator *act, uiBlock *block, sh yco-= ysize; break; + case ACT_ARMATURE: + armAct = act->data; + + if (ob->type == OB_ARMATURE) { + str= "Constraint %t|Run armature %x0|Enable %x1|Disable %x2|Set target %x3|Set weight %x4"; + uiDefButI(block, MENU, B_REDR, str, xco+5, yco-24, (width-10)*0.35, 19, &armAct->type, 0.0, 0.0, 0, 0, ""); + + switch (armAct->type) { + case ACT_ARM_RUN: + ysize = 28; + break; + default: + uiBlockBeginAlign(block); + but = uiDefBut(block, TEX, 1, "Bone: ", + (xco+5), (yco-44), (width-10)/2, 19, + armAct->posechannel, 0, 31, 0, 0, + "Bone on which the constraint is defined"); + uiButSetFunc(but, check_armature_actuator, but, armAct); + but = uiDefBut(block, TEX, 1, "Cons: ", + (xco+5)+(width-10)/2, (yco-44), (width-10)/2, 19, + armAct->constraint, 0, 31, 0, 0, + "Name of the constraint you want to controle"); + uiButSetFunc(but, check_armature_actuator, but, armAct); + uiBlockEndAlign(block); + ysize = 48; + switch (armAct->type) { + case ACT_ARM_SETTARGET: + uiDefIDPoinBut(block, test_obpoin_but, ID_OB, 1, "Target: ", xco+5, yco-64, (width-10), 19, &(armAct->target), "Set this object as the target of the constraint"); + uiDefIDPoinBut(block, test_obpoin_but, ID_OB, 1, "Secondary Target: ", xco+5, yco-84, (width-10), 19, &(armAct->subtarget), "Set this object as the secondary target of the constraint (only IK polar target at the moment)"); + ysize += 40; + break; + case ACT_ARM_SETWEIGHT: + uiDefButF(block, NUM, B_REDR, "Weight:", xco+5+(width-10)*0.35,yco-24,(width-10)*0.65,19,&armAct->weight,0.0,1.0,0.0,0.0,"Set weight of this constraint"); + break; + } + } + } + glRects(xco, yco-ysize, xco+width, yco); + uiEmboss((float)xco, (float)yco-ysize, (float)xco+width, (float)yco, 1); + yco-= ysize; + break; + default: ysize= 4; @@ -3317,7 +3476,7 @@ void logic_buttons(bContext *C, ARegion *ar) uiButSetFunc(but, make_unique_prop_names_cb, sens->name, (void*) 0); sens->otype= sens->type; - yco= draw_sensorbuttons(sens, block, xco, yco, width,ob->id.name); + yco= draw_sensorbuttons(ob, sens, block, xco, yco, width,ob->id.name); if(yco-6 < ycoo) ycoo= (yco+ycoo-20)/2; } else { diff --git a/source/blender/editors/space_nla/nla_buttons.c b/source/blender/editors/space_nla/nla_buttons.c index a5ba63fd15d..b193b89d65a 100644 --- a/source/blender/editors/space_nla/nla_buttons.c +++ b/source/blender/editors/space_nla/nla_buttons.c @@ -114,34 +114,69 @@ static int nla_panel_context(const bContext *C, PointerRNA *adt_ptr, PointerRNA if (ANIM_animdata_get_context(C, &ac) == 0) return 0; - /* extract list of active channel(s), of which we should only take the first one (expecting it to be an NLA track) */ - filter= (ANIMFILTER_VISIBLE|ANIMFILTER_ACTIVE); + /* extract list of active channel(s), of which we should only take the first one + * - we need the channels flag to get the active AnimData block when there are no NLA Tracks + */ + filter= (ANIMFILTER_VISIBLE|ANIMFILTER_ACTIVE|ANIMFILTER_CHANNELS); ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype); for (ale= anim_data.first; ale; ale= ale->next) { - // TODO: need some way to select active animdata too... - if (ale->type == ANIMTYPE_NLATRACK) { - NlaTrack *nlt= (NlaTrack *)ale->data; - AnimData *adt= ale->adt; - - /* found it, now set the pointers */ - if (adt_ptr) { - /* AnimData pointer */ - RNA_pointer_create(ale->id, &RNA_AnimData, adt, adt_ptr); - } - if (nlt_ptr) { - /* NLA-Track pointer */ - RNA_pointer_create(ale->id, &RNA_NlaTrack, nlt, nlt_ptr); - } - if (strip_ptr) { - /* NLA-Strip pointer */ - NlaStrip *strip= BKE_nlastrip_find_active(nlt); - RNA_pointer_create(ale->id, &RNA_NlaStrip, strip, strip_ptr); + switch (ale->type) { + case ANIMTYPE_NLATRACK: /* NLA Track - The primary data type which should get caught */ + { + NlaTrack *nlt= (NlaTrack *)ale->data; + AnimData *adt= ale->adt; + + /* found it, now set the pointers */ + if (adt_ptr) { + /* AnimData pointer */ + RNA_pointer_create(ale->id, &RNA_AnimData, adt, adt_ptr); + } + if (nlt_ptr) { + /* NLA-Track pointer */ + RNA_pointer_create(ale->id, &RNA_NlaTrack, nlt, nlt_ptr); + } + if (strip_ptr) { + /* NLA-Strip pointer */ + NlaStrip *strip= BKE_nlastrip_find_active(nlt); + RNA_pointer_create(ale->id, &RNA_NlaStrip, strip, strip_ptr); + } + + found= 1; } - - found= 1; - break; + break; + + case ANIMTYPE_SCENE: /* Top-Level Widgets doubling up as datablocks */ + case ANIMTYPE_OBJECT: + case ANIMTYPE_FILLACTD: /* Action Expander */ + case ANIMTYPE_DSMAT: /* Datablock AnimData Expanders */ + case ANIMTYPE_DSLAM: + case ANIMTYPE_DSCAM: + case ANIMTYPE_DSCUR: + case ANIMTYPE_DSSKEY: + case ANIMTYPE_DSWOR: + case ANIMTYPE_DSPART: + case ANIMTYPE_DSMBALL: + case ANIMTYPE_DSARM: + { + /* for these channels, we only do AnimData */ + if (ale->id && ale->adt) { + if (adt_ptr) { + /* AnimData pointer */ + RNA_pointer_create(ale->id, &RNA_AnimData, ale->adt, adt_ptr); + + /* set found status to -1, since setting to 1 would break the loop + * and potentially skip an active NLA-Track in some cases... + */ + found= -1; + } + } + } + break; } + + if (found > 0) + break; } /* free temp data */ @@ -211,7 +246,7 @@ static void nla_panel_animdata (const bContext *C, Panel *pa) /* Active Action Properties ------------------------------------- */ /* action */ row= uiLayoutRow(layout, 1); - uiTemplateID(row, (bContext *)C, &adt_ptr, "action", NULL /*"ACT_OT_new"*/, NULL, NULL /*"ACT_OT_unlink"*/); // XXX: need to make these operators + uiTemplateID(row, (bContext *)C, &adt_ptr, "action", "ACT_OT_new", NULL, NULL /*"ACT_OT_unlink"*/); // XXX: need to make these operators /* extrapolation */ row= uiLayoutRow(layout, 1); diff --git a/source/blender/editors/space_nla/nla_channels.c b/source/blender/editors/space_nla/nla_channels.c index ccf23266427..07dc3f0ad89 100644 --- a/source/blender/editors/space_nla/nla_channels.c +++ b/source/blender/editors/space_nla/nla_channels.c @@ -116,18 +116,22 @@ static int mouse_nla_channels (bAnimContext *ac, float x, int channel_index, sho } /* action to take depends on what channel we've got */ + // WARNING: must keep this in sync with the equivalent function in anim_channels_edit.c switch (ale->type) { case ANIMTYPE_SCENE: { Scene *sce= (Scene *)ale->data; + AnimData *adt= sce->adt; /* set selection status */ if (selectmode == SELECT_INVERT) { /* swap select */ sce->flag ^= SCE_DS_SELECTED; + if (adt) adt->flag ^= ADT_UI_SELECTED; } else { sce->flag |= SCE_DS_SELECTED; + if (adt) adt->flag |= ADT_UI_SELECTED; } notifierFlags |= ND_ANIMCHAN_SELECT; @@ -139,6 +143,7 @@ static int mouse_nla_channels (bAnimContext *ac, float x, int channel_index, sho Scene *sce= (Scene *)ads->source; Base *base= (Base *)ale->data; Object *ob= base->object; + AnimData *adt= ob->adt; if (nlaedit_is_tweakmode_on(ac) == 0) { /* set selection status */ @@ -146,23 +151,30 @@ static int mouse_nla_channels (bAnimContext *ac, float x, int channel_index, sho /* swap select */ base->flag ^= SELECT; ob->flag= base->flag; + + if (adt) adt->flag ^= ADT_UI_SELECTED; } else { Base *b; - /* deleselect all */ + /* deselect all */ + // TODO: should this deselect all other types of channels too? for (b= sce->base.first; b; b= b->next) { b->flag &= ~SELECT; b->object->flag= b->flag; + if (b->object->adt) b->object->adt->flag &= ~(ADT_UI_SELECTED|ADT_UI_ACTIVE); } /* select object now */ base->flag |= SELECT; ob->flag |= SELECT; + if (adt) adt->flag |= ADT_UI_SELECTED; } /* xxx should be ED_base_object_activate(), but we need context pointer for that... */ //set_active_base(base); + if ((adt) && (adt->flag & ADT_UI_SELECTED)) + adt->flag |= ADT_UI_ACTIVE; /* notifiers - channel was selected */ notifierFlags |= ND_ANIMCHAN_SELECT; @@ -170,6 +182,39 @@ static int mouse_nla_channels (bAnimContext *ac, float x, int channel_index, sho } break; + case ANIMTYPE_FILLACTD: /* Action Expander */ + case ANIMTYPE_DSMAT: /* Datablock AnimData Expanders */ + case ANIMTYPE_DSLAM: + case ANIMTYPE_DSCAM: + case ANIMTYPE_DSCUR: + case ANIMTYPE_DSSKEY: + case ANIMTYPE_DSWOR: + case ANIMTYPE_DSPART: + case ANIMTYPE_DSMBALL: + case ANIMTYPE_DSARM: + { + /* sanity checking... */ + if (ale->adt) { + /* select/deselect */ + if (selectmode == SELECT_INVERT) { + /* inverse selection status of this AnimData block only */ + ale->adt->flag ^= ADT_UI_SELECTED; + } + else { + /* select AnimData block by itself */ + ANIM_deselect_anim_channels(ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR); + ale->adt->flag |= ADT_UI_SELECTED; + } + + /* set active? */ + if ((ale->adt) && (ale->adt->flag & ADT_UI_SELECTED)) + ale->adt->flag |= ADT_UI_ACTIVE; + } + + notifierFlags |= ND_ANIMCHAN_SELECT; + } + break; + case ANIMTYPE_NLATRACK: { NlaTrack *nlt= (NlaTrack *)ale->data; diff --git a/source/blender/editors/space_nla/nla_header.c b/source/blender/editors/space_nla/nla_header.c index 0d3bf2cb6b1..4eb9fac5cb8 100644 --- a/source/blender/editors/space_nla/nla_header.c +++ b/source/blender/editors/space_nla/nla_header.c @@ -246,31 +246,7 @@ void nla_header_buttons(const bContext *C, ARegion *ar) uiBlockSetEmboss(block, UI_EMBOSS); /* filtering buttons */ - if (snla->ads) { - uiBlockBeginAlign(block); - uiDefIconButBitI(block, TOG, ADS_FILTER_ONLYSEL, B_REDR, ICON_RESTRICT_SELECT_OFF, (short)(xco+=XIC),yco,XIC,YIC, &(snla->ads->filterflag), 0, 0, 0, 0, "Only display selected Objects"); - uiDefIconButBitI(block, TOGN, ADS_FILTER_NLA_NOACT, B_REDR, ICON_ACTION, (short)(xco+=XIC),yco,XIC,YIC, &(snla->ads->filterflag), 0, 0, 0, 0, "Include AnimData blocks with no NLA Data"); - uiBlockEndAlign(block); - xco += 5; - - uiBlockBeginAlign(block); - uiDefIconButBitI(block, TOGN, ADS_FILTER_NOSCE, B_REDR, ICON_SCENE_DATA, (short)(xco+=XIC),yco,XIC,YIC, &(snla->ads->filterflag), 0, 0, 0, 0, "Display Scene Animation"); - uiDefIconButBitI(block, TOGN, ADS_FILTER_NOWOR, B_REDR, ICON_WORLD_DATA, (short)(xco+=XIC),yco,XIC,YIC, &(snla->ads->filterflag), 0, 0, 0, 0, "Display World Animation"); - uiDefIconButBitI(block, TOGN, ADS_FILTER_NOSHAPEKEYS, B_REDR, ICON_SHAPEKEY_DATA, (short)(xco+=XIC),yco,XIC,YIC, &(snla->ads->filterflag), 0, 0, 0, 0, "Display ShapeKeys"); - uiDefIconButBitI(block, TOGN, ADS_FILTER_NOMAT, B_REDR, ICON_MATERIAL_DATA, (short)(xco+=XIC),yco,XIC,YIC, &(snla->ads->filterflag), 0, 0, 0, 0, "Display Materials"); - uiDefIconButBitI(block, TOGN, ADS_FILTER_NOLAM, B_REDR, ICON_LAMP_DATA, (short)(xco+=XIC),yco,XIC,YIC, &(snla->ads->filterflag), 0, 0, 0, 0, "Display Lamps"); - uiDefIconButBitI(block, TOGN, ADS_FILTER_NOCAM, B_REDR, ICON_CAMERA_DATA, (short)(xco+=XIC),yco,XIC,YIC, &(snla->ads->filterflag), 0, 0, 0, 0, "Display Cameras"); - uiDefIconButBitI(block, TOGN, ADS_FILTER_NOCUR, B_REDR, ICON_CURVE_DATA, (short)(xco+=XIC),yco,XIC,YIC, &(snla->ads->filterflag), 0, 0, 0, 0, "Display Curves"); - uiDefIconButBitI(block, TOGN, ADS_FILTER_NOMBA, B_REDR, ICON_META_DATA, (short)(xco+=XIC),yco,XIC,YIC, &(snla->ads->filterflag), 0, 0, 0, 0, "Display MetaBalls"); - uiDefIconButBitI(block, TOGN, ADS_FILTER_NOPART, B_REDR, ICON_PARTICLE_DATA, (short)(xco+=XIC),yco,XIC,YIC, &(snla->ads->filterflag), 0, 0, 0, 0, "Display Particles"); - uiBlockEndAlign(block); - xco += 15; - } - else { - // XXX this case shouldn't happen at all... for now, just pad out same amount of space - xco += 10*XIC + 15; - } - xco += (XIC + 8); + xco= ANIM_headerUI_standard_buttons(C, snla->ads, block, xco, yco); /* auto-snap selector */ if (snla->flag & SNLA_DRAWTIME) { diff --git a/source/blender/editors/space_nla/space_nla.c b/source/blender/editors/space_nla/space_nla.c index 06ee34a6573..41435810889 100644 --- a/source/blender/editors/space_nla/space_nla.c +++ b/source/blender/editors/space_nla/space_nla.c @@ -409,6 +409,7 @@ static void nla_main_area_listener(ARegion *ar, wmNotifier *wmn) break; case NC_SCENE: switch(wmn->data) { + case ND_RENDER_OPTIONS: case ND_OB_ACTIVE: case ND_FRAME: case ND_MARKERS: diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c index a9f53c9efd9..b8da42079c4 100644 --- a/source/blender/editors/space_node/drawnode.c +++ b/source/blender/editors/space_node/drawnode.c @@ -22,7 +22,7 @@ * * The Original Code is: all of this file. * - * Contributor(s): David Millan Escriva, Juho Vepsäläinen, Bob Holcomb + * Contributor(s): David Millan Escriva, Juho Vepsäläinen, Bob Holcomb, Thomas Dinges * * ***** END GPL LICENSE BLOCK ***** */ @@ -243,12 +243,12 @@ static void node_buts_rgb(uiLayout *layout, PointerRNA *ptr) } static void node_buts_mix_rgb(uiLayout *layout, PointerRNA *ptr) -{ - bNodeTree *ntree= (bNodeTree*)ptr->id.data; +{ uiLayout *row; - row= uiLayoutRow(layout, 1); + bNodeTree *ntree= (bNodeTree*)ptr->id.data; + row= uiLayoutRow(layout, 1); uiItemR(row, "", 0, ptr, "blend_type", 0); if(ntree->type == NTREE_COMPOSIT) uiItemR(row, "", ICON_IMAGE_RGB_ALPHA, ptr, "alpha", 0); @@ -1107,330 +1107,167 @@ static void node_blur_update_sizey_cb(bContext *C, void *node, void *poin2) } static void node_composit_buts_blur(uiLayout *layout, PointerRNA *ptr) { - uiBlock *block= uiLayoutFreeBlock(layout); - bNode *node= ptr->data; - rctf *butr= &node->butr; - NodeBlurData *nbd= node->storage; - uiBut *bt; - short dy= butr->ymin+58; - short dx= (butr->xmax-butr->xmin)/2; - char str[256]; + uiLayout *col; - uiBlockBeginAlign(block); - sprintf(str, "Filter Type%%t|Flat %%x%d|Tent %%x%d|Quad %%x%d|Cubic %%x%d|Gauss %%x%d|Fast Gauss%%x%d|CatRom %%x%d|Mitch %%x%d", R_FILTER_BOX, R_FILTER_TENT, R_FILTER_QUAD, R_FILTER_CUBIC, R_FILTER_GAUSS, R_FILTER_FAST_GAUSS, R_FILTER_CATROM, R_FILTER_MITCH); - uiDefButS(block, MENU, B_NODE_EXEC,str, - butr->xmin, dy, dx*2, 19, - &nbd->filtertype, 0, 0, 0, 0, "Set sampling filter for blur"); - dy-=19; - if (nbd->filtertype != R_FILTER_FAST_GAUSS) { - uiDefButC(block, TOG, B_NODE_EXEC, "Bokeh", - butr->xmin, dy, dx, 19, - &nbd->bokeh, 0, 0, 0, 0, "Uses circular filter, warning it's slow!"); - uiDefButC(block, TOG, B_NODE_EXEC, "Gamma", - butr->xmin+dx, dy, dx, 19, - &nbd->gamma, 0, 0, 0, 0, "Applies filter on gamma corrected values"); - } else { - uiBlockEndAlign(block); - uiBlockBeginAlign(block); + col= uiLayoutColumn(layout, 0); + + uiItemR(col, "", 0, ptr, "filter_type", 0); + /* Only for "Fast Gaussian" */ + if (RNA_enum_get(ptr, "filter_type")!= 7) { + uiItemR(col, NULL, 0, ptr, "bokeh", 0); + uiItemR(col, NULL, 0, ptr, "gamma", 0); } - dy-=19; - bt= uiDefButS(block, TOG, B_NOP, "Relative", - butr->xmin, dy, dx*2, 19, - &nbd->relative, 0, 0, 0, 0, "Use relative (percent) values to define blur radius"); - uiButSetFunc(bt, node_blur_relative_cb, node, NULL); - - dy-=19; - if(nbd->relative) { - bt= uiDefButF(block, NUM, B_NODE_EXEC, "X:", - butr->xmin, dy, dx, 19, - &nbd->percentx, 0.0f, 1.0f, 0, 0, ""); - uiButSetFunc(bt, node_blur_update_sizex_cb, node, NULL); - bt= uiDefButF(block, NUM, B_NODE_EXEC, "Y:", - butr->xmin+dx, dy, dx, 19, - &nbd->percenty, 0.0f, 1.0f, 0, 0, ""); - uiButSetFunc(bt, node_blur_update_sizey_cb, node, NULL); + + uiItemR(col, NULL, 0, ptr, "relative", 0); + col= uiLayoutColumn(layout, 1); + if (RNA_boolean_get(ptr, "relative")== 1) { + uiItemR(col, "X", 0, ptr, "factor_x", 0); + uiItemR(col, "Y", 0, ptr, "factor_y", 0); } else { - uiDefButS(block, NUM, B_NODE_EXEC, "X:", - butr->xmin, dy, dx, 19, - &nbd->sizex, 0, 256, 0, 0, ""); - uiDefButS(block, NUM, B_NODE_EXEC, "Y:", - butr->xmin+dx, dy, dx, 19, - &nbd->sizey, 0, 256, 0, 0, ""); + uiItemR(col, "X", 0, ptr, "sizex", 0); + uiItemR(col, "Y", 0, ptr, "sizey", 0); } - uiBlockEndAlign(block); } static void node_composit_buts_dblur(uiLayout *layout, PointerRNA *ptr) { - uiBlock *block= uiLayoutFreeBlock(layout); - bNode *node= ptr->data; - rctf *butr= &node->butr; - NodeDBlurData *ndbd = node->storage; - short dy = butr->ymin + 171; - short dx = butr->xmax - butr->xmin; - short halfdx= (short)dx/2; - - uiBlockBeginAlign(block); - uiDefButS(block, NUM, B_NODE_EXEC, "Iterations:", - butr->xmin, dy, dx, 19, - &ndbd->iter, 1, 32, 10, 0, "Amount of iterations"); - uiDefButC(block, TOG, B_NODE_EXEC, "Wrap", - butr->xmin, dy-= 19, dx, 19, - &ndbd->wrap, 0, 0, 0, 0, "Wrap blur"); - uiBlockEndAlign(block); - - dy-= 9; - - uiDefBut(block, LABEL, B_NOP, "Center", butr->xmin, dy-= 19, dx, 19, NULL, 0.0f, 0.0f, 0, 0, ""); - - uiBlockBeginAlign(block); - uiDefButF(block, NUM, B_NODE_EXEC, "X:", - butr->xmin, dy-= 19, halfdx, 19, - &ndbd->center_x, 0.0f, 1.0f, 10, 0, "X center in percents"); - uiDefButF(block, NUM, B_NODE_EXEC, "Y:", - butr->xmin+halfdx, dy, halfdx, 19, - &ndbd->center_y, 0.0f, 1.0f, 10, 0, "Y center in percents"); - uiBlockEndAlign(block); - - dy-= 9; - - uiBlockBeginAlign(block); - uiDefButF(block, NUM, B_NODE_EXEC, "Distance:", - butr->xmin, dy-= 19, dx, 19, - &ndbd->distance, -1.0f, 1.0f, 10, 0, "Amount of which the image moves"); - uiDefButF(block, NUM, B_NODE_EXEC, "Angle:", - butr->xmin, dy-= 19, dx, 19, - &ndbd->angle, 0.0f, 360.0f, 1000, 0, "Angle in which the image will be moved"); - uiBlockEndAlign(block); - - dy-= 9; - - uiDefButF(block, NUM, B_NODE_EXEC, "Spin:", - butr->xmin, dy-= 19, dx, 19, - &ndbd->spin, -360.0f, 360.0f, 1000, 0, "Angle that is used to spin the image"); - - dy-= 9; - - uiDefButF(block, NUM, B_NODE_EXEC, "Zoom:", - butr->xmin, dy-= 19, dx, 19, - &ndbd->zoom, 0.0f, 100.0f, 100, 0, "Amount of which the image is zoomed"); + uiLayout *col; + + uiItemR(layout, NULL, 0, ptr, "iterations", 0); + uiItemR(layout, NULL, 0, ptr, "wrap", 0); + + col= uiLayoutColumn(layout, 1); + uiItemL(col, "Center:", 0); + uiItemR(col, "X", 0, ptr, "center_x", 0); + uiItemR(col, "Y", 0, ptr, "center_y", 0); + + uiItemS(layout); + + col= uiLayoutColumn(layout, 1); + uiItemR(col, NULL, 0, ptr, "distance", 0); + uiItemR(col, NULL, 0, ptr, "angle", 0); + + uiItemS(layout); + + uiItemR(layout, NULL, 0, ptr, "spin", 0); + uiItemR(layout, NULL, 0, ptr, "zoom", 0); } static void node_composit_buts_bilateralblur(uiLayout *layout, PointerRNA *ptr) -{ - uiBlock *block= uiLayoutFreeBlock(layout); - bNode *node= ptr->data; - rctf *butr= &node->butr; - NodeBilateralBlurData *nbbd= node->storage; - short dy= butr->ymin+38; - short dx= (butr->xmax-butr->xmin); +{ + uiLayout *col; - uiBlockBeginAlign(block); - uiDefButS(block, NUM, B_NODE_EXEC, "Iterations:", - butr->xmin, dy, dx, 19, - &nbbd->iter, 1, 128, 0, 0, "Amount of iterations"); - dy-=19; - uiDefButF(block, NUM, B_NODE_EXEC, "Color Sigma:", - butr->xmin, dy, dx, 19, - &nbbd->sigma_color,0.01, 3, 10, 0, "Sigma value used to modify color"); - dy-=19; - uiDefButF(block, NUM, B_NODE_EXEC, "Space Sigma:", - butr->xmin, dy, dx, 19, - &nbbd->sigma_space ,0.01, 30, 10, 0, "Sigma value used to modify space"); + col= uiLayoutColumn(layout, 1); + uiItemR(col, NULL, 0, ptr, "iterations", 0); + uiItemR(col, NULL, 0, ptr, "sigma_color", 0); + uiItemR(col, NULL, 0, ptr, "sigma_space", 0); } /* qdn: defocus node */ static void node_composit_buts_defocus(uiLayout *layout, PointerRNA *ptr) { - uiBlock *block= uiLayoutFreeBlock(layout); - bNode *node= ptr->data; - rctf *butr= &node->butr; - NodeDefocus *nqd = node->storage; - short dy = butr->ymin + 209; - short dx = butr->xmax - butr->xmin; - char* mstr1 = "Bokeh Type%t|Octagon %x8|Heptagon %x7|Hexagon %x6|Pentagon %x5|Square %x4|Triangle %x3|Disk %x0"; - - uiDefBut(block, LABEL, B_NOP, "Bokeh Type", butr->xmin, dy, dx, 19, NULL, 0, 0, 0, 0, ""); - uiDefButC(block, MENU, B_NODE_EXEC, mstr1, - butr->xmin, dy-19, dx, 19, - &nqd->bktype, 0, 0, 0, 0, "Bokeh type"); - if (nqd->bktype) { /* for some reason rotating a disk doesn't seem to work... ;) */ - uiDefButC(block, NUM, B_NODE_EXEC, "Rotate:", - butr->xmin, dy-38, dx, 19, - &nqd->rotation, 0, 90, 0, 0, "Bokeh shape rotation offset in degrees"); - } - uiDefButC(block, TOG, B_NODE_EXEC, "Gamma Correct", - butr->xmin, dy-57, dx, 19, - &nqd->gamco, 0, 0, 0, 0, "Enable gamma correction before and after main process"); - if (nqd->no_zbuf==0) { - // only needed for zbuffer input - uiDefButF(block, NUM, B_NODE_EXEC, "fStop:", - butr->xmin, dy-76, dx, 19, - &nqd->fstop, 0.5, 128, 10, 0, "Amount of focal blur, 128=infinity=perfect focus, half the value doubles the blur radius"); - } - uiDefButF(block, NUM, B_NODE_EXEC, "Maxblur:", - butr->xmin, dy-95, dx, 19, - &nqd->maxblur, 0, 10000, 1000, 0, "blur limit, maximum CoC radius, 0=no limit"); - uiDefButF(block, NUM, B_NODE_EXEC, "BThreshold:", - butr->xmin, dy-114, dx, 19, - &nqd->bthresh, 0, 100, 100, 0, "CoC radius threshold, prevents background bleed on in-focus midground, 0=off"); - uiDefButC(block, TOG, B_NODE_EXEC, "Preview", - butr->xmin, dy-142, dx, 19, - &nqd->preview, 0, 0, 0, 0, "Enable sampling mode, useful for preview when using low samplecounts"); - if (nqd->preview) { - /* only visible when sampling mode enabled */ - uiDefButS(block, NUM, B_NODE_EXEC, "Samples:", - butr->xmin, dy-161, dx, 19, - &nqd->samples, 16, 256, 0, 0, "Number of samples (16=grainy, higher=less noise)"); - } - uiDefButS(block, TOG, B_NODE_EXEC, "No zbuffer", - butr->xmin, dy-190, dx, 19, - &nqd->no_zbuf, 0, 0, 0, 0, "Enable when using an image as input instead of actual zbuffer (auto enabled if node not image based, eg. time node)"); - if (nqd->no_zbuf) { - uiDefButF(block, NUM, B_NODE_EXEC, "Zscale:", - butr->xmin, dy-209, dx, 19, - &nqd->scale, 0, 1000, 100, 0, "Scales the Z input when not using a zbuffer, controls maximum blur designated by the color white or input value 1"); - } -} + uiLayout *sub, *col; + + col= uiLayoutColumn(layout, 0); + uiItemL(col, "Bokeh Type:", 0); + uiItemR(col, "", 0, ptr, "bokeh", 0); + uiItemR(col, NULL, 0, ptr, "angle", 0); + + uiItemR(layout, NULL, 0, ptr, "gamma_correction", 0); + col = uiLayoutColumn(layout, 0); + uiLayoutSetActive(col, RNA_boolean_get(ptr, "use_zbuffer")==0); + uiItemR(col, NULL, 0, ptr, "f_stop", 0); + + uiItemR(layout, NULL, 0, ptr, "max_blur", 0); + uiItemR(layout, NULL, 0, ptr, "threshold", 0); + + // Preview + col = uiLayoutColumn(layout, 0); + uiItemR(col, NULL, 0, ptr, "preview", 0); + sub = uiLayoutColumn(col, 0); + uiLayoutSetActive(sub, RNA_boolean_get(ptr, "preview")); + uiItemR(sub, NULL, 0, ptr, "samples", 0); + + // Z-Buffer + col = uiLayoutColumn(layout, 0); + uiItemR(col, NULL, 0, ptr, "use_zbuffer", 0); + sub = uiLayoutColumn(col, 0); + uiLayoutSetActive(sub, RNA_boolean_get(ptr, "use_zbuffer")); + uiItemR(sub, NULL, 0, ptr, "z_scale", 0); +} /* qdn: glare node */ static void node_composit_buts_glare(uiLayout *layout, PointerRNA *ptr) -{ - uiBlock *block= uiLayoutFreeBlock(layout); - bNode *node= ptr->data; - rctf *butr= &node->butr; - NodeGlare *ndg = node->storage; - short dy = butr->ymin + 152, dx = butr->xmax - butr->xmin; - char* mn1 = "Type%t|Ghosts%x3|Streaks%x2|Fog Glow%x1|Simple Star%x0"; - char* mn2 = "Quality/Speed%t|High/Slow%x0|Medium/Medium%x1|Low/Fast%x2"; - uiDefButC(block, MENU, B_NODE_EXEC, mn1, - butr->xmin, dy, dx, 19, - &ndg->type, 0, 0, 0, 0, "Glow/Flare/Bloom type"); - uiDefButC(block, MENU, B_NODE_EXEC, mn2, - butr->xmin, dy-19, dx, 19, - &ndg->quality, 0, 0, 0, 0, - "Quality speed trade off, if not set to high quality, effect will be applied to low-res copy of source image"); - if (ndg->type != 1) { - uiDefButC(block, NUM, B_NODE_EXEC, "Iterations:", - butr->xmin, dy-38, dx, 19, - &ndg->iter, 2, 5, 1, 0, - "higher values will generate longer/more streaks/ghosts"); - if (ndg->type != 0) - uiDefButF(block, NUM, B_NODE_EXEC, "ColMod:", - butr->xmin, dy-57, dx, 19, - &ndg->colmod, 0, 1, 10, 0, - "Amount of Color Modulation, modulates colors of streaks and ghosts for a spectral dispersion effect"); - } - uiDefButF(block, NUM, B_NODE_EXEC, "Mix:", - butr->xmin, dy-76, dx, 19, - &ndg->mix, -1, 1, 10, 0, - "Mix balance, -1 is original image only, 0 is exact 50/50 mix, 1 is processed image only"); - uiDefButF(block, NUM, B_NODE_EXEC, "Threshold:", - butr->xmin, dy-95, dx, 19, - &ndg->threshold, 0, 1000, 10, 0, - "Brightness threshold, the glarefilter will be applied only to pixels brighter than this value"); - if ((ndg->type == 2) || (ndg->type == 0)) - { - if (ndg->type == 2) { - uiDefButC(block, NUM, B_NODE_EXEC, "streaks:", - butr->xmin, dy-114, dx, 19, - &ndg->angle, 2, 16, 1000, 0, - "Total number of streaks"); - uiDefButC(block, NUM, B_NODE_EXEC, "AngOfs:", - butr->xmin, dy-133, dx, 19, - &ndg->angle_ofs, 0, 180, 1000, 0, - "Streak angle rotation offset in degrees"); - } - uiDefButF(block, NUM, B_NODE_EXEC, "Fade:", - butr->xmin, dy-152, dx, 19, - &ndg->fade, 0.75, 1, 5, 0, - "Streak fade out factor"); - } - if (ndg->type == 0) - uiDefButC(block, TOG, B_NODE_EXEC, "Rot45", - butr->xmin, dy-114, dx, 19, - &ndg->angle, 0, 0, 0, 0, - "simple star filter, add 45 degree rotation offset"); - if ((ndg->type == 1) || (ndg->type > 3)) // PBGH and fog glow - uiDefButC(block, NUM, B_NODE_EXEC, "Size:", - butr->xmin, dy-114, dx, 19, - &ndg->size, 6, 9, 1000, 0, - "glow/glare size (not actual size, relative to initial size of bright area of pixels)"); +{ + uiItemR(layout, "", 0, ptr, "glare_type", 0); + uiItemR(layout, "", 0, ptr, "quality", 0); + + if (RNA_enum_get(ptr, "glare_type")!= 1) { + uiItemR(layout, NULL, 0, ptr, "iterations", 0); + + if (RNA_enum_get(ptr, "glare_type")!= 0) + uiItemR(layout, NULL, 0, ptr, "color_modulation", UI_ITEM_R_SLIDER); + } + + uiItemR(layout, NULL, 0, ptr, "mix", 0); + uiItemR(layout, NULL, 0, ptr, "threshold", 0); + + if (RNA_enum_get(ptr, "glare_type")== 2) { + uiItemR(layout, NULL, 0, ptr, "streaks", 0); + uiItemR(layout, NULL, 0, ptr, "angle_offset", 0); + } + if (RNA_enum_get(ptr, "glare_type")== 0 || RNA_enum_get(ptr, "glare_type")== 2) { + uiItemR(layout, NULL, 0, ptr, "fade", UI_ITEM_R_SLIDER); + + if (RNA_enum_get(ptr, "glare_type")== 0) + uiItemR(layout, NULL, 0, ptr, "rotate_45", 0); + } + if (RNA_enum_get(ptr, "glare_type")== 1) { + uiItemR(layout, NULL, 0, ptr, "size", 0); + } } /* qdn: tonemap node */ static void node_composit_buts_tonemap(uiLayout *layout, PointerRNA *ptr) -{ - uiBlock *block= uiLayoutFreeBlock(layout); - bNode *node= ptr->data; - rctf *butr= &node->butr; - NodeTonemap *ntm = node->storage; - short dy = butr->ymin + 76, dx = butr->xmax - butr->xmin; - char* mn = "Type%t|R/D Photoreceptor%x1|Rh Simple%x0"; - - uiBlockBeginAlign(block); - uiDefButI(block, MENU, B_NODE_EXEC, mn, - butr->xmin, dy, dx, 19, - &ntm->type, 0, 0, 0, 0, - "Tone mapping type"); - if (ntm->type == 0) { - uiDefButF(block, NUM, B_NODE_EXEC, "Key:", - butr->xmin, dy-19, dx, 19, - &ntm->key, 0, 1, 5, 0, - "The value the average luminance is mapped to"); - uiDefButF(block, NUM, B_NODE_EXEC, "Offset:", - butr->xmin, dy-38, dx, 19, - &ntm->offset, 0.001, 10, 5, 0, - "Tonemap offset, normally always 1, but can be used as an extra control to alter the brightness curve"); - uiDefButF(block, NUM, B_NODE_EXEC, "Gamma:", - butr->xmin, dy-57, dx, 19, - &ntm->gamma, 0.001, 3, 5, 0, - "Gamma factor, if not used, set to 1"); +{ + uiLayout *col; + + col = uiLayoutColumn(layout, 0); + uiItemR(col, "", 0, ptr, "tonemap_type", 0); + if (RNA_enum_get(ptr, "tonemap_type")== 0) { + uiItemR(col, NULL, 0, ptr, "key", UI_ITEM_R_SLIDER); + uiItemR(col, NULL, 0, ptr, "offset", 0); + uiItemR(col, NULL, 0, ptr, "gamma", 0); } else { - uiDefButF(block, NUM, B_NODE_EXEC, "Intensity:", - butr->xmin, dy-19, dx, 19, - &ntm->f, -8, 8, 10, 0, "if less than zero, darkens image, otherwise makes it brighter"); - uiDefButF(block, NUM, B_NODE_EXEC, "Contrast:", - butr->xmin, dy-38, dx, 19, - &ntm->m, 0, 1, 5, 0, "Set to 0 to use estimate from input image"); - uiDefButF(block, NUM, B_NODE_EXEC, "Adaptation:", - butr->xmin, dy-57, dx, 19, - &ntm->a, 0, 1, 5, 0, "if 0, global, if 1, based on pixel intensity"); - uiDefButF(block, NUM, B_NODE_EXEC, "ColCorrect:", - butr->xmin, dy-76, dx, 19, - &ntm->c, 0, 1, 5, 0, "color correction, if 0, same for all channels, if 1, each independent"); + uiItemR(col, NULL, 0, ptr, "intensity", 0); + uiItemR(col, NULL, 0, ptr, "contrast", UI_ITEM_R_SLIDER); + uiItemR(col, NULL, 0, ptr, "adaptation", UI_ITEM_R_SLIDER); + uiItemR(col, NULL, 0, ptr, "correction", UI_ITEM_R_SLIDER); } - uiBlockEndAlign(block); } /* qdn: lens distortion node */ static void node_composit_buts_lensdist(uiLayout *layout, PointerRNA *ptr) { uiLayout *col; - - bNode *node= ptr->data; - NodeLensDist *nld = node->storage; col= uiLayoutColumn(layout, 0); - uiItemR(col, NULL, 0, ptr, "projector", 0); - if (!nld->proj) { - col = uiLayoutColumn(col, 0); - uiItemR(col, NULL, 0, ptr, "jitter", 0); - uiItemR(col, NULL, 0, ptr, "fit", 0); - } -// uiLayoutSetActive(col, RNA_boolean_get(&imaptr, "projector")); -} + col = uiLayoutColumn(col, 0); + uiLayoutSetActive(col, RNA_boolean_get(ptr, "projector")==0); + uiItemR(col, NULL, 0, ptr, "jitter", 0); + uiItemR(col, NULL, 0, ptr, "fit", 0); +} static void node_composit_buts_vecblur(uiLayout *layout, PointerRNA *ptr) { uiLayout *col; - col= uiLayoutColumn(layout, 1); + col= uiLayoutColumn(layout, 0); uiItemR(col, NULL, 0, ptr, "samples", 0); uiItemR(col, "Blur", 0, ptr, "factor", 0); @@ -1438,10 +1275,8 @@ static void node_composit_buts_vecblur(uiLayout *layout, PointerRNA *ptr) uiItemL(col, "Speed:", 0); uiItemR(col, "Min", 0, ptr, "min_speed", 0); uiItemR(col, "Max", 0, ptr, "max_speed", 0); - - col= uiLayoutColumn(layout, 0); - uiItemR(col, NULL, 0, ptr, "curved", 0); + uiItemR(layout, NULL, 0, ptr, "curved", 0); } static void node_composit_buts_filter(uiLayout *layout, PointerRNA *ptr) @@ -1458,9 +1293,7 @@ static void node_composit_buts_crop(uiLayout *layout, PointerRNA *ptr) { uiLayout *col; - col= uiLayoutColumn(layout, 1); - - uiItemR(col, NULL, 0, ptr, "crop_size", 0); + uiItemR(layout, NULL, 0, ptr, "crop_size", 0); col= uiLayoutColumn(layout, 1); uiItemR(col, "Left", 0, ptr, "x1", 0); @@ -1471,203 +1304,132 @@ static void node_composit_buts_crop(uiLayout *layout, PointerRNA *ptr) static void node_composit_buts_splitviewer(uiLayout *layout, PointerRNA *ptr) { - uiBlock *block= uiLayoutFreeBlock(layout); - bNode *node= ptr->data; - rctf *butr= &node->butr; - - uiBlockBeginAlign(block); + uiLayout *row, *col; - uiDefButS(block, ROW, B_NODE_EXEC, "X", - butr->xmin, butr->ymin+19, (butr->xmax-butr->xmin)/2, 20, - &node->custom2, 0.0, 0.0, 0, 0, ""); - uiDefButS(block, ROW, B_NODE_EXEC, "Y", - butr->xmin+(butr->xmax-butr->xmin)/2, butr->ymin+19, (butr->xmax-butr->xmin)/2, 20, - &node->custom2, 0.0, 1.0, 0, 0, ""); - - uiDefButS(block, NUMSLI, B_NODE_EXEC, "Split %: ", - butr->xmin, butr->ymin, butr->xmax-butr->xmin, 20, &node->custom1, 0, 100, 10, 0, ""); + col= uiLayoutColumn(layout, 0); + row= uiLayoutRow(col, 0); + uiItemR(row, NULL, 0, ptr, "axis", UI_ITEM_R_EXPAND); + uiItemR(col, NULL, 0, ptr, "factor", 0); } static void node_composit_buts_map_value(uiLayout *layout, PointerRNA *ptr) { - uiBlock *block= uiLayoutFreeBlock(layout); - bNode *node= ptr->data; - rctf *butr= &node->butr; - TexMapping *texmap= node->storage; - short xstart= (short)butr->xmin; - short dy= (short)(butr->ymax-19.0f); - short dx= (short)(butr->xmax-butr->xmin)/2; + uiLayout *sub, *col; - uiBlockBeginAlign(block); - uiDefButF(block, NUM, B_NODE_EXEC, "Offs:", xstart, dy, 2*dx, 19, texmap->loc, -1000.0f, 1000.0f, 10, 2, ""); - dy-= 19; - uiDefButF(block, NUM, B_NODE_EXEC, "Size:", xstart, dy, 2*dx, 19, texmap->size, -1000.0f, 1000.0f, 10, 3, ""); - dy-= 23; - uiBlockBeginAlign(block); - uiDefButBitI(block, TOG, TEXMAP_CLIP_MIN, B_NODE_EXEC, "Min", xstart, dy, dx, 19, &texmap->flag, 0.0f, 0.0f, 0, 0, ""); - uiDefButF(block, NUM, B_NODE_EXEC, "", xstart+dx, dy, dx, 19, texmap->min, -1000.0f, 1000.0f, 10, 2, ""); - dy-= 19; - uiDefButBitI(block, TOG, TEXMAP_CLIP_MAX, B_NODE_EXEC, "Max", xstart, dy, dx, 19, &texmap->flag, 0.0f, 0.0f, 0, 0, ""); - uiDefButF(block, NUM, B_NODE_EXEC, "", xstart+dx, dy, dx, 19, texmap->max, -1000.0f, 1000.0f, 10, 2, ""); + col =uiLayoutColumn(layout, 1); + uiItemR(col, NULL, 0, ptr, "offset", 0); + uiItemR(col, NULL, 0, ptr, "size", 0); + + col =uiLayoutColumn(layout, 1); + uiItemR(col, NULL, 0, ptr, "use_min", 0); + sub =uiLayoutColumn(col, 0); + uiLayoutSetActive(sub, RNA_boolean_get(ptr, "use_min")); + uiItemR(sub, "", 0, ptr, "min", 0); + + col =uiLayoutColumn(layout, 1); + uiItemR(col, NULL, 0, ptr, "use_max", 0); + sub =uiLayoutColumn(col, 0); + uiLayoutSetActive(sub, RNA_boolean_get(ptr, "use_max")); + uiItemR(sub, "", 0, ptr, "max", 0); } static void node_composit_buts_alphaover(uiLayout *layout, PointerRNA *ptr) -{ - uiBlock *block= uiLayoutFreeBlock(layout); - bNode *node= ptr->data; - rctf *butr= &node->butr; - NodeTwoFloats *ntf= node->storage; +{ + uiLayout *col; + col =uiLayoutColumn(layout, 1); /* alpha type */ - uiDefButS(block, TOG, B_NODE_EXEC, "ConvertPremul", - butr->xmin, butr->ymin+19, butr->xmax-butr->xmin, 19, - &node->custom1, 0, 0, 0, 0, ""); + uiItemR(col, NULL, 0, ptr, "convert_premul", 0); /* mix factor */ - uiDefButF(block, NUM, B_NODE_EXEC, "Premul: ", - butr->xmin, butr->ymin, butr->xmax-butr->xmin, 19, - &ntf->x, 0.0f, 1.0f, 100, 0, ""); + uiItemR(col, NULL, 0, ptr, "premul", 0); } static void node_composit_buts_hue_sat(uiLayout *layout, PointerRNA *ptr) { - uiBlock *block= uiLayoutFreeBlock(layout); - bNode *node= ptr->data; - rctf *butr= &node->butr; - NodeHueSat *nhs= node->storage; + uiLayout *col; - uiBlockBeginAlign(block); - uiDefButF(block, NUMSLI, B_NODE_EXEC, "Hue: ", - butr->xmin, butr->ymin+40.0f, butr->xmax-butr->xmin, 20, - &nhs->hue, 0.0f, 1.0f, 100, 0, ""); - uiDefButF(block, NUMSLI, B_NODE_EXEC, "Sat: ", - butr->xmin, butr->ymin+20.0f, butr->xmax-butr->xmin, 20, - &nhs->sat, 0.0f, 2.0f, 100, 0, ""); - uiDefButF(block, NUMSLI, B_NODE_EXEC, "Val: ", - butr->xmin, butr->ymin, butr->xmax-butr->xmin, 20, - &nhs->val, 0.0f, 2.0f, 100, 0, ""); + col =uiLayoutColumn(layout, 0); + uiItemR(col, NULL, 0, ptr, "hue", UI_ITEM_R_SLIDER); + uiItemR(col, NULL, 0, ptr, "sat", UI_ITEM_R_SLIDER); + uiItemR(col, NULL, 0, ptr, "val", UI_ITEM_R_SLIDER); } static void node_composit_buts_dilateerode(uiLayout *layout, PointerRNA *ptr) { - uiBlock *block= uiLayoutFreeBlock(layout); - bNode *node= ptr->data; - rctf *butr= &node->butr; - - uiDefButS(block, NUM, B_NODE_EXEC, "Distance:", - butr->xmin, butr->ymin, butr->xmax-butr->xmin, 20, - &node->custom2, -100, 100, 0, 0, "Distance to grow/shrink (number of iterations)"); + uiItemR(layout, NULL, 0, ptr, "distance", 0); } static void node_composit_buts_diff_matte(uiLayout *layout, PointerRNA *ptr) { - uiBlock *block= uiLayoutFreeBlock(layout); - bNode *node= ptr->data; - rctf *butr= &node->butr; - NodeChroma *c= node->storage; + uiLayout *col; - uiBlockBeginAlign(block); - uiDefButF(block, NUMSLI, B_NODE_EXEC+node->nr, "Tolerance: ", - butr->xmin, butr->ymin+20, butr->xmax-butr->xmin, 20, - &c->t1, 0.0f, 1.0f, 100, 0, "Color differences below this threshold are keyed."); - uiDefButF(block, NUMSLI, B_NODE_EXEC+node->nr, "Falloff: ", - butr->xmin, butr->ymin, butr->xmax-butr->xmin, 20, - &c->t2, 0.0f, 1.0f, 100, 0, "Color differences below this additional threshold are partially keyed."); - uiBlockEndAlign(block); + col =uiLayoutColumn(layout, 1); + uiItemR(col, NULL, 0, ptr, "tolerance", UI_ITEM_R_SLIDER); + uiItemR(col, NULL, 0, ptr, "falloff", UI_ITEM_R_SLIDER); } static void node_composit_buts_distance_matte(uiLayout *layout, PointerRNA *ptr) { - uiBlock *block= uiLayoutFreeBlock(layout); - bNode *node= ptr->data; - rctf *butr= &node->butr; - NodeChroma *c= node->storage; + uiLayout *col; - uiBlockBeginAlign(block); - uiDefButF(block, NUMSLI, B_NODE_EXEC+node->nr, "Tolerance: ", - butr->xmin, butr->ymin+20, butr->xmax-butr->xmin, 20, - &c->t1, 0.0f, 1.0f, 100, 0, "Color distances below this threshold are keyed."); - uiDefButF(block, NUMSLI, B_NODE_EXEC+node->nr, "Falloff: ", - butr->xmin, butr->ymin, butr->xmax-butr->xmin, 20, - &c->t2, 0.0f, 1.0f, 100, 0, "Color distances below this additional threshold are partially keyed."); - uiBlockEndAlign(block); + col =uiLayoutColumn(layout, 1); + uiItemR(col, NULL, 0, ptr, "tolerance", UI_ITEM_R_SLIDER); + uiItemR(col, NULL, 0, ptr, "falloff", UI_ITEM_R_SLIDER); } static void node_composit_buts_color_spill(uiLayout *layout, PointerRNA *ptr) { - uiBlock *block= uiLayoutFreeBlock(layout); - bNode *node= ptr->data; - rctf *butr= &node->butr; - short dx= (butr->xmax-butr->xmin)/3; - - NodeChroma *c=node->storage; - uiBlockBeginAlign(block); - uiDefButF(block, NUM, B_NODE_EXEC, "Enhance: ", - butr->xmin, butr->ymin+20.0, butr->xmax-butr->xmin, 20, - &c->t1, 0.0f, 0.5f, 100, 2, "Adjusts how much selected channel is affected by color spill algorithm"); - uiDefButS(block, ROW, B_NODE_EXEC, "R", - butr->xmin,butr->ymin,dx,20, - &node->custom1,1,1, 0, 0, "Red Spill Suppression"); - uiDefButS(block, ROW, B_NODE_EXEC, "G", - butr->xmin+dx,butr->ymin,dx,20, - &node->custom1,1,2, 0, 0, "Green Spill Suppression"); - uiDefButS(block, ROW, B_NODE_EXEC, "B", - butr->xmin+2*dx,butr->ymin,dx,20, - &node->custom1, 1, 3, 0, 0, "Blue Spill Suppression"); - uiBlockEndAlign(block); + uiLayout *row, *col; + + col =uiLayoutColumn(layout, 0); + uiItemR(col, NULL, 0, ptr, "factor", 0); + row= uiLayoutRow(col, 0); + uiItemR(row, NULL, 0, ptr, "channel", UI_ITEM_R_EXPAND); } static void node_composit_buts_chroma_matte(uiLayout *layout, PointerRNA *ptr) { - uiBlock *block= uiLayoutFreeBlock(layout); - bNode *node= ptr->data; - rctf *butr= &node->butr; - short dx=(butr->xmax-butr->xmin)/2; - NodeChroma *c= node->storage; - uiBlockBeginAlign(block); - - uiDefButF(block, NUMSLI, B_NODE_EXEC, "Acceptance ", - butr->xmin, butr->ymin+60, butr->xmax-butr->xmin, 20, - &c->t1, 1.0f, 80.0f, 100, 0, "Tolerance for colors to be considered a keying color"); - uiDefButF(block, NUMSLI, B_NODE_EXEC, "Cutoff ", - butr->xmin, butr->ymin+40, butr->xmax-butr->xmin, 20, - &c->t2, 0.0f, 30.0f, 100, 0, "Colors below this will be considered as exact matches for keying color"); - - uiDefButF(block, NUMSLI, B_NODE_EXEC, "Lift ", - butr->xmin, butr->ymin+20, dx, 20, - &c->fsize, 0.0f, 1.0f, 100, 0, "Alpha Lift"); - uiDefButF(block, NUMSLI, B_NODE_EXEC, "Gain ", - butr->xmin+dx, butr->ymin+20, dx, 20, - &c->fstrength, 0.0f, 1.0f, 100, 0, "Alpha Gain"); - - uiDefButF(block, NUMSLI, B_NODE_EXEC, "Shadow Adjust ", - butr->xmin, butr->ymin, butr->xmax-butr->xmin, 20, - &c->t3, 0.0f, 1.0f, 100, 0, "Adjusts the brightness of any shadows captured"); - uiBlockEndAlign(block); - - if(c->t2 > c->t1) - c->t2=c->t1; + uiLayout *col; + + col= uiLayoutColumn(layout, 0); + uiItemR(col, NULL, 0, ptr, "acceptance", 0); + uiItemR(col, NULL, 0, ptr, "cutoff", 0); + + col= uiLayoutColumn(layout, 1); + uiItemR(col, NULL, 0, ptr, "lift", UI_ITEM_R_SLIDER); + uiItemR(col, NULL, 0, ptr, "gain", UI_ITEM_R_SLIDER); + uiItemR(col, NULL, 0, ptr, "shadow_adjust", UI_ITEM_R_SLIDER); + +// uiBlock *block= uiLayoutFreeBlock(layout); +// bNode *node= ptr->data; +// rctf *butr= &node->butr; +// short dx=(butr->xmax-butr->xmin)/2; +// NodeChroma *c= node->storage; + +// uiBlockBeginAlign(block); +// +// uiDefButF(block, NUMSLI, B_NODE_EXEC, "Acceptance ", butr->xmin, butr->ymin+60, butr->xmax-butr->xmin, 20, &c->t1, 1.0f, 80.0f, 100, 0, "Tolerance for colors to be considered a keying color"); +// uiDefButF(block, NUMSLI, B_NODE_EXEC, "Cutoff ", butr->xmin, butr->ymin+40, butr->xmax-butr->xmin, 20, &c->t2, 0.0f, 30.0f, 100, 0, "Colors below this will be considered as exact matches for keying color"); +// +// uiDefButF(block, NUMSLI, B_NODE_EXEC, "Lift ", butr->xmin, butr->ymin+20, dx, 20, &c->fsize, 0.0f, 1.0f, 100, 0, "Alpha Lift"); +// uiDefButF(block, NUMSLI, B_NODE_EXEC, "Gain ", butr->xmin+dx, butr->ymin+20, dx, 20, &c->fstrength, 0.0f, 1.0f, 100, 0, "Alpha Gain"); +// +// uiDefButF(block, NUMSLI, B_NODE_EXEC, "Shadow Adjust ", butr->xmin, butr->ymin, butr->xmax-butr->xmin, 20, &c->t3, 0.0f, 1.0f, 100, 0, "Adjusts the brightness of any shadows captured"); +// uiBlockEndAlign(block); +// +// if(c->t2 > c->t1) +// c->t2=c->t1; } static void node_composit_buts_color_matte(uiLayout *layout, PointerRNA *ptr) { - uiBlock *block= uiLayoutFreeBlock(layout); - bNode *node= ptr->data; - rctf *butr= &node->butr; - NodeChroma *c= node->storage; - uiBlockBeginAlign(block); - - uiDefButF(block, NUMSLI, B_NODE_EXEC+node->nr, "H: ", - butr->xmin, butr->ymin+40, butr->xmax-butr->xmin, 20, - &c->t1, 0.0f, 0.25f, 100, 0, "Hue tolerance for colors to be considered a keying color"); - uiDefButF(block, NUMSLI, B_NODE_EXEC+node->nr, "S: ", - butr->xmin, butr->ymin+20, butr->xmax-butr->xmin, 20, - &c->t2, 0.0f, 1.0f, 100, 0, "Saturation Tolerance for the color"); - uiDefButF(block, NUMSLI, B_NODE_EXEC+node->nr, "V: ", - butr->xmin, butr->ymin, butr->xmax-butr->xmin, 20, - &c->t3, 0.0f, 1.0f, 100, 0, "Value Tolerance for the color"); - - uiBlockEndAlign(block); + uiLayout *col; + + col= uiLayoutColumn(layout, 1); + uiItemR(col, NULL, 0, ptr, "h", UI_ITEM_R_SLIDER); + uiItemR(col, NULL, 0, ptr, "s", UI_ITEM_R_SLIDER); + uiItemR(col, NULL, 0, ptr, "v", UI_ITEM_R_SLIDER); } static void node_composit_buts_channel_matte(uiLayout *layout, PointerRNA *ptr) @@ -1874,56 +1636,23 @@ static void node_composit_buts_scale(uiLayout *layout, PointerRNA *ptr) static void node_composit_buts_invert(uiLayout *layout, PointerRNA *ptr) { - uiBlock *block= uiLayoutFreeBlock(layout); - bNode *node= ptr->data; - rctf *butr= &node->butr; - - uiBlockBeginAlign(block); - uiDefButBitS(block, TOG, CMP_CHAN_RGB, B_NODE_EXEC, "RGB", - butr->xmin, butr->ymin, (butr->xmax-butr->xmin)/2, 20, - &node->custom1, 0, 0, 0, 0, ""); - uiDefButBitS(block, TOG, CMP_CHAN_A, B_NODE_EXEC, "A", - butr->xmin+(butr->xmax-butr->xmin)/2, butr->ymin, (butr->xmax-butr->xmin)/2, 20, - &node->custom1, 0, 0, 0, 0, ""); - uiBlockEndAlign(block); + uiLayout *col; + + col= uiLayoutColumn(layout, 0); + uiItemR(col, NULL, 0, ptr, "rgb", 0); + uiItemR(col, NULL, 0, ptr, "alpha", 0); } static void node_composit_buts_premulkey(uiLayout *layout, PointerRNA *ptr) { - uiBlock *block= uiLayoutFreeBlock(layout); - bNode *node= ptr->data; - rctf *butr= &node->butr; - uiBut *bt; - - /* blend type */ - bt=uiDefButS(block, MENU, B_NODE_EXEC, "Key to Premul %x0|Premul to Key %x1", - butr->xmin, butr->ymin, butr->xmax-butr->xmin, 20, - &node->custom1, 0, 0, 0, 0, "Conversion between premultiplied alpha and key alpha"); + uiItemR(layout, "", 0, ptr, "mapping", 0); } static void node_composit_buts_view_levels(uiLayout *layout, PointerRNA *ptr) { - uiBlock *block= uiLayoutFreeBlock(layout); - bNode *node= ptr->data; - rctf *butr= &node->butr; - short sx= (butr->xmax-butr->xmin)/5; - - /*color space selectors*/ - uiBlockBeginAlign(block); - uiDefButS(block, ROW,B_NODE_EXEC+node->nr,"C", - butr->xmin,butr->ymin,sx,20,&node->custom1,1,1, 0, 0, "Combined RGB"); - uiDefButS(block, ROW,B_NODE_EXEC+node->nr,"R", - butr->xmin+sx,butr->ymin,sx,20,&node->custom1,1,2, 0, 0, "Red Channel"); - uiDefButS(block, ROW,B_NODE_EXEC+node->nr,"G", - butr->xmin+2*sx,butr->ymin,sx,20,&node->custom1,1,3, 0, 0, "Green Channel"); - uiDefButS(block, ROW,B_NODE_EXEC+node->nr,"B", - butr->xmin+3*sx,butr->ymin,sx,20,&node->custom1,1,4, 0, 0, "Blue Channel"); - uiDefButS(block, ROW,B_NODE_EXEC+node->nr,"L", - butr->xmin+4*sx,butr->ymin,sx,20,&node->custom1,1,5, 0, 0, "Luminenc Channel"); - uiBlockEndAlign(block); + uiItemR(layout, NULL, 0, ptr, "color_space", UI_ITEM_R_EXPAND); } - /* only once called */ static void node_composit_set_butfunc(bNodeType *ntype) { diff --git a/source/blender/editors/space_node/node_draw.c b/source/blender/editors/space_node/node_draw.c index a87a141972b..1d57f4e0d4c 100644 --- a/source/blender/editors/space_node/node_draw.c +++ b/source/blender/editors/space_node/node_draw.c @@ -567,6 +567,7 @@ static uiBlock *socket_vector_menu(bContext *C, ARegion *ar, void *socket_v) } block= uiBeginBlock(C, ar, "socket menu", UI_EMBOSS); + uiBlockSetFlag(block, UI_BLOCK_KEEP_OPEN); /* use this for a fake extra empy space around the buttons */ uiDefBut(block, LABEL, 0, "", -4, -4, 188, 68, NULL, 0, 0, 0, 0, ""); diff --git a/source/blender/editors/space_node/node_select.c b/source/blender/editors/space_node/node_select.c index 94691dd0ed2..5e482758c9d 100644 --- a/source/blender/editors/space_node/node_select.c +++ b/source/blender/editors/space_node/node_select.c @@ -140,7 +140,7 @@ static int node_select_modal(bContext *C, wmOperator *op, wmEvent *event) printf("%d %d\n", event->x, event->y); break; case SELECTMOUSE: - //if (event->val==0) { + //if (event->val==KM_RELEASE) { /* calculate overall delta mouse-movement for redo */ printf("done translating\n"); //WM_cursor_restore(CTX_wm_window(C)); diff --git a/source/blender/editors/space_outliner/outliner.c b/source/blender/editors/space_outliner/outliner.c index a3b47d505fd..a1fdbab9ccc 100644 --- a/source/blender/editors/space_outliner/outliner.c +++ b/source/blender/editors/space_outliner/outliner.c @@ -5049,6 +5049,8 @@ static char *keymap_mouse_menu(void) str += sprintf(str, formatstr, "Left Mouse", LEFTMOUSE); str += sprintf(str, formatstr, "Middle Mouse", MIDDLEMOUSE); str += sprintf(str, formatstr, "Right Mouse", RIGHTMOUSE); + str += sprintf(str, formatstr, "Button4 Mouse ", BUTTON4MOUSE); + str += sprintf(str, formatstr, "Button5 Mouse ", BUTTON5MOUSE); str += sprintf(str, formatstr, "Action Mouse", ACTIONMOUSE); str += sprintf(str, formatstr, "Select Mouse", SELECTMOUSE); str += sprintf(str, formatstr, "Mouse Move", MOUSEMOVE); @@ -5071,6 +5073,8 @@ static char *keymap_tweak_menu(void) str += sprintf(str, formatstr, "Left Mouse", EVT_TWEAK_L); str += sprintf(str, formatstr, "Middle Mouse", EVT_TWEAK_M); str += sprintf(str, formatstr, "Right Mouse", EVT_TWEAK_R); + str += sprintf(str, formatstr, "Button4 Mouse ", BUTTON4MOUSE); + str += sprintf(str, formatstr, "Button5 Mouse ", BUTTON5MOUSE); str += sprintf(str, formatstr, "Action Mouse", EVT_TWEAK_A); str += sprintf(str, formatstr, "Select Mouse", EVT_TWEAK_S); diff --git a/source/blender/editors/space_text/text_draw.c b/source/blender/editors/space_text/text_draw.c index 9721fbc2b9c..5996770c206 100644 --- a/source/blender/editors/space_text/text_draw.c +++ b/source/blender/editors/space_text/text_draw.c @@ -425,60 +425,6 @@ static void format_draw_color(char formatchar) } } -/*********************** utilities ************************/ - -int text_check_bracket(char ch) -{ - int a; - char opens[] = "([{"; - char close[] = ")]}"; - - for(a=0; a<3; a++) { - if(ch==opens[a]) - return a+1; - else if(ch==close[a]) - return -(a+1); - } - return 0; -} - -int text_check_delim(char ch) -{ - int a; - char delims[] = "():\"\' ~!%^&*-+=[]{};/<>|.#\t,"; - - for(a=0; a<28; a++) { - if(ch==delims[a]) - return 1; - } - return 0; -} - -int text_check_digit(char ch) -{ - if(ch < '0') return 0; - if(ch <= '9') return 1; - return 0; -} - -int text_check_identifier(char ch) -{ - if(ch < '0') return 0; - if(ch <= '9') return 1; - if(ch < 'A') return 0; - if(ch <= 'Z' || ch == '_') return 1; - if(ch < 'a') return 0; - if(ch <= 'z') return 1; - return 0; -} - -int text_check_whitespace(char ch) -{ - if(ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n') - return 1; - return 0; -} - /************************** draw text *****************************/ /***********************/ /* diff --git a/source/blender/editors/space_view3d/Makefile b/source/blender/editors/space_view3d/Makefile index 07102157854..9204f2482c6 100644 --- a/source/blender/editors/space_view3d/Makefile +++ b/source/blender/editors/space_view3d/Makefile @@ -53,6 +53,9 @@ CPPFLAGS += -I../../render/extern/include CPPFLAGS += -I../../blenfont CPPFLAGS += -I$(NAN_GUARDEDALLOC)/include CPPFLAGS += -I$(NAN_SMOKE)/include -# own include +ifneq ($(NAN_NO_KETSJI),true) + CPPFLAGS += -I../../../kernel/gen_system +endif +# own include CPPFLAGS += -I../include diff --git a/source/blender/editors/space_view3d/drawarmature.c b/source/blender/editors/space_view3d/drawarmature.c index fa810677fe8..028d666dc71 100644 --- a/source/blender/editors/space_view3d/drawarmature.c +++ b/source/blender/editors/space_view3d/drawarmature.c @@ -639,7 +639,7 @@ static void draw_sphere_bone_dist(float smat[][4], float imat[][4], int boneflag /* figure out the sizes of spheres */ if (ebone) { - /* this routine doesn't call set_matrix_editbone() that calculates it */ + /* this routine doesn't call get_matrix_editbone() that calculates it */ ebone->length = VecLenf(ebone->head, ebone->tail); length= ebone->length; @@ -749,7 +749,7 @@ static void draw_sphere_bone_wire(float smat[][4], float imat[][4], int armflag, /* figure out the sizes of spheres */ if (ebone) { - /* this routine doesn't call set_matrix_editbone() that calculates it */ + /* this routine doesn't call get_matrix_editbone() that calculates it */ ebone->length = VecLenf(ebone->head, ebone->tail); length= ebone->length; @@ -1516,15 +1516,25 @@ static void draw_pose_dofs(Object *ob) } } +static void bone_matrix_translate_y(float mat[][4], float y) +{ + float trans[3]; + + VECCOPY(trans, mat[1]); + VecMulf(trans, y); + VecAddf(mat[3], mat[3], trans); +} + /* assumes object is Armature with pose */ -static void draw_pose_channels(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base, int dt) +static void draw_pose_channels(Scene *scene, View3D *v3d, ARegion *ar, Base *base, int dt) { + RegionView3D *rv3d= ar->regiondata; Object *ob= base->object; bArmature *arm= ob->data; bPoseChannel *pchan; Bone *bone; GLfloat tmp; - float smat[4][4], imat[4][4]; + float smat[4][4], imat[4][4], bmat[4][4]; int index= -1; short do_dashed= 3, draw_wire= 0; short flag, constflag; @@ -1809,15 +1819,21 @@ static void draw_pose_channels(Scene *scene, View3D *v3d, RegionView3D *rv3d, Ba /* Draw names of bone */ if (arm->flag & ARM_DRAWNAMES) { VecMidf(vec, pchan->pose_head, pchan->pose_tail); - view3d_object_text_draw_add(vec[0], vec[1], vec[2], pchan->name, 10); + view3d_cached_text_draw_add(vec[0], vec[1], vec[2], pchan->name, 10); } /* Draw additional axes on the bone tail */ if ( (arm->flag & ARM_DRAWAXES) && (arm->flag & ARM_POSEMODE) ) { glPushMatrix(); - glMultMatrixf(pchan->pose_mat); - glTranslatef(0.0f, pchan->bone->length, 0.0f); - drawaxes(0.25f*pchan->bone->length, 0, OB_ARROWS); + Mat4CpyMat4(bmat, pchan->pose_mat); + bone_matrix_translate_y(bmat, pchan->bone->length); + glMultMatrixf(bmat); + + /* do cached text draw immediate to include transform */ + view3d_cached_text_draw_begin(); + drawaxes(pchan->bone->length*0.25f, 0, OB_ARROWS); + view3d_cached_text_draw_end(v3d, ar, 1, bmat); + glPopMatrix(); } } @@ -1830,32 +1846,28 @@ static void draw_pose_channels(Scene *scene, View3D *v3d, RegionView3D *rv3d, Ba } /* in editmode, we don't store the bone matrix... */ -static void set_matrix_editbone(EditBone *eBone) +static void get_matrix_editbone(EditBone *eBone, float bmat[][4]) { - float delta[3],offset[3]; - float mat[3][3], bmat[4][4]; + float delta[3]; + float mat[3][3]; /* Compose the parent transforms (i.e. their translations) */ - VECCOPY(offset, eBone->head); - - glTranslatef(offset[0],offset[1],offset[2]); - VecSubf(delta, eBone->tail, eBone->head); eBone->length = (float)sqrt(delta[0]*delta[0] + delta[1]*delta[1] +delta[2]*delta[2]); vec_roll_to_mat3(delta, eBone->roll, mat); Mat4CpyMat3(bmat, mat); - - glMultMatrixf(bmat); - + + VecAddf(bmat[3], bmat[3], eBone->head); } -static void draw_ebones(View3D *v3d, RegionView3D *rv3d, Object *ob, int dt) +static void draw_ebones(View3D *v3d, ARegion *ar, Object *ob, int dt) { + RegionView3D *rv3d= ar->regiondata; EditBone *eBone; bArmature *arm= ob->data; - float smat[4][4], imat[4][4]; + float smat[4][4], imat[4][4], bmat[4][4]; unsigned int index; int flag; @@ -1893,7 +1905,8 @@ static void draw_ebones(View3D *v3d, RegionView3D *rv3d, Object *ob, int dt) if (eBone->layer & arm->layer) { if ((eBone->flag & BONE_HIDDEN_A)==0) { glPushMatrix(); - set_matrix_editbone(eBone); + get_matrix_editbone(eBone, bmat); + glMultMatrixf(bmat); /* catch exception for bone with hidden parent */ flag= eBone->flag; @@ -1941,7 +1954,8 @@ static void draw_ebones(View3D *v3d, RegionView3D *rv3d, Object *ob, int dt) } else { glPushMatrix(); - set_matrix_editbone(eBone); + get_matrix_editbone(eBone, bmat); + glMultMatrixf(bmat); if (arm->drawtype == ARM_LINE) draw_line_bone(arm->flag, flag, 0, index, NULL, eBone); @@ -1994,14 +2008,20 @@ static void draw_ebones(View3D *v3d, RegionView3D *rv3d, Object *ob, int dt) if (arm->flag & ARM_DRAWNAMES) { VecMidf(vec, eBone->head, eBone->tail); glRasterPos3fv(vec); - view3d_object_text_draw_add(vec[0], vec[1], vec[2], eBone->name, 10); + view3d_cached_text_draw_add(vec[0], vec[1], vec[2], eBone->name, 10); } /* Draw additional axes */ if (arm->flag & ARM_DRAWAXES) { glPushMatrix(); - set_matrix_editbone(eBone); - glTranslatef(0.0f, eBone->length, 0.0f); + get_matrix_editbone(eBone, bmat); + bone_matrix_translate_y(bmat, eBone->length); + glMultMatrixf(bmat); + + /* do cached text draw immediate to include transform */ + view3d_cached_text_draw_begin(); drawaxes(eBone->length*0.25f, 0, OB_ARROWS); + view3d_cached_text_draw_end(v3d, ar, 1, bmat); + glPopMatrix(); } @@ -2021,8 +2041,9 @@ static void draw_ebones(View3D *v3d, RegionView3D *rv3d, Object *ob, int dt) /* draw bone paths * - in view space */ -static void draw_pose_paths(Scene *scene, View3D *v3d, RegionView3D *rv3d, Object *ob) +static void draw_pose_paths(Scene *scene, View3D *v3d, ARegion *ar, Object *ob) { + RegionView3D *rv3d= ar->regiondata; AnimData *adt= BKE_animdata_from_id(&ob->id); bArmature *arm= ob->data; bPoseChannel *pchan; @@ -2155,12 +2176,12 @@ static void draw_pose_paths(Scene *scene, View3D *v3d, RegionView3D *rv3d, Objec /* only draw framenum if several consecutive highlighted points don't occur on same point */ if (a == 0) { sprintf(str, "%d", (a+sfra)); - view3d_object_text_draw_add(fp[0], fp[1], fp[2], str, 0); + view3d_cached_text_draw_add(fp[0], fp[1], fp[2], str, 0); } else if ((a > stepsize) && (a < len-stepsize)) { if ((VecEqual(fp, fp-(stepsize*3))==0) || (VecEqual(fp, fp+(stepsize*3))==0)) { sprintf(str, "%d", (a+sfra)); - view3d_object_text_draw_add(fp[0], fp[1], fp[2], str, 0); + view3d_cached_text_draw_add(fp[0], fp[1], fp[2], str, 0); } } } @@ -2202,7 +2223,7 @@ static void draw_pose_paths(Scene *scene, View3D *v3d, RegionView3D *rv3d, Objec char str[32]; sprintf(str, "%d", (a+sfra)); - view3d_object_text_draw_add(fp[0], fp[1], fp[2], str, 0); + view3d_cached_text_draw_add(fp[0], fp[1], fp[2], str, 0); } } } @@ -2253,7 +2274,7 @@ static void ghost_poses_tag_unselected(Object *ob, short unset) /* draw ghosts that occur within a frame range * note: object should be in posemode */ -static void draw_ghost_poses_range(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base) +static void draw_ghost_poses_range(Scene *scene, View3D *v3d, ARegion *ar, Base *base) { Object *ob= base->object; AnimData *adt= BKE_animdata_from_id(&ob->id); @@ -2295,7 +2316,7 @@ static void draw_ghost_poses_range(Scene *scene, View3D *v3d, RegionView3D *rv3d BKE_animsys_evaluate_animdata(&ob->id, adt, (float)CFRA, ADT_RECALC_ALL); where_is_pose(scene, ob); - draw_pose_channels(scene, v3d, rv3d, base, OB_WIRE); + draw_pose_channels(scene, v3d, ar, base, OB_WIRE); } glDisable(GL_BLEND); if (v3d->zbuf) glEnable(GL_DEPTH_TEST); @@ -2315,7 +2336,7 @@ static void draw_ghost_poses_range(Scene *scene, View3D *v3d, RegionView3D *rv3d /* draw ghosts on keyframes in action within range * - object should be in posemode */ -static void draw_ghost_poses_keys(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base) +static void draw_ghost_poses_keys(Scene *scene, View3D *v3d, ARegion *ar, Base *base) { Object *ob= base->object; AnimData *adt= BKE_animdata_from_id(&ob->id); @@ -2374,7 +2395,7 @@ static void draw_ghost_poses_keys(Scene *scene, View3D *v3d, RegionView3D *rv3d, BKE_animsys_evaluate_animdata(&ob->id, adt, (float)CFRA, ADT_RECALC_ALL); where_is_pose(scene, ob); - draw_pose_channels(scene, v3d, rv3d, base, OB_WIRE); + draw_pose_channels(scene, v3d, ar, base, OB_WIRE); } glDisable(GL_BLEND); if (v3d->zbuf) glEnable(GL_DEPTH_TEST); @@ -2394,7 +2415,7 @@ static void draw_ghost_poses_keys(Scene *scene, View3D *v3d, RegionView3D *rv3d, /* draw ghosts around current frame * - object is supposed to be armature in posemode */ -static void draw_ghost_poses(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base) +static void draw_ghost_poses(Scene *scene, View3D *v3d, ARegion *ar, Base *base) { Object *ob= base->object; AnimData *adt= BKE_animdata_from_id(&ob->id); @@ -2444,7 +2465,7 @@ static void draw_ghost_poses(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base if (CFRA != cfrao) { BKE_animsys_evaluate_animdata(&ob->id, adt, (float)CFRA, ADT_RECALC_ALL); where_is_pose(scene, ob); - draw_pose_channels(scene, v3d, rv3d, base, OB_WIRE); + draw_pose_channels(scene, v3d, ar, base, OB_WIRE); } } @@ -2459,7 +2480,7 @@ static void draw_ghost_poses(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base if (CFRA != cfrao) { BKE_animsys_evaluate_animdata(&ob->id, adt, (float)CFRA, ADT_RECALC_ALL); where_is_pose(scene, ob); - draw_pose_channels(scene, v3d, rv3d, base, OB_WIRE); + draw_pose_channels(scene, v3d, ar, base, OB_WIRE); } } } @@ -2480,7 +2501,7 @@ static void draw_ghost_poses(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base /* ********************************** Armature Drawing - Main ************************* */ /* called from drawobject.c, return 1 if nothing was drawn */ -int draw_armature(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base, int dt, int flag) +int draw_armature(Scene *scene, View3D *v3d, ARegion *ar, Base *base, int dt, int flag) { Object *ob= base->object; bArmature *arm= ob->data; @@ -2504,7 +2525,7 @@ int draw_armature(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base, int /* editmode? */ if(arm->edbo) { arm->flag |= ARM_EDITMODE; - draw_ebones(v3d, rv3d, ob, dt); + draw_ebones(v3d, ar, ob, dt); arm->flag &= ~ARM_EDITMODE; } else{ @@ -2513,32 +2534,36 @@ int draw_armature(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base, int /* drawing posemode selection indices or colors only in these cases */ if(!(base->flag & OB_FROMDUPLI)) { if(G.f & G_PICKSEL) { - if(ob->mode & OB_MODE_POSE) + if(OBACT && (OBACT->mode & OB_MODE_WEIGHT_PAINT)) { + if(ob==modifiers_isDeformedByArmature(OBACT)) + arm->flag |= ARM_POSEMODE; + } + else if(ob->mode & OB_MODE_POSE) arm->flag |= ARM_POSEMODE; } else if(ob->mode & OB_MODE_POSE) { if (arm->ghosttype == ARM_GHOST_RANGE) { - draw_ghost_poses_range(scene, v3d, rv3d, base); + draw_ghost_poses_range(scene, v3d, ar, base); } else if (arm->ghosttype == ARM_GHOST_KEYS) { - draw_ghost_poses_keys(scene, v3d, rv3d, base); + draw_ghost_poses_keys(scene, v3d, ar, base); } else if (arm->ghosttype == ARM_GHOST_CUR) { if (arm->ghostep) - draw_ghost_poses(scene, v3d, rv3d, base); + draw_ghost_poses(scene, v3d, ar, base); } if ((flag & DRAW_SCENESET)==0) { if(ob==OBACT) arm->flag |= ARM_POSEMODE; - else if(ob->mode & OB_MODE_WEIGHT_PAINT) { - if(OBACT && ob==modifiers_isDeformedByArmature(OBACT)) + else if(OBACT && (OBACT->mode & OB_MODE_WEIGHT_PAINT)) { + if(ob==modifiers_isDeformedByArmature(OBACT)) arm->flag |= ARM_POSEMODE; } - draw_pose_paths(scene, v3d, rv3d, ob); + draw_pose_paths(scene, v3d, ar, ob); } } } - draw_pose_channels(scene, v3d, rv3d, base, dt); + draw_pose_channels(scene, v3d, ar, base, dt); arm->flag &= ~ARM_POSEMODE; if(ob->mode & OB_MODE_POSE) diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c index b8852486dea..60ae91e7a89 100644 --- a/source/blender/editors/space_view3d/drawobject.c +++ b/source/blender/editors/space_view3d/drawobject.c @@ -434,11 +434,11 @@ void drawaxes(float size, int flag, char drawtype) // patch for 3d cards crashing on glSelect for text drawing (IBM) if((flag & DRAW_PICKING) == 0) { if (axis==0) - view3d_object_text_draw_add(v2[0], v2[1], v2[2], "x", 0); + view3d_cached_text_draw_add(v2[0], v2[1], v2[2], "x", 0); else if (axis==1) - view3d_object_text_draw_add(v2[0], v2[1], v2[2], "y", 0); + view3d_cached_text_draw_add(v2[0], v2[1], v2[2], "y", 0); else - view3d_object_text_draw_add(v2[0], v2[1], v2[2], "z", 0); + view3d_cached_text_draw_add(v2[0], v2[1], v2[2], "z", 0); } } break; @@ -496,23 +496,32 @@ static void drawcentercircle(View3D *v3d, RegionView3D *rv3d, float *vec, int se if(v3d->zbuf) glDepthFunc(GL_LEQUAL); } -/* *********** text drawing for object ************* */ -static ListBase strings= {NULL, NULL}; +/* *********** text drawing for object/particles/armature ************* */ -typedef struct ViewObjectString { - struct ViewObjectString *next, *prev; +static ListBase CachedText[3]; +static int CachedTextLevel= 0; + +typedef struct ViewCachedString { + struct ViewCachedString *next, *prev; float vec[3], col[4]; char str[128]; short mval[2]; short xoffs; -} ViewObjectString; +} ViewCachedString; +void view3d_cached_text_draw_begin() +{ + ListBase *strings= &CachedText[CachedTextLevel]; + strings->first= strings->last= NULL; + CachedTextLevel++; +} -void view3d_object_text_draw_add(float x, float y, float z, char *str, short xoffs) +void view3d_cached_text_draw_add(float x, float y, float z, char *str, short xoffs) { - ViewObjectString *vos= MEM_callocN(sizeof(ViewObjectString), "ViewObjectString"); + ListBase *strings= &CachedText[CachedTextLevel-1]; + ViewCachedString *vos= MEM_callocN(sizeof(ViewCachedString), "ViewCachedString"); - BLI_addtail(&strings, vos); + BLI_addtail(strings, vos); BLI_strncpy(vos->str, str, 128); vos->vec[0]= x; vos->vec[1]= y; @@ -521,22 +530,23 @@ void view3d_object_text_draw_add(float x, float y, float z, char *str, short xof vos->xoffs= xoffs; } -static void view3d_object_text_draw(View3D *v3d, ARegion *ar) +void view3d_cached_text_draw_end(View3D *v3d, ARegion *ar, int depth_write, float mat[][4]) { - ViewObjectString *vos; - int tot= 0; + RegionView3D *rv3d= ar->regiondata; + ListBase *strings= &CachedText[CachedTextLevel-1]; + ViewCachedString *vos; + int a, tot= 0; /* project first and test */ - for(vos= strings.first; vos; vos= vos->next) { + for(vos= strings->first; vos; vos= vos->next) { + if(mat) + Mat4MulVecfl(mat, vos->vec); view3d_project_short_clip(ar, vos->vec, vos->mval); if(vos->mval[0]!=IS_CLIPPED) tot++; } - + if(tot) { - RegionView3D *rv3d= ar->regiondata; - int a; - if(rv3d->rflag & RV3D_CLIPPING) for(a=0; a<6; a++) glDisable(GL_CLIP_PLANE0+a); @@ -544,16 +554,22 @@ static void view3d_object_text_draw(View3D *v3d, ARegion *ar) wmPushMatrix(); ED_region_pixelspace(ar); - if(v3d->zbuf) glDisable(GL_DEPTH_TEST); + if(depth_write) { + if(v3d->zbuf) glDisable(GL_DEPTH_TEST); + } + else glDepthMask(0); - for(vos= strings.first; vos; vos= vos->next) { + for(vos= strings->first; vos; vos= vos->next) { if(vos->mval[0]!=IS_CLIPPED) { glColor3fv(vos->col); - BLF_draw_default((float)vos->mval[0]+vos->xoffs, (float)vos->mval[1], 0.0, vos->str); + BLF_draw_default((float)vos->mval[0]+vos->xoffs, (float)vos->mval[1], (depth_write)? 0.0f: 2.0f, vos->str); } } - if(v3d->zbuf) glEnable(GL_DEPTH_TEST); + if(depth_write) { + if(v3d->zbuf) glEnable(GL_DEPTH_TEST); + } + else glDepthMask(1); wmPopMatrix(); @@ -562,10 +578,14 @@ static void view3d_object_text_draw(View3D *v3d, ARegion *ar) glEnable(GL_CLIP_PLANE0+a); } - if(strings.first) - BLI_freelistN(&strings); + if(strings->first) + BLI_freelistN(strings); + + CachedTextLevel--; } +/* ******************** primitive drawing ******************* */ + static void drawcube(void) { @@ -1912,7 +1932,7 @@ static void draw_em_measure_stats(View3D *v3d, RegionView3D *rv3d, Object *ob, E else sprintf(val, conv_float, VecLenf(v1, v2)); - view3d_object_text_draw_add(x, y, z, val, 0); + view3d_cached_text_draw_add(x, y, z, val, 0); } } } @@ -1951,7 +1971,7 @@ static void draw_em_measure_stats(View3D *v3d, RegionView3D *rv3d, Object *ob, E else sprintf(val, conv_float, area); - view3d_object_text_draw_add(efa->cent[0], efa->cent[1], efa->cent[2], val, 0); + view3d_cached_text_draw_add(efa->cent[0], efa->cent[1], efa->cent[2], val, 0); } } } @@ -1993,13 +2013,13 @@ static void draw_em_measure_stats(View3D *v3d, RegionView3D *rv3d, Object *ob, E /* Vec 1 */ sprintf(val,"%.3f", RAD2DEG(VecAngle3(v4, v1, v2))); VecLerpf(fvec, efa->cent, efa->v1->co, 0.8f); - view3d_object_text_draw_add(efa->cent[0], efa->cent[1], efa->cent[2], val, 0); + view3d_cached_text_draw_add(efa->cent[0], efa->cent[1], efa->cent[2], val, 0); } if( (e1->f & e2->f & SELECT) || (G.moving && (efa->v2->f & SELECT)) ) { /* Vec 2 */ sprintf(val,"%.3f", RAD2DEG(VecAngle3(v1, v2, v3))); VecLerpf(fvec, efa->cent, efa->v2->co, 0.8f); - view3d_object_text_draw_add(fvec[0], fvec[1], fvec[2], val, 0); + view3d_cached_text_draw_add(fvec[0], fvec[1], fvec[2], val, 0); } if( (e2->f & e3->f & SELECT) || (G.moving && (efa->v3->f & SELECT)) ) { /* Vec 3 */ @@ -2008,14 +2028,14 @@ static void draw_em_measure_stats(View3D *v3d, RegionView3D *rv3d, Object *ob, E else sprintf(val,"%.3f", RAD2DEG(VecAngle3(v2, v3, v1))); VecLerpf(fvec, efa->cent, efa->v3->co, 0.8f); - view3d_object_text_draw_add(fvec[0], fvec[1], fvec[2], val, 0); + view3d_cached_text_draw_add(fvec[0], fvec[1], fvec[2], val, 0); } /* Vec 4 */ if(efa->v4) { if( (e3->f & e4->f & SELECT) || (G.moving && (efa->v4->f & SELECT)) ) { sprintf(val,"%.3f", RAD2DEG(VecAngle3(v3, v4, v1))); VecLerpf(fvec, efa->cent, efa->v4->co, 0.8f); - view3d_object_text_draw_add(fvec[0], fvec[1], fvec[2], val, 0); + view3d_cached_text_draw_add(fvec[0], fvec[1], fvec[2], val, 0); } } } @@ -2905,75 +2925,8 @@ static int drawDispList(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *bas return retval; } -/* *********** text drawing for particles ************* */ -static ListBase pstrings= {NULL, NULL}; - -typedef struct ViewParticleString { - struct ViewParticleString *next, *prev; - float vec[3], col[4]; - char str[128]; - short mval[2]; - short xoffs; -} ViewParticleString; - - -void view3d_particle_text_draw_add(float x, float y, float z, char *str, short xoffs) -{ - ViewObjectString *vos= MEM_callocN(sizeof(ViewObjectString), "ViewObjectString"); - - BLI_addtail(&pstrings, vos); - BLI_strncpy(vos->str, str, 128); - vos->vec[0]= x; - vos->vec[1]= y; - vos->vec[2]= z; - glGetFloatv(GL_CURRENT_COLOR, vos->col); - vos->xoffs= xoffs; -} - -static void view3d_particle_text_draw(View3D *v3d, ARegion *ar) -{ - ViewObjectString *vos; - int tot= 0; - - /* project first and test */ - for(vos= pstrings.first; vos; vos= vos->next) { - project_short(ar, vos->vec, vos->mval); - if(vos->mval[0]!=IS_CLIPPED) - tot++; - } - - if(tot) { - RegionView3D *rv3d= ar->regiondata; - int a; - - if(rv3d->rflag & RV3D_CLIPPING) - for(a=0; a<6; a++) - glDisable(GL_CLIP_PLANE0+a); - - wmPushMatrix(); - ED_region_pixelspace(ar); - - if(v3d->zbuf) glDepthMask(0); - - for(vos= pstrings.first; vos; vos= vos->next) { - if(vos->mval[0]!=IS_CLIPPED) { - glColor3fv(vos->col); - BLF_draw_default((float)vos->mval[0]+vos->xoffs, (float)vos->mval[1], 2.0, vos->str); - } - } - - if(v3d->zbuf) glDepthMask(1); - - wmPopMatrix(); +/* *********** drawing for particles ************* */ - if(rv3d->rflag & RV3D_CLIPPING) - for(a=0; a<6; a++) - glEnable(GL_CLIP_PLANE0+a); - } - - if(pstrings.first) - BLI_freelistN(&pstrings); -} static void draw_particle(ParticleKey *state, int draw_as, short draw, float pixsize, float imat[4][4], float *draw_line, ParticleBillboardData *bb, ParticleDrawData *pdd) { float vec[3], vec2[3]; @@ -3540,7 +3493,7 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv sprintf(val, "%s %.2f", val, pa_health); /* in path drawing state.co is the end point */ - view3d_particle_text_draw_add(state.co[0], state.co[1], state.co[2], val, 0); + view3d_cached_text_draw_add(state.co[0], state.co[1], state.co[2], val, 0); } } } @@ -4755,8 +4708,9 @@ static void drawtexspace(Object *ob) } /* draws wire outline */ -static void drawSolidSelect(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base) +static void drawSolidSelect(Scene *scene, View3D *v3d, ARegion *ar, Base *base) { + RegionView3D *rv3d= ar->regiondata; Object *ob= base->object; glLineWidth(2.0); @@ -4775,7 +4729,7 @@ static void drawSolidSelect(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base } else if(ob->type==OB_ARMATURE) { if(!(ob->mode & OB_MODE_POSE)) - draw_armature(scene, v3d, rv3d, base, OB_WIRE, 0); + draw_armature(scene, v3d, ar, base, OB_WIRE, 0); } glLineWidth(1.0); @@ -4885,11 +4839,11 @@ void drawRBpivot(bRigidBodyJointConstraint *data) glVertex3fv(v); glEnd(); if (axis==0) - view3d_object_text_draw_add(v[0], v[1], v[2], "px", 0); + view3d_cached_text_draw_add(v[0], v[1], v[2], "px", 0); else if (axis==1) - view3d_object_text_draw_add(v[0], v[1], v[2], "py", 0); + view3d_cached_text_draw_add(v[0], v[1], v[2], "py", 0); else - view3d_object_text_draw_add(v[0], v[1], v[2], "pz", 0); + view3d_cached_text_draw_add(v[0], v[1], v[2], "pz", 0); } glLineWidth (1.0f); setlinestyle(0); @@ -4932,6 +4886,9 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, int flag) } } + /* no return after this point, otherwise leaks */ + view3d_cached_text_draw_begin(); + /* draw keys? */ #if 0 // XXX old animation system if(base==(scene->basact) || (base->flag & (SELECT+BA_WAS_SEL))) { @@ -5116,7 +5073,7 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, int flag) if(dt>OB_WIRE && dt<OB_TEXTURE && ob!=scene->obedit && (flag && DRAW_SCENESET)==0) { if (!(ob->dtx&OB_DRAWWIRE) && (ob->flag&SELECT) && !(flag&DRAW_PICKING)) { - drawSolidSelect(scene, v3d, rv3d, base); + drawSolidSelect(scene, v3d, ar, base); } } } @@ -5262,7 +5219,7 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, int flag) break; case OB_ARMATURE: if(dt>OB_WIRE) GPU_enable_material(0, NULL); // we use default material - empty_object= draw_armature(scene, v3d, rv3d, base, dt, flag); + empty_object= draw_armature(scene, v3d, ar, base, dt, flag); if(dt>OB_WIRE) GPU_disable_material(); break; default: @@ -5282,10 +5239,12 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, int flag) wmLoadMatrix(rv3d->viewmat); + view3d_cached_text_draw_begin(); + for(psys=ob->particlesystem.first; psys; psys=psys->next) draw_new_particle_system(scene, v3d, rv3d, base, psys, dt); - view3d_particle_text_draw(v3d, ar); + view3d_cached_text_draw_end(v3d, ar, 0, NULL); wmMultMatrix(ob->obmat); @@ -5437,7 +5396,7 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, int flag) /* patch for several 3d cards (IBM mostly) that crash on glSelect with text drawing */ /* but, we also dont draw names for sets or duplicators */ if(flag == 0) { - view3d_object_text_draw_add(0.0f, 0.0f, 0.0f, ob->id.name+2, 10); + view3d_cached_text_draw_add(0.0f, 0.0f, 0.0f, ob->id.name+2, 10); } } /*if(dtx & OB_DRAWIMAGE) drawDispListwire(&ob->disp);*/ @@ -5460,7 +5419,7 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, int flag) } /* return warning, this is cached text draw */ - view3d_object_text_draw(v3d, ar); + view3d_cached_text_draw_end(v3d, ar, 1, NULL); wmLoadMatrix(rv3d->viewmat); diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c index 5ea633a47f7..6e415ec731d 100644 --- a/source/blender/editors/space_view3d/space_view3d.c +++ b/source/blender/editors/space_view3d/space_view3d.c @@ -259,7 +259,6 @@ static SpaceLink *view3d_duplicate(SpaceLink *sl) if(v3do->localvd) { v3do->localvd= NULL; v3do->properties_storage= NULL; - v3do->localview= 0; v3do->lay= v3dn->localvd->lay; v3do->lay &= 0xFFFFFF; } @@ -420,6 +419,7 @@ static void view3d_main_area_listener(ARegion *ar, wmNotifier *wmn) case ND_BONE_ACTIVE: case ND_BONE_SELECT: case ND_TRANSFORM: + case ND_POSE: case ND_DRAW: case ND_MODIFIER: case ND_CONSTRAINT: @@ -560,6 +560,7 @@ static void view3d_buttons_area_listener(ARegion *ar, wmNotifier *wmn) case ND_BONE_ACTIVE: case ND_BONE_SELECT: case ND_TRANSFORM: + case ND_POSE: case ND_DRAW: case ND_KEYS: ED_region_tag_redraw(ar); diff --git a/source/blender/editors/space_view3d/view3d_buttons.c b/source/blender/editors/space_view3d/view3d_buttons.c index 286b0ca0898..89d07fbbfea 100644 --- a/source/blender/editors/space_view3d/view3d_buttons.c +++ b/source/blender/editors/space_view3d/view3d_buttons.c @@ -512,6 +512,10 @@ static void v3d_posearmature_buts(uiBlock *block, View3D *v3d, Object *ob, float if(bone && (bone->flag & BONE_ACTIVE) && (bone->layer & arm->layer)) break; } + if (!pchan) { + uiDefBut(block, LABEL, 0, "No Bone Active", 0, 240, 100, 20, 0, 0, 0, 0, 0, ""); + return; + } if (pchan->rotmode == PCHAN_ROT_AXISANGLE) { float quat[4]; @@ -1447,25 +1451,12 @@ void view3d_buttons_register(ARegionType *art) pt->draw= view3d_panel_transform_spaces; BLI_addtail(&art->paneltypes, pt); - pt= MEM_callocN(sizeof(PanelType), "spacetype view3d panel gpencil"); - strcpy(pt->idname, "VIEW3D_PT_gpencil"); - strcpy(pt->label, "Greas Pencil"); - pt->draw= view3d_panel_gpencil; - BLI_addtail(&art->paneltypes, pt);*/ - pt= MEM_callocN(sizeof(PanelType), "spacetype view3d panel bonesketch spaces"); strcpy(pt->idname, "VIEW3D_PT_bonesketch_spaces"); strcpy(pt->label, "Bone Sketching"); pt->draw= view3d_panel_bonesketch_spaces; pt->poll= view3d_panel_bonesketch_spaces_poll; BLI_addtail(&art->paneltypes, pt); - - /* - pt= MEM_callocN(sizeof(PanelType), "spacetype view3d panel redo"); - strcpy(pt->idname, "VIEW3D_PT_redo"); - strcpy(pt->label, "Last Operator"); - pt->draw= view3d_panel_operator_redo; - BLI_addtail(&art->paneltypes, pt); */ // XXX view3d_panel_preview(C, ar, 0); } diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c index f8584b14e2b..5612e60e899 100644 --- a/source/blender/editors/space_view3d/view3d_draw.c +++ b/source/blender/editors/space_view3d/view3d_draw.c @@ -732,7 +732,7 @@ static void draw_viewport_name(ARegion *ar, View3D *v3d) char *name = view3d_get_name(v3d, rv3d); char *printable = NULL; - if (v3d->localview) { + if (v3d->localvd) { printable = malloc(strlen(name) + strlen(" (Local)_")); /* '_' gives space for '\0' */ strcpy(printable, name); strcat(printable, " (Local)"); @@ -745,7 +745,7 @@ static void draw_viewport_name(ARegion *ar, View3D *v3d) BLF_draw_default(22, ar->winy-17, 0.0f, printable); } - if (v3d->localview) { + if (v3d->localvd) { free(printable); } } diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c index 0faa1f8c16d..c07d9108993 100644 --- a/source/blender/editors/space_view3d/view3d_edit.c +++ b/source/blender/editors/space_view3d/view3d_edit.c @@ -239,9 +239,10 @@ typedef struct ViewOpsData { float ofs[3], obofs[3]; float reverse, dist0; float grid, far; + short axis_snap; /* view rotate only */ int origx, origy, oldx, oldy; - int origkey; + int origkey; /* the key that triggered the operator */ } ViewOpsData; @@ -289,7 +290,7 @@ static void viewops_data(bContext *C, wmOperator *op, wmEvent *event) QUATCOPY(vod->oldquat, rv3d->viewquat); vod->origx= vod->oldx= event->x; vod->origy= vod->oldy= event->y; - vod->origkey= event->type; + vod->origkey= event->type; /* the key that triggered the operator. */ /* lookup, we dont pass on v3d to prevent confusement */ vod->grid= v3d->grid; @@ -357,11 +358,52 @@ static float snapquats[39][6] = { {0.0, 0.0, 0.0, 1.0, 0, 0} }; +enum { + VIEW_PASS= 0, + VIEW_APPLY, + VIEW_CONFIRM +}; + +/* NOTE: these defines are saved in keymap files, do not change values but just add new ones */ +#define VIEW_MODAL_CONFIRM 1 /* used for all view operations */ +#define VIEWROT_MODAL_AXIS_SNAP_ENABLE 2 +#define VIEWROT_MODAL_AXIS_SNAP_DISABLE 3 + + +/* called in transform_ops.c, on each regeneration of keymaps */ +void viewrotate_modal_keymap(wmWindowManager *wm) +{ + static EnumPropertyItem modal_items[] = { + {VIEW_MODAL_CONFIRM, "CONFIRM", 0, "Cancel", ""}, + + {VIEWROT_MODAL_AXIS_SNAP_ENABLE, "AXIS_SNAP_ENABLE", 0, "Enable Axis Snap", ""}, + {VIEWROT_MODAL_AXIS_SNAP_DISABLE, "AXIS_SNAP_DISABLE", 0, "Enable Axis Snap", ""}, + + {0, NULL, 0, NULL, NULL}}; + + wmKeyMap *keymap= WM_modalkeymap_get(wm, "View3D Rotate Modal"); -static void viewrotate_apply(ViewOpsData *vod, int x, int y, int ctrl) + /* this function is called for each spacetype, only needs to add map once */ + if(keymap) return; + + keymap= WM_modalkeymap_add(wm, "View3D Rotate Modal", modal_items); + + /* items for modal map */ + WM_modalkeymap_add_item(keymap, MIDDLEMOUSE, KM_RELEASE, KM_ANY, 0, VIEW_MODAL_CONFIRM); + WM_modalkeymap_add_item(keymap, ESCKEY, KM_PRESS, KM_ANY, 0, VIEW_MODAL_CONFIRM); + + WM_modalkeymap_add_item(keymap, LEFTCTRLKEY, KM_PRESS, KM_ANY, 0, VIEWROT_MODAL_AXIS_SNAP_ENABLE); + WM_modalkeymap_add_item(keymap, LEFTCTRLKEY, KM_RELEASE, KM_ANY, 0, VIEWROT_MODAL_AXIS_SNAP_DISABLE); + + /* assign map to operators */ + WM_modalkeymap_assign(keymap, "VIEW3D_OT_rotate"); + +} + +static void viewrotate_apply(ViewOpsData *vod, int x, int y) { RegionView3D *rv3d= vod->rv3d; - int use_sel= 0; /* XXX */ + int use_sel= U.uiflag & USER_ORBIT_SELECTION; rv3d->view= 0; /* need to reset everytime because of view snapping */ @@ -462,7 +504,7 @@ static void viewrotate_apply(ViewOpsData *vod, int x, int y, int ctrl) } /* check for view snap */ - if (ctrl){ + if (vod->axis_snap){ int i; float viewmat[3][3]; @@ -496,23 +538,41 @@ static void viewrotate_apply(ViewOpsData *vod, int x, int y, int ctrl) static int viewrotate_modal(bContext *C, wmOperator *op, wmEvent *event) { ViewOpsData *vod= op->customdata; + short event_code= VIEW_PASS; /* execute the events */ - switch(event->type) { - case MOUSEMOVE: - viewrotate_apply(vod, event->x, event->y, event->ctrl); - break; + if(event->type==MOUSEMOVE) { + event_code= VIEW_APPLY; + } + else if(event->type==EVT_MODAL_MAP) { + switch (event->val) { + case VIEW_MODAL_CONFIRM: + event_code= VIEW_CONFIRM; + break; + case VIEWROT_MODAL_AXIS_SNAP_ENABLE: + vod->axis_snap= TRUE; + event_code= VIEW_APPLY; + break; + case VIEWROT_MODAL_AXIS_SNAP_DISABLE: + vod->axis_snap= FALSE; + event_code= VIEW_APPLY; + break; + } + } + else if(event->type==vod->origkey && event->val==KM_RELEASE) { + event_code= VIEW_CONFIRM; + } - default: - /* origkey may be zero when invoked from a button */ - if(ELEM3(event->type, ESCKEY, LEFTMOUSE, RIGHTMOUSE) || (event->type==vod->origkey && event->val==0)) { - request_depth_update(CTX_wm_region_view3d(C)); + if(event_code==VIEW_APPLY) { + viewrotate_apply(vod, event->x, event->y); + } + else if (event_code==VIEW_CONFIRM) { + request_depth_update(CTX_wm_region_view3d(C)); - MEM_freeN(vod); - op->customdata= NULL; + MEM_freeN(vod); + op->customdata= NULL; - return OPERATOR_FINISHED; - } + return OPERATOR_FINISHED; } return OPERATOR_RUNNING_MODAL; @@ -547,13 +607,13 @@ static int viewrotate_invoke(bContext *C, wmOperator *op, wmEvent *event) } -void VIEW3D_OT_viewrotate(wmOperatorType *ot) +void VIEW3D_OT_rotate(wmOperatorType *ot) { /* identifiers */ ot->name= "Rotate view"; ot->description = "Rotate the view."; - ot->idname= "VIEW3D_OT_viewrotate"; + ot->idname= "VIEW3D_OT_rotate"; /* api callbacks */ ot->invoke= viewrotate_invoke; @@ -566,6 +626,33 @@ void VIEW3D_OT_viewrotate(wmOperatorType *ot) /* ************************ viewmove ******************************** */ + +/* NOTE: these defines are saved in keymap files, do not change values but just add new ones */ + +/* called in transform_ops.c, on each regeneration of keymaps */ +void viewmove_modal_keymap(wmWindowManager *wm) +{ + static EnumPropertyItem modal_items[] = { + {VIEW_MODAL_CONFIRM, "CONFIRM", 0, "Confirm", ""}, + + {0, NULL, 0, NULL, NULL}}; + + wmKeyMap *keymap= WM_modalkeymap_get(wm, "View3D Move Modal"); + + /* this function is called for each spacetype, only needs to add map once */ + if(keymap) return; + + keymap= WM_modalkeymap_add(wm, "View3D Move Modal", modal_items); + + /* items for modal map */ + WM_modalkeymap_add_item(keymap, MIDDLEMOUSE, KM_RELEASE, KM_ANY, 0, VIEW_MODAL_CONFIRM); + WM_modalkeymap_add_item(keymap, ESCKEY, KM_PRESS, KM_ANY, 0, VIEW_MODAL_CONFIRM); + + /* assign map to operators */ + WM_modalkeymap_assign(keymap, "VIEW3D_OT_move"); +} + + static void viewmove_apply(ViewOpsData *vod, int x, int y) { if(vod->rv3d->persp==V3D_CAMOB) { @@ -596,24 +683,35 @@ static void viewmove_apply(ViewOpsData *vod, int x, int y) static int viewmove_modal(bContext *C, wmOperator *op, wmEvent *event) { + ViewOpsData *vod= op->customdata; + short event_code= VIEW_PASS; /* execute the events */ - switch(event->type) { - case MOUSEMOVE: - viewmove_apply(vod, event->x, event->y); - break; + if(event->type==MOUSEMOVE) { + event_code= VIEW_APPLY; + } + else if(event->type==EVT_MODAL_MAP) { + switch (event->val) { + case VIEW_MODAL_CONFIRM: + event_code= VIEW_CONFIRM; + break; + } + } + else if(event->type==vod->origkey && event->val==KM_RELEASE) { + event_code= VIEW_CONFIRM; + } - default: - /* origkey may be zero when invoked from a button */ - if(ELEM3(event->type, ESCKEY, LEFTMOUSE, RIGHTMOUSE) || (event->type==vod->origkey && event->val==0)) { - request_depth_update(CTX_wm_region_view3d(C)); + if(event_code==VIEW_APPLY) { + viewmove_apply(vod, event->x, event->y); + } + else if (event_code==VIEW_CONFIRM) { + request_depth_update(CTX_wm_region_view3d(C)); - MEM_freeN(vod); - op->customdata= NULL; + MEM_freeN(vod); + op->customdata= NULL; - return OPERATOR_FINISHED; - } + return OPERATOR_FINISHED; } return OPERATOR_RUNNING_MODAL; @@ -631,13 +729,13 @@ static int viewmove_invoke(bContext *C, wmOperator *op, wmEvent *event) } -void VIEW3D_OT_viewmove(wmOperatorType *ot) +void VIEW3D_OT_move(wmOperatorType *ot) { /* identifiers */ ot->name= "Move view"; ot->description = "Move the view."; - ot->idname= "VIEW3D_OT_viewmove"; + ot->idname= "VIEW3D_OT_move"; /* api callbacks */ ot->invoke= viewmove_invoke; @@ -650,6 +748,29 @@ void VIEW3D_OT_viewmove(wmOperatorType *ot) /* ************************ viewzoom ******************************** */ +/* called in transform_ops.c, on each regeneration of keymaps */ +void viewzoom_modal_keymap(wmWindowManager *wm) +{ + static EnumPropertyItem modal_items[] = { + {VIEW_MODAL_CONFIRM, "CONFIRM", 0, "Confirm", ""}, + + {0, NULL, 0, NULL, NULL}}; + + wmKeyMap *keymap= WM_modalkeymap_get(wm, "View3D Zoom Modal"); + + /* this function is called for each spacetype, only needs to add map once */ + if(keymap) return; + + keymap= WM_modalkeymap_add(wm, "View3D Zoom Modal", modal_items); + + /* items for modal map */ + WM_modalkeymap_add_item(keymap, MIDDLEMOUSE, KM_RELEASE, KM_ANY, 0, VIEW_MODAL_CONFIRM); + WM_modalkeymap_add_item(keymap, ESCKEY, KM_PRESS, KM_ANY, 0, VIEW_MODAL_CONFIRM); + + /* assign map to operators */ + WM_modalkeymap_assign(keymap, "VIEW3D_OT_zoom"); +} + static void view_zoom_mouseloc(ARegion *ar, float dfac, int mx, int my) { RegionView3D *rv3d= ar->regiondata; @@ -758,23 +879,33 @@ static void viewzoom_apply(ViewOpsData *vod, int x, int y) static int viewzoom_modal(bContext *C, wmOperator *op, wmEvent *event) { ViewOpsData *vod= op->customdata; + short event_code= VIEW_PASS; /* execute the events */ - switch(event->type) { - case MOUSEMOVE: - viewzoom_apply(vod, event->x, event->y); - break; + if(event->type==MOUSEMOVE) { + event_code= VIEW_APPLY; + } + else if(event->type==EVT_MODAL_MAP) { + switch (event->val) { + case VIEW_MODAL_CONFIRM: + event_code= VIEW_CONFIRM; + break; + } + } + else if(event->type==vod->origkey && event->val==KM_RELEASE) { + event_code= VIEW_CONFIRM; + } - default: - /* origkey may be zero when invoked from a button */ - if(ELEM3(event->type, ESCKEY, LEFTMOUSE, RIGHTMOUSE) || (event->type==vod->origkey && event->val==0)) { - request_depth_update(CTX_wm_region_view3d(C)); + if(event_code==VIEW_APPLY) { + viewzoom_apply(vod, event->x, event->y); + } + else if (event_code==VIEW_CONFIRM) { + request_depth_update(CTX_wm_region_view3d(C)); - MEM_freeN(vod); - op->customdata= NULL; + MEM_freeN(vod); + op->customdata= NULL; - return OPERATOR_FINISHED; - } + return OPERATOR_FINISHED; } return OPERATOR_RUNNING_MODAL; @@ -925,7 +1056,7 @@ static int viewhome_exec(bContext *C, wmOperator *op) /* was view3d_home() in 2. void VIEW3D_OT_view_all(wmOperatorType *ot) { /* identifiers */ - ot->name= "View home"; + ot->name= "View All"; ot->description = "View all objects in scene."; ot->idname= "VIEW3D_OT_view_all"; @@ -1064,7 +1195,7 @@ void VIEW3D_OT_view_center(wmOperatorType *ot) { /* identifiers */ - ot->name= "View center"; + ot->name= "View Selected"; ot->description = "Move the view to the selection center."; ot->idname= "VIEW3D_OT_view_center"; @@ -1628,7 +1759,7 @@ static int viewpersportho_exec(bContext *C, wmOperator *op) void VIEW3D_OT_view_persportho(wmOperatorType *ot) { /* identifiers */ - ot->name= "View persp/ortho"; + ot->name= "View Persp/Ortho"; ot->description = "Switch the current view from perspective/orthographic."; ot->idname= "VIEW3D_OT_view_persportho"; @@ -2338,7 +2469,7 @@ void viewmoveNDOF(Scene *scene, ARegion *ar, View3D *v3d, int mode) if (use_sel) { QuatConj(q1); /* conj == inv for unit quat */ - VecSubf(v3d->ofs, v3d->ofs, obofs); + VecSubf(rv3d->ofs, rv3d->ofs, obofs); QuatMulVecf(q1, rv3d->ofs); VecAddf(rv3d->ofs, rv3d->ofs, obofs); } diff --git a/source/blender/editors/space_view3d/view3d_header.c b/source/blender/editors/space_view3d/view3d_header.c index a633969d557..45828d654aa 100644 --- a/source/blender/editors/space_view3d/view3d_header.c +++ b/source/blender/editors/space_view3d/view3d_header.c @@ -177,7 +177,7 @@ static void handle_view3d_lock(bContext *C) View3D *v3d= CTX_wm_view3d(C); if (v3d != NULL && sa != NULL) { - if(v3d->localview==0 && v3d->scenelock && sa->spacetype==SPACE_VIEW3D) { + if(v3d->localvd==NULL && v3d->scenelock && sa->spacetype==SPACE_VIEW3D) { /* copy to scene */ scene->lay= v3d->lay; @@ -195,27 +195,38 @@ static int layers_exec(bContext *C, wmOperator *op) View3D *v3d= sa->spacedata.first; int nr= RNA_int_get(op->ptr, "nr"); - if(nr<=0) + if(nr < 0) return OPERATOR_CANCELLED; - nr--; - - if(RNA_boolean_get(op->ptr, "extend")) - v3d->lay |= (1<<nr); - else - v3d->lay = (1<<nr); - - /* set active layer, ensure to always have one */ - if(v3d->lay & (1<<nr)) - v3d->layact= 1<<nr; - else if((v3d->lay & v3d->layact)==0) { - int bit= 0; + + + if(nr == 0) { + /* all layers */ + v3d->lay |= (1<<20)-1; + + if(!v3d->layact) + v3d->layact= 1; + } + else { + nr--; + + if(RNA_boolean_get(op->ptr, "extend")) + v3d->lay |= (1<<nr); + else + v3d->lay = (1<<nr); - while(bit<32) { - if(v3d->lay & (1<<bit)) { - v3d->layact= 1<<bit; - break; + /* set active layer, ensure to always have one */ + if(v3d->lay & (1<<nr)) + v3d->layact= 1<<nr; + else if((v3d->lay & v3d->layact)==0) { + int bit= 0; + + while(bit<32) { + if(v3d->lay & (1<<bit)) { + v3d->layact= 1<<bit; + break; + } + bit++; } - bit++; } } @@ -263,8 +274,8 @@ void VIEW3D_OT_layers(wmOperatorType *ot) /* flags */ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; - RNA_def_int(ot->srna, "nr", 1, 0, 20, "Number", "", 0, 20); - RNA_def_boolean(ot->srna, "extend", 0, "Extend", ""); + RNA_def_int(ot->srna, "nr", 1, 0, 20, "Number", "The layer number to set, zero for all layers", 0, 20); + RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Add this layer to the current view layers"); } #if 0 @@ -1801,8 +1812,10 @@ static void do_view3d_header_buttons(bContext *C, void *arg, int event) ED_area_tag_redraw(sa); break; case B_NDOF: + ED_area_tag_redraw(sa); break; case B_MAN_MODE: + ED_area_tag_redraw(sa); break; case B_VIEW_BUTSEDIT: break; @@ -2076,7 +2089,7 @@ void uiTemplateHeader3D(uiLayout *layout, struct bContext *C) } /* LAYERS */ - if(obedit==NULL && v3d->localview==0) { + if(obedit==NULL && v3d->localvd==NULL) { int ob_lay = ob ? ob->lay : 0; uiBlockBeginAlign(block); for(a=0; a<5; a++) { diff --git a/source/blender/editors/space_view3d/view3d_intern.h b/source/blender/editors/space_view3d/view3d_intern.h index 7dbea44b68b..e7ab79ab955 100644 --- a/source/blender/editors/space_view3d/view3d_intern.h +++ b/source/blender/editors/space_view3d/view3d_intern.h @@ -66,8 +66,8 @@ void view3d_keymap(struct wmWindowManager *wm); /* view3d_edit.c */ void VIEW3D_OT_zoom(struct wmOperatorType *ot); -void VIEW3D_OT_viewmove(struct wmOperatorType *ot); -void VIEW3D_OT_viewrotate(struct wmOperatorType *ot); +void VIEW3D_OT_move(struct wmOperatorType *ot); +void VIEW3D_OT_rotate(struct wmOperatorType *ot); void VIEW3D_OT_view_all(struct wmOperatorType *ot); void VIEW3D_OT_viewnumpad(struct wmOperatorType *ot); void VIEW3D_OT_view_center(struct wmOperatorType *ot); @@ -89,10 +89,13 @@ int draw_glsl_material(Scene *scene, Object *ob, View3D *v3d, int dt); void draw_object_instance(Scene *scene, View3D *v3d, RegionView3D *rv3d, Object *ob, int dt, int outline); void draw_object_backbufsel(Scene *scene, View3D *v3d, RegionView3D *rv3d, Object *ob); void drawaxes(float size, int flag, char drawtype); -void view3d_object_text_draw_add(float x, float y, float z, char *str, short xoffs); + +void view3d_cached_text_draw_begin(void); +void view3d_cached_text_draw_add(float x, float y, float z, char *str, short xoffs); +void view3d_cached_text_draw_end(View3D *v3d, ARegion *ar, int depth_write, float mat[][4]); /* drawarmature.c */ -int draw_armature(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base, int dt, int flag); +int draw_armature(Scene *scene, View3D *v3d, ARegion *ar, Base *base, int dt, int flag); /* drawmesh.c */ void draw_mesh_textured(Scene *scene, View3D *v3d, RegionView3D *rv3d, Object *ob, struct DerivedMesh *dm, int faceselect); @@ -121,6 +124,7 @@ void VIEW3D_OT_smoothview(struct wmOperatorType *ot); void VIEW3D_OT_setcameratoview(struct wmOperatorType *ot); void VIEW3D_OT_localview(struct wmOperatorType *ot); void VIEW3D_OT_game_start(struct wmOperatorType *ot); +void VIEW3D_OT_fly(struct wmOperatorType *ot); int boundbox_clip(RegionView3D *rv3d, float obmat[][4], struct BoundBox *bb); @@ -132,6 +136,11 @@ void smooth_view(struct bContext *C, Object *, Object *, float *ofs, float *quat void setwinmatrixview3d(ARegion *ar, View3D *v3d, rctf *rect); /* rect: for picking */ void setviewmatrixview3d(Scene *scene, View3D *v3d, RegionView3D *rv3d); +void fly_modal_keymap(struct wmWindowManager *wm); +void viewrotate_modal_keymap(struct wmWindowManager *wm); +void viewmove_modal_keymap(struct wmWindowManager *wm); +void viewzoom_modal_keymap(struct wmWindowManager *wm); + /* view3d_buttons.c */ void VIEW3D_OT_properties(struct wmOperatorType *ot); void view3d_buttons_register(struct ARegionType *art); diff --git a/source/blender/editors/space_view3d/view3d_ops.c b/source/blender/editors/space_view3d/view3d_ops.c index 3569e2a79e3..f9cedbd28a1 100644 --- a/source/blender/editors/space_view3d/view3d_ops.c +++ b/source/blender/editors/space_view3d/view3d_ops.c @@ -62,8 +62,8 @@ void view3d_operatortypes(void) { - WM_operatortype_append(VIEW3D_OT_viewrotate); - WM_operatortype_append(VIEW3D_OT_viewmove); + WM_operatortype_append(VIEW3D_OT_rotate); + WM_operatortype_append(VIEW3D_OT_move); WM_operatortype_append(VIEW3D_OT_zoom); WM_operatortype_append(VIEW3D_OT_view_all); WM_operatortype_append(VIEW3D_OT_viewnumpad); @@ -85,6 +85,7 @@ void view3d_operatortypes(void) WM_operatortype_append(VIEW3D_OT_drawtype); WM_operatortype_append(VIEW3D_OT_localview); WM_operatortype_append(VIEW3D_OT_game_start); + WM_operatortype_append(VIEW3D_OT_fly); WM_operatortype_append(VIEW3D_OT_layers); WM_operatortype_append(VIEW3D_OT_properties); @@ -118,11 +119,13 @@ void view3d_keymap(wmWindowManager *wm) WM_keymap_verify_item(keymap, "VIEW3D_OT_cursor3d", ACTIONMOUSE, KM_PRESS, 0, 0); - WM_keymap_verify_item(keymap, "VIEW3D_OT_viewrotate", MIDDLEMOUSE, KM_PRESS, 0, 0); - WM_keymap_verify_item(keymap, "VIEW3D_OT_viewmove", MIDDLEMOUSE, KM_PRESS, KM_SHIFT, 0); + WM_keymap_verify_item(keymap, "VIEW3D_OT_rotate", MIDDLEMOUSE, KM_PRESS, 0, 0); + WM_keymap_verify_item(keymap, "VIEW3D_OT_move", MIDDLEMOUSE, KM_PRESS, KM_SHIFT, 0); WM_keymap_verify_item(keymap, "VIEW3D_OT_zoom", MIDDLEMOUSE, KM_PRESS, KM_CTRL, 0); WM_keymap_verify_item(keymap, "VIEW3D_OT_view_center", PADPERIOD, KM_PRESS, 0, 0); + WM_keymap_verify_item(keymap, "VIEW3D_OT_fly", FKEY, KM_PRESS, KM_SHIFT, 0); + WM_keymap_verify_item(keymap, "VIEW3D_OT_smoothview", TIMER1, KM_ANY, KM_ANY, 0); RNA_int_set(WM_keymap_add_item(keymap, "VIEW3D_OT_zoom", PADPLUSKEY, KM_PRESS, 0, 0)->ptr, "delta", 1); @@ -157,6 +160,7 @@ void view3d_keymap(wmWindowManager *wm) WM_keymap_add_item(keymap, "VIEW3D_OT_game_start", PKEY, KM_PRESS, 0, 0); /* layers, shift + alt are properties set in invoke() */ + RNA_int_set(WM_keymap_add_item(keymap, "VIEW3D_OT_layers", ACCENTGRAVEKEY, KM_PRESS, 0, 0)->ptr, "nr", 0); RNA_int_set(WM_keymap_add_item(keymap, "VIEW3D_OT_layers", ONEKEY, KM_PRESS, KM_ANY, 0)->ptr, "nr", 1); RNA_int_set(WM_keymap_add_item(keymap, "VIEW3D_OT_layers", TWOKEY, KM_PRESS, KM_ANY, 0)->ptr, "nr", 2); RNA_int_set(WM_keymap_add_item(keymap, "VIEW3D_OT_layers", THREEKEY, KM_PRESS, KM_ANY, 0)->ptr, "nr", 3); @@ -217,5 +221,9 @@ void view3d_keymap(wmWindowManager *wm) transform_keymap_for_space(wm, keymap, SPACE_VIEW3D); + fly_modal_keymap(wm); + viewrotate_modal_keymap(wm); + viewmove_modal_keymap(wm); + viewzoom_modal_keymap(wm); } diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c index b1fec793b09..a37e916064c 100644 --- a/source/blender/editors/space_view3d/view3d_select.c +++ b/source/blender/editors/space_view3d/view3d_select.c @@ -1148,7 +1148,7 @@ static void mouse_select(bContext *C, short *mval, short extend, short obcenter, WM_event_add_notifier(C, NC_OBJECT|ND_BONE_ACTIVE, basact->object); /* in weightpaint, we use selected bone to select vertexgroup, so no switch to new active object */ - if(basact->object->mode & OB_MODE_WEIGHT_PAINT) { + if(BASACT && BASACT->object->mode & OB_MODE_WEIGHT_PAINT) { /* prevent activating */ basact= NULL; } diff --git a/source/blender/editors/space_view3d/view3d_view.c b/source/blender/editors/space_view3d/view3d_view.c index 7831d604ddf..f722a97963d 100644 --- a/source/blender/editors/space_view3d/view3d_view.c +++ b/source/blender/editors/space_view3d/view3d_view.c @@ -56,9 +56,11 @@ #include "BKE_object.h" #include "BKE_global.h" #include "BKE_main.h" +#include "BKE_report.h" #include "BKE_scene.h" #include "BKE_screen.h" #include "BKE_utildefines.h" +#include "BKE_depsgraph.h" /* for fly mode updating */ #include "RE_pipeline.h" // make_stars @@ -110,7 +112,7 @@ void view3d_operator_needs_opengl(const bContext *C) float *give_cursor(Scene *scene, View3D *v3d) { - if(v3d && v3d->localview) return v3d->cursor; + if(v3d && v3d->localvd) return v3d->cursor; else return scene->cursor; } @@ -384,26 +386,31 @@ void VIEW3D_OT_smoothview(wmOperatorType *ot) ot->poll= ED_operator_view3d_active; } -static int view3d_setcameratoview_exec(bContext *C, wmOperator *op) +static void setcameratoview3d(View3D *v3d, RegionView3D *rv3d, Object *ob) { - View3D *v3d = CTX_wm_view3d(C); - RegionView3D *rv3d= CTX_wm_region_view3d(C); - Object *ob; float dvec[3]; - ob= v3d->camera; dvec[0]= rv3d->dist*rv3d->viewinv[2][0]; dvec[1]= rv3d->dist*rv3d->viewinv[2][1]; dvec[2]= rv3d->dist*rv3d->viewinv[2][2]; VECCOPY(ob->loc, dvec); - VecSubf(ob->loc, ob->loc, v3d->ofs); + VecSubf(ob->loc, ob->loc, rv3d->ofs); rv3d->viewquat[0]= -rv3d->viewquat[0]; QuatToEul(rv3d->viewquat, ob->rot); rv3d->viewquat[0]= -rv3d->viewquat[0]; ob->recalc= OB_RECALC_OB; +} + + +static int view3d_setcameratoview_exec(bContext *C, wmOperator *op) +{ + View3D *v3d = CTX_wm_view3d(C); + RegionView3D *rv3d= CTX_wm_region_view3d(C); + + setcameratoview3d(v3d, rv3d, v3d->camera); WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, CTX_data_scene(C)); @@ -1303,7 +1310,6 @@ static void initlocalview(Scene *scene, ScrArea *sa) base->object->lay= base->lay; } } - v3d->localview= 0; } } @@ -1325,7 +1331,6 @@ static void restore_localviewdata(ScrArea *sa, int free) if(free) { MEM_freeN(v3d->localvd); v3d->localvd= NULL; - v3d->localview= 0; } for(ar= sa->regionbase.first; ar; ar= ar->next) { @@ -1416,8 +1421,6 @@ static void SaveState(bContext *C) glPushAttrib(GL_ALL_ATTRIB_BITS); - GPU_state_init(); - if(obact && obact->mode & OB_MODE_TEXTURE_PAINT) GPU_paint_set_mipmap(1); @@ -1446,6 +1449,8 @@ static void RestoreState(bContext *C) win->queue= queue_back; + GPU_state_init(); + glPopAttrib(); } @@ -1574,6 +1579,802 @@ void VIEW3D_OT_game_start(wmOperatorType *ot) ot->poll= game_engine_poll; } + +/* NOTE: these defines are saved in keymap files, do not change values but just add new ones */ +#define FLY_MODAL_CANCEL 1 +#define FLY_MODAL_CONFIRM 2 +#define FLY_MODAL_ACCELERATE 3 +#define FLY_MODAL_DECELERATE 4 +#define FLY_MODAL_PAN_ENABLE 5 +#define FLY_MODAL_PAN_DISABLE 6 +#define FLY_MODAL_DIR_FORWARD 7 +#define FLY_MODAL_DIR_BACKWARD 8 +#define FLY_MODAL_DIR_LEFT 9 +#define FLY_MODAL_DIR_RIGHT 10 +#define FLY_MODAL_DIR_UP 11 +#define FLY_MODAL_DIR_DOWN 12 +#define FLY_MODAL_AXIS_LOCK_X 13 +#define FLY_MODAL_AXIS_LOCK_Z 14 +#define FLY_MODAL_PRECISION_ENABLE 15 +#define FLY_MODAL_PRECISION_DISABLE 16 + +/* called in transform_ops.c, on each regeneration of keymaps */ +void fly_modal_keymap(wmWindowManager *wm) +{ + static EnumPropertyItem modal_items[] = { + {FLY_MODAL_CANCEL, "CANCEL", 0, "Cancel", ""}, + {FLY_MODAL_CONFIRM, "CONFIRM", 0, "Confirm", ""}, + {FLY_MODAL_ACCELERATE, "ACCELERATE", 0, "Accelerate", ""}, + {FLY_MODAL_DECELERATE, "DECELERATE", 0, "Decelerate", ""}, + + {FLY_MODAL_PAN_ENABLE, "PAN_ENABLE", 0, "Pan Enable", ""}, + {FLY_MODAL_PAN_DISABLE, "PAN_DISABLE", 0, "Pan Disable", ""}, + + {FLY_MODAL_DIR_FORWARD, "FORWARD", 0, "Fly Forward", ""}, + {FLY_MODAL_DIR_BACKWARD,"BACKWARD", 0, "Fly Backward", ""}, + {FLY_MODAL_DIR_LEFT, "LEFT", 0, "Fly Left", ""}, + {FLY_MODAL_DIR_RIGHT, "RIGHT", 0, "Fly Right", ""}, + {FLY_MODAL_DIR_UP, "UP", 0, "Fly Up", ""}, + {FLY_MODAL_DIR_DOWN, "DOWN", 0, "Fly Down", ""}, + + {FLY_MODAL_AXIS_LOCK_X, "AXIS_LOCK_X", 0, "X Axis Correction", "X axis correction (toggle)"}, + {FLY_MODAL_AXIS_LOCK_Z, "AXIS_LOCK_Z", 0, "X Axis Correction", "Z axis correction (toggle)"}, + + {FLY_MODAL_PRECISION_ENABLE, "PRECISION_ENABLE", 0, "Precision Enable", ""}, + {FLY_MODAL_PRECISION_DISABLE, "PRECISION_DISABLE", 0, "Precision Disable", ""}, + + {0, NULL, 0, NULL, NULL}}; + + wmKeyMap *keymap= WM_modalkeymap_get(wm, "View3D Fly Modal"); + + /* this function is called for each spacetype, only needs to add map once */ + if(keymap) return; + + keymap= WM_modalkeymap_add(wm, "View3D Fly Modal", modal_items); + + /* items for modal map */ + WM_modalkeymap_add_item(keymap, ESCKEY, KM_PRESS, KM_ANY, 0, FLY_MODAL_CANCEL); + WM_modalkeymap_add_item(keymap, RIGHTMOUSE, KM_ANY, KM_ANY, 0, FLY_MODAL_CANCEL); + + WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_ANY, KM_ANY, 0, FLY_MODAL_CONFIRM); + WM_modalkeymap_add_item(keymap, RETKEY, KM_PRESS, KM_ANY, 0, FLY_MODAL_CONFIRM); + WM_modalkeymap_add_item(keymap, PADENTER, KM_PRESS, KM_ANY, 0, FLY_MODAL_CONFIRM); + + WM_modalkeymap_add_item(keymap, PADPLUSKEY, KM_PRESS, 0, 0, FLY_MODAL_ACCELERATE); + WM_modalkeymap_add_item(keymap, PADMINUS, KM_PRESS, 0, 0, FLY_MODAL_DECELERATE); + WM_modalkeymap_add_item(keymap, WHEELUPMOUSE, KM_PRESS, 0, 0, FLY_MODAL_ACCELERATE); + WM_modalkeymap_add_item(keymap, WHEELDOWNMOUSE, KM_PRESS, 0, 0, FLY_MODAL_DECELERATE); + + WM_modalkeymap_add_item(keymap, MIDDLEMOUSE, KM_PRESS, KM_ANY, 0, FLY_MODAL_PAN_ENABLE); + WM_modalkeymap_add_item(keymap, MIDDLEMOUSE, KM_RELEASE, KM_ANY, 0, FLY_MODAL_PAN_DISABLE); /* XXX - Bug in the event system, middle mouse release doesnt work */ + + /* WASD */ + WM_modalkeymap_add_item(keymap, WKEY, KM_PRESS, 0, 0, FLY_MODAL_DIR_FORWARD); + WM_modalkeymap_add_item(keymap, SKEY, KM_PRESS, 0, 0, FLY_MODAL_DIR_BACKWARD); + WM_modalkeymap_add_item(keymap, AKEY, KM_PRESS, 0, 0, FLY_MODAL_DIR_LEFT); + WM_modalkeymap_add_item(keymap, DKEY, KM_PRESS, 0, 0, FLY_MODAL_DIR_RIGHT); + WM_modalkeymap_add_item(keymap, RKEY, KM_PRESS, 0, 0, FLY_MODAL_DIR_UP); + WM_modalkeymap_add_item(keymap, FKEY, KM_PRESS, 0, 0, FLY_MODAL_DIR_DOWN); + + WM_modalkeymap_add_item(keymap, XKEY, KM_PRESS, 0, 0, FLY_MODAL_AXIS_LOCK_X); + WM_modalkeymap_add_item(keymap, ZKEY, KM_PRESS, 0, 0, FLY_MODAL_AXIS_LOCK_Z); + + WM_modalkeymap_add_item(keymap, LEFTSHIFTKEY, KM_PRESS, KM_ANY, 0, FLY_MODAL_PRECISION_ENABLE); + WM_modalkeymap_add_item(keymap, LEFTSHIFTKEY, KM_RELEASE, KM_ANY, 0, FLY_MODAL_PRECISION_DISABLE); + + /* assign map to operators */ + WM_modalkeymap_assign(keymap, "VIEW3D_OT_fly"); + +} + +typedef struct FlyInfo { + /* context stuff */ + RegionView3D *rv3d; + View3D *v3d; + ARegion *ar; + Scene *scene; + + wmTimer *timer; /* needed for redraws */ + + short state; + short use_precision; + short redraw; + short mval[2]; + + /* fly state state */ + float speed; /* the speed the view is moving per redraw */ + short axis; /* Axis index to move allong by default Z to move allong the view */ + short pan_view; /* when true, pan the view instead of rotating */ + + /* relative view axis locking - xlock, zlock + 0; disabled + 1; enabled but not checking because mouse hasnt moved outside the margin since locking was checked an not needed + when the mouse moves, locking is set to 2 so checks are done. + 2; mouse moved and checking needed, if no view altering is donem its changed back to 1 */ + short xlock, zlock; + float xlock_momentum, zlock_momentum; /* nicer dynamics */ + float grid; /* world scale 1.0 default */ + + /* backup values */ + float dist_backup; /* backup the views distance since we use a zero dist for fly mode */ + float ofs_backup[3]; /* backup the views offset incase the user cancels flying in non camera mode */ + float rot_backup[4]; /* backup the views quat incase the user cancels flying in non camera mode. (quat for view, eul for camera) */ + short persp_backup; /* remember if were ortho or not, only used for restoring the view if it was a ortho view */ + + /* compare between last state */ + double time_lastwheel; /* used to accelerate when using the mousewheel a lot */ + double time_lastdraw; /* time between draws */ + + /* use for some lag */ + float dvec_prev[3]; /* old for some lag */ + +} FlyInfo; + +/* FlyInfo->state */ +#define FLY_RUNNING 0 +#define FLY_CANCEL 1 +#define FLY_CONFIRM 2 + +int initFlyInfo (bContext *C, FlyInfo *fly, wmOperator *op, wmEvent *event) +{ + float upvec[3]; // tmp + float mat[3][3]; + + fly->rv3d= CTX_wm_region_view3d(C); + fly->v3d = CTX_wm_view3d(C); + fly->ar = CTX_wm_region(C); + fly->scene= CTX_data_scene(C); + + if(fly->rv3d->persp==V3D_CAMOB && fly->v3d->camera->id.lib) { + BKE_report(op->reports, RPT_ERROR, "Cannot fly a camera from an external library"); + return FALSE; + } + + if(fly->v3d->ob_centre) { + BKE_report(op->reports, RPT_ERROR, "Cannot fly when the view is locked to an object"); + return FALSE; + } + + if(fly->rv3d->persp==V3D_CAMOB && fly->v3d->camera->constraints.first) { + BKE_report(op->reports, RPT_ERROR, "Cannot fly an object with constraints"); + return FALSE; + } + + fly->state= FLY_RUNNING; + fly->speed= 0.0f; + fly->axis= 2; + fly->pan_view= FALSE; + fly->xlock= FALSE; + fly->zlock= TRUE; + fly->xlock_momentum=0.0f; + fly->zlock_momentum=0.0f; + fly->grid= 1.0f; + fly->use_precision= 0; + + fly->dvec_prev[0]= fly->dvec_prev[1]= fly->dvec_prev[2]= 0.0f; + + fly->timer= WM_event_add_window_timer(CTX_wm_window(C), TIMER, 0.01f); + + + /* we have to rely on events to give proper mousecoords after a warp_pointer */ +//XXX2.5 warp_pointer(cent_orig[0], cent_orig[1]); + //fly->mval[0]= (fly->sa->winx)/2; + //fly->mval[1]= (fly->sa->winy)/2; + + fly->mval[0] = event->x - fly->ar->winrct.xmin; + fly->mval[1] = event->y - fly->ar->winrct.ymin; + + + fly->time_lastdraw= fly->time_lastwheel= PIL_check_seconds_timer(); + + fly->rv3d->rflag |= RV3D_FLYMODE; /* so we draw the corner margins */ + + /* detect weather to start with Z locking */ + upvec[0]=1.0f; upvec[1]=0.0f; upvec[2]=0.0f; + Mat3CpyMat4(mat, fly->rv3d->viewinv); + Mat3MulVecfl(mat, upvec); + if (fabs(upvec[2]) < 0.1) + fly->zlock = 1; + upvec[0]=0; upvec[1]=0; upvec[2]=0; + + fly->persp_backup= fly->rv3d->persp; + fly->dist_backup= fly->rv3d->dist; + if (fly->rv3d->persp==V3D_CAMOB) { + /* store the origoinal camera loc and rot */ + VECCOPY(fly->ofs_backup, fly->v3d->camera->loc); + VECCOPY(fly->rot_backup, fly->v3d->camera->rot); + + where_is_object(fly->scene, fly->v3d->camera); + VECCOPY(fly->rv3d->ofs, fly->v3d->camera->obmat[3]); + VecMulf(fly->rv3d->ofs, -1.0f); /*flip the vector*/ + + fly->rv3d->dist=0.0; + fly->rv3d->viewbut=0; + + /* used for recording */ +//XXX2.5 if(v3d->camera->ipoflag & OB_ACTION_OB) +//XXX2.5 actname= "Object"; + + } else { + /* perspective or ortho */ + if (fly->rv3d->persp==V3D_ORTHO) + fly->rv3d->persp= V3D_PERSP; /*if ortho projection, make perspective */ + QUATCOPY(fly->rot_backup, fly->rv3d->viewquat); + VECCOPY(fly->ofs_backup, fly->rv3d->ofs); + fly->rv3d->dist= 0.0; + + upvec[2]= fly->dist_backup; /*x and y are 0*/ + Mat3MulVecfl(mat, upvec); + VecSubf(fly->rv3d->ofs, fly->rv3d->ofs, upvec); + /*Done with correcting for the dist*/ + } + + return 1; +} + +static int flyEnd(bContext *C, FlyInfo *fly) +{ + RegionView3D *rv3d= fly->rv3d; + View3D *v3d = fly->v3d; + + float upvec[3]; + + if(fly->state == FLY_RUNNING) + return OPERATOR_RUNNING_MODAL; + + WM_event_remove_window_timer(CTX_wm_window(C), fly->timer); + + rv3d->dist= fly->dist_backup; + + if (fly->state == FLY_CANCEL) { + /* Revert to original view? */ + if (fly->persp_backup==V3D_CAMOB) { /* a camera view */ + rv3d->viewbut=1; + VECCOPY(v3d->camera->loc, fly->ofs_backup); + VECCOPY(v3d->camera->rot, fly->rot_backup); + DAG_id_flush_update(&v3d->camera->id, OB_RECALC_OB); + } else { + /* Non Camera we need to reset the view back to the original location bacause the user canceled*/ + QUATCOPY(rv3d->viewquat, fly->rot_backup); + VECCOPY(rv3d->ofs, fly->ofs_backup); + rv3d->persp= fly->persp_backup; + } + } + else if (fly->persp_backup==V3D_CAMOB) { /* camera */ + float mat3[3][3]; + Mat3CpyMat4(mat3, v3d->camera->obmat); + Mat3ToCompatibleEul(mat3, v3d->camera->rot, fly->rot_backup); + + DAG_id_flush_update(&v3d->camera->id, OB_RECALC_OB); +#if 0 //XXX2.5 + if (IS_AUTOKEY_MODE(NORMAL)) { + allqueue(REDRAWIPO, 0); + allspace(REMAKEIPO, 0); + allqueue(REDRAWNLA, 0); + allqueue(REDRAWTIME, 0); + } +#endif + } + else { /* not camera */ + /* Apply the fly mode view */ + /*restore the dist*/ + float mat[3][3]; + upvec[0]= upvec[1]= 0; + upvec[2]= fly->dist_backup; /*x and y are 0*/ + Mat3CpyMat4(mat, rv3d->viewinv); + Mat3MulVecfl(mat, upvec); + VecAddf(rv3d->ofs, rv3d->ofs, upvec); + /*Done with correcting for the dist */ + } + + rv3d->rflag &= ~RV3D_FLYMODE; +//XXX2.5 BIF_view3d_previewrender_signal(fly->sa, PR_DBASE|PR_DISPRECT); /* not working at the moment not sure why */ + + + if(fly->state == FLY_CONFIRM) { + MEM_freeN(fly); + return OPERATOR_FINISHED; + } + + MEM_freeN(fly); + return OPERATOR_CANCELLED; +} + +void flyEvent(FlyInfo *fly, wmEvent *event) +{ + if (event->type == TIMER) { + fly->redraw = 1; + } + else if (event->type == MOUSEMOVE) { + fly->mval[0] = event->x - fly->ar->winrct.xmin; + fly->mval[1] = event->y - fly->ar->winrct.ymin; + } /* handle modal keymap first */ + else if (event->type == EVT_MODAL_MAP) { + switch (event->val) { + case FLY_MODAL_CANCEL: + fly->state = FLY_CANCEL; + break; + case FLY_MODAL_CONFIRM: + fly->state = FLY_CONFIRM; + break; + + case FLY_MODAL_ACCELERATE: + { + double time_currwheel; + float time_wheel; + + time_currwheel= PIL_check_seconds_timer(); + time_wheel = (float)(time_currwheel - fly->time_lastwheel); + fly->time_lastwheel = time_currwheel; + /*printf("Wheel %f\n", time_wheel);*/ + /*Mouse wheel delays range from 0.5==slow to 0.01==fast*/ + time_wheel = 1+ (10 - (20*MIN2(time_wheel, 0.5))); /* 0-0.5 -> 0-5.0 */ + + if (fly->speed<0.0f) fly->speed= 0.0f; + else { + if (event->shift) + fly->speed+= fly->grid*time_wheel*0.1; + else + fly->speed+= fly->grid*time_wheel; + } + break; + } + case FLY_MODAL_DECELERATE: + { + double time_currwheel; + float time_wheel; + + time_currwheel= PIL_check_seconds_timer(); + time_wheel = (float)(time_currwheel - fly->time_lastwheel); + fly->time_lastwheel = time_currwheel; + time_wheel = 1+ (10 - (20*MIN2(time_wheel, 0.5))); /* 0-0.5 -> 0-5.0 */ + + if (fly->speed>0) fly->speed=0; + else { + if (event->shift) + fly->speed-= fly->grid*time_wheel*0.1; + else + fly->speed-= fly->grid*time_wheel; + } + break; + } + case FLY_MODAL_PAN_ENABLE: + fly->pan_view= TRUE; + break; + case FLY_MODAL_PAN_DISABLE: +//XXX2.5 warp_pointer(cent_orig[0], cent_orig[1]); + fly->pan_view= FALSE; + break; + + /* impliment WASD keys */ + case FLY_MODAL_DIR_FORWARD: + if (fly->speed < 0.0f) fly->speed= -fly->speed; /* flip speed rather then stopping, game like motion */ + else fly->speed += fly->grid; /* increse like mousewheel if were alredy moving in that difection*/ + fly->axis= 2; + break; + case FLY_MODAL_DIR_BACKWARD: + if (fly->speed>0) fly->speed= -fly->speed; + else fly->speed -= fly->grid; + fly->axis= 2; + break; + case FLY_MODAL_DIR_LEFT: + if (fly->speed < 0.0f) fly->speed= -fly->speed; + fly->axis= 0; + break; + case FLY_MODAL_DIR_RIGHT: + if (fly->speed > 0.0f) fly->speed= -fly->speed; + fly->axis= 0; + break; + + case FLY_MODAL_DIR_UP: + if (fly->speed < 0.0f) fly->speed= -fly->speed; + fly->axis= 1; + break; + + case FLY_MODAL_DIR_DOWN: + if (fly->speed > 0.0f) fly->speed= -fly->speed; + fly->axis= 1; + break; + + case FLY_MODAL_AXIS_LOCK_X: + if (fly->xlock) fly->xlock=0; + else { + fly->xlock = 2; + fly->xlock_momentum = 0.0; + } + break; + case FLY_MODAL_AXIS_LOCK_Z: + if (fly->zlock) fly->zlock=0; + else { + fly->zlock = 2; + fly->zlock_momentum = 0.0; + } + break; + + case FLY_MODAL_PRECISION_ENABLE: + fly->use_precision= TRUE; + break; + case FLY_MODAL_PRECISION_DISABLE: + fly->use_precision= FALSE; + break; + + } + } +} + +//int fly_exec(bContext *C, wmOperator *op) +int flyApply(FlyInfo *fly) +{ + /* + fly mode - Shift+F + a fly loop where the user can move move the view as if they are flying + */ + RegionView3D *rv3d= fly->rv3d; + View3D *v3d = fly->v3d; + ARegion *ar = fly->ar; + Scene *scene= fly->scene; + + float mat[3][3], /* 3x3 copy of the view matrix so we can move allong the view axis */ + dvec[3]={0,0,0}, /* this is the direction thast added to the view offset per redraw */ + + /* Camera Uprighting variables */ + upvec[3]={0,0,0}, /* stores the view's up vector */ + + moffset[2], /* mouse offset from the views center */ + tmp_quat[4]; /* used for rotating the view */ + + int cent_orig[2], /* view center */ +//XXX- can avoid using // cent[2], /* view center modified */ + xmargin, ymargin; /* x and y margin are define the safe area where the mouses movement wont rotate the view */ + unsigned char + apply_rotation= 1; /* if the user presses shift they can look about without movinf the direction there looking*/ + + /* for recording */ +#if 0 //XXX2.5 todo, get animation recording working again. + int playing_anim = 0; //XXX has_screenhandler(G.curscreen, SCREEN_HANDLER_ANIM); + int cfra = -1; /*so the first frame always has a key added */ + char *actname=""; +#endif + /* the dist defines a vector that is infront of the offset + to rotate the view about. + this is no good for fly mode because we + want to rotate about the viewers center. + but to correct the dist removal we must + alter offset so the view doesn't jump. */ + + xmargin= ar->winx/20.0f; + ymargin= ar->winy/20.0f; + + cent_orig[0]= ar->winrct.xmin + ar->winx/2; + cent_orig[1]= ar->winrct.ymin + ar->winy/2; + + { + + /* mouse offset from the center */ + moffset[0]= fly->mval[0]- ar->winx/2; + moffset[1]= fly->mval[1]- ar->winy/2; + + /* enforce a view margin */ + if (moffset[0]>xmargin) moffset[0]-=xmargin; + else if (moffset[0] < -xmargin) moffset[0]+=xmargin; + else moffset[0]=0; + + if (moffset[1]>ymargin) moffset[1]-=ymargin; + else if (moffset[1] < -ymargin) moffset[1]+=ymargin; + else moffset[1]=0; + + + /* scale the mouse movement by this value - scales mouse movement to the view size + * moffset[0]/(ar->winx-xmargin*2) - window size minus margin (same for y) + * + * the mouse moves isnt linear */ + + if(moffset[0]) { + moffset[0] /= ar->winx - (xmargin*2); + moffset[0] *= fabs(moffset[0]); + } + + if(moffset[1]) { + moffset[1] /= ar->winy - (ymargin*2); + moffset[1] *= fabs(moffset[1]); + } + + /* Should we redraw? */ + if(fly->speed != 0.0f || moffset[0] || moffset[1] || fly->zlock || fly->xlock || dvec[0] || dvec[1] || dvec[2] ) { + float dvec_tmp[3]; + double time_current, time_redraw; /*time how fast it takes for us to redraw, this is so simple scenes dont fly too fast */ + float time_redraw_clamped; + + time_current= PIL_check_seconds_timer(); + time_redraw= (float)(time_current - fly->time_lastdraw); + time_redraw_clamped= MIN2(0.05f, time_redraw); /* clamt the redraw time to avoid jitter in roll correction */ + fly->time_lastdraw= time_current; + /*fprintf(stderr, "%f\n", time_redraw);*/ /* 0.002 is a small redraw 0.02 is larger */ + + /* Scale the time to use shift to scale the speed down- just like + shift slows many other areas of blender down */ + if (fly->use_precision) + fly->speed= fly->speed * (1.0f-time_redraw_clamped); + + Mat3CpyMat4(mat, rv3d->viewinv); + + if (fly->pan_view==TRUE) { + /* pan only */ + dvec_tmp[0]= -moffset[0]; + dvec_tmp[1]= -moffset[1]; + dvec_tmp[2]= 0; + + if (fly->use_precision) { + dvec_tmp[0] *= 0.1; + dvec_tmp[1] *= 0.1; + } + + Mat3MulVecfl(mat, dvec_tmp); + VecMulf(dvec_tmp, time_redraw*200.0 * fly->grid); + + } else { + float roll; /* similar to the angle between the camera's up and the Z-up, but its very rough so just roll*/ + + /* rotate about the X axis- look up/down */ + if (moffset[1]) { + upvec[0]=1; + upvec[1]=0; + upvec[2]=0; + Mat3MulVecfl(mat, upvec); + VecRotToQuat( upvec, (float)moffset[1]*-time_redraw*20, tmp_quat); /* Rotate about the relative up vec */ + QuatMul(rv3d->viewquat, rv3d->viewquat, tmp_quat); + + if (fly->xlock) fly->xlock = 2; /*check for rotation*/ + if (fly->zlock) fly->zlock = 2; + fly->xlock_momentum= 0.0f; + } + + /* rotate about the Y axis- look left/right */ + if (moffset[0]) { + + /* if we're upside down invert the moffset */ + upvec[0]=0; + upvec[1]=1; + upvec[2]=0; + Mat3MulVecfl(mat, upvec); + + if(upvec[2] < 0.0f) + moffset[0]= -moffset[0]; + + /* make the lock vectors */ + if (fly->zlock) { + upvec[0]=0; + upvec[1]=0; + upvec[2]=1; + } else { + upvec[0]=0; + upvec[1]=1; + upvec[2]=0; + Mat3MulVecfl(mat, upvec); + } + + VecRotToQuat( upvec, (float)moffset[0]*time_redraw*20, tmp_quat); /* Rotate about the relative up vec */ + QuatMul(rv3d->viewquat, rv3d->viewquat, tmp_quat); + + if (fly->xlock) fly->xlock = 2;/*check for rotation*/ + if (fly->zlock) fly->zlock = 2; + } + + if (fly->zlock==2) { + upvec[0]=1; + upvec[1]=0; + upvec[2]=0; + Mat3MulVecfl(mat, upvec); + + /*make sure we have some z rolling*/ + if (fabs(upvec[2]) > 0.00001f) { + roll= upvec[2]*5; + upvec[0]=0; /*rotate the view about this axis*/ + upvec[1]=0; + upvec[2]=1; + + Mat3MulVecfl(mat, upvec); + VecRotToQuat( upvec, roll*time_redraw_clamped*fly->zlock_momentum*0.1, tmp_quat); /* Rotate about the relative up vec */ + QuatMul(rv3d->viewquat, rv3d->viewquat, tmp_quat); + + fly->zlock_momentum += 0.05f; + } else { + fly->zlock=1; /* dont check until the view rotates again */ + fly->zlock_momentum= 0.0f; + } + } + + if (fly->xlock==2 && moffset[1]==0) { /*only apply xcorrect when mouse isnt applying x rot*/ + upvec[0]=0; + upvec[1]=0; + upvec[2]=1; + Mat3MulVecfl(mat, upvec); + /*make sure we have some z rolling*/ + if (fabs(upvec[2]) > 0.00001) { + roll= upvec[2] * -5; + + upvec[0]= 1.0f; /*rotate the view about this axis*/ + upvec[1]= 0.0f; + upvec[2]= 0.0f; + + Mat3MulVecfl(mat, upvec); + + VecRotToQuat( upvec, roll*time_redraw_clamped*fly->xlock_momentum*0.1f, tmp_quat); /* Rotate about the relative up vec */ + QuatMul(rv3d->viewquat, rv3d->viewquat, tmp_quat); + + fly->xlock_momentum += 0.05f; + } else { + fly->xlock=1; /* see above */ + fly->xlock_momentum= 0.0f; + } + } + + + if (apply_rotation) { + /* Normal operation */ + /* define dvec, view direction vector */ + dvec_tmp[0]= dvec_tmp[1]= dvec_tmp[2]= 0.0f; + /* move along the current axis */ + dvec_tmp[fly->axis]= 1.0f; + + Mat3MulVecfl(mat, dvec_tmp); + + VecMulf(dvec_tmp, fly->speed * time_redraw * 0.25f); + } + } + + /* impose a directional lag */ + VecLerpf(dvec, dvec_tmp, fly->dvec_prev, (1.0f/(1.0f+(time_redraw*5.0f)))); + + if (rv3d->persp==V3D_CAMOB) { + if (v3d->camera->protectflag & OB_LOCK_LOCX) + dvec[0] = 0.0; + if (v3d->camera->protectflag & OB_LOCK_LOCY) + dvec[1] = 0.0; + if (v3d->camera->protectflag & OB_LOCK_LOCZ) + dvec[2] = 0.0; + } + + VecAddf(rv3d->ofs, rv3d->ofs, dvec); +#if 0 //XXX2.5 + if (fly->zlock && fly->xlock) + headerprint("FlyKeys Speed:(+/- | Wheel), Upright Axis:X on/Z on, Slow:Shift, Direction:WASDRF, Ok:LMB, Pan:MMB, Cancel:RMB"); + else if (fly->zlock) + headerprint("FlyKeys Speed:(+/- | Wheel), Upright Axis:X off/Z on, Slow:Shift, Direction:WASDRF, Ok:LMB, Pan:MMB, Cancel:RMB"); + else if (fly->xlock) + headerprint("FlyKeys Speed:(+/- | Wheel), Upright Axis:X on/Z off, Slow:Shift, Direction:WASDRF, Ok:LMB, Pan:MMB, Cancel:RMB"); + else + headerprint("FlyKeys Speed:(+/- | Wheel), Upright Axis:X off/Z off, Slow:Shift, Direction:WASDRF, Ok:LMB, Pan:MMB, Cancel:RMB"); +#endif + +//XXX2.5 do_screenhandlers(G.curscreen); /* advance the next frame */ + + /* we are in camera view so apply the view ofs and quat to the view matrix and set the camera to the view */ + if (rv3d->persp==V3D_CAMOB) { + rv3d->persp= V3D_PERSP; /*set this so setviewmatrixview3d uses the ofs and quat instead of the camera */ + setviewmatrixview3d(scene, v3d, rv3d); + + setcameratoview3d(v3d, rv3d, v3d->camera); + + { //XXX - some reason setcameratoview3d doesnt copy, shouldnt not be needed! + VECCOPY(v3d->camera->loc, rv3d->ofs); + VecNegf(v3d->camera->loc); + } + + rv3d->persp= V3D_CAMOB; +#if 0 //XXX2.5 + /* record the motion */ + if (IS_AUTOKEY_MODE(NORMAL) && (!playing_anim || cfra != G.scene->r.cfra)) { + cfra = G.scene->r.cfra; + + if (fly->xlock || fly->zlock || moffset[0] || moffset[1]) { + insertkey(&v3d->camera->id, ID_OB, actname, NULL, OB_ROT_X, 0); + insertkey(&v3d->camera->id, ID_OB, actname, NULL, OB_ROT_Y, 0); + insertkey(&v3d->camera->id, ID_OB, actname, NULL, OB_ROT_Z, 0); + } + if (fly->speed) { + insertkey(&v3d->camera->id, ID_OB, actname, NULL, OB_LOC_X, 0); + insertkey(&v3d->camera->id, ID_OB, actname, NULL, OB_LOC_Y, 0); + insertkey(&v3d->camera->id, ID_OB, actname, NULL, OB_LOC_Z, 0); + } + } +#endif + } +//XXX2.5 scrarea_do_windraw(curarea); +//XXX2.5 screen_swapbuffers(); + } else + /*were not redrawing but we need to update the time else the view will jump */ + fly->time_lastdraw= PIL_check_seconds_timer(); + /* end drawing */ + VECCOPY(fly->dvec_prev, dvec); + } + +/* moved to flyEnd() */ + + return OPERATOR_FINISHED; +} + + + +static int fly_invoke(bContext *C, wmOperator *op, wmEvent *event) +{ + RegionView3D *rv3d= CTX_wm_region_view3d(C); + FlyInfo *fly; + + if(rv3d->viewlock) + return OPERATOR_CANCELLED; + + fly= MEM_callocN(sizeof(FlyInfo), "FlyOperation"); + + op->customdata= fly; + + if(initFlyInfo(C, fly, op, event)==FALSE) { + MEM_freeN(op->customdata); + return OPERATOR_CANCELLED; + } + + flyEvent(fly, event); + + WM_event_add_modal_handler(C, op); + + return OPERATOR_RUNNING_MODAL; +} + +static int fly_cancel(bContext *C, wmOperator *op) +{ + FlyInfo *fly = op->customdata; + + fly->state = FLY_CANCEL; + flyEnd(C, fly); + op->customdata= NULL; + + return OPERATOR_CANCELLED; +} + +static int fly_modal(bContext *C, wmOperator *op, wmEvent *event) +{ + int exit_code; + + FlyInfo *fly = op->customdata; + + fly->redraw= 0; + + flyEvent(fly, event); + + if(event->type==TIMER) + flyApply(fly); + + if(fly->redraw) {; + ED_region_tag_redraw(CTX_wm_region(C)); + } + + exit_code = flyEnd(C, fly); + + if(exit_code!=OPERATOR_RUNNING_MODAL) + ED_region_tag_redraw(CTX_wm_region(C)); + + return exit_code; +} + +void VIEW3D_OT_fly(wmOperatorType *ot) +{ + + /* identifiers */ + ot->name= "Fly Navigation"; + ot->description= "Interactively fly around the scene."; + ot->idname= "VIEW3D_OT_fly"; + + /* api callbacks */ + ot->invoke= fly_invoke; + ot->cancel= fly_cancel; + ot->modal= fly_modal; + ot->poll= ED_operator_view3d_active; + + /* flags */ + ot->flag= OPTYPE_BLOCKING; + +} + /* ************************************** */ void view3d_align_axis_to_vector(View3D *v3d, RegionView3D *rv3d, int axisidx, float vec[3]) diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c index e877f1fecae..bc529486085 100644 --- a/source/blender/editors/transform/transform.c +++ b/source/blender/editors/transform/transform.c @@ -100,6 +100,7 @@ #include "ED_markers.h" #include "ED_util.h" #include "ED_view3d.h" +#include "ED_mesh.h" #include "UI_view2d.h" #include "WM_types.h" @@ -108,6 +109,8 @@ #include "BLI_arithb.h" #include "BLI_blenlib.h" #include "BLI_editVert.h" +#include "BLI_ghash.h" +#include "BLI_linklist.h" #include "PIL_time.h" /* sleep */ @@ -1318,7 +1321,12 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op) if (t->flag & T_MODAL) { ts->prop_mode = t->prop_mode; - ts->proportional = proportional; + + /* only save back if it wasn't automatically disabled */ + if ((t->options & CTX_NO_PET) == 0) + { + ts->proportional = proportional; + } if(t->spacetype == SPACE_VIEW3D) { @@ -1428,6 +1436,9 @@ int initTransform(bContext *C, TransInfo *t, wmOperator *op, wmEvent *event, int case TFM_BONE_ENVELOPE: initBoneEnvelope(t); break; + case TFM_EDGE_SLIDE: + initEdgeSlide(t); + break; case TFM_BONE_ROLL: initBoneRoll(t); break; @@ -4029,6 +4040,692 @@ int BoneEnvelope(TransInfo *t, short mval[2]) return 1; } +/* ******************** Edge Slide *************** */ + +static int createSlideVerts(TransInfo *t) +{ + Mesh *me = t->obedit->data; + EditMesh *em = me->edit_mesh; + EditFace *efa; + EditEdge *eed,*first=NULL,*last=NULL, *temp = NULL; + EditVert *ev, *nearest = NULL; + LinkNode *edgelist = NULL, *vertlist=NULL, *look; + GHash *vertgh; + TransDataSlideVert *tempsv; + float perc = 0, percp = 0,vertdist; // XXX, projectMat[4][4]; + float shiftlabda= 0.0f,len = 0.0f; + int i, j, numsel, numadded=0, timesthrough = 0, vertsel=0, prop=1, cancel = 0,flip=0; + int wasshift = 0; + /* UV correction vars */ + GHash **uvarray= NULL; + SlideData *sld = MEM_callocN(sizeof(*sld), "sld"); + int uvlay_tot= CustomData_number_of_layers(&em->fdata, CD_MTFACE); + int uvlay_idx; + TransDataSlideUv *slideuvs=NULL, *suv=NULL, *suv_last=NULL; + RegionView3D *v3d = t->ar->regiondata; + float projectMat[4][4]; + float start[3] = {0.0f, 0.0f, 0.0f}, end[3] = {0.0f, 0.0f, 0.0f}; + float vec[3]; + //short mval[2], mvalo[2]; + float labda = 0.0f, totvec=0.0; + + if (!v3d) { + /*ok, let's try to survive this*/ + Mat4One(projectMat); + } else { + view3d_get_object_project_mat(v3d, t->obedit, projectMat); + } + + //mvalo[0] = -1; mvalo[1] = -1; + numsel =0; + + // Get number of selected edges and clear some flags + for(eed=em->edges.first;eed;eed=eed->next) { + eed->f1 = 0; + eed->f2 = 0; + if(eed->f & SELECT) numsel++; + } + + for(ev=em->verts.first;ev;ev=ev->next) { + ev->f1 = 0; + } + + //Make sure each edge only has 2 faces + // make sure loop doesn't cross face + for(efa=em->faces.first;efa;efa=efa->next) { + int ct = 0; + if(efa->e1->f & SELECT) { + ct++; + efa->e1->f1++; + if(efa->e1->f1 > 2) { + //BKE_report(op->reports, RPT_ERROR, "3+ face edge"); + return 0; + } + } + if(efa->e2->f & SELECT) { + ct++; + efa->e2->f1++; + if(efa->e2->f1 > 2) { + //BKE_report(op->reports, RPT_ERROR, "3+ face edge"); + return 0; + } + } + if(efa->e3->f & SELECT) { + ct++; + efa->e3->f1++; + if(efa->e3->f1 > 2) { + //BKE_report(op->reports, RPT_ERROR, "3+ face edge"); + return 0; + } + } + if(efa->e4 && efa->e4->f & SELECT) { + ct++; + efa->e4->f1++; + if(efa->e4->f1 > 2) { + //BKE_report(op->reports, RPT_ERROR, "3+ face edge"); + return 0; + } + } + // Make sure loop is not 2 edges of same face + if(ct > 1) { + //BKE_report(op->reports, RPT_ERROR, "Loop crosses itself"); + return 0; + } + } + + // Get # of selected verts + for(ev=em->verts.first;ev;ev=ev->next) { + if(ev->f & SELECT) vertsel++; + } + + // Test for multiple segments + if(vertsel > numsel+1) { + //BKE_report(op->reports, RPT_ERROR, "Please choose a single edge loop"); + return 0; + } + + // Get the edgeloop in order - mark f1 with SELECT once added + for(eed=em->edges.first;eed;eed=eed->next) { + if((eed->f & SELECT) && !(eed->f1 & SELECT)) { + // If this is the first edge added, just put it in + if(!edgelist) { + BLI_linklist_prepend(&edgelist,eed); + numadded++; + first = eed; + last = eed; + eed->f1 = SELECT; + } else { + if(editedge_getSharedVert(eed, last)) { + BLI_linklist_append(&edgelist,eed); + eed->f1 = SELECT; + numadded++; + last = eed; + } else if(editedge_getSharedVert(eed, first)) { + BLI_linklist_prepend(&edgelist,eed); + eed->f1 = SELECT; + numadded++; + first = eed; + } + } + } + if(eed->next == NULL && numadded != numsel) { + eed=em->edges.first; + timesthrough++; + } + + // It looks like there was an unexpected case - Hopefully should not happen + if(timesthrough >= numsel*2) { + BLI_linklist_free(edgelist,NULL); + //BKE_report(op->reports, RPT_ERROR, "Could not order loop"); + return 0; + } + } + + // Put the verts in order in a linklist + look = edgelist; + while(look) { + eed = look->link; + if(!vertlist) { + if(look->next) { + temp = look->next->link; + + //This is the first entry takes care of extra vert + if(eed->v1 != temp->v1 && eed->v1 != temp->v2) { + BLI_linklist_append(&vertlist,eed->v1); + eed->v1->f1 = 1; + } else { + BLI_linklist_append(&vertlist,eed->v2); + eed->v2->f1 = 1; + } + } else { + //This is the case that we only have 1 edge + BLI_linklist_append(&vertlist,eed->v1); + eed->v1->f1 = 1; + } + } + // for all the entries + if(eed->v1->f1 != 1) { + BLI_linklist_append(&vertlist,eed->v1); + eed->v1->f1 = 1; + } else if(eed->v2->f1 != 1) { + BLI_linklist_append(&vertlist,eed->v2); + eed->v2->f1 = 1; + } + look = look->next; + } + + // populate the SlideVerts + + vertgh = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp); + look = vertlist; + while(look) { + i=0; + j=0; + ev = look->link; + tempsv = (struct TransDataSlideVert*)MEM_mallocN(sizeof(struct TransDataSlideVert),"SlideVert"); + tempsv->up = NULL; + tempsv->down = NULL; + tempsv->origvert.co[0] = ev->co[0]; + tempsv->origvert.co[1] = ev->co[1]; + tempsv->origvert.co[2] = ev->co[2]; + tempsv->origvert.no[0] = ev->no[0]; + tempsv->origvert.no[1] = ev->no[1]; + tempsv->origvert.no[2] = ev->no[2]; + // i is total edges that vert is on + // j is total selected edges that vert is on + + for(eed=em->edges.first;eed;eed=eed->next) { + if(eed->v1 == ev || eed->v2 == ev) { + i++; + if(eed->f & SELECT) { + j++; + } + } + } + // If the vert is in the middle of an edge loop, it touches 2 selected edges and 2 unselected edges + if(i == 4 && j == 2) { + for(eed=em->edges.first;eed;eed=eed->next) { + if(editedge_containsVert(eed, ev)) { + if(!(eed->f & SELECT)) { + if(!tempsv->up) { + tempsv->up = eed; + } else if (!(tempsv->down)) { + tempsv->down = eed; + } + } + } + } + } + // If it is on the end of the loop, it touches 1 selected and as least 2 more unselected + if(i >= 3 && j == 1) { + for(eed=em->edges.first;eed;eed=eed->next) { + if(editedge_containsVert(eed, ev) && eed->f & SELECT) { + for(efa = em->faces.first;efa;efa=efa->next) { + if(editface_containsEdge(efa, eed)) { + if(editedge_containsVert(efa->e1, ev) && efa->e1 != eed) { + if(!tempsv->up) { + tempsv->up = efa->e1; + } else if (!(tempsv->down)) { + tempsv->down = efa->e1; + } + } + if(editedge_containsVert(efa->e2, ev) && efa->e2 != eed) { + if(!tempsv->up) { + tempsv->up = efa->e2; + } else if (!(tempsv->down)) { + tempsv->down = efa->e2; + } + } + if(editedge_containsVert(efa->e3, ev) && efa->e3 != eed) { + if(!tempsv->up) { + tempsv->up = efa->e3; + } else if (!(tempsv->down)) { + tempsv->down = efa->e3; + } + } + if(efa->e4) { + if(editedge_containsVert(efa->e4, ev) && efa->e4 != eed) { + if(!tempsv->up) { + tempsv->up = efa->e4; + } else if (!(tempsv->down)) { + tempsv->down = efa->e4; + } + } + } + + } + } + } + } + } + if(i > 4 && j == 2) { + BLI_ghash_free(vertgh, NULL, (GHashValFreeFP)MEM_freeN); + BLI_linklist_free(vertlist,NULL); + BLI_linklist_free(edgelist,NULL); + return 0; + } + BLI_ghash_insert(vertgh,ev,tempsv); + + look = look->next; + } + + // make sure the UPs nad DOWNs are 'faceloops' + // Also find the nearest slidevert to the cursor + + look = vertlist; + nearest = NULL; + vertdist = -1; + while(look) { + tempsv = BLI_ghash_lookup(vertgh,(EditVert*)look->link); + + if(!tempsv->up || !tempsv->down) { + //BKE_report(op->reports, RPT_ERROR, "Missing rails"); + BLI_ghash_free(vertgh, NULL, (GHashValFreeFP)MEM_freeN); + BLI_linklist_free(vertlist,NULL); + BLI_linklist_free(edgelist,NULL); + return 0; + } + + if(me->drawflag & ME_DRAW_EDGELEN) { + if(!(tempsv->up->f & SELECT)) { + tempsv->up->f |= SELECT; + tempsv->up->f2 |= 16; + } else { + tempsv->up->f2 |= ~16; + } + if(!(tempsv->down->f & SELECT)) { + tempsv->down->f |= SELECT; + tempsv->down->f2 |= 16; + } else { + tempsv->down->f2 |= ~16; + } + } + + if(look->next != NULL) { + TransDataSlideVert *sv; + + ev = (EditVert*)look->next->link; + sv = BLI_ghash_lookup(vertgh, ev); + + if(sv) { + float co[3], co2[3], vec[3]; + + ev = (EditVert*)look->link; + + if(!sharesFace(em, tempsv->up,sv->up)) { + EditEdge *swap; + swap = sv->up; + sv->up = sv->down; + sv->down = swap; + } + + if (v3d) { + view3d_project_float(t->ar, tempsv->up->v1->co, co, projectMat); + view3d_project_float(t->ar, tempsv->up->v2->co, co2, projectMat); + } + + if (ev == tempsv->up->v1) { + VecSubf(vec, co, co2); + } else { + VecSubf(vec, co2, co); + } + + VecAddf(start, start, vec); + + if (v3d) { + view3d_project_float(t->ar, tempsv->down->v1->co, co, projectMat); + view3d_project_float(t->ar, tempsv->down->v2->co, co2, projectMat); + } + + if (ev == tempsv->down->v1) { + VecSubf(vec, co2, co); + } else { + VecSubf(vec, co, co2); + } + + VecAddf(end, end, vec); + + totvec += 1.0f; + nearest = (EditVert*)look->link; + } + } + + + + look = look->next; + } + + VecAddf(start, start, end); + VecMulf(start, 0.5*(1.0/totvec)); + VECCOPY(vec, start); + start[0] = t->mval[0]; + start[1] = t->mval[1]; + VecAddf(end, start, vec); + + sld->start[0] = (short) start[0]; + sld->start[1] = (short) start[1]; + sld->end[0] = (short) end[0]; + sld->end[1] = (short) end[1]; + + if (uvlay_tot) { // XXX && (scene->toolsettings->uvcalc_flag & UVCALC_TRANSFORM_CORRECT)) { + int maxnum = 0; + + uvarray = MEM_callocN( uvlay_tot * sizeof(GHash *), "SlideUVs Array"); + sld->totuv = uvlay_tot; + suv_last = slideuvs = MEM_callocN( uvlay_tot * (numadded+1) * sizeof(TransDataSlideUv), "SlideUVs"); /* uvLayers * verts */ + suv = NULL; + + for (uvlay_idx=0; uvlay_idx<uvlay_tot; uvlay_idx++) { + + uvarray[uvlay_idx] = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp); + + for(ev=em->verts.first;ev;ev=ev->next) { + ev->tmp.l = 0; + } + look = vertlist; + while(look) { + float *uv_new; + tempsv = BLI_ghash_lookup(vertgh,(EditVert*)look->link); + + ev = look->link; + suv = NULL; + for(efa = em->faces.first;efa;efa=efa->next) { + if (ev->tmp.l != -1) { /* test for self, in this case its invalid */ + int k=-1; /* face corner */ + + /* Is this vert in the faces corner? */ + if (efa->v1==ev) k=0; + else if (efa->v2==ev) k=1; + else if (efa->v3==ev) k=2; + else if (efa->v4 && efa->v4==ev) k=3; + + if (k != -1) { + MTFace *tf = CustomData_em_get_n(&em->fdata, efa->data, CD_MTFACE, uvlay_idx); + EditVert *ev_up, *ev_down; + + uv_new = tf->uv[k]; + + if (ev->tmp.l) { + if (fabs(suv->origuv[0]-uv_new[0]) > 0.0001 || fabs(suv->origuv[1]-uv_new[1])) { + ev->tmp.l = -1; /* Tag as invalid */ + BLI_linklist_free(suv->fuv_list,NULL); + suv->fuv_list = NULL; + BLI_ghash_remove(uvarray[uvlay_idx],ev, NULL, NULL); + suv = NULL; + break; + } + } else { + ev->tmp.l = 1; + suv = suv_last; + + suv->fuv_list = NULL; + suv->uv_up = suv->uv_down = NULL; + suv->origuv[0] = uv_new[0]; + suv->origuv[1] = uv_new[1]; + + BLI_linklist_prepend(&suv->fuv_list, uv_new); + BLI_ghash_insert(uvarray[uvlay_idx],ev,suv); + + suv_last++; /* advance to next slide UV */ + maxnum++; + } + + /* Now get the uvs along the up or down edge if we can */ + if (suv) { + if (!suv->uv_up) { + ev_up = editedge_getOtherVert(tempsv->up,ev); + if (efa->v1==ev_up) suv->uv_up = tf->uv[0]; + else if (efa->v2==ev_up) suv->uv_up = tf->uv[1]; + else if (efa->v3==ev_up) suv->uv_up = tf->uv[2]; + else if (efa->v4 && efa->v4==ev_up) suv->uv_up = tf->uv[3]; + } + if (!suv->uv_down) { /* if the first face was apart of the up edge, it cant be apart of the down edge */ + ev_down = editedge_getOtherVert(tempsv->down,ev); + if (efa->v1==ev_down) suv->uv_down = tf->uv[0]; + else if (efa->v2==ev_down) suv->uv_down = tf->uv[1]; + else if (efa->v3==ev_down) suv->uv_down = tf->uv[2]; + else if (efa->v4 && efa->v4==ev_down) suv->uv_down = tf->uv[3]; + } + + /* Copy the pointers to the face UV's */ + BLI_linklist_prepend(&suv->fuv_list, uv_new); + } + } + } + } + look = look->next; + } + } /* end uv layer loop */ + } /* end uvlay_tot */ + + sld->uvhash = uvarray; + sld->slideuv = slideuvs; + sld->vhash = vertgh; + sld->nearest = nearest; + sld->vertlist = vertlist; + sld->edgelist = edgelist; + sld->suv_last = suv_last; + sld->uvlay_tot = uvlay_tot; + + // we should have enough info now to slide + + t->customData = sld; + + return 1; +} + +void freeSlideVerts(TransInfo *t) +{ + TransDataSlideUv *suv; + SlideData *sld = t->customData; + int uvlay_idx; + + //BLI_ghash_free(edgesgh, freeGHash, NULL); + BLI_ghash_free(sld->vhash, NULL, (GHashValFreeFP)MEM_freeN); + BLI_linklist_free(sld->vertlist, NULL); + BLI_linklist_free(sld->edgelist, NULL); + + if (sld->uvlay_tot) { + for (uvlay_idx=0; uvlay_idx<sld->uvlay_tot; uvlay_idx++) { + BLI_ghash_free(sld->uvhash[uvlay_idx], NULL, NULL); + } + + suv = sld->suv_last-1; + while (suv >= sld->slideuv) { + if (suv->fuv_list) { + BLI_linklist_free(suv->fuv_list,NULL); + } + suv--; + } + + MEM_freeN(sld->slideuv); + MEM_freeN(sld->uvhash); + } + + MEM_freeN(sld); + t->customData = NULL; +} + +void initEdgeSlide(TransInfo *t) +{ + SlideData *sld; + + t->mode = TFM_EDGE_SLIDE; + t->transform = EdgeSlide; + + createSlideVerts(t); + sld = t->customData; + + if (!sld) + return; + + t->customFree = freeSlideVerts; + + initMouseInputMode(t, &t->mouse, INPUT_CUSTOM_RATIO); + setCustomPoints(t, &t->mouse, sld->end, sld->start); + + t->idx_max = 0; + t->num.idx_max = 0; + t->snap[0] = 0.0f; + t->snap[1] = (float)((5.0/180)*M_PI); + t->snap[2] = t->snap[1] * 0.2f; + + t->flag |= T_NO_CONSTRAINT; +} + +int doEdgeSlide(TransInfo *t, float perc) +{ + Mesh *me= t->obedit->data; + EditMesh *em = me->edit_mesh; + SlideData *sld = t->customData; + EditEdge *first=NULL,*last=NULL, *temp = NULL; + EditVert *ev, *nearest = sld->nearest; + EditVert *centerVert, *upVert, *downVert; + LinkNode *edgelist = sld->edgelist, *vertlist=sld->vertlist, *look; + GHash *vertgh = sld->vhash; + TransDataSlideVert *tempsv; + float shiftlabda= 0.0f,len = 0.0f; + int i = 0, numadded=0, timesthrough = 0, vertsel=0, prop=1, cancel = 0,flip=0; + int wasshift = 0; + /* UV correction vars */ + GHash **uvarray= sld->uvhash; + int uvlay_tot= CustomData_number_of_layers(&em->fdata, CD_MTFACE); + int uvlay_idx; + TransDataSlideUv *slideuvs=sld->slideuv, *suv=sld->slideuv, *suv_last=NULL; + float uv_tmp[2]; + LinkNode *fuv_link; + float labda = 0.0f; + + len = 0.0f; + + tempsv = BLI_ghash_lookup(vertgh,nearest); + + centerVert = editedge_getSharedVert(tempsv->up, tempsv->down); + upVert = editedge_getOtherVert(tempsv->up, centerVert); + downVert = editedge_getOtherVert(tempsv->down, centerVert); + + len = MIN2(perc, VecLenf(upVert->co,downVert->co)); + len = MAX2(len, 0); + + //Adjust Edgeloop + if(prop) { + look = vertlist; + while(look) { + EditVert *tempev; + ev = look->link; + tempsv = BLI_ghash_lookup(vertgh,ev); + + tempev = editedge_getOtherVert((perc>=0)?tempsv->up:tempsv->down, ev); + VecLerpf(ev->co, tempsv->origvert.co, tempev->co, fabs(perc)); + + if (uvlay_tot) { // XXX scene->toolsettings->uvcalc_flag & UVCALC_TRANSFORM_CORRECT) { + for (uvlay_idx=0; uvlay_idx<uvlay_tot; uvlay_idx++) { + suv = BLI_ghash_lookup( uvarray[uvlay_idx], ev ); + if (suv && suv->fuv_list && suv->uv_up && suv->uv_down) { + Vec2Lerpf(uv_tmp, suv->origuv, (perc>=0)?suv->uv_up:suv->uv_down, fabs(perc)); + fuv_link = suv->fuv_list; + while (fuv_link) { + VECCOPY2D(((float *)fuv_link->link), uv_tmp); + fuv_link = fuv_link->next; + } + } + } + } + + look = look->next; + } + } + else { + //Non prop code + look = vertlist; + while(look) { + float newlen; + ev = look->link; + tempsv = BLI_ghash_lookup(vertgh,ev); + newlen = (len / VecLenf(editedge_getOtherVert(tempsv->up,ev)->co,editedge_getOtherVert(tempsv->down,ev)->co)); + if(newlen > 1.0) {newlen = 1.0;} + if(newlen < 0.0) {newlen = 0.0;} + if(flip == 0) { + VecLerpf(ev->co, editedge_getOtherVert(tempsv->down,ev)->co, editedge_getOtherVert(tempsv->up,ev)->co, fabs(newlen)); + if (uvlay_tot) { // XXX scene->toolsettings->uvcalc_flag & UVCALC_TRANSFORM_CORRECT) { + /* dont do anything if no UVs */ + for (uvlay_idx=0; uvlay_idx<uvlay_tot; uvlay_idx++) { + suv = BLI_ghash_lookup( uvarray[uvlay_idx], ev ); + if (suv && suv->fuv_list && suv->uv_up && suv->uv_down) { + Vec2Lerpf(uv_tmp, suv->uv_down, suv->uv_up, fabs(newlen)); + fuv_link = suv->fuv_list; + while (fuv_link) { + VECCOPY2D(((float *)fuv_link->link), uv_tmp); + fuv_link = fuv_link->next; + } + } + } + } + } else{ + VecLerpf(ev->co, editedge_getOtherVert(tempsv->up,ev)->co, editedge_getOtherVert(tempsv->down,ev)->co, fabs(newlen)); + + if (uvlay_tot) { // XXX scene->toolsettings->uvcalc_flag & UVCALC_TRANSFORM_CORRECT) { + /* dont do anything if no UVs */ + for (uvlay_idx=0; uvlay_idx<uvlay_tot; uvlay_idx++) { + suv = BLI_ghash_lookup( uvarray[uvlay_idx], ev ); + if (suv && suv->fuv_list && suv->uv_up && suv->uv_down) { + Vec2Lerpf(uv_tmp, suv->uv_up, suv->uv_down, fabs(newlen)); + fuv_link = suv->fuv_list; + while (fuv_link) { + VECCOPY2D(((float *)fuv_link->link), uv_tmp); + fuv_link = fuv_link->next; + } + } + } + } + } + look = look->next; + } + + } + + return 1; +} + +int EdgeSlide(TransInfo *t, short mval[2]) +{ + TransData *td = t->data; + char str[50]; + float final; + + final = t->values[0]; + + snapGrid(t, &final); + + if (hasNumInput(&t->num)) { + char c[20]; + + applyNumInput(&t->num, &final); + + outputNumInput(&(t->num), c); + + sprintf(str, "Edge Slide Percent: %s", &c[0]); + } + else { + sprintf(str, "Edge Slide Percent: %.2f", final); + } + + CLAMP(final, -1.0f, 1.0f); + + /*do stuff here*/ + if (t->customData) + doEdgeSlide(t, final); + else { + strcpy(str, "Invalid Edge Selection"); + t->state = TRANS_CANCEL; + } + + recalcData(t); + + ED_area_headerprint(t->sa, str); + + return 1; +} /* ******************** EditBone roll *************** */ diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h index e5bd405c0cd..66d5ecd4d66 100644 --- a/source/blender/editors/transform/transform.h +++ b/source/blender/editors/transform/transform.h @@ -32,6 +32,8 @@ #include "ED_transform.h" +#include "BLI_editVert.h" + /* ************************** Types ***************************** */ struct TransInfo; @@ -179,6 +181,31 @@ typedef struct TransDataNla { int handle; /* handle-index: 0 for dummy entry, -1 for start, 1 for end, 2 for both ends */ } TransDataNla; +struct LinkNode; +struct EditEdge; +struct EditVert; +struct GHash; +typedef struct TransDataSlideUv { + float origuv[2]; + float *uv_up, *uv_down; + //float *fuv[4]; + struct LinkNode *fuv_list; +} TransDataSlideUv; + +typedef struct TransDataSlideVert { + struct EditEdge *up, *down; + struct EditVert origvert; +} TransDataSlideVert; + +typedef struct SlideData { + TransDataSlideUv *slideuv, *suv_last; + int totuv, uvlay_tot; + struct GHash *vhash, **uvhash; + struct EditVert *nearest; + struct LinkNode *edgelist, *vertlist; + short start[2], end[2]; +} SlideData; + typedef struct TransData { float dist; /* Distance needed to affect element (for Proportionnal Editing) */ float rdist; /* Distance to the nearest element (for Proportionnal Editing) */ @@ -210,6 +237,7 @@ typedef struct MouseInput { short precision_mval[2]; /* mouse position when precision key was pressed */ int center[2]; float factor; + void *data; /* additional data, if needed by the particular function */ } MouseInput; typedef struct TransInfo { @@ -263,6 +291,7 @@ typedef struct TransInfo { struct Object *poseobj; /* if t->flag & T_POSE, this denotes pose object */ void *customData; /* Per Transform custom data */ + void (*customFree)(struct TransInfo *); /* if a special free function is needed */ /*************** NEW STUFF *********************/ @@ -466,6 +495,9 @@ int BoneEnvelope(TransInfo *t, short mval[2]); void initBoneRoll(TransInfo *t); int BoneRoll(TransInfo *t, short mval[2]); +void initEdgeSlide(TransInfo *t); +int EdgeSlide(TransInfo *t, short mval[2]); + void initTimeTranslate(TransInfo *t); int TimeTranslate(TransInfo *t, short mval[2]); @@ -575,7 +607,8 @@ typedef enum { INPUT_HORIZONTAL_RATIO, INPUT_HORIZONTAL_ABSOLUTE, INPUT_VERTICAL_RATIO, - INPUT_VERTICAL_ABSOLUTE + INPUT_VERTICAL_ABSOLUTE, + INPUT_CUSTOM_RATIO } MouseInputMode; void initMouseInput(TransInfo *t, MouseInput *mi, int center[2], short mval[2]); @@ -583,6 +616,8 @@ void initMouseInputMode(TransInfo *t, MouseInput *mi, MouseInputMode mode); int handleMouseInput(struct TransInfo *t, struct MouseInput *mi, struct wmEvent *event); void applyMouseInput(struct TransInfo *t, struct MouseInput *mi, short mval[2], float output[3]); +void setCustomPoints(TransInfo *t, MouseInput *mi, short start[2], short end[2]); + /*********************** Generics ********************************/ int initTransInfo(struct bContext *C, TransInfo *t, struct wmOperator *op, struct wmEvent *event); @@ -663,6 +698,8 @@ int getTransformOrientation(const struct bContext *C, float normal[3], float pla int createSpaceNormal(float mat[3][3], float normal[3]); int createSpaceNormalTangent(float mat[3][3], float normal[3], float tangent[3]); +void freeSlideVerts(TransInfo *t); + #endif diff --git a/source/blender/editors/transform/transform_conversions.c b/source/blender/editors/transform/transform_conversions.c index 776f2e47d1e..543bbf13fcc 100644 --- a/source/blender/editors/transform/transform_conversions.c +++ b/source/blender/editors/transform/transform_conversions.c @@ -4262,7 +4262,7 @@ static void ObjectToTransData(bContext *C, TransInfo *t, TransData *td, Object * /* it deselects Bases, so we have to call the clear function always after */ static void set_trans_object_base_flags(bContext *C, TransInfo *t) { - Scene *sce = CTX_data_scene(C); + Scene *scene = CTX_data_scene(C); View3D *v3d = t->view; /* @@ -4279,15 +4279,15 @@ static void set_trans_object_base_flags(bContext *C, TransInfo *t) copy_baseflags(t->scene); /* handle pending update events, otherwise they got copied below */ - for (base= sce->base.first; base; base= base->next) { + for (base= scene->base.first; base; base= base->next) { if(base->object->recalc) object_handle_update(t->scene, base->object); } - for (base= sce->base.first; base; base= base->next) { + for (base= scene->base.first; base; base= base->next) { base->flag &= ~BA_WAS_SEL; - if(TESTBASELIB(v3d, base)) { + if(TESTBASELIB_BGMODE(v3d, base)) { Object *ob= base->object; Object *parsel= ob->parent; @@ -4319,7 +4319,7 @@ static void set_trans_object_base_flags(bContext *C, TransInfo *t) /* and we store them temporal in base (only used for transform code) */ /* this because after doing updates, the object->recalc is cleared */ - for (base= sce->base.first; base; base= base->next) { + for (base= scene->base.first; base; base= base->next) { if(base->object->recalc & OB_RECALC_OB) base->flag |= BA_HAS_RECALC_OB; if(base->object->recalc & OB_RECALC_DATA) @@ -5289,7 +5289,7 @@ void createTransData(bContext *C, TransInfo *t) { if(ob_armature->type==OB_ARMATURE) { - if(ob_armature->mode & OB_MODE_POSE) + if((ob_armature->mode & OB_MODE_POSE) && ob_armature == modifiers_isDeformedByArmature(ob)) { createTransPose(C, t, ob_armature); break; @@ -5312,6 +5312,8 @@ void createTransData(bContext *C, TransInfo *t) } else { t->flag &= ~T_PROP_EDIT; /* no proportional edit in object mode */ + t->options |= CTX_NO_PET; + createTransObject(C, t); t->flag |= T_OBJECT; @@ -5319,7 +5321,7 @@ void createTransData(bContext *C, TransInfo *t) { View3D *v3d = t->view; RegionView3D *rv3d = CTX_wm_region_view3d(C); - if((t->flag & T_OBJECT) && v3d->camera == OBACT && rv3d->persp==V3D_CAMOB) + if(rv3d && (t->flag & T_OBJECT) && v3d->camera == OBACT && rv3d->persp==V3D_CAMOB) { t->flag |= T_CAMERA; } diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c index 0b7029adde0..ea5653dc130 100644 --- a/source/blender/editors/transform/transform_generics.c +++ b/source/blender/editors/transform/transform_generics.c @@ -978,51 +978,60 @@ int initTransInfo (bContext *C, TransInfo *t, wmOperator *op, wmEvent *event) } } - /* setting PET flag */ - if (op && RNA_struct_find_property(op->ptr, "proportional") && RNA_property_is_set(op->ptr, "proportional")) + /* setting PET flag only if property exist in operator. Otherwise, assume it's not supported */ + if (op && RNA_struct_find_property(op->ptr, "proportional")) { - switch(RNA_enum_get(op->ptr, "proportional")) + if (RNA_property_is_set(op->ptr, "proportional")) { - case 2: /* XXX connected constant */ - t->flag |= T_PROP_CONNECTED; - case 1: /* XXX prop on constant */ - t->flag |= T_PROP_EDIT; - break; + switch(RNA_enum_get(op->ptr, "proportional")) + { + case 2: /* XXX connected constant */ + t->flag |= T_PROP_CONNECTED; + case 1: /* XXX prop on constant */ + t->flag |= T_PROP_EDIT; + break; + } } - } - else - { - if ((t->options & CTX_NO_PET) == 0 && (ts->proportional)) { - t->flag |= T_PROP_EDIT; + else + { + if ((t->options & CTX_NO_PET) == 0 && (ts->proportional)) { + t->flag |= T_PROP_EDIT; - if(ts->proportional == 2) - t->flag |= T_PROP_CONNECTED; // yes i know, has to become define + if(ts->proportional == 2) + t->flag |= T_PROP_CONNECTED; // yes i know, has to become define + } } - } - if (op && RNA_struct_find_property(op->ptr, "proportional_size") && RNA_property_is_set(op->ptr, "proportional_size")) - { - t->prop_size = RNA_float_get(op->ptr, "proportional_size"); - } - else - { - t->prop_size = ts->proportional_size; - } + if (op && RNA_struct_find_property(op->ptr, "proportional_size") && RNA_property_is_set(op->ptr, "proportional_size")) + { + t->prop_size = RNA_float_get(op->ptr, "proportional_size"); + } + else + { + t->prop_size = ts->proportional_size; + } - if (op && RNA_struct_find_property(op->ptr, "proportional_editing_falloff") && RNA_property_is_set(op->ptr, "proportional_editing_falloff")) - { - t->prop_mode = RNA_enum_get(op->ptr, "proportional_editing_falloff"); + + /* TRANSFORM_FIX_ME rna restrictions */ + if (t->prop_size <= 0) + { + t->prop_size = 1.0f; + } + + if (op && RNA_struct_find_property(op->ptr, "proportional_editing_falloff") && RNA_property_is_set(op->ptr, "proportional_editing_falloff")) + { + t->prop_mode = RNA_enum_get(op->ptr, "proportional_editing_falloff"); + } + else + { + t->prop_mode = ts->prop_mode; + } } - else + else /* add not pet option to context when not available */ { - t->prop_mode = ts->prop_mode; + t->options |= CTX_NO_PET; } - /* TRANSFORM_FIX_ME rna restrictions */ - if (t->prop_size <= 0) - { - t->prop_size = 1.0f; - } setTransformViewMatrices(t); initNumInput(&t->num); @@ -1052,7 +1061,7 @@ void postTrans (TransInfo *t) } MEM_freeN(t->data); } - + if (t->ext) MEM_freeN(t->ext); if (t->data2d) { MEM_freeN(t->data2d); @@ -1065,8 +1074,18 @@ void postTrans (TransInfo *t) ED_uvedit_live_unwrap_end(t->state == TRANS_CANCEL); } else if(ELEM(t->spacetype, SPACE_ACTION, SPACE_NLA)) { - if (t->customData) - MEM_freeN(t->customData); + } + + if (t->mouse.data) + { + MEM_freeN(t->mouse.data); + } + + if (t->customFree) { + t->customFree(t); + } + else if (t->customData) { + MEM_freeN(t->customData); } } diff --git a/source/blender/editors/transform/transform_input.c b/source/blender/editors/transform/transform_input.c index 6bd0a8c8d42..83d4a314057 100644 --- a/source/blender/editors/transform/transform_input.c +++ b/source/blender/editors/transform/transform_input.c @@ -34,7 +34,7 @@ #include "transform.h" - +#include "MEM_guardedalloc.h" /* ************************** INPUT FROM MOUSE *************************** */ @@ -163,6 +163,47 @@ void InputVerticalAbsolute(TransInfo *t, MouseInput *mi, short mval[2], float ou output[0] = Inpf(t->viewinv[1], vec) * 2.0f; } +void setCustomPoints(TransInfo *t, MouseInput *mi, short start[2], short end[2]) +{ + short *data = mi->data; + + data[0] = start[0]; + data[1] = start[1]; + data[2] = end[0]; + data[3] = end[1]; +} + +void InputCustomRatio(TransInfo *t, MouseInput *mi, short mval[2], float output[3]) +{ + float length; + float distance; + short *data = mi->data; + short dx, dy; + + dx = data[2] - data[0]; + dy = data[3] - data[1]; + + length = (float)sqrtf(dx*dx + dy*dy); + + if (mi->precision) { + /* deal with Shift key by adding motion / 10 to motion before shift press */ + short mdx, mdy; + mdx = (mi->precision_mval[0] + (float)(mval[0] - mi->precision_mval[0]) / 10.0f) - data[2]; + mdy = (mi->precision_mval[1] + (float)(mval[1] - mi->precision_mval[1]) / 10.0f) - data[3]; + + distance = (mdx*dx + mdy*dy) / length; + } + else { + short mdx, mdy; + mdx = mval[0] - data[2]; + mdy = mval[1] - data[3]; + + distance = (mdx*dx + mdy*dy) / length; + } + + output[0] = distance / length; +} + void InputAngle(TransInfo *t, MouseInput *mi, short mval[2], float output[3]) { double dx2 = mval[0] - mi->center[0]; @@ -291,6 +332,11 @@ void initMouseInputMode(TransInfo *t, MouseInput *mi, MouseInputMode mode) mi->apply = InputVerticalAbsolute; t->helpline = HLP_VARROW; break; + case INPUT_CUSTOM_RATIO: + mi->apply = InputCustomRatio; + t->helpline = HLP_NONE; + mi->data = MEM_callocN(sizeof(short) * 4, "custom points"); + break; case INPUT_NONE: default: mi->apply = NULL; diff --git a/source/blender/editors/transform/transform_ops.c b/source/blender/editors/transform/transform_ops.c index f9597b81114..f369fba79df 100644 --- a/source/blender/editors/transform/transform_ops.c +++ b/source/blender/editors/transform/transform_ops.c @@ -99,6 +99,7 @@ char OP_SHRINK_FATTEN[] = "TFM_OT_shrink_fatten"; char OP_TILT[] = "TFM_OT_tilt"; char OP_TRACKBALL[] = "TFM_OT_trackball"; char OP_MIRROR[] = "TFM_OT_mirror"; +char OP_EDGE_SLIDE[] = "TFM_OT_edge_slide"; TransformModeItem transform_modes[] = @@ -113,6 +114,7 @@ TransformModeItem transform_modes[] = {OP_TILT, TFM_TILT}, {OP_TRACKBALL, TFM_TRACKBALL}, {OP_MIRROR, TFM_MIRROR}, + {OP_EDGE_SLIDE, TFM_EDGE_SLIDE}, {NULL, 0} }; @@ -523,7 +525,7 @@ void TFM_OT_tosphere(struct wmOperatorType *ot) ot->cancel = transform_cancel; ot->poll = ED_operator_areaactive; - RNA_def_float_percentage(ot->srna, "value", 0, 0, 1, "Percentage", "", 0, 1); + RNA_def_float_factor(ot->srna, "value", 0, 0, 1, "Factor", "", 0, 1); Properties_Proportional(ot); @@ -549,6 +551,26 @@ void TFM_OT_mirror(struct wmOperatorType *ot) Properties_Constraints(ot); } +void TFM_OT_edge_slide(struct wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Edge Slide"; + ot->description= "Slide an edge loop along a mesh."; + ot->idname = OP_EDGE_SLIDE; + ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO|OPTYPE_BLOCKING; + + /* api callbacks */ + ot->invoke = transform_invoke; + ot->exec = transform_exec; + ot->modal = transform_modal; + ot->cancel = transform_cancel; + ot->poll = ED_operator_editmesh; + + RNA_def_float_factor(ot->srna, "value", 0, -1.0f, 1.0f, "Factor", "", -1.0f, 1.0f); + + RNA_def_boolean(ot->srna, "mirror", 0, "Mirror Editing", ""); +} + void TFM_OT_transform(struct wmOperatorType *ot) { static EnumPropertyItem transform_mode_types[] = { @@ -578,6 +600,7 @@ void TFM_OT_transform(struct wmOperatorType *ot) {TFM_BEVEL, "BEVEL", 0, "Bevel", ""}, {TFM_BWEIGHT, "BWEIGHT", 0, "Bweight", ""}, {TFM_ALIGN, "ALIGN", 0, "Align", ""}, + {TFM_EDGE_SLIDE, "EDGESLIDE", 0, "Edge Slide", ""}, {0, NULL, 0, NULL, NULL} }; @@ -617,6 +640,7 @@ void transform_operatortypes(void) WM_operatortype_append(TFM_OT_tilt); WM_operatortype_append(TFM_OT_trackball); WM_operatortype_append(TFM_OT_mirror); + WM_operatortype_append(TFM_OT_edge_slide); WM_operatortype_append(TFM_OT_select_orientation); } diff --git a/source/blender/editors/transform/transform_orientations.c b/source/blender/editors/transform/transform_orientations.c index 9416425704f..d82be842596 100644 --- a/source/blender/editors/transform/transform_orientations.c +++ b/source/blender/editors/transform/transform_orientations.c @@ -353,7 +353,8 @@ void BIF_selectTransformOrientation(bContext *C, TransformOrientation *target) { void BIF_selectTransformOrientationValue(bContext *C, int orientation) { View3D *v3d = CTX_wm_view3d(C); - v3d->twmode = orientation; + if(v3d) /* currently using generic poll */ + v3d->twmode = orientation; } EnumPropertyItem *BIF_enumTransformOrientation(bContext *C) diff --git a/source/blender/editors/uvedit/uvedit_ops.c b/source/blender/editors/uvedit/uvedit_ops.c index 611eee00d79..9216cfb5cdc 100644 --- a/source/blender/editors/uvedit/uvedit_ops.c +++ b/source/blender/editors/uvedit/uvedit_ops.c @@ -180,7 +180,13 @@ static void uvedit_pixel_to_float(SpaceImage *sima, float *dist, float pixeldist { int width, height; - ED_space_image_size(sima, &width, &height); + if(sima) { + ED_space_image_size(sima, &width, &height); + } + else { + width= 256; + height= 256; + } dist[0]= pixeldist/width; dist[1]= pixeldist/height; @@ -1097,11 +1103,11 @@ static int stitch_exec(bContext *C, wmOperator *op) if(RNA_boolean_get(op->ptr, "use_limit")) { UvVertMap *vmap; UvMapVert *vlist, *iterv; - float newuv[2], limit[2], pixels; + float newuv[2], limit[2]; int a, vtot; - pixels= RNA_float_get(op->ptr, "limit"); - uvedit_pixel_to_float(sima, limit, pixels); + limit[0]= RNA_float_get(op->ptr, "limit"); + limit[1]= limit[0]; EM_init_index_arrays(em, 0, 0, 1); vmap= EM_make_uv_vert_map(em, 1, 0, limit); @@ -1255,7 +1261,7 @@ void UV_OT_stitch(wmOperatorType *ot) /* properties */ RNA_def_boolean(ot->srna, "use_limit", 1, "Use Limit", "Stitch UVs within a specified limit distance."); - RNA_def_float(ot->srna, "limit", 20.0, 0.0f, FLT_MAX, "Limit", "Limit distance in image pixels.", -FLT_MAX, FLT_MAX); + RNA_def_float(ot->srna, "limit", 0.01f, 0.0f, FLT_MAX, "Limit", "Limit distance in normalized coordinates.", -FLT_MAX, FLT_MAX); } /* ******************** (de)select all operator **************** */ @@ -1439,7 +1445,7 @@ static int mouse_select(bContext *C, float co[2], int extend, int loop) else { sync= 0; selectmode= ts->uv_selectmode; - sticky= sima->sticky; + sticky= (sima)? sima->sticky: 1; } /* find nearest element */ @@ -2471,13 +2477,18 @@ static int snap_uvs_to_adjacent_unselected(Scene *scene, Image *ima, Object *obe static int snap_uvs_to_pixels(SpaceImage *sima, Scene *scene, Object *obedit) { EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data); - Image *ima= sima->image; + Image *ima; EditFace *efa; MTFace *tface; int width= 0, height= 0; float w, h; short change = 0; + if(!sima) + return 0; + + ima= sima->image; + ED_space_image_size(sima, &width, &height); w = (float)width; h = (float)height; @@ -2657,6 +2668,7 @@ static int hide_exec(bContext *C, wmOperator *op) EditFace *efa; MTFace *tf; int swap= RNA_boolean_get(op->ptr, "unselected"); + int facemode= sima ? sima->flag & SI_SELACTFACE : 0; if(ts->uv_flag & UV_SYNC_SELECTION) { EM_hide_mesh(em, swap); @@ -2670,7 +2682,7 @@ static int hide_exec(bContext *C, wmOperator *op) for(efa= em->faces.first; efa; efa= efa->next) { if(efa->f & SELECT) { tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); - if(sima->flag & SI_SELACTFACE) { + if(facemode) { /* Pretend face mode */ if(( (efa->v4==NULL && ( tf->flag & (TF_SEL1|TF_SEL2|TF_SEL3)) == (TF_SEL1|TF_SEL2|TF_SEL3) ) || @@ -2715,7 +2727,7 @@ static int hide_exec(bContext *C, wmOperator *op) if(efa->f & SELECT) { tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); - if(sima->flag & SI_SELACTFACE) { + if(facemode) { if( (efa->v4==NULL && ( tf->flag & (TF_SEL1|TF_SEL2|TF_SEL3)) == (TF_SEL1|TF_SEL2|TF_SEL3) ) || ( tf->flag & (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4)) == (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4) ) { @@ -2799,6 +2811,8 @@ static int reveal_exec(bContext *C, wmOperator *op) EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data); EditFace *efa; MTFace *tf; + int facemode= sima ? sima->flag & SI_SELACTFACE : 0; + int stickymode= sima ? (sima->sticky != SI_STICKY_DISABLE) : 1; /* call the mesh function if we are in mesh sync sel */ if(ts->uv_flag & UV_SYNC_SELECTION) { @@ -2809,7 +2823,7 @@ static int reveal_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } - if(sima->flag & SI_SELACTFACE) { + if(facemode) { if(em->selectmode == SCE_SELECT_FACE) { for(efa= em->faces.first; efa; efa= efa->next) { if(!(efa->h) && !(efa->f & SELECT)) { @@ -2821,7 +2835,7 @@ static int reveal_exec(bContext *C, wmOperator *op) } else { /* enable adjacent faces to have disconnected UV selections if sticky is disabled */ - if(sima->sticky == SI_STICKY_DISABLE) { + if(!stickymode) { for(efa= em->faces.first; efa; efa= efa->next) { if(!(efa->h) && !(efa->f & SELECT)) { /* All verts must be unselected for the face to be selected in the UV view */ diff --git a/source/blender/editors/uvedit/uvedit_unwrap_ops.c b/source/blender/editors/uvedit/uvedit_unwrap_ops.c index b848bd4fb09..c7258e616fa 100644 --- a/source/blender/editors/uvedit/uvedit_unwrap_ops.c +++ b/source/blender/editors/uvedit/uvedit_unwrap_ops.c @@ -423,7 +423,7 @@ void UV_OT_minimize_stretch(wmOperatorType *ot) /* properties */ RNA_def_boolean(ot->srna, "fill_holes", 1, "Fill Holes", "Virtual fill holes in mesh before unwrapping, to better avoid overlaps and preserve symmetry."); - RNA_def_float_percentage(ot->srna, "blend", 0.0f, 0.0f, 1.0f, "Blend", "Blend factor between stretch minimized and original.", 0.0f, 1.0f); + RNA_def_float_factor(ot->srna, "blend", 0.0f, 0.0f, 1.0f, "Blend", "Blend factor between stretch minimized and original.", 0.0f, 1.0f); RNA_def_int(ot->srna, "iterations", 0, 0, INT_MAX, "Iterations", "Number of iterations to run, 0 is unlimited when run interactively.", 0, 100); } diff --git a/source/blender/freestyle/intern/app_blender/AppConfig.cpp b/source/blender/freestyle/intern/app_blender/AppConfig.cpp index 9d31d4660d4..9ef14321624 100755 --- a/source/blender/freestyle/intern/app_blender/AppConfig.cpp +++ b/source/blender/freestyle/intern/app_blender/AppConfig.cpp @@ -33,7 +33,7 @@ Path* Path::_pInstance = 0; Path::Path() { // get the root directory //soc - setRootDir( BLI_gethome_folder("scripts") ); + setRootDir( BLI_gethome_folder("scripts", BLI_GETHOME_ALL) ); _pInstance = this; } diff --git a/source/blender/ikplugin/BIK_api.h b/source/blender/ikplugin/BIK_api.h new file mode 100644 index 00000000000..a259d0aa62a --- /dev/null +++ b/source/blender/ikplugin/BIK_api.h @@ -0,0 +1,93 @@ +/** + * $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. + * + * Original author: Benoit Bolsee + * Contributor(s): + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef BIK_API_H +#define BIK_API_H + +#ifdef __cplusplus +extern "C" { +#endif + +struct Object; +struct bPoseChannel; +struct bPose; +struct bArmature; +struct Scene; +struct bConstraint; + +enum BIK_ParamType { + BIK_PARAM_TYPE_FLOAT = 0, + BIK_PARAM_TYPE_INT, + BIK_PARAM_TYPE_STRING, +}; + +struct BIK_ParamValue { + short type; /* BIK_PARAM_TYPE_.. */ + short length; /* for string, does not include terminating 0 */ + union { + float f[8]; + int i[8]; + char s[32]; + } value; +}; +typedef struct BIK_ParamValue BIK_ParamValue; + +void BIK_initialize_tree(struct Scene *scene, struct Object *ob, float ctime); +void BIK_execute_tree(struct Scene *scene, struct Object *ob, struct bPoseChannel *pchan, float ctime); +void BIK_release_tree(struct Scene *scene, struct Object *ob, float ctime); +void BIK_clear_data(struct bPose *pose); +void BIK_clear_cache(struct bPose *pose); +void BIK_update_param(struct bPose *pose); +void BIK_test_constraint(struct Object *ob, struct bConstraint *cons); +// not yet implemented +int BIK_get_constraint_param(struct bPose *pose, struct bConstraint *cons, int id, BIK_ParamValue *value); +int BIK_get_channel_param(struct bPose *pose, struct bPoseChannel *pchan, int id, BIK_ParamValue *value); +int BIK_get_solver_param(struct bPose *pose, struct bPoseChannel *pchan, int id, BIK_ParamValue *value); + +// number of solver available +// 0 = iksolver +// 1 = iTaSC +#define BIK_SOLVER_COUNT 2 + +/* for use in BIK_get_constraint_param */ +#define BIK_PARAM_CONSTRAINT_ERROR 0 + +/* for use in BIK_get_channel_param */ +#define BIK_PARAM_CHANNEL_JOINT 0 + +/* for use in BIK_get_solver_param */ +#define BIK_PARAM_SOLVER_RANK 0 +#define BIK_PARAM_SOLVER_ITERATION 1 + +#ifdef __cplusplus +} +#endif + +#endif // BIK_API_H + diff --git a/source/blender/ikplugin/CMakeLists.txt b/source/blender/ikplugin/CMakeLists.txt new file mode 100644 index 00000000000..5790d4ef12f --- /dev/null +++ b/source/blender/ikplugin/CMakeLists.txt @@ -0,0 +1,35 @@ +# $Id: CMakeLists.txt 20156 2009-05-11 16:31:30Z ben2610 $ +# ***** 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) 2006, Blender Foundation +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): Jacques Beaurain. +# +# ***** END GPL LICENSE BLOCK ***** + +FILE(GLOB SRC intern/*.c intern/*.cpp) + +SET(INC + ../../../intern/guardedalloc ../../../intern/iksolver/extern + ../../../intern/itasc ../../../extern/Eigen2 + ../blenlib ../makesdna ../blenkernel ../include ../ikplugin +) + +BLENDERLIB(bf_ikplugin "${SRC}" "${INC}") diff --git a/source/blender/ikplugin/Makefile b/source/blender/ikplugin/Makefile new file mode 100644 index 00000000000..370ed418464 --- /dev/null +++ b/source/blender/ikplugin/Makefile @@ -0,0 +1,31 @@ +# ***** 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 ***** +# +# Bounces make to subdirectories. + +SOURCEDIR = source/blender/ikplugin +DIRS = intern + +include nan_subdirs.mk diff --git a/source/blender/ikplugin/SConscript b/source/blender/ikplugin/SConscript new file mode 100644 index 00000000000..a745a93077a --- /dev/null +++ b/source/blender/ikplugin/SConscript @@ -0,0 +1,9 @@ +#!/usr/bin/python +Import ('env') + +sources = env.Glob('intern/*.c') + env.Glob('intern/*.cpp') + +incs = '#/intern/guardedalloc #/intern/iksolver/extern ../makesdna ../blenlib' +incs += ' ../blenkernel ../include ../ikplugin #/intern/itasc #/extern/Eigen2' + +env.BlenderLib ( 'bf_ikplugin', sources, Split(incs), [], libtype=['core','player'], priority=[180, 190] ) diff --git a/source/blender/ikplugin/intern/Makefile b/source/blender/ikplugin/intern/Makefile new file mode 100644 index 00000000000..0c54e5d1264 --- /dev/null +++ b/source/blender/ikplugin/intern/Makefile @@ -0,0 +1,51 @@ +# ***** 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 ***** +# +# + +LIBNAME = ikplugin +DIR = $(OCGDIR)/blender/ikplugin + +include nan_compile.mk + +CFLAGS += $(LEVEL_1_C_WARNINGS) +CFLAGS += -I$(NAN_GUARDEDALLOC)/include +CFLAGS += -I../../makesdna +CFLAGS += -I../../blenkernel +CFLAGS += -I../../blenlib +CFLAGS += -I../../include +CFLAGS += -I../../../../intern/itasc +CFLAGS += -I../../../../extern/Eigen2 +CFLAGS += -I.. + +CPPFLAGS += -I$(NAN_GUARDEDALLOC)/include +CPPFLAGS += -I$(NAN_IKSOLVER)/include +CPPFLAGS += -I../../makesdna +CPPFLAGS += -I../../blenkernel +CPPFLAGS += -I../../blenlib +CPPFLAGS += -I../../include +CPPFLAGS += -I../../../../intern/itasc +CPPFLAGS += -I../../../../extern/Eigen2 +CPPFLAGS += -I.. diff --git a/source/blender/ikplugin/intern/ikplugin_api.c b/source/blender/ikplugin/intern/ikplugin_api.c new file mode 100644 index 00000000000..f106302dbaf --- /dev/null +++ b/source/blender/ikplugin/intern/ikplugin_api.c @@ -0,0 +1,138 @@ +/** + * $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. + * + * Original author: Benoit Bolsee + * Contributor(s): + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "MEM_guardedalloc.h" + +#include "BIK_api.h" +#include "BLI_blenlib.h" +#include "BLI_arithb.h" + +#include "BKE_armature.h" +#include "BKE_utildefines.h" +#include "DNA_object_types.h" +#include "DNA_action_types.h" +#include "DNA_scene_types.h" +#include "DNA_constraint_types.h" +#include "DNA_armature_types.h" + +#include "ikplugin_api.h" +#include "iksolver_plugin.h" +#include "itasc_plugin.h" + + +static IKPlugin ikplugin_tab[BIK_SOLVER_COUNT] = { + /* Legacy IK solver */ + { + iksolver_initialize_tree, + iksolver_execute_tree, + NULL, + NULL, + NULL, + NULL, + NULL, + }, + /* iTaSC IK solver */ + { + itasc_initialize_tree, + itasc_execute_tree, + itasc_release_tree, + itasc_clear_data, + itasc_clear_cache, + itasc_update_param, + itasc_test_constraint, + } +}; + + +static IKPlugin *get_plugin(bPose *pose) +{ + if (!pose || pose->iksolver < 0 || pose->iksolver >= BIK_SOLVER_COUNT) + return NULL; + + return &ikplugin_tab[pose->iksolver]; +} + +/*----------------------------------------*/ +/* Plugin API */ + +void BIK_initialize_tree(Scene *scene, Object *ob, float ctime) +{ + IKPlugin *plugin = get_plugin(ob->pose); + + if (plugin && plugin->initialize_tree_func) + plugin->initialize_tree_func(scene, ob, ctime); +} + +void BIK_execute_tree(struct Scene *scene, Object *ob, bPoseChannel *pchan, float ctime) +{ + IKPlugin *plugin = get_plugin(ob->pose); + + if (plugin && plugin->execute_tree_func) + plugin->execute_tree_func(scene, ob, pchan, ctime); +} + +void BIK_release_tree(struct Scene *scene, Object *ob, float ctime) +{ + IKPlugin *plugin = get_plugin(ob->pose); + + if (plugin && plugin->release_tree_func) + plugin->release_tree_func(scene, ob, ctime); +} + +void BIK_clear_data(struct bPose *pose) +{ + IKPlugin *plugin = get_plugin(pose); + + if (plugin && plugin->remove_armature_func) + plugin->remove_armature_func(pose); +} + +void BIK_clear_cache(struct bPose *pose) +{ + IKPlugin *plugin = get_plugin(pose); + + if (plugin && plugin->clear_cache) + plugin->clear_cache(pose); +} + +void BIK_update_param(struct bPose *pose) +{ + IKPlugin *plugin = get_plugin(pose); + + if (plugin && plugin->update_param) + plugin->update_param(pose); +} + +void BIK_test_constraint(struct Object *ob, struct bConstraint *cons) +{ + IKPlugin *plugin = get_plugin(ob->pose); + + if (plugin && plugin->test_constraint) + plugin->test_constraint(ob, cons); +} diff --git a/source/blender/ikplugin/intern/ikplugin_api.h b/source/blender/ikplugin/intern/ikplugin_api.h new file mode 100644 index 00000000000..cc4dff4ec75 --- /dev/null +++ b/source/blender/ikplugin/intern/ikplugin_api.h @@ -0,0 +1,60 @@ +/** + * $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. + * + * Original author: Benoit Bolsee + * Contributor(s): + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef IKPLUGIN_API_H +#define IKPLUGIN_API_H + +#ifdef __cplusplus +extern "C" { +#endif + +struct Object; +struct bPoseChannel; +struct bArmature; +struct Scene; + + +struct IKPlugin { + void (*initialize_tree_func)(struct Scene *scene, struct Object *ob, float ctime); + void (*execute_tree_func)(struct Scene *scene, struct Object *ob, struct bPoseChannel *pchan, float ctime); + void (*release_tree_func)(struct Scene *scene, struct Object *ob, float ctime); + void (*remove_armature_func)(struct bPose *pose); + void (*clear_cache)(struct bPose *pose); + void (*update_param)(struct bPose *pose); + void (*test_constraint)(struct Object *ob, struct bConstraint *cons); +}; + +typedef struct IKPlugin IKPlugin; + +#ifdef __cplusplus +} +#endif + +#endif // IKPLUGIN_API_H + diff --git a/source/blender/ikplugin/intern/iksolver_plugin.c b/source/blender/ikplugin/intern/iksolver_plugin.c new file mode 100644 index 00000000000..68afbcd0db2 --- /dev/null +++ b/source/blender/ikplugin/intern/iksolver_plugin.c @@ -0,0 +1,530 @@ +/** + * $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. + * + * Original author: Benoit Bolsee + * Contributor(s): + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "MEM_guardedalloc.h" + +#include "BIK_api.h" +#include "BLI_blenlib.h" +#include "BLI_arithb.h" + +#include "BKE_armature.h" +#include "BKE_constraint.h" +#include "BKE_utildefines.h" +#include "DNA_object_types.h" +#include "DNA_action_types.h" +#include "DNA_constraint_types.h" +#include "DNA_armature_types.h" + +#include "IK_solver.h" +#include "iksolver_plugin.h" + +#include <string.h> /* memcpy */ + +/* ********************** THE IK SOLVER ******************* */ + +/* allocates PoseTree, and links that to root bone/channel */ +/* Note: detecting the IK chain is duplicate code... in drawarmature.c and in transform_conversions.c */ +static void initialize_posetree(struct Object *ob, bPoseChannel *pchan_tip) +{ + bPoseChannel *curchan, *pchan_root=NULL, *chanlist[256], **oldchan; + PoseTree *tree; + PoseTarget *target; + bConstraint *con; + bKinematicConstraint *data; + int a, segcount= 0, size, newsize, *oldparent, parent; + + /* find IK constraint, and validate it */ + for(con= pchan_tip->constraints.first; con; con= con->next) { + if(con->type==CONSTRAINT_TYPE_KINEMATIC) { + data=(bKinematicConstraint*)con->data; + if (data->flag & CONSTRAINT_IK_AUTO) break; + if (data->tar==NULL) continue; + if (data->tar->type==OB_ARMATURE && data->subtarget[0]==0) continue; + if ((con->flag & (CONSTRAINT_DISABLE|CONSTRAINT_OFF))==0 && (con->enforce!=0.0)) break; + } + } + if(con==NULL) return; + + /* exclude tip from chain? */ + if(!(data->flag & CONSTRAINT_IK_TIP)) + pchan_tip= pchan_tip->parent; + + /* Find the chain's root & count the segments needed */ + for (curchan = pchan_tip; curchan; curchan=curchan->parent){ + pchan_root = curchan; + + curchan->flag |= POSE_CHAIN; // don't forget to clear this + chanlist[segcount]=curchan; + segcount++; + + if(segcount==data->rootbone || segcount>255) break; // 255 is weak + } + if (!segcount) return; + + /* setup the chain data */ + + /* we make tree-IK, unless all existing targets are in this chain */ + for(tree= pchan_root->iktree.first; tree; tree= tree->next) { + for(target= tree->targets.first; target; target= target->next) { + curchan= tree->pchan[target->tip]; + if(curchan->flag & POSE_CHAIN) + curchan->flag &= ~POSE_CHAIN; + else + break; + } + if(target) break; + } + + /* create a target */ + target= MEM_callocN(sizeof(PoseTarget), "posetarget"); + target->con= con; + pchan_tip->flag &= ~POSE_CHAIN; + + if(tree==NULL) { + /* make new tree */ + tree= MEM_callocN(sizeof(PoseTree), "posetree"); + + tree->iterations= data->iterations; + tree->totchannel= segcount; + tree->stretch = (data->flag & CONSTRAINT_IK_STRETCH); + + tree->pchan= MEM_callocN(segcount*sizeof(void*), "ik tree pchan"); + tree->parent= MEM_callocN(segcount*sizeof(int), "ik tree parent"); + for(a=0; a<segcount; a++) { + tree->pchan[a]= chanlist[segcount-a-1]; + tree->parent[a]= a-1; + } + target->tip= segcount-1; + + /* AND! link the tree to the root */ + BLI_addtail(&pchan_root->iktree, tree); + } + else { + tree->iterations= MAX2(data->iterations, tree->iterations); + tree->stretch= tree->stretch && !(data->flag & CONSTRAINT_IK_STRETCH); + + /* skip common pose channels and add remaining*/ + size= MIN2(segcount, tree->totchannel); + for(a=0; a<size && tree->pchan[a]==chanlist[segcount-a-1]; a++); + parent= a-1; + + segcount= segcount-a; + target->tip= tree->totchannel + segcount - 1; + + if (segcount > 0) { + /* resize array */ + newsize= tree->totchannel + segcount; + oldchan= tree->pchan; + oldparent= tree->parent; + + tree->pchan= MEM_callocN(newsize*sizeof(void*), "ik tree pchan"); + tree->parent= MEM_callocN(newsize*sizeof(int), "ik tree parent"); + memcpy(tree->pchan, oldchan, sizeof(void*)*tree->totchannel); + memcpy(tree->parent, oldparent, sizeof(int)*tree->totchannel); + MEM_freeN(oldchan); + MEM_freeN(oldparent); + + /* add new pose channels at the end, in reverse order */ + for(a=0; a<segcount; a++) { + tree->pchan[tree->totchannel+a]= chanlist[segcount-a-1]; + tree->parent[tree->totchannel+a]= tree->totchannel+a-1; + } + tree->parent[tree->totchannel]= parent; + + tree->totchannel= newsize; + } + + /* move tree to end of list, for correct evaluation order */ + BLI_remlink(&pchan_root->iktree, tree); + BLI_addtail(&pchan_root->iktree, tree); + } + + /* add target to the tree */ + BLI_addtail(&tree->targets, target); + /* mark root channel having an IK tree */ + pchan_root->flag |= POSE_IKTREE; +} + + +/* transform from bone(b) to bone(b+1), store in chan_mat */ +static void make_dmats(bPoseChannel *pchan) +{ + if (pchan->parent) { + float iR_parmat[4][4]; + Mat4Invert(iR_parmat, pchan->parent->pose_mat); + Mat4MulMat4(pchan->chan_mat, pchan->pose_mat, iR_parmat); // delta mat + } + else Mat4CpyMat4(pchan->chan_mat, pchan->pose_mat); +} + +/* applies IK matrix to pchan, IK is done separated */ +/* formula: pose_mat(b) = pose_mat(b-1) * diffmat(b-1, b) * ik_mat(b) */ +/* to make this work, the diffmats have to be precalculated! Stored in chan_mat */ +static void where_is_ik_bone(bPoseChannel *pchan, float ik_mat[][3]) // nr = to detect if this is first bone +{ + float vec[3], ikmat[4][4]; + + Mat4CpyMat3(ikmat, ik_mat); + + if (pchan->parent) + Mat4MulSerie(pchan->pose_mat, pchan->parent->pose_mat, pchan->chan_mat, ikmat, NULL, NULL, NULL, NULL, NULL); + else + Mat4MulMat4(pchan->pose_mat, ikmat, pchan->chan_mat); + + /* calculate head */ + VECCOPY(pchan->pose_head, pchan->pose_mat[3]); + /* calculate tail */ + VECCOPY(vec, pchan->pose_mat[1]); + VecMulf(vec, pchan->bone->length); + VecAddf(pchan->pose_tail, pchan->pose_head, vec); + + pchan->flag |= POSE_DONE; +} + + +/* called from within the core where_is_pose loop, all animsystems and constraints +were executed & assigned. Now as last we do an IK pass */ +static void execute_posetree(Object *ob, PoseTree *tree) +{ + float R_parmat[3][3], identity[3][3]; + float iR_parmat[3][3]; + float R_bonemat[3][3]; + float goalrot[3][3], goalpos[3]; + float rootmat[4][4], imat[4][4]; + float goal[4][4], goalinv[4][4]; + float irest_basis[3][3], full_basis[3][3]; + float end_pose[4][4], world_pose[4][4]; + float length, basis[3][3], rest_basis[3][3], start[3], *ikstretch=NULL; + float resultinf=0.0f; + int a, flag, hasstretch=0, resultblend=0; + bPoseChannel *pchan; + IK_Segment *seg, *parent, **iktree, *iktarget; + IK_Solver *solver; + PoseTarget *target; + bKinematicConstraint *data, *poleangledata=NULL; + Bone *bone; + + if (tree->totchannel == 0) + return; + + iktree= MEM_mallocN(sizeof(void*)*tree->totchannel, "ik tree"); + + for(a=0; a<tree->totchannel; a++) { + pchan= tree->pchan[a]; + bone= pchan->bone; + + /* set DoF flag */ + flag= 0; + if(!(pchan->ikflag & BONE_IK_NO_XDOF) && !(pchan->ikflag & BONE_IK_NO_XDOF_TEMP)) + flag |= IK_XDOF; + if(!(pchan->ikflag & BONE_IK_NO_YDOF) && !(pchan->ikflag & BONE_IK_NO_YDOF_TEMP)) + flag |= IK_YDOF; + if(!(pchan->ikflag & BONE_IK_NO_ZDOF) && !(pchan->ikflag & BONE_IK_NO_ZDOF_TEMP)) + flag |= IK_ZDOF; + + if(tree->stretch && (pchan->ikstretch > 0.0)) { + flag |= IK_TRANS_YDOF; + hasstretch = 1; + } + + seg= iktree[a]= IK_CreateSegment(flag); + + /* find parent */ + if(a == 0) + parent= NULL; + else + parent= iktree[tree->parent[a]]; + + IK_SetParent(seg, parent); + + /* get the matrix that transforms from prevbone into this bone */ + Mat3CpyMat4(R_bonemat, pchan->pose_mat); + + /* gather transformations for this IK segment */ + + if (pchan->parent) + Mat3CpyMat4(R_parmat, pchan->parent->pose_mat); + else + Mat3One(R_parmat); + + /* bone offset */ + if (pchan->parent && (a > 0)) + VecSubf(start, pchan->pose_head, pchan->parent->pose_tail); + else + /* only root bone (a = 0) has no parent */ + start[0]= start[1]= start[2]= 0.0f; + + /* change length based on bone size */ + length= bone->length*VecLength(R_bonemat[1]); + + /* compute rest basis and its inverse */ + Mat3CpyMat3(rest_basis, bone->bone_mat); + Mat3CpyMat3(irest_basis, bone->bone_mat); + Mat3Transp(irest_basis); + + /* compute basis with rest_basis removed */ + Mat3Inv(iR_parmat, R_parmat); + Mat3MulMat3(full_basis, iR_parmat, R_bonemat); + Mat3MulMat3(basis, irest_basis, full_basis); + + /* basis must be pure rotation */ + Mat3Ortho(basis); + + /* transform offset into local bone space */ + Mat3Ortho(iR_parmat); + Mat3MulVecfl(iR_parmat, start); + + IK_SetTransform(seg, start, rest_basis, basis, length); + + if (pchan->ikflag & BONE_IK_XLIMIT) + IK_SetLimit(seg, IK_X, pchan->limitmin[0], pchan->limitmax[0]); + if (pchan->ikflag & BONE_IK_YLIMIT) + IK_SetLimit(seg, IK_Y, pchan->limitmin[1], pchan->limitmax[1]); + if (pchan->ikflag & BONE_IK_ZLIMIT) + IK_SetLimit(seg, IK_Z, pchan->limitmin[2], pchan->limitmax[2]); + + IK_SetStiffness(seg, IK_X, pchan->stiffness[0]); + IK_SetStiffness(seg, IK_Y, pchan->stiffness[1]); + IK_SetStiffness(seg, IK_Z, pchan->stiffness[2]); + + if(tree->stretch && (pchan->ikstretch > 0.0)) { + float ikstretch = pchan->ikstretch*pchan->ikstretch; + IK_SetStiffness(seg, IK_TRANS_Y, MIN2(1.0-ikstretch, 0.99)); + IK_SetLimit(seg, IK_TRANS_Y, 0.001, 1e10); + } + } + + solver= IK_CreateSolver(iktree[0]); + + /* set solver goals */ + + /* first set the goal inverse transform, assuming the root of tree was done ok! */ + pchan= tree->pchan[0]; + if (pchan->parent) + /* transform goal by parent mat, so this rotation is not part of the + segment's basis. otherwise rotation limits do not work on the + local transform of the segment itself. */ + Mat4CpyMat4(rootmat, pchan->parent->pose_mat); + else + Mat4One(rootmat); + VECCOPY(rootmat[3], pchan->pose_head); + + Mat4MulMat4 (imat, rootmat, ob->obmat); + Mat4Invert (goalinv, imat); + + for (target=tree->targets.first; target; target=target->next) { + float polepos[3]; + int poleconstrain= 0; + + data= (bKinematicConstraint*)target->con->data; + + /* 1.0=ctime, we pass on object for auto-ik (owner-type here is object, even though + * strictly speaking, it is a posechannel) + */ + get_constraint_target_matrix(target->con, 0, CONSTRAINT_OBTYPE_OBJECT, ob, rootmat, 1.0); + + /* and set and transform goal */ + Mat4MulMat4(goal, rootmat, goalinv); + + VECCOPY(goalpos, goal[3]); + Mat3CpyMat4(goalrot, goal); + + /* same for pole vector target */ + if(data->poletar) { + get_constraint_target_matrix(target->con, 1, CONSTRAINT_OBTYPE_OBJECT, ob, rootmat, 1.0); + + if(data->flag & CONSTRAINT_IK_SETANGLE) { + /* don't solve IK when we are setting the pole angle */ + break; + } + else { + Mat4MulMat4(goal, rootmat, goalinv); + VECCOPY(polepos, goal[3]); + poleconstrain= 1; + + /* for pole targets, we blend the result of the ik solver + * instead of the target position, otherwise we can't get + * a smooth transition */ + resultblend= 1; + resultinf= target->con->enforce; + + if(data->flag & CONSTRAINT_IK_GETANGLE) { + poleangledata= data; + data->flag &= ~CONSTRAINT_IK_GETANGLE; + } + } + } + + /* do we need blending? */ + if (!resultblend && target->con->enforce!=1.0) { + float q1[4], q2[4], q[4]; + float fac= target->con->enforce; + float mfac= 1.0-fac; + + pchan= tree->pchan[target->tip]; + + /* end effector in world space */ + Mat4CpyMat4(end_pose, pchan->pose_mat); + VECCOPY(end_pose[3], pchan->pose_tail); + Mat4MulSerie(world_pose, goalinv, ob->obmat, end_pose, 0, 0, 0, 0, 0); + + /* blend position */ + goalpos[0]= fac*goalpos[0] + mfac*world_pose[3][0]; + goalpos[1]= fac*goalpos[1] + mfac*world_pose[3][1]; + goalpos[2]= fac*goalpos[2] + mfac*world_pose[3][2]; + + /* blend rotation */ + Mat3ToQuat(goalrot, q1); + Mat4ToQuat(world_pose, q2); + QuatInterpol(q, q1, q2, mfac); + QuatToMat3(q, goalrot); + } + + iktarget= iktree[target->tip]; + + if(data->weight != 0.0) { + if(poleconstrain) + IK_SolverSetPoleVectorConstraint(solver, iktarget, goalpos, + polepos, data->poleangle*M_PI/180, (poleangledata == data)); + IK_SolverAddGoal(solver, iktarget, goalpos, data->weight); + } + if((data->flag & CONSTRAINT_IK_ROT) && (data->orientweight != 0.0)) + if((data->flag & CONSTRAINT_IK_AUTO)==0) + IK_SolverAddGoalOrientation(solver, iktarget, goalrot, + data->orientweight); + } + + /* solve */ + IK_Solve(solver, 0.0f, tree->iterations); + + if(poleangledata) + poleangledata->poleangle= IK_SolverGetPoleAngle(solver)*180/M_PI; + + IK_FreeSolver(solver); + + /* gather basis changes */ + tree->basis_change= MEM_mallocN(sizeof(float[3][3])*tree->totchannel, "ik basis change"); + if(hasstretch) + ikstretch= MEM_mallocN(sizeof(float)*tree->totchannel, "ik stretch"); + + for(a=0; a<tree->totchannel; a++) { + IK_GetBasisChange(iktree[a], tree->basis_change[a]); + + if(hasstretch) { + /* have to compensate for scaling received from parent */ + float parentstretch, stretch; + + pchan= tree->pchan[a]; + parentstretch= (tree->parent[a] >= 0)? ikstretch[tree->parent[a]]: 1.0; + + if(tree->stretch && (pchan->ikstretch > 0.0)) { + float trans[3], length; + + IK_GetTranslationChange(iktree[a], trans); + length= pchan->bone->length*VecLength(pchan->pose_mat[1]); + + ikstretch[a]= (length == 0.0)? 1.0: (trans[1]+length)/length; + } + else + ikstretch[a] = 1.0; + + stretch= (parentstretch == 0.0)? 1.0: ikstretch[a]/parentstretch; + + VecMulf(tree->basis_change[a][0], stretch); + VecMulf(tree->basis_change[a][1], stretch); + VecMulf(tree->basis_change[a][2], stretch); + } + + if(resultblend && resultinf!=1.0f) { + Mat3One(identity); + Mat3BlendMat3(tree->basis_change[a], identity, + tree->basis_change[a], resultinf); + } + + IK_FreeSegment(iktree[a]); + } + + MEM_freeN(iktree); + if(ikstretch) MEM_freeN(ikstretch); +} + +static void free_posetree(PoseTree *tree) +{ + BLI_freelistN(&tree->targets); + if(tree->pchan) MEM_freeN(tree->pchan); + if(tree->parent) MEM_freeN(tree->parent); + if(tree->basis_change) MEM_freeN(tree->basis_change); + MEM_freeN(tree); +} + +///---------------------------------------- +/// Plugin API for legacy iksolver + +void iksolver_initialize_tree(struct Scene *scene, struct Object *ob, float ctime) +{ + bPoseChannel *pchan; + + for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) { + if(pchan->constflag & PCHAN_HAS_IK) // flag is set on editing constraints + initialize_posetree(ob, pchan); // will attach it to root! + } + ob->pose->flag &= ~POSE_WAS_REBUILT; +} + +void iksolver_execute_tree(struct Scene *scene, struct Object *ob, struct bPoseChannel *pchan, float ctime) +{ + while(pchan->iktree.first) { + PoseTree *tree= pchan->iktree.first; + int a; + + /* 4. walk over the tree for regular solving */ + for(a=0; a<tree->totchannel; a++) { + if(!(tree->pchan[a]->flag & POSE_DONE)) // successive trees can set the flag + where_is_pose_bone(scene, ob, tree->pchan[a], ctime); + // tell blender that this channel was controlled by IK, it's cleared on each where_is_pose() + tree->pchan[a]->flag |= POSE_CHAIN; + } + /* 5. execute the IK solver */ + execute_posetree(ob, tree); + + /* 6. apply the differences to the channels, + we need to calculate the original differences first */ + for(a=0; a<tree->totchannel; a++) + make_dmats(tree->pchan[a]); + + for(a=0; a<tree->totchannel; a++) + /* sets POSE_DONE */ + where_is_ik_bone(tree->pchan[a], tree->basis_change[a]); + + /* 7. and free */ + BLI_remlink(&pchan->iktree, tree); + free_posetree(tree); + } +} + diff --git a/source/blender/ikplugin/intern/iksolver_plugin.h b/source/blender/ikplugin/intern/iksolver_plugin.h new file mode 100644 index 00000000000..d5d1d9a77da --- /dev/null +++ b/source/blender/ikplugin/intern/iksolver_plugin.h @@ -0,0 +1,47 @@ +/** + * $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. + * + * Original author: Benoit Bolsee + * Contributor(s): + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef IKSOLVER_PLUGIN_H +#define IKSOLVER_PLUGIN_H + +#include "ikplugin_api.h" + +#ifdef __cplusplus +extern "C" { +#endif + +void iksolver_initialize_tree(struct Scene *scene, struct Object *ob, float ctime); +void iksolver_execute_tree(struct Scene *scene, struct Object *ob, struct bPoseChannel *pchan, float ctime); + +#ifdef __cplusplus +} +#endif + +#endif // IKSOLVER_PLUGIN_H + diff --git a/source/blender/ikplugin/intern/itasc_plugin.cpp b/source/blender/ikplugin/intern/itasc_plugin.cpp new file mode 100644 index 00000000000..4aebda1347c --- /dev/null +++ b/source/blender/ikplugin/intern/itasc_plugin.cpp @@ -0,0 +1,1777 @@ +/** + * $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. + * + * Original author: Benoit Bolsee + * Contributor(s): + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include <stdlib.h> +#include <string.h> +#include <vector> + +// iTaSC headers +#include "Armature.hpp" +#include "MovingFrame.hpp" +#include "CopyPose.hpp" +#include "WSDLSSolver.hpp" +#include "WDLSSolver.hpp" +#include "Scene.hpp" +#include "Cache.hpp" +#include "Distance.hpp" + +#include "MEM_guardedalloc.h" + +extern "C" { +#include "BIK_api.h" +#include "BLI_blenlib.h" +#include "BLI_arithb.h" + +#include "BKE_global.h" +#include "BKE_armature.h" +#include "BKE_action.h" +#include "BKE_utildefines.h" +#include "BKE_constraint.h" +#include "DNA_object_types.h" +#include "DNA_action_types.h" +#include "DNA_constraint_types.h" +#include "DNA_armature_types.h" +#include "DNA_scene_types.h" +}; + +#include "itasc_plugin.h" + +// default parameters +bItasc DefIKParam; + +// in case of animation mode, feedback and timestep is fixed +#define ANIM_TIMESTEP 1.0 +#define ANIM_FEEDBACK 0.8 +#define ANIM_QMAX 0.52 + + +// Structure pointed by bPose.ikdata +// It contains everything needed to simulate the armatures +// There can be several simulation islands independent to each other +struct IK_Data +{ + struct IK_Scene* first; +}; + +typedef float Vector3[3]; +typedef float Vector4[4]; +struct IK_Target; +typedef void (*ErrorCallback)(const iTaSC::ConstraintValues* values, unsigned int nvalues, IK_Target* iktarget); +// For some reason, gcc doesn't find the declaration of this function in linux +void KDL::SetToZero(JntArray& array); + +// one structure for each target in the scene +struct IK_Target +{ + iTaSC::MovingFrame* target; + iTaSC::ConstraintSet* constraint; + struct bConstraint* blenderConstraint; + struct bPoseChannel* rootChannel; + Object* owner; //for auto IK + ErrorCallback errorCallback; + std::string targetName; + std::string constraintName; + unsigned short controlType; + short channel; //index in IK channel array of channel on which this target is defined + short ee; //end effector number + bool simulation; //true when simulation mode is used (update feedback) + bool eeBlend; //end effector affected by enforce blending + float eeRest[4][4]; //end effector initial pose relative to armature + + IK_Target() { + target = NULL; + constraint = NULL; + blenderConstraint = NULL; + rootChannel = NULL; + owner = NULL; + controlType = 0; + channel = 0; + ee = 0; + eeBlend = true; + simulation = true; + targetName.reserve(32); + constraintName.reserve(32); + } + ~IK_Target() { + if (constraint) + delete constraint; + if (target) + delete target; + } +}; + +struct IK_Channel { + bPoseChannel* pchan; // channel where we must copy matrix back + KDL::Frame frame; // frame of the bone relative to object base, not armature base + std::string tail; // segment name of the joint from which we get the bone tail + std::string head; // segment name of the joint from which we get the bone head + int parent; // index in this array of the parent channel + short jointType; // type of joint, combination of IK_SegmentFlag + char ndof; // number of joint angles for this channel + char jointValid; // set to 1 when jointValue has been computed + // for joint constraint + Object* owner; // for pose and IK param + double jointValue[4]; // computed joint value + + IK_Channel() { + pchan = NULL; + parent = -1; + jointType = 0; + ndof = 0; + jointValid = 0; + owner = NULL; + jointValue[0] = 0.0; + jointValue[1] = 0.0; + jointValue[2] = 0.0; + jointValue[3] = 0.0; + } +}; + +struct IK_Scene +{ + IK_Scene* next; + int numchan; // number of channel in pchan + int numjoint; // number of joint in jointArray + // array of bone information, one per channel in the tree + IK_Channel* channels; + iTaSC::Armature* armature; + iTaSC::Cache* cache; + iTaSC::Scene* scene; + iTaSC::MovingFrame* base; // armature base object + KDL::Frame baseFrame; // frame of armature base relative to blArmature + KDL::JntArray jointArray; // buffer for storing temporary joint array + iTaSC::Solver* solver; + Object* blArmature; + struct bConstraint* polarConstraint; + std::vector<IK_Target*> targets; + + IK_Scene() { + next = NULL; + channels = NULL; + armature = NULL; + cache = NULL; + scene = NULL; + base = NULL; + solver = NULL; + blArmature = NULL; + numchan = 0; + numjoint = 0; + polarConstraint = NULL; + } + + ~IK_Scene() { + // delete scene first + if (scene) + delete scene; + for(std::vector<IK_Target*>::iterator it = targets.begin(); it != targets.end(); ++it) + delete (*it); + targets.clear(); + if (channels) + delete [] channels; + if (solver) + delete solver; + if (armature) + delete armature; + if (base) + delete base; + // delete cache last + if (cache) + delete cache; + } +}; + +// type of IK joint, can be combined to list the joints corresponding to a bone +enum IK_SegmentFlag { + IK_XDOF = 1, + IK_YDOF = 2, + IK_ZDOF = 4, + IK_SWING = 8, + IK_REVOLUTE = 16, + IK_TRANSY = 32, +}; + +enum IK_SegmentAxis { + IK_X = 0, + IK_Y = 1, + IK_Z = 2, + IK_TRANS_X = 3, + IK_TRANS_Y = 4, + IK_TRANS_Z = 5 +}; + +static int initialize_chain(Object *ob, bPoseChannel *pchan_tip, bConstraint *con) +{ + bPoseChannel *curchan, *pchan_root=NULL, *chanlist[256], **oldchan; + PoseTree *tree; + PoseTarget *target; + bKinematicConstraint *data; + int a, t, segcount= 0, size, newsize, *oldparent, parent, rootbone, treecount; + + data=(bKinematicConstraint*)con->data; + + /* exclude tip from chain? */ + if(!(data->flag & CONSTRAINT_IK_TIP)) + pchan_tip= pchan_tip->parent; + + rootbone = data->rootbone; + /* Find the chain's root & count the segments needed */ + for (curchan = pchan_tip; curchan; curchan=curchan->parent){ + pchan_root = curchan; + + if (++segcount > 255) // 255 is weak + break; + + if(segcount==rootbone){ + // reached this end of the chain but if the chain is overlapping with a + // previous one, we must go back up to the root of the other chain + if ((curchan->flag & POSE_CHAIN) && curchan->iktree.first == NULL){ + rootbone++; + continue; + } + break; + } + + if (curchan->iktree.first != NULL) + // Oh oh, there is already a chain starting from this channel and our chain is longer... + // Should handle this by moving the previous chain up to the begining of our chain + // For now we just stop here + break; + } + if (!segcount) return 0; + // we reached a limit and still not the end of a previous chain, quit + if ((pchan_root->flag & POSE_CHAIN) && pchan_root->iktree.first == NULL) return 0; + + // now that we know how many segment we have, set the flag + for (rootbone = segcount, segcount = 0, curchan = pchan_tip; segcount < rootbone; segcount++, curchan=curchan->parent) { + chanlist[segcount]=curchan; + curchan->flag |= POSE_CHAIN; + } + + /* setup the chain data */ + /* create a target */ + target= (PoseTarget*)MEM_callocN(sizeof(PoseTarget), "posetarget"); + target->con= con; + // by contruction there can be only one tree per channel and each channel can be part of at most one tree. + tree = (PoseTree*)pchan_root->iktree.first; + + if(tree==NULL) { + /* make new tree */ + tree= (PoseTree*)MEM_callocN(sizeof(PoseTree), "posetree"); + + tree->iterations= data->iterations; + tree->totchannel= segcount; + tree->stretch = (data->flag & CONSTRAINT_IK_STRETCH); + + tree->pchan= (bPoseChannel**)MEM_callocN(segcount*sizeof(void*), "ik tree pchan"); + tree->parent= (int*)MEM_callocN(segcount*sizeof(int), "ik tree parent"); + for(a=0; a<segcount; a++) { + tree->pchan[a]= chanlist[segcount-a-1]; + tree->parent[a]= a-1; + } + target->tip= segcount-1; + + /* AND! link the tree to the root */ + BLI_addtail(&pchan_root->iktree, tree); + // new tree + treecount = 1; + } + else { + tree->iterations= MAX2(data->iterations, tree->iterations); + tree->stretch= tree->stretch && !(data->flag & CONSTRAINT_IK_STRETCH); + + /* skip common pose channels and add remaining*/ + size= MIN2(segcount, tree->totchannel); + a = t = 0; + while (a<size && t<tree->totchannel) { + // locate first matching channel + for (;t<tree->totchannel && tree->pchan[t]!=chanlist[segcount-a-1];t++); + if (t>=tree->totchannel) + break; + for(; a<size && t<tree->totchannel && tree->pchan[t]==chanlist[segcount-a-1]; a++, t++); + } + parent= a-1; + segcount= segcount-a; + target->tip= tree->totchannel + segcount - 1; + + if (segcount > 0) { + /* resize array */ + newsize= tree->totchannel + segcount; + oldchan= tree->pchan; + oldparent= tree->parent; + + tree->pchan= (bPoseChannel**)MEM_callocN(newsize*sizeof(void*), "ik tree pchan"); + tree->parent= (int*)MEM_callocN(newsize*sizeof(int), "ik tree parent"); + memcpy(tree->pchan, oldchan, sizeof(void*)*tree->totchannel); + memcpy(tree->parent, oldparent, sizeof(int)*tree->totchannel); + MEM_freeN(oldchan); + MEM_freeN(oldparent); + + /* add new pose channels at the end, in reverse order */ + for(a=0; a<segcount; a++) { + tree->pchan[tree->totchannel+a]= chanlist[segcount-a-1]; + tree->parent[tree->totchannel+a]= tree->totchannel+a-1; + } + tree->parent[tree->totchannel]= parent; + + tree->totchannel= newsize; + } + // reusing tree + treecount = 0; + } + + /* add target to the tree */ + BLI_addtail(&tree->targets, target); + /* mark root channel having an IK tree */ + pchan_root->flag |= POSE_IKTREE; + return treecount; +} + +static bool is_cartesian_constraint(bConstraint *con) +{ + //bKinematicConstraint* data=(bKinematicConstraint*)con->data; + + return true; +} + +static bool constraint_valid(bConstraint *con) +{ + bKinematicConstraint* data=(bKinematicConstraint*)con->data; + + if (data->flag & CONSTRAINT_IK_AUTO) + return true; + if (con->flag & CONSTRAINT_DISABLE) + return false; + if (is_cartesian_constraint(con)) { + /* cartesian space constraint */ + if (data->tar==NULL) + return false; + if (data->tar->type==OB_ARMATURE && data->subtarget[0]==0) + return false; + } + return true; +} + +int initialize_scene(Object *ob, bPoseChannel *pchan_tip) +{ + bConstraint *con; + int treecount; + + /* find all IK constraints and validate them */ + treecount = 0; + for(con= (bConstraint *)pchan_tip->constraints.first; con; con= (bConstraint *)con->next) { + if(con->type==CONSTRAINT_TYPE_KINEMATIC) { + if (constraint_valid(con)) + treecount += initialize_chain(ob, pchan_tip, con); + } + } + return treecount; +} + +static IK_Data* get_ikdata(bPose *pose) +{ + if (pose->ikdata) + return (IK_Data*)pose->ikdata; + pose->ikdata = MEM_callocN(sizeof(IK_Data), "iTaSC ikdata"); + // here init ikdata if needed + // now that we have scene, make sure the default param are initialized + if (!DefIKParam.iksolver) + init_pose_itasc(&DefIKParam); + + return (IK_Data*)pose->ikdata; +} +static double EulerAngleFromMatrix(const KDL::Rotation& R, int axis) +{ + double t = KDL::sqrt(R(0,0)*R(0,0) + R(0,1)*R(0,1)); + + if (t > 16.0*KDL::epsilon) { + if (axis == 0) return -KDL::atan2(R(1,2), R(2,2)); + else if(axis == 1) return KDL::atan2(-R(0,2), t); + else return -KDL::atan2(R(0,1), R(0,0)); + } else { + if (axis == 0) return -KDL::atan2(-R(2,1), R(1,1)); + else if(axis == 1) return KDL::atan2(-R(0,2), t); + else return 0.0f; + } +} + +static double ComputeTwist(const KDL::Rotation& R) +{ + // qy and qw are the y and w components of the quaternion from R + double qy = R(0,2) - R(2,0); + double qw = R(0,0) + R(1,1) + R(2,2) + 1; + + double tau = 2*KDL::atan2(qy, qw); + + return tau; +} + +static void RemoveEulerAngleFromMatrix(KDL::Rotation& R, double angle, int axis) +{ + // compute twist parameter + KDL::Rotation T; + switch (axis) { + case 0: + T = KDL::Rotation::RotX(-angle); + break; + case 1: + T = KDL::Rotation::RotY(-angle); + break; + case 2: + T = KDL::Rotation::RotZ(-angle); + break; + default: + return; + } + // remove angle + R = R*T; +} + +#if 0 +static void GetEulerXZY(const KDL::Rotation& R, double& X,double& Z,double& Y) +{ + if (fabs(R(0,1)) > 1.0 - KDL::epsilon ) { + X = -KDL::sign(R(0,1)) * KDL::atan2(R(1,2), R(1,0)); + Z = -KDL::sign(R(0,1)) * KDL::PI / 2; + Y = 0.0 ; + } else { + X = KDL::atan2(R(2,1), R(1,1)); + Z = KDL::atan2(-R(0,1), KDL::sqrt( KDL::sqr(R(0,0)) + KDL::sqr(R(0,2)))); + Y = KDL::atan2(R(0,2), R(0,0)); + } +} + +static void GetEulerXYZ(const KDL::Rotation& R, double& X,double& Y,double& Z) +{ + if (fabs(R(0,2)) > 1.0 - KDL::epsilon ) { + X = KDL::sign(R(0,2)) * KDL::atan2(-R(1,0), R(1,1)); + Y = KDL::sign(R(0,2)) * KDL::PI / 2; + Z = 0.0 ; + } else { + X = KDL::atan2(-R(1,2), R(2,2)); + Y = KDL::atan2(R(0,2), KDL::sqrt( KDL::sqr(R(0,0)) + KDL::sqr(R(0,1)))); + Z = KDL::atan2(-R(0,1), R(0,0)); + } +} +#endif + +static void GetJointRotation(KDL::Rotation& boneRot, int type, double* rot) +{ + switch (type & ~IK_TRANSY) + { + default: + // fixed bone, no joint + break; + case IK_XDOF: + // RX only, get the X rotation + rot[0] = EulerAngleFromMatrix(boneRot, 0); + break; + case IK_YDOF: + // RY only, get the Y rotation + rot[0] = ComputeTwist(boneRot); + break; + case IK_ZDOF: + // RZ only, get the Z rotation + rot[0] = EulerAngleFromMatrix(boneRot, 2); + break; + case IK_XDOF|IK_YDOF: + rot[1] = ComputeTwist(boneRot); + RemoveEulerAngleFromMatrix(boneRot, rot[1], 1); + rot[0] = EulerAngleFromMatrix(boneRot, 0); + break; + case IK_SWING: + // RX+RZ + boneRot.GetXZRot().GetValue(rot); + break; + case IK_YDOF|IK_ZDOF: + // RZ+RY + rot[1] = ComputeTwist(boneRot); + RemoveEulerAngleFromMatrix(boneRot, rot[1], 1); + rot[0] = EulerAngleFromMatrix(boneRot, 2); + break; + case IK_SWING|IK_YDOF: + rot[2] = ComputeTwist(boneRot); + RemoveEulerAngleFromMatrix(boneRot, rot[2], 1); + boneRot.GetXZRot().GetValue(rot); + break; + case IK_REVOLUTE: + boneRot.GetRot().GetValue(rot); + break; + } +} + +static bool target_callback(const iTaSC::Timestamp& timestamp, const iTaSC::Frame& current, iTaSC::Frame& next, void *param) +{ + IK_Target* target = (IK_Target*)param; + // compute next target position + // get target matrix from constraint. + bConstraint* constraint = (bConstraint*)target->blenderConstraint; + float tarmat[4][4]; + + get_constraint_target_matrix(constraint, 0, CONSTRAINT_OBTYPE_OBJECT, target->owner, tarmat, 1.0); + + // rootmat contains the target pose in world coordinate + // if enforce is != 1.0, blend the target position with the end effector position + // if the armature was in rest position. This information is available in eeRest + if (constraint->enforce != 1.0f && target->eeBlend) { + // eeRest is relative to the reference frame of the IK root + // get this frame in world reference + float restmat[4][4]; + bPoseChannel* pchan = target->rootChannel; + if (pchan->parent) { + pchan = pchan->parent; + float chanmat[4][4]; + Mat4CpyMat4(chanmat, pchan->pose_mat); + VECCOPY(chanmat[3], pchan->pose_tail); + Mat4MulSerie(restmat, target->owner->obmat, chanmat, target->eeRest, NULL, NULL, NULL, NULL, NULL); + } + else { + Mat4MulMat4(restmat, target->eeRest, target->owner->obmat); + } + // blend the target + Mat4BlendMat4(tarmat, restmat, tarmat, constraint->enforce); + } + next.setValue(&tarmat[0][0]); + return true; +} + +static bool base_callback(const iTaSC::Timestamp& timestamp, const iTaSC::Frame& current, iTaSC::Frame& next, void *param) +{ + IK_Scene* ikscene = (IK_Scene*)param; + // compute next armature base pose + // algorithm: + // ikscene->pchan[0] is the root channel of the tree + // if it has a parent, get the pose matrix from it and replace [3] by parent pchan->tail + // then multiply by the armature matrix to get ikscene->armature base position + bPoseChannel* pchan = ikscene->channels[0].pchan; + float rootmat[4][4]; + if (pchan->parent) { + pchan = pchan->parent; + float chanmat[4][4]; + Mat4CpyMat4(chanmat, pchan->pose_mat); + VECCOPY(chanmat[3], pchan->pose_tail); + // save the base as a frame too so that we can compute deformation + // after simulation + ikscene->baseFrame.setValue(&chanmat[0][0]); + Mat4MulMat4(rootmat, chanmat, ikscene->blArmature->obmat); + } + else { + Mat4CpyMat4(rootmat, ikscene->blArmature->obmat); + ikscene->baseFrame = iTaSC::F_identity; + } + next.setValue(&rootmat[0][0]); + // if there is a polar target (only during solving otherwise we don't have end efffector) + if (ikscene->polarConstraint && timestamp.update) { + // compute additional rotation of base frame so that armature follows the polar target + float imat[4][4]; // IK tree base inverse matrix + float polemat[4][4]; // polar target in IK tree base frame + float goalmat[4][4]; // target in IK tree base frame + float mat[4][4]; // temp matrix + bKinematicConstraint* poledata = (bKinematicConstraint*)ikscene->polarConstraint->data; + + Mat4Invert(imat, rootmat); + // polar constraint imply only one target + IK_Target *iktarget = ikscene->targets[0]; + // root channel from which we take the bone initial orientation + IK_Channel &rootchan = ikscene->channels[0]; + + // get polar target matrix in world space + get_constraint_target_matrix(ikscene->polarConstraint, 1, CONSTRAINT_OBTYPE_OBJECT, ikscene->blArmature, mat, 1.0); + // convert to armature space + Mat4MulMat4(polemat, mat, imat); + // get the target in world space (was computed before as target object are defined before base object) + iktarget->target->getPose().getValue(mat[0]); + // convert to armature space + Mat4MulMat4(goalmat, mat, imat); + // take position of target, polar target, end effector, in armature space + KDL::Vector goalpos(goalmat[3]); + KDL::Vector polepos(polemat[3]); + KDL::Vector endpos = ikscene->armature->getPose(iktarget->ee).p; + // get root bone orientation + KDL::Frame rootframe; + ikscene->armature->getRelativeFrame(rootframe, rootchan.tail); + KDL::Vector rootx = rootframe.M.UnitX(); + KDL::Vector rootz = rootframe.M.UnitZ(); + // and compute root bone head + double q_rest[3], q[3], length; + const KDL::Joint* joint; + const KDL::Frame* tip; + ikscene->armature->getSegment(rootchan.tail, 3, joint, q_rest[0], q[0], tip); + length = (joint->getType() == KDL::Joint::TransY) ? q[0] : tip->p(1); + KDL::Vector rootpos = rootframe.p - length*rootframe.M.UnitY(); + + // compute main directions + KDL::Vector dir = KDL::Normalize(endpos - rootpos); + KDL::Vector poledir = KDL::Normalize(goalpos-rootpos); + // compute up directions + KDL::Vector poleup = KDL::Normalize(polepos-rootpos); + KDL::Vector up = rootx*KDL::cos(poledata->poleangle) + rootz*KDL::sin(poledata->poleangle); + // from which we build rotation matrix + KDL::Rotation endrot, polerot; + // for the armature, using the root bone orientation + KDL::Vector x = KDL::Normalize(dir*up); + endrot.UnitX(x); + endrot.UnitY(KDL::Normalize(x*dir)); + endrot.UnitZ(-dir); + // for the polar target + x = KDL::Normalize(poledir*poleup); + polerot.UnitX(x); + polerot.UnitY(KDL::Normalize(x*poledir)); + polerot.UnitZ(-poledir); + // the difference between the two is the rotation we want to apply + KDL::Rotation result(polerot*endrot.Inverse()); + // apply on base frame as this is an artificial additional rotation + next.M = next.M*result; + ikscene->baseFrame.M = ikscene->baseFrame.M*result; + } + return true; +} + +static bool copypose_callback(const iTaSC::Timestamp& timestamp, iTaSC::ConstraintValues* const _values, unsigned int _nvalues, void* _param) +{ + IK_Target* iktarget =(IK_Target*)_param; + bKinematicConstraint *condata = (bKinematicConstraint *)iktarget->blenderConstraint->data; + iTaSC::ConstraintValues* values = _values; + bItasc* ikparam = (bItasc*) iktarget->owner->pose->ikparam; + + // we need default parameters + if (!ikparam) + ikparam = &DefIKParam; + + if (iktarget->blenderConstraint->flag & CONSTRAINT_OFF) { + if (iktarget->controlType & iTaSC::CopyPose::CTL_POSITION) { + values->alpha = 0.0; + values->action = iTaSC::ACT_ALPHA; + values++; + } + if (iktarget->controlType & iTaSC::CopyPose::CTL_ROTATION) { + values->alpha = 0.0; + values->action = iTaSC::ACT_ALPHA; + values++; + } + } else { + if (iktarget->controlType & iTaSC::CopyPose::CTL_POSITION) { + // update error + values->alpha = condata->weight; + values->action = iTaSC::ACT_ALPHA|iTaSC::ACT_FEEDBACK; + values->feedback = (iktarget->simulation) ? ikparam->feedback : ANIM_FEEDBACK; + values++; + } + if (iktarget->controlType & iTaSC::CopyPose::CTL_ROTATION) { + // update error + values->alpha = condata->orientweight; + values->action = iTaSC::ACT_ALPHA|iTaSC::ACT_FEEDBACK; + values->feedback = (iktarget->simulation) ? ikparam->feedback : ANIM_FEEDBACK; + values++; + } + } + return true; +} + +static void copypose_error(const iTaSC::ConstraintValues* values, unsigned int nvalues, IK_Target* iktarget) +{ + iTaSC::ConstraintSingleValue* value; + double error; + int i; + + if (iktarget->controlType & iTaSC::CopyPose::CTL_POSITION) { + // update error + for (i=0, error=0.0, value=values->values; i<values->number; ++i, ++value) + error += KDL::sqr(value->y - value->yd); + iktarget->blenderConstraint->lin_error = (float)KDL::sqrt(error); + values++; + } + if (iktarget->controlType & iTaSC::CopyPose::CTL_ROTATION) { + // update error + for (i=0, error=0.0, value=values->values; i<values->number; ++i, ++value) + error += KDL::sqr(value->y - value->yd); + iktarget->blenderConstraint->rot_error = (float)KDL::sqrt(error); + values++; + } +} + +static bool distance_callback(const iTaSC::Timestamp& timestamp, iTaSC::ConstraintValues* const _values, unsigned int _nvalues, void* _param) +{ + IK_Target* iktarget =(IK_Target*)_param; + bKinematicConstraint *condata = (bKinematicConstraint *)iktarget->blenderConstraint->data; + iTaSC::ConstraintValues* values = _values; + bItasc* ikparam = (bItasc*) iktarget->owner->pose->ikparam; + // we need default parameters + if (!ikparam) + ikparam = &DefIKParam; + + // update weight according to mode + if (iktarget->blenderConstraint->flag & CONSTRAINT_OFF) { + values->alpha = 0.0; + } else { + switch (condata->mode) { + case LIMITDIST_INSIDE: + values->alpha = (values->values[0].y > condata->dist) ? condata->weight : 0.0; + break; + case LIMITDIST_OUTSIDE: + values->alpha = (values->values[0].y < condata->dist) ? condata->weight : 0.0; + break; + default: + values->alpha = condata->weight; + break; + } + if (!timestamp.substep) { + // only update value on first timestep + switch (condata->mode) { + case LIMITDIST_INSIDE: + values->values[0].yd = condata->dist*0.95; + break; + case LIMITDIST_OUTSIDE: + values->values[0].yd = condata->dist*1.05; + break; + default: + values->values[0].yd = condata->dist; + break; + } + values->values[0].action = iTaSC::ACT_VALUE|iTaSC::ACT_FEEDBACK; + values->feedback = (iktarget->simulation) ? ikparam->feedback : ANIM_FEEDBACK; + } + } + values->action |= iTaSC::ACT_ALPHA; + return true; +} + +static void distance_error(const iTaSC::ConstraintValues* values, unsigned int _nvalues, IK_Target* iktarget) +{ + iktarget->blenderConstraint->lin_error = (float)(values->values[0].y - values->values[0].yd); +} + +static bool joint_callback(const iTaSC::Timestamp& timestamp, iTaSC::ConstraintValues* const _values, unsigned int _nvalues, void* _param) +{ + IK_Channel* ikchan = (IK_Channel*)_param; + bItasc* ikparam = (bItasc*)ikchan->owner->pose->ikparam; + bPoseChannel* chan = ikchan->pchan; + int dof; + + // a channel can be splitted into multiple joints, so we get called multiple + // times for one channel (this callback is only for 1 joint in the armature) + // the IK_JointTarget structure is shared between multiple joint constraint + // and the target joint values is computed only once, remember this in jointValid + // Don't forget to reset it before each frame + if (!ikchan->jointValid) { + float rmat[3][3]; + + if (chan->rotmode > 0) { + /* euler rotations (will cause gimble lock, but this can be alleviated a bit with rotation orders) */ + EulOToMat3(chan->eul, chan->rotmode, rmat); + } + else if (chan->rotmode == PCHAN_ROT_AXISANGLE) { + /* axis-angle - stored in quaternion data, but not really that great for 3D-changing orientations */ + AxisAngleToMat3(&chan->quat[1], chan->quat[0], rmat); + } + else { + /* quats are normalised before use to eliminate scaling issues */ + NormalQuat(chan->quat); + QuatToMat3(chan->quat, rmat); + } + KDL::Rotation jointRot( + rmat[0][0], rmat[1][0], rmat[2][0], + rmat[0][1], rmat[1][1], rmat[2][1], + rmat[0][2], rmat[1][2], rmat[2][2]); + GetJointRotation(jointRot, ikchan->jointType, ikchan->jointValue); + ikchan->jointValid = 1; + } + // determine which part of jointValue is used for this joint + // closely related to the way the joints are defined + switch (ikchan->jointType & ~IK_TRANSY) + { + case IK_XDOF: + case IK_YDOF: + case IK_ZDOF: + dof = 0; + break; + case IK_XDOF|IK_YDOF: + // X + Y + dof = (_values[0].id == iTaSC::Armature::ID_JOINT_RX) ? 0 : 1; + break; + case IK_SWING: + // XZ + dof = 0; + break; + case IK_YDOF|IK_ZDOF: + // Z + Y + dof = (_values[0].id == iTaSC::Armature::ID_JOINT_RZ) ? 0 : 1; + break; + case IK_SWING|IK_YDOF: + // XZ + Y + dof = (_values[0].id == iTaSC::Armature::ID_JOINT_RY) ? 2 : 0; + break; + case IK_REVOLUTE: + dof = 0; + break; + default: + dof = -1; + break; + } + if (dof >= 0) { + for (unsigned int i=0; i<_nvalues; i++, dof++) { + _values[i].values[0].yd = ikchan->jointValue[dof]; + _values[i].alpha = chan->ikrotweight; + _values[i].feedback = ikparam->feedback; + } + } + return true; +} + +// build array of joint corresponding to IK chain +static int convert_channels(IK_Scene *ikscene, PoseTree *tree) +{ + IK_Channel *ikchan; + bPoseChannel *pchan; + Bone *bone; + int a, flag, njoint; + + njoint = 0; + for(a=0, ikchan = ikscene->channels; a<ikscene->numchan; ++a, ++ikchan) { + pchan= tree->pchan[a]; + bone= pchan->bone; + ikchan->pchan = pchan; + ikchan->parent = (a>0) ? tree->parent[a] : -1; + ikchan->owner = ikscene->blArmature; + + /* set DoF flag */ + flag = 0; + if(!(pchan->ikflag & BONE_IK_NO_XDOF) && !(pchan->ikflag & BONE_IK_NO_XDOF_TEMP) && + (!(pchan->ikflag & BONE_IK_XLIMIT) || pchan->limitmin[0]<0.f || pchan->limitmax[0]>0.f)) + flag |= IK_XDOF; + if(!(pchan->ikflag & BONE_IK_NO_YDOF) && !(pchan->ikflag & BONE_IK_NO_YDOF_TEMP) && + (!(pchan->ikflag & BONE_IK_YLIMIT) || pchan->limitmin[1]<0.f || pchan->limitmax[1]>0.f)) + flag |= IK_YDOF; + if(!(pchan->ikflag & BONE_IK_NO_ZDOF) && !(pchan->ikflag & BONE_IK_NO_ZDOF_TEMP) && + (!(pchan->ikflag & BONE_IK_ZLIMIT) || pchan->limitmin[2]<0.f || pchan->limitmax[2]>0.f)) + flag |= IK_ZDOF; + + if(tree->stretch && (pchan->ikstretch > 0.0)) { + flag |= IK_TRANSY; + } + /* + Logic to create the segments: + RX,RY,RZ = rotational joints with no length + RY(tip) = rotational joints with a fixed length arm = (0,length,0) + TY = translational joint on Y axis + F(pos) = fixed joint with an arm at position pos + Conversion rule of the above flags: + - ==> F(tip) + X ==> RX(tip) + Y ==> RY(tip) + Z ==> RZ(tip) + XY ==> RX+RY(tip) + XZ ==> RX+RZ(tip) + YZ ==> RZ+RY(tip) + XYZ ==> full spherical unless there are limits, in which case RX+RZ+RY(tip) + In case of stretch, tip=(0,0,0) and there is an additional TY joint + The frame at last of these joints represents the tail of the bone. + The head is computed by a reverse translation on Y axis of the bone length + or in case of TY joint, by the frame at previous joint. + In case of separation of bones, there is an additional F(head) joint + + Computing rest pose and length is complicated: the solver works in world space + Here is the logic: + rest position is computed only from bone->bone_mat. + bone length is computed from bone->length multiplied by the scaling factor of + the armature. Non-uniform scaling will give bad result! + + */ + switch (flag & (IK_XDOF|IK_YDOF|IK_ZDOF)) + { + default: + ikchan->jointType = 0; + ikchan->ndof = 0; + break; + case IK_XDOF: + // RX only, get the X rotation + ikchan->jointType = IK_XDOF; + ikchan->ndof = 1; + break; + case IK_YDOF: + // RY only, get the Y rotation + ikchan->jointType = IK_YDOF; + ikchan->ndof = 1; + break; + case IK_ZDOF: + // RZ only, get the Zz rotation + ikchan->jointType = IK_ZDOF; + ikchan->ndof = 1; + break; + case IK_XDOF|IK_YDOF: + ikchan->jointType = IK_XDOF|IK_YDOF; + ikchan->ndof = 2; + break; + case IK_XDOF|IK_ZDOF: + // RX+RZ + ikchan->jointType = IK_SWING; + ikchan->ndof = 2; + break; + case IK_YDOF|IK_ZDOF: + // RZ+RY + ikchan->jointType = IK_ZDOF|IK_YDOF; + ikchan->ndof = 2; + break; + case IK_XDOF|IK_YDOF|IK_ZDOF: + // spherical joint + if (pchan->ikflag & (BONE_IK_XLIMIT|BONE_IK_YLIMIT|BONE_IK_ZLIMIT)) + // decompose in a Swing+RotY joint + ikchan->jointType = IK_SWING|IK_YDOF; + else + ikchan->jointType = IK_REVOLUTE; + ikchan->ndof = 3; + break; + } + if (flag & IK_TRANSY) { + ikchan->jointType |= IK_TRANSY; + ikchan->ndof++; + } + njoint += ikchan->ndof; + } + // njoint is the joint coordinate, create the Joint Array + ikscene->jointArray.resize(njoint); + ikscene->numjoint = njoint; + return njoint; +} + +// compute array of joint value corresponding to current pose +static void convert_pose(IK_Scene *ikscene) +{ + KDL::Rotation boneRot; + bPoseChannel *pchan; + IK_Channel *ikchan; + Bone *bone; + float rmat[4][4]; // rest pose of bone with parent taken into account + float bmat[4][4]; // difference + float scale; + double *rot; + int a, joint; + + // assume uniform scaling and take Y scale as general scale for the armature + scale = VecLength(ikscene->blArmature->obmat[1]); + rot = &ikscene->jointArray(0); + for(joint=a=0, ikchan = ikscene->channels; a<ikscene->numchan && joint<ikscene->numjoint; ++a, ++ikchan) { + pchan= ikchan->pchan; + bone= pchan->bone; + + if (pchan->parent) { + Mat4One(bmat); + Mat4MulMat43(bmat, pchan->parent->pose_mat, bone->bone_mat); + } else { + Mat4CpyMat4(bmat, bone->arm_mat); + } + Mat4Invert(rmat, bmat); + Mat4MulMat4(bmat, pchan->pose_mat, rmat); + Mat4Ortho(bmat); + boneRot.setValue(bmat[0]); + GetJointRotation(boneRot, ikchan->jointType, rot); + if (ikchan->jointType & IK_TRANSY) { + // compute actual length + rot[ikchan->ndof-1] = VecLenf(pchan->pose_tail, pchan->pose_head) * scale; + } + rot += ikchan->ndof; + joint += ikchan->ndof; + } +} + +// compute array of joint value corresponding to current pose +static void rest_pose(IK_Scene *ikscene) +{ + bPoseChannel *pchan; + IK_Channel *ikchan; + Bone *bone; + float scale; + double *rot; + int a, joint; + + // assume uniform scaling and take Y scale as general scale for the armature + scale = VecLength(ikscene->blArmature->obmat[1]); + // rest pose is 0 + KDL::SetToZero(ikscene->jointArray); + // except for transY joints + rot = &ikscene->jointArray(0); + for(joint=a=0, ikchan = ikscene->channels; a<ikscene->numchan && joint<ikscene->numjoint; ++a, ++ikchan) { + pchan= ikchan->pchan; + bone= pchan->bone; + + if (ikchan->jointType & IK_TRANSY) + rot[ikchan->ndof-1] = bone->length*scale; + rot += ikchan->ndof; + joint += ikchan->ndof; + } +} + +static IK_Scene* convert_tree(Scene *blscene, Object *ob, bPoseChannel *pchan) +{ + PoseTree *tree = (PoseTree*)pchan->iktree.first; + PoseTarget *target; + bKinematicConstraint *condata; + bConstraint *polarcon; + bItasc *ikparam; + iTaSC::Armature* arm; + iTaSC::Scene* scene; + IK_Scene* ikscene; + IK_Channel* ikchan; + KDL::Frame initPose; + KDL::Rotation boneRot; + Bone *bone; + int a, numtarget; + unsigned int t; + float length; + bool ret = true, ingame; + double *rot; + + if (tree->totchannel == 0) + return NULL; + + ikscene = new IK_Scene; + arm = new iTaSC::Armature(); + scene = new iTaSC::Scene(); + ikscene->channels = new IK_Channel[tree->totchannel]; + ikscene->numchan = tree->totchannel; + ikscene->armature = arm; + ikscene->scene = scene; + ikparam = (bItasc*)ob->pose->ikparam; + ingame = (ob->pose->flag & POSE_GAME_ENGINE); + if (!ikparam) { + // you must have our own copy + ikparam = &DefIKParam; + } else if (ingame) { + // tweak the param when in game to have efficient stepping + // using fixed substep is not effecient since frames in the GE are often + // shorter than in animation => move to auto step automatically and set + // the target substep duration via min/max + if (!(ikparam->flag & ITASC_AUTO_STEP)) { + float timestep = blscene->r.frs_sec_base/blscene->r.frs_sec; + if (ikparam->numstep > 0) + timestep /= ikparam->numstep; + // with equal min and max, the algorythm will take this step and the indicative substep most of the time + ikparam->minstep = ikparam->maxstep = timestep; + ikparam->flag |= ITASC_AUTO_STEP; + } + } + if ((ikparam->flag & ITASC_SIMULATION) && !ingame) + // no cache in animation mode + ikscene->cache = new iTaSC::Cache(); + + switch (ikparam->solver) { + case ITASC_SOLVER_SDLS: + ikscene->solver = new iTaSC::WSDLSSolver(); + break; + case ITASC_SOLVER_DLS: + ikscene->solver = new iTaSC::WDLSSolver(); + break; + default: + delete ikscene; + return NULL; + } + ikscene->blArmature = ob; + + std::string joint; + std::string root("root"); + std::string parent; + std::vector<double> weights; + double weight[3]; + // assume uniform scaling and take Y scale as general scale for the armature + float scale = VecLength(ob->obmat[1]); + // build the array of joints corresponding to the IK chain + convert_channels(ikscene, tree); + if (ingame) { + // in the GE, set the initial joint angle to match the current pose + // this will update the jointArray in ikscene + convert_pose(ikscene); + } else { + // in Blender, the rest pose is always 0 for joints + rest_pose(ikscene); + } + rot = &ikscene->jointArray(0); + for(a=0, ikchan = ikscene->channels; a<tree->totchannel; ++a, ++ikchan) { + pchan= ikchan->pchan; + bone= pchan->bone; + + KDL::Frame tip(iTaSC::F_identity); + Vector3 *fl = bone->bone_mat; + KDL::Frame head(KDL::Rotation( + fl[0][0], fl[1][0], fl[2][0], + fl[0][1], fl[1][1], fl[2][1], + fl[0][2], fl[1][2], fl[2][2]), + KDL::Vector(bone->head[0], bone->head[1], bone->head[2])*scale); + + // rest pose length of the bone taking scaling into account + length= bone->length*scale; + parent = (a > 0) ? ikscene->channels[tree->parent[a]].tail : root; + // first the fixed segment to the bone head + if (head.p.Norm() > KDL::epsilon || head.M.GetRot().Norm() > KDL::epsilon) { + joint = bone->name; + joint += ":H"; + ret = arm->addSegment(joint, parent, KDL::Joint::None, 0.0, head); + parent = joint; + } + if (!(ikchan->jointType & IK_TRANSY)) { + // fixed length, put it in tip + tip.p[1] = length; + } + joint = bone->name; + weight[0] = (1.0-pchan->stiffness[0]); + weight[1] = (1.0-pchan->stiffness[1]); + weight[2] = (1.0-pchan->stiffness[2]); + switch (ikchan->jointType & ~IK_TRANSY) + { + case 0: + // fixed bone + if (!(ikchan->jointType & IK_TRANSY)) { + joint += ":F"; + ret = arm->addSegment(joint, parent, KDL::Joint::None, 0.0, tip); + } + break; + case IK_XDOF: + // RX only, get the X rotation + joint += ":RX"; + ret = arm->addSegment(joint, parent, KDL::Joint::RotX, rot[0], tip); + weights.push_back(weight[0]); + break; + case IK_YDOF: + // RY only, get the Y rotation + joint += ":RY"; + ret = arm->addSegment(joint, parent, KDL::Joint::RotY, rot[0], tip); + weights.push_back(weight[1]); + break; + case IK_ZDOF: + // RZ only, get the Zz rotation + joint += ":RZ"; + ret = arm->addSegment(joint, parent, KDL::Joint::RotZ, rot[0], tip); + weights.push_back(weight[2]); + break; + case IK_XDOF|IK_YDOF: + joint += ":RX"; + ret = arm->addSegment(joint, parent, KDL::Joint::RotX, rot[0]); + weights.push_back(weight[0]); + if (ret) { + parent = joint; + joint = bone->name; + joint += ":RY"; + ret = arm->addSegment(joint, parent, KDL::Joint::RotY, rot[1], tip); + weights.push_back(weight[1]); + } + break; + case IK_SWING: + joint += ":SW"; + ret = arm->addSegment(joint, parent, KDL::Joint::Swing, rot[0], tip); + weights.push_back(weight[0]); + weights.push_back(weight[2]); + break; + case IK_YDOF|IK_ZDOF: + // RZ+RY + joint += ":RZ"; + ret = arm->addSegment(joint, parent, KDL::Joint::RotZ, rot[0]); + weights.push_back(weight[2]); + if (ret) { + parent = joint; + joint = bone->name; + joint += ":RY"; + ret = arm->addSegment(joint, parent, KDL::Joint::RotY, rot[1], tip); + weights.push_back(weight[1]); + } + break; + case IK_SWING|IK_YDOF: + // decompose in a Swing+RotY joint + joint += ":SW"; + ret = arm->addSegment(joint, parent, KDL::Joint::Swing, rot[0]); + weights.push_back(weight[0]); + weights.push_back(weight[2]); + if (ret) { + parent = joint; + joint = bone->name; + joint += ":RY"; + ret = arm->addSegment(joint, parent, KDL::Joint::RotY, rot[2], tip); + weights.push_back(weight[1]); + } + break; + case IK_REVOLUTE: + joint += ":SJ"; + ret = arm->addSegment(joint, parent, KDL::Joint::Sphere, rot[0], tip); + weights.push_back(weight[0]); + weights.push_back(weight[1]); + weights.push_back(weight[2]); + break; + } + if (ret && (ikchan->jointType & IK_TRANSY)) { + parent = joint; + joint = bone->name; + joint += ":TY"; + ret = arm->addSegment(joint, parent, KDL::Joint::TransY, rot[ikchan->ndof-1]); + float ikstretch = pchan->ikstretch*pchan->ikstretch; + weight[1] = (1.0-MIN2(1.0-ikstretch, 0.99)); + weights.push_back(weight[1]); + } + if (!ret) + // error making the armature?? + break; + // joint points to the segment that correspond to the bone per say + ikchan->tail = joint; + ikchan->head = parent; + // in case of error + ret = false; + if ((ikchan->jointType & IK_XDOF) && (pchan->ikflag & (BONE_IK_XLIMIT|BONE_IK_ROTCTL))) { + joint = bone->name; + joint += ":RX"; + if (pchan->ikflag & BONE_IK_XLIMIT) { + if (arm->addLimitConstraint(joint, 0, pchan->limitmin[0], pchan->limitmax[0]) < 0) + break; + } + if (pchan->ikflag & BONE_IK_ROTCTL) { + if (arm->addConstraint(joint, joint_callback, ikchan, false, false) < 0) + break; + } + } + if ((ikchan->jointType & IK_YDOF) && (pchan->ikflag & (BONE_IK_YLIMIT|BONE_IK_ROTCTL))) { + joint = bone->name; + joint += ":RY"; + if (pchan->ikflag & BONE_IK_YLIMIT) { + if (arm->addLimitConstraint(joint, 0, pchan->limitmin[1], pchan->limitmax[1]) < 0) + break; + } + if (pchan->ikflag & BONE_IK_ROTCTL) { + if (arm->addConstraint(joint, joint_callback, ikchan, false, false) < 0) + break; + } + } + if ((ikchan->jointType & IK_ZDOF) && (pchan->ikflag & (BONE_IK_ZLIMIT|BONE_IK_ROTCTL))) { + joint = bone->name; + joint += ":RZ"; + if (pchan->ikflag & BONE_IK_ZLIMIT) { + if (arm->addLimitConstraint(joint, 0, pchan->limitmin[2], pchan->limitmax[2]) < 0) + break; + } + if (pchan->ikflag & BONE_IK_ROTCTL) { + if (arm->addConstraint(joint, joint_callback, ikchan, false, false) < 0) + break; + } + } + if ((ikchan->jointType & IK_SWING) && (pchan->ikflag & (BONE_IK_XLIMIT|BONE_IK_ZLIMIT|BONE_IK_ROTCTL))) { + joint = bone->name; + joint += ":SW"; + if (pchan->ikflag & BONE_IK_XLIMIT) { + if (arm->addLimitConstraint(joint, 0, pchan->limitmin[0], pchan->limitmax[0]) < 0) + break; + } + if (pchan->ikflag & BONE_IK_ZLIMIT) { + if (arm->addLimitConstraint(joint, 1, pchan->limitmin[2], pchan->limitmax[2]) < 0) + break; + } + if (pchan->ikflag & BONE_IK_ROTCTL) { + if (arm->addConstraint(joint, joint_callback, ikchan, false, false) < 0) + break; + } + } + if ((ikchan->jointType & IK_REVOLUTE) && (pchan->ikflag & BONE_IK_ROTCTL)) { + joint = bone->name; + joint += ":SJ"; + if (arm->addConstraint(joint, joint_callback, ikchan, false, false) < 0) + break; + } + // no error, so restore + ret = true; + rot += ikchan->ndof; + } + if (!ret) { + delete ikscene; + return NULL; + } + // for each target, we need to add an end effector in the armature + for (numtarget=0, polarcon=NULL, ret = true, target=(PoseTarget*)tree->targets.first; target; target=(PoseTarget*)target->next) { + condata= (bKinematicConstraint*)target->con->data; + pchan = tree->pchan[target->tip]; + + if (is_cartesian_constraint(target->con)) { + // add the end effector + IK_Target* iktarget = new IK_Target(); + ikscene->targets.push_back(iktarget); + iktarget->ee = arm->addEndEffector(ikscene->channels[target->tip].tail); + if (iktarget->ee == -1) { + ret = false; + break; + } + // initialize all the fields that we can set at this time + iktarget->blenderConstraint = target->con; + iktarget->channel = target->tip; + iktarget->simulation = (ikparam->flag & ITASC_SIMULATION); + iktarget->rootChannel = ikscene->channels[0].pchan; + iktarget->owner = ob; + iktarget->targetName = pchan->bone->name; + iktarget->targetName += ":T:"; + iktarget->targetName += target->con->name; + iktarget->constraintName = pchan->bone->name; + iktarget->constraintName += ":C:"; + iktarget->constraintName += target->con->name; + numtarget++; + if (condata->poletar) + // this constraint has a polar target + polarcon = target->con; + } + } + // deal with polar target if any + if (numtarget == 1 && polarcon) { + ikscene->polarConstraint = polarcon; + } + // we can now add the armature + // the armature is based on a moving frame. + // initialize with the correct position in case there is no cache + base_callback(iTaSC::Timestamp(), iTaSC::F_identity, initPose, ikscene); + ikscene->base = new iTaSC::MovingFrame(initPose); + ikscene->base->setCallback(base_callback, ikscene); + std::string armname; + armname = ob->id.name; + armname += ":B"; + ret = scene->addObject(armname, ikscene->base); + armname = ob->id.name; + armname += ":AR"; + if (ret) + ret = scene->addObject(armname, ikscene->armature, ikscene->base); + if (!ret) { + delete ikscene; + return NULL; + } + // set the weight + e_matrix& Wq = arm->getWq(); + assert(Wq.cols() == (int)weights.size()); + for (int q=0; q<Wq.cols(); q++) + Wq(q,q)=weights[q]; + // get the inverse rest pose frame of the base to compute relative rest pose of end effectors + // this is needed to handle the enforce parameter + // ikscene->pchan[0] is the root channel of the tree + // if it has no parent, then it's just the identify Frame + float invBaseFrame[4][4]; + pchan = ikscene->channels[0].pchan; + if (pchan->parent) { + // it has a parent, get the pose matrix from it + float baseFrame[4][4]; + pchan = pchan->parent; + Mat4CpyMat4(baseFrame, pchan->bone->arm_mat); + // move to the tail and scale to get rest pose of armature base + VecCopyf(baseFrame[3], pchan->bone->arm_tail); + Mat4Invert(invBaseFrame, baseFrame); + } else { + Mat4One(invBaseFrame); + } + // finally add the constraint + for (t=0; t<ikscene->targets.size(); t++) { + IK_Target* iktarget = ikscene->targets[t]; + condata= (bKinematicConstraint*)iktarget->blenderConstraint->data; + pchan = tree->pchan[iktarget->channel]; + unsigned int controltype, bonecnt; + double bonelen; + float mat[4][4]; + + // add the end effector + // estimate the average bone length, used to clamp feedback error + for (bonecnt=0, bonelen=0.f, a=iktarget->channel; a>=0; a=tree->parent[a], bonecnt++) + bonelen += scale*tree->pchan[a]->bone->length; + bonelen /= bonecnt; + + // store the rest pose of the end effector to compute enforce target + Mat4CpyMat4(mat, pchan->bone->arm_mat); + VecCopyf(mat[3], pchan->bone->arm_tail); + // get the rest pose relative to the armature base + Mat4MulMat4(iktarget->eeRest, mat, invBaseFrame); + iktarget->eeBlend = (!ikscene->polarConstraint && condata->type==CONSTRAINT_IK_COPYPOSE) ? true : false; + // use target_callback to make sure the initPose includes enforce coefficient + target_callback(iTaSC::Timestamp(), iTaSC::F_identity, initPose, iktarget); + iktarget->target = new iTaSC::MovingFrame(initPose); + iktarget->target->setCallback(target_callback, iktarget); + ret = scene->addObject(iktarget->targetName, iktarget->target); + if (!ret) + break; + + switch (condata->type) { + case CONSTRAINT_IK_COPYPOSE: + controltype = 0; + if ((condata->flag & CONSTRAINT_IK_ROT) && (condata->orientweight != 0.0)) + controltype |= iTaSC::CopyPose::CTL_ROTATION; + if ((condata->weight != 0.0)) + controltype |= iTaSC::CopyPose::CTL_POSITION; + if (controltype) { + iktarget->constraint = new iTaSC::CopyPose(controltype, controltype, bonelen); + // set the gain + if (controltype & iTaSC::CopyPose::CTL_POSITION) + iktarget->constraint->setControlParameter(iTaSC::CopyPose::ID_POSITION, iTaSC::ACT_ALPHA, condata->weight); + if (controltype & iTaSC::CopyPose::CTL_ROTATION) + iktarget->constraint->setControlParameter(iTaSC::CopyPose::ID_ROTATION, iTaSC::ACT_ALPHA, condata->orientweight); + iktarget->constraint->registerCallback(copypose_callback, iktarget); + iktarget->errorCallback = copypose_error; + iktarget->controlType = controltype; + // add the constraint + ret = scene->addConstraintSet(iktarget->constraintName, iktarget->constraint, armname, iktarget->targetName, ikscene->channels[iktarget->channel].tail); + } + break; + case CONSTRAINT_IK_DISTANCE: + iktarget->constraint = new iTaSC::Distance(bonelen); + iktarget->constraint->setControlParameter(iTaSC::Distance::ID_DISTANCE, iTaSC::ACT_VALUE, condata->dist); + iktarget->constraint->registerCallback(distance_callback, iktarget); + iktarget->errorCallback = distance_error; + // we can update the weight on each substep + iktarget->constraint->substep(true); + // add the constraint + ret = scene->addConstraintSet(iktarget->constraintName, iktarget->constraint, armname, iktarget->targetName, ikscene->channels[iktarget->channel].tail); + break; + } + if (!ret) + break; + } + if (!ret || + !scene->addCache(ikscene->cache) || + !scene->addSolver(ikscene->solver) || + !scene->initialize()) { + delete ikscene; + ikscene = NULL; + } + return ikscene; +} + +static void create_scene(Scene *scene, Object *ob) +{ + bPoseChannel *pchan; + + // create the IK scene + for(pchan= (bPoseChannel *)ob->pose->chanbase.first; pchan; pchan= (bPoseChannel *)pchan->next) { + // by construction there is only one tree + PoseTree *tree = (PoseTree*)pchan->iktree.first; + if (tree) { + IK_Data* ikdata = get_ikdata(ob->pose); + // convert tree in iTaSC::Scene + IK_Scene* ikscene = convert_tree(scene, ob, pchan); + if (ikscene) { + ikscene->next = ikdata->first; + ikdata->first = ikscene; + } + // delete the trees once we are done + while(tree) { + BLI_remlink(&pchan->iktree, tree); + BLI_freelistN(&tree->targets); + if(tree->pchan) MEM_freeN(tree->pchan); + if(tree->parent) MEM_freeN(tree->parent); + if(tree->basis_change) MEM_freeN(tree->basis_change); + MEM_freeN(tree); + tree = (PoseTree*)pchan->iktree.first; + } + } + } +} + +static void init_scene(Object *ob) +{ + if (ob->pose->ikdata) { + for(IK_Scene* scene = ((IK_Data*)ob->pose->ikdata)->first; + scene != NULL; + scene = scene->next) { + scene->channels[0].pchan->flag |= POSE_IKTREE; + } + } +} + +static void execute_scene(Scene* blscene, IK_Scene* ikscene, bItasc* ikparam, float ctime, float frtime) +{ + int i; + IK_Channel* ikchan; + if (ikparam->flag & ITASC_SIMULATION) { + for (i=0, ikchan=ikscene->channels; i<ikscene->numchan; i++, ++ikchan) { + // In simulation mode we don't allow external contraint to change our bones, mark the channel done + // also tell Blender that this channel is part of IK tree (cleared on each where_is_pose() + ikchan->pchan->flag |= (POSE_DONE|POSE_CHAIN); + ikchan->jointValid = 0; + } + } else { + // in animation mode, we must get the bone position from action and constraints + for(i=0, ikchan=ikscene->channels; i<ikscene->numchan; i++, ++ikchan) { + if (!(ikchan->pchan->flag & POSE_DONE)) + where_is_pose_bone(blscene, ikscene->blArmature, ikchan->pchan, ctime); + // tell blender that this channel was controlled by IK, it's cleared on each where_is_pose() + ikchan->pchan->flag |= (POSE_DONE|POSE_CHAIN); + ikchan->jointValid = 0; + } + } + // only run execute the scene if at least one of our target is enabled + for (i=ikscene->targets.size(); i > 0; --i) { + IK_Target* iktarget = ikscene->targets[i-1]; + if (!(iktarget->blenderConstraint->flag & CONSTRAINT_OFF)) + break; + } + if (i == 0 && ikscene->armature->getNrOfConstraints() == 0) + // all constraint disabled + return; + + // compute timestep + double timestamp = ctime * frtime + 2147483.648; + double timestep = frtime; + bool reiterate = (ikparam->flag & ITASC_REITERATION) ? true : false; + int numstep = (ikparam->flag & ITASC_AUTO_STEP) ? 0 : ikparam->numstep; + bool simulation = true; + + if (ikparam->flag & ITASC_SIMULATION) { + ikscene->solver->setParam(iTaSC::Solver::DLS_QMAX, ikparam->maxvel); + } + else { + // in animation mode we start from the pose after action and constraint + convert_pose(ikscene); + ikscene->armature->setJointArray(ikscene->jointArray); + // and we don't handle velocity + reiterate = true; + simulation = false; + // time is virtual, so take fixed value for velocity parameters (see itasc_update_param) + // and choose 1s timestep to allow having velocity parameters in radiant + timestep = 1.0; + // use auto setup to let the solver test the variation of the joints + numstep = 0; + } + + if (ikscene->cache && !reiterate && simulation) { + iTaSC::CacheTS sts, cts; + sts = cts = (iTaSC::CacheTS)(timestamp*1000.0+0.5); + if (ikscene->cache->getPreviousCacheItem(ikscene->armature, 0, &cts) == NULL || cts == 0) { + // the cache is empty before this time, reiterate + if (ikparam->flag & ITASC_INITIAL_REITERATION) + reiterate = true; + } else { + // can take the cache as a start point. + sts -= cts; + timestep = sts/1000.0; + } + } + // don't cache if we are reiterating because we don't want to distroy the cache unnecessarily + ikscene->scene->update(timestamp, timestep, numstep, false, !reiterate, simulation); + if (reiterate) { + // how many times do we reiterate? + for (i=0; i<ikparam->numiter; i++) { + if (ikscene->armature->getMaxJointChange() < ikparam->precision || + ikscene->armature->getMaxEndEffectorChange() < ikparam->precision) + break; + ikscene->scene->update(timestamp, timestep, numstep, true, false, simulation); + } + if (simulation) { + // one more fake iteration to cache + ikscene->scene->update(timestamp, 0.0, 1, true, true, true); + } + } + // compute constraint error + for (i=ikscene->targets.size(); i > 0; --i) { + IK_Target* iktarget = ikscene->targets[i-1]; + if (!(iktarget->blenderConstraint->flag & CONSTRAINT_OFF)) { + unsigned int nvalues; + const iTaSC::ConstraintValues* values; + values = iktarget->constraint->getControlParameters(&nvalues); + iktarget->errorCallback(values, nvalues, iktarget); + } + } + // Apply result to bone: + // walk the ikscene->channels + // for each, get the Frame of the joint corresponding to the bone relative to its parent + // combine the parent and the joint frame to get the frame relative to armature + // a backward translation of the bone length gives the head + // if TY, compute the scale as the ratio of the joint length with rest pose length + iTaSC::Armature* arm = ikscene->armature; + KDL::Frame frame; + double q_rest[3], q[3]; + const KDL::Joint* joint; + const KDL::Frame* tip; + bPoseChannel* pchan; + float scale; + float length; + float yaxis[3]; + for (i=0, ikchan=ikscene->channels; i<ikscene->numchan; ++i, ++ikchan) { + if (i == 0) { + if (!arm->getRelativeFrame(frame, ikchan->tail)) + break; + // this frame is relative to base, make it relative to object + ikchan->frame = ikscene->baseFrame * frame; + } + else { + if (!arm->getRelativeFrame(frame, ikchan->tail, ikscene->channels[ikchan->parent].tail)) + break; + // combine with parent frame to get frame relative to object + ikchan->frame = ikscene->channels[ikchan->parent].frame * frame; + } + // ikchan->frame is the tail frame relative to object + // get bone length + if (!arm->getSegment(ikchan->tail, 3, joint, q_rest[0], q[0], tip)) + break; + if (joint->getType() == KDL::Joint::TransY) { + // stretch bones have a TY joint, compute the scale + scale = (float)(q[0]/q_rest[0]); + // the length is the joint itself + length = (float)q[0]; + } + else { + scale = 1.0f; + // for fixed bone, the length is in the tip (always along Y axis) + length = tip->p(1); + } + // ready to compute the pose mat + pchan = ikchan->pchan; + // tail mat + ikchan->frame.getValue(&pchan->pose_mat[0][0]); + VECCOPY(pchan->pose_tail, pchan->pose_mat[3]); + // shift to head + VECCOPY(yaxis, pchan->pose_mat[1]); + VecMulf(yaxis, length); + VecSubf(pchan->pose_mat[3], pchan->pose_mat[3], yaxis); + VECCOPY(pchan->pose_head, pchan->pose_mat[3]); + // add scale + VecMulf(pchan->pose_mat[0], scale); + VecMulf(pchan->pose_mat[1], scale); + VecMulf(pchan->pose_mat[2], scale); + } + if (i<ikscene->numchan) { + // big problem + ; + } +} + +//--------------------------------------------------- +// plugin interface +// +void itasc_initialize_tree(struct Scene *scene, Object *ob, float ctime) +{ + bPoseChannel *pchan; + int count = 0; + + if (ob->pose->ikdata != NULL && !(ob->pose->flag & POSE_WAS_REBUILT)) { + init_scene(ob); + return; + } + // first remove old scene + itasc_clear_data(ob->pose); + // we should handle all the constraint and mark them all disabled + // for blender but we'll start with the IK constraint alone + for(pchan= (bPoseChannel *)ob->pose->chanbase.first; pchan; pchan= (bPoseChannel *)pchan->next) { + if(pchan->constflag & PCHAN_HAS_IK) + count += initialize_scene(ob, pchan); + } + // if at least one tree, create the scenes from the PoseTree stored in the channels + if (count) + create_scene(scene, ob); + itasc_update_param(ob->pose); + // make sure we don't rebuilt until the user changes something important + ob->pose->flag &= ~POSE_WAS_REBUILT; +} + +void itasc_execute_tree(struct Scene *scene, struct Object *ob, struct bPoseChannel *pchan, float ctime) +{ + if (ob->pose->ikdata) { + IK_Data* ikdata = (IK_Data*)ob->pose->ikdata; + bItasc* ikparam = (bItasc*) ob->pose->ikparam; + // we need default parameters + if (!ikparam) ikparam = &DefIKParam; + + for (IK_Scene* ikscene = ikdata->first; ikscene; ikscene = ikscene->next) { + if (ikscene->channels[0].pchan == pchan) { + float timestep = scene->r.frs_sec_base/scene->r.frs_sec; + if (ob->pose->flag & POSE_GAME_ENGINE) { + timestep = ob->pose->ctime; + // limit the timestep to avoid excessive number of iteration + if (timestep > 0.2f) + timestep = 0.2f; + } + execute_scene(scene, ikscene, ikparam, ctime, timestep); + break; + } + } + } +} + +void itasc_release_tree(struct Scene *scene, struct Object *ob, float ctime) +{ + // not used for iTaSC +} + +void itasc_clear_data(struct bPose *pose) +{ + if (pose->ikdata) { + IK_Data* ikdata = (IK_Data*)pose->ikdata; + for (IK_Scene* scene = ikdata->first; scene; scene = ikdata->first) { + ikdata->first = scene->next; + delete scene; + } + MEM_freeN(ikdata); + pose->ikdata = NULL; + } +} + +void itasc_clear_cache(struct bPose *pose) +{ + if (pose->ikdata) { + IK_Data* ikdata = (IK_Data*)pose->ikdata; + for (IK_Scene* scene = ikdata->first; scene; scene = scene->next) { + if (scene->cache) + // clear all cache but leaving the timestamp 0 (=rest pose) + scene->cache->clearCacheFrom(NULL, 1); + } + } +} + +void itasc_update_param(struct bPose *pose) +{ + if (pose->ikdata && pose->ikparam) { + IK_Data* ikdata = (IK_Data*)pose->ikdata; + bItasc* ikparam = (bItasc*)pose->ikparam; + for (IK_Scene* ikscene = ikdata->first; ikscene; ikscene = ikscene->next) { + double armlength = ikscene->armature->getArmLength(); + ikscene->solver->setParam(iTaSC::Solver::DLS_LAMBDA_MAX, ikparam->dampmax*armlength); + ikscene->solver->setParam(iTaSC::Solver::DLS_EPSILON, ikparam->dampeps*armlength); + if (ikparam->flag & ITASC_SIMULATION) { + ikscene->scene->setParam(iTaSC::Scene::MIN_TIMESTEP, ikparam->minstep); + ikscene->scene->setParam(iTaSC::Scene::MAX_TIMESTEP, ikparam->maxstep); + ikscene->solver->setParam(iTaSC::Solver::DLS_QMAX, ikparam->maxvel); + ikscene->armature->setControlParameter(CONSTRAINT_ID_ALL, iTaSC::Armature::ID_JOINT, iTaSC::ACT_FEEDBACK, ikparam->feedback); + } else { + // in animation mode timestep is 1s by convention => + // qmax becomes radiant and feedback becomes fraction of error gap corrected in one iteration + ikscene->scene->setParam(iTaSC::Scene::MIN_TIMESTEP, 1.0); + ikscene->scene->setParam(iTaSC::Scene::MAX_TIMESTEP, 1.0); + ikscene->solver->setParam(iTaSC::Solver::DLS_QMAX, 0.52); + ikscene->armature->setControlParameter(CONSTRAINT_ID_ALL, iTaSC::Armature::ID_JOINT, iTaSC::ACT_FEEDBACK, 0.8); + } + } + } +} + +void itasc_test_constraint(struct Object *ob, struct bConstraint *cons) +{ + struct bKinematicConstraint *data = (struct bKinematicConstraint *)cons->data; + + /* only for IK constraint */ + if (cons->type != CONSTRAINT_TYPE_KINEMATIC || data == NULL) + return; + + switch (data->type) { + case CONSTRAINT_IK_COPYPOSE: + case CONSTRAINT_IK_DISTANCE: + /* cartesian space constraint */ + break; + } +} + diff --git a/source/blender/ikplugin/intern/itasc_plugin.h b/source/blender/ikplugin/intern/itasc_plugin.h new file mode 100644 index 00000000000..25e48965a52 --- /dev/null +++ b/source/blender/ikplugin/intern/itasc_plugin.h @@ -0,0 +1,52 @@ +/** + * $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. + * + * Original author: Benoit Bolsee + * Contributor(s): + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef ITASC_PLUGIN_H +#define ITASC_PLUGIN_H + +#include "ikplugin_api.h" + +#ifdef __cplusplus +extern "C" { +#endif + +void itasc_initialize_tree(struct Scene *scene, struct Object *ob, float ctime); +void itasc_execute_tree(struct Scene *scene, struct Object *ob, struct bPoseChannel *pchan, float ctime); +void itasc_release_tree(struct Scene *scene, struct Object *ob, float ctime); +void itasc_clear_data(struct bPose *pose); +void itasc_clear_cache(struct bPose *pose); +void itasc_update_param(struct bPose *pose); +void itasc_test_constraint(struct Object *ob, struct bConstraint *cons); + +#ifdef __cplusplus +} +#endif + +#endif // ITASC_PLUGIN_H + diff --git a/source/blender/makesdna/DNA_action_types.h b/source/blender/makesdna/DNA_action_types.h index 318204e3dd8..2ed08150f3e 100644 --- a/source/blender/makesdna/DNA_action_types.h +++ b/source/blender/makesdna/DNA_action_types.h @@ -146,7 +146,9 @@ typedef struct bPoseChannel { float limitmin[3], limitmax[3]; /* DOF constraint */ float stiffness[3]; /* DOF stiffness */ float ikstretch; - + float ikrotweight; /* weight of joint rotation constraint */ + float iklinweight; /* weight of joint stretch constraint */ + float *path; /* totpath x 3 x float */ struct Object *custom; /* draws custom object instead of this channel */ } bPoseChannel; @@ -166,7 +168,8 @@ typedef enum ePchan_Flag { POSE_CHAIN = 0x0200, POSE_DONE = 0x0400, POSE_KEY = 0x1000, - POSE_STRIDE = 0x2000 + POSE_STRIDE = 0x2000, + POSE_IKTREE = 0x4000, } ePchan_Flag; /* PoseChannel constflag (constraint detection) */ @@ -190,9 +193,13 @@ typedef enum ePchan_IkFlag { BONE_IK_YLIMIT = (1<<4), BONE_IK_ZLIMIT = (1<<5), + BONE_IK_ROTCTL = (1<<6), + BONE_IK_LINCTL = (1<<7), + BONE_IK_NO_XDOF_TEMP = (1<<10), BONE_IK_NO_YDOF_TEMP = (1<<11), - BONE_IK_NO_ZDOF_TEMP = (1<<12) + BONE_IK_NO_ZDOF_TEMP = (1<<12), + } ePchan_IkFlag; /* PoseChannel->rotmode */ @@ -209,6 +216,7 @@ typedef enum ePchan_RotMode { /* NOTE: space is reserved here for 18 other possible * euler rotation orders not implemented */ + PCHAN_ROT_MAX, /* sentinel for Py API*/ /* axis angle rotations */ PCHAN_ROT_AXISANGLE = -1 } ePchan_RotMode; @@ -233,7 +241,9 @@ typedef struct bPose { ListBase agroups; /* list of bActionGroups */ int active_group; /* index of active group (starts from 1) */ - int pad; + int iksolver; /* ik solver to use, see ePose_IKSolverType */ + void *ikdata; /* temporary IK data, depends on the IK solver. Not saved in file */ + void *ikparam; /* IK solver parameters, structure depends on iksolver */ } bPose; @@ -249,8 +259,53 @@ typedef enum ePose_Flags { POSE_CONSTRAINTS_TIMEDEPEND = (1<<3), /* recalculate bone paths */ POSE_RECALCPATHS = (1<<4), + /* set by armature_rebuild_pose to give a chance to the IK solver to rebuild IK tree */ + POSE_WAS_REBUILT = (1<<5), + /* set by game_copy_pose to indicate that this pose is used in the game engine */ + POSE_GAME_ENGINE = (1<<6), } ePose_Flags; +/* bPose->iksolver and bPose->ikparam->iksolver */ +typedef enum { + IKSOLVER_LEGACY = 0, + IKSOLVER_ITASC, +} ePose_IKSolverType; + +/* header for all bPose->ikparam structures */ +typedef struct bIKParam { + int iksolver; +} bIKParam; + +/* bPose->ikparam when bPose->iksolver=1 */ +typedef struct bItasc { + int iksolver; + float precision; + short numiter; + short numstep; + float minstep; + float maxstep; + short solver; + short flag; + float feedback; + float maxvel; /* max velocity to SDLS solver */ + float dampmax; /* maximum damping for DLS solver */ + float dampeps; /* threshold of singular value from which the damping start progressively */ +} bItasc; + +/* bItasc->flag */ +typedef enum { + ITASC_AUTO_STEP = (1<<0), + ITASC_INITIAL_REITERATION = (1<<1), + ITASC_REITERATION = (1<<2), + ITASC_SIMULATION = (1<<3), +} eItasc_Flags; + +/* bItasc->solver */ +typedef enum { + ITASC_SOLVER_SDLS = 0, /* selective damped least square, suitable for CopyPose constraint */ + ITASC_SOLVER_DLS /* damped least square with numerical filtering of damping */ +} eItasc_Solver; + /* ************************************************ */ /* Action */ @@ -372,12 +427,13 @@ typedef enum DOPESHEET_FILTERFLAG { ADS_FILTER_NOSCE = (1<<15), ADS_FILTER_NOPART = (1<<16), ADS_FILTER_NOMBA = (1<<17), + ADS_FILTER_NOARM = (1<<18), /* NLA-specific filters */ ADS_FILTER_NLA_NOACT = (1<<20), /* if the AnimData block has no NLA data, don't include to just show Action-line */ /* combination filters (some only used at runtime) */ - ADS_FILTER_NOOBDATA = (ADS_FILTER_NOCAM|ADS_FILTER_NOMAT|ADS_FILTER_NOLAM|ADS_FILTER_NOCUR|ADS_FILTER_NOPART), + ADS_FILTER_NOOBDATA = (ADS_FILTER_NOCAM|ADS_FILTER_NOMAT|ADS_FILTER_NOLAM|ADS_FILTER_NOCUR|ADS_FILTER_NOPART|ADS_FILTER_NOARM), } DOPESHEET_FILTERFLAG; /* DopeSheet general flags */ diff --git a/source/blender/makesdna/DNA_actuator_types.h b/source/blender/makesdna/DNA_actuator_types.h index 278da27faf9..58fa38ae159 100644 --- a/source/blender/makesdna/DNA_actuator_types.h +++ b/source/blender/makesdna/DNA_actuator_types.h @@ -142,7 +142,7 @@ typedef struct bGroupActuator { char name[32]; /* property or groupkey */ short pad[3], cur, butsta, butend;/* not referenced, can remove? */ - struct Group *group; /* only during game */ + /* struct Group *group; not used, remove */ } bGroupActuator; @@ -224,6 +224,15 @@ typedef struct bStateActuator { unsigned int mask; /* the bits to change */ } bStateActuator; +typedef struct bArmatureActuator { + char posechannel[32]; + char constraint[32]; + int type; /* 0=run, 1=enable, 2=disable, 3=set target, 4=set weight */ + float weight; + struct Object *target; + struct Object *subtarget; +} bArmatureActuator; + typedef struct bActuator { struct bActuator *next, *prev, *mynew; short type; @@ -295,6 +304,7 @@ typedef struct FreeCamera { #define ACT_PARENT 20 #define ACT_SHAPEACTION 21 #define ACT_STATE 22 +#define ACT_ARMATURE 23 /* actuator flag */ #define ACT_SHOW 1 @@ -484,6 +494,15 @@ typedef struct FreeCamera { #define ACT_PARENT_COMPOUND 1 #define ACT_PARENT_GHOST 2 +/* armatureactuator->type */ +#define ACT_ARM_RUN 0 +#define ACT_ARM_ENABLE 1 +#define ACT_ARM_DISABLE 2 +#define ACT_ARM_SETTARGET 3 +#define ACT_ARM_SETWEIGHT 4 +/* update this define if more type are addedd */ +#define ACT_ARM_MAXTYPE 4 + #endif diff --git a/source/blender/makesdna/DNA_anim_types.h b/source/blender/makesdna/DNA_anim_types.h index f75ed273164..c1e9ed4be40 100644 --- a/source/blender/makesdna/DNA_anim_types.h +++ b/source/blender/makesdna/DNA_anim_types.h @@ -763,6 +763,11 @@ typedef enum eAnimData_Flag { /* don't execute drivers */ ADT_DRIVERS_DISABLED = (1<<11), + /* AnimData block is selected in UI */ + ADT_UI_SELECTED = (1<<14), + /* AnimData block is active in UI */ + ADT_UI_ACTIVE = (1<<15), + /* F-Curves from this AnimData block are not visible in the Graph Editor */ ADT_CURVES_NOT_VISIBLE = (1<<16), } eAnimData_Flag; diff --git a/source/blender/makesdna/DNA_armature_types.h b/source/blender/makesdna/DNA_armature_types.h index bb60fb107ff..590e7dadcdc 100644 --- a/source/blender/makesdna/DNA_armature_types.h +++ b/source/blender/makesdna/DNA_armature_types.h @@ -31,6 +31,8 @@ #include "DNA_listBase.h" #include "DNA_ID.h" +struct AnimData; + /* this system works on different transformation space levels; 1) Bone Space; with each Bone having own (0,0,0) origin @@ -69,6 +71,7 @@ typedef struct Bone { typedef struct bArmature { ID id; + struct AnimData *adt; ListBase bonebase; ListBase chainbase; ListBase *edbo; /* editbone listbase, we use pointer so we can check state */ @@ -102,7 +105,8 @@ typedef enum eArmature_Flag { ARM_AUTO_IK = (1<<9), ARM_NO_CUSTOM = (1<<10), /* made option negative, for backwards compat */ ARM_COL_CUSTOM = (1<<11), /* draw custom colours */ - ARM_GHOST_ONLYSEL = (1<<12) /* when ghosting, only show selected bones (this should belong to ghostflag instead) */ + ARM_GHOST_ONLYSEL = (1<<12), /* when ghosting, only show selected bones (this should belong to ghostflag instead) */ + ARM_DS_EXPAND = (1<<13) } eArmature_Flag; /* armature->drawtype */ diff --git a/source/blender/makesdna/DNA_constraint_types.h b/source/blender/makesdna/DNA_constraint_types.h index 70430af3fc8..fccec7a556f 100644 --- a/source/blender/makesdna/DNA_constraint_types.h +++ b/source/blender/makesdna/DNA_constraint_types.h @@ -66,6 +66,9 @@ typedef struct bConstraint { int pad; struct Ipo *ipo; /* local influence ipo or driver */ // XXX depreceated for 2.5... old animation system hack + /* below are readonly fields that are set at runtime by the solver for use in the GE (only IK atm) */ + float lin_error; /* residual error on constraint expressed in blender unit*/ + float rot_error; /* residual error on constraint expressed in radiant */ } bConstraint; @@ -119,24 +122,34 @@ typedef struct bPythonConstraint { } bPythonConstraint; -/* Inverse-Kinematics (IK) constraint */ +/* inverse-Kinematics (IK) constraint + This constraint supports a variety of mode determine by the type field + according to B_CONSTRAINT_IK_TYPE. + Some fields are used by all types, some are specific to some types + This is indicated in the comments for each field + */ typedef struct bKinematicConstraint { - Object *tar; - short iterations; /* Maximum number of iterations to try */ - short flag; /* Like CONSTRAINT_IK_TIP */ - short rootbone; /* index to rootbone, if zero go all the way to mother bone */ - short max_rootbone; /* for auto-ik, maximum length of chain */ - char subtarget[32]; /* String to specify sub-object target */ - - Object *poletar; /* Pole vector target */ - char polesubtarget[32]; /* Pole vector sub-object target */ - float poleangle; /* Pole vector rest angle */ - - float weight; /* Weight of goal in IK tree */ - float orientweight; /* Amount of rotation a target applies on chain */ - float grabtarget[3]; /* for target-less IK */ + Object *tar; /* All: target object in case constraint needs a target */ + short iterations; /* All: Maximum number of iterations to try */ + short flag; /* All & CopyPose: some options Like CONSTRAINT_IK_TIP */ + short rootbone; /* All: index to rootbone, if zero go all the way to mother bone */ + short max_rootbone; /* CopyPose: for auto-ik, maximum length of chain */ + char subtarget[32]; /* All: String to specify sub-object target */ + Object *poletar; /* All: Pole vector target */ + char polesubtarget[32]; /* All: Pole vector sub-object target */ + float poleangle; /* All: Pole vector rest angle */ + float weight; /* All: Weight of constraint in IK tree */ + float orientweight; /* CopyPose: Amount of rotation a target applies on chain */ + float grabtarget[3]; /* CopyPose: for target-less IK */ + short type; /* subtype of IK constraint: B_CONSTRAINT_IK_TYPE */ + short mode; /* Distance: how to limit in relation to clamping sphere: LIMITDIST_.. */ + float dist; /* Distance: distance (radius of clamping sphere) from target */ } bKinematicConstraint; +typedef enum B_CONSTRAINT_IK_TYPE { + CONSTRAINT_IK_COPYPOSE = 0, /* 'standard' IK constraint: match position and/or orientation of target */ + CONSTRAINT_IK_DISTANCE /* maintain distance with target */ +} B_CONSTRAINT_IK_TYPE; /* Single-target subobject constraints --------------------- */ /* Track To Constraint */ @@ -376,7 +389,9 @@ typedef enum B_CONSTRAINT_FLAG { /* influence ipo is on constraint itself, not in action channel */ CONSTRAINT_OWN_IPO = (1<<7), /* indicates that constraint was added locally (i.e. didn't come from the proxy-lib) */ - CONSTRAINT_PROXY_LOCAL = (1<<8) + CONSTRAINT_PROXY_LOCAL = (1<<8), + /* indicates that constraint is temporarily disabled (only used in GE) */ + CONSTRAINT_OFF = (1<<9) } B_CONSTRAINT_FLAG; /* bConstraint->ownspace/tarspace */ diff --git a/source/blender/makesdna/DNA_curve_types.h b/source/blender/makesdna/DNA_curve_types.h index 109a9528de2..6cfeb646cf2 100644 --- a/source/blender/makesdna/DNA_curve_types.h +++ b/source/blender/makesdna/DNA_curve_types.h @@ -310,6 +310,7 @@ typedef enum eBezTriple_Interpolation { /* types of keyframe (used only for BezTriple->hide when BezTriple is used in F-Curves) */ typedef enum eBezTriple_KeyframeType { BEZT_KEYTYPE_KEYFRAME = 0, /* default - 'proper' Keyframe */ + BEZT_KEYTYPE_EXTREME, /* 'extreme' keyframe */ BEZT_KEYTYPE_BREAKDOWN, /* 'breakdown' keyframe */ } eBezTriple_KeyframeType; diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h index 54433fd4254..bcb85b5f87e 100644 --- a/source/blender/makesdna/DNA_modifier_types.h +++ b/source/blender/makesdna/DNA_modifier_types.h @@ -438,9 +438,7 @@ typedef struct CollisionModifierData { unsigned int numverts; unsigned int numfaces; - short absorption; /* used for forces, in % */ - short pad; - float time; /* cfra time of modifier */ + float time, pad; /* cfra time of modifier */ struct BVHTree *bvhtree; /* bounding volume hierarchy for this cloth object */ } CollisionModifierData; diff --git a/source/blender/makesdna/DNA_object_force.h b/source/blender/makesdna/DNA_object_force.h index 986a75f1a96..468ad35de85 100644 --- a/source/blender/makesdna/DNA_object_force.h +++ b/source/blender/makesdna/DNA_object_force.h @@ -62,6 +62,8 @@ typedef struct PartDeflect { float pdef_sbift; /* inner face thickness for softbody deflection */ float pdef_sboft; /* outer face thickness for softbody deflection */ + float absorption, pad; /* used for forces */ + /* variables for guide curve */ float clump_fac, clump_pow; float kink_freq, kink_shape, kink_amp, free_end; diff --git a/source/blender/makesdna/DNA_object_types.h b/source/blender/makesdna/DNA_object_types.h index a89f8e1fb2e..f0fd3e60cf2 100644 --- a/source/blender/makesdna/DNA_object_types.h +++ b/source/blender/makesdna/DNA_object_types.h @@ -243,6 +243,7 @@ typedef struct Object { ListBase gpulamp; /* runtime, for lamps only */ ListBase pc_ids; + ListBase *duplilist; /* for temporary dupli list storage, only for use by RNA API */ } Object; /* Warning, this is not used anymore because hooks are now modifiers */ @@ -263,6 +264,14 @@ typedef struct ObHook { float force; } ObHook; +typedef struct DupliObject { + struct DupliObject *next, *prev; + struct Object *ob; + unsigned int origlay; + int index, no_draw, type, animated; + float mat[4][4], omat[4][4]; + float orco[3], uv[2]; +} DupliObject; /* this work object is defined in object.c */ extern Object workob; diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h index 8a7d20fbc43..b192040ad5b 100644 --- a/source/blender/makesdna/DNA_scene_types.h +++ b/source/blender/makesdna/DNA_scene_types.h @@ -94,6 +94,8 @@ typedef struct FFMpegCodecData { int audio_codec; int video_bitrate; int audio_bitrate; + int audio_mixrate; + float audio_volume; int gop_size; int flags; @@ -107,10 +109,13 @@ typedef struct FFMpegCodecData { typedef struct AudioData { - int mixrate; - float main; /* Main mix in dB */ + int mixrate; // 2.5: now in FFMpegCodecData: audio_mixrate + float main; // 2.5: now in FFMpegCodecData: audio_volume + float speed_of_sound; + float doppler_factor; + int distance_model; short flag; - short pad[3]; + short pad; } AudioData; typedef struct SceneRenderLayer { @@ -175,7 +180,6 @@ typedef struct RenderData { struct AviCodecData *avicodecdata; struct QuicktimeCodecData *qtcodecdata; struct FFMpegCodecData ffcodecdata; - struct AudioData audio; /* new in 2.5 */ int cfra, sfra, efra; /* frames as in 'images' */ int psfra, pefra; /* start+end frames of preview range */ @@ -702,7 +706,7 @@ typedef struct Scene { /* migrate or replace? depends on some internal things... */ /* no, is on the right place (ton) */ struct RenderData r; - struct AudioData audio; /* DEPRECATED 2.5 */ + struct AudioData audio; ListBase markers; ListBase transform_spaces; diff --git a/source/blender/makesdna/DNA_sensor_types.h b/source/blender/makesdna/DNA_sensor_types.h index cc998de7eec..a5ba5886ed5 100644 --- a/source/blender/makesdna/DNA_sensor_types.h +++ b/source/blender/makesdna/DNA_sensor_types.h @@ -126,6 +126,13 @@ typedef struct bRaySensor { int axisflag; } bRaySensor; +typedef struct bArmatureSensor { + char posechannel[32]; + char constraint[32]; + int type; + float value; +} bArmatureSensor; + typedef struct bMessageSensor { /** * (Possible future use) pointer to a single sender object @@ -202,6 +209,15 @@ typedef struct bJoystickSensor { #define SENS_MESG_MESG 0 #define SENS_MESG_PROP 1 +/* bArmatureSensor->type */ +#define SENS_ARM_STATE_CHANGED 0 +#define SENS_ARM_LIN_ERROR_BELOW 1 +#define SENS_ARM_LIN_ERROR_ABOVE 2 +#define SENS_ARM_ROT_ERROR_BELOW 3 +#define SENS_ARM_ROT_ERROR_ABOVE 4 +/* update this when adding new type */ +#define SENS_ARM_MAXTYPE 4 + /* sensor->type */ #define SENS_ALWAYS 0 #define SENS_TOUCH 1 @@ -217,6 +233,7 @@ typedef struct bJoystickSensor { #define SENS_JOYSTICK 11 #define SENS_ACTUATOR 12 #define SENS_DELAY 13 +#define SENS_ARMATURE 14 /* sensor->flag */ #define SENS_SHOW 1 #define SENS_DEL 2 diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h index 806d12815b5..2cd47e340bd 100644 --- a/source/blender/makesdna/DNA_space_types.h +++ b/source/blender/makesdna/DNA_space_types.h @@ -569,18 +569,19 @@ typedef struct SpaceUserPref { /* buts->mainb new */ -#define BCONTEXT_SCENE 0 -#define BCONTEXT_WORLD 1 -#define BCONTEXT_OBJECT 2 -#define BCONTEXT_DATA 3 -#define BCONTEXT_MATERIAL 4 -#define BCONTEXT_TEXTURE 5 -#define BCONTEXT_PARTICLE 6 -#define BCONTEXT_PHYSICS 7 -#define BCONTEXT_BONE 9 -#define BCONTEXT_MODIFIER 10 -#define BCONTEXT_CONSTRAINT 12 -#define BCONTEXT_TOT 13 +#define BCONTEXT_SCENE 0 +#define BCONTEXT_WORLD 1 +#define BCONTEXT_OBJECT 2 +#define BCONTEXT_DATA 3 +#define BCONTEXT_MATERIAL 4 +#define BCONTEXT_TEXTURE 5 +#define BCONTEXT_PARTICLE 6 +#define BCONTEXT_PHYSICS 7 +#define BCONTEXT_BONE 9 +#define BCONTEXT_MODIFIER 10 +#define BCONTEXT_CONSTRAINT 12 +#define BCONTEXT_BONE_CONSTRAINT 13 +#define BCONTEXT_TOT 14 /* sbuts->flag */ #define SB_PRV_OSA 1 @@ -833,6 +834,7 @@ enum { #define TIME_SEQ 32 #define TIME_ALL_IMAGE_WIN 64 #define TIME_CONTINUE_PHYSICS 128 +#define TIME_NODES 256 /* sseq->mainb */ #define SEQ_DRAW_SEQUENCE 0 diff --git a/source/blender/makesdna/DNA_view3d_types.h b/source/blender/makesdna/DNA_view3d_types.h index d42ccd62694..f67a242b469 100644 --- a/source/blender/makesdna/DNA_view3d_types.h +++ b/source/blender/makesdna/DNA_view3d_types.h @@ -144,7 +144,7 @@ typedef struct View3D { * The drawing mode for the 3d display. Set to OB_WIRE, OB_SOLID, * OB_SHADED or OB_TEXTURE */ short drawtype; - short localview; + short pad2; short scenelock, around, pad3; short flag, flag2; diff --git a/source/blender/makesdna/DNA_windowmanager_types.h b/source/blender/makesdna/DNA_windowmanager_types.h index f1ce3491d0a..ea9d0e86c38 100644 --- a/source/blender/makesdna/DNA_windowmanager_types.h +++ b/source/blender/makesdna/DNA_windowmanager_types.h @@ -1,5 +1,5 @@ /** - * $Id: + * $Id$ * * ***** BEGIN GPL LICENSE BLOCK ***** * diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h index b1f5292f9d4..9ea7725b855 100644 --- a/source/blender/makesrna/RNA_access.h +++ b/source/blender/makesrna/RNA_access.h @@ -333,6 +333,7 @@ extern StructRNA RNA_Pose; extern StructRNA RNA_PoseChannel; extern StructRNA RNA_Property; extern StructRNA RNA_PropertySensor; +extern StructRNA RNA_ArmatureSensor; extern StructRNA RNA_PythonConstraint; extern StructRNA RNA_PythonController; extern StructRNA RNA_RadarSensor; diff --git a/source/blender/makesrna/RNA_define.h b/source/blender/makesrna/RNA_define.h index 595562503aa..37b175fbf12 100644 --- a/source/blender/makesrna/RNA_define.h +++ b/source/blender/makesrna/RNA_define.h @@ -102,6 +102,8 @@ PropertyRNA *RNA_def_float_dynamic_array(StructOrFunctionRNA *cont, const char * */ PropertyRNA *RNA_def_float_percentage(StructOrFunctionRNA *cont, const char *identifier, float default_value, float hardmin, float hardmax, const char *ui_name, const char *ui_description, float softmin, float softmax); +PropertyRNA *RNA_def_float_factor(StructOrFunctionRNA *cont, const char *identifier, float default_value, float hardmin, float hardmax, + const char *ui_name, const char *ui_description, float softmin, float softmax); PropertyRNA *RNA_def_pointer(StructOrFunctionRNA *cont, const char *identifier, const char *type, const char *ui_name, const char *ui_description); diff --git a/source/blender/makesrna/RNA_types.h b/source/blender/makesrna/RNA_types.h index 353c859cf27..5fff2af29ff 100644 --- a/source/blender/makesrna/RNA_types.h +++ b/source/blender/makesrna/RNA_types.h @@ -94,9 +94,10 @@ typedef enum PropertySubType { /* numbers */ PROP_UNSIGNED = 13, PROP_PERCENTAGE = 14, - PROP_ANGLE = 15|PROP_UNIT_ROTATION, - PROP_TIME = 16|PROP_UNIT_TIME, - PROP_DISTANCE = 17|PROP_UNIT_LENGTH, + PROP_FACTOR = 15, + PROP_ANGLE = 16|PROP_UNIT_ROTATION, + PROP_TIME = 17|PROP_UNIT_TIME, + PROP_DISTANCE = 18|PROP_UNIT_LENGTH, /* number arrays */ PROP_COLOR = 20, diff --git a/source/blender/makesrna/SConscript b/source/blender/makesrna/SConscript index 845abf636e2..8fc9df0fbf6 100644 --- a/source/blender/makesrna/SConscript +++ b/source/blender/makesrna/SConscript @@ -7,7 +7,7 @@ o = SConscript('intern/SConscript') objs += o incs = '#/intern/guardedalloc ../blenkernel ../blenlib ../makesdna intern .' -incs += ' ../windowmanager ../editors/include ../imbuf' +incs += ' ../windowmanager ../editors/include ../imbuf ../ikplugin' incs += ' ../render/extern/include' defs = [] diff --git a/source/blender/makesrna/intern/CMakeLists.txt b/source/blender/makesrna/intern/CMakeLists.txt index 709c5d017ec..50cf0b00b84 100644 --- a/source/blender/makesrna/intern/CMakeLists.txt +++ b/source/blender/makesrna/intern/CMakeLists.txt @@ -39,7 +39,7 @@ SET(SRC ../../../../intern/guardedalloc/intern/mallocn.c ../../../../intern/guardedalloc/intern/mmap_win.c) -INCLUDE_DIRECTORIES(../../../../intern/guardedalloc .. ../../makesdna ../../blenkernel ../../blenlib ../../windowmanager ../../editors/include ../../imbuf ../../render/extern/include .) +INCLUDE_DIRECTORIES(../../../../intern/guardedalloc .. ../../makesdna ../../blenkernel ../../blenlib ../../ikplugin ../../windowmanager ../../editors/include ../../imbuf ../../render/extern/include .) FILE(GLOB INC_FILES ../*.h ../../makesdna/*.h) IF(WITH_GAMEENGINE) diff --git a/source/blender/makesrna/intern/Makefile b/source/blender/makesrna/intern/Makefile index 4a4e41edd15..7923ea1e7de 100644 --- a/source/blender/makesrna/intern/Makefile +++ b/source/blender/makesrna/intern/Makefile @@ -49,6 +49,7 @@ CPPFLAGS += -I$(NAN_GUARDEDALLOC)/include CPPFLAGS += -I../../blenlib CPPFLAGS += -I../../blenkernel CPPFLAGS += -I../../imbuf +CPPFLAGS += -I../../ikplugin CPPFLAGS += -I../../makesdna CPPFLAGS += -I../../windowmanager CPPFLAGS += -I../../editors/include diff --git a/source/blender/makesrna/intern/SConscript b/source/blender/makesrna/intern/SConscript index 569f0547731..0f8bc752f09 100644 --- a/source/blender/makesrna/intern/SConscript +++ b/source/blender/makesrna/intern/SConscript @@ -30,7 +30,7 @@ makesrna_tool.Append(CCFLAGS = '-DBASE_HEADER="\\"source/blender/makesrna/\\"" ' defs = [] incs = '#/intern/guardedalloc ../../blenlib ../../blenkernel' -incs += ' ../../imbuf ../../makesdna ../../makesrna' +incs += ' ../../imbuf ../../makesdna ../../makesrna ../../ikplugin' incs += ' ../../windowmanager ../../editors/include' incs += ' ../../render/extern/include' diff --git a/source/blender/makesrna/intern/makesrna.c b/source/blender/makesrna/intern/makesrna.c index c734cdfec87..961fb9a3d0b 100644 --- a/source/blender/makesrna/intern/makesrna.c +++ b/source/blender/makesrna/intern/makesrna.c @@ -1406,6 +1406,7 @@ static const char *rna_property_subtypename(PropertyType type) case PROP_DIRPATH: return "PROP_DIRPATH"; case PROP_UNSIGNED: return "PROP_UNSIGNED"; case PROP_PERCENTAGE: return "PROP_PERCENTAGE"; + case PROP_FACTOR: return "PROP_FACTOR"; case PROP_ANGLE: return "PROP_ANGLE"; case PROP_TIME: return "PROP_TIME"; case PROP_DISTANCE: return "PROP_DISTANCE"; @@ -1968,7 +1969,7 @@ RNAProcessItem PROCESS_ITEMS[]= { {"rna_rna.c", NULL, RNA_def_rna}, {"rna_ID.c", NULL, RNA_def_ID}, {"rna_texture.c", NULL, RNA_def_texture}, - {"rna_action.c", NULL, RNA_def_action}, + {"rna_action.c", "rna_action_api.c", RNA_def_action}, {"rna_animation.c", "rna_animation_api.c", RNA_def_animation}, {"rna_actuator.c", NULL, RNA_def_actuator}, {"rna_armature.c", NULL, RNA_def_armature}, @@ -1985,12 +1986,12 @@ RNAProcessItem PROCESS_ITEMS[]= { {"rna_fluidsim.c", NULL, RNA_def_fluidsim}, {"rna_gpencil.c", NULL, RNA_def_gpencil}, {"rna_group.c", NULL, RNA_def_group}, - {"rna_image.c", NULL, RNA_def_image}, + {"rna_image.c", "rna_image_api.c", RNA_def_image}, {"rna_key.c", NULL, RNA_def_key}, {"rna_lamp.c", NULL, RNA_def_lamp}, {"rna_lattice.c", NULL, RNA_def_lattice}, {"rna_main.c", "rna_main_api.c", RNA_def_main}, - {"rna_material.c", NULL, RNA_def_material}, + {"rna_material.c", "rna_material_api.c", RNA_def_material}, {"rna_mesh.c", "rna_mesh_api.c", RNA_def_mesh}, {"rna_meta.c", NULL, RNA_def_meta}, {"rna_modifier.c", NULL, RNA_def_modifier}, @@ -2000,7 +2001,7 @@ RNAProcessItem PROCESS_ITEMS[]= { {"rna_object_force.c", NULL, RNA_def_object_force}, {"rna_packedfile.c", NULL, RNA_def_packedfile}, {"rna_particle.c", NULL, RNA_def_particle}, - {"rna_pose.c", NULL, RNA_def_pose}, + {"rna_pose.c", "rna_pose_api.c", RNA_def_pose}, {"rna_property.c", NULL, RNA_def_gameproperty}, {"rna_render.c", NULL, RNA_def_render}, {"rna_scene.c", "rna_scene_api.c", RNA_def_scene}, diff --git a/source/blender/makesrna/intern/rna_action.c b/source/blender/makesrna/intern/rna_action.c index 99090b62938..eaa11b4ad38 100644 --- a/source/blender/makesrna/intern/rna_action.c +++ b/source/blender/makesrna/intern/rna_action.c @@ -100,6 +100,8 @@ static void rna_def_action(BlenderRNA *brna) RNA_def_property_collection_sdna(prop, NULL, "markers", NULL); RNA_def_property_struct_type(prop, "TimelineMarker"); RNA_def_property_ui_text(prop, "Pose Markers", "Markers specific to this Action, for labeling poses."); + + RNA_api_action(srna); } /* --------- */ diff --git a/source/blender/makesrna/intern/rna_action_api.c b/source/blender/makesrna/intern/rna_action_api.c new file mode 100644 index 00000000000..991a8251cc5 --- /dev/null +++ b/source/blender/makesrna/intern/rna_action_api.c @@ -0,0 +1,80 @@ +/** + * ***** 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) 2009 Blender Foundation. + * All rights reserved. + * + * + * Contributor(s): Arystanbek Dyussenov + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <time.h> + +#include "RNA_define.h" +#include "RNA_types.h" + +#include "DNA_action_types.h" + +#ifdef RNA_RUNTIME + +#include "BKE_action.h" + +#include "DNA_anim_types.h" +#include "DNA_curve_types.h" + +/* XXX disabled until RNA allows returning arrays */ +#if 0 +/* return frame range of all curves (min, max) or (0, 1) if there are no keys */ +int *rna_Action_get_frame_range(bAction *act, int *ret_length) +{ + int *ret; + float start, end; + + calc_action_range(act, &start, &end, 1); + + *ret_length= 2; + ret= MEM_callocN(*ret_length * sizeof(int), "rna_Action_get_frame_range"); + + ret[0]= (int)start; + ret[1]= (int)end; + + return ret; +} +#endif + +#else + +void RNA_api_action(StructRNA *srna) +{ +#if 0 + FunctionRNA *func; + PropertyRNA *parm; + + func= RNA_def_function(srna, "get_frame_range", "rna_Action_get_frame_range"); + RNA_def_function_ui_description(func, "Get action frame range as a (min, max) tuple."); + parm= RNA_def_int_array(func, "frame_range", 1, NULL, 0, 0, "", "Action frame range.", 0, 0); + RNA_def_property_flag(parm, PROP_DYNAMIC_ARRAY); + RNA_def_function_return(func, parm); +#endif +} + +#endif diff --git a/source/blender/makesrna/intern/rna_actuator.c b/source/blender/makesrna/intern/rna_actuator.c index 473e726db60..ce83d1c469b 100644 --- a/source/blender/makesrna/intern/rna_actuator.c +++ b/source/blender/makesrna/intern/rna_actuator.c @@ -58,6 +58,7 @@ void RNA_def_actuator(BlenderRNA *brna) {ACT_PARENT, "PARENT", 0, "Parent", ""}, {ACT_SHAPEACTION, "SHAPE_ACTION", 0, "Shape Action", ""}, {ACT_STATE, "STATE", 0, "State", ""}, + {ACT_ARMATURE, "ARMATURE", 0, "Armature", ""}, {0, NULL, 0, NULL, NULL}}; srna= RNA_def_struct(brna, "Actuator", NULL); diff --git a/source/blender/makesrna/intern/rna_animation.c b/source/blender/makesrna/intern/rna_animation.c index a8d3a6edaae..4b2c11c2e0d 100644 --- a/source/blender/makesrna/intern/rna_animation.c +++ b/source/blender/makesrna/intern/rna_animation.c @@ -57,6 +57,12 @@ static int rna_AnimData_action_editable(PointerRNA *ptr) return 1; } +static void rna_AnimData_action_set(PointerRNA *ptr, PointerRNA value) +{ + AnimData *adt= (AnimData*)(ptr->data); + adt->action= value.data; +} + static void rna_ksPath_RnaPath_get(PointerRNA *ptr, char *value) { KS_Path *ksp= (KS_Path *)ptr->data; @@ -202,8 +208,11 @@ void rna_def_animdata(BlenderRNA *brna) /* Active Action */ prop= RNA_def_property(srna, "action", PROP_POINTER, PROP_NONE); - RNA_def_property_ui_text(prop, "Action", "Active Action for this datablock."); + RNA_def_property_pointer_funcs(prop, NULL, "rna_AnimData_action_set", NULL); + RNA_def_property_flag(prop, PROP_EDITABLE); /* this flag as well as the dynamic test must be defined for this to be editable... */ RNA_def_property_editable_func(prop, "rna_AnimData_action_editable"); + RNA_def_property_ui_text(prop, "Action", "Active Action for this datablock."); + /* Active Action Settings */ prop= RNA_def_property(srna, "action_extrapolation", PROP_ENUM, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_armature.c b/source/blender/makesrna/intern/rna_armature.c index dcf89b7ac1e..5dbfdd3e6f1 100644 --- a/source/blender/makesrna/intern/rna_armature.c +++ b/source/blender/makesrna/intern/rna_armature.c @@ -52,6 +52,7 @@ static void rna_Armature_update_data(bContext *C, PointerRNA *ptr) DAG_id_flush_update(id, OB_RECALC_DATA); WM_event_add_notifier(C, NC_GEOM|ND_DATA, id); + //WM_event_add_notifier(C, NC_OBJECT|ND_POSE, NULL); } static void rna_Armature_redraw_data(bContext *C, PointerRNA *ptr) @@ -61,6 +62,11 @@ static void rna_Armature_redraw_data(bContext *C, PointerRNA *ptr) WM_event_add_notifier(C, NC_GEOM|ND_DATA, id); } +static char *rna_Bone_path(PointerRNA *ptr) +{ + return BLI_sprintfN("bones[\"%s\"]", ((Bone*)ptr->data)->name); +} + static void rna_bone_layer_set(short *layer, const int *values) { int i, tot= 0; @@ -430,6 +436,7 @@ static void rna_def_bone(BlenderRNA *brna) srna= RNA_def_struct(brna, "Bone", NULL); RNA_def_struct_ui_text(srna, "Bone", "Bone in an Armature datablock."); RNA_def_struct_ui_icon(srna, ICON_BONE_DATA); + RNA_def_struct_path_func(srna, "rna_Bone_path"); /* pointers/collections */ /* parent (pointer) */ @@ -457,6 +464,37 @@ static void rna_def_bone(BlenderRNA *brna) RNA_def_property_boolean_sdna(prop, NULL, "flag", BONE_SELECTED); RNA_def_property_ui_text(prop, "Selected", ""); RNA_def_property_update(prop, 0, "rna_Armature_redraw_data"); + + /* XXX better matrix descriptions possible (Arystan) */ + prop= RNA_def_property(srna, "matrix", PROP_FLOAT, PROP_MATRIX); + RNA_def_property_float_sdna(prop, NULL, "bone_mat"); + RNA_def_property_array(prop, 9); + RNA_def_property_ui_text(prop, "Bone Matrix", "3x3 bone matrix."); + + prop= RNA_def_property(srna, "armature_matrix", PROP_FLOAT, PROP_MATRIX); + RNA_def_property_float_sdna(prop, NULL, "arm_mat"); + RNA_def_property_array(prop, 16); + RNA_def_property_ui_text(prop, "Bone Armature-Relative Matrix", "4x4 bone matrix relative to armature."); + + prop= RNA_def_property(srna, "tail", PROP_FLOAT, PROP_TRANSLATION); + RNA_def_property_float_sdna(prop, NULL, "tail"); + RNA_def_property_array(prop, 3); + RNA_def_property_ui_text(prop, "Tail", "Location of tail end of the bone."); + + prop= RNA_def_property(srna, "armature_tail", PROP_FLOAT, PROP_TRANSLATION); + RNA_def_property_float_sdna(prop, NULL, "arm_tail"); + RNA_def_property_array(prop, 3); + RNA_def_property_ui_text(prop, "Armature-Relative Tail", "Location of tail end of the bone relative to armature."); + + prop= RNA_def_property(srna, "head", PROP_FLOAT, PROP_TRANSLATION); + RNA_def_property_float_sdna(prop, NULL, "head"); + RNA_def_property_array(prop, 3); + RNA_def_property_ui_text(prop, "Head", "Location of head end of the bone."); + + prop= RNA_def_property(srna, "armature_head", PROP_FLOAT, PROP_TRANSLATION); + RNA_def_property_float_sdna(prop, NULL, "arm_head"); + RNA_def_property_array(prop, 3); + RNA_def_property_ui_text(prop, "Armature-Relative Head", "Location of head end of the bone relative to armature."); } static void rna_def_edit_bone(BlenderRNA *brna) @@ -526,23 +564,37 @@ static void rna_def_armature(BlenderRNA *brna) PropertyRNA *prop; static EnumPropertyItem prop_drawtype_items[] = { - {ARM_OCTA, "OCTAHEDRAL", 0, "Octahedral", "Draw bones as octahedral shape (default)."}, - {ARM_LINE, "STICK", 0, "Stick", "Draw bones as simple 2D lines with dots."}, - {ARM_B_BONE, "BBONE", 0, "B-Bone", "Draw bones as boxes, showing subdivision and B-Splines"}, - {ARM_ENVELOPE, "ENVELOPE", 0, "Envelope", "Draw bones as extruded spheres, showing defomation influence volume."}, + {ARM_OCTA, "OCTAHEDRAL", 0, "Octahedral", "Display bones as octahedral shape (default)."}, + {ARM_LINE, "STICK", 0, "Stick", "Display bones as simple 2D lines with dots."}, + {ARM_B_BONE, "BBONE", 0, "B-Bone", "Display bones as boxes, showing subdivision and B-Splines"}, + {ARM_ENVELOPE, "ENVELOPE", 0, "Envelope", "Display bones as extruded spheres, showing defomation influence volume."}, {0, NULL, 0, NULL, NULL}}; static EnumPropertyItem prop_ghost_type_items[] = { - {ARM_GHOST_CUR, "CURRENT_FRAME", 0, "Around Current Frame", "Draw Ghosts of poses within a fixed number of frames around the current frame."}, - {ARM_GHOST_RANGE, "RANGE", 0, "In Range", "Draw Ghosts of poses within specified range."}, - {ARM_GHOST_KEYS, "KEYS", 0, "On Keyframes", "Draw Ghosts of poses on Keyframes."}, + {ARM_GHOST_CUR, "CURRENT_FRAME", 0, "Around Frame", "Display Ghosts of poses within a fixed number of frames around the current frame."}, + {ARM_GHOST_RANGE, "RANGE", 0, "In Range", "Display Ghosts of poses within specified range."}, + {ARM_GHOST_KEYS, "KEYS", 0, "On Keyframes", "Display Ghosts of poses on Keyframes."}, + {0, NULL, 0, NULL, NULL}}; + static const EnumPropertyItem prop_paths_type_items[]= { + {ARM_PATH_ACFRA, "CURRENT_FRAME", 0, "Around Frame", "Display Paths of poses within a fixed number of frames around the current frame."}, + {0, "RANGE", 0, "In Range", "Display Paths of poses within specified range."}, + {0, NULL, 0, NULL, NULL}}; + static const EnumPropertyItem prop_paths_location_items[]= { + {ARM_PATH_HEADS, "HEADS", 0, "Heads", "Calculate bone paths from heads"}, + {0, "TAILS", 0, "Tails", "Calculate bone paths from tails"}, + {0, NULL, 0, NULL, NULL}}; + static const EnumPropertyItem prop_pose_position_items[]= { + {0, "POSE_POSITION", 0, "Pose Position", "Show armature in posed state."}, + {ARM_RESTPOS, "REST_POSITION", 0, "Rest Position", "Show Armature in binding pose state. No posing possible."}, {0, NULL, 0, NULL, NULL}}; srna= RNA_def_struct(brna, "Armature", "ID"); RNA_def_struct_ui_text(srna, "Armature", "Armature datablock containing a hierarchy of bones, usually used for rigging characters."); RNA_def_struct_ui_icon(srna, ICON_ARMATURE_DATA); - RNA_def_struct_sdna(srna, "bArmature"); + /* Animation Data */ + rna_def_animdata_common(srna); + /* Collections */ prop= RNA_def_property(srna, "bones", PROP_COLLECTION, PROP_NONE); RNA_def_property_collection_sdna(prop, NULL, "bonebase", NULL); @@ -556,6 +608,17 @@ static void rna_def_armature(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Edit Bones", ""); /* Enum values */ +// prop= RNA_def_property(srna, "rest_position", PROP_BOOLEAN, PROP_NONE); +// RNA_def_property_boolean_sdna(prop, NULL, "flag", ARM_RESTPOS); +// RNA_def_property_ui_text(prop, "Rest Position", "Show Armature in Rest Position. No posing possible."); +// RNA_def_property_update(prop, 0, "rna_Armature_update_data"); + + prop= RNA_def_property(srna, "pose_position", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_bitflag_sdna(prop, NULL, "flag"); + RNA_def_property_enum_items(prop, prop_pose_position_items); + RNA_def_property_ui_text(prop, "Pose Position", "Show armature in binding pose or final posed state."); + RNA_def_property_update(prop, 0, "rna_Armature_update_data"); + prop= RNA_def_property(srna, "drawtype", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, prop_drawtype_items); RNA_def_property_ui_text(prop, "Draw Type", ""); @@ -564,7 +627,19 @@ static void rna_def_armature(BlenderRNA *brna) prop= RNA_def_property(srna, "ghost_type", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "ghosttype"); RNA_def_property_enum_items(prop, prop_ghost_type_items); - RNA_def_property_ui_text(prop, "Ghost Drawing", "Method of Onion-skinning for active Action"); + RNA_def_property_ui_text(prop, "Ghost Type", "Method of Onion-skinning for active Action"); + RNA_def_property_update(prop, 0, "rna_Armature_redraw_data"); + + prop= RNA_def_property(srna, "paths_type", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_bitflag_sdna(prop, NULL, "pathflag"); + RNA_def_property_enum_items(prop, prop_paths_type_items); + RNA_def_property_ui_text(prop, "Paths Type", "Type of range to show for Bone Paths"); + RNA_def_property_update(prop, 0, "rna_Armature_redraw_data"); + + prop= RNA_def_property(srna, "paths_location", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_bitflag_sdna(prop, NULL, "pathflag"); + RNA_def_property_enum_items(prop, prop_paths_location_items); + RNA_def_property_ui_text(prop, "Paths Location", "When calculating Bone Paths, use Head or Tips"); RNA_def_property_update(prop, 0, "rna_Armature_redraw_data"); /* Boolean values */ @@ -574,7 +649,7 @@ static void rna_def_armature(BlenderRNA *brna) RNA_def_property_array(prop, 16); RNA_def_property_ui_text(prop, "Visible Layers", "Armature layer visibility."); RNA_def_property_boolean_funcs(prop, NULL, "rna_Armature_layer_set"); - RNA_def_property_update(prop, NC_OBJECT|ND_POSE, NULL); + RNA_def_property_update(prop, NC_OBJECT|ND_POSE, "rna_Armature_redraw_data"); RNA_def_property_flag(prop, PROP_LIB_EXCEPTION); /* layer protection */ @@ -585,10 +660,7 @@ static void rna_def_armature(BlenderRNA *brna) RNA_def_property_update(prop, 0, "rna_Armature_redraw_data"); /* flag */ - prop= RNA_def_property(srna, "rest_position", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "flag", ARM_RESTPOS); - RNA_def_property_ui_text(prop, "Rest Position", "Show Armature in Rest Position. No posing possible."); - RNA_def_property_update(prop, 0, "rna_Armature_update_data"); + prop= RNA_def_property(srna, "draw_axes", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", ARM_DRAWAXES); @@ -626,8 +698,8 @@ static void rna_def_armature(BlenderRNA *brna) RNA_def_property_update(prop, 0, "rna_Armature_redraw_data"); prop= RNA_def_property(srna, "ghost_only_selected", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", ARM_GHOST_ONLYSEL); - RNA_def_property_ui_text(prop, "Draw Ghosts on Selected Keyframes Only", ""); + RNA_def_property_boolean_sdna(prop, NULL, "flag", ARM_GHOST_ONLYSEL); + RNA_def_property_ui_text(prop, "Draw Ghosts on Selected Bones Only", ""); RNA_def_property_update(prop, 0, "rna_Armature_redraw_data"); /* deformflag */ @@ -672,15 +744,6 @@ static void rna_def_armature(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Paths Show Keyframe Numbers", "When drawing Armature in Pose Mode, show frame numbers of Keyframes on Bone Paths"); RNA_def_property_update(prop, 0, "rna_Armature_redraw_data"); - prop= RNA_def_property(srna, "paths_show_around_current_frame", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "pathflag", ARM_PATH_ACFRA); - RNA_def_property_ui_text(prop, "Paths Around Current Frame", "When drawing Armature in Pose Mode, only show section of Bone Paths that falls around current frame"); - RNA_def_property_update(prop, 0, "rna_Armature_redraw_data"); - - prop= RNA_def_property(srna, "paths_calculate_head_positions", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "pathflag", ARM_PATH_HEADS); - RNA_def_property_ui_text(prop, "Paths Use Heads", "When calculating Bone Paths, use Head locations instead of Tips"); - RNA_def_property_update(prop, 0, "rna_Armature_redraw_data"); /* Number fields */ /* ghost/onionskining settings */ diff --git a/source/blender/makesrna/intern/rna_camera.c b/source/blender/makesrna/intern/rna_camera.c index 9c33b0afb00..eaf647e02a2 100644 --- a/source/blender/makesrna/intern/rna_camera.c +++ b/source/blender/makesrna/intern/rna_camera.c @@ -62,7 +62,7 @@ void RNA_def_camera(BlenderRNA *brna) /* Number values */ - prop= RNA_def_property(srna, "passepartout_alpha", PROP_FLOAT, PROP_PERCENTAGE); + prop= RNA_def_property(srna, "passepartout_alpha", PROP_FLOAT, PROP_FACTOR); RNA_def_property_float_sdna(prop, NULL, "passepartalpha"); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_ui_text(prop, "Passepartout Alpha", "Opacity (alpha) of the darkened overlay in Camera view."); diff --git a/source/blender/makesrna/intern/rna_constraint.c b/source/blender/makesrna/intern/rna_constraint.c index 04d56eb666e..b630e61a680 100644 --- a/source/blender/makesrna/intern/rna_constraint.c +++ b/source/blender/makesrna/intern/rna_constraint.c @@ -33,6 +33,7 @@ #include "DNA_object_types.h" #include "DNA_scene_types.h" +#include "ED_object.h" #include "WM_types.h" EnumPropertyItem constraint_type_items[] ={ @@ -80,6 +81,19 @@ EnumPropertyItem space_object_items[] = { {1, "LOCAL", 0, "Local (Without Parent) Space", ""}, {0, NULL, 0, NULL, NULL}}; +EnumPropertyItem constraint_ik_type_items[] ={ + {CONSTRAINT_IK_COPYPOSE, "COPY_POSE", 0, "Copy Pose", ""}, + {CONSTRAINT_IK_DISTANCE, "DISTANCE", 0, "Distance", ""}, + {0, NULL, 0, NULL, NULL}, +}; + +static EnumPropertyItem constraint_distance_items[] = { + {LIMITDIST_INSIDE, "LIMITDIST_INSIDE", 0, "Inside", ""}, + {LIMITDIST_OUTSIDE, "LIMITDIST_OUTSIDE", 0, "Outside", ""}, + {LIMITDIST_ONSURFACE, "LIMITDIST_ONSURFACE", 0, "On Surface", ""}, + {0, NULL, 0, NULL, NULL} +}; + #ifdef RNA_RUNTIME #include "BKE_action.h" @@ -160,24 +174,12 @@ static char *rna_Constraint_path(PointerRNA *ptr) static void rna_Constraint_update(bContext *C, PointerRNA *ptr) { - Object *ob= ptr->id.data; - - if(ob->pose) update_pose_constraint_flags(ob->pose); - - object_test_constraints(ob); - - if(ob->type==OB_ARMATURE) DAG_id_flush_update(&ob->id, OB_RECALC_DATA|OB_RECALC_OB); - else DAG_id_flush_update(&ob->id, OB_RECALC_OB); + ED_object_constraint_update(ptr->id.data); } static void rna_Constraint_dependency_update(bContext *C, PointerRNA *ptr) { - Object *ob= ptr->id.data; - - rna_Constraint_update(C, ptr); - - if(ob->pose) ob->pose->flag |= POSE_RECALC; // checks & sorts pose channels - DAG_scene_sort(CTX_data_scene(C)); + ED_object_constraint_dependency_update(CTX_data_scene(C), ptr->id.data); } static void rna_Constraint_influence_update(bContext *C, PointerRNA *ptr) @@ -190,6 +192,24 @@ static void rna_Constraint_influence_update(bContext *C, PointerRNA *ptr) rna_Constraint_update(C, ptr); } +static void rna_Constraint_ik_type_set(struct PointerRNA *ptr, int value) +{ + bConstraint *con = ptr->data; + bKinematicConstraint *ikdata = con->data; + + if (ikdata->type != value) { + // the type of IK constraint has changed, set suitable default values + // in case constraints reuse same fields incompatible + switch (value) { + case CONSTRAINT_IK_COPYPOSE: + break; + case CONSTRAINT_IK_DISTANCE: + break; + } + ikdata->type = value; + } +} + static EnumPropertyItem *rna_Constraint_owner_space_itemf(bContext *C, PointerRNA *ptr, int *free) { Object *ob= (Object*)ptr->id.data; @@ -253,6 +273,22 @@ static EnumPropertyItem *rna_Constraint_target_space_itemf(bContext *C, PointerR return space_object_items; } +static void rna_ActionConstraint_minmax_range(PointerRNA *ptr, float *min, float *max) +{ + bConstraint *con= (bConstraint*)ptr->data; + bActionConstraint *acon = (bActionConstraint *)con->data; + + /* 0, 1, 2 = magic numbers for rotX, rotY, rotZ */ + if (ELEM3(acon->type, 0, 1, 2)) { + *min= -90.f; + *max= 90.f; + } else { + *min= -1000.f; + *max= 1000.f; + } +} + + #else static void rna_def_constrainttarget(BlenderRNA *brna) @@ -440,21 +476,40 @@ static void rna_def_constraint_kinematic(BlenderRNA *brna) prop= RNA_def_property(srna, "tail", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", CONSTRAINT_IK_TIP); RNA_def_property_ui_text(prop, "Use Tail", "Include bone's tail as last element in chain."); - RNA_def_property_update(prop, NC_OBJECT|ND_CONSTRAINT, "rna_Constraint_update"); + RNA_def_property_update(prop, NC_OBJECT|ND_CONSTRAINT, "rna_Constraint_dependency_update"); prop= RNA_def_property(srna, "rotation", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", CONSTRAINT_IK_ROT); RNA_def_property_ui_text(prop, "Rotation", "Chain follows rotation of target."); - RNA_def_property_update(prop, NC_OBJECT|ND_CONSTRAINT, "rna_Constraint_update"); + RNA_def_property_update(prop, NC_OBJECT|ND_CONSTRAINT, "rna_Constraint_dependency_update"); prop= RNA_def_property(srna, "targetless", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", CONSTRAINT_IK_AUTO); RNA_def_property_ui_text(prop, "Targetless", "Use targetless IK."); - RNA_def_property_update(prop, NC_OBJECT|ND_CONSTRAINT, "rna_Constraint_update"); + RNA_def_property_update(prop, NC_OBJECT|ND_CONSTRAINT, "rna_Constraint_dependency_update"); prop= RNA_def_property(srna, "stretch", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", CONSTRAINT_IK_STRETCH); RNA_def_property_ui_text(prop, "Stretch", "Enable IK Stretching."); + RNA_def_property_update(prop, NC_OBJECT|ND_CONSTRAINT, "rna_Constraint_dependency_update"); + + prop= RNA_def_property(srna, "ik_type", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "type"); + RNA_def_property_enum_funcs(prop, NULL, "rna_Constraint_ik_type_set", NULL); + RNA_def_property_enum_items(prop, constraint_ik_type_items); + RNA_def_property_ui_text(prop, "IK Type", ""); + RNA_def_property_update(prop, NC_OBJECT|ND_CONSTRAINT, "rna_Constraint_dependency_update"); + + prop= RNA_def_property(srna, "limit_mode", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "mode"); + RNA_def_property_enum_items(prop, constraint_distance_items); + RNA_def_property_ui_text(prop, "Limit Mode", "Distances in relation to sphere of influence to allow."); + RNA_def_property_update(prop, NC_OBJECT|ND_CONSTRAINT, "rna_Constraint_dependency_update"); + + prop= RNA_def_property(srna, "distance", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "dist"); + RNA_def_property_range(prop, 0.0, 100.f); + RNA_def_property_ui_text(prop, "Distance", "Radius of limiting sphere."); RNA_def_property_update(prop, NC_OBJECT|ND_CONSTRAINT, "rna_Constraint_update"); } @@ -575,7 +630,7 @@ static void rna_def_constraint_locate_like(BlenderRNA *brna) srna= RNA_def_struct(brna, "CopyLocationConstraint", "Constraint"); RNA_def_struct_ui_text(srna, "Copy Location Constraint", "Copies the location of the target."); - prop= RNA_def_property(srna, "head_tail", PROP_FLOAT, PROP_PERCENTAGE); + prop= RNA_def_property(srna, "head_tail", PROP_FLOAT, PROP_FACTOR); RNA_def_property_float_sdna(prop, "bConstraint", "headtail"); RNA_def_property_ui_text(prop, "Head/Tail", "Target along length of bone: Head=0, Tail=1."); RNA_def_property_update(prop, NC_OBJECT|ND_CONSTRAINT, "rna_Constraint_update"); @@ -781,15 +836,17 @@ static void rna_def_constraint_action(BlenderRNA *brna) prop= RNA_def_property(srna, "maximum", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "max"); - RNA_def_property_range(prop, 0.0, 1000.f); + RNA_def_property_range(prop, -1000.f, 1000.f); RNA_def_property_ui_text(prop, "Maximum", "Maximum value for target channel range."); RNA_def_property_update(prop, NC_OBJECT|ND_CONSTRAINT, "rna_Constraint_update"); + RNA_def_property_float_funcs(prop, NULL, NULL, "rna_ActionConstraint_minmax_range"); prop= RNA_def_property(srna, "minimum", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "min"); - RNA_def_property_range(prop, 0.0, 1000.f); + RNA_def_property_range(prop, -1000.f, 1000.f); RNA_def_property_ui_text(prop, "Minimum", "Minimum value for target channel range."); RNA_def_property_update(prop, NC_OBJECT|ND_CONSTRAINT, "rna_Constraint_update"); + RNA_def_property_float_funcs(prop, NULL, NULL, "rna_ActionConstraint_minmax_range"); } static void rna_def_constraint_locked_track(BlenderRNA *brna) @@ -875,10 +932,10 @@ static void rna_def_constraint_follow_path(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Offset", "Offset from the position corresponding to the time frame."); RNA_def_property_update(prop, NC_OBJECT|ND_CONSTRAINT, "rna_Constraint_update"); - prop= RNA_def_property(srna, "offset_percentage", PROP_FLOAT, PROP_PERCENTAGE); + prop= RNA_def_property(srna, "offset_factor", PROP_FLOAT, PROP_FACTOR); RNA_def_property_float_sdna(prop, NULL, "offset"); // XXX we might be better with another var or some hackery? RNA_def_property_range(prop, 0.0f, 1.0f); - RNA_def_property_ui_text(prop, "Offset Percentage", "Percentage value defining target position along length of bone."); + RNA_def_property_ui_text(prop, "Offset Factor", "Percentage value defining target position along length of bone."); RNA_def_property_update(prop, NC_OBJECT|ND_CONSTRAINT, "rna_Constraint_update"); prop= RNA_def_property(srna, "forward", PROP_ENUM, PROP_NONE); @@ -1457,12 +1514,6 @@ static void rna_def_constraint_distance_limit(BlenderRNA *brna) StructRNA *srna; PropertyRNA *prop; - static EnumPropertyItem distance_items[] = { - {LIMITDIST_INSIDE, "LIMITDIST_INSIDE", 0, "Inside", ""}, - {LIMITDIST_OUTSIDE, "LIMITDIST_OUTSIDE", 0, "Outside", ""}, - {LIMITDIST_ONSURFACE, "LIMITDIST_ONSURFACE", 0, "On Surface", ""}, - {0, NULL, 0, NULL, NULL}}; - srna= RNA_def_struct(brna, "LimitDistanceConstraint", "Constraint"); RNA_def_struct_ui_text(srna, "Limit Distance Constraint", "Limits the distance from target object."); RNA_def_struct_sdna_from(srna, "bDistLimitConstraint", "data"); @@ -1486,7 +1537,7 @@ static void rna_def_constraint_distance_limit(BlenderRNA *brna) prop= RNA_def_property(srna, "limit_mode", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "mode"); - RNA_def_property_enum_items(prop, distance_items); + RNA_def_property_enum_items(prop, constraint_distance_items); RNA_def_property_ui_text(prop, "Limit Mode", "Distances in relation to sphere of influence to allow."); RNA_def_property_update(prop, NC_OBJECT|ND_CONSTRAINT, "rna_Constraint_update"); } @@ -1599,12 +1650,23 @@ void RNA_def_constraint(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Proxy Local", "Constraint was added in this proxy instance (i.e. did not belong to source Armature)."); /* values */ - prop= RNA_def_property(srna, "influence", PROP_FLOAT, PROP_PERCENTAGE); + prop= RNA_def_property(srna, "influence", PROP_FLOAT, PROP_FACTOR); RNA_def_property_float_sdna(prop, NULL, "enforce"); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_ui_text(prop, "Influence", "Amount of influence constraint will have on the final solution."); RNA_def_property_update(prop, NC_OBJECT|ND_CONSTRAINT, "rna_Constraint_influence_update"); - + + /* readonly values */ + prop= RNA_def_property(srna, "lin_error", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "lin_error"); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_ui_text(prop, "Lin error", "Amount of residual error in Blender space unit for constraints that work on position."); + + prop= RNA_def_property(srna, "rot_error", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "rot_error"); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_ui_text(prop, "Rot error", "Amount of residual error in radiant for constraints that work on orientation."); + /* pointers */ rna_def_constrainttarget(brna); diff --git a/source/blender/makesrna/intern/rna_curve.c b/source/blender/makesrna/intern/rna_curve.c index 4a5af56d64a..3b6bd2255f2 100644 --- a/source/blender/makesrna/intern/rna_curve.c +++ b/source/blender/makesrna/intern/rna_curve.c @@ -54,6 +54,7 @@ EnumPropertyItem beztriple_interpolation_mode_items[] = { EnumPropertyItem beztriple_keyframe_type_items[] = { {BEZT_KEYTYPE_KEYFRAME, "KEYFRAME", 0, "Keyframe", ""}, {BEZT_KEYTYPE_BREAKDOWN, "BREAKDOWN", 0, "Breakdown", ""}, + {BEZT_KEYTYPE_EXTREME, "EXTREME", 0, "Extreme", ""}, {0, NULL, 0, NULL, NULL}}; #ifdef RNA_RUNTIME diff --git a/source/blender/makesrna/intern/rna_define.c b/source/blender/makesrna/intern/rna_define.c index 45517546c16..cc86da18a0b 100644 --- a/source/blender/makesrna/intern/rna_define.c +++ b/source/blender/makesrna/intern/rna_define.c @@ -890,7 +890,7 @@ PropertyRNA *RNA_def_property(StructOrFunctionRNA *cont_, const char *identifier fprop->softmin= 0.0f; fprop->softmax= 1.0f; } - else if(subtype == PROP_PERCENTAGE) { + else if(subtype == PROP_FACTOR) { fprop->softmin= fprop->hardmin= 0.0f; fprop->softmax= fprop->hardmax= 1.0f; } @@ -1530,7 +1530,7 @@ void RNA_def_property_int_sdna(PropertyRNA *prop, const char *structname, const iprop->softmax= 10000; } - if(prop->subtype == PROP_UNSIGNED || prop->subtype == PROP_PERCENTAGE) + if(prop->subtype == PROP_UNSIGNED || prop->subtype == PROP_PERCENTAGE || prop->subtype == PROP_FACTOR) iprop->hardmin= iprop->softmin= 0; } } @@ -2261,6 +2261,21 @@ PropertyRNA *RNA_def_float_percentage(StructOrFunctionRNA *cont_, const char *id return prop; } +PropertyRNA *RNA_def_float_factor(StructOrFunctionRNA *cont_, const char *identifier, float default_value, + float hardmin, float hardmax, const char *ui_name, const char *ui_description, float softmin, float softmax) +{ + ContainerRNA *cont= cont_; + PropertyRNA *prop; + + prop= RNA_def_property(cont, identifier, PROP_FLOAT, PROP_FACTOR); + RNA_def_property_float_default(prop, default_value); + if(hardmin != hardmax) RNA_def_property_range(prop, hardmin, hardmax); + RNA_def_property_ui_text(prop, ui_name, ui_description); + RNA_def_property_ui_range(prop, softmin, softmax, 1, 3); + + return prop; +} + PropertyRNA *RNA_def_pointer(StructOrFunctionRNA *cont_, const char *identifier, const char *type, const char *ui_name, const char *ui_description) { diff --git a/source/blender/makesrna/intern/rna_image.c b/source/blender/makesrna/intern/rna_image.c index 13ec9aea9bb..4c2689d4f64 100644 --- a/source/blender/makesrna/intern/rna_image.c +++ b/source/blender/makesrna/intern/rna_image.c @@ -144,6 +144,29 @@ static EnumPropertyItem *rna_Image_source_itemf(bContext *C, PointerRNA *ptr, in return item; } +static int rna_Image_has_data_get(PointerRNA *ptr) +{ + Image *im= (Image*)ptr->data; + + if (im->ibufs.first) + return 1; + + return 0; +} + +static int rna_Image_depth_get(PointerRNA *ptr) +{ + Image *im= (Image*)ptr->data; + ImBuf *ibuf= BKE_image_get_ibuf(im, NULL); + + if (!ibuf) return 0; + + if (ibuf->rect_float) + return 128; + + return ibuf->depth; +} + #else static void rna_def_imageuser(BlenderRNA *brna) @@ -219,7 +242,7 @@ static void rna_def_image(BlenderRNA *brna) {0, NULL, 0, NULL, NULL}}; static const EnumPropertyItem prop_field_order_items[]= { {0, "EVEN", 0, "Even", "Even Fields first"}, - {IMA_STD_FIELD, "Odd", 0, "Odd", "Odd Fields first"}, + {IMA_STD_FIELD, "ODD", 0, "Odd", "Odd Fields first"}, {0, NULL, 0, NULL, NULL}}; srna= RNA_def_struct(brna, "Image", "ID"); @@ -356,6 +379,22 @@ static void rna_def_image(BlenderRNA *brna) RNA_def_property_boolean_sdna(prop, NULL, "tpageflag", IMA_CLAMP_V); RNA_def_property_ui_text(prop, "Clamp Y", "Disable texture repeating vertically."); RNA_def_property_update(prop, NC_IMAGE|ND_DISPLAY, NULL); + + /* + Image.has_data and Image.depth are temporary, + Update import_obj.py when they are replaced (Arystan) + */ + prop= RNA_def_property(srna, "has_data", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_funcs(prop, "rna_Image_has_data_get", NULL); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_ui_text(prop, "Has data", "True if this image has data."); + + prop= RNA_def_property(srna, "depth", PROP_INT, PROP_NONE); + RNA_def_property_int_funcs(prop, "rna_Image_depth_get", NULL, NULL); + RNA_def_property_ui_text(prop, "Depth", "Image bit depth."); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + + RNA_api_image(srna); } void RNA_def_image(BlenderRNA *brna) diff --git a/source/blender/makesrna/intern/rna_image_api.c b/source/blender/makesrna/intern/rna_image_api.c new file mode 100644 index 00000000000..2bb7905fc03 --- /dev/null +++ b/source/blender/makesrna/intern/rna_image_api.c @@ -0,0 +1,101 @@ +/** + * $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) 2009 Blender Foundation. + * All rights reserved. + * + * + * Contributor(s): Arystanbek Dyussenov + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <time.h> + +#include "RNA_define.h" +#include "RNA_types.h" + +#ifdef RNA_RUNTIME + +#include "BKE_image.h" +#include "BKE_main.h" +#include "BKE_utildefines.h" + +#include "DNA_image_types.h" +#include "DNA_scene_types.h" + +#include "MEM_guardedalloc.h" + +/* + User should check if returned path exists before copying a file there. + + TODO: it would be better to return a (abs, rel) tuple. +*/ +static char *rna_Image_get_export_path(Image *image, char *dest_dir, int rel) +{ + int length = FILE_MAX; + char *path= MEM_callocN(length, "image file path"); + + if (!BKE_get_image_export_path(image, dest_dir, rel ? NULL : path, length, rel ? path : NULL, length )) { + MEM_freeN(path); + return NULL; + } + + return path; +} + +char *rna_Image_get_abs_filename(Image *image, bContext *C) +{ + char *filename= MEM_callocN(FILE_MAX, "Image.get_abs_filename()"); + + BLI_strncpy(filename, image->name, FILE_MAXDIR + FILE_MAXFILE); + BLI_convertstringcode(filename, CTX_data_main(C)->name); + BLI_convertstringframe(filename, CTX_data_scene(C)->r.cfra); + + return filename; +} + +#else + +void RNA_api_image(StructRNA *srna) +{ + FunctionRNA *func; + PropertyRNA *parm; + + func= RNA_def_function(srna, "get_export_path", "rna_Image_get_export_path"); + RNA_def_function_ui_description(func, "Produce image export path."); + parm= RNA_def_string(func, "dest_dir", "", 0, "", "Destination directory."); + RNA_def_property_flag(parm, PROP_REQUIRED); + parm= RNA_def_boolean(func, "get_rel_path", 1, "", "Return relative path if True."); + RNA_def_property_flag(parm, PROP_REQUIRED); + parm= RNA_def_string(func, "path", "", 0, "", "Absolute export path."); + RNA_def_function_return(func, parm); + + func= RNA_def_function(srna, "get_abs_filename", "rna_Image_get_abs_filename"); + RNA_def_function_ui_description(func, "Get absolute filename."); + RNA_def_function_flag(func, FUNC_USE_CONTEXT); + parm= RNA_def_string_file_path(func, "abs_filename", NULL, 0, "", "Image/movie absolute filename."); + RNA_def_function_return(func, parm); +} + +#endif + diff --git a/source/blender/makesrna/intern/rna_internal.h b/source/blender/makesrna/intern/rna_internal.h index 4d8ef7082b6..3723c05ada0 100644 --- a/source/blender/makesrna/intern/rna_internal.h +++ b/source/blender/makesrna/intern/rna_internal.h @@ -200,15 +200,19 @@ void rna_Mesh_update_draw(struct bContext *C, struct PointerRNA *ptr); /* API functions */ +void RNA_api_action(StructRNA *srna); +void RNA_api_image(struct StructRNA *srna); void RNA_api_keyingset(struct StructRNA *srna); void RNA_api_main(struct StructRNA *srna); +void RNA_api_material(StructRNA *srna); void RNA_api_mesh(struct StructRNA *srna); void RNA_api_object(struct StructRNA *srna); -void RNA_api_scene(struct StructRNA *srna); +void RNA_api_scene(struct StructRNA *srna); void RNA_api_text(struct StructRNA *srna); void RNA_api_ui_layout(struct StructRNA *srna); void RNA_api_wm(struct StructRNA *srna); + /* ID Properties */ extern StringPropertyRNA rna_IDProperty_string; diff --git a/source/blender/makesrna/intern/rna_key.c b/source/blender/makesrna/intern/rna_key.c index e66ee683e61..e1551404438 100644 --- a/source/blender/makesrna/intern/rna_key.c +++ b/source/blender/makesrna/intern/rna_key.c @@ -257,6 +257,11 @@ static PointerRNA rna_ShapeKey_data_get(CollectionPropertyIterator *iter) return rna_pointer_inherit_refine(&iter->parent, type, rna_iterator_array_get(iter)); } +static char *rna_ShapeKey_path(PointerRNA *ptr) +{ + return BLI_sprintfN("keys[\"%s\"]", ((KeyBlock*)ptr->data)->name); +} + static void rna_Key_update_data(bContext *C, PointerRNA *ptr) { Main *bmain= CTX_data_main(C); @@ -343,6 +348,7 @@ static void rna_def_keyblock(BlenderRNA *brna) srna= RNA_def_struct(brna, "ShapeKey", NULL); RNA_def_struct_ui_text(srna, "Shape Key", "Shape key in a shape keys datablock."); RNA_def_struct_sdna(srna, "KeyBlock"); + RNA_def_struct_path_func(srna, "rna_ShapeKey_path"); RNA_def_struct_ui_icon(srna, ICON_SHAPEKEY_DATA); prop= RNA_def_property(srna, "name", PROP_STRING, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_main_api.c b/source/blender/makesrna/intern/rna_main_api.c index d0a3789b9d8..379cf75d450 100644 --- a/source/blender/makesrna/intern/rna_main_api.c +++ b/source/blender/makesrna/intern/rna_main_api.c @@ -31,14 +31,23 @@ #include "RNA_define.h" #include "RNA_types.h" +#include "RNA_enum_types.h" + +#include "DNA_object_types.h" +#include "DNA_material_types.h" +#include "DNA_mesh_types.h" #ifdef RNA_RUNTIME #include "BKE_main.h" #include "BKE_mesh.h" #include "BKE_library.h" +#include "BKE_object.h" +#include "BKE_material.h" +#include "BKE_image.h" +#include "BKE_texture.h" -#include "DNA_mesh_types.h" +#include "DNA_lamp_types.h" static Mesh *rna_Main_add_mesh(Main *main, char *name) { @@ -57,24 +66,130 @@ static void rna_Main_remove_mesh(Main *main, ReportList *reports, Mesh *me) /* XXX python now has invalid pointer? */ } +static Lamp *rna_Main_add_lamp(Main *main, char *name) +{ + Lamp *la= add_lamp(name); + la->id.us--; + return la; +} + +/* +static void rna_Main_remove_lamp(Main *main, ReportList *reports, Lamp *la) +{ + if(la->id.us == 0) + free_libblock(&main->lamp, la); + else + BKE_report(reports, RPT_ERROR, "Lamp must have zero users to be removed."); +} +*/ + +static Object* rna_Main_add_object(Main *main, int type, char *name) +{ + Object *ob= add_only_object(type, name); + ob->id.us--; + return ob; +} + +/* + NOTE: the following example shows when this function should _not_ be called + + ob = bpy.data.add_object() + scene.add_object(ob) + + # ob is freed here + scene.remove_object(ob) + + # don't do this since ob is already freed! + bpy.data.remove_object(ob) +*/ +static void rna_Main_remove_object(Main *main, ReportList *reports, Object *ob) +{ + if(ob->id.us == 0) + free_libblock(&main->object, ob); + else + BKE_report(reports, RPT_ERROR, "Object must have zero users to be removed."); +} + +static Material *rna_Main_add_material(Main *main, char *name) +{ + return add_material(name); +} + +/* TODO: remove material? */ + +struct Tex *rna_Main_add_texture(Main *main, char *name) +{ + return add_texture(name); +} + +/* TODO: remove texture? */ + +struct Image *rna_Main_add_image(Main *main, char *filename) +{ + return BKE_add_image_file(filename, 0); +} + #else void RNA_api_main(StructRNA *srna) { FunctionRNA *func; - PropertyRNA *prop; + PropertyRNA *parm; + + func= RNA_def_function(srna, "add_object", "rna_Main_add_object"); + RNA_def_function_ui_description(func, "Add a new object."); + parm= RNA_def_enum(func, "type", object_type_items, 0, "", "Type of Object."); + RNA_def_property_flag(parm, PROP_REQUIRED); + parm= RNA_def_string(func, "name", "Object", 0, "", "New name for the datablock."); + RNA_def_property_flag(parm, PROP_REQUIRED); + parm= RNA_def_pointer(func, "object", "Object", "", "New object."); + RNA_def_function_return(func, parm); + + func= RNA_def_function(srna, "remove_object", "rna_Main_remove_object"); + RNA_def_function_flag(func, FUNC_USE_REPORTS); + RNA_def_function_ui_description(func, "Remove an object if it has zero users."); + parm= RNA_def_pointer(func, "object", "Object", "", "Object to remove."); + RNA_def_property_flag(parm, PROP_REQUIRED); func= RNA_def_function(srna, "add_mesh", "rna_Main_add_mesh"); RNA_def_function_ui_description(func, "Add a new mesh."); - prop= RNA_def_string(func, "name", "Mesh", 0, "", "New name for the datablock."); - prop= RNA_def_pointer(func, "mesh", "Mesh", "", "New mesh."); - RNA_def_function_return(func, prop); + parm= RNA_def_string(func, "name", "Mesh", 0, "", "New name for the datablock."); + RNA_def_property_flag(parm, PROP_REQUIRED); + parm= RNA_def_pointer(func, "mesh", "Mesh", "", "New mesh."); + RNA_def_function_return(func, parm); func= RNA_def_function(srna, "remove_mesh", "rna_Main_remove_mesh"); RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Remove a mesh if it has zero users."); - prop= RNA_def_pointer(func, "mesh", "Mesh", "", "Mesh to remove."); - RNA_def_property_flag(prop, PROP_REQUIRED); + parm= RNA_def_pointer(func, "mesh", "Mesh", "", "Mesh to remove."); + RNA_def_property_flag(parm, PROP_REQUIRED); + + func= RNA_def_function(srna, "add_lamp", "rna_Main_add_lamp"); + RNA_def_function_ui_description(func, "Add a new lamp."); + parm= RNA_def_string(func, "name", "Lamp", 0, "", "New name for the datablock."); + RNA_def_property_flag(parm, PROP_REQUIRED); + parm= RNA_def_pointer(func, "mesh", "Lamp", "", "New lamp."); + RNA_def_function_return(func, parm); + + func= RNA_def_function(srna, "add_material", "rna_Main_add_material"); + RNA_def_function_ui_description(func, "Add a new material."); + parm= RNA_def_string(func, "name", "Material", 0, "", "New name for the datablock."); /* optional */ + parm= RNA_def_pointer(func, "material", "Material", "", "New material."); + RNA_def_function_return(func, parm); + + func= RNA_def_function(srna, "add_texture", "rna_Main_add_texture"); + RNA_def_function_ui_description(func, "Add a new texture."); + parm= RNA_def_string(func, "name", "Tex", 0, "", "New name for the datablock."); /* optional */ + parm= RNA_def_pointer(func, "texture", "Texture", "", "New texture."); + RNA_def_function_return(func, parm); + + func= RNA_def_function(srna, "add_image", "rna_Main_add_image"); + RNA_def_function_ui_description(func, "Add a new image."); + parm= RNA_def_string(func, "filename", "", 0, "", "Filename to load image from."); + RNA_def_property_flag(parm, PROP_REQUIRED); + parm= RNA_def_pointer(func, "image", "Image", "", "New image."); + RNA_def_function_return(func, parm); + } #endif diff --git a/source/blender/makesrna/intern/rna_material.c b/source/blender/makesrna/intern/rna_material.c index 18c0dc42e17..a6f22017aaa 100644 --- a/source/blender/makesrna/intern/rna_material.c +++ b/source/blender/makesrna/intern/rna_material.c @@ -645,12 +645,12 @@ static void rna_def_material_colors(StructRNA *srna) RNA_def_property_ui_text(prop, "Mirror Color", "Mirror color of the material."); RNA_def_property_update(prop, NC_MATERIAL|ND_SHADING, NULL); - prop= RNA_def_property(srna, "alpha", PROP_FLOAT, PROP_PERCENTAGE); + prop= RNA_def_property(srna, "alpha", PROP_FLOAT, PROP_FACTOR); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_ui_text(prop, "Alpha", "Alpha transparency of the material."); RNA_def_property_update(prop, NC_MATERIAL|ND_SHADING_DRAW, NULL); - prop= RNA_def_property(srna, "specular_alpha", PROP_FLOAT, PROP_PERCENTAGE); + prop= RNA_def_property(srna, "specular_alpha", PROP_FLOAT, PROP_FACTOR); RNA_def_property_float_sdna(prop, NULL, "spectra"); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_ui_text(prop, "Specular Alpha", "Alpha transparency for specular areas."); @@ -725,7 +725,7 @@ static void rna_def_material_diffuse(StructRNA *srna) RNA_def_property_ui_text(prop, "Diffuse Shader Model", ""); RNA_def_property_update(prop, NC_MATERIAL|ND_SHADING, NULL); - prop= RNA_def_property(srna, "diffuse_intensity", PROP_FLOAT, PROP_PERCENTAGE); + prop= RNA_def_property(srna, "diffuse_intensity", PROP_FLOAT, PROP_FACTOR); RNA_def_property_float_sdna(prop, NULL, "ref"); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_ui_text(prop, "Diffuse Intensity", "Amount of diffuse reflection."); @@ -742,7 +742,7 @@ static void rna_def_material_diffuse(StructRNA *srna) RNA_def_property_ui_text(prop, "Diffuse Toon Size", "Size of diffuse toon area."); RNA_def_property_update(prop, NC_MATERIAL|ND_SHADING, NULL); - prop= RNA_def_property(srna, "diffuse_toon_smooth", PROP_FLOAT, PROP_PERCENTAGE); + prop= RNA_def_property(srna, "diffuse_toon_smooth", PROP_FLOAT, PROP_FACTOR); RNA_def_property_float_sdna(prop, NULL, "param[1]"); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_ui_text(prop, "Diffuse Toon Smooth", "Smoothness of diffuse toon area."); @@ -786,7 +786,7 @@ static void rna_def_material_raymirror(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Enabled", "Enable raytraced reflections."); RNA_def_property_update(prop, NC_MATERIAL|ND_SHADING, NULL); - prop= RNA_def_property(srna, "reflect_factor", PROP_FLOAT, PROP_PERCENTAGE); + prop= RNA_def_property(srna, "reflect_factor", PROP_FLOAT, PROP_FACTOR); RNA_def_property_float_sdna(prop, NULL, "ray_mirror"); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_ui_text(prop, "Reflectivity", "Sets the amount mirror reflection for raytrace."); @@ -798,19 +798,19 @@ static void rna_def_material_raymirror(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Fresnel", "Power of Fresnel for mirror reflection."); RNA_def_property_update(prop, NC_MATERIAL|ND_SHADING, NULL); - prop= RNA_def_property(srna, "fresnel_factor", PROP_FLOAT, PROP_PERCENTAGE); + prop= RNA_def_property(srna, "fresnel_factor", PROP_FLOAT, PROP_FACTOR); RNA_def_property_float_sdna(prop, NULL, "fresnel_mir_i"); RNA_def_property_range(prop, 0.0f, 5.0f); RNA_def_property_ui_text(prop, "Fresnel Factor", "Blending factor for Fresnel."); RNA_def_property_update(prop, NC_MATERIAL|ND_SHADING, NULL); - prop= RNA_def_property(srna, "gloss_factor", PROP_FLOAT, PROP_PERCENTAGE); + prop= RNA_def_property(srna, "gloss_factor", PROP_FLOAT, PROP_FACTOR); RNA_def_property_float_sdna(prop, NULL, "gloss_mir"); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_ui_text(prop, "Gloss Amount", "The shininess of the reflection. Values < 1.0 give diffuse, blurry reflections."); RNA_def_property_update(prop, NC_MATERIAL|ND_SHADING, NULL); - prop= RNA_def_property(srna, "gloss_anisotropic", PROP_FLOAT, PROP_PERCENTAGE); + prop= RNA_def_property(srna, "gloss_anisotropic", PROP_FLOAT, PROP_FACTOR); RNA_def_property_float_sdna(prop, NULL, "aniso_gloss_mir"); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_ui_text(prop, "Gloss Anisotropy", "The shape of the reflection, from 0.0 (circular) to 1.0 (fully stretched along the tangent."); @@ -822,7 +822,7 @@ static void rna_def_material_raymirror(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Gloss Samples", "Number of cone samples averaged for blurry reflections."); RNA_def_property_update(prop, NC_MATERIAL|ND_SHADING, NULL); - prop= RNA_def_property(srna, "gloss_threshold", PROP_FLOAT, PROP_PERCENTAGE); + prop= RNA_def_property(srna, "gloss_threshold", PROP_FLOAT, PROP_FACTOR); RNA_def_property_float_sdna(prop, NULL, "adapt_thresh_mir"); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_ui_text(prop, "Gloss Threshold", "Threshold for adaptive sampling. If a sample contributes less than this amount (as a percentage), sampling is stopped."); @@ -869,13 +869,13 @@ static void rna_def_material_raytra(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Fresnel", "Power of Fresnel for transparency (Ray or ZTransp)."); RNA_def_property_update(prop, NC_MATERIAL|ND_SHADING, NULL); - prop= RNA_def_property(srna, "fresnel_factor", PROP_FLOAT, PROP_PERCENTAGE); + prop= RNA_def_property(srna, "fresnel_factor", PROP_FLOAT, PROP_FACTOR); RNA_def_property_float_sdna(prop, NULL, "fresnel_tra_i"); RNA_def_property_range(prop, 1.0f, 5.0f); RNA_def_property_ui_text(prop, "Fresnel Factor", "Blending factor for Fresnel."); RNA_def_property_update(prop, NC_MATERIAL|ND_SHADING, NULL); - prop= RNA_def_property(srna, "gloss_factor", PROP_FLOAT, PROP_PERCENTAGE); + prop= RNA_def_property(srna, "gloss_factor", PROP_FLOAT, PROP_FACTOR); RNA_def_property_float_sdna(prop, NULL, "gloss_tra"); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_ui_text(prop, "Gloss Amount", "The clarity of the refraction. Values < 1.0 give diffuse, blurry refractions."); @@ -887,7 +887,7 @@ static void rna_def_material_raytra(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Gloss Samples", "Number of cone samples averaged for blurry refractions."); RNA_def_property_update(prop, NC_MATERIAL|ND_SHADING, NULL); - prop= RNA_def_property(srna, "gloss_threshold", PROP_FLOAT, PROP_PERCENTAGE); + prop= RNA_def_property(srna, "gloss_threshold", PROP_FLOAT, PROP_FACTOR); RNA_def_property_float_sdna(prop, NULL, "adapt_thresh_tra"); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_ui_text(prop, "Gloss Threshold", "Threshold for adaptive sampling. If a sample contributes less than this amount (as a percentage), sampling is stopped."); @@ -899,7 +899,7 @@ static void rna_def_material_raytra(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Depth", "Maximum allowed number of light inter-refractions."); RNA_def_property_update(prop, NC_MATERIAL|ND_SHADING, NULL); - prop= RNA_def_property(srna, "filter", PROP_FLOAT, PROP_PERCENTAGE); + prop= RNA_def_property(srna, "filter", PROP_FLOAT, PROP_FACTOR); RNA_def_property_float_sdna(prop, NULL, "filter"); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_ui_text(prop, "Filter", "Amount to blend in the material's diffuse color in raytraced transparency (simulating absorption)."); @@ -1011,7 +1011,7 @@ static void rna_def_material_volume(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Depth Cutoff", "Stop ray marching early if transmission drops below this luminance - higher values give speedups in dense volumes at the expense of accuracy."); RNA_def_property_update(prop, NC_MATERIAL|ND_SHADING, NULL); - prop= RNA_def_property(srna, "density", PROP_FLOAT, PROP_PERCENTAGE); + prop= RNA_def_property(srna, "density", PROP_FLOAT, PROP_FACTOR); RNA_def_property_float_sdna(prop, NULL, "density"); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_ui_text(prop, "Density", "The base density of the volume"); @@ -1093,7 +1093,7 @@ static void rna_def_material_halo(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Hardness", "Sets the hardness of the halo."); RNA_def_property_update(prop, NC_MATERIAL|ND_SHADING, NULL); - prop= RNA_def_property(srna, "add", PROP_FLOAT, PROP_PERCENTAGE); + prop= RNA_def_property(srna, "add", PROP_FLOAT, PROP_FACTOR); RNA_def_property_float_sdna(prop, NULL, "add"); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_ui_text(prop, "Add", "Sets the strength of the add effect."); @@ -1239,13 +1239,13 @@ static void rna_def_material_sss(BlenderRNA *brna) RNA_def_property_ui_text(prop, "IOR", "Index of refraction (higher values are denser)."); RNA_def_property_update(prop, NC_MATERIAL|ND_SHADING, NULL); - prop= RNA_def_property(srna, "color_factor", PROP_FLOAT, PROP_PERCENTAGE); + prop= RNA_def_property(srna, "color_factor", PROP_FLOAT, PROP_FACTOR); RNA_def_property_float_sdna(prop, NULL, "sss_colfac"); RNA_def_property_ui_range(prop, 0, 1, 10, 3); RNA_def_property_ui_text(prop, "Color Factor", "Blend factor for SSS colors."); RNA_def_property_update(prop, NC_MATERIAL|ND_SHADING, NULL); - prop= RNA_def_property(srna, "texture_factor", PROP_FLOAT, PROP_PERCENTAGE); + prop= RNA_def_property(srna, "texture_factor", PROP_FLOAT, PROP_FACTOR); RNA_def_property_float_sdna(prop, NULL, "sss_texfac"); RNA_def_property_ui_range(prop, 0, 1, 10, 3); RNA_def_property_ui_text(prop, "Texture Factor", "Texture scatting blend factor."); @@ -1287,7 +1287,7 @@ static void rna_def_material_specularity(StructRNA *srna) RNA_def_property_ui_text(prop, "Specular Shader Model", ""); RNA_def_property_update(prop, NC_MATERIAL|ND_SHADING, NULL); - prop= RNA_def_property(srna, "specular_intensity", PROP_FLOAT, PROP_PERCENTAGE); + prop= RNA_def_property(srna, "specular_intensity", PROP_FLOAT, PROP_FACTOR); RNA_def_property_float_sdna(prop, NULL, "spec"); RNA_def_property_range(prop, 0, 1); RNA_def_property_ui_text(prop, "Specular Intensity", ""); @@ -1316,7 +1316,7 @@ static void rna_def_material_specularity(StructRNA *srna) RNA_def_property_ui_text(prop, "Specular Toon Size", "Size of specular toon area."); RNA_def_property_update(prop, NC_MATERIAL|ND_SHADING, NULL); - prop= RNA_def_property(srna, "specular_toon_smooth", PROP_FLOAT, PROP_PERCENTAGE); + prop= RNA_def_property(srna, "specular_toon_smooth", PROP_FLOAT, PROP_FACTOR); RNA_def_property_float_sdna(prop, NULL, "param[3]"); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_ui_text(prop, "Specular Toon Smooth", "Ssmoothness of specular toon area."); @@ -1474,7 +1474,7 @@ void RNA_def_material(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Transparency Method", "Method to use for rendering transparency."); RNA_def_property_update(prop, NC_MATERIAL|ND_SHADING, NULL); - prop= RNA_def_property(srna, "ambient", PROP_FLOAT, PROP_PERCENTAGE); + prop= RNA_def_property(srna, "ambient", PROP_FLOAT, PROP_FACTOR); RNA_def_property_float_sdna(prop, NULL, "amb"); RNA_def_property_range(prop, 0, 1); RNA_def_property_ui_text(prop, "Ambient", "Amount of global ambient color the material receives."); @@ -1486,7 +1486,7 @@ void RNA_def_material(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Emit", "Amount of light to emit."); RNA_def_property_update(prop, NC_MATERIAL|ND_SHADING, NULL); - prop= RNA_def_property(srna, "translucency", PROP_FLOAT, PROP_PERCENTAGE); + prop= RNA_def_property(srna, "translucency", PROP_FLOAT, PROP_FACTOR); RNA_def_property_range(prop, 0, 1); RNA_def_property_ui_text(prop, "Translucency", "Amount of diffuse shading on the back side."); RNA_def_property_update(prop, NC_MATERIAL|ND_SHADING, NULL); @@ -1511,7 +1511,7 @@ void RNA_def_material(BlenderRNA *brna) RNA_def_property_range(prop, 0, 10); RNA_def_property_ui_text(prop, "Shadow Buffer Bias", "Factor to multiply shadow buffer bias with (0 is ignore.)"); - prop= RNA_def_property(srna, "shadow_casting_alpha", PROP_FLOAT, PROP_PERCENTAGE); + prop= RNA_def_property(srna, "shadow_casting_alpha", PROP_FLOAT, PROP_FACTOR); RNA_def_property_float_sdna(prop, NULL, "shad_alpha"); RNA_def_property_range(prop, 0.001, 1); RNA_def_property_ui_text(prop, "Shadow Casting Alpha", "Shadow casting alpha, only in use for Irregular Shadowbuffer."); @@ -1688,6 +1688,8 @@ void RNA_def_material(BlenderRNA *brna) rna_def_material_mtex(brna); rna_def_material_strand(brna); rna_def_material_physics(brna); + + RNA_api_material(srna); } void rna_def_mtex_common(StructRNA *srna, const char *begin, const char *activeget, const char *activeset, const char *structname) diff --git a/source/blender/makesrna/intern/rna_material_api.c b/source/blender/makesrna/intern/rna_material_api.c new file mode 100644 index 00000000000..aa28b6b923c --- /dev/null +++ b/source/blender/makesrna/intern/rna_material_api.c @@ -0,0 +1,126 @@ +/** + * + * + * ***** 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) 2009 Blender Foundation. + * All rights reserved. + * + * + * Contributor(s): Blender Foundation + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include <stdlib.h> +#include <stdio.h> + +#include "RNA_define.h" +#include "RNA_types.h" + +#include "DNA_material_types.h" + +#ifdef RNA_RUNTIME + +#include "BKE_material.h" +#include "BKE_texture.h" + +/* + Adds material to the first free texture slot. + If all slots are busy, replaces the first. +*/ +static void rna_Material_add_texture(Material *ma, Tex *tex, int mapto, int texco) +{ + int i; + MTex *mtex; + int slot= -1; + + for (i= 0; i < MAX_MTEX; i++) { + if (!ma->mtex[i]) { + slot= i; + break; + } + } + + if (slot == -1) + slot= 0; + + if (ma->mtex[slot]) { + ma->mtex[slot]->tex->id.us--; + } + else { + ma->mtex[slot]= add_mtex(); + } + + mtex= ma->mtex[slot]; + + mtex->tex= tex; + id_us_plus(&tex->id); + + mtex->texco= mapto; + mtex->mapto= texco; +} + +#else + +void RNA_api_material(StructRNA *srna) +{ + FunctionRNA *func; + PropertyRNA *parm; + + /* copied from rna_def_material_mtex (rna_material.c) */ + static EnumPropertyItem prop_texture_coordinates_items[] = { + {TEXCO_GLOB, "GLOBAL", 0, "Global", "Uses global coordinates for the texture coordinates."}, + {TEXCO_OBJECT, "OBJECT", 0, "Object", "Uses linked object's coordinates for texture coordinates."}, + {TEXCO_UV, "UV", 0, "UV", "Uses UV coordinates for texture coordinates."}, + {TEXCO_ORCO, "ORCO", 0, "Generated", "Uses the original undeformed coordinates of the object."}, + {TEXCO_STRAND, "STRAND", 0, "Strand", "Uses normalized strand texture coordinate (1D)."}, + {TEXCO_STICKY, "STICKY", 0, "Sticky", "Uses mesh's sticky coordinates for the texture coordinates."}, + {TEXCO_WINDOW, "WINDOW", 0, "Window", "Uses screen coordinates as texture coordinates."}, + {TEXCO_NORM, "NORMAL", 0, "Normal", "Uses normal vector as texture coordinates."}, + {TEXCO_REFL, "REFLECTION", 0, "Reflection", "Uses reflection vector as texture coordinates."}, + {TEXCO_STRESS, "STRESS", 0, "Stress", "Uses the difference of edge lengths compared to original coordinates of the mesh."}, + {TEXCO_TANGENT, "TANGENT", 0, "Tangent", "Uses the optional tangent vector as texture coordinates."}, + + {0, NULL, 0, NULL, NULL}}; + + static EnumPropertyItem prop_texture_mapto_items[] = { + {MAP_COL, "COLOR", 0, "Color", "Causes the texture to affect basic color of the material"}, + {MAP_NORM, "NORMAL", 0, "Normal", "Causes the texture to affect the rendered normal"}, + {MAP_COLSPEC, "SPECULAR_COLOR", 0, "Specularity Color", "Causes the texture to affect the specularity color"}, + {MAP_COLMIR, "MIRROR", 0, "Mirror", "Causes the texture to affect the mirror color"}, + {MAP_REF, "REFLECTION", 0, "Reflection", "Causes the texture to affect the value of the materials reflectivity"}, + {MAP_SPEC, "SPECULARITY", 0, "Specularity", "Causes the texture to affect the value of specularity"}, + {MAP_EMIT, "EMIT", 0, "Emit", "Causes the texture to affect the emit value"}, + {MAP_ALPHA, "ALPHA", 0, "Alpha", "Causes the texture to affect the alpha value"}, + {MAP_HAR, "HARDNESS", 0, "Hardness", "Causes the texture to affect the hardness value"}, + {MAP_RAYMIRR, "RAY_MIRROR", 0, "Ray-Mirror", "Causes the texture to affect the ray-mirror value"}, + {MAP_TRANSLU, "TRANSLUCENCY", 0, "Translucency", "Causes the texture to affect the translucency value"}, + {MAP_AMB, "AMBIENT", 0, "Ambient", "Causes the texture to affect the value of ambient"}, + {MAP_DISPLACE, "DISPLACEMENT", 0, "Displacement", "Let the texture displace the surface"}, + {MAP_WARP, "WARP", 0, "Warp", "Let the texture warp texture coordinates of next channels"}, + {0, NULL, 0, NULL, NULL}}; + + func= RNA_def_function(srna, "add_texture", "rna_Material_add_texture"); + RNA_def_function_ui_description(func, "Add a texture to material's free texture slot."); + parm= RNA_def_pointer(func, "texture", "Texture", "", "Texture to add."); + parm= RNA_def_enum(func, "texture_coordinates", prop_texture_coordinates_items, TEXCO_UV, "", "Source of texture coordinate information."); /* optional */ + parm= RNA_def_enum(func, "map_to", prop_texture_mapto_items, MAP_COL, "", "Controls which material property the texture affects."); /* optional */ +} + +#endif + diff --git a/source/blender/makesrna/intern/rna_mesh.c b/source/blender/makesrna/intern/rna_mesh.c index 78fb8ede3ee..ecfe59a0142 100644 --- a/source/blender/makesrna/intern/rna_mesh.c +++ b/source/blender/makesrna/intern/rna_mesh.c @@ -953,6 +953,16 @@ static void rna_def_medge(BlenderRNA *brna) RNA_def_property_boolean_sdna(prop, NULL, "flag", ME_SHARP); RNA_def_property_ui_text(prop, "Sharp", "Sharp edge for the EdgeSplit modifier"); RNA_def_property_update(prop, 0, "rna_Mesh_update_data"); + + prop= RNA_def_property(srna, "loose", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", ME_LOOSEEDGE); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_ui_text(prop, "Loose", "Loose edge"); + + prop= RNA_def_property(srna, "fgon", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", ME_FGON); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_ui_text(prop, "Fgon", "Fgon edge"); } static void rna_def_mface(BlenderRNA *brna) @@ -972,6 +982,7 @@ static void rna_def_mface(BlenderRNA *brna) RNA_def_property_flag(prop, PROP_DYNAMIC); RNA_def_property_dynamic_array_funcs(prop, "rna_MeshFace_verts_get_length"); RNA_def_property_int_funcs(prop, "rna_MeshFace_verts_get", "rna_MeshFace_verts_set", NULL); + RNA_def_property_ui_text(prop, "Vertices", "Vertex indices"); prop= RNA_def_property(srna, "material_index", PROP_INT, PROP_UNSIGNED); diff --git a/source/blender/makesrna/intern/rna_mesh_api.c b/source/blender/makesrna/intern/rna_mesh_api.c index 686d91e4fe2..d8466337781 100644 --- a/source/blender/makesrna/intern/rna_mesh_api.c +++ b/source/blender/makesrna/intern/rna_mesh_api.c @@ -42,12 +42,19 @@ #include "BKE_DerivedMesh.h" #include "BKE_main.h" #include "BKE_mesh.h" +#include "BKE_material.h" +#include "DNA_mesh_types.h" +#include "DNA_scene_types.h" + +#include "BLI_arithb.h" #include "BLI_edgehash.h" #include "WM_api.h" #include "WM_types.h" +#include "MEM_guardedalloc.h" + static void rna_Mesh_calc_edges(Mesh *mesh) { CustomData edata; @@ -102,6 +109,9 @@ static void rna_Mesh_calc_edges(Mesh *mesh) static void rna_Mesh_update(Mesh *mesh, bContext *C) { + Main *bmain= CTX_data_main(C); + Object *ob; + if(mesh->totface && mesh->totedge == 0) rna_Mesh_calc_edges(mesh); @@ -111,6 +121,18 @@ static void rna_Mesh_update(Mesh *mesh, bContext *C) WM_event_add_notifier(C, NC_GEOM|ND_DATA, mesh); } +static void rna_Mesh_transform(Mesh *me, float *mat) +{ + + /* TODO: old API transform had recalc_normals option */ + int i; + MVert *mvert= me->mvert; + + for(i= 0; i < me->totvert; i++, mvert++) { + Mat4MulVecfl((float (*)[4])mat, mvert->co); + } +} + static void rna_Mesh_add_verts(Mesh *mesh, int len) { CustomData vdata; @@ -141,6 +163,14 @@ static void rna_Mesh_add_verts(Mesh *mesh, int len) mesh->totvert= totvert; } +Mesh *rna_Mesh_create_copy(Mesh *me) +{ + Mesh *ret= copy_mesh(me); + ret->id.us--; + + return ret; +} + static void rna_Mesh_add_edges(Mesh *mesh, int len) { CustomData edata; @@ -201,6 +231,12 @@ static void rna_Mesh_add_faces(Mesh *mesh, int len) mesh->totface= totface; } +/* +static void rna_Mesh_add_faces(Mesh *mesh) +{ +} +*/ + static void rna_Mesh_add_geometry(Mesh *mesh, int verts, int edges, int faces) { if(verts) @@ -211,6 +247,39 @@ static void rna_Mesh_add_geometry(Mesh *mesh, int verts, int edges, int faces) rna_Mesh_add_faces(mesh, faces); } +static void rna_Mesh_add_uv_texture(Mesh *me) +{ + me->mtface= CustomData_add_layer(&me->fdata, CD_MTFACE, CD_DEFAULT, NULL, me->totface); +} + +static void rna_Mesh_calc_normals(Mesh *me) +{ + mesh_calc_normals(me->mvert, me->totvert, me->mface, me->totface, NULL); +} + +static void rna_Mesh_add_material(Mesh *me, Material *ma) +{ + int i; + int totcol = me->totcol + 1; + Material **mat; + + /* don't add if mesh already has it */ + for (i = 0; i < me->totcol; i++) + if (me->mat[i] == ma) + return; + + mat= MEM_callocN(sizeof(void*) * totcol, "newmatar"); + + if (me->totcol) memcpy(mat, me->mat, sizeof(void*) * me->totcol); + if (me->mat) MEM_freeN(me->mat); + + me->mat = mat; + me->mat[me->totcol++] = ma; + ma->id.us++; + + test_object_materials((ID*)me); +} + #else void RNA_api_mesh(StructRNA *srna) @@ -218,6 +287,11 @@ void RNA_api_mesh(StructRNA *srna) FunctionRNA *func; PropertyRNA *parm; + func= RNA_def_function(srna, "transform", "rna_Mesh_transform"); + RNA_def_function_ui_description(func, "Transform mesh vertices by a matrix."); + parm= RNA_def_float_matrix(func, "matrix", 4, 4, NULL, 0.0f, 0.0f, "", "Matrix.", 0.0f, 0.0f); + RNA_def_property_flag(parm, PROP_REQUIRED); + func= RNA_def_function(srna, "add_geometry", "rna_Mesh_add_geometry"); parm= RNA_def_int(func, "verts", 0, 0, INT_MAX, "Number", "Number of vertices to add.", 0, INT_MAX); RNA_def_property_flag(parm, PROP_REQUIRED); @@ -226,8 +300,24 @@ void RNA_api_mesh(StructRNA *srna) parm= RNA_def_int(func, "faces", 0, 0, INT_MAX, "Number", "Number of faces to add.", 0, INT_MAX); RNA_def_property_flag(parm, PROP_REQUIRED); + func= RNA_def_function(srna, "create_copy", "rna_Mesh_create_copy"); + RNA_def_function_ui_description(func, "Create a copy of this Mesh datablock."); + parm= RNA_def_pointer(func, "mesh", "Mesh", "", "Mesh, remove it if it is only used for export."); + RNA_def_function_return(func, parm); + + func= RNA_def_function(srna, "add_uv_texture", "rna_Mesh_add_uv_texture"); + RNA_def_function_ui_description(func, "Add a UV texture layer to Mesh."); + + func= RNA_def_function(srna, "calc_normals", "rna_Mesh_calc_normals"); + RNA_def_function_ui_description(func, "Calculate vertex normals."); + func= RNA_def_function(srna, "update", "rna_Mesh_update"); RNA_def_function_flag(func, FUNC_USE_CONTEXT); + + func= RNA_def_function(srna, "add_material", "rna_Mesh_add_material"); + RNA_def_function_ui_description(func, "Add a new material to Mesh."); + parm= RNA_def_pointer(func, "material", "Material", "", "Material to add."); + RNA_def_property_flag(parm, PROP_REQUIRED); } #endif diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c index ffc2d78a6ce..480abff19cb 100644 --- a/source/blender/makesrna/intern/rna_modifier.c +++ b/source/blender/makesrna/intern/rna_modifier.c @@ -1619,12 +1619,6 @@ static void rna_def_modifier_collision(BlenderRNA *brna) RNA_def_property_struct_type(prop, "CollisionSettings"); RNA_def_property_pointer_funcs(prop, "rna_CollisionModifier_settings_get", NULL, NULL); RNA_def_property_ui_text(prop, "Settings", ""); - - prop= RNA_def_property(srna, "absorption", PROP_INT, PROP_PERCENTAGE); - RNA_def_property_int_sdna(prop, NULL, "absorption"); - RNA_def_property_ui_range(prop, 0, 100, 1, 2); - RNA_def_property_ui_text(prop, "Absorption %", "How much of effector force gets lost during collision with this object (in percent)."); - RNA_def_property_update(prop, 0, "rna_Modifier_update"); } static void rna_def_modifier_bevel(BlenderRNA *brna) diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c index f2caf1a4d52..ebd032bb0b1 100644 --- a/source/blender/makesrna/intern/rna_nodetree.c +++ b/source/blender/makesrna/intern/rna_nodetree.c @@ -473,10 +473,11 @@ static void def_sh_geometry(StructRNA *srna) static void def_cmp_alpha_over(StructRNA *srna) { PropertyRNA *prop; - + + // XXX: Tooltip prop = RNA_def_property(srna, "convert_premul", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "custom1", 1); - RNA_def_property_ui_text(prop, "convert_premul", "TODO: don't know what this is"); + RNA_def_property_ui_text(prop, "Convert Premul", ""); RNA_def_property_update(prop, 0, "rna_Node_update"); RNA_def_struct_sdna_from(srna, "NodeTwoFloats", "storage"); @@ -488,6 +489,31 @@ static void def_cmp_alpha_over(StructRNA *srna) RNA_def_property_update(prop, 0, "rna_Node_update"); } +static void def_cmp_hue_saturation(StructRNA *srna) +{ + PropertyRNA *prop; + + RNA_def_struct_sdna_from(srna, "NodeHueSat", "storage"); + + prop = RNA_def_property(srna, "hue", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "hue"); + RNA_def_property_range(prop, 0.0f, 1.0f); + RNA_def_property_ui_text(prop, "Hue", ""); + RNA_def_property_update(prop, 0, "rna_Node_update"); + + prop = RNA_def_property(srna, "sat", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "sat"); + RNA_def_property_range(prop, 0.0f, 2.0f); + RNA_def_property_ui_text(prop, "Saturation", ""); + RNA_def_property_update(prop, 0, "rna_Node_update"); + + prop = RNA_def_property(srna, "val", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "val"); + RNA_def_property_range(prop, 0.0f, 2.0f); + RNA_def_property_ui_text(prop, "Value", ""); + RNA_def_property_update(prop, 0, "rna_Node_update"); +} + static void def_cmp_blur(StructRNA *srna) { PropertyRNA *prop; @@ -514,7 +540,7 @@ static void def_cmp_blur(StructRNA *srna) prop = RNA_def_property(srna, "sizey", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "sizey"); - RNA_def_property_range(prop, 1, 256); + RNA_def_property_range(prop, 0, 256); RNA_def_property_ui_text(prop, "Size Y", ""); RNA_def_property_update(prop, 0, "rna_Node_update"); @@ -605,12 +631,14 @@ static void def_cmp_map_value(StructRNA *srna) prop = RNA_def_property(srna, "offset", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "loc"); + RNA_def_property_array(prop, 1); RNA_def_property_range(prop, -1000.0f, 1000.0f); RNA_def_property_ui_text(prop, "Offset", ""); RNA_def_property_update(prop, 0, "rna_Node_update"); prop = RNA_def_property(srna, "size", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "size"); + RNA_def_property_array(prop, 1); RNA_def_property_range(prop, -1000.0f, 1000.0f); RNA_def_property_ui_text(prop, "Size", ""); RNA_def_property_update(prop, 0, "rna_Node_update"); @@ -627,12 +655,14 @@ static void def_cmp_map_value(StructRNA *srna) prop = RNA_def_property(srna, "min", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "min"); + RNA_def_property_array(prop, 1); RNA_def_property_range(prop, -1000.0f, 1000.0f); RNA_def_property_ui_text(prop, "Minimum", ""); RNA_def_property_update(prop, 0, "rna_Node_update"); prop = RNA_def_property(srna, "max", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "max"); + RNA_def_property_array(prop, 1); RNA_def_property_range(prop, -1000.0f, 1000.0f); RNA_def_property_ui_text(prop, "Maximum", ""); RNA_def_property_update(prop, 0, "rna_Node_update"); @@ -670,6 +700,26 @@ static void def_cmp_vector_blur(StructRNA *srna) RNA_def_property_update(prop, 0, "rna_Node_update"); } +static void def_cmp_levels(StructRNA *srna) +{ + PropertyRNA *prop; + + static EnumPropertyItem space_items[] = { + {1, "COMNINED_RGB", 0, "C", "Combined RGB"}, + {2, "RED", 0, "R", "Red Channel"}, + {3, "GREEN", 0, "G", "Green Channel"}, + {4, "BLUE", 0, "B", "Blue Channel"}, + {5, "LUMINANCE", 0, "L", "Luminance Channel"}, + {0, NULL, 0, NULL, NULL} + }; + + prop = RNA_def_property(srna, "color_space", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "custom1"); + RNA_def_property_enum_items(prop, space_items); + RNA_def_property_ui_text(prop, "Color Space", ""); + RNA_def_property_update(prop, 0, "rna_Node_update"); +} + static void def_cmp_image(StructRNA *srna) { PropertyRNA *prop; @@ -837,6 +887,7 @@ static void def_cmp_dilate_erode(StructRNA *srna) prop = RNA_def_property(srna, "distance", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "custom2"); + RNA_def_property_range(prop, -100, 100); RNA_def_property_ui_text(prop, "Distance", "Distance to grow/shrink (number of iterations)"); RNA_def_property_update(prop, 0, "rna_Node_update"); } @@ -933,9 +984,9 @@ static void def_cmp_color_spill(StructRNA *srna) PropertyRNA *prop; static EnumPropertyItem channel_items[] = { - {1, "R", 0, "Red", ""}, - {2, "G", 0, "Green", ""}, - {3, "B", 0, "Blue", ""}, + {1, "R", 0, "R", "Red Spill Suppression"}, + {2, "G", 0, "G", "Green Spill Suppression"}, + {3, "B", 0, "B", "Blue Spill Suppression"}, {0, NULL, 0, NULL, NULL} }; @@ -1066,11 +1117,10 @@ static void def_cmp_splitviewer(StructRNA *srna) RNA_def_property_enum_items(prop, axis_items); RNA_def_property_ui_text(prop, "Axis", ""); RNA_def_property_update(prop, 0, "rna_Node_update"); - - /* TODO: percentage */ - prop = RNA_def_property(srna, "factor", PROP_FLOAT, PROP_PERCENTAGE); - RNA_def_property_float_sdna(prop, NULL, "custom1"); - RNA_def_property_range(prop, 0.0f, 100.0f); + + prop = RNA_def_property(srna, "factor", PROP_INT, PROP_FACTOR); + RNA_def_property_int_sdna(prop, NULL, "custom1"); + RNA_def_property_range(prop, 0, 100); RNA_def_property_ui_text(prop, "Factor", ""); RNA_def_property_update(prop, 0, "rna_Node_update"); } @@ -1090,7 +1140,7 @@ static void def_cmp_map_uv(StructRNA *srna) { PropertyRNA *prop; - prop = RNA_def_property(srna, "alpha", PROP_INT, PROP_PERCENTAGE); + prop = RNA_def_property(srna, "alpha", PROP_INT, PROP_FACTOR); RNA_def_property_int_sdna(prop, NULL, "custom1"); RNA_def_property_range(prop, 0, 100); RNA_def_property_ui_text(prop, "Alpha", ""); @@ -1255,7 +1305,7 @@ static void def_cmp_dblur(StructRNA *srna) prop = RNA_def_property(srna, "iterations", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "iter"); - RNA_def_property_range(prop, 1, 128); + RNA_def_property_range(prop, 1, 32); RNA_def_property_ui_text(prop, "Iterations", ""); RNA_def_property_update(prop, 0, "rna_Node_update"); @@ -1356,12 +1406,12 @@ static void def_cmp_glare(StructRNA *srna) {0, NULL, 0, NULL, NULL} }; - /*static EnumPropertyItem quality_items[] = { + static EnumPropertyItem quality_items[] = { {0, "HIGH", 0, "High", ""}, {1, "MEDIUM", 0, "Medium", ""}, {2, "LOW", 0, "Low", ""}, {0, NULL, 0, NULL, NULL} - };*/ + }; RNA_def_struct_sdna_from(srna, "NodeGlare", "storage"); @@ -1373,7 +1423,7 @@ static void def_cmp_glare(StructRNA *srna) prop = RNA_def_property(srna, "quality", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "quality"); - RNA_def_property_enum_items(prop, type_items); + RNA_def_property_enum_items(prop, quality_items); RNA_def_property_ui_text(prop, "Quality", "If not set to high quality, the effect will be applied to a low-res copy of the source image"); RNA_def_property_update(prop, 0, "rna_Node_update"); @@ -1386,7 +1436,7 @@ static void def_cmp_glare(StructRNA *srna) prop = RNA_def_property(srna, "color_modulation", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "colmod"); RNA_def_property_range(prop, 0.0f, 1.0f); - RNA_def_property_ui_text(prop, "Color Modulation", ""); + RNA_def_property_ui_text(prop, "Color Modulation", "Amount of Color Modulation, modulates colors of streaks and ghosts for a spectral dispersion effect"); RNA_def_property_update(prop, 0, "rna_Node_update"); prop = RNA_def_property(srna, "mix", PROP_FLOAT, PROP_NONE); @@ -1451,8 +1501,6 @@ static void def_cmp_tonemap(StructRNA *srna) RNA_def_property_ui_text(prop, "Tonemap Type", ""); RNA_def_property_update(prop, 0, "rna_Node_update"); - /* TODO: if type==0 { */ - prop = RNA_def_property(srna, "key", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "key"); RNA_def_property_range(prop, 0.0f, 1.0f); @@ -1471,8 +1519,6 @@ static void def_cmp_tonemap(StructRNA *srna) RNA_def_property_ui_text(prop, "Gamma", "If not used, set to 1"); RNA_def_property_update(prop, 0, "rna_Node_update"); - /* TODO: } else { */ - prop = RNA_def_property(srna, "intensity", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "f"); RNA_def_property_range(prop, -8.0f, 8.0f); @@ -1665,6 +1711,8 @@ static void rna_def_nodetree(BlenderRNA *brna) RNA_def_struct_ui_text(srna, "Node Tree", "Node tree consisting of linked nodes used for materials, textures and compositing."); RNA_def_struct_sdna(srna, "bNodeTree"); RNA_def_struct_ui_icon(srna, ICON_NODE); + + rna_def_animdata_common(srna); prop = RNA_def_property(srna, "nodes", PROP_COLLECTION, PROP_NONE); RNA_def_property_collection_sdna(prop, NULL, "nodes", NULL); diff --git a/source/blender/makesrna/intern/rna_nodetree_types.h b/source/blender/makesrna/intern/rna_nodetree_types.h index be4f131a6d6..69424649b3b 100644 --- a/source/blender/makesrna/intern/rna_nodetree_types.h +++ b/source/blender/makesrna/intern/rna_nodetree_types.h @@ -64,7 +64,7 @@ DefNode( CompositorNode, CMP_NODE_VECBLUR, def_cmp_vector_blur, "VECBL DefNode( CompositorNode, CMP_NODE_SEPRGBA, 0, "SEPRGBA", SepRGBA, "Separate RGBA", "" ) DefNode( CompositorNode, CMP_NODE_SEPHSVA, 0, "SEPHSVA", SepHSVA, "Separate HSVA", "" ) DefNode( CompositorNode, CMP_NODE_SETALPHA, 0, "SETALPHA", SetAlpha, "Set Alpha", "" ) -DefNode( CompositorNode, CMP_NODE_HUE_SAT, 0, "HUE_SAT", HueSat, "Hue/Saturation", "" ) +DefNode( CompositorNode, CMP_NODE_HUE_SAT, def_cmp_hue_saturation, "HUE_SAT", HueSat, "Hue/Saturation", "" ) DefNode( CompositorNode, CMP_NODE_IMAGE, def_cmp_image, "IMAGE", Image, "Image", "" ) DefNode( CompositorNode, CMP_NODE_R_LAYERS, def_cmp_render_layers, "R_LAYERS", RLayers, "Render Layers", "" ) DefNode( CompositorNode, CMP_NODE_COMPOSITE, 0, "COMPOSITE", Composite, "Composite", "" ) @@ -104,7 +104,7 @@ DefNode( CompositorNode, CMP_NODE_PREMULKEY, def_cmp_premul_key, "PREMU DefNode( CompositorNode, CMP_NODE_GLARE, def_cmp_glare, "GLARE", Glare, "Glare", "" ) DefNode( CompositorNode, CMP_NODE_TONEMAP, def_cmp_tonemap, "TONEMAP", Tonemap, "Tonemap", "" ) DefNode( CompositorNode, CMP_NODE_LENSDIST, def_cmp_lensdist, "LENSDIST", Lensdist, "Lensdist", "" ) -DefNode( CompositorNode, CMP_NODE_VIEW_LEVELS, 0, "LEVELS", Levels, "Levels", "" ) +DefNode( CompositorNode, CMP_NODE_VIEW_LEVELS, def_cmp_levels, "LEVELS", Levels, "Levels", "" ) DefNode( CompositorNode, CMP_NODE_COLOR_MATTE, def_cmp_color_matte, "COLOR_MATTE", ColorMatte, "Color Matte", "" ) DefNode( CompositorNode, CMP_NODE_DIST_MATTE, def_cmp_distance_matte, "DISTANCE_MATTE", DistanceMatte, "Distance Matte", "" ) diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c index 8e805597e11..5c665c0d730 100644 --- a/source/blender/makesrna/intern/rna_object.c +++ b/source/blender/makesrna/intern/rna_object.c @@ -103,6 +103,12 @@ void rna_Object_update(bContext *C, PointerRNA *ptr) DAG_id_flush_update(ptr->id.data, OB_RECALC_OB); } +void rna_Object_matrix_update(bContext *C, PointerRNA *ptr) +{ + ED_object_apply_obmat(ptr->id.data); + rna_Object_update(C, ptr); +} + void rna_Object_update_data(bContext *C, PointerRNA *ptr) { DAG_id_flush_update(ptr->id.data, OB_RECALC_DATA); @@ -1212,6 +1218,7 @@ static void rna_def_object(BlenderRNA *brna) RNA_def_property_float_sdna(prop, NULL, "obmat"); RNA_def_property_multi_array(prop, 2, matrix_dimsize); RNA_def_property_ui_text(prop, "Matrix", "Transformation matrix."); + RNA_def_property_update(prop, NC_OBJECT|ND_TRANSFORM, "rna_Object_matrix_update"); /* collections */ prop= RNA_def_property(srna, "constraints", PROP_COLLECTION, PROP_NONE); @@ -1407,6 +1414,11 @@ static void rna_def_object(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Dupli Frames Off", "Recurring frames to exclude from the Dupliframes."); RNA_def_property_update(prop, NC_OBJECT|ND_DRAW, "rna_Object_update"); + prop= RNA_def_property(srna, "dupli_list", PROP_COLLECTION, PROP_NONE); + RNA_def_property_collection_sdna(prop, NULL, "duplilist", NULL); + RNA_def_property_struct_type(prop, "DupliObject"); + RNA_def_property_ui_text(prop, "Dupli list", "Object duplis."); + /* time offset */ prop= RNA_def_property(srna, "time_offset", PROP_FLOAT, PROP_NONE|PROP_UNIT_TIME); @@ -1524,12 +1536,43 @@ static void rna_def_object(BlenderRNA *brna) RNA_api_object(srna); } +static void rna_def_dupli_object(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + + srna= RNA_def_struct(brna, "DupliObject", NULL); + RNA_def_struct_sdna(srna, "DupliObject"); + RNA_def_struct_ui_text(srna, "Dupli Object", "Dupli Object data."); + /* RNA_def_struct_ui_icon(srna, ICON_OBJECT_DATA); */ + + prop= RNA_def_property(srna, "object", PROP_POINTER, PROP_NONE); + /* RNA_def_property_struct_type(prop, "Object"); */ + RNA_def_property_pointer_sdna(prop, NULL, "ob"); + /* RNA_def_property_pointer_funcs(prop, "rna_DupliObject_object_get", NULL, NULL); */ + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_ui_text(prop, "Object", "Object this DupliObject represents."); + + prop= RNA_def_property(srna, "ob_matrix", PROP_FLOAT, PROP_MATRIX); + RNA_def_property_float_sdna(prop, NULL, "omat"); + RNA_def_property_array(prop, 16); + RNA_def_property_ui_text(prop, "Object Matrix", "Object transformation matrix."); + + prop= RNA_def_property(srna, "matrix", PROP_FLOAT, PROP_MATRIX); + RNA_def_property_float_sdna(prop, NULL, "mat"); + RNA_def_property_array(prop, 16); + RNA_def_property_ui_text(prop, "DupliObject Matrix", "DupliObject transformation matrix."); + + /* TODO: DupliObject has more properties that can be wrapped */ +} + void RNA_def_object(BlenderRNA *brna) { rna_def_object(brna); rna_def_object_game_settings(brna); rna_def_vertex_group(brna); rna_def_material_slot(brna); + rna_def_dupli_object(brna); } #endif diff --git a/source/blender/makesrna/intern/rna_object_api.c b/source/blender/makesrna/intern/rna_object_api.c index e51dcbe3c57..098604c1eab 100644 --- a/source/blender/makesrna/intern/rna_object_api.c +++ b/source/blender/makesrna/intern/rna_object_api.c @@ -28,43 +28,64 @@ #include <stdlib.h> #include <stdio.h> +#include <string.h> +#include <time.h> #include "RNA_define.h" #include "RNA_types.h" +#include "DNA_object_types.h" + +#include "BLO_sys_types.h" /* needed for intptr_t used in ED_mesh.h */ + +#include "ED_mesh.h" + #ifdef RNA_RUNTIME -#include "MEM_guardedalloc.h" +#include "BKE_main.h" +#include "BKE_global.h" +#include "BKE_context.h" +#include "BKE_report.h" +#include "BKE_object.h" +#include "BKE_mesh.h" +#include "BKE_DerivedMesh.h" #include "BKE_customdata.h" -#include "BKE_DerivedMesh.h" +#include "BKE_anim.h" +#include "BKE_depsgraph.h" #include "BKE_displist.h" -#include "BKE_object.h" +#include "BKE_font.h" #include "BKE_mball.h" -#include "BKE_main.h" + +#include "BLI_arithb.h" #include "DNA_mesh_types.h" -#include "DNA_curve_types.h" #include "DNA_scene_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_curve_types.h" +#include "DNA_modifier_types.h" + +#include "MEM_guardedalloc.h" -/* copied from init_render_mesh (render code) */ -static Mesh *rna_Object_create_render_mesh(Object *ob, bContext *C, Scene *scene) +/* copied from Mesh_getFromObject and adapted to RNA interface */ +/* settings: 0 - preview, 1 - render */ +static Mesh *rna_Object_create_mesh(Object *ob, bContext *C, ReportList *reports, int apply_modifiers, int settings) { - CustomDataMask mask = CD_MASK_BAREMESH|CD_MASK_MTFACE|CD_MASK_MCOL; + Mesh *tmpmesh; + Curve *tmpcu = NULL; Object *tmpobj = NULL; - DerivedMesh *dm; - Mesh *me; - - switch(ob->type) { + int render = settings, i; + int cage = !apply_modifiers; + Scene *sce = CTX_data_scene(C); + + /* perform the mesh extraction based on type */ + switch (ob->type) { case OB_FONT: case OB_CURVE: case OB_SURF: - { - int cage = 0; //XXX -todo - Curve *tmpcu = NULL; /* copies object and modifiers (but not the data) */ - tmpobj= copy_object( ob ); + tmpobj= copy_object(ob); tmpcu = (Curve *)tmpobj->data; tmpcu->id.us--; @@ -88,80 +109,321 @@ static Mesh *rna_Object_create_render_mesh(Object *ob, bContext *C, Scene *scene #endif /* get updated display list, and convert to a mesh */ - makeDispListCurveTypes( scene, tmpobj, 0 ); + makeDispListCurveTypes( sce, tmpobj, 0 ); nurbs_to_mesh( tmpobj ); - - /* nurbs_to_mesh changes the type tp a mesh, check it worked */ + + /* nurbs_to_mesh changes the type to a mesh, check it worked */ if (tmpobj->type != OB_MESH) { free_libblock_us( &(CTX_data_main(C)->object), tmpobj ); - printf("cant convert curve to mesh. Does the curve have any segments?" ); // XXX use report api + BKE_report(reports, RPT_ERROR, "cant convert curve to mesh. Does the curve have any segments?"); + return NULL; } - me = tmpobj->data; - free_libblock_us( &(CTX_data_main(C)->object), tmpobj ); - break; - } + tmpmesh = tmpobj->data; + free_libblock_us( &G.main->object, tmpobj ); + break; + case OB_MBALL: /* metaballs don't have modifiers, so just convert to mesh */ - ob = find_basis_mball(scene, ob); + ob = find_basis_mball( sce, ob ); /* todo, re-generatre for render-res */ - // metaball_polygonize(scene, ob) - me = add_mesh("Mesh"); - mball_to_mesh( &ob->disp, me ); + /* metaball_polygonize(scene, ob) */ + + tmpmesh = add_mesh("Mesh"); + mball_to_mesh( &ob->disp, tmpmesh ); + break; + + case OB_MESH: + /* copies object and modifiers (but not the data) */ + if (cage) { + /* copies the data */ + tmpmesh = copy_mesh( ob->data ); + /* if not getting the original caged mesh, get final derived mesh */ + } else { + /* Make a dummy mesh, saves copying */ + DerivedMesh *dm; + /* CustomDataMask mask = CD_MASK_BAREMESH|CD_MASK_MTFACE|CD_MASK_MCOL; */ + CustomDataMask mask = CD_MASK_MESH; /* this seems more suitable, exporter, + for example, needs CD_MASK_MDEFORMVERT */ + + /* Write the display mesh into the dummy mesh */ + if (render) + dm = mesh_create_derived_render( sce, ob, mask ); + else + dm = mesh_create_derived_view( sce, ob, mask ); + + tmpmesh = add_mesh( "Mesh" ); + DM_to_mesh( dm, tmpmesh ); + dm->release( dm ); + } + break; - case OB_MESH: - { - dm= mesh_create_derived_render(scene, ob, mask); - // dm= mesh_create_derived_view(scene, ob, mask); + default: + BKE_report(reports, RPT_ERROR, "Object does not have geometry data"); + return NULL; + } - if(!dm) - return NULL; + /* Copy materials to new mesh */ + switch (ob->type) { + case OB_SURF: + tmpmesh->totcol = tmpcu->totcol; + + /* free old material list (if it exists) and adjust user counts */ + if( tmpcu->mat ) { + for( i = tmpcu->totcol; i-- > 0; ) { + /* are we an object material or data based? */ + if (ob->colbits & 1<<i) + tmpmesh->mat[i] = ob->mat[i]; + else + tmpmesh->mat[i] = tmpcu->mat[i]; + + if (tmpmesh->mat[i]) + tmpmesh->mat[i]->id.us++; + } + } + break; + +#if 0 + /* Crashes when assigning the new material, not sure why */ + case OB_MBALL: + tmpmb = (MetaBall *)ob->data; + tmpmesh->totcol = tmpmb->totcol; + + /* free old material list (if it exists) and adjust user counts */ + if( tmpmb->mat ) { + for( i = tmpmb->totcol; i-- > 0; ) { + tmpmesh->mat[i] = tmpmb->mat[i]; /* CRASH HERE ??? */ + if (tmpmesh->mat[i]) { + tmpmb->mat[i]->id.us++; + } + } + } + break; +#endif - me= add_mesh("tmp_render_mesh"); - me->id.us--; /* we don't assign it to anything */ - DM_to_mesh(dm, me); - dm->release(dm); + case OB_MESH: + if (!cage) { + Mesh *origmesh= ob->data; + tmpmesh->flag= origmesh->flag; + tmpmesh->mat = MEM_dupallocN(origmesh->mat); + tmpmesh->totcol = origmesh->totcol; + tmpmesh->smoothresh= origmesh->smoothresh; + if( origmesh->mat ) { + for( i = origmesh->totcol; i-- > 0; ) { + /* are we an object material or data based? */ + if (ob->colbits & 1<<i) + tmpmesh->mat[i] = ob->mat[i]; + else + tmpmesh->mat[i] = origmesh->mat[i]; + if (tmpmesh->mat[i]) + tmpmesh->mat[i]->id.us++; + } + } + } break; + } /* end copy materials */ + + /* we don't assign it to anything */ + tmpmesh->id.us--; + + /* make sure materials get updated in objects */ + test_object_materials( ( ID * ) tmpmesh ); + + return tmpmesh; +} + +/* When no longer needed, duplilist should be freed with Object.free_duplilist */ +static void rna_Object_create_duplilist(Object *ob, bContext *C, ReportList *reports) +{ + if (!(ob->transflag & OB_DUPLI)) { + BKE_report(reports, RPT_ERROR, "Object does not have duplis."); + return; } - default: - return NULL; + + /* free duplilist if a user forgets to */ + if (ob->duplilist) { + BKE_reportf(reports, RPT_WARNING, "Object.dupli_list has not been freed."); + + free_object_duplilist(ob->duplilist); + ob->duplilist= NULL; + } + + ob->duplilist= object_duplilist(CTX_data_scene(C), ob); + + /* ob->duplilist should now be freed with Object.free_duplilist */ +} + +static void rna_Object_free_duplilist(Object *ob, ReportList *reports) +{ + if (ob->duplilist) { + free_object_duplilist(ob->duplilist); + ob->duplilist= NULL; } +} + +static bDeformGroup *rna_Object_add_vertex_group(Object *ob, char *group_name) +{ + return ED_vgroup_add_name(ob, group_name); +} +static void rna_Object_add_vertex_to_group(Object *ob, int vertex_index, bDeformGroup *def, float weight, int assignmode) +{ + /* creates dverts if needed */ + ED_vgroup_vert_add(ob, def, vertex_index, weight, assignmode); +} + +/* copied from old API Object.makeDisplayList (Object.c) */ +static void rna_Object_make_display_list(Object *ob, bContext *C) +{ + Scene *sce= CTX_data_scene(C); + + if (ob->type == OB_FONT) { + Curve *cu = ob->data; + freedisplist(&cu->disp); + BKE_text_to_curve(sce, ob, CU_LEFT); + } - { /* update the material */ - short i, *totcol =give_totcolp(ob); + DAG_id_flush_update(&ob->id, OB_RECALC_DATA); +} - /* free the current material list */ - if(me->mat) - MEM_freeN((void *)me->mat); +static Object *rna_Object_find_armature(Object *ob) +{ + Object *ob_arm = NULL; - me->mat= (Material **)MEM_callocN(sizeof(void *)*(*totcol), "matarray"); + if (ob->type != OB_MESH) return NULL; - for(i=0; i<*totcol; i++) { - Material *mat= give_current_material(ob, i+1); - if(mat) { - me->mat[i]= mat; - mat->id.us++; + if (ob->parent && ob->partype == PARSKEL && ob->parent->type == OB_ARMATURE) { + ob_arm = ob->parent; + } + else { + ModifierData *mod = (ModifierData*)ob->modifiers.first; + while (mod) { + if (mod->type == eModifierType_Armature) { + ob_arm = ((ArmatureModifierData*)mod)->object; } + + mod = mod->next; } } - return me; + return ob_arm; +} + +int rna_Object_is_visible(Object *ob, bContext *C) +{ + return ob->lay & CTX_data_scene(C)->lay; +} + +/* +static void rna_Mesh_assign_verts_to_group(Object *ob, bDeformGroup *group, int *indices, int totindex, float weight, int assignmode) +{ + if (ob->type != OB_MESH) { + BKE_report(reports, RPT_ERROR, "Object should be of MESH type."); + return; + } + + Mesh *me = (Mesh*)ob->data; + int group_index = get_defgroup_num(ob, group); + if (group_index == -1) { + BKE_report(reports, RPT_ERROR, "No deform groups assigned to mesh."); + return; + } + + if (assignmode != WEIGHT_REPLACE && assignmode != WEIGHT_ADD && assignmode != WEIGHT_SUBTRACT) { + BKE_report(reports, RPT_ERROR, "Bad assignment mode." ); + return; + } + + // makes a set of dVerts corresponding to the mVerts + if (!me->dvert) + create_dverts(&me->id); + + // loop list adding verts to group + for (i= 0; i < totindex; i++) { + if(i < 0 || i >= me->totvert) { + BKE_report(reports, RPT_ERROR, "Bad vertex index in list."); + return; + } + + add_vert_defnr(ob, group_index, i, weight, assignmode); + } } +*/ #else void RNA_api_object(StructRNA *srna) { FunctionRNA *func; - PropertyRNA *prop; + PropertyRNA *parm; + + static EnumPropertyItem mesh_type_items[] = { + {0, "PREVIEW", 0, "Preview", "Apply modifier preview settings."}, + {1, "RENDER", 0, "Render", "Apply modifier render settings."}, + {0, NULL, 0, NULL, NULL} + }; + + static EnumPropertyItem assign_mode_items[] = { + {WEIGHT_REPLACE, "REPLACE", 0, "Replace", "Replace."}, /* TODO: more meaningful descriptions */ + {WEIGHT_ADD, "ADD", 0, "Add", "Add."}, + {WEIGHT_SUBTRACT, "SUBTRACT", 0, "Subtract", "Subtract."}, + {0, NULL, 0, NULL, NULL} + }; + + /* mesh */ + func= RNA_def_function(srna, "create_mesh", "rna_Object_create_mesh"); + RNA_def_function_ui_description(func, "Create a Mesh datablock with modifiers applied."); + RNA_def_function_flag(func, FUNC_USE_CONTEXT|FUNC_USE_REPORTS); + parm= RNA_def_boolean(func, "apply_modifiers", 0, "", "Apply modifiers."); + RNA_def_property_flag(parm, PROP_REQUIRED); + parm= RNA_def_enum(func, "settings", mesh_type_items, 0, "", "Modifier settings to apply."); + RNA_def_property_flag(parm, PROP_REQUIRED); + parm= RNA_def_pointer(func, "mesh", "Mesh", "", "Mesh created from object, remove it if it is only used for export."); + RNA_def_function_return(func, parm); + + /* duplis */ + func= RNA_def_function(srna, "create_dupli_list", "rna_Object_create_duplilist"); + RNA_def_function_ui_description(func, "Create a list of dupli objects for this object, needs to be freed manually with free_dupli_list."); + RNA_def_function_flag(func, FUNC_USE_CONTEXT|FUNC_USE_REPORTS); + + func= RNA_def_function(srna, "free_dupli_list", "rna_Object_free_duplilist"); + RNA_def_function_ui_description(func, "Free the list of dupli objects."); + RNA_def_function_flag(func, FUNC_USE_REPORTS); + + /* vertex groups */ + func= RNA_def_function(srna, "add_vertex_group", "rna_Object_add_vertex_group"); + RNA_def_function_ui_description(func, "Add vertex group to object."); + parm= RNA_def_string(func, "name", "Group", 0, "", "Vertex group name."); /* optional */ + parm= RNA_def_pointer(func, "group", "VertexGroup", "", "New vertex group."); + RNA_def_function_return(func, parm); + + func= RNA_def_function(srna, "add_vertex_to_group", "rna_Object_add_vertex_to_group"); + RNA_def_function_ui_description(func, "Add vertex to a vertex group."); + parm= RNA_def_int(func, "vertex_index", 0, 0, 0, "", "Vertex index.", 0, 0); + RNA_def_property_flag(parm, PROP_REQUIRED); + parm= RNA_def_pointer(func, "group", "VertexGroup", "", "Vertex group to add vertex to."); + RNA_def_property_flag(parm, PROP_REQUIRED); + parm= RNA_def_float(func, "weight", 0, 0.0f, 1.0f, "", "Vertex weight.", 0.0f, 1.0f); + RNA_def_property_flag(parm, PROP_REQUIRED); + parm= RNA_def_enum(func, "type", assign_mode_items, 0, "", "Vertex assign mode."); + RNA_def_property_flag(parm, PROP_REQUIRED); + + /* Armature */ + func= RNA_def_function(srna, "find_armature", "rna_Object_find_armature"); + RNA_def_function_ui_description(func, "Find armature influencing this object as a parent or via a modifier."); + parm= RNA_def_pointer(func, "ob_arm", "Object", "", "Armature object influencing this object or NULL."); + RNA_def_function_return(func, parm); + + /* DAG */ + func= RNA_def_function(srna, "make_display_list", "rna_Object_make_display_list"); + RNA_def_function_ui_description(func, "Update object's display data."); /* XXX describe better */ + RNA_def_function_flag(func, FUNC_USE_CONTEXT); - func= RNA_def_function(srna, "create_render_mesh", "rna_Object_create_render_mesh"); - RNA_def_function_ui_description(func, "Create a Mesh datablock with all modifiers applied."); + /* View */ + func= RNA_def_function(srna, "is_visible", "rna_Object_is_visible"); + RNA_def_function_ui_description(func, "Determine if object is visible in active scene."); RNA_def_function_flag(func, FUNC_USE_CONTEXT); - prop= RNA_def_pointer(func, "scene", "Scene", "", ""); - RNA_def_property_flag(prop, PROP_REQUIRED); - prop= RNA_def_pointer(func, "mesh", "Mesh", "", "Mesh created from object, remove it if it is only used for export."); - RNA_def_function_return(func, prop); + parm= RNA_def_boolean(func, "is_visible", 0, "", "Object visibility."); + RNA_def_function_return(func, parm); } #endif diff --git a/source/blender/makesrna/intern/rna_object_force.c b/source/blender/makesrna/intern/rna_object_force.c index 3dfbfcccacf..1f0d01ce784 100644 --- a/source/blender/makesrna/intern/rna_object_force.c +++ b/source/blender/makesrna/intern/rna_object_force.c @@ -617,6 +617,12 @@ static void rna_def_collision(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Collision from Stack", "Pick collision object from modifier stack (softbody only)"); RNA_def_property_update(prop, 0, "rna_CollisionSettings_update"); */ + + prop= RNA_def_property(srna, "absorption", PROP_FLOAT, PROP_FACTOR); + RNA_def_property_range(prop, 0.0f, 1.0f); + RNA_def_property_ui_range(prop, 0.0f, 1.0f, 1, 2); + RNA_def_property_ui_text(prop, "Absorption", "How much of effector force gets lost during collision with this object (in percent)."); + RNA_def_property_update(prop, 0, "rna_CollisionSettings_update"); } static void rna_def_field(BlenderRNA *brna) diff --git a/source/blender/makesrna/intern/rna_pose.c b/source/blender/makesrna/intern/rna_pose.c index cb566fb473f..e76cd56af4e 100644 --- a/source/blender/makesrna/intern/rna_pose.c +++ b/source/blender/makesrna/intern/rna_pose.c @@ -23,6 +23,7 @@ */ #include <stdlib.h> +#include <string.h> #include "RNA_define.h" #include "RNA_types.h" @@ -39,8 +40,8 @@ #ifdef RNA_RUNTIME -#include <string.h> - +#include "BIK_api.h" +#include "BKE_action.h" #include "BLI_arithb.h" #include "DNA_userdef_types.h" @@ -49,8 +50,11 @@ #include "BKE_depsgraph.h" #include "BKE_idprop.h" +#include "ED_object.h" #include "ED_armature.h" +#include "MEM_guardedalloc.h" + static void rna_Pose_update(bContext *C, PointerRNA *ptr) { // XXX when to use this? ob->pose->flag |= (POSE_LOCKED|POSE_DO_UNLOCK); @@ -58,6 +62,15 @@ static void rna_Pose_update(bContext *C, PointerRNA *ptr) DAG_id_flush_update(ptr->id.data, OB_RECALC_DATA); } +static void rna_Pose_IK_update(bContext *C, PointerRNA *ptr) +{ + // XXX when to use this? ob->pose->flag |= (POSE_LOCKED|POSE_DO_UNLOCK); + Object *ob= ptr->id.data; + + DAG_id_flush_update(&ob->id, OB_RECALC_DATA); + BIK_clear_data(ob->pose); +} + static char *rna_PoseChannel_path(PointerRNA *ptr) { return BLI_sprintfN("pose.pose_channels[\"%s\"]", ((bPoseChannel*)ptr->data)->name); @@ -110,6 +123,38 @@ static IDProperty *rna_PoseChannel_idproperties(PointerRNA *ptr, int create) return pchan->prop; } +static void rna_Pose_ik_solver_set(struct PointerRNA *ptr, int value) +{ + bPose *pose= (bPose*)ptr->data; + + if (pose->iksolver != value) { + // the solver has changed, must clean any temporary structures + BIK_clear_data(pose); + if (pose->ikparam) { + MEM_freeN(pose->ikparam); + pose->ikparam = NULL; + } + pose->iksolver = value; + init_pose_ikparam(pose); + } +} + +static void rna_Pose_ik_solver_update(bContext *C, PointerRNA *ptr) +{ + Object *ob= ptr->id.data; + bPose *pose = ptr->data; + Scene *scene = CTX_data_scene(C); + + pose->flag |= POSE_RECALC; // checks & sorts pose channels + DAG_scene_sort(scene); + + update_pose_constraint_flags(pose); + + object_test_constraints(ob); + + DAG_id_flush_update(&ob->id, OB_RECALC_DATA|OB_RECALC_OB); +} + /* rotation - euler angles */ static void rna_PoseChannel_euler_rotation_get(PointerRNA *ptr, float *value) { @@ -236,6 +281,70 @@ static int rna_PoseChannel_has_ik_get(PointerRNA *ptr) return ED_pose_channel_in_IK_chain(ob, pchan); } +StructRNA *rna_IKParam_refine(PointerRNA *ptr) +{ + bIKParam *param = (bIKParam *)ptr->data; + + switch (param->iksolver) { + case IKSOLVER_ITASC: + return &RNA_Itasc; + default: + return &RNA_IKParam; + } +} + +PointerRNA rna_Pose_ikparam_get(struct PointerRNA *ptr) +{ + bPose *pose= (bPose*)ptr->data; + return rna_pointer_inherit_refine(ptr, &RNA_IKParam, pose->ikparam); +} + +static StructRNA *rna_Pose_ikparam_typef(PointerRNA *ptr) +{ + bPose *pose= (bPose*)ptr->data; + + switch (pose->iksolver) { + case IKSOLVER_ITASC: + return &RNA_Itasc; + default: + return &RNA_IKParam; + } +} + +static void rna_Itasc_update(bContext *C, PointerRNA *ptr) +{ + Object *ob = ptr->id.data; + bItasc *itasc = ptr->data; + + /* verify values */ + if (itasc->precision < 0.0001f) + itasc->precision = 0.0001f; + if (itasc->minstep < 0.001f) + itasc->minstep = 0.001f; + if (itasc->maxstep < itasc->minstep) + itasc->maxstep = itasc->minstep; + if (itasc->feedback < 0.01f) + itasc->feedback = 0.01f; + if (itasc->feedback > 100.f) + itasc->feedback = 100.f; + if (itasc->maxvel < 0.01f) + itasc->maxvel = 0.01f; + if (itasc->maxvel > 100.f) + itasc->maxvel = 100.f; + BIK_update_param(ob->pose); + + DAG_id_flush_update(&ob->id, OB_RECALC_DATA); +} + +static void rna_Itasc_update_rebuild(bContext *C, PointerRNA *ptr) +{ + Object *ob= ptr->id.data; + bPose *pose = ob->pose; + + pose->flag |= POSE_RECALC; // checks & sorts pose channels + rna_Itasc_update(C, ptr); +} + static PointerRNA rna_PoseChannel_bone_group_get(PointerRNA *ptr) { Object *ob= (Object*)ptr->id.data; @@ -438,6 +547,16 @@ static void rna_def_bone_group(BlenderRNA *brna) RNA_def_property_update(prop, NC_OBJECT|ND_POSE, "rna_Pose_update"); } +static EnumPropertyItem prop_iksolver_items[] = { + {IKSOLVER_LEGACY, "LEGACY", 0, "Legacy", "Original IK solver."}, + {IKSOLVER_ITASC, "ITASC", 0, "iTaSC", "Multi constraint, stateful IK solver."}, + {0, NULL, 0, NULL, NULL}}; + +static EnumPropertyItem prop_solver_items[] = { + {ITASC_SOLVER_SDLS, "SDLS", 0, "SDLS", "Selective Damped Least Square"}, + {ITASC_SOLVER_DLS, "DLS", 0, "DLS", "Damped Least Square with Numerical Filtering"}, + {0, NULL, 0, NULL, NULL}}; + static void rna_def_pose_channel(BlenderRNA *brna) { static EnumPropertyItem prop_rotmode_items[] = { @@ -470,7 +589,7 @@ static void rna_def_pose_channel(BlenderRNA *brna) RNA_def_property_string_funcs(prop, NULL, NULL, "rna_PoseChannel_name_set"); RNA_def_property_ui_text(prop, "Name", ""); RNA_def_struct_name_property(srna, prop); - + prop= RNA_def_property(srna, "selected", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "selectflag", BONE_SELECTED); RNA_def_property_ui_text(prop, "Selected", ""); @@ -480,13 +599,13 @@ static void rna_def_pose_channel(BlenderRNA *brna) RNA_def_property_int_sdna(prop, NULL, "pathsf"); RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_ui_text(prop, "Bone Paths Calculation Start Frame", "Starting frame of range of frames to use for Bone Path calculations."); - RNA_def_property_update(prop, NC_OBJECT|ND_POSE|ND_TRANSFORM, "rna_Pose_update"); + RNA_def_property_update(prop, NC_OBJECT|ND_POSE, "rna_Pose_update"); prop= RNA_def_property(srna, "path_end_frame", PROP_INT, PROP_TIME); RNA_def_property_int_sdna(prop, NULL, "pathef"); RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_ui_text(prop, "Bone Paths Calculation End Frame", "End frame of range of frames to use for Bone Path calculations."); - RNA_def_property_update(prop, NC_OBJECT|ND_POSE|ND_TRANSFORM, "rna_Pose_update"); + RNA_def_property_update(prop, NC_OBJECT|ND_POSE, "rna_Pose_update"); /* Relationships to other bones */ prop= RNA_def_property(srna, "bone", PROP_POINTER, PROP_NONE); @@ -547,21 +666,25 @@ static void rna_def_pose_channel(BlenderRNA *brna) RNA_def_property_update(prop, NC_OBJECT|ND_POSE, "rna_Pose_update"); /* These three matrix properties await an implementation of the PROP_MATRIX subtype, which currently doesn't exist. */ -/* prop= RNA_def_property(srna, "channel_matrix", PROP_FLOAT, PROP_MATRIX); - RNA_def_property_struct_type(prop, "chan_mat"); + prop= RNA_def_property(srna, "channel_matrix", PROP_FLOAT, PROP_MATRIX); + RNA_def_property_float_sdna(prop, NULL, "chan_mat"); + RNA_def_property_array(prop, 16); RNA_def_property_clear_flag(prop, PROP_EDITABLE); - RNA_def_property_ui_text(prop, "Channel Matrix", "4x4 matrix, before constraints.");*/ + RNA_def_property_ui_text(prop, "Channel Matrix", "4x4 matrix, before constraints."); /* kaito says this should be not user-editable; I disagree; power users should be able to force this in python; he's the boss. */ -/* prop= RNA_def_property(srna, "pose_matrix", PROP_FLOAT, PROP_MATRIX); - RNA_def_property_struct_type(prop, "pose_mat"); + prop= RNA_def_property(srna, "pose_matrix", PROP_FLOAT, PROP_MATRIX); + RNA_def_property_float_sdna(prop, NULL, "pose_mat"); + RNA_def_property_array(prop, 16); RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_ui_text(prop, "Pose Matrix", "Final 4x4 matrix for this channel."); + /* prop= RNA_def_property(srna, "constraint_inverse_matrix", PROP_FLOAT, PROP_MATRIX); RNA_def_property_struct_type(prop, "constinv"); RNA_def_property_clear_flag(prop, PROP_EDITABLE); - RNA_def_property_ui_text(prop, "Constraint Inverse Matrix", "4x4 matrix, defines transform from final position to unconstrained position."); */ + RNA_def_property_ui_text(prop, "Constraint Inverse Matrix", "4x4 matrix, defines transform from final position to unconstrained position."); + */ /* Head/Tail Coordinates (in Pose Space) - Automatically calculated... */ prop= RNA_def_property(srna, "pose_head", PROP_FLOAT, PROP_TRANSLATION); @@ -577,96 +700,118 @@ static void rna_def_pose_channel(BlenderRNA *brna) RNA_def_property_boolean_funcs(prop, "rna_PoseChannel_has_ik_get", NULL); RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_ui_text(prop, "Has IK", "Is part of an IK chain."); - RNA_def_property_update(prop, NC_OBJECT|ND_POSE, "rna_Pose_update"); + RNA_def_property_update(prop, NC_OBJECT|ND_POSE, "rna_Pose_IK_update"); prop= RNA_def_property(srna, "ik_dof_x", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_negative_sdna(prop, NULL, "ikflag", BONE_IK_NO_XDOF); RNA_def_property_ui_text(prop, "IK X DoF", "Allow movement around the X axis."); - RNA_def_property_update(prop, NC_OBJECT|ND_POSE, "rna_Pose_update"); + RNA_def_property_update(prop, NC_OBJECT|ND_POSE, "rna_Pose_IK_update"); prop= RNA_def_property(srna, "ik_dof_y", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_negative_sdna(prop, NULL, "ikflag", BONE_IK_NO_YDOF); RNA_def_property_ui_text(prop, "IK Y DoF", "Allow movement around the Y axis."); - RNA_def_property_update(prop, NC_OBJECT|ND_POSE, "rna_Pose_update"); + RNA_def_property_update(prop, NC_OBJECT|ND_POSE|ND_TRANSFORM, "rna_Pose_IK_update"); prop= RNA_def_property(srna, "ik_dof_z", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_negative_sdna(prop, NULL, "ikflag", BONE_IK_NO_ZDOF); RNA_def_property_ui_text(prop, "IK Z DoF", "Allow movement around the Z axis."); - RNA_def_property_update(prop, NC_OBJECT|ND_POSE, "rna_Pose_update"); + RNA_def_property_update(prop, NC_OBJECT|ND_POSE, "rna_Pose_IK_update"); prop= RNA_def_property(srna, "ik_limit_x", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "ikflag", BONE_IK_XLIMIT); RNA_def_property_ui_text(prop, "IK X Limit", "Limit movement around the X axis."); - RNA_def_property_update(prop, NC_OBJECT|ND_POSE, "rna_Pose_update"); + RNA_def_property_update(prop, NC_OBJECT|ND_POSE, "rna_Pose_IK_update"); prop= RNA_def_property(srna, "ik_limit_y", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "ikflag", BONE_IK_YLIMIT); RNA_def_property_ui_text(prop, "IK Y Limit", "Limit movement around the Y axis."); - RNA_def_property_update(prop, NC_OBJECT|ND_POSE, "rna_Pose_update"); + RNA_def_property_update(prop, NC_OBJECT|ND_POSE, "rna_Pose_IK_update"); prop= RNA_def_property(srna, "ik_limit_z", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "ikflag", BONE_IK_ZLIMIT); RNA_def_property_ui_text(prop, "IK Z Limit", "Limit movement around the Z axis."); - RNA_def_property_update(prop, NC_OBJECT|ND_POSE, "rna_Pose_update"); + RNA_def_property_update(prop, NC_OBJECT|ND_POSE, "rna_Pose_IK_update"); + + prop= RNA_def_property(srna, "ik_rot_control", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "ikflag", BONE_IK_ROTCTL); + RNA_def_property_ui_text(prop, "IK rot control", "Apply channel rotation as IK constraint"); + RNA_def_property_update(prop, NC_OBJECT|ND_POSE, "rna_Pose_IK_update"); + + prop= RNA_def_property(srna, "ik_lin_control", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "ikflag", BONE_IK_LINCTL); + RNA_def_property_ui_text(prop, "IK rot control", "Apply channel size as IK constraint if stretching is enabled"); + RNA_def_property_update(prop, NC_OBJECT|ND_POSE, "rna_Pose_IK_update"); prop= RNA_def_property(srna, "ik_min_x", PROP_FLOAT, PROP_ANGLE); RNA_def_property_float_sdna(prop, NULL, "limitmin[0]"); RNA_def_property_range(prop, -180.0f, 0.0f); RNA_def_property_ui_text(prop, "IK X Minimum", "Minimum angles for IK Limit"); - RNA_def_property_update(prop, NC_OBJECT|ND_POSE, "rna_Pose_update"); + RNA_def_property_update(prop, NC_OBJECT|ND_POSE, "rna_Pose_IK_update"); prop= RNA_def_property(srna, "ik_max_x", PROP_FLOAT, PROP_ANGLE); RNA_def_property_float_sdna(prop, NULL, "limitmax[0]"); RNA_def_property_range(prop, 0.0f, 180.0f); RNA_def_property_ui_text(prop, "IK X Maximum", "Maximum angles for IK Limit"); - RNA_def_property_update(prop, NC_OBJECT|ND_POSE, "rna_Pose_update"); + RNA_def_property_update(prop, NC_OBJECT|ND_POSE, "rna_Pose_IK_update"); prop= RNA_def_property(srna, "ik_min_y", PROP_FLOAT, PROP_ANGLE); RNA_def_property_float_sdna(prop, NULL, "limitmin[1]"); RNA_def_property_range(prop, -180.0f, 0.0f); RNA_def_property_ui_text(prop, "IK Y Minimum", "Minimum angles for IK Limit"); - RNA_def_property_update(prop, NC_OBJECT|ND_POSE, "rna_Pose_update"); + RNA_def_property_update(prop, NC_OBJECT|ND_POSE, "rna_Pose_IK_update"); prop= RNA_def_property(srna, "ik_max_y", PROP_FLOAT, PROP_ANGLE); RNA_def_property_float_sdna(prop, NULL, "limitmax[1]"); RNA_def_property_range(prop, 0.0f, 180.0f); RNA_def_property_ui_text(prop, "IK Y Maximum", "Maximum angles for IK Limit"); - RNA_def_property_update(prop, NC_OBJECT|ND_POSE, "rna_Pose_update"); + RNA_def_property_update(prop, NC_OBJECT|ND_POSE, "rna_Pose_IK_update"); prop= RNA_def_property(srna, "ik_min_z", PROP_FLOAT, PROP_ANGLE); RNA_def_property_float_sdna(prop, NULL, "limitmin[2]"); RNA_def_property_range(prop, -180.0f, 0.0f); RNA_def_property_ui_text(prop, "IK Z Minimum", "Minimum angles for IK Limit"); - RNA_def_property_update(prop, NC_OBJECT|ND_POSE, "rna_Pose_update"); + RNA_def_property_update(prop, NC_OBJECT|ND_POSE, "rna_Pose_IK_update"); prop= RNA_def_property(srna, "ik_max_z", PROP_FLOAT, PROP_ANGLE); RNA_def_property_float_sdna(prop, NULL, "limitmax[2]"); RNA_def_property_range(prop, 0.0f, 180.0f); RNA_def_property_ui_text(prop, "IK Z Maximum", "Maximum angles for IK Limit"); - RNA_def_property_update(prop, NC_OBJECT|ND_POSE, "rna_Pose_update"); + RNA_def_property_update(prop, NC_OBJECT|ND_POSE, "rna_Pose_IK_update"); prop= RNA_def_property(srna, "ik_stiffness_x", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "stiffness[0]"); RNA_def_property_range(prop, 0.0f, 0.99f); RNA_def_property_ui_text(prop, "IK X Stiffness", "IK stiffness around the X axis."); - RNA_def_property_update(prop, NC_OBJECT|ND_POSE, "rna_Pose_update"); + RNA_def_property_update(prop, NC_OBJECT|ND_POSE, "rna_Pose_IK_update"); prop= RNA_def_property(srna, "ik_stiffness_y", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "stiffness[1]"); RNA_def_property_range(prop, 0.0f, 0.99f); RNA_def_property_ui_text(prop, "IK Y Stiffness", "IK stiffness around the Y axis."); - RNA_def_property_update(prop, NC_OBJECT|ND_POSE, "rna_Pose_update"); + RNA_def_property_update(prop, NC_OBJECT|ND_POSE, "rna_Pose_IK_update"); prop= RNA_def_property(srna, "ik_stiffness_z", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "stiffness[2]"); RNA_def_property_range(prop, 0.0f, 0.99f); RNA_def_property_ui_text(prop, "IK Z Stiffness", "IK stiffness around the Z axis."); - RNA_def_property_update(prop, NC_OBJECT|ND_POSE, "rna_Pose_update"); + RNA_def_property_update(prop, NC_OBJECT|ND_POSE, "rna_Pose_IK_update"); prop= RNA_def_property(srna, "ik_stretch", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "ikstretch"); RNA_def_property_range(prop, 0.0f,1.0f); RNA_def_property_ui_text(prop, "IK Stretch", "Allow scaling of the bone for IK."); + RNA_def_property_update(prop, NC_OBJECT|ND_POSE, "rna_Pose_IK_update"); + + prop= RNA_def_property(srna, "ik_rot_weight", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "ikrotweight"); + RNA_def_property_range(prop, 0.0f,1.0f); + RNA_def_property_ui_text(prop, "IK Rot Weight", "Weight of rotation constraint for IK."); + RNA_def_property_update(prop, NC_OBJECT|ND_POSE, "rna_Pose_update"); + + prop= RNA_def_property(srna, "ik_lin_weight", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "iklinweight"); + RNA_def_property_range(prop, 0.0f,1.0f); + RNA_def_property_ui_text(prop, "IK Lin Weight", "Weight of scale constraint for IK."); RNA_def_property_update(prop, NC_OBJECT|ND_POSE, "rna_Pose_update"); /* custom bone shapes */ @@ -723,6 +868,113 @@ static void rna_def_pose_channel(BlenderRNA *brna) RNA_def_property_update(prop, NC_OBJECT|ND_POSE, "rna_Pose_update"); } +static void rna_def_pose_itasc(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + + srna= RNA_def_struct(brna, "Itasc", "IKParam"); + RNA_def_struct_sdna(srna, "bItasc"); + RNA_def_struct_ui_text(srna, "bItasc", "Parameters for the iTaSC IK solver."); + + prop= RNA_def_property(srna, "precision", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "precision"); + RNA_def_property_range(prop, 0.0f,0.1f); + RNA_def_property_ui_text(prop, "Precision", "Precision of convergence in case of reiteration."); + RNA_def_property_update(prop, NC_OBJECT|ND_POSE, "rna_Itasc_update"); + + prop= RNA_def_property(srna, "num_iter", PROP_INT, PROP_NONE); + RNA_def_property_int_sdna(prop, NULL, "numiter"); + RNA_def_property_range(prop, 1.f,1000.f); + RNA_def_property_ui_text(prop, "Iterations", "Maximum number of iterations for convergence in case of reiteration."); + RNA_def_property_update(prop, NC_OBJECT|ND_POSE, "rna_Itasc_update"); + + prop= RNA_def_property(srna, "num_step", PROP_INT, PROP_NONE); + RNA_def_property_int_sdna(prop, NULL, "numstep"); + RNA_def_property_range(prop, 1.f, 50.f); + RNA_def_property_ui_text(prop, "Num steps", "Divides the frame interval into this many steps."); + RNA_def_property_update(prop, NC_OBJECT|ND_POSE, "rna_Itasc_update"); + + prop= RNA_def_property(srna, "simulation", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", ITASC_SIMULATION); + RNA_def_property_ui_text(prop, "Simulation", "Simulation mode: solver is statefull, runs in real-time context and ignores actions and non-IK constraints (i.e. solver is in full charge of the IK chain)."); + RNA_def_property_update(prop, NC_OBJECT|ND_POSE, "rna_Itasc_update_rebuild"); + + prop= RNA_def_property(srna, "initial_reiteration", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", ITASC_INITIAL_REITERATION); + RNA_def_property_ui_text(prop, "Initial Reiteration", "Allow reiteration for initial frame."); + RNA_def_property_update(prop, NC_OBJECT|ND_POSE, "rna_Itasc_update"); + + prop= RNA_def_property(srna, "reiteration", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", ITASC_REITERATION); + RNA_def_property_ui_text(prop, "Reiteration", "Allow reiteration for all frames."); + RNA_def_property_update(prop, NC_OBJECT|ND_POSE, "rna_Itasc_update"); + + prop= RNA_def_property(srna, "auto_step", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", ITASC_AUTO_STEP); + RNA_def_property_ui_text(prop, "Auto step", "Automatically determine the optimal number of steps for best performance/accurary trade off."); + RNA_def_property_update(prop, NC_OBJECT|ND_POSE, "rna_Itasc_update"); + + prop= RNA_def_property(srna, "min_step", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "minstep"); + RNA_def_property_range(prop, 0.0f,0.1f); + RNA_def_property_ui_text(prop, "Min step", "Lower bound for timestep in second in case of automatic substeps."); + RNA_def_property_update(prop, NC_OBJECT|ND_POSE, "rna_Itasc_update"); + + prop= RNA_def_property(srna, "max_step", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "maxstep"); + RNA_def_property_range(prop, 0.0f,1.0f); + RNA_def_property_ui_text(prop, "Max step", "Higher bound for timestep in second in case of automatic substeps."); + RNA_def_property_update(prop, NC_OBJECT|ND_POSE, "rna_Itasc_update"); + + prop= RNA_def_property(srna, "feedback", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "feedback"); + RNA_def_property_range(prop, 0.0f,100.0f); + RNA_def_property_ui_text(prop, "Feedback", "Feedback coefficient for error correction. Average response time=1/feedback. Default=20."); + RNA_def_property_update(prop, NC_OBJECT|ND_POSE, "rna_Itasc_update"); + + prop= RNA_def_property(srna, "max_velocity", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "maxvel"); + RNA_def_property_range(prop, 0.0f,100.0f); + RNA_def_property_ui_text(prop, "Max Velocity", "Maximum joint velocity in rad/s. Default=50."); + RNA_def_property_update(prop, NC_OBJECT|ND_POSE, "rna_Itasc_update"); + + prop= RNA_def_property(srna, "solver", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "solver"); + RNA_def_property_enum_items(prop, prop_solver_items); + RNA_def_property_ui_text(prop, "Solver", "Solving method selection: Automatic damping or manual damping"); + RNA_def_property_update(prop, NC_OBJECT|ND_POSE, "rna_Itasc_update_rebuild"); + + prop= RNA_def_property(srna, "dampmax", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "dampmax"); + RNA_def_property_range(prop, 0.0f,1.0f); + RNA_def_property_ui_text(prop, "Damp", "Maximum damping coefficient when singular value is nearly 0. Higher values=more stability, less reactivity. Default=0.5"); + RNA_def_property_update(prop, NC_OBJECT|ND_POSE, "rna_Itasc_update"); + + prop= RNA_def_property(srna, "dampeps", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "dampeps"); + RNA_def_property_range(prop, 0.0f,1.0f); + RNA_def_property_ui_text(prop, "Epsilon", "Singular value under which damping is progressively applied. Higher values=more stability, less reactivity. Default=0.1"); + RNA_def_property_update(prop, NC_OBJECT|ND_POSE, "rna_Itasc_update"); +} + +static void rna_def_pose_ikparam(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + + srna= RNA_def_struct(brna, "IKParam", NULL); + RNA_def_struct_sdna(srna, "bIKParam"); + RNA_def_struct_ui_text(srna, "IKParam", "Base type for IK solver parameters."); + RNA_def_struct_refine_func(srna, "rna_IKParam_refine"); + + prop= RNA_def_property(srna, "ik_solver", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "iksolver"); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_enum_items(prop, prop_iksolver_items); + RNA_def_property_ui_text(prop, "IK Solver", "IK solver for which these parameters are defined, 0 for Legacy, 1 for iTaSC."); +} + static void rna_def_pose(BlenderRNA *brna) { StructRNA *srna; @@ -757,13 +1009,29 @@ static void rna_def_pose(BlenderRNA *brna) RNA_def_property_int_funcs(prop, "rna_Pose_active_bone_group_index_get", "rna_Pose_active_bone_group_index_set", "rna_Pose_active_bone_group_index_range"); RNA_def_property_ui_text(prop, "Active Bone Group Index", "Active index in bone groups array."); RNA_def_property_update(prop, NC_OBJECT|ND_POSE, "rna_Pose_update"); + + prop= RNA_def_property(srna, "ik_solver", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "iksolver"); + RNA_def_property_enum_funcs(prop, NULL, "rna_Pose_ik_solver_set", NULL); + RNA_def_property_enum_items(prop, prop_iksolver_items); + RNA_def_property_ui_text(prop, "IK Solver", "Selection of IK solver for IK chain, current choice is 0 for Legacy, 1 for iTaSC."); + RNA_def_property_update(prop, NC_OBJECT|ND_POSE, "rna_Pose_ik_solver_update"); + + prop= RNA_def_property(srna, "ik_param", PROP_POINTER, PROP_NONE); + RNA_def_property_struct_type(prop, "IKParam"); + RNA_def_property_pointer_funcs(prop, "rna_Pose_ikparam_get", NULL, "rna_Pose_ikparam_typef"); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_ui_text(prop, "IK Param", "Parameters for IK solver."); + + /* RNA_api_pose(srna); */ } void RNA_def_pose(BlenderRNA *brna) { rna_def_pose(brna); rna_def_pose_channel(brna); - + rna_def_pose_ikparam(brna); + rna_def_pose_itasc(brna); rna_def_bone_group(brna); } diff --git a/source/blender/makesrna/intern/rna_pose_api.c b/source/blender/makesrna/intern/rna_pose_api.c new file mode 100644 index 00000000000..40bb131b3f9 --- /dev/null +++ b/source/blender/makesrna/intern/rna_pose_api.c @@ -0,0 +1,56 @@ +/** + * $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) 2009 Blender Foundation. + * All rights reserved. + * + * + * Contributor(s): Blender Foundation + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <time.h> + +#include "RNA_define.h" +#include "RNA_types.h" + +#include "DNA_object_types.h" + +/* #include "BLO_sys_types.h" */ + +#ifdef RNA_RUNTIME + +/* #include "DNA_anim_types.h" */ +#include "DNA_action_types.h" /* bPose */ + +#else + +void RNA_api_pose(StructRNA *srna) +{ + /* FunctionRNA *func; */ + /* PropertyRNA *parm; */ + +} + +#endif + diff --git a/source/blender/makesrna/intern/rna_rna.c b/source/blender/makesrna/intern/rna_rna.c index 37a1c9fb186..8dd751cd26a 100644 --- a/source/blender/makesrna/intern/rna_rna.c +++ b/source/blender/makesrna/intern/rna_rna.c @@ -842,6 +842,7 @@ static void rna_def_property(BlenderRNA *brna) {PROP_DIRPATH, "DIRECTORY_PATH", 0, "Directory Path", ""}, {PROP_UNSIGNED, "UNSIGNED", 0, "Unsigned Number", ""}, {PROP_PERCENTAGE, "PERCENTAGE", 0, "Percentage", ""}, + {PROP_FACTOR, "FACTOR", 0, "Factor", ""}, {PROP_ANGLE, "ANGLE", 0, "Angle", ""}, {PROP_TIME, "TIME", 0, "Time", ""}, {PROP_DISTANCE, "DISTANCE", 0, "Distance", ""}, diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c index 08efa13d8f4..1d8ebdce369 100644 --- a/source/blender/makesrna/intern/rna_scene.c +++ b/source/blender/makesrna/intern/rna_scene.c @@ -523,7 +523,7 @@ static void rna_def_tool_settings(BlenderRNA *brna) RNA_def_property_enum_items(prop, mesh_select_mode_items); RNA_def_property_ui_text(prop, "Mesh Selection Mode", "Mesh selection and display mode."); - prop= RNA_def_property(srna, "vertex_group_weight", PROP_FLOAT, PROP_PERCENTAGE); + prop= RNA_def_property(srna, "vertex_group_weight", PROP_FLOAT, PROP_FACTOR); RNA_def_property_float_sdna(prop, NULL, "vgroup_weight"); RNA_def_property_ui_text(prop, "Vertex Group Weight", "Weight to assign in vertex groups."); } @@ -1512,6 +1512,19 @@ static void rna_def_scene_render_data(BlenderRNA *brna) RNA_def_property_boolean_sdna(prop, NULL, "ffcodecdata.flags", FFMPEG_MULTIPLEX_AUDIO); RNA_def_property_ui_text(prop, "Multiplex Audio", "Interleave audio with the output video"); RNA_def_property_update(prop, NC_SCENE|ND_RENDER_OPTIONS, NULL); + + prop= RNA_def_property(srna, "ffmpeg_audio_mixrate", PROP_INT, PROP_NONE); + RNA_def_property_int_sdna(prop, NULL, "ffcodecdata.audio_mixrate"); + RNA_def_property_range(prop, 8000, 192000); + RNA_def_property_ui_text(prop, "Samplerate", "Audio samplerate(samples/s)"); + RNA_def_property_update(prop, NC_SCENE|ND_RENDER_OPTIONS, NULL); + + prop= RNA_def_property(srna, "ffmpeg_audio_volume", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "ffcodecdata.audio_volume"); + RNA_def_property_range(prop, 0.0f, 1.0f); + RNA_def_property_ui_text(prop, "Volume", "Audio volume"); + RNA_def_property_update(prop, NC_SCENE|ND_RENDER_OPTIONS, NULL); + #endif prop= RNA_def_property(srna, "fps", PROP_INT, PROP_NONE); @@ -1583,11 +1596,6 @@ static void rna_def_scene_render_data(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Fields Still", "Disable the time difference between fields."); RNA_def_property_update(prop, NC_SCENE|ND_RENDER_OPTIONS, NULL); - prop= RNA_def_property(srna, "sync_audio", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "audio.flag", AUDIO_SYNC); - RNA_def_property_ui_text(prop, "Sync Audio", "Play back and sync with audio from Sequence Editor"); - RNA_def_property_update(prop, NC_SCENE, NULL); - prop= RNA_def_property(srna, "render_shadows", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "mode", R_SHADOW); RNA_def_property_ui_text(prop, "Render Shadows", "Calculate shadows while rendering."); @@ -1657,6 +1665,30 @@ static void rna_def_scene_render_data(BlenderRNA *brna) RNA_def_property_boolean_sdna(prop, NULL, "mode", R_BORDER); RNA_def_property_ui_text(prop, "Border", "Render a user-defined border region, within the frame size."); RNA_def_property_update(prop, NC_SCENE|ND_RENDER_OPTIONS, NULL); + + prop= RNA_def_property(srna, "border_min_x", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "border.xmin"); + RNA_def_property_range(prop, 0.0f, 1.0f); + RNA_def_property_ui_text(prop, "Border Minimum X", "Sets minimum X value to for the render border."); + RNA_def_property_update(prop, NC_SCENE|ND_RENDER_OPTIONS, NULL); + + prop= RNA_def_property(srna, "border_min_y", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "border.ymin"); + RNA_def_property_range(prop, 0.0f, 1.0f); + RNA_def_property_ui_text(prop, "Border Minimum Y", "Sets minimum Y value for the render border"); + RNA_def_property_update(prop, NC_SCENE|ND_RENDER_OPTIONS, NULL); + + prop= RNA_def_property(srna, "border_max_x", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "border.xmax"); + RNA_def_property_range(prop, 0.0f, 1.0f); + RNA_def_property_ui_text(prop, "Border Maximum X", "Sets maximum X value for the render border"); + RNA_def_property_update(prop, NC_SCENE|ND_RENDER_OPTIONS, NULL); + + prop= RNA_def_property(srna, "border_max_y", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "border.ymax"); + RNA_def_property_range(prop, 0.0f, 1.0f); + RNA_def_property_ui_text(prop, "Border Maximum Y", "Sets maximum Y value for the render border"); + RNA_def_property_update(prop, NC_SCENE|ND_RENDER_OPTIONS, NULL); prop= RNA_def_property(srna, "crop_to_border", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "mode", R_CROP); @@ -1907,6 +1939,16 @@ void RNA_def_scene(BlenderRNA *brna) PropertyRNA *prop; FunctionRNA *func; + static EnumPropertyItem audio_distance_model_items[] = { + {0, "NONE", 0, "None", "No distance attenuation."}, + {1, "INVERSE", 0, "Inverse", "Inverse distance model."}, + {2, "INVERSE_CLAMPED", 0, "Inverse Clamped", "Inverse distance model with clamping."}, + {3, "LINEAR", 0, "Linear", "Linear distance model."}, + {4, "LINEAR_CLAMPED", 0, "Linear Clamped", "Linear distance model with clamping."}, + {5, "EXPONENT", 0, "Exponent", "Exponent distance model."}, + {6, "EXPONENT_CLAMPED", 0, "Exponent Clamped", "Exponent distance model with clamping."}, + {0, NULL, 0, NULL, NULL}}; + /* Struct definition */ srna= RNA_def_struct(brna, "Scene", "ID"); RNA_def_struct_ui_text(srna, "Scene", "Scene consisting objects and defining time and render related settings."); @@ -1999,6 +2041,9 @@ void RNA_def_scene(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Stamp Note", "User define note for the render stamping."); RNA_def_property_update(prop, NC_SCENE|ND_RENDER_OPTIONS, NULL); + /* Animation Data (for Scene) */ + rna_def_animdata_common(srna); + /* Nodes (Compositing) */ prop= RNA_def_property(srna, "nodetree", PROP_POINTER, PROP_NONE); RNA_def_property_ui_text(prop, "Node Tree", "Compositing node tree."); @@ -2063,6 +2108,40 @@ void RNA_def_scene(BlenderRNA *brna) RNA_def_property_struct_type(prop, "TimelineMarker"); RNA_def_property_ui_text(prop, "Timeline Markers", "Markers used in all timelines for the current scene."); + /* Audio Settings */ + prop= RNA_def_property(srna, "mute_audio", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "audio.flag", AUDIO_MUTE); + RNA_def_property_ui_text(prop, "Audio Muted", "Play back of audio from Sequence Editor will be muted."); + RNA_def_property_update(prop, NC_SCENE, NULL); + + prop= RNA_def_property(srna, "sync_audio", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "audio.flag", AUDIO_SYNC); + RNA_def_property_ui_text(prop, "Audio Sync", "Play back and sync with audio from Sequence Editor."); + RNA_def_property_update(prop, NC_SCENE, NULL); + + prop= RNA_def_property(srna, "scrub_audio", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "audio.flag", AUDIO_SCRUB); + RNA_def_property_ui_text(prop, "Audio Scrubbing", "Play audio from Sequence Editor while scrubbing."); + RNA_def_property_update(prop, NC_SCENE, NULL); + + prop= RNA_def_property(srna, "speed_of_sound", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "audio.speed_of_sound"); + RNA_def_property_range(prop, 0.01f, FLT_MAX); + RNA_def_property_ui_text(prop, "Speed of Sound", "Speed of sound for doppler effect calculation."); + RNA_def_property_update(prop, NC_SCENE, NULL); + + prop= RNA_def_property(srna, "doppler_factor", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "audio.doppler_factor"); + RNA_def_property_range(prop, 0.0, FLT_MAX); + RNA_def_property_ui_text(prop, "Doppler Factor", "Pitch factor for doppler effect calculation."); + RNA_def_property_update(prop, NC_SCENE, NULL); + + prop= RNA_def_property(srna, "distance_model", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_bitflag_sdna(prop, NULL, "audio.distance_model"); + RNA_def_property_enum_items(prop, audio_distance_model_items); + RNA_def_property_ui_text(prop, "Distance Model", "Distance model for distance attenuation calculation."); + RNA_def_property_update(prop, NC_SCENE, NULL); + /* Game Settings */ prop= RNA_def_property(srna, "game_data", PROP_POINTER, PROP_NONE); RNA_def_property_flag(prop, PROP_NEVER_NULL); diff --git a/source/blender/makesrna/intern/rna_scene_api.c b/source/blender/makesrna/intern/rna_scene_api.c index 26047ab5dc3..40f2db6d4a4 100644 --- a/source/blender/makesrna/intern/rna_scene_api.c +++ b/source/blender/makesrna/intern/rna_scene_api.c @@ -1,5 +1,5 @@ /** - * $Id: + * $Id$ * * ***** BEGIN GPL LICENSE BLOCK ***** * @@ -21,7 +21,7 @@ * All rights reserved. * * - * Contributor(s): Joshua Leung + * Contributor(s): Joshua Leung, Arystanbek Dyussenov * * ***** END GPL LICENSE BLOCK ***** */ @@ -40,9 +40,49 @@ #ifdef RNA_RUNTIME #include "BKE_animsys.h" +#include "BKE_scene.h" +#include "BKE_depsgraph.h" -// Scene API stuff from kazanbas branch here... +#include "ED_object.h" +#include "WM_api.h" + +static void rna_Scene_add_object(Scene *sce, ReportList *reports, Object *ob) +{ + Base *base= object_in_scene(ob, sce); + if (base) { + BKE_report(reports, RPT_ERROR, "Object is already in this scene."); + return; + } + base= scene_add_base(sce, ob); + ob->id.us++; + + /* this is similar to what object_add_type and add_object do */ + ob->lay= base->lay= sce->lay; + ob->recalc |= OB_RECALC; + + DAG_scene_sort(sce); +} + +static void rna_Scene_remove_object(Scene *sce, ReportList *reports, Object *ob) +{ + Base *base= object_in_scene(ob, sce); + if (!base) { + BKE_report(reports, RPT_ERROR, "Object is not in this scene."); + return; + } + /* as long as ED_base_object_free_and_unlink calls free_libblock_us, we don't have to decrement ob->id.us */ + ED_base_object_free_and_unlink(sce, base); +} + +static void rna_Scene_set_frame(Scene *sce, bContext *C, int frame) +{ + sce->r.cfra= frame; + CLAMP(sce->r.cfra, MINAFRAME, MAXFRAME); + scene_update_for_newframe(sce, (1<<20) - 1); + + WM_event_add_notifier(C, NC_SCENE|ND_FRAME, sce); +} static KeyingSet *rna_Scene_add_keying_set(Scene *sce, ReportList *reports, char name[], int absolute, int insertkey_needed, int insertkey_visual) @@ -77,21 +117,37 @@ void RNA_api_scene(StructRNA *srna) { FunctionRNA *func; PropertyRNA *parm; - - // Scene API stuff from kazanbas branch here... - + + func= RNA_def_function(srna, "add_object", "rna_Scene_add_object"); + RNA_def_function_ui_description(func, "Add object to scene."); + RNA_def_function_flag(func, FUNC_USE_REPORTS); + parm= RNA_def_pointer(func, "object", "Object", "", "Object to add to scene."); + RNA_def_property_flag(parm, PROP_REQUIRED); + + func= RNA_def_function(srna, "remove_object", "rna_Scene_remove_object"); + RNA_def_function_ui_description(func, "Remove object from scene."); + RNA_def_function_flag(func, FUNC_USE_REPORTS); + parm= RNA_def_pointer(func, "object", "Object", "", "Object to remove from scene."); + RNA_def_property_flag(parm, PROP_REQUIRED); + + func= RNA_def_function(srna, "set_frame", "rna_Scene_set_frame"); + RNA_def_function_flag(func, FUNC_USE_CONTEXT); + RNA_def_function_ui_description(func, "Set scene frame updating all objects immediately."); + parm= RNA_def_int(func, "frame", 0, MINAFRAME, MAXFRAME, "", "Frame number to set.", MINAFRAME, MAXFRAME); + RNA_def_property_flag(parm, PROP_REQUIRED); + /* Add Keying Set */ func= RNA_def_function(srna, "add_keying_set", "rna_Scene_add_keying_set"); RNA_def_function_ui_description(func, "Add a new Keying Set to Scene."); RNA_def_function_flag(func, FUNC_USE_REPORTS); - /* returns the new KeyingSet */ + /* returns the new KeyingSet */ parm= RNA_def_pointer(func, "keyingset", "KeyingSet", "", "Newly created Keying Set."); - RNA_def_function_return(func, parm); - /* name */ + RNA_def_function_return(func, parm); + /* name */ RNA_def_string(func, "name", "KeyingSet", 64, "Name", "Name of Keying Set"); - /* flags */ + /* flags */ RNA_def_boolean(func, "absolute", 1, "Absolute", "Keying Set defines specific paths/settings to be keyframed (i.e. is not reliant on context info)"); - /* keying flags */ + /* keying flags */ RNA_def_boolean(func, "insertkey_needed", 0, "Insert Keyframes - Only Needed", "Only insert keyframes where they're needed in the relevant F-Curves."); RNA_def_boolean(func, "insertkey_visual", 0, "Insert Keyframes - Visual", "Insert keyframes based on 'visual transforms'."); } diff --git a/source/blender/makesrna/intern/rna_sensor.c b/source/blender/makesrna/intern/rna_sensor.c index a5d76fdb039..1003af6d4d1 100644 --- a/source/blender/makesrna/intern/rna_sensor.c +++ b/source/blender/makesrna/intern/rna_sensor.c @@ -48,6 +48,8 @@ static StructRNA* rna_Sensor_refine(struct PointerRNA *ptr) return &RNA_KeyboardSensor; case SENS_PROPERTY: return &RNA_PropertySensor; + case SENS_ARMATURE: + return &RNA_ArmatureSensor; case SENS_MOUSE: return &RNA_MouseSensor; case SENS_COLLISION: @@ -92,6 +94,7 @@ static void rna_def_sensor(BlenderRNA *brna) {SENS_JOYSTICK, "JOYSTICK", 0, "joystick", ""}, {SENS_ACTUATOR, "ACTUATOR", 0, "Actuator", ""}, {SENS_DELAY, "DELAY", 0, "Delay", ""}, + {SENS_ARMATURE, "ARMATURE", 0, "Armature", ""}, {0, NULL, 0, NULL, NULL}}; srna= RNA_def_struct(brna, "Sensor", NULL); @@ -278,6 +281,40 @@ static void rna_def_property_sensor(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Maximum Value", "Specify maximum value in Interval type."); } +static void rna_def_armature_sensor(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + static EnumPropertyItem prop_type_items[] ={ + {SENS_ARM_STATE_CHANGED, "STATECHG", 0, "State Changed", ""}, + {SENS_ARM_LIN_ERROR_BELOW, "LINERRORBELOW", 0, "Lin error below", ""}, + {SENS_ARM_LIN_ERROR_ABOVE, "LINERRORABOVE", 0, "Lin error above", ""}, + {SENS_ARM_ROT_ERROR_BELOW, "ROTERRORBELOW", 0, "Rot error below", ""}, + {SENS_ARM_ROT_ERROR_ABOVE, "ROTERRORBELOW", 0, "Rot error above", ""}, + {0, NULL, 0, NULL, NULL}}; + + srna= RNA_def_struct(brna, "ArmatureSensor", "Sensor"); + RNA_def_struct_ui_text(srna, "Armature Sensor", "Sensor to detect values and changes in values of IK solver."); + RNA_def_struct_sdna_from(srna, "bArmatureSensor", "data"); + + prop= RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "type"); + RNA_def_property_enum_items(prop, prop_type_items); + RNA_def_property_ui_text(prop, "Test Type", "Type of value and test."); + + prop= RNA_def_property(srna, "channel_name", PROP_STRING, PROP_NONE); + RNA_def_property_string_sdna(prop, NULL, "posechannel"); + RNA_def_property_ui_text(prop, "Bone name", "Identify the bone to check value from"); + + prop= RNA_def_property(srna, "constraint_name", PROP_STRING, PROP_NONE); + RNA_def_property_string_sdna(prop, NULL, "constraint"); + RNA_def_property_ui_text(prop, "Constraint name", "Identify the bone constraint to check value from."); + + prop= RNA_def_property(srna, "value", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "value"); + RNA_def_property_ui_text(prop, "Compare Value", "Specify value to be used in comparison."); +} + static void rna_def_actuator_sensor(BlenderRNA *brna) { StructRNA *srna; @@ -531,6 +568,7 @@ void RNA_def_sensor(BlenderRNA *brna) rna_def_touch_sensor(brna); rna_def_keyboard_sensor(brna); rna_def_property_sensor(brna); + rna_def_armature_sensor(brna); rna_def_actuator_sensor(brna); rna_def_delay_sensor(brna); rna_def_collision_sensor(brna); diff --git a/source/blender/makesrna/intern/rna_sequence.c b/source/blender/makesrna/intern/rna_sequence.c index 4e12aab853e..9404fb775c3 100644 --- a/source/blender/makesrna/intern/rna_sequence.c +++ b/source/blender/makesrna/intern/rna_sequence.c @@ -228,7 +228,15 @@ static char *rna_Sequence_path(PointerRNA *ptr) /* sequencer data comes from scene... * TODO: would be nice to make SequenceEditor data a datablock of its own (for shorter paths) */ - return BLI_sprintfN("sequence_editor.sequences[\"%s\"]", seq->name+2); + if (seq->name+2) + return BLI_sprintfN("sequence_editor.sequences[\"%s\"]", seq->name+2); + else { + /* compromise for the frequent sitation when strips don't have names... */ + Scene *sce= (Scene*)ptr->id.data; + Editing *ed= seq_give_editing(sce, FALSE); + + return BLI_sprintfN("sequence_editor.sequences[%d]", BLI_findindex(&ed->seqbase, seq)); + } } static PointerRNA rna_SequenceEdtior_meta_stack_get(CollectionPropertyIterator *iter) @@ -239,6 +247,35 @@ static PointerRNA rna_SequenceEdtior_meta_stack_get(CollectionPropertyIterator * return rna_pointer_inherit_refine(&iter->parent, &RNA_Sequence, ms->parseq); } +static void rna_MovieSequence_filename_set(PointerRNA *ptr, const char *value) +{ + Sequence *seq= (Sequence*)(ptr->data); + char dir[FILE_MAX], name[FILE_MAX]; + + BLI_split_dirfile_basic(value, dir, name); + BLI_strncpy(seq->strip->dir, dir, sizeof(seq->strip->dir)); + BLI_strncpy(seq->strip->stripdata->name, name, sizeof(seq->strip->stripdata->name)); +} + +static void rna_SoundSequence_filename_set(PointerRNA *ptr, const char *value) +{ + Sequence *seq= (Sequence*)(ptr->data); + char dir[FILE_MAX], name[FILE_MAX]; + + BLI_split_dirfile_basic(value, dir, name); + BLI_strncpy(seq->strip->dir, dir, sizeof(seq->strip->dir)); + BLI_strncpy(seq->strip->stripdata->name, name, sizeof(seq->strip->stripdata->name)); +} + +static void rna_SequenceElement_filename_set(PointerRNA *ptr, const char *value) +{ + StripElem *elem= (StripElem*)(ptr->data); + char name[FILE_MAX]; + + BLI_split_dirfile_basic(value, NULL, name); + BLI_strncpy(elem->name, name, sizeof(elem->name)); +} + #else static void rna_def_strip_element(BlenderRNA *brna) @@ -253,6 +290,7 @@ static void rna_def_strip_element(BlenderRNA *brna) prop= RNA_def_property(srna, "filename", PROP_STRING, PROP_FILEPATH); RNA_def_property_string_sdna(prop, NULL, "name"); RNA_def_property_ui_text(prop, "Filename", ""); + RNA_def_property_string_funcs(prop, NULL, NULL, "rna_SequenceElement_filename_set"); } static void rna_def_strip_crop(BlenderRNA *brna) @@ -490,6 +528,7 @@ static void rna_def_sequence(BlenderRNA *brna) prop= RNA_def_property(srna, "channel", PROP_INT, PROP_UNSIGNED); RNA_def_property_int_sdna(prop, NULL, "machine"); + RNA_def_property_range(prop, 0, MAXSEQ-1); RNA_def_property_ui_text(prop, "Channel", "Y position of the sequence strip."); RNA_def_property_int_funcs(prop, NULL, "rna_SequenceEditor_channel_set",NULL); // overlap test RNA_def_property_update(prop, NC_SCENE|ND_SEQUENCER, NULL); @@ -736,6 +775,7 @@ static void rna_def_movie(BlenderRNA *brna) prop= RNA_def_property(srna, "filename", PROP_STRING, PROP_FILEPATH); RNA_def_property_string_sdna(prop, NULL, "strip->stripdata->name"); RNA_def_property_ui_text(prop, "Filename", ""); + RNA_def_property_string_funcs(prop, NULL, NULL, "rna_MovieSequence_filename_set"); prop= RNA_def_property(srna, "directory", PROP_STRING, PROP_DIRPATH); RNA_def_property_string_sdna(prop, NULL, "strip->dir"); @@ -762,6 +802,7 @@ static void rna_def_sound(BlenderRNA *brna) prop= RNA_def_property(srna, "filename", PROP_STRING, PROP_FILEPATH); RNA_def_property_string_sdna(prop, NULL, "strip->stripdata->name"); RNA_def_property_ui_text(prop, "Filename", ""); + RNA_def_property_string_funcs(prop, NULL, NULL, "rna_SoundSequence_filename_set"); prop= RNA_def_property(srna, "directory", PROP_STRING, PROP_DIRPATH); RNA_def_property_string_sdna(prop, NULL, "strip->dir"); diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c index 30c5d4988b3..df956670eb3 100644 --- a/source/blender/makesrna/intern/rna_space.c +++ b/source/blender/makesrna/intern/rna_space.c @@ -602,11 +602,9 @@ static void rna_def_space_3dview(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Viewport Shading", "Method to display/shade objects in the 3D View."); RNA_def_property_update(prop, NC_SPACE|ND_SPACE_VIEW3D, NULL); - prop= RNA_def_property(srna, "localview", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "localview", 0); - RNA_def_property_clear_flag(prop, PROP_EDITABLE); + prop= RNA_def_property(srna, "local_view", PROP_POINTER, PROP_NONE); + RNA_def_property_pointer_sdna(prop, NULL, "localvd"); RNA_def_property_ui_text(prop, "Local View", "Display an isolated sub-set of objects, apart from the scene visibility."); - RNA_def_property_update(prop, NC_SPACE|ND_SPACE_VIEW3D, NULL); prop= RNA_def_property(srna, "lens", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "lens"); @@ -747,10 +745,11 @@ static void rna_def_space_buttons(BlenderRNA *brna) {BCONTEXT_SCENE, "SCENE", ICON_SCENE, "Scene", "Scene"}, {BCONTEXT_WORLD, "WORLD", ICON_WORLD, "World", "World"}, {BCONTEXT_OBJECT, "OBJECT", ICON_OBJECT_DATA, "Object", "Object"}, - {BCONTEXT_CONSTRAINT, "CONSTRAINT", ICON_CONSTRAINT, "Constraint", "Constraint"}, - {BCONTEXT_MODIFIER, "MODIFIER", ICON_MODIFIER, "Modifier", "Modifier"}, + {BCONTEXT_CONSTRAINT, "CONSTRAINT", ICON_CONSTRAINT, "Constraints", "Constraints"}, + {BCONTEXT_MODIFIER, "MODIFIER", ICON_MODIFIER, "Modifiers", "Modifiers"}, {BCONTEXT_DATA, "DATA", 0, "Data", "Data"}, {BCONTEXT_BONE, "BONE", ICON_BONE_DATA, "Bone", "Bone"}, + {BCONTEXT_BONE_CONSTRAINT, "BONE_CONSTRAINT", ICON_CONSTRAINT, "Bone Constraints", "Bone Constraints"}, {BCONTEXT_MATERIAL, "MATERIAL", ICON_MATERIAL, "Material", "Material"}, {BCONTEXT_TEXTURE, "TEXTURE", ICON_TEXTURE, "Texture", "Texture"}, {BCONTEXT_PARTICLE, "PARTICLE", ICON_PARTICLES, "Particle", "Particle"}, @@ -1238,6 +1237,11 @@ static void rna_def_space_time(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Sequencer Windows", ""); RNA_def_property_update(prop, NC_SPACE|ND_SPACE_TIME, "rna_SpaceTime_redraw_update"); + prop= RNA_def_property(srna, "play_nodes", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "redraws", TIME_NODES); + RNA_def_property_ui_text(prop, "Node Windows", ""); + RNA_def_property_update(prop, NC_SPACE|ND_SPACE_TIME, "rna_SpaceTime_redraw_update"); + /* Other options */ prop= RNA_def_property(srna, "continue_physics", PROP_BOOLEAN, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c index b9c5739e7eb..e9fcb299c53 100644 --- a/source/blender/makesrna/intern/rna_userdef.c +++ b/source/blender/makesrna/intern/rna_userdef.c @@ -316,7 +316,7 @@ static void rna_def_userdef_theme_ui_wcol_state(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Driven Selected", ""); RNA_def_property_update(prop, 0, "rna_userdef_update"); - prop= RNA_def_property(srna, "blend", PROP_FLOAT, PROP_PERCENTAGE); + prop= RNA_def_property(srna, "blend", PROP_FLOAT, PROP_FACTOR); RNA_def_property_ui_text(prop, "Blend", ""); RNA_def_property_update(prop, 0, "rna_userdef_update"); } diff --git a/source/blender/makesrna/intern/rna_wm.c b/source/blender/makesrna/intern/rna_wm.c index fff51ad8ade..0dd9e3aed42 100644 --- a/source/blender/makesrna/intern/rna_wm.c +++ b/source/blender/makesrna/intern/rna_wm.c @@ -46,6 +46,8 @@ EnumPropertyItem event_type_items[] = { {LEFTMOUSE, "LEFTMOUSE", 0, "Left Mouse", ""}, {MIDDLEMOUSE, "MIDDLEMOUSE", 0, "Middle Mouse", ""}, {RIGHTMOUSE, "RIGHTMOUSE", 0, "Right Mouse", ""}, + {BUTTON4MOUSE, "BUTTON4MOUSE", 0, "Button4 Mouse", ""}, + {BUTTON5MOUSE, "BUTTON5MOUSE", 0, "Button5 Mouse", ""}, {ACTIONMOUSE, "ACTIONMOUSE", 0, "Action Mouse", ""}, {SELECTMOUSE, "SELECTMOUSE", 0, "Select Mouse", ""}, diff --git a/source/blender/python/intern/bpy_interface.c b/source/blender/python/intern/bpy_interface.c index c8b05237072..10cf59d49a7 100644 --- a/source/blender/python/intern/bpy_interface.c +++ b/source/blender/python/intern/bpy_interface.c @@ -235,26 +235,10 @@ static PyObject *CreateGlobalDictionary( bContext *C ) return dict; } -/* Use this so we can include our own python bundle */ -#if 0 -wchar_t* Py_GetPath(void) -{ - int i; - static wchar_t py_path[FILE_MAXDIR] = L""; - char *dirname= BLI_gethome_folder("python"); - if(dirname) { - i= mbstowcs(py_path, dirname, FILE_MAXDIR); - printf("py path %s, %d\n", dirname, i); - } - return py_path; -} -#endif - - /* must be called before Py_Initialize */ void BPY_start_python_path(void) { - char *py_path_bundle= BLI_gethome_folder("python"); + char *py_path_bundle= BLI_gethome_folder("python", BLI_GETHOME_ALL); if(py_path_bundle==NULL) return; @@ -311,6 +295,11 @@ void BPY_start_python( int argc, char **argv ) PyObject *d = PyEval_GetBuiltins( ); PyDict_SetItemString(d, "reload", item=PyCFunction_New(bpy_reload_meth, NULL)); Py_DECREF(item); PyDict_SetItemString(d, "__import__", item=PyCFunction_New(bpy_import_meth, NULL)); Py_DECREF(item); + + /* a bit nasty but this prevents help() and input() from locking blender + * Ideally we could have some way for the console to replace sys.stdin but + * python would lock blender while waiting for a return value, not easy :| */ + PySys_SetObject("stdin", Py_None); } pyrna_alloc_types(); @@ -591,8 +580,9 @@ void BPY_run_ui_scripts(bContext *C, int reload) char *file_extension; char *dirname; char path[FILE_MAX]; - char *dirs[] = {"ui", "io", NULL}; - int a, err; + char *dirs[] = {"scripts/ui", "scripts/io", NULL}; + int path_flags[] = {BLI_GETHOME_LOCAL|BLI_GETHOME_SYSTEM, BLI_GETHOME_USER}; /* SYSTEM / NON-SYSTEM */ + int a, err, flag_iter; PyGILState_STATE gilstate; PyObject *sys_path; @@ -602,56 +592,60 @@ void BPY_run_ui_scripts(bContext *C, int reload) sys_path= PySys_GetObject("path"); /* borrow */ PyList_Insert(sys_path, 0, Py_None); /* place holder, resizes the list */ - for(a=0; dirs[a]; a++) { - dirname= BLI_gethome_folder(dirs[a]); + /* Scan system scripts first, then local/user */ + for(flag_iter=0; flag_iter < sizeof(path_flags)/sizeof(int); flag_iter++) { + + for(a=0; dirs[a]; a++) { + dirname= BLI_gethome_folder(dirs[a], path_flags[flag_iter]); - if(!dirname) - continue; + if(!dirname) + continue; - dir = opendir(dirname); + dir = opendir(dirname); - if(!dir) - continue; - - /* set the first dir in the sys.path for fast importing of modules */ - PyList_SetItem(sys_path, 0, PyUnicode_FromString(dirname)); /* steals the ref */ + if(!dir) + continue; - while((de = readdir(dir)) != NULL) { - /* We could stat the file but easier just to let python - * import it and complain if theres a problem */ - err = 0; - - if (de->d_name[0] == '.') { - /* do nothing, probably .svn */ - } - else if ((file_extension = strstr(de->d_name, ".py"))) { - /* normal py files? */ - if(file_extension && file_extension[3] == '\0') { - de->d_name[(file_extension - de->d_name)] = '\0'; - err= bpy_import_module(de->d_name, reload); + /* set the first dir in the sys.path for fast importing of modules */ + PyList_SetItem(sys_path, 0, PyUnicode_FromString(dirname)); /* steals the ref */ + + while((de = readdir(dir)) != NULL) { + /* We could stat the file but easier just to let python + * import it and complain if theres a problem */ + err = 0; + + if (de->d_name[0] == '.') { + /* do nothing, probably .svn */ + } + else if ((file_extension = strstr(de->d_name, ".py"))) { + /* normal py files? */ + if(file_extension && file_extension[3] == '\0') { + de->d_name[(file_extension - de->d_name)] = '\0'; + err= bpy_import_module(de->d_name, reload); + } } - } #ifndef __linux__ - else if( BLI_join_dirfile(path, dirname, de->d_name), S_ISDIR(BLI_exist(path))) { + else if( BLI_join_dirfile(path, dirname, de->d_name), S_ISDIR(BLI_exist(path))) { #else - else if(de->d_type==DT_DIR) { - BLI_join_dirfile(path, dirname, de->d_name); + else if(de->d_type==DT_DIR) { + BLI_join_dirfile(path, dirname, de->d_name); #endif - /* support packages */ - BLI_join_dirfile(path, path, "__init__.py"); + /* support packages */ + BLI_join_dirfile(path, path, "__init__.py"); - if(BLI_exists(path)) { - err= bpy_import_module(de->d_name, reload); + if(BLI_exists(path)) { + err= bpy_import_module(de->d_name, reload); + } } - } - if(err==-1) { - BPy_errors_to_report(NULL); - fprintf(stderr, "unable to import %s/%s\n", dirname, de->d_name); + if(err==-1) { + BPy_errors_to_report(NULL); + fprintf(stderr, "unable to import %s/%s\n", dirname, de->d_name); + } } - } - closedir(dir); + closedir(dir); + } } PyList_SetSlice(sys_path, 0, 1, NULL); /* remove the first item */ diff --git a/source/blender/python/intern/bpy_operator.c b/source/blender/python/intern/bpy_operator.c index f2e2dd77e6d..301204d3e2b 100644 --- a/source/blender/python/intern/bpy_operator.c +++ b/source/blender/python/intern/bpy_operator.c @@ -89,6 +89,16 @@ static PyObject *pyop_call( PyObject * self, PyObject * args) if(BPy_reports_to_error(reports)) error_val = -1; + /* operator output is nice to have in the terminal/console too */ + if(reports->list.first) { + char *report_str= BKE_reports_string(reports, 0); /* all reports */ + + if(report_str) { + PySys_WriteStdout(report_str); + MEM_freeN(report_str); + } + } + BKE_reports_clear(reports); if ((reports->flag & RPT_FREE) == 0) { diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c index 50e32f34594..1f800be266b 100644 --- a/source/blender/python/intern/bpy_rna.c +++ b/source/blender/python/intern/bpy_rna.c @@ -345,6 +345,27 @@ static char *pyrna_enum_as_string(PointerRNA *ptr, PropertyRNA *prop) return result; } +static int pyrna_string_to_enum(PyObject *item, PointerRNA *ptr, PropertyRNA *prop, int *val, const char *error_prefix) +{ + char *param= _PyUnicode_AsString(item); + + if (param==NULL) { + char *enum_str= pyrna_enum_as_string(ptr, prop); + PyErr_Format(PyExc_TypeError, "%.200s expected a string enum type in (%.200s)", error_prefix, enum_str); + MEM_freeN(enum_str); + return 0; + } else { + if (!RNA_property_enum_value(BPy_GetContext(), ptr, prop, param, val)) { + char *enum_str= pyrna_enum_as_string(ptr, prop); + PyErr_Format(PyExc_TypeError, "%.200s enum \"%.200s\" not found in (%.200s)", error_prefix, param, enum_str); + MEM_freeN(enum_str); + return 0; + } + } + + return 1; +} + PyObject * pyrna_prop_to_py(PointerRNA *ptr, PropertyRNA *prop) { PyObject *ret; @@ -603,25 +624,34 @@ int pyrna_py_to_prop(PointerRNA *ptr, PropertyRNA *prop, void *data, PyObject *v } case PROP_ENUM: { - char *param = _PyUnicode_AsString(value); - - if (param==NULL) { + int val, i; + + if (PyUnicode_Check(value)) { + if (!pyrna_string_to_enum(value, ptr, prop, &val, error_prefix)) + return -1; + } + else if (PyTuple_Check(value)) { + /* tuple of enum items, concatenate all values with OR */ + val= 0; + for (i= 0; i < PyTuple_Size(value); i++) { + int tmpval; + + /* PyTuple_GET_ITEM returns a borrowed reference */ + if (!pyrna_string_to_enum(PyTuple_GET_ITEM(value, i), ptr, prop, &tmpval, error_prefix)) + return -1; + + val |= tmpval; + } + } + else { char *enum_str= pyrna_enum_as_string(ptr, prop); - PyErr_Format(PyExc_TypeError, "%.200s expected a string enum type in (%.200s)", error_prefix, enum_str); + PyErr_Format(PyExc_TypeError, "%.200s expected a string enum or a tuple of strings in (%.200s)", error_prefix, enum_str); MEM_freeN(enum_str); return -1; - } else { - int val; - if (RNA_property_enum_value(BPy_GetContext(), ptr, prop, param, &val)) { - if(data) *((int*)data)= val; - else RNA_property_enum_set(ptr, prop, val); - } else { - char *enum_str= pyrna_enum_as_string(ptr, prop); - PyErr_Format(PyExc_TypeError, "%.200s enum \"%.200s\" not found in (%.200s)", error_prefix, param, enum_str); - MEM_freeN(enum_str); - return -1; - } } + + if(data) *((int*)data)= val; + else RNA_property_enum_set(ptr, prop, val); break; } diff --git a/source/blender/render/intern/source/pipeline.c b/source/blender/render/intern/source/pipeline.c index 9234e72df9c..b6c81e1ea60 100644 --- a/source/blender/render/intern/source/pipeline.c +++ b/source/blender/render/intern/source/pipeline.c @@ -409,7 +409,7 @@ static int passtype_from_name(char *str) static void render_unique_exr_name(Render *re, char *str, int sample) { - char di[FILE_MAX], name[FILE_MAXFILE], fi[FILE_MAXFILE]; + char di[FILE_MAX], name[FILE_MAXFILE+MAX_ID_NAME+100], fi[FILE_MAXFILE]; BLI_strncpy(di, G.sce, FILE_MAX); BLI_splitdirstring(di, fi); diff --git a/source/blender/render/intern/source/rayshade.c b/source/blender/render/intern/source/rayshade.c index d2599f6050c..c1d0c943ca9 100644 --- a/source/blender/render/intern/source/rayshade.c +++ b/source/blender/render/intern/source/rayshade.c @@ -1900,7 +1900,8 @@ static void ray_shadow_qmc(ShadeInput *shi, LampRen *lar, float *lampco, float * else max_samples = 1; } else { if (do_soft) max_samples = lar->ray_totsamp; - else max_samples = (R.osa > 4)?R.osa:5; + else if (shi->depth == 0) max_samples = (R.osa > 4)?R.osa:5; + else max_samples = 1; } ray_shadow_jittered_coords(shi, max_samples, jitco, &totjitco); diff --git a/source/blender/render/intern/source/texture.c b/source/blender/render/intern/source/texture.c index 2d2c01e0bf1..f25a167600f 100644 --- a/source/blender/render/intern/source/texture.c +++ b/source/blender/render/intern/source/texture.c @@ -1631,7 +1631,7 @@ void do_material_tex(ShadeInput *shi) float fact, facm, factt, facmm, stencilTin=1.0; float texvec[3], dxt[3], dyt[3], tempvec[3], norvec[3], warpvec[3]={0.0f, 0.0f, 0.0f}, Tnor=1.0; int tex_nr, rgbnor= 0, warpdone=0; - float nu[3], nv[3], nn[3] = {0,0,0}, dudnu = 1.f, dudnv = 0.f, dvdnu = 0.f, dvdnv = 1.f; // bump mapping + float nu[3] = {0,0,0}, nv[3] = {0,0,0}, nn[3] = {0,0,0}, dudnu = 1.f, dudnv = 0.f, dvdnu = 0.f, dvdnv = 1.f; // bump mapping int nunvdone= 0; if (R.r.scemode & R_NO_TEX) return; diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c index 40026d27bac..846309f1265 100644 --- a/source/blender/windowmanager/intern/wm_event_system.c +++ b/source/blender/windowmanager/intern/wm_event_system.c @@ -239,7 +239,7 @@ void wm_event_do_notifiers(bContext *C) if(G.rendering==0) { // XXX make lock in future, or separated derivedmesh users in scene - /* update all objects, ipos, matrices, displists, etc. Flags set by depgraph or manual, + /* update all objects, drivers, matrices, displists, etc. Flags set by depgraph or manual, no layer check here, gets correct flushed */ /* sets first, we allow per definition current scene to have dependencies on sets */ if(scene->set) { @@ -415,7 +415,9 @@ static int wm_operator_invoke(bContext *C, wmOperatorType *ot, wmEvent *event, P else printf("invalid operator call %s\n", ot->idname); /* debug, important to leave a while, should never happen */ - if(!(retval & OPERATOR_RUNNING_MODAL)) { + /* Note, if the report is given as an argument then assume the caller will deal with displaying them + * currently python only uses this */ + if(!(retval & OPERATOR_RUNNING_MODAL) && reports==NULL) { if(op->reports->list.first) /* only show the report if the report list was not given in the function */ uiPupMenuReports(C, op->reports); @@ -718,7 +720,7 @@ static int wm_eventmatch(wmEvent *winevent, wmKeymapItem *kmi) /* the matching rules */ if(kmitype==KM_TEXTINPUT) - if(ISKEYBOARD(winevent->type) && winevent->ascii) return 1; + if(ISTEXTINPUT(winevent->type) && winevent->ascii) return 1; if(kmitype!=KM_ANY) if(winevent->type!=kmitype) return 0; @@ -741,7 +743,7 @@ static int wm_eventmatch(wmEvent *winevent, wmKeymapItem *kmi) /* key modifiers always check when event has it */ /* otherwise regular keypresses with keymodifier still work */ if(winevent->keymodifier) - if(ISKEYBOARD(winevent->type)) + if(ISTEXTINPUT(winevent->type)) if(winevent->keymodifier!=kmi->keymodifier) return 0; return 1; @@ -1002,7 +1004,7 @@ static int wm_handlers_do(bContext *C, wmEvent *event, ListBase *handlers) int always_pass; if(handlers==NULL) return action; - + /* modal handlers can get removed in this loop, we keep the loop this way */ for(handler= handlers->first; handler; handler= nexthandler) { nexthandler= handler->next; @@ -1155,7 +1157,7 @@ void wm_event_do_handlers(bContext *C) while( (event= win->queue.first) ) { int action; - + CTX_wm_window_set(C, win); /* we let modal handlers get active area/region, also wm_paintcursor_test needs it */ @@ -1174,7 +1176,7 @@ void wm_event_do_handlers(bContext *C) /* builtin tweak, if action is break it removes tweak */ wm_tweakevent_test(C, event, action); - + if(action==WM_HANDLER_CONTINUE) { ScrArea *sa; ARegion *ar; @@ -1187,7 +1189,7 @@ void wm_event_do_handlers(bContext *C) /* for regions having custom cursors */ wm_paintcursor_test(C, event); } - + for(sa= win->screen->areabase.first; sa; sa= sa->next) { if(wm_event_inside_i(event, &sa->totrct)) { CTX_wm_area_set(C, sa); @@ -1231,7 +1233,7 @@ void wm_event_do_handlers(bContext *C) /* XXX hrmf, this gives reliable previous mouse coord for area change, feels bad? doing it on ghost queue gives errors when mousemoves go over area borders */ - if(doit && win->screen->subwinactive != win->screen->mainwin) { + if(doit && win->screen && win->screen->subwinactive != win->screen->mainwin) { win->eventstate->prevx= event->x; win->eventstate->prevy= event->y; } @@ -1244,7 +1246,7 @@ void wm_event_do_handlers(bContext *C) } /* only add mousemove when queue was read entirely */ - if(win->addmousemove) { + if(win->addmousemove && win->eventstate) { wmEvent event= *(win->eventstate); event.type= MOUSEMOVE; event.prevx= event.x; @@ -1573,12 +1575,16 @@ void wm_event_add_ghostevent(wmWindow *win, int type, void *customdata) case GHOST_kEventButtonDown: case GHOST_kEventButtonUp: { GHOST_TEventButtonData *bd= customdata; - event.val= (type==GHOST_kEventButtonDown); + event.val= (type==GHOST_kEventButtonDown) ? KM_PRESS:KM_RELEASE; /* Note!, this starts as 0/1 but later is converted to KM_PRESS/KM_RELEASE by tweak */ if (bd->button == GHOST_kButtonMaskLeft) event.type= LEFTMOUSE; else if (bd->button == GHOST_kButtonMaskRight) event.type= RIGHTMOUSE; + else if (bd->button == GHOST_kButtonMaskButton4) + event.type= BUTTON4MOUSE; + else if (bd->button == GHOST_kButtonMaskButton5) + event.type= BUTTON5MOUSE; else event.type= MIDDLEMOUSE; @@ -1596,7 +1602,7 @@ void wm_event_add_ghostevent(wmWindow *win, int type, void *customdata) event.val= (type==GHOST_kEventKeyDown)?KM_PRESS:KM_RELEASE; /* exclude arrow keys, esc, etc from text input */ - if(type==GHOST_kEventKeyUp || (event.ascii<32 && event.ascii>14)) + if(type==GHOST_kEventKeyUp || (event.ascii<32 && event.ascii>0)) event.ascii= '\0'; /* modifiers */ @@ -1626,6 +1632,13 @@ void wm_event_add_ghostevent(wmWindow *win, int type, void *customdata) else if(event.val==KM_RELEASE && event.keymodifier==event.type) event.keymodifier= evt->keymodifier= 0; } + + /* this case happens on some systems that on holding a key pressed, + generate press events without release, we still want to keep the + modifier in win->eventstate, but for the press event of the same + key we don't want the key modifier */ + if(event.keymodifier == event.type) + event.keymodifier= 0; /* if test_break set, it catches this. XXX Keep global for now? */ if(event.type==ESCKEY) diff --git a/source/blender/windowmanager/intern/wm_init_exit.c b/source/blender/windowmanager/intern/wm_init_exit.c index 5c78b32f3f8..1074c424663 100644 --- a/source/blender/windowmanager/intern/wm_init_exit.c +++ b/source/blender/windowmanager/intern/wm_init_exit.c @@ -166,6 +166,7 @@ extern wchar_t *copybufinfo; // XXX copy/paste buffer stuff... extern void free_anim_copybuf(); +extern void free_anim_drivers_copybuf(); extern void free_posebuf(); /* called in creator.c even... tsk, split this! */ @@ -213,6 +214,7 @@ void WM_exit(bContext *C) free_blender(); /* blender.c, does entire library and spacetypes */ // free_matcopybuf(); free_anim_copybuf(); + free_anim_drivers_copybuf(); free_posebuf(); // free_vertexpaint(); // free_imagepaint(); diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c index a6fc575ce70..486a887b354 100644 --- a/source/blender/windowmanager/intern/wm_operators.c +++ b/source/blender/windowmanager/intern/wm_operators.c @@ -943,7 +943,7 @@ static int wm_link_append_invoke(bContext *C, wmOperator *op, wmEvent *event) return WM_operator_call(C, op); } else { - /* XXX solve where to get last linked library from */ + /* XXX TODO solve where to get last linked library from */ RNA_string_set(op->ptr, "path", G.lib); WM_event_add_fileselect(C, op); return OPERATOR_RUNNING_MODAL; @@ -1064,6 +1064,8 @@ static int wm_link_append_exec(bContext *C, wmOperator *op) DAG_ids_flush_update(0); BLO_blendhandle_close(bh); + + /* XXX TODO: align G.lib with other directory storage (like last opened image etc...) */ BLI_strncpy(G.lib, dir, FILE_MAX); WM_event_add_notifier(C, NC_WINDOW, NULL); @@ -1483,7 +1485,7 @@ int WM_gesture_circle_modal(bContext *C, wmOperator *op, wmEvent *event) case LEFTMOUSE: case MIDDLEMOUSE: case RIGHTMOUSE: - if(event->val==0) { /* key release */ + if(event->val==KM_RELEASE) { /* key release */ wm_gesture_end(C, op); return OPERATOR_FINISHED; } @@ -1566,7 +1568,7 @@ static void tweak_gesture_modal(bContext *C, wmEvent *event) if(gesture->event_type==event->type) { WM_gesture_end(C, gesture); window->tweak= NULL; - + /* when tweak fails we should give the other keymap entries a chance */ event->val= KM_RELEASE; } @@ -1584,7 +1586,7 @@ void wm_tweakevent_test(bContext *C, wmEvent *event, int action) if(win->tweak==NULL) { if(CTX_wm_region(C)) { - if(event->val) { // pressed + if(event->val==KM_PRESS) { // pressed if( ELEM3(event->type, LEFTMOUSE, MIDDLEMOUSE, RIGHTMOUSE) ) win->tweak= WM_gesture_new(C, event, WM_GESTURE_TWEAK); } @@ -1684,7 +1686,7 @@ int WM_gesture_lasso_modal(bContext *C, wmOperator *op, wmEvent *event) case LEFTMOUSE: case MIDDLEMOUSE: case RIGHTMOUSE: - if(event->val==0) { /* key release */ + if(event->val==KM_RELEASE) { /* key release */ gesture_lasso_apply(C, op, event->type); return OPERATOR_FINISHED; } @@ -1977,17 +1979,19 @@ void WM_OT_radial_control_partial(wmOperatorType *ot) /* uses no type defines, fully local testing function anyway... ;) */ -static int ten_timer_exec(bContext *C, wmOperator *op) +static int redraw_timer_exec(bContext *C, wmOperator *op) { ARegion *ar= CTX_wm_region(C); double stime= PIL_check_seconds_timer(); int type = RNA_int_get(op->ptr, "type"); - int a, time; - char tmpstr[128]; + int iter = RNA_int_get(op->ptr, "iterations"); + int a; + float time; + char *infostr= ""; WM_cursor_wait(1); - - for(a=0; a<10; a++) { + + for(a=0; a<iter; a++) { if (type==0) { ED_region_do_draw(C, ar); } @@ -2003,13 +2007,35 @@ static int ten_timer_exec(bContext *C, wmOperator *op) wmWindow *win= CTX_wm_window(C); ScrArea *sa; + ScrArea *sa_back= CTX_wm_area(C); + ARegion *ar_back= CTX_wm_region(C); + + for(sa= CTX_wm_screen(C)->areabase.first; sa; sa= sa->next) { + ARegion *ar_iter; + CTX_wm_area_set(C, sa); + + for(ar_iter= sa->regionbase.first; ar_iter; ar_iter= ar_iter->next) { + CTX_wm_region_set(C, ar_iter); + ED_region_do_draw(C, ar_iter); + } + } + + CTX_wm_window_set(C, win); /* XXX context manipulation warning! */ + + CTX_wm_area_set(C, sa_back); + CTX_wm_region_set(C, ar_back); + } + else if (type==3) { + wmWindow *win= CTX_wm_window(C); + ScrArea *sa; + for(sa= CTX_wm_screen(C)->areabase.first; sa; sa= sa->next) ED_area_tag_redraw(sa); wm_draw_update(C); CTX_wm_window_set(C, win); /* XXX context manipulation warning! */ } - else if (type==3) { + else if (type==4) { Scene *scene= CTX_data_scene(C); if(a & 1) scene->r.cfra--; @@ -2022,40 +2048,43 @@ static int ten_timer_exec(bContext *C, wmOperator *op) } } - time= (int) ((PIL_check_seconds_timer()-stime)*1000); + time= ((PIL_check_seconds_timer()-stime)*1000); - if(type==0) sprintf(tmpstr, "10 x Draw Region: %d ms", time); - if(type==1) sprintf(tmpstr, "10 x Draw Region and Swap: %d ms", time); - if(type==2) sprintf(tmpstr, "10 x Draw Window and Swap: %d ms", time); - if(type==3) sprintf(tmpstr, "Anim Step: %d ms", time); - if(type==4) sprintf(tmpstr, "10 x Undo/Redo: %d ms", time); + if(type==0) infostr= "Draw Region"; + if(type==1) infostr= "Draw Region and Swap"; + if(type==2) infostr= "Draw Window"; + if(type==3) infostr= "Draw Window and Swap"; + if(type==4) infostr= "Animation Steps"; + if(type==5) infostr= "Undo/Redo"; WM_cursor_wait(0); - uiPupMenuNotice(C, tmpstr); + BKE_reportf(op->reports, RPT_INFO, "%d x %s: %.2f ms, average: %.4f", iter, infostr, time, time/iter); return OPERATOR_FINISHED; } -static void WM_OT_ten_timer(wmOperatorType *ot) +static void WM_OT_redraw_timer(wmOperatorType *ot) { static EnumPropertyItem prop_type_items[] = { {0, "DRAW", 0, "Draw Region", ""}, - {1, "DRAWSWAP", 0, "Draw Region + Swap", ""}, - {2, "DRAWWINSWAP", 0, "Draw Window + Swap", ""}, - {3, "ANIMSTEP", 0, "Anim Step", ""}, - {4, "UNDO", 0, "Undo/Redo", ""}, + {1, "DRAW_SWAP", 0, "Draw Region + Swap", ""}, + {2, "DRAW_WIN", 0, "Draw Window", ""}, + {3, "DRAW_WIN_SWAP", 0, "Draw Window + Swap", ""}, + {4, "ANIM_STEP", 0, "Anim Step", ""}, + {5, "UNDO", 0, "Undo/Redo", ""}, {0, NULL, 0, NULL, NULL}}; - ot->name= "Ten Timer"; - ot->idname= "WM_OT_ten_timer"; - ot->description="Ten Timer operator."; + ot->name= "Redraw Timer"; + ot->idname= "WM_OT_redraw_timer"; + ot->description="Simple redraw timer to test the speed of updating the interface."; ot->invoke= WM_menu_invoke; - ot->exec= ten_timer_exec; + ot->exec= redraw_timer_exec; ot->poll= WM_operator_winactive; RNA_def_enum(ot->srna, "type", prop_type_items, 0, "Type", ""); + RNA_def_int(ot->srna, "iterations", 10, 1,INT_MAX, "Iterations", "Number of times to redraw", 1,1000); } @@ -2090,7 +2119,7 @@ void wm_operatortype_init(void) WM_operatortype_append(WM_OT_jobs_timer); WM_operatortype_append(WM_OT_save_as_mainfile); WM_operatortype_append(WM_OT_save_mainfile); - WM_operatortype_append(WM_OT_ten_timer); + WM_operatortype_append(WM_OT_redraw_timer); WM_operatortype_append(WM_OT_debug_menu); WM_operatortype_append(WM_OT_search_menu); } @@ -2125,7 +2154,7 @@ void wm_window_keymap(wmWindowManager *wm) WM_keymap_add_item(keymap, "WM_OT_exit_blender", QKEY, KM_PRESS, KM_CTRL, 0); /* debug/testing */ - WM_keymap_verify_item(keymap, "WM_OT_ten_timer", TKEY, KM_PRESS, KM_ALT|KM_CTRL, 0); + WM_keymap_verify_item(keymap, "WM_OT_redraw_timer", TKEY, KM_PRESS, KM_ALT|KM_CTRL, 0); WM_keymap_verify_item(keymap, "WM_OT_debug_menu", DKEY, KM_PRESS, KM_ALT|KM_CTRL, 0); WM_keymap_verify_item(keymap, "WM_OT_search_menu", SPACEKEY, KM_PRESS, 0, 0); diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c index 9d3d0a9535e..c853afe4507 100644 --- a/source/blender/windowmanager/intern/wm_window.c +++ b/source/blender/windowmanager/intern/wm_window.c @@ -627,6 +627,7 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr private) if(state!=GHOST_kWindowStateMinimized) { GHOST_RectangleHandle client_rect; int l, t, r, b, scr_w, scr_h; + int sizex, sizey, posx, posy; client_rect= GHOST_GetClientBounds(win->ghostwin); GHOST_GetRectangle(client_rect, &l, &t, &r, &b); @@ -634,37 +635,56 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr private) GHOST_DisposeRectangle(client_rect); wm_get_screensize(&scr_w, &scr_h); - win->sizex= r-l; - win->sizey= b-t; - win->posx= l; - win->posy= scr_h - t - win->sizey; - - /* debug prints */ - if(0) { - state = GHOST_GetWindowState(win->ghostwin); - - if(state==GHOST_kWindowStateNormal) { - if(G.f & G_DEBUG) printf("window state: normal\n"); - } - else if(state==GHOST_kWindowStateMinimized) { - if(G.f & G_DEBUG) printf("window state: minimized\n"); - } - else if(state==GHOST_kWindowStateMaximized) { - if(G.f & G_DEBUG) printf("window state: maximized\n"); + sizex= r-l; + sizey= b-t; + posx= l; + posy= scr_h - t - win->sizey; + + /* + * Ghost sometimes send size or move events when the window hasn't changed. + * One case of this is using compiz on linux. To alleviate the problem + * we ignore all such event here. + * + * It might be good to eventually do that at Ghost level, but that is for + * another time. + */ + if (win->sizex != sizex || + win->sizey != sizey || + win->posx != posx || + win->posy != posy) + { + win->sizex= sizex; + win->sizey= sizey; + win->posx= posx; + win->posy= posy; + + /* debug prints */ + if(0) { + state = GHOST_GetWindowState(win->ghostwin); + + if(state==GHOST_kWindowStateNormal) { + if(G.f & G_DEBUG) printf("window state: normal\n"); + } + else if(state==GHOST_kWindowStateMinimized) { + if(G.f & G_DEBUG) printf("window state: minimized\n"); + } + else if(state==GHOST_kWindowStateMaximized) { + if(G.f & G_DEBUG) printf("window state: maximized\n"); + } + else if(state==GHOST_kWindowStateFullScreen) { + if(G.f & G_DEBUG) printf("window state: fullscreen\n"); + } + + if(type!=GHOST_kEventWindowSize) { + if(G.f & G_DEBUG) printf("win move event pos %d %d size %d %d\n", win->posx, win->posy, win->sizex, win->sizey); + } + } - else if(state==GHOST_kWindowStateFullScreen) { - if(G.f & G_DEBUG) printf("window state: fullscreen\n"); - } - - if(type!=GHOST_kEventWindowSize) { - if(G.f & G_DEBUG) printf("win move event pos %d %d size %d %d\n", win->posx, win->posy, win->sizex, win->sizey); - } - + + wm_window_make_drawable(C, win); + wm_draw_window_clear(win); + WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL); } - - wm_window_make_drawable(C, win); - wm_draw_window_clear(win); - WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL); } break; } diff --git a/source/blender/windowmanager/wm_event_types.h b/source/blender/windowmanager/wm_event_types.h index b331e036b9e..cc6041ce529 100644 --- a/source/blender/windowmanager/wm_event_types.h +++ b/source/blender/windowmanager/wm_event_types.h @@ -56,6 +56,9 @@ /* only use if you want user option switch possible */ #define ACTIONMOUSE 0x005 #define SELECTMOUSE 0x006 +/* Extra mouse buttons */ +#define BUTTON4MOUSE 0x007 +#define BUTTON5MOUSE 0x008 /* defaults from ghost */ #define WHEELUPMOUSE 0x00a #define WHEELDOWNMOUSE 0x00b @@ -191,10 +194,13 @@ /* for event checks */ /* only used for KM_TEXTINPUT, so assume that we want all user-inputtable ascii codes included */ -#define ISKEYBOARD(event) (event >=' ' && event <=255) +#define ISTEXTINPUT(event) (event >=' ' && event <=255) + + /* test wether the event is a key on the keyboard */ +#define ISKEYBOARD(event) (event >=' ' && event <=320) /* test whether event type is acceptable as hotkey, excluding modifiers */ -#define ISHOTKEY(event) (event >=' ' && event <=320 && !(event>=LEFTCTRLKEY && event<=ESCKEY) && !(event>=UNKNOWNKEY && event<=GRLESSKEY)) +#define ISHOTKEY(event) (ISKEYBOARD(event) && !(event>=LEFTCTRLKEY && event<=ESCKEY) && !(event>=UNKNOWNKEY && event<=GRLESSKEY)) /* **************** BLENDER GESTURE EVENTS ********************* */ |