Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndre Susano Pinto <andresusanopinto@gmail.com>2009-08-01 14:21:26 +0400
committerAndre Susano Pinto <andresusanopinto@gmail.com>2009-08-01 14:21:26 +0400
commitc3a4936d9dc4abc6be5c74a16521d252893a2805 (patch)
tree0c4ef038058d84e37a0c302bef89240eb780d2e0 /source/blender/blenkernel
parent2830f25ff3bf7a80c88b86132f76081ced3e86a1 (diff)
parent78bbe5c479f80a331528d730486770c4f46e74fc (diff)
svn merge -r 21508:22111 https://svn.blender.org/svnroot/bf-blender/branches/blender2.5/blender
Diffstat (limited to 'source/blender/blenkernel')
-rw-r--r--source/blender/blenkernel/BKE_action.h42
-rw-r--r--source/blender/blenkernel/BKE_animsys.h27
-rw-r--r--source/blender/blenkernel/BKE_blender.h1
-rw-r--r--source/blender/blenkernel/BKE_boids.h62
-rw-r--r--source/blender/blenkernel/BKE_cloth.h3
-rw-r--r--source/blender/blenkernel/BKE_colortools.h12
-rw-r--r--source/blender/blenkernel/BKE_context.h20
-rw-r--r--source/blender/blenkernel/BKE_fcurve.h56
-rw-r--r--source/blender/blenkernel/BKE_modifier.h1
-rw-r--r--source/blender/blenkernel/BKE_nla.h99
-rw-r--r--source/blender/blenkernel/BKE_object.h5
-rw-r--r--source/blender/blenkernel/BKE_particle.h37
-rw-r--r--source/blender/blenkernel/BKE_pointcache.h2
-rw-r--r--source/blender/blenkernel/BKE_property.h1
-rw-r--r--source/blender/blenkernel/BKE_report.h31
-rw-r--r--source/blender/blenkernel/BKE_screen.h38
-rw-r--r--source/blender/blenkernel/BKE_sketch.h157
-rw-r--r--source/blender/blenkernel/BKE_smoke.h55
-rw-r--r--source/blender/blenkernel/BKE_softbody.h4
-rw-r--r--source/blender/blenkernel/BKE_utildefines.h1
-rw-r--r--source/blender/blenkernel/BKE_writeffmpeg.h22
-rw-r--r--source/blender/blenkernel/CMakeLists.txt9
-rw-r--r--source/blender/blenkernel/SConscript1
-rw-r--r--source/blender/blenkernel/intern/Makefile1
-rw-r--r--source/blender/blenkernel/intern/action.c113
-rw-r--r--source/blender/blenkernel/intern/anim_sys.c810
-rw-r--r--source/blender/blenkernel/intern/armature.c10
-rw-r--r--source/blender/blenkernel/intern/blender.c20
-rw-r--r--source/blender/blenkernel/intern/boids.c1524
-rw-r--r--source/blender/blenkernel/intern/colortools.c85
-rw-r--r--source/blender/blenkernel/intern/context.c110
-rw-r--r--source/blender/blenkernel/intern/depsgraph.c81
-rw-r--r--source/blender/blenkernel/intern/effect.c4
-rw-r--r--source/blender/blenkernel/intern/exotic.c48
-rw-r--r--source/blender/blenkernel/intern/fcurve.c1107
-rw-r--r--source/blender/blenkernel/intern/fluidsim.c14
-rw-r--r--source/blender/blenkernel/intern/fmodifier.c1197
-rw-r--r--source/blender/blenkernel/intern/image.c62
-rw-r--r--source/blender/blenkernel/intern/ipo.c124
-rw-r--r--source/blender/blenkernel/intern/material.c72
-rw-r--r--source/blender/blenkernel/intern/mesh.c7
-rw-r--r--source/blender/blenkernel/intern/modifier.c158
-rw-r--r--source/blender/blenkernel/intern/multires.c4
-rw-r--r--source/blender/blenkernel/intern/nla.c1515
-rw-r--r--source/blender/blenkernel/intern/object.c160
-rw-r--r--source/blender/blenkernel/intern/particle.c725
-rw-r--r--source/blender/blenkernel/intern/particle_system.c1428
-rw-r--r--source/blender/blenkernel/intern/pointcache.c156
-rw-r--r--source/blender/blenkernel/intern/property.c64
-rw-r--r--source/blender/blenkernel/intern/report.c19
-rw-r--r--source/blender/blenkernel/intern/scene.c64
-rw-r--r--source/blender/blenkernel/intern/screen.c29
-rw-r--r--source/blender/blenkernel/intern/sequence.c9
-rw-r--r--source/blender/blenkernel/intern/sketch.c600
-rw-r--r--source/blender/blenkernel/intern/smoke.c1342
-rw-r--r--source/blender/blenkernel/intern/softbody.c63
-rw-r--r--source/blender/blenkernel/intern/texture.c11
-rw-r--r--source/blender/blenkernel/intern/world.c17
-rw-r--r--source/blender/blenkernel/intern/writeavi.c3
-rw-r--r--source/blender/blenkernel/intern/writeffmpeg.c317
-rw-r--r--source/blender/blenkernel/nla_private.h85
61 files changed, 9809 insertions, 3035 deletions
diff --git a/source/blender/blenkernel/BKE_action.h b/source/blender/blenkernel/BKE_action.h
index f0796697670..d35acb5447a 100644
--- a/source/blender/blenkernel/BKE_action.h
+++ b/source/blender/blenkernel/BKE_action.h
@@ -1,6 +1,6 @@
/* BKE_action.h May 2001
*
- * Blender kernel action functionality
+ * Blender kernel action and pose functionality
*
* Reevan McKay
*
@@ -26,7 +26,7 @@
* All rights reserved.
*
* Contributor(s): Full recode, Ton Roosendaal, Crete 2005
- * Full recode, Joshua Leung, 2009
+ * Full recode, Joshua Leung, 2009
*
* ***** END GPL LICENSE BLOCK *****
*/
@@ -68,6 +68,9 @@ void make_local_action(struct bAction *act);
/* Some kind of bounding box operation on the action */
void calc_action_range(const struct bAction *act, float *start, float *end, int incl_hidden);
+/* Does action have any motion data at all? */
+short action_has_motion(const struct bAction *act);
+
/* Action Groups API ----------------- */
/* Make the given Action Group the active one */
@@ -100,8 +103,7 @@ void free_pose(struct bPose *pose);
* Allocate a new pose on the heap, and copy the src pose and it's channels
* into the new pose. *dst is set to the newly allocated structure, and assumed to be NULL.
*/
-void copy_pose(struct bPose **dst, struct bPose *src,
- int copyconstraints);
+void copy_pose(struct bPose **dst, struct bPose *src, int copyconstraints);
@@ -109,9 +111,8 @@ void copy_pose(struct bPose **dst, struct bPose *src,
* Return a pointer to the pose channel of the given name
* from this pose.
*/
-struct bPoseChannel *get_pose_channel(const struct bPose *pose,
- const char *name);
-
+struct bPoseChannel *get_pose_channel(const struct bPose *pose, const char *name);
+
/**
* Return a pointer to the active pose channel from this Object.
* (Note: Object, not bPose is used here, as we need layer info from Armature)
@@ -123,8 +124,9 @@ struct bPoseChannel *get_active_posechannel(struct Object *ob);
* already exists in this pose - if not a new one is
* allocated and initialized.
*/
-struct bPoseChannel *verify_pose_channel(struct bPose* pose,
- const char* name);
+struct bPoseChannel *verify_pose_channel(struct bPose* pose, const char* name);
+
+
/* sets constraint flags */
void update_pose_constraint_flags(struct bPose *pose);
@@ -133,23 +135,29 @@ void update_pose_constraint_flags(struct bPose *pose);
// XXX to be depreceated for a more general solution in animsys...
void framechange_poses_clear_unkeyed(void);
+/* Bone Groups API --------------------- */
+
+/* Adds a new bone-group */
+void pose_add_group(struct Object *ob);
+
+/* Remove the active bone-group */
+void pose_remove_group(struct Object *ob);
+
+/* Assorted Evaluation ----------------- */
+
/* Used for the Action Constraint */
void what_does_obaction(struct Scene *scene, struct Object *ob, struct Object *workob, struct bPose *pose, struct bAction *act, char groupname[], float cframe);
-/* 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);
-
/* for proxy */
void copy_pose_result(struct bPose *to, struct bPose *from);
/* clear all transforms */
void rest_pose(struct bPose *pose);
-/* map global time (frame nr) to strip converted time, doesn't clip */
-float get_action_frame(struct Object *ob, float cframe);
-/* map strip time to global time (frame nr) */
-float get_action_frame_inv(struct Object *ob, float cframe);
+/* 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);
diff --git a/source/blender/blenkernel/BKE_animsys.h b/source/blender/blenkernel/BKE_animsys.h
index b45917e6ca1..2447d1823af 100644
--- a/source/blender/blenkernel/BKE_animsys.h
+++ b/source/blender/blenkernel/BKE_animsys.h
@@ -1,5 +1,28 @@
-/* Testing code for new animation system in 2.5
- * Copyright 2009, Joshua Leung
+/**
+ * $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
+ * All rights reserved.
+ *
+ * Contributor(s): Joshua Leung (original author)
+ *
+ * ***** END GPL LICENSE BLOCK *****
*/
#ifndef BKE_ANIM_SYS_H
diff --git a/source/blender/blenkernel/BKE_blender.h b/source/blender/blenkernel/BKE_blender.h
index 795c7585b9c..19b9c315939 100644
--- a/source/blender/blenkernel/BKE_blender.h
+++ b/source/blender/blenkernel/BKE_blender.h
@@ -71,6 +71,7 @@ void pushpop_test(void);
/* global undo */
extern void BKE_write_undo(struct bContext *C, char *name);
extern void BKE_undo_step(struct bContext *C, int step);
+extern void BKE_undo_name(struct bContext *C, const char *name);
extern void BKE_reset_undo(void);
extern char *BKE_undo_menu_string(void);
extern void BKE_undo_number(struct bContext *C, int nr);
diff --git a/source/blender/blenkernel/BKE_boids.h b/source/blender/blenkernel/BKE_boids.h
new file mode 100644
index 00000000000..acceff863b9
--- /dev/null
+++ b/source/blender/blenkernel/BKE_boids.h
@@ -0,0 +1,62 @@
+/* BKE_particle.h
+ *
+ *
+ * $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 Janne Karhu.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef BKE_BOIDS_H
+#define BKE_BOIDS_H
+
+#include "DNA_boid_types.h"
+
+typedef struct BoidBrainData {
+ Scene *scene;
+ struct Object *ob;
+ struct ParticleSystem *psys;
+ struct ParticleSettings *part;
+ float timestep, cfra, dfra;
+ float wanted_co[3], wanted_speed;
+
+ /* Goal stuff */
+ struct Object *goal_ob;
+ float goal_co[3];
+ float goal_nor[3];
+ float goal_priority;
+} BoidBrainData;
+
+void boids_precalc_rules(struct ParticleSettings *part, float cfra);
+void boid_brain(BoidBrainData *bbd, int p, struct ParticleData *pa);
+void boid_body(BoidBrainData *bbd, struct ParticleData *pa);
+void boid_default_settings(BoidSettings *boids);
+BoidRule *boid_new_rule(int type);
+BoidState *boid_new_state(BoidSettings *boids);
+BoidState *boid_duplicate_state(BoidSettings *boids, BoidState *state);
+void boid_free_settings(BoidSettings *boids);
+BoidSettings *boid_copy_settings(BoidSettings *boids);
+BoidState *boid_get_current_state(BoidSettings *boids);
+#endif
diff --git a/source/blender/blenkernel/BKE_cloth.h b/source/blender/blenkernel/BKE_cloth.h
index 4270c677338..f3165c959bf 100644
--- a/source/blender/blenkernel/BKE_cloth.h
+++ b/source/blender/blenkernel/BKE_cloth.h
@@ -65,8 +65,7 @@ struct CollisionTree;
#elif defined (__sun) || defined (__sun__)
# define DO_INLINE
#else
-# define DO_INLINE inline
-# define LINUX
+# define DO_INLINE static inline
#endif
#define CLOTH_MAX_THREAD 2
diff --git a/source/blender/blenkernel/BKE_colortools.h b/source/blender/blenkernel/BKE_colortools.h
index 6f6c4a834df..c83a260690b 100644
--- a/source/blender/blenkernel/BKE_colortools.h
+++ b/source/blender/blenkernel/BKE_colortools.h
@@ -33,7 +33,16 @@ struct CurveMapping;
struct CurveMap;
struct ImBuf;
struct rctf;
-
+
+void gamma_correct_rec709(float *c, float gamma);
+void gamma_correct(float *c, float gamma);
+float srgb_to_linearrgb(float c);
+float linearrgb_to_srgb(float c);
+void color_manage_linearize(float *col_to, float *col_from);
+
+void floatbuf_to_srgb_byte(float *rectf, unsigned char *rectc, int x1, int x2, int y1, int y2, int w);
+void floatbuf_to_byte(float *rectf, unsigned char *rectc, int x1, int x2, int y1, int y2, int w);
+
struct CurveMapping *curvemapping_add(int tot, float minx, float miny, float maxx, float maxy);
void curvemapping_free(struct CurveMapping *cumap);
struct CurveMapping *curvemapping_copy(struct CurveMapping *cumap);
@@ -60,5 +69,6 @@ void curvemapping_initialize(struct CurveMapping *cumap);
void curvemapping_table_RGBA(struct CurveMapping *cumap, float **array, int *size);
void colorcorrection_do_ibuf(struct ImBuf *ibuf, const char *profile);
+
#endif
diff --git a/source/blender/blenkernel/BKE_context.h b/source/blender/blenkernel/BKE_context.h
index f536e117b7b..e47ad969b91 100644
--- a/source/blender/blenkernel/BKE_context.h
+++ b/source/blender/blenkernel/BKE_context.h
@@ -101,6 +101,10 @@ bContextStore *CTX_store_copy(bContextStore *store);
void CTX_store_free(bContextStore *store);
void CTX_store_free_list(ListBase *contexts);
+/* need to store if python is initialized or not */
+int CTX_py_init_get(bContext *C);
+void CTX_py_init_set(bContext *C, int value);
+
/* Window Manager Context */
struct wmWindowManager *CTX_wm_manager(const bContext *C);
@@ -111,11 +115,24 @@ struct SpaceLink *CTX_wm_space_data(const bContext *C);
struct ARegion *CTX_wm_region(const bContext *C);
void *CTX_wm_region_data(const bContext *C);
struct ARegion *CTX_wm_menu(const bContext *C);
+struct ReportList *CTX_wm_reports(const bContext *C);
struct View3D *CTX_wm_view3d(const bContext *C);
struct RegionView3D *CTX_wm_region_view3d(const bContext *C);
struct SpaceText *CTX_wm_space_text(const bContext *C);
struct SpaceImage *CTX_wm_space_image(const bContext *C);
+struct SpaceConsole *CTX_wm_space_console(const bContext *C);
+struct SpaceButs *CTX_wm_space_buts(const bContext *C);
+struct SpaceFile *CTX_wm_space_file(const bContext *C);
+struct SpaceSeq *CTX_wm_space_seq(const bContext *C);
+struct SpaceOops *CTX_wm_space_outliner(const bContext *C);
+struct SpaceNla *CTX_wm_space_nla(const bContext *C);
+struct SpaceTime *CTX_wm_space_time(const bContext *C);
+struct SpaceNode *CTX_wm_space_node(const bContext *C);
+struct SpaceLogic *CTX_wm_space_logic(const bContext *C);
+struct SpaceIpo *CTX_wm_space_graph(const bContext *C);
+struct SpaceAction *CTX_wm_space_action(const bContext *C);
+struct SpaceInfo *CTX_wm_space_info(const bContext *C);
void CTX_wm_manager_set(bContext *C, struct wmWindowManager *wm);
void CTX_wm_window_set(bContext *C, struct wmWindow *win);
@@ -186,6 +203,9 @@ int CTX_data_selected_bases(const bContext *C, ListBase *list);
int CTX_data_visible_objects(const bContext *C, ListBase *list);
int CTX_data_visible_bases(const bContext *C, ListBase *list);
+int CTX_data_selectable_objects(const bContext *C, ListBase *list);
+int CTX_data_selectable_bases(const bContext *C, ListBase *list);
+
struct Object *CTX_data_active_object(const bContext *C);
struct Base *CTX_data_active_base(const bContext *C);
struct Object *CTX_data_edit_object(const bContext *C);
diff --git a/source/blender/blenkernel/BKE_fcurve.h b/source/blender/blenkernel/BKE_fcurve.h
index 9b8a2990fe5..cda64c6b241 100644
--- a/source/blender/blenkernel/BKE_fcurve.h
+++ b/source/blender/blenkernel/BKE_fcurve.h
@@ -1,12 +1,33 @@
-/* Testing code for new animation system in 2.5
- * Copyright 2009, Joshua Leung
+/**
+ * $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
+ * All rights reserved.
+ *
+ * Contributor(s): Joshua Leung (full recode)
+ *
+ * ***** END GPL LICENSE BLOCK *****
*/
#ifndef BKE_FCURVE_H
#define BKE_FCURVE_H
-//struct ListBase;
-
struct FCurve;
struct FModifier;
struct ChannelDriver;
@@ -54,8 +75,8 @@ typedef struct FModifierTypeInfo {
short size; /* size in bytes of the struct */
short acttype; /* eFMI_Action_Types */
short requires; /* eFMI_Requirement_Flags */
- char name[32]; /* name of modifier in interface */
- char structName[32]; /* name of struct for SDNA */
+ char name[64]; /* name of modifier in interface */
+ char structName[64]; /* name of struct for SDNA */
/* data management function pointers - special handling */
/* free any data that is allocated separately (optional) */
@@ -104,14 +125,20 @@ FModifierTypeInfo *get_fmodifier_typeinfo(int type);
/* ---------------------- */
-struct FModifier *fcurve_add_modifier(struct FCurve *fcu, int type);
-void fcurve_copy_modifiers(ListBase *dst, ListBase *src);
-void fcurve_remove_modifier(struct FCurve *fcu, struct FModifier *fcm);
-void fcurve_free_modifiers(struct FCurve *fcu);
-void fcurve_bake_modifiers(struct FCurve *fcu, int start, int end);
+struct FModifier *add_fmodifier(ListBase *modifiers, int type);
+void copy_fmodifiers(ListBase *dst, ListBase *src);
+void remove_fmodifier(ListBase *modifiers, struct FModifier *fcm);
+void free_fmodifiers(ListBase *modifiers);
+
+struct FModifier *find_active_fmodifier(ListBase *modifiers);
+void set_active_fmodifier(ListBase *modifiers, struct FModifier *fcm);
+
+short list_has_suitable_fmodifier(ListBase *modifiers, int mtype, short acttype);
-struct FModifier *fcurve_find_active_modifier(struct FCurve *fcu);
-void fcurve_set_active_modifier(struct FCurve *fcu, struct FModifier *fcm);
+float evaluate_time_fmodifiers(ListBase *modifiers, struct FCurve *fcu, float cvalue, float evaltime);
+void evaluate_value_fmodifiers(ListBase *modifiers, struct FCurve *fcu, float *cvalue, float evaltime);
+
+void fcurve_bake_modifiers(struct FCurve *fcu, int start, int end);
/* ************** F-Curves API ******************** */
@@ -126,9 +153,6 @@ 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);
-/* test if there is a keyframe at cfra */
-short on_keyframe_fcurve(struct FCurve *fcu, float cfra);
-
/* 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_modifier.h b/source/blender/blenkernel/BKE_modifier.h
index 144ed3bc624..b65d77751e2 100644
--- a/source/blender/blenkernel/BKE_modifier.h
+++ b/source/blender/blenkernel/BKE_modifier.h
@@ -33,6 +33,7 @@
#include "DNA_modifier_types.h" /* needed for all enum typdefs */
#include "BKE_customdata.h"
+struct ID;
struct EditMesh;
struct DerivedMesh;
struct DagForest;
diff --git a/source/blender/blenkernel/BKE_nla.h b/source/blender/blenkernel/BKE_nla.h
index 230096d7ea7..241a8fd7b59 100644
--- a/source/blender/blenkernel/BKE_nla.h
+++ b/source/blender/blenkernel/BKE_nla.h
@@ -17,12 +17,12 @@
* 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.
+ * The Original Code is Copyright (C) 2009 Blender Foundation, Joshua Leung
* All rights reserved.
*
* The Original Code is: all of this file.
*
- * Contributor(s): none yet.
+ * Contributor(s): Joshua Leung (full recode)
*
* ***** END GPL LICENSE BLOCK *****
*/
@@ -30,15 +30,92 @@
#ifndef BKE_NLA_H
#define BKE_NLA_H
-struct bActionStrip;
-struct ListBase;
-struct Object;
+struct AnimData;
+struct NlaStrip;
+struct NlaTrack;
+struct bAction;
+
+/* ----------------------------- */
+/* Data Management */
+
+void free_nlastrip(ListBase *strips, struct NlaStrip *strip);
+void free_nlatrack(ListBase *tracks, struct NlaTrack *nlt);
+void free_nladata(ListBase *tracks);
+
+struct NlaStrip *copy_nlastrip(struct NlaStrip *strip);
+struct NlaTrack *copy_nlatrack(struct NlaTrack *nlt);
+void copy_nladata(ListBase *dst, ListBase *src);
+
+struct NlaTrack *add_nlatrack(struct AnimData *adt, struct NlaTrack *prev);
+struct NlaStrip *add_nlastrip(struct bAction *act);
+struct NlaStrip *add_nlastrip_to_stack(struct AnimData *adt, struct bAction *act);
+
+/* ----------------------------- */
+/* API */
+
+short BKE_nlastrips_has_space(ListBase *strips, float start, float end);
+void BKE_nlastrips_sort_strips(ListBase *strips);
+
+short BKE_nlastrips_add_strip(ListBase *strips, struct NlaStrip *strip);
+
+
+void BKE_nlastrips_make_metas(ListBase *strips, short temp);
+void BKE_nlastrips_clear_metas(ListBase *strips, short onlySel, short onlyTemp);
+void BKE_nlastrips_clear_metastrip(ListBase *strips, struct NlaStrip *strip);
+short BKE_nlameta_add_strip(struct NlaStrip *mstrip, struct NlaStrip *strip);
+void BKE_nlameta_flush_transforms(struct NlaStrip *mstrip);
+
+/* ............ */
+
+struct NlaTrack *BKE_nlatrack_find_active(ListBase *tracks);
+void BKE_nlatrack_set_active(ListBase *tracks, struct NlaTrack *nlt);
+
+void BKE_nlatrack_solo_toggle(struct AnimData *adt, struct NlaTrack *nlt);
+
+short BKE_nlatrack_has_space(struct NlaTrack *nlt, float start, float end);
+void BKE_nlatrack_sort_strips(struct NlaTrack *nlt);
+
+short BKE_nlatrack_add_strip(struct NlaTrack *nlt, struct NlaStrip *strip);
+
+/* ............ */
+
+struct NlaStrip *BKE_nlastrip_find_active(struct NlaTrack *nlt);
+
+short BKE_nlastrip_within_bounds(struct NlaStrip *strip, float min, float max);
+
+void BKE_nlastrip_validate_name(struct AnimData *adt, struct NlaStrip *strip);
+
+/* ............ */
+
+short BKE_nlatrack_has_animated_strips(struct NlaTrack *nlt);
+short BKE_nlatracks_have_animated_strips(ListBase *tracks);
+void BKE_nlastrip_validate_fcurves(struct NlaStrip *strip);
+
+void BKE_nla_validate_state(struct AnimData *adt);
+
+/* ............ */
+
+void BKE_nla_action_pushdown(struct AnimData *adt);
+
+short BKE_nla_tweakmode_enter(struct AnimData *adt);
+void BKE_nla_tweakmode_exit(struct AnimData *adt);
+
+/* ----------------------------- */
+/* Time Mapping */
+
+/* time mapping conversion modes */
+enum {
+ /* convert from global time to strip time - for evaluation */
+ NLATIME_CONVERT_EVAL = 0,
+ /* convert from global time to strip time - for editing corrections */
+ // XXX old 0 invert
+ NLATIME_CONVERT_UNMAP,
+ /* convert from strip time to global time */
+ // xxx old 1 invert
+ NLATIME_CONVERT_MAP,
+} eNlaTime_ConvertModes;
+
+float BKE_nla_tweakedit_remap(struct AnimData *adt, float cframe, short mode);
-void free_actionstrip (struct bActionStrip* strip);
-void free_nlastrips (struct ListBase *nlalist);
-void copy_nlastrips (struct ListBase *dst, struct ListBase *src);
-void copy_actionstrip (struct bActionStrip **dst, struct bActionStrip **src);
-void find_stridechannel(struct Object *ob, struct bActionStrip *strip);
-struct bActionStrip *convert_action_to_strip (struct Object *ob);
#endif
diff --git a/source/blender/blenkernel/BKE_object.h b/source/blender/blenkernel/BKE_object.h
index 3d71193f37a..a57529ccf75 100644
--- a/source/blender/blenkernel/BKE_object.h
+++ b/source/blender/blenkernel/BKE_object.h
@@ -98,11 +98,6 @@ void object_to_mat4(struct Object *ob, float mat[][4]);
void set_no_parent_ipo(int val);
-void disable_where_script(short on);
-int during_script(void);
-void disable_where_scriptlink(short on);
-int during_scriptlink(void);
-
void where_is_object_time(struct Scene *scene, struct Object *ob, float ctime);
void where_is_object(struct Scene *scene, struct Object *ob);
void where_is_object_simul(struct Scene *scene, struct Object *ob);
diff --git a/source/blender/blenkernel/BKE_particle.h b/source/blender/blenkernel/BKE_particle.h
index aa24706077d..cf02efc34ac 100644
--- a/source/blender/blenkernel/BKE_particle.h
+++ b/source/blender/blenkernel/BKE_particle.h
@@ -55,6 +55,9 @@ struct IpoCurve;
struct LinkNode;
struct KDTree;
struct RNG;
+struct SurfaceModifierData;
+struct BVHTreeRay;
+struct BVHTreeRayHit;
typedef struct ParticleEffectorCache {
struct ParticleEffectorCache *next, *prev;
@@ -95,16 +98,6 @@ typedef struct ParticleTexture{
float rough1, rough2, roughe; /* used in path caching */
} ParticleTexture;
-typedef struct BoidVecFunc{
- void (*Addf)(float *v, float *v1, float *v2);
- void (*Subf)(float *v, float *v1, float *v2);
- void (*Mulf)(float *v, float f);
- float (*Length)(float *v);
- float (*Normalize)(float *v);
- float (*Inpf)(float *v1, float *v2);
- void (*Copyf)(float *v1, float *v2);
-} BoidVecFunc;
-
typedef struct ParticleSeam{
float v0[3], v1[3];
float nor[3], dir[3], tan[3];
@@ -209,6 +202,19 @@ typedef struct ParticleBillboardData
}
ParticleBillboardData;
+/* container for moving data between deflet_particle and particle_intersect_face */
+typedef struct ParticleCollision
+{
+ struct Object *ob, *ob_t; // collided and current objects
+ struct CollisionModifierData *md; // collision modifier for ob_t;
+ float nor[3]; // normal at collision point
+ float vel[3]; // velocity of collision point
+ float co1[3], co2[3]; // ray start and end points
+ float ray_len; // original length of co2-co1, needed for collision time evaluation
+ float t; // time of previous collision, needed for substracting face velocity
+}
+ParticleCollision;
+
/* ----------- functions needed outside particlesystem ---------------- */
/* particle.c */
int count_particles(struct ParticleSystem *psys);
@@ -231,6 +237,7 @@ int psys_ob_has_hair(struct Object *ob);
int psys_in_edit_mode(struct Scene *scene, struct ParticleSystem *psys);
int psys_check_enabled(struct Object *ob, struct ParticleSystem *psys);
+void psys_free_boid_rules(struct ListBase *list);
void psys_free_settings(struct ParticleSettings *part);
void free_child_path_cache(struct ParticleSystem *psys);
void psys_free_path_cache(struct ParticleSystem *psys);
@@ -260,7 +267,6 @@ void psys_flush_particle_settings(struct Scene *scene, struct ParticleSettings *
void make_local_particlesettings(struct ParticleSettings *part);
struct LinkNode *psys_using_settings(struct Scene *scene, struct ParticleSettings *part, int flush_update);
-void psys_changed_type(struct ParticleSystem *psys);
void psys_reset(struct ParticleSystem *psys, int mode);
void psys_find_parents(struct Object *ob, struct ParticleSystemModifierData *psmd, struct ParticleSystem *psys);
@@ -289,14 +295,19 @@ void psys_thread_create_path(ParticleThread *thread, struct ChildParticle *cpa,
void psys_make_billboard(ParticleBillboardData *bb, float xvec[3], float yvec[3], float zvec[3], float center[3]);
/* particle_system.c */
-int psys_count_keyed_targets(struct Object *ob, struct ParticleSystem *psys);
+struct ParticleSystem *psys_get_target_system(struct Object *ob, struct ParticleTarget *pt);
+void psys_count_keyed_targets(struct Object *ob, struct ParticleSystem *psys);
void psys_get_reactor_target(struct Object *ob, struct ParticleSystem *psys, struct Object **target_ob, struct ParticleSystem **target_psys);
void psys_init_effectors(struct Scene *scene, struct Object *obsrc, struct Group *group, struct ParticleSystem *psys);
void psys_end_effectors(struct ParticleSystem *psys);
+void psys_make_temp_pointcache(struct Object *ob, struct ParticleSystem *psys);
+void psys_end_temp_pointcache(struct ParticleSystem *psys);
void psys_get_pointcache_start_end(struct Scene *scene, struct ParticleSystem *psys, int *sfra, int *efra);
+void psys_check_boid_data(struct ParticleSystem *psys);
+
void particle_system_update(struct Scene *scene, struct Object *ob, struct ParticleSystem *psys);
/* ----------- functions needed only inside particlesystem ------------ */
@@ -320,11 +331,13 @@ float psys_interpolate_value_from_verts(struct DerivedMesh *dm, short from, int
void psys_get_from_key(struct ParticleKey *key, float *loc, float *vel, float *rot, float *time);
int psys_intersect_dm(struct Scene *scene, struct Object *ob, struct DerivedMesh *dm, float *vert_cos, float *co1, float* co2, float *min_d, int *min_face, float *min_uv, float *face_minmax, float *pa_minmax, float radius, float *ipoint);
+void particle_intersect_face(void *userdata, int index, const struct BVHTreeRay *ray, struct BVHTreeRayHit *hit);
void psys_particle_on_dm(struct DerivedMesh *dm, int from, int index, int index_dmcache, float *fw, float foffset, float *vec, float *nor, float *utan, float *vtan, float *orco, float *ornor);
/* particle_system.c */
void initialize_particle(struct ParticleData *pa, int p, struct Object *ob, struct ParticleSystem *psys, struct ParticleSystemModifierData *psmd);
+int effector_find_co(struct Scene *scene, float *pco, struct SurfaceModifierData *sur, struct Object *ob, struct PartDeflect *pd, float *co, float *nor, float *vel, int *index);
void do_effectors(int pa_no, struct ParticleData *pa, struct ParticleKey *state, struct Scene *scene, struct Object *ob, struct ParticleSystem *psys, float *texco, float *force_field, float *vel,float framestep, float cfra);
void psys_calc_dmcache(struct Object *ob, struct DerivedMesh *dm, struct ParticleSystem *psys);
diff --git a/source/blender/blenkernel/BKE_pointcache.h b/source/blender/blenkernel/BKE_pointcache.h
index c5d423c13ba..8062f807055 100644
--- a/source/blender/blenkernel/BKE_pointcache.h
+++ b/source/blender/blenkernel/BKE_pointcache.h
@@ -166,4 +166,6 @@ void BKE_ptcache_quick_cache_all(struct Scene *scene);
void BKE_ptcache_make_cache(struct PTCacheBaker* baker);
void BKE_ptcache_toggle_disk_cache(struct PTCacheID *pid);
+void BKE_ptcache_load_external(struct PTCacheID *pid);
+
#endif
diff --git a/source/blender/blenkernel/BKE_property.h b/source/blender/blenkernel/BKE_property.h
index 6af1deda727..78a9ecddaac 100644
--- a/source/blender/blenkernel/BKE_property.h
+++ b/source/blender/blenkernel/BKE_property.h
@@ -41,6 +41,7 @@ struct bProperty *copy_property(struct bProperty *prop);
void copy_properties(struct ListBase *lbn, struct ListBase *lbo);
void init_property(struct bProperty *prop);
struct bProperty *new_property(int type);
+void unique_property(struct bProperty *first, struct bProperty *prop, int force);
struct bProperty *get_ob_property(struct Object *ob, char *name);
void set_ob_property(struct Object *ob, struct bProperty *propc);
int compare_property(struct bProperty *prop, char *str);
diff --git a/source/blender/blenkernel/BKE_report.h b/source/blender/blenkernel/BKE_report.h
index 1bb7152fbf3..1d72b1c81f0 100644
--- a/source/blender/blenkernel/BKE_report.h
+++ b/source/blender/blenkernel/BKE_report.h
@@ -32,41 +32,14 @@
extern "C" {
#endif
-#include "DNA_listBase.h"
+#include "DNA_windowmanager_types.h"
/* Reporting Information and Errors
*
* These functions also accept NULL in case no error reporting
* is needed. */
-typedef enum ReportType {
- RPT_DEBUG = 0,
- RPT_INFO = 1000,
- RPT_WARNING = 2000,
- RPT_ERROR = 3000,
- RPT_ERROR_INVALID_INPUT = 3001,
- RPT_ERROR_INVALID_CONTEXT = 3002,
- RPT_ERROR_OUT_OF_MEMORY = 3003
-} ReportType;
-
-enum ReportListFlags {
- RPT_PRINT = 1,
- RPT_STORE = 2,
-};
-
-typedef struct Report {
- struct Report *next, *prev;
- ReportType type;
- char *typestr;
- char *message;
-} Report;
-
-typedef struct ReportList {
- ListBase list;
- ReportType printlevel;
- ReportType storelevel;
- int flag;
-} ReportList;
+/* report structures are stored in DNA */
void BKE_reports_init(ReportList *reports, int flag);
void BKE_reports_clear(ReportList *reports);
diff --git a/source/blender/blenkernel/BKE_screen.h b/source/blender/blenkernel/BKE_screen.h
index be625fb856a..4fcb7c881be 100644
--- a/source/blender/blenkernel/BKE_screen.h
+++ b/source/blender/blenkernel/BKE_screen.h
@@ -46,10 +46,8 @@ struct wmWindow;
struct wmWindowManager;
struct uiLayout;
struct uiMenuItem;
-struct StructRNA;
-struct PointerRNA;
-struct FunctionRNA;
-struct ParameterList;
+
+#include "RNA_types.h"
/* spacetype has everything stored to get an editor working, it gets initialized via
ED_spacetypes_init() in editors/area/spacetypes.c */
@@ -169,11 +167,8 @@ typedef struct PanelType {
/* draw entirely, view changes should be handled here */
void (*draw)(const struct bContext *, struct Panel *);
- /* python integration */
- void *py_data;
- struct StructRNA *py_srna;
- int (*py_call)(struct PointerRNA *, struct FunctionRNA *, struct ParameterList *);
- void (*py_free)(void *py_data);
+ /* RNA integration */
+ ExtensionRNA ext;
} PanelType;
/* header types */
@@ -187,13 +182,16 @@ typedef struct HeaderType {
/* draw entirely, view changes should be handled here */
void (*draw)(const struct bContext *, struct Header *);
- /* python integration */
- void *py_data;
- struct StructRNA *py_srna;
- int (*py_call)(struct PointerRNA *, struct FunctionRNA *, struct ParameterList *);
- void (*py_free)(void *py_data);
+ /* RNA integration */
+ ExtensionRNA ext;
} HeaderType;
+typedef struct Header {
+ struct HeaderType *type; /* runtime */
+ struct uiLayout *layout; /* runtime for drawing */
+} Header;
+
+
/* menu types */
typedef struct MenuType {
@@ -208,13 +206,15 @@ typedef struct MenuType {
/* draw entirely, view changes should be handled here */
void (*draw)(const struct bContext *, struct Menu *);
- /* python integration */
- void *py_data;
- struct StructRNA *py_srna;
- int (*py_call)(struct PointerRNA *, struct FunctionRNA *, struct ParameterList *);
- void (*py_free)(void *py_data);
+ /* RNA integration */
+ ExtensionRNA ext;
} MenuType;
+typedef struct Menu {
+ struct MenuType *type; /* runtime */
+ struct uiLayout *layout; /* runtime for drawing */
+} Menu;
+
/* spacetypes */
struct SpaceType *BKE_spacetype_from_id(int spaceid);
struct ARegionType *BKE_regiontype_from_id(struct SpaceType *st, int regionid);
diff --git a/source/blender/blenkernel/BKE_sketch.h b/source/blender/blenkernel/BKE_sketch.h
new file mode 100644
index 00000000000..424dd5c9f80
--- /dev/null
+++ b/source/blender/blenkernel/BKE_sketch.h
@@ -0,0 +1,157 @@
+/**
+ *
+ * $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.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+#ifndef BKE_SKETCH_H
+#define BKE_SKETCH_H
+
+typedef enum SK_PType
+{
+ PT_CONTINUOUS,
+ PT_EXACT,
+} SK_PType;
+
+typedef enum SK_PMode
+{
+ PT_SNAP,
+ PT_PROJECT,
+} SK_PMode;
+
+typedef struct SK_Point
+{
+ float p[3];
+ short p2d[2];
+ float no[3];
+ float size;
+ SK_PType type;
+ SK_PMode mode;
+} SK_Point;
+
+typedef struct SK_Stroke
+{
+ struct SK_Stroke *next, *prev;
+
+ SK_Point *points;
+ int nb_points;
+ int buf_size;
+ int selected;
+} SK_Stroke;
+
+#define SK_OVERDRAW_LIMIT 5
+
+typedef struct SK_Overdraw
+{
+ SK_Stroke *target;
+ int start, end;
+ int count;
+} SK_Overdraw;
+
+#define SK_Stroke_BUFFER_INIT_SIZE 20
+
+typedef struct SK_DrawData
+{
+ short mval[2];
+ short previous_mval[2];
+ SK_PType type;
+} SK_DrawData;
+
+typedef struct SK_Intersection
+{
+ struct SK_Intersection *next, *prev;
+ SK_Stroke *stroke;
+ int before;
+ int after;
+ int gesture_index;
+ float p[3];
+ float lambda; /* used for sorting intersection points */
+} SK_Intersection;
+
+typedef struct SK_Sketch
+{
+ ListBase strokes;
+ ListBase depth_peels;
+ SK_Stroke *active_stroke;
+ SK_Stroke *gesture;
+ SK_Point next_point;
+ SK_Overdraw over;
+} SK_Sketch;
+
+
+typedef struct SK_Gesture {
+ SK_Stroke *stk;
+ SK_Stroke *segments;
+
+ ListBase intersections;
+ ListBase self_intersections;
+
+ int nb_self_intersections;
+ int nb_intersections;
+ int nb_segments;
+} SK_Gesture;
+
+
+/************************************************/
+
+void freeSketch(SK_Sketch *sketch);
+SK_Sketch* createSketch();
+
+void sk_removeStroke(SK_Sketch *sketch, SK_Stroke *stk);
+
+void sk_freeStroke(SK_Stroke *stk);
+SK_Stroke* sk_createStroke();
+
+SK_Point *sk_lastStrokePoint(SK_Stroke *stk);
+
+void sk_allocStrokeBuffer(SK_Stroke *stk);
+void sk_shrinkStrokeBuffer(SK_Stroke *stk);
+void sk_growStrokeBuffer(SK_Stroke *stk);
+void sk_growStrokeBufferN(SK_Stroke *stk, int n);
+
+void sk_replaceStrokePoint(SK_Stroke *stk, SK_Point *pt, int n);
+void sk_insertStrokePoint(SK_Stroke *stk, SK_Point *pt, int n);
+void sk_appendStrokePoint(SK_Stroke *stk, SK_Point *pt);
+void sk_insertStrokePoints(SK_Stroke *stk, SK_Point *pts, int len, int start, int end);
+
+void sk_trimStroke(SK_Stroke *stk, int start, int end);
+void sk_straightenStroke(SK_Stroke *stk, int start, int end, float p_start[3], float p_end[3]);
+void sk_polygonizeStroke(SK_Stroke *stk, int start, int end);
+void sk_flattenStroke(SK_Stroke *stk, int start, int end);
+void sk_reverseStroke(SK_Stroke *stk);
+
+void sk_filterLastContinuousStroke(SK_Stroke *stk);
+void sk_filterStroke(SK_Stroke *stk, int start, int end);
+
+void sk_initPoint(SK_Point *pt, SK_DrawData *dd, float *no);
+void sk_copyPoint(SK_Point *dst, SK_Point *src);
+
+int sk_stroke_filtermval(SK_DrawData *dd);
+void sk_endContinuousStroke(SK_Stroke *stk);
+
+void sk_updateNextPoint(SK_Sketch *sketch, SK_Stroke *stk);
+
+void sk_initDrawData(SK_DrawData *dd, short mval[2]);
+
+void sk_deleteSelectedStrokes(SK_Sketch *sketch);
+void sk_selectAllSketch(SK_Sketch *sketch, int mode);
+
+#endif
diff --git a/source/blender/blenkernel/BKE_smoke.h b/source/blender/blenkernel/BKE_smoke.h
new file mode 100644
index 00000000000..b37e1d08fcc
--- /dev/null
+++ b/source/blender/blenkernel/BKE_smoke.h
@@ -0,0 +1,55 @@
+/**
+ * BKE_cloth.h
+ *
+ * $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) Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Daniel Genrich
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef BKE_SMOKE_H_
+#define BKE_SMOKE_H_
+
+void smokeModifier_do(struct SmokeModifierData *smd, struct Scene *scene, struct Object *ob, struct DerivedMesh *dm);
+
+void smokeModifier_free (struct SmokeModifierData *smd);
+void smokeModifier_reset(struct SmokeModifierData *smd);
+void smokeModifier_createType(struct SmokeModifierData *smd);
+
+void smoke_set_tray(struct SmokeModifierData *smd, size_t index, float transparency);
+float smoke_get_tray(struct SmokeModifierData *smd, size_t index);
+float smoke_get_tvox(struct SmokeModifierData *smd, size_t index);
+void smoke_set_tvox(struct SmokeModifierData *smd, size_t index, float tvox);
+
+void smoke_set_bigtray(struct SmokeModifierData *smd, size_t index, float transparency);
+float smoke_get_bigtray(struct SmokeModifierData *smd, size_t index);
+float smoke_get_bigtvox(struct SmokeModifierData *smd, size_t index);
+void smoke_set_bigtvox(struct SmokeModifierData *smd, size_t index, float tvox);
+
+long long smoke_get_mem_req(int xres, int yres, int zres, int amplify);
+void smoke_prepare_View(struct SmokeModifierData *smd, float *light);
+void smoke_prepare_bigView(struct SmokeModifierData *smd, float *light);
+
+#endif /* BKE_SMOKE_H_ */
diff --git a/source/blender/blenkernel/BKE_softbody.h b/source/blender/blenkernel/BKE_softbody.h
index 05a9bfb0ca9..971ac7a5f01 100644
--- a/source/blender/blenkernel/BKE_softbody.h
+++ b/source/blender/blenkernel/BKE_softbody.h
@@ -44,7 +44,9 @@ typedef struct BodyPoint {
float choke,choke2,frozen;
float colball;
short flag;
- char octantflag;
+ //char octantflag;
+ float mass;
+ float springweight;
} BodyPoint;
/* allocates and initializes general main data */
diff --git a/source/blender/blenkernel/BKE_utildefines.h b/source/blender/blenkernel/BKE_utildefines.h
index 1c88b94df85..f5287e4e100 100644
--- a/source/blender/blenkernel/BKE_utildefines.h
+++ b/source/blender/blenkernel/BKE_utildefines.h
@@ -136,6 +136,7 @@
#define IS_EQT(a, b, c) ((a > b)? (((a-b) <= c)? 1:0) : ((((b-a) <= c)? 1:0)))
#define IN_RANGE(a, b, c) ((b < c)? ((b<a && a<c)? 1:0) : ((c<a && a<b)? 1:0))
+#define IN_RANGE_INCL(a, b, c) ((b < c)? ((b<=a && a<=c)? 1:0) : ((c<=a && a<=b)? 1:0))
/* this weirdo pops up in two places ... */
#if !defined(WIN32)
diff --git a/source/blender/blenkernel/BKE_writeffmpeg.h b/source/blender/blenkernel/BKE_writeffmpeg.h
index dba3944a58d..be136bd9d6d 100644
--- a/source/blender/blenkernel/BKE_writeffmpeg.h
+++ b/source/blender/blenkernel/BKE_writeffmpeg.h
@@ -46,19 +46,29 @@ extern "C" {
#define FFMPEG_MKV 9
#define FFMPEG_OGG 10
-#define FFMPEG_PRESET_NONE 0
-#define FFMPEG_PRESET_DVD 1
-#define FFMPEG_PRESET_SVCD 2
-#define FFMPEG_PRESET_VCD 3
-#define FFMPEG_PRESET_DV 4
-#define FFMPEG_PRESET_H264 5
+#define FFMPEG_PRESET_NONE 0
+#define FFMPEG_PRESET_DVD 1
+#define FFMPEG_PRESET_SVCD 2
+#define FFMPEG_PRESET_VCD 3
+#define FFMPEG_PRESET_DV 4
+#define FFMPEG_PRESET_H264 5
+#define FFMPEG_PRESET_THEORA 6
+#define FFMPEG_PRESET_XVID 7
+struct IDProperty;
struct RenderData;
extern void start_ffmpeg(struct RenderData *rd, int rectx, int recty);
extern void end_ffmpeg(void);
extern void append_ffmpeg(struct RenderData *rd, int frame, int *pixels, int rectx, int recty);
+extern void ffmpeg_set_preset(struct RenderData *rd, int preset);
+extern void ffmpeg_verify_image_type(struct RenderData *rd);
+
+extern struct IDProperty *ffmpeg_property_add(struct RenderData *Rd, char *type, int opt_index, int parent_index);
+extern int ffmpeg_property_add_string(struct RenderData *rd, const char *type, const char *str);
+extern void ffmpeg_property_del(struct RenderData *rd, void *type, void *prop_);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt
index ebe0ea74c28..656a292da15 100644
--- a/source/blender/blenkernel/CMakeLists.txt
+++ b/source/blender/blenkernel/CMakeLists.txt
@@ -32,9 +32,8 @@ SET(INC
../imbuf ../avi ../../../intern/elbeem/extern ../../../intern/opennl/extern
../../../intern/iksolver/extern ../blenloader ../quicktime
../../../extern/bullet2/src
- ../nodes ../../../extern/glew/include ../gpu ../makesrna
+ ../nodes ../../../extern/glew/include ../gpu ../makesrna ../../../intern/smoke/extern
../../../intern/bsp/extern
- ${SDL_INC}
${ZLIB_INC}
)
@@ -55,6 +54,12 @@ IF(WITH_QUICKTIME)
ADD_DEFINITIONS(-DWITH_QUICKTIME)
ENDIF(WITH_QUICKTIME)
+IF(WITH_SDL)
+ SET(INC ${INC} ${SDL_INC})
+ELSE(WITH_SDL)
+ ADD_DEFINITIONS(-DDISABLE_SDL)
+ENDIF(WITH_SDL)
+
IF(WITH_FFMPEG)
SET(INC ${INC} ${FFMPEG_INC})
ADD_DEFINITIONS(-DWITH_FFMPEG)
diff --git a/source/blender/blenkernel/SConscript b/source/blender/blenkernel/SConscript
index dbc990d0613..7016d992f02 100644
--- a/source/blender/blenkernel/SConscript
+++ b/source/blender/blenkernel/SConscript
@@ -10,6 +10,7 @@ incs += ' #/intern/iksolver/extern ../blenloader'
incs += ' #/extern/bullet2/src'
incs += ' #/intern/opennl/extern #/intern/bsp/extern'
incs += ' ../gpu #/extern/glew/include'
+incs += ' #/intern/smoke/extern'
incs += ' ' + env['BF_OPENGL_INC']
incs += ' ' + env['BF_ZLIB_INC']
diff --git a/source/blender/blenkernel/intern/Makefile b/source/blender/blenkernel/intern/Makefile
index a6a5066b574..fe7187200aa 100644
--- a/source/blender/blenkernel/intern/Makefile
+++ b/source/blender/blenkernel/intern/Makefile
@@ -68,6 +68,7 @@ CPPFLAGS += -I$(NAN_DECIMATION)/include
CPPFLAGS += -I$(NAN_ELBEEM)/include
CPPFLAGS += -I$(NAN_OPENNL)/include
CPPFLAGS += -I$(NAN_BSP)/include
+CPPFLAGS += -I$(NAN_SMOKE)/include
# path to zlib
CPPFLAGS += -I$(NAN_ZLIB)/include
diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c
index f7e15cef4c4..f4d4eb1cc9c 100644
--- a/source/blender/blenkernel/intern/action.c
+++ b/source/blender/blenkernel/intern/action.c
@@ -21,6 +21,7 @@
* All rights reserved.
*
* Contributor(s): Full recode, Ton Roosendaal, Crete 2005
+ * Full recode, Joshua Leung, 2009
*
* ***** END GPL LICENSE BLOCK *****
*/
@@ -31,7 +32,8 @@
#include <string.h>
#include <math.h>
-#include <stdlib.h> /* for NULL */
+#include <stdlib.h>
+#include <stddef.h>
#include "MEM_guardedalloc.h"
@@ -68,8 +70,6 @@
#include "RNA_access.h"
#include "RNA_types.h"
-//XXX #include "nla.h"
-
/* *********************** NOTE ON POSE AND ACTION **********************
- Pose is the local (object level) component of armature. The current
@@ -765,74 +765,77 @@ void framechange_poses_clear_unkeyed(void)
}
}
-/* ************************ END Pose channels *************** */
-
-/* ************** time ****************** */
+/* ************************** Bone Groups ************************** */
-static bActionStrip *get_active_strip(Object *ob)
+/* Adds a new bone-group */
+void pose_add_group (Object *ob)
{
-#if 0 // XXX old animation system
- bActionStrip *strip;
+ bPose *pose= (ob) ? ob->pose : NULL;
+ bActionGroup *grp;
- if(ob->action==NULL)
- return NULL;
-
- for (strip=ob->nlastrips.first; strip; strip=strip->next)
- if(strip->flag & ACTSTRIP_ACTIVE)
- break;
+ if (ELEM(NULL, ob, ob->pose))
+ return;
- if(strip && strip->act==ob->action)
- return strip;
-#endif // XXX old animation system
-
- return NULL;
+ grp= MEM_callocN(sizeof(bActionGroup), "PoseGroup");
+ strcpy(grp->name, "Group");
+ BLI_addtail(&pose->agroups, grp);
+ BLI_uniquename(&pose->agroups, grp, "Group", '.', offsetof(bActionGroup, name), 32);
+
+ pose->active_group= BLI_countlist(&pose->agroups);
}
-/* non clipped mapping of strip */
-static float get_actionstrip_frame(bActionStrip *strip, float cframe, int invert)
+/* Remove the active bone-group */
+void pose_remove_group (Object *ob)
{
- float length, actlength, repeat, scale;
-
- if (strip->repeat == 0.0f) strip->repeat = 1.0f;
- repeat = (strip->flag & ACTSTRIP_USESTRIDE) ? (1.0f) : (strip->repeat);
-
- if (strip->scale == 0.0f) strip->scale= 1.0f;
- scale = (float)fabs(strip->scale); /* scale must be positive (for now) */
+ bPose *pose= (ob) ? ob->pose : NULL;
+ bActionGroup *grp = NULL;
+ bPoseChannel *pchan;
- actlength = strip->actend-strip->actstart;
- if (actlength == 0.0f) actlength = 1.0f;
- length = repeat * scale * actlength;
+ /* sanity checks */
+ if (ELEM(NULL, ob, pose))
+ return;
+ if (pose->active_group <= 0)
+ return;
- /* invert = convert action-strip time to global time */
- if (invert)
- return length*(cframe - strip->actstart)/(repeat*actlength) + strip->start;
- else
- return repeat*actlength*(cframe - strip->start)/length + strip->actstart;
+ /* get group to remove */
+ grp= BLI_findlink(&pose->agroups, pose->active_group-1);
+ if (grp) {
+ /* adjust group references (the trouble of using indices!):
+ * - firstly, make sure nothing references it
+ * - also, make sure that those after this item get corrected
+ */
+ for (pchan= pose->chanbase.first; pchan; pchan= pchan->next) {
+ if (pchan->agrp_index == pose->active_group)
+ pchan->agrp_index= 0;
+ else if (pchan->agrp_index > pose->active_group)
+ pchan->agrp_index--;
+ }
+
+ /* now, remove it from the pose */
+ BLI_freelinkN(&pose->agroups, grp);
+ pose->active_group= 0;
+ }
}
-/* if the conditions match, it converts current time to strip time */
-float get_action_frame(Object *ob, float cframe)
-{
- bActionStrip *strip= get_active_strip(ob);
-
- if(strip)
- return get_actionstrip_frame(strip, cframe, 0);
- return cframe;
-}
+/* ************** time ****************** */
-/* inverted, strip time to current time */
-float get_action_frame_inv(Object *ob, float cframe)
+/* Check if the given action has any keyframes */
+short action_has_motion(const bAction *act)
{
- bActionStrip *strip= get_active_strip(ob);
+ FCurve *fcu;
- if(strip)
- return get_actionstrip_frame(strip, cframe, 1);
- return cframe;
+ /* return on the first F-Curve that has some keyframes/samples defined */
+ if (act) {
+ for (fcu= act->curves.first; fcu; fcu= fcu->next) {
+ if (fcu->totvert)
+ return 1;
+ }
+ }
+
+ /* nothing found */
+ return 0;
}
-
-
-
/* Calculate the extents of given action */
void calc_action_range(const bAction *act, float *start, float *end, int incl_hidden)
{
diff --git a/source/blender/blenkernel/intern/anim_sys.c b/source/blender/blenkernel/intern/anim_sys.c
index 441e17f3318..2b4a2c135eb 100644
--- a/source/blender/blenkernel/intern/anim_sys.c
+++ b/source/blender/blenkernel/intern/anim_sys.c
@@ -1,10 +1,37 @@
-/* Testing code for new animation system in 2.5
- * Copyright 2009, Joshua Leung
+/**
+ * $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
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Joshua Leung (full recode)
+ *
+ * ***** END GPL LICENSE BLOCK *****
*/
#include <stdio.h>
#include <string.h>
#include <stddef.h>
+#include <float.h>
+#include <math.h>
#include "MEM_guardedalloc.h"
@@ -12,9 +39,12 @@
#include "BLI_arithb.h"
#include "BLI_dynstr.h"
+#include "DNA_anim_types.h"
+
#include "BKE_animsys.h"
#include "BKE_action.h"
#include "BKE_fcurve.h"
+#include "BKE_nla.h"
#include "BKE_global.h"
#include "BKE_main.h"
#include "BKE_utildefines.h"
@@ -22,7 +52,7 @@
#include "RNA_access.h"
#include "RNA_types.h"
-#include "DNA_anim_types.h"
+#include "nla_private.h"
/* ***************************************** */
/* AnimData API */
@@ -90,8 +120,15 @@ AnimData *BKE_id_add_animdata (ID *id)
IdAdtTemplate *iat= (IdAdtTemplate *)id;
/* check if there's already AnimData, in which case, don't add */
- if (iat->adt == NULL)
- iat->adt= MEM_callocN(sizeof(AnimData), "AnimData");
+ if (iat->adt == NULL) {
+ AnimData *adt;
+
+ /* add animdata */
+ adt= iat->adt= MEM_callocN(sizeof(AnimData), "AnimData");
+
+ /* set default settings */
+ adt->act_influence= 1.0f;
+ }
return iat->adt;
}
@@ -116,7 +153,13 @@ void BKE_free_animdata (ID *id)
/* unlink action (don't free, as it's in its own list) */
if (adt->action)
adt->action->id.us--;
+ /* same goes for the temporarily displaced action */
+ if (adt->tmpact)
+ adt->tmpact->id.us--;
+ /* free nla data */
+ free_nladata(&adt->nla_tracks);
+
/* free drivers - stored as a list of F-Curves */
free_fcurves(&adt->drivers);
@@ -146,9 +189,10 @@ AnimData *BKE_copy_animdata (AnimData *adt)
// XXX review this... it might not be optimal behaviour yet...
//id_us_plus((ID *)dadt->action);
dadt->action= copy_action(adt->action);
+ dadt->tmpact= copy_action(adt->tmpact);
/* duplicate NLA data */
- // XXX todo...
+ copy_nladata(&dadt->nla_tracks, &adt->nla_tracks);
/* duplicate drivers (F-Curves) */
copy_fcurves(&dadt->drivers, &adt->drivers);
@@ -355,10 +399,10 @@ void BKE_keyingsets_free (ListBase *list)
short animsys_remap_path (AnimMapper *remap, char *path, char **dst)
{
/* is there a valid remapping table to use? */
- if (remap) {
+ //if (remap) {
/* find a matching entry... to use to remap */
// ...TODO...
- }
+ //}
/* nothing suitable found, so just set dst to look at path (i.e. no alloc/free needed) */
*dst= path;
@@ -455,11 +499,14 @@ static void animsys_evaluate_fcurves (PointerRNA *ptr, ListBase *list, AnimMappe
/* calculate then execute each curve */
for (fcu= list->first; fcu; fcu= fcu->next)
{
- /* check if this curve should be skipped */
- if ((fcu->flag & (FCURVE_MUTED|FCURVE_DISABLED)) == 0)
- {
- calculate_fcurve(fcu, ctime);
- animsys_execute_fcurve(ptr, remap, fcu);
+ /* check if this F-Curve doesn't belong to a muted group */
+ if ((fcu->grp == NULL) || (fcu->grp->flag & AGRP_MUTED)==0) {
+ /* check if this curve should be skipped */
+ if ((fcu->flag & (FCURVE_MUTED|FCURVE_DISABLED)) == 0)
+ {
+ calculate_fcurve(fcu, ctime);
+ animsys_execute_fcurve(ptr, remap, fcu);
+ }
}
}
}
@@ -481,7 +528,6 @@ static void animsys_evaluate_drivers (PointerRNA *ptr, AnimData *adt, float ctim
short ok= 0;
/* check if this driver's curve should be skipped */
- // FIXME: maybe we shouldn't check for muted, though that would make things more confusing, as there's already too many ways to disable?
if ((fcu->flag & (FCURVE_MUTED|FCURVE_DISABLED)) == 0)
{
/* check if driver itself is tagged for recalculation */
@@ -514,6 +560,10 @@ void animsys_evaluate_action_group (PointerRNA *ptr, bAction *act, bActionGroup
if ELEM(NULL, act, agrp) return;
if ((remap) && (remap->target != act)) remap= NULL;
+ /* if group is muted, don't evaluated any of the F-Curve */
+ if (agrp->flag & AGRP_MUTED)
+ return;
+
/* calculate then execute each curve */
for (fcu= agrp->channels.first; (fcu) && (fcu->grp == agrp); fcu= fcu->next)
{
@@ -540,152 +590,603 @@ void animsys_evaluate_action (PointerRNA *ptr, bAction *act, AnimMapper *remap,
/* ***************************************** */
/* NLA System - Evaluation */
-/* used for list of strips to accumulate at current time */
-typedef struct NlaEvalStrip {
- struct NlaEvalStrip *next, *prev;
-
- NlaTrack *track; /* track that this strip belongs to */
- NlaStrip *strip; /* strip that's being used */
- NlaStrip *sblend; /* strip that's being blended towards (if applicable) */
-
- short track_index; /* the index of the track within the list */
- short strip_mode; /* which end of the strip are we looking at */
-} NlaEvalStrip;
-
-/* bNlaEvalStrip->strip_mode */
-enum {
- NES_TIME_BEFORE = -1,
- NES_TIME_WITHIN,
- NES_TIME_AFTER,
- NES_TIME_AFTER_BLEND
-} eNlaEvalStrip_StripMode;
+/* calculate influence of strip based for given frame based on blendin/out values */
+static float nlastrip_get_influence (NlaStrip *strip, float cframe)
+{
+ /* sanity checks - normalise the blendin/out values? */
+ strip->blendin= (float)fabs(strip->blendin);
+ strip->blendout= (float)fabs(strip->blendout);
+
+ /* result depends on where frame is in respect to blendin/out values */
+ if (IS_EQ(strip->blendin, 0)==0 && (cframe <= (strip->start + strip->blendin))) {
+ /* there is some blend-in */
+ return (float)fabs(cframe - strip->start) / (strip->blendin);
+ }
+ else if (IS_EQ(strip->blendout, 0)==0 && (cframe >= (strip->end - strip->blendout))) {
+ /* there is some blend-out */
+ return (float)fabs(strip->end - cframe) / (strip->blendout);
+ }
+ else {
+ /* in the middle of the strip, we should be full strength */
+ return 1.0f;
+ }
+}
+/* evaluate the evaluation time and influence for the strip, storing the results in the strip */
+static void nlastrip_evaluate_controls (NlaStrip *strip, float ctime)
+{
+ /* firstly, analytically generate values for influence and time (if applicable) */
+ if ((strip->flag & NLASTRIP_FLAG_USR_TIME) == 0)
+ strip->strip_time= nlastrip_get_frame(strip, ctime, NLATIME_CONVERT_EVAL);
+ if ((strip->flag & NLASTRIP_FLAG_USR_INFLUENCE) == 0)
+ strip->influence= nlastrip_get_influence(strip, ctime);
+
+ /* now strip's evaluate F-Curves for these settings (if applicable) */
+ if (strip->fcurves.first) {
+ PointerRNA strip_ptr;
+
+ /* create RNA-pointer needed to set values */
+ RNA_pointer_create(NULL, &RNA_NlaStrip, strip, &strip_ptr);
+
+ /* execute these settings as per normal */
+ animsys_evaluate_fcurves(&strip_ptr, &strip->fcurves, NULL, ctime);
+ }
+}
-/* temp channel for accumulating data from NLA (avoids needing to clear all values first) */
-// TODO: maybe this will be used as the 'cache' stuff needed for editable values too?
-typedef struct NlaEvalChannel {
- struct NlaEvalChannel *next, *prev;
+/* gets the strip active at the current time for a list of strips for evaluation purposes */
+NlaEvalStrip *nlastrips_ctime_get_strip (ListBase *list, ListBase *strips, short index, float ctime)
+{
+ NlaStrip *strip, *estrip=NULL;
+ NlaEvalStrip *nes;
+ short side= 0;
+
+ /* loop over strips, checking if they fall within the range */
+ for (strip= strips->first; strip; strip= strip->next) {
+ /* check if current time occurs within this strip */
+ if (IN_RANGE_INCL(ctime, strip->start, strip->end)) {
+ /* this strip is active, so try to use it */
+ estrip= strip;
+ side= NES_TIME_WITHIN;
+ break;
+ }
+
+ /* if time occurred before current strip... */
+ if (ctime < strip->start) {
+ if (strip == strips->first) {
+ /* before first strip - only try to use it if it extends backwards in time too */
+ if (strip->extendmode == NLASTRIP_EXTEND_HOLD)
+ estrip= strip;
+
+ /* side is 'before' regardless of whether there's a useful strip */
+ side= NES_TIME_BEFORE;
+ }
+ else {
+ /* before next strip - previous strip has ended, but next hasn't begun,
+ * so blending mode depends on whether strip is being held or not...
+ * - only occurs when no transition strip added, otherwise the transition would have
+ * been picked up above...
+ */
+ strip= strip->prev;
+
+ if (strip->extendmode != NLASTRIP_EXTEND_NOTHING)
+ estrip= strip;
+ side= NES_TIME_AFTER;
+ }
+ break;
+ }
+
+ /* if time occurred after current strip... */
+ if (ctime > strip->end) {
+ /* only if this is the last strip should we do anything, and only if that is being held */
+ if (strip == strips->last) {
+ if (strip->extendmode != NLASTRIP_EXTEND_NOTHING)
+ estrip= strip;
+
+ side= NES_TIME_AFTER;
+ break;
+ }
+
+ /* otherwise, skip... as the 'before' case will catch it more elegantly! */
+ }
+ }
- char *path; /* ready-to-use path (i.e. remapped already) */
- int array_index; /* if applicable... */
+ /* check if a valid strip was found
+ * - must not be muted (i.e. will have contribution
+ */
+ if ((estrip == NULL) || (estrip->flag & NLASTRIP_FLAG_MUTED))
+ return NULL;
+
+ /* if ctime was not within the boundaries of the strip, clamp! */
+ switch (side) {
+ case NES_TIME_BEFORE: /* extend first frame only */
+ ctime= estrip->start;
+ break;
+ case NES_TIME_AFTER: /* extend last frame only */
+ ctime= estrip->end;
+ break;
+ }
- float value; /* value of this channel */
-} NlaEvalChannel;
-
+ /* evaluate strip's evaluation controls
+ * - skip if no influence (i.e. same effect as muting the strip)
+ * - negative influence is not supported yet... how would that be defined?
+ */
+ // TODO: this sounds a bit hacky having a few isolated F-Curves stuck on some data it operates on...
+ nlastrip_evaluate_controls(estrip, ctime);
+ if (estrip->influence <= 0.0f)
+ return NULL;
+
+ /* check if strip has valid data to evaluate,
+ * and/or perform any additional type-specific actions
+ */
+ switch (estrip->type) {
+ case NLASTRIP_TYPE_CLIP:
+ /* clip must have some action to evaluate */
+ if (estrip->act == NULL)
+ return NULL;
+ break;
+ case NLASTRIP_TYPE_TRANSITION:
+ /* there must be strips to transition from and to (i.e. prev and next required) */
+ if (ELEM(NULL, estrip->prev, estrip->next))
+ return NULL;
+
+ /* evaluate controls for the relevant extents of the bordering strips... */
+ nlastrip_evaluate_controls(estrip->prev, estrip->start);
+ nlastrip_evaluate_controls(estrip->next, estrip->end);
+ break;
+ }
+
+ /* add to list of strips we need to evaluate */
+ nes= MEM_callocN(sizeof(NlaEvalStrip), "NlaEvalStrip");
+
+ nes->strip= estrip;
+ nes->strip_mode= side;
+ nes->track_index= index;
+ nes->strip_time= estrip->strip_time;
+
+ if (list)
+ BLI_addtail(list, nes);
+
+ return nes;
+}
/* ---------------------- */
-/* evaluate the F-Curves controlling settings for the NLA-strips (currently, not relinkable) */
-static void nlastrip_evaluate_fcurves (NlaStrip *strip, float ctime)
+/* find an NlaEvalChannel that matches the given criteria
+ * - ptr and prop are the RNA data to find a match for
+ */
+static NlaEvalChannel *nlaevalchan_find_match (ListBase *channels, PointerRNA *ptr, PropertyRNA *prop, int array_index)
{
- //PointerRNA actstrip_ptr;
- //FCurve *fcu;
+ NlaEvalChannel *nec;
- /* create RNA-pointer needed to set values */
- //RNA_pointer_create(NULL, &RNA_NlaStrip, strip, &actstrip_ptr);
+ /* sanity check */
+ if (channels == NULL)
+ return NULL;
- /* execute these settings as per normal */
- //animsys_evaluate_fcurves(&actstrip_ptr, &strip->fcurves, NULL, ctime);
+ /* loop through existing channels, checking for a channel which affects the same property */
+ for (nec= channels->first; nec; nec= nec->next) {
+ /* - comparing the PointerRNA's is done by comparing the pointers
+ * to the actual struct the property resides in, since that all the
+ * other data stored in PointerRNA cannot allow us to definitively
+ * identify the data
+ */
+ if ((nec->ptr.data == ptr->data) && (nec->prop == prop) && (nec->index == array_index))
+ return nec;
+ }
+
+ /* not found */
+ return NULL;
}
+/* verify that an appropriate NlaEvalChannel for this F-Curve exists */
+static NlaEvalChannel *nlaevalchan_verify (PointerRNA *ptr, ListBase *channels, NlaEvalStrip *nes, FCurve *fcu, short *newChan)
+{
+ NlaEvalChannel *nec;
+ NlaStrip *strip= nes->strip;
+ PropertyRNA *prop;
+ PointerRNA new_ptr;
+ char *path = NULL;
+ short free_path=0;
+
+ /* sanity checks */
+ if (channels == NULL)
+ return NULL;
+
+ /* get RNA pointer+property info from F-Curve for more convenient handling */
+ /* get path, remapped as appropriate to work in its new environment */
+ free_path= animsys_remap_path(strip->remap, fcu->rna_path, &path);
+
+ /* a valid property must be available, and it must be animateable */
+ if (RNA_path_resolve(ptr, path, &new_ptr, &prop) == 0) {
+ if (G.f & G_DEBUG) printf("NLA Strip Eval: Cannot resolve path \n");
+ return NULL;
+ }
+ /* only ok if animateable */
+ else if (RNA_property_animateable(&new_ptr, prop) == 0) {
+ if (G.f & G_DEBUG) printf("NLA Strip Eval: Property not animateable \n");
+ return NULL;
+ }
+
+ /* try to find a match */
+ nec= nlaevalchan_find_match(channels, &new_ptr, prop, fcu->array_index);
+
+ /* allocate a new struct for this if none found */
+ if (nec == NULL) {
+ nec= MEM_callocN(sizeof(NlaEvalChannel), "NlaEvalChannel");
+ *newChan= 1;
+ BLI_addtail(channels, nec);
+
+ nec->ptr= new_ptr;
+ nec->prop= prop;
+ nec->index= fcu->array_index;
+ }
+ else
+ *newChan= 0;
+
+ /* we can now return */
+ return nec;
+}
-/* gets the strip active at the current time for a track */
-static void nlatrack_ctime_get_strip (ListBase *list, NlaTrack *nlt, short index, float ctime)
+/* accumulate (i.e. blend) the given value on to the channel it affects */
+static void nlaevalchan_accumulate (NlaEvalChannel *nec, NlaEvalStrip *nes, short newChan, float value)
{
- NlaStrip *strip, *astrip=NULL, *bstrip=NULL;
- NlaEvalStrip *nes;
- short side= 0;
+ NlaStrip *strip= nes->strip;
+ short blendmode= strip->blendmode;
+ float inf= strip->influence;
- /* skip if track is muted */
- if (nlt->flag & NLATRACK_MUTED)
+ /* if channel is new, just store value regardless of blending factors, etc. */
+ if (newChan) {
+ nec->value= value;
return;
+ }
+
+ /* if this is being performed as part of transition evaluation, incorporate
+ * an additional weighting factor for the influence
+ */
+ if (nes->strip_mode == NES_TIME_TRANSITION_END)
+ inf *= nes->strip_time;
+
+ /* premultiply the value by the weighting factor */
+ if (IS_EQ(inf, 0)) return;
+ value *= inf;
+
+ /* perform blending */
+ switch (blendmode) {
+ case NLASTRIP_MODE_ADD:
+ /* simply add the scaled value on to the stack */
+ nec->value += value;
+ break;
+
+ case NLASTRIP_MODE_SUBTRACT:
+ /* simply subtract the scaled value from the stack */
+ nec->value -= value;
+ break;
+
+ case NLASTRIP_MODE_MULTIPLY:
+ /* multiply the scaled value with the stack */
+ nec->value *= value;
+ break;
+
+ case NLASTRIP_MODE_REPLACE:
+ default: // TODO: do we really want to blend by default? it seems more uses might prefer add...
+ /* do linear interpolation
+ * - the influence of the accumulated data (elsewhere, that is called dstweight)
+ * is 1 - influence, since the strip's influence is srcweight
+ */
+ nec->value= nec->value * (1.0f - inf) + value;
+ break;
+ }
+}
+
+/* accumulate the results of a temporary buffer with the results of the full-buffer */
+static void nlaevalchan_buffers_accumulate (ListBase *channels, ListBase *tmp_buffer, NlaEvalStrip *nes)
+{
+ NlaEvalChannel *nec, *necn, *necd;
- /* loop over strips, checking if they fall within the range */
- for (strip= nlt->strips.first; strip; strip= strip->next) {
- /* only consider if:
- * - current time occurs within strip's extents
- * - current time occurs before strip (if it is the first)
- * - current time occurs after strip (if hold is on)
- * - current time occurs between strips (1st of those isn't holding) - blend!
+ /* optimise - abort if no channels */
+ if (tmp_buffer->first == NULL)
+ return;
+
+ /* accumulate results in tmp_channels buffer to the accumulation buffer */
+ for (nec= tmp_buffer->first; nec; nec= necn) {
+ /* get pointer to next channel in case we remove the current channel from the temp-buffer */
+ necn= nec->next;
+
+ /* try to find an existing matching channel for this setting in the accumulation buffer */
+ necd= nlaevalchan_find_match(channels, &nec->ptr, nec->prop, nec->index);
+
+ /* if there was a matching channel already in the buffer, accumulate to it,
+ * otherwise, add the current channel to the buffer for efficiency
*/
- if (IN_RANGE(ctime, strip->start, strip->end)) {
- astrip= strip;
- side= NES_TIME_WITHIN;
- break;
+ if (necd)
+ nlaevalchan_accumulate(necd, nes, 0, nec->value);
+ else {
+ BLI_remlink(tmp_buffer, nec);
+ BLI_addtail(channels, nec);
}
- else if (ctime < strip->start) {
- if (strip == nlt->strips.first) {
- astrip= strip;
- side= NES_TIME_BEFORE;
- break;
- }
- else {
- astrip= strip->prev;
-
- if (astrip->flag & NLASTRIP_HOLDLASTFRAME) {
- side= NES_TIME_AFTER;
- break;
- }
- else {
- bstrip= strip;
- side= NES_TIME_AFTER_BLEND;
- break;
- }
- }
+ }
+
+ /* free temp-channels that haven't been assimilated into the buffer */
+ BLI_freelistN(tmp_buffer);
+}
+
+/* ---------------------- */
+/* F-Modifier stack joining/separation utilities - should we generalise these for BLI_listbase.h interface? */
+
+/* Temporarily join two lists of modifiers together, storing the result in a third list */
+static void nlaeval_fmodifiers_join_stacks (ListBase *result, ListBase *list1, ListBase *list2)
+{
+ FModifier *fcm1, *fcm2;
+
+ /* if list1 is invalid... */
+ if ELEM(NULL, list1, list1->first) {
+ if (list2 && list2->first) {
+ result->first= list2->first;
+ result->last= list2->last;
}
}
+ /* if list 2 is invalid... */
+ else if ELEM(NULL, list2, list2->first) {
+ result->first= list1->first;
+ result->last= list1->last;
+ }
+ else {
+ /* list1 should be added first, and list2 second, with the endpoints of these being the endpoints for result
+ * - the original lists must be left unchanged though, as we need that fact for restoring
+ */
+ result->first= list1->first;
+ result->last= list2->last;
+
+ fcm1= list1->last;
+ fcm2= list2->first;
+
+ fcm1->next= fcm2;
+ fcm2->prev= fcm1;
+ }
+}
+
+/* Split two temporary lists of modifiers */
+static void nlaeval_fmodifiers_split_stacks (ListBase *list1, ListBase *list2)
+{
+ FModifier *fcm1, *fcm2;
- /* check if strip has been found (and whether it has data worth considering) */
- if (ELEM(NULL, astrip, astrip->act))
+ /* if list1/2 is invalid... just skip */
+ if ELEM(NULL, list1, list2)
return;
- if (astrip->flag & NLASTRIP_MUTE)
+ if ELEM(NULL, list1->first, list2->first)
return;
+
+ /* get endpoints */
+ fcm1= list1->last;
+ fcm2= list2->first;
+
+ /* clear their links */
+ fcm1->next= NULL;
+ fcm2->prev= NULL;
+}
+
+/* ---------------------- */
+
+/* evaluate action-clip strip */
+static void nlastrip_evaluate_actionclip (PointerRNA *ptr, ListBase *channels, ListBase *modifiers, NlaEvalStrip *nes)
+{
+ ListBase tmp_modifiers = {NULL, NULL};
+ NlaStrip *strip= nes->strip;
+ FCurve *fcu;
+ float evaltime;
+
+ /* join this strip's modifiers to the parent's modifiers (own modifiers first) */
+ nlaeval_fmodifiers_join_stacks(&tmp_modifiers, &strip->modifiers, modifiers);
- /* check if blending between strips */
- if (side == NES_TIME_AFTER_BLEND) {
- /* blending between strips... so calculate influence+act_time of both */
- nlastrip_evaluate_fcurves(astrip, ctime);
- nlastrip_evaluate_fcurves(bstrip, ctime);
+ /* evaluate strip's modifiers which modify time to evaluate the base curves at */
+ evaltime= evaluate_time_fmodifiers(&tmp_modifiers, NULL, 0.0f, strip->strip_time);
+
+ /* evaluate all the F-Curves in the action, saving the relevant pointers to data that will need to be used */
+ for (fcu= strip->act->curves.first; fcu; fcu= fcu->next) {
+ NlaEvalChannel *nec;
+ float value = 0.0f;
+ short newChan = -1;
- if ((astrip->influence <= 0.0f) && (bstrip->influence <= 0.0f))
- return;
+ /* check if this curve should be skipped */
+ if (fcu->flag & (FCURVE_MUTED|FCURVE_DISABLED))
+ continue;
+ if ((fcu->grp) && (fcu->grp->flag & AGRP_MUTED))
+ continue;
+
+ /* evaluate the F-Curve's value for the time given in the strip
+ * NOTE: we use the modified time here, since strip's F-Curve Modifiers are applied on top of this
+ */
+ value= evaluate_fcurve(fcu, evaltime);
+
+ /* apply strip's F-Curve Modifiers on this value
+ * NOTE: we apply the strip's original evaluation time not the modified one (as per standard F-Curve eval)
+ */
+ evaluate_value_fmodifiers(&tmp_modifiers, fcu, &value, strip->strip_time);
+
+
+ /* get an NLA evaluation channel to work with, and accumulate the evaluated value with the value(s)
+ * stored in this channel if it has been used already
+ */
+ nec= nlaevalchan_verify(ptr, channels, nes, fcu, &newChan);
+ if (nec)
+ nlaevalchan_accumulate(nec, nes, newChan, value);
+ }
+
+ /* unlink this strip's modifiers from the parent's modifiers again */
+ nlaeval_fmodifiers_split_stacks(&strip->modifiers, modifiers);
+}
+
+/* evaluate transition strip */
+static void nlastrip_evaluate_transition (PointerRNA *ptr, ListBase *channels, ListBase *modifiers, NlaEvalStrip *nes)
+{
+ ListBase tmp_channels = {NULL, NULL};
+ ListBase tmp_modifiers = {NULL, NULL};
+ NlaEvalStrip tmp_nes;
+ NlaStrip *s1, *s2;
+
+ /* join this strip's modifiers to the parent's modifiers (own modifiers first) */
+ nlaeval_fmodifiers_join_stacks(&tmp_modifiers, &nes->strip->modifiers, modifiers);
+
+ /* get the two strips to operate on
+ * - we use the endpoints of the strips directly flanking our strip
+ * using these as the endpoints of the transition (destination and source)
+ * - these should have already been determined to be valid...
+ * - if this strip is being played in reverse, we need to swap these endpoints
+ * otherwise they will be interpolated wrong
+ */
+ if (nes->strip->flag & NLASTRIP_FLAG_REVERSE) {
+ s1= nes->strip->next;
+ s2= nes->strip->prev;
}
else {
- /* calculate/set the influence+act_time of this strip - don't consider if 0 influence */
- nlastrip_evaluate_fcurves(astrip, ctime);
-
- if (astrip->influence <= 0.0f)
- return;
+ s1= nes->strip->prev;
+ s2= nes->strip->next;
}
+ /* prepare template for 'evaluation strip'
+ * - based on the transition strip's evaluation strip data
+ * - strip_mode is NES_TIME_TRANSITION_* based on which endpoint
+ * - strip_time is the 'normalised' (i.e. in-strip) time for evaluation,
+ * which doubles up as an additional weighting factor for the strip influences
+ * which allows us to appear to be 'interpolating' between the two extremes
+ */
+ tmp_nes= *nes;
- /* allocate new eval-strip for this strip + add to stack */
- nes= MEM_callocN(sizeof(NlaEvalStrip), "NlaEvalStrip");
+ /* evaluate these strips into a temp-buffer (tmp_channels) */
+ // FIXME: modifier evalation here needs some work...
+ /* first strip */
+ tmp_nes.strip_mode= NES_TIME_TRANSITION_START;
+ tmp_nes.strip= s1;
+ nlastrip_evaluate(ptr, &tmp_channels, &tmp_modifiers, &tmp_nes);
+
+ /* second strip */
+ tmp_nes.strip_mode= NES_TIME_TRANSITION_END;
+ tmp_nes.strip= s2;
+ nlastrip_evaluate(ptr, &tmp_channels, &tmp_modifiers, &tmp_nes);
- nes->track= nlt;
- nes->strip= astrip;
- nes->sblend= bstrip;
- nes->track_index= index;
- nes->strip_mode= side;
- BLI_addtail(list, nes);
+ /* assumulate temp-buffer and full-buffer, using the 'real' strip */
+ nlaevalchan_buffers_accumulate(channels, &tmp_channels, nes);
+
+ /* unlink this strip's modifiers from the parent's modifiers again */
+ nlaeval_fmodifiers_split_stacks(&nes->strip->modifiers, modifiers);
}
-/* ---------------------- */
+/* evaluate meta-strip */
+static void nlastrip_evaluate_meta (PointerRNA *ptr, ListBase *channels, ListBase *modifiers, NlaEvalStrip *nes)
+{
+ ListBase tmp_channels = {NULL, NULL};
+ ListBase tmp_modifiers = {NULL, NULL};
+ NlaStrip *strip= nes->strip;
+ NlaEvalStrip *tmp_nes;
+ float evaltime;
+
+ /* meta-strip was calculated normally to have some time to be evaluated at
+ * and here we 'look inside' the meta strip, treating it as a decorated window to
+ * it's child strips, which get evaluated as if they were some tracks on a strip
+ * (but with some extra modifiers to apply).
+ *
+ * NOTE: keep this in sync with animsys_evaluate_nla()
+ */
+
+ /* join this strip's modifiers to the parent's modifiers (own modifiers first) */
+ nlaeval_fmodifiers_join_stacks(&tmp_modifiers, &strip->modifiers, modifiers);
+
+ /* find the child-strip to evaluate */
+ evaltime= (nes->strip_time * (strip->end - strip->start)) + strip->start;
+ tmp_nes= nlastrips_ctime_get_strip(NULL, &strip->strips, -1, evaltime);
+ if (tmp_nes == NULL)
+ return;
+
+ /* evaluate child-strip into tmp_channels buffer before accumulating
+ * in the accumulation buffer
+ */
+ nlastrip_evaluate(ptr, &tmp_channels, &tmp_modifiers, tmp_nes);
+
+ /* assumulate temp-buffer and full-buffer, using the 'real' strip */
+ nlaevalchan_buffers_accumulate(channels, &tmp_channels, nes);
+
+ /* free temp eval-strip */
+ MEM_freeN(tmp_nes);
+
+ /* unlink this strip's modifiers from the parent's modifiers again */
+ nlaeval_fmodifiers_split_stacks(&strip->modifiers, modifiers);
+}
/* evaluates the given evaluation strip */
-// FIXME: will we need the evaluation cache table set up to blend stuff in?
-// TODO: only evaluate here, but flush in one go using the accumulated channels at end...
-static void nlastrip_ctime_evaluate (ListBase *channels, NlaEvalStrip *nes, float ctime)
+void nlastrip_evaluate (PointerRNA *ptr, ListBase *channels, ListBase *modifiers, NlaEvalStrip *nes)
{
- // 1. (in old code) was to extract 'IPO-channels' from actions
- // 2. blend between the 'accumulated' data, and the new data
+ NlaStrip *strip= nes->strip;
+
+ /* to prevent potential infinite recursion problems (i.e. transition strip, beside meta strip containing a transition
+ * several levels deep inside it), we tag the current strip as being evaluated, and clear this when we leave
+ */
+ // TODO: be careful with this flag, since some edit tools may be running and have set this while animplayback was running
+ if (strip->flag & NLASTRIP_FLAG_EDIT_TOUCHED)
+ return;
+ strip->flag |= NLASTRIP_FLAG_EDIT_TOUCHED;
+
+ /* actions to take depend on the type of strip */
+ switch (strip->type) {
+ case NLASTRIP_TYPE_CLIP: /* action-clip */
+ nlastrip_evaluate_actionclip(ptr, channels, modifiers, nes);
+ break;
+ case NLASTRIP_TYPE_TRANSITION: /* transition */
+ nlastrip_evaluate_transition(ptr, channels, modifiers, nes);
+ break;
+ case NLASTRIP_TYPE_META: /* meta */
+ nlastrip_evaluate_meta(ptr, channels, modifiers, nes);
+ break;
+ }
+
+ /* clear temp recursion safe-check */
+ strip->flag &= ~NLASTRIP_FLAG_EDIT_TOUCHED;
}
/* write the accumulated settings to */
-static void nladata_flush_channels (PointerRNA *ptr, ListBase *channels)
+void nladata_flush_channels (ListBase *channels)
{
+ NlaEvalChannel *nec;
+ /* sanity checks */
+ if (channels == NULL)
+ return;
+
+ /* for each channel with accumulated values, write its value on the property it affects */
+ for (nec= channels->first; nec; nec= nec->next) {
+ PointerRNA *ptr= &nec->ptr;
+ PropertyRNA *prop= nec->prop;
+ int array_index= nec->index;
+ float value= nec->value;
+
+ /* write values - see animsys_write_rna_setting() to sync the code */
+ switch (RNA_property_type(prop))
+ {
+ case PROP_BOOLEAN:
+ if (RNA_property_array_length(prop))
+ RNA_property_boolean_set_index(ptr, prop, array_index, (int)value);
+ else
+ RNA_property_boolean_set(ptr, prop, (int)value);
+ break;
+ case PROP_INT:
+ if (RNA_property_array_length(prop))
+ RNA_property_int_set_index(ptr, prop, array_index, (int)value);
+ else
+ RNA_property_int_set(ptr, prop, (int)value);
+ break;
+ case PROP_FLOAT:
+ if (RNA_property_array_length(prop))
+ RNA_property_float_set_index(ptr, prop, array_index, value);
+ else
+ RNA_property_float_set(ptr, prop, value);
+ break;
+ case PROP_ENUM:
+ RNA_property_enum_set(ptr, prop, (int)value);
+ break;
+ default:
+ // can't do anything with other types of property....
+ break;
+ }
+ }
}
/* ---------------------- */
@@ -696,6 +1197,9 @@ static void nladata_flush_channels (PointerRNA *ptr, ListBase *channels)
*/
static void animsys_evaluate_nla (PointerRNA *ptr, AnimData *adt, float ctime)
{
+ ListBase dummy_trackslist = {NULL, NULL};
+ NlaStrip dummy_strip;
+
NlaTrack *nlt;
short track_index=0;
@@ -703,9 +1207,49 @@ static void animsys_evaluate_nla (PointerRNA *ptr, AnimData *adt, float ctime)
ListBase echannels= {NULL, NULL};
NlaEvalStrip *nes;
+ // TODO: need to zero out all channels used, otherwise we have problems with threadsafety
+ // and also when the user jumps between different times instead of moving sequentially...
+
/* 1. get the stack of strips to evaluate at current time (influence calculated here) */
- for (nlt=adt->nla_tracks.first; nlt; nlt=nlt->next, track_index++)
- nlatrack_ctime_get_strip(&estrips, nlt, track_index, ctime);
+ for (nlt=adt->nla_tracks.first; nlt; nlt=nlt->next, track_index++) {
+ /* if tweaking is on and this strip is the tweaking track, stop on this one */
+ if ((adt->flag & ADT_NLA_EDIT_ON) && (nlt->flag & NLATRACK_DISABLED))
+ break;
+
+ /* skip if we're only considering a track tagged 'solo' */
+ if ((adt->flag & ADT_NLA_SOLO_TRACK) && (nlt->flag & NLATRACK_SOLO)==0)
+ continue;
+ /* skip if track is muted */
+ if (nlt->flag & NLATRACK_MUTED)
+ continue;
+
+ /* otherwise, get strip to evaluate for this channel */
+ nes= nlastrips_ctime_get_strip(&estrips, &nlt->strips, track_index, ctime);
+ if (nes) nes->track= nlt;
+ }
+
+ /* add 'active' Action (may be tweaking track) as last strip to evaluate in NLA stack
+ * - only do this if we're not exclusively evaluating the 'solo' NLA-track
+ */
+ if ((adt->action) && !(adt->flag & ADT_NLA_SOLO_TRACK)) {
+ /* make dummy NLA strip, and add that to the stack */
+ memset(&dummy_strip, 0, sizeof(NlaStrip));
+ dummy_trackslist.first= dummy_trackslist.last= &dummy_strip;
+
+ dummy_strip.act= adt->action;
+ dummy_strip.remap= adt->remap;
+
+ calc_action_range(dummy_strip.act, &dummy_strip.actstart, &dummy_strip.actend, 1);
+ dummy_strip.start = dummy_strip.actstart;
+ dummy_strip.end = (IS_EQ(dummy_strip.actstart, dummy_strip.actend)) ? (dummy_strip.actstart + 1.0f): (dummy_strip.actend);
+
+ dummy_strip.blendmode= adt->act_blendmode;
+ dummy_strip.extendmode= adt->act_extendmode;
+ dummy_strip.influence= adt->act_influence;
+
+ /* add this to our list of evaluation strips */
+ nlastrips_ctime_get_strip(&estrips, &dummy_trackslist, -1, ctime);
+ }
/* only continue if there are strips to evaluate */
if (estrips.first == NULL)
@@ -714,10 +1258,10 @@ static void animsys_evaluate_nla (PointerRNA *ptr, AnimData *adt, float ctime)
/* 2. for each strip, evaluate then accumulate on top of existing channels, but don't set values yet */
for (nes= estrips.first; nes; nes= nes->next)
- nlastrip_ctime_evaluate(&echannels, nes, ctime);
+ nlastrip_evaluate(ptr, &echannels, NULL, nes);
/* 3. flush effects of accumulating channels in NLA to the actual data they affect */
- nladata_flush_channels(ptr, &echannels);
+ nladata_flush_channels(&echannels);
/* 4. free temporary evaluation data */
BLI_freelistN(&estrips);
@@ -799,17 +1343,19 @@ void BKE_animsys_evaluate_animdata (ID *id, AnimData *adt, float ctime, short re
* - NLA before Active Action, as Active Action behaves as 'tweaking track'
* that overrides 'rough' work in NLA
*/
+ // TODO: need to double check that this all works correctly
if ((recalc & ADT_RECALC_ANIM) || (adt->recalc & ADT_RECALC_ANIM))
{
/* evaluate NLA data */
if ((adt->nla_tracks.first) && !(adt->flag & ADT_NLA_EVAL_OFF))
{
+ /* evaluate NLA-stack
+ * - active action is evaluated as part of the NLA stack as the last item
+ */
animsys_evaluate_nla(&id_ptr, adt, ctime);
}
-
- /* evaluate Action data */
- // FIXME: what if the solo track was not tweaking one, then nla-solo should be checked too?
- if (adt->action)
+ /* evaluate Active Action only */
+ else if (adt->action)
animsys_evaluate_action(&id_ptr, adt->action, adt->remap, ctime);
/* reset tag */
@@ -876,10 +1422,22 @@ void BKE_animsys_evaluate_all_animation (Main *main, float ctime)
EVAL_ANIM_IDS(main->camera.first, ADT_RECALC_ANIM);
/* shapekeys */
+ // TODO: we probably need the same hack as for curves (ctime-hack)
EVAL_ANIM_IDS(main->key.first, ADT_RECALC_ANIM);
/* curves */
- // TODO...
+ /* we need to perform a special hack here to ensure that the ctime
+ * value of the curve gets set in case there's no animation for that
+ * - it needs to be set before animation is evaluated just so that
+ * animation can successfully override...
+ */
+ for (id= main->curve.first; id; id= id->next) {
+ AnimData *adt= BKE_animdata_from_id(id);
+ Curve *cu= (Curve *)id;
+
+ cu->ctime= ctime;
+ BKE_animsys_evaluate_animdata(id, adt, ctime, ADT_RECALC_ANIM);
+ }
/* meshes */
// TODO...
diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c
index 1b930a74449..eb8a894e800 100644
--- a/source/blender/blenkernel/intern/armature.c
+++ b/source/blender/blenkernel/intern/armature.c
@@ -66,8 +66,7 @@
#include "BKE_object.h"
#include "BKE_object.h"
#include "BKE_utildefines.h"
-
-//XXX #include "BIF_editdeform.h"
+#include "BKE_sketch.h"
#include "IK_solver.h"
@@ -83,6 +82,7 @@ bArmature *add_armature(char *name)
arm= alloc_libblock (&G.main->armature, ID_AR, name);
arm->deformflag = ARM_DEF_VGROUP|ARM_DEF_ENVELOPE;
+ arm->flag = ARM_COL_CUSTOM; /* custom bone-group colors */
arm->layer= 1;
return arm;
}
@@ -140,6 +140,12 @@ void free_armature(bArmature *arm)
MEM_freeN(arm->edbo);
arm->edbo= NULL;
}
+
+ /* free sketch */
+ if (arm->sketch) {
+ freeSketch(arm->sketch);
+ arm->sketch = NULL;
+ }
}
}
diff --git a/source/blender/blenkernel/intern/blender.c b/source/blender/blenkernel/intern/blender.c
index d3d21018c1c..2728aa30e6e 100644
--- a/source/blender/blenkernel/intern/blender.c
+++ b/source/blender/blenkernel/intern/blender.c
@@ -387,10 +387,6 @@ static void setup_app_data(bContext *C, BlendFileData *bfd, char *filename)
/* now tag update flags, to ensure deformers get calculated on redraw */
DAG_scene_update_flags(CTX_data_scene(C), CTX_data_scene(C)->lay);
- if (G.f & G_DOSCRIPTLINKS) {
- /* there's an onload scriptlink to execute in screenmain */
-// XXX mainqenter(ONLOAD_SCRIPT, 1);
- }
if (G.sce != filename) /* these are the same at times, should never copy to the same location */
strcpy(G.sce, filename);
@@ -692,6 +688,22 @@ void BKE_undo_number(bContext *C, int nr)
BKE_undo_step(C, 0);
}
+/* go back to the last occurance of name in stack */
+void BKE_undo_name(bContext *C, const char *name)
+{
+ UndoElem *uel;
+
+ for(uel= undobase.last; uel; uel= uel->prev) {
+ if(strcmp(name, uel->name)==0)
+ break;
+ }
+ if(uel && uel->prev) {
+ curundo= uel->prev;
+ BKE_undo_step(C, 0);
+ }
+}
+
+
char *BKE_undo_menu_string(void)
{
UndoElem *uel;
diff --git a/source/blender/blenkernel/intern/boids.c b/source/blender/blenkernel/intern/boids.c
new file mode 100644
index 00000000000..d8926fc5753
--- /dev/null
+++ b/source/blender/blenkernel/intern/boids.c
@@ -0,0 +1,1524 @@
+/* boids.c
+ *
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2009 by Janne Karhu.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include <string.h>
+#include <math.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_particle_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_object_force.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_boid_types.h"
+#include "DNA_listBase.h"
+
+#include "BLI_rand.h"
+#include "BLI_arithb.h"
+#include "BLI_blenlib.h"
+#include "BLI_kdtree.h"
+#include "BLI_kdopbvh.h"
+#include "BKE_effect.h"
+#include "BKE_boids.h"
+#include "BKE_particle.h"
+#include "BKE_utildefines.h"
+#include "BKE_modifier.h"
+
+#include "RNA_enum_types.h"
+
+typedef struct BoidValues {
+ float max_speed, max_acc;
+ float max_ave, min_speed;
+ float personal_space, jump_speed;
+} BoidValues;
+
+static int apply_boid_rule(BoidBrainData *bbd, BoidRule *rule, BoidValues *val, ParticleData *pa, float fuzziness);
+
+static int rule_none(BoidRule *rule, BoidBrainData *data, BoidValues *val, ParticleData *pa)
+{
+ return 0;
+}
+
+static int rule_goal_avoid(BoidRule *rule, BoidBrainData *bbd, BoidValues *val, ParticleData *pa)
+{
+ BoidRuleGoalAvoid *gabr = (BoidRuleGoalAvoid*) rule;
+ BoidSettings *boids = bbd->part->boids;
+ ParticleEffectorCache *ec;
+ Object *priority_ob = NULL;
+ float vec[3] = {0.0f, 0.0f, 0.0f}, loc[3] = {0.0f, 0.0f, 0.0f};
+ float mul = (rule->type == eBoidRuleType_Avoid ? 1.0 : -1.0);
+ float priority = 0.0f, len;
+ int ret = 0;
+
+ /* first find out goal/predator with highest priority */
+ /* if rule->ob specified use it */
+ if(gabr->ob && (rule->type != eBoidRuleType_Goal || gabr->ob != pa->stick_ob)) {
+ PartDeflect *pd = gabr->ob->pd;
+ float vec_to_part[3];
+
+ if(pd && pd->forcefield == PFIELD_BOID) {
+ effector_find_co(bbd->scene, pa->prev_state.co, NULL, gabr->ob, pd, loc, vec, NULL, NULL);
+
+ VecSubf(vec_to_part, pa->prev_state.co, loc);
+
+ priority = mul * pd->f_strength * effector_falloff(pd, vec, vec_to_part);
+ }
+ else
+ priority = 1.0;
+
+ priority = 1.0;
+ priority_ob = gabr->ob;
+ }
+ else for(ec=bbd->psys->effectors.first; ec; ec=ec->next) {
+ if(ec->type & PSYS_EC_EFFECTOR) {
+ Object *eob = ec->ob;
+ PartDeflect *pd = eob->pd;
+
+ /* skip current object */
+ if(rule->type == eBoidRuleType_Goal && eob == pa->stick_ob)
+ continue;
+
+ if(pd->forcefield == PFIELD_BOID && mul * pd->f_strength > 0.0f) {
+ float vec_to_part[3], temp;
+
+ effector_find_co(bbd->scene, pa->prev_state.co, NULL, eob, pd, loc, vec, NULL, NULL);
+
+ VecSubf(vec_to_part, pa->prev_state.co, loc);
+
+ temp = mul * pd->f_strength * effector_falloff(pd, vec, vec_to_part);
+
+ if(temp == 0.0f)
+ ; /* do nothing */
+ else if(temp > priority) {
+ priority = temp;
+ priority_ob = eob;
+ len = VecLength(vec_to_part);
+ }
+ /* choose closest object with same priority */
+ else if(temp == priority) {
+ float len2 = VecLength(vec_to_part);
+
+ if(len2 < len) {
+ priority_ob = eob;
+ len = len2;
+ }
+ }
+ }
+ }
+ }
+
+ /* then use that effector */
+ if(priority > (rule->type==eBoidRuleType_Avoid ? gabr->fear_factor : 0.0f)) { /* with avoid, factor is "fear factor" */
+ Object *eob = priority_ob;
+ PartDeflect *pd = eob->pd;
+ float vec_to_part[3];
+ float surface = 0.0f;
+ float nor[3];
+
+ if(gabr->options & BRULE_GOAL_AVOID_PREDICT) {
+ /* estimate future location of target */
+ surface = (float)effector_find_co(bbd->scene, pa->prev_state.co, NULL, eob, pd, loc, nor, vec, NULL);
+
+ VecSubf(vec_to_part, pa->prev_state.co, loc);
+ len = Normalize(vec_to_part);
+
+ VecMulf(vec, len / (val->max_speed * bbd->timestep));
+ VecAddf(loc, loc, vec);
+ VecSubf(vec_to_part, pa->prev_state.co, loc);
+ }
+ else {
+ surface = (float)effector_find_co(bbd->scene, pa->prev_state.co, NULL, eob, pd, loc, nor, NULL, NULL);
+
+ VecSubf(vec_to_part, pa->prev_state.co, loc);
+ len = VecLength(vec_to_part);
+ }
+
+ if(rule->type == eBoidRuleType_Goal && boids->options & BOID_ALLOW_CLIMB && surface!=0.0f) {
+ if(!bbd->goal_ob || bbd->goal_priority < priority) {
+ bbd->goal_ob = eob;
+ VECCOPY(bbd->goal_co, loc);
+ VECCOPY(bbd->goal_nor, nor);
+ }
+ }
+ else if(rule->type == eBoidRuleType_Avoid && pa->boid->mode == eBoidMode_Climbing &&
+ priority > 2.0f * gabr->fear_factor) {
+ /* detach from surface and try to fly away from danger */
+ VECCOPY(vec_to_part, pa->r_ve);
+ VecMulf(vec_to_part, -1.0f);
+ }
+
+ VECCOPY(bbd->wanted_co, vec_to_part);
+ VecMulf(bbd->wanted_co, mul);
+
+ bbd->wanted_speed = val->max_speed * priority;
+
+ /* with goals factor is approach velocity factor */
+ if(rule->type == eBoidRuleType_Goal && boids->landing_smoothness > 0.0f) {
+ float len2 = 2.0f*VecLength(pa->prev_state.vel);
+
+ surface *= pa->size * boids->height;
+
+ if(len2 > 0.0f && len - surface < len2) {
+ len2 = (len - surface)/len2;
+ bbd->wanted_speed *= pow(len2, boids->landing_smoothness);
+ }
+ }
+
+ ret = 1;
+ }
+
+ return ret;
+}
+
+static int rule_avoid_collision(BoidRule *rule, BoidBrainData *bbd, BoidValues *val, ParticleData *pa)
+{
+ BoidRuleAvoidCollision *acbr = (BoidRuleAvoidCollision*) rule;
+ KDTreeNearest *ptn = NULL;
+ ParticleEffectorCache *ec;
+ ParticleTarget *pt;
+ float vec[3] = {0.0f, 0.0f, 0.0f}, loc[3] = {0.0f, 0.0f, 0.0f};
+ float co1[3], vel1[3], co2[3], vel2[3];
+ float len, t, inp, t_min = 2.0f;
+ int n, neighbors = 0, nearest = 0;
+ int ret = 0;
+
+ //check deflector objects first
+ if(acbr->options & BRULE_ACOLL_WITH_DEFLECTORS) {
+ ParticleCollision col;
+ BVHTreeRayHit hit;
+ float radius = val->personal_space * pa->size, ray_dir[3];
+
+ VECCOPY(col.co1, pa->prev_state.co);
+ VecAddf(col.co2, pa->prev_state.co, pa->prev_state.vel);
+ VecSubf(ray_dir, col.co2, col.co1);
+ VecMulf(ray_dir, acbr->look_ahead);
+ col.t = 0.0f;
+ hit.index = -1;
+ hit.dist = col.ray_len = VecLength(ray_dir);
+
+ /* find out closest deflector object */
+ for(ec=bbd->psys->effectors.first; ec; ec=ec->next) {
+ if(ec->type & PSYS_EC_DEFLECT) {
+ Object *eob = ec->ob;
+
+ /* don't check with current ground object */
+ if(eob == pa->stick_ob)
+ continue;
+
+ col.md = ( CollisionModifierData * ) ( modifiers_findByType ( eob, eModifierType_Collision ) );
+ col.ob_t = eob;
+
+ if(col.md && col.md->bvhtree)
+ BLI_bvhtree_ray_cast(col.md->bvhtree, col.co1, ray_dir, radius, &hit, particle_intersect_face, &col);
+ }
+ }
+ /* then avoid that object */
+ if(hit.index>=0) {
+ /* TODO: not totally happy with this part */
+ t = hit.dist/col.ray_len;
+
+ VECCOPY(bbd->wanted_co, col.nor);
+
+ VecMulf(bbd->wanted_co, (1.0f - t) * val->personal_space * pa->size);
+
+ bbd->wanted_speed = sqrt(t) * VecLength(pa->prev_state.vel);
+
+ return 1;
+ }
+ }
+
+ //check boids in own system
+ if(acbr->options & BRULE_ACOLL_WITH_BOIDS)
+ {
+ neighbors = BLI_kdtree_range_search(bbd->psys->tree, acbr->look_ahead * VecLength(pa->prev_state.vel), pa->prev_state.co, pa->prev_state.ave, &ptn);
+ if(neighbors > 1) for(n=1; n<neighbors; n++) {
+ VECCOPY(co1, pa->prev_state.co);
+ VECCOPY(vel1, pa->prev_state.vel);
+ VECCOPY(co2, (bbd->psys->particles + ptn[n].index)->prev_state.co);
+ VECCOPY(vel2, (bbd->psys->particles + ptn[n].index)->prev_state.vel);
+
+ VecSubf(loc, co1, co2);
+
+ VecSubf(vec, vel1, vel2);
+
+ inp = Inpf(vec,vec);
+
+ /* velocities not parallel */
+ if(inp != 0.0f) {
+ t = -Inpf(loc, vec)/inp;
+ /* cpa is not too far in the future so investigate further */
+ if(t > 0.0f && t < t_min) {
+ VECADDFAC(co1, co1, vel1, t);
+ VECADDFAC(co2, co2, vel2, t);
+
+ VecSubf(vec, co2, co1);
+
+ len = Normalize(vec);
+
+ /* distance of cpa is close enough */
+ if(len < 2.0f * val->personal_space * pa->size) {
+ t_min = t;
+
+ VecMulf(vec, VecLength(vel1));
+ VecMulf(vec, (2.0f - t)/2.0f);
+ VecSubf(bbd->wanted_co, vel1, vec);
+ bbd->wanted_speed = VecLength(bbd->wanted_co);
+ ret = 1;
+ }
+ }
+ }
+ }
+ }
+ if(ptn){ MEM_freeN(ptn); ptn=NULL; }
+
+ /* check boids in other systems */
+ for(pt=bbd->psys->targets.first; pt; pt=pt->next) {
+ ParticleSystem *epsys = psys_get_target_system(bbd->ob, pt);
+
+ if(epsys) {
+ neighbors = BLI_kdtree_range_search(epsys->tree, acbr->look_ahead * VecLength(pa->prev_state.vel), pa->prev_state.co, pa->prev_state.ave, &ptn);
+ if(neighbors > 0) for(n=0; n<neighbors; n++) {
+ VECCOPY(co1, pa->prev_state.co);
+ VECCOPY(vel1, pa->prev_state.vel);
+ VECCOPY(co2, (epsys->particles + ptn[n].index)->prev_state.co);
+ VECCOPY(vel2, (epsys->particles + ptn[n].index)->prev_state.vel);
+
+ VecSubf(loc, co1, co2);
+
+ VecSubf(vec, vel1, vel2);
+
+ inp = Inpf(vec,vec);
+
+ /* velocities not parallel */
+ if(inp != 0.0f) {
+ t = -Inpf(loc, vec)/inp;
+ /* cpa is not too far in the future so investigate further */
+ if(t > 0.0f && t < t_min) {
+ VECADDFAC(co1, co1, vel1, t);
+ VECADDFAC(co2, co2, vel2, t);
+
+ VecSubf(vec, co2, co1);
+
+ len = Normalize(vec);
+
+ /* distance of cpa is close enough */
+ if(len < 2.0f * val->personal_space * pa->size) {
+ t_min = t;
+
+ VecMulf(vec, VecLength(vel1));
+ VecMulf(vec, (2.0f - t)/2.0f);
+ VecSubf(bbd->wanted_co, vel1, vec);
+ bbd->wanted_speed = VecLength(bbd->wanted_co);
+ ret = 1;
+ }
+ }
+ }
+ }
+
+ if(ptn){ MEM_freeN(ptn); ptn=NULL; }
+ }
+ }
+
+
+ if(ptn && nearest==0)
+ MEM_freeN(ptn);
+
+ return ret;
+}
+static int rule_separate(BoidRule *rule, BoidBrainData *bbd, BoidValues *val, ParticleData *pa)
+{
+ KDTreeNearest *ptn = NULL;
+ ParticleTarget *pt;
+ float len = 2.0f * val->personal_space * pa->size + 1.0f;
+ float vec[3] = {0.0f, 0.0f, 0.0f};
+ int neighbors = BLI_kdtree_range_search(bbd->psys->tree, 2.0f * val->personal_space * pa->size, pa->prev_state.co, NULL, &ptn);
+ int ret = 0;
+
+ if(neighbors > 1 && ptn[1].dist!=0.0f) {
+ VecSubf(vec, pa->prev_state.co, bbd->psys->particles[ptn[1].index].state.co);
+ VecMulf(vec, (2.0f * val->personal_space * pa->size - ptn[1].dist) / ptn[1].dist);
+ VecAddf(bbd->wanted_co, bbd->wanted_co, vec);
+ bbd->wanted_speed = val->max_speed;
+ len = ptn[1].dist;
+ ret = 1;
+ }
+ if(ptn){ MEM_freeN(ptn); ptn=NULL; }
+
+ /* check other boid systems */
+ for(pt=bbd->psys->targets.first; pt; pt=pt->next) {
+ ParticleSystem *epsys = psys_get_target_system(bbd->ob, pt);
+
+ if(epsys) {
+ neighbors = BLI_kdtree_range_search(epsys->tree, 2.0f * val->personal_space * pa->size, pa->prev_state.co, NULL, &ptn);
+
+ if(neighbors > 0 && ptn[0].dist < len) {
+ VecSubf(vec, pa->prev_state.co, ptn[0].co);
+ VecMulf(vec, (2.0f * val->personal_space * pa->size - ptn[0].dist) / ptn[1].dist);
+ VecAddf(bbd->wanted_co, bbd->wanted_co, vec);
+ bbd->wanted_speed = val->max_speed;
+ len = ptn[0].dist;
+ ret = 1;
+ }
+
+ if(ptn){ MEM_freeN(ptn); ptn=NULL; }
+ }
+ }
+ return ret;
+}
+static int rule_flock(BoidRule *rule, BoidBrainData *bbd, BoidValues *val, ParticleData *pa)
+{
+ KDTreeNearest ptn[11];
+ float vec[3] = {0.0f, 0.0f, 0.0f}, loc[3] = {0.0f, 0.0f, 0.0f};
+ int neighbors = BLI_kdtree_find_n_nearest(bbd->psys->tree, 11, pa->state.co, pa->prev_state.ave, ptn);
+ int n;
+ int ret = 0;
+
+ if(neighbors > 1) {
+ for(n=1; n<neighbors; n++) {
+ VecAddf(loc, loc, bbd->psys->particles[ptn[n].index].prev_state.co);
+ VecAddf(vec, vec, bbd->psys->particles[ptn[n].index].prev_state.vel);
+ }
+
+ VecMulf(loc, 1.0f/((float)neighbors - 1.0f));
+ VecMulf(vec, 1.0f/((float)neighbors - 1.0f));
+
+ VecSubf(loc, loc, pa->prev_state.co);
+ VecSubf(vec, vec, pa->prev_state.vel);
+
+ VecAddf(bbd->wanted_co, bbd->wanted_co, vec);
+ VecAddf(bbd->wanted_co, bbd->wanted_co, loc);
+ bbd->wanted_speed = VecLength(bbd->wanted_co);
+
+ ret = 1;
+ }
+ return ret;
+}
+static int rule_follow_leader(BoidRule *rule, BoidBrainData *bbd, BoidValues *val, ParticleData *pa)
+{
+ BoidRuleFollowLeader *flbr = (BoidRuleFollowLeader*) rule;
+ float vec[3] = {0.0f, 0.0f, 0.0f}, loc[3] = {0.0f, 0.0f, 0.0f};
+ float mul, len;
+ int n = (flbr->queue_size <= 1) ? bbd->psys->totpart : flbr->queue_size;
+ int i, ret = 0, p = pa - bbd->psys->particles;
+
+ if(flbr->ob) {
+ float vec2[3], t;
+
+ /* first check we're not blocking the leader*/
+ VecSubf(vec, flbr->loc, flbr->oloc);
+ VecMulf(vec, 1.0f/bbd->timestep);
+
+ VecSubf(loc, pa->prev_state.co, flbr->oloc);
+
+ mul = Inpf(vec, vec);
+
+ /* leader is not moving */
+ if(mul < 0.01) {
+ len = VecLength(loc);
+ /* too close to leader */
+ if(len < 2.0f * val->personal_space * pa->size) {
+ VECCOPY(bbd->wanted_co, loc);
+ bbd->wanted_speed = val->max_speed;
+ return 1;
+ }
+ }
+ else {
+ t = Inpf(loc, vec)/mul;
+
+ /* possible blocking of leader in near future */
+ if(t > 0.0f && t < 3.0f) {
+ VECCOPY(vec2, vec);
+ VecMulf(vec2, t);
+
+ VecSubf(vec2, loc, vec2);
+
+ len = VecLength(vec2);
+
+ if(len < 2.0f * val->personal_space * pa->size) {
+ VECCOPY(bbd->wanted_co, vec2);
+ bbd->wanted_speed = val->max_speed * (3.0f - t)/3.0f;
+ return 1;
+ }
+ }
+ }
+
+ /* not blocking so try to follow leader */
+ if(p && flbr->options & BRULE_LEADER_IN_LINE) {
+ VECCOPY(vec, bbd->psys->particles[p-1].prev_state.vel);
+ VECCOPY(loc, bbd->psys->particles[p-1].prev_state.co);
+ }
+ else {
+ VECCOPY(loc, flbr->oloc);
+ VecSubf(vec, flbr->loc, flbr->oloc);
+ VecMulf(vec, 1.0/bbd->timestep);
+ }
+
+ /* fac is seconds behind leader */
+ VECADDFAC(loc, loc, vec, -flbr->distance);
+
+ VecSubf(bbd->wanted_co, loc, pa->prev_state.co);
+ bbd->wanted_speed = VecLength(bbd->wanted_co);
+
+ ret = 1;
+ }
+ else if(p % n) {
+ float vec2[3], t, t_min = 3.0f;
+
+ /* first check we're not blocking any leaders */
+ for(i = 0; i< bbd->psys->totpart; i+=n){
+ VECCOPY(vec, bbd->psys->particles[i].prev_state.vel);
+
+ VecSubf(loc, pa->prev_state.co, bbd->psys->particles[i].prev_state.co);
+
+ mul = Inpf(vec, vec);
+
+ /* leader is not moving */
+ if(mul < 0.01) {
+ len = VecLength(loc);
+ /* too close to leader */
+ if(len < 2.0f * val->personal_space * pa->size) {
+ VECCOPY(bbd->wanted_co, loc);
+ bbd->wanted_speed = val->max_speed;
+ return 1;
+ }
+ }
+ else {
+ t = Inpf(loc, vec)/mul;
+
+ /* possible blocking of leader in near future */
+ if(t > 0.0f && t < t_min) {
+ VECCOPY(vec2, vec);
+ VecMulf(vec2, t);
+
+ VecSubf(vec2, loc, vec2);
+
+ len = VecLength(vec2);
+
+ if(len < 2.0f * val->personal_space * pa->size) {
+ t_min = t;
+ VECCOPY(bbd->wanted_co, loc);
+ bbd->wanted_speed = val->max_speed * (3.0f - t)/3.0f;
+ ret = 1;
+ }
+ }
+ }
+ }
+
+ if(ret) return 1;
+
+ /* not blocking so try to follow leader */
+ if(flbr->options & BRULE_LEADER_IN_LINE) {
+ VECCOPY(vec, bbd->psys->particles[p-1].prev_state.vel);
+ VECCOPY(loc, bbd->psys->particles[p-1].prev_state.co);
+ }
+ else {
+ VECCOPY(vec, bbd->psys->particles[p - p%n].prev_state.vel);
+ VECCOPY(loc, bbd->psys->particles[p - p%n].prev_state.co);
+ }
+
+ /* fac is seconds behind leader */
+ VECADDFAC(loc, loc, vec, -flbr->distance);
+
+ VecSubf(bbd->wanted_co, loc, pa->prev_state.co);
+ bbd->wanted_speed = VecLength(bbd->wanted_co);
+
+ ret = 1;
+ }
+
+ return ret;
+}
+static int rule_average_speed(BoidRule *rule, BoidBrainData *bbd, BoidValues *val, ParticleData *pa)
+{
+ BoidRuleAverageSpeed *asbr = (BoidRuleAverageSpeed*)rule;
+ float vec[3] = {0.0f, 0.0f, 0.0f};
+
+ if(asbr->wander > 0.0f) {
+ /* abuse pa->r_ave for wandering */
+ pa->r_ave[0] += asbr->wander * (-1.0f + 2.0f * BLI_frand());
+ pa->r_ave[1] += asbr->wander * (-1.0f + 2.0f * BLI_frand());
+ pa->r_ave[2] += asbr->wander * (-1.0f + 2.0f * BLI_frand());
+
+ Normalize(pa->r_ave);
+
+ VECCOPY(vec, pa->r_ave);
+
+ QuatMulVecf(pa->prev_state.rot, vec);
+
+ VECCOPY(bbd->wanted_co, pa->prev_state.ave);
+
+ VecMulf(bbd->wanted_co, 1.1f);
+
+ VecAddf(bbd->wanted_co, bbd->wanted_co, vec);
+
+ /* leveling */
+ if(asbr->level > 0.0f) {
+ Projf(vec, bbd->wanted_co, bbd->psys->part->acc);
+ VecMulf(vec, asbr->level);
+ VecSubf(bbd->wanted_co, bbd->wanted_co, vec);
+ }
+ }
+ else {
+ VECCOPY(bbd->wanted_co, pa->prev_state.ave);
+
+ /* may happen at birth */
+ if(Inp2f(bbd->wanted_co,bbd->wanted_co)==0.0f) {
+ bbd->wanted_co[0] = 2.0f*(0.5f - BLI_frand());
+ bbd->wanted_co[1] = 2.0f*(0.5f - BLI_frand());
+ bbd->wanted_co[2] = 2.0f*(0.5f - BLI_frand());
+ }
+
+ /* leveling */
+ if(asbr->level > 0.0f) {
+ Projf(vec, bbd->wanted_co, bbd->psys->part->acc);
+ VecMulf(vec, asbr->level);
+ VecSubf(bbd->wanted_co, bbd->wanted_co, vec);
+ }
+
+ }
+ bbd->wanted_speed = asbr->speed * val->max_speed;
+
+ return 1;
+}
+static int rule_fight(BoidRule *rule, BoidBrainData *bbd, BoidValues *val, ParticleData *pa)
+{
+ BoidRuleFight *fbr = (BoidRuleFight*)rule;
+ KDTreeNearest *ptn = NULL;
+ ParticleTarget *pt;
+ ParticleData *epars;
+ ParticleData *enemy_pa;
+ /* friends & enemies */
+ float closest_enemy[3] = {0.0f,0.0f,0.0f};
+ float closest_dist = fbr->distance + 1.0f;
+ float f_strength = 0.0f, e_strength = 0.0f;
+ float health = 0.0f;
+ int n, ret = 0;
+
+ /* calculate own group strength */
+ int neighbors = BLI_kdtree_range_search(bbd->psys->tree, fbr->distance, pa->prev_state.co, NULL, &ptn);
+ for(n=0; n<neighbors; n++)
+ health += bbd->psys->particles[ptn[n].index].boid->health;
+
+ f_strength += bbd->part->boids->strength * health;
+
+ if(ptn){ MEM_freeN(ptn); ptn=NULL; }
+
+ /* add other friendlies and calculate enemy strength and find closest enemy */
+ for(pt=bbd->psys->targets.first; pt; pt=pt->next) {
+ ParticleSystem *epsys = psys_get_target_system(bbd->ob, pt);
+ if(epsys) {
+ epars = epsys->particles;
+
+ neighbors = BLI_kdtree_range_search(epsys->tree, fbr->distance, pa->prev_state.co, NULL, &ptn);
+
+ health = 0.0f;
+
+ for(n=0; n<neighbors; n++) {
+ health += epars[ptn[n].index].boid->health;
+
+ if(n==0 && pt->mode==PTARGET_MODE_ENEMY && ptn[n].dist < closest_dist) {
+ VECCOPY(closest_enemy, ptn[n].co);
+ closest_dist = ptn[n].dist;
+ enemy_pa = epars + ptn[n].index;
+ }
+ }
+ if(pt->mode==PTARGET_MODE_ENEMY)
+ e_strength += epsys->part->boids->strength * health;
+ else if(pt->mode==PTARGET_MODE_FRIEND)
+ f_strength += epsys->part->boids->strength * health;
+
+ if(ptn){ MEM_freeN(ptn); ptn=NULL; }
+ }
+ }
+ /* decide action if enemy presence found */
+ if(e_strength > 0.0f) {
+ VecSubf(bbd->wanted_co, closest_enemy, pa->prev_state.co);
+
+ /* attack if in range */
+ if(closest_dist <= bbd->part->boids->range + pa->size + enemy_pa->size) {
+ float damage = BLI_frand();
+ float enemy_dir[3] = {bbd->wanted_co[0],bbd->wanted_co[1],bbd->wanted_co[2]};
+
+ Normalize(enemy_dir);
+
+ /* fight mode */
+ bbd->wanted_speed = 0.0f;
+
+ /* must face enemy to fight */
+ if(Inpf(pa->prev_state.ave, enemy_dir)>0.5f) {
+ enemy_pa->boid->health -= bbd->part->boids->strength * bbd->timestep * ((1.0f-bbd->part->boids->accuracy)*damage + bbd->part->boids->accuracy);
+ }
+ }
+ else {
+ /* approach mode */
+ bbd->wanted_speed = val->max_speed;
+ }
+
+ /* check if boid doesn't want to fight */
+ if(pa->boid->health/bbd->part->boids->health * bbd->part->boids->aggression < e_strength / f_strength) {
+ /* decide to flee */
+ if(closest_dist < fbr->flee_distance * fbr->distance) {
+ VecMulf(bbd->wanted_co, -1.0f);
+ bbd->wanted_speed = val->max_speed;
+ }
+ else { /* wait for better odds */
+ bbd->wanted_speed = 0.0f;
+ }
+ }
+
+ ret = 1;
+ }
+
+ return ret;
+}
+
+typedef int (*boid_rule_cb)(BoidRule *rule, BoidBrainData *data, BoidValues *val, ParticleData *pa);
+
+static boid_rule_cb boid_rules[] = {
+ rule_none,
+ rule_goal_avoid,
+ rule_goal_avoid,
+ rule_avoid_collision,
+ rule_separate,
+ rule_flock,
+ rule_follow_leader,
+ rule_average_speed,
+ rule_fight,
+ //rule_help,
+ //rule_protect,
+ //rule_hide,
+ //rule_follow_path,
+ //rule_follow_wall
+};
+
+static void set_boid_values(BoidValues *val, BoidSettings *boids, ParticleData *pa)
+{
+ if(ELEM(pa->boid->mode, eBoidMode_OnLand, eBoidMode_Climbing)) {
+ val->max_speed = boids->land_max_speed * pa->boid->health/boids->health;
+ val->max_acc = boids->land_max_acc * val->max_speed;
+ val->max_ave = boids->land_max_ave * M_PI * pa->boid->health/boids->health;
+ val->min_speed = 0.0f; /* no minimum speed on land */
+ val->personal_space = boids->land_personal_space;
+ val->jump_speed = boids->land_jump_speed * pa->boid->health/boids->health;
+ }
+ else {
+ val->max_speed = boids->air_max_speed * pa->boid->health/boids->health;
+ val->max_acc = boids->air_max_acc * val->max_speed;
+ val->max_ave = boids->air_max_ave * M_PI * pa->boid->health/boids->health;
+ val->min_speed = boids->air_min_speed * boids->air_max_speed;
+ val->personal_space = boids->air_personal_space;
+ val->jump_speed = 0.0f; /* no jumping in air */
+ }
+}
+static Object *boid_find_ground(BoidBrainData *bbd, ParticleData *pa, float *ground_co, float *ground_nor)
+{
+ if(pa->boid->mode == eBoidMode_Climbing) {
+ SurfaceModifierData *surmd = NULL;
+ float x[3], v[3];
+
+ surmd = (SurfaceModifierData *)modifiers_findByType ( pa->stick_ob, eModifierType_Surface );
+
+ /* take surface velocity into account */
+ effector_find_co(bbd->scene, pa->state.co, surmd, NULL, NULL, x, NULL, v, NULL);
+ VecAddf(x, x, v);
+
+ /* get actual position on surface */
+ effector_find_co(bbd->scene, x, surmd, NULL, NULL, ground_co, ground_nor, NULL, NULL);
+
+ return pa->stick_ob;
+ }
+ else {
+ float zvec[3] = {0.0f, 0.0f, 2000.0f};
+ ParticleCollision col;
+ BVHTreeRayHit hit;
+ ParticleEffectorCache *ec;
+ float radius = 0.0f, t, ray_dir[3];
+
+ VECCOPY(col.co1, pa->state.co);
+ VECCOPY(col.co2, pa->state.co);
+ VecAddf(col.co1, col.co1, zvec);
+ VecSubf(col.co2, col.co2, zvec);
+ VecSubf(ray_dir, col.co2, col.co1);
+ col.t = 0.0f;
+ hit.index = -1;
+ hit.dist = col.ray_len = VecLength(ray_dir);
+
+ /* find out upmost deflector object */
+ for(ec=bbd->psys->effectors.first; ec; ec=ec->next) {
+ if(ec->type & PSYS_EC_DEFLECT) {
+ Object *eob = ec->ob;
+
+ col.md = ( CollisionModifierData * ) ( modifiers_findByType ( eob, eModifierType_Collision ) );
+ col.ob_t = eob;
+
+ if(col.md && col.md->bvhtree)
+ BLI_bvhtree_ray_cast(col.md->bvhtree, col.co1, ray_dir, radius, &hit, particle_intersect_face, &col);
+ }
+ }
+ /* then use that object */
+ if(hit.index>=0) {
+ t = hit.dist/col.ray_len;
+ VecLerpf(ground_co, col.co1, col.co2, t);
+ VECCOPY(ground_nor, col.nor);
+ Normalize(ground_nor);
+ return col.ob;
+ }
+ else {
+ /* default to z=0 */
+ VECCOPY(ground_co, pa->state.co);
+ ground_co[2] = 0;
+ ground_nor[0] = ground_nor[1] = 0.0f;
+ ground_nor[2] = 1.0f;
+ return NULL;
+ }
+ }
+}
+static int boid_rule_applies(ParticleData *pa, BoidSettings *boids, BoidRule *rule)
+{
+ if(rule==NULL)
+ return 0;
+
+ if(ELEM(pa->boid->mode, eBoidMode_OnLand, eBoidMode_Climbing) && rule->flag & BOIDRULE_ON_LAND)
+ return 1;
+
+ if(pa->boid->mode==eBoidMode_InAir && rule->flag & BOIDRULE_IN_AIR)
+ return 1;
+
+ return 0;
+}
+void boids_precalc_rules(ParticleSettings *part, float cfra)
+{
+ BoidState *state = part->boids->states.first;
+ BoidRule *rule;
+ for(; state; state=state->next) {
+ for(rule = state->rules.first; rule; rule=rule->next) {
+ if(rule->type==eBoidRuleType_FollowLeader) {
+ BoidRuleFollowLeader *flbr = (BoidRuleFollowLeader*) rule;
+
+ if(flbr->ob && flbr->cfra != cfra) {
+ /* save object locations for velocity calculations */
+ VECCOPY(flbr->oloc, flbr->loc);
+ VECCOPY(flbr->loc, flbr->ob->obmat[3]);
+ flbr->cfra = cfra;
+ }
+ }
+ }
+ }
+}
+static void boid_climb(BoidSettings *boids, ParticleData *pa, float *surface_co, float *surface_nor)
+{
+ float nor[3], vel[3];
+ VECCOPY(nor, surface_nor);
+
+ /* gather apparent gravity to r_ve */
+ VECADDFAC(pa->r_ve, pa->r_ve, surface_nor, -1.0);
+ Normalize(pa->r_ve);
+
+ /* raise boid it's size from surface */
+ VecMulf(nor, pa->size * boids->height);
+ VecAddf(pa->state.co, surface_co, nor);
+
+ /* remove normal component from velocity */
+ Projf(vel, pa->state.vel, surface_nor);
+ VecSubf(pa->state.vel, pa->state.vel, vel);
+}
+static float boid_goal_signed_dist(float *boid_co, float *goal_co, float *goal_nor)
+{
+ float vec[3];
+
+ VecSubf(vec, boid_co, goal_co);
+
+ return Inpf(vec, goal_nor);
+}
+/* wanted_co is relative to boid location */
+static int apply_boid_rule(BoidBrainData *bbd, BoidRule *rule, BoidValues *val, ParticleData *pa, float fuzziness)
+{
+ if(rule==NULL)
+ return 0;
+
+ if(boid_rule_applies(pa, bbd->part->boids, rule)==0)
+ return 0;
+
+ if(boid_rules[rule->type](rule, bbd, val, pa)==0)
+ return 0;
+
+ if(fuzziness < 0.0f || VecLenCompare(bbd->wanted_co, pa->prev_state.vel, fuzziness * VecLength(pa->prev_state.vel))==0)
+ return 1;
+ else
+ return 0;
+}
+static BoidState *get_boid_state(BoidSettings *boids, ParticleData *pa) {
+ BoidState *state = boids->states.first;
+
+ for(; state; state=state->next) {
+ if(state->id==pa->boid->state_id)
+ return state;
+ }
+
+ /* for some reason particle isn't at a valid state */
+ state = boids->states.first;
+ if(state)
+ pa->boid->state_id = state->id;
+
+ return state;
+}
+//static int boid_condition_is_true(BoidCondition *cond) {
+// /* TODO */
+// return 0;
+//}
+
+/* determines the velocity the boid wants to have */
+void boid_brain(BoidBrainData *bbd, int p, ParticleData *pa)
+{
+ BoidRule *rule;
+ BoidSettings *boids = bbd->part->boids;
+ BoidValues val;
+ BoidState *state = get_boid_state(boids, pa);
+ //BoidCondition *cond;
+
+ if(pa->boid->health <= 0.0f) {
+ pa->alive = PARS_DYING;
+ return;
+ }
+
+ //planned for near future
+ //cond = state->conditions.first;
+ //for(; cond; cond=cond->next) {
+ // if(boid_condition_is_true(cond)) {
+ // pa->boid->state_id = cond->state_id;
+ // state = get_boid_state(boids, pa);
+ // break; /* only first true condition is used */
+ // }
+ //}
+
+ bbd->wanted_co[0]=bbd->wanted_co[1]=bbd->wanted_co[2]=bbd->wanted_speed=0.0f;
+
+ /* create random seed for every particle & frame */
+ BLI_srandom(bbd->psys->seed + p + (int)bbd->cfra + (int)(1000*pa->r_rot[0]));
+
+ set_boid_values(&val, bbd->part->boids, pa);
+
+ /* go through rules */
+ switch(state->ruleset_type) {
+ case eBoidRulesetType_Fuzzy:
+ {
+ for(rule = state->rules.first; rule; rule = rule->next) {
+ if(apply_boid_rule(bbd, rule, &val, pa, state->rule_fuzziness))
+ break; /* only first nonzero rule that comes through fuzzy rule is applied */
+ }
+ break;
+ }
+ case eBoidRulesetType_Random:
+ {
+ /* use random rule for each particle (allways same for same particle though) */
+ rule = BLI_findlink(&state->rules, (int)(1000.0f * pa->r_rot[1]) % BLI_countlist(&state->rules));
+
+ apply_boid_rule(bbd, rule, &val, pa, -1.0);
+ }
+ case eBoidRulesetType_Average:
+ {
+ float wanted_co[3] = {0.0f, 0.0f, 0.0f}, wanted_speed = 0.0f;
+ int n = 0;
+ for(rule = state->rules.first; rule; rule=rule->next) {
+ if(apply_boid_rule(bbd, rule, &val, pa, -1.0f)) {
+ VecAddf(wanted_co, wanted_co, bbd->wanted_co);
+ wanted_speed += bbd->wanted_speed;
+ n++;
+ bbd->wanted_co[0]=bbd->wanted_co[1]=bbd->wanted_co[2]=bbd->wanted_speed=0.0f;
+ }
+ }
+
+ if(n > 1) {
+ VecMulf(wanted_co, 1.0f/(float)n);
+ wanted_speed /= (float)n;
+ }
+
+ VECCOPY(bbd->wanted_co, wanted_co);
+ bbd->wanted_speed = wanted_speed;
+ break;
+ }
+
+ }
+
+ /* decide on jumping & liftoff */
+ if(pa->boid->mode == eBoidMode_OnLand) {
+ /* fuzziness makes boids capable of misjudgement */
+ float mul = 1.0 + state->rule_fuzziness;
+
+ if(boids->options & BOID_ALLOW_FLIGHT && bbd->wanted_co[2] > 0.0f) {
+ float cvel[3], dir[3];
+
+ VECCOPY(dir, pa->prev_state.ave);
+ Normalize2(dir);
+
+ VECCOPY(cvel, bbd->wanted_co);
+ Normalize2(cvel);
+
+ if(Inp2f(cvel, dir) > 0.95 / mul)
+ pa->boid->mode = eBoidMode_Liftoff;
+ }
+ else if(val.jump_speed > 0.0f) {
+ float jump_v[3];
+ int jump = 0;
+
+ /* jump to get to a location */
+ if(bbd->wanted_co[2] > 0.0f) {
+ float cvel[3], dir[3];
+ float z_v, ground_v, cur_v;
+ float len;
+
+ VECCOPY(dir, pa->prev_state.ave);
+ Normalize2(dir);
+
+ VECCOPY(cvel, bbd->wanted_co);
+ Normalize2(cvel);
+
+ len = Vec2Length(pa->prev_state.vel);
+
+ /* first of all, are we going in a suitable direction? */
+ /* or at a suitably slow speed */
+ if(Inp2f(cvel, dir) > 0.95f / mul || len <= state->rule_fuzziness) {
+ /* try to reach goal at highest point of the parabolic path */
+ cur_v = Vec2Length(pa->prev_state.vel);
+ z_v = sasqrt(-2.0f * bbd->part->acc[2] * bbd->wanted_co[2]);
+ ground_v = Vec2Length(bbd->wanted_co)*sasqrt(-0.5f * bbd->part->acc[2] / bbd->wanted_co[2]);
+
+ len = sasqrt((ground_v-cur_v)*(ground_v-cur_v) + z_v*z_v);
+
+ if(len < val.jump_speed * mul || bbd->part->boids->options & BOID_ALLOW_FLIGHT) {
+ jump = 1;
+
+ len = MIN2(len, val.jump_speed);
+
+ VECCOPY(jump_v, dir);
+ jump_v[2] = z_v;
+ VecMulf(jump_v, ground_v);
+
+ Normalize(jump_v);
+ VecMulf(jump_v, len);
+ Vec2Addf(jump_v, jump_v, pa->prev_state.vel);
+ }
+ }
+ }
+
+ /* jump to go faster */
+ if(jump == 0 && val.jump_speed > val.max_speed && bbd->wanted_speed > val.max_speed) {
+
+ }
+
+ if(jump) {
+ VECCOPY(pa->prev_state.vel, jump_v);
+ pa->boid->mode = eBoidMode_Falling;
+ }
+ }
+ }
+}
+/* tries to realize the wanted velocity taking all constraints into account */
+void boid_body(BoidBrainData *bbd, ParticleData *pa)
+{
+ BoidSettings *boids = bbd->part->boids;
+ BoidValues val;
+ float acc[3] = {0.0f, 0.0f, 0.0f}, tan_acc[3], nor_acc[3];
+ float dvec[3], bvec[3];
+ float new_dir[3], new_speed;
+ float old_dir[3], old_speed;
+ float wanted_dir[3];
+ float q[4], mat[3][3]; /* rotation */
+ float ground_co[3] = {0.0f, 0.0f, 0.0f}, ground_nor[3] = {0.0f, 0.0f, 1.0f};
+ float force[3] = {0.0f, 0.0f, 0.0f}, tvel[3] = {0.0f, 0.0f, 1.0f};
+ float pa_mass=bbd->part->mass, dtime=bbd->dfra*bbd->timestep;
+ int p = pa - bbd->psys->particles;
+
+ set_boid_values(&val, boids, pa);
+
+ /* make sure there's something in new velocity, location & rotation */
+ copy_particle_key(&pa->state,&pa->prev_state,0);
+
+ if(bbd->part->flag & PART_SIZEMASS)
+ pa_mass*=pa->size;
+
+ /* if boids can't fly they fall to the ground */
+ if((boids->options & BOID_ALLOW_FLIGHT)==0 && ELEM(pa->boid->mode, eBoidMode_OnLand, eBoidMode_Climbing)==0 && bbd->part->acc[2] != 0.0f)
+ pa->boid->mode = eBoidMode_Falling;
+
+ if(pa->boid->mode == eBoidMode_Falling) {
+ /* Falling boids are only effected by gravity. */
+ acc[2] = bbd->part->acc[2];
+ }
+ else {
+ /* figure out acceleration */
+ float landing_level = 2.0f;
+ float level = landing_level + 1.0f;
+ float new_vel[3];
+
+ if(pa->boid->mode == eBoidMode_Liftoff) {
+ pa->boid->mode = eBoidMode_InAir;
+ pa->stick_ob = boid_find_ground(bbd, pa, ground_co, ground_nor);
+ }
+ else if(pa->boid->mode == eBoidMode_InAir && boids->options & BOID_ALLOW_LAND) {
+ /* auto-leveling & landing if close to ground */
+
+ pa->stick_ob = boid_find_ground(bbd, pa, ground_co, ground_nor);
+
+ /* level = how many particle sizes above ground */
+ level = (pa->prev_state.co[2] - ground_co[2])/(2.0f * pa->size) - 0.5;
+
+ landing_level = - boids->landing_smoothness * pa->prev_state.vel[2] * pa_mass;
+
+ if(pa->prev_state.vel[2] < 0.0f) {
+ if(level < 1.0f) {
+ bbd->wanted_co[0] = bbd->wanted_co[1] = bbd->wanted_co[2] = 0.0f;
+ bbd->wanted_speed = 0.0f;
+ pa->boid->mode = eBoidMode_Falling;
+ }
+ else if(level < landing_level) {
+ bbd->wanted_speed *= (level - 1.0f)/landing_level;
+ bbd->wanted_co[2] *= (level - 1.0f)/landing_level;
+ }
+ }
+ }
+
+ VECCOPY(old_dir, pa->prev_state.ave);
+ VECCOPY(wanted_dir, bbd->wanted_co);
+ new_speed = Normalize(wanted_dir);
+
+ /* first check if we have valid direction we want to go towards */
+ if(new_speed == 0.0f) {
+ VECCOPY(new_dir, old_dir);
+ }
+ else {
+ float old_dir2[2], wanted_dir2[2], nor[3], angle;
+ Vec2Copyf(old_dir2, old_dir);
+ Normalize2(old_dir2);
+ Vec2Copyf(wanted_dir2, wanted_dir);
+ Normalize2(wanted_dir2);
+
+ /* choose random direction to turn if wanted velocity */
+ /* is directly behind regardless of z-coordinate */
+ if(Inp2f(old_dir2, wanted_dir2) < -0.99f) {
+ wanted_dir[0] = 2.0f*(0.5f - BLI_frand());
+ wanted_dir[1] = 2.0f*(0.5f - BLI_frand());
+ wanted_dir[2] = 2.0f*(0.5f - BLI_frand());
+ Normalize(wanted_dir);
+ }
+
+ /* constrain direction with maximum angular velocity */
+ angle = saacos(Inpf(old_dir, wanted_dir));
+ angle = MIN2(angle, val.max_ave);
+
+ Crossf(nor, old_dir, wanted_dir);
+ VecRotToQuat(nor, angle, q);
+ VECCOPY(new_dir, old_dir);
+ QuatMulVecf(q, new_dir);
+ Normalize(new_dir);
+
+ /* save direction in case resulting velocity too small */
+ VecRotToQuat(nor, angle*dtime, q);
+ VECCOPY(pa->state.ave, old_dir);
+ QuatMulVecf(q, pa->state.ave);
+ Normalize(pa->state.ave);
+ }
+
+ /* constrain speed with maximum acceleration */
+ old_speed = VecLength(pa->prev_state.vel);
+
+ if(bbd->wanted_speed < old_speed)
+ new_speed = MAX2(bbd->wanted_speed, old_speed - val.max_acc);
+ else
+ new_speed = MIN2(bbd->wanted_speed, old_speed + val.max_acc);
+
+ /* combine direction and speed */
+ VECCOPY(new_vel, new_dir);
+ VecMulf(new_vel, new_speed);
+
+ /* maintain minimum flying velocity if not landing */
+ if(level >= landing_level) {
+ float len2 = Inp2f(new_vel,new_vel);
+ float root;
+
+ len2 = MAX2(len2, val.min_speed*val.min_speed);
+ root = sasqrt(new_speed*new_speed - len2);
+
+ new_vel[2] = new_vel[2] < 0.0f ? -root : root;
+
+ Normalize2(new_vel);
+ Vec2Mulf(new_vel, sasqrt(len2));
+ }
+
+ /* finally constrain speed to max speed */
+ new_speed = Normalize(new_vel);
+ VecMulf(new_vel, MIN2(new_speed, val.max_speed));
+
+ /* get acceleration from difference of velocities */
+ VecSubf(acc, new_vel, pa->prev_state.vel);
+
+ /* break acceleration to components */
+ Projf(tan_acc, acc, pa->prev_state.ave);
+ VecSubf(nor_acc, acc, tan_acc);
+ }
+
+ /* account for effectors */
+ do_effectors(p, pa, &pa->state, bbd->scene, bbd->ob, bbd->psys, pa->state.co, force, tvel, bbd->dfra, bbd->cfra);
+
+ if(ELEM(pa->boid->mode, eBoidMode_OnLand, eBoidMode_Climbing)) {
+ float length = Normalize(force);
+
+ length = MAX2(0.0f, length - boids->land_stick_force);
+
+ VecMulf(force, length);
+ }
+
+ VecAddf(acc, acc, force);
+
+ /* store smoothed acceleration for nice banking etc. */
+ VECADDFAC(pa->boid->acc, pa->boid->acc, acc, dtime);
+ VecMulf(pa->boid->acc, 1.0f / (1.0f + dtime));
+
+ /* integrate new location & velocity */
+
+ /* by regarding the acceleration as a force at this stage we*/
+ /* can get better control allthough it's a bit unphysical */
+ VecMulf(acc, 1.0f/pa_mass);
+
+ VECCOPY(dvec, acc);
+ VecMulf(dvec, dtime*dtime*0.5f);
+
+ VECCOPY(bvec, pa->prev_state.vel);
+ VecMulf(bvec, dtime);
+ VecAddf(dvec, dvec, bvec);
+ VecAddf(pa->state.co, pa->state.co, dvec);
+
+ VECADDFAC(pa->state.vel, pa->state.vel, acc, dtime);
+
+ if(pa->boid->mode != eBoidMode_InAir)
+ pa->stick_ob = boid_find_ground(bbd, pa, ground_co, ground_nor);
+
+ /* change modes, constrain movement & keep track of down vector */
+ switch(pa->boid->mode) {
+ case eBoidMode_InAir:
+ {
+ float grav[3] = {0.0f, 0.0f, bbd->part->acc[2] < 0.0f ? -1.0f : 0.0f};
+
+ /* don't take forward acceleration into account (better banking) */
+ if(Inpf(pa->boid->acc, pa->state.vel) > 0.0f) {
+ Projf(dvec, pa->boid->acc, pa->state.vel);
+ VecSubf(dvec, pa->boid->acc, dvec);
+ }
+ else {
+ VECCOPY(dvec, pa->boid->acc);
+ }
+
+ /* gather apparent gravity to r_ve */
+ VECADDFAC(pa->r_ve, grav, dvec, -boids->banking);
+ Normalize(pa->r_ve);
+
+ /* stick boid on goal when close enough */
+ if(bbd->goal_ob && boid_goal_signed_dist(pa->state.co, bbd->goal_co, bbd->goal_nor) <= pa->size * boids->height) {
+ pa->boid->mode = eBoidMode_Climbing;
+ pa->stick_ob = bbd->goal_ob;
+ boid_find_ground(bbd, pa, ground_co, ground_nor);
+ boid_climb(boids, pa, ground_co, ground_nor);
+ }
+ /* land boid when belowg ground */
+ else if(boids->options & BOID_ALLOW_LAND && pa->state.co[2] <= ground_co[2] + pa->size * boids->height) {
+ pa->state.co[2] = ground_co[2] + pa->size * boids->height;
+ pa->state.vel[2] = 0.0f;
+ pa->boid->mode = eBoidMode_OnLand;
+ }
+ break;
+ }
+ case eBoidMode_Falling:
+ {
+ float grav[3] = {0.0f, 0.0f, bbd->part->acc[2] < 0.0f ? -1.0f : 0.0f};
+
+ /* gather apparent gravity to r_ve */
+ VECADDFAC(pa->r_ve, pa->r_ve, grav, dtime);
+ Normalize(pa->r_ve);
+
+ if(boids->options & BOID_ALLOW_LAND) {
+ /* stick boid on goal when close enough */
+ if(bbd->goal_ob && boid_goal_signed_dist(pa->state.co, bbd->goal_co, bbd->goal_nor) <= pa->size * boids->height) {
+ pa->boid->mode = eBoidMode_Climbing;
+ pa->stick_ob = bbd->goal_ob;
+ boid_find_ground(bbd, pa, ground_co, ground_nor);
+ boid_climb(boids, pa, ground_co, ground_nor);
+ }
+ /* land boid when really near ground */
+ else if(pa->state.co[2] <= ground_co[2] + 1.01 * pa->size * boids->height){
+ pa->state.co[2] = ground_co[2] + pa->size * boids->height;
+ pa->state.vel[2] = 0.0f;
+ pa->boid->mode = eBoidMode_OnLand;
+ }
+ /* if we're falling, can fly and want to go upwards lets fly */
+ else if(boids->options & BOID_ALLOW_FLIGHT && bbd->wanted_co[2] > 0.0f)
+ pa->boid->mode = eBoidMode_InAir;
+ }
+ else
+ pa->boid->mode = eBoidMode_InAir;
+ break;
+ }
+ case eBoidMode_Climbing:
+ {
+ boid_climb(boids, pa, ground_co, ground_nor);
+ //float nor[3];
+ //VECCOPY(nor, ground_nor);
+
+ ///* gather apparent gravity to r_ve */
+ //VECADDFAC(pa->r_ve, pa->r_ve, ground_nor, -1.0);
+ //Normalize(pa->r_ve);
+
+ ///* raise boid it's size from surface */
+ //VecMulf(nor, pa->size * boids->height);
+ //VecAddf(pa->state.co, ground_co, nor);
+
+ ///* remove normal component from velocity */
+ //Projf(v, pa->state.vel, ground_nor);
+ //VecSubf(pa->state.vel, pa->state.vel, v);
+ break;
+ }
+ case eBoidMode_OnLand:
+ {
+ /* stick boid on goal when close enough */
+ if(bbd->goal_ob && boid_goal_signed_dist(pa->state.co, bbd->goal_co, bbd->goal_nor) <= pa->size * boids->height) {
+ pa->boid->mode = eBoidMode_Climbing;
+ pa->stick_ob = bbd->goal_ob;
+ boid_find_ground(bbd, pa, ground_co, ground_nor);
+ boid_climb(boids, pa, ground_co, ground_nor);
+ }
+ /* ground is too far away so boid falls */
+ else if(pa->state.co[2]-ground_co[2] > 1.1 * pa->size * boids->height)
+ pa->boid->mode = eBoidMode_Falling;
+ else {
+ /* constrain to surface */
+ pa->state.co[2] = ground_co[2] + pa->size * boids->height;
+ pa->state.vel[2] = 0.0f;
+ }
+
+ if(boids->banking > 0.0f) {
+ float grav[3];
+ /* Don't take gravity's strength in to account, */
+ /* otherwise amount of banking is hard to control. */
+ VECCOPY(grav, ground_nor);
+ VecMulf(grav, -1.0f);
+
+ Projf(dvec, pa->boid->acc, pa->state.vel);
+ VecSubf(dvec, pa->boid->acc, dvec);
+
+ /* gather apparent gravity to r_ve */
+ VECADDFAC(pa->r_ve, grav, dvec, -boids->banking);
+ Normalize(pa->r_ve);
+ }
+ else {
+ /* gather negative surface normal to r_ve */
+ VECADDFAC(pa->r_ve, pa->r_ve, ground_nor, -1.0f);
+ Normalize(pa->r_ve);
+ }
+ break;
+ }
+ }
+
+ /* save direction to state.ave unless the boid is falling */
+ /* (boids can't effect their direction when falling) */
+ if(pa->boid->mode!=eBoidMode_Falling && VecLength(pa->state.vel) > 0.1*pa->size) {
+ VECCOPY(pa->state.ave, pa->state.vel);
+ Normalize(pa->state.ave);
+ }
+
+ /* apply damping */
+ if(ELEM(pa->boid->mode, eBoidMode_OnLand, eBoidMode_Climbing))
+ VecMulf(pa->state.vel, 1.0f - 0.2f*bbd->part->dampfac);
+
+ /* calculate rotation matrix based on forward & down vectors */
+ if(pa->boid->mode == eBoidMode_InAir) {
+ VECCOPY(mat[0], pa->state.ave);
+
+ Projf(dvec, pa->r_ve, pa->state.ave);
+ VecSubf(mat[2], pa->r_ve, dvec);
+ Normalize(mat[2]);
+ }
+ else {
+ Projf(dvec, pa->state.ave, pa->r_ve);
+ VecSubf(mat[0], pa->state.ave, dvec);
+ Normalize(mat[0]);
+
+ VECCOPY(mat[2], pa->r_ve);
+ }
+ VecMulf(mat[2], -1.0f);
+ Crossf(mat[1], mat[2], mat[0]);
+
+ /* apply rotation */
+ Mat3ToQuat_is_ok(mat, q);
+ QuatCopy(pa->state.rot, q);
+}
+
+BoidRule *boid_new_rule(int type)
+{
+ BoidRule *rule = NULL;
+ if(type <= 0)
+ return NULL;
+
+ switch(type) {
+ case eBoidRuleType_Goal:
+ case eBoidRuleType_Avoid:
+ rule = MEM_callocN(sizeof(BoidRuleGoalAvoid), "BoidRuleGoalAvoid");
+ break;
+ case eBoidRuleType_AvoidCollision:
+ rule = MEM_callocN(sizeof(BoidRuleAvoidCollision), "BoidRuleAvoidCollision");
+ ((BoidRuleAvoidCollision*)rule)->look_ahead = 2.0f;
+ break;
+ case eBoidRuleType_FollowLeader:
+ rule = MEM_callocN(sizeof(BoidRuleFollowLeader), "BoidRuleFollowLeader");
+ ((BoidRuleFollowLeader*)rule)->distance = 1.0f;
+ break;
+ case eBoidRuleType_AverageSpeed:
+ rule = MEM_callocN(sizeof(BoidRuleAverageSpeed), "BoidRuleAverageSpeed");
+ ((BoidRuleAverageSpeed*)rule)->speed = 0.5f;
+ break;
+ case eBoidRuleType_Fight:
+ rule = MEM_callocN(sizeof(BoidRuleFight), "BoidRuleFight");
+ ((BoidRuleFight*)rule)->distance = 100.0f;
+ ((BoidRuleFight*)rule)->flee_distance = 100.0f;
+ break;
+ default:
+ rule = MEM_callocN(sizeof(BoidRule), "BoidRule");
+ break;
+ }
+
+ rule->type = type;
+ rule->flag |= BOIDRULE_IN_AIR|BOIDRULE_ON_LAND;
+ strcpy(rule->name, boidrule_type_items[type-1].name);
+
+ return rule;
+}
+void boid_default_settings(BoidSettings *boids)
+{
+ boids->air_max_speed = 10.0f;
+ boids->air_max_acc = 0.5f;
+ boids->air_max_ave = 0.5f;
+ boids->air_personal_space = 1.0f;
+
+ boids->land_max_speed = 5.0f;
+ boids->land_max_acc = 0.5f;
+ boids->land_max_ave = 0.5f;
+ boids->land_personal_space = 1.0f;
+
+ boids->options = BOID_ALLOW_FLIGHT;
+
+ boids->landing_smoothness = 3.0f;
+ boids->banking = 1.0f;
+ boids->height = 1.0f;
+
+ boids->health = 1.0f;
+ boids->accuracy = 1.0f;
+ boids->aggression = 2.0f;
+ boids->range = 1.0f;
+ boids->strength = 0.1f;
+}
+
+BoidState *boid_new_state(BoidSettings *boids)
+{
+ BoidState *state = MEM_callocN(sizeof(BoidState), "BoidState");
+
+ state->id = boids->last_state_id++;
+ if(state->id)
+ sprintf(state->name, "State %i", state->id);
+ else
+ strcpy(state->name, "State");
+
+ state->rule_fuzziness = 0.5;
+ state->volume = 1.0f;
+ state->channels |= ~0;
+
+ return state;
+}
+
+BoidState *boid_duplicate_state(BoidSettings *boids, BoidState *state) {
+ BoidState *staten = MEM_dupallocN(state);
+
+ BLI_duplicatelist(&staten->rules, &state->rules);
+ BLI_duplicatelist(&staten->conditions, &state->conditions);
+ BLI_duplicatelist(&staten->actions, &state->actions);
+
+ staten->id = boids->last_state_id++;
+
+ return staten;
+}
+void boid_free_settings(BoidSettings *boids)
+{
+ if(boids) {
+ BoidState *state = boids->states.first;
+
+ for(; state; state=state->next) {
+ BLI_freelistN(&state->rules);
+ BLI_freelistN(&state->conditions);
+ BLI_freelistN(&state->actions);
+ }
+
+ BLI_freelistN(&boids->states);
+
+ MEM_freeN(boids);
+ }
+}
+BoidSettings *boid_copy_settings(BoidSettings *boids)
+{
+ BoidSettings *nboids = NULL;
+
+ if(boids) {
+ BoidState *state;
+ BoidState *nstate;
+
+ nboids = MEM_dupallocN(boids);
+
+ BLI_duplicatelist(&nboids->states, &boids->states);
+
+ state = boids->states.first;
+ nstate = nboids->states.first;
+ for(; state; state=state->next, nstate=nstate->next) {
+ BLI_duplicatelist(&nstate->rules, &state->rules);
+ BLI_duplicatelist(&nstate->conditions, &state->conditions);
+ BLI_duplicatelist(&nstate->actions, &state->actions);
+ }
+ }
+
+ return nboids;
+}
+BoidState *boid_get_current_state(BoidSettings *boids)
+{
+ BoidState *state = boids->states.first;
+
+ for(; state; state=state->next) {
+ if(state->flag & BOIDSTATE_CURRENT)
+ break;
+ }
+
+ return state;
+}
+
diff --git a/source/blender/blenkernel/intern/colortools.c b/source/blender/blenkernel/intern/colortools.c
index e8716aba296..2280ec71f7a 100644
--- a/source/blender/blenkernel/intern/colortools.c
+++ b/source/blender/blenkernel/intern/colortools.c
@@ -58,6 +58,91 @@
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
+/* ********************************* color transforms ********************************* */
+
+/*Transform linear RGB values to nonlinear RGB values. Rec.
+ 709 is ITU-R Recommendation BT. 709 (1990) ``Basic
+ Parameter Values for the HDTV Standard for the Studio and
+ for International Programme Exchange'', formerly CCIR Rec.
+ 709.*/
+void gamma_correct_rec709(float *c, float gamma)
+{
+ /* Rec. 709 gamma correction. */
+ float cc = 0.018f;
+
+ if (*c < cc)
+ *c *= ((1.099f * (float)pow(cc, gamma)) - 0.099f) / cc;
+ else
+ *c = (1.099f * (float)pow(*c, gamma)) - 0.099f;
+}
+
+void gamma_correct(float *c, float gamma)
+{
+ *c = pow((*c), gamma);
+}
+
+float srgb_to_linearrgb(float c)
+{
+ if (c < 0.04045f)
+ return (c < 0.f)?0.f:c / 12.92;
+ else
+ return pow((c + 0.055)/1.055, 2.4);
+}
+
+float linearrgb_to_srgb(float c)
+{
+ if (c < 0.0031308)
+ return (c < 0.f)?0.f:c * 12.92;
+ else
+ return 1.055 * pow(c, 1.0/2.4) - 0.055;
+}
+
+/* utility function convert an RGB triplet from sRGB to linear RGB color space */
+void color_manage_linearize(float *col_to, float *col_from)
+{
+ col_to[0] = srgb_to_linearrgb(col_from[0]);
+ col_to[1] = srgb_to_linearrgb(col_from[1]);
+ col_to[2] = srgb_to_linearrgb(col_from[2]);
+}
+
+void floatbuf_to_srgb_byte(float *rectf, unsigned char *rectc, int x1, int x2, int y1, int y2, int w)
+{
+ int x, y;
+ float *rf= rectf;
+ float srgb[3];
+ unsigned char *rc= rectc;
+
+ for(y=y1; y<y2; y++) {
+ for(x=x1; x<x2; x++, rf+=4, rc+=4) {
+ srgb[0]= linearrgb_to_srgb(rf[0]);
+ srgb[1]= linearrgb_to_srgb(rf[1]);
+ srgb[2]= linearrgb_to_srgb(rf[2]);
+
+ rc[0]= FTOCHAR(srgb[0]);
+ rc[1]= FTOCHAR(srgb[1]);
+ rc[2]= FTOCHAR(srgb[2]);
+ rc[3]= FTOCHAR(rf[3]);
+ }
+ }
+}
+
+void floatbuf_to_byte(float *rectf, unsigned char *rectc, int x1, int x2, int y1, int y2, int w)
+{
+ int x, y;
+ float *rf= rectf;
+ unsigned char *rc= rectc;
+
+ for(y=y1; y<y2; y++) {
+ for(x=x1; x<x2; x++, rf+=4, rc+=4) {
+ rc[0]= FTOCHAR(rf[0]);
+ rc[1]= FTOCHAR(rf[1]);
+ rc[2]= FTOCHAR(rf[2]);
+ rc[3]= FTOCHAR(rf[3]);
+ }
+ }
+}
+
+
/* ********************************* color curve ********************* */
/* ***************** operations on full struct ************* */
diff --git a/source/blender/blenkernel/intern/context.c b/source/blender/blenkernel/intern/context.c
index 4a68d90a4ed..78c29a96bff 100644
--- a/source/blender/blenkernel/intern/context.c
+++ b/source/blender/blenkernel/intern/context.c
@@ -68,6 +68,7 @@ struct bContext {
struct Scene *scene;
int recursion;
+ int py_init; /* true if python is initialized */
} data;
/* data evaluation */
@@ -162,6 +163,16 @@ void CTX_store_free_list(ListBase *contexts)
}
}
+/* is python initialied? */
+int CTX_py_init_get(bContext *C)
+{
+ return C->data.py_init;
+}
+void CTX_py_init_set(bContext *C, int value)
+{
+ C->data.py_init= value;
+}
+
/* window manager context */
wmWindowManager *CTX_wm_manager(const bContext *C)
@@ -204,6 +215,11 @@ struct ARegion *CTX_wm_menu(const bContext *C)
return C->wm.menu;
}
+struct ReportList *CTX_wm_reports(const bContext *C)
+{
+ return &(C->wm.manager->reports);
+}
+
View3D *CTX_wm_view3d(const bContext *C)
{
if(C->wm.area && C->wm.area->spacetype==SPACE_VIEW3D)
@@ -226,6 +242,13 @@ struct SpaceText *CTX_wm_space_text(const bContext *C)
return NULL;
}
+struct SpaceConsole *CTX_wm_space_console(const bContext *C)
+{
+ if(C->wm.area && C->wm.area->spacetype==SPACE_CONSOLE)
+ return C->wm.area->spacedata.first;
+ return NULL;
+}
+
struct SpaceImage *CTX_wm_space_image(const bContext *C)
{
if(C->wm.area && C->wm.area->spacetype==SPACE_IMAGE)
@@ -233,6 +256,83 @@ struct SpaceImage *CTX_wm_space_image(const bContext *C)
return NULL;
}
+struct SpaceButs *CTX_wm_space_buts(const bContext *C)
+{
+ if(C->wm.area && C->wm.area->spacetype==SPACE_BUTS)
+ return C->wm.area->spacedata.first;
+ return NULL;
+}
+
+struct SpaceFile *CTX_wm_space_file(const bContext *C)
+{
+ if(C->wm.area && C->wm.area->spacetype==SPACE_FILE)
+ return C->wm.area->spacedata.first;
+ return NULL;
+}
+
+struct SpaceSeq *CTX_wm_space_seq(const bContext *C)
+{
+ if(C->wm.area && C->wm.area->spacetype==SPACE_SEQ)
+ return C->wm.area->spacedata.first;
+ return NULL;
+}
+
+struct SpaceOops *CTX_wm_space_outliner(const bContext *C)
+{
+ if(C->wm.area && C->wm.area->spacetype==SPACE_OUTLINER)
+ return C->wm.area->spacedata.first;
+ return NULL;
+}
+
+struct SpaceNla *CTX_wm_space_nla(const bContext *C)
+{
+ if(C->wm.area && C->wm.area->spacetype==SPACE_NLA)
+ return C->wm.area->spacedata.first;
+ return NULL;
+}
+
+struct SpaceTime *CTX_wm_space_time(const bContext *C)
+{
+ if(C->wm.area && C->wm.area->spacetype==SPACE_TIME)
+ return C->wm.area->spacedata.first;
+ return NULL;
+}
+
+struct SpaceNode *CTX_wm_space_node(const bContext *C)
+{
+ if(C->wm.area && C->wm.area->spacetype==SPACE_NODE)
+ return C->wm.area->spacedata.first;
+ return NULL;
+}
+
+struct SpaceLogic *CTX_wm_space_logic(const bContext *C)
+{
+ if(C->wm.area && C->wm.area->spacetype==SPACE_LOGIC)
+ return C->wm.area->spacedata.first;
+ return NULL;
+}
+
+struct SpaceIpo *CTX_wm_space_graph(const bContext *C)
+{
+ if(C->wm.area && C->wm.area->spacetype==SPACE_IPO)
+ return C->wm.area->spacedata.first;
+ return NULL;
+}
+
+struct SpaceAction *CTX_wm_space_action(const bContext *C)
+{
+ if(C->wm.area && C->wm.area->spacetype==SPACE_ACTION)
+ return C->wm.area->spacedata.first;
+ return NULL;
+}
+
+struct SpaceInfo *CTX_wm_space_info(const bContext *C)
+{
+ if(C->wm.area && C->wm.area->spacetype==SPACE_INFO)
+ return C->wm.area->spacedata.first;
+ return NULL;
+}
+
void CTX_wm_manager_set(bContext *C, wmWindowManager *wm)
{
C->wm.manager= wm;
@@ -606,6 +706,16 @@ int CTX_data_visible_bases(const bContext *C, ListBase *list)
return ctx_data_collection_get(C, "visible_bases", list);
}
+int CTX_data_selectable_objects(const bContext *C, ListBase *list)
+{
+ return ctx_data_collection_get(C, "selectable_objects", list);
+}
+
+int CTX_data_selectable_bases(const bContext *C, ListBase *list)
+{
+ return ctx_data_collection_get(C, "selectable_bases", list);
+}
+
struct Object *CTX_data_active_object(const bContext *C)
{
return ctx_data_pointer_get(C, "active_object");
diff --git a/source/blender/blenkernel/intern/depsgraph.c b/source/blender/blenkernel/intern/depsgraph.c
index de036e25d82..6c765b02e5d 100644
--- a/source/blender/blenkernel/intern/depsgraph.c
+++ b/source/blender/blenkernel/intern/depsgraph.c
@@ -39,6 +39,7 @@
#include "DNA_anim_types.h"
#include "DNA_action_types.h"
#include "DNA_armature_types.h"
+#include "DNA_boid_types.h"
#include "DNA_curve_types.h"
#include "DNA_camera_types.h"
#include "DNA_ID.h"
@@ -555,6 +556,8 @@ static void build_dag_object(DagForest *dag, DagNode *scenenode, Scene *scene, O
GroupObject *go;
for(; psys; psys=psys->next) {
+ BoidRule *rule = NULL;
+ BoidState *state = NULL;
ParticleSettings *part= psys->part;
dag_add_relation(dag, node, node, DAG_RL_OB_DATA, "Particle-Object Relation");
@@ -562,10 +565,15 @@ static void build_dag_object(DagForest *dag, DagNode *scenenode, Scene *scene, O
if(!psys_check_enabled(ob, psys))
continue;
- if(part->phystype==PART_PHYS_KEYED && psys->keyed_ob &&
- BLI_findlink(&psys->keyed_ob->particlesystem,psys->keyed_psys-1)) {
- node2 = dag_get_node(dag, psys->keyed_ob);
- dag_add_relation(dag, node2, node, DAG_RL_DATA_DATA, "Particle Keyed Physics");
+ if(ELEM(part->phystype,PART_PHYS_KEYED,PART_PHYS_BOIDS)) {
+ ParticleTarget *pt = psys->targets.first;
+
+ for(; pt; pt=pt->next) {
+ if(pt->ob && BLI_findlink(&pt->ob->particlesystem, pt->psys-1)) {
+ node2 = dag_get_node(dag, pt->ob);
+ dag_add_relation(dag, node2, node, DAG_RL_DATA_DATA|DAG_RL_OB_DATA, "Particle Targets");
+ }
+ }
}
if(part->ren_as == PART_DRAW_OB && part->dup_ob) {
@@ -582,33 +590,47 @@ static void build_dag_object(DagForest *dag, DagNode *scenenode, Scene *scene, O
}
}
- if(psys->effectors.first)
- psys_end_effectors(psys);
+ psys_end_effectors(psys);
psys_init_effectors(scene, ob, psys->part->eff_group, psys);
- if(psys->effectors.first) {
- for(nec= psys->effectors.first; nec; nec= nec->next) {
- Object *ob1= nec->ob;
+ for(nec= psys->effectors.first; nec; nec= nec->next) {
+ Object *ob1= nec->ob;
- if(nec->type & PSYS_EC_EFFECTOR) {
- node2 = dag_get_node(dag, ob1);
- if(ob1->pd->forcefield==PFIELD_GUIDE)
- dag_add_relation(dag, node2, node, DAG_RL_DATA_DATA|DAG_RL_OB_DATA, "Particle Field");
- else
- dag_add_relation(dag, node2, node, DAG_RL_OB_DATA, "Particle Field");
- }
- else if(nec->type & PSYS_EC_DEFLECT) {
- node2 = dag_get_node(dag, ob1);
- dag_add_relation(dag, node2, node, DAG_RL_DATA_DATA|DAG_RL_OB_DATA, "Particle Collision");
- }
- else if(nec->type & PSYS_EC_PARTICLE) {
- node2 = dag_get_node(dag, ob1);
- dag_add_relation(dag, node2, node, DAG_RL_DATA_DATA, "Particle Field");
- }
-
- if(nec->type & PSYS_EC_REACTOR) {
- node2 = dag_get_node(dag, ob1);
- dag_add_relation(dag, node, node2, DAG_RL_DATA_DATA, "Particle Reactor");
+ if(nec->type & PSYS_EC_EFFECTOR) {
+ node2 = dag_get_node(dag, ob1);
+ if(ob1->pd->forcefield==PFIELD_GUIDE)
+ dag_add_relation(dag, node2, node, DAG_RL_DATA_DATA|DAG_RL_OB_DATA, "Particle Field");
+ else
+ dag_add_relation(dag, node2, node, DAG_RL_OB_DATA, "Particle Field");
+ }
+ else if(nec->type & PSYS_EC_DEFLECT) {
+ node2 = dag_get_node(dag, ob1);
+ dag_add_relation(dag, node2, node, DAG_RL_DATA_DATA|DAG_RL_OB_DATA, "Particle Collision");
+ }
+ else if(nec->type & PSYS_EC_PARTICLE) {
+ node2 = dag_get_node(dag, ob1);
+ dag_add_relation(dag, node2, node, DAG_RL_DATA_DATA, "Particle Field");
+ }
+
+ if(nec->type & PSYS_EC_REACTOR) {
+ node2 = dag_get_node(dag, ob1);
+ dag_add_relation(dag, node, node2, DAG_RL_DATA_DATA, "Particle Reactor");
+ }
+ }
+
+ if(part->boids) {
+ for(state = part->boids->states.first; state; state=state->next) {
+ for(rule = state->rules.first; rule; rule=rule->next) {
+ Object *ruleob = NULL;
+ if(rule->type==eBoidRuleType_Avoid)
+ ruleob = ((BoidRuleGoalAvoid*)rule)->ob;
+ else if(rule->type==eBoidRuleType_FollowLeader)
+ ruleob = ((BoidRuleFollowLeader*)rule)->ob;
+
+ if(ruleob) {
+ node2 = dag_get_node(dag, ruleob);
+ dag_add_relation(dag, node2, node, DAG_RL_OB_DATA, "Boid Rule");
+ }
}
}
}
@@ -1975,8 +1997,6 @@ static void dag_object_time_update_flags(Object *ob)
}
}
- if(ob->scriptlink.totscript) ob->recalc |= OB_RECALC_OB;
-
if(ob->parent) {
/* motion path or bone child */
if(ob->parent->type==OB_CURVE || ob->parent->type==OB_ARMATURE) ob->recalc |= OB_RECALC_OB;
@@ -2063,7 +2083,6 @@ static void dag_object_time_update_flags(Object *ob)
}
}
}
-
/* flag all objects that need recalc, for changes in time for example */
void DAG_scene_update_flags(Scene *scene, unsigned int lay)
{
diff --git a/source/blender/blenkernel/intern/effect.c b/source/blender/blenkernel/intern/effect.c
index 553fdfe530e..e3c4f12184e 100644
--- a/source/blender/blenkernel/intern/effect.c
+++ b/source/blender/blenkernel/intern/effect.c
@@ -105,6 +105,7 @@ PartDeflect *object_add_collision_fields(void)
pd->pdef_sbift = 0.2f;
pd->pdef_sboft = 0.02f;
pd->seed = ((unsigned int)(ceil(PIL_check_seconds_timer()))+1) % 128;
+ pd->f_strength = 1.0f;
return pd;
}
@@ -504,6 +505,9 @@ void do_physical_effector(Scene *scene, Object *ob, float *opco, short type, flo
VecAddf(field,field,mag_vec);
break;
}
+ case PFIELD_BOID:
+ /* Boid field is handled completely in boids code. */
+ break;
}
}
diff --git a/source/blender/blenkernel/intern/exotic.c b/source/blender/blenkernel/intern/exotic.c
index 4e7e76dfae3..8827897a509 100644
--- a/source/blender/blenkernel/intern/exotic.c
+++ b/source/blender/blenkernel/intern/exotic.c
@@ -334,7 +334,7 @@ static void read_stl_mesh_ascii(Scene *scene, char *str)
*/
numtenthousand = 1;
vertdata = malloc(numtenthousand*3*30000*sizeof(float)); // uses realloc!
- if (!vertdata); STLALLOCERROR;
+ if (!vertdata) { STLALLOCERROR; }
linenum = 1;
/* Get rid of the first line */
@@ -357,7 +357,7 @@ static void read_stl_mesh_ascii(Scene *scene, char *str)
++numtenthousand;
vertdata = realloc(vertdata,
numtenthousand*3*30000*sizeof(float));
- if (!vertdata); STLALLOCERROR;
+ if (!vertdata) { STLALLOCERROR; }
}
/* Don't read normal, but check line for proper syntax anyway
@@ -1415,11 +1415,6 @@ static void displist_to_mesh(Scene *scene, DispList *dlfirst)
return;
}
- if(totcol>16) {
- //XXX error("Found more than 16 different colors");
- totcol= 16;
- }
-
vec[0]= (min[0]+max[0])/2;
vec[1]= (min[1]+max[1])/2;
vec[2]= (min[2]+max[2])/2;
@@ -1433,6 +1428,7 @@ static void displist_to_mesh(Scene *scene, DispList *dlfirst)
/* colors */
if(totcol) {
ob->mat= MEM_callocN(sizeof(void *)*totcol, "ob->mat");
+ ob->matbits= MEM_callocN(sizeof(char)*totcol, "ob->matbits");
me->mat= MEM_callocN(sizeof(void *)*totcol, "me->mat");
me->totcol= totcol;
ob->totcol= (unsigned char) me->totcol;
@@ -1482,7 +1478,7 @@ static void displist_to_mesh(Scene *scene, DispList *dlfirst)
dl= dlfirst;
while(dl) {
- colnr= (dl->col>15 ? 15: dl->col);
+ colnr= dl->col;
if(colnr) colnr--;
if(dl->type==DL_SURF) {
@@ -1691,7 +1687,7 @@ static void displist_to_objects(Scene *scene, ListBase *lbase)
if(totvert==0) {
- if(ivsurf==0) ; //XXX error("Found no data");
+ if(ivsurf==0) {}; //XXX error("Found no data");
if(lbase->first) BLI_freelistN(lbase);
return;
@@ -1904,16 +1900,15 @@ void write_stl(Scene *scene, char *str)
if(BLI_testextensie(str,".ble")) str[ strlen(str)-4]= 0;
if(BLI_testextensie(str,".stl")==0) strcat(str, ".stl");
- if (!during_script()) {
- if (BLI_exists(str))
- ; //XXX if(saveover(str)==0)
- //XXX return;
+ if (BLI_exists(str)) {
+ ; //XXX if(saveover(str)==0)
+ //XXX return;
}
fpSTL= fopen(str, "wb");
if(fpSTL==NULL) {
- if (!during_script()) ; //XXX error("Can't write file");
+ //XXX error("Can't write file");
return;
}
strcpy(temp_dir, str);
@@ -2237,11 +2232,11 @@ void write_vrml(Scene *scene, char *str)
if(BLI_testextensie(str,".blend")) str[ strlen(str)-6]= 0;
if(BLI_testextensie(str,".ble")) str[ strlen(str)-4]= 0;
if(BLI_testextensie(str,".wrl")==0) strcat(str, ".wrl");
- //XXX saveover() if(!during_script() && saveover(str)==0) return;
+ //XXX saveover() if(saveover(str)==0) return;
fp= fopen(str, "w");
- if(fp==NULL && !during_script()) {
+ if(fp==NULL) {
//XXX error("Can't write file");
return;
}
@@ -2548,15 +2543,15 @@ void write_dxf(struct Scene *scene, char *str)
if(BLI_testextensie(str,".ble")) str[ strlen(str)-4]= 0;
if(BLI_testextensie(str,".dxf")==0) strcat(str, ".dxf");
- if (!during_script()) {
- if (BLI_exists(str))
- ; //XXX if(saveover(str)==0)
- // return;
+
+ if (BLI_exists(str)) {
+ ; //XXX if(saveover(str)==0)
+ // return;
}
fp= fopen(str, "w");
- if(fp==NULL && !during_script()) {
+ if(fp==NULL) {
//XXX error("Can't write file");
return;
}
@@ -2804,8 +2799,11 @@ static void dxf_add_mat (Object *ob, Mesh *me, float color[3], char *layer)
if (!me) return;
- if(ob) ob->mat= MEM_callocN(sizeof(void *)*1, "ob->mat");
- if(ob) ob->actcol= 1;
+ if(ob) {
+ ob->mat= MEM_callocN(sizeof(void *)*1, "ob->mat");
+ ob->matbits= MEM_callocN(sizeof(char)*1, "ob->matbits");
+ ob->actcol= 1;
+ }
me->totcol= 1;
me->mat= MEM_callocN(sizeof(void *)*1, "me->mat");
@@ -4053,7 +4051,6 @@ static void dxf_read(Scene *scene, char *filename)
ob->type= OB_MESH;
ob->dt= OB_SHADED;
- if(U.flag & USER_MAT_ON_OB) ob->colbits= -1;
ob->trackflag= OB_POSY;
ob->upflag= OB_POSZ;
@@ -4072,9 +4069,10 @@ static void dxf_read(Scene *scene, char *filename)
VECCOPY(ob->rot, obrot);
ob->mat= MEM_callocN(sizeof(void *)*1, "ob->mat");
+ ob->matbits= MEM_callocN(sizeof(char)*1, "ob->matbits");
ob->totcol= (unsigned char) ((Mesh*)ob->data)->totcol;
ob->actcol= 1;
-
+
/* note: materials are either linked to mesh or object, if both then
you have to increase user counts. below line is not needed.
I leave it commented out here as warning (ton) */
diff --git a/source/blender/blenkernel/intern/fcurve.c b/source/blender/blenkernel/intern/fcurve.c
index ad8115ba9aa..ebd94b94f8c 100644
--- a/source/blender/blenkernel/intern/fcurve.c
+++ b/source/blender/blenkernel/intern/fcurve.c
@@ -1,5 +1,30 @@
-/* Testing code for new animation system in 2.5
- * Copyright 2009, Joshua Leung
+/**
+ * $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
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Joshua Leung (full recode)
+ *
+ * ***** END GPL LICENSE BLOCK *****
*/
@@ -31,7 +56,7 @@
#include "RNA_types.h"
#ifndef DISABLE_PYTHON
-#include "BPY_extern.h" /* for BPY_pydriver_eval() */
+#include "BPY_extern.h"
#endif
#define SMALL -1.0e-10
@@ -59,7 +84,7 @@ void free_fcurve (FCurve *fcu)
/* free extra data - i.e. modifiers, and driver */
fcurve_free_driver(fcu);
- fcurve_free_modifiers(fcu);
+ free_fmodifiers(&fcu->modifiers);
/* free f-curve itself */
MEM_freeN(fcu);
@@ -115,7 +140,7 @@ FCurve *copy_fcurve (FCurve *fcu)
fcu_d->driver= fcurve_copy_driver(fcu_d->driver);
/* copy modifiers */
- fcurve_copy_modifiers(&fcu_d->modifiers, &fcu->modifiers);
+ copy_fmodifiers(&fcu_d->modifiers, &fcu->modifiers);
/* return new data */
return fcu_d;
@@ -175,20 +200,6 @@ FCurve *list_find_fcurve (ListBase *list, const char rna_path[], const int array
return NULL;
}
-short on_keyframe_fcurve(FCurve *fcu, float cfra)
-{
- BezTriple *bezt;
- unsigned i;
-
- bezt= fcu->bezt;
- for (i=0; i<fcu->totvert; i++, bezt++) {
- if (IS_EQ(bezt->vec[1][0], cfra))
- return 1;
- }
-
- return 0;
-}
-
/* Calculate the extents of F-Curve's data */
void calc_fcurve_bounds (FCurve *fcu, float *xmin, float *xmax, float *ymin, float *ymax)
{
@@ -1245,1016 +1256,6 @@ static float fcurve_eval_samples (FCurve *fcu, FPoint *fpts, float evaltime)
return cvalue;
}
-/* ******************************** F-Curve Modifiers ********************************* */
-
-/* Template --------------------------- */
-
-/* Each modifier defines a set of functions, which will be called at the appropriate
- * times. In addition to this, each modifier should have a type-info struct, where
- * its functions are attached for use.
- */
-
-/* Template for type-info data:
- * - make a copy of this when creating new modifiers, and just change the functions
- * pointed to as necessary
- * - although the naming of functions doesn't matter, it would help for code
- * readability, to follow the same naming convention as is presented here
- * - any functions that a constraint doesn't need to define, don't define
- * for such cases, just use NULL
- * - these should be defined after all the functions have been defined, so that
- * forward-definitions/prototypes don't need to be used!
- * - keep this copy #if-def'd so that future constraints can get based off this
- */
-#if 0
-static FModifierTypeInfo FMI_MODNAME = {
- FMODIFIER_TYPE_MODNAME, /* type */
- sizeof(FMod_ModName), /* size */
- FMI_TYPE_SOME_ACTION, /* action type */
- FMI_REQUIRES_SOME_REQUIREMENT, /* requirements */
- "Modifier Name", /* name */
- "FMod_ModName", /* struct name */
- fcm_modname_free, /* free data */
- fcm_modname_relink, /* relink data */
- fcm_modname_copy, /* copy data */
- fcm_modname_new_data, /* new data */
- fcm_modname_verify, /* verify */
- fcm_modname_time, /* evaluate time */
- fcm_modname_evaluate /* evaluate */
-};
-#endif
-
-/* Generator F-Curve Modifier --------------------------- */
-
-/* Generators available:
- * 1) simple polynomial generator:
- * - Exanded form - (y = C[0]*(x^(n)) + C[1]*(x^(n-1)) + ... + C[n])
- * - Factorised form - (y = (C[0][0]*x + C[0][1]) * (C[1][0]*x + C[1][1]) * ... * (C[n][0]*x + C[n][1]))
- * 2) simple builin 'functions':
- * of the form (y = C[0] * fn( C[1]*x + C[2] ) + C[3])
- * where fn() can be any one of:
- * sin, cos, tan, ln, sqrt
- * 3) expression...
- */
-
-static void fcm_generator_free (FModifier *fcm)
-{
- FMod_Generator *data= (FMod_Generator *)fcm->data;
-
- /* free polynomial coefficients array */
- if (data->coefficients)
- MEM_freeN(data->coefficients);
-}
-
-static void fcm_generator_copy (FModifier *fcm, FModifier *src)
-{
- FMod_Generator *gen= (FMod_Generator *)fcm->data;
- FMod_Generator *ogen= (FMod_Generator *)src->data;
-
- /* copy coefficients array? */
- if (ogen->coefficients)
- gen->coefficients= MEM_dupallocN(ogen->coefficients);
-}
-
-static void fcm_generator_new_data (void *mdata)
-{
- FMod_Generator *data= (FMod_Generator *)mdata;
- float *cp;
-
- /* set default generator to be linear 0-1 (gradient = 1, y-offset = 0) */
- data->poly_order= 1;
- data->arraysize= 2;
- cp= data->coefficients= MEM_callocN(sizeof(float)*2, "FMod_Generator_Coefs");
- cp[0] = 0; // y-offset
- cp[1] = 1; // gradient
-}
-
-static void fcm_generator_verify (FModifier *fcm)
-{
- FMod_Generator *data= (FMod_Generator *)fcm->data;
-
- /* requirements depend on mode */
- switch (data->mode) {
- case FCM_GENERATOR_POLYNOMIAL: /* expanded polynomial expression */
- {
- /* arraysize needs to be order+1, so resize if not */
- if (data->arraysize != (data->poly_order+1)) {
- float *nc;
-
- /* make new coefficients array, and copy over as much data as can fit */
- nc= MEM_callocN(sizeof(float)*(data->poly_order+1), "FMod_Generator_Coefs");
-
- if (data->coefficients) {
- if (data->arraysize > (data->poly_order+1))
- memcpy(nc, data->coefficients, sizeof(float)*(data->poly_order+1));
- else
- memcpy(nc, data->coefficients, sizeof(float)*data->arraysize);
-
- /* free the old data */
- MEM_freeN(data->coefficients);
- }
-
- /* set the new data */
- data->coefficients= nc;
- data->arraysize= data->poly_order+1;
- }
- }
- break;
-
- case FCM_GENERATOR_POLYNOMIAL_FACTORISED: /* expanded polynomial expression */
- {
- /* arraysize needs to be 2*order, so resize if not */
- if (data->arraysize != (data->poly_order * 2)) {
- float *nc;
-
- /* make new coefficients array, and copy over as much data as can fit */
- nc= MEM_callocN(sizeof(float)*(data->poly_order*2), "FMod_Generator_Coefs");
-
- if (data->coefficients) {
- if (data->arraysize > (data->poly_order * 2))
- memcpy(nc, data->coefficients, sizeof(float)*(data->poly_order * 2));
- else
- memcpy(nc, data->coefficients, sizeof(float)*data->arraysize);
-
- /* free the old data */
- MEM_freeN(data->coefficients);
- }
-
- /* set the new data */
- data->coefficients= nc;
- data->arraysize= data->poly_order * 2;
- }
- }
- break;
-
- case FCM_GENERATOR_FUNCTION: /* builtin function */
- {
- /* arraysize needs to be 4*/
- if (data->arraysize != 4) {
- float *nc;
-
- /* free the old data */
- if (data->coefficients)
- MEM_freeN(data->coefficients);
-
- /* make new coefficients array, and init using default values */
- nc= data->coefficients= MEM_callocN(sizeof(float)*4, "FMod_Generator_Coefs");
- data->arraysize= 4;
-
- nc[0]= 1.0f;
- nc[1]= 1.0f;
- nc[2]= 0.0f;
- nc[3]= 0.0f;
- }
- }
- break;
- }
-}
-
-static void fcm_generator_evaluate (FCurve *fcu, FModifier *fcm, float *cvalue, float evaltime)
-{
- FMod_Generator *data= (FMod_Generator *)fcm->data;
-
- /* behaviour depends on mode
- * NOTE: the data in its default state is fine too
- */
- switch (data->mode) {
- case FCM_GENERATOR_POLYNOMIAL: /* expanded polynomial expression */
- {
- /* we overwrite cvalue with the sum of the polynomial */
- float *powers = MEM_callocN(sizeof(float)*data->arraysize, "Poly Powers");
- float value= 0.0f;
- unsigned int i;
-
- /* for each x^n, precalculate value based on previous one first... this should be
- * faster that calling pow() for each entry
- */
- for (i=0; i < data->arraysize; i++) {
- /* first entry is x^0 = 1, otherwise, calculate based on previous */
- if (i)
- powers[i]= powers[i-1] * evaltime;
- else
- powers[0]= 1;
- }
-
- /* for each coefficient, add to value, which we'll write to *cvalue in one go */
- for (i=0; i < data->arraysize; i++)
- value += data->coefficients[i] * powers[i];
-
- /* only if something changed, write *cvalue in one go */
- if (data->poly_order) {
- if (data->flag & FCM_GENERATOR_ADDITIVE)
- *cvalue += value;
- else
- *cvalue= value;
- }
-
- /* cleanup */
- if (powers)
- MEM_freeN(powers);
- }
- break;
-
- case FCM_GENERATOR_POLYNOMIAL_FACTORISED: /* factorised polynomial */
- {
- float value= 1.0f, *cp=NULL;
- unsigned int i;
-
- /* for each coefficient pair, solve for that bracket before accumulating in value by multiplying */
- for (cp=data->coefficients, i=0; (cp) && (i < data->poly_order); cp+=2, i++)
- value *= (cp[0]*evaltime + cp[1]);
-
- /* only if something changed, write *cvalue in one go */
- if (data->poly_order) {
- if (data->flag & FCM_GENERATOR_ADDITIVE)
- *cvalue += value;
- else
- *cvalue= value;
- }
- }
- break;
-
- case FCM_GENERATOR_FUNCTION: /* builtin function */
- {
- double arg= data->coefficients[1]*evaltime + data->coefficients[2];
- double (*fn)(double v) = NULL;
-
- /* get function pointer to the func to use:
- * WARNING: must perform special argument validation hereto guard against crashes
- */
- switch (data->func_type)
- {
- /* simple ones */
- case FCM_GENERATOR_FN_SIN: /* sine wave */
- fn= sin;
- break;
- case FCM_GENERATOR_FN_COS: /* cosine wave */
- fn= cos;
- break;
-
- /* validation required */
- case FCM_GENERATOR_FN_TAN: /* tangent wave */
- {
- /* check that argument is not on one of the discontinuities (i.e. 90deg, 270 deg, etc) */
- if IS_EQ(fmod((arg - M_PI_2), M_PI), 0.0) {
- if ((data->flag & FCM_GENERATOR_ADDITIVE) == 0)
- *cvalue = 0.0f; /* no value possible here */
- }
- else
- fn= tan;
- }
- break;
- case FCM_GENERATOR_FN_LN: /* natural log */
- {
- /* check that value is greater than 1? */
- if (arg > 1.0f) {
- fn= log;
- }
- else {
- if ((data->flag & FCM_GENERATOR_ADDITIVE) == 0)
- *cvalue = 0.0f; /* no value possible here */
- }
- }
- break;
- case FCM_GENERATOR_FN_SQRT: /* square root */
- {
- /* no negative numbers */
- if (arg > 0.0f) {
- fn= sqrt;
- }
- else {
- if ((data->flag & FCM_GENERATOR_ADDITIVE) == 0)
- *cvalue = 0.0f; /* no value possible here */
- }
- }
- break;
-
- default:
- printf("Invalid Function-Generator for F-Modifier - %d \n", data->func_type);
- }
-
- /* execute function callback to set value if appropriate */
- if (fn) {
- float value= (float)(data->coefficients[0]*fn(arg) + data->coefficients[3]);
-
- if (data->flag & FCM_GENERATOR_ADDITIVE)
- *cvalue += value;
- else
- *cvalue= value;
- }
- }
- break;
-
-#ifndef DISABLE_PYTHON
- case FCM_GENERATOR_EXPRESSION: /* py-expression */
- // TODO...
- break;
-#endif /* DISABLE_PYTHON */
- }
-}
-
-static FModifierTypeInfo FMI_GENERATOR = {
- FMODIFIER_TYPE_GENERATOR, /* type */
- sizeof(FMod_Generator), /* size */
- FMI_TYPE_GENERATE_CURVE, /* action type */
- FMI_REQUIRES_NOTHING, /* requirements */
- "Generator", /* name */
- "FMod_Generator", /* struct name */
- fcm_generator_free, /* free data */
- fcm_generator_copy, /* copy data */
- fcm_generator_new_data, /* new data */
- fcm_generator_verify, /* verify */
- NULL, /* evaluate time */
- fcm_generator_evaluate /* evaluate */
-};
-
-/* Envelope F-Curve Modifier --------------------------- */
-
-static void fcm_envelope_free (FModifier *fcm)
-{
- FMod_Envelope *env= (FMod_Envelope *)fcm->data;
-
- /* free envelope data array */
- if (env->data)
- MEM_freeN(env->data);
-}
-
-static void fcm_envelope_copy (FModifier *fcm, FModifier *src)
-{
- FMod_Envelope *env= (FMod_Envelope *)fcm->data;
- FMod_Envelope *oenv= (FMod_Envelope *)src->data;
-
- /* copy envelope data array */
- if (oenv->data)
- env->data= MEM_dupallocN(oenv->data);
-}
-
-static void fcm_envelope_new_data (void *mdata)
-{
- FMod_Envelope *env= (FMod_Envelope *)mdata;
-
- /* set default min/max ranges */
- env->min= -1.0f;
- env->max= 1.0f;
-}
-
-static void fcm_envelope_verify (FModifier *fcm)
-{
- FMod_Envelope *env= (FMod_Envelope *)fcm->data;
-
- /* if the are points, perform bubble-sort on them, as user may have changed the order */
- if (env->data) {
- // XXX todo...
- }
-}
-
-static void fcm_envelope_evaluate (FCurve *fcu, FModifier *fcm, float *cvalue, float evaltime)
-{
- FMod_Envelope *env= (FMod_Envelope *)fcm->data;
- FCM_EnvelopeData *fed, *prevfed, *lastfed;
- float min=0.0f, max=0.0f, fac=0.0f;
- int a;
-
- /* get pointers */
- if (env->data == NULL) return;
- prevfed= env->data;
- fed= prevfed + 1;
- lastfed= prevfed + (env->totvert-1);
-
- /* get min/max values for envelope at evaluation time (relative to mid-value) */
- if (prevfed->time >= evaltime) {
- /* before or on first sample, so just extend value */
- min= prevfed->min;
- max= prevfed->max;
- }
- else if (lastfed->time <= evaltime) {
- /* after or on last sample, so just extend value */
- min= lastfed->min;
- max= lastfed->max;
- }
- else {
- /* evaltime occurs somewhere between segments */
- // TODO: implement binary search for this to make it faster?
- for (a=0; prevfed && fed && (a < env->totvert-1); a++, prevfed=fed, fed++) {
- /* evaltime occurs within the interval defined by these two envelope points */
- if ((prevfed->time <= evaltime) && (fed->time >= evaltime)) {
- float afac, bfac, diff;
-
- diff= fed->time - prevfed->time;
- afac= (evaltime - prevfed->time) / diff;
- bfac= (fed->time - evaltime) / diff;
-
- min= bfac*prevfed->min + afac*fed->min;
- max= bfac*prevfed->max + afac*fed->max;
-
- break;
- }
- }
- }
-
- /* adjust *cvalue
- * - fac is the ratio of how the current y-value corresponds to the reference range
- * - thus, the new value is found by mapping the old range to the new!
- */
- fac= (*cvalue - (env->midval + env->min)) / (env->max - env->min);
- *cvalue= min + fac*(max - min);
-}
-
-static FModifierTypeInfo FMI_ENVELOPE = {
- FMODIFIER_TYPE_ENVELOPE, /* type */
- sizeof(FMod_Envelope), /* size */
- FMI_TYPE_REPLACE_VALUES, /* action type */
- 0, /* requirements */
- "Envelope", /* name */
- "FMod_Envelope", /* struct name */
- fcm_envelope_free, /* free data */
- fcm_envelope_copy, /* copy data */
- fcm_envelope_new_data, /* new data */
- fcm_envelope_verify, /* verify */
- NULL, /* evaluate time */
- fcm_envelope_evaluate /* evaluate */
-};
-
-/* Cycles F-Curve Modifier --------------------------- */
-
-/* This modifier changes evaltime to something that exists within the curve's frame-range,
- * then re-evaluates modifier stack up to this point using the new time. This re-entrant behaviour
- * is very likely to be more time-consuming than the original approach... (which was tighly integrated into
- * the calculation code...).
- *
- * NOTE: this needs to be at the start of the stack to be of use, as it needs to know the extents of the keyframes/sample-data
- * Possible TODO - store length of cycle information that can be initialised from the extents of the keyframes/sample-data, and adjusted
- * as appropriate
- */
-
-/* temp data used during evaluation */
-typedef struct tFCMED_Cycles {
- float cycyofs; /* y-offset to apply */
-} tFCMED_Cycles;
-
-static void fcm_cycles_new_data (void *mdata)
-{
- FMod_Cycles *data= (FMod_Cycles *)mdata;
-
- /* turn on cycles by default */
- data->before_mode= data->after_mode= FCM_EXTRAPOLATE_CYCLIC;
-}
-
-static float fcm_cycles_time (FCurve *fcu, FModifier *fcm, float cvalue, float evaltime)
-{
- FMod_Cycles *data= (FMod_Cycles *)fcm->data;
- float prevkey[2], lastkey[2], cycyofs=0.0f;
- short side=0, mode=0;
- int cycles=0;
-
- /* check if modifier is first in stack, otherwise disable ourself... */
- // FIXME...
- if (fcm->prev) {
- fcm->flag |= FMODIFIER_FLAG_DISABLED;
- return evaltime;
- }
-
- /* calculate new evaltime due to cyclic interpolation */
- if (fcu && fcu->bezt) {
- BezTriple *prevbezt= fcu->bezt;
- BezTriple *lastbezt= prevbezt + fcu->totvert-1;
-
- prevkey[0]= prevbezt->vec[1][0];
- prevkey[1]= prevbezt->vec[1][1];
-
- lastkey[0]= lastbezt->vec[1][0];
- lastkey[1]= lastbezt->vec[1][1];
- }
- else if (fcu && fcu->fpt) {
- FPoint *prevfpt= fcu->fpt;
- FPoint *lastfpt= prevfpt + fcu->totvert-1;
-
- prevkey[0]= prevfpt->vec[0];
- prevkey[1]= prevfpt->vec[1];
-
- lastkey[0]= lastfpt->vec[0];
- lastkey[1]= lastfpt->vec[1];
- }
- else
- return evaltime;
-
- /* check if modifier will do anything
- * 1) if in data range, definitely don't do anything
- * 2) if before first frame or after last frame, make sure some cycling is in use
- */
- if (evaltime < prevkey[0]) {
- if (data->before_mode) {
- side= -1;
- mode= data->before_mode;
- cycles= data->before_cycles;
- }
- }
- else if (evaltime > lastkey[0]) {
- if (data->after_mode) {
- side= 1;
- mode= data->after_mode;
- cycles= data->after_cycles;
- }
- }
- if ELEM(0, side, mode)
- return evaltime;
-
- /* find relative place within a cycle */
- {
- float cycdx=0, cycdy=0, ofs=0;
- float cycle= 0;
-
- /* ofs is start frame of cycle */
- ofs= prevkey[0];
-
- /* calculate period and amplitude (total height) of a cycle */
- cycdx= lastkey[0] - prevkey[0];
- cycdy= lastkey[1] - prevkey[1];
-
- /* check if cycle is infinitely small, to be point of being impossible to use */
- if (cycdx == 0)
- return evaltime;
-
- /* calculate the 'number' of the cycle */
- cycle= ((float)side * (evaltime - ofs) / cycdx);
-
- /* check that cyclic is still enabled for the specified time */
- if (cycles == 0) {
- /* catch this case so that we don't exit when we have cycles=0
- * as this indicates infinite cycles...
- */
- }
- else if (cycle > (cycles+1)) {
- /* we are too far away from range to evaluate
- * TODO: but we should still hold last value...
- */
- return evaltime;
- }
-
- /* check if 'cyclic extrapolation', and thus calculate y-offset for this cycle */
- if (mode == FCM_EXTRAPOLATE_CYCLIC_OFFSET) {
- cycyofs = (float)floor((evaltime - ofs) / cycdx);
- cycyofs *= cycdy;
- }
-
- /* calculate where in the cycle we are (overwrite evaltime to reflect this) */
- if ((mode == FCM_EXTRAPOLATE_MIRROR) && ((int)(cycle) % 2)) {
- /* when 'mirror' option is used and cycle number is odd, this cycle is played in reverse
- * - for 'before' extrapolation, we need to flip in a different way, otherwise values past
- * then end of the curve get referenced (result of fmod will be negative, and with different phase)
- */
- if (side < 0)
- evaltime= (float)(prevkey[0] - fmod(evaltime-ofs, cycdx));
- else
- evaltime= (float)(lastkey[0] - fmod(evaltime-ofs, cycdx));
- }
- else {
- /* the cycle is played normally... */
- evaltime= (float)(fmod(evaltime-ofs, cycdx) + ofs);
- }
- if (evaltime < ofs) evaltime += cycdx;
- }
-
- /* store temp data if needed */
- if (mode == FCM_EXTRAPOLATE_CYCLIC_OFFSET) {
- tFCMED_Cycles *edata;
-
- /* for now, this is just a float, but we could get more stuff... */
- fcm->edata= edata= MEM_callocN(sizeof(tFCMED_Cycles), "tFCMED_Cycles");
- edata->cycyofs= cycyofs;
- }
-
- /* return the new frame to evaluate */
- return evaltime;
-}
-
-static void fcm_cycles_evaluate (FCurve *fcu, FModifier *fcm, float *cvalue, float evaltime)
-{
- tFCMED_Cycles *edata= (tFCMED_Cycles *)fcm->edata;
-
- /* use temp data */
- if (edata) {
- /* add cyclic offset - no need to check for now, otherwise the data wouldn't exist! */
- *cvalue += edata->cycyofs;
-
- /* free temp data */
- MEM_freeN(edata);
- fcm->edata= NULL;
- }
-}
-
-static FModifierTypeInfo FMI_CYCLES = {
- FMODIFIER_TYPE_CYCLES, /* type */
- sizeof(FMod_Cycles), /* size */
- FMI_TYPE_EXTRAPOLATION, /* action type */
- FMI_REQUIRES_ORIGINAL_DATA, /* requirements */
- "Cycles", /* name */
- "FMod_Cycles", /* struct name */
- NULL, /* free data */
- NULL, /* copy data */
- fcm_cycles_new_data, /* new data */
- NULL /*fcm_cycles_verify*/, /* verify */
- fcm_cycles_time, /* evaluate time */
- fcm_cycles_evaluate /* evaluate */
-};
-
-/* Noise F-Curve Modifier --------------------------- */
-
-static void fcm_noise_new_data (void *mdata)
-{
- FMod_Noise *data= (FMod_Noise *)mdata;
-
- /* defaults */
- data->size= 1.0f;
- data->strength= 1.0f;
- data->phase= 1.0f;
- data->depth = 0;
- data->modification = FCM_NOISE_MODIF_REPLACE;
-}
-
-static void fcm_noise_evaluate (FCurve *fcu, FModifier *fcm, float *cvalue, float evaltime)
-{
- FMod_Noise *data= (FMod_Noise *)fcm->data;
- float noise;
-
- noise = BLI_turbulence(data->size, evaltime, data->phase, 0.f, data->depth);
-
- switch (data->modification) {
- case FCM_NOISE_MODIF_ADD:
- *cvalue= *cvalue + noise * data->strength;
- break;
- case FCM_NOISE_MODIF_SUBTRACT:
- *cvalue= *cvalue - noise * data->strength;
- break;
- case FCM_NOISE_MODIF_MULTIPLY:
- *cvalue= *cvalue * noise * data->strength;
- break;
- case FCM_NOISE_MODIF_REPLACE:
- default:
- *cvalue= *cvalue + (noise - 0.5f) * data->strength;
- break;
- }
-}
-
-static FModifierTypeInfo FMI_NOISE = {
- FMODIFIER_TYPE_NOISE, /* type */
- sizeof(FMod_Noise), /* size */
- FMI_TYPE_REPLACE_VALUES, /* action type */
- 0, /* requirements */
- "Noise", /* name */
- "FMod_Noise", /* struct name */
- NULL, /* free data */
- NULL, /* copy data */
- fcm_noise_new_data, /* new data */
- NULL /*fcm_noise_verify*/, /* verify */
- NULL, /* evaluate time */
- fcm_noise_evaluate /* evaluate */
-};
-
-/* Filter F-Curve Modifier --------------------------- */
-
-#if 0 // XXX not yet implemented
-static FModifierTypeInfo FMI_FILTER = {
- FMODIFIER_TYPE_FILTER, /* type */
- sizeof(FMod_Filter), /* size */
- FMI_TYPE_REPLACE_VALUES, /* action type */
- 0, /* requirements */
- "Filter", /* name */
- "FMod_Filter", /* struct name */
- NULL, /* free data */
- NULL, /* copy data */
- NULL, /* new data */
- NULL /*fcm_filter_verify*/, /* verify */
- NULL, /* evlauate time */
- fcm_filter_evaluate /* evaluate */
-};
-#endif // XXX not yet implemented
-
-
-/* Python F-Curve Modifier --------------------------- */
-
-static void fcm_python_free (FModifier *fcm)
-{
- FMod_Python *data= (FMod_Python *)fcm->data;
-
- /* id-properties */
- IDP_FreeProperty(data->prop);
- MEM_freeN(data->prop);
-}
-
-static void fcm_python_new_data (void *mdata)
-{
- FMod_Python *data= (FMod_Python *)mdata;
-
- /* everything should be set correctly by calloc, except for the prop->type constant.*/
- data->prop = MEM_callocN(sizeof(IDProperty), "PyFModifierProps");
- data->prop->type = IDP_GROUP;
-}
-
-static void fcm_python_copy (FModifier *fcm, FModifier *src)
-{
- FMod_Python *pymod = (FMod_Python *)fcm->data;
- FMod_Python *opymod = (FMod_Python *)src->data;
-
- pymod->prop = IDP_CopyProperty(opymod->prop);
-}
-
-static void fcm_python_evaluate (FCurve *fcu, FModifier *fcm, float *cvalue, float evaltime)
-{
-#ifndef DISABLE_PYTHON
- //FMod_Python *data= (FMod_Python *)fcm->data;
-
- /* FIXME... need to implement this modifier...
- * It will need it execute a script using the custom properties
- */
-#endif /* DISABLE_PYTHON */
-}
-
-static FModifierTypeInfo FMI_PYTHON = {
- FMODIFIER_TYPE_PYTHON, /* type */
- sizeof(FMod_Python), /* size */
- FMI_TYPE_GENERATE_CURVE, /* action type */
- FMI_REQUIRES_RUNTIME_CHECK, /* requirements */
- "Python", /* name */
- "FMod_Python", /* struct name */
- fcm_python_free, /* free data */
- fcm_python_copy, /* copy data */
- fcm_python_new_data, /* new data */
- NULL /*fcm_python_verify*/, /* verify */
- NULL /*fcm_python_time*/, /* evaluate time */
- fcm_python_evaluate /* evaluate */
-};
-
-
-/* Limits F-Curve Modifier --------------------------- */
-
-static float fcm_limits_time (FCurve *fcu, FModifier *fcm, float cvalue, float evaltime)
-{
- FMod_Limits *data= (FMod_Limits *)fcm->data;
-
- /* check for the time limits */
- if ((data->flag & FCM_LIMIT_XMIN) && (evaltime < data->rect.xmin))
- return data->rect.xmin;
- if ((data->flag & FCM_LIMIT_XMAX) && (evaltime > data->rect.xmax))
- return data->rect.xmax;
-
- /* modifier doesn't change time */
- return evaltime;
-}
-
-static void fcm_limits_evaluate (FCurve *fcu, FModifier *fcm, float *cvalue, float evaltime)
-{
- FMod_Limits *data= (FMod_Limits *)fcm->data;
-
- /* value limits now */
- if ((data->flag & FCM_LIMIT_YMIN) && (*cvalue < data->rect.ymin))
- *cvalue= data->rect.ymin;
- if ((data->flag & FCM_LIMIT_YMAX) && (*cvalue > data->rect.ymax))
- *cvalue= data->rect.ymax;
-}
-
-static FModifierTypeInfo FMI_LIMITS = {
- FMODIFIER_TYPE_LIMITS, /* type */
- sizeof(FMod_Limits), /* size */
- FMI_TYPE_GENERATE_CURVE, /* action type */ /* XXX... err... */
- FMI_REQUIRES_RUNTIME_CHECK, /* requirements */
- "Limits", /* name */
- "FMod_Limits", /* struct name */
- NULL, /* free data */
- NULL, /* copy data */
- NULL, /* new data */
- NULL, /* verify */
- fcm_limits_time, /* evaluate time */
- fcm_limits_evaluate /* evaluate */
-};
-
-/* F-Curve Modifier API --------------------------- */
-/* All of the F-Curve Modifier api functions use FModifierTypeInfo structs to carry out
- * and operations that involve F-Curve modifier specific code.
- */
-
-/* These globals only ever get directly accessed in this file */
-static FModifierTypeInfo *fmodifiersTypeInfo[FMODIFIER_NUM_TYPES];
-static short FMI_INIT= 1; /* when non-zero, the list needs to be updated */
-
-/* This function only gets called when FMI_INIT is non-zero */
-static void fmods_init_typeinfo ()
-{
- fmodifiersTypeInfo[0]= NULL; /* 'Null' F-Curve Modifier */
- fmodifiersTypeInfo[1]= &FMI_GENERATOR; /* Generator F-Curve Modifier */
- fmodifiersTypeInfo[2]= &FMI_ENVELOPE; /* Envelope F-Curve Modifier */
- fmodifiersTypeInfo[3]= &FMI_CYCLES; /* Cycles F-Curve Modifier */
- fmodifiersTypeInfo[4]= &FMI_NOISE; /* Apply-Noise F-Curve Modifier */
- fmodifiersTypeInfo[5]= NULL/*&FMI_FILTER*/; /* Filter F-Curve Modifier */ // XXX unimplemented
- fmodifiersTypeInfo[6]= &FMI_PYTHON; /* Custom Python F-Curve Modifier */
- fmodifiersTypeInfo[7]= &FMI_LIMITS; /* Limits F-Curve Modifier */
-}
-
-/* This function should be used for getting the appropriate type-info when only
- * a F-Curve modifier type is known
- */
-FModifierTypeInfo *get_fmodifier_typeinfo (int type)
-{
- /* initialise the type-info list? */
- if (FMI_INIT) {
- fmods_init_typeinfo();
- FMI_INIT = 0;
- }
-
- /* only return for valid types */
- if ( (type >= FMODIFIER_TYPE_NULL) &&
- (type <= FMODIFIER_NUM_TYPES ) )
- {
- /* there shouldn't be any segfaults here... */
- return fmodifiersTypeInfo[type];
- }
- else {
- printf("No valid F-Curve Modifier type-info data available. Type = %i \n", type);
- }
-
- return NULL;
-}
-
-/* This function should always be used to get the appropriate type-info, as it
- * has checks which prevent segfaults in some weird cases.
- */
-FModifierTypeInfo *fmodifier_get_typeinfo (FModifier *fcm)
-{
- /* only return typeinfo for valid modifiers */
- if (fcm)
- return get_fmodifier_typeinfo(fcm->type);
- else
- return NULL;
-}
-
-/* API --------------------------- */
-
-/* Add a new F-Curve Modifier to the given F-Curve of a certain type */
-FModifier *fcurve_add_modifier (FCurve *fcu, int type)
-{
- FModifierTypeInfo *fmi= get_fmodifier_typeinfo(type);
- FModifier *fcm;
-
- /* sanity checks */
- if ELEM(NULL, fcu, fmi)
- return NULL;
-
- /* special checks for whether modifier can be added */
- if ((fcu->modifiers.first) && (type == FMODIFIER_TYPE_CYCLES)) {
- /* cycles modifier must be first in stack, so for now, don't add if it can't be */
- // TODO: perhaps there is some better way, but for now,
- printf("Error: Cannot add 'Cycles' modifier to F-Curve, as 'Cycles' modifier can only be first in stack. \n");
- return NULL;
- }
-
- /* add modifier itself */
- fcm= MEM_callocN(sizeof(FModifier), "F-Curve Modifier");
- fcm->type = type;
- fcm->flag = FMODIFIER_FLAG_EXPANDED;
- BLI_addtail(&fcu->modifiers, fcm);
-
- /* add modifier's data */
- fcm->data= MEM_callocN(fmi->size, fmi->structName);
-
- /* init custom settings if necessary */
- if (fmi->new_data)
- fmi->new_data(fcm->data);
-
- /* return modifier for further editing */
- return fcm;
-}
-
-/* Duplicate all of the F-Curve Modifiers in the Modifier stacks */
-void fcurve_copy_modifiers (ListBase *dst, ListBase *src)
-{
- FModifier *fcm, *srcfcm;
-
- if ELEM(NULL, dst, src)
- return;
-
- dst->first= dst->last= NULL;
- BLI_duplicatelist(dst, src);
-
- for (fcm=dst->first, srcfcm=src->first; fcm && srcfcm; srcfcm=srcfcm->next, fcm=fcm->next) {
- FModifierTypeInfo *fmi= fmodifier_get_typeinfo(fcm);
-
- /* make a new copy of the F-Modifier's data */
- fcm->data = MEM_dupallocN(fcm->data);
-
- /* only do specific constraints if required */
- if (fmi && fmi->copy_data)
- fmi->copy_data(fcm, srcfcm);
- }
-}
-
-/* Remove and free the given F-Curve Modifier from the given F-Curve's stack */
-void fcurve_remove_modifier (FCurve *fcu, FModifier *fcm)
-{
- FModifierTypeInfo *fmi= fmodifier_get_typeinfo(fcm);
-
- /* sanity check */
- if (fcm == NULL)
- return;
-
- /* free modifier's special data (stored inside fcm->data) */
- if (fcm->data) {
- if (fmi && fmi->free_data)
- fmi->free_data(fcm);
-
- /* free modifier's data (fcm->data) */
- MEM_freeN(fcm->data);
- }
-
- /* remove modifier from stack */
- if (fcu)
- BLI_freelinkN(&fcu->modifiers, fcm);
- else {
- // XXX this case can probably be removed some day, as it shouldn't happen...
- printf("fcurve_remove_modifier() - no fcurve \n");
- MEM_freeN(fcm);
- }
-}
-
-/* Remove all of a given F-Curve's modifiers */
-void fcurve_free_modifiers (FCurve *fcu)
-{
- FModifier *fcm, *fmn;
-
- /* sanity check */
- if (fcu == NULL)
- return;
-
- /* free each modifier in order - modifier is unlinked from list and freed */
- for (fcm= fcu->modifiers.first; fcm; fcm= fmn) {
- fmn= fcm->next;
- fcurve_remove_modifier(fcu, fcm);
- }
-}
-
-/* Bake modifiers for given F-Curve to curve sample data, in the frame range defined
- * by start and end (inclusive).
- */
-void fcurve_bake_modifiers (FCurve *fcu, int start, int end)
-{
- ChannelDriver *driver;
-
- /* sanity checks */
- // TODO: make these tests report errors using reports not printf's
- if ELEM(NULL, fcu, fcu->modifiers.first) {
- printf("Error: No F-Curve with F-Curve Modifiers to Bake\n");
- return;
- }
-
- /* temporarily, disable driver while we sample, so that they don't influence the outcome */
- driver= fcu->driver;
- fcu->driver= NULL;
-
- /* bake the modifiers, by sampling the curve at each frame */
- fcurve_store_samples(fcu, NULL, start, end, fcurve_samplingcb_evalcurve);
-
- /* free the modifiers now */
- fcurve_free_modifiers(fcu);
-
- /* restore driver */
- fcu->driver= driver;
-}
-
-/* Find the active F-Curve Modifier */
-FModifier *fcurve_find_active_modifier (FCurve *fcu)
-{
- FModifier *fcm;
-
- /* sanity checks */
- if ELEM(NULL, fcu, fcu->modifiers.first)
- return NULL;
-
- /* loop over modifiers until 'active' one is found */
- for (fcm= fcu->modifiers.first; fcm; fcm= fcm->next) {
- if (fcm->flag & FMODIFIER_FLAG_ACTIVE)
- return fcm;
- }
-
- /* no modifier is active */
- return NULL;
-}
-
-/* Set the active F-Curve Modifier */
-void fcurve_set_active_modifier (FCurve *fcu, FModifier *fcm)
-{
- FModifier *fm;
-
- /* sanity checks */
- if ELEM(NULL, fcu, fcu->modifiers.first)
- return;
-
- /* deactivate all, and set current one active */
- for (fm= fcu->modifiers.first; fm; fm= fm->next)
- fm->flag &= ~FMODIFIER_FLAG_ACTIVE;
-
- /* make given modifier active */
- if (fcm)
- fcm->flag |= FMODIFIER_FLAG_ACTIVE;
-}
-
/* ***************************** F-Curve - Evaluation ********************************* */
/* Evaluate and return the value of the given F-Curve at the specified frame ("evaltime")
@@ -2262,7 +1263,6 @@ void fcurve_set_active_modifier (FCurve *fcu, FModifier *fcm)
*/
float evaluate_fcurve (FCurve *fcu, float evaltime)
{
- FModifier *fcm;
float cvalue= 0.0f;
float devaltime;
@@ -2275,28 +1275,8 @@ float evaluate_fcurve (FCurve *fcu, float evaltime)
evaltime= cvalue= evaluate_driver(fcu->driver, evaltime);
}
- /* evaluate time modifications imposed by some F-Curve Modifiers
- * - this step acts as an optimisation to prevent the F-Curve stack being evaluated
- * several times by modifiers requesting the time be modified, as the final result
- * would have required using the modified time
- * - modifiers only ever recieve the unmodified time, as subsequent modifiers should be
- * working on the 'global' result of the modified curve, not some localised segment,
- * so nevaltime gets set to whatever the last time-modifying modifier likes...
- * - we start from the end of the stack, as only the last one matters for now
- */
- devaltime= evaltime;
-
- for (fcm= fcu->modifiers.last; fcm; fcm= fcm->prev) {
- FModifierTypeInfo *fmi= fmodifier_get_typeinfo(fcm);
-
- /* only evaluate if there's a callback for this */
- // TODO: implement the 'influence' control feature...
- if (fmi && fmi->evaluate_modifier_time) {
- if ((fcm->flag & (FMODIFIER_FLAG_DISABLED|FMODIFIER_FLAG_MUTED)) == 0)
- devaltime= fmi->evaluate_modifier_time(fcu, fcm, cvalue, evaltime);
- break;
- }
- }
+ /* evaluate modifiers which modify time to evaluate the base curve at */
+ devaltime= evaluate_time_fmodifiers(&fcu->modifiers, fcu, cvalue, evaltime);
/* evaluate curve-data
* - 'devaltime' instead of 'evaltime', as this is the time that the last time-modifying
@@ -2308,16 +1288,7 @@ float evaluate_fcurve (FCurve *fcu, float evaltime)
cvalue= fcurve_eval_samples(fcu, fcu->fpt, devaltime);
/* evaluate modifiers */
- for (fcm= fcu->modifiers.first; fcm; fcm= fcm->next) {
- FModifierTypeInfo *fmi= fmodifier_get_typeinfo(fcm);
-
- /* only evaluate if there's a callback for this */
- // TODO: implement the 'influence' control feature...
- if (fmi && fmi->evaluate_modifier) {
- if ((fcm->flag & (FMODIFIER_FLAG_DISABLED|FMODIFIER_FLAG_MUTED)) == 0)
- fmi->evaluate_modifier(fcu, fcm, &cvalue, evaltime);
- }
- }
+ evaluate_value_fmodifiers(&fcu->modifiers, fcu, &cvalue, evaltime);
/* if curve can only have integral values, perform truncation (i.e. drop the decimal part)
* here so that the curve can be sampled correctly
@@ -2330,10 +1301,16 @@ float evaluate_fcurve (FCurve *fcu, float evaltime)
}
/* Calculate the value of the given F-Curve at the given frame, and set its curval */
-// TODO: will this be necessary?
void calculate_fcurve (FCurve *fcu, float ctime)
{
- /* calculate and set curval (evaluates driver too) */
- fcu->curval= evaluate_fcurve(fcu, ctime);
+ /* only calculate + set curval (overriding the existing value) if curve has
+ * any data which warrants this...
+ */
+ if ( (fcu->totvert) || (fcu->driver && !(fcu->driver->flag & DRIVER_FLAG_INVALID)) ||
+ list_has_suitable_fmodifier(&fcu->modifiers, 0, FMI_TYPE_GENERATE_CURVE) )
+ {
+ /* calculate and set curval (evaluates driver too if necessary) */
+ fcu->curval= evaluate_fcurve(fcu, ctime);
+ }
}
diff --git a/source/blender/blenkernel/intern/fluidsim.c b/source/blender/blenkernel/intern/fluidsim.c
index 2b4032af503..ad9e481ffd2 100644
--- a/source/blender/blenkernel/intern/fluidsim.c
+++ b/source/blender/blenkernel/intern/fluidsim.c
@@ -83,9 +83,9 @@ void fluidsim_init(FluidsimModifierData *fluidmd)
fss->type = OB_FLUIDSIM_ENABLE;
fss->show_advancedoptions = 0;
- fss->resolutionxyz = 50;
- fss->previewresxyz = 25;
- fss->realsize = 0.03;
+ fss->resolutionxyz = 65;
+ fss->previewresxyz = 45;
+ fss->realsize = 0.5;
fss->guiDisplayMode = 2; // preview
fss->renderDisplayMode = 3; // render
@@ -98,7 +98,7 @@ void fluidsim_init(FluidsimModifierData *fluidmd)
fss->gravy = 0.0;
fss->gravz = -9.81;
fss->animStart = 0.0;
- fss->animEnd = 0.30;
+ fss->animEnd = 4.0;
fss->gstar = 0.005; // used as normgstar
fss->maxRefine = -1;
// maxRefine is set according to resolutionxyz during bake
@@ -114,15 +114,15 @@ void fluidsim_init(FluidsimModifierData *fluidmd)
// no bounding box needed
// todo - reuse default init from elbeem!
- fss->typeFlags = OB_FSBND_NOSLIP;
+ fss->typeFlags = OB_FSBND_PARTSLIP;
fss->domainNovecgen = 0;
fss->volumeInitType = 1; // volume
- fss->partSlipValue = 0.0;
+ fss->partSlipValue = 0.2;
fss->generateTracers = 0;
fss->generateParticles = 0.0;
fss->surfaceSmoothing = 1.0;
- fss->surfaceSubdivs = 1.0;
+ fss->surfaceSubdivs = 0.0;
fss->particleInfSize = 0.0;
fss->particleInfAlpha = 0.0;
diff --git a/source/blender/blenkernel/intern/fmodifier.c b/source/blender/blenkernel/intern/fmodifier.c
new file mode 100644
index 00000000000..64558d0b456
--- /dev/null
+++ b/source/blender/blenkernel/intern/fmodifier.c
@@ -0,0 +1,1197 @@
+/**
+ * $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
+ * All rights reserved.
+ *
+ * Contributor(s): Joshua Leung (full recode)
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+
+#include <math.h>
+#include <stdio.h>
+#include <stddef.h>
+#include <string.h>
+#include <float.h>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_anim_types.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+#include "BLI_noise.h"
+
+#include "BKE_fcurve.h"
+#include "BKE_curve.h"
+#include "BKE_global.h"
+#include "BKE_idprop.h"
+#include "BKE_utildefines.h"
+
+#include "RNA_access.h"
+#include "RNA_types.h"
+
+#ifndef DISABLE_PYTHON
+#include "BPY_extern.h" /* for BPY_pydriver_eval() */
+#endif
+
+#define SMALL -1.0e-10
+#define SELECT 1
+
+/* ******************************** F-Modifiers ********************************* */
+
+/* Info ------------------------------- */
+
+/* F-Modifiers are modifiers which operate on F-Curves. However, they can also be defined
+ * on NLA-Strips to affect all of the F-Curves referenced by the NLA-Strip.
+ */
+
+/* Template --------------------------- */
+
+/* Each modifier defines a set of functions, which will be called at the appropriate
+ * times. In addition to this, each modifier should have a type-info struct, where
+ * its functions are attached for use.
+ */
+
+/* Template for type-info data:
+ * - make a copy of this when creating new modifiers, and just change the functions
+ * pointed to as necessary
+ * - although the naming of functions doesn't matter, it would help for code
+ * readability, to follow the same naming convention as is presented here
+ * - any functions that a constraint doesn't need to define, don't define
+ * for such cases, just use NULL
+ * - these should be defined after all the functions have been defined, so that
+ * forward-definitions/prototypes don't need to be used!
+ * - keep this copy #if-def'd so that future constraints can get based off this
+ */
+#if 0
+static FModifierTypeInfo FMI_MODNAME = {
+ FMODIFIER_TYPE_MODNAME, /* type */
+ sizeof(FMod_ModName), /* size */
+ FMI_TYPE_SOME_ACTION, /* action type */
+ FMI_REQUIRES_SOME_REQUIREMENT, /* requirements */
+ "Modifier Name", /* name */
+ "FMod_ModName", /* struct name */
+ fcm_modname_free, /* free data */
+ fcm_modname_relink, /* relink data */
+ fcm_modname_copy, /* copy data */
+ fcm_modname_new_data, /* new data */
+ fcm_modname_verify, /* verify */
+ fcm_modname_time, /* evaluate time */
+ fcm_modname_evaluate /* evaluate */
+};
+#endif
+
+/* Generator F-Curve Modifier --------------------------- */
+
+/* Generators available:
+ * 1) simple polynomial generator:
+ * - Exanded form - (y = C[0]*(x^(n)) + C[1]*(x^(n-1)) + ... + C[n])
+ * - Factorised form - (y = (C[0][0]*x + C[0][1]) * (C[1][0]*x + C[1][1]) * ... * (C[n][0]*x + C[n][1]))
+ */
+
+static void fcm_generator_free (FModifier *fcm)
+{
+ FMod_Generator *data= (FMod_Generator *)fcm->data;
+
+ /* free polynomial coefficients array */
+ if (data->coefficients)
+ MEM_freeN(data->coefficients);
+}
+
+static void fcm_generator_copy (FModifier *fcm, FModifier *src)
+{
+ FMod_Generator *gen= (FMod_Generator *)fcm->data;
+ FMod_Generator *ogen= (FMod_Generator *)src->data;
+
+ /* copy coefficients array? */
+ if (ogen->coefficients)
+ gen->coefficients= MEM_dupallocN(ogen->coefficients);
+}
+
+static void fcm_generator_new_data (void *mdata)
+{
+ FMod_Generator *data= (FMod_Generator *)mdata;
+ float *cp;
+
+ /* set default generator to be linear 0-1 (gradient = 1, y-offset = 0) */
+ data->poly_order= 1;
+ data->arraysize= 2;
+ cp= data->coefficients= MEM_callocN(sizeof(float)*2, "FMod_Generator_Coefs");
+ cp[0] = 0; // y-offset
+ cp[1] = 1; // gradient
+}
+
+static void fcm_generator_verify (FModifier *fcm)
+{
+ FMod_Generator *data= (FMod_Generator *)fcm->data;
+
+ /* requirements depend on mode */
+ switch (data->mode) {
+ case FCM_GENERATOR_POLYNOMIAL: /* expanded polynomial expression */
+ {
+ /* arraysize needs to be order+1, so resize if not */
+ if (data->arraysize != (data->poly_order+1)) {
+ float *nc;
+
+ /* make new coefficients array, and copy over as much data as can fit */
+ nc= MEM_callocN(sizeof(float)*(data->poly_order+1), "FMod_Generator_Coefs");
+
+ if (data->coefficients) {
+ if (data->arraysize > (data->poly_order+1))
+ memcpy(nc, data->coefficients, sizeof(float)*(data->poly_order+1));
+ else
+ memcpy(nc, data->coefficients, sizeof(float)*data->arraysize);
+
+ /* free the old data */
+ MEM_freeN(data->coefficients);
+ }
+
+ /* set the new data */
+ data->coefficients= nc;
+ data->arraysize= data->poly_order+1;
+ }
+ }
+ break;
+
+ case FCM_GENERATOR_POLYNOMIAL_FACTORISED: /* expanded polynomial expression */
+ {
+ /* arraysize needs to be 2*order, so resize if not */
+ if (data->arraysize != (data->poly_order * 2)) {
+ float *nc;
+
+ /* make new coefficients array, and copy over as much data as can fit */
+ nc= MEM_callocN(sizeof(float)*(data->poly_order*2), "FMod_Generator_Coefs");
+
+ if (data->coefficients) {
+ if (data->arraysize > (data->poly_order * 2))
+ memcpy(nc, data->coefficients, sizeof(float)*(data->poly_order * 2));
+ else
+ memcpy(nc, data->coefficients, sizeof(float)*data->arraysize);
+
+ /* free the old data */
+ MEM_freeN(data->coefficients);
+ }
+
+ /* set the new data */
+ data->coefficients= nc;
+ data->arraysize= data->poly_order * 2;
+ }
+ }
+ break;
+ }
+}
+
+static void fcm_generator_evaluate (FCurve *fcu, FModifier *fcm, float *cvalue, float evaltime)
+{
+ FMod_Generator *data= (FMod_Generator *)fcm->data;
+
+ /* behaviour depends on mode
+ * NOTE: the data in its default state is fine too
+ */
+ switch (data->mode) {
+ case FCM_GENERATOR_POLYNOMIAL: /* expanded polynomial expression */
+ {
+ /* we overwrite cvalue with the sum of the polynomial */
+ float *powers = MEM_callocN(sizeof(float)*data->arraysize, "Poly Powers");
+ float value= 0.0f;
+ unsigned int i;
+
+ /* for each x^n, precalculate value based on previous one first... this should be
+ * faster that calling pow() for each entry
+ */
+ for (i=0; i < data->arraysize; i++) {
+ /* first entry is x^0 = 1, otherwise, calculate based on previous */
+ if (i)
+ powers[i]= powers[i-1] * evaltime;
+ else
+ powers[0]= 1;
+ }
+
+ /* for each coefficient, add to value, which we'll write to *cvalue in one go */
+ for (i=0; i < data->arraysize; i++)
+ value += data->coefficients[i] * powers[i];
+
+ /* only if something changed, write *cvalue in one go */
+ if (data->poly_order) {
+ if (data->flag & FCM_GENERATOR_ADDITIVE)
+ *cvalue += value;
+ else
+ *cvalue= value;
+ }
+
+ /* cleanup */
+ if (powers)
+ MEM_freeN(powers);
+ }
+ break;
+
+ case FCM_GENERATOR_POLYNOMIAL_FACTORISED: /* factorised polynomial */
+ {
+ float value= 1.0f, *cp=NULL;
+ unsigned int i;
+
+ /* for each coefficient pair, solve for that bracket before accumulating in value by multiplying */
+ for (cp=data->coefficients, i=0; (cp) && (i < data->poly_order); cp+=2, i++)
+ value *= (cp[0]*evaltime + cp[1]);
+
+ /* only if something changed, write *cvalue in one go */
+ if (data->poly_order) {
+ if (data->flag & FCM_GENERATOR_ADDITIVE)
+ *cvalue += value;
+ else
+ *cvalue= value;
+ }
+ }
+ break;
+ }
+}
+
+static FModifierTypeInfo FMI_GENERATOR = {
+ FMODIFIER_TYPE_GENERATOR, /* type */
+ sizeof(FMod_Generator), /* size */
+ FMI_TYPE_GENERATE_CURVE, /* action type */
+ FMI_REQUIRES_NOTHING, /* requirements */
+ "Generator", /* name */
+ "FMod_Generator", /* struct name */
+ fcm_generator_free, /* free data */
+ fcm_generator_copy, /* copy data */
+ fcm_generator_new_data, /* new data */
+ fcm_generator_verify, /* verify */
+ NULL, /* evaluate time */
+ fcm_generator_evaluate /* evaluate */
+};
+
+/* Built-In Function Generator F-Curve Modifier --------------------------- */
+
+/* This uses the general equation for equations:
+ * y = amplitude * fn(phase_multiplier*x + phase_offset) + y_offset
+ *
+ * where amplitude, phase_multiplier/offset, y_offset are user-defined coefficients,
+ * x is the evaluation 'time', and 'y' is the resultant value
+ *
+ * Functions available are
+ * sin, cos, tan, sinc (normalised sin), natural log, square root
+ */
+
+static void fcm_fn_generator_new_data (void *mdata)
+{
+ FMod_FunctionGenerator *data= (FMod_FunctionGenerator *)mdata;
+
+ /* set amplitude and phase multiplier to 1.0f so that something is generated */
+ data->amplitude= 1.0f;
+ data->phase_multiplier= 1.0f;
+}
+
+/* Unary 'normalised sine' function
+ * y = sin(PI + x) / (PI * x),
+ * except for x = 0 when y = 1.
+ */
+static double sinc (double x)
+{
+ if (fabs(x) < 0.0001)
+ return 1.0;
+ else
+ return sin(M_PI * x) / (M_PI * x);
+}
+
+static void fcm_fn_generator_evaluate (FCurve *fcu, FModifier *fcm, float *cvalue, float evaltime)
+{
+ FMod_FunctionGenerator *data= (FMod_FunctionGenerator *)fcm->data;
+ double arg= data->phase_multiplier*evaltime + data->phase_offset;
+ double (*fn)(double v) = NULL;
+
+ /* get function pointer to the func to use:
+ * WARNING: must perform special argument validation hereto guard against crashes
+ */
+ switch (data->type)
+ {
+ /* simple ones */
+ case FCM_GENERATOR_FN_SIN: /* sine wave */
+ fn= sin;
+ break;
+ case FCM_GENERATOR_FN_COS: /* cosine wave */
+ fn= cos;
+ break;
+ case FCM_GENERATOR_FN_SINC: /* normalised sine wave */
+ fn= sinc;
+ break;
+
+ /* validation required */
+ case FCM_GENERATOR_FN_TAN: /* tangent wave */
+ {
+ /* check that argument is not on one of the discontinuities (i.e. 90deg, 270 deg, etc) */
+ if IS_EQ(fmod((arg - M_PI_2), M_PI), 0.0) {
+ if ((data->flag & FCM_GENERATOR_ADDITIVE) == 0)
+ *cvalue = 0.0f; /* no value possible here */
+ }
+ else
+ fn= tan;
+ }
+ break;
+ case FCM_GENERATOR_FN_LN: /* natural log */
+ {
+ /* check that value is greater than 1? */
+ if (arg > 1.0f) {
+ fn= log;
+ }
+ else {
+ if ((data->flag & FCM_GENERATOR_ADDITIVE) == 0)
+ *cvalue = 0.0f; /* no value possible here */
+ }
+ }
+ break;
+ case FCM_GENERATOR_FN_SQRT: /* square root */
+ {
+ /* no negative numbers */
+ if (arg > 0.0f) {
+ fn= sqrt;
+ }
+ else {
+ if ((data->flag & FCM_GENERATOR_ADDITIVE) == 0)
+ *cvalue = 0.0f; /* no value possible here */
+ }
+ }
+ break;
+
+ default:
+ printf("Invalid Function-Generator for F-Modifier - %d \n", data->type);
+ }
+
+ /* execute function callback to set value if appropriate */
+ if (fn) {
+ float value= (float)(data->amplitude*fn(arg) + data->value_offset);
+
+ if (data->flag & FCM_GENERATOR_ADDITIVE)
+ *cvalue += value;
+ else
+ *cvalue= value;
+ }
+}
+
+static FModifierTypeInfo FMI_FN_GENERATOR = {
+ FMODIFIER_TYPE_FN_GENERATOR, /* type */
+ sizeof(FMod_FunctionGenerator), /* size */
+ FMI_TYPE_GENERATE_CURVE, /* action type */
+ FMI_REQUIRES_NOTHING, /* requirements */
+ "Built-In Function", /* name */
+ "FMod_FunctionGenerator", /* struct name */
+ NULL, /* free data */
+ NULL, /* copy data */
+ fcm_fn_generator_new_data, /* new data */
+ NULL, /* verify */
+ NULL, /* evaluate time */
+ fcm_fn_generator_evaluate /* evaluate */
+};
+
+/* Envelope F-Curve Modifier --------------------------- */
+
+static void fcm_envelope_free (FModifier *fcm)
+{
+ FMod_Envelope *env= (FMod_Envelope *)fcm->data;
+
+ /* free envelope data array */
+ if (env->data)
+ MEM_freeN(env->data);
+}
+
+static void fcm_envelope_copy (FModifier *fcm, FModifier *src)
+{
+ FMod_Envelope *env= (FMod_Envelope *)fcm->data;
+ FMod_Envelope *oenv= (FMod_Envelope *)src->data;
+
+ /* copy envelope data array */
+ if (oenv->data)
+ env->data= MEM_dupallocN(oenv->data);
+}
+
+static void fcm_envelope_new_data (void *mdata)
+{
+ FMod_Envelope *env= (FMod_Envelope *)mdata;
+
+ /* set default min/max ranges */
+ env->min= -1.0f;
+ env->max= 1.0f;
+}
+
+static void fcm_envelope_verify (FModifier *fcm)
+{
+ FMod_Envelope *env= (FMod_Envelope *)fcm->data;
+
+ /* if the are points, perform bubble-sort on them, as user may have changed the order */
+ if (env->data) {
+ // XXX todo...
+ }
+}
+
+static void fcm_envelope_evaluate (FCurve *fcu, FModifier *fcm, float *cvalue, float evaltime)
+{
+ FMod_Envelope *env= (FMod_Envelope *)fcm->data;
+ FCM_EnvelopeData *fed, *prevfed, *lastfed;
+ float min=0.0f, max=0.0f, fac=0.0f;
+ int a;
+
+ /* get pointers */
+ if (env->data == NULL) return;
+ prevfed= env->data;
+ fed= prevfed + 1;
+ lastfed= prevfed + (env->totvert-1);
+
+ /* get min/max values for envelope at evaluation time (relative to mid-value) */
+ if (prevfed->time >= evaltime) {
+ /* before or on first sample, so just extend value */
+ min= prevfed->min;
+ max= prevfed->max;
+ }
+ else if (lastfed->time <= evaltime) {
+ /* after or on last sample, so just extend value */
+ min= lastfed->min;
+ max= lastfed->max;
+ }
+ else {
+ /* evaltime occurs somewhere between segments */
+ // TODO: implement binary search for this to make it faster?
+ for (a=0; prevfed && fed && (a < env->totvert-1); a++, prevfed=fed, fed++) {
+ /* evaltime occurs within the interval defined by these two envelope points */
+ if ((prevfed->time <= evaltime) && (fed->time >= evaltime)) {
+ float afac, bfac, diff;
+
+ diff= fed->time - prevfed->time;
+ afac= (evaltime - prevfed->time) / diff;
+ bfac= (fed->time - evaltime) / diff;
+
+ min= bfac*prevfed->min + afac*fed->min;
+ max= bfac*prevfed->max + afac*fed->max;
+
+ break;
+ }
+ }
+ }
+
+ /* adjust *cvalue
+ * - fac is the ratio of how the current y-value corresponds to the reference range
+ * - thus, the new value is found by mapping the old range to the new!
+ */
+ fac= (*cvalue - (env->midval + env->min)) / (env->max - env->min);
+ *cvalue= min + fac*(max - min);
+}
+
+static FModifierTypeInfo FMI_ENVELOPE = {
+ FMODIFIER_TYPE_ENVELOPE, /* type */
+ sizeof(FMod_Envelope), /* size */
+ FMI_TYPE_REPLACE_VALUES, /* action type */
+ 0, /* requirements */
+ "Envelope", /* name */
+ "FMod_Envelope", /* struct name */
+ fcm_envelope_free, /* free data */
+ fcm_envelope_copy, /* copy data */
+ fcm_envelope_new_data, /* new data */
+ fcm_envelope_verify, /* verify */
+ NULL, /* evaluate time */
+ fcm_envelope_evaluate /* evaluate */
+};
+
+/* Cycles F-Curve Modifier --------------------------- */
+
+/* This modifier changes evaltime to something that exists within the curve's frame-range,
+ * then re-evaluates modifier stack up to this point using the new time. This re-entrant behaviour
+ * is very likely to be more time-consuming than the original approach... (which was tighly integrated into
+ * the calculation code...).
+ *
+ * NOTE: this needs to be at the start of the stack to be of use, as it needs to know the extents of the keyframes/sample-data
+ * Possible TODO - store length of cycle information that can be initialised from the extents of the keyframes/sample-data, and adjusted
+ * as appropriate
+ */
+
+/* temp data used during evaluation */
+typedef struct tFCMED_Cycles {
+ float cycyofs; /* y-offset to apply */
+} tFCMED_Cycles;
+
+static void fcm_cycles_new_data (void *mdata)
+{
+ FMod_Cycles *data= (FMod_Cycles *)mdata;
+
+ /* turn on cycles by default */
+ data->before_mode= data->after_mode= FCM_EXTRAPOLATE_CYCLIC;
+}
+
+static float fcm_cycles_time (FCurve *fcu, FModifier *fcm, float cvalue, float evaltime)
+{
+ FMod_Cycles *data= (FMod_Cycles *)fcm->data;
+ float prevkey[2], lastkey[2], cycyofs=0.0f;
+ short side=0, mode=0;
+ int cycles=0;
+
+ /* check if modifier is first in stack, otherwise disable ourself... */
+ // FIXME...
+ if (fcm->prev) {
+ fcm->flag |= FMODIFIER_FLAG_DISABLED;
+ return evaltime;
+ }
+
+ /* calculate new evaltime due to cyclic interpolation */
+ if (fcu && fcu->bezt) {
+ BezTriple *prevbezt= fcu->bezt;
+ BezTriple *lastbezt= prevbezt + fcu->totvert-1;
+
+ prevkey[0]= prevbezt->vec[1][0];
+ prevkey[1]= prevbezt->vec[1][1];
+
+ lastkey[0]= lastbezt->vec[1][0];
+ lastkey[1]= lastbezt->vec[1][1];
+ }
+ else if (fcu && fcu->fpt) {
+ FPoint *prevfpt= fcu->fpt;
+ FPoint *lastfpt= prevfpt + fcu->totvert-1;
+
+ prevkey[0]= prevfpt->vec[0];
+ prevkey[1]= prevfpt->vec[1];
+
+ lastkey[0]= lastfpt->vec[0];
+ lastkey[1]= lastfpt->vec[1];
+ }
+ else
+ return evaltime;
+
+ /* check if modifier will do anything
+ * 1) if in data range, definitely don't do anything
+ * 2) if before first frame or after last frame, make sure some cycling is in use
+ */
+ if (evaltime < prevkey[0]) {
+ if (data->before_mode) {
+ side= -1;
+ mode= data->before_mode;
+ cycles= data->before_cycles;
+ }
+ }
+ else if (evaltime > lastkey[0]) {
+ if (data->after_mode) {
+ side= 1;
+ mode= data->after_mode;
+ cycles= data->after_cycles;
+ }
+ }
+ if ELEM(0, side, mode)
+ return evaltime;
+
+ /* find relative place within a cycle */
+ {
+ float cycdx=0, cycdy=0, ofs=0;
+ float cycle= 0;
+
+ /* ofs is start frame of cycle */
+ ofs= prevkey[0];
+
+ /* calculate period and amplitude (total height) of a cycle */
+ cycdx= lastkey[0] - prevkey[0];
+ cycdy= lastkey[1] - prevkey[1];
+
+ /* check if cycle is infinitely small, to be point of being impossible to use */
+ if (cycdx == 0)
+ return evaltime;
+
+ /* calculate the 'number' of the cycle */
+ cycle= ((float)side * (evaltime - ofs) / cycdx);
+
+ /* check that cyclic is still enabled for the specified time */
+ if (cycles == 0) {
+ /* catch this case so that we don't exit when we have cycles=0
+ * as this indicates infinite cycles...
+ */
+ }
+ else if (cycle > (cycles+1)) {
+ /* we are too far away from range to evaluate
+ * TODO: but we should still hold last value...
+ */
+ return evaltime;
+ }
+
+ /* check if 'cyclic extrapolation', and thus calculate y-offset for this cycle */
+ if (mode == FCM_EXTRAPOLATE_CYCLIC_OFFSET) {
+ cycyofs = (float)floor((evaltime - ofs) / cycdx);
+ cycyofs *= cycdy;
+ }
+
+ /* calculate where in the cycle we are (overwrite evaltime to reflect this) */
+ if ((mode == FCM_EXTRAPOLATE_MIRROR) && ((int)(cycle) % 2)) {
+ /* when 'mirror' option is used and cycle number is odd, this cycle is played in reverse
+ * - for 'before' extrapolation, we need to flip in a different way, otherwise values past
+ * then end of the curve get referenced (result of fmod will be negative, and with different phase)
+ */
+ if (side < 0)
+ evaltime= (float)(prevkey[0] - fmod(evaltime-ofs, cycdx));
+ else
+ evaltime= (float)(lastkey[0] - fmod(evaltime-ofs, cycdx));
+ }
+ else {
+ /* the cycle is played normally... */
+ evaltime= (float)(fmod(evaltime-ofs, cycdx) + ofs);
+ }
+ if (evaltime < ofs) evaltime += cycdx;
+ }
+
+ /* store temp data if needed */
+ if (mode == FCM_EXTRAPOLATE_CYCLIC_OFFSET) {
+ tFCMED_Cycles *edata;
+
+ /* for now, this is just a float, but we could get more stuff... */
+ fcm->edata= edata= MEM_callocN(sizeof(tFCMED_Cycles), "tFCMED_Cycles");
+ edata->cycyofs= cycyofs;
+ }
+
+ /* return the new frame to evaluate */
+ return evaltime;
+}
+
+static void fcm_cycles_evaluate (FCurve *fcu, FModifier *fcm, float *cvalue, float evaltime)
+{
+ tFCMED_Cycles *edata= (tFCMED_Cycles *)fcm->edata;
+
+ /* use temp data */
+ if (edata) {
+ /* add cyclic offset - no need to check for now, otherwise the data wouldn't exist! */
+ *cvalue += edata->cycyofs;
+
+ /* free temp data */
+ MEM_freeN(edata);
+ fcm->edata= NULL;
+ }
+}
+
+static FModifierTypeInfo FMI_CYCLES = {
+ FMODIFIER_TYPE_CYCLES, /* type */
+ sizeof(FMod_Cycles), /* size */
+ FMI_TYPE_EXTRAPOLATION, /* action type */
+ FMI_REQUIRES_ORIGINAL_DATA, /* requirements */
+ "Cycles", /* name */
+ "FMod_Cycles", /* struct name */
+ NULL, /* free data */
+ NULL, /* copy data */
+ fcm_cycles_new_data, /* new data */
+ NULL /*fcm_cycles_verify*/, /* verify */
+ fcm_cycles_time, /* evaluate time */
+ fcm_cycles_evaluate /* evaluate */
+};
+
+/* Noise F-Curve Modifier --------------------------- */
+
+static void fcm_noise_new_data (void *mdata)
+{
+ FMod_Noise *data= (FMod_Noise *)mdata;
+
+ /* defaults */
+ data->size= 1.0f;
+ data->strength= 1.0f;
+ data->phase= 1.0f;
+ data->depth = 0;
+ data->modification = FCM_NOISE_MODIF_REPLACE;
+}
+
+static void fcm_noise_evaluate (FCurve *fcu, FModifier *fcm, float *cvalue, float evaltime)
+{
+ FMod_Noise *data= (FMod_Noise *)fcm->data;
+ float noise;
+
+ noise = BLI_turbulence(data->size, evaltime, data->phase, 0.f, data->depth);
+
+ switch (data->modification) {
+ case FCM_NOISE_MODIF_ADD:
+ *cvalue= *cvalue + noise * data->strength;
+ break;
+ case FCM_NOISE_MODIF_SUBTRACT:
+ *cvalue= *cvalue - noise * data->strength;
+ break;
+ case FCM_NOISE_MODIF_MULTIPLY:
+ *cvalue= *cvalue * noise * data->strength;
+ break;
+ case FCM_NOISE_MODIF_REPLACE:
+ default:
+ *cvalue= *cvalue + (noise - 0.5f) * data->strength;
+ break;
+ }
+}
+
+static FModifierTypeInfo FMI_NOISE = {
+ FMODIFIER_TYPE_NOISE, /* type */
+ sizeof(FMod_Noise), /* size */
+ FMI_TYPE_REPLACE_VALUES, /* action type */
+ 0, /* requirements */
+ "Noise", /* name */
+ "FMod_Noise", /* struct name */
+ NULL, /* free data */
+ NULL, /* copy data */
+ fcm_noise_new_data, /* new data */
+ NULL /*fcm_noise_verify*/, /* verify */
+ NULL, /* evaluate time */
+ fcm_noise_evaluate /* evaluate */
+};
+
+/* Filter F-Curve Modifier --------------------------- */
+
+#if 0 // XXX not yet implemented
+static FModifierTypeInfo FMI_FILTER = {
+ FMODIFIER_TYPE_FILTER, /* type */
+ sizeof(FMod_Filter), /* size */
+ FMI_TYPE_REPLACE_VALUES, /* action type */
+ 0, /* requirements */
+ "Filter", /* name */
+ "FMod_Filter", /* struct name */
+ NULL, /* free data */
+ NULL, /* copy data */
+ NULL, /* new data */
+ NULL /*fcm_filter_verify*/, /* verify */
+ NULL, /* evlauate time */
+ fcm_filter_evaluate /* evaluate */
+};
+#endif // XXX not yet implemented
+
+
+/* Python F-Curve Modifier --------------------------- */
+
+static void fcm_python_free (FModifier *fcm)
+{
+ FMod_Python *data= (FMod_Python *)fcm->data;
+
+ /* id-properties */
+ IDP_FreeProperty(data->prop);
+ MEM_freeN(data->prop);
+}
+
+static void fcm_python_new_data (void *mdata)
+{
+ FMod_Python *data= (FMod_Python *)mdata;
+
+ /* everything should be set correctly by calloc, except for the prop->type constant.*/
+ data->prop = MEM_callocN(sizeof(IDProperty), "PyFModifierProps");
+ data->prop->type = IDP_GROUP;
+}
+
+static void fcm_python_copy (FModifier *fcm, FModifier *src)
+{
+ FMod_Python *pymod = (FMod_Python *)fcm->data;
+ FMod_Python *opymod = (FMod_Python *)src->data;
+
+ pymod->prop = IDP_CopyProperty(opymod->prop);
+}
+
+static void fcm_python_evaluate (FCurve *fcu, FModifier *fcm, float *cvalue, float evaltime)
+{
+#ifndef DISABLE_PYTHON
+ //FMod_Python *data= (FMod_Python *)fcm->data;
+
+ /* FIXME... need to implement this modifier...
+ * It will need it execute a script using the custom properties
+ */
+#endif /* DISABLE_PYTHON */
+}
+
+static FModifierTypeInfo FMI_PYTHON = {
+ FMODIFIER_TYPE_PYTHON, /* type */
+ sizeof(FMod_Python), /* size */
+ FMI_TYPE_GENERATE_CURVE, /* action type */
+ FMI_REQUIRES_RUNTIME_CHECK, /* requirements */
+ "Python", /* name */
+ "FMod_Python", /* struct name */
+ fcm_python_free, /* free data */
+ fcm_python_copy, /* copy data */
+ fcm_python_new_data, /* new data */
+ NULL /*fcm_python_verify*/, /* verify */
+ NULL /*fcm_python_time*/, /* evaluate time */
+ fcm_python_evaluate /* evaluate */
+};
+
+
+/* Limits F-Curve Modifier --------------------------- */
+
+static float fcm_limits_time (FCurve *fcu, FModifier *fcm, float cvalue, float evaltime)
+{
+ FMod_Limits *data= (FMod_Limits *)fcm->data;
+
+ /* check for the time limits */
+ if ((data->flag & FCM_LIMIT_XMIN) && (evaltime < data->rect.xmin))
+ return data->rect.xmin;
+ if ((data->flag & FCM_LIMIT_XMAX) && (evaltime > data->rect.xmax))
+ return data->rect.xmax;
+
+ /* modifier doesn't change time */
+ return evaltime;
+}
+
+static void fcm_limits_evaluate (FCurve *fcu, FModifier *fcm, float *cvalue, float evaltime)
+{
+ FMod_Limits *data= (FMod_Limits *)fcm->data;
+
+ /* value limits now */
+ if ((data->flag & FCM_LIMIT_YMIN) && (*cvalue < data->rect.ymin))
+ *cvalue= data->rect.ymin;
+ if ((data->flag & FCM_LIMIT_YMAX) && (*cvalue > data->rect.ymax))
+ *cvalue= data->rect.ymax;
+}
+
+static FModifierTypeInfo FMI_LIMITS = {
+ FMODIFIER_TYPE_LIMITS, /* type */
+ sizeof(FMod_Limits), /* size */
+ FMI_TYPE_GENERATE_CURVE, /* action type */ /* XXX... err... */
+ FMI_REQUIRES_RUNTIME_CHECK, /* requirements */
+ "Limits", /* name */
+ "FMod_Limits", /* struct name */
+ NULL, /* free data */
+ NULL, /* copy data */
+ NULL, /* new data */
+ NULL, /* verify */
+ fcm_limits_time, /* evaluate time */
+ fcm_limits_evaluate /* evaluate */
+};
+
+/* F-Curve Modifier API --------------------------- */
+/* All of the F-Curve Modifier api functions use FModifierTypeInfo structs to carry out
+ * and operations that involve F-Curve modifier specific code.
+ */
+
+/* These globals only ever get directly accessed in this file */
+static FModifierTypeInfo *fmodifiersTypeInfo[FMODIFIER_NUM_TYPES];
+static short FMI_INIT= 1; /* when non-zero, the list needs to be updated */
+
+/* This function only gets called when FMI_INIT is non-zero */
+static void fmods_init_typeinfo ()
+{
+ fmodifiersTypeInfo[0]= NULL; /* 'Null' F-Curve Modifier */
+ fmodifiersTypeInfo[1]= &FMI_GENERATOR; /* Generator F-Curve Modifier */
+ fmodifiersTypeInfo[2]= &FMI_FN_GENERATOR; /* Built-In Function Generator F-Curve Modifier */
+ fmodifiersTypeInfo[3]= &FMI_ENVELOPE; /* Envelope F-Curve Modifier */
+ fmodifiersTypeInfo[4]= &FMI_CYCLES; /* Cycles F-Curve Modifier */
+ fmodifiersTypeInfo[5]= &FMI_NOISE; /* Apply-Noise F-Curve Modifier */
+ fmodifiersTypeInfo[6]= NULL/*&FMI_FILTER*/; /* Filter F-Curve Modifier */ // XXX unimplemented
+ fmodifiersTypeInfo[7]= &FMI_PYTHON; /* Custom Python F-Curve Modifier */
+ fmodifiersTypeInfo[8]= &FMI_LIMITS; /* Limits F-Curve Modifier */
+}
+
+/* This function should be used for getting the appropriate type-info when only
+ * a F-Curve modifier type is known
+ */
+FModifierTypeInfo *get_fmodifier_typeinfo (int type)
+{
+ /* initialise the type-info list? */
+ if (FMI_INIT) {
+ fmods_init_typeinfo();
+ FMI_INIT = 0;
+ }
+
+ /* only return for valid types */
+ if ( (type >= FMODIFIER_TYPE_NULL) &&
+ (type <= FMODIFIER_NUM_TYPES ) )
+ {
+ /* there shouldn't be any segfaults here... */
+ return fmodifiersTypeInfo[type];
+ }
+ else {
+ printf("No valid F-Curve Modifier type-info data available. Type = %i \n", type);
+ }
+
+ return NULL;
+}
+
+/* This function should always be used to get the appropriate type-info, as it
+ * has checks which prevent segfaults in some weird cases.
+ */
+FModifierTypeInfo *fmodifier_get_typeinfo (FModifier *fcm)
+{
+ /* only return typeinfo for valid modifiers */
+ if (fcm)
+ return get_fmodifier_typeinfo(fcm->type);
+ else
+ return NULL;
+}
+
+/* API --------------------------- */
+
+/* Add a new F-Curve Modifier to the given F-Curve of a certain type */
+FModifier *add_fmodifier (ListBase *modifiers, int type)
+{
+ FModifierTypeInfo *fmi= get_fmodifier_typeinfo(type);
+ FModifier *fcm;
+
+ /* sanity checks */
+ if ELEM(NULL, modifiers, fmi)
+ return NULL;
+
+ /* special checks for whether modifier can be added */
+ if ((modifiers->first) && (type == FMODIFIER_TYPE_CYCLES)) {
+ /* cycles modifier must be first in stack, so for now, don't add if it can't be */
+ // TODO: perhaps there is some better way, but for now,
+ printf("Error: Cannot add 'Cycles' modifier to F-Curve, as 'Cycles' modifier can only be first in stack. \n");
+ return NULL;
+ }
+
+ /* add modifier itself */
+ fcm= MEM_callocN(sizeof(FModifier), "F-Curve Modifier");
+ fcm->type = type;
+ fcm->flag = FMODIFIER_FLAG_EXPANDED;
+ BLI_addtail(modifiers, fcm);
+
+ /* add modifier's data */
+ fcm->data= MEM_callocN(fmi->size, fmi->structName);
+
+ /* init custom settings if necessary */
+ if (fmi->new_data)
+ fmi->new_data(fcm->data);
+
+ /* return modifier for further editing */
+ return fcm;
+}
+
+/* Duplicate all of the F-Modifiers in the Modifier stacks */
+void copy_fmodifiers (ListBase *dst, ListBase *src)
+{
+ FModifier *fcm, *srcfcm;
+
+ if ELEM(NULL, dst, src)
+ return;
+
+ dst->first= dst->last= NULL;
+ BLI_duplicatelist(dst, src);
+
+ for (fcm=dst->first, srcfcm=src->first; fcm && srcfcm; srcfcm=srcfcm->next, fcm=fcm->next) {
+ FModifierTypeInfo *fmi= fmodifier_get_typeinfo(fcm);
+
+ /* make a new copy of the F-Modifier's data */
+ fcm->data = MEM_dupallocN(fcm->data);
+
+ /* only do specific constraints if required */
+ if (fmi && fmi->copy_data)
+ fmi->copy_data(fcm, srcfcm);
+ }
+}
+
+/* Remove and free the given F-Modifier from the given stack */
+void remove_fmodifier (ListBase *modifiers, FModifier *fcm)
+{
+ FModifierTypeInfo *fmi= fmodifier_get_typeinfo(fcm);
+
+ /* sanity check */
+ if (fcm == NULL)
+ return;
+
+ /* free modifier's special data (stored inside fcm->data) */
+ if (fcm->data) {
+ if (fmi && fmi->free_data)
+ fmi->free_data(fcm);
+
+ /* free modifier's data (fcm->data) */
+ MEM_freeN(fcm->data);
+ }
+
+ /* remove modifier from stack */
+ if (modifiers)
+ BLI_freelinkN(modifiers, fcm);
+ else {
+ // XXX this case can probably be removed some day, as it shouldn't happen...
+ printf("remove_fmodifier() - no modifier stack given \n");
+ MEM_freeN(fcm);
+ }
+}
+
+/* Remove all of a given F-Curve's modifiers */
+void free_fmodifiers (ListBase *modifiers)
+{
+ FModifier *fcm, *fmn;
+
+ /* sanity check */
+ if (modifiers == NULL)
+ return;
+
+ /* free each modifier in order - modifier is unlinked from list and freed */
+ for (fcm= modifiers->first; fcm; fcm= fmn) {
+ fmn= fcm->next;
+ remove_fmodifier(modifiers, fcm);
+ }
+}
+
+/* Find the active F-Modifier */
+FModifier *find_active_fmodifier (ListBase *modifiers)
+{
+ FModifier *fcm;
+
+ /* sanity checks */
+ if ELEM(NULL, modifiers, modifiers->first)
+ return NULL;
+
+ /* loop over modifiers until 'active' one is found */
+ for (fcm= modifiers->first; fcm; fcm= fcm->next) {
+ if (fcm->flag & FMODIFIER_FLAG_ACTIVE)
+ return fcm;
+ }
+
+ /* no modifier is active */
+ return NULL;
+}
+
+/* Set the active F-Modifier */
+void set_active_fmodifier (ListBase *modifiers, FModifier *fcm)
+{
+ FModifier *fm;
+
+ /* sanity checks */
+ if ELEM(NULL, modifiers, modifiers->first)
+ return;
+
+ /* deactivate all, and set current one active */
+ for (fm= modifiers->first; fm; fm= fm->next)
+ fm->flag &= ~FMODIFIER_FLAG_ACTIVE;
+
+ /* make given modifier active */
+ if (fcm)
+ fcm->flag |= FMODIFIER_FLAG_ACTIVE;
+}
+
+/* Do we have any modifiers which match certain criteria
+ * - mtype - type of modifier (if 0, doesn't matter)
+ * - acttype - type of action to perform (if -1, doesn't matter)
+ */
+short list_has_suitable_fmodifier (ListBase *modifiers, int mtype, short acttype)
+{
+ FModifier *fcm;
+
+ /* if there are no specific filtering criteria, just skip */
+ if ((mtype == 0) && (acttype == 0))
+ return (modifiers && modifiers->first);
+
+ /* sanity checks */
+ if ELEM(NULL, modifiers, modifiers->first)
+ return 0;
+
+ /* find the first mdifier fitting these criteria */
+ for (fcm= modifiers->first; fcm; fcm= fcm->next) {
+ FModifierTypeInfo *fmi= fmodifier_get_typeinfo(fcm);
+ short mOk=1, aOk=1; /* by default 1, so that when only one test, won't fail */
+
+ /* check if applicable ones are fullfilled */
+ if (mtype)
+ mOk= (fcm->type == mtype);
+ if (acttype > -1)
+ aOk= (fmi->acttype == acttype);
+
+ /* if both are ok, we've found a hit */
+ if (mOk && aOk)
+ return 1;
+ }
+
+ /* no matches */
+ return 0;
+}
+
+/* Evaluation API --------------------------- */
+
+/* evaluate time modifications imposed by some F-Curve Modifiers
+ * - this step acts as an optimisation to prevent the F-Curve stack being evaluated
+ * several times by modifiers requesting the time be modified, as the final result
+ * would have required using the modified time
+ * - modifiers only ever recieve the unmodified time, as subsequent modifiers should be
+ * working on the 'global' result of the modified curve, not some localised segment,
+ * so nevaltime gets set to whatever the last time-modifying modifier likes...
+ * - we start from the end of the stack, as only the last one matters for now
+ */
+float evaluate_time_fmodifiers (ListBase *modifiers, FCurve *fcu, float cvalue, float evaltime)
+{
+ FModifier *fcm;
+ float m_evaltime= evaltime;
+
+ /* sanity checks */
+ if ELEM(NULL, modifiers, modifiers->last)
+ return evaltime;
+
+ /* find the first modifier from end of stack that modifies time, and calculate the time the modifier
+ * would calculate time at
+ */
+ for (fcm= modifiers->last; fcm; fcm= fcm->prev) {
+ FModifierTypeInfo *fmi= fmodifier_get_typeinfo(fcm);
+
+ /* only evaluate if there's a callback for this */
+ // TODO: implement the 'influence' control feature...
+ if (fmi && fmi->evaluate_modifier_time) {
+ if ((fcm->flag & (FMODIFIER_FLAG_DISABLED|FMODIFIER_FLAG_MUTED)) == 0)
+ m_evaltime= fmi->evaluate_modifier_time(fcu, fcm, cvalue, evaltime);
+ break;
+ }
+ }
+
+ /* return the modified evaltime */
+ return m_evaltime;
+}
+
+/* Evalautes the given set of F-Curve Modifiers using the given data
+ * Should only be called after evaluate_time_fmodifiers() has been called...
+ */
+void evaluate_value_fmodifiers (ListBase *modifiers, FCurve *fcu, float *cvalue, float evaltime)
+{
+ FModifier *fcm;
+
+ /* sanity checks */
+ if ELEM(NULL, modifiers, modifiers->first)
+ return;
+
+ /* evaluate modifiers */
+ for (fcm= modifiers->first; fcm; fcm= fcm->next) {
+ FModifierTypeInfo *fmi= fmodifier_get_typeinfo(fcm);
+
+ /* only evaluate if there's a callback for this */
+ // TODO: implement the 'influence' control feature...
+ if (fmi && fmi->evaluate_modifier) {
+ if ((fcm->flag & (FMODIFIER_FLAG_DISABLED|FMODIFIER_FLAG_MUTED)) == 0)
+ fmi->evaluate_modifier(fcu, fcm, cvalue, evaltime);
+ }
+ }
+}
+
+/* ---------- */
+
+/* Bake modifiers for given F-Curve to curve sample data, in the frame range defined
+ * by start and end (inclusive).
+ */
+void fcurve_bake_modifiers (FCurve *fcu, int start, int end)
+{
+ ChannelDriver *driver;
+
+ /* sanity checks */
+ // TODO: make these tests report errors using reports not printf's
+ if ELEM(NULL, fcu, fcu->modifiers.first) {
+ printf("Error: No F-Curve with F-Curve Modifiers to Bake\n");
+ return;
+ }
+
+ /* temporarily, disable driver while we sample, so that they don't influence the outcome */
+ driver= fcu->driver;
+ fcu->driver= NULL;
+
+ /* bake the modifiers, by sampling the curve at each frame */
+ fcurve_store_samples(fcu, NULL, start, end, fcurve_samplingcb_evalcurve);
+
+ /* free the modifiers now */
+ free_fmodifiers(&fcu->modifiers);
+
+ /* restore driver */
+ fcu->driver= driver;
+}
diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c
index 754ec06f23f..62af05fbc9a 100644
--- a/source/blender/blenkernel/intern/image.c
+++ b/source/blender/blenkernel/intern/image.c
@@ -456,19 +456,19 @@ static ImBuf *add_ibuf_size(int width, int height, char *name, int floatbuf, sho
* easy to tweak like this, speed isn't really that much of an issue in this situation... */
/* checkers */
- for(y=0; y<ibuf->y; y++) {
- dark = pow(-1, floor(y / checkerwidth));
+ for(y=0; y<height; y++) {
+ dark = powf(-1.0f, floorf(y / checkerwidth));
- for(x=0; x<ibuf->x; x++) {
+ for(x=0; x<width; x++) {
if (x % checkerwidth == 0) dark *= -1;
if (floatbuf) {
if (dark > 0) {
- rect_float[0] = rect_float[1] = rect_float[2] = 0.25;
- rect_float[3] = 1.0;
+ rect_float[0] = rect_float[1] = rect_float[2] = 0.25f;
+ rect_float[3] = 1.0f;
} else {
- rect_float[0] = rect_float[1] = rect_float[2] = 0.58;
- rect_float[3] = 1.0;
+ rect_float[0] = rect_float[1] = rect_float[2] = 0.58f;
+ rect_float[3] = 1.0f;
}
rect_float+=4;
}
@@ -489,11 +489,11 @@ static ImBuf *add_ibuf_size(int width, int height, char *name, int floatbuf, sho
if (floatbuf) rect_float= (float*)ibuf->rect_float;
else rect= (unsigned char*)ibuf->rect;
- for(y=0; y<ibuf->y; y++) {
- hoffs = 0.125 * floor(y / checkerwidth);
+ for(y=0; y<height; y++) {
+ hoffs = 0.125f * floorf(y / checkerwidth);
- for(x=0; x<ibuf->x; x++) {
- h = 0.125 * floor(x / checkerwidth);
+ for(x=0; x<width; x++) {
+ h = 0.125f * floorf(x / checkerwidth);
if ((fabs((x % checkerwidth) - (checkerwidth / 2)) < 4) &&
(fabs((y % checkerwidth) - (checkerwidth / 2)) < 4)) {
@@ -501,19 +501,19 @@ static ImBuf *add_ibuf_size(int width, int height, char *name, int floatbuf, sho
if ((fabs((x % checkerwidth) - (checkerwidth / 2)) < 1) ||
(fabs((y % checkerwidth) - (checkerwidth / 2)) < 1)) {
- hue = fmod(fabs(h-hoffs), 1.0);
+ hue = fmodf(fabs(h-hoffs), 1.0f);
hsv_to_rgb(hue, s, v, &r, &g, &b);
if (floatbuf) {
rect_float[0]= r;
rect_float[1]= g;
rect_float[2]= b;
- rect_float[3]= 1.0;
+ rect_float[3]= 1.0f;
}
else {
- rect[0]= (char)(r * 255.0);
- rect[1]= (char)(g * 255.0);
- rect[2]= (char)(b * 255.0);
+ rect[0]= (char)(r * 255.0f);
+ rect[1]= (char)(g * 255.0f);
+ rect[2]= (char)(b * 255.0f);
rect[3]= 255;
}
}
@@ -526,8 +526,15 @@ static ImBuf *add_ibuf_size(int width, int height, char *name, int floatbuf, sho
}
}
} else { /* blank image */
- for(y=0; y<ibuf->y; y++) {
- for(x=0; x<ibuf->x; x++) {
+ char ccol[4];
+
+ ccol[0]= (char)(color[0]*255.0f);
+ ccol[1]= (char)(color[1]*255.0f);
+ ccol[2]= (char)(color[2]*255.0f);
+ ccol[3]= (char)(color[3]*255.0f);
+
+ for(y=0; y<height; y++) {
+ for(x=0; x<width; x++) {
if (floatbuf) {
rect_float[0]= color[0];
rect_float[1]= color[1];
@@ -536,10 +543,10 @@ static ImBuf *add_ibuf_size(int width, int height, char *name, int floatbuf, sho
rect_float+=4;
}
else {
- rect[0]= (char)(color[0] * 255.0);
- rect[1]= (char)(color[1] * 255.0);
- rect[2]= (char)(color[2] * 255.0);
- rect[3]= (char)(color[3] * 255.0);
+ rect[0]= ccol[0];
+ rect[1]= ccol[1];
+ rect[2]= ccol[2];
+ rect[3]= ccol[3];
rect+=4;
}
}
@@ -860,6 +867,9 @@ int BKE_imtype_is_movie(int imtype)
case R_AVICODEC:
case R_QUICKTIME:
case R_FFMPEG:
+ case R_H264:
+ case R_THEORA:
+ case R_XVID:
case R_FRAMESERVER:
return 1;
}
@@ -870,7 +880,7 @@ void BKE_add_image_extension(Scene *scene, char *string, int imtype)
{
char *extension="";
- if(scene->r.imtype== R_IRIS) {
+ if(imtype== R_IRIS) {
if(!BLI_testextensie(string, ".rgb"))
extension= ".rgb";
}
@@ -882,7 +892,7 @@ void BKE_add_image_extension(Scene *scene, char *string, int imtype)
if(!BLI_testextensie(string, ".hdr"))
extension= ".hdr";
}
- else if(imtype==R_PNG || imtype==R_FFMPEG) {
+ else if (ELEM5(imtype, R_PNG, R_FFMPEG, R_H264, R_THEORA, R_XVID)) {
if(!BLI_testextensie(string, ".png"))
extension= ".png";
}
@@ -1230,7 +1240,7 @@ int BKE_write_ibuf(Scene *scene, ImBuf *ibuf, char *name, int imtype, int subimt
else if ((imtype==R_RADHDR)) {
ibuf->ftype= RADHDR;
}
- else if (imtype==R_PNG || imtype==R_FFMPEG) {
+ else if (ELEM5(imtype, R_PNG, R_FFMPEG, R_H264, R_THEORA, R_XVID)) {
ibuf->ftype= PNG;
}
#ifdef WITH_DDS
@@ -1305,7 +1315,7 @@ int BKE_write_ibuf(Scene *scene, ImBuf *ibuf, char *name, int imtype, int subimt
BLI_make_existing_file(name);
- if(scene->r.scemode & R_STAMP_INFO)
+ if(scene->r.stamp & R_STAMP_ALL)
BKE_stamp_info(scene, ibuf);
ok = IMB_saveiff(ibuf, name, IB_rect | IB_zbuf | IB_zbuffloat);
diff --git a/source/blender/blenkernel/intern/ipo.c b/source/blender/blenkernel/intern/ipo.c
index 54618813a0b..cf7e486613b 100644
--- a/source/blender/blenkernel/intern/ipo.c
+++ b/source/blender/blenkernel/intern/ipo.c
@@ -58,6 +58,7 @@
#include "DNA_key_types.h"
#include "DNA_material_types.h"
#include "DNA_mesh_types.h"
+#include "DNA_nla_types.h"
#include "DNA_object_types.h"
#include "DNA_object_force.h"
#include "DNA_particle_types.h"
@@ -85,6 +86,7 @@
#include "BKE_library.h"
#include "BKE_main.h"
#include "BKE_mesh.h"
+#include "BKE_nla.h"
#include "BKE_object.h"
@@ -825,6 +827,10 @@ char *get_rna_access (int blocktype, int adrcode, char actname[], char constname
char buf[512];
int dummy_index= 0;
+ /* hack: if constname is set, we can only be dealing with an Constraint curve */
+ if (constname)
+ blocktype= ID_CO;
+
/* get property name based on blocktype */
switch (blocktype) {
case ID_OB: /* object */
@@ -840,7 +846,7 @@ char *get_rna_access (int blocktype, int adrcode, char actname[], char constname
break;
case ID_CO: /* constraint */
- propname= constraint_adrcodes_to_paths(adrcode, &dummy_index);
+ propname= constraint_adrcodes_to_paths(adrcode, &dummy_index);
break;
case ID_TE: /* texture */
@@ -870,7 +876,10 @@ char *get_rna_access (int blocktype, int adrcode, char actname[], char constname
/* XXX problematic blocktypes */
case ID_CU: /* curve */
- propname= "speed"; // XXX this was a 'dummy curve' that didn't really correspond to any real var...
+ /* this used to be a 'dummy' curve which got evaluated on the fly...
+ * now we've got real var for this!
+ */
+ propname= "eval_time";
break;
case ID_SEQ: /* sequencer strip */
@@ -1144,7 +1153,7 @@ static void icu_to_fcurves (ListBase *groups, ListBase *list, IpoCurve *icu, cha
/* Add a new FModifier (Cyclic) instead of setting extend value
* as that's the new equivilant of that option.
*/
- FModifier *fcm= fcurve_add_modifier(fcu, FMODIFIER_TYPE_CYCLES);
+ FModifier *fcm= add_fmodifier(&fcu->modifiers, FMODIFIER_TYPE_CYCLES);
FMod_Cycles *data= (FMod_Cycles *)fcm->data;
/* if 'offset' one is in use, set appropriate settings */
@@ -1463,6 +1472,87 @@ static void action_to_animdata (ID *id, bAction *act)
action_to_animato(act, &adt->action->groups, &adt->action->curves, &adt->drivers);
}
+/* ------------------------- */
+
+// TODO:
+// - NLA group duplicators info
+// - NLA curve/stride modifiers...
+
+/* Convert NLA-Strip to new system */
+static void nlastrips_to_animdata (ID *id, ListBase *strips)
+{
+ AnimData *adt= BKE_animdata_from_id(id);
+ NlaTrack *nlt = NULL;
+ NlaStrip *strip;
+ bActionStrip *as, *asn;
+
+ /* for each one of the original strips, convert to a new strip and free the old... */
+ for (as= strips->first; as; as= asn) {
+ asn= as->next;
+
+ /* this old strip is only worth something if it had an action... */
+ if (as->act) {
+ /* convert Action data (if not yet converted), storing the results in the same Action */
+ action_to_animato(as->act, &as->act->groups, &as->act->curves, &adt->drivers);
+
+ /* create a new-style NLA-strip which references this Action, then copy over relevant settings */
+ {
+ /* init a new strip, and assign the action to it
+ * - no need to muck around with the user-counts, since this is just
+ * passing over the ref to the new owner, not creating an additional ref
+ */
+ strip= MEM_callocN(sizeof(NlaStrip), "NlaStrip");
+ strip->act= as->act;
+
+ /* endpoints */
+ strip->start= as->start;
+ strip->end= as->end;
+ strip->actstart= as->actstart;
+ strip->actend= as->actend;
+
+ /* action reuse */
+ strip->repeat= as->repeat;
+ strip->scale= as->scale;
+ if (as->flag & ACTSTRIP_LOCK_ACTION) strip->flag |= NLASTRIP_FLAG_SYNC_LENGTH;
+
+ /* blending */
+ strip->blendin= as->blendin;
+ strip->blendout= as->blendout;
+ strip->blendmode= (as->mode==ACTSTRIPMODE_ADD) ? NLASTRIP_MODE_ADD : NLASTRIP_MODE_REPLACE;
+ if (as->flag & ACTSTRIP_AUTO_BLENDS) strip->flag |= NLASTRIP_FLAG_AUTO_BLENDS;
+
+ /* assorted setting flags */
+ if (as->flag & ACTSTRIP_SELECT) strip->flag |= NLASTRIP_FLAG_SELECT;
+ if (as->flag & ACTSTRIP_ACTIVE) strip->flag |= NLASTRIP_FLAG_ACTIVE;
+
+ if (as->flag & ACTSTRIP_MUTE) strip->flag |= NLASTRIP_FLAG_MUTED;
+ if (as->flag & ACTSTRIP_REVERSE) strip->flag |= NLASTRIP_FLAG_REVERSE;
+
+ /* by default, we now always extrapolate, while in the past this was optional */
+ if ((as->flag & ACTSTRIP_HOLDLASTFRAME)==0)
+ strip->extendmode= NLASTRIP_EXTEND_NOTHING;
+ }
+
+ /* try to add this strip to the current NLA-Track (i.e. the 'last' one on the stack atm) */
+ if (BKE_nlatrack_add_strip(nlt, strip) == 0) {
+ /* trying to add to the current failed (no space),
+ * so add a new track to the stack, and add to that...
+ */
+ nlt= add_nlatrack(adt, NULL);
+ BKE_nlatrack_add_strip(nlt, strip);
+ }
+ }
+
+ /* modifiers */
+ // FIXME: for now, we just free them...
+ if (as->modifiers.first)
+ BLI_freelistN(&as->modifiers);
+
+ /* free the old strip */
+ BLI_freelinkN(strips, as);
+ }
+}
+
/* *************************************************** */
/* External API - Only Called from do_versions() */
@@ -1509,7 +1599,30 @@ void do_versions_ipos_to_animato(Main *main)
if (G.f & G_DEBUG) printf("\tconverting ob %s \n", id->name+2);
/* check if object has any animation data */
- if ((ob->ipo) || (ob->action) || (ob->nlastrips.first)) {
+ if (ob->nlastrips.first) {
+ /* Add AnimData block */
+ adt= BKE_id_add_animdata(id);
+
+ /* IPO first to take into any non-NLA'd Object Animation */
+ if (ob->ipo) {
+ ipo_to_animdata(id, ob->ipo, NULL, NULL);
+
+ ob->ipo->id.us--;
+ ob->ipo= NULL;
+ }
+
+ /* Action is skipped since it'll be used by some strip in the NLA anyway,
+ * causing errors with evaluation in the new evaluation pipeline
+ */
+ if (ob->action) {
+ ob->action->id.us--;
+ ob->action= NULL;
+ }
+
+ /* finally NLA */
+ nlastrips_to_animdata(id, &ob->nlastrips);
+ }
+ else if ((ob->ipo) || (ob->action)) {
/* Add AnimData block */
adt= BKE_id_add_animdata(id);
@@ -1530,9 +1643,6 @@ void do_versions_ipos_to_animato(Main *main)
ob->ipo->id.us--;
ob->ipo= NULL;
}
-
- /* finally NLA */
- // XXX todo... for now, new NLA code not hooked up yet, so keep old stuff (but not for too long!)
}
/* check PoseChannels for constraints with local data */
diff --git a/source/blender/blenkernel/intern/material.c b/source/blender/blenkernel/intern/material.c
index 57b88bb0b3f..08a19cada7d 100644
--- a/source/blender/blenkernel/intern/material.c
+++ b/source/blender/blenkernel/intern/material.c
@@ -43,6 +43,7 @@
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "DNA_texture_types.h"
+#include "DNA_userdef_types.h"
#include "BLI_blenlib.h"
#include "BLI_arithb.h"
@@ -79,10 +80,6 @@ void free_material(Material *ma)
{
MTex *mtex;
int a;
-
-#ifndef DISABLE_PYTHON
- BPY_free_scriptlink(&ma->scriptlink);
-#endif
for(a=0; a<MAX_MTEX; a++) {
mtex= ma->mtex[a];
@@ -209,10 +206,6 @@ Material *copy_material(Material *ma)
id_us_plus((ID *)man->mtex[a]->tex);
}
}
-
-#ifndef DISABLE_PYTHON
- BPY_copy_scriptlink(&ma->scriptlink);
-#endif
if(ma->ramp_col) man->ramp_col= MEM_dupallocN(ma->ramp_col);
if(ma->ramp_spec) man->ramp_spec= MEM_dupallocN(ma->ramp_spec);
@@ -445,7 +438,7 @@ Material *give_current_material(Object *ob, int act)
if(act>ob->totcol) act= ob->totcol;
else if(act<=0) act= 1;
- if( BTST(ob->colbits, act-1) ) { /* in object */
+ if(ob->matbits[act-1]) { /* in object */
ma= ob->mat[act-1];
}
else { /* in data */
@@ -473,7 +466,7 @@ ID *material_from(Object *ob, int act)
if(ob->totcol==0) return ob->data;
if(act==0) act= 1;
- if( BTST(ob->colbits, act-1) ) return (ID *)ob;
+ if(ob->matbits[act-1]) return (ID *)ob;
else return ob->data;
}
@@ -498,6 +491,7 @@ void test_object_materials(ID *id)
Curve *cu;
MetaBall *mb;
Material **newmatar;
+ char *newmatbits;
int totcol=0;
if(id==0) return;
@@ -524,16 +518,22 @@ void test_object_materials(ID *id)
if(totcol==0) {
if(ob->totcol) {
MEM_freeN(ob->mat);
- ob->mat= 0;
+ MEM_freeN(ob->matbits);
+ ob->mat= NULL;
+ ob->matbits= NULL;
}
}
else if(ob->totcol<totcol) {
newmatar= MEM_callocN(sizeof(void *)*totcol, "newmatar");
+ newmatbits= MEM_callocN(sizeof(char)*totcol, "newmatbits");
if(ob->totcol) {
memcpy(newmatar, ob->mat, sizeof(void *)*ob->totcol);
+ memcpy(newmatbits, ob->matbits, sizeof(char)*ob->totcol);
MEM_freeN(ob->mat);
+ MEM_freeN(ob->matbits);
}
ob->mat= newmatar;
+ ob->matbits= newmatbits;
}
ob->totcol= totcol;
if(ob->totcol && ob->actcol==0) ob->actcol= 1;
@@ -547,6 +547,7 @@ void test_object_materials(ID *id)
void assign_material(Object *ob, Material *ma, int act)
{
Material *mao, **matar, ***matarar;
+ char *matbits;
short *totcolp;
if(act>MAXMAT) return;
@@ -559,29 +560,41 @@ void assign_material(Object *ob, Material *ma, int act)
if(totcolp==0 || matarar==0) return;
- if( act > *totcolp) {
+ if(act > *totcolp) {
matar= MEM_callocN(sizeof(void *)*act, "matarray1");
- if( *totcolp) {
- memcpy(matar, *matarar, sizeof(void *)*( *totcolp ));
+
+ if(*totcolp) {
+ memcpy(matar, *matarar, sizeof(void *)*(*totcolp));
MEM_freeN(*matarar);
}
+
*matarar= matar;
*totcolp= act;
}
if(act > ob->totcol) {
matar= MEM_callocN(sizeof(void *)*act, "matarray2");
+ matbits= MEM_callocN(sizeof(char)*act, "matbits1");
if( ob->totcol) {
memcpy(matar, ob->mat, sizeof(void *)*( ob->totcol ));
+ memcpy(matbits, ob->matbits, sizeof(char)*(*totcolp));
MEM_freeN(ob->mat);
+ MEM_freeN(ob->matbits);
}
ob->mat= matar;
+ ob->matbits= matbits;
ob->totcol= act;
+
+ /* copy object/mesh linking, or assign based on userpref */
+ if(ob->actcol)
+ ob->matbits[act-1]= ob->matbits[ob->actcol-1];
+ else
+ ob->matbits[act-1]= (U.flag & USER_MAT_ON_OB)? 1: 0;
}
/* do it */
- if( BTST(ob->colbits, act-1) ) { /* in object */
+ if(ob->matbits[act-1]) { /* in object */
mao= ob->mat[act-1];
if(mao) mao->id.us--;
ob->mat[act-1]= ma;
@@ -591,7 +604,9 @@ void assign_material(Object *ob, Material *ma, int act)
if(mao) mao->id.us--;
(*matarar)[act-1]= ma;
}
- id_us_plus((ID *)ma);
+
+ if(ma)
+ id_us_plus((ID *)ma);
test_object_materials(ob->data);
}
@@ -623,19 +638,7 @@ void object_add_material_slot(Object *ob)
if(ob->totcol>=MAXMAT) return;
ma= give_current_material(ob, ob->actcol);
- if(ma==NULL)
- ma= add_material("Material");
- else
- ma= copy_material(ma);
-
- ma->id.us= 0; /* eeh... */
-
- if(ob->actcol) {
- if( BTST(ob->colbits, ob->actcol-1) ) {
- ob->colbits= BSET(ob->colbits, ob->totcol);
- }
- }
-
+
assign_material(ob, ma, ob->totcol+1);
ob->actcol= ob->totcol;
}
@@ -660,6 +663,7 @@ static void do_init_render_material(Material *ma, int r_mode, float *amb)
ma->mapto |= mtex->mapto;
if(r_mode & R_OSA) {
if ELEM3(mtex->tex->type, TEX_IMAGE, TEX_PLUGIN, TEX_ENVMAP) ma->texco |= TEXCO_OSA;
+ else if(mtex->texflag & MTEX_NEW_BUMP) ma->texco |= TEXCO_OSA; // NEWBUMP: need texture derivatives for procedurals as well
}
if(ma->texco & (TEXCO_ORCO|TEXCO_REFL|TEXCO_NORM|TEXCO_STRAND|TEXCO_STRESS)) needuv= 1;
@@ -880,9 +884,8 @@ void object_remove_material_slot(Object *ob)
if(mao) mao->id.us--;
}
- for(a=ob->actcol; a<ob->totcol; a++) {
+ for(a=ob->actcol; a<ob->totcol; a++)
(*matarar)[a-1]= (*matarar)[a];
- }
(*totcolp)--;
if(*totcolp==0) {
@@ -900,13 +903,18 @@ void object_remove_material_slot(Object *ob)
mao= obt->mat[actcol-1];
if(mao) mao->id.us--;
- for(a=actcol; a<obt->totcol; a++) obt->mat[a-1]= obt->mat[a];
+ for(a=actcol; a<obt->totcol; a++) {
+ obt->mat[a-1]= obt->mat[a];
+ obt->matbits[a-1]= obt->matbits[a];
+ }
obt->totcol--;
if(obt->actcol > obt->totcol) obt->actcol= obt->totcol;
if(obt->totcol==0) {
MEM_freeN(obt->mat);
+ MEM_freeN(obt->matbits);
obt->mat= 0;
+ obt->matbits= NULL;
}
}
obt= obt->id.next;
diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c
index 3facf975992..c7454d3b832 100644
--- a/source/blender/blenkernel/intern/mesh.c
+++ b/source/blender/blenkernel/intern/mesh.c
@@ -795,6 +795,8 @@ void nurbs_to_mesh(Object *ob)
dl= cu->disp.first;
while(dl) {
+ int smooth= dl->rt & CU_SMOOTH ? 1 : 0;
+
if(dl->type==DL_SEGM) {
startvert= vertcount;
a= dl->parts*dl->nr;
@@ -811,6 +813,7 @@ void nurbs_to_mesh(Object *ob)
for(b=1; b<dl->nr; b++) {
mface->v1= startvert+ofs+b-1;
mface->v2= startvert+ofs+b;
+ if(smooth) mface->flag |= ME_SMOOTH;
mface++;
}
}
@@ -835,6 +838,7 @@ void nurbs_to_mesh(Object *ob)
mface->v1= startvert+ofs+b;
if(b==dl->nr-1) mface->v2= startvert+ofs;
else mface->v2= startvert+ofs+b+1;
+ if(smooth) mface->flag |= ME_SMOOTH;
mface++;
}
}
@@ -860,6 +864,7 @@ void nurbs_to_mesh(Object *ob)
mface->v4= 0;
test_index_face(mface, NULL, 0, 3);
+ if(smooth) mface->flag |= ME_SMOOTH;
mface++;
index+= 3;
}
@@ -907,6 +912,8 @@ void nurbs_to_mesh(Object *ob)
mface->v4= p2;
mface->mat_nr= (unsigned char)dl->col;
test_index_face(mface, NULL, 0, 4);
+
+ if(smooth) mface->flag |= ME_SMOOTH;
mface++;
p4= p3;
diff --git a/source/blender/blenkernel/intern/modifier.c b/source/blender/blenkernel/intern/modifier.c
index 046dfcc9f87..d86d563aaa2 100644
--- a/source/blender/blenkernel/intern/modifier.c
+++ b/source/blender/blenkernel/intern/modifier.c
@@ -58,6 +58,7 @@
#include "DNA_cloth_types.h"
#include "DNA_curve_types.h"
#include "DNA_effect_types.h"
+#include "DNA_group_types.h"
#include "DNA_material_types.h"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
@@ -67,6 +68,7 @@
#include "DNA_object_force.h"
#include "DNA_particle_types.h"
#include "DNA_scene_types.h"
+#include "DNA_smoke_types.h"
#include "DNA_texture_types.h"
#include "BLI_editVert.h"
@@ -96,6 +98,7 @@
#include "BKE_object.h"
#include "BKE_particle.h"
#include "BKE_pointcache.h"
+#include "BKE_smoke.h"
#include "BKE_softbody.h"
#include "BKE_subsurf.h"
#include "BKE_texture.h"
@@ -5069,7 +5072,7 @@ static void waveModifier_initData(ModifierData *md)
wmd->map_object = NULL;
wmd->height= 0.5f;
wmd->width= 1.5f;
- wmd->speed= 0.5f;
+ wmd->speed= 0.25f;
wmd->narrow= 1.5f;
wmd->lifetime= 0.0f;
wmd->damp= 10.0f;
@@ -5787,6 +5790,100 @@ static int softbodyModifier_dependsOnTime(ModifierData *md)
return 1;
}
+/* Smoke */
+
+static void smokeModifier_initData(ModifierData *md)
+{
+ SmokeModifierData *smd = (SmokeModifierData*) md;
+
+ smd->domain = NULL;
+ smd->flow = NULL;
+ smd->coll = NULL;
+ smd->type = 0;
+ smd->time = -1;
+
+ /*
+ smd->fluid = NULL;
+ smd->maxres = 48;
+ smd->amplify = 4;
+ smd->omega = 0.5;
+ smd->time = 0;
+ smd->flags = 0;
+ smd->noise = MOD_SMOKE_NOISEWAVE;
+ smd->visibility = 1;
+
+ // init 3dview buffer
+ smd->tvox = NULL;
+ smd->tray = NULL;
+ smd->tvoxbig = NULL;
+ smd->traybig = NULL;
+ smd->viewsettings = 0;
+ smd->bind = NULL;
+ smd->max_textures = 0;
+ */
+}
+
+static void smokeModifier_freeData(ModifierData *md)
+{
+ SmokeModifierData *smd = (SmokeModifierData*) md;
+
+ smokeModifier_free (smd);
+}
+
+static void smokeModifier_deformVerts(
+ ModifierData *md, Object *ob, DerivedMesh *derivedData,
+ float (*vertexCos)[3], int numVerts, int useRenderParams, int isFinalCalc)
+{
+ SmokeModifierData *smd = (SmokeModifierData*) md;
+ DerivedMesh *dm = NULL;
+
+ if(derivedData) dm = derivedData;
+ else if(ob->type == OB_MESH) dm = CDDM_from_mesh(ob->data, ob);
+ else return;
+
+ CDDM_apply_vert_coords(dm, vertexCos);
+ CDDM_calc_normals(dm);
+
+ smokeModifier_do(smd, md->scene, ob, dm);
+
+ if(dm != derivedData) dm->release(dm);
+}
+
+static int smokeModifier_dependsOnTime(ModifierData *md)
+{
+ return 1;
+}
+
+static void smokeModifier_updateDepgraph(
+ ModifierData *md, DagForest *forest, Scene *scene, Object *ob,
+ DagNode *obNode)
+{
+ SmokeModifierData *smd = (SmokeModifierData *) md;
+ /*
+ if(smd && (smd->type & MOD_SMOKE_TYPE_DOMAIN) && smd->domain)
+ {
+ if(smd->domain->fluid_group)
+ {
+ GroupObject *go = NULL;
+
+ for(go = smd->domain->fluid_group->gobject.first; go; go = go->next)
+ {
+ if(go->ob)
+ {
+ SmokeModifierData *smd2 = (SmokeModifierData *)modifiers_findByType(go->ob, eModifierType_Smoke);
+
+ // check for initialized smoke object
+ if(smd2 && (smd2->type & MOD_SMOKE_TYPE_FLOW) && smd2->flow)
+ {
+ DagNode *curNode = dag_get_node(forest, go->ob);
+ dag_add_relation(forest, curNode, obNode, DAG_RL_DATA_DATA|DAG_RL_OB_DATA, "Smoke Flow");
+ }
+ }
+ }
+ }
+ }
+ */
+}
/* Cloth */
@@ -6113,9 +6210,14 @@ static void surfaceModifier_freeData(ModifierData *md)
MEM_freeN(surmd->bvhtree);
}
- if(surmd->dm)
- surmd->dm->release(surmd->dm);
+ surmd->dm->release(surmd->dm);
+
+ if(surmd->x)
+ MEM_freeN(surmd->x);
+ if(surmd->v)
+ MEM_freeN(surmd->v);
+
surmd->bvhtree = NULL;
surmd->dm = NULL;
}
@@ -6128,7 +6230,7 @@ static int surfaceModifier_dependsOnTime(ModifierData *md)
static void surfaceModifier_deformVerts(
ModifierData *md, Object *ob, DerivedMesh *derivedData,
- float (*vertexCos)[3], int numVerts, int useRenderParams, int isFinalCalc)
+ float (*vertexCos)[3], int numVerts, int useRenderParams, int isFinalCalc)
{
SurfaceModifierData *surmd = (SurfaceModifierData*) md;
unsigned int numverts = 0, i = 0;
@@ -6148,14 +6250,47 @@ static void surfaceModifier_deformVerts(
if(surmd->dm)
{
+ int init = 0;
+ float *vec;
+ MVert *x, *v;
+
CDDM_apply_vert_coords(surmd->dm, vertexCos);
CDDM_calc_normals(surmd->dm);
numverts = surmd->dm->getNumVerts ( surmd->dm );
- /* convert to global coordinates */
- for(i = 0; i<numverts; i++)
- Mat4MulVecfl(ob->obmat, CDDM_get_vert(surmd->dm, i)->co);
+ if(numverts != surmd->numverts || surmd->x == NULL || surmd->v == NULL || md->scene->r.cfra != surmd->cfra+1) {
+ if(surmd->x) {
+ MEM_freeN(surmd->x);
+ surmd->x = NULL;
+ }
+ if(surmd->v) {
+ MEM_freeN(surmd->v);
+ surmd->v = NULL;
+ }
+
+ surmd->x = MEM_callocN(numverts * sizeof(MVert), "MVert");
+ surmd->v = MEM_callocN(numverts * sizeof(MVert), "MVert");
+
+ surmd->numverts = numverts;
+
+ init = 1;
+ }
+
+ /* convert to global coordinates and calculate velocity */
+ for(i = 0, x = surmd->x, v = surmd->v; i<numverts; i++, x++, v++) {
+ vec = CDDM_get_vert(surmd->dm, i)->co;
+ Mat4MulVecfl(ob->obmat, vec);
+
+ if(init)
+ v->co[0] = v->co[1] = v->co[2] = 0.0f;
+ else
+ VecSubf(v->co, vec, x->co);
+
+ VecCopyf(x->co, vec);
+ }
+
+ surmd->cfra = md->scene->r.cfra;
if(surmd->bvhtree)
free_bvhtree_from_mesh(surmd->bvhtree);
@@ -8439,6 +8574,15 @@ ModifierTypeInfo *modifierType_getInfo(ModifierType type)
| eModifierTypeFlag_Single;
mti->deformVerts = softbodyModifier_deformVerts;
mti->dependsOnTime = softbodyModifier_dependsOnTime;
+
+ mti = INIT_TYPE(Smoke);
+ mti->type = eModifierTypeType_OnlyDeform;
+ mti->initData = smokeModifier_initData;
+ mti->freeData = smokeModifier_freeData;
+ mti->flags = eModifierTypeFlag_AcceptsMesh;
+ mti->deformVerts = smokeModifier_deformVerts;
+ mti->dependsOnTime = smokeModifier_dependsOnTime;
+ mti->updateDepgraph = smokeModifier_updateDepgraph;
mti = INIT_TYPE(Cloth);
mti->type = eModifierTypeType_Nonconstructive;
diff --git a/source/blender/blenkernel/intern/multires.c b/source/blender/blenkernel/intern/multires.c
index 5def910ddef..22a471f6521 100644
--- a/source/blender/blenkernel/intern/multires.c
+++ b/source/blender/blenkernel/intern/multires.c
@@ -101,7 +101,7 @@ void multiresModifier_join(Object *ob)
/* First find the highest level of subdivision */
base = FIRSTBASE;
while(base) {
- if(TESTBASELIB_BGMODE(base) && base->object->type==OB_MESH) {
+ if(TESTBASELIB_BGMODE(v3d, base) && base->object->type==OB_MESH) {
ModifierData *md;
for(md = base->object->modifiers.first; md; md = md->next) {
if(md->type == eModifierType_Multires) {
@@ -124,7 +124,7 @@ void multiresModifier_join(Object *ob)
/* Subdivide all the displacements to the highest level */
base = FIRSTBASE;
while(base) {
- if(TESTBASELIB_BGMODE(base) && base->object->type==OB_MESH) {
+ if(TESTBASELIB_BGMODE(v3d, base) && base->object->type==OB_MESH) {
ModifierData *md = NULL;
MultiresModifierData *mmd = NULL;
diff --git a/source/blender/blenkernel/intern/nla.c b/source/blender/blenkernel/intern/nla.c
index dc2bf26759f..1871ec006f4 100644
--- a/source/blender/blenkernel/intern/nla.c
+++ b/source/blender/blenkernel/intern/nla.c
@@ -17,171 +17,1506 @@
* 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.
+ * The Original Code is Copyright (C) 2009 Blender Foundation, Joshua Leung
* All rights reserved.
*
* The Original Code is: all of this file.
*
- * Contributor(s): none yet.
+ * Contributor(s): Joshua Leung (full recode)
*
* ***** END GPL LICENSE BLOCK *****
*/
#include <stdlib.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+#include <float.h>
#include "MEM_guardedalloc.h"
#include "BLI_blenlib.h"
+#include "BLI_ghash.h"
-#include "DNA_space_types.h"
-#include "DNA_nla_types.h"
+#include "DNA_anim_types.h"
#include "DNA_action_types.h"
-#include "DNA_ID.h"
-#include "DNA_ipo_types.h"
-#include "DNA_object_types.h"
-#include "BKE_nla.h"
+#include "BKE_animsys.h"
#include "BKE_action.h"
+#include "BKE_fcurve.h"
+#include "BKE_nla.h"
#include "BKE_blender.h"
#include "BKE_library.h"
-#include "BKE_object.h" /* for convert_action_to_strip(ob) */
+#include "BKE_object.h"
+#include "BKE_utildefines.h"
+
+#include "RNA_access.h"
+#include "nla_private.h"
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
-/* NOTE: in group.c the strips get copied for group-nla override, this assumes
- that strips are one single block, without additional data to be copied */
-void copy_actionstrip (bActionStrip **dst, bActionStrip **src){
- bActionStrip *dstrip;
- bActionStrip *sstrip = *src;
+/* *************************************************** */
+/* Data Management */
- if (!*src){
- *dst=NULL;
+/* Freeing ------------------------------------------- */
+
+/* Remove the given NLA strip from the NLA track it occupies, free the strip's data,
+ * and the strip itself.
+ */
+void free_nlastrip (ListBase *strips, NlaStrip *strip)
+{
+ NlaStrip *cs, *csn;
+
+ /* sanity checks */
+ if (strip == NULL)
return;
+
+ /* free child-strips */
+ for (cs= strip->strips.first; cs; cs= csn) {
+ csn= cs->next;
+ free_nlastrip(&strip->strips, cs);
}
+
+ /* remove reference to action */
+ if (strip->act)
+ strip->act->id.us--;
+
+ /* free remapping info */
+ //if (strip->remap)
+ // BKE_animremap_free();
+
+ /* free own F-Curves */
+ free_fcurves(&strip->fcurves);
+
+ /* free own F-Modifiers */
+ free_fmodifiers(&strip->modifiers);
+
+ /* free the strip itself */
+ if (strips)
+ BLI_freelinkN(strips, strip);
+ else
+ MEM_freeN(strip);
+}
- *dst = MEM_dupallocN(sstrip);
+/* Remove the given NLA track from the set of NLA tracks, free the track's data,
+ * and the track itself.
+ */
+void free_nlatrack (ListBase *tracks, NlaTrack *nlt)
+{
+ NlaStrip *strip, *stripn;
+
+ /* sanity checks */
+ if (nlt == NULL)
+ return;
+
+ /* free strips */
+ for (strip= nlt->strips.first; strip; strip= stripn) {
+ stripn= strip->next;
+ free_nlastrip(&nlt->strips, strip);
+ }
+
+ /* free NLA track itself now */
+ if (tracks)
+ BLI_freelinkN(tracks, nlt);
+ else
+ MEM_freeN(nlt);
+}
- dstrip = *dst;
- if (dstrip->act)
- dstrip->act->id.us++;
+/* Free the elements of type NLA Tracks provided in the given list, but do not free
+ * the list itself since that is not free-standing
+ */
+void free_nladata (ListBase *tracks)
+{
+ NlaTrack *nlt, *nltn;
+
+ /* sanity checks */
+ if ELEM(NULL, tracks, tracks->first)
+ return;
+
+ /* free tracks one by one */
+ for (nlt= tracks->first; nlt; nlt= nltn) {
+ nltn= nlt->next;
+ free_nlatrack(tracks, nlt);
+ }
+
+ /* clear the list's pointers to be safe */
+ tracks->first= tracks->last= NULL;
+}
- if (dstrip->ipo)
- dstrip->ipo->id.us++;
+/* Copying ------------------------------------------- */
+
+/* Copy NLA strip */
+NlaStrip *copy_nlastrip (NlaStrip *strip)
+{
+ NlaStrip *strip_d;
+ NlaStrip *cs, *cs_d;
+
+ /* sanity check */
+ if (strip == NULL)
+ return NULL;
+
+ /* make a copy */
+ strip_d= MEM_dupallocN(strip);
+ strip_d->next= strip_d->prev= NULL;
- if (dstrip->modifiers.first) {
- BLI_duplicatelist (&dstrip->modifiers, &sstrip->modifiers);
+ /* increase user-count of action */
+ if (strip_d->act)
+ strip_d->act->id.us++;
+
+ /* copy F-Curves and modifiers */
+ copy_fcurves(&strip_d->fcurves, &strip->fcurves);
+ copy_fmodifiers(&strip_d->modifiers, &strip->modifiers);
+
+ /* make a copy of all the child-strips, one at a time */
+ strip_d->strips.first= strip_d->strips.last= NULL;
+
+ for (cs= strip->strips.first; cs; cs= cs->next) {
+ cs_d= copy_nlastrip(cs);
+ BLI_addtail(&strip_d->strips, cs_d);
}
+ /* return the strip */
+ return strip_d;
}
-void copy_nlastrips (ListBase *dst, ListBase *src)
+/* Copy NLA Track */
+NlaTrack *copy_nlatrack (NlaTrack *nlt)
{
- bActionStrip *strip;
+ NlaStrip *strip, *strip_d;
+ NlaTrack *nlt_d;
+
+ /* sanity check */
+ if (nlt == NULL)
+ return NULL;
+
+ /* make a copy */
+ nlt_d= MEM_dupallocN(nlt);
+ nlt_d->next= nlt_d->prev= NULL;
+
+ /* make a copy of all the strips, one at a time */
+ nlt_d->strips.first= nlt_d->strips.last= NULL;
+
+ for (strip= nlt->strips.first; strip; strip= strip->next) {
+ strip_d= copy_nlastrip(strip);
+ BLI_addtail(&nlt_d->strips, strip_d);
+ }
+
+ /* return the copy */
+ return nlt_d;
+}
- dst->first=dst->last=NULL;
+/* Copy all NLA data */
+void copy_nladata (ListBase *dst, ListBase *src)
+{
+ NlaTrack *nlt, *nlt_d;
+
+ /* sanity checks */
+ if ELEM(NULL, dst, src)
+ return;
+
+ /* copy each NLA-track, one at a time */
+ for (nlt= src->first; nlt; nlt= nlt->next) {
+ /* make a copy, and add the copy to the destination list */
+ nlt_d= copy_nlatrack(nlt);
+ BLI_addtail(dst, nlt_d);
+ }
+}
- BLI_duplicatelist (dst, src);
+/* Adding ------------------------------------------- */
- /* Update specific data */
- if (!dst->first)
- return;
+/* Add a NLA Track to the given AnimData
+ * - prev: NLA-Track to add the new one after
+ */
+NlaTrack *add_nlatrack (AnimData *adt, NlaTrack *prev)
+{
+ NlaTrack *nlt;
+
+ /* sanity checks */
+ if (adt == NULL)
+ return NULL;
+
+ /* allocate new track */
+ nlt= MEM_callocN(sizeof(NlaTrack), "NlaTrack");
+
+ /* set settings requiring the track to not be part of the stack yet */
+ nlt->flag = NLATRACK_SELECTED;
+ nlt->index= BLI_countlist(&adt->nla_tracks);
+
+ /* add track to stack, and make it the active one */
+ if (prev)
+ BLI_insertlinkafter(&adt->nla_tracks, prev, nlt);
+ else
+ BLI_addtail(&adt->nla_tracks, nlt);
+ BKE_nlatrack_set_active(&adt->nla_tracks, nlt);
+
+ /* must have unique name, but we need to seed this */
+ sprintf(nlt->name, "NlaTrack");
+ BLI_uniquename(&adt->nla_tracks, nlt, "NlaTrack", '.', offsetof(NlaTrack, name), 64);
+
+ /* return the new track */
+ return nlt;
+}
- for (strip = dst->first; strip; strip=strip->next){
- if (strip->act)
- strip->act->id.us++;
- if (strip->ipo)
- strip->ipo->id.us++;
- if (strip->modifiers.first) {
- ListBase listb;
- BLI_duplicatelist (&listb, &strip->modifiers);
- strip->modifiers= listb;
+/* Add a NLA Strip referencing the given Action */
+NlaStrip *add_nlastrip (bAction *act)
+{
+ NlaStrip *strip;
+
+ /* sanity checks */
+ if (act == NULL)
+ return NULL;
+
+ /* allocate new strip */
+ strip= MEM_callocN(sizeof(NlaStrip), "NlaStrip");
+
+ /* generic settings
+ * - selected flag to highlight this to the user
+ * - auto-blends to ensure that blend in/out values are automatically
+ * determined by overlaps of strips
+ * - (XXX) synchronisation of strip-length in accordance with changes to action-length
+ * is not done though, since this should only really happens in editmode for strips now
+ * though this decision is still subject to further review...
+ */
+ strip->flag = NLASTRIP_FLAG_SELECT|NLASTRIP_FLAG_AUTO_BLENDS;
+
+ /* assign the action reference */
+ strip->act= act;
+ id_us_plus(&act->id);
+
+ /* determine initial range
+ * - strip length cannot be 0... ever...
+ */
+ calc_action_range(strip->act, &strip->actstart, &strip->actend, 1);
+
+ strip->start = strip->actstart;
+ strip->end = (IS_EQ(strip->actstart, strip->actend)) ? (strip->actstart + 1.0f): (strip->actend);
+
+ /* strip should be referenced as-is */
+ strip->scale= 1.0f;
+ strip->repeat = 1.0f;
+
+ /* return the new strip */
+ return strip;
+}
+
+/* Add new NLA-strip to the top of the NLA stack - i.e. into the last track if space, or a new one otherwise */
+NlaStrip *add_nlastrip_to_stack (AnimData *adt, bAction *act)
+{
+ NlaStrip *strip;
+ NlaTrack *nlt;
+
+ /* sanity checks */
+ if ELEM(NULL, adt, act)
+ return NULL;
+
+ /* create a new NLA strip */
+ strip= add_nlastrip(act);
+ if (strip == NULL)
+ return NULL;
+
+ /* firstly try adding strip to last track, but if that fails, add to a new track */
+ if (BKE_nlatrack_add_strip(adt->nla_tracks.last, strip) == 0) {
+ /* trying to add to the last track failed (no track or no space),
+ * so add a new track to the stack, and add to that...
+ */
+ nlt= add_nlatrack(adt, NULL);
+ BKE_nlatrack_add_strip(nlt, strip);
+ }
+
+ /* automatically name it too */
+ BKE_nlastrip_validate_name(adt, strip);
+
+ /* returns the strip added */
+ return strip;
+}
+
+/* *************************************************** */
+/* NLA Evaluation <-> Editing Stuff */
+
+/* Strip Mapping ------------------------------------- */
+
+/* non clipped mapping for strip-time <-> global time (for Action-Clips)
+ * invert = convert action-strip time to global time
+ */
+static float nlastrip_get_frame_actionclip (NlaStrip *strip, float cframe, short mode)
+{
+ float actlength, repeat, scale;
+
+ /* get number of repeats */
+ if (IS_EQ(strip->repeat, 0.0f)) strip->repeat = 1.0f;
+ repeat = strip->repeat;
+
+ /* scaling */
+ if (IS_EQ(strip->scale, 0.0f)) strip->scale= 1.0f;
+ scale = (float)fabs(strip->scale); /* scale must be positive - we've got a special flag for reversing */
+
+ /* length of referenced action */
+ actlength = strip->actend - strip->actstart;
+ if (IS_EQ(actlength, 0.0f)) actlength = 1.0f;
+
+ /* reversed = play strip backwards */
+ if (strip->flag & NLASTRIP_FLAG_REVERSE) {
+ // FIXME: this won't work right with Graph Editor?
+ if (mode == NLATIME_CONVERT_MAP) {
+ return strip->end - scale*(cframe - strip->actstart);
+ }
+ else if (mode == NLATIME_CONVERT_UNMAP) {
+ int repeatsNum = (int)((cframe - strip->start) / (actlength * scale));
+
+ /* this method doesn't clip the values to lie within the action range only
+ * - the '(repeatsNum * actlength * scale)' compensates for the fmod(...)
+ * - the fmod(...) works in the same way as for eval
+ */
+ return strip->actend - (repeatsNum * actlength * scale)
+ - (fmod(cframe - strip->start, actlength*scale) / scale);
+ }
+ else /* if (mode == NLATIME_CONVERT_EVAL) */{
+ if (IS_EQ(cframe, strip->end) && IS_EQ(strip->repeat, ((int)strip->repeat))) {
+ /* this case prevents the motion snapping back to the first frame at the end of the strip
+ * by catching the case where repeats is a whole number, which means that the end of the strip
+ * could also be interpreted as the end of the start of a repeat
+ */
+ return strip->actstart;
+ }
+ else {
+ /* - the 'fmod(..., actlength*scale)' is needed to get the repeats working
+ * - the '/ scale' is needed to ensure that scaling influences the timing within the repeat
+ */
+ return strip->actend - fmod(cframe - strip->start, actlength*scale) / scale;
+ }
+ }
+ }
+ else {
+ if (mode == NLATIME_CONVERT_MAP) {
+ return strip->start + scale*(cframe - strip->actstart);
+ }
+ else if (mode == NLATIME_CONVERT_UNMAP) {
+ int repeatsNum = (int)((cframe - strip->start) / (actlength * scale));
+
+ /* this method doesn't clip the values to lie within the action range only
+ * - the '(repeatsNum * actlength * scale)' compensates for the fmod(...)
+ * - the fmod(...) works in the same way as for eval
+ */
+ return strip->actstart + (repeatsNum * actlength * scale)
+ + (fmod(cframe - strip->start, actlength*scale) / scale);
+ }
+ else /* if (mode == NLATIME_CONVERT_EVAL) */{
+ if (IS_EQ(cframe, strip->end) && IS_EQ(strip->repeat, ((int)strip->repeat))) {
+ /* this case prevents the motion snapping back to the first frame at the end of the strip
+ * by catching the case where repeats is a whole number, which means that the end of the strip
+ * could also be interpreted as the end of the start of a repeat
+ */
+ return strip->actend;
+ }
+ else {
+ /* - the 'fmod(..., actlength*scale)' is needed to get the repeats working
+ * - the '/ scale' is needed to ensure that scaling influences the timing within the repeat
+ */
+ return strip->actstart + fmod(cframe - strip->start, actlength*scale) / scale;
+ }
}
}
}
-/* from editnla, for convert_action_to_strip -- no UI code so should be ok here.. */
-void find_stridechannel(Object *ob, bActionStrip *strip)
+/* non clipped mapping for strip-time <-> global time (for Transitions)
+ * invert = convert action-strip time to global time
+ */
+static float nlastrip_get_frame_transition (NlaStrip *strip, float cframe, short mode)
{
- if(ob && ob->pose) {
- bPoseChannel *pchan;
- for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next)
- if(pchan->flag & POSE_STRIDE)
- break;
- if(pchan)
- BLI_strncpy(strip->stridechannel, pchan->name, 32);
+ float length;
+
+ /* length of strip */
+ length= strip->end - strip->start;
+
+ /* reversed = play strip backwards */
+ if (strip->flag & NLASTRIP_FLAG_REVERSE) {
+ if (mode == NLATIME_CONVERT_MAP)
+ return strip->end - (length * cframe);
else
- strip->stridechannel[0]= 0;
+ return (strip->end - cframe) / length;
}
+ else {
+ if (mode == NLATIME_CONVERT_MAP)
+ return (length * cframe) + strip->start;
+ else
+ return (cframe - strip->start) / length;
+ }
+}
+
+/* non clipped mapping for strip-time <-> global time
+ * mode = eNlaTime_ConvertModes[] -> NLATIME_CONVERT_*
+ *
+ * only secure for 'internal' (i.e. within AnimSys evaluation) operations,
+ * but should not be directly relied on for stuff which interacts with editors
+ */
+float nlastrip_get_frame (NlaStrip *strip, float cframe, short mode)
+{
+ switch (strip->type) {
+ case NLASTRIP_TYPE_META: /* meta - for now, does the same as transition (is really just an empty container) */
+ case NLASTRIP_TYPE_TRANSITION: /* transition */
+ return nlastrip_get_frame_transition(strip, cframe, mode);
+
+ case NLASTRIP_TYPE_CLIP: /* action-clip (default) */
+ default:
+ return nlastrip_get_frame_actionclip(strip, cframe, mode);
+ }
}
-//called by convert_nla / bpy api with an object with the action to be converted to a new strip
-bActionStrip *convert_action_to_strip (Object *ob)
+
+/* Non clipped mapping for strip-time <-> global time
+ * mode = eNlaTime_ConvertModesp[] -> NLATIME_CONVERT_*
+ *
+ * Public API method - perform this mapping using the given AnimData block
+ * and perform any necessary sanity checks on the value
+ */
+float BKE_nla_tweakedit_remap (AnimData *adt, float cframe, short mode)
{
- bActionStrip *nstrip;
+ NlaStrip *strip;
+
+ /* sanity checks
+ * - obviously we've got to have some starting data
+ * - when not in tweakmode, the active Action does not have any scaling applied :)
+ * - when in tweakmode, if the no-mapping flag is set, do not map
+ */
+ if ((adt == NULL) || (adt->flag & ADT_NLA_EDIT_ON)==0 || (adt->flag & ADT_NLA_EDIT_NOMAP))
+ return cframe;
+
+ /* if the active-strip info has been stored already, access this, otherwise look this up
+ * and store for (very probable) future usage
+ */
+ if (adt->actstrip == NULL) {
+ NlaTrack *nlt= BKE_nlatrack_find_active(&adt->nla_tracks);
+ adt->actstrip= BKE_nlastrip_find_active(nlt);
+ }
+ strip= adt->actstrip;
+
+ /* sanity checks
+ * - in rare cases, we may not be able to find this strip for some reason (internal error)
+ * - for now, if the user has defined a curve to control the time, this correction cannot be performed
+ * reliably...
+ */
+ if ((strip == NULL) || (strip->flag & NLASTRIP_FLAG_USR_TIME))
+ return cframe;
+
+ /* perform the correction now... */
+ return nlastrip_get_frame(strip, cframe, mode);
+}
+
+/* *************************************************** */
+/* NLA API */
+
+/* List of Strips ------------------------------------ */
+/* (these functions are used for NLA-Tracks and also for nested/meta-strips) */
+
+/* Check if there is any space in the given list to add the given strip */
+short BKE_nlastrips_has_space (ListBase *strips, float start, float end)
+{
+ NlaStrip *strip;
+
+ /* sanity checks */
+ if ((strips == NULL) || IS_EQ(start, end))
+ return 0;
+ if (start > end) {
+ puts("BKE_nlastrips_has_space() error... start and end arguments swapped");
+ SWAP(float, start, end);
+ }
+
+ /* loop over NLA strips checking for any overlaps with this area... */
+ for (strip= strips->first; strip; strip= strip->next) {
+ /* if start frame of strip is past the target end-frame, that means that
+ * we've gone past the window we need to check for, so things are fine
+ */
+ if (strip->start > end)
+ return 1;
+
+ /* if the end of the strip is greater than either of the boundaries, the range
+ * must fall within the extents of the strip
+ */
+ if ((strip->end > start) || (strip->end > end))
+ return 0;
+ }
+
+ /* if we are still here, we haven't encountered any overlapping strips */
+ return 1;
+}
+
+/* Rearrange the strips in the track so that they are always in order
+ * (usually only needed after a strip has been moved)
+ */
+void BKE_nlastrips_sort_strips (ListBase *strips)
+{
+ ListBase tmp = {NULL, NULL};
+ NlaStrip *strip, *sstrip, *stripn;
+
+ /* sanity checks */
+ if ELEM(NULL, strips, strips->first)
+ return;
+
+ /* we simply perform insertion sort on this list, since it is assumed that per track,
+ * there are only likely to be at most 5-10 strips
+ */
+ for (strip= strips->first; strip; strip= stripn) {
+ short not_added = 1;
+
+ stripn= strip->next;
+
+ /* remove this strip from the list, and add it to the new list, searching from the end of
+ * the list, assuming that the lists are in order
+ */
+ BLI_remlink(strips, strip);
+
+ for (sstrip= tmp.last; sstrip; sstrip= sstrip->prev) {
+ /* check if add after */
+ if (sstrip->end <= strip->start) {
+ BLI_insertlinkafter(&tmp, sstrip, strip);
+ not_added= 0;
+ break;
+ }
+ }
+
+ /* add before first? */
+ if (not_added)
+ BLI_addhead(&tmp, strip);
+ }
+
+ /* reassign the start and end points of the strips */
+ strips->first= tmp.first;
+ strips->last= tmp.last;
+}
+
+/* Add the given NLA-Strip to the given list of strips, assuming that it
+ * isn't currently a member of another list
+ */
+short BKE_nlastrips_add_strip (ListBase *strips, NlaStrip *strip)
+{
+ NlaStrip *ns;
+ short not_added = 1;
+
+ /* sanity checks */
+ if ELEM(NULL, strips, strip)
+ return 0;
+
+ /* check if any space to add */
+ if (BKE_nlastrips_has_space(strips, strip->start, strip->end)==0)
+ return 0;
+
+ /* find the right place to add the strip to the nominated track */
+ for (ns= strips->first; ns; ns= ns->next) {
+ /* if current strip occurs after the new strip, add it before */
+ if (ns->start > strip->end) {
+ BLI_insertlinkbefore(strips, ns, strip);
+ not_added= 0;
+ break;
+ }
+ }
+ if (not_added) {
+ /* just add to the end of the list of the strips then... */
+ BLI_addtail(strips, strip);
+ }
+
+ /* added... */
+ return 1;
+}
- /* Make new actionstrip */
- nstrip = MEM_callocN(sizeof(bActionStrip), "bActionStrip");
+
+/* Meta-Strips ------------------------------------ */
+
+/* Convert 'islands' (i.e. continuous string of) selected strips to be
+ * contained within 'Meta-Strips' which act as strips which contain strips.
+ * temp: are the meta-strips to be created 'temporary' ones used for transforms?
+ */
+void BKE_nlastrips_make_metas (ListBase *strips, short temp)
+{
+ NlaStrip *mstrip = NULL;
+ NlaStrip *strip, *stripn;
+
+ /* sanity checks */
+ if ELEM(NULL, strips, strips->first)
+ return;
+
+ /* group all continuous chains of selected strips into meta-strips */
+ for (strip= strips->first; strip; strip= stripn) {
+ stripn= strip->next;
+
+ if (strip->flag & NLASTRIP_FLAG_SELECT) {
+ /* if there is an existing meta-strip, add this strip to it, otherwise, create a new one */
+ if (mstrip == NULL) {
+ /* add a new meta-strip, and add it before the current strip that it will replace... */
+ mstrip= MEM_callocN(sizeof(NlaStrip), "Meta-NlaStrip");
+ mstrip->type = NLASTRIP_TYPE_META;
+ BLI_insertlinkbefore(strips, strip, mstrip);
+
+ /* set flags */
+ mstrip->flag = NLASTRIP_FLAG_SELECT;
+
+ /* set temp flag if appropriate (i.e. for transform-type editing) */
+ if (temp)
+ mstrip->flag |= NLASTRIP_FLAG_TEMP_META;
+
+ /* set default repeat/scale values to prevent warnings */
+ mstrip->repeat= mstrip->scale= 1.0f;
+
+ /* make its start frame be set to the start frame of the current strip */
+ mstrip->start= strip->start;
+ }
+
+ /* remove the selected strips from the track, and add to the meta */
+ BLI_remlink(strips, strip);
+ BLI_addtail(&mstrip->strips, strip);
+
+ /* expand the meta's dimensions to include the newly added strip- i.e. its last frame */
+ mstrip->end= strip->end;
+ }
+ else {
+ /* current strip wasn't selected, so the end of 'island' of selected strips has been reached,
+ * so stop adding strips to the current meta
+ */
+ mstrip= NULL;
+ }
+ }
+}
+
+/* Split a meta-strip into a set of normal strips */
+void BKE_nlastrips_clear_metastrip (ListBase *strips, NlaStrip *strip)
+{
+ NlaStrip *cs, *csn;
+
+ /* sanity check */
+ if ELEM(NULL, strips, strip)
+ return;
+
+ /* move each one of the meta-strip's children before the meta-strip
+ * in the list of strips after unlinking them from the meta-strip
+ */
+ for (cs= strip->strips.first; cs; cs= csn) {
+ csn= cs->next;
+ BLI_remlink(&strip->strips, cs);
+ BLI_insertlinkbefore(strips, strip, cs);
+ }
+
+ /* free the meta-strip now */
+ BLI_freelinkN(strips, strip);
+}
+
+/* Remove meta-strips (i.e. flatten the list of strips) from the top-level of the list of strips
+ * sel: only consider selected meta-strips, otherwise all meta-strips are removed
+ * onlyTemp: only remove the 'temporary' meta-strips used for transforms
+ */
+void BKE_nlastrips_clear_metas (ListBase *strips, short onlySel, short onlyTemp)
+{
+ NlaStrip *strip, *stripn;
+
+ /* sanity checks */
+ if ELEM(NULL, strips, strips->first)
+ return;
+
+ /* remove meta-strips fitting the criteria of the arguments */
+ for (strip= strips->first; strip; strip= stripn) {
+ stripn= strip->next;
+
+ /* check if strip is a meta-strip */
+ if (strip->type == NLASTRIP_TYPE_META) {
+ /* if check if selection and 'temporary-only' considerations are met */
+ if ((onlySel==0) || (strip->flag & NLASTRIP_FLAG_SELECT)) {
+ if ((!onlyTemp) || (strip->flag & NLASTRIP_FLAG_TEMP_META)) {
+ BKE_nlastrips_clear_metastrip(strips, strip);
+ }
+ }
+ }
+ }
+}
+
+/* Add the given NLA-Strip to the given Meta-Strip, assuming that the
+ * strip isn't attached to anyy list of strips
+ */
+short BKE_nlameta_add_strip (NlaStrip *mstrip, NlaStrip *strip)
+{
+ /* sanity checks */
+ if ELEM(NULL, mstrip, strip)
+ return 0;
+
+ /* firstly, check if the meta-strip has space for this */
+ if (BKE_nlastrips_has_space(&mstrip->strips, strip->start, strip->end) == 0)
+ return 0;
+
+ /* check if this would need to be added to the ends of the meta,
+ * and subsequently, if the neighbouring strips allow us enough room
+ */
+ if (strip->start < mstrip->start) {
+ /* check if strip to the left (if it exists) ends before the
+ * start of the strip we're trying to add
+ */
+ if ((mstrip->prev == NULL) || (mstrip->prev->end <= strip->start)) {
+ /* add strip to start of meta's list, and expand dimensions */
+ BLI_addhead(&mstrip->strips, strip);
+ mstrip->start= strip->start;
+
+ return 1;
+ }
+ else /* failed... no room before */
+ return 0;
+ }
+ else if (strip->end > mstrip->end) {
+ /* check if strip to the right (if it exists) starts before the
+ * end of the strip we're trying to add
+ */
+ if ((mstrip->next == NULL) || (mstrip->next->start >= strip->end)) {
+ /* add strip to end of meta's list, and expand dimensions */
+ BLI_addtail(&mstrip->strips, strip);
+ mstrip->end= strip->end;
+
+ return 1;
+ }
+ else /* failed... no room after */
+ return 0;
+ }
+ else {
+ /* just try to add to the meta-strip (no dimension changes needed) */
+ return BKE_nlastrips_add_strip(&mstrip->strips, strip);
+ }
+}
+
+/* Adjust the settings of NLA-Strips contained within a Meta-Strip (recursively),
+ * until the Meta-Strips children all fit within the Meta-Strip's new dimensions
+ */
+void BKE_nlameta_flush_transforms (NlaStrip *mstrip)
+{
+ NlaStrip *strip;
+ float oStart, oEnd, offset;
+ float oLen, nLen;
+ short scaleChanged= 0;
+
+ /* sanity checks
+ * - strip must exist
+ * - strip must be a meta-strip with some contents
+ */
+ if ELEM(NULL, mstrip, mstrip->strips.first)
+ return;
+ if (mstrip->type != NLASTRIP_TYPE_META)
+ return;
+
+ /* get the original start/end points, and calculate the start-frame offset
+ * - these are simply the start/end frames of the child strips,
+ * since we assume they weren't transformed yet
+ */
+ oStart= ((NlaStrip *)mstrip->strips.first)->start;
+ oEnd= ((NlaStrip *)mstrip->strips.last)->end;
+ offset= mstrip->start - oStart;
+
+ /* optimisation:
+ * don't flush if nothing changed yet
+ * TODO: maybe we need a flag to say always flush?
+ */
+ if (IS_EQ(oStart, mstrip->start) && IS_EQ(oEnd, mstrip->end))
+ return;
+
+ /* check if scale changed */
+ oLen = oEnd - oStart;
+ nLen = mstrip->end - mstrip->start;
+ if (IS_EQ(nLen, oLen) == 0)
+ scaleChanged= 1;
+
+ /* for each child-strip, calculate new start/end points based on this new info */
+ for (strip= mstrip->strips.first; strip; strip= strip->next) {
+ if (scaleChanged) {
+ PointerRNA ptr;
+ float p1, p2, nStart, nEnd;
+
+ /* compute positions of endpoints relative to old extents of strip */
+ p1= (strip->start - oStart) / oLen;
+ p2= (strip->end - oStart) / oLen;
- /* Link the action to the nstrip */
- nstrip->act = ob->action;
- id_us_plus(&nstrip->act->id);
- calc_action_range(nstrip->act, &nstrip->actstart, &nstrip->actend, 1);
- nstrip->start = nstrip->actstart;
- nstrip->end = nstrip->actend;
- nstrip->flag = ACTSTRIP_SELECT|ACTSTRIP_LOCK_ACTION;
+ /* compute the new strip endpoints using the proportions */
+ nStart= (p1 * nLen) + mstrip->start;
+ nEnd= (p2 * nLen) + mstrip->start;
- find_stridechannel(ob, nstrip);
- //set_active_strip(ob, nstrip); /* is in editnla as does UI calls */
+ /* firstly, apply the new positions manually, then apply using RNA
+ * - first time is to make sure no truncation errors from one endpoint not being
+ * set yet occur
+ * - second time is to make sure scale is computed properly...
+ */
+ strip->start= nStart;
+ strip->end= nEnd;
- nstrip->repeat = 1.0;
+ RNA_pointer_create(NULL, &RNA_NlaStrip, strip, &ptr);
+ RNA_float_set(&ptr, "start_frame", nStart);
+ RNA_float_set(&ptr, "end_frame", nEnd);
+ }
+ else {
+ /* just apply the changes in offset to both ends of the strip */
+ strip->start += offset;
+ strip->end += offset;
+ }
+
+ /* finally, make sure the strip's children (if it is a meta-itself), get updated */
+ BKE_nlameta_flush_transforms(strip);
+ }
+}
- if(ob->nlastrips.first == NULL)
- ob->nlaflag |= OB_NLA_OVERRIDE;
+/* NLA-Tracks ---------------------------------------- */
+
+/* Find the active NLA-track for the given stack */
+NlaTrack *BKE_nlatrack_find_active (ListBase *tracks)
+{
+ NlaTrack *nlt;
- BLI_addtail(&ob->nlastrips, nstrip);
- return nstrip; /* is created, malloced etc. here so is safe to just return the pointer?
- this is needed for setting this active in UI, and probably useful for API too */
+ /* sanity check */
+ if ELEM(NULL, tracks, tracks->first)
+ return NULL;
+
+ /* try to find the first active track */
+ for (nlt= tracks->first; nlt; nlt= nlt->next) {
+ if (nlt->flag & NLATRACK_ACTIVE)
+ return nlt;
+ }
+ /* none found */
+ return NULL;
}
+/* Toggle the 'solo' setting for the given NLA-track, making sure that it is the only one
+ * that has this status in its AnimData block.
+ */
+void BKE_nlatrack_solo_toggle (AnimData *adt, NlaTrack *nlt)
+{
+ NlaTrack *nt;
+
+ /* sanity check */
+ if ELEM(NULL, adt, adt->nla_tracks.first)
+ return;
+
+ /* firstly, make sure 'solo' flag for all tracks is disabled */
+ for (nt= adt->nla_tracks.first; nt; nt= nt->next) {
+ if (nt != nlt)
+ nt->flag &= ~NLATRACK_SOLO;
+ }
+
+ /* now, enable 'solo' for the given track if appropriate */
+ if (nlt) {
+ /* toggle solo status */
+ nlt->flag ^= NLATRACK_SOLO;
+
+ /* set or clear solo-status on AnimData */
+ if (nlt->flag & NLATRACK_SOLO)
+ adt->flag |= ADT_NLA_SOLO_TRACK;
+ else
+ adt->flag &= ~ADT_NLA_SOLO_TRACK;
+ }
+ else
+ adt->flag &= ~ADT_NLA_SOLO_TRACK;
+}
-/* not strip itself! */
-void free_actionstrip(bActionStrip* strip)
+/* Make the given NLA-track the active one for the given stack. If no track is provided,
+ * this function can be used to simply deactivate all the NLA tracks in the given stack too.
+ */
+void BKE_nlatrack_set_active (ListBase *tracks, NlaTrack *nlt_a)
{
- if (!strip)
+ NlaTrack *nlt;
+
+ /* sanity check */
+ if ELEM(NULL, tracks, tracks->first)
return;
+
+ /* deactive all the rest */
+ for (nlt= tracks->first; nlt; nlt= nlt->next)
+ nlt->flag &= ~NLATRACK_ACTIVE;
+
+ /* set the given one as the active one */
+ if (nlt_a)
+ nlt_a->flag |= NLATRACK_ACTIVE;
+}
- if (strip->act){
- strip->act->id.us--;
- strip->act = NULL;
+/* Check if there is any space in the given track to add a strip of the given length */
+short BKE_nlatrack_has_space (NlaTrack *nlt, float start, float end)
+{
+ /* sanity checks */
+ if ((nlt == NULL) || IS_EQ(start, end))
+ return 0;
+ if (start > end) {
+ puts("BKE_nlatrack_has_space() error... start and end arguments swapped");
+ SWAP(float, start, end);
+ }
+
+ /* check if there's any space left in the track for a strip of the given length */
+ return BKE_nlastrips_has_space(&nlt->strips, start, end);
+}
+
+/* Rearrange the strips in the track so that they are always in order
+ * (usually only needed after a strip has been moved)
+ */
+void BKE_nlatrack_sort_strips (NlaTrack *nlt)
+{
+ /* sanity checks */
+ if ELEM(NULL, nlt, nlt->strips.first)
+ return;
+
+ /* sort the strips with a more generic function */
+ BKE_nlastrips_sort_strips(&nlt->strips);
+}
+
+/* Add the given NLA-Strip to the given NLA-Track, assuming that it
+ * isn't currently attached to another one
+ */
+short BKE_nlatrack_add_strip (NlaTrack *nlt, NlaStrip *strip)
+{
+ /* sanity checks */
+ if ELEM(NULL, nlt, strip)
+ return 0;
+
+ /* try to add the strip to the track using a more generic function */
+ return BKE_nlastrips_add_strip(&nlt->strips, strip);
+}
+
+/* NLA Strips -------------------------------------- */
+
+/* Find the active NLA-strip within the given track */
+NlaStrip *BKE_nlastrip_find_active (NlaTrack *nlt)
+{
+ NlaStrip *strip;
+
+ /* sanity check */
+ if ELEM(NULL, nlt, nlt->strips.first)
+ return NULL;
+
+ /* try to find the first active strip */
+ for (strip= nlt->strips.first; strip; strip= strip->next) {
+ if (strip->flag & NLASTRIP_FLAG_ACTIVE)
+ return strip;
}
- if (strip->ipo){
- strip->ipo->id.us--;
- strip->ipo = NULL;
+
+ /* none found */
+ return NULL;
+}
+
+/* Does the given NLA-strip fall within the given bounds (times)? */
+short BKE_nlastrip_within_bounds (NlaStrip *strip, float min, float max)
+{
+ const float stripLen= (strip) ? strip->end - strip->start : 0.0f;
+ const float boundsLen= (float)fabs(max - min);
+
+ /* sanity checks */
+ if ((strip == NULL) || IS_EQ(stripLen, 0.0f) || IS_EQ(boundsLen, 0.0f))
+ return 0;
+
+ /* only ok if at least part of the strip is within the bounding window
+ * - first 2 cases cover when the strip length is less than the bounding area
+ * - second 2 cases cover when the strip length is greater than the bounding area
+ */
+ if ( (stripLen < boundsLen) &&
+ !(IN_RANGE(strip->start, min, max) ||
+ IN_RANGE(strip->end, min, max)) )
+ {
+ return 0;
}
- if (strip->modifiers.first) {
- BLI_freelistN(&strip->modifiers);
+ if ( (stripLen > boundsLen) &&
+ !(IN_RANGE(min, strip->start, strip->end) ||
+ IN_RANGE(max, strip->start, strip->end)) )
+ {
+ return 0;
}
+ /* should be ok! */
+ return 1;
}
-void free_nlastrips (ListBase *nlalist)
+/* Is the given NLA-strip the first one to occur for the given AnimData block */
+// TODO: make this an api method if necesary, but need to add prefix first
+short nlastrip_is_first (AnimData *adt, NlaStrip *strip)
{
- bActionStrip *strip;
+ NlaTrack *nlt;
+ NlaStrip *ns;
+
+ /* sanity checks */
+ if ELEM(NULL, adt, strip)
+ return 0;
+
+ /* check if strip has any strips before it */
+ if (strip->prev)
+ return 0;
+
+ /* check other tracks to see if they have a strip that's earlier */
+ // TODO: or should we check that the strip's track is also the first?
+ for (nlt= adt->nla_tracks.first; nlt; nlt= nlt->next) {
+ /* only check the first strip, assuming that they're all in order */
+ ns= nlt->strips.first;
+ if (ns) {
+ if (ns->start < strip->start)
+ return 0;
+ }
+ }
+
+ /* should be first now */
+ return 1;
+}
+
+/* Animated Strips ------------------------------------------- */
- if (!nlalist->first)
+/* Check if the given NLA-Track has any strips with own F-Curves */
+short BKE_nlatrack_has_animated_strips (NlaTrack *nlt)
+{
+ NlaStrip *strip;
+
+ /* sanity checks */
+ if ELEM(NULL, nlt, nlt->strips.first)
+ return 0;
+
+ /* check each strip for F-Curves only (don't care about whether the flags are set) */
+ for (strip= nlt->strips.first; strip; strip= strip->next) {
+ if (strip->fcurves.first)
+ return 1;
+ }
+
+ /* none found */
+ return 0;
+}
+
+/* Check if given NLA-Tracks have any strips with own F-Curves */
+short BKE_nlatracks_have_animated_strips (ListBase *tracks)
+{
+ NlaTrack *nlt;
+
+ /* sanity checks */
+ if ELEM(NULL, tracks, tracks->first)
+ return 0;
+
+ /* check each track, stopping on the first hit */
+ for (nlt= tracks->first; nlt; nlt= nlt->next) {
+ if (BKE_nlatrack_has_animated_strips(nlt))
+ return 1;
+ }
+
+ /* none found */
+ return 0;
+}
+
+/* Validate the NLA-Strips 'control' F-Curves based on the flags set*/
+void BKE_nlastrip_validate_fcurves (NlaStrip *strip)
+{
+ FCurve *fcu;
+
+ /* sanity checks */
+ if (strip == NULL)
return;
+
+ /* if controlling influence... */
+ if (strip->flag & NLASTRIP_FLAG_USR_INFLUENCE) {
+ /* try to get F-Curve */
+ fcu= list_find_fcurve(&strip->fcurves, "influence", 0);
+
+ /* add one if not found */
+ if (fcu == NULL) {
+ /* make new F-Curve */
+ fcu= MEM_callocN(sizeof(FCurve), "NlaStrip FCurve");
+ BLI_addtail(&strip->fcurves, fcu);
+
+ /* set default flags */
+ fcu->flag = (FCURVE_VISIBLE|FCURVE_AUTO_HANDLES|FCURVE_SELECTED);
+
+ /* store path - make copy, and store that */
+ fcu->rna_path= BLI_strdupn("influence", 9);
+
+ // TODO: insert a few keyframes to ensure default behaviour?
+ }
+ }
+
+ /* if controlling time... */
+ if (strip->flag & NLASTRIP_FLAG_USR_TIME) {
+ /* try to get F-Curve */
+ fcu= list_find_fcurve(&strip->fcurves, "strip_time", 0);
+
+ /* add one if not found */
+ if (fcu == NULL) {
+ /* make new F-Curve */
+ fcu= MEM_callocN(sizeof(FCurve), "NlaStrip FCurve");
+ BLI_addtail(&strip->fcurves, fcu);
+
+ /* set default flags */
+ fcu->flag = (FCURVE_VISIBLE|FCURVE_AUTO_HANDLES|FCURVE_SELECTED);
+
+ /* store path - make copy, and store that */
+ fcu->rna_path= BLI_strdupn("strip_time", 10);
+
+ // TODO: insert a few keyframes to ensure default behaviour?
+ }
+ }
+}
+
+/* Sanity Validation ------------------------------------ */
- /* Do any specific freeing */
- for (strip=nlalist->first; strip; strip=strip->next)
+/* Find (and set) a unique name for a strip from the whole AnimData block
+ * Uses a similar method to the BLI method, but is implemented differently
+ * as we need to ensure that the name is unique over several lists of tracks,
+ * not just a single track.
+ */
+void BKE_nlastrip_validate_name (AnimData *adt, NlaStrip *strip)
+{
+ GHash *gh;
+ NlaStrip *tstrip;
+ NlaTrack *nlt;
+
+ /* sanity checks */
+ if ELEM(NULL, adt, strip)
+ return;
+
+ /* give strip a default name if none already */
+ if (strip->name[0]==0) {
+ switch (strip->type) {
+ case NLASTRIP_TYPE_CLIP: /* act-clip */
+ sprintf(strip->name, "Act: %s", (strip->act)?(strip->act->id.name+2):("<None>"));
+ break;
+ case NLASTRIP_TYPE_TRANSITION: /* transition */
+ sprintf(strip->name, "Transition");
+ break;
+ case NLASTRIP_TYPE_META: /* meta */
+ sprintf(strip->name, "Meta");
+ break;
+ default:
+ sprintf(strip->name, "NLA Strip");
+ break;
+ }
+ }
+
+ /* build a hash-table of all the strips in the tracks
+ * - this is easier than iterating over all the tracks+strips hierarchy everytime
+ * (and probably faster)
+ */
+ gh= BLI_ghash_new(BLI_ghashutil_strhash, BLI_ghashutil_strcmp);
+
+ for (nlt= adt->nla_tracks.first; nlt; nlt= nlt->next) {
+ for (tstrip= nlt->strips.first; tstrip; tstrip= tstrip->next) {
+ /* don't add the strip of interest */
+ if (tstrip == strip)
+ continue;
+
+ /* use the name of the strip as the key, and the strip as the value, since we're mostly interested in the keys */
+ BLI_ghash_insert(gh, tstrip->name, tstrip);
+ }
+ }
+
+ /* if the hash-table has a match for this name, try other names...
+ * - in an extreme case, it might not be able to find a name, but then everything else in Blender would fail too :)
+ */
+ if (BLI_ghash_haskey(gh, strip->name)) {
+ char tempname[128];
+ int number = 1;
+ char *dot;
+
+ /* Strip off the suffix */
+ dot = strchr(strip->name, '.');
+ if (dot) *dot=0;
+
+ /* Try different possibilities */
+ for (number = 1; number <= 999; number++) {
+ /* assemble alternative name */
+ BLI_snprintf(tempname, 128, "%s%c%03d", strip->name, ".", number);
+
+ /* if hash doesn't have this, set it */
+ if (BLI_ghash_haskey(gh, tempname) == 0) {
+ BLI_strncpy(strip->name, tempname, sizeof(strip->name));
+ break;
+ }
+ }
+ }
+
+ /* free the hash... */
+ BLI_ghash_free(gh, NULL, NULL);
+}
+
+/* ---- */
+
+/* Get strips which overlap the given one at the start/end of its range
+ * - strip: strip that we're finding overlaps for
+ * - track: nla-track that the overlapping strips should be found from
+ * - start, end: frames for the offending endpoints
+ */
+static void nlastrip_get_endpoint_overlaps (NlaStrip *strip, NlaTrack *track, float **start, float **end)
+{
+ NlaStrip *nls;
+
+ /* find strips that overlap over the start/end of the given strip,
+ * but which don't cover the entire length
+ */
+ // TODO: this scheme could get quite slow for doing this on many strips...
+ for (nls= track->strips.first; nls; nls= nls->next) {
+ /* check if strip overlaps (extends over or exactly on) the entire range of the strip we're validating */
+ if ((nls->start <= strip->start) && (nls->end >= strip->end)) {
+ *start= NULL;
+ *end= NULL;
+ return;
+ }
+
+ /* check if strip doesn't even occur anywhere near... */
+ if (nls->end < strip->start)
+ continue; /* skip checking this strip... not worthy of mention */
+ if (nls->start > strip->end)
+ return; /* the range we're after has already passed */
+
+ /* if this strip is not part of an island of continuous strips, it can be used
+ * - this check needs to be done for each end of the strip we try and use...
+ */
+ if ((nls->next == NULL) || IS_EQ(nls->next->start, nls->end)==0) {
+ if ((nls->end > strip->start) && (nls->end < strip->end))
+ *start= &nls->end;
+ }
+ if ((nls->prev == NULL) || IS_EQ(nls->prev->end, nls->start)==0) {
+ if ((nls->start < strip->end) && (nls->start > strip->start))
+ *end= &nls->start;
+ }
+ }
+}
+
+/* Determine auto-blending for the given strip */
+void BKE_nlastrip_validate_autoblends (NlaTrack *nlt, NlaStrip *nls)
+{
+ float *ps=NULL, *pe=NULL;
+ float *ns=NULL, *ne=NULL;
+
+ /* sanity checks */
+ if ELEM(NULL, nls, nlt)
+ return;
+ if ((nlt->prev == NULL) && (nlt->next == NULL))
+ return;
+ if ((nls->flag & NLASTRIP_FLAG_AUTO_BLENDS)==0)
+ return;
+
+ /* get test ranges */
+ if (nlt->prev)
+ nlastrip_get_endpoint_overlaps(nls, nlt->prev, &ps, &pe);
+ if (nlt->next)
+ nlastrip_get_endpoint_overlaps(nls, nlt->next, &ns, &ne);
+
+ /* set overlaps for this strip
+ * - don't use the values obtained though if the end in question
+ * is directly followed/preceeded by another strip, forming an
+ * 'island' of continuous strips
+ */
+ if ( (ps || ns) && ((nls->prev == NULL) || IS_EQ(nls->prev->end, nls->start)==0) )
+ {
+ /* start overlaps - pick the largest overlap */
+ if ( ((ps && ns) && (*ps > *ns)) || (ps) )
+ nls->blendin= *ps - nls->start;
+ else
+ nls->blendin= *ns - nls->start;
+ }
+ else /* no overlap allowed/needed */
+ nls->blendin= 0.0f;
+
+ if ( (pe || ne) && ((nls->next == NULL) || IS_EQ(nls->next->start, nls->end)==0) )
{
- free_actionstrip (strip);
- };
+ /* end overlaps - pick the largest overlap */
+ if ( ((pe && ne) && (*pe > *ne)) || (pe) )
+ nls->blendout= nls->end - *pe;
+ else
+ nls->blendout= nls->end - *ne;
+ }
+ else /* no overlap allowed/needed */
+ nls->blendout= 0.0f;
+}
- /* Free the whole list */
- BLI_freelistN(nlalist);
+/* Ensure that auto-blending and other settings are set correctly */
+void BKE_nla_validate_state (AnimData *adt)
+{
+ NlaStrip *strip, *fstrip=NULL;
+ NlaTrack *nlt;
+
+ /* sanity checks */
+ if ELEM(NULL, adt, adt->nla_tracks.first)
+ return;
+
+ /* adjust blending values for auto-blending, and also do an initial pass to find the earliest strip */
+ for (nlt= adt->nla_tracks.first; nlt; nlt= nlt->next) {
+ for (strip= nlt->strips.first; strip; strip= strip->next) {
+ /* auto-blending first */
+ BKE_nlastrip_validate_autoblends(nlt, strip);
+
+ /* extend mode - find first strip */
+ if ((fstrip == NULL) || (strip->start < fstrip->start))
+ fstrip= strip;
+ }
+ }
+
+ /* second pass over the strips to adjust the extend-mode to fix any problems */
+ for (nlt= adt->nla_tracks.first; nlt; nlt= nlt->next) {
+ for (strip= nlt->strips.first; strip; strip= strip->next) {
+ /* apart from 'nothing' option which user has to explicitly choose, we don't really know if
+ * we should be overwriting the extend setting (but assume that's what the user wanted)
+ */
+ // TODO: 1 solution is to tie this in with auto-blending...
+ if (strip->extendmode != NLASTRIP_EXTEND_NOTHING) {
+ if (strip == fstrip)
+ strip->extendmode= NLASTRIP_EXTEND_HOLD;
+ else
+ strip->extendmode= NLASTRIP_EXTEND_HOLD_FORWARD;
+ }
+ }
+ }
+}
+
+/* Core Tools ------------------------------------------- */
+
+/* For the given AnimData block, add the active action to the NLA
+ * stack (i.e. 'push-down' action). The UI should only allow this
+ * for normal editing only (i.e. not in editmode for some strip's action),
+ * so no checks for this are performed.
+ */
+// TODO: maybe we should have checks for this too...
+void BKE_nla_action_pushdown (AnimData *adt)
+{
+ NlaStrip *strip;
+
+ /* sanity checks */
+ // TODO: need to report the error for this
+ if ELEM(NULL, adt, adt->action)
+ return;
+
+ /* if the action is empty, we also shouldn't try to add to stack,
+ * as that will cause us grief down the track
+ */
+ // TODO: what about modifiers?
+ if (action_has_motion(adt->action) == 0) {
+ printf("BKE_nla_action_pushdown(): action has no data \n");
+ return;
+ }
+
+ /* add a new NLA strip to the track, which references the active action */
+ strip= add_nlastrip_to_stack(adt, adt->action);
+
+ /* do other necessary work on strip */
+ if (strip) {
+ /* clear reference to action now that we've pushed it onto the stack */
+ adt->action->id.us--;
+ adt->action= NULL;
+
+ /* if the strip is the first one in the track it lives in, check if there
+ * are strips in any other tracks that may be before this, and set the extend
+ * mode accordingly
+ */
+ if (nlastrip_is_first(adt, strip) == 0) {
+ /* not first, so extend mode can only be NLASTRIP_EXTEND_HOLD_FORWARD not NLASTRIP_EXTEND_HOLD,
+ * so that it doesn't override strips in previous tracks
+ */
+ // FIXME: this needs to be more automated, since user can rearrange strips
+ strip->extendmode= NLASTRIP_EXTEND_HOLD_FORWARD;
+ }
+ }
+}
+
+
+/* Find the active strip + track combo, and set them up as the tweaking track,
+ * and return if successful or not.
+ */
+short BKE_nla_tweakmode_enter (AnimData *adt)
+{
+ NlaTrack *nlt, *activeTrack=NULL;
+ NlaStrip *strip, *activeStrip=NULL;
+
+ /* verify that data is valid */
+ if ELEM(NULL, adt, adt->nla_tracks.first)
+ return 0;
+
+ /* if block is already in tweakmode, just leave, but we should report
+ * that this block is in tweakmode (as our returncode)
+ */
+ if (adt->flag & ADT_NLA_EDIT_ON)
+ return 1;
+
+ /* go over the tracks, finding the active one, and its active strip
+ * - if we cannot find both, then there's nothing to do
+ */
+ for (nlt= adt->nla_tracks.first; nlt; nlt= nlt->next) {
+ /* check if active */
+ if (nlt->flag & NLATRACK_ACTIVE) {
+ /* store reference to this active track */
+ activeTrack= nlt;
+
+ /* now try to find active strip */
+ activeStrip= BKE_nlastrip_find_active(nlt);
+ break;
+ }
+ }
+ if ELEM3(NULL, activeTrack, activeStrip, activeStrip->act) {
+ printf("NLA tweakmode enter - neither active requirement found \n");
+ return 0;
+ }
+
+ /* go over all the tracks up to the active one, tagging each strip that uses the same
+ * action as the active strip, but leaving everything else alone
+ */
+ for (nlt= activeTrack->prev; nlt; nlt= nlt->prev) {
+ for (strip= nlt->strips.first; strip; strip= strip->next) {
+ if (strip->act == activeStrip->act)
+ strip->flag |= NLASTRIP_FLAG_TWEAKUSER;
+ else
+ strip->flag &= ~NLASTRIP_FLAG_TWEAKUSER;
+ }
+ }
+
+
+ /* go over all the tracks after AND INCLUDING the active one, tagging them as being disabled
+ * - the active track needs to also be tagged, otherwise, it'll overlap with the tweaks going on
+ */
+ for (nlt= activeTrack; nlt; nlt= nlt->next)
+ nlt->flag |= NLATRACK_DISABLED;
+
+ /* handle AnimData level changes:
+ * - 'real' active action to temp storage (no need to change user-counts)
+ * - action of active strip set to be the 'active action', and have its usercount incremented
+ * - editing-flag for this AnimData block should also get turned on (for more efficient restoring)
+ * - take note of the active strip for mapping-correction of keyframes in the action being edited
+ */
+ adt->tmpact= adt->action;
+ adt->action= activeStrip->act;
+ adt->actstrip= activeStrip;
+ id_us_plus(&activeStrip->act->id);
+ adt->flag |= ADT_NLA_EDIT_ON;
+
+ /* done! */
+ return 1;
}
+
+/* Exit tweakmode for this AnimData block */
+void BKE_nla_tweakmode_exit (AnimData *adt)
+{
+ NlaStrip *strip;
+ NlaTrack *nlt;
+
+ /* verify that data is valid */
+ if ELEM(NULL, adt, adt->nla_tracks.first)
+ return;
+
+ /* hopefully the flag is correct - skip if not on */
+ if ((adt->flag & ADT_NLA_EDIT_ON) == 0)
+ return;
+
+ // TODO: need to sync the user-strip with the new state of the action!
+
+ /* for all Tracks, clear the 'disabled' flag
+ * for all Strips, clear the 'tweak-user' flag
+ */
+ for (nlt= adt->nla_tracks.first; nlt; nlt= nlt->next) {
+ nlt->flag &= ~NLATRACK_DISABLED;
+
+ for (strip= nlt->strips.first; strip; strip= strip->next)
+ strip->flag &= ~NLASTRIP_FLAG_TWEAKUSER;
+ }
+
+ /* handle AnimData level changes:
+ * - 'temporary' active action needs its usercount decreased, since we're removing this reference
+ * - 'real' active action is restored from storage
+ * - storage pointer gets cleared (to avoid having bad notes hanging around)
+ * - editing-flag for this AnimData block should also get turned off
+ * - clear pointer to active strip
+ */
+ if (adt->action) adt->action->id.us--;
+ adt->action= adt->tmpact;
+ adt->tmpact= NULL;
+ adt->actstrip= NULL;
+ adt->flag &= ~ADT_NLA_EDIT_ON;
+}
+
+/* *************************************************** */
diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c
index 81bd78f1851..e463d007a2d 100644
--- a/source/blender/blenkernel/intern/object.c
+++ b/source/blender/blenkernel/intern/object.c
@@ -42,6 +42,7 @@
#include "DNA_anim_types.h"
#include "DNA_action_types.h"
#include "DNA_armature_types.h"
+#include "DNA_boid_types.h"
#include "DNA_camera_types.h"
#include "DNA_constraint_types.h"
#include "DNA_curve_types.h"
@@ -243,7 +244,9 @@ void free_object(Object *ob)
if(ob->mat[a]) ob->mat[a]->id.us--;
}
if(ob->mat) MEM_freeN(ob->mat);
+ if(ob->matbits) MEM_freeN(ob->matbits);
ob->mat= 0;
+ ob->matbits= 0;
if(ob->bb) MEM_freeN(ob->bb);
ob->bb= 0;
if(ob->path) free_path(ob->path);
@@ -263,10 +266,6 @@ void free_object(Object *ob)
free_actuators(&ob->actuators);
free_constraints(&ob->constraints);
-
-#ifndef DISABLE_PYTHON
- BPY_free_scriptlink(&ob->scriptlink);
-#endif
if(ob->pd){
if(ob->pd->tex)
@@ -427,17 +426,16 @@ void unlink_object(Scene *scene, Object *ob)
if(obt->particlesystem.first) {
ParticleSystem *tpsys= obt->particlesystem.first;
for(; tpsys; tpsys=tpsys->next) {
- if(tpsys->keyed_ob==ob) {
- ParticleSystem *psys= BLI_findlink(&ob->particlesystem,tpsys->keyed_psys-1);
+ BoidState *state = NULL;
+ BoidRule *rule = NULL;
- if(psys && psys->keyed_ob) {
- tpsys->keyed_ob= psys->keyed_ob;
- tpsys->keyed_psys= psys->keyed_psys;
+ ParticleTarget *pt = tpsys->targets.first;
+ for(; pt; pt=pt->next) {
+ if(pt->ob==ob) {
+ pt->ob = NULL;
+ obt->recalc |= OB_RECALC_DATA;
+ break;
}
- else
- tpsys->keyed_ob= NULL;
-
- obt->recalc |= OB_RECALC_DATA;
}
if(tpsys->target_ob==ob) {
@@ -459,6 +457,22 @@ void unlink_object(Scene *scene, Object *ob)
}
}
}
+ if(tpsys->part->boids) {
+ for(state = tpsys->part->boids->states.first; state; state=state->next) {
+ for(rule = state->rules.first; rule; rule=rule->next) {
+ if(rule->type==eBoidRuleType_Avoid) {
+ BoidRuleGoalAvoid *gabr = (BoidRuleGoalAvoid*)rule;
+ if(gabr->ob==ob)
+ gabr->ob= NULL;
+ }
+ else if(rule->type==eBoidRuleType_FollowLeader) {
+ BoidRuleFollowLeader *flbr = (BoidRuleFollowLeader*)rule;
+ if(flbr->ob==ob)
+ flbr->ob= NULL;
+ }
+ }
+ }
+ }
}
if(ob->pd)
obt->recalc |= OB_RECALC_DATA;
@@ -627,10 +641,7 @@ Camera *copy_camera(Camera *cam)
camn= copy_libblock(cam);
camn->adt= BKE_copy_animdata(cam->adt);
-
-#ifndef DISABLE_PYTHON
- BPY_copy_scriptlink(&camn->scriptlink);
-#endif
+
return camn;
}
@@ -716,7 +727,7 @@ void *add_lamp(char *name)
la->r= la->g= la->b= la->k= 1.0f;
la->haint= la->energy= 1.0f;
- la->dist= 20.0f;
+ la->dist= 25.0f;
la->spotsize= 45.0f;
la->spotblend= 0.15f;
la->att2= 1.0f;
@@ -735,7 +746,7 @@ void *add_lamp(char *name)
la->ray_samp_method = LA_SAMP_HALTON;
la->adapt_thresh = 0.001f;
la->preview=NULL;
- la->falloff_type = LA_FALLOFF_INVLINEAR;
+ la->falloff_type = LA_FALLOFF_INVSQUARE;
la->curfalloff = curvemapping_add(1, 0.0f, 1.0f, 1.0f, 0.0f);
la->sun_effect_type = 0;
la->horizon_brightness = 1.0;
@@ -779,9 +790,7 @@ Lamp *copy_lamp(Lamp *la)
#endif // XXX old animation system
if (la->preview) lan->preview = BKE_previewimg_copy(la->preview);
-#ifndef DISABLE_PYTHON
- BPY_copy_scriptlink(&la->scriptlink);
-#endif
+
return lan;
}
@@ -839,9 +848,6 @@ void make_local_lamp(Lamp *la)
void free_camera(Camera *ca)
{
-#ifndef DISABLE_PYTHON
- BPY_free_scriptlink(&ca->scriptlink);
-#endif
BKE_free_animdata((ID *)ca);
}
@@ -850,11 +856,6 @@ void free_lamp(Lamp *la)
MTex *mtex;
int a;
- /* scriptlinks */
-#ifndef DISABLE_PYTHON
- BPY_free_scriptlink(&la->scriptlink);
-#endif
-
for(a=0; a<MAX_MTEX; a++) {
mtex= la->mtex[a];
if(mtex && mtex->tex) mtex->tex->id.us--;
@@ -945,7 +946,6 @@ Object *add_only_object(int type, char *name)
Mat4One(ob->parentinv);
Mat4One(ob->obmat);
ob->dt= OB_SHADED;
- if(U.flag & USER_MAT_ON_OB) ob->colbits= -1;
ob->empty_drawtype= OB_ARROWS;
ob->empty_drawsize= 1.0;
@@ -1050,18 +1050,29 @@ ParticleSystem *copy_particlesystem(ParticleSystem *psys)
psysn= MEM_dupallocN(psys);
psysn->particles= MEM_dupallocN(psys->particles);
psysn->child= MEM_dupallocN(psys->child);
+ if(psysn->particles->keys)
+ psysn->particles->keys = MEM_dupallocN(psys->particles->keys);
for(a=0, pa=psysn->particles; a<psysn->totpart; a++, pa++) {
if(pa->hair)
pa->hair= MEM_dupallocN(pa->hair);
- if(pa->keys)
- pa->keys= MEM_dupallocN(pa->keys);
+ if(a)
+ pa->keys= (pa-1)->keys + (pa-1)->totkey;
}
if(psys->soft) {
psysn->soft= copy_softbody(psys->soft);
psysn->soft->particles = psysn;
}
+
+ if(psys->particles->boid) {
+ psysn->particles->boid = MEM_dupallocN(psys->particles->boid);
+ for(a=1, pa=psysn->particles+1; a<psysn->totpart; a++, pa++)
+ pa->boid = (pa-1)->boid + 1;
+ }
+
+ if(psys->targets.first)
+ BLI_duplicatelist(&psysn->targets, &psys->targets);
psysn->pathcache= NULL;
psysn->childcache= NULL;
@@ -1168,6 +1179,7 @@ Object *copy_object(Object *ob)
if(ob->totcol) {
obn->mat= MEM_dupallocN(ob->mat);
+ obn->matbits= MEM_dupallocN(ob->matbits);
}
if(ob->bb) obn->bb= MEM_dupallocN(ob->bb);
@@ -1181,9 +1193,7 @@ Object *copy_object(Object *ob)
modifier_copyData(md, nmd);
BLI_addtail(&obn->modifiers, nmd);
}
-#ifndef DISABLE_PYTHON
- BPY_copy_scriptlink(&ob->scriptlink);
-#endif
+
obn->prop.first = obn->prop.last = NULL;
copy_properties(&obn->prop, &ob->prop);
@@ -1198,18 +1208,12 @@ Object *copy_object(Object *ob)
armature_rebuild_pose(obn, obn->data);
}
copy_defgroups(&obn->defbase, &ob->defbase);
-#if 0 // XXX old animation system
- copy_nlastrips(&obn->nlastrips, &ob->nlastrips);
-#endif // XXX old animation system
copy_constraints(&obn->constraints, &ob->constraints);
/* increase user numbers */
id_us_plus((ID *)obn->data);
-#if 0 // XXX old animation system
- id_us_plus((ID *)obn->ipo);
- id_us_plus((ID *)obn->action);
-#endif // XXX old animation system
id_us_plus((ID *)obn->dup_group);
+ // FIXME: add this for animdata too...
for(a=0; a<obn->totcol; a++) id_us_plus((ID *)obn->mat[a]);
@@ -1325,7 +1329,18 @@ void make_local_object(Object *ob)
expand_local_object(ob);
}
-/* returns true if the Object data is a from an external blend file (libdata) */
+/*
+ * Returns true if the Object is a from an external blend file (libdata)
+ */
+int object_is_libdata(Object *ob)
+{
+ if (!ob) return 0;
+ if (ob->proxy) return 0;
+ if (ob->id.lib) return 1;
+ return 0;
+}
+
+/* Returns true if the Object data is a from an external blend file (libdata) */
int object_data_is_libdata(Object *ob)
{
if(!ob) return 0;
@@ -1401,7 +1416,9 @@ void object_make_proxy(Object *ob, Object *target, Object *gob)
/* copy material and index information */
ob->actcol= ob->totcol= 0;
if(ob->mat) MEM_freeN(ob->mat);
+ if(ob->matbits) MEM_freeN(ob->matbits);
ob->mat = NULL;
+ ob->matbits= NULL;
if ((target->totcol) && (target->mat) && ELEM5(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_MBALL)) { //XXX OB_SUPPORT_MATERIAL
int i;
ob->colbits = target->colbits;
@@ -1410,6 +1427,7 @@ void object_make_proxy(Object *ob, Object *target, Object *gob)
ob->totcol= target->totcol;
ob->mat = MEM_dupallocN(target->mat);
+ ob->matbits = MEM_dupallocN(target->matbits);
for(i=0; i<target->totcol; i++) {
/* dont need to run test_object_materials since we know this object is new and not used elsewhere */
id_us_plus((ID *)ob->mat[i]);
@@ -1575,14 +1593,14 @@ static void ob_parcurve(Scene *scene, Object *ob, Object *par, float mat[][4])
}
/* catch exceptions: curve paths used as a duplicator */
else if(enable_cu_speed) {
- ctime= bsystem_time(scene, ob, (float)scene->r.cfra, 0.0);
-
-#if 0 // XXX old animation system
- if(calc_ipo_spec(cu->ipo, CU_SPEED, &ctime)==0) {
- ctime /= cu->pathlen;
- CLAMP(ctime, 0.0, 1.0);
- }
-#endif // XXX old animation system
+ /* 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...
+ *
+ * we firstly calculate the modulus of cu->ctime/cu->pathlen to clamp ctime within the 0.0 to 1.0 times pathlen
+ * range, then divide this (the modulus) by pathlen to get a value between 0.0 and 1.0
+ */
+ ctime= fmod(cu->ctime, cu->pathlen) / cu->pathlen;
+ CLAMP(ctime, 0.0, 1.0);
}
else {
ctime= scene->r.cfra - give_timeoffset(ob);
@@ -1806,26 +1824,6 @@ void set_no_parent_ipo(int val)
no_parent_ipo= val;
}
-static int during_script_flag=0;
-void disable_where_script(short on)
-{
- during_script_flag= on;
-}
-
-int during_script(void) {
- return during_script_flag;
-}
-
-static int during_scriptlink_flag=0;
-void disable_where_scriptlink(short on)
-{
- during_scriptlink_flag= on;
-}
-
-int during_scriptlink(void) {
- return during_scriptlink_flag;
-}
-
void where_is_object_time(Scene *scene, Object *ob, float ctime)
{
float *fp1, *fp2, slowmat[4][4] = MAT4_UNITY;
@@ -1925,11 +1923,6 @@ void where_is_object_time(Scene *scene, Object *ob, float ctime)
constraints_clear_evalob(cob);
}
-#ifndef DISABLE_PYTHON
- if(ob->scriptlink.totscript && !during_script()) {
- if (G.f & G_DOSCRIPTLINKS) BPY_do_pyscript((ID *)ob, SCRIPT_REDRAW);
- }
-#endif
/* set negative scale flag in object */
Crossf(vec, ob->obmat[0], ob->obmat[1]);
@@ -2301,9 +2294,6 @@ void object_handle_update(Scene *scene, Object *ob)
}
else
where_is_object(scene, ob);
-#ifndef DISABLE_PYTHON
- if (G.f & G_DOSCRIPTLINKS) BPY_do_pyscript((ID *)ob, SCRIPT_OBJECTUPDATE);
-#endif
}
if(ob->recalc & OB_RECALC_DATA) {
@@ -2357,10 +2347,17 @@ void object_handle_update(Scene *scene, Object *ob)
if(ob->particlesystem.first) {
ParticleSystem *tpsys, *psys;
DerivedMesh *dm;
+ ob->transflag &= ~OB_DUPLIPARTS;
psys= ob->particlesystem.first;
while(psys) {
if(psys_check_enabled(ob, psys)) {
+ /* check use of dupli objects here */
+ if(psys->part && psys->part->draw_as == PART_DRAW_REND &&
+ ((psys->part->ren_as == PART_DRAW_OB && psys->part->dup_ob)
+ || (psys->part->ren_as == PART_DRAW_GR && psys->part->dup_group)))
+ ob->transflag |= OB_DUPLIPARTS;
+
particle_system_update(scene, ob, psys);
psys= psys->next;
}
@@ -2385,9 +2382,6 @@ void object_handle_update(Scene *scene, Object *ob)
psys_get_modifier(ob, psys)->flag &= ~eParticleSystemFlag_psys_updated;
}
}
-#ifndef DISABLE_PYTHON
- if (G.f & G_DOSCRIPTLINKS) BPY_do_pyscript((ID *)ob, SCRIPT_OBDATAUPDATE);
-#endif
}
/* the no-group proxy case, we call update */
diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c
index 4488f8cdffd..e4f8a484061 100644
--- a/source/blender/blenkernel/intern/particle.c
+++ b/source/blender/blenkernel/intern/particle.c
@@ -36,6 +36,7 @@
#include "MEM_guardedalloc.h"
#include "DNA_scene_types.h"
+#include "DNA_boid_types.h"
#include "DNA_particle_types.h"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
@@ -58,6 +59,7 @@
#include "BKE_anim.h"
+#include "BKE_boids.h"
#include "BKE_global.h"
#include "BKE_main.h"
#include "BKE_lattice.h"
@@ -84,7 +86,8 @@ static void get_cpa_texture(DerivedMesh *dm, Material *ma, int face_index,
static void get_child_modifier_parameters(ParticleSettings *part, ParticleThreadContext *ctx,
ChildParticle *cpa, short cpa_from, int cpa_num, float *cpa_fuv, float *orco, ParticleTexture *ptex);
static void do_child_modifiers(Scene *scene, Object *ob, ParticleSystem *psys, ParticleSettings *part,
- ParticleTexture *ptex, ParticleKey *par, float *par_rot, ChildParticle *cpa, float *orco, ParticleKey *state, float t);
+ ParticleTexture *ptex, ParticleKey *par, float *par_rot, ChildParticle *cpa,
+ float *orco, float mat[4][4], ParticleKey *state, float t);
/* few helpers for countall etc. */
int count_particles(ParticleSystem *psys){
@@ -354,10 +357,13 @@ void psys_free_settings(ParticleSettings *part)
MEM_freeN(part->pd);
part->pd = NULL;
}
+
if(part->pd2) {
MEM_freeN(part->pd2);
part->pd2 = NULL;
}
+
+ boid_free_settings(part->boids);
}
void free_hair(ParticleSystem *psys, int softbody)
@@ -438,6 +444,9 @@ void psys_free(Object *ob, ParticleSystem * psys)
psys->free_edit(psys);
if(psys->particles){
+ if(psys->particles->boid)
+ MEM_freeN(psys->particles->boid);
+
MEM_freeN(psys->particles);
psys->particles = 0;
psys->totpart = 0;
@@ -478,10 +487,18 @@ void psys_free(Object *ob, ParticleSystem * psys)
if(psys->pointcache)
BKE_ptcache_free(psys->pointcache);
+ if(psys->targets.first)
+ BLI_freelistN(&psys->targets);
+
+ BLI_kdtree_free(psys->tree);
+
MEM_freeN(psys);
}
}
+/************************************************/
+/* Rendering */
+/************************************************/
/* these functions move away particle data and bring it back after
* rendering, to make different render settings possible without
* removing the previous data. this should be solved properly once */
@@ -889,7 +906,7 @@ int psys_render_simplify_params(ParticleSystem *psys, ChildParticle *cpa, float
}
/************************************************/
-/* Interpolated Particles */
+/* Interpolation */
/************************************************/
static float interpolate_particle_value(float v1, float v2, float v3, float v4, float *w, int four)
{
@@ -938,6 +955,214 @@ void psys_interpolate_particle(short type, ParticleKey keys[4], float dt, Partic
+typedef struct ParticleInterpolationData {
+ ParticleKey *kkey[2];
+ HairKey *hkey[2];
+ BodyPoint *bp[2];
+ SoftBody *soft;
+ int keyed, cached;
+ float birthtime, dietime;
+} ParticleInterpolationData;
+/* Assumes pointcache->mem_cache exists, so for disk cached particles call psys_make_temp_pointcache() before use */
+static void get_pointcache_keys_for_time(Object *ob, ParticleSystem *psys, int index, float t, ParticleKey *key1, ParticleKey *key2)
+{
+ PointCache *cache = psys->pointcache;
+ static PTCacheMem *pm = NULL; /* not thread safe */
+
+ if(index < 0) { /* initialize */
+ pm = cache->mem_cache.first;
+
+ if(pm)
+ pm = pm->next;
+ }
+ else {
+ if(pm) {
+ while(pm && pm->next && (float)pm->frame < t)
+ pm = pm->next;
+
+ copy_particle_key(key2, ((ParticleKey *)pm->data) + index, 1);
+ copy_particle_key(key1, ((ParticleKey *)(pm->prev)->data) + index, 1);
+ }
+ else if(cache->mem_cache.first) {
+ PTCacheMem *pm2 = cache->mem_cache.first;
+ copy_particle_key(key2, ((ParticleKey *)pm2->data) + index, 1);
+ copy_particle_key(key1, ((ParticleKey *)pm2->data) + index, 1);
+ }
+ }
+}
+static void init_particle_interpolation(Object *ob, ParticleSystem *psys, ParticleData *pa, ParticleInterpolationData *pind)
+{
+
+ if(pind->keyed) {
+ pind->kkey[0] = pa->keys;
+
+ if(pa->totkey > 1)
+ pind->kkey[1] = pa->keys + 1;
+ else
+ pind->kkey[1] = NULL;
+
+ pind->birthtime = pa->keys->time;
+ pind->dietime = (pa->keys + pa->totkey - 1)->time;
+ }
+ else if(pind->cached) {
+ get_pointcache_keys_for_time(ob, psys, -1, 0.0f, NULL, NULL);
+
+ pind->birthtime = pa->time;
+ pind->dietime = pa->dietime;
+ }
+ else {
+ pind->hkey[0] = pa->hair;
+ pind->hkey[1] = pa->hair + 1;
+
+ pind->birthtime = pa->hair->time;
+ pind->dietime = (pa->hair + pa->totkey - 1)->time;
+ }
+
+ if(pind->soft) {
+ pind->bp[0] = pind->soft->bpoint + pa->bpi;
+ pind->bp[1] = pind->soft->bpoint + pa->bpi + 1;
+ }
+}
+static void hair_to_particle(ParticleKey *key, HairKey *hkey)
+{
+ VECCOPY(key->co, hkey->co);
+ key->time = hkey->time;
+}
+static void bp_to_particle(ParticleKey *key, BodyPoint *bp, HairKey *hkey)
+{
+ VECCOPY(key->co, bp->pos);
+ key->time = hkey->time;
+}
+
+static void do_particle_interpolation(ParticleSystem *psys, int p, ParticleData *pa, float t, float frs_sec, ParticleInterpolationData *pind, ParticleKey *result)
+{
+ ParticleKey keys[4];
+ float real_t, dfra, keytime;
+
+ /* interpret timing and find keys */
+ if(pind->keyed) {
+ /* we have only one key, so let's use that */
+ if(pind->kkey[1]==NULL) {
+ copy_particle_key(result, pind->kkey[0], 1);
+ return;
+ }
+
+ if(result->time < 0.0f)
+ real_t = -result->time;
+ else
+ real_t = pind->kkey[0]->time + t * (pind->kkey[0][pa->totkey-1].time - pind->kkey[0]->time);
+
+ if(psys->part->phystype==PART_PHYS_KEYED && psys->flag & PSYS_KEYED_TIMING) {
+ ParticleTarget *pt = psys->targets.first;
+
+ pt=pt->next;
+
+ while(pt && pa->time + pt->time < real_t)
+ pt= pt->next;
+
+ if(pt) {
+ pt=pt->prev;
+
+ if(pa->time + pt->time + pt->duration > real_t)
+ real_t = pa->time + pt->time;
+ }
+ else
+ real_t = pa->time + ((ParticleTarget*)psys->targets.last)->time;
+ }
+
+ CLAMP(real_t, pa->time, pa->dietime);
+
+ while(pind->kkey[1]->time < real_t)
+ pind->kkey[1]++;
+
+ pind->kkey[0] = pind->kkey[1] - 1;
+ }
+ else if(pind->cached) {
+ if(result->time < 0.0f) /* flag for time in frames */
+ real_t = -result->time;
+ else
+ real_t = pa->time + t * (pa->dietime - pa->time);
+ }
+ else {
+ if(result->time < 0.0f)
+ real_t = -result->time;
+ else
+ real_t = pind->hkey[0]->time + t * (pind->hkey[0][pa->totkey-1].time - pind->hkey[0]->time);
+
+ while(pind->hkey[1]->time < real_t) {
+ pind->hkey[1]++;
+ pind->bp[1]++;
+ }
+
+ pind->hkey[0] = pind->hkey[1] - 1;
+ }
+
+ /* set actual interpolation keys */
+ if(pind->soft) {
+ pind->bp[0] = pind->bp[1] - 1;
+ bp_to_particle(keys + 1, pind->bp[0], pind->hkey[0]);
+ bp_to_particle(keys + 2, pind->bp[1], pind->hkey[1]);
+ }
+ else if(pind->keyed) {
+ memcpy(keys + 1, pind->kkey[0], sizeof(ParticleKey));
+ memcpy(keys + 2, pind->kkey[1], sizeof(ParticleKey));
+ }
+ else if(pind->cached) {
+ get_pointcache_keys_for_time(NULL, psys, p, real_t, keys+1, keys+2);
+ }
+ else {
+ hair_to_particle(keys + 1, pind->hkey[0]);
+ hair_to_particle(keys + 2, pind->hkey[1]);
+ }
+
+ /* set secondary interpolation keys for hair */
+ if(!pind->keyed && !pind->cached) {
+ if(pind->soft) {
+ if(pind->hkey[0] != pa->hair)
+ bp_to_particle(keys, pind->bp[0] - 1, pind->hkey[0] - 1);
+ else
+ bp_to_particle(keys, pind->bp[0], pind->hkey[0]);
+ }
+ else {
+ if(pind->hkey[0] != pa->hair)
+ hair_to_particle(keys, pind->hkey[0] - 1);
+ else
+ hair_to_particle(keys, pind->hkey[0]);
+ }
+
+ if(pind->soft) {
+ if(pind->hkey[1] != pa->hair + pa->totkey - 1)
+ bp_to_particle(keys + 3, pind->bp[1] + 1, pind->hkey[1] + 1);
+ else
+ bp_to_particle(keys + 3, pind->bp[1], pind->hkey[1]);
+ }
+ else {
+ if(pind->hkey[1] != pa->hair + pa->totkey - 1)
+ hair_to_particle(keys + 3, pind->hkey[1] + 1);
+ else
+ hair_to_particle(keys + 3, pind->hkey[1]);
+ }
+ }
+
+ dfra = keys[2].time - keys[1].time;
+ keytime = (real_t - keys[1].time) / dfra;
+
+ /* convert velocity to timestep size */
+ if(pind->keyed || pind->cached){
+ VecMulf(keys[1].vel, dfra / frs_sec);
+ VecMulf(keys[2].vel, dfra / frs_sec);
+ QuatInterpol(result->rot,keys[1].rot,keys[2].rot,keytime);
+ }
+
+ /* now we should have in chronologiacl order k1<=k2<=t<=k3<=k4 with keytime between [0,1]->[k2,k3] (k1 & k4 used for cardinal & bspline interpolation)*/
+ psys_interpolate_particle((pind->keyed || pind->cached) ? -1 /* signal for cubic interpolation */
+ : ((psys->part->flag & PART_HAIR_BSPLINE) ? KEY_BSPLINE : KEY_CARDINAL)
+ ,keys, keytime, result, 1);
+
+ /* the velocity needs to be converted back from cubic interpolation */
+ if(pind->keyed || pind->cached)
+ VecMulf(result->vel, frs_sec / dfra);
+}
/************************************************/
/* Particles on a dm */
/************************************************/
@@ -1438,16 +1663,6 @@ void psys_particle_on_emitter(ParticleSystemModifierData *psmd, int from, int in
/************************************************/
/* Path Cache */
/************************************************/
-static void hair_to_particle(ParticleKey *key, HairKey *hkey)
-{
- VECCOPY(key->co, hkey->co);
- key->time = hkey->time;
-}
-static void bp_to_particle(ParticleKey *key, BodyPoint *bp, HairKey *hkey)
-{
- VECCOPY(key->co, bp->pos);
- key->time = hkey->time;
-}
static float vert_weight(MDeformVert *dvert, int group)
{
MDeformWeight *dw;
@@ -1734,7 +1949,7 @@ int do_guide(Scene *scene, ParticleKey *state, int pa_num, float time, ListBase
}
return 0;
}
-static void do_rough(float *loc, float t, float fac, float size, float thres, ParticleKey *state)
+static void do_rough(float *loc, float mat[4][4], float t, float fac, float size, float thres, ParticleKey *state)
{
float rough[3];
float rco[3];
@@ -1747,32 +1962,24 @@ static void do_rough(float *loc, float t, float fac, float size, float thres, Pa
rough[0]=-1.0f+2.0f*BLI_gTurbulence(size, rco[0], rco[1], rco[2], 2,0,2);
rough[1]=-1.0f+2.0f*BLI_gTurbulence(size, rco[1], rco[2], rco[0], 2,0,2);
rough[2]=-1.0f+2.0f*BLI_gTurbulence(size, rco[2], rco[0], rco[1], 2,0,2);
- VECADDFAC(state->co,state->co,rough,fac);
+
+ VECADDFAC(state->co,state->co,mat[0],fac*rough[0]);
+ VECADDFAC(state->co,state->co,mat[1],fac*rough[1]);
+ VECADDFAC(state->co,state->co,mat[2],fac*rough[2]);
}
-static void do_rough_end(float *loc, float t, float fac, float shape, ParticleKey *state, ParticleKey *par)
+static void do_rough_end(float *loc, float mat[4][4], float t, float fac, float shape, ParticleKey *state)
{
- float rough[3], rnor[3];
+ float rough[2];
float roughfac;
roughfac=fac*(float)pow((double)t,shape);
VECCOPY(rough,loc);
rough[0]=-1.0f+2.0f*rough[0];
rough[1]=-1.0f+2.0f*rough[1];
- rough[2]=-1.0f+2.0f*rough[2];
VecMulf(rough,roughfac);
-
- if(par){
- VECCOPY(rnor,par->vel);
- }
- else{
- VECCOPY(rnor,state->vel);
- }
- Normalize(rnor);
- Projf(rnor,rough,rnor);
- VECSUB(rough,rough,rnor);
-
- VECADD(state->co,state->co,rough);
+ VECADDFAC(state->co,state->co,mat[0],rough[0]);
+ VECADDFAC(state->co,state->co,mat[1],rough[1]);
}
static void do_path_effectors(Scene *scene, Object *ob, ParticleSystem *psys, int i, ParticleCacheKey *ca, int k, int steps, float *rootco, float effector, float dfra, float cfra, float *length, float *vec)
{
@@ -2007,7 +2214,7 @@ void psys_thread_create_path(ParticleThread *thread, struct ChildParticle *cpa,
ParticleData *pa=NULL;
ParticleTexture ptex;
float *cpa_fuv=0, *par_rot=0;
- float co[3], orco[3], ornor[3], t, cpa_1st[3], dvec[3];
+ float co[3], orco[3], ornor[3], hairmat[4][4], t, cpa_1st[3], dvec[3];
float branch_begin, branch_end, branch_prob, rough_rand;
float length, max_length = 1.0f, cur_length = 0.0f;
float eff_length, eff_vec[3];
@@ -2065,8 +2272,6 @@ void psys_thread_create_path(ParticleThread *thread, struct ChildParticle *cpa,
cpa_num = cpa->num;
foffset= cpa->foffset;
- if(part->childtype == PART_CHILD_FACES)
- foffset = -(2.0f + part->childspread);
cpa_fuv = cpa->fuv;
cpa_from = PART_FROM_FACE;
@@ -2078,6 +2283,10 @@ void psys_thread_create_path(ParticleThread *thread, struct ChildParticle *cpa,
Mat4MulVecfl(ob->obmat,cpa_1st);
}
+ pa = psys->particles + cpa->parent;
+
+ psys_mat_hair_to_global(ob, ctx->psmd->dm, psys->part->from, pa, hairmat);
+
pa=0;
}
else{
@@ -2099,6 +2308,8 @@ void psys_thread_create_path(ParticleThread *thread, struct ChildParticle *cpa,
cpa_fuv=pa->fuv;
psys_particle_on_emitter(ctx->psmd,cpa_from,cpa_num,DMCACHE_ISCHILD,cpa_fuv,pa->foffset,co,ornor,0,0,orco,0);
+
+ psys_mat_hair_to_global(ob, ctx->psmd->dm, psys->part->from, pa, hairmat);
}
keys->steps = ctx->steps;
@@ -2190,7 +2401,7 @@ void psys_thread_create_path(ParticleThread *thread, struct ChildParticle *cpa,
}
/* apply different deformations to the child path */
- do_child_modifiers(ctx->scene, ob, psys, part, &ptex, (ParticleKey *)par, par_rot, cpa, orco, (ParticleKey *)state, t);
+ do_child_modifiers(ctx->scene, ob, psys, part, &ptex, (ParticleKey *)par, par_rot, cpa, orco, hairmat, (ParticleKey *)state, t);
/* TODO: better branching */
//if(part->flag & PART_BRANCHING && ctx->between == 0 && part->flag & PART_ANIM_BRANCHING)
@@ -2247,20 +2458,12 @@ void psys_thread_create_path(ParticleThread *thread, struct ChildParticle *cpa,
/* check if path needs to be cut before actual end of data points */
if(k){
VECSUB(dvec,state->co,(state-1)->co);
- if(part->flag&PART_ABS_LENGTH)
- length=VecLength(dvec);
- else
- length=1.0f/(float)ctx->steps;
-
+ length=1.0f/(float)ctx->steps;
k=check_path_length(k,keys,state,max_length,&cur_length,length,dvec);
}
else{
/* initialize length calculation */
- if(part->flag&PART_ABS_LENGTH)
- max_length= part->abslength*ptex.length;
- else
- max_length= ptex.length;
-
+ max_length= ptex.length;
cur_length= 0.0f;
}
@@ -2353,36 +2556,6 @@ void psys_cache_child_paths(Scene *scene, Object *ob, ParticleSystem *psys, floa
psys_threads_free(pthreads);
}
-static void get_pointcache_keys_for_time(ParticleSystem *psys, int index, float t, ParticleKey *key1, ParticleKey *key2)
-{
- PointCache *cache = psys->pointcache;
- static PTCacheMem *pm = NULL;
-
- if(cache->flag & PTCACHE_DISK_CACHE) {
- /* TODO */
- }
- else {
- if(index < 0) { /* initialize */
- pm = cache->mem_cache.first;
- if(pm)
- pm = pm->next;
- }
- else {
- if(pm) {
- while(pm && pm->next && (float)pm->frame < t)
- pm = pm->next;
-
- copy_particle_key(key2, ((ParticleKey *)pm->data) + index, 1);
- copy_particle_key(key1, ((ParticleKey *)(pm->prev)->data) + index, 1);
- }
- else if(cache->mem_cache.first) {
- pm = cache->mem_cache.first;
- copy_particle_key(key2, ((ParticleKey *)pm->data) + index, 1);
- copy_particle_key(key1, ((ParticleKey *)pm->data) + index, 1);
- }
- }
- }
-}
/* Calculates paths ready for drawing/rendering. */
/* -Usefull for making use of opengl vertex arrays for super fast strand drawing. */
/* -Makes child strands possible and creates them too into the cache. */
@@ -2395,8 +2568,7 @@ void psys_cache_paths(Scene *scene, Object *ob, ParticleSystem *psys, float cfra
ParticleSettings *part = psys->part;
ParticleData *pa;
- ParticleKey keys[4], result, *kkey[2] = {NULL, NULL};
- HairKey *hkey[2] = {NULL, NULL};
+ ParticleKey result;
ParticleEdit *edit = 0;
ParticleEditKey *ekey = 0;
@@ -2405,11 +2577,14 @@ void psys_cache_paths(Scene *scene, Object *ob, ParticleSystem *psys, float cfra
BodyPoint *bp[2] = {NULL, NULL};
Material *ma;
+
+ ParticleInterpolationData pind;
float birthtime = 0.0, dietime = 0.0;
float t, time = 0.0, keytime = 0.0, dfra = 1.0, frs_sec = scene->r.frs_sec;
float col[4] = {0.5f, 0.5f, 0.5f, 1.0f};
float prev_tangent[3], hairmat[4][4];
+ float rotmat[3][3];
int k,i;
int steps = (int)pow(2.0, (double)psys->part->draw_step);
int totpart = psys->totpart;
@@ -2492,7 +2667,6 @@ void psys_cache_paths(Scene *scene, Object *ob, ParticleSystem *psys, float cfra
else memset(cache[i], 0, sizeof(*cache[i])*(steps+1));
if(!edit && !psys->totchild) {
- //pa_length = part->length * (1.0f - part->randlength*pa->r_ave[0]);
pa_length = 1.0f - part->randlength * 0.5 * (1.0f + pa->r_ave[0]);
if(vg_length)
pa_length *= psys_particle_value_from_verts(psmd->dm,part->from,pa,vg_length);
@@ -2504,38 +2678,27 @@ void psys_cache_paths(Scene *scene, Object *ob, ParticleSystem *psys, float cfra
ekey = edit->keys[i];
/*--get the first data points--*/
- if(keyed) {
- kkey[0] = pa->keys;
- kkey[1] = kkey[0] + 1;
-
- birthtime = kkey[0]->time;
- dietime = kkey[0][pa->totkey-1].time;
- }
- else if(baked) {
- get_pointcache_keys_for_time(psys, -1, 0.0f, NULL, NULL);
-
- birthtime = pa->time;
- dietime = pa->dietime;
- }
- else {
- hkey[0] = pa->hair;
- hkey[1] = hkey[0] + 1;
+ pind.keyed = keyed;
+ pind.cached = baked;
+ pind.soft = soft;
+ init_particle_interpolation(ob, psys, pa, &pind);
- birthtime = hkey[0]->time;
- dietime = hkey[0][pa->totkey-1].time;
- psys_mat_hair_to_global(ob, psmd->dm, psys->part->from, pa, hairmat);
- }
+ /* hairmat is needed for for non-hair particle too so we get proper rotations */
+ psys_mat_hair_to_global(ob, psmd->dm, psys->part->from, pa, hairmat);
+ VECCOPY(rotmat[0], hairmat[2]);
+ VECCOPY(rotmat[1], hairmat[1]);
+ VECCOPY(rotmat[2], hairmat[0]);
if(!edit) {
if(part->draw & PART_ABS_PATH_TIME) {
- birthtime = MAX2(birthtime, part->path_start);
- dietime = MIN2(dietime, part->path_end);
+ birthtime = MAX2(pind.birthtime, part->path_start);
+ dietime = MIN2(pind.dietime, part->path_end);
}
else {
- float tb = birthtime;
- birthtime = tb + part->path_start * (dietime - tb);
- dietime = tb + part->path_end * (dietime - tb);
+ float tb = pind.birthtime;
+ birthtime = tb + part->path_start * (pind.dietime - tb);
+ dietime = tb + part->path_end * (pind.dietime - tb);
}
if(birthtime >= dietime) {
@@ -2545,11 +2708,10 @@ void psys_cache_paths(Scene *scene, Object *ob, ParticleSystem *psys, float cfra
dietime = birthtime + pa_length * (dietime - birthtime);
}
-
- if(soft){
- bp[0] = soft->bpoint + pa->bpi;
- bp[1] = bp[0] + 1;
- }
+ else
+ /* XXX brecht: don't know if this code from 2.4 is correct
+ * still, but makes hair appear again in particle mode */
+ dietime= pind.hkey[0][pa->totkey-1].time;
/*--interpolate actual path from data points--*/
for(k=0, ca=cache[i]; k<=steps; k++, ca++){
@@ -2557,90 +2719,12 @@ void psys_cache_paths(Scene *scene, Object *ob, ParticleSystem *psys, float cfra
t = birthtime + time * (dietime - birthtime);
- if(keyed) {
- while(kkey[1]->time < t) {
- kkey[1]++;
- }
-
- kkey[0] = kkey[1] - 1;
- }
- else if(baked) {
- get_pointcache_keys_for_time(psys, i, t, keys+1, keys+2);
- }
- else {
- while(hkey[1]->time < t) {
- hkey[1]++;
- bp[1]++;
- }
-
- hkey[0] = hkey[1] - 1;
- }
-
- if(soft) {
- bp[0] = bp[1] - 1;
- bp_to_particle(keys + 1, bp[0], hkey[0]);
- bp_to_particle(keys + 2, bp[1], hkey[1]);
- }
- else if(keyed) {
- memcpy(keys + 1, kkey[0], sizeof(ParticleKey));
- memcpy(keys + 2, kkey[1], sizeof(ParticleKey));
- }
- else if(baked)
- ; /* keys already set */
- else {
- hair_to_particle(keys + 1, hkey[0]);
- hair_to_particle(keys + 2, hkey[1]);
- }
-
-
- if(!keyed && !baked) {
- if(soft) {
- if(hkey[0] != pa->hair)
- bp_to_particle(keys, bp[0] - 1, hkey[0] - 1);
- else
- bp_to_particle(keys, bp[0], hkey[0]);
- }
- else {
- if(hkey[0] != pa->hair)
- hair_to_particle(keys, hkey[0] - 1);
- else
- hair_to_particle(keys, hkey[0]);
- }
-
- if(soft) {
- if(hkey[1] != pa->hair + pa->totkey - 1)
- bp_to_particle(keys + 3, bp[1] + 1, hkey[1] + 1);
- else
- bp_to_particle(keys + 3, bp[1], hkey[1]);
- }
- else {
- if(hkey[1] != pa->hair + pa->totkey - 1)
- hair_to_particle(keys + 3, hkey[1] + 1);
- else
- hair_to_particle(keys + 3, hkey[1]);
- }
- }
-
- dfra = keys[2].time - keys[1].time;
+ result.time = -t;
- keytime = (t - keys[1].time) / dfra;
-
- /* convert velocity to timestep size */
- if(keyed || baked){
- VecMulf(keys[1].vel, dfra / frs_sec);
- VecMulf(keys[2].vel, dfra / frs_sec);
- }
+ do_particle_interpolation(psys, i, pa, t, frs_sec, &pind, &result);
- /* now we should have in chronologiacl order k1<=k2<=t<=k3<=k4 with keytime between [0,1]->[k2,k3] (k1 & k4 used for cardinal & bspline interpolation)*/
- psys_interpolate_particle((keyed || baked) ? -1 /* signal for cubic interpolation */
- : ((psys->part->flag & PART_HAIR_BSPLINE) ? KEY_BSPLINE : KEY_CARDINAL)
- ,keys, keytime, &result, 0);
-
- /* the velocity needs to be converted back from cubic interpolation */
- if(keyed || baked){
- VecMulf(result.vel, frs_sec / dfra);
- }
- else if(soft==NULL) { /* softbody and keyed are allready in global space */
+ /* keyed, baked and softbody are allready in global space */
+ if(!keyed && !baked && !soft) {
Mat4MulVecfl(hairmat, result.co);
}
@@ -2650,14 +2734,14 @@ void psys_cache_paths(Scene *scene, Object *ob, ParticleSystem *psys, float cfra
if(edit){
if(pset->brushtype==PE_BRUSH_WEIGHT){
if(k==steps)
- VecLerpf(ca->col, nosel_col, sel_col, hkey[0]->weight);
+ VecLerpf(ca->col, nosel_col, sel_col, pind.hkey[0]->weight);
else
VecLerpf(ca->col, nosel_col, sel_col,
- (1.0f - keytime) * hkey[0]->weight + keytime * hkey[1]->weight);
+ (1.0f - keytime) * pind.hkey[0]->weight + keytime * pind.hkey[1]->weight);
}
else{
- if((ekey + (hkey[0] - pa->hair))->flag & PEK_SELECT){
- if((ekey + (hkey[1] - pa->hair))->flag & PEK_SELECT){
+ if((ekey + (pind.hkey[0] - pa->hair))->flag & PEK_SELECT){
+ if((ekey + (pind.hkey[1] - pa->hair))->flag & PEK_SELECT){
VECCOPY(ca->col, sel_col);
}
else{
@@ -2665,7 +2749,7 @@ void psys_cache_paths(Scene *scene, Object *ob, ParticleSystem *psys, float cfra
}
}
else{
- if((ekey + (hkey[1] - pa->hair))->flag & PEK_SELECT){
+ if((ekey + (pind.hkey[1] - pa->hair))->flag & PEK_SELECT){
VecLerpf(ca->col, nosel_col, sel_col, keytime);
}
else{
@@ -2678,8 +2762,9 @@ void psys_cache_paths(Scene *scene, Object *ob, ParticleSystem *psys, float cfra
VECCOPY(ca->col, col);
}
}
+
- /*--modify paths--*/
+ /*--modify paths and calculate rotation & velocity--*/
VecSubf(vec,(cache[i]+1)->co,cache[i]->co);
length = VecLength(vec);
@@ -2708,12 +2793,18 @@ void psys_cache_paths(Scene *scene, Object *ob, ParticleSystem *psys, float cfra
float cosangle, angle, tangent[3], normal[3], q[4];
if(k == 1) {
+ /* calculate initial tangent for incremental rotations */
VECSUB(tangent, ca->co, (ca - 1)->co);
-
- vectoquat(tangent, OB_POSX, OB_POSZ, (ca-1)->rot);
-
VECCOPY(prev_tangent, tangent);
Normalize(prev_tangent);
+
+ /* First rotation is based on emitting face orientation. */
+ /* This is way better than having flipping rotations resulting */
+ /* from using a global axis as a rotation pole (vec_to_quat()). */
+ /* It's not an ideal solution though since it disregards the */
+ /* initial tangent, but taking that in to account will allow */
+ /* the possibility of flipping again. -jahka */
+ Mat3ToQuat_is_ok(rotmat, (ca-1)->rot);
}
else {
VECSUB(tangent, ca->co, (ca - 1)->co);
@@ -2780,15 +2871,6 @@ void copy_particle_key(ParticleKey *to, ParticleKey *from, int time){
memcpy(to,from,sizeof(ParticleKey));
to->time=to_time;
}
- /*
- VECCOPY(to->co,from->co);
- VECCOPY(to->vel,from->vel);
- QUATCOPY(to->rot,from->rot);
- if(time)
- to->time=from->time;
- to->flag=from->flag;
- to->sbw=from->sbw;
- */
}
void psys_get_from_key(ParticleKey *key, float *loc, float *vel, float *rot, float *time){
if(loc) VECCOPY(loc,key->co);
@@ -2959,7 +3041,12 @@ void object_add_particle_system(Scene *scene, Object *ob)
psys->pointcache = BKE_ptcache_add();
BLI_addtail(&ob->particlesystem, psys);
- psys->part = psys_new_settings("PSys", NULL);
+ psys->part = psys_new_settings("ParticleSettings", NULL);
+
+ if(BLI_countlist(&ob->particlesystem)>1)
+ sprintf(psys->name, "ParticleSystem %i", BLI_countlist(&ob->particlesystem));
+ else
+ strcpy(psys->name, "ParticleSystem");
md= modifier_new(eModifierType_ParticleSystem);
sprintf(md->name, "ParticleSystem %i", BLI_countlist(&ob->particlesystem));
@@ -3008,7 +3095,7 @@ static void default_particle_settings(ParticleSettings *part)
part->bb_uv_split=1;
part->bb_align=PART_BB_VIEW;
part->bb_split_offset=PART_BB_OFF_LINEAR;
- part->flag=PART_REACT_MULTIPLE|PART_HAIR_GEOMETRY;
+ part->flag=PART_REACT_MULTIPLE|PART_HAIR_GEOMETRY|PART_EDISTR|PART_TRAND;
part->sta= 1.0;
part->end= 100.0;
@@ -3017,8 +3104,6 @@ static void default_particle_settings(ParticleSettings *part)
part->totpart= 1000;
part->grid_res= 10;
part->timetweak= 1.0;
- part->keyed_time= 0.5;
- //part->userjit;
part->integrator= PART_INT_MIDPOINT;
part->phystype= PART_PHYS_NEWTON;
@@ -3032,19 +3117,13 @@ static void default_particle_settings(ParticleSettings *part)
part->reactevent= PART_EVENT_DEATH;
part->disp=100;
part->from= PART_FROM_FACE;
- part->length= 1.0;
- part->nbetween= 4;
- part->boidneighbours= 5;
- part->max_vel = 10.0f;
- part->average_vel = 0.3f;
- part->max_tan_acc = 0.2f;
- part->max_lat_acc = 1.0f;
+ part->normfac= 1.0f;
part->reactshape=1.0f;
part->mass=1.0;
- part->size=1.0;
+ part->size=0.05;
part->childsize=1.0;
part->child_nbr=10;
@@ -3059,17 +3138,19 @@ static void default_particle_settings(ParticleSettings *part)
part->rough2_size=1.0;
part->rough_end_shape=1.0;
+ part->clength=1.0f;
+ part->clength_thres=0.0f;
+
+ part->draw= PART_DRAW_EMITTER|PART_DRAW_MAT_COL;
part->draw_line[0]=0.5;
part->path_start = 0.0f;
part->path_end = 1.0f;
- part->banking=1.0;
- part->max_bank=1.0;
+ part->keyed_loops = 1;
+
+ for(i=0; i<10; i++)
+ part->effector_weight[i]=1.0f;
- for(i=0; i<BOID_TOT_RULES; i++){
- part->boidrule[i]=(char)i;
- part->boidfac[i]=0.5;
- }
#if 0 // XXX old animation system
part->ipo = NULL;
@@ -3103,6 +3184,8 @@ ParticleSettings *psys_copy_settings(ParticleSettings *part)
partn= copy_libblock(part);
if(partn->pd) partn->pd= MEM_dupallocN(part->pd);
if(partn->pd2) partn->pd2= MEM_dupallocN(part->pd2);
+
+ partn->boids = boid_copy_settings(part->boids);
return partn;
}
@@ -3480,7 +3563,7 @@ float psys_get_child_size(ParticleSystem *psys, ChildParticle *cpa, float cfra,
}
static void get_child_modifier_parameters(ParticleSettings *part, ParticleThreadContext *ctx, ChildParticle *cpa, short cpa_from, int cpa_num, float *cpa_fuv, float *orco, ParticleTexture *ptex)
{
- ptex->length=part->length*(1.0f - part->randlength*cpa->rand[0]);
+ ptex->length= 1.0f - part->randlength*cpa->rand[0];
ptex->clump=1.0;
ptex->kink=1.0;
ptex->rough1= 1.0;
@@ -3489,6 +3572,8 @@ static void get_child_modifier_parameters(ParticleSettings *part, ParticleThread
ptex->exist= 1.0;
ptex->effector= 1.0;
+ ptex->length*= part->clength_thres < cpa->rand[1] ? part->clength : 1.0f;
+
get_cpa_texture(ctx->dm,ctx->ma,cpa_num,cpa_fuv,orco,ptex,
MAP_PA_DENS|MAP_PA_LENGTH|MAP_PA_CLUMP|MAP_PA_KINK|MAP_PA_ROUGH);
@@ -3511,7 +3596,7 @@ static void get_child_modifier_parameters(ParticleSettings *part, ParticleThread
if(ctx->vg_effector)
ptex->effector*=psys_interpolate_value_from_verts(ctx->dm,cpa_from,cpa_num,cpa_fuv,ctx->vg_effector);
}
-static void do_child_modifiers(Scene *scene, Object *ob, ParticleSystem *psys, ParticleSettings *part, ParticleTexture *ptex, ParticleKey *par, float *par_rot, ChildParticle *cpa, float *orco, ParticleKey *state, float t)
+static void do_child_modifiers(Scene *scene, Object *ob, ParticleSystem *psys, ParticleSettings *part, ParticleTexture *ptex, ParticleKey *par, float *par_rot, ChildParticle *cpa, float *orco, float mat[4][4], ParticleKey *state, float t)
{
int guided = 0;
@@ -3528,13 +3613,13 @@ static void do_child_modifiers(Scene *scene, Object *ob, ParticleSystem *psys, P
}
if(part->rough1 != 0.0 && ptex->rough1 != 0.0)
- do_rough(orco, t, ptex->rough1*part->rough1, part->rough1_size, 0.0, state);
+ do_rough(orco, mat, t, ptex->rough1*part->rough1, part->rough1_size, 0.0, state);
if(part->rough2 != 0.0 && ptex->rough2 != 0.0)
- do_rough(cpa->rand, t, ptex->rough2*part->rough2, part->rough2_size, part->rough2_thres, state);
+ do_rough(cpa->rand, mat, t, ptex->rough2*part->rough2, part->rough2_size, part->rough2_thres, state);
if(part->rough_end != 0.0 && ptex->roughe != 0.0)
- do_rough_end(cpa->rand, t, ptex->roughe*part->rough_end, part->rough_end_shape, state, par);
+ do_rough_end(cpa->rand, mat, t, ptex->roughe*part->rough_end, part->rough_end_shape, state);
}
/* get's hair (or keyed) particles state at the "path time" specified in state->time */
void psys_get_particle_on_path(Scene *scene, Object *ob, ParticleSystem *psys, int p, ParticleKey *state, int vel)
@@ -3545,12 +3630,11 @@ void psys_get_particle_on_path(Scene *scene, Object *ob, ParticleSystem *psys, i
ParticleData *pa;
ChildParticle *cpa;
ParticleTexture ptex;
- ParticleKey *kkey[2] = {NULL, NULL};
- HairKey *hkey[2] = {NULL, NULL};
ParticleKey *par=0, keys[4], tstate;
ParticleThreadContext ctx; /* fake thread context for child modifiers */
+ ParticleInterpolationData pind;
- float t, real_t, dfra, keytime, frs_sec = scene->r.frs_sec;
+ float t, frs_sec = scene->r.frs_sec;
float co[3], orco[3];
float hairmat[4][4];
int totparent = 0;
@@ -3558,7 +3642,7 @@ void psys_get_particle_on_path(Scene *scene, Object *ob, ParticleSystem *psys, i
int totchild = psys->totchild;
short between = 0, edit = 0;
- int keyed = psys->flag & PSYS_KEYED;
+ int keyed = part->phystype & PART_PHYS_KEYED && psys->flag & PSYS_KEYED;
int cached = !keyed && part->type != PART_HAIR;
float *cpa_fuv; int cpa_num; short cpa_from;
@@ -3580,88 +3664,14 @@ void psys_get_particle_on_path(Scene *scene, Object *ob, ParticleSystem *psys, i
key_from_object(pa->stick_ob,state);
return;
}
-
- if(keyed) {
- kkey[0] = pa->keys;
- kkey[1] = kkey[0] + 1;
-
- if(state->time < 0.0f)
- real_t = -state->time;
- else
- real_t = kkey[0]->time + t * (kkey[0][pa->totkey-1].time - kkey[0]->time);
- }
- else if(cached) {
- get_pointcache_keys_for_time(psys, -1, 0.0f, NULL, NULL);
- }
- else {
- hkey[0] = pa->hair;
- hkey[1] = pa->hair + 1;
-
- if(state->time < 0.0f)
- real_t = -state->time;
- else
- real_t = hkey[0]->time + t * (hkey[0][pa->totkey-1].time - hkey[0]->time);
- }
- if(keyed) {
- while(kkey[1]->time < real_t) {
- kkey[1]++;
- }
- kkey[0] = kkey[1] - 1;
-
- memcpy(keys + 1, kkey[0], sizeof(ParticleKey));
- memcpy(keys + 2, kkey[1], sizeof(ParticleKey));
- }
- else if(cached) {
- if(state->time < 0.0f) /* flag for time in frames */
- real_t = -state->time;
- else
- real_t = pa->time + t * (pa->dietime - pa->time);
-
- get_pointcache_keys_for_time(psys, p, real_t, keys+1, keys+2);
- }
- else {
- while(hkey[1]->time < real_t)
- hkey[1]++;
-
- hkey[0] = hkey[1] - 1;
-
- hair_to_particle(keys + 1, hkey[0]);
- hair_to_particle(keys + 2, hkey[1]);
- }
+ pind.keyed = keyed;
+ pind.cached = cached;
+ pind.soft = NULL;
+ init_particle_interpolation(ob, psys, pa, &pind);
+ do_particle_interpolation(psys, p, pa, t, frs_sec, &pind, state);
if(!keyed && !cached) {
- if(hkey[0] != pa->hair)
- hair_to_particle(keys, hkey[0] - 1);
- else
- hair_to_particle(keys, hkey[0]);
-
- if(hkey[1] != pa->hair + pa->totkey - 1)
- hair_to_particle(keys + 3, hkey[1] + 1);
- else
- hair_to_particle(keys + 3, hkey[1]);
- }
-
- dfra = keys[2].time - keys[1].time;
-
- keytime = (real_t - keys[1].time) / dfra;
-
- /* convert velocity to timestep size */
- if(keyed || cached){
- VecMulf(keys[1].vel, dfra / frs_sec);
- VecMulf(keys[2].vel, dfra / frs_sec);
- QuatInterpol(state->rot,keys[1].rot,keys[2].rot,keytime);
- }
-
- psys_interpolate_particle((keyed || cached) ? -1 /* signal for cubic interpolation */
- : ((psys->part->flag & PART_HAIR_BSPLINE) ? KEY_BSPLINE : KEY_CARDINAL)
- ,keys, keytime, state, 1);
-
- /* the velocity needs to be converted back from cubic interpolation */
- if(keyed || cached){
- VecMulf(state->vel, frs_sec / dfra);
- }
- else {
if((pa->flag & PARS_REKEY)==0) {
psys_mat_hair_to_global(ob, psmd->dm, part->from, pa, hairmat);
Mat4MulVecfl(hairmat, state->co);
@@ -3709,8 +3719,6 @@ void psys_get_particle_on_path(Scene *scene, Object *ob, ParticleSystem *psys, i
cpa_num=cpa->num;
foffset= cpa->foffset;
- if(part->childtype == PART_CHILD_FACES)
- foffset = -(2.0f + part->childspread);
cpa_fuv = cpa->fuv;
cpa_from = PART_FROM_FACE;
@@ -3721,11 +3729,14 @@ void psys_get_particle_on_path(Scene *scene, Object *ob, ParticleSystem *psys, i
//Mat4MulVecfl(ob->obmat,cpa_1st);
+ pa = psys->particles + cpa->parent;
+
+ psys_mat_hair_to_global(ob, psmd->dm, psys->part->from, pa, hairmat);
+
pa=0;
}
else{
/* get the parent state */
-
keys->time = state->time;
psys_get_particle_on_path(scene, ob, psys, cpa->parent, keys,1);
@@ -3737,6 +3748,8 @@ void psys_get_particle_on_path(Scene *scene, Object *ob, ParticleSystem *psys, i
cpa_fuv=pa->fuv;
psys_particle_on_emitter(psmd,cpa_from,cpa_num,DMCACHE_ISCHILD,cpa_fuv,pa->foffset,co,0,0,0,orco,0);
+
+ psys_mat_hair_to_global(ob, psmd->dm, psys->part->from, pa, hairmat);
}
/* correct child ipo timing */
@@ -3785,7 +3798,7 @@ void psys_get_particle_on_path(Scene *scene, Object *ob, ParticleSystem *psys, i
copy_particle_key(&tstate, state, 1);
/* apply different deformations to the child path */
- do_child_modifiers(scene, ob, psys, part, &ptex, par, par->rot, cpa, orco, state, t);
+ do_child_modifiers(scene, ob, psys, part, &ptex, par, par->rot, cpa, orco, hairmat, state, t);
/* try to estimate correct velocity */
if(vel){
@@ -3856,7 +3869,7 @@ int psys_get_particle_state(struct Scene *scene, Object *ob, ParticleSystem *psy
state->time= (cfra-(part->sta+(part->end-part->sta)*cpa->rand[0]))/(part->lifetime*cpa->rand[1]);
}
else
- state->time= (cfra-pa->time)/(pa->dietime-pa->time);
+ state->time= -cfra;
psys_get_particle_on_path(scene, ob, psys, p, state,1);
return 1;
@@ -3893,57 +3906,55 @@ int psys_get_particle_state(struct Scene *scene, Object *ob, ParticleSystem *psy
calc_latt_deform(psys->lattice, state->co,1.0f);
}
else{
- if (pa) { /* TODO PARTICLE - should this ever be NULL? - Campbell */
- if(pa->state.time==state->time || ELEM(part->phystype,PART_PHYS_NO,PART_PHYS_KEYED))
- copy_particle_key(state, &pa->state, 1);
- else if(pa->prev_state.time==state->time)
- copy_particle_key(state, &pa->prev_state, 1);
- else {
- /* let's interpolate to try to be as accurate as possible */
- if(pa->state.time + 1.0f > state->time && pa->prev_state.time - 1.0f < state->time) {
- ParticleKey keys[4];
- float dfra, keytime, frs_sec = scene->r.frs_sec;
+ if(pa->state.time==state->time || ELEM(part->phystype,PART_PHYS_NO,PART_PHYS_KEYED))
+ copy_particle_key(state, &pa->state, 1);
+ else if(pa->prev_state.time==state->time)
+ copy_particle_key(state, &pa->prev_state, 1);
+ else {
+ /* let's interpolate to try to be as accurate as possible */
+ if(pa->state.time + 1.0f > state->time && pa->prev_state.time - 1.0f < state->time) {
+ ParticleKey keys[4];
+ float dfra, keytime, frs_sec = scene->r.frs_sec;
- if(pa->prev_state.time >= pa->state.time) {
- /* prev_state is wrong so let's not use it, this can happen at frame 1 or particle birth */
- copy_particle_key(state, &pa->state, 1);
+ if(pa->prev_state.time >= pa->state.time) {
+ /* prev_state is wrong so let's not use it, this can happen at frame 1 or particle birth */
+ copy_particle_key(state, &pa->state, 1);
- VECADDFAC(state->co, state->co, state->vel, (state->time-pa->state.time)/frs_sec);
- }
- else {
- copy_particle_key(keys+1, &pa->prev_state, 1);
- copy_particle_key(keys+2, &pa->state, 1);
+ VECADDFAC(state->co, state->co, state->vel, (state->time-pa->state.time)/frs_sec);
+ }
+ else {
+ copy_particle_key(keys+1, &pa->prev_state, 1);
+ copy_particle_key(keys+2, &pa->state, 1);
- dfra = keys[2].time - keys[1].time;
+ dfra = keys[2].time - keys[1].time;
- keytime = (state->time - keys[1].time) / dfra;
+ keytime = (state->time - keys[1].time) / dfra;
- /* convert velocity to timestep size */
- VecMulf(keys[1].vel, dfra / frs_sec);
- VecMulf(keys[2].vel, dfra / frs_sec);
-
- psys_interpolate_particle(-1, keys, keytime, state, 1);
-
- /* convert back to real velocity */
- VecMulf(state->vel, frs_sec / dfra);
+ /* convert velocity to timestep size */
+ VecMulf(keys[1].vel, dfra / frs_sec);
+ VecMulf(keys[2].vel, dfra / frs_sec);
+
+ psys_interpolate_particle(-1, keys, keytime, state, 1);
+
+ /* convert back to real velocity */
+ VecMulf(state->vel, frs_sec / dfra);
- VecLerpf(state->ave, keys[1].ave, keys[2].ave, keytime);
- QuatInterpol(state->rot, keys[1].rot, keys[2].rot, keytime);
- }
- }
- else {
- /* extrapolating over big ranges is not accurate so let's just give something close to reasonable back */
- copy_particle_key(state, &pa->state, 0);
+ VecLerpf(state->ave, keys[1].ave, keys[2].ave, keytime);
+ QuatInterpol(state->rot, keys[1].rot, keys[2].rot, keytime);
}
}
-
- if(pa->alive==PARS_DEAD && part->flag&PART_STICKY && pa->flag&PARS_STICKY && pa->stick_ob){
- key_from_object(pa->stick_ob,state);
+ else {
+ /* extrapolating over big ranges is not accurate so let's just give something close to reasonable back */
+ copy_particle_key(state, &pa->state, 0);
}
+ }
- if(psys->lattice)
- calc_latt_deform(psys->lattice, state->co,1.0f);
+ if(pa->alive==PARS_DEAD && part->flag&PART_STICKY && pa->flag&PARS_STICKY && pa->stick_ob){
+ key_from_object(pa->stick_ob,state);
}
+
+ if(psys->lattice)
+ calc_latt_deform(psys->lattice, state->co,1.0f);
}
return 1;
diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c
index 07e0e82a86d..b5d58e9db8c 100644
--- a/source/blender/blenkernel/intern/particle_system.c
+++ b/source/blender/blenkernel/intern/particle_system.c
@@ -37,6 +37,7 @@
#include "MEM_guardedalloc.h"
+#include "DNA_boid_types.h"
#include "DNA_particle_types.h"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
@@ -49,6 +50,7 @@
#include "DNA_scene_types.h"
#include "DNA_texture_types.h"
#include "DNA_ipo_types.h" // XXX old animation system stuff... to be removed!
+#include "DNA_listBase.h"
#include "BLI_rand.h"
#include "BLI_jitter.h"
@@ -60,6 +62,7 @@
#include "BLI_threads.h"
#include "BKE_anim.h"
+#include "BKE_boids.h"
#include "BKE_cdderivedmesh.h"
#include "BKE_collision.h"
#include "BKE_displist.h"
@@ -111,10 +114,7 @@ static int get_current_display_percentage(ParticleSystem *psys)
return 100;
if(part->phystype==PART_PHYS_KEYED){
- if(psys->flag & PSYS_FIRST_KEYED)
- return psys->part->disp;
- else
- return 100;
+ return psys->part->disp;
}
else
return psys->part->disp;
@@ -175,6 +175,7 @@ void psys_reset(ParticleSystem *psys, int mode)
static void realloc_particles(Object *ob, ParticleSystem *psys, int new_totpart)
{
ParticleData *newpars = 0, *pa;
+ BoidData *newboids = 0;
int i, totpart, totsaved = 0;
if(new_totpart<0) {
@@ -188,22 +189,34 @@ static void realloc_particles(Object *ob, ParticleSystem *psys, int new_totpart)
else
totpart=new_totpart;
- if(totpart)
+ if(totpart) {
newpars= MEM_callocN(totpart*sizeof(ParticleData), "particles");
+
+ if(psys->part->phystype == PART_PHYS_BOIDS)
+ newboids = MEM_callocN(totpart*sizeof(BoidData), "Boid Data");
+ }
if(psys->particles) {
totsaved=MIN2(psys->totpart,totpart);
/*save old pars*/
- if(totsaved)
+ if(totsaved) {
memcpy(newpars,psys->particles,totsaved*sizeof(ParticleData));
+ if(newboids)
+ memcpy(newboids, psys->particles->boid, totsaved*sizeof(BoidData));
+ }
+
if(psys->particles->keys)
MEM_freeN(psys->particles->keys);
- for(i=0, pa=psys->particles; i<psys->totpart; i++, pa++)
+ if(psys->particles->boid)
+ MEM_freeN(psys->particles->boid);
+
+ for(i=0, pa=newpars; i<totsaved; i++, pa++) {
if(pa->keys) {
pa->keys= NULL;
pa->totkey= 0;
}
+ }
for(i=totsaved, pa=psys->particles+totsaved; i<psys->totpart; i++, pa++)
if(pa->hair) MEM_freeN(pa->hair);
@@ -212,6 +225,13 @@ static void realloc_particles(Object *ob, ParticleSystem *psys, int new_totpart)
}
psys->particles=newpars;
+ if(newboids) {
+ pa = psys->particles;
+ pa->boid = newboids;
+ for(i=1, pa++; i<totpart; i++,pa++)
+ pa->boid = (pa-1)->boid + 1;
+ }
+
if(psys->child) {
MEM_freeN(psys->child);
psys->child=0;
@@ -1610,12 +1630,15 @@ void initialize_particle(ParticleData *pa, int p, Object *ob, ParticleSystem *ps
rand= BLI_frand();
/* while loops are to have a spherical distribution (avoid cubic distribution) */
- length=2.0f;
- while(length>1.0){
- pa->r_ve[0]=2.0f*(BLI_frand()-0.5f);
- pa->r_ve[1]=2.0f*(BLI_frand()-0.5f);
- pa->r_ve[2]=2.0f*(BLI_frand()-0.5f);
- length=VecLength(pa->r_ve);
+ if(part->phystype != PART_PHYS_BOIDS) {
+ /* boids store gravity in r_ve, so skip here */
+ length=2.0f;
+ while(length>1.0){
+ pa->r_ve[0]=2.0f*(BLI_frand()-0.5f);
+ pa->r_ve[1]=2.0f*(BLI_frand()-0.5f);
+ pa->r_ve[2]=2.0f*(BLI_frand()-0.5f);
+ length=VecLength(pa->r_ve);
+ }
}
length=2.0f;
@@ -1831,122 +1854,164 @@ void reset_particle(Scene *scene, ParticleData *pa, ParticleSystem *psys, Partic
QuatMul(r_rot,r_rot,rot);
}
}
- /* conversion done so now we apply new: */
- /* -velocity from: */
- /* *reactions */
- if(dtime>0.0f){
- VECSUB(vel,pa->state.vel,pa->prev_state.vel);
- }
+ if(part->phystype==PART_PHYS_BOIDS) {
+ float dvec[3], q[4], mat[3][3];
+
+ VECCOPY(pa->state.co,loc);
- /* *emitter velocity */
- if(dtime!=0.0 && part->obfac!=0.0){
- VECSUB(vel,loc,pa->state.co);
- VecMulf(vel,part->obfac/dtime);
+ /* boids don't get any initial velocity */
+ pa->state.vel[0]=pa->state.vel[1]=pa->state.vel[2]=0.0f;
+
+ /* boids store direction in ave */
+ if(fabs(nor[2])==1.0f) {
+ VecSubf(pa->state.ave, loc, ob->obmat[3]);
+ Normalize(pa->state.ave);
+ }
+ else {
+ VECCOPY(pa->state.ave, nor);
+ }
+ /* and gravity in r_ve */
+ pa->r_ve[0] = pa->r_ve[1] = 0.0f;
+ pa->r_ve[2] = -1.0f;
+ if(part->acc[2]!=0.0f)
+ pa->r_ve[2] = part->acc[2];
+
+ /* calculate rotation matrix */
+ Projf(dvec, pa->r_ve, pa->state.ave);
+ VecSubf(mat[0], pa->state.ave, dvec);
+ Normalize(mat[0]);
+ VECCOPY(mat[2], pa->r_ve);
+ VecMulf(mat[2], -1.0f);
+ Normalize(mat[2]);
+ Crossf(mat[1], mat[2], mat[0]);
+
+ /* apply rotation */
+ Mat3ToQuat_is_ok(mat, q);
+ QuatCopy(pa->state.rot, q);
+
+ pa->boid->health = part->boids->health;
+ pa->boid->mode = eBoidMode_InAir;
+ pa->boid->state_id = ((BoidState*)part->boids->states.first)->id;
+ pa->boid->acc[0]=pa->boid->acc[1]=pa->boid->acc[2]=0.0f;
}
-
- /* *emitter normal */
- if(part->normfac!=0.0)
- VECADDFAC(vel,vel,nor,part->normfac);
-
- /* *emitter tangent */
- if(part->tanfac!=0.0)
- VECADDFAC(vel,vel,vtan,part->tanfac*(vg_tan?psys_particle_value_from_verts(psmd->dm,part->from,pa,vg_tan):1.0f));
+ else {
+ /* conversion done so now we apply new: */
+ /* -velocity from: */
- /* *texture */
- /* TODO */
+ /* *reactions */
+ if(dtime>0.0f){
+ VECSUB(vel,pa->state.vel,pa->prev_state.vel);
+ }
- /* *random */
- if(part->randfac!=0.0)
- VECADDFAC(vel,vel,r_vel,part->randfac);
+ /* *emitter velocity */
+ if(dtime!=0.0 && part->obfac!=0.0){
+ VECSUB(vel,loc,pa->state.co);
+ VecMulf(vel,part->obfac/dtime);
+ }
+
+ /* *emitter normal */
+ if(part->normfac!=0.0)
+ VECADDFAC(vel,vel,nor,part->normfac);
+
+ /* *emitter tangent */
+ if(psmd && part->tanfac!=0.0)
+ VECADDFAC(vel,vel,vtan,part->tanfac*(vg_tan?psys_particle_value_from_verts(psmd->dm,part->from,pa,vg_tan):1.0f));
- /* *particle */
- if(part->partfac!=0.0)
- VECADDFAC(vel,vel,p_vel,part->partfac);
+ /* *texture */
+ /* TODO */
-#if 0 // XXX old animation system
- icu=find_ipocurve(psys->part->ipo,PART_EMIT_VEL);
- if(icu){
- calc_icu(icu,100*((pa->time-part->sta)/(part->end-part->sta)));
- ptex.ivel*=icu->curval;
- }
-#endif // XXX old animation system
+ /* *random */
+ if(part->randfac!=0.0)
+ VECADDFAC(vel,vel,r_vel,part->randfac);
- VecMulf(vel,ptex.ivel);
-
- VECCOPY(pa->state.vel,vel);
+ /* *particle */
+ if(part->partfac!=0.0)
+ VECADDFAC(vel,vel,p_vel,part->partfac);
- /* -location from emitter */
- VECCOPY(pa->state.co,loc);
+ //icu=find_ipocurve(psys->part->ipo,PART_EMIT_VEL);
+ //if(icu){
+ // calc_icu(icu,100*((pa->time-part->sta)/(part->end-part->sta)));
+ // ptex.ivel*=icu->curval;
+ //}
- /* -rotation */
- pa->state.rot[0]=1.0;
- pa->state.rot[1]=pa->state.rot[2]=pa->state.rot[3]=0.0;
+ VecMulf(vel,ptex.ivel);
- if(part->rotmode){
- /* create vector into which rotation is aligned */
- switch(part->rotmode){
- case PART_ROT_NOR:
- VecCopyf(rot_vec, nor);
- break;
- case PART_ROT_VEL:
- VecCopyf(rot_vec, vel);
- break;
- case PART_ROT_GLOB_X:
- case PART_ROT_GLOB_Y:
- case PART_ROT_GLOB_Z:
- rot_vec[part->rotmode - PART_ROT_GLOB_X] = 1.0f;
- break;
- case PART_ROT_OB_X:
- case PART_ROT_OB_Y:
- case PART_ROT_OB_Z:
- VecCopyf(rot_vec, ob->obmat[part->rotmode - PART_ROT_OB_X]);
- break;
- }
+ //if(ELEM(part->phystype, PART_PHYS_GRADU_EX, PART_PHYS_GRADU_SIM))
+ // VecAddf(vel,vel,part->acc);
- /* create rotation quat */
- VecNegf(rot_vec);
- vectoquat(rot_vec, OB_POSX, OB_POSZ, q2);
+ VECCOPY(pa->state.vel,vel);
- /* randomize rotation quat */
- if(part->randrotfac!=0.0f)
- QuatInterpol(rot, q2, r_rot, part->randrotfac);
- else
- QuatCopy(rot,q2);
-
- /* rotation phase */
- phasefac = part->phasefac;
- if(part->randphasefac != 0.0f) /* abuse r_ave[0] as a random number */
- phasefac += part->randphasefac * pa->r_ave[0];
- VecRotToQuat(x_vec, phasefac*(float)M_PI, q_phase);
+ /* -location from emitter */
+ VECCOPY(pa->state.co,loc);
- /* combine base rotation & phase */
- QuatMul(pa->state.rot, rot, q_phase);
- }
+ /* -rotation */
+ pa->state.rot[0]=1.0;
+ pa->state.rot[1]=pa->state.rot[2]=pa->state.rot[3]=0.0;
+
+ if(part->rotmode){
+ /* create vector into which rotation is aligned */
+ switch(part->rotmode){
+ case PART_ROT_NOR:
+ VecCopyf(rot_vec, nor);
+ break;
+ case PART_ROT_VEL:
+ VecCopyf(rot_vec, vel);
+ break;
+ case PART_ROT_GLOB_X:
+ case PART_ROT_GLOB_Y:
+ case PART_ROT_GLOB_Z:
+ rot_vec[part->rotmode - PART_ROT_GLOB_X] = 1.0f;
+ break;
+ case PART_ROT_OB_X:
+ case PART_ROT_OB_Y:
+ case PART_ROT_OB_Z:
+ VecCopyf(rot_vec, ob->obmat[part->rotmode - PART_ROT_OB_X]);
+ break;
+ }
+
+ /* create rotation quat */
+ VecNegf(rot_vec);
+ vectoquat(rot_vec, OB_POSX, OB_POSZ, q2);
- /* -angular velocity */
+ /* randomize rotation quat */
+ if(part->randrotfac!=0.0f)
+ QuatInterpol(rot, q2, r_rot, part->randrotfac);
+ else
+ QuatCopy(rot,q2);
- pa->state.ave[0] = pa->state.ave[1] = pa->state.ave[2] = 0.0;
+ /* rotation phase */
+ phasefac = part->phasefac;
+ if(part->randphasefac != 0.0f) /* abuse r_ave[0] as a random number */
+ phasefac += part->randphasefac * pa->r_ave[0];
+ VecRotToQuat(x_vec, phasefac*(float)M_PI, q_phase);
- if(part->avemode){
- switch(part->avemode){
- case PART_AVE_SPIN:
- VECCOPY(pa->state.ave,vel);
- break;
- case PART_AVE_RAND:
- VECCOPY(pa->state.ave,r_ave);
- break;
+ /* combine base rotation & phase */
+ QuatMul(pa->state.rot, rot, q_phase);
}
- Normalize(pa->state.ave);
- VecMulf(pa->state.ave,part->avefac);
-#if 0 // XXX old animation system
- icu=find_ipocurve(psys->part->ipo,PART_EMIT_AVE);
- if(icu){
- calc_icu(icu,100*((pa->time-part->sta)/(part->end-part->sta)));
- VecMulf(pa->state.ave,icu->curval);
+ /* -angular velocity */
+
+ pa->state.ave[0] = pa->state.ave[1] = pa->state.ave[2] = 0.0;
+
+ if(part->avemode){
+ switch(part->avemode){
+ case PART_AVE_SPIN:
+ VECCOPY(pa->state.ave,vel);
+ break;
+ case PART_AVE_RAND:
+ VECCOPY(pa->state.ave,r_ave);
+ break;
+ }
+ Normalize(pa->state.ave);
+ VecMulf(pa->state.ave,part->avefac);
+
+ //icu=find_ipocurve(psys->part->ipo,PART_EMIT_AVE);
+ //if(icu){
+ // calc_icu(icu,100*((pa->time-part->sta)/(part->end-part->sta)));
+ // VecMulf(pa->state.ave,icu->curval);
+ //}
}
-#endif // XXX old animation system
}
pa->dietime = pa->time + pa->lifetime;
@@ -1974,67 +2039,57 @@ static void reset_all_particles(Scene *scene, Object *ob, ParticleSystem *psys,
MEM_freeN(vg_vel);
}
/************************************************/
-/* Keyed particles */
+/* Particle targets */
/************************************************/
-/* a bit of an unintuitive function :) counts objects in a keyed chain and returns 1 if some of them were selected (used in drawing) */
-int psys_count_keyed_targets(Object *ob, ParticleSystem *psys)
+ParticleSystem *psys_get_target_system(Object *ob, ParticleTarget *pt)
{
- ParticleSystem *kpsys=psys,*tpsys;
- ParticleSettings *tpart;
- Object *kob=ob,*tob;
- int select=ob->flag&SELECT;
- short totkeyed=0;
- Base *base;
+ ParticleSystem *psys = NULL;
- ListBase lb;
- lb.first=lb.last=0;
-
- tob=psys->keyed_ob;
- while(tob){
- if((tpsys=BLI_findlink(&tob->particlesystem,kpsys->keyed_psys-1))){
- tpart=tpsys->part;
-
- if(tpart->phystype==PART_PHYS_KEYED){
- if(lb.first){
- for(base=lb.first;base;base=base->next){
- if(tob==base->object){
- fprintf(stderr,"Error: loop in keyed chain!\n");
- BLI_freelistN(&lb);
- return select;
- }
- }
- }
- base=MEM_callocN(sizeof(Base), "keyed base");
- base->object=tob;
- BLI_addtail(&lb,base);
-
- if(tob->flag&SELECT)
- select++;
- kob=tob;
- kpsys=tpsys;
- tob=tpsys->keyed_ob;
- totkeyed++;
- }
- else{
- tob=0;
- totkeyed++;
- }
+ if(pt->ob == NULL || pt->ob == ob)
+ psys = BLI_findlink(&ob->particlesystem, pt->psys-1);
+ else
+ psys = BLI_findlink(&pt->ob->particlesystem, pt->psys-1);
+
+ if(psys)
+ pt->flag |= PTARGET_VALID;
+ else
+ pt->flag &= ~PTARGET_VALID;
+
+ return psys;
+}
+/************************************************/
+/* Keyed particles */
+/************************************************/
+/* Counts valid keyed targets */
+void psys_count_keyed_targets(Object *ob, ParticleSystem *psys)
+{
+ ParticleSystem *kpsys;
+ ParticleTarget *pt = psys->targets.first;
+ int keys_valid = 1;
+ psys->totkeyed = 0;
+
+ for(; pt; pt=pt->next) {
+ kpsys = psys_get_target_system(ob, pt);
+
+ if(kpsys && kpsys->totpart) {
+ psys->totkeyed += keys_valid;
+ if(psys->flag & PSYS_KEYED_TIMING && pt->duration != 0.0f)
+ psys->totkeyed += 1;
+ }
+ else {
+ keys_valid = 0;
}
- else
- tob=0;
}
- psys->totkeyed=totkeyed;
- BLI_freelistN(&lb);
- return select;
+
+ psys->totkeyed *= psys->flag & PSYS_KEYED_TIMING ? 1 : psys->part->keyed_loops;
}
static void set_keyed_keys(Scene *scene, Object *ob, ParticleSystem *psys)
{
- Object *kob = ob;
ParticleSystem *kpsys = psys;
+ ParticleTarget *pt;
ParticleData *pa;
- int totpart = psys->totpart, i, k, totkeys = psys->totkeyed + 1;
- float prevtime, nexttime, keyedtime;
+ int totpart = psys->totpart, i, k, totkeys = psys->totkeyed;
/* no proper targets so let's clear and bail out */
if(psys->totkeyed==0) {
@@ -2046,7 +2101,7 @@ static void set_keyed_keys(Scene *scene, Object *ob, ParticleSystem *psys)
if(totpart && psys->particles->totkey != totkeys) {
free_keyed_keys(psys);
- psys->particles->keys = MEM_callocN(psys->totpart*totkeys*sizeof(ParticleKey), "Keyed keys");
+ psys->particles->keys = MEM_callocN(totpart*totkeys*sizeof(ParticleKey), "Keyed keys");
psys->particles->totkey = totkeys;
for(i=1, pa=psys->particles+1; i<totpart; i++,pa++){
@@ -2057,32 +2112,36 @@ static void set_keyed_keys(Scene *scene, Object *ob, ParticleSystem *psys)
psys->flag &= ~PSYS_KEYED;
+
+ pt = psys->targets.first;
for(k=0; k<totkeys; k++) {
+ if(pt->ob)
+ kpsys = BLI_findlink(&pt->ob->particlesystem, pt->psys - 1);
+ else
+ kpsys = BLI_findlink(&ob->particlesystem, pt->psys - 1);
+
for(i=0,pa=psys->particles; i<totpart; i++, pa++) {
(pa->keys + k)->time = -1.0; /* use current time */
- if(kpsys->totpart > 0)
- psys_get_particle_state(scene, kob, kpsys, i%kpsys->totpart, pa->keys + k, 1);
+ psys_get_particle_state(scene, pt->ob, kpsys, i%kpsys->totpart, pa->keys + k, 1);
- if(k==0)
- pa->keys->time = pa->time;
- else if(k==totkeys-1)
- (pa->keys + k)->time = pa->time + pa->lifetime;
- else{
- if(psys->flag & PSYS_KEYED_TIME){
- prevtime = (pa->keys + k - 1)->time;
- nexttime = pa->time + pa->lifetime;
- keyedtime = kpsys->part->keyed_time;
- (pa->keys + k)->time = (1.0f - keyedtime) * prevtime + keyedtime * nexttime;
+ if(psys->flag & PSYS_KEYED_TIMING){
+ (pa->keys+k)->time = pa->time + pt->time;
+ if(pt->duration != 0.0f && k+1 < totkeys) {
+ copy_particle_key(pa->keys+k+1, pa->keys+k, 1);
+ (pa->keys+k+1)->time = pa->time + pt->time + pt->duration;
}
- else
- (pa->keys+k)->time = pa->time + (float)k / (float)(totkeys - 1) * pa->lifetime;
}
+ else if(totkeys > 1)
+ (pa->keys+k)->time = pa->time + (float)k / (float)(totkeys - 1) * pa->lifetime;
+ else
+ pa->keys->time = pa->time;
}
- if(kpsys->keyed_ob){
- kob = kpsys->keyed_ob;
- kpsys = BLI_findlink(&kob->particlesystem, kpsys->keyed_psys - 1);
- }
+
+ if(psys->flag & PSYS_KEYED_TIMING && pt->duration!=0.0f)
+ k++;
+
+ pt = (pt->next && pt->next->flag & PTARGET_VALID)? pt->next : psys->targets.first;
}
psys->flag |= PSYS_KEYED;
@@ -2198,6 +2257,60 @@ void psys_get_reactor_target(Object *ob, ParticleSystem *psys, Object **target_o
/************************************************/
/* Point Cache */
/************************************************/
+void psys_make_temp_pointcache(Object *ob, ParticleSystem *psys)
+{
+ PointCache *cache = psys->pointcache;
+ PTCacheFile *pf = NULL;
+ PTCacheMem *pm = NULL;
+ PTCacheID pid;
+ int cfra, sfra = cache->startframe, efra = cache->endframe;
+ int totelem = psys->totpart;
+ int float_count = sizeof(ParticleKey) / sizeof(float);
+ int tot = totelem * float_count;
+
+ if((cache->flag & PTCACHE_DISK_CACHE)==0 || cache->mem_cache.first)
+ return;
+
+ BKE_ptcache_id_from_particles(&pid, ob, psys);
+
+ for(cfra=sfra; cfra <= efra; cfra++) {
+ pf = BKE_ptcache_file_open(&pid, PTCACHE_FILE_READ, cfra);
+
+ if(pf) {
+ pm = MEM_callocN(sizeof(PTCacheMem), "Pointcache temp mem");
+ pm->data = MEM_callocN(sizeof(float)*tot, "Pointcache temp mem data");
+
+ if(fread(pm->data, sizeof(float), tot, pf->fp)!= tot) {
+ printf("Error reading from disk cache\n");
+
+ MEM_freeN(pm->data);
+ MEM_freeN(pm);
+ BKE_ptcache_file_close(pf);
+ return;
+ }
+
+ pm->frame = cfra;
+ pm->totpoint = totelem;
+
+ BLI_addtail(&cache->mem_cache, pm);
+
+ BKE_ptcache_file_close(pf);
+ }
+ }
+}
+void psys_clear_temp_pointcache(ParticleSystem *psys)
+{
+ PTCacheMem *pm = psys->pointcache->mem_cache.first;
+
+ if((psys->pointcache->flag & PTCACHE_DISK_CACHE)==0)
+ return;
+
+ for(; pm; pm=pm->next) {
+ MEM_freeN(pm->data);
+ }
+
+ BLI_freelistN(&psys->pointcache->mem_cache);
+}
void psys_get_pointcache_start_end(Scene *scene, ParticleSystem *psys, int *sfra, int *efra)
{
ParticleSettings *part = psys->part;
@@ -2247,6 +2360,7 @@ static void particle_cache_interpolate(int index, void *psys_ptr, float frs_sec,
VecMulf(keys[2].vel, dfra / frs_sec);
psys_interpolate_particle(-1, keys, (cfra - cfra1) / dfra, &pa->state, 1);
+ QuatInterpol(pa->state.rot, keys[1].rot,keys[2].rot, (cfra - cfra1) / dfra);
VecMulf(pa->state.vel, frs_sec / dfra);
@@ -2290,6 +2404,30 @@ static int get_particles_from_cache(Scene *scene, Object *ob, ParticleSystem *ps
/************************************************/
/* Effectors */
/************************************************/
+static void update_particle_tree(ParticleSystem *psys)
+{
+ if(psys) {
+ ParticleData *pa = psys->particles;
+ int p, totpart = psys->totpart;
+
+ if(!psys->tree || psys->tree_frame != psys->cfra) {
+
+ BLI_kdtree_free(psys->tree);
+
+ psys->tree = BLI_kdtree_new(totpart);
+
+ for(p=0, pa=psys->particles; p<totpart; p++,pa++){
+ if(pa->flag & (PARS_NO_DISP+PARS_UNEXIST) || pa->alive != PARS_ALIVE)
+ continue;
+
+ BLI_kdtree_insert(psys->tree, p, pa->state.co, NULL);
+ }
+ BLI_kdtree_balance(psys->tree);
+
+ psys->tree_frame = psys->cfra;
+ }
+ }
+}
static void do_texture_effector(Tex *tex, short mode, short is_2d, float nabla, short object, float *pa_co, float obmat[4][4], float force_val, float falloff, float *field)
{
TexResult result[4];
@@ -2491,31 +2629,29 @@ void psys_end_effectors(ParticleSystem *psys)
/* NOTE:
ec->ob is not valid in here anymore! - dg
*/
- ListBase *lb=&psys->effectors;
- if(lb->first) {
- ParticleEffectorCache *ec;
- for(ec= lb->first; ec; ec= ec->next){
- if(ec->distances)
- MEM_freeN(ec->distances);
+ ParticleEffectorCache *ec = psys->effectors.first;
- if(ec->locations)
- MEM_freeN(ec->locations);
+ for(; ec; ec= ec->next){
+ if(ec->distances)
+ MEM_freeN(ec->distances);
- if(ec->face_minmax)
- MEM_freeN(ec->face_minmax);
+ if(ec->locations)
+ MEM_freeN(ec->locations);
- if(ec->vert_cos)
- MEM_freeN(ec->vert_cos);
+ if(ec->face_minmax)
+ MEM_freeN(ec->face_minmax);
- if(ec->tree)
- BLI_kdtree_free(ec->tree);
-
- if(ec->rng)
- rng_free(ec->rng);
- }
+ if(ec->vert_cos)
+ MEM_freeN(ec->vert_cos);
- BLI_freelistN(lb);
+ if(ec->tree)
+ BLI_kdtree_free(ec->tree);
+
+ if(ec->rng)
+ rng_free(ec->rng);
}
+
+ BLI_freelistN(&psys->effectors);
}
static void precalc_effectors(Scene *scene, Object *ob, ParticleSystem *psys, ParticleSystemModifierData *psmd, float cfra)
@@ -2598,7 +2734,84 @@ static void precalc_effectors(Scene *scene, Object *ob, ParticleSystem *psys, Pa
}
}
+int effector_find_co(Scene *scene, float *pco, SurfaceModifierData *sur, Object *ob, PartDeflect *pd, float *co, float *nor, float *vel, int *index)
+{
+ SurfaceModifierData *surmd = NULL;
+ int ret = 0;
+
+ if(sur)
+ surmd = sur;
+ else if(pd && pd->flag&PFIELD_SURFACE)
+ {
+ surmd = (SurfaceModifierData *)modifiers_findByType ( ob, eModifierType_Surface );
+ }
+
+ if(surmd) {
+ /* closest point in the object surface is an effector */
+ BVHTreeNearest nearest;
+
+ nearest.index = -1;
+ nearest.dist = FLT_MAX;
+
+ BLI_bvhtree_find_nearest(surmd->bvhtree->tree, pco, &nearest, surmd->bvhtree->nearest_callback, surmd->bvhtree);
+
+ if(nearest.index != -1) {
+ VECCOPY(co, nearest.co);
+
+ if(nor) {
+ VECCOPY(nor, nearest.no);
+ }
+
+ if(vel) {
+ MFace *mface = CDDM_get_face(surmd->dm, nearest.index);
+
+ VECCOPY(vel, surmd->v[mface->v1].co);
+ VecAddf(vel, vel, surmd->v[mface->v2].co);
+ VecAddf(vel, vel, surmd->v[mface->v3].co);
+ if(mface->v4)
+ VecAddf(vel, vel, surmd->v[mface->v4].co);
+
+ VecMulf(vel, mface->v4 ? 0.25f : 0.333f);
+ }
+
+ if(index)
+ *index = nearest.index;
+ ret = 1;
+ }
+ else {
+ co[0] = co[1] = co[2] = 0.0f;
+
+ if(nor)
+ nor[0] = nor[1] = nor[2] = 0.0f;
+
+ if(vel)
+ vel[0] = vel[1] = vel[2] = 0.0f;
+ }
+ }
+ else {
+ /* use center of object for distance calculus */
+ VECCOPY(co, ob->obmat[3]);
+
+ if(nor) {
+ VECCOPY(nor, ob->obmat[2]);
+ }
+
+ if(vel) {
+ Object obcopy = *ob;
+
+ VECCOPY(vel, ob->obmat[3]);
+
+ where_is_object_time(scene, ob, scene->r.cfra - 1.0);
+
+ VecSubf(vel, vel, ob->obmat[3]);
+
+ *ob = obcopy;
+ }
+ }
+
+ return ret;
+}
/* calculate forces that all effectors apply to a particle*/
void do_effectors(int pa_no, ParticleData *pa, ParticleKey *state, Scene *scene, Object *ob, ParticleSystem *psys, float *rootco, float *force_field, float *vel,float framestep, float cfra)
{
@@ -2608,12 +2821,11 @@ void do_effectors(int pa_no, ParticleData *pa, ParticleKey *state, Scene *scene,
ParticleData *epa;
ParticleKey estate;
PartDeflect *pd;
- SurfaceModifierData *surmd = NULL;
ListBase *lb=&psys->effectors;
ParticleEffectorCache *ec;
- float distance, vec_to_part[3];
- float falloff, charge = 0.0f;
- int p;
+ float distance, vec_to_part[3], pco[3], co[3];
+ float falloff, charge = 0.0f, strength;
+ int p, face_index=-1;
/* check all effector objects for interaction */
if(lb->first){
@@ -2637,45 +2849,33 @@ void do_effectors(int pa_no, ParticleData *pa, ParticleKey *state, Scene *scene,
where_is_object_time(scene, eob,cfra);
if(pd && pd->flag&PFIELD_SURFACE) {
- surmd = (SurfaceModifierData *)modifiers_findByType ( eob, eModifierType_Surface );
- }
- if(surmd) {
- /* closest point in the object surface is an effector */
- BVHTreeNearest nearest;
float velocity[3];
-
- nearest.index = -1;
- nearest.dist = FLT_MAX;
-
/* using velocity corrected location allows for easier sliding over effector surface */
VecCopyf(velocity, state->vel);
VecMulf(velocity, psys_get_timestep(psys->part));
- VecAddf(vec_to_part, state->co, velocity);
-
- BLI_bvhtree_find_nearest(surmd->bvhtree->tree, vec_to_part, &nearest, surmd->bvhtree->nearest_callback, surmd->bvhtree);
-
- if(nearest.index != -1) {
- VecSubf(vec_to_part, state->co, nearest.co);
- }
- else
- vec_to_part[0] = vec_to_part[1] = vec_to_part[2] = 0.0f;
+ VecAddf(pco, state->co, velocity);
}
else
- /* use center of object for distance calculus */
- VecSubf(vec_to_part, state->co, eob->obmat[3]);
+ VECCOPY(pco, state->co);
+
+ effector_find_co(scene, pco, NULL, eob, pd, co, NULL, NULL, &face_index);
+
+ VecSubf(vec_to_part, state->co, co);
distance = VecLength(vec_to_part);
falloff=effector_falloff(pd,eob->obmat[2],vec_to_part);
+ strength = pd->f_strength * psys->part->effector_weight[0] * psys->part->effector_weight[pd->forcefield];
+
if(falloff<=0.0f)
; /* don't do anything */
else if(pd->forcefield==PFIELD_TEXTURE) {
do_texture_effector(pd->tex, pd->tex_mode, pd->flag&PFIELD_TEX_2D, pd->tex_nabla,
pd->flag & PFIELD_TEX_OBJECT, (pd->flag & PFIELD_TEX_ROOTCO) ? rootco : state->co, eob->obmat,
- pd->f_strength, falloff, force_field);
+ strength, falloff, force_field);
} else {
- do_physical_effector(scene, eob, state->co, pd->forcefield,pd->f_strength,distance,
+ do_physical_effector(scene, eob, state->co, pd->forcefield,strength,distance,
falloff,0.0,pd->f_damp,eob->obmat[2],vec_to_part,
state->vel,force_field,pd->flag&PFIELD_PLANAR,ec->rng,pd->f_noise,charge,pa->size);
}
@@ -2716,10 +2916,12 @@ void do_effectors(int pa_no, ParticleData *pa, ParticleKey *state, Scene *scene,
falloff=effector_falloff(pd,estate.vel,vec_to_part);
+ strength = pd->f_strength * psys->part->effector_weight[0] * psys->part->effector_weight[pd->forcefield];
+
if(falloff<=0.0f)
; /* don't do anything */
else
- do_physical_effector(scene, eob, state->co, pd->forcefield,pd->f_strength,distance,
+ do_physical_effector(scene, eob, state->co, pd->forcefield,strength,distance,
falloff,epart->size,pd->f_damp,estate.vel,vec_to_part,
state->vel,force_field,0, ec->rng, pd->f_noise,charge,pa->size);
}
@@ -3071,20 +3273,7 @@ int psys_intersect_dm(Scene *scene, Object *ob, DerivedMesh *dm, float *vert_cos
return intersect;
}
-/* container for moving data between deflet_particle and particle_intersect_face */
-typedef struct ParticleCollision
-{
- struct Object *ob, *ob_t; // collided and current objects
- struct CollisionModifierData *md; // collision modifier for ob_t;
- float nor[3]; // normal at collision point
- float vel[3]; // velocity of collision point
- float co1[3], co2[3]; // ray start and end points
- float ray_len; // original length of co2-co1, needed for collision time evaluation
- float t; // time of previous collision, needed for substracting face velocity
-}
-ParticleCollision;
-
-static void particle_intersect_face(void *userdata, int index, const BVHTreeRay *ray, BVHTreeRayHit *hit)
+void particle_intersect_face(void *userdata, int index, const BVHTreeRay *ray, BVHTreeRayHit *hit)
{
ParticleCollision *col = (ParticleCollision *) userdata;
MFace *face = col->md->mfaces + index;
@@ -3159,20 +3348,27 @@ static void particle_intersect_face(void *userdata, int index, const BVHTreeRay
/* 1. check for all possible deflectors for closest intersection on particle path */
/* 2. if deflection was found kill the particle or calculate new coordinates */
static void deflect_particle(Scene *scene, Object *pob, ParticleSystemModifierData *psmd, ParticleSystem *psys, ParticleSettings *part, ParticleData *pa, int p, float timestep, float dfra, float cfra){
- Object *ob = NULL;
+ Object *ob = NULL, *skip_ob = NULL;
ListBase *lb=&psys->effectors;
ParticleEffectorCache *ec;
ParticleKey reaction_state;
ParticleCollision col;
BVHTreeRayHit hit;
float ray_dir[3], zerovec[3]={0.0,0.0,0.0};
- float radius = ((part->flag & PART_SIZE_DEFL)?pa->size:0.0f);
+ float radius = ((part->flag & PART_SIZE_DEFL)?pa->size:0.0f), boid_z;
int deflections=0, max_deflections=10;
VECCOPY(col.co1, pa->prev_state.co);
VECCOPY(col.co2, pa->state.co);
col.t = 0.0f;
+ /* override for boids */
+ if(part->phystype == PART_PHYS_BOIDS) {
+ radius = pa->size;
+ boid_z = pa->state.co[2];
+ skip_ob = pa->stick_ob;
+ }
+
/* 10 iterations to catch multiple deflections */
if(lb->first) while(deflections < max_deflections){
/* 1. */
@@ -3190,13 +3386,17 @@ static void deflect_particle(Scene *scene, Object *pob, ParticleSystemModifierDa
if(ec->type & PSYS_EC_DEFLECT){
ob= ec->ob;
- if(part->type!=PART_HAIR)
- where_is_object_time(scene, ob,cfra);
+ /* for boids: don't check with current ground object */
+ if(ob==skip_ob)
+ continue;
/* particles should not collide with emitter at birth */
if(ob==pob && pa->time < cfra && pa->time >= psys->cfra)
continue;
+ if(part->type!=PART_HAIR)
+ where_is_object_time(scene,ob,cfra);
+
col.md = ( CollisionModifierData * ) ( modifiers_findByType ( ec->ob, eModifierType_Collision ) );
col.ob_t = ob;
@@ -3328,6 +3528,13 @@ static void deflect_particle(Scene *scene, Object *pob, ParticleSystemModifierDa
/* make sure we don't hit the current face again */
VECADDFAC(co, co, col.nor, (through ? -0.0001f : 0.0001f));
+ if(part->phystype == PART_PHYS_BOIDS && part->boids->options & BOID_ALLOW_LAND) {
+ if(pa->boid->mode == eBoidMode_OnLand || co[2] <= boid_z) {
+ co[2] = boid_z;
+ vel[2] = 0.0f;
+ }
+ }
+
/* store state for reactors */
VECCOPY(reaction_state.co, co);
VecLerpf(reaction_state.vel, pa->prev_state.vel, pa->state.vel, dt);
@@ -3361,619 +3568,6 @@ static void deflect_particle(Scene *scene, Object *pob, ParticleSystemModifierDa
}
}
/************************************************/
-/* Boid physics */
-/************************************************/
-static int boid_see_mesh(ListBase *lb, Scene *scene, Object *pob, ParticleSystem *psys, float *vec1, float *vec2, float *loc, float *nor, float cfra)
-{
- Object *ob, *min_ob;
- DerivedMesh *dm;
- MFace *mface;
- MVert *mvert;
- ParticleEffectorCache *ec;
- ParticleSystemModifierData *psmd=psys_get_modifier(pob,psys);
- float imat[4][4];
- float co1[3], co2[3], min_w[4], min_d;
- int min_face=0, intersect=0;
-
- if(lb->first){
- intersect=0;
- min_d=20000.0;
- min_ob=NULL;
- for(ec=lb->first; ec; ec=ec->next){
- if(ec->type & PSYS_EC_DEFLECT){
- ob= ec->ob;
-
- if(psys->part->type!=PART_HAIR)
- where_is_object_time(scene, ob,cfra);
-
- if(ob==pob)
- dm=psmd->dm;
- else
- dm=0;
-
- VECCOPY(co1,vec1);
- VECCOPY(co2,vec2);
-
- if(ec->vert_cos==0){
- /* convert particle coordinates to object coordinates */
- Mat4Invert(imat,ob->obmat);
-
- Mat4MulVecfl(imat,co1);
- Mat4MulVecfl(imat,co2);
- }
-
- if(psys_intersect_dm(scene,ob,dm,ec->vert_cos,co1,co2,&min_d,&min_face,min_w,ec->face_minmax,0,0,0))
- min_ob=ob;
- }
- }
- if(min_ob){
- ob=min_ob;
-
- if(ob==pob){
- dm=psmd->dm;
- }
- else{
- psys_disable_all(ob);
-
- dm=mesh_get_derived_final(scene, ob, 0);
- if(dm==0)
- dm=mesh_get_derived_deform(scene, ob, 0);
-
- psys_enable_all(ob);
- }
-
- mface=dm->getFaceDataArray(dm,CD_MFACE);
- mface+=min_face;
- mvert=dm->getVertDataArray(dm,CD_MVERT);
-
- /* get deflection point & normal */
- psys_interpolate_face(mvert,mface,0,0,min_w,loc,nor,0,0,0,0);
-
- VECADD(nor,nor,loc);
- Mat4MulVecfl(ob->obmat,loc);
- Mat4MulVecfl(ob->obmat,nor);
- VECSUB(nor,nor,loc);
- return 1;
- }
- }
- return 0;
-}
-/* vector calculus functions in 2d vs. 3d */
-static void set_boid_vec_func(BoidVecFunc *bvf, int is_2d)
-{
- if(is_2d){
- bvf->Addf = Vec2Addf;
- bvf->Subf = Vec2Subf;
- bvf->Mulf = Vec2Mulf;
- bvf->Length = Vec2Length;
- bvf->Normalize = Normalize2;
- bvf->Inpf = Inp2f;
- bvf->Copyf = Vec2Copyf;
- }
- else{
- bvf->Addf = VecAddf;
- bvf->Subf = VecSubf;
- bvf->Mulf = VecMulf;
- bvf->Length = VecLength;
- bvf->Normalize = Normalize;
- bvf->Inpf = Inpf;
- bvf->Copyf = VecCopyf;
- }
-}
-/* boids have limited processing capability so once there's too much information (acceleration) no more is processed */
-static int add_boid_acc(BoidVecFunc *bvf, float lat_max, float tan_max, float *lat_accu, float *tan_accu, float *acc, float *dvec, float *vel)
-{
- static float tangent[3];
- static float tan_length;
-
- if(vel){
- bvf->Copyf(tangent,vel);
- tan_length=bvf->Normalize(tangent);
- return 1;
- }
- else{
- float cur_tan, cur_lat;
- float tan_acc[3], lat_acc[3];
- int ret=0;
-
- bvf->Copyf(tan_acc,tangent);
-
- if(tan_length>0.0){
- bvf->Mulf(tan_acc,Inpf(tangent,dvec));
-
- bvf->Subf(lat_acc,dvec,tan_acc);
- }
- else{
- bvf->Copyf(tan_acc,dvec);
- lat_acc[0]=lat_acc[1]=lat_acc[2]=0.0f;
- *lat_accu=lat_max;
- }
-
- cur_tan=bvf->Length(tan_acc);
- cur_lat=bvf->Length(lat_acc);
-
- /* add tangential acceleration */
- if(*lat_accu+cur_lat<=lat_max){
- bvf->Addf(acc,acc,lat_acc);
- *lat_accu+=cur_lat;
- ret=1;
- }
- else{
- bvf->Mulf(lat_acc,(lat_max-*lat_accu)/cur_lat);
- bvf->Addf(acc,acc,lat_acc);
- *lat_accu=lat_max;
- }
-
- /* add lateral acceleration */
- if(*tan_accu+cur_tan<=tan_max){
- bvf->Addf(acc,acc,tan_acc);
- *tan_accu+=cur_tan;
- ret=1;
- }
- else{
- bvf->Mulf(tan_acc,(tan_max-*tan_accu)/cur_tan);
- bvf->Addf(acc,acc,tan_acc);
- *tan_accu=tan_max;
- }
-
- return ret;
- }
-}
-/* determines the acceleration that the boid tries to acchieve */
-static void boid_brain(BoidVecFunc *bvf, ParticleData *pa, Scene *scene, Object *ob, ParticleSystem *psys, ParticleSettings *part, KDTree *tree, float timestep, float cfra, float *acc)
-{
- ParticleData *pars=psys->particles;
- KDTreeNearest ptn[MAX_BOIDNEIGHBOURS+1];
- ParticleEffectorCache *ec=0;
- float dvec[3]={0.0,0.0,0.0}, ob_co[3], ob_nor[3];
- float avoid[3]={0.0,0.0,0.0}, velocity[3]={0.0,0.0,0.0}, center[3]={0.0,0.0,0.0};
- float cubedist[MAX_BOIDNEIGHBOURS+1];
- int i, n, neighbours=0, near, not_finished=1;
-
- float cur_vel;
- float lat_accu=0.0f, max_lat_acc=part->max_vel*part->max_lat_acc;
- float tan_accu=0.0f, max_tan_acc=part->max_vel*part->max_tan_acc;
- float avg_vel=part->average_vel*part->max_vel;
-
- acc[0]=acc[1]=acc[2]=0.0f;
- /* the +1 neighbour is because boid itself is in the tree */
- neighbours=BLI_kdtree_find_n_nearest(tree,part->boidneighbours+1,pa->state.co,NULL,ptn);
-
- for(n=1; n<neighbours; n++){
- cubedist[n]=(float)pow((double)(ptn[n].dist/pa->size),3.0);
- cubedist[n]=1.0f/MAX2(cubedist[n],1.0f);
- }
-
- /* initialize tangent */
- add_boid_acc(bvf,0.0,0.0,0,0,0,0,pa->state.vel);
-
- for(i=0; i<BOID_TOT_RULES && not_finished; i++){
- switch(part->boidrule[i]){
- case BOID_COLLIDE:
- /* collision avoidance */
- bvf->Copyf(dvec,pa->prev_state.vel);
- bvf->Mulf(dvec,5.0f);
- bvf->Addf(dvec,dvec,pa->prev_state.co);
- if(boid_see_mesh(&psys->effectors,scene, ob,psys,pa->prev_state.co,dvec,ob_co,ob_nor,cfra)){
- float probelen = bvf->Length(dvec);
- float proj;
- float oblen;
-
- Normalize(ob_nor);
- proj = bvf->Inpf(ob_nor,pa->prev_state.vel);
-
- bvf->Subf(dvec,pa->prev_state.co,ob_co);
- oblen=bvf->Length(dvec);
-
- bvf->Copyf(dvec,ob_nor);
- bvf->Mulf(dvec,-proj);
- bvf->Mulf(dvec,((probelen/oblen)-1.0f)*100.0f*part->boidfac[BOID_COLLIDE]);
-
- not_finished=add_boid_acc(bvf,max_lat_acc,max_tan_acc,&lat_accu,&tan_accu,acc,dvec,0);
- }
- break;
- case BOID_AVOID:
- /* predator avoidance */
- if(psys->effectors.first){
- for(ec=psys->effectors.first; ec; ec=ec->next){
- if(ec->type & PSYS_EC_EFFECTOR){
- Object *eob = ec->ob;
- PartDeflect *pd = eob->pd;
-
- if(pd->forcefield==PFIELD_FORCE && pd->f_strength<0.0){
- float distance;
- VECSUB(dvec,eob->obmat[3],pa->prev_state.co);
-
- distance=Normalize(dvec);
-
- if(part->flag & PART_DIE_ON_COL && distance < pd->mindist){
- pa->alive = PARS_DYING;
- pa->dietime=cfra;
- i=BOID_TOT_RULES;
- break;
- }
-
- if(pd->flag&PFIELD_USEMAX && distance > pd->maxdist)
- ;
- else{
- bvf->Mulf(dvec,part->boidfac[BOID_AVOID]*pd->f_strength/(float)pow((double)distance,(double)pd->f_power));
-
- not_finished=add_boid_acc(bvf,max_lat_acc,max_tan_acc,&lat_accu,&tan_accu,acc,dvec,0);
- }
- }
- }
- else if(ec->type & PSYS_EC_PARTICLE){
- Object *eob = ec->ob;
- ParticleSystem *epsys;
- ParticleSettings *epart;
- ParticleKey state;
- PartDeflect *pd;
- KDTreeNearest ptn2[MAX_BOIDNEIGHBOURS];
- int totepart, p, count;
- float distance;
- epsys= BLI_findlink(&eob->particlesystem,ec->psys_nbr);
- epart= epsys->part;
- pd= epart->pd;
- totepart= epsys->totpart;
-
- if(pd->forcefield==PFIELD_FORCE && pd->f_strength<0.0 && ec->tree){
- count=BLI_kdtree_find_n_nearest(ec->tree,epart->boidneighbours,pa->prev_state.co,NULL,ptn2);
- for(p=0; p<count; p++){
- state.time=-1.0;
- if(psys_get_particle_state(scene, eob,epsys,ptn2[p].index,&state,0)){
- VECSUB(dvec, state.co, pa->prev_state.co);
-
- distance = Normalize(dvec);
-
- if(part->flag & PART_DIE_ON_COL && distance < (epsys->particles+ptn2[p].index)->size){
- pa->alive = PARS_DYING;
- pa->dietime=cfra;
- i=BOID_TOT_RULES;
- break;
- }
-
- if(pd->flag&PFIELD_USEMAX && distance > pd->maxdist)
- ;
- else{
- bvf->Mulf(dvec,part->boidfac[BOID_AVOID]*pd->f_strength/(float)pow((double)distance,(double)pd->f_power));
-
- not_finished=add_boid_acc(bvf,max_lat_acc,max_tan_acc,&lat_accu,&tan_accu,acc,dvec,0);
- }
- }
- }
- }
- }
- }
- }
- break;
- case BOID_CROWD:
- /* crowd avoidance */
- near=0;
- for(n=1; n<neighbours; n++){
- if(ptn[n].dist<2.0f*pa->size){
- if(ptn[n].dist!=0.0f) {
- bvf->Subf(dvec,pa->prev_state.co,pars[ptn[n].index].state.co);
- bvf->Mulf(dvec,(2.0f*pa->size-ptn[n].dist)/ptn[n].dist);
- bvf->Addf(avoid,avoid,dvec);
- near++;
- }
- }
- /* ptn[] is distance ordered so no need to check others */
- else break;
- }
- if(near){
- bvf->Mulf(avoid,part->boidfac[BOID_CROWD]*2.0f/timestep);
-
- not_finished=add_boid_acc(bvf,max_lat_acc,max_tan_acc,&lat_accu,&tan_accu,acc,avoid,0);
- }
- break;
- case BOID_CENTER:
- /* flock centering */
- if(neighbours>1){
- for(n=1; n<neighbours; n++){
- bvf->Addf(center,center,pars[ptn[n].index].state.co);
- }
- bvf->Mulf(center,1.0f/((float)neighbours-1.0f));
-
- bvf->Subf(dvec,center,pa->prev_state.co);
-
- bvf->Mulf(dvec,part->boidfac[BOID_CENTER]*2.0f);
-
- not_finished=add_boid_acc(bvf,max_lat_acc,max_tan_acc,&lat_accu,&tan_accu,acc,dvec,0);
- }
- break;
- case BOID_AV_VEL:
- /* average velocity */
- cur_vel=bvf->Length(pa->prev_state.vel);
- if(cur_vel>0.0){
- bvf->Copyf(dvec,pa->prev_state.vel);
- bvf->Mulf(dvec,part->boidfac[BOID_AV_VEL]*(avg_vel-cur_vel)/cur_vel);
- not_finished=add_boid_acc(bvf,max_lat_acc,max_tan_acc,&lat_accu,&tan_accu,acc,dvec,0);
- }
- break;
- case BOID_VEL_MATCH:
- /* velocity matching */
- if(neighbours>1){
- for(n=1; n<neighbours; n++){
- bvf->Copyf(dvec,pars[ptn[n].index].state.vel);
- bvf->Mulf(dvec,cubedist[n]);
- bvf->Addf(velocity,velocity,dvec);
- }
- bvf->Mulf(velocity,1.0f/((float)neighbours-1.0f));
-
- bvf->Subf(dvec,velocity,pa->prev_state.vel);
-
- bvf->Mulf(dvec,part->boidfac[BOID_VEL_MATCH]);
-
- not_finished=add_boid_acc(bvf,max_lat_acc,max_tan_acc,&lat_accu,&tan_accu,acc,dvec,0);
- }
- break;
- case BOID_GOAL:
- /* goal seeking */
- if(psys->effectors.first){
- for(ec=psys->effectors.first; ec; ec=ec->next){
- if(ec->type & PSYS_EC_EFFECTOR){
- Object *eob = ec->ob;
- PartDeflect *pd = eob->pd;
- float temp[4];
-
- if(pd->forcefield==PFIELD_FORCE && pd->f_strength>0.0){
- float distance;
- VECSUB(dvec,eob->obmat[3],pa->prev_state.co);
-
- distance=Normalize(dvec);
-
- if(pd->flag&PFIELD_USEMAX && distance > pd->maxdist)
- ;
- else{
- VecMulf(dvec,pd->f_strength*part->boidfac[BOID_GOAL]/(float)pow((double)distance,(double)pd->f_power));
-
- not_finished=add_boid_acc(bvf,max_lat_acc,max_tan_acc,&lat_accu,&tan_accu,acc,dvec,0);
- }
- }
- else if(pd->forcefield==PFIELD_GUIDE){
- float distance;
-
- where_on_path(eob, (cfra-pa->time)/pa->lifetime, temp, dvec);
-
- VECSUB(dvec,temp,pa->prev_state.co);
-
- distance=Normalize(dvec);
-
- if(pd->flag&PFIELD_USEMAX && distance > pd->maxdist)
- ;
- else{
- VecMulf(dvec,pd->f_strength*part->boidfac[BOID_GOAL]/(float)pow((double)distance,(double)pd->f_power));
-
- not_finished=add_boid_acc(bvf,max_lat_acc,max_tan_acc,&lat_accu,&tan_accu,acc,dvec,0);
- }
- }
- }
- else if(ec->type & PSYS_EC_PARTICLE){
- Object *eob = ec->ob;
- ParticleSystem *epsys;
- ParticleSettings *epart;
- ParticleKey state;
- PartDeflect *pd;
- KDTreeNearest ptn2[MAX_BOIDNEIGHBOURS];
- int totepart, p, count;
- float distance;
- epsys= BLI_findlink(&eob->particlesystem,ec->psys_nbr);
- epart= epsys->part;
- pd= epart->pd;
- totepart= epsys->totpart;
-
- if(pd->forcefield==PFIELD_FORCE && pd->f_strength>0.0 && ec->tree){
- count=BLI_kdtree_find_n_nearest(ec->tree,epart->boidneighbours,pa->prev_state.co,NULL,ptn2);
- for(p=0; p<count; p++){
- state.time=-1.0;
- if(psys_get_particle_state(scene, eob,epsys,ptn2[p].index,&state,0)){
- VECSUB(dvec, state.co, pa->prev_state.co);
-
- distance = Normalize(dvec);
-
- if(pd->flag&PFIELD_USEMAX && distance > pd->maxdist)
- ;
- else{
- bvf->Mulf(dvec,part->boidfac[BOID_AVOID]*pd->f_strength/(float)pow((double)distance,(double)pd->f_power));
-
- not_finished=add_boid_acc(bvf,max_lat_acc,max_tan_acc,&lat_accu,&tan_accu,acc,dvec,0);
- }
- }
- }
- }
- }
- }
- }
- break;
- case BOID_LEVEL:
- /* level flight */
- if((part->flag & PART_BOIDS_2D)==0){
- dvec[0]=dvec[1]=0.0;
- dvec[2]=-pa->prev_state.vel[2];
-
- VecMulf(dvec,part->boidfac[BOID_LEVEL]);
- not_finished=add_boid_acc(bvf,max_lat_acc,max_tan_acc,&lat_accu,&tan_accu,acc,dvec,0);
- }
- break;
- }
- }
-}
-/* tries to realize the wanted acceleration */
-static void boid_body(Scene *scene, BoidVecFunc *bvf, ParticleData *pa, ParticleSystem *psys, ParticleSettings *part, float timestep, float *acc)
-{
- float dvec[3], bvec[3], length, max_vel=part->max_vel;
- float q2[4], q[4];
- float g=9.81f, pa_mass=part->mass;
- float yvec[3]={0.0,1.0,0.0}, zvec[3]={0.0,0.0,-1.0}, bank;
-
- /* apply new velocity, location & rotation */
- copy_particle_key(&pa->state,&pa->prev_state,0);
-
- if(part->flag & PART_SIZEMASS)
- pa_mass*=pa->size;
-
- /* by regarding the acceleration as a force at this stage we*/
- /* can get better controll allthough it's a bit unphysical */
- bvf->Mulf(acc,1.0f/pa_mass);
-
- bvf->Copyf(dvec,acc);
- bvf->Mulf(dvec,timestep*timestep*0.5f);
-
- bvf->Copyf(bvec,pa->state.vel);
- bvf->Mulf(bvec,timestep);
- bvf->Addf(dvec,dvec,bvec);
- bvf->Addf(pa->state.co,pa->state.co,dvec);
-
- /* air speed from wind and vortex effectors */
- if(psys->effectors.first) {
- ParticleEffectorCache *ec;
- for(ec=psys->effectors.first; ec; ec=ec->next) {
- if(ec->type & PSYS_EC_EFFECTOR) {
- Object *eob = ec->ob;
- PartDeflect *pd = eob->pd;
- float direction[3], vec_to_part[3];
- float falloff;
-
- if(pd->f_strength != 0.0f) {
- VecCopyf(direction, eob->obmat[2]);
- VecSubf(vec_to_part, pa->state.co, eob->obmat[3]);
-
- falloff=effector_falloff(pd, direction, vec_to_part);
-
- switch(pd->forcefield) {
- case PFIELD_WIND:
- if(falloff <= 0.0f)
- ; /* don't do anything */
- else {
- Normalize(direction);
- VecMulf(direction, pd->f_strength * falloff);
- bvf->Addf(pa->state.co, pa->state.co, direction);
- }
- break;
- case PFIELD_VORTEX:
- {
- float distance, mag_vec[3];
- Crossf(mag_vec, direction, vec_to_part);
- Normalize(mag_vec);
-
- distance = VecLength(vec_to_part);
-
- VecMulf(mag_vec, pd->f_strength * distance * falloff);
- bvf->Addf(pa->state.co, pa->state.co, mag_vec);
- break;
- }
- }
- }
- }
- }
- }
-
-
- if((part->flag & PART_BOIDS_2D)==0 && pa->prev_state.vel[0]!=0.0 && pa->prev_state.vel[0]!=0.0 && pa->prev_state.vel[0]!=0.0){
- Crossf(yvec,pa->state.vel,zvec);
-
- Normalize(yvec);
-
- bank=Inpf(yvec,acc);
-
- bank=-(float)atan((double)(bank/g));
-
- bank*=part->banking;
-
- bank-=pa->bank;
- if(bank>M_PI*part->max_bank){
- bank=pa->bank+(float)M_PI*part->max_bank;
- }
- else if(bank<-M_PI*part->max_bank){
- bank=pa->bank-(float)M_PI*part->max_bank;
- }
- else
- bank+=pa->bank;
-
- pa->bank=bank;
- }
- else{
- bank=0.0;
- }
-
-
- VecRotToQuat(pa->state.vel,bank,q);
-
- VECCOPY(dvec,pa->state.vel);
- VecNegf(dvec);
- vectoquat(dvec, OB_POSX, OB_POSZ, q2);
-
- QuatMul(pa->state.rot,q,q2);
-
- bvf->Mulf(acc,timestep);
- bvf->Addf(pa->state.vel,pa->state.vel,acc);
-
- if(part->flag & PART_BOIDS_2D){
- pa->state.vel[2]=0.0;
- pa->state.co[2]=part->groundz;
-
- if(psys->keyed_ob && (psys->keyed_ob->type == OB_MESH)){
- Object *zob=psys->keyed_ob;
- int min_face;
- float co1[3],co2[3],min_d=2.0,min_w[4],imat[4][4];
- VECCOPY(co1,pa->state.co);
- VECCOPY(co2,pa->state.co);
-
- co1[2]=1000.0f;
- co2[2]=-1000.0f;
-
- Mat4Invert(imat,zob->obmat);
- Mat4MulVecfl(imat,co1);
- Mat4MulVecfl(imat,co2);
-
- if(psys_intersect_dm(scene,zob,0,0,co1,co2,&min_d,&min_face,min_w,0,0,0,0)){
- DerivedMesh *dm;
- MFace *mface;
- MVert *mvert;
- float loc[3],nor[3],q1[4];
-
- psys_disable_all(zob);
- dm=mesh_get_derived_final(scene, zob, 0);
- psys_enable_all(zob);
-
- mface=dm->getFaceDataArray(dm,CD_MFACE);
- mface+=min_face;
- mvert=dm->getVertDataArray(dm,CD_MVERT);
-
- /* get deflection point & normal */
- psys_interpolate_face(mvert,mface,0,0,min_w,loc,nor,0,0,0,0);
-
- Mat4MulVecfl(zob->obmat,loc);
- Mat4Mul3Vecfl(zob->obmat,nor);
-
- Normalize(nor);
-
- VECCOPY(pa->state.co,loc);
-
- zvec[2]=1.0;
-
- Crossf(loc,zvec,nor);
-
- bank=VecLength(loc);
- if(bank>0.0){
- bank=saasin(bank);
-
- VecRotToQuat(loc,bank,q);
-
- QUATCOPY(q1,pa->state.rot);
-
- QuatMul(pa->state.rot,q,q1);
- }
- }
- }
- }
-
- length=bvf->Length(pa->state.vel);
- if(length > max_vel)
- bvf->Mulf(pa->state.vel,max_vel/length);
-}
-/************************************************/
/* Hair */
/************************************************/
static void save_hair(Scene *scene, Object *ob, ParticleSystem *psys, ParticleSystemModifierData *psmd, float cfra){
@@ -4030,9 +3624,9 @@ static void dynamics_step(Scene *scene, Object *ob, ParticleSystem *psys, Partic
ParticleData *pa;
ParticleSettings *part=psys->part;
KDTree *tree=0;
- BoidVecFunc bvf;
IpoCurve *icu_esize= NULL; //=find_ipocurve(part->ipo,PART_EMIT_SIZE); // XXX old animation system
Material *ma=give_current_material(ob,part->omat);
+ BoidBrainData bbd;
float timestep;
int p, totpart;
/* current time */
@@ -4112,16 +3706,23 @@ static void dynamics_step(Scene *scene, Object *ob, ParticleSystem *psys, Partic
precalc_effectors(scene, ob,psys,psmd,cfra);
if(part->phystype==PART_PHYS_BOIDS){
- /* create particle tree for fast inter-particle comparisons */
- tree=BLI_kdtree_new(totpart);
- for(p=0, pa=psys->particles; p<totpart; p++,pa++){
- if(pa->flag & (PARS_NO_DISP+PARS_UNEXIST) || pa->alive!=PARS_ALIVE)
- continue;
-
- BLI_kdtree_insert(tree, p, pa->state.co, NULL);
+ ParticleTarget *pt = psys->targets.first;
+ bbd.scene = scene;
+ bbd.ob = ob;
+ bbd.psys = psys;
+ bbd.part = part;
+ bbd.cfra = cfra;
+ bbd.dfra = dfra;
+ bbd.timestep = timestep;
+
+ update_particle_tree(psys);
+
+ boids_precalc_rules(part, cfra);
+
+ for(; pt; pt=pt->next) {
+ if(pt->ob)
+ update_particle_tree(BLI_findlink(&pt->ob->particlesystem, pt->psys-1));
}
- BLI_kdtree_balance(tree);
- set_boid_vec_func(&bvf,part->flag&PART_BOIDS_2D);
}
/* main loop: calculate physics for all particles */
@@ -4190,10 +3791,14 @@ static void dynamics_step(Scene *scene, Object *ob, ParticleSystem *psys, Partic
break;
case PART_PHYS_BOIDS:
{
- float acc[3];
- boid_brain(&bvf, pa, scene, ob, psys, part, tree, timestep,cfra,acc);
- if(pa->alive != PARS_DYING)
- boid_body(scene, &bvf,pa,psys,part,timestep,acc);
+ bbd.goal_ob = NULL;
+ boid_brain(&bbd, p, pa);
+ if(pa->alive != PARS_DYING) {
+ boid_body(&bbd, pa);
+
+ /* deflection */
+ deflect_particle(scene,ob,psmd,psys,part,pa,p,timestep,pa_dfra,cfra);
+ }
break;
}
}
@@ -4238,7 +3843,7 @@ static void psys_update_path_cache(Scene *scene, Object *ob, ParticleSystemModif
if((psys->part->childtype && psys->totchild != get_psys_tot_child(scene, psys)) || psys->recalc&PSYS_RECALC_RESET)
alloc=1;
- if(alloc || psys->recalc&PSYS_RECALC_RESET || (psys->vgroup[PSYS_VG_DENSITY] && (G.f & G_WEIGHTPAINT)))
+ if(alloc || psys->recalc&PSYS_RECALC_CHILD || (psys->vgroup[PSYS_VG_DENSITY] && (G.f & G_WEIGHTPAINT)))
distr=1;
if(distr){
@@ -4373,9 +3978,10 @@ static void cached_step(Scene *scene, Object *ob, ParticleSystemModifierData *ps
dietime = birthtime + (1 + pa->loop) * (pa->dietime - pa->time);
/* update alive status and push events */
- if(pa->time > cfra) {
- pa->alive = PARS_UNBORN;
- reset_particle(scene, pa, psys, psmd, ob, 0.0f, cfra, NULL, NULL, NULL);
+ if(pa->time >= cfra) {
+ pa->alive = pa->time==cfra ? PARS_ALIVE : PARS_UNBORN;
+ if((psys->pointcache->flag & PTCACHE_EXTERNAL) == 0)
+ reset_particle(scene, pa, psys, psmd, ob, 0.0f, cfra, NULL, NULL, NULL);
}
else if(dietime <= cfra){
if(dietime > psys->cfra){
@@ -4416,12 +4022,15 @@ static void cached_step(Scene *scene, Object *ob, ParticleSystemModifierData *ps
MEM_freeN(vg_size);
}
-void psys_changed_type(ParticleSystem *psys)
+static void psys_changed_type(Object *ob, ParticleSystem *psys)
{
ParticleSettings *part;
+ PTCacheID pid;
part= psys->part;
+ BKE_ptcache_id_from_particles(&pid, ob, psys);
+
/* system type has changed so set sensible defaults and clear non applicable flags */
if(part->from == PART_FROM_PARTICLE) {
if(part->type != PART_REACTOR)
@@ -4430,7 +4039,7 @@ void psys_changed_type(ParticleSystem *psys)
part->distr = PART_DISTR_JIT;
}
- if(psys->part->phystype != PART_PHYS_KEYED)
+ if(part->phystype != PART_PHYS_KEYED)
psys->flag &= ~PSYS_KEYED;
if(part->type == PART_HAIR) {
@@ -4442,6 +4051,8 @@ void psys_changed_type(ParticleSystem *psys)
CLAMP(part->path_start, 0.0f, 100.0f);
CLAMP(part->path_end, 0.0f, 100.0f);
+
+ BKE_ptcache_id_clear(&pid, PTCACHE_CLEAR_ALL, 0);
}
else {
free_hair(psys, 1);
@@ -4454,7 +4065,60 @@ void psys_changed_type(ParticleSystem *psys)
psys_reset(psys, PSYS_RESET_ALL);
}
+void psys_check_boid_data(ParticleSystem *psys)
+{
+ ParticleData *pa = psys->particles;
+ int p = 1;
+
+ if(!pa)
+ return;
+
+ if(psys->part && psys->part->phystype==PART_PHYS_BOIDS) {
+ if(!pa->boid) {
+ pa->boid = MEM_callocN(psys->totpart * sizeof(BoidData), "Boid Data");
+
+ for(pa++; p<psys->totpart; p++, pa++)
+ pa->boid = (pa-1)->boid + 1;
+ }
+ }
+ else if(pa->boid){
+ MEM_freeN(pa->boid);
+ for(; p<psys->totpart; p++, pa++)
+ pa->boid = NULL;
+ }
+}
+static void psys_changed_physics(Object *ob, ParticleSystem *psys)
+{
+ ParticleSettings *part = psys->part;
+ if(ELEM(part->phystype, PART_PHYS_NO, PART_PHYS_KEYED)) {
+ PTCacheID pid;
+ BKE_ptcache_id_from_particles(&pid, ob, psys);
+ BKE_ptcache_id_clear(&pid, PTCACHE_CLEAR_ALL, 0);
+ }
+ else {
+ free_keyed_keys(psys);
+ psys->flag &= ~PSYS_KEYED;
+ }
+
+ if(part->phystype == PART_PHYS_BOIDS && part->boids == NULL) {
+ BoidState *state;
+
+ psys_check_boid_data(psys);
+
+ part->boids = MEM_callocN(sizeof(BoidSettings), "Boid Settings");
+ boid_default_settings(part->boids);
+
+ state = boid_new_state(part->boids);
+ BLI_addtail(&state->rules, boid_new_rule(eBoidRuleType_Separate));
+ BLI_addtail(&state->rules, boid_new_rule(eBoidRuleType_Flock));
+
+ ((BoidRule*)state->rules.first)->flag |= BOIDRULE_CURRENT;
+
+ state->flag |= BOIDSTATE_CURRENT;
+ BLI_addtail(&part->boids->states, state);
+ }
+}
static void particles_fluid_step(Scene *scene, Object *ob, ParticleSystem *psys, int cfra)
{
if(psys->particles){
@@ -4588,6 +4252,8 @@ static void system_step(Scene *scene, Object *ob, ParticleSystem *psys, Particle
BKE_ptcache_id_from_particles(&pid, ob, psys);
BKE_ptcache_id_time(&pid, scene, 0.0f, &startframe, &endframe, NULL);
+ psys_clear_temp_pointcache(psys);
+
/* update ipo's */
#if 0 // XXX old animation system
if((part->flag & PART_ABS_TIME) && part->ipo) {
@@ -4636,7 +4302,9 @@ static void system_step(Scene *scene, Object *ob, ParticleSystem *psys, Particle
oldtotpart = psys->totpart;
oldtotchild = psys->totchild;
- if(part->distr == PART_DISTR_GRID && part->from != PART_FROM_VERT)
+ if(psys->pointcache->flag & PTCACHE_EXTERNAL)
+ totpart = pid.cache->totpoint;
+ else if(part->distr == PART_DISTR_GRID && part->from != PART_FROM_VERT)
totpart = part->grid_res*part->grid_res*part->grid_res;
else
totpart = psys->part->totpart;
@@ -4736,7 +4404,7 @@ static void system_step(Scene *scene, Object *ob, ParticleSystem *psys, Particle
if(usecache && psys->cfra == startframe && (cache->flag & PTCACHE_OUTDATED || cache->last_exact==0))
write_particles_to_cache(ob, psys, startframe);
- if(part->phystype==PART_PHYS_KEYED && psys->flag&PSYS_FIRST_KEYED)
+ if(part->phystype==PART_PHYS_KEYED)
psys_count_keyed_targets(ob,psys);
/* initialize vertex groups */
@@ -4783,7 +4451,7 @@ static void system_step(Scene *scene, Object *ob, ParticleSystem *psys, Particle
write_particles_to_cache(ob, psys, framenr);
/* for keyed particles the path is allways known so it can be drawn */
- if(part->phystype==PART_PHYS_KEYED && psys->flag&PSYS_FIRST_KEYED){
+ if(part->phystype==PART_PHYS_KEYED) {
set_keyed_keys(scene, ob, psys);
psys_update_path_cache(scene, ob, psmd, psys,(int)cfra);
}
@@ -4866,7 +4534,9 @@ void particle_system_update(Scene *scene, Object *ob, ParticleSystem *psys)
return;
if(psys->recalc & PSYS_RECALC_TYPE)
- psys_changed_type(psys);
+ psys_changed_type(ob, psys);
+ else if(psys->recalc & PSYS_RECALC_PHYS)
+ psys_changed_physics(ob, psys);
/* (re-)create hair */
if(psys->part->type==PART_HAIR && hair_needs_recalc(psys)) {
diff --git a/source/blender/blenkernel/intern/pointcache.c b/source/blender/blenkernel/intern/pointcache.c
index 2fe46be7a89..4bb571aa8ca 100644
--- a/source/blender/blenkernel/intern/pointcache.c
+++ b/source/blender/blenkernel/intern/pointcache.c
@@ -181,7 +181,11 @@ static int ptcache_path(PTCacheID *pid, char *filename)
lib= (pid)? pid->ob->id.lib: NULL;
- if (G.relbase_valid || lib) {
+ if(pid->cache->flag & PTCACHE_EXTERNAL) {
+ strcpy(filename, pid->cache->path);
+ return BLI_add_slash(filename); /* new strlen() */
+ }
+ else if (G.relbase_valid || lib) {
char file[MAX_PTCACHE_PATH]; /* we dont want the dir, only the file */
char *blendfilename;
@@ -196,15 +200,14 @@ static int ptcache_path(PTCacheID *pid, char *filename)
snprintf(filename, MAX_PTCACHE_PATH, "//"PTCACHE_PATH"%s", file); /* add blend file name to pointcache dir */
BLI_convertstringcode(filename, blendfilename);
- BLI_add_slash(filename);
- return strlen(filename);
+ return BLI_add_slash(filename); /* new strlen() */
}
/* use the temp path. this is weak but better then not using point cache at all */
/* btempdir is assumed to exist and ALWAYS has a trailing slash */
snprintf(filename, MAX_PTCACHE_PATH, "%s"PTCACHE_PATH"%d", btempdir, abs(getpid()));
- BLI_add_slash(filename);
- return strlen(filename);
+
+ return BLI_add_slash(filename); /* new strlen() */
}
static int BKE_ptcache_id_filename(PTCacheID *pid, char *filename, int cfra, short do_path, short do_ext)
@@ -215,14 +218,14 @@ static int BKE_ptcache_id_filename(PTCacheID *pid, char *filename, int cfra, sho
filename[0] = '\0';
newname = filename;
- if (!G.relbase_valid) return 0; /* save blend file before using disk pointcache */
+ if (!G.relbase_valid && (pid->cache->flag & PTCACHE_EXTERNAL)==0) return 0; /* save blend file before using disk pointcache */
/* start with temp dir */
if (do_path) {
len = ptcache_path(pid, filename);
newname += len;
}
- if(strcmp(pid->cache->name, "")==0) {
+ if(strcmp(pid->cache->name, "")==0 && (pid->cache->flag & PTCACHE_EXTERNAL)==0) {
idname = (pid->ob->id.name+2);
/* convert chars to hex so they are always a valid filename */
while('\0' != *idname) {
@@ -239,7 +242,15 @@ static int BKE_ptcache_id_filename(PTCacheID *pid, char *filename, int cfra, sho
}
if (do_ext) {
- snprintf(newname, MAX_PTCACHE_FILE, "_%06d_%02d"PTCACHE_EXT, cfra, pid->stack_index); /* always 6 chars */
+ if(pid->cache->flag & PTCACHE_EXTERNAL) {
+ if(pid->cache->index >= 0)
+ snprintf(newname, MAX_PTCACHE_FILE, "_%06d_%02d"PTCACHE_EXT, cfra, pid->stack_index); /* always 6 chars */
+ else
+ snprintf(newname, MAX_PTCACHE_FILE, "_%06d"PTCACHE_EXT, cfra); /* always 6 chars */
+ }
+ else {
+ snprintf(newname, MAX_PTCACHE_FILE, "_%06d_%02d"PTCACHE_EXT, cfra, pid->stack_index); /* always 6 chars */
+ }
len += 16;
}
@@ -257,7 +268,7 @@ PTCacheFile *BKE_ptcache_file_open(PTCacheID *pid, int mode, int cfra)
if(pid->ob->id.lib && mode == PTCACHE_FILE_WRITE)
return NULL;
- if (!G.relbase_valid) return NULL; /* save blend file before using disk pointcache */
+ if (!G.relbase_valid && (pid->cache->flag & PTCACHE_EXTERNAL)==0) return NULL; /* save blend file before using disk pointcache */
BKE_ptcache_id_filename(pid, filename, cfra, 1, 1);
@@ -315,8 +326,10 @@ static int ptcache_pid_totelem(PTCacheID *pid)
ParticleSystem *psys = pid->data;
return psys->totpart;
}
- else if(pid->type==PTCACHE_TYPE_CLOTH)
- return 0; // TODO
+ else if(pid->type==PTCACHE_TYPE_CLOTH) {
+ ClothModifierData *clmd = pid->data;
+ return clmd->clothObject->numverts;
+ }
return 0;
}
@@ -327,6 +340,21 @@ void BKE_ptcache_update_info(PTCacheID *pid)
int totframes = 0;
char mem_info[64];
+ if(cache->flag & PTCACHE_EXTERNAL) {
+ int cfra = cache->startframe;
+
+ for(; cfra<=cache->endframe; cfra++) {
+ if(BKE_ptcache_id_exist(pid, cfra))
+ totframes++;
+ }
+
+ if(totframes)
+ sprintf(cache->info, "%i points read for %i frames", cache->totpoint, totframes);
+ else
+ sprintf(cache->info, "No valid data to read!");
+ return;
+ }
+
if(cache->flag & PTCACHE_DISK_CACHE) {
int cfra = cache->startframe;
@@ -429,6 +457,7 @@ int BKE_ptcache_read_cache(PTCacheReader *reader)
if(pf) {
BKE_ptcache_file_close(pf);
+ pf = NULL;
MEM_freeN(data);
}
@@ -523,7 +552,9 @@ int BKE_ptcache_read_cache(PTCacheReader *reader)
if(pf) {
BKE_ptcache_file_close(pf);
+ pf = NULL;
BKE_ptcache_file_close(pf2);
+ pf2 = NULL;
MEM_freeN(data1);
MEM_freeN(data2);
}
@@ -567,10 +598,13 @@ int BKE_ptcache_read_cache(PTCacheReader *reader)
if(pf) {
BKE_ptcache_file_close(pf);
+ pf = NULL;
MEM_freeN(data);
}
- if(pf2)
+ if(pf2) {
BKE_ptcache_file_close(pf2);
+ pf = NULL;
+ }
ret = PTCACHE_READ_OLD;
}
@@ -602,13 +636,15 @@ int BKE_ptcache_write_cache(PTCacheWriter *writer)
PTCacheFile *pf= NULL;
int elemsize = ptcache_pid_elemsize(writer->pid);
int i, incr = elemsize / sizeof(float);
- int add = 0, overwrite = 0, ocfra;
+ int add = 0, overwrite = 0;
float temp[14];
if(writer->totelem == 0 || writer->cfra <= 0)
return 0;
if(cache->flag & PTCACHE_DISK_CACHE) {
+ int cfra = cache->endframe;
+
/* allways start from scratch on the first frame */
if(writer->cfra == cache->startframe) {
BKE_ptcache_id_clear(writer->pid, PTCACHE_CLEAR_ALL, writer->cfra);
@@ -616,7 +652,7 @@ int BKE_ptcache_write_cache(PTCacheWriter *writer)
add = 1;
}
else {
- int cfra = cache->endframe;
+ int ocfra;
/* find last cached frame */
while(cfra > cache->startframe && !BKE_ptcache_id_exist(writer->pid, cfra))
cfra--;
@@ -626,7 +662,7 @@ int BKE_ptcache_write_cache(PTCacheWriter *writer)
while(ocfra > cache->startframe && !BKE_ptcache_id_exist(writer->pid, ocfra))
ocfra--;
- if(writer->cfra > cfra) {
+ if(cfra >= cache->startframe && writer->cfra > cfra) {
if(ocfra >= cache->startframe && cfra - ocfra < cache->step)
overwrite = 1;
else
@@ -636,7 +672,7 @@ int BKE_ptcache_write_cache(PTCacheWriter *writer)
if(add || overwrite) {
if(overwrite)
- BKE_ptcache_id_clear(writer->pid, PTCACHE_CLEAR_FRAME, ocfra);
+ BKE_ptcache_id_clear(writer->pid, PTCACHE_CLEAR_FRAME, cfra);
pf = BKE_ptcache_file_open(writer->pid, PTCACHE_FILE_WRITE, writer->cfra);
if(!pf)
@@ -665,7 +701,7 @@ int BKE_ptcache_write_cache(PTCacheWriter *writer)
pm2 = cache->mem_cache.last;
if(pm2 && writer->cfra > pm2->frame) {
- if(pm2 && pm2->prev && pm2->frame - pm2->prev->frame < cache->step)
+ if(pm2->prev && pm2->frame - pm2->prev->frame < cache->step)
overwrite = 1;
else
add = 1;
@@ -734,7 +770,7 @@ void BKE_ptcache_id_clear(PTCacheID *pid, int mode, int cfra)
char path_full[MAX_PTCACHE_FILE];
char ext[MAX_PTCACHE_PATH];
- if(!pid->cache)
+ if(!pid->cache || pid->cache->flag & PTCACHE_BAKED)
return;
/* don't allow clearing for linked objects */
@@ -1102,6 +1138,10 @@ PointCache *BKE_ptcache_copy(PointCache *cache)
ncache= MEM_dupallocN(cache);
+ /* hmm, should these be copied over instead? */
+ ncache->mem_cache.first = NULL;
+ ncache->mem_cache.last = NULL;
+
ncache->flag= 0;
ncache->simframe= 0;
@@ -1211,8 +1251,9 @@ void BKE_ptcache_make_cache(PTCacheBaker* baker)
cache = pid->cache;
if((cache->flag & PTCACHE_BAKED)==0) {
if(pid->type==PTCACHE_TYPE_PARTICLES) {
- /* skip hair particles */
- if(((ParticleSystem*)pid->data)->part->type == PART_HAIR)
+ ParticleSystem *psys = (ParticleSystem*)pid->data;
+ /* skip hair & keyed particles */
+ if(psys->part->type == PART_HAIR || psys->part->phystype == PART_PHYS_KEYED)
continue;
psys_get_pointcache_start_end(scene, pid->data, &cache->startframe, &cache->endframe);
@@ -1310,6 +1351,7 @@ void BKE_ptcache_toggle_disk_cache(PTCacheID *pid) {
if (!G.relbase_valid){
cache->flag &= ~PTCACHE_DISK_CACHE;
+ printf("File must be saved before using disk cache!\n");
return;
}
@@ -1393,3 +1435,77 @@ void BKE_ptcache_toggle_disk_cache(PTCacheID *pid) {
BKE_ptcache_update_info(pid);
}
+
+void BKE_ptcache_load_external(PTCacheID *pid)
+{
+ PointCache *cache = pid->cache;
+ int len; /* store the length of the string */
+
+ /* mode is same as fopen's modes */
+ DIR *dir;
+ struct dirent *de;
+ char path[MAX_PTCACHE_PATH];
+ char filename[MAX_PTCACHE_FILE];
+ char path_full[MAX_PTCACHE_FILE];
+ char ext[MAX_PTCACHE_PATH];
+
+ if(!cache)
+ return;
+
+ cache->startframe = MAXFRAME;
+ cache->endframe = -1;
+ cache->totpoint = 0;
+
+ ptcache_path(pid, path);
+
+ len = BKE_ptcache_id_filename(pid, filename, 1, 0, 0); /* no path */
+
+ dir = opendir(path);
+ if (dir==NULL)
+ return;
+
+ if(cache->index >= 0)
+ snprintf(ext, sizeof(ext), "_%02d"PTCACHE_EXT, cache->index);
+ else
+ strcpy(ext, PTCACHE_EXT);
+
+ while ((de = readdir(dir)) != NULL) {
+ if (strstr(de->d_name, ext)) { /* do we have the right extension?*/
+ if (strncmp(filename, de->d_name, len ) == 0) { /* do we have the right prefix */
+ /* read the number of the file */
+ int frame, len2 = strlen(de->d_name);
+ char num[7];
+
+ if (len2 > 15) { /* could crash if trying to copy a string out of this range*/
+ BLI_strncpy(num, de->d_name + (strlen(de->d_name) - 15), sizeof(num));
+ frame = atoi(num);
+
+ cache->startframe = MIN2(cache->startframe, frame);
+ cache->endframe = MAX2(cache->endframe, frame);
+ }
+ }
+ }
+ }
+ closedir(dir);
+
+ if(cache->startframe != MAXFRAME) {
+ PTCacheFile *pf;
+ int elemsize = ptcache_pid_elemsize(pid);
+ int incr = elemsize / sizeof(float);
+ float *data = NULL;
+ pf= BKE_ptcache_file_open(pid, PTCACHE_FILE_READ, cache->startframe);
+
+ if(pf) {
+ data = MEM_callocN(elemsize, "pointcache read data");
+ while(BKE_ptcache_file_read_floats(pf, data, incr))
+ cache->totpoint++;
+
+ BKE_ptcache_file_close(pf);
+ MEM_freeN(data);
+ }
+ }
+
+ cache->flag &= ~(PTCACHE_OUTDATED|PTCACHE_FRAMES_SKIPPED);
+
+ BKE_ptcache_update_info(pid);
+}
diff --git a/source/blender/blenkernel/intern/property.c b/source/blender/blenkernel/intern/property.c
index 261b58454bd..5cae527957b 100644
--- a/source/blender/blenkernel/intern/property.c
+++ b/source/blender/blenkernel/intern/property.c
@@ -33,6 +33,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <ctype.h>
#ifdef HAVE_CONFIG_H
#include <config.h>
@@ -99,25 +100,18 @@ void init_property(bProperty *prop)
if(prop->poin && prop->poin != &prop->data) MEM_freeN(prop->poin);
prop->poin= 0;
- prop->otype= prop->type;
prop->data= 0;
switch(prop->type) {
case GPROP_BOOL:
- prop->poin= &prop->data;
- break;
case GPROP_INT:
- prop->poin= &prop->data;
- break;
case GPROP_FLOAT:
+ case GPROP_TIME:
prop->poin= &prop->data;
break;
case GPROP_STRING:
prop->poin= MEM_callocN(MAX_PROPSTRING, "property string");
break;
- case GPROP_TIME:
- prop->poin= &prop->data;
- break;
}
}
@@ -136,6 +130,60 @@ bProperty *new_property(int type)
return prop;
}
+/* used by unique_property() only */
+static bProperty *get_property__internal(bProperty *first, bProperty *self, const char *name)
+{
+ bProperty *p;
+ for(p= first; p; p= p->next) {
+ if (p!=self && (strcmp(p->name, name)==0))
+ return p;
+ }
+ return NULL;
+}
+void unique_property(bProperty *first, bProperty *prop, int force)
+{
+ bProperty *p;
+
+ /* set the first if its not set */
+ if(first==NULL) {
+ first= prop;
+ while(first->prev) {
+ first= first->prev;
+ }
+ }
+
+ if(force) {
+ /* change other names to make them unique */
+ while((p = get_property__internal(first, prop, prop->name))) {
+ unique_property(first, p, 0);
+ }
+ }else {
+ /* change our own name until its unique */
+ if(get_property__internal(first, prop, prop->name)) {
+ /* there is a collision */
+ char new_name[sizeof(prop->name)];
+ char base_name[sizeof(prop->name)];
+ char num[sizeof(prop->name)];
+ int i= 0;
+
+ /* strip numbers */
+ strcpy(base_name, prop->name);
+ for(i= strlen(base_name)-1; (i>=0 && isdigit(base_name[i])); i--) {
+ base_name[i]= '\0';
+ }
+ i= 0;
+
+ do { /* ensure we have enough chars for the new number in the name */
+ sprintf(num, "%d", i++);
+ BLI_strncpy(new_name, base_name, sizeof(prop->name) - strlen(num));
+ strcat(new_name, num);
+ } while(get_property__internal(first, prop, new_name));
+
+ strcpy(prop->name, new_name);
+ }
+ }
+}
+
bProperty *get_ob_property(Object *ob, char *name)
{
bProperty *prop;
diff --git a/source/blender/blenkernel/intern/report.c b/source/blender/blenkernel/intern/report.c
index 8de8cf8d0f4..391adfb762a 100644
--- a/source/blender/blenkernel/intern/report.c
+++ b/source/blender/blenkernel/intern/report.c
@@ -49,6 +49,7 @@ static char *report_type_str(int type)
switch(type) {
case RPT_DEBUG: return "Debug";
case RPT_INFO: return "Info";
+ case RPT_OPERATOR: return "Operator";
case RPT_WARNING: return "Warning";
case RPT_ERROR: return "Error";
case RPT_ERROR_INVALID_INPUT: return "Invalid Input Error";
@@ -72,15 +73,21 @@ void BKE_reports_init(ReportList *reports, int flag)
void BKE_reports_clear(ReportList *reports)
{
- Report *report;
+ Report *report, *report_next;
if(!reports)
return;
- for(report=reports->list.first; report; report=report->next)
+ report= reports->list.first;
+
+ while (report) {
+ report_next= report->next;
MEM_freeN(report->message);
+ MEM_freeN(report);
+ report= report_next;
+ }
- BLI_freelistN(&reports->list);
+ reports->list.first= reports->list.last= NULL;
}
void BKE_report(ReportList *reports, ReportType type, const char *message)
@@ -101,7 +108,7 @@ void BKE_report(ReportList *reports, ReportType type, const char *message)
len= strlen(message);
report->message= MEM_callocN(sizeof(char)*(len+1), "ReportMessage");
memcpy(report->message, message, sizeof(char)*(len+1));
-
+ report->len= len;
BLI_addtail(&reports->list, report);
}
}
@@ -128,7 +135,7 @@ void BKE_reportf(ReportList *reports, ReportType type, const char *format, ...)
va_end(args);
report->message= BLI_dynstr_get_cstring(ds);
-
+ report->len= BLI_dynstr_get_len(ds);
BLI_dynstr_free(ds);
report->type= type;
@@ -154,6 +161,7 @@ void BKE_reports_prepend(ReportList *reports, const char *prepend)
MEM_freeN(report->message);
report->message= BLI_dynstr_get_cstring(ds);
+ report->len= BLI_dynstr_get_len(ds);
BLI_dynstr_free(ds);
}
@@ -178,6 +186,7 @@ void BKE_reports_prependf(ReportList *reports, const char *prepend, ...)
MEM_freeN(report->message);
report->message= BLI_dynstr_get_cstring(ds);
+ report->len= BLI_dynstr_get_len(ds);
BLI_dynstr_free(ds);
}
diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c
index 23da5c66850..d629654c426 100644
--- a/source/blender/blenkernel/intern/scene.c
+++ b/source/blender/blenkernel/intern/scene.c
@@ -54,7 +54,6 @@
#include "DNA_meta_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
-#include "DNA_scriptlink_types.h"
#include "DNA_texture_types.h"
#include "DNA_userdef_types.h"
@@ -142,10 +141,6 @@ void free_scene(Scene *sce)
BLI_freelistN(&sce->base);
seq_free_editing(sce->ed);
-
-#ifndef DISABLE_PYTHON
- BPY_free_scriptlink(&sce->scriptlink);
-#endif
BKE_free_animdata((ID *)sce);
BKE_keyingsets_free(&sce->keyingsets);
@@ -204,17 +199,17 @@ Scene *add_scene(char *name)
sce= alloc_libblock(&G.main->scene, ID_SCE, name);
sce->lay= 1;
- sce->r.mode= R_GAMMA;
+ sce->r.mode= R_GAMMA|R_OSA|R_SHADOW|R_SSS|R_ENVMAP|R_RAYTRACE;
sce->r.cfra= 1;
sce->r.sfra= 1;
sce->r.efra= 250;
- sce->r.xsch= 320;
- sce->r.ysch= 256;
+ sce->r.xsch= 1920;
+ sce->r.ysch= 1080;
sce->r.xasp= 1;
sce->r.yasp= 1;
- sce->r.xparts= 4;
- sce->r.yparts= 4;
- sce->r.size= 100;
+ sce->r.xparts= 8;
+ sce->r.yparts= 8;
+ sce->r.size= 25;
sce->r.planes= 24;
sce->r.quality= 90;
sce->r.framapto= 100;
@@ -223,26 +218,18 @@ Scene *add_scene(char *name)
sce->r.frs_sec= 25;
sce->r.frs_sec_base= 1;
sce->r.ocres = 128;
+ sce->r.color_mgt_flag |= R_COLOR_MANAGEMENT;
sce->r.bake_mode= 1; /* prevent to include render stuff here */
- sce->r.bake_filter= 2;
+ sce->r.bake_filter= 8;
sce->r.bake_osa= 5;
sce->r.bake_flag= R_BAKE_CLEAR;
sce->r.bake_normal_space= R_BAKE_SPACE_TANGENT;
-
- sce->r.xplay= 640;
- sce->r.yplay= 480;
- sce->r.freqplay= 60;
- sce->r.depth= 32;
+
+ sce->r.scemode= R_DOCOMP|R_DOSEQ|R_EXTENSION;
+ sce->r.stamp= R_STAMP_TIME|R_STAMP_FRAME|R_STAMP_DATE|R_STAMP_SCENE|R_STAMP_CAMERA;
sce->r.threads= 1;
-
- sce->r.stereomode = 1; // no stereo
- sce->r.domeangle = 180;
- sce->r.domemode = 1;
- sce->r.domeres = 4;
- sce->r.domeresbuf = 1.0f;
- sce->r.dometilt = 0;
sce->r.simplify_subsurf= 6;
sce->r.simplify_particles= 1.0f;
@@ -318,6 +305,29 @@ Scene *add_scene(char *name)
/* note; in header_info.c the scene copy happens..., if you add more to renderdata it has to be checked there */
scene_add_render_layer(sce);
+ /* game data */
+ sce->gm.stereoflag = STEREO_NOSTEREO;
+ sce->gm.stereomode = STEREO_ANAGLYPH;
+ sce->gm.dome.angle = 180;
+ sce->gm.dome.mode = DOME_FISHEYE;
+ sce->gm.dome.res = 4;
+ sce->gm.dome.resbuf = 1.0f;
+ sce->gm.dome.tilt = 0;
+
+ sce->gm.xplay= 800;
+ sce->gm.yplay= 600;
+ sce->gm.freqplay= 60;
+ sce->gm.depth= 32;
+
+ sce->gm.gravity= 9.8f;
+ sce->gm.physicsEngine= WOPHY_BULLET;
+ sce->gm.mode = 32; //XXX ugly harcoding, still not sure we should drop mode. 32 == 1 << 5 == use_occlusion_culling
+ sce->gm.occlusionRes = 128;
+ sce->gm.ticrate = 60;
+ sce->gm.maxlogicstep = 5;
+ sce->gm.physubstep = 1;
+ sce->gm.maxphystep = 5;
+
return sce;
}
@@ -383,9 +393,6 @@ void set_scene_bg(Scene *scene)
ob->ctime= -1234567.0; /* force ipo to be calculated later */
}
/* no full animation update, this to enable render code to work (render code calls own animation updates) */
-
- /* do we need FRAMECHANGED in set_scene? */
-// if (G.f & G_DOSCRIPTLINKS) BPY_do_all_scripts(SCRIPT_FRAMECHANGED, 0);
}
/* called from creator.c */
@@ -644,9 +651,6 @@ void scene_update_for_newframe(Scene *sce, unsigned int lay)
/* clear animation overrides */
// XXX TODO...
-#ifndef DISABLE_PYTHON
- if (G.f & G_DOSCRIPTLINKS) BPY_do_all_scripts(SCRIPT_FRAMECHANGED, 0);
-#endif
/* sets first, we allow per definition current scene to have dependencies on sets */
for(sce= sce->set; sce; sce= sce->set)
scene_update(sce, lay);
diff --git a/source/blender/blenkernel/intern/screen.c b/source/blender/blenkernel/intern/screen.c
index 4b6eddf60d0..cc740d7fb3d 100644
--- a/source/blender/blenkernel/intern/screen.c
+++ b/source/blender/blenkernel/intern/screen.c
@@ -61,16 +61,16 @@ static void spacetype_free(SpaceType *st)
BLI_freelistN(&art->drawcalls);
for(pt= art->paneltypes.first; pt; pt= pt->next)
- if(pt->py_free)
- pt->py_free(pt->py_data);
+ if(pt->ext.free)
+ pt->ext.free(pt->ext.data);
for(ht= art->headertypes.first; ht; ht= ht->next)
- if(ht->py_free)
- ht->py_free(ht->py_data);
+ if(ht->ext.free)
+ ht->ext.free(ht->ext.data);
for(mt= art->menutypes.first; mt; mt= mt->next)
- if(mt->py_free)
- mt->py_free(mt->py_data);
+ if(mt->ext.free)
+ mt->ext.free(mt->ext.data);
BLI_freelistN(&art->paneltypes);
BLI_freelistN(&art->headertypes);
@@ -112,7 +112,7 @@ ARegionType *BKE_regiontype_from_id(SpaceType *st, int regionid)
if(art->regionid==regionid)
return art;
- printf("Error, region type missing in %s\n", st->name);
+ printf("Error, region type missing in - name:\"%s\", id:%d\n", st->name, st->spaceid);
return st->regiontypes.first;
}
@@ -179,6 +179,9 @@ ARegion *BKE_area_region_copy(SpaceType *st, ARegion *ar)
else
newar->regiondata= MEM_dupallocN(ar->regiondata);
}
+
+ if(ar->v2d.tab_offset)
+ newar->v2d.tab_offset= MEM_dupallocN(ar->v2d.tab_offset);
newar->panels.first= newar->panels.last= NULL;
BLI_duplicatelist(&newar->panels, &ar->panels);
@@ -271,10 +274,14 @@ void BKE_area_region_free(SpaceType *st, ARegion *ar)
}
else if(ar->type && ar->type->free)
ar->type->free(ar);
+
+ if(ar->v2d.tab_offset) {
+ MEM_freeN(ar->v2d.tab_offset);
+ ar->v2d.tab_offset= NULL;
+ }
- if(ar) {
+ if(ar)
BLI_freelistN(&ar->panels);
- }
}
/* not area itself */
@@ -291,10 +298,6 @@ void BKE_screen_area_free(ScrArea *sa)
BKE_spacedata_freelist(&sa->spacedata);
BLI_freelistN(&sa->actionzones);
-
-#ifndef DISABLE_PYTHON
- BPY_free_scriptlink(&sa->scriptlink);
-#endif
}
/* don't free screen itself */
diff --git a/source/blender/blenkernel/intern/sequence.c b/source/blender/blenkernel/intern/sequence.c
index c8d95929027..4832086ac88 100644
--- a/source/blender/blenkernel/intern/sequence.c
+++ b/source/blender/blenkernel/intern/sequence.c
@@ -58,7 +58,7 @@
/* **** XXX ******** */
static int seqrectx= 0; /* bad bad global! */
static int seqrecty= 0;
-static void waitcursor() {}
+static void waitcursor(int val) {}
static int blender_test_break() {return 0;}
/* **** XXX ******** */
@@ -2017,7 +2017,8 @@ static void do_build_seq_ibuf(Scene *scene, Sequence * seq, TStripElem *se, int
RenderResult rres;
int doseq, rendering= G.rendering;
char scenename[64];
- int sce_valid =sce&& (sce->camera || sce->r.scemode & R_DOSEQ);
+ int have_seq= (sce->r.scemode & R_DOSEQ) && sce->ed && sce->ed->seqbase.first;
+ int sce_valid =sce && (sce->camera || have_seq);
if (se->ibuf == NULL && sce_valid && !build_proxy_run) {
se->ibuf = seq_proxy_fetch(scene, seq, cfra, render_size);
@@ -2038,7 +2039,7 @@ static void do_build_seq_ibuf(Scene *scene, Sequence * seq, TStripElem *se, int
} else if (se->ibuf==NULL && sce_valid) {
/* no need to display a waitcursor on sequencer
scene strips */
- if (!(sce->r.scemode & R_DOSEQ))
+ if (!have_seq)
waitcursor(1);
/* Hack! This function can be called from do_render_seq(), in that case
@@ -2093,7 +2094,7 @@ static void do_build_seq_ibuf(Scene *scene, Sequence * seq, TStripElem *se, int
// XXX
#if 0
if((G.f & G_PLAYANIM)==0 /* bad, is set on do_render_seq */
- && !(sce->r.scemode & R_DOSEQ)
+ && !have_seq
&& !build_proxy_run)
#endif
diff --git a/source/blender/blenkernel/intern/sketch.c b/source/blender/blenkernel/intern/sketch.c
new file mode 100644
index 00000000000..8deae7e8e10
--- /dev/null
+++ b/source/blender/blenkernel/intern/sketch.c
@@ -0,0 +1,600 @@
+/**
+ *
+ * $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.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include <string.h>
+#include <math.h>
+#include <float.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+
+#include "BKE_sketch.h"
+#include "BKE_utildefines.h"
+
+#include "DNA_userdef_types.h"
+
+void freeSketch(SK_Sketch *sketch)
+{
+ SK_Stroke *stk, *next;
+
+ for (stk = sketch->strokes.first; stk; stk = next)
+ {
+ next = stk->next;
+
+ sk_freeStroke(stk);
+ }
+
+ BLI_freelistN(&sketch->depth_peels);
+
+ MEM_freeN(sketch);
+}
+
+SK_Sketch* createSketch()
+{
+ SK_Sketch *sketch;
+
+ sketch = MEM_callocN(sizeof(SK_Sketch), "SK_Sketch");
+
+ sketch->active_stroke = NULL;
+ sketch->gesture = NULL;
+
+ sketch->strokes.first = NULL;
+ sketch->strokes.last = NULL;
+
+ return sketch;
+}
+
+void sk_initPoint(SK_Point *pt, SK_DrawData *dd, float *no)
+{
+ if (no)
+ {
+ VECCOPY(pt->no, no);
+ Normalize(pt->no);
+ }
+ else
+ {
+ pt->no[0] = 0;
+ pt->no[1] = 0;
+ pt->no[2] = 1;
+ }
+ pt->p2d[0] = dd->mval[0];
+ pt->p2d[1] = dd->mval[1];
+ /* more init code here */
+}
+
+void sk_copyPoint(SK_Point *dst, SK_Point *src)
+{
+ memcpy(dst, src, sizeof(SK_Point));
+}
+
+void sk_allocStrokeBuffer(SK_Stroke *stk)
+{
+ stk->points = MEM_callocN(sizeof(SK_Point) * stk->buf_size, "SK_Point buffer");
+}
+
+void sk_freeStroke(SK_Stroke *stk)
+{
+ MEM_freeN(stk->points);
+ MEM_freeN(stk);
+}
+
+SK_Stroke* sk_createStroke()
+{
+ SK_Stroke *stk;
+
+ stk = MEM_callocN(sizeof(SK_Stroke), "SK_Stroke");
+
+ stk->selected = 0;
+ stk->nb_points = 0;
+ stk->buf_size = SK_Stroke_BUFFER_INIT_SIZE;
+
+ sk_allocStrokeBuffer(stk);
+
+ return stk;
+}
+
+void sk_shrinkStrokeBuffer(SK_Stroke *stk)
+{
+ if (stk->nb_points < stk->buf_size)
+ {
+ SK_Point *old_points = stk->points;
+
+ stk->buf_size = stk->nb_points;
+
+ sk_allocStrokeBuffer(stk);
+
+ memcpy(stk->points, old_points, sizeof(SK_Point) * stk->nb_points);
+
+ MEM_freeN(old_points);
+ }
+}
+
+void sk_growStrokeBuffer(SK_Stroke *stk)
+{
+ if (stk->nb_points == stk->buf_size)
+ {
+ SK_Point *old_points = stk->points;
+
+ stk->buf_size *= 2;
+
+ sk_allocStrokeBuffer(stk);
+
+ memcpy(stk->points, old_points, sizeof(SK_Point) * stk->nb_points);
+
+ MEM_freeN(old_points);
+ }
+}
+
+void sk_growStrokeBufferN(SK_Stroke *stk, int n)
+{
+ if (stk->nb_points + n > stk->buf_size)
+ {
+ SK_Point *old_points = stk->points;
+
+ while (stk->nb_points + n > stk->buf_size)
+ {
+ stk->buf_size *= 2;
+ }
+
+ sk_allocStrokeBuffer(stk);
+
+ memcpy(stk->points, old_points, sizeof(SK_Point) * stk->nb_points);
+
+ MEM_freeN(old_points);
+ }
+}
+
+
+void sk_replaceStrokePoint(SK_Stroke *stk, SK_Point *pt, int n)
+{
+ memcpy(stk->points + n, pt, sizeof(SK_Point));
+}
+
+void sk_insertStrokePoint(SK_Stroke *stk, SK_Point *pt, int n)
+{
+ int size = stk->nb_points - n;
+
+ sk_growStrokeBuffer(stk);
+
+ memmove(stk->points + n + 1, stk->points + n, size * sizeof(SK_Point));
+
+ memcpy(stk->points + n, pt, sizeof(SK_Point));
+
+ stk->nb_points++;
+}
+
+void sk_appendStrokePoint(SK_Stroke *stk, SK_Point *pt)
+{
+ sk_growStrokeBuffer(stk);
+
+ memcpy(stk->points + stk->nb_points, pt, sizeof(SK_Point));
+
+ stk->nb_points++;
+}
+
+void sk_insertStrokePoints(SK_Stroke *stk, SK_Point *pts, int len, int start, int end)
+{
+ int size = end - start + 1;
+
+ sk_growStrokeBufferN(stk, len - size);
+
+ if (len != size)
+ {
+ int tail_size = stk->nb_points - end + 1;
+
+ memmove(stk->points + start + len, stk->points + end + 1, tail_size * sizeof(SK_Point));
+ }
+
+ memcpy(stk->points + start, pts, len * sizeof(SK_Point));
+
+ stk->nb_points += len - size;
+}
+
+void sk_trimStroke(SK_Stroke *stk, int start, int end)
+{
+ int size = end - start + 1;
+
+ if (start > 0)
+ {
+ memmove(stk->points, stk->points + start, size * sizeof(SK_Point));
+ }
+
+ stk->nb_points = size;
+}
+
+void sk_straightenStroke(SK_Stroke *stk, int start, int end, float p_start[3], float p_end[3])
+{
+ SK_Point pt1, pt2;
+ SK_Point *prev, *next;
+ float delta_p[3];
+ int i, total;
+
+ total = end - start;
+
+ VecSubf(delta_p, p_end, p_start);
+
+ prev = stk->points + start;
+ next = stk->points + end;
+
+ VECCOPY(pt1.p, p_start);
+ VECCOPY(pt1.no, prev->no);
+ pt1.mode = prev->mode;
+ pt1.type = prev->type;
+
+ VECCOPY(pt2.p, p_end);
+ VECCOPY(pt2.no, next->no);
+ pt2.mode = next->mode;
+ pt2.type = next->type;
+
+ sk_insertStrokePoint(stk, &pt1, start + 1); /* insert after start */
+ sk_insertStrokePoint(stk, &pt2, end + 1); /* insert before end (since end was pushed back already) */
+
+ for (i = 1; i < total; i++)
+ {
+ float delta = (float)i / (float)total;
+ float *p = stk->points[start + 1 + i].p;
+
+ VECCOPY(p, delta_p);
+ VecMulf(p, delta);
+ VecAddf(p, p, p_start);
+ }
+}
+
+void sk_polygonizeStroke(SK_Stroke *stk, int start, int end)
+{
+ int offset;
+ int i;
+
+ /* find first exact points outside of range */
+ for (;start > 0; start--)
+ {
+ if (stk->points[start].type == PT_EXACT)
+ {
+ break;
+ }
+ }
+
+ for (;end < stk->nb_points - 1; end++)
+ {
+ if (stk->points[end].type == PT_EXACT)
+ {
+ break;
+ }
+ }
+
+ offset = start + 1;
+
+ for (i = start + 1; i < end; i++)
+ {
+ if (stk->points[i].type == PT_EXACT)
+ {
+ if (offset != i)
+ {
+ memcpy(stk->points + offset, stk->points + i, sizeof(SK_Point));
+ }
+
+ offset++;
+ }
+ }
+
+ /* some points were removes, move end of array */
+ if (offset < end)
+ {
+ int size = stk->nb_points - end;
+ memmove(stk->points + offset, stk->points + end, size * sizeof(SK_Point));
+ stk->nb_points = offset + size;
+ }
+}
+
+void sk_flattenStroke(SK_Stroke *stk, int start, int end)
+{
+ float normal[3], distance[3];
+ float limit;
+ int i, total;
+
+ total = end - start + 1;
+
+ VECCOPY(normal, stk->points[start].no);
+
+ VecSubf(distance, stk->points[end].p, stk->points[start].p);
+ Projf(normal, distance, normal);
+ limit = Normalize(normal);
+
+ for (i = 1; i < total - 1; i++)
+ {
+ float d = limit * i / total;
+ float offset[3];
+ float *p = stk->points[start + i].p;
+
+ VecSubf(distance, p, stk->points[start].p);
+ Projf(distance, distance, normal);
+
+ VECCOPY(offset, normal);
+ VecMulf(offset, d);
+
+ VecSubf(p, p, distance);
+ VecAddf(p, p, offset);
+ }
+}
+
+void sk_removeStroke(SK_Sketch *sketch, SK_Stroke *stk)
+{
+ if (sketch->active_stroke == stk)
+ {
+ sketch->active_stroke = NULL;
+ }
+
+ BLI_remlink(&sketch->strokes, stk);
+ sk_freeStroke(stk);
+}
+
+void sk_reverseStroke(SK_Stroke *stk)
+{
+ SK_Point *old_points = stk->points;
+ int i = 0;
+
+ sk_allocStrokeBuffer(stk);
+
+ for (i = 0; i < stk->nb_points; i++)
+ {
+ sk_copyPoint(stk->points + i, old_points + stk->nb_points - 1 - i);
+ }
+
+ MEM_freeN(old_points);
+}
+
+
+/* Ramer-Douglas-Peucker algorithm for line simplification */
+void sk_filterStroke(SK_Stroke *stk, int start, int end)
+{
+ SK_Point *old_points = stk->points;
+ int nb_points = stk->nb_points;
+ char *marked = NULL;
+ char work;
+ int i;
+
+ if (start == -1)
+ {
+ start = 0;
+ end = stk->nb_points - 1;
+ }
+
+ sk_allocStrokeBuffer(stk);
+ stk->nb_points = 0;
+
+ /* adding points before range */
+ for (i = 0; i < start; i++)
+ {
+ sk_appendStrokePoint(stk, old_points + i);
+ }
+
+ marked = MEM_callocN(nb_points, "marked array");
+ marked[start] = 1;
+ marked[end] = 1;
+
+ work = 1;
+
+ /* while still reducing */
+ while (work)
+ {
+ int ls, le;
+ work = 0;
+
+ ls = start;
+ le = start+1;
+
+ /* while not over interval */
+ while (ls < end)
+ {
+ int max_i = 0;
+ short v1[2];
+ float max_dist = 16; /* more than 4 pixels */
+
+ /* find the next marked point */
+ while(marked[le] == 0)
+ {
+ le++;
+ }
+
+ /* perpendicular vector to ls-le */
+ v1[1] = old_points[le].p2d[0] - old_points[ls].p2d[0];
+ v1[0] = old_points[ls].p2d[1] - old_points[le].p2d[1];
+
+
+ for( i = ls + 1; i < le; i++ )
+ {
+ float mul;
+ float dist;
+ short v2[2];
+
+ v2[0] = old_points[i].p2d[0] - old_points[ls].p2d[0];
+ v2[1] = old_points[i].p2d[1] - old_points[ls].p2d[1];
+
+ if (v2[0] == 0 && v2[1] == 0)
+ {
+ continue;
+ }
+
+ mul = (float)(v1[0]*v2[0] + v1[1]*v2[1]) / (float)(v2[0]*v2[0] + v2[1]*v2[1]);
+
+ dist = mul * mul * (v2[0]*v2[0] + v2[1]*v2[1]);
+
+ if (dist > max_dist)
+ {
+ max_dist = dist;
+ max_i = i;
+ }
+ }
+
+ if (max_i != 0)
+ {
+ work = 1;
+ marked[max_i] = 1;
+ }
+
+ ls = le;
+ le = ls + 1;
+ }
+ }
+
+
+ /* adding points after range */
+ for (i = start; i <= end; i++)
+ {
+ if (marked[i])
+ {
+ sk_appendStrokePoint(stk, old_points + i);
+ }
+ }
+
+ MEM_freeN(marked);
+
+ /* adding points after range */
+ for (i = end + 1; i < nb_points; i++)
+ {
+ sk_appendStrokePoint(stk, old_points + i);
+ }
+
+ MEM_freeN(old_points);
+
+ sk_shrinkStrokeBuffer(stk);
+}
+
+
+void sk_filterLastContinuousStroke(SK_Stroke *stk)
+{
+ int start, end;
+
+ end = stk->nb_points -1;
+
+ for (start = end - 1; start > 0 && stk->points[start].type == PT_CONTINUOUS; start--)
+ {
+ /* nothing to do here*/
+ }
+
+ if (end - start > 1)
+ {
+ sk_filterStroke(stk, start, end);
+ }
+}
+
+SK_Point *sk_lastStrokePoint(SK_Stroke *stk)
+{
+ SK_Point *pt = NULL;
+
+ if (stk->nb_points > 0)
+ {
+ pt = stk->points + (stk->nb_points - 1);
+ }
+
+ return pt;
+}
+
+void sk_endContinuousStroke(SK_Stroke *stk)
+{
+ stk->points[stk->nb_points - 1].type = PT_EXACT;
+}
+
+void sk_updateNextPoint(SK_Sketch *sketch, SK_Stroke *stk)
+{
+ if (stk)
+ {
+ memcpy(&sketch->next_point, stk->points[stk->nb_points - 1].p, sizeof(SK_Point));
+ }
+}
+
+int sk_stroke_filtermval(SK_DrawData *dd)
+{
+ int retval = 0;
+ if (ABS(dd->mval[0] - dd->previous_mval[0]) + ABS(dd->mval[1] - dd->previous_mval[1]) > U.gp_manhattendist)
+ {
+ retval = 1;
+ }
+
+ return retval;
+}
+
+void sk_initDrawData(SK_DrawData *dd, short mval[2])
+{
+ dd->mval[0] = mval[0];
+ dd->mval[1] = mval[1];
+ dd->previous_mval[0] = -1;
+ dd->previous_mval[1] = -1;
+ dd->type = PT_EXACT;
+}
+
+
+void sk_deleteSelectedStrokes(SK_Sketch *sketch)
+{
+ SK_Stroke *stk, *next;
+
+ for (stk = sketch->strokes.first; stk; stk = next)
+ {
+ next = stk->next;
+
+ if (stk->selected == 1)
+ {
+ sk_removeStroke(sketch, stk);
+ }
+ }
+}
+
+void sk_selectAllSketch(SK_Sketch *sketch, int mode)
+{
+ SK_Stroke *stk = NULL;
+
+ if (mode == -1)
+ {
+ for (stk = sketch->strokes.first; stk; stk = stk->next)
+ {
+ stk->selected = 0;
+ }
+ }
+ else if (mode == 0)
+ {
+ for (stk = sketch->strokes.first; stk; stk = stk->next)
+ {
+ stk->selected = 1;
+ }
+ }
+ else if (mode == 1)
+ {
+ int selected = 1;
+
+ for (stk = sketch->strokes.first; stk; stk = stk->next)
+ {
+ selected &= stk->selected;
+ }
+
+ selected ^= 1;
+
+ for (stk = sketch->strokes.first; stk; stk = stk->next)
+ {
+ stk->selected = selected;
+ }
+ }
+}
diff --git a/source/blender/blenkernel/intern/smoke.c b/source/blender/blenkernel/intern/smoke.c
new file mode 100644
index 00000000000..fbf6beb835f
--- /dev/null
+++ b/source/blender/blenkernel/intern/smoke.c
@@ -0,0 +1,1342 @@
+/**
+ * BKE_cloth.h
+ *
+ * $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) Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Daniel Genrich
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/* Part of the code copied from elbeem fluid library, copyright by Nils Thuerey */
+
+#include <GL/glew.h>
+
+#include "MEM_guardedalloc.h"
+
+#include <float.h>
+#include <math.h>
+#include "stdio.h"
+
+#include "BLI_linklist.h"
+#include "BLI_rand.h"
+#include "BLI_jitter.h"
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+#include "BLI_edgehash.h"
+#include "BLI_kdtree.h"
+#include "BLI_kdopbvh.h"
+
+#include "BKE_cdderivedmesh.h"
+#include "BKE_customdata.h"
+#include "BKE_DerivedMesh.h"
+#include "BKE_modifier.h"
+#include "BKE_particle.h"
+#include "BKE_utildefines.h"
+
+#include "DNA_customdata_types.h"
+#include "DNA_group_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_object_types.h"
+#include "DNA_particle_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_smoke_types.h"
+
+#include "smoke_API.h"
+
+#include "BKE_smoke.h"
+
+#ifdef _WIN32
+#include <time.h>
+#include <stdio.h>
+#include <conio.h>
+#include <windows.h>
+
+static LARGE_INTEGER liFrequency;
+static LARGE_INTEGER liStartTime;
+static LARGE_INTEGER liCurrentTime;
+
+static void tstart ( void )
+{
+ QueryPerformanceFrequency ( &liFrequency );
+ QueryPerformanceCounter ( &liStartTime );
+}
+static void tend ( void )
+{
+ QueryPerformanceCounter ( &liCurrentTime );
+}
+static double tval()
+{
+ return ((double)( (liCurrentTime.QuadPart - liStartTime.QuadPart)* (double)1000.0/(double)liFrequency.QuadPart ));
+}
+#else
+#include <sys/time.h>
+static struct timeval _tstart, _tend;
+static struct timezone tz;
+static void tstart ( void )
+{
+ gettimeofday ( &_tstart, &tz );
+}
+static void tend ( void )
+{
+ gettimeofday ( &_tend,&tz );
+}
+static double tval()
+{
+ double t1, t2;
+ t1 = ( double ) _tstart.tv_sec*1000 + ( double ) _tstart.tv_usec/ ( 1000 );
+ t2 = ( double ) _tend.tv_sec*1000 + ( double ) _tend.tv_usec/ ( 1000 );
+ return t2-t1;
+}
+#endif
+
+struct Object;
+struct Scene;
+struct DerivedMesh;
+struct SmokeModifierData;
+
+// forward declerations
+static void get_cell(struct SmokeModifierData *smd, float *pos, int *cell, int correct);
+static void get_bigcell(struct SmokeModifierData *smd, float *pos, int *cell, int correct);
+void calcTriangleDivs(Object *ob, MVert *verts, int numverts, MFace *tris, int numfaces, int numtris, int **tridivs, float cell_len);
+
+#define TRI_UVOFFSET (1./4.)
+
+int smokeModifier_init (SmokeModifierData *smd, Object *ob, Scene *scene, DerivedMesh *dm)
+{
+ if((smd->type & MOD_SMOKE_TYPE_DOMAIN) && smd->domain && !smd->domain->fluid)
+ {
+ size_t i;
+ float min[3] = {FLT_MAX, FLT_MAX, FLT_MAX}, max[3] = {-FLT_MAX, -FLT_MAX, -FLT_MAX};
+ float size[3];
+ MVert *verts = dm->getVertArray(dm);
+ float scale = 0.0;
+ int res = smd->domain->maxres;
+
+ // get BB of domain
+ for(i = 0; i < dm->getNumVerts(dm); i++)
+ {
+ float tmp[3];
+
+ VECCOPY(tmp, verts[i].co);
+ Mat4MulVecfl(ob->obmat, tmp);
+
+ // min BB
+ min[0] = MIN2(min[0], tmp[0]);
+ min[1] = MIN2(min[1], tmp[1]);
+ min[2] = MIN2(min[2], tmp[2]);
+
+ // max BB
+ max[0] = MAX2(max[0], tmp[0]);
+ max[1] = MAX2(max[1], tmp[1]);
+ max[2] = MAX2(max[2], tmp[2]);
+ }
+
+ VECCOPY(smd->domain->p0, min);
+ VECCOPY(smd->domain->p1, max);
+
+ // calc other res with max_res provided
+ VECSUB(size, max, min);
+ if(size[0] > size[1])
+ {
+ if(size[0] > size[1])
+ {
+ scale = res / size[0];
+ smd->domain->dx = size[0] / res;
+ smd->domain->res[0] = res;
+ smd->domain->res[1] = (int)(size[1] * scale + 0.5);
+ smd->domain->res[2] = (int)(size[2] * scale + 0.5);
+ }
+ else
+ {
+ scale = res / size[1];
+ smd->domain->dx = size[1] / res;
+ smd->domain->res[1] = res;
+ smd->domain->res[0] = (int)(size[0] * scale + 0.5);
+ smd->domain->res[2] = (int)(size[2] * scale + 0.5);
+ }
+ }
+ else
+ {
+ if(size[1] > size[2])
+ {
+ scale = res / size[1];
+ smd->domain->dx = size[1] / res;
+ smd->domain->res[1] = res;
+ smd->domain->res[0] = (int)(size[0] * scale + 0.5);
+ smd->domain->res[2] = (int)(size[2] * scale + 0.5);
+ }
+ else
+ {
+ scale = res / size[2];
+ smd->domain->dx = size[2] / res;
+ smd->domain->res[2] = res;
+ smd->domain->res[0] = (int)(size[0] * scale + 0.5);
+ smd->domain->res[1] = (int)(size[1] * scale + 0.5);
+ }
+ }
+
+ printf("res[0]: %d, res[1]: %d, res[2]: %d\n", smd->domain->res[0], smd->domain->res[1], smd->domain->res[2]);
+
+ // dt max is 0.1
+ smd->domain->fluid = smoke_init(smd->domain->res, smd->domain->amplify, smd->domain->p0, smd->domain->p1, 2.5 / FPS);
+ smd->time = scene->r.cfra;
+ smd->domain->firstframe = smd->time;
+
+ smoke_initBlenderRNA(smd->domain->fluid, &(smd->domain->alpha), &(smd->domain->beta));
+
+ return 1;
+ }
+ else if((smd->type & MOD_SMOKE_TYPE_FLOW) && smd->flow)
+ {
+ // handle flow object here
+ // XXX TODO
+
+ smd->time = scene->r.cfra;
+
+ // update particle lifetime to be one frame
+ // smd->flow->psys->part->lifetime = scene->r.efra + 1;
+
+ return 1;
+ }
+ else if((smd->type & MOD_SMOKE_TYPE_COLL) && smd->coll)
+ {
+ smd->time = scene->r.cfra;
+
+ if(!smd->coll->points)
+ {
+ // init collision points
+ SmokeCollSettings *scs = smd->coll;
+ MVert *mvert = dm->getVertArray(dm);
+ MFace *mface = dm->getFaceArray(dm);
+ size_t i = 0, divs = 0;
+ int *tridivs = NULL;
+ float cell_len = 1.0 / 50.0; // for res = 50
+ size_t newdivs = 0;
+ size_t max_points = 0;
+ size_t quads = 0, facecounter = 0;
+
+ // count quads
+ for(i = 0; i < dm->getNumFaces(dm); i++)
+ {
+ if(mface[i].v4)
+ quads++;
+ }
+
+ calcTriangleDivs(ob, mvert, dm->getNumVerts(dm), mface, dm->getNumFaces(dm), dm->getNumFaces(dm) + quads, &tridivs, cell_len);
+
+ // count triangle divisions
+ for(i = 0; i < dm->getNumFaces(dm) + quads; i++)
+ {
+ divs += (tridivs[3 * i] + 1) * (tridivs[3 * i + 1] + 1) * (tridivs[3 * i + 2] + 1);
+ }
+
+ // printf("divs: %d\n", divs);
+
+ scs->points = MEM_callocN(sizeof(float) * (dm->getNumVerts(dm) + divs) * 3, "SmokeCollPoints");
+
+ for(i = 0; i < dm->getNumVerts(dm); i++)
+ {
+ float tmpvec[3];
+ VECCOPY(tmpvec, mvert[i].co);
+ Mat4MulVecfl (ob->obmat, tmpvec);
+ VECCOPY(&scs->points[i * 3], tmpvec);
+ }
+
+ for(i = 0, facecounter = 0; i < dm->getNumFaces(dm); i++)
+ {
+ int again = 0;
+ do
+ {
+ size_t j, k;
+ int divs1 = tridivs[3 * facecounter + 0];
+ int divs2 = tridivs[3 * facecounter + 1];
+ int divs3 = tridivs[3 * facecounter + 2];
+ float side1[3], side2[3], trinormorg[3], trinorm[3];
+
+ if(again == 1 && mface[i].v4)
+ {
+ VECSUB(side1, mvert[ mface[i].v3 ].co, mvert[ mface[i].v1 ].co);
+ VECSUB(side2, mvert[ mface[i].v4 ].co, mvert[ mface[i].v1 ].co);
+ }
+ else
+ {
+ VECSUB(side1, mvert[ mface[i].v2 ].co, mvert[ mface[i].v1 ].co);
+ VECSUB(side2, mvert[ mface[i].v3 ].co, mvert[ mface[i].v1 ].co);
+ }
+
+ Crossf(trinormorg, side1, side2);
+ Normalize(trinormorg);
+ VECCOPY(trinorm, trinormorg);
+ VecMulf(trinorm, 0.25 * cell_len);
+
+ for(j = 0; j <= divs1; j++)
+ {
+ for(k = 0; k <= divs2; k++)
+ {
+ float p1[3], p2[3], p3[3], p[3]={0,0,0};
+ const float uf = (float)(j + TRI_UVOFFSET) / (float)(divs1 + 0.0);
+ const float vf = (float)(k + TRI_UVOFFSET) / (float)(divs2 + 0.0);
+ float tmpvec[3];
+
+ if(uf+vf > 1.0)
+ {
+ // printf("bigger - divs1: %d, divs2: %d\n", divs1, divs2);
+ continue;
+ }
+
+ VECCOPY(p1, mvert[ mface[i].v1 ].co);
+ if(again == 1 && mface[i].v4)
+ {
+ VECCOPY(p2, mvert[ mface[i].v3 ].co);
+ VECCOPY(p3, mvert[ mface[i].v4 ].co);
+ }
+ else
+ {
+ VECCOPY(p2, mvert[ mface[i].v2 ].co);
+ VECCOPY(p3, mvert[ mface[i].v3 ].co);
+ }
+
+ VecMulf(p1, (1.0-uf-vf));
+ VecMulf(p2, uf);
+ VecMulf(p3, vf);
+
+ VECADD(p, p1, p2);
+ VECADD(p, p, p3);
+
+ if(newdivs > divs)
+ printf("mem problem\n");
+
+ // mMovPoints.push_back(p + trinorm);
+ VECCOPY(tmpvec, p);
+ VECADD(tmpvec, tmpvec, trinorm);
+ Mat4MulVecfl (ob->obmat, tmpvec);
+ VECCOPY(&scs->points[3 * (dm->getNumVerts(dm) + newdivs)], tmpvec);
+ newdivs++;
+
+ if(newdivs > divs)
+ printf("mem problem\n");
+
+ // mMovPoints.push_back(p - trinorm);
+ VECCOPY(tmpvec, p);
+ VECSUB(tmpvec, tmpvec, trinorm);
+ Mat4MulVecfl (ob->obmat, tmpvec);
+ VECCOPY(&scs->points[3 * (dm->getNumVerts(dm) + newdivs)], tmpvec);
+ newdivs++;
+ }
+ }
+
+ if(again == 0 && mface[i].v4)
+ again++;
+ else
+ again = 0;
+
+ facecounter++;
+
+ } while(again!=0);
+ }
+
+ scs->numpoints = dm->getNumVerts(dm) + newdivs;
+
+ MEM_freeN(tridivs);
+ }
+
+ }
+
+ return 0;
+}
+
+/*! init triangle divisions */
+void calcTriangleDivs(Object *ob, MVert *verts, int numverts, MFace *faces, int numfaces, int numtris, int **tridivs, float cell_len)
+{
+ // mTriangleDivs1.resize( faces.size() );
+ // mTriangleDivs2.resize( faces.size() );
+ // mTriangleDivs3.resize( faces.size() );
+
+ size_t i = 0, facecounter = 0;
+ float maxscale[3] = {1,1,1}; // = channelFindMaxVf(mcScale);
+ float maxpart = ABS(maxscale[0]);
+ float scaleFac = 0;
+ float fsTri = 0;
+ if(ABS(maxscale[1])>maxpart) maxpart = ABS(maxscale[1]);
+ if(ABS(maxscale[2])>maxpart) maxpart = ABS(maxscale[2]);
+ scaleFac = 1.0 / maxpart;
+ // featureSize = mLevel[mMaxRefine].nodeSize
+ fsTri = cell_len * 0.5 * scaleFac;
+
+ if(*tridivs)
+ MEM_freeN(*tridivs);
+
+ *tridivs = MEM_callocN(sizeof(int) * numtris * 3, "Smoke_Tridivs");
+
+ for(i = 0, facecounter = 0; i < numfaces; i++)
+ {
+ float p0[3], p1[3], p2[3];
+ float side1[3];
+ float side2[3];
+ float side3[3];
+ int divs1=0, divs2=0, divs3=0;
+
+ VECCOPY(p0, verts[faces[i].v1].co);
+ Mat4MulVecfl (ob->obmat, p0);
+ VECCOPY(p1, verts[faces[i].v2].co);
+ Mat4MulVecfl (ob->obmat, p1);
+ VECCOPY(p2, verts[faces[i].v3].co);
+ Mat4MulVecfl (ob->obmat, p2);
+
+ VECSUB(side1, p1, p0);
+ VECSUB(side2, p2, p0);
+ VECSUB(side3, p1, p2);
+
+ if(INPR(side1, side1) > fsTri*fsTri)
+ {
+ float tmp = Normalize(side1);
+ divs1 = (int)(tmp/fsTri);
+ }
+ if(INPR(side2, side2) > fsTri*fsTri)
+ {
+ float tmp = Normalize(side2);
+ divs2 = (int)(tmp/fsTri);
+
+ /*
+ // debug
+ if(i==0)
+ printf("b tmp: %f, fsTri: %f, divs2: %d\n", tmp, fsTri, divs2);
+ */
+ }
+
+ (*tridivs)[3 * facecounter + 0] = divs1;
+ (*tridivs)[3 * facecounter + 1] = divs2;
+ (*tridivs)[3 * facecounter + 2] = divs3;
+
+ // TODO quad case
+ if(faces[i].v4)
+ {
+ divs1=0, divs2=0, divs3=0;
+
+ facecounter++;
+
+ VECCOPY(p1, verts[faces[i].v3].co);
+ Mat4MulVecfl (ob->obmat, p1);
+ VECCOPY(p2, verts[faces[i].v4].co);
+ Mat4MulVecfl (ob->obmat, p2);
+
+ VECSUB(side1, p1, p0);
+ VECSUB(side2, p2, p0);
+ VECSUB(side3, p1, p2);
+
+ if(INPR(side1, side1) > fsTri*fsTri)
+ {
+ float tmp = Normalize(side1);
+ divs1 = (int)(tmp/fsTri);
+ }
+ if(INPR(side2, side2) > fsTri*fsTri)
+ {
+ float tmp = Normalize(side2);
+ divs2 = (int)(tmp/fsTri);
+ }
+
+ (*tridivs)[3 * facecounter + 0] = divs1;
+ (*tridivs)[3 * facecounter + 1] = divs2;
+ (*tridivs)[3 * facecounter + 2] = divs3;
+ }
+ facecounter++;
+ }
+}
+
+void smokeModifier_freeDomain(SmokeModifierData *smd)
+{
+ if(smd->domain)
+ {
+ // free visualisation buffers
+ if(smd->domain->bind)
+ {
+ glDeleteTextures(smd->domain->max_textures, (GLuint *)smd->domain->bind);
+ MEM_freeN(smd->domain->bind);
+ }
+ smd->domain->max_textures = 0; // unnecessary but let's be sure
+
+ if(smd->domain->tray)
+ MEM_freeN(smd->domain->tray);
+ if(smd->domain->tvox)
+ MEM_freeN(smd->domain->tvox);
+ if(smd->domain->traybig)
+ MEM_freeN(smd->domain->traybig);
+ if(smd->domain->tvoxbig)
+ MEM_freeN(smd->domain->tvoxbig);
+
+ if(smd->domain->fluid)
+ {
+ smoke_free(smd->domain->fluid);
+ }
+ MEM_freeN(smd->domain);
+ smd->domain = NULL;
+ }
+}
+
+void smokeModifier_freeFlow(SmokeModifierData *smd)
+{
+ if(smd->flow)
+ {
+ MEM_freeN(smd->flow);
+ smd->flow = NULL;
+ }
+}
+
+void smokeModifier_freeCollision(SmokeModifierData *smd)
+{
+ if(smd->coll)
+ {
+ if(smd->coll->points)
+ {
+ MEM_freeN(smd->coll->points);
+ smd->coll->points = NULL;
+ }
+
+ MEM_freeN(smd->coll);
+ smd->coll = NULL;
+ }
+}
+
+void smokeModifier_reset(struct SmokeModifierData *smd)
+{
+ if(smd)
+ {
+ if(smd->domain)
+ {
+ // free visualisation buffers
+ if(smd->domain->bind)
+ {
+ glDeleteTextures(smd->domain->max_textures, (GLuint *)smd->domain->bind);
+ MEM_freeN(smd->domain->bind);
+ smd->domain->bind = NULL;
+ }
+ smd->domain->max_textures = 0;
+ smd->domain->viewsettings = 0; // reset view for new frame
+
+ if(smd->domain->tray)
+ MEM_freeN(smd->domain->tray);
+ if(smd->domain->tvox)
+ MEM_freeN(smd->domain->tvox);
+ if(smd->domain->traybig)
+ MEM_freeN(smd->domain->traybig);
+ if(smd->domain->tvoxbig)
+ MEM_freeN(smd->domain->tvoxbig);
+
+ smd->domain->tvox = NULL;
+ smd->domain->tray = NULL;
+ smd->domain->tvoxbig = NULL;
+ smd->domain->traybig = NULL;
+
+ if(smd->domain->fluid)
+ {
+ smoke_free(smd->domain->fluid);
+ smd->domain->fluid = NULL;
+ }
+ }
+ else if(smd->flow)
+ {
+
+ }
+ else if(smd->coll)
+ {
+ if(smd->coll->points)
+ {
+ MEM_freeN(smd->coll->points);
+ smd->coll->points = NULL;
+ }
+ }
+ }
+}
+
+void smokeModifier_free (SmokeModifierData *smd)
+{
+ if(smd)
+ {
+ smokeModifier_freeDomain(smd);
+ smokeModifier_freeFlow(smd);
+ smokeModifier_freeCollision(smd);
+ }
+}
+
+void smokeModifier_createType(struct SmokeModifierData *smd)
+{
+ if(smd)
+ {
+ if(smd->type & MOD_SMOKE_TYPE_DOMAIN)
+ {
+ if(smd->domain)
+ smokeModifier_freeDomain(smd);
+
+ smd->domain = MEM_callocN(sizeof(SmokeDomainSettings), "SmokeDomain");
+
+ smd->domain->smd = smd;
+
+ /* set some standard values */
+ smd->domain->fluid = NULL;
+ smd->domain->eff_group = NULL;
+ smd->domain->fluid_group = NULL;
+ smd->domain->coll_group = NULL;
+ smd->domain->maxres = 48;
+ smd->domain->amplify = 2;
+ smd->domain->omega = 0.5;
+ smd->domain->alpha = -0.001;
+ smd->domain->beta = 0.1;
+ smd->domain->flags = 0;
+ smd->domain->noise = MOD_SMOKE_NOISEWAVE;
+ smd->domain->visibility = 1;
+
+ // init 3dview buffer
+ smd->domain->tvox = NULL;
+ smd->domain->tray = NULL;
+ smd->domain->tvoxbig = NULL;
+ smd->domain->traybig = NULL;
+ smd->domain->viewsettings = 0;
+ smd->domain->bind = NULL;
+ smd->domain->max_textures = 0;
+ }
+ else if(smd->type & MOD_SMOKE_TYPE_FLOW)
+ {
+ if(smd->flow)
+ smokeModifier_freeFlow(smd);
+
+ smd->flow = MEM_callocN(sizeof(SmokeFlowSettings), "SmokeFlow");
+
+ smd->flow->smd = smd;
+
+ /* set some standard values */
+ smd->flow->density = 1.0;
+ smd->flow->temp = 1.0;
+
+ smd->flow->psys = NULL;
+
+ }
+ else if(smd->type & MOD_SMOKE_TYPE_COLL)
+ {
+ if(smd->coll)
+ smokeModifier_freeCollision(smd);
+
+ smd->coll = MEM_callocN(sizeof(SmokeCollSettings), "SmokeColl");
+
+ smd->coll->smd = smd;
+ smd->coll->points = NULL;
+ smd->coll->numpoints = 0;
+ }
+ }
+}
+
+// forward declaration
+void smoke_calc_transparency(struct SmokeModifierData *smd, float *light, int big);
+
+void smokeModifier_do(SmokeModifierData *smd, Scene *scene, Object *ob, DerivedMesh *dm)
+{
+ if(scene->r.cfra >= smd->time)
+ smokeModifier_init(smd, ob, scene, dm);
+
+ if((smd->type & MOD_SMOKE_TYPE_FLOW))
+ {
+ if(scene->r.cfra > smd->time)
+ {
+ // XXX TODO
+ }
+ else if(scene->r.cfra < smd->time)
+ {
+ smd->time = scene->r.cfra;
+ smokeModifier_reset(smd);
+ }
+ }
+ else if((smd->type & MOD_SMOKE_TYPE_DOMAIN))
+ {
+ SmokeDomainSettings *sds = smd->domain;
+
+ if(scene->r.cfra > smd->time)
+ {
+ GroupObject *go = NULL;
+ Base *base = NULL;
+ int cnt_domain = 0;
+
+ tstart();
+
+ sds->viewsettings = 0; // reset view for new frame
+
+ // check for 2nd domain, if not there -> no groups are necessary
+ for(base = scene->base.first; base; base= base->next)
+ {
+ Object *ob1= base->object;
+
+ if(ob1 && ob1 != ob)
+ {
+ ModifierData *tmd = modifiers_findByType(ob1, eModifierType_Smoke);
+
+ if(tmd && tmd->mode & (eModifierMode_Realtime | eModifierMode_Render))
+ {
+ SmokeModifierData *tsmd = (SmokeModifierData *)tmd;
+
+ if((tsmd->type & MOD_SMOKE_TYPE_DOMAIN))
+ {
+ cnt_domain++;
+ }
+ }
+ }
+ }
+
+ // do flows and fluids
+ if(sds->fluid_group || !cnt_domain)
+ {
+ Object *otherobj = NULL;
+ ModifierData *md = NULL;
+
+ if(cnt_domain && !sds->fluid_group) // we use groups since we have 2 domains
+ go = sds->fluid_group->gobject.first;
+ else
+ base = scene->base.first;
+
+ while(base || go)
+ {
+ otherobj = NULL;
+
+ if(cnt_domain && !sds->fluid_group)
+ {
+ if(go->ob)
+ otherobj = go->ob;
+ }
+ else
+ otherobj = base->object;
+
+ if(!otherobj)
+ {
+ if(cnt_domain && !sds->fluid_group)
+ go = go->next;
+ else
+ base= base->next;
+
+ continue;
+ }
+
+ md = modifiers_findByType(otherobj, eModifierType_Smoke);
+
+ // check for active smoke modifier
+ if(md && md->mode & (eModifierMode_Realtime | eModifierMode_Render))
+ {
+ SmokeModifierData *smd2 = (SmokeModifierData *)md;
+
+ // check for initialized smoke object
+ if((smd2->type & MOD_SMOKE_TYPE_FLOW) && smd2->flow)
+ {
+ // we got nice flow object
+ SmokeFlowSettings *sfs = smd2->flow;
+
+ if(sfs->psys && sfs->psys->part && sfs->psys->part->type==PART_EMITTER) // is particle system selected
+ {
+ ParticleSystem *psys = sfs->psys;
+ ParticleSettings *part=psys->part;
+ ParticleData *pa = NULL;
+ int p = 0;
+ float *density = smoke_get_density(sds->fluid);
+ float *bigdensity = smoke_get_bigdensity(sds->fluid);
+ float *heat = smoke_get_heat(sds->fluid);
+ float *velocity_x = smoke_get_velocity_x(sds->fluid);
+ float *velocity_y = smoke_get_velocity_y(sds->fluid);
+ float *velocity_z = smoke_get_velocity_z(sds->fluid);
+ int bigres[3];
+
+ smoke_get_bigres(smd->domain->fluid, bigres);
+
+ // mostly copied from particle code
+ for(p=0, pa=psys->particles; p<psys->totpart; p++, pa++)
+ {
+ int cell[3];
+ int valid = 1;
+ size_t i = 0;
+ size_t index = 0;
+
+ if(pa->alive == PARS_KILLED) continue;
+ else if(pa->alive == PARS_UNBORN && (part->flag & PART_UNBORN)==0) continue;
+ else if(pa->alive == PARS_DEAD && (part->flag & PART_DIED)==0) continue;
+ else if(pa->flag & (PARS_UNEXIST+PARS_NO_DISP)) continue;
+
+ // VECCOPY(pos, pa->state.co);
+ // Mat4MulVecfl (ob->imat, pos);
+
+ // 1. get corresponding cell
+ get_cell(smd, pa->state.co, cell, 0);
+
+ // check if cell is valid (in the domain boundary)
+ for(i = 0; i < 3; i++)
+ if((cell[i] > sds->res[i] - 1) || (cell[i] < 0))
+ valid = 0;
+
+ if(!valid)
+ continue;
+
+ // 2. set cell values (heat, density and velocity)
+ index = smoke_get_index(cell[0], sds->res[0], cell[1], sds->res[1], cell[2]);
+
+ heat[index] = sfs->temp;
+ density[index] = sfs->density;
+ velocity_x[index] = pa->state.vel[0];
+ velocity_y[index] = pa->state.vel[1];
+ velocity_z[index] = pa->state.vel[2];
+
+ // we need different handling for the high-res feature
+ if(bigdensity)
+ {
+ // init all surrounding cells according to amplification, too
+ int i, j, k;
+ for(i = 0; i < smd->domain->amplify; i++)
+ for(j = 0; j < smd->domain->amplify; j++)
+ for(k = 0; k < smd->domain->amplify; k++)
+ {
+ index = smoke_get_index(smd->domain->amplify * cell[0] + i, bigres[0], smd->domain->amplify * cell[1] + j, bigres[1], smd->domain->amplify * cell[2] + k);
+ bigdensity[index] = sfs->density;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if(cnt_domain && !sds->fluid_group)
+ go = go->next;
+ else
+ base= base->next;
+ }
+ }
+
+ // do effectors
+ /*
+ if(sds->eff_group)
+ {
+ for(go = sds->eff_group->gobject.first; go; go = go->next)
+ {
+ if(go->ob)
+ {
+ if(ob->pd)
+ {
+
+ }
+ }
+ }
+ }
+ */
+
+ // do collisions
+ if(sds->coll_group || !cnt_domain)
+ {
+ Object *otherobj = NULL;
+ ModifierData *md = NULL;
+
+ if(cnt_domain && !sds->coll_group) // we use groups since we have 2 domains
+ go = sds->coll_group->gobject.first;
+ else
+ base = scene->base.first;
+
+ while(base || go)
+ {
+ otherobj = NULL;
+
+ if(cnt_domain && !sds->coll_group)
+ {
+ if(go->ob)
+ otherobj = go->ob;
+ }
+ else
+ otherobj = base->object;
+
+ if(!otherobj)
+ {
+ if(cnt_domain && !sds->coll_group)
+ go = go->next;
+ else
+ base= base->next;
+
+ continue;
+ }
+
+ md = modifiers_findByType(otherobj, eModifierType_Smoke);
+
+ // check for active smoke modifier
+ if(md && md->mode & (eModifierMode_Realtime | eModifierMode_Render))
+ {
+ SmokeModifierData *smd2 = (SmokeModifierData *)md;
+
+ if((smd2->type & MOD_SMOKE_TYPE_COLL) && smd2->coll)
+ {
+ // we got nice collision object
+ SmokeCollSettings *scs = smd2->coll;
+ int cell[3];
+ int valid = 1;
+ size_t index = 0;
+ size_t i, j;
+ unsigned char *obstacles = smoke_get_obstacle(smd->domain->fluid);
+
+ for(i = 0; i < scs->numpoints; i++)
+ {
+ // 1. get corresponding cell
+ get_cell(smd, &scs->points[3 * i], cell, 0);
+
+ // check if cell is valid (in the domain boundary)
+ for(j = 0; j < 3; j++)
+ if((cell[j] > sds->res[j] - 1) || (cell[j] < 0))
+ valid = 0;
+
+ if(!valid)
+ continue;
+
+ // 2. set cell values (heat, density and velocity)
+ index = smoke_get_index(cell[0], sds->res[0], cell[1], sds->res[1], cell[2]);
+
+ obstacles[index] = 1;
+
+ // for moving gobstacles
+ /*
+ const LbmFloat maxVelVal = 0.1666;
+ const LbmFloat maxusqr = maxVelVal*maxVelVal*3. *1.5;
+
+ LbmVec objvel = vec2L((mMOIVertices[n]-mMOIVerticesOld[n]) /dvec); {
+ const LbmFloat usqr = (objvel[0]*objvel[0]+objvel[1]*objvel[1]+objvel[2]*objvel[2])*1.5;
+ USQRMAXCHECK(usqr, objvel[0],objvel[1],objvel[2], mMaxVlen, mMxvx,mMxvy,mMxvz);
+ if(usqr>maxusqr) {
+ // cutoff at maxVelVal
+ for(int jj=0; jj<3; jj++) {
+ if(objvel[jj]>0.) objvel[jj] = maxVelVal;
+ if(objvel[jj]<0.) objvel[jj] = -maxVelVal;
+ }
+ } }
+
+ const LbmFloat dp=dot(objvel, vec2L((*pNormals)[n]) );
+ const LbmVec oldov=objvel; // debug
+ objvel = vec2L((*pNormals)[n]) *dp;
+ */
+ }
+ }
+ }
+
+ if(cnt_domain && !sds->coll_group)
+ go = go->next;
+ else
+ base= base->next;
+ }
+ }
+
+ // set new time
+ smd->time = scene->r.cfra;
+
+ // simulate the actual smoke (c++ code in intern/smoke)
+ smoke_step(sds->fluid);
+
+ tend();
+ printf ( "Frame: %d, Time: %f\n", (int)smd->time, ( float ) tval() );
+ }
+ else if(scene->r.cfra < smd->time)
+ {
+ // we got back in time, reset smoke in this case (TODO: use cache later)
+ smd->time = scene->r.cfra;
+ smokeModifier_reset(smd);
+ }
+ }
+}
+
+// update necessary information for 3dview
+void smoke_prepare_View(SmokeModifierData *smd, float *light)
+{
+ float *density = NULL;
+ int x, y, z;
+
+ if(!smd->domain->tray)
+ {
+ // TRay is for self shadowing
+ smd->domain->tray = MEM_callocN(sizeof(float)*smd->domain->res[0]*smd->domain->res[1]*smd->domain->res[2], "Smoke_tRay");
+ }
+ if(!smd->domain->tvox)
+ {
+ // TVox is for tranaparency
+ smd->domain->tvox = MEM_callocN(sizeof(float)*smd->domain->res[0]*smd->domain->res[1]*smd->domain->res[2], "Smoke_tVox");
+ }
+
+ // update 3dview
+ density = smoke_get_density(smd->domain->fluid);
+ for(x = 0; x < smd->domain->res[0]; x++)
+ for(y = 0; y < smd->domain->res[1]; y++)
+ for(z = 0; z < smd->domain->res[2]; z++)
+ {
+ size_t index;
+
+ index = smoke_get_index(x, smd->domain->res[0], y, smd->domain->res[1], z);
+ // Transparency computation
+ // formula taken from "Visual Simulation of Smoke" / Fedkiw et al. pg. 4
+ // T_vox = exp(-C_ext * h)
+ // C_ext/sigma_t = density * C_ext
+ smoke_set_tvox(smd, index, exp(-density[index] * 4.0 * smd->domain->dx));
+ }
+ smoke_calc_transparency(smd, light, 0);
+}
+
+// update necessary information for 3dview ("high res" option)
+void smoke_prepare_bigView(SmokeModifierData *smd, float *light)
+{
+ float *density = NULL;
+ size_t i = 0;
+ int bigres[3];
+
+ smoke_get_bigres(smd->domain->fluid, bigres);
+
+ if(!smd->domain->traybig)
+ {
+ // TRay is for self shadowing
+ smd->domain->traybig = MEM_callocN(sizeof(float)*bigres[0]*bigres[1]*bigres[2], "Smoke_tRayBig");
+ }
+ if(!smd->domain->tvoxbig)
+ {
+ // TVox is for tranaparency
+ smd->domain->tvoxbig = MEM_callocN(sizeof(float)*bigres[0]*bigres[1]*bigres[2], "Smoke_tVoxBig");
+ }
+
+ density = smoke_get_bigdensity(smd->domain->fluid);
+ for (i = 0; i < bigres[0] * bigres[1] * bigres[2]; i++)
+ {
+ // Transparency computation
+ // formula taken from "Visual Simulation of Smoke" / Fedkiw et al. pg. 4
+ // T_vox = exp(-C_ext * h)
+ // C_ext/sigma_t = density * C_ext
+ smoke_set_bigtvox(smd, i, exp(-density[i] * 4.0 * smd->domain->dx / smd->domain->amplify) );
+ }
+ smoke_calc_transparency(smd, light, 1);
+}
+
+
+float smoke_get_tvox(SmokeModifierData *smd, size_t index)
+{
+ return smd->domain->tvox[index];
+}
+
+void smoke_set_tvox(SmokeModifierData *smd, size_t index, float tvox)
+{
+ smd->domain->tvox[index] = tvox;
+}
+
+float smoke_get_tray(SmokeModifierData *smd, size_t index)
+{
+ return smd->domain->tray[index];
+}
+
+void smoke_set_tray(SmokeModifierData *smd, size_t index, float transparency)
+{
+ smd->domain->tray[index] = transparency;
+}
+
+float smoke_get_bigtvox(SmokeModifierData *smd, size_t index)
+{
+ return smd->domain->tvoxbig[index];
+}
+
+void smoke_set_bigtvox(SmokeModifierData *smd, size_t index, float tvox)
+{
+ smd->domain->tvoxbig[index] = tvox;
+}
+
+float smoke_get_bigtray(SmokeModifierData *smd, size_t index)
+{
+ return smd->domain->traybig[index];
+}
+
+void smoke_set_bigtray(SmokeModifierData *smd, size_t index, float transparency)
+{
+ smd->domain->traybig[index] = transparency;
+}
+
+long long smoke_get_mem_req(int xres, int yres, int zres, int amplify)
+{
+ int totalCells = xres * yres * zres;
+ int amplifiedCells = totalCells * amplify * amplify * amplify;
+
+ // print out memory requirements
+ long long int coarseSize = sizeof(float) * totalCells * 22 +
+ sizeof(unsigned char) * totalCells;
+
+ long long int fineSize = sizeof(float) * amplifiedCells * 7 + // big grids
+ sizeof(float) * totalCells * 8 + // small grids
+ sizeof(float) * 128 * 128 * 128; // noise tile
+
+ long long int totalMB = (coarseSize + fineSize) / (1024 * 1024);
+
+ return totalMB;
+}
+
+
+static void calc_voxel_transp(SmokeModifierData *smd, int *pixel, float *tRay)
+{
+ // printf("Pixel(%d, %d, %d)\n", pixel[0], pixel[1], pixel[2]);
+ const size_t index = smoke_get_index(pixel[0], smd->domain->res[0], pixel[1], smd->domain->res[1], pixel[2]);
+
+ // T_ray *= T_vox
+ *tRay *= smoke_get_tvox(smd, index);
+}
+
+static void calc_voxel_transp_big(SmokeModifierData *smd, int *pixel, float *tRay)
+{
+ int bigres[3];
+ size_t index;
+
+ smoke_get_bigres(smd->domain->fluid, bigres);
+ index = smoke_get_index(pixel[0], bigres[0], pixel[1], bigres[1], pixel[2]);
+
+ /*
+ if(index > bigres[0]*bigres[1]*bigres[2])
+ printf("pixel[0]: %d, [1]: %d, [2]: %d\n", pixel[0], pixel[1], pixel[2]);
+ */
+
+ // T_ray *= T_vox
+ *tRay *= smoke_get_bigtvox(smd, index);
+}
+
+static void bresenham_linie_3D(SmokeModifierData *smd, int x1, int y1, int z1, int x2, int y2, int z2, float *tRay, int big)
+{
+ int dx, dy, dz, i, l, m, n, x_inc, y_inc, z_inc, err_1, err_2, dx2, dy2, dz2;
+ int pixel[3];
+
+ pixel[0] = x1;
+ pixel[1] = y1;
+ pixel[2] = z1;
+
+ dx = x2 - x1;
+ dy = y2 - y1;
+ dz = z2 - z1;
+
+ x_inc = (dx < 0) ? -1 : 1;
+ l = abs(dx);
+ y_inc = (dy < 0) ? -1 : 1;
+ m = abs(dy);
+ z_inc = (dz < 0) ? -1 : 1;
+ n = abs(dz);
+ dx2 = l << 1;
+ dy2 = m << 1;
+ dz2 = n << 1;
+
+ if ((l >= m) && (l >= n)) {
+ err_1 = dy2 - l;
+ err_2 = dz2 - l;
+ for (i = 0; i < l; i++) {
+ if(!big)
+ calc_voxel_transp(smd, pixel, tRay);
+ else
+ calc_voxel_transp_big(smd, pixel, tRay);
+ if(*tRay < 0.0f)
+ return;
+ if (err_1 > 0) {
+ pixel[1] += y_inc;
+ err_1 -= dx2;
+ }
+ if (err_2 > 0) {
+ pixel[2] += z_inc;
+ err_2 -= dx2;
+ }
+ err_1 += dy2;
+ err_2 += dz2;
+ pixel[0] += x_inc;
+ }
+ } else if ((m >= l) && (m >= n)) {
+ err_1 = dx2 - m;
+ err_2 = dz2 - m;
+ for (i = 0; i < m; i++) {
+ if(!big)
+ calc_voxel_transp(smd, pixel, tRay);
+ else
+ calc_voxel_transp_big(smd, pixel, tRay);
+ if(*tRay < 0.0f)
+ return;
+ if (err_1 > 0) {
+ pixel[0] += x_inc;
+ err_1 -= dy2;
+ }
+ if (err_2 > 0) {
+ pixel[2] += z_inc;
+ err_2 -= dy2;
+ }
+ err_1 += dx2;
+ err_2 += dz2;
+ pixel[1] += y_inc;
+ }
+ } else {
+ err_1 = dy2 - n;
+ err_2 = dx2 - n;
+ for (i = 0; i < n; i++) {
+ if(!big)
+ calc_voxel_transp(smd, pixel, tRay);
+ else
+ calc_voxel_transp_big(smd, pixel, tRay);
+ if(*tRay < 0.0f)
+ return;
+ if (err_1 > 0) {
+ pixel[1] += y_inc;
+ err_1 -= dz2;
+ }
+ if (err_2 > 0) {
+ pixel[0] += x_inc;
+ err_2 -= dz2;
+ }
+ err_1 += dy2;
+ err_2 += dx2;
+ pixel[2] += z_inc;
+ }
+ }
+ if(!big)
+ calc_voxel_transp(smd, pixel, tRay);
+ else
+ calc_voxel_transp_big(smd, pixel, tRay);
+}
+
+static void get_cell(struct SmokeModifierData *smd, float *pos, int *cell, int correct)
+{
+ float tmp[3];
+
+ VECSUB(tmp, pos, smd->domain->p0);
+ VecMulf(tmp, 1.0 / smd->domain->dx);
+
+ if(correct)
+ {
+ cell[0] = MIN2(smd->domain->res[0] - 1, MAX2(0, (int)(tmp[0] + 0.5)));
+ cell[1] = MIN2(smd->domain->res[1] - 1, MAX2(0, (int)(tmp[1] + 0.5)));
+ cell[2] = MIN2(smd->domain->res[2] - 1, MAX2(0, (int)(tmp[2] + 0.5)));
+ }
+ else
+ {
+ cell[0] = (int)(tmp[0] + 0.5);
+ cell[1] = (int)(tmp[1] + 0.5);
+ cell[2] = (int)(tmp[2] + 0.5);
+ }
+}
+static void get_bigcell(struct SmokeModifierData *smd, float *pos, int *cell, int correct)
+{
+ float tmp[3];
+ int res[3];
+ smoke_get_bigres(smd->domain->fluid, res);
+
+ VECSUB(tmp, pos, smd->domain->p0);
+
+ VecMulf(tmp, smd->domain->amplify / smd->domain->dx );
+
+ if(correct)
+ {
+ cell[0] = MIN2(res[0] - 1, MAX2(0, (int)(tmp[0] + 0.5)));
+ cell[1] = MIN2(res[1] - 1, MAX2(0, (int)(tmp[1] + 0.5)));
+ cell[2] = MIN2(res[2] - 1, MAX2(0, (int)(tmp[2] + 0.5)));
+ }
+ else
+ {
+ cell[0] = (int)(tmp[0] + 0.5);
+ cell[1] = (int)(tmp[1] + 0.5);
+ cell[2] = (int)(tmp[2] + 0.5);
+ }
+}
+
+
+void smoke_calc_transparency(struct SmokeModifierData *smd, float *light, int big)
+{
+ int x, y, z;
+ float bv[6];
+ int res[3];
+ float bigfactor = 1.0;
+
+ // x
+ bv[0] = smd->domain->p0[0];
+ bv[1] = smd->domain->p1[0];
+ // y
+ bv[2] = smd->domain->p0[1];
+ bv[3] = smd->domain->p1[1];
+ // z
+ bv[4] = smd->domain->p0[2];
+ bv[5] = smd->domain->p1[2];
+/*
+ printf("bv[0]: %f, [1]: %f, [2]: %f, [3]: %f, [4]: %f, [5]: %f\n", bv[0], bv[1], bv[2], bv[3], bv[4], bv[5]);
+
+ printf("p0[0]: %f, p0[1]: %f, p0[2]: %f\n", smd->domain->p0[0], smd->domain->p0[1], smd->domain->p0[2]);
+ printf("p1[0]: %f, p1[1]: %f, p1[2]: %f\n", smd->domain->p1[0], smd->domain->p1[1], smd->domain->p1[2]);
+ printf("dx: %f, amp: %d\n", smd->domain->dx, smd->domain->amplify);
+*/
+ if(!big)
+ {
+ res[0] = smd->domain->res[0];
+ res[1] = smd->domain->res[1];
+ res[2] = smd->domain->res[2];
+ }
+ else
+ {
+ smoke_get_bigres(smd->domain->fluid, res);
+ bigfactor = 1.0 / smd->domain->amplify;
+ }
+
+#pragma omp parallel for schedule(static) private(y, z) shared(big, smd, light, res, bigfactor)
+ for(x = 0; x < res[0]; x++)
+ for(y = 0; y < res[1]; y++)
+ for(z = 0; z < res[2]; z++)
+ {
+ float voxelCenter[3];
+ size_t index;
+ float pos[3];
+ int cell[3];
+ float tRay = 1.0;
+
+ index = smoke_get_index(x, res[0], y, res[1], z);
+
+ // voxelCenter = m_voxelarray[i].GetCenter();
+ voxelCenter[0] = smd->domain->p0[0] + smd->domain->dx * bigfactor * x + smd->domain->dx * bigfactor * 0.5;
+ voxelCenter[1] = smd->domain->p0[1] + smd->domain->dx * bigfactor * y + smd->domain->dx * bigfactor * 0.5;
+ voxelCenter[2] = smd->domain->p0[2] + smd->domain->dx * bigfactor * z + smd->domain->dx * bigfactor * 0.5;
+
+ // printf("vc[0]: %f, vc[1]: %f, vc[2]: %f\n", voxelCenter[0], voxelCenter[1], voxelCenter[2]);
+ // printf("light[0]: %f, light[1]: %f, light[2]: %f\n", light[0], light[1], light[2]);
+
+ // get starting position (in voxel coords)
+ if(BLI_bvhtree_bb_raycast(bv, light, voxelCenter, pos) > FLT_EPSILON)
+ {
+ // we're ouside
+ // printf("out: pos[0]: %f, pos[1]: %f, pos[2]: %f\n", pos[0], pos[1], pos[2]);
+ if(!big)
+ get_cell(smd, pos, cell, 1);
+ else
+ get_bigcell(smd, pos, cell, 1);
+ }
+ else
+ {
+ // printf("in: pos[0]: %f, pos[1]: %f, pos[2]: %f\n", light[0], light[1], light[2]);
+ // we're inside
+ if(!big)
+ get_cell(smd, light, cell, 1);
+ else
+ get_bigcell(smd, light, cell, 1);
+ }
+
+ // printf("cell - [0]: %d, [1]: %d, [2]: %d\n", cell[0], cell[1], cell[2]);
+ bresenham_linie_3D(smd, cell[0], cell[1], cell[2], x, y, z, &tRay, big);
+
+ if(!big)
+ smoke_set_tray(smd, index, tRay);
+ else
+ smoke_set_bigtray(smd, index, tRay);
+ }
+}
+
diff --git a/source/blender/blenkernel/intern/softbody.c b/source/blender/blenkernel/intern/softbody.c
index bc6b487080c..fe63585ae1c 100644
--- a/source/blender/blenkernel/intern/softbody.c
+++ b/source/blender/blenkernel/intern/softbody.c
@@ -82,7 +82,7 @@ variables on the UI for now
#include "BKE_DerivedMesh.h"
#include "BKE_pointcache.h"
#include "BKE_modifier.h"
-
+#include "BKE_deform.h"
//XXX #include "BIF_editdeform.h"
//XXX #include "BIF_graphics.h"
#include "PIL_time.h"
@@ -2051,7 +2051,7 @@ static void sb_spring_force(Object *ob,int bpi,BodySpring *bs,float iks,float fo
BodyPoint *bp1,*bp2;
float dir[3],dvel[3];
- float distance,forcefactor,kd,absvel,projvel;
+ float distance,forcefactor,kd,absvel,projvel,kw;
int ia,ic;
/* prepare depending on which side of the spring we are on */
if (bpi == bs->v1){
@@ -2085,7 +2085,10 @@ static void sb_spring_force(Object *ob,int bpi,BodySpring *bs,float iks,float fo
forcefactor = iks/bs->len;
else
forcefactor = iks;
- forcefactor *= bs->strength;
+ kw = (bp1->springweight+bp2->springweight)/2.0f;
+ kw = kw * kw;
+ kw = kw * kw;
+ forcefactor *= bs->strength * kw;
Vec3PlusStVec(bp1->force,(bs->len - distance)*forcefactor,dir);
/* do bp1 <--> bp2 viscous */
@@ -2185,14 +2188,14 @@ static int _softbody_calc_forces_slice_in_a_thread(Scene *scene, Object *ob, flo
VecMidf(velcenter, bp->vec, obp->vec);
VecSubf(dvel,velcenter,bp->vec);
- VecMulf(dvel,sb->nodemass);
+ VecMulf(dvel,bp->mass);
Vec3PlusStVec(bp->force,f*(1.0f-sb->balldamp),def);
Vec3PlusStVec(bp->force,sb->balldamp,dvel);
/* exploit force(a,b) == -force(b,a) part2/2 */
VecSubf(dvel,velcenter,obp->vec);
- VecMulf(dvel,sb->nodemass);
+ VecMulf(dvel,bp->mass);
Vec3PlusStVec(obp->force,sb->balldamp,dvel);
Vec3PlusStVec(obp->force,-f*(1.0f-sb->balldamp),def);
@@ -2237,7 +2240,7 @@ static int _softbody_calc_forces_slice_in_a_thread(Scene *scene, Object *ob, flo
/* gravitation */
if (sb){
float gravity = sb->grav * sb_grav_force_scale(ob);
- bp->force[2]-= gravity*sb->nodemass; /* individual mass of node here */
+ bp->force[2]-= gravity*bp->mass; /* individual mass of node here */
}
/* particle field & vortex */
@@ -2549,7 +2552,7 @@ static void softbody_calc_forces(Scene *scene, Object *ob, float forcetime, floa
VecMidf(velcenter, bp->vec, obp->vec);
VecSubf(dvel,velcenter,bp->vec);
- VecMulf(dvel,sb->nodemass);
+ VecMulf(dvel,bp->mass);
Vec3PlusStVec(bp->force,f*(1.0f-sb->balldamp),def);
Vec3PlusStVec(bp->force,sb->balldamp,dvel);
@@ -2580,7 +2583,7 @@ static void softbody_calc_forces(Scene *scene, Object *ob, float forcetime, floa
/* exploit force(a,b) == -force(b,a) part2/2 */
VecSubf(dvel,velcenter,obp->vec);
- VecMulf(dvel,sb->nodemass);
+ VecMulf(dvel,(bp->mass+obp->mass)/2.0f);
Vec3PlusStVec(obp->force,sb->balldamp,dvel);
Vec3PlusStVec(obp->force,-f*(1.0f-sb->balldamp),def);
@@ -2640,8 +2643,7 @@ static void softbody_calc_forces(Scene *scene, Object *ob, float forcetime, floa
/* gravitation */
- bp->force[2]-= gravity*sb->nodemass; /* individual mass of node here */
- //bp->force[1]-= gravity*sb->nodemass; /* individual mass of node here */
+ bp->force[2]-= gravity*bp->mass; /* individual mass of node here */
/* particle field & vortex */
@@ -2850,11 +2852,20 @@ static void softbody_apply_forces(Object *ob, float forcetime, int mode, float *
aabbmin[0]=aabbmin[1]=aabbmin[2] = 1e20f;
aabbmax[0]=aabbmax[1]=aabbmax[2] = -1e20f;
+ /* old one with homogenous masses */
/* claim a minimum mass for vertex */
+ /*
if (sb->nodemass > 0.009999f) timeovermass = forcetime/sb->nodemass;
else timeovermass = forcetime/0.009999f;
+ */
for(a=sb->totpoint, bp= sb->bpoint; a>0; a--, bp++) {
+/* now we have individual masses */
+/* claim a minimum mass for vertex */
+ if (bp->mass > 0.009999f) timeovermass = forcetime/bp->mass;
+ else timeovermass = forcetime/0.009999f;
+
+
if(bp->goal < SOFTGOALSNAP){
/* this makes t~ = t */
if(mid_flags & MID_PRESERVE) VECCOPY(dx,bp->vec);
@@ -3228,10 +3239,36 @@ static void mesh_to_softbody(Scene *scene, Object *ob)
/* to proove the concept
this would enable per vertex *mass painting*
- strcpy(name,"SOFTMASS");
- error = get_scalar_from_named_vertexgroup(ob,name, a,&temp);
- if (!error) bp->mass = temp * ob->rangeofmass;
*/
+ /* first set the default */
+ bp->mass = sb->nodemass;
+
+ if (sb->namedVG_Mass[0])
+ {
+ int grp= get_named_vertexgroup_num (ob,sb->namedVG_Mass);
+ /* printf("VGN %s %d \n",sb->namedVG_Mass,grp); */
+ if(grp > -1){
+ get_scalar_from_vertexgroup(ob, a,(short) (grp), &bp->mass);
+ bp->mass = bp->mass * sb->nodemass;
+ /* printf("bp->mass %f \n",bp->mass); */
+
+ }
+ }
+ /* first set the default */
+ bp->springweight = 1.0f;
+
+ if (sb->namedVG_Spring_K[0])
+ {
+ int grp= get_named_vertexgroup_num (ob,sb->namedVG_Spring_K);
+ //printf("VGN %s %d \n",sb->namedVG_Spring_K,grp);
+ if(grp > -1){
+ get_scalar_from_vertexgroup(ob, a,(short) (grp), &bp->springweight);
+ //printf("bp->springweight %f \n",bp->springweight);
+
+ }
+ }
+
+
}
/* but we only optionally add body edge springs */
diff --git a/source/blender/blenkernel/intern/texture.c b/source/blender/blenkernel/intern/texture.c
index 66f7fe8a44b..eeffbfe5ef6 100644
--- a/source/blender/blenkernel/intern/texture.c
+++ b/source/blender/blenkernel/intern/texture.c
@@ -435,12 +435,15 @@ void default_tex(Tex *tex)
VarStruct *varstr;
int a;
+ tex->type= TEX_CLOUDS;
tex->stype= 0;
tex->flag= TEX_CHECKER_ODD;
- tex->imaflag= TEX_INTERPOL+TEX_MIPMAP+TEX_USEALPHA;
+ tex->imaflag= TEX_INTERPOL|TEX_MIPMAP|TEX_USEALPHA;
tex->extend= TEX_REPEAT;
tex->cropxmin= tex->cropymin= 0.0;
tex->cropxmax= tex->cropymax= 1.0;
+ tex->texfilter = TXF_EWA;
+ tex->afmax = 8;
tex->xrepeat= tex->yrepeat= 1;
tex->fie_ima= 2;
tex->sfra= 1;
@@ -531,7 +534,7 @@ void default_mtex(MTex *mtex)
mtex->size[1]= 1.0;
mtex->size[2]= 1.0;
mtex->tex= 0;
- mtex->texflag= 0;
+ mtex->texflag= MTEX_NEW_BUMP;
mtex->colormodel= 0;
mtex->r= 1.0;
mtex->g= 0.0;
@@ -540,7 +543,7 @@ void default_mtex(MTex *mtex)
mtex->def_var= 1.0;
mtex->blendtype= MTEX_BLEND;
mtex->colfac= 1.0;
- mtex->norfac= 0.5;
+ mtex->norfac= 1.0;
mtex->varfac= 1.0;
mtex->dispfac=0.2;
mtex->normapspace= MTEX_NSPACE_TANGENT;
@@ -784,7 +787,7 @@ Tex *give_current_texture(Object *ob, int act)
if(act>ob->totcol) act= ob->totcol;
else if(act==0) act= 1;
- if( BTST(ob->colbits, act-1) ) { /* in object */
+ if(ob->matbits[act-1]) { /* in object */
ma= ob->mat[act-1];
}
else { /* in data */
diff --git a/source/blender/blenkernel/intern/world.c b/source/blender/blenkernel/intern/world.c
index 7fe129ed6fc..f795c147f54 100644
--- a/source/blender/blenkernel/intern/world.c
+++ b/source/blender/blenkernel/intern/world.c
@@ -36,7 +36,6 @@
#include "DNA_world_types.h"
#include "DNA_texture_types.h"
-#include "DNA_scriptlink_types.h"
#include "DNA_scene_types.h"
#include "DNA_object_types.h"
#include "DNA_camera_types.h"
@@ -66,10 +65,7 @@ void free_world(World *wrld)
{
MTex *mtex;
int a;
-
-#ifndef DISABLE_PYTHON
- BPY_free_scriptlink(&wrld->scriptlink);
-#endif
+
for(a=0; a<MAX_MTEX; a++) {
mtex= wrld->mtex[a];
if(mtex && mtex->tex) mtex->tex->id.us--;
@@ -94,7 +90,6 @@ World *add_world(char *name)
wrld->skytype= WO_SKYBLEND;
wrld->stardist= 15.0f;
wrld->starsize= 2.0f;
- wrld->gravity= 9.8f;
wrld->exp= 0.0f;
wrld->exposure=wrld->range= 1.0f;
@@ -106,14 +101,7 @@ World *add_world(char *name)
wrld->ao_samp_method = WO_AOSAMP_HAMMERSLEY;
wrld->ao_approx_error= 0.25f;
- wrld->physicsEngine= WOPHY_BULLET;//WOPHY_SUMO; Bullet by default
- wrld->mode = WO_DBVT_CULLING; // DBVT culling by default
- wrld->occlusionRes = 128;
wrld->preview = NULL;
- wrld->ticrate = 60;
- wrld->maxlogicstep = 5;
- wrld->physubstep = 1;
- wrld->maxphystep = 5;
return wrld;
}
@@ -134,9 +122,6 @@ World *copy_world(World *wrld)
}
if (wrld->preview) wrldn->preview = BKE_previewimg_copy(wrld->preview);
-#ifndef DISABLE_PYTHON
- BPY_copy_scriptlink(&wrld->scriptlink);
-#endif
#if 0 // XXX old animation system
id_us_plus((ID *)wrldn->ipo);
diff --git a/source/blender/blenkernel/intern/writeavi.c b/source/blender/blenkernel/intern/writeavi.c
index f84bd690347..cfbe3f629d6 100644
--- a/source/blender/blenkernel/intern/writeavi.c
+++ b/source/blender/blenkernel/intern/writeavi.c
@@ -40,6 +40,7 @@
#include "BLI_blenlib.h"
#include "BKE_global.h"
+#include "BKE_utildefines.h"
#include "BKE_writeavi.h"
#include "AVI_avi.h"
@@ -87,7 +88,7 @@ bMovieHandle *BKE_get_movie_handle(int imtype)
}
#endif
#ifdef WITH_FFMPEG
- if (imtype == R_FFMPEG) {
+ if (ELEM4(imtype, R_FFMPEG, R_H264, R_XVID, R_THEORA)) {
mh.start_movie = start_ffmpeg;
mh.append_movie = append_ffmpeg;
mh.end_movie = end_ffmpeg;
diff --git a/source/blender/blenkernel/intern/writeffmpeg.c b/source/blender/blenkernel/intern/writeffmpeg.c
index 25dc6fa2fd7..5e3c8024524 100644
--- a/source/blender/blenkernel/intern/writeffmpeg.c
+++ b/source/blender/blenkernel/intern/writeffmpeg.c
@@ -937,5 +937,322 @@ void end_ffmpeg(void)
img_convert_ctx = 0;
}
}
+
+/* properties */
+
+void ffmpeg_property_del(RenderData *rd, void *type, void *prop_)
+{
+ struct IDProperty *prop = (struct IDProperty *) prop_;
+ IDProperty * group;
+
+ if (!rd->ffcodecdata.properties) {
+ return;
+ }
+
+ group = IDP_GetPropertyFromGroup(
+ rd->ffcodecdata.properties, (char*) type);
+ if (group && prop) {
+ IDP_RemFromGroup(group, prop);
+ IDP_FreeProperty(prop);
+ MEM_freeN(prop);
+ }
+}
+
+IDProperty *ffmpeg_property_add(RenderData *rd, char * type, int opt_index, int parent_index)
+{
+ AVCodecContext c;
+ const AVOption * o;
+ const AVOption * parent;
+ IDProperty * group;
+ IDProperty * prop;
+ IDPropertyTemplate val;
+ int idp_type;
+ char name[256];
+
+ avcodec_get_context_defaults(&c);
+
+ o = c.av_class->option + opt_index;
+ parent = c.av_class->option + parent_index;
+
+ if (!rd->ffcodecdata.properties) {
+ IDPropertyTemplate val;
+
+ rd->ffcodecdata.properties
+ = IDP_New(IDP_GROUP, val, "ffmpeg");
+ }
+
+ group = IDP_GetPropertyFromGroup(
+ rd->ffcodecdata.properties, (char*) type);
+
+ if (!group) {
+ IDPropertyTemplate val;
+
+ group = IDP_New(IDP_GROUP, val, (char*) type);
+ IDP_AddToGroup(rd->ffcodecdata.properties, group);
+ }
+
+ if (parent_index) {
+ sprintf(name, "%s:%s", parent->name, o->name);
+ } else {
+ strcpy(name, o->name);
+ }
+
+ fprintf(stderr, "ffmpeg_property_add: %s %d %d %s\n",
+ type, parent_index, opt_index, name);
+
+ prop = IDP_GetPropertyFromGroup(group, name);
+ if (prop) {
+ return prop;
+ }
+
+ switch (o->type) {
+ case FF_OPT_TYPE_INT:
+ case FF_OPT_TYPE_INT64:
+ val.i = o->default_val;
+ idp_type = IDP_INT;
+ break;
+ case FF_OPT_TYPE_DOUBLE:
+ case FF_OPT_TYPE_FLOAT:
+ val.f = o->default_val;
+ idp_type = IDP_FLOAT;
+ break;
+ case FF_OPT_TYPE_STRING:
+ val.str = " ";
+ idp_type = IDP_STRING;
+ break;
+ case FF_OPT_TYPE_CONST:
+ val.i = 1;
+ idp_type = IDP_INT;
+ break;
+ default:
+ return NULL;
+ }
+ prop = IDP_New(idp_type, val, name);
+ IDP_AddToGroup(group, prop);
+ return prop;
+}
+
+/* not all versions of ffmpeg include that, so here we go ... */
+
+static const AVOption *my_av_find_opt(void *v, const char *name,
+ const char *unit, int mask, int flags){
+ AVClass *c= *(AVClass**)v;
+ const AVOption *o= c->option;
+
+ for(;o && o->name; o++){
+ if(!strcmp(o->name, name) &&
+ (!unit || (o->unit && !strcmp(o->unit, unit))) &&
+ (o->flags & mask) == flags )
+ return o;
+ }
+ return NULL;
+}
+
+int ffmpeg_property_add_string(RenderData *rd, const char * type, const char * str)
+{
+ AVCodecContext c;
+ const AVOption * o = 0;
+ const AVOption * p = 0;
+ char name_[128];
+ char * name;
+ char * param;
+ IDProperty * prop;
+
+ avcodec_get_context_defaults(&c);
+
+ strncpy(name_, str, 128);
+
+ name = name_;
+ while (*name == ' ') name++;
+
+ param = strchr(name, ':');
+
+ if (!param) {
+ param = strchr(name, ' ');
+ }
+ if (param) {
+ *param++ = 0;
+ while (*param == ' ') param++;
+ }
+
+ o = my_av_find_opt(&c, name, NULL, 0, 0);
+ if (!o) {
+ return 0;
+ }
+ if (param && o->type == FF_OPT_TYPE_CONST) {
+ return 0;
+ }
+ if (param && o->type != FF_OPT_TYPE_CONST && o->unit) {
+ p = my_av_find_opt(&c, param, o->unit, 0, 0);
+ prop = ffmpeg_property_add(rd,
+ (char*) type, p - c.av_class->option,
+ o - c.av_class->option);
+ } else {
+ prop = ffmpeg_property_add(rd,
+ (char*) type, o - c.av_class->option, 0);
+ }
+
+
+ if (!prop) {
+ return 0;
+ }
+
+ if (param && !p) {
+ switch (prop->type) {
+ case IDP_INT:
+ IDP_Int(prop) = atoi(param);
+ break;
+ case IDP_FLOAT:
+ IDP_Float(prop) = atof(param);
+ break;
+ case IDP_STRING:
+ strncpy(IDP_String(prop), param, prop->len);
+ break;
+ }
+ }
+ return 1;
+}
+
+void ffmpeg_set_preset(RenderData *rd, int preset)
+{
+ int isntsc = (rd->frs_sec != 25);
+
+ switch (preset) {
+ case FFMPEG_PRESET_VCD:
+ rd->ffcodecdata.type = FFMPEG_MPEG1;
+ rd->ffcodecdata.video_bitrate = 1150;
+ rd->xsch = 352;
+ rd->ysch = isntsc ? 240 : 288;
+ rd->ffcodecdata.gop_size = isntsc ? 18 : 15;
+ rd->ffcodecdata.rc_max_rate = 1150;
+ rd->ffcodecdata.rc_min_rate = 1150;
+ rd->ffcodecdata.rc_buffer_size = 40*8;
+ rd->ffcodecdata.mux_packet_size = 2324;
+ rd->ffcodecdata.mux_rate = 2352 * 75 * 8;
+ break;
+
+ case FFMPEG_PRESET_SVCD:
+ rd->ffcodecdata.type = FFMPEG_MPEG2;
+ rd->ffcodecdata.video_bitrate = 2040;
+ rd->xsch = 480;
+ rd->ysch = isntsc ? 480 : 576;
+ rd->ffcodecdata.gop_size = isntsc ? 18 : 15;
+ rd->ffcodecdata.rc_max_rate = 2516;
+ rd->ffcodecdata.rc_min_rate = 0;
+ rd->ffcodecdata.rc_buffer_size = 224*8;
+ rd->ffcodecdata.mux_packet_size = 2324;
+ rd->ffcodecdata.mux_rate = 0;
+ break;
+
+ case FFMPEG_PRESET_DVD:
+ rd->ffcodecdata.type = FFMPEG_MPEG2;
+ rd->ffcodecdata.video_bitrate = 6000;
+ rd->xsch = 720;
+ rd->ysch = isntsc ? 480 : 576;
+ rd->ffcodecdata.gop_size = isntsc ? 18 : 15;
+ rd->ffcodecdata.rc_max_rate = 9000;
+ rd->ffcodecdata.rc_min_rate = 0;
+ rd->ffcodecdata.rc_buffer_size = 224*8;
+ rd->ffcodecdata.mux_packet_size = 2048;
+ rd->ffcodecdata.mux_rate = 10080000;
+ break;
+
+ case FFMPEG_PRESET_DV:
+ rd->ffcodecdata.type = FFMPEG_DV;
+ rd->xsch = 720;
+ rd->ysch = isntsc ? 480 : 576;
+ break;
+
+ case FFMPEG_PRESET_H264:
+ rd->ffcodecdata.type = FFMPEG_AVI;
+ rd->ffcodecdata.codec = CODEC_ID_H264;
+ rd->ffcodecdata.video_bitrate = 6000;
+ rd->ffcodecdata.gop_size = isntsc ? 18 : 15;
+ rd->ffcodecdata.rc_max_rate = 9000;
+ rd->ffcodecdata.rc_min_rate = 0;
+ rd->ffcodecdata.rc_buffer_size = 224*8;
+ rd->ffcodecdata.mux_packet_size = 2048;
+ rd->ffcodecdata.mux_rate = 10080000;
+
+ ffmpeg_property_add_string(rd, "video", "coder:vlc");
+ ffmpeg_property_add_string(rd, "video", "flags:loop");
+ ffmpeg_property_add_string(rd, "video", "cmp:chroma");
+ ffmpeg_property_add_string(rd, "video", "partitions:parti4x4");
+ ffmpeg_property_add_string(rd, "video", "partitions:partp8x8");
+ ffmpeg_property_add_string(rd, "video", "partitions:partb8x8");
+ ffmpeg_property_add_string(rd, "video", "me:hex");
+ ffmpeg_property_add_string(rd, "video", "subq:5");
+ ffmpeg_property_add_string(rd, "video", "me_range:16");
+ ffmpeg_property_add_string(rd, "video", "keyint_min:25");
+ ffmpeg_property_add_string(rd, "video", "sc_threshold:40");
+ ffmpeg_property_add_string(rd, "video", "i_qfactor:0.71");
+ ffmpeg_property_add_string(rd, "video", "b_strategy:1");
+
+ break;
+
+ case FFMPEG_PRESET_THEORA:
+ case FFMPEG_PRESET_XVID:
+ if(preset == FFMPEG_PRESET_XVID) {
+ rd->ffcodecdata.type = FFMPEG_AVI;
+ rd->ffcodecdata.codec = CODEC_ID_XVID;
+ }
+ else if(preset == FFMPEG_PRESET_THEORA) {
+ rd->ffcodecdata.type = FFMPEG_OGG; // XXX broken
+ rd->ffcodecdata.codec = CODEC_ID_THEORA;
+ }
+
+ rd->ffcodecdata.video_bitrate = 6000;
+ rd->ffcodecdata.gop_size = isntsc ? 18 : 15;
+ rd->ffcodecdata.rc_max_rate = 9000;
+ rd->ffcodecdata.rc_min_rate = 0;
+ rd->ffcodecdata.rc_buffer_size = 224*8;
+ rd->ffcodecdata.mux_packet_size = 2048;
+ rd->ffcodecdata.mux_rate = 10080000;
+ break;
+
+ }
+}
+
+void ffmpeg_verify_image_type(RenderData *rd)
+{
+ int audio= 0;
+
+ if(rd->imtype == R_FFMPEG) {
+ if(rd->ffcodecdata.type <= 0 ||
+ rd->ffcodecdata.codec <= 0 ||
+ rd->ffcodecdata.audio_codec <= 0 ||
+ rd->ffcodecdata.video_bitrate <= 1) {
+
+ rd->ffcodecdata.codec = CODEC_ID_MPEG2VIDEO;
+ ffmpeg_set_preset(rd, FFMPEG_PRESET_DVD);
+ }
+
+ audio= 1;
+ }
+ else if(rd->imtype == R_H264) {
+ if(rd->ffcodecdata.codec != CODEC_ID_H264) {
+ ffmpeg_set_preset(rd, FFMPEG_PRESET_H264);
+ audio= 1;
+ }
+ }
+ else if(rd->imtype == R_XVID) {
+ if(rd->ffcodecdata.codec != CODEC_ID_XVID) {
+ ffmpeg_set_preset(rd, FFMPEG_PRESET_XVID);
+ audio= 1;
+ }
+ }
+ else if(rd->imtype == R_THEORA) {
+ if(rd->ffcodecdata.codec != CODEC_ID_THEORA) {
+ ffmpeg_set_preset(rd, FFMPEG_PRESET_THEORA);
+ audio= 1;
+ }
+ }
+
+ if(audio && rd->ffcodecdata.audio_codec <= 0) {
+ rd->ffcodecdata.audio_codec = CODEC_ID_MP2;
+ rd->ffcodecdata.audio_bitrate = 128;
+ }
+}
+
#endif
diff --git a/source/blender/blenkernel/nla_private.h b/source/blender/blenkernel/nla_private.h
new file mode 100644
index 00000000000..325798f325f
--- /dev/null
+++ b/source/blender/blenkernel/nla_private.h
@@ -0,0 +1,85 @@
+/**
+ * $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
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Joshua Leung (full recode)
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef NLA_PRIVATE
+#define NLA_PRIVATE
+
+/* --------------- NLA Evaluation DataTypes ----------------------- */
+
+/* used for list of strips to accumulate at current time */
+typedef struct NlaEvalStrip {
+ struct NlaEvalStrip *next, *prev;
+
+ NlaTrack *track; /* track that this strip belongs to */
+ NlaStrip *strip; /* strip that's being used */
+
+ short track_index; /* the index of the track within the list */
+ short strip_mode; /* which end of the strip are we looking at */
+
+ float strip_time; /* time at which which strip is being evaluated */
+} NlaEvalStrip;
+
+/* NlaEvalStrip->strip_mode */
+enum {
+ /* standard evaluation */
+ NES_TIME_BEFORE = -1,
+ NES_TIME_WITHIN,
+ NES_TIME_AFTER,
+
+ /* transition-strip evaluations */
+ NES_TIME_TRANSITION_START,
+ NES_TIME_TRANSITION_END,
+} eNlaEvalStrip_StripMode;
+
+
+/* temp channel for accumulating data from NLA (avoids needing to clear all values first) */
+// TODO: maybe this will be used as the 'cache' stuff needed for editable values too?
+typedef struct NlaEvalChannel {
+ struct NlaEvalChannel *next, *prev;
+
+ PointerRNA ptr; /* pointer to struct containing property to use */
+ PropertyRNA *prop; /* RNA-property type to use (should be in the struct given) */
+ int index; /* array index (where applicable) */
+
+ float value; /* value of this channel */
+} NlaEvalChannel;
+
+/* --------------- NLA Functions (not to be used as a proper API) ----------------------- */
+
+/* convert from strip time <-> global time */
+float nlastrip_get_frame(NlaStrip *strip, float cframe, short mode);
+
+/* --------------- NLA Evaluation (very-private stuff) ----------------------- */
+/* these functions are only defined here to avoid problems with the order in which they get defined... */
+
+NlaEvalStrip *nlastrips_ctime_get_strip(ListBase *list, ListBase *strips, short index, float ctime);
+void nlastrip_evaluate(PointerRNA *ptr, ListBase *channels, ListBase *modifiers, NlaEvalStrip *nes);
+void nladata_flush_channels(ListBase *channels);
+
+#endif // NLA_PRIVATE