1
1

Compare commits

...

113 Commits

Author SHA1 Message Date
e56beb5c5f Remove 'topochange' from EDBM.
In future, there may be several tools relying on topo hash, each one making
updates to it when it needs. Hence, such thing should absolutely not be held
by mesh data, but (in this case) by Key data.

Also made some reorganization and renaming a bit.

Note: this code compiles, but for now cannot really be tested, since scratch
is not enabled...
2014-11-15 19:02:56 +01:00
2a88cabaab Merge branch 'master' into soc-2014-shapekey 2014-11-15 18:40:09 +01:00
f93b0a746d Merge branch 'master' into soc-2014-shapekey 2014-11-15 14:37:03 +01:00
a8c7a98826 Add Mesh's counterpart to BM_mesh_topology_hash. 2014-11-14 12:54:46 +01:00
0f91a7c528 Fix stupid logic error. 2014-11-14 12:35:15 +01:00
ac49d2b7b9 Use new BLI_hash_mm2a. 2014-11-14 12:34:06 +01:00
4da6eed0d8 Merge branch 'master' into soc-2014-shapekey 2014-11-14 11:04:28 +01:00
85b4c61b4e Reorganization and better topohash code (2 times faster at least).
WIP, will move murmur2a to BLI in master first.
2014-11-11 18:22:14 +01:00
ed24379fcc Merge branch 'master' into soc-2014-shapekey 2014-11-11 08:48:10 +01:00
53ae7384a6 Merge branch 'master' into soc-2014-shapekey
Conflicts:
	source/blender/editors/mesh/editmesh_utils.c
2014-11-10 14:19:52 +01:00
e49550d73b Merge branch 'master' into soc-2014-shapekey 2014-11-02 11:25:22 +01:00
4efb5bf5c6 Merge branch 'master' into soc-2014-shapekey
Conflicts:
	source/blender/windowmanager/intern/wm_operators.c
2014-11-01 22:27:56 +01:00
2a72704c16 Tweaks to skey compression: switch from userpref option to savefile op option.
Makes more sense, and follow what we did e.g. for BMesh.
2014-11-01 21:40:09 +01:00
2420ffb7ef Fix for previous merge. 2014-11-01 21:37:39 +01:00
0288d50bc5 Merge branch 'master' into soc-2014-shapekey 2014-11-01 19:08:10 +01:00
56da7947c9 Cleanup some leftover changes from merge of 'move skey' part in master. 2014-10-30 19:31:19 +01:00
4d6e11b87f Merge branch 'master' into soc-2014-shapekey 2014-10-30 19:19:51 +01:00
bbb22f8036 Merge branch 'master' into soc-2014-shapekey 2014-10-21 14:10:52 +02:00
33fb541e32 Merge branch 'master' into soc-2014-shapekey
Conflicts:
	source/blender/blenkernel/BKE_key.h
	source/blender/blenkernel/intern/key.c
2014-10-21 12:13:32 +02:00
1628ab6960 Better icons (use one tri + bar to symbolyze 'ultimate' left/right/up/down).
More universal and sensible (double tri usually means 'quicker' rather than 'farther').
2014-10-21 10:38:03 +02:00
b775a76d66 Merge branch 'master' into soc-2014-shapekey 2014-10-21 08:46:06 +02:00
a0741a473b slightly less verbose version of previous work. 2014-10-20 18:11:42 +02:00
a8aa291e13 Full rewrite of 'move shapekeys' code.
Now handles correctly position of absolute skeys in all cases. Also only does one
full loop over whole list.

Ans some more cleanup.
2014-10-20 17:04:17 +02:00
a5d52cf758 Some UI cleanup and bringback in sync with master (show frames for absolute keys was lost somehow). 2014-10-20 14:05:23 +02:00
69b310c628 Merge branch 'master' into soc-2014-shapekey 2014-10-20 13:12:48 +02:00
b04728785f More picky little 'master-synchronization' 2014-10-19 20:27:55 +02:00
f0f36eeef0 Merge branch 'master' into soc-2014-shapekey
Conflicts:
	source/blender/blenloader/intern/versioning_270.c
	source/blender/editors/transform/transform_generics.c
