Sculpt-dev: Clean up brush test code

* The standard sculpt brush spot test
  API now supports square brushes.
* Supports tip scale x from paint brush.
* TODO: rewrite clay strips and paint
  brushes to use standard api.
* Roll texture mapping semi-works.
This commit is contained in:
Joseph Eagar 2022-05-21 14:29:18 -07:00
parent d6d1ddbf0b
commit 7217d1f355
23 changed files with 950 additions and 427 deletions

View File

@ -923,6 +923,9 @@ typedef struct SculptSession {
* Last used painting canvas key.
*/
char *last_paint_canvas_key;
/* Used to derive initial tip rotation. */
float last_grab_delta[3];
} SculptSession;
void BKE_sculptsession_free(struct Object *ob);

View File

@ -2308,11 +2308,13 @@ float BKE_brush_sample_tex_3d(const Scene *scene,
invradius = 1.0f / ups->pixel_radius;
}
else if (mtex->brush_map_mode == MTEX_MAP_MODE_ROLL) {
// XXX implement me
x = point_2d[0] - ups->tex_mouse[0];
y = point_2d[1] - ups->tex_mouse[1];
/* leave the coordinates relative to the screen */
invradius = 1.0f / ups->pixel_radius;
/* use unadjusted size for tiled mode */
invradius = 1.0f / BKE_brush_size_get(scene, br, false);
x = point_2d[0];
y = point_2d[1];
}
x *= invradius;

View File

