1
1

Compare commits

...

60 Commits

Author SHA1 Message Date
Sebastian Witt
b8a14f04af Fixed inverse tube bug. Minor normal issue remains. 2017-09-02 17:39:25 +02:00
Sebastian Witt
f428554df4 Fixed a really hard to find crasher bug and a lot of mesh issues! 2017-08-29 16:51:29 +02:00
Sebastian Witt
0c24cb542d Added clamping to input settings. 2017-08-29 15:35:50 +02:00
Sebastian Witt
c3bd1c8414 Mini fixes. Catch some cornercases that shouldn't happen. 2017-08-29 15:21:52 +02:00
Sebastian Witt
c982e62128 Fixed a crasher, mutex was missing initialisation. 2017-08-28 17:34:34 +02:00
Sebastian Witt
f729653f5d Possibly fixed a big portion of the ring missalignments and uncomplete rings. 2017-08-25 12:18:53 +02:00
Sebastian Witt
5f6c7a9eb6 Fixed some normal orientation issues. B-Ring normals are now aligned A-ring still needs normal alignment. 2017-08-25 10:28:25 +02:00
Sebastian Witt
6d86842dd3 Mayor rework of the edgering system. Unified code, bugfixes.
A lot of bugs still remain.
2017-08-24 17:10:47 +02:00
Sebastian Witt
e27bacaa43 Fix mini crasher, last commit before mayor rework of the edgering detection/sort. 2017-08-22 18:03:51 +02:00
Sebastian Witt
5e1d75247d Fix holes bug in fillets. 2017-08-22 11:13:17 +02:00
Sebastian Witt
a25577433c Compiler pointer arithmetic fix. 2017-08-20 16:49:44 +02:00
Sebastian Witt
664936777b Fix compiler error on win. (Arithmetic on void pointer) 2017-08-20 12:22:04 +02:00
Sebastian Witt
b77d3ecb5c Added subtract mode. "Clipping brush" 2017-08-19 11:07:40 +02:00
Sebastian Witt
30d32fa602 Fillets now get generated. Almost feature complete. 2017-08-19 00:35:53 +02:00
Sebastian Witt
b0b1101716 Improved triangulation, working on ring assignments. 2017-08-18 16:31:22 +02:00
Sebastian Witt
d0cb5c8fd9 Added first triangulation to generate the fillets. Still needs ring order and assignment though. 2017-08-17 16:39:47 +02:00
Sebastian Witt
30aea5e13e Most data is now exposed to be used for final transitions/fillets.
Exact point order can be improved since some are discarded. (todo)
2017-08-16 14:07:42 +02:00
Sebastian Witt
4c567c578a Fixing flooding bug, partial fix. Found BB related flood cause. Realloc fix. 2017-08-15 12:52:00 +02:00
Sebastian Witt
fa86bbb054 Inner vertices now get calculated as well as edgerings. Problem with holes in the edgerings. 2017-08-15 09:58:30 +02:00
Sebastian Witt
3ab49cae0e First version calculating the inside and outside vertices. Needs multiple ring support. Holes from earlier misscalculations break the "floodfill" algorithm. 2017-08-14 13:01:54 +02:00
Sebastian Witt
8ac93b5428 Managed intersection data from multiprocess. Fixed ghash_pop workaround. 2017-08-11 14:14:48 +02:00
Sebastian Witt
72713bddc0 Added Multithreading to the intersection tests. No real performance improvement. Maybe multithreading needs to be relative to the rings, not to the nodes (double nested both?). 2017-08-10 12:29:23 +02:00
Sebastian Witt
779682537e Calculating intersecting edges in the silhouette. (Big performance hit) 2017-08-10 11:06:21 +02:00
Sebastian Witt
781a7f0822 Generating Tri array for later intersection testing. 2017-08-09 13:18:38 +02:00
Sebastian Witt
cba8a0e1c2 Calculate BBs for branches. 2017-08-09 10:57:26 +02:00
Sebastian Witt
3aca62a444 Orthographic projection now fixed as well as wrong stroke boundingbox calculation. Ring calculation might need a different approach. 2017-08-08 16:16:00 +02:00
Sebastian Witt
3566bb561c Added method to remove vertices from basic meshes by remapping the v/e/l/p custom data arrays. 2017-08-07 18:19:50 +02:00
Sebastian Witt
5465a1ee16 Overlapping parts of cross node edgecuts are now calculated. 2017-08-04 15:08:24 +02:00
Sebastian Witt
5062205b2a Merge branch 'master' into soc-2017-sculpting_improvements. Keep the branch up to date. 2017-08-03 18:04:46 +02:00
Sebastian Witt
d684bdd139 Added memory and data to handle intersection rings. Still WIP unstable. 2017-08-03 17:56:44 +02:00
Sebastian Witt
473cea6f0a Added edge border calculation. Cut edge for the part is now being calculated. Added some Macros for dynamic memory allocation. 2017-08-02 11:39:59 +02:00
Sebastian Witt
8fbe4be8a5 Changed Z-Vector calculation to orthographic. Makes more sense the z-vec is orthogonal to the plane the silhouette is placed on.
Added Z intersection test/approximation. Inaccurate with larger smoothing factors.
2017-07-28 14:50:32 +02:00
Sebastian Witt
a09c182b34 Started connecting the silhouette to existing geometry. Intersecting vertices get detected. (define DEBUG_DRAW to see) 2017-07-28 13:02:43 +02:00
Sebastian Witt
c416bfa757 Minor fix, crash on smoothness = 100%. 2017-07-26 15:20:23 +02:00
Sebastian Witt
7c2213c00a Front and backside of the silhouette are now connected. 2017-07-26 13:08:10 +02:00
Sebastian Witt
7e1af56fab Connected T-Intersections, Tubes, Caps front and backside. Now only transitions miss one quad. 2017-07-25 15:16:01 +02:00
Sebastian Witt
774de995f3 Added Backside to the shape. Frontside and backside still need to be connected. 2017-07-24 16:58:38 +02:00
Sebastian Witt
83bc4f9c9e Added Redo. Currently the whole mesh is stored. Partial copy todo. 2017-07-21 16:22:33 +02:00
Sebastian Witt
dfcef67095 Added a new undonode for the silhouette operator.
Bare basics of undo now work, Redo can cause a crash and still needs to be implemented.
Fixed crash when stroke with < 3 points was drawn.
2017-07-21 13:12:24 +02:00
Sebastian Witt
16fca86e92 Correct missing in last commit. 2017-07-20 12:35:39 +02:00
Sebastian Witt
1f63381746 Fixed shape anchor and z-orientation. Added tools to sculpt panel. (smoothness, depth, resolution). 2017-07-20 12:17:24 +02:00
Sebastian Witt
85e280bc43 Added orientation calculation. Normals are now flipped correctly. 2017-07-19 12:32:42 +02:00
Sebastian Witt
78a97b79f8 Bugfix T-Intersection orientation out of order. 2017-07-19 10:58:45 +02:00
Sebastian Witt
8dea4b3d99 Minor Bugfixes, holes in t-intersections and edge offset in smaller intersections fixed. 2017-07-18 16:36:37 +02:00
Sebastian Witt
8611880b86 Bugfix, parts now no longer disappear.
(Division by 0)
2017-07-18 13:11:20 +02:00
Sebastian Witt
fdefef10a3 Minor bugfix, jagged lines on the right side of tubes.
Interpolation needs to be within 0...1
2017-07-18 11:34:38 +02:00
Sebastian Witt
e054e3c87e Parts now get connected. T-Intersections are bugged sometimes. 2017-07-12 16:55:55 +02:00
Sebastian Witt
e8f3165282 Finished T-intersection topology. Next up connecting the parts. 2017-07-11 20:30:55 +02:00
Sebastian Witt
7239c7d4a1 Finished cap geometry. Fixed uneven tube offset. Tubes and Caps now have a unified edge-border structure. 2017-07-11 13:15:54 +02:00
witt
323e34aa28 Reworked most of the vertex/edge/poly/loop generation. Added a unified interpolation method. Vertices are now subsequent so it will be easier to bridge the different parts. Removed dependency on the order of generation. 2017-07-10 18:56:27 +02:00
witt
637a32a3d9 Last commit before mayor rework. Mostly for future reference. 2017-07-06 17:01:34 +02:00
witt
d213d26e3c Minor code cleanup and structuring. Bug fixes! 2017-07-03 16:48:27 +02:00
witt
82835bcaad Progress on generated shape. Lots of smaller bugfixes parts are partially bridged. 2017-06-30 19:40:07 +02:00
witt
e9a6e62d19 Added t-intersections and caps. Next step: bridging the gaps. 2017-06-23 19:51:58 +02:00
witt
e0d8817e05 Added 2D shape topology detection, first silhouette geometry gets created. Use with alt+leftclick within sculpting mode.
--Experimental/Broken--
2017-06-16 22:32:03 +02:00
witt
0a41049893 Merge branch 'master' into soc-2017-sculpting_improvements
Keep the branch updated to make merging it easier later.
2017-06-12 10:12:49 +02:00
witt
ce2671b0e2 Fixed some issues when inserting new meshdata into a pbvh.
Buffers now get reset and primitives are written.
Works for the simplest cornercase: Alt+Leftclick draw on a mesh with one node outside of that node.
2017-06-09 17:27:52 +02:00
witt
15d74e7e51 Silhouette Operator basis setup.
First tests to generate Geometry, failed to integrate into the existing pbvh structure.
Experimental broken code.
2017-06-09 12:05:36 +02:00
witt
5fa1b47494 Small cleanup. Cleared every unconnected changes and fixed some minor ui bugs. 2017-06-01 11:10:03 +02:00
witt
109fc7682b Initial commit on: Adaptive spacing (based on diff by LetterRip see:T50939).
First prototype to calculate spacing distance by measuring distance drawn on surface rather than drawn on screen.
The code is just a prototype, it needs a clean up and further testing.
2017-05-30 16:41:20 +02:00
18 changed files with 5390 additions and 47 deletions