2014-10-19 20:26:09 +02:00
33ed259044 Cleanup
Mostly, revert unrelevant changes from master, with a few style cleanup as well here and there.
No change in behavior expected!
2014-10-19 19:17:31 +02:00
f59b30e41e Merge branch 'master' into soc-2014-shapekey 2014-10-19 17:16:06 +02:00
0d7fd47878 Restore double-up/down arrows icons. 2014-10-10 22:40:35 +02:00
e5a1c2ef65 Merge branch 'master' into soc-2014-shapekey
Conflicts:
	release/datafiles/blender_icons.svg
	source/blender/editors/mesh/editmesh_tools.c
	source/blender/editors/object/object_shapekey.c

Note about blender_icons.svg: blindly reset to master state, hard to do otherwise on such file... :/
2014-10-10 22:09:04 +02:00
e74279b77d Fixed compilation under MSVC 2014-08-15 03:08:17 +04:00
1b7dadd6ba Cleanup of gcc warnings. 2014-08-10 17:27:08 +02:00
c597a1bb75 Fix compilation after merge. 2014-08-10 17:01:35 +02:00
f838e3632d Merge branch 'master' into soc-2014-shapekey
Conflicts:
	source/blender/editors/object/object_shapekey.c
2014-08-10 16:58:22 +02:00
002cb94cc6 Better naming for compressed keyblock vertices-related stuff
(No 'real' changes)
2014-08-03 17:16:12 +04:00
30099d8544 Merge remote-tracking branch 'origin' into soc
Conflicts:
	source/blender/blenloader/intern/versioning_270.c
2014-08-02 06:11:51 +04:00
7038bdb159 Another iteration for Modal Blend From Shape 2014-08-02 04:21:58 +04:00
b811398778 Fixed a crash in Blend From Shape involving boundboxes 2014-08-01 20:37:20 +04:00
31c242fd0f Double triangle icons for Shape Key Move
Shape Key Move now has proper icons for moving the shape keys to top or bottom of the list
2014-08-01 15:22:01 +04:00
c484f4cf8d Fixed crash on edge bevel and edge crease adjust
How didn't I notice that stuff earlier? New transform center code would
fail in these cases.
2014-07-25 17:58:54 +04:00
8c221fb0bb Fixed a crash when renaming shapes in editmode 2014-07-25 15:47:48 +04:00
cfc3adc80b Fixed a bug in keyblock compression
If the file was saved with compression and then saved over with Legacy
Keyblocks option, the compress flag was never cleared and file failed to
load.
2014-07-25 13:57:17 +04:00
aa3953c0cb Added basic info display to Modal Blend From Shape 2014-07-23 03:15:40 +04:00
cad1e40995 Don't draw shape key values in Absolute mode 2014-07-21 15:21:41 +04:00
f43fb3ee82 Fixed a bad crash while switching shapekeys with topo changes
Turned out to be a memory corruption issue due to a stupid 'premature
optimization' attempt, used Valgrind to figure out where that was.
2014-07-19 02:41:37 +04:00
b9893a8f6a Fixed compilation under GCC 2014-07-18 21:44:42 +04:00
bec0bd734e Merge remote-tracking branch 'origin' into soc 2014-07-10 17:51:59 +04:00
1a6c7a142e Updated modal Blend From Shape
Now can switch between Add Mode and Blend (Interp) Mode with MMB, cycle falloff types with O and cycle PE types with Shift-O
2014-07-09 01:52:25 +04:00
09d95bc8ca Dirty prototype for modal Blend From Shape with PE
Supports intepreting between keys for now. Move mouse L/R to adjust intensity and Up/Down to adjust PE falloff!
2014-07-08 03:58:11 +04:00
e3ccce5864 Fixed meshes without shape keys not being loaded on em exit 2014-07-07 16:24:31 +04:00
635b4e377b In sculpt mode, new shape keys will have value = 1.0
...as per qurq's request finally!
2014-07-06 11:41:00 +04:00
2939cda6b2 Added Commit To Another Shape
This new operator allows you to change shapes while editing, helping if you've edited the wrong shape.

Implementation-wise had to slightly change the way editmode undo is pushed and popped, this operator messed with it. Now RealMesh keyblocks will be restored from the stored UndoMesh on undo pop.
2014-07-06 01:58:54 +04:00
1fcb5e986a Made debug-built blender pause on exit if there's unfreed memory 2014-07-06 01:54:41 +04:00
80fdc894ac Incorporated D460 undo fix in soc-2014-shapekey 2014-07-04 02:52:48 +04:00
860eed1f87 Fixed undo in editmode getting things broken
This actually consisted of two bugs: scratch shape key was interfering with undo and with-topology-change shape swithing was handled incorrectly.

