Particle merge: svn merge -r 12653:12664 https://svn.blender.org/svnroot/bf-blender...
authorDaniel Genrich <daniel.genrich@gmx.net>
Mon, 26 Nov 2007 23:11:07 +0000 (23:11 +0000)
committerDaniel Genrich <daniel.genrich@gmx.net>
Mon, 26 Nov 2007 23:11:07 +0000 (23:11 +0000)
108 files changed:
projectfiles_vc7/blender/blenkernel/BKE_blenkernel.vcproj
projectfiles_vc7/blender/src/BL_src.vcproj
release/datafiles/blenderbuttons
release/datafiles/preview.blend
source/blender/blenkernel/BKE_DerivedMesh.h
source/blender/blenkernel/BKE_bad_level_calls.h
source/blender/blenkernel/BKE_blender.h
source/blender/blenkernel/BKE_cloth.h
source/blender/blenkernel/BKE_displist.h
source/blender/blenkernel/BKE_global.h
source/blender/blenkernel/BKE_main.h
source/blender/blenkernel/BKE_modifier.h
source/blender/blenkernel/BKE_particle.h [new file with mode: 0644]
source/blender/blenkernel/BKE_pointcache.h
source/blender/blenkernel/BKE_softbody.h
source/blender/blenkernel/BKE_utildefines.h
source/blender/blenkernel/bad_level_call_stubs/stubs.c
source/blender/blenkernel/intern/DerivedMesh.c
source/blender/blenkernel/intern/anim.c
source/blender/blenkernel/intern/blender.c
source/blender/blenkernel/intern/cdderivedmesh.c
source/blender/blenkernel/intern/cloth.c
source/blender/blenkernel/intern/customdata.c
source/blender/blenkernel/intern/depsgraph.c
source/blender/blenkernel/intern/displist.c
source/blender/blenkernel/intern/effect.c
source/blender/blenkernel/intern/ipo.c
source/blender/blenkernel/intern/library.c
source/blender/blenkernel/intern/modifier.c
source/blender/blenkernel/intern/object.c
source/blender/blenkernel/intern/particle.c [new file with mode: 0644]
source/blender/blenkernel/intern/particle_system.c [new file with mode: 0644]
source/blender/blenkernel/intern/pointcache.c
source/blender/blenkernel/intern/scene.c
source/blender/blenkernel/intern/softbody.c
source/blender/blenlib/BLI_arithb.h
source/blender/blenlib/BLI_kdtree.h [new file with mode: 0644]
source/blender/blenlib/intern/BLI_kdtree.c [new file with mode: 0644]
source/blender/blenlib/intern/arithb.c
source/blender/blenlib/intern/threads.c
source/blender/blenloader/intern/readfile.c
source/blender/blenloader/intern/writefile.c
source/blender/include/BDR_editobject.h
source/blender/include/BIF_butspace.h
source/blender/include/BIF_editparticle.h [new file with mode: 0644]
source/blender/include/BIF_editsima.h
source/blender/include/BIF_editview.h
source/blender/include/BIF_meshtools.h
source/blender/include/BIF_resources.h
source/blender/include/BIF_transform.h
source/blender/include/BSE_editipo.h
source/blender/include/blendef.h
source/blender/include/butspace.h
source/blender/include/transform.h
source/blender/makesdna/DNA_ID.h
source/blender/makesdna/DNA_customdata_types.h
source/blender/makesdna/DNA_ipo_types.h
source/blender/makesdna/DNA_material_types.h
source/blender/makesdna/DNA_meshdata_types.h
source/blender/makesdna/DNA_modifier_types.h
source/blender/makesdna/DNA_object_force.h
source/blender/makesdna/DNA_object_types.h
source/blender/makesdna/DNA_particle_types.h [new file with mode: 0644]
source/blender/makesdna/DNA_scene_types.h
source/blender/makesdna/DNA_texture_types.h
source/blender/makesdna/intern/makesdna.c
source/blender/render/extern/include/RE_render_ext.h
source/blender/render/intern/include/renderdatabase.h
source/blender/render/intern/source/convertblender.c
source/blender/render/intern/source/renderdatabase.c
source/blender/render/intern/source/texture.c
source/blender/src/blenderbuttons.c
source/blender/src/butspace.c
source/blender/src/buttons_editing.c
source/blender/src/buttons_object.c
source/blender/src/buttons_shading.c
source/blender/src/drawimage.c
source/blender/src/drawobject.c
source/blender/src/drawscene.c
source/blender/src/drawview.c
source/blender/src/edit.c
source/blender/src/editface.c
source/blender/src/editipo.c
source/blender/src/editipo_lib.c
source/blender/src/editmesh_tools.c
source/blender/src/editobject.c
source/blender/src/editparticle.c [new file with mode: 0644]
source/blender/src/editscreen.c
source/blender/src/editsima.c
source/blender/src/editview.c
source/blender/src/header_buttonswin.c
source/blender/src/header_info.c
source/blender/src/header_ipo.c
source/blender/src/header_view3d.c
source/blender/src/headerbuttons.c
source/blender/src/meshtools.c
source/blender/src/parametrizer.c
source/blender/src/preview.blend.c
source/blender/src/sequence.c
source/blender/src/space.c
source/blender/src/toets.c
source/blender/src/transform.c
source/blender/src/transform_constraints.c
source/blender/src/transform_conversions.c
source/blender/src/transform_generics.c
source/blender/src/transform_manipulator.c
source/blender/src/unwrapper.c
source/blender/src/view.c

index 4e58c6617aac5ed6ea336adaef64edaaa0bf18db..8f473c85976599ee4e91c601481abe78c0bdf9c5 100644 (file)
                        <File
                                RelativePath="..\..\..\source\blender\blenkernel\intern\packedFile.c">
                        </File>
+                       <File
+                               RelativePath="..\..\..\source\blender\blenkernel\intern\particle.c">
+                       </File>
+                       <File
+                               RelativePath="..\..\..\source\blender\blenkernel\intern\particle_system.c">
+                       </File>
+                       <File
+                               RelativePath="..\..\..\source\blender\blenkernel\intern\pointcache.c">
+                       </File>
                        <File
                                RelativePath="..\..\..\source\blender\blenkernel\intern\property.c">
                        </File>
                        <File
                                RelativePath="..\..\..\source\blender\blenkernel\BKE_plugin_types.h">
                        </File>
+                       <File
+                               RelativePath="..\..\..\source\blender\blenkernel\BKE_pointcache.h">
+                       </File>
                        <File
                                RelativePath="..\..\..\source\blender\blenkernel\BKE_property.h">
                        </File>
index 685615e4b6d614c2fd4885bdf159a1cf467a0e6b..6cc8f27f3988bdd350b1f32b5a649c3519bdcab7 100644 (file)
                        <File
                                RelativePath="..\..\..\source\blender\src\editoops.c">
                        </File>
+                       <File
+                               RelativePath="..\..\..\source\blender\src\editparticle.c">
+                       </File>
                        <File
                                RelativePath="..\..\..\source\blender\src\editscreen.c">
                        </File>
                        <File
                                RelativePath="..\..\..\source\blender\include\BIF_editoops.h">
                        </File>
+                       <File
+                               RelativePath="..\..\..\source\blender\include\BIF_editparticle.h">
+                       </File>
                        <File
                                RelativePath="..\..\..\source\blender\include\BIF_editsca.h">
                        </File>
