Compare commits
113 Commits
temp-gpu-u
...
soc-2014-s
Author | SHA1 | Date | |
---|---|---|---|
e56beb5c5f | |||
2a88cabaab | |||
f93b0a746d | |||
a8c7a98826 | |||
0f91a7c528 | |||
ac49d2b7b9 | |||
4da6eed0d8 | |||
85b4c61b4e | |||
ed24379fcc | |||
53ae7384a6 | |||
e49550d73b | |||
4efb5bf5c6 | |||
2a72704c16 | |||
2420ffb7ef | |||
0288d50bc5 | |||
56da7947c9 | |||
4d6e11b87f | |||
bbb22f8036 | |||
33fb541e32 | |||
1628ab6960 | |||
b775a76d66 | |||
a0741a473b | |||
a8aa291e13 | |||
a5d52cf758 | |||
69b310c628 | |||
b04728785f | |||
f0f36eeef0 | |||
33ed259044 | |||
f59b30e41e | |||
0d7fd47878 | |||
e5a1c2ef65 | |||
e74279b77d | |||
1b7dadd6ba | |||
c597a1bb75 | |||
f838e3632d | |||
002cb94cc6 | |||
30099d8544 | |||
7038bdb159 | |||
b811398778 | |||
31c242fd0f | |||
c484f4cf8d | |||
8c221fb0bb | |||
cfc3adc80b | |||
aa3953c0cb | |||
cad1e40995 | |||
f43fb3ee82 | |||
b9893a8f6a | |||
bec0bd734e | |||
1a6c7a142e | |||
09d95bc8ca | |||
e3ccce5864 | |||
635b4e377b | |||
2939cda6b2 | |||
1fcb5e986a | |||
80fdc894ac | |||
860eed1f87 | |||
452374f8d2 | |||
ed52efdd35 | |||
4b4b1582eb | |||
002c747926 | |||
f2a996bbde | |||
236a578a87 | |||
8b4efc6283 | |||
52ce0e546e | |||
54d069b593 | |||
99e361ffd4 | |||
3b9e69cbdf | |||
4c56a47730 | |||
610a3e288e | |||
b01c944552 | |||
31a1d1cad4 | |||
5fea04bed0 | |||
f272a91113 | |||
4775345805 | |||
516038c983 | |||
ed01fea80a | |||
f3503448d3 | |||
edff9d3eda | |||
26efda7327 | |||
1f151d6319 | |||
cc05580813 | |||
7aeef37d54 | |||
8824482287 | |||
ab73b97928 | |||
4afcb68668 | |||
96e296c659 | |||
63a7fbe3a0 | |||
a48122cde5 | |||
aa009766d6 | |||
68e60b3cbb | |||
dd69bfae24 | |||
0c4fe0b50e | |||
ba3a78472a | |||
9492d96dc5 | |||
4c02209769 | |||
097178e8ea | |||
3e68ab7893 | |||
fa5dac46b7 | |||
82ad15d379 | |||
43fb821054 | |||
1e9b5a7076 | |||
3f5bfbbae5 | |||
e9c28ddbbd | |||
c6c9a279ab | |||
09694357dc | |||
32ae05b96c | |||
9674ed1b22 | |||
c804a4daeb | |||
268f7bedb5 | |||
3f8794a405 | |||
dad4b619f5 | |||
3c7b8f0086 | |||
2b3810f672 |
@@ -79,18 +79,22 @@ class MESH_UL_shape_keys(UIList):
|
||||
def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index):
|
||||
# assert(isinstance(item, bpy.types.ShapeKey))
|
||||
obj = active_data
|
||||
# key = data
|
||||
is_editmode = (obj.mode == 'EDIT')
|
||||
key = data
|
||||
key_block = item
|
||||
if self.layout_type in {'DEFAULT', 'COMPACT'}:
|
||||
split = layout.split(0.66, False)
|
||||
split.prop(key_block, "name", text="", emboss=False, icon_value=icon)
|
||||
row = split.row(align=True)
|
||||
if key_block.mute or (obj.mode == 'EDIT' and not (obj.use_shape_key_edit_mode and obj.type == 'MESH')):
|
||||
if key_block.mute or (is_editmode and not (obj.use_shape_key_edit_mode and obj.type == 'MESH')):
|
||||
row.active = False
|
||||
if not item.id_data.use_relative:
|
||||
if not key.use_relative:
|
||||
row.prop(key_block, "frame", text="", emboss=False)
|
||||
elif index > 0:
|
||||
row.prop(key_block, "value", text="", emboss=False)
|
||||
if is_editmode and not key.mix_from_animation:
|
||||
row.prop(key_block, "edit_mix_value", text="Temp", emboss=False)
|
||||
else:
|
||||
row.prop(key_block, "value", text="", emboss=False)
|
||||
else:
|
||||
row.label(text="")
|
||||
row.prop(key_block, "mute", text="", emboss=False)
|
||||
@@ -242,13 +246,9 @@ class DATA_PT_shape_keys(MeshButtonsPanel, Panel):
|
||||
ob = context.object
|
||||
key = ob.data.shape_keys
|
||||
kb = ob.active_shape_key
|
||||
ts = context.scene.tool_settings
|
||||
|
||||
enable_edit = ob.mode != 'EDIT'
|
||||
enable_edit_value = False
|
||||
|
||||
if ob.show_only_shape_key is False:
|
||||
if enable_edit or (ob.type == 'MESH' and ob.use_shape_key_edit_mode):
|
||||
enable_edit_value = True
|
||||
is_editmode = (ob.mode == 'EDIT')
|
||||
|
||||
row = layout.row()
|
||||
|
||||
@@ -273,18 +273,24 @@ class DATA_PT_shape_keys(MeshButtonsPanel, Panel):
|
||||
|
||||
split = layout.split(percentage=0.4)
|
||||
row = split.row()
|
||||
row.enabled = enable_edit
|
||||
row.enabled = not is_editmode
|
||||
row.prop(key, "use_relative")
|
||||
|
||||
row = split.row()
|
||||
# if is_editmode:
|
||||
# row.prop(ts, "kb_auto_commit", text = "Auto-commit")
|
||||
row.alignment = 'RIGHT'
|
||||
|
||||
sub = row.row(align=True)
|
||||
sub.label() # XXX, for alignment only
|
||||
subsub = sub.row(align=True)
|
||||
subsub.active = enable_edit_value
|
||||
subsub.prop(ob, "show_only_shape_key", text="")
|
||||
sub.prop(ob, "use_shape_key_edit_mode", text="")
|
||||
|
||||
if is_editmode:
|
||||
if ob.type == 'MESH':
|
||||
subsub.prop(key, "mix_from_animation", text="")
|
||||
subsub.prop(ob, "use_shape_key_edit_mode", text="")
|
||||
else:
|
||||
subsub.prop(ob, "show_only_shape_key", text="")
|
||||
|
||||
sub = row.row()
|
||||
if key.use_relative:
|
||||
@@ -295,19 +301,21 @@ class DATA_PT_shape_keys(MeshButtonsPanel, Panel):
|
||||
if key.use_relative:
|
||||
if ob.active_shape_key_index != 0:
|
||||
row = layout.row()
|
||||
row.active = enable_edit_value
|
||||
row.prop(kb, "value")
|
||||
if is_editmode and not key.mix_from_animation:
|
||||
row.prop(kb, "edit_mix_value", text="Temp Value")
|
||||
else:
|
||||
row.prop(kb, "value", text="Value")
|
||||
|
||||
split = layout.split()
|
||||
|
||||
col = split.column(align=True)
|
||||
col.active = enable_edit_value
|
||||
col.active = not is_editmode
|
||||
col.label(text="Range:")
|
||||
col.prop(kb, "slider_min", text="Min")
|
||||
col.prop(kb, "slider_max", text="Max")
|
||||
|
||||
col = split.column(align=True)
|
||||
col.active = enable_edit_value
|
||||
col.active = not is_editmode
|
||||
col.label(text="Blend:")
|
||||
col.prop_search(kb, "vertex_group", ob, "vertex_groups", text="")
|
||||
col.prop_search(kb, "relative_key", key, "key_blocks", text="")
|
||||
@@ -315,7 +323,7 @@ class DATA_PT_shape_keys(MeshButtonsPanel, Panel):
|
||||
else:
|
||||
layout.prop(kb, "interpolation")
|
||||
row = layout.column()
|
||||
row.active = enable_edit_value
|
||||
row.active = not is_editmode
|
||||
row.prop(key, "eval_time")
|
||||
row.prop(key, "slurph")
|
||||
|
||||
|
@@ -38,6 +38,8 @@ struct Scene;
|
||||
struct Object;
|
||||
struct BMEditMesh;
|
||||
struct Mesh;
|
||||
struct BMEditSelection;
|
||||
struct DerivedMesh;
|
||||
|
||||
/* crazyspace.c */
|
||||
float (*BKE_crazyspace_get_mapped_editverts(struct Scene *scene, struct Object *obedit))[3];
|
||||
@@ -48,6 +50,20 @@ void BKE_crazyspace_set_quats_mesh(struct Mesh *me, float (*origcos)[3], float (
|
||||
int BKE_sculpt_get_first_deform_matrices(struct Scene *scene, struct Object *ob, float (**deformmats)[3][3], float (**deformcos)[3]);
|
||||
void BKE_crazyspace_build_sculpt(struct Scene *scene, struct Object *ob, float (**deformmats)[3][3], float (**deformcos)[3]);
|
||||
|
||||
/* Returns true if the object's derived cage vertex indexes can be assumed to be in sync to
|
||||
* the editdata (base) vertex indexes */
|
||||
bool BKE_crazyspace_cageindexes_in_sync(struct Object *ob);
|
||||
|
||||
/* Maps editmesh vertex indexes to derivedmesh cage vertex indexes and returns the map.
|
||||
* If returns NULL, it means that mapping failed for some reason (modifier failing to set CD_ORIGINDEX, etc).
|
||||
* It is the caller's responsibility to free the returned array! */
|
||||
int *BKE_crazyspace_map_em_to_cage(struct BMEditMesh *em, struct DerivedMesh *cage_dm);
|
||||
|
||||
/* Calculates editmesh active element selection center in global space on derived cage
|
||||
* (used in calculating visual manipulator and transform constraint centers) */
|
||||
void BKE_crazyspace_cage_active_sel_center(struct BMEditSelection *active_sel, struct DerivedMesh *cage,
|
||||
int *derived_index_map, float *cent);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@@ -37,6 +37,7 @@ struct Mesh;
|
||||
struct Scene;
|
||||
struct DerivedMesh;
|
||||
struct MeshStatVis;
|
||||
struct MTopoHash;
|
||||
|
||||
/* ok: the EDBM module is for editmode bmesh stuff. in contrast, the
|
||||
* BMEdit module is for code shared with blenkernel that concerns
|
||||
@@ -94,6 +95,10 @@ void BKE_editmesh_update_linked_customdata(BMEditMesh *em);
|
||||
void BKE_editmesh_color_free(BMEditMesh *em);
|
||||
void BKE_editmesh_color_ensure(BMEditMesh *em, const char htype);
|
||||
|
||||
/* Topology hash compute/check. */
|
||||
void BKE_editmesh_topohash_compute(BMEditMesh *em, struct MTopoHash **topohash);
|
||||
bool BKE_editmesh_topohash_identity(BMEditMesh *em, struct MTopoHash *topohash, const bool do_update);
|
||||
|
||||
/* editderivedmesh.c */
|
||||
/* should really be defined in editmesh.c, but they use 'EditDerivedBMesh' */
|
||||
void BKE_editmesh_statvis_calc(BMEditMesh *em, struct DerivedMesh *dm,
|
||||
|
@@ -166,6 +166,7 @@ enum {
|
||||
#define G_FILE_HISTORY (1 << 25)
|
||||
#define G_FILE_MESH_COMPAT (1 << 26) /* BMesh option to save as older mesh format */
|
||||
#define G_FILE_SAVE_COPY (1 << 27) /* restore paths after editing them */
|
||||
#define G_FILE_SHAPEKEY_COMPAT (1 << 28) /* Option to save as older shapekey format (no compression) */
|
||||
|
||||
#define G_FILE_FLAGS_RUNTIME (G_FILE_NO_UI | G_FILE_RELATIVE_REMAP | G_FILE_MESH_COMPAT | G_FILE_SAVE_COPY)
|
||||
|
||||
|
@@ -42,6 +42,8 @@ struct Scene;
|
||||
struct Lattice;
|
||||
struct Mesh;
|
||||
struct WeightsArrayCache;
|
||||
struct BMEditMesh;
|
||||
struct ScratchKeyBlock;
|
||||
|
||||
/* Kernel prototypes */
|
||||
#ifdef __cplusplus
|
||||
@@ -54,6 +56,9 @@ struct Key *BKE_key_add(struct ID *id);
|
||||
struct Key *BKE_key_copy(struct Key *key);
|
||||
struct Key *BKE_key_copy_nolib(struct Key *key);
|
||||
void BKE_key_make_local(struct Key *key);
|
||||
/* overwrites data in 'to' with data in 'from', frees old 'to' data.
|
||||
* does not touch any library data, animation data and ID and from */
|
||||
void BKE_key_overwrite_data(struct Key *from, struct Key *to);
|
||||
void BKE_key_sort(struct Key *key);
|
||||
|
||||
void key_curve_position_weights(float t, float data[4], int type);
|
||||
@@ -75,6 +80,32 @@ struct KeyBlock *BKE_keyblock_find_name(struct Key *key, const char name[]);
|
||||
void BKE_keyblock_copy_settings(struct KeyBlock *kb_dst, const struct KeyBlock *kb_src);
|
||||
char *BKE_keyblock_curval_rnapath_get(struct Key *key, struct KeyBlock *kb);
|
||||
|
||||
/* returns a pointer to active shape value (mixval/anim-driven val) */
|
||||
float *BKE_keyblock_get_active_value(struct Object *ob, struct KeyBlock *kb);
|
||||
|
||||
/* ==== scratch keyblock ==== */
|
||||
|
||||
/* performs a first-time setup of the scratch. if it's already inited
|
||||
* (e. g. existed in a mainfile), does nothing. */
|
||||
void BKE_key_init_scratch(struct Object *ob);
|
||||
|
||||
/* moves current edit data to and from the scratch shape */
|
||||
void BKE_key_editdata_to_scratch(struct Object *ob, bool shapedata_indeces_in_sync);
|
||||
|
||||
/* populates the current editdata from scratch shapekey */
|
||||
void BKE_key_editdata_from_scratch(struct Object *ob);
|
||||
|
||||
/* ==== editmote evaluation ==== */
|
||||
|
||||
/* evaluates the current shape key situation and puts it into the editmesh coordinates */
|
||||
void BKE_key_eval_editmesh_rel(struct BMEditMesh *edbm, bool pinned);
|
||||
|
||||
/* evaluates a relative mesh keyblock and puts the resulting offsets in out_offsets */
|
||||
void BKE_key_block_mesh_eval_rel(struct Object *ob, struct Key *key, struct KeyBlock *kb,
|
||||
bool use_vgroup, float (*out_offsets)[3]);
|
||||
|
||||
/* ========================= */
|
||||
|
||||
// needed for the GE
|
||||
typedef struct WeightsArrayCache {
|
||||
int num_defgroup_weights;
|
||||
@@ -83,7 +114,7 @@ typedef struct WeightsArrayCache {
|
||||
|
||||
float **BKE_keyblock_get_per_block_weights(struct Object *ob, struct Key *key, struct WeightsArrayCache *cache);
|
||||
void BKE_keyblock_free_per_block_weights(struct Key *key, float **per_keyblock_weights, struct WeightsArrayCache *cache);
|
||||
void BKE_key_evaluate_relative(const int start, int end, const int tot, char *basispoin, struct Key *key, struct KeyBlock *actkb,
|
||||
void BKE_key_evaluate_relative(struct Object *ob, const int start, int end, const int tot, char *basispoin, struct Key *key, struct KeyBlock *actkb,
|
||||
float **per_keyblock_weights, const int mode);
|
||||
|
||||
/* conversion functions */
|
||||
@@ -100,6 +131,13 @@ void BKE_key_convert_from_offset(struct Object *ob, struct KeyBlock *kb, floa
|
||||
/* other management */
|
||||
bool BKE_keyblock_move(struct Object *ob, int org_index, int new_index);
|
||||
|
||||
/* basic key math */
|
||||
float (*BKE_keyblock_math_deltas(struct Object *ob, struct KeyBlock *a, struct KeyBlock *basis))[3];
|
||||
float (*BKE_keyblock_math_deltas_mult(struct Object *ob, struct KeyBlock *a, struct KeyBlock *basis, float mult, float dists[]))[3];
|
||||
|
||||
void BKE_keyblock_math_add(struct Object *ob, struct KeyBlock *r, struct KeyBlock *a, struct KeyBlock* basis, float mult);
|
||||
void BKE_keyblock_math_interp(struct Object *ob, struct KeyBlock *r, struct KeyBlock *a, float mult);
|
||||
|
||||
|
||||
/* key.c */
|
||||
extern int slurph_opt;
|
||||
|
@@ -282,7 +282,8 @@ void BKE_mesh_calc_relative_deform(
|
||||
const float (*vert_cos_org)[3],
|
||||
float (*vert_cos_new)[3]);
|
||||
|
||||
|
||||
/* Topology. */
|
||||
unsigned int BKE_mesh_topology_hash(struct Mesh *mesh);
|
||||
|
||||
/* *** mesh_validate.c *** */
|
||||
|
||||
|
@@ -419,3 +419,88 @@ void BKE_crazyspace_build_sculpt(Scene *scene, Object *ob, float (**deformmats)[
|
||||
unit_m3((*deformmats)[a]);
|
||||
}
|
||||
}
|
||||
|
||||
void BKE_crazyspace_cage_active_sel_center(BMEditSelection *ese, DerivedMesh *cage, int *derived_index_map, float *cent)
|
||||
{
|
||||
MVert *dm_verts = cage->getVertArray(cage);
|
||||
|
||||
if (ese->htype == BM_VERT) {
|
||||
BMVert *v = (BMVert *)ese->ele;
|
||||
int cage_index = derived_index_map ? derived_index_map[BM_elem_index_get(v)] : BM_elem_index_get(v);
|
||||
copy_v3_v3(cent, dm_verts[cage_index].co);
|
||||
}
|
||||
else if (ese->htype == BM_EDGE) {
|
||||
BMEdge *e = (BMEdge *)ese->ele;
|
||||
int cage_ind_v1 = derived_index_map ? derived_index_map[BM_elem_index_get(e->v1)] : BM_elem_index_get(e->v1);
|
||||
int cage_ind_v2 = derived_index_map ? derived_index_map[BM_elem_index_get(e->v2)] : BM_elem_index_get(e->v2);
|
||||
|
||||
zero_v3(cent);
|
||||
add_v3_v3(cent, dm_verts[cage_ind_v1].co);
|
||||
add_v3_v3(cent, dm_verts[cage_ind_v2].co);
|
||||
mul_v3_fl(cent, 0.5f);
|
||||
}
|
||||
else if (ese->htype == BM_FACE) {
|
||||
BMFace *f = (BMFace *) ese->ele;
|
||||
BMVert *v;
|
||||
BMIter iter;
|
||||
int total = 0, cage_index;
|
||||
|
||||
zero_v3(cent);
|
||||
BM_ITER_ELEM(v, &iter, f, BM_VERTS_OF_FACE) {
|
||||
++total;
|
||||
cage_index = derived_index_map ? derived_index_map[BM_elem_index_get(v)] : BM_elem_index_get(v);
|
||||
add_v3_v3(cent, dm_verts[cage_index].co);
|
||||
}
|
||||
mul_v3_fl(cent, 1.0f / total);
|
||||
}
|
||||
}
|
||||
|
||||
bool BKE_crazyspace_cageindexes_in_sync(Object *ob)
|
||||
{
|
||||
ModifierData *md;
|
||||
ModifierTypeInfo *mti;
|
||||
|
||||
BLI_assert(ob->type == OB_MESH);
|
||||
for (md = ob->modifiers.first; md; md = md->next) {
|
||||
mti = modifierType_getInfo(md->type);
|
||||
if (mti->type != eModifierTypeType_OnlyDeform && md->mode & eModifierMode_OnCage
|
||||
&& md->mode & eModifierMode_Editmode && md->mode & eModifierMode_Realtime)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int *BKE_crazyspace_map_em_to_cage(BMEditMesh *em, DerivedMesh *cage_dm)
|
||||
{
|
||||
int *derived_index_map = NULL;
|
||||
|
||||
int totdmvert = cage_dm->getNumVerts(cage_dm);
|
||||
int orig_index;
|
||||
int *p_indexlayer;
|
||||
int totmapped = 0;
|
||||
|
||||
p_indexlayer = DM_get_vert_data_layer(cage_dm, CD_ORIGINDEX);
|
||||
|
||||
if (p_indexlayer) {
|
||||
int a;
|
||||
|
||||
derived_index_map = MEM_mallocN(em->bm->totvert * sizeof(int), "derived index map");
|
||||
for (a = 0; a < totdmvert; ++a) {
|
||||
orig_index = *p_indexlayer;
|
||||
if (orig_index != ORIGINDEX_NONE) {
|
||||
totmapped++;
|
||||
BLI_assert(orig_index < em->bm->totvert);
|
||||
derived_index_map[orig_index] = a;
|
||||
}
|
||||
++p_indexlayer;
|
||||
}
|
||||
if (totmapped < em->bm->totvert) {
|
||||
MEM_freeN(derived_index_map);
|
||||
derived_index_map = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return derived_index_map;
|
||||
}
|
||||
|
@@ -34,6 +34,7 @@
|
||||
#include "DNA_listBase.h"
|
||||
#include "DNA_object_types.h"
|
||||
#include "DNA_mesh_types.h"
|
||||
#include "DNA_meshdata_types.h"
|
||||
|
||||
#include "BLI_math.h"
|
||||
|
||||
@@ -246,3 +247,60 @@ void BKE_editmesh_color_ensure(BMEditMesh *em, const char htype)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* ==================== topology hashing ======================= */
|
||||
|
||||
/**
|
||||
* Compute given \a em's topology signature, and stores it into \a topohash.
|
||||
*
|
||||
* If \a topohash is not yet allocated, will take care of this too, user must take care of freeing.
|
||||
*
|
||||
* \param em The BMEditMesh to check current topology.
|
||||
* \param topohash The topology hash to fill in.
|
||||
*/
|
||||
void BKE_editmesh_topohash_compute(BMEditMesh *em, MTopoHash **topohash)
|
||||
{
|
||||
if (*topohash == NULL) {
|
||||
*topohash = MEM_mallocN(sizeof(**topohash), __func__);
|
||||
}
|
||||
|
||||
(*topohash)->totvert = em->bm->totvert;
|
||||
(*topohash)->totedge = em->bm->totedge;
|
||||
(*topohash)->totloop = em->bm->totloop;
|
||||
(*topohash)->totpoly = em->bm->totface;
|
||||
|
||||
(*topohash)->hash = BM_mesh_topology_hash(em->bm);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if current \a em topology is identical to the one which generated \a topohash.
|
||||
*
|
||||
* \param em The BMEditMesh to check current topology.
|
||||
* \param topohash The previously computed topology hash.
|
||||
* \param do_update If true, update \a topohash to current \a em's topology 'signature'.
|
||||
*
|
||||
* \return True if topology matches given hash.
|
||||
*/
|
||||
bool BKE_editmesh_topohash_identity(BMEditMesh *em, MTopoHash *topohash, const bool do_update)
|
||||
{
|
||||
if (do_update ||
|
||||
((em->bm->totvert == topohash->totvert) && (em->bm->totedge == topohash->totedge) &&
|
||||
(em->bm->totloop == topohash->totloop) && (em->bm->totface == topohash->totpoly)))
|
||||
{
|
||||
unsigned int hash = BM_mesh_topology_hash(em->bm);
|
||||
|
||||
if (hash != topohash->hash) {
|
||||
if (do_update) {
|
||||
topohash->totvert = em->bm->totvert;
|
||||
topohash->totedge = em->bm->totedge;
|
||||
topohash->totloop = em->bm->totloop;
|
||||
topohash->totpoly = em->bm->totface;
|
||||
topohash->hash = hash;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@@ -73,6 +73,10 @@
|
||||
#define IPO_BEZTRIPLE 100
|
||||
#define IPO_BPOINT 101
|
||||
|
||||
#define ELEMSIZE_MESH (sizeof(float) * 3)
|
||||
#define ELEMSIZE_LATTICE (sizeof(float) * 3)
|
||||
#define ELEMSIZE_CURVE (sizeof(float) * 4)
|
||||
|
||||
/* extern, not threadsafe */
|
||||
int slurph_opt = 1;
|
||||
|
||||
@@ -88,6 +92,9 @@ void BKE_key_free(Key *key)
|
||||
MEM_freeN(kb->data);
|
||||
MEM_freeN(kb);
|
||||
}
|
||||
|
||||
MEM_SAFE_FREE(key->scratch.data);
|
||||
MEM_SAFE_FREE(key->topohash);
|
||||
}
|
||||
|
||||
void BKE_key_free_nolib(Key *key)
|
||||
@@ -99,6 +106,9 @@ void BKE_key_free_nolib(Key *key)
|
||||
MEM_freeN(kb->data);
|
||||
MEM_freeN(kb);
|
||||
}
|
||||
|
||||
MEM_SAFE_FREE(key->scratch.data);
|
||||
MEM_SAFE_FREE(key->topohash);
|
||||
}
|
||||
|
||||
Key *BKE_key_add(ID *id) /* common function */
|
||||
@@ -112,7 +122,9 @@ Key *BKE_key_add(ID *id) /* common function */
|
||||
key->from = id;
|
||||
|
||||
key->uidgen = 1;
|
||||
|
||||
|
||||
key->topohash = NULL;
|
||||
|
||||
/* XXX the code here uses some defines which will soon be deprecated... */
|
||||
switch (GS(id->name)) {
|
||||
case ID_ME:
|
||||
@@ -122,7 +134,7 @@ Key *BKE_key_add(ID *id) /* common function */
|
||||
el[1] = IPO_FLOAT;
|
||||
el[2] = 0;
|
||||
|
||||
key->elemsize = 12;
|
||||
key->elemsize = ELEMSIZE_MESH;
|
||||
|
||||
break;
|
||||
case ID_LT:
|
||||
@@ -132,7 +144,7 @@ Key *BKE_key_add(ID *id) /* common function */
|
||||
el[1] = IPO_FLOAT;
|
||||
el[2] = 0;
|
||||
|
||||
key->elemsize = 12;
|
||||
key->elemsize = ELEMSIZE_LATTICE;
|
||||
|
||||
break;
|
||||
case ID_CU:
|
||||
@@ -142,7 +154,7 @@ Key *BKE_key_add(ID *id) /* common function */
|
||||
el[1] = IPO_BPOINT;
|
||||
el[2] = 0;
|
||||
|
||||
key->elemsize = 16;
|
||||
key->elemsize = ELEMSIZE_CURVE;
|
||||
|
||||
break;
|
||||
}
|
||||
@@ -171,10 +183,60 @@ Key *BKE_key_copy(Key *key)
|
||||
kbn = kbn->next;
|
||||
kb = kb->next;
|
||||
}
|
||||
|
||||
|
||||
if (key->scratch.data) {
|
||||
keyn->scratch.data = MEM_dupallocN(key->scratch.data);
|
||||
}
|
||||
if (key->topohash) {
|
||||
keyn->topohash = MEM_dupallocN(key->topohash);
|
||||
}
|
||||
|
||||
return keyn;
|
||||
}
|
||||
|
||||
void BKE_key_overwrite_data(Key *from, Key *to)
|
||||
{
|
||||
KeyBlock *kbt, *kbf;
|
||||
|
||||
LISTBASE_ITER_FWD(to->block, kbt) {
|
||||
if (kbt->data)
|
||||
MEM_freeN(kbt->data);
|
||||
}
|
||||
|
||||
MEM_SAFE_FREE(to->scratch.data);
|
||||
MEM_SAFE_FREE(to->topohash);
|
||||
|
||||
if (from->scratch.data) {
|
||||
to->scratch.data = MEM_dupallocN(from->scratch.data);
|
||||
}
|
||||
if (from->topohash) {
|
||||
to->topohash = MEM_dupallocN(from->topohash);
|
||||
}
|
||||
|
||||
BLI_freelistN(&to->block);
|
||||
BLI_duplicatelist(&to->block, &from->block);
|
||||
|
||||
kbf = from->block.first;
|
||||
kbt = to->block.first;
|
||||
|
||||
while (kbf) {
|
||||
if (kbf->data) {
|
||||
kbt->data = MEM_dupallocN(kbf->data);
|
||||
}
|
||||
if (kbf == from->refkey) to->refkey = kbt;
|
||||
if (kbf == from->scratch.origin) to->scratch.origin = kbt;
|
||||
|
||||
kbf = kbf->next;
|
||||
kbt = kbt->next;
|
||||
}
|
||||
|
||||
to->mix_mode = from->mix_mode;
|
||||
to->type = from->type;
|
||||
to->slurph = from->slurph;
|
||||
to->ctime = from->ctime;
|
||||
to->uidgen = from->uidgen;
|
||||
}
|
||||
|
||||
|
||||
Key *BKE_key_copy_nolib(Key *key)
|
||||
{
|
||||
@@ -196,11 +258,19 @@ Key *BKE_key_copy_nolib(Key *key)
|
||||
|
||||
if (kbn->data) kbn->data = MEM_dupallocN(kbn->data);
|
||||
if (kb == key->refkey) keyn->refkey = kbn;
|
||||
if (kb == key->scratch.origin) keyn->scratch.origin = kbn;
|
||||
|
||||
kbn = kbn->next;
|
||||
kb = kb->next;
|
||||
}
|
||||
|
||||
|
||||
if (key->scratch.data) {
|
||||
keyn->scratch.data = MEM_dupallocN(key->scratch.data);
|
||||
}
|
||||
if (key->topohash) {
|
||||
keyn->topohash = MEM_dupallocN(key->topohash);
|
||||
}
|
||||
|
||||
return keyn;
|
||||
}
|
||||
|
||||
@@ -725,7 +795,7 @@ 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,
|
||||
void BKE_key_evaluate_relative(Object *ob, const int start, int end, const int tot, char *basispoin, Key *key, KeyBlock *actkb,
|
||||
float **per_keyblock_weights, const int mode)
|
||||
{
|
||||
KeyBlock *kb;
|
||||
@@ -755,9 +825,9 @@ void BKE_key_evaluate_relative(const int start, int end, const int tot, char *ba
|
||||
|
||||
/* step 2: do it */
|
||||
|
||||
for (kb = key->block.first, keyblock_index = 0; kb; kb = kb->next, keyblock_index++) {
|
||||
LISTBASE_ITER_FWD_INDEX(key->block, kb, keyblock_index) {
|
||||
if (kb != key->refkey) {
|
||||
float icuval = kb->curval;
|
||||
float icuval = *BKE_keyblock_get_active_value(ob, kb);
|
||||
|
||||
/* only with value, and no difference allowed */
|
||||
if (!(kb->flag & KEYBLOCK_MUTE) && icuval != 0.0f && kb->totelem == tot) {
|
||||
@@ -1203,7 +1273,7 @@ static void do_mesh_key(Scene *scene, Object *ob, Key *key, char *out, const int
|
||||
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_key_evaluate_relative(ob, 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 {
|
||||
@@ -1239,19 +1309,20 @@ static void do_cu_key(Curve *cu, Key *key, KeyBlock *actkb, KeyBlock **k, float
|
||||
}
|
||||
}
|
||||
|
||||
static void do_rel_cu_key(Curve *cu, Key *key, KeyBlock *actkb, char *out, const int tot)
|
||||
static void do_rel_cu_key(Object *ob, Key *key, KeyBlock *actkb, char *out, const int tot)
|
||||
{
|
||||
Curve *cu = ob->data;
|
||||
Nurb *nu;
|
||||
int a, step;
|
||||
|
||||
for (a = 0, nu = cu->nurb.first; nu; nu = nu->next, a += step) {
|
||||
if (nu->bp) {
|
||||
step = nu->pntsu * nu->pntsv;
|
||||
BKE_key_evaluate_relative(a, a + step, tot, out, key, actkb, NULL, KEY_MODE_BPOINT);
|
||||
BKE_key_evaluate_relative(ob, a, a + step, tot, out, key, actkb, NULL, KEY_MODE_BPOINT);
|
||||
}
|
||||
else if (nu->bezt) {
|
||||
step = 3 * nu->pntsu;
|
||||
BKE_key_evaluate_relative(a, a + step, tot, out, key, actkb, NULL, KEY_MODE_BEZTRIPLE);
|
||||
BKE_key_evaluate_relative(ob, a, a + step, tot, out, key, actkb, NULL, KEY_MODE_BEZTRIPLE);
|
||||
}
|
||||
else {
|
||||
step = 0;
|
||||
@@ -1328,7 +1399,7 @@ static void do_curve_key(Scene *scene, Object *ob, Key *key, char *out, const in
|
||||
}
|
||||
else {
|
||||
if (key->type == KEY_RELATIVE) {
|
||||
do_rel_cu_key(cu, cu->key, actkb, out, tot);
|
||||
do_rel_cu_key(ob, cu->key, actkb, out, tot);
|
||||
}
|
||||
else {
|
||||
const float ctime_scaled = key->ctime / 100.0f;
|
||||
@@ -1367,7 +1438,7 @@ static void do_latt_key(Scene *scene, Object *ob, Key *key, char *out, const int
|
||||
if (key->type == KEY_RELATIVE) {
|
||||
float **per_keyblock_weights;
|
||||
per_keyblock_weights = BKE_keyblock_get_per_block_weights(ob, key, NULL);
|
||||
BKE_key_evaluate_relative(0, tot, tot, (char *)out, key, actkb, per_keyblock_weights, KEY_MODE_DUMMY);
|
||||
BKE_key_evaluate_relative(ob, 0, tot, tot, (char *)out, key, actkb, per_keyblock_weights, KEY_MODE_DUMMY);
|
||||
BKE_keyblock_free_per_block_weights(key, per_keyblock_weights, NULL);
|
||||
}
|
||||
else {
|
||||
@@ -1637,6 +1708,7 @@ void BKE_keyblock_copy_settings(KeyBlock *kb_dst, const KeyBlock *kb_src)
|
||||
{
|
||||
kb_dst->pos = kb_src->pos;
|
||||
kb_dst->curval = kb_src->curval;
|
||||
kb_dst->mixval = kb_src->mixval;
|
||||
kb_dst->type = kb_src->type;
|
||||
kb_dst->relative = kb_src->relative;
|
||||
BLI_strncpy(kb_dst->vgroup, kb_src->vgroup, sizeof(kb_dst->vgroup));
|
||||
@@ -2056,6 +2128,225 @@ void BKE_key_convert_from_offset(Object *ob, KeyBlock *kb, float (*ofs)[3])
|
||||
}
|
||||
}
|
||||
|
||||
float *BKE_keyblock_get_active_value(Object *ob, KeyBlock *kb)
|
||||
{
|
||||
/* in editmode, there can be the local mix value or the animation mix value */
|
||||
Key *key = BKE_key_from_object(ob);
|
||||
if (ob->mode == OB_MODE_EDIT) {
|
||||
return key->mix_mode == KEY_MIX_FROM_ANIMDATA ? &kb->curval : &kb->mixval;
|
||||
}
|
||||
else return &kb->curval;
|
||||
}
|
||||
|
||||
/* ================== Scratch stuff ====================== */
|
||||
|
||||
void BKE_key_init_scratch(Object *ob)
|
||||
{
|
||||
Key *key = BKE_key_from_object(ob);
|
||||
KeyBlock *kb = BKE_keyblock_from_object(ob);
|
||||
if (key && kb && key->totkey > 0) {
|
||||
key->scratch.origin = kb;
|
||||
key->scratch.data = MEM_mallocN(key->elemsize * kb->totelem, __func__);
|
||||
memcpy(key->scratch.data, kb->data, key->elemsize * kb->totelem);
|
||||
}
|
||||
}
|
||||
|
||||
void BKE_key_editdata_to_scratch(Object *ob, bool indeces_in_sync)
|
||||
{
|
||||
Key *k = BKE_key_from_object(ob);
|
||||
ScratchKeyBlock *skb = &k->scratch;
|
||||
|
||||
BLI_assert(ELEM(ob->type, OB_MESH, OB_LATTICE, OB_CURVE));
|
||||
BLI_assert(ob->mode == OB_MODE_EDIT);
|
||||
|
||||
if (ob->type == OB_MESH) {
|
||||
Mesh *m = ob->data;
|
||||
BMesh *bm = m->edit_btmesh->bm;
|
||||
BMVert *v;
|
||||
BMIter iter;
|
||||
int a;
|
||||
float (*co)[3] = skb->data;
|
||||
|
||||
if (indeces_in_sync) {
|
||||
BM_ITER_MESH_INDEX(v, &iter, bm, BM_VERTS_OF_MESH, a) {
|
||||
copy_v3_v3(co[a], v->co);
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* don't shrink the memory here, only grow. If it's shrinked to new bm->totvert,
|
||||
* the CD_SHAPE_KEYINDEX can potentially be out of bounds. */
|
||||
if (bm->totvert > skb->origin->totelem) {
|
||||
skb->data = MEM_reallocN(skb->data, bm->totvert * ELEMSIZE_MESH);
|
||||
co = skb->data;
|
||||
}
|
||||
|
||||
BM_ITER_MESH(v, &iter, bm, BM_VERTS_OF_MESH) {
|
||||
a = *(int *) CustomData_bmesh_get(&bm->vdata, v->head.data, CD_SHAPE_KEYINDEX);
|
||||
if (a != ORIGINDEX_NONE) {
|
||||
copy_v3_v3(co[a], v->co);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (ob->type == OB_LATTICE) {
|
||||
BLI_assert(0); /* not done yet */
|
||||
}
|
||||
else if (ob->type == OB_CURVE) {
|
||||
BLI_assert(0); /* not done yet */
|
||||
}
|
||||
}
|
||||
|
||||
void BKE_key_editdata_from_scratch(Object *ob)
|
||||
{
|
||||
ScratchKeyBlock *skb = &BKE_key_from_object(ob)->scratch;
|
||||
|
||||
BLI_assert(ELEM(ob->type, OB_MESH, OB_LATTICE, OB_CURVE));
|
||||
BLI_assert(ob->mode == OB_MODE_EDIT);
|
||||
|
||||
if (ob->type == OB_MESH) {
|
||||
Mesh *m = ob->data;
|
||||
BMesh *bm = m->edit_btmesh->bm;
|
||||
BMVert *v;
|
||||
BMIter iter;
|
||||
int a;
|
||||
float(*co)[3] = skb->data;
|
||||
|
||||
BLI_assert(bm->totvert == skb->origin->totelem);
|
||||
|
||||
BM_ITER_MESH_INDEX(v, &iter, bm, BM_VERTS_OF_MESH, a) {
|
||||
copy_v3_v3(v->co, co[a]);
|
||||
}
|
||||
}
|
||||
else if (ob->type == OB_LATTICE) {
|
||||
BLI_assert(0); /* not done yet */
|
||||
}
|
||||
else if (ob->type == OB_CURVE) {
|
||||
BLI_assert(0); /* not done yet */
|
||||
}
|
||||
}
|
||||
|
||||
/*============ editmode mesh keyblock eval tools ===========*/
|
||||
|
||||
/* NOTE: I don't use these in editmode anymore, but they can be useful later in some key math */
|
||||
|
||||
#define KB_FOR_EACH_CO(kb, indexvar) \
|
||||
for ((indexvar) = 0; (indexvar) < (kb)->totelem; ++(indexvar))
|
||||
|
||||
static void key_block_mesh_get_deltas(Key *key, KeyBlock *kb, float (*out_deltas)[3])
|
||||
{
|
||||
int a;
|
||||
KeyBlock *basis = BLI_findlink(&key->block, kb->relative);
|
||||
float (*basis_cos)[3];
|
||||
float (*kb_cos)[3];
|
||||
|
||||
BLI_assert(basis && basis->totelem == kb->totelem);
|
||||
|
||||
basis_cos = basis->data;
|
||||
kb_cos = kb->data;
|
||||
|
||||
KB_FOR_EACH_CO(kb, a)
|
||||
sub_v3_v3v3(out_deltas[a], kb_cos[a], basis_cos[a]);
|
||||
}
|
||||
|
||||
void BKE_key_block_mesh_eval_rel(Object *ob, Key *key, KeyBlock *kb, bool use_vgroup, float (*out_offsets)[3])
|
||||
{
|
||||
int a;
|
||||
float *per_vertex_weights = NULL;
|
||||
|
||||
float influence = *BKE_keyblock_get_active_value(ob, kb);
|
||||
|
||||
if (use_vgroup)
|
||||
per_vertex_weights = get_weights_array(ob, kb->vgroup, NULL);
|
||||
|
||||
key_block_mesh_get_deltas(key, kb, out_offsets);
|
||||
|
||||
if (per_vertex_weights)
|
||||
{
|
||||
KB_FOR_EACH_CO(kb, a) {
|
||||
mul_v3_fl(out_offsets[a], influence);
|
||||
mul_v3_fl(out_offsets[a], per_vertex_weights[a]);
|
||||
}
|
||||
}
|
||||
else {
|
||||
KB_FOR_EACH_CO(kb, a) {
|
||||
mul_v3_fl(out_offsets[a], influence);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void key_block_mesh_eval_scratch(Object *ob, Key *key, float(*out_offsets)[3])
|
||||
{
|
||||
/* we need to eval a regular key, but with scratch's data */
|
||||
ScratchKeyBlock *skb = &key->scratch;
|
||||
KeyBlock bogus;
|
||||
|
||||
bogus = *skb->origin;
|
||||
|
||||
BKE_key_block_mesh_eval_rel(ob, key, &bogus, false, out_offsets);
|
||||
}
|
||||
|
||||
void BKE_key_eval_editmesh_rel(BMEditMesh *edbm, bool pinned)
|
||||
{
|
||||
/* the process is apparent from this picture */
|
||||
/* http://wiki.blender.org/index.php/File:Dev-gsoc-shapes-shape-eval-in-editmode.png */
|
||||
|
||||
int act_shape_index = edbm->bm->shapenr - 1;
|
||||
|
||||
Mesh *me = edbm->ob->data;
|
||||
Key *key = me->key;
|
||||
|
||||
BMesh *bm = edbm->bm;
|
||||
BMVert *mv;
|
||||
BMIter iter;
|
||||
|
||||
KeyBlock *refkb = key->refkey;
|
||||
ScratchKeyBlock *scratchkb = &key->scratch;
|
||||
ListBase kblist = key->block;
|
||||
int a, b;
|
||||
|
||||
float (*out_vcos)[3] = MEM_mallocN(bm->totvert * key->elemsize, __func__);
|
||||
int kbdata_size = key->elemsize * refkb->totelem;
|
||||
float (*kb_offsets_cos)[3] = MEM_callocN(kbdata_size, __func__);
|
||||
|
||||
if (pinned) {
|
||||
/* if the key is pinned, we need only the scratch with weight = 1.0 */
|
||||
memcpy(out_vcos, scratchkb->data, key->elemsize * scratchkb->origin->totelem);
|
||||
}
|
||||
else {
|
||||
KeyBlock *kb;
|
||||
|
||||
/* add in the refkey */
|
||||
memcpy(out_vcos, refkb->data, key->elemsize * refkb->totelem);
|
||||
|
||||
/* add in other keys */
|
||||
LISTBASE_ITER_FWD_INDEX(kblist, kb, a) {
|
||||
if (a == 0 || a == act_shape_index)
|
||||
continue;
|
||||
|
||||
BKE_key_block_mesh_eval_rel(edbm->ob, key, kb, true, kb_offsets_cos);
|
||||
|
||||
KB_FOR_EACH_CO(kb, b) {
|
||||
add_v3_v3(out_vcos[b], kb_offsets_cos[b]);
|
||||
}
|
||||
}
|
||||
|
||||
/* eval the scratch key */
|
||||
key_block_mesh_eval_scratch(edbm->ob, key, kb_offsets_cos);
|
||||
/* one last time */
|
||||
KB_FOR_EACH_CO(refkb, b) {
|
||||
add_v3_v3(out_vcos[b], kb_offsets_cos[b]);
|
||||
}
|
||||
}
|
||||
/* to bmesh! */
|
||||
BM_ITER_MESH_INDEX(mv, &iter, bm, BM_VERTS_OF_MESH, a) {
|
||||
copy_v3_v3(mv->co, out_vcos[a]);
|
||||
}
|
||||
|
||||
MEM_freeN(kb_offsets_cos);
|
||||
MEM_freeN(out_vcos);
|
||||
}
|
||||
|
||||
|
||||
/* ==========================================================*/
|
||||
|
||||
/** Move shape key from org_index to new_index. Safe, clamps index to valid range, updates reference keys,
|
||||
|
@@ -42,6 +42,7 @@
|
||||
#include "BLI_math.h"
|
||||
#include "BLI_edgehash.h"
|
||||
#include "BLI_bitmap.h"
|
||||
#include "BLI_hash_mm2a.h"
|
||||
#include "BLI_polyfill2d.h"
|
||||
#include "BLI_linklist.h"
|
||||
#include "BLI_linklist_stack.h"
|
||||
@@ -2253,3 +2254,71 @@ void BKE_mesh_calc_relative_deform(
|
||||
MEM_freeN(vert_accum);
|
||||
}
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
||||
/** \name Mesh Topology Hashing
|
||||
* \{ */
|
||||
|
||||
/**
|
||||
* This function computes a hash of current mesh's topology. Allows to detect any topology change.
|
||||
*
|
||||
* Similar to `BM_mesh_topology_hash()`.
|
||||
*
|
||||
* \param mesh The Mesh.
|
||||
* \return The hash, as an unsigned integer.
|
||||
*
|
||||
* \note We use vertex indices as core 'reference'.
|
||||
*/
|
||||
unsigned int BKE_mesh_topology_hash(Mesh *mesh)
|
||||
{
|
||||
int me_idx, mp_idx;
|
||||
|
||||
BLI_HashMurmur2A mm2;
|
||||
|
||||
unsigned int seed = (unsigned int)mesh->totvert + (unsigned int)mesh->totedge +
|
||||
(unsigned int)mesh->totloop + (unsigned int)mesh->totpoly;
|
||||
|
||||
if (!seed) {
|
||||
return seed;
|
||||
}
|
||||
|
||||
if (mesh->totedge == 0) {
|
||||
/* Cloud mesh, only vertices, totvert is good enough. */
|
||||
return seed;
|
||||
}
|
||||
|
||||
/* Init the murmur hash. */
|
||||
BLI_hash_mm2a_init(&mm2, seed);
|
||||
|
||||
/* Compute edge topology, using only vert indices. */
|
||||
for (me_idx = 0; me_idx < mesh->totedge; me_idx++) {
|
||||
MEdge *me = &mesh->medge[me_idx];
|
||||
|
||||
/* Edge topology is fully defined by its two vertices. */
|
||||
BLI_hash_mm2a_add_int(&mm2, (int)me->v1);
|
||||
BLI_hash_mm2a_add_int(&mm2, (int)me->v2);
|
||||
}
|
||||
|
||||
if (mesh->totpoly == 0) {
|
||||
/* No poly (nor loop), we are done. */
|
||||
return (unsigned int)BLI_hash_mm2a_end(&mm2);
|
||||
}
|
||||
|
||||
/* Else, we have to check all polys too - it *is* possible to change topology
|
||||
* without affecting edges nor changing numbers of verts/edges/loops/polys! */
|
||||
for (mp_idx = 0; mp_idx < mesh->totpoly; mp_idx++) {
|
||||
MPoly *mp = &mesh->mpoly[mp_idx];
|
||||
int ml_idx = mp->loopstart;
|
||||
const int ml_idx_end = mp->loopstart + mp->totloop;
|
||||
|
||||
/* Poly topology is fully defined by its vertices and their order in it. */
|
||||
for (; ml_idx < ml_idx_end; ml_idx++) {
|
||||
MLoop *ml = &mesh->mloop[ml_idx];
|
||||
|
||||
BLI_hash_mm2a_add_int(&mm2, (int)ml->v);
|
||||
}
|
||||
}
|
||||
|
||||
return (unsigned int)BLI_hash_mm2a_end(&mm2);
|
||||
}
|
||||
|
@@ -518,7 +518,7 @@ static void sculptsession_bm_to_me_update_data_only(Object *ob, bool reorder)
|
||||
}
|
||||
if (reorder)
|
||||
BM_log_mesh_elems_reorder(ss->bm, ss->bm_log);
|
||||
BM_mesh_bm_to_me(ss->bm, ob->data, false);
|
||||
BM_mesh_bm_to_me(ss->bm, ob->data, false, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1628,7 +1628,7 @@ static void prepare_mesh_for_viewport_render(Main *bmain, Scene *scene)
|
||||
{
|
||||
if (check_rendered_viewport_visible(bmain)) {
|
||||
BMesh *bm = mesh->edit_btmesh->bm;
|
||||
BM_mesh_bm_to_me(bm, mesh, false);
|
||||
BM_mesh_bm_to_me(bm, mesh, false, true);
|
||||
DAG_id_tag_update(&mesh->id, 0);
|
||||
}
|
||||
}
|
||||
|
@@ -91,6 +91,22 @@ BLI_INLINE void BLI_listbase_clear(struct ListBase *lb) { lb->first = lb->last =
|
||||
/* create a generic list node containing link to provided data */
|
||||
struct LinkData *BLI_genericNodeN(void *data);
|
||||
|
||||
|
||||
/* Loops through the whole list fwd or bwd */
|
||||
|
||||
#define LISTBASE_ITER_FWD(lb, lb_iter) \
|
||||
for ((lb_iter) = (lb).first; (lb_iter); (lb_iter) = (lb_iter)->next)
|
||||
|
||||
#define LISTBASE_ITER_BWD(lb, lb_iter) \
|
||||
for ((lb_iter) = (lb).last; (lb_iter); (lb_iter) = (lb_iter)->prev)
|
||||
|
||||
#define LISTBASE_ITER_FWD_INDEX(lb, lb_iter, indexvar) \
|
||||
for ((lb_iter) = (lb).first, (indexvar) = 0; (lb_iter); (lb_iter) = (lb_iter)->next, ++(indexvar))
|
||||
|
||||
#define LISTBASE_ITER_BWD_INDEX(lb, lb_iter, indexvar) \
|
||||
for ((lb_iter) = (lb).first, (indexvar) = BLI_countlist(lb); (lb_iter); (lb_iter) = (lb_iter)->prev; --(indexvar))
|
||||
|
||||
|
||||
/**
|
||||
* Does a full loop on the list, with any value acting as first
|
||||
* (handy for cycling items)
|
||||
|
@@ -3085,32 +3085,71 @@ static void lib_link_key(FileData *fd, Main *main)
|
||||
}
|
||||
}
|
||||
|
||||
static void uncompress_kb(Key * key, KeyBlock *kb)
|
||||
{
|
||||
int a, index;
|
||||
float(*kbco)[3];
|
||||
|
||||
KeyBlock *rk = key->refkey;
|
||||
CompressedMeshVertex *verts = (CompressedMeshVertex *)kb->data;
|
||||
|
||||
/* allocate space for uncompressed data */
|
||||
kb->data = MEM_mallocN(sizeof(float) * 3 * rk->totelem, "KeyBlock");
|
||||
kbco = kb->data;
|
||||
|
||||
/* step one: init with ref values */
|
||||
memcpy(kb->data, rk->data, sizeof(float) * 3 * rk->totelem);
|
||||
|
||||
/* step two: overwrite the saved vertices */
|
||||
for (a = 0; a < kb->totelem; ++a) {
|
||||
index = verts[a].vertex_index;
|
||||
copy_v3_v3(kbco[index], verts[a].co);
|
||||
}
|
||||
|
||||
kb->totelem = rk->totelem;
|
||||
|
||||
/* free compressed data */
|
||||
if (verts) {
|
||||
/* compressed data may be NULL when a kb doesn't have any differences from the basis */
|
||||
MEM_freeN(verts);
|
||||
}
|
||||
}
|
||||
|
||||
static void switch_endian_keyblock(Key *key, KeyBlock *kb)
|
||||
{
|
||||
int elemsize, a, b;
|
||||
const char *data, *poin, *cp;
|
||||
|
||||
elemsize = key->elemsize;
|
||||
data = kb->data;
|
||||
|
||||
for (a = 0; a < kb->totelem; a++) {
|
||||
cp = key->elemstr;
|
||||
poin = data;
|
||||
|
||||
while (cp[0]) { /* cp[0] == amount */
|
||||
switch (cp[1]) { /* cp[1] = type */
|
||||
case IPO_FLOAT:
|
||||
case IPO_BPOINT:
|
||||
case IPO_BEZTRIPLE:
|
||||
b = cp[0];
|
||||
BLI_endian_switch_float_array((float *)poin, b);
|
||||
poin += sizeof(float) * b;
|
||||
break;
|
||||
}
|
||||
|
||||
cp += 2;
|
||||
|
||||
if (kb->flag & KEY_COMPRESSED) {
|
||||
CompressedMeshVertex *verts = (CompressedMeshVertex *)data;
|
||||
for (a = 0; a < kb->totelem; ++a) {
|
||||
BLI_endian_switch_int32(&verts[a].vertex_index);
|
||||
BLI_endian_switch_float_array((float *) &verts[a].co, 3);
|
||||
}
|
||||
data += elemsize;
|
||||
}
|
||||
else {
|
||||
elemsize = key->elemsize;
|
||||
for (a = 0; a < kb->totelem; a++) {
|
||||
cp = key->elemstr;
|
||||
poin = data;
|
||||
|
||||
while (cp[0]) { /* cp[0] == amount */
|
||||
switch (cp[1]) { /* cp[1] = type */
|
||||
case IPO_FLOAT:
|
||||
case IPO_BPOINT:
|
||||
case IPO_BEZTRIPLE:
|
||||
b = cp[0];
|
||||
BLI_endian_switch_float_array((float *)poin, b);
|
||||
poin += sizeof(float) * b;
|
||||
break;
|
||||
}
|
||||
|
||||
cp += 2;
|
||||
}
|
||||
data += elemsize;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3125,11 +3164,20 @@ static void direct_link_key(FileData *fd, Key *key)
|
||||
|
||||
key->refkey= newdataadr(fd, key->refkey);
|
||||
|
||||
key->scratch.origin = newdataadr(fd, key->scratch.origin);
|
||||
key->scratch.data = newdataadr(fd, key->scratch.data);
|
||||
|
||||
key->topohash = NULL;
|
||||
|
||||
for (kb = key->block.first; kb; kb = kb->next) {
|
||||
kb->data = newdataadr(fd, kb->data);
|
||||
|
||||
if (fd->flags & FD_FLAGS_SWITCH_ENDIAN)
|
||||
switch_endian_keyblock(key, kb);
|
||||
|
||||
if ((kb->flag & KEY_COMPRESSED) && key->refkey != kb) {
|
||||
uncompress_kb(key, kb);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -45,6 +45,7 @@
|
||||
#include "DNA_modifier_types.h"
|
||||
#include "DNA_particle_types.h"
|
||||
#include "DNA_linestyle_types.h"
|
||||
#include "DNA_key_types.h"
|
||||
#include "DNA_actuator_types.h"
|
||||
|
||||
#include "DNA_genfile.h"
|
||||
@@ -437,4 +438,15 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* if (!MAIN_VERSION_ATLEAST(main, 273, 0)) { */
|
||||
if (!DNA_struct_elem_find(fd->filesdna, "Key", "short", "mix_mode")) {
|
||||
Key *k;
|
||||
|
||||
/* set mixing to be governed by animdata */
|
||||
for (k = main->key.first; k; k = k->id.next) {
|
||||
k->mix_mode = KEY_MIX_FROM_ANIMDATA;
|
||||
}
|
||||
}
|
||||
/* } */
|
||||
}
|
||||
|
@@ -144,6 +144,7 @@
|
||||
#include "BLI_blenlib.h"
|
||||
#include "BLI_linklist.h"
|
||||
#include "BLI_mempool.h"
|
||||
#include "BLI_math.h" /* shape key compression */
|
||||
|
||||
#include "BKE_action.h"
|
||||
#include "BKE_blender.h"
|
||||
@@ -161,6 +162,7 @@
|
||||
#include "BKE_fcurve.h"
|
||||
#include "BKE_pointcache.h"
|
||||
#include "BKE_mesh.h"
|
||||
#include "BKE_key.h" /* shape key compression */
|
||||
|
||||
#ifdef USE_NODE_COMPAT_CUSTOMNODES
|
||||
#include "NOD_common.h"
|
||||
@@ -308,6 +310,7 @@ typedef struct {
|
||||
#ifdef USE_BMESH_SAVE_AS_COMPAT
|
||||
char use_mesh_compat; /* option to save with older mesh format */
|
||||
#endif
|
||||
char use_skey_compat; /* option to save skeys without compression */
|
||||
} WriteData;
|
||||
|
||||
static WriteData *writedata_new(WriteWrap *ww)
|
||||
@@ -1691,6 +1694,64 @@ static void write_vfonts(WriteData *wd, ListBase *idbase)
|
||||
}
|
||||
|
||||
|
||||
/* ========================== shape keys =============================== */
|
||||
|
||||
static void compress_kb(KeyBlock *kb, Key *key_owner)
|
||||
{
|
||||
/* the idea: we can get a space win by storing only the vertices with changed positions */
|
||||
int a, n_changed_verts;
|
||||
float diff[3];
|
||||
KeyBlock *rk = key_owner->refkey;
|
||||
float (*kbco)[3] = kb->data;
|
||||
float (*rkbco)[3] = rk->data;
|
||||
|
||||
CompressedMeshVertex *verts = MEM_callocN(sizeof(CompressedMeshVertex)* rk->totelem, __func__);
|
||||
|
||||
BLI_assert(kb->data); /* should not happen at any time! */
|
||||
|
||||
n_changed_verts = 0; /* counts CompressedMeshVertex's */
|
||||
for (a = 0; a < rk->totelem; ++a) {
|
||||
sub_v3_v3v3(diff, rkbco[a], kbco[a]);
|
||||
if (len_squared_v3(diff) > KEY_MIN_SQUARED_LEN) {
|
||||
/* this vert's pos has changed from the base */
|
||||
copy_v3_v3(verts[n_changed_verts].co, kbco[a]);
|
||||
verts[n_changed_verts].vertex_index = a;
|
||||
++n_changed_verts;
|
||||
}
|
||||
}
|
||||
|
||||
/* time to decide if we're going to win space by saving to compressed format */
|
||||
/* size we get with compress size we get without compress */
|
||||
if (n_changed_verts * sizeof(verts) < rk->totelem * sizeof(float)* 3) {
|
||||
kb->flag |= KEY_COMPRESSED;
|
||||
kb->totelem = n_changed_verts;
|
||||
|
||||
MEM_freeN(kb->data);
|
||||
kb->data = verts;
|
||||
|
||||
if (G.debug_value == 1) {
|
||||
printf("Compressed Shape Key %s, %.2f times smaller\n", kb->name,
|
||||
(rk->totelem * sizeof(float) * 3.0f) / (n_changed_verts * sizeof(CompressedMeshVertex)));
|
||||
}
|
||||
}
|
||||
else {
|
||||
MEM_freeN(verts);
|
||||
/* just ensure */
|
||||
kb->flag &= ~KEY_COMPRESSED;
|
||||
}
|
||||
}
|
||||
|
||||
static void compress_keyblocks(Key *k)
|
||||
{
|
||||
KeyBlock *kb = k->block.first;
|
||||
while (kb) {
|
||||
if (kb != k->refkey) {
|
||||
compress_kb(kb, k);
|
||||
}
|
||||
kb = kb->next;
|
||||
}
|
||||
}
|
||||
|
||||
static void write_keys(WriteData *wd, ListBase *idbase)
|
||||
{
|
||||
Key *key;
|
||||
@@ -1699,18 +1760,59 @@ static void write_keys(WriteData *wd, ListBase *idbase)
|
||||
key= idbase->first;
|
||||
while (key) {
|
||||
if (key->id.us>0 || wd->current) {
|
||||
/* write LibData */
|
||||
writestruct(wd, ID_KE, "Key", 1, key);
|
||||
if (key->id.properties) IDP_WriteProperty(key->id.properties, wd);
|
||||
|
||||
if (key->adt) write_animdata(wd, key->adt);
|
||||
|
||||
/* direct data */
|
||||
kb= key->block.first;
|
||||
while (kb) {
|
||||
writestruct(wd, DATA, "KeyBlock", 1, kb);
|
||||
if (kb->data) writedata(wd, DATA, kb->totelem*key->elemsize, kb->data);
|
||||
kb= kb->next;
|
||||
if (GS(key->from->name) == ID_ME && !wd->use_skey_compat) {
|
||||
ListBase lb = key->block;
|
||||
|
||||
/* if mesh keys, save a compressed copy */
|
||||
Key *dupe = BKE_key_copy_nolib(key);
|
||||
|
||||
/* restore these later - we need to write the current key struct,
|
||||
* or linkage will fail later on file read */
|
||||
key->block = dupe->block;
|
||||
key->refkey = dupe->refkey;
|
||||
|
||||
/* write LibData */
|
||||
writestruct(wd, ID_KE, "Key", 1, key);
|
||||
if (key->id.properties)
|
||||
IDP_WriteProperty(dupe->id.properties, wd);
|
||||
|
||||
if (key->adt)
|
||||
write_animdata(wd, key->adt);
|
||||
|
||||
compress_keyblocks(dupe);
|
||||
|
||||
/* direct */
|
||||
for (kb = key->block.first; kb; kb = kb->next) {
|
||||
writestruct(wd, DATA, "KeyBlock", 1, kb);
|
||||
if (kb->flag & KEY_COMPRESSED)
|
||||
writedata(wd, DATA, kb->totelem * sizeof(CompressedMeshVertex), kb->data);
|
||||
else
|
||||
writedata(wd, DATA, kb->totelem * key->elemsize, kb->data);
|
||||
}
|
||||
|
||||
/* restore key data */
|
||||
key->block = lb;
|
||||
key->refkey = lb.first; /* reference kb always is basis */
|
||||
|
||||
BKE_key_free_nolib(dupe);
|
||||
MEM_freeN(dupe);
|
||||
}
|
||||
else {
|
||||
/* lib */
|
||||
writestruct(wd, ID_KE, "Key", 1, key);
|
||||
if (key->id.properties)
|
||||
IDP_WriteProperty(key->id.properties, wd);
|
||||
|
||||
if (key->adt)
|
||||
write_animdata(wd, key->adt);
|
||||
|
||||
/* direct */
|
||||
for (kb = key->block.first; kb; kb = kb->next) {
|
||||
kb->flag &= ~KEY_COMPRESSED;
|
||||
writestruct(wd, DATA, "KeyBlock", 1, kb);
|
||||
if (kb->data) writedata(wd, DATA, kb->totelem * key->elemsize, kb->data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3501,6 +3603,8 @@ static int write_file_handle(
|
||||
wd->use_mesh_compat = (write_flags & G_FILE_MESH_COMPAT) != 0;
|
||||
#endif
|
||||
|
||||
wd->use_skey_compat = (write_flags & G_FILE_SHAPEKEY_COMPAT) != 0;
|
||||
|
||||
#ifdef USE_NODE_COMPAT_CUSTOMNODES
|
||||
/* don't write compatibility data on undo */
|
||||
if (!current) {
|
||||
|
@@ -120,6 +120,8 @@ set(SRC
|
||||
intern/bmesh_walkers.h
|
||||
intern/bmesh_walkers_impl.c
|
||||
intern/bmesh_walkers_private.h
|
||||
intern/bmesh_pe.h
|
||||
intern/bmesh_pe.c
|
||||
|
||||
intern/bmesh_operator_api.h
|
||||
intern/bmesh_error.h
|
||||
|
@@ -259,7 +259,7 @@ extern "C" {
|
||||
#include "intern/bmesh_polygon.h"
|
||||
#include "intern/bmesh_queries.h"
|
||||
#include "intern/bmesh_walkers.h"
|
||||
|
||||
#include "intern/bmesh_pe.h"
|
||||
#include "intern/bmesh_inline.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
@@ -566,7 +566,7 @@ BLI_INLINE void bmesh_quick_edgedraw_flag(MEdge *med, BMEdge *e)
|
||||
}
|
||||
}
|
||||
|
||||
void BM_mesh_bm_to_me(BMesh *bm, Mesh *me, bool do_tessface)
|
||||
void BM_mesh_bm_to_me(BMesh *bm, Mesh *me, bool do_tessface, bool do_keys)
|
||||
{
|
||||
MLoop *mloop;
|
||||
MPoly *mpoly;
|
||||
@@ -814,7 +814,7 @@ void BM_mesh_bm_to_me(BMesh *bm, Mesh *me, bool do_tessface)
|
||||
|
||||
/* see comment below, this logic is in twice */
|
||||
|
||||
if (me->key) {
|
||||
if (me->key && do_keys) {
|
||||
const int cd_shape_keyindex_offset = CustomData_get_offset(&bm->vdata, CD_SHAPE_KEYINDEX);
|
||||
|
||||
KeyBlock *currkey;
|
||||
|
@@ -41,6 +41,6 @@ char BM_mesh_cd_flag_from_bmesh(BMesh *bm);
|
||||
|
||||
void BM_mesh_bm_from_me(BMesh *bm, struct Mesh *me,
|
||||
const bool calc_face_normal, const bool set_key, int act_key_nr);
|
||||
void BM_mesh_bm_to_me(BMesh *bm, struct Mesh *me, bool do_tessface);
|
||||
void BM_mesh_bm_to_me(BMesh *bm, struct Mesh *me, bool do_tessface, bool do_shapes);
|
||||
|
||||
#endif /* __BMESH_MESH_CONV_H__ */
|
||||
|
328
source/blender/bmesh/intern/bmesh_pe.c
Normal file
328
source/blender/bmesh/intern/bmesh_pe.c
Normal file
@@ -0,0 +1,328 @@
|
||||
/*
|
||||
* ***** 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.
|
||||
*
|
||||
* Contributor(s): Grigory Revzin.
|
||||
*
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
#include <float.h>
|
||||
|
||||
#include "BLI_blenlib.h"
|
||||
#include "BLI_utildefines.h"
|
||||
#include "BLI_linklist_stack.h"
|
||||
#include "BLI_math.h"
|
||||
#include "BLI_rand.h"
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "DNA_scene_types.h"
|
||||
|
||||
#include "bmesh.h"
|
||||
|
||||
|
||||
static bool vtx_dist_add(BMVert *v, BMVert *v_other,
|
||||
float *dists, const float *dists_prev,
|
||||
float loc_to_world_mtx[3][3])
|
||||
{
|
||||
if ((BM_elem_flag_test(v_other, BM_ELEM_SELECT) == 0) &&
|
||||
(BM_elem_flag_test(v_other, BM_ELEM_HIDDEN) == 0))
|
||||
{
|
||||
const int i = BM_elem_index_get(v);
|
||||
const int i_other = BM_elem_index_get(v_other);
|
||||
float vec[3];
|
||||
float dist_other;
|
||||
sub_v3_v3v3(vec, v->co, v_other->co);
|
||||
mul_m3_v3(loc_to_world_mtx, vec);
|
||||
|
||||
dist_other = dists_prev[i] + len_v3(vec);
|
||||
if (dist_other < dists[i_other]) {
|
||||
dists[i_other] = dist_other;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void BM_prop_dist_calc_connected(BMesh *bm, float loc_to_world_mtx[3][3], float *dists)
|
||||
{
|
||||
/* need to be very careful of feedback loops here, store previous dist's to avoid feedback */
|
||||
float *dists_prev = MEM_mallocN(bm->totvert * sizeof(float), __func__);
|
||||
|
||||
BLI_LINKSTACK_DECLARE(queue, BMVert *);
|
||||
|
||||
/* any BM_ELEM_TAG'd vertex is in 'queue_next', so we don't add in twice */
|
||||
BLI_LINKSTACK_DECLARE(queue_next, BMVert *);
|
||||
|
||||
BLI_LINKSTACK_INIT(queue);
|
||||
BLI_LINKSTACK_INIT(queue_next);
|
||||
|
||||
{
|
||||
BMIter viter;
|
||||
BMVert *v;
|
||||
int i;
|
||||
|
||||
BM_ITER_MESH_INDEX(v, &viter, bm, BM_VERTS_OF_MESH, i) {
|
||||
BM_elem_index_set(v, i); /* set_inline */
|
||||
BM_elem_flag_disable(v, BM_ELEM_TAG);
|
||||
|
||||
if (BM_elem_flag_test(v, BM_ELEM_SELECT) == 0 || BM_elem_flag_test(v, BM_ELEM_HIDDEN)) {
|
||||
dists[i] = FLT_MAX;
|
||||
}
|
||||
else {
|
||||
BLI_LINKSTACK_PUSH(queue, v);
|
||||
dists[i] = 0.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
do {
|
||||
BMVert *v;
|
||||
LinkNode *lnk;
|
||||
|
||||
memcpy(dists_prev, dists, sizeof(float) * bm->totvert);
|
||||
|
||||
while ((v = BLI_LINKSTACK_POP(queue))) {
|
||||
BMIter iter;
|
||||
BMEdge *e;
|
||||
BMLoop *l;
|
||||
|
||||
/* connected edge-verts */
|
||||
BM_ITER_ELEM(e, &iter, v, BM_EDGES_OF_VERT) {
|
||||
if (BM_elem_flag_test(e, BM_ELEM_HIDDEN) == 0) {
|
||||
BMVert *v_other = BM_edge_other_vert(e, v);
|
||||
/* */
|
||||
if (vtx_dist_add(v, v_other, dists, dists_prev, loc_to_world_mtx)) {
|
||||
if (BM_elem_flag_test(v_other, BM_ELEM_TAG) == 0) {
|
||||
BM_elem_flag_enable(v_other, BM_ELEM_TAG);
|
||||
BLI_LINKSTACK_PUSH(queue_next, v_other);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* connected face-verts (excluding adjacent verts) */
|
||||
BM_ITER_ELEM(l, &iter, v, BM_LOOPS_OF_VERT) {
|
||||
if ((BM_elem_flag_test(l->f, BM_ELEM_HIDDEN) == 0) && (l->f->len > 3)) {
|
||||
BMLoop *l_end = l->prev;
|
||||
l = l->next->next;
|
||||
do {
|
||||
BMVert *v_other = l->v;
|
||||
if (vtx_dist_add(v, v_other, dists, dists_prev, loc_to_world_mtx)) {
|
||||
if (BM_elem_flag_test(v_other, BM_ELEM_TAG) == 0) {
|
||||
BM_elem_flag_enable(v_other, BM_ELEM_TAG);
|
||||
BLI_LINKSTACK_PUSH(queue_next, v_other);
|
||||
}
|
||||
}
|
||||
} while ((l = l->next) != l_end);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* clear for the next loop */
|
||||
for (lnk = queue_next; lnk; lnk = lnk->next) {
|
||||
BM_elem_flag_disable((BMVert *)lnk->link, BM_ELEM_TAG);
|
||||
}
|
||||
|
||||
BLI_LINKSTACK_SWAP(queue, queue_next);
|
||||
|
||||
/* none should be tagged now since 'queue_next' is empty */
|
||||
BLI_assert(BM_iter_mesh_count_flag(BM_VERTS_OF_MESH, bm, BM_ELEM_TAG, true) == 0);
|
||||
|
||||
} while (BLI_LINKSTACK_SIZE(queue));
|
||||
|
||||
BLI_LINKSTACK_FREE(queue);
|
||||
BLI_LINKSTACK_FREE(queue_next);
|
||||
|
||||
MEM_freeN(dists_prev);
|
||||
}
|
||||
|
||||
static void move_selected_verts_to_top(BMesh *bm, int *indexes)
|
||||
{
|
||||
BMVert *v;
|
||||
BMIter viter;
|
||||
int a, b, ix;
|
||||
|
||||
b = bm->totvert - 1;
|
||||
a = 0;
|
||||
|
||||
BM_ITER_MESH(v, &viter, bm, BM_VERTS_OF_MESH) {
|
||||
/* if the vert is selected, get its index to top, otherwise to bottom */
|
||||
ix = BM_elem_index_get(v);
|
||||
if (BM_elem_flag_test(v, BM_ELEM_SELECT)) {
|
||||
indexes[a] = ix;
|
||||
++a;
|
||||
}
|
||||
else {
|
||||
indexes[b] = ix;
|
||||
--b;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static float dist_proj_sq(float a[3], float b[3], float loc_to_world_mtx[3][3], float proj_plane_n[3])
|
||||
{
|
||||
float v[3], v1[3];
|
||||
sub_v3_v3v3(v, a, b);
|
||||
mul_m3_v3(loc_to_world_mtx, v);
|
||||
project_v3_v3v3(v1, v, proj_plane_n);
|
||||
sub_v3_v3(v, v1);
|
||||
return len_squared_v3(v);
|
||||
}
|
||||
|
||||
static float dist_sq(float a[3], float b[3])
|
||||
{
|
||||
float v[3];
|
||||
sub_v3_v3v3(v, a, b);
|
||||
return len_squared_v3(v);
|
||||
}
|
||||
|
||||
static float dist_transform(float a[3], float b[3], float loc_to_world_mtx[3][3])
|
||||
{
|
||||
float v[3], v1[3];
|
||||
sub_v3_v3v3(v, a, b);
|
||||
mul_v3_m3v3(v1, loc_to_world_mtx, v);
|
||||
return len_v3(v1);
|
||||
}
|
||||
|
||||
|
||||
void BM_prop_dist_calc(BMesh *bm, float loc_to_world_mtx[3][3], float proj_plane_n[3], float dists[])
|
||||
{
|
||||
int a, b;
|
||||
BMVert
|
||||
*unsel_vert,
|
||||
*sel_vert,
|
||||
*decision_vert;
|
||||
float dist, dist_max;
|
||||
int *vindexes;
|
||||
|
||||
if (bm->totvertsel == bm->totvert) {
|
||||
memset(dists, 0.0f, sizeof(float) * bm->totvert);
|
||||
return;
|
||||
}
|
||||
|
||||
vindexes = MEM_mallocN(sizeof(int) * bm->totvert, __func__);
|
||||
|
||||
for (a = 0; a < bm->totvert; ++a)
|
||||
dists[a] = FLT_MAX;
|
||||
|
||||
move_selected_verts_to_top(bm, vindexes);
|
||||
/* we have to loop over all vertices for each vertex, ahh n^2
|
||||
* to counter this, we are trying to reduce the loop count by stopping once we are through the selected vertices
|
||||
*/
|
||||
|
||||
/* some dupli code, but it saves from checking the proj_plane_n on every loop */
|
||||
if (proj_plane_n) {
|
||||
for (a = bm->totvertsel; a < bm->totvert; ++a) {
|
||||
unsel_vert = BM_vert_at_index(bm, vindexes[a]);
|
||||
|
||||
if (BM_elem_flag_test_bool(unsel_vert, BM_ELEM_HIDDEN))
|
||||
continue;
|
||||
|
||||
dist_max = FLT_MAX;
|
||||
|
||||
for (b = 0; b < bm->totvertsel; ++b) {
|
||||
sel_vert = BM_vert_at_index(bm, vindexes[b]);
|
||||
dist = dist_proj_sq(sel_vert->co, unsel_vert->co, loc_to_world_mtx, proj_plane_n);
|
||||
if (dist <= dist_max) {
|
||||
dist_max = dist;
|
||||
}
|
||||
}
|
||||
|
||||
dists[vindexes[a]] = sqrtf(dist_max);
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (a = bm->totvertsel; a < bm->totvert; ++a) {
|
||||
/* all unselected verts are at the end now */
|
||||
unsel_vert = BM_vert_at_index(bm, vindexes[a]);
|
||||
|
||||
if (BM_elem_flag_test_bool(unsel_vert, BM_ELEM_HIDDEN))
|
||||
continue;
|
||||
|
||||
dist_max = FLT_MAX;
|
||||
decision_vert = NULL;
|
||||
|
||||
for (b = 0; b < bm->totvertsel; ++b) {
|
||||
/* all selected verts are at the beginning */
|
||||
sel_vert = BM_vert_at_index(bm, vindexes[b]);
|
||||
/* can use the localspace mesh here - linear transforms never change the relationships between distances -
|
||||
* why do mul_m3_v3 if we don't have to? */
|
||||
dist = dist_sq(sel_vert->co, unsel_vert->co);
|
||||
|
||||
if (dist <= dist_max) {
|
||||
dist_max = dist;
|
||||
decision_vert = BM_vert_at_index(bm, vindexes[b]);
|
||||
}
|
||||
}
|
||||
dists[vindexes[a]] = dist_transform(decision_vert->co, unsel_vert->co, loc_to_world_mtx);
|
||||
}
|
||||
}
|
||||
|
||||
/* set distance to selected vertices to zero */
|
||||
for (b = 0; b < bm->totvertsel; ++b)
|
||||
dists[vindexes[b]] = 0.0f;
|
||||
|
||||
MEM_freeN(vindexes);
|
||||
}
|
||||
|
||||
|
||||
float BM_prop_factor_distance(float dist, float maxdist, int mode)
|
||||
{
|
||||
float factor;
|
||||
|
||||
if (dist == 0.0f) /* signal for selected */
|
||||
return 1.0f;
|
||||
|
||||
if (dist < 0.0f)
|
||||
dist = 0.0f;
|
||||
|
||||
if (dist > maxdist)
|
||||
return 0.0f;
|
||||
|
||||
dist = dist / maxdist;
|
||||
|
||||
CLAMP(dist, 0.0f, maxdist);
|
||||
|
||||
switch (mode) {
|
||||
case PROP_SHARP:
|
||||
factor = dist * dist;
|
||||
break;
|
||||
case PROP_SMOOTH: /* bell-ish hermite spline h_0_0 */
|
||||
factor = 3.0f * dist * dist - 2.0f * dist * dist * dist;
|
||||
break;
|
||||
case PROP_ROOT:
|
||||
factor = sqrtf(dist);
|
||||
break;
|
||||
case PROP_LIN:
|
||||
factor = dist;
|
||||
break;
|
||||
case PROP_SPHERE:
|
||||
factor = sqrtf(2 * dist - dist * dist);
|
||||
break;
|
||||
case PROP_RANDOM:
|
||||
factor = BLI_frand() * dist;
|
||||
break;
|
||||
case PROP_CONST: /* fall-through */
|
||||
default:
|
||||
factor = 0.0f;
|
||||
break;
|
||||
}
|
||||
|
||||
return 1.0f - factor;
|
||||
}
|
43
source/blender/bmesh/intern/bmesh_pe.h
Normal file
43
source/blender/bmesh/intern/bmesh_pe.h
Normal file
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* ***** 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.
|
||||
*
|
||||
* Contributor(s): Grigory Revzin.
|
||||
*
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
#ifndef __BMESH_PE_H__
|
||||
#define __BMESH_PE_H__
|
||||
|
||||
typedef struct BMesh BMesh;
|
||||
|
||||
/* both of these calculate distances to closest selected vertices - after any kind of transform defined by the matrix */
|
||||
|
||||
/* the distance is calculated along the surface from the selected vertices */
|
||||
void BM_prop_dist_calc_connected(BMesh *bm, float loc_to_world_mtx[3][3], float *dists);
|
||||
|
||||
/* the distance is calculated either by a bounding sphere or a cicle
|
||||
* in the projection plane from the closest selected vertex */
|
||||
void BM_prop_dist_calc(BMesh *bm, float loc_to_world_mtx[3][3], float proj_plane_n[3], float dists[]);
|
||||
|
||||
/* get the PE factor for a given distance
|
||||
* mode is one of the following:
|
||||
* PROP_SMOOTH, PROP_SPHERE, PROP_ROOT, PROP_SHARP, PROP_LIN, PROP_CONST, PROP_RANDOM
|
||||
* from DNA_scene_types.h */
|
||||
float BM_prop_factor_distance(float dist, float maxdist, int mode);
|
||||
|
||||
#endif /* __BMESH_PE_H__ */
|
@@ -35,6 +35,7 @@
|
||||
|
||||
#include "BLI_math.h"
|
||||
#include "BLI_alloca.h"
|
||||
#include "BLI_hash_mm2a.h"
|
||||
#include "BLI_linklist.h"
|
||||
#include "BLI_stackdefines.h"
|
||||
|
||||
@@ -2350,6 +2351,67 @@ int BM_mesh_calc_edge_groups(BMesh *bm, int *r_groups_array, int (**r_group_inde
|
||||
return group_curr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate a hash of current topology.
|
||||
*
|
||||
* Similar to `BKE_mesh_topology_hash()`.
|
||||
*
|
||||
* \param bm The BMesh.
|
||||
* \return The hash, as an unsigned integer.
|
||||
*
|
||||
* \note We use vertex indices as core 'reference'.
|
||||
*/
|
||||
unsigned int BM_mesh_topology_hash(BMesh *bm)
|
||||
{
|
||||
BMIter iter;
|
||||
BMEdge *e;
|
||||
BMLoop *l;
|
||||
BMFace *f;
|
||||
|
||||
BLI_HashMurmur2A mm2;
|
||||
|
||||
unsigned int seed = (unsigned int)bm->totvert + (unsigned int)bm->totedge +
|
||||
(unsigned int)bm->totloop + (unsigned int)bm->totface;
|
||||
|
||||
if (!seed) {
|
||||
return seed;
|
||||
}
|
||||
|
||||
if (bm->totedge == 0) {
|
||||
/* Cloud mesh, only vertices, totvert is good enough. */
|
||||
return seed;
|
||||
}
|
||||
|
||||
/* Now, we need vert indices! */
|
||||
BM_mesh_elem_index_ensure(bm, BM_VERT);
|
||||
|
||||
/* Init the murmur hash. */
|
||||
BLI_hash_mm2a_init(&mm2, seed);
|
||||
|
||||
/* Compute edge topology, using only vert indices. */
|
||||
BM_ITER_MESH(e, &iter, bm, BM_EDGES_OF_MESH) {
|
||||
/* Edge topology is fully defined by its two vertices. */
|
||||
BLI_hash_mm2a_add_int(&mm2, BM_elem_index_get(e->v1));
|
||||
BLI_hash_mm2a_add_int(&mm2, BM_elem_index_get(e->v2));
|
||||
}
|
||||
|
||||
if (bm->totface == 0) {
|
||||
/* No face (nor loop), we are done. */
|
||||
return (unsigned int)BLI_hash_mm2a_end(&mm2);
|
||||
}
|
||||
|
||||
/* Else, we have to check all faces too - it *is* possible to change topology
|
||||
* without affecting edges nor changing numbers of verts/edges/loops/faces! */
|
||||
BM_ITER_MESH(f, &iter, bm, BM_FACES_OF_MESH) {
|
||||
/* Face topology is fully defined by its vertices and their order in it. */
|
||||
BM_ITER_ELEM(l, &iter, f, BM_LOOPS_OF_FACE) {
|
||||
BLI_hash_mm2a_add_int(&mm2, BM_elem_index_get(l->v));
|
||||
}
|
||||
}
|
||||
|
||||
return (unsigned int)BLI_hash_mm2a_end(&mm2);
|
||||
}
|
||||
|
||||
float bmesh_subd_falloff_calc(const int falloff, float val)
|
||||
{
|
||||
switch (falloff) {
|
||||
|
@@ -151,6 +151,8 @@ int BM_mesh_calc_edge_groups(BMesh *bm, int *r_groups_array, int (**r_group_in
|
||||
BMElemFilterFunc filter_fn, void *user_data,
|
||||
const char hflag_test) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 2, 3);
|
||||
|
||||
unsigned int BM_mesh_topology_hash(BMesh *bm);
|
||||
|
||||
/* not really any good place to put this */
|
||||
float bmesh_subd_falloff_calc(const int falloff, float val) ATTR_WARN_UNUSED_RESULT;
|
||||
|
||||
|
@@ -69,5 +69,5 @@ void bmo_bmesh_to_mesh_exec(BMesh *bm, BMOperator *op)
|
||||
/* Object *ob = BMO_slot_ptr_get(op, "object"); */
|
||||
const bool dotess = !BMO_slot_bool_get(op->slots_in, "skip_tessface");
|
||||
|
||||
BM_mesh_bm_to_me(bm, me, dotess);
|
||||
BM_mesh_bm_to_me(bm, me, dotess, true);
|
||||
}
|
||||
|
@@ -362,6 +362,6 @@ void bc_triangulate_mesh(Mesh *me)
|
||||
BM_mesh_bm_from_me(bm, me, true, false, 0);
|
||||
BM_mesh_triangulate(bm, quad_method, use_beauty, tag_only, NULL, NULL);
|
||||
|
||||
BM_mesh_bm_to_me(bm, me, false);
|
||||
BM_mesh_bm_to_me(bm, me, false, true);
|
||||
BM_mesh_free(bm);
|
||||
}
|
||||
|
@@ -97,6 +97,17 @@ void EDBM_mesh_free(struct BMEditMesh *em);
|
||||
void EDBM_mesh_load(struct Object *ob);
|
||||
struct DerivedMesh *EDBM_mesh_deform_dm_get(struct BMEditMesh *em);
|
||||
|
||||
/* create an editmesh from the mesh */
|
||||
void EDBM_editmesh_from_mesh(struct Object *ob, struct Scene *s);
|
||||
/* download the editmesh to the mesh */
|
||||
bool EDBM_mesh_from_editmesh(struct Object *obedit, bool do_free);
|
||||
/* updates the active shape, recalculates the key blocks */
|
||||
void EDBM_handle_active_shape_update(struct Object *ob, struct Scene *s);
|
||||
|
||||
/* commit the scratch keyblock's contents to the active keyblock, recalc the keyblocks */
|
||||
void EDBM_commit_scratch_to_active(struct Object *ob, struct Scene *s);
|
||||
void EDBM_update_scratch_from_active(struct Object *ob);
|
||||
|
||||
/* flushes based on the current select mode. if in vertex select mode,
|
||||
* verts select/deselect edges and faces, if in edge select mode,
|
||||
* edges select/deselect faces and vertices, and in face select mode faces select/deselect
|
||||
|
@@ -33,6 +33,7 @@
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "DNA_curve_types.h"
|
||||
#include "DNA_key_types.h"
|
||||
#include "DNA_material_types.h"
|
||||
#include "DNA_mesh_types.h"
|
||||
@@ -46,6 +47,7 @@
|
||||
#include "BLI_math.h"
|
||||
#include "BLI_rand.h"
|
||||
#include "BLI_sort_utils.h"
|
||||
#include "BLI_string.h"
|
||||
|
||||
#include "BKE_material.h"
|
||||
#include "BKE_context.h"
|
||||
@@ -54,8 +56,12 @@
|
||||
#include "BKE_texture.h"
|
||||
#include "BKE_main.h"
|
||||
#include "BKE_editmesh.h"
|
||||
#include "BKE_key.h"
|
||||
#include "BKE_mesh.h"
|
||||
|
||||
#include "BLF_translation.h"
|
||||
#include "BLF_api.h"
|
||||
#include "BIF_gl.h"
|
||||
|
||||
#include "RNA_define.h"
|
||||
#include "RNA_access.h"
|
||||
@@ -67,6 +73,7 @@
|
||||
#include "ED_mesh.h"
|
||||
#include "ED_object.h"
|
||||
#include "ED_screen.h"
|
||||
#include "ED_space_api.h"
|
||||
#include "ED_transform.h"
|
||||
#include "ED_uvedit.h"
|
||||
#include "ED_view3d.h"
|
||||
@@ -2065,8 +2072,74 @@ void MESH_OT_shape_propagate_to_all(wmOperatorType *ot)
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
||||
}
|
||||
|
||||
/* ================================== Blend From Shape ===================================== */
|
||||
/* BMESH_TODO this should be properly encapsulated in a bmop. but later.*/
|
||||
static int edbm_blend_from_shape_exec(bContext *C, wmOperator *op)
|
||||
|
||||
typedef struct bfs_customdata {
|
||||
KeyBlock *opkb; /* kb on which we operate */
|
||||
|
||||
float *add_shape_co; /* argument co minus basis co, float tripletsm, for add mode */
|
||||
|
||||
float *origcos; /* original editmesh coords */
|
||||
|
||||
float *distances, /* proportional falloff distances */
|
||||
*factors; /* proportional falloff factors (why not cache?) */
|
||||
|
||||
float amount; /* blending intensity */
|
||||
|
||||
short ww, wh; /* area width and height */
|
||||
float distance; /* PE falloff distance */
|
||||
|
||||
int origx, origy; /* mouse coords at starting state;state */
|
||||
|
||||
float xscale; /* scale between the horiz mouse movement and amount */
|
||||
float yscale; /* scale between the vert mouse movement and falloff */
|
||||
|
||||
int blend_mode; /* 0 = interp, 1 = add */
|
||||
|
||||
int prop_mode; /* from DNA_scene_types.h, PE falloff interpolator mode */
|
||||
int prop_type; /* simple/connected/projected */
|
||||
|
||||
int prev_prop_type; /* used for deciding when to recalc falloff distances */
|
||||
|
||||
int longest_kb_name_l; /* used for drawing info*/
|
||||
|
||||
float obmat[3][3]; /* object's worldmat */
|
||||
|
||||
BMEditMesh *em; /* editmesh */
|
||||
Key *key;
|
||||
|
||||
ARegion *ar; /* View3D */
|
||||
void *draw_handler; /* pointer to info handler */
|
||||
uiBlock *shapesel;
|
||||
} bfs_customdata;
|
||||
|
||||
#define BFS_TOTAL_PARAM 6
|
||||
/* keyblock, amount, distance, blend mode, prop mode, prop type */
|
||||
|
||||
enum {
|
||||
BFS_MODE_INTERP = 0,
|
||||
BFS_MODE_ADD = 1
|
||||
};
|
||||
|
||||
static void edbm_bfs_freedata(bfs_customdata *mem)
|
||||
{
|
||||
if (mem->distances)
|
||||
MEM_freeN(mem->distances);
|
||||
|
||||
if (mem->factors)
|
||||
MEM_freeN(mem->factors);
|
||||
|
||||
if (mem->add_shape_co)
|
||||
MEM_freeN(mem->add_shape_co);
|
||||
|
||||
if (mem->origcos)
|
||||
MEM_freeN(mem->origcos);
|
||||
|
||||
MEM_freeN(mem);
|
||||
}
|
||||
|
||||
static int edbm_bfs_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
Object *obedit = CTX_data_edit_object(C);
|
||||
Mesh *me = obedit->data;
|
||||
@@ -2124,25 +2197,17 @@ static int edbm_blend_from_shape_exec(bContext *C, wmOperator *op)
|
||||
static EnumPropertyItem *shape_itemf(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free)
|
||||
{
|
||||
Object *obedit = CTX_data_edit_object(C);
|
||||
BMEditMesh *em;
|
||||
EnumPropertyItem *item = NULL;
|
||||
int totitem = 0;
|
||||
Key *k = BKE_key_from_object(obedit);
|
||||
KeyBlock *kb;
|
||||
int totitem = 0, i;
|
||||
|
||||
if ((obedit && obedit->type == OB_MESH) &&
|
||||
(em = BKE_editmesh_from_object(obedit)) &&
|
||||
CustomData_has_layer(&em->bm->vdata, CD_SHAPEKEY))
|
||||
{
|
||||
EnumPropertyItem tmp = {0, "", 0, "", ""};
|
||||
int a;
|
||||
if (obedit && obedit->type == OB_MESH && BKE_keyblock_from_object(obedit)) {
|
||||
EnumPropertyItem tmp = { 0, "", 0, "", "" };
|
||||
|
||||
for (a = 0; a < em->bm->vdata.totlayer; a++) {
|
||||
if (em->bm->vdata.layers[a].type != CD_SHAPEKEY)
|
||||
continue;
|
||||
|
||||
tmp.value = totitem;
|
||||
tmp.identifier = em->bm->vdata.layers[a].name;
|
||||
tmp.name = em->bm->vdata.layers[a].name;
|
||||
/* RNA_enum_item_add sets totitem itself! */
|
||||
LISTBASE_ITER_FWD_INDEX(k->block, kb, i) {
|
||||
tmp.value = i;
|
||||
tmp.identifier = tmp.name = kb->name;
|
||||
RNA_enum_item_add(&item, &totitem, &tmp);
|
||||
}
|
||||
}
|
||||
@@ -2153,7 +2218,7 @@ static EnumPropertyItem *shape_itemf(bContext *C, PointerRNA *UNUSED(ptr), Prop
|
||||
return item;
|
||||
}
|
||||
|
||||
static void edbm_blend_from_shape_ui(bContext *C, wmOperator *op)
|
||||
static void edbm_bfs_ui(bContext *C, wmOperator *op)
|
||||
{
|
||||
uiLayout *layout = op->layout;
|
||||
PointerRNA ptr;
|
||||
@@ -2169,6 +2234,508 @@ static void edbm_blend_from_shape_ui(bContext *C, wmOperator *op)
|
||||
uiItemR(layout, &ptr, "add", 0, NULL, ICON_NONE);
|
||||
}
|
||||
|
||||
static void edbm_bfs_recalc_shapes(bfs_customdata *state)
|
||||
{
|
||||
int a;
|
||||
float(*opshapeco)[3] = (float(*)[3]) state->opkb->data;
|
||||
float(*addshapeco)[3] = (float(*)[3]) state->add_shape_co;
|
||||
float(*origshapeco)[3] = (float(*)[3]) state->origcos;
|
||||
float vec[3];
|
||||
BMVert *v;
|
||||
BMIter iter;
|
||||
|
||||
switch (state->blend_mode) {
|
||||
case BFS_MODE_INTERP:
|
||||
BM_ITER_MESH_INDEX(v, &iter, state->em->bm, BM_VERTS_OF_MESH, a) {
|
||||
interp_v3_v3v3(v->co, origshapeco[a], opshapeco[a], state->amount * state->factors[a]);
|
||||
}
|
||||
break;
|
||||
|
||||
case BFS_MODE_ADD:
|
||||
if (!addshapeco) {
|
||||
KeyBlock *base_kb = BLI_findlink(&state->key->block, state->opkb->relative);
|
||||
float(*baseshapeco)[3] = base_kb->data;
|
||||
|
||||
state->add_shape_co
|
||||
= MEM_mallocN(sizeof(float) * 3 * state->em->bm->totvert, "blend from shape add cos");
|
||||
|
||||
addshapeco = (float(*)[3]) state->add_shape_co;
|
||||
|
||||
for (a = 0; a < state->em->bm->totvert; ++a) {
|
||||
sub_v3_v3v3(addshapeco[a], opshapeco[a], baseshapeco[a]);
|
||||
}
|
||||
}
|
||||
|
||||
BM_ITER_MESH_INDEX(v, &iter, state->em->bm, BM_VERTS_OF_MESH, a) {
|
||||
copy_v3_v3(vec, addshapeco[a]);
|
||||
mul_v3_fl(vec, state->amount * state->factors[a]);
|
||||
add_v3_v3v3(v->co, origshapeco[a], vec);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
BLI_assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
static const char *edbm_bfs_mode_to_string(int mode)
|
||||
{
|
||||
if (mode == BFS_MODE_ADD)
|
||||
return IFACE_("Add");
|
||||
if (mode == BFS_MODE_INTERP)
|
||||
return IFACE_("Interp");
|
||||
return "ERR";
|
||||
}
|
||||
|
||||
static const char *edbm_bfs_pe_mode_to_string(int mode)
|
||||
{
|
||||
if (mode == PROP_EDIT_OFF) {
|
||||
return IFACE_("None");
|
||||
}
|
||||
if (mode == PROP_EDIT_ON) {
|
||||
return IFACE_("On");
|
||||
}
|
||||
if (mode == PROP_EDIT_CONNECTED) {
|
||||
return IFACE_("Connected");
|
||||
}
|
||||
if (mode == PROP_EDIT_PROJECTED) {
|
||||
return IFACE_("Projected");
|
||||
}
|
||||
return "ERR";
|
||||
}
|
||||
|
||||
static const char *edbm_bfs_falloff_to_string(int type)
|
||||
{
|
||||
switch (type) {
|
||||
case PROP_SHARP:
|
||||
return IFACE_("Sharp");
|
||||
|
||||
case PROP_SMOOTH:
|
||||
return IFACE_("Smooth");
|
||||
|
||||
case PROP_ROOT:
|
||||
return IFACE_("Root");
|
||||
|
||||
case PROP_LIN:
|
||||
return IFACE_("Linear");
|
||||
|
||||
case PROP_SPHERE:
|
||||
return IFACE_("Sphere");
|
||||
|
||||
case PROP_RANDOM:
|
||||
return IFACE_("Random");
|
||||
|
||||
case PROP_CONST:
|
||||
return IFACE_("Constant");
|
||||
default:
|
||||
return "ERR";
|
||||
}
|
||||
}
|
||||
|
||||
static const char *edbm_bfs_get_preposition(int blend_mode)
|
||||
{
|
||||
/* We interp TOWARDS and add FROM */
|
||||
switch (blend_mode) {
|
||||
case BFS_MODE_ADD:
|
||||
return IFACE_("Adding from");
|
||||
case BFS_MODE_INTERP:
|
||||
return IFACE_("Interp towards");
|
||||
default:
|
||||
BLI_assert(0);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void edbm_bfs_draw_info(const bContext *C, ARegion *UNUSED(ar), void *customdata)
|
||||
{
|
||||
#define BUFFER 1024 /* long keyblock names are a reality :\ */
|
||||
char buf[BUFFER];
|
||||
rcti rect;
|
||||
int y, x_namebase, x_valuebase;
|
||||
bfs_customdata *state = customdata;
|
||||
/* we draw a small table: on the left, the parameter names, on the right, the values */
|
||||
/* _______________________________
|
||||
* |Add from:______|OpenJaw_______|
|
||||
* |Proportional:__|None__________|
|
||||
* |_______________|______________|
|
||||
* x_namebase x_valuebase rcti.xmax - U.widget_unit */
|
||||
|
||||
ED_region_visible_rect(state->ar, &rect);
|
||||
|
||||
/* determine x_valuebase: space for ~15 chars or more for keyblock name */
|
||||
if (state->longest_kb_name_l > 10) {
|
||||
x_valuebase = ceil(rect.xmax - U.widget_unit - state->longest_kb_name_l * BLF_width_default("_", 1));
|
||||
}
|
||||
else {
|
||||
x_valuebase = ceil(rect.xmax - U.widget_unit - 15 * BLF_width_default("_", 1));
|
||||
}
|
||||
|
||||
x_namebase = ceil(x_valuebase - 15 * BLF_width_default("_", 1));
|
||||
|
||||
y = rect.ymin + U.widget_unit * BFS_TOTAL_PARAM;
|
||||
|
||||
if (BKE_keyblock_from_object(state->em->ob) == state->opkb) {
|
||||
strcpy(buf, "ROTATE MOUSEWHEEL");
|
||||
BLF_draw_default(x_namebase, y, 0.0f, buf, strlen(buf));
|
||||
return;
|
||||
}
|
||||
|
||||
if (state->opkb->next) {
|
||||
if (state->opkb->next != BKE_keyblock_from_object(state->em->ob)) {
|
||||
BLI_snprintf(buf, BUFFER, "%s", state->opkb->next->name);
|
||||
BLF_draw_default(x_valuebase, y + U.widget_unit / 1.5f, 0.0f, buf, strlen(buf));
|
||||
}
|
||||
else if (state->opkb->next->next) {
|
||||
BLI_snprintf(buf, BUFFER, "%s", state->opkb->next->next->name);
|
||||
BLF_draw_default(x_valuebase, y + U.widget_unit / 1.5f, 0.0f, buf, strlen(buf));
|
||||
}
|
||||
}
|
||||
|
||||
/* draw argument kb */
|
||||
BLI_snprintf(buf, BUFFER, "%s:", edbm_bfs_get_preposition(state->blend_mode));
|
||||
BLF_draw_default(x_namebase, y, 0.0f, buf, strlen(buf));
|
||||
BLI_snprintf(buf, BUFFER, "%s", state->opkb->name);
|
||||
BLF_draw_default(x_valuebase, y, 0.0f, buf, strlen(buf));
|
||||
|
||||
/* if there's a possibility, draw prev and next kb */
|
||||
|
||||
if (state->opkb->prev) {
|
||||
if (state->opkb->prev != BKE_keyblock_from_object(state->em->ob)) {
|
||||
BLI_snprintf(buf, BUFFER, "%s", state->opkb->prev->name);
|
||||
BLF_draw_default(x_valuebase, y - U.widget_unit / 1.5f, 0.0f, buf, strlen(buf));
|
||||
}
|
||||
else if (state->opkb->prev->prev) {
|
||||
BLI_snprintf(buf, BUFFER, "%s", state->opkb->prev->prev->name);
|
||||
BLF_draw_default(x_valuebase, y - U.widget_unit / 1.5f, 0.0f, buf, strlen(buf));
|
||||
}
|
||||
}
|
||||
|
||||
y -= 1.3f * U.widget_unit ;
|
||||
strcpy(buf, IFACE_("Amount:"));
|
||||
BLF_draw_default(x_namebase, y, 0.0f, buf, strlen(buf));
|
||||
BLI_snprintf(buf, BUFFER, "%.3f", state->amount);
|
||||
BLF_draw_default(x_valuebase, y, 0.0f, buf, strlen(buf));
|
||||
|
||||
if (state->prop_type) {
|
||||
y -= U.widget_unit;
|
||||
strcpy(buf, IFACE_("Distance:"));
|
||||
BLF_draw_default(x_namebase, y, 0.0f, buf, strlen(buf));
|
||||
BLI_snprintf(buf, BUFFER, "%.3f", state->distance);
|
||||
BLF_draw_default(x_valuebase, y, 0.0f, buf, strlen(buf));
|
||||
}
|
||||
|
||||
y -= U.widget_unit;
|
||||
strcpy(buf, IFACE_("Mode:"));
|
||||
BLF_draw_default(x_namebase, y, 0.0f, buf, strlen(buf));
|
||||
BLI_snprintf(buf, BUFFER, "%s", edbm_bfs_mode_to_string(state->blend_mode));
|
||||
BLF_draw_default(x_valuebase, y, 0.0f, buf, strlen(buf));
|
||||
|
||||
y -= U.widget_unit;
|
||||
strcpy(buf, IFACE_("Proportional:"));
|
||||
BLF_draw_default(x_namebase, y, 0.0f, buf, strlen(buf));
|
||||
BLI_snprintf(buf, BUFFER, "%s", edbm_bfs_pe_mode_to_string(state->prop_type));
|
||||
BLF_draw_default(x_valuebase, y, 0.0f, buf, strlen(buf));
|
||||
|
||||
if (state->prop_type) {
|
||||
y -= U.widget_unit;
|
||||
strcpy(buf, IFACE_("Falloff:"));
|
||||
BLF_draw_default(x_namebase, y, 0.0f, buf, strlen(buf));
|
||||
BLI_snprintf(buf, BUFFER, "%s", edbm_bfs_falloff_to_string(state->prop_mode));
|
||||
BLF_draw_default(x_valuebase, y, 0.0f, buf, strlen(buf));
|
||||
}
|
||||
|
||||
strcpy(buf, "Mouse drag up/down: falloff distance. Mouse left/right: amount."
|
||||
"Mousewheel: select keyblock. LMB / RMB: Confirm. ESC: Cancel."
|
||||
"O: Cycle Falloff Types. Shift-O: No PE/On/Connected/Projected.");
|
||||
|
||||
ED_area_headerprint(CTX_wm_area(C), buf);
|
||||
#undef BUFFER
|
||||
}
|
||||
|
||||
|
||||
#if 0 /* Unused */
|
||||
static uiBlock *edbm_bfs_create_shapeselector(bContext *C, ARegion *ar, void *arg_op)
|
||||
{
|
||||
uiBlock *block;
|
||||
uiLayout *layout;
|
||||
|
||||
block = uiBeginBlock(C, ar, "edbm blend from shape shape falldown", UI_EMBOSS);
|
||||
uiBlockClearFlag(block, UI_BLOCK_LOOP);
|
||||
uiBlockSetFlag(block, UI_BLOCK_KEEP_OPEN);
|
||||
|
||||
layout = uiBlockLayout(block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, 0, 0, 15 * UI_UNIT_X, UI_UNIT_Y, 0, UI_GetStyle());
|
||||
|
||||
return block;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int edbm_bfs_invoke(bContext *C, wmOperator *op, const wmEvent *event)
|
||||
{
|
||||
Object *obedit = CTX_data_edit_object(C);
|
||||
Mesh *me = obedit->data;
|
||||
Key *k = me->key;
|
||||
KeyBlock *kb = NULL;
|
||||
BMEditMesh *em = me->edit_btmesh;
|
||||
/* Scene *scene = CTX_data_scene(C); */ /* UNUSED */
|
||||
bfs_customdata *state;
|
||||
ToolSettings *ts = CTX_data_tool_settings(C);
|
||||
/* RegionView3D *rv3d = CTX_wm_region_view3d(C); */ /* UNUSED */
|
||||
ScrArea *ar = CTX_wm_area(C);
|
||||
BMVert *v;
|
||||
BMIter iter;
|
||||
int a;
|
||||
|
||||
/* check properties aren't set (except the shape) */
|
||||
|
||||
/* check that we can safely blend */
|
||||
LISTBASE_ITER_FWD(k->block, kb) {
|
||||
if (kb->totelem != em->bm->totvert) {
|
||||
BKE_report(op->reports, RPT_ERROR, "Shape topology has changed, can't blend!");
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
}
|
||||
|
||||
/* alloc customdata */
|
||||
op->customdata = MEM_callocN(sizeof(bfs_customdata), "blend from shape modal data");
|
||||
state = op->customdata;
|
||||
|
||||
state->distances = MEM_callocN(sizeof(float) * em->bm->totvert, "blend from shape distances");
|
||||
state->factors = MEM_callocN(sizeof(float) * em->bm->totvert, "blend from shape factors");
|
||||
state->origcos = MEM_callocN(sizeof(float) * em->bm->totvert * 3, "blend from shape origcos");
|
||||
|
||||
state->ar = CTX_wm_region(C);
|
||||
|
||||
state->blend_mode = BFS_MODE_INTERP;
|
||||
state->origx = event->x;
|
||||
state->origy = event->y;
|
||||
state->em = em;
|
||||
state->key = k;
|
||||
state->prop_type = ts->proportional; /* no/simple/cnct/proj */
|
||||
state->prev_prop_type = -1;
|
||||
state->prop_mode = ts->prop_mode; /* falloffs */
|
||||
state->opkb = BKE_key_from_object(obedit)->block.first;
|
||||
state->wh = ar->winy;
|
||||
state->ww = ar->winx;
|
||||
|
||||
state->draw_handler = ED_region_draw_cb_activate(state->ar->type, edbm_bfs_draw_info, state,
|
||||
REGION_DRAW_POST_PIXEL);
|
||||
|
||||
{
|
||||
float(*origshapeco)[3] = (float(*)[3]) state->origcos;
|
||||
BM_ITER_MESH_INDEX(v, &iter, state->em->bm, BM_VERTS_OF_MESH, a) {
|
||||
copy_v3_v3(origshapeco[a], v->co);
|
||||
}
|
||||
}
|
||||
|
||||
/* figure out control scales */
|
||||
{
|
||||
BoundBox *bb = BKE_mesh_boundbox_get(obedit);
|
||||
float bbox_diag[3];
|
||||
copy_m3_m4(state->obmat, obedit->obmat);
|
||||
zero_v3(bbox_diag);
|
||||
copy_v3_v3(bbox_diag, bb->vec[0]);
|
||||
sub_v3_v3(bbox_diag, bb->vec[6]);
|
||||
mul_m3_v3(state->obmat, bbox_diag);
|
||||
|
||||
state->yscale = 3.0 / 4.0 * len_v3(bbox_diag) / ar->winy;
|
||||
|
||||
/* 2.0f blending amount per entire view3d width, simple */
|
||||
state->xscale = 2.0f / ar->winx;
|
||||
}
|
||||
|
||||
state->longest_kb_name_l = 0;
|
||||
|
||||
LISTBASE_ITER_FWD(state->key->block, kb) {
|
||||
int a;
|
||||
if ((a = strlen(kb->name)) > state->longest_kb_name_l) {
|
||||
state->longest_kb_name_l = a;
|
||||
}
|
||||
}
|
||||
|
||||
/* register modal handler */
|
||||
WM_event_add_modal_handler(C, op);
|
||||
|
||||
return OPERATOR_RUNNING_MODAL;
|
||||
}
|
||||
|
||||
static void edbm_bfs_handle_mousemove(short mx, short my, bfs_customdata *state)
|
||||
{
|
||||
state->distance = my * state->yscale;
|
||||
state->amount = -1.0f + mx * state->xscale;
|
||||
|
||||
CLAMP(state->amount, -1.5f, 1.5f);
|
||||
CLAMP(state->distance, 0.0f, FLT_MAX);
|
||||
}
|
||||
|
||||
static void edbm_bfs_recalc_factors(bfs_customdata *state) {
|
||||
int a;
|
||||
/* Object *ob = state->em->ob; */ /* UNUSED */
|
||||
RegionView3D *rv3d = (RegionView3D *) state->ar;
|
||||
float proj_vec[3];
|
||||
|
||||
memset(state->factors, 0.0f, sizeof(float) * state->em->bm->totvert);
|
||||
|
||||
if (state->prop_type != state->prev_prop_type) {
|
||||
switch (state->prop_type) {
|
||||
case PROP_EDIT_ON:
|
||||
BM_prop_dist_calc(state->em->bm, state->obmat, NULL, state->distances);
|
||||
break;
|
||||
|
||||
case PROP_EDIT_PROJECTED:
|
||||
normalize_v3_v3(proj_vec, rv3d->viewinv[2]);
|
||||
BM_prop_dist_calc(state->em->bm, state->obmat, proj_vec, state->distances);
|
||||
break;
|
||||
|
||||
case PROP_EDIT_CONNECTED:
|
||||
BM_prop_dist_calc_connected(state->em->bm, state->obmat, state->distances);
|
||||
break;
|
||||
default:
|
||||
state->prev_prop_type = state->prop_type;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (state->prop_type) {
|
||||
for (a = 0; a < state->em->bm->totvert; ++a) {
|
||||
state->factors[a] = BM_prop_factor_distance(state->distances[a], state->distance, state->prop_mode);
|
||||
}
|
||||
}
|
||||
else {
|
||||
BMVert *v;
|
||||
BMIter iter;
|
||||
/* selected = 1.0 factor */
|
||||
BM_ITER_MESH_INDEX(v, &iter, state->em->bm, BM_VERTS_OF_MESH, a) {
|
||||
state->factors[a] = BM_elem_flag_test(v, BM_ELEM_SELECT) ? 1.0f : 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
state->prev_prop_type = state->prop_type;
|
||||
}
|
||||
|
||||
static int edbm_bfs_modal(bContext *C, wmOperator *op, const wmEvent *event)
|
||||
{
|
||||
int rc = 0;
|
||||
bfs_customdata *state = op->customdata;
|
||||
|
||||
switch (event->type) {
|
||||
case MOUSEMOVE:
|
||||
/* up/down = falloff; left/right = intensity */
|
||||
edbm_bfs_handle_mousemove(event->x, event->y, state);
|
||||
break;
|
||||
|
||||
case OKEY:
|
||||
if (event->val == KM_RELEASE)
|
||||
break;
|
||||
if (event->shift) {
|
||||
/* cycle PE */
|
||||
state->prop_type++;
|
||||
if (state->prop_type == PROP_EDIT_PROJECTED) /* skip projected for now */
|
||||
state->prop_type = 0;
|
||||
break;
|
||||
}
|
||||
state->prop_mode++;
|
||||
if (state->prop_mode == PROP_MODE_MAX)
|
||||
state->prop_mode = 0;
|
||||
break;
|
||||
|
||||
case MIDDLEMOUSE:
|
||||
if (event->val == KM_RELEASE)
|
||||
break;
|
||||
if (state->blend_mode == BFS_MODE_INTERP)
|
||||
state->blend_mode = BFS_MODE_ADD;
|
||||
else
|
||||
state->blend_mode = BFS_MODE_INTERP;
|
||||
break;
|
||||
|
||||
case LEFTMOUSE: /* fall-through */
|
||||
case RIGHTMOUSE:
|
||||
/* confirm, cleanup */
|
||||
rc = OPERATOR_FINISHED;
|
||||
break;
|
||||
{
|
||||
KeyBlock *kb;
|
||||
case WHEELDOWNMOUSE:
|
||||
/* switch to next shape */
|
||||
if ((kb = state->opkb->next)) {
|
||||
if (kb == BKE_keyblock_from_object(state->em->ob)) {
|
||||
/* skip active kb */
|
||||
if (kb->next)
|
||||
kb = kb->next;
|
||||
else
|
||||
kb = kb->prev;
|
||||
}
|
||||
state->opkb = kb;
|
||||
}
|
||||
if (state->add_shape_co) {
|
||||
MEM_freeN(state->add_shape_co);
|
||||
state->add_shape_co = NULL;
|
||||
}
|
||||
break;
|
||||
|
||||
case WHEELUPMOUSE:
|
||||
/* switch to prev shape */
|
||||
if ((kb = state->opkb->prev)) {
|
||||
if (kb == BKE_keyblock_from_object(state->em->ob)) {
|
||||
/* skip active kb */
|
||||
if (kb->prev)
|
||||
kb = kb->prev;
|
||||
else
|
||||
kb = kb->next;
|
||||
}
|
||||
state->opkb = kb;
|
||||
}
|
||||
if (state->add_shape_co) {
|
||||
MEM_freeN(state->add_shape_co);
|
||||
state->add_shape_co = NULL;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ESCKEY:
|
||||
/* cancel, cleanup */
|
||||
rc = OPERATOR_CANCELLED;
|
||||
break;
|
||||
}
|
||||
/* recalc */
|
||||
edbm_bfs_recalc_factors(state);
|
||||
|
||||
edbm_bfs_recalc_shapes(state);
|
||||
|
||||
EDBM_update_generic(state->em, false, false);
|
||||
|
||||
ED_region_tag_redraw(CTX_wm_region(C));
|
||||
|
||||
if (state->opkb == BKE_keyblock_from_object(state->em->ob)) {
|
||||
ED_area_headerprint(CTX_wm_area(C), "ROTATE MOUSEWHEEL");
|
||||
return OPERATOR_RUNNING_MODAL;
|
||||
}
|
||||
if (rc) {
|
||||
/* exit */
|
||||
|
||||
if (rc == OPERATOR_CANCELLED) {
|
||||
BMVert *v;
|
||||
BMIter iter;
|
||||
int a;
|
||||
|
||||
/* restore original shape */
|
||||
float(*origshapeco)[3] = (float(*)[3]) state->origcos;
|
||||
BM_ITER_MESH_INDEX(v, &iter, state->em->bm, BM_VERTS_OF_MESH, a) {
|
||||
copy_v3_v3(v->co, origshapeco[a]);
|
||||
}
|
||||
}
|
||||
|
||||
/* unregister info draw callback */
|
||||
ED_region_draw_cb_exit(state->ar->type, state->draw_handler);
|
||||
|
||||
edbm_bfs_freedata(op->customdata);
|
||||
|
||||
/* disable info in header */
|
||||
ED_area_headerprint(CTX_wm_area(C), NULL);
|
||||
return rc;
|
||||
}
|
||||
|
||||
return OPERATOR_RUNNING_MODAL;
|
||||
}
|
||||
|
||||
void MESH_OT_blend_from_shape(wmOperatorType *ot)
|
||||
{
|
||||
PropertyRNA *prop;
|
||||
@@ -2179,22 +2746,27 @@ void MESH_OT_blend_from_shape(wmOperatorType *ot)
|
||||
ot->idname = "MESH_OT_blend_from_shape";
|
||||
|
||||
/* api callbacks */
|
||||
ot->exec = edbm_blend_from_shape_exec;
|
||||
// ot->invoke = WM_operator_props_popup_call; /* disable because search popup closes too easily */
|
||||
ot->ui = edbm_blend_from_shape_ui;
|
||||
ot->exec = edbm_bfs_exec;
|
||||
ot->modal = edbm_bfs_modal;
|
||||
ot->invoke = edbm_bfs_invoke;
|
||||
ot->ui = edbm_bfs_ui;
|
||||
ot->poll = ED_operator_editmesh;
|
||||
|
||||
/* flags */
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING;
|
||||
|
||||
/* properties */
|
||||
prop = RNA_def_enum(ot->srna, "shape", DummyRNA_NULL_items, 0, "Shape", "Shape key to use for blending");
|
||||
RNA_def_enum_funcs(prop, shape_itemf);
|
||||
RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE);
|
||||
RNA_def_float(ot->srna, "blend", 1.0f, -FLT_MAX, FLT_MAX, "Blend", "Blending factor", -2.0f, 2.0f);
|
||||
RNA_def_boolean(ot->srna, "add", 1, "Add", "Add rather than blend between shapes");
|
||||
RNA_def_boolean(ot->srna, "prop_enabled", true, "Connected Vertices", "Blend nearby vertices propotionally");
|
||||
RNA_def_float(ot->srna, "prop_dist", 0.1f, -FLT_MAX, FLT_MAX, "Distance",
|
||||
"Proportional editing falloff distance, in relation to object's bounding box", 0.0f, 1.0f);
|
||||
}
|
||||
|
||||
/* ================================== Solidify ===================================== */
|
||||
|
||||
static int edbm_solidify_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
Object *obedit = CTX_data_edit_object(C);
|
||||
@@ -2249,6 +2821,67 @@ void MESH_OT_solidify(wmOperatorType *ot)
|
||||
RNA_def_property_ui_range(prop, -10, 10, 0.1, 4);
|
||||
}
|
||||
|
||||
/* ================================== Commit To Another ===================================== */
|
||||
|
||||
static int shape_key_commit_to_another_poll(bContext *C)
|
||||
{
|
||||
Object *obedit = CTX_data_edit_object(C);
|
||||
Key *key = BKE_key_from_object(obedit);
|
||||
return (ED_operator_editmesh(C) && key && BLI_countlist(&key->block) > 1);
|
||||
}
|
||||
|
||||
static int shape_key_commit_to_another_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
|
||||
Object *obedit = CTX_data_edit_object(C);
|
||||
|
||||
Key *k = BKE_key_from_object(obedit);
|
||||
BMEditMesh *em = BKE_editmesh_from_object(obedit);
|
||||
KeyBlock *act_kb = BKE_keyblock_from_object(obedit);
|
||||
int tgt_shape_idx = RNA_enum_get(op->ptr, "shape");
|
||||
KeyBlock *tgt_kb = BLI_findlink(&k->block, tgt_shape_idx);
|
||||
|
||||
if (tgt_shape_idx == obedit->shapenr - 1)
|
||||
return OPERATOR_FINISHED;
|
||||
|
||||
BLI_assert(BLI_countlist(&k->block) > 1);
|
||||
|
||||
/* forbid if some of the sizes are different */
|
||||
if (act_kb->totelem != tgt_kb->totelem || tgt_kb->totelem != em->bm->totvert || act_kb->totelem != em->bm->totvert) {
|
||||
BKE_report(op->reports, RPT_ERROR, "Cannot commit to another shape - edit data topology has changed!");
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
/* don't really 'commit', just force switch to another shape without recalc --
|
||||
* will look all the same from the user side */
|
||||
em->bm->shapenr = obedit->shapenr = tgt_shape_idx + 1;
|
||||
EDBM_update_scratch_from_active(obedit);
|
||||
EDBM_update_generic(em, false, false);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
void MESH_OT_shape_key_commit_to_another(wmOperatorType *ot)
|
||||
{
|
||||
/* identifiers */
|
||||
PropertyRNA* prop;
|
||||
|
||||
ot->name = "Commit To Another Shape";
|
||||
ot->idname = "OBJECT_OT_shape_key_commit_to_another";
|
||||
ot->description = "Commit the edited shape into another shape. Resets the current shape.";
|
||||
|
||||
/* api callbacks */
|
||||
ot->poll = shape_key_commit_to_another_poll;
|
||||
ot->exec = shape_key_commit_to_another_exec;
|
||||
|
||||
/* flags */
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
||||
|
||||
prop = RNA_def_enum(ot->srna, "shape", DummyRNA_NULL_items, 0, "Shape", "Shape key to commit to");
|
||||
RNA_def_enum_funcs(prop, shape_itemf);
|
||||
RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE);
|
||||
}
|
||||
|
||||
/* ******************************************************************** */
|
||||
/* Knife Subdivide Tool. Subdivides edges intersected by a mouse trail
|
||||
* drawn by user.
|
||||
@@ -2619,7 +3252,7 @@ static Base *mesh_separate_tagged(Main *bmain, Scene *scene, Base *base_old, BMe
|
||||
|
||||
BM_mesh_normals_update(bm_new);
|
||||
|
||||
BM_mesh_bm_to_me(bm_new, base_new->object->data, false);
|
||||
BM_mesh_bm_to_me(bm_new, base_new->object->data, false, true);
|
||||
|
||||
BM_mesh_free(bm_new);
|
||||
((Mesh *)base_new->object->data)->edit_btmesh = NULL;
|
||||
@@ -2899,7 +3532,7 @@ static int edbm_separate_exec(bContext *C, wmOperator *op)
|
||||
else BLI_assert(0);
|
||||
|
||||
if (retval_iter) {
|
||||
BM_mesh_bm_to_me(bm_old, me, false);
|
||||
BM_mesh_bm_to_me(bm_old, me, false, true);
|
||||
|
||||
DAG_id_tag_update(&me->id, OB_RECALC_DATA);
|
||||
WM_event_add_notifier(C, NC_GEOM | ND_DATA, me);
|
||||
|
@@ -31,7 +31,9 @@
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "DNA_key_types.h"
|
||||
#include "DNA_mesh_types.h"
|
||||
#include "DNA_meshdata_types.h"
|
||||
#include "DNA_object_types.h"
|
||||
#include "DNA_key_types.h"
|
||||
|
||||
@@ -61,8 +63,12 @@
|
||||
#include "ED_util.h"
|
||||
#include "ED_view3d.h"
|
||||
|
||||
#include "bmesh.h"
|
||||
|
||||
#include "mesh_intern.h" /* own include */
|
||||
|
||||
/* ======================================================================== */
|
||||
|
||||
/* mesh backup implementation. This would greatly benefit from some sort of binary diffing
|
||||
* just as the undo stack would. So leaving this as an interface for further work */
|
||||
|
||||
@@ -376,6 +382,13 @@ void EDBM_mesh_make(ToolSettings *ts, Object *ob)
|
||||
|
||||
/* we need to flush selection because the mode may have changed from when last in editmode */
|
||||
EDBM_selectmode_flush(me->edit_btmesh);
|
||||
|
||||
{
|
||||
Key *k = BKE_key_from_object(ob);
|
||||
if (k && BKE_keyblock_from_object(ob)) {
|
||||
BKE_editmesh_topohash_compute(me->edit_btmesh, &k->topohash);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void EDBM_mesh_load(Object *ob)
|
||||
@@ -389,7 +402,7 @@ void EDBM_mesh_load(Object *ob)
|
||||
bm->shapenr = 1;
|
||||
}
|
||||
|
||||
BM_mesh_bm_to_me(bm, me, false);
|
||||
BM_mesh_bm_to_me(bm, me, false, true);
|
||||
|
||||
#ifdef USE_TESSFACE_DEFAULT
|
||||
BKE_mesh_tessface_calc(me);
|
||||
@@ -482,6 +495,245 @@ void EDBM_flag_enable_all(BMEditMesh *em, const char hflag)
|
||||
BM_mesh_elem_hflag_enable_all(em->bm, BM_VERT | BM_EDGE | BM_FACE, hflag, true);
|
||||
}
|
||||
|
||||
/* ===================== BMesh & Mesh syncronization stuff =============================================== */
|
||||
/*
|
||||
* When working with shape keys, the 95% of all edits are deform-only. This calls for a more efficient data
|
||||
* syncronization than just recalculating the RealMesh and BMesh every time the active shape key is changed.
|
||||
* The idea: detect if topology hasn't changed. If it has, run the heavy-duty tools from bmesh_mesh_conv.c.
|
||||
*/
|
||||
|
||||
static void update_bmesh_shapes(Object *ob)
|
||||
{
|
||||
Key *key = BKE_key_from_object(ob);
|
||||
|
||||
if (key) {
|
||||
BMesh *bm = BKE_editmesh_from_object(ob)->bm;
|
||||
BMVert *v;
|
||||
BMIter iter;
|
||||
CustomData *vdata = &bm->vdata;
|
||||
KeyBlock *kb;
|
||||
int i, j, index;
|
||||
float (*kbco)[3] = NULL;
|
||||
float *cdco = NULL;
|
||||
int cd_vindex_offset = -1;
|
||||
|
||||
LISTBASE_ITER_FWD_INDEX(key->block, kb, i) {
|
||||
index = -1;
|
||||
for (j = 0; j < vdata->totlayer; ++j) {
|
||||
if (kb->uid == vdata->layers[j].uid) {
|
||||
index = j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
BLI_assert(index != -1);
|
||||
|
||||
kbco = kb->data;
|
||||
|
||||
BM_ITER_MESH_INDEX(v, &iter, bm, BM_VERTS_OF_MESH, j) {
|
||||
int data_offset = vdata->layers[index].offset;
|
||||
cdco = (float *)(((char *)v->head.data) + data_offset);
|
||||
copy_v3_v3(cdco, kbco[j]);
|
||||
}
|
||||
}
|
||||
|
||||
kb = BLI_findlink(&key->block, ob->shapenr - 1);
|
||||
kbco = kb->data;
|
||||
/* fix up the editcos along the CD_SHAPEKEY too */
|
||||
cd_vindex_offset = CustomData_get_offset(&bm->vdata, CD_SHAPE_KEYINDEX);
|
||||
BM_ITER_MESH(v, &iter, bm, BM_VERTS_OF_MESH) {
|
||||
index = BM_ELEM_CD_GET_INT(v, cd_vindex_offset);
|
||||
if (index != ORIGINDEX_NONE) {
|
||||
copy_v3_v3(v->co, kbco[index]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void recalc_keyblocks_from_scratch(Object *ob)
|
||||
{
|
||||
Key *k = BKE_key_from_object(ob);
|
||||
Mesh *me = ob->data;
|
||||
|
||||
ScratchKeyBlock *skb = &k->scratch;
|
||||
KeyBlock *old_active = skb->origin,
|
||||
*kb;
|
||||
|
||||
ListBase kbs = k->block;
|
||||
|
||||
int old_index = BLI_findindex(&kbs, old_active);
|
||||
int a, b;
|
||||
|
||||
float (*offsets_co)[3] = NULL;
|
||||
float (*skb_co)[3] = skb->data;
|
||||
float (*kb_co)[3] = NULL;
|
||||
|
||||
if (k->type == KEY_RELATIVE) {
|
||||
|
||||
LISTBASE_ITER_FWD_INDEX(kbs, kb, a) {
|
||||
/* for all keyblocks, find their relative keyblock */
|
||||
if (kb != k->refkey)
|
||||
BLI_assert(kb->relative != a);
|
||||
/* kb can't be relative to itself (except for refkey, it can trigger strange asserts and doesn't matter) */
|
||||
|
||||
/* refkey can't have a basis, don't update it */
|
||||
if (kb->relative == old_index && kb != k->refkey) {
|
||||
/* need to propagate the offsets */
|
||||
if (!offsets_co) {
|
||||
/* calculate them if we haven't already */
|
||||
offsets_co = MEM_mallocN(sizeof(float) * 3 * old_active->totelem, __func__);
|
||||
kb_co = old_active->data;
|
||||
for (b = 0; b < old_active->totelem; ++b)
|
||||
sub_v3_v3v3(offsets_co[b], skb_co[b], kb_co[b]);
|
||||
}
|
||||
|
||||
kb_co = kb->data;
|
||||
for (b = 0; b < old_active->totelem; ++b)
|
||||
add_v3_v3(kb_co[b], offsets_co[b]);
|
||||
}
|
||||
}
|
||||
}
|
||||
/* scratch -> 'real' keyblock */
|
||||
memcpy(old_active->data, skb->data, sizeof(float) * 3 * old_active->totelem);
|
||||
|
||||
/* patch me->co */
|
||||
kb_co = k->refkey->data;
|
||||
for (b = 0; b < old_active->totelem; ++b)
|
||||
copy_v3_v3(me->mvert[b].co, kb_co[b]);
|
||||
|
||||
if (offsets_co)
|
||||
MEM_freeN(offsets_co);
|
||||
}
|
||||
|
||||
void EDBM_commit_scratch_to_active(Object *ob, Scene *s)
|
||||
{
|
||||
BMEditMesh *em = BKE_editmesh_from_object(ob);
|
||||
Key *k = BKE_key_from_object(ob);
|
||||
|
||||
/* XXX Check it is OK to update topohash here (i.e. subsequent calls to this are OK to assume same topo again). */
|
||||
const bool topo_changed = !BKE_editmesh_topohash_identity(em, k->topohash, true);
|
||||
|
||||
if (topo_changed) {
|
||||
EDBM_mesh_load(em->ob);
|
||||
EDBM_mesh_make(s->toolsettings, ob);
|
||||
/* after mesh_make, old em is now invalidated */
|
||||
em = BKE_editmesh_from_object(ob);
|
||||
EDBM_mesh_normals_update(em);
|
||||
BKE_editmesh_tessface_calc(em);
|
||||
}
|
||||
else {
|
||||
/* update scratch from editdata */
|
||||
BKE_key_editdata_to_scratch(ob, true);
|
||||
/* faster keyblock recalc */
|
||||
recalc_keyblocks_from_scratch(ob);
|
||||
/* update shapes customdata on bmesh from recalced keyblocks */
|
||||
update_bmesh_shapes(ob);
|
||||
}
|
||||
}
|
||||
|
||||
void EDBM_update_scratch_from_active(Object *ob)
|
||||
{
|
||||
Key *k = BKE_key_from_object(ob);
|
||||
/* KeyBlock *oldorigin = k->scratch.origin; */ /* UNUSED */
|
||||
KeyBlock *neworigin = BKE_keyblock_from_object(ob);
|
||||
|
||||
k->scratch.origin = neworigin;
|
||||
|
||||
if (k->scratch.data) {
|
||||
MEM_freeN(k->scratch.data);
|
||||
k->scratch.data = MEM_mallocN(sizeof(float) * 3 * neworigin->totelem, __func__);
|
||||
}
|
||||
|
||||
/* neworigin -> scratch */
|
||||
BLI_assert(neworigin->totelem == BKE_editmesh_from_object(ob)->bm->totvert);
|
||||
memcpy(k->scratch.data, neworigin->data, sizeof(float) * 3 * neworigin->totelem);
|
||||
}
|
||||
|
||||
void EDBM_editmesh_from_mesh(Object *ob, Scene *scene)
|
||||
{
|
||||
BMEditMesh *em;
|
||||
Key *k = BKE_key_from_object(ob);
|
||||
|
||||
scene->obedit = ob; /* context sees this */
|
||||
|
||||
EDBM_mesh_make(scene->toolsettings, ob);
|
||||
|
||||
em = BKE_editmesh_from_object(ob);
|
||||
if (LIKELY(em)) {
|
||||
/* order doesn't matter */
|
||||
EDBM_mesh_normals_update(em);
|
||||
BKE_editmesh_tessface_calc(em);
|
||||
BM_mesh_select_mode_flush(em->bm);
|
||||
}
|
||||
|
||||
if (k) {
|
||||
BKE_key_init_scratch(ob);
|
||||
}
|
||||
}
|
||||
|
||||
bool EDBM_mesh_from_editmesh(Object *obedit, bool do_free)
|
||||
{
|
||||
Mesh *me = obedit->data;
|
||||
BMEditMesh *em = me->edit_btmesh;
|
||||
Key *k = me->key;
|
||||
|
||||
if (me->edit_btmesh->bm->totvert > MESH_MAX_VERTS) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (k && BKE_keyblock_from_object(obedit)) {
|
||||
/* XXX Check it is OK to update topohash here (i.e. subsequent calls to this are OK to assume same topo again). */
|
||||
if (BKE_editmesh_topohash_identity(em, k->topohash, true)) {
|
||||
BKE_key_editdata_to_scratch(obedit, true);
|
||||
recalc_keyblocks_from_scratch(obedit);
|
||||
update_bmesh_shapes(obedit);
|
||||
}
|
||||
|
||||
if (do_free && k->scratch.data) {
|
||||
MEM_freeN(k->scratch.data);
|
||||
k->scratch.data = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
EDBM_mesh_load(obedit);
|
||||
|
||||
EDBM_mesh_normals_update(em);
|
||||
BKE_editmesh_tessface_calc(em);
|
||||
|
||||
if (do_free) {
|
||||
EDBM_mesh_free(me->edit_btmesh);
|
||||
MEM_freeN(me->edit_btmesh);
|
||||
me->edit_btmesh = NULL;
|
||||
}
|
||||
if (obedit->restore_mode & OB_MODE_WEIGHT_PAINT) {
|
||||
ED_mesh_mirror_spatial_table(NULL, NULL, NULL, 'e');
|
||||
ED_mesh_mirror_topo_table(NULL, 'e');
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void EDBM_handle_active_shape_update(Object *ob, Scene *s)
|
||||
{
|
||||
Mesh *me = ob->data;
|
||||
BMEditMesh *em = me->edit_btmesh;
|
||||
Key *key = BKE_key_from_object(ob);
|
||||
KeyBlock *kb = BKE_keyblock_from_object(ob);
|
||||
|
||||
/* check the active keyblock is really a new one */
|
||||
if (kb == key->scratch.origin)
|
||||
return;
|
||||
|
||||
EDBM_commit_scratch_to_active(ob, s);
|
||||
EDBM_update_scratch_from_active(ob);
|
||||
em = BKE_editmesh_from_object(ob);
|
||||
EDBM_update_generic(em, false, false);
|
||||
|
||||
/* update shape number on bmesh */
|
||||
em->bm->shapenr = ob->shapenr;
|
||||
}
|
||||
|
||||
|
||||
/**************-------------- Undo ------------*****************/
|
||||
|
||||
/* for callbacks */
|
||||
@@ -522,9 +774,15 @@ static void *editbtMesh_to_undoMesh(void *emv, void *obdata)
|
||||
/* make sure shape keys work */
|
||||
um->me.key = obme->key ? BKE_key_copy_nolib(obme->key) : NULL;
|
||||
|
||||
if (um->me.key && um->me.key->scratch.data) {
|
||||
/* don't store scratch data */
|
||||
MEM_freeN(um->me.key->scratch.data);
|
||||
um->me.key->scratch.data = NULL;
|
||||
}
|
||||
|
||||
/* BM_mesh_validate(em->bm); */ /* for troubleshooting */
|
||||
|
||||
BM_mesh_bm_to_me(em->bm, &um->me, false);
|
||||
BM_mesh_bm_to_me(em->bm, &um->me, false, false);
|
||||
|
||||
um->selectmode = em->selectmode;
|
||||
um->shapenr = em->bm->shapenr;
|
||||
@@ -532,12 +790,14 @@ static void *editbtMesh_to_undoMesh(void *emv, void *obdata)
|
||||
return um;
|
||||
}
|
||||
|
||||
static void undoMesh_to_editbtMesh(void *umv, void *em_v, void *UNUSED(obdata))
|
||||
static void undoMesh_to_editbtMesh(void *umv, void *em_v, void *obdata)
|
||||
{
|
||||
BMEditMesh *em = em_v, *em_tmp;
|
||||
Object *ob = em->ob;
|
||||
UndoMesh *um = umv;
|
||||
BMesh *bm;
|
||||
Mesh *me = obdata;
|
||||
/* Key *k = me->key; */ /* UNUSED */
|
||||
|
||||
const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_ME(&um->me);
|
||||
|
||||
@@ -556,6 +816,12 @@ static void undoMesh_to_editbtMesh(void *umv, void *em_v, void *UNUSED(obdata))
|
||||
bm->selectmode = um->selectmode;
|
||||
em->ob = ob;
|
||||
|
||||
/* restore realmesh keyblocks */
|
||||
if (um->me.key) {
|
||||
BKE_key_overwrite_data(um->me.key, me->key);
|
||||
BKE_key_init_scratch(ob);
|
||||
}
|
||||
|
||||
MEM_freeN(em_tmp);
|
||||
}
|
||||
|
||||
|
@@ -184,6 +184,7 @@ void MESH_OT_symmetrize(struct wmOperatorType *ot);
|
||||
void MESH_OT_symmetry_snap(struct wmOperatorType *ot);
|
||||
void MESH_OT_shape_propagate_to_all(struct wmOperatorType *ot);
|
||||
void MESH_OT_blend_from_shape(struct wmOperatorType *ot);
|
||||
void MESH_OT_shape_key_commit_to_another(struct wmOperatorType *ot);
|
||||
void MESH_OT_sort_elements(struct wmOperatorType *ot);
|
||||
void MESH_OT_uvs_rotate(struct wmOperatorType *ot);
|
||||
void MESH_OT_uvs_reverse(struct wmOperatorType *ot);
|
||||
|
@@ -146,6 +146,7 @@ void ED_operatortypes_mesh(void)
|
||||
WM_operatortype_append(MESH_OT_rip_edge);
|
||||
WM_operatortype_append(MESH_OT_blend_from_shape);
|
||||
WM_operatortype_append(MESH_OT_shape_propagate_to_all);
|
||||
WM_operatortype_append(MESH_OT_shape_key_commit_to_another);
|
||||
|
||||
WM_operatortype_append(MESH_OT_uv_texture_add);
|
||||
WM_operatortype_append(MESH_OT_uv_texture_remove);
|
||||
|
@@ -77,6 +77,7 @@
|
||||
#include "BKE_modifier.h"
|
||||
#include "BKE_editmesh.h"
|
||||
#include "BKE_report.h"
|
||||
#include "BKE_key.h"
|
||||
|
||||
#include "ED_armature.h"
|
||||
#include "ED_curve.h"
|
||||
@@ -101,7 +102,6 @@
|
||||
#include "object_intern.h" // own include
|
||||
|
||||
/* ************* XXX **************** */
|
||||
static void error(const char *UNUSED(arg)) {}
|
||||
static void waitcursor(int UNUSED(val)) {}
|
||||
static int pupmenu(const char *UNUSED(msg)) { return 0; }
|
||||
|
||||
@@ -322,24 +322,7 @@ static bool ED_object_editmode_load_ex(Object *obedit, const bool freedata)
|
||||
}
|
||||
|
||||
if (obedit->type == OB_MESH) {
|
||||
Mesh *me = obedit->data;
|
||||
|
||||
if (me->edit_btmesh->bm->totvert > MESH_MAX_VERTS) {
|
||||
error("Too many vertices");
|
||||
return false;
|
||||
}
|
||||
|
||||
EDBM_mesh_load(obedit);
|
||||
|
||||
if (freedata) {
|
||||
EDBM_mesh_free(me->edit_btmesh);
|
||||
MEM_freeN(me->edit_btmesh);
|
||||
me->edit_btmesh = NULL;
|
||||
}
|
||||
if (obedit->restore_mode & OB_MODE_WEIGHT_PAINT) {
|
||||
ED_mesh_mirror_spatial_table(NULL, NULL, NULL, 'e');
|
||||
ED_mesh_mirror_topo_table(NULL, 'e');
|
||||
}
|
||||
EDBM_mesh_from_editmesh(obedit, freedata);
|
||||
}
|
||||
else if (obedit->type == OB_ARMATURE) {
|
||||
ED_armature_from_edit(obedit->data);
|
||||
@@ -479,21 +462,8 @@ void ED_object_editmode_enter(bContext *C, int flag)
|
||||
ob->mode = OB_MODE_EDIT;
|
||||
|
||||
if (ob->type == OB_MESH) {
|
||||
BMEditMesh *em;
|
||||
EDBM_editmesh_from_mesh(ob, scene);
|
||||
ok = 1;
|
||||
scene->obedit = ob; /* context sees this */
|
||||
|
||||
EDBM_mesh_make(scene->toolsettings, ob);
|
||||
|
||||
em = BKE_editmesh_from_object(ob);
|
||||
if (LIKELY(em)) {
|
||||
/* order doesn't matter */
|
||||
EDBM_mesh_normals_update(em);
|
||||
BKE_editmesh_tessface_calc(em);
|
||||
|
||||
BM_mesh_select_mode_flush(em->bm);
|
||||
}
|
||||
|
||||
WM_event_add_notifier(C, NC_SCENE | ND_MODE | NS_EDITMODE_MESH, scene);
|
||||
}
|
||||
else if (ob->type == OB_ARMATURE) {
|
||||
|
@@ -83,6 +83,10 @@ static void ED_object_shape_key_add(bContext *C, Scene *scene, Object *ob, const
|
||||
/* for absolute shape keys, new keys may not be added last */
|
||||
ob->shapenr = BLI_findindex(&key->block, kb) + 1;
|
||||
|
||||
/* in sculpt mode, set weight to 1 */
|
||||
if (ob->mode == OB_MODE_SCULPT)
|
||||
kb->curval = kb->mixval = 1.0f;
|
||||
|
||||
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
|
||||
}
|
||||
}
|
||||
@@ -149,6 +153,10 @@ static bool ED_object_shape_key_remove(Main *bmain, Object *ob)
|
||||
if (kb->data) MEM_freeN(kb->data);
|
||||
MEM_freeN(kb);
|
||||
|
||||
if (key->scratch.origin == kb) {
|
||||
key->scratch.origin = key->refkey;
|
||||
}
|
||||
|
||||
if (ob->shapenr > 1) {
|
||||
ob->shapenr--;
|
||||
}
|
||||
|
@@ -5282,7 +5282,7 @@ static int add_simple_uvs_exec(bContext *C, wmOperator *UNUSED(op))
|
||||
/* set the margin really quickly before the packing operation*/
|
||||
scene->toolsettings->uvcalc_margin = 0.001f;
|
||||
ED_uvedit_pack_islands(scene, ob, bm, false, false, true);
|
||||
BM_mesh_bm_to_me(bm, me, false);
|
||||
BM_mesh_bm_to_me(bm, me, false, true);
|
||||
BM_mesh_free(bm);
|
||||
|
||||
if (synch_selection)
|
||||
|
@@ -2212,7 +2212,7 @@ static void VertsToTransData(TransInfo *t, TransData *td, TransDataExtension *tx
|
||||
|
||||
td->ext = NULL;
|
||||
td->val = NULL;
|
||||
td->extra = NULL;
|
||||
td->extra = eve;
|
||||
if (t->mode == TFM_BWEIGHT) {
|
||||
td->val = bweight;
|
||||
td->ival = *bweight;
|
||||
|
@@ -70,6 +70,7 @@
|
||||
#include "BKE_action.h"
|
||||
#include "BKE_armature.h"
|
||||
#include "BKE_curve.h"
|
||||
#include "BKE_crazyspace.h"
|
||||
#include "BKE_depsgraph.h"
|
||||
#include "BKE_fcurve.h"
|
||||
#include "BKE_lattice.h"
|
||||
@@ -80,6 +81,7 @@
|
||||
#include "BKE_editmesh.h"
|
||||
#include "BKE_tracking.h"
|
||||
#include "BKE_mask.h"
|
||||
#include "BKE_DerivedMesh.h"
|
||||
|
||||
#include "ED_anim_api.h"
|
||||
#include "ED_armature.h"
|
||||
@@ -1643,12 +1645,54 @@ void calculateCenterMedian(TransInfo *t, float r_center[3])
|
||||
float partial[3] = {0.0f, 0.0f, 0.0f};
|
||||
int total = 0;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < t->total; i++) {
|
||||
if (t->data[i].flag & TD_SELECTED) {
|
||||
if (!(t->data[i].flag & TD_NOCENTER)) {
|
||||
add_v3_v3(partial, t->data[i].center);
|
||||
total++;
|
||||
Object *ob = t->obedit;
|
||||
|
||||
if (ob && ob->type == OB_MESH && t->mode != TFM_BWEIGHT && t->mode != TFM_CREASE) {
|
||||
Mesh *me = ob->data;
|
||||
DerivedMesh *cage = editbmesh_get_derived_cage(t->scene, ob, me->edit_btmesh, t->scene->customdata_mask);
|
||||
int *derived_index_map = NULL;
|
||||
MVert *dmv;
|
||||
BMVert *emv;
|
||||
|
||||
if (!BKE_crazyspace_cageindexes_in_sync(ob)) {
|
||||
derived_index_map = BKE_crazyspace_map_em_to_cage(me->edit_btmesh, cage);
|
||||
}
|
||||
|
||||
dmv = cage->getVertArray(cage);
|
||||
|
||||
if (derived_index_map) {
|
||||
int dm_index;
|
||||
for (i = 0; i < t->total; i++) {
|
||||
if (t->data[i].flag & TD_SELECTED) {
|
||||
if (!(t->data[i].flag & TD_NOCENTER)) {
|
||||
emv = t->data[i].extra;
|
||||
dm_index = derived_index_map[BM_elem_index_get(emv)];
|
||||
add_v3_v3(partial, dmv[dm_index].co);
|
||||
total++;
|
||||
}
|
||||
}
|
||||
}
|
||||
MEM_freeN(derived_index_map);
|
||||
}
|
||||
else {
|
||||
for (i = 0; i < t->total; i++) {
|
||||
if (t->data[i].flag & TD_SELECTED) {
|
||||
if (!(t->data[i].flag & TD_NOCENTER)) {
|
||||
emv = t->data[i].extra;
|
||||
add_v3_v3(partial, dmv[BM_elem_index_get(emv)].co);
|
||||
total++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (i = 0; i < t->total; i++) {
|
||||
if (t->data[i].flag & TD_SELECTED) {
|
||||
if (!(t->data[i].flag & TD_NOCENTER)) {
|
||||
add_v3_v3(partial, t->data[i].center);
|
||||
total++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1689,13 +1733,23 @@ bool calculateCenterActive(TransInfo *t, bool select_only, float r_center[3])
|
||||
switch (t->obedit->type) {
|
||||
case OB_MESH:
|
||||
{
|
||||
int *derived_index_map = NULL;
|
||||
BMEditSelection ese;
|
||||
BMEditMesh *em = BKE_editmesh_from_object(t->obedit);
|
||||
DerivedMesh *cage = editbmesh_get_derived_cage(t->scene, t->obedit, em, t->scene->customdata_mask);
|
||||
|
||||
if (!BKE_crazyspace_cageindexes_in_sync(t->obedit)) {
|
||||
derived_index_map = BKE_crazyspace_map_em_to_cage(em, cage);
|
||||
}
|
||||
|
||||
if (BM_select_history_active_get(em->bm, &ese)) {
|
||||
BM_editselection_center(&ese, r_center);
|
||||
BKE_crazyspace_cage_active_sel_center(&ese, cage, derived_index_map, r_center);
|
||||
ok = true;
|
||||
}
|
||||
|
||||
if (derived_index_map)
|
||||
MEM_freeN(derived_index_map);
|
||||
|
||||
break;
|
||||
}
|
||||
case OB_ARMATURE:
|
||||
|
@@ -56,6 +56,9 @@
|
||||
#include "BKE_pointcache.h"
|
||||
#include "BKE_editmesh.h"
|
||||
#include "BKE_lattice.h"
|
||||
#include "BKE_DerivedMesh.h"
|
||||
#include "BKE_crazyspace.h"
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "BIF_gl.h"
|
||||
|
||||
@@ -259,6 +262,11 @@ bool gimbal_axis(Object *ob, float gmat[3][3])
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void calc_tw_center_dm(Scene *scene, MVert *dm_verts, int edit_vert_index, int *derived_index_map)
|
||||
{
|
||||
int derived_index = derived_index_map ? derived_index_map[edit_vert_index] : edit_vert_index;
|
||||
calc_tw_center(scene, dm_verts[derived_index].co);
|
||||
}
|
||||
|
||||
/* centroid, boundbox, of selection */
|
||||
/* returns total items selected */
|
||||
@@ -273,6 +281,7 @@ static int calc_manipulator_stats(const bContext *C)
|
||||
RegionView3D *rv3d = ar->regiondata;
|
||||
Base *base;
|
||||
Object *ob = OBACT;
|
||||
MVert *dmverts = NULL;
|
||||
int a, totsel = 0;
|
||||
|
||||
/* transform widget matrix */
|
||||
@@ -289,31 +298,38 @@ static int calc_manipulator_stats(const bContext *C)
|
||||
if ((ob->lay & v3d->lay) == 0) return 0;
|
||||
|
||||
if (obedit->type == OB_MESH) {
|
||||
BMEditMesh *em = BKE_editmesh_from_object(obedit);
|
||||
BMEditSelection ese;
|
||||
float vec[3] = {0, 0, 0};
|
||||
BMEditMesh *em = BKE_editmesh_from_object(obedit);
|
||||
DerivedMesh *dm = editbmesh_get_derived_cage(scene, ob, em, scene->customdata_mask);
|
||||
int *derived_index_map = NULL;
|
||||
|
||||
dmverts = dm->getVertArray(dm);
|
||||
|
||||
if (!BKE_crazyspace_cageindexes_in_sync(ob)) {
|
||||
derived_index_map = BKE_crazyspace_map_em_to_cage(em, dm);
|
||||
}
|
||||
|
||||
/* USE LAST SELECTE WITH ACTIVE */
|
||||
if ((v3d->around == V3D_ACTIVE) && BM_select_history_active_get(em->bm, &ese)) {
|
||||
BM_editselection_center(&ese, vec);
|
||||
calc_tw_center(scene, vec);
|
||||
BKE_crazyspace_cage_active_sel_center(&ese, dm, derived_index_map, scene->twcent);
|
||||
/* these two are to prevent anything from messing with twcent */
|
||||
copy_v3_v3(scene->twmin, scene->twcent);
|
||||
copy_v3_v3(scene->twmax, scene->twcent);
|
||||
totsel = 1;
|
||||
}
|
||||
else {
|
||||
BMesh *bm = em->bm;
|
||||
BMVert *eve;
|
||||
|
||||
BMIter iter;
|
||||
|
||||
/* do vertices/edges/faces for center depending on selection
|
||||
* mode. note we can't use just vertex selection flag because
|
||||
* it is not flush down on changes */
|
||||
if (ts->selectmode & SCE_SELECT_VERTEX) {
|
||||
BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
|
||||
BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, a) {
|
||||
if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
|
||||
if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
|
||||
totsel++;
|
||||
calc_tw_center(scene, eve->co);
|
||||
calc_tw_center_dm(scene, dmverts, a, derived_index_map);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -321,13 +337,13 @@ static int calc_manipulator_stats(const bContext *C)
|
||||
else if (ts->selectmode & SCE_SELECT_EDGE) {
|
||||
BMIter itersub;
|
||||
BMEdge *eed;
|
||||
BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
|
||||
BM_ITER_MESH_INDEX(eve, &iter, bm, BM_VERTS_OF_MESH, a) {
|
||||
if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
|
||||
/* check the vertex has a selected edge, only add it once */
|
||||
BM_ITER_ELEM (eed, &itersub, eve, BM_EDGES_OF_VERT) {
|
||||
if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) {
|
||||
totsel++;
|
||||
calc_tw_center(scene, eve->co);
|
||||
calc_tw_center_dm(scene, dmverts, a, derived_index_map);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -337,13 +353,13 @@ static int calc_manipulator_stats(const bContext *C)
|
||||
else {
|
||||
BMIter itersub;
|
||||
BMFace *efa;
|
||||
BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
|
||||
BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, a) {
|
||||
if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
|
||||
/* check the vertex has a selected face, only add it once */
|
||||
BM_ITER_ELEM (efa, &itersub, eve, BM_FACES_OF_VERT) {
|
||||
if (BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
|
||||
totsel++;
|
||||
calc_tw_center(scene, eve->co);
|
||||
calc_tw_center_dm(scene, dmverts, a, derived_index_map);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -351,6 +367,9 @@ static int calc_manipulator_stats(const bContext *C)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (derived_index_map)
|
||||
MEM_freeN(derived_index_map);
|
||||
} /* end editmesh */
|
||||
else if (obedit->type == OB_ARMATURE) {
|
||||
bArmature *arm = obedit->data;
|
||||
|
@@ -37,11 +37,19 @@
|
||||
|
||||
#include "DNA_defs.h"
|
||||
#include "DNA_listBase.h"
|
||||
#include "DNA_meshdata_types.h"
|
||||
#include "DNA_ID.h"
|
||||
|
||||
struct AnimData;
|
||||
struct Ipo;
|
||||
|
||||
# /* These two things tell makesdna to ignore this struct */
|
||||
#
|
||||
typedef struct CompressedMeshVertex {
|
||||
int vertex_index;
|
||||
float co[3];
|
||||
} CompressedMeshVertex;
|
||||
|
||||
typedef struct KeyBlock {
|
||||
struct KeyBlock *next, *prev;
|
||||
|
||||
@@ -62,13 +70,22 @@ typedef struct KeyBlock {
|
||||
void *data; /* array of shape key values, size is (Key->elemsize * KeyBlock->totelem) */
|
||||
char name[64]; /* MAX_NAME (unique name, user assigned) */
|
||||
char vgroup[64]; /* MAX_VGROUP_NAME (optional vertex group), array gets allocated into 'weights' when set */
|
||||
|
||||
float mixval; /* animation-independent mix influence (Key->type == KEY_RELATIVE only) */
|
||||
|
||||
/* ranges, for RNA and UI only to clamp 'curval' */
|
||||
/* ranges, for RNA and UI only to clamp 'curval' and 'mixval' */
|
||||
float slidermin;
|
||||
float slidermax;
|
||||
|
||||
char pad[4];
|
||||
} KeyBlock;
|
||||
|
||||
typedef struct ScratchKeyBlock {
|
||||
/* array of values, size Key->elemsize * KeyBlock->totelem */
|
||||
void *data;
|
||||
/* where this scratch has come from, all other setting are read from there */
|
||||
KeyBlock *origin;
|
||||
} ScratchKeyBlock;
|
||||
|
||||
typedef struct Key {
|
||||
ID id;
|
||||
@@ -78,13 +95,21 @@ typedef struct Key {
|
||||
* Looks like this is _always_ 'key->block.first',
|
||||
* perhaps later on it could be defined as some other KeyBlock - campbell */
|
||||
KeyBlock *refkey;
|
||||
|
||||
/* 'Runtime' KeyBlock where the 'real' data editing happens. Gets committed to its origin (saved in .blend). */
|
||||
ScratchKeyBlock scratch;
|
||||
|
||||
/* Strictly-runtime topology hash, to detect changes in topology of skeyed mesh. */
|
||||
MTopoHash *topohash;
|
||||
|
||||
/* this is not a regular string, although it is \0 terminated
|
||||
* this is an array of (element_array_size, element_type) pairs
|
||||
* (each one char) used for calculating shape key-blocks */
|
||||
char elemstr[32];
|
||||
int elemsize; /* size of each element in #KeyBlock.data, use for allocation and stride */
|
||||
int pad;
|
||||
short pad;
|
||||
short mix_mode; /* Key->type == KEY_RELATIVE only; defines whether the mix will be from the animation or
|
||||
* from the temporary user values */
|
||||
|
||||
ListBase block; /* list of KeyBlock's */
|
||||
struct Ipo *ipo DNA_DEPRECATED; /* old animation system, deprecated for 2.5 */
|
||||
@@ -115,11 +140,23 @@ enum {
|
||||
KEY_RELATIVE = 1
|
||||
};
|
||||
|
||||
/* Key->mix_mode */
|
||||
enum {
|
||||
KEY_MIX_FROM_TEMPVALUES = 0,
|
||||
KEY_MIX_FROM_ANIMDATA = 1,
|
||||
};
|
||||
|
||||
/* Key->flag */
|
||||
enum {
|
||||
KEY_DS_EXPAND = 1
|
||||
KEY_DS_EXPAND = 1 << 0,
|
||||
/* File save only - if set, key's data is laid out as an array of CompressedMeshVertex structs (total totelem).
|
||||
* Mesh only. Does not do anything useful at runtime */
|
||||
KEY_COMPRESSED = 1 << 1,
|
||||
};
|
||||
|
||||
/* Min squared distance between org vertex and skey one, to store the skey in file (compressed mode only). */
|
||||
#define KEY_MIN_SQUARED_LEN 1e-6f
|
||||
|
||||
/* KeyBlock->type */
|
||||
enum {
|
||||
KEY_LINEAR = 0,
|
||||
|
@@ -38,6 +38,27 @@
|
||||
struct Bone;
|
||||
struct Image;
|
||||
|
||||
/* Generic mesh topology hash.
|
||||
* Note we store also numbers of verts/edges/loops/polys, since checking those is much cheaper than recomputing
|
||||
* the real hash, and should be enough to detect 99% of topology changes!
|
||||
* Strictly runtime, never to be saved, so tag it as DNA-ignored.
|
||||
*/
|
||||
/* Note: only half-convinced we really need numbers of verts/edges/loops/polys here. Thing is, they are only useful
|
||||
* to detect topo *changes*, if topology remains the same we have to recompute the hash every time anyway,
|
||||
* and unchanged topology is the most common expected case... On the other hand, storing numbers here
|
||||
* does not add much overhead, and maybe we'll be happy to have this 'is changed' quick check in some cases?
|
||||
*/
|
||||
#
|
||||
#
|
||||
typedef struct MTopoHash {
|
||||
int totvert;
|
||||
int totedge;
|
||||
int totloop;
|
||||
int totpoly;
|
||||
|
||||
unsigned int hash;
|
||||
} MTopoHash;
|
||||
|
||||
/*tessellation face, see MLoop/MPoly for the real face data*/
|
||||
typedef struct MFace {
|
||||
unsigned int v1, v2, v3, v4;
|
||||
|
@@ -1064,6 +1064,11 @@ typedef struct MeshStatVis {
|
||||
/* *************************************************************** */
|
||||
/* Tool Settings */
|
||||
|
||||
enum {
|
||||
KB_AUTO_COMMIT = 1,
|
||||
KB_DO_NOT_AUTO_COMMIT = 0
|
||||
};
|
||||
|
||||
typedef struct ToolSettings {
|
||||
VPaint *vpaint; /* vertex paint */
|
||||
VPaint *wpaint; /* weight paint */
|
||||
@@ -1286,7 +1291,8 @@ typedef struct Scene {
|
||||
/* Movie Tracking */
|
||||
struct MovieClip *clip; /* active movie clip */
|
||||
|
||||
uint64_t customdata_mask; /* XXX. runtime flag for drawing, actually belongs in the window, only used by BKE_object_handle_update() */
|
||||
uint64_t customdata_mask; /* XXX. runtime flag for drawing, actually belongs in the window, only used by BKE_object_handle_update()
|
||||
* and for drawing 3D manipulator and getting visual tranform center */
|
||||
uint64_t customdata_mask_modal; /* XXX. same as above but for temp operator use (gl renders) */
|
||||
|
||||
/* Color Management */
|
||||
|
@@ -40,6 +40,7 @@
|
||||
#include "RNA_access.h"
|
||||
#include "RNA_define.h"
|
||||
#include "RNA_enum_types.h"
|
||||
#include "ED_mesh.h"
|
||||
|
||||
#include "rna_internal.h"
|
||||
|
||||
@@ -105,6 +106,13 @@ static void rna_ShapeKey_value_set(PointerRNA *ptr, float value)
|
||||
data->curval = value;
|
||||
}
|
||||
|
||||
static void rna_ShapeKey_editmixvalue_set(PointerRNA *ptr, float value)
|
||||
{
|
||||
KeyBlock *data = (KeyBlock *)ptr->data;
|
||||
CLAMP(value, data->slidermin, data->slidermax);
|
||||
data->mixval = value;
|
||||
}
|
||||
|
||||
static void rna_ShapeKey_value_range(PointerRNA *ptr, float *min, float *max,
|
||||
float *UNUSED(softmin), float *UNUSED(softmax))
|
||||
{
|
||||
@@ -192,9 +200,12 @@ static PointerRNA rna_ShapeKey_relative_key_get(PointerRNA *ptr)
|
||||
|
||||
static void rna_ShapeKey_relative_key_set(PointerRNA *ptr, PointerRNA value)
|
||||
{
|
||||
KeyBlock *kb = (KeyBlock *)ptr->data;
|
||||
|
||||
kb->relative = rna_object_shapekey_index_set(ptr->id.data, value, kb->relative);
|
||||
KeyBlock *kb = ptr->data;
|
||||
KeyBlock *basis_can = value.data;
|
||||
if (kb != basis_can)
|
||||
kb->relative = rna_object_shapekey_index_set(ptr->id.data, value, kb->relative);
|
||||
else
|
||||
printf("RNA warning: can't make a shape key %s to be relative to itself.\n", kb->name);
|
||||
}
|
||||
|
||||
static void rna_ShapeKeyPoint_co_get(PointerRNA *ptr, float *values)
|
||||
@@ -377,11 +388,14 @@ static void rna_Key_update_data(Main *bmain, Scene *UNUSED(scene), PointerRNA *p
|
||||
Object *ob;
|
||||
|
||||
for (ob = bmain->object.first; ob; ob = ob->id.next) {
|
||||
if (BKE_key_from_object(ob) == key) {
|
||||
DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
|
||||
WM_main_add_notifier(NC_OBJECT | ND_MODIFIER, ob);
|
||||
}
|
||||
if (BKE_key_from_object(ob) == key)
|
||||
break;
|
||||
}
|
||||
|
||||
BLI_assert(ob);
|
||||
|
||||
DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
|
||||
WM_main_add_notifier(NC_OBJECT | ND_MODIFIER, ob);
|
||||
}
|
||||
|
||||
static KeyBlock *rna_ShapeKeyData_find_keyblock(Key *key, float *point)
|
||||
@@ -590,6 +604,14 @@ static void rna_def_keyblock(BlenderRNA *brna)
|
||||
RNA_def_property_ui_text(prop, "Value", "Value of shape key at the current frame");
|
||||
RNA_def_property_update(prop, 0, "rna_Key_update_data");
|
||||
|
||||
prop = RNA_def_property(srna, "edit_mix_value", PROP_FLOAT, PROP_FACTOR);
|
||||
RNA_def_property_float_sdna(prop, NULL, "mixval");
|
||||
RNA_def_property_float_funcs(prop, NULL, "rna_ShapeKey_editmixvalue_set", "rna_ShapeKey_value_range");
|
||||
RNA_def_property_ui_range(prop, -10.0f, 10.0f, 10, 3);
|
||||
RNA_def_property_ui_text(prop, "Value", "Animation-independent value of shape key for editmode");
|
||||
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); /* don't make this animatable, this would be considered abuse */
|
||||
RNA_def_property_update(prop, 0, "rna_Key_update_data");
|
||||
|
||||
prop = RNA_def_property(srna, "interpolation", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_sdna(prop, NULL, "type");
|
||||
RNA_def_property_enum_items(prop, keyblock_type_items);
|
||||
@@ -670,6 +692,13 @@ static void rna_def_key(BlenderRNA *brna)
|
||||
"otherwise play through shapes as a sequence using the evaluation time");
|
||||
RNA_def_property_update(prop, 0, "rna_Key_update_data");
|
||||
|
||||
prop = RNA_def_property(srna, "mix_from_animation", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "mix_mode", KEY_MIX_FROM_TEMPVALUES);
|
||||
RNA_def_property_ui_text(prop, "Mix From Animation", "Make animation curves define the shape mix, "
|
||||
"or use an animation-independent mix");
|
||||
RNA_def_property_update(prop, 0, "rna_Key_update_data");
|
||||
RNA_def_property_ui_icon(prop, ICON_IPO_BEZIER, 0);
|
||||
|
||||
prop = RNA_def_property(srna, "eval_time", PROP_FLOAT, PROP_NONE);
|
||||
RNA_def_property_float_sdna(prop, NULL, "ctime");
|
||||
RNA_def_property_range(prop, MINFRAME, MAXFRAME);
|
||||
|
@@ -271,13 +271,9 @@ static void rna_Object_active_shape_update(Main *bmain, Scene *scene, PointerRNA
|
||||
Object *ob = ptr->id.data;
|
||||
|
||||
if (scene->obedit == ob) {
|
||||
/* exit/enter editmode to get new shape */
|
||||
switch (ob->type) {
|
||||
case OB_MESH:
|
||||
EDBM_mesh_load(ob);
|
||||
EDBM_mesh_make(scene->toolsettings, ob);
|
||||
EDBM_mesh_normals_update(((Mesh *)ob->data)->edit_btmesh);
|
||||
BKE_editmesh_tessface_calc(((Mesh *)ob->data)->edit_btmesh);
|
||||
EDBM_handle_active_shape_update(ob, scene);
|
||||
break;
|
||||
case OB_CURVE:
|
||||
case OB_SURF:
|
||||
|
@@ -908,7 +908,7 @@ static PyObject *bpy_bmesh_to_mesh(BPy_BMesh *self, PyObject *args)
|
||||
/* python won't ensure matching uv/mtex */
|
||||
BM_mesh_cd_validate(bm);
|
||||
|
||||
BM_mesh_bm_to_me(bm, me, false);
|
||||
BM_mesh_bm_to_me(bm, me, false, true);
|
||||
|
||||
/* we could have the user do this but if they forget blender can easy crash
|
||||
* since the references arrays for the objects derived meshes are now invalid */
|
||||
|
@@ -2844,6 +2844,9 @@ static int wm_save_as_mainfile_exec(bContext *C, wmOperator *op)
|
||||
G_FILE_MESH_COMPAT);
|
||||
#endif
|
||||
|
||||
BKE_BIT_TEST_SET(fileflags, RNA_boolean_get(op->ptr, "use_shapekey_compat"),
|
||||
G_FILE_SHAPEKEY_COMPAT);
|
||||
|
||||
if (wm_file_write(C, path, fileflags, op->reports) != 0)
|
||||
return OPERATOR_CANCELLED;
|
||||
|
||||
@@ -2893,6 +2896,8 @@ static void WM_OT_save_as_mainfile(wmOperatorType *ot)
|
||||
"Save using legacy mesh format (no ngons) - WARNING: only saves tris and quads, other ngons will "
|
||||
"be lost (no implicit triangulation)");
|
||||
#endif
|
||||
RNA_def_boolean(ot->srna, "use_shapekey_compat", false, "Legacy ShapeKey Format",
|
||||
"Save using legacy ShapeKey format (no compression)");
|
||||
}
|
||||
|
||||
/* *************** save file directly ******** */
|
||||
@@ -2961,6 +2966,8 @@ static void WM_OT_save_mainfile(wmOperatorType *ot)
|
||||
RNA_def_boolean(ot->srna, "compress", false, "Compress", "Write compressed .blend file");
|
||||
RNA_def_boolean(ot->srna, "relative_remap", false, "Remap Relative",
|
||||
"Remap relative paths when saving in a different directory");
|
||||
RNA_def_boolean(ot->srna, "use_shapekey_compat", false, "Legacy ShapeKey Format",
|
||||
"Save using legacy ShapeKey format (no compression)");
|
||||
}
|
||||
|
||||
static void WM_OT_window_fullscreen_toggle(wmOperatorType *ot)
|
||||
|
@@ -216,6 +216,7 @@ void EDBM_selectmode_set(struct BMEditMesh *em) RET_NONE
|
||||
void EDBM_mesh_load(struct Object *ob) RET_NONE
|
||||
void EDBM_mesh_make(struct ToolSettings *ts, struct Object *ob) RET_NONE
|
||||
void EDBM_mesh_normals_update(struct BMEditMesh *em) RET_NONE
|
||||
void EDBM_handle_active_shape_update(struct Object *ob, struct Scene *s) RET_NONE
|
||||
void *g_system;
|
||||
|
||||
float *RE_RenderLayerGetPass(struct RenderLayer *rl, int passtype) RET_NULL
|
||||
|
@@ -192,7 +192,7 @@ bool BL_ShapeDeformer::Update(void)
|
||||
VerifyStorage();
|
||||
|
||||
per_keyblock_weights = BKE_keyblock_get_per_block_weights(blendobj, m_key, &cache);
|
||||
BKE_key_evaluate_relative(0, m_bmesh->totvert, m_bmesh->totvert, (char *)(float *)m_transverts,
|
||||
BKE_key_evaluate_relative(blendobj, 0, m_bmesh->totvert, m_bmesh->totvert, (char *)(float *)m_transverts,
|
||||
m_key, NULL, per_keyblock_weights, 0); /* last arg is ignored */
|
||||
BKE_keyblock_free_per_block_weights(m_key, per_keyblock_weights, &cache);
|
||||
|
||||
|
Reference in New Issue
Block a user