Compare commits
214 Commits
temp-geome
...
soc-2017-n
Author | SHA1 | Date | |
---|---|---|---|
2da3949e26 | |||
3b01edd52e | |||
8e44c30d71 | |||
b4c057f42f | |||
4ae2d8daf9 | |||
ec52b7dbb6 | |||
51e196f716 | |||
6e57d8475b | |||
15e299a8b2 | |||
d6940e4e89 | |||
ec58cbbfa6 | |||
cd7d305d1a | |||
4be1a79a14 | |||
a7a4beecb2 | |||
e294a1154c | |||
bcfc16fcca | |||
ec82e6ffcd | |||
970d16b669 | |||
93ef006e3c | |||
bd74ae9ca5 | |||
c389ba20d3 | |||
cd06e503a5 | |||
4fa55703dc | |||
76817f1745 | |||
b19b250d55 | |||
481dc77389 | |||
04e61143c5 | |||
c63e9a32e8 | |||
d1596dc170 | |||
acb4a99c42 | |||
d92bd5746d | |||
87d167e303 | |||
7b512dde2d | |||
d7a8cb0a35 | |||
2e26844ef6 | |||
9a568dbce0 | |||
5bc2f90d6f | |||
f9b2e4a16b | |||
fdd7b788ac | |||
604b6369da | |||
9d3ad0eb5a | |||
0d60656039 | |||
5fbc799d37 | |||
11adf6e998 | |||
e8bce2b56d | |||
399cbf9f4b | |||
b41bce3905 | |||
648cdd7984 | |||
b9573ac780 | |||
a08e5d8695 | |||
4bb4749791 | |||
8c4295f3c3 | |||
5a6be7ba72 | |||
ee23226f5d | |||
d17d562ad0 | |||
dd6642bb80 | |||
40407509d4 | |||
78b555b940 | |||
4220891236 | |||
ccd25d93a4 | |||
70bc7fbe37 | |||
203af5af9b | |||
f0e23f9321 | |||
5ee8eac59e | |||
f956156e32 | |||
0a01cc04d6 | |||
1f649dc265 | |||
95bbe124a1 | |||
c8d84df4aa | |||
7c8d616cbc | |||
14fc221614 | |||
d35869ace8 | |||
670aea5029 | |||
a578ea34f7 | |||
eff73afd72 | |||
4b4114acc4 | |||
50e32a7744 | |||
e7b93f06e1 | |||
f9d7ff4d2d | |||
e45dbcfb6b | |||
cabec0af38 | |||
9f10bfc1e4 | |||
920294b248 | |||
3fa30dfa40 | |||
60b2603634 | |||
5d11e6a009 | |||
502ebd058a | |||
![]() |
5d8e35d9d9 | ||
8524793a39 | |||
28e2ee839e | |||
a31c8d1fe3 | |||
6ee95ebc75 | |||
ff15d06f53 | |||
8eb7f3a3d4 | |||
aac0c9b910 | |||
460b8600d5 | |||
41eaabfb38 | |||
a63cb77c56 | |||
40a034e522 | |||
39c1f7318a | |||
cb3d7e28bb | |||
e0b4c8b250 | |||
d96556021d | |||
22616a67c9 | |||
98ed543352 | |||
ecf1ef7420 | |||
9d0d881fa5 | |||
f03533fda1 | |||
9dcc9e3bc4 | |||
61a5e1bd54 | |||
c67a6a8d1b | |||
ab6df05037 | |||
cb10147f78 | |||
598198f8c0 | |||
3b2865e88c | |||
5255dc86c7 | |||
724cdee37b | |||
2eedacfee2 | |||
d23e682cc6 | |||
c280d8c8e9 | |||
3e8c42a36c | |||
20303c5fe6 | |||
100fe0ad1c | |||
eb0fb1eb13 | |||
65e3d546f1 | |||
7858428075 | |||
4993d3f3a4 | |||
db480d0e9f | |||
b6ff16f426 | |||
bfce6fa630 | |||
009129c0c9 | |||
de1d13f03a | |||
81cb9381a7 | |||
dbd3445d78 | |||
27ffbb5d99 | |||
0e73b3e5bd | |||
b4ca473704 | |||
f4588ec10f | |||
08bda283f7 | |||
dc64328df1 | |||
1139f19db2 | |||
cfe33f3d58 | |||
b7a753cc6f | |||
f43a48ac7e | |||
5fe32381a3 | |||
0b0af5baa6 | |||
ce9fa1fb75 | |||
f85cff9fd4 | |||
6b1d91f20c | |||
4d3ed78510 | |||
4f7bc6da81 | |||
243dcf5e87 | |||
b4ee0225fb | |||
1c6f59def7 | |||
3cc2dcdb0b | |||
39e60c3067 | |||
ea631a1e7a | |||
4a438cfa58 | |||
1f5857b395 | |||
3776754641 | |||
dca08a4440 | |||
986b1f6f32 | |||
18df657631 | |||
8c942d9708 | |||
1b92a80703 | |||
96e76ea4a3 | |||
342793ef75 | |||
2b5f825ce4 | |||
a917e14afa | |||
395119d5ce | |||
07c700365b | |||
28afe63fb7 | |||
29e5f37bdd | |||
3df612c61f | |||
7eb51ebaae | |||
16289abe50 | |||
c7e8f0d6da | |||
c174f1c888 | |||
5aab60e60f | |||
fd3960a4eb | |||
c1af648c33 | |||
d0c25f8296 | |||
8b4d448ec7 | |||
6a06b247d8 | |||
7c8ecd9226 | |||
33a95c40a3 | |||
d586e5557b | |||
86e6350747 | |||
3858f956db | |||
604bd8799e | |||
94007a1769 | |||
51d49a0f7c | |||
9773709cf1 | |||
d438bbfa43 | |||
4a7653005b | |||
626c9888d7 | |||
55237cfe97 | |||
7376444b84 | |||
28061ac85e | |||
448c61b861 | |||
41b118c9d9 | |||
5c8a38a858 | |||
a2ad1b4e88 | |||
137bcc528a | |||
66199cf540 | |||
1516d8d1d1 | |||
19ff231ff5 | |||
201689daeb | |||
15279c04d7 | |||
cd9939fa50 | |||
9673aa8c15 | |||
bf892c10fc | |||
5bc15b3f75 | |||
cf811e7828 |
30
README.md
Normal file
30
README.md
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
# soc-2017-normal-tools
|
||||||
|
|
||||||
|
Clone of my GSoC branch hosted at Blender's git servers [soc-2017-normal-tools](https://git.blender.org/gitweb/gitweb.cgi/blender.git/shortlog/refs/heads/soc-2017-normal-tools)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### Phabricator tracker
|
||||||
|
|
||||||
|
https://developer.blender.org/diffusion/B/browse/soc-2017-normal-tools/
|
||||||
|
|
||||||
|
### Proposal
|
||||||
|
|
||||||
|
https://wiki.blender.org/index.php/User:RohanRathi/GSoC_2017/Proposal
|
||||||
|
|
||||||
|
### Weekly Reports
|
||||||
|
|
||||||
|
https://wiki.blender.org/index.php/User:RohanRathi/GSoC_2017/Reports
|
||||||
|
|
||||||
|
### Blender Artists thread
|
||||||
|
|
||||||
|
https://blenderartists.org/forum/showthread.php?427746-GSoC-2017-Normal-Editing-Tools
|
||||||
|
|
||||||
|
### User Documentation
|
||||||
|
|
||||||
|
https://wiki.blender.org/index.php/User:RohanRathi/GSoC_2017/User_Documentation
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Do note that this branch does not include any other work not associated with Normal editing.
|
Submodule release/datafiles/locale updated: 469c949d1c...59495b4b59
Submodule release/scripts/addons updated: c88411ff77...27970761a1
Submodule release/scripts/addons_contrib updated: 310578043d...6a4f93c9b8
@@ -56,6 +56,7 @@ KM_HIERARCHY = [
|
|||||||
('Particle', 'EMPTY', 'WINDOW', []),
|
('Particle', 'EMPTY', 'WINDOW', []),
|
||||||
|
|
||||||
('Knife Tool Modal Map', 'EMPTY', 'WINDOW', []),
|
('Knife Tool Modal Map', 'EMPTY', 'WINDOW', []),
|
||||||
|
('Custom Normals Modal Map', 'EMPTY', 'WINDOW', []),
|
||||||
('Paint Stroke Modal', 'EMPTY', 'WINDOW', []),
|
('Paint Stroke Modal', 'EMPTY', 'WINDOW', []),
|
||||||
('Paint Curve', 'EMPTY', 'WINDOW', []),
|
('Paint Curve', 'EMPTY', 'WINDOW', []),
|
||||||
|
|
||||||
|
@@ -203,57 +203,7 @@ class MeshSelectPrev(Operator):
|
|||||||
return {'FINISHED'}
|
return {'FINISHED'}
|
||||||
|
|
||||||
|
|
||||||
# XXX This is hackish (going forth and back from Object mode...), to be redone once we have proper support of
|
|
||||||
# custom normals in BMesh/edit mode.
|
|
||||||
class MehsSetNormalsFromFaces(Operator):
|
|
||||||
"""Set the custom vertex normals from the selected faces ones"""
|
|
||||||
bl_idname = "mesh.set_normals_from_faces"
|
|
||||||
bl_label = "Set Normals From Faces"
|
|
||||||
bl_options = {'REGISTER', 'UNDO'}
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def poll(cls, context):
|
|
||||||
return (context.mode == 'EDIT_MESH' and context.edit_object.data.polygons)
|
|
||||||
|
|
||||||
def execute(self, context):
|
|
||||||
import mathutils
|
|
||||||
|
|
||||||
bpy.ops.object.mode_set(mode='OBJECT')
|
|
||||||
obj = context.active_object
|
|
||||||
me = obj.data
|
|
||||||
|
|
||||||
v2nors = {}
|
|
||||||
for p in me.polygons:
|
|
||||||
if not p.select:
|
|
||||||
continue
|
|
||||||
for lidx, vidx in zip(p.loop_indices, p.vertices):
|
|
||||||
assert(me.loops[lidx].vertex_index == vidx)
|
|
||||||
v2nors.setdefault(vidx, []).append(p.normal)
|
|
||||||
|
|
||||||
for nors in v2nors.values():
|
|
||||||
nors[:] = [sum(nors, mathutils.Vector((0, 0, 0))).normalized()]
|
|
||||||
|
|
||||||
if not me.has_custom_normals:
|
|
||||||
me.create_normals_split()
|
|
||||||
me.calc_normals_split()
|
|
||||||
|
|
||||||
normals = []
|
|
||||||
for l in me.loops:
|
|
||||||
nor = v2nors.get(l.vertex_index, [None])[0]
|
|
||||||
if nor is None:
|
|
||||||
nor = l.normal
|
|
||||||
normals.append(nor.to_tuple())
|
|
||||||
|
|
||||||
me.normals_split_custom_set(normals)
|
|
||||||
|
|
||||||
me.free_normals_split()
|
|
||||||
bpy.ops.object.mode_set(mode='EDIT')
|
|
||||||
|
|
||||||
return {'FINISHED'}
|
|
||||||
|
|
||||||
|
|
||||||
classes = (
|
classes = (
|
||||||
MehsSetNormalsFromFaces,
|
|
||||||
MeshMirrorUV,
|
MeshMirrorUV,
|
||||||
MeshSelectNext,
|
MeshSelectNext,
|
||||||
MeshSelectPrev,
|
MeshSelectPrev,
|
||||||
|
@@ -1549,6 +1549,22 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel):
|
|||||||
if md.rest_source == 'BIND':
|
if md.rest_source == 'BIND':
|
||||||
layout.operator("object.correctivesmooth_bind", text="Unbind" if is_bind else "Bind")
|
layout.operator("object.correctivesmooth_bind", text="Unbind" if is_bind else "Bind")
|
||||||
|
|
||||||
|
def WEIGHTED_NORMAL(self, layout, ob, md):
|
||||||
|
layout.label("Weighting Mode:")
|
||||||
|
split = layout.split(align=True)
|
||||||
|
col = split.column(align=True)
|
||||||
|
col.prop(md, "mode", text="")
|
||||||
|
col.prop(md, "weight", text="Weight")
|
||||||
|
col.prop(md, "keep_sharp")
|
||||||
|
|
||||||
|
col = split.column(align=True)
|
||||||
|
row = col.row(align=True)
|
||||||
|
row.prop_search(md, "vertex_group", ob, "vertex_groups", text="")
|
||||||
|
row.active = bool(md.vertex_group)
|
||||||
|
row.prop(md, "invert_vertex_group", text="", icon='ARROW_LEFTRIGHT')
|
||||||
|
col.prop(md, "thresh", text="Threshold")
|
||||||
|
col.prop(md, "face_influence")
|
||||||
|
|
||||||
|
|
||||||
classes = (
|
classes = (
|
||||||
DATA_PT_modifiers,
|
DATA_PT_modifiers,
|
||||||
|
@@ -441,11 +441,59 @@ class VIEW3D_PT_tools_shading(View3DPanel, Panel):
|
|||||||
props.clear = True
|
props.clear = True
|
||||||
row.operator("mesh.mark_sharp", text="Sharp").use_verts = True
|
row.operator("mesh.mark_sharp", text="Sharp").use_verts = True
|
||||||
|
|
||||||
|
|
||||||
|
class VIEW3D_PT_tools_normal(View3DPanel, Panel):
|
||||||
|
bl_category = "Shading / UVs"
|
||||||
|
bl_context = "mesh_edit"
|
||||||
|
bl_label = "Normal Tools"
|
||||||
|
|
||||||
|
def draw(self, context):
|
||||||
|
layout = self.layout
|
||||||
|
toolsettings = context.tool_settings
|
||||||
|
|
||||||
col = layout.column(align=True)
|
col = layout.column(align=True)
|
||||||
col.label(text="Normals:")
|
col.label(text="Vertex Normals:")
|
||||||
col.operator("mesh.normals_make_consistent", text="Recalculate")
|
col.operator("mesh.normals_make_consistent", text="Recalculate")
|
||||||
col.operator("mesh.flip_normals", text="Flip Direction")
|
col.operator("mesh.flip_normals", text="Flip Direction")
|
||||||
|
|
||||||
|
layout.separator()
|
||||||
|
layout.label(text="Custom Normals:")
|
||||||
|
|
||||||
|
col = layout.column(align=True)
|
||||||
col.operator("mesh.set_normals_from_faces", text="Set From Faces")
|
col.operator("mesh.set_normals_from_faces", text="Set From Faces")
|
||||||
|
col.operator("transform.rotate_normal", text="Rotate")
|
||||||
|
col.operator("mesh.point_normals", text="Point To...")
|
||||||
|
|
||||||
|
row = layout.row(align=True)
|
||||||
|
row.operator("mesh.merge_normals", text="Merge")
|
||||||
|
row.operator("mesh.split_normals", text="Split")
|
||||||
|
|
||||||
|
col = layout.column(align=True)
|
||||||
|
col.operator_menu_enum("mesh.average_normals", "average_type")
|
||||||
|
|
||||||
|
col = layout.column(align=True)
|
||||||
|
col.label(text="Normal Vector:")
|
||||||
|
col.prop(toolsettings, "normal_vector", text="")
|
||||||
|
|
||||||
|
row = col.row(align=True)
|
||||||
|
row.operator("mesh.normals_tools", text="Copy").mode = 'COPY'
|
||||||
|
row.operator("mesh.normals_tools", text="Paste").mode = 'PASTE'
|
||||||
|
|
||||||
|
row = col.row(align=True)
|
||||||
|
row.operator("mesh.normals_tools", text="Multiply").mode = 'MULTIPLY'
|
||||||
|
row.operator("mesh.normals_tools", text="Add").mode = 'ADD'
|
||||||
|
|
||||||
|
col.operator("mesh.normals_tools", text="Reset").mode = 'RESET'
|
||||||
|
|
||||||
|
col = layout.column(align=True)
|
||||||
|
col.operator("mesh.smoothen_normals", text="Smoothen")
|
||||||
|
|
||||||
|
col = layout.column(align=True)
|
||||||
|
col.label(text="Face Strength:")
|
||||||
|
row = col.row(align=True)
|
||||||
|
row.prop(toolsettings, "face_strength", text="")
|
||||||
|
row.operator("mesh.mod_weighted_strength", text="", icon = "FACESEL").set = False
|
||||||
|
row.operator("mesh.mod_weighted_strength", text="", icon = "ZOOMIN").set = True
|
||||||
|
|
||||||
|
|
||||||
class VIEW3D_PT_tools_uvs(View3DPanel, Panel):
|
class VIEW3D_PT_tools_uvs(View3DPanel, Panel):
|
||||||
@@ -2073,6 +2121,7 @@ classes = (
|
|||||||
VIEW3D_PT_tools_meshweight,
|
VIEW3D_PT_tools_meshweight,
|
||||||
VIEW3D_PT_tools_add_mesh_edit,
|
VIEW3D_PT_tools_add_mesh_edit,
|
||||||
VIEW3D_PT_tools_shading,
|
VIEW3D_PT_tools_shading,
|
||||||
|
VIEW3D_PT_tools_normal,
|
||||||
VIEW3D_PT_tools_uvs,
|
VIEW3D_PT_tools_uvs,
|
||||||
VIEW3D_PT_tools_meshedit_options,
|
VIEW3D_PT_tools_meshedit_options,
|
||||||
VIEW3D_PT_tools_transform_curve,
|
VIEW3D_PT_tools_transform_curve,
|
||||||
|
@@ -93,6 +93,7 @@ void BKE_editmesh_update_linked_customdata(BMEditMesh *em);
|
|||||||
void BKE_editmesh_color_free(BMEditMesh *em);
|
void BKE_editmesh_color_free(BMEditMesh *em);
|
||||||
void BKE_editmesh_color_ensure(BMEditMesh *em, const char htype);
|
void BKE_editmesh_color_ensure(BMEditMesh *em, const char htype);
|
||||||
float (*BKE_editmesh_vertexCos_get_orco(BMEditMesh *em, int *r_numVerts))[3];
|
float (*BKE_editmesh_vertexCos_get_orco(BMEditMesh *em, int *r_numVerts))[3];
|
||||||
|
void BKE_editmesh_lnorspace_update(BMEditMesh *em);
|
||||||
|
|
||||||
/* editderivedmesh.c */
|
/* editderivedmesh.c */
|
||||||
/* should really be defined in editmesh.c, but they use 'EditDerivedBMesh' */
|
/* should really be defined in editmesh.c, but they use 'EditDerivedBMesh' */
|
||||||
|
@@ -222,6 +222,8 @@ typedef struct MLoopNorSpace {
|
|||||||
* - BMLoop pointers. */
|
* - BMLoop pointers. */
|
||||||
struct LinkNode *loops;
|
struct LinkNode *loops;
|
||||||
char flags;
|
char flags;
|
||||||
|
|
||||||
|
void *user_data; /* To be used for extended processing related to loop normal spaces (aka smooth fans). */
|
||||||
} MLoopNorSpace;
|
} MLoopNorSpace;
|
||||||
/**
|
/**
|
||||||
* MLoopNorSpace.flags
|
* MLoopNorSpace.flags
|
||||||
@@ -237,6 +239,7 @@ typedef struct MLoopNorSpaceArray {
|
|||||||
MLoopNorSpace **lspacearr; /* MLoop aligned array */
|
MLoopNorSpace **lspacearr; /* MLoop aligned array */
|
||||||
struct LinkNode *loops_pool; /* Allocated once, avoids to call BLI_linklist_prepend_arena() for each loop! */
|
struct LinkNode *loops_pool; /* Allocated once, avoids to call BLI_linklist_prepend_arena() for each loop! */
|
||||||
char data_type; /* Whether we store loop indices, or pointers to BMLoop. */
|
char data_type; /* Whether we store loop indices, or pointers to BMLoop. */
|
||||||
|
int num_spaces; /* Number of clnors spaces defined in this array. */
|
||||||
struct MemArena *mem;
|
struct MemArena *mem;
|
||||||
} MLoopNorSpaceArray;
|
} MLoopNorSpaceArray;
|
||||||
/**
|
/**
|
||||||
|
@@ -214,7 +214,7 @@ static void emDM_calcLoopNormalsSpaceArray(
|
|||||||
cd_loop_clnors_offset = clnors_data ? -1 : CustomData_get_offset(&bm->ldata, CD_CUSTOMLOOPNORMAL);
|
cd_loop_clnors_offset = clnors_data ? -1 : CustomData_get_offset(&bm->ldata, CD_CUSTOMLOOPNORMAL);
|
||||||
|
|
||||||
BM_loops_calc_normal_vcos(bm, vertexCos, vertexNos, polyNos, use_split_normals, split_angle, loopNos,
|
BM_loops_calc_normal_vcos(bm, vertexCos, vertexNos, polyNos, use_split_normals, split_angle, loopNos,
|
||||||
r_lnors_spacearr, clnors_data, cd_loop_clnors_offset);
|
r_lnors_spacearr, clnors_data, cd_loop_clnors_offset, false);
|
||||||
#ifdef DEBUG_CLNORS
|
#ifdef DEBUG_CLNORS
|
||||||
if (r_lnors_spacearr) {
|
if (r_lnors_spacearr) {
|
||||||
int i;
|
int i;
|
||||||
|
@@ -264,3 +264,26 @@ float (*BKE_editmesh_vertexCos_get_orco(BMEditMesh *em, int *r_numVerts))[3]
|
|||||||
|
|
||||||
return orco;
|
return orco;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void BKE_editmesh_lnorspace_update(BMEditMesh *em)
|
||||||
|
{
|
||||||
|
BMesh *bm = em->bm;
|
||||||
|
|
||||||
|
/* We need to create clnors data is none exist yet, otherwise there is no way to edit them. */
|
||||||
|
/* Similar code to MESH_OT_customdata_custom_splitnormals_add operator, we want to keep same shading
|
||||||
|
* in case we were using autosmooth so far... */
|
||||||
|
/* Note: there is a problem here, which is that is someone starts a normal editing operation on previously
|
||||||
|
* autosmooth-ed mesh, and cancel that operation, generated clnors data remain, with related sharp edges
|
||||||
|
* (and hence autosmooth is 'lost').
|
||||||
|
* Not sure how critical this is, and how to fix that issue? */
|
||||||
|
if (!CustomData_has_layer(&bm->ldata, CD_CUSTOMLOOPNORMAL)) {
|
||||||
|
Mesh *me = em->ob->data;
|
||||||
|
if (me->flag & ME_AUTOSMOOTH) {
|
||||||
|
BM_edges_sharp_from_angle_set(bm, me->smoothresh);
|
||||||
|
|
||||||
|
me->drawflag |= ME_DRAWSHARP;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BM_lnorspace_update(bm);
|
||||||
|
}
|
||||||
|
@@ -455,6 +455,8 @@ void BKE_lnor_spacearr_init(MLoopNorSpaceArray *lnors_spacearr, const int numLoo
|
|||||||
mem = lnors_spacearr->mem;
|
mem = lnors_spacearr->mem;
|
||||||
lnors_spacearr->lspacearr = BLI_memarena_calloc(mem, sizeof(MLoopNorSpace *) * (size_t)numLoops);
|
lnors_spacearr->lspacearr = BLI_memarena_calloc(mem, sizeof(MLoopNorSpace *) * (size_t)numLoops);
|
||||||
lnors_spacearr->loops_pool = BLI_memarena_alloc(mem, sizeof(LinkNode) * (size_t)numLoops);
|
lnors_spacearr->loops_pool = BLI_memarena_alloc(mem, sizeof(LinkNode) * (size_t)numLoops);
|
||||||
|
|
||||||
|
lnors_spacearr->num_spaces = 0;
|
||||||
}
|
}
|
||||||
BLI_assert(ELEM(data_type, MLNOR_SPACEARR_BMLOOP_PTR, MLNOR_SPACEARR_LOOP_INDEX));
|
BLI_assert(ELEM(data_type, MLNOR_SPACEARR_BMLOOP_PTR, MLNOR_SPACEARR_LOOP_INDEX));
|
||||||
lnors_spacearr->data_type = data_type;
|
lnors_spacearr->data_type = data_type;
|
||||||
@@ -462,21 +464,24 @@ void BKE_lnor_spacearr_init(MLoopNorSpaceArray *lnors_spacearr, const int numLoo
|
|||||||
|
|
||||||
void BKE_lnor_spacearr_clear(MLoopNorSpaceArray *lnors_spacearr)
|
void BKE_lnor_spacearr_clear(MLoopNorSpaceArray *lnors_spacearr)
|
||||||
{
|
{
|
||||||
BLI_memarena_clear(lnors_spacearr->mem);
|
lnors_spacearr->num_spaces = 0;
|
||||||
lnors_spacearr->lspacearr = NULL;
|
lnors_spacearr->lspacearr = NULL;
|
||||||
lnors_spacearr->loops_pool = NULL;
|
lnors_spacearr->loops_pool = NULL;
|
||||||
|
BLI_memarena_clear(lnors_spacearr->mem);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BKE_lnor_spacearr_free(MLoopNorSpaceArray *lnors_spacearr)
|
void BKE_lnor_spacearr_free(MLoopNorSpaceArray *lnors_spacearr)
|
||||||
{
|
{
|
||||||
BLI_memarena_free(lnors_spacearr->mem);
|
lnors_spacearr->num_spaces = 0;
|
||||||
lnors_spacearr->lspacearr = NULL;
|
lnors_spacearr->lspacearr = NULL;
|
||||||
lnors_spacearr->loops_pool = NULL;
|
lnors_spacearr->loops_pool = NULL;
|
||||||
|
BLI_memarena_free(lnors_spacearr->mem);
|
||||||
lnors_spacearr->mem = NULL;
|
lnors_spacearr->mem = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
MLoopNorSpace *BKE_lnor_space_create(MLoopNorSpaceArray *lnors_spacearr)
|
MLoopNorSpace *BKE_lnor_space_create(MLoopNorSpaceArray *lnors_spacearr)
|
||||||
{
|
{
|
||||||
|
lnors_spacearr->num_spaces++;
|
||||||
return BLI_memarena_calloc(lnors_spacearr->mem, sizeof(MLoopNorSpace));
|
return BLI_memarena_calloc(lnors_spacearr->mem, sizeof(MLoopNorSpace));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -38,6 +38,8 @@ struct BMEdge;
|
|||||||
struct BMLoop;
|
struct BMLoop;
|
||||||
struct BMFace;
|
struct BMFace;
|
||||||
|
|
||||||
|
struct MLoopNorSpaceArray;
|
||||||
|
|
||||||
struct BLI_mempool;
|
struct BLI_mempool;
|
||||||
|
|
||||||
/* note: it is very important for BMHeader to start with two
|
/* note: it is very important for BMHeader to start with two
|
||||||
@@ -236,6 +238,9 @@ typedef struct BMesh {
|
|||||||
struct BLI_mempool *looplistpool;
|
struct BLI_mempool *looplistpool;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
struct MLoopNorSpaceArray *lnor_spacearr; /* Stores MLoopNorSpaceArray for this BMesh */
|
||||||
|
char spacearr_dirty;
|
||||||
|
|
||||||
/* should be copy of scene select mode */
|
/* should be copy of scene select mode */
|
||||||
/* stored in BMEditMesh too, this is a bit confusing,
|
/* stored in BMEditMesh too, this is a bit confusing,
|
||||||
* make sure they're in sync!
|
* make sure they're in sync!
|
||||||
@@ -263,9 +268,33 @@ enum {
|
|||||||
BM_FACE = 8
|
BM_FACE = 8
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef struct BMLoopNorEditData {
|
||||||
|
int loop_index;
|
||||||
|
BMLoop *loop;
|
||||||
|
float niloc[3];
|
||||||
|
float nloc[3];
|
||||||
|
float *loc;
|
||||||
|
short *clnors_data;
|
||||||
|
} BMLoopNorEditData;
|
||||||
|
|
||||||
|
typedef struct BMLoopNorEditDataArray {
|
||||||
|
BMLoopNorEditData *lnor_editdata;
|
||||||
|
/* This one has full amount of loops, used to map loop index to actual BMLoopNorEditData struct. */
|
||||||
|
BMLoopNorEditData **lidx_to_lnor_editdata;
|
||||||
|
|
||||||
|
int cd_custom_normal_offset;
|
||||||
|
int totloop;
|
||||||
|
} BMLoopNorEditDataArray;
|
||||||
|
|
||||||
#define BM_ALL (BM_VERT | BM_EDGE | BM_LOOP | BM_FACE)
|
#define BM_ALL (BM_VERT | BM_EDGE | BM_LOOP | BM_FACE)
|
||||||
#define BM_ALL_NOLOOP (BM_VERT | BM_EDGE | BM_FACE)
|
#define BM_ALL_NOLOOP (BM_VERT | BM_EDGE | BM_FACE)
|
||||||
|
|
||||||
|
enum {
|
||||||
|
BM_SPACEARR_DIRTY = 1 << 0,
|
||||||
|
BM_SPACEARR_DIRTY_ALL = 1 << 1,
|
||||||
|
BM_SPACEARR_BMO_SET = 1 << 2,
|
||||||
|
};
|
||||||
|
|
||||||
/* args for _Generic */
|
/* args for _Generic */
|
||||||
#define _BM_GENERIC_TYPE_ELEM_NONCONST \
|
#define _BM_GENERIC_TYPE_ELEM_NONCONST \
|
||||||
void *, BMVert *, BMEdge *, BMLoop *, BMFace *, \
|
void *, BMVert *, BMEdge *, BMLoop *, BMFace *, \
|
||||||
|
@@ -30,6 +30,7 @@
|
|||||||
|
|
||||||
#include "DNA_listBase.h"
|
#include "DNA_listBase.h"
|
||||||
#include "DNA_object_types.h"
|
#include "DNA_object_types.h"
|
||||||
|
#include "DNA_scene_types.h"
|
||||||
|
|
||||||
#include "BLI_linklist_stack.h"
|
#include "BLI_linklist_stack.h"
|
||||||
#include "BLI_listbase.h"
|
#include "BLI_listbase.h"
|
||||||
@@ -260,6 +261,11 @@ void BM_mesh_data_free(BMesh *bm)
|
|||||||
|
|
||||||
BLI_freelistN(&bm->selected);
|
BLI_freelistN(&bm->selected);
|
||||||
|
|
||||||
|
if (bm->lnor_spacearr) {
|
||||||
|
BKE_lnor_spacearr_free(bm->lnor_spacearr);
|
||||||
|
MEM_freeN(bm->lnor_spacearr);
|
||||||
|
}
|
||||||
|
|
||||||
BMO_error_clear(bm);
|
BMO_error_clear(bm);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -313,6 +319,10 @@ void BM_mesh_free(BMesh *bm)
|
|||||||
* Helpers for #BM_mesh_normals_update and #BM_verts_calc_normal_vcos
|
* Helpers for #BM_mesh_normals_update and #BM_verts_calc_normal_vcos
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/* We use that existing internal API flag, assuming no other tool using it would run concurrently to clnors editing. */
|
||||||
|
/* XXX Should we rather add a new internal flag? */
|
||||||
|
#define BM_LNORSPACE_UPDATE _FLAG_MF
|
||||||
|
|
||||||
typedef struct BMEdgesCalcVectorsData {
|
typedef struct BMEdgesCalcVectorsData {
|
||||||
/* Read-only data. */
|
/* Read-only data. */
|
||||||
const float (*vcos)[3];
|
const float (*vcos)[3];
|
||||||
@@ -638,7 +648,8 @@ bool BM_loop_check_cyclic_smooth_fan(BMLoop *l_curr)
|
|||||||
* Will use first clnors_data array, and fallback to cd_loop_clnors_offset (use NULL and -1 to not use clnors). */
|
* Will use first clnors_data array, and fallback to cd_loop_clnors_offset (use NULL and -1 to not use clnors). */
|
||||||
static void bm_mesh_loops_calc_normals(
|
static void bm_mesh_loops_calc_normals(
|
||||||
BMesh *bm, const float (*vcos)[3], const float (*fnos)[3], float (*r_lnos)[3],
|
BMesh *bm, const float (*vcos)[3], const float (*fnos)[3], float (*r_lnos)[3],
|
||||||
MLoopNorSpaceArray *r_lnors_spacearr, short (*clnors_data)[2], const int cd_loop_clnors_offset)
|
MLoopNorSpaceArray *r_lnors_spacearr, short (*clnors_data)[2],
|
||||||
|
const int cd_loop_clnors_offset, const bool do_rebuild)
|
||||||
{
|
{
|
||||||
BMIter fiter;
|
BMIter fiter;
|
||||||
BMFace *f_curr;
|
BMFace *f_curr;
|
||||||
@@ -694,6 +705,11 @@ static void bm_mesh_loops_calc_normals(
|
|||||||
|
|
||||||
l_curr = l_first = BM_FACE_FIRST_LOOP(f_curr);
|
l_curr = l_first = BM_FACE_FIRST_LOOP(f_curr);
|
||||||
do {
|
do {
|
||||||
|
if (do_rebuild && !BM_ELEM_API_FLAG_TEST(l_curr, BM_LNORSPACE_UPDATE) &&
|
||||||
|
!(bm->spacearr_dirty & BM_SPACEARR_DIRTY_ALL))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
/* A smooth edge, we have to check for cyclic smooth fan case.
|
/* A smooth edge, we have to check for cyclic smooth fan case.
|
||||||
* If we find a new, never-processed cyclic smooth fan, we can do it now using that loop/edge as
|
* If we find a new, never-processed cyclic smooth fan, we can do it now using that loop/edge as
|
||||||
* 'entry point', otherwise we can skip it. */
|
* 'entry point', otherwise we can skip it. */
|
||||||
@@ -894,7 +910,10 @@ static void bm_mesh_loops_calc_normals(
|
|||||||
clnors_avg[0] /= clnors_nbr;
|
clnors_avg[0] /= clnors_nbr;
|
||||||
clnors_avg[1] /= clnors_nbr;
|
clnors_avg[1] /= clnors_nbr;
|
||||||
/* Fix/update all clnors of this fan with computed average value. */
|
/* Fix/update all clnors of this fan with computed average value. */
|
||||||
printf("Invalid clnors in this fan!\n");
|
|
||||||
|
/* Prints continuously when merge custom normals, so commenting. */
|
||||||
|
/* printf("Invalid clnors in this fan!\n"); */
|
||||||
|
|
||||||
while ((clnor = BLI_SMALLSTACK_POP(clnors))) {
|
while ((clnor = BLI_SMALLSTACK_POP(clnors))) {
|
||||||
//print_v2("org clnor", clnor);
|
//print_v2("org clnor", clnor);
|
||||||
clnor[0] = (short)clnors_avg[0];
|
clnor[0] = (short)clnors_avg[0];
|
||||||
@@ -1009,7 +1028,8 @@ void BM_mesh_loop_normals_update(
|
|||||||
void BM_loops_calc_normal_vcos(
|
void BM_loops_calc_normal_vcos(
|
||||||
BMesh *bm, const float (*vcos)[3], const float (*vnos)[3], const float (*fnos)[3],
|
BMesh *bm, const float (*vcos)[3], const float (*vnos)[3], const float (*fnos)[3],
|
||||||
const bool use_split_normals, const float split_angle, float (*r_lnos)[3],
|
const bool use_split_normals, const float split_angle, float (*r_lnos)[3],
|
||||||
MLoopNorSpaceArray *r_lnors_spacearr, short (*clnors_data)[2], const int cd_loop_clnors_offset)
|
MLoopNorSpaceArray *r_lnors_spacearr, short (*clnors_data)[2],
|
||||||
|
const int cd_loop_clnors_offset, const bool do_rebuild)
|
||||||
{
|
{
|
||||||
const bool has_clnors = clnors_data || (cd_loop_clnors_offset != -1);
|
const bool has_clnors = clnors_data || (cd_loop_clnors_offset != -1);
|
||||||
|
|
||||||
@@ -1019,7 +1039,8 @@ void BM_loops_calc_normal_vcos(
|
|||||||
bm_mesh_edges_sharp_tag(bm, vnos, fnos, r_lnos, has_clnors ? (float)M_PI : split_angle, false);
|
bm_mesh_edges_sharp_tag(bm, vnos, fnos, r_lnos, has_clnors ? (float)M_PI : split_angle, false);
|
||||||
|
|
||||||
/* Finish computing lnos by accumulating face normals in each fan of faces defined by sharp edges. */
|
/* Finish computing lnos by accumulating face normals in each fan of faces defined by sharp edges. */
|
||||||
bm_mesh_loops_calc_normals(bm, vcos, fnos, r_lnos, r_lnors_spacearr, clnors_data, cd_loop_clnors_offset);
|
bm_mesh_loops_calc_normals(
|
||||||
|
bm, vcos, fnos, r_lnos, r_lnors_spacearr, clnors_data, cd_loop_clnors_offset, do_rebuild);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
BLI_assert(!r_lnors_spacearr);
|
BLI_assert(!r_lnors_spacearr);
|
||||||
@@ -1041,6 +1062,380 @@ void BM_edges_sharp_from_angle_set(BMesh *bm, const float split_angle)
|
|||||||
bm_mesh_edges_sharp_tag(bm, NULL, NULL, NULL, split_angle, true);
|
bm_mesh_edges_sharp_tag(bm, NULL, NULL, NULL, split_angle, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void BM_lnorspacearr_store(BMesh *bm, float (*r_lnors)[3])
|
||||||
|
{
|
||||||
|
BLI_assert(bm->lnor_spacearr != NULL);
|
||||||
|
|
||||||
|
if (!CustomData_has_layer(&bm->ldata, CD_CUSTOMLOOPNORMAL)) {
|
||||||
|
BM_data_layer_add(bm, &bm->ldata, CD_CUSTOMLOOPNORMAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
int cd_loop_clnors_offset = CustomData_get_offset(&bm->ldata, CD_CUSTOMLOOPNORMAL);
|
||||||
|
|
||||||
|
BM_loops_calc_normal_vcos(
|
||||||
|
bm, NULL, NULL, NULL, true, M_PI, r_lnors, bm->lnor_spacearr, NULL, cd_loop_clnors_offset, false);
|
||||||
|
bm->spacearr_dirty &= ~(BM_SPACEARR_DIRTY | BM_SPACEARR_DIRTY_ALL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* will change later */
|
||||||
|
#define CLEAR_SPACEARRAY_THRESHOLD(x) ((x) / 2)
|
||||||
|
|
||||||
|
void BM_lnorspace_invalidate(BMesh *bm, const bool do_invalidate_all)
|
||||||
|
{
|
||||||
|
if (bm->spacearr_dirty & BM_SPACEARR_DIRTY_ALL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (do_invalidate_all || bm->totvertsel > CLEAR_SPACEARRAY_THRESHOLD(bm->totvert)) {
|
||||||
|
bm->spacearr_dirty |= BM_SPACEARR_DIRTY_ALL;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (bm->lnor_spacearr == NULL) {
|
||||||
|
bm->spacearr_dirty |= BM_SPACEARR_DIRTY_ALL;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
BMVert *v;
|
||||||
|
BMLoop *l;
|
||||||
|
BMIter viter, liter;
|
||||||
|
/* Note: we could use temp tag of BMItem for that, but probably better not use it in such a low-level func?
|
||||||
|
* --mont29 */
|
||||||
|
BLI_bitmap *done_verts = BLI_BITMAP_NEW(bm->totvert, __func__);
|
||||||
|
|
||||||
|
BM_mesh_elem_index_ensure(bm, BM_VERT);
|
||||||
|
|
||||||
|
/* When we affect a given vertex, we may affect following smooth fans:
|
||||||
|
* - all smooth fans of said vertex;
|
||||||
|
* - all smooth fans of all immediate loop-neighbors vertices;
|
||||||
|
* This can be simplified as 'all loops of selected vertices and their immediate neighbors'
|
||||||
|
* need to be tagged for update.
|
||||||
|
*/
|
||||||
|
BM_ITER_MESH(v, &viter, bm, BM_VERTS_OF_MESH) {
|
||||||
|
if (BM_elem_flag_test(v, BM_ELEM_SELECT)) {
|
||||||
|
BM_ITER_ELEM(l, &liter, v, BM_LOOPS_OF_VERT) {
|
||||||
|
BM_ELEM_API_FLAG_ENABLE(l, BM_LNORSPACE_UPDATE);
|
||||||
|
|
||||||
|
/* Note that we only handle unselected neighbor vertices here, main loop will take care of
|
||||||
|
* selected ones. */
|
||||||
|
if (!BM_elem_flag_test(l->prev->v, BM_ELEM_SELECT) &&
|
||||||
|
!BLI_BITMAP_TEST(done_verts, BM_elem_index_get(l->prev->v)))
|
||||||
|
{
|
||||||
|
BMLoop *l_prev;
|
||||||
|
BMIter liter_prev;
|
||||||
|
BM_ITER_ELEM(l_prev, &liter_prev, l->prev->v, BM_LOOPS_OF_VERT) {
|
||||||
|
BM_ELEM_API_FLAG_ENABLE(l_prev, BM_LNORSPACE_UPDATE);
|
||||||
|
}
|
||||||
|
BLI_BITMAP_ENABLE(done_verts, BM_elem_index_get(l_prev->v));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!BM_elem_flag_test(l->next->v, BM_ELEM_SELECT) &&
|
||||||
|
!BLI_BITMAP_TEST(done_verts, BM_elem_index_get(l->next->v)))
|
||||||
|
{
|
||||||
|
BMLoop *l_next;
|
||||||
|
BMIter liter_next;
|
||||||
|
BM_ITER_ELEM(l_next, &liter_next, l->next->v, BM_LOOPS_OF_VERT) {
|
||||||
|
BM_ELEM_API_FLAG_ENABLE(l_next, BM_LNORSPACE_UPDATE);
|
||||||
|
}
|
||||||
|
BLI_BITMAP_ENABLE(done_verts, BM_elem_index_get(l_next->v));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BLI_BITMAP_ENABLE(done_verts, BM_elem_index_get(v));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MEM_freeN(done_verts);
|
||||||
|
bm->spacearr_dirty |= BM_SPACEARR_DIRTY;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BM_lnorspace_rebuild(BMesh *bm, bool preserve_clnor)
|
||||||
|
{
|
||||||
|
BLI_assert(bm->lnor_spacearr != NULL);
|
||||||
|
|
||||||
|
if (!(bm->spacearr_dirty & (BM_SPACEARR_DIRTY | BM_SPACEARR_DIRTY_ALL))) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
BMFace *f;
|
||||||
|
BMLoop *l;
|
||||||
|
BMIter fiter, liter;
|
||||||
|
|
||||||
|
float (*r_lnors)[3] = MEM_callocN(sizeof(*r_lnors) * bm->totloop, __func__);
|
||||||
|
float (*oldnors)[3] = preserve_clnor ? MEM_mallocN(sizeof(*oldnors) * bm->totloop, __func__) : NULL;
|
||||||
|
|
||||||
|
int cd_loop_clnors_offset = CustomData_get_offset(&bm->ldata, CD_CUSTOMLOOPNORMAL);
|
||||||
|
|
||||||
|
BM_mesh_elem_index_ensure(bm, BM_LOOP);
|
||||||
|
|
||||||
|
if (preserve_clnor) {
|
||||||
|
BLI_assert(bm->lnor_spacearr->lspacearr != NULL);
|
||||||
|
|
||||||
|
BM_ITER_MESH(f, &fiter, bm, BM_FACES_OF_MESH) {
|
||||||
|
BM_ITER_ELEM(l, &liter, f, BM_LOOPS_OF_FACE) {
|
||||||
|
if (BM_ELEM_API_FLAG_TEST(l, BM_LNORSPACE_UPDATE) || bm->spacearr_dirty & BM_SPACEARR_DIRTY_ALL) {
|
||||||
|
short(*clnor)[2] = BM_ELEM_CD_GET_VOID_P(l, cd_loop_clnors_offset);
|
||||||
|
int l_index = BM_elem_index_get(l);
|
||||||
|
|
||||||
|
BKE_lnor_space_custom_data_to_normal(bm->lnor_spacearr->lspacearr[l_index], *clnor, oldnors[l_index]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bm->spacearr_dirty & BM_SPACEARR_DIRTY_ALL) {
|
||||||
|
BKE_lnor_spacearr_clear(bm->lnor_spacearr);
|
||||||
|
}
|
||||||
|
BM_loops_calc_normal_vcos(
|
||||||
|
bm, NULL, NULL, NULL, true, M_PI, r_lnors, bm->lnor_spacearr, NULL, cd_loop_clnors_offset, true);
|
||||||
|
MEM_freeN(r_lnors);
|
||||||
|
|
||||||
|
BM_ITER_MESH(f, &fiter, bm, BM_FACES_OF_MESH) {
|
||||||
|
BM_ITER_ELEM(l, &liter, f, BM_LOOPS_OF_FACE) {
|
||||||
|
if (BM_ELEM_API_FLAG_TEST(l, BM_LNORSPACE_UPDATE) || bm->spacearr_dirty & BM_SPACEARR_DIRTY_ALL) {
|
||||||
|
if (preserve_clnor) {
|
||||||
|
short(*clnor)[2] = BM_ELEM_CD_GET_VOID_P(l, cd_loop_clnors_offset);
|
||||||
|
int l_index = BM_elem_index_get(l);
|
||||||
|
BKE_lnor_space_custom_normal_to_data(bm->lnor_spacearr->lspacearr[l_index], oldnors[l_index], *clnor);
|
||||||
|
}
|
||||||
|
BM_ELEM_API_FLAG_DISABLE(l, BM_LNORSPACE_UPDATE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MEM_SAFE_FREE(oldnors);
|
||||||
|
bm->spacearr_dirty &= ~(BM_SPACEARR_DIRTY | BM_SPACEARR_DIRTY_ALL);
|
||||||
|
|
||||||
|
#ifndef NDEBUG
|
||||||
|
BM_lnorspace_err(bm);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void BM_lnorspace_update(BMesh *bm)
|
||||||
|
{
|
||||||
|
if (bm->lnor_spacearr == NULL) {
|
||||||
|
bm->lnor_spacearr = MEM_callocN(sizeof(*bm->lnor_spacearr), __func__);
|
||||||
|
}
|
||||||
|
if (bm->lnor_spacearr->lspacearr == NULL) {
|
||||||
|
float (*lnors)[3] = MEM_callocN(sizeof(*lnors) * bm->totloop, __func__);
|
||||||
|
|
||||||
|
BM_lnorspacearr_store(bm, lnors);
|
||||||
|
|
||||||
|
MEM_freeN(lnors);
|
||||||
|
}
|
||||||
|
else if(bm->spacearr_dirty & (BM_SPACEARR_DIRTY | BM_SPACEARR_DIRTY_ALL)){
|
||||||
|
BM_lnorspace_rebuild(bm, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Auxillary function only used by rebuild to detect if any spaces were not marked as invalid.
|
||||||
|
* Reports error if any of the lnor spaces change after rebuilding, meaning that all the possible
|
||||||
|
* lnor spaces to be rebuilt were not correctly marked.
|
||||||
|
*/
|
||||||
|
#ifndef NDEBUG
|
||||||
|
void BM_lnorspace_err(BMesh *bm)
|
||||||
|
{
|
||||||
|
bm->spacearr_dirty |= BM_SPACEARR_DIRTY_ALL;
|
||||||
|
bool clear = true;
|
||||||
|
|
||||||
|
MLoopNorSpaceArray *temp = MEM_callocN(sizeof(*temp), __func__);
|
||||||
|
temp->lspacearr = NULL;
|
||||||
|
|
||||||
|
BKE_lnor_spacearr_init(temp, bm->totloop, MLNOR_SPACEARR_BMLOOP_PTR);
|
||||||
|
|
||||||
|
int cd_loop_clnors_offset = CustomData_get_offset(&bm->ldata, CD_CUSTOMLOOPNORMAL);
|
||||||
|
float (*lnors)[3] = MEM_callocN(sizeof(*lnors) * bm->totloop, __func__);
|
||||||
|
BM_loops_calc_normal_vcos(bm, NULL, NULL, NULL, true, M_PI, lnors, temp, NULL, cd_loop_clnors_offset, true);
|
||||||
|
|
||||||
|
for (int i = 0; i < bm->totloop; i++) {
|
||||||
|
int j = 0;
|
||||||
|
j += compare_ff(temp->lspacearr[i]->ref_alpha, bm->lnor_spacearr->lspacearr[i]->ref_alpha, 1e-4f);
|
||||||
|
j += compare_ff(temp->lspacearr[i]->ref_beta, bm->lnor_spacearr->lspacearr[i]->ref_beta, 1e-4f);
|
||||||
|
j += compare_v3v3(temp->lspacearr[i]->vec_lnor, bm->lnor_spacearr->lspacearr[i]->vec_lnor, 1e-4f);
|
||||||
|
j += compare_v3v3(temp->lspacearr[i]->vec_ortho, bm->lnor_spacearr->lspacearr[i]->vec_ortho, 1e-4f);
|
||||||
|
j += compare_v3v3(temp->lspacearr[i]->vec_ref, bm->lnor_spacearr->lspacearr[i]->vec_ref, 1e-4f);
|
||||||
|
|
||||||
|
if (j != 5) {
|
||||||
|
clear = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
BKE_lnor_spacearr_free(temp);
|
||||||
|
MEM_freeN(temp);
|
||||||
|
MEM_freeN(lnors);
|
||||||
|
BLI_assert(clear);
|
||||||
|
|
||||||
|
bm->spacearr_dirty &= ~BM_SPACEARR_DIRTY_ALL;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static void bm_loop_normal_mark_indiv_do_loop(
|
||||||
|
BMLoop *l, BLI_bitmap *loops, MLoopNorSpaceArray *lnor_spacearr, int *totloopsel)
|
||||||
|
{
|
||||||
|
if (l != NULL) {
|
||||||
|
const int l_idx = BM_elem_index_get(l);
|
||||||
|
|
||||||
|
if (!BLI_BITMAP_TEST(loops, BM_elem_index_get(l))) {
|
||||||
|
/* If vert and face selected share a loop, mark it for editing. */
|
||||||
|
BLI_BITMAP_ENABLE(loops, l_idx);
|
||||||
|
(*totloopsel)++;
|
||||||
|
|
||||||
|
/* Mark all loops in same loop normal space (aka smooth fan). */
|
||||||
|
if ((lnor_spacearr->lspacearr[l_idx]->flags & MLNOR_SPACE_IS_SINGLE) == 0) {
|
||||||
|
for (LinkNode *node = lnor_spacearr->lspacearr[l_idx]->loops; node; node = node->next) {
|
||||||
|
const int lfan_idx = BM_elem_index_get((BMLoop *)node->link);
|
||||||
|
if (!BLI_BITMAP_TEST(loops, lfan_idx)) {
|
||||||
|
BLI_BITMAP_ENABLE(loops, lfan_idx);
|
||||||
|
(*totloopsel)++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Mark the individual clnors to be edited, if multiple selection methods are used. */
|
||||||
|
static int bm_loop_normal_mark_indiv(BMesh *bm, BLI_bitmap *loops)
|
||||||
|
{
|
||||||
|
BMEditSelection *ese, *ese_prev;
|
||||||
|
int totloopsel = 0;
|
||||||
|
|
||||||
|
BM_mesh_elem_index_ensure(bm, BM_LOOP);
|
||||||
|
|
||||||
|
BLI_assert(bm->lnor_spacearr != NULL);
|
||||||
|
BLI_assert(bm->lnor_spacearr->data_type == MLNOR_SPACEARR_BMLOOP_PTR);
|
||||||
|
|
||||||
|
/* Goes from last selected to the first selected element. */
|
||||||
|
for (ese = bm->selected.last; ese; ese = ese->prev) {
|
||||||
|
if (ese->htype == BM_FACE) {
|
||||||
|
ese_prev = ese;
|
||||||
|
/* If current face is selected, then any verts to be edited must have been selected before it. */
|
||||||
|
while ((ese_prev = ese_prev->prev)) {
|
||||||
|
if (ese_prev->htype == BM_VERT) {
|
||||||
|
bm_loop_normal_mark_indiv_do_loop(
|
||||||
|
BM_face_vert_share_loop((BMFace *)ese->ele, (BMVert *)ese_prev->ele),
|
||||||
|
loops, bm->lnor_spacearr, &totloopsel);
|
||||||
|
}
|
||||||
|
else if (ese_prev->htype == BM_EDGE) {
|
||||||
|
bm_loop_normal_mark_indiv_do_loop(
|
||||||
|
BM_face_vert_share_loop((BMFace *)ese->ele, ((BMEdge *)ese_prev->ele)->v1),
|
||||||
|
loops, bm->lnor_spacearr, &totloopsel);
|
||||||
|
|
||||||
|
bm_loop_normal_mark_indiv_do_loop(
|
||||||
|
BM_face_vert_share_loop((BMFace *)ese->ele, ((BMEdge *)ese_prev->ele)->v2),
|
||||||
|
loops, bm->lnor_spacearr, &totloopsel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return totloopsel;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void loop_normal_editdata_init(BMesh *bm, BMLoopNorEditData *lnor_ed, BMVert *v, BMLoop *l, const int offset)
|
||||||
|
{
|
||||||
|
BLI_assert(bm->lnor_spacearr != NULL);
|
||||||
|
BLI_assert(bm->lnor_spacearr->lspacearr != NULL);
|
||||||
|
|
||||||
|
const int l_index = BM_elem_index_get(l);
|
||||||
|
short *clnors_data = BM_ELEM_CD_GET_VOID_P(l, offset);
|
||||||
|
|
||||||
|
lnor_ed->loop_index = l_index;
|
||||||
|
lnor_ed->loop = l;
|
||||||
|
|
||||||
|
float custom_normal[3];
|
||||||
|
BKE_lnor_space_custom_data_to_normal(bm->lnor_spacearr->lspacearr[l_index], clnors_data, custom_normal);
|
||||||
|
|
||||||
|
lnor_ed->clnors_data = clnors_data;
|
||||||
|
copy_v3_v3(lnor_ed->nloc, custom_normal);
|
||||||
|
copy_v3_v3(lnor_ed->niloc, custom_normal);
|
||||||
|
|
||||||
|
lnor_ed->loc = v->co;
|
||||||
|
}
|
||||||
|
|
||||||
|
BMLoopNorEditDataArray *BM_loop_normal_editdata_array_init(BMesh *bm)
|
||||||
|
{
|
||||||
|
BMLoop *l;
|
||||||
|
BMVert *v;
|
||||||
|
BMIter liter, viter;
|
||||||
|
|
||||||
|
bool verts = (bm->selectmode & SCE_SELECT_VERTEX) != 0;
|
||||||
|
bool edges = (bm->selectmode & SCE_SELECT_EDGE) != 0;
|
||||||
|
bool faces = (bm->selectmode & SCE_SELECT_FACE) != 0;
|
||||||
|
int totloopsel = 0;
|
||||||
|
|
||||||
|
BLI_assert(bm->spacearr_dirty == 0);
|
||||||
|
|
||||||
|
BMLoopNorEditDataArray *lnors_ed_arr = MEM_mallocN(sizeof(*lnors_ed_arr), __func__);
|
||||||
|
lnors_ed_arr->lidx_to_lnor_editdata = MEM_callocN(sizeof(*lnors_ed_arr->lidx_to_lnor_editdata) * bm->totloop, __func__);
|
||||||
|
|
||||||
|
if (!CustomData_has_layer(&bm->ldata, CD_CUSTOMLOOPNORMAL)) {
|
||||||
|
BM_data_layer_add(bm, &bm->ldata, CD_CUSTOMLOOPNORMAL);
|
||||||
|
}
|
||||||
|
const int cd_custom_normal_offset = CustomData_get_offset(&bm->ldata, CD_CUSTOMLOOPNORMAL);
|
||||||
|
|
||||||
|
BM_mesh_elem_index_ensure(bm, BM_LOOP);
|
||||||
|
|
||||||
|
BLI_bitmap *loops = BLI_BITMAP_NEW(bm->totloop, __func__);
|
||||||
|
if (faces && (verts || edges)) {
|
||||||
|
/* More than one selection mode, check for individual normals to edit. */
|
||||||
|
totloopsel = bm_loop_normal_mark_indiv(bm, loops);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (totloopsel) {
|
||||||
|
BMLoopNorEditData *lnor_ed = lnors_ed_arr->lnor_editdata = MEM_mallocN(sizeof(*lnor_ed) * totloopsel, __func__);
|
||||||
|
|
||||||
|
BM_ITER_MESH(v, &viter, bm, BM_VERTS_OF_MESH) {
|
||||||
|
BM_ITER_ELEM(l, &liter, v, BM_LOOPS_OF_VERT) {
|
||||||
|
if (BLI_BITMAP_TEST(loops, BM_elem_index_get(l))) {
|
||||||
|
loop_normal_editdata_init(bm, lnor_ed, v, l, cd_custom_normal_offset);
|
||||||
|
lnors_ed_arr->lidx_to_lnor_editdata[BM_elem_index_get(l)] = lnor_ed;
|
||||||
|
lnor_ed++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lnors_ed_arr->totloop = totloopsel;
|
||||||
|
}
|
||||||
|
else { /* If multiple selection modes are inactive OR no such loop is found, fall back to editing all loops. */
|
||||||
|
totloopsel = BM_total_loop_select(bm);
|
||||||
|
BMLoopNorEditData *lnor_ed = lnors_ed_arr->lnor_editdata = MEM_mallocN(sizeof(*lnor_ed) * totloopsel, __func__);
|
||||||
|
|
||||||
|
BM_ITER_MESH(v, &viter, bm, BM_VERTS_OF_MESH) {
|
||||||
|
if (BM_elem_flag_test(v, BM_ELEM_SELECT)) {
|
||||||
|
BM_ITER_ELEM(l, &liter, v, BM_LOOPS_OF_VERT) {
|
||||||
|
loop_normal_editdata_init(bm, lnor_ed, v, l, cd_custom_normal_offset);
|
||||||
|
lnors_ed_arr->lidx_to_lnor_editdata[BM_elem_index_get(l)] = lnor_ed;
|
||||||
|
lnor_ed++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lnors_ed_arr->totloop = totloopsel;
|
||||||
|
}
|
||||||
|
|
||||||
|
MEM_freeN(loops);
|
||||||
|
lnors_ed_arr->cd_custom_normal_offset = cd_custom_normal_offset;
|
||||||
|
return lnors_ed_arr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BM_loop_normal_editdata_array_free(BMLoopNorEditDataArray *lnors_ed_arr)
|
||||||
|
{
|
||||||
|
MEM_SAFE_FREE(lnors_ed_arr->lnor_editdata);
|
||||||
|
MEM_SAFE_FREE(lnors_ed_arr->lidx_to_lnor_editdata);
|
||||||
|
MEM_freeN(lnors_ed_arr);
|
||||||
|
}
|
||||||
|
|
||||||
|
int BM_total_loop_select(BMesh *bm)
|
||||||
|
{
|
||||||
|
int r_sel = 0;
|
||||||
|
BMVert *v;
|
||||||
|
BMIter viter;
|
||||||
|
|
||||||
|
BM_ITER_MESH(v, &viter, bm, BM_VERTS_OF_MESH) {
|
||||||
|
if (BM_elem_flag_test(v, BM_ELEM_SELECT)) {
|
||||||
|
r_sel += BM_vert_face_count(v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return r_sel;
|
||||||
|
}
|
||||||
|
|
||||||
static void UNUSED_FUNCTION(bm_mdisps_space_set)(Object *ob, BMesh *bm, int from, int to)
|
static void UNUSED_FUNCTION(bm_mdisps_space_set)(Object *ob, BMesh *bm, int from, int to)
|
||||||
{
|
{
|
||||||
/* switch multires data out of tangent space */
|
/* switch multires data out of tangent space */
|
||||||
@@ -1141,6 +1536,7 @@ void bmesh_edit_end(BMesh *bm, BMOpTypeFlag type_flag)
|
|||||||
|
|
||||||
/* compute normals, clear temp flags and flush selections */
|
/* compute normals, clear temp flags and flush selections */
|
||||||
if (type_flag & BMO_OPTYPE_FLAG_NORMALS_CALC) {
|
if (type_flag & BMO_OPTYPE_FLAG_NORMALS_CALC) {
|
||||||
|
bm->spacearr_dirty |= BM_SPACEARR_DIRTY_ALL;
|
||||||
BM_mesh_normals_update(bm);
|
BM_mesh_normals_update(bm);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1157,6 +1553,9 @@ void bmesh_edit_end(BMesh *bm, BMOpTypeFlag type_flag)
|
|||||||
if ((type_flag & BMO_OPTYPE_FLAG_SELECT_VALIDATE) == 0) {
|
if ((type_flag & BMO_OPTYPE_FLAG_SELECT_VALIDATE) == 0) {
|
||||||
bm->selected = select_history;
|
bm->selected = select_history;
|
||||||
}
|
}
|
||||||
|
if (type_flag & BMO_OPTYPE_FLAG_INVALIDATE_CLNOR_ALL) {
|
||||||
|
bm->spacearr_dirty |= BM_SPACEARR_DIRTY_ALL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void BM_mesh_elem_index_ensure(BMesh *bm, const char htype)
|
void BM_mesh_elem_index_ensure(BMesh *bm, const char htype)
|
||||||
|
@@ -29,6 +29,7 @@
|
|||||||
|
|
||||||
struct BMAllocTemplate;
|
struct BMAllocTemplate;
|
||||||
struct MLoopNorSpaceArray;
|
struct MLoopNorSpaceArray;
|
||||||
|
struct BMLoopNorEditDataArray;
|
||||||
|
|
||||||
void BM_mesh_elem_toolflags_ensure(BMesh *bm);
|
void BM_mesh_elem_toolflags_ensure(BMesh *bm);
|
||||||
void BM_mesh_elem_toolflags_clear(BMesh *bm);
|
void BM_mesh_elem_toolflags_clear(BMesh *bm);
|
||||||
@@ -50,9 +51,22 @@ void BM_verts_calc_normal_vcos(BMesh *bm, const float (*fnos)[3], const float (*
|
|||||||
void BM_loops_calc_normal_vcos(
|
void BM_loops_calc_normal_vcos(
|
||||||
BMesh *bm, const float (*vcos)[3], const float (*vnos)[3], const float (*pnos)[3],
|
BMesh *bm, const float (*vcos)[3], const float (*vnos)[3], const float (*pnos)[3],
|
||||||
const bool use_split_normals, const float split_angle, float (*r_lnos)[3],
|
const bool use_split_normals, const float split_angle, float (*r_lnos)[3],
|
||||||
struct MLoopNorSpaceArray *r_lnors_spacearr, short (*clnors_data)[2], const int cd_loop_clnors_offset);
|
struct MLoopNorSpaceArray *r_lnors_spacearr, short (*clnors_data)[2],
|
||||||
|
const int cd_loop_clnors_offset, const bool do_rebuild);
|
||||||
|
|
||||||
bool BM_loop_check_cyclic_smooth_fan(BMLoop *l_curr);
|
bool BM_loop_check_cyclic_smooth_fan(BMLoop *l_curr);
|
||||||
|
void BM_lnorspacearr_store(BMesh *bm, float (*r_lnors)[3]);
|
||||||
|
void BM_lnorspace_invalidate(BMesh *bm, const bool do_invalidate_all);
|
||||||
|
void BM_lnorspace_rebuild(BMesh *bm, bool preserve_clnor);
|
||||||
|
void BM_lnorspace_update(BMesh *bm);
|
||||||
|
#ifndef NDEBUG
|
||||||
|
void BM_lnorspace_err(BMesh *bm);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Loop Generics */
|
||||||
|
struct BMLoopNorEditDataArray *BM_loop_normal_editdata_array_init(BMesh *bm);
|
||||||
|
void BM_loop_normal_editdata_array_free(struct BMLoopNorEditDataArray *lnors_ed_arr);
|
||||||
|
int BM_total_loop_select(BMesh *bm);
|
||||||
|
|
||||||
|
|
||||||
void BM_edges_sharp_from_angle_set(BMesh *bm, const float split_angle);
|
void BM_edges_sharp_from_angle_set(BMesh *bm, const float split_angle);
|
||||||
|
@@ -244,6 +244,7 @@ typedef enum {
|
|||||||
BMO_OPTYPE_FLAG_NORMALS_CALC = (1 << 1),
|
BMO_OPTYPE_FLAG_NORMALS_CALC = (1 << 1),
|
||||||
BMO_OPTYPE_FLAG_SELECT_FLUSH = (1 << 2),
|
BMO_OPTYPE_FLAG_SELECT_FLUSH = (1 << 2),
|
||||||
BMO_OPTYPE_FLAG_SELECT_VALIDATE = (1 << 3),
|
BMO_OPTYPE_FLAG_SELECT_VALIDATE = (1 << 3),
|
||||||
|
BMO_OPTYPE_FLAG_INVALIDATE_CLNOR_ALL = (1 << 4),
|
||||||
} BMOpTypeFlag;
|
} BMOpTypeFlag;
|
||||||
|
|
||||||
typedef struct BMOperator {
|
typedef struct BMOperator {
|
||||||
|
@@ -171,6 +171,7 @@ int ED_operator_object_active_editable_font(struct bContext *C);
|
|||||||
int ED_operator_editmesh(struct bContext *C);
|
int ED_operator_editmesh(struct bContext *C);
|
||||||
int ED_operator_editmesh_view3d(struct bContext *C);
|
int ED_operator_editmesh_view3d(struct bContext *C);
|
||||||
int ED_operator_editmesh_region_view3d(struct bContext *C);
|
int ED_operator_editmesh_region_view3d(struct bContext *C);
|
||||||
|
int ED_operator_editmesh_auto_smooth(struct bContext *C);
|
||||||
int ED_operator_editarmature(struct bContext *C);
|
int ED_operator_editarmature(struct bContext *C);
|
||||||
int ED_operator_editcurve(struct bContext *C);
|
int ED_operator_editcurve(struct bContext *C);
|
||||||
int ED_operator_editcurve_3d(struct bContext *C);
|
int ED_operator_editcurve_3d(struct bContext *C);
|
||||||
|
@@ -88,6 +88,7 @@ enum TfmMode {
|
|||||||
TFM_VERT_SLIDE,
|
TFM_VERT_SLIDE,
|
||||||
TFM_SEQ_SLIDE,
|
TFM_SEQ_SLIDE,
|
||||||
TFM_BONE_ENVELOPE_DIST,
|
TFM_BONE_ENVELOPE_DIST,
|
||||||
|
TFM_NORMAL_ROTATION,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* TRANSFORM CONTEXTS */
|
/* TRANSFORM CONTEXTS */
|
||||||
@@ -150,6 +151,7 @@ int BIF_countTransformOrientation(const struct bContext *C);
|
|||||||
#define P_NO_TEXSPACE (1 << 11)
|
#define P_NO_TEXSPACE (1 << 11)
|
||||||
#define P_CENTER (1 << 12)
|
#define P_CENTER (1 << 12)
|
||||||
#define P_GPENCIL_EDIT (1 << 13)
|
#define P_GPENCIL_EDIT (1 << 13)
|
||||||
|
#define P_CLNOR_INVALIDATE (1 << 14)
|
||||||
|
|
||||||
void Transform_Properties(struct wmOperatorType *ot, int flags);
|
void Transform_Properties(struct wmOperatorType *ot, int flags);
|
||||||
|
|
||||||
|
File diff suppressed because it is too large
Load Diff
@@ -589,6 +589,8 @@ static void undomesh_to_editmesh(UndoMesh *um, BMEditMesh *em, Mesh *obmesh)
|
|||||||
bm->selectmode = um->selectmode;
|
bm->selectmode = um->selectmode;
|
||||||
em->ob = ob;
|
em->ob = ob;
|
||||||
|
|
||||||
|
bm->spacearr_dirty = BM_SPACEARR_DIRTY_ALL;
|
||||||
|
|
||||||
/* T35170: Restore the active key on the RealMesh. Otherwise 'fake' offset propagation happens
|
/* T35170: Restore the active key on the RealMesh. Otherwise 'fake' offset propagation happens
|
||||||
* if the active is a basis for any other. */
|
* if the active is a basis for any other. */
|
||||||
if (key && (key->type == KEY_RELATIVE)) {
|
if (key && (key->type == KEY_RELATIVE)) {
|
||||||
|
@@ -1349,7 +1349,10 @@ void EDBM_update_generic(BMEditMesh *em, const bool do_tessface, const bool is_d
|
|||||||
/* in debug mode double check we didn't need to recalculate */
|
/* in debug mode double check we didn't need to recalculate */
|
||||||
BLI_assert(BM_mesh_elem_table_check(em->bm) == true);
|
BLI_assert(BM_mesh_elem_table_check(em->bm) == true);
|
||||||
}
|
}
|
||||||
|
if (em->bm->spacearr_dirty & BM_SPACEARR_BMO_SET) {
|
||||||
|
BM_lnorspace_invalidate(em->bm, false);
|
||||||
|
em->bm->spacearr_dirty &= ~BM_SPACEARR_BMO_SET;
|
||||||
|
}
|
||||||
/* don't keep stale derivedMesh data around, see: [#38872] */
|
/* don't keep stale derivedMesh data around, see: [#38872] */
|
||||||
BKE_editmesh_free_derivedmesh(em);
|
BKE_editmesh_free_derivedmesh(em);
|
||||||
|
|
||||||
|
@@ -229,6 +229,16 @@ void MESH_OT_duplicate(struct wmOperatorType *ot);
|
|||||||
void MESH_OT_merge(struct wmOperatorType *ot);
|
void MESH_OT_merge(struct wmOperatorType *ot);
|
||||||
void MESH_OT_remove_doubles(struct wmOperatorType *ot);
|
void MESH_OT_remove_doubles(struct wmOperatorType *ot);
|
||||||
void MESH_OT_poke(struct wmOperatorType *ot);
|
void MESH_OT_poke(struct wmOperatorType *ot);
|
||||||
|
void MESH_OT_point_normals(struct wmOperatorType *ot);
|
||||||
|
void MESH_OT_merge_normals(struct wmOperatorType *ot);
|
||||||
|
void MESH_OT_split_normals(struct wmOperatorType *ot);
|
||||||
|
void MESH_OT_normals_tools(struct wmOperatorType *ot);
|
||||||
|
void MESH_OT_set_normals_from_faces(struct wmOperatorType *ot);
|
||||||
|
void MESH_OT_average_normals(struct wmOperatorType *ot);
|
||||||
|
void MESH_OT_smoothen_normals(struct wmOperatorType *ot);
|
||||||
|
void MESH_OT_mod_weighted_strength(struct wmOperatorType *ot);
|
||||||
|
|
||||||
|
struct wmKeyMap *point_normals_modal_keymap(wmKeyConfig *keyconf);
|
||||||
|
|
||||||
#ifdef WITH_FREESTYLE
|
#ifdef WITH_FREESTYLE
|
||||||
void MESH_OT_mark_freestyle_edge(struct wmOperatorType *ot);
|
void MESH_OT_mark_freestyle_edge(struct wmOperatorType *ot);
|
||||||
|
@@ -192,6 +192,15 @@ void ED_operatortypes_mesh(void)
|
|||||||
WM_operatortype_append(MESH_OT_symmetrize);
|
WM_operatortype_append(MESH_OT_symmetrize);
|
||||||
WM_operatortype_append(MESH_OT_symmetry_snap);
|
WM_operatortype_append(MESH_OT_symmetry_snap);
|
||||||
|
|
||||||
|
WM_operatortype_append(MESH_OT_point_normals);
|
||||||
|
WM_operatortype_append(MESH_OT_merge_normals);
|
||||||
|
WM_operatortype_append(MESH_OT_split_normals);
|
||||||
|
WM_operatortype_append(MESH_OT_normals_tools);
|
||||||
|
WM_operatortype_append(MESH_OT_set_normals_from_faces);
|
||||||
|
WM_operatortype_append(MESH_OT_average_normals);
|
||||||
|
WM_operatortype_append(MESH_OT_smoothen_normals);
|
||||||
|
WM_operatortype_append(MESH_OT_mod_weighted_strength);
|
||||||
|
|
||||||
#ifdef WITH_GAMEENGINE
|
#ifdef WITH_GAMEENGINE
|
||||||
WM_operatortype_append(MESH_OT_navmesh_make);
|
WM_operatortype_append(MESH_OT_navmesh_make);
|
||||||
WM_operatortype_append(MESH_OT_navmesh_face_copy);
|
WM_operatortype_append(MESH_OT_navmesh_face_copy);
|
||||||
@@ -423,6 +432,8 @@ void ED_keymap_mesh(wmKeyConfig *keyconf)
|
|||||||
WM_keymap_add_item(keymap, "MESH_OT_split", YKEY, KM_PRESS, 0, 0);
|
WM_keymap_add_item(keymap, "MESH_OT_split", YKEY, KM_PRESS, 0, 0);
|
||||||
WM_keymap_add_item(keymap, "MESH_OT_vert_connect_path", JKEY, KM_PRESS, 0, 0);
|
WM_keymap_add_item(keymap, "MESH_OT_vert_connect_path", JKEY, KM_PRESS, 0, 0);
|
||||||
|
|
||||||
|
WM_keymap_add_item(keymap, "MESH_OT_point_normals", LKEY, KM_PRESS, KM_ALT, 0);
|
||||||
|
|
||||||
/* Vertex Slide */
|
/* Vertex Slide */
|
||||||
WM_keymap_add_item(keymap, "TRANSFORM_OT_vert_slide", VKEY, KM_PRESS, KM_SHIFT, 0);
|
WM_keymap_add_item(keymap, "TRANSFORM_OT_vert_slide", VKEY, KM_PRESS, KM_SHIFT, 0);
|
||||||
/* use KM_CLICK because same key is used for tweaks */
|
/* use KM_CLICK because same key is used for tweaks */
|
||||||
@@ -466,5 +477,6 @@ void ED_keymap_mesh(wmKeyConfig *keyconf)
|
|||||||
ED_keymap_proportional_editmode(keyconf, keymap, true);
|
ED_keymap_proportional_editmode(keyconf, keymap, true);
|
||||||
|
|
||||||
knifetool_modal_keymap(keyconf);
|
knifetool_modal_keymap(keyconf);
|
||||||
|
point_normals_modal_keymap(keyconf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -46,6 +46,7 @@
|
|||||||
#include "DNA_gpencil_types.h"
|
#include "DNA_gpencil_types.h"
|
||||||
#include "DNA_scene_types.h"
|
#include "DNA_scene_types.h"
|
||||||
#include "DNA_meta_types.h"
|
#include "DNA_meta_types.h"
|
||||||
|
#include "DNA_mesh_types.h"
|
||||||
#include "DNA_mask_types.h"
|
#include "DNA_mask_types.h"
|
||||||
#include "DNA_node_types.h"
|
#include "DNA_node_types.h"
|
||||||
#include "DNA_userdef_types.h"
|
#include "DNA_userdef_types.h"
|
||||||
@@ -353,6 +354,15 @@ int ED_operator_editmesh_region_view3d(bContext *C)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int ED_operator_editmesh_auto_smooth(bContext *C)
|
||||||
|
{
|
||||||
|
Object *obedit = CTX_data_edit_object(C);
|
||||||
|
if (obedit && obedit->type == OB_MESH && (((Mesh *)(obedit->data))->flag & ME_AUTOSMOOTH)) {
|
||||||
|
return NULL != BKE_editmesh_from_object(obedit);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int ED_operator_editarmature(bContext *C)
|
int ED_operator_editarmature(bContext *C)
|
||||||
{
|
{
|
||||||
Object *obedit = CTX_data_edit_object(C);
|
Object *obedit = CTX_data_edit_object(C);
|
||||||
|
@@ -1181,6 +1181,7 @@ static void tselem_draw_icon(uiBlock *block, int xmax, float x, float y, TreeSto
|
|||||||
case eModifierType_DataTransfer:
|
case eModifierType_DataTransfer:
|
||||||
UI_icon_draw(x, y, ICON_MOD_DATA_TRANSFER); break;
|
UI_icon_draw(x, y, ICON_MOD_DATA_TRANSFER); break;
|
||||||
case eModifierType_NormalEdit:
|
case eModifierType_NormalEdit:
|
||||||
|
case eModifierType_WeightedNormal:
|
||||||
UI_icon_draw(x, y, ICON_MOD_NORMALEDIT); break;
|
UI_icon_draw(x, y, ICON_MOD_NORMALEDIT); break;
|
||||||
/* Default */
|
/* Default */
|
||||||
case eModifierType_None:
|
case eModifierType_None:
|
||||||
|
@@ -41,6 +41,7 @@
|
|||||||
#include "DNA_armature_types.h"
|
#include "DNA_armature_types.h"
|
||||||
#include "DNA_constraint_types.h"
|
#include "DNA_constraint_types.h"
|
||||||
#include "DNA_mask_types.h"
|
#include "DNA_mask_types.h"
|
||||||
|
#include "DNA_mesh_types.h"
|
||||||
#include "DNA_movieclip_types.h"
|
#include "DNA_movieclip_types.h"
|
||||||
#include "DNA_scene_types.h" /* PET modes */
|
#include "DNA_scene_types.h" /* PET modes */
|
||||||
|
|
||||||
@@ -62,6 +63,7 @@
|
|||||||
#include "BKE_particle.h"
|
#include "BKE_particle.h"
|
||||||
#include "BKE_unit.h"
|
#include "BKE_unit.h"
|
||||||
#include "BKE_mask.h"
|
#include "BKE_mask.h"
|
||||||
|
#include "BKE_mesh.h"
|
||||||
#include "BKE_report.h"
|
#include "BKE_report.h"
|
||||||
|
|
||||||
#include "BIF_gl.h"
|
#include "BIF_gl.h"
|
||||||
@@ -86,6 +88,7 @@
|
|||||||
#include "UI_resources.h"
|
#include "UI_resources.h"
|
||||||
|
|
||||||
#include "RNA_access.h"
|
#include "RNA_access.h"
|
||||||
|
#include "RNA_define.h"
|
||||||
|
|
||||||
#include "BLF_api.h"
|
#include "BLF_api.h"
|
||||||
#include "BLT_translation.h"
|
#include "BLT_translation.h"
|
||||||
@@ -106,6 +109,7 @@ static void postInputRotation(TransInfo *t, float values[3]);
|
|||||||
static void ElementRotation(TransInfo *t, TransData *td, float mat[3][3], const short around);
|
static void ElementRotation(TransInfo *t, TransData *td, float mat[3][3], const short around);
|
||||||
static void initSnapSpatial(TransInfo *t, float r_snap[3]);
|
static void initSnapSpatial(TransInfo *t, float r_snap[3]);
|
||||||
|
|
||||||
|
static void storeCustomLNorValue(TransInfo *t, BMesh *bm);
|
||||||
|
|
||||||
/* Transform Callbacks */
|
/* Transform Callbacks */
|
||||||
static void initBend(TransInfo *t);
|
static void initBend(TransInfo *t);
|
||||||
@@ -131,6 +135,9 @@ static void applyToSphere(TransInfo *t, const int mval[2]);
|
|||||||
static void initRotation(TransInfo *t);
|
static void initRotation(TransInfo *t);
|
||||||
static void applyRotation(TransInfo *t, const int mval[2]);
|
static void applyRotation(TransInfo *t, const int mval[2]);
|
||||||
|
|
||||||
|
static void initNormalRotation(TransInfo *t);
|
||||||
|
static void applyNormalRotation(TransInfo *t, const int mval[2]);
|
||||||
|
|
||||||
static void initShrinkFatten(TransInfo *t);
|
static void initShrinkFatten(TransInfo *t);
|
||||||
static void applyShrinkFatten(TransInfo *t, const int mval[2]);
|
static void applyShrinkFatten(TransInfo *t, const int mval[2]);
|
||||||
|
|
||||||
@@ -1465,6 +1472,20 @@ int transformEvent(TransInfo *t, const wmEvent *event)
|
|||||||
handled = true;
|
handled = true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case NKEY:
|
||||||
|
if (ELEM(t->mode, TFM_ROTATION)) {
|
||||||
|
if (t->obedit && t->obedit->type == OB_MESH) {
|
||||||
|
if (((Mesh *)(t->obedit->data))->flag & ME_AUTOSMOOTH) {
|
||||||
|
restoreTransObjects(t);
|
||||||
|
resetTransModal(t);
|
||||||
|
resetTransRestrictions(t);
|
||||||
|
initNormalRotation(t);
|
||||||
|
t->redraw = TREDRAW_HARD;
|
||||||
|
handled = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -2303,6 +2324,9 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
|
|||||||
case TFM_SEQ_SLIDE:
|
case TFM_SEQ_SLIDE:
|
||||||
initSeqSlide(t);
|
initSeqSlide(t);
|
||||||
break;
|
break;
|
||||||
|
case TFM_NORMAL_ROTATION:
|
||||||
|
initNormalRotation(t);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (t->state == TRANS_CANCEL) {
|
if (t->state == TRANS_CANCEL) {
|
||||||
@@ -2359,6 +2383,34 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
|
|||||||
t->flag |= T_AUTOVALUES;
|
t->flag |= T_AUTOVALUES;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((prop = RNA_struct_find_property(op->ptr, "preserve_clnor"))) {
|
||||||
|
if (t->obedit && t->obedit->type == OB_MESH && (((Mesh *)(t->obedit->data))->flag & ME_AUTOSMOOTH)) {
|
||||||
|
BMEditMesh *em = BKE_editmesh_from_object(t->obedit);
|
||||||
|
bool do_skip = false;
|
||||||
|
|
||||||
|
/* Currently only used for two of three most frequent transform ops, can include more ops.
|
||||||
|
* Note that scaling cannot be included here, non-uniform scaling will affect normals. */
|
||||||
|
if (ELEM(t->mode, TFM_TRANSLATION, TFM_ROTATION)) {
|
||||||
|
if (em->bm->totvertsel == em->bm->totvert) {
|
||||||
|
/* No need to invalidate if whole mesh is selected. */
|
||||||
|
do_skip = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (t->flag & T_MODAL) {
|
||||||
|
RNA_property_boolean_set(op->ptr, prop, false);
|
||||||
|
}
|
||||||
|
else if (!do_skip) {
|
||||||
|
const bool preserve_clnor = RNA_property_boolean_get(op->ptr, prop);
|
||||||
|
if (preserve_clnor) {
|
||||||
|
BKE_editmesh_lnorspace_update(em);
|
||||||
|
t->flag |= T_CLNOR_REBUILD;
|
||||||
|
}
|
||||||
|
BM_lnorspace_invalidate(em->bm, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
t->context = NULL;
|
t->context = NULL;
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
@@ -2419,6 +2471,10 @@ int transformEnd(bContext *C, TransInfo *t)
|
|||||||
restoreTransObjects(t); // calls recalcData()
|
restoreTransObjects(t); // calls recalcData()
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
if (t->flag & T_CLNOR_REBUILD) {
|
||||||
|
BMEditMesh *em = BKE_editmesh_from_object(t->obedit);
|
||||||
|
BM_lnorspace_rebuild(em->bm, true);
|
||||||
|
}
|
||||||
exit_code = OPERATOR_FINISHED;
|
exit_code = OPERATOR_FINISHED;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3714,6 +3770,28 @@ static void initRotation(TransInfo *t)
|
|||||||
copy_v3_v3(t->axis_orig, t->axis);
|
copy_v3_v3(t->axis_orig, t->axis);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Used by Transform Rotation and Transform Normal Rotation */
|
||||||
|
static void headerRotation(TransInfo *t, char str[UI_MAX_DRAW_STR], float final)
|
||||||
|
{
|
||||||
|
size_t ofs = 0;
|
||||||
|
|
||||||
|
if (hasNumInput(&t->num)) {
|
||||||
|
char c[NUM_STR_REP_LEN];
|
||||||
|
|
||||||
|
outputNumInput(&(t->num), c, &t->scene->unit);
|
||||||
|
|
||||||
|
ofs += BLI_snprintf(str + ofs, UI_MAX_DRAW_STR - ofs, IFACE_("Rot: %s %s %s"), &c[0], t->con.text, t->proptext);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ofs += BLI_snprintf(str + ofs, UI_MAX_DRAW_STR - ofs, IFACE_("Rot: %.2f%s %s"),
|
||||||
|
RAD2DEGF(final), t->con.text, t->proptext);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (t->flag & T_PROP_EDIT_ALL) {
|
||||||
|
ofs += BLI_snprintf(str + ofs, UI_MAX_DRAW_STR - ofs, IFACE_(" Proportional size: %.2f"), t->prop_size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Applies values of rotation to `td->loc` and `td->ext->quat`
|
* Applies values of rotation to `td->loc` and `td->ext->quat`
|
||||||
* based on a rotation matrix (mat) and a pivot (center).
|
* based on a rotation matrix (mat) and a pivot (center).
|
||||||
@@ -3979,7 +4057,6 @@ static void applyRotationValue(TransInfo *t, float angle, float axis[3])
|
|||||||
static void applyRotation(TransInfo *t, const int UNUSED(mval[2]))
|
static void applyRotation(TransInfo *t, const int UNUSED(mval[2]))
|
||||||
{
|
{
|
||||||
char str[UI_MAX_DRAW_STR];
|
char str[UI_MAX_DRAW_STR];
|
||||||
size_t ofs = 0;
|
|
||||||
|
|
||||||
float final;
|
float final;
|
||||||
|
|
||||||
@@ -4002,21 +4079,7 @@ static void applyRotation(TransInfo *t, const int UNUSED(mval[2]))
|
|||||||
|
|
||||||
t->values[0] = final;
|
t->values[0] = final;
|
||||||
|
|
||||||
if (hasNumInput(&t->num)) {
|
headerRotation(t, str, final);
|
||||||
char c[NUM_STR_REP_LEN];
|
|
||||||
|
|
||||||
outputNumInput(&(t->num), c, &t->scene->unit);
|
|
||||||
|
|
||||||
ofs += BLI_snprintf(str + ofs, sizeof(str) - ofs, IFACE_("Rot: %s %s %s"), &c[0], t->con.text, t->proptext);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
ofs += BLI_snprintf(str + ofs, sizeof(str) - ofs, IFACE_("Rot: %.2f%s %s"),
|
|
||||||
RAD2DEGF(final), t->con.text, t->proptext);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (t->flag & T_PROP_EDIT_ALL) {
|
|
||||||
ofs += BLI_snprintf(str + ofs, sizeof(str) - ofs, IFACE_(" Proportional size: %.2f"), t->prop_size);
|
|
||||||
}
|
|
||||||
|
|
||||||
applyRotationValue(t, final, t->axis);
|
applyRotationValue(t, final, t->axis);
|
||||||
|
|
||||||
@@ -4142,6 +4205,122 @@ static void applyTrackball(TransInfo *t, const int UNUSED(mval[2]))
|
|||||||
/** \} */
|
/** \} */
|
||||||
|
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------- */
|
||||||
|
/* Transform (Normal Rotation) */
|
||||||
|
|
||||||
|
/** \name Transform Normal Rotation
|
||||||
|
* \{ */
|
||||||
|
|
||||||
|
static void storeCustomLNorValue(TransInfo *t, BMesh *bm)
|
||||||
|
{
|
||||||
|
BMLoopNorEditDataArray *lnors_ed_arr = BM_loop_normal_editdata_array_init(bm);
|
||||||
|
BMLoopNorEditData *lnor_ed = lnors_ed_arr->lnor_editdata;
|
||||||
|
|
||||||
|
t->custom.mode.data = lnors_ed_arr;
|
||||||
|
t->custom.mode.free_cb = freeCustomNormalArray;
|
||||||
|
}
|
||||||
|
|
||||||
|
void freeCustomNormalArray(TransInfo *t, TransCustomData *custom_data)
|
||||||
|
{
|
||||||
|
BMLoopNorEditDataArray *lnors_ed_arr = custom_data->data;
|
||||||
|
|
||||||
|
if (t->state == TRANS_CANCEL) {
|
||||||
|
BMLoopNorEditData *lnor_ed = lnors_ed_arr->lnor_editdata;
|
||||||
|
BMEditMesh *em = BKE_editmesh_from_object(t->obedit);
|
||||||
|
BMesh *bm = em->bm;
|
||||||
|
|
||||||
|
for (int i = 0; i < lnors_ed_arr->totloop; i++, lnor_ed++) { /* Restore custom loop normal on cancel */
|
||||||
|
BKE_lnor_space_custom_normal_to_data(
|
||||||
|
bm->lnor_spacearr->lspacearr[lnor_ed->loop_index], lnor_ed->niloc, lnor_ed->clnors_data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BM_loop_normal_editdata_array_free(lnors_ed_arr);
|
||||||
|
|
||||||
|
t->custom.mode.data = NULL;
|
||||||
|
t->custom.mode.free_cb = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void initNormalRotation(TransInfo *t)
|
||||||
|
{
|
||||||
|
t->mode = TFM_NORMAL_ROTATION;
|
||||||
|
t->transform = applyNormalRotation;
|
||||||
|
|
||||||
|
setInputPostFct(&t->mouse, postInputRotation);
|
||||||
|
initMouseInputMode(t, &t->mouse, INPUT_ANGLE);
|
||||||
|
|
||||||
|
t->idx_max = 0;
|
||||||
|
t->num.idx_max = 0;
|
||||||
|
t->snap[0] = 0.0f;
|
||||||
|
t->snap[1] = DEG2RAD(5.0);
|
||||||
|
t->snap[2] = DEG2RAD(1.0);
|
||||||
|
|
||||||
|
copy_v3_fl(t->num.val_inc, t->snap[2]);
|
||||||
|
t->num.unit_sys = t->scene->unit.system;
|
||||||
|
t->num.unit_use_radians = (t->scene->unit.system_rotation == USER_UNIT_ROT_RADIANS);
|
||||||
|
t->num.unit_type[0] = B_UNIT_ROTATION;
|
||||||
|
|
||||||
|
BMEditMesh *em = BKE_editmesh_from_object(t->obedit);
|
||||||
|
BMesh *bm = em->bm;
|
||||||
|
|
||||||
|
BKE_editmesh_lnorspace_update(em);
|
||||||
|
|
||||||
|
storeCustomLNorValue(t, bm);
|
||||||
|
|
||||||
|
negate_v3_v3(t->axis, t->viewinv[2]);
|
||||||
|
normalize_v3(t->axis);
|
||||||
|
|
||||||
|
copy_v3_v3(t->axis_orig, t->axis);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Works by getting custom normal from clnor_data, transform, then store */
|
||||||
|
static void applyNormalRotation(TransInfo *t, const int UNUSED(mval[2]))
|
||||||
|
{
|
||||||
|
BMEditMesh *em = BKE_editmesh_from_object(t->obedit);
|
||||||
|
BMesh *bm = em->bm;
|
||||||
|
char str[UI_MAX_DRAW_STR];
|
||||||
|
|
||||||
|
if ((t->con.mode & CON_APPLY) && t->con.applyRot) {
|
||||||
|
t->con.applyRot(t, NULL, t->axis, NULL);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* reset axis if constraint is not set */
|
||||||
|
copy_v3_v3(t->axis, t->axis_orig);
|
||||||
|
}
|
||||||
|
|
||||||
|
BMLoopNorEditDataArray *lnors_ed_arr = t->custom.mode.data;
|
||||||
|
BMLoopNorEditData *lnor_ed = lnors_ed_arr->lnor_editdata;
|
||||||
|
|
||||||
|
float axis[3];
|
||||||
|
float mat[3][3];
|
||||||
|
float angle = t->values[0];
|
||||||
|
copy_v3_v3(axis, t->axis);
|
||||||
|
|
||||||
|
snapGridIncrement(t, &angle);
|
||||||
|
|
||||||
|
applySnapping(t, &angle);
|
||||||
|
|
||||||
|
applyNumInput(&t->num, &angle);
|
||||||
|
|
||||||
|
headerRotation(t, str, angle);
|
||||||
|
|
||||||
|
axis_angle_normalized_to_mat3(mat, axis, angle);
|
||||||
|
|
||||||
|
for (int i = 0; i < lnors_ed_arr->totloop; i++, lnor_ed++) {
|
||||||
|
mul_v3_m3v3(lnor_ed->nloc, mat, lnor_ed->niloc);
|
||||||
|
|
||||||
|
BKE_lnor_space_custom_normal_to_data(
|
||||||
|
bm->lnor_spacearr->lspacearr[lnor_ed->loop_index], lnor_ed->nloc, lnor_ed->clnors_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
recalcData(t);
|
||||||
|
|
||||||
|
ED_area_headerprint(t->sa, str);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \} */
|
||||||
|
|
||||||
|
|
||||||
/* -------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------- */
|
||||||
/* Transform (Translation) */
|
/* Transform (Translation) */
|
||||||
|
|
||||||
|
@@ -536,6 +536,8 @@ typedef struct TransInfo {
|
|||||||
/** #TransInfo.center has been set, don't change it. */
|
/** #TransInfo.center has been set, don't change it. */
|
||||||
#define T_OVERRIDE_CENTER (1 << 25)
|
#define T_OVERRIDE_CENTER (1 << 25)
|
||||||
|
|
||||||
|
#define T_CLNOR_REBUILD (1 << 26)
|
||||||
|
|
||||||
/* TransInfo->modifiers */
|
/* TransInfo->modifiers */
|
||||||
#define MOD_CONSTRAINT_SELECT 0x01
|
#define MOD_CONSTRAINT_SELECT 0x01
|
||||||
#define MOD_PRECISION 0x02
|
#define MOD_PRECISION 0x02
|
||||||
@@ -798,6 +800,8 @@ bool applyTransformOrientation(const struct bContext *C, float mat[3][3], char r
|
|||||||
int getTransformOrientation_ex(const struct bContext *C, float normal[3], float plane[3], const short around);
|
int getTransformOrientation_ex(const struct bContext *C, float normal[3], float plane[3], const short around);
|
||||||
int getTransformOrientation(const struct bContext *C, float normal[3], float plane[3]);
|
int getTransformOrientation(const struct bContext *C, float normal[3], float plane[3]);
|
||||||
|
|
||||||
|
void freeCustomNormalArray(TransInfo *t, TransCustomData *custom_data);
|
||||||
|
|
||||||
void freeEdgeSlideTempFaces(EdgeSlideData *sld);
|
void freeEdgeSlideTempFaces(EdgeSlideData *sld);
|
||||||
void freeEdgeSlideVerts(TransInfo *t, TransCustomData *custom_data);
|
void freeEdgeSlideVerts(TransInfo *t, TransCustomData *custom_data);
|
||||||
void projectEdgeSlideData(TransInfo *t, bool is_final);
|
void projectEdgeSlideData(TransInfo *t, bool is_final);
|
||||||
|
@@ -1072,6 +1072,9 @@ void resetTransModal(TransInfo *t)
|
|||||||
else if (t->mode == TFM_VERT_SLIDE) {
|
else if (t->mode == TFM_VERT_SLIDE) {
|
||||||
freeVertSlideVerts(t, &t->custom.mode);
|
freeVertSlideVerts(t, &t->custom.mode);
|
||||||
}
|
}
|
||||||
|
else if (t->mode == TFM_NORMAL_ROTATION) {
|
||||||
|
freeCustomNormalArray(t, &t->custom.mode);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void resetTransRestrictions(TransInfo *t)
|
void resetTransRestrictions(TransInfo *t)
|
||||||
|
@@ -81,6 +81,7 @@ static const char OP_VERT_SLIDE[] = "TRANSFORM_OT_vert_slide";
|
|||||||
static const char OP_EDGE_CREASE[] = "TRANSFORM_OT_edge_crease";
|
static const char OP_EDGE_CREASE[] = "TRANSFORM_OT_edge_crease";
|
||||||
static const char OP_EDGE_BWEIGHT[] = "TRANSFORM_OT_edge_bevelweight";
|
static const char OP_EDGE_BWEIGHT[] = "TRANSFORM_OT_edge_bevelweight";
|
||||||
static const char OP_SEQ_SLIDE[] = "TRANSFORM_OT_seq_slide";
|
static const char OP_SEQ_SLIDE[] = "TRANSFORM_OT_seq_slide";
|
||||||
|
static const char OP_NORMAL_ROTATION[] = "TRANSFORM_OT_rotate_normal";
|
||||||
|
|
||||||
static void TRANSFORM_OT_translate(struct wmOperatorType *ot);
|
static void TRANSFORM_OT_translate(struct wmOperatorType *ot);
|
||||||
static void TRANSFORM_OT_rotate(struct wmOperatorType *ot);
|
static void TRANSFORM_OT_rotate(struct wmOperatorType *ot);
|
||||||
@@ -99,6 +100,7 @@ static void TRANSFORM_OT_vert_slide(struct wmOperatorType *ot);
|
|||||||
static void TRANSFORM_OT_edge_crease(struct wmOperatorType *ot);
|
static void TRANSFORM_OT_edge_crease(struct wmOperatorType *ot);
|
||||||
static void TRANSFORM_OT_edge_bevelweight(struct wmOperatorType *ot);
|
static void TRANSFORM_OT_edge_bevelweight(struct wmOperatorType *ot);
|
||||||
static void TRANSFORM_OT_seq_slide(struct wmOperatorType *ot);
|
static void TRANSFORM_OT_seq_slide(struct wmOperatorType *ot);
|
||||||
|
static void TRANSFORM_OT_rotate_normal(struct wmOperatorType *ot);
|
||||||
|
|
||||||
static TransformModeItem transform_modes[] =
|
static TransformModeItem transform_modes[] =
|
||||||
{
|
{
|
||||||
@@ -119,6 +121,7 @@ static TransformModeItem transform_modes[] =
|
|||||||
{OP_EDGE_CREASE, TFM_CREASE, TRANSFORM_OT_edge_crease},
|
{OP_EDGE_CREASE, TFM_CREASE, TRANSFORM_OT_edge_crease},
|
||||||
{OP_EDGE_BWEIGHT, TFM_BWEIGHT, TRANSFORM_OT_edge_bevelweight},
|
{OP_EDGE_BWEIGHT, TFM_BWEIGHT, TRANSFORM_OT_edge_bevelweight},
|
||||||
{OP_SEQ_SLIDE, TFM_SEQ_SLIDE, TRANSFORM_OT_seq_slide},
|
{OP_SEQ_SLIDE, TFM_SEQ_SLIDE, TRANSFORM_OT_seq_slide},
|
||||||
|
{OP_NORMAL_ROTATION, TFM_NORMAL_ROTATION, TRANSFORM_OT_rotate_normal},
|
||||||
{NULL, 0}
|
{NULL, 0}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -495,6 +498,39 @@ static int transform_invoke(bContext *C, wmOperator *op, const wmEvent *event)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool transform_draw_check_prop(PointerRNA *ptr, PropertyRNA *prop)
|
||||||
|
{
|
||||||
|
const char *prop_id = RNA_property_identifier(prop);
|
||||||
|
|
||||||
|
/* Only show preserve_clnor option if requested (kinda hackish, we need to take that decision based on context... */
|
||||||
|
if (STREQ(prop_id, "preserve_clnor")) {
|
||||||
|
return RNA_boolean_get(ptr, "show_preserve_clnor");;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Else, show it! */
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void transform_ui(bContext *C, wmOperator *op)
|
||||||
|
{
|
||||||
|
uiLayout *layout = op->layout;
|
||||||
|
wmWindowManager *wm = CTX_wm_manager(C);
|
||||||
|
PointerRNA ptr;
|
||||||
|
Object *obedit = CTX_data_edit_object(C);
|
||||||
|
|
||||||
|
PropertyRNA *prop = RNA_struct_find_property(op->ptr, "show_preserve_clnor");
|
||||||
|
if (prop) {
|
||||||
|
RNA_property_boolean_set(
|
||||||
|
op->ptr, prop,
|
||||||
|
(obedit && obedit->type == OB_MESH && (((Mesh *)(obedit->data))->flag & ME_AUTOSMOOTH)));
|
||||||
|
}
|
||||||
|
|
||||||
|
RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr);
|
||||||
|
|
||||||
|
/* Main auto-draw call */
|
||||||
|
uiDefAutoButsRNA(layout, &ptr, transform_draw_check_prop, '\0');
|
||||||
|
}
|
||||||
|
|
||||||
void Transform_Properties(struct wmOperatorType *ot, int flags)
|
void Transform_Properties(struct wmOperatorType *ot, int flags)
|
||||||
{
|
{
|
||||||
PropertyRNA *prop;
|
PropertyRNA *prop;
|
||||||
@@ -580,6 +616,12 @@ void Transform_Properties(struct wmOperatorType *ot, int flags)
|
|||||||
prop = RNA_def_boolean(ot->srna, "use_accurate", 0, "Accurate", "Use accurate transformation");
|
prop = RNA_def_boolean(ot->srna, "use_accurate", 0, "Accurate", "Use accurate transformation");
|
||||||
RNA_def_property_flag(prop, PROP_HIDDEN);
|
RNA_def_property_flag(prop, PROP_HIDDEN);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (flags & P_CLNOR_INVALIDATE) {
|
||||||
|
RNA_def_boolean(ot->srna, "preserve_clnor", false, "Preserve Normals", "Keep custom normals during transform");
|
||||||
|
prop = RNA_def_boolean(ot->srna, "show_preserve_clnor", false, "Show Preserve Normals", "");
|
||||||
|
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void TRANSFORM_OT_translate(struct wmOperatorType *ot)
|
static void TRANSFORM_OT_translate(struct wmOperatorType *ot)
|
||||||
@@ -596,10 +638,11 @@ static void TRANSFORM_OT_translate(struct wmOperatorType *ot)
|
|||||||
ot->modal = transform_modal;
|
ot->modal = transform_modal;
|
||||||
ot->cancel = transform_cancel;
|
ot->cancel = transform_cancel;
|
||||||
ot->poll = ED_operator_screenactive;
|
ot->poll = ED_operator_screenactive;
|
||||||
|
ot->ui = transform_ui;
|
||||||
|
|
||||||
RNA_def_float_vector_xyz(ot->srna, "value", 3, NULL, -FLT_MAX, FLT_MAX, "Vector", "", -FLT_MAX, FLT_MAX);
|
RNA_def_float_vector_xyz(ot->srna, "value", 3, NULL, -FLT_MAX, FLT_MAX, "Vector", "", -FLT_MAX, FLT_MAX);
|
||||||
|
|
||||||
Transform_Properties(ot, P_CONSTRAINT | P_PROPORTIONAL | P_MIRROR | P_ALIGN_SNAP | P_OPTIONS | P_GPENCIL_EDIT);
|
Transform_Properties(ot, P_CONSTRAINT | P_PROPORTIONAL | P_MIRROR | P_ALIGN_SNAP | P_OPTIONS | P_GPENCIL_EDIT | P_CLNOR_INVALIDATE);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void TRANSFORM_OT_resize(struct wmOperatorType *ot)
|
static void TRANSFORM_OT_resize(struct wmOperatorType *ot)
|
||||||
@@ -616,12 +659,12 @@ static void TRANSFORM_OT_resize(struct wmOperatorType *ot)
|
|||||||
ot->modal = transform_modal;
|
ot->modal = transform_modal;
|
||||||
ot->cancel = transform_cancel;
|
ot->cancel = transform_cancel;
|
||||||
ot->poll = ED_operator_screenactive;
|
ot->poll = ED_operator_screenactive;
|
||||||
|
ot->ui = transform_ui;
|
||||||
|
|
||||||
RNA_def_float_vector(ot->srna, "value", 3, VecOne, -FLT_MAX, FLT_MAX, "Vector", "", -FLT_MAX, FLT_MAX);
|
RNA_def_float_vector(ot->srna, "value", 3, VecOne, -FLT_MAX, FLT_MAX, "Vector", "", -FLT_MAX, FLT_MAX);
|
||||||
|
|
||||||
Transform_Properties(
|
Transform_Properties(
|
||||||
ot, P_CONSTRAINT | P_PROPORTIONAL | P_MIRROR | P_GEO_SNAP | P_OPTIONS | P_GPENCIL_EDIT | P_CENTER);
|
ot, P_CONSTRAINT | P_PROPORTIONAL | P_MIRROR | P_GEO_SNAP | P_OPTIONS | P_GPENCIL_EDIT | P_CENTER | P_CLNOR_INVALIDATE);}
|
||||||
}
|
|
||||||
|
|
||||||
static int skin_resize_poll(bContext *C)
|
static int skin_resize_poll(bContext *C)
|
||||||
{
|
{
|
||||||
@@ -647,6 +690,7 @@ static void TRANSFORM_OT_skin_resize(struct wmOperatorType *ot)
|
|||||||
ot->modal = transform_modal;
|
ot->modal = transform_modal;
|
||||||
ot->cancel = transform_cancel;
|
ot->cancel = transform_cancel;
|
||||||
ot->poll = skin_resize_poll;
|
ot->poll = skin_resize_poll;
|
||||||
|
ot->ui = transform_ui;
|
||||||
|
|
||||||
RNA_def_float_vector(ot->srna, "value", 3, VecOne, -FLT_MAX, FLT_MAX, "Vector", "", -FLT_MAX, FLT_MAX);
|
RNA_def_float_vector(ot->srna, "value", 3, VecOne, -FLT_MAX, FLT_MAX, "Vector", "", -FLT_MAX, FLT_MAX);
|
||||||
|
|
||||||
@@ -667,12 +711,12 @@ static void TRANSFORM_OT_trackball(struct wmOperatorType *ot)
|
|||||||
ot->modal = transform_modal;
|
ot->modal = transform_modal;
|
||||||
ot->cancel = transform_cancel;
|
ot->cancel = transform_cancel;
|
||||||
ot->poll = ED_operator_screenactive;
|
ot->poll = ED_operator_screenactive;
|
||||||
|
ot->ui = transform_ui;
|
||||||
|
|
||||||
/* Maybe we could use float_vector_xyz here too? */
|
/* Maybe we could use float_vector_xyz here too? */
|
||||||
RNA_def_float_rotation(ot->srna, "value", 2, NULL, -FLT_MAX, FLT_MAX, "Angle", "", -FLT_MAX, FLT_MAX);
|
RNA_def_float_rotation(ot->srna, "value", 2, NULL, -FLT_MAX, FLT_MAX, "Angle", "", -FLT_MAX, FLT_MAX);
|
||||||
|
|
||||||
Transform_Properties(ot, P_PROPORTIONAL | P_MIRROR | P_SNAP | P_GPENCIL_EDIT | P_CENTER);
|
Transform_Properties(ot, P_PROPORTIONAL | P_MIRROR | P_SNAP | P_GPENCIL_EDIT | P_CENTER | P_CLNOR_INVALIDATE);}
|
||||||
}
|
|
||||||
|
|
||||||
static void TRANSFORM_OT_rotate(struct wmOperatorType *ot)
|
static void TRANSFORM_OT_rotate(struct wmOperatorType *ot)
|
||||||
{
|
{
|
||||||
@@ -688,12 +732,12 @@ static void TRANSFORM_OT_rotate(struct wmOperatorType *ot)
|
|||||||
ot->modal = transform_modal;
|
ot->modal = transform_modal;
|
||||||
ot->cancel = transform_cancel;
|
ot->cancel = transform_cancel;
|
||||||
ot->poll = ED_operator_screenactive;
|
ot->poll = ED_operator_screenactive;
|
||||||
|
ot->ui = transform_ui;
|
||||||
|
|
||||||
RNA_def_float_rotation(ot->srna, "value", 0, NULL, -FLT_MAX, FLT_MAX, "Angle", "", -M_PI * 2, M_PI * 2);
|
RNA_def_float_rotation(ot->srna, "value", 0, NULL, -FLT_MAX, FLT_MAX, "Angle", "", -M_PI * 2, M_PI * 2);
|
||||||
|
|
||||||
Transform_Properties(
|
Transform_Properties(
|
||||||
ot, P_AXIS | P_CONSTRAINT | P_PROPORTIONAL | P_MIRROR | P_GEO_SNAP | P_GPENCIL_EDIT | P_CENTER);
|
ot, P_AXIS | P_CONSTRAINT | P_PROPORTIONAL | P_MIRROR | P_GEO_SNAP | P_GPENCIL_EDIT | P_CENTER | P_CLNOR_INVALIDATE);}
|
||||||
}
|
|
||||||
|
|
||||||
static void TRANSFORM_OT_tilt(struct wmOperatorType *ot)
|
static void TRANSFORM_OT_tilt(struct wmOperatorType *ot)
|
||||||
{
|
{
|
||||||
@@ -712,6 +756,7 @@ static void TRANSFORM_OT_tilt(struct wmOperatorType *ot)
|
|||||||
ot->modal = transform_modal;
|
ot->modal = transform_modal;
|
||||||
ot->cancel = transform_cancel;
|
ot->cancel = transform_cancel;
|
||||||
ot->poll = ED_operator_editcurve_3d;
|
ot->poll = ED_operator_editcurve_3d;
|
||||||
|
ot->ui = transform_ui;
|
||||||
|
|
||||||
RNA_def_float_rotation(ot->srna, "value", 0, NULL, -FLT_MAX, FLT_MAX, "Angle", "", -M_PI * 2, M_PI * 2);
|
RNA_def_float_rotation(ot->srna, "value", 0, NULL, -FLT_MAX, FLT_MAX, "Angle", "", -M_PI * 2, M_PI * 2);
|
||||||
|
|
||||||
@@ -732,11 +777,11 @@ static void TRANSFORM_OT_bend(struct wmOperatorType *ot)
|
|||||||
ot->modal = transform_modal;
|
ot->modal = transform_modal;
|
||||||
ot->cancel = transform_cancel;
|
ot->cancel = transform_cancel;
|
||||||
ot->poll = ED_operator_region_view3d_active;
|
ot->poll = ED_operator_region_view3d_active;
|
||||||
|
ot->ui = transform_ui;
|
||||||
|
|
||||||
RNA_def_float_rotation(ot->srna, "value", 1, NULL, -FLT_MAX, FLT_MAX, "Angle", "", -M_PI * 2, M_PI * 2);
|
RNA_def_float_rotation(ot->srna, "value", 1, NULL, -FLT_MAX, FLT_MAX, "Angle", "", -M_PI * 2, M_PI * 2);
|
||||||
|
|
||||||
Transform_Properties(ot, P_PROPORTIONAL | P_MIRROR | P_SNAP | P_GPENCIL_EDIT | P_CENTER);
|
Transform_Properties(ot, P_PROPORTIONAL | P_MIRROR | P_SNAP | P_GPENCIL_EDIT | P_CENTER | P_CLNOR_INVALIDATE);}
|
||||||
}
|
|
||||||
|
|
||||||
static void TRANSFORM_OT_shear(struct wmOperatorType *ot)
|
static void TRANSFORM_OT_shear(struct wmOperatorType *ot)
|
||||||
{
|
{
|
||||||
@@ -752,10 +797,11 @@ static void TRANSFORM_OT_shear(struct wmOperatorType *ot)
|
|||||||
ot->modal = transform_modal;
|
ot->modal = transform_modal;
|
||||||
ot->cancel = transform_cancel;
|
ot->cancel = transform_cancel;
|
||||||
ot->poll = ED_operator_screenactive;
|
ot->poll = ED_operator_screenactive;
|
||||||
|
ot->ui = transform_ui;
|
||||||
|
|
||||||
RNA_def_float(ot->srna, "value", 0, -FLT_MAX, FLT_MAX, "Offset", "", -FLT_MAX, FLT_MAX);
|
RNA_def_float(ot->srna, "value", 0, -FLT_MAX, FLT_MAX, "Offset", "", -FLT_MAX, FLT_MAX);
|
||||||
|
|
||||||
Transform_Properties(ot, P_PROPORTIONAL | P_MIRROR | P_SNAP | P_GPENCIL_EDIT);
|
Transform_Properties(ot, P_PROPORTIONAL | P_MIRROR | P_SNAP | P_GPENCIL_EDIT | P_CLNOR_INVALIDATE);
|
||||||
// XXX Shear axis?
|
// XXX Shear axis?
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -773,11 +819,11 @@ static void TRANSFORM_OT_push_pull(struct wmOperatorType *ot)
|
|||||||
ot->modal = transform_modal;
|
ot->modal = transform_modal;
|
||||||
ot->cancel = transform_cancel;
|
ot->cancel = transform_cancel;
|
||||||
ot->poll = ED_operator_screenactive;
|
ot->poll = ED_operator_screenactive;
|
||||||
|
ot->ui = transform_ui;
|
||||||
|
|
||||||
RNA_def_float(ot->srna, "value", 0, -FLT_MAX, FLT_MAX, "Distance", "", -FLT_MAX, FLT_MAX);
|
RNA_def_float(ot->srna, "value", 0, -FLT_MAX, FLT_MAX, "Distance", "", -FLT_MAX, FLT_MAX);
|
||||||
|
|
||||||
Transform_Properties(ot, P_PROPORTIONAL | P_MIRROR | P_SNAP | P_CENTER);
|
Transform_Properties(ot, P_PROPORTIONAL | P_MIRROR | P_SNAP | P_CENTER | P_CLNOR_INVALIDATE);}
|
||||||
}
|
|
||||||
|
|
||||||
static void TRANSFORM_OT_shrink_fatten(struct wmOperatorType *ot)
|
static void TRANSFORM_OT_shrink_fatten(struct wmOperatorType *ot)
|
||||||
{
|
{
|
||||||
@@ -793,12 +839,13 @@ static void TRANSFORM_OT_shrink_fatten(struct wmOperatorType *ot)
|
|||||||
ot->modal = transform_modal;
|
ot->modal = transform_modal;
|
||||||
ot->cancel = transform_cancel;
|
ot->cancel = transform_cancel;
|
||||||
ot->poll = ED_operator_editmesh;
|
ot->poll = ED_operator_editmesh;
|
||||||
|
ot->ui = transform_ui;
|
||||||
|
|
||||||
RNA_def_float(ot->srna, "value", 0, -FLT_MAX, FLT_MAX, "Offset", "", -FLT_MAX, FLT_MAX);
|
RNA_def_float(ot->srna, "value", 0, -FLT_MAX, FLT_MAX, "Offset", "", -FLT_MAX, FLT_MAX);
|
||||||
|
|
||||||
RNA_def_boolean(ot->srna, "use_even_offset", true, "Offset Even", "Scale the offset to give more even thickness");
|
RNA_def_boolean(ot->srna, "use_even_offset", true, "Offset Even", "Scale the offset to give more even thickness");
|
||||||
|
|
||||||
Transform_Properties(ot, P_PROPORTIONAL | P_MIRROR | P_SNAP);
|
Transform_Properties(ot, P_PROPORTIONAL | P_MIRROR | P_SNAP | P_CLNOR_INVALIDATE);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void TRANSFORM_OT_tosphere(struct wmOperatorType *ot)
|
static void TRANSFORM_OT_tosphere(struct wmOperatorType *ot)
|
||||||
@@ -816,11 +863,11 @@ static void TRANSFORM_OT_tosphere(struct wmOperatorType *ot)
|
|||||||
ot->modal = transform_modal;
|
ot->modal = transform_modal;
|
||||||
ot->cancel = transform_cancel;
|
ot->cancel = transform_cancel;
|
||||||
ot->poll = ED_operator_screenactive;
|
ot->poll = ED_operator_screenactive;
|
||||||
|
ot->ui = transform_ui;
|
||||||
|
|
||||||
RNA_def_float_factor(ot->srna, "value", 0, 0, 1, "Factor", "", 0, 1);
|
RNA_def_float_factor(ot->srna, "value", 0, 0, 1, "Factor", "", 0, 1);
|
||||||
|
|
||||||
Transform_Properties(ot, P_PROPORTIONAL | P_MIRROR | P_SNAP | P_GPENCIL_EDIT | P_CENTER);
|
Transform_Properties(ot, P_PROPORTIONAL | P_MIRROR | P_SNAP | P_GPENCIL_EDIT | P_CENTER | P_CLNOR_INVALIDATE);}
|
||||||
}
|
|
||||||
|
|
||||||
static void TRANSFORM_OT_mirror(struct wmOperatorType *ot)
|
static void TRANSFORM_OT_mirror(struct wmOperatorType *ot)
|
||||||
{
|
{
|
||||||
@@ -836,9 +883,9 @@ static void TRANSFORM_OT_mirror(struct wmOperatorType *ot)
|
|||||||
ot->modal = transform_modal;
|
ot->modal = transform_modal;
|
||||||
ot->cancel = transform_cancel;
|
ot->cancel = transform_cancel;
|
||||||
ot->poll = ED_operator_screenactive;
|
ot->poll = ED_operator_screenactive;
|
||||||
|
ot->ui = transform_ui;
|
||||||
|
|
||||||
Transform_Properties(ot, P_CONSTRAINT | P_PROPORTIONAL | P_GPENCIL_EDIT | P_CENTER);
|
Transform_Properties(ot, P_CONSTRAINT | P_PROPORTIONAL | P_GPENCIL_EDIT | P_CENTER | P_CLNOR_INVALIDATE);}
|
||||||
}
|
|
||||||
|
|
||||||
static void TRANSFORM_OT_edge_slide(struct wmOperatorType *ot)
|
static void TRANSFORM_OT_edge_slide(struct wmOperatorType *ot)
|
||||||
{
|
{
|
||||||
@@ -856,6 +903,7 @@ static void TRANSFORM_OT_edge_slide(struct wmOperatorType *ot)
|
|||||||
ot->modal = transform_modal;
|
ot->modal = transform_modal;
|
||||||
ot->cancel = transform_cancel;
|
ot->cancel = transform_cancel;
|
||||||
ot->poll = ED_operator_editmesh_region_view3d;
|
ot->poll = ED_operator_editmesh_region_view3d;
|
||||||
|
ot->ui = transform_ui;
|
||||||
|
|
||||||
RNA_def_float_factor(ot->srna, "value", 0, -10.0f, 10.0f, "Factor", "", -1.0f, 1.0f);
|
RNA_def_float_factor(ot->srna, "value", 0, -10.0f, 10.0f, "Factor", "", -1.0f, 1.0f);
|
||||||
|
|
||||||
@@ -868,7 +916,7 @@ static void TRANSFORM_OT_edge_slide(struct wmOperatorType *ot)
|
|||||||
RNA_def_boolean(ot->srna, "use_clamp", true, "Clamp",
|
RNA_def_boolean(ot->srna, "use_clamp", true, "Clamp",
|
||||||
"Clamp within the edge extents");
|
"Clamp within the edge extents");
|
||||||
|
|
||||||
Transform_Properties(ot, P_MIRROR | P_SNAP | P_CORRECT_UV);
|
Transform_Properties(ot, P_MIRROR | P_SNAP | P_CORRECT_UV | P_CLNOR_INVALIDATE);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void TRANSFORM_OT_vert_slide(struct wmOperatorType *ot)
|
static void TRANSFORM_OT_vert_slide(struct wmOperatorType *ot)
|
||||||
@@ -885,6 +933,7 @@ static void TRANSFORM_OT_vert_slide(struct wmOperatorType *ot)
|
|||||||
ot->modal = transform_modal;
|
ot->modal = transform_modal;
|
||||||
ot->cancel = transform_cancel;
|
ot->cancel = transform_cancel;
|
||||||
ot->poll = ED_operator_editmesh_region_view3d;
|
ot->poll = ED_operator_editmesh_region_view3d;
|
||||||
|
ot->ui = transform_ui;
|
||||||
|
|
||||||
RNA_def_float_factor(ot->srna, "value", 0, -10.0f, 10.0f, "Factor", "", -1.0f, 1.0f);
|
RNA_def_float_factor(ot->srna, "value", 0, -10.0f, 10.0f, "Factor", "", -1.0f, 1.0f);
|
||||||
RNA_def_boolean(ot->srna, "use_even", false, "Even",
|
RNA_def_boolean(ot->srna, "use_even", false, "Even",
|
||||||
@@ -894,7 +943,7 @@ static void TRANSFORM_OT_vert_slide(struct wmOperatorType *ot)
|
|||||||
RNA_def_boolean(ot->srna, "use_clamp", true, "Clamp",
|
RNA_def_boolean(ot->srna, "use_clamp", true, "Clamp",
|
||||||
"Clamp within the edge extents");
|
"Clamp within the edge extents");
|
||||||
|
|
||||||
Transform_Properties(ot, P_MIRROR | P_SNAP | P_CORRECT_UV);
|
Transform_Properties(ot, P_MIRROR | P_SNAP | P_CORRECT_UV | P_CLNOR_INVALIDATE);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void TRANSFORM_OT_edge_crease(struct wmOperatorType *ot)
|
static void TRANSFORM_OT_edge_crease(struct wmOperatorType *ot)
|
||||||
@@ -911,6 +960,7 @@ static void TRANSFORM_OT_edge_crease(struct wmOperatorType *ot)
|
|||||||
ot->modal = transform_modal;
|
ot->modal = transform_modal;
|
||||||
ot->cancel = transform_cancel;
|
ot->cancel = transform_cancel;
|
||||||
ot->poll = ED_operator_editmesh;
|
ot->poll = ED_operator_editmesh;
|
||||||
|
ot->ui = transform_ui;
|
||||||
|
|
||||||
RNA_def_float_factor(ot->srna, "value", 0, -1.0f, 1.0f, "Factor", "", -1.0f, 1.0f);
|
RNA_def_float_factor(ot->srna, "value", 0, -1.0f, 1.0f, "Factor", "", -1.0f, 1.0f);
|
||||||
|
|
||||||
@@ -952,6 +1002,7 @@ static void TRANSFORM_OT_edge_bevelweight(struct wmOperatorType *ot)
|
|||||||
ot->modal = transform_modal;
|
ot->modal = transform_modal;
|
||||||
ot->cancel = transform_cancel;
|
ot->cancel = transform_cancel;
|
||||||
ot->poll = ED_operator_editmesh;
|
ot->poll = ED_operator_editmesh;
|
||||||
|
ot->ui = transform_ui;
|
||||||
|
|
||||||
RNA_def_float_factor(ot->srna, "value", 0, -1.0f, 1.0f, "Factor", "", -1.0f, 1.0f);
|
RNA_def_float_factor(ot->srna, "value", 0, -1.0f, 1.0f, "Factor", "", -1.0f, 1.0f);
|
||||||
|
|
||||||
@@ -972,12 +1023,34 @@ static void TRANSFORM_OT_seq_slide(struct wmOperatorType *ot)
|
|||||||
ot->modal = transform_modal;
|
ot->modal = transform_modal;
|
||||||
ot->cancel = transform_cancel;
|
ot->cancel = transform_cancel;
|
||||||
ot->poll = ED_operator_sequencer_active;
|
ot->poll = ED_operator_sequencer_active;
|
||||||
|
ot->ui = transform_ui;
|
||||||
|
|
||||||
RNA_def_float_vector_xyz(ot->srna, "value", 2, NULL, -FLT_MAX, FLT_MAX, "Vector", "", -FLT_MAX, FLT_MAX);
|
RNA_def_float_vector_xyz(ot->srna, "value", 2, NULL, -FLT_MAX, FLT_MAX, "Vector", "", -FLT_MAX, FLT_MAX);
|
||||||
|
|
||||||
Transform_Properties(ot, P_SNAP);
|
Transform_Properties(ot, P_SNAP);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void TRANSFORM_OT_rotate_normal(struct wmOperatorType *ot)
|
||||||
|
{
|
||||||
|
/* identifiers */
|
||||||
|
ot->name = "Normal Rotate";
|
||||||
|
ot->description = "Rotate split normal of selected items";
|
||||||
|
ot->idname = OP_NORMAL_ROTATION;
|
||||||
|
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING;
|
||||||
|
|
||||||
|
/* api callbacks */
|
||||||
|
ot->invoke = transform_invoke;
|
||||||
|
ot->exec = transform_exec;
|
||||||
|
ot->modal = transform_modal;
|
||||||
|
ot->cancel = transform_cancel;
|
||||||
|
ot->poll = ED_operator_editmesh_auto_smooth;
|
||||||
|
ot->ui = transform_ui;
|
||||||
|
|
||||||
|
RNA_def_float_rotation(ot->srna, "value", 0, NULL, -FLT_MAX, FLT_MAX, "Angle", "", -M_PI * 2, M_PI * 2);
|
||||||
|
|
||||||
|
Transform_Properties(ot, P_AXIS | P_CONSTRAINT | P_MIRROR);
|
||||||
|
}
|
||||||
|
|
||||||
static void TRANSFORM_OT_transform(struct wmOperatorType *ot)
|
static void TRANSFORM_OT_transform(struct wmOperatorType *ot)
|
||||||
{
|
{
|
||||||
PropertyRNA *prop;
|
PropertyRNA *prop;
|
||||||
@@ -994,6 +1067,7 @@ static void TRANSFORM_OT_transform(struct wmOperatorType *ot)
|
|||||||
ot->modal = transform_modal;
|
ot->modal = transform_modal;
|
||||||
ot->cancel = transform_cancel;
|
ot->cancel = transform_cancel;
|
||||||
ot->poll = ED_operator_screenactive;
|
ot->poll = ED_operator_screenactive;
|
||||||
|
ot->ui = transform_ui;
|
||||||
|
|
||||||
prop = RNA_def_enum(ot->srna, "mode", rna_enum_transform_mode_types, TFM_TRANSLATION, "Mode", "");
|
prop = RNA_def_enum(ot->srna, "mode", rna_enum_transform_mode_types, TFM_TRANSLATION, "Mode", "");
|
||||||
RNA_def_property_flag(prop, PROP_HIDDEN);
|
RNA_def_property_flag(prop, PROP_HIDDEN);
|
||||||
|
@@ -87,6 +87,7 @@ typedef enum ModifierType {
|
|||||||
eModifierType_CorrectiveSmooth = 51,
|
eModifierType_CorrectiveSmooth = 51,
|
||||||
eModifierType_MeshSequenceCache = 52,
|
eModifierType_MeshSequenceCache = 52,
|
||||||
eModifierType_SurfaceDeform = 53,
|
eModifierType_SurfaceDeform = 53,
|
||||||
|
eModifierType_WeightedNormal = 54,
|
||||||
NUM_MODIFIER_TYPES
|
NUM_MODIFIER_TYPES
|
||||||
} ModifierType;
|
} ModifierType;
|
||||||
|
|
||||||
@@ -1619,6 +1620,32 @@ enum {
|
|||||||
MOD_SDEF_MODE_CENTROID = 2,
|
MOD_SDEF_MODE_CENTROID = 2,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef struct WeightedNormalModifierData {
|
||||||
|
ModifierData modifier;
|
||||||
|
|
||||||
|
char defgrp_name[64]; /* MAX_VGROUP_NAME */
|
||||||
|
char mode, flag;
|
||||||
|
short weight;
|
||||||
|
float thresh;
|
||||||
|
} WeightedNormalModifierData;
|
||||||
|
|
||||||
|
/* Name/id of the generic PROP_INT cdlayer storing face weights. */
|
||||||
|
#define MOD_WEIGHTEDNORMALS_FACEWEIGHT_CDLAYER_ID "__mod_weightednormals_faceweight"
|
||||||
|
|
||||||
|
/* WeightedNormalModifierData.mode */
|
||||||
|
enum {
|
||||||
|
MOD_WEIGHTEDNORMAL_MODE_FACE = 0,
|
||||||
|
MOD_WEIGHTEDNORMAL_MODE_ANGLE = 1,
|
||||||
|
MOD_WEIGHTEDNORMAL_MODE_FACE_ANGLE = 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* WeightedNormalModifierData.flag */
|
||||||
|
enum {
|
||||||
|
MOD_WEIGHTEDNORMAL_KEEP_SHARP = (1 << 0),
|
||||||
|
MOD_WEIGHTEDNORMAL_INVERT_VGROUP = (1 << 1),
|
||||||
|
MOD_WEIGHTEDNORMAL_FACE_INFLUENCE = (1 << 2),
|
||||||
|
};
|
||||||
|
|
||||||
#define MOD_MESHSEQ_READ_ALL \
|
#define MOD_MESHSEQ_READ_ALL \
|
||||||
(MOD_MESHSEQ_READ_VERT | MOD_MESHSEQ_READ_POLY | MOD_MESHSEQ_READ_UV | MOD_MESHSEQ_READ_COLOR)
|
(MOD_MESHSEQ_READ_VERT | MOD_MESHSEQ_READ_POLY | MOD_MESHSEQ_READ_UV | MOD_MESHSEQ_READ_COLOR)
|
||||||
|
|
||||||
|
@@ -1579,6 +1579,10 @@ typedef struct ToolSettings {
|
|||||||
struct CurvePaintSettings curve_paint_settings;
|
struct CurvePaintSettings curve_paint_settings;
|
||||||
|
|
||||||
struct MeshStatVis statvis;
|
struct MeshStatVis statvis;
|
||||||
|
|
||||||
|
/* Normal Editing */
|
||||||
|
float normal_vector[3];
|
||||||
|
int face_strength;
|
||||||
} ToolSettings;
|
} ToolSettings;
|
||||||
|
|
||||||
/* *************************************************************** */
|
/* *************************************************************** */
|
||||||
@@ -2042,6 +2046,13 @@ enum {
|
|||||||
OB_DRAW_GROUPUSER_ALL = 2
|
OB_DRAW_GROUPUSER_ALL = 2
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* toolsettings->face_strength */
|
||||||
|
enum {
|
||||||
|
FACE_STRENGTH_WEAK = -16384,
|
||||||
|
FACE_STRENGTH_MEDIUM = 0,
|
||||||
|
FACE_STRENGTH_STRONG = 16384,
|
||||||
|
};
|
||||||
|
|
||||||
/* object_vgroup.c */
|
/* object_vgroup.c */
|
||||||
/* ToolSettings.vgroupsubset */
|
/* ToolSettings.vgroupsubset */
|
||||||
typedef enum eVGroupSelect {
|
typedef enum eVGroupSelect {
|
||||||
|
@@ -697,6 +697,7 @@ extern StructRNA RNA_WaveModifier;
|
|||||||
extern StructRNA RNA_VertexWeightEditModifier;
|
extern StructRNA RNA_VertexWeightEditModifier;
|
||||||
extern StructRNA RNA_VertexWeightMixModifier;
|
extern StructRNA RNA_VertexWeightMixModifier;
|
||||||
extern StructRNA RNA_VertexWeightProximityModifier;
|
extern StructRNA RNA_VertexWeightProximityModifier;
|
||||||
|
extern StructRNA RNA_WeightedNormalModifier;
|
||||||
extern StructRNA RNA_Window;
|
extern StructRNA RNA_Window;
|
||||||
extern StructRNA RNA_WindowManager;
|
extern StructRNA RNA_WindowManager;
|
||||||
extern StructRNA RNA_WipeSequence;
|
extern StructRNA RNA_WipeSequence;
|
||||||
|
@@ -68,6 +68,7 @@ const EnumPropertyItem rna_enum_object_modifier_type_items[] = {
|
|||||||
{eModifierType_MeshCache, "MESH_CACHE", ICON_MOD_MESHDEFORM, "Mesh Cache", ""},
|
{eModifierType_MeshCache, "MESH_CACHE", ICON_MOD_MESHDEFORM, "Mesh Cache", ""},
|
||||||
{eModifierType_MeshSequenceCache, "MESH_SEQUENCE_CACHE", ICON_MOD_MESHDEFORM, "Mesh Sequence Cache", ""},
|
{eModifierType_MeshSequenceCache, "MESH_SEQUENCE_CACHE", ICON_MOD_MESHDEFORM, "Mesh Sequence Cache", ""},
|
||||||
{eModifierType_NormalEdit, "NORMAL_EDIT", ICON_MOD_NORMALEDIT, "Normal Edit", ""},
|
{eModifierType_NormalEdit, "NORMAL_EDIT", ICON_MOD_NORMALEDIT, "Normal Edit", ""},
|
||||||
|
{eModifierType_WeightedNormal, "WEIGHTED_NORMAL", ICON_MOD_NORMALEDIT, "Weighted Normal", ""},
|
||||||
{eModifierType_UVProject, "UV_PROJECT", ICON_MOD_UVPROJECT, "UV Project", ""},
|
{eModifierType_UVProject, "UV_PROJECT", ICON_MOD_UVPROJECT, "UV Project", ""},
|
||||||
{eModifierType_UVWarp, "UV_WARP", ICON_MOD_UVPROJECT, "UV Warp", ""},
|
{eModifierType_UVWarp, "UV_WARP", ICON_MOD_UVPROJECT, "UV Warp", ""},
|
||||||
{eModifierType_WeightVGEdit, "VERTEX_WEIGHT_EDIT", ICON_MOD_VERTEX_WEIGHT, "Vertex Weight Edit", ""},
|
{eModifierType_WeightVGEdit, "VERTEX_WEIGHT_EDIT", ICON_MOD_VERTEX_WEIGHT, "Vertex Weight Edit", ""},
|
||||||
@@ -411,6 +412,8 @@ static StructRNA *rna_Modifier_refine(struct PointerRNA *ptr)
|
|||||||
return &RNA_MeshSequenceCacheModifier;
|
return &RNA_MeshSequenceCacheModifier;
|
||||||
case eModifierType_SurfaceDeform:
|
case eModifierType_SurfaceDeform:
|
||||||
return &RNA_SurfaceDeformModifier;
|
return &RNA_SurfaceDeformModifier;
|
||||||
|
case eModifierType_WeightedNormal:
|
||||||
|
return &RNA_WeightedNormalModifier;
|
||||||
/* Default */
|
/* Default */
|
||||||
case eModifierType_None:
|
case eModifierType_None:
|
||||||
case eModifierType_ShapeKey:
|
case eModifierType_ShapeKey:
|
||||||
@@ -501,6 +504,7 @@ RNA_MOD_VGROUP_NAME_SET(WeightVGMix, defgrp_name_b);
|
|||||||
RNA_MOD_VGROUP_NAME_SET(WeightVGMix, mask_defgrp_name);
|
RNA_MOD_VGROUP_NAME_SET(WeightVGMix, mask_defgrp_name);
|
||||||
RNA_MOD_VGROUP_NAME_SET(WeightVGProximity, defgrp_name);
|
RNA_MOD_VGROUP_NAME_SET(WeightVGProximity, defgrp_name);
|
||||||
RNA_MOD_VGROUP_NAME_SET(WeightVGProximity, mask_defgrp_name);
|
RNA_MOD_VGROUP_NAME_SET(WeightVGProximity, mask_defgrp_name);
|
||||||
|
RNA_MOD_VGROUP_NAME_SET(WeightedNormal, defgrp_name);
|
||||||
RNA_MOD_VGROUP_NAME_SET(Wireframe, defgrp_name);
|
RNA_MOD_VGROUP_NAME_SET(Wireframe, defgrp_name);
|
||||||
|
|
||||||
static void rna_ExplodeModifier_vgroup_get(PointerRNA *ptr, char *value)
|
static void rna_ExplodeModifier_vgroup_get(PointerRNA *ptr, char *value)
|
||||||
@@ -4809,6 +4813,68 @@ static void rna_def_modifier_surfacedeform(BlenderRNA *brna)
|
|||||||
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
|
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void rna_def_modifier_weightednormal(BlenderRNA *brna)
|
||||||
|
{
|
||||||
|
StructRNA *srna;
|
||||||
|
PropertyRNA *prop;
|
||||||
|
|
||||||
|
static EnumPropertyItem prop_weighting_mode_items[] = {
|
||||||
|
{MOD_WEIGHTEDNORMAL_MODE_FACE, "FACE_AREA", 0, "Face Area", "Generate face area weighted normals"},
|
||||||
|
{MOD_WEIGHTEDNORMAL_MODE_ANGLE, "CORNER_ANGLE", 0, "Corner Angle", "Generate corner angle weighted normals"},
|
||||||
|
{MOD_WEIGHTEDNORMAL_MODE_FACE_ANGLE, "FACE_AREA_WITH_ANGLE", 0, "Face Area And Angle",
|
||||||
|
"Generated normals weighted by both face area and angle"},
|
||||||
|
{0, NULL, 0, NULL, NULL}
|
||||||
|
};
|
||||||
|
|
||||||
|
srna = RNA_def_struct(brna, "WeightedNormalModifier", "Modifier");
|
||||||
|
RNA_def_struct_ui_text(srna, "WeightedNormal Modifier", "");
|
||||||
|
RNA_def_struct_sdna(srna, "WeightedNormalModifierData");
|
||||||
|
RNA_def_struct_ui_icon(srna, ICON_MOD_NORMALEDIT);
|
||||||
|
|
||||||
|
prop = RNA_def_property(srna, "weight", PROP_INT, PROP_NONE);
|
||||||
|
RNA_def_property_range(prop, 1, 100);
|
||||||
|
RNA_def_property_ui_range(prop, 1, 100, 1, -1);
|
||||||
|
RNA_def_property_ui_text(prop, "Weight",
|
||||||
|
"Corrective factor applied to faces' weights, 50 is neutral, "
|
||||||
|
"lower values increase weight of weak faces, "
|
||||||
|
"higher values increase weight of strong faces");
|
||||||
|
RNA_def_property_update(prop, 0, "rna_Modifier_update");
|
||||||
|
|
||||||
|
prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE);
|
||||||
|
RNA_def_property_enum_items(prop, prop_weighting_mode_items);
|
||||||
|
RNA_def_property_ui_text(prop, "Weighting Mode", "Weighted vertex normal mode to use");
|
||||||
|
RNA_def_property_update(prop, 0, "rna_Modifier_update");
|
||||||
|
|
||||||
|
prop = RNA_def_property(srna, "thresh", PROP_FLOAT, PROP_NONE);
|
||||||
|
RNA_def_property_range(prop, 0, 10);
|
||||||
|
RNA_def_property_ui_range(prop, 0, 10, 1, 2);
|
||||||
|
RNA_def_property_ui_text(prop, "Threshold", "Threshold value for different weights to be considered equal");
|
||||||
|
RNA_def_property_update(prop, 0, "rna_Modifier_update");
|
||||||
|
|
||||||
|
prop = RNA_def_property(srna, "keep_sharp", PROP_BOOLEAN, PROP_NONE);
|
||||||
|
RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_WEIGHTEDNORMAL_KEEP_SHARP);
|
||||||
|
RNA_def_property_ui_text(prop, "Keep Sharp",
|
||||||
|
"Keep sharp edges as computed for default split normals, "
|
||||||
|
"instead of setting a single weighted normal for each vertex.");
|
||||||
|
RNA_def_property_update(prop, 0, "rna_Modifier_update");
|
||||||
|
|
||||||
|
prop = RNA_def_property(srna, "vertex_group", PROP_STRING, PROP_NONE);
|
||||||
|
RNA_def_property_string_sdna(prop, NULL, "defgrp_name");
|
||||||
|
RNA_def_property_ui_text(prop, "Vertex Group", "Vertex group name for modifying the selected areas");
|
||||||
|
RNA_def_property_string_funcs(prop, NULL, NULL, "rna_WeightedNormalModifier_defgrp_name_set");
|
||||||
|
RNA_def_property_update(prop, 0, "rna_Modifier_update");
|
||||||
|
|
||||||
|
prop = RNA_def_property(srna, "invert_vertex_group", PROP_BOOLEAN, PROP_NONE);
|
||||||
|
RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_WEIGHTEDNORMAL_INVERT_VGROUP);
|
||||||
|
RNA_def_property_ui_text(prop, "Invert", "Invert vertex group influence");
|
||||||
|
RNA_def_property_update(prop, 0, "rna_Modifier_update");
|
||||||
|
|
||||||
|
prop = RNA_def_property(srna, "face_influence", PROP_BOOLEAN, PROP_NONE);
|
||||||
|
RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_WEIGHTEDNORMAL_FACE_INFLUENCE);
|
||||||
|
RNA_def_property_ui_text(prop, "Face Influence", "Use influence of face for weighting");
|
||||||
|
RNA_def_property_update(prop, 0, "rna_Modifier_update");
|
||||||
|
}
|
||||||
|
|
||||||
void RNA_def_modifier(BlenderRNA *brna)
|
void RNA_def_modifier(BlenderRNA *brna)
|
||||||
{
|
{
|
||||||
StructRNA *srna;
|
StructRNA *srna;
|
||||||
@@ -4927,6 +4993,7 @@ void RNA_def_modifier(BlenderRNA *brna)
|
|||||||
rna_def_modifier_normaledit(brna);
|
rna_def_modifier_normaledit(brna);
|
||||||
rna_def_modifier_meshseqcache(brna);
|
rna_def_modifier_meshseqcache(brna);
|
||||||
rna_def_modifier_surfacedeform(brna);
|
rna_def_modifier_surfacedeform(brna);
|
||||||
|
rna_def_modifier_weightednormal(brna);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@@ -2502,6 +2502,13 @@ static void rna_def_tool_settings(BlenderRNA *brna)
|
|||||||
{0, NULL, 0, NULL, NULL}
|
{0, NULL, 0, NULL, NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static EnumPropertyItem mod_weighted_strength[] = {
|
||||||
|
{FACE_STRENGTH_WEAK, "Weak", 0, "Weak", ""},
|
||||||
|
{FACE_STRENGTH_MEDIUM, "Medium", 0, "Medium", ""},
|
||||||
|
{FACE_STRENGTH_STRONG, "Strong", 0, "Strong", ""},
|
||||||
|
{0, NULL, 0, NULL, NULL},
|
||||||
|
};
|
||||||
|
|
||||||
static const EnumPropertyItem draw_groupuser_items[] = {
|
static const EnumPropertyItem draw_groupuser_items[] = {
|
||||||
{OB_DRAW_GROUPUSER_NONE, "NONE", 0, "None", ""},
|
{OB_DRAW_GROUPUSER_NONE, "NONE", 0, "None", ""},
|
||||||
{OB_DRAW_GROUPUSER_ACTIVE, "ACTIVE", 0, "Active", "Show vertices with no weights in the active group"},
|
{OB_DRAW_GROUPUSER_ACTIVE, "ACTIVE", 0, "Active", "Show vertices with no weights in the active group"},
|
||||||
@@ -2890,6 +2897,14 @@ static void rna_def_tool_settings(BlenderRNA *brna)
|
|||||||
RNA_def_property_boolean_sdna(prop, NULL, "edge_mode_live_unwrap", 1);
|
RNA_def_property_boolean_sdna(prop, NULL, "edge_mode_live_unwrap", 1);
|
||||||
RNA_def_property_ui_text(prop, "Live Unwrap", "Changing edges seam re-calculates UV unwrap");
|
RNA_def_property_ui_text(prop, "Live Unwrap", "Changing edges seam re-calculates UV unwrap");
|
||||||
|
|
||||||
|
prop = RNA_def_property(srna, "normal_vector", PROP_FLOAT, PROP_XYZ);
|
||||||
|
RNA_def_property_ui_text(prop, "Normal Vector", "Normal Vector used to copy, add or multiply");
|
||||||
|
RNA_def_property_ui_range(prop, -10000.0, 10000.0, 1, 3);
|
||||||
|
|
||||||
|
prop = RNA_def_property(srna, "face_strength", PROP_ENUM, PROP_NONE);
|
||||||
|
RNA_def_property_enum_items(prop, mod_weighted_strength);
|
||||||
|
RNA_def_property_ui_text(prop, "Face Strength", "Set strength of face to specified value");
|
||||||
|
|
||||||
/* etch-a-ton */
|
/* etch-a-ton */
|
||||||
prop = RNA_def_property(srna, "use_bone_sketching", PROP_BOOLEAN, PROP_NONE);
|
prop = RNA_def_property(srna, "use_bone_sketching", PROP_BOOLEAN, PROP_NONE);
|
||||||
RNA_def_property_boolean_sdna(prop, NULL, "bone_sketching", BONE_SKETCHING);
|
RNA_def_property_boolean_sdna(prop, NULL, "bone_sketching", BONE_SKETCHING);
|
||||||
|
@@ -100,6 +100,7 @@ set(SRC
|
|||||||
intern/MOD_uvproject.c
|
intern/MOD_uvproject.c
|
||||||
intern/MOD_warp.c
|
intern/MOD_warp.c
|
||||||
intern/MOD_wave.c
|
intern/MOD_wave.c
|
||||||
|
intern/MOD_weighted_normal.c
|
||||||
intern/MOD_weightvg_util.c
|
intern/MOD_weightvg_util.c
|
||||||
intern/MOD_weightvgedit.c
|
intern/MOD_weightvgedit.c
|
||||||
intern/MOD_weightvgmix.c
|
intern/MOD_weightvgmix.c
|
||||||
|
@@ -86,6 +86,7 @@ extern ModifierTypeInfo modifierType_NormalEdit;
|
|||||||
extern ModifierTypeInfo modifierType_CorrectiveSmooth;
|
extern ModifierTypeInfo modifierType_CorrectiveSmooth;
|
||||||
extern ModifierTypeInfo modifierType_MeshSequenceCache;
|
extern ModifierTypeInfo modifierType_MeshSequenceCache;
|
||||||
extern ModifierTypeInfo modifierType_SurfaceDeform;
|
extern ModifierTypeInfo modifierType_SurfaceDeform;
|
||||||
|
extern ModifierTypeInfo modifierType_WeightedNormal;
|
||||||
|
|
||||||
/* MOD_util.c */
|
/* MOD_util.c */
|
||||||
void modifier_type_init(ModifierTypeInfo *types[]);
|
void modifier_type_init(ModifierTypeInfo *types[]);
|
||||||
|
@@ -288,5 +288,6 @@ void modifier_type_init(ModifierTypeInfo *types[])
|
|||||||
INIT_TYPE(CorrectiveSmooth);
|
INIT_TYPE(CorrectiveSmooth);
|
||||||
INIT_TYPE(MeshSequenceCache);
|
INIT_TYPE(MeshSequenceCache);
|
||||||
INIT_TYPE(SurfaceDeform);
|
INIT_TYPE(SurfaceDeform);
|
||||||
|
INIT_TYPE(WeightedNormal);
|
||||||
#undef INIT_TYPE
|
#undef INIT_TYPE
|
||||||
}
|
}
|
||||||
|
657
source/blender/modifiers/intern/MOD_weighted_normal.c
Normal file
657
source/blender/modifiers/intern/MOD_weighted_normal.c
Normal file
@@ -0,0 +1,657 @@
|
|||||||
|
/*
|
||||||
|
* ***** BEGIN GPL LICENSE BLOCK *****
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
* ***** END GPL LICENSE BLOCK *****
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** \file blender/modifiers/intern/MOD_weighted_normal.c
|
||||||
|
* \ingroup modifiers
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "MEM_guardedalloc.h"
|
||||||
|
|
||||||
|
#include "DNA_mesh_types.h"
|
||||||
|
#include "DNA_object_types.h"
|
||||||
|
#include "DNA_scene_types.h"
|
||||||
|
|
||||||
|
#include "BKE_cdderivedmesh.h"
|
||||||
|
#include "BKE_deform.h"
|
||||||
|
#include "BKE_mesh.h"
|
||||||
|
|
||||||
|
#include "BLI_math.h"
|
||||||
|
#include "BLI_linklist.h"
|
||||||
|
|
||||||
|
#include "MOD_modifiertypes.h"
|
||||||
|
#include "MOD_util.h"
|
||||||
|
|
||||||
|
#define CLNORS_VALID_VEC_LEN (1e-6f)
|
||||||
|
|
||||||
|
typedef struct ModePair {
|
||||||
|
float val; /* Contains mode based value (face area / corner angle). */
|
||||||
|
int index; /* Index value per poly or per loop. */
|
||||||
|
} ModePair;
|
||||||
|
|
||||||
|
/* Sorting function used in modifier, sorts in decreasing order. */
|
||||||
|
static int modepair_cmp_by_val_inverse(const void *p1, const void *p2)
|
||||||
|
{
|
||||||
|
ModePair *r1 = (ModePair *)p1;
|
||||||
|
ModePair *r2 = (ModePair *)p2;
|
||||||
|
|
||||||
|
return (r1->val < r2->val) ? 1 : ((r1->val > r2->val) ? -1 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* There will be one of those per vertex (simple case, computing one normal per vertex), or per smooth fan. */
|
||||||
|
typedef struct WeightedNormalDataAggregateItem {
|
||||||
|
float normal[3];
|
||||||
|
|
||||||
|
int num_loops; /* Count number of loops using this item so far. */
|
||||||
|
float curr_val; /* Current max val for this item. */
|
||||||
|
int curr_strength; /* Current max strength encountered for this item. */
|
||||||
|
} WeightedNormalDataAggregateItem;
|
||||||
|
|
||||||
|
#define NUM_CACHED_INVERSE_POWERS_OF_WEIGHT 128
|
||||||
|
|
||||||
|
typedef struct WeightedNormalData {
|
||||||
|
const int numVerts;
|
||||||
|
const int numEdges;
|
||||||
|
const int numLoops;
|
||||||
|
const int numPolys;
|
||||||
|
|
||||||
|
MVert *mvert;
|
||||||
|
MEdge *medge;
|
||||||
|
|
||||||
|
MLoop *mloop;
|
||||||
|
short (*clnors)[2];
|
||||||
|
const bool has_clnors; /* True if clnors already existed, false if we had to create them. */
|
||||||
|
const float split_angle;
|
||||||
|
|
||||||
|
MPoly *mpoly;
|
||||||
|
float (*polynors)[3];
|
||||||
|
int *poly_strength;
|
||||||
|
|
||||||
|
MDeformVert *dvert;
|
||||||
|
const int defgrp_index;
|
||||||
|
const bool use_invert_vgroup;
|
||||||
|
|
||||||
|
const float weight;
|
||||||
|
const short mode;
|
||||||
|
|
||||||
|
/* Lower-level, internal processing data. */
|
||||||
|
float cached_inverse_powers_of_weight[NUM_CACHED_INVERSE_POWERS_OF_WEIGHT];
|
||||||
|
|
||||||
|
WeightedNormalDataAggregateItem *items_data;
|
||||||
|
|
||||||
|
ModePair *mode_pair;
|
||||||
|
|
||||||
|
int *loop_to_poly;
|
||||||
|
} WeightedNormalData;
|
||||||
|
|
||||||
|
/* Check strength of given poly compared to those found so far for that given item (vertex or smooth fan),
|
||||||
|
* and reset matching item_data in case we get a stronger new strength. */
|
||||||
|
static bool check_item_poly_strength(
|
||||||
|
WeightedNormalData *wn_data, WeightedNormalDataAggregateItem *item_data, const int mp_index)
|
||||||
|
{
|
||||||
|
BLI_assert (wn_data->poly_strength != NULL);
|
||||||
|
|
||||||
|
const int mp_strength = wn_data->poly_strength[mp_index];
|
||||||
|
|
||||||
|
if (mp_strength > item_data->curr_strength) {
|
||||||
|
item_data->curr_strength = mp_strength;
|
||||||
|
item_data->curr_val = 0.0f;
|
||||||
|
item_data->num_loops = 0;
|
||||||
|
zero_v3(item_data->normal);
|
||||||
|
}
|
||||||
|
|
||||||
|
return mp_strength == item_data->curr_strength;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void aggregate_item_normal(
|
||||||
|
WeightedNormalModifierData *wnmd, WeightedNormalData *wn_data,
|
||||||
|
WeightedNormalDataAggregateItem *item_data,
|
||||||
|
const int mv_index, const int mp_index,
|
||||||
|
const float curr_val, const bool use_face_influence)
|
||||||
|
{
|
||||||
|
float (*polynors)[3] = wn_data->polynors;
|
||||||
|
|
||||||
|
MDeformVert *dvert = wn_data->dvert;
|
||||||
|
const int defgrp_index = wn_data->defgrp_index;
|
||||||
|
const bool use_invert_vgroup = wn_data->use_invert_vgroup;
|
||||||
|
|
||||||
|
const float weight = wn_data->weight;
|
||||||
|
|
||||||
|
float *cached_inverse_powers_of_weight = wn_data->cached_inverse_powers_of_weight;
|
||||||
|
|
||||||
|
const bool has_vgroup = dvert != NULL;
|
||||||
|
const bool vert_of_group = has_vgroup && defvert_find_index(&dvert[mv_index], defgrp_index) != NULL;
|
||||||
|
|
||||||
|
if (has_vgroup && ((vert_of_group && use_invert_vgroup) || (!vert_of_group && !use_invert_vgroup))) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (use_face_influence && !check_item_poly_strength(wn_data, item_data, mp_index)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If item's curr_val is 0 init it to present value. */
|
||||||
|
if (item_data->curr_val == 0.0f) {
|
||||||
|
item_data->curr_val = curr_val;
|
||||||
|
}
|
||||||
|
if (!compare_ff(item_data->curr_val, curr_val, wnmd->thresh)) {
|
||||||
|
/* item's curr_val and present value differ more than threshold, update. */
|
||||||
|
item_data->num_loops++;
|
||||||
|
item_data->curr_val = curr_val;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Exponentially divided weight for each normal (since a few values will be used by most cases, we cache those). */
|
||||||
|
const int num_loops = item_data->num_loops;
|
||||||
|
if (num_loops < NUM_CACHED_INVERSE_POWERS_OF_WEIGHT && cached_inverse_powers_of_weight[num_loops] == 0.0f) {
|
||||||
|
cached_inverse_powers_of_weight[num_loops] = 1.0f / powf(weight, num_loops);
|
||||||
|
}
|
||||||
|
const float inverted_n_weight = num_loops < NUM_CACHED_INVERSE_POWERS_OF_WEIGHT ?
|
||||||
|
cached_inverse_powers_of_weight[num_loops] : 1.0f / powf(weight, num_loops);
|
||||||
|
|
||||||
|
madd_v3_v3fl(item_data->normal, polynors[mp_index], curr_val * inverted_n_weight);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void apply_weights_vertex_normal(WeightedNormalModifierData *wnmd, WeightedNormalData *wn_data)
|
||||||
|
{
|
||||||
|
const int numVerts = wn_data->numVerts;
|
||||||
|
const int numEdges = wn_data->numEdges;
|
||||||
|
const int numLoops = wn_data->numLoops;
|
||||||
|
const int numPolys = wn_data->numPolys;
|
||||||
|
|
||||||
|
MVert *mvert = wn_data->mvert;
|
||||||
|
MEdge *medge = wn_data->medge;
|
||||||
|
|
||||||
|
MLoop *mloop = wn_data->mloop;
|
||||||
|
short (*clnors)[2] = wn_data->clnors;
|
||||||
|
int *loop_to_poly = wn_data->loop_to_poly;
|
||||||
|
|
||||||
|
MPoly *mpoly = wn_data->mpoly;
|
||||||
|
float (*polynors)[3] = wn_data->polynors;
|
||||||
|
int *poly_strength = wn_data->poly_strength;
|
||||||
|
|
||||||
|
MDeformVert *dvert = wn_data->dvert;
|
||||||
|
|
||||||
|
const short mode = wn_data->mode;
|
||||||
|
ModePair *mode_pair = wn_data->mode_pair;
|
||||||
|
|
||||||
|
const bool has_clnors = wn_data->has_clnors;
|
||||||
|
const float split_angle = wn_data->split_angle;
|
||||||
|
MLoopNorSpaceArray lnors_spacearr = {NULL};
|
||||||
|
|
||||||
|
const bool keep_sharp = (wnmd->flag & MOD_WEIGHTEDNORMAL_KEEP_SHARP) != 0;
|
||||||
|
const bool use_face_influence = (wnmd->flag & MOD_WEIGHTEDNORMAL_FACE_INFLUENCE) != 0 && poly_strength != NULL;
|
||||||
|
const bool has_vgroup = dvert != NULL;
|
||||||
|
|
||||||
|
float (*loop_normals)[3] = NULL;
|
||||||
|
|
||||||
|
WeightedNormalDataAggregateItem *items_data = NULL;
|
||||||
|
int num_items = 0;
|
||||||
|
if (keep_sharp) {
|
||||||
|
BLI_bitmap *done_loops = BLI_BITMAP_NEW(numLoops, __func__);
|
||||||
|
|
||||||
|
/* This will give us loop normal spaces, we do not actually care about computed loop_normals for now... */
|
||||||
|
loop_normals = MEM_calloc_arrayN((size_t)numLoops, sizeof(*loop_normals), __func__);
|
||||||
|
BKE_mesh_normals_loop_split(mvert, numVerts, medge, numEdges,
|
||||||
|
mloop, loop_normals, numLoops, mpoly, polynors, numPolys,
|
||||||
|
true, split_angle, &lnors_spacearr, has_clnors ? clnors : NULL, loop_to_poly);
|
||||||
|
|
||||||
|
num_items = lnors_spacearr.num_spaces;
|
||||||
|
items_data = MEM_calloc_arrayN((size_t)num_items, sizeof(*items_data), __func__);
|
||||||
|
|
||||||
|
/* In this first loop, we assign each WeightedNormalDataAggregateItem to its smooth fan of loops (aka lnor space). */
|
||||||
|
MPoly *mp;
|
||||||
|
int mp_index;
|
||||||
|
int item_index;
|
||||||
|
for (mp = mpoly, mp_index = 0, item_index = 0; mp_index < numPolys; mp++, mp_index++) {
|
||||||
|
int ml_index = mp->loopstart;
|
||||||
|
const int ml_end_index = ml_index + mp->totloop;
|
||||||
|
|
||||||
|
for (; ml_index < ml_end_index; ml_index++) {
|
||||||
|
if (BLI_BITMAP_TEST(done_loops, ml_index)) {
|
||||||
|
/* Smooth fan of this loop has already been processed, skip it. */
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
BLI_assert(item_index < num_items);
|
||||||
|
|
||||||
|
WeightedNormalDataAggregateItem *itdt = &items_data[item_index];
|
||||||
|
itdt->curr_strength = FACE_STRENGTH_WEAK;
|
||||||
|
|
||||||
|
MLoopNorSpace *lnor_space = lnors_spacearr.lspacearr[ml_index];
|
||||||
|
lnor_space->user_data = itdt;
|
||||||
|
|
||||||
|
if (!(lnor_space->flags & MLNOR_SPACE_IS_SINGLE)) {
|
||||||
|
for (LinkNode *lnode = lnor_space->loops; lnode; lnode = lnode->next) {
|
||||||
|
const int ml_fan_index = GET_INT_FROM_POINTER(lnode->link);
|
||||||
|
BLI_BITMAP_ENABLE(done_loops, ml_fan_index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
BLI_BITMAP_ENABLE(done_loops, ml_index);
|
||||||
|
}
|
||||||
|
|
||||||
|
item_index++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MEM_freeN(done_loops);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
num_items = numVerts;
|
||||||
|
items_data = MEM_calloc_arrayN((size_t)num_items, sizeof(*items_data), __func__);
|
||||||
|
if (use_face_influence) {
|
||||||
|
for (int item_index = 0; item_index < num_items; item_index++) {
|
||||||
|
items_data[item_index].curr_strength = FACE_STRENGTH_WEAK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
wn_data->items_data = items_data;
|
||||||
|
|
||||||
|
switch (mode) {
|
||||||
|
case MOD_WEIGHTEDNORMAL_MODE_FACE:
|
||||||
|
for (int i = 0; i < numPolys; i++) {
|
||||||
|
const int mp_index = mode_pair[i].index;
|
||||||
|
const float mp_val = mode_pair[i].val;
|
||||||
|
|
||||||
|
int ml_index = mpoly[mp_index].loopstart;
|
||||||
|
const int ml_index_end = ml_index + mpoly[mp_index].totloop;
|
||||||
|
for (; ml_index < ml_index_end; ml_index++) {
|
||||||
|
const int mv_index = mloop[ml_index].v;
|
||||||
|
WeightedNormalDataAggregateItem *item_data = keep_sharp ?
|
||||||
|
lnors_spacearr.lspacearr[ml_index]->user_data:
|
||||||
|
&items_data[mv_index];
|
||||||
|
|
||||||
|
aggregate_item_normal(wnmd, wn_data, item_data, mv_index, mp_index, mp_val, use_face_influence);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case MOD_WEIGHTEDNORMAL_MODE_ANGLE:
|
||||||
|
case MOD_WEIGHTEDNORMAL_MODE_FACE_ANGLE:
|
||||||
|
BLI_assert(loop_to_poly != NULL);
|
||||||
|
|
||||||
|
for (int i = 0; i < numLoops; i++) {
|
||||||
|
const int ml_index = mode_pair[i].index;
|
||||||
|
const float ml_val = mode_pair[i].val;
|
||||||
|
|
||||||
|
const int mp_index = loop_to_poly[ml_index];
|
||||||
|
const int mv_index = mloop[ml_index].v;
|
||||||
|
WeightedNormalDataAggregateItem *item_data = keep_sharp ?
|
||||||
|
lnors_spacearr.lspacearr[ml_index]->user_data:
|
||||||
|
&items_data[mv_index];
|
||||||
|
|
||||||
|
aggregate_item_normal(wnmd, wn_data, item_data, mv_index, mp_index, ml_val, use_face_influence);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
BLI_assert(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Validate computed weighted normals. */
|
||||||
|
for (int item_index = 0; item_index < num_items; item_index++) {
|
||||||
|
if (normalize_v3(items_data[item_index].normal) < CLNORS_VALID_VEC_LEN) {
|
||||||
|
zero_v3(items_data[item_index].normal);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (keep_sharp) {
|
||||||
|
/* Set loop normals for normal computed for each lnor space (smooth fan).
|
||||||
|
* Note that loop_normals is already populated with clnors (before this modifier is applied, at start of
|
||||||
|
* this function), so no need to recompute them here. */
|
||||||
|
for (int ml_index = 0; ml_index < numLoops; ml_index++) {
|
||||||
|
WeightedNormalDataAggregateItem *item_data = lnors_spacearr.lspacearr[ml_index]->user_data;
|
||||||
|
if (!is_zero_v3(item_data->normal)) {
|
||||||
|
copy_v3_v3(loop_normals[ml_index], item_data->normal);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BKE_mesh_normals_loop_custom_set(mvert, numVerts, medge, numEdges,
|
||||||
|
mloop, loop_normals, numLoops, mpoly, polynors, numPolys, clnors);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* TODO: Ideally, we could add an option to BKE_mesh_normals_loop_custom_[from_vertices_]set() to keep current
|
||||||
|
* clnors instead of resetting them to default autocomputed ones, when given new custom normal is zero-vec.
|
||||||
|
* But this is not exactly trivial change, better to keep this optimization for later...
|
||||||
|
*/
|
||||||
|
if (!has_vgroup) {
|
||||||
|
/* Note: in theory, we could avoid this extra allocation & copying... But think we can live with it for now,
|
||||||
|
* and it makes code simpler & cleaner. */
|
||||||
|
float (*vert_normals)[3] = MEM_calloc_arrayN((size_t)numVerts, sizeof(*loop_normals), __func__);
|
||||||
|
|
||||||
|
for (int ml_index = 0; ml_index < numLoops; ml_index++) {
|
||||||
|
const int mv_index = mloop[ml_index].v;
|
||||||
|
copy_v3_v3(vert_normals[mv_index], items_data[mv_index].normal);
|
||||||
|
}
|
||||||
|
|
||||||
|
BKE_mesh_normals_loop_custom_from_vertices_set(mvert, vert_normals, numVerts, medge, numEdges,
|
||||||
|
mloop, numLoops, mpoly, polynors, numPolys, clnors);
|
||||||
|
|
||||||
|
MEM_freeN(vert_normals);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
loop_normals = MEM_calloc_arrayN((size_t)numLoops, sizeof(*loop_normals), __func__);
|
||||||
|
|
||||||
|
BKE_mesh_normals_loop_split(mvert, numVerts, medge, numEdges,
|
||||||
|
mloop, loop_normals, numLoops, mpoly, polynors, numPolys,
|
||||||
|
true, split_angle, NULL, has_clnors ? clnors : NULL, loop_to_poly);
|
||||||
|
|
||||||
|
for (int ml_index = 0; ml_index < numLoops; ml_index++) {
|
||||||
|
const int item_index = mloop[ml_index].v;
|
||||||
|
if (!is_zero_v3(items_data[item_index].normal)) {
|
||||||
|
copy_v3_v3(loop_normals[ml_index], items_data[item_index].normal);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BKE_mesh_normals_loop_custom_set(mvert, numVerts, medge, numEdges,
|
||||||
|
mloop, loop_normals, numLoops, mpoly, polynors, numPolys, clnors);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (keep_sharp) {
|
||||||
|
BKE_lnor_spacearr_free(&lnors_spacearr);
|
||||||
|
}
|
||||||
|
MEM_SAFE_FREE(loop_normals);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void wn_face_area(WeightedNormalModifierData *wnmd, WeightedNormalData *wn_data)
|
||||||
|
{
|
||||||
|
const int numPolys = wn_data->numPolys;
|
||||||
|
|
||||||
|
MVert *mvert = wn_data->mvert;
|
||||||
|
MLoop *mloop = wn_data->mloop;
|
||||||
|
MPoly *mpoly = wn_data->mpoly;
|
||||||
|
|
||||||
|
MPoly *mp;
|
||||||
|
int mp_index;
|
||||||
|
|
||||||
|
ModePair *face_area = MEM_malloc_arrayN((size_t)numPolys, sizeof(*face_area), __func__);
|
||||||
|
|
||||||
|
ModePair *f_area = face_area;
|
||||||
|
for (mp_index = 0, mp = mpoly; mp_index < numPolys; mp_index++, mp++, f_area++) {
|
||||||
|
f_area->val = BKE_mesh_calc_poly_area(mp, &mloop[mp->loopstart], mvert);
|
||||||
|
f_area->index = mp_index;
|
||||||
|
}
|
||||||
|
|
||||||
|
qsort(face_area, numPolys, sizeof(*face_area), modepair_cmp_by_val_inverse);
|
||||||
|
|
||||||
|
wn_data->mode_pair = face_area;
|
||||||
|
apply_weights_vertex_normal(wnmd, wn_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void wn_corner_angle(WeightedNormalModifierData *wnmd, WeightedNormalData *wn_data)
|
||||||
|
{
|
||||||
|
const int numLoops = wn_data->numLoops;
|
||||||
|
const int numPolys = wn_data->numPolys;
|
||||||
|
|
||||||
|
MVert *mvert = wn_data->mvert;
|
||||||
|
MLoop *mloop = wn_data->mloop;
|
||||||
|
MPoly *mpoly = wn_data->mpoly;
|
||||||
|
|
||||||
|
MPoly *mp;
|
||||||
|
int mp_index;
|
||||||
|
|
||||||
|
int *loop_to_poly = MEM_malloc_arrayN((size_t)numLoops, sizeof(*loop_to_poly), __func__);
|
||||||
|
|
||||||
|
ModePair *corner_angle = MEM_malloc_arrayN((size_t)numLoops, sizeof(*corner_angle), __func__);
|
||||||
|
|
||||||
|
for (mp_index = 0, mp = mpoly; mp_index < numPolys; mp_index++, mp++) {
|
||||||
|
MLoop *ml_start = &mloop[mp->loopstart];
|
||||||
|
|
||||||
|
float *index_angle = MEM_malloc_arrayN((size_t)mp->totloop, sizeof(*index_angle), __func__);
|
||||||
|
BKE_mesh_calc_poly_angles(mp, ml_start, mvert, index_angle);
|
||||||
|
|
||||||
|
ModePair *c_angl = &corner_angle[mp->loopstart];
|
||||||
|
float *angl = index_angle;
|
||||||
|
for (int ml_index = mp->loopstart; ml_index < mp->loopstart + mp->totloop; ml_index++, c_angl++, angl++) {
|
||||||
|
c_angl->val = (float)M_PI - *angl;
|
||||||
|
c_angl->index = ml_index;
|
||||||
|
|
||||||
|
loop_to_poly[ml_index] = mp_index;
|
||||||
|
}
|
||||||
|
MEM_freeN(index_angle);
|
||||||
|
}
|
||||||
|
|
||||||
|
qsort(corner_angle, numLoops, sizeof(*corner_angle), modepair_cmp_by_val_inverse);
|
||||||
|
|
||||||
|
wn_data->loop_to_poly = loop_to_poly;
|
||||||
|
wn_data->mode_pair = corner_angle;
|
||||||
|
apply_weights_vertex_normal(wnmd, wn_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void wn_face_with_angle(WeightedNormalModifierData *wnmd, WeightedNormalData *wn_data)
|
||||||
|
{
|
||||||
|
const int numLoops = wn_data->numLoops;
|
||||||
|
const int numPolys = wn_data->numPolys;
|
||||||
|
|
||||||
|
MVert *mvert = wn_data->mvert;
|
||||||
|
MLoop *mloop = wn_data->mloop;
|
||||||
|
MPoly *mpoly = wn_data->mpoly;
|
||||||
|
|
||||||
|
MPoly *mp;
|
||||||
|
int mp_index;
|
||||||
|
|
||||||
|
int *loop_to_poly = MEM_malloc_arrayN((size_t)numLoops, sizeof(*loop_to_poly), __func__);
|
||||||
|
|
||||||
|
ModePair *combined = MEM_malloc_arrayN((size_t)numLoops, sizeof(*combined), __func__);
|
||||||
|
|
||||||
|
for (mp_index = 0, mp = mpoly; mp_index < numPolys; mp_index++, mp++) {
|
||||||
|
MLoop *ml_start = &mloop[mp->loopstart];
|
||||||
|
|
||||||
|
float face_area = BKE_mesh_calc_poly_area(mp, ml_start, mvert);
|
||||||
|
float *index_angle = MEM_malloc_arrayN((size_t)mp->totloop, sizeof(*index_angle), __func__);
|
||||||
|
BKE_mesh_calc_poly_angles(mp, ml_start, mvert, index_angle);
|
||||||
|
|
||||||
|
ModePair *cmbnd = &combined[mp->loopstart];
|
||||||
|
float *angl = index_angle;
|
||||||
|
for (int ml_index = mp->loopstart; ml_index < mp->loopstart + mp->totloop; ml_index++, cmbnd++, angl++) {
|
||||||
|
/* In this case val is product of corner angle and face area. */
|
||||||
|
cmbnd->val = ((float)M_PI - *angl) * face_area;
|
||||||
|
cmbnd->index = ml_index;
|
||||||
|
|
||||||
|
loop_to_poly[ml_index] = mp_index;
|
||||||
|
}
|
||||||
|
MEM_freeN(index_angle);
|
||||||
|
}
|
||||||
|
|
||||||
|
qsort(combined, numLoops, sizeof(*combined), modepair_cmp_by_val_inverse);
|
||||||
|
|
||||||
|
wn_data->loop_to_poly = loop_to_poly;
|
||||||
|
wn_data->mode_pair = combined;
|
||||||
|
apply_weights_vertex_normal(wnmd, wn_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static DerivedMesh *applyModifier(ModifierData *md, Object *ob, DerivedMesh *dm, ModifierApplyFlag UNUSED(flag))
|
||||||
|
{
|
||||||
|
WeightedNormalModifierData *wnmd = (WeightedNormalModifierData *)md;
|
||||||
|
|
||||||
|
Mesh *me = ob->data;
|
||||||
|
|
||||||
|
if (!(me->flag & ME_AUTOSMOOTH)) {
|
||||||
|
modifier_setError((ModifierData *)wnmd, "Enable 'Auto Smooth' option in mesh settings");
|
||||||
|
return dm;
|
||||||
|
}
|
||||||
|
|
||||||
|
const int numVerts = dm->getNumVerts(dm);
|
||||||
|
const int numEdges = dm->getNumEdges(dm);
|
||||||
|
const int numLoops = dm->getNumLoops(dm);
|
||||||
|
const int numPolys = dm->getNumPolys(dm);
|
||||||
|
|
||||||
|
MEdge *medge = dm->getEdgeArray(dm);
|
||||||
|
if (me->medge == medge) {
|
||||||
|
/* We need to duplicate data here, otherwise setting custom normals (which may also affect sharp edges) could
|
||||||
|
* modify org mesh. */
|
||||||
|
dm = CDDM_copy(dm);
|
||||||
|
medge = dm->getEdgeArray(dm);
|
||||||
|
}
|
||||||
|
MPoly *mpoly = dm->getPolyArray(dm);
|
||||||
|
MVert *mvert = dm->getVertArray(dm);
|
||||||
|
MLoop *mloop = dm->getLoopArray(dm);
|
||||||
|
|
||||||
|
bool free_polynors = false;
|
||||||
|
|
||||||
|
/* Right now:
|
||||||
|
* If weight = 50 then all faces are given equal weight.
|
||||||
|
* If weight > 50 then more weight given to faces with larger vals (face area / corner angle).
|
||||||
|
* If weight < 50 then more weight given to faces with lesser vals. However current calculation
|
||||||
|
* does not converge to min/max.
|
||||||
|
*/
|
||||||
|
float weight = ((float)wnmd->weight) / 50.0f;
|
||||||
|
if (wnmd->weight == 100) {
|
||||||
|
weight = (float)SHRT_MAX;
|
||||||
|
}
|
||||||
|
else if (wnmd->weight == 1) {
|
||||||
|
weight = 1 / (float)SHRT_MAX;
|
||||||
|
}
|
||||||
|
else if ((weight - 1) * 25 > 1) {
|
||||||
|
weight = (weight - 1) * 25;
|
||||||
|
}
|
||||||
|
|
||||||
|
float (*polynors)[3] = dm->getPolyDataArray(dm, CD_NORMAL);
|
||||||
|
if (!polynors) {
|
||||||
|
polynors = MEM_malloc_arrayN((size_t)numPolys, sizeof(*polynors), __func__);
|
||||||
|
BKE_mesh_calc_normals_poly(mvert, NULL, numVerts, mloop, mpoly, numLoops, numPolys, polynors, false);
|
||||||
|
free_polynors = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const float split_angle = me->smoothresh;
|
||||||
|
short (*clnors)[2];
|
||||||
|
clnors = CustomData_duplicate_referenced_layer(&dm->loopData, CD_CUSTOMLOOPNORMAL, numLoops);
|
||||||
|
/* Keep info whether we had clnors, it helps when generating clnor spaces and default normals. */
|
||||||
|
const bool has_clnors = clnors != NULL;
|
||||||
|
if (!clnors) {
|
||||||
|
DM_add_loop_layer(dm, CD_CUSTOMLOOPNORMAL, CD_CALLOC, NULL);
|
||||||
|
clnors = dm->getLoopDataArray(dm, CD_CUSTOMLOOPNORMAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
MDeformVert *dvert;
|
||||||
|
int defgrp_index;
|
||||||
|
modifier_get_vgroup(ob, dm, wnmd->defgrp_name, &dvert, &defgrp_index);
|
||||||
|
|
||||||
|
WeightedNormalData wn_data = {
|
||||||
|
.numVerts = numVerts,
|
||||||
|
.numEdges = numEdges,
|
||||||
|
.numLoops = numLoops,
|
||||||
|
.numPolys = numPolys,
|
||||||
|
|
||||||
|
.mvert = mvert,
|
||||||
|
.medge = medge,
|
||||||
|
|
||||||
|
.mloop = mloop,
|
||||||
|
.clnors = clnors,
|
||||||
|
.has_clnors = has_clnors,
|
||||||
|
.split_angle = split_angle,
|
||||||
|
|
||||||
|
.mpoly = mpoly,
|
||||||
|
.polynors = polynors,
|
||||||
|
.poly_strength = CustomData_get_layer_named(&dm->polyData, CD_PROP_INT, MOD_WEIGHTEDNORMALS_FACEWEIGHT_CDLAYER_ID),
|
||||||
|
|
||||||
|
.dvert = dvert,
|
||||||
|
.defgrp_index = defgrp_index,
|
||||||
|
.use_invert_vgroup = (wnmd->flag & MOD_WEIGHTEDNORMAL_INVERT_VGROUP) != 0,
|
||||||
|
|
||||||
|
.weight = weight,
|
||||||
|
.mode = wnmd->mode,
|
||||||
|
};
|
||||||
|
|
||||||
|
switch (wnmd->mode) {
|
||||||
|
case MOD_WEIGHTEDNORMAL_MODE_FACE:
|
||||||
|
wn_face_area(wnmd, &wn_data);
|
||||||
|
break;
|
||||||
|
case MOD_WEIGHTEDNORMAL_MODE_ANGLE:
|
||||||
|
wn_corner_angle(wnmd, &wn_data);
|
||||||
|
break;
|
||||||
|
case MOD_WEIGHTEDNORMAL_MODE_FACE_ANGLE:
|
||||||
|
wn_face_with_angle(wnmd, &wn_data);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (free_polynors) {
|
||||||
|
MEM_freeN(polynors);
|
||||||
|
}
|
||||||
|
|
||||||
|
MEM_SAFE_FREE(wn_data.loop_to_poly);
|
||||||
|
MEM_SAFE_FREE(wn_data.mode_pair);
|
||||||
|
MEM_SAFE_FREE(wn_data.items_data);
|
||||||
|
|
||||||
|
return dm;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void copyData(ModifierData *md, ModifierData *target)
|
||||||
|
{
|
||||||
|
modifier_copyData_generic(md, target);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void initData(ModifierData *md)
|
||||||
|
{
|
||||||
|
WeightedNormalModifierData *wnmd = (WeightedNormalModifierData *)md;
|
||||||
|
wnmd->mode = MOD_WEIGHTEDNORMAL_MODE_FACE;
|
||||||
|
wnmd->weight = 50;
|
||||||
|
wnmd->thresh = 1e-2f;
|
||||||
|
wnmd->flag = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *md)
|
||||||
|
{
|
||||||
|
WeightedNormalModifierData *wnmd = (WeightedNormalModifierData *)md;
|
||||||
|
CustomDataMask dataMask = CD_CUSTOMLOOPNORMAL;
|
||||||
|
|
||||||
|
if (wnmd->defgrp_name[0]) {
|
||||||
|
dataMask |= CD_MASK_MDEFORMVERT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wnmd->flag & MOD_WEIGHTEDNORMAL_FACE_INFLUENCE) {
|
||||||
|
dataMask |= CD_MASK_PROP_INT;
|
||||||
|
}
|
||||||
|
|
||||||
|
return dataMask;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool dependsOnNormals(ModifierData *UNUSED(md))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
ModifierTypeInfo modifierType_WeightedNormal = {
|
||||||
|
/* name */ "Weighted Normal",
|
||||||
|
/* structName */ "WeightedNormalModifierData",
|
||||||
|
/* structSize */ sizeof(WeightedNormalModifierData),
|
||||||
|
/* type */ eModifierTypeType_Constructive,
|
||||||
|
/* flags */ eModifierTypeFlag_AcceptsMesh |
|
||||||
|
eModifierTypeFlag_SupportsMapping |
|
||||||
|
eModifierTypeFlag_SupportsEditmode |
|
||||||
|
eModifierTypeFlag_EnableInEditmode,
|
||||||
|
|
||||||
|
/* copyData */ copyData,
|
||||||
|
/* deformVerts */ NULL,
|
||||||
|
/* deformMatrices */ NULL,
|
||||||
|
/* deformVertsEM */ NULL,
|
||||||
|
/* deformMatricesEM */ NULL,
|
||||||
|
/* applyModifier */ applyModifier,
|
||||||
|
/* applyModifierEM */ NULL,
|
||||||
|
/* initData */ initData,
|
||||||
|
/* requiredDataMask */ requiredDataMask,
|
||||||
|
/* freeData */ NULL,
|
||||||
|
/* isDisabled */ NULL,
|
||||||
|
/* updateDepgraph */ NULL,
|
||||||
|
/* updateDepsgraph */ NULL,
|
||||||
|
/* dependsOnTime */ NULL,
|
||||||
|
/* dependsOnNormals */ dependsOnNormals,
|
||||||
|
/* foreachObjectLink */ NULL,
|
||||||
|
/* foreachIDLink */ NULL,
|
||||||
|
/* foreachTexLink */ NULL,
|
||||||
|
};
|
Submodule source/tools updated: 7695e14cfc...88a1758d2d
Reference in New Issue
Block a user