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

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/blenkernel/intern/key.c')
-rw-r--r--source/blender/blenkernel/intern/key.c1008
1 files changed, 938 insertions, 70 deletions
diff --git a/source/blender/blenkernel/intern/key.c b/source/blender/blenkernel/intern/key.c
index 8427b17c01a..092dd90041f 100644
--- a/source/blender/blenkernel/intern/key.c
+++ b/source/blender/blenkernel/intern/key.c
@@ -45,34 +45,43 @@
#include "DNA_anim_types.h"
#include "DNA_key_types.h"
#include "DNA_lattice_types.h"
+#include "DNA_material_types.h"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
+#include "DNA_modifier_types.h"
#include "DNA_object_types.h"
+#include "DNA_particle_types.h"
#include "DNA_scene_types.h"
+#include "DNA_strands_types.h"
+#include "DNA_texture_types.h"
#include "BKE_animsys.h"
#include "BKE_curve.h"
#include "BKE_customdata.h"
#include "BKE_deform.h"
+#include "BKE_pointcache.h"
#include "BKE_global.h"
#include "BKE_key.h"
#include "BKE_lattice.h"
#include "BKE_library.h"
+#include "BKE_particle.h"
#include "BKE_editmesh.h"
#include "BKE_scene.h"
-
+#include "BKE_strands.h"
#include "RNA_access.h"
-#define KEY_MODE_DUMMY 0 /* use where mode isn't checked for */
-#define KEY_MODE_BPOINT 1
-#define KEY_MODE_BEZTRIPLE 2
+#include "RE_render_ext.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
+
void BKE_key_free(Key *key)
{
KeyBlock *kb;
@@ -97,55 +106,82 @@ void BKE_key_free_nolib(Key *key)
}
}
-Key *BKE_key_add(ID *id) /* common function */
+static void key_set_elemstr(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_OWNER_MESH:
+ numelem = 3;
+ elemtype = IPO_FLOAT;
+ elemsize = 12;
+ break;
+ case KEY_OWNER_LATTICE:
+ numelem = 3;
+ elemtype = IPO_FLOAT;
+ elemsize = 12;
+ break;
+ case KEY_OWNER_CURVE:
+ numelem = 4;
+ elemtype = IPO_BPOINT;
+ elemsize = 16;
+ break;
+ case KEY_OWNER_PARTICLES:
+ numelem = 3;
+ elemtype = IPO_FLOAT;
+ elemsize = 12;
+ break;
+ case KEY_OWNER_CACHELIB:
+ 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, int fromtype, int fromindex) /* common function */
{
Key *key;
- char *el;
key = BKE_libblock_alloc(G.main, ID_KE, "Key");
key->type = KEY_NORMAL;
- key->from = id;
+ key->from = from;
+ key->fromtype = fromtype;
+ key->fromindex = fromindex;
key->uidgen = 1;
- /* XXX the code here uses some defines which will soon be deprecated... */
- switch (GS(id->name)) {
- case ID_ME:
- el = key->elemstr;
-
- el[0] = 3;
- el[1] = IPO_FLOAT;
- el[2] = 0;
-
- key->elemsize = 12;
-
- break;
- case ID_LT:
- el = key->elemstr;
-
- el[0] = 3;
- el[1] = IPO_FLOAT;
- el[2] = 0;
-
- key->elemsize = 12;
-
- break;
- case ID_CU:
- el = key->elemstr;
-
- el[0] = 4;
- el[1] = IPO_BPOINT;
- el[2] = 0;
-
- key->elemsize = 16;
-
- break;
- }
+ key_set_elemstr(fromtype, key->elemstr, &key->elemsize);
return key;
}
+Key *BKE_key_add(ID *id)
+{
+ int fromtype = 0;
+ switch (GS(id->name)) {
+ case ID_ME: fromtype = KEY_OWNER_MESH; break;
+ case ID_CU: fromtype = KEY_OWNER_CURVE; break;
+ case ID_LT: fromtype = KEY_OWNER_LATTICE; break;
+ default: BLI_assert(false); break; /* other fromtypes should use the _ex version for specifying the type */
+ }
+ return BKE_key_add_ex(id, fromtype, -1);
+}
+
+Key *BKE_key_add_particles(Object *ob, ParticleSystem *psys) /* particles are "special" */
+{
+ return BKE_key_add_ex((ID *)ob, KEY_OWNER_PARTICLES, BLI_findindex(&ob->particlesystem, psys));
+}
+
Key *BKE_key_copy(Key *key)
{
Key *keyn;
@@ -250,6 +286,28 @@ void BKE_key_sort(Key *key)
key->refkey = key->block.first;
}
+void BKE_key_set_from_id(Key *key, ID *id)
+{
+ if (key) {
+ key->from = id;
+ switch (GS(id->name)) {
+ case ID_ME: key->fromtype = KEY_OWNER_MESH; break;
+ case ID_CU: key->fromtype = KEY_OWNER_CURVE; break;
+ case ID_LT: key->fromtype = KEY_OWNER_LATTICE; break;
+ }
+ key->fromindex = -1;
+ }
+}
+
+void BKE_key_set_from_particles(Key *key, Object *ob, ParticleSystem *psys)
+{
+ if (key) {
+ key->from = (ID *)ob;
+ key->fromtype = KEY_OWNER_PARTICLES;
+ key->fromindex = BLI_findindex(&ob->particlesystem, psys);
+ }
+}
+
/**************** do the key ****************/
void key_curve_position_weights(float t, float data[4], int type)
@@ -514,7 +572,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 && key->fromtype == KEY_OWNER_MESH) {
Mesh *me;
BMVert *eve;
BMIter iter;
@@ -546,20 +604,20 @@ 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) {
+ /* some types allow NULL for key->from */
+ if (!key->from && !ELEM(key->fromtype, KEY_OWNER_CACHELIB))
return false;
- }
-
- switch (GS(key->from->name)) {
- case ID_ME:
+
+ switch (key->fromtype) {
+ case KEY_OWNER_MESH:
*ofs = sizeof(float) * 3;
*poinsize = *ofs;
break;
- case ID_LT:
+ case KEY_OWNER_LATTICE:
*ofs = sizeof(float) * 3;
*poinsize = *ofs;
break;
- case ID_CU:
+ case KEY_OWNER_CURVE:
if (mode == KEY_MODE_BPOINT) {
*ofs = sizeof(float) * 4;
*poinsize = *ofs;
@@ -568,13 +626,20 @@ static bool key_pointer_size(const Key *key, const int mode, int *poinsize, int
ofs[0] = sizeof(float) * 12;
*poinsize = (*ofs) / 3;
}
-
break;
+ case KEY_OWNER_PARTICLES:
+ *ofs = sizeof(float) * 3;
+ *poinsize = *ofs;
+ break;
+ case KEY_OWNER_CACHELIB:
+ *ofs = sizeof(float) * 3;
+ *poinsize = *ofs;
+ break;
+
default:
BLI_assert(!"invalid 'key->from' ID type");
return false;
}
-
return true;
}
@@ -696,6 +761,87 @@ static void cp_key(const int start, int end, const int tot, char *poin, Key *key
if (freekref) MEM_freeN(freekref);
}
+static void cp_key_strands(const int start, int end, const int tot, char *poin, Key *key, KeyBlock *actkb, KeyBlock *kb, float *weights, const int mode)
+{
+ float ktot = 0.0, kd = 0.0;
+ int elemsize, poinsize = 0, a, ofs, flagflo = 0;
+ char *k1, *freek1;
+
+ /* currently always 0, in future key_pointer_size may assign */
+ ofs = 0;
+
+ if (!key_pointer_size(key, mode, &poinsize, &ofs))
+ return;
+
+ if (end > tot) end = tot;
+
+ if (tot != kb->totelem) {
+ ktot = 0.0;
+ flagflo = 1;
+ if (kb->totelem) {
+ kd = kb->totelem / (float)tot;
+ }
+ else {
+ return;
+ }
+ }
+
+ k1 = key_block_get_data(key, actkb, kb, &freek1);
+
+ /* this exception is needed curves with multiple splines */
+ if (start != 0) {
+
+ poin += poinsize * start;
+
+ if (flagflo) {
+ ktot += start * kd;
+ a = (int)floor(ktot);
+ if (a) {
+ ktot -= a;
+ k1 += a * key->elemsize;
+ }
+ }
+ else {
+ k1 += start * key->elemsize;
+ }
+ }
+
+ /* just do it here, not above! */
+ elemsize = key->elemsize;
+ if (mode == KEY_MODE_BEZTRIPLE) elemsize *= 3;
+
+ for (a = start; a < end; a++) {
+ if (weights) {
+ if (*weights != 0.0f)
+ madd_v3_v3fl((float *)poin, (float *)k1, *weights);
+ weights++;
+ }
+ else {
+ add_v3_v3((float *)poin, (float *)k1);
+ }
+
+ poin += ofs;
+
+ /* are we going to be nasty? */
+ if (flagflo) {
+ ktot += kd;
+ while (ktot >= 1.0f) {
+ ktot -= 1.0f;
+ k1 += elemsize;
+ }
+ }
+ else {
+ k1 += elemsize;
+ }
+
+ if (mode == KEY_MODE_BEZTRIPLE) {
+ a += 2;
+ }
+ }
+
+ if (freek1) MEM_freeN(freek1);
+}
+
static void cp_cu_key(Curve *cu, Key *key, KeyBlock *actkb, KeyBlock *kb, const int start, int end, char *out, const int tot)
{
Nurb *nu;
@@ -730,7 +876,8 @@ void BKE_key_evaluate_relative(const int start, int end, const int tot, char *ba
{
KeyBlock *kb;
int *ofsp, ofs[3], elemsize, b;
- char *cp, *poin, *reffrom, *from, elemstr[8];
+ char *poin, *reffrom, *from;
+ char elemstr[8];
int poinsize, keyblock_index;
/* currently always 0, in future key_pointer_size may assign */
@@ -761,23 +908,25 @@ 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);
+ {
+ /* 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!
from += key->elemsize * start;
for (b = start; b < end; b++) {
+ char *cp;
weight = weights ? (*weights * icuval) : icuval;
@@ -826,6 +975,57 @@ void BKE_key_evaluate_relative(const int start, int end, const int tot, char *ba
}
}
+void BKE_key_evaluate_strands_relative(const int start, int end, const int tot, char *basispoin, Key *key, KeyBlock *actkb,
+ float **per_keyblock_weights, const int mode)
+{
+ KeyBlock *kb;
+ int ofs, elemsize, b;
+ char *poin, *from;
+ int poinsize, keyblock_index;
+
+ if (!key_pointer_size(key, mode, &poinsize, &ofs))
+ return;
+
+ if (end > tot) end = tot;
+
+ /* just here, not above! */
+ elemsize = key->elemsize;
+ if (mode == KEY_MODE_BEZTRIPLE) elemsize *= 3;
+
+ for (kb = key->block.first, keyblock_index = 0; kb; kb = kb->next, keyblock_index++) {
+ if (kb != key->refkey) {
+ float icuval = kb->curval;
+
+ /* only with value, and no difference allowed */
+ if (!(kb->flag & KEYBLOCK_MUTE) && icuval != 0.0f && kb->totelem == tot) {
+ float weight, *weights = per_keyblock_weights ? per_keyblock_weights[keyblock_index] : NULL;
+ char *freefrom = NULL;
+
+ poin = basispoin;
+ from = key_block_get_data(key, actkb, kb, &freefrom);
+
+ poin += start * poinsize;
+ from += key->elemsize * start;
+
+ for (b = start; b < end; b++) {
+ float delta[3];
+
+ weight = weights ? (*weights * icuval) : icuval;
+
+ sub_v3_v3v3(delta, (float *)from, (float *)poin);
+ madd_v3_v3fl((float *)poin, delta, weight);
+
+ poin += ofs;
+ from += elemsize;
+ if (mode == KEY_MODE_BEZTRIPLE) b += 2;
+ if (weights) weights++;
+ }
+
+ if (freefrom) MEM_freeN(freefrom);
+ }
+ }
+ }
+}
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)
{
@@ -1052,7 +1252,199 @@ static void do_key(const int start, int end, const int tot, char *poin, Key *key
if (freek4) MEM_freeN(freek4);
}
-static float *get_weights_array(Object *ob, char *vgroup, WeightsArrayCache *cache)
+static void do_key_strands(const int start, int end, const int tot, char *poin, Key *key, KeyBlock *actkb, KeyBlock **k, float *t, const int mode)
+{
+ float k1tot = 0.0, k2tot = 0.0, k3tot = 0.0, k4tot = 0.0;
+ float k1d = 0.0, k2d = 0.0, k3d = 0.0, k4d = 0.0;
+ int a, ofs;
+ int flagdo = 15, flagflo = 0, elemsize, poinsize = 0;
+ char *k1, *k2, *k3, *k4, *freek1, *freek2, *freek3, *freek4;
+
+ /* currently always 0, in future key_pointer_size may assign */
+ if (!key_pointer_size(key, mode, &poinsize, &ofs))
+ return;
+
+ if (end > tot) end = tot;
+
+ k1 = key_block_get_data(key, actkb, k[0], &freek1);
+ k2 = key_block_get_data(key, actkb, k[1], &freek2);
+ k3 = key_block_get_data(key, actkb, k[2], &freek3);
+ k4 = key_block_get_data(key, actkb, k[3], &freek4);
+
+ /* test for more or less points (per key!) */
+ if (tot != k[0]->totelem) {
+ k1tot = 0.0;
+ flagflo |= 1;
+ if (k[0]->totelem) {
+ k1d = k[0]->totelem / (float)tot;
+ }
+ else {
+ flagdo -= 1;
+ }
+ }
+ if (tot != k[1]->totelem) {
+ k2tot = 0.0;
+ flagflo |= 2;
+ if (k[0]->totelem) {
+ k2d = k[1]->totelem / (float)tot;
+ }
+ else {
+ flagdo -= 2;
+ }
+ }
+ if (tot != k[2]->totelem) {
+ k3tot = 0.0;
+ flagflo |= 4;
+ if (k[0]->totelem) {
+ k3d = k[2]->totelem / (float)tot;
+ }
+ else {
+ flagdo -= 4;
+ }
+ }
+ if (tot != k[3]->totelem) {
+ k4tot = 0.0;
+ flagflo |= 8;
+ if (k[0]->totelem) {
+ k4d = k[3]->totelem / (float)tot;
+ }
+ else {
+ flagdo -= 8;
+ }
+ }
+
+ /* this exception is needed for curves with multiple splines */
+ if (start != 0) {
+
+ poin += poinsize * start;
+
+ if (flagdo & 1) {
+ if (flagflo & 1) {
+ k1tot += start * k1d;
+ a = (int)floor(k1tot);
+ if (a) {
+ k1tot -= a;
+ k1 += a * key->elemsize;
+ }
+ }
+ else {
+ k1 += start * key->elemsize;
+ }
+ }
+ if (flagdo & 2) {
+ if (flagflo & 2) {
+ k2tot += start * k2d;
+ a = (int)floor(k2tot);
+ if (a) {
+ k2tot -= a;
+ k2 += a * key->elemsize;
+ }
+ }
+ else {
+ k2 += start * key->elemsize;
+ }
+ }
+ if (flagdo & 4) {
+ if (flagflo & 4) {
+ k3tot += start * k3d;
+ a = (int)floor(k3tot);
+ if (a) {
+ k3tot -= a;
+ k3 += a * key->elemsize;
+ }
+ }
+ else {
+ k3 += start * key->elemsize;
+ }
+ }
+ if (flagdo & 8) {
+ if (flagflo & 8) {
+ k4tot += start * k4d;
+ a = (int)floor(k4tot);
+ if (a) {
+ k4tot -= a;
+ k4 += a * key->elemsize;
+ }
+ }
+ else {
+ k4 += start * key->elemsize;
+ }
+ }
+
+ }
+
+ /* only here, not above! */
+ elemsize = key->elemsize;
+ if (mode == KEY_MODE_BEZTRIPLE) elemsize *= 3;
+
+ for (a = start; a < end; a++) {
+
+ zero_v3((float *)poin);
+ madd_v3_v3fl((float *)poin, (float *)k1, t[0]);
+ madd_v3_v3fl((float *)poin, (float *)k2, t[1]);
+ madd_v3_v3fl((float *)poin, (float *)k3, t[2]);
+ madd_v3_v3fl((float *)poin, (float *)k4, t[3]);
+
+ poin += ofs;
+
+ /* lets do it the difficult way: when keys have a different size */
+ if (flagdo & 1) {
+ if (flagflo & 1) {
+ k1tot += k1d;
+ while (k1tot >= 1.0f) {
+ k1tot -= 1.0f;
+ k1 += elemsize;
+ }
+ }
+ else k1 += elemsize;
+ }
+ if (flagdo & 2) {
+ if (flagflo & 2) {
+ k2tot += k2d;
+ while (k2tot >= 1.0f) {
+ k2tot -= 1.0f;
+ k2 += elemsize;
+ }
+ }
+ else {
+ k2 += elemsize;
+ }
+ }
+ if (flagdo & 4) {
+ if (flagflo & 4) {
+ k3tot += k3d;
+ while (k3tot >= 1.0f) {
+ k3tot -= 1.0f;
+ k3 += elemsize;
+ }
+ }
+ else {
+ k3 += elemsize;
+ }
+ }
+ if (flagdo & 8) {
+ if (flagflo & 8) {
+ k4tot += k4d;
+ while (k4tot >= 1.0f) {
+ k4tot -= 1.0f;
+ k4 += elemsize;
+ }
+ }
+ else {
+ k4 += elemsize;
+ }
+ }
+
+ if (mode == KEY_MODE_BEZTRIPLE) a += 2;
+ }
+
+ if (freek1) MEM_freeN(freek1);
+ if (freek2) MEM_freeN(freek2);
+ if (freek3) MEM_freeN(freek3);
+ if (freek4) MEM_freeN(freek4);
+}
+
+static float *get_object_weights_array(Object *ob, char *vgroup, WeightsArrayCache *cache)
{
MDeformVert *dvert = NULL;
BMEditMesh *em = NULL;
@@ -1124,7 +1516,109 @@ static float *get_weights_array(Object *ob, char *vgroup, WeightsArrayCache *cac
return NULL;
}
-float **BKE_keyblock_get_per_block_weights(Object *ob, Key *key, WeightsArrayCache *cache)
+static float *get_weights_array_strands(Strands *strands, const char *UNUSED(vgroup), bool is_refkey, WeightsArrayCache *UNUSED(cache))
+{
+ int totvert = strands->totverts;
+
+ if (is_refkey) {
+ /* for the refkey, return zero weights, so the refkey actually uses the unmodified data */
+ float *weights = MEM_callocN(totvert * sizeof(float), "weights");
+ return weights;
+ }
+ else {
+ /* TODO no vgroup support for strands yet */
+ return NULL;
+ }
+}
+
+float **BKE_keyblock_get_per_block_object_weights(Object *ob, Key *key, WeightsArrayCache *cache)
+{
+ KeyBlock *keyblock;
+ 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_object_weights_array(ob, keyblock->vgroup, cache);
+ }
+
+ return per_keyblock_weights;
+}
+
+static int particle_count_keys(ParticleSystem *psys)
+{
+ ParticleData *pa;
+ int p;
+ int totkey = 0;
+ for (p = 0, pa = psys->particles; p < psys->totpart; ++p, ++pa) {
+ totkey += pa->totkey;
+ }
+ return totkey;
+}
+
+static float *get_particle_weights_array(Object *ob, ParticleSystem *psys, const char *name, float cfra)
+{
+ ParticleSettings *part = psys->part;
+ ParticleSimulationData sim;
+ MTex **mtexp;
+ int m, i, p, k;
+ int totvert = 0;
+ float *weights = NULL;
+
+ sim.scene = NULL;
+ sim.ob = ob;
+ sim.psys = psys;
+ sim.psmd = psys_get_modifier(ob, psys);
+
+ for (m = 0, mtexp = part->mtex; m < MAX_MTEX; ++m, ++mtexp) {
+ MTex *mtex = *mtexp;
+ if (mtex && (mtex->mapto & PAMAP_SHAPEKEY) && STREQ(mtex->shapekey, name)) {
+ const float def = mtex->def_var;
+ const short blend = mtex->blendtype;
+
+ ParticleData *pa;
+ float value, rgba[4];
+
+ /* lazy init */
+ if (!weights) {
+ totvert = particle_count_keys(psys);
+ weights = MEM_mallocN(totvert * sizeof(float), "weights");
+ for (i = 0; i < totvert; ++i)
+ weights[i] = 1.0f;
+ }
+
+ i = 0;
+ for (p = 0, pa = psys->particles; p < psys->totpart; ++p, ++pa) {
+ if (particle_mtex_eval(&sim, mtex, pa, cfra, &value, rgba)) {
+ /* weight is the same for all hair keys,
+ * only need to evaluate the texture once!
+ */
+ float result = texture_value_blend(def, weights[i], value, mtex->shapefac, blend);
+ for (k = 0; k < pa->totkey; ++k) {
+ weights[i + k] = result;
+ }
+ }
+
+ i += pa->totkey;
+ }
+ }
+ }
+
+ if (weights) {
+ for (i = 0; i < totvert; ++i)
+ CLAMP(weights[i], 0.0f, 1.0f);
+ }
+
+ return weights;
+}
+
+float **BKE_keyblock_get_per_block_particle_weights(Object *ob, ParticleSystem *psys, float cfra, Key *key, WeightsArrayCache *UNUSED(cache))
{
KeyBlock *keyblock;
float **per_keyblock_weights;
@@ -1138,7 +1632,27 @@ float **BKE_keyblock_get_per_block_weights(Object *ob, Key *key, WeightsArrayCac
keyblock;
keyblock = keyblock->next, keyblock_index++)
{
- per_keyblock_weights[keyblock_index] = get_weights_array(ob, keyblock->vgroup, cache);
+ per_keyblock_weights[keyblock_index] = get_particle_weights_array(ob, psys, keyblock->name, cfra);
+ }
+
+ return per_keyblock_weights;
+}
+
+float **BKE_keyblock_strands_get_per_block_weights(Strands *strands, Key *key, WeightsArrayCache *cache)
+{
+ KeyBlock *keyblock;
+ float **per_keyblock_weights;
+ int keyblock_index;
+
+ per_keyblock_weights =
+ MEM_mallocN(sizeof(*per_keyblock_weights) * key->totkey,
+ "per keyblock weights");
+
+ for (keyblock = key->block.first, keyblock_index = 0;
+ keyblock;
+ keyblock = keyblock->next, keyblock_index++)
+ {
+ per_keyblock_weights[keyblock_index] = get_weights_array_strands(strands, keyblock->vgroup, keyblock == key->refkey, cache);
}
return per_keyblock_weights;
@@ -1179,7 +1693,7 @@ static void do_mesh_key(Object *ob, Key *key, char *out, const int tot)
if (key->type == KEY_RELATIVE) {
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_get_per_block_object_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);
}
@@ -1270,7 +1784,7 @@ static void do_latt_key(Object *ob, Key *key, char *out, const int tot)
if (key->type == KEY_RELATIVE) {
float **per_keyblock_weights;
- per_keyblock_weights = BKE_keyblock_get_per_block_weights(ob, key, NULL);
+ per_keyblock_weights = BKE_keyblock_get_per_block_object_weights(ob, key, NULL);
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, NULL);
}
@@ -1290,6 +1804,32 @@ static void do_latt_key(Object *ob, Key *key, char *out, const int tot)
if (lt->flag & LT_OUTSIDE) outside_lattice(lt);
}
+static void do_psys_key(Object *ob, ParticleSystem *psys, float cfra, Key *key, char *out, const int tot)
+{
+ KeyBlock *k[4], *actkb = BKE_keyblock_from_particles(psys);
+ float t[4];
+ int flag = 0;
+
+ if (key->type == KEY_RELATIVE) {
+ WeightsArrayCache cache = {0, NULL};
+ float **per_keyblock_weights;
+
+ per_keyblock_weights = BKE_keyblock_get_per_block_particle_weights(ob, psys, cfra, 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 {
+ 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);
+ }
+}
+
/* returns key coordinates (+ tilt) when key applied, NULL otherwise */
float *BKE_key_evaluate_object_ex(
Object *ob, int *r_totelem,
@@ -1349,7 +1889,7 @@ float *BKE_key_evaluate_object_ex(
}
/* prevent python from screwing this up? anyhoo, the from pointer could be dropped */
- key->from = (ID *)ob->data;
+ BKE_key_set_from_id(key, (ID *)ob->data);
if (ob->shapeflag & OB_SHAPE_LOCK) {
/* shape locked, copy the locked shape instead of blending */
@@ -1364,7 +1904,7 @@ float *BKE_key_evaluate_object_ex(
}
if (OB_TYPE_SUPPORT_VGROUP(ob->type)) {
- float *weights = get_weights_array(ob, kb->vgroup, NULL);
+ float *weights = get_object_weights_array(ob, kb->vgroup, NULL);
cp_key(0, tot, tot, out, key, actkb, kb, weights, 0);
@@ -1392,6 +1932,196 @@ float *BKE_key_evaluate_object(Object *ob, int *r_totelem)
return BKE_key_evaluate_object_ex(ob, r_totelem, NULL, 0);
}
+static void do_strands_key(Strands *strands, Key *key, KeyBlock *actkb, char *out, const int tot)
+{
+ KeyBlock *k[4];
+ float t[4];
+ int flag = 0;
+
+ if (key->type == KEY_RELATIVE) {
+ WeightsArrayCache cache = {0, NULL};
+ float **per_keyblock_weights ;
+ per_keyblock_weights = BKE_keyblock_strands_get_per_block_weights(strands, key, &cache);
+ BKE_key_evaluate_strands_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 {
+ const float ctime_scaled = key->ctime / 100.0f;
+
+ flag = setkeys(ctime_scaled, &key->block, k, t, 0);
+
+ if (flag == 0) {
+ do_key_strands(0, tot, tot, (char *)out, key, actkb, k, t, KEY_MODE_DUMMY);
+ }
+ else {
+ cp_key_strands(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 = get_weights_array_strands(strands, actkb->vgroup, actkb == key->refkey, NULL);
+
+ cp_key_strands(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, bool use_motion)
+{
+ size_t size = sizeof(float) * 3 * strands->totverts;
+ float *data = MEM_mallocN(size, "strands shape key data");
+ float *result;
+ float *fp;
+ int i;
+
+ if (use_motion && strands->state) {
+ for (i = 0, fp = data; i < strands->totverts; ++i, fp += 3)
+ copy_v3_v3(fp, strands->state[i].co);
+ }
+ else {
+ for (i = 0, fp = data; i < strands->totverts; ++i, fp += 3)
+ copy_v3_v3(fp, strands->verts[i].co);
+ }
+
+ result = BKE_key_evaluate_strands_ex(strands, key, actkb, lock_shape, r_totelem, data, size);
+ if (result != data)
+ MEM_freeN(data);
+
+ return result;
+}
+
+/* returns key coordinates when key applied, NULL otherwise */
+float *BKE_key_evaluate_particles_ex(Object *ob, ParticleSystem *psys, float cfra, int *r_totelem,
+ float *arr, size_t arr_size)
+{
+ const bool use_editmode = (ob->mode & OB_MODE_PARTICLE_EDIT) && psys == psys_get_current(ob) && (psys->edit || psys->pointcache->edit) && !psys->renderdata;
+ Key *key = psys->key;
+ KeyBlock *actkb = BKE_keyblock_from_particles(psys);
+ char *out;
+ int tot = 0, size = 0;
+ int i;
+
+ if (key == NULL || BLI_listbase_is_empty(&key->block))
+ return NULL;
+
+ /* compute size of output array */
+ tot = 0;
+ for (i = 0; i < psys->totpart; ++i)
+ tot += psys->particles[i].totkey;
+ 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_object out");
+ }
+ else {
+ if (arr_size != size) {
+ return NULL;
+ }
+
+ out = (char *)arr;
+ }
+
+ /* prevent python from screwing this up? anyhoo, the from pointer could be dropped */
+ BKE_key_set_from_particles(key, ob, psys);
+
+ if (use_editmode) {
+ /* in edit mode, only evaluate the active shape */
+ KeyBlock *kb = BLI_findlink(&key->block, psys->shapenr - 1);
+
+ if (kb && (kb->flag & KEYBLOCK_MUTE))
+ kb = key->refkey;
+
+ if (kb == NULL) {
+ kb = key->block.first;
+ psys->shapenr = 1;
+ }
+
+ cp_key(0, tot, tot, out, key, actkb, kb, NULL, 0);
+ }
+ else if (ob->shapeflag & OB_SHAPE_LOCK) {
+ /* shape locked, copy the locked shape instead of blending */
+ KeyBlock *kb = BLI_findlink(&key->block, psys->shapenr - 1);
+ float *weights;
+
+ if (kb && (kb->flag & KEYBLOCK_MUTE))
+ kb = key->refkey;
+
+ if (kb == NULL) {
+ kb = key->block.first;
+ psys->shapenr = 1;
+ }
+
+ weights = get_particle_weights_array(ob, psys, kb->name, cfra);
+
+ cp_key(0, tot, tot, out, key, actkb, kb, weights, 0);
+
+ if (weights) MEM_freeN(weights);
+ }
+ else {
+ do_psys_key(ob, psys, cfra, key, out, tot);
+ }
+
+ if (r_totelem) {
+ *r_totelem = tot;
+ }
+ return (float *)out;
+}
+
+float *BKE_key_evaluate_particles(Object *ob, ParticleSystem *psys, float cfra, int *r_totelem)
+{
+ return BKE_key_evaluate_particles_ex(ob, psys, cfra, r_totelem, NULL, 0);
+}
+
Key **BKE_key_from_object_p(Object *ob)
{
if (ob == NULL)
@@ -1522,6 +2252,29 @@ KeyBlock *BKE_keyblock_from_object_reference(Object *ob)
return NULL;
}
+/* only the active keyblock */
+KeyBlock *BKE_keyblock_from_particles(ParticleSystem *psys)
+{
+ Key *key = psys->key;
+
+ if (key) {
+ KeyBlock *kb = BLI_findlink(&key->block, psys->shapenr - 1);
+ return kb;
+ }
+
+ return NULL;
+}
+
+KeyBlock *BKE_keyblock_from_particles_reference(ParticleSystem *psys)
+{
+ Key *key = psys->key;
+
+ if (key)
+ return key->refkey;
+
+ return NULL;
+}
+
/* get the appropriate KeyBlock given an index */
KeyBlock *BKE_keyblock_from_key(Key *key, int index)
{
@@ -1774,6 +2527,72 @@ void BKE_keyblock_convert_to_mesh(KeyBlock *kb, Mesh *me)
}
}
+/************************* Strands ************************/
+void BKE_keyblock_update_from_strands(Strands *strands, KeyBlock *kb, bool use_motion)
+{
+ float (*fp)[3];
+ int a, tot;
+
+ BLI_assert(strands->totverts == kb->totelem);
+
+ tot = strands->totverts;
+ if (tot == 0) return;
+
+ fp = kb->data;
+ /* use vertex locations as fallback, so we always get a valid shape */
+ if (use_motion && strands->state) {
+ StrandsMotionState *state = strands->state;
+ for (a = 0; a < tot; a++, fp++, state++) {
+ copy_v3_v3(*fp, state->co);
+ }
+ }
+ else {
+ StrandsVertex *vert = strands->verts;
+ 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, bool use_motion)
+{
+ 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, use_motion);
+}
+
+void BKE_keyblock_convert_to_strands(KeyBlock *kb, Strands *strands, bool use_motion)
+{
+ const float (*fp)[3];
+ int a, tot;
+
+ fp = kb->data;
+
+ tot = min_ii(kb->totelem, strands->totverts);
+
+ if (use_motion) {
+ if (strands->state) {
+ StrandsMotionState *state = strands->state;
+ for (a = 0; a < tot; a++, fp++, state++) {
+ copy_v3_v3(state->co, *fp);
+ }
+ }
+ }
+ else {
+ StrandsVertex *vert = strands->verts;
+ 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])
{
@@ -1960,6 +2779,48 @@ void BKE_keyblock_update_from_offset(Object *ob, KeyBlock *kb, float (*ofs)[3])
}
}
+/************************* Mesh ************************/
+
+void BKE_keyblock_convert_to_hair_keys(struct KeyBlock *kb, struct Object *UNUSED(ob), struct ParticleSystem *psys)
+{
+ ParticleData *pa;
+ HairKey *hkey;
+ float *fp;
+ int i, k;
+
+ fp = kb->data;
+ for (i = 0, pa = psys->particles; i < psys->totpart; ++i, ++pa) {
+ for (k = 0, hkey = pa->hair; k < pa->totkey; ++k, ++hkey) {
+ copy_v3_v3(hkey->co, fp);
+ fp += 3;
+ }
+ }
+}
+
+void BKE_keyblock_convert_from_hair_keys(struct Object *UNUSED(ob), struct ParticleSystem *psys, struct KeyBlock *kb)
+{
+ ParticleData *pa;
+ HairKey *hkey;
+ float *fp;
+ int i, k;
+
+ if (kb->data) MEM_freeN(kb->data);
+
+ kb->totelem = 0;
+ for (i = 0, pa = psys->particles; i < psys->totpart; ++i, ++pa) {
+ kb->totelem += pa->totkey;
+ }
+ kb->data = MEM_mallocN(psys->key->elemsize * kb->totelem, "kb->data");
+
+ fp = kb->data;
+ for (i = 0, pa = psys->particles; i < psys->totpart; ++i, ++pa) {
+ for (k = 0, hkey = pa->hair; k < pa->totkey; ++k, ++hkey) {
+ copy_v3_v3(fp, hkey->co);
+ fp += 3;
+ }
+ }
+}
+
/* ==========================================================*/
/** Move shape key from org_index to new_index. Safe, clamps index to valid range, updates reference keys,
@@ -1969,11 +2830,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;
@@ -2033,13 +2893,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 */
@@ -2048,6 +2908,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.
*/