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 | |
parent | b24004343f40fddc0ad5e5f6bfbfa2f4245dcc77 (diff) | |
parent | 8ea2904693707209d739928a70072d339c547b84 (diff) |
soc-2008-mxcurioni: merged changes to revision 23516
Diffstat (limited to 'source')
338 files changed, 15055 insertions, 3301 deletions
diff --git a/source/Makefile b/source/Makefile index dab037d1749..5a071a10a9c 100644 --- a/source/Makefile +++ b/source/Makefile @@ -98,7 +98,11 @@ COMLIB += $(OCGDIR)/blender/nodes_tex/$(DEBUG_DIR)libnodes_tex.a COMLIB += $(OCGDIR)/blender/nodes/$(DEBUG_DIR)libnodes.a COMLIB += $(OCGDIR)/blender/imbuf/$(DEBUG_DIR)libimbuf.a COMLIB += $(OCGDIR)/blender/blenlib/$(DEBUG_DIR)libblenlib.a +COMLIB += $(OCGDIR)/blender/ikplugin/$(DEBUG_DIR)libikplugin.a COMLIB += $(NAN_IKSOLVER)/lib/$(DEBUG_DIR)libiksolver.a +COMLIB += $(NAN_ITASC)/lib/$(DEBUG_DIR)libitasc.a +COMLIB += $(NAN_ITASC)/lib/$(DEBUG_DIR)libitasc_kdl.a +COMLIB += $(NAN_ITASC)/lib/$(DEBUG_DIR)libitasc_kdl_util.a COMLIB += $(NAN_MOTO)/lib/$(DEBUG_DIR)libmoto.a COMLIB += $(NAN_SUPERLU)/lib/$(DEBUG_DIR)libsuperlu.a COMLIB += $(OCGDIR)/blender/avi/$(DEBUG_DIR)libavi.a 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 ********************* */ diff --git a/source/creator/CMakeLists.txt b/source/creator/CMakeLists.txt index 1256881182b..95dbe9ecb37 100644 --- a/source/creator/CMakeLists.txt +++ b/source/creator/CMakeLists.txt @@ -24,6 +24,9 @@ # # ***** END GPL LICENSE BLOCK ***** +# So BUILDINFO and BLENDERPATH strings are automatically quoted +CMAKE_POLICY(SET CMP0005 NEW) + SETUP_LIBDIRS() INCLUDE_DIRECTORIES(../../intern/guardedalloc @@ -66,19 +69,37 @@ IF(NOT WITH_SDL) ADD_DEFINITIONS(-DDISABLE_SDL) ENDIF(NOT WITH_SDL) +IF(UNIX AND NOT APPLE) + SET(BLENDERPATH ${CMAKE_INSTALL_PREFIX}/share/blender/${BLENDER_VERSION}) + # blender_path in creator.c + ADD_DEFINITIONS(-DBLENDERPATH="${BLENDERPATH}") +ENDIF(UNIX AND NOT APPLE) + IF(CMAKE_SYSTEM_NAME MATCHES "Linux") ADD_DEFINITIONS(-DWITH_BINRELOC) INCLUDE_DIRECTORIES(${BINRELOC_INC}) ENDIF(CMAKE_SYSTEM_NAME MATCHES "Linux") -MESSAGE(STATUS "Configuring blender") +# Setup the exe sources and buildinfo +SET(EXESRC creator.c) IF(WIN32) - ADD_EXECUTABLE(blender ${EXETYPE} creator.c ../icons/winblender.rc) -ELSE(WIN32) - ADD_EXECUTABLE(blender ${EXETYPE} creator.c) + SET(EXESRC ${EXESRC} ../icons/winblender.rc) ENDIF(WIN32) +IF(WITH_BUILDINFO) + ADD_DEFINITIONS(-DBUILD_DATE="${BUILD_DATE}") + ADD_DEFINITIONS(-DBUILD_TIME="${BUILD_TIME}") + ADD_DEFINITIONS(-DBUILD_REV="${BUILD_REV}") + ADD_DEFINITIONS(-DBUILD_PLATFORM="${CMAKE_SYSTEM_NAME}") + ADD_DEFINITIONS(-DBUILD_TYPE="${CMAKE_BUILD_TYPE}") + + SET(EXESRC ${EXESRC} buildinfo.c) +ENDIF(WITH_BUILDINFO) + +MESSAGE(STATUS "Configuring blender") + +ADD_EXECUTABLE(blender ${EXETYPE} ${EXESRC}) # Post build steps for bundling/packaging. @@ -96,6 +117,9 @@ IF(WITH_INSTALL) ENDIF(UNIX) IF(UNIX AND NOT APPLE) + + # Local installation, "make install" can be done after this optionally + ADD_CUSTOM_COMMAND( TARGET blender POST_BUILD MAIN_DEPENDENCY blender COMMAND rm -Rf ${TARGETDIR}/.blender @@ -115,8 +139,7 @@ IF(WITH_INSTALL) ADD_CUSTOM_COMMAND( TARGET blender POST_BUILD MAIN_DEPENDENCY blender COMMENT "copying blender scripts..." - COMMAND cp -R ${CMAKE_SOURCE_DIR}/release/ui ${TARGETDIR}/.blender/ - COMMAND cp -R ${CMAKE_SOURCE_DIR}/release/io ${TARGETDIR}/.blender/ + COMMAND cp -R ${CMAKE_SOURCE_DIR}/release/scripts ${TARGETDIR}/.blender/ COMMAND find ${TARGETDIR} -name "*.py?" -prune -exec rm -rf {} "\;" ) @@ -152,6 +175,27 @@ IF(WITH_INSTALL) COMMAND find ${TARGETDIR} -name .svn -prune -exec rm -rf {} "\;" ) + + # Above we bundle a portable distrobution in ./bin + # This is an optional "make install" which installs blender on the system. + INSTALL( + PROGRAMS ${TARGETDIR}/blender + DESTINATION ${CMAKE_INSTALL_PREFIX}/bin + ) + + IF(WITH_GAMEENGINE AND WITH_PLAYER) + INSTALL( + PROGRAMS ${TARGETDIR}/blenderplayer + DESTINATION ${CMAKE_INSTALL_PREFIX}/bin + ) + ENDIF(WITH_GAMEENGINE AND WITH_PLAYER) + + INSTALL( + DIRECTORY ${TARGETDIR}/.blender/ + DESTINATION ${BLENDERPATH} + ) + # end "make install" + ENDIF(UNIX AND NOT APPLE) IF(APPLE) @@ -183,8 +227,7 @@ IF(WITH_INSTALL) IF(WITH_PYTHON) ADD_CUSTOM_COMMAND( TARGET blender POST_BUILD MAIN_DEPENDENCY blender - COMMAND cp -Rf ${CMAKE_SOURCE_DIR}/release/ui ${TARGETDIR}/blender.app/Contents/MacOS/.blender/ - COMMAND cp -Rf ${CMAKE_SOURCE_DIR}/release/io ${TARGETDIR}/blender.app/Contents/MacOS/.blender/ + COMMAND cp -Rf ${CMAKE_SOURCE_DIR}/release/scripts ${TARGETDIR}/blender.app/Contents/MacOS/.blender/ COMMAND mkdir ${TARGETDIR}/blender.app/Contents/MacOS/.blender/python/ COMMAND unzip -q ${LIBDIR}/release/python.zip -d ${TARGETDIR}/blender.app/Contents/MacOS/.blender/python/ COMMAND find ${TARGETDIR}/blender.app -name "*.py?" -prune -exec rm -rf {} "\;" @@ -206,15 +249,12 @@ IF(WITH_INSTALL) MAIN_DEPENDENCY blender COMMAND if not exist \"${TARGETDIR}\\.blender\" mkdir \"${TARGETDIR}\\.blender\" COMMAND if not exist \"${TARGETDIR}\\.blender\\locale\" mkdir \"${TARGETDIR}\\.blender\\locale\" - COMMAND if not exist \"${TARGETDIR}\\.blender\\ui\" mkdir \"${TARGETDIR}\\.blender\\ui\" - COMMAND if not exist \"${TARGETDIR}\\.blender\\io\" mkdir \"${TARGETDIR}\\.blender\\io\" + COMMAND if not exist \"${TARGETDIR}\\.blender\\scripts\" mkdir \"${TARGETDIR}\\.blender\\scripts\" COMMAND if not exist \"${TARGETDIR}\\plugins\" mkdir \"${TARGETDIR}\\plugins\" COMMAND copy /Y \"${WIN_SOURCE_DIR}\\bin\\.blender\\.Blanguages\" \"${TARGETDIR}\\.blender\\\" COMMAND copy /Y \"${WIN_SOURCE_DIR}\\bin\\.blender\\.bfont.ttf\" \"${TARGETDIR}\\.blender\\\" COMMAND xcopy /E /Y \"${WIN_SOURCE_DIR}\\bin\\.blender\\locale\\*.*\" \"${TARGETDIR}\\.blender\\locale\" COMMAND xcopy /E /Y \"${WIN_SOURCE_DIR}\\release\\scripts\\*.*\" \"${TARGETDIR}\\.blender\\scripts\" - COMMAND xcopy /E /Y \"${WIN_SOURCE_DIR}\\release\\ui\\*.*\" \"${TARGETDIR}\\.blender\\ui\" - COMMAND xcopy /E /Y \"${WIN_SOURCE_DIR}\\release\\io\\*.*\" \"${TARGETDIR}\\.blender\\io\" COMMAND xcopy /E /Y \"${WIN_SOURCE_DIR}\\release\\plugins\\*.*\" \"${TARGETDIR}\\plugins\" COMMAND copy /Y \"${WIN_SOURCE_DIR}\\release\\text\\*.*\" \"${TARGETDIR}\" COMMAND copy /Y \"${WIN_SOURCE_DIR}\\release\\windows\\extra\\python26.zip\" \"${TARGETDIR}\\\" @@ -319,6 +359,7 @@ IF(UNIX) blender_ONL bf_python bf_gen_python + bf_ikplugin bf_blenkernel bf_nodes bf_gpu @@ -363,6 +404,7 @@ IF(UNIX) bf_ngnetwork extern_bullet bf_loopbacknetwork + bf_ITASC bf_common bf_moto bf_python diff --git a/source/creator/SConscript b/source/creator/SConscript index 75e7494ebb5..7b3d1493ed2 100644 --- a/source/creator/SConscript +++ b/source/creator/SConscript @@ -1,5 +1,6 @@ #!/usr/bin/python Import ('env') +import os sources = 'creator.c' @@ -32,4 +33,8 @@ if env['WITH_BF_PYTHON']: else: defs.append('DISABLE_PYTHON') +if env['WITH_BF_FHS']: # /usr -> /usr/share/blender/2.5 + defs.append('BLENDERPATH=\\"' + os.path.join(env['BF_INSTALLDIR'], 'share', 'blender', env['BF_VERSION']) + '\\"') + + env.BlenderLib ( libname = 'bf_creator', sources = Split(sources), includes = Split(incs), defines = defs, libtype='core', priority = 0 ) diff --git a/source/creator/creator.c b/source/creator/creator.c index 4d00e3e521d..5887e047e85 100644 --- a/source/creator/creator.c +++ b/source/creator/creator.c @@ -101,6 +101,7 @@ #ifdef BUILD_DATE extern char * build_date; extern char * build_time; +extern char * build_rev; extern char * build_platform; extern char * build_type; #endif @@ -116,6 +117,14 @@ extern int pluginapi_force_ref(void); /* from blenpluginapi:pluginapi.c */ char bprogname[FILE_MAXDIR+FILE_MAXFILE]; /* from blenpluginapi:pluginapi.c */ char btempdir[FILE_MAXDIR+FILE_MAXFILE]; +/* unix path support. + * defined by the compiler. eg "/usr/share/blender/2.5" "/opt/blender/2.5" */ +#ifndef BLENDERPATH +#define BLENDERPATH "" +#endif + +char blender_path[FILE_MAXDIR+FILE_MAXFILE] = BLENDERPATH; + /* Initialise callbacks for the modules that need them */ static void setCallbacks(void); @@ -221,6 +230,10 @@ static void print_help(void) printf (" \t\t passed unchanged. Access via Python's sys.argv\n"); printf ("\nEnvironment Variables:\n"); printf (" $HOME\t\t\tStore files such as .blender/ .B.blend .Bfs .Blog here.\n"); + printf (" $BLENDERPATH\tSystem directory to use for data files and scripts.\n"); + printf (" \tFor this build of blender the default BLENDERPATH is...\n"); + printf (" \t\"%s\"\n", blender_path); + printf (" \tseting the $BLENDERPATH will override this\n"); #ifdef WIN32 printf (" $TEMP\t\tStore temporary files here.\n"); #else @@ -305,6 +318,12 @@ int main(int argc, char **argv) BLI_where_am_i(bprogname, argv[0]); + { /* override the hard coded blender path */ + char *blender_path_env = getenv("BLENDERPATH"); + if(blender_path_env) + BLI_strncpy(blender_path, blender_path_env, sizeof(blender_path)); + } + RNA_init(); RE_engines_init(); diff --git a/source/darwin/Makefile b/source/darwin/Makefile index 35842b43eae..1431ab817ff 100644 --- a/source/darwin/Makefile +++ b/source/darwin/Makefile @@ -49,8 +49,6 @@ ifeq ($(APPLICATION), blender) @echo "---> copying .blender/ scripts" @cp -R $(NANBLENDERHOME)/bin/.blender $(DIR)/bin/$(APPLICATION).app/Contents/MacOS @cp -R $(NANBLENDERHOME)/release/scripts $(DIR)/bin/$(APPLICATION).app/Contents/MacOS/.blender/ - @echo "---> copying ui scripts" - @cp -R $(NANBLENDERHOME)/release/ui $(DIR)/bin/$(APPLICATION).app/Contents/MacOS/.blender/ @echo "---> copying python modules" @mkdir $(DIR)/bin/$(APPLICATION).app/Contents/MacOS/.blender/python @unzip -q $(LCGDIR)/release/python.zip -d $(DIR)/bin/$(APPLICATION).app/Contents/MacOS/.blender/python/ diff --git a/source/gameengine/BlenderRoutines/BL_KetsjiEmbedStart.cpp b/source/gameengine/BlenderRoutines/BL_KetsjiEmbedStart.cpp index ae46f880711..1ede16f017e 100644 --- a/source/gameengine/BlenderRoutines/BL_KetsjiEmbedStart.cpp +++ b/source/gameengine/BlenderRoutines/BL_KetsjiEmbedStart.cpp @@ -89,6 +89,8 @@ extern "C" { #include "DNA_scene_types.h" /***/ +#include "AUD_C-API.h" + //XXX #include "BSE_headerbuttons.h" #include "BKE_context.h" #include "../../blender/windowmanager/WM_types.h" @@ -386,6 +388,11 @@ extern "C" void StartKetsjiShell(struct bContext *C, struct ARegion *ar, int alw if(blscene->gm.stereoflag == STEREO_DOME) ketsjiengine->InitDome(blscene->gm.dome.res, blscene->gm.dome.mode, blscene->gm.dome.angle, blscene->gm.dome.resbuf, blscene->gm.dome.tilt, blscene->gm.dome.warptext); + // initialize 3D Audio Settings + AUD_set3DSetting(AUD_3DS_SPEED_OF_SOUND, blscene->audio.speed_of_sound); + AUD_set3DSetting(AUD_3DS_DOPPLER_FACTOR, blscene->audio.doppler_factor); + AUD_set3DSetting(AUD_3DS_DISTANCE_MODEL, blscene->audio.distance_model); + if (sceneconverter) { // convert and add scene diff --git a/source/gameengine/BlenderRoutines/CMakeLists.txt b/source/gameengine/BlenderRoutines/CMakeLists.txt index ee15fd99ed5..ce85c1185b0 100644 --- a/source/gameengine/BlenderRoutines/CMakeLists.txt +++ b/source/gameengine/BlenderRoutines/CMakeLists.txt @@ -6,6 +6,7 @@ SET(INC ../../../source/kernel/gen_system ../../../intern/string ../../../intern/guardedalloc + ../../../intern/audaspace/intern ../../../source/gameengine/Rasterizer/RAS_OpenGLRasterizer ../../../source/gameengine/Converter ../../../source/blender/imbuf diff --git a/source/gameengine/BlenderRoutines/KX_BlenderGL.cpp b/source/gameengine/BlenderRoutines/KX_BlenderGL.cpp index dba6d1113c9..bb02f3b372e 100644 --- a/source/gameengine/BlenderRoutines/KX_BlenderGL.cpp +++ b/source/gameengine/BlenderRoutines/KX_BlenderGL.cpp @@ -44,6 +44,7 @@ extern "C" { * This little block needed for linking to Blender... */ #ifdef WIN32 +#include <vector> #include "BLI_winstuff.h" #endif diff --git a/source/gameengine/BlenderRoutines/Makefile b/source/gameengine/BlenderRoutines/Makefile index 4b65da667ef..4a437aff97d 100644 --- a/source/gameengine/BlenderRoutines/Makefile +++ b/source/gameengine/BlenderRoutines/Makefile @@ -40,6 +40,7 @@ CPPFLAGS += -I$(NAN_STRING)/include CPPFLAGS += -I$(NAN_MOTO)/include CPPFLAGS += -I$(NAN_GLEW)/include CPPFLAGS += -I$(OPENGL_HEADERS) +CPPFLAGS += -I$(NAN_AUDASPACE)/include # because of kernel dependency on makesdna CPPFLAGS += -I../../blender/makesdna CPPFLAGS += -I../../blender/editors/include diff --git a/source/gameengine/BlenderRoutines/SConscript b/source/gameengine/BlenderRoutines/SConscript index ad6f9f23fce..1e8ff3c48e8 100644 --- a/source/gameengine/BlenderRoutines/SConscript +++ b/source/gameengine/BlenderRoutines/SConscript @@ -8,6 +8,7 @@ incs = '. #source/kernel/gen_system #intern/string #intern/guardedalloc' incs += ' #source/gameengine/Rasterizer/RAS_OpenGLRasterizer' incs += ' #source/gameengine/Converter #source/blender/imbuf' incs += ' #intern/ghost/include' +incs += ' #intern/audaspace/intern' incs += ' #intern/moto/include #source/gameengine/Ketsji #source/blender/blenlib' incs += ' #source/blender/blenkernel #source/blender' incs += ' #source/blender/blenfont #source/blender/editors/include' diff --git a/source/gameengine/Converter/BL_ActionActuator.cpp b/source/gameengine/Converter/BL_ActionActuator.cpp index ca4290703e1..2f0e3e9fa65 100644 --- a/source/gameengine/Converter/BL_ActionActuator.cpp +++ b/source/gameengine/Converter/BL_ActionActuator.cpp @@ -526,12 +526,11 @@ KX_PYMETHODDEF_DOC(BL_ActionActuator, setChannel, mat.setValue((const float *)matrix); BL_ArmatureObject *obj = (BL_ArmatureObject*)GetParent(); - obj->GetPose(&m_pose); /* Get the underlying pose from the armature */ if (!m_userpose) { if(!m_pose) obj->GetPose(&m_pose); /* Get the underlying pose from the armature */ - game_copy_pose(&m_userpose, m_pose); + game_copy_pose(&m_userpose, m_pose, 0); } // pchan= verify_pose_channel(m_userpose, string); // adds the channel if its not there. pchan= get_pose_channel(m_userpose, string); // adds the channel if its not there. @@ -554,7 +553,7 @@ KX_PYMETHODDEF_DOC(BL_ActionActuator, setChannel, if (!m_userpose) { if(!m_pose) obj->GetPose(&m_pose); /* Get the underlying pose from the armature */ - game_copy_pose(&m_userpose, m_pose); + game_copy_pose(&m_userpose, m_pose, 0); } // pchan= verify_pose_channel(m_userpose, string); pchan= get_pose_channel(m_userpose, string); // adds the channel if its not there. @@ -572,7 +571,6 @@ KX_PYMETHODDEF_DOC(BL_ActionActuator, setChannel, return NULL; } - pchan->flag |= POSE_ROT|POSE_LOC|POSE_SIZE; Py_RETURN_NONE; } diff --git a/source/gameengine/Converter/BL_ActionActuator.h b/source/gameengine/Converter/BL_ActionActuator.h index a6b4c4a055d..2e0e38b4cc3 100644 --- a/source/gameengine/Converter/BL_ActionActuator.h +++ b/source/gameengine/Converter/BL_ActionActuator.h @@ -50,7 +50,7 @@ public: short priority, short end_reset, float stride) - : SCA_IActuator(gameobj), + : SCA_IActuator(gameobj, KX_ACT_ACTION), m_lastpos(0, 0, 0), m_blendframe(0), diff --git a/source/gameengine/Converter/BL_ArmatureActuator.cpp b/source/gameengine/Converter/BL_ArmatureActuator.cpp new file mode 100644 index 00000000000..741f1cf0553 --- /dev/null +++ b/source/gameengine/Converter/BL_ArmatureActuator.cpp @@ -0,0 +1,265 @@ +/** + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "DNA_action_types.h" +#include "DNA_constraint_types.h" +#include "DNA_actuator_types.h" +#include "BKE_constraint.h" +#include "BLI_arithb.h" +#include "BL_ArmatureActuator.h" +#include "BL_ArmatureObject.h" + +/** + * This class is the conversion of the Pose channel constraint. + * It makes a link between the pose constraint and the KX scene. + * The main purpose is to give access to the constraint target + * to link it to a game object. + * It also allows to activate/deactivate constraints during the game. + * Later it will also be possible to create constraint on the fly + */ + +BL_ArmatureActuator::BL_ArmatureActuator(SCA_IObject* obj, + int type, + const char *posechannel, + const char *constraintname, + KX_GameObject* targetobj, + KX_GameObject* subtargetobj, + float weight) : + SCA_IActuator(obj, KX_ACT_ARMATURE), + m_constraint(NULL), + m_gametarget(targetobj), + m_gamesubtarget(subtargetobj), + m_posechannel(posechannel), + m_constraintname(constraintname), + m_weight(weight), + m_type(type) +{ + if (m_gametarget) + m_gametarget->RegisterActuator(this); + if (m_gamesubtarget) + m_gamesubtarget->RegisterActuator(this); + FindConstraint(); +} + +BL_ArmatureActuator::~BL_ArmatureActuator() +{ + if (m_gametarget) + m_gametarget->UnregisterActuator(this); + if (m_gamesubtarget) + m_gamesubtarget->UnregisterActuator(this); +} + +void BL_ArmatureActuator::ProcessReplica() +{ + // the replica is tracking the same object => register it (this may be changed in Relnk()) + if (m_gametarget) + m_gametarget->RegisterActuator(this); + if (m_gamesubtarget) + m_gamesubtarget->UnregisterActuator(this); + SCA_IActuator::ProcessReplica(); +} + +void BL_ArmatureActuator::ReParent(SCA_IObject* parent) +{ + SCA_IActuator::ReParent(parent); + // must remap the constraint + FindConstraint(); +} + +bool BL_ArmatureActuator::UnlinkObject(SCA_IObject* clientobj) +{ + bool res=false; + if (clientobj == m_gametarget) + { + // this object is being deleted, we cannot continue to track it. + m_gametarget = NULL; + res = true; + } + if (clientobj == m_gamesubtarget) + { + // this object is being deleted, we cannot continue to track it. + m_gamesubtarget = NULL; + res = true; + } + return res; +} + +void BL_ArmatureActuator::Relink(GEN_Map<GEN_HashedPtr, void*> *obj_map) +{ + void **h_obj = (*obj_map)[m_gametarget]; + if (h_obj) { + if (m_gametarget) + m_gametarget->UnregisterActuator(this); + m_gametarget = (KX_GameObject*)(*h_obj); + m_gametarget->RegisterActuator(this); + } + h_obj = (*obj_map)[m_gamesubtarget]; + if (h_obj) { + if (m_gamesubtarget) + m_gamesubtarget->UnregisterActuator(this); + m_gamesubtarget = (KX_GameObject*)(*h_obj); + m_gamesubtarget->RegisterActuator(this); + } +} + +void BL_ArmatureActuator::FindConstraint() +{ + m_constraint = NULL; + + if (m_gameobj->GetGameObjectType() == SCA_IObject::OBJ_ARMATURE) { + BL_ArmatureObject* armobj = (BL_ArmatureObject*)m_gameobj; + m_constraint = armobj->GetConstraint(m_posechannel, m_constraintname); + } +} + +bool BL_ArmatureActuator::Update(double curtime, bool frame) +{ + // the only role of this actuator is to ensure that the armature pose will be evaluated + bool result = false; + bool bNegativeEvent = IsNegativeEvent(); + RemoveAllEvents(); + + if (!bNegativeEvent) { + BL_ArmatureObject *obj = (BL_ArmatureObject*)GetParent(); + switch (m_type) { + case ACT_ARM_RUN: + result = true; + obj->SetActiveAction(NULL, 0, curtime); + break; + case ACT_ARM_ENABLE: + if (m_constraint) + m_constraint->ClrConstraintFlag(CONSTRAINT_OFF); + break; + case ACT_ARM_DISABLE: + if (m_constraint) + m_constraint->SetConstraintFlag(CONSTRAINT_OFF); + break; + case ACT_ARM_SETTARGET: + if (m_constraint) { + m_constraint->SetTarget(m_gametarget); + m_constraint->SetSubtarget(m_gamesubtarget); + } + break; + case ACT_ARM_SETWEIGHT: + if (m_constraint) + m_constraint->SetWeight(m_weight); + break; + } + } + return result; +} + +/* ------------------------------------------------------------------------- */ +/* Python Integration Hooks */ +/* ------------------------------------------------------------------------- */ + +PyTypeObject BL_ArmatureActuator::Type = { +#if (PY_VERSION_HEX >= 0x02060000) + PyVarObject_HEAD_INIT(NULL, 0) +#else + /* python 2.5 and below */ + PyObject_HEAD_INIT( NULL ) /* required py macro */ + 0, /* ob_size */ +#endif + "BL_ArmatureActuator", + sizeof(PyObjectPlus_Proxy), + 0, + py_base_dealloc, + 0, + 0, + 0, + 0, + py_base_repr, + 0,0,0,0,0,0,0,0,0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + 0,0,0,0,0,0,0, + Methods, + 0, + 0, + &SCA_IActuator::Type, + 0,0,0,0,0,0, + py_base_new +}; + + +PyMethodDef BL_ArmatureActuator::Methods[] = { + {NULL,NULL} //Sentinel +}; + +PyAttributeDef BL_ArmatureActuator::Attributes[] = { + KX_PYATTRIBUTE_RO_FUNCTION("constraint", BL_ArmatureActuator, pyattr_get_constraint), + KX_PYATTRIBUTE_RW_FUNCTION("target", BL_ArmatureActuator, pyattr_get_object, pyattr_set_object), + KX_PYATTRIBUTE_RW_FUNCTION("subtarget", BL_ArmatureActuator, pyattr_get_object, pyattr_set_object), + KX_PYATTRIBUTE_FLOAT_RW("weight",0.0f,1.0f,BL_ArmatureActuator,m_weight), + KX_PYATTRIBUTE_INT_RW("type",0,ACT_ARM_MAXTYPE,false,BL_ArmatureActuator,m_type), + { NULL } //Sentinel +}; + +PyObject* BL_ArmatureActuator::pyattr_get_object(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef) +{ + BL_ArmatureActuator* actuator = static_cast<BL_ArmatureActuator*>(self); + KX_GameObject *target = (!strcmp(attrdef->m_name, "target")) ? actuator->m_gametarget : actuator->m_gamesubtarget; + if (!target) + Py_RETURN_NONE; + else + return target->GetProxy(); +} + +int BL_ArmatureActuator::pyattr_set_object(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +{ + BL_ArmatureActuator* actuator = static_cast<BL_ArmatureActuator*>(self); + KX_GameObject* &target = (!strcmp(attrdef->m_name, "target")) ? actuator->m_gametarget : actuator->m_gamesubtarget; + KX_GameObject *gameobj; + + if (!ConvertPythonToGameObject(value, &gameobj, true, "actuator.object = value: BL_ArmatureActuator")) + return PY_SET_ATTR_FAIL; // ConvertPythonToGameObject sets the error + + if (target != NULL) + target->UnregisterActuator(actuator); + + target = gameobj; + + if (target) + target->RegisterActuator(actuator); + + return PY_SET_ATTR_SUCCESS; +} + +PyObject* BL_ArmatureActuator::pyattr_get_constraint(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef) +{ + BL_ArmatureActuator* actuator = static_cast<BL_ArmatureActuator*>(self); + BL_ArmatureConstraint* constraint = actuator->m_constraint; + if (!constraint) + Py_RETURN_NONE; + else + return constraint->GetProxy(); +} + + + diff --git a/source/gameengine/Converter/BL_ArmatureActuator.h b/source/gameengine/Converter/BL_ArmatureActuator.h new file mode 100644 index 00000000000..5a7752b8169 --- /dev/null +++ b/source/gameengine/Converter/BL_ArmatureActuator.h @@ -0,0 +1,89 @@ +/** + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ +#ifndef BL_ARMATUREACTUATOR +#define BL_ARMATUREACTUATOR + +#include "SCA_IActuator.h" +#include "BL_ArmatureConstraint.h" + +/** + * This class is the conversion of the Pose channel constraint. + * It makes a link between the pose constraint and the KX scene. + * The main purpose is to give access to the constraint target + * to link it to a game object. + * It also allows to activate/deactivate constraints during the game. + * Later it will also be possible to create constraint on the fly + */ + +class BL_ArmatureActuator : public SCA_IActuator +{ + Py_Header; +public: + BL_ArmatureActuator(SCA_IObject* gameobj, + int type, + const char *posechannel, + const char *constraintname, + KX_GameObject* targetobj, + KX_GameObject* subtargetobj, + float weight); + + virtual ~BL_ArmatureActuator(); + + virtual CValue* GetReplica() { + BL_ArmatureActuator* replica = new BL_ArmatureActuator(*this); + replica->ProcessReplica(); + return replica; + }; + virtual void ProcessReplica(); + virtual bool UnlinkObject(SCA_IObject* clientobj); + virtual void Relink(GEN_Map<GEN_HashedPtr, void*> *obj_map); + virtual bool Update(double curtime, bool frame); + virtual void ReParent(SCA_IObject* parent); + + /* These are used to get and set m_target */ + static PyObject* pyattr_get_constraint(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef); + static PyObject* pyattr_get_object(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_object(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); + +private: + // identify the constraint that this actuator controls + void FindConstraint(); + + BL_ArmatureConstraint* m_constraint; + KX_GameObject* m_gametarget; + KX_GameObject* m_gamesubtarget; + STR_String m_posechannel; + STR_String m_constraintname; + float m_weight; + int m_type; +}; + +#endif //BL_ARMATUREACTUATOR + + diff --git a/source/gameengine/Converter/BL_ArmatureChannel.cpp b/source/gameengine/Converter/BL_ArmatureChannel.cpp new file mode 100644 index 00000000000..c0afeb008f6 --- /dev/null +++ b/source/gameengine/Converter/BL_ArmatureChannel.cpp @@ -0,0 +1,461 @@ +/** + * $Id$ + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "DNA_armature_types.h" +#include "BL_ArmatureChannel.h" +#include "BL_ArmatureObject.h" +#include "BL_ArmatureConstraint.h" +#include "BLI_arithb.h" +#include "BLI_string.h" + +PyTypeObject BL_ArmatureChannel::Type = { + PyVarObject_HEAD_INIT(NULL, 0) + "BL_ArmatureChannel", + sizeof(PyObjectPlus_Proxy), + 0, + py_base_dealloc, + 0, + 0, + 0, + 0, + py_base_repr, + 0,0,0,0,0,0,0,0,0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + 0,0,0,0,0,0,0, + Methods, + 0, + 0, + &CValue::Type, + 0,0,0,0,0,0, + py_base_new +}; + +PyObject* BL_ArmatureChannel::py_repr(void) +{ + return PyUnicode_FromString(m_posechannel->name); +} + +PyObject *BL_ArmatureChannel::GetProxy() +{ + return GetProxyPlus_Ext(this, &Type, m_posechannel); +} + +PyObject *BL_ArmatureChannel::NewProxy(bool py_owns) +{ + return NewProxyPlus_Ext(this, &Type, m_posechannel, py_owns); +} + +BL_ArmatureChannel::BL_ArmatureChannel( + BL_ArmatureObject *armature, + bPoseChannel *posechannel) + : PyObjectPlus(), m_posechannel(posechannel), m_armature(armature) +{ +} + +BL_ArmatureChannel::~BL_ArmatureChannel() +{ +} + +// PYTHON + +PyMethodDef BL_ArmatureChannel::Methods[] = { + {NULL,NULL} //Sentinel +}; + +// order of definition of attributes, must match Attributes[] array +#define BCA_BONE 0 +#define BCA_PARENT 1 + +PyAttributeDef BL_ArmatureChannel::Attributes[] = { + // Keep these attributes in order of BCA_ defines!!! used by py_attr_getattr and py_attr_setattr + KX_PYATTRIBUTE_RO_FUNCTION("bone",BL_ArmatureChannel,py_attr_getattr), + KX_PYATTRIBUTE_RO_FUNCTION("parent",BL_ArmatureChannel,py_attr_getattr), + + { NULL } //Sentinel +}; + +/* attributes directly taken from bPoseChannel */ +PyAttributeDef BL_ArmatureChannel::AttributesPtr[] = { + KX_PYATTRIBUTE_CHAR_RO("name",bPoseChannel,name), + KX_PYATTRIBUTE_FLAG_RO("has_ik",bPoseChannel,flag, POSE_CHAIN), + KX_PYATTRIBUTE_FLAG_NEGATIVE_RO("ik_dof_x",bPoseChannel,ikflag, BONE_IK_NO_XDOF), + KX_PYATTRIBUTE_FLAG_NEGATIVE_RO("ik_dof_y",bPoseChannel,ikflag, BONE_IK_NO_YDOF), + KX_PYATTRIBUTE_FLAG_NEGATIVE_RO("ik_dof_z",bPoseChannel,ikflag, BONE_IK_NO_ZDOF), + KX_PYATTRIBUTE_FLAG_RO("ik_limit_x",bPoseChannel,ikflag, BONE_IK_XLIMIT), + KX_PYATTRIBUTE_FLAG_RO("ik_limit_y",bPoseChannel,ikflag, BONE_IK_YLIMIT), + KX_PYATTRIBUTE_FLAG_RO("ik_limit_z",bPoseChannel,ikflag, BONE_IK_ZLIMIT), + KX_PYATTRIBUTE_FLAG_RO("ik_rot_control",bPoseChannel,ikflag, BONE_IK_ROTCTL), + KX_PYATTRIBUTE_FLAG_RO("ik_lin_control",bPoseChannel,ikflag, BONE_IK_LINCTL), + KX_PYATTRIBUTE_FLOAT_VECTOR_RW("location",-FLT_MAX,FLT_MAX,bPoseChannel,loc,3), + KX_PYATTRIBUTE_FLOAT_VECTOR_RW("scale",-FLT_MAX,FLT_MAX,bPoseChannel,size,3), + KX_PYATTRIBUTE_FLOAT_VECTOR_RW("rotation",-1.0f,1.0f,bPoseChannel,quat,4), + KX_PYATTRIBUTE_FLOAT_VECTOR_RW("euler_rotation",-10.f,10.f,bPoseChannel,eul,3), + KX_PYATTRIBUTE_SHORT_RW("rotation_mode",0,PCHAN_ROT_MAX-1,false,bPoseChannel,rotmode), + KX_PYATTRIBUTE_FLOAT_MATRIX_RO("channel_matrix",bPoseChannel,chan_mat,4), + KX_PYATTRIBUTE_FLOAT_MATRIX_RO("pose_matrix",bPoseChannel,pose_mat,4), + KX_PYATTRIBUTE_FLOAT_VECTOR_RO("pose_head",bPoseChannel,pose_head,3), + KX_PYATTRIBUTE_FLOAT_VECTOR_RO("pose_tail",bPoseChannel,pose_tail,3), + KX_PYATTRIBUTE_FLOAT_RO("ik_min_x",bPoseChannel,limitmin[0]), + KX_PYATTRIBUTE_FLOAT_RO("ik_max_x",bPoseChannel,limitmax[0]), + KX_PYATTRIBUTE_FLOAT_RO("ik_min_y",bPoseChannel,limitmin[1]), + KX_PYATTRIBUTE_FLOAT_RO("ik_max_y",bPoseChannel,limitmax[1]), + KX_PYATTRIBUTE_FLOAT_RO("ik_min_z",bPoseChannel,limitmin[2]), + KX_PYATTRIBUTE_FLOAT_RO("ik_max_z",bPoseChannel,limitmax[2]), + KX_PYATTRIBUTE_FLOAT_RO("ik_stiffness_x",bPoseChannel,stiffness[0]), + KX_PYATTRIBUTE_FLOAT_RO("ik_stiffness_y",bPoseChannel,stiffness[1]), + KX_PYATTRIBUTE_FLOAT_RO("ik_stiffness_z",bPoseChannel,stiffness[2]), + KX_PYATTRIBUTE_FLOAT_RO("ik_stretch",bPoseChannel,ikstretch), + KX_PYATTRIBUTE_FLOAT_RW("ik_rot_weight",0,1.0f,bPoseChannel,ikrotweight), + KX_PYATTRIBUTE_FLOAT_RW("ik_lin_weight",0,1.0f,bPoseChannel,iklinweight), + KX_PYATTRIBUTE_RW_FUNCTION("joint_rotation",BL_ArmatureChannel,py_attr_get_joint_rotation,py_attr_set_joint_rotation), + { NULL } //Sentinel +}; + +PyObject* BL_ArmatureChannel::py_attr_getattr(void *self_v, const struct KX_PYATTRIBUTE_DEF *attrdef) +{ + BL_ArmatureChannel* self= static_cast<BL_ArmatureChannel*>(self_v); + bPoseChannel* channel = self->m_posechannel; + int attr_order = attrdef-Attributes; + + if (!channel) { + PyErr_SetString(PyExc_AttributeError, "channel is NULL"); + return NULL; + } + + switch (attr_order) { + case BCA_BONE: + // bones are standalone proxy + return NewProxyPlus_Ext(NULL,&BL_ArmatureBone::Type,channel->bone,false); + case BCA_PARENT: + { + BL_ArmatureChannel* parent = self->m_armature->GetChannel(channel->parent); + if (parent) + return parent->GetProxy(); + else + Py_RETURN_NONE; + } + } + PyErr_SetString(PyExc_AttributeError, "channel unknown attribute"); + return NULL; +} + +int BL_ArmatureChannel::py_attr_setattr(void *self_v, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +{ + BL_ArmatureChannel* self= static_cast<BL_ArmatureChannel*>(self_v); + bPoseChannel* channel = self->m_posechannel; + int attr_order = attrdef-Attributes; + + int ival; + double dval; + char* sval; + KX_GameObject *oval; + + if (!channel) { + PyErr_SetString(PyExc_AttributeError, "channel is NULL"); + return PY_SET_ATTR_FAIL; + } + + switch (attr_order) { + default: + break; + } + + PyErr_SetString(PyExc_AttributeError, "channel unknown attribute"); + return PY_SET_ATTR_FAIL; +} + +PyObject* BL_ArmatureChannel::py_attr_get_joint_rotation(void *self_v, const struct KX_PYATTRIBUTE_DEF *attrdef) +{ + BL_ArmatureChannel* self= static_cast<BL_ArmatureChannel*>(self_v); + bPoseChannel* pchan = self->m_posechannel; + // decompose the pose matrix in euler rotation + float rest_mat[3][3]; + float pose_mat[3][3]; + float joint_mat[3][3]; + float joints[3]; + float norm; + double sa, ca; + // get rotation in armature space + Mat3CpyMat4(pose_mat, pchan->pose_mat); + Mat3Ortho(pose_mat); + if (pchan->parent) { + // bone has a parent, compute the rest pose of the bone taking actual pose of parent + Mat3IsMat3MulMat4(rest_mat, pchan->bone->bone_mat, pchan->parent->pose_mat); + Mat3Ortho(rest_mat); + } else { + // otherwise, the bone matrix in armature space is the rest pose + Mat3CpyMat4(rest_mat, pchan->bone->arm_mat); + } + // remove the rest pose to get the joint movement + Mat3Transp(rest_mat); + Mat3MulMat3(joint_mat, rest_mat, pose_mat); + joints[0] = joints[1] = joints[2] = 0.f; + // returns a 3 element list that gives corresponding joint + int flag = 0; + if (!(pchan->ikflag & BONE_IK_NO_XDOF)) + flag |= 1; + if (!(pchan->ikflag & BONE_IK_NO_YDOF)) + flag |= 2; + if (!(pchan->ikflag & BONE_IK_NO_ZDOF)) + flag |= 4; + switch (flag) { + case 0: // fixed joint + break; + case 1: // X only + Mat3ToEulO(joint_mat, joints, EULER_ORDER_XYZ); + joints[1] = joints[2] = 0.f; + break; + case 2: // Y only + Mat3ToEulO(joint_mat, joints, EULER_ORDER_XYZ); + joints[0] = joints[2] = 0.f; + break; + case 3: // X+Y + Mat3ToEulO(joint_mat, joints, EULER_ORDER_ZYX); + joints[2] = 0.f; + break; + case 4: // Z only + Mat3ToEulO(joint_mat, joints, EULER_ORDER_XYZ); + joints[0] = joints[1] = 0.f; + break; + case 5: // X+Z + // decompose this as an equivalent rotation vector in X/Z plane + joints[0] = joint_mat[1][2]; + joints[2] = -joint_mat[1][0]; + norm = Normalize(joints); + if (norm < FLT_EPSILON) { + norm = (joint_mat[1][1] < 0.f) ? M_PI : 0.f; + } else { + norm = acos(joint_mat[1][1]); + } + VecMulf(joints, norm); + break; + case 6: // Y+Z + Mat3ToEulO(joint_mat, joints, EULER_ORDER_XYZ); + joints[0] = 0.f; + break; + case 7: // X+Y+Z + // equivalent axis + joints[0] = (joint_mat[1][2]-joint_mat[2][1])*0.5f; + joints[1] = (joint_mat[2][0]-joint_mat[0][2])*0.5f; + joints[2] = (joint_mat[0][1]-joint_mat[1][0])*0.5f; + sa = VecLength(joints); + ca = (joint_mat[0][0]+joint_mat[1][1]+joint_mat[1][1]-1.0f)*0.5f; + if (sa > FLT_EPSILON) { + norm = atan2(sa,ca)/sa; + } else { + if (ca < 0.0) { + norm = M_PI; + VecMulf(joints,0.f); + if (joint_mat[0][0] > 0.f) { + joints[0] = 1.0f; + } else if (joint_mat[1][1] > 0.f) { + joints[1] = 1.0f; + } else { + joints[2] = 1.0f; + } + } else { + norm = 0.0; + } + } + VecMulf(joints,norm); + break; + } + return newVectorObject(joints, 3, Py_NEW, NULL); +} + +int BL_ArmatureChannel::py_attr_set_joint_rotation(void *self_v, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +{ + BL_ArmatureChannel* self= static_cast<BL_ArmatureChannel*>(self_v); + bPoseChannel* pchan = self->m_posechannel; + PyObject *item; + float joints[3]; + float quat[4]; + + if (!PySequence_Check(value) || PySequence_Size(value) != 3) { + PyErr_SetString(PyExc_AttributeError, "expected a sequence of [3] floats"); + return PY_SET_ATTR_FAIL; + } + for (int i=0; i<3; i++) { + item = PySequence_GetItem(value, i); /* new ref */ + joints[i] = PyFloat_AsDouble(item); + Py_DECREF(item); + if (joints[i] == -1.0f && PyErr_Occurred()) { + PyErr_SetString(PyExc_AttributeError, "expected a sequence of [3] floats"); + return PY_SET_ATTR_FAIL; + } + } + + int flag = 0; + if (!(pchan->ikflag & BONE_IK_NO_XDOF)) + flag |= 1; + if (!(pchan->ikflag & BONE_IK_NO_YDOF)) + flag |= 2; + if (!(pchan->ikflag & BONE_IK_NO_ZDOF)) + flag |= 4; + QuatOne(quat); + switch (flag) { + case 0: // fixed joint + break; + case 1: // X only + joints[1] = joints[2] = 0.f; + EulOToQuat(joints, EULER_ORDER_XYZ, quat); + break; + case 2: // Y only + joints[0] = joints[2] = 0.f; + EulOToQuat(joints, EULER_ORDER_XYZ, quat); + break; + case 3: // X+Y + joints[2] = 0.f; + EulOToQuat(joints, EULER_ORDER_ZYX, quat); + break; + case 4: // Z only + joints[0] = joints[1] = 0.f; + EulOToQuat(joints, EULER_ORDER_XYZ, quat); + break; + case 5: // X+Z + // X and Z are components of an equivalent rotation axis + joints[1] = 0; + VecRotToQuat(joints, VecLength(joints), quat); + break; + case 6: // Y+Z + joints[0] = 0.f; + EulOToQuat(joints, EULER_ORDER_XYZ, quat); + break; + case 7: // X+Y+Z + // equivalent axis + VecRotToQuat(joints, VecLength(joints), quat); + break; + } + if (pchan->rotmode > 0) { + QuatToEulO(quat, joints, pchan->rotmode); + VecCopyf(pchan->eul, joints); + } else + QuatCopy(pchan->quat, quat); + return PY_SET_ATTR_SUCCESS; +} + +// ************************* +// BL_ArmatureBone +// +// Access to Bone structure +PyTypeObject BL_ArmatureBone::Type = { + PyVarObject_HEAD_INIT(NULL, 0) + "BL_ArmatureBone", + sizeof(PyObjectPlus_Proxy), + 0, + py_base_dealloc, + 0, + 0, + 0, + 0, + py_bone_repr, + 0,0,0,0,0,0,0,0,0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + 0,0,0,0,0,0,0, + Methods, + 0, + 0, + &CValue::Type, + 0,0,0,0,0,0, + py_base_new +}; + +// not used since this class is never instantiated +PyObject *BL_ArmatureBone::GetProxy() +{ + return NULL; +} +PyObject *BL_ArmatureBone::NewProxy(bool py_owns) +{ + return NULL; +} + +PyObject *BL_ArmatureBone::py_bone_repr(PyObject *self) +{ + Bone* bone = static_cast<Bone*>BGE_PROXY_PTR(self); + return PyUnicode_FromString(bone->name); +} + +PyMethodDef BL_ArmatureBone::Methods[] = { + {NULL,NULL} //Sentinel +}; + +/* no attributes on C++ class since it is never instantiated */ +PyAttributeDef BL_ArmatureBone::Attributes[] = { + { NULL } //Sentinel +}; + +// attributes that work on proxy ptr (points to a Bone structure) +PyAttributeDef BL_ArmatureBone::AttributesPtr[] = { + KX_PYATTRIBUTE_CHAR_RO("name",Bone,name), + KX_PYATTRIBUTE_FLAG_RO("connected",Bone,flag, BONE_CONNECTED), + KX_PYATTRIBUTE_FLAG_RO("hinge",Bone,flag, BONE_HINGE), + KX_PYATTRIBUTE_FLAG_NEGATIVE_RO("inherit_scale",Bone,flag, BONE_NO_SCALE), + KX_PYATTRIBUTE_SHORT_RO("bbone_segments",Bone,segments), + KX_PYATTRIBUTE_FLOAT_RO("roll",Bone,roll), + KX_PYATTRIBUTE_FLOAT_VECTOR_RO("head",Bone,head,3), + KX_PYATTRIBUTE_FLOAT_VECTOR_RO("tail",Bone,tail,3), + KX_PYATTRIBUTE_FLOAT_RO("length",Bone,length), + KX_PYATTRIBUTE_FLOAT_VECTOR_RO("arm_head",Bone,arm_head,3), + KX_PYATTRIBUTE_FLOAT_VECTOR_RO("arm_tail",Bone,arm_tail,3), + KX_PYATTRIBUTE_FLOAT_MATRIX_RO("arm_mat",Bone,arm_mat,4), + KX_PYATTRIBUTE_FLOAT_MATRIX_RO("bone_mat",Bone,bone_mat,4), + KX_PYATTRIBUTE_RO_FUNCTION("parent",BL_ArmatureBone,py_bone_get_parent), + KX_PYATTRIBUTE_RO_FUNCTION("children",BL_ArmatureBone,py_bone_get_parent), + { NULL } //Sentinel +}; + +PyObject *BL_ArmatureBone::py_bone_get_parent(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef) +{ + Bone* bone = reinterpret_cast<Bone*>BGE_PROXY_PTR(self); + if (bone->parent) { + // create a proxy unconnected to any GE object + return NewProxyPlus_Ext(NULL,&Type,bone->parent,false); + } + Py_RETURN_NONE; +} + +PyObject *BL_ArmatureBone::py_bone_get_children(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef) +{ + Bone* bone = reinterpret_cast<Bone*>BGE_PROXY_PTR(self); + Bone* child; + int count = 0; + for (child=(Bone*)bone->childbase.first; child; child=(Bone*)child->next) + count++; + + PyObject* childrenlist = PyList_New(count); + + for (count = 0, child=(Bone*)bone->childbase.first; child; child=(Bone*)child->next, ++count) + PyList_SET_ITEM(childrenlist,count,NewProxyPlus_Ext(NULL,&Type,child,false)); + + return childrenlist; +} diff --git a/source/gameengine/Converter/BL_ArmatureChannel.h b/source/gameengine/Converter/BL_ArmatureChannel.h new file mode 100644 index 00000000000..0f0f5a062e0 --- /dev/null +++ b/source/gameengine/Converter/BL_ArmatureChannel.h @@ -0,0 +1,91 @@ +/** + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ +#ifndef __BL_ARMATURECHANNEL +#define __BL_ARMATURECHANNEL + +#include "DNA_action_types.h" +#include "GEN_HashedPtr.h" +#include "GEN_Map.h" +#include "PyObjectPlus.h" + +class SCA_IObject; +class KX_GameObject; +class BL_ArmatureObject; +struct bConstraint; +struct bPoseChannel; +struct Object; +struct bPose; + +class BL_ArmatureChannel : public PyObjectPlus +{ + // use Py_HeaderPtr since we use generic pointer in proxy + Py_HeaderPtr; + +private: + friend class BL_ArmatureObject; + struct bPoseChannel* m_posechannel; + BL_ArmatureObject* m_armature; + +public: + BL_ArmatureChannel(class BL_ArmatureObject *armature, + struct bPoseChannel *posechannel); + virtual ~BL_ArmatureChannel(); + + virtual PyObject* py_repr(void); + + // Python access + static PyObject* py_attr_getattr(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef); + static int py_attr_setattr(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject* py_attr_get_joint_rotation(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef); + static int py_attr_set_joint_rotation(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); + +}; + +/* this is a factory class to access bBone data field in the GE. + It's not supposed to be instantiated, we only need it for the Attributes and Method array. + The actual proxy object will be manually created using NewProxyPtr */ +class BL_ArmatureBone : public PyObjectPlus +{ + // use Py_HeaderPtr since we use generic pointer in proxy + Py_HeaderPtr; +private: + // make constructor private to make sure no one tries to instantiate this class + BL_ArmatureBone() {} + virtual ~BL_ArmatureBone() {} + +public: + static PyObject *py_bone_repr(PyObject *self); + static PyObject *py_bone_get_parent(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef); + static PyObject *py_bone_get_children(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef); + +}; + + +#endif //__BL_ARMATURECHANNEL + diff --git a/source/gameengine/Converter/BL_ArmatureConstraint.cpp b/source/gameengine/Converter/BL_ArmatureConstraint.cpp new file mode 100644 index 00000000000..15e12611483 --- /dev/null +++ b/source/gameengine/Converter/BL_ArmatureConstraint.cpp @@ -0,0 +1,447 @@ +/** + * $Id$ + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "DNA_constraint_types.h" +#include "DNA_action_types.h" +#include "BL_ArmatureConstraint.h" +#include "BL_ArmatureObject.h" +#include "BLI_arithb.h" +#include "BLI_string.h" + +PyTypeObject BL_ArmatureConstraint::Type = { + PyVarObject_HEAD_INIT(NULL, 0) + "BL_ArmatureConstraint", + sizeof(PyObjectPlus_Proxy), + 0, + py_base_dealloc, + 0, + 0, + 0, + 0, + py_base_repr, + 0,0,0,0,0,0,0,0,0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + 0,0,0,0,0,0,0, + Methods, + 0, + 0, + &CValue::Type, + 0,0,0,0,0,0, + py_base_new +}; + +PyObject* BL_ArmatureConstraint::py_repr(void) +{ + return PyUnicode_FromString(m_name); +} + +BL_ArmatureConstraint::BL_ArmatureConstraint( + BL_ArmatureObject *armature, + bPoseChannel *posechannel, + bConstraint *constraint, + KX_GameObject* target, + KX_GameObject* subtarget) + : PyObjectPlus(), m_armature(armature), m_constraint(constraint), m_posechannel(posechannel) +{ + m_target = target; + m_blendtarget = (target) ? target->GetBlenderObject() : NULL; + m_subtarget = subtarget; + m_blendsubtarget = (subtarget) ? subtarget->GetBlenderObject() : NULL; + m_pose = m_subpose = NULL; + if (m_blendtarget) { + Mat4CpyMat4(m_blendmat, m_blendtarget->obmat); + if (m_blendtarget->type == OB_ARMATURE) + m_pose = m_blendtarget->pose; + } + if (m_blendsubtarget) { + Mat4CpyMat4(m_blendsubmat, m_blendsubtarget->obmat); + if (m_blendsubtarget->type == OB_ARMATURE) + m_subpose = m_blendsubtarget->pose; + } + if (m_target) + m_target->RegisterObject(m_armature); + if (m_subtarget) + m_subtarget->RegisterObject(m_armature); + BLI_snprintf(m_name, sizeof(m_name), "%s:%s", m_posechannel->name, m_constraint->name); +} + +BL_ArmatureConstraint::~BL_ArmatureConstraint() +{ + if (m_target) + m_target->UnregisterObject(m_armature); + if (m_subtarget) + m_subtarget->UnregisterObject(m_armature); +} + +BL_ArmatureConstraint* BL_ArmatureConstraint::GetReplica() const +{ + BL_ArmatureConstraint* replica = new BL_ArmatureConstraint(*this); + replica->ProcessReplica(); + return replica; +} + +void BL_ArmatureConstraint::ReParent(BL_ArmatureObject* armature) +{ + m_armature = armature; + if (m_target) + m_target->RegisterObject(armature); + if (m_subtarget) + m_subtarget->RegisterObject(armature); + // find the corresponding constraint in the new armature object + if (m_constraint) { + bPose* newpose = armature->GetOrigPose(); + char* constraint = m_constraint->name; + char* posechannel = m_posechannel->name; + bPoseChannel* pchan; + bConstraint* pcon; + m_constraint = NULL; + m_posechannel = NULL; + // and locate the constraint + for (pchan = (bPoseChannel*)newpose->chanbase.first; pchan; pchan=(bPoseChannel*)pchan->next) { + if (!strcmp(pchan->name, posechannel)) { + // now locate the constraint + for (pcon = (bConstraint*)pchan->constraints.first; pcon; pcon=(bConstraint*)pcon->next) { + if (!strcmp(pcon->name, constraint)) { + m_constraint = pcon; + m_posechannel = pchan; + break; + } + } + break; + } + } + } +} + +void BL_ArmatureConstraint::Relink(GEN_Map<GEN_HashedPtr, void*> *obj_map) +{ + void **h_obj = (*obj_map)[m_target]; + if (h_obj) { + m_target->UnregisterObject(m_armature); + m_target = (KX_GameObject*)(*h_obj); + m_target->RegisterObject(m_armature); + } + h_obj = (*obj_map)[m_subtarget]; + if (h_obj) { + m_subtarget->UnregisterObject(m_armature); + m_subtarget = (KX_GameObject*)(*h_obj); + m_subtarget->RegisterObject(m_armature); + } +} + +bool BL_ArmatureConstraint::UnlinkObject(SCA_IObject* clientobj) +{ + bool res=false; + if (clientobj == m_target) { + m_target = NULL; + res = true; + } + if (clientobj == m_subtarget) { + m_subtarget = NULL; + res = true; + } + return res; +} + +void BL_ArmatureConstraint::UpdateTarget() +{ + if (m_constraint && !(m_constraint->flag&CONSTRAINT_OFF) && (!m_blendtarget || m_target)) { + if (m_blendtarget) { + // external target, must be updated + m_target->UpdateBlenderObjectMatrix(m_blendtarget); + if (m_pose && m_target->GetGameObjectType() == SCA_IObject::OBJ_ARMATURE) + // update the pose in case a bone is specified in the constraint target + m_blendtarget->pose = ((BL_ArmatureObject*)m_target)->GetOrigPose(); + } + if (m_blendsubtarget && m_subtarget) { + m_subtarget->UpdateBlenderObjectMatrix(m_blendsubtarget); + if (m_subpose && m_subtarget->GetGameObjectType() == SCA_IObject::OBJ_ARMATURE) + m_blendsubtarget->pose = ((BL_ArmatureObject*)m_target)->GetOrigPose(); + } + } +} + +void BL_ArmatureConstraint::RestoreTarget() +{ + if (m_constraint && !(m_constraint->flag&CONSTRAINT_OFF) && (!m_blendtarget || m_target)) { + if (m_blendtarget) { + Mat4CpyMat4(m_blendtarget->obmat, m_blendmat); + if (m_pose) + m_blendtarget->pose = m_pose; + } + if (m_blendsubtarget && m_subtarget) { + Mat4CpyMat4(m_blendsubtarget->obmat, m_blendsubmat); + if (m_subpose) + m_blendsubtarget->pose = m_subpose; + } + } +} + +bool BL_ArmatureConstraint::Match(const char* posechannel, const char* constraint) +{ + return (!strcmp(m_posechannel->name, posechannel) && !strcmp(m_constraint->name, constraint)); +} + +void BL_ArmatureConstraint::SetTarget(KX_GameObject* target) +{ + if (m_blendtarget) { + if (target != m_target) { + m_target->UnregisterObject(m_armature); + m_target = target; + if (m_target) + m_target->RegisterObject(m_armature); + } + } + +} + +void BL_ArmatureConstraint::SetSubtarget(KX_GameObject* subtarget) +{ + if (m_blendsubtarget) { + if (subtarget != m_subtarget) { + m_subtarget->UnregisterObject(m_armature); + m_subtarget = subtarget; + if (m_subtarget) + m_subtarget->RegisterObject(m_armature); + } + } + +} + +// PYTHON + +PyMethodDef BL_ArmatureConstraint::Methods[] = { + {NULL,NULL} //Sentinel +}; + +// order of definition of attributes, must match Attributes[] array +#define BCA_TYPE 0 +#define BCA_NAME 1 +#define BCA_ENFORCE 2 +#define BCA_HEADTAIL 3 +#define BCA_LINERROR 4 +#define BCA_ROTERROR 5 +#define BCA_TARGET 6 +#define BCA_SUBTARGET 7 +#define BCA_ACTIVE 8 +#define BCA_IKWEIGHT 9 +#define BCA_IKTYPE 10 +#define BCA_IKFLAG 11 +#define BCA_IKDIST 12 +#define BCA_IKMODE 13 + +PyAttributeDef BL_ArmatureConstraint::Attributes[] = { + // Keep these attributes in order of BCA_ defines!!! used by py_attr_getattr and py_attr_setattr + KX_PYATTRIBUTE_RO_FUNCTION("type",BL_ArmatureConstraint,py_attr_getattr), + KX_PYATTRIBUTE_RO_FUNCTION("name",BL_ArmatureConstraint,py_attr_getattr), + KX_PYATTRIBUTE_RW_FUNCTION("enforce",BL_ArmatureConstraint,py_attr_getattr,py_attr_setattr), + KX_PYATTRIBUTE_RW_FUNCTION("headtail",BL_ArmatureConstraint,py_attr_getattr,py_attr_setattr), + KX_PYATTRIBUTE_RO_FUNCTION("lin_error",BL_ArmatureConstraint,py_attr_getattr), + KX_PYATTRIBUTE_RO_FUNCTION("rot_error",BL_ArmatureConstraint,py_attr_getattr), + KX_PYATTRIBUTE_RW_FUNCTION("target",BL_ArmatureConstraint,py_attr_getattr,py_attr_setattr), + KX_PYATTRIBUTE_RW_FUNCTION("subtarget",BL_ArmatureConstraint,py_attr_getattr,py_attr_setattr), + KX_PYATTRIBUTE_RW_FUNCTION("active",BL_ArmatureConstraint,py_attr_getattr,py_attr_setattr), + KX_PYATTRIBUTE_RW_FUNCTION("ik_weight",BL_ArmatureConstraint,py_attr_getattr,py_attr_setattr), + KX_PYATTRIBUTE_RO_FUNCTION("ik_type",BL_ArmatureConstraint,py_attr_getattr), + KX_PYATTRIBUTE_RO_FUNCTION("ik_flag",BL_ArmatureConstraint,py_attr_getattr), + KX_PYATTRIBUTE_RW_FUNCTION("ik_dist",BL_ArmatureConstraint,py_attr_getattr,py_attr_setattr), + KX_PYATTRIBUTE_RW_FUNCTION("ik_mode",BL_ArmatureConstraint,py_attr_getattr,py_attr_setattr), + + { NULL } //Sentinel +}; + + +PyObject* BL_ArmatureConstraint::py_attr_getattr(void *self_v, const struct KX_PYATTRIBUTE_DEF *attrdef) +{ + BL_ArmatureConstraint* self= static_cast<BL_ArmatureConstraint*>(self_v); + bConstraint* constraint = self->m_constraint; + bKinematicConstraint* ikconstraint = (constraint && constraint->type == CONSTRAINT_TYPE_KINEMATIC) ? (bKinematicConstraint*)constraint->data : NULL; + int attr_order = attrdef-Attributes; + + if (!constraint) { + PyErr_SetString(PyExc_AttributeError, "constraint is NULL"); + return NULL; + } + + switch (attr_order) { + case BCA_TYPE: + return PyLong_FromLong(constraint->type); + case BCA_NAME: + return PyUnicode_FromString(constraint->name); + case BCA_ENFORCE: + return PyFloat_FromDouble(constraint->enforce); + case BCA_HEADTAIL: + return PyFloat_FromDouble(constraint->headtail); + case BCA_LINERROR: + return PyFloat_FromDouble(constraint->lin_error); + case BCA_ROTERROR: + return PyFloat_FromDouble(constraint->rot_error); + case BCA_TARGET: + if (!self->m_target) + Py_RETURN_NONE; + else + return self->m_target->GetProxy(); + case BCA_SUBTARGET: + if (!self->m_subtarget) + Py_RETURN_NONE; + else + return self->m_subtarget->GetProxy(); + case BCA_ACTIVE: + return PyBool_FromLong(constraint->flag & CONSTRAINT_OFF); + case BCA_IKWEIGHT: + case BCA_IKTYPE: + case BCA_IKFLAG: + case BCA_IKDIST: + case BCA_IKMODE: + if (!ikconstraint) { + PyErr_SetString(PyExc_AttributeError, "constraint is not of IK type"); + return NULL; + } + switch (attr_order) { + case BCA_IKWEIGHT: + return PyFloat_FromDouble((ikconstraint)?ikconstraint->weight:0.0); + case BCA_IKTYPE: + return PyLong_FromLong(ikconstraint->type); + case BCA_IKFLAG: + return PyLong_FromLong(ikconstraint->flag); + case BCA_IKDIST: + return PyFloat_FromDouble(ikconstraint->dist); + case BCA_IKMODE: + return PyLong_FromLong(ikconstraint->mode); + } + // should not come here + break; + } + PyErr_SetString(PyExc_AttributeError, "constraint unknown attribute"); + return NULL; +} + +int BL_ArmatureConstraint::py_attr_setattr(void *self_v, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +{ + BL_ArmatureConstraint* self= static_cast<BL_ArmatureConstraint*>(self_v); + bConstraint* constraint = self->m_constraint; + bKinematicConstraint* ikconstraint = (constraint && constraint->type == CONSTRAINT_TYPE_KINEMATIC) ? (bKinematicConstraint*)constraint->data : NULL; + int attr_order = attrdef-Attributes; + int ival; + double dval; + char* sval; + KX_GameObject *oval; + + if (!constraint) { + PyErr_SetString(PyExc_AttributeError, "constraint is NULL"); + return PY_SET_ATTR_FAIL; + } + + switch (attr_order) { + case BCA_ENFORCE: + dval = PyFloat_AsDouble(value); + if (dval < 0.0f || dval > 1.0f) { /* also accounts for non float */ + PyErr_SetString(PyExc_AttributeError, "constraint.enforce = float: BL_ArmatureConstraint, expected a float between 0 and 1"); + return PY_SET_ATTR_FAIL; + } + constraint->enforce = dval; + return PY_SET_ATTR_SUCCESS; + + case BCA_HEADTAIL: + dval = PyFloat_AsDouble(value); + if (dval < 0.0f || dval > 1.0f) { /* also accounts for non float */ + PyErr_SetString(PyExc_AttributeError, "constraint.headtail = float: BL_ArmatureConstraint, expected a float between 0 and 1"); + return PY_SET_ATTR_FAIL; + } + constraint->headtail = dval; + return PY_SET_ATTR_SUCCESS; + + case BCA_TARGET: + if (!ConvertPythonToGameObject(value, &oval, true, "constraint.target = value: BL_ArmatureConstraint")) + return PY_SET_ATTR_FAIL; // ConvertPythonToGameObject sets the error + self->SetTarget(oval); + return PY_SET_ATTR_SUCCESS; + + case BCA_SUBTARGET: + if (!ConvertPythonToGameObject(value, &oval, true, "constraint.subtarget = value: BL_ArmatureConstraint")) + return PY_SET_ATTR_FAIL; // ConvertPythonToGameObject sets the error + self->SetSubtarget(oval); + return PY_SET_ATTR_SUCCESS; + + case BCA_ACTIVE: + ival = PyObject_IsTrue( value ); + if (ival == -1) { + PyErr_SetString(PyExc_AttributeError, "constraint.active = bool: BL_ArmatureConstraint, expected True or False"); + return PY_SET_ATTR_FAIL; + } + self->m_constraint->flag = (self->m_constraint->flag & ~CONSTRAINT_OFF) | ((ival)?0:CONSTRAINT_OFF); + return PY_SET_ATTR_SUCCESS; + + case BCA_IKWEIGHT: + case BCA_IKDIST: + case BCA_IKMODE: + if (!ikconstraint) { + PyErr_SetString(PyExc_AttributeError, "constraint is not of IK type"); + return PY_SET_ATTR_FAIL; + } + switch (attr_order) { + case BCA_IKWEIGHT: + dval = PyFloat_AsDouble(value); + if (dval < 0.0f || dval > 1.0f) { /* also accounts for non float */ + PyErr_SetString(PyExc_AttributeError, "constraint.weight = float: BL_ArmatureConstraint, expected a float between 0 and 1"); + return PY_SET_ATTR_FAIL; + } + ikconstraint->weight = dval; + return PY_SET_ATTR_SUCCESS; + + case BCA_IKDIST: + dval = PyFloat_AsDouble(value); + if (dval < 0.0f) { /* also accounts for non float */ + PyErr_SetString(PyExc_AttributeError, "constraint.ik_dist = float: BL_ArmatureConstraint, expected a positive float"); + return PY_SET_ATTR_FAIL; + } + ikconstraint->dist = dval; + return PY_SET_ATTR_SUCCESS; + + case BCA_IKMODE: + ival = PyLong_AsLong(value); + if (ival < 0) { + PyErr_SetString(PyExc_AttributeError, "constraint.ik_mode = integer: BL_ArmatureConstraint, expected a positive integer"); + return PY_SET_ATTR_FAIL; + } + ikconstraint->mode = ival; + return PY_SET_ATTR_SUCCESS; + } + // should not come here + break; + + } + + PyErr_SetString(PyExc_AttributeError, "constraint unknown attribute"); + return PY_SET_ATTR_FAIL; +} + diff --git a/source/gameengine/Converter/BL_ArmatureConstraint.h b/source/gameengine/Converter/BL_ArmatureConstraint.h new file mode 100644 index 00000000000..f10849ea05b --- /dev/null +++ b/source/gameengine/Converter/BL_ArmatureConstraint.h @@ -0,0 +1,117 @@ +/** + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ +#ifndef __BL_ARMATURECONSTRAINT +#define __BL_ARMATURECONSTRAINT + +#include "DNA_constraint_types.h" +#include "GEN_HashedPtr.h" +#include "GEN_Map.h" +#include "PyObjectPlus.h" + +class SCA_IObject; +class KX_GameObject; +class BL_ArmatureObject; +struct bConstraint; +struct bPoseChannel; +struct Object; +struct bPose; + +/** + * SG_DList : element of controlled constraint list + * head = BL_ArmatureObject::m_controlledConstraints + * SG_QList : not used + */ +class BL_ArmatureConstraint : public PyObjectPlus +{ + Py_Header; + +private: + struct bConstraint* m_constraint; + struct bPoseChannel* m_posechannel; + class BL_ArmatureObject* m_armature; + char m_name[64]; + KX_GameObject* m_target; + KX_GameObject* m_subtarget; + struct Object* m_blendtarget; + struct Object* m_blendsubtarget; + float m_blendmat[4][4]; + float m_blendsubmat[4][4]; + struct bPose* m_pose; + struct bPose* m_subpose; + +public: + BL_ArmatureConstraint(class BL_ArmatureObject *armature, + struct bPoseChannel *posechannel, + struct bConstraint *constraint, + KX_GameObject* target, + KX_GameObject* subtarget); + virtual ~BL_ArmatureConstraint(); + + + virtual PyObject* py_repr(void); + + BL_ArmatureConstraint* GetReplica() const; + void ReParent(BL_ArmatureObject* armature); + void Relink(GEN_Map<GEN_HashedPtr, void*> *map); + bool UnlinkObject(SCA_IObject* clientobj); + + void UpdateTarget(); + void RestoreTarget(); + + bool Match(const char* posechannel, const char* constraint); + const char* GetName() { return m_name; } + + void SetConstraintFlag(int flag) + { + if (m_constraint) + m_constraint->flag |= flag; + } + void ClrConstraintFlag(int flag) + { + if (m_constraint) + m_constraint->flag &= ~flag; + } + void SetWeight(float weight) + { + if (m_constraint && m_constraint->type == CONSTRAINT_TYPE_KINEMATIC && m_constraint->data) { + bKinematicConstraint* con = (bKinematicConstraint*)m_constraint->data; + con->weight = weight; + } + } + void SetTarget(KX_GameObject* target); + void SetSubtarget(KX_GameObject* subtarget); + + // Python access + static PyObject* py_attr_getattr(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef); + static int py_attr_setattr(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); + +}; + +#endif //__BL_ARMATURECONSTRAINT + diff --git a/source/gameengine/Converter/BL_ArmatureObject.cpp b/source/gameengine/Converter/BL_ArmatureObject.cpp index cfd90813a16..d5660d9ef84 100644 --- a/source/gameengine/Converter/BL_ArmatureObject.cpp +++ b/source/gameengine/Converter/BL_ArmatureObject.cpp @@ -29,9 +29,15 @@ #include "BL_ArmatureObject.h" #include "BL_ActionActuator.h" +#include "KX_BlenderSceneConverter.h" #include "BLI_blenlib.h" +#include "BLI_ghash.h" +#include "BLI_arithb.h" +#include "BIK_api.h" #include "BKE_action.h" #include "BKE_armature.h" +#include "BKE_utildefines.h" +#include "BKE_constraint.h" #include "GEN_Map.h" #include "GEN_HashedPtr.h" #include "MEM_guardedalloc.h" @@ -39,6 +45,11 @@ #include "DNA_armature_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" +#include "DNA_nla_types.h" +#include "DNA_constraint_types.h" +#include "KX_PythonSeq.h" +#include "KX_PythonInit.h" +#include "KX_KetsjiEngine.h" #include "MT_Matrix4x4.h" @@ -46,6 +57,153 @@ #include <config.h> #endif +/** + * Move here pose function for game engine so that we can mix with GE objects + * Principle is as follow: + * Use Blender structures so that where_is_pose can be used unchanged + * Copy the constraint so that they can be enabled/disabled/added/removed at runtime + * Don't copy the constraints for the pose used by the Action actuator, it does not need them. + * Scan the constraint structures so that the KX equivalent of target objects are identified and + * stored in separate list. + * When it is about to evaluate the pose, set the KX object position in the obmat of the corresponding + * Blender objects and restore after the evaluation. + */ +void game_copy_pose(bPose **dst, bPose *src, int copy_constraint) +{ + 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. */ + + if (!src) { + *dst=NULL; + return; + } + else if (*dst==src) { + printf("copy_pose source and target are the same\n"); + *dst=NULL; + return; + } + + out= (bPose*)MEM_dupallocN(src); + out->agroups.first= out->agroups.last= NULL; + out->ikdata = NULL; + out->ikparam = MEM_dupallocN(out->ikparam); + out->flag |= POSE_GAME_ENGINE; + BLI_duplicatelist(&out->chanbase, &src->chanbase); + + /* remap pointers */ + ghash= BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp); + + pchan= (bPoseChannel*)src->chanbase.first; + outpchan= (bPoseChannel*)out->chanbase.first; + for (; pchan; pchan=pchan->next, outpchan=outpchan->next) + BLI_ghash_insert(ghash, pchan, outpchan); + + for (pchan=(bPoseChannel*)out->chanbase.first; pchan; pchan=(bPoseChannel*)pchan->next) { + pchan->parent= (bPoseChannel*)BLI_ghash_lookup(ghash, pchan->parent); + pchan->child= (bPoseChannel*)BLI_ghash_lookup(ghash, pchan->child); + pchan->path= NULL; + + if (copy_constraint) { + ListBase listb; + // copy all constraint for backward compatibility + copy_constraints(&listb, &pchan->constraints); // copy_constraints NULLs listb + pchan->constraints= listb; + } else { + pchan->constraints.first = NULL; + pchan->constraints.last = 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= (bPoseChannel*)src->chanbase.first; + for (dchan = (bPoseChannel*)dst->chanbase.first; dchan; dchan=(bPoseChannel*)dchan->next, schan= (bPoseChannel*)schan->next){ + // always blend on all channels since we don't know which one has been set + /* 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... */ + dchan->loc[i] = (dchan->loc[i]*dstweight) + (schan->loc[i]*srcweight); + 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->rotmode) + dchan->eul[i] = (dchan->eul[i]*dstweight) + (schan->eul[i]*srcweight); + } + for(dcon= (bConstraint*)dchan->constraints.first, scon= (bConstraint*)schan->constraints.first; dcon && scon; dcon= (bConstraint*)dcon->next, scon= (bConstraint*)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; +} + +void game_free_pose(bPose *pose) +{ + if (pose) { + /* free pose-channels and constraints */ + free_pose_channels(pose); + + /* free IK solver state */ + BIK_clear_data(pose); + + /* free IK solver param */ + if (pose->ikparam) + MEM_freeN(pose->ikparam); + + MEM_freeN(pose); + } +} + BL_ArmatureObject::BL_ArmatureObject( void* sgReplicationInfo, SG_Callbacks callbacks, @@ -53,12 +211,17 @@ BL_ArmatureObject::BL_ArmatureObject( Scene *scene) : KX_GameObject(sgReplicationInfo,callbacks), + m_controlledConstraints(), + m_poseChannels(), m_objArma(armature), m_framePose(NULL), m_scene(scene), // maybe remove later. needed for where_is_pose m_lastframe(0.0), + m_timestep(0.040), m_activeAct(NULL), m_activePriority(999), + m_constraintNumber(0), + m_channelNumber(0), m_lastapplyframe(0.0) { m_armature = (bArmature *)armature->data; @@ -67,7 +230,177 @@ BL_ArmatureObject::BL_ArmatureObject( * the original pose before calling into blender functions, to deal with * replica's or other objects using the same blender object */ m_pose = NULL; - game_copy_pose(&m_pose, m_objArma->pose); + game_copy_pose(&m_pose, m_objArma->pose, 1); + // store the original armature object matrix + memcpy(m_obmat, m_objArma->obmat, sizeof(m_obmat)); +} + +BL_ArmatureObject::~BL_ArmatureObject() +{ + BL_ArmatureConstraint* constraint; + while ((constraint = m_controlledConstraints.Remove()) != NULL) { + delete constraint; + } + BL_ArmatureChannel* channel; + while ((channel = static_cast<BL_ArmatureChannel*>(m_poseChannels.Remove())) != NULL) { + delete channel; + } + if (m_pose) + game_free_pose(m_pose); + if (m_framePose) + game_free_pose(m_framePose); +} + + +void BL_ArmatureObject::LoadConstraints(KX_BlenderSceneConverter* converter) +{ + // first delete any existing constraint (should not have any) + while (!m_controlledConstraints.Empty()) { + BL_ArmatureConstraint* constraint = m_controlledConstraints.Remove(); + delete constraint; + } + m_constraintNumber = 0; + + // list all the constraint and convert them to BL_ArmatureConstraint + // get the persistent pose structure + bPoseChannel* pchan; + bConstraint* pcon; + bConstraintTypeInfo* cti; + Object* blendtarget; + KX_GameObject* gametarget; + KX_GameObject* gamesubtarget; + + // and locate the constraint + for (pchan = (bPoseChannel*)m_pose->chanbase.first; pchan; pchan=(bPoseChannel*)pchan->next) { + for (pcon = (bConstraint*)pchan->constraints.first; pcon; pcon=(bConstraint*)pcon->next) { + if (pcon->flag & CONSTRAINT_DISABLE) + continue; + // which constraint should we support? + switch (pcon->type) { + case CONSTRAINT_TYPE_TRACKTO: + case CONSTRAINT_TYPE_KINEMATIC: + case CONSTRAINT_TYPE_ROTLIKE: + case CONSTRAINT_TYPE_LOCLIKE: + case CONSTRAINT_TYPE_MINMAX: + case CONSTRAINT_TYPE_SIZELIKE: + case CONSTRAINT_TYPE_LOCKTRACK: + case CONSTRAINT_TYPE_STRETCHTO: + case CONSTRAINT_TYPE_CLAMPTO: + case CONSTRAINT_TYPE_TRANSFORM: + case CONSTRAINT_TYPE_DISTLIMIT: + cti = constraint_get_typeinfo(pcon); + gametarget = gamesubtarget = NULL; + if (cti && cti->get_constraint_targets) { + ListBase listb = { NULL, NULL }; + cti->get_constraint_targets(pcon, &listb); + if (listb.first) { + bConstraintTarget* target = (bConstraintTarget*)listb.first; + if (target->tar && target->tar != m_objArma) { + // only remember external objects, self target is handled automatically + blendtarget = target->tar; + gametarget = converter->FindGameObject(blendtarget); + } + if (target->next != NULL) { + // secondary target + target = (bConstraintTarget*)target->next; + if (target->tar && target->tar != m_objArma) { + // only track external object + blendtarget = target->tar; + gamesubtarget = converter->FindGameObject(blendtarget); + } + } + } + if (cti->flush_constraint_targets) + cti->flush_constraint_targets(pcon, &listb, 1); + } + BL_ArmatureConstraint* constraint = new BL_ArmatureConstraint(this, pchan, pcon, gametarget, gamesubtarget); + m_controlledConstraints.AddBack(constraint); + m_constraintNumber++; + } + } + } +} + +BL_ArmatureConstraint* BL_ArmatureObject::GetConstraint(const char* posechannel, const char* constraintname) +{ + SG_DList::iterator<BL_ArmatureConstraint> cit(m_controlledConstraints); + for (cit.begin(); !cit.end(); ++cit) { + BL_ArmatureConstraint* constraint = *cit; + if (constraint->Match(posechannel, constraintname)) + return constraint; + } + return NULL; +} + +BL_ArmatureConstraint* BL_ArmatureObject::GetConstraint(const char* posechannelconstraint) +{ + // performance: use hash string instead of plain string compare + SG_DList::iterator<BL_ArmatureConstraint> cit(m_controlledConstraints); + for (cit.begin(); !cit.end(); ++cit) { + BL_ArmatureConstraint* constraint = *cit; + if (!strcmp(constraint->GetName(), posechannelconstraint)) + return constraint; + } + return NULL; +} + +BL_ArmatureConstraint* BL_ArmatureObject::GetConstraint(int index) +{ + SG_DList::iterator<BL_ArmatureConstraint> cit(m_controlledConstraints); + for (cit.begin(); !cit.end() && index; ++cit, --index); + return (cit.end()) ? NULL : *cit; +} + +/* this function is called to populate the m_poseChannels list */ +void BL_ArmatureObject::LoadChannels() +{ + if (m_poseChannels.Empty()) { + bPoseChannel* pchan; + BL_ArmatureChannel* proxy; + + m_channelNumber = 0; + for (pchan = (bPoseChannel*)m_pose->chanbase.first; pchan; pchan=(bPoseChannel*)pchan->next) { + proxy = new BL_ArmatureChannel(this, pchan); + m_poseChannels.AddBack(proxy); + m_channelNumber++; + } + } +} + +BL_ArmatureChannel* BL_ArmatureObject::GetChannel(bPoseChannel* pchan) +{ + LoadChannels(); + SG_DList::iterator<BL_ArmatureChannel> cit(m_poseChannels); + for (cit.begin(); !cit.end(); ++cit) + { + BL_ArmatureChannel* channel = *cit; + if (channel->m_posechannel == pchan) + return channel; + } + return NULL; +} + +BL_ArmatureChannel* BL_ArmatureObject::GetChannel(const char* str) +{ + LoadChannels(); + SG_DList::iterator<BL_ArmatureChannel> cit(m_poseChannels); + for (cit.begin(); !cit.end(); ++cit) + { + BL_ArmatureChannel* channel = *cit; + if (!strcmp(channel->m_posechannel->name, str)) + return channel; + } + return NULL; +} + +BL_ArmatureChannel* BL_ArmatureObject::GetChannel(int index) +{ + LoadChannels(); + if (index < 0 || index >= m_channelNumber) + return NULL; + SG_DList::iterator<BL_ArmatureChannel> cit(m_poseChannels); + for (cit.begin(); !cit.end() && index; ++cit, --index); + return (cit.end()) ? NULL : *cit; } CValue* BL_ArmatureObject::GetReplica() @@ -83,22 +416,61 @@ void BL_ArmatureObject::ProcessReplica() KX_GameObject::ProcessReplica(); m_pose = NULL; - game_copy_pose(&m_pose, pose); + m_framePose = NULL; + game_copy_pose(&m_pose, pose, 1); } -BL_ArmatureObject::~BL_ArmatureObject() +void BL_ArmatureObject::ReParentLogic() { - if (m_pose) - game_free_pose(m_pose); + SG_DList::iterator<BL_ArmatureConstraint> cit(m_controlledConstraints); + for (cit.begin(); !cit.end(); ++cit) { + (*cit)->ReParent(this); + } + KX_GameObject::ReParentLogic(); +} + +void BL_ArmatureObject::Relink(GEN_Map<GEN_HashedPtr, void*> *obj_map) +{ + SG_DList::iterator<BL_ArmatureConstraint> cit(m_controlledConstraints); + for (cit.begin(); !cit.end(); ++cit) { + (*cit)->Relink(obj_map); + } + KX_GameObject::Relink(obj_map); +} + +bool BL_ArmatureObject::UnlinkObject(SCA_IObject* clientobj) +{ + // clientobj is being deleted, make sure we don't hold any reference to it + bool res = false; + SG_DList::iterator<BL_ArmatureConstraint> cit(m_controlledConstraints); + for (cit.begin(); !cit.end(); ++cit) { + res |= (*cit)->UnlinkObject(clientobj); + } + return res; } void BL_ArmatureObject::ApplyPose() { m_armpose = m_objArma->pose; m_objArma->pose = m_pose; + // in the GE, we use ctime to store the timestep + m_pose->ctime = (float)m_timestep; //m_scene->r.cfra++; if(m_lastapplyframe != m_lastframe) { + // update the constraint if any, first put them all off so that only the active ones will be updated + SG_DList::iterator<BL_ArmatureConstraint> cit(m_controlledConstraints); + for (cit.begin(); !cit.end(); ++cit) { + (*cit)->UpdateTarget(); + } + // update ourself + UpdateBlenderObjectMatrix(m_objArma); where_is_pose(m_scene, m_objArma); // XXX + // restore ourself + memcpy(m_objArma->obmat, m_obmat, sizeof(m_obmat)); + // restore active targets + for (cit.begin(); !cit.end(); ++cit) { + (*cit)->RestoreTarget(); + } m_lastapplyframe = m_lastframe; } } @@ -119,30 +491,37 @@ bool BL_ArmatureObject::SetActiveAction(BL_ActionActuator *act, short priority, { if (curtime != m_lastframe){ m_activePriority = 9999; + // compute the timestep for the underlying IK algorithm + m_timestep = curtime-m_lastframe; m_lastframe= curtime; m_activeAct = NULL; // remember the pose at the start of the frame - m_framePose = m_pose; + GetPose(&m_framePose); } - if (priority<=m_activePriority) + if (act) { - if (priority<m_activePriority) - // this action overwrites the previous ones, start from initial pose to cancel their effects - m_pose = m_framePose; - if (m_activeAct && (m_activeAct!=act)) - m_activeAct->SetBlendTime(0.0); /* Reset the blend timer */ - m_activeAct = act; - m_activePriority = priority; - m_lastframe = curtime; - - return true; - } - else{ - act->SetBlendTime(0.0); - return false; + if (priority<=m_activePriority) + { + if (priority<m_activePriority) { + // this action overwrites the previous ones, start from initial pose to cancel their effects + SetPose(m_framePose); + if (m_activeAct && (m_activeAct!=act)) + /* Reset the blend timer since this new action cancels the old one */ + m_activeAct->SetBlendTime(0.0); + } + m_activeAct = act; + m_activePriority = priority; + m_lastframe = curtime; + + return true; + } + else{ + act->SetBlendTime(0.0); + return false; + } } - + return false; } BL_ActionActuator * BL_ArmatureObject::GetActiveAction() @@ -161,7 +540,7 @@ void BL_ArmatureObject::GetPose(bPose **pose) a crash and memory leakage when &BL_ActionActuator::m_pose is freed */ - game_copy_pose(pose, m_pose); + game_copy_pose(pose, m_pose, 0); } else { if (*pose == m_pose) @@ -178,7 +557,7 @@ void BL_ArmatureObject::GetMRDPose(bPose **pose) /* Otherwise, copy the armature's pose channels into the caller-supplied pose */ if (!*pose) - game_copy_pose(pose, m_pose); + game_copy_pose(pose, m_pose, 0); else extract_pose_from_pose(*pose, m_pose); } @@ -210,3 +589,68 @@ float BL_ArmatureObject::GetBoneLength(Bone* bone) const { return (float)(MT_Point3(bone->head) - MT_Point3(bone->tail)).length(); } + +// PYTHON + +PyTypeObject BL_ArmatureObject::Type = { + PyVarObject_HEAD_INIT(NULL, 0) + "BL_ArmatureObject", + sizeof(PyObjectPlus_Proxy), + 0, + py_base_dealloc, + 0, + 0, + 0, + 0, + py_base_repr, + 0, + &KX_GameObject::Sequence, + &KX_GameObject::Mapping, + 0,0,0, + NULL, + NULL, + 0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + 0,0,0,0,0,0,0, + Methods, + 0, + 0, + &KX_GameObject::Type, + 0,0,0,0,0,0, + py_base_new +}; + +PyMethodDef BL_ArmatureObject::Methods[] = { + + KX_PYMETHODTABLE_NOARGS(BL_ArmatureObject, update), + {NULL,NULL} //Sentinel +}; + +PyAttributeDef BL_ArmatureObject::Attributes[] = { + + KX_PYATTRIBUTE_RO_FUNCTION("constraints", BL_ArmatureObject, pyattr_get_constraints), + KX_PYATTRIBUTE_RO_FUNCTION("channels", BL_ArmatureObject, pyattr_get_channels), + {NULL} //Sentinel +}; + +PyObject* BL_ArmatureObject::pyattr_get_constraints(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +{ + return KX_PythonSeq_CreatePyObject((static_cast<BL_ArmatureObject*>(self_v))->m_proxy, KX_PYGENSEQ_OB_TYPE_CONSTRAINTS); +} + +PyObject* BL_ArmatureObject::pyattr_get_channels(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +{ + BL_ArmatureObject* self = static_cast<BL_ArmatureObject*>(self_v); + self->LoadChannels(); // make sure we have the channels + return KX_PythonSeq_CreatePyObject((static_cast<BL_ArmatureObject*>(self_v))->m_proxy, KX_PYGENSEQ_OB_TYPE_CHANNELS); +} + +KX_PYMETHODDEF_DOC_NOARGS(BL_ArmatureObject, update, + "update()\n" + "Make sure that the armature will be updated on next graphic frame.\n" + "This is automatically done if a KX_ArmatureActuator with mode run is active\n" + "or if an action is playing. This function is usefull in other cases.\n") +{ + SetActiveAction(NULL, 0, KX_GetActiveEngine()->GetFrameTime()); + Py_RETURN_NONE; +} diff --git a/source/gameengine/Converter/BL_ArmatureObject.h b/source/gameengine/Converter/BL_ArmatureObject.h index af0b7dc201c..8e3d5734b73 100644 --- a/source/gameengine/Converter/BL_ArmatureObject.h +++ b/source/gameengine/Converter/BL_ArmatureObject.h @@ -31,21 +31,34 @@ #define BL_ARMATUREOBJECT #include "KX_GameObject.h" +#include "BL_ArmatureConstraint.h" +#include "BL_ArmatureChannel.h" #include "SG_IObject.h" +#include <vector> +#include <algorithm> struct bArmature; struct Bone; +struct bConstraint; class BL_ActionActuator; +class BL_ArmatureActuator; class MT_Matrix4x4; struct Object; +class KX_BlenderSceneConverter; class BL_ArmatureObject : public KX_GameObject { + Py_Header; public: + double GetLastFrame (); short GetActivePriority(); virtual void ProcessReplica(); + virtual void ReParentLogic(); + virtual void Relink(GEN_Map<GEN_HashedPtr, void*> *obj_map); + virtual bool UnlinkObject(SCA_IObject* clientobj); + class BL_ActionActuator * GetActiveAction(); BL_ArmatureObject( @@ -73,6 +86,19 @@ public: Object* GetArmatureObject() {return m_objArma;} + // for constraint python API + void LoadConstraints(KX_BlenderSceneConverter* converter); + size_t GetConstraintNumber() const { return m_constraintNumber; } + BL_ArmatureConstraint* GetConstraint(const char* posechannel, const char* constraint); + BL_ArmatureConstraint* GetConstraint(const char* posechannelconstraint); + BL_ArmatureConstraint* GetConstraint(int index); + // for pose channel python API + void LoadChannels(); + size_t GetChannelNumber() const { return m_constraintNumber; } + BL_ArmatureChannel* GetChannel(bPoseChannel* channel); + BL_ArmatureChannel* GetChannel(const char* channel); + BL_ArmatureChannel* GetChannel(int index); + /// Retrieve the pose matrix for the specified bone. /// Returns true on success. bool GetBoneMatrix(Bone* bone, MT_Matrix4x4& matrix); @@ -81,7 +107,17 @@ public: float GetBoneLength(Bone* bone) const; virtual int GetGameObjectType() { return OBJ_ARMATURE; } + + // PYTHON + static PyObject* pyattr_get_constraints(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); + static PyObject* pyattr_get_channels(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); + KX_PYMETHOD_DOC_NOARGS(BL_ArmatureObject, update); + protected: + /* list element: BL_ArmatureConstraint. Use SG_DListHead to have automatic list replication */ + SG_DListHead<BL_ArmatureConstraint> m_controlledConstraints; + /* list element: BL_ArmatureChannel. Use SG_DList to avoid list replication */ + SG_DList m_poseChannels; Object *m_objArma; struct bArmature *m_armature; struct bPose *m_pose; @@ -89,18 +125,23 @@ protected: struct bPose *m_framePose; struct Scene *m_scene; // need for where_is_pose double m_lastframe; + double m_timestep; // delta since last pose evaluation. class BL_ActionActuator *m_activeAct; short m_activePriority; + size_t m_constraintNumber; + size_t m_channelNumber; + // store the original armature object matrix + float m_obmat[4][4]; double m_lastapplyframe; +}; +/* Pose function specific to the 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); +void game_copy_pose(struct bPose **dst, struct bPose *src, int copy_con); +void game_free_pose(struct bPose *pose); -#ifdef WITH_CXX_GUARDEDALLOC -public: - void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:BL_ArmatureObject"); } - void operator delete( void *mem ) { MEM_freeN(mem); } -#endif -}; #endif diff --git a/source/gameengine/Converter/BL_BlenderDataConversion.cpp b/source/gameengine/Converter/BL_BlenderDataConversion.cpp index 230820719aa..8feae48f12e 100644 --- a/source/gameengine/Converter/BL_BlenderDataConversion.cpp +++ b/source/gameengine/Converter/BL_BlenderDataConversion.cpp @@ -2501,6 +2501,14 @@ void BL_ConvertBlenderObjects(struct Main* maggie, gameobj->GetDeformer()->UpdateBuckets(); } + // Set up armature constraints + for (i=0;i<sumolist->GetCount();++i) + { + KX_GameObject* gameobj = (KX_GameObject*) sumolist->GetValue(i); + if (gameobj->GetGameObjectType() == SCA_IObject::OBJ_ARMATURE) + ((BL_ArmatureObject*)gameobj)->LoadConstraints(converter); + } + bool processCompoundChildren = false; // create physics information diff --git a/source/gameengine/Converter/BL_ShapeActionActuator.h b/source/gameengine/Converter/BL_ShapeActionActuator.h index 28a6d90abdf..80157630e27 100644 --- a/source/gameengine/Converter/BL_ShapeActionActuator.h +++ b/source/gameengine/Converter/BL_ShapeActionActuator.h @@ -51,7 +51,7 @@ public: short blendin, short priority, float stride) - : SCA_IActuator(gameobj), + : SCA_IActuator(gameobj, KX_ACT_SHAPEACTION), m_lastpos(0, 0, 0), m_blendframe(0), diff --git a/source/gameengine/Converter/CMakeLists.txt b/source/gameengine/Converter/CMakeLists.txt index 257ca856b2c..d617934ec01 100644 --- a/source/gameengine/Converter/CMakeLists.txt +++ b/source/gameengine/Converter/CMakeLists.txt @@ -59,6 +59,7 @@ SET(INC ../../../source/blender/misc ../../../source/blender/blenloader ../../../source/blender/gpu + ../../../source/blender/ikplugin ../../../extern/bullet2/src ${PYTHON_INC} ) diff --git a/source/gameengine/Converter/KX_ConvertActuators.cpp b/source/gameengine/Converter/KX_ConvertActuators.cpp index 91a39bd7686..1cb16acf148 100644 --- a/source/gameengine/Converter/KX_ConvertActuators.cpp +++ b/source/gameengine/Converter/KX_ConvertActuators.cpp @@ -88,6 +88,7 @@ #include "DNA_packedFile_types.h" #include "BL_ActionActuator.h" #include "BL_ShapeActionActuator.h" +#include "BL_ArmatureActuator.h" /* end of blender include block */ #include "BL_BlenderDataConversion.h" @@ -1021,6 +1022,15 @@ void BL_ConvertActuators(char* maggiename, break; } + case ACT_ARMATURE: + { + bArmatureActuator* armAct = (bArmatureActuator*) bact->data; + KX_GameObject *tmpgob = converter->FindGameObject(armAct->target); + KX_GameObject *subgob = converter->FindGameObject(armAct->subtarget); + BL_ArmatureActuator* tmparmact = new BL_ArmatureActuator(gameobj, armAct->type, armAct->posechannel, armAct->constraint, tmpgob, subgob, armAct->weight); + baseact = tmparmact; + break; + } default: ; /* generate some error */ } diff --git a/source/gameengine/Converter/KX_ConvertSensors.cpp b/source/gameengine/Converter/KX_ConvertSensors.cpp index 09027f18844..99a2ec3ca64 100644 --- a/source/gameengine/Converter/KX_ConvertSensors.cpp +++ b/source/gameengine/Converter/KX_ConvertSensors.cpp @@ -64,6 +64,7 @@ probably misplaced */ #include "KX_NearSensor.h" #include "KX_RadarSensor.h" #include "KX_MouseFocusSensor.h" +#include "KX_ArmatureSensor.h" #include "SCA_JoystickSensor.h" #include "KX_NetworkMessageSensor.h" #include "SCA_ActuatorSensor.h" @@ -302,7 +303,7 @@ void BL_ConvertSensors(struct Object* blenderobject, case SENS_ALWAYS: { - SCA_EventManager* eventmgr = logicmgr->FindEventManager(SCA_EventManager::ALWAYS_EVENTMGR); + SCA_EventManager* eventmgr = logicmgr->FindEventManager(SCA_EventManager::BASIC_EVENTMGR); if (eventmgr) { gamesensor = new SCA_AlwaysSensor(eventmgr, gameobj); @@ -314,7 +315,7 @@ void BL_ConvertSensors(struct Object* blenderobject, case SENS_DELAY: { // we can reuse the Always event manager for the delay sensor - SCA_EventManager* eventmgr = logicmgr->FindEventManager(SCA_EventManager::ALWAYS_EVENTMGR); + SCA_EventManager* eventmgr = logicmgr->FindEventManager(SCA_EventManager::BASIC_EVENTMGR); if (eventmgr) { bDelaySensor* delaysensor = (bDelaySensor*)sens->data; @@ -550,7 +551,7 @@ void BL_ConvertSensors(struct Object* blenderobject, { bPropertySensor* blenderpropsensor = (bPropertySensor*) sens->data; SCA_EventManager* eventmgr - = logicmgr->FindEventManager(SCA_EventManager::PROPERTY_EVENTMGR); + = logicmgr->FindEventManager(SCA_EventManager::BASIC_EVENTMGR); if (eventmgr) { STR_String propname=blenderpropsensor->name; @@ -601,6 +602,21 @@ void BL_ConvertSensors(struct Object* blenderobject, break; } + case SENS_ARMATURE: + { + bArmatureSensor* blenderarmsensor = (bArmatureSensor*) sens->data; + // we will reuse the property event manager, there is nothing special with this sensor + SCA_EventManager* eventmgr + = logicmgr->FindEventManager(SCA_EventManager::BASIC_EVENTMGR); + if (eventmgr) + { + STR_String bonename=blenderarmsensor->posechannel; + STR_String constraintname=blenderarmsensor->constraint; + gamesensor = new KX_ArmatureSensor(eventmgr,gameobj,bonename,constraintname, blenderarmsensor->type, blenderarmsensor->value); + } + break; + } + case SENS_RADAR: { @@ -659,7 +675,7 @@ void BL_ConvertSensors(struct Object* blenderobject, bRaySensor* blenderraysensor = (bRaySensor*) sens->data; //blenderradarsensor->angle; - SCA_EventManager* eventmgr = logicmgr->FindEventManager(SCA_EventManager::RAY_EVENTMGR); + SCA_EventManager* eventmgr = logicmgr->FindEventManager(SCA_EventManager::BASIC_EVENTMGR); if (eventmgr) { bool bFindMaterial = (blenderraysensor->mode & SENS_COLLISION_MATERIAL); @@ -691,7 +707,7 @@ void BL_ConvertSensors(struct Object* blenderobject, // some files didn't write randomsensor, avoid crash now for NULL ptr's if (blenderrndsensor) { - SCA_EventManager* eventmgr = logicmgr->FindEventManager(SCA_EventManager::RANDOM_EVENTMGR); + SCA_EventManager* eventmgr = logicmgr->FindEventManager(SCA_EventManager::BASIC_EVENTMGR); if (eventmgr) { int randomSeed = blenderrndsensor->seed; diff --git a/source/gameengine/Converter/Makefile b/source/gameengine/Converter/Makefile index e261f9350e9..d41cc705087 100644 --- a/source/gameengine/Converter/Makefile +++ b/source/gameengine/Converter/Makefile @@ -53,6 +53,7 @@ CPPFLAGS += -I../../blender/blenlib CPPFLAGS += -I../../blender/blenkernel CPPFLAGS += -I../../blender/render/extern/include CPPFLAGS += -I../../blender/gpu +CPPFLAGS += -I../../blender/ikplugin CPPFLAGS += -I$(NAN_GUARDEDALLOC)/include CPPFLAGS += -I../Expressions -I../Rasterizer -I../GameLogic CPPFLAGS += -I../Ketsji -I../BlenderRoutines -I../SceneGraph diff --git a/source/gameengine/Converter/SConscript b/source/gameengine/Converter/SConscript index 2d126310475..5f6e9df521b 100644 --- a/source/gameengine/Converter/SConscript +++ b/source/gameengine/Converter/SConscript @@ -19,6 +19,7 @@ incs += ' #source/gameengine/Network/LoopBackNetwork' incs += ' #source/blender/misc #source/blender/blenloader #source/blender/gpu' incs += ' #source/blender/windowmanager' incs += ' #source/blender/makesrna' +incs += ' #source/blender/ikplugin' incs += ' ' + env['BF_PYTHON_INC'] incs += ' ' + env['BF_BULLET_INC'] diff --git a/source/gameengine/Expressions/CMakeLists.txt b/source/gameengine/Expressions/CMakeLists.txt index 439a50852a7..ec3738d1fe8 100644 --- a/source/gameengine/Expressions/CMakeLists.txt +++ b/source/gameengine/Expressions/CMakeLists.txt @@ -30,6 +30,7 @@ SET(INC . ../../../source/kernel/gen_system ../../../intern/string + ../../../intern/guardedalloc ../../../intern/moto/include ../../../source/gameengine/SceneGraph ../../../source/blender/blenloader diff --git a/source/gameengine/Expressions/PyObjectPlus.cpp b/source/gameengine/Expressions/PyObjectPlus.cpp index 1d1d9e6103b..7adbf5ac651 100644 --- a/source/gameengine/Expressions/PyObjectPlus.cpp +++ b/source/gameengine/Expressions/PyObjectPlus.cpp @@ -51,6 +51,7 @@ #include "PyObjectPlus.h" #include "STR_String.h" #include "MT_Vector3.h" +#include "MEM_guardedalloc.h" /*------------------------------ * PyObjectPlus Type -- Every class, even the abstract one should have a Type ------------------------------*/ @@ -95,7 +96,6 @@ PyObject *PyObjectPlus::py_base_repr(PyObject *self) // This should be the ent PyErr_SetString(PyExc_SystemError, BGE_PROXY_ERROR_MSG); return NULL; } - return self_plus->py_repr(); } @@ -145,42 +145,55 @@ PyObject * PyObjectPlus::py_base_new(PyTypeObject *type, PyObject *args, PyObjec PyObjectPlus_Proxy *ret = (PyObjectPlus_Proxy *) type->tp_alloc(type, 0); /* starts with 1 ref, used for the return ref' */ ret->ref= base->ref; - base->ref= NULL; /* invalidate! disallow further access */ - + ret->ptr= base->ptr; ret->py_owns= base->py_owns; + ret->py_ref = base->py_ref; - ret->ref->m_proxy= NULL; - - /* 'base' may be free'd after this func finished but not necessarily - * there is no reference to the BGE data now so it will throw an error on access */ - Py_DECREF(base); - - ret->ref->m_proxy= (PyObject *)ret; /* no need to add a ref because one is added when creating. */ - Py_INCREF(ret); /* we return a new ref but m_proxy holds a ref so we need to add one */ - - - /* 'ret' will have 2 references. - * - One ref is needed because ret->ref->m_proxy holds a refcount to the current proxy. - * - Another is needed for returning the value. - * - * So we should be ok with 2 refs, but for some reason this crashes. so adding a new ref... - * */ + if (ret->py_ref) { + base->ref= NULL; /* invalidate! disallow further access */ + base->ptr = NULL; + if (ret->ref) + ret->ref->m_proxy= NULL; + /* 'base' may be free'd after this func finished but not necessarily + * there is no reference to the BGE data now so it will throw an error on access */ + Py_DECREF(base); + if (ret->ref) { + ret->ref->m_proxy= (PyObject *)ret; /* no need to add a ref because one is added when creating. */ + Py_INCREF(ret); /* we return a new ref but m_proxy holds a ref so we need to add one */ + } + } else { + // generic structures don't hold a reference to this proxy, so don't increment ref count + if (ret->py_owns) + // but if the proxy owns the structure, there can be only one owner + base->ptr= NULL; + } return (PyObject *)ret; } void PyObjectPlus::py_base_dealloc(PyObject *self) // python wrapper { - PyObjectPlus *self_plus= BGE_PROXY_REF(self); - if(self_plus) { - if(BGE_PROXY_PYOWNS(self)) { /* Does python own this?, then delete it */ - self_plus->m_proxy = NULL; /* Need this to stop ~PyObjectPlus from decrefing m_proxy otherwise its decref'd twice and py-debug crashes */ - delete self_plus; + if (BGE_PROXY_PYREF(self)) { + PyObjectPlus *self_plus= BGE_PROXY_REF(self); + if(self_plus) { + if(BGE_PROXY_PYOWNS(self)) { /* Does python own this?, then delete it */ + self_plus->m_proxy = NULL; /* Need this to stop ~PyObjectPlus from decrefing m_proxy otherwise its decref'd twice and py-debug crashes */ + delete self_plus; + } + BGE_PROXY_REF(self)= NULL; // not really needed + } + // the generic pointer is not deleted directly, only through self_plus + BGE_PROXY_PTR(self)= NULL; // not really needed + } else { + void *ptr= BGE_PROXY_PTR(self); + if(ptr) { + if(BGE_PROXY_PYOWNS(self)) { /* Does python own this?, then delete it */ + // generic structure owned by python MUST be created though MEM_alloc + MEM_freeN(ptr); + } + BGE_PROXY_PTR(self)= NULL; // not really needed } - - BGE_PROXY_REF(self)= NULL; // not really needed } - #if 0 /* is ok normally but not for subtyping, use tp_free instead. */ PyObject_DEL( self ); @@ -217,8 +230,9 @@ PyObject* PyObjectPlus::pyattr_get_invalid(void *self_v, const KX_PYATTRIBUTE_DE /* note, this is called as a python 'getset, where the PyAttributeDef is the closure */ PyObject *PyObjectPlus::py_get_attrdef(PyObject *self_py, const PyAttributeDef *attrdef) { - void *self= (void *)(BGE_PROXY_REF(self_py)); - if(self==NULL) { + PyObjectPlus *ref= (BGE_PROXY_REF(self_py)); + char* ptr = (attrdef->m_usePtr) ? (char*)BGE_PROXY_PTR(self_py) : (char*)ref; + if(ptr == NULL || (BGE_PROXY_PYREF(self_py) && (ref==NULL || !ref->py_is_valid()))) { if(attrdef == attr_invalid) Py_RETURN_TRUE; // dont bother running the function @@ -226,7 +240,6 @@ PyObject *PyObjectPlus::py_get_attrdef(PyObject *self_py, const PyAttributeDef * return NULL; } - if (attrdef->m_type == KX_PYATTRIBUTE_TYPE_DUMMY) { // fake attribute, ignore @@ -237,9 +250,9 @@ PyObject *PyObjectPlus::py_get_attrdef(PyObject *self_py, const PyAttributeDef * // the attribute has no field correspondance, handover processing to function. if (attrdef->m_getFunction == NULL) return NULL; - return (*attrdef->m_getFunction)(self, attrdef); + return (*attrdef->m_getFunction)(ref, attrdef); } - char *ptr = reinterpret_cast<char*>(self)+attrdef->m_offset; + ptr += attrdef->m_offset; if (attrdef->m_length > 1) { PyObject* resultlist = PyList_New(attrdef->m_length); @@ -293,6 +306,35 @@ PyObject *PyObjectPlus::py_get_attrdef(PyObject *self_py, const PyAttributeDef * else { switch (attrdef->m_type) { + case KX_PYATTRIBUTE_TYPE_FLAG: + { + bool bval; + switch (attrdef->m_size) { + case 1: + { + unsigned char *val = reinterpret_cast<unsigned char*>(ptr); + bval = (*val & attrdef->m_imin); + break; + } + case 2: + { + unsigned short *val = reinterpret_cast<unsigned short*>(ptr); + bval = (*val & attrdef->m_imin); + break; + } + case 4: + { + unsigned int *val = reinterpret_cast<unsigned int*>(ptr); + bval = (*val & attrdef->m_imin); + break; + } + default: + return NULL; + } + if (attrdef->m_imax) + bval = !bval; + return PyLong_FromSsize_t(bval); + } case KX_PYATTRIBUTE_TYPE_BOOL: { bool *val = reinterpret_cast<bool*>(ptr); @@ -318,7 +360,49 @@ PyObject *PyObjectPlus::py_get_attrdef(PyObject *self_py, const PyAttributeDef * case KX_PYATTRIBUTE_TYPE_FLOAT: { float *val = reinterpret_cast<float*>(ptr); - return PyFloat_FromDouble(*val); + if (attrdef->m_imin == 0) { + if (attrdef->m_imax == 0) { + return PyFloat_FromDouble(*val); + } else { + // vector, verify size + if (attrdef->m_size != attrdef->m_imax*sizeof(float)) + { + return NULL; + } +#ifdef USE_MATHUTILS + return newVectorObject(val, attrdef->m_imax, Py_NEW, NULL); +#else + PyObject* resultlist = PyList_New(attrdef->m_imax); + for (unsigned int i=0; i<attrdef->m_imax; i++) + { + PyList_SET_ITEM(resultlist,i,PyFloat_FromDouble(val[i])); + } + return resultlist; +#endif + } + } else { + // matrix case + if (attrdef->m_size != attrdef->m_imax*attrdef->m_imin*sizeof(float)) + { + return NULL; + } +#ifdef USE_MATHUTILS + return newMatrixObject(val, attrdef->m_imin, attrdef->m_imax, Py_WRAP, NULL); +#else + PyObject* rowlist = PyList_New(attrdef->m_imin); + for (unsigned int i=0; i<attrdef->m_imin; i++) + { + PyObject* collist = PyList_New(attrdef->m_imax); + for (unsigned int j=0; j<attrdef->m_imax; j++) + { + PyList_SET_ITEM(collist,j,PyFloat_FromDouble(val[j])); + } + PyList_SET_ITEM(rowlist,i,collist); + val += attrdef->m_imax; + } + return rowlist; +#endif + } } case KX_PYATTRIBUTE_TYPE_VECTOR: { @@ -340,17 +424,47 @@ PyObject *PyObjectPlus::py_get_attrdef(PyObject *self_py, const PyAttributeDef * STR_String *val = reinterpret_cast<STR_String*>(ptr); return PyUnicode_FromString(*val); } + case KX_PYATTRIBUTE_TYPE_CHAR: + { + return PyUnicode_FromString(ptr); + } default: return NULL; } } } + +static bool py_check_attr_float(float *var, PyObject *value, const PyAttributeDef *attrdef) +{ + double val = PyFloat_AsDouble(value); + if (val == -1.0 && PyErr_Occurred()) + { + PyErr_Format(PyExc_TypeError, "expected float value for attribute \"%s\"", attrdef->m_name); + return false; + } + if (attrdef->m_clamp) + { + if (val < attrdef->m_fmin) + val = attrdef->m_fmin; + else if (val > attrdef->m_fmax) + val = attrdef->m_fmax; + } + else if (val < attrdef->m_fmin || val > attrdef->m_fmax) + { + PyErr_Format(PyExc_ValueError, "value out of range for attribute \"%s\"", attrdef->m_name); + return false; + } + *var = (float)val; + return true; +} + /* note, this is called as a python getset */ int PyObjectPlus::py_set_attrdef(PyObject *self_py, PyObject *value, const PyAttributeDef *attrdef) { - void *self= (void *)(BGE_PROXY_REF(self_py)); - if(self==NULL) { + PyObjectPlus *ref= (BGE_PROXY_REF(self_py)); + char* ptr = (attrdef->m_usePtr) ? (char*)BGE_PROXY_PTR(self_py) : (char*)ref; + if(ref==NULL || !ref->py_is_valid() || ptr==NULL) { PyErr_SetString(PyExc_SystemError, BGE_PROXY_ERROR_MSG); return PY_SET_ATTR_FAIL; } @@ -358,8 +472,10 @@ int PyObjectPlus::py_set_attrdef(PyObject *self_py, PyObject *value, const PyAtt void *undoBuffer = NULL; void *sourceBuffer = NULL; size_t bufferSize = 0; + PyObject *item = NULL; // to store object that must be dereferenced in case of error + PyObject *list = NULL; // to store object that must be dereferenced in case of error - char *ptr = reinterpret_cast<char*>(self)+attrdef->m_offset; + ptr += attrdef->m_offset; if (attrdef->m_length > 1) { if (!PySequence_Check(value)) @@ -380,7 +496,7 @@ int PyObjectPlus::py_set_attrdef(PyObject *self_py, PyObject *value, const PyAtt PyErr_Format(PyExc_AttributeError, "function attribute without function for attribute \"%s\", report to blender.org", attrdef->m_name); return PY_SET_ATTR_FAIL; } - return (*attrdef->m_setFunction)(self, attrdef, value); + return (*attrdef->m_setFunction)(ref, attrdef, value); case KX_PYATTRIBUTE_TYPE_BOOL: bufferSize = sizeof(bool); break; @@ -409,10 +525,7 @@ int PyObjectPlus::py_set_attrdef(PyObject *self_py, PyObject *value, const PyAtt } for (int i=0; i<attrdef->m_length; i++) { - PyObject *item = PySequence_GetItem(value, i); /* new ref */ - // we can decrement the reference immediately, the reference count - // is at least 1 because the item is part of an array - Py_DECREF(item); + item = PySequence_GetItem(value, i); /* new ref */ switch (attrdef->m_type) { case KX_PYATTRIBUTE_TYPE_BOOL: @@ -528,11 +641,14 @@ int PyObjectPlus::py_set_attrdef(PyObject *self_py, PyObject *value, const PyAtt PyErr_Format(PyExc_AttributeError, "type check error for attribute \"%s\", report to blender.org", attrdef->m_name); goto UNDO_AND_ERROR; } + // finished using item, release + Py_DECREF(item); + item = NULL; } // no error, call check function if any if (attrdef->m_checkFunction != NULL) { - if ((*attrdef->m_checkFunction)(self, attrdef) != 0) + if ((*attrdef->m_checkFunction)(ref, attrdef) != 0) { // if the checing function didnt set an error then set a generic one here so we dont set an error with no exception if (PyErr_Occurred()==0) @@ -545,6 +661,8 @@ int PyObjectPlus::py_set_attrdef(PyObject *self_py, PyObject *value, const PyAtt memcpy(sourceBuffer, undoBuffer, bufferSize); free(undoBuffer); } + if (item) + Py_DECREF(item); return PY_SET_ATTR_FAIL; } } @@ -561,7 +679,7 @@ int PyObjectPlus::py_set_attrdef(PyObject *self_py, PyObject *value, const PyAtt PyErr_Format(PyExc_AttributeError, "function attribute without function \"%s\", report to blender.org", attrdef->m_name); return PY_SET_ATTR_FAIL; } - return (*attrdef->m_setFunction)(self, attrdef, value); + return (*attrdef->m_setFunction)(ref, attrdef, value); } if (attrdef->m_checkFunction != NULL || attrdef->m_type == KX_PYATTRIBUTE_TYPE_VECTOR) { @@ -576,11 +694,19 @@ int PyObjectPlus::py_set_attrdef(PyObject *self_py, PyObject *value, const PyAtt bufferSize = sizeof(short); break; case KX_PYATTRIBUTE_TYPE_ENUM: + case KX_PYATTRIBUTE_TYPE_FLAG: + case KX_PYATTRIBUTE_TYPE_CHAR: + bufferSize = attrdef->m_size; + break; case KX_PYATTRIBUTE_TYPE_INT: bufferSize = sizeof(int); break; case KX_PYATTRIBUTE_TYPE_FLOAT: bufferSize = sizeof(float); + if (attrdef->m_imax) + bufferSize *= attrdef->m_imax; + if (attrdef->m_imin) + bufferSize *= attrdef->m_imin; break; case KX_PYATTRIBUTE_TYPE_STRING: sourceBuffer = reinterpret_cast<STR_String*>(ptr)->Ptr(); @@ -624,6 +750,49 @@ int PyObjectPlus::py_set_attrdef(PyObject *self_py, PyObject *value, const PyAtt } break; } + case KX_PYATTRIBUTE_TYPE_FLAG: + { + bool bval; + if (PyLong_Check(value)) + { + bval = (PyLong_AsSsize_t(value) != 0); + } + else if (PyBool_Check(value)) + { + bval = (value == Py_True); + } + else + { + PyErr_Format(PyExc_TypeError, "expected an integer or a bool for attribute \"%s\"", attrdef->m_name); + goto FREE_AND_ERROR; + } + if (attrdef->m_imax) + bval = !bval; + switch (attrdef->m_size) { + case 1: + { + unsigned char *val = reinterpret_cast<unsigned char*>(ptr); + *val = (*val & ~attrdef->m_imin) | ((bval)?attrdef->m_imin:0); + break; + } + case 2: + { + unsigned short *val = reinterpret_cast<unsigned short*>(ptr); + *val = (*val & ~attrdef->m_imin) | ((bval)?attrdef->m_imin:0); + break; + } + case 4: + { + unsigned int *val = reinterpret_cast<unsigned int*>(ptr); + *val = (*val & ~attrdef->m_imin) | ((bval)?attrdef->m_imin:0); + break; + } + default: + PyErr_Format(PyExc_TypeError, "internal error: unsupported flag field \"%s\"", attrdef->m_name); + goto FREE_AND_ERROR; + } + break; + } case KX_PYATTRIBUTE_TYPE_SHORT: { short int *var = reinterpret_cast<short int*>(ptr); @@ -689,25 +858,71 @@ int PyObjectPlus::py_set_attrdef(PyObject *self_py, PyObject *value, const PyAtt case KX_PYATTRIBUTE_TYPE_FLOAT: { float *var = reinterpret_cast<float*>(ptr); - double val = PyFloat_AsDouble(value); - if (val == -1.0 && PyErr_Occurred()) + if (attrdef->m_imin != 0) { - PyErr_Format(PyExc_TypeError, "expected a float for attribute \"%s\"", attrdef->m_name); - goto FREE_AND_ERROR; - } - else if (attrdef->m_clamp) + if (attrdef->m_size != attrdef->m_imin*attrdef->m_imax*sizeof(float)) + { + PyErr_Format(PyExc_TypeError, "internal error: incorrect field size for attribute \"%s\"", attrdef->m_name); + goto FREE_AND_ERROR; + } + if (!PySequence_Check(value) || PySequence_Size(value) != attrdef->m_imin) + { + PyErr_Format(PyExc_TypeError, "expected a sequence of [%d][%d] floats for attribute \"%s\"", attrdef->m_imin, attrdef->m_imax, attrdef->m_name); + goto FREE_AND_ERROR; + } + for (int i=0; i<attrdef->m_imin; i++) + { + PyObject *list = PySequence_GetItem(value, i); /* new ref */ + if (!PySequence_Check(list) || PySequence_Size(list) != attrdef->m_imax) + { + PyErr_Format(PyExc_TypeError, "expected a sequence of [%d][%d] floats for attribute \"%s\"", attrdef->m_imin, attrdef->m_imax, attrdef->m_name); + goto RESTORE_AND_ERROR; + } + for (int j=0; j<attrdef->m_imax; j++) + { + item = PySequence_GetItem(list, j); /* new ref */ + if (!py_check_attr_float(var, item, attrdef)) + { + PyErr_Format(PyExc_TypeError, "expected a sequence of [%d][%d] floats for attribute \"%s\"", attrdef->m_imin, attrdef->m_imax, attrdef->m_name); + goto RESTORE_AND_ERROR; + } + Py_DECREF(item); + item = NULL; + ++var; + } + Py_DECREF(list); + list = NULL; + } + } + else if (attrdef->m_imax != 0) { - if (val < attrdef->m_fmin) - val = attrdef->m_fmin; - else if (val > attrdef->m_fmax) - val = attrdef->m_fmax; - } - else if (val < attrdef->m_fmin || val > attrdef->m_fmax) + if (attrdef->m_size != attrdef->m_imax*sizeof(float)) + { + PyErr_Format(PyExc_TypeError, "internal error: incorrect field size for attribute \"%s\"", attrdef->m_name); + goto FREE_AND_ERROR; + } + if (!PySequence_Check(value) || PySequence_Size(value) != attrdef->m_imax) + { + PyErr_Format(PyExc_TypeError, "expected a sequence of [%d] floats for attribute \"%s\"", attrdef->m_imax, attrdef->m_name); + goto FREE_AND_ERROR; + } + for (int i=0; i<attrdef->m_imax; i++) + { + item = PySequence_GetItem(value, i); /* new ref */ + if (!py_check_attr_float(var, item, attrdef)) + { + goto RESTORE_AND_ERROR; + } + Py_DECREF(item); + item = NULL; + ++var; + } + } + else { - PyErr_Format(PyExc_ValueError, "value out of range for attribute \"%s\"", attrdef->m_name); - goto FREE_AND_ERROR; + if (!py_check_attr_float(var, value, attrdef)) + goto FREE_AND_ERROR; } - *var = (float)val; break; } case KX_PYATTRIBUTE_TYPE_VECTOR: @@ -715,16 +930,15 @@ int PyObjectPlus::py_set_attrdef(PyObject *self_py, PyObject *value, const PyAtt if (!PySequence_Check(value) || PySequence_Size(value) != 3) { PyErr_Format(PyExc_TypeError, "expected a sequence of 3 floats for attribute \"%s\"", attrdef->m_name); - return PY_SET_ATTR_FAIL; + goto FREE_AND_ERROR; } MT_Vector3 *var = reinterpret_cast<MT_Vector3*>(ptr); for (int i=0; i<3; i++) { - PyObject *item = PySequence_GetItem(value, i); /* new ref */ - // we can decrement the reference immediately, the reference count - // is at least 1 because the item is part of an array - Py_DECREF(item); + item = PySequence_GetItem(value, i); /* new ref */ double val = PyFloat_AsDouble(item); + Py_DECREF(item); + item = NULL; if (val == -1.0 && PyErr_Occurred()) { PyErr_Format(PyExc_TypeError, "expected a sequence of 3 floats for attribute \"%s\"", attrdef->m_name); @@ -746,6 +960,22 @@ int PyObjectPlus::py_set_attrdef(PyObject *self_py, PyObject *value, const PyAtt } break; } + case KX_PYATTRIBUTE_TYPE_CHAR: + { + if (PyUnicode_Check(value)) + { + Py_ssize_t val_len; + char *val = _PyUnicode_AsStringAndSize(value, &val_len); + strncpy(ptr, val, attrdef->m_size); + ptr[attrdef->m_size-1] = 0; + } + else + { + PyErr_Format(PyExc_TypeError, "expected a string for attribute \"%s\"", attrdef->m_name); + goto FREE_AND_ERROR; + } + break; + } case KX_PYATTRIBUTE_TYPE_STRING: { STR_String *var = reinterpret_cast<STR_String*>(ptr); @@ -793,7 +1023,7 @@ int PyObjectPlus::py_set_attrdef(PyObject *self_py, PyObject *value, const PyAtt // check if post processing is needed if (attrdef->m_checkFunction != NULL) { - if ((*attrdef->m_checkFunction)(self, attrdef) != 0) + if ((*attrdef->m_checkFunction)(ref, attrdef) != 0) { // restore value RESTORE_AND_ERROR: @@ -814,6 +1044,10 @@ int PyObjectPlus::py_set_attrdef(PyObject *self_py, PyObject *value, const PyAtt FREE_AND_ERROR: if (undoBuffer) free(undoBuffer); + if (list) + Py_DECREF(list); + if (item) + Py_DECREF(item); return 1; } } @@ -857,23 +1091,35 @@ void PyObjectPlus::InvalidateProxy() // check typename of each parent } } -PyObject *PyObjectPlus::GetProxy_Ext(PyObjectPlus *self, PyTypeObject *tp) +PyObject *PyObjectPlus::GetProxyPlus_Ext(PyObjectPlus *self, PyTypeObject *tp, void *ptr) { if (self->m_proxy==NULL) { self->m_proxy = reinterpret_cast<PyObject *>PyObject_NEW( PyObjectPlus_Proxy, tp); BGE_PROXY_PYOWNS(self->m_proxy) = false; + BGE_PROXY_PYREF(self->m_proxy) = true; } //PyObject_Print(self->m_proxy, stdout, 0); //printf("ref %d\n", self->m_proxy->ob_refcnt); BGE_PROXY_REF(self->m_proxy) = self; /* Its possible this was set to NULL, so set it back here */ + BGE_PROXY_PTR(self->m_proxy) = ptr; Py_INCREF(self->m_proxy); /* we own one, thos ones fore the return */ return self->m_proxy; } -PyObject *PyObjectPlus::NewProxy_Ext(PyObjectPlus *self, PyTypeObject *tp, bool py_owns) +PyObject *PyObjectPlus::NewProxyPlus_Ext(PyObjectPlus *self, PyTypeObject *tp, void *ptr, bool py_owns) { + if (!self) + { + // in case of proxy without reference to game object + PyObject* proxy = reinterpret_cast<PyObject *>PyObject_NEW( PyObjectPlus_Proxy, tp); + BGE_PROXY_PYREF(proxy) = false; + BGE_PROXY_PYOWNS(proxy) = py_owns; + BGE_PROXY_REF(proxy) = NULL; + BGE_PROXY_PTR(proxy) = ptr; + return proxy; + } if (self->m_proxy) { if(py_owns) @@ -889,7 +1135,7 @@ PyObject *PyObjectPlus::NewProxy_Ext(PyObjectPlus *self, PyTypeObject *tp, bool } - GetProxy_Ext(self, tp); + GetProxyPlus_Ext(self, tp, ptr); if(py_owns) { BGE_PROXY_PYOWNS(self->m_proxy) = py_owns; Py_DECREF(self->m_proxy); /* could avoid thrashing here but for now its ok */ diff --git a/source/gameengine/Expressions/PyObjectPlus.h b/source/gameengine/Expressions/PyObjectPlus.h index f9edb7877b0..237f01f5a3a 100644 --- a/source/gameengine/Expressions/PyObjectPlus.h +++ b/source/gameengine/Expressions/PyObjectPlus.h @@ -88,13 +88,17 @@ typedef struct { typedef struct PyObjectPlus_Proxy { PyObject_HEAD /* required python macro */ - class PyObjectPlus *ref; - bool py_owns; + class PyObjectPlus *ref; // pointer to GE object, it holds a reference to this proxy + void *ptr; // optional pointer to generic structure, the structure holds no reference to this proxy + bool py_owns; // true if the object pointed by ref should be deleted when the proxy is deleted + bool py_ref; // true if proxy is connected to a GE object (ref is used) } PyObjectPlus_Proxy; #define BGE_PROXY_ERROR_MSG "Blender Game Engine data has been freed, cannot use this python variable" #define BGE_PROXY_REF(_self) (((PyObjectPlus_Proxy *)_self)->ref) +#define BGE_PROXY_PTR(_self) (((PyObjectPlus_Proxy *)_self)->ptr) #define BGE_PROXY_PYOWNS(_self) (((PyObjectPlus_Proxy *)_self)->py_owns) +#define BGE_PROXY_PYREF(_self) (((PyObjectPlus_Proxy *)_self)->py_ref) /* Note, sometimes we dont care what BGE type this is as long as its a proxy */ #define BGE_PROXY_CHECK_TYPE(_type) ((_type)->tp_dealloc == PyObjectPlus::py_base_dealloc) @@ -103,18 +107,33 @@ typedef struct PyObjectPlus_Proxy { #define BGE_PROXY_FROM_REF(_self) (((PyObjectPlus *)_self)->GetProxy()) - // This must be the first line of each - // PyC++ class +// This must be the first line of each +// PyC++ class +// AttributesPtr correspond to attributes of proxy generic pointer +// each PyC++ class must be registered in KX_PythonInitTypes.cpp #define __Py_Header \ public: \ static PyTypeObject Type; \ static PyMethodDef Methods[]; \ static PyAttributeDef Attributes[]; \ virtual PyTypeObject *GetType(void) {return &Type;}; \ - virtual PyObject *GetProxy() {return GetProxy_Ext(this, &Type);}; \ - virtual PyObject *NewProxy(bool py_owns) {return NewProxy_Ext(this, &Type, py_owns);}; \ + virtual PyObject *GetProxy() {return GetProxyPlus_Ext(this, &Type, NULL);}; \ + virtual PyObject *NewProxy(bool py_owns) {return NewProxyPlus_Ext(this, &Type, NULL, py_owns);}; \ +// leave above line empty (macro)! +// use this macro for class that use generic pointer in proxy +// GetProxy() and NewProxy() must be defined to set the correct pointer in the proxy +#define __Py_HeaderPtr \ + public: \ + static PyTypeObject Type; \ + static PyMethodDef Methods[]; \ + static PyAttributeDef Attributes[]; \ + static PyAttributeDef AttributesPtr[]; \ + virtual PyTypeObject *GetType(void) {return &Type;}; \ + virtual PyObject *GetProxy(); \ + virtual PyObject *NewProxy(bool py_owns); \ +// leave above line empty (macro)! #ifdef WITH_CXX_GUARDEDALLOC #define Py_Header __Py_Header \ void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, Type.tp_name); } \ @@ -124,6 +143,15 @@ typedef struct PyObjectPlus_Proxy { #define Py_Header __Py_Header #endif +#ifdef WITH_CXX_GUARDEDALLOC +#define Py_HeaderPtr __Py_HeaderPtr \ + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, Type.tp_name); } \ + void operator delete( void *mem ) { MEM_freeN(mem); } \ + +#else +#define Py_HeaderPtr __Py_HeaderPtr +#endif + /* * nonzero values are an error for setattr * however because of the nested lookups we need to know if the errors @@ -245,6 +273,8 @@ enum KX_PYATTRIBUTE_TYPE { KX_PYATTRIBUTE_TYPE_DUMMY, KX_PYATTRIBUTE_TYPE_FUNCTION, KX_PYATTRIBUTE_TYPE_VECTOR, + KX_PYATTRIBUTE_TYPE_FLAG, + KX_PYATTRIBUTE_TYPE_CHAR, }; enum KX_PYATTRIBUTE_ACCESS { @@ -261,11 +291,14 @@ typedef struct KX_PYATTRIBUTE_DEF { const char *m_name; // name of the python attribute KX_PYATTRIBUTE_TYPE m_type; // type of value KX_PYATTRIBUTE_ACCESS m_access; // read/write access or read-only - int m_imin; // minimum value in case of integer attributes (for string: minimum string length) - int m_imax; // maximum value in case of integer attributes (for string: maximum string length) + int m_imin; // minimum value in case of integer attributes + // (for string: minimum string length, for flag: mask value, for float: matrix row size) + int m_imax; // maximum value in case of integer attributes + // (for string: maximum string length, for flag: 1 if flag is negative, float: vector/matrix col size) float m_fmin; // minimum value in case of float attributes float m_fmax; // maximum value in case of float attributes bool m_clamp; // enforce min/max value by clamping + bool m_usePtr; // the attribute uses the proxy generic pointer, set at runtime size_t m_offset; // position of field in structure size_t m_size; // size of field for runtime verification (enum only) size_t m_length; // length of array, 1=simple attribute @@ -283,104 +316,146 @@ typedef struct KX_PYATTRIBUTE_DEF { float *m_floatPtr; STR_String *m_stringPtr; MT_Vector3 *m_vectorPtr; + char *m_charPtr; } m_typeCheck; } PyAttributeDef; #define KX_PYATTRIBUTE_DUMMY(name) \ - { name, KX_PYATTRIBUTE_TYPE_DUMMY, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, 0, 0, 1, NULL, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, NULL} } + { name, KX_PYATTRIBUTE_TYPE_DUMMY, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, false, 0, 0, 1, NULL, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, NULL, NULL} } #define KX_PYATTRIBUTE_BOOL_RW(name,object,field) \ - { name, KX_PYATTRIBUTE_TYPE_BOOL, KX_PYATTRIBUTE_RW, 0, 1, 0.f, 0.f, false, offsetof(object,field), 0, 1, NULL, NULL, NULL, {&((object *)0)->field, NULL, NULL, NULL, NULL, NULL} } + { name, KX_PYATTRIBUTE_TYPE_BOOL, KX_PYATTRIBUTE_RW, 0, 1, 0.f, 0.f, false, false, offsetof(object,field), 0, 1, NULL, NULL, NULL, {&((object *)0)->field, NULL, NULL, NULL, NULL, NULL, NULL} } #define KX_PYATTRIBUTE_BOOL_RW_CHECK(name,object,field,function) \ - { name, KX_PYATTRIBUTE_TYPE_BOOL, KX_PYATTRIBUTE_RW, 0, 1, 0.f, 0.f, false, offsetof(object,field), 0, 1, &object::function, NULL, NULL, {&((object *)0)->field, NULL, NULL, NULL, NULL, NULL} } + { name, KX_PYATTRIBUTE_TYPE_BOOL, KX_PYATTRIBUTE_RW, 0, 1, 0.f, 0.f, false, false, offsetof(object,field), 0, 1, &object::function, NULL, NULL, {&((object *)0)->field, NULL, NULL, NULL, NULL, NULL, NULL} } #define KX_PYATTRIBUTE_BOOL_RO(name,object,field) \ - { name, KX_PYATTRIBUTE_TYPE_BOOL, KX_PYATTRIBUTE_RO, 0, 1, 0.f, 0.f, false, offsetof(object,field), 0, 1, NULL, NULL, NULL, {&((object *)0)->field, NULL, NULL, NULL, NULL, NULL} } + { name, KX_PYATTRIBUTE_TYPE_BOOL, KX_PYATTRIBUTE_RO, 0, 1, 0.f, 0.f, false, false, offsetof(object,field), 0, 1, NULL, NULL, NULL, {&((object *)0)->field, NULL, NULL, NULL, NULL, NULL, NULL} } + +/* attribute points to a single bit of an integer field, attribute=true if bit is set */ +#define KX_PYATTRIBUTE_FLAG_RW(name,object,field,bit) \ + { name, KX_PYATTRIBUTE_TYPE_FLAG, KX_PYATTRIBUTE_RW, bit, 0, 0.f, 0.f, false, false, offsetof(object,field), sizeof(((object *)0)->field), 1, NULL, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, NULL, NULL} } +#define KX_PYATTRIBUTE_FLAG_RW_CHECK(name,object,field,bit,function) \ + { name, KX_PYATTRIBUTE_TYPE_FLAG, KX_PYATTRIBUTE_RW, bit, 0, 0.f, 0.f, false, false, offsetof(object,field), sizeof(((object *)0)->field), 1, &object::function, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, NULL, NULL} } +#define KX_PYATTRIBUTE_FLAG_RO(name,object,field,bit) \ + { name, KX_PYATTRIBUTE_TYPE_FLAG, KX_PYATTRIBUTE_RO, bit, 0, 0.f, 0.f, false, false, offsetof(object,field), sizeof(((object *)0)->field), 1, NULL, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, NULL, NULL} } + +/* attribute points to a single bit of an integer field, attribute=true if bit is set*/ +#define KX_PYATTRIBUTE_FLAG_NEGATIVE_RW(name,object,field,bit) \ + { name, KX_PYATTRIBUTE_TYPE_FLAG, KX_PYATTRIBUTE_RW, bit, 1, 0.f, 0.f, false, false, offsetof(object,field), sizeof(((object *)0)->field), 1, NULL, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, NULL, NULL} } +#define KX_PYATTRIBUTE_FLAG_NEGATIVE_RW_CHECK(name,object,field,bit,function) \ + { name, KX_PYATTRIBUTE_TYPE_FLAG, KX_PYATTRIBUTE_RW, bit, 1, 0.f, 0.f, false, false, offsetof(object,field), sizeof(((object *)0)->field), 1, &object::function, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, NULL, NULL} } +#define KX_PYATTRIBUTE_FLAG_NEGATIVE_RO(name,object,field,bit) \ + { name, KX_PYATTRIBUTE_TYPE_FLAG, KX_PYATTRIBUTE_RO, bit, 1, 0.f, 0.f, false, false, offsetof(object,field), sizeof(((object *)0)->field), 1, NULL, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, NULL, NULL} } // enum field cannot be mapped to pointer (because we would need a pointer for each enum) // use field size to verify mapping at runtime only, assuming enum size is equal to int size. #define KX_PYATTRIBUTE_ENUM_RW(name,min,max,clamp,object,field) \ - { name, KX_PYATTRIBUTE_TYPE_ENUM, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, offsetof(object,field), sizeof(((object *)0)->field), 1, NULL, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, NULL} } + { name, KX_PYATTRIBUTE_TYPE_ENUM, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, false, offsetof(object,field), sizeof(((object *)0)->field), 1, NULL, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, NULL, NULL} } #define KX_PYATTRIBUTE_ENUM_RW_CHECK(name,min,max,clamp,object,field,function) \ - { name, KX_PYATTRIBUTE_TYPE_ENUM, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, offsetof(object,field), sizeof(((object *)0)->field), 1, &object::function, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, NULL} } + { name, KX_PYATTRIBUTE_TYPE_ENUM, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, false, offsetof(object,field), sizeof(((object *)0)->field), 1, &object::function, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, NULL, NULL} } #define KX_PYATTRIBUTE_ENUM_RO(name,object,field) \ - { name, KX_PYATTRIBUTE_TYPE_ENUM, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, offsetof(object,field), sizeof(((object *)0)->field), 1, NULL, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, NULL} } + { name, KX_PYATTRIBUTE_TYPE_ENUM, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, false, offsetof(object,field), sizeof(((object *)0)->field), 1, NULL, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, NULL, NULL} } #define KX_PYATTRIBUTE_SHORT_RW(name,min,max,clamp,object,field) \ - { name, KX_PYATTRIBUTE_TYPE_SHORT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, offsetof(object,field), 0, 1, NULL, NULL, NULL, {NULL, &((object *)0)->field, NULL, NULL, NULL, NULL} } + { name, KX_PYATTRIBUTE_TYPE_SHORT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, false, offsetof(object,field), 0, 1, NULL, NULL, NULL, {NULL, &((object *)0)->field, NULL, NULL, NULL, NULL, NULL} } #define KX_PYATTRIBUTE_SHORT_RW_CHECK(name,min,max,clamp,object,field,function) \ - { name, KX_PYATTRIBUTE_TYPE_SHORT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, offsetof(object,field), 0, 1, &object::function, NULL, NULL, {NULL, &((object *)0)->field, NULL, NULL, NULL, NULL} } + { name, KX_PYATTRIBUTE_TYPE_SHORT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, false, offsetof(object,field), 0, 1, &object::function, NULL, NULL, {NULL, &((object *)0)->field, NULL, NULL, NULL, NULL, NULL} } #define KX_PYATTRIBUTE_SHORT_RO(name,object,field) \ - { name, KX_PYATTRIBUTE_TYPE_SHORT, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, offsetof(object,field), 0, 1, NULL, NULL, NULL, {NULL, &((object *)0)->field, NULL, NULL, NULL, NULL} } + { name, KX_PYATTRIBUTE_TYPE_SHORT, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, false, offsetof(object,field), 0, 1, NULL, NULL, NULL, {NULL, &((object *)0)->field, NULL, NULL, NULL, NULL, NULL} } #define KX_PYATTRIBUTE_SHORT_ARRAY_RW(name,min,max,clamp,object,field,length) \ - { name, KX_PYATTRIBUTE_TYPE_SHORT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, offsetof(object,field), 0, length, NULL, NULL, NULL, {NULL, ((object *)0)->field, NULL, NULL, NULL, NULL} } + { name, KX_PYATTRIBUTE_TYPE_SHORT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, false, offsetof(object,field), 0, length, NULL, NULL, NULL, {NULL, ((object *)0)->field, NULL, NULL, NULL, NULL, NULL} } #define KX_PYATTRIBUTE_SHORT_ARRAY_RW_CHECK(name,min,max,clamp,object,field,length,function) \ - { name, KX_PYATTRIBUTE_TYPE_SHORT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, offsetof(object,field), 0, length, &object::function, NULL, NULL, {NULL, ((object *)0)->field, NULL, NULL, NULL, NULL} } + { name, KX_PYATTRIBUTE_TYPE_SHORT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, false, offsetof(object,field), 0, length, &object::function, NULL, NULL, {NULL, ((object *)0)->field, NULL, NULL, NULL, NULL, NULL} } #define KX_PYATTRIBUTE_SHORT_ARRAY_RO(name,object,field,length) \ - { name, KX_PYATTRIBUTE_TYPE_SHORT, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, offsetof(object,field), 0, length, NULL, NULL, NULL, {NULL, ((object *)0)->field, NULL, NULL, NULL, NULL} } + { name, KX_PYATTRIBUTE_TYPE_SHORT, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, false, offsetof(object,field), 0, length, NULL, NULL, NULL, {NULL, ((object *)0)->field, NULL, NULL, NULL, NULL, NULL} } // SHORT_LIST #define KX_PYATTRIBUTE_SHORT_LIST_RW(name,min,max,clamp,object,field,length) \ - { name, KX_PYATTRIBUTE_TYPE_SHORT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, offsetof(object,field), 0, length, NULL, NULL, NULL, {NULL, &((object *)0)->field, NULL, NULL, NULL, NULL} } + { name, KX_PYATTRIBUTE_TYPE_SHORT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, false, offsetof(object,field), 0, length, NULL, NULL, NULL, {NULL, &((object *)0)->field, NULL, NULL, NULL, NULL, NULL} } #define KX_PYATTRIBUTE_SHORT_LIST_RW_CHECK(name,min,max,clamp,object,field,length,function) \ - { name, KX_PYATTRIBUTE_TYPE_SHORT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, offsetof(object,field), 0, length, &object::function, NULL, NULL, {NULL, &((object *)0)->field, NULL, NULL, NULL, NULL} } + { name, KX_PYATTRIBUTE_TYPE_SHORT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, false, offsetof(object,field), 0, length, &object::function, NULL, NULL, {NULL, &((object *)0)->field, NULL, NULL, NULL, NULL, NULL} } #define KX_PYATTRIBUTE_SHORT_LIST_RO(name,object,field,length) \ - { name, KX_PYATTRIBUTE_TYPE_SHORT, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, offsetof(object,field), 0, length, NULL, NULL, NULL, {NULL, &((object *)0)->field, NULL, NULL, NULL, NULL} } + { name, KX_PYATTRIBUTE_TYPE_SHORT, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, false, offsetof(object,field), 0, length, NULL, NULL, NULL, {NULL, &((object *)0)->field, NULL, NULL, NULL, NULL, NULL} } #define KX_PYATTRIBUTE_INT_RW(name,min,max,clamp,object,field) \ - { name, KX_PYATTRIBUTE_TYPE_INT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, offsetof(object,field), 0, 1, NULL, NULL, NULL, {NULL, NULL, &((object *)0)->field, NULL, NULL, NULL} } + { name, KX_PYATTRIBUTE_TYPE_INT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, false, offsetof(object,field), 0, 1, NULL, NULL, NULL, {NULL, NULL, &((object *)0)->field, NULL, NULL, NULL, NULL} } #define KX_PYATTRIBUTE_INT_RW_CHECK(name,min,max,clamp,object,field,function) \ - { name, KX_PYATTRIBUTE_TYPE_INT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, offsetof(object,field), 0, 1, &object::function, NULL, NULL, {NULL, NULL, &((object *)0)->field, NULL, NULL, NULL} } + { name, KX_PYATTRIBUTE_TYPE_INT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, false, offsetof(object,field), 0, 1, &object::function, NULL, NULL, {NULL, NULL, &((object *)0)->field, NULL, NULL, NULL, NULL} } #define KX_PYATTRIBUTE_INT_RO(name,object,field) \ - { name, KX_PYATTRIBUTE_TYPE_INT, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, offsetof(object,field), 0, 1, NULL, NULL, NULL, {NULL, NULL, &((object *)0)->field, NULL, NULL, NULL} } + { name, KX_PYATTRIBUTE_TYPE_INT, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, false, offsetof(object,field), 0, 1, NULL, NULL, NULL, {NULL, NULL, &((object *)0)->field, NULL, NULL, NULL, NULL} } #define KX_PYATTRIBUTE_INT_ARRAY_RW(name,min,max,clamp,object,field,length) \ - { name, KX_PYATTRIBUTE_TYPE_INT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, offsetof(object,field), 0, length, NULL, NULL, NULL, {NULL, NULL, ((object *)0)->field, NULL, NULL, NULL} } + { name, KX_PYATTRIBUTE_TYPE_INT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, false, offsetof(object,field), 0, length, NULL, NULL, NULL, {NULL, NULL, ((object *)0)->field, NULL, NULL, NULL, NULL} } #define KX_PYATTRIBUTE_INT_ARRAY_RW_CHECK(name,min,max,clamp,object,field,length,function) \ - { name, KX_PYATTRIBUTE_TYPE_INT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, offsetof(object,field), 0, length, &object::function, NULL, NULL, {NULL, NULL, ((object *)0)->field, NULL, NULL, NULL} } + { name, KX_PYATTRIBUTE_TYPE_INT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, false, offsetof(object,field), 0, length, &object::function, NULL, NULL, {NULL, NULL, ((object *)0)->field, NULL, NULL, NULL, NULL} } #define KX_PYATTRIBUTE_INT_ARRAY_RO(name,object,field,length) \ - { name, KX_PYATTRIBUTE_TYPE_INT, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, offsetof(object,field), 0, length, NULL, NULL, NULL, {NULL, NULL, ((object *)0)->field, NULL, NULL, NULL} } + { name, KX_PYATTRIBUTE_TYPE_INT, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, false, offsetof(object,field), 0, length, NULL, NULL, NULL, {NULL, NULL, ((object *)0)->field, NULL, NULL, NULL, NULL} } // INT_LIST #define KX_PYATTRIBUTE_INT_LIST_RW(name,min,max,clamp,object,field,length) \ - { name, KX_PYATTRIBUTE_TYPE_INT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, offsetof(object,field), 0, length, NULL, NULL, NULL, {NULL, NULL, &((object *)0)->field, NULL, NULL, NULL} } + { name, KX_PYATTRIBUTE_TYPE_INT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, false, offsetof(object,field), 0, length, NULL, NULL, NULL, {NULL, NULL, &((object *)0)->field, NULL, NULL, NULL, NULL} } #define KX_PYATTRIBUTE_INT_LIST_RW_CHECK(name,min,max,clamp,object,field,length,function) \ - { name, KX_PYATTRIBUTE_TYPE_INT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, offsetof(object,field), 0, length, &object::function, NULL, NULL, {NULL, NULL, &((object *)0)->field, NULL, NULL, NULL} } + { name, KX_PYATTRIBUTE_TYPE_INT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, false, offsetof(object,field), 0, length, &object::function, NULL, NULL, {NULL, NULL, &((object *)0)->field, NULL, NULL, NULL, NULL} } #define KX_PYATTRIBUTE_INT_LIST_RO(name,object,field,length) \ - { name, KX_PYATTRIBUTE_TYPE_INT, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, offsetof(object,field), 0, length, NULL, NULL, NULL, {NULL, NULL, &((object *)0)->field, NULL, NULL, NULL} } + { name, KX_PYATTRIBUTE_TYPE_INT, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, false, offsetof(object,field), 0, length, NULL, NULL, NULL, {NULL, NULL, &((object *)0)->field, NULL, NULL, NULL, NULL} } // always clamp for float #define KX_PYATTRIBUTE_FLOAT_RW(name,min,max,object,field) \ - { name, KX_PYATTRIBUTE_TYPE_FLOAT, KX_PYATTRIBUTE_RW, 0, 0, min, max, true, offsetof(object,field), 0, 1, NULL, NULL, NULL, {NULL, NULL, NULL, &((object *)0)->field, NULL, NULL} } + { name, KX_PYATTRIBUTE_TYPE_FLOAT, KX_PYATTRIBUTE_RW, 0, 0, min, max, true, false, offsetof(object,field), 0, 1, NULL, NULL, NULL, {NULL, NULL, NULL, &((object *)0)->field, NULL, NULL, NULL} } #define KX_PYATTRIBUTE_FLOAT_RW_CHECK(name,min,max,object,field,function) \ - { name, KX_PYATTRIBUTE_TYPE_FLOAT, KX_PYATTRIBUTE_RW, 0, 0, min, max, true, offsetof(object,field), 0, 1, &object::function, NULL, NULL, {NULL, NULL, NULL, &((object *)0)->field, NULL, NULL} } + { name, KX_PYATTRIBUTE_TYPE_FLOAT, KX_PYATTRIBUTE_RW, 0, 0, min, max, true, false, offsetof(object,field), 0, 1, &object::function, NULL, NULL, {NULL, NULL, NULL, &((object *)0)->field, NULL, NULL, NULL} } #define KX_PYATTRIBUTE_FLOAT_RO(name,object,field) \ - { name, KX_PYATTRIBUTE_TYPE_FLOAT, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, offsetof(object,field), 0, 1, NULL, NULL, NULL, {NULL, NULL, NULL, &((object *)0)->field, NULL, NULL} } + { name, KX_PYATTRIBUTE_TYPE_FLOAT, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, false, offsetof(object,field), 0, 1, NULL, NULL, NULL, {NULL, NULL, NULL, &((object *)0)->field, NULL, NULL, NULL} } +// field must be float[n], returns a sequence #define KX_PYATTRIBUTE_FLOAT_ARRAY_RW(name,min,max,object,field,length) \ - { name, KX_PYATTRIBUTE_TYPE_FLOAT, KX_PYATTRIBUTE_RW, 0, 0, min, max, true, offsetof(object,field), 0, length, NULL, NULL, NULL, {NULL, NULL, NULL, ((object *)0)->field, NULL, NULL} } + { name, KX_PYATTRIBUTE_TYPE_FLOAT, KX_PYATTRIBUTE_RW, 0, 0, min, max, true, false, offsetof(object,field), 0, length, NULL, NULL, NULL, {NULL, NULL, NULL, ((object *)0)->field, NULL, NULL, NULL} } #define KX_PYATTRIBUTE_FLOAT_ARRAY_RW_CHECK(name,min,max,object,field,length,function) \ - { name, KX_PYATTRIBUTE_TYPE_FLOAT, KX_PYATTRIBUTE_RW, 0, 0, min, max, true, offsetof(object,field), 0, length, &object::function, NULL, NULL, {NULL, NULL, NULL, ((object *)0)->field, NULL, NULL} } + { name, KX_PYATTRIBUTE_TYPE_FLOAT, KX_PYATTRIBUTE_RW, 0, 0, min, max, true, false, offsetof(object,field), 0, length, &object::function, NULL, NULL, {NULL, NULL, NULL, ((object *)0)->field, NULL, NULL, NULL} } #define KX_PYATTRIBUTE_FLOAT_ARRAY_RO(name,object,field,length) \ - { name, KX_PYATTRIBUTE_TYPE_FLOAT, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, offsetof(object,field), 0, length, NULL, NULL, NULL, {NULL, NULL, NULL, ((object *)0)->field, NULL, NULL} } - + { name, KX_PYATTRIBUTE_TYPE_FLOAT, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, false, offsetof(object,field), 0, length, NULL, NULL, NULL, {NULL, NULL, NULL, ((object *)0)->field, NULL, NULL, NULL} } +// field must be float[n], returns a vector +#define KX_PYATTRIBUTE_FLOAT_VECTOR_RW(name,min,max,object,field,length) \ + { name, KX_PYATTRIBUTE_TYPE_FLOAT, KX_PYATTRIBUTE_RW, 0, length, min, max, true, false, offsetof(object,field), sizeof(((object *)0)->field), 1, NULL, NULL, NULL, {NULL, NULL, NULL, ((object *)0)->field, NULL, NULL, NULL} } +#define KX_PYATTRIBUTE_FLOAT_VECTOR_RW_CHECK(name,min,max,object,field,length,function) \ + { name, KX_PYATTRIBUTE_TYPE_FLOAT, KX_PYATTRIBUTE_RW, 0, length, min, max, true, false, offsetof(object,field), sizeof(((object *)0)->field), 1, &object::function, NULL, NULL, {NULL, NULL, NULL, ((object *)0)->field, NULL, NULL, NULL} } +#define KX_PYATTRIBUTE_FLOAT_VECTOR_RO(name,object,field,length) \ + { name, KX_PYATTRIBUTE_TYPE_FLOAT, KX_PYATTRIBUTE_RO, 0, length, 0.f, 0.f, false, false, offsetof(object,field), sizeof(((object *)0)->field), 1, NULL, NULL, NULL, {NULL, NULL, NULL, ((object *)0)->field, NULL, NULL, NULL} } +// field must be float[n][n], returns a matrix +#define KX_PYATTRIBUTE_FLOAT_MATRIX_RW(name,min,max,object,field,length) \ + { name, KX_PYATTRIBUTE_TYPE_FLOAT, KX_PYATTRIBUTE_RW, length, length, min, max, true, false, offsetof(object,field), sizeof(((object *)0)->field), 1, NULL, NULL, NULL, {NULL, NULL, NULL, ((object *)0)->field[0], NULL, NULL, NULL} } +#define KX_PYATTRIBUTE_FLOAT_MATRIX_RW_CHECK(name,min,max,object,field,length,function) \ + { name, KX_PYATTRIBUTE_TYPE_FLOAT, KX_PYATTRIBUTE_RW, length, length, min, max, true, false, offsetof(object,field), sizeof(((object *)0)->field), 1, &object::function, NULL, NULL, {NULL, NULL, NULL, ((object *)0)->field[0], NULL, NULL, NULL} } +#define KX_PYATTRIBUTE_FLOAT_MATRIX_RO(name,object,field,length) \ + { name, KX_PYATTRIBUTE_TYPE_FLOAT, KX_PYATTRIBUTE_RO, length, length, 0.f, 0.f, false, false, offsetof(object,field), sizeof(((object *)0)->field), 1, NULL, NULL, NULL, {NULL, NULL, NULL, ((object *)0)->field[0], NULL, NULL, NULL} } + +// only for STR_String member #define KX_PYATTRIBUTE_STRING_RW(name,min,max,clamp,object,field) \ - { name, KX_PYATTRIBUTE_TYPE_STRING, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, offsetof(object,field), 0, 1, NULL, NULL, NULL, {NULL, NULL, NULL, NULL, &((object *)0)->field, NULL} } + { name, KX_PYATTRIBUTE_TYPE_STRING, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, false, offsetof(object,field), 0, 1, NULL, NULL, NULL, {NULL, NULL, NULL, NULL, &((object *)0)->field, NULL, NULL} } #define KX_PYATTRIBUTE_STRING_RW_CHECK(name,min,max,clamp,object,field,function) \ - { name, KX_PYATTRIBUTE_TYPE_STRING, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, offsetof(object,field), 0, 1, &object::function, NULL, NULL, {NULL, NULL, NULL, NULL, &((object *)0)->field, NULL} } + { name, KX_PYATTRIBUTE_TYPE_STRING, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, false, offsetof(object,field), 0, 1, &object::function, NULL, NULL, {NULL, NULL, NULL, NULL, &((object *)0)->field, NULL, NULL} } #define KX_PYATTRIBUTE_STRING_RO(name,object,field) \ - { name, KX_PYATTRIBUTE_TYPE_STRING, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, offsetof(object,field), 0, 1 , NULL, NULL, NULL, {NULL, NULL, NULL, NULL, &((object *)0)->field, NULL} } + { name, KX_PYATTRIBUTE_TYPE_STRING, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, false, offsetof(object,field), 0, 1 , NULL, NULL, NULL, {NULL, NULL, NULL, NULL, &((object *)0)->field, NULL, NULL} } + +// only for char [] array +#define KX_PYATTRIBUTE_CHAR_RW(name,object,field) \ + { name, KX_PYATTRIBUTE_TYPE_CHAR, KX_PYATTRIBUTE_RW, 0, 0, 0.f, 0.f, true, false, offsetof(object,field), sizeof(((object *)0)->field), 1, NULL, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, NULL, ((object *)0)->field} } +#define KX_PYATTRIBUTE_CHAR_RW_CHECK(name,object,field,function) \ + { name, KX_PYATTRIBUTE_TYPE_CHAR, KX_PYATTRIBUTE_RW, 0, 0, 0.f, 0.f, true, false, offsetof(object,field), sizeof(((object *)0)->field), 1, &object::function, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, NULL, ((object *)0)->field} } +#define KX_PYATTRIBUTE_CHAR_RO(name,object,field) \ + { name, KX_PYATTRIBUTE_TYPE_CHAR, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, false, offsetof(object,field), sizeof(((object *)0)->field), 1 , NULL, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, NULL, ((object *)0)->field} } +// for MT_Vector3 member #define KX_PYATTRIBUTE_VECTOR_RW(name,min,max,object,field) \ - { name, KX_PYATTRIBUTE_TYPE_VECTOR, KX_PYATTRIBUTE_RW, 0, 0, min, max, true, offsetof(object,field), 0, 1, NULL, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, &((object *)0)->field} } + { name, KX_PYATTRIBUTE_TYPE_VECTOR, KX_PYATTRIBUTE_RW, 0, 0, min, max, true, false, offsetof(object,field), 0, 1, NULL, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, &((object *)0)->field, NULL} } #define KX_PYATTRIBUTE_VECTOR_RW_CHECK(name,min,max,clamp,object,field,function) \ - { name, KX_PYATTRIBUTE_TYPE_VECTOR, KX_PYATTRIBUTE_RW, 0, 0, min, max, true, offsetof(object,field), 0, 1, &object::function, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, &((object *)0)->field} } + { name, KX_PYATTRIBUTE_TYPE_VECTOR, KX_PYATTRIBUTE_RW, 0, 0, min, max, true, false, offsetof(object,field), 0, 1, &object::function, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, &((object *)0)->field, NULL} } #define KX_PYATTRIBUTE_VECTOR_RO(name,object,field) \ - { name, KX_PYATTRIBUTE_TYPE_VECTOR, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, offsetof(object,field), 0, 1 , NULL, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, &((object *)0)->field} } + { name, KX_PYATTRIBUTE_TYPE_VECTOR, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, false, offsetof(object,field), 0, 1 , NULL, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, &((object *)0)->field, NULL} } #define KX_PYATTRIBUTE_RW_FUNCTION(name,object,getfunction,setfunction) \ - { name, KX_PYATTRIBUTE_TYPE_FUNCTION, KX_PYATTRIBUTE_RW, 0, 0, 0.f, 0.f, false, 0, 0, 1, NULL, &object::setfunction, &object::getfunction, {NULL, NULL, NULL, NULL, NULL, NULL} } + { name, KX_PYATTRIBUTE_TYPE_FUNCTION, KX_PYATTRIBUTE_RW, 0, 0, 0.f, 0.f, false, false, 0, 0, 1, NULL, &object::setfunction, &object::getfunction, {NULL, NULL, NULL, NULL, NULL, NULL, NULL} } #define KX_PYATTRIBUTE_RO_FUNCTION(name,object,getfunction) \ - { name, KX_PYATTRIBUTE_TYPE_FUNCTION, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, 0, 0, 1, NULL, NULL, &object::getfunction, {NULL, NULL, NULL, NULL, NULL, NULL} } + { name, KX_PYATTRIBUTE_TYPE_FUNCTION, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, false, 0, 0, 1, NULL, NULL, &object::getfunction, {NULL, NULL, NULL, NULL, NULL, NULL, NULL} } #define KX_PYATTRIBUTE_ARRAY_RW_FUNCTION(name,object,length,getfunction,setfunction) \ - { name, KX_PYATTRIBUTE_TYPE_FUNCTION, KX_PYATTRIBUTE_RW, 0, 0, 0.f, 0,f, false, 0, 0, length, NULL, &object::setfunction, &object::getfunction, {NULL, NULL, NULL, NULL, NULL, NULL} } + { name, KX_PYATTRIBUTE_TYPE_FUNCTION, KX_PYATTRIBUTE_RW, 0, 0, 0.f, 0,f, false, false, 0, 0, length, NULL, &object::setfunction, &object::getfunction, {NULL, NULL, NULL, NULL, NULL, NULL, NULL} } #define KX_PYATTRIBUTE_ARRAY_RO_FUNCTION(name,object,length,getfunction) \ - { name, KX_PYATTRIBUTE_TYPE_FUNCTION, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0,f, false, 0, 0, length, NULL, NULL, &object::getfunction, {NULL, NULL, NULL, NULL, NULL, NULL} } + { name, KX_PYATTRIBUTE_TYPE_FUNCTION, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0,f, false, false, 0, 0, length, NULL, NULL, &object::getfunction, {NULL, NULL, NULL, NULL, NULL, NULL, NULL} } /*------------------------------ @@ -422,16 +497,23 @@ public: /* These are all virtual python methods that are defined in each class * Our own fake subclassing calls these on each class, then calls the parent */ virtual PyObject* py_repr(void); + /* subclass may overwrite this function to implement more sophisticated method of validating a proxy */ + virtual bool py_is_valid(void) { return true; } static PyObject* py_get_attrdef(PyObject *self_py, const PyAttributeDef *attrdef); static int py_set_attrdef(PyObject *self_py, PyObject *value, const PyAttributeDef *attrdef); /* Kindof dumb, always returns True, the false case is checked for, before this function gets accessed */ static PyObject* pyattr_get_invalid(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - - static PyObject *GetProxy_Ext(PyObjectPlus *self, PyTypeObject *tp); - static PyObject *NewProxy_Ext(PyObjectPlus *self, PyTypeObject *tp, bool py_owns); - + + static PyObject *GetProxyPlus_Ext(PyObjectPlus *self, PyTypeObject *tp, void *ptr); + /* self=NULL => proxy to generic pointer detached from GE object + if py_owns is true, the memory pointed by ptr will be deleted automatially with MEM_freeN + self!=NULL=> proxy attached to GE object, ptr is optional and point to a struct from which attributes can be defined + if py_owns is true, the object will be deleted automatically, ptr will NOT be deleted + (assume object destructor takes care of it) */ + static PyObject *NewProxyPlus_Ext(PyObjectPlus *self, PyTypeObject *tp, void *ptr, bool py_owns); + void InvalidateProxy(); /** diff --git a/source/gameengine/Expressions/SConscript b/source/gameengine/Expressions/SConscript index c819bfb0d3e..26cafb004b2 100644 --- a/source/gameengine/Expressions/SConscript +++ b/source/gameengine/Expressions/SConscript @@ -3,7 +3,7 @@ Import ('env') sources = env.Glob('*.cpp') -incs ='. #source/kernel/gen_system #intern/string #intern/moto/include #source/gameengine/SceneGraph #source/blender/blenloader' +incs ='. #source/kernel/gen_system #intern/guardedalloc #intern/string #intern/moto/include #source/gameengine/SceneGraph #source/blender/blenloader' incs += ' ' + env['BF_PYTHON_INC'] env.BlenderLib ( 'bf_expressions', sources, Split(incs), [], libtype=['core','player'], priority = [360,80], cxx_compileflags=env['BGE_CXXFLAGS']) diff --git a/source/gameengine/GameLogic/SCA_2DFilterActuator.cpp b/source/gameengine/GameLogic/SCA_2DFilterActuator.cpp index 9dfb5ddc38f..9b04e263350 100644 --- a/source/gameengine/GameLogic/SCA_2DFilterActuator.cpp +++ b/source/gameengine/GameLogic/SCA_2DFilterActuator.cpp @@ -43,7 +43,7 @@ SCA_2DFilterActuator::SCA_2DFilterActuator( int int_arg, RAS_IRasterizer* rasterizer, RAS_IRenderTools* rendertools) - : SCA_IActuator(gameobj), + : SCA_IActuator(gameobj, KX_ACT_2DFILTER), m_type(type), m_disableMotionBlur(flag), m_float_arg(float_arg), diff --git a/source/gameengine/GameLogic/SCA_ActuatorEventManager.cpp b/source/gameengine/GameLogic/SCA_ActuatorEventManager.cpp index a80b2af55c8..e4dfe4e0bff 100644 --- a/source/gameengine/GameLogic/SCA_ActuatorEventManager.cpp +++ b/source/gameengine/GameLogic/SCA_ActuatorEventManager.cpp @@ -36,8 +36,7 @@ SCA_ActuatorEventManager::SCA_ActuatorEventManager(class SCA_LogicManager* logicmgr) - : SCA_EventManager(ACTUATOR_EVENTMGR), - m_logicmgr(logicmgr) + : SCA_EventManager(logicmgr, ACTUATOR_EVENTMGR) { } diff --git a/source/gameengine/GameLogic/SCA_ActuatorEventManager.h b/source/gameengine/GameLogic/SCA_ActuatorEventManager.h index f3884c87a75..8c86d0dd422 100644 --- a/source/gameengine/GameLogic/SCA_ActuatorEventManager.h +++ b/source/gameengine/GameLogic/SCA_ActuatorEventManager.h @@ -37,8 +37,6 @@ using namespace std; class SCA_ActuatorEventManager : public SCA_EventManager { - class SCA_LogicManager* m_logicmgr; - public: SCA_ActuatorEventManager(class SCA_LogicManager* logicmgr); virtual ~SCA_ActuatorEventManager(); diff --git a/source/gameengine/GameLogic/SCA_AlwaysEventManager.cpp b/source/gameengine/GameLogic/SCA_AlwaysEventManager.cpp index dd3b55abcc9..aee01606974 100644 --- a/source/gameengine/GameLogic/SCA_AlwaysEventManager.cpp +++ b/source/gameengine/GameLogic/SCA_AlwaysEventManager.cpp @@ -42,8 +42,7 @@ using namespace std; SCA_AlwaysEventManager::SCA_AlwaysEventManager(class SCA_LogicManager* logicmgr) - : SCA_EventManager(ALWAYS_EVENTMGR), - m_logicmgr(logicmgr) + : SCA_EventManager(logicmgr, ALWAYS_EVENTMGR) { } diff --git a/source/gameengine/GameLogic/SCA_AlwaysEventManager.h b/source/gameengine/GameLogic/SCA_AlwaysEventManager.h index 9540e3b71f6..f7fb3b9714e 100644 --- a/source/gameengine/GameLogic/SCA_AlwaysEventManager.h +++ b/source/gameengine/GameLogic/SCA_AlwaysEventManager.h @@ -34,8 +34,6 @@ using namespace std; class SCA_AlwaysEventManager : public SCA_EventManager { - - class SCA_LogicManager* m_logicmgr; public: SCA_AlwaysEventManager(class SCA_LogicManager* logicmgr); virtual void NextFrame(); diff --git a/source/gameengine/GameLogic/SCA_BasicEventManager.cpp b/source/gameengine/GameLogic/SCA_BasicEventManager.cpp new file mode 100644 index 00000000000..a2a7e535b5c --- /dev/null +++ b/source/gameengine/GameLogic/SCA_BasicEventManager.cpp @@ -0,0 +1,61 @@ +/** + * Manager for 'always' events. Since always sensors can operate in pulse + * mode, they need to be activated. + * + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "SCA_BasicEventManager.h" +#include "SCA_LogicManager.h" +#include <vector> +#include "SCA_ISensor.h" + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +using namespace std; + +SCA_BasicEventManager::SCA_BasicEventManager(class SCA_LogicManager* logicmgr) + : SCA_EventManager(logicmgr, BASIC_EVENTMGR) +{ +} + +SCA_BasicEventManager::~SCA_BasicEventManager() +{ +} + +void SCA_BasicEventManager::NextFrame() +{ + SG_DList::iterator<SCA_ISensor> it(m_sensors); + for (it.begin();!it.end();++it) + { + (*it)->Activate(m_logicmgr); + } +} + diff --git a/source/gameengine/GameLogic/SCA_BasicEventManager.h b/source/gameengine/GameLogic/SCA_BasicEventManager.h new file mode 100644 index 00000000000..3bd2df08c07 --- /dev/null +++ b/source/gameengine/GameLogic/SCA_BasicEventManager.h @@ -0,0 +1,57 @@ +/** + * Manager for sensor that only need to call Update + * + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef __SCA_BASICEVENTMGR +#define __SCA_BASICEVENTMGR + +#include "SCA_EventManager.h" +#include <vector> + +using namespace std; + +class SCA_BasicEventManager : public SCA_EventManager +{ +public: + SCA_BasicEventManager(class SCA_LogicManager* logicmgr); + ~SCA_BasicEventManager(); + + virtual void NextFrame(); + + +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:SCA_BasicEventManager"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif +}; + +#endif //__SCA_BASICEVENTMGR + diff --git a/source/gameengine/GameLogic/SCA_EventManager.cpp b/source/gameengine/GameLogic/SCA_EventManager.cpp index d1301541a0a..5b6f3c46022 100644 --- a/source/gameengine/GameLogic/SCA_EventManager.cpp +++ b/source/gameengine/GameLogic/SCA_EventManager.cpp @@ -35,8 +35,9 @@ #endif -SCA_EventManager::SCA_EventManager(EVENT_MANAGER_TYPE mgrtype) - :m_mgrtype(mgrtype) +SCA_EventManager::SCA_EventManager(SCA_LogicManager* logicmgr, EVENT_MANAGER_TYPE mgrtype) + :m_logicmgr(logicmgr), + m_mgrtype(mgrtype) { } diff --git a/source/gameengine/GameLogic/SCA_EventManager.h b/source/gameengine/GameLogic/SCA_EventManager.h index 424150ffa63..debefcc45b0 100644 --- a/source/gameengine/GameLogic/SCA_EventManager.h +++ b/source/gameengine/GameLogic/SCA_EventManager.h @@ -38,6 +38,8 @@ class SCA_EventManager { protected: + class SCA_LogicManager* m_logicmgr; /* all event manager subclasses use this (other then TimeEventManager) */ + // use a set to speed-up insertion/removal //std::set <class SCA_ISensor*> m_sensors; SG_DList m_sensors; @@ -52,13 +54,13 @@ public: TIME_EVENTMGR, RANDOM_EVENTMGR, RAY_EVENTMGR, - RADAR_EVENTMGR, NETWORK_EVENTMGR, JOY_EVENTMGR, - ACTUATOR_EVENTMGR + ACTUATOR_EVENTMGR, + BASIC_EVENTMGR }; - SCA_EventManager(EVENT_MANAGER_TYPE mgrtype); + SCA_EventManager(SCA_LogicManager* logicmgr, EVENT_MANAGER_TYPE mgrtype); virtual ~SCA_EventManager(); virtual void RemoveSensor(class SCA_ISensor* sensor); diff --git a/source/gameengine/GameLogic/SCA_IActuator.cpp b/source/gameengine/GameLogic/SCA_IActuator.cpp index 0fda75590c1..0338213b3cf 100644 --- a/source/gameengine/GameLogic/SCA_IActuator.cpp +++ b/source/gameengine/GameLogic/SCA_IActuator.cpp @@ -34,8 +34,9 @@ using namespace std; -SCA_IActuator::SCA_IActuator(SCA_IObject* gameobj) : +SCA_IActuator::SCA_IActuator(SCA_IObject* gameobj, KX_ACTUATOR_TYPE type) : SCA_ILogicBrick(gameobj), + m_type(type), m_links(0), m_posevent(false), m_negevent(false) diff --git a/source/gameengine/GameLogic/SCA_IActuator.h b/source/gameengine/GameLogic/SCA_IActuator.h index 00ba8c9ce4e..2f1c04192ab 100644 --- a/source/gameengine/GameLogic/SCA_IActuator.h +++ b/source/gameengine/GameLogic/SCA_IActuator.h @@ -41,6 +41,7 @@ class SCA_IActuator : public SCA_ILogicBrick { friend class SCA_LogicManager; protected: + int m_type; int m_links; // number of active links to controllers // when 0, the actuator is automatically stopped //std::vector<CValue*> m_events; @@ -60,8 +61,33 @@ public: /** * This class also inherits the default copy constructors */ - - SCA_IActuator(SCA_IObject* gameobj); + enum KX_ACTUATOR_TYPE { + KX_ACT_OBJECT, + KX_ACT_IPO, + KX_ACT_CAMERA, + KX_ACT_SOUND, + KX_ACT_PROPERTY, + KX_ACT_ADD_OBJECT, + KX_ACT_END_OBJECT, + KX_ACT_DYNAMIC, + KX_ACT_REPLACE_MESH, + KX_ACT_TRACKTO, + KX_ACT_CONSTRAINT, + KX_ACT_SCENE, + KX_ACT_RANDOM, + KX_ACT_MESSAGE, + KX_ACT_ACTION, + KX_ACT_CD, + KX_ACT_GAME, + KX_ACT_VISIBILITY, + KX_ACT_2DFILTER, + KX_ACT_PARENT, + KX_ACT_SHAPEACTION, + KX_ACT_STATE, + KX_ACT_ARMATURE, + }; + + SCA_IActuator(SCA_IObject* gameobj, KX_ACTUATOR_TYPE type); /** * UnlinkObject(...) @@ -127,7 +153,7 @@ public: void IncLink() { m_links++; } void DecLink(); bool IsNoLink() const { return !m_links; } - + bool IsType(KX_ACTUATOR_TYPE type) { return m_type == type; } #ifdef WITH_CXX_GUARDEDALLOC public: diff --git a/source/gameengine/GameLogic/SCA_IObject.cpp b/source/gameengine/GameLogic/SCA_IObject.cpp index 2bffd029bd4..fbf66b64d08 100644 --- a/source/gameengine/GameLogic/SCA_IObject.cpp +++ b/source/gameengine/GameLogic/SCA_IObject.cpp @@ -26,6 +26,7 @@ * ***** END GPL LICENSE BLOCK ***** */ #include <iostream> +#include <algorithm> #include "SCA_IObject.h" #include "SCA_ISensor.h" @@ -76,6 +77,12 @@ SCA_IObject::~SCA_IObject() (*ita)->Delete(); } + SCA_ObjectList::iterator ito; + for (ito = m_registeredObjects.begin(); !(ito==m_registeredObjects.end()); ++ito) + { + (*ito)->UnlinkObject(this); + } + //T_InterpolatorList::iterator i; //for (i = m_interpolators.begin(); !(i == m_interpolators.end()); ++i) { // delete *i; @@ -123,6 +130,26 @@ void SCA_IObject::UnregisterActuator(SCA_IActuator* act) } } +void SCA_IObject::RegisterObject(SCA_IObject* obj) +{ + // one object may be registered multiple times via constraint target + // store multiple reference, this will serve as registration counter + m_registeredObjects.push_back(obj); +} + +void SCA_IObject::UnregisterObject(SCA_IObject* obj) +{ + SCA_ObjectList::iterator ito; + for (ito = m_registeredObjects.begin(); ito != m_registeredObjects.end(); ++ito) + { + if ((*ito) == obj) { + (*ito) = m_registeredObjects.back(); + m_registeredObjects.pop_back(); + break; + } + } +} + void SCA_IObject::ReParentLogic() { SCA_ActuatorList& oldactuators = GetActuators(); @@ -165,7 +192,7 @@ void SCA_IObject::ReParentLogic() // a new object cannot be client of any actuator m_registeredActuators.clear(); - + m_registeredObjects.clear(); } diff --git a/source/gameengine/GameLogic/SCA_IObject.h b/source/gameengine/GameLogic/SCA_IObject.h index 3060410dc6b..64ea0a76af1 100644 --- a/source/gameengine/GameLogic/SCA_IObject.h +++ b/source/gameengine/GameLogic/SCA_IObject.h @@ -36,6 +36,7 @@ #include "Value.h" #include <vector> +class SCA_IObject; class SCA_ISensor; class SCA_IController; class SCA_IActuator; @@ -45,6 +46,7 @@ template<class T> T PyVecTo(PyObject*); typedef std::vector<SCA_ISensor *> SCA_SensorList; typedef std::vector<SCA_IController *> SCA_ControllerList; typedef std::vector<SCA_IActuator *> SCA_ActuatorList; +typedef std::vector<SCA_IObject *> SCA_ObjectList; class SCA_IObject : public CValue { @@ -59,6 +61,7 @@ protected: SCA_ControllerList m_controllers; SCA_ActuatorList m_actuators; SCA_ActuatorList m_registeredActuators; // actuators that use a pointer to this object + SCA_ObjectList m_registeredObjects; // objects that hold reference to this object // SG_Dlist: element of objects with active actuators // Head: SCA_LogicManager::m_activeActuators @@ -143,13 +146,22 @@ public: void RegisterActuator(SCA_IActuator* act); void UnregisterActuator(SCA_IActuator* act); + void RegisterObject(SCA_IObject* objs); + void UnregisterObject(SCA_IObject* objs); + /** + * UnlinkObject(...) + * this object is informed that one of the object to which it holds a reference is deleted + * returns true if there was indeed a reference. + */ + virtual bool UnlinkObject(SCA_IObject* clientobj) { return false; } + SCA_ISensor* FindSensor(const STR_String& sensorname); SCA_IActuator* FindActuator(const STR_String& actuatorname); SCA_IController* FindController(const STR_String& controllername); void SetCurrentTime(float currentTime) {} - void ReParentLogic(); + virtual void ReParentLogic(); /** * Set whether or not to ignore activity culling requests diff --git a/source/gameengine/GameLogic/SCA_JoystickManager.cpp b/source/gameengine/GameLogic/SCA_JoystickManager.cpp index ff8f3b1c81f..480292774da 100644 --- a/source/gameengine/GameLogic/SCA_JoystickManager.cpp +++ b/source/gameengine/GameLogic/SCA_JoystickManager.cpp @@ -37,8 +37,7 @@ SCA_JoystickManager::SCA_JoystickManager(class SCA_LogicManager* logicmgr) - : SCA_EventManager(JOY_EVENTMGR), - m_logicmgr(logicmgr) + : SCA_EventManager(logicmgr, JOY_EVENTMGR) { int i; for (i=0; i<JOYINDEX_MAX; i++) { diff --git a/source/gameengine/GameLogic/SCA_JoystickManager.h b/source/gameengine/GameLogic/SCA_JoystickManager.h index be55e95b033..cd0e22cc367 100644 --- a/source/gameengine/GameLogic/SCA_JoystickManager.h +++ b/source/gameengine/GameLogic/SCA_JoystickManager.h @@ -35,8 +35,6 @@ using namespace std; class SCA_JoystickManager : public SCA_EventManager { - - class SCA_LogicManager* m_logicmgr; /** * SDL Joystick Class Instance */ diff --git a/source/gameengine/GameLogic/SCA_KeyboardManager.cpp b/source/gameengine/GameLogic/SCA_KeyboardManager.cpp index 279adab94d8..3d010f57055 100644 --- a/source/gameengine/GameLogic/SCA_KeyboardManager.cpp +++ b/source/gameengine/GameLogic/SCA_KeyboardManager.cpp @@ -37,9 +37,8 @@ SCA_KeyboardManager::SCA_KeyboardManager(SCA_LogicManager* logicmgr, SCA_IInputDevice* inputdev) - : SCA_EventManager(KEYBOARD_EVENTMGR), - m_inputDevice(inputdev), - m_logicmanager(logicmgr) + : SCA_EventManager(logicmgr, KEYBOARD_EVENTMGR), + m_inputDevice(inputdev) { } @@ -65,7 +64,7 @@ void SCA_KeyboardManager::NextFrame() SG_DList::iterator<SCA_ISensor> it(m_sensors); for (it.begin();!it.end();++it) { - (*it)->Activate(m_logicmanager); + (*it)->Activate(m_logicmgr); } } diff --git a/source/gameengine/GameLogic/SCA_KeyboardManager.h b/source/gameengine/GameLogic/SCA_KeyboardManager.h index c5553a74aef..8155283a274 100644 --- a/source/gameengine/GameLogic/SCA_KeyboardManager.h +++ b/source/gameengine/GameLogic/SCA_KeyboardManager.h @@ -45,8 +45,6 @@ using namespace std; class SCA_KeyboardManager : public SCA_EventManager { class SCA_IInputDevice* m_inputDevice; - class SCA_LogicManager* m_logicmanager; - public: SCA_KeyboardManager(class SCA_LogicManager* logicmgr,class SCA_IInputDevice* inputdev); diff --git a/source/gameengine/GameLogic/SCA_MouseManager.cpp b/source/gameengine/GameLogic/SCA_MouseManager.cpp index d407647cec3..c752701e785 100644 --- a/source/gameengine/GameLogic/SCA_MouseManager.cpp +++ b/source/gameengine/GameLogic/SCA_MouseManager.cpp @@ -48,9 +48,8 @@ SCA_MouseManager::SCA_MouseManager(SCA_LogicManager* logicmgr, SCA_IInputDevice* mousedev) - : SCA_EventManager(MOUSE_EVENTMGR), - m_mousedevice (mousedev), - m_logicmanager(logicmgr) + : SCA_EventManager(logicmgr, MOUSE_EVENTMGR), + m_mousedevice (mousedev) { m_xpos = 0; m_ypos = 0; @@ -93,7 +92,7 @@ void SCA_MouseManager::NextFrame() mousesensor->setX(mx); mousesensor->setY(my); - mousesensor->Activate(m_logicmanager); + mousesensor->Activate(m_logicmgr); } } } diff --git a/source/gameengine/GameLogic/SCA_MouseManager.h b/source/gameengine/GameLogic/SCA_MouseManager.h index ef1533c636b..00bbab66aa6 100644 --- a/source/gameengine/GameLogic/SCA_MouseManager.h +++ b/source/gameengine/GameLogic/SCA_MouseManager.h @@ -47,7 +47,6 @@ class SCA_MouseManager : public SCA_EventManager { class SCA_IInputDevice* m_mousedevice; - class SCA_LogicManager* m_logicmanager; unsigned short m_xpos; // Cached location of the mouse pointer unsigned short m_ypos; diff --git a/source/gameengine/GameLogic/SCA_PropertyActuator.cpp b/source/gameengine/GameLogic/SCA_PropertyActuator.cpp index 9446487cdb7..2a3e600a653 100644 --- a/source/gameengine/GameLogic/SCA_PropertyActuator.cpp +++ b/source/gameengine/GameLogic/SCA_PropertyActuator.cpp @@ -43,7 +43,7 @@ /* ------------------------------------------------------------------------- */ SCA_PropertyActuator::SCA_PropertyActuator(SCA_IObject* gameobj,SCA_IObject* sourceObj,const STR_String& propname,const STR_String& expr,int acttype) - : SCA_IActuator(gameobj), + : SCA_IActuator(gameobj, KX_ACT_PROPERTY), m_type(acttype), m_propname(propname), m_exprtxt(expr), diff --git a/source/gameengine/GameLogic/SCA_PropertyEventManager.cpp b/source/gameengine/GameLogic/SCA_PropertyEventManager.cpp index 764465309df..e01ce74e0a9 100644 --- a/source/gameengine/GameLogic/SCA_PropertyEventManager.cpp +++ b/source/gameengine/GameLogic/SCA_PropertyEventManager.cpp @@ -35,8 +35,7 @@ SCA_PropertyEventManager::SCA_PropertyEventManager(class SCA_LogicManager* logicmgr) - : SCA_EventManager(PROPERTY_EVENTMGR), - m_logicmgr(logicmgr) + : SCA_EventManager(logicmgr, PROPERTY_EVENTMGR) { } diff --git a/source/gameengine/GameLogic/SCA_PropertyEventManager.h b/source/gameengine/GameLogic/SCA_PropertyEventManager.h index a9692377df8..5a036abb8b7 100644 --- a/source/gameengine/GameLogic/SCA_PropertyEventManager.h +++ b/source/gameengine/GameLogic/SCA_PropertyEventManager.h @@ -37,8 +37,6 @@ using namespace std; class SCA_PropertyEventManager : public SCA_EventManager { - class SCA_LogicManager* m_logicmgr; - public: SCA_PropertyEventManager(class SCA_LogicManager* logicmgr); virtual ~SCA_PropertyEventManager(); diff --git a/source/gameengine/GameLogic/SCA_RandomActuator.cpp b/source/gameengine/GameLogic/SCA_RandomActuator.cpp index a3a5cc2303e..8f9482b7826 100644 --- a/source/gameengine/GameLogic/SCA_RandomActuator.cpp +++ b/source/gameengine/GameLogic/SCA_RandomActuator.cpp @@ -51,7 +51,7 @@ SCA_RandomActuator::SCA_RandomActuator(SCA_IObject *gameobj, float para1, float para2, const STR_String &propName) - : SCA_IActuator(gameobj), + : SCA_IActuator(gameobj, KX_ACT_RANDOM), m_propname(propName), m_parameter1(para1), m_parameter2(para2), diff --git a/source/gameengine/GameLogic/SCA_RandomEventManager.cpp b/source/gameengine/GameLogic/SCA_RandomEventManager.cpp index 976597aa812..780f8d10857 100644 --- a/source/gameengine/GameLogic/SCA_RandomEventManager.cpp +++ b/source/gameengine/GameLogic/SCA_RandomEventManager.cpp @@ -42,8 +42,7 @@ using namespace std; #endif SCA_RandomEventManager::SCA_RandomEventManager(class SCA_LogicManager* logicmgr) - : SCA_EventManager(RANDOM_EVENTMGR), - m_logicmgr(logicmgr) + : SCA_EventManager(logicmgr, RANDOM_EVENTMGR) { } diff --git a/source/gameengine/GameLogic/SCA_RandomEventManager.h b/source/gameengine/GameLogic/SCA_RandomEventManager.h index c8b511b87b7..81896709551 100644 --- a/source/gameengine/GameLogic/SCA_RandomEventManager.h +++ b/source/gameengine/GameLogic/SCA_RandomEventManager.h @@ -39,8 +39,6 @@ using namespace std; class SCA_RandomEventManager : public SCA_EventManager { - class SCA_LogicManager* m_logicmgr; - public: SCA_RandomEventManager(class SCA_LogicManager* logicmgr); diff --git a/source/gameengine/GameLogic/SCA_TimeEventManager.cpp b/source/gameengine/GameLogic/SCA_TimeEventManager.cpp index 911ea772bef..1b49906b8de 100644 --- a/source/gameengine/GameLogic/SCA_TimeEventManager.cpp +++ b/source/gameengine/GameLogic/SCA_TimeEventManager.cpp @@ -43,7 +43,7 @@ #include "FloatValue.h" SCA_TimeEventManager::SCA_TimeEventManager(SCA_LogicManager* logicmgr) -: SCA_EventManager(TIME_EVENTMGR) +: SCA_EventManager(NULL, TIME_EVENTMGR) { } diff --git a/source/gameengine/Ketsji/KXNetwork/KX_NetworkEventManager.cpp b/source/gameengine/Ketsji/KXNetwork/KX_NetworkEventManager.cpp index 738f64713b0..65f7d98253c 100644 --- a/source/gameengine/Ketsji/KXNetwork/KX_NetworkEventManager.cpp +++ b/source/gameengine/Ketsji/KXNetwork/KX_NetworkEventManager.cpp @@ -45,7 +45,7 @@ KX_NetworkEventManager::KX_NetworkEventManager(class SCA_LogicManager* logicmgr, class NG_NetworkDeviceInterface *ndi) : -SCA_EventManager(NETWORK_EVENTMGR), m_logicmgr(logicmgr), m_ndi(ndi) +SCA_EventManager(logicmgr, NETWORK_EVENTMGR), m_ndi(ndi) { //printf("KX_NetworkEventManager constructor\n"); } diff --git a/source/gameengine/Ketsji/KXNetwork/KX_NetworkEventManager.h b/source/gameengine/Ketsji/KXNetwork/KX_NetworkEventManager.h index ae88f1d4987..fd776640bcf 100644 --- a/source/gameengine/Ketsji/KXNetwork/KX_NetworkEventManager.h +++ b/source/gameengine/Ketsji/KXNetwork/KX_NetworkEventManager.h @@ -34,7 +34,6 @@ class KX_NetworkEventManager : public SCA_EventManager { - class SCA_LogicManager* m_logicmgr; class NG_NetworkDeviceInterface* m_ndi; public: diff --git a/source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageActuator.cpp b/source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageActuator.cpp index 3af8f765251..1cfab87d78b 100644 --- a/source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageActuator.cpp +++ b/source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageActuator.cpp @@ -42,7 +42,7 @@ KX_NetworkMessageActuator::KX_NetworkMessageActuator( const STR_String &subject, int bodyType, const STR_String &body) : - SCA_IActuator(gameobj), + SCA_IActuator(gameobj, KX_ACT_MESSAGE), m_networkscene(networkscene), m_toPropName(toPropName), m_subject(subject), diff --git a/source/gameengine/Ketsji/KX_ArmatureSensor.cpp b/source/gameengine/Ketsji/KX_ArmatureSensor.cpp new file mode 100644 index 00000000000..1b759bda28e --- /dev/null +++ b/source/gameengine/Ketsji/KX_ArmatureSensor.cpp @@ -0,0 +1,205 @@ +/** + * Armature sensor + * + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "DNA_action_types.h" +#include "DNA_constraint_types.h" +#include "BKE_constraint.h" +#include "DNA_sensor_types.h" + +#include "BL_ArmatureObject.h" +#include "KX_ArmatureSensor.h" +#include "SCA_EventManager.h" +#include "SCA_LogicManager.h" + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +KX_ArmatureSensor::KX_ArmatureSensor(class SCA_EventManager* eventmgr, + SCA_IObject* gameobj, + const char *posechannel, + const char *constraintname, + int type, + float value) + : SCA_ISensor(gameobj,eventmgr), + m_constraint(NULL), + m_posechannel(posechannel), + m_constraintname(constraintname), + m_type(type), + m_value(value) +{ + FindConstraint(); +} + +void KX_ArmatureSensor::Init() +{ + m_lastresult = m_invert?true:false; + m_result = false; + m_reset = true; +} + +void KX_ArmatureSensor::FindConstraint() +{ + m_constraint = NULL; + + if (m_gameobj->GetGameObjectType() == SCA_IObject::OBJ_ARMATURE) { + BL_ArmatureObject* armobj = (BL_ArmatureObject*)m_gameobj; + // get the persistent pose structure + bPose* pose = armobj->GetOrigPose(); + bPoseChannel* pchan; + bConstraint* pcon; + // and locate the constraint + for (pchan = (bPoseChannel*)pose->chanbase.first; pchan; pchan=(bPoseChannel*)pchan->next) { + if (!strcmp(pchan->name, m_posechannel)) { + // now locate the constraint + for (pcon = (bConstraint*)pchan->constraints.first; pcon; pcon=(bConstraint*)pcon->next) { + if (!strcmp(pcon->name, m_constraintname)) { + if (pcon->flag & CONSTRAINT_DISABLE) + /* this constraint is not valid, can't use it */ + break; + m_constraint = pcon; + break; + } + } + break; + } + } + } +} + + +CValue* KX_ArmatureSensor::GetReplica() +{ + KX_ArmatureSensor* replica = new KX_ArmatureSensor(*this); + // m_range_expr must be recalculated on replica! + replica->ProcessReplica(); + return replica; +} + +void KX_ArmatureSensor::ReParent(SCA_IObject* parent) +{ + SCA_ISensor::ReParent(parent); + // must remap the constraint + FindConstraint(); +} + +bool KX_ArmatureSensor::IsPositiveTrigger() +{ + return (m_invert) ? !m_result : m_result; +} + + +KX_ArmatureSensor::~KX_ArmatureSensor() +{ +} + +bool KX_ArmatureSensor::Evaluate() +{ + bool reset = m_reset && m_level; + + m_reset = false; + if (!m_constraint) + return false; + switch (m_type) { + case SENS_ARM_STATE_CHANGED: + m_result = !(m_constraint->flag & CONSTRAINT_OFF); + break; + case SENS_ARM_LIN_ERROR_BELOW: + m_result = (m_constraint->lin_error < m_value); + break; + case SENS_ARM_LIN_ERROR_ABOVE: + m_result = (m_constraint->lin_error > m_value); + break; + case SENS_ARM_ROT_ERROR_BELOW: + m_result = (m_constraint->rot_error < m_value); + break; + case SENS_ARM_ROT_ERROR_ABOVE: + m_result = (m_constraint->rot_error > m_value); + break; + } + if (m_lastresult!=m_result) + { + m_lastresult = m_result; + return true; + } + return (reset) ? true : false; +} + + +/* ------------------------------------------------------------------------- */ +/* Python functions */ +/* ------------------------------------------------------------------------- */ + +/* Integration hooks ------------------------------------------------------- */ +PyTypeObject KX_ArmatureSensor::Type = { + PyVarObject_HEAD_INIT(NULL, 0) + "KX_ArmatureSensor", + sizeof(PyObjectPlus_Proxy), + 0, + py_base_dealloc, + 0, + 0, + 0, + 0, + py_base_repr, + 0,0,0,0,0,0,0,0,0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + 0,0,0,0,0,0,0, + Methods, + 0, + 0, + &SCA_ISensor::Type, + 0,0,0,0,0,0, + py_base_new +}; + +PyMethodDef KX_ArmatureSensor::Methods[] = { + {NULL,NULL} //Sentinel +}; + +PyAttributeDef KX_ArmatureSensor::Attributes[] = { + KX_PYATTRIBUTE_RO_FUNCTION("constraint", KX_ArmatureSensor, pyattr_get_constraint), + KX_PYATTRIBUTE_FLOAT_RW("value",-FLT_MAX,FLT_MAX,KX_ArmatureSensor,m_value), + KX_PYATTRIBUTE_INT_RW("type",0,SENS_ARM_MAXTYPE,false,KX_ArmatureSensor,m_type), + { NULL } //Sentinel +}; + +PyObject* KX_ArmatureSensor::pyattr_get_constraint(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef) +{ + KX_ArmatureSensor* sensor = static_cast<KX_ArmatureSensor*>(self); + if (sensor->m_gameobj->GetGameObjectType() == SCA_IObject::OBJ_ARMATURE) { + BL_ArmatureObject* armobj = (BL_ArmatureObject*)sensor->m_gameobj; + BL_ArmatureConstraint* constraint = armobj->GetConstraint(sensor->m_posechannel, sensor->m_constraintname); + if (constraint) + return constraint->GetProxy(); + } + Py_RETURN_NONE; +} diff --git a/source/gameengine/Ketsji/KX_ArmatureSensor.h b/source/gameengine/Ketsji/KX_ArmatureSensor.h new file mode 100644 index 00000000000..2af002afff9 --- /dev/null +++ b/source/gameengine/Ketsji/KX_ArmatureSensor.h @@ -0,0 +1,85 @@ +/** + * Property sensor + * + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef __KX_ARMATURESENSOR +#define __KX_ARMATURESENSOR + +struct bConstraint; + +#include "SCA_ISensor.h" +#include "DNA_sensor_types.h" + +class KX_ArmatureSensor : public SCA_ISensor +{ + Py_Header; + //class CExpression* m_rightexpr; + +protected: + +public: + KX_ArmatureSensor(class SCA_EventManager* eventmgr, + SCA_IObject* gameobj, + const char *posechannel, + const char *constraintname, + int type, + float value); + + /** + * For property sensor, it is used to release the pre-calculated expression + * so that self references are removed before the sensor itself is released + */ + virtual ~KX_ArmatureSensor(); + virtual CValue* GetReplica(); + virtual void ReParent(SCA_IObject* parent); + virtual void Init(); + virtual bool Evaluate(); + virtual bool IsPositiveTrigger(); + + // identify the constraint that this actuator controls + void FindConstraint(); + + /* --------------------------------------------------------------------- */ + /* Python interface ---------------------------------------------------- */ + /* --------------------------------------------------------------------- */ + static PyObject* pyattr_get_constraint(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef); + +private: + struct bConstraint* m_constraint; + STR_String m_posechannel; + STR_String m_constraintname; + int m_type; + float m_value; + bool m_result; + bool m_lastresult; +}; + +#endif + diff --git a/source/gameengine/Ketsji/KX_CameraActuator.cpp b/source/gameengine/Ketsji/KX_CameraActuator.cpp index 9c00b5991af..99618fab8e3 100644 --- a/source/gameengine/Ketsji/KX_CameraActuator.cpp +++ b/source/gameengine/Ketsji/KX_CameraActuator.cpp @@ -55,7 +55,7 @@ KX_CameraActuator::KX_CameraActuator( float maxhght, bool xytog ): - SCA_IActuator(gameobj), + SCA_IActuator(gameobj, KX_ACT_CAMERA), m_ob (obj), m_height (hght), m_minHeight (minhght), diff --git a/source/gameengine/Ketsji/KX_ConstraintActuator.cpp b/source/gameengine/Ketsji/KX_ConstraintActuator.cpp index 7f1d2c7d53c..ea0b9f4f1e2 100644 --- a/source/gameengine/Ketsji/KX_ConstraintActuator.cpp +++ b/source/gameengine/Ketsji/KX_ConstraintActuator.cpp @@ -56,7 +56,7 @@ KX_ConstraintActuator::KX_ConstraintActuator(SCA_IObject *gameobj, int time, int option, char *property) : - SCA_IActuator(gameobj), + SCA_IActuator(gameobj, KX_ACT_CONSTRAINT), m_refDirVector(refDir), m_currentTime(0) { diff --git a/source/gameengine/Ketsji/KX_GameActuator.cpp b/source/gameengine/Ketsji/KX_GameActuator.cpp index 42dc4d8fd24..71980a3347e 100644 --- a/source/gameengine/Ketsji/KX_GameActuator.cpp +++ b/source/gameengine/Ketsji/KX_GameActuator.cpp @@ -50,7 +50,7 @@ KX_GameActuator::KX_GameActuator(SCA_IObject *gameobj, const STR_String& loadinganimationname, KX_Scene* scene, KX_KetsjiEngine* ketsjiengine) - : SCA_IActuator(gameobj) + : SCA_IActuator(gameobj, KX_ACT_GAME) { m_mode = mode; m_filename = filename; diff --git a/source/gameengine/Ketsji/KX_GameObject.cpp b/source/gameengine/Ketsji/KX_GameObject.cpp index 8193aa8c37b..a02fd9cec1b 100644 --- a/source/gameengine/Ketsji/KX_GameObject.cpp +++ b/source/gameengine/Ketsji/KX_GameObject.cpp @@ -46,6 +46,7 @@ typedef unsigned long uint_ptr; #define KX_INERTIA_INFINITE 10000 +#include "BLI_arithb.h" #include "RAS_IPolygonMaterial.h" #include "KX_BlenderMaterial.h" #include "KX_GameObject.h" @@ -454,6 +455,22 @@ double* KX_GameObject::GetOpenGLMatrix() return fl; } +void KX_GameObject::UpdateBlenderObjectMatrix(Object* blendobj) +{ + if (!blendobj) + blendobj = m_pBlenderObject; + if (blendobj) { + const MT_Matrix3x3& rot = NodeGetWorldOrientation(); + const MT_Vector3& scale = NodeGetWorldScaling(); + const MT_Vector3& pos = NodeGetWorldPosition(); + rot.getValue(blendobj->obmat[0]); + pos.getValue(blendobj->obmat[3]); + VecMulf(blendobj->obmat[0], scale[0]); + VecMulf(blendobj->obmat[1], scale[1]); + VecMulf(blendobj->obmat[2], scale[2]); + } +} + void KX_GameObject::AddMeshUser() { for (size_t i=0;i<m_meshes.size();i++) diff --git a/source/gameengine/Ketsji/KX_GameObject.h b/source/gameengine/Ketsji/KX_GameObject.h index 845cead1cdb..4c4eed9ca71 100644 --- a/source/gameengine/Ketsji/KX_GameObject.h +++ b/source/gameengine/Ketsji/KX_GameObject.h @@ -158,6 +158,15 @@ public: return &m_OpenGL_4x4Matrix; }; + /** + * Update the blender object obmat field from the object world position + * if blendobj is NULL, update the object pointed by m_pBlenderObject + * The user must take action to restore the matrix before leaving the GE. + * Used in Armature evaluation + */ + void + UpdateBlenderObjectMatrix(Object* blendobj=NULL); + /** * Get a pointer to the game object that is the parent of * this object. Or NULL if there is no parent. The returned diff --git a/source/gameengine/Ketsji/KX_IpoActuator.cpp b/source/gameengine/Ketsji/KX_IpoActuator.cpp index b71907be961..d7f800fe5bd 100644 --- a/source/gameengine/Ketsji/KX_IpoActuator.cpp +++ b/source/gameengine/Ketsji/KX_IpoActuator.cpp @@ -71,7 +71,7 @@ KX_IpoActuator::KX_IpoActuator(SCA_IObject* gameobj, bool ipo_as_force, bool ipo_add, bool ipo_local) - : SCA_IActuator(gameobj), + : SCA_IActuator(gameobj, KX_ACT_IPO), m_bNegativeEvent(false), m_startframe (starttime), m_endframe(endtime), diff --git a/source/gameengine/Ketsji/KX_KetsjiEngine.cpp b/source/gameengine/Ketsji/KX_KetsjiEngine.cpp index 4117e493322..e95676ff9d2 100644 --- a/source/gameengine/Ketsji/KX_KetsjiEngine.cpp +++ b/source/gameengine/Ketsji/KX_KetsjiEngine.cpp @@ -1783,6 +1783,11 @@ double KX_KetsjiEngine::GetClockTime(void) const return m_clockTime; } +double KX_KetsjiEngine::GetFrameTime(void) const +{ + return m_frameTime; +} + double KX_KetsjiEngine::GetRealTime(void) const { return m_kxsystem->GetTimeInSeconds(); diff --git a/source/gameengine/Ketsji/KX_KetsjiEngine.h b/source/gameengine/Ketsji/KX_KetsjiEngine.h index acb9e53df8a..373e8bf218c 100644 --- a/source/gameengine/Ketsji/KX_KetsjiEngine.h +++ b/source/gameengine/Ketsji/KX_KetsjiEngine.h @@ -269,6 +269,10 @@ public: * Returns current render frame clock time */ double GetClockTime(void) const; + /** + * Returns current logic frame clock time + */ + double GetFrameTime(void) const; double GetRealTime(void) const; /** diff --git a/source/gameengine/Ketsji/KX_ObjectActuator.cpp b/source/gameengine/Ketsji/KX_ObjectActuator.cpp index 2601ced9c38..924e4a47008 100644 --- a/source/gameengine/Ketsji/KX_ObjectActuator.cpp +++ b/source/gameengine/Ketsji/KX_ObjectActuator.cpp @@ -55,7 +55,7 @@ KX_ObjectActuator( const short damping, const KX_LocalFlags& flag ) : - SCA_IActuator(gameobj), + SCA_IActuator(gameobj, KX_ACT_OBJECT), m_force(force), m_torque(torque), m_dloc(dloc), diff --git a/source/gameengine/Ketsji/KX_ParentActuator.cpp b/source/gameengine/Ketsji/KX_ParentActuator.cpp index 20e982f03e0..a4a6b67ad10 100644 --- a/source/gameengine/Ketsji/KX_ParentActuator.cpp +++ b/source/gameengine/Ketsji/KX_ParentActuator.cpp @@ -51,7 +51,7 @@ KX_ParentActuator::KX_ParentActuator(SCA_IObject *gameobj, bool addToCompound, bool ghost, SCA_IObject *ob) - : SCA_IActuator(gameobj), + : SCA_IActuator(gameobj, KX_ACT_PARENT), m_mode(mode), m_addToCompound(addToCompound), m_ghost(ghost), diff --git a/source/gameengine/Ketsji/KX_PyMath.h b/source/gameengine/Ketsji/KX_PyMath.h index 17102905607..1ce8bcafbb6 100644 --- a/source/gameengine/Ketsji/KX_PyMath.h +++ b/source/gameengine/Ketsji/KX_PyMath.h @@ -157,7 +157,7 @@ bool PyVecTo(PyObject* pyval, T& vec) return true; } - else if (PyObject_TypeCheck(pyval, &PyObjectPlus::Type)) + else if (PyObject_TypeCheck(pyval, (PyTypeObject *)&PyObjectPlus::Type)) { /* note, include this check because PySequence_Check does too much introspection * on the PyObject (like getting its __class__, on a BGE type this means searching up * the parent list each time only to discover its not a sequence. diff --git a/source/gameengine/Ketsji/KX_PythonInit.cpp b/source/gameengine/Ketsji/KX_PythonInit.cpp index 298d485aaaf..bef00fb7a06 100644 --- a/source/gameengine/Ketsji/KX_PythonInit.cpp +++ b/source/gameengine/Ketsji/KX_PythonInit.cpp @@ -51,6 +51,7 @@ extern "C" { #include "KX_KetsjiEngine.h" #include "KX_RadarSensor.h" #include "KX_RaySensor.h" +#include "KX_ArmatureSensor.h" #include "KX_SceneActuator.h" #include "KX_GameActuator.h" #include "KX_ParentActuator.h" @@ -65,6 +66,7 @@ extern "C" { #include "KX_SoundActuator.h" #include "KX_StateActuator.h" #include "BL_ActionActuator.h" +#include "BL_ArmatureObject.h" #include "RAS_IRasterizer.h" #include "RAS_ICanvas.h" #include "RAS_BucketManager.h" @@ -1218,6 +1220,53 @@ PyObject* initGameLogic(KX_KetsjiEngine *engine, KX_Scene* scene) // quick hack KX_MACRO_addTypesToDict(d, KX_PARENT_SET, KX_ParentActuator::KX_PARENT_SET); KX_MACRO_addTypesToDict(d, KX_PARENT_REMOVE, KX_ParentActuator::KX_PARENT_REMOVE); + /* BL_ArmatureConstraint type */ + KX_MACRO_addTypesToDict(d, CONSTRAINT_TYPE_TRACKTO, CONSTRAINT_TYPE_TRACKTO); + KX_MACRO_addTypesToDict(d, CONSTRAINT_TYPE_KINEMATIC, CONSTRAINT_TYPE_KINEMATIC); + KX_MACRO_addTypesToDict(d, CONSTRAINT_TYPE_ROTLIKE, CONSTRAINT_TYPE_ROTLIKE); + KX_MACRO_addTypesToDict(d, CONSTRAINT_TYPE_LOCLIKE, CONSTRAINT_TYPE_LOCLIKE); + KX_MACRO_addTypesToDict(d, CONSTRAINT_TYPE_MINMAX, CONSTRAINT_TYPE_MINMAX); + KX_MACRO_addTypesToDict(d, CONSTRAINT_TYPE_SIZELIKE, CONSTRAINT_TYPE_SIZELIKE); + KX_MACRO_addTypesToDict(d, CONSTRAINT_TYPE_LOCKTRACK, CONSTRAINT_TYPE_LOCKTRACK); + KX_MACRO_addTypesToDict(d, CONSTRAINT_TYPE_STRETCHTO, CONSTRAINT_TYPE_STRETCHTO); + KX_MACRO_addTypesToDict(d, CONSTRAINT_TYPE_CLAMPTO, CONSTRAINT_TYPE_CLAMPTO); + KX_MACRO_addTypesToDict(d, CONSTRAINT_TYPE_TRANSFORM, CONSTRAINT_TYPE_TRANSFORM); + KX_MACRO_addTypesToDict(d, CONSTRAINT_TYPE_DISTLIMIT, CONSTRAINT_TYPE_DISTLIMIT); + /* BL_ArmatureConstraint ik_type */ + KX_MACRO_addTypesToDict(d, CONSTRAINT_IK_COPYPOSE, CONSTRAINT_IK_COPYPOSE); + KX_MACRO_addTypesToDict(d, CONSTRAINT_IK_DISTANCE, CONSTRAINT_IK_DISTANCE); + /* BL_ArmatureConstraint ik_mode */ + KX_MACRO_addTypesToDict(d, CONSTRAINT_IK_MODE_INSIDE, LIMITDIST_INSIDE); + KX_MACRO_addTypesToDict(d, CONSTRAINT_IK_MODE_OUTSIDE, LIMITDIST_OUTSIDE); + KX_MACRO_addTypesToDict(d, CONSTRAINT_IK_MODE_ONSURFACE, LIMITDIST_ONSURFACE); + /* BL_ArmatureConstraint ik_flag */ + KX_MACRO_addTypesToDict(d, CONSTRAINT_IK_FLAG_TIP, CONSTRAINT_IK_TIP); + KX_MACRO_addTypesToDict(d, CONSTRAINT_IK_FLAG_ROT, CONSTRAINT_IK_ROT); + KX_MACRO_addTypesToDict(d, CONSTRAINT_IK_FLAG_STRETCH, CONSTRAINT_IK_STRETCH); + KX_MACRO_addTypesToDict(d, CONSTRAINT_IK_FLAG_POS, CONSTRAINT_IK_POS); + /* KX_ArmatureSensor type */ + KX_MACRO_addTypesToDict(d, KX_ARMSENSOR_STATE_CHANGED, SENS_ARM_STATE_CHANGED); + KX_MACRO_addTypesToDict(d, KX_ARMSENSOR_LIN_ERROR_BELOW, SENS_ARM_LIN_ERROR_BELOW); + KX_MACRO_addTypesToDict(d, KX_ARMSENSOR_LIN_ERROR_ABOVE, SENS_ARM_LIN_ERROR_ABOVE); + KX_MACRO_addTypesToDict(d, KX_ARMSENSOR_ROT_ERROR_BELOW, SENS_ARM_ROT_ERROR_BELOW); + KX_MACRO_addTypesToDict(d, KX_ARMSENSOR_ROT_ERROR_ABOVE, SENS_ARM_ROT_ERROR_ABOVE); + + /* BL_ArmatureActuator type */ + KX_MACRO_addTypesToDict(d, KX_ACT_ARMATURE_RUN, ACT_ARM_RUN); + KX_MACRO_addTypesToDict(d, KX_ACT_ARMATURE_ENABLE, ACT_ARM_ENABLE); + KX_MACRO_addTypesToDict(d, KX_ACT_ARMATURE_DISABLE, ACT_ARM_DISABLE); + KX_MACRO_addTypesToDict(d, KX_ACT_ARMATURE_SETTARGET, ACT_ARM_SETTARGET); + KX_MACRO_addTypesToDict(d, KX_ACT_ARMATURE_SETWEIGHT, ACT_ARM_SETWEIGHT); + + /* BL_Armature Channel rotation_mode */ + KX_MACRO_addTypesToDict(d, PCHAN_ROT_QUAT, PCHAN_ROT_QUAT); + KX_MACRO_addTypesToDict(d, PCHAN_ROT_XYZ, PCHAN_ROT_XYZ); + KX_MACRO_addTypesToDict(d, PCHAN_ROT_XZY, PCHAN_ROT_XZY); + KX_MACRO_addTypesToDict(d, PCHAN_ROT_YXZ, PCHAN_ROT_YXZ); + KX_MACRO_addTypesToDict(d, PCHAN_ROT_YZX, PCHAN_ROT_YZX); + KX_MACRO_addTypesToDict(d, PCHAN_ROT_ZXY, PCHAN_ROT_ZXY); + KX_MACRO_addTypesToDict(d, PCHAN_ROT_ZYX, PCHAN_ROT_ZYX); + // Check for errors if (PyErr_Occurred()) { diff --git a/source/gameengine/Ketsji/KX_PythonInitTypes.cpp b/source/gameengine/Ketsji/KX_PythonInitTypes.cpp index 61e563791c3..c2c33918172 100644 --- a/source/gameengine/Ketsji/KX_PythonInitTypes.cpp +++ b/source/gameengine/Ketsji/KX_PythonInitTypes.cpp @@ -35,6 +35,10 @@ /* Only for Class::Parents */ #include "BL_BlenderShader.h" #include "BL_ShapeActionActuator.h" +#include "BL_ArmatureActuator.h" +#include "BL_ArmatureConstraint.h" +#include "BL_ArmatureObject.h" +#include "BL_ArmatureChannel.h" #include "KX_BlenderMaterial.h" #include "KX_CameraActuator.h" #include "KX_ConstraintActuator.h" @@ -86,7 +90,22 @@ #include "SCA_RandomActuator.h" #include "SCA_IController.h" -static void PyType_Ready_ADD(PyObject *dict, PyTypeObject *tp, PyAttributeDef *attributes, int init_getset) +static void PyType_Attr_Set(PyGetSetDef *attr_getset, PyAttributeDef *attr) +{ + attr_getset->name= (char *)attr->m_name; + attr_getset->doc= NULL; + + attr_getset->get= reinterpret_cast<getter>(PyObjectPlus::py_get_attrdef); + + if(attr->m_access==KX_PYATTRIBUTE_RO) + attr_getset->set= NULL; + else + attr_getset->set= reinterpret_cast<setter>(PyObjectPlus::py_set_attrdef); + + attr_getset->closure= reinterpret_cast<void *>(attr); +} + +static void PyType_Ready_ADD(PyObject *dict, PyTypeObject *tp, PyAttributeDef *attributes, PyAttributeDef *attributesPtr, int init_getset) { PyAttributeDef *attr; @@ -97,29 +116,31 @@ static void PyType_Ready_ADD(PyObject *dict, PyTypeObject *tp, PyAttributeDef *a //if(tp->tp_base==NULL) // printf("Debug: No Parents - '%s'\n" , tp->tp_name); - if(tp->tp_getset==NULL && attributes->m_name) { + if(tp->tp_getset==NULL && ((attributes && attributes->m_name) || (attributesPtr && attributesPtr->m_name))) { PyGetSetDef *attr_getset; int attr_tot= 0; - for(attr= attributes; attr->m_name; attr++, attr_tot++) {}; + if (attributes) { + for(attr= attributes; attr->m_name; attr++, attr_tot++) + attr->m_usePtr = false; + } + if (attributesPtr) { + for(attr= attributesPtr; attr->m_name; attr++, attr_tot++) + attr->m_usePtr = true; + } tp->tp_getset = attr_getset = reinterpret_cast<PyGetSetDef *>(PyMem_Malloc((attr_tot+1) * sizeof(PyGetSetDef))); // XXX - Todo, free - - for(attr= attributes; attr->m_name; attr++, attr_getset++) { - attr_getset->name= (char *)attr->m_name; - attr_getset->doc= NULL; - - attr_getset->get= reinterpret_cast<getter>(PyObjectPlus::py_get_attrdef); - - if(attr->m_access==KX_PYATTRIBUTE_RO) - attr_getset->set= NULL; - else - attr_getset->set= reinterpret_cast<setter>(PyObjectPlus::py_set_attrdef); - - attr_getset->closure= reinterpret_cast<void *>(attr); + if (attributes) { + for(attr= attributes; attr->m_name; attr++, attr_getset++) { + PyType_Attr_Set(attr_getset, attr); + } + } + if (attributesPtr) { + for(attr= attributesPtr; attr->m_name; attr++, attr_getset++) { + PyType_Attr_Set(attr_getset, attr); + } } - memset(attr_getset, 0, sizeof(PyGetSetDef)); } } else { @@ -130,7 +151,8 @@ static void PyType_Ready_ADD(PyObject *dict, PyTypeObject *tp, PyAttributeDef *a } -#define PyType_Ready_Attr(d, n, i) PyType_Ready_ADD(d, &n::Type, n::Attributes, i) +#define PyType_Ready_Attr(d, n, i) PyType_Ready_ADD(d, &n::Type, n::Attributes, NULL, i) +#define PyType_Ready_AttrPtr(d, n, i) PyType_Ready_ADD(d, &n::Type, n::Attributes, n::AttributesPtr, i) void initPyTypes(void) { @@ -151,6 +173,11 @@ void initPyTypes(void) PyType_Ready_Attr(dict, BL_ActionActuator, init_getset); PyType_Ready_Attr(dict, BL_Shader, init_getset); PyType_Ready_Attr(dict, BL_ShapeActionActuator, init_getset); + PyType_Ready_Attr(dict, BL_ArmatureObject, init_getset); + PyType_Ready_Attr(dict, BL_ArmatureActuator, init_getset); + PyType_Ready_Attr(dict, BL_ArmatureConstraint, init_getset); + PyType_Ready_AttrPtr(dict, BL_ArmatureBone, init_getset); + PyType_Ready_AttrPtr(dict, BL_ArmatureChannel, init_getset); PyType_Ready_Attr(dict, CListValue, init_getset); PyType_Ready_Attr(dict, CValue, init_getset); PyType_Ready_Attr(dict, KX_BlenderMaterial, init_getset); diff --git a/source/gameengine/Ketsji/KX_PythonSeq.cpp b/source/gameengine/Ketsji/KX_PythonSeq.cpp index 75a7c9b8aeb..f7ad7acb252 100644 --- a/source/gameengine/Ketsji/KX_PythonSeq.cpp +++ b/source/gameengine/Ketsji/KX_PythonSeq.cpp @@ -31,6 +31,7 @@ #include "KX_PythonSeq.h" #include "KX_GameObject.h" +#include "BL_ArmatureObject.h" #include "SCA_ISensor.h" #include "SCA_IController.h" #include "SCA_IActuator.h" @@ -72,6 +73,10 @@ static Py_ssize_t KX_PythonSeq_len( PyObject * self ) return ((KX_GameObject *)self_plus)->GetControllers().size(); case KX_PYGENSEQ_OB_TYPE_ACTUATORS: return ((KX_GameObject *)self_plus)->GetActuators().size(); + case KX_PYGENSEQ_OB_TYPE_CONSTRAINTS: + return ((BL_ArmatureObject *)self_plus)->GetConstraintNumber(); + case KX_PYGENSEQ_OB_TYPE_CHANNELS: + return ((BL_ArmatureObject *)self_plus)->GetChannelNumber(); default: /* Should never happen */ PyErr_SetString(PyExc_SystemError, "invalid type, internal error"); @@ -139,6 +144,29 @@ static PyObject *KX_PythonSeq_getIndex(PyObject* self, int index) } return linkedactuators[index]->GetProxy(); } + case KX_PYGENSEQ_OB_TYPE_CONSTRAINTS: + { + int nb_constraint = ((BL_ArmatureObject *)self_plus)->GetConstraintNumber(); + if(index<0) + index += nb_constraint; + if(index<0 || index>= nb_constraint) { + PyErr_SetString(PyExc_IndexError, "seq[i]: index out of range"); + return NULL; + } + return ((BL_ArmatureObject *)self_plus)->GetConstraint(index)->GetProxy(); + } + case KX_PYGENSEQ_OB_TYPE_CHANNELS: + { + int nb_channel = ((BL_ArmatureObject *)self_plus)->GetChannelNumber(); + if(index<0) + index += nb_channel; + if(index<0 || index>= nb_channel) { + PyErr_SetString(PyExc_IndexError, "seq[i]: index out of range"); + return NULL; + } + return ((BL_ArmatureObject *)self_plus)->GetChannel(index)->GetProxy(); + } + } PyErr_SetString(PyExc_SystemError, "invalid sequence type, this is a bug"); @@ -206,6 +234,14 @@ static PyObjectPlus * KX_PythonSeq_subscript__internal(PyObject *self, char *key } break; } + case KX_PYGENSEQ_OB_TYPE_CONSTRAINTS: + { + return ((BL_ArmatureObject*)self_plus)->GetConstraint(key); + } + case KX_PYGENSEQ_OB_TYPE_CHANNELS: + { + return ((BL_ArmatureObject*)self_plus)->GetChannel(key); + } } return NULL; diff --git a/source/gameengine/Ketsji/KX_PythonSeq.h b/source/gameengine/Ketsji/KX_PythonSeq.h index 15a016224a9..34243aa9b9c 100644 --- a/source/gameengine/Ketsji/KX_PythonSeq.h +++ b/source/gameengine/Ketsji/KX_PythonSeq.h @@ -39,7 +39,9 @@ enum KX_PYGENSEQ_TYPE { KX_PYGENSEQ_CONT_TYPE_ACTUATORS, KX_PYGENSEQ_OB_TYPE_SENSORS, KX_PYGENSEQ_OB_TYPE_CONTROLLERS, - KX_PYGENSEQ_OB_TYPE_ACTUATORS + KX_PYGENSEQ_OB_TYPE_ACTUATORS, + KX_PYGENSEQ_OB_TYPE_CONSTRAINTS, + KX_PYGENSEQ_OB_TYPE_CHANNELS, }; /* The Main PyType Object defined in Main.c */ diff --git a/source/gameengine/Ketsji/KX_RayEventManager.h b/source/gameengine/Ketsji/KX_RayEventManager.h index 27c9be14d1f..030dae525e1 100644 --- a/source/gameengine/Ketsji/KX_RayEventManager.h +++ b/source/gameengine/Ketsji/KX_RayEventManager.h @@ -41,8 +41,7 @@ class KX_RayEventManager : public SCA_EventManager class SCA_LogicManager* m_logicmgr; public: KX_RayEventManager(class SCA_LogicManager* logicmgr) - : SCA_EventManager(RAY_EVENTMGR), - m_logicmgr(logicmgr) + : SCA_EventManager(logicmgr, RAY_EVENTMGR) {} virtual void NextFrame(); diff --git a/source/gameengine/Ketsji/KX_SCA_AddObjectActuator.cpp b/source/gameengine/Ketsji/KX_SCA_AddObjectActuator.cpp index 099403fc28d..c1e74070d72 100644 --- a/source/gameengine/Ketsji/KX_SCA_AddObjectActuator.cpp +++ b/source/gameengine/Ketsji/KX_SCA_AddObjectActuator.cpp @@ -57,7 +57,7 @@ KX_SCA_AddObjectActuator::KX_SCA_AddObjectActuator(SCA_IObject *gameobj, const float *angvel, bool angv_local) : - SCA_IActuator(gameobj), + SCA_IActuator(gameobj, KX_ACT_ADD_OBJECT), m_OriginalObject(original), m_scene(scene), diff --git a/source/gameengine/Ketsji/KX_SCA_DynamicActuator.cpp b/source/gameengine/Ketsji/KX_SCA_DynamicActuator.cpp index 646cfb7219f..73c85ad07b3 100644 --- a/source/gameengine/Ketsji/KX_SCA_DynamicActuator.cpp +++ b/source/gameengine/Ketsji/KX_SCA_DynamicActuator.cpp @@ -87,7 +87,7 @@ KX_SCA_DynamicActuator::KX_SCA_DynamicActuator(SCA_IObject *gameobj, short dyn_operation, float setmass) : - SCA_IActuator(gameobj), + SCA_IActuator(gameobj, KX_ACT_DYNAMIC), m_dyn_operation(dyn_operation), m_setmass(setmass) { diff --git a/source/gameengine/Ketsji/KX_SCA_EndObjectActuator.cpp b/source/gameengine/Ketsji/KX_SCA_EndObjectActuator.cpp index dd9d8015724..e7dc71d9b27 100644 --- a/source/gameengine/Ketsji/KX_SCA_EndObjectActuator.cpp +++ b/source/gameengine/Ketsji/KX_SCA_EndObjectActuator.cpp @@ -44,7 +44,7 @@ KX_SCA_EndObjectActuator::KX_SCA_EndObjectActuator(SCA_IObject *gameobj, SCA_IScene* scene): - SCA_IActuator(gameobj), + SCA_IActuator(gameobj, KX_ACT_END_OBJECT), m_scene(scene) { // intentionally empty diff --git a/source/gameengine/Ketsji/KX_SCA_ReplaceMeshActuator.cpp b/source/gameengine/Ketsji/KX_SCA_ReplaceMeshActuator.cpp index e85b8a32798..e118972edc8 100644 --- a/source/gameengine/Ketsji/KX_SCA_ReplaceMeshActuator.cpp +++ b/source/gameengine/Ketsji/KX_SCA_ReplaceMeshActuator.cpp @@ -122,7 +122,7 @@ KX_SCA_ReplaceMeshActuator::KX_SCA_ReplaceMeshActuator(SCA_IObject *gameobj, bool use_gfx, bool use_phys) : - SCA_IActuator(gameobj), + SCA_IActuator(gameobj, KX_ACT_REPLACE_MESH), m_mesh(mesh), m_scene(scene), m_use_gfx(use_gfx), diff --git a/source/gameengine/Ketsji/KX_Scene.cpp b/source/gameengine/Ketsji/KX_Scene.cpp index 3483496c3a6..140be3fb3db 100644 --- a/source/gameengine/Ketsji/KX_Scene.cpp +++ b/source/gameengine/Ketsji/KX_Scene.cpp @@ -40,14 +40,15 @@ #include "ListValue.h" #include "SCA_LogicManager.h" #include "SCA_TimeEventManager.h" -#include "SCA_AlwaysEventManager.h" -#include "SCA_RandomEventManager.h" -#include "KX_RayEventManager.h" +//#include "SCA_AlwaysEventManager.h" +//#include "SCA_RandomEventManager.h" +//#include "KX_RayEventManager.h" #include "KX_TouchEventManager.h" #include "SCA_KeyboardManager.h" #include "SCA_MouseManager.h" -#include "SCA_PropertyEventManager.h" +//#include "SCA_PropertyEventManager.h" #include "SCA_ActuatorEventManager.h" +#include "SCA_BasicEventManager.h" #include "KX_Camera.h" #include "SCA_JoystickManager.h" @@ -168,25 +169,27 @@ KX_Scene::KX_Scene(class SCA_IInputDevice* keyboarddevice, m_keyboardmgr = new SCA_KeyboardManager(m_logicmgr,keyboarddevice); m_mousemgr = new SCA_MouseManager(m_logicmgr,mousedevice); - SCA_AlwaysEventManager* alwaysmgr = new SCA_AlwaysEventManager(m_logicmgr); - SCA_PropertyEventManager* propmgr = new SCA_PropertyEventManager(m_logicmgr); + //SCA_AlwaysEventManager* alwaysmgr = new SCA_AlwaysEventManager(m_logicmgr); + //SCA_PropertyEventManager* propmgr = new SCA_PropertyEventManager(m_logicmgr); SCA_ActuatorEventManager* actmgr = new SCA_ActuatorEventManager(m_logicmgr); - SCA_RandomEventManager* rndmgr = new SCA_RandomEventManager(m_logicmgr); - KX_RayEventManager* raymgr = new KX_RayEventManager(m_logicmgr); + //SCA_RandomEventManager* rndmgr = new SCA_RandomEventManager(m_logicmgr); + SCA_BasicEventManager* basicmgr = new SCA_BasicEventManager(m_logicmgr); + //KX_RayEventManager* raymgr = new KX_RayEventManager(m_logicmgr); KX_NetworkEventManager* netmgr = new KX_NetworkEventManager(m_logicmgr, ndi); - m_logicmgr->RegisterEventManager(alwaysmgr); - m_logicmgr->RegisterEventManager(propmgr); + //m_logicmgr->RegisterEventManager(alwaysmgr); + //m_logicmgr->RegisterEventManager(propmgr); m_logicmgr->RegisterEventManager(actmgr); m_logicmgr->RegisterEventManager(m_keyboardmgr); m_logicmgr->RegisterEventManager(m_mousemgr); m_logicmgr->RegisterEventManager(m_timemgr); - m_logicmgr->RegisterEventManager(rndmgr); - m_logicmgr->RegisterEventManager(raymgr); + //m_logicmgr->RegisterEventManager(rndmgr); + //m_logicmgr->RegisterEventManager(raymgr); m_logicmgr->RegisterEventManager(netmgr); + m_logicmgr->RegisterEventManager(basicmgr); SYS_SystemHandle hSystem = SYS_GetSystem(); diff --git a/source/gameengine/Ketsji/KX_SceneActuator.cpp b/source/gameengine/Ketsji/KX_SceneActuator.cpp index ea1be7bca6c..c7721c480e0 100644 --- a/source/gameengine/Ketsji/KX_SceneActuator.cpp +++ b/source/gameengine/Ketsji/KX_SceneActuator.cpp @@ -50,7 +50,7 @@ KX_SceneActuator::KX_SceneActuator(SCA_IObject *gameobj, KX_KetsjiEngine* ketsjiEngine, const STR_String& nextSceneName, KX_Camera* camera) - : SCA_IActuator(gameobj) + : SCA_IActuator(gameobj, KX_ACT_SCENE) { m_mode = mode; m_scene = scene; diff --git a/source/gameengine/Ketsji/KX_SoundActuator.cpp b/source/gameengine/Ketsji/KX_SoundActuator.cpp index e2b4022a312..9d261137497 100644 --- a/source/gameengine/Ketsji/KX_SoundActuator.cpp +++ b/source/gameengine/Ketsji/KX_SoundActuator.cpp @@ -49,7 +49,7 @@ KX_SoundActuator::KX_SoundActuator(SCA_IObject* gameobj, bool is3d, KX_3DSoundSettings settings, KX_SOUNDACT_TYPE type)//, - : SCA_IActuator(gameobj) + : SCA_IActuator(gameobj, KX_ACT_SOUND) { m_sound = sound; m_volume = volume; diff --git a/source/gameengine/Ketsji/KX_StateActuator.cpp b/source/gameengine/Ketsji/KX_StateActuator.cpp index 4159e9c373d..60812220953 100644 --- a/source/gameengine/Ketsji/KX_StateActuator.cpp +++ b/source/gameengine/Ketsji/KX_StateActuator.cpp @@ -40,7 +40,7 @@ KX_StateActuator::KX_StateActuator( int operation, unsigned int mask ) - : SCA_IActuator(gameobj), + : SCA_IActuator(gameobj, KX_ACT_STATE), m_operation(operation), m_mask(mask) { diff --git a/source/gameengine/Ketsji/KX_TouchEventManager.cpp b/source/gameengine/Ketsji/KX_TouchEventManager.cpp index 712a512995e..6b454f6a338 100644 --- a/source/gameengine/Ketsji/KX_TouchEventManager.cpp +++ b/source/gameengine/Ketsji/KX_TouchEventManager.cpp @@ -40,8 +40,7 @@ KX_TouchEventManager::KX_TouchEventManager(class SCA_LogicManager* logicmgr, PHY_IPhysicsEnvironment* physEnv) - : SCA_EventManager(TOUCH_EVENTMGR), - m_logicmgr(logicmgr), + : SCA_EventManager(logicmgr, TOUCH_EVENTMGR), m_physEnv(physEnv) { //notm_scene->addTouchCallback(STATIC_RESPONSE, KX_TouchEventManager::collisionResponse, this); diff --git a/source/gameengine/Ketsji/KX_TouchEventManager.h b/source/gameengine/Ketsji/KX_TouchEventManager.h index 6da37d615a4..e6414a2e285 100644 --- a/source/gameengine/Ketsji/KX_TouchEventManager.h +++ b/source/gameengine/Ketsji/KX_TouchEventManager.h @@ -43,7 +43,6 @@ class PHY_IPhysicsEnvironment; class KX_TouchEventManager : public SCA_EventManager { typedef std::pair<PHY_IPhysicsController*, PHY_IPhysicsController*> NewCollision; - class SCA_LogicManager* m_logicmgr; PHY_IPhysicsEnvironment* m_physEnv; std::set<NewCollision> m_newCollisions; diff --git a/source/gameengine/Ketsji/KX_TrackToActuator.cpp b/source/gameengine/Ketsji/KX_TrackToActuator.cpp index e6c2f86bbce..ace1cf8a6f4 100644 --- a/source/gameengine/Ketsji/KX_TrackToActuator.cpp +++ b/source/gameengine/Ketsji/KX_TrackToActuator.cpp @@ -60,7 +60,7 @@ KX_TrackToActuator::KX_TrackToActuator(SCA_IObject *gameobj, bool allow3D, int trackflag, int upflag) - : SCA_IActuator(gameobj) + : SCA_IActuator(gameobj, KX_ACT_TRACKTO) { m_time = time; m_allow3D = allow3D; diff --git a/source/gameengine/Ketsji/KX_VisibilityActuator.cpp b/source/gameengine/Ketsji/KX_VisibilityActuator.cpp index 184e127209f..5b0f6e6e9f2 100644 --- a/source/gameengine/Ketsji/KX_VisibilityActuator.cpp +++ b/source/gameengine/Ketsji/KX_VisibilityActuator.cpp @@ -41,7 +41,7 @@ KX_VisibilityActuator::KX_VisibilityActuator( bool occlusion, bool recursive ) - : SCA_IActuator(gameobj), + : SCA_IActuator(gameobj, KX_ACT_VISIBILITY), m_visible(visible), m_occlusion(occlusion), m_recursive(recursive) diff --git a/source/gameengine/Ketsji/SConscript b/source/gameengine/Ketsji/SConscript index 5f38020780b..b20da20d0e2 100644 --- a/source/gameengine/Ketsji/SConscript +++ b/source/gameengine/Ketsji/SConscript @@ -29,7 +29,7 @@ if env['WITH_BF_SDL']: else: defs.append('DISABLE_SDL') -if env['OURPLATFORM'] in ('win32-vc', 'win64-vc'): +if env['OURPLATFORM'] in ('win32-vc', 'win64-vc', 'win32-mingw'): if env['BF_DEBUG']: defs.append('_DEBUG') # for Python diff --git a/source/gameengine/PyDoc/GameTypes.py b/source/gameengine/PyDoc/GameTypes.py index c391d0c3dec..60511f41c2b 100644 --- a/source/gameengine/PyDoc/GameTypes.py +++ b/source/gameengine/PyDoc/GameTypes.py @@ -4,15 +4,17 @@ Documentation for the GameTypes Module. @group Base: PyObjectPlus, CValue, CPropValue, SCA_ILogicBrick, SCA_IObject, SCA_ISensor, SCA_IController, SCA_IActuator -@group Object: KX_GameObject, KX_LightObject, KX_Camera +@group Object: KX_GameObject, KX_LightObject, KX_Camera, BL_ArmatureObject + +@group Animation: BL_ArmatureConstraint @group Mesh: KX_MeshProxy, KX_PolyProxy, KX_VertexProxy @group Shading: KX_PolygonMaterial, KX_BlenderMaterial, BL_Shader -@group Sensors: SCA_ActuatorSensor, SCA_AlwaysSensor, SCA_DelaySensor, SCA_JoystickSensor, SCA_KeyboardSensor, KX_MouseFocusSensor, SCA_MouseSensor, KX_NearSensor, KX_NetworkMessageSensor, SCA_PropertySensor, KX_RadarSensor, SCA_RandomSensor, KX_RaySensor, KX_TouchSensor +@group Sensors: SCA_ActuatorSensor, SCA_AlwaysSensor, SCA_DelaySensor, SCA_JoystickSensor, SCA_KeyboardSensor, KX_MouseFocusSensor, SCA_MouseSensor, KX_NearSensor, KX_NetworkMessageSensor, SCA_PropertySensor, KX_RadarSensor, SCA_RandomSensor, KX_RaySensor, KX_TouchSensor, KX_ArmatureSensor -@group Actuators: SCA_2DFilterActuator, BL_ActionActuator, KX_SCA_AddObjectActuator, KX_CameraActuator, KX_ConstraintActuator, KX_SCA_DynamicActuator, KX_SCA_EndObjectActuator, KX_GameActuator, KX_IpoActuator, KX_NetworkMessageActuator, KX_ObjectActuator, KX_ParentActuator, SCA_PropertyActuator, SCA_RandomActuator, KX_SCA_ReplaceMeshActuator, KX_SceneActuator, BL_ShapeActionActuator, KX_SoundActuator, KX_StateActuator, KX_TrackToActuator, KX_VisibilityActuator +@group Actuators: SCA_2DFilterActuator, BL_ActionActuator, BL_ArmatureActuator, KX_SCA_AddObjectActuator, KX_CameraActuator, KX_ConstraintActuator, KX_SCA_DynamicActuator, KX_SCA_EndObjectActuator, KX_GameActuator, KX_IpoActuator, KX_NetworkMessageActuator, KX_ObjectActuator, KX_ParentActuator, SCA_PropertyActuator, SCA_RandomActuator, KX_SCA_ReplaceMeshActuator, KX_SceneActuator, BL_ShapeActionActuator, KX_SoundActuator, KX_StateActuator, KX_TrackToActuator, KX_VisibilityActuator @group Controllers: SCA_ANDController, SCA_NANDController, SCA_NORController, SCA_ORController, SCA_PythonController, SCA_XNORController, SCA_XORController """ @@ -5686,6 +5688,332 @@ class KX_Camera(KX_GameObject): @return: the first object hit or None if no object or object does not match prop """ +class BL_ArmatureObject(KX_GameObject): + """ + An armature object. + + @ivar constraints: The list of armature constraint defined on this armature + Elements of the list can be accessed by index or string. + The key format for string access is '<bone_name>:<constraint_name>' + @type constraints: list of L{BL_ArmatureConstraint} + @ivar channels: The list of armature channels. + Elements of the list can be accessed by index or name the bone. + @type channels: list of L{BL_ArmatureChannel} + """ + + def update(): + """ + Ensures that the armature will be updated on next graphic frame. + + This action is unecessary if a KX_ArmatureActuator with mode run is active + or if an action is playing. Use this function in other cases. It must be called + on each frame to ensure that the armature is updated continously. + """ + +class BL_ArmatureActuator(SCA_IActuator): + """ + Armature Actuators change constraint condition on armatures. + + @group Constants: KX_ACT_ARMATURE_RUN, KX_ACT_ARMATURE_ENABLE, KX_ACT_ARMATURE_DISABLE, KX_ACT_ARMATURE_SETTARGET, KX_ACT_ARMATURE_SETWEIGHT + @ivar KX_ACT_ARMATURE_RUN: see type + @ivar KX_ACT_ARMATURE_ENABLE: see type + @ivar KX_ACT_ARMATURE_DISABLE: see type + @ivar KX_ACT_ARMATURE_SETTARGET: see type + @ivar KX_ACT_ARMATURE_SETWEIGHT: see type + @ivar type: The type of action that the actuator executes when it is active. + + KX_ACT_ARMATURE_RUN(0): just make sure the armature will be updated on the next graphic frame + This is the only persistent mode of the actuator: it executes automatically once per frame until stopped by a controller + + KX_ACT_ARMATURE_ENABLE(1): enable the constraint. + + KX_ACT_ARMATURE_DISABLE(2): disable the constraint (runtime constraint values are not updated). + + KX_ACT_ARMATURE_SETTARGET(3): change target and subtarget of constraint + + KX_ACT_ARMATURE_SETWEIGHT(4): change weight of (only for IK constraint) + @type type: integer + @ivar constraint: The constraint object this actuator is controlling. + @type constraint: L{BL_ArmatureConstraint} + @ivar target: The object that this actuator will set as primary target to the constraint it controls + @type target: L{KX_GameObject} + @ivar subtarget: The object that this actuator will set as secondary target to the constraint it controls. + Currently, the only secondary target is the pole target for IK constraint. + @type subtarget: L{KX_GameObject} + @ivar weight: The weight this actuator will set on the constraint it controls. + Currently only the IK constraint has a weight. It must be a value between 0 and 1. + A weight of 0 disables a constraint while still updating constraint runtime values (see L{BL_ArmatureConstraint}) + @type weight: float + """ + +class KX_ArmatureSensor(SCA_ISensor): + """ + Armature sensor detect conditions on armatures. + + @group Constants: KX_ARMSENSOR_STATE_CHANGED, KX_ARMSENSOR_LIN_ERROR_BELOW, KX_ARMSENSOR_LIN_ERROR_ABOVE, KX_ARMSENSOR_ROT_ERROR_BELOW, KX_ARMSENSOR_ROT_ERROR_ABOVE + @ivar KX_ARMSENSOR_STATE_CHANGED: see type + @ivar KX_ARMSENSOR_LIN_ERROR_BELOW: see type + @ivar KX_ARMSENSOR_LIN_ERROR_ABOVE: see type + @ivar KX_ARMSENSOR_ROT_ERROR_BELOW: see type + @ivar KX_ARMSENSOR_ROT_ERROR_ABOVE: see type + @ivar type: The type of measurement that the sensor make when it is active. + + KX_ARMSENSOR_STATE_CHANGED(0): detect that the constraint is changing state (active/inactive) + + KX_ARMSENSOR_LIN_ERROR_BELOW(1): detect that the constraint linear error is above a threshold + + KX_ARMSENSOR_LIN_ERROR_ABOVE(2): detect that the constraint linear error is below a threshold + + KX_ARMSENSOR_ROT_ERROR_BELOW(3): detect that the constraint rotation error is above a threshold + + KX_ARMSENSOR_ROT_ERROR_ABOVE(4): detect that the constraint rotation error is below a threshold + @type type: integer + @ivar constraint: The constraint object this sensor is watching. + @type constraint: L{BL_ArmatureConstraint} + @ivar value: The threshold used in the comparison with the constraint error + The linear error is only updated on CopyPose/Distance IK constraint with iTaSC solver + The rotation error is only updated on CopyPose+rotation IK constraint with iTaSC solver + The linear error on CopyPose is always >= 0: it is the norm of the distance between the target and the bone + The rotation error on CopyPose is always >= 0: it is the norm of the equivalent rotation vector between the bone and the target orientations + The linear error on Distance can be positive if the distance between the bone and the target is greater than the desired distance, and negative if the distance is smaller + @type value: float + """ + +class BL_ArmatureConstraint(PyObjectPlus): + """ + Proxy to Armature Constraint. Allows to change constraint on the fly. + Obtained through L{BL_ArmatureObject}.constraints. + Note: not all armature constraints are supported in the GE. + + @group Constants: CONSTRAINT_TYPE_TRACKTO, CONSTRAINT_TYPE_KINEMATIC, CONSTRAINT_TYPE_ROTLIKE, CONSTRAINT_TYPE_LOCLIKE, CONSTRAINT_TYPE_MINMAX, CONSTRAINT_TYPE_SIZELIKE, CONSTRAINT_TYPE_LOCKTRACK, CONSTRAINT_TYPE_STRETCHTO, CONSTRAINT_TYPE_CLAMPTO, CONSTRAINT_TYPE_TRANSFORM, CONSTRAINT_TYPE_DISTLIMIT,CONSTRAINT_IK_COPYPOSE, CONSTRAINT_IK_DISTANCE,CONSTRAINT_IK_MODE_INSIDE, CONSTRAINT_IK_MODE_OUTSIDE,CONSTRAINT_IK_MODE_ONSURFACE,CONSTRAINT_IK_FLAG_TIP,CONSTRAINT_IK_FLAG_ROT, CONSTRAINT_IK_FLAG_STRETCH, CONSTRAINT_IK_FLAG_POS + @ivar CONSTRAINT_TYPE_TRACKTO: see type + @ivar CONSTRAINT_TYPE_KINEMATIC: see type + @ivar CONSTRAINT_TYPE_ROTLIKE: see type + @ivar CONSTRAINT_TYPE_LOCLIKE: see type + @ivar CONSTRAINT_TYPE_MINMAX: see type + @ivar CONSTRAINT_TYPE_SIZELIKE: see type + @ivar CONSTRAINT_TYPE_LOCKTRACK: see type + @ivar CONSTRAINT_TYPE_STRETCHTO: see type + @ivar CONSTRAINT_TYPE_CLAMPTO: see type + @ivar CONSTRAINT_TYPE_TRANSFORM: see type + @ivar CONSTRAINT_TYPE_DISTLIMIT: see type + @ivar CONSTRAINT_IK_COPYPOSE: see ik_type + @ivar CONSTRAINT_IK_DISTANCE: see ik_type + @ivar CONSTRAINT_IK_MODE_INSIDE: see ik_mode + @ivar CONSTRAINT_IK_MODE_OUTSIDE: see ik_mode + @ivar CONSTRAINT_IK_MODE_ONSURFACE: see ik_mode + @ivar CONSTRAINT_IK_FLAG_TIP: see ik_flag + @ivar CONSTRAINT_IK_FLAG_ROT: see ik_flag + @ivar CONSTRAINT_IK_FLAG_STRETCH: see ik_flag + @ivar CONSTRAINT_IK_FLAG_POS: see ik_flag + @ivar type: Type of constraint, read-only + @type type: integer, one of CONSTRAINT_TYPE_ constant + @ivar name: Name of constraint constructed as <bone_name>:<constraint_name> + This name is also the key subscript on L{BL_ArmatureObject}.constraints list + @type name: string + @ivar enforce: fraction of constraint effect that is enforced. Between 0 and 1. + @type enforce: float + @ivar headtail: position of target between head and tail of the target bone: 0=head, 1=tail + Only used if the target is a bone (i.e target object is an armature) + @type headtail: float + @ivar lin_error: runtime linear error (in Blender unit) on constraint at the current frame. + This is a runtime value updated on each frame by the IK solver. Only available on IK constraint and iTaSC solver. + @type lin_error: float + @ivar rot_error: runtime rotation error (in radiant) on constraint at the current frame. + This is a runtime value updated on each frame by the IK solver. Only available on IK constraint and iTaSC solver. + It is only set if the constraint has a rotation part, for example, a CopyPose+Rotation IK constraint. + @type rot_error: float + @ivar target: Primary target object for the constraint. The position of this object in the GE will be used as target for the constraint. + @type target: L{KX_GameObject} + @ivar subtarget: Secondary target object for the constraint. The position of this object in the GE will be used as secondary target for the constraint. + Currently this is only used for pole target on IK constraint. + @type subtarget: L{KX_GameObject} + @ivar active: True if the constraint is active. + Note: an inactive constraint does not update lin_error and rot_error. + @type active: boolean + @ivar ik_weight: Weight of the IK constraint between 0 and 1. + Only defined for IK constraint. + @type ik_weight: float + @ivar ik_type: Type of IK constraint, read-only + + CONSTRAINT_IK_COPYPOSE(0): constraint is trying to match the position and eventually the rotation of the target. + + CONSTRAINT_IK_DISTANCE(1): constraint is maintaining a certain distance to target subject to ik_mode + @type ik_type: integer + @ivar ik_flag: Combination of IK constraint option flags, read-only + + CONSTRAINT_IK_FLAG_TIP(1) : set when the constraint operates on the head of the bone and not the tail + + CONSTRAINT_IK_FLAG_ROT(2) : set when the constraint tries to match the orientation of the target + + CONSTRAINT_IK_FLAG_STRETCH(16) : set when the armature is allowed to stretch (only the bones with stretch factor > 0.0) + + CONSTRAINT_IK_FLAG_POS(32) : set when the constraint tries to match the position of the target + @type ik_flag: integer + @ivar ik_dist: Distance the constraint is trying to maintain with target, only used when ik_type=CONSTRAINT_IK_DISTANCE + @type ik_dist: float + @ivar ik_mode: Additional mode for IK constraint. Currently only used for Distance constraint: + + CONSTRAINT_IK_MODE_INSIDE(0) : the constraint tries to keep the bone within ik_dist of target + + CONSTRAINT_IK_MODE_OUTSIDE(1) : the constraint tries to keep the bone outside ik_dist of the target + + CONSTRAINT_IK_MODE_ONSURFACE(2) : the constraint tries to keep the bone exactly at ik_dist of the target + @type ik_mode: integer + """ + +class BL_ArmatureChannel(PyObjectPlus): + """ + Proxy to armature pose channel. Allows to read and set armature pose. + The attributes are identical to RNA attributes, but mostly in read-only mode. + + @group Constants: PCHAN_ROT_QUAT, PCHAN_ROT_XYZ, PCHAN_ROT_XZY, PCHAN_ROT_YXZ, PCHAN_ROT_YZX, PCHAN_ROT_ZXY, PCHAN_ROT_ZYX + @ivar PCHAN_ROT_QUAT: see rotation_mode + @ivar PCHAN_ROT_XYZ: see rotation_mode + @ivar PCHAN_ROT_XZY: see rotation_mode + @ivar PCHAN_ROT_YXZ: see rotation_mode + @ivar PCHAN_ROT_YZX: see rotation_mode + @ivar PCHAN_ROT_ZXY: see rotation_mode + @ivar PCHAN_ROT_ZYX: see rotation_mode + @ivar name: channel name (=bone name), read-only. + @type name: string + @ivar bone: return the bone object corresponding to this pose channel, read-only. + @type bone: L{BL_ArmatureBone} + @ivar parent: return the parent channel object, None if root channel, read-only. + @type parent: L{BL_ArmatureChannel} + @ivar has_ik: true if the bone is part of an active IK chain, read-only. + This flag is not set when an IK constraint is defined but not enabled (miss target information for example) + @type has_ik: boolean + @ivar ik_dof_x: true if the bone is free to rotation in the X axis, read-only. + @type ik_dof_x: boolean + @ivar ik_dof_y: true if the bone is free to rotation in the Y axis, read-only. + @type ik_dof_y: boolean + @ivar ik_dof_z: true if the bone is free to rotation in the Z axis, read-only. + @type ik_dof_z: boolean + @ivar ik_limit_x: true if a limit is imposed on X rotation, read-only. + @type ik_limit_x: boolean + @ivar ik_limit_y: true if a limit is imposed on Y rotation, read-only. + @type ik_limit_y: boolean + @ivar ik_limit_z: true if a limit is imposed on Z rotation, read-only. + @type ik_limit_z: boolean + @ivar ik_rot_control: true if channel rotation should applied as IK constraint, read-only. + @type ik_rot_control: boolean + @ivar ik_lin_control: true if channel size should applied as IK constraint, read-only. + @type ik_lin_control: boolean + @ivar location: displacement of the bone head in armature local space, read-write. + You can only move a bone if it is unconnected to its parent. An action playing on the armature may change the value. An IK chain does not update this value, see joint_rotation. + Changing this field has no immediate effect, the pose is updated when the armature is updated during the graphic render (see L{BL_ArmatureObject.update}) + @type location: vector [X,Y,Z] + @ivar scale: scale of the bone relative to its parent, read-write. + An action playing on the armature may change the value. An IK chain does not update this value, see joint_rotation. + Changing this field has no immediate effect, the pose is updated when the armature is updated during the graphic render (see L{BL_ArmatureObject.update}) + @type scale: vector [sizeX, sizeY, sizeZ] + @ivar rotation: rotation of the bone relative to its parent expressed as a quaternion, read-write. + This field is only used if rotation_mode is 0. An action playing on the armature may change the value. An IK chain does not update this value, see joint_rotation. + Changing this field has no immediate effect, the pose is updated when the armature is updated during the graphic render (see L{BL_ArmatureObject.update}) + @type rotation: vector [qr, qi, qj, qk] + @ivar euler_rotation: rotation of the bone relative to its parent expressed as a set of euler angles, read-write. + This field is only used if rotation_mode is > 0. You must always pass the angles in [X,Y,Z] order; the order of applying the angles to the bone depends on rotation_mode. An action playing on the armature may change this field. An IK chain does not update this value, see joint_rotation. + Changing this field has no immediate effect, the pose is updated when the armature is updated during the graphic render (see L{BL_ArmatureObject.update}) + @type euler_rotation: vector [X, Y, Z] + @ivar rotation_mode: method of updating the bone rotation, read-write. + Use the following constants (euler mode are named as in BLender UI but the actual axis order is reversed): + - PCHAN_ROT_QUAT(0) : use quaternioin in rotation attribute to update bone rotation + - PCHAN_ROT_XYZ(1) : use euler_rotation and apply angles on bone's Z, Y, X axis successively + - PCHAN_ROT_XZY(2) : use euler_rotation and apply angles on bone's Y, Z, X axis successively + - PCHAN_ROT_YXZ(3) : use euler_rotation and apply angles on bone's Z, X, Y axis successively + - PCHAN_ROT_YZX(4) : use euler_rotation and apply angles on bone's X, Z, Y axis successively + - PCHAN_ROT_ZXY(5) : use euler_rotation and apply angles on bone's Y, X, Z axis successively + - PCHAN_ROT_ZYX(6) : use euler_rotation and apply angles on bone's X, Y, Z axis successively + @type rotation_mode: integer + @ivar channel_matrix: pose matrix in bone space (deformation of the bone due to action, constraint, etc), Read-only. + This field is updated after the graphic render, it represents the current pose. + @type channel_matrix: matrix [4][4] + @ivar pose_matrix: pose matrix in armature space, read-only, + This field is updated after the graphic render, it represents the current pose. + @type pose_matrix: matrix [4][4] + @ivar pose_head: position of bone head in armature space, read-only. + @type pose_head: vector [x, y, z] + @ivar pose_tail: position of bone tail in armature space, read-only. + @type pose_tail: vector [x, y, z] + @ivar ik_min_x: minimum value of X rotation in degree (<= 0) when X rotation is limited (see ik_limit_x), read-only. + @type ik_min_x: float + @ivar ik_max_x: maximum value of X rotation in degree (>= 0) when X rotation is limited (see ik_limit_x), read-only. + @type ik_max_x: float + @ivar ik_min_y: minimum value of Y rotation in degree (<= 0) when Y rotation is limited (see ik_limit_y), read-only. + @type ik_min_y: float + @ivar ik_max_y: maximum value of Y rotation in degree (>= 0) when Y rotation is limited (see ik_limit_y), read-only. + @type ik_max_y: float + @ivar ik_min_z: minimum value of Z rotation in degree (<= 0) when Z rotation is limited (see ik_limit_z), read-only. + @type ik_min_z: float + @ivar ik_max_z: maximum value of Z rotation in degree (>= 0) when Z rotation is limited (see ik_limit_z), read-only. + @type ik_max_z: float + @ivar ik_stiffness_x: bone rotation stiffness in X axis, read-only + @type ik_stiffness_x: float between 0 and 1 + @ivar ik_stiffness_y: bone rotation stiffness in Y axis, read-only + @type ik_stiffness_y: float between 0 and 1 + @ivar ik_stiffness_z: bone rotation stiffness in Z axis, read-only + @type ik_stiffness_z: float between 0 and 1 + @ivar ik_stretch: ratio of scale change that is allowed, 0=bone can't change size, read-only. + @type ik_stretch: float + @ivar ik_rot_weight: weight of rotation constraint when ik_rot_control is set, read-write. + @type ik_rot_weight: float between 0 and 1 + @ivar ik_lin_weight: weight of size constraint when ik_lin_control is set, read-write. + @type ik_lin_weight: float between 0 and 1 + @ivar joint_rotation: control bone rotation in term of joint angle (for robotic applications), read-write. + When writing to this attribute, you pass a [x, y, z] vector and an appropriate set of euler angles or quaternion is calculated according to the rotation_mode. + When you read this attribute, the current pose matrix is converted into a [x, y, z] vector representing the joint angles. + The value and the meaning of the x, y, z depends on the ik_dof_ attributes: + - 1DoF joint X, Y or Z: the corresponding x, y, or z value is used an a joint angle in radiant + - 2DoF joint X+Y or Z+Y: treated as 2 successive 1DoF joints: first X or Z, then Y. The x or z value is used as a joint angle in radiant along the X or Z axis, followed by a rotation along the new Y axis of y radiants. + - 2DoF joint X+Z: treated as a 2DoF joint with rotation axis on the X/Z plane. The x and z values are used as the coordinates of the rotation vector in the X/Z plane. + - 3DoF joint X+Y+Z: treated as a revolute joint. The [x,y,z] vector represents the equivalent rotation vector to bring the joint from the rest pose to the new pose. + + Notes: + - The bone must be part of an IK chain if you want to set the ik_dof_ attributes via the UI, but this will interfere with this attribute since the IK solver will overwrite the pose. You can stay in control of the armature if you create an IK constraint but do not finalize it (e.g. don't set a target): the IK solver will not run but the IK panel will show up on the UI for each bone in the chain. + - [0,0,0] always corresponds to the rest pose. + - You must request the armature pose to update and wait for the next graphic frame to see the effect of setting this attribute (see L{BL_ArmatureObject.update}). + - You can read the result of the calculation in rotation or euler_rotation attributes after setting this attribute. + @type joint_rotation: vector [x, y, z] + """ + +class BL_ArmatureBone(PyObjectPlus): + """ + Proxy to Blender bone structure. All fields are read-only and comply to RNA names. + All space attribute correspond to the rest pose. + + @ivar name: bone name + @type name: string + @ivar connected: true when the bone head is struck to the parent's tail + @type connected: boolean + @ivar hinge: true when bone doesn't inherit rotation or scale from parent bone + @type hinge: boolean + @ivar inherit_scale: true when bone inherits scaling from parent bone + @type inherit_scale: boolean + @ivar bbone_segments: number of B-bone segments + @type bbone_segments: integer + @ivar roll: bone rotation around head-tail axis + @type roll: float + @ivar head: location of head end of the bone in parent bone space + @type head: vector [x, y, z] + @ivar tail: location of head end of the bone in parent bone space + @type tail: vector [x, y, z] + @ivar length: bone length + @type length: float + @ivar arm_head: location of head end of the bone in armature space + @type arm_head: vector [x, y, z] + @ivar arm_tail: location of tail end of the bone in armature space + @type arm_tail: vector [x, y, z] + @ivar arm_mat: matrix of the bone head in armature space + This matrix has no scale part. + @type arm_mat: matrix [4][4] + @ivar bone_mat: rotation matrix of the bone in parent bone space. + @type bone_mat: matrix [3][3] + @ivar parent: parent bone, or None for root bone + @type parent: L{BL_ArmatureBone} + @ivar children: list of bone's children + @type children: list of L{BL_ArmatureBone} + """ # Util func to extract all attrs """ import types diff --git a/source/gameengine/PyDoc/SConscript b/source/gameengine/PyDoc/SConscript index ed9712ba273..dabe004ae6a 100644 --- a/source/gameengine/PyDoc/SConscript +++ b/source/gameengine/PyDoc/SConscript @@ -1,6 +1,11 @@ #!/usr/bin/python Import ('env') +import os +if env['WITH_BF_FHS']: + BLENDERPATH = os.path.join(env['BF_INSTALLDIR'], 'share', 'blender', env['BF_VERSION']) +else: + BLENDERPATH = env['BF_INSTALLDIR'] from optparse import OptionParser import epydoc @@ -14,7 +19,7 @@ optvalues["quiet"] = 0 optvalues["include_source_code"] = 0 optvalues["inheritance"] = "included" optvalues["show_private"] = 0 -optvalues["target"] = env["BF_DOCDIR"]+"/BGE_API/" +optvalues["target"] = os.path.join(BLENDERPATH, 'doc') optvalues["url"] = "http://www.blender.org" optvalues["top"] = "Game Engine API" optvalues["name"] = "Blender" diff --git a/source/gameengine/SceneGraph/SG_DList.h b/source/gameengine/SceneGraph/SG_DList.h index 3e17fb55dc0..97951792ab5 100644 --- a/source/gameengine/SceneGraph/SG_DList.h +++ b/source/gameengine/SceneGraph/SG_DList.h @@ -89,6 +89,46 @@ public: } }; + template<typename T> class const_iterator + { + private: + const SG_DList& m_head; + const T* m_current; + public: + typedef const_iterator<T> _myT; + const_iterator(const SG_DList& head) : m_head(head), m_current(NULL) {} + ~const_iterator() {} + + void begin() + { + m_current = (const T*)m_head.Peek(); + } + void back() + { + m_current = (const T*)m_head.Back(); + } + bool end() + { + return (m_current == (const T*)m_head.Self()); + } + const T* operator*() + { + return m_current; + } + _myT& operator++() + { + // no check of NULL! make sure you don't try to increment beyond end + m_current = (const T*)m_current->Peek(); + return *this; + } + _myT& operator--() + { + // no check of NULL! make sure you don't try to increment beyond end + m_current = (const T*)m_current->Back(); + return *this; + } + }; + SG_DList() { m_flink = m_blink = this; @@ -159,6 +199,18 @@ public: { return this; } + inline const SG_DList *Peek() const // Look at front without removing + { + return (const SG_DList*)m_flink; + } + inline const SG_DList *Back() const // Look at front without removing + { + return (const SG_DList*)m_blink; + } + inline const SG_DList *Self() const + { + return this; + } #ifdef WITH_CXX_GUARDEDALLOC @@ -168,5 +220,32 @@ public: #endif }; +/** + * SG_DListHead : Template class that implements copy constructor to duplicate list automatically + * The elements of the list must have themselves a copy constructor. + */ +template<typename T> class SG_DListHead : public SG_DList +{ +public: + typedef SG_DListHead<T> _myT; + SG_DListHead() : SG_DList() {} + SG_DListHead(const _myT& other) : SG_DList() + { + // copy the list, assuming objects of type T + const_iterator<T> eit(other); + T* elem; + for (eit.begin(); !eit.end(); ++eit) { + elem = (*eit)->GetReplica(); + AddBack(elem); + } + } + virtual ~SG_DListHead() {} + T* Remove() + { + return static_cast<T*>(SG_DList::Remove()); + } + +}; + #endif //__SG_DLIST diff --git a/source/gameengine/VideoTexture/SConscript b/source/gameengine/VideoTexture/SConscript index 119bd1c9954..dac0b6d32ab 100644 --- a/source/gameengine/VideoTexture/SConscript +++ b/source/gameengine/VideoTexture/SConscript @@ -15,12 +15,11 @@ incs += ' #source/blender/gpu #source/kernel/gen_system #intern/string #intern/m incs += ' #intern/guardedalloc #extern/glew/include' defs = [] -if env['OURPLATFORM'] in ('win32-vc', 'win64-vc'): +if env['OURPLATFORM'] in ('win32-vc', 'win64-vc','win32-mingw'): if env['BF_DEBUG']: defs.append('_DEBUG') incs += ' ' + env['BF_PYTHON_INC'] -#incs += ' ' + env['BF_OPENGL_INC'] if env['WITH_BF_FFMPEG']: defs.append('WITH_FFMPEG') diff --git a/source/nan_definitions.mk b/source/nan_definitions.mk index 6d4a7139d5b..1aff7e1dea7 100644 --- a/source/nan_definitions.mk +++ b/source/nan_definitions.mk @@ -81,6 +81,8 @@ ifndef CONFIG_GUESS endif export NAN_MOTO ?= $(LCGDIR)/moto + export NAN_ITASC ?= $(LCGDIR)/itasc + export BF_PROFILE ?= false export NAN_USE_BULLET ?= true export NAN_BULLET2 ?= $(LCGDIR)/bullet2 diff --git a/source/nan_warn.mk b/source/nan_warn.mk index b685c13604d..0dd4e0b8147 100644 --- a/source/nan_warn.mk +++ b/source/nan_warn.mk @@ -34,19 +34,19 @@ # # Force the correct redefinition -LEVEL_1_C_WARNINGS = -FIX_NAN_WARN -LEVEL_1_CPP_WARNINGS = -FIX_NAN_WARN -LEVEL_2_C_WARNINGS = -FIX_NAN_WARN -LEVEL_2_CPP_WARNINGS = -FIX_NAN_WARN -FIX_STUBS_WARNINGS = -FIX_NAN_WARN +LEVEL_1_C_WARNINGS = -FIX_NAN_WARN1A +LEVEL_1_CPP_WARNINGS = -FIX_NAN_WARN1B +LEVEL_2_C_WARNINGS = -FIX_NAN_WARN2A +LEVEL_2_CPP_WARNINGS = -FIX_NAN_WARN2B +FIX_STUBS_WARNINGS = -FIX_NAN_WARN3 ######################################################################## # Level 1: basic C warnings. -ifeq ($(CC),gcc) +ifeq (gcc, $(findstring gcc,$(CC))) LEVEL_1_C_WARNINGS = -Wall LEVEL_1_C_WARNINGS += -Wno-char-subscripts else - ifeq ($(CC),cc) + ifeq (cc, $(findstring cc,$(CC))) ifeq ($(OS),irix) # MIPSpro Compilers # @@ -71,11 +71,11 @@ else endif # Level 1: basic CPP warnings. -ifeq ($(CCC),g++) +ifeq (g++, $(findstring g++,$(CCC))) LEVEL_1_CPP_WARNINGS = -Wall LEVEL_1_CPP_WARNINGS += -Wno-reorder else - ifeq ($(CCC),CC) + ifeq (CC, $(findstring CC,$(CCC))) ifeq ($(OS),irix) # MIPSpro Compilers # see warning descriptions above @@ -91,7 +91,7 @@ endif ######################################################################## # Level 2: paranoia level C warnings. # DO NOT REUSE LEVEL_1_ DEFINES. -ifeq ($(CC),gcc) +ifeq (gcc, $(findstring gcc,$(CC))) LEVEL_2_C_WARNINGS = -Wall LEVEL_2_C_WARNINGS += -W # deliberately enable char-subscript warnings @@ -107,7 +107,7 @@ ifeq ($(CC),gcc) LEVEL_2_C_WARNINGS += -Wnested-externs LEVEL_2_C_WARNINGS += -Wredundant-decls else - ifeq ($(CC),cc) + ifeq (cc, $(findstring cc,$(CC))) ifeq ($(OS),irix) # MIPSpro Compilers # see warning descriptions above @@ -126,7 +126,7 @@ endif # Level 2: paranoia level CPP warnings. # DO NOT REUSE LEVEL_1_ DEFINES. -ifeq ($(CCC),g++) +ifeq (g++, $(findstring g++,$(CCC))) LEVEL_2_CPP_WARNINGS = -Wall LEVEL_2_CPP_WARNINGS += -W # deliberately enable char-subscript warnings @@ -144,7 +144,7 @@ ifeq ($(CCC),g++) LEVEL_2_CPP_WARNINGS += -Wsign-promo LEVEL_2_CPP_WARNINGS += -Wsynth else - ifeq ($(CCC),CC) + ifeq (CC, $(findstring CC,$(CCC))) ifeq ($(OS),irix) # MIPSpro Compilers # see warning descriptions above @@ -159,7 +159,7 @@ endif ######################################################################## # stubs warning fix -ifeq ($(CC),gcc) +ifeq (gcc, $(findstring gcc,$(CC))) FIX_STUBS_WARNINGS = -Wno-unused else FIX_STUBS_WARNINGS = |