diff options
Diffstat (limited to 'source/blender/blenkernel/intern/key.c')
-rw-r--r-- | source/blender/blenkernel/intern/key.c | 1008 |
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. */ |