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

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/blenkernel/intern')
-rw-r--r--source/blender/blenkernel/intern/brush.c2
-rw-r--r--source/blender/blenkernel/intern/cache_library.c192
-rw-r--r--source/blender/blenkernel/intern/context.c2
-rw-r--r--source/blender/blenkernel/intern/customdata.c29
-rw-r--r--source/blender/blenkernel/intern/editstrands.c267
-rw-r--r--source/blender/blenkernel/intern/key.c409
-rw-r--r--source/blender/blenkernel/intern/mesh_sample.c379
-rw-r--r--source/blender/blenkernel/intern/object.c1
-rw-r--r--source/blender/blenkernel/intern/object_dupli.c122
-rw-r--r--source/blender/blenkernel/intern/particle.c13
10 files changed, 1263 insertions, 153 deletions
diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c
index 307f97f1344..d5c5fb5fe43 100644
--- a/source/blender/blenkernel/intern/brush.c
+++ b/source/blender/blenkernel/intern/brush.c
@@ -68,7 +68,7 @@ static void brush_defaults(Brush *brush)
brush->blend = 0;
brush->flag = 0;
- brush->ob_mode = OB_MODE_ALL_PAINT;
+ brush->ob_mode = OB_MODE_ALL_BRUSH;
/* BRUSH SCULPT TOOL SETTINGS */
brush->weight = 1.0f; /* weight of brush 0 - 1.0 */
diff --git a/source/blender/blenkernel/intern/cache_library.c b/source/blender/blenkernel/intern/cache_library.c
index b9ac9cd82b7..74bdb027022 100644
--- a/source/blender/blenkernel/intern/cache_library.c
+++ b/source/blender/blenkernel/intern/cache_library.c
@@ -42,6 +42,7 @@
#include "DNA_cache_library_types.h"
#include "DNA_group_types.h"
+#include "DNA_key_types.h"
#include "DNA_modifier_types.h"
#include "DNA_object_force.h"
#include "DNA_object_types.h"
@@ -56,9 +57,11 @@
#include "BKE_context.h"
#include "BKE_depsgraph.h"
#include "BKE_DerivedMesh.h"
+#include "BKE_editstrands.h"
#include "BKE_effect.h"
#include "BKE_global.h"
#include "BKE_group.h"
+#include "BKE_key.h"
#include "BKE_library.h"
#include "BKE_main.h"
#include "BKE_modifier.h"
@@ -84,7 +87,7 @@ CacheLibrary *BKE_cache_library_add(Main *bmain, const char *name)
BLI_snprintf(cachelib->output_filepath, sizeof(cachelib->output_filepath), "//cache/%s.%s", basename, PTC_get_default_archive_extension());
cachelib->source_mode = CACHE_LIBRARY_SOURCE_SCENE;
- cachelib->display_mode = CACHE_LIBRARY_DISPLAY_RESULT;
+ cachelib->display_mode = CACHE_LIBRARY_DISPLAY_MODIFIERS;
cachelib->display_flag = CACHE_LIBRARY_DISPLAY_MOTION | CACHE_LIBRARY_DISPLAY_CHILDREN;
cachelib->render_flag = CACHE_LIBRARY_RENDER_MOTION | CACHE_LIBRARY_RENDER_CHILDREN;
cachelib->eval_mode = CACHE_LIBRARY_EVAL_REALTIME | CACHE_LIBRARY_EVAL_RENDER;
@@ -319,7 +322,7 @@ static bool has_active_cache(CacheLibrary *cachelib)
}
}
- if (cachelib->source_mode == CACHE_LIBRARY_SOURCE_CACHE) {
+ if (ELEM(cachelib->source_mode, CACHE_LIBRARY_SOURCE_CACHE, CACHE_LIBRARY_DISPLAY_MODIFIERS)) {
return true;
}
@@ -342,7 +345,7 @@ static struct PTCReaderArchive *find_active_cache(Scene *scene, CacheLibrary *ca
}
}
- if (!archive && cachelib->source_mode == CACHE_LIBRARY_SOURCE_CACHE) {
+ if (!archive && ELEM(cachelib->source_mode, CACHE_LIBRARY_SOURCE_CACHE, CACHE_LIBRARY_DISPLAY_MODIFIERS)) {
BKE_cache_archive_input_path(cachelib, filename, sizeof(filename));
archive = PTC_open_reader_archive(scene, filename);
}
@@ -846,7 +849,7 @@ bool BKE_cache_modifier_find_object(DupliCache *dupcache, Object *ob, DupliObjec
return true;
}
-bool BKE_cache_modifier_find_strands(DupliCache *dupcache, Object *ob, int hair_system, DupliObjectData **r_data, Strands **r_strands)
+bool BKE_cache_modifier_find_strands(DupliCache *dupcache, Object *ob, int hair_system, DupliObjectData **r_data, Strands **r_strands, const char **r_name)
{
DupliObjectData *dobdata;
ParticleSystem *psys;
@@ -875,6 +878,7 @@ bool BKE_cache_modifier_find_strands(DupliCache *dupcache, Object *ob, int hair_
if (r_data) *r_data = dobdata;
if (r_strands) *r_strands = strands;
+ if (r_name) *r_name = psys->name;
return true;
}
@@ -949,7 +953,7 @@ static void hairsim_process(HairSimCacheModifier *hsmd, CacheProcessContext *ctx
// if (eval_mode != CACHE_LIBRARY_EVAL_REALTIME)
// return;
- if (!BKE_cache_modifier_find_strands(data->dupcache, ob, hsmd->hair_system, NULL, &strands))
+ if (!BKE_cache_modifier_find_strands(data->dupcache, ob, hsmd->hair_system, NULL, &strands, NULL))
return;
/* Note: motion state data should always be created regardless of actual sim.
@@ -1110,7 +1114,7 @@ static void shrinkwrap_data_free(ShrinkWrapCacheData *data)
}
}
-static void shrinkwrap_apply_vertex(ShrinkWrapCacheModifier *smd, ShrinkWrapCacheData *data, ShrinkWrapCacheInstance *inst, StrandsVertex *vertex, StrandsMotionState *UNUSED(state))
+static void shrinkwrap_apply_vertex(ShrinkWrapCacheModifier *UNUSED(smd), ShrinkWrapCacheData *data, ShrinkWrapCacheInstance *inst, StrandsVertex *vertex, StrandsMotionState *UNUSED(state))
{
// const float *point = state->co;
// float *npoint = state->co;
@@ -1167,7 +1171,7 @@ static void shrinkwrap_apply(ShrinkWrapCacheModifier *smd, ShrinkWrapCacheData *
}
}
-static void shrinkwrap_process(ShrinkWrapCacheModifier *smd, CacheProcessContext *UNUSED(ctx), CacheProcessData *data, int frame, int frame_prev, eCacheLibrary_EvalMode eval_mode)
+static void shrinkwrap_process(ShrinkWrapCacheModifier *smd, CacheProcessContext *UNUSED(ctx), CacheProcessData *data, int UNUSED(frame), int UNUSED(frame_prev), eCacheLibrary_EvalMode UNUSED(eval_mode))
{
Object *ob = smd->object;
DupliObject *dob;
@@ -1177,15 +1181,7 @@ static void shrinkwrap_process(ShrinkWrapCacheModifier *smd, CacheProcessContext
ShrinkWrapCacheData shrinkwrap;
- /* only perform hair sim once */
- if (eval_mode != CACHE_LIBRARY_EVAL_REALTIME)
- return;
-
- /* skip first step and potential backward steps */
- if (frame <= frame_prev)
- return;
-
- if (!BKE_cache_modifier_find_strands(data->dupcache, ob, smd->hair_system, NULL, &strands))
+ if (!BKE_cache_modifier_find_strands(data->dupcache, ob, smd->hair_system, NULL, &strands, NULL))
return;
if (!BKE_cache_modifier_find_object(data->dupcache, smd->target, &target_data))
return;
@@ -1222,11 +1218,175 @@ CacheModifierTypeInfo cacheModifierType_ShrinkWrap = {
/* free */ (CacheModifier_FreeFunc)shrinkwrap_free,
};
+/* ------------------------------------------------------------------------- */
+
+static void strandskey_init(StrandsKeyCacheModifier *skmd)
+{
+ skmd->object = NULL;
+ skmd->hair_system = -1;
+
+ skmd->key = BKE_key_add_ex(NULL, KEY_FROMTYPE_STRANDS);
+ skmd->key->type = KEY_RELATIVE;
+}
+
+static void strandskey_copy(StrandsKeyCacheModifier *skmd, StrandsKeyCacheModifier *tskmd)
+{
+ tskmd->key = BKE_key_copy(skmd->key);
+
+ tskmd->edit = NULL;
+}
+
+static void strandskey_free(StrandsKeyCacheModifier *skmd)
+{
+ BKE_key_free(skmd->key);
+
+ if (skmd->edit) {
+ BKE_editstrands_free(skmd->edit);
+ MEM_freeN(skmd->edit);
+ skmd->edit = NULL;
+ }
+}
+
+static void strandskey_foreach_id_link(StrandsKeyCacheModifier *skmd, CacheLibrary *cachelib, CacheModifier_IDWalkFunc walk, void *userdata)
+{
+ walk(userdata, cachelib, &skmd->modifier, (ID **)(&skmd->object));
+}
+
+static void strandskey_process(StrandsKeyCacheModifier *skmd, CacheProcessContext *UNUSED(ctx), CacheProcessData *data, int UNUSED(frame), int UNUSED(frame_prev), eCacheLibrary_EvalMode UNUSED(eval_mode))
+{
+ Object *ob = skmd->object;
+ Strands *strands;
+ KeyBlock *actkb;
+ float *shape;
+
+ if (!BKE_cache_modifier_find_strands(data->dupcache, ob, skmd->hair_system, NULL, &strands, NULL))
+ return;
+
+ actkb = BLI_findlink(&skmd->key->block, skmd->shapenr);
+ shape = BKE_key_evaluate_strands(strands, skmd->key, actkb, skmd->flag & eStrandsKeyCacheModifier_Flag_ShapeLock, NULL);
+ if (shape) {
+ StrandsVertex *vert = strands->verts;
+ int totvert = strands->totverts;
+ int i;
+
+ float *fp = shape;
+ for (i = 0; i < totvert; ++i) {
+ copy_v3_v3(vert->co, fp);
+
+ fp += 3;
+ ++vert;
+ }
+
+ MEM_freeN(shape);
+ }
+}
+
+CacheModifierTypeInfo cacheModifierType_StrandsKey = {
+ /* name */ "StrandsKey",
+ /* structName */ "StrandsKeyCacheModifier",
+ /* structSize */ sizeof(StrandsKeyCacheModifier),
+
+ /* copy */ (CacheModifier_CopyFunc)strandskey_copy,
+ /* foreachIDLink */ (CacheModifier_ForeachIDLinkFunc)strandskey_foreach_id_link,
+ /* process */ (CacheModifier_ProcessFunc)strandskey_process,
+ /* init */ (CacheModifier_InitFunc)strandskey_init,
+ /* free */ (CacheModifier_FreeFunc)strandskey_free,
+};
+
+KeyBlock *BKE_cache_modifier_strands_key_insert_key(StrandsKeyCacheModifier *skmd, Strands *strands, const char *name, const bool from_mix)
+{
+ Key *key = skmd->key;
+ KeyBlock *kb;
+ bool newkey = false;
+
+ if (key == NULL) {
+ key = skmd->key = BKE_key_add_ex(NULL, KEY_FROMTYPE_STRANDS);
+ key->type = KEY_RELATIVE;
+ newkey = true;
+ }
+ else if (BLI_listbase_is_empty(&key->block)) {
+ newkey = true;
+ }
+
+ if (newkey || from_mix == false) {
+ /* create from mesh */
+ kb = BKE_keyblock_add_ctime(key, name, false);
+ BKE_keyblock_convert_from_strands(strands, key, kb);
+ }
+ else {
+ /* copy from current values */
+ KeyBlock *actkb = BLI_findlink(&skmd->key->block, skmd->shapenr);
+ bool shape_lock = skmd->flag & eStrandsKeyCacheModifier_Flag_ShapeLock;
+ int totelem;
+ float *data = BKE_key_evaluate_strands(strands, key, actkb, shape_lock, &totelem);
+
+ /* create new block with prepared data */
+ kb = BKE_keyblock_add_ctime(key, name, false);
+ kb->data = data;
+ kb->totelem = totelem;
+ }
+
+ return kb;
+}
+
+bool BKE_cache_modifier_strands_key_get(Object *ob, StrandsKeyCacheModifier **r_skmd, DerivedMesh **r_dm, Strands **r_strands, DupliObjectData **r_dobdata, const char **r_name, float r_mat[4][4])
+{
+ CacheLibrary *cachelib = ob->cache_library;
+ CacheModifier *md;
+
+ if (!cachelib)
+ return false;
+
+ /* ignore when the object is not actually using the cachelib */
+ if (!((ob->transflag & OB_DUPLIGROUP) && ob->dup_group && ob->dup_cache))
+ return false;
+
+ for (md = cachelib->modifiers.first; md; md = md->next) {
+ if (md->type == eCacheModifierType_StrandsKey) {
+ StrandsKeyCacheModifier *skmd = (StrandsKeyCacheModifier *)md;
+ DupliObjectData *dobdata;
+
+ if (BKE_cache_modifier_find_strands(ob->dup_cache, skmd->object, skmd->hair_system, &dobdata, r_strands, r_name)) {
+ if (r_skmd) *r_skmd = skmd;
+ if (r_dm) *r_dm = dobdata->dm;
+ if (r_dobdata) *r_dobdata = dobdata;
+
+ /* relative transform from the original hair object to the duplicator local space */
+ /* XXX bad hack, common problem: we want to display strand edit data in the place of "the" instance,
+ * but in fact there can be multiple instances of the same dupli object data, so this is ambiguous ...
+ * For our basic use case, just pick the first dupli instance, assuming that it's the only one.
+ * ugh ...
+ */
+ if (r_mat) {
+ DupliObject *dob;
+ for (dob = ob->dup_cache->duplilist.first; dob; dob = dob->next) {
+ if (dob->ob == skmd->object)
+ break;
+ }
+ if (dob) {
+ /* note: plain duplis from the dupli cache list are relative
+ * to the duplicator already! (not in world space like final duplis)
+ */
+ copy_m4_m4(r_mat, dob->mat);
+ }
+ else
+ unit_m4(r_mat);
+ }
+
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
void BKE_cache_modifier_init(void)
{
cache_modifier_type_set(eCacheModifierType_HairSimulation, &cacheModifierType_HairSimulation);
cache_modifier_type_set(eCacheModifierType_ForceField, &cacheModifierType_ForceField);
cache_modifier_type_set(eCacheModifierType_ShrinkWrap, &cacheModifierType_ShrinkWrap);
+ cache_modifier_type_set(eCacheModifierType_StrandsKey, &cacheModifierType_StrandsKey);
}
/* ========================================================================= */
diff --git a/source/blender/blenkernel/intern/context.c b/source/blender/blenkernel/intern/context.c
index 59f7da83925..b463a1650b7 100644
--- a/source/blender/blenkernel/intern/context.c
+++ b/source/blender/blenkernel/intern/context.c
@@ -928,6 +928,7 @@ int CTX_data_mode_enum(const bContext *C)
else if (ob->mode & OB_MODE_VERTEX_PAINT) return CTX_MODE_PAINT_VERTEX;
else if (ob->mode & OB_MODE_TEXTURE_PAINT) return CTX_MODE_PAINT_TEXTURE;
else if (ob->mode & OB_MODE_PARTICLE_EDIT) return CTX_MODE_PARTICLE;
+ else if (ob->mode & OB_MODE_HAIR_EDIT) return CTX_MODE_HAIR;
}
}
@@ -951,6 +952,7 @@ static const char *data_mode_strings[] = {
"vertexpaint",
"imagepaint",
"particlemode",
+ "hairmode",
"objectmode",
NULL
};
diff --git a/source/blender/blenkernel/intern/customdata.c b/source/blender/blenkernel/intern/customdata.c
index 724ca6de3fc..dac03ff360b 100644
--- a/source/blender/blenkernel/intern/customdata.c
+++ b/source/blender/blenkernel/intern/customdata.c
@@ -55,6 +55,7 @@
#include "BKE_customdata.h"
#include "BKE_customdata_file.h"
+#include "BKE_editstrands.h"
#include "BKE_global.h"
#include "BKE_main.h"
#include "BKE_mesh_mapping.h"
@@ -1324,6 +1325,8 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
{sizeof(short[2]), "vec2s", 1, NULL, NULL, NULL, NULL, NULL, NULL},
/* 42: CD_FACEMAP */
{sizeof(int), "", 0, NULL, NULL, NULL, NULL, NULL, layerDefault_fmap, NULL},
+ /* 43: CD_MSURFACE_SAMPLE */
+ {sizeof(MSurfaceSample), "MSurfaceSample", 1, NULL, NULL, NULL, NULL, NULL, NULL},
};
/* note, numbers are from trunk and need updating for bmesh */
@@ -1341,6 +1344,7 @@ static const char *LAYERTYPENAMES[CD_NUMTYPES] = {
/* 35-36 */ "CDGridPaintMask", "CDMVertSkin",
/* 37-38 */ "CDFreestyleEdge", "CDFreestyleFace",
/* 39-42 */ "CDMLoopTangent", "CDTessLoopNormal", "CDCustomLoopNormal", "CDFaceMap",
+ /* 43 */ "CDMSurfaceSample",
};
@@ -1378,6 +1382,17 @@ const CustomDataMask CD_MASK_BMESH =
const CustomDataMask CD_MASK_FACECORNERS = /* XXX Not used anywhere! */
CD_MASK_MTFACE | CD_MASK_MCOL | CD_MASK_MTEXPOLY | CD_MASK_MLOOPUV |
CD_MASK_MLOOPCOL | CD_MASK_NORMAL | CD_MASK_MLOOPTANGENT;
+const CustomDataMask CD_MASK_STRANDS =
+ CD_MASK_MVERT | CD_MASK_MEDGE |
+ CD_MASK_MSTICKY | CD_MASK_MDEFORMVERT | CD_MASK_MCOL |
+ CD_MASK_PROP_FLT | CD_MASK_PROP_INT | CD_MASK_PROP_STR | CD_MASK_MDISPS |
+ CD_MASK_MVERT_SKIN | CD_MASK_FREESTYLE_EDGE |
+ CD_MASK_MSURFACE_SAMPLE;
+const CustomDataMask CD_MASK_STRANDS_BMESH =
+ CD_MASK_MSTICKY | CD_MASK_MDEFORMVERT | CD_MASK_PROP_FLT | CD_MASK_PROP_INT |
+ CD_MASK_PROP_STR | CD_MASK_SHAPEKEY | CD_MASK_SHAPE_KEYINDEX | CD_MASK_MDISPS |
+ CD_MASK_MVERT_SKIN | CD_MASK_FREESTYLE_EDGE |
+ CD_MASK_MSURFACE_SAMPLE;
const CustomDataMask CD_MASK_EVERYTHING =
CD_MASK_MVERT | CD_MASK_MSTICKY /* DEPRECATED */ | CD_MASK_MDEFORMVERT | CD_MASK_MEDGE | CD_MASK_MFACE |
CD_MASK_MTFACE | CD_MASK_MCOL | CD_MASK_ORIGINDEX | CD_MASK_NORMAL /* | CD_MASK_POLYINDEX */ | CD_MASK_PROP_FLT |
@@ -1389,7 +1404,7 @@ const CustomDataMask CD_MASK_EVERYTHING =
/* BMESH ONLY END */
CD_MASK_PAINT_MASK | CD_MASK_GRID_PAINT_MASK | CD_MASK_MVERT_SKIN |
CD_MASK_FREESTYLE_EDGE | CD_MASK_FREESTYLE_FACE |
- CD_MASK_MLOOPTANGENT | CD_MASK_TESSLOOPNORMAL | CD_MASK_CUSTOMLOOPNORMAL | CD_MASK_FACEMAP;
+ CD_MASK_MLOOPTANGENT | CD_MASK_TESSLOOPNORMAL | CD_MASK_CUSTOMLOOPNORMAL | CD_MASK_FACEMAP | CD_MASK_MSURFACE_SAMPLE;
static const LayerTypeInfo *layerType_getInfo(int type)
{
@@ -2838,6 +2853,18 @@ void *CustomData_bmesh_get_layer_n(const CustomData *data, void *block, int n)
return POINTER_OFFSET(block, data->layers[n].offset);
}
+/*Bmesh Custom Data Functions. Should replace editmesh ones with these as well, due to more effecient memory alloc*/
+void *CustomData_bmesh_get_named(const CustomData *data, void *block, int type, const char *name)
+{
+ int layer_index;
+
+ /* get the layer index of the named layer of type */
+ layer_index = CustomData_get_named_layer_index(data, type, name);
+ if (layer_index == -1) return NULL;
+
+ return (char *)block + data->layers[layer_index].offset;
+}
+
bool CustomData_layer_has_math(const struct CustomData *data, int layer_n)
{
const LayerTypeInfo *typeInfo = layerType_getInfo(data->layers[layer_n].type);
diff --git a/source/blender/blenkernel/intern/editstrands.c b/source/blender/blenkernel/intern/editstrands.c
new file mode 100644
index 00000000000..86e81925b58
--- /dev/null
+++ b/source/blender/blenkernel/intern/editstrands.c
@@ -0,0 +1,267 @@
+/*
+ * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) Blender Foundation
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Lukas Toenne
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/blenkernel/intern/editstrands.c
+ * \ingroup bke
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_math.h"
+#include "BLI_mempool.h"
+
+#include "DNA_cache_library_types.h"
+#include "DNA_customdata_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_object_types.h"
+#include "DNA_particle_types.h"
+#include "DNA_strands_types.h"
+
+#include "BKE_bvhutils.h"
+#include "BKE_cache_library.h"
+#include "BKE_customdata.h"
+#include "BKE_cdderivedmesh.h"
+#include "BKE_DerivedMesh.h"
+#include "BKE_editstrands.h"
+#include "BKE_effect.h"
+#include "BKE_mesh_sample.h"
+#include "BKE_particle.h"
+
+#include "BPH_strands.h"
+
+#include "intern/bmesh_strands_conv.h"
+
+/* mat can be used to transform the dm into another space,
+ * in case the edited object is not the active object:
+ * mat = inv(M_act) * M_edit
+ */
+BMEditStrands *BKE_editstrands_create(BMesh *bm, DerivedMesh *root_dm, float mat[4][4])
+{
+ BMEditStrands *es = MEM_callocN(sizeof(BMEditStrands), __func__);
+
+ es->bm = bm;
+ es->root_dm = CDDM_copy(root_dm);
+
+ if (mat) {
+ DerivedMesh *dm = es->root_dm;
+ MVert *mv = dm->getVertArray(dm);
+ int totvert = dm->getNumVerts(dm), i;
+ for (i = 0; i < totvert; ++i, ++mv) {
+ mul_m4_v3(mat, mv->co);
+ }
+ }
+
+ return es;
+}
+
+BMEditStrands *BKE_editstrands_copy(BMEditStrands *es)
+{
+ BMEditStrands *es_copy = MEM_callocN(sizeof(BMEditStrands), __func__);
+ *es_copy = *es;
+
+ es_copy->bm = BM_mesh_copy(es->bm);
+ es_copy->root_dm = CDDM_copy(es->root_dm);
+
+ return es_copy;
+}
+
+/**
+ * \brief Return the BMEditStrands for a given object
+ */
+BMEditStrands *BKE_editstrands_from_object(Object *ob)
+{
+ {
+ ParticleSystem *psys = psys_get_current(ob);
+ if (psys && psys->hairedit)
+ return psys->hairedit;
+ }
+
+ {
+ StrandsKeyCacheModifier *skmd;
+ if (BKE_cache_modifier_strands_key_get(ob, &skmd, NULL, NULL, NULL, NULL, NULL)) {
+ if (skmd->edit)
+ return skmd->edit;
+ }
+ }
+
+ return NULL;
+}
+
+void BKE_editstrands_update_linked_customdata(BMEditStrands *es)
+{
+ BMesh *bm = es->bm;
+
+ /* this is done for BMEditMesh, but should never exist for strands */
+ BLI_assert(!CustomData_has_layer(&bm->pdata, CD_MTEXPOLY));
+}
+
+/*does not free the BMEditStrands struct itself*/
+void BKE_editstrands_free(BMEditStrands *es)
+{
+ if (es->bm)
+ BM_mesh_free(es->bm);
+ if (es->root_dm)
+ es->root_dm->release(es->root_dm);
+}
+
+/* === constraints === */
+
+BMEditStrandsLocations BKE_editstrands_get_locations(BMEditStrands *edit)
+{
+ BMesh *bm = edit->bm;
+ BMEditStrandsLocations locs = MEM_mallocN(3*sizeof(float) * bm->totvert, "editstrands locations");
+
+ BMVert *v;
+ BMIter iter;
+ int i;
+
+ BM_ITER_MESH_INDEX(v, &iter, bm, BM_VERTS_OF_MESH, i) {
+ copy_v3_v3(locs[i], v->co);
+ }
+
+ return locs;
+}
+
+void BKE_editstrands_free_locations(BMEditStrandsLocations locs)
+{
+ MEM_freeN(locs);
+}
+
+void BKE_editstrands_solve_constraints(Object *ob, BMEditStrands *es, BMEditStrandsLocations orig)
+{
+ BKE_editstrands_ensure(es);
+
+ BPH_strands_solve_constraints(ob, es, orig);
+}
+
+static void editstrands_calc_segment_lengths(BMesh *bm)
+{
+ BMVert *root, *v, *vprev;
+ BMIter iter, iter_strand;
+ int k;
+
+ BM_ITER_STRANDS(root, &iter, bm, BM_STRANDS_OF_MESH) {
+ BM_ITER_STRANDS_ELEM_INDEX(v, &iter_strand, root, BM_VERTS_OF_STRAND, k) {
+ if (k > 0) {
+ float length = len_v3v3(v->co, vprev->co);
+ BM_elem_float_data_named_set(&bm->vdata, v, CD_PROP_FLT, CD_HAIR_SEGMENT_LENGTH, length);
+ }
+ vprev = v;
+ }
+ }
+}
+
+void BKE_editstrands_ensure(BMEditStrands *es)
+{
+ BM_strands_cd_flag_ensure(es->bm, 0);
+
+ if (es->flag & BM_STRANDS_DIRTY_SEGLEN) {
+ editstrands_calc_segment_lengths(es->bm);
+
+ es->flag &= ~BM_STRANDS_DIRTY_SEGLEN;
+ }
+}
+
+
+/* === cache shape key conversion === */
+
+BMesh *BKE_cache_strands_to_bmesh(struct Strands *strands, struct Key *key, float mat[4][4], int act_key_nr, DerivedMesh *dm)
+{
+ const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_STRANDS(strands);
+ BMesh *bm;
+
+ DM_ensure_tessface(dm);
+
+ bm = BM_mesh_create(&allocsize);
+ BM_strands_bm_from_strands(bm, strands, key, dm, mat, true, act_key_nr);
+ editstrands_calc_segment_lengths(bm);
+
+ return bm;
+}
+
+struct Strands *BKE_cache_strands_from_bmesh(BMEditStrands *edit, struct Key *key, float mat[4][4], DerivedMesh *dm)
+{
+ BMesh *bm = edit ? edit->bm : NULL;
+ Strands *strands = NULL;
+
+ if (bm && dm) {
+ BVHTreeFromMesh bvhtree = {NULL};
+
+ DM_ensure_tessface(dm);
+
+ bvhtree_from_mesh_faces(&bvhtree, dm, 0.0, 2, 6);
+
+ strands = BM_strands_bm_to_strands(bm, strands, key, mat, dm, &bvhtree);
+
+ free_bvhtree_from_mesh(&bvhtree);
+ }
+
+ return strands;
+}
+
+
+/* === particle conversion === */
+
+BMesh *BKE_particles_to_bmesh(Object *ob, ParticleSystem *psys)
+{
+ ParticleSystemModifierData *psmd = psys_get_modifier(ob, psys);
+
+ const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_PSYS(psys);
+ BMesh *bm;
+
+ bm = BM_mesh_create(&allocsize);
+
+ if (psmd && psmd->dm) {
+ DM_ensure_tessface(psmd->dm);
+
+ BM_strands_bm_from_psys(bm, ob, psys, psmd->dm, true, /*psys->shapenr*/ -1);
+
+ editstrands_calc_segment_lengths(bm);
+ }
+
+ return bm;
+}
+
+void BKE_particles_from_bmesh(Object *ob, ParticleSystem *psys)
+{
+ ParticleSystemModifierData *psmd = psys_get_modifier(ob, psys);
+ BMesh *bm = psys->hairedit ? psys->hairedit->bm : NULL;
+
+ if (bm) {
+ if (psmd && psmd->dm) {
+ BVHTreeFromMesh bvhtree = {NULL};
+
+ DM_ensure_tessface(psmd->dm);
+
+ bvhtree_from_mesh_faces(&bvhtree, psmd->dm, 0.0, 2, 6);
+
+ BM_strands_bm_to_psys(bm, ob, psys, psmd->dm, &bvhtree);
+
+ free_bvhtree_from_mesh(&bvhtree);
+ }
+ }
+}
diff --git a/source/blender/blenkernel/intern/key.c b/source/blender/blenkernel/intern/key.c
index a1d0680785d..23d9c076182 100644
--- a/source/blender/blenkernel/intern/key.c
+++ b/source/blender/blenkernel/intern/key.c
@@ -52,6 +52,7 @@
#include "DNA_object_types.h"
#include "DNA_particle_types.h"
#include "DNA_scene_types.h"
+#include "DNA_strands_types.h"
#include "DNA_texture_types.h"
#include "BKE_animsys.h"
@@ -66,20 +67,21 @@
#include "BKE_particle.h"
#include "BKE_editmesh.h"
#include "BKE_scene.h"
+#include "BKE_strands.h"
#include "RNA_access.h"
#include "RE_render_ext.h"
-#define KEY_MODE_DUMMY 0 /* use where mode isn't checked for */
-#define KEY_MODE_BPOINT 1
-#define KEY_MODE_BEZTRIPLE 2
-
/* old defines from DNA_ipo_types.h for data-type, stored in DNA - don't modify! */
#define IPO_FLOAT 4
#define IPO_BEZTRIPLE 100
#define IPO_BPOINT 101
+#define KEY_MODE_DUMMY 0 /* use where mode isn't checked for */
+#define KEY_MODE_BPOINT 1
+#define KEY_MODE_BEZTRIPLE 2
+
void BKE_key_free(Key *key)
{
KeyBlock *kb;
@@ -104,55 +106,70 @@ void BKE_key_free_nolib(Key *key)
}
}
-Key *BKE_key_add(ID *id) /* common function */
+static void key_set_elemstr(ID *id, short fromtype, char *r_elemstr, int *r_elemsize)
+{
+ /* XXX the code here uses some defines which will soon be deprecated... */
+ char elemtype = IPO_FLOAT;
+ char numelem = 0;
+ int elemsize = 0;
+
+ switch (fromtype) {
+ case KEY_FROMTYPE_ID:
+ if (id) {
+ switch (GS(id->name)) {
+ case ID_ME:
+ numelem = 3;
+ elemtype = IPO_FLOAT;
+ elemsize = 12;
+ break;
+ case ID_LT:
+ numelem = 3;
+ elemtype = IPO_FLOAT;
+ elemsize = 12;
+ break;
+ case ID_CU:
+ numelem = 4;
+ elemtype = IPO_BPOINT;
+ elemsize = 16;
+ break;
+ }
+ }
+ break;
+ case KEY_FROMTYPE_STRANDS:
+ numelem = 3;
+ elemtype = IPO_FLOAT;
+ elemsize = 12;
+ break;
+ }
+
+ r_elemstr[0] = numelem;
+ r_elemstr[1] = elemtype;
+ r_elemstr[2] = 0;
+ *r_elemsize = elemsize;
+}
+
+Key *BKE_key_add_ex(ID *from, short fromtype) /* common function */
{
Key *key;
- char *el;
key = BKE_libblock_alloc(G.main, ID_KE, "Key");
key->type = KEY_NORMAL;
- BKE_key_set_from_id(key, id);
+ BKE_key_set_from_id(key, from);
+ key->fromtype = fromtype;
key->uidgen = 1;
- /* XXX the code here uses some defines which will soon be deprecated... */
- switch (GS(id->name)) {
- case ID_ME:
- el = key->elemstr;
-
- el[0] = 3;
- el[1] = IPO_FLOAT;
- el[2] = 0;
-
- key->elemsize = 12;
-
- break;
- case ID_LT:
- el = key->elemstr;
-
- el[0] = 3;
- el[1] = IPO_FLOAT;
- el[2] = 0;
-
- key->elemsize = 12;
-
- break;
- case ID_CU:
- el = key->elemstr;
-
- el[0] = 4;
- el[1] = IPO_BPOINT;
- el[2] = 0;
-
- key->elemsize = 16;
-
- break;
- }
+ key_set_elemstr(from, fromtype, key->elemstr, &key->elemsize);
return key;
}
+Key *BKE_key_add(ID *id)
+{
+ return BKE_key_add_ex(id, KEY_FROMTYPE_ID);
+}
+
Key *BKE_key_add_particles(Object *ob, ParticleSystem *psys) /* particles are "special" */
{
Key *key;
@@ -566,7 +583,7 @@ static char *key_block_get_data(Key *key, KeyBlock *actkb, KeyBlock *kb, char **
if (kb == actkb) {
/* this hack makes it possible to edit shape keys in
* edit mode with shape keys blending applied */
- if (key->from_extra.type == KEY_OWNER_MESH) {
+ if (key->from && key->from_extra.type == KEY_OWNER_MESH) {
Mesh *me;
BMVert *eve;
BMIter iter;
@@ -598,39 +615,50 @@ static char *key_block_get_data(Key *key, KeyBlock *actkb, KeyBlock *kb, char **
/* currently only the first value of 'ofs' may be set. */
static bool key_pointer_size(const Key *key, const int mode, int *poinsize, int *ofs)
{
- switch (key->from_extra.type) {
- case KEY_OWNER_MESH:
- *ofs = sizeof(float) * 3;
- *poinsize = *ofs;
- break;
- case KEY_OWNER_LATTICE:
- *ofs = sizeof(float) * 3;
- *poinsize = *ofs;
- break;
- case KEY_OWNER_CURVE:
- if (mode == KEY_MODE_BPOINT) {
- *ofs = sizeof(float) * 4;
- *poinsize = *ofs;
- }
- else {
- ofs[0] = sizeof(float) * 12;
- *poinsize = (*ofs) / 3;
+ switch (key->fromtype) {
+ case KEY_FROMTYPE_ID:
+ if (!key->from)
+ return false;
+
+ switch (GS(key->from->name)) {
+ case ID_ME:
+ *ofs = sizeof(float) * 3;
+ *poinsize = *ofs;
+ break;
+ case KEY_OWNER_LATTICE:
+ *ofs = sizeof(float) * 3;
+ *poinsize = *ofs;
+ break;
+ case KEY_OWNER_CURVE:
+ if (mode == KEY_MODE_BPOINT) {
+ *ofs = sizeof(float) * 4;
+ *poinsize = *ofs;
+ }
+ else {
+ ofs[0] = sizeof(float) * 12;
+ *poinsize = (*ofs) / 3;
+ }
+ break;
+ case KEY_OWNER_PARTICLES:
+ *ofs = sizeof(float) * 3;
+ *poinsize = *ofs;
+ break;
+
+ default:
+ BLI_assert(!"invalid 'key->from' ID type");
+ return false;
}
break;
- case KEY_OWNER_PARTICLES:
+
+ case KEY_FROMTYPE_STRANDS:
*ofs = sizeof(float) * 3;
*poinsize = *ofs;
break;
-
- default:
- BLI_assert(!"invalid 'key->from' ID type");
- return false;
}
-
return true;
}
-static void cp_key(const int start, int end, const int tot, char *poin, Key *key, KeyBlock *actkb, KeyBlock *kb, float *weights, const int mode)
+static void cp_key(const int start, int end, const int tot, char *poin, Key *key, KeyBlock *actkb, KeyBlock *kb, float *weights, const int mode, void *kref_data)
{
float ktot = 0.0, kd = 0.0;
int elemsize, poinsize = 0, a, *ofsp, ofs[32], flagflo = 0;
@@ -657,7 +685,12 @@ static void cp_key(const int start, int end, const int tot, char *poin, Key *key
}
k1 = key_block_get_data(key, actkb, kb, &freek1);
- kref = key_block_get_data(key, actkb, key->refkey, &freekref);
+ if (kref_data) {
+ kref = kref_data;
+ freekref = NULL;
+ }
+ else
+ kref = key_block_get_data(key, actkb, key->refkey, &freekref);
/* this exception is needed curves with multiple splines */
if (start != 0) {
@@ -760,7 +793,7 @@ static void cp_cu_key(Curve *cu, Key *key, KeyBlock *actkb, KeyBlock *kb, const
a1 = max_ii(a, start);
a2 = min_ii(a + step, end);
- if (a1 < a2) cp_key(a1, a2, tot, out, key, actkb, kb, NULL, KEY_MODE_BPOINT);
+ if (a1 < a2) cp_key(a1, a2, tot, out, key, actkb, kb, NULL, KEY_MODE_BPOINT, NULL);
}
else if (nu->bezt) {
step = 3 * nu->pntsu;
@@ -769,7 +802,7 @@ static void cp_cu_key(Curve *cu, Key *key, KeyBlock *actkb, KeyBlock *kb, const
a1 = max_ii(a, start);
a2 = min_ii(a + step, end);
- if (a1 < a2) cp_key(a1, a2, tot, out, key, actkb, kb, NULL, KEY_MODE_BEZTRIPLE);
+ if (a1 < a2) cp_key(a1, a2, tot, out, key, actkb, kb, NULL, KEY_MODE_BEZTRIPLE, NULL);
}
else {
step = 0;
@@ -777,8 +810,8 @@ static void cp_cu_key(Curve *cu, Key *key, KeyBlock *actkb, KeyBlock *kb, const
}
}
-void BKE_key_evaluate_relative(const int start, int end, const int tot, char *basispoin, Key *key, KeyBlock *actkb,
- float **per_keyblock_weights, const int mode)
+void BKE_key_evaluate_relative_ex(const int start, int end, const int tot, char *basispoin, Key *key, KeyBlock *actkb,
+ float **per_keyblock_weights, const int mode, char *refdata)
{
KeyBlock *kb;
int *ofsp, ofs[3], elemsize, b;
@@ -803,7 +836,8 @@ void BKE_key_evaluate_relative(const int start, int end, const int tot, char *ba
if (mode == KEY_MODE_BEZTRIPLE) elemsize *= 3;
/* step 1 init */
- cp_key(start, end, tot, basispoin, key, actkb, key->refkey, NULL, mode);
+ if (!refdata)
+ cp_key(start, end, tot, basispoin, key, actkb, key->refkey, NULL, mode, NULL);
/* step 2: do it */
@@ -813,17 +847,21 @@ void BKE_key_evaluate_relative(const int start, int end, const int tot, char *ba
/* only with value, and no difference allowed */
if (!(kb->flag & KEYBLOCK_MUTE) && icuval != 0.0f && kb->totelem == tot) {
- KeyBlock *refb;
float weight, *weights = per_keyblock_weights ? per_keyblock_weights[keyblock_index] : NULL;
char *freefrom = NULL, *freereffrom = NULL;
- /* reference now can be any block */
- refb = BLI_findlink(&key->block, kb->relative);
- if (refb == NULL) continue;
-
poin = basispoin;
from = key_block_get_data(key, actkb, kb, &freefrom);
- reffrom = key_block_get_data(key, actkb, refb, &freereffrom);
+ if (refdata) {
+ reffrom = refdata;
+ }
+ else {
+ /* reference now can be any block */
+ KeyBlock *refb = BLI_findlink(&key->block, kb->relative);
+ if (refb == NULL) continue;
+
+ reffrom = key_block_get_data(key, actkb, refb, &freereffrom);
+ }
poin += start * poinsize;
reffrom += key->elemsize * start; // key elemsize yes!
@@ -878,6 +916,11 @@ void BKE_key_evaluate_relative(const int start, int end, const int tot, char *ba
}
}
+void BKE_key_evaluate_relative(const int start, int end, const int tot, char *basispoin, Key *key, KeyBlock *actkb,
+ float **per_keyblock_weights, const int mode)
+{
+ BKE_key_evaluate_relative_ex(start, end, tot, basispoin, key, actkb, per_keyblock_weights, mode, NULL);
+}
static void do_key(const int start, int end, const int tot, char *poin, Key *key, KeyBlock *actkb, KeyBlock **k, float *t, const int mode)
{
@@ -1174,6 +1217,21 @@ static float *get_object_weights_array(Object *ob, char *vgroup, WeightsArrayCac
return NULL;
}
+static float *get_weights_array_strands(Strands *strands, const char *UNUSED(vgroup), bool is_refkey, WeightsArrayCache *UNUSED(cache))
+{
+ int totvert = strands->totverts;
+
+ if (is_refkey) {
+ /* for the refkey, return zero weights, so the refkey actually uses the unmodified data */
+ float *weights = MEM_callocN(totvert * sizeof(float), "weights");
+ return weights;
+ }
+ else {
+ /* TODO no vgroup support for strands yet */
+ return NULL;
+ }
+}
+
float **BKE_keyblock_get_per_block_object_weights(Object *ob, Key *key, WeightsArrayCache *cache)
{
KeyBlock *keyblock;
@@ -1281,6 +1339,26 @@ float **BKE_keyblock_get_per_block_particle_weights(Object *ob, ParticleSystem *
return per_keyblock_weights;
}
+float **BKE_keyblock_strands_get_per_block_weights(Strands *strands, Key *key, WeightsArrayCache *cache)
+{
+ KeyBlock *keyblock;
+ float **per_keyblock_weights;
+ int keyblock_index;
+
+ per_keyblock_weights =
+ MEM_mallocN(sizeof(*per_keyblock_weights) * key->totkey,
+ "per keyblock weights");
+
+ for (keyblock = key->block.first, keyblock_index = 0;
+ keyblock;
+ keyblock = keyblock->next, keyblock_index++)
+ {
+ per_keyblock_weights[keyblock_index] = get_weights_array_strands(strands, keyblock->vgroup, keyblock == key->refkey, cache);
+ }
+
+ return per_keyblock_weights;
+}
+
void BKE_keyblock_free_per_block_weights(Key *key, float **per_keyblock_weights, WeightsArrayCache *cache)
{
int a;
@@ -1329,7 +1407,7 @@ static void do_mesh_key(Object *ob, Key *key, char *out, const int tot)
do_key(0, tot, tot, (char *)out, key, actkb, k, t, KEY_MODE_DUMMY);
}
else {
- cp_key(0, tot, tot, (char *)out, key, actkb, k[2], NULL, KEY_MODE_DUMMY);
+ cp_key(0, tot, tot, (char *)out, key, actkb, k[2], NULL, KEY_MODE_DUMMY, NULL);
}
}
}
@@ -1420,7 +1498,7 @@ static void do_latt_key(Object *ob, Key *key, char *out, const int tot)
do_key(0, tot, tot, (char *)out, key, actkb, k, t, KEY_MODE_DUMMY);
}
else {
- cp_key(0, tot, tot, (char *)out, key, actkb, k[2], NULL, KEY_MODE_DUMMY);
+ cp_key(0, tot, tot, (char *)out, key, actkb, k[2], NULL, KEY_MODE_DUMMY, NULL);
}
}
@@ -1449,7 +1527,7 @@ static void do_psys_key(Object *ob, ParticleSystem *psys, float cfra, Key *key,
if (flag == 0)
do_key(0, tot, tot, (char *)out, key, actkb, k, t, KEY_MODE_DUMMY);
else
- cp_key(0, tot, tot, (char *)out, key, actkb, k[2], NULL, KEY_MODE_DUMMY);
+ cp_key(0, tot, tot, (char *)out, key, actkb, k[2], NULL, KEY_MODE_DUMMY, NULL);
}
}
@@ -1529,7 +1607,7 @@ float *BKE_key_evaluate_object_ex(
if (OB_TYPE_SUPPORT_VGROUP(ob->type)) {
float *weights = get_object_weights_array(ob, kb->vgroup, NULL);
- cp_key(0, tot, tot, out, key, actkb, kb, weights, 0);
+ cp_key(0, tot, tot, out, key, actkb, kb, weights, 0, NULL);
if (weights) MEM_freeN(weights);
}
@@ -1555,6 +1633,103 @@ float *BKE_key_evaluate_object(Object *ob, int *r_totelem)
return BKE_key_evaluate_object_ex(ob, r_totelem, NULL, 0);
}
+static void do_strands_key(Strands *strands, Key *key, KeyBlock *actkb, char *out, const int tot)
+{
+ KeyBlock *k[4];
+ float t[4];
+ int flag = 0;
+
+ if (key->type == KEY_RELATIVE) {
+ WeightsArrayCache cache = {0, NULL};
+ float **per_keyblock_weights ;
+ per_keyblock_weights = BKE_keyblock_strands_get_per_block_weights(strands, key, &cache);
+ BKE_key_evaluate_relative_ex(0, tot, tot, (char *)out, key, actkb, per_keyblock_weights, KEY_MODE_DUMMY, out);
+ BKE_keyblock_free_per_block_weights(key, per_keyblock_weights, &cache);
+ }
+ else {
+ const float ctime_scaled = key->ctime / 100.0f;
+
+ flag = setkeys(ctime_scaled, &key->block, k, t, 0);
+
+ if (flag == 0) {
+ do_key(0, tot, tot, (char *)out, key, actkb, k, t, KEY_MODE_DUMMY);
+ }
+ else {
+ cp_key(0, tot, tot, (char *)out, key, actkb, k[2], NULL, KEY_MODE_DUMMY, out);
+ }
+ }
+}
+
+float *BKE_key_evaluate_strands_ex(Strands *strands, Key *key, KeyBlock *actkb, bool lock_shape, int *r_totelem, float *arr, size_t arr_size)
+{
+ char *out;
+ int tot = 0, size = 0;
+
+ if (key == NULL || BLI_listbase_is_empty(&key->block))
+ return NULL;
+
+ /* compute size of output array */
+ tot = strands->totverts;
+ size = tot * 3 * sizeof(float);
+ /* if nothing to interpolate, cancel */
+ if (tot == 0 || size == 0)
+ return NULL;
+
+ /* allocate array */
+ if (arr == NULL) {
+ out = MEM_callocN(size, "BKE_key_evaluate_strands out");
+ }
+ else {
+ if (arr_size != size) {
+ return NULL;
+ }
+
+ out = (char *)arr;
+ }
+
+ if (lock_shape && actkb) {
+ /* shape locked, copy the locked shape instead of blending */
+ float *weights;
+
+ if (actkb->flag & KEYBLOCK_MUTE)
+ actkb = key->refkey;
+
+ /* XXX weights not supported for strands yet */
+ weights = get_weights_array_strands(strands, actkb->vgroup, actkb == key->refkey, NULL);
+
+ cp_key(0, tot, tot, out, key, actkb, actkb, weights, 0, out);
+
+ if (weights)
+ MEM_freeN(weights);
+ }
+ else {
+ do_strands_key(strands, key, actkb, out, tot);
+ }
+
+ if (r_totelem) {
+ *r_totelem = tot;
+ }
+ return (float *)out;
+}
+
+float *BKE_key_evaluate_strands(Strands *strands, Key *key, KeyBlock *actkb, bool lock_shape, int *r_totelem)
+{
+ size_t size = sizeof(float) * 3 * strands->totverts;
+ float *data = MEM_mallocN(size, "strands shape key data");
+ float *result;
+ float *fp;
+ int i;
+
+ for (i = 0, fp = data; i < strands->totverts; ++i, fp += 3)
+ copy_v3_v3(fp, strands->verts[i].co);
+
+ result = BKE_key_evaluate_strands_ex(strands, key, actkb, lock_shape, r_totelem, data, size);
+ if (result != data)
+ MEM_freeN(data);
+
+ return result;
+}
+
/* returns key coordinates when key applied, NULL otherwise */
float *BKE_key_evaluate_particles_ex(Object *ob, ParticleSystem *psys, float cfra, int *r_totelem,
float *arr, size_t arr_size)
@@ -1606,7 +1781,7 @@ float *BKE_key_evaluate_particles_ex(Object *ob, ParticleSystem *psys, float cfr
psys->shapenr = 1;
}
- cp_key(0, tot, tot, out, key, actkb, kb, NULL, 0);
+ cp_key(0, tot, tot, out, key, actkb, kb, NULL, 0, NULL);
}
else if (ob->shapeflag & OB_SHAPE_LOCK) {
/* shape locked, copy the locked shape instead of blending */
@@ -1623,7 +1798,7 @@ float *BKE_key_evaluate_particles_ex(Object *ob, ParticleSystem *psys, float cfr
weights = get_particle_weights_array(ob, psys, kb->name, cfra);
- cp_key(0, tot, tot, out, key, actkb, kb, weights, 0);
+ cp_key(0, tot, tot, out, key, actkb, kb, weights, 0, NULL);
if (weights) MEM_freeN(weights);
}
@@ -2035,6 +2210,55 @@ void BKE_keyblock_convert_to_mesh(KeyBlock *kb, Mesh *me)
}
}
+/************************* Strands ************************/
+void BKE_keyblock_update_from_strands(Strands *strands, KeyBlock *kb)
+{
+ StrandsVertex *vert;
+ float (*fp)[3];
+ int a, tot;
+
+ BLI_assert(strands->totverts == kb->totelem);
+
+ tot = strands->totverts;
+ if (tot == 0) return;
+
+ vert = strands->verts;
+ fp = kb->data;
+ for (a = 0; a < tot; a++, fp++, vert++) {
+ copy_v3_v3(*fp, vert->co);
+ }
+}
+
+void BKE_keyblock_convert_from_strands(Strands *strands, Key *key, KeyBlock *kb)
+{
+ int tot = strands->totverts;
+
+ if (strands->totverts == 0) return;
+
+ MEM_SAFE_FREE(kb->data);
+
+ kb->data = MEM_mallocN(key->elemsize * tot, __func__);
+ kb->totelem = tot;
+
+ BKE_keyblock_update_from_strands(strands, kb);
+}
+
+void BKE_keyblock_convert_to_strands(KeyBlock *kb, Strands *strands)
+{
+ StrandsVertex *vert;
+ const float (*fp)[3];
+ int a, tot;
+
+ vert = strands->verts;
+ fp = kb->data;
+
+ tot = min_ii(kb->totelem, strands->totverts);
+
+ for (a = 0; a < tot; a++, fp++, vert++) {
+ copy_v3_v3(vert->co, *fp);
+ }
+}
+
/************************* raw coords ************************/
void BKE_keyblock_update_from_vertcos(Object *ob, KeyBlock *kb, float (*vertCos)[3])
{
@@ -2272,11 +2496,10 @@ void BKE_keyblock_convert_from_hair_keys(struct Object *UNUSED(ob), struct Parti
* \param org_index if < 0, current object's active shape will be used as skey to move.
* \return true if something was done, else false.
*/
-bool BKE_keyblock_move(Object *ob, int org_index, int new_index)
+bool BKE_keyblock_move_ex(Key *key, int *shapenr, int org_index, int new_index)
{
- Key *key = BKE_key_from_object(ob);
KeyBlock *kb;
- const int act_index = ob->shapenr - 1;
+ const int act_index = *shapenr - 1;
const int totkey = key->totkey;
int i;
bool rev, in_range = false;
@@ -2336,13 +2559,13 @@ bool BKE_keyblock_move(Object *ob, int org_index, int new_index)
/* Need to update active shape number if it's affected, same principle as for relative indices above. */
if (org_index == act_index) {
- ob->shapenr = new_index + 1;
+ *shapenr = new_index + 1;
}
else if (act_index < org_index && act_index >= new_index) {
- ob->shapenr++;
+ (*shapenr)++;
}
else if (act_index > org_index && act_index <= new_index) {
- ob->shapenr--;
+ (*shapenr)--;
}
/* First key is always refkey, matches interface and BKE_key_sort */
@@ -2351,6 +2574,14 @@ bool BKE_keyblock_move(Object *ob, int org_index, int new_index)
return true;
}
+bool BKE_keyblock_move(Object *ob, int org_index, int new_index)
+{
+ int shapenr;
+ bool result = BKE_keyblock_move_ex(BKE_key_from_object(ob), &shapenr, org_index, new_index);
+ ob->shapenr = shapenr;
+ return result;
+}
+
/**
* Check if given keyblock (as index) is used as basis by others in given key.
*/
diff --git a/source/blender/blenkernel/intern/mesh_sample.c b/source/blender/blenkernel/intern/mesh_sample.c
new file mode 100644
index 00000000000..c36d2adde8b
--- /dev/null
+++ b/source/blender/blenkernel/intern/mesh_sample.c
@@ -0,0 +1,379 @@
+/*
+ * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/blenkernel/intern/mesh_sample.c
+ * \ingroup bke
+ *
+ * Sample a mesh surface or volume and evaluate samples on deformed meshes.
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_key_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "BLI_utildefines.h"
+#include "BLI_math.h"
+#include "BLI_rand.h"
+
+#include "BKE_bvhutils.h"
+#include "BKE_mesh_sample.h"
+#include "BKE_customdata.h"
+#include "BKE_DerivedMesh.h"
+
+#include "BLI_strict_flags.h"
+
+/* ==== Evaluate ==== */
+
+bool BKE_mesh_sample_eval(DerivedMesh *dm, const MSurfaceSample *sample, float loc[3], float nor[3], float tang[3])
+{
+ MVert *mverts = dm->getVertArray(dm);
+ unsigned int totverts = (unsigned int)dm->getNumVerts(dm);
+ MVert *v1, *v2, *v3;
+
+ zero_v3(loc);
+ zero_v3(nor);
+ zero_v3(tang);
+
+ if (sample->orig_verts[0] >= totverts ||
+ sample->orig_verts[1] >= totverts ||
+ sample->orig_verts[2] >= totverts)
+ return false;
+
+ v1 = &mverts[sample->orig_verts[0]];
+ v2 = &mverts[sample->orig_verts[1]];
+ v3 = &mverts[sample->orig_verts[2]];
+
+ { /* location */
+ madd_v3_v3fl(loc, v1->co, sample->orig_weights[0]);
+ madd_v3_v3fl(loc, v2->co, sample->orig_weights[1]);
+ madd_v3_v3fl(loc, v3->co, sample->orig_weights[2]);
+ }
+
+ { /* normal */
+ float vnor[3];
+
+ normal_short_to_float_v3(vnor, v1->no);
+ madd_v3_v3fl(nor, vnor, sample->orig_weights[0]);
+ normal_short_to_float_v3(vnor, v2->no);
+ madd_v3_v3fl(nor, vnor, sample->orig_weights[1]);
+ normal_short_to_float_v3(vnor, v3->no);
+ madd_v3_v3fl(nor, vnor, sample->orig_weights[2]);
+
+ normalize_v3(nor);
+ }
+
+ { /* tangent */
+ float edge[3];
+
+ /* XXX simply using the v1-v2 edge as a tangent vector for now ...
+ * Eventually mikktspace generated tangents (CD_TANGENT tessface layer)
+ * should be used for consistency, but requires well-defined tessface
+ * indices for the mesh surface samples.
+ */
+
+ sub_v3_v3v3(edge, v2->co, v1->co);
+ /* make edge orthogonal to nor */
+ madd_v3_v3fl(edge, nor, -dot_v3v3(edge, nor));
+ normalize_v3_v3(tang, edge);
+ }
+
+ return true;
+}
+
+bool BKE_mesh_sample_shapekey(Key *key, KeyBlock *kb, const MSurfaceSample *sample, float loc[3])
+{
+ float *v1, *v2, *v3;
+
+ BLI_assert(key->elemsize == 3 * sizeof(float));
+ BLI_assert(sample->orig_verts[0] < (unsigned int)kb->totelem);
+ BLI_assert(sample->orig_verts[1] < (unsigned int)kb->totelem);
+ BLI_assert(sample->orig_verts[2] < (unsigned int)kb->totelem);
+
+ v1 = (float *)kb->data + sample->orig_verts[0] * 3;
+ v2 = (float *)kb->data + sample->orig_verts[1] * 3;
+ v3 = (float *)kb->data + sample->orig_verts[2] * 3;
+
+ zero_v3(loc);
+ madd_v3_v3fl(loc, v1, sample->orig_weights[0]);
+ madd_v3_v3fl(loc, v2, sample->orig_weights[1]);
+ madd_v3_v3fl(loc, v3, sample->orig_weights[2]);
+
+ /* TODO use optional vgroup weights to determine if a shapeky actually affects the sample */
+ return true;
+}
+
+
+/* ==== Sampling Utilities ==== */
+
+BLI_INLINE void mesh_sample_weights_from_loc(MSurfaceSample *sample, DerivedMesh *dm, int face_index, const float loc[3])
+{
+ MFace *face = &dm->getTessFaceArray(dm)[face_index];
+ unsigned int index[4] = { face->v1, face->v2, face->v3, face->v4 };
+ MVert *mverts = dm->getVertArray(dm);
+
+ float *v1 = mverts[face->v1].co;
+ float *v2 = mverts[face->v2].co;
+ float *v3 = mverts[face->v3].co;
+ float *v4 = face->v4 ? mverts[face->v4].co : NULL;
+ float w[4];
+ int tri[3];
+
+ interp_weights_face_v3_index(tri, w, v1, v2, v3, v4, loc);
+
+ sample->orig_verts[0] = index[tri[0]];
+ sample->orig_verts[1] = index[tri[1]];
+ sample->orig_verts[2] = index[tri[2]];
+ sample->orig_weights[0] = w[tri[0]];
+ sample->orig_weights[1] = w[tri[1]];
+ sample->orig_weights[2] = w[tri[2]];
+}
+
+/* ==== Sampling ==== */
+
+static bool mesh_sample_store_array_sample(void *vdata, int capacity, int index, const MSurfaceSample *sample)
+{
+ MSurfaceSample *data = vdata;
+ if (index >= capacity)
+ return false;
+
+ data[index] = *sample;
+ return true;
+}
+
+void BKE_mesh_sample_storage_single(MSurfaceSampleStorage *storage, MSurfaceSample *sample)
+{
+ /* handled as just a special array case with capacity = 1 */
+ storage->store_sample = mesh_sample_store_array_sample;
+ storage->capacity = 1;
+ storage->data = sample;
+ storage->free_data = false;
+}
+
+void BKE_mesh_sample_storage_array(MSurfaceSampleStorage *storage, MSurfaceSample *samples, int capacity)
+{
+ storage->store_sample = mesh_sample_store_array_sample;
+ storage->capacity = capacity;
+ storage->data = samples;
+ storage->free_data = false;
+}
+
+void BKE_mesh_sample_storage_release(MSurfaceSampleStorage *storage)
+{
+ if (storage->free_data)
+ MEM_freeN(storage->data);
+}
+
+
+int BKE_mesh_sample_generate_random(MSurfaceSampleStorage *dst, DerivedMesh *dm, unsigned int seed, int totsample)
+{
+ MFace *mfaces;
+ int totfaces;
+ RNG *rng;
+ MFace *mface;
+ float a, b;
+ int i, stored = 0;
+
+ rng = BLI_rng_new(seed);
+
+ DM_ensure_tessface(dm);
+ mfaces = dm->getTessFaceArray(dm);
+ totfaces = dm->getNumTessFaces(dm);
+
+ for (i = 0; i < totsample; ++i) {
+ MSurfaceSample sample = {{0}};
+
+ mface = &mfaces[BLI_rng_get_int(rng) % totfaces];
+
+ if (mface->v4 && BLI_rng_get_int(rng) % 2 == 0) {
+ sample.orig_verts[0] = mface->v3;
+ sample.orig_verts[1] = mface->v4;
+ sample.orig_verts[2] = mface->v1;
+ }
+ else {
+ sample.orig_verts[0] = mface->v1;
+ sample.orig_verts[1] = mface->v2;
+ sample.orig_verts[2] = mface->v3;
+ }
+
+ a = BLI_rng_get_float(rng);
+ b = BLI_rng_get_float(rng);
+ if (a + b > 1.0f) {
+ a = 1.0f - a;
+ b = 1.0f - b;
+ }
+ sample.orig_weights[0] = 1.0f - (a + b);
+ sample.orig_weights[1] = a;
+ sample.orig_weights[2] = b;
+
+ if (dst->store_sample(dst->data, dst->capacity, i, &sample))
+ ++stored;
+ else
+ break;
+ }
+
+ BLI_rng_free(rng);
+
+ return stored;
+}
+
+
+static bool sample_bvh_raycast(MSurfaceSample *sample, DerivedMesh *dm, BVHTreeFromMesh *bvhdata, const float ray_start[3], const float ray_end[3])
+{
+ BVHTreeRayHit hit;
+ float ray_normal[3], dist;
+
+ sub_v3_v3v3(ray_normal, ray_end, ray_start);
+ dist = normalize_v3(ray_normal);
+
+ hit.index = -1;
+ hit.dist = dist;
+
+ if (BLI_bvhtree_ray_cast(bvhdata->tree, ray_start, ray_normal, 0.0f,
+ &hit, bvhdata->raycast_callback, bvhdata) >= 0) {
+
+ mesh_sample_weights_from_loc(sample, dm, hit.index, hit.co);
+
+ return true;
+ }
+ else
+ return false;
+}
+
+int BKE_mesh_sample_generate_raycast(MSurfaceSampleStorage *dst, DerivedMesh *dm, MeshSampleRayCallback ray_cb, void *userdata, int totsample)
+{
+ BVHTreeFromMesh bvhdata;
+ float ray_start[3], ray_end[3];
+ int i, stored = 0;
+
+ DM_ensure_tessface(dm);
+
+ memset(&bvhdata, 0, sizeof(BVHTreeFromMesh));
+ bvhtree_from_mesh_faces(&bvhdata, dm, 0.0f, 4, 6);
+
+ if (bvhdata.tree) {
+ for (i = 0; i < totsample; ++i) {
+ if (ray_cb(userdata, ray_start, ray_end)) {
+ MSurfaceSample sample;
+ if (sample_bvh_raycast(&sample, dm, &bvhdata, ray_start, ray_end)) {
+ if (dst->store_sample(dst->data, dst->capacity, i, &sample))
+ ++stored;
+ else
+ break;
+ }
+ }
+ }
+ }
+
+ free_bvhtree_from_mesh(&bvhdata);
+
+ return stored;
+}
+
+/* ==== Utilities ==== */
+
+#include "DNA_particle_types.h"
+
+#include "BKE_bvhutils.h"
+#include "BKE_particle.h"
+
+bool BKE_mesh_sample_from_particle(MSurfaceSample *sample, ParticleSystem *psys, DerivedMesh *dm, ParticleData *pa)
+{
+ MVert *mverts;
+ MFace *mface;
+ float mapfw[4];
+ int mapindex;
+ float *co1 = NULL, *co2 = NULL, *co3 = NULL, *co4 = NULL;
+ float vec[3];
+ float w[4];
+
+ if (!psys_get_index_on_dm(psys, dm, pa, &mapindex, mapfw))
+ return false;
+
+ mface = dm->getTessFaceData(dm, mapindex, CD_MFACE);
+ mverts = dm->getVertDataArray(dm, CD_MVERT);
+
+ co1 = mverts[mface->v1].co;
+ co2 = mverts[mface->v2].co;
+ co3 = mverts[mface->v3].co;
+
+ if (mface->v4) {
+ co4 = mverts[mface->v4].co;
+
+ interp_v3_v3v3v3v3(vec, co1, co2, co3, co4, mapfw);
+ }
+ else {
+ interp_v3_v3v3v3(vec, co1, co2, co3, mapfw);
+ }
+
+ /* test both triangles of the face */
+ interp_weights_face_v3(w, co1, co2, co3, NULL, vec);
+ if (w[0] <= 1.0f && w[1] <= 1.0f && w[2] <= 1.0f) {
+ sample->orig_verts[0] = mface->v1;
+ sample->orig_verts[1] = mface->v2;
+ sample->orig_verts[2] = mface->v3;
+
+ copy_v3_v3(sample->orig_weights, w);
+ return true;
+ }
+ else if (mface->v4) {
+ interp_weights_face_v3(w, co3, co4, co1, NULL, vec);
+ sample->orig_verts[0] = mface->v3;
+ sample->orig_verts[1] = mface->v4;
+ sample->orig_verts[2] = mface->v1;
+
+ copy_v3_v3(sample->orig_weights, w);
+ return true;
+ }
+ else
+ return false;
+}
+
+bool BKE_mesh_sample_to_particle(MSurfaceSample *sample, ParticleSystem *UNUSED(psys), DerivedMesh *dm, BVHTreeFromMesh *bvhtree, ParticleData *pa)
+{
+ BVHTreeNearest nearest;
+ float vec[3], nor[3], tang[3];
+
+ BKE_mesh_sample_eval(dm, sample, vec, nor, tang);
+
+ nearest.index = -1;
+ nearest.dist_sq = FLT_MAX;
+ BLI_bvhtree_find_nearest(bvhtree->tree, vec, &nearest, bvhtree->nearest_callback, bvhtree);
+ if (nearest.index >= 0) {
+ MFace *mface = dm->getTessFaceData(dm, nearest.index, CD_MFACE);
+ MVert *mverts = dm->getVertDataArray(dm, CD_MVERT);
+
+ float *co1 = mverts[mface->v1].co;
+ float *co2 = mverts[mface->v2].co;
+ float *co3 = mverts[mface->v3].co;
+ float *co4 = mface->v4 ? mverts[mface->v4].co : NULL;
+
+ pa->num = nearest.index;
+ pa->num_dmcache = DMCACHE_NOTFOUND;
+
+ interp_weights_face_v3(pa->fuv, co1, co2, co3, co4, vec);
+ pa->foffset = 0.0f; /* XXX any sensible way to reconstruct this? */
+
+ return true;
+ }
+ else
+ return false;
+}
diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c
index 35c169f64f2..845f0d9da4e 100644
--- a/source/blender/blenkernel/intern/object.c
+++ b/source/blender/blenkernel/intern/object.c
@@ -1338,6 +1338,7 @@ ParticleSystem *BKE_object_copy_particlesystem(ParticleSystem *psys)
psysn->pathcache = NULL;
psysn->childcache = NULL;
psysn->edit = NULL;
+ psysn->hairedit = NULL;
psysn->pdd = NULL;
psysn->effectors = NULL;
psysn->tree = NULL;
diff --git a/source/blender/blenkernel/intern/object_dupli.c b/source/blender/blenkernel/intern/object_dupli.c
index 24a5f7e849b..3ee6cb9e85d 100644
--- a/source/blender/blenkernel/intern/object_dupli.c
+++ b/source/blender/blenkernel/intern/object_dupli.c
@@ -62,6 +62,7 @@
#include "BKE_lattice.h"
#include "BKE_main.h"
#include "BKE_mesh.h"
+#include "BKE_mesh_sample.h"
#include "BKE_object.h"
#include "BKE_particle.h"
#include "BKE_scene.h"
@@ -1601,13 +1602,56 @@ static int count_hair_verts(ParticleSystem *psys)
return numverts;
}
+static void dupli_strands_data_update(CacheLibrary *cachelib, DupliObjectData *data,
+ DupliObject *dob, bool calc_strands_base) {
+ ParticleSystem *psys;
+ for (psys = dob->ob->particlesystem.first; psys; psys = psys->next) {
+ if (cachelib->data_types & CACHE_TYPE_HAIR) {
+ if (psys->part && psys->part->type == PART_HAIR) {
+ int numstrands = psys->totpart;
+ int numverts = count_hair_verts(psys);
+ ParticleData *pa;
+ HairKey *hkey;
+ int p, k;
+
+ Strands *strands = BKE_strands_new(numstrands, numverts);
+ StrandsCurve *scurve = strands->curves;
+ StrandsVertex *svert = strands->verts;
+
+ for (p = 0, pa = psys->particles; p < psys->totpart; ++p, ++pa) {
+ float hairmat[4][4];
+ psys_mat_hair_to_object(dob->ob, data->dm, psys->part->from, pa, hairmat);
+
+ scurve->numverts = pa->totkey;
+ copy_m3_m4(scurve->root_matrix, hairmat);
+ BKE_mesh_sample_from_particle(&scurve->msurf, psys, data->dm, pa);
+
+ for (k = 0, hkey = pa->hair; k < pa->totkey; ++k, ++hkey) {
+ copy_v3_v3(svert->co, hkey->co);
+ if (calc_strands_base)
+ copy_v3_v3(svert->base, hkey->co);
+ svert->time = hkey->time;
+ svert->weight = hkey->weight;
+ ++svert;
+ }
+ ++scurve;
+ }
+
+ BKE_dupli_object_data_add_strands(data, psys->name, strands);
+ }
+ }
+ }
+}
+
typedef struct DupliObjectDataFromGroupState {
EvaluationContext *eval_ctx;
Scene *scene;
+ CacheLibrary *cachelib;
+ bool calc_strands_base;
} DupliObjectDataFromGroupState;
typedef struct DupliObjectDataFromGroupTask {
- Object *object;
+ DupliObject *dob;
DupliObjectData *data;
} DupliObjectDataFromGroupTask;
@@ -1615,18 +1659,21 @@ static void dupli_object_data_from_group_func(TaskPool *pool, void *taskdata, in
{
DupliObjectDataFromGroupState *state = (DupliObjectDataFromGroupState *)BLI_task_pool_userdata(pool);
DupliObjectDataFromGroupTask *task = (DupliObjectDataFromGroupTask *)taskdata;
+ Object *object = task->dob->ob;
DerivedMesh *dm;
if (state->eval_ctx->mode == DAG_EVAL_RENDER) {
- dm = mesh_create_derived_render(state->scene, task->object, CD_MASK_BAREMESH);
+ dm = mesh_create_derived_render(state->scene, object, CD_MASK_BAREMESH);
}
else {
- dm = mesh_create_derived_view(state->scene, task->object, CD_MASK_BAREMESH);
+ dm = mesh_create_derived_view(state->scene, object, CD_MASK_BAREMESH);
}
if (dm != NULL) {
BKE_dupli_object_data_set_mesh(task->data, dm);
}
+
+ dupli_strands_data_update(state->cachelib, task->data, task->dob, state->calc_strands_base);
}
void BKE_dupli_cache_from_group(Scene *scene, Group *group, CacheLibrary *cachelib, DupliCache *dupcache, EvaluationContext *eval_ctx, bool calc_strands_base)
@@ -1651,62 +1698,29 @@ void BKE_dupli_cache_from_group(Scene *scene, Group *group, CacheLibrary *cachel
state.eval_ctx = eval_ctx;
state.scene = scene;
+ state.cachelib = cachelib;
+ state.calc_strands_base = calc_strands_base;
task_pool = BLI_task_pool_create(task_scheduler, &state);
for (dob = dupcache->duplilist.first; dob; dob = dob->next) {
DupliObjectData *data = BKE_dupli_cache_find_data(dupcache, dob->ob);
if (!data) {
- ParticleSystem *psys;
-
+ bool strands_handled = false;
data = dupli_cache_add_object_data(dupcache, dob->ob);
-
if (cachelib->data_types & CACHE_TYPE_DERIVED_MESH) {
if (dob->ob->type == OB_MESH) {
/* TODO(sergey): Consider using memory pool instead. */
DupliObjectDataFromGroupTask *task = MEM_mallocN(sizeof(DupliObjectDataFromGroupTask),
- "dupcache task");
- task->object = dob->ob;
+ "dupcache task");
+ task->dob = dob;
task->data = data;
BLI_task_pool_push(task_pool, dupli_object_data_from_group_func, task, true, TASK_PRIORITY_LOW);
+ /* Task is getting care of strands as well. */
+ strands_handled = true;
}
}
-
- for (psys = dob->ob->particlesystem.first; psys; psys = psys->next) {
- if (cachelib->data_types & CACHE_TYPE_HAIR) {
- if (psys->part && psys->part->type == PART_HAIR) {
- int numstrands = psys->totpart;
- int numverts = count_hair_verts(psys);
- ParticleData *pa;
- HairKey *hkey;
- int p, k;
-
- Strands *strands = BKE_strands_new(numstrands, numverts);
- StrandsCurve *scurve = strands->curves;
- StrandsVertex *svert = strands->verts;
-
- for (p = 0, pa = psys->particles; p < psys->totpart; ++p, ++pa) {
- float hairmat[4][4];
- psys_mat_hair_to_object(dob->ob, data->dm, psys->part->from, pa, hairmat);
-
- scurve->numverts = pa->totkey;
- copy_m3_m4(scurve->root_matrix, hairmat);
-
- for (k = 0, hkey = pa->hair; k < pa->totkey; ++k, ++hkey) {
- copy_v3_v3(svert->co, hkey->co);
- if (calc_strands_base)
- copy_v3_v3(svert->base, hkey->co);
- svert->time = hkey->time;
- svert->weight = hkey->weight;
-
- ++svert;
- }
-
- ++scurve;
- }
-
- BKE_dupli_object_data_add_strands(data, psys->name, strands);
- }
- }
+ if (!strands_handled) {
+ dupli_strands_data_update(cachelib, data, dob, calc_strands_base);
}
}
}
@@ -1717,12 +1731,26 @@ void BKE_dupli_cache_from_group(Scene *scene, Group *group, CacheLibrary *cachel
/* ------------------------------------------------------------------------- */
+static void object_dupli_cache_apply_modifiers(Object *ob, Scene *scene, eCacheLibrary_EvalMode eval_mode)
+{
+ CacheLibrary *cachelib = ob->cache_library;
+ int frame = scene->r.cfra;
+ CacheProcessData process_data;
+
+ process_data.lay = ob->lay;
+ copy_m4_m4(process_data.mat, ob->obmat);
+ process_data.dupcache = ob->dup_cache;
+
+ BKE_cache_process_dupli_cache(cachelib, &process_data, scene, ob->dup_group, (float)frame, (float)frame, eval_mode);
+}
+
void BKE_object_dupli_cache_update(Scene *scene, Object *ob, EvaluationContext *eval_ctx, float frame)
{
const eCacheLibrary_EvalMode eval_mode = eval_ctx->mode == DAG_EVAL_RENDER ? CACHE_LIBRARY_EVAL_RENDER : CACHE_LIBRARY_EVAL_REALTIME;
bool is_dupligroup = (ob->transflag & OB_DUPLIGROUP) && ob->dup_group;
bool is_cached = ob->cache_library && (ob->cache_library->source_mode == CACHE_LIBRARY_SOURCE_CACHE || ob->cache_library->display_mode == CACHE_LIBRARY_DISPLAY_RESULT);
+ bool do_modifiers = ob->cache_library && ob->cache_library->display_mode == CACHE_LIBRARY_DISPLAY_MODIFIERS;
/* cache is a group duplicator feature only */
if (is_dupligroup && is_cached) {
@@ -1745,6 +1773,10 @@ void BKE_object_dupli_cache_update(Scene *scene, Object *ob, EvaluationContext *
if (!(ob->cache_library->flag & CACHE_LIBRARY_BAKING)) {
/* TODO at this point we could apply animation offset */
BKE_cache_read_dupli_cache(ob->cache_library, ob->dup_cache, scene, ob->dup_group, frame, eval_mode, true);
+
+ if (do_modifiers) {
+ object_dupli_cache_apply_modifiers(ob, scene, eval_mode);
+ }
}
ob->dup_cache->flag &= ~DUPCACHE_FLAG_DIRTY;
diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c
index 34dfa4cb476..97508523060 100644
--- a/source/blender/blenkernel/intern/particle.c
+++ b/source/blender/blenkernel/intern/particle.c
@@ -65,6 +65,7 @@
#include "BKE_boids.h"
#include "BKE_cloth.h"
#include "BKE_colortools.h"
+#include "BKE_editstrands.h"
#include "BKE_effect.h"
#include "BKE_global.h"
#include "BKE_group.h"
@@ -578,6 +579,11 @@ void psys_free(Object *ob, ParticleSystem *psys)
if (psys->edit && psys->free_edit)
psys->free_edit(psys->edit);
+ if (psys->hairedit) {
+ BKE_editstrands_free(psys->hairedit);
+ MEM_freeN(psys->hairedit);
+ psys->hairedit = NULL;
+ }
if (psys->child) {
MEM_freeN(psys->child);
@@ -1175,6 +1181,11 @@ static int psys_map_index_on_dm(DerivedMesh *dm, int from, int index, int index_
return 1;
}
+int psys_get_index_on_dm(ParticleSystem *psys, DerivedMesh *dm, ParticleData *pa, int *mapindex, float mapfw[4])
+{
+ return psys_map_index_on_dm(dm, psys->part->from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, mapindex, mapfw);
+}
+
/* interprets particle data to get a point on a mesh in object space */
void psys_particle_on_dm(DerivedMesh *dm, int from, int index, int index_dmcache,
const float fw[4], float foffset, float vec[3], float nor[3], float utan[3], float vtan[3],
@@ -2775,7 +2786,7 @@ void object_remove_particle_system(Scene *UNUSED(scene), Object *ob)
if (ob->particlesystem.first)
((ParticleSystem *) ob->particlesystem.first)->flag |= PSYS_CURRENT;
else
- ob->mode &= ~OB_MODE_PARTICLE_EDIT;
+ ob->mode &= ~(OB_MODE_PARTICLE_EDIT | OB_MODE_HAIR_EDIT);
DAG_relations_tag_update(G.main);
DAG_id_tag_update(&ob->id, OB_RECALC_DATA);