Particles
authorBrecht Van Lommel <brechtvanlommel@pandora.be>
Mon, 26 Nov 2007 22:09:57 +0000 (22:09 +0000)
committerBrecht Van Lommel <brechtvanlommel@pandora.be>
Mon, 26 Nov 2007 22:09:57 +0000 (22:09 +0000)
=========

Merge of the famous particle patch by Janne Karhu, a full rewrite
of the Blender particle system. This includes:

- Emitter, Hair and Reactor particle types.
- Newtonian, Keyed and Boids physics.
- Various particle visualisation and rendering types.
- Vertex group and texture control for various properties.
- Interpolated child particles from parents.
- Hair editing with combing, growing, cutting, .. .
- Explode modifier.
- Harmonic, Magnetic fields, and multiple falloff types.

.. and lots of other things, some more info is here:

http://wiki.blender.org/index.php/BlenderDev/Particles_Rewrite
http://wiki.blender.org/index.php/BlenderDev/Particles_Rewrite_Doc

The new particle system cannot be backwards compatible. Old particle
systems are being converted to the new system, but will require
tweaking to get them looking the same as before.

Point Cache
===========

The new system to replace manual baking, based on automatic caching
on disk. This is currently used by softbodies and the particle system.

See the Cache API section on:
http://wiki.blender.org/index.php/BlenderDev/PhysicsSprint

Documentation
=============

These new features still need good docs for the release logs, help
for this is appreciated.

97 files changed:
1  2 
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_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
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/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
source/blender/blenkernel/intern/particle_system.c
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
source/blender/blenlib/intern/BLI_kdtree.c
source/blender/blenlib/intern/arithb.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
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
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/drawobject.c
source/blender/src/drawscene.c
source/blender/src/drawview.c
source/blender/src/edit.c
source/blender/src/editipo.c
source/blender/src/editipo_lib.c
source/blender/src/editobject.c
source/blender/src/editparticle.c
source/blender/src/editscreen.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/space.c
source/blender/src/toets.c
source/blender/src/transform.c
source/blender/src/transform_conversions.c
source/blender/src/transform_generics.c
source/blender/src/transform_manipulator.c
source/blender/src/view.c

index 4e58c6617aac5ed6ea336adaef64edaaa0bf18db,55732a1dda75731e7f2fe740675040a575ad6b4d..8f473c85976599ee4e91c601481abe78c0bdf9c5
                        <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,af367ac2ce3baa6672436331f0f3f90a307d08d9..6cc8f27f3988bdd350b1f32b5a649c3519bdcab7
                        <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,7c2db223c743756aacfba9468d7c79cb07be782e..d447b3b4f2c61f712cee19c4447627b8f29c1054
