From 24b77359ae46c5aecbd90c3179e883efeed25398 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20T=C3=B6nne?= Date: Mon, 3 Mar 2014 10:59:36 +0100 Subject: Skeleton code for sampling meshes. Conflicts: source/blender/blenkernel/CMakeLists.txt --- source/blender/blenkernel/intern/mesh_sample.c | 85 ++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 source/blender/blenkernel/intern/mesh_sample.c (limited to 'source/blender/blenkernel/intern') diff --git a/source/blender/blenkernel/intern/mesh_sample.c b/source/blender/blenkernel/intern/mesh_sample.c new file mode 100644 index 00000000000..ddb35e222e3 --- /dev/null +++ b/source/blender/blenkernel/intern/mesh_sample.c @@ -0,0 +1,85 @@ +/* + * ***** 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_mesh_types.h" +#include "DNA_meshdata_types.h" + +#include "BLI_utildefines.h" +#include "BLI_math.h" +#include "BLI_rand.h" + +#include "BKE_mesh_sample.h" +#include "BKE_customdata.h" +#include "BKE_DerivedMesh.h" + +#include "BLI_strict_flags.h" + +/* Evaluate */ + + +/* Iterators */ + +#if 0 +static void mesh_sample_surface_array_iterator_next(MSurfaceSampleArrayIterator *iter) +{ + ++iter->cur; + --iter->remaining; +} + +static bool mesh_sample_surface_array_iterator_valid(MSurfaceSampleArrayIterator *iter) +{ + return (iter->remaining > 0); +} + +static void mesh_sample_surface_array_iterator_free(MSurfaceSampleArrayIterator *iter) +{ +} + +void BKE_mesh_sample_surface_array_begin(MSurfaceSampleArrayIterator *iter, MSurfaceSample *array, int totarray) +{ + iter->cur = array; + iter->remaining = totarray; + + iter->base.next = +} +#endif + + +/* Sampling */ + +static mesh_sample_surface_uniform(const MSurfaceSampleInfo *info, MSurfaceSample *sample, RNG *rng) +{ + sample->orig_face = BLI_rng_get_int(rng) % info->dm->getNumTessFaces(info->dm); + sample->orig_weights = +} + +void BKE_mesh_sample_surface_array(const MSurfaceSampleInfo *info, MSurfaceSample *samples, int totsample) +{ + RNG *rng = BLI_rng_new(info->seed); + +} -- cgit v1.2.3 From 71e34dad2b1e93fd03fcc2061c8be623a14bb5f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20T=C3=B6nne?= Date: Mon, 3 Mar 2014 12:36:02 +0100 Subject: Usable random distribution algorithm. Does not include area weighting yet. --- source/blender/blenkernel/intern/mesh_sample.c | 54 ++++++++++++++++++++++++-- 1 file changed, 50 insertions(+), 4 deletions(-) (limited to 'source/blender/blenkernel/intern') diff --git a/source/blender/blenkernel/intern/mesh_sample.c b/source/blender/blenkernel/intern/mesh_sample.c index ddb35e222e3..53b9231384d 100644 --- a/source/blender/blenkernel/intern/mesh_sample.c +++ b/source/blender/blenkernel/intern/mesh_sample.c @@ -72,14 +72,60 @@ void BKE_mesh_sample_surface_array_begin(MSurfaceSampleArrayIterator *iter, MSur /* Sampling */ -static mesh_sample_surface_uniform(const MSurfaceSampleInfo *info, MSurfaceSample *sample, RNG *rng) +void BKE_mesh_sample_info_random(MSurfaceSampleInfo *info, DerivedMesh *dm, unsigned int seed) { - sample->orig_face = BLI_rng_get_int(rng) % info->dm->getNumTessFaces(info->dm); - sample->orig_weights = + info->algorithm = MSS_RANDOM; + info->dm = dm; + + info->rng = BLI_rng_new(seed); +} + +void BKE_mesh_sample_info_release(MSurfaceSampleInfo *info) +{ + if (info->rng) { + BLI_rng_free(info->rng); + info->rng = NULL; + } +} + + +static void mesh_sample_surface_random(const MSurfaceSampleInfo *info, MSurfaceSample *sample) +{ + MFace *mfaces = info->dm->getTessFaceArray(info->dm); + int totfaces = info->dm->getNumTessFaces(info->dm); + MFace *mface; + float sum, inv_sum; + + sample->orig_face = BLI_rng_get_int(info->rng) % totfaces; + + mface = &mfaces[sample->orig_face]; + sample->orig_weights[0] = BLI_rng_get_float(info->rng); + sample->orig_weights[1] = BLI_rng_get_float(info->rng); + sample->orig_weights[2] = BLI_rng_get_float(info->rng); + sample->orig_weights[3] = mface->v4 ? BLI_rng_get_float(info->rng) : 0.0f; + + sum = sample->orig_weights[0] + + sample->orig_weights[1] + + sample->orig_weights[2] + + sample->orig_weights[3]; + inv_sum = sum > 0.0f ? 1.0f/sum : 0.0f; + sample->orig_weights[0] *= inv_sum; + sample->orig_weights[1] *= inv_sum; + sample->orig_weights[2] *= inv_sum; + sample->orig_weights[3] *= inv_sum; } void BKE_mesh_sample_surface_array(const MSurfaceSampleInfo *info, MSurfaceSample *samples, int totsample) { - RNG *rng = BLI_rng_new(info->seed); + MSurfaceSample *sample; + int i; + switch (info->algorithm) { + case MSS_RANDOM: { + DM_ensure_tessface(info->dm); + for (sample = samples, i = 0; i < totsample; ++sample, ++i) + mesh_sample_surface_random(info, sample); + break; + } + } } -- cgit v1.2.3 From a952800ffcae717f6e5220a031ba492e7c155409 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20T=C3=B6nne?= Date: Mon, 3 Mar 2014 14:10:58 +0100 Subject: Eval function to get a location and normal vector from mesh samples. --- source/blender/blenkernel/intern/mesh_sample.c | 40 ++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) (limited to 'source/blender/blenkernel/intern') diff --git a/source/blender/blenkernel/intern/mesh_sample.c b/source/blender/blenkernel/intern/mesh_sample.c index 53b9231384d..49e44863f9f 100644 --- a/source/blender/blenkernel/intern/mesh_sample.c +++ b/source/blender/blenkernel/intern/mesh_sample.c @@ -41,6 +41,46 @@ /* Evaluate */ +void BKE_mesh_sample_eval(DerivedMesh *dm, const MSurfaceSample *sample, float loc[3], float nor[3]) +{ + MVert *mverts = dm->getVertArray(dm); + MVert *v1, *v2, *v3, *v4; + MFace *mfaces = dm->getTessFaceArray(dm); + int totfaces = dm->getNumTessFaces(dm); + MFace *mface = &mfaces[sample->orig_face]; + float vnor[3]; + + zero_v3(loc); + zero_v3(nor); + + if (sample->orig_face >= totfaces) + return; + + v1 = &mverts[mface->v1]; + v2 = &mverts[mface->v2]; + v3 = &mverts[mface->v3]; + + 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_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]); + + if (mface->v4) { + v4 = &mverts[mface->v4]; + + madd_v3_v3fl(loc, v4->co, sample->orig_weights[3]); + + normal_short_to_float_v3(vnor, v4->no); + madd_v3_v3fl(nor, vnor, sample->orig_weights[3]); + } +} + /* Iterators */ -- cgit v1.2.3 From 308af3bfb36248a50eb35581b194835de67061c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20T=C3=B6nne?= Date: Tue, 4 Mar 2014 13:41:01 +0100 Subject: Added a bool return to the eval function to give feedback on invalid samples. --- source/blender/blenkernel/intern/mesh_sample.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'source/blender/blenkernel/intern') diff --git a/source/blender/blenkernel/intern/mesh_sample.c b/source/blender/blenkernel/intern/mesh_sample.c index 49e44863f9f..a2454e8b732 100644 --- a/source/blender/blenkernel/intern/mesh_sample.c +++ b/source/blender/blenkernel/intern/mesh_sample.c @@ -41,7 +41,7 @@ /* Evaluate */ -void BKE_mesh_sample_eval(DerivedMesh *dm, const MSurfaceSample *sample, float loc[3], float nor[3]) +bool BKE_mesh_sample_eval(DerivedMesh *dm, const MSurfaceSample *sample, float loc[3], float nor[3]) { MVert *mverts = dm->getVertArray(dm); MVert *v1, *v2, *v3, *v4; @@ -54,7 +54,7 @@ void BKE_mesh_sample_eval(DerivedMesh *dm, const MSurfaceSample *sample, float l zero_v3(nor); if (sample->orig_face >= totfaces) - return; + return false; v1 = &mverts[mface->v1]; v2 = &mverts[mface->v2]; @@ -79,6 +79,8 @@ void BKE_mesh_sample_eval(DerivedMesh *dm, const MSurfaceSample *sample, float l normal_short_to_float_v3(vnor, v4->no); madd_v3_v3fl(nor, vnor, sample->orig_weights[3]); } + + return true; } -- cgit v1.2.3 From fe48c353f184d5c73f9ae8340ca7b4664a69df59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20T=C3=B6nne?= Date: Tue, 4 Mar 2014 13:42:51 +0100 Subject: Normalize the normal vector after sample eval to account for interpolation. --- source/blender/blenkernel/intern/mesh_sample.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'source/blender/blenkernel/intern') diff --git a/source/blender/blenkernel/intern/mesh_sample.c b/source/blender/blenkernel/intern/mesh_sample.c index a2454e8b732..51de927152a 100644 --- a/source/blender/blenkernel/intern/mesh_sample.c +++ b/source/blender/blenkernel/intern/mesh_sample.c @@ -80,6 +80,8 @@ bool BKE_mesh_sample_eval(DerivedMesh *dm, const MSurfaceSample *sample, float l madd_v3_v3fl(nor, vnor, sample->orig_weights[3]); } + normalize_v3(nor); + return true; } -- cgit v1.2.3 From 4b4f24607e4bfd1ad7f5d8ef295eaea33f645010 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20T=C3=B6nne?= Date: Tue, 4 Mar 2014 15:39:48 +0100 Subject: Changed mesh sample definition to use 3 vertex weights instead of a face index. This is easier to sample uniformly and avoids the need for tesselation for evaluating. --- source/blender/blenkernel/intern/mesh_sample.c | 62 ++++++++++++-------------- 1 file changed, 29 insertions(+), 33 deletions(-) (limited to 'source/blender/blenkernel/intern') diff --git a/source/blender/blenkernel/intern/mesh_sample.c b/source/blender/blenkernel/intern/mesh_sample.c index 51de927152a..c105ffab911 100644 --- a/source/blender/blenkernel/intern/mesh_sample.c +++ b/source/blender/blenkernel/intern/mesh_sample.c @@ -44,21 +44,21 @@ bool BKE_mesh_sample_eval(DerivedMesh *dm, const MSurfaceSample *sample, float loc[3], float nor[3]) { MVert *mverts = dm->getVertArray(dm); - MVert *v1, *v2, *v3, *v4; - MFace *mfaces = dm->getTessFaceArray(dm); - int totfaces = dm->getNumTessFaces(dm); - MFace *mface = &mfaces[sample->orig_face]; + int totverts = dm->getNumVerts(dm); + MVert *v1, *v2, *v3; float vnor[3]; zero_v3(loc); zero_v3(nor); - if (sample->orig_face >= totfaces) + if (sample->orig_verts[0] >= totverts || + sample->orig_verts[1] >= totverts || + sample->orig_verts[2] >= totverts) return false; - v1 = &mverts[mface->v1]; - v2 = &mverts[mface->v2]; - v3 = &mverts[mface->v3]; + v1 = &mverts[sample->orig_verts[0]]; + v2 = &mverts[sample->orig_verts[1]]; + v3 = &mverts[sample->orig_verts[2]]; madd_v3_v3fl(loc, v1->co, sample->orig_weights[0]); madd_v3_v3fl(loc, v2->co, sample->orig_weights[1]); @@ -71,15 +71,6 @@ bool BKE_mesh_sample_eval(DerivedMesh *dm, const MSurfaceSample *sample, float l normal_short_to_float_v3(vnor, v3->no); madd_v3_v3fl(nor, vnor, sample->orig_weights[2]); - if (mface->v4) { - v4 = &mverts[mface->v4]; - - madd_v3_v3fl(loc, v4->co, sample->orig_weights[3]); - - normal_short_to_float_v3(vnor, v4->no); - madd_v3_v3fl(nor, vnor, sample->orig_weights[3]); - } - normalize_v3(nor); return true; @@ -138,25 +129,30 @@ static void mesh_sample_surface_random(const MSurfaceSampleInfo *info, MSurfaceS MFace *mfaces = info->dm->getTessFaceArray(info->dm); int totfaces = info->dm->getNumTessFaces(info->dm); MFace *mface; - float sum, inv_sum; + float a, b; - sample->orig_face = BLI_rng_get_int(info->rng) % totfaces; + mface = &mfaces[BLI_rng_get_int(info->rng) % totfaces]; - mface = &mfaces[sample->orig_face]; - sample->orig_weights[0] = BLI_rng_get_float(info->rng); - sample->orig_weights[1] = BLI_rng_get_float(info->rng); - sample->orig_weights[2] = BLI_rng_get_float(info->rng); - sample->orig_weights[3] = mface->v4 ? BLI_rng_get_float(info->rng) : 0.0f; + if (mface->v4 && BLI_rng_get_int(info->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; + } - sum = sample->orig_weights[0] + - sample->orig_weights[1] + - sample->orig_weights[2] + - sample->orig_weights[3]; - inv_sum = sum > 0.0f ? 1.0f/sum : 0.0f; - sample->orig_weights[0] *= inv_sum; - sample->orig_weights[1] *= inv_sum; - sample->orig_weights[2] *= inv_sum; - sample->orig_weights[3] *= inv_sum; + a = BLI_rng_get_float(info->rng); + b = BLI_rng_get_float(info->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; } void BKE_mesh_sample_surface_array(const MSurfaceSampleInfo *info, MSurfaceSample *samples, int totsample) -- cgit v1.2.3 From 82132fc5b031b49b5d9f73c4732a11906be6cbc1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20T=C3=B6nne?= Date: Wed, 24 Sep 2014 15:58:53 +0200 Subject: Added generalized method for creating an array of mesh samples with arbitrary stride. --- source/blender/blenkernel/intern/mesh_sample.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'source/blender/blenkernel/intern') diff --git a/source/blender/blenkernel/intern/mesh_sample.c b/source/blender/blenkernel/intern/mesh_sample.c index c105ffab911..a1c3e71c8db 100644 --- a/source/blender/blenkernel/intern/mesh_sample.c +++ b/source/blender/blenkernel/intern/mesh_sample.c @@ -44,7 +44,7 @@ bool BKE_mesh_sample_eval(DerivedMesh *dm, const MSurfaceSample *sample, float loc[3], float nor[3]) { MVert *mverts = dm->getVertArray(dm); - int totverts = dm->getNumVerts(dm); + unsigned int totverts = (unsigned int)dm->getNumVerts(dm); MVert *v1, *v2, *v3; float vnor[3]; @@ -156,6 +156,11 @@ static void mesh_sample_surface_random(const MSurfaceSampleInfo *info, MSurfaceS } void BKE_mesh_sample_surface_array(const MSurfaceSampleInfo *info, MSurfaceSample *samples, int totsample) +{ + BKE_mesh_sample_surface_array_stride(info, samples, (int)sizeof(MSurfaceSample), totsample); +} + +void BKE_mesh_sample_surface_array_stride(const struct MSurfaceSampleInfo *info, struct MSurfaceSample *first, int stride, int totsample) { MSurfaceSample *sample; int i; @@ -163,7 +168,7 @@ void BKE_mesh_sample_surface_array(const MSurfaceSampleInfo *info, MSurfaceSampl switch (info->algorithm) { case MSS_RANDOM: { DM_ensure_tessface(info->dm); - for (sample = samples, i = 0; i < totsample; ++sample, ++i) + for (sample = first, i = 0; i < totsample; sample = (MSurfaceSample *)((char *)sample + stride), ++i) mesh_sample_surface_random(info, sample); break; } -- cgit v1.2.3 From 6783b15453688ab71a900ef98b9a4be1d91b7cb2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20T=C3=B6nne?= Date: Wed, 24 Sep 2014 17:01:56 +0200 Subject: Shifted the dispatch from the algorithm side to the storage side of the sampling system to keep the code simple. Now there is a MSurfaceSampleStorage struct that encodes the storage details, which the algorithms don't have to care about. --- source/blender/blenkernel/intern/mesh_sample.c | 131 ++++++++++--------------- 1 file changed, 54 insertions(+), 77 deletions(-) (limited to 'source/blender/blenkernel/intern') diff --git a/source/blender/blenkernel/intern/mesh_sample.c b/source/blender/blenkernel/intern/mesh_sample.c index a1c3e71c8db..99f512eb3fc 100644 --- a/source/blender/blenkernel/intern/mesh_sample.c +++ b/source/blender/blenkernel/intern/mesh_sample.c @@ -39,7 +39,7 @@ #include "BLI_strict_flags.h" -/* Evaluate */ +/* ==== Evaluate ==== */ bool BKE_mesh_sample_eval(DerivedMesh *dm, const MSurfaceSample *sample, float loc[3], float nor[3]) { @@ -77,100 +77,77 @@ bool BKE_mesh_sample_eval(DerivedMesh *dm, const MSurfaceSample *sample, float l } -/* Iterators */ +/* ==== Sampling ==== */ -#if 0 -static void mesh_sample_surface_array_iterator_next(MSurfaceSampleArrayIterator *iter) +static bool mesh_sample_store_array_sample(void *vdata, int capacity, int index, const MSurfaceSample *sample) { - ++iter->cur; - --iter->remaining; -} - -static bool mesh_sample_surface_array_iterator_valid(MSurfaceSampleArrayIterator *iter) -{ - return (iter->remaining > 0); -} - -static void mesh_sample_surface_array_iterator_free(MSurfaceSampleArrayIterator *iter) -{ -} - -void BKE_mesh_sample_surface_array_begin(MSurfaceSampleArrayIterator *iter, MSurfaceSample *array, int totarray) -{ - iter->cur = array; - iter->remaining = totarray; + MSurfaceSample *data = vdata; + if (index >= capacity) + return false; - iter->base.next = + data[index] = *sample; + return true; } -#endif - -/* Sampling */ - -void BKE_mesh_sample_info_random(MSurfaceSampleInfo *info, DerivedMesh *dm, unsigned int seed) +void BKE_mesh_sample_storage_array(MSurfaceSampleStorage *storage, MSurfaceSample *samples, int capacity) { - info->algorithm = MSS_RANDOM; - info->dm = dm; - - info->rng = BLI_rng_new(seed); + storage->store_sample = mesh_sample_store_array_sample; + storage->capacity = capacity; + storage->data = samples; + storage->free_data = false; } -void BKE_mesh_sample_info_release(MSurfaceSampleInfo *info) +void BKE_mesh_sample_storage_release(MSurfaceSampleStorage *storage) { - if (info->rng) { - BLI_rng_free(info->rng); - info->rng = NULL; - } + if (storage->free_data) + MEM_freeN(storage->data); } -static void mesh_sample_surface_random(const MSurfaceSampleInfo *info, MSurfaceSample *sample) +void BKE_mesh_sample_generate_random(MSurfaceSampleStorage *dst, DerivedMesh *dm, unsigned int seed, int totsample) { - MFace *mfaces = info->dm->getTessFaceArray(info->dm); - int totfaces = info->dm->getNumTessFaces(info->dm); + MFace *mfaces; + int totfaces; + RNG *rng; MFace *mface; float a, b; + int i; - mface = &mfaces[BLI_rng_get_int(info->rng) % totfaces]; - - if (mface->v4 && BLI_rng_get_int(info->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; - } + rng = BLI_rng_new(seed); - a = BLI_rng_get_float(info->rng); - b = BLI_rng_get_float(info->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; -} - -void BKE_mesh_sample_surface_array(const MSurfaceSampleInfo *info, MSurfaceSample *samples, int totsample) -{ - BKE_mesh_sample_surface_array_stride(info, samples, (int)sizeof(MSurfaceSample), totsample); -} - -void BKE_mesh_sample_surface_array_stride(const struct MSurfaceSampleInfo *info, struct MSurfaceSample *first, int stride, int totsample) -{ - MSurfaceSample *sample; - int i; + DM_ensure_tessface(dm); + mfaces = dm->getTessFaceArray(dm); + totfaces = dm->getNumTessFaces(dm); - switch (info->algorithm) { - case MSS_RANDOM: { - DM_ensure_tessface(info->dm); - for (sample = first, i = 0; i < totsample; sample = (MSurfaceSample *)((char *)sample + stride), ++i) - mesh_sample_surface_random(info, sample); - break; + 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)) + break; } + + BLI_rng_free(rng); } -- cgit v1.2.3 From 6078e79cea5bb450e98f8e07aab56a87eb37e7c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20T=C3=B6nne?= Date: Wed, 24 Sep 2014 17:35:10 +0200 Subject: Minor syntax fix. --- source/blender/blenkernel/intern/mesh_sample.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source/blender/blenkernel/intern') diff --git a/source/blender/blenkernel/intern/mesh_sample.c b/source/blender/blenkernel/intern/mesh_sample.c index 99f512eb3fc..d1493f33f8d 100644 --- a/source/blender/blenkernel/intern/mesh_sample.c +++ b/source/blender/blenkernel/intern/mesh_sample.c @@ -120,7 +120,7 @@ void BKE_mesh_sample_generate_random(MSurfaceSampleStorage *dst, DerivedMesh *dm totfaces = dm->getNumTessFaces(dm); for (i = 0; i < totsample; ++i) { - MSurfaceSample sample = {0}; + MSurfaceSample sample = {{0}}; mface = &mfaces[BLI_rng_get_int(rng) % totfaces]; -- cgit v1.2.3 From a9001adbb45c5774341fa2e8aa81006326a9cd82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20T=C3=B6nne?= Date: Mon, 24 Nov 2014 20:55:26 +0100 Subject: New edit mode for hair. Conflicts: source/blender/blenloader/intern/readfile.c --- source/blender/blenkernel/intern/context.c | 2 ++ source/blender/blenkernel/intern/particle.c | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) (limited to 'source/blender/blenkernel/intern') diff --git a/source/blender/blenkernel/intern/context.c b/source/blender/blenkernel/intern/context.c index 7142c092583..4aeb3af60ae 100644 --- a/source/blender/blenkernel/intern/context.c +++ b/source/blender/blenkernel/intern/context.c @@ -926,6 +926,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; } } @@ -949,6 +950,7 @@ static const char *data_mode_strings[] = { "vertexpaint", "imagepaint", "particlemode", + "hairmode", "objectmode", NULL }; diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c index 6c354c59d7a..afcf5e1068d 100644 --- a/source/blender/blenkernel/intern/particle.c +++ b/source/blender/blenkernel/intern/particle.c @@ -3095,7 +3095,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); -- cgit v1.2.3 From 7bb90a06e19ec8966f1400931e2111754ff1a1bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20T=C3=B6nne?= Date: Tue, 25 Nov 2014 09:04:09 +0100 Subject: Moved code for the hair edit data structures to blenkernel. This makes it work more like editmesh, and avoid the awkward and basically bad-level approach in particles, where the edit data is an anonymous pointer in particle systems together with a callback for freeing. Conflicts: source/blender/blenkernel/CMakeLists.txt --- source/blender/blenkernel/intern/edithair.c | 113 +++++++++++++ .../blender/blenkernel/intern/edithair_particles.c | 181 +++++++++++++++++++++ 2 files changed, 294 insertions(+) create mode 100644 source/blender/blenkernel/intern/edithair.c create mode 100644 source/blender/blenkernel/intern/edithair_particles.c (limited to 'source/blender/blenkernel/intern') diff --git a/source/blender/blenkernel/intern/edithair.c b/source/blender/blenkernel/intern/edithair.c new file mode 100644 index 00000000000..ec229b96a91 --- /dev/null +++ b/source/blender/blenkernel/intern/edithair.c @@ -0,0 +1,113 @@ +/* + * ***** 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/editors/hair/edithair.c + * \ingroup bke + */ + +#include "MEM_guardedalloc.h" + +#include "BLI_math.h" + +#include "BKE_edithair.h" + +HairEditData *BKE_edithair_create(void) +{ + HairEditData *hedit = MEM_callocN(sizeof(HairEditData), "hair edit data"); + return hedit; +} + +HairEditData *BKE_edithair_copy(HairEditData *hedit) +{ + HairEditData *thedit = MEM_dupallocN(hedit); + + if (hedit->curves) { + thedit->curves = MEM_dupallocN(hedit->curves); + } + + if (hedit->verts) { + thedit->verts = MEM_dupallocN(hedit->verts); + } + + return thedit; +} + +void BKE_edithair_free(HairEditData *hedit) +{ + if (hedit->curves) { + MEM_freeN(hedit->curves); + } + + if (hedit->verts) { + MEM_freeN(hedit->verts); + } + + MEM_freeN(hedit); +} + +void BKE_edithair_clear(HairEditData *hedit) +{ + if (hedit->curves) { + MEM_freeN(hedit->curves); + hedit->curves = NULL; + } + hedit->totcurves = 0; + hedit->alloc_curves = 0; + + if (hedit->verts) { + MEM_freeN(hedit->verts); + hedit->verts = NULL; + } + hedit->totverts = 0; + hedit->alloc_verts = 0; +} + +void BKE_edithair_reserve(HairEditData *hedit, int alloc_curves, int alloc_verts, bool shrink) +{ + if (!hedit) + return; + + if ((alloc_curves > hedit->alloc_curves) || (alloc_curves < hedit->alloc_curves && shrink)) { + size_t size_curves = sizeof(HairEditCurve) * alloc_curves; + if (hedit->curves) + hedit->curves = MEM_recallocN_id(hedit->curves, size_curves, "hair edit curves"); + else + hedit->curves = MEM_callocN(size_curves, "hair edit curves"); + hedit->alloc_curves = alloc_curves; + CLAMP_MAX(hedit->totcurves, alloc_curves); + } + + if ((alloc_verts > hedit->alloc_verts) || (alloc_verts < hedit->alloc_verts && shrink)) { + size_t size_verts = sizeof(HairEditVertex) * alloc_verts; + if (hedit->verts) + hedit->verts = MEM_recallocN_id(hedit->verts, size_verts, "hair edit verts"); + else + hedit->verts = MEM_callocN(size_verts, "hair edit verts"); + hedit->alloc_verts = alloc_verts; + CLAMP_MAX(hedit->totverts, alloc_verts); + } +} diff --git a/source/blender/blenkernel/intern/edithair_particles.c b/source/blender/blenkernel/intern/edithair_particles.c new file mode 100644 index 00000000000..215ba24265a --- /dev/null +++ b/source/blender/blenkernel/intern/edithair_particles.c @@ -0,0 +1,181 @@ +/* + * ***** 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/editors/hair/hair_particles.c + * \ingroup edhair + */ + +#include "MEM_guardedalloc.h" + +#include "BLI_math.h" + +#include "DNA_object_types.h" +#include "DNA_particle_types.h" + +#include "BKE_edithair.h" +#include "BKE_particle.h" + +/* ==== convert particle data to hair edit ==== */ + +static int particle_totverts(ParticleSystem *psys) +{ + ParticleData *pa; + int p; + int totverts = 0; + + for (p = 0, pa = psys->particles; p < psys->totpart; ++p, ++pa) + totverts += pa->totkey; + + return totverts; +} + +static void copy_edit_curve(HairEditData *hedit, HairEditCurve *curve, ParticleData *pa, int start) +{ + int totverts = pa->totkey; + HairKey *hair = pa->hair; + HairEditVertex *vert; + HairKey *hkey; + int k; + + BLI_assert(start + totverts <= hedit->alloc_verts); + + curve->start = start; + curve->numverts = totverts; + + for (k = 0, vert = hedit->verts + start, hkey = hair; + k < totverts; + ++k, ++vert, ++hkey) { + + copy_v3_v3(vert->co, hkey->co); + // TODO define other key stuff ... + } +} + +void BKE_edithair_from_particles(HairEditData *hedit, Object *UNUSED(ob), ParticleSystem *psys) +{ + int totverts = particle_totverts(psys); + + HairEditCurve *curve; + int i; + ParticleData *pa; + int p; + int vert_start; + + BKE_edithair_clear(hedit); + + BKE_edithair_reserve(hedit, psys->totpart, totverts, true); + + /* TODO we should have a clean input stream API for hair edit data + * to avoid implicit size and index calculations here and make the code + * as fool proof as possible. + */ + + hedit->totcurves = psys->totpart; + hedit->totverts = totverts; + + vert_start = 0; + for (i = 0, curve = hedit->curves, p = 0, pa = psys->particles; + i < hedit->totcurves; + ++i, ++curve, ++p, ++pa) { + + copy_edit_curve(hedit, curve, pa, vert_start); + + // TODO copy particle stuff ... + + vert_start += curve->numverts; + } +} + +/* ==== convert hair edit to particle data ==== */ + +static void free_particle_data(ParticleSystem *psys) +{ + if (psys->particles) { + ParticleData *pa; + int p; + + for (p = 0, pa = psys->particles; p < psys->totpart; ++p, ++pa) { + if (pa->hair) + MEM_freeN(pa->hair); + } + + MEM_freeN(psys->particles); + psys->particles = NULL; + psys->totpart = 0; + } +} + +static void create_particle_curve(ParticleData *pa, HairEditData *hedit, HairEditCurve *curve) +{ + int ntotkey = curve->numverts; + HairKey *nhair = MEM_callocN(sizeof(HairKey) * ntotkey, "hair keys"); + HairEditVertex *vert; + HairKey *hkey; + int k; + + for (k = 0, vert = hedit->verts + curve->start, hkey = nhair; + k < curve->numverts; + ++k, ++vert, ++hkey) { + + copy_v3_v3(hkey->co, vert->co); + // TODO define other key stuff ... + } + + pa->totkey = ntotkey; + pa->hair = nhair; +} + +static void create_particle_data(ParticleSystem *psys, HairEditData *hedit) +{ + int ntotpart = hedit->totcurves; + ParticleData *nparticles = MEM_callocN(sizeof(ParticleData) * ntotpart, "particle data"); + HairEditCurve *curve; + int i; + ParticleData *pa; + int p; + + for (i = 0, curve = hedit->curves, p = 0, pa = nparticles; + i < hedit->totcurves; + ++i, ++curve, ++p, ++pa) { + + // TODO copy particle stuff ... + + create_particle_curve(pa, hedit, curve); + } + + psys->particles = nparticles; + psys->totpart = hedit->totcurves; +} + +void BKE_edithair_to_particles(HairEditData *hedit, Object *UNUSED(ob), ParticleSystem *psys) +{ + psys->flag |= PSYS_EDITED; + + free_particle_data(psys); + + create_particle_data(psys, hedit); +} -- cgit v1.2.3 From 1c7053f7a0529d4087cd820139ccbb37bd0bf56a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20T=C3=B6nne?= Date: Tue, 25 Nov 2014 09:30:59 +0100 Subject: Store hair edit data in particle systems and manage it in the operator for entering/exiting the edit mode. Conflicts: source/blender/blenkernel/intern/particle.c --- source/blender/blenkernel/intern/edithair_particles.c | 3 --- source/blender/blenkernel/intern/object.c | 1 + source/blender/blenkernel/intern/particle.c | 3 +++ 3 files changed, 4 insertions(+), 3 deletions(-) (limited to 'source/blender/blenkernel/intern') diff --git a/source/blender/blenkernel/intern/edithair_particles.c b/source/blender/blenkernel/intern/edithair_particles.c index 215ba24265a..463af02cf56 100644 --- a/source/blender/blenkernel/intern/edithair_particles.c +++ b/source/blender/blenkernel/intern/edithair_particles.c @@ -173,9 +173,6 @@ static void create_particle_data(ParticleSystem *psys, HairEditData *hedit) void BKE_edithair_to_particles(HairEditData *hedit, Object *UNUSED(ob), ParticleSystem *psys) { - psys->flag |= PSYS_EDITED; - free_particle_data(psys); - create_particle_data(psys, hedit); } diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c index f14f72614f4..304275d2b1a 100644 --- a/source/blender/blenkernel/intern/object.c +++ b/source/blender/blenkernel/intern/object.c @@ -1321,6 +1321,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/particle.c b/source/blender/blenkernel/intern/particle.c index afcf5e1068d..1adfff34d6a 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_edithair.h" #include "BKE_effect.h" #include "BKE_global.h" #include "BKE_group.h" @@ -546,6 +547,8 @@ void psys_free(Object *ob, ParticleSystem *psys) if (psys->edit && psys->free_edit) psys->free_edit(psys->edit); + if (psys->hairedit) + BKE_edithair_free(psys->hairedit); if (psys->child) { MEM_freeN(psys->child); -- cgit v1.2.3 From f1e4d35489f74983113d42abc652632408edff25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20T=C3=B6nne?= Date: Tue, 25 Nov 2014 14:39:07 +0100 Subject: Reconstruct most basic particle data when applying the hair edit, so particle hairs remain visible. Note that currently the hair root location (num/num_dmcache, fuv, foffset) is not stored from edit data, so all hairs end up in a default location. --- .../blender/blenkernel/intern/edithair_particles.c | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) (limited to 'source/blender/blenkernel/intern') diff --git a/source/blender/blenkernel/intern/edithair_particles.c b/source/blender/blenkernel/intern/edithair_particles.c index 463af02cf56..8465edcda63 100644 --- a/source/blender/blenkernel/intern/edithair_particles.c +++ b/source/blender/blenkernel/intern/edithair_particles.c @@ -71,6 +71,7 @@ static void copy_edit_curve(HairEditData *hedit, HairEditCurve *curve, ParticleD ++k, ++vert, ++hkey) { copy_v3_v3(vert->co, hkey->co); + // TODO define other key stuff ... } } @@ -129,7 +130,7 @@ static void free_particle_data(ParticleSystem *psys) } } -static void create_particle_curve(ParticleData *pa, HairEditData *hedit, HairEditCurve *curve) +static void create_particle_curve(ParticleSystem *psys, ParticleData *pa, HairEditData *hedit, HairEditCurve *curve) { int ntotkey = curve->numverts; HairKey *nhair = MEM_callocN(sizeof(HairKey) * ntotkey, "hair keys"); @@ -137,11 +138,27 @@ static void create_particle_curve(ParticleData *pa, HairEditData *hedit, HairEdi HairKey *hkey; int k; + pa->alive = PARS_ALIVE; + pa->flag = 0; + + pa->time = 0.0f; + pa->lifetime = 100.0f; + pa->dietime = 100.0f; + + pa->fuv[0] = 1.0f; + pa->fuv[1] = 0.0f; + pa->fuv[2] = 0.0f; + pa->fuv[3] = 0.0f; + + pa->size = psys->part->size; + for (k = 0, vert = hedit->verts + curve->start, hkey = nhair; k < curve->numverts; ++k, ++vert, ++hkey) { copy_v3_v3(hkey->co, vert->co); + hkey->time = ntotkey > 0 ? (float)k / (float)(ntotkey - 1) : 0.0f; + hkey->weight = 1.0f; // TODO define other key stuff ... } @@ -164,7 +181,7 @@ static void create_particle_data(ParticleSystem *psys, HairEditData *hedit) // TODO copy particle stuff ... - create_particle_curve(pa, hedit, curve); + create_particle_curve(psys, pa, hedit, curve); } psys->particles = nparticles; -- cgit v1.2.3 From afb947c00c134671c8203bf1a69c46aea92230ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20T=C3=B6nne?= Date: Wed, 26 Nov 2014 20:11:38 +0100 Subject: Switched the hair edit data to a bmesh-like structure for consistency. This means using mempools to store curve and vertex data, which allows arbitrary addition and removal of data more easily. Also this includes an iterator system similar to bmesh iterators (although the simpler topology makes it a lot less complex). Conflicts: source/blender/blenkernel/intern/customdata.c source/blender/makesdna/DNA_customdata_types.h --- source/blender/blenkernel/intern/customdata.c | 5 + source/blender/blenkernel/intern/edithair.c | 236 +++++++++++++++++---- source/blender/blenkernel/intern/edithair_inline.h | 154 ++++++++++++++ .../blender/blenkernel/intern/edithair_particles.c | 78 +++---- 4 files changed, 376 insertions(+), 97 deletions(-) create mode 100644 source/blender/blenkernel/intern/edithair_inline.h (limited to 'source/blender/blenkernel/intern') diff --git a/source/blender/blenkernel/intern/customdata.c b/source/blender/blenkernel/intern/customdata.c index add6bb0fd0b..baf6639d2cf 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_edithair.h" #include "BKE_global.h" #include "BKE_main.h" #include "BKE_mesh_mapping.h" @@ -1312,6 +1313,10 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = { {sizeof(short[4][3]), "", 0, NULL, NULL, NULL, NULL, layerSwap_flnor, NULL}, /* 41: CD_CUSTOMLOOPNORMAL */ {sizeof(short[2]), "vec2s", 1, NULL, NULL, NULL, NULL, NULL, NULL}, + /* 42: CD_HAIR_CURVE */ + {sizeof(HairEditCurve), "HairEditCurve", 1, NULL, NULL, NULL, NULL, NULL, NULL}, + /* 43: CD_HAIR_VERT */ + {sizeof(HairEditVertex), "HairEditVertex", 1, NULL, NULL, NULL, NULL, NULL, NULL}, }; /* note, numbers are from trunk and need updating for bmesh */ diff --git a/source/blender/blenkernel/intern/edithair.c b/source/blender/blenkernel/intern/edithair.c index ec229b96a91..af0ea4ecb44 100644 --- a/source/blender/blenkernel/intern/edithair.c +++ b/source/blender/blenkernel/intern/edithair.c @@ -32,82 +32,226 @@ #include "MEM_guardedalloc.h" #include "BLI_math.h" +#include "BLI_mempool.h" +#include "DNA_customdata_types.h" + +#include "BKE_customdata.h" #include "BKE_edithair.h" +static const int chunksize_default_totcurve = 512; +static const int allocsize_default_totcurve = 512; + +static const int chunksize_default_totvert = 1024; +static const int allocsize_default_totvert = 1024; + +static void edithair_mempool_init(HairEditData *hedit) +{ + hedit->cpool = BLI_mempool_create(sizeof(HairEditCurve), allocsize_default_totcurve, + chunksize_default_totcurve, BLI_MEMPOOL_ALLOW_ITER); + hedit->vpool = BLI_mempool_create(sizeof(HairEditVertex), allocsize_default_totvert, + chunksize_default_totvert, BLI_MEMPOOL_ALLOW_ITER); +} + HairEditData *BKE_edithair_create(void) { HairEditData *hedit = MEM_callocN(sizeof(HairEditData), "hair edit data"); + + edithair_mempool_init(hedit); + + CustomData_reset(&hedit->cdata); + CustomData_reset(&hedit->vdata); + return hedit; } -HairEditData *BKE_edithair_copy(HairEditData *hedit) +void BKE_edithair_data_free(HairEditData *hedit) { - HairEditData *thedit = MEM_dupallocN(hedit); - - if (hedit->curves) { - thedit->curves = MEM_dupallocN(hedit->curves); + if (CustomData_bmesh_has_free(&(hedit->cdata))) { + HairEditCurve *curve; + HairEditIter iter; + HAIREDIT_ITER(curve, &iter, hedit, HAIREDIT_CURVES_OF_MESH) { + CustomData_bmesh_free_block(&hedit->cdata, &curve->data); + } } - if (hedit->verts) { - thedit->verts = MEM_dupallocN(hedit->verts); + if (CustomData_bmesh_has_free(&(hedit->vdata))) { + HairEditVertex *vert; + HairEditIter iter; + HAIREDIT_ITER(vert, &iter, hedit, HAIREDIT_VERTS_OF_MESH) { + CustomData_bmesh_free_block(&hedit->vdata, &vert->data); + } } - return thedit; + /* Free custom data pools, This should probably go in CustomData_free? */ + if (hedit->cdata.totlayer) BLI_mempool_destroy(hedit->cdata.pool); + if (hedit->vdata.totlayer) BLI_mempool_destroy(hedit->vdata.pool); + + /* free custom data */ + CustomData_free(&hedit->cdata, 0); + CustomData_free(&hedit->vdata, 0); + + /* destroy element pools */ + BLI_mempool_destroy(hedit->cpool); + BLI_mempool_destroy(hedit->vpool); +} + +void BKE_edithair_clear(HairEditData *hedit) +{ + /* free old data */ + BKE_edithair_data_free(hedit); + memset(hedit, 0, sizeof(HairEditData)); + + /* allocate the memory pools for the hair elements */ + edithair_mempool_init(hedit); + + CustomData_reset(&hedit->cdata); + CustomData_reset(&hedit->vdata); } void BKE_edithair_free(HairEditData *hedit) { - if (hedit->curves) { - MEM_freeN(hedit->curves); - } - - if (hedit->verts) { - MEM_freeN(hedit->verts); - } + BKE_edithair_data_free(hedit); MEM_freeN(hedit); } -void BKE_edithair_clear(HairEditData *hedit) +void BKE_edithair_get_min_max(HairEditData *hedit, float r_min[3], float r_max[3]) { - if (hedit->curves) { - MEM_freeN(hedit->curves); - hedit->curves = NULL; + if (hedit->totverts) { + HairEditVertex *vert; + HairEditIter iter; + + INIT_MINMAX(r_min, r_max); + + HAIREDIT_ITER(vert, &iter, hedit, HAIREDIT_VERTS_OF_MESH) { + minmax_v3v3_v3(r_min, r_max, vert->co); + } } - hedit->totcurves = 0; - hedit->alloc_curves = 0; - - if (hedit->verts) { - MEM_freeN(hedit->verts); - hedit->verts = NULL; + else { + zero_v3(r_min); + zero_v3(r_max); + } +} + +HairEditCurve *BKE_edithair_curve_create(HairEditData *hedit, HairEditCurve *example) +{ + HairEditCurve *c = NULL; + + c = BLI_mempool_alloc(hedit->cpool); + + /* --- assign all members --- */ + c->data = NULL; + + c->v = NULL; + /* --- done --- */ + + hedit->totcurves++; + + if (example) { + CustomData_bmesh_copy_data(&hedit->cdata, &hedit->cdata, example->data, &c->data); + } + else { + CustomData_bmesh_set_default(&hedit->cdata, &c->data); } - hedit->totverts = 0; - hedit->alloc_verts = 0; + + return c; } -void BKE_edithair_reserve(HairEditData *hedit, int alloc_curves, int alloc_verts, bool shrink) +int BKE_edithair_curve_vertex_count(HairEditData *UNUSED(hedit), HairEditCurve *c) { - if (!hedit) - return; + const HairEditVertex *v; + int count = 0; + for (v = c->v; v; v = v->next) { + ++count; + } + return count; +} + +static HairEditVertex *edithair_vertex_create(HairEditData *hedit, HairEditVertex *example) +{ + HairEditVertex *v = NULL; + + v = BLI_mempool_alloc(hedit->vpool); + + /* --- assign all members --- */ + v->data = NULL; + + v->next = v->prev = NULL; + /* --- done --- */ + + hedit->totverts++; + + if (example) { + CustomData_bmesh_copy_data(&hedit->vdata, &hedit->vdata, example->data, &v->data); + } + else { + CustomData_bmesh_set_default(&hedit->vdata, &v->data); + } + + return v; +} + +HairEditVertex *BKE_edithair_curve_extend(HairEditData *hedit, HairEditCurve *c, HairEditVertex *example, int num) +{ + HairEditVertex *v_first = NULL; + int i; - if ((alloc_curves > hedit->alloc_curves) || (alloc_curves < hedit->alloc_curves && shrink)) { - size_t size_curves = sizeof(HairEditCurve) * alloc_curves; - if (hedit->curves) - hedit->curves = MEM_recallocN_id(hedit->curves, size_curves, "hair edit curves"); - else - hedit->curves = MEM_callocN(size_curves, "hair edit curves"); - hedit->alloc_curves = alloc_curves; - CLAMP_MAX(hedit->totcurves, alloc_curves); + for (i = 0; i < num; ++i) { + HairEditVertex *v = edithair_vertex_create(hedit, example); + if (i == 0) + v_first = v; + + v->prev = c->v; + if (c->v) + c->v->next = v; + c->v = v; } - if ((alloc_verts > hedit->alloc_verts) || (alloc_verts < hedit->alloc_verts && shrink)) { - size_t size_verts = sizeof(HairEditVertex) * alloc_verts; - if (hedit->verts) - hedit->verts = MEM_recallocN_id(hedit->verts, size_verts, "hair edit verts"); - else - hedit->verts = MEM_callocN(size_verts, "hair edit verts"); - hedit->alloc_verts = alloc_verts; - CLAMP_MAX(hedit->totverts, alloc_verts); + return v_first; +} + +/* ==== Iterators ==== */ + +/* + * CURVE OF MESH CALLBACKS + */ + +void hairedit_iter__elem_of_mesh_begin(struct HairEditIter__elem_of_mesh *iter) +{ + BLI_mempool_iternew(iter->pooliter.pool, &iter->pooliter); +} + +void *hairedit_iter__elem_of_mesh_step(struct HairEditIter__elem_of_mesh *iter) +{ + return BLI_mempool_iterstep(&iter->pooliter); +} + +/* + * VERT OF CURVE CALLBACKS + */ + +void hairedit_iter__vert_of_curve_begin(struct HairEditIter__vert_of_curve *iter) +{ + if (iter->cdata->v) { + iter->v_first = iter->cdata->v; + iter->v_next = iter->cdata->v; + } + else { + iter->v_first = NULL; + iter->v_next = NULL; } } + +void *hairedit_iter__vert_of_curve_step(struct HairEditIter__vert_of_curve *iter) +{ + HairEditVertex *v_curr = iter->v_next; + + if (iter->v_next) { + iter->v_next = iter->v_next->next; + } + + return v_curr; +} + +/* =================== */ diff --git a/source/blender/blenkernel/intern/edithair_inline.h b/source/blender/blenkernel/intern/edithair_inline.h new file mode 100644 index 00000000000..a95162c6e07 --- /dev/null +++ b/source/blender/blenkernel/intern/edithair_inline.h @@ -0,0 +1,154 @@ +/* + * ***** 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 ***** + */ + +#ifndef __EDITHAIR_INLINE_H__ +#define __EDITHAIR_INLINE_H__ + +/** \file blender/editors/hair/edithair_inline.h + * \ingroup bke + */ + +#include "BLI_mempool.h" +#include "BLI_utildefines.h" + +#include "BKE_edithair.h" + +/* iterator type structs */ +struct HairEditIter__elem_of_mesh { + BLI_mempool_iter pooliter; +}; +struct HairEditIter__vert_of_curve { + HairEditCurve *cdata; + HairEditVertex *v_first, *v_next; +}; + +typedef void (*HairEditIter__begin_cb) (void *); +typedef void *(*HairEditIter__step_cb) (void *); + +typedef struct HairEditIter { + /* keep union first */ + union { + struct HairEditIter__elem_of_mesh elem_of_mesh; + struct HairEditIter__vert_of_curve vert_of_curve; + } data; + + HairEditIter__begin_cb begin; + HairEditIter__step_cb step; + + int count; /* note, only some iterators set this, don't rely on it */ + char itype; +} HairEditIter; + +#define HAIREDIT_ITER_CB_DEF(name) \ + struct HairEditIter__##name; \ + void hairedit_iter__##name##_begin(struct HairEditIter__##name *iter); \ + void *hairedit_iter__##name##_step(struct HairEditIter__##name *iter) + +HAIREDIT_ITER_CB_DEF(elem_of_mesh); +HAIREDIT_ITER_CB_DEF(vert_of_curve); + +#undef HAIREDIT_ITER_CB_DEF + +/* inline here optimizes out the switch statement when called with + * constant values (which is very common), nicer for loop-in-loop situations */ + +/** + * \brief Iterator Step + * + * Calls an iterators step function to return the next element. + */ +BLI_INLINE void *HairEdit_iter_step(HairEditIter *iter) +{ + return iter->step(iter); +} + +/** + * \brief Iterator Init + * + * Takes a hair iterator structure and fills + * it with the appropriate function pointers based + * upon its type. + */ +BLI_INLINE bool HairEdit_iter_init(HairEditIter *iter, HairEditData *hedit, const char itype, void *data) +{ + /* int argtype; */ + iter->itype = itype; + + /* inlining optimizes out this switch when called with the defined type */ + switch ((HairEditIterType)itype) { + case HAIREDIT_CURVES_OF_MESH: + BLI_assert(hedit != NULL); + BLI_assert(data == NULL); + iter->begin = (HairEditIter__begin_cb)hairedit_iter__elem_of_mesh_begin; + iter->step = (HairEditIter__step_cb)hairedit_iter__elem_of_mesh_step; + iter->data.elem_of_mesh.pooliter.pool = hedit->cpool; + break; + case HAIREDIT_VERTS_OF_MESH: + BLI_assert(hedit != NULL); + BLI_assert(data == NULL); + iter->begin = (HairEditIter__begin_cb)hairedit_iter__elem_of_mesh_begin; + iter->step = (HairEditIter__step_cb)hairedit_iter__elem_of_mesh_step; + iter->data.elem_of_mesh.pooliter.pool = hedit->vpool; + break; + case HAIREDIT_VERTS_OF_CURVE: + BLI_assert(data != NULL); + iter->begin = (HairEditIter__begin_cb)hairedit_iter__vert_of_curve_begin; + iter->step = (HairEditIter__step_cb)hairedit_iter__vert_of_curve_step; + iter->data.vert_of_curve.cdata = (HairEditCurve *)data; + break; + default: + /* should never happen */ + BLI_assert(0); + return false; + break; + } + + iter->begin(iter); + + return true; +} + +/** + * \brief Iterator New + * + * Takes a bmesh iterator structure and fills + * it with the appropriate function pointers based + * upon its type and then calls BMeshIter_step() + * to return the first element of the iterator. + * + */ +BLI_INLINE void *HairEdit_iter_new(HairEditIter *iter, HairEditData *hedit, const char itype, void *data) +{ + if (LIKELY(HairEdit_iter_init(iter, hedit, itype, data))) { + return HairEdit_iter_step(iter); + } + else { + return NULL; + } +} + +#endif diff --git a/source/blender/blenkernel/intern/edithair_particles.c b/source/blender/blenkernel/intern/edithair_particles.c index 8465edcda63..667d0b4515c 100644 --- a/source/blender/blenkernel/intern/edithair_particles.c +++ b/source/blender/blenkernel/intern/edithair_particles.c @@ -41,34 +41,17 @@ /* ==== convert particle data to hair edit ==== */ -static int particle_totverts(ParticleSystem *psys) -{ - ParticleData *pa; - int p; - int totverts = 0; - - for (p = 0, pa = psys->particles; p < psys->totpart; ++p, ++pa) - totverts += pa->totkey; - - return totverts; -} - -static void copy_edit_curve(HairEditData *hedit, HairEditCurve *curve, ParticleData *pa, int start) +static void copy_edit_curve(HairEditData *hedit, HairEditCurve *curve, ParticleData *pa) { int totverts = pa->totkey; - HairKey *hair = pa->hair; HairEditVertex *vert; HairKey *hkey; int k; - BLI_assert(start + totverts <= hedit->alloc_verts); - - curve->start = start; - curve->numverts = totverts; - - for (k = 0, vert = hedit->verts + start, hkey = hair; + vert = BKE_edithair_curve_extend(hedit, curve, NULL, totverts); + for (k = 0, hkey = pa->hair; k < totverts; - ++k, ++vert, ++hkey) { + ++k, ++hkey, vert = vert->next) { copy_v3_v3(vert->co, hkey->co); @@ -78,36 +61,21 @@ static void copy_edit_curve(HairEditData *hedit, HairEditCurve *curve, ParticleD void BKE_edithair_from_particles(HairEditData *hedit, Object *UNUSED(ob), ParticleSystem *psys) { - int totverts = particle_totverts(psys); - HairEditCurve *curve; - int i; ParticleData *pa; int p; - int vert_start; BKE_edithair_clear(hedit); - BKE_edithair_reserve(hedit, psys->totpart, totverts, true); - - /* TODO we should have a clean input stream API for hair edit data - * to avoid implicit size and index calculations here and make the code - * as fool proof as possible. - */ - - hedit->totcurves = psys->totpart; - hedit->totverts = totverts; - - vert_start = 0; - for (i = 0, curve = hedit->curves, p = 0, pa = psys->particles; - i < hedit->totcurves; - ++i, ++curve, ++p, ++pa) { + for (p = 0, pa = psys->particles; + p < psys->totpart; + ++p, ++pa) { - copy_edit_curve(hedit, curve, pa, vert_start); + curve = BKE_edithair_curve_create(hedit, NULL); - // TODO copy particle stuff ... + copy_edit_curve(hedit, curve, pa); - vert_start += curve->numverts; + // TODO copy particle stuff ... } } @@ -132,8 +100,10 @@ static void free_particle_data(ParticleSystem *psys) static void create_particle_curve(ParticleSystem *psys, ParticleData *pa, HairEditData *hedit, HairEditCurve *curve) { - int ntotkey = curve->numverts; + int ntotkey = BKE_edithair_curve_vertex_count(hedit, curve); HairKey *nhair = MEM_callocN(sizeof(HairKey) * ntotkey, "hair keys"); + + HairEditIter iter; HairEditVertex *vert; HairKey *hkey; int k; @@ -152,14 +122,16 @@ static void create_particle_curve(ParticleSystem *psys, ParticleData *pa, HairEd pa->size = psys->part->size; - for (k = 0, vert = hedit->verts + curve->start, hkey = nhair; - k < curve->numverts; - ++k, ++vert, ++hkey) { - + k = 0; + hkey = nhair; + HAIREDIT_ITER_ELEM(vert, &iter, curve, HAIREDIT_VERTS_OF_CURVE) { copy_v3_v3(hkey->co, vert->co); hkey->time = ntotkey > 0 ? (float)k / (float)(ntotkey - 1) : 0.0f; hkey->weight = 1.0f; // TODO define other key stuff ... + + ++k; + ++hkey; } pa->totkey = ntotkey; @@ -170,18 +142,22 @@ static void create_particle_data(ParticleSystem *psys, HairEditData *hedit) { int ntotpart = hedit->totcurves; ParticleData *nparticles = MEM_callocN(sizeof(ParticleData) * ntotpart, "particle data"); + HairEditCurve *curve; - int i; + HairEditIter iter; ParticleData *pa; int p; - for (i = 0, curve = hedit->curves, p = 0, pa = nparticles; - i < hedit->totcurves; - ++i, ++curve, ++p, ++pa) { + p = 0; + pa = nparticles; + HAIREDIT_ITER(curve, &iter, hedit, HAIREDIT_CURVES_OF_MESH) { // TODO copy particle stuff ... create_particle_curve(psys, pa, hedit, curve); + + ++p; + ++pa; } psys->particles = nparticles; -- cgit v1.2.3 From b0a9e48a19788145bf6c6a19ca080af7dec97614 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20T=C3=B6nne?= Date: Thu, 27 Nov 2014 09:35:54 +0100 Subject: New customdata type for mesh surface samples. Conflicts: source/blender/makesdna/DNA_customdata_types.h --- source/blender/blenkernel/intern/customdata.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'source/blender/blenkernel/intern') diff --git a/source/blender/blenkernel/intern/customdata.c b/source/blender/blenkernel/intern/customdata.c index baf6639d2cf..a05082a5873 100644 --- a/source/blender/blenkernel/intern/customdata.c +++ b/source/blender/blenkernel/intern/customdata.c @@ -1317,6 +1317,8 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = { {sizeof(HairEditCurve), "HairEditCurve", 1, NULL, NULL, NULL, NULL, NULL, NULL}, /* 43: CD_HAIR_VERT */ {sizeof(HairEditVertex), "HairEditVertex", 1, NULL, NULL, NULL, NULL, NULL, NULL}, + /* 44: CD_MESH_SAMPLE */ + {sizeof(MSurfaceSample), "MSurfaceSample", 1, NULL, NULL, NULL, NULL, NULL, NULL}, }; /* note, numbers are from trunk and need updating for bmesh */ -- cgit v1.2.3 From 5f44f4a2ffcbe7ab12aa02aac7ed22471d6807f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20T=C3=B6nne?= Date: Thu, 27 Nov 2014 19:18:46 +0100 Subject: Intermediate commit: switching strand edit data to BMesh. Hair/Strand editing will only use a subset of the bmesh topology and expect a specific topology that needs to be verified and enforced. However, this extra requirement is much less work than reimplementing a whole edit data system with the same feature set as bmesh and avoids much redundant code. Conflicts: source/blender/blenkernel/intern/customdata.c source/blender/makesdna/DNA_customdata_types.h --- source/blender/blenkernel/intern/customdata.c | 6 +--- source/blender/blenkernel/intern/edithair.c | 36 ++++++++++++++++++++++ .../blender/blenkernel/intern/edithair_particles.c | 25 +++++++++++++++ source/blender/blenkernel/intern/particle.c | 2 +- 4 files changed, 63 insertions(+), 6 deletions(-) (limited to 'source/blender/blenkernel/intern') diff --git a/source/blender/blenkernel/intern/customdata.c b/source/blender/blenkernel/intern/customdata.c index a05082a5873..5fa778b8ee1 100644 --- a/source/blender/blenkernel/intern/customdata.c +++ b/source/blender/blenkernel/intern/customdata.c @@ -1313,11 +1313,7 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = { {sizeof(short[4][3]), "", 0, NULL, NULL, NULL, NULL, layerSwap_flnor, NULL}, /* 41: CD_CUSTOMLOOPNORMAL */ {sizeof(short[2]), "vec2s", 1, NULL, NULL, NULL, NULL, NULL, NULL}, - /* 42: CD_HAIR_CURVE */ - {sizeof(HairEditCurve), "HairEditCurve", 1, NULL, NULL, NULL, NULL, NULL, NULL}, - /* 43: CD_HAIR_VERT */ - {sizeof(HairEditVertex), "HairEditVertex", 1, NULL, NULL, NULL, NULL, NULL, NULL}, - /* 44: CD_MESH_SAMPLE */ + /* 42: CD_MESH_SAMPLE */ {sizeof(MSurfaceSample), "MSurfaceSample", 1, NULL, NULL, NULL, NULL, NULL, NULL}, }; diff --git a/source/blender/blenkernel/intern/edithair.c b/source/blender/blenkernel/intern/edithair.c index af0ea4ecb44..30d1a111620 100644 --- a/source/blender/blenkernel/intern/edithair.c +++ b/source/blender/blenkernel/intern/edithair.c @@ -39,6 +39,41 @@ #include "BKE_customdata.h" #include "BKE_edithair.h" +BMEditStrands *BKE_editstrands_create(BMesh *bm) +{ + BMEditStrands *es = MEM_callocN(sizeof(BMEditStrands), __func__); + + es->bm = bm; + + return es; +} + +BMEditStrands *BKE_editstrands_copy(BMEditStrands *em) +{ + BMEditStrands *es_copy = MEM_callocN(sizeof(BMEditStrands), __func__); + *es_copy = *em; + + es_copy->bm = BM_mesh_copy(em->bm); + + return es_copy; +} + +void BKE_editstrands_update_linked_customdata(BMEditStrands *em) +{ + BMesh *bm = em->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 *em) +{ + if (em->bm) + BM_mesh_free(em->bm); +} + +#if 0 static const int chunksize_default_totcurve = 512; static const int allocsize_default_totcurve = 512; @@ -255,3 +290,4 @@ void *hairedit_iter__vert_of_curve_step(struct HairEditIter__vert_of_curve *ite } /* =================== */ +#endif diff --git a/source/blender/blenkernel/intern/edithair_particles.c b/source/blender/blenkernel/intern/edithair_particles.c index 667d0b4515c..785ee00d0e7 100644 --- a/source/blender/blenkernel/intern/edithair_particles.c +++ b/source/blender/blenkernel/intern/edithair_particles.c @@ -39,6 +39,30 @@ #include "BKE_edithair.h" #include "BKE_particle.h" +#include "intern/bmesh_strands_conv.h" + +BMesh *BKE_particles_to_bmesh(Object *UNUSED(ob), ParticleSystem *psys) +{ + BMesh *bm; + const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_PSYS(psys); + + bm = BM_mesh_create(&allocsize); + + BM_strands_bm_from_psys(bm, psys, true, psys->shapenr); + + return bm; +} + +void BKE_particles_from_bmesh(Object *UNUSED(ob), ParticleSystem *psys) +{ + BMesh *bm = psys->hairedit ? psys->hairedit->bm : NULL; + + if (bm) + BM_strands_bm_to_psys(bm, psys); +} + + +#if 0 /* ==== convert particle data to hair edit ==== */ static void copy_edit_curve(HairEditData *hedit, HairEditCurve *curve, ParticleData *pa) @@ -169,3 +193,4 @@ void BKE_edithair_to_particles(HairEditData *hedit, Object *UNUSED(ob), Particle free_particle_data(psys); create_particle_data(psys, hedit); } +#endif diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c index 1adfff34d6a..b529d39c561 100644 --- a/source/blender/blenkernel/intern/particle.c +++ b/source/blender/blenkernel/intern/particle.c @@ -548,7 +548,7 @@ void psys_free(Object *ob, ParticleSystem *psys) if (psys->edit && psys->free_edit) psys->free_edit(psys->edit); if (psys->hairedit) - BKE_edithair_free(psys->hairedit); + BKE_editstrands_free(psys->hairedit); if (psys->child) { MEM_freeN(psys->child); -- cgit v1.2.3 From 991ee8a57094dda66338966a2ef9e26185645ab5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20T=C3=B6nne?= Date: Fri, 28 Nov 2014 10:17:29 +0100 Subject: First customdata layer for particle mass. This is more for testing purposes, since currently there is only a single mass property for the psys as a whole. This should change in the future though, to allow variable mass per strand or vertex. Conflicts: source/blender/bmesh/intern/bmesh_interp.c --- source/blender/blenkernel/intern/customdata.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'source/blender/blenkernel/intern') diff --git a/source/blender/blenkernel/intern/customdata.c b/source/blender/blenkernel/intern/customdata.c index 5fa778b8ee1..a5eb2c80760 100644 --- a/source/blender/blenkernel/intern/customdata.c +++ b/source/blender/blenkernel/intern/customdata.c @@ -2829,6 +2829,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); -- cgit v1.2.3 From dc43df89cd0514adad2e66e155d0894b7cdfc3b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20T=C3=B6nne?= Date: Fri, 28 Nov 2014 12:42:50 +0100 Subject: CustomData layer for storing hair root locations as MSurfaceSamples. This requires converting the old messy particle num/num_dmcache/fuv/foffset data into the new mesh samples, which can potentially introduce floating point errors and inaccuracies due to lack of face index mapping in the new system. However, in any well-constructed particle system the hair roots should be nearest to their num face, so mapping would be accurate enough. If necessary face index data could be added to samples as a legacy code hack, but probably it's best to eventually replace the hair system as a whole anyway. --- .../blender/blenkernel/intern/edithair_particles.c | 33 ++++++-- source/blender/blenkernel/intern/mesh_sample.c | 90 ++++++++++++++++++++++ source/blender/blenkernel/intern/particle.c | 5 ++ 3 files changed, 122 insertions(+), 6 deletions(-) (limited to 'source/blender/blenkernel/intern') diff --git a/source/blender/blenkernel/intern/edithair_particles.c b/source/blender/blenkernel/intern/edithair_particles.c index 785ee00d0e7..dc245d92b5a 100644 --- a/source/blender/blenkernel/intern/edithair_particles.c +++ b/source/blender/blenkernel/intern/edithair_particles.c @@ -33,32 +33,53 @@ #include "BLI_math.h" +#include "DNA_modifier_types.h" #include "DNA_object_types.h" #include "DNA_particle_types.h" +#include "BKE_bvhutils.h" +#include "BKE_DerivedMesh.h" #include "BKE_edithair.h" #include "BKE_particle.h" #include "intern/bmesh_strands_conv.h" -BMesh *BKE_particles_to_bmesh(Object *UNUSED(ob), ParticleSystem *psys) +BMesh *BKE_particles_to_bmesh(Object *ob, ParticleSystem *psys) { - BMesh *bm; + ParticleSystemModifierData *psmd = psys_get_modifier(ob, psys); + const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_PSYS(psys); + BMesh *bm; bm = BM_mesh_create(&allocsize); - BM_strands_bm_from_psys(bm, psys, true, psys->shapenr); + if (psmd && psmd->dm) { + DM_ensure_tessface(psmd->dm); + + BM_strands_bm_from_psys(bm, psys, psmd->dm, true, psys->shapenr); + } return bm; } -void BKE_particles_from_bmesh(Object *UNUSED(ob), ParticleSystem *psys) +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) - BM_strands_bm_to_psys(bm, psys); + 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, psys, psmd->dm, &bvhtree); + + free_bvhtree_from_mesh(&bvhtree); + } + } } diff --git a/source/blender/blenkernel/intern/mesh_sample.c b/source/blender/blenkernel/intern/mesh_sample.c index d1493f33f8d..7300dbe99c1 100644 --- a/source/blender/blenkernel/intern/mesh_sample.c +++ b/source/blender/blenkernel/intern/mesh_sample.c @@ -151,3 +151,93 @@ void BKE_mesh_sample_generate_random(MSurfaceSampleStorage *dst, DerivedMesh *dm BLI_rng_free(rng); } + +/* ==== 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]; + + BKE_mesh_sample_eval(dm, sample, vec, nor); + + 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/particle.c b/source/blender/blenkernel/intern/particle.c index b529d39c561..c02cf9550b3 100644 --- a/source/blender/blenkernel/intern/particle.c +++ b/source/blender/blenkernel/intern/particle.c @@ -1523,6 +1523,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], -- cgit v1.2.3 From 2d79994e39d64120852a895b828e171500d3afe4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20T=C3=B6nne?= Date: Fri, 28 Nov 2014 14:15:14 +0100 Subject: Free strand edit memory after use. --- source/blender/blenkernel/intern/particle.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'source/blender/blenkernel/intern') diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c index c02cf9550b3..2243a91087d 100644 --- a/source/blender/blenkernel/intern/particle.c +++ b/source/blender/blenkernel/intern/particle.c @@ -547,8 +547,11 @@ void psys_free(Object *ob, ParticleSystem *psys) if (psys->edit && psys->free_edit) psys->free_edit(psys->edit); - if (psys->hairedit) + if (psys->hairedit) { BKE_editstrands_free(psys->hairedit); + MEM_freeN(psys->hairedit); + psys->hairedit = NULL; + } if (psys->child) { MEM_freeN(psys->child); -- cgit v1.2.3 From 23b284348b86656dda539ff4dd00de0c8bc41e64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20T=C3=B6nne?= Date: Fri, 28 Nov 2014 14:21:11 +0100 Subject: Removed deprecated code. --- source/blender/blenkernel/intern/edithair.c | 237 +++------------------ source/blender/blenkernel/intern/edithair_inline.h | 154 ------------- .../blender/blenkernel/intern/edithair_particles.c | 217 ------------------- 3 files changed, 33 insertions(+), 575 deletions(-) delete mode 100644 source/blender/blenkernel/intern/edithair_inline.h delete mode 100644 source/blender/blenkernel/intern/edithair_particles.c (limited to 'source/blender/blenkernel/intern') diff --git a/source/blender/blenkernel/intern/edithair.c b/source/blender/blenkernel/intern/edithair.c index 30d1a111620..67a8fc0f21a 100644 --- a/source/blender/blenkernel/intern/edithair.c +++ b/source/blender/blenkernel/intern/edithair.c @@ -35,9 +35,17 @@ #include "BLI_mempool.h" #include "DNA_customdata_types.h" +#include "DNA_modifier_types.h" +#include "DNA_object_types.h" +#include "DNA_particle_types.h" +#include "BKE_bvhutils.h" #include "BKE_customdata.h" #include "BKE_edithair.h" +#include "BKE_DerivedMesh.h" +#include "BKE_particle.h" + +#include "intern/bmesh_strands_conv.h" BMEditStrands *BKE_editstrands_create(BMesh *bm) { @@ -73,221 +81,42 @@ void BKE_editstrands_free(BMEditStrands *em) BM_mesh_free(em->bm); } -#if 0 -static const int chunksize_default_totcurve = 512; -static const int allocsize_default_totcurve = 512; - -static const int chunksize_default_totvert = 1024; -static const int allocsize_default_totvert = 1024; - -static void edithair_mempool_init(HairEditData *hedit) -{ - hedit->cpool = BLI_mempool_create(sizeof(HairEditCurve), allocsize_default_totcurve, - chunksize_default_totcurve, BLI_MEMPOOL_ALLOW_ITER); - hedit->vpool = BLI_mempool_create(sizeof(HairEditVertex), allocsize_default_totvert, - chunksize_default_totvert, BLI_MEMPOOL_ALLOW_ITER); -} +/* === particle conversion === */ -HairEditData *BKE_edithair_create(void) +BMesh *BKE_particles_to_bmesh(Object *ob, ParticleSystem *psys) { - HairEditData *hedit = MEM_callocN(sizeof(HairEditData), "hair edit data"); - - edithair_mempool_init(hedit); + ParticleSystemModifierData *psmd = psys_get_modifier(ob, psys); - CustomData_reset(&hedit->cdata); - CustomData_reset(&hedit->vdata); - - return hedit; -} - -void BKE_edithair_data_free(HairEditData *hedit) -{ - if (CustomData_bmesh_has_free(&(hedit->cdata))) { - HairEditCurve *curve; - HairEditIter iter; - HAIREDIT_ITER(curve, &iter, hedit, HAIREDIT_CURVES_OF_MESH) { - CustomData_bmesh_free_block(&hedit->cdata, &curve->data); - } - } - - if (CustomData_bmesh_has_free(&(hedit->vdata))) { - HairEditVertex *vert; - HairEditIter iter; - HAIREDIT_ITER(vert, &iter, hedit, HAIREDIT_VERTS_OF_MESH) { - CustomData_bmesh_free_block(&hedit->vdata, &vert->data); - } - } - - /* Free custom data pools, This should probably go in CustomData_free? */ - if (hedit->cdata.totlayer) BLI_mempool_destroy(hedit->cdata.pool); - if (hedit->vdata.totlayer) BLI_mempool_destroy(hedit->vdata.pool); - - /* free custom data */ - CustomData_free(&hedit->cdata, 0); - CustomData_free(&hedit->vdata, 0); - - /* destroy element pools */ - BLI_mempool_destroy(hedit->cpool); - BLI_mempool_destroy(hedit->vpool); -} - -void BKE_edithair_clear(HairEditData *hedit) -{ - /* free old data */ - BKE_edithair_data_free(hedit); - memset(hedit, 0, sizeof(HairEditData)); + const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_PSYS(psys); + BMesh *bm; - /* allocate the memory pools for the hair elements */ - edithair_mempool_init(hedit); + bm = BM_mesh_create(&allocsize); - CustomData_reset(&hedit->cdata); - CustomData_reset(&hedit->vdata); -} - -void BKE_edithair_free(HairEditData *hedit) -{ - BKE_edithair_data_free(hedit); - - MEM_freeN(hedit); -} - -void BKE_edithair_get_min_max(HairEditData *hedit, float r_min[3], float r_max[3]) -{ - if (hedit->totverts) { - HairEditVertex *vert; - HairEditIter iter; - - INIT_MINMAX(r_min, r_max); + if (psmd && psmd->dm) { + DM_ensure_tessface(psmd->dm); - HAIREDIT_ITER(vert, &iter, hedit, HAIREDIT_VERTS_OF_MESH) { - minmax_v3v3_v3(r_min, r_max, vert->co); - } - } - else { - zero_v3(r_min); - zero_v3(r_max); - } -} - -HairEditCurve *BKE_edithair_curve_create(HairEditData *hedit, HairEditCurve *example) -{ - HairEditCurve *c = NULL; - - c = BLI_mempool_alloc(hedit->cpool); - - /* --- assign all members --- */ - c->data = NULL; - - c->v = NULL; - /* --- done --- */ - - hedit->totcurves++; - - if (example) { - CustomData_bmesh_copy_data(&hedit->cdata, &hedit->cdata, example->data, &c->data); - } - else { - CustomData_bmesh_set_default(&hedit->cdata, &c->data); - } - - return c; -} - -int BKE_edithair_curve_vertex_count(HairEditData *UNUSED(hedit), HairEditCurve *c) -{ - const HairEditVertex *v; - int count = 0; - for (v = c->v; v; v = v->next) { - ++count; + BM_strands_bm_from_psys(bm, psys, psmd->dm, true, psys->shapenr); } - return count; -} - -static HairEditVertex *edithair_vertex_create(HairEditData *hedit, HairEditVertex *example) -{ - HairEditVertex *v = NULL; - - v = BLI_mempool_alloc(hedit->vpool); - - /* --- assign all members --- */ - v->data = NULL; - - v->next = v->prev = NULL; - /* --- done --- */ - - hedit->totverts++; - if (example) { - CustomData_bmesh_copy_data(&hedit->vdata, &hedit->vdata, example->data, &v->data); - } - else { - CustomData_bmesh_set_default(&hedit->vdata, &v->data); - } - - return v; + return bm; } -HairEditVertex *BKE_edithair_curve_extend(HairEditData *hedit, HairEditCurve *c, HairEditVertex *example, int num) +void BKE_particles_from_bmesh(Object *ob, ParticleSystem *psys) { - HairEditVertex *v_first = NULL; - int i; - - for (i = 0; i < num; ++i) { - HairEditVertex *v = edithair_vertex_create(hedit, example); - if (i == 0) - v_first = v; - - v->prev = c->v; - if (c->v) - c->v->next = v; - c->v = v; - } + ParticleSystemModifierData *psmd = psys_get_modifier(ob, psys); + BMesh *bm = psys->hairedit ? psys->hairedit->bm : NULL; - return v_first; -} - -/* ==== Iterators ==== */ - -/* - * CURVE OF MESH CALLBACKS - */ - -void hairedit_iter__elem_of_mesh_begin(struct HairEditIter__elem_of_mesh *iter) -{ - BLI_mempool_iternew(iter->pooliter.pool, &iter->pooliter); -} - -void *hairedit_iter__elem_of_mesh_step(struct HairEditIter__elem_of_mesh *iter) -{ - return BLI_mempool_iterstep(&iter->pooliter); -} - -/* - * VERT OF CURVE CALLBACKS - */ - -void hairedit_iter__vert_of_curve_begin(struct HairEditIter__vert_of_curve *iter) -{ - if (iter->cdata->v) { - iter->v_first = iter->cdata->v; - iter->v_next = iter->cdata->v; - } - else { - iter->v_first = NULL; - iter->v_next = NULL; - } -} - -void *hairedit_iter__vert_of_curve_step(struct HairEditIter__vert_of_curve *iter) -{ - HairEditVertex *v_curr = iter->v_next; - - if (iter->v_next) { - iter->v_next = iter->v_next->next; + 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, psys, psmd->dm, &bvhtree); + + free_bvhtree_from_mesh(&bvhtree); + } } - - return v_curr; } - -/* =================== */ -#endif diff --git a/source/blender/blenkernel/intern/edithair_inline.h b/source/blender/blenkernel/intern/edithair_inline.h deleted file mode 100644 index a95162c6e07..00000000000 --- a/source/blender/blenkernel/intern/edithair_inline.h +++ /dev/null @@ -1,154 +0,0 @@ -/* - * ***** 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 ***** - */ - -#ifndef __EDITHAIR_INLINE_H__ -#define __EDITHAIR_INLINE_H__ - -/** \file blender/editors/hair/edithair_inline.h - * \ingroup bke - */ - -#include "BLI_mempool.h" -#include "BLI_utildefines.h" - -#include "BKE_edithair.h" - -/* iterator type structs */ -struct HairEditIter__elem_of_mesh { - BLI_mempool_iter pooliter; -}; -struct HairEditIter__vert_of_curve { - HairEditCurve *cdata; - HairEditVertex *v_first, *v_next; -}; - -typedef void (*HairEditIter__begin_cb) (void *); -typedef void *(*HairEditIter__step_cb) (void *); - -typedef struct HairEditIter { - /* keep union first */ - union { - struct HairEditIter__elem_of_mesh elem_of_mesh; - struct HairEditIter__vert_of_curve vert_of_curve; - } data; - - HairEditIter__begin_cb begin; - HairEditIter__step_cb step; - - int count; /* note, only some iterators set this, don't rely on it */ - char itype; -} HairEditIter; - -#define HAIREDIT_ITER_CB_DEF(name) \ - struct HairEditIter__##name; \ - void hairedit_iter__##name##_begin(struct HairEditIter__##name *iter); \ - void *hairedit_iter__##name##_step(struct HairEditIter__##name *iter) - -HAIREDIT_ITER_CB_DEF(elem_of_mesh); -HAIREDIT_ITER_CB_DEF(vert_of_curve); - -#undef HAIREDIT_ITER_CB_DEF - -/* inline here optimizes out the switch statement when called with - * constant values (which is very common), nicer for loop-in-loop situations */ - -/** - * \brief Iterator Step - * - * Calls an iterators step function to return the next element. - */ -BLI_INLINE void *HairEdit_iter_step(HairEditIter *iter) -{ - return iter->step(iter); -} - -/** - * \brief Iterator Init - * - * Takes a hair iterator structure and fills - * it with the appropriate function pointers based - * upon its type. - */ -BLI_INLINE bool HairEdit_iter_init(HairEditIter *iter, HairEditData *hedit, const char itype, void *data) -{ - /* int argtype; */ - iter->itype = itype; - - /* inlining optimizes out this switch when called with the defined type */ - switch ((HairEditIterType)itype) { - case HAIREDIT_CURVES_OF_MESH: - BLI_assert(hedit != NULL); - BLI_assert(data == NULL); - iter->begin = (HairEditIter__begin_cb)hairedit_iter__elem_of_mesh_begin; - iter->step = (HairEditIter__step_cb)hairedit_iter__elem_of_mesh_step; - iter->data.elem_of_mesh.pooliter.pool = hedit->cpool; - break; - case HAIREDIT_VERTS_OF_MESH: - BLI_assert(hedit != NULL); - BLI_assert(data == NULL); - iter->begin = (HairEditIter__begin_cb)hairedit_iter__elem_of_mesh_begin; - iter->step = (HairEditIter__step_cb)hairedit_iter__elem_of_mesh_step; - iter->data.elem_of_mesh.pooliter.pool = hedit->vpool; - break; - case HAIREDIT_VERTS_OF_CURVE: - BLI_assert(data != NULL); - iter->begin = (HairEditIter__begin_cb)hairedit_iter__vert_of_curve_begin; - iter->step = (HairEditIter__step_cb)hairedit_iter__vert_of_curve_step; - iter->data.vert_of_curve.cdata = (HairEditCurve *)data; - break; - default: - /* should never happen */ - BLI_assert(0); - return false; - break; - } - - iter->begin(iter); - - return true; -} - -/** - * \brief Iterator New - * - * Takes a bmesh iterator structure and fills - * it with the appropriate function pointers based - * upon its type and then calls BMeshIter_step() - * to return the first element of the iterator. - * - */ -BLI_INLINE void *HairEdit_iter_new(HairEditIter *iter, HairEditData *hedit, const char itype, void *data) -{ - if (LIKELY(HairEdit_iter_init(iter, hedit, itype, data))) { - return HairEdit_iter_step(iter); - } - else { - return NULL; - } -} - -#endif diff --git a/source/blender/blenkernel/intern/edithair_particles.c b/source/blender/blenkernel/intern/edithair_particles.c deleted file mode 100644 index dc245d92b5a..00000000000 --- a/source/blender/blenkernel/intern/edithair_particles.c +++ /dev/null @@ -1,217 +0,0 @@ -/* - * ***** 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/editors/hair/hair_particles.c - * \ingroup edhair - */ - -#include "MEM_guardedalloc.h" - -#include "BLI_math.h" - -#include "DNA_modifier_types.h" -#include "DNA_object_types.h" -#include "DNA_particle_types.h" - -#include "BKE_bvhutils.h" -#include "BKE_DerivedMesh.h" -#include "BKE_edithair.h" -#include "BKE_particle.h" - -#include "intern/bmesh_strands_conv.h" - -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, psys, psmd->dm, true, psys->shapenr); - } - - 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, psys, psmd->dm, &bvhtree); - - free_bvhtree_from_mesh(&bvhtree); - } - } -} - - -#if 0 -/* ==== convert particle data to hair edit ==== */ - -static void copy_edit_curve(HairEditData *hedit, HairEditCurve *curve, ParticleData *pa) -{ - int totverts = pa->totkey; - HairEditVertex *vert; - HairKey *hkey; - int k; - - vert = BKE_edithair_curve_extend(hedit, curve, NULL, totverts); - for (k = 0, hkey = pa->hair; - k < totverts; - ++k, ++hkey, vert = vert->next) { - - copy_v3_v3(vert->co, hkey->co); - - // TODO define other key stuff ... - } -} - -void BKE_edithair_from_particles(HairEditData *hedit, Object *UNUSED(ob), ParticleSystem *psys) -{ - HairEditCurve *curve; - ParticleData *pa; - int p; - - BKE_edithair_clear(hedit); - - for (p = 0, pa = psys->particles; - p < psys->totpart; - ++p, ++pa) { - - curve = BKE_edithair_curve_create(hedit, NULL); - - copy_edit_curve(hedit, curve, pa); - - // TODO copy particle stuff ... - } -} - -/* ==== convert hair edit to particle data ==== */ - -static void free_particle_data(ParticleSystem *psys) -{ - if (psys->particles) { - ParticleData *pa; - int p; - - for (p = 0, pa = psys->particles; p < psys->totpart; ++p, ++pa) { - if (pa->hair) - MEM_freeN(pa->hair); - } - - MEM_freeN(psys->particles); - psys->particles = NULL; - psys->totpart = 0; - } -} - -static void create_particle_curve(ParticleSystem *psys, ParticleData *pa, HairEditData *hedit, HairEditCurve *curve) -{ - int ntotkey = BKE_edithair_curve_vertex_count(hedit, curve); - HairKey *nhair = MEM_callocN(sizeof(HairKey) * ntotkey, "hair keys"); - - HairEditIter iter; - HairEditVertex *vert; - HairKey *hkey; - int k; - - pa->alive = PARS_ALIVE; - pa->flag = 0; - - pa->time = 0.0f; - pa->lifetime = 100.0f; - pa->dietime = 100.0f; - - pa->fuv[0] = 1.0f; - pa->fuv[1] = 0.0f; - pa->fuv[2] = 0.0f; - pa->fuv[3] = 0.0f; - - pa->size = psys->part->size; - - k = 0; - hkey = nhair; - HAIREDIT_ITER_ELEM(vert, &iter, curve, HAIREDIT_VERTS_OF_CURVE) { - copy_v3_v3(hkey->co, vert->co); - hkey->time = ntotkey > 0 ? (float)k / (float)(ntotkey - 1) : 0.0f; - hkey->weight = 1.0f; - // TODO define other key stuff ... - - ++k; - ++hkey; - } - - pa->totkey = ntotkey; - pa->hair = nhair; -} - -static void create_particle_data(ParticleSystem *psys, HairEditData *hedit) -{ - int ntotpart = hedit->totcurves; - ParticleData *nparticles = MEM_callocN(sizeof(ParticleData) * ntotpart, "particle data"); - - HairEditCurve *curve; - HairEditIter iter; - ParticleData *pa; - int p; - - p = 0; - pa = nparticles; - HAIREDIT_ITER(curve, &iter, hedit, HAIREDIT_CURVES_OF_MESH) { - - // TODO copy particle stuff ... - - create_particle_curve(psys, pa, hedit, curve); - - ++p; - ++pa; - } - - psys->particles = nparticles; - psys->totpart = hedit->totcurves; -} - -void BKE_edithair_to_particles(HairEditData *hedit, Object *UNUSED(ob), ParticleSystem *psys) -{ - free_particle_data(psys); - create_particle_data(psys, hedit); -} -#endif -- cgit v1.2.3 From eb5257002bfd65b92c713a96a524ccf7c19bca9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20T=C3=B6nne?= Date: Fri, 28 Nov 2014 17:09:39 +0100 Subject: New drawing code for hair edit mode. Conflicts: source/blender/editors/space_view3d/drawobject.c source/blender/editors/space_view3d/view3d_intern.h --- source/blender/blenkernel/intern/edithair.c | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) (limited to 'source/blender/blenkernel/intern') diff --git a/source/blender/blenkernel/intern/edithair.c b/source/blender/blenkernel/intern/edithair.c index 67a8fc0f21a..4bd5a8a12bb 100644 --- a/source/blender/blenkernel/intern/edithair.c +++ b/source/blender/blenkernel/intern/edithair.c @@ -56,29 +56,41 @@ BMEditStrands *BKE_editstrands_create(BMesh *bm) return es; } -BMEditStrands *BKE_editstrands_copy(BMEditStrands *em) +BMEditStrands *BKE_editstrands_copy(BMEditStrands *es) { BMEditStrands *es_copy = MEM_callocN(sizeof(BMEditStrands), __func__); - *es_copy = *em; + *es_copy = *es; - es_copy->bm = BM_mesh_copy(em->bm); + es_copy->bm = BM_mesh_copy(es->bm); return es_copy; } -void BKE_editstrands_update_linked_customdata(BMEditStrands *em) +/** + * \brief Return the BMEditStrands for a given object + */ +BMEditStrands *BKE_editstrands_from_object(Object *ob) +{ + ParticleSystem *psys = psys_get_current(ob); + if (psys) { + return psys->hairedit; + } + return NULL; +} + +void BKE_editstrands_update_linked_customdata(BMEditStrands *es) { - BMesh *bm = em->bm; + 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 *em) +void BKE_editstrands_free(BMEditStrands *es) { - if (em->bm) - BM_mesh_free(em->bm); + if (es->bm) + BM_mesh_free(es->bm); } /* === particle conversion === */ -- cgit v1.2.3 From 7b6332f634eeb7e0133086eaaaefa01140a54f8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20T=C3=B6nne?= Date: Fri, 28 Nov 2014 17:58:04 +0100 Subject: Apply the hair matrices when converting from particle keys to bmesh, so the edit data is consistently in object space. --- source/blender/blenkernel/intern/edithair.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'source/blender/blenkernel/intern') diff --git a/source/blender/blenkernel/intern/edithair.c b/source/blender/blenkernel/intern/edithair.c index 4bd5a8a12bb..d9ced64ce81 100644 --- a/source/blender/blenkernel/intern/edithair.c +++ b/source/blender/blenkernel/intern/edithair.c @@ -107,7 +107,7 @@ BMesh *BKE_particles_to_bmesh(Object *ob, ParticleSystem *psys) if (psmd && psmd->dm) { DM_ensure_tessface(psmd->dm); - BM_strands_bm_from_psys(bm, psys, psmd->dm, true, psys->shapenr); + BM_strands_bm_from_psys(bm, ob, psys, psmd->dm, true, psys->shapenr); } return bm; @@ -126,7 +126,7 @@ void BKE_particles_from_bmesh(Object *ob, ParticleSystem *psys) bvhtree_from_mesh_faces(&bvhtree, psmd->dm, 0.0, 2, 6); - BM_strands_bm_to_psys(bm, psys, psmd->dm, &bvhtree); + BM_strands_bm_to_psys(bm, ob, psys, psmd->dm, &bvhtree); free_bvhtree_from_mesh(&bvhtree); } -- cgit v1.2.3 From 7ae6492c85c7c6da6e3d0f6e1239436a2fd3ce6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20T=C3=B6nne?= Date: Tue, 2 Dec 2014 11:30:53 +0100 Subject: Lots of small fixes for paint system quirks to make hair brushes work in the UI. Conflicts: release/scripts/startup/bl_ui/space_view3d.py source/blender/editors/transform/manipulator_widget.c --- source/blender/blenkernel/intern/brush.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source/blender/blenkernel/intern') 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 */ -- cgit v1.2.3 From 83b20c7ddfe60ca779f53a0d337cc1b7854fb14c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20T=C3=B6nne?= Date: Tue, 2 Dec 2014 15:56:30 +0100 Subject: Enforce hair constraints (constant segment length) after applying a tool. Currently uses the same approach as old particle edit mode (rescale hair segments from the root on). A more sophisticated approach using least-square error minimization of the displacement could yield better results. --- source/blender/blenkernel/intern/edithair.c | 52 +++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) (limited to 'source/blender/blenkernel/intern') diff --git a/source/blender/blenkernel/intern/edithair.c b/source/blender/blenkernel/intern/edithair.c index d9ced64ce81..6beb5f595d2 100644 --- a/source/blender/blenkernel/intern/edithair.c +++ b/source/blender/blenkernel/intern/edithair.c @@ -93,6 +93,56 @@ void BKE_editstrands_free(BMEditStrands *es) BM_mesh_free(es->bm); } +/* === constraints === */ + +void BKE_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_solve_constraints(BMEditStrands *es) +{ + /* XXX Simplistic implementation from particles: + * adjust segment lengths starting from the root. + * This should be replaced by a more advanced method using a least-squares + * error metric with length and root location constraints + */ + + BMesh *bm = es->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 base_length = BM_elem_float_data_named_get(&bm->vdata, v, CD_PROP_FLT, CD_HAIR_SEGMENT_LENGTH); + float dist[3]; + float length; + + sub_v3_v3v3(dist, v->co, vprev->co); + length = len_v3(dist); + if (length > 0.0f) + madd_v3_v3v3fl(v->co, vprev->co, dist, base_length / length); + } + vprev = v; + } + } +} + + /* === particle conversion === */ BMesh *BKE_particles_to_bmesh(Object *ob, ParticleSystem *psys) @@ -108,6 +158,8 @@ BMesh *BKE_particles_to_bmesh(Object *ob, ParticleSystem *psys) DM_ensure_tessface(psmd->dm); BM_strands_bm_from_psys(bm, ob, psys, psmd->dm, true, psys->shapenr); + + BKE_editstrands_calc_segment_lengths(bm); } return bm; -- cgit v1.2.3 From 2590231315b6d47cc83e6f39e8d922f53c40eb1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20T=C3=B6nne?= Date: Tue, 2 Dec 2014 17:26:25 +0100 Subject: Constrain hair root vertices to their mesh location after applying tools. Conflicts: source/blender/bmesh/intern/bmesh_interp.c source/blender/bmesh/intern/bmesh_interp.h --- source/blender/blenkernel/intern/edithair.c | 45 ++++++++++++++++++++++++----- 1 file changed, 37 insertions(+), 8 deletions(-) (limited to 'source/blender/blenkernel/intern') diff --git a/source/blender/blenkernel/intern/edithair.c b/source/blender/blenkernel/intern/edithair.c index 6beb5f595d2..e1064d95946 100644 --- a/source/blender/blenkernel/intern/edithair.c +++ b/source/blender/blenkernel/intern/edithair.c @@ -41,17 +41,20 @@ #include "BKE_bvhutils.h" #include "BKE_customdata.h" +#include "BKE_cdderivedmesh.h" #include "BKE_edithair.h" #include "BKE_DerivedMesh.h" +#include "BKE_mesh_sample.h" #include "BKE_particle.h" #include "intern/bmesh_strands_conv.h" -BMEditStrands *BKE_editstrands_create(BMesh *bm) +BMEditStrands *BKE_editstrands_create(BMesh *bm, DerivedMesh *root_dm) { BMEditStrands *es = MEM_callocN(sizeof(BMEditStrands), __func__); es->bm = bm; + es->root_dm = CDDM_copy(root_dm); return es; } @@ -62,6 +65,7 @@ BMEditStrands *BKE_editstrands_copy(BMEditStrands *es) *es_copy = *es; es_copy->bm = BM_mesh_copy(es->bm); + es_copy->root_dm = CDDM_copy(es->root_dm); return es_copy; } @@ -91,6 +95,8 @@ 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 === */ @@ -112,19 +118,36 @@ void BKE_editstrands_calc_segment_lengths(BMesh *bm) } } -void BKE_editstrands_solve_constraints(BMEditStrands *es) +static void editstrands_apply_root_locations(BMesh *bm, DerivedMesh *root_dm) { - /* XXX Simplistic implementation from particles: - * adjust segment lengths starting from the root. - * This should be replaced by a more advanced method using a least-squares - * error metric with length and root location constraints - */ + BMVert *root; + BMIter iter; - BMesh *bm = es->bm; + if (!root_dm) + return; + + BM_ITER_STRANDS(root, &iter, bm, BM_STRANDS_OF_MESH) { + MSurfaceSample root_sample; + float loc[3], nor[3]; + + BM_elem_meshsample_data_named_get(&bm->vdata, root, CD_MSURFACE_SAMPLE, CD_HAIR_ROOT_LOCATION, &root_sample); + if (BKE_mesh_sample_eval(root_dm, &root_sample, loc, nor)) { + copy_v3_v3(root->co, loc); + } + } +} + +static void editstrands_solve_segment_lengths(BMesh *bm) +{ BMVert *root, *v, *vprev; BMIter iter, iter_strand; int k; + /* XXX Simplistic implementation from particles: + * adjust segment lengths starting from the root. + * This should be replaced by a more advanced method using a least-squares + * error metric with length and root location constraints + */ 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) { @@ -142,6 +165,12 @@ void BKE_editstrands_solve_constraints(BMEditStrands *es) } } +void BKE_editstrands_solve_constraints(BMEditStrands *es) +{ + editstrands_apply_root_locations(es->bm, es->root_dm); + editstrands_solve_segment_lengths(es->bm); +} + /* === particle conversion === */ -- cgit v1.2.3 From a4664ef88daf01bb39beccfbc5bfc1050aa1cb6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20T=C3=B6nne?= Date: Sun, 30 Nov 2014 10:58:16 +0100 Subject: New mesh sample evaluation function for shape key data. --- source/blender/blenkernel/intern/mesh_sample.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) (limited to 'source/blender/blenkernel/intern') diff --git a/source/blender/blenkernel/intern/mesh_sample.c b/source/blender/blenkernel/intern/mesh_sample.c index 7300dbe99c1..65995a6277c 100644 --- a/source/blender/blenkernel/intern/mesh_sample.c +++ b/source/blender/blenkernel/intern/mesh_sample.c @@ -26,6 +26,7 @@ #include "MEM_guardedalloc.h" +#include "DNA_key_types.h" #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" @@ -76,6 +77,27 @@ bool BKE_mesh_sample_eval(DerivedMesh *dm, const MSurfaceSample *sample, float l 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; + + 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 ==== */ -- cgit v1.2.3 From e5b25e3c077cece734f92cba2539ee6c078bb988 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20T=C3=B6nne?= Date: Sun, 30 Nov 2014 15:52:05 +0100 Subject: Generic raycast method for generating mesh surface samples. Conflicts: source/blender/blenkernel/intern/mesh_sample.c --- source/blender/blenkernel/intern/mesh_sample.c | 77 ++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) (limited to 'source/blender/blenkernel/intern') diff --git a/source/blender/blenkernel/intern/mesh_sample.c b/source/blender/blenkernel/intern/mesh_sample.c index 65995a6277c..7dbbe889ec7 100644 --- a/source/blender/blenkernel/intern/mesh_sample.c +++ b/source/blender/blenkernel/intern/mesh_sample.c @@ -34,6 +34,7 @@ #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" @@ -99,6 +100,31 @@ bool BKE_mesh_sample_shapekey(Key *key, KeyBlock *kb, const MSurfaceSample *samp } +/* ==== 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) @@ -174,6 +200,57 @@ void BKE_mesh_sample_generate_random(MSurfaceSampleStorage *dst, DerivedMesh *dm BLI_rng_free(rng); } + +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; +} + +void BKE_mesh_sample_generate_raycast(MSurfaceSampleStorage *dst, DerivedMesh *dm, MeshSampleRayCallback ray_cb, void *userdata) +{ + BVHTreeFromMesh bvhdata; + float ray_start[3], ray_end[3]; + int i; + + DM_ensure_tessface(dm); + + memset(&bvhdata, 0, sizeof(BVHTreeFromMesh)); + bvhtree_from_mesh_faces(&bvhdata, dm, 0.0f, 4, 6); + + if (bvhdata.tree) { + i = 0; + while (ray_cb(userdata, ray_start, ray_end)) { + MSurfaceSample sample; + + sample_bvh_raycast(&sample, dm, &bvhdata, ray_start, ray_end); + + if (!dst->store_sample(dst->data, dst->capacity, i, &sample)) + break; + + ++i; + } + } + + free_bvhtree_from_mesh(&bvhdata); +} + /* ==== Utilities ==== */ #include "DNA_particle_types.h" -- cgit v1.2.3 From 79e649a3bf63e7f6533dd4280e1dbe357269f243 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20T=C3=B6nne?= Date: Mon, 1 Dec 2014 14:38:03 +0100 Subject: New simple storage method for single sample values. --- source/blender/blenkernel/intern/mesh_sample.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'source/blender/blenkernel/intern') diff --git a/source/blender/blenkernel/intern/mesh_sample.c b/source/blender/blenkernel/intern/mesh_sample.c index 7dbbe889ec7..664dfeaf963 100644 --- a/source/blender/blenkernel/intern/mesh_sample.c +++ b/source/blender/blenkernel/intern/mesh_sample.c @@ -137,6 +137,15 @@ static bool mesh_sample_store_array_sample(void *vdata, int capacity, int index, 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; -- cgit v1.2.3 From f95dde244e562d90026be9a07d6cc596225a0db2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20T=C3=B6nne?= Date: Mon, 1 Dec 2014 14:41:02 +0100 Subject: Better feedback about valid sample from mesh sampling methods. Conflicts: source/blender/editors/object/object_shapekey.c --- source/blender/blenkernel/intern/mesh_sample.c | 36 +++++++++++++++----------- 1 file changed, 21 insertions(+), 15 deletions(-) (limited to 'source/blender/blenkernel/intern') diff --git a/source/blender/blenkernel/intern/mesh_sample.c b/source/blender/blenkernel/intern/mesh_sample.c index 664dfeaf963..cd568e44d68 100644 --- a/source/blender/blenkernel/intern/mesh_sample.c +++ b/source/blender/blenkernel/intern/mesh_sample.c @@ -161,14 +161,14 @@ void BKE_mesh_sample_storage_release(MSurfaceSampleStorage *storage) } -void BKE_mesh_sample_generate_random(MSurfaceSampleStorage *dst, DerivedMesh *dm, unsigned int seed, int totsample) +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; + int i, stored = 0; rng = BLI_rng_new(seed); @@ -202,11 +202,15 @@ void BKE_mesh_sample_generate_random(MSurfaceSampleStorage *dst, DerivedMesh *dm sample.orig_weights[1] = a; sample.orig_weights[2] = b; - if (!dst->store_sample(dst->data, dst->capacity, i, &sample)) + if (dst->store_sample(dst->data, dst->capacity, i, &sample)) + ++stored; + else break; } BLI_rng_free(rng); + + return stored; } @@ -232,11 +236,11 @@ static bool sample_bvh_raycast(MSurfaceSample *sample, DerivedMesh *dm, BVHTreeF return false; } -void BKE_mesh_sample_generate_raycast(MSurfaceSampleStorage *dst, DerivedMesh *dm, MeshSampleRayCallback ray_cb, void *userdata) +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; + int i, stored = 0; DM_ensure_tessface(dm); @@ -244,20 +248,22 @@ void BKE_mesh_sample_generate_raycast(MSurfaceSampleStorage *dst, DerivedMesh *d bvhtree_from_mesh_faces(&bvhdata, dm, 0.0f, 4, 6); if (bvhdata.tree) { - i = 0; - while (ray_cb(userdata, ray_start, ray_end)) { - MSurfaceSample sample; - - sample_bvh_raycast(&sample, dm, &bvhdata, ray_start, ray_end); - - if (!dst->store_sample(dst->data, dst->capacity, i, &sample)) - break; - - ++i; + 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 ==== */ -- cgit v1.2.3 From 8672304e30a207767888b75ebe9015ad7f3210a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20T=C3=B6nne?= Date: Mon, 1 Dec 2014 14:42:18 +0100 Subject: Fix for uninitialized return value. --- source/blender/blenkernel/intern/mesh_sample.c | 1 + 1 file changed, 1 insertion(+) (limited to 'source/blender/blenkernel/intern') diff --git a/source/blender/blenkernel/intern/mesh_sample.c b/source/blender/blenkernel/intern/mesh_sample.c index cd568e44d68..b4c59037f88 100644 --- a/source/blender/blenkernel/intern/mesh_sample.c +++ b/source/blender/blenkernel/intern/mesh_sample.c @@ -91,6 +91,7 @@ bool BKE_mesh_sample_shapekey(Key *key, KeyBlock *kb, const MSurfaceSample *samp 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]); -- cgit v1.2.3 From 56a09434c533e5ca72d2f8ff6e144bfcdd88886c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20T=C3=B6nne?= Date: Fri, 5 Dec 2014 14:42:22 +0100 Subject: Basic Add tool for creating new strands in hair edit mode. --- source/blender/blenkernel/intern/edithair.c | 21 ++++++++--- source/blender/blenkernel/intern/mesh_sample.c | 49 ++++++++++++++++++-------- 2 files changed, 52 insertions(+), 18 deletions(-) (limited to 'source/blender/blenkernel/intern') diff --git a/source/blender/blenkernel/intern/edithair.c b/source/blender/blenkernel/intern/edithair.c index e1064d95946..2da64f18dc0 100644 --- a/source/blender/blenkernel/intern/edithair.c +++ b/source/blender/blenkernel/intern/edithair.c @@ -101,7 +101,7 @@ void BKE_editstrands_free(BMEditStrands *es) /* === constraints === */ -void BKE_editstrands_calc_segment_lengths(BMesh *bm) +static void editstrands_calc_segment_lengths(BMesh *bm) { BMVert *root, *v, *vprev; BMIter iter, iter_strand; @@ -128,10 +128,10 @@ static void editstrands_apply_root_locations(BMesh *bm, DerivedMesh *root_dm) BM_ITER_STRANDS(root, &iter, bm, BM_STRANDS_OF_MESH) { MSurfaceSample root_sample; - float loc[3], nor[3]; + float loc[3], nor[3], tang[3]; BM_elem_meshsample_data_named_get(&bm->vdata, root, CD_MSURFACE_SAMPLE, CD_HAIR_ROOT_LOCATION, &root_sample); - if (BKE_mesh_sample_eval(root_dm, &root_sample, loc, nor)) { + if (BKE_mesh_sample_eval(root_dm, &root_sample, loc, nor, tang)) { copy_v3_v3(root->co, loc); } } @@ -167,10 +167,23 @@ static void editstrands_solve_segment_lengths(BMesh *bm) void BKE_editstrands_solve_constraints(BMEditStrands *es) { + BKE_editstrands_ensure(es); + editstrands_apply_root_locations(es->bm, es->root_dm); editstrands_solve_segment_lengths(es->bm); } +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; + } +} + /* === particle conversion === */ @@ -188,7 +201,7 @@ BMesh *BKE_particles_to_bmesh(Object *ob, ParticleSystem *psys) BM_strands_bm_from_psys(bm, ob, psys, psmd->dm, true, psys->shapenr); - BKE_editstrands_calc_segment_lengths(bm); + editstrands_calc_segment_lengths(bm); } return bm; diff --git a/source/blender/blenkernel/intern/mesh_sample.c b/source/blender/blenkernel/intern/mesh_sample.c index b4c59037f88..c36d2adde8b 100644 --- a/source/blender/blenkernel/intern/mesh_sample.c +++ b/source/blender/blenkernel/intern/mesh_sample.c @@ -43,15 +43,15 @@ /* ==== Evaluate ==== */ -bool BKE_mesh_sample_eval(DerivedMesh *dm, const MSurfaceSample *sample, float loc[3], float nor[3]) +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; - float vnor[3]; zero_v3(loc); zero_v3(nor); + zero_v3(tang); if (sample->orig_verts[0] >= totverts || sample->orig_verts[1] >= totverts || @@ -62,18 +62,39 @@ bool BKE_mesh_sample_eval(DerivedMesh *dm, const MSurfaceSample *sample, float l v2 = &mverts[sample->orig_verts[1]]; v3 = &mverts[sample->orig_verts[2]]; - 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]); + { /* 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_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]); + { /* 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); + } - 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; } @@ -329,9 +350,9 @@ bool BKE_mesh_sample_from_particle(MSurfaceSample *sample, ParticleSystem *psys, bool BKE_mesh_sample_to_particle(MSurfaceSample *sample, ParticleSystem *UNUSED(psys), DerivedMesh *dm, BVHTreeFromMesh *bvhtree, ParticleData *pa) { BVHTreeNearest nearest; - float vec[3], nor[3]; + float vec[3], nor[3], tang[3]; - BKE_mesh_sample_eval(dm, sample, vec, nor); + BKE_mesh_sample_eval(dm, sample, vec, nor, tang); nearest.index = -1; nearest.dist_sq = FLT_MAX; -- cgit v1.2.3 From b70c815ac271927bf8ef49d9b4b927b45f8b2138 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20T=C3=B6nne?= Date: Sun, 7 Dec 2014 12:26:57 +0100 Subject: Renamed the edithair files in BKE to editstrands. The rationale behind this is that the BKE code could be used for modeling hair and fur as well as a number of other features such as grass. The primary addition to BMesh is the limitation to strand-like topology (simple vertex chains, optionally rooted on a mesh surface). The editor code OTOH is quite hair specific, since the result should be suitable for hair simulation, and the workflow should mimick actual hair grooming intuitively. Eventually the hair edit mode could become a generalized strand edit mode with slightly different tool sets for various purposes, but for now it is quite specifically built for hair. Conflicts: source/blender/blenkernel/CMakeLists.txt source/blender/blenkernel/intern/particle.c --- source/blender/blenkernel/intern/customdata.c | 2 +- source/blender/blenkernel/intern/edithair.c | 228 ------------------------- source/blender/blenkernel/intern/editstrands.c | 228 +++++++++++++++++++++++++ source/blender/blenkernel/intern/particle.c | 2 +- 4 files changed, 230 insertions(+), 230 deletions(-) delete mode 100644 source/blender/blenkernel/intern/edithair.c create mode 100644 source/blender/blenkernel/intern/editstrands.c (limited to 'source/blender/blenkernel/intern') diff --git a/source/blender/blenkernel/intern/customdata.c b/source/blender/blenkernel/intern/customdata.c index a5eb2c80760..569af4acdfc 100644 --- a/source/blender/blenkernel/intern/customdata.c +++ b/source/blender/blenkernel/intern/customdata.c @@ -55,7 +55,7 @@ #include "BKE_customdata.h" #include "BKE_customdata_file.h" -#include "BKE_edithair.h" +#include "BKE_editstrands.h" #include "BKE_global.h" #include "BKE_main.h" #include "BKE_mesh_mapping.h" diff --git a/source/blender/blenkernel/intern/edithair.c b/source/blender/blenkernel/intern/edithair.c deleted file mode 100644 index 2da64f18dc0..00000000000 --- a/source/blender/blenkernel/intern/edithair.c +++ /dev/null @@ -1,228 +0,0 @@ -/* - * ***** 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/editors/hair/edithair.c - * \ingroup bke - */ - -#include "MEM_guardedalloc.h" - -#include "BLI_math.h" -#include "BLI_mempool.h" - -#include "DNA_customdata_types.h" -#include "DNA_modifier_types.h" -#include "DNA_object_types.h" -#include "DNA_particle_types.h" - -#include "BKE_bvhutils.h" -#include "BKE_customdata.h" -#include "BKE_cdderivedmesh.h" -#include "BKE_edithair.h" -#include "BKE_DerivedMesh.h" -#include "BKE_mesh_sample.h" -#include "BKE_particle.h" - -#include "intern/bmesh_strands_conv.h" - -BMEditStrands *BKE_editstrands_create(BMesh *bm, DerivedMesh *root_dm) -{ - BMEditStrands *es = MEM_callocN(sizeof(BMEditStrands), __func__); - - es->bm = bm; - es->root_dm = CDDM_copy(root_dm); - - 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) { - return psys->hairedit; - } - 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 === */ - -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; - } - } -} - -static void editstrands_apply_root_locations(BMesh *bm, DerivedMesh *root_dm) -{ - BMVert *root; - BMIter iter; - - if (!root_dm) - return; - - BM_ITER_STRANDS(root, &iter, bm, BM_STRANDS_OF_MESH) { - MSurfaceSample root_sample; - float loc[3], nor[3], tang[3]; - - BM_elem_meshsample_data_named_get(&bm->vdata, root, CD_MSURFACE_SAMPLE, CD_HAIR_ROOT_LOCATION, &root_sample); - if (BKE_mesh_sample_eval(root_dm, &root_sample, loc, nor, tang)) { - copy_v3_v3(root->co, loc); - } - } -} - -static void editstrands_solve_segment_lengths(BMesh *bm) -{ - BMVert *root, *v, *vprev; - BMIter iter, iter_strand; - int k; - - /* XXX Simplistic implementation from particles: - * adjust segment lengths starting from the root. - * This should be replaced by a more advanced method using a least-squares - * error metric with length and root location constraints - */ - 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 base_length = BM_elem_float_data_named_get(&bm->vdata, v, CD_PROP_FLT, CD_HAIR_SEGMENT_LENGTH); - float dist[3]; - float length; - - sub_v3_v3v3(dist, v->co, vprev->co); - length = len_v3(dist); - if (length > 0.0f) - madd_v3_v3v3fl(v->co, vprev->co, dist, base_length / length); - } - vprev = v; - } - } -} - -void BKE_editstrands_solve_constraints(BMEditStrands *es) -{ - BKE_editstrands_ensure(es); - - editstrands_apply_root_locations(es->bm, es->root_dm); - editstrands_solve_segment_lengths(es->bm); -} - -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; - } -} - - -/* === 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); - - 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/editstrands.c b/source/blender/blenkernel/intern/editstrands.c new file mode 100644 index 00000000000..0edd9a7cc60 --- /dev/null +++ b/source/blender/blenkernel/intern/editstrands.c @@ -0,0 +1,228 @@ +/* + * ***** 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_customdata_types.h" +#include "DNA_modifier_types.h" +#include "DNA_object_types.h" +#include "DNA_particle_types.h" + +#include "BKE_bvhutils.h" +#include "BKE_customdata.h" +#include "BKE_cdderivedmesh.h" +#include "BKE_editstrands.h" +#include "BKE_DerivedMesh.h" +#include "BKE_mesh_sample.h" +#include "BKE_particle.h" + +#include "intern/bmesh_strands_conv.h" + +BMEditStrands *BKE_editstrands_create(BMesh *bm, DerivedMesh *root_dm) +{ + BMEditStrands *es = MEM_callocN(sizeof(BMEditStrands), __func__); + + es->bm = bm; + es->root_dm = CDDM_copy(root_dm); + + 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) { + return psys->hairedit; + } + 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 === */ + +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; + } + } +} + +static void editstrands_apply_root_locations(BMesh *bm, DerivedMesh *root_dm) +{ + BMVert *root; + BMIter iter; + + if (!root_dm) + return; + + BM_ITER_STRANDS(root, &iter, bm, BM_STRANDS_OF_MESH) { + MSurfaceSample root_sample; + float loc[3], nor[3], tang[3]; + + BM_elem_meshsample_data_named_get(&bm->vdata, root, CD_MSURFACE_SAMPLE, CD_HAIR_ROOT_LOCATION, &root_sample); + if (BKE_mesh_sample_eval(root_dm, &root_sample, loc, nor, tang)) { + copy_v3_v3(root->co, loc); + } + } +} + +static void editstrands_solve_segment_lengths(BMesh *bm) +{ + BMVert *root, *v, *vprev; + BMIter iter, iter_strand; + int k; + + /* XXX Simplistic implementation from particles: + * adjust segment lengths starting from the root. + * This should be replaced by a more advanced method using a least-squares + * error metric with length and root location constraints + */ + 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 base_length = BM_elem_float_data_named_get(&bm->vdata, v, CD_PROP_FLT, CD_HAIR_SEGMENT_LENGTH); + float dist[3]; + float length; + + sub_v3_v3v3(dist, v->co, vprev->co); + length = len_v3(dist); + if (length > 0.0f) + madd_v3_v3v3fl(v->co, vprev->co, dist, base_length / length); + } + vprev = v; + } + } +} + +void BKE_editstrands_solve_constraints(BMEditStrands *es) +{ + BKE_editstrands_ensure(es); + + editstrands_apply_root_locations(es->bm, es->root_dm); + editstrands_solve_segment_lengths(es->bm); +} + +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; + } +} + + +/* === 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); + + 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/particle.c b/source/blender/blenkernel/intern/particle.c index 2243a91087d..69732b1c02a 100644 --- a/source/blender/blenkernel/intern/particle.c +++ b/source/blender/blenkernel/intern/particle.c @@ -65,7 +65,7 @@ #include "BKE_boids.h" #include "BKE_cloth.h" #include "BKE_colortools.h" -#include "BKE_edithair.h" +#include "BKE_editstrands.h" #include "BKE_effect.h" #include "BKE_global.h" #include "BKE_group.h" -- cgit v1.2.3 From f3b22c5769059a5af3fd5f63cc93051bdee29dcc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20T=C3=B6nne?= Date: Sun, 7 Dec 2014 13:12:48 +0100 Subject: Support for sim_debug drawing in hair edit mode (dev feature). --- source/blender/blenkernel/intern/editstrands.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'source/blender/blenkernel/intern') diff --git a/source/blender/blenkernel/intern/editstrands.c b/source/blender/blenkernel/intern/editstrands.c index 0edd9a7cc60..62271616b42 100644 --- a/source/blender/blenkernel/intern/editstrands.c +++ b/source/blender/blenkernel/intern/editstrands.c @@ -42,8 +42,9 @@ #include "BKE_bvhutils.h" #include "BKE_customdata.h" #include "BKE_cdderivedmesh.h" -#include "BKE_editstrands.h" #include "BKE_DerivedMesh.h" +#include "BKE_editstrands.h" +#include "BKE_effect.h" #include "BKE_mesh_sample.h" #include "BKE_particle.h" @@ -66,6 +67,7 @@ BMEditStrands *BKE_editstrands_copy(BMEditStrands *es) es_copy->bm = BM_mesh_copy(es->bm); es_copy->root_dm = CDDM_copy(es->root_dm); + es_copy->debug_data = NULL; return es_copy; } @@ -97,6 +99,8 @@ void BKE_editstrands_free(BMEditStrands *es) BM_mesh_free(es->bm); if (es->root_dm) es->root_dm->release(es->root_dm); + if (es->debug_data) + BKE_sim_debug_data_free(es->debug_data); } /* === constraints === */ -- cgit v1.2.3 From eacc24ccf1f758597adbdd33c830229737e5839d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20T=C3=B6nne?= Date: Thu, 11 Dec 2014 17:40:05 +0100 Subject: Ported over the relaxation method for hair vertices from particle edit mode. This method is simple, but not really very usable. It works by successively relaxing segments that are too long or too short, moving both vertices along the edge between them. This is repeated N^2 times (N: number of vertices on the strand). A true IK solver could give a lot better results, as well as providing many opportunities to apply weighting for targets (e.g. preferring to move non-selected over selected vertices). Many different methods for simple IK solvers exist, so there should be one that works well for large number of simple strands. See e.g. http://www.math.ucsd.edu/~sbuss/ResearchWeb/ikmethods/iksurvey.pdf --- source/blender/blenkernel/intern/editstrands.c | 75 +++++++++++++++++++++++--- 1 file changed, 68 insertions(+), 7 deletions(-) (limited to 'source/blender/blenkernel/intern') diff --git a/source/blender/blenkernel/intern/editstrands.c b/source/blender/blenkernel/intern/editstrands.c index 62271616b42..94aa9b9e3f4 100644 --- a/source/blender/blenkernel/intern/editstrands.c +++ b/source/blender/blenkernel/intern/editstrands.c @@ -141,17 +141,75 @@ static void editstrands_apply_root_locations(BMesh *bm, DerivedMesh *root_dm) } } -static void editstrands_solve_segment_lengths(BMesh *bm) +/* try to find a nice solution to keep distances between neighboring keys */ +/* XXX Stub implementation ported from particles: + * Successively relax each segment starting from the root, + * repeat this for every vertex (O(n^2) !!) + * This should be replaced by a more advanced method using a least-squares + * error metric with length and root location constraints (IK solver) + */ +static void editstrands_solve_targets(BMEditStrands *edit) +{ + BMesh *bm = edit->bm; + BMVert *root; + BMIter iter; + + if (!edit) + return; +// if (!(pset->flag & PE_KEEP_LENGTHS)) // XXX TODO +// return; + + BM_ITER_STRANDS(root, &iter, bm, BM_STRANDS_OF_MESH) { + const int numvert = BM_strands_keys_count(root); + float relax_factor = numvert > 0 ? 1.0f / numvert : 0.0f; + + BMVert *vj; + BMIter iterj; + int j; + + BM_ITER_STRANDS_ELEM_INDEX(vj, &iterj, root, BM_VERTS_OF_STRAND, j) { + BMVert *vk, *vk_prev; + float lenk, lenk_prev; + BMIter iterk; + int k; + bool skip_first; + + if (j == 0) + continue; + + if (true /* XXX particles use PE_LOCK_FIRST option */) + skip_first = true; + else + skip_first = false; + + BM_ITER_STRANDS_ELEM_INDEX(vk, &iterk, root, BM_VERTS_OF_STRAND, k) { + float dir[3], tlen, relax; + + lenk = BM_elem_float_data_named_get(&bm->vdata, vk, CD_PROP_FLT, CD_HAIR_SEGMENT_LENGTH); + + if (k > 0) { + sub_v3_v3v3(dir, vk->co, vk_prev->co); + tlen = normalize_v3(dir); + relax = relax_factor * (tlen - lenk_prev); + + if (!(k == 1 && skip_first)) + madd_v3_v3fl(vk_prev->co, dir, relax); + madd_v3_v3fl(vk->co, dir, -relax); + } + + vk_prev = vk; + lenk_prev = lenk; + } + } + } +} + +static void editstrands_adjust_segment_lengths(BMesh *bm) { BMVert *root, *v, *vprev; BMIter iter, iter_strand; int k; - /* XXX Simplistic implementation from particles: - * adjust segment lengths starting from the root. - * This should be replaced by a more advanced method using a least-squares - * error metric with length and root location constraints - */ 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) { @@ -174,7 +232,10 @@ void BKE_editstrands_solve_constraints(BMEditStrands *es) BKE_editstrands_ensure(es); editstrands_apply_root_locations(es->bm, es->root_dm); - editstrands_solve_segment_lengths(es->bm); + + editstrands_solve_targets(es); + + editstrands_adjust_segment_lengths(es->bm); } void BKE_editstrands_ensure(BMEditStrands *es) -- cgit v1.2.3 From 48a86af3887c3d93e1a8cf34033e86b23d1edd12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20T=C3=B6nne?= Date: Fri, 12 Dec 2014 13:48:36 +0100 Subject: IK solver for hair strands that provides a better solution for keeping consistent segment lengths when transforming vertices. Warning: The implementation is not correct yet, but all the steps should be there. The main idea is to treat strands as a sequence of joints that are displaced out of their original locations by a transform or other tool. The solver then tries to find a global per-strand solution that keeps the segment lengths unmodified, with a minimum change in angles from the original starting shape. Such a solution is much more usable and efficient than the current O(n^2) attempt of "spreading the error" across the strand. The inverse kinematics method is very flexible. It can also include stretching, which would be very welcome for features like the length tool. Different parts of the strand could be weighted separately using scaling factors for the angle/stretch parameters. Conflicts: source/blender/physics/intern/implicit.h --- source/blender/blenkernel/intern/editstrands.c | 128 ++++--------------------- 1 file changed, 21 insertions(+), 107 deletions(-) (limited to 'source/blender/blenkernel/intern') diff --git a/source/blender/blenkernel/intern/editstrands.c b/source/blender/blenkernel/intern/editstrands.c index 94aa9b9e3f4..777c8bda316 100644 --- a/source/blender/blenkernel/intern/editstrands.c +++ b/source/blender/blenkernel/intern/editstrands.c @@ -48,6 +48,8 @@ #include "BKE_mesh_sample.h" #include "BKE_particle.h" +#include "BPH_strands.h" + #include "intern/bmesh_strands_conv.h" BMEditStrands *BKE_editstrands_create(BMesh *bm, DerivedMesh *root_dm) @@ -105,106 +107,35 @@ void BKE_editstrands_free(BMEditStrands *es) /* === constraints === */ -static void editstrands_calc_segment_lengths(BMesh *bm) +BMEditStrandsLocations BKE_editstrands_get_locations(BMEditStrands *edit) { - BMVert *root, *v, *vprev; - BMIter iter, iter_strand; - int k; + BMesh *bm = edit->bm; + BMEditStrandsLocations locs = MEM_mallocN(3*sizeof(float) * bm->totvert, "editstrands locations"); - 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; - } + 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; } -static void editstrands_apply_root_locations(BMesh *bm, DerivedMesh *root_dm) +void BKE_editstrands_free_locations(BMEditStrandsLocations locs) { - BMVert *root; - BMIter iter; - - if (!root_dm) - return; - - BM_ITER_STRANDS(root, &iter, bm, BM_STRANDS_OF_MESH) { - MSurfaceSample root_sample; - float loc[3], nor[3], tang[3]; - - BM_elem_meshsample_data_named_get(&bm->vdata, root, CD_MSURFACE_SAMPLE, CD_HAIR_ROOT_LOCATION, &root_sample); - if (BKE_mesh_sample_eval(root_dm, &root_sample, loc, nor, tang)) { - copy_v3_v3(root->co, loc); - } - } + MEM_freeN(locs); } -/* try to find a nice solution to keep distances between neighboring keys */ -/* XXX Stub implementation ported from particles: - * Successively relax each segment starting from the root, - * repeat this for every vertex (O(n^2) !!) - * This should be replaced by a more advanced method using a least-squares - * error metric with length and root location constraints (IK solver) - */ -static void editstrands_solve_targets(BMEditStrands *edit) +void BKE_editstrands_solve_constraints(Object *ob, BMEditStrands *es, BMEditStrandsLocations orig) { - BMesh *bm = edit->bm; - BMVert *root; - BMIter iter; - - if (!edit) - return; -// if (!(pset->flag & PE_KEEP_LENGTHS)) // XXX TODO -// return; + BKE_editstrands_ensure(es); - BM_ITER_STRANDS(root, &iter, bm, BM_STRANDS_OF_MESH) { - const int numvert = BM_strands_keys_count(root); - float relax_factor = numvert > 0 ? 1.0f / numvert : 0.0f; - - BMVert *vj; - BMIter iterj; - int j; - - BM_ITER_STRANDS_ELEM_INDEX(vj, &iterj, root, BM_VERTS_OF_STRAND, j) { - BMVert *vk, *vk_prev; - float lenk, lenk_prev; - BMIter iterk; - int k; - bool skip_first; - - if (j == 0) - continue; - - if (true /* XXX particles use PE_LOCK_FIRST option */) - skip_first = true; - else - skip_first = false; - - BM_ITER_STRANDS_ELEM_INDEX(vk, &iterk, root, BM_VERTS_OF_STRAND, k) { - float dir[3], tlen, relax; - - lenk = BM_elem_float_data_named_get(&bm->vdata, vk, CD_PROP_FLT, CD_HAIR_SEGMENT_LENGTH); - - if (k > 0) { - sub_v3_v3v3(dir, vk->co, vk_prev->co); - tlen = normalize_v3(dir); - relax = relax_factor * (tlen - lenk_prev); - - if (!(k == 1 && skip_first)) - madd_v3_v3fl(vk_prev->co, dir, relax); - madd_v3_v3fl(vk->co, dir, -relax); - } - - vk_prev = vk; - lenk_prev = lenk; - } - } - } + BPH_strands_solve_constraints(ob, es, orig); } -static void editstrands_adjust_segment_lengths(BMesh *bm) +static void editstrands_calc_segment_lengths(BMesh *bm) { BMVert *root, *v, *vprev; BMIter iter, iter_strand; @@ -213,31 +144,14 @@ static void editstrands_adjust_segment_lengths(BMesh *bm) 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 base_length = BM_elem_float_data_named_get(&bm->vdata, v, CD_PROP_FLT, CD_HAIR_SEGMENT_LENGTH); - float dist[3]; - float length; - - sub_v3_v3v3(dist, v->co, vprev->co); - length = len_v3(dist); - if (length > 0.0f) - madd_v3_v3v3fl(v->co, vprev->co, dist, base_length / length); + 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_solve_constraints(BMEditStrands *es) -{ - BKE_editstrands_ensure(es); - - editstrands_apply_root_locations(es->bm, es->root_dm); - - editstrands_solve_targets(es); - - editstrands_adjust_segment_lengths(es->bm); -} - void BKE_editstrands_ensure(BMEditStrands *es) { BM_strands_cd_flag_ensure(es->bm, 0); -- cgit v1.2.3 From 4798464e8bbbcc3f92fbda82b1114c4824eaabf1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20T=C3=B6nne?= Date: Fri, 30 Jan 2015 10:54:05 +0100 Subject: Extended Mesh <-> BMesh copy function versions for specifying custom data masks explicitly. A dummy mesh is used for strand edit undo storage like in mesh edit to prevent unnecessary code duplication. However, when copying from/to BMesh only the mesh data layers are copied by default, omitting the new data layers for strands (currently only MSurfaceSample hair root data). --- source/blender/blenkernel/intern/customdata.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'source/blender/blenkernel/intern') diff --git a/source/blender/blenkernel/intern/customdata.c b/source/blender/blenkernel/intern/customdata.c index 569af4acdfc..444163e4c32 100644 --- a/source/blender/blenkernel/intern/customdata.c +++ b/source/blender/blenkernel/intern/customdata.c @@ -1369,6 +1369,12 @@ 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_FREESTYLE_FACE | + 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 | -- cgit v1.2.3 From ed1dc43657c6362ec91a4cc4a1e80021279a9415 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20T=C3=B6nne?= Date: Sun, 1 Feb 2015 14:20:45 +0100 Subject: Fix for strands undo creating an invalid BMesh. When copying mesh data to bmesh the MVERT and similar customdata types have to be omitted. Otherwise the bmesh instance ends up with NULL pointers in customdata layers, but entries in the typemap != -1. The effect was that when storing new steps after one or more undo, the resulting original data would be copied, and subsequent undo steps are ignored. --- source/blender/blenkernel/intern/customdata.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'source/blender/blenkernel/intern') diff --git a/source/blender/blenkernel/intern/customdata.c b/source/blender/blenkernel/intern/customdata.c index 444163e4c32..dd86d79a7b3 100644 --- a/source/blender/blenkernel/intern/customdata.c +++ b/source/blender/blenkernel/intern/customdata.c @@ -1373,7 +1373,12 @@ 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_FREESTYLE_FACE | + 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 | -- cgit v1.2.3 From 9cafd3ae564523c984a7a5201ed6fd2c671bc37f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20T=C3=B6nne?= Date: Mon, 20 Apr 2015 12:58:16 +0200 Subject: SimDebugData is now global, for easier usage and less intrusive code. --- source/blender/blenkernel/intern/editstrands.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'source/blender/blenkernel/intern') diff --git a/source/blender/blenkernel/intern/editstrands.c b/source/blender/blenkernel/intern/editstrands.c index 777c8bda316..5dc0402ef19 100644 --- a/source/blender/blenkernel/intern/editstrands.c +++ b/source/blender/blenkernel/intern/editstrands.c @@ -69,7 +69,6 @@ BMEditStrands *BKE_editstrands_copy(BMEditStrands *es) es_copy->bm = BM_mesh_copy(es->bm); es_copy->root_dm = CDDM_copy(es->root_dm); - es_copy->debug_data = NULL; return es_copy; } @@ -101,8 +100,6 @@ void BKE_editstrands_free(BMEditStrands *es) BM_mesh_free(es->bm); if (es->root_dm) es->root_dm->release(es->root_dm); - if (es->debug_data) - BKE_sim_debug_data_free(es->debug_data); } /* === constraints === */ -- cgit v1.2.3 From 20e960215a80a41fd7e9782d009531d8d9f827cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20T=C3=B6nne?= Date: Mon, 20 Apr 2015 12:59:01 +0200 Subject: Particle shapekey code is only in the gooseberry branch, disabled here. --- source/blender/blenkernel/intern/editstrands.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source/blender/blenkernel/intern') diff --git a/source/blender/blenkernel/intern/editstrands.c b/source/blender/blenkernel/intern/editstrands.c index 5dc0402ef19..642eee315b7 100644 --- a/source/blender/blenkernel/intern/editstrands.c +++ b/source/blender/blenkernel/intern/editstrands.c @@ -175,7 +175,7 @@ BMesh *BKE_particles_to_bmesh(Object *ob, ParticleSystem *psys) if (psmd && psmd->dm) { DM_ensure_tessface(psmd->dm); - BM_strands_bm_from_psys(bm, ob, psys, psmd->dm, true, psys->shapenr); + BM_strands_bm_from_psys(bm, ob, psys, psmd->dm, true, /*psys->shapenr*/ -1); editstrands_calc_segment_lengths(bm); } -- cgit v1.2.3 From de5952c3d696fbb71365f20c66c14c22ac399477 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20T=C3=B6nne?= Date: Sun, 3 May 2015 11:53:51 +0200 Subject: Removed optimization by applying cache shrinkwrap modifier only in the realtime pass. As with hair sim, this would be preferable, but is causing too many problems with the current cache archive layout. --- source/blender/blenkernel/intern/cache_library.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'source/blender/blenkernel/intern') diff --git a/source/blender/blenkernel/intern/cache_library.c b/source/blender/blenkernel/intern/cache_library.c index b9ac9cd82b7..8d59020266c 100644 --- a/source/blender/blenkernel/intern/cache_library.c +++ b/source/blender/blenkernel/intern/cache_library.c @@ -1110,7 +1110,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 +1167,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 frame, int frame_prev, eCacheLibrary_EvalMode UNUSED(eval_mode)) { Object *ob = smd->object; DupliObject *dob; @@ -1177,10 +1177,6 @@ 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; -- cgit v1.2.3 From dbc4be381d4fb44d2915d6d78588fa860cff8bd1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20T=C3=B6nne?= Date: Sun, 3 May 2015 12:13:03 +0200 Subject: New cache modifier type "Strands Key" for implementing shape keys on cached strands data. This modifier acts as a container for shape key data (i.e. as part of the cache library). Such shape data can be applied to cached strands data, which allows tweaking of animated hair shapes. This could work both as a shape for the strand goals (adding dynamics on top) or as a final modification after dynamics. Both methods have their advantages (pre-sim allows control and sim at the same time, post-sim gives accurate shapes but becomes rigid). --- source/blender/blenkernel/intern/cache_library.c | 47 ++++++++++++++++++++++++ 1 file changed, 47 insertions(+) (limited to 'source/blender/blenkernel/intern') diff --git a/source/blender/blenkernel/intern/cache_library.c b/source/blender/blenkernel/intern/cache_library.c index 8d59020266c..e5d781ead74 100644 --- a/source/blender/blenkernel/intern/cache_library.c +++ b/source/blender/blenkernel/intern/cache_library.c @@ -1218,11 +1218,58 @@ CacheModifierTypeInfo cacheModifierType_ShrinkWrap = { /* free */ (CacheModifier_FreeFunc)shrinkwrap_free, }; +/* ------------------------------------------------------------------------- */ + +static void strandskey_init(StrandsKeyCacheModifier *skmd) +{ + skmd->object = NULL; + skmd->hair_system = -1; +} + +static void strandskey_copy(StrandsKeyCacheModifier *UNUSED(skmd), StrandsKeyCacheModifier *UNUSED(tskmd)) +{ +} + +static void strandskey_free(StrandsKeyCacheModifier *UNUSED(skmd)) +{ +} + +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 frame, int frame_prev, eCacheLibrary_EvalMode UNUSED(eval_mode)) +{ + Object *ob = skmd->object; + Strands *strands; + + /* skip first step and potential backward steps */ + if (frame <= frame_prev) + return; + + if (!BKE_cache_modifier_find_strands(data->dupcache, ob, skmd->hair_system, NULL, &strands)) + return; +} + +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, +}; + 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); } /* ========================================================================= */ -- cgit v1.2.3 From 958e6b1f20436b7f6b9f3cef3928feef170789ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20T=C3=B6nne?= Date: Sun, 3 May 2015 12:44:49 +0200 Subject: Some NULL pointer checks in shape key code to ensure the Key struct can be used without a 'from' pointer. --- source/blender/blenkernel/intern/key.c | 68 +++++++++++++++++----------------- 1 file changed, 35 insertions(+), 33 deletions(-) (limited to 'source/blender/blenkernel/intern') diff --git a/source/blender/blenkernel/intern/key.c b/source/blender/blenkernel/intern/key.c index 3aea343ec5a..3d8950b941a 100644 --- a/source/blender/blenkernel/intern/key.c +++ b/source/blender/blenkernel/intern/key.c @@ -109,38 +109,40 @@ Key *BKE_key_add(ID *id) /* common function */ 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; + if (id) { + /* 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; + } } return key; @@ -514,7 +516,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 (GS(key->from->name) == ID_ME) { + if (key->from && GS(key->from->name) == ID_ME) { Mesh *me; BMVert *eve; BMIter iter; -- cgit v1.2.3 From ed81c38c975fae00f1ef11c0ea48a4e52a7feaf8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20T=C3=B6nne?= Date: Sun, 3 May 2015 13:46:38 +0200 Subject: Extended 'add' function for shape keys that allows passing a NULL pointer for 'from'. The Key DNA has some very old and largely deprecated legacy code that needs initializing, which requires either explicit info or deduction from an ID. The cache modifier creates keys in a new environment without an existing known ID type to deduce the data element settings from. --- source/blender/blenkernel/intern/key.c | 63 ++++++++++++++++------------------ 1 file changed, 30 insertions(+), 33 deletions(-) (limited to 'source/blender/blenkernel/intern') diff --git a/source/blender/blenkernel/intern/key.c b/source/blender/blenkernel/intern/key.c index 3d8950b941a..e29a5220744 100644 --- a/source/blender/blenkernel/intern/key.c +++ b/source/blender/blenkernel/intern/key.c @@ -68,11 +68,6 @@ #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 - void BKE_key_free(Key *key) { KeyBlock *kb; @@ -97,7 +92,7 @@ void BKE_key_free_nolib(Key *key) } } -Key *BKE_key_add(ID *id) /* common function */ +Key *BKE_key_add_ex(ID *from, char elemtype, char numelem, int elemsize) /* common function */ { Key *key; char *el; @@ -105,47 +100,49 @@ Key *BKE_key_add(ID *id) /* common function */ key = BKE_libblock_alloc(G.main, ID_KE, "Key"); key->type = KEY_NORMAL; - key->from = id; + key->from = from; key->uidgen = 1; + el = key->elemstr; + + el[0] = numelem; + el[1] = elemtype; + el[2] = 0; + + key->elemsize = elemsize; + + return key; +} + +Key *BKE_key_add(ID *id) +{ + /* XXX the code here uses some defines which will soon be deprecated... */ + char elemtype = IPO_FLOAT; + char numelem = 0; + int elemsize = 0; + if (id) { - /* 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; - + numelem = 3; + elemtype = IPO_FLOAT; + elemsize = 12; break; case ID_LT: - el = key->elemstr; - - el[0] = 3; - el[1] = IPO_FLOAT; - el[2] = 0; - - key->elemsize = 12; - + numelem = 3; + elemtype = IPO_FLOAT; + elemsize = 12; break; case ID_CU: - el = key->elemstr; - - el[0] = 4; - el[1] = IPO_BPOINT; - el[2] = 0; - - key->elemsize = 16; - + numelem = 4; + elemtype = IPO_BPOINT; + elemsize = 16; break; } } - return key; + return BKE_key_add_ex(id, elemtype, numelem, elemsize); } Key *BKE_key_copy(Key *key) -- cgit v1.2.3 From ba878a08803b78aa821ccf9f2089efebd02ae15f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20T=C3=B6nne?= Date: Sun, 3 May 2015 18:24:43 +0200 Subject: Main shape key implementation for cached strand data. This includes storage of the shape keys in a `Key` instance in the modifier data, and accompanying operators for adding, removing, moving, etc. shape keys, as well as the necessary UI code. --- source/blender/blenkernel/intern/cache_library.c | 43 +++++- source/blender/blenkernel/intern/key.c | 159 ++++++++++++++++++++++- 2 files changed, 194 insertions(+), 8 deletions(-) (limited to 'source/blender/blenkernel/intern') diff --git a/source/blender/blenkernel/intern/cache_library.c b/source/blender/blenkernel/intern/cache_library.c index e5d781ead74..cbb68e77448 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" @@ -59,6 +60,7 @@ #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" @@ -1224,14 +1226,18 @@ static void strandskey_init(StrandsKeyCacheModifier *skmd) { skmd->object = NULL; skmd->hair_system = -1; + + skmd->key = BKE_key_add_ex(NULL, IPO_FLOAT, 3, 12); } -static void strandskey_copy(StrandsKeyCacheModifier *UNUSED(skmd), StrandsKeyCacheModifier *UNUSED(tskmd)) +static void strandskey_copy(StrandsKeyCacheModifier *skmd, StrandsKeyCacheModifier *tskmd) { + tskmd->key = BKE_key_copy(skmd->key); } -static void strandskey_free(StrandsKeyCacheModifier *UNUSED(skmd)) +static void strandskey_free(StrandsKeyCacheModifier *skmd) { + BKE_key_free(skmd->key); } static void strandskey_foreach_id_link(StrandsKeyCacheModifier *skmd, CacheLibrary *cachelib, CacheModifier_IDWalkFunc walk, void *userdata) @@ -1264,6 +1270,39 @@ CacheModifierTypeInfo cacheModifierType_StrandsKey = { /* 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 = 0; + + if (key == NULL) { + key = skmd->key = BKE_key_add_ex(NULL, IPO_FLOAT, 3, 12); + key->type = KEY_RELATIVE; + 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; +} + void BKE_cache_modifier_init(void) { cache_modifier_type_set(eCacheModifierType_HairSimulation, &cacheModifierType_HairSimulation); diff --git a/source/blender/blenkernel/intern/key.c b/source/blender/blenkernel/intern/key.c index e29a5220744..29e71ec4a08 100644 --- a/source/blender/blenkernel/intern/key.c +++ b/source/blender/blenkernel/intern/key.c @@ -49,6 +49,7 @@ #include "DNA_meshdata_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" +#include "DNA_strands_types.h" #include "BKE_animsys.h" #include "BKE_curve.h" @@ -60,6 +61,7 @@ #include "BKE_library.h" #include "BKE_editmesh.h" #include "BKE_scene.h" +#include "BKE_strands.h" #include "RNA_access.h" @@ -1389,6 +1391,95 @@ 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 *UNUSED(strands), Key *key, KeyBlock *actkb, char *out, const int tot) +{ + KeyBlock *k[4]; + float t[4]; + int flag = 0; + + if (key->type == KEY_RELATIVE) { + /* XXX weights not supported for strands yet */ +#if 0 + WeightsArrayCache cache = {0, NULL}; + float **per_keyblock_weights ; + per_keyblock_weights = BKE_keyblock_get_per_block_weights(ob, key, &cache); + BKE_key_evaluate_relative(0, tot, tot, (char *)out, key, actkb, per_keyblock_weights, KEY_MODE_DUMMY); + BKE_keyblock_free_per_block_weights(key, per_keyblock_weights, &cache); +#else + BKE_key_evaluate_relative(0, tot, tot, (char *)out, key, actkb, NULL, KEY_MODE_DUMMY); +#endif + } + 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); + } + } +} + +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 = NULL /*get_weights_array(ob, actkb->vgroup, NULL)*/; + + cp_key(0, tot, tot, out, key, actkb, actkb, weights, 0); + + 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) +{ + return BKE_key_evaluate_strands_ex(strands, key, actkb, lock_shape, r_totelem, NULL, 0); +} + Key *BKE_key_from_object(Object *ob) { if (ob == NULL) return NULL; @@ -1759,6 +1850,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]) { @@ -1954,11 +2094,10 @@ void BKE_keyblock_update_from_offset(Object *ob, KeyBlock *kb, float (*ofs)[3]) * \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; @@ -2018,13 +2157,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 */ @@ -2033,6 +2172,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. */ -- cgit v1.2.3 From 699c280a3f474ed47c7fc861a41a01b9c8641381 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20T=C3=B6nne?= Date: Sun, 3 May 2015 19:19:43 +0200 Subject: Added a new "Modifiers" display mode for cache libraries, which reads the source cache and then applies modifiers afterward. This only performs non-iterative modifiers, which don't require the passage of time to work (e.g. shrinkwrap). --- source/blender/blenkernel/intern/cache_library.c | 10 +++------- source/blender/blenkernel/intern/object_dupli.c | 18 ++++++++++++++++++ 2 files changed, 21 insertions(+), 7 deletions(-) (limited to 'source/blender/blenkernel/intern') diff --git a/source/blender/blenkernel/intern/cache_library.c b/source/blender/blenkernel/intern/cache_library.c index cbb68e77448..cbb3cbfb51e 100644 --- a/source/blender/blenkernel/intern/cache_library.c +++ b/source/blender/blenkernel/intern/cache_library.c @@ -86,7 +86,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; @@ -321,7 +321,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; } @@ -344,7 +344,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); } @@ -1179,10 +1179,6 @@ static void shrinkwrap_process(ShrinkWrapCacheModifier *smd, CacheProcessContext ShrinkWrapCacheData shrinkwrap; - /* 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)) return; if (!BKE_cache_modifier_find_object(data->dupcache, smd->target, &target_data)) diff --git a/source/blender/blenkernel/intern/object_dupli.c b/source/blender/blenkernel/intern/object_dupli.c index 1574c4a36f8..b652128b2a0 100644 --- a/source/blender/blenkernel/intern/object_dupli.c +++ b/source/blender/blenkernel/intern/object_dupli.c @@ -1717,12 +1717,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 +1759,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; -- cgit v1.2.3 From 51260cbe71dcc4534dee43869e1f2feb3abf5f9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20T=C3=B6nne?= Date: Mon, 4 May 2015 12:57:26 +0200 Subject: Create a dummy weights array for strand keys, otherwise the eval function will exit early. --- source/blender/blenkernel/intern/key.c | 37 ++++++++++++++++++++++++++-------- 1 file changed, 29 insertions(+), 8 deletions(-) (limited to 'source/blender/blenkernel/intern') diff --git a/source/blender/blenkernel/intern/key.c b/source/blender/blenkernel/intern/key.c index 29e71ec4a08..c7ebdc2e426 100644 --- a/source/blender/blenkernel/intern/key.c +++ b/source/blender/blenkernel/intern/key.c @@ -1123,6 +1123,12 @@ static float *get_weights_array(Object *ob, char *vgroup, WeightsArrayCache *cac return NULL; } +static float *get_weights_array_strands(Strands *UNUSED(strands), const char *UNUSED(vgroup), WeightsArrayCache *UNUSED(cache)) +{ + /* TODO no vgroup support for strands yet */ + return NULL; +} + float **BKE_keyblock_get_per_block_weights(Object *ob, Key *key, WeightsArrayCache *cache) { KeyBlock *keyblock; @@ -1143,6 +1149,26 @@ float **BKE_keyblock_get_per_block_weights(Object *ob, Key *key, WeightsArrayCac 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, cache); + } + + return per_keyblock_weights; +} + void BKE_keyblock_free_per_block_weights(Key *key, float **per_keyblock_weights, WeightsArrayCache *cache) { int a; @@ -1391,23 +1417,18 @@ 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 *UNUSED(strands), Key *key, KeyBlock *actkb, char *out, const int tot) +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) { - /* XXX weights not supported for strands yet */ -#if 0 WeightsArrayCache cache = {0, NULL}; float **per_keyblock_weights ; - per_keyblock_weights = BKE_keyblock_get_per_block_weights(ob, key, &cache); + per_keyblock_weights = BKE_keyblock_strands_get_per_block_weights(strands, key, &cache); BKE_key_evaluate_relative(0, tot, tot, (char *)out, key, actkb, per_keyblock_weights, KEY_MODE_DUMMY); BKE_keyblock_free_per_block_weights(key, per_keyblock_weights, &cache); -#else - BKE_key_evaluate_relative(0, tot, tot, (char *)out, key, actkb, NULL, KEY_MODE_DUMMY); -#endif } else { const float ctime_scaled = key->ctime / 100.0f; @@ -1458,7 +1479,7 @@ float *BKE_key_evaluate_strands_ex(Strands *strands, Key *key, KeyBlock *actkb, actkb = key->refkey; /* XXX weights not supported for strands yet */ - weights = NULL /*get_weights_array(ob, actkb->vgroup, NULL)*/; + weights = get_weights_array_strands(strands, actkb->vgroup, NULL); cp_key(0, tot, tot, out, key, actkb, actkb, weights, 0); -- cgit v1.2.3 From 1e6e44fd24995279b26d3e670c9d13fd340a5d86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20T=C3=B6nne?= Date: Mon, 4 May 2015 12:59:34 +0200 Subject: New 'fromtype' variable in Key to allow handling type-dependent pointer size and stride. This is terribly messy due to the legacy code. At some point should be cleaned up to get rid of the 'from' backpointer and simplify. --- source/blender/blenkernel/intern/cache_library.c | 4 +- source/blender/blenkernel/intern/key.c | 141 +++++++++++++---------- 2 files changed, 84 insertions(+), 61 deletions(-) (limited to 'source/blender/blenkernel/intern') diff --git a/source/blender/blenkernel/intern/cache_library.c b/source/blender/blenkernel/intern/cache_library.c index cbb3cbfb51e..8876e3d77b3 100644 --- a/source/blender/blenkernel/intern/cache_library.c +++ b/source/blender/blenkernel/intern/cache_library.c @@ -1223,7 +1223,7 @@ static void strandskey_init(StrandsKeyCacheModifier *skmd) skmd->object = NULL; skmd->hair_system = -1; - skmd->key = BKE_key_add_ex(NULL, IPO_FLOAT, 3, 12); + skmd->key = BKE_key_add_ex(NULL, KEY_FROMTYPE_STRANDS); } static void strandskey_copy(StrandsKeyCacheModifier *skmd, StrandsKeyCacheModifier *tskmd) @@ -1273,7 +1273,7 @@ KeyBlock *BKE_cache_modifier_strands_key_insert_key(StrandsKeyCacheModifier *skm bool newkey = 0; if (key == NULL) { - key = skmd->key = BKE_key_add_ex(NULL, IPO_FLOAT, 3, 12); + key = skmd->key = BKE_key_add_ex(NULL, KEY_FROMTYPE_STRANDS); key->type = KEY_RELATIVE; newkey = true; } diff --git a/source/blender/blenkernel/intern/key.c b/source/blender/blenkernel/intern/key.c index c7ebdc2e426..4a88e9e4378 100644 --- a/source/blender/blenkernel/intern/key.c +++ b/source/blender/blenkernel/intern/key.c @@ -66,6 +66,11 @@ #include "RNA_access.h" +/* 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 @@ -94,57 +99,68 @@ void BKE_key_free_nolib(Key *key) } } -Key *BKE_key_add_ex(ID *from, char elemtype, char numelem, int elemsize) /* 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; key->from = from; + key->fromtype = fromtype; key->uidgen = 1; - el = key->elemstr; - - el[0] = numelem; - el[1] = elemtype; - el[2] = 0; - - key->elemsize = elemsize; + key_set_elemstr(from, fromtype, key->elemstr, &key->elemsize); return key; } Key *BKE_key_add(ID *id) { - /* XXX the code here uses some defines which will soon be deprecated... */ - char elemtype = IPO_FLOAT; - char numelem = 0; - int elemsize = 0; - - 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; - } - } - - return BKE_key_add_ex(id, elemtype, numelem, elemsize); + return BKE_key_add_ex(id, KEY_FROMTYPE_ID); } Key *BKE_key_copy(Key *key) @@ -547,35 +563,42 @@ 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) { - if (key->from == NULL) { - return false; - } - - switch (GS(key->from->name)) { - case ID_ME: - *ofs = sizeof(float) * 3; - *poinsize = *ofs; + 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 ID_LT: + *ofs = sizeof(float) * 3; + *poinsize = *ofs; + break; + case ID_CU: + if (mode == KEY_MODE_BPOINT) { + *ofs = sizeof(float) * 4; + *poinsize = *ofs; + } + else { + ofs[0] = sizeof(float) * 12; + *poinsize = (*ofs) / 3; + } + + break; + default: + BLI_assert(!"invalid 'key->from' ID type"); + return false; + } break; - case ID_LT: + + case KEY_FROMTYPE_STRANDS: *ofs = sizeof(float) * 3; *poinsize = *ofs; break; - case ID_CU: - if (mode == KEY_MODE_BPOINT) { - *ofs = sizeof(float) * 4; - *poinsize = *ofs; - } - else { - ofs[0] = sizeof(float) * 12; - *poinsize = (*ofs) / 3; - } - - break; - default: - BLI_assert(!"invalid 'key->from' ID type"); - return false; } - return true; } -- cgit v1.2.3 From 2df6da20aaf4cb35aa8c27d4aaf6eec627586a6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20T=C3=B6nne?= Date: Mon, 4 May 2015 13:01:08 +0200 Subject: Unused variables. --- source/blender/blenkernel/intern/cache_library.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source/blender/blenkernel/intern') diff --git a/source/blender/blenkernel/intern/cache_library.c b/source/blender/blenkernel/intern/cache_library.c index 8876e3d77b3..2ae5129078f 100644 --- a/source/blender/blenkernel/intern/cache_library.c +++ b/source/blender/blenkernel/intern/cache_library.c @@ -1169,7 +1169,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 UNUSED(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; -- cgit v1.2.3 From de125950f50983bfe9cde3ff7bdac2bbd74ef39d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20T=C3=B6nne?= Date: Mon, 4 May 2015 13:01:30 +0200 Subject: Make strand shapes relative by default. --- source/blender/blenkernel/intern/cache_library.c | 1 + 1 file changed, 1 insertion(+) (limited to 'source/blender/blenkernel/intern') diff --git a/source/blender/blenkernel/intern/cache_library.c b/source/blender/blenkernel/intern/cache_library.c index 2ae5129078f..22f81a3a08c 100644 --- a/source/blender/blenkernel/intern/cache_library.c +++ b/source/blender/blenkernel/intern/cache_library.c @@ -1224,6 +1224,7 @@ static void strandskey_init(StrandsKeyCacheModifier *skmd) 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) -- cgit v1.2.3 From 1ea8324a71904a7e5c5be79e2aa441e40abf9e45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20T=C3=B6nne?= Date: Mon, 4 May 2015 13:04:41 +0200 Subject: Actual shape key evaluation in the shape key modifier for caches. --- source/blender/blenkernel/intern/cache_library.c | 26 +++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) (limited to 'source/blender/blenkernel/intern') diff --git a/source/blender/blenkernel/intern/cache_library.c b/source/blender/blenkernel/intern/cache_library.c index 22f81a3a08c..5fa0ead026e 100644 --- a/source/blender/blenkernel/intern/cache_library.c +++ b/source/blender/blenkernel/intern/cache_library.c @@ -1242,17 +1242,33 @@ static void strandskey_foreach_id_link(StrandsKeyCacheModifier *skmd, CacheLibra walk(userdata, cachelib, &skmd->modifier, (ID **)(&skmd->object)); } -static void strandskey_process(StrandsKeyCacheModifier *skmd, CacheProcessContext *UNUSED(ctx), CacheProcessData *data, int frame, int frame_prev, eCacheLibrary_EvalMode UNUSED(eval_mode)) +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; - - /* skip first step and potential backward steps */ - if (frame <= frame_prev) - return; + KeyBlock *actkb; + float *shape; if (!BKE_cache_modifier_find_strands(data->dupcache, ob, skmd->hair_system, NULL, &strands)) 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 = { -- cgit v1.2.3 From ed5de2ba08ab65cd17f09cdb816c0e6672f28025 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20T=C3=B6nne?= Date: Mon, 4 May 2015 13:05:06 +0200 Subject: Consider an empty keyblocks list to be a new key, so a Basis shape is added automatically. --- source/blender/blenkernel/intern/cache_library.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'source/blender/blenkernel/intern') diff --git a/source/blender/blenkernel/intern/cache_library.c b/source/blender/blenkernel/intern/cache_library.c index 5fa0ead026e..f18728208cb 100644 --- a/source/blender/blenkernel/intern/cache_library.c +++ b/source/blender/blenkernel/intern/cache_library.c @@ -1287,13 +1287,16 @@ KeyBlock *BKE_cache_modifier_strands_key_insert_key(StrandsKeyCacheModifier *skm { Key *key = skmd->key; KeyBlock *kb; - bool newkey = 0; + 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 */ -- cgit v1.2.3 From 556c25f14526d563cdae33d7ffa994e7cc8771e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20T=C3=B6nne?= Date: Mon, 4 May 2015 16:54:26 +0200 Subject: Extended shape key evaluation for cached strands blending. Now shape keys don't replace the cached base data entirely with the static Basis shape. Instead the current state as coming from the cache is interpreted as the variable refkey instead of the Basis key. The Basis key is in fact redundant, but removing it would require changing a lot of shared shapekey code, so it's left in for now. --- source/blender/blenkernel/intern/key.c | 87 ++++++++++++++++++++++++---------- 1 file changed, 62 insertions(+), 25 deletions(-) (limited to 'source/blender/blenkernel/intern') diff --git a/source/blender/blenkernel/intern/key.c b/source/blender/blenkernel/intern/key.c index 4a88e9e4378..91aabc122f1 100644 --- a/source/blender/blenkernel/intern/key.c +++ b/source/blender/blenkernel/intern/key.c @@ -602,7 +602,7 @@ static bool key_pointer_size(const Key *key, const int mode, int *poinsize, int 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; @@ -629,7 +629,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) { @@ -732,7 +737,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; @@ -741,7 +746,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; @@ -749,8 +754,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; @@ -775,7 +780,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 */ @@ -785,17 +791,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! @@ -850,6 +860,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) { @@ -1146,10 +1161,19 @@ static float *get_weights_array(Object *ob, char *vgroup, WeightsArrayCache *cac return NULL; } -static float *get_weights_array_strands(Strands *UNUSED(strands), const char *UNUSED(vgroup), WeightsArrayCache *UNUSED(cache)) +static float *get_weights_array_strands(Strands *strands, const char *UNUSED(vgroup), bool is_refkey, WeightsArrayCache *UNUSED(cache)) { - /* TODO no vgroup support for strands yet */ - return NULL; + 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_weights(Object *ob, Key *key, WeightsArrayCache *cache) @@ -1186,7 +1210,7 @@ float **BKE_keyblock_strands_get_per_block_weights(Strands *strands, Key *key, W keyblock; keyblock = keyblock->next, keyblock_index++) { - per_keyblock_weights[keyblock_index] = get_weights_array_strands(strands, keyblock->vgroup, cache); + per_keyblock_weights[keyblock_index] = get_weights_array_strands(strands, keyblock->vgroup, keyblock == key->refkey, cache); } return per_keyblock_weights; @@ -1240,7 +1264,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); } } } @@ -1331,7 +1355,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); } } @@ -1414,7 +1438,7 @@ float *BKE_key_evaluate_object_ex( if (OB_TYPE_SUPPORT_VGROUP(ob->type)) { float *weights = get_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); } @@ -1450,7 +1474,7 @@ static void do_strands_key(Strands *strands, Key *key, KeyBlock *actkb, char *ou 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(0, tot, tot, (char *)out, key, actkb, per_keyblock_weights, KEY_MODE_DUMMY); + 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 { @@ -1462,7 +1486,7 @@ static void do_strands_key(Strands *strands, Key *key, KeyBlock *actkb, char *ou 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, out); } } } @@ -1502,9 +1526,9 @@ float *BKE_key_evaluate_strands_ex(Strands *strands, Key *key, KeyBlock *actkb, actkb = key->refkey; /* XXX weights not supported for strands yet */ - weights = get_weights_array_strands(strands, actkb->vgroup, NULL); + weights = get_weights_array_strands(strands, actkb->vgroup, actkb == key->refkey, NULL); - cp_key(0, tot, tot, out, key, actkb, actkb, weights, 0); + cp_key(0, tot, tot, out, key, actkb, actkb, weights, 0, out); if (weights) MEM_freeN(weights); @@ -1521,7 +1545,20 @@ float *BKE_key_evaluate_strands_ex(Strands *strands, Key *key, KeyBlock *actkb, float *BKE_key_evaluate_strands(Strands *strands, Key *key, KeyBlock *actkb, bool lock_shape, int *r_totelem) { - return BKE_key_evaluate_strands_ex(strands, key, actkb, lock_shape, r_totelem, NULL, 0); + 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; } Key *BKE_key_from_object(Object *ob) -- cgit v1.2.3 From 16b6d6c676a8222361bbebce4624f256d0c0a05a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20T=C3=B6nne?= Date: Mon, 4 May 2015 17:52:13 +0200 Subject: Added missing CD layer type name for MSurfaceSample. --- source/blender/blenkernel/intern/customdata.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source/blender/blenkernel/intern') diff --git a/source/blender/blenkernel/intern/customdata.c b/source/blender/blenkernel/intern/customdata.c index dd86d79a7b3..0c57cdce9d2 100644 --- a/source/blender/blenkernel/intern/customdata.c +++ b/source/blender/blenkernel/intern/customdata.c @@ -1331,7 +1331,7 @@ static const char *LAYERTYPENAMES[CD_NUMTYPES] = { /* 30-34 */ "CDSubSurfCrease", "CDOrigSpaceLoop", "CDPreviewLoopCol", "CDBMElemPyPtr", "CDPaintMask", /* 35-36 */ "CDGridPaintMask", "CDMVertSkin", /* 37-38 */ "CDFreestyleEdge", "CDFreestyleFace", - /* 39-41 */ "CDMLoopTangent", "CDTessLoopNormal", "CDCustomLoopNormal", + /* 39-42 */ "CDMLoopTangent", "CDTessLoopNormal", "CDCustomLoopNormal", "CDMSurfaceSample", }; -- cgit v1.2.3 From e0a780d9a76501744c16936448af2ab9cf6a7829 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20T=C3=B6nne?= Date: Tue, 5 May 2015 14:41:04 +0200 Subject: Strand edit functions for storing edit data in the Cache Shape Key modifier and editing in hair edit mode. --- source/blender/blenkernel/intern/cache_library.c | 47 ++++++++++++++++++-- source/blender/blenkernel/intern/editstrands.c | 56 ++++++++++++++++++++++-- 2 files changed, 96 insertions(+), 7 deletions(-) (limited to 'source/blender/blenkernel/intern') diff --git a/source/blender/blenkernel/intern/cache_library.c b/source/blender/blenkernel/intern/cache_library.c index f18728208cb..6fff1602296 100644 --- a/source/blender/blenkernel/intern/cache_library.c +++ b/source/blender/blenkernel/intern/cache_library.c @@ -57,6 +57,7 @@ #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" @@ -848,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; @@ -877,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; } @@ -951,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. @@ -1179,7 +1181,7 @@ static void shrinkwrap_process(ShrinkWrapCacheModifier *smd, CacheProcessContext ShrinkWrapCacheData shrinkwrap; - 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; @@ -1230,11 +1232,19 @@ static void strandskey_init(StrandsKeyCacheModifier *skmd) 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) @@ -1249,7 +1259,7 @@ static void strandskey_process(StrandsKeyCacheModifier *skmd, CacheProcessContex KeyBlock *actkb; float *shape; - if (!BKE_cache_modifier_find_strands(data->dupcache, ob, skmd->hair_system, NULL, &strands)) + if (!BKE_cache_modifier_find_strands(data->dupcache, ob, skmd->hair_system, NULL, &strands, NULL)) return; actkb = BLI_findlink(&skmd->key->block, skmd->shapenr); @@ -1319,6 +1329,35 @@ KeyBlock *BKE_cache_modifier_strands_key_insert_key(StrandsKeyCacheModifier *skm 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) +{ + 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; + return true; + } + } + } + + return false; +} + void BKE_cache_modifier_init(void) { cache_modifier_type_set(eCacheModifierType_HairSimulation, &cacheModifierType_HairSimulation); diff --git a/source/blender/blenkernel/intern/editstrands.c b/source/blender/blenkernel/intern/editstrands.c index 642eee315b7..741af51bdd9 100644 --- a/source/blender/blenkernel/intern/editstrands.c +++ b/source/blender/blenkernel/intern/editstrands.c @@ -34,12 +34,15 @@ #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" @@ -78,10 +81,20 @@ BMEditStrands *BKE_editstrands_copy(BMEditStrands *es) */ BMEditStrands *BKE_editstrands_from_object(Object *ob) { - ParticleSystem *psys = psys_get_current(ob); - if (psys) { - return psys->hairedit; + { + 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)) { + if (skmd->edit) + return skmd->edit; + } + } + return NULL; } @@ -161,6 +174,43 @@ void BKE_editstrands_ensure(BMEditStrands *es) } +/* === cache shape key conversion === */ + +BMesh *BKE_cache_strands_to_bmesh(struct Strands *strands, struct Key *key, 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, true, act_key_nr); + editstrands_calc_segment_lengths(bm); + + return bm; +} + +struct Strands *BKE_cache_strands_from_bmesh(BMEditStrands *edit, struct Key *key, 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, dm, &bvhtree); + + free_bvhtree_from_mesh(&bvhtree); + } + + return strands; +} + + /* === particle conversion === */ BMesh *BKE_particles_to_bmesh(Object *ob, ParticleSystem *psys) -- cgit v1.2.3 From 39ab4dab664616c42c98bb41e583846116582b1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20T=C3=B6nne?= Date: Tue, 5 May 2015 15:37:00 +0200 Subject: Take transformation into account between the duplicator and strands object. The strand edit mode uses the local space of the active object, which is the duplicator (and dupli cache owner). The strands data is in local space of the original particle system object however, so have to convert. This is a very hackish solution, using the first instance of the strands data, which only works for single instance data. --- source/blender/blenkernel/intern/cache_library.c | 25 +++++++++++++++++++++++- source/blender/blenkernel/intern/editstrands.c | 10 +++++----- 2 files changed, 29 insertions(+), 6 deletions(-) (limited to 'source/blender/blenkernel/intern') diff --git a/source/blender/blenkernel/intern/cache_library.c b/source/blender/blenkernel/intern/cache_library.c index 6fff1602296..74bdb027022 100644 --- a/source/blender/blenkernel/intern/cache_library.c +++ b/source/blender/blenkernel/intern/cache_library.c @@ -1329,7 +1329,7 @@ KeyBlock *BKE_cache_modifier_strands_key_insert_key(StrandsKeyCacheModifier *skm 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) +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; @@ -1350,6 +1350,29 @@ bool BKE_cache_modifier_strands_key_get(Object *ob, StrandsKeyCacheModifier **r_ 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; } } diff --git a/source/blender/blenkernel/intern/editstrands.c b/source/blender/blenkernel/intern/editstrands.c index 741af51bdd9..d2ba3248d69 100644 --- a/source/blender/blenkernel/intern/editstrands.c +++ b/source/blender/blenkernel/intern/editstrands.c @@ -89,7 +89,7 @@ BMEditStrands *BKE_editstrands_from_object(Object *ob) { StrandsKeyCacheModifier *skmd; - if (BKE_cache_modifier_strands_key_get(ob, &skmd, NULL, NULL, NULL, NULL)) { + if (BKE_cache_modifier_strands_key_get(ob, &skmd, NULL, NULL, NULL, NULL, NULL)) { if (skmd->edit) return skmd->edit; } @@ -176,7 +176,7 @@ void BKE_editstrands_ensure(BMEditStrands *es) /* === cache shape key conversion === */ -BMesh *BKE_cache_strands_to_bmesh(struct Strands *strands, struct Key *key, int act_key_nr, DerivedMesh *dm) +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; @@ -184,13 +184,13 @@ BMesh *BKE_cache_strands_to_bmesh(struct Strands *strands, struct Key *key, int DM_ensure_tessface(dm); bm = BM_mesh_create(&allocsize); - BM_strands_bm_from_strands(bm, strands, key, dm, true, act_key_nr); + 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, DerivedMesh *dm) +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; @@ -202,7 +202,7 @@ struct Strands *BKE_cache_strands_from_bmesh(BMEditStrands *edit, struct Key *ke bvhtree_from_mesh_faces(&bvhtree, dm, 0.0, 2, 6); - strands = BM_strands_bm_to_strands(bm, strands, key, dm, &bvhtree); + strands = BM_strands_bm_to_strands(bm, strands, key, mat, dm, &bvhtree); free_bvhtree_from_mesh(&bvhtree); } -- cgit v1.2.3 From 6534a7b9edfb563857f565a6c301d132e2c0b173 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Wed, 6 May 2015 10:12:46 +0200 Subject: Fix for threaded dupli cache generation from groups. Strands require a valid DerivedMesh for calculating their root matrix and surface mapping. The scheduler tasks were created such that strands would be calculated while the DM task was not finished yet, leading to missing DM data. --- source/blender/blenkernel/intern/object_dupli.c | 102 +++++++++++++----------- 1 file changed, 57 insertions(+), 45 deletions(-) (limited to 'source/blender/blenkernel/intern') diff --git a/source/blender/blenkernel/intern/object_dupli.c b/source/blender/blenkernel/intern/object_dupli.c index b652128b2a0..83985d4df7a 100644 --- a/source/blender/blenkernel/intern/object_dupli.c +++ b/source/blender/blenkernel/intern/object_dupli.c @@ -1601,13 +1601,55 @@ 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); + + 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 +1657,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 +1696,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); } } } -- cgit v1.2.3 From af7fe835ffeff094df994f5e3fd75735f0514d8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20T=C3=B6nne?= Date: Wed, 6 May 2015 11:13:36 +0200 Subject: Store MSurfaceSample data in hair strands for mapping to a mesh. This data is not strictly necessary for the strands drawing or rendering or even hair simulation, because the hair root offset and rotation is already cached explicitly. However, the strand edit mode needs this information to correctly apply length constraints. --- source/blender/blenkernel/intern/editstrands.c | 15 ++++++++++++++- source/blender/blenkernel/intern/object_dupli.c | 2 ++ 2 files changed, 16 insertions(+), 1 deletion(-) (limited to 'source/blender/blenkernel/intern') diff --git a/source/blender/blenkernel/intern/editstrands.c b/source/blender/blenkernel/intern/editstrands.c index d2ba3248d69..86e81925b58 100644 --- a/source/blender/blenkernel/intern/editstrands.c +++ b/source/blender/blenkernel/intern/editstrands.c @@ -55,13 +55,26 @@ #include "intern/bmesh_strands_conv.h" -BMEditStrands *BKE_editstrands_create(BMesh *bm, DerivedMesh *root_dm) +/* 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; } diff --git a/source/blender/blenkernel/intern/object_dupli.c b/source/blender/blenkernel/intern/object_dupli.c index 83985d4df7a..593bb30ec0c 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" @@ -1623,6 +1624,7 @@ static void dupli_strands_data_update(CacheLibrary *cachelib, DupliObjectData *d 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); -- cgit v1.2.3