index d34acb7be0408739fc11320407a7ada337b11a48..d447b3b4f2c61f712cee19c4447627b8f29c1054 100644 (file)
Binary files a/release/datafiles/blenderbuttons and b/release/datafiles/blenderbuttons differ
index 8d67a88f679aae5ad652f665feb290e7a1b830d6..c39c26b063dbea88bbe8c418903cfba56d257a94 100644 (file)
Binary files a/release/datafiles/preview.blend and b/release/datafiles/preview.blend differ
index 1852dc72a400d24d55f95fd7b272717130192ab1..29fc1438c479bcd22ad247357584910283053edc 100644 (file)
@@ -70,6 +70,7 @@ struct DerivedMesh {
        CustomData vertData, edgeData, faceData;
        int numVertData, numEdgeData, numFaceData;
        int needsFree; /* checked on ->release, is set to 0 for cached results */
+       int deformedOnly; /* set by modifier stack if only deformed from original */
 
        /* Misc. Queries */
 
index b942add80e2364b0ee33cc2821fda754939ac4bf..7a838ff76143adc8f4e64ad02c5dd1020a0721c8 100644 (file)
@@ -231,5 +231,12 @@ struct MeshDeformModifierData;
 void harmonic_coordinates_bind(struct MeshDeformModifierData *mmd,
        float (*vertexcos)[3], int totvert, float cagemat[][4]);
 
+/* particle.c */
+struct ParticleSystem;
+
+void PE_free_particle_edit(struct ParticleSystem *psys);
+void PE_get_colors(char sel[4], char nosel[4]);
+void PE_recalc_world_cos(struct Object *ob, struct ParticleSystem *psys);
+
 #endif
 
index 55a542f51d54ab9eb30874acde34be9dea7eac40..5cd905d07ac7c8b74befef11ba63bb9e0958318c 100644 (file)
@@ -44,7 +44,7 @@ struct ListBase;
 struct MemFile;
 
 #define BLENDER_VERSION                        245
-#define BLENDER_SUBVERSION             7
+#define BLENDER_SUBVERSION             8
 
 #define BLENDER_MINVERSION             240
 #define BLENDER_MINSUBVERSION  0
index f83cf0515dfc63638e15ee9e1351aae77e262ed9..5a986119b71b4f70b6633293e1927e81043e003b 100644 (file)
 #ifndef BKE_CLOTH_H
 #define BKE_CLOTH_H
 
+#include "BKE_customdata.h"
 #include "BLI_linklist.h"
 #include "BKE_DerivedMesh.h"
+#include "BKE_object.h"
+
+#include "DNA_cloth_types.h"
 #include "DNA_customdata_types.h"
-#include "BKE_customdata.h"
 #include "DNA_meshdata_types.h"
 
 struct Object;
 struct Cloth;
 struct MFace;
 struct DerivedMesh;
+struct ClothModifierData;
 
 // this is needed for inlining behaviour
 
@@ -162,17 +166,17 @@ typedef enum
 
 
 // needed for buttons_object.c
-void cloth_clear_cache(Object *ob, ClothModifierData *clmd, float framenr);
-void cloth_free_modifier ( ClothModifierData *clmd );
+void cloth_clear_cache(struct Object *ob, struct ClothModifierData *clmd, float framenr);
+void cloth_free_modifier ( struct ClothModifierData *clmd );
 
 // needed for cloth.c
-void implicit_set_positions ( ClothModifierData *clmd );
+void implicit_set_positions ( struct ClothModifierData *clmd );
 
 // from cloth.c, needed for modifier.c
-DerivedMesh *clothModifier_do(ClothModifierData *clmd,Object *ob, DerivedMesh *dm, int useRenderParams, int isFinalCalc);
+DerivedMesh *clothModifier_do(struct ClothModifierData *clmd, struct Object *ob, struct DerivedMesh *dm, int useRenderParams, int isFinalCalc);
 
 // needed in implicit.c
-int cloth_bvh_objcollision(ClothModifierData * clmd, float step, float prevstep, float dt);
+int cloth_bvh_objcollision(struct ClothModifierData *clmd, float step, float prevstep, float dt);
 
 ////////////////////////////////////////////////
 
@@ -180,13 +184,13 @@ int cloth_bvh_objcollision(ClothModifierData * clmd, float step, float prevstep,
 /////////////////////////////////////////////////
 // cloth.c
 ////////////////////////////////////////////////
-void cloth_free_modifier ( ClothModifierData *clmd );
-void cloth_init ( ClothModifierData *clmd );
+void cloth_free_modifier ( struct ClothModifierData *clmd );
+void cloth_init ( struct ClothModifierData *clmd );
 ////////////////////////////////////////////////
 
 
 /* Typedefs for function pointers we need for solvers and collision detection. */
-typedef void ( *CM_COLLISION_SELF ) ( ClothModifierData *clmd, int step );
+typedef void ( *CM_COLLISION_SELF ) ( struct ClothModifierData *clmd, int step );
 // typedef void ( *CM_COLLISION_OBJ ) ( ClothModifierData *clmd, int step, CM_COLLISION_RESPONSE collision_response );
 
 
@@ -204,22 +208,22 @@ typedef struct
 {
        char            *name;
        CM_SOLVER_ID    id;
-       int     ( *init ) ( Object *ob, ClothModifierData *clmd );
-       int     ( *solver ) ( Object *ob, float framenr, ClothModifierData *clmd, ListBase *effectors );
-       int     ( *free ) ( ClothModifierData *clmd );
+       int     ( *init ) ( struct Object *ob, struct ClothModifierData *clmd );
+       int     ( *solver ) ( struct Object *ob, float framenr, struct ClothModifierData *clmd, struct ListBase *effectors );
+       int     ( *free ) ( struct ClothModifierData *clmd );
 }
 CM_SOLVER_DEF;
 
 
 /* new C implicit simulator */
-int implicit_init ( Object *ob, ClothModifierData *clmd );
-int implicit_free ( ClothModifierData *clmd );
-int implicit_solver ( Object *ob, float frame, ClothModifierData *clmd, ListBase *effectors );
+int implicit_init ( struct Object *ob, struct ClothModifierData *clmd );
+int implicit_free ( struct ClothModifierData *clmd );
+int implicit_solver ( struct Object *ob, float frame, struct ClothModifierData *clmd, struct ListBase *effectors );
 
 /* explicit verlet simulator */
-int verlet_init ( Object *ob, ClothModifierData *clmd );
-int verlet_free ( ClothModifierData *clmd );
-int verlet_solver ( Object *ob, float frame, ClothModifierData *clmd, ListBase *effectors );
+int verlet_init ( struct Object *ob, struct ClothModifierData *clmd );
+int verlet_free ( struct ClothModifierData *clmd );
+int verlet_solver ( struct Object *ob, float frame, struct ClothModifierData *clmd, struct ListBase *effectors );
 
 
 /* used for collisions in collision.c */
index 979ed31fb2000e09bb4313ed06ac5ed957f3534d..2dc4de3213297549f710783c18846bbcc9ebfbe6 100644 (file)
@@ -123,5 +123,7 @@ void filldisplist(struct ListBase *dispbase, struct ListBase *to);
 
 void fastshade_free_render(void);
 
+float calc_taper(struct Object *taperobj, int cur, int tot);
+
 #endif
 
index 949b6c959b952b71cf3aff873ead73095c9a9ca4..e71145e8d79d98dfb6d1f4e25d38361271d14899 100644 (file)
@@ -187,6 +187,7 @@ typedef struct Global {
 /*#endif*/
 #define G_DRAWSHARP     (1 << 28) /* draw edges with the sharp flag */
 #define G_SCULPTMODE    (1 << 29)
+#define G_PARTICLEEDIT (1 << 30)
 
 #define G_AUTOMATKEYS  (1 << 30)
 #define G_HIDDENHANDLES (1 << 31) /* used for curves only */
@@ -243,9 +244,10 @@ typedef struct Global {
 #define B_ENDIAN       0
 
 /* G.moving, signals drawing in (3d) window to denote transform */
-#define G_TRANSFORM_OBJ                1
-#define G_TRANSFORM_EDIT       2
-#define G_TRANSFORM_MANIP      4
+#define G_TRANSFORM_OBJ                        1
+#define G_TRANSFORM_EDIT               2
+#define G_TRANSFORM_MANIP              4
+#define G_TRANSFORM_PARTICLE   8
 
 /* G.special1 */
 
index 6e0f2fdb284536c9131a8e1977057f4a69ac76ee..2cfa1dc5cc41fb792f5828e6eddfb736db3443dc 100644 (file)
@@ -78,6 +78,7 @@ typedef struct Main {
        ListBase action;
        ListBase nodetree;
        ListBase brush;
+       ListBase particle;
 } Main;
 
 
index 644c3dd32f40db36ceb8c8e4eb56a822007ea8ad..48e083bbf9b47f322171690d47cd40f8513ea124 100644 (file)
@@ -59,6 +59,12 @@ typedef enum {
 
        eModifierTypeType_Constructive,
        eModifierTypeType_Nonconstructive,
+
+       /* both deformVerts & applyModifier are valid calls
+        * used for particles modifier that doesn't actually modify the object
+        * unless it's a mesh and can be exploded -> curve can also emit particles
+        */
+       eModifierTypeType_DeformOrConstruct
 } ModifierTypeType;
 
 typedef enum {
@@ -81,8 +87,8 @@ typedef enum {
        eModifierTypeFlag_RequiresOriginalData = (1<<5),
 } ModifierTypeFlag;
 
-typedef void (*ObjectWalkFunc)(void *userData, Object *ob, Object **obpoin);
-typedef void (*IDWalkFunc)(void *userData, Object *ob, ID **idpoin);
+typedef void (*ObjectWalkFunc)(void *userData, struct Object *ob, struct Object **obpoin);
+typedef void (*IDWalkFunc)(void *userData, struct Object *ob, struct ID **idpoin);
 
 typedef struct ModifierTypeInfo {
        /* The user visible name for this modifier */
@@ -278,11 +284,15 @@ int           modifiers_getCageIndex(struct Object *ob,
 
 int           modifiers_isSoftbodyEnabled(struct Object *ob);
 struct ClothModifierData *modifiers_isClothEnabled(Object *ob);
+int           modifiers_isParticleEnabled(struct Object *ob);
+
 struct Object *modifiers_isDeformedByArmature(struct Object *ob);
 struct Object *modifiers_isDeformedByLattice(struct Object *ob);
 int           modifiers_usesArmature(struct Object *ob, struct bArmature *arm);
 int           modifiers_isDeformed(struct Object *ob);
 
+int           modifiers_indexInObject(struct Object *ob, struct ModifierData *md);
+
 /* Calculates and returns a linked list of CustomDataMasks indicating the
  * data required by each modifier in the stack pointed to by md for correct
  * evaluation, assuming the data indicated by dataMask is required at the
diff --git a/source/blender/blenkernel/BKE_particle.h b/source/blender/blenkernel/BKE_particle.h
new file mode 100644 (file)
index 0000000..afed219
--- /dev/null
@@ -0,0 +1,254 @@
+/* BKE_particle.h
+ *
+ *
+ * $Id: BKE_particle.h $
+ *
+ * ***** BEGIN GPL/BL DUAL 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. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License.  See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * 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) 2007 by Janne Karhu.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef BKE_PARTICLE_H
+#define BKE_PARTICLE_H
+
+#include "DNA_particle_types.h"
+#include "DNA_object_types.h"
+
+struct ParticleSystemModifierData;
+struct ParticleSystem;
+struct ParticleKey;
+struct HairKey;
+
+struct Main;
+struct Group;
+struct Object;
+struct DerivedMesh;
+struct ModifierData;
+struct MTFace;
+struct MFace;
+struct MVert;
+struct IpoCurve;
+struct LinkNode;
+struct KDTree;
+
+typedef struct ParticleEffectorCache {
+       struct ParticleEffectorCache *next, *prev;
+       struct Object *ob;
+       
+       /* precalculated variables for guides */
+       float firstloc[4], firstdir[3];
+       float *distances;
+       float *locations;
+       /* precalculated variables for deflection */
+       float ob_minmax[6];
+       float *face_minmax;
+       float *vert_cos;
+       /* precalculated variables for boids */
+       struct KDTree *tree;
+
+       short type, psys_nbr;
+       
+       struct Object obcopy;   /* for restoring transformation data */
+} ParticleEffectorCache;
+
+typedef struct ParticleReactEvent {
+       struct ParticleReactEvent *next, *prev;
+       int event, pa_num;
+       Object *ob;
+       struct ParticleSystem *psys;
+       struct ParticleKey state;
+
+       float time, size;
+}ParticleReactEvent;
+
+typedef struct ParticleTexture{
+       float ivel;                                             /* used in reset */
+       float time, life, exist, size;  /* used in init */
+       float pvel[3];                                  /* used in physics */
+       float length, clump, kink;              /* 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];
+       float length2;
+} ParticleSeam;
+
+typedef struct ParticleCacheKey{
+       float co[3];
+       float vel[3];
+       float rot[4];
+       float col[3];
+       int steps;
+} ParticleCacheKey;
+
+typedef struct ParticleEditKey{
+       float *co;
+       float *vel;
+       float *rot;
+       float *time;
+
+       float world_co[3];
+       float length;
+       short flag;
+} ParticleEditKey;
+
+typedef struct ParticleUndo {
+       struct ParticleUndo *next, *prev;
+       struct ParticleEditKey **keys;
+       struct KDTree *emitter_field;
+       struct ParticleData *particles;
+       float *emitter_cosnos;
+       int totpart, totkeys;
+       char name[64];
+} ParticleUndo;
+
+typedef struct ParticleEdit{
+       ListBase undo;
+       struct ParticleUndo *curundo;
+       struct KDTree *emitter_field;
+       ParticleEditKey **keys;
+       int *mirror_cache;
+       float *emitter_cosnos;
+
+       int totkeys;
+} ParticleEdit;
+
+/* ----------- functions needed outside particlesystem ---------------- */
+/* particle.c */
+int count_particles(struct ParticleSystem *psys);
+int count_particles_mod(struct ParticleSystem *psys, int totgr, int cur);
+int psys_count_keys(struct ParticleSystem *psys);
+char *psys_menu_string(struct Object *ob, int for_sb);
+
+struct ParticleSystem *psys_get_current(struct Object *ob);
+short psys_get_current_num(struct Object *ob);
+//struct ParticleSystem *psys_get(struct Object *ob, int index);
+struct ParticleData *psys_get_selected_particle(struct ParticleSystem *psys, int *index);
+struct ParticleKey *psys_get_selected_key(struct ParticleSystem *psys, int pa_index, int *key_index);
+void psys_change_act(void *ob_v, void *act_v);
+struct Object *psys_get_lattice(struct Object *ob, struct ParticleSystem *psys);
+void psys_disable_all(struct Object *ob);
+void psys_enable_all(struct Object *ob);
+int psys_ob_has_hair(struct Object *ob);
+int psys_in_edit_mode(struct ParticleSystem *psys);
+
+void psys_free_settings(struct ParticleSettings *part);
+void free_child_path_cache(struct ParticleSystem *psys);
+void psys_free_path_cache(struct ParticleSystem *psys);
+void free_hair(struct ParticleSystem *psys);
+void free_keyed_keys(struct ParticleSystem *psys);
+void psys_free(struct Object * ob, struct ParticleSystem * psys);
+
+void clear_particles_from_cache(struct Object *ob, struct ParticleSystem *psys, int cfra);
+//void psys_remove_from_particle_list(struct Object *ob, short nbr, struct ParticleSystem *psys);
+
+void psys_interpolate_uvs(struct MTFace *tface, int quad, float *uv, float *uvco);
+
+void copy_particle_key(struct ParticleKey *to, struct ParticleKey *from, int time);
+
+void psys_particle_on_emitter(struct Object *ob, struct ParticleSystemModifierData *psmd, int distr, int index, int index_dmcache, float *fuv, float foffset, float *vec, float *nor, float *utan, float *vtan);
+struct ParticleSystemModifierData *psys_get_modifier(struct Object *ob, struct ParticleSystem *psys);
+
+struct ParticleSettings *psys_new_settings(char *name, struct Main *main);
+struct ParticleSettings *psys_copy_settings(struct ParticleSettings *part);
+void psys_flush_settings(struct ParticleSettings *part, int event, int hair_recalc);
+
+void psys_find_parents(struct Object *ob, struct ParticleSystemModifierData *psmd, struct ParticleSystem *psys);
+
+void psys_cache_paths(struct Object *ob, struct ParticleSystem *psys, float cfra, int editupdate);
+void psys_cache_child_paths(struct Object *ob, struct ParticleSystem *psys, float cfra, int editupdate);
+int do_guide(struct ParticleKey *state, int pa_num, float time, struct ListBase *lb);
+float psys_get_size(struct Object *ob, struct Material *ma, struct ParticleSystemModifierData *psmd, struct IpoCurve *icu_size, struct ParticleSystem *psys, struct ParticleSettings *part, struct ParticleData *pa, float *vg_size);
+float psys_get_timestep(struct ParticleSettings *part);
+float psys_get_child_time(struct ParticleSystem *psys, int child_nbr, float cfra);
+float psys_get_child_size(struct ParticleSystem *psys, int child_nbr, float cfra, float *pa_time);
+void psys_get_particle_on_path(struct Object *ob, struct ParticleSystem *psys, int pa_num, struct ParticleKey *state, int vel);
+int psys_get_particle_state(struct Object *ob, struct ParticleSystem *psys, int p, struct ParticleKey *state, int always);
+
+/* particle_system.c */
+int 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 Object *obsrc, struct Group *group, struct ParticleSystem *psys);
+void psys_end_effectors(struct ParticleSystem *psys);
+
+void particle_system_update(struct Object *ob, struct ParticleSystem *psys);
+
+/* ----------- functions needed only inside particlesystem ------------ */
+/* particle.c */
+void psys_key_to_object(struct Object *ob, struct ParticleKey *key, float imat[][4]);
+//void psys_key_to_geometry(struct DerivedMesh *dm, struct ParticleData *pa, struct ParticleKey *key);
+//void psys_key_from_geometry(struct DerivedMesh *dm, struct ParticleData *pa, struct ParticleKey *key);
+//void psys_face_mat(struct DerivedMesh *dm, struct ParticleData *pa, float mat[][4]);
+void psys_vec_rot_to_face(struct DerivedMesh *dm, struct ParticleData *pa, float *vec);
+//void psys_vec_rot_from_face(struct DerivedMesh *dm, struct ParticleData *pa, float *vec);
+void psys_mat_hair_to_object(struct Object *ob, struct DerivedMesh *dm, short from, struct ParticleData *pa, float hairmat[][4]);
+void psys_mat_hair_to_global(struct Object *ob, struct DerivedMesh *dm, short from, struct ParticleData *pa, float hairmat[][4]);
+
+float *psys_cache_vgroup(struct DerivedMesh *dm, struct ParticleSystem *psys, int vgroup);
+void psys_get_texture(struct Object *ob, struct Material *ma, struct ParticleSystemModifierData *psmd, struct ParticleSystem *psys, struct ParticleData *pa, struct ParticleTexture *ptex, int event);
+void psys_interpolate_face(struct MVert *mvert, struct MFace *mface, struct MTFace *tface, float *uv, float *vec, float *nor, float *utan, float *vtan);
+float psys_interpolate_value_from_verts(struct DerivedMesh *dm, short from, int index, float *fw, float *values);
+void psys_get_from_key(struct ParticleKey *key, float *loc, float *vel, float *rot, float *time);
+
+int psys_intersect_dm(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 psys_particle_on_dm(struct Object *ob, struct DerivedMesh *dm, int from, int index, int index_dmcache, float *fw, float foffset, float *vec, float *nor, float *utan, float *vtan);
+
+/* particle_system.c */
+void initialize_particle(struct ParticleData *pa, int p, struct Object *ob, struct ParticleSystem *psys, struct ParticleSystemModifierData *psmd);
+void reset_particle(struct ParticleData *pa, struct ParticleSystem *psys, struct ParticleSystemModifierData *psmd, struct Object *ob, float dtime, float cfra, float *vg_vel, float *vg_tan, float *vg_rot);
+
+int psys_particle_dm_face_lookup(struct Object *ob, struct DerivedMesh *dm, int index, float *fw, struct LinkNode *node);
+
+/* ParticleEffectorCache->type */
+#define PSYS_EC_EFFECTOR       1
+#define PSYS_EC_DEFLECT                2
+#define PSYS_EC_PARTICLE       4
+#define PSYS_EC_REACTOR                8
+
+/* ParticleEditKey->flag */
+#define PEK_SELECT             1
+#define PEK_TO_SELECT  2
+#define PEK_TAG                        4
+#define PEK_HIDE               8
+
+/* index_dmcache */
+#define DMCACHE_NOTFOUND       -1
+#define DMCACHE_ISCHILD                -2
+
+#endif
index 9359177b4e926e23aafd1d45c683f3ccb1e22037..020b9d15417a3f9a2cd4b457e8872eb0ef119985 100644 (file)
 
 #include "DNA_ID.h"
 
-#define PTCache_EXT ".bphys"
-#define PTCache_PATH "//pointcache/"
+/* options for clearing pointcache - used for BKE_ptcache_id_clear
+ Before and after are non inclusive (they wont remove the cfra) */
+#define PTCACHE_CLEAR_ALL              0
+#define PTCACHE_CLEAR_FRAME            1
+#define PTCACHE_CLEAR_BEFORE   2
+#define PTCACHE_CLEAR_AFTER            3
 
-int            PTCache_id_filename(struct ID *id, char *filename, int cfra, int stack_index, short do_path, short do_ext);
-FILE * PTCache_id_fopen(struct ID *id, char mode, int cfra, int stack_index);
-void   PTCache_id_clear(struct ID *id, int cfra, int stack_index);
+#define PTCACHE_EXT ".bphys"
+#define PTCACHE_PATH "//pointcache/"
+
+int    BKE_ptcache_id_filename(struct ID *id, char *filename, int cfra, int stack_index, short do_path, short do_ext);
+FILE * BKE_ptcache_id_fopen(struct ID *id, char mode, int cfra, int stack_index);
+void   BKE_ptcache_id_clear(struct ID *id, char mode, int cfra, int stack_index);
 
 #endif
index 15200bf46f8b5d54e0a9e4f61199eca2f007fbac..0f58b93730a564900ed43108e3cfa42f86640e71 100644 (file)
 struct Object;
 struct SoftBody;
 
+typedef struct BodyPoint {
+       float origS[3], origE[3], origT[3], pos[3], vec[3], force[3];
+       float goal;
+       float prevpos[3], prevvec[3], prevdx[3], prevdv[3]; /* used for Heun integration */
+    int nofsprings; int *springs;
+       float choke;
+       float colball;
+       short flag;
+       char octantflag;
+} BodyPoint;
+
 /* allocates and initializes general main data */
 extern struct SoftBody *sbNew(void);
 
 /* frees internal data and softbody itself */
 extern void                            sbFree(struct SoftBody *sb);
 
+extern void                            softbody_clear_cache(struct Object *ob, float framenr);
+
 /* do one simul step, reading and writing vertex locs from given array */
 extern void                            sbObjectStep(struct Object *ob, float framnr, float (*vertexCos)[3], int numVerts);
 
index a30617a2f15946e4b18e43194000f8589f5bc714..f3f66190c31b98f020bf2feb86d5cb006b390d08 100644 (file)
 #define ELEM8(a, b, c, d, e, f, g, h, i)        ( ELEM4(a, b, c, d, e) || ELEM4(a, f, g, h, i) )
 #define ELEM9(a, b, c, d, e, f, g, h, i, j)        ( ELEM4(a, b, c, d, e) || ELEM5(a, f, g, h, i, j) )
 
+/* shift around elements */
+#define SHIFT3(type, a, b, c) { type tmp; tmp = a; a = c; c = b; b = tmp; }
+#define SHIFT4(type, a, b, c, d) { type tmp; tmp = a; a = d; d = c; c = b; b = tmp; }
+
 /* string compare */
 #define STREQ(str, a)           ( strcmp((str), (a))==0 )
 #define STREQ2(str, a, b)       ( STREQ(str, a) || STREQ(str, b) )
index a3925dfaa9a2e07853bd0d86afcdcc1f9e31a518..7e1aca3bb204eddb1002ff557894e520ad5231ba 100644 (file)
@@ -246,6 +246,8 @@ void fluidsimSettingsCopy(struct FluidsimSettings* sb) {}
 
 /*new render funcs */
 int     externtex(struct MTex *mtex, float *vec, float *tin, float *tr, float *tg, float *tb, float *ta) { return 0; }
+void texture_rgb_blend(float *in, float *tex, float *out, float fact, float facg, int blendtype) {}
+float texture_value_blend(float tex, float out, float fact, float facg, int blendtype, int flip) { return 0; }
 
 void RE_FreeRenderResult(struct RenderResult *rr) {}
 void RE_GetResultImage(struct Render *re, struct RenderResult *rr) {}
@@ -339,3 +341,8 @@ Sequence *get_forground_frame_seq(int frame){return 0;};
 void harmonic_coordinates_bind(struct MeshDeformModifierData *mmd,
        float (*vertexcos)[3], int totvert, float cagemat[][4]) {}
 
+/* particle.c */
+void PE_free_particle_edit(struct ParticleSystem *psys) {}
+void PE_get_colors(char sel[4], char nosel[4]) {}
+void PE_recalc_world_cos(struct Object *ob, struct ParticleSystem *psys) {}
+
index 4e6d4a31173569754cf0fe7fbc58cbc3ed7ae92e..5e688af14a4b6667b0d68863e722b7b06063a164 100644 (file)
@@ -55,6 +55,7 @@
 #include "DNA_view3d_types.h"
 #include "DNA_screen_types.h"
 #include "DNA_space_types.h"
+#include "DNA_particle_types.h"
 
 #include "BLI_arithb.h"
 #include "BLI_blenlib.h"
@@ -77,6 +78,7 @@
 #include "BKE_subsurf.h"
 #include "BKE_texture.h"
 #include "BKE_utildefines.h"
+#include "BKE_particle.h"
 
 #ifdef WITH_VERSE
 #include "BKE_verse.h"
@@ -1961,6 +1963,7 @@ static void mesh_calc_modifiers(Object *ob, float (*inputVertexCos)[3],
                 */
 
                if(mti->type == eModifierTypeType_OnlyDeform) {
+                       
                        /* No existing verts to deform, need to build them. */
                        if(!deformedVerts) {
                                if(dm) {
@@ -2002,9 +2005,12 @@ static void mesh_calc_modifiers(Object *ob, float (*inputVertexCos)[3],
 
                        /* set the DerivedMesh to only copy needed data */
                        DM_set_only_copy(dm, (CustomDataMask)curr->link);
-
-                       ndm = mti->applyModifier(md, ob, dm, useRenderParams,
-                                                !inputVertexCos);
+                       
+                       if(((CustomDataMask)curr->link) & CD_MASK_ORIGSPACE)
+                               if(!CustomData_has_layer(&dm->faceData, CD_ORIGSPACE))
+                                       CustomData_add_layer(&dm->faceData, CD_ORIGSPACE, CD_DEFAULT, NULL, dm->getNumFaces(dm));
+                       
+                       ndm = mti->applyModifier(md, ob, dm, useRenderParams, !inputVertexCos);
 
                        if(ndm) {
                                /* if the modifier returned a new dm, release the old one */
@@ -2182,6 +2188,10 @@ static void editmesh_calc_modifiers(DerivedMesh **cage_r,
                        /* set the DerivedMesh to only copy needed data */
                        DM_set_only_copy(dm, (CustomDataMask)curr->link);
 
+                       if(((CustomDataMask)curr->link) & CD_MASK_ORIGSPACE)
+                               if(!CustomData_has_layer(&dm->faceData, CD_ORIGSPACE))
+                                       CustomData_add_layer(&dm->faceData, CD_ORIGSPACE, CD_DEFAULT, NULL, dm->getNumFaces(dm));
+                       
                        ndm = mti->applyModifierEM(md, ob, em, dm);
 
                        if (ndm) {
@@ -2360,7 +2370,7 @@ static void mesh_build_data(Object *ob, CustomDataMask dataMask)
 
        if(ob!=G.obedit) {
                Object *obact = G.scene->basact?G.scene->basact->object:NULL;
-               int editing = (FACESEL_PAINT_TEST);
+               int editing = (FACESEL_PAINT_TEST)|(G.f & G_PARTICLEEDIT);
                int needMapping = editing && (ob==obact);
 
                if( (G.f & G_WEIGHTPAINT) && ob==obact ) {
index 32ea2b3ed2c7a31666d478a93c52abcd05362243..43168733b3ff74dbf9e44dcee8f89604380ca68d 100644 (file)
@@ -38,6 +38,7 @@
 #include "MEM_guardedalloc.h"
 #include "BLI_blenlib.h"
 #include "BLI_arithb.h"
+#include "BLI_rand.h"
 #include "DNA_listBase.h"
 
 #include "DNA_curve_types.h"
@@ -47,6 +48,7 @@
 #include "DNA_mesh_types.h"
 #include "DNA_meshdata_types.h"
 #include "DNA_object_types.h"
+#include "DNA_particle_types.h"
 #include "DNA_scene_types.h"
 #include "DNA_view3d_types.h"
 #include "DNA_vfont_types.h"
 #include "BKE_global.h"
 #include "BKE_ipo.h"
 #include "BKE_key.h"
+#include "BKE_lattice.h"
 #include "BKE_main.h"
 #include "BKE_object.h"
+#include "BKE_particle.h"
 #include "BKE_utildefines.h"
 
 #include "BKE_bad_level_calls.h"
@@ -563,134 +567,143 @@ static void face_duplilist(ListBase *lb, Scene *sce, Object *par)
        dm->release(dm);
 }
 
-
-
-static void particle_duplilist(ListBase *lb, Scene *sce, Object *par, PartEff *paf)
+static void new_particle_duplilist(ListBase *lb, Scene *sce, Object *par, ParticleSystem *psys)
 {
-       Object *ob, copyob;
-       Base *base;
-       Particle *pa;
-       float ctime, vec1[3];
-       float vec[3], tmat[4][4], mat[3][3];
-       float *q2;
-       int lay, a, counter;    /* counter is used to find in render the indexed object */
-       
-       pa= paf->keys;
-       if(pa==NULL || (G.rendering && paf->disp!=100)) {
-               build_particle_system(par);
-               pa= paf->keys;
-               if(pa==NULL) return;
-       }
-       
-       ctime= bsystem_time(par, (float)G.scene->r.cfra, 0.0);
+       GroupObject *go;
+       Object *ob, **oblist=0;
+       ParticleSettings *part;
+       ParticleData *pa;
+       ParticleKey state;
+       float ctime, pa_time;
+       float tmat[4][4], mat[3][3], obrotmat[3][3], parotmat[3][3], size=0.0;
+       float xvec[3] = {-1.0, 0.0, 0.0}, *q;
+       int lay, a, k, step_nbr = 0, counter;
+       int totpart, totchild, totgroup=0, pa_num;
+
+       if(psys==0) return;
        
+       part=psys->part;
+
+       if(part==0) return;
+
+       ctime = bsystem_time(par, (float)G.scene->r.cfra, 0.0);
+
+       totpart = psys->totpart;
+       totchild = psys->totchild;
+
+       BLI_srandom(31415926 + psys->seed);
+               
        lay= G.scene->lay;
+       if((part->draw_as == PART_DRAW_OB && part->dup_ob) ||
+               (part->draw_as == PART_DRAW_GR && part->dup_group && part->dup_group->gobject.first)) {
 
-       for(base= sce->base.first; base; base= base->next) {
-               if(base->object->type>0 && (base->lay & lay) && G.obedit!=base->object) {
-                       ob= base->object->parent;
-                       while(ob) {
-                               if(ob==par) {
-                               
-                                       ob= base->object;
-                                       /* temp copy, to have ipos etc to work OK */
-                                       copyob= *ob;
-                                       
-                                       /* don't want parent animation to apply on past object positions */
-                                       if(!(paf->flag & PAF_STATIC))
-                                               ob->parent= NULL;
-                                       
-                                       for(a=0, pa= paf->keys, counter=0; a<paf->totpart; a++, pa+=paf->totkey, counter++) {
-                                               
-                                               if(paf->flag & PAF_STATIC) {
-                                                       float mtime;
-                                                       
-                                                       where_is_particle(paf, pa, pa->time, vec1);
-                                                       mtime= pa->time+pa->lifetime;
-                                                       
-                                                       for(ctime= pa->time; ctime<mtime; ctime+=paf->staticstep, counter++) {
-                                                               
-                                                               /* make sure hair grows until the end.. */ 
-                                                               if(ctime>pa->time+pa->lifetime) ctime= pa->time+pa->lifetime;
-                                                               
-                                                               /* to give ipos in object correct offset */
-                                                               where_is_object_time(ob, ctime-pa->time);
-
-                                                               where_is_particle(paf, pa, ctime, vec); // makes sure there's always a vec
-                                                               Mat4MulVecfl(par->obmat, vec);
-                                                               
-                                                               if(paf->stype==PAF_VECT) {
-                                                                       where_is_particle(paf, pa, ctime+1.0, vec1); // makes sure there's always a vec
-                                                                       Mat4MulVecfl(par->obmat, vec1);
-
-                                                                       VecSubf(vec1, vec1, vec);
-                                                                       q2= vectoquat(vec1, ob->trackflag, ob->upflag);
-                                                                       
-                                                                       QuatToMat3(q2, mat);
-                                                                       Mat4CpyMat4(tmat, ob->obmat);
-                                                                       Mat4MulMat43(ob->obmat, tmat, mat);
-                                                               }
-                                                               
-                                                               VECCOPY(ob->obmat[3], vec);
-                                                               /* put object back in original state, so it cam be restored OK */
-                                                               Mat4CpyMat4(tmat, ob->obmat);
-                                                               Mat4CpyMat4(ob->obmat, copyob.obmat);
-                                                               new_dupli_object(lb, ob, tmat, par->lay, counter);
-                                                       }
-                                               }
-                                               else { // non static particles
-                                                       
-                                                       if((paf->flag & PAF_UNBORN)==0 && ctime < pa->time) continue;
-                                                       if((paf->flag & PAF_DIED)==0 && ctime > pa->time+pa->lifetime) continue;
+               if(psys->flag & (PSYS_HAIR_DONE|PSYS_KEYED) && part->draw & PART_DRAW_KEYS)
+                       step_nbr = part->keys_step;
+               else
+                       step_nbr = 0;
 
-                                                       //if(ctime < pa->time+pa->lifetime) {
+               psys->lattice = psys_get_lattice(par, psys);
 
-                                                       /* to give ipos in object correct offset, ob->parent is NULLed */
-                                                       where_is_object_time(ob, ctime-pa->time);
-                                                       
-                                                       where_is_particle(paf, pa, ctime, vec);
-                                                       if(paf->stype==PAF_VECT) {
-                                                               
-                                                               /* if particle died, we use previous position */
-                                                               if(ctime > pa->time+pa->lifetime) {
-                                                                       where_is_particle(paf, pa, pa->time+pa->lifetime-1.0f, vec1);
-                                                                       VecSubf(vec1, vec, vec1);
-                                                               }
-                                                               else {
-                                                                       where_is_particle(paf, pa, ctime+1.0f, vec1);
-                                                                       VecSubf(vec1, vec1, vec);
-                                                               }
-                                                               q2= vectoquat(vec1, ob->trackflag, ob->upflag);
-                                       
-                                                               QuatToMat3(q2, mat);
-                                                               Mat4CpyMat4(tmat, ob->obmat);
-                                                               Mat4MulMat43(ob->obmat, tmat, mat);
-                                                       }
+               if(part->draw_as==PART_DRAW_GR) {
+                       group_handle_recalc_and_update(par, part->dup_group);
 
-                                                       VECCOPY(ob->obmat[3], vec);
-                                                       
-                                                       /* put object back in original state, so it can be restored OK */
-                                                       Mat4CpyMat4(tmat, ob->obmat);
-                                                       Mat4CpyMat4(ob->obmat, copyob.obmat);
-                                                       new_dupli_object(lb, ob, tmat, par->lay, counter);
-                                               }                                       
+                       go= part->dup_group->gobject.first;
+                       while(go) {
+                               go=go->next;
+                               totgroup++;
+                       }
+
+                       oblist= MEM_callocN(totgroup*sizeof(Object *), "dupgroup object list");
+                       go= part->dup_group->gobject.first;
+                       for(a=0; a<totgroup; a++, go=go->next)
+                               oblist[a]=go->ob;
+               }
+
+               if(totchild==0 || part->draw & PART_DRAW_PARENT)
+                       a=0;
+               else
+                       a=totpart;
+
+               for(pa=psys->particles,counter=0; a<totpart+totchild; a++,pa++,counter++) {
+                       if(a<totpart) {
+                               if(pa->flag & (PARS_UNEXIST+PARS_NO_DISP)) continue;
+
+                               pa_num=pa->num;
+
+                               pa_time=pa->time;
+
+                               size=pa->size;
+                       }
+                       else {
+                               /* TODO: figure these two out */
+                               pa_num = a;
+                               pa_time = psys->particles[psys->child[a - totpart].parent].time;
+
+                               size=psys_get_child_size(psys, a - totpart, ctime, 0);
+                       }
+
+                       if(part->draw_as==PART_DRAW_GR) {
+                               if(part->draw&PART_DRAW_RAND_GR)
+                                       ob = oblist[BLI_rand() % totgroup];
+                               else if(part->from==PART_FROM_PARTICLE)
+                                       ob = oblist[pa_num % totgroup];
+                               else
+                                       ob = oblist[a % totgroup];
+                       }
+                       else
+                               ob = part->dup_ob;
+
+                       for(k=0; k<=step_nbr; k++, counter++) {
+                               if(step_nbr) {
+                                       state.time = (float)k / (float)step_nbr;
+                                       psys_get_particle_on_path(par, psys, a, &state, 0);
+                               }
+                               else {
+                                       state.time = -1.0;
+                                       if(psys_get_particle_state(par, psys, a, &state, 0) == 0)
+                                               continue;
+                               }
+
+                               QuatToMat3(state.rot, parotmat);
+
+                               if(part->draw_as==PART_DRAW_GR && psys->part->draw & PART_DRAW_WHOLE_GR) {
+                                       for(go= part->dup_group->gobject.first; go; go= go->next) {
+
+                                               Mat4CpyMat4(tmat, go->ob->obmat);
+                                               Mat4MulMat43(tmat, go->ob->obmat, parotmat);
+                                               Mat4MulFloat3((float *)tmat, size);
+
+                                               VECADD(tmat[3], go->ob->obmat[3], state.co);
+
+                                               new_dupli_object(lb, go->ob, tmat, par->lay, counter);
                                        }
-                                       /* temp copy, to have ipos etc to work OK */
-                                       *ob= copyob;
+                               }
+                               else {
+                                       /* to give ipos in object correct offset */
+                                       where_is_object_time(ob, ctime-pa_time);
                                        
-                                       break;
+                                       q = vectoquat(xvec, ob->trackflag, ob->upflag);
+                                       QuatToMat3(q, obrotmat);
+
+                                       Mat3MulMat3(mat, parotmat, obrotmat);
+                                       Mat4CpyMat4(tmat, ob->obmat);
+                                       Mat4MulMat43(tmat, ob->obmat, mat);
+                                       Mat4MulFloat3((float *)tmat, size);
+
+                                       VECCOPY(tmat[3], state.co);
+
+                                       new_dupli_object(lb, ob, tmat, par->lay, counter);
                                }
-                               ob= ob->parent;
                        }
                }
        }
-       
-       if(G.rendering && paf->disp!=100) {
-               MEM_freeN(paf->keys);
-               paf->keys= NULL;
+       if(oblist)
+               MEM_freeN(oblist);
+
+       if(psys->lattice) {
+               end_latt_deform();
+               psys->lattice = 0;
        }
-       
-       
 }
 
 static Object *find_family_object(Object **obar, char *family, char ch)
@@ -771,13 +784,14 @@ ListBase *object_duplilist(Scene *sce, Object *ob)
        duplilist->first= duplilist->last= NULL;
        
        if(ob->transflag & OB_DUPLI) {
-               if(ob->transflag & OB_DUPLIVERTS) {
+               if(ob->transflag & OB_DUPLIPARTS) {
+                       ParticleSystem *psys = ob->particlesystem.first;
+                       for(; psys; psys=psys->next)
+                               new_particle_duplilist(duplilist, sce, ob, psys);
+               }
+               else if(ob->transflag & OB_DUPLIVERTS) {
                        if(ob->type==OB_MESH) {
-                               PartEff *paf;
-                               if( (paf=give_parteff(ob)) ) 
-                                       particle_duplilist(duplilist, sce, ob, paf);
-                               else 
-                                       vertex_duplilist(duplilist, sce, ob);
+                               vertex_duplilist(duplilist, sce, ob);
                        }
                        else if(ob->type==OB_FONT) {
                                font_duplilist(duplilist, ob);
@@ -823,14 +837,18 @@ int count_duplilist(Object *ob)
                if(ob->transflag & OB_DUPLIVERTS) {
                        if(ob->type==OB_MESH) {
                                if(ob->transflag & OB_DUPLIVERTS) {
-                                       PartEff *paf;
-                                       if( (paf=give_parteff(ob)) ) {
-                                               return paf->totpart;
-                                       }
-                                       else {
+                                       ParticleSystem *psys = ob->particlesystem.first;
+                                       int pdup=0;
+
+                                       for(; psys; psys=psys->next)
+                                               pdup += psys->totpart;
+
+                                       if(pdup==0){
                                                Mesh *me= ob->data;
                                                return me->totvert;
                                        }
+                                       else
+                                               return pdup;
                                }
                        }
                }
index 9d86b86a47fec33af18f7137ffe20e2df5fde58a..9845f5711261983459076db438f8e5aa4ec6ed11 100644 (file)
@@ -266,7 +266,7 @@ static void clear_global(void)
        
        free_vertexpaint();
        
-       G.f &= ~(G_WEIGHTPAINT + G_VERTEXPAINT + G_FACESELECT);
+       G.f &= ~(G_WEIGHTPAINT + G_VERTEXPAINT + G_FACESELECT + G_PARTICLEEDIT);
 }
 
 /* make sure path names are correct for OS */
index 2d5f5f091c37670cf9d34dea68189be0154eec14..6a85630791637ac946adad537c3474e4ddb1489d 100644 (file)
@@ -751,6 +751,7 @@ DerivedMesh *CDDM_from_mesh(Mesh *mesh, Object *ob)
        /* this does a referenced copy, the only new layers being ORIGINDEX */
 
        DM_init(dm, mesh->totvert, mesh->totedge, mesh->totface);
+       dm->deformedOnly = 1;
 
        CustomData_merge(&mesh->vdata, &dm->vertData, CD_MASK_MESH, CD_REFERENCE,
                         mesh->totvert);
@@ -798,6 +799,8 @@ DerivedMesh *CDDM_from_editmesh(EditMesh *em, Mesh *me)
        MFace *mface = cddm->mface;
        int i, *index;
 
+       dm->deformedOnly = 1;
+
        CustomData_merge(&em->vdata, &dm->vertData, CD_MASK_DERIVEDMESH,
                         CD_CALLOC, dm->numVertData);
        /* CustomData_merge(&em->edata, &dm->edgeData, CD_MASK_DERIVEDMESH,
@@ -889,6 +892,7 @@ DerivedMesh *CDDM_copy(DerivedMesh *source)
 
        /* this initializes dm, and copies all non mvert/medge/mface layers */
        DM_from_template(dm, source, numVerts, numEdges, numFaces);
+       dm->deformedOnly = source->deformedOnly;
 
        CustomData_copy_data(&source->vertData, &dm->vertData, 0, 0, numVerts);
        CustomData_copy_data(&source->edgeData, &dm->edgeData, 0, 0, numEdges);
index 436a14d1d6c8888a5f5166b430e5e1aedc1d7618..b997049a637ec47d19e4f1efa8948997bf47da66 100644 (file)
@@ -412,7 +412,7 @@ void cloth_clear_cache(Object *ob, ClothModifierData *clmd, float framenr)
        {
                stack_index = modifiers_indexInObject(ob, (ModifierData *)clmd);
                
-               PTCache_id_clear((ID *)ob, framenr, stack_index);
+               BKE_ptcache_id_clear((ID *)ob, PTCACHE_CLEAR_AFTER, framenr, stack_index);
        }
 }
 static void cloth_write_cache(Object *ob, ClothModifierData *clmd, float framenr)
@@ -427,7 +427,7 @@ static void cloth_write_cache(Object *ob, ClothModifierData *clmd, float framenr
        
        stack_index = modifiers_indexInObject(ob, (ModifierData *)clmd);
        
-       fp = PTCache_id_fopen((ID *)ob, 'w', framenr, stack_index);
+       fp = BKE_ptcache_id_fopen((ID *)ob, 'w', framenr, stack_index);
        if(!fp) return;
        
        for(a = 0; a < cloth->numverts; a++)
@@ -451,7 +451,7 @@ static int cloth_read_cache(Object *ob, ClothModifierData *clmd, float framenr)
        
        stack_index = modifiers_indexInObject(ob, (ModifierData *)clmd);
        
-       fp = PTCache_id_fopen((ID *)ob, 'r', framenr, stack_index);
+       fp = BKE_ptcache_id_fopen((ID *)ob, 'r', framenr, stack_index);
        if(!fp)
                ret = 0;
        else {
@@ -1039,7 +1039,7 @@ int cloth_build_springs ( Cloth *cloth, DerivedMesh *dm )
 {
        ClothSpring *spring = NULL, *tspring = NULL, *tspring2 = NULL;
        unsigned int struct_springs = 0, shear_springs=0, bend_springs = 0;
-       unsigned int i = 0;
+       unsigned int i = 0, j = 0;
        unsigned int numverts = dm->getNumVerts ( dm );
        unsigned int numedges = dm->getNumEdges ( dm );
        unsigned int numfaces = dm->getNumFaces ( dm );
@@ -1093,6 +1093,30 @@ int cloth_build_springs ( Cloth *cloth, DerivedMesh *dm )
                }
        }
        
+       // calc collision balls *slow*
+       // better: use precalculated list with O(1) index access to all springs of a vertex
+       // missing for structural since it's not needed for building bending springs
+       /*
+       for ( i = 0; i < numverts; i++ )
+       {
+               search = cloth->springs;
+               for ( j = 0; j < struct_springs; j++ )
+               {
+                       if ( !search )
+                               break;
+
+                       tspring = search->link;
+                       
+                       if((tspring->ij == i) || (tspring->kl == i))
+                       {
+                               akku += bs->len;
+                               akku_count++,
+                               min = MIN2(bs->len,min);
+                               max = MAX2(bs->len,max);
+                       }
+               }
+       }
+       */
        // shear springs
        for ( i = 0; i < numfaces; i++ )
        {
index 466ba9f4201301dc7cbb1236903adf5f611bc4cb..aa0dc10f4e0251d2bf296290269032cadb006058 100644 (file)
@@ -271,7 +271,7 @@ static void layerSwap_tface(void *data, int *corner_indices)
 
 static void layerDefault_tface(void *data, int count)
 {
-       static MTFace default_tf = {{{0, 1}, {0, 0}, {1, 0}, {1, 1}}, NULL,
+       static MTFace default_tf = {{{0, 0}, {1, 0}, {1, 1}, {0, 1}}, NULL,
                                   0, 0, TF_DYNAMIC, 0, 0};
        MTFace *tf = (MTFace*)data;
        int i;
@@ -280,6 +280,83 @@ static void layerDefault_tface(void *data, int count)
                tf[i] = default_tf;
 }
 
+static void layerCopy_origspace_face(const void *source, void *dest, int count)
+{
+       const OrigSpaceFace *source_tf = (const OrigSpaceFace*)source;
+       OrigSpaceFace *dest_tf = (OrigSpaceFace*)dest;
+       int i;
+
+       for(i = 0; i < count; ++i)
+               dest_tf[i] = source_tf[i];
+}
+
+static void layerInterp_origspace_face(void **sources, float *weights,
+                                                         float *sub_weights, int count, void *dest)
+{
+       OrigSpaceFace *osf = dest;
+       int i, j, k;
+       float uv[4][2];
+       float *sub_weight;
+
+       if(count <= 0) return;
+
+       memset(uv, 0, sizeof(uv));
+
+       sub_weight = sub_weights;
+       for(i = 0; i < count; ++i) {
+               float weight = weights ? weights[i] : 1;
+               OrigSpaceFace *src = sources[i];
+
+               for(j = 0; j < 4; ++j) {
+                       if(sub_weights) {
+                               for(k = 0; k < 4; ++k, ++sub_weight) {
+                                       float w = (*sub_weight) * weight;
+                                       float *tmp_uv = src->uv[k];
+
+                                       uv[j][0] += tmp_uv[0] * w;
+                                       uv[j][1] += tmp_uv[1] * w;
+                               }
+                       } else {
+                               uv[j][0] += src->uv[j][0] * weight;
+                               uv[j][1] += src->uv[j][1] * weight;
+                       }
+               }
+       }
+
+       *osf = *(OrigSpaceFace *)sources[0];
+       for(j = 0; j < 4; ++j) {
+               osf->uv[j][0] = uv[j][0];
+               osf->uv[j][1] = uv[j][1];
+       }
+}
+
+static void layerSwap_origspace_face(void *data, int *corner_indices)
+{
+       OrigSpaceFace *osf = data;
+       float uv[4][2];
+       int j;
+
+       for(j = 0; j < 4; ++j) {
+               uv[j][0] = osf->uv[corner_indices[j]][0];
+               uv[j][1] = osf->uv[corner_indices[j]][1];
+       }
+       memcpy(osf->uv, uv, sizeof(osf->uv));
+}
+
+static void layerDefault_origspace_face(void *data, int count)
+{
+       static OrigSpaceFace default_osf = {{{0, 0}, {1, 0}, {1, 1}, {0, 1}}};
+       OrigSpaceFace *osf = (OrigSpaceFace*)data;
+       int i;
+
+       for(i = 0; i < count; i++)
+               osf[i] = default_osf;
+}
+/* --------- */
+
+
+
+
 static void layerInterp_mcol(void **sources, float *weights,
                              float *sub_weights, int count, void *dest)
 {
@@ -370,11 +447,13 @@ const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
        {sizeof(MFloatProperty), "MFloatProperty",1,"Float",NULL,NULL,NULL,NULL},
        {sizeof(MIntProperty), "MIntProperty",1,"Int",NULL,NULL,NULL,NULL},
        {sizeof(MStringProperty), "MStringProperty",1,"String",NULL,NULL,NULL,NULL},
+       {sizeof(OrigSpaceFace), "OrigSpaceFace", 1, "UVTex", layerCopy_origspace_face, NULL,
+        layerInterp_origspace_face, layerSwap_origspace_face, layerDefault_origspace_face},
 };
 
 const char *LAYERTYPENAMES[CD_NUMTYPES] = {
        "CDMVert", "CDMSticky", "CDMDeformVert", "CDMEdge", "CDMFace", "CDMTFace",
-       "CDMCol", "CDOrigIndex", "CDNormal", "CDFlags","CDMFloatProperty","CDMIntProperty","CDMStringProperty"};
+       "CDMCol", "CDOrigIndex", "CDNormal", "CDFlags","CDMFloatProperty","CDMIntProperty","CDMStringProperty", "CDOrigSpace"};
 
 const CustomDataMask CD_MASK_BAREMESH =
        CD_MASK_MVERT | CD_MASK_MEDGE | CD_MASK_MFACE;
@@ -387,8 +466,8 @@ const CustomDataMask CD_MASK_EDITMESH =
        CD_MASK_MCOL|CD_MASK_PROP_FLT | CD_MASK_PROP_INT | CD_MASK_PROP_STR;
 const CustomDataMask CD_MASK_DERIVEDMESH =
        CD_MASK_MSTICKY | CD_MASK_MDEFORMVERT | CD_MASK_MTFACE |
-       CD_MASK_MCOL | CD_MASK_ORIGINDEX|
-       CD_MASK_PROP_FLT | CD_MASK_PROP_INT | CD_MASK_PROP_STR;
+       CD_MASK_MCOL | CD_MASK_ORIGINDEX |
+       CD_MASK_PROP_FLT | CD_MASK_PROP_INT | CD_MASK_PROP_STR | CD_MASK_ORIGSPACE;
 
 static const LayerTypeInfo *layerType_getInfo(int type)
 {
index 11ec8670ed1e9f8f23c6fab1d657db160cff6ebd..924f544285ef3fc082b6a73547731120bb19e23a 100644 (file)
@@ -57,6 +57,7 @@
 #include "DNA_object_force.h"
 #include "DNA_object_fluidsim.h"
 #include "DNA_oops_types.h"
+#include "DNA_particle_types.h"
 #include "DNA_scene_types.h"
 #include "DNA_screen_types.h"
 #include "DNA_space_types.h"
@@ -72,8 +73,9 @@
 #include "BKE_mball.h"
 #include "BKE_modifier.h"
 #include "BKE_object.h"
-#include "BKE_scene.h"
+#include "BKE_particle.h"
 #include "BKE_utildefines.h"
+#include "BKE_scene.h"
 
 #include "MEM_guardedalloc.h"
 #include "blendef.h"
@@ -353,6 +355,7 @@ static void build_dag_object(DagForest *dag, DagNode *scenenode, Object *ob, int
        DagNode * node2;
        DagNode * node3;
        Key *key;
+       ParticleSystem *psys;
        int addtoroot= 1;
        
        node = dag_get_node(dag, ob);
@@ -586,6 +589,54 @@ static void build_dag_object(DagForest *dag, DagNode *scenenode, Object *ob, int
                        }
                }
        }
+
+       psys= ob->particlesystem.first;
+       if(psys) {
+               ParticleEffectorCache *nec;
+
+               for(; psys; psys=psys->next) {
+                       ParticleSettings *part= psys->part;
+                       
+                       dag_add_relation(dag, node, node, DAG_RL_OB_DATA);
+
+                       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);
+                       }
+
+                       if(psys->effectors.first)
+                               psys_end_effectors(psys);
+                       psys_init_effectors(ob,psys->part->eff_group,psys);
+
+                       if(psys->effectors.first) {
+                               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);
+                                               else
+                                                       dag_add_relation(dag, node2, node, DAG_RL_OB_DATA);
+                                       }
+                                       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);
+                                       }
+                                       else if(nec->type & PSYS_EC_PARTICLE) {
+                                               node2 = dag_get_node(dag, ob1);
+                                               dag_add_relation(dag, node2, node, DAG_RL_DATA_DATA);
+                                       }
+                                       
+                                       if(nec->type & PSYS_EC_REACTOR) {
+                                               node2 = dag_get_node(dag, ob1);
+                                               dag_add_relation(dag, node, node2, DAG_RL_DATA_DATA);
+                                       }
+                               }
+                       }
+               }
+       }
        
        for (con = ob->constraints.first; con; con=con->next) {
                bConstraintTypeInfo *cti= constraint_get_typeinfo(con);
@@ -1813,6 +1864,8 @@ static void dag_object_time_update_flags(Object *ob)
                                                ob->recalc |= OB_RECALC_DATA; // NT FSPARTICLE
                                        }
                                }
+                               if(ob->particlesystem.first)
+                                       ob->recalc |= OB_RECALC_DATA;
                                break;
                        case OB_CURVE:
                        case OB_SURF:
@@ -1842,6 +1895,17 @@ static void dag_object_time_update_flags(Object *ob)
                                if(ob->transflag & OB_DUPLI) ob->recalc |= OB_RECALC_DATA;
                                break;
                }
+
+               if(ob->particlesystem.first) {
+                       ParticleSystem *psys= ob->particlesystem.first;
+
+                       for(; psys; psys=psys->next) {
+                               if(psys->flag & PSYS_ENABLED) {
+                                       ob->recalc |= OB_RECALC_DATA;
+                                       break;
+                               }
+                       }
+               }
        }               
 }
 
index 30a4c8c34339451bbb6928721df286c0ed565a3d..f410167c2ac2195d9eeaa829f20b3af86be2dee6 100644 (file)
@@ -1098,7 +1098,7 @@ void curve_to_filledpoly(Curve *cu, ListBase *nurb, ListBase *dispbase)
   - first point left, last point right
   - based on subdivided points in original curve, not on points in taper curve (still)
 */
-static float calc_taper(Object *taperobj, int cur, int tot)
+float calc_taper(Object *taperobj, int cur, int tot)
 {
        Curve *cu;
        DispList *dl;
@@ -1256,7 +1256,7 @@ void curve_calc_modifiers_post(Object *ob, ListBase *nurb, ListBase *dispbase, i
 
                if ((md->mode & required_mode) != required_mode) continue;
                if (mti->isDisabled && mti->isDisabled(md)) continue;
-               if (mti->type!=eModifierTypeType_OnlyDeform) continue;
+               if (mti->type!=eModifierTypeType_OnlyDeform && mti->type!=eModifierTypeType_DeformOrConstruct) continue;
 
                for (dl=dispbase->first; dl; dl=dl->next) {
                        mti->deformVerts(md, ob, NULL, (float(*)[3]) dl->verts, (dl->type==DL_INDEX3)?dl->nr:dl->parts*dl->nr);
index 07fe8bbee31d411bd6f939105a8ee973ed5b8895..1b345616888cf00241867b9e0745e94506931976 100644 (file)
@@ -799,7 +799,7 @@ static int pdDoDeflection(RNG *rng, float opco[3], float npco[3], float opno[3],
                                                
 //                                     t= 0.5; // this is labda of line, can use it optimize quad intersection
 // sorry but no .. see below (BM)                                      
-                                       if( LineIntersectsTriangle(opco, npco, nv1, nv2, nv3, &t) ) {
+                                       if( LineIntersectsTriangle(opco, npco, nv1, nv2, nv3, &t, NULL) ) {
                                                if (t < min_t) {
                                                        deflected = 1;
                                                        deflected_now = 1;
@@ -810,7 +810,7 @@ static int pdDoDeflection(RNG *rng, float opco[3], float npco[3], float opno[3],
 // it might give a smaller t on (close to) the edge .. this is numerics not esoteric maths :)
 // note: the 2 triangles don't need to share a plane ! (BM)
                                        if (mface->v4) {
-                                               if( LineIntersectsTriangle(opco, npco, nv1, nv3, nv4, &t2) ) {
+                                               if( LineIntersectsTriangle(opco, npco, nv1, nv3, nv4, &t2, NULL) ) {
                                                        if (t2 < min_t) {
                                                                deflected = 1;
                                                                deflected_now = 2;
index 83b845a0064a9064fe0d5ad41297e972fce1626c..03a34df090a2a0af69ae2b11d5d7baa93d6fdc3c 100644 (file)
@@ -52,6 +52,7 @@
 #include "DNA_mesh_types.h"
 #include "DNA_object_types.h"
 #include "DNA_object_force.h"
+#include "DNA_particle_types.h"
 #include "DNA_sequence_types.h"
 #include "DNA_scene_types.h"
 #include "DNA_sound_types.h"
@@ -93,7 +94,7 @@ int ob_ar[OB_TOTIPO]= {
        OB_ROT_X, OB_ROT_Y, OB_ROT_Z, OB_DROT_X, OB_DROT_Y, OB_DROT_Z, 
        OB_SIZE_X, OB_SIZE_Y, OB_SIZE_Z, OB_DSIZE_X, OB_DSIZE_Y, OB_DSIZE_Z, 
        OB_LAY, OB_TIME, OB_COL_R, OB_COL_G, OB_COL_B, OB_COL_A,
-       OB_PD_FSTR, OB_PD_FFALL, OB_PD_SDAMP, OB_PD_RDAMP, OB_PD_PERM
+       OB_PD_FSTR, OB_PD_FFALL, OB_PD_SDAMP, OB_PD_RDAMP, OB_PD_PERM, OB_PD_FMAXD
 };
 
 int ac_ar[AC_TOTIPO]= {
@@ -180,6 +181,12 @@ int fluidsim_ar[FLUIDSIM_TOTIPO]= {
        FLUIDSIM_ACTIVE 
 };
 
+int part_ar[PART_TOTIPO]= {
+       PART_EMIT_FREQ, PART_EMIT_LIFE, PART_EMIT_VEL, PART_EMIT_AVE, PART_EMIT_SIZE,
+       PART_AVE, PART_SIZE, PART_DRAG, PART_BROWN, PART_DAMP, PART_LENGTH, PART_CLUMP,
+    PART_GRAV_X, PART_GRAV_Y, PART_GRAV_Z, PART_KINK_AMP, PART_KINK_FREQ, PART_KINK_SHAPE,
+       PART_BB_TILT
+};
 
 
 float frame_to_float(int cfra)         /* see also bsystem_time in object.c */
@@ -1231,6 +1238,7 @@ void *get_ipo_poin(ID *id, IpoCurve *icu, int *type)
        Lamp *la;
        Sequence *seq;
        World *wo;
+       ParticleSettings *part;
 
        *type= IPO_FLOAT;
 
@@ -1308,6 +1316,9 @@ void *get_ipo_poin(ID *id, IpoCurve *icu, int *type)
                case OB_PD_PERM:
                        if(ob->pd) poin= &(ob->pd->pdef_perm);
                        break;
+               case OB_PD_FMAXD:
+                       if(ob->pd) poin= &(ob->pd->maxdist);
+                       break;
                }
        }
        else if( GS(id->name)==ID_MA) {
@@ -1560,7 +1571,48 @@ void *get_ipo_poin(ID *id, IpoCurve *icu, int *type)
                        poin= &(snd->attenuation); break;
                }
        }
-       
+       else if( GS(id->name)==ID_PA) {
+               
+               part= (ParticleSettings *)id;
+               
+               switch(icu->adrcode) {
+               case PART_EMIT_FREQ:
+               case PART_EMIT_LIFE:
+               case PART_EMIT_VEL:
+               case PART_EMIT_AVE:
+               case PART_EMIT_SIZE:
+                       poin= NULL; break;
+               case PART_CLUMP:
+                       poin= &(part->clumpfac); break;
+               case PART_AVE:
+                       poin= &(part->avefac); break;
+               case PART_SIZE:
+                       poin= &(part->size); break;
+               case PART_DRAG:
+                       poin= &(part->dragfac); break;
+               case PART_BROWN:
+                       poin= &(part->brownfac); break;
+               case PART_DAMP:
+                       poin= &(part->dampfac); break;
+               case PART_LENGTH:
+                       poin= &(part->length); break;
+               case PART_GRAV_X:
+                       poin= &(part->acc[0]); break;
+               case PART_GRAV_Y:
+                       poin= &(part->acc[1]); break;
+               case PART_GRAV_Z:
+                       poin= &(part->acc[2]); break;
+               case PART_KINK_AMP:
+                       poin= &(part->kink_amp); break;
+               case PART_KINK_FREQ:
+                       poin= &(part->kink_freq); break;
+               case PART_KINK_SHAPE:
+                       poin= &(part->kink_shape); break;
+               case PART_BB_TILT:
+                       poin= &(part->bb_tilt); break;
+               }
+       }
+
        return poin;
 }
 
@@ -1855,6 +1907,29 @@ void set_icu_vars(IpoCurve *icu)
                        break;
                }
        }
+       else if(icu->blocktype==ID_PA){
+
+               switch(icu->adrcode) {
+               case PART_EMIT_LIFE:
+               case PART_SIZE:
+               case PART_KINK_FREQ:
+               case PART_EMIT_VEL:
+               case PART_EMIT_AVE:
+               case PART_EMIT_SIZE:
+                       icu->ymin= 0.0;
+                       break;
+               case PART_CLUMP:
+               case PART_DRAG:
+               case PART_DAMP:
+               case PART_LENGTH:
+                       icu->ymin= 0.0;
+                       icu->ymax= 1.0;
+                       break;
+               case PART_KINK_SHAPE:
+                       icu->ymin= -0.999;
+                       icu->ymax= 0.999;
+               }
+       }
        else if(icu->blocktype==ID_CO) {
                icu->ymin= 0.0;
                icu->ymax= 1.0f;
@@ -2325,6 +2400,7 @@ void make_cfra_list(Ipo *ipo, ListBase *elems)
                                case OB_PD_SDAMP:
                                case OB_PD_RDAMP:
                                case OB_PD_PERM:
+                               case OB_PD_FMAXD:
                                        bezt= icu->bezt;
                                        if(bezt) {
                                                a= icu->totvert;
index 28a6aad7b4d938c634316123e4631cea9428c1ed..e81d3bac655b993afb764d56b3290be0573906b4 100644 (file)
@@ -78,6 +78,8 @@
 #include "DNA_nla_types.h"
 #include "DNA_effect_types.h"
 #include "DNA_brush_types.h"
+#include "DNA_particle_types.h"
+#include "BKE_particle.h"
 
 #include "BLI_blenlib.h"
 #include "BLI_dynstr.h"
@@ -194,6 +196,8 @@ ListBase *wich_libbase(Main *mainlib, short type)
                        return &(mainlib->nodetree);
                case ID_BR:
                        return &(mainlib->brush);
+               case ID_PA:
+                       return &(mainlib->particle);
        }
        return 0;
 }
@@ -254,16 +258,17 @@ int set_listbasepointers(Main *main, ListBase **lb)
        lb[18]= &(main->nodetree);
        lb[19]= &(main->brush);
        lb[20]= &(main->script);
+       lb[21]= &(main->particle);
        
-       lb[21]= &(main->world);
-       lb[22]= &(main->screen);
-       lb[23]= &(main->object);
-       lb[24]= &(main->scene);
-       lb[25]= &(main->library);
+       lb[22]= &(main->world);
+       lb[23]= &(main->screen);
+       lb[24]= &(main->object);
+       lb[25]= &(main->scene);
+       lb[26]= &(main->library);
        
-       lb[26]= NULL;
+       lb[27]= NULL;
 
-       return 26;
+       return 27;
 }
 
 /* *********** ALLOC AND FREE *****************
@@ -359,6 +364,9 @@ static ID *alloc_libblock_notest(short type)
                case ID_BR:
                        id = MEM_callocN(sizeof(Brush), "brush");
                        break;
+               case ID_PA:
+                       id = MEM_callocN(sizeof(ParticleSettings), "ParticleSettings");
+                       break;
        }
        return id;
 }
@@ -503,6 +511,9 @@ void free_libblock(ListBase *lb, void *idv)
                case ID_BR:
                        free_brush((Brush *)id);
                        break;
+               case ID_PA:
+                       psys_free_settings((ParticleSettings *)id);
+                       break;
        }
 
        if (id->properties) {
index 85dc1ca44fbf7f1af456bd2c31e09260cdb60696..998a15df28cbe8348227ae8d9e0bd10acb3e44f2 100644 (file)
 #include "math.h"
 #include "float.h"
 
-#include "BLI_blenlib.h"
-#include "BLI_rand.h"
 #include "BLI_arithb.h"
+#include "BLI_blenlib.h"
+#include "BLI_kdtree.h"
 #include "BLI_linklist.h"
+#include "BLI_rand.h"
 #include "BLI_edgehash.h"
 #include "BLI_ghash.h"
 #include "BLI_memarena.h"
@@ -60,6 +61,7 @@
 #include "DNA_modifier_types.h"
 #include "DNA_object_types.h"
 #include "DNA_object_force.h"
+#include "DNA_particle_types.h"
 #include "DNA_scene_types.h"
 #include "DNA_texture_types.h"
 #include "DNA_curve_types.h"
 #include "BKE_anim.h"
 #include "BKE_bad_level_calls.h"
 #include "BKE_collisions.h"
+#include "BKE_curve.h"
 #include "BKE_customdata.h"
 #include "BKE_global.h"
-#include "BKE_utildefines.h"
 #include "BKE_cdderivedmesh.h"
 #include "BKE_DerivedMesh.h"
 #include "BKE_booleanops.h"
 #include "BKE_displist.h"
 #include "BKE_modifier.h"
 #include "BKE_lattice.h"
+#include "BKE_library.h"
 #include "BKE_subsurf.h"
 #include "BKE_object.h"
 #include "BKE_mesh.h"
 #include "BKE_softbody.h"
 #include "BKE_cloth.h"
 #include "BKE_material.h"
+#include "BKE_particle.h"
+#include "BKE_pointcache.h"
+#include "BKE_utildefines.h"
 #include "depsgraph_private.h"
 
 #include "LOD_DependKludge.h"
@@ -4688,7 +4694,7 @@ static void armatureModifier_deformVerts(
        
        armature_deform_verts(amd->object, ob, derivedData, vertexCos, NULL,
                              numVerts, amd->deformflag, 
-                                                 amd->prevCos, amd->defgrp_name);
+                                                 (float(*)[3])amd->prevCos, amd->defgrp_name);
        /* free cache */
        if(amd->prevCos) {
                MEM_freeN(amd->prevCos);
@@ -5251,6 +5257,1220 @@ static DerivedMesh *booleanModifier_applyModifier(
        return derivedData;
 }
 
+/* Particles */
+static void particleSystemModifier_initData(ModifierData *md) 
+{
+       ParticleSystemModifierData *psmd= (ParticleSystemModifierData*) md;
+       psmd->psys= 0;
+       psmd->dm=0;
+
+}
+static void particleSystemModifier_freeData(ModifierData *md)
+{
+       ParticleSystemModifierData *psmd= (ParticleSystemModifierData*) md;
+
+       if(psmd->dm){
+               psmd->dm->needsFree = 1;
+               psmd->dm->release(psmd->dm);
+               psmd->dm=0;
+       }
+
+       psmd->psys->flag &= ~PSYS_ENABLED;
+       psmd->psys->flag |= PSYS_DELETE;
+}
+static void particleSystemModifier_copyData(ModifierData *md, ModifierData *target)
+{
+       ParticleSystemModifierData *psmd= (ParticleSystemModifierData*) md;
+       ParticleSystemModifierData *tpsmd= (ParticleSystemModifierData*) target;
+
+       tpsmd->dm = 0;
+       //tpsmd->facepa = 0;
+       tpsmd->flag = psmd->flag;
+       /* need to keep this to recognise a bit later in copy_object */
+       tpsmd->psys = psmd->psys;
+}
+
+CustomDataMask particleSystemModifier_requiredDataMask(ModifierData *md)
+{
+       ParticleSystemModifierData *psmd= (ParticleSystemModifierData*) md;
+       CustomDataMask dataMask = (1 << CD_MTFACE) + (1 << CD_MEDGE);
+       int i;
+
+       /* ask for vertexgroups if we need them */
+       for(i=0; i<PSYS_TOT_VG; i++){
+               if(psmd->psys->vgroup[i]){
+                       dataMask |= (1 << CD_MDEFORMVERT);
+                       break;
+               }
+       }
+       
+       /* particles only need this if they are after a non deform modifier, and
+        * the modifier stack will only create them in that case. */
+       dataMask |= CD_MASK_ORIGSPACE;
+       
+       return dataMask;
+}
+static int is_last_displist(Object *ob)
+{
+       Curve *cu = ob->data;
+       static int curvecount=0, totcurve=0;
+
+       if(curvecount==0){
+               DispList *dl;
+
+               totcurve=0;
+               for(dl=cu->disp.first; dl; dl=dl->next){
+                       totcurve++;
+               }
+       }
+
+       curvecount++;
+
+       if(curvecount==totcurve){
+               curvecount=0;
+               return 1;
+       }
+
+       return 0;
+}
+/* saves the current emitter state for a particle system and calculates particles */
+static void particleSystemModifier_deformVerts(
+                 ModifierData *md, Object *ob, DerivedMesh *derivedData,
+                float (*vertexCos)[3], int numVerts)
+{
+       DerivedMesh *dm = derivedData;
+       ParticleSystemModifierData *psmd= (ParticleSystemModifierData*) md;
+       ParticleSystem * psys=0;
+       int totvert=0,totedge=0,totface=0,needsFree=0;
+       
+       if(ob->particlesystem.first)
+               psys=psmd->psys;
+       else
+               return;
+       
+       if((psys->flag&PSYS_ENABLED)==0)
+               return;
+
+       if(dm==0){
+               if(ob->type==OB_MESH){
+                       dm = CDDM_from_mesh((Mesh*)(ob->data), ob);
+
+                       CDDM_apply_vert_coords(dm, vertexCos);
+                       //CDDM_calc_normals(dm);
+
+                       needsFree=1;
+               }
+               else if(ELEM3(ob->type,OB_FONT,OB_CURVE,OB_SURF)){
+                       Object *tmpobj;
+                       Curve *tmpcu;
+
+                       if(is_last_displist(ob)){
+                               /* copies object and modifiers (but not the data) */
+                               tmpobj= copy_object( ob );
+                               tmpcu = (Curve *)tmpobj->data;
+                               tmpcu->id.us--;
+
+                               /* copies the data */
+                               tmpobj->data = copy_curve( (Curve *) ob->data );
+
+                               makeDispListCurveTypes( tmpobj, 1 );
+                               nurbs_to_mesh( tmpobj );
+
+                               dm = CDDM_from_mesh((Mesh*)(tmpobj->data), tmpobj);
+                               //CDDM_calc_normals(dm);
+
+                               free_libblock_us( &G.main->object, tmpobj );
+
+                               needsFree=1;
+                       }
+                       else return;
+               }
+               else return;
+       }
+
+       /* clear old dm */
+       if(psmd->dm){
+               totvert=psmd->dm->getNumVerts(psmd->dm);
+               totedge=psmd->dm->getNumEdges(psmd->dm);
+               totface=psmd->dm->getNumFaces(psmd->dm);
+               psmd->dm->needsFree = 1;
+               psmd->dm->release(psmd->dm);
+       }
+
+       /* make new dm */
+       psmd->dm=CDDM_copy(dm);
+       CDDM_calc_normals(psmd->dm);
+
+       if(needsFree){
+               dm->needsFree = 1;
+               dm->release(dm);
+       }
+
+       /* protect dm */
+       psmd->dm->needsFree = 0;
+
+       /* report change in mesh structure */
+       if(psmd->dm->getNumVerts(psmd->dm)!=totvert ||
+          psmd->dm->getNumEdges(psmd->dm)!=totedge ||
+          psmd->dm->getNumFaces(psmd->dm)!=totface){
+               /* in file read dm hasn't really changed but just wasn't saved in file */
+               if(psmd->flag & eParticleSystemFlag_Loaded)
+                       psmd->flag &= ~eParticleSystemFlag_Loaded;
+               else{
+                       /* TODO PARTICLE - Added this so changing subsurf under hair updates it
+                       should it be done elsewhere? - Campbell */
+                       psys->recalc |= PSYS_RECALC_HAIR;
+                       psys->recalc |= PSYS_DISTR;
+                       psmd->flag |= eParticleSystemFlag_DM_changed;
+               }
+       }
+
+       if(psys){
+               particle_system_update(ob,psys);
+               psmd->flag |= eParticleSystemFlag_psys_updated;
+               psmd->flag &= ~eParticleSystemFlag_DM_changed;
+       }
+}
+
+static void particleSystemModifier_deformVertsEM(
+                ModifierData *md, Object *ob, EditMesh *editData,
+                DerivedMesh *derivedData, float (*vertexCos)[3], int numVerts)
+{
+       DerivedMesh *dm = derivedData;
+
+       if(!derivedData) dm = CDDM_from_editmesh(editData, ob->data);
+
+       particleSystemModifier_deformVerts(md, ob, dm, vertexCos, numVerts);
+
+       if(!derivedData) dm->release(dm);
+}
+
+/* Particle Instance */
+static void particleInstanceModifier_initData(ModifierData *md) 
+{
+       ParticleInstanceModifierData *pimd= (ParticleInstanceModifierData*) md;
+
+       pimd->flag = eParticleInstanceFlag_Parents|eParticleInstanceFlag_Unborn|
+                               eParticleInstanceFlag_Alive|eParticleInstanceFlag_Dead;
+       pimd->psys = 1;
+
+}
+static void particleInstanceModifier_copyData(ModifierData *md, ModifierData *target)
+{
+       ParticleInstanceModifierData *pimd= (ParticleInstanceModifierData*) md;
+       ParticleInstanceModifierData *tpimd= (ParticleInstanceModifierData*) target;
+
+       tpimd->ob = pimd->ob;
+       tpimd->psys = pimd->psys;
+       tpimd->flag = pimd->flag;
+}
+
+static int particleInstanceModifier_dependsOnTime(ModifierData *md) 
+{
+       return 0;
+}
+static void particleInstanceModifier_updateDepgraph(ModifierData *md, DagForest *forest,
+                                         Object *ob, DagNode *obNode)
+{
+       ParticleInstanceModifierData *pimd = (ParticleInstanceModifierData*) md;
+
+       if (pimd->ob) {
+               DagNode *curNode = dag_get_node(forest, pimd->ob);
+
+               dag_add_relation(forest, curNode, obNode,
+                                DAG_RL_DATA_DATA | DAG_RL_OB_DATA);
+       }
+}
+
+static void particleInstanceModifier_foreachObjectLink(ModifierData *md, Object *ob,
+                                        ObjectWalkFunc walk, void *userData)
+{
+       ParticleInstanceModifierData *pimd = (ParticleInstanceModifierData*) md;
+
+       walk(userData, ob, &pimd->ob);
+}
+
+static DerivedMesh * particleInstanceModifier_applyModifier(
+                 ModifierData *md, Object *ob, DerivedMesh *derivedData,
+                 int useRenderParams, int isFinalCalc)
+{
+       DerivedMesh *dm = derivedData, *result;
+       ParticleInstanceModifierData *pimd= (ParticleInstanceModifierData*) md;
+       ParticleSystem * psys=0;
+       ParticleData *pa=0, *pars=0;
+       MFace *mface, *orig_mface;
+       MVert *mvert, *orig_mvert;
+       int i,totvert, totpart=0, totface, maxvert, maxface, first_particle=0;
+       short track=ob->trackflag%3, trackneg;
+       float max_co=0.0, min_co=0.0, temp_co[3];
+
+       trackneg=((ob->trackflag>2)?1:0);
+
+       if(pimd->ob==ob){
+               pimd->ob=0;
+               return derivedData;
+       }
+
+       if(pimd->ob){
+               psys = BLI_findlink(&pimd->ob->particlesystem,pimd->psys-1);
+               if(psys==0 || psys->totpart==0)
+                       return derivedData;
+       }
+       else return derivedData;
+
+       if(pimd->flag & eParticleInstanceFlag_Parents)
+               totpart+=psys->totpart;
+       if(pimd->flag & eParticleInstanceFlag_Children){
+               if(totpart==0)
+                       first_particle=psys->totpart;
+               totpart+=psys->totchild;
+       }
+
+       if(totpart==0)
+               return derivedData;
+
+       pars=psys->particles;
+
+       totvert=dm->getNumVerts(dm);
+       totface=dm->getNumFaces(dm);
+
+       maxvert=totvert*totpart;
+       maxface=totface*totpart;
+
+       psys->lattice=psys_get_lattice(ob, psys);
+
+       if(psys->flag & (PSYS_HAIR_DONE|PSYS_KEYED)){
+               float co[3];
+               for(i=0; i< totvert; i++){
+                       dm->getVertCo(dm,i,co);
+                       if(i==0){
+                               min_co=max_co=co[track];
+                       }
+                       else{
+                               if(co[track]<min_co)
+                                       min_co=co[track];
+
+                               if(co[track]>max_co)
+                                       max_co=co[track];
+                       }
+               }
+       }
+
+       result = CDDM_from_template(dm, maxvert,dm->getNumEdges(dm)*totpart,maxface);
+
+       mvert=result->getVertArray(result);
+       orig_mvert=dm->getVertArray(dm);
+
+       for(i=0; i<maxvert; i++){
+               MVert *inMV;
+               MVert *mv = mvert + i;
+               ParticleKey state;
+
+               inMV = orig_mvert + i%totvert;
+               DM_copy_vert_data(dm, result, i%totvert, i, 1);
+               *mv = *inMV;
+
+               /*change orientation based on object trackflag*/
+               VECCOPY(temp_co,mv->co);
+               mv->co[0]=temp_co[track];
+               mv->co[1]=temp_co[(track+1)%3];
+               mv->co[2]=temp_co[(track+2)%3];
+
+               if(psys->flag & (PSYS_HAIR_DONE|PSYS_KEYED) && pimd->flag & eParticleInstanceFlag_Path){
+                       state.time=(mv->co[0]-min_co)/(max_co-min_co);
+                       if(trackneg)
+                               state.time=1.0f-state.time;
+                       psys_get_particle_on_path(pimd->ob,psys,first_particle + i/totvert,&state,1);
+               }
+               else{
+                       state.time=-1.0;
+                       psys_get_particle_state(pimd->ob,psys,i/totvert,&state,1);
+               }
+
+               /*displace vertice to path location*/
+               if(pimd->flag & eParticleInstanceFlag_Path)
+                       mv->co[0]=0.0;
+
+               QuatMulVecf(state.rot,mv->co);
+               VECADD(mv->co,mv->co,state.co);
+       }
+
+       mface=result->getFaceArray(result);
+       orig_mface=dm->getFaceArray(dm);
+
+       for(i=0; i<maxface; i++){
+               MFace *inMF;
+               MFace *mf = mface + i;
+
+               if(pimd->flag & eParticleInstanceFlag_Parents){
+                       if(i/totface>=psys->totpart){
+                               if(psys->part->childtype==PART_CHILD_PARTICLES)
+                                       pa=psys->particles+(psys->child+i/totface-psys->totpart)->parent;
+                               else
+                                       pa=0;
+                       }
+                       else
+                               pa=pars+i/totface;
+               }
+               else{
+                       if(psys->part->childtype==PART_CHILD_PARTICLES)
+                               pa=psys->particles+(psys->child+i/totface)->parent;
+                       else
+                               pa=0;
+               }
+
+               if(pa){
+                       if(pa->alive==PARS_UNBORN && (pimd->flag&eParticleInstanceFlag_Unborn)==0) continue;
+                       if(pa->alive==PARS_ALIVE && (pimd->flag&eParticleInstanceFlag_Alive)==0) continue;
+                       if(pa->alive==PARS_DEAD && (pimd->flag&eParticleInstanceFlag_Dead)==0) continue;
+               }
+
+               inMF = orig_mface + i%totface;
+               DM_copy_face_data(dm, result, i%totface, i, 1);
+               *mf = *inMF;
+
+               mf->v1+=(i/totface)*totvert;
+               mf->v2+=(i/totface)*totvert;
+               mf->v3+=(i/totface)*totvert;
+               if(mf->v4)
+                       mf->v4+=(i/totface)*totvert;
+       }
+       
+       CDDM_calc_edges(result);
+       CDDM_calc_normals(result);
+
+       if(psys->lattice){
+               end_latt_deform();
+               psys->lattice=0;
+       }
+
+       return result;
+}
+static DerivedMesh *particleInstanceModifier_applyModifierEM(
+                        ModifierData *md, Object *ob, EditMesh *editData,
+                        DerivedMesh *derivedData)
+{
+       return particleInstanceModifier_applyModifier(md, ob, derivedData, 0, 1);
+}
+
+/* Explode */
+static void explodeModifier_initData(ModifierData *md)
+{
+       ExplodeModifierData *emd= (ExplodeModifierData*) md;
+
+       emd->facepa=0;
+       emd->flag |= eExplodeFlag_Unborn+eExplodeFlag_Alive+eExplodeFlag_Dead;
+}
+static void explodeModifier_freeData(ModifierData *md)
+{
+       ExplodeModifierData *emd= (ExplodeModifierData*) md;
+       
+       if(emd->facepa) MEM_freeN(emd->facepa);
+}
+static void explodeModifier_copyData(ModifierData *md, ModifierData *target)
+{
+       ExplodeModifierData *emd= (ExplodeModifierData*) md;
+       ExplodeModifierData *temd= (ExplodeModifierData*) target;
+
+       temd->facepa = 0;
+       temd->flag = emd->flag;
+}
+static int explodeModifier_dependsOnTime(ModifierData *md) 
+{
+       return 1;
+}
+CustomDataMask explodeModifier_requiredDataMask(ModifierData *md)
+{
+       ExplodeModifierData *emd= (ExplodeModifierData*) md;
+       CustomDataMask dataMask = 0;
+
+       if(emd->vgroup)
+               dataMask |= (1 << CD_MDEFORMVERT);
+
+       return dataMask;
+}
+
+/* this should really be put somewhere permanently */
+static float vert_weight(MDeformVert *dvert, int group)
+{
+       MDeformWeight *dw;
+       int i;
+       
+       if(dvert) {
+               dw= dvert->dw;
+               for(i= dvert->totweight; i>0; i--, dw++) {
+                       if(dw->def_nr == group) return dw->weight;
+                       if(i==1) break; /*otherwise dw will point to somewhere it shouldn't*/
+               }
+       }
+       return 0.0;
+}
+
+static void explodeModifier_createFacepa(ExplodeModifierData *emd,
+                                                                                ParticleSystemModifierData *psmd,
+                                                                                Object *ob, DerivedMesh *dm)
+{
+       ParticleSystem *psys=psmd->psys;
+       MFace *fa=0, *mface=0;
+       MVert *mvert = 0;
+       ParticleData *pa;
+       KDTree *tree;
+       float center[3], co[3];
+       int *facepa=0,*vertpa=0,totvert=0,totface=0,totpart=0;
+       int i,p,v1,v2,v3,v4=0;
+
+       mvert = dm->getVertArray(dm);
+       mface = dm->getFaceArray(dm);
+       totface= dm->getNumFaces(dm);
+       totvert= dm->getNumVerts(dm);
+       totpart= psmd->psys->totpart;
+
+       BLI_srandom(psys->seed);
+
+       if(emd->facepa)
+               MEM_freeN(emd->facepa);
+
+       facepa = emd->facepa = MEM_callocN(sizeof(int)*totface, "explode_facepa");
+
+       vertpa = MEM_callocN(sizeof(int)*totvert, "explode_vertpa");
+
+       /* initialize all faces & verts to no particle */
+       for(i=0; i<totface; i++)
+               facepa[i]=totpart;
+
+       for (i=0; i<totvert; i++)
+               vertpa[i]=totpart;
+
+       /* set protected verts */
+       if(emd->vgroup){
+               MDeformVert *dvert = dm->getVertDataArray(dm, CD_MDEFORMVERT);
+               float val;
+               if(dvert){
+                       for(i=0; i<totvert; i++){
+                               val = BLI_frand();
+                               val = (1.0f-emd->protect)*val + emd->protect*0.5f;
+                               if(val < vert_weight(dvert+i,emd->vgroup-1))
+                                       vertpa[i] = -1;
+                       }
+               }
+       }
+
+       /* make tree of emitter locations */
+       tree=BLI_kdtree_new(totpart);
+       for(p=0,pa=psys->particles; p<totpart; p++,pa++){
+               psys_particle_on_dm(ob,dm,psys->part->from,pa->num,pa->num_dmcache,pa->fuv,pa->foffset,co,0,0,0);
+               BLI_kdtree_insert(tree, p, co, NULL);
+       }
+       BLI_kdtree_balance(tree);
+
+       /* set face-particle-indexes to nearest particle to face center */
+       for(i=0,fa=mface; i<totface; i++,fa++){
+               VecAddf(center,mvert[fa->v1].co,mvert[fa->v2].co);
+               VecAddf(center,center,mvert[fa->v3].co);
+               if(fa->v4){
+                       VecAddf(center,center,mvert[fa->v4].co);
+                       VecMulf(center,0.25);
+               }
+               else
+                       VecMulf(center,0.3333f);
+
+               p= BLI_kdtree_find_nearest(tree,center,NULL,NULL);
+
+               v1=vertpa[fa->v1];
+               v2=vertpa[fa->v2];
+               v3=vertpa[fa->v3];
+               if(fa->v4)
+                       v4=vertpa[fa->v4];
+
+               if(v1>=0 && v2>=0 && v3>=0 && (fa->v4==0 || v4>=0))
+                       facepa[i]=p;
+
+               if(v1>=0) vertpa[fa->v1]=p;
+               if(v2>=0) vertpa[fa->v2]=p;
+               if(v3>=0) vertpa[fa->v3]=p;
+               if(fa->v4 && v4>=0) vertpa[fa->v4]=p;
+       }
+
+       if(vertpa) MEM_freeN(vertpa);
+       BLI_kdtree_free(tree);
+}
+static DerivedMesh * explodeModifier_splitEdges(ExplodeModifierData *emd, DerivedMesh *dm){
+       DerivedMesh *splitdm;
+       MFace *mf=0,*df1=0,*df2=0,*df3=0;
+       MFace *mface=CDDM_get_faces(dm);
+       MVert *dupve, *mv;
+       int totvert=dm->getNumVerts(dm);
+       int totface=dm->getNumFaces(dm);
+
+       int *edgesplit = MEM_callocN(sizeof(int)*totvert*totvert,"explode_edgesplit");
+       int *facesplit = MEM_callocN(sizeof(int)*totface,"explode_edgesplit");
+       int *vertpa = MEM_callocN(sizeof(int)*totvert,"explode_vertpa2");
+       int *facepa = emd->facepa;
+       int *fs, totesplit=0,totfsplit=0,totin=0,curdupvert=0,curdupface=0,curdupin=0;
+       int i,j,v1,v2,v3,v4;
+
+       /* recreate vertpa from facepa calculation */
+       for (i=0,mf=mface; i<totface; i++,mf++) {
+               vertpa[mf->v1]=facepa[i];
+               vertpa[mf->v2]=facepa[i];
+               vertpa[mf->v3]=facepa[i];
+               if(mf->v4)
+                       vertpa[mf->v4]=facepa[i];
+       }
+
+       /* mark edges for splitting and how to split faces */
+       for (i=0,mf=mface,fs=facesplit; i<totface; i++,mf++,fs++) {
+               if(mf->v4){
+                       v1=vertpa[mf->v1];
+                       v2=vertpa[mf->v2];
+                       v3=vertpa[mf->v3];
+                       v4=vertpa[mf->v4];
+
+                       if(v1!=v2){
+                               edgesplit[mf->v1*totvert+mf->v2]=edgesplit[mf->v2*totvert+mf->v1]=1;
+                               (*fs)++;
+                       }
+
+                       if(v2!=v3){
+                               edgesplit[mf->v2*totvert+mf->v3]=edgesplit[mf->v3*totvert+mf->v2]=1;
+                               (*fs)++;
+                       }
+
+                       if(v3!=v4){
+                               edgesplit[mf->v3*totvert+mf->v4]=edgesplit[mf->v4*totvert+mf->v3]=1;
+                               (*fs)++;
+                       }
+
+                       if(v1!=v4){
+                               edgesplit[mf->v1*totvert+mf->v4]=edgesplit[mf->v4*totvert+mf->v1]=1;
+                               (*fs)++;
+                       }
+
+                       if(*fs==2){
+                               if((v1==v2 && v3==v4) || (v1==v4 && v2==v3))
+                                       *fs=1;
+                               else if(v1!=v2){
+                                       if(v1!=v4)
+                                               edgesplit[mf->v2*totvert+mf->v3]=edgesplit[mf->v3*totvert+mf->v2]=1;
+                                       else
+                                               edgesplit[mf->v3*totvert+mf->v4]=edgesplit[mf->v4*totvert+mf->v3]=1;
+                               }
+                               else{ 
+                                       if(v1!=v4)
+                                               edgesplit[mf->v1*totvert+mf->v2]=edgesplit[mf->v2*totvert+mf->v1]=1;
+                                       else
+                                               edgesplit[mf->v1*totvert+mf->v4]=edgesplit[mf->v4*totvert+mf->v1]=1;
+                               }
+                       }
+               }
+       }
+
+       /* count splits & reindex */
+       totesplit=totvert;
+       for(j=0; j<totvert; j++){
+               for(i=j+1; i<totvert; i++){
+                       if(edgesplit[j*totvert+i])
+                               edgesplit[j*totvert+i]=edgesplit[i*totvert+j]=totesplit++;
+               }
+       }
+       /* count new faces due to splitting */
+       for(i=0,fs=facesplit; i<totface; i++,fs++){
+               if(*fs==1)
+                       totfsplit+=1;
+               else if(*fs==2)
+                       totfsplit+=2;
+               else if(*fs==3)
+                       totfsplit+=3;
+               else if(*fs==4){
+                       totfsplit+=3;
+
+                       mf=dm->getFaceData(dm,i,CD_MFACE);//CDDM_get_face(dm,i);
+
+                       if(vertpa[mf->v1]!=vertpa[mf->v2] && vertpa[mf->v2]!=vertpa[mf->v3])
+                               totin++;
+               }
+       }
+       
+       splitdm= CDDM_from_template(dm, totesplit+totin, dm->getNumEdges(dm),totface+totfsplit);
+
+       /* copy new faces & verts (is it really this painful with custom data??) */
+       for(i=0; i<totvert; i++){
+               MVert source;
+               MVert *dest;
+               dm->getVert(dm, i, &source);
+               dest = CDDM_get_vert(splitdm, i);
+
+               DM_copy_vert_data(dm, splitdm, i, i, 1);
+               *dest = source;
+       }
+       for(i=0; i<totface; i++){
+               MFace source;
+               MFace *dest;
+               dm->getFace(dm, i, &source);
+               dest = CDDM_get_face(splitdm, i);
+
+               DM_copy_face_data(dm, splitdm, i, i, 1);
+               *dest = source;
+       }
+
+       /* override original facepa (original pointer is saved in caller function) */
+       facepa= MEM_callocN(sizeof(int)*(totface+totfsplit),"explode_facepa");
+       memcpy(facepa,emd->facepa,totface*sizeof(int));
+       emd->facepa=facepa;
+
+       /* create new verts */
+       curdupvert=totvert;
+       for(j=0; j<totvert; j++){
+               for(i=j+1; i<totvert; i++){
+                       if(edgesplit[j*totvert+i]){
+                               mv=CDDM_get_vert(splitdm,j);
+                               dupve=CDDM_get_vert(splitdm,edgesplit[j*totvert+i]);
+
+                               DM_copy_vert_data(splitdm,splitdm,j,edgesplit[j*totvert+i],1);
+
+                               *dupve=*mv;
+
+                               mv=CDDM_get_vert(splitdm,i);
+
+                               VECADD(dupve->co,dupve->co,mv->co);
+                               VecMulf(dupve->co,0.5);
+                       }
+               }
+       }
+
+       /* create new faces */
+       curdupface=totface;
+       curdupin=totesplit;
+       for(i=0,fs=facesplit; i<totface; i++,fs++){
+               if(*fs){
+                       mf=CDDM_get_face(splitdm,i);
+
+                       v1=vertpa[mf->v1];
+                       v2=vertpa[mf->v2];
+                       v3=vertpa[mf->v3];
+                       v4=vertpa[mf->v4];
+                       /* ouch! creating new faces & remapping them to new verts is no fun */
+                       if(*fs==1){
+                               df1=CDDM_get_face(splitdm,curdupface);
+                               DM_copy_face_data(splitdm,splitdm,i,curdupface,1);
+                               *df1=*mf;
+                               curdupface++;
+                               
+                               if(v1==v2){
+                                       df1->v1=edgesplit[mf->v1*totvert+mf->v4];
+                                       df1->v2=edgesplit[mf->v2*totvert+mf->v3];
+                                       mf->v3=df1->v2;
+                                       mf->v4=df1->v1;
+                               }
+                               else{
+                                       df1->v1=edgesplit[mf->v1*totvert+mf->v2];
+                                       df1->v4=edgesplit[mf->v3*totvert+mf->v4];
+                                       mf->v2=df1->v1;
+                                       mf->v3=df1->v4;
+                               }
+
+                               facepa[i]=v1;
+                               facepa[curdupface-1]=v3;
+
+                               test_index_face(df1, &splitdm->faceData, curdupface, (df1->v4 ? 4 : 3));
+                       }
+                       if(*fs==2){
+                               df1=CDDM_get_face(splitdm,curdupface);
+                               DM_copy_face_data(splitdm,splitdm,i,curdupface,1);
+                               *df1=*mf;
+                               curdupface++;
+
+                               df2=CDDM_get_face(splitdm,curdupface);
+                               DM_copy_face_data(splitdm,splitdm,i,curdupface,1);
+                               *df2=*mf;
+                               curdupface++;
+
+                               if(v1!=v2){
+                                       if(v1!=v4){
+                                               df1->v1=edgesplit[mf->v1*totvert+mf->v4];
+                                               df1->v2=edgesplit[mf->v1*totvert+mf->v2];
+                                               df2->v1=df1->v3=mf->v2;
+                                               df2->v3=df1->v4=mf->v4;
+                                               df2->v2=mf->v3;
+
+                                               mf->v2=df1->v2;
+                                               mf->v3=df1->v1;
+
+                                               df2->v4=mf->v4=0;
+
+                                               facepa[i]=v1;
+                                       }
+                                       else{
+                                               df1->v2=edgesplit[mf->v1*totvert+mf->v2];
+                                               df1->v3=edgesplit[mf->v2*totvert+mf->v3];
+                                               df1->v4=mf->v3;
+                                               df2->v2=mf->v3;
+                                               df2->v3=mf->v4;
+
+                                               mf->v1=df1->v2;
+                                               mf->v3=df1->v3;
+
+                                               df2->v4=mf->v4=0;
+
+                                               facepa[i]=v2;
+                                       }
+                                       facepa[curdupface-1]=facepa[curdupface-2]=v3;
+                               }
+                               else{
+                                       if(v1!=v4){
+                                               df1->v3=edgesplit[mf->v3*totvert+mf->v4];
+                                               df1->v4=edgesplit[mf->v1*totvert+mf->v4];
+                                               df1->v2=mf->v3;
+
+                                               mf->v1=df1->v4;
+                                               mf->v2=df1->v3;
+                                               mf->v3=mf->v4;
+
+                                               df2->v4=mf->v4=0;
+
+                                               facepa[i]=v4;
+                                       }
+                                       else{
+                                               df1->v3=edgesplit[mf->v2*totvert+mf->v3];
+                                               df1->v4=edgesplit[mf->v3*totvert+mf->v4];
+                                               df1->v1=mf->v4;
+                                               df1->v2=mf->v2;
+                                               df2->v3=mf->v4;
+
+                                               mf->v1=df1->v4;
+                                               mf->v2=df1->v3;
+
+                                               df2->v4=mf->v4=0;
+
+                                               facepa[i]=v3;
+                                       }
+
+                                       facepa[curdupface-1]=facepa[curdupface-2]=v1;
+                               }
+
+                               test_index_face(df1, &splitdm->faceData, curdupface-2, (df1->v4 ? 4 : 3));
+                               test_index_face(df1, &splitdm->faceData, curdupface-1, (df1->v4 ? 4 : 3));
+                       }
+                       else if(*fs==3){
+                               df1=CDDM_get_face(splitdm,curdupface);
+                               DM_copy_face_data(splitdm,splitdm,i,curdupface,1);
+                               *df1=*mf;
+                               curdupface++;
+
+                               df2=CDDM_get_face(splitdm,curdupface);
+                               DM_copy_face_data(splitdm,splitdm,i,curdupface,1);
+                               *df2=*mf;
+                               curdupface++;
+
+                               df3=CDDM_get_face(splitdm,curdupface);
+                               DM_copy_face_data(splitdm,splitdm,i,curdupface,1);
+                               *df3=*mf;
+                               curdupface++;
+
+                               if(v1==v2){
+                                       df2->v1=df1->v1=edgesplit[mf->v1*totvert+mf->v4];
+                                       df3->v1=df1->v2=edgesplit[mf->v2*totvert+mf->v3];
+                                       df3->v3=df2->v2=df1->v3=edgesplit[mf->v3*totvert+mf->v4];
+                                       df3->v2=mf->v3;
+                                       df2->v3=mf->v4;
+                                       df1->v4=df2->v4=df3->v4=0;
+
+                                       mf->v3=df1->v2;
+                                       mf->v4=df1->v1;
+
+                                       facepa[i]=facepa[curdupface-3]=v1;
+                                       facepa[curdupface-1]=v3;
+                                       facepa[curdupface-2]=v4;
+                               }
+                               else if(v2==v3){
+                                       df3->v1=df2->v3=df1->v1=edgesplit[mf->v1*totvert+mf->v4];
+                                       df2->v2=df1->v2=edgesplit[mf->v1*totvert+mf->v2];
+                                       df3->v2=df1->v3=edgesplit[mf->v3*totvert+mf->v4];
+
+                                       df3->v3=mf->v4;
+                                       df2->v1=mf->v1;
+                                       df1->v4=df2->v4=df3->v4=0;
+
+                                       mf->v1=df1->v2;
+                                       mf->v4=df1->v3;
+
+                                       facepa[i]=facepa[curdupface-3]=v2;
+                                       facepa[curdupface-1]=v4;
+                                       facepa[curdupface-2]=v1;
+                               }
+                               else if(v3==v4){
+                                       df3->v2=df2->v1=df1->v1=edgesplit[mf->v1*totvert+mf->v2];
+                                       df2->v3=df1->v2=edgesplit[mf->v2*totvert+mf->v3];
+                                       df3->v3=df1->v3=edgesplit[mf->v1*totvert+mf->v4];
+
+                                       df3->v1=mf->v1;
+                                       df2->v2=mf->v2;
+                                       df1->v4=df2->v4=df3->v4=0;
+
+                                       mf->v1=df1->v3;
+                                       mf->v2=df1->v2;
+
+                                       facepa[i]=facepa[curdupface-3]=v3;
+                                       facepa[curdupface-1]=v1;
+                                       facepa[curdupface-2]=v2;
+                               }
+                               else{
+                                       df3->v1=df1->v1=edgesplit[mf->v1*totvert+mf->v2];
+                                       df3->v3=df2->v1=df1->v2=edgesplit[mf->v2*totvert+mf->v3];
+                                       df2->v3=df1->v3=edgesplit[mf->v3*totvert+mf->v4];
+
+                                       df3->v2=mf->v2;
+                                       df2->v2=mf->v3;
+                                       df1->v4=df2->v4=df3->v4=0;
+
+                                       mf->v2=df1->v1;
+                                       mf->v3=df1->v3;
+
+                                       facepa[i]=facepa[curdupface-3]=v1;
+                                       facepa[curdupface-1]=v2;
+                                       facepa[curdupface-2]=v3;
+                               }
+
+                               test_index_face(df1, &splitdm->faceData, curdupface-3, (df1->v4 ? 4 : 3));
+                               test_index_face(df1, &splitdm->faceData, curdupface-2, (df1->v4 ? 4 : 3));
+                               test_index_face(df1, &splitdm->faceData, curdupface-1, (df1->v4 ? 4 : 3));
+                       }
+                       else if(*fs==4){
+                               if(v1!=v2 && v2!=v3){
+
+                                       /* set new vert to face center */
+                                       mv=CDDM_get_vert(splitdm,mf->v1);
+                                       dupve=CDDM_get_vert(splitdm,curdupin);
+                                       DM_copy_vert_data(splitdm,splitdm,mf->v1,curdupin,1);
+                                       *dupve=*mv;
+
+                                       mv=CDDM_get_vert(splitdm,mf->v2);
+                                       VECADD(dupve->co,dupve->co,mv->co);
+                                       mv=CDDM_get_vert(splitdm,mf->v3);
+                                       VECADD(dupve->co,dupve->co,mv->co);
+                                       mv=CDDM_get_vert(splitdm,mf->v4);
+                                       VECADD(dupve->co,dupve->co,mv->co);
+                                       VecMulf(dupve->co,0.25);
+
+
+                                       df1=CDDM_get_face(splitdm,curdupface);
+                                       DM_copy_face_data(splitdm,splitdm,i,curdupface,1);
+                                       *df1=*mf;
+                                       curdupface++;
+
+                                       df2=CDDM_get_face(splitdm,curdupface);
+                                       DM_copy_face_data(splitdm,splitdm,i,curdupface,1);
+                                       *df2=*mf;
+                                       curdupface++;
+
+                                       df3=CDDM_get_face(splitdm,curdupface);
+                                       DM_copy_face_data(splitdm,splitdm,i,curdupface,1);
+                                       *df3=*mf;
+                                       curdupface++;
+
+                                       df1->v1=edgesplit[mf->v1*totvert+mf->v2];
+                                       df3->v2=df1->v3=edgesplit[mf->v2*totvert+mf->v3];
+
+                                       df2->v1=edgesplit[mf->v1*totvert+mf->v4];
+                                       df3->v4=df2->v3=edgesplit[mf->v3*totvert+mf->v4];
+
+                                       df3->v1=df2->v2=df1->v4=curdupin;
+
+                                       mf->v2=df1->v1;
+                                       mf->v3=curdupin;
+                                       mf->v4=df2->v1;
+
+                                       curdupin++;
+
+                                       facepa[i]=v1;
+                                       facepa[curdupface-3]=v2;
+                                       facepa[curdupface-2]=v3;
+                                       facepa[curdupface-1]=v4;
+
+                                       test_index_face(df1, &splitdm->faceData, curdupface-3, (df1->v4 ? 4 : 3));
+
+                                       test_index_face(df1, &splitdm->faceData, curdupface-2, (df1->v4 ? 4 : 3));
+                                       test_index_face(df1, &splitdm->faceData, curdupface-1, (df1->v4 ? 4 : 3));
+                               }
+                               else{
+                                       df1=CDDM_get_face(splitdm,curdupface);
+                                       DM_copy_face_data(splitdm,splitdm,i,curdupface,1);
+                                       *df1=*mf;
+                                       curdupface++;
+
+                                       df2=CDDM_get_face(splitdm,curdupface);
+                                       DM_copy_face_data(splitdm,splitdm,i,curdupface,1);
+                                       *df2=*mf;
+                                       curdupface++;
+
+                                       df3=CDDM_get_face(splitdm,curdupface);
+                                       DM_copy_face_data(splitdm,splitdm,i,curdupface,1);
+                                       *df3=*mf;
+                                       curdupface++;
+
+                                       if(v2==v3){
+                                               df1->v1=edgesplit[mf->v1*totvert+mf->v2];
+                                               df3->v1=df1->v2=df1->v3=edgesplit[mf->v2*totvert+mf->v3];
+                                               df2->v1=df1->v4=edgesplit[mf->v1*totvert+mf->v4];
+
+                                               df3->v3=df2->v3=edgesplit[mf->v3*totvert+mf->v4];
+
+                                               df3->v2=mf->v3;
+                                               df3->v4=0;
+
+                                               mf->v2=df1->v1;
+                                               mf->v3=df1->v4;
+                                               mf->v4=0;
+
+                                               facepa[i]=v1;
+                                               facepa[curdupface-3]=facepa[curdupface-2]=v2;
+                                               facepa[curdupface-1]=v3;
+                                       }
+                                       else{
+                                               df3->v1=df2->v1=df1->v2=edgesplit[mf->v1*totvert+mf->v2];
+                                               df2->v4=df1->v3=edgesplit[mf->v3*totvert+mf->v4];
+                                               df1->v4=edgesplit[mf->v1*totvert+mf->v4];
+
+                                               df3->v3=df2->v2=edgesplit[mf->v2*totvert+mf->v3];
+
+                                               df3->v4=0;
+
+                                               mf->v1=df1->v4;
+                                               mf->v2=df1->v3;
+                                               mf->v3=mf->v4;
+                                               mf->v4=0;
+
+                                               facepa[i]=v4;
+                                               facepa[curdupface-3]=facepa[curdupface-2]=v1;
+                                               facepa[curdupface-1]=v2;
+                                       }
+
+                                       test_index_face(df1, &splitdm->faceData, curdupface-3, (df1->v4 ? 4 : 3));
+                                       test_index_face(df1, &splitdm->faceData, curdupface-2, (df1->v4 ? 4 : 3));
+                                       test_index_face(df1, &splitdm->faceData, curdupface-1, (df1->v4 ? 4 : 3));
+                               }
+                       }
+
+                       test_index_face(df1, &splitdm->faceData, i, (df1->v4 ? 4 : 3));
+               }
+       }
+
+       MEM_freeN(edgesplit);
+       MEM_freeN(facesplit);
+       MEM_freeN(vertpa);
+
+       return splitdm;
+
+}
+static DerivedMesh * explodeModifier_explodeMesh(ExplodeModifierData *emd, 
+                                                                                                ParticleSystemModifierData *psmd, Object *ob, 
+                                                                                                DerivedMesh *to_explode)
+{
+       DerivedMesh *explode, *dm=to_explode;
+       MFace *mf=0;
+       MVert *dupvert=0;
+       ParticleSettings *part=psmd->psys->part;
+       ParticleData *pa, *pars=psmd->psys->particles;
+       ParticleKey state;
+       float *vertco=0, imat[4][4];
+       float loc0[3], nor[3];
+       float timestep, cfra;
+       int *facepa=emd->facepa, *vertpa=0;
+       int totdup=0,totvert=0,totface=0,totpart=0;
+       int i, j, v, mindex=0;
+
+       totface= dm->getNumFaces(dm);
+       totvert= dm->getNumVerts(dm);
+       totpart= psmd->psys->totpart;
+
+       timestep= psys_get_timestep(part);
+
+       if(part->flag & PART_GLOB_TIME)
+               cfra=bsystem_time(0,(float)G.scene->r.cfra,0.0);
+       else
+               cfra=bsystem_time(ob,(float)G.scene->r.cfra,0.0);
+
+       /* table for vertice <-> particle relations (row totpart+1 is for yet unexploded verts) */
+       vertpa = MEM_callocN(sizeof(int)*(totpart+1)*totvert, "explode_vertpatab");
+       for(i=0; i<(totpart+1)*totvert; i++)
+               vertpa[i] = -1;
+
+       for (i=0; i<totface; i++) {
+               if(facepa[i]==totpart || cfra <= (pars+facepa[i])->time)
+                       mindex = totpart*totvert;
+               else 
+                       mindex = facepa[i]*totvert;
+
+               mf=CDDM_get_face(dm,i);
+
+               /*set face vertices to exist in particle group*/
+               vertpa[mindex+mf->v1] = 1;
+               vertpa[mindex+mf->v2] = 1;
+               vertpa[mindex+mf->v3] = 1;
+               if(mf->v4)
+                       vertpa[mindex+mf->v4] = 1;
+       }
+
+       /*make new vertice indexes & count total vertices after duplication*/
+       for(i=0; i<(totpart+1)*totvert; i++){
+               if(vertpa[i] != -1)
+                       vertpa[i] = totdup++;
+       }
+
+       /*the final duplicated vertices*/
+       explode= CDDM_from_template(dm, totdup, 0,totface);
+       dupvert= CDDM_get_verts(explode);
+
+       /* getting back to object space */
+       Mat4Invert(imat,ob->obmat);
+
+       psmd->psys->lattice = psys_get_lattice(ob, psmd->psys);
+
+       /*duplicate & displace vertices*/
+       for(i=0, pa=pars; i<=totpart; i++, pa++){
+               if(i!=totpart){
+                       psys_particle_on_emitter(ob, psmd,part->from,pa->num,-1,pa->fuv,pa->foffset,loc0,nor,0,0);
+                       Mat4MulVecfl(ob->obmat,loc0);
+
+                       state.time=cfra;
+                       psys_get_particle_state(ob,psmd->psys,i,&state,1);
+               }
+
+               for(j=0; j<totvert; j++){
+                       v=vertpa[i*totvert+j];
+                       if(v != -1) {
+                               MVert source;
+                               MVert *dest;
+
+                               dm->getVert(dm, j, &source);
+                               dest = CDDM_get_vert(explode,v);
+
+                               DM_copy_vert_data(dm,explode,j,v,1);
+                               *dest = source;
+
+                               if(i!=totpart){
+                                       vertco=CDDM_get_vert(explode,v)->co;
+                                       
+                                       Mat4MulVecfl(ob->obmat,vertco);
+
+                                       VECSUB(vertco,vertco,loc0);
+
+                                       /* apply rotation, size & location */
+                                       QuatMulVecf(state.rot,vertco);
+                                       VecMulf(vertco,pa->size);
+                                       VECADD(vertco,vertco,state.co);
+
+                                       Mat4MulVecfl(imat,vertco);
+                               }
+                       }
+               }
+       }
+
+       /*map new vertices to faces*/
+       for (i=0; i<totface; i++) {
+               MFace source;
+               int orig_v4;
+
+               if(facepa[i]!=totpart)
+               {
+                       pa=pars+facepa[i];
+
+                       if(pa->alive==PARS_UNBORN && (emd->flag&eExplodeFlag_Unborn)==0) continue;
+                       if(pa->alive==PARS_ALIVE && (emd->flag&eExplodeFlag_Alive)==0) continue;
+                       if(pa->alive==PARS_DEAD && (emd->flag&eExplodeFlag_Dead)==0) continue;
+               }
+
+               dm->getFace(dm,i,&source);
+               mf=CDDM_get_face(explode,i);
+               
+               orig_v4 = source.v4;
+
+               if(facepa[i]!=totpart && cfra <= pa->time)
+                       mindex = totpart*totvert;
+               else 
+                       mindex = facepa[i]*totvert;
+
+               source.v1 = vertpa[mindex+source.v1];
+               source.v2 = vertpa[mindex+source.v2];
+               source.v3 = vertpa[mindex+source.v3];
+               if(source.v4)
+                       source.v4 = vertpa[mindex+source.v4];
+
+               DM_copy_face_data(dm,explode,i,i,1);
+
+               *mf = source;
+
+               test_index_face(mf, &explode->faceData, i, (mf->v4 ? 4 : 3));
+       }
+
+
+       /* cleanup */
+       if(vertpa) MEM_freeN(vertpa);
+
+       /* finalization */
+       CDDM_calc_edges(explode);
+       CDDM_calc_normals(explode);
+
+       if(psmd->psys->lattice){
+               end_latt_deform();
+               psmd->psys->lattice=0;
+       }
+
+       return explode;
+}
+
+static ParticleSystemModifierData * explodeModifier_findPrecedingParticlesystem(Object *ob, ModifierData *emd)
+{
+       ModifierData *md;
+       ParticleSystemModifierData *psmd=0;
+
+       for (md=ob->modifiers.first; emd!=md; md=md->next){
+               if(md->type==eModifierType_ParticleSystem)
+                       psmd= (ParticleSystemModifierData*) md;
+       }
+       return psmd;
+}
+static DerivedMesh * explodeModifier_applyModifier(
+                               ModifierData *md, Object *ob, DerivedMesh *derivedData,
+                 int useRenderParams, int isFinalCalc)
+{
+       DerivedMesh *dm = derivedData;
+       ExplodeModifierData *emd= (ExplodeModifierData*) md;
+       ParticleSystemModifierData *psmd=explodeModifier_findPrecedingParticlesystem(ob,md);;
+
+       if(psmd){
+               ParticleSystem * psys=psmd->psys;
+
+               if(psys==0 || psys->totpart==0) return derivedData;
+               if(psys->part==0 || psys->particles==0) return derivedData;
+
+               /* 1. find faces to be exploded if needed */
+               if(emd->facepa==0 || psmd->flag&eParticleSystemFlag_Pars || emd->flag&eExplodeFlag_CalcFaces){
+                       if(psmd->flag & eParticleSystemFlag_Pars)
+                               psmd->flag &= ~eParticleSystemFlag_Pars;
+                       
+                       if(emd->flag & eExplodeFlag_CalcFaces)
+                               emd->flag &= ~eExplodeFlag_CalcFaces;
+
+                       explodeModifier_createFacepa(emd,psmd,ob,derivedData);
+               }
+
+               /* 2. create new mesh */
+               if(emd->flag & eExplodeFlag_EdgeSplit){
+                       int *facepa = emd->facepa;
+                       DerivedMesh *splitdm=explodeModifier_splitEdges(emd,dm);
+                       DerivedMesh *explode=explodeModifier_explodeMesh(emd,psmd,ob,splitdm);
+
+                       MEM_freeN(emd->facepa);
+                       emd->facepa=facepa;
+                       splitdm->release(splitdm);
+                       return explode;
+               }
+               else
+                       return explodeModifier_explodeMesh(emd,psmd,ob,derivedData);
+       }
+       return derivedData;
+}
 /* MeshDeform */
 
 static void meshdeformModifier_initData(ModifierData *md)
@@ -5544,83 +6764,6 @@ static void meshdeformModifier_deformVertsEM(
                dm->release(dm);
 }
 
-
-/* PointCache - example DONT USE SERIOUSLY */
-static void pointCacheModifier_initData(ModifierData *md)
-{
-       PointCacheModifierData *pcm= (PointCacheModifierData*) md;
-
-       pcm->mode= ePointCache_Read; /* read */
-}
-static void pointCacheModifier_freeData(ModifierData *md)
-{
-       PointCacheModifierData *pcm = (PointCacheModifierData*) md;
-}
-static void pointCacheModifier_copyData(ModifierData *md, ModifierData *target)
-{
-       PointCacheModifierData *pcm= (PointCacheModifierData*) md;
-       PointCacheModifierData *tpcm= (PointCacheModifierData*) target;
-
-       tpcm->mode = pcm->mode;
-}
-static int pointCacheModifier_dependsOnTime(ModifierData *md) 
-{
-       return 1;
-}
-CustomDataMask pointCacheModifier_requiredDataMask(ModifierData *md)
-{
-       PointCacheModifierData *pcm= (PointCacheModifierData*) md;
-       CustomDataMask dataMask = 0;
-       return dataMask;
-}
-
-static void pointCacheModifier_deformVerts(
-                                          ModifierData *md, Object *ob, DerivedMesh *derivedData,
-       float (*vertexCos)[3], int numVerts)
-{
-       PointCacheModifierData *pcm = (PointCacheModifierData*) md;
-
-       FILE *fp = NULL;
-       int i;
-       int stack_index = modifiers_indexInObject(ob, md);
-       int totvert;
-       MVert *mvert, *mv;
-       
-       DerivedMesh *dm;
-
-       if(derivedData) dm = CDDM_copy(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);
-       
-       mvert = mv = dm->getVertArray(dm);
-       totvert = dm->getNumVerts(dm);
-                       
-       if (pcm->mode == ePointCache_Read) {
-               fp = PTCache_id_fopen((ID *)ob, 'w', G.scene->r.cfra, stack_index);
-               if (!fp) return;
-               for (mv=mvert, i=0; i<totvert; mv++, i++) {
-                       fwrite(&mv->co, sizeof(float), 3, fp);
-               }
-               fclose(fp);
-       } else if (pcm->mode == ePointCache_Write) {
-               float pt[3];
-               fp = PTCache_id_fopen((ID *)ob, 'r', G.scene->r.cfra, stack_index);
-               if (!fp) return;
-               for (mv=mvert, i=0; i<totvert; mv++, i++) {
-                       float *co = vertexCos[i];
-                       if ((fread(co, sizeof(float), 3, fp)) != 3) {
-                               break;
-                       }
-               }
-               fclose(fp);
-       }
-       
-       if(!derivedData) dm->release(dm);
-}
-
 /***/
 
 static ModifierTypeInfo typeArr[NUM_MODIFIER_TYPES];
@@ -5890,16 +7033,42 @@ ModifierTypeInfo *modifierType_getInfo(ModifierType type)
                mti->updateDepgraph = meshdeformModifier_updateDepgraph;
                mti->deformVerts = meshdeformModifier_deformVerts;
                mti->deformVertsEM = meshdeformModifier_deformVertsEM;
-               
-               mti = INIT_TYPE(PointCache);
+
+               mti = INIT_TYPE(ParticleSystem);
                mti->type = eModifierTypeType_OnlyDeform;
-               mti->flags = eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_RequiresOriginalData;
-               mti->initData = pointCacheModifier_initData;
-               mti->freeData = pointCacheModifier_freeData;
-               mti->copyData = pointCacheModifier_copyData;
-               mti->dependsOnTime = pointCacheModifier_dependsOnTime;
-               mti->requiredDataMask = pointCacheModifier_requiredDataMask;
-               mti->deformVerts = pointCacheModifier_deformVerts;
+               mti->flags = eModifierTypeFlag_AcceptsMesh
+                                       |eModifierTypeFlag_SupportsEditmode
+                                       |eModifierTypeFlag_EnableInEditmode;
+               mti->initData = particleSystemModifier_initData;
+               mti->freeData = particleSystemModifier_freeData;
+               mti->copyData = particleSystemModifier_copyData;
+               mti->deformVerts = particleSystemModifier_deformVerts;
+               mti->deformVertsEM = particleSystemModifier_deformVertsEM;
+               mti->requiredDataMask = particleSystemModifier_requiredDataMask;
+
+               mti = INIT_TYPE(ParticleInstance);
+               mti->type = eModifierTypeType_Constructive;
+               mti->flags = eModifierTypeFlag_AcceptsMesh
+                            | eModifierTypeFlag_SupportsMapping
+                            | eModifierTypeFlag_SupportsEditmode
+                            | eModifierTypeFlag_EnableInEditmode;
+               mti->initData = particleInstanceModifier_initData;
+               mti->copyData = particleInstanceModifier_copyData;
+               mti->dependsOnTime = particleInstanceModifier_dependsOnTime;
+               mti->foreachObjectLink = particleInstanceModifier_foreachObjectLink;
+               mti->applyModifier = particleInstanceModifier_applyModifier;
+               mti->applyModifierEM = particleInstanceModifier_applyModifierEM;
+               mti->updateDepgraph = particleInstanceModifier_updateDepgraph;
+
+               mti = INIT_TYPE(Explode);
+               mti->type = eModifierTypeType_Nonconstructive;
+               mti->flags = eModifierTypeFlag_AcceptsMesh;
+               mti->initData = explodeModifier_initData;
+               mti->freeData = explodeModifier_freeData;
+               mti->copyData = explodeModifier_copyData;
+               mti->dependsOnTime = explodeModifier_dependsOnTime;
+               mti->requiredDataMask = explodeModifier_requiredDataMask;
+               mti->applyModifier = explodeModifier_applyModifier;
 
                typeArrInit = 0;
 #undef INIT_TYPE
@@ -6100,6 +7269,13 @@ ClothModifierData *modifiers_isClothEnabled(Object *ob)
        return clmd;
 }
 
+int modifiers_isParticleEnabled(Object *ob)
+{
+       ModifierData *md = modifiers_findByType(ob, eModifierType_ParticleSystem);
+
+       return (md && md->mode & (eModifierMode_Realtime | eModifierMode_Render));
+}
+
 LinkNode *modifiers_calcDataMasks(ModifierData *md, CustomDataMask dataMask)
 {
        LinkNode *dataMasks = NULL;
@@ -6283,21 +7459,6 @@ int modifiers_isDeformed(Object *ob)
        return 0;
 }
 
-/* checks we only have deform modifiers */
-int modifiers_isDeformedOnly(Object *ob)
-{
-       ModifierData *md = modifiers_getVirtualModifierList(ob);
-       ModifierTypeInfo *mti;
-       for (; md; md=md->next) {
-               mti = modifierType_getInfo(md->type);
-               /* TODO - check the modifier is being used! */
-               if (mti->type != eModifierTypeType_OnlyDeform) {
-                       return 0;
-               }
-       }
-       return 1;
-}
-
 int modifiers_indexInObject(Object *ob, ModifierData *md_seek)
 {
        int i= 0;
@@ -6307,3 +7468,4 @@ int modifiers_indexInObject(Object *ob, ModifierData *md_seek)
        if (!md) return -1; /* modifier isnt in the object */
        return i;
 }
+
index 095d6f525a91644844d4766b2c06d1339fd66996..d9b2ce84fa5e1b40dfa7eba2d2aca0956084f724 100644 (file)
@@ -60,6 +60,7 @@
 #include "DNA_object_force.h"
 #include "DNA_object_fluidsim.h"
 #include "DNA_oops_types.h"
+#include "DNA_particle_types.h"
 #include "DNA_scene_types.h"
 #include "DNA_screen_types.h"
 #include "DNA_space_types.h"
 #include "BKE_mball.h"
 #include "BKE_modifier.h"
 #include "BKE_object.h"
+#include "BKE_particle.h"
 #include "BKE_property.h"
 #include "BKE_sca.h"
 #include "BKE_scene.h"
@@ -164,6 +166,15 @@ void object_free_modifiers(Object *ob)
 
                modifier_free(md);
        }
+
+       /* particle modifiers were freed, so free the particlesystems as well */
+       while(ob->particlesystem.first){
+               ParticleSystem *psys = ob->particlesystem.first;
+
+               BLI_remlink(&ob->particlesystem,psys);
+
+               psys_free(ob,psys);
+       }
 }
 
 /* here we will collect all local displist stuff */
@@ -235,7 +246,11 @@ void free_object(Object *ob)
        
        BPY_free_scriptlink(&ob->scriptlink);
        
-       if(ob->pd) MEM_freeN(ob->pd);
+       if(ob->pd){
+               if(ob->pd->tex)
+                       ob->pd->tex->id.us--;
+               MEM_freeN(ob->pd);
+       }
        if(ob->soft) sbFree(ob->soft);
        if(ob->fluidsimSettings) fluidsimSettingsFree(ob->fluidsimSettings);
 }
@@ -380,6 +395,47 @@ void unlink_object(Object *ob)
                        }
                }
 
+               /* particle systems */
+               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);
+
+                                       if(psys && psys->keyed_ob) {
+                                               tpsys->keyed_ob= psys->keyed_ob;
+                                               tpsys->keyed_psys= psys->keyed_psys;
+                                       }
+                                       else
+                                               tpsys->keyed_ob= NULL;
+
+                                       obt->recalc |= OB_RECALC_DATA;
+                               }
+
+                               if(tpsys->target_ob==ob) {
+                                       tpsys->target_ob= NULL;
+                                       obt->recalc |= OB_RECALC_DATA;
+                               }
+
+                               if(tpsys->part->dup_ob==ob)
+                                       tpsys->part->dup_ob= NULL;
+
+                               if(tpsys->part->flag&PART_STICKY) {
+                                       ParticleData *pa;
+                                       int p;
+
+                                       for(p=0,pa=tpsys->particles; p<tpsys->totpart; p++,pa++) {
+                                               if(pa->stick_ob==ob) {
+                                                       pa->stick_ob= 0;
+                                                       pa->flag &= ~PARS_STICKY;
+                                               }
+                                       }
+                               }
+                       }
+                       if(ob->pd)
+                               obt->recalc |= OB_RECALC_DATA;
+               }
+
                obt= obt->id.next;
        }
        
@@ -946,6 +1002,22 @@ SoftBody *copy_softbody(SoftBody *sb)
        return sbn;
 }
 
+ParticleSystem *copy_particlesystem(ParticleSystem *psys)
+{
+       ParticleSystem *psysn;
+
+       psysn= MEM_dupallocN(psys);
+       psysn->particles= MEM_dupallocN(psys->particles);
+
+       psysn->child= MEM_dupallocN(psys->child);
+
+       psysn->effectors.first= psysn->effectors.last= 0;
+
+       id_us_plus((ID *)psysn->part);
+
+       return psysn;
+}
+
 static void copy_object_pose(Object *obn, Object *ob)
 {
        bPoseChannel *chan;
@@ -981,6 +1053,7 @@ Object *copy_object(Object *ob)
 {
        Object *obn;
        ModifierData *md;
+       ParticleSystem *psys;
        int a;
 
        obn= copy_libblock(ob);
@@ -1031,7 +1104,11 @@ Object *copy_object(Object *ob)
        
        obn->disp.first= obn->disp.last= NULL;
        
-       if(ob->pd) obn->pd= MEM_dupallocN(ob->pd);
+       if(ob->pd){
+               obn->pd= MEM_dupallocN(ob->pd);
+               if(obn->pd->tex)
+                       id_us_plus(&(obn->pd->tex->id));
+       }
        obn->soft= copy_softbody(ob->soft);
 
        /* NT copy fluid sim setting memory */
@@ -1042,6 +1119,23 @@ Object *copy_object(Object *ob)
                        obn->fluidsimSettings->orgMesh = (Mesh *)obn->data;
                }
        }
+
+       obn->particlesystem.first= obn->particlesystem.last= NULL;
+       for(psys=ob->particlesystem.first; psys; psys=psys->next) {
+               ParticleSystemModifierData *psmd;
+               ParticleSystem *npsys= copy_particlesystem(psys);
+
+               BLI_addtail(&obn->particlesystem, npsys);
+
+               /* need to update particle modifiers too */
+               for(md=obn->modifiers.first; md; md=md->next) {
+                       if(md->type==eModifierType_ParticleSystem) {
+                               psmd= (ParticleSystemModifierData*)md;
+                               if(psmd->psys==psys)
+                                       psmd->psys= npsys;
+                       }
+               }
+       }
        
        obn->derivedDeform = NULL;
        obn->derivedFinal = NULL;
@@ -2077,8 +2171,28 @@ void object_handle_update(Object *ob)
                                        where_is_pose(ob);
                                }
                        }
+
+                       if(ob->particlesystem.first) {
+                               ParticleSystem *tpsys, *psys;
+                               
+                               psys= ob->particlesystem.first;
+                               while(psys) {
+                                       if(psys->flag & PSYS_ENABLED) {
+                                               particle_system_update(ob, psys);
+                                               psys= psys->next;
+                                       }
+                                       else if(psys->flag & PSYS_DELETE) {
+                                               tpsys=psys->next;
+                                               BLI_remlink(&ob->particlesystem, psys);
+                                               psys_free(ob,psys);
+                                               psys= tpsys;
+                                       }
+                                       else
+                                               psys= psys->next;
+                               }
+                       }
                }
-       
+
                /* the no-group proxy case, we call update */
                if(ob->proxy && ob->proxy_group==NULL) {
                        /* set pointer in library proxy target, for copying, but restore it */
diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c
new file mode 100644 (file)
index 0000000..c0de190
--- /dev/null
@@ -0,0 +1,2978 @@
+/* particle.c
+ *
+ *
+ * $Id: particle.c $
+ *
+ * ***** BEGIN GPL/BL DUAL 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. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License.  See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * 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) 2007 by Janne Karhu.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include <stdlib.h>
+#include <math.h>
+#include <string.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_scene_types.h"
+#include "DNA_particle_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_object_force.h"
+#include "DNA_texture_types.h"
+#include "DNA_material_types.h"
+#include "DNA_object_types.h"
+#include "DNA_curve_types.h"
+#include "DNA_key_types.h"
+
+#include "BLI_arithb.h"
+#include "BLI_blenlib.h"
+#include "BLI_dynstr.h"
+#include "BLI_kdtree.h"
+#include "BLI_linklist.h"
+#include "BLI_rand.h"
+
+#include "BKE_anim.h"
+
+#include "BKE_global.h"
+#include "BKE_main.h"
+#include "BKE_lattice.h"
+#include "BKE_utildefines.h"
+#include "BKE_displist.h"
+#include "BKE_particle.h"
+#include "BKE_DerivedMesh.h"
+#include "BKE_ipo.h"
+#include "BKE_object.h"
+#include "BKE_softbody.h"
+#include "BKE_material.h"
+#include "BKE_key.h"
+#include "BKE_library.h"
+#include "BKE_depsgraph.h"
+#include "BKE_bad_level_calls.h"
+#include "BKE_modifier.h"
+
+#include "blendef.h"
+#include "RE_render_ext.h"
+
+static void key_from_object(Object *ob, ParticleKey *key);
+static void get_cpa_texture(DerivedMesh *dm, Material *ma, int face_index,
+                               float *fuv, float *orco, ParticleTexture *ptex, int event);
+
+/* few helpers for countall etc. */
+int count_particles(ParticleSystem *psys){
+       ParticleSettings *part=psys->part;
+       ParticleData *pa;
+       int tot=0,p;
+
+       for(p=0,pa=psys->particles; p<psys->totpart; p++,pa++){
+               if(pa->alive == PARS_KILLED);
+               else if(pa->alive == PARS_UNBORN && (part->flag & PART_UNBORN)==0);
+               else if(pa->alive == PARS_DEAD && (part->flag & PART_DIED)==0);
+               else if(pa->flag & (PARS_UNEXIST+PARS_NO_DISP));
+               else tot++;
+       }
+       return tot;
+}
+int count_particles_mod(ParticleSystem *psys, int totgr, int cur){
+       ParticleSettings *part=psys->part;
+       ParticleData *pa;
+       int tot=0,p;
+
+       for(p=0,pa=psys->particles; p<psys->totpart; p++,pa++){
+               if(pa->alive == PARS_KILLED);
+               else if(pa->alive == PARS_UNBORN && (part->flag & PART_UNBORN)==0);
+               else if(pa->alive == PARS_DEAD && (part->flag & PART_DIED)==0);
+               else if(pa->flag & (PARS_UNEXIST+PARS_NO_DISP));
+               else if(p%totgr==cur) tot++;
+       }
+       return tot;
+}
+int psys_count_keys(ParticleSystem *psys)
+{
+       ParticleData *pa;
+       int i, totpart=psys->totpart, totkey=0;
+
+       for(i=0, pa=psys->particles; i<totpart; i++, pa++)
+               totkey += pa->totkey;
+
+       return totkey;
+}
+/* remember to free the pointer returned from this! */
+char *psys_menu_string(Object *ob, int for_sb)
+{
+       ParticleSystem *psys;
+       DynStr *ds;
+       char *str, num[6];
+       int i;
+
+       ds = BLI_dynstr_new();
+
+       if(for_sb)
+               BLI_dynstr_append(ds, "|Object%x-1");
+       
+       for(i=0,psys=ob->particlesystem.first; psys; i++,psys=psys->next){
+
+               BLI_dynstr_append(ds, "|");
+               sprintf(num,"%i. ",i+1);
+               BLI_dynstr_append(ds, num);
+               BLI_dynstr_append(ds, psys->part->id.name+2);
+               sprintf(num,"%%x%i",i+1);
+               BLI_dynstr_append(ds, num);
+       }
+       
+       str = BLI_dynstr_get_cstring(ds);
+
+       BLI_dynstr_free(ds);
+
+       return str;
+}
+/************************************************/
+/*                     Getting stuff                                           */
+/************************************************/
+/* get object's active particle system safely */
+ParticleSystem *psys_get_current(Object *ob)
+{
+       ParticleSystem *psys;
+       if(ob==0) return 0;
+
+       for(psys=ob->particlesystem.first; psys; psys=psys->next){
+               if(psys->flag & PSYS_CURRENT)
+                       return psys;
+       }
+       
+       return 0;
+}
+short psys_get_current_num(Object *ob)
+{
+       ParticleSystem *psys;
+       short i;
+
+       if(ob==0) return 0;
+
+       for(psys=ob->particlesystem.first, i=0; psys; psys=psys->next, i++)
+               if(psys->flag & PSYS_CURRENT)
+                       return i;
+       
+       return i;
+}
+/* change object's active particle system */
+void psys_change_act(void *ob_v, void *act_v)
+{
+       Object *ob = ob_v;
+       ParticleSystem *npsys, *psys;
+       short act = *((short*)act_v)-1;
+
+       if(act>=0){
+               npsys=BLI_findlink(&ob->particlesystem,act);
+               psys=psys_get_current(ob);
+
+               if(psys)
+                       psys->flag &= ~PSYS_CURRENT;
+               if(npsys)
+                       npsys->flag |= PSYS_CURRENT;
+       }
+}
+Object *psys_get_lattice(Object *ob, ParticleSystem *psys)
+{
+       Object *lattice=0;
+       
+       if(!psys_in_edit_mode(psys)==0){
+
+               ModifierData *md = (ModifierData*)psys_get_modifier(ob,psys);
+
+               for(; md; md=md->next){
+                       if(md->type==eModifierType_Lattice){
+                               LatticeModifierData *lmd = (LatticeModifierData *)md;
+                               lattice=lmd->object;
+                               break;
+                       }
+               }
+               if(lattice)
+                       init_latt_deform(lattice,0);
+       }
+
+       return lattice;
+}
+void psys_disable_all(Object *ob)
+{
+       ParticleSystem *psys=ob->particlesystem.first;
+
+       for(; psys; psys=psys->next)
+               psys->flag &= ~PSYS_ENABLED;
+}
+void psys_enable_all(Object *ob)
+{
+       ParticleSystem *psys=ob->particlesystem.first;
+
+       for(; psys; psys=psys->next)
+               psys->flag |= PSYS_ENABLED;
+}
+int psys_ob_has_hair(Object *ob)
+{
+       ParticleSystem *psys = ob->particlesystem.first;
+
+       for(; psys; psys=psys->next)
+               if(psys->part->type == PART_HAIR)
+                       return 1;
+
+       return 0;
+}
+int psys_in_edit_mode(ParticleSystem *psys)
+{
+       return ((G.f & G_PARTICLEEDIT) && psys==psys_get_current(OBACT) && psys->edit);
+}
+
+/************************************************/
+/*                     Freeing stuff                                           */
+/************************************************/
+void psys_free_settings(ParticleSettings *part)
+{
+       if(part->pd)
+               MEM_freeN(part->pd);
+}
+void free_hair(ParticleSystem *psys)
+{
+       ParticleData *pa;
+       int i, totpart=psys->totpart;
+
+       for(i=0, pa=psys->particles; i<totpart; i++, pa++) {
+               if(pa->hair)
+                       MEM_freeN(pa->hair);
+               pa->hair = NULL;
+       }
+
+       psys->flag &= ~PSYS_HAIR_DONE;
+}
+void free_keyed_keys(ParticleSystem *psys)
+{
+       if(psys->particles && psys->particles->keys)
+               MEM_freeN(psys->particles->keys);
+}
+void free_child_path_cache(ParticleSystem *psys)
+{
+
+       if(psys->childcache){
+               if(psys->childcache[0])
+                       MEM_freeN(psys->childcache[0]);
+
+               MEM_freeN(psys->childcache);
+
+               psys->childcache = NULL;
+               psys->totchildcache = 0;
+       }
+}
+void psys_free_path_cache(ParticleSystem *psys)
+{
+       if(psys->pathcache){
+               if(psys->pathcache[0])
+                       MEM_freeN(psys->pathcache[0]);
+
+               MEM_freeN(psys->pathcache);
+
+               psys->pathcache = NULL;
+               psys->totcached = 0;
+       }
+       free_child_path_cache(psys);
+}
+/* free everything */
+void psys_free(Object *ob, ParticleSystem * psys)
+{
+       if(psys){
+               if(ob->particlesystem.first == NULL && G.f & G_PARTICLEEDIT)
+                       G.f &= ~G_PARTICLEEDIT;
+
+               psys_free_path_cache(psys);
+
+               free_hair(psys);
+
+               free_keyed_keys(psys);
+
+               PE_free_particle_edit(psys);
+
+               if(psys->particles){
+                       MEM_freeN(psys->particles);
+                       psys->particles = 0;
+                       psys->totpart = 0;
+               }
+
+               if(psys->child){
+                       MEM_freeN(psys->child);
+                       psys->child = 0;
+                       psys->totchild = 0;
+               }
+
+               if(psys->effectors.first)
+                       psys_end_effectors(psys);
+
+               if(psys->part){
+                       psys->part->id.us--;            
+                       psys->part=0;
+               }
+
+               if(psys->soft){
+                       sbFree(psys->soft);
+                       psys->soft = 0;
+               }
+
+               MEM_freeN(psys);
+       }
+}
+
+/************************************************/
+/*                     Interpolated Particles                          */
+/************************************************/
+static float interpolate_particle_value(float v1, float v2, float v3, float v4, float *w, int four)
+{
+       float value;
+
+       value= w[0]*v1 + w[1]*v2 + w[2]*v3;
+       if(four)
+               value += w[3]*v4;
+       
+       return value;
+}
+static void weighted_particle_vector(float *v1, float *v2, float *v3, float *v4, float *weights, float *vec)
+{
+       vec[0]= weights[0]*v1[0] + weights[1]*v2[0] + weights[2]*v3[0] + weights[3]*v4[0];
+       vec[1]= weights[0]*v1[1] + weights[1]*v2[1] + weights[2]*v3[1] + weights[3]*v4[1];
+       vec[2]= weights[0]*v1[2] + weights[1]*v2[2] + weights[2]*v3[2] + weights[3]*v4[2];
+}
+static void interpolate_particle(short type, ParticleKey keys[4], float dt, ParticleKey *result)
+{
+       float t[4];
+
+       if(type<0) {
+               VecfCubicInterpol(keys[1].co, keys[1].vel, keys[2].co, keys[2].vel, dt, result->co, result->vel);
+       }
+       else {
+               set_four_ipo(dt, t, type);
+
+               weighted_particle_vector(keys[0].co, keys[1].co, keys[2].co, keys[3].co, t, result->co);
+
+               //if(ve){
+               //      if(dt>0.999f){
+               //              set_four_ipo(dt+0.001f,t,ipo_type);
+               //              weighted_particle_vector(key0->co,key1->co,key2->co,key3->co,t,temp);
+               //              VECSUB(ve,temp,co);
+               //      }
+               //      else{
+               //              set_four_ipo(dt-0.001f,t,ipo_type);
+               //              weighted_particle_vector(key0->co,key1->co,key2->co,key3->co,t,temp);
+               //              VECSUB(ve,co,temp);
+               //      }
+               //}
+       }
+}
+
+
+
+/************************************************/
+/*                     Particles on a dm                                       */
+/************************************************/
+/* interpolate a location on a face based on face coordinates */
+void psys_interpolate_face(MVert *mvert, MFace *mface, MTFace *tface, float *w, float *vec, float *nor, float *utan, float *vtan){
+       float *v1=0, *v2=0, *v3=0, *v4=0;
+       float e1[3],e2[3],s1,s2,t1,t2;
+       float *uv1, *uv2, *uv3, *uv4;
+       float n1[3], n2[3], n3[3], n4[3];
+       float tuv[4][2];
+
+       v1= (mvert+mface->v1)->co;
+       v2= (mvert+mface->v2)->co;
+       v3= (mvert+mface->v3)->co;
+       VECCOPY(n1,(mvert+mface->v1)->no);
+       VECCOPY(n2,(mvert+mface->v2)->no);
+       VECCOPY(n3,(mvert+mface->v3)->no);
+       Normalize(n1);
+       Normalize(n2);
+       Normalize(n3);
+
+       if(mface->v4) {
+               v4= (mvert+mface->v4)->co;
+               VECCOPY(n4,(mvert+mface->v4)->no);
+               Normalize(n4);
+               
+               vec[0]= w[0]*v1[0] + w[1]*v2[0] + w[2]*v3[0] + w[3]*v4[0];
+               vec[1]= w[0]*v1[1] + w[1]*v2[1] + w[2]*v3[1] + w[3]*v4[1];
+               vec[2]= w[0]*v1[2] + w[1]*v2[2] + w[2]*v3[2] + w[3]*v4[2];
+
+               if(nor){
+                       if(mface->flag & ME_SMOOTH){
+                               nor[0]= w[0]*n1[0] + w[1]*n2[0] + w[2]*n3[0] + w[3]*n4[0];
+                               nor[1]= w[0]*n1[1] + w[1]*n2[1] + w[2]*n3[1] + w[3]*n4[1];
+                               nor[2]= w[0]*n1[2] + w[1]*n2[2] + w[2]*n3[2] + w[3]*n4[2];
+                       }
+                       else
+                               CalcNormFloat4(v1,v2,v3,v4,nor);
+               }
+       }
+       else {
+               vec[0]= w[0]*v1[0] + w[1]*v2[0] + w[2]*v3[0];
+               vec[1]= w[0]*v1[1] + w[1]*v2[1] + w[2]*v3[1];
+               vec[2]= w[0]*v1[2] + w[1]*v2[2] + w[2]*v3[2];
+               
+               if(nor){
+                       if(mface->flag & ME_SMOOTH){
+                               nor[0]= w[0]*n1[0] + w[1]*n2[0] + w[2]*n3[0];
+                               nor[1]= w[0]*n1[1] + w[1]*n2[1] + w[2]*n3[1];
+                               nor[2]= w[0]*n1[2] + w[1]*n2[2] + w[2]*n3[2];
+                       }
+                       else
+                               CalcNormFloat(v1,v2,v3,nor);
+               }
+       }
+       
+       /* calculate tangent vectors */
+       if(utan && vtan){
+               if(tface){
+                       uv1= tface->uv[0];
+                       uv2= tface->uv[1];
+                       uv3= tface->uv[2];
+                       uv4= tface->uv[3];
+               }
+               else{
+                       uv1= tuv[0]; uv2= tuv[1]; uv3= tuv[2]; uv4= tuv[3];
+                       spheremap(v1[0], v1[1], v1[2], uv1, uv1+1);
+                       spheremap(v2[0], v2[1], v2[2], uv2, uv2+1);
+                       spheremap(v3[0], v3[1], v3[2], uv3, uv3+1);
+                       if(v4)
+                               spheremap(v4[0], v4[1], v4[2], uv4, uv4+1);
+               }
+
+               if(v4){
+                       s1= uv3[0] - uv1[0];
+                       s2= uv4[0] - uv1[0];
+
+                       t1= uv3[1] - uv1[1];
+                       t2= uv4[1] - uv1[1];
+
+                       VecSubf(e1, v3, v1);
+                       VecSubf(e2, v4, v1);
+               }
+               else{
+                       s1= uv2[0] - uv1[0];
+                       s2= uv3[0] - uv1[0];
+
+                       t1= uv2[1] - uv1[1];
+                       t2= uv3[1] - uv1[1];
+
+                       VecSubf(e1, v2, v1);
+                       VecSubf(e2, v3, v1);
+               }
+
+               vtan[0] = (s1*e2[0] - s2*e1[0]);
+               vtan[1] = (s1*e2[1] - s2*e1[1]);
+               vtan[2] = (s1*e2[2] - s2*e1[2]);
+
+               utan[0] = (t1*e2[0] - t2*e1[0]);
+               utan[1] = (t1*e2[1] - t2*e1[1]);
+               utan[2] = (t1*e2[2] - t2*e1[2]);
+       }
+}
+void psys_interpolate_uvs(MTFace *tface, int quad, float *w, float *uvco){
+       float v10= tface->uv[0][0];
+       float v11= tface->uv[0][1];
+       float v20= tface->uv[1][0];
+       float v21= tface->uv[1][1];
+       float v30= tface->uv[2][0];
+       float v31= tface->uv[2][1];
+       float v40,v41;
+
+       if(quad) {
+               v40= tface->uv[3][0];
+               v41= tface->uv[3][1];
+
+               uvco[0]= w[0]*v10 + w[1]*v20 + w[2]*v30 + w[3]*v40;
+               uvco[1]= w[0]*v11 + w[1]*v21 + w[2]*v31 + w[3]*v41;
+       }
+       else {
+               uvco[0]= w[0]*v10 + w[1]*v20 + w[2]*v30;
+               uvco[1]= w[0]*v11 + w[1]*v21 + w[2]*v31;
+       }
+}
+float psys_interpolate_value_from_verts(DerivedMesh *dm, short from, int index, float *fw, float *values)
+{
+       if(values==0)
+               return 0.0;
+
+       switch(from){
+               case PART_FROM_VERT:
+                       return values[index];
+               case PART_FROM_FACE:
+               case PART_FROM_VOLUME:
+               {
+                       MFace *mf=dm->getFaceData(dm,index,CD_MFACE);
+                       return interpolate_particle_value(values[mf->v1],values[mf->v2],values[mf->v3],values[mf->v4],fw,mf->v4);
+               }
+                       
+       }
+       return 0.0;
+}
+
+/* conversion of pa->fw to origspace layer coordinates */
+static void psys_w_to_origspace(float *w, float *uv)
+{
+       uv[0]= w[1] + w[2];
+       uv[1]= w[2] + w[3];
+}
+
+/* conversion of pa->fw to weights in face from origspace */
+static void psys_origspace_to_w(OrigSpaceFace *osface, int quad, float *w, float *neww)
+{
+       float v[4][3], co[3];
+
+       v[0][0]= osface->uv[0][0]; v[0][1]= osface->uv[0][1]; v[0][2]= 0.0f;
+       v[1][0]= osface->uv[1][0]; v[1][1]= osface->uv[1][1]; v[1][2]= 0.0f;
+       v[2][0]= osface->uv[2][0]; v[2][1]= osface->uv[2][1]; v[2][2]= 0.0f;
+
+       psys_w_to_origspace(w, co);
+       co[2]= 0.0f;
+       
+       if(quad) {
+               v[3][0]= osface->uv[3][0]; v[3][1]= osface->uv[3][1]; v[3][2]= 0.0f;
+               MeanValueWeights(v, 4, co, neww);
+       }
+       else {
+               MeanValueWeights(v, 3, co, neww);
+               neww[3]= 0.0f;
+       }
+}
+
+/* find the derived mesh face for a particle, set the mf passed.
+This is slow, can be optimized but only for many lookups, return the face lookup index*/
+int psys_particle_dm_face_lookup(Object *ob, DerivedMesh *dm, int index, float *fw, struct LinkNode *node)
+{
+       Mesh *me= (Mesh*)ob->data;
+       MFace *mface;
+       OrigSpaceFace *osface;
+       int *origindex;
+       int quad, findex, totface;
+       float uv[2], (*faceuv)[2];
+
+       mface = dm->getFaceDataArray(dm, CD_MFACE);
+       origindex = dm->getFaceDataArray(dm, CD_ORIGINDEX);
+       osface = dm->getFaceDataArray(dm, CD_ORIGSPACE);
+
+       totface = dm->getNumFaces(dm);
+       
+       if(osface==NULL || origindex==NULL) {
+               /* Assume we dont need osface data */
+               if (index <totface) {
+                       printf("\tNO CD_ORIGSPACE, assuming not needed\n");
+                       return index;
+               } else {
+                       printf("\tNO CD_ORIGSPACE, error out of range\n");
+                       return DMCACHE_NOTFOUND;
+               }
+       }
+       else if(index >= me->totface)
+               return DMCACHE_NOTFOUND; /* index not in the original mesh */
+
+       psys_w_to_origspace(fw, uv);
+       
+       if(node) { /* we have a linked list of faces that we use, faster! */
+               for(;node; node=node->next) {
+                       findex= (int)node->link;
+                       faceuv= osface[findex].uv;
+                       quad= mface[findex].v4;
+
+                       /* check that this intersects - Its possible this misses :/ -
+                        * could also check its not between */
+                       if(quad) {
+                               if(IsectPQ2Df(uv, faceuv[0], faceuv[1], faceuv[2], faceuv[3]))
+                                       return findex;
+                       }
+                       else if(IsectPT2Df(uv, faceuv[0], faceuv[1], faceuv[2]))
+                               return findex;
+               }
+       }
+       else { /* if we have no node, try every face */
+               for(findex=0; findex<totface; findex++) {
+                       if(origindex[findex] == index) {
+                               faceuv= osface[findex].uv;
+                               quad= mface[findex].v4;
+
+                               /* check that this intersects - Its possible this misses :/ -
+                                * could also check its not between */
+                               if(quad) {
+                                       if(IsectPQ2Df(uv, faceuv[0], faceuv[1], faceuv[2], faceuv[3]))
+                                               return findex;
+                               }
+                               else if(IsectPT2Df(uv, faceuv[0], faceuv[1], faceuv[2]))
+                                       return findex;
+                       }
+               }
+       }
+
+       return DMCACHE_NOTFOUND;
+}
+
+/* interprets particle data to get a point on a mesh in object space */
+#define PARTICLE_ERROR(_nor, _vec) _vec[0]=_vec[1]=_vec[2]=0.0; if(_nor){ _nor[0]=_nor[1]=0.0; _nor[2]=1.0; }
+void psys_particle_on_dm(Object *ob, DerivedMesh *dm, int from, int index, int index_dmcache, float *fw, float foffset, float *vec, float *nor, float *utan, float *vtan)
+{
+       if(index < 0){ /* 'no dm' error has happened! */
+               PARTICLE_ERROR(nor, vec);
+               return;
+       }
+
+       if (dm->deformedOnly || index_dmcache == DMCACHE_ISCHILD) {
+               /* this works for meshes with deform verts only - constructive modifiers wont work properly*/
+               float temp1[3];
+
+               if(index_dmcache == DMCACHE_ISCHILD && index >= dm->getNumFaces(dm)) {
+                       PARTICLE_ERROR(nor, vec);
+                       return;
+               }
+
+               if(from == PART_FROM_VERT) {
+                       dm->getVertCo(dm,index,vec);
+                       if(nor){
+                               dm->getVertNo(dm,index,nor);
+                               Normalize(nor);
+                       }
+               }
+               else { /* PART_FROM_FACE / PART_FROM_VOLUME */
+                       MFace *mface=dm->getFaceData(dm,index,CD_MFACE);
+                       MTFace *mtface=0;
+                       MVert *mvert=dm->getVertDataArray(dm,CD_MVERT);
+                       int uv_index=CustomData_get_active_layer_index(&dm->faceData,CD_MTFACE);
+
+                       if(uv_index>=0){
+                               CustomDataLayer *layer=&dm->faceData.layers[uv_index];
+                               mtface= &((MTFace*)layer->data)[index];
+                       }
+
+                       if(from==PART_FROM_VOLUME){
+                               psys_interpolate_face(mvert,mface,mtface,fw,vec,temp1,utan,vtan);
+                               if(nor)
+                                       VECCOPY(nor,temp1);
+                               Normalize(temp1);
+                               VecMulf(temp1,-foffset);
+                               VECADD(vec,vec,temp1);
+                       }
+                       else
+                               psys_interpolate_face(mvert,mface,mtface,fw,vec,nor,utan,vtan);
+               }
+       } else {
+               /* Need to support constructive modifiers, this is a bit more tricky
+                       we need a customdata layer like UV's so we can position the particle */
+               
+               /* Only face supported at the moment */
+               if (from==PART_FROM_FACE) {
+                       /* find a face on the derived mesh that uses this face */
+                       Mesh *me= (Mesh*)ob->data;
+                       MVert *mvert;
+                       MFace *mface;
+                       MTFace *mtface;
+                       OrigSpaceFace *osface;
+                       int *origindex;
+                       float fw_mod[4];
+                       int i, totface;
+                       
+                       mvert= dm->getVertDataArray(dm,CD_MVERT);
+
+                       osface= dm->getFaceDataArray(dm, CD_ORIGSPACE);
+                       origindex= dm->getFaceDataArray(dm, CD_ORIGINDEX);
+
+                       /* For this to work we need origindex and OrigSpace coords */
+                       if(origindex==NULL || osface==NULL || index>=me->totface) {
+                               PARTICLE_ERROR(nor, vec);
+                               return;
+                       }
+                       
+                       if (index_dmcache == DMCACHE_NOTFOUND)
+                               i = psys_particle_dm_face_lookup(ob, dm, index, fw, (LinkNode*)NULL);
+                       else
+                               i = index_dmcache;
+
+                       totface = dm->getNumFaces(dm);
+
+                       /* Any time this happens, and the face has not been removed,
+                       * its a BUG watch out for this error! */
+                       if (i==-1) {
+                               printf("Cannot find original face %i\n", index);
+                               PARTICLE_ERROR(nor, vec);
+                               return;
+                       }
+                       else if(i >= totface)
+                               return;
+
+                       mface= dm->getFaceData(dm, i, CD_MFACE);
+                       mtface= dm->getFaceData(dm, i, CD_MTFACE); 
+                       osface += i;
+
+                       /* we need to modify the original weights to become weights for
+                        * the derived mesh face */
+                       psys_origspace_to_w(osface, mface->v4, fw, fw_mod);
+                       psys_interpolate_face(mvert,mface,mtface,fw_mod,vec,nor,utan,vtan);
+               }
+               else {
+                       /* TODO PARTICLE - support verts and volume */
+                       PARTICLE_ERROR(nor, vec);
+               }
+       }
+}
+#undef PARTICLE_ERROR
+
+ParticleSystemModifierData *psys_get_modifier(Object *ob, ParticleSystem *psys)
+{
+       ModifierData *md;
+       ParticleSystemModifierData *psmd;
+
+       for(md=ob->modifiers.first; md; md=md->next){
+               if(md->type==eModifierType_ParticleSystem){
+                       psmd= (ParticleSystemModifierData*) md;
+                       if(psmd->psys==psys){
+                               return psmd;
+                       }
+               }
+       }
+       return 0;
+}
+/************************************************/
+/*                     Particles on a shape                            */
+/************************************************/
+/* ready for future use */
+void psys_particle_on_shape(int distr, int index, float *fuv, float *vec, float *nor, float *utan, float *vtan)
+{
+       /* TODO */
+       float zerovec[3]={0.0f,0.0f,0.0f};
+       if(vec){
+               VECCOPY(vec,zerovec);
+       }
+       if(nor){
+               VECCOPY(nor,zerovec);
+       }
+       if(utan){
+               VECCOPY(utan,zerovec);
+       }
+       if(vtan){
+               VECCOPY(vtan,zerovec);
+       }
+}
+/************************************************/
+/*                     Particles on emitter                            */
+/************************************************/
+void psys_particle_on_emitter(Object *ob, ParticleSystemModifierData *psmd, int from, int index, int index_dmcache, float *fuv, float foffset, float *vec, float *nor, float *utan, float *vtan){
+       if(psmd){
+               if(psmd->psys->part->distr==PART_DISTR_GRID){
+                       if(vec){
+                               VECCOPY(vec,fuv);
+                       }
+                       return;
+               }
+               /* we cant use the num_dmcache */
+               psys_particle_on_dm(ob, psmd->dm,from,index,index_dmcache,fuv,foffset,vec,nor,utan,vtan);
+       }
+       else
+               psys_particle_on_shape(from,index,fuv,vec,nor,utan,vtan);
+
+}
+/************************************************/
+/*                     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;
+       int i;
+       
+       if(dvert) {
+               dw= dvert->dw;
+               for(i= dvert->totweight; i>0; i--, dw++) {
+                       if(dw->def_nr == group) return dw->weight;
+                       if(i==1) break; /*otherwise dw will point to somewhere it shouldn't*/
+               }
+       }
+       return 0.0;
+}
+static void do_prekink(ParticleKey *state, ParticleKey *par, float *par_rot, float time, float freq, float shape, float amplitude, short type, short axis, float obmat[][4])
+{
+       float vec[3]={0.0,0.0,0.0}, q1[4]={1,0,0,0},*q2;
+       float t;
+
+       CLAMP(time,0.0,1.0);
+
+       if(shape!=0.0f && type!=PART_KINK_BRAID) {
+               if(shape<0.0f)
+                       time= (float)pow(time, 1.0+shape);
+               else
+                       time= (float)pow(time, 1.0/(1.0-shape));
+       }
+
+       t=time;
+
+       t*=(float)M_PI*freq;
+
+       if(par==0) return;
+
+       switch(type){
+               case PART_KINK_CURL:
+                       vec[axis]=1.0;
+                       if(par_rot)
+                               q2=par_rot;
+                       else{
+                               q2=vectoquat(par->vel,axis,(axis+1)%3);
+                       }
+                       QuatMulVecf(q2,vec);
+                       VecMulf(vec,amplitude);
+                       VECADD(state->co,state->co,vec);
+
+                       VECSUB(vec,state->co,par->co);
+
+                       if(t!=0.0)
+                               VecRotToQuat(par->vel,t,q1);
+                       
+                       QuatMulVecf(q1,vec);
+                       
+                       VECADD(state->co,par->co,vec);
+                       break;
+               case PART_KINK_RADIAL:
+                       VECSUB(vec,state->co,par->co);
+
+                       Normalize(vec);
+                       VecMulf(vec,amplitude*(float)sin(t));
+
+                       VECADD(state->co,state->co,vec);
+                       break;
+               case PART_KINK_WAVE:
+                       vec[axis]=1.0;
+                       if(obmat)
+                               Mat4MulVecfl(obmat,vec);
+
+                       if(par_rot)
+                               QuatMulVecf(par_rot,vec);
+
+                       Projf(q1,vec,par->vel);
+                       
+                       VECSUB(vec,vec,q1);
+                       Normalize(vec);
+
+                       VecMulf(vec,amplitude*(float)sin(t));
+
+                       VECADD(state->co,state->co,vec);
+                       break;
+               case PART_KINK_BRAID:
+                       if(par){
+                               float y_vec[3]={0.0,1.0,0.0};
+                               float z_vec[3]={0.0,0.0,1.0};
+                               float vec_from_par[3], vec_one[3], radius, state_co[3];
+                               float inp_y,inp_z,length;
+                               
+                               if(par_rot)
+                                       q2=par_rot;
+                               else
+                                       q2=vectoquat(par->vel,axis,(axis+1)%3);
+                               QuatMulVecf(q2,y_vec);
+                               QuatMulVecf(q2,z_vec);
+                               
+                               VECSUB(vec_from_par,state->co,par->co);
+                               VECCOPY(vec_one,vec_from_par);
+                               radius=Normalize(vec_one);
+
+                               inp_y=Inpf(y_vec,vec_one);
+                               inp_z=Inpf(z_vec,vec_one);
+
+                               if(inp_y>0.5){
+                                       VECCOPY(state_co,y_vec);
+
+                                       VecMulf(y_vec,amplitude*(float)cos(t));
+                                       VecMulf(z_vec,amplitude/2.0f*(float)sin(2.0f*t));
+                               }
+                               else if(inp_z>0.0){
+                                       VECCOPY(state_co,z_vec);
+                                       VecMulf(state_co,(float)sin(M_PI/3.0f));
+                                       VECADDFAC(state_co,state_co,y_vec,-0.5f);
+
+                                       VecMulf(y_vec,-amplitude*(float)cos(t + M_PI/3.0f));
+                                       VecMulf(z_vec,amplitude/2.0f*(float)cos(2.0f*t + M_PI/6.0f));
+                               }
+                               else{
+                                       VECCOPY(state_co,z_vec);
+                                       VecMulf(state_co,-(float)sin(M_PI/3.0f));
+                                       VECADDFAC(state_co,state_co,y_vec,-0.5f);
+
+                                       VecMulf(y_vec,amplitude*(float)-sin(t+M_PI/6.0f));
+                                       VecMulf(z_vec,amplitude/2.0f*(float)-sin(2.0f*t+M_PI/3.0f));
+                               }
+
+                               VecMulf(state_co,amplitude);
+                               VECADD(state_co,state_co,par->co);
+                               VECSUB(vec_from_par,state->co,state_co);
+
+                               length=Normalize(vec_from_par);
+                               VecMulf(vec_from_par,MIN2(length,amplitude/2.0f));
+
+                               VECADD(state_co,par->co,y_vec);
+                               VECADD(state_co,state_co,z_vec);
+                               VECADD(state_co,state_co,vec_from_par);
+
+                               shape=(2.0f*(float)M_PI)*(1.0f+shape);
+
+                               if(t<shape){
+                                       shape=t/shape;
+                                       shape=(float)sqrt((double)shape);
+                                       VecLerpf(state->co,state->co,state_co,shape);
+                               }
+                               else{
+                                       VECCOPY(state->co,state_co);
+                               }
+                       }
+                       break;
+               //case PART_KINK_ROT:
+               //      vec[axis]=1.0;
+
+               //      QuatMulVecf(par->rot,vec);
+
+               //      VecMulf(vec,amplitude*(float)sin(t));
+
+               //      VECADD(state->co,state->co,vec);
+               //      break;
+       }
+}
+static void do_postkink(ParticleKey *state, ParticleKey *par, float *par_rot, float time, float freq, float shape, float amplitude, short type, short axis, float obmat[][4])
+{
+       static ParticleKey first;
+       static float q[4];
+       float vec[3]={0.0,0.0,0.0};
+       float t;
+
+       CLAMP(time,0.0,1.0);
+
+       t=time;
+
+       t*=(float)M_PI*freq;
+
+       if(par==0) return;
+
+       switch(type){
+               case PART_KINK_ROLL:
+                       if(time<(0.5+shape/2.0f)){
+                               float *q2;
+                               memcpy(&first,state,sizeof(ParticleKey));
+                               Normalize(first.vel);
+                               if(par_rot)
+                                       q2=par_rot;
+                               else
+                                       q2=vectoquat(par->vel,axis,(axis+1)%3);
+                               QUATCOPY(q,q2);
+                       }
+                       else{
+                               float fac;
+                               shape=0.5f+shape/2.0f;
+                               t-=(float)M_PI*(shape*freq + 0.5f);
+
+                               vec[axis]=1.0;
+                               
+                               QuatMulVecf(q,vec);
+
+                               fac=amplitude*(1.0f+((1.0f-time)/(1.0f-shape)*(float)sin(t)));
+                               VECADDFAC(state->co,first.co,vec,fac);
+                               fac=amplitude*((1.0f-time)/(1.0f-shape)*(float)cos(t));
+                               VECADDFAC(state->co,state->co,first.vel,fac);
+                       }
+                       break;
+       }
+}
+static void do_clump(ParticleKey *state, ParticleKey *par, float time, float clumpfac, float clumppow, float pa_clump)
+{
+       if(par && clumpfac!=0.0){
+               float clump, cpow;
+
+               if(clumppow<0.0)
+                       cpow=1.0f+clumppow;
+               else
+                       cpow=1.0f+9.0f*clumppow;
+
+               if(clumpfac<0.0) /* clump roots instead of tips */
+                       clump = -clumpfac*pa_clump*(float)pow(1.0-(double)time,(double)cpow);
+               else
+                       clump = clumpfac*pa_clump*(float)pow((double)time,(double)cpow);
+               VecLerpf(state->co,state->co,par->co,clump);
+       }
+}
+int do_guide(ParticleKey *state, int pa_num, float time, ListBase *lb)
+{
+       PartDeflect *pd;
+       ParticleEffectorCache *ec;
+       Object *eob;
+       Curve *cu;
+       ParticleKey key, par;
+
+       float effect[3]={0.0,0.0,0.0}, distance, f_force, mindist, totforce=0.0;
+       float guidevec[4], guidedir[3], rot2[4], temp[3], angle, pa_loc[3], pa_zero[3]={0.0f,0.0f,0.0f};
+       float veffect[3]={0.0,0.0,0.0}, guidetime;
+
+       effect[0]=effect[1]=effect[2]=0.0;
+
+       if(lb->first){
+               for(ec = lb->first; ec; ec= ec->next){
+                       eob= ec->ob;
+                       if(ec->type & PSYS_EC_EFFECTOR){
+                               pd=eob->pd;
+                               if(pd->forcefield==PFIELD_GUIDE){
+                                       cu = (Curve*)eob->data;
+
+                                       distance=ec->distances[pa_num];
+                                       mindist=pd->f_strength;
+
+                                       VECCOPY(pa_loc, ec->locations+3*pa_num);
+                                       VECCOPY(pa_zero,pa_loc);
+                                       VECADD(pa_zero,pa_zero,ec->firstloc);
+
+                                       guidetime=time/(1.0-pd->free_end);
+
+                                       /* WARNING: bails out with continue here */
+                                       if(((pd->flag & PFIELD_USEMAX) && distance>pd->maxdist) || guidetime>1.0f) continue;
+
+                                       if(guidetime>1.0f) continue;
+
+                                       /* calculate contribution factor for this guide */
+                                       f_force=1.0f;
+                                       if(distance<=mindist);
+                                       else if(pd->flag & PFIELD_USEMAX) {
+                                               if(mindist>=pd->maxdist) f_force= 0.0f;
+                                               else if(pd->f_power!=0.0f){
+                                                       f_force= 1.0f - (distance-mindist)/(pd->maxdist - mindist);
+                                                       f_force = (float)pow(f_force, pd->f_power);
+                                               }
+                                       }
+                                       else if(pd->f_power!=0.0f){
+                                               f_force= 1.0f/(1.0f + distance-mindist);
+                                               f_force = (float)pow(f_force, pd->f_power);
+                                       }
+
+                                       if(pd->flag & PFIELD_GUIDE_PATH_ADD)
+                                               where_on_path(eob, f_force*guidetime, guidevec, guidedir);
+                                       else
+                                               where_on_path(eob, guidetime, guidevec, guidedir);
+
+                                       Mat4MulVecfl(ec->ob->obmat,guidevec);
+                                       Mat4Mul3Vecfl(ec->ob->obmat,guidedir);
+
+                                       Normalize(guidedir);
+
+                                       if(guidetime!=0.0){
+                                               /* curve direction */
+                                               Crossf(temp, ec->firstdir, guidedir);
+                                               angle=Inpf(ec->firstdir,guidedir)/(VecLength(ec->firstdir));
+                                               angle=saacos(angle);
+                                               VecRotToQuat(temp,angle,rot2);
+                                               QuatMulVecf(rot2,pa_loc);
+
+                                               /* curve tilt */
+                                               VecRotToQuat(guidedir,guidevec[3]-ec->firstloc[3],rot2);
+                                               QuatMulVecf(rot2,pa_loc);
+
+                                               //q=vectoquat(guidedir, pd->kink_axis, (pd->kink_axis+1)%3);
+                                               //QuatMul(par.rot,rot2,q);
+                                       }
+                                       //else{
+                                       //      par.rot[0]=1.0f;
+                                       //      par.rot[1]=par.rot[2]=par.rot[3]=0.0f;
+                                       //}
+
+                                       /* curve taper */
+                                       if(cu->taperobj)
+                                               VecMulf(pa_loc,calc_taper(cu->taperobj,(int)(f_force*guidetime*100.0),100));
+                                       /* TODO */
+                                       //else{
+                                       ///* curve size*/
+                                       //      calc_curve_subdiv_radius(cu,cu->nurb.first,((Nurb*)cu->nurb.first)->
+                                       //}
+                                       par.co[0]=par.co[1]=par.co[2]=0.0f;
+                                       VECCOPY(key.co,pa_loc);
+                                       do_prekink(&key, &par, 0, guidetime, pd->kink_freq, pd->kink_shape, pd->kink_amp, pd->kink, pd->kink_axis, 0);
+                                       do_clump(&key, &par, guidetime, pd->clump_fac, pd->clump_pow, 1.0f);
+                                       do_postkink(&key, &par, 0, guidetime, pd->kink_freq, pd->kink_shape, pd->kink_amp, pd->kink, pd->kink_axis, 0);
+                                       VECCOPY(pa_loc,key.co);
+
+                                       VECADD(pa_loc,pa_loc,guidevec);
+                                       VECSUB(pa_loc,pa_loc,pa_zero);
+                                       VECADDFAC(effect,effect,pa_loc,f_force);
+                                       VECADDFAC(veffect,veffect,guidedir,f_force);
+                                       totforce+=f_force;
+                               }
+                       }
+               }
+
+               if(totforce!=0.0){
+                       if(totforce>1.0)
+                               VecMulf(effect,1.0f/totforce);
+                       CLAMP(totforce,0.0,1.0);
+                       VECADD(effect,effect,pa_zero);
+                       VecLerpf(state->co,state->co,effect,totforce);
+
+                       Normalize(veffect);
+                       VecMulf(veffect,VecLength(state->vel));
+                       VECCOPY(state->vel,veffect);
+                       return 1;
+               }
+       }
+       return 0;
+}
+static void do_rough(float *loc, float t, float fac, float size, float thres, ParticleKey *state)
+{
+       float rough[3];
+       float rco[3];
+
+       if(thres!=0.0)
+               if((float)fabs((float)(-1.5+loc[0]+loc[1]+loc[2]))<1.5f*thres) return;
+
+       VECCOPY(rco,loc);
+       VecMulf(rco,t);
+       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);
+}
+static void do_rough_end(float *loc, float t, float fac, float shape, ParticleKey *state, ParticleKey *par)
+{
+       float rough[3], rnor[3];
+       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);
+}
+static int check_path_length(int k, int p, ParticleCacheKey **cache, ParticleCacheKey *state, float length, float *dvec)
+{
+       static float max_length = 1.0, cur_length = 0.0;
+
+       if(k) {
+               if(cur_length + length > max_length){
+                       //if(p<totparent){
+                       //      if(k<=(int)cache[totpart+p]->time){
+                       //              /* parents need to be calculated fully first so that they don't mess up their children */
+                       //              /* we'll make a note of where we got to though so that they're easy to finish later */
+                       //              state->time=(max_length-cur_length)/length;
+                       //              cache[totpart+p]->time=(float)k;
+                       //      }
+                       //}
+                       //else{
+                       VecMulf(dvec, (max_length - cur_length) / length);
+                       VECADD(state->co, (state - 1)->co, dvec);
+                       cache[p]->steps = k;
+                       /* something over the maximum step value */
+                       return k=100000;
+                       //}
+               }
+               else {
+                       cur_length+=length;
+               }
+       }
+       else {/* reset signal */
+               max_length=length;
+               cur_length=0.0;
+       }
+       return k;
+}
+static void finalize_path_length(int p, ParticleCacheKey **cache)
+{
+       ParticleCacheKey *state = cache[p];
+       float dvec[3];
+       state += state->steps;
+
+       VECSUB(dvec, state->co, (state - 1)->co);
+       VecMulf(dvec, state->steps);
+       VECADD(state->co, (state - 1)->co, dvec);
+}
+static void offset_child(ChildParticle *cpa, ParticleKey *par, ParticleKey *child, float flat, float radius)
+{
+       VECCOPY(child->co,cpa->fuv);
+       VecMulf(child->co,radius);
+
+       child->co[0]*=flat;
+
+       VECCOPY(child->vel,par->vel);
+
+       QuatMulVecf(par->rot,child->co);
+
+       QUATCOPY(child->rot,par->rot);
+
+       VECADD(child->co,child->co,par->co);
+}
+float *psys_cache_vgroup(DerivedMesh *dm, ParticleSystem *psys, int vgroup)
+{
+       float *vg=0;
+
+       if(psys->vgroup[vgroup]){
+               MDeformVert *dvert = dm->getVertDataArray(dm, CD_MDEFORMVERT);
+               if(dvert){
+                       int totvert=dm->getNumVerts(dm), i;
+                       vg=MEM_callocN(sizeof(float)*totvert, "vg_cache");
+                       if(psys->vg_neg&(1<<vgroup)){
+                               for(i=0; i<totvert; i++)
+                                       vg[i]=1.0f-vert_weight(dvert+i,psys->vgroup[vgroup]-1);
+                       }
+                       else{
+                               for(i=0; i<totvert; i++)
+                                       vg[i]=vert_weight(dvert+i,psys->vgroup[vgroup]-1);
+                       }
+               }
+       }
+       return vg;
+}
+void psys_find_parents(Object *ob, ParticleSystemModifierData *psmd, ParticleSystem *psys)
+{
+       ParticleSettings *part=psys->part;
+       KDTree *tree;
+       ChildParticle *cpa;
+       int p, totparent,totchild=psys->totchild;
+       float co[3], *orcos=0;
+       int from=PART_FROM_FACE;
+       totparent=(int)(totchild*part->parents*0.3);
+
+       tree=BLI_kdtree_new(totparent);
+
+       for(p=0,cpa=psys->child; p<totparent; p++,cpa++){
+               psys_particle_on_emitter(ob,psmd,from,cpa->num,-1,cpa->fuv,cpa->foffset,co,0,0,0);
+               BLI_kdtree_insert(tree, p, co, NULL);
+       }
+
+       BLI_kdtree_balance(tree);
+
+       for(; p<totchild; p++,cpa++){
+               psys_particle_on_emitter(ob,psmd,from,cpa->num,DMCACHE_ISCHILD,cpa->fuv,cpa->foffset,co,0,0,0);
+               cpa->parent=BLI_kdtree_find_nearest(tree, co, NULL, NULL);
+       }
+
+       BLI_kdtree_free(tree);
+       if(orcos)
+               MEM_freeN(orcos);
+}
+void psys_cache_child_paths(Object *ob, ParticleSystem *psys, float cfra, int editupdate)
+{
+       ParticleSettings *part = psys->part;
+       ParticleEditSettings *pset = &G.scene->toolsettings->particle;
+       ParticleSystemModifierData *psmd = psys_get_modifier(ob,psys);
+       ParticleData *pa;
+       ChildParticle *cpa;
+       ParticleCacheKey **cache = psys->childcache, **pcache = psys->pathcache;
+       ParticleCacheKey *tcache, *state, *par=0, *key[4];
+       ParticleTexture ptex;
+       Material *ma = give_current_material(ob, part->omat);
+
+       float length, pa_length = 1.0, pa_clump = 1.0, pa_kink = 1.0;
+       float pa_rough1 = 1.0, pa_rough2 = 1.0, pa_roughe = 1.0;
+       float t, rough_t;
+       float dvec[3], orco[3], ornor[3], imat[4][4];
+       float *vg_length = 0, *vg_clump = 0, *vg_kink = 0;
+       float *vg_rough1 = 0, *vg_rough2 = 0, *vg_roughe = 0;
+       float cpa_1st[3];
+
+       int k, i, totparent=0, between=0, edit=0;
+       int steps = (int)pow(2.0,(double)part->draw_step);
+       int totchild = psys->totchild;
+       int cpa_num; short cpa_from;
+
+       if(part->flag & PART_ANIM_BRANCHING)
+               BLI_srandom(31415926 + psys->seed + (int)cfra);
+       else
+               BLI_srandom(31415926 + psys->seed);
+
+       /*---start figuring out what is actually wanted---*/
+       if(psys_in_edit_mode(psys)){
+               if(G.rendering==0 && (psys->edit==NULL || pset->flag & PE_SHOW_CHILD)==0)
+                       totchild=0;
+               edit=1;
+       }
+
+       if(totchild && part->from!=PART_FROM_PARTICLE && part->childtype==PART_CHILD_FACES){
+               totparent=(int)(totchild*part->parents*0.3);
+               /* part->parents could still be 0 so we can't test with totparent */
+               between=1;
+       }
+
+       if(G.rendering)
+               steps=(int)pow(2.0,(double)part->ren_step);
+       else if(part->flag & PART_CHILD_RENDER){
+               totchild=0;
+       }
+       else{
+               totchild=(int)((float)totchild*(float)part->disp/100.0f);
+               totparent=MIN2(totparent,totchild);
+       }
+
+       if(totchild==0) return;
+
+       if(editupdate && psys->childcache && !(part->flag & PART_BRANCHING) && totchild == psys->totchildcache) {
+               cache = psys->childcache;
+       }
+       else {
+               /* clear out old and create new empty path cache */
+               free_child_path_cache(psys);
+
+               cache = psys->childcache = MEM_callocN(totchild*sizeof(void *), "Child path cache array");
+               tcache = MEM_callocN(totchild * (steps + 1) * sizeof(ParticleCacheKey), "Child path cache");
+               for(i=0; i<totchild; i++)
+                       cache[i] = tcache + i * (steps + 1);
+       }
+
+       psys->lattice = psys_get_lattice(ob,psys);
+
+       /* cache all relevant vertex groups if they exist */
+       if(part->from!=PART_FROM_PARTICLE){
+               vg_length = psys_cache_vgroup(psmd->dm,psys,PSYS_VG_LENGTH);
+               vg_clump = psys_cache_vgroup(psmd->dm,psys,PSYS_VG_CLUMP);
+               vg_kink = psys_cache_vgroup(psmd->dm,psys,PSYS_VG_KINK);
+               vg_rough1 = psys_cache_vgroup(psmd->dm,psys,PSYS_VG_ROUGH1);
+               vg_rough2 = psys_cache_vgroup(psmd->dm,psys,PSYS_VG_ROUGH2);
+               vg_roughe = psys_cache_vgroup(psmd->dm,psys,PSYS_VG_ROUGHE);
+       }
+
+       /* set correct ipo timing */
+       if(part->flag&PART_ABS_TIME && part->ipo){
+               calc_ipo(part->ipo, cfra);
+               execute_ipo((ID *)part, part->ipo);
+       }
+
+       Mat4Invert(imat,ob->obmat);
+
+       for(i=0,cpa=psys->child; i<totchild; i++, cpa++){
+               int guided=0;
+               float *cpa_fuv=0;
+               float branch_begin=0.0f, branch_end=0.0f, branch_prob=0.0f;
+               float branchfac, rough_rand=0.0f;
+               
+               if(part->flag & PART_BRANCHING) {
+                       branch_begin=BLI_frand();
+                       branch_end=branch_begin+(1.0f-branch_begin)*BLI_frand();
+                       branch_prob=BLI_frand();
+                       rough_rand=BLI_frand();
+               }
+
+               if(i<psys->totpart){
+                       branch_begin=0.0f;
+                       branch_end=1.0f;
+                       branch_prob=0.0f;
+               }
+
+               if(between){
+                       int w, needupdate;
+                       float foffset;
+
+                       if(editupdate && !(part->flag & PART_BRANCHING)) {
+                               needupdate= 0;
+                               w= 0;
+                               while(w<4 && cpa->pa[w]>=0) {
+                                       if(psys->particles[cpa->pa[w]].flag & PARS_EDIT_RECALC) {
+                                               needupdate= 1;
+                                               break;
+                                       }
+                                       w++;
+                               }
+
+                               if(!needupdate)
+                                       continue;
+                               else
+                                       memset(cache[i], 0, sizeof(*cache[i])*(steps+1));
+                       }
+
+                       /* get parent paths */
+                       w= 0;
+                       while(w<4 && cpa->pa[w]>=0){
+                               key[w] = pcache[cpa->pa[w]];
+                               w++;
+                       }
+
+                       /* get the original coordinates (orco) for texture usage */
+                       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;
+
+                       psys_particle_on_emitter(ob,psmd,cpa_from,cpa_num,DMCACHE_ISCHILD,cpa->fuv,foffset,orco,ornor,0,0);
+
+                       /* we need to save the actual root position of the child for positioning it accurately to the surface of the emitter */
+                       VECCOPY(cpa_1st,orco);
+                       Mat4MulVecfl(ob->obmat,cpa_1st);
+
+                       pa=0;
+               }
+               else{
+                       if(editupdate && !(part->flag & PART_BRANCHING)) {
+                               if(!(psys->particles[cpa->parent].flag & PARS_EDIT_RECALC))
+                                       continue;
+
+                               memset(cache[i], 0, sizeof(*cache[i])*(steps+1));
+                       }
+
+                       /* get the parent path */
+                       key[0]=pcache[cpa->parent];
+
+                       /* get the original coordinates (orco) for texture usage */
+                       pa=psys->particles+cpa->parent;
+
+                       cpa_from=part->from;
+                       cpa_num=pa->num;
+                       cpa_fuv=pa->fuv;
+
+                       psys_particle_on_emitter(ob,psmd,cpa_from,cpa_num,DMCACHE_ISCHILD,cpa_fuv,pa->foffset,orco,ornor,0,0);
+               }
+
+               cache[i]->steps = steps;
+
+               /* correct child ipo timing */
+               if((part->flag&PART_ABS_TIME)==0 && part->ipo){
+                       float dsta=part->end-part->sta;
+                       calc_ipo(part->ipo, 100.0f*(cfra-(part->sta+dsta*cpa->rand[1]))/(part->lifetime*(1.0f - part->randlife*cpa->rand[0])));
+                       execute_ipo((ID *)part, part->ipo);
+               }
+
+               /* get different child parameters from textures & vgroups */
+               ptex.length=part->length*(1.0f - part->randlength*cpa->rand[0]);
+               ptex.clump=1.0;
+               ptex.kink=1.0;
+
+               get_cpa_texture(psmd->dm,ma,cpa_num,cpa_fuv,orco,&ptex,MAP_PA_CACHE);
+               
+               pa_length=ptex.length;
+               pa_clump=ptex.clump;
+               pa_kink=ptex.kink;
+               pa_rough1=1.0;
+               pa_rough2=1.0;
+               pa_roughe=1.0;
+
+               if(vg_length)
+                       pa_length*=psys_interpolate_value_from_verts(psmd->dm,cpa_from,cpa_num,cpa_fuv,vg_length);
+               if(vg_clump)
+                       pa_clump*=psys_interpolate_value_from_verts(psmd->dm,cpa_from,cpa_num,cpa_fuv,vg_clump);
+               if(vg_kink)
+                       pa_kink*=psys_interpolate_value_from_verts(psmd->dm,cpa_from,cpa_num,cpa_fuv,vg_kink);
+               if(vg_rough1)
+                       pa_rough1*=psys_interpolate_value_from_verts(psmd->dm,cpa_from,cpa_num,cpa_fuv,vg_rough1);
+               if(vg_rough2)
+                       pa_rough2*=psys_interpolate_value_from_verts(psmd->dm,cpa_from,cpa_num,cpa_fuv,vg_rough2);
+               if(vg_roughe)
+                       pa_roughe*=psys_interpolate_value_from_verts(psmd->dm,cpa_from,cpa_num,cpa_fuv,vg_roughe);
+
+               /* create the child path */
+               for(k=0,state=cache[i]; k<=steps; k++,state++){
+                       t=(float)k/(float)steps;
+
+                       if(between){
+                               int w=0;
+
+                               state->co[0] = state->co[1] = state->co[2] = 0.0f;
+                               state->vel[0] = state->vel[1] = state->vel[2] = 0.0f;
+
+                               //QUATCOPY(state->rot,key[0]->rot);
+
+                               /* child position is the weighted sum of parent positions */
+                               while(w<4 && cpa->pa[w]>=0){
+                                       state->co[0] += cpa->w[w] * key[w]->co[0];
+                                       state->co[1] += cpa->w[w] * key[w]->co[1];
+                                       state->co[2] += cpa->w[w] * key[w]->co[2];
+
+                                       state->vel[0] += cpa->w[w] * key[w]->vel[0];
+                                       state->vel[1] += cpa->w[w] * key[w]->vel[1];
+                                       state->vel[2] += cpa->w[w] * key[w]->vel[2];
+                                       key[w]++;
+                                       w++;
+                               }
+                               if(k==0){
+                                       /* calculate the offset between actual child root position and first position interpolated from parents */
+                                       VECSUB(cpa_1st,cpa_1st,state->co);
+                               }
+                               /* apply offset for correct positioning */
+                               VECADD(state->co,state->co,cpa_1st);
+                       }
+                       else{
+                               /* offset the child from the parent position */
+                               offset_child(cpa, (ParticleKey*)key[0], (ParticleKey*)state, part->childflat, part->childrad);
+
+                               key[0]++;
+                       }
+
+                       if(totparent){
+                               if(i>=totparent)
+                                       par = cache[cpa->parent] + k;
+                               else
+                                       par=0;
+                       }
+                       else if(cpa->parent>=0){
+                               par=pcache[cpa->parent]+k;
+                       }
+
+                       /* apply different deformations to the child path */
+                       if(part->flag & PART_CHILD_GUIDE)
+                               guided = do_guide((ParticleKey*)state, i, t, &(psys->effectors)); //safe to cast, since only co and vel are used
+
+                       if(guided==0){
+                               if(part->kink)
+                                       do_prekink((ParticleKey*)state, (ParticleKey*)par, par->rot, t,
+                                       part->kink_freq * pa_kink, part->kink_shape, part->kink_amp, part->kink, part->kink_axis, ob->obmat);
+                                               
+                               do_clump((ParticleKey*)state, (ParticleKey*)par, t, part->clumpfac, part->clumppow, pa_clump);
+
+                               if(part->kink)
+                                       do_postkink((ParticleKey*)state, (ParticleKey*)par, par->rot, t,
+                                       part->kink_freq * pa_kink, part->kink_shape, part->kink_amp, part->kink, part->kink_axis, ob->obmat);
+                       }
+
+                       if(part->flag & PART_BRANCHING && between == 0 && part->flag & PART_ANIM_BRANCHING)
+                               rough_t = t * rough_rand;
+                       else
+                               rough_t = t;
+
+                       if(part->rough1 != 0.0 && pa_rough1 != 0.0)
+                                       do_rough(orco, rough_t, pa_rough1*part->rough1, part->rough1_size, 0.0, (ParticleKey*)state);
+
+                       if(part->rough2 != 0.0 && pa_rough2 != 0.0)
+                               do_rough(cpa->rand, rough_t, pa_rough2*part->rough2, part->rough2_size, part->rough2_thres, (ParticleKey*)state);
+
+                       if(part->rough_end != 0.0 && pa_roughe != 0.0)
+                               do_rough_end(cpa->rand, rough_t, pa_roughe*part->rough_end, part->rough_end_shape, (ParticleKey*)state, (ParticleKey*)par);
+
+                       if(part->flag & PART_BRANCHING && between==0){
+                               if(branch_prob > part->branch_thres){
+                                       branchfac=0.0f;
+                               }
+                               else{
+                                       if(part->flag & PART_SYMM_BRANCHING){
+                                               if(t < branch_begin || t > branch_end)
+                                                       branchfac=0.0f;
+                                               else{
+                                                       if((t-branch_begin)/(branch_end-branch_begin)<0.5)
+                                                               branchfac=2.0f*(t-branch_begin)/(branch_end-branch_begin);
+                                                       else
+                                                               branchfac=2.0f*(branch_end-t)/(branch_end-branch_begin);
+
+                                                       CLAMP(branchfac,0.0f,1.0f);
+                                               }
+                                       }
+                                       else{
+                                               if(t < branch_begin){
+                                                       branchfac=0.0f;
+                                               }
+                                               else{
+                                                       branchfac=(t-branch_begin)/((1.0f-branch_begin)*0.5f);
+                                                       CLAMP(branchfac,0.0f,1.0f);
+                                               }
+                                       }
+                               }
+
+                               if(i<psys->totpart){
+                                       VecLerpf(state->co, (pcache[i] + k)->co, state->co, branchfac);
+                               }
+                               else
+                                       VecLerpf(state->co, (cache[i - psys->totpart] + k)->co, state->co, branchfac);
+                       }
+
+                       /* we have to correct velocity because of kink & clump */
+                       if(k>1){
+                               VECSUB((state-1)->vel,state->co,(state-2)->co);
+                               VecMulf((state-1)->vel,0.5);
+                       }
+                       
+                       /* 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)steps;
+
+                               k=check_path_length(k,i,cache,state,length,dvec);
+                       }
+                       else{
+                               /* initialize length calculation */
+                               if(part->flag&PART_ABS_LENGTH)
+                                       check_path_length(0,0,0,0,part->abslength*pa_length,0);
+                               else
+                                       check_path_length(0,0,0,0,pa_length,0);
+                       }
+               }
+       }
+       /* now let's finalise the interpolated parents that we might have left half done before */
+       if(totchild) for(i=0,cpa=psys->child; i<totparent; i++, cpa++)
+               finalize_path_length(i,cache);
+
+       if(vg_length)
+               MEM_freeN(vg_length);
+       if(vg_clump)
+               MEM_freeN(vg_clump);
+       if(vg_kink)
+               MEM_freeN(vg_kink);
+       if(vg_rough1)
+               MEM_freeN(vg_rough1);
+       if(vg_rough2)
+               MEM_freeN(vg_roughe);
+       if(vg_roughe)
+               MEM_freeN(vg_roughe);
+
+       psys->totchildcache = totchild;
+
+       if(psys->lattice){
+               end_latt_deform();
+               psys->lattice=0;
+       }
+}
+/* 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.                          */
+/* -Cached path data is also used to determine cut position for the editmode tool.     */
+void psys_cache_paths(Object *ob, ParticleSystem *psys, float cfra, int editupdate)
+{
+       ParticleCacheKey *ca, **cache=psys->pathcache;
+       ParticleSystemModifierData *psmd = psys_get_modifier(ob, psys);
+       ParticleEditSettings *pset = &G.scene->toolsettings->particle;
+       
+       ParticleData *pa;
+       ParticleKey keys[4], result, *kkey[2] = {NULL, NULL};
+       HairKey *hkey[2] = {NULL, NULL};
+
+       ParticleEdit *edit = 0;
+       ParticleEditKey *ekey = 0;
+
+       SoftBody *soft = 0;
+       BodyPoint *bp[2] = {NULL, NULL};
+       
+       float birthtime = 0.0, dietime = 0.0;
+       float t, time, keytime, dfra = 1.0, frs_sec = G.scene->r.frs_sec;
+       float col[3] = {0.5f, 0.5f, 0.5f};
+       float prev_tangent[3], hairmat[4][4];
+       int k,i;
+       int steps = (int)pow(2.0, (double)psys->part->draw_step);
+       int totpart = psys->totpart;
+       char nosel[4], sel[4];
+       float sel_col[3];
+       float nosel_col[3];
+
+       /* we don't have anything valid to create paths from so let's quit here */
+       if((psys->flag & PSYS_HAIR_DONE)==0 && (psys->flag & PSYS_KEYED)==0)
+               return;
+
+       if(G.rendering)
+               steps = (int)pow(2.0, (double)psys->part->ren_step);
+       else if(psys_in_edit_mode(psys)){
+               edit=psys->edit;
+               
+               //timed = edit->draw_timed;
+
+               PE_get_colors(sel,nosel);
+               if(pset->brushtype == PE_BRUSH_WEIGHT){
+                       sel_col[0] = sel_col[1] = sel_col[2] = 1.0f;
+                       nosel_col[0] = nosel_col[1] = nosel_col[2] = 0.0f;
+               }
+               else{
+                       sel_col[0] = (float)sel[0] / 255.0f;
+                       sel_col[1] = (float)sel[1] / 255.0f;
+                       sel_col[2] = (float)sel[2] / 255.0f;
+                       nosel_col[0] = (float)nosel[0] / 255.0f;
+                       nosel_col[1] = (float)nosel[1] / 255.0f;
+                       nosel_col[2] = (float)nosel[2] / 255.0f;
+               }
+       }
+
+       if(editupdate && psys->pathcache && totpart == psys->totcached) {
+               cache = psys->pathcache;
+       }
+       else {
+               /* clear out old and create new empty path cache */
+               psys_free_path_cache(psys);
+
+               /* allocate cache array for fast access and set pointers to contiguous mem block */
+               cache = psys->pathcache = MEM_callocN(MAX2(1, totpart) * sizeof(void *), "Path cache array");
+               cache[0] = MEM_callocN(totpart * (steps + 1) * sizeof(ParticleCacheKey), "Path cache");
+               for(i=1; i<totpart; i++)
+                       cache[i] = cache[0] + i * (steps + 1);
+       }
+
+       if(edit==NULL && psys->soft && psys->softflag & OB_SB_ENABLE)
+               soft = psys->soft;
+       
+       psys->lattice = psys_get_lattice(ob, psys);
+
+       /*---first main loop: create all actual particles' paths---*/
+       for(i=0,pa=psys->particles; i<totpart; i++, pa++){
+               if(psys && edit==NULL && (pa->flag & PARS_NO_DISP || pa->flag & PARS_UNEXIST)) {
+                       if(soft)
+                               bp[0] += pa->totkey; /* TODO use of initialized value? */
+                       continue;
+               }
+
+               if(editupdate && !(pa->flag & PARS_EDIT_RECALC)) continue;
+               else memset(cache[i], 0, sizeof(*cache[i])*(steps+1));
+
+               cache[i]->steps = steps;
+
+               if(edit)
+                       ekey = edit->keys[i];
+
+               /*--get the first data points--*/
+               if(psys->flag & PSYS_KEYED) {
+                       kkey[0] = pa->keys;
+                       kkey[1] = kkey[0] + 1;
+
+                       birthtime = kkey[0]->time;
+                       dietime = kkey[0][pa->totkey-1].time;
+               }
+               else {
+                       hkey[0] = pa->hair;
+                       hkey[1] = hkey[0] + 1;
+
+                       birthtime = hkey[0]->time;
+                       dietime = hkey[0][pa->totkey-1].time;
+
+                       psys_mat_hair_to_global(ob, psmd->dm, psys->part->from, pa, hairmat);
+               }
+
+               if(soft){
+                       bp[0] = soft->bpoint + pa->bpi;
+                       bp[1] = bp[0] + 1;
+               }
+
+               /*--interpolate actual path from data points--*/
+               for(k=0, ca=cache[i]; k<=steps; k++, ca++){
+                       time = (float)k / (float)steps;
+
+                       t = birthtime + time * (dietime - birthtime);
+
+                       if(psys->flag & PSYS_KEYED) {
+                               while(kkey[1]->time < t) {
+                                       kkey[1]++;
+                               }
+
+                               kkey[0] = kkey[1] - 1;                          
+                       }
+                       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(psys->flag & PSYS_KEYED) {
+                               memcpy(keys + 1, kkey[0], sizeof(ParticleKey));
+                               memcpy(keys + 2, kkey[1], sizeof(ParticleKey));
+                       }
+                       else {
+                               hair_to_particle(keys + 1, hkey[0]);
+                               hair_to_particle(keys + 2, hkey[1]);
+                       }
+
+
+                       if((psys->flag & PSYS_KEYED)==0) {
+                               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], 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;
+
+                       keytime = (t - keys[1].time) / dfra;
+
+                       /* convert velocity to timestep size */
+                       if(psys->flag & PSYS_KEYED){
+                               VecMulf(keys[1].vel, dfra / frs_sec);
+                               VecMulf(keys[2].vel, dfra / frs_sec);
+                       }
+
+                       /* 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)*/
+                       interpolate_particle((psys->flag & PSYS_KEYED) ? -1 /* signal for cubic interpolation */
+                               : ((psys->part->flag & PART_HAIR_BSPLINE) ? KEY_BSPLINE : KEY_CARDINAL)
+                               ,keys, keytime, &result);
+
+
+                       /* the velocity needs to be converted back from cubic interpolation */
+                       if(psys->flag & PSYS_KEYED){
+                               VecMulf(result.vel, frs_sec / dfra);
+                       }
+                       else if(soft==NULL) { /* softbody and keyed are allready in global space */
+                               Mat4MulVecfl(hairmat, result.co);
+                       }
+                       
+
+                       /* apply guide curves to path data */
+                       if(edit==0 && psys->effectors.first && (psys->part->flag & PART_CHILD_GUIDE)==0)
+                               do_guide(&result, i, time, &psys->effectors);
+
+                       /* figure out rotation */
+                       
+                       if(k) {
+                               float angle, tangent[3], normal[3], q[4];
+
+                               if(k == 1) {
+                                       float *q2;
+
+                                       VECSUB(tangent, result.co, (ca - 1)->co);
+
+                                       q2 = vectoquat(tangent, OB_POSX, OB_POSZ);
+
+                                       QUATCOPY((ca - 1)->rot, q2);
+
+                                       VECCOPY(prev_tangent, tangent);
+                                       Normalize(prev_tangent);
+                               }
+                               else {
+                                       VECSUB(tangent, result.co, (ca - 1)->co);
+                                       Normalize(tangent);
+                                       angle = saacos(Inpf(tangent, prev_tangent));
+
+                                       if((angle > -0.000001) && (angle < 0.000001)){
+                                               QUATCOPY((ca - 1)->rot, (ca - 2)->rot);
+                                       }
+                                       else{
+                                               Crossf(normal, prev_tangent, tangent);
+                                               VecRotToQuat(normal, angle, q);
+                                               QuatMul((ca - 1)->rot, q, (ca - 2)->rot);
+                                       }
+
+                                       VECCOPY(prev_tangent, tangent);
+                               }
+
+                               if(k == steps) {
+                                       QUATCOPY(ca->rot, (ca - 1)->rot);
+                               }
+                       }
+
+                       VECCOPY(ca->co, result.co);
+                       
+                       if(k){
+                               VECSUB(ca->vel, ca->co, (ca-1)->co);
+
+                               if(k==1) {
+                                       VECCOPY((ca-1)->vel, ca->vel);
+                               }
+
+                       }
+
+
+                       /* selection coloring in edit mode */
+                       if(edit){
+                               if(pset->brushtype==PE_BRUSH_WEIGHT){
+                                       if(k==steps)
+                                               VecLerpf(ca->col, nosel_col, sel_col, hkey[0]->weight);
+                                       else
+                                               VecLerpf(ca->col,nosel_col,sel_col,
+                                               (1.0f - keytime) * hkey[0]->weight + keytime * hkey[1]->weight);
+                               }
+                               else{
+                                       if((ekey + (hkey[0] - pa->hair))->flag & PEK_SELECT){
+                                               if((ekey + (hkey[1] - pa->hair))->flag & PEK_SELECT){
+                                                       VECCOPY(ca->col, sel_col);
+                                               }
+                                               else{
+                                                       VecLerpf(ca->col, sel_col, nosel_col, keytime);
+                                               }
+                                       }
+                                       else{
+                                               if((ekey + (hkey[1] - pa->hair))->flag & PEK_SELECT){
+                                                       VecLerpf(ca->col, nosel_col, sel_col, keytime);
+                                               }
+                                               else{
+                                                       VECCOPY(ca->col, nosel_col);
+                                               }
+                                       }
+                               }
+                       }
+                       else{
+                               VECCOPY(ca->col, col);
+                       }
+
+                       if(psys->lattice && edit==0)
+                               calc_latt_deform(ca->co, 1.0f);
+               }
+       }
+
+       psys->totcached = totpart;
+
+       if(psys && psys->lattice){
+               end_latt_deform();
+               psys->lattice=0;
+       }
+}
+/************************************************/
+/*                     Particle Key handling                           */
+/************************************************/
+void copy_particle_key(ParticleKey *to, ParticleKey *from, int time){
+       if(time){
+               memcpy(to,from,sizeof(ParticleKey));
+       }
+       else{
+               float to_time=to->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);
+       if(vel) VECCOPY(vel,key->vel);
+       if(rot) QUATCOPY(rot,key->rot);
+       if(time) *time=key->time;
+}
+/*-------changing particle keys from space to another-------*/
+void psys_key_to_object(Object *ob, ParticleKey *key, float imat[][4]){
+       float q[4], imat2[4][4];
+
+       if(imat==0){
+               Mat4Invert(imat2,ob->obmat);
+               imat=imat2;
+       }
+
+       VECADD(key->vel,key->vel,key->co);
+
+       Mat4MulVecfl(imat,key->co);
+       Mat4MulVecfl(imat,key->vel);
+       Mat4ToQuat(imat,q);
+
+       VECSUB(key->vel,key->vel,key->co);
+       QuatMul(key->rot,q,key->rot);
+}
+static void key_from_object(Object *ob, ParticleKey *key){
+       float q[4];
+
+       VECADD(key->vel,key->vel,key->co);
+
+       Mat4MulVecfl(ob->obmat,key->co);
+       Mat4MulVecfl(ob->obmat,key->vel);
+       Mat4ToQuat(ob->obmat,q);
+
+       VECSUB(key->vel,key->vel,key->co);
+       QuatMul(key->rot,q,key->rot);
+}
+
+static void triatomat(float *v1, float *v2, float *v3, float (*uv)[2], float mat[][4])
+{
+       float det, w1, w2, d1[2], d2[2];
+
+       memset(mat, 0, sizeof(float)*4*4);
+       mat[3][3]= 1.0f;
+
+       /* first axis is the normal */
+       CalcNormFloat(v1, v2, v3, mat[2]);
+
+       /* second axis along (1, 0) in uv space */
+       if(uv) {
+               d1[0]= uv[1][0] - uv[0][0];
+               d1[1]= uv[1][1] - uv[0][1];
+               d2[0]= uv[2][0] - uv[0][0];
+               d2[1]= uv[2][1] - uv[0][1];
+
+               det = d2[0]*d1[1] - d2[1]*d1[0];
+
+               if(det != 0.0f) {
+                       det= 1.0f/det;
+                       w1= -d2[1]*det;
+                       w2= d1[1]*det;
+
+                       mat[1][0]= w1*(v2[0] - v1[0]) + w2*(v3[0] - v1[0]);
+                       mat[1][1]= w1*(v2[1] - v1[1]) + w2*(v3[1] - v1[1]);
+                       mat[1][2]= w1*(v2[2] - v1[2]) + w2*(v3[2] - v1[2]);
+                       Normalize(mat[1]);
+               }
+               else
+                       mat[1][0]= mat[1][1]= mat[1][2]= 0.0f;
+       }
+       else {
+               VecSubf(mat[1], v2, v1);
+               Normalize(mat[1]);
+       }
+       
+       /* third as a cross product */
+       Crossf(mat[0], mat[1], mat[2]);
+}
+
+static void psys_face_mat(DerivedMesh *dm, ParticleData *pa, float mat[][4])
+{
+       float v1[3], v2[3], v3[3];
+       MFace *mface;
+       OrigSpaceFace *osface;
+
+       int i = pa->num_dmcache==DMCACHE_NOTFOUND ? pa->num : pa->num_dmcache;
+       
+       if (i==-1 || i >= dm->getNumFaces(dm)) { Mat4One(mat); return; }
+       mface=dm->getFaceData(dm,i,CD_MFACE);
+       osface=dm->getFaceData(dm,i,CD_ORIGSPACE);
+       
+       dm->getVertCo(dm,mface->v1,v1);
+       dm->getVertCo(dm,mface->v2,v2);
+       dm->getVertCo(dm,mface->v3,v3);
+
+       triatomat(v1, v2, v3, (osface)? osface->uv: NULL, mat);
+}
+void psys_mat_hair_to_object(Object *ob, DerivedMesh *dm, short from, ParticleData *pa, float hairmat[][4])
+{
+       float vec[3];
+
+       psys_face_mat(dm, pa, hairmat);
+       psys_particle_on_dm(ob, dm, from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, vec, 0, 0, 0);
+       VECCOPY(hairmat[3],vec);
+}
+
+/*
+void psys_key_to_geometry(DerivedMesh *dm, ParticleData *pa, ParticleKey *key)
+{
+       float q[4], v1[3], v2[3], v3[3];
+
+       dm->getVertCo(dm,pa->verts[0],v1);
+       dm->getVertCo(dm,pa->verts[1],v2);
+       dm->getVertCo(dm,pa->verts[2],v3);
+
+       triatoquat(v1, v2, v3, q);
+
+       QuatInv(q);
+
+       VECSUB(key->co,key->co,v1);
+
+       VECADD(key->vel,key->vel,key->co);
+
+       QuatMulVecf(q, key->co);
+       QuatMulVecf(q, key->vel);
+       
+       VECSUB(key->vel,key->vel,key->co);
+
+       QuatMul(key->rot,q,key->rot);
+}
+
+void psys_key_from_geometry(DerivedMesh *dm, ParticleData *pa, ParticleKey *key)
+{
+       float q[4], v1[3], v2[3], v3[3];
+
+       dm->getVertCo(dm,pa->verts[0],v1);
+       dm->getVertCo(dm,pa->verts[1],v2);
+       dm->getVertCo(dm,pa->verts[2],v3);
+
+       triatoquat(v1, v2, v3, q);
+
+       VECADD(key->vel,key->vel,key->co);
+
+       QuatMulVecf(q, key->co);
+       QuatMulVecf(q, key->vel);
+       
+       VECSUB(key->vel,key->vel,key->co);
+
+       VECADD(key->co,key->co,v1);
+
+       QuatMul(key->rot,q,key->rot);
+}
+*/
+
+void psys_vec_rot_to_face(DerivedMesh *dm, ParticleData *pa, float *vec)//to_geometry(DerivedMesh *dm, ParticleData *pa, float *vec)
+{
+       float mat[4][4];
+
+       psys_face_mat(dm, pa, mat);
+       Mat4Transp(mat); /* cheap inverse for rotation matrix */
+       Mat4Mul3Vecfl(mat, vec);
+}
+
+/* unused */
+#if 0
+static void psys_vec_rot_from_face(DerivedMesh *dm, ParticleData *pa, float *vec)//from_geometry(DerivedMesh *dm, ParticleData *pa, float *vec)
+{
+       float q[4], v1[3], v2[3], v3[3];
+       /*
+       dm->getVertCo(dm,pa->verts[0],v1);
+       dm->getVertCo(dm,pa->verts[1],v2);
+       dm->getVertCo(dm,pa->verts[2],v3);
+       */
+       /* replace with this */
+       MFace *mface;
+       int i; // = psys_particle_dm_face_lookup(dm, pa->num, pa->fuv, pa->foffset, (LinkNode*)NULL);
+       i = pa->num_dmcache==DMCACHE_NOTFOUND ? pa->num : pa->num_dmcache;
+       if (i==-1 || i >= dm->getNumFaces(dm)) { vec[0] = vec[1] = 0; vec[2] = 1; return; }
+       mface=dm->getFaceData(dm,i,CD_MFACE);
+       
+       dm->getVertCo(dm,mface->v1,v1);
+       dm->getVertCo(dm,mface->v2,v2);
+       dm->getVertCo(dm,mface->v3,v3);
+       /* done */
+       
+       triatoquat(v1, v2, v3, q);
+
+       QuatMulVecf(q, vec);
+
+       //VECADD(vec,vec,v1);
+}
+#endif
+
+void psys_mat_hair_to_global(Object *ob, DerivedMesh *dm, short from, ParticleData *pa, float hairmat[][4])
+{
+       float facemat[4][4];
+
+       psys_mat_hair_to_object(ob, dm, from, pa, facemat);
+
+       Mat4MulMat4(hairmat, facemat, ob->obmat);
+}
+
+/************************************************/
+/*                     ParticleSettings handling                       */
+/************************************************/
+static void default_particle_settings(ParticleSettings *part)
+{
+       int i;
+
+       part->type= PART_EMITTER;
+       part->distr= PART_DISTR_JIT;
+       part->draw_as=PART_DRAW_DOT;
+       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->sta= 1.0;
+       part->end= 100.0;
+       part->lifetime= 50.0;
+       part->jitfac= 1.0;
+       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;
+       part->hair_step= 10;
+       part->keys_step= 5;
+       part->draw_step= 4;
+       part->ren_step= 6;
+       part->adapt_angle= 5;
+       part->adapt_pix= 3;
+       part->kink_axis= 2;
+       part->reactevent= PART_EVENT_DEATH;
+       part->disp=100;
+       part->from= PART_FROM_FACE;
+       part->length= 1.0;
+       part->rotfac= 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->reactshape=1.0f;
+
+       part->mass=1.0;
+       part->size=1.0;
+       part->childsize=1.0;
+
+       part->child_nbr=10;
+       part->childrad=0.2f;
+       part->childflat=0.0f;
+       part->clumppow=0.0f;
+       part->kink_amp=0.2f;
+       part->kink_freq=2.0;
+
+       part->rough1_size=1.0;
+       part->rough2_size=1.0;
+       part->rough_end_shape=1.0;
+
+       part->draw_line[0]=0.5;
+
+       part->banking=1.0;
+       part->max_bank=1.0;
+
+       for(i=0; i<BOID_TOT_RULES; i++){
+               part->boidrule[i]=(char)i;
+               part->boidfac[i]=0.5;
+       }
+
+       part->ipo = NULL;
+}
+
+
+ParticleSettings *psys_new_settings(char *name, Main *main)
+{
+       ParticleSettings *part;
+
+       part= alloc_libblock(&main->particle, ID_PA, name);
+       
+       default_particle_settings(part);
+
+       return part;
+}
+
+ParticleSettings *psys_copy_settings(ParticleSettings *part)
+{
+       ParticleSettings *partn;
+       
+       partn= copy_libblock(part);
+       if(partn->pd) partn->pd= MEM_dupallocN(part->pd);
+       
+       return partn;
+}
+
+void psys_make_local_settings(ParticleSettings *part)
+{
+       Object *ob;
+       ParticleSettings *par;
+       int local=0, lib=0;
+
+       /* - only lib users: do nothing
+           * - only local users: set flag
+           * - mixed: make copy
+           */
+       
+       if(part->id.lib==0) return;
+       if(part->id.us==1) {
+               part->id.lib= 0;
+               part->id.flag= LIB_LOCAL;
+               new_id(0, (ID *)part, 0);
+               return;
+       }
+       
+       /* test objects */
+       ob= G.main->object.first;
+       while(ob) {
+               ParticleSystem *psys=ob->particlesystem.first;
+               for(; psys; psys=psys->next){
+                       if(psys->part==part) {
+                               if(ob->id.lib) lib= 1;
+                               else local= 1;
+                       }
+               }
+               ob= ob->id.next;
+       }
+       
+       if(local && lib==0) {
+               part->id.lib= 0;
+               part->id.flag= LIB_LOCAL;
+               new_id(0, (ID *)part, 0);
+       }
+       else if(local && lib) {
+               
+               par= psys_copy_settings(part);
+               par->id.us= 0;
+               
+               /* do objects */
+               ob= G.main->object.first;
+               while(ob) {
+                       ParticleSystem *psys=ob->particlesystem.first;
+                       for(; psys; psys=psys->next){
+                               if(psys->part==part && ob->id.lib==0) {
+                                       psys->part= par;
+                                       par->id.us++;
+                                       part->id.us--;
+                               }
+                       }
+                       ob= ob->id.next;
+               }
+       }
+}
+
+/* should be integrated to depgraph signals */
+void psys_flush_settings(ParticleSettings *part, int event, int hair_recalc)
+{
+       Base *base;
+       Object *ob, *tob;
+       ParticleSystem *psys;
+       int flush;
+
+       /* update all that have same particle settings */
+       for(base = G.scene->base.first; base; base= base->next) {
+               if(base->object->particlesystem.first) {
+                       ob=base->object;
+                       flush=0;
+                       for(psys=ob->particlesystem.first; psys; psys=psys->next){
+                               if(psys->part==part){
+                                       psys->recalc |= event;
+                                       if(hair_recalc)
+                                               psys->recalc |= PSYS_RECALC_HAIR;
+                                       flush++;
+                               }
+                               else if(psys->part->type==PART_REACTOR){
+                                       ParticleSystem *tpsys;
+                                       tob=psys->target_ob;
+                                       if(tob==0)
+                                               tob=ob;
+                                       tpsys=BLI_findlink(&tob->particlesystem,psys->target_psys-1);
+
+                                       if(tpsys && tpsys->part==part){
+                                               psys->flag |= event;
+                                               flush++;
+                                       }
+                               }
+                       }
+                       if(flush)
+                               DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
+               }
+       }
+}
+/************************************************/
+/*                     Textures                                                        */
+/************************************************/
+static void get_cpa_texture(DerivedMesh *dm, Material *ma, int face_index, float *fw, float *orco, ParticleTexture *ptex, int event)
+{
+       MTex *mtex;
+       int m,setvars=0;
+       float value, rgba[4], texco[3];
+
+       if(ma) for(m=0; m<MAX_MTEX; m++){
+               mtex=ma->mtex[m];
+               if(mtex && (ma->septex & (1<<m))==0){
+                       float var=mtex->varfac;
+                       short blend=mtex->blendtype;
+                       short neg=mtex->pmaptoneg;
+
+                       if(mtex->texco & TEXCO_UV && fw){
+                               int uv_index=CustomData_get_named_layer_index(&dm->faceData,CD_MTFACE,mtex->uvname);
+                               if(uv_index<0){
+                                       uv_index=CustomData_get_active_layer_index(&dm->faceData,CD_MTFACE);
+                               }
+                               if(uv_index>=0){
+                                       CustomDataLayer *layer=&dm->faceData.layers[uv_index];
+                                       MTFace *mtface= &((MTFace*)layer->data)[face_index];
+                                       MFace *mf=dm->getFaceData(dm,face_index,CD_MFACE);
+                                       psys_interpolate_uvs(mtface,mf->v4,fw,texco);
+                                       texco[0]*=2.0;
+                                       texco[1]*=2.0;
+                                       texco[0]-=1.0;
+                                       texco[1]-=1.0;
+                               }
+                               else
+                                       VECCOPY(texco,orco);
+                       }
+                       else{
+                               VECCOPY(texco,orco);
+                       }
+                       externtex(mtex, texco, &value, rgba, rgba+1, rgba+2, rgba+3);
+                       if((event & mtex->pmapto) & MAP_PA_TIME){
+                               if((setvars&MAP_PA_TIME)==0){
+                                       ptex->time=0.0;
+                                       setvars|=MAP_PA_TIME;
+                               }
+                               ptex->time= texture_value_blend(mtex->def_var,ptex->time,value,var,blend,neg & MAP_PA_TIME);
+                       }
+                       if((event & mtex->pmapto) & MAP_PA_LENGTH)
+                               ptex->length= texture_value_blend(value,ptex->length,value,var,blend,neg & MAP_PA_LENGTH);
+                       if((event & mtex->pmapto) & MAP_PA_CLUMP)
+                               ptex->clump= texture_value_blend(value,ptex->clump,value,var,blend,neg & MAP_PA_CLUMP);
+                       if((event & mtex->pmapto) & MAP_PA_KINK)
+                               ptex->kink= texture_value_blend(value,ptex->kink,value,var,blend,neg & MAP_PA_CLUMP);
+               }
+       }
+       CLAMP(ptex->time,0.0,1.0);
+       CLAMP(ptex->length,0.0,1.0);
+       CLAMP(ptex->clump,0.0,1.0);
+       CLAMP(ptex->kink,0.0,1.0);
+}
+void psys_get_texture(Object *ob, Material *ma, ParticleSystemModifierData *psmd, ParticleSystem *psys, ParticleData *pa, ParticleTexture *ptex, int event)
+{
+       MTex *mtex;
+       int m;
+       float value, rgba[4], texco[3];
+       int setvars=0;
+
+       if(ma) for(m=0; m<MAX_MTEX; m++){
+               mtex=ma->mtex[m];
+               if(mtex && (ma->septex & (1<<m))==0){
+                       float var=mtex->varfac;
+                       short blend=mtex->blendtype;
+                       short neg=mtex->pmaptoneg;
+
+                       if(mtex->texco & TEXCO_UV){
+                               int uv_index=CustomData_get_named_layer_index(&psmd->dm->faceData,CD_MTFACE,mtex->uvname);
+                               if(uv_index<0){
+                                       uv_index=CustomData_get_active_layer_index(&psmd->dm->faceData,CD_MTFACE);
+                               }
+                               if(uv_index>=0){
+                                       CustomDataLayer *layer=&psmd->dm->faceData.layers[uv_index];
+                                       MTFace *mtface= &((MTFace*)layer->data)[pa->num];
+                                       MFace *mf=psmd->dm->getFaceData(psmd->dm,pa->num,CD_MFACE);
+                                       psys_interpolate_uvs(mtface,mf->v4,pa->fuv,texco);
+                                       texco[0]*=2.0;
+                                       texco[1]*=2.0;
+                                       texco[0]-=1.0;
+                                       texco[1]-=1.0;
+                               }
+                               else
+                                       //psys_particle_on_emitter(ob,psmd,psys->part->from,pa->num,pa->fuv,pa->foffset,texco,0,0,0);
+                                       /* <jahka> anyways I think it will be too small a difference to notice, so psys_get_texture should only know about the original mesh structure.. no dm needed anywhere */
+                                       psys_particle_on_emitter(ob,psmd,psys->part->from,pa->num,-1,pa->fuv,pa->foffset,texco,0,0,0);
+                       }
+                       else{
+                               //psys_particle_on_emitter(ob,psmd,psys->part->from,pa->num,pa->fuv,pa->offset,texco,0,0,0);
+                               /* ditto above */
+                               psys_particle_on_emitter(ob,psmd,psys->part->from,pa->num,-1,pa->fuv,pa->foffset,texco,0,0,0);
+                       }
+                       externtex(mtex, texco, &value, rgba, rgba+1, rgba+2, rgba+3);
+
+                       if((event & mtex->pmapto) & MAP_PA_TIME){
+                               if((setvars&MAP_PA_TIME)==0){
+                                       ptex->time=0.0;
+                                       setvars|=MAP_PA_TIME;
+                               }
+                               ptex->time= texture_value_blend(mtex->def_var,ptex->time,value,var,blend,neg & MAP_PA_TIME);
+                       }
+                       if((event & mtex->pmapto) & MAP_PA_LIFE)
+                               ptex->life= texture_value_blend(mtex->def_var,ptex->life,value,var,blend,neg & MAP_PA_LIFE);
+                       if((event & mtex->pmapto) & MAP_PA_DENS)
+                               ptex->exist= texture_value_blend(mtex->def_var,ptex->exist,value,var,blend,neg & MAP_PA_DENS);
+                       if((event & mtex->pmapto) & MAP_PA_SIZE)
+                               ptex->size= texture_value_blend(mtex->def_var,ptex->size,value,var,blend,neg & MAP_PA_SIZE);
+                       if((event & mtex->pmapto) & MAP_PA_IVEL)
+                               ptex->ivel= texture_value_blend(mtex->def_var,ptex->ivel,value,var,blend,neg & MAP_PA_IVEL);
+                       if((event & mtex->pmapto) & MAP_PA_PVEL)
+                               texture_rgb_blend(ptex->pvel,rgba,ptex->pvel,value,var,blend);
+                       if((event & mtex->pmapto) & MAP_PA_LENGTH)
+                               ptex->length= texture_value_blend(mtex->def_var,ptex->length,value,var,blend,neg & MAP_PA_LENGTH);
+                       if((event & mtex->pmapto) & MAP_PA_CLUMP)
+                               ptex->clump= texture_value_blend(mtex->def_var,ptex->clump,value,var,blend,neg & MAP_PA_CLUMP);
+                       if((event & mtex->pmapto) & MAP_PA_KINK)
+                               ptex->kink= texture_value_blend(mtex->def_var,ptex->kink,value,var,blend,neg & MAP_PA_CLUMP);
+               }
+       }
+       CLAMP(ptex->time,0.0,1.0);
+       CLAMP(ptex->life,0.0,1.0);
+       CLAMP(ptex->exist,0.0,1.0);
+       CLAMP(ptex->size,0.0,1.0);
+       CLAMP(ptex->ivel,0.0,1.0);
+       CLAMP(ptex->length,0.0,1.0);
+       CLAMP(ptex->clump,0.0,1.0);
+       CLAMP(ptex->kink,0.0,1.0);
+}
+/************************************************/
+/*                     Particle State                                          */
+/************************************************/
+float psys_get_timestep(ParticleSettings *part)
+{
+       return 0.04f*part->timetweak;
+}
+/* part->size should be updated with possible ipo effection before this is called */
+float psys_get_size(Object *ob, Material *ma, ParticleSystemModifierData *psmd, IpoCurve *icu_size, ParticleSystem *psys, ParticleSettings *part, ParticleData *pa, float *vg_size)
+{
+       ParticleTexture ptex;
+       float size=1.0f;
+       
+       if(ma && part->from!=PART_FROM_PARTICLE){
+               ptex.size=size;
+               psys_get_texture(ob,ma,psmd,psys,pa,&ptex,MAP_PA_SIZE);
+               size=ptex.size;
+       }
+       
+       if(icu_size){
+               calc_icu(icu_size,pa->time);
+               size*=icu_size->curval;
+       }
+
+       if(vg_size)
+               size*=psys_interpolate_value_from_verts(psmd->dm,part->from,pa->num,pa->fuv,vg_size);
+
+       if(part->randsize!=0.0)
+               size*= 1.0f - part->randsize*pa->sizemul;
+
+       return size*part->size;
+}
+float psys_get_child_time(ParticleSystem *psys, int child_nbr, float cfra)
+{
+       ParticleSettings *part = psys->part;
+       ChildParticle *cpa=psys->child+child_nbr;
+
+       if(part->childtype==PART_CHILD_FACES){
+               float time;
+               int w=0;
+               time=0.0;
+               while(w<4 && cpa->pa[w]>=0){
+                       time+=cpa->w[w]*(psys->particles+cpa->pa[w])->time;
+                       w++;
+               }
+
+               return (cfra-time)/(part->lifetime*(1.0f-part->randlife*cpa->rand[1]));
+       }
+       else{
+               ParticleData *pa = psys->particles + cpa->parent;
+               return (cfra-pa->time)/pa->lifetime;
+       }
+}
+float psys_get_child_size(ParticleSystem *psys, int child_nbr, float cfra, float *pa_time)
+{
+       ParticleSettings *part = psys->part;
+       ChildParticle *cpa = psys->child + child_nbr;
+       float size, time;
+       
+       if(part->childtype==PART_CHILD_FACES){
+               if(pa_time)
+                       time=*pa_time;
+               else
+                       time=psys_get_child_time(psys,child_nbr,cfra);
+
+               if((part->flag&PART_ABS_TIME)==0 && part->ipo){
+                       calc_ipo(part->ipo, 100*time);
+                       execute_ipo((ID *)part, part->ipo);
+               }
+               size=part->size;
+       }
+       else
+               size=psys->particles[cpa->parent].size;
+
+       size*=part->childsize;
+
+       if(part->childrandsize!=0.0)
+               size *= 1.0f - part->childrandsize*cpa->rand[2];
+
+       return size;
+}
+/* get's hair (or keyed) particles state at the "path time" specified in state->time */
+void psys_get_particle_on_path(Object *ob, ParticleSystem *psys, int p, ParticleKey *state, int vel)
+{
+       ParticleSettings *part = psys->part;
+       ParticleSystemModifierData *psmd = psys_get_modifier(ob, psys);
+       Material *ma = give_current_material(ob, part->omat);
+       ParticleData *pa;
+       ChildParticle *cpa;
+       ParticleTexture ptex;
+       ParticleKey tstate;
+       HairKey *hkey[2];
+       ParticleKey *par=0, keys[4];
+
+       float t, real_t, dfra, keytime;
+       float orco[3];
+       float imat[4][4], hairmat[4][4], cpa_1st[3];
+       float pa_clump = 0.0, pa_kink = 0.0;
+       int totparent = 0;
+       int totpart = psys->totpart;
+       int totchild = psys->totchild;
+       short between = 0, edit = 0;
+
+       float *cpa_fuv; int cpa_num; short cpa_from;
+
+       //if(psys_in_edit_mode(psys)){
+       //      if((psys->edit_path->flag & PSYS_EP_SHOW_CHILD)==0)
+       //              totchild=0;
+       //      edit=1;
+       //}
+
+       if(G.rendering==0&nbs