View File

@@ -1441,16 +1441,13 @@ class VIEW3D_PT_tools_brush_stroke(Panel, View3DPaintPanel):
col.separator()
col.prop(brush, "rate", text="Rate", slider=True)
if brush.use_space:
if brush.use_space or brush.use_line or brush.use_curve:
col.separator()
row = col.row(align=True)
row.prop(brush, "spacing", text="Spacing")
row.prop(brush, "use_pressure_spacing", toggle=True, text="")
if brush.use_line or brush.use_curve:
col.separator()
row = col.row(align=True)
row.prop(brush, "spacing", text="Spacing")
col.prop(brush, "use_adaptive_space", text="Adaptive Spacing")
if brush.use_curve:
col.separator()
@@ -1656,6 +1653,33 @@ class VIEW3D_PT_sculpt_symmetry(Panel, View3DPaintPanel):
layout.column().prop(sculpt, "tile_offset", text="Tile Offset")
class VIEW3D_PT_sculpt_silhouette(Panel, View3DPaintPanel):
bl_category = "Tools"
bl_label = "Silhouette"
bl_options = {'DEFAULT_CLOSED'}
@classmethod
def poll(cls, context):
return (context.sculpt_object and context.tool_settings.sculpt)
def draw(self, context):
layout = self.layout
sculpt = context.tool_settings.sculpt
col = layout.column(align=False)
col.label(text="Shape:")
col.prop(sculpt, "silhouette_smoothness", text="Smoothness", slider=True)
col.prop(sculpt, "silhouette_depth", text="Depth")
col.prop(sculpt, "silhouette_resolution", text="Resolution")
sub = col.column()
sub.row().prop(sculpt, "silhouette_add", text="Add")
sub.row().prop(sculpt, "silhouette_subtract", text="Subtract")
col.separator()
class VIEW3D_PT_tools_brush_appearance(Panel, View3DPaintPanel):
bl_category = "Options"
bl_label = "Appearance"
@@ -2056,6 +2080,7 @@ classes = (
VIEW3D_PT_sculpt_dyntopo,
VIEW3D_PT_sculpt_options,
VIEW3D_PT_sculpt_symmetry,
VIEW3D_PT_sculpt_silhouette,
VIEW3D_PT_tools_brush_appearance,
VIEW3D_PT_tools_weightpaint,
VIEW3D_PT_tools_weightpaint_options,

View File

@@ -105,6 +105,7 @@ void BKE_brush_weight_set(const struct Scene *scene, struct Brush *brush, float
int BKE_brush_use_locked_size(const struct Scene *scene, const struct Brush *brush);
int BKE_brush_use_alpha_pressure(const struct Scene *scene, const struct Brush *brush);
int BKE_brush_use_size_pressure(const struct Scene *scene, const struct Brush *brush);
int BKE_brush_use_adaptive_spacing(const struct Brush *brush);
/* scale unprojected radius to reflect a change in the brush's 2D size */
void BKE_brush_scale_unprojected_radius(

View File

@@ -29,6 +29,7 @@
#include "BLI_bitmap.h"
#include "BLI_ghash.h"
#include "BLI_utildefines.h"
#include "DNA_mesh_types.h"
struct CCGElem;
struct CCGKey;
@@ -61,6 +62,8 @@ typedef void (*BKE_pbvh_HitOccludedCallback)(PBVHNode *node, void *data, float *
/* Building */
PBVH *BKE_pbvh_new(void);
void BKE_pbvh_attach_mesh(PBVH *pbvh, PBVHNode *node, Mesh *me, int totprim, float *max_bmin, float *max_bmax);
void BKE_pbvh_build_mesh_complete(PBVH *pbvh, Mesh *me);
void BKE_pbvh_build_mesh(
PBVH *bvh,
const struct MPoly *mpoly, const struct MLoop *mloop,
@@ -71,6 +74,7 @@ void BKE_pbvh_build_grids(PBVH *bvh, struct CCGElem **grid_elems,
struct CCGKey *key, void **gridfaces, struct DMFlagMat *flagmats,
unsigned int **grid_hidden);
void BKE_pbvh_build_bmesh(PBVH *bvh, struct BMesh *bm, bool smooth_shading, struct BMLog *log, const int cd_vert_node_offset, const int cd_face_node_offset);
void BKE_pbvh_build_tmp_bmesh(PBVH *bvh, struct BMesh *bm, bool smooth_shading);
void BKE_pbvh_free(PBVH *bvh);
void BKE_pbvh_free_layer_disp(PBVH *bvh);
@@ -172,6 +176,8 @@ typedef enum {
PBVH_UpdateTopology = 256,
} PBVHNodeFlags;
bool BKE_pbvh_node_is_valid(PBVHNode *node);
bool BKE_pbvh_node_is_leaf(PBVHNode *node);
void BKE_pbvh_node_mark_update(PBVHNode *node);
void BKE_pbvh_node_mark_rebuild_draw(PBVHNode *node);
void BKE_pbvh_node_mark_redraw(PBVHNode *node);
@@ -190,9 +196,15 @@ void BKE_pbvh_node_get_verts(
PBVH *bvh, PBVHNode *node,
const int **r_vert_indices, struct MVert **r_verts);
int BKE_pbvh_recalc_looptri_from_me(PBVH *pbvh, Mesh *me);
PBVHNode *BKE_search_closest_pbvh_leaf_node(PBVH *pbvh, PBVHNode *p_node, float *target_bmin, float *target_bmax);
void BKE_pbvh_node_get_BB(PBVHNode *node, float bb_min[3], float bb_max[3]);
void BKE_pbvh_node_get_original_BB(PBVHNode *node, float bb_min[3], float bb_max[3]);
void BKE_pbvh_node_get_children(PBVH *pbvh, PBVHNode *node, PBVHNode **left, PBVHNode **right);
PBVHNode *BKE_pbvh_node_get_root(PBVH *pbvh);
float BKE_pbvh_node_get_tmin(PBVHNode *node);
/* test if AABB is at least partially inside the planes' volume */
@@ -351,6 +363,8 @@ void BKE_pbvh_node_get_bm_orco_data(
bool BKE_pbvh_node_vert_update_check_any(PBVH *bvh, PBVHNode *node);
void BKE_pbvh_get_node_tris_from_verts(PBVH *bvh, PBVHNode *curr_node, GHash *vert_hash, int **tris, int *r_tot_tris);
void BKE_pbvh_get_tri(PBVH *bvh, const struct MLoopTri **r_tri);
//void BKE_pbvh_node_BB_reset(PBVHNode *node);
//void BKE_pbvh_node_BB_expand(PBVHNode *node, float co[3]);

View File

@@ -94,7 +94,7 @@ static void brush_defaults(Brush *brush)
zero_v3(brush->secondary_rgb);
/* BRUSH STROKE SETTINGS */
brush->flag |= (BRUSH_SPACE | BRUSH_SPACE_ATTEN);
brush->flag |= (BRUSH_SPACE | BRUSH_SPACE_ATTEN | BRUSH_ADAPTIVE_SPACE);
brush->spacing = 10; /* how far each brush dot should be spaced as a percentage of brush diameter */
brush->smooth_stroke_radius = 75;
@@ -104,6 +104,8 @@ static void brush_defaults(Brush *brush)
brush->jitter = 0.0f;
brush->adaptive_space_factor = 1;
/* BRUSH TEXTURE SETTINGS */
BKE_texture_mtex_default(&brush->mtex);
BKE_texture_mtex_default(&brush->mask_mtex);
@@ -844,6 +846,12 @@ int BKE_brush_use_alpha_pressure(const Scene *scene, const Brush *brush)
(brush->flag & BRUSH_ALPHA_PRESSURE);
}
int BKE_brush_use_adaptive_spacing(const Brush *brush)
{
return (brush->flag & BRUSH_ADAPTIVE_SPACE); //FIXME make sure we are in view3D
}
void BKE_brush_unprojected_radius_set(Scene *scene, Brush *brush, float unprojected_radius)
{
UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;

View File

@@ -38,6 +38,7 @@
#include "BKE_global.h"
#include "BKE_mesh.h" /* for BKE_mesh_calc_normals */
#include "BKE_paint.h"
#include "DNA_mesh_types.h"
#include "GPU_buffers.h"
@@ -57,6 +58,9 @@
#define PBVH_THREADED_LIMIT 4
/*TODO: Usefull?*/
#define TRI_ARRAY_GROW 50
typedef struct PBVHStack {
PBVHNode *node;
bool revisiting;
@@ -514,6 +518,93 @@ static void pbvh_build(PBVH *bvh, BB *cb, BBC *prim_bbc, int totprim)
build_sub(bvh, 0, cb, prim_bbc, 0, totprim);
}
/**
* Attach a new mesh to a node of the PBVH
* vertdata etc needs to be already in the basemesh
*/
void BKE_pbvh_attach_mesh(PBVH *pbvh, PBVHNode *node, Mesh *me, int totprim, float *max_bmin, float *max_bmax)
{
BB new_BB;
copy_v3_v3(new_BB.bmin, max_bmin);
copy_v3_v3(new_BB.bmax, max_bmax);
int d_prim = totprim-pbvh->totprim;
/*for (int i = 0; i < pbvh->totprim; i++) {
printf("%i,",pbvh->prim_indices[i]);
}*/
if (me->totvert <= pbvh->leaf_limit) {
pbvh->totvert = me->totvert;
pbvh->totprim = totprim;
MEM_freeN(pbvh->prim_indices);
pbvh->prim_indices = MEM_mallocN(sizeof(int) * pbvh->totprim, "bvh prim indices");
//TODO: parent nodes need to be scaled as well
node->totprim += d_prim;
node->prim_indices = pbvh->prim_indices;
//Fill with all prim to test
for (int i = 0; i < pbvh->totprim; i++) {
pbvh->prim_indices[i] = i;
}
BB_expand_with_bb( &node->vb, &new_BB);
pbvh->verts = me->mvert;
pbvh->mloop = me->mloop;
pbvh->mpoly = me->mpoly;
build_mesh_leaf_node(pbvh, node);
MEM_freeN(node->draw_buffers);
node->draw_buffers = NULL;
BKE_pbvh_node_mark_rebuild_draw(node);
printf("Attached new shape to pbvh.\n");
} else {
//TODO: Attach to multiple nodes.
}
}
void BKE_pbvh_build_mesh_complete(PBVH *pbvh, Mesh *me){
PBVHNode *root;
int looptri_num;
//BKE_pbvh_free(pbvh);
//pbvh = BKE_pbvh_new();
looptri_num = BKE_pbvh_recalc_looptri_from_me(pbvh, me);
BKE_pbvh_build_mesh( pbvh, me->mpoly, me->mloop, me->mvert,
me->totvert, &me->vdata,
pbvh->looptri, looptri_num);
/*pbvh_show_diffuse_color_set(pbvh, false);*/
root = BKE_pbvh_node_get_root(pbvh);
BKE_pbvh_node_mark_rebuild_draw(root);
BKE_pbvh_update( pbvh, root->flag, NULL);
/*if (root->flag & PBVH_RebuildDrawBuffers) {
root->draw_buffers = NULL;
} else if (root->draw_buffers){
MEM_freeN(root->draw_buffers);
root->draw_buffers = NULL;
}
root->draw_buffers = NULL;*/
/*printf("Buffers freed\n");
if (root->flag & PBVH_RebuildDrawBuffers) {
root->draw_buffers = NULL;
} else {
GPU_pbvh_buffers_free(root->draw_buffers);
root->draw_buffers = NULL;
}
BKE_pbvh_node_mark_rebuild_draw(root);
BKE_pbvh_update( pbvh, root->flag, NULL);*/
}
/**
* Do a full rebuild with on Mesh data structure.
*
@@ -1337,6 +1428,16 @@ BMesh *BKE_pbvh_get_bmesh(PBVH *bvh)
/***************************** Node Access ***********************************/
bool BKE_pbvh_node_is_valid(PBVHNode *node)
{
return node->flag; //TODO: check diffrent!
}
bool BKE_pbvh_node_is_leaf(PBVHNode *node)
{
return node->flag & PBVH_Leaf;
}
void BKE_pbvh_node_mark_update(PBVHNode *node)
{
node->flag |= PBVH_UpdateNormals | PBVH_UpdateBB | PBVH_UpdateOriginalBB | PBVH_UpdateDrawBuffers | PBVH_UpdateRedraw;
@@ -1428,6 +1529,112 @@ void BKE_pbvh_node_get_grids(
}
}
static float get_bb_distance_sqr(BB a, BB b)
{
float dist = 0.0f;
for (int i = 0; i < 3; i++) {
if (a.bmin[i] >= b.bmax[i]) {
dist += (b.bmax[i] - a.bmin[i]) * (b.bmax[i] - a.bmin[i]);
} else if (a.bmax[i] < b.bmin[i]) {
dist += (b.bmin[i] - a.bmax[i]) * (b.bmin[i] - a.bmax[i]);
}
}
return dist;
}
int BKE_pbvh_recalc_looptri_from_me(PBVH *pbvh, Mesh *me)
{
if(pbvh->looptri){
MEM_freeN((void*)pbvh->looptri);
}
MLoopTri *looptri = NULL;
int looptri_num = poly_to_tri_count(me->totpoly, me->totloop);
looptri = MEM_mallocN(sizeof(*looptri) * looptri_num, __func__);
BKE_mesh_recalc_looptri(
me->mloop, me->mpoly,
me->mvert,
me->totloop, me->totpoly,
looptri);
/*for (int i = 0; i < looptri_num; i++) {
printf("Tri (%i,%i,%i), Poly %i\n", looptri[i].tri[0], looptri[i].tri[1], looptri[i].tri[2], looptri[i].poly);
}*/
pbvh->looptri = looptri;
return looptri_num;
}
void BKE_pbvh_get_tri(PBVH *bvh, const struct MLoopTri **r_tri)
{
*r_tri = bvh->looptri;
}
void BKE_pbvh_get_node_tris_from_verts(PBVH *bvh, PBVHNode *node, GHash *vert_hash, int **r_tris, int *r_tot_tris)
{
const int *faces = node->prim_indices;
const MLoop *mloop = bvh->mloop;
int totface = node->totprim;
int *tris;
int r_tris_max;
/* Estimated that every vert has roughly two tris in a uniform mesh*/
tris = MEM_callocN(sizeof(int) * BLI_ghash_size(vert_hash) * 2, "tris connected to verts");
r_tris_max = BLI_ghash_size(vert_hash) * 2;
*r_tot_tris = 0;
for (int i = 0; i < totface; i++) {
const MLoopTri lt = bvh->looptri[faces[i]];
/* TODO: Original or not etc?
const int *face_verts = node->face_vert_indices[i];*/
for(int s = 0; s < 3; s++) {
if (BLI_ghash_haskey(vert_hash, SET_INT_IN_POINTER(mloop[lt.tri[s]].v))) {
if (*r_tot_tris >= r_tris_max) {
r_tris_max += TRI_ARRAY_GROW;
tris = MEM_reallocN(tris, sizeof(int) * r_tris_max);
}
tris[*r_tot_tris] = faces[i];
*r_tot_tris += 1;
break;
}
}
}
*r_tris = tris;
}
PBVHNode *BKE_search_closest_pbvh_leaf_node(PBVH *pbvh, PBVHNode *p_node, float *target_bmin, float *target_bmax)
{
BB new_BB;
copy_v3_v3(new_BB.bmin,target_bmin);
copy_v3_v3(new_BB.bmax,target_bmax);
BB_expand_with_bb(&p_node->vb,&new_BB);
if (BKE_pbvh_node_is_leaf(p_node)) {
return p_node;
}
PBVHNode *left = NULL, *right = NULL;
BB bb_left, bb_right, bb_target;
copy_v3_v3(bb_target.bmin,target_bmin);
copy_v3_v3(bb_target.bmax,target_bmax);
BKE_pbvh_node_get_children(pbvh, p_node, &left, &right);
if ((!left && !right)) {
return p_node;
} else if (!left) {
return BKE_search_closest_pbvh_leaf_node(pbvh, right, bb_target.bmin, bb_target.bmax);
} else if (!right) {
return BKE_search_closest_pbvh_leaf_node(pbvh, left, bb_target.bmin, bb_target.bmax);
}
BKE_pbvh_node_get_BB(left, bb_left.bmin, bb_left.bmax);
BKE_pbvh_node_get_BB(right, bb_right.bmin, bb_right.bmax);
if (get_bb_distance_sqr(bb_target,bb_left) > get_bb_distance_sqr(bb_target,bb_right)) {
return BKE_search_closest_pbvh_leaf_node(pbvh, right, bb_target.bmin, bb_target.bmax);
} else {
return BKE_search_closest_pbvh_leaf_node(pbvh, left, bb_target.bmin, bb_target.bmax);
}
}
void BKE_pbvh_node_get_BB(PBVHNode *node, float bb_min[3], float bb_max[3])
{
copy_v3_v3(bb_min, node->vb.bmin);
@@ -1440,6 +1647,17 @@ void BKE_pbvh_node_get_original_BB(PBVHNode *node, float bb_min[3], float bb_max
copy_v3_v3(bb_max, node->orig_vb.bmax);
}
void BKE_pbvh_node_get_children(PBVH *pbvh, PBVHNode *node, PBVHNode **left, PBVHNode **right)
{
*left = pbvh->nodes+node->children_offset;
*right = pbvh->nodes+node->children_offset+1;
}
PBVHNode *BKE_pbvh_node_get_root(PBVH *pbvh)
{
return pbvh->nodes;
}
void BKE_pbvh_node_get_proxies(PBVHNode *node, PBVHProxyNode **proxies, int *proxy_count)
{
if (node->proxy_count > 0) {

View File

@@ -1850,6 +1850,71 @@ void BKE_pbvh_build_bmesh(
MEM_freeN(nodeinfo);
}
/* Build a PBVH from a BMesh */
void BKE_pbvh_build_tmp_bmesh(
PBVH *bvh, BMesh *bm, bool smooth_shading)
{
bvh->cd_vert_node_offset = 0;
bvh->cd_face_node_offset = 0;
bvh->bm = bm;
bvh->type = PBVH_BMESH;
/* TODO: choose leaf limit better */
bvh->leaf_limit = 100;
if (smooth_shading)
bvh->flags |= PBVH_DYNTOPO_SMOOTH_SHADING;
/* bounding box array of all faces, no need to recalculate every time */
BBC *bbc_array = MEM_mallocN(sizeof(BBC) * bm->totface, "BBC");
BMFace **nodeinfo = MEM_mallocN(sizeof(*nodeinfo) * bm->totface, "nodeinfo");
MemArena *arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, "fast PBVH node storage");
BMIter iter;
BMFace *f;
int i;
BM_ITER_MESH_INDEX(f, &iter, bm, BM_FACES_OF_MESH, i) {
BBC *bbc = &bbc_array[i];
BMLoop *l_first = BM_FACE_FIRST_LOOP(f);
BMLoop *l_iter = l_first;
BB_reset((BB *)bbc);
do {
BB_expand((BB *)bbc, l_iter->v->co);
} while ((l_iter = l_iter->next) != l_first);
BBC_update_centroid(bbc);
/* so we can do direct lookups on 'bbc_array' */
BM_elem_index_set(f, i); /* set_dirty! */
nodeinfo[i] = f;
}
/* likely this is already dirty */
bm->elem_index_dirty |= BM_FACE;
/* setup root node */
struct FastNodeBuildInfo rootnode = {0};
rootnode.totface = bm->totface;
/* start recursion, assign faces to nodes accordingly */
pbvh_bmesh_node_limit_ensure_fast(bvh, nodeinfo, bbc_array, &rootnode, arena);
/* we now have all faces assigned to a node, next we need to assign those to the gsets of the nodes */
/* Start with all faces in the root node */
bvh->nodes = MEM_callocN(sizeof(PBVHNode), "PBVHNode");
bvh->totnode = 1;
/* take root node and visit and populate children recursively */
pbvh_bmesh_create_nodes_fast_recursive(bvh, nodeinfo, bbc_array, &rootnode, 0);
BLI_memarena_free(arena);
MEM_freeN(bbc_array);
MEM_freeN(nodeinfo);
}
/* Collapse short edges, subdivide long edges */
bool BKE_pbvh_bmesh_update_topology(
PBVH *bvh, PBVHTopologyUpdateMode mode,

View File

@@ -107,6 +107,10 @@ void BLO_update_defaults_startup_blend(Main *bmain)
sculpt->paint.symmetry_flags |= PAINT_SYMM_X;
sculpt->flags |= SCULPT_DYNTOPO_COLLAPSE;
sculpt->detail_size = 12;
sculpt->silhouette_smoothness = 50.0f;
sculpt->silhouette_depth = 1.0f;
sculpt->silhouette_resolution = 3;
}
if (ts->gp_sculpt.brush[0].size == 0) {

View File

@@ -32,6 +32,7 @@
#ifndef __PAINT_INTERN_H__
#define __PAINT_INTERN_H__
struct ARegion;
struct bContext;
struct Brush;
@@ -76,6 +77,7 @@ bool paint_supports_smooth_stroke(struct Brush *br, enum PaintMode mode);
bool paint_supports_texture(enum PaintMode mode);
bool paint_supports_jitter(enum PaintMode mode);
struct wmKeyMap *paint_stroke_modal_keymap(struct wmKeyConfig *keyconf);
int paint_stroke_modal(struct bContext *C, struct wmOperator *op, const struct wmEvent *event);
int paint_stroke_exec(struct bContext *C, struct wmOperator *op);

View File

@@ -1564,6 +1564,10 @@ void ED_keymap_paint(wmKeyConfig *keyconf)
/* Toggle dynamic topology */
WM_keymap_add_item(keymap, "SCULPT_OT_dynamic_topology_toggle", DKEY, KM_PRESS, KM_CTRL, 0);
/* Draw Silhouette */
RNA_enum_set(WM_keymap_add_item(keymap, "SCULPT_OT_silhouette_draw", LEFTMOUSE, KM_PRESS, KM_ALT, 0)->ptr, "mode", BRUSH_STROKE_NORMAL);
RNA_enum_set(WM_keymap_add_item(keymap, "SCULPT_OT_silhouette_draw", RIGHTMOUSE, KM_PRESS, KM_ALT, 0)->ptr, "mode", BRUSH_STROKE_INVERT);
/* Dynamic-topology detail size
*
* This should be improved further, perhaps by showing a triangle

View File

@@ -66,16 +66,40 @@
#include "IMB_imbuf_types.h"
#include "paint_intern.h"
#include "sculpt_intern.h"
#include <float.h>
#include <math.h>
#include <stdio.h>
//#define DEBUG_TIME
#ifdef DEBUG_TIME
# include "PIL_time_utildefines.h"
#endif
/*Debug spacing calc define DEBUG_DRAW to get info about sampling etc.*/
/*#define DEBUG_DRAW*/
#ifdef DEBUG_DRAW
static void bl_debug_draw(void);
/* add these locally when using these functions for testing */
extern void bl_debug_draw_quad_clear(void);
extern void bl_debug_draw_quad_add(const float v0[3], const float v1[3], const float v2[3], const float v3[3]);
extern void bl_debug_draw_edge_add(const float v0[3], const float v1[3]);
extern void bl_debug_color_set(const unsigned int col);
void bl_debug_draw_point(const float pos[3],const float thickness){
float h = thickness*0.5;
float v1[] = {pos[0]-h,pos[1]-h,pos[2]};
float v2[] = {pos[0]-h,pos[1]+h,pos[2]};
float v3[] = {pos[0]+h,pos[1]-h,pos[2]};
float v4[] = {pos[0]+h,pos[1]+h,pos[2]};
bl_debug_draw_quad_add(v1,v2,v3,v4);
}
#endif
typedef struct PaintSample {
float mouse[2];
float pressure;
@@ -101,8 +125,10 @@ typedef struct PaintStroke {
int cur_sample;
float last_mouse_position[2];
float last_v3_mouse_position[3];
/* space distance covered so far */
float stroke_distance;
float distance_since_last_dab;
/* Set whether any stroke step has yet occurred
* e.g. in sculpt mode, stroke doesn't start until cursor
@@ -444,6 +470,7 @@ static void paint_brush_stroke_add_step(bContext *C, wmOperator *op, const float
* will create too many dabs */
copy_v2_v2(stroke->last_mouse_position, mouse_in);
stroke->last_pressure = pressure;
stroke->distance_since_last_dab = 0.0f;
if (paint_stroke_use_jitter(mode, brush, stroke->stroke_mode == BRUSH_STROKE_INVERT)) {
float delta[2];
@@ -474,6 +501,14 @@ static void paint_brush_stroke_add_step(bContext *C, wmOperator *op, const float
return;
}
#ifdef DEBUG_DRAW
bl_debug_color_set(0x0000FF);
bl_debug_draw_point(ups->last_location,0.05f);
bl_debug_color_set(0x000000);
#endif
copy_v3_v3(stroke->last_v3_mouse_position, location);
/* Add to stroke */
RNA_collection_add(op->ptr, "stroke", &itemptr);
RNA_float_set(&itemptr, "size", ups->pixel_radius);
@@ -516,36 +551,56 @@ static bool paint_smooth_stroke(
return true;
}
static float paint_space_stroke_spacing(const Scene *scene, PaintStroke *stroke, float size_pressure, float spacing_pressure)
static const float MIN_BRUSH_SIZE_PIXELS = 1.0f;
static const float MAGIC_50 = 50.0f;
static const float MAGIC_1_5 = 1.5f;
/* Brush spacing ignoring both pressure and brush angle to the geometry */
static float paint_space_unadjusted_stroke_spacing(const Scene *scene, PaintStroke *stroke) {
const float size_clamp = max_ff(MIN_BRUSH_SIZE_PIXELS, BKE_brush_size_get(scene, stroke->brush));
return max_ff(MIN_BRUSH_SIZE_PIXELS, size_clamp * stroke->brush->spacing / MAGIC_50);
}
static float paint_space_stroke_adaptive_spacing(const Scene *scene, PaintStroke *stroke, float spacing)
{
spacing = spacing * stroke->brush->adaptive_space_factor;
return spacing;
}
static float paint_space_stroke_pressure_spacing(const Scene *scene, PaintStroke *stroke, float size_pressure, float spacing_pressure, float spacing)
{
/* brushes can have a minimum size of 1.0 but with pressure it can be smaller then a pixel
* causing very high step sizes, hanging blender [#32381] */
const float size_clamp = max_ff(1.0f, BKE_brush_size_get(scene, stroke->brush) * size_pressure);
float spacing = stroke->brush->spacing;
//TODO size_clamp should probably be calculated at the start and used throughout
const float size_clamp = max_ff(MIN_BRUSH_SIZE_PIXELS, BKE_brush_size_get(scene, stroke->brush) * size_pressure);
/* apply spacing pressure */
if (stroke->brush->flag & BRUSH_SPACING_PRESSURE)
spacing = spacing * (1.5f - spacing_pressure);
spacing = spacing * (MAGIC_1_5 - spacing_pressure);
//TODO zoom_2d should be seperated out
/* stroke system is used for 2d paint too, so we need to account for
* the fact that brush can be scaled there. */
spacing *= stroke->zoom_2d;
return max_ff(1.0, size_clamp * spacing / 50.0f);
return max_ff(MIN_BRUSH_SIZE_PIXELS, size_clamp * spacing / MAGIC_50);
}
static float paint_stroke_overlapped_curve(Brush *br, float x, float spacing)
{
int i;
const int n = 100 / spacing;
const float h = spacing / 50.0f;
const float x0 = x - 1;
//TODO I think the refactoring and spacing integration elsewhere makes this no longer necessary
//const int n = 100 / ((br->flag&BRUSH_ADAPTIVE_SPACE ? br->adaptive_space_factor : 1.0f) * br->spacing);
const float h = spacing / MAGIC_50;
const float x0 = x - 1.0f;
float sum;
sum = 0;
sum = 0.0f;
for (i = 0; i < n; i++) {
float xx;
@@ -585,32 +640,71 @@ static float paint_stroke_integrate_overlap(Brush *br, float factor)
static float paint_space_stroke_spacing_variable(const Scene *scene, PaintStroke *stroke, float pressure, float dpressure, float length)
{
float spacing = paint_space_unadjusted_stroke_spacing(scene, stroke);
if (BKE_brush_use_adaptive_spacing(stroke->brush)) {
/*adapt the stroke spacing to account for geometry that curves away from the viewport*/
spacing = paint_space_stroke_adaptive_spacing(scene, stroke, spacing);
}
if (BKE_brush_use_size_pressure(scene, stroke->brush)) {
/* use pressure to modify size. set spacing so that at 100%, the circles
* are aligned nicely with no overlap. for this the spacing needs to be
* the average of the previous and next size. */
float s = paint_space_stroke_spacing(scene, stroke, 1.0f, pressure);
float q = s * dpressure / (2.0f * length);
float q = spacing * dpressure / (2.0f * length);
float pressure_fac = (1.0f + q) / (1.0f - q);
float last_size_pressure = stroke->last_pressure;
float new_size_pressure = stroke->last_pressure * pressure_fac;
/* average spacing */
float last_spacing = paint_space_stroke_spacing(scene, stroke, last_size_pressure, pressure);
float new_spacing = paint_space_stroke_spacing(scene, stroke, new_size_pressure, pressure);
float last_spacing = paint_space_stroke_pressure_spacing(scene, stroke, last_size_pressure, pressure, spacing);
float new_spacing = paint_space_stroke_pressure_spacing(scene, stroke, new_size_pressure, pressure, spacing);
spacing = 0.5f * (last_spacing + new_spacing);
return 0.5f * (last_spacing + new_spacing);
}
else {
/* no size pressure */
return paint_space_stroke_spacing(scene, stroke, 1.0f, pressure);
}
return spacing;
}
/* For brushes with stroke spacing enabled, moves mouse in steps
* towards the final mouse location. */
static int paint_space_stroke(bContext *C, wmOperator *op, const float final_mouse[2], float final_pressure)
/* Draw a dab in the sample region.
* sample_point is the end point.
* step_v2 is the vector between first point and the end point.
* draw dabs with spacing interpolated on the line between the two points.
*/
static int draw_spaced_dab(bContext *C, wmOperator *op,const float sample_point[2], float step_v2[2], float dist_last_dab, float spacing, float pressure, float *length_v3){
float draw_pos[2];
float interpol_fact;
float interpol_pos = -dist_last_dab;
int cnt = 0;
while((*length_v3)-interpol_pos >= spacing){
interpol_fact = 1.0f-((interpol_pos+spacing)/(*length_v3));
if(interpol_fact > 0.0f && interpol_fact <= 1.0f){
mul_v2_v2fl(draw_pos,step_v2,-interpol_fact);
add_v2_v2(draw_pos,sample_point);
paint_brush_stroke_add_step(C, op, draw_pos, pressure);
cnt ++;
}else{
/*Cornercase should not happen. TODO: Delete?*/
mul_v2_v2fl(draw_pos,step_v2,-1.0f);
add_v2_v2(draw_pos,sample_point);
paint_brush_stroke_add_step(C, op, draw_pos, pressure);
*length_v3 = 0.0f;
return cnt+1;
}
interpol_pos += spacing;
}
/* transfer remaining space between end point and last dab to the next region*/
*length_v3 -= interpol_pos;
return cnt;
}
/* Calculate spacing in screen space. (distance between last dab in screen space)
* This checks distance to the last dab. Maybe it should be distance drawn on screen?
*/
static int paint_space_stroke_screen_space(bContext *C, wmOperator *op, const float final_mouse[2], float final_pressure)
{
const Scene *scene = CTX_data_scene(C);
PaintStroke *stroke = op->customdata;
@@ -620,7 +714,7 @@ static int paint_space_stroke(bContext *C, wmOperator *op, const float final_mou
float pressure, dpressure;
float mouse[2], dmouse[2];
float length;
float no_pressure_spacing = paint_space_stroke_spacing(scene, stroke, 1.0f, 1.0f);
float no_pressure_spacing = paint_space_unadjusted_stroke_spacing(scene, stroke);
sub_v2_v2v2(dmouse, final_mouse, stroke->last_mouse_position);
@@ -652,6 +746,143 @@ static int paint_space_stroke(bContext *C, wmOperator *op, const float final_mou
break;
}
}
return cnt;
}
/* For brushes with adaptive stroke spacing enabled.
* Calculate spacing in object space. Distance drawn on surface rather than distance drawn on screen.
*/
static int paint_space_stroke_object_space(bContext *C, wmOperator *op, const float final_mouse[2], float final_pressure)
{
const Scene *scene = CTX_data_scene(C);
PaintStroke *stroke = op->customdata;
UnifiedPaintSettings *ups = stroke->ups;
int cnt = 0;
float pressure, dpressure;
float mouse_v3[3], diff_mouse_v3[3];
float length, length_v3;
float no_pressure_spacing = paint_space_unadjusted_stroke_spacing(scene, stroke);
int steps;
float length_v2,step_size;
float diff_path_v2[2], step_pos_v2[2];
float start_step_v3[3], end_step_v3[3];
bool off_mesh = false;
float min_res = 0.1f;
pressure = stroke->last_pressure;
dpressure = final_pressure - stroke->last_pressure;
if(stroke->get_location){
if(!stroke->get_location(C, mouse_v3, final_mouse)){
off_mesh = true;
}
}
sub_v3_v3v3(diff_mouse_v3, mouse_v3, stroke->last_v3_mouse_position);
/* accumulate path or 3d max distance from last dab?
* accumulative version here:
*/
/*length_v3 is the distance between the last samplepoint and the current*/
length_v3 = normalize_v3(diff_mouse_v3);
if(length_v3 > 0.0f){
float spacing = paint_space_stroke_spacing_variable(scene, stroke, pressure, dpressure, stroke->distance_since_last_dab);
/*check if more samplepoints are needed to better approximate the surface.*/
if(length_v3 > min_res){
steps = ceilf(length_v3/min_res);
sub_v2_v2v2(diff_path_v2,final_mouse,stroke->last_mouse_position);
length_v2 = normalize_v2(diff_path_v2);
if(off_mesh){
step_size = 1.0f/min_res;
steps = 10000;/*turns "for" into "while", maybe there is a better way?*/
}else{
step_size = length_v2/steps;
}
length_v3 = 0.0f;
mul_v2_fl(diff_path_v2,step_size);
copy_v3_v3(start_step_v3,stroke->last_v3_mouse_position);
copy_v2_v2(step_pos_v2,stroke->last_mouse_position);
#ifdef DEBUG_DRAW
bl_debug_color_set(0x000000);
#endif
/*split up the current section into smaller parts*/
for(int i = 0; i < steps; i++){
if(i < steps-1){
add_v2_v2(step_pos_v2,diff_path_v2);
if(stroke->get_location){
if(!stroke->get_location(C, end_step_v3, step_pos_v2)){
copy_v2_v2(stroke->last_mouse_position,step_pos_v2);
copy_v3_v3(stroke->last_v3_mouse_position,end_step_v3);
return cnt;
}
}
length_v3 = len_v3v3(end_step_v3,start_step_v3);
#ifdef DEBUG_DRAW
bl_debug_draw_edge_add(end_step_v3,start_step_v3);
#endif
copy_v3_v3(start_step_v3,end_step_v3);
}else{
add_v2_v2(step_pos_v2,diff_path_v2);
length_v3 = len_v3v3(end_step_v3,mouse_v3);
#ifdef DEBUG_DRAW
bl_debug_color_set(0xff0000);
bl_debug_draw_edge_add(end_step_v3,mouse_v3);
#endif
}
/*Dab*/
length = stroke->distance_since_last_dab + length_v3;
if(length >= spacing){
pressure = stroke->last_pressure + (spacing / length) * dpressure;
ups->overlap_factor = paint_stroke_integrate_overlap(stroke->brush, (spacing/stroke->brush->adaptive_space_factor) / no_pressure_spacing);
stroke->stroke_distance += spacing;
cnt += draw_spaced_dab(C, op, step_pos_v2, diff_path_v2, stroke->distance_since_last_dab, spacing, pressure, &length_v3);
stroke->distance_since_last_dab = length_v3;
pressure = stroke->last_pressure;
dpressure = final_pressure - stroke->last_pressure;
}else{
stroke->distance_since_last_dab += length_v3;
}
/*end Dab*/
}
}else{
/*Dab*/
length = stroke->distance_since_last_dab + length_v3;
if(length >= spacing){
sub_v2_v2v2(diff_path_v2,final_mouse,stroke->last_mouse_position);
pressure = stroke->last_pressure + (spacing / length) * dpressure;
ups->overlap_factor = paint_stroke_integrate_overlap(stroke->brush, (spacing/stroke->brush->adaptive_space_factor) / no_pressure_spacing);//paint_stroke_integrate_overlap(stroke->brush, spacing / no_pressure_spacing);
stroke->stroke_distance += length;
cnt += draw_spaced_dab(C, op, final_mouse, diff_path_v2, stroke->distance_since_last_dab, spacing, pressure, &length_v3);
stroke->distance_since_last_dab = length_v3;
pressure = stroke->last_pressure;
dpressure = final_pressure - stroke->last_pressure;
}else{
stroke->distance_since_last_dab += length_v3;
}
/*end Dab*/
}
}
copy_v2_v2(stroke->last_mouse_position,final_mouse);
copy_v3_v3(stroke->last_v3_mouse_position,mouse_v3);
return cnt;
}
@@ -960,7 +1191,12 @@ static void paint_stroke_line_end(bContext *C, wmOperator *op, PaintStroke *stro
stroke->ups->overlap_factor = paint_stroke_integrate_overlap(br, 1.0);
paint_brush_stroke_add_step(C, op, stroke->last_mouse_position, 1.0);
paint_space_stroke(C, op, mouse, 1.0);
if(BKE_brush_use_adaptive_spacing(stroke->brush)){
paint_space_stroke_object_space(C,op, mouse, 1.0f);
}else{
paint_space_stroke_screen_space(C,op, mouse, 1.0f);
}
}
}
@@ -971,7 +1207,7 @@ static bool paint_stroke_curve_end(bContext *C, wmOperator *op, PaintStroke *str
if (br->flag & BRUSH_CURVE) {
UnifiedPaintSettings *ups = &CTX_data_tool_settings(C)->unified_paint_settings;
const Scene *scene = CTX_data_scene(C);
const float spacing = paint_space_stroke_spacing(scene, stroke, 1.0f, 1.0f);
const float spacing = paint_space_unadjusted_stroke_spacing(scene, stroke);
PaintCurve *pc = br->paint_curve;
PaintCurvePoint *pcp;
float length_residue = 0.0f;
@@ -1125,6 +1361,7 @@ int paint_stroke_modal(bContext *C, wmOperator *op, const wmEvent *event)
if (!stroke->stroke_started) {
stroke->last_pressure = sample_average.pressure;
copy_v2_v2(stroke->last_mouse_position, sample_average.mouse);
stroke->get_location(C,stroke->last_v3_mouse_position,stroke->last_mouse_position);
stroke->stroke_started = stroke->test_start(C, op, sample_average.mouse);
BLI_assert((stroke->stroke_started & ~1) == 0); /* 0/1 */
@@ -1191,8 +1428,13 @@ int paint_stroke_modal(bContext *C, wmOperator *op, const wmEvent *event)
if (paint_smooth_stroke(stroke, &sample_average, mode, mouse, &pressure)) {
if (stroke->stroke_started) {
if (paint_space_stroke_enabled(br, mode)) {
if (paint_space_stroke(C, op, mouse, pressure))
redraw = true;
if (BKE_brush_use_adaptive_spacing(stroke->brush)) {
if (paint_space_stroke_object_space(C, op, mouse, pressure))
redraw = true;
}else{
if (paint_space_stroke_screen_space(C, op, mouse, pressure))
redraw = true;
}
}
else {
float dmouse[2];

File diff suppressed because it is too large Load Diff

View File

@@ -36,12 +36,11 @@
#include "DNA_listBase.h"
#include "DNA_vec_types.h"
#include "DNA_key_types.h"
#include "DNA_customdata_types.h"
#include "BLI_bitmap.h"
#include "BKE_pbvh.h"
struct bContext;
struct KeyBlock;
struct Object;
struct SculptUndoNode;
@@ -64,19 +63,20 @@ void sculpt_dynamic_topology_disable(struct bContext *C,
/* Undo */
typedef enum {
typedef enum SculptUndoType {
SCULPT_UNDO_COORDS,
SCULPT_UNDO_HIDDEN,
SCULPT_UNDO_MASK,
SCULPT_UNDO_DYNTOPO_BEGIN,
SCULPT_UNDO_DYNTOPO_END,
SCULPT_UNDO_DYNTOPO_SYMMETRIZE,
SCULPT_UNDO_SILHOUETTE
} SculptUndoType;
typedef struct SculptUndoNode {
struct SculptUndoNode *next, *prev;
SculptUndoType type;
enum SculptUndoType type;
char idname[MAX_ID_NAME]; /* name instead of pointer*/
void *node; /* only during push, not valid afterwards! */
@@ -100,6 +100,7 @@ typedef struct SculptUndoNode {
BLI_bitmap **grid_hidden;
/* bmesh */
/* Reused for Silhouette undonode. TODO: Maybe separate?*/
struct BMLogEntry *bm_entry;
bool applied;
CustomData bm_enter_vdata;
@@ -117,6 +118,7 @@ typedef struct SculptUndoNode {
SculptUndoNode *sculpt_undo_push_node(Object *ob, PBVHNode *node, SculptUndoType type);
SculptUndoNode *sculpt_undo_get_node(PBVHNode *node);
SculptUndoNode *sculpt_undo_silhouette_push(Object *ob, int v_start, int e_start, int l_start, int p_start);
void sculpt_undo_push_begin(const char *name);
void sculpt_undo_push_end(const struct bContext *C);

View File

@@ -68,6 +68,8 @@
#include "bmesh.h"
#include "paint_intern.h"
#include "sculpt_intern.h"
#include "BKE_object.h"
#include "ED_mesh.h"
/************************** Undo *************************/
@@ -446,6 +448,74 @@ static int sculpt_undo_bmesh_restore(bContext *C,
return false;
}
static void sculpt_undo_silhouette_restore(bContext *C, Object *ob, SculptUndoNode *unode)
{
Mesh *me = ob->data;
if(unode->applied){
unode->applied = false;
CustomData_free_elem(&me->vdata, me->totvert - unode->bm_enter_totvert, unode->bm_enter_totvert);
CustomData_free_elem(&me->edata, me->totedge - unode->bm_enter_totedge, unode->bm_enter_totedge);
CustomData_free_elem(&me->ldata, me->totloop - unode->bm_enter_totloop, unode->bm_enter_totloop);
CustomData_free_elem(&me->pdata, me->totpoly - unode->bm_enter_totpoly, unode->bm_enter_totpoly);
CustomData_realloc(&me->vdata, me->totvert - unode->bm_enter_totvert);
CustomData_realloc(&me->edata, me->totedge - unode->bm_enter_totedge);
CustomData_realloc(&me->ldata, me->totloop - unode->bm_enter_totloop);
CustomData_realloc(&me->pdata, me->totpoly - unode->bm_enter_totpoly);
BKE_mesh_update_customdata_pointers(me, false);
me->totvert = me->totvert - unode->bm_enter_totvert;
me->totedge = me->totedge - unode->bm_enter_totedge;
me->totloop = me->totloop - unode->bm_enter_totloop;
me->totpoly = me->totpoly - unode->bm_enter_totpoly;
BKE_mesh_calc_edges(me, false, true);
BKE_mesh_tessface_clear(me);
BKE_mesh_calc_normals(me);
DAG_id_tag_update(&me->id, 0);
WM_event_add_notifier(C, NC_GEOM | ND_DATA, me);
BKE_object_free_derived_caches(ob);
} else {
unode->applied = true;
int v_start_n, e_start_n, l_start_n, p_start_n;
v_start_n = me->totvert;
e_start_n = me->totedge;
l_start_n = me->totloop;
p_start_n = me->totpoly;
ED_mesh_vertices_add(me, NULL, unode->bm_enter_totvert);
ED_mesh_edges_add(me, NULL, unode->bm_enter_totedge);
ED_mesh_loops_add(me, NULL, unode->bm_enter_totloop);
ED_mesh_polys_add(me, NULL, unode->bm_enter_totpoly);
CustomData_copy_data(&unode->bm_enter_vdata, &me->vdata, v_start_n, v_start_n, unode->bm_enter_totvert);
CustomData_copy_data(&unode->bm_enter_edata, &me->edata, e_start_n, e_start_n, unode->bm_enter_totedge);
CustomData_copy_data(&unode->bm_enter_ldata, &me->ldata, l_start_n, l_start_n, unode->bm_enter_totloop);
CustomData_copy_data(&unode->bm_enter_pdata, &me->pdata, p_start_n, p_start_n, unode->bm_enter_totpoly);
/* TODO: Not a full copy:
CustomData_copy_data(&unode->bm_enter_vdata, &me->vdata, 0, v_start_n, unode->bm_enter_totvert);
CustomData_copy_data(&unode->bm_enter_edata, &me->edata, 0, e_start_n, unode->bm_enter_totedge);
CustomData_copy_data(&unode->bm_enter_ldata, &me->ldata, 0, l_start_n, unode->bm_enter_totloop);
CustomData_copy_data(&unode->bm_enter_pdata, &me->pdata, 0, p_start_n, unode->bm_enter_totpoly);*/
BKE_mesh_update_customdata_pointers(me, true);
BKE_mesh_calc_edges(me, false, true);
BKE_mesh_tessface_clear(me);
BKE_mesh_calc_normals(me);
DAG_id_tag_update(&me->id, 0);
WM_event_add_notifier(C, NC_GEOM | ND_DATA, me);
BKE_object_free_derived_caches(ob);
}
}
static void sculpt_undo_restore(bContext *C, ListBase *lb)
{
Scene *scene = CTX_data_scene(C);
@@ -517,6 +587,12 @@ static void sculpt_undo_restore(bContext *C, ListBase *lb)
case SCULPT_UNDO_DYNTOPO_SYMMETRIZE:
BLI_assert(!"Dynamic topology should've already been handled");
break;
case SCULPT_UNDO_SILHOUETTE:
sculpt_undo_silhouette_restore(C, ob, unode);
rebuild = true;
partial_update = false;
return;
break;
}
}
@@ -711,6 +787,8 @@ static SculptUndoNode *sculpt_undo_alloc_node(Object *ob, PBVHNode *node,
case SCULPT_UNDO_DYNTOPO_SYMMETRIZE:
BLI_assert(!"Dynamic topology should've already been handled");
break;
case SCULPT_UNDO_SILHOUETTE:
break;
}
BLI_addtail(lb, unode);
@@ -868,6 +946,7 @@ static SculptUndoNode *sculpt_undo_bmesh_push(Object *ob,
case SCULPT_UNDO_DYNTOPO_BEGIN:
case SCULPT_UNDO_DYNTOPO_END:
case SCULPT_UNDO_DYNTOPO_SYMMETRIZE:
case SCULPT_UNDO_SILHOUETTE:
break;
}
}
@@ -875,6 +954,53 @@ static SculptUndoNode *sculpt_undo_bmesh_push(Object *ob,
return unode;
}
SculptUndoNode *sculpt_undo_silhouette_push(Object *ob, int v_start, int e_start, int l_start, int p_start)
{
/* list is manipulated by multiple threads, so we lock */
BLI_lock_thread(LOCK_CUSTOM1);
ListBase *lb = undo_paint_push_get_list(UNDO_PAINT_MESH);
SculptUndoNode *unode = lb->first;
if (!lb->first) {
unode = MEM_callocN(sizeof(*unode), __func__);
BLI_strncpy(unode->idname, ob->id.name, sizeof(unode->idname));
unode->type = SCULPT_UNDO_SILHOUETTE;
unode->applied = true;
Mesh *me = ob->data;
/* Store a copy of the silhouettes current vertices, loops, and
* polys. TODO: Add bridge edges and deleted existing geometry later */
CustomData_copy(&me->vdata, &unode->bm_enter_vdata, CD_MASK_MESH,
CD_DUPLICATE, me->totvert);
CustomData_copy(&me->edata, &unode->bm_enter_edata, CD_MASK_MESH,
CD_DUPLICATE, me->totedge);
CustomData_copy(&me->ldata, &unode->bm_enter_ldata, CD_MASK_MESH,
CD_DUPLICATE, me->totloop);
CustomData_copy(&me->pdata, &unode->bm_enter_pdata, CD_MASK_MESH,
CD_DUPLICATE, me->totpoly);
/*TODO: Not a full copy:
CustomData_copy_data(&me->vdata, &unode->bm_enter_vdata, me->totvert - unode->bm_enter_totvert, 0, unode->bm_enter_totvert);
CustomData_copy_data(&me->edata, &unode->bm_enter_edata, me->totedge - unode->bm_enter_totedge, 0, unode->bm_enter_totedge);
CustomData_copy_data(&me->ldata, &unode->bm_enter_ldata, me->totloop - unode->bm_enter_totloop, 0, unode->bm_enter_totloop);
CustomData_copy_data(&me->pdata, &unode->bm_enter_pdata, me->totpoly - unode->bm_enter_totpoly, 0, unode->bm_enter_totpoly);*/
unode->bm_enter_totvert = me->totvert - v_start;
unode->bm_enter_totedge = me->totedge - e_start;
unode->bm_enter_totloop = me->totloop - l_start;
unode->bm_enter_totpoly = me->totpoly - p_start;
BLI_addtail(lb, unode);
}
BLI_unlock_thread(LOCK_CUSTOM1);
return unode;
}
SculptUndoNode *sculpt_undo_push_node(Object *ob, PBVHNode *node,
SculptUndoType type)
{
@@ -898,6 +1024,10 @@ SculptUndoNode *sculpt_undo_push_node(Object *ob, PBVHNode *node,
else if ((unode = sculpt_undo_get_node(node))) {
BLI_unlock_thread(LOCK_CUSTOM1);
return unode;
} else if (ELEM(type,SCULPT_UNDO_SILHOUETTE)) {
/* TODO:Remove? Should not reach. */
BLI_unlock_thread(LOCK_CUSTOM1);
return unode;
}
unode = sculpt_undo_alloc_node(ob, node, type);
@@ -935,6 +1065,8 @@ SculptUndoNode *sculpt_undo_push_node(Object *ob, PBVHNode *node,
case SCULPT_UNDO_DYNTOPO_SYMMETRIZE:
BLI_assert(!"Dynamic topology should've already been handled");
break;
case SCULPT_UNDO_SILHOUETTE:/*TODO: Store data?*/
break;
}
/* store active shape key */

View File

@@ -112,7 +112,7 @@ static void view3d_stereo3d_setup_offscreen(Scene *scene, View3D *v3d, ARegion *
/* handy utility for drawing shapes in the viewport for arbitrary code.
* could add lines and points too */
// #define DEBUG_DRAW
#define DEBUG_DRAW
#ifdef DEBUG_DRAW
static void bl_debug_draw(void);
/* add these locally when using these functions for testing */
@@ -4064,8 +4064,8 @@ void view3d_main_region_draw(const bContext *C, ARegion *ar)
#ifdef DEBUG_DRAW
/* debug drawing */
#define _DEBUG_DRAW_QUAD_TOT 1024
#define _DEBUG_DRAW_EDGE_TOT 1024
#define _DEBUG_DRAW_QUAD_TOT 16000
#define _DEBUG_DRAW_EDGE_TOT 16000
static float _bl_debug_draw_quads[_DEBUG_DRAW_QUAD_TOT][4][3];
static int _bl_debug_draw_quads_tot = 0;
static float _bl_debug_draw_edges[_DEBUG_DRAW_QUAD_TOT][2][3];

View File

@@ -119,6 +119,8 @@ typedef struct Brush {
float unprojected_radius;
float adaptive_space_factor;
/* soften/sharpen */
float sharp_threshold;
int blur_kernel_radius;
@@ -135,6 +137,8 @@ typedef struct Brush {
float mask_stencil_pos[2];
float mask_stencil_dimension[2];
float pad;
} Brush;
typedef struct PaletteColor {

View File

@@ -1141,7 +1141,14 @@ typedef struct Sculpt {
/* scale for constant detail size */
float constant_detail; /* Constant detail resolution (Blender unit / constant_detail) */
float detail_percent;
float pad;
/* silhouette settings */
float silhouette_smoothness;
float silhouette_depth;
int silhouette_resolution;
int silhouette_flags;
int pad;
struct Object *gravity_object;
} Sculpt;

View File

@@ -1224,7 +1224,6 @@ static void rna_def_brush(BlenderRNA *brna)
"Automatically adjust strength to give consistent results for different spacings");
RNA_def_property_update(prop, 0, "rna_Brush_update");
/* adaptive space is not implemented yet */
prop = RNA_def_property(srna, "use_adaptive_space", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", BRUSH_ADAPTIVE_SPACE);
RNA_def_property_ui_text(prop, "Adaptive Spacing",

View File

@@ -647,6 +647,24 @@ static void rna_def_sculpt(BlenderRNA *brna)
RNA_def_property_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Orientation", "Object whose Z axis defines orientation of gravity");
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
prop = RNA_def_property(srna, "silhouette_smoothness", PROP_FLOAT, PROP_PERCENTAGE);
RNA_def_property_ui_range(prop, 0.0, 100.0, 1.0, 0.1);
RNA_def_property_ui_text(prop, "Smoothness Factor", "Smoothness of generated silhouette");
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
prop = RNA_def_property(srna, "silhouette_depth", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_default(prop, 1.0f);
RNA_def_property_range(prop, 0.0001, FLT_MAX);
RNA_def_property_ui_range(prop, 0.001, 1000.0, 10, 2);
RNA_def_property_ui_text(prop, "Depth", "Depth or thickness of the generated silhouette");
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
prop = RNA_def_property(srna, "silhouette_resolution", PROP_INT, PROP_UNSIGNED);
RNA_def_property_int_default(prop, 3);
RNA_def_property_ui_range(prop, 1, 8, 0, -1);
RNA_def_property_ui_text(prop, "Subsurf resolution", "Subdivision of the generated geometry");
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
}