@ -324,6 +324,8 @@ static bool check_builtin_init()
// SETCAT(direction, "Basic");
SETCAT(accumulate, "Basic");
SETCAT(use_frontface, "Basic");
SETCAT(tip_roundness, "Basic");
SETCAT(tip_scale_x, "Basic");
SETCAT(smear_deform_type, "Smear");
SETCAT(smear_deform_blend, "Smear");
@ -435,6 +437,16 @@ static bool check_builtin_init()
# undef ADDCH
#endif
/* TODO: Destroy these macros.*/
#define ADDCH_EX(idname, category, visflag) \
do { \
BKE_brush_channelset_ensure_builtin(chset, BRUSH_BUILTIN_##idname); \
BrushChannel *ch = BKE_brush_channelset_lookup(chset, BRUSH_BUILTIN_##idname); \
SETCAT(idname, category); \
ch->flag |= visflag; \
} while (0);
/* TODO: replace these two macros with equivalent BRUSHSET_XXX ones */
#define ADDCH(name) \
(BKE_brush_channelset_ensure_builtin(chset, BRUSH_BUILTIN_##name), \
@ -1266,6 +1278,19 @@ void BKE_brush_builtin_patch(Brush *brush, int tool)
ADDCH(deform_target);
/* Patch olds files. */
if (!BRUSHSET_LOOKUP(chset, tip_scale_x)) {
ADDCH_EX(tip_scale_x,
"Basic",
BRUSH_CHANNEL_SHOW_IN_WORKSPACE | BRUSH_CHANNEL_SHOW_IN_CONTEXT_MENU);
ADDCH_EX(tip_roundness,
"Basic",
BRUSH_CHANNEL_SHOW_IN_WORKSPACE | BRUSH_CHANNEL_SHOW_IN_CONTEXT_MENU);
if (tool == SCULPT_TOOL_CLAY_STRIPS) {
BRUSHSET_SET_FLOAT(chset, tip_roundness, 0.18f);
}
}
/* stuff for deform_target cloth mode*/
ADDCH(cloth_use_collision);
ADDCH(cloth_solve_bending);
@ -1306,8 +1331,6 @@ void BKE_brush_builtin_patch(Brush *brush, int tool)
ADDCH(wet_paint_radius_factor);
ADDCH(wet_persistence);
ADDCH(density);
ADDCH(tip_scale_x);
ADDCH(tip_roundness);
ADDCH(flow);
ADDCH(rate);
ADDCH(blend);
@ -1489,6 +1512,11 @@ void BKE_brush_channelset_ui_init(Brush *brush, int tool)
SHOWWRK(hardness);
SHOWWRK(dyntopo_disabled);
SHOWWRK(tip_roundness);
SHOWCTX(tip_roundness);
SHOWWRK(tip_scale_x);
SHOWCTX(tip_scale_x);
switch (tool) {
case SCULPT_TOOL_DRAW_SHARP:
SHOWWRK(sharp_mode);
@ -1555,7 +1583,6 @@ void BKE_brush_channelset_ui_init(Brush *brush, int tool)
SHOWWRK(area_radius_factor);
SHOW_WRK_CTX(plane_offset);
SHOW_WRK_CTX(plane_trim);
SHOWWRK(tip_roundness);
SHOW_WRK_CTX(use_plane_trim);
SHOWWRK(use_smoothed_rake);
@ -1568,7 +1595,6 @@ void BKE_brush_channelset_ui_init(Brush *brush, int tool)
SHOWWRK(area_radius_factor);
SHOWWRK(plane_offset);
SHOWWRK(plane_trim);
SHOWWRK(tip_roundness);
SHOWWRK(use_plane_trim);
SHOWCTX(autosmooth);
@ -1661,10 +1687,8 @@ void BKE_brush_channelset_ui_init(Brush *brush, int tool)
SHOWWRK(wet_paint_radius_factor);
SHOWWRK(wet_persistence);
SHOWWRK(density);
SHOWWRK(tip_scale_x);
SHOWWRK(hardness);
SHOWWRK(wet_mix);
SHOWWRK(tip_roundness);
SHOWWRK(flow);
SHOWWRK(rate);
SHOWALL(blend);

View File

@ -25,6 +25,7 @@
#include "BKE_attribute.h"
#include "BKE_ccg.h"
#include "BKE_main.h"
#include "BKE_mesh.h" /* for BKE_mesh_calc_normals */
#include "BKE_mesh_mapping.h"
#include "BKE_object.h"
@ -1543,7 +1544,8 @@ static void pbvh_update_draw_buffer_cb(void *__restrict userdata,
pbvh->face_sets_color_seed,
pbvh->face_sets_color_default,
update_flags,
pbvh->vert_normals);
pbvh->vert_normals,
pbvh->mdyntopo_verts);
} break;
case PBVH_BMESH:
if (BKE_pbvh_bmesh_check_tris(pbvh, node)) {
@ -1644,7 +1646,8 @@ void pbvh_update_free_all_draw_buffers(PBVH *pbvh, PBVHNode *node)
}
}
static void pbvh_update_draw_buffers(PBVH *pbvh, Mesh *me, PBVHNode **nodes, int totnode, int update_flag)
static void pbvh_update_draw_buffers(
PBVH *pbvh, Mesh *me, PBVHNode **nodes, int totnode, int update_flag)
{
CustomData *vdata;
@ -2098,7 +2101,8 @@ void BKE_pbvh_node_mark_original_update(PBVHNode *node)
void BKE_pbvh_node_mark_update(PBVHNode *node)
{
node->flag |= PBVH_UpdateNormals | PBVH_UpdateBB | PBVH_UpdateOriginalBB |
PBVH_UpdateDrawBuffers | PBVH_UpdateRedraw | PBVH_UpdateCurvatureDir | PBVH_RebuildPixels;
PBVH_UpdateDrawBuffers | PBVH_UpdateRedraw | PBVH_UpdateCurvatureDir |
PBVH_RebuildPixels | PBVH_UpdateTriAreas;
}
void BKE_pbvh_node_mark_update_mask(PBVHNode *node)
@ -2503,15 +2507,15 @@ bool ray_update_depth_and_hit_count(const float depth_test,
return false;
}
float ray_face_intersection_depth_quad(const float ray_start[3],
struct IsectRayPrecalc *isect_precalc,
const float t0[3],
const float t1[3],
const float t2[3],
const float t3[3],
float *r_depth,
float *r_back_depth,
int *hit_count)
bool ray_face_intersection_depth_quad(const float ray_start[3],
struct IsectRayPrecalc *isect_precalc,
const float t0[3],
const float t1[3],
const float t2[3],
const float t3[3],
float *r_depth,
float *r_back_depth,
int *hit_count)
{
float depth_test;
if (!(isect_ray_tri_watertight_v3(ray_start, isect_precalc, t0, t1, t2, &depth_test, NULL) ||
@ -4907,10 +4911,21 @@ void BKE_pbvh_clear_cache(PBVH *preserve)
pbvh_clear_cached_pbvhs(NULL);
}
#define PBVH_CACHE_KEY_SIZE 1024
static void pbvh_make_cached_key(Object *ob, char out[PBVH_CACHE_KEY_SIZE])
{
sprintf(out, "%s:%p", ob->id.name, G.main);
}
void BKE_pbvh_invalidate_cache(Object *ob)
{
Object *ob_orig = DEG_get_original_object(ob);
PBVH *pbvh = BLI_ghash_lookup(cached_pbvhs, ob_orig->id.name);
char key[PBVH_CACHE_KEY_SIZE];
pbvh_make_cached_key(ob_orig, key);
PBVH *pbvh = BLI_ghash_lookup(cached_pbvhs, key);
if (pbvh) {
BKE_pbvh_cache_remove(pbvh);
@ -4921,7 +4936,10 @@ PBVH *BKE_pbvh_get_or_free_cached(Object *ob, Mesh *me, PBVHType pbvh_type)
{
Object *ob_orig = DEG_get_original_object(ob);
PBVH *pbvh = BLI_ghash_lookup(cached_pbvhs, ob_orig->id.name);
char key[PBVH_CACHE_KEY_SIZE];
pbvh_make_cached_key(ob_orig, key);
PBVH *pbvh = BLI_ghash_lookup(cached_pbvhs, key);
if (!pbvh) {
return NULL;
@ -4966,7 +4984,10 @@ void BKE_pbvh_set_cached(Object *ob, PBVH *pbvh)
Object *ob_orig = DEG_get_original_object(ob);
PBVH *exist = BLI_ghash_lookup(cached_pbvhs, ob_orig->id.name);
char key[PBVH_CACHE_KEY_SIZE];
pbvh_make_cached_key(ob_orig, key);
PBVH *exist = BLI_ghash_lookup(cached_pbvhs, key);
if (pbvh->invalid) {
printf("pbvh invalid!");
@ -4978,7 +4999,11 @@ void BKE_pbvh_set_cached(Object *ob, PBVH *pbvh)
if (!exist || exist != pbvh) {
pbvh_clear_cached_pbvhs(pbvh);
BLI_ghash_insert(cached_pbvhs, BLI_strdup(ob_orig->id.name), pbvh);
char key[PBVH_CACHE_KEY_SIZE];
pbvh_make_cached_key(ob_orig, key);
BLI_ghash_insert(cached_pbvhs, BLI_strdup(key), pbvh);
}
BKE_pbvh_cache(BKE_object_get_original_mesh(ob_orig), pbvh);

View File

@ -141,6 +141,7 @@ typedef struct PaintStroke {
StrokeDone done;
float spacing;
void *debug_draw_handle;
} PaintStroke;
struct PaintStroke *paint_stroke_new(struct bContext *C,
@ -619,6 +620,8 @@ void paint_delete_blur_kernel(BlurKernel *);
#define PAINT_CURVE_NUM_SEGMENTS 40
bool paint_stroke_has_cubic(const PaintStroke *stroke);
float bezier3_arclength_v2(const float control[4][2]);
float bezier3_arclength_v3(const float control[4][3]);
#ifdef __cplusplus
}

View File

@ -35,6 +35,7 @@
#include "GPU_state.h"
#include "ED_screen.h"
#include "ED_space_api.h"
#include "ED_view3d.h"
#include "IMB_imbuf_types.h"
@ -51,6 +52,89 @@
# include "PIL_time_utildefines.h"
#endif
static void paint_stroke_add_sample(
const Paint *paint, PaintStroke *stroke, float x, float y, float pressure);
#define DRAW_DEBUG_VIS
#ifdef DRAW_DEBUG_VIS
static void paint_brush_cubic_vis(const bContext *C, ARegion *region, void *userdata)
{
PaintStroke *stroke = userdata;
if (!stroke->num_samples) {
return;
}
GPU_line_smooth(true);
GPU_blend(GPU_BLEND_ALPHA);
uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
immUniformColor4ub(0, 0, 0, 155);
GPU_point_size(12);
immBegin(GPU_PRIM_LINES, 6);
immVertex2f(pos, stroke->mouse_cubic[0][0], stroke->mouse_cubic[0][1]);
immVertex2f(pos, stroke->mouse_cubic[1][0], stroke->mouse_cubic[1][1]);
immVertex2f(pos, stroke->mouse_cubic[1][0], stroke->mouse_cubic[1][1]);
immVertex2f(pos, stroke->mouse_cubic[2][0], stroke->mouse_cubic[2][1]);
immVertex2f(pos, stroke->mouse_cubic[2][0], stroke->mouse_cubic[2][1]);
immVertex2f(pos, stroke->mouse_cubic[3][0], stroke->mouse_cubic[3][1]);
immEnd();
immBegin(GPU_PRIM_POINTS, 2);
immVertex2f(pos, stroke->mouse_cubic[0][0], stroke->mouse_cubic[0][1]);
// immVertex2f(pos, stroke->mouse_cubic[1][0], stroke->mouse_cubic[1][1]);
// immVertex2f(pos, stroke->mouse_cubic[2][0], stroke->mouse_cubic[2][1]);
immVertex2f(pos, stroke->mouse_cubic[3][0], stroke->mouse_cubic[3][1]);
immEnd();
immUniformColor4ub(255, 0, 0, 155);
GPU_point_size(8);
for (int i = 0; i < 2; i++) {
if (i) {
if (stroke->num_samples < 2) {
break;
}
immBegin(GPU_PRIM_LINES, (stroke->num_samples - 1) * 2);
}
else {
immBegin(GPU_PRIM_POINTS, stroke->num_samples);
}
for (int j = 0; j < stroke->num_samples; j++) {
int j2 = (j + stroke->cur_sample) % stroke->num_samples;
immVertex2f(pos, stroke->samples[j2].mouse[0], stroke->samples[j2].mouse[1]);
if (i && j < stroke->num_samples - 1) {
int j3 = (j + stroke->cur_sample + 1) % stroke->num_samples;
immVertex2f(pos, stroke->samples[j3].mouse[0], stroke->samples[j3].mouse[1]);
}
}
immEnd();
}
immUniformColor4ub(0, 0, 255, 155);
immBegin(GPU_PRIM_POINTS, 1);
immVertex2fv(pos, stroke->samples[stroke->cur_sample].mouse);
immEnd();
immUnbindProgram();
GPU_blend(GPU_BLEND_NONE);
GPU_line_smooth(false);
}
#endif
/*** Cursors ***/
static void paint_draw_smooth_cursor(bContext *C, int x, int y, void *customdata)
{
@ -205,6 +289,58 @@ static bool paint_tool_require_inbetween_mouse_events(Brush *brush, ePaintMode m
return true;
}
static void paint_brush_make_cubic(PaintStroke *stroke)
{
float a[2], b[2], c[2], d[2];
int ia = (stroke->cur_sample - 3 + stroke->num_samples) % stroke->num_samples;
int id = (stroke->cur_sample - 2 + stroke->num_samples) % stroke->num_samples;
int ib = (stroke->cur_sample - 4 + stroke->num_samples) % stroke->num_samples;
int ic = (stroke->cur_sample - 1 + stroke->num_samples) % stroke->num_samples;
copy_v2_v2(a, stroke->samples[ia].mouse);
copy_v2_v2(b, stroke->samples[ib].mouse);
copy_v2_v2(c, stroke->samples[ic].mouse);
copy_v2_v2(d, stroke->samples[id].mouse);
float tmp[2];
#if 1
sub_v2_v2v2(tmp, d, a);
sub_v2_v2v2(b, a, b);
interp_v2_v2v2(b, b, tmp, 0.5f);
mul_v2_fl(b, 1.0f / 3.0f);
#else
zero_v2(b);
#endif
add_v2_v2(b, a);
#if 1
sub_v2_v2v2(tmp, a, d);
sub_v2_v2v2(c, d, c);
interp_v2_v2v2(c, c, tmp, 0.5f);
mul_v2_fl(c, 1.0f / 3.0f);
#else
zero_v2(c);
#endif
add_v2_v2(c, d);
copy_v2_v2(stroke->mouse_cubic[0], a);
copy_v2_v2(stroke->mouse_cubic[1], b);
copy_v2_v2(stroke->mouse_cubic[2], c);
copy_v2_v2(stroke->mouse_cubic[3], d);
#if 0
printf("\n");
printf("a: %.2f: %.2f\n", a[0], a[1]);
printf("b: %.2f: %.2f\n", b[0], b[1]);
printf("c: %.2f: %.2f\n", c[0], c[1]);
printf("d: %.2f: %.2f\n", d[0], d[1]);
#endif
}
bool paint_stroke_apply_subspacing(struct PaintStroke *stroke,
const float spacing,
const enum ePaintMode mode,
@ -461,8 +597,8 @@ static bool paint_stroke_use_jitter(ePaintMode mode, Brush *brush, bool invert)
}
/* Put the location of the next stroke dot into the stroke RNA and apply it to the mesh */
ATTR_NO_OPT static void paint_brush_stroke_add_step(
bContext *C, wmOperator *op, PaintStroke *stroke, const float mouse_in[2], float pressure)
static void paint_brush_stroke_add_step(
bContext *C, wmOperator *op, PaintStroke *stroke, const float mouse[2], float pressure)
{
Scene *scene = CTX_data_scene(C);
Paint *paint = BKE_paint_get_active_from_context(C);
@ -473,6 +609,37 @@ ATTR_NO_OPT static void paint_brush_stroke_add_step(
PointerRNA itemptr;
float location[3];
const float *mouse_in;
if (stroke->has_cubic_stroke) {
paint_stroke_add_sample(paint, stroke, mouse[0], mouse[1], pressure);
paint_brush_make_cubic(stroke);
}
float mousetemp[2];
if (stroke->has_cubic_stroke) {
printf("\n");
for (int i = 0; i < stroke->num_samples; i++) {
PaintSample *sample = stroke->samples + ((stroke->cur_sample + i) % stroke->num_samples);
printf("%.2f %.2f\n", sample->mouse[0], sample->mouse[1]);
}
mouse_in = mousetemp;
PaintSample *sample1 = stroke->samples +
((stroke->cur_sample - 3 + stroke->num_samples) % stroke->num_samples);
PaintSample *sample2 = stroke->samples +
((stroke->cur_sample - 2 + stroke->num_samples) % stroke->num_samples);
interp_v2_v2v2(mousetemp, sample1->mouse, sample2->mouse, 0.5f);
// copy_v2_v2(mousetemp, sample1->mouse);
}
else {
mouse_in = mouse;
}
stroke->stroke_sample_index++;
/* the following code is adapted from texture paint. It may not be needed but leaving here
@ -504,7 +671,8 @@ ATTR_NO_OPT static void paint_brush_stroke_add_step(
/* copy last position -before- jittering, or space fill code
* will create too many dabs */
copy_v2_v2(stroke->last_mouse_position, mouse_in);
copy_v2_v2(stroke->last_mouse_position, mouse);
stroke->last_pressure2 = stroke->last_pressure;
stroke->last_pressure = pressure;
@ -537,6 +705,7 @@ ATTR_NO_OPT static void paint_brush_stroke_add_step(
}
bool is_location_is_set;
ups->last_hit = paint_brush_update(
C, brush, mode, stroke, mouse_in, mouse_out, pressure, location, &is_location_is_set);
if (is_location_is_set) {
@ -838,11 +1007,11 @@ static float paint_space_stroke_spacing_variable(bContext *C,
/* For brushes with stroke spacing enabled, moves mouse in steps
* towards the final mouse location. */
ATTR_NO_OPT static int paint_space_stroke(bContext *C,
wmOperator *op,
PaintStroke *stroke,
const float final_mouse[2],
float final_pressure)
static int paint_space_stroke(bContext *C,
wmOperator *op,
PaintStroke *stroke,
const float final_mouse[2],
float final_pressure)
{
const Scene *scene = CTX_data_scene(C);
ARegion *region = CTX_wm_region(C);
@ -910,18 +1079,24 @@ ATTR_NO_OPT static int paint_space_stroke(bContext *C,
ups->overlap_factor = paint_stroke_integrate_overlap(stroke->brush,
spacing / no_pressure_spacing);
float real_spacing = spacing;
if (stroke->has_cubic_stroke) {
// paint_brush_make_cubic(stroke);
// real_spacing = bezier3_arclength_v2(stroke->mouse_cubic);
}
if (use_scene_spacing) {
float size = paint_space_get_final_size(C, scene, stroke, pressure, dpressure, length);
stroke->stroke_distance += stroke->ups->pixel_radius * spacing / size;
stroke->stroke_distance_t += spacing / size;
stroke->stroke_distance += stroke->ups->pixel_radius * real_spacing / size;
stroke->stroke_distance_t += real_spacing / size;
}
else {
stroke->stroke_distance += spacing / stroke->zoom_2d;
stroke->stroke_distance_t += (spacing / stroke->zoom_2d) / stroke->ups->pixel_radius;
stroke->stroke_distance += real_spacing / stroke->zoom_2d;
stroke->stroke_distance_t += (real_spacing / stroke->zoom_2d) / stroke->ups->pixel_radius;
}
stroke->stroke_distance += spacing / stroke->zoom_2d;
stroke->stroke_distance += real_spacing / stroke->zoom_2d;
paint_brush_stroke_add_step(C, op, stroke, mouse, pressure);
length -= spacing;
@ -940,14 +1115,14 @@ ATTR_NO_OPT static int paint_space_stroke(bContext *C,
/**** Public API ****/
ATTR_NO_OPT PaintStroke *paint_stroke_new(bContext *C,
wmOperator *op,
StrokeGetLocation get_location,
StrokeTestStart test_start,
StrokeUpdateStep update_step,
StrokeRedraw redraw,
StrokeDone done,
int event_type)
PaintStroke *paint_stroke_new(bContext *C,
wmOperator *op,
StrokeGetLocation get_location,
StrokeTestStart test_start,
StrokeUpdateStep update_step,
StrokeRedraw redraw,
StrokeDone done,
int event_type)
{
struct Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
PaintStroke *stroke = MEM_callocN(sizeof(PaintStroke), "PaintStroke");
@ -957,9 +1132,15 @@ ATTR_NO_OPT PaintStroke *paint_stroke_new(bContext *C,
Brush *br = stroke->brush = BKE_paint_brush(p);
RegionView3D *rv3d = CTX_wm_region_view3d(C);
float zoomx, zoomy;
ARegion *region = CTX_wm_region(C);
ED_view3d_viewcontext_init(C, &stroke->vc, depsgraph);
#ifdef DRAW_DEBUG_VIS
stroke->debug_draw_handle = ED_region_draw_cb_activate(
region->type, paint_brush_cubic_vis, stroke, REGION_DRAW_POST_PIXEL);
#endif
stroke->get_location = get_location;
stroke->test_start = test_start;
stroke->update_step = update_step;
@ -1034,6 +1215,14 @@ void paint_stroke_free(bContext *C, wmOperator *UNUSED(op), PaintStroke *stroke)
BLI_freelistN(&stroke->line);
ARegion *region = CTX_wm_region(C);
#ifdef DRAW_DEBUG_VIS
ED_region_draw_cb_exit(region->type, stroke->debug_draw_handle);
#endif
ED_region_tag_redraw(region);
MEM_SAFE_FREE(stroke);
}
@ -1206,15 +1395,22 @@ bool paint_stroke_has_cubic(const PaintStroke *stroke)
return stroke->has_cubic_stroke;
}
static int paint_stroke_max_samples(const Paint *paint, PaintStroke *stroke)
{
int max_samples = CLAMPIS(paint->num_input_samples, 1, PAINT_MAX_INPUT_SAMPLES);
if (stroke->has_cubic_stroke) {
max_samples = max_ii(max_samples, 6);
}
return max_samples;
}
static void paint_stroke_add_sample(
const Paint *paint, PaintStroke *stroke, float x, float y, float pressure)
{
PaintSample *sample = &stroke->samples[stroke->cur_sample];
int max_samples = CLAMPIS(paint->num_input_samples, 1, PAINT_MAX_INPUT_SAMPLES);
if (stroke->has_cubic_stroke) {
max_samples = max_ii(max_samples, 5);
}
int max_samples = paint_stroke_max_samples(paint, stroke);
sample->mouse[0] = x;
sample->mouse[1] = y;
@ -1434,10 +1630,6 @@ static bool paint_stroke_curve_end(bContext *C, wmOperator *op, PaintStroke *str
if (stroke->stroke_started) {
paint_brush_stroke_add_step(C, op, stroke, data + 2 * j, 1.0);
if (stroke->has_cubic_stroke) {
paint_brush_stroke_add_step(C, op, stroke, data + 2 * j, 1.0);
}
paint_line_strokes_spacing(
C, op, stroke, spacing, &length_residue, data + 2 * j, data + 2 * (j + 1));
}
@ -1490,10 +1682,7 @@ static void paint_stroke_line_constrain(PaintStroke *stroke, float mouse[2])
}
}
ATTR_NO_OPT int paint_stroke_modal(bContext *C,
wmOperator *op,
const wmEvent *event,
PaintStroke **stroke_p)
int paint_stroke_modal(bContext *C, wmOperator *op, const wmEvent *event, PaintStroke **stroke_p)
{
Paint *p = BKE_paint_get_active_from_context(C);
ePaintMode mode = BKE_paintmode_get_active_from_context(C);
@ -1524,52 +1713,25 @@ ATTR_NO_OPT int paint_stroke_modal(bContext *C,
stroke->last_tablet_event_pressure = pressure;
}
paint_stroke_add_sample(p, stroke, event->mval[0], event->mval[1], pressure);
paint_stroke_sample_average(stroke, &sample_average);
if (stroke->stroke_sample_index == 0) {
for (int i = 0; i < 3; i++) {
paint_stroke_add_sample(p, stroke, event->mval[0], event->mval[1], pressure);
}
if (!stroke->has_cubic_stroke) {
paint_stroke_add_sample(p, stroke, event->mval[0], event->mval[1], pressure);
paint_stroke_sample_average(stroke, &sample_average);
}
else {
sample_average.mouse[0] = (float)event->mval[0];
sample_average.mouse[1] = (float)event->mval[1];
sample_average.pressure = pressure;
}
if (stroke->has_cubic_stroke) {
float a[2], b[2], c[2], d[2];
if (stroke->stroke_sample_index == 0) {
stroke->last_mouse_position[0] = event->mval[0];
stroke->last_mouse_position[1] = event->mval[1];
int ia = (stroke->cur_sample - 3 + stroke->num_samples) % stroke->num_samples;
int id = (stroke->cur_sample - 1 + stroke->num_samples) % stroke->num_samples;
int ib = (stroke->cur_sample - 2 + stroke->num_samples) % stroke->num_samples;
int ic = (stroke->cur_sample - 0 + stroke->num_samples) % stroke->num_samples;
int max_samples = paint_stroke_max_samples(p, stroke);
copy_v2_v2(a, stroke->samples[ia].mouse);
copy_v2_v2(b, stroke->samples[ib].mouse);
copy_v2_v2(c, stroke->samples[ic].mouse);
copy_v2_v2(d, stroke->samples[id].mouse);
float tmp[3];
sub_v2_v2v2(tmp, d, a);
sub_v2_v2(b, a);
negate_v2(b);
interp_v2_v2v2(b, b, tmp, 0.5f);
add_v2_v2(b, a);
sub_v2_v2v2(tmp, d, a);
sub_v2_v2(c, d);
interp_v2_v2v2(c, c, tmp, 0.5f);
negate_v2(c);
add_v2_v2(c, d);
copy_v2_v2(stroke->mouse_cubic[0], a);
copy_v2_v2(stroke->mouse_cubic[1], b);
copy_v2_v2(stroke->mouse_cubic[2], c);
copy_v2_v2(stroke->mouse_cubic[3], d);
printf("\n");
printf("a: %.2f: %.2f\n", a[0], a[1]);
printf("b: %.2f: %.2f\n", b[0], b[1]);
printf("c: %.2f: %.2f\n", c[0], c[1]);
printf("d: %.2f: %.2f\n", d[0], d[1]);
for (int i = stroke->num_samples; i < max_samples; i++) {
paint_stroke_add_sample(p, stroke, event->mval[0], event->mval[1], pressure);
}
}
/* Tilt. */
@ -1734,7 +1896,7 @@ ATTR_NO_OPT int paint_stroke_modal(bContext *C,
return OPERATOR_RUNNING_MODAL;
}
ATTR_NO_OPT int paint_stroke_exec(bContext *C, wmOperator *op, PaintStroke *stroke)
int paint_stroke_exec(bContext *C, wmOperator *op, PaintStroke *stroke)
{
/* only when executed for the first time */
if (stroke->stroke_started == 0) {

View File

@ -1979,8 +1979,8 @@ static void do_wpaint_brush_blur_task_cb_ex(void *__restrict userdata,
const bool use_vert_sel = (data->me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0;
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
ss, &test, data->brush->falloff_shape);
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init(
ss, &test, (eBrushFalloffShape)data->brush->falloff_shape);
const float *sculpt_normal_frontface = SCULPT_brush_frontface_normal_from_falloff_shape(
ss, data->brush->falloff_shape);
@ -2080,8 +2080,8 @@ static void do_wpaint_brush_smear_task_cb_ex(void *__restrict userdata,
if (cache->is_last_valid && (normalize_v3(brush_dir) != 0.0f)) {
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
ss, &test, data->brush->falloff_shape);
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init(
ss, &test, (eBrushFalloffShape)data->brush->falloff_shape);
const float *sculpt_normal_frontface = SCULPT_brush_frontface_normal_from_falloff_shape(
ss, data->brush->falloff_shape);
@ -2191,8 +2191,8 @@ static void do_wpaint_brush_draw_task_cb_ex(void *__restrict userdata,
const bool use_vert_sel = (data->me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0;
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
ss, &test, data->brush->falloff_shape);
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init(
ss, &test, (eBrushFalloffShape)data->brush->falloff_shape);
const float *sculpt_normal_frontface = SCULPT_brush_frontface_normal_from_falloff_shape(
ss, data->brush->falloff_shape);
@ -2258,8 +2258,8 @@ static void do_wpaint_brush_calc_average_weight_cb_ex(
accum->value = 0.0;
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
ss, &test, data->brush->falloff_shape);
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init(
ss, &test, (eBrushFalloffShape)data->brush->falloff_shape);
const float *sculpt_normal_frontface = SCULPT_brush_frontface_normal_from_falloff_shape(
ss, data->brush->falloff_shape);
@ -3054,8 +3054,8 @@ static void do_vpaint_brush_blur_loops(bContext *C,
const bool use_face_sel = (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
ss, &test, brush->falloff_shape);
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init(
ss, &test, (eBrushFalloffShape)brush->falloff_shape);
const float *sculpt_normal_frontface = SCULPT_brush_frontface_normal_from_falloff_shape(
ss, brush->falloff_shape);
@ -3201,8 +3201,8 @@ static void do_vpaint_brush_blur_verts(bContext *C,
const bool use_face_sel = (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
ss, &test, brush->falloff_shape);
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init(
ss, &test, (eBrushFalloffShape)brush->falloff_shape);
const float *sculpt_normal_frontface = SCULPT_brush_frontface_normal_from_falloff_shape(
ss, brush->falloff_shape);
@ -3357,8 +3357,8 @@ static void do_vpaint_brush_smear(bContext *C,
if (cache->is_last_valid && (normalize_v3(brush_dir) != 0.0f)) {
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
ss, &test, brush->falloff_shape);
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init(
ss, &test, (eBrushFalloffShape)brush->falloff_shape);
const float *sculpt_normal_frontface = SCULPT_brush_frontface_normal_from_falloff_shape(
ss, brush->falloff_shape);
@ -3523,8 +3523,8 @@ static void calculate_average_color(VPaintData<Color, Traits, domain> *vpd,
memset(accum2->value, 0, sizeof(accum2->value));
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
ss, &test, brush->falloff_shape);
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init(
ss, &test, (eBrushFalloffShape)brush->falloff_shape);
/* For each vertex */
PBVHVertexIter vd;
@ -3641,8 +3641,8 @@ static void vpaint_do_draw(bContext *C,
const bool use_face_sel = (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
ss, &test, brush->falloff_shape);
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init(
ss, &test, (eBrushFalloffShape)brush->falloff_shape);
const float *sculpt_normal_frontface = SCULPT_brush_frontface_normal_from_falloff_shape(
ss, brush->falloff_shape);

View File

@ -2984,11 +2984,13 @@ void ED_sculpt_redraw_planes_get(float planes[4][4], ARegion *region, Object *ob
/************************ Brush Testing *******************/
void SCULPT_brush_test_init(SculptSession *ss, SculptBrushTest *test)
static void sculpt_brush_test_init(const SculptSession *ss, SculptBrushTest *test)
{
RegionView3D *rv3d = ss->cache ? ss->cache->vc->rv3d : ss->rv3d;
View3D *v3d = ss->cache ? ss->cache->vc->v3d : ss->v3d;
test->tip_roundness = test->tip_scale_x = 1.0f;
test->radius_squared = ss->cache ? ss->cache->radius_squared :
ss->cursor_radius * ss->cursor_radius;
test->radius = sqrtf(test->radius_squared);
@ -3051,6 +3053,28 @@ bool SCULPT_brush_test_sphere(SculptBrushTest *test, const float co[3])
return true;
}
bool SCULPT_brush_test_cube_sq(SculptBrushTest *test, const float co[3])
{
if (SCULPT_brush_test_cube(test, co, test->cube_matrix, test->tip_roundness, true)) {
test->dist *= test->dist * test->radius_squared;
return true;
}
return false;
}
bool SCULPT_brush_test_thru_cube_sq(SculptBrushTest *test, const float co[3])
{
if (SCULPT_brush_test_cube(test, co, test->cube_matrix, test->tip_roundness, false)) {
test->dist *= test->dist * test->radius_squared;
return true;
}
return false;
}
bool SCULPT_brush_test_sphere_sq(SculptBrushTest *test, const float co[3])
{
float distsq = len_squared_v3v3(co, test->location);
@ -3094,7 +3118,8 @@ bool SCULPT_brush_test_circle_sq(SculptBrushTest *test, const float co[3])
bool SCULPT_brush_test_cube(SculptBrushTest *test,
const float co[3],
const float local[4][4],
const float roundness)
const float roundness,
bool test_z)
{
float side = M_SQRT1_2;
float local_co[3];
@ -3116,7 +3141,7 @@ bool SCULPT_brush_test_cube(SculptBrushTest *test,
const float constant_side = hardness * side;
const float falloff_side = roundness * side;
if (!(local_co[0] <= side && local_co[1] <= side && local_co[2] <= side)) {
if (!(local_co[0] <= side && local_co[1] <= side && (!test_z || local_co[2] <= side))) {
/* Outside the square. */
return false;
}
@ -3138,20 +3163,140 @@ bool SCULPT_brush_test_cube(SculptBrushTest *test,
return true;
}
SculptBrushTestFn SCULPT_brush_test_init_with_falloff_shape(SculptSession *ss,
SculptBrushTest *test,
char falloff_shape)
SculptBrushTestFn SCULPT_brush_test_init(const SculptSession *ss,
SculptBrushTest *test,
eBrushFalloffShape falloff_mode)
{
SCULPT_brush_test_init(ss, test);
SculptBrushTestFn sculpt_brush_test_sq_fn;
if (falloff_shape == PAINT_FALLOFF_SHAPE_SPHERE) {
sculpt_brush_test_sq_fn = SCULPT_brush_test_sphere_sq;
float tip_roundness = 1.0f;
float tip_scale_x = 1.0f;
if (ss->cache && ss->cache->channels_final) {
tip_roundness = SCULPT_get_float(ss, tip_roundness, NULL, NULL);
tip_scale_x = SCULPT_get_float(ss, tip_scale_x, NULL, NULL);
}
return SCULPT_brush_test_init_ex(ss, test, falloff_mode, tip_roundness, tip_scale_x);
}
SculptBrushTestFn SCULPT_brush_test_init_ex(const SculptSession *ss,
SculptBrushTest *test,
eBrushFalloffShape falloff_mode,
float tip_roundness,
float tip_scale_x)
{
sculpt_brush_test_init(ss, test);
SculptBrushTestFn sculpt_brush_test_sq_fn = NULL;
test->tip_roundness = tip_roundness;
test->tip_scale_x = tip_scale_x;
if (tip_roundness != 1.0f || tip_scale_x != 1.0f) {
float mat[4][4], tmat[4][4], scale[4][4];
float grab_delta[3];
copy_v3_v3(grab_delta, ss->cache->grab_delta_symmetry);
if (dot_v3v3(grab_delta, grab_delta) < 0.0001f) {
/* First time, use cached grab delta. */
copy_v3_v3(grab_delta, ss->last_grab_delta);
flip_v3_v3(grab_delta, grab_delta, ss->cache->mirror_symmetry_pass);
mul_m4_v3(ss->cache->symm_rot_mat, grab_delta);
}
if (dot_v3v3(grab_delta, grab_delta) < 0.0001f) {
/* Grab_delta still zero? Use cross of view and normal vectors. */
cross_v3_v3v3(grab_delta, ss->cache->view_normal, ss->cache->sculpt_normal);
}
if (dot_v3v3(grab_delta, grab_delta) < 0.0001f) {
/* Still zero? */
int axis;
float ax = fabsf(ss->cache->view_normal[0]);
float ay = fabsf(ss->cache->view_normal[1]);
float az = fabsf(ss->cache->view_normal[2]);
if (ax > ay && ax > az) {
axis = 1;
}
else if (ay > ax && ay > az) {
axis = 2;
}
else {
axis = 0;
}
grab_delta[axis] = 1.0f;
}
cross_v3_v3v3(mat[0], ss->cache->cached_area_normal, grab_delta);
mat[0][3] = 0;
cross_v3_v3v3(mat[1], ss->cache->cached_area_normal, mat[0]);
mat[1][3] = 0;
copy_v3_v3(mat[2], ss->cache->cached_area_normal);
mat[2][3] = 0;
copy_v3_v3(mat[3], ss->cache->location);
mat[3][3] = 1;
normalize_m4(mat);
if (determinant_m4(mat) < 0.000001f) {
fprintf(stderr, "%s: Matrix error 1\n", __func__);
unit_m4(mat);
}
scale_m4_fl(scale, ss->cache->radius);
mul_m4_m4m4(tmat, mat, scale);
mul_v3_fl(tmat[1], tip_scale_x);
if (determinant_m4(tmat) < 0.000001f) {
fprintf(stderr, "%s: Matrix error 2\n", __func__);
unit_m4(tmat);
}
invert_m4_m4(mat, tmat);
copy_m4_m4(test->cube_matrix, mat);
switch (falloff_mode) {
case PAINT_FALLOFF_SHAPE_SPHERE:
sculpt_brush_test_sq_fn = SCULPT_brush_test_cube_sq;
case PAINT_FALLOFF_SHAPE_TUBE:
if (ss->cache) {
plane_from_point_normal_v3(test->plane_view, test->location, ss->cache->view_normal);
}
else {
zero_v3(test->plane_view);
test->plane_view[2] = 1.0f;
}
sculpt_brush_test_sq_fn = SCULPT_brush_test_thru_cube_sq;
case PAINT_FALLOFF_NOOP:
break;
}
}
else {
/* PAINT_FALLOFF_SHAPE_TUBE */
plane_from_point_normal_v3(test->plane_view, test->location, ss->cache->view_normal);
sculpt_brush_test_sq_fn = SCULPT_brush_test_circle_sq;
switch (falloff_mode) {
case PAINT_FALLOFF_SHAPE_SPHERE:
sculpt_brush_test_sq_fn = SCULPT_brush_test_sphere_sq;
case PAINT_FALLOFF_SHAPE_TUBE:
if (ss->cache) {
plane_from_point_normal_v3(test->plane_view, test->location, ss->cache->view_normal);
}
else {
zero_v3(test->plane_view);
test->plane_view[2] = 1.0f;
}
sculpt_brush_test_sq_fn = SCULPT_brush_test_circle_sq;
case PAINT_FALLOFF_NOOP:
break;
}
}
return sculpt_brush_test_sq_fn;
}
@ -3319,8 +3464,8 @@ static void calc_area_normal_and_center_task_cb(void *__restrict userdata,
}
SculptBrushTest normal_test;
SculptBrushTestFn sculpt_brush_normal_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
ss, &normal_test, data->brush->falloff_shape);
SculptBrushTestFn sculpt_brush_normal_test_sq_fn = SCULPT_brush_test_init_ex(
ss, &normal_test, data->brush->falloff_shape, 1.0f, 1.0f);
/* Update the test radius to sample the normal using the normal radius of the brush. */
if (data->brush->ob_mode == OB_MODE_SCULPT) {
@ -3331,8 +3476,8 @@ static void calc_area_normal_and_center_task_cb(void *__restrict userdata,
}
SculptBrushTest area_test;
SculptBrushTestFn sculpt_brush_area_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
ss, &area_test, data->brush->falloff_shape);
SculptBrushTestFn sculpt_brush_area_test_sq_fn = SCULPT_brush_test_init_ex(
ss, &area_test, data->brush->falloff_shape, 1.0f, 1.0f);
if (data->brush->ob_mode == OB_MODE_SCULPT) {
float test_radius = sqrtf(area_test.radius_squared);
@ -3704,34 +3849,58 @@ off fort;
*/
ATTR_NO_OPT float dcubic(float k1, float k2, float k3, float k4, float t)
float bezier3_derivative(float k1, float k2, float k3, float k4, float t)
{
return -3.0f * ((t - 1.0f) * (t - 1.0f) * k1 - k4 * t * t + (3.0f * t - 2.0f) * k3 * t -
(3.0f * t - 1.0f) * (t - 1.0f) * k2);
}
ATTR_NO_OPT float cubic_arclen(const float control[4][3])
void bezier3_derivative_v3(float r_out[3], float control[4][3], float t)
{
r_out[0] = bezier3_derivative(control[0][0], control[1][0], control[2][0], control[3][0], t);
r_out[1] = bezier3_derivative(control[0][1], control[1][1], control[2][1], control[3][1], t);
r_out[2] = bezier3_derivative(control[0][2], control[1][2], control[2][2], control[3][2], t);
}
float bezier3_arclength_v3(const float control[4][3])
{
const int steps = 2048;
float t = 0.0f, dt = 1.0f / (float)steps;
float arc = 0.0f;
for (int i = 0; i < steps; i++, t += dt) {
float dx = dcubic(control[0][0], control[1][0], control[2][0], control[3][0], t);
float dy = dcubic(control[0][1], control[1][1], control[2][1], control[3][1], t);
float dz = dcubic(control[0][2], control[1][2], control[2][2], control[3][2], t);
float dx = bezier3_derivative(control[0][0], control[1][0], control[2][0], control[3][0], t);
float dy = bezier3_derivative(control[0][1], control[1][1], control[2][1], control[3][1], t);
float dz = bezier3_derivative(control[0][2], control[1][2], control[2][2], control[3][2], t);
arc += sqrtf(dx * dx + dy * dy + dz * dz);
arc += sqrtf(dx * dx + dy * dy + dz * dz) * dt;
}
return arc;
}
float bezier3_arclength_v2(const float control[4][2])
{
const int steps = 2048;
float t = 0.0f, dt = 1.0f / (float)steps;
float arc = 0.0f;
for (int i = 0; i < steps; i++, t += dt) {
float dx = bezier3_derivative(control[0][0], control[1][0], control[2][0], control[3][0], t);
float dy = bezier3_derivative(control[0][1], control[1][1], control[2][1], control[3][1], t);
arc += sqrtf(dx * dx + dy * dy) * dt;
}
return arc;
}
/* Evaluate bezier position and tangent at a specific parameter value
* using the De Casteljau algorithm. */
ATTR_NO_OPT static void evaluate_cubic_bezier(const float control[4][3],
float t,
float r_pos[3],
float r_tangent[3])
static void evaluate_cubic_bezier(const float control[4][3],
float t,
float r_pos[3],
float r_tangent[3])
{
float layer1[3][3];
interp_v3_v3v3(layer1[0], control[0], control[1], t);
@ -3745,12 +3914,12 @@ ATTR_NO_OPT static void evaluate_cubic_bezier(const float control[4][3],
sub_v3_v3v3(r_tangent, layer2[1], layer2[0]);
madd_v3_v3v3fl(r_pos, layer2[0], r_tangent, t);
r_tangent[0] = dcubic(control[0][0], control[1][0], control[2][0], control[3][0], t);
r_tangent[1] = dcubic(control[0][1], control[1][1], control[2][1], control[3][1], t);
r_tangent[2] = dcubic(control[0][2], control[1][2], control[2][2], control[3][2], t);
r_tangent[0] = bezier3_derivative(control[0][0], control[1][0], control[2][0], control[3][0], t);
r_tangent[1] = bezier3_derivative(control[0][1], control[1][1], control[2][1], control[3][1], t);
r_tangent[2] = bezier3_derivative(control[0][2], control[1][2], control[2][2], control[3][2], t);
}
ATTR_NO_OPT static float cubic_uv_test(const float co[3], const float p[3], const float tan[3])
static float cubic_uv_test(const float co[3], const float p[3], const float tan[3])
{
float tmp[3];
@ -3758,12 +3927,10 @@ ATTR_NO_OPT static float cubic_uv_test(const float co[3], const float p[3], cons
return dot_v3v3(tmp, tan);
}
ATTR_NO_OPT static void calc_cubic_uv_v3(const float cubic[4][3],
const float co[3],
float r_out[2])
static void calc_cubic_uv_v3(const float cubic[4][3], const float co[3], float r_out[2])
{
const int steps = 5;
const int binary_steps = 5;
const int binary_steps = 10;
float dt = 1.0f / (float)steps, t = dt;
float lastp[3];
@ -4018,15 +4185,15 @@ static float brush_strength(const Sculpt *sd,
}
}
ATTR_NO_OPT float SCULPT_brush_strength_factor(SculptSession *ss,
const Brush *br,
const float brush_point[3],
const float len,
const float vno[3],
const float fno[3],
const float mask,
const SculptVertRef vertex_index,
const int thread_id)
float SCULPT_brush_strength_factor(SculptSession *ss,
const Brush *br,
const float brush_point[3],
const float len,
const float vno[3],
const float fno[3],
const float mask,
const SculptVertRef vertex_index,
const int thread_id)
{
StrokeCache *cache = ss->cache;
const Scene *scene = cache->vc->scene;
@ -4087,23 +4254,63 @@ ATTR_NO_OPT float SCULPT_brush_strength_factor(SculptSession *ss,
calc_cubic_uv_v3(ss->cache->world_cubic, SCULPT_vertex_co_get(ss, vertex_index), point_3d);
if (point_3d[0] == 0.0f || point_3d[0] == 1.0f) {
float eps = 0.001;
if (point_3d[0] < eps || point_3d[0] >= 1.0f - eps) {
return 0.0f;
}
point_3d[1] /= ss->cache->radius;
if (point_3d[1] >= ss->cache->radius) {
// return 0.0f;
}
//point_3d[0] = ss->cache->input_mapping.stroke_t + point_3d[0] * ss->cache->world_cubic_arclength;
point_3d[0] -= floorf(point_3d[0]);
float pos[3], tan[3];
evaluate_cubic_bezier(ss->cache->world_cubic, point_3d[0], pos, tan);
float vec[3], vec2[3];
normalize_v3(tan);
sub_v3_v3v3(vec, SCULPT_vertex_co_get(ss, vertex_index), pos);
normalize_v3(vec);
cross_v3_v3v3(vec2, vec, tan);
if (dot_v3v3(vec2, ss->cache->view_normal) < 0.0) {
point_3d[1] = (ss->cache->radius + point_3d[1]) * 0.5f;
}
else {
point_3d[1] = (ss->cache->radius - point_3d[1]) * 0.5f;
}
float t1 = ss->cache->last_stroke_distance_t;
float t2 = point_3d[0] * ss->cache->world_cubic_arclength / ss->cache->radius;
point_3d[0] = t1 + t2;
point_3d[0] *= ss->cache->radius;
#if 0
float color[4] = {point_3d[0], point_3d[0], point_3d[0], 1.0f};
mul_v3_fl(color, 0.25f / ss->cache->radius);
color[0] -= floorf(color[0]);
color[1] -= floorf(color[1]);
color[2] -= floorf(color[2]);
float color[4] = {point_3d[0], point_3d[1], 0.0f, 1.0f};
SCULPT_vertex_color_set(ss, vertex_index, color);
avg = BKE_brush_sample_tex_3d(scene, br, point_3d, rgba, 0, ss->tex_pool);
// avg = 0.0f;
#endif
//#else
// point_3d[0] /= ss->cache->radius;
// point_3d[0] -= floorf(point_3d[0]);
float pixel_radius = br->size;
mul_v3_fl(point_3d, pixel_radius / ss->cache->radius);
avg = BKE_brush_sample_tex_3d(scene, br, point_3d, rgba, thread_id, ss->tex_pool);
//#endif
}
else {
const float point_3d[3] = {point_2d[0], point_2d[1], 0.0f};
avg = BKE_brush_sample_tex_3d(scene, br, point_3d, rgba, 0, ss->tex_pool);
avg = BKE_brush_sample_tex_3d(scene, br, point_3d, rgba, thread_id, ss->tex_pool);
}
}
@ -4714,7 +4921,7 @@ static void do_gravity_task_cb_ex(void *__restrict userdata,
proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init(
ss, &test, data->brush->falloff_shape);
const int thread_id = BLI_task_parallel_thread_id(tls);
@ -5128,6 +5335,10 @@ static void get_nodes_undo(Sculpt *sd,
float radius_scale = 1.0f;
const bool use_original = sculpt_tool_needs_original(cmd->tool) ? true : ss->cache->original;
if (BRUSHSET_GET_FLOAT(cmd->params_mapped, tip_roundness, &ss->cache->input_mapping) != 1.0f) {
radius_scale *= sqrtf(2.0f);
}
if (SCULPT_tool_needs_all_pbvh_nodes(brush)) {
/* These brushes need to update all nodes as they are not constrained by the brush radius
*/
@ -5280,6 +5491,12 @@ static void sculpt_apply_alt_smmoth_settings(SculptSession *ss, Sculpt *sd, Brus
BRUSHSET_LOOKUP(ss->cache->channels_final, projection), ch, parentch, false, true);
}
bool SCULPT_needs_area_normal(SculptSession *ss, Sculpt *sd, Brush *brush)
{
return SCULPT_get_float(ss, tip_roundness, sd, brush) != 1.0f ||
SCULPT_get_float(ss, tip_scale_x, sd, brush) != 1.0f;
}
static void SCULPT_run_command(Sculpt *sd,
Object *ob,
Brush *brush,
@ -5313,7 +5530,7 @@ static void SCULPT_run_command(Sculpt *sd,
Brush _brush2, *brush2 = &_brush2;
/*
* Check that original data is for anchored and drag dot modes
* Check that original data exists for anchored and drag dot modes
*/
if (brush->flag & (BRUSH_ANCHORED | BRUSH_DRAG_DOT)) {
for (int i = 0; i < totnode; i++) {
@ -5378,6 +5595,14 @@ static void SCULPT_run_command(Sculpt *sd,
/*Search PBVH*/
if (SCULPT_needs_area_normal(ss, sd, brush2)) {
SCULPT_calc_area_normal(sd, ob, nodes, totnode, ss->cache->cached_area_normal);
if (dot_v3v3(ss->cache->cached_area_normal, ss->cache->cached_area_normal) == 0.0f) {
ss->cache->cached_area_normal[2] = 1.0f;
}
}
if (sculpt_brush_needs_normal(ss, brush2)) {
update_sculpt_normal(sd, ob, nodes, totnode);
}
@ -6853,6 +7078,9 @@ static void sculpt_update_brush_delta(UnifiedPaintSettings *ups, Object *ob, Bru
SCULPT_TOOL_ARRAY,
SCULPT_TOOL_THUMB);
bad = bad && SCULPT_get_float(ss, tip_roundness, NULL, brush) == 1.0f;
bad = bad && SCULPT_get_float(ss, tip_scale_x, NULL, brush) == 1.0f;
bad = bad && !sculpt_brush_use_topology_rake(ss, brush);
bad = bad && !SCULPT_get_bool(ss, use_autofset, NULL, brush);
@ -6981,6 +7209,10 @@ static void sculpt_update_brush_delta(UnifiedPaintSettings *ups, Object *ob, Bru
}
}
if (dot_v3v3(cache->grab_delta, cache->grab_delta) > 0.0f) {
copy_v3_v3(ss->last_grab_delta, cache->grab_delta);
}
// XXX implement me
if (SCULPT_get_int(ss, use_smoothed_rake, NULL, brush)) {
@ -7125,10 +7357,7 @@ static float sculpt_update_speed_average(SculptSession *ss, float speed)
return speed / (float)tot;
}
/* Initialize the stroke cache variants from operator properties. */
ATTR_NO_OPT static void sculpt_update_cache_variants(bContext *C,
Sculpt *sd,
Object *ob,
PointerRNA *ptr)
static void sculpt_update_cache_variants(bContext *C, Sculpt *sd, Object *ob, PointerRNA *ptr)
{
Scene *scene = CTX_data_scene(C);
UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
@ -7143,6 +7372,43 @@ ATTR_NO_OPT static void sculpt_update_cache_variants(bContext *C,
RNA_float_get_array(ptr, "location", cache->true_location);
}
/*
* Make sure last_grab_delta, which controls tip rotation on
* first brush dab, is not zero.
*/
if (dot_v3v3(ss->last_grab_delta, ss->last_grab_delta) == 0.0f) {
int axis;
float mat[4][4];
ED_view3d_ob_project_mat_get(cache->vc->rv3d, ob, mat);
invert_m4(mat);
float dx = mat[0][0];
float dy = mat[1][1];
float dz = mat[2][2];
float ax = fabsf(dx);
float ay = fabsf(dy);
float az = fabsf(dz);
float sign;
if (ax > ay && ax > az) {
axis = 1;
sign = dx < 0.0f ? -1.0f : 1.0f;
}
else if (ay > ax && ay > az) {
axis = 2;
sign = dy < 0.0f ? -1.0f : 1.0f;
}
else {
axis = 0;
sign = dz < 0.0f ? -1.0f : 1.0f;
}
ss->last_grab_delta[axis] = sign;
}
float last_mouse[2];
copy_v2_v2(last_mouse, cache->mouse);
@ -7275,13 +7541,18 @@ ATTR_NO_OPT static void sculpt_update_cache_variants(bContext *C,
10.0f; /*scale to a more user-friendly value*/
if (cache->has_cubic) {
RNA_float_get_array(ptr, "mouse_cubic", (float *)cache->mouse_cubic);
float mouse_cubic[4][2];
printf("\n");
RNA_float_get_array(ptr, "mouse_cubic", (float *)mouse_cubic);
// printf("\n");
/* Project mouse cubic into 3d space. */
for (int i = 0; i < 4; i++) {
if (!SCULPT_stroke_get_location(C, cache->world_cubic[i], cache->mouse_cubic[i])) {
copy_v2_v2(cache->mouse_cubic[i], mouse_cubic[i]);
cache->mouse_cubic[i][2] = 0.0f;
if (!SCULPT_stroke_get_location(C, cache->world_cubic[i], mouse_cubic[i])) {
float loc[3];
mul_v3_m4v3(loc, ob->obmat, cache->true_location);
@ -7289,11 +7560,11 @@ ATTR_NO_OPT static void sculpt_update_cache_variants(bContext *C,
ED_view3d_win_to_3d(CTX_wm_view3d(C),
CTX_wm_region(C),
cache->true_location,
cache->mouse_cubic[i],
mouse_cubic[i],
cache->world_cubic[i]);
}
#if 1
#if 0
printf("%.2f, %.2f %.2f\n",
cache->world_cubic[i][0],
cache->world_cubic[i][1],
@ -7301,7 +7572,8 @@ ATTR_NO_OPT static void sculpt_update_cache_variants(bContext *C,
#endif
}
cache->world_cubic_arclength = cubic_arclen(cache->world_cubic);
cache->world_cubic_arclength = bezier3_arclength_v3(cache->world_cubic);
cache->mouse_cubic_arclength = bezier3_arclength_v3(cache->mouse_cubic);
}
}
@ -8090,17 +8362,17 @@ static void sculpt_cache_dyntopo_settings(BrushChannelSet *chset,
r_settings->flag = BRUSHSET_GET_INT(chset, dyntopo_mode, NULL);
r_settings->mode = BRUSHSET_GET_INT(chset, dyntopo_detail_mode, NULL);
r_settings->radius_scale = BRUSHSET_GET_FLOAT(chset, dyntopo_radius_scale, input_data);
r_settings->spacing = BRUSHSET_GET_FLOAT(chset, dyntopo_spacing, input_data);
r_settings->spacing = (int)BRUSHSET_GET_FLOAT(chset, dyntopo_spacing, input_data);
r_settings->detail_size = BRUSHSET_GET_FLOAT(chset, dyntopo_detail_size, input_data);
r_settings->detail_range = BRUSHSET_GET_FLOAT(chset, dyntopo_detail_range, input_data);
r_settings->detail_percent = BRUSHSET_GET_FLOAT(chset, dyntopo_detail_percent, input_data);
r_settings->constant_detail = BRUSHSET_GET_FLOAT(chset, dyntopo_constant_detail, input_data);
};
ATTR_NO_OPT static void sculpt_stroke_update_step(bContext *C,
wmOperator *UNUSED(op),
struct PaintStroke *stroke,
PointerRNA *itemptr)
static void sculpt_stroke_update_step(bContext *C,
wmOperator *UNUSED(op),
struct PaintStroke *stroke,
PointerRNA *itemptr)
{
@ -8182,8 +8454,10 @@ ATTR_NO_OPT static void sculpt_stroke_update_step(bContext *C,
}
ss->cache->stroke_distance = stroke->stroke_distance;
ss->cache->last_stroke_distance_t = ss->cache->stroke_distance_t;
ss->cache->stroke_distance_t = stroke->stroke_distance_t;
ss->cache->stroke = stroke;
ss->cache->stroke_spacing_t = SCULPT_get_float(ss, spacing, sd, brush) / 100.0f;
if (SCULPT_stroke_is_first_brush_step(ss->cache)) {
ss->cache->last_dyntopo_t = 0.0f;

View File

@ -229,7 +229,7 @@ typedef float (*SculptBrushTestFn)(SculptBrushTest *test, float *co);
typedef bool (*BKE_pbvh_SearchCallback)(PBVHNode *node, void *data);
void BKE_pbvh_search_gather(
PBVH *pbvh, BKE_pbvh_SearchCallback scb, void *search_data, PBVHNode ***array, int *tot);
SculptBrushTestFn SCULPT_brush_test_init_with_falloff_shape(struct SculptSession *ss,
SculptBrushTestFn SCULPT_brush_test_init(struct SculptSession *ss,
SculptBrushTest *test,
char falloff_shape);
bool SCULPT_search_sphere_cb(PBVHNode *node, void *data_v);
@ -747,7 +747,7 @@ class BMeshPBVH {
if (!args->test) {
args->test = &default_test;
args->test_func = SCULPT_brush_test_init_with_falloff_shape(
args->test_func = SCULPT_brush_test_init(
_ss, &default_test, /*args->brush->falloff_shape*/ 0);
}
@ -859,7 +859,7 @@ class SculptImpl {
BKE_curvemapping_init(brush->curve);
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init(
ss, &test, ss->cache->brush->falloff_shape);
/*

View File

@ -322,7 +322,7 @@ static void do_draw_brush_task_cb_ex(void *__restrict userdata,
proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init(
ss, &test, data->brush->falloff_shape);
const int thread_id = BLI_task_parallel_thread_id(tls);
@ -404,7 +404,7 @@ static void do_twist_brush_task_cb_ex(void *__restrict userdata,
const float bstrength = flip ? -ss->cache->bstrength : ss->cache->bstrength;
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init(
ss, &test, data->brush->falloff_shape);
const int thread_id = BLI_task_parallel_thread_id(tls);
@ -484,7 +484,7 @@ static void do_twist_brush_post_smooth_task_cb_ex(void *__restrict userdata,
PBVHVertexIter vd;
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init(
ss, &test, data->brush->falloff_shape);
const int thread_id = BLI_task_parallel_thread_id(tls);
@ -681,7 +681,7 @@ static void do_fill_brush_task_cb_ex(void *__restrict userdata,
proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init(
ss, &test, data->brush->falloff_shape);
const int thread_id = BLI_task_parallel_thread_id(tls);
@ -780,7 +780,7 @@ static void do_scrape_brush_task_cb_ex(void *__restrict userdata,
proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init(
ss, &test, data->brush->falloff_shape);
const int thread_id = BLI_task_parallel_thread_id(tls);
plane_from_point_normal_v3(test.plane_tool, area_co, area_no);
@ -883,7 +883,7 @@ static void do_clay_thumb_brush_task_cb_ex(void *__restrict userdata,
proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init(
ss, &test, data->brush->falloff_shape);
const int thread_id = BLI_task_parallel_thread_id(tls);
@ -1056,7 +1056,7 @@ static void do_flatten_brush_task_cb_ex(void *__restrict userdata,
proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init(
ss, &test, data->brush->falloff_shape);
const int thread_id = BLI_task_parallel_thread_id(tls);
@ -1154,7 +1154,7 @@ static void calc_clay_surface_task_cb(void *__restrict userdata,
PBVHVertexIter vd;
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init(
ss, &test, brush->falloff_shape);
/* Apply the brush normal radius to the test before sampling. */
@ -1211,7 +1211,7 @@ static void do_clay_brush_task_cb_ex(void *__restrict userdata,
proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init(
ss, &test, data->brush->falloff_shape);
const int thread_id = BLI_task_parallel_thread_id(tls);
@ -1336,12 +1336,16 @@ static void do_clay_strips_brush_task_cb_ex(void *__restrict userdata,
proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
SCULPT_brush_test_init(ss, &test);
SCULPT_brush_test_init(ss, &test, PAINT_FALLOFF_NOOP);
plane_from_point_normal_v3(test.plane_tool, area_co, area_no_sp);
const int thread_id = BLI_task_parallel_thread_id(tls);
BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
if (!SCULPT_brush_test_cube(&test, vd.co, mat, brush->tip_roundness)) {
if (!SCULPT_brush_test_cube(&test,
vd.co,
mat,
brush->tip_roundness,
brush->falloff_shape != PAINT_FALLOFF_SHAPE_TUBE)) {
continue;
}
@ -1503,7 +1507,7 @@ static void do_snake_hook_brush_task_cb_ex(void *__restrict userdata,
proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init(
ss, &test, data->brush->falloff_shape);
const int thread_id = BLI_task_parallel_thread_id(tls);
@ -1644,7 +1648,7 @@ static void do_thumb_brush_task_cb_ex(void *__restrict userdata,
proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init(
ss, &test, data->brush->falloff_shape);
const int thread_id = BLI_task_parallel_thread_id(tls);
@ -1714,7 +1718,7 @@ static void do_rotate_brush_task_cb_ex(void *__restrict userdata,
proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init(
ss, &test, data->brush->falloff_shape);
const int thread_id = BLI_task_parallel_thread_id(tls);
@ -1828,7 +1832,7 @@ static void do_layer_brush_task_cb_ex(void *__restrict userdata,
SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n], SCULPT_UNDO_COORDS);
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init(
ss, &test, data->brush->falloff_shape);
const int thread_id = BLI_task_parallel_thread_id(tls);
@ -2108,7 +2112,7 @@ static void do_inflate_brush_task_cb_ex(void *__restrict userdata,
proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init(
ss, &test, data->brush->falloff_shape);
const int thread_id = BLI_task_parallel_thread_id(tls);
@ -2176,7 +2180,7 @@ static void do_nudge_brush_task_cb_ex(void *__restrict userdata,
proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init(
ss, &test, data->brush->falloff_shape);
const int thread_id = BLI_task_parallel_thread_id(tls);
@ -2254,7 +2258,7 @@ static void do_crease_brush_task_cb_ex(void *__restrict userdata,
proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init(
ss, &test, data->brush->falloff_shape);
const int thread_id = BLI_task_parallel_thread_id(tls);
@ -2369,7 +2373,7 @@ static void do_pinch_brush_task_cb_ex(void *__restrict userdata,
proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init(
ss, &test, data->brush->falloff_shape);
const int thread_id = BLI_task_parallel_thread_id(tls);
@ -2486,7 +2490,7 @@ static void do_grab_brush_task_cb_ex(void *__restrict userdata,
proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init(
ss, &test, data->brush->falloff_shape);
const int thread_id = BLI_task_parallel_thread_id(tls);
@ -2737,7 +2741,7 @@ static void do_draw_sharp_brush_task_cb_ex(void *__restrict userdata,
proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init(
ss, &test, data->brush->falloff_shape);
const int thread_id = BLI_task_parallel_thread_id(tls);
@ -2793,7 +2797,7 @@ static void do_draw_sharp_brush_task_cb_ex_plane(void *__restrict userdata,
proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init(
ss, &test, data->brush->falloff_shape);
const int thread_id = BLI_task_parallel_thread_id(tls);
@ -3030,7 +3034,7 @@ static void do_scene_project_brush_task_cb_ex(void *__restrict userdata,
SculptThreadedTaskData *data = userdata;
SculptSession *ss = data->ob->sculpt;
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init(
ss, &test, data->brush->falloff_shape);
const float bstrength = clamp_f(ss->cache->bstrength, 0.0f, 1.0f);
@ -3147,7 +3151,7 @@ static void do_topology_slide_task_cb_ex(void *__restrict userdata,
proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init(
ss, &test, data->brush->falloff_shape);
const int thread_id = BLI_task_parallel_thread_id(tls);
@ -3318,7 +3322,7 @@ static void do_topology_relax_task_cb_ex(void *__restrict userdata,
BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n]);
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init(
ss, &test, data->brush->falloff_shape);
const int thread_id = BLI_task_parallel_thread_id(tls);
@ -3416,7 +3420,7 @@ static void do_fairing_brush_tag_store_task_cb_ex(void *__restrict userdata,
SculptThreadedTaskData *data = userdata;
SculptSession *ss = data->ob->sculpt;
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init(
ss, &test, data->brush->falloff_shape);
PBVHVertexIter vd;
@ -3722,7 +3726,7 @@ static void do_displacement_eraser_brush_task_cb_ex(void *__restrict userdata,
float(*proxy)[3] = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init(
ss, &test, data->brush->falloff_shape);
const int thread_id = BLI_task_parallel_thread_id(tls);
@ -3785,7 +3789,7 @@ static void do_displacement_smear_brush_task_cb_ex(void *__restrict userdata,
const float bstrength = clamp_f(ss->cache->bstrength, 0.0f, 1.0f);
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init(
ss, &test, data->brush->falloff_shape);
const int thread_id = BLI_task_parallel_thread_id(tls);
@ -3952,7 +3956,7 @@ static void do_topology_rake_bmesh_task_cb_ex(void *__restrict userdata,
const float bstrength = sqrtf(clamp_f(data->strength, 0.0f, 1.0f));
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init(
ss, &test, data->brush->falloff_shape);
const int thread_id = BLI_task_parallel_thread_id(tls);
@ -4098,7 +4102,7 @@ void SCULPT_bmesh_topology_rake(Sculpt *sd,
PBVHVertexIter vd;
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init(
ss, &test, brush->falloff_shape);
BKE_pbvh_vertex_iter_begin (ss->pbvh, node, vd, PBVH_ITER_UNIQUE) {
@ -4180,7 +4184,7 @@ static void do_mask_brush_draw_task_cb_ex(void *__restrict userdata,
PBVHVertexIter vd;
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init(
ss, &test, data->brush->falloff_shape);
const int thread_id = BLI_task_parallel_thread_id(tls);

View File

@ -1265,7 +1265,7 @@ static void do_cloth_brush_apply_forces_task_cb_ex(void *__restrict userdata,
const float bstrength = ss->cache->bstrength;
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init(
ss, &test, data->brush->falloff_shape);
const int thread_id = BLI_task_parallel_thread_id(tls);

View File

@ -1609,7 +1609,7 @@ static void sculpt_uv_brush_cb(void *__restrict userdata,
// const float *offset = data->offset;
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init(
ss, &test, data->brush->falloff_shape);
PBVHNode *node = data->nodes[n];
@ -1767,7 +1767,7 @@ void SCULPT_uv_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
uvsolver_solve_begin(solver);
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init(
ss, &test, brush->falloff_shape);
BLI_mempool_iter iter;

View File

@ -367,7 +367,7 @@ void do_draw_face_sets_brush_task_cb_ex(void *__restrict userdata,
PBVHVertexIter vd;
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init(
ss, &test, data->brush->falloff_shape);
const int thread_id = BLI_task_parallel_thread_id(tls);
@ -637,7 +637,7 @@ static void do_relax_face_sets_brush_task_cb_ex(void *__restrict userdata,
PBVHVertexIter vd;
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init(
ss, &test, data->brush->falloff_shape);
const bool relax_face_sets = !(ss->cache->iteration_count % 3 == 0);

View File

@ -444,6 +444,11 @@ typedef struct SculptBrushTest {
int radial_symmetry_pass;
float symm_rot_mat_inv[4][4];
float tip_roundness;
float tip_scale_x;
float cube_matrix[4][4];
/* For circle (not sphere) projection. */
float plane_view[4];
@ -604,6 +609,8 @@ typedef struct StrokeCache {
float sculpt_normal[3];
float sculpt_normal_symm[3];
float cached_area_normal[3];
/* Used for area texture mode, local_mat gets calculated by
* calc_brush_local_mat() and used in tex_strength(). */
float brush_local_mat[4][4];
@ -692,6 +699,8 @@ typedef struct StrokeCache {
float stroke_distance; // copy of PaintStroke->stroke_distance
float stroke_distance_t; // copy of PaintStroke->stroke_distance_t
float stroke_spacing_t;
float last_stroke_distance_t;
float last_dyntopo_t;
float last_smooth_t[SCULPT_MAX_SYMMETRY_PASSES];
@ -715,9 +724,10 @@ typedef struct StrokeCache {
int tool_override;
BrushChannelSet *tool_override_channels;
float mouse_cubic[4][2];
float mouse_cubic[4][3];
float world_cubic[4][3];
float world_cubic_arclength;
float mouse_cubic_arclength;
bool has_cubic;
} StrokeCache;
@ -1483,9 +1493,20 @@ void SCULPT_flip_quat_by_symm_area(float quat[4],
const float pivot[3]);
/**
* Initialize a point-in-brush test
* Initialize a point-in-brush test with a given falloff shape.
*
* \param falloff_shape: #PAINT_FALLOFF_SHAPE_SPHERE, #PAINT_FALLOFF_SHAPE_TUBE or
* #PAINT_FALLOFF_SHAPE_NOOP \return The brush falloff function, or nullptr if falloff_shape was
* #PAINT_FALLOFF_SHAPE_NOOP
*/
void SCULPT_brush_test_init(struct SculptSession *ss, SculptBrushTest *test);
SculptBrushTestFn SCULPT_brush_test_init(const SculptSession *ss,
SculptBrushTest *test,
eBrushFalloffShape falloff_mode);
SculptBrushTestFn SCULPT_brush_test_init_ex(const SculptSession *ss,
SculptBrushTest *test,
eBrushFalloffShape falloff_mode,
float tip_roundness,
float tip_scale_x);
bool SCULPT_brush_test_sphere(SculptBrushTest *test, const float co[3]);
bool SCULPT_brush_test_sphere_sq(SculptBrushTest *test, const float co[3]);
@ -1493,7 +1514,8 @@ bool SCULPT_brush_test_sphere_fast(const SculptBrushTest *test, const float co[3
bool SCULPT_brush_test_cube(SculptBrushTest *test,
const float co[3],
const float local[4][4],
float roundness);
float roundness,
bool test_z);
bool SCULPT_brush_test_circle_sq(SculptBrushTest *test, const float co[3]);
/**
* Test AABB against sphere.
@ -1504,15 +1526,6 @@ bool SCULPT_search_sphere_cb(PBVHNode *node, void *data_v);
*/
bool SCULPT_search_circle_cb(PBVHNode *node, void *data_v);
/**
* Initialize a point-in-brush test with a given falloff shape.
*
* \param falloff_shape: #PAINT_FALLOFF_SHAPE_SPHERE or #PAINT_FALLOFF_SHAPE_TUBE.
* \return The brush falloff function.
*/
SculptBrushTestFn SCULPT_brush_test_init_with_falloff_shape(SculptSession *ss,
SculptBrushTest *test,
char falloff_shape);
const float *SCULPT_brush_frontface_normal_from_falloff_shape(SculptSession *ss,
char falloff_shape);
@ -2602,6 +2615,7 @@ void SCULPT_dyntopo_automasking_end(void *mask_data);
#define BOUNDARY_SMOOTH_EXP 2.0
#define SCULPT_TOOL_NEEDS_COLOR(tool) ELEM(tool, SCULPT_TOOL_PAINT, SCULPT_TOOL_SMEAR)
bool SCULPT_needs_area_normal(SculptSession *ss, Sculpt *sd, Brush *brush);
#ifdef __cplusplus
}

View File

@ -60,7 +60,7 @@ static void calc_multiplane_scrape_surface_task_cb(void *__restrict userdata,
PBVHVertexIter vd;
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init(
ss, &test, brush->falloff_shape);
const int thread_id = BLI_task_parallel_thread_id(tls);
@ -140,7 +140,7 @@ static void do_multiplane_scrape_brush_task_cb_ex(void *__restrict userdata,
proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init(
ss, &test, data->brush->falloff_shape);
const int thread_id = BLI_task_parallel_thread_id(tls);

View File

@ -66,7 +66,7 @@ static void do_color_smooth_task_cb_exec(void *__restrict userdata,
PBVHVertexIter vd;
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init(
ss, &test, data->brush->falloff_shape);
const int thread_id = BLI_task_parallel_thread_id(tls);
@ -118,7 +118,7 @@ static void do_paint_brush_task_cb_ex(void *__restrict userdata,
PBVHVertexIter vd;
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init(
ss, &test, data->brush->falloff_shape);
const int thread_id = BLI_task_parallel_thread_id(tls);
@ -143,6 +143,9 @@ static void do_paint_brush_task_cb_ex(void *__restrict userdata,
float alpha = BKE_brush_channelset_get_final_float(
BKE_paint_brush(&data->sd->paint)->channels, data->sd->channels, "strength", NULL);
bool do_test = brush->mtex.brush_map_mode != MTEX_MAP_MODE_ROLL &&
brush->mtex.brush_map_mode != MTEX_MAP_MODE_ROLL;
BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
// SCULPT_orig_vert_data_update(&orig_data, vd.vertex);
SCULPT_vertex_check_origdata(ss, vd.vertex);
@ -163,7 +166,8 @@ static void do_paint_brush_task_cb_ex(void *__restrict userdata,
bool affect_vertex = false;
float distance_to_stroke_location = 0.0f;
if (brush->tip_roundness < 1.0f) {
affect_vertex = SCULPT_brush_test_cube(&test, vd.co, data->mat, brush->tip_roundness);
affect_vertex = SCULPT_brush_test_cube(
&test, vd.co, data->mat, brush->tip_roundness, brush->falloff_shape != PAINT_FALLOFF_SHAPE_TUBE);
distance_to_stroke_location = ss->cache->radius * test.dist;
}
else {
@ -171,7 +175,7 @@ static void do_paint_brush_task_cb_ex(void *__restrict userdata,
distance_to_stroke_location = sqrtf(test.dist);
}
if (!affect_vertex) {
if (do_test && !affect_vertex) {
continue;
}
@ -251,7 +255,7 @@ static void do_sample_wet_paint_task_cb(void *__restrict userdata,
PBVHVertexIter vd;
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init(
ss, &test, data->brush->falloff_shape);
test.radius *= data->brush->wet_paint_radius_factor;
@ -467,7 +471,7 @@ static void do_smear_brush_task_cb_exec(void *__restrict userdata,
PBVHVertexIter vd;
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init(
ss, &test, data->brush->falloff_shape);
const int thread_id = BLI_task_parallel_thread_id(tls);

View File

@ -221,7 +221,7 @@ template<typename ImageBuffer> class PaintingKernel {
}
void init_brush_test()
{
brush_test_fn = SCULPT_brush_test_init_with_falloff_shape(ss, &test, brush->falloff_shape);
brush_test_fn = SCULPT_brush_test_init(ss, &test, (eBrushFalloffShape)brush->falloff_shape);
}
/**
@ -269,7 +269,7 @@ static std::vector<bool> init_triangle_brush_test(SculptSession *ss,
{
std::vector<bool> brush_test(triangles.size());
SculptBrushTest test;
SCULPT_brush_test_init(ss, &test);
SCULPT_brush_test_init(ss, &test, PAINT_FALLOFF_NOOP);
float3 brush_min_bounds(test.location[0] - test.radius,
test.location[1] - test.radius,
test.location[2] - test.radius);

View File

@ -1481,7 +1481,7 @@ static void do_enhance_details_brush_task_cb_ex(void *__restrict userdata,
CLAMP(bstrength, -1.0f, 1.0f);
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init(
ss, &test, data->brush->falloff_shape);
const int thread_id = BLI_task_parallel_thread_id(tls);
@ -1523,7 +1523,7 @@ static void do_enhance_details_brush_dir_task_cb_ex(void *__restrict userdata,
PBVHVertexIter vd;
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init(
ss, &test, data->brush->falloff_shape);
SculptCustomLayer *strokeid_scl = data->scl2;
@ -1577,7 +1577,7 @@ static void do_enhance_details_brush_dir2_task_cb_ex(void *__restrict userdata,
PBVHVertexIter vd;
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init(
ss, &test, data->brush->falloff_shape);
// SculptCustomLayer *strokeid_scl = data->scl2;
@ -1832,7 +1832,7 @@ static void do_smooth_brush_task_cb_ex(void *__restrict userdata,
CLAMP(bstrength, 0.0f, 1.0f);
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init(
ss, &test, data->brush->falloff_shape);
const int thread_id = BLI_task_parallel_thread_id(tls);
@ -2254,7 +2254,7 @@ static void SCULPT_do_surface_smooth_brush_laplacian_task_cb_ex(
SculptOrigVertData orig_data;
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init(
ss, &test, data->brush->falloff_shape);
const int thread_id = BLI_task_parallel_thread_id(tls);
@ -2333,7 +2333,7 @@ static void SCULPT_do_surface_smooth_brush_displace_task_cb_ex(
PBVHVertexIter vd;
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init(
ss, &test, data->brush->falloff_shape);
const int thread_id = BLI_task_parallel_thread_id(tls);
@ -2404,7 +2404,7 @@ static void SCULPT_do_directional_smooth_task_cb_ex(void *__restrict userdata,
PBVHVertexIter vd;
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init(
ss, &test, data->brush->falloff_shape);
const int thread_id = BLI_task_parallel_thread_id(tls);
@ -2505,7 +2505,7 @@ static void SCULPT_do_uniform_weigths_smooth_task_cb_ex(void *__restrict userdat
PBVHVertexIter vd;
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init(
ss, &test, data->brush->falloff_shape);
const int thread_id = BLI_task_parallel_thread_id(tls);
@ -2619,7 +2619,7 @@ static void do_smooth_vcol_boundary_brush_task_cb_ex(void *__restrict userdata,
CLAMP(bstrength, 0.0f, 1.0f);
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init(
ss, &test, data->brush->falloff_shape);
const int thread_id = BLI_task_parallel_thread_id(tls);

View File

@ -219,7 +219,7 @@ static void do_shape_symmetrize_brush_task_cb(void *__restrict userdata,
const Brush *brush = data->brush;
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init(
ss, &test, brush->falloff_shape);
const int thread_id = BLI_task_parallel_thread_id(tls);

View File

@ -24,6 +24,7 @@ struct TableGSet;
struct MLoop;
struct MLoopCol;
struct MLoopTri;
struct MSculptVert;
struct MPoly;
struct MPropCol;
struct MVert;
@ -119,7 +120,8 @@ void GPU_pbvh_mesh_buffers_update(GPU_PBVH_Buffers *buffers,
const int face_sets_color_seed,
const int face_sets_color_default,
const int update_flags,
const float (*vert_normals)[3]);
const float (*vert_normals)[3],
struct MSculptVert *sverts);
bool GPU_pbvh_update_attribute_names(
const CustomData *vdata,

View File

@ -128,6 +128,7 @@ typedef struct PBVHGPUFormat {
} PBVHGPUFormat;
static PBVHGPUFormat g_vbo_id = {{0}};
bool pbvh_show_orig_co = false;
static int gpu_pbvh_make_attr_offs(AttributeDomainMask domain_mask,
CustomDataMask type_mask,
@ -253,7 +254,8 @@ void GPU_pbvh_mesh_buffers_update(GPU_PBVH_Buffers *buffers,
const int face_sets_color_seed,
const int face_sets_color_default,
const int update_flags,
const float (*vert_normals)[3])
const float (*vert_normals)[3],
MSculptVert *sverts)
{
GPUAttrRef vcol_refs[MAX_GPU_ATTR];
GPUAttrRef cd_uvs[MAX_GPU_ATTR];
@ -297,184 +299,188 @@ void GPU_pbvh_mesh_buffers_update(GPU_PBVH_Buffers *buffers,
bool empty_mask = true;
bool default_face_set = true;
{
const int totelem = buffers->tot_tri * 3;
const int totelem = buffers->tot_tri * 3;
/* Build VBO */
if (gpu_pbvh_vert_buf_data_set(buffers, totelem)) {
GPUVertBufRaw pos_step = {0};
GPUVertBufRaw nor_step = {0};
GPUVertBufRaw msk_step = {0};
GPUVertBufRaw fset_step = {0};
GPUVertBufRaw col_step = {0};
GPUVertBufRaw uv_step = {0};
/* Build VBO */
if (gpu_pbvh_vert_buf_data_set(buffers, totelem)) {
GPUVertBufRaw pos_step = {0};
GPUVertBufRaw nor_step = {0};
GPUVertBufRaw msk_step = {0};
GPUVertBufRaw fset_step = {0};
GPUVertBufRaw col_step = {0};
GPUVertBufRaw uv_step = {0};
GPU_vertbuf_attr_get_raw_data(buffers->vert_buf, g_vbo_id.pos, &pos_step);
GPU_vertbuf_attr_get_raw_data(buffers->vert_buf, g_vbo_id.nor, &nor_step);
GPU_vertbuf_attr_get_raw_data(buffers->vert_buf, g_vbo_id.msk, &msk_step);
GPU_vertbuf_attr_get_raw_data(buffers->vert_buf, g_vbo_id.fset, &fset_step);
GPU_vertbuf_attr_get_raw_data(buffers->vert_buf, g_vbo_id.pos, &pos_step);
GPU_vertbuf_attr_get_raw_data(buffers->vert_buf, g_vbo_id.nor, &nor_step);
GPU_vertbuf_attr_get_raw_data(buffers->vert_buf, g_vbo_id.msk, &msk_step);
GPU_vertbuf_attr_get_raw_data(buffers->vert_buf, g_vbo_id.fset, &fset_step);
/* calculate normal for each polygon only once */
uint mpoly_prev = UINT_MAX;
short no[3] = {0, 0, 0};
/* calculate normal for each polygon only once */
uint mpoly_prev = UINT_MAX;
short no[3] = {0, 0, 0};
if (cd_uv_count > 0) {
for (int uv_i = 0; uv_i < cd_uv_count; uv_i++) {
GPU_vertbuf_attr_get_raw_data(buffers->vert_buf, g_vbo_id.uv[uv_i], &uv_step);
if (cd_uv_count > 0) {
for (int uv_i = 0; uv_i < cd_uv_count; uv_i++) {
GPU_vertbuf_attr_get_raw_data(buffers->vert_buf, g_vbo_id.uv[uv_i], &uv_step);
GPUAttrRef *ref = cd_uvs + uv_i;
CustomDataLayer *layer = ldata->layers + ref->layer_idx;
MLoopUV *muv = layer->data;
GPUAttrRef *ref = cd_uvs + uv_i;
CustomDataLayer *layer = ldata->layers + ref->layer_idx;
MLoopUV *muv = layer->data;
for (uint i = 0; i < buffers->face_indices_len; i++) {
const MLoopTri *lt = &buffers->looptri[buffers->face_indices[i]];
for (uint i = 0; i < buffers->face_indices_len; i++) {
const MLoopTri *lt = &buffers->looptri[buffers->face_indices[i]];
if (!gpu_pbvh_is_looptri_visible(lt, mvert, buffers->mloop, sculpt_face_sets)) {
continue;
}
for (uint j = 0; j < 3; j++) {
MLoopUV *muv2 = muv + lt->tri[j];
memcpy(GPU_vertbuf_raw_step(&uv_step), muv2->uv, sizeof(muv2->uv));
}
}
}
}
if (show_vcol) {
for (int col_i = 0; col_i < totcol; col_i++) {
GPU_vertbuf_attr_get_raw_data(buffers->vert_buf, g_vbo_id.col[col_i], &col_step);
MPropCol *pcol = NULL;
MLoopCol *mcol = NULL;
GPUAttrRef *ref = vcol_refs + col_i;
const CustomData *cdata = ref->domain == ATTR_DOMAIN_POINT ? vdata : ldata;
CustomDataLayer *layer = cdata->layers + ref->layer_idx;
bool color_loops = ref->domain == ATTR_DOMAIN_CORNER;
if (layer->type == CD_PROP_COLOR) {
pcol = (MPropCol *)layer->data;
}
else {
mcol = (MLoopCol *)layer->data;
if (!gpu_pbvh_is_looptri_visible(lt, mvert, buffers->mloop, sculpt_face_sets)) {
continue;
}
for (uint i = 0; i < buffers->face_indices_len; i++) {
const MLoopTri *lt = &buffers->looptri[buffers->face_indices[i]];
const uint vtri[3] = {
buffers->mloop[lt->tri[0]].v,
buffers->mloop[lt->tri[1]].v,
buffers->mloop[lt->tri[2]].v,
};
for (uint j = 0; j < 3; j++) {
MLoopUV *muv2 = muv + lt->tri[j];
if (!gpu_pbvh_is_looptri_visible(lt, mvert, buffers->mloop, sculpt_face_sets)) {
continue;
}
for (uint j = 0; j < 3; j++) {
/* Vertex Colors. */
if (show_vcol) {
ushort scol[4] = {USHRT_MAX, USHRT_MAX, USHRT_MAX, USHRT_MAX};
if (pcol) {
if (color_loops) {
scol[0] = unit_float_to_ushort_clamp(pcol[lt->tri[j]].color[0]);
scol[1] = unit_float_to_ushort_clamp(pcol[lt->tri[j]].color[1]);
scol[2] = unit_float_to_ushort_clamp(pcol[lt->tri[j]].color[2]);
scol[3] = unit_float_to_ushort_clamp(pcol[lt->tri[j]].color[3]);
}
else {
scol[0] = unit_float_to_ushort_clamp(pcol[vtri[j]].color[0]);
scol[1] = unit_float_to_ushort_clamp(pcol[vtri[j]].color[1]);
scol[2] = unit_float_to_ushort_clamp(pcol[vtri[j]].color[2]);
scol[3] = unit_float_to_ushort_clamp(pcol[vtri[j]].color[3]);
}
memcpy(GPU_vertbuf_raw_step(&col_step), scol, sizeof(scol));
}
else if (mcol) {
const uint loop_index = lt->tri[j];
const MLoopCol *mcol2 = mcol + (color_loops ? loop_index : vtri[j]);
scol[0] = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mcol2->r]);
scol[1] = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mcol2->g]);
scol[2] = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mcol2->b]);
scol[3] = unit_float_to_ushort_clamp(mcol2->a * (1.0f / 255.0f));
memcpy(GPU_vertbuf_raw_step(&col_step), scol, sizeof(scol));
}
}
}
}
}
}
for (uint i = 0; i < buffers->face_indices_len; i++) {
const MLoopTri *lt = &buffers->looptri[buffers->face_indices[i]];
const uint vtri[3] = {
buffers->mloop[lt->tri[0]].v,
buffers->mloop[lt->tri[1]].v,
buffers->mloop[lt->tri[2]].v,
};
if (!gpu_pbvh_is_looptri_visible(lt, mvert, buffers->mloop, sculpt_face_sets)) {
continue;
}
/* Face normal and mask */
if (lt->poly != mpoly_prev && !buffers->smooth) {
const MPoly *mp = &buffers->mpoly[lt->poly];
float fno[3];
BKE_mesh_calc_poly_normal(mp, &buffers->mloop[mp->loopstart], mvert, fno);
normal_float_to_short_v3(no, fno);
mpoly_prev = lt->poly;
}
uchar face_set_color[4] = {UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX};
if (show_face_sets) {
const int fset = abs(sculpt_face_sets[lt->poly]);
/* Skip for the default color Face Set to render it white. */
if (fset != face_sets_color_default) {
BKE_paint_face_set_overlay_color_get(fset, face_sets_color_seed, face_set_color);
default_face_set = false;
}
}
float fmask = 0.0f;
uchar cmask = 0;
if (show_mask && !buffers->smooth) {
fmask = (vmask[vtri[0]] + vmask[vtri[1]] + vmask[vtri[2]]) / 3.0f;
cmask = (uchar)(fmask * 255);
}
for (uint j = 0; j < 3; j++) {
const MVert *v = &mvert[vtri[j]];
copy_v3_v3(GPU_vertbuf_raw_step(&pos_step), v->co);
if (buffers->smooth) {
normal_float_to_short_v3(no, vert_normals[vtri[j]]);
}
copy_v3_v3_short(GPU_vertbuf_raw_step(&nor_step), no);
if (show_mask && buffers->smooth) {
cmask = (uchar)(vmask[vtri[j]] * 255);
}
*(uchar *)GPU_vertbuf_raw_step(&msk_step) = cmask;
empty_mask = empty_mask && (cmask == 0);
if (!g_vbo_id.fast_mode) {
/* Face Sets. */
memcpy(GPU_vertbuf_raw_step(&fset_step), face_set_color, sizeof(uchar[3]));
memcpy(GPU_vertbuf_raw_step(&uv_step), muv2->uv, sizeof(muv2->uv));
}
}
}
}
gpu_pbvh_batch_init(buffers, GPU_PRIM_TRIS);
if (show_vcol) {
for (int col_i = 0; col_i < totcol; col_i++) {
GPU_vertbuf_attr_get_raw_data(buffers->vert_buf, g_vbo_id.col[col_i], &col_step);
MPropCol *pcol = NULL;
MLoopCol *mcol = NULL;
GPUAttrRef *ref = vcol_refs + col_i;
const CustomData *cdata = ref->domain == ATTR_DOMAIN_POINT ? vdata : ldata;
CustomDataLayer *layer = cdata->layers + ref->layer_idx;
bool color_loops = ref->domain == ATTR_DOMAIN_CORNER;
if (layer->type == CD_PROP_COLOR) {
pcol = (MPropCol *)layer->data;
}
else {
mcol = (MLoopCol *)layer->data;
}
for (uint i = 0; i < buffers->face_indices_len; i++) {
const MLoopTri *lt = &buffers->looptri[buffers->face_indices[i]];
const uint vtri[3] = {
buffers->mloop[lt->tri[0]].v,
buffers->mloop[lt->tri[1]].v,
buffers->mloop[lt->tri[2]].v,
};
if (!gpu_pbvh_is_looptri_visible(lt, mvert, buffers->mloop, sculpt_face_sets)) {
continue;
}
for (uint j = 0; j < 3; j++) {
/* Vertex Colors. */
if (show_vcol) {
ushort scol[4] = {USHRT_MAX, USHRT_MAX, USHRT_MAX, USHRT_MAX};
if (pcol) {
if (color_loops) {
scol[0] = unit_float_to_ushort_clamp(pcol[lt->tri[j]].color[0]);
scol[1] = unit_float_to_ushort_clamp(pcol[lt->tri[j]].color[1]);
scol[2] = unit_float_to_ushort_clamp(pcol[lt->tri[j]].color[2]);
scol[3] = unit_float_to_ushort_clamp(pcol[lt->tri[j]].color[3]);
}
else {
scol[0] = unit_float_to_ushort_clamp(pcol[vtri[j]].color[0]);
scol[1] = unit_float_to_ushort_clamp(pcol[vtri[j]].color[1]);
scol[2] = unit_float_to_ushort_clamp(pcol[vtri[j]].color[2]);
scol[3] = unit_float_to_ushort_clamp(pcol[vtri[j]].color[3]);
}
memcpy(GPU_vertbuf_raw_step(&col_step), scol, sizeof(scol));
}
else if (mcol) {
const uint loop_index = lt->tri[j];
const MLoopCol *mcol2 = mcol + (color_loops ? loop_index : vtri[j]);
scol[0] = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mcol2->r]);
scol[1] = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mcol2->g]);
scol[2] = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mcol2->b]);
scol[3] = unit_float_to_ushort_clamp(mcol2->a * (1.0f / 255.0f));
memcpy(GPU_vertbuf_raw_step(&col_step), scol, sizeof(scol));
}
}
}
}
}
}
for (uint i = 0; i < buffers->face_indices_len; i++) {
const MLoopTri *lt = &buffers->looptri[buffers->face_indices[i]];
const uint vtri[3] = {
buffers->mloop[lt->tri[0]].v,
buffers->mloop[lt->tri[1]].v,
buffers->mloop[lt->tri[2]].v,
};
if (!gpu_pbvh_is_looptri_visible(lt, mvert, buffers->mloop, sculpt_face_sets)) {
continue;
}
/* Face normal and mask */
if (lt->poly != mpoly_prev && !buffers->smooth) {
const MPoly *mp = &buffers->mpoly[lt->poly];
float fno[3];
BKE_mesh_calc_poly_normal(mp, &buffers->mloop[mp->loopstart], mvert, fno);
normal_float_to_short_v3(no, fno);
mpoly_prev = lt->poly;
}
uchar face_set_color[4] = {UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX};
if (show_face_sets) {
const int fset = abs(sculpt_face_sets[lt->poly]);
/* Skip for the default color Face Set to render it white. */
if (fset != face_sets_color_default) {
BKE_paint_face_set_overlay_color_get(fset, face_sets_color_seed, face_set_color);
default_face_set = false;
}
}
float fmask = 0.0f;
uchar cmask = 0;
if (show_mask && !buffers->smooth) {
fmask = (vmask[vtri[0]] + vmask[vtri[1]] + vmask[vtri[2]]) / 3.0f;
cmask = (uchar)(fmask * 255);
}
for (uint j = 0; j < 3; j++) {
const MVert *v = &mvert[vtri[j]];
if (pbvh_show_orig_co) {
copy_v3_v3(GPU_vertbuf_raw_step(&pos_step), sverts[vtri[j]].origco);
}
else {
copy_v3_v3(GPU_vertbuf_raw_step(&pos_step), v->co);
}
if (buffers->smooth) {
normal_float_to_short_v3(no, vert_normals[vtri[j]]);
}
copy_v3_v3_short(GPU_vertbuf_raw_step(&nor_step), no);
if (show_mask && buffers->smooth) {
cmask = (uchar)(vmask[vtri[j]] * 255);
}
*(uchar *)GPU_vertbuf_raw_step(&msk_step) = cmask;
empty_mask = empty_mask && (cmask == 0);
if (!g_vbo_id.fast_mode) {
/* Face Sets. */
memcpy(GPU_vertbuf_raw_step(&fset_step), face_set_color, sizeof(uchar[3]));
}
}
}
}
gpu_pbvh_batch_init(buffers, GPU_PRIM_TRIS);
/* Get material index from the first face of this buffer. */
const MLoopTri *lt = &buffers->looptri[buffers->face_indices[0]];
const MPoly *mp = &buffers->mpoly[lt->poly];
@ -948,7 +954,6 @@ GPU_PBVH_Buffers *GPU_pbvh_grid_buffers_build(int totgrid, BLI_bitmap **grid_hid
* \{ */
static int debug_pass = 0;
bool pbvh_show_orig_co = false;
static void gpu_bmesh_get_vcol(BMVert *v, BMLoop *l, const GPUAttrRef *ref, float color[4])
{

View File

@ -337,7 +337,7 @@ typedef enum eAutomasking_flag {
BRUSH_AUTOMASKING_BOUNDARY_FACE_SETS = (1 << 3),
BRUSH_AUTOMASKING_CONCAVITY = (1 << 4),
BRUSH_AUTOMASKING_INVERT_CONCAVITY = (1 << 5),
BRUSH_AUTOMASKING_BRUSH_NORMAL = (1<<6),
BRUSH_AUTOMASKING_BRUSH_NORMAL = (1 << 6),
BRUSH_AUTOMASKING_VIEW_NORMAL = (1 << 7),
} eAutomasking_flag;
@ -660,6 +660,7 @@ typedef enum eBlurKernelType {
typedef enum eBrushFalloffShape {
PAINT_FALLOFF_SHAPE_SPHERE = 0,
PAINT_FALLOFF_SHAPE_TUBE = 1,
PAINT_FALLOFF_NOOP = 2,
} eBrushFalloffShape;
// dyntopo flags

View File

@ -73,7 +73,7 @@ static const EnumPropertyItem rna_enum_brush_texture_slot_map_all_mode_items[] =
{MTEX_MAP_MODE_3D, "3D", 0, "3D", ""},
{MTEX_MAP_MODE_RANDOM, "RANDOM", 0, "Random", ""},
{MTEX_MAP_MODE_STENCIL, "STENCIL", 0, "Stencil", ""},
//{MTEX_MAP_MODE_ROLL, "ROLL", 0, "Roll", ""},
{MTEX_MAP_MODE_ROLL, "ROLL", 0, "Roll", ""},
{0, NULL, 0, NULL, NULL},
};