Spent way too much time pinpointing this, ugh! :(
2014-07-04 02:45:24 +04:00
452374f8d2 Merge remote-tracking branch 'origin' into soc 2014-07-01 21:32:47 +04:00
ed52efdd35 Scratch shape key now exists only in EM
Stopped writing it to disk and to undo, pointless!
2014-06-22 19:39:39 +04:00
4b4b1582eb Stopped blender closing itself in debug build crashes on Win
TerminateProcess in creator.c crash handling prevented MSVC from seeing an
unhandled exception, now it won't so we can actually see where the problem
happened.
2014-06-22 19:38:48 +04:00
002c747926 Cosmetic -- corrected odd brace placement 2014-06-22 15:55:09 +04:00
f2a996bbde Merge branch 'master' into soc 2014-06-21 22:44:30 +04:00
236a578a87 Merging second round of trasnform patch code review
Conflicts:
	source/blender/editors/transform/transform_manipulator.c
2014-06-21 22:21:07 +04:00
8b4efc6283 Got rid of some more gcc warnings in own code 2014-06-21 02:05:32 +04:00
52ce0e546e Got rid of most GCC warnings
Mostly missing 'static' declarations and some potential bugs.
2014-06-21 01:59:32 +04:00
54d069b593 Fix compilation on gcc (minimalist changes, only tackled errors, not warnings).
Fixed two cases of 'code before var declarations'.
Did not touch to missing 'static' for functions, nor 'UNUSED' parameters...
2014-06-19 13:49:34 +02:00
99e361ffd4 Addressing mont29's code review
Also removed pointless #include "BKE_key.h" in transform_manipulator.c
2014-06-15 23:25:33 +04:00
3b9e69cbdf Merge remote-tracking branch 'origin/master' into soc
Now I have a facny 2.71 splash too!

Conflicts:
	source/blender/blenloader/intern/versioning_270.c
2014-06-15 18:51:17 +04:00
4c56a47730 Fixed yesterday's shape key compression
1) Shape key data would fail to link on file read, fixed now.

2) Endianess flipping now supports compressed shape keys, just have to
test (thanks ideasman42 for ideas)

3) Also removed some debug printfs
2014-06-14 21:30:25 +04:00
610a3e288e Implemented mesh shape key compression
Mesh shape keys are now compressed on file write by storing only the vertices that have changed from the rest position (the logic automatically determines if there will be a gain from such compression, if not, no compression will happen).

This showed 3x disk space reduction on Elizabeth's head here (4.5 kvert mesh, 157 shape keys for different facial expression):
http://dl.dropboxusercontent.com/u/91422001/liz_headonly_masterbranch.blend
http://cs617325.vk.me/v617325382/e0e1/cjnMXhbtU44.jpg