Binary files differ
index 8d67a88f679aae5ad652f665feb290e7a1b830d6,8d67a88f679aae5ad652f665feb290e7a1b830d6..c39c26b063dbea88bbe8c418903cfba56d257a94
Binary files differ
index 1852dc72a400d24d55f95fd7b272717130192ab1,872717fdb9b27e79139c9005121239ac8db62385..29fc1438c479bcd22ad247357584910283053edc
@@@ -70,6 -69,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,ddc18851a9f9d7ffe9b2ff14157b09635243bf68..7a838ff76143adc8f4e64ad02c5dd1020a0721c8
@@@ -225,11 -215,5 +225,18 @@@ void antialias_tagbuf(int xsize, int ys
  /* imagetexture.c */
  void ibuf_sample(struct ImBuf *ibuf, float fx, float fy, float dx, float dy, float *result);
  
 +/* modifier.c */
 +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,4b9e10651cf065a4ff0bb63480dfec93d51f48fd..5cd905d07ac7c8b74befef11ba63bb9e0958318c
@@@ -43,8 -43,8 +43,8 @@@ extern "C" 
  struct ListBase;
  struct MemFile;
  
 -#define BLENDER_VERSION                       244
 -#define BLENDER_SUBVERSION            2
 +#define BLENDER_VERSION                       245
- #define BLENDER_SUBVERSION            7
++#define BLENDER_SUBVERSION            8
  
  #define BLENDER_MINVERSION            240
  #define BLENDER_MINSUBVERSION 0
index 979ed31fb2000e09bb4313ed06ac5ed957f3534d,979ed31fb2000e09bb4313ed06ac5ed957f3534d..2dc4de3213297549f710783c18846bbcc9ebfbe6
@@@ -123,5 -123,5 +123,7 @@@ void filldisplist(struct ListBase *disp
  
  void fastshade_free_render(void);
  
++float calc_taper(struct Object *taperobj, int cur, int tot);
++
  #endif
  
index 949b6c959b952b71cf3aff873ead73095c9a9ca4,98a0cb99942d0e4f44a400ab290282ee7a4eb008..e71145e8d79d98dfb6d1f4e25d38361271d14899
@@@ -185,16 -187,9 +185,17 @@@ typedef struct Global 
  #define G_VERSE_CONNECTED  (1 << 26)
  #define G_DRAW_VERSE_DEBUG (1 << 27)
  /*#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 */
 +
 +/* macro for testing face select mode
 + * Texture paint could be removed since selected faces are not used
 + * however hiding faces is useful */
 +#define FACESEL_PAINT_TEST ((G.f&G_FACESELECT) && (G.f & (G_VERTEXPAINT|G_WEIGHTPAINT|G_TEXTUREPAINT))) 
  
  /* G.fileflags */
  
  #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,6e0f2fdb284536c9131a8e1977057f4a69ac76ee..2cfa1dc5cc41fb792f5828e6eddfb736db3443dc
@@@ -78,6 -78,6 +78,7 @@@ typedef struct Main 
        ListBase action;
        ListBase nodetree;
        ListBase brush;
++      ListBase particle;
  } Main;
  
  
index 297443b883d57b91f24c74eaaece97826d93aec7,ce3f33bd35c589e8c7d5b155b64d382f4106ae94..24da941db905bf2064b08795d0dbd5a46e82d819
@@@ -59,6 -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 -81,8 +87,8 @@@
        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 */
@@@ -277,11 -271,11 +283,14 @@@ int           modifiers_getCageIndex(st
                                       int *lastPossibleCageIndex_r);
  
  int           modifiers_isSoftbodyEnabled(struct 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
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..afed219dbc6389f70682269d5c7e186d95cc9b32
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,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 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..46d240a41833a2e54d1b40daea3774e15c1038e7
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,48 @@@
++/*
++*
++* ***** BEGIN GPL LICENSE BLOCK *****
++*
++* This program is free software; you can redistribute it and/or
++* modify it under the terms of the GNU General Public License
++* as published by the Free Software Foundation; either version 2
++* of the License, or (at your option) any later version.
++*
++* This program is distributed in the hope that it will be useful,
++* but WITHOUT ANY WARRANTY; without even the implied warranty of
++* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++* GNU General Public License for more details.
++*
++* You should have received a copy of the GNU General Public License
++* along with this program; if not, write to the Free Software  Foundation,
++* Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
++*
++* The Original Code is Copyright (C) 2006 Blender Foundation.
++* All rights reserved.
++*
++* The Original Code is: all of this file.
++*
++* Contributor(s): Campbell Barton <ideasman42@gmail.com>
++*
++* ***** END GPL LICENSE BLOCK *****
++*/
++
++#ifndef BKE_POINTCACHE_H
++#define BKE_POINTCACHE_H
++
++#include "DNA_ID.h"
++
++/* 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
++
++#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,15200bf46f8b5d54e0a9e4f61199eca2f007fbac..0f58b93730a564900ed43108e3cfa42f86640e71
  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,81dd2807812618cdf6ecea4781b6c4f5ee9d0e0d..f3f66190c31b98f020bf2feb86d5cb006b390d08
  #define ELEM6(a, b, c, d, e, f, g)      ( ELEM(a, b, c) || ELEM4(a, d, e, f, g) )
  #define ELEM7(a, b, c, d, e, f, g, h)   ( ELEM3(a, b, c, d) || ELEM4(a, e, f, g, h) )
  #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,344f763608c23b25196b953a1f5195a29e242e63..7e1aca3bb204eddb1002ff557894e520ad5231ba
@@@ -246,6 -229,6 +246,8 @@@ void fluidsimSettingsCopy(struct Fluids
  
  /*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) {}
@@@ -324,18 -307,6 +326,23 @@@ void antialias_tagbuf(int xsize, int ys
  /* imagetexture.c stub */
  void ibuf_sample(struct ImBuf *ibuf, float fx, float fy, float dx, float dy, float *result) {}
  
 -void update_for_newframe()
 -{
 -}
 +void update_for_newframe() {}
 +
 +struct FileList;
 +void BIF_filelist_freelib(struct FileList* filelist) {};
 +
 +/* edittime.c stub */
 +TimeMarker *get_frame_marker(int frame){return 0;};
 +
 +/* editseq.c */
 +Sequence *get_forground_frame_seq(int frame){return 0;};
 +
 +/* modifier.c stub */
 +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,5f8e9c7b207bcdcdbcf776bb7bf36de7d23a0374..5e688af14a4b6667b0d68863e722b7b06063a164
@@@ -55,6 -54,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"
@@@ -75,8 -72,9 +76,9 @@@
  #include "BKE_mesh.h"
  #include "BKE_object.h"
  #include "BKE_subsurf.h"
 -#include "BKE_deform.h"
 -#include "BKE_modifier.h"
 -#include "BKE_key.h"
 +#include "BKE_texture.h"
 +#include "BKE_utildefines.h"
++#include "BKE_particle.h"
  
  #ifdef WITH_VERSE
  #include "BKE_verse.h"
@@@ -1961,6 -1770,6 +1963,7 @@@ static void mesh_calc_modifiers(Object 
                 */
  
                if(mti->type == eModifierTypeType_OnlyDeform) {
++                      
                        /* No existing verts to deform, need to build them. */
                        if(!deformedVerts) {
                                if(dm) {
  
                        /* 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 -1980,6 +2188,10 @@@ static void editmesh_calc_modifiers(Der
                        /* 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 -2146,7 +2370,7 @@@ static void mesh_build_data(Object *ob
  
        if(ob!=G.obedit) {
                Object *obact = G.scene->basact?G.scene->basact->object:NULL;
-               int editing = (FACESEL_PAINT_TEST);
 -              int editing = (G.f & (G_FACESELECT|G_WEIGHTPAINT|G_VERTEXPAINT|G_TEXTUREPAINT));
++              int editing = (FACESEL_PAINT_TEST)|(G.f & G_PARTICLEEDIT);
                int needMapping = editing && (ob==obact);
  
                if( (G.f & G_WEIGHTPAINT) && ob==obact ) {
index 32ea2b3ed2c7a31666d478a93c52abcd05362243,0019308a5691abebf81da34609e93c6cc56f53a3..43168733b3ff74dbf9e44dcee8f89604380ca68d
@@@ -38,6 -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 -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 -559,134 +567,143 @@@ static void face_duplilist(ListBase *lb
        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);
 -      ctime= bsystem_time(par, 0, (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 -767,13 +784,14 @@@ ListBase *object_duplilist(Scene *sce, 
        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 -819,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,cad8d3b0861bc42f61e9cbf0727c4c415ad2f887..9845f5711261983459076db438f8e5aa4ec6ed11
@@@ -266,7 -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,2d5f5f091c37670cf9d34dea68189be0154eec14..6a85630791637ac946adad537c3474e4ddb1489d
@@@ -751,6 -751,6 +751,7 @@@ DerivedMesh *CDDM_from_mesh(Mesh *mesh
        /* 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 -798,6 +799,8 @@@ DerivedMesh *CDDM_from_editmesh(EditMes
        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 -889,6 +892,7 @@@ DerivedMesh *CDDM_copy(DerivedMesh *sou
  
        /* 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 466ba9f4201301dc7cbb1236903adf5f611bc4cb,2c8199f90f361722d82e6fc669e61dbdb76c0cf7..aa0dc10f4e0251d2bf296290269032cadb006058
@@@ -271,7 -271,7 +271,7 @@@ static void layerSwap_tface(void *data
  
  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;
                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 -370,11 +447,13 @@@ const LayerTypeInfo LAYERTYPEINFO[CD_NU
        {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 -387,7 +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_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,a71ed731b078961f9db1970f3aa0ca2e2a91f93e..924f544285ef3fc082b6a73547731120bb19e23a
@@@ -57,6 -56,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 -71,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 -351,6 +355,7 @@@ static void build_dag_object(DagForest 
        DagNode * node2;
        DagNode * node3;
        Key *key;
++      ParticleSystem *psys;
        int addtoroot= 1;
        
        node = dag_get_node(dag, ob);
                        }
                }
        }
++
++      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){
 -              if (constraint_has_target(con)) {
 -                      char *str;
 -                      Object *obt= get_constraint_target(con, &str);
 +      for (con = ob->constraints.first; con; con=con->next) {
 +              bConstraintTypeInfo *cti= constraint_get_typeinfo(con);
 +              ListBase targets = {NULL, NULL};
 +              bConstraintTarget *ct;
 +              
 +              if (cti && cti->get_constraint_targets) {
 +                      cti->get_constraint_targets(con, &targets);
                        
 -                      node2 = dag_get_node(dag, obt);
 -                      if(con->type==CONSTRAINT_TYPE_FOLLOWPATH)
 -                              dag_add_relation(dag, node2, node, DAG_RL_DATA_OB|DAG_RL_OB_OB);
 -                      else {
 -                              if(obt->type==OB_ARMATURE && str[0])
 -                                      dag_add_relation(dag, node2, node, DAG_RL_DATA_OB|DAG_RL_OB_OB);
 +                      for (ct= targets.first; ct; ct= ct->next) {
 +                              Object *obt;
 +                              
 +                              if (ct->tar)
 +                                      obt= ct->tar;
                                else
 -                                      dag_add_relation(dag, node2, node, DAG_RL_OB_OB);
 +                                      continue;
 +                              
 +                              node2 = dag_get_node(dag, obt);
 +                              if (ELEM(con->type, CONSTRAINT_TYPE_FOLLOWPATH, CONSTRAINT_TYPE_CLAMPTO))
 +                                      dag_add_relation(dag, node2, node, DAG_RL_DATA_OB|DAG_RL_OB_OB);
 +                              else {
 +                                      if (ELEM3(obt->type, OB_ARMATURE, OB_MESH, OB_LATTICE) && (ct->subtarget[0]))
 +                                              dag_add_relation(dag, node2, node, DAG_RL_DATA_OB|DAG_RL_OB_OB);
 +                                      else
 +                                              dag_add_relation(dag, node2, node, DAG_RL_OB_OB);
 +                              }
 +                              addtoroot = 0;
                        }
 -                      addtoroot = 0;
 +                      
 +                      if (cti->flush_constraint_targets)
 +                              cti->flush_constraint_targets(con, &targets, 1);
                }
        }
  
@@@ -1813,6 -1765,6 +1864,8 @@@ static void dag_object_time_update_flag
                                                ob->recalc |= OB_RECALC_DATA; // NT FSPARTICLE
                                        }
                                }
++                              if(ob->particlesystem.first)
++                                      ob->recalc |= OB_RECALC_DATA;
                                break;
                        case OB_CURVE:
                        case OB_SURF:
                                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,30a4c8c34339451bbb6928721df286c0ed565a3d..f410167c2ac2195d9eeaa829f20b3af86be2dee6
@@@ -1098,7 -1098,7 +1098,7 @@@ void curve_to_filledpoly(Curve *cu, Lis
    - 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 +1256,7 @@@ void curve_calc_modifiers_post(Object *
  
                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,f42d0fa79e22a673d9e943c604ccaaee7744654a..1b345616888cf00241867b9e0745e94506931976
@@@ -799,7 -799,7 +799,7 @@@ static int pdDoDeflection(RNG *rng, flo
                                                
  //                                    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;
  // 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,08924ac96d58c4d6ec1d94a071be28e909f70d6d..03a34df090a2a0af69ae2b11d5d7baa93d6fdc3c
@@@ -52,6 -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 -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 -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 -1185,6 +1238,7 @@@ void *get_ipo_poin(ID *id, IpoCurve *ic
        Lamp *la;
        Sequence *seq;
        World *wo;
++      ParticleSettings *part;
  
        *type= IPO_FLOAT;
  
                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) {
                        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,14 -1809,6 +1907,37 @@@ 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;
 +      }
 +      
 +      /* by default, slider limits will be icu->ymin and icu->ymax */
 +      icu->slide_min= icu->ymin;
 +      icu->slide_max= icu->ymax;
  }
  
  /* not for actions or constraints! */
@@@ -2325,6 -2271,6 +2400,7 @@@ void make_cfra_list(Ipo *ipo, ListBase 
                                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,0163cced795e856362fc984dd750fdd35ecd21ac..e81d3bac655b993afb764d56b3290be0573906b4
@@@ -78,6 -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 -194,6 +196,8 @@@ ListBase *wich_libbase(Main *mainlib, s
                        return &(mainlib->nodetree);
                case ID_BR:
                        return &(mainlib->brush);
++              case ID_PA:
++                      return &(mainlib->particle);
        }
        return 0;
  }
@@@ -254,16 -254,16 +258,17 @@@ int set_listbasepointers(Main *main, Li
        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 -359,6 +364,9 @@@ static ID *alloc_libblock_notest(short 
                case ID_BR:
                        id = MEM_callocN(sizeof(Brush), "brush");
                        break;
++              case ID_PA:
++                      id = MEM_callocN(sizeof(ParticleSettings), "ParticleSettings");
++                      break;
        }
        return id;
  }
@@@ -503,6 -502,6 +511,9 @@@ void free_libblock(ListBase *lb, void *
                case ID_BR:
                        free_brush((Brush *)id);
                        break;
++              case ID_PA:
++                      psys_free_settings((ParticleSettings *)id);
++                      break;
        }
  
        if (id->properties) {
index 3a6611a2be778d2604a91d51eff4ca0f4885f2df,707f050d56e27068449b42ebed3424248a2c482e..9336dde01510fb256397c7725ee09486f24ca238
  #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"
  
  #include "MEM_guardedalloc.h"
  
@@@ -59,6 -58,6 +60,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_main.h"
  #include "BKE_anim.h"
  #include "BKE_bad_level_calls.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_material.h"
++#include "BKE_particle.h"
++#include "BKE_pointcache.h"
++#include "BKE_utildefines.h"
  #include "depsgraph_private.h"
  
  #include "LOD_DependKludge.h"
@@@ -4681,16 -4570,8 +4687,16 @@@ static void armatureModifier_deformVert
  {
        ArmatureModifierData *amd = (ArmatureModifierData*) md;
  
 -      armature_deform_verts(amd->object, ob, derivedData, vertexCos, numVerts,
 -                            amd->deformflag, amd->defgrp_name);
 +      modifier_vgroup_cache(md, vertexCos); /* if next modifier needs original vertices */
 +      
 +      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);
 +              amd->prevCos= NULL;
 +      }
  }
  
  static void armatureModifier_deformVertsEM(
@@@ -4998,455 -4863,160 +5004,1669 @@@ static DerivedMesh *booleanModifier_app
        return derivedData;
  }
  
 -/***/
++/* Particles */
++static void particleSystemModifier_initData(ModifierData *md) 
++{
++      ParticleSystemModifierData *psmd= (ParticleSystemModifierData*) md;
++      psmd->psys= 0;
++      psmd->dm=0;
 -static ModifierTypeInfo typeArr[NUM_MODIFIER_TYPES];
 -static int typeArrInit = 1;
++}
++static void particleSystemModifier_freeData(ModifierData *md)
++{
++      ParticleSystemModifierData *psmd= (ParticleSystemModifierData*) md;
 -ModifierTypeInfo *modifierType_getInfo(ModifierType type)
++      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)
+ {
 -      if (typeArrInit) {
 -              ModifierTypeInfo *mti;
++      ParticleSystemModifierData *psmd= (ParticleSystemModifierData*) md;
++      ParticleSystemModifierData *tpsmd= (ParticleSystemModifierData*) target;
 -              memset(typeArr, 0, sizeof(typeArr));
++      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;
++}
 -              /* Initialize and return the appropriate type info structure,
 -               * assumes that modifier has:
 -               *  name == typeName, 
 -               *  structName == typeName + 'ModifierData'
 -               */
 -#define INIT_TYPE(typeName) \
 -              (strcpy(typeArr[eModifierType_##typeName].name, #typeName), \
 -              strcpy(typeArr[eModifierType_##typeName].structName, \
 -                     #typeName "ModifierData"), \
 -              typeArr[eModifierType_##typeName].structSize = \
 -                                                  sizeof(typeName##ModifierData), \
 -              &typeArr[eModifierType_##typeName])
++CustomDataMask particleSystemModifier_requiredDataMask(ModifierData *md)
++{
++      ParticleSystemModifierData *psmd= (ParticleSystemModifierData*) md;
++      CustomDataMask dataMask = (1 << CD_MTFACE) + (1 << CD_MEDGE);
++      int i;
 -              mti = &typeArr[eModifierType_None];
 -              strcpy(mti->name, "None");
 -              strcpy(mti->structName, "ModifierData");
 -              mti->structSize = sizeof(ModifierData);
 -              mti->type = eModifierType_None;
 -              mti->flags = eModifierTypeFlag_AcceptsMesh
 -                           | eModifierTypeFlag_AcceptsCVs;
 -              mti->isDisabled = noneModifier_isDisabled;
 -              
 -              mti = INIT_TYPE(Curve);
 -              mti->type = eModifierTypeType_OnlyDeform;
 -              mti->flags = eModifierTypeFlag_AcceptsCVs
 -                           | eModifierTypeFlag_SupportsEditmode;
 -              mti->initData = curveModifier_initData;
 -              mti->copyData = curveModifier_copyData;
 -              mti->requiredDataMask = curveModifier_requiredDataMask;
 -              mti->isDisabled = curveModifier_isDisabled;
 -              mti->foreachObjectLink = curveModifier_foreachObjectLink;
 -              mti->updateDepgraph = curveModifier_updateDepgraph;
 -              mti->deformVerts = curveModifier_deformVerts;
 -              mti->deformVertsEM = curveModifier_deformVertsEM;
++      /* 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;
 -              mti = INIT_TYPE(Lattice);
 -              mti->type = eModifierTypeType_OnlyDeform;
 -              mti->flags = eModifierTypeFlag_AcceptsCVs
 -                           | eModifierTypeFlag_SupportsEditmode;
 -              mti->copyData = latticeModifier_copyData;
 -              mti->requiredDataMask = latticeModifier_requiredDataMask;
 -              mti->isDisabled = latticeModifier_isDisabled;
 -              mti->foreachObjectLink = latticeModifier_foreachObjectLink;
 -              mti->updateDepgraph = latticeModifier_updateDepgraph;
 -              mti->deformVerts = latticeModifier_deformVerts;
 -              mti->deformVertsEM = latticeModifier_deformVertsEM;
++      if(curvecount==0){
++              DispList *dl;
 -              mti = INIT_TYPE(Subsurf);
 -              mti->type = eModifierTypeType_Constructive;
 -              mti->flags = eModifierTypeFlag_AcceptsMesh
 -                           | eModifierTypeFlag_SupportsMapping
 -                           | eModifierTypeFlag_SupportsEditmode
 -                           | eModifierTypeFlag_EnableInEditmode;
 -              mti->initData = subsurfModifier_initData;
 -              mti->copyData = subsurfModifier_copyData;
 -              mti->freeData = subsurfModifier_freeData;
 -              mti->applyModifier = subsurfModifier_applyModifier;
 -              mti->applyModifierEM = subsurfModifier_applyModifierEM;
++              totcurve=0;
++              for(dl=cu->disp.first; dl; dl=dl->next){
++                      totcurve++;
++              }
++      }
 -              mti = INIT_TYPE(Build);
 -              mti->type = eModifierTypeType_Nonconstructive;
 -              mti->flags = eModifierTypeFlag_AcceptsMesh;
 -              mti->initData = buildModifier_initData;
 -              mti->copyData = buildModifier_copyData;
 -              mti->dependsOnTime = buildModifier_dependsOnTime;
 -              mti->applyModifier = buildModifier_applyModifier;
++      curvecount++;
 -              mti = INIT_TYPE(Array);
 -              mti->type = eModifierTypeType_Constructive;
 -              mti->flags = eModifierTypeFlag_AcceptsMesh
 -                           | eModifierTypeFlag_SupportsMapping
 -                           | eModifierTypeFlag_SupportsEditmode
 -                           | eModifierTypeFlag_EnableInEditmode;
 -              mti->initData = arrayModifier_initData;
 -              mti->copyData = arrayModifier_copyData;
 -              mti->foreachObjectLink = arrayModifier_foreachObjectLink;
 -              mti->updateDepgraph = arrayModifier_updateDepgraph;
 -              mti->applyModifier = arrayModifier_applyModifier;
 -              mti->applyModifierEM = arrayModifier_applyModifierEM;
++      if(curvecount==totcurve){
++              curvecount=0;
++              return 1;
++      }
 -              mti = INIT_TYPE(Mirror);
 -              mti->type = eModifierTypeType_Constructive;
 -              mti->flags = eModifierTypeFlag_AcceptsMesh
 -                           | eModifierTypeFlag_SupportsMapping
 -                           | eModifierTypeFlag_SupportsEditmode
 -                           | eModifierTypeFlag_EnableInEditmode;
 -              mti->initData = mirrorModifier_initData;
 -              mti->copyData = mirrorModifier_copyData;
 -              mti->applyModifier = mirrorModifier_applyModifier;
 -              mti->applyModifierEM = mirrorModifier_applyModifierEM;
++      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;
 -              mti = INIT_TYPE(EdgeSplit);
 -              mti->type = eModifierTypeType_Constructive;
 -              mti->flags = eModifierTypeFlag_AcceptsMesh
 -                           | eModifierTypeFlag_SupportsMapping
 -                           | eModifierTypeFlag_SupportsEditmode
 -                           | eModifierTypeFlag_EnableInEditmode;
 -              mti->initData = edgesplitModifier_initData;
 -              mti->copyData = edgesplitModifier_copyData;
 -              mti->applyModifier = edgesplitModifier_applyModifier;
 -              mti->applyModifierEM = edgesplitModifier_applyModifierEM;
++      if(dm==0){
++              if(ob->type==OB_MESH){
++                      dm = CDDM_from_mesh((Mesh*)(ob->data), ob);
 -              mti = INIT_TYPE(Displace);
 -              mti->type = eModifierTypeType_OnlyDeform;
 -              mti->flags = eModifierTypeFlag_AcceptsMesh|eModifierTypeFlag_SupportsEditmode;
 -              mti->initData = displaceModifier_initData;
 -              mti->copyData = displaceModifier_copyData;
 -              mti->requiredDataMask = displaceModifier_requiredDataMask;
 -              mti->foreachObjectLink = displaceModifier_foreachObjectLink;
 -              mti->foreachIDLink = displaceModifier_foreachIDLink;
 -              mti->updateDepgraph = displaceModifier_updateDepgraph;
 -              mti->isDisabled = displaceModifier_isDisabled;
 -              mti->deformVerts = displaceModifier_deformVerts;
 -              mti->deformVertsEM = displaceModifier_deformVertsEM;
++                      CDDM_apply_vert_coords(dm, vertexCos);
++                      //CDDM_calc_normals(dm);
 -              mti = INIT_TYPE(UVProject);
 -              mti->type = eModifierTypeType_Nonconstructive;
 -              mti->flags = eModifierTypeFlag_AcceptsMesh
 -                           | eModifierTypeFlag_SupportsMapping
 -                           | eModifierTypeFlag_SupportsEditmode
 -                           | eModifierTypeFlag_EnableInEditmode;
 -              mti->initData = uvprojectModifier_initData;
 -              mti->copyData = uvprojectModifier_copyData;
 -              mti->requiredDataMask = uvprojectModifier_requiredDataMask;
 -              mti->foreachObjectLink = uvprojectModifier_foreachObjectLink;
 -              mti->foreachIDLink = uvprojectModifier_foreachIDLink;
 -              mti->updateDepgraph = uvprojectModifier_updateDepgraph;
 -              mti->applyModifier = uvprojectModifier_applyModifier;
 -              mti->applyModifierEM = uvprojectModifier_applyModifierEM;
++                      needsFree=1;
++              }
++              else if(ELEM3(ob->type,OB_FONT,OB_CURVE,OB_SURF)){
++                      Object *tmpobj;
++                      Curve *tmpcu;
 -              mti = INIT_TYPE(Decimate);
 -              mti->type = eModifierTypeType_Nonconstructive;
 -              mti->flags = eModifierTypeFlag_AcceptsMesh;
 -              mti->initData = decimateModifier_initData;
 -              mti->copyData = decimateModifier_copyData;
 -              mti->applyModifier = decimateModifier_applyModifier;
++                      if(is_last_displist(ob)){
++                              /* copies object and modifiers (but not the data) */
++                              tmpobj= copy_object( ob );
++                              tmpcu = (Curve *)tmpobj->data;
++                              tmpcu->id.us--;
 -              mti = INIT_TYPE(Smooth);
 -              mti->type = eModifierTypeType_OnlyDeform;
 -              mti->flags = eModifierTypeFlag_AcceptsMesh
 -                           | eModifierTypeFlag_SupportsEditmode;
 -              mti->initData = smoothModifier_initData;
++                              /* 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)
 +{
 +      MeshDeformModifierData *mmd = (MeshDeformModifierData*) md;
 +
 +      mmd->gridsize= 5;
 +}
 +
 +static void meshdeformModifier_freeData(ModifierData *md)
 +{
 +      MeshDeformModifierData *mmd = (MeshDeformModifierData*) md;
 +
 +      if(mmd->bindweights) MEM_freeN(mmd->bindweights);
 +      if(mmd->bindcos) MEM_freeN(mmd->bindcos);
 +      if(mmd->dyngrid) MEM_freeN(mmd->dyngrid);
 +      if(mmd->dyninfluences) MEM_freeN(mmd->dyninfluences);
 +      if(mmd->dynverts) MEM_freeN(mmd->dynverts);
 +}
 +
 +static void meshdeformModifier_copyData(ModifierData *md, ModifierData *target)
 +{
 +      MeshDeformModifierData *mmd = (MeshDeformModifierData*) md;
 +      MeshDeformModifierData *tmmd = (MeshDeformModifierData*) target;
 +
 +      tmmd->gridsize = mmd->gridsize;
 +      tmmd->object = mmd->object;
 +}
 +
 +CustomDataMask meshdeformModifier_requiredDataMask(ModifierData *md)
 +{     
 +      MeshDeformModifierData *mmd = (MeshDeformModifierData *)md;
 +      CustomDataMask dataMask = 0;
 +
 +      /* ask for vertexgroups if we need them */
 +      if(mmd->defgrp_name[0]) dataMask |= (1 << CD_MDEFORMVERT);
 +
 +      return dataMask;
 +}
 +
 +static int meshdeformModifier_isDisabled(ModifierData *md)
 +{
 +      MeshDeformModifierData *mmd = (MeshDeformModifierData*) md;
 +
 +      return !mmd->object;
 +}
 +
 +static void meshdeformModifier_foreachObjectLink(
 +                ModifierData *md, Object *ob,
 +                void (*walk)(void *userData, Object *ob, Object **obpoin),
 +                void *userData)
 +{
 +      MeshDeformModifierData *mmd = (MeshDeformModifierData*) md;
 +
 +      walk(userData, ob, &mmd->object);
 +}
 +
 +static void meshdeformModifier_updateDepgraph(
 +                ModifierData *md, DagForest *forest, Object *ob,
 +                DagNode *obNode)
 +{
 +      MeshDeformModifierData *mmd = (MeshDeformModifierData*) md;
 +
 +      if (mmd->object) {
 +              DagNode *curNode = dag_get_node(forest, mmd->object);
 +
 +              dag_add_relation(forest, curNode, obNode,
 +                               DAG_RL_DATA_DATA|DAG_RL_OB_DATA|DAG_RL_DATA_OB|DAG_RL_OB_OB);
 +      }
 +}
 +
 +static float meshdeform_dynamic_bind(MeshDeformModifierData *mmd, float (*dco)[3], float *vec)
 +{
 +      MDefCell *cell;
 +      MDefInfluence *inf;
 +      float gridvec[3], dvec[3], ivec[3], co[3], wx, wy, wz;
 +      float weight, cageweight, totweight, *cageco;
 +      int i, j, a, x, y, z, size;
 +
 +      co[0]= co[1]= co[2]= 0.0f;
 +      totweight= 0.0f;
 +      size= mmd->dyngridsize;
 +
 +      for(i=0; i<3; i++) {
 +              gridvec[i]= (vec[i] - mmd->dyncellmin[i] - mmd->dyncellwidth*0.5f)/mmd->dyncellwidth;
 +              ivec[i]= (int)gridvec[i];
 +              dvec[i]= gridvec[i] - ivec[i];
 +      }
 +
 +      for(i=0; i<8; i++) {
 +              if(i & 1) { x= ivec[0]+1; wx= dvec[0]; }
 +              else { x= ivec[0]; wx= 1.0f-dvec[0]; } 
 +
 +              if(i & 2) { y= ivec[1]+1; wy= dvec[1]; }
 +              else { y= ivec[1]; wy= 1.0f-dvec[1]; } 
 +
 +              if(i & 4) { z= ivec[2]+1; wz= dvec[2]; }
 +              else { z= ivec[2]; wz= 1.0f-dvec[2]; } 
 +
 +              CLAMP(x, 0, size-1);
 +              CLAMP(y, 0, size-1);
 +              CLAMP(z, 0, size-1);
 +
 +              a= x + y*size + z*size*size;
 +              weight= wx*wy*wz;
 +
 +              cell= &mmd->dyngrid[a];
 +              inf= mmd->dyninfluences + cell->offset;
 +              for(j=0; j<cell->totinfluence; j++, inf++) {
 +                      cageco= dco[inf->vertex];
 +                      cageweight= weight*inf->weight;
 +                      co[0] += cageweight*cageco[0];
 +                      co[1] += cageweight*cageco[1];
 +                      co[2] += cageweight*cageco[2];
 +                      totweight += cageweight;
 +              }
 +      }
 +
 +      VECCOPY(vec, co);
 +
 +      return totweight;
 +}
 +
 +static void meshdeformModifier_do(
 +                ModifierData *md, Object *ob, DerivedMesh *dm,
 +                float (*vertexCos)[3], int numVerts)
 +{
 +      MeshDeformModifierData *mmd = (MeshDeformModifierData*) md;
 +      float imat[4][4], cagemat[4][4], icagemat[4][4], iobmat[3][3];
 +      float weight, totweight, fac, co[3], *weights, (*dco)[3], (*bindcos)[3];
 +      int a, b, totvert, totcagevert, defgrp_index;
 +      DerivedMesh *tmpdm, *cagedm;
 +      MDeformVert *dvert = NULL;
 +      MDeformWeight *dw;
 +      MVert *cagemvert;
 +
 +      if(!mmd->object || (!mmd->bindcos && !mmd->needbind))
 +              return;
 +      
 +      /* get cage derivedmesh */
 +      if(mmd->object == G.obedit) {
 +              tmpdm= editmesh_get_derived_cage_and_final(&cagedm, 0);
 +              if(tmpdm)
 +                      tmpdm->release(tmpdm);
 +      }
 +      else
 +              cagedm= mesh_get_derived_final(mmd->object, CD_MASK_BAREMESH);
 +      
 +      /* TODO: this could give inifinite loop for circular dependency */
 +      if(!cagedm)
 +              return;
 +
 +      /* compute matrices to go in and out of cage object space */
 +      Mat4Invert(imat, (mmd->bindcos)? mmd->bindmat: mmd->object->obmat);
 +      Mat4MulMat4(cagemat, ob->obmat, imat);
 +      Mat4Invert(icagemat, cagemat);
 +      Mat4Invert(imat, ob->obmat);
 +      Mat3CpyMat4(iobmat, imat);
 +
 +      /* bind weights if needed */
 +      if(!mmd->bindcos)
 +              harmonic_coordinates_bind(mmd, vertexCos, numVerts, cagemat);
 +
 +      /* verify we have compatible weights */
 +      totvert= numVerts;
 +      totcagevert= cagedm->getNumVerts(cagedm);
 +
 +      if(mmd->totvert!=totvert || mmd->totcagevert!=totcagevert || !mmd->bindcos) {
 +              cagedm->release(cagedm);
 +              return;
 +      }
 +      
 +      /* setup deformation data */
 +      cagemvert= cagedm->getVertArray(cagedm);
 +      weights= mmd->bindweights;
 +      bindcos= (float(*)[3])mmd->bindcos;
 +
 +      dco= MEM_callocN(sizeof(*dco)*totcagevert, "MDefDco");
 +      for(a=0; a<totcagevert; a++) {
 +              VECCOPY(co, cagemvert[a].co);
 +              Mat4MulVecfl(mmd->object->obmat, co);
 +              VECSUB(dco[a], co, bindcos[a]);
 +      }
 +
 +      defgrp_index = -1;
 +
 +      if(mmd->defgrp_name[0]) {
 +              bDeformGroup *def;
 +
 +              for(a=0, def=ob->defbase.first; def; def=def->next, a++) {
 +                      if(!strcmp(def->name, mmd->defgrp_name)) {
 +                              defgrp_index= a;
 +                              break;
 +                      }
 +              }
 +
 +              if (defgrp_index >= 0)
 +                      dvert= dm->getVertDataArray(dm, CD_MDEFORMVERT);
 +      }
 +
 +      /* do deformation */
 +      fac= 1.0f;
 +
 +      for(b=0; b<totvert; b++) {
 +              if(mmd->flag & MOD_MDEF_DYNAMIC_BIND)
 +                      if(!mmd->dynverts[b])
 +                              continue;
 +
 +              if(dvert) {
 +                      for(dw=NULL, a=0; a<dvert[b].totweight; a++) {
 +                              if(dvert[b].dw[a].def_nr == defgrp_index) {
 +                                      dw = &dvert[b].dw[a];
 +                                      break;
 +                              }
 +                      }
 +
 +                      if(mmd->flag & MOD_MDEF_INVERT_VGROUP) {
 +                              if(!dw) fac= 1.0f;
 +                              else if(dw->weight == 1.0f) continue;
 +                              else fac=1.0f-dw->weight;
 +                      }
 +                      else {
 +                              if(!dw) continue;
 +                              else fac= dw->weight;
 +                      }
 +              }
 +
 +              if(mmd->flag & MOD_MDEF_DYNAMIC_BIND) {
 +                      VECCOPY(co, vertexCos[b]);
 +                      Mat4MulVecfl(cagemat, co);
 +                      totweight= meshdeform_dynamic_bind(mmd, dco, co);
 +              }
 +              else {
 +                      totweight= 0.0f;
 +                      co[0]= co[1]= co[2]= 0.0f;
 +
 +                      for(a=0; a<totcagevert; a++) {
 +                              weight= weights[a + b*totcagevert];
 +                              co[0]+= weight*dco[a][0];
 +                              co[1]+= weight*dco[a][1];
 +                              co[2]+= weight*dco[a][2];
 +                              totweight += weight;
 +                      }
 +              }
 +
 +              if(totweight > 0.0f) {
 +                      VecMulf(co, fac/totweight);
 +                      Mat3MulVecfl(iobmat, co);
 +                      VECADD(vertexCos[b], vertexCos[b], co);
 +              }
 +      }
 +
 +      /* release cage derivedmesh */
 +      MEM_freeN(dco);
 +      cagedm->release(cagedm);
 +}
 +
 +static void meshdeformModifier_deformVerts(
 +                ModifierData *md, Object *ob, DerivedMesh *derivedData,
 +                float (*vertexCos)[3], int numVerts)
 +{
 +      DerivedMesh *dm;
 +
 +      if(!derivedData && ob->type==OB_MESH)
 +              dm= CDDM_from_mesh(ob->data, ob);
 +      else
 +              dm= derivedData;
 +
 +      modifier_vgroup_cache(md, vertexCos); /* if next modifier needs original vertices */
 +      
 +      meshdeformModifier_do(md, ob, dm, vertexCos, numVerts);
 +
 +      if(dm != derivedData)
 +              dm->release(dm);
 +}
 +
 +static void meshdeformModifier_deformVertsEM(
 +                ModifierData *md, Object *ob, EditMesh *editData,
 +                DerivedMesh *derivedData, float (*vertexCos)[3], int numVerts)
 +{
 +      DerivedMesh *dm;
 +
 +      if(!derivedData && ob->type == OB_MESH)
 +              dm = CDDM_from_editmesh(editData, ob->data);
 +      else
 +              dm = derivedData;
 +
 +      meshdeformModifier_do(md, ob, dm, vertexCos, numVerts);
 +
 +      if(dm != derivedData)
 +              dm->release(dm);
 +}
 +
 +/***/
 +
 +static ModifierTypeInfo typeArr[NUM_MODIFIER_TYPES];
 +static int typeArrInit = 1;
 +
 +ModifierTypeInfo *modifierType_getInfo(ModifierType type)
 +{
 +      if (typeArrInit) {
 +              ModifierTypeInfo *mti;
 +
 +              memset(typeArr, 0, sizeof(typeArr));
 +
 +              /* Initialize and return the appropriate type info structure,
 +               * assumes that modifier has:
 +               *  name == typeName, 
 +               *  structName == typeName + 'ModifierData'
 +               */
 +#define INIT_TYPE(typeName) \
 +              (strcpy(typeArr[eModifierType_##typeName].name, #typeName), \
 +              strcpy(typeArr[eModifierType_##typeName].structName, \
 +                     #typeName "ModifierData"), \
 +              typeArr[eModifierType_##typeName].structSize = \
 +                                                  sizeof(typeName##ModifierData), \
 +              &typeArr[eModifierType_##typeName])
 +
 +              mti = &typeArr[eModifierType_None];
 +              strcpy(mti->name, "None");
 +              strcpy(mti->structName, "ModifierData");
 +              mti->structSize = sizeof(ModifierData);
 +              mti->type = eModifierType_None;
 +              mti->flags = eModifierTypeFlag_AcceptsMesh
 +                           | eModifierTypeFlag_AcceptsCVs;
 +              mti->isDisabled = noneModifier_isDisabled;
 +              
 +              mti = INIT_TYPE(Curve);
 +              mti->type = eModifierTypeType_OnlyDeform;
 +              mti->flags = eModifierTypeFlag_AcceptsCVs
 +                           | eModifierTypeFlag_SupportsEditmode;
 +              mti->initData = curveModifier_initData;
 +              mti->copyData = curveModifier_copyData;
 +              mti->requiredDataMask = curveModifier_requiredDataMask;
 +              mti->isDisabled = curveModifier_isDisabled;
 +              mti->foreachObjectLink = curveModifier_foreachObjectLink;
 +              mti->updateDepgraph = curveModifier_updateDepgraph;
 +              mti->deformVerts = curveModifier_deformVerts;
 +              mti->deformVertsEM = curveModifier_deformVertsEM;
 +
 +              mti = INIT_TYPE(Lattice);
 +              mti->type = eModifierTypeType_OnlyDeform;
 +              mti->flags = eModifierTypeFlag_AcceptsCVs
 +                           | eModifierTypeFlag_SupportsEditmode;
 +              mti->copyData = latticeModifier_copyData;
 +              mti->requiredDataMask = latticeModifier_requiredDataMask;
 +              mti->isDisabled = latticeModifier_isDisabled;
 +              mti->foreachObjectLink = latticeModifier_foreachObjectLink;
 +              mti->updateDepgraph = latticeModifier_updateDepgraph;
 +              mti->deformVerts = latticeModifier_deformVerts;
 +              mti->deformVertsEM = latticeModifier_deformVertsEM;
 +
 +              mti = INIT_TYPE(Subsurf);
 +              mti->type = eModifierTypeType_Constructive;
 +              mti->flags = eModifierTypeFlag_AcceptsMesh
 +                           | eModifierTypeFlag_SupportsMapping
 +                           | eModifierTypeFlag_SupportsEditmode
 +                           | eModifierTypeFlag_EnableInEditmode;
 +              mti->initData = subsurfModifier_initData;
 +              mti->copyData = subsurfModifier_copyData;
 +              mti->freeData = subsurfModifier_freeData;
 +              mti->applyModifier = subsurfModifier_applyModifier;
 +              mti->applyModifierEM = subsurfModifier_applyModifierEM;
 +
 +              mti = INIT_TYPE(Build);
 +              mti->type = eModifierTypeType_Nonconstructive;
 +              mti->flags = eModifierTypeFlag_AcceptsMesh;
 +              mti->initData = buildModifier_initData;
 +              mti->copyData = buildModifier_copyData;
 +              mti->dependsOnTime = buildModifier_dependsOnTime;
 +              mti->applyModifier = buildModifier_applyModifier;
 +
 +              mti = INIT_TYPE(Array);
 +              mti->type = eModifierTypeType_Constructive;
 +              mti->flags = eModifierTypeFlag_AcceptsMesh
 +                           | eModifierTypeFlag_SupportsMapping
 +                           | eModifierTypeFlag_SupportsEditmode
 +                           | eModifierTypeFlag_EnableInEditmode;
 +              mti->initData = arrayModifier_initData;
 +              mti->copyData = arrayModifier_copyData;
 +              mti->foreachObjectLink = arrayModifier_foreachObjectLink;
 +              mti->updateDepgraph = arrayModifier_updateDepgraph;
 +              mti->applyModifier = arrayModifier_applyModifier;
 +              mti->applyModifierEM = arrayModifier_applyModifierEM;
 +
 +              mti = INIT_TYPE(Mirror);
 +              mti->type = eModifierTypeType_Constructive;
 +              mti->flags = eModifierTypeFlag_AcceptsMesh
 +                           | eModifierTypeFlag_SupportsMapping
 +                           | eModifierTypeFlag_SupportsEditmode
 +                           | eModifierTypeFlag_EnableInEditmode;
 +              mti->initData = mirrorModifier_initData;
 +              mti->copyData = mirrorModifier_copyData;
 +              mti->foreachObjectLink = mirrorModifier_foreachObjectLink;
 +              mti->updateDepgraph = mirrorModifier_updateDepgraph;
 +              mti->applyModifier = mirrorModifier_applyModifier;
 +              mti->applyModifierEM = mirrorModifier_applyModifierEM;
 +
 +              mti = INIT_TYPE(EdgeSplit);
 +              mti->type = eModifierTypeType_Constructive;
 +              mti->flags = eModifierTypeFlag_AcceptsMesh
 +                           | eModifierTypeFlag_SupportsMapping
 +                           | eModifierTypeFlag_SupportsEditmode
 +                           | eModifierTypeFlag_EnableInEditmode;
 +              mti->initData = edgesplitModifier_initData;
 +              mti->copyData = edgesplitModifier_copyData;
 +              mti->applyModifier = edgesplitModifier_applyModifier;
 +              mti->applyModifierEM = edgesplitModifier_applyModifierEM;
 +
 +              mti = INIT_TYPE(Displace);
 +              mti->type = eModifierTypeType_OnlyDeform;
 +              mti->flags = eModifierTypeFlag_AcceptsMesh|eModifierTypeFlag_SupportsEditmode;
 +              mti->initData = displaceModifier_initData;
 +              mti->copyData = displaceModifier_copyData;
 +              mti->requiredDataMask = displaceModifier_requiredDataMask;
 +              mti->foreachObjectLink = displaceModifier_foreachObjectLink;
 +              mti->foreachIDLink = displaceModifier_foreachIDLink;
 +              mti->updateDepgraph = displaceModifier_updateDepgraph;
 +              mti->isDisabled = displaceModifier_isDisabled;
 +              mti->deformVerts = displaceModifier_deformVerts;
 +              mti->deformVertsEM = displaceModifier_deformVertsEM;
 +
 +              mti = INIT_TYPE(UVProject);
 +              mti->type = eModifierTypeType_Nonconstructive;
 +              mti->flags = eModifierTypeFlag_AcceptsMesh
 +                           | eModifierTypeFlag_SupportsMapping
 +                           | eModifierTypeFlag_SupportsEditmode
 +                           | eModifierTypeFlag_EnableInEditmode;
 +              mti->initData = uvprojectModifier_initData;
 +              mti->copyData = uvprojectModifier_copyData;
 +              mti->requiredDataMask = uvprojectModifier_requiredDataMask;
 +              mti->foreachObjectLink = uvprojectModifier_foreachObjectLink;
 +              mti->foreachIDLink = uvprojectModifier_foreachIDLink;
 +              mti->updateDepgraph = uvprojectModifier_updateDepgraph;
 +              mti->applyModifier = uvprojectModifier_applyModifier;
 +              mti->applyModifierEM = uvprojectModifier_applyModifierEM;
 +
 +              mti = INIT_TYPE(Decimate);
 +              mti->type = eModifierTypeType_Nonconstructive;
 +              mti->flags = eModifierTypeFlag_AcceptsMesh;
 +              mti->initData = decimateModifier_initData;
 +              mti->copyData = decimateModifier_copyData;
 +              mti->applyModifier = decimateModifier_applyModifier;
 +
 +              mti = INIT_TYPE(Smooth);
 +              mti->type = eModifierTypeType_OnlyDeform;
 +              mti->flags = eModifierTypeFlag_AcceptsMesh
 +                           | eModifierTypeFlag_SupportsEditmode;
 +              mti->initData = smoothModifier_initData;
                mti->copyData = smoothModifier_copyData;
                mti->requiredDataMask = smoothModifier_requiredDataMask;
                mti->deformVerts = smoothModifier_deformVerts;
                mti->foreachObjectLink = booleanModifier_foreachObjectLink;
                mti->updateDepgraph = booleanModifier_updateDepgraph;
  
 +              mti = INIT_TYPE(MeshDeform);
 +              mti->type = eModifierTypeType_OnlyDeform;
 +              mti->flags = eModifierTypeFlag_AcceptsCVs
 +                           | eModifierTypeFlag_SupportsEditmode;
 +              mti->initData = meshdeformModifier_initData;
 +              mti->freeData = meshdeformModifier_freeData;
 +              mti->copyData = meshdeformModifier_copyData;
 +              mti->requiredDataMask = meshdeformModifier_requiredDataMask;
 +              mti->isDisabled = meshdeformModifier_isDisabled;
 +              mti->foreachObjectLink = meshdeformModifier_foreachObjectLink;
 +              mti->updateDepgraph = meshdeformModifier_updateDepgraph;
 +              mti->deformVerts = meshdeformModifier_deformVerts;
 +              mti->deformVertsEM = meshdeformModifier_deformVertsEM;
 +
++              mti = INIT_TYPE(ParticleSystem);
++              mti->type = eModifierTypeType_OnlyDeform;
++              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
        }
@@@ -5727,6 -5281,6 +6983,13 @@@ int modifiers_isSoftbodyEnabled(Object 
        return (md && md->mode & (eModifierMode_Realtime | eModifierMode_Render));
  }
  
++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;
@@@ -5909,4 -5457,3 +7172,14 @@@ int modifiers_isDeformed(Object *ob
        }
        return 0;
  }
 +
++int modifiers_indexInObject(Object *ob, ModifierData *md_seek)
++{
++      int i= 0;
++      ModifierData *md;
++      
++      for (md=ob->modifiers.first; (md && md_seek!=md); md=md->next, i++);
++      if (!md) return -1; /* modifier isnt in the object */
++      return i;
++}
++
index 095d6f525a91644844d4766b2c06d1339fd66996,4cb6f64569fd074730bd70c27057d8284cce9289..d9b2ce84fa5e1b40dfa7eba2d2aca0956084f724
@@@ -60,6 -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 -163,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 -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 -352,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 -878,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 -899,6 +1053,7 @@@ Object *copy_object(Object *ob
  {
        Object *obn;
        ModifierData *md;
++      ParticleSystem *psys;
        int a;
  
        obn= copy_libblock(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 */
                        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 -2071,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 */
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..c0de1901f69206ba691aad99ec50d957ae4a2930
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,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);
++