A User Preference (on File tab) has been added to save the shape keys in the old format (compressed shape keys won't be readable from Master branch)

This also decreases object mode undo memory usage, as undo uses a file in memory.

TODO: endian conversions won't work on compressed keys right now.
2014-06-14 03:42:17 +04:00
b01c944552 Small speedup - compute hash only if there are keyblocks 2014-06-12 20:03:13 +04:00
31a1d1cad4 Merge remote-tracking branch 'origin' into soc 2014-06-12 19:07:42 +04:00
5fea04bed0 Changed the subversion back to master
Versioning now uses DNA_struct_elem_find

Also, got rid of forgotten auto-commit leftover
2014-06-12 17:27:14 +04:00
f272a91113 Fixed blenderplayer link error 2014-06-12 16:38:53 +04:00
4775345805 Fixed GE compile error, thanks MiikaH 2014-06-12 02:06:15 +04:00
516038c983 Transform constraint and propcircle drawing positions update
Manipulator and constraints and prop circle are now drawn where they should be drawn: on derived cage-based positions.

http://screenshot.su/img/ef/e6/26/efe626a9a496e794c174e76ec9522736.jpg

Moved the mapping function over to crazyspace, seems a better place for them. Abstracted active element center calculation to crazyspace, too. Use scene->customdata_mask on mesh to prevent recalculating the DerivedMesh every time.

Screenshot here:
2014-06-12 02:06:14 +04:00
ed01fea80a Merge branch 'manip-fix' into soc 2014-06-08 03:39:31 +04:00
f3503448d3 Merge remote-tracking branch 'origin' into soc 2014-06-08 03:39:26 +04:00
edff9d3eda Merge remote-tracking branch 'origin' into manip-fix 2014-06-08 03:39:12 +04:00
26efda7327 Moved index mapping to DerivedMesh.c for reuse
Can move to fixing constraints drawing in the morning now, reusing this part of code
2014-06-08 03:38:03 +04:00
1f151d6319 Intermediate code for fixing transform manip draw 2014-06-08 01:43:52 +04:00
cc05580813 Corrections to the last commit 2014-06-06 12:03:35 +04:00
7aeef37d54 Merge branch 'manip-fix' into soc 2014-06-06 11:42:41 +04:00
8824482287 Corrections for getting the derived data for manip
Was getting the wrong DerivedMesh & didn't need customdata
2014-06-06 11:40:10 +04:00
ab73b97928 Merge branch 'manip-fix' into soc 2014-06-06 02:23:12 +04:00
4afcb68668 Merge remote-tracking branch 'origin/master' into soc 2014-06-06 02:22:18 +04:00
96e296c659 Manip handles are now drawn in right place with deform modifiers
Now to constraint axis
2014-06-06 02:17:22 +04:00
63a7fbe3a0 Reverting getting rid of Apply Shape Keys in EM
This turned out to be a bad idea after all. Now, Apply Shape Keys in
Editmode works as it did before. Shape recalc hasn't been changed.
Key->pin moved back to object->shapeflag.

Apply Shape Keys in Editmode is made to be aware of the alternative
editmode mix and the user can switch between them.
2014-06-05 15:35:26 +04:00
a48122cde5 Merge remote-tracking branch 'origin/master' into soc 2014-06-02 01:39:27 +04:00
aa009766d6 Can mix shapekeys in editmode now
The user can now edit a shape key on top of a mix.

The difference to the master is that the 'Apply Shape Keys in Editmode' is gone completely. You can either pin the shapekey or edit on top of a mix: http://screenshot.su/img/a1/70/dc/a170dc61123ee1648e8a6dc3394b3812.jpg, and that is all.

The user can select the values that he wants to use in the mix: the animation-driven values (KeyBlock->curval) or a temporary mix value visible only in editmode.

Implementation-wise this is sort of an emulation of the shape keys modifier behavior. On editmode enter, the mesh keyblocks get evaluated and that is put in the edit coordinates. On shapekey switch or editmode exit the underlying mix gets subtracted from the editmesh cos, the resulting isolated shape coordinates gets adjusted for value (we store data with 1.0 values only!) and than processed as a normal (pinned) shape key update. Then the mesh gets re-evaluated, etc.

There is some optimization potential which will be explored!

Undo might be broken at the moment, this is the next thing to do.
2014-06-02 01:26:15 +04:00
68e60b3cbb Fixed key->mix_mode having incorrect values
The values of mix_mode (KEY_MIX_FROM_ANIMDATA/KEY_MIX_FROM_TEMPVALUES)
were used the wrong way. Also, added a function to access the active value
of the keyblock.
2014-05-31 00:48:14 +04:00
dd69bfae24 Fixed a bug in hashing where it would crash on certain wire meshes 2014-05-28 21:33:06 +04:00
0c4fe0b50e Merge remote-tracking branch 'origin/master' into soc 2014-05-25 19:40:38 +04:00
ba3a78472a Correction to the last merge 2014-05-19 08:57:32 +04:00
9492d96dc5 Merge remote-tracking branch 'origin/master' into soc 2014-05-19 02:40:36 +04:00
4c02209769 Moved Object->shapeflag to Key->pin
Since we aren't going to use the shape key modifier for editmode blending,
Apply Shape Keys in Editmode is now obsolete too, and shapeflag just says
is the key is pinned or not.

Why to do this? In editmode, we want to be able to switch from Blending
shapekeys to pinned shapekeys and this is done in key RNA update handler,
so we want it to be called when pinning changes.

The RNA property was removed from the Object and added to the Key, all
code that referenced Object->shapeflag now references Key->pin.

The UI was updated to accomodate for that.

Unrelated change which I couldn't stage seperately is that there is now
support for temporary mix values from RNA and UI. The user can select
which one to use in Editmode. The value in the UI will automatically
reflect the editmix or the animation mix, transparent for the artist.
2014-05-19 02:34:33 +04:00
097178e8ea Added an include guard to bmesh_pe.h 2014-05-19 01:18:08 +04:00
3e68ab7893 Cleaned up mm2_hash() 2014-05-18 02:53:00 +04:00
fa5dac46b7 Removed a pointless assert and a bad totelem change from editdata_to_scratch 2014-05-18 02:49:08 +04:00
82ad15d379 Changed the topology hash function to Murmur2, hashing improved altogether.
According to that [1], Murmur2 is faster and will work quite good in our situation.

[1] http://floodyberry.com/noncryptohashzoo/
2014-05-18 02:48:05 +04:00
43fb821054 Fixed a dumb out-of-bounds on topology-changing keyblock recalc
BKE_key_editdata_to_scratch didn't alloc space in the scratch if more verts were in the new mesh
2014-05-18 00:55:00 +04:00
1e9b5a7076 Merge remote-tracking branch 'origin/master' into soc 2014-05-16 03:49:42 +04:00
3f5bfbbae5 Initial rough support for Scratch Shapekey
Scratch shape key types added to Key DNA. Modifications to file
reading/writing are done to save the Scratch's data.

Auto-commit property is added to the Scene's tool_settings. Versioning
code to set it to 1 by default is added.

EditMesh kernel module now has a hashing function to determine if the
mesh's topology has been changed.

editmesh_utils.c now has features to work with both the scratch shape key,
supporting scratch-based shape key recalculations, and sped-up
shapekey recalculation in case the Mesh didn't change topology.
This is draft rough buggy code yet.

UI: added Auto-Commit under the Shape Keys panel, removed Apply Shape keys
in Edit Mode - won't be needed later.

Next to do: check undo support.
2014-05-16 03:42:43 +04:00
e9c28ddbbd Implemented draft topology x17-based hashing in BKE_editmesh 2014-05-16 03:19:36 +04:00
c6c9a279ab Revert "Minor cleanup in key.c"
This reverts commit 25883c59cd0320c5f0841145352aed411220def5.

Was a terrible idea after two hours of WTF crashes
2014-05-13 15:29:37 +04:00
09694357dc Minor cleanup in key.c 2014-05-13 15:29:37 +04:00
32ae05b96c Modifications to key DNA and RNA to have initial types for scratch and mix switching 2014-05-13 15:29:36 +04:00
9674ed1b22 It's now forbidden to set a shape key to be relative to itself 2014-05-13 15:29:36 +04:00
c804a4daeb Small updates on bmesh_pe 2014-05-13 15:29:36 +04:00
268f7bedb5 Remove testing code from transform_conversions 2014-05-13 15:29:35 +04:00
3f8794a405 Small style cleanup in key.c 2014-05-13 15:29:35 +04:00
dad4b619f5 Proportional editing distance for BMeshes
Connected, projected and simple falloff distance calculation can now be
done from bmesh_pe.h.

Temporary terrible code alterations to test the falloff routines in transform engine
2014-05-13 15:29:34 +04:00
3c7b8f0086 A much better shapekey-movement idea
Removed place at index and updated Shape Key Move instead to do the same
thing and not break existing Python access to Shape Key move.
2014-05-13 15:29:34 +04:00
2b3810f672 Shape keys code cleanup round 1
BKE_key_move introduced. Moves a shape key to a given index in the shape
key list. Has a wrapper operator. Can implement shape key sorting now and other stuff.

TODO: need double triangle icon!
2014-05-13 15:29:33 +04:00
46 changed files with 2424 additions and 175 deletions

View File

@@ -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")

View File

@@ -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

View File

@@ -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,

View File

@@ -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)

View File

@@ -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;

View File

@@ -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 *** */

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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,

View File

@@ -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);
}

View File

@@ -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);
}
}
}

View File

@@ -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);
}
}

View File

@@ -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)

View File

@@ -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);
}
}
}

View File

@@ -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;
}
}
/* } */
}

View File

@@ -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) {

View File

@@ -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

View File

@@ -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

View File

@@ -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;

View File

@@ -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__ */

View 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;
}

View 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__ */

View File

@@ -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) {

View File

@@ -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;

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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

View File

@@ -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);

View File

@@ -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);
}

View File

@@ -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);

View File

@@ -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);

View File

@@ -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) {

View File

@@ -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--;
}

View File

@@ -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)

View File

@@ -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;

View File

@@ -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:

View File

@@ -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;

View File

@@ -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,

View File

@@ -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;

View File

@@ -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 */

View File

@@ -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);

View File

@@ -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:

View File

@@ -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 */

View File

@@ -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)

View File

@@ -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

View File

@@ -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);