Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCampbell Barton <ideasman42@gmail.com>2019-04-17 07:17:24 +0300
committerCampbell Barton <ideasman42@gmail.com>2019-04-17 07:21:24 +0300
commite12c08e8d170b7ca40f204a5b0423c23a9fbc2c1 (patch)
tree8cf3453d12edb177a218ef8009357518ec6cab6a /source/blender/editors/sculpt_paint
parentb3dabc200a4b0399ec6b81f2ff2730d07b44fcaa (diff)
ClangFormat: apply to source, most of intern
Apply clang format as proposed in T53211. For details on usage and instructions for migrating branches without conflicts, see: https://wiki.blender.org/wiki/Tools/ClangFormat
Diffstat (limited to 'source/blender/editors/sculpt_paint')
-rw-r--r--source/blender/editors/sculpt_paint/CMakeLists.txt84
-rw-r--r--source/blender/editors/sculpt_paint/paint_cursor.c1934
-rw-r--r--source/blender/editors/sculpt_paint/paint_curve.c1125
-rw-r--r--source/blender/editors/sculpt_paint/paint_curve_undo.c122
-rw-r--r--source/blender/editors/sculpt_paint/paint_hide.c700
-rw-r--r--source/blender/editors/sculpt_paint/paint_image.c1787
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_2d.c3129
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_proj.c10715
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_undo.c806
-rw-r--r--source/blender/editors/sculpt_paint/paint_intern.h259
-rw-r--r--source/blender/editors/sculpt_paint/paint_mask.c795
-rw-r--r--source/blender/editors/sculpt_paint/paint_ops.c1609
-rw-r--r--source/blender/editors/sculpt_paint/paint_stroke.c2126
-rw-r--r--source/blender/editors/sculpt_paint/paint_utils.c1093
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex.c5580
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex_color_ops.c743
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex_color_utils.c921
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex_proj.c260
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c1326
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex_weight_utils.c363
-rw-r--r--source/blender/editors/sculpt_paint/sculpt.c9838
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_intern.h459
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_undo.c1792
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_uv.c1512
24 files changed, 24896 insertions, 24182 deletions
diff --git a/source/blender/editors/sculpt_paint/CMakeLists.txt b/source/blender/editors/sculpt_paint/CMakeLists.txt
index e7a8c704fda..cddaf69b965 100644
--- a/source/blender/editors/sculpt_paint/CMakeLists.txt
+++ b/source/blender/editors/sculpt_paint/CMakeLists.txt
@@ -16,61 +16,61 @@
# ***** END GPL LICENSE BLOCK *****
set(INC
- ../include
- ../uvedit
- ../../blenkernel
- ../../blenlib
- ../../blentranslation
- ../../bmesh
- ../../depsgraph
- ../../gpu
- ../../imbuf
- ../../makesdna
- ../../makesrna
- ../../render/extern/include
- ../../windowmanager
- ../../../../intern/guardedalloc
- ../../../../intern/glew-mx
+ ../include
+ ../uvedit
+ ../../blenkernel
+ ../../blenlib
+ ../../blentranslation
+ ../../bmesh
+ ../../depsgraph
+ ../../gpu
+ ../../imbuf
+ ../../makesdna
+ ../../makesrna
+ ../../render/extern/include
+ ../../windowmanager
+ ../../../../intern/guardedalloc
+ ../../../../intern/glew-mx
)
set(INC_SYS
- ${GLEW_INCLUDE_PATH}
+ ${GLEW_INCLUDE_PATH}
)
set(SRC
- paint_cursor.c
- paint_curve.c
- paint_curve_undo.c
- paint_hide.c
- paint_image.c
- paint_image_2d.c
- paint_image_proj.c
- paint_image_undo.c
- paint_mask.c
- paint_ops.c
- paint_stroke.c
- paint_utils.c
- paint_vertex.c
- paint_vertex_color_ops.c
- paint_vertex_color_utils.c
- paint_vertex_proj.c
- paint_vertex_weight_ops.c
- paint_vertex_weight_utils.c
- sculpt.c
- sculpt_undo.c
- sculpt_uv.c
+ paint_cursor.c
+ paint_curve.c
+ paint_curve_undo.c
+ paint_hide.c
+ paint_image.c
+ paint_image_2d.c
+ paint_image_proj.c
+ paint_image_undo.c
+ paint_mask.c
+ paint_ops.c
+ paint_stroke.c
+ paint_utils.c
+ paint_vertex.c
+ paint_vertex_color_ops.c
+ paint_vertex_color_utils.c
+ paint_vertex_proj.c
+ paint_vertex_weight_ops.c
+ paint_vertex_weight_utils.c
+ sculpt.c
+ sculpt_undo.c
+ sculpt_uv.c
- paint_intern.h
- sculpt_intern.h
+ paint_intern.h
+ sculpt_intern.h
)
set(LIB
- bf_blenkernel
- bf_blenlib
+ bf_blenkernel
+ bf_blenlib
)
if(WITH_INTERNATIONAL)
- add_definitions(-DWITH_INTERNATIONAL)
+ add_definitions(-DWITH_INTERNATIONAL)
endif()
add_definitions(${GL_DEFINITIONS})
diff --git a/source/blender/editors/sculpt_paint/paint_cursor.c b/source/blender/editors/sculpt_paint/paint_cursor.c
index 4b714e03d3b..da183d190fa 100644
--- a/source/blender/editors/sculpt_paint/paint_cursor.c
+++ b/source/blender/editors/sculpt_paint/paint_cursor.c
@@ -75,1103 +75,1101 @@
*/
typedef struct TexSnapshot {
- GLuint overlay_texture;
- int winx;
- int winy;
- int old_size;
- float old_zoom;
- bool old_col;
+ GLuint overlay_texture;
+ int winx;
+ int winy;
+ int old_size;
+ float old_zoom;
+ bool old_col;
} TexSnapshot;
typedef struct CursorSnapshot {
- GLuint overlay_texture;
- int size;
- int zoom;
+ GLuint overlay_texture;
+ int size;
+ int zoom;
} CursorSnapshot;
static TexSnapshot primary_snap = {0};
-static TexSnapshot secondary_snap = {0};
-static CursorSnapshot cursor_snap = {0};
+static TexSnapshot secondary_snap = {0};
+static CursorSnapshot cursor_snap = {0};
/* delete overlay cursor textures to preserve memory and invalidate all overlay flags */
void paint_cursor_delete_textures(void)
{
- if (primary_snap.overlay_texture)
- glDeleteTextures(1, &primary_snap.overlay_texture);
- if (secondary_snap.overlay_texture)
- glDeleteTextures(1, &secondary_snap.overlay_texture);
- if (cursor_snap.overlay_texture)
- glDeleteTextures(1, &cursor_snap.overlay_texture);
-
- memset(&primary_snap, 0, sizeof(TexSnapshot));
- memset(&secondary_snap, 0, sizeof(TexSnapshot));
- memset(&cursor_snap, 0, sizeof(CursorSnapshot));
-
- BKE_paint_invalidate_overlay_all();
+ if (primary_snap.overlay_texture)
+ glDeleteTextures(1, &primary_snap.overlay_texture);
+ if (secondary_snap.overlay_texture)
+ glDeleteTextures(1, &secondary_snap.overlay_texture);
+ if (cursor_snap.overlay_texture)
+ glDeleteTextures(1, &cursor_snap.overlay_texture);
+
+ memset(&primary_snap, 0, sizeof(TexSnapshot));
+ memset(&secondary_snap, 0, sizeof(TexSnapshot));
+ memset(&cursor_snap, 0, sizeof(CursorSnapshot));
+
+ BKE_paint_invalidate_overlay_all();
}
static int same_tex_snap(TexSnapshot *snap, MTex *mtex, ViewContext *vc, bool col, float zoom)
{
- return (/* make brush smaller shouldn't cause a resample */
- //(mtex->brush_map_mode != MTEX_MAP_MODE_VIEW ||
- //(BKE_brush_size_get(vc->scene, brush) <= snap->BKE_brush_size_get)) &&
-
- (mtex->brush_map_mode != MTEX_MAP_MODE_TILED ||
- (vc->ar->winx == snap->winx &&
- vc->ar->winy == snap->winy)) &&
- (mtex->brush_map_mode == MTEX_MAP_MODE_STENCIL ||
- snap->old_zoom == zoom) &&
- snap->old_col == col
- );
+ return (/* make brush smaller shouldn't cause a resample */
+ //(mtex->brush_map_mode != MTEX_MAP_MODE_VIEW ||
+ //(BKE_brush_size_get(vc->scene, brush) <= snap->BKE_brush_size_get)) &&
+
+ (mtex->brush_map_mode != MTEX_MAP_MODE_TILED ||
+ (vc->ar->winx == snap->winx && vc->ar->winy == snap->winy)) &&
+ (mtex->brush_map_mode == MTEX_MAP_MODE_STENCIL || snap->old_zoom == zoom) &&
+ snap->old_col == col);
}
static void make_tex_snap(TexSnapshot *snap, ViewContext *vc, float zoom)
{
- snap->old_zoom = zoom;
- snap->winx = vc->ar->winx;
- snap->winy = vc->ar->winy;
+ snap->old_zoom = zoom;
+ snap->winx = vc->ar->winx;
+ snap->winy = vc->ar->winy;
}
typedef struct LoadTexData {
- Brush *br;
- ViewContext *vc;
+ Brush *br;
+ ViewContext *vc;
- MTex *mtex;
- GLubyte *buffer;
- bool col;
+ MTex *mtex;
+ GLubyte *buffer;
+ bool col;
- struct ImagePool *pool;
- int size;
- float rotation;
- float radius;
+ struct ImagePool *pool;
+ int size;
+ float rotation;
+ float radius;
} LoadTexData;
-static void load_tex_task_cb_ex(
- void *__restrict userdata,
- const int j,
- const ParallelRangeTLS *__restrict tls)
+static void load_tex_task_cb_ex(void *__restrict userdata,
+ const int j,
+ const ParallelRangeTLS *__restrict tls)
{
- LoadTexData *data = userdata;
- Brush *br = data->br;
- ViewContext *vc = data->vc;
-
- MTex *mtex = data->mtex;
- GLubyte *buffer = data->buffer;
- const bool col = data->col;
-
- struct ImagePool *pool = data->pool;
- const int size = data->size;
- const float rotation = data->rotation;
- const float radius = data->radius;
-
- bool convert_to_linear = false;
- struct ColorSpace *colorspace = NULL;
-
- if (mtex->tex && mtex->tex->type == TEX_IMAGE && mtex->tex->ima) {
- ImBuf *tex_ibuf = BKE_image_pool_acquire_ibuf(mtex->tex->ima, &mtex->tex->iuser, pool);
- /* For consistency, sampling always returns color in linear space */
- if (tex_ibuf && tex_ibuf->rect_float == NULL) {
- convert_to_linear = true;
- colorspace = tex_ibuf->rect_colorspace;
- }
- BKE_image_pool_release_ibuf(mtex->tex->ima, tex_ibuf, pool);
- }
-
- for (int i = 0; i < size; i++) {
- // largely duplicated from tex_strength
-
- int index = j * size + i;
-
- float x = (float)i / size;
- float y = (float)j / size;
- float len;
-
- if (mtex->brush_map_mode == MTEX_MAP_MODE_TILED) {
- x *= vc->ar->winx / radius;
- y *= vc->ar->winy / radius;
- }
- else {
- x = (x - 0.5f) * 2.0f;
- y = (y - 0.5f) * 2.0f;
- }
-
- len = sqrtf(x * x + y * y);
-
- if (ELEM(mtex->brush_map_mode, MTEX_MAP_MODE_TILED, MTEX_MAP_MODE_STENCIL) || len <= 1.0f) {
- /* it is probably worth optimizing for those cases where the texture is not rotated by skipping the calls to
- * atan2, sqrtf, sin, and cos. */
- if (mtex->tex && (rotation > 0.001f || rotation < -0.001f)) {
- const float angle = atan2f(y, x) + rotation;
-
- x = len * cosf(angle);
- y = len * sinf(angle);
- }
-
- if (col) {
- float rgba[4];
-
- paint_get_tex_pixel_col(mtex, x, y, rgba, pool, tls->thread_id, convert_to_linear, colorspace);
-
- buffer[index * 4] = rgba[0] * 255;
- buffer[index * 4 + 1] = rgba[1] * 255;
- buffer[index * 4 + 2] = rgba[2] * 255;
- buffer[index * 4 + 3] = rgba[3] * 255;
- }
- else {
- float avg = paint_get_tex_pixel(mtex, x, y, pool, tls->thread_id);
-
- avg += br->texture_sample_bias;
-
- /* clamp to avoid precision overflow */
- CLAMP(avg, 0.0f, 1.0f);
- buffer[index] = 255 - (GLubyte)(255 * avg);
- }
- }
- else {
- if (col) {
- buffer[index * 4] = 0;
- buffer[index * 4 + 1] = 0;
- buffer[index * 4 + 2] = 0;
- buffer[index * 4 + 3] = 0;
- }
- else {
- buffer[index] = 0;
- }
- }
- }
+ LoadTexData *data = userdata;
+ Brush *br = data->br;
+ ViewContext *vc = data->vc;
+
+ MTex *mtex = data->mtex;
+ GLubyte *buffer = data->buffer;
+ const bool col = data->col;
+
+ struct ImagePool *pool = data->pool;
+ const int size = data->size;
+ const float rotation = data->rotation;
+ const float radius = data->radius;
+
+ bool convert_to_linear = false;
+ struct ColorSpace *colorspace = NULL;
+
+ if (mtex->tex && mtex->tex->type == TEX_IMAGE && mtex->tex->ima) {
+ ImBuf *tex_ibuf = BKE_image_pool_acquire_ibuf(mtex->tex->ima, &mtex->tex->iuser, pool);
+ /* For consistency, sampling always returns color in linear space */
+ if (tex_ibuf && tex_ibuf->rect_float == NULL) {
+ convert_to_linear = true;
+ colorspace = tex_ibuf->rect_colorspace;
+ }
+ BKE_image_pool_release_ibuf(mtex->tex->ima, tex_ibuf, pool);
+ }
+
+ for (int i = 0; i < size; i++) {
+ // largely duplicated from tex_strength
+
+ int index = j * size + i;
+
+ float x = (float)i / size;
+ float y = (float)j / size;
+ float len;
+
+ if (mtex->brush_map_mode == MTEX_MAP_MODE_TILED) {
+ x *= vc->ar->winx / radius;
+ y *= vc->ar->winy / radius;
+ }
+ else {
+ x = (x - 0.5f) * 2.0f;
+ y = (y - 0.5f) * 2.0f;
+ }
+
+ len = sqrtf(x * x + y * y);
+
+ if (ELEM(mtex->brush_map_mode, MTEX_MAP_MODE_TILED, MTEX_MAP_MODE_STENCIL) || len <= 1.0f) {
+ /* it is probably worth optimizing for those cases where the texture is not rotated by skipping the calls to
+ * atan2, sqrtf, sin, and cos. */
+ if (mtex->tex && (rotation > 0.001f || rotation < -0.001f)) {
+ const float angle = atan2f(y, x) + rotation;
+
+ x = len * cosf(angle);
+ y = len * sinf(angle);
+ }
+
+ if (col) {
+ float rgba[4];
+
+ paint_get_tex_pixel_col(
+ mtex, x, y, rgba, pool, tls->thread_id, convert_to_linear, colorspace);
+
+ buffer[index * 4] = rgba[0] * 255;
+ buffer[index * 4 + 1] = rgba[1] * 255;
+ buffer[index * 4 + 2] = rgba[2] * 255;
+ buffer[index * 4 + 3] = rgba[3] * 255;
+ }
+ else {
+ float avg = paint_get_tex_pixel(mtex, x, y, pool, tls->thread_id);
+
+ avg += br->texture_sample_bias;
+
+ /* clamp to avoid precision overflow */
+ CLAMP(avg, 0.0f, 1.0f);
+ buffer[index] = 255 - (GLubyte)(255 * avg);
+ }
+ }
+ else {
+ if (col) {
+ buffer[index * 4] = 0;
+ buffer[index * 4 + 1] = 0;
+ buffer[index * 4 + 2] = 0;
+ buffer[index * 4 + 3] = 0;
+ }
+ else {
+ buffer[index] = 0;
+ }
+ }
+ }
}
static int load_tex(Brush *br, ViewContext *vc, float zoom, bool col, bool primary)
{
- bool init;
- TexSnapshot *target;
-
- MTex *mtex = (primary) ? &br->mtex : &br->mask_mtex;
- eOverlayControlFlags overlay_flags = BKE_paint_get_overlay_flags();
- GLubyte *buffer = NULL;
-
- int size;
- bool refresh;
- eOverlayControlFlags invalid = (
- (primary) ?
- (overlay_flags & PAINT_OVERLAY_INVALID_TEXTURE_PRIMARY) :
- (overlay_flags & PAINT_OVERLAY_INVALID_TEXTURE_SECONDARY));
- target = (primary) ? &primary_snap : &secondary_snap;
-
- refresh =
- !target->overlay_texture ||
- (invalid != 0) ||
- !same_tex_snap(target, mtex, vc, col, zoom);
-
- init = (target->overlay_texture != 0);
-
- if (refresh) {
- struct ImagePool *pool = NULL;
- /* stencil is rotated later */
- const float rotation = (mtex->brush_map_mode != MTEX_MAP_MODE_STENCIL) ? -mtex->rot : 0.0f;
- const float radius = BKE_brush_size_get(vc->scene, br) * zoom;
-
- make_tex_snap(target, vc, zoom);
-
- if (mtex->brush_map_mode == MTEX_MAP_MODE_VIEW) {
- int s = BKE_brush_size_get(vc->scene, br);
- int r = 1;
-
- for (s >>= 1; s > 0; s >>= 1)
- r++;
-
- size = (1 << r);
-
- if (size < 256)
- size = 256;
-
- if (size < target->old_size)
- size = target->old_size;
- }
- else {
- size = 512;
- }
-
- if (target->old_size != size) {
- if (target->overlay_texture) {
- glDeleteTextures(1, &target->overlay_texture);
- target->overlay_texture = 0;
- }
-
- init = false;
-
- target->old_size = size;
- }
- if (col)
- buffer = MEM_mallocN(sizeof(GLubyte) * size * size * 4, "load_tex");
- else
- buffer = MEM_mallocN(sizeof(GLubyte) * size * size, "load_tex");
-
- pool = BKE_image_pool_new();
-
- if (mtex->tex && mtex->tex->nodetree) {
- /* has internal flag to detect it only does it once */
- ntreeTexBeginExecTree(mtex->tex->nodetree);
- }
-
- LoadTexData data = {
- .br = br, .vc = vc, .mtex = mtex, .buffer = buffer, .col = col,
- .pool = pool, .size = size, .rotation = rotation, .radius = radius,
- };
-
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- BLI_task_parallel_range(0, size, &data, load_tex_task_cb_ex, &settings);
-
- if (mtex->tex && mtex->tex->nodetree)
- ntreeTexEndExecTree(mtex->tex->nodetree->execdata);
-
- if (pool)
- BKE_image_pool_free(pool);
-
- if (!target->overlay_texture)
- glGenTextures(1, &target->overlay_texture);
- }
- else {
- size = target->old_size;
- }
-
- glActiveTexture(GL_TEXTURE0);
- glBindTexture(GL_TEXTURE_2D, target->overlay_texture);
-
- if (refresh) {
- GLenum format = col ? GL_RGBA : GL_RED;
- GLenum internalformat = col ? GL_RGBA8 : GL_R8;
-
- if (!init || (target->old_col != col)) {
- glTexImage2D(GL_TEXTURE_2D, 0, internalformat, size, size, 0, format, GL_UNSIGNED_BYTE, buffer);
- }
- else {
- glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, size, size, format, GL_UNSIGNED_BYTE, buffer);
- }
-
- if (buffer)
- MEM_freeN(buffer);
-
- target->old_col = col;
- }
-
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-
- if (mtex->brush_map_mode == MTEX_MAP_MODE_VIEW) {
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
- }
-
- BKE_paint_reset_overlay_invalid(invalid);
-
- return 1;
+ bool init;
+ TexSnapshot *target;
+
+ MTex *mtex = (primary) ? &br->mtex : &br->mask_mtex;
+ eOverlayControlFlags overlay_flags = BKE_paint_get_overlay_flags();
+ GLubyte *buffer = NULL;
+
+ int size;
+ bool refresh;
+ eOverlayControlFlags invalid = ((primary) ?
+ (overlay_flags & PAINT_OVERLAY_INVALID_TEXTURE_PRIMARY) :
+ (overlay_flags & PAINT_OVERLAY_INVALID_TEXTURE_SECONDARY));
+ target = (primary) ? &primary_snap : &secondary_snap;
+
+ refresh = !target->overlay_texture || (invalid != 0) ||
+ !same_tex_snap(target, mtex, vc, col, zoom);
+
+ init = (target->overlay_texture != 0);
+
+ if (refresh) {
+ struct ImagePool *pool = NULL;
+ /* stencil is rotated later */
+ const float rotation = (mtex->brush_map_mode != MTEX_MAP_MODE_STENCIL) ? -mtex->rot : 0.0f;
+ const float radius = BKE_brush_size_get(vc->scene, br) * zoom;
+
+ make_tex_snap(target, vc, zoom);
+
+ if (mtex->brush_map_mode == MTEX_MAP_MODE_VIEW) {
+ int s = BKE_brush_size_get(vc->scene, br);
+ int r = 1;
+
+ for (s >>= 1; s > 0; s >>= 1)
+ r++;
+
+ size = (1 << r);
+
+ if (size < 256)
+ size = 256;
+
+ if (size < target->old_size)
+ size = target->old_size;
+ }
+ else {
+ size = 512;
+ }
+
+ if (target->old_size != size) {
+ if (target->overlay_texture) {
+ glDeleteTextures(1, &target->overlay_texture);
+ target->overlay_texture = 0;
+ }
+
+ init = false;
+
+ target->old_size = size;
+ }
+ if (col)
+ buffer = MEM_mallocN(sizeof(GLubyte) * size * size * 4, "load_tex");
+ else
+ buffer = MEM_mallocN(sizeof(GLubyte) * size * size, "load_tex");
+
+ pool = BKE_image_pool_new();
+
+ if (mtex->tex && mtex->tex->nodetree) {
+ /* has internal flag to detect it only does it once */
+ ntreeTexBeginExecTree(mtex->tex->nodetree);
+ }
+
+ LoadTexData data = {
+ .br = br,
+ .vc = vc,
+ .mtex = mtex,
+ .buffer = buffer,
+ .col = col,
+ .pool = pool,
+ .size = size,
+ .rotation = rotation,
+ .radius = radius,
+ };
+
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ BLI_task_parallel_range(0, size, &data, load_tex_task_cb_ex, &settings);
+
+ if (mtex->tex && mtex->tex->nodetree)
+ ntreeTexEndExecTree(mtex->tex->nodetree->execdata);
+
+ if (pool)
+ BKE_image_pool_free(pool);
+
+ if (!target->overlay_texture)
+ glGenTextures(1, &target->overlay_texture);
+ }
+ else {
+ size = target->old_size;
+ }
+
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, target->overlay_texture);
+
+ if (refresh) {
+ GLenum format = col ? GL_RGBA : GL_RED;
+ GLenum internalformat = col ? GL_RGBA8 : GL_R8;
+
+ if (!init || (target->old_col != col)) {
+ glTexImage2D(
+ GL_TEXTURE_2D, 0, internalformat, size, size, 0, format, GL_UNSIGNED_BYTE, buffer);
+ }
+ else {
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, size, size, format, GL_UNSIGNED_BYTE, buffer);
+ }
+
+ if (buffer)
+ MEM_freeN(buffer);
+
+ target->old_col = col;
+ }
+
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+
+ if (mtex->brush_map_mode == MTEX_MAP_MODE_VIEW) {
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
+ }
+
+ BKE_paint_reset_overlay_invalid(invalid);
+
+ return 1;
}
-static void load_tex_cursor_task_cb(
- void *__restrict userdata,
- const int j,
- const ParallelRangeTLS *__restrict UNUSED(tls))
+static void load_tex_cursor_task_cb(void *__restrict userdata,
+ const int j,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
- LoadTexData *data = userdata;
- Brush *br = data->br;
+ LoadTexData *data = userdata;
+ Brush *br = data->br;
- GLubyte *buffer = data->buffer;
+ GLubyte *buffer = data->buffer;
- const int size = data->size;
+ const int size = data->size;
- for (int i = 0; i < size; i++) {
- // largely duplicated from tex_strength
+ for (int i = 0; i < size; i++) {
+ // largely duplicated from tex_strength
- const int index = j * size + i;
- const float x = (((float)i / size) - 0.5f) * 2.0f;
- const float y = (((float)j / size) - 0.5f) * 2.0f;
- const float len = sqrtf(x * x + y * y);
+ const int index = j * size + i;
+ const float x = (((float)i / size) - 0.5f) * 2.0f;
+ const float y = (((float)j / size) - 0.5f) * 2.0f;
+ const float len = sqrtf(x * x + y * y);
- if (len <= 1.0f) {
- float avg = BKE_brush_curve_strength_clamped(br, len, 1.0f); /* Falloff curve */
+ if (len <= 1.0f) {
+ float avg = BKE_brush_curve_strength_clamped(br, len, 1.0f); /* Falloff curve */
- buffer[index] = 255 - (GLubyte)(255 * avg);
- }
- else {
- buffer[index] = 0;
- }
- }
+ buffer[index] = 255 - (GLubyte)(255 * avg);
+ }
+ else {
+ buffer[index] = 0;
+ }
+ }
}
static int load_tex_cursor(Brush *br, ViewContext *vc, float zoom)
{
- bool init;
+ bool init;
- eOverlayControlFlags overlay_flags = BKE_paint_get_overlay_flags();
- GLubyte *buffer = NULL;
+ eOverlayControlFlags overlay_flags = BKE_paint_get_overlay_flags();
+ GLubyte *buffer = NULL;
- int size;
- const bool refresh =
- !cursor_snap.overlay_texture ||
- (overlay_flags & PAINT_OVERLAY_INVALID_CURVE) ||
- cursor_snap.zoom != zoom;
+ int size;
+ const bool refresh = !cursor_snap.overlay_texture ||
+ (overlay_flags & PAINT_OVERLAY_INVALID_CURVE) || cursor_snap.zoom != zoom;
- init = (cursor_snap.overlay_texture != 0);
+ init = (cursor_snap.overlay_texture != 0);
- if (refresh) {
- int s, r;
+ if (refresh) {
+ int s, r;
- cursor_snap.zoom = zoom;
+ cursor_snap.zoom = zoom;
- s = BKE_brush_size_get(vc->scene, br);
- r = 1;
+ s = BKE_brush_size_get(vc->scene, br);
+ r = 1;
- for (s >>= 1; s > 0; s >>= 1)
- r++;
+ for (s >>= 1; s > 0; s >>= 1)
+ r++;
- size = (1 << r);
+ size = (1 << r);
- if (size < 256)
- size = 256;
+ if (size < 256)
+ size = 256;
- if (size < cursor_snap.size)
- size = cursor_snap.size;
+ if (size < cursor_snap.size)
+ size = cursor_snap.size;
- if (cursor_snap.size != size) {
- if (cursor_snap.overlay_texture) {
- glDeleteTextures(1, &cursor_snap.overlay_texture);
- cursor_snap.overlay_texture = 0;
- }
+ if (cursor_snap.size != size) {
+ if (cursor_snap.overlay_texture) {
+ glDeleteTextures(1, &cursor_snap.overlay_texture);
+ cursor_snap.overlay_texture = 0;
+ }
- init = false;
+ init = false;
- cursor_snap.size = size;
- }
- buffer = MEM_mallocN(sizeof(GLubyte) * size * size, "load_tex");
+ cursor_snap.size = size;
+ }
+ buffer = MEM_mallocN(sizeof(GLubyte) * size * size, "load_tex");
- curvemapping_initialize(br->curve);
+ curvemapping_initialize(br->curve);
- LoadTexData data = {
- .br = br, .buffer = buffer, .size = size,
- };
+ LoadTexData data = {
+ .br = br,
+ .buffer = buffer,
+ .size = size,
+ };
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- BLI_task_parallel_range(0, size, &data, load_tex_cursor_task_cb, &settings);
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ BLI_task_parallel_range(0, size, &data, load_tex_cursor_task_cb, &settings);
- if (!cursor_snap.overlay_texture)
- glGenTextures(1, &cursor_snap.overlay_texture);
- }
- else {
- size = cursor_snap.size;
- }
+ if (!cursor_snap.overlay_texture)
+ glGenTextures(1, &cursor_snap.overlay_texture);
+ }
+ else {
+ size = cursor_snap.size;
+ }
- glActiveTexture(GL_TEXTURE0);
- glBindTexture(GL_TEXTURE_2D, cursor_snap.overlay_texture);
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, cursor_snap.overlay_texture);
- if (refresh) {
- if (!init) {
- glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, size, size, 0, GL_RED, GL_UNSIGNED_BYTE, buffer);
- }
- else {
- glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, size, size, GL_RED, GL_UNSIGNED_BYTE, buffer);
- }
+ if (refresh) {
+ if (!init) {
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, size, size, 0, GL_RED, GL_UNSIGNED_BYTE, buffer);
+ }
+ else {
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, size, size, GL_RED, GL_UNSIGNED_BYTE, buffer);
+ }
- if (buffer)
- MEM_freeN(buffer);
- }
+ if (buffer)
+ MEM_freeN(buffer);
+ }
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
- BKE_paint_reset_overlay_invalid(PAINT_OVERLAY_INVALID_CURVE);
+ BKE_paint_reset_overlay_invalid(PAINT_OVERLAY_INVALID_CURVE);
- return 1;
+ return 1;
}
-
-
-static int project_brush_radius(
- ViewContext *vc,
- float radius,
- const float location[3])
+static int project_brush_radius(ViewContext *vc, float radius, const float location[3])
{
- float view[3], nonortho[3], ortho[3], offset[3], p1[2], p2[2];
-
- ED_view3d_global_to_vector(vc->rv3d, location, view);
-
- /* create a vector that is not orthogonal to view */
-
- if (fabsf(view[0]) < 0.1f) {
- nonortho[0] = view[0] + 1.0f;
- nonortho[1] = view[1];
- nonortho[2] = view[2];
- }
- else if (fabsf(view[1]) < 0.1f) {
- nonortho[0] = view[0];
- nonortho[1] = view[1] + 1.0f;
- nonortho[2] = view[2];
- }
- else {
- nonortho[0] = view[0];
- nonortho[1] = view[1];
- nonortho[2] = view[2] + 1.0f;
- }
-
- /* get a vector in the plane of the view */
- cross_v3_v3v3(ortho, nonortho, view);
- normalize_v3(ortho);
-
- /* make a point on the surface of the brush tangent to the view */
- mul_v3_fl(ortho, radius);
- add_v3_v3v3(offset, location, ortho);
-
- /* project the center of the brush, and the tangent point to the view onto the screen */
- if ((ED_view3d_project_float_global(vc->ar, location, p1, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) &&
- (ED_view3d_project_float_global(vc->ar, offset, p2, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK))
- {
- /* the distance between these points is the size of the projected brush in pixels */
- return len_v2v2(p1, p2);
- }
- else {
- BLI_assert(0); /* assert because the code that sets up the vectors should disallow this */
- return 0;
- }
+ float view[3], nonortho[3], ortho[3], offset[3], p1[2], p2[2];
+
+ ED_view3d_global_to_vector(vc->rv3d, location, view);
+
+ /* create a vector that is not orthogonal to view */
+
+ if (fabsf(view[0]) < 0.1f) {
+ nonortho[0] = view[0] + 1.0f;
+ nonortho[1] = view[1];
+ nonortho[2] = view[2];
+ }
+ else if (fabsf(view[1]) < 0.1f) {
+ nonortho[0] = view[0];
+ nonortho[1] = view[1] + 1.0f;
+ nonortho[2] = view[2];
+ }
+ else {
+ nonortho[0] = view[0];
+ nonortho[1] = view[1];
+ nonortho[2] = view[2] + 1.0f;
+ }
+
+ /* get a vector in the plane of the view */
+ cross_v3_v3v3(ortho, nonortho, view);
+ normalize_v3(ortho);
+
+ /* make a point on the surface of the brush tangent to the view */
+ mul_v3_fl(ortho, radius);
+ add_v3_v3v3(offset, location, ortho);
+
+ /* project the center of the brush, and the tangent point to the view onto the screen */
+ if ((ED_view3d_project_float_global(vc->ar, location, p1, V3D_PROJ_TEST_NOP) ==
+ V3D_PROJ_RET_OK) &&
+ (ED_view3d_project_float_global(vc->ar, offset, p2, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK)) {
+ /* the distance between these points is the size of the projected brush in pixels */
+ return len_v2v2(p1, p2);
+ }
+ else {
+ BLI_assert(0); /* assert because the code that sets up the vectors should disallow this */
+ return 0;
+ }
}
-static bool sculpt_get_brush_geometry(
- bContext *C, ViewContext *vc,
- int x, int y, int *pixel_radius,
- float location[3], UnifiedPaintSettings *ups)
+static bool sculpt_get_brush_geometry(bContext *C,
+ ViewContext *vc,
+ int x,
+ int y,
+ int *pixel_radius,
+ float location[3],
+ UnifiedPaintSettings *ups)
{
- Scene *scene = CTX_data_scene(C);
- Paint *paint = BKE_paint_get_active_from_context(C);
- float mouse[2];
- bool hit = false;
-
- mouse[0] = x;
- mouse[1] = y;
-
- if (vc->obact->sculpt && vc->obact->sculpt->pbvh) {
- if (!ups->stroke_active) {
- hit = sculpt_stroke_get_location(C, location, mouse);
- }
- else {
- hit = ups->last_hit;
- copy_v3_v3(location, ups->last_location);
- }
- }
-
- if (hit) {
- Brush *brush = BKE_paint_brush(paint);
-
- *pixel_radius = project_brush_radius(
- vc, BKE_brush_unprojected_radius_get(scene, brush), location);
-
- if (*pixel_radius == 0)
- *pixel_radius = BKE_brush_size_get(scene, brush);
-
- mul_m4_v3(vc->obact->obmat, location);
- }
- else {
- Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
- Brush *brush = BKE_paint_brush(&sd->paint);
-
- *pixel_radius = BKE_brush_size_get(scene, brush);
- }
-
- return hit;
+ Scene *scene = CTX_data_scene(C);
+ Paint *paint = BKE_paint_get_active_from_context(C);
+ float mouse[2];
+ bool hit = false;
+
+ mouse[0] = x;
+ mouse[1] = y;
+
+ if (vc->obact->sculpt && vc->obact->sculpt->pbvh) {
+ if (!ups->stroke_active) {
+ hit = sculpt_stroke_get_location(C, location, mouse);
+ }
+ else {
+ hit = ups->last_hit;
+ copy_v3_v3(location, ups->last_location);
+ }
+ }
+
+ if (hit) {
+ Brush *brush = BKE_paint_brush(paint);
+
+ *pixel_radius = project_brush_radius(
+ vc, BKE_brush_unprojected_radius_get(scene, brush), location);
+
+ if (*pixel_radius == 0)
+ *pixel_radius = BKE_brush_size_get(scene, brush);
+
+ mul_m4_v3(vc->obact->obmat, location);
+ }
+ else {
+ Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
+ Brush *brush = BKE_paint_brush(&sd->paint);
+
+ *pixel_radius = BKE_brush_size_get(scene, brush);
+ }
+
+ return hit;
}
/* Draw an overlay that shows what effect the brush's texture will
* have on brush strength */
-static void paint_draw_tex_overlay(
- UnifiedPaintSettings *ups, Brush *brush,
- ViewContext *vc, int x, int y, float zoom, bool col, bool primary)
+static void paint_draw_tex_overlay(UnifiedPaintSettings *ups,
+ Brush *brush,
+ ViewContext *vc,
+ int x,
+ int y,
+ float zoom,
+ bool col,
+ bool primary)
{
- rctf quad;
- /* check for overlay mode */
-
- MTex *mtex = (primary) ? &brush->mtex : &brush->mask_mtex;
- bool valid = (
- (primary) ?
- (brush->overlay_flags & BRUSH_OVERLAY_PRIMARY) != 0 :
- (brush->overlay_flags & BRUSH_OVERLAY_SECONDARY) != 0);
- int overlay_alpha = (primary) ? brush->texture_overlay_alpha : brush->mask_overlay_alpha;
-
- if (!(mtex->tex) || !((mtex->brush_map_mode == MTEX_MAP_MODE_STENCIL) ||
- (valid &&
- ELEM(mtex->brush_map_mode, MTEX_MAP_MODE_VIEW, MTEX_MAP_MODE_TILED))))
- {
- return;
- }
-
- if (load_tex(brush, vc, zoom, col, primary)) {
- GPU_blend(true);
-
- glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
- glDepthMask(GL_FALSE);
- glDepthFunc(GL_ALWAYS);
-
- if (mtex->brush_map_mode == MTEX_MAP_MODE_VIEW) {
- GPU_matrix_push();
-
- /* brush rotation */
- GPU_matrix_translate_2f(x, y);
- GPU_matrix_rotate_2d(-RAD2DEGF(primary ? ups->brush_rotation : ups->brush_rotation_sec));
- GPU_matrix_translate_2f(-x, -y);
-
- /* scale based on tablet pressure */
- if (primary && ups->stroke_active && BKE_brush_use_size_pressure(vc->scene, brush)) {
- const float scale = ups->size_pressure_value;
- GPU_matrix_translate_2f(x, y);
- GPU_matrix_scale_2f(scale, scale);
- GPU_matrix_translate_2f(-x, -y);
- }
-
- if (ups->draw_anchored) {
- quad.xmin = ups->anchored_initial_mouse[0] - ups->anchored_size;
- quad.ymin = ups->anchored_initial_mouse[1] - ups->anchored_size;
- quad.xmax = ups->anchored_initial_mouse[0] + ups->anchored_size;
- quad.ymax = ups->anchored_initial_mouse[1] + ups->anchored_size;
- }
- else {
- const int radius = BKE_brush_size_get(vc->scene, brush) * zoom;
- quad.xmin = x - radius;
- quad.ymin = y - radius;
- quad.xmax = x + radius;
- quad.ymax = y + radius;
- }
- }
- else if (mtex->brush_map_mode == MTEX_MAP_MODE_TILED) {
- quad.xmin = 0;
- quad.ymin = 0;
- quad.xmax = BLI_rcti_size_x(&vc->ar->winrct);
- quad.ymax = BLI_rcti_size_y(&vc->ar->winrct);
- }
- /* Stencil code goes here */
- else {
- if (primary) {
- quad.xmin = -brush->stencil_dimension[0];
- quad.ymin = -brush->stencil_dimension[1];
- quad.xmax = brush->stencil_dimension[0];
- quad.ymax = brush->stencil_dimension[1];
- }
- else {
- quad.xmin = -brush->mask_stencil_dimension[0];
- quad.ymin = -brush->mask_stencil_dimension[1];
- quad.xmax = brush->mask_stencil_dimension[0];
- quad.ymax = brush->mask_stencil_dimension[1];
- }
- GPU_matrix_push();
- if (primary)
- GPU_matrix_translate_2fv(brush->stencil_pos);
- else
- GPU_matrix_translate_2fv(brush->mask_stencil_pos);
- GPU_matrix_rotate_2d(RAD2DEGF(mtex->rot));
- }
-
- /* set quad color. Colored overlay does not get blending */
- GPUVertFormat *format = immVertexFormat();
- uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- uint texCoord = GPU_vertformat_attr_add(format, "texCoord", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
-
- if (col) {
- immBindBuiltinProgram(GPU_SHADER_2D_IMAGE_COLOR);
- immUniformColor4f(1.0f, 1.0f, 1.0f, overlay_alpha * 0.01f);
- }
- else {
- GPU_blend_set_func(GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
- immBindBuiltinProgram(GPU_SHADER_2D_IMAGE_ALPHA_COLOR);
- immUniformColor3fvAlpha(U.sculpt_paint_overlay_col, overlay_alpha * 0.01f);
- }
-
- /* draw textured quad */
- immUniform1i("image", 0);
-
- immBegin(GPU_PRIM_TRI_FAN, 4);
- immAttr2f(texCoord, 0.0f, 0.0f);
- immVertex2f(pos, quad.xmin, quad.ymin);
- immAttr2f(texCoord, 1.0f, 0.0f);
- immVertex2f(pos, quad.xmax, quad.ymin);
- immAttr2f(texCoord, 1.0f, 1.0f);
- immVertex2f(pos, quad.xmax, quad.ymax);
- immAttr2f(texCoord, 0.0f, 1.0f);
- immVertex2f(pos, quad.xmin, quad.ymax);
- immEnd();
-
- immUnbindProgram();
- GPU_blend_set_func(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA);
-
- if (ELEM(mtex->brush_map_mode, MTEX_MAP_MODE_STENCIL, MTEX_MAP_MODE_VIEW)) {
- GPU_matrix_pop();
- }
- }
+ rctf quad;
+ /* check for overlay mode */
+
+ MTex *mtex = (primary) ? &brush->mtex : &brush->mask_mtex;
+ bool valid = ((primary) ? (brush->overlay_flags & BRUSH_OVERLAY_PRIMARY) != 0 :
+ (brush->overlay_flags & BRUSH_OVERLAY_SECONDARY) != 0);
+ int overlay_alpha = (primary) ? brush->texture_overlay_alpha : brush->mask_overlay_alpha;
+
+ if (!(mtex->tex) ||
+ !((mtex->brush_map_mode == MTEX_MAP_MODE_STENCIL) ||
+ (valid && ELEM(mtex->brush_map_mode, MTEX_MAP_MODE_VIEW, MTEX_MAP_MODE_TILED)))) {
+ return;
+ }
+
+ if (load_tex(brush, vc, zoom, col, primary)) {
+ GPU_blend(true);
+
+ glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+ glDepthMask(GL_FALSE);
+ glDepthFunc(GL_ALWAYS);
+
+ if (mtex->brush_map_mode == MTEX_MAP_MODE_VIEW) {
+ GPU_matrix_push();
+
+ /* brush rotation */
+ GPU_matrix_translate_2f(x, y);
+ GPU_matrix_rotate_2d(-RAD2DEGF(primary ? ups->brush_rotation : ups->brush_rotation_sec));
+ GPU_matrix_translate_2f(-x, -y);
+
+ /* scale based on tablet pressure */
+ if (primary && ups->stroke_active && BKE_brush_use_size_pressure(vc->scene, brush)) {
+ const float scale = ups->size_pressure_value;
+ GPU_matrix_translate_2f(x, y);
+ GPU_matrix_scale_2f(scale, scale);
+ GPU_matrix_translate_2f(-x, -y);
+ }
+
+ if (ups->draw_anchored) {
+ quad.xmin = ups->anchored_initial_mouse[0] - ups->anchored_size;
+ quad.ymin = ups->anchored_initial_mouse[1] - ups->anchored_size;
+ quad.xmax = ups->anchored_initial_mouse[0] + ups->anchored_size;
+ quad.ymax = ups->anchored_initial_mouse[1] + ups->anchored_size;
+ }
+ else {
+ const int radius = BKE_brush_size_get(vc->scene, brush) * zoom;
+ quad.xmin = x - radius;
+ quad.ymin = y - radius;
+ quad.xmax = x + radius;
+ quad.ymax = y + radius;
+ }
+ }
+ else if (mtex->brush_map_mode == MTEX_MAP_MODE_TILED) {
+ quad.xmin = 0;
+ quad.ymin = 0;
+ quad.xmax = BLI_rcti_size_x(&vc->ar->winrct);
+ quad.ymax = BLI_rcti_size_y(&vc->ar->winrct);
+ }
+ /* Stencil code goes here */
+ else {
+ if (primary) {
+ quad.xmin = -brush->stencil_dimension[0];
+ quad.ymin = -brush->stencil_dimension[1];
+ quad.xmax = brush->stencil_dimension[0];
+ quad.ymax = brush->stencil_dimension[1];
+ }
+ else {
+ quad.xmin = -brush->mask_stencil_dimension[0];
+ quad.ymin = -brush->mask_stencil_dimension[1];
+ quad.xmax = brush->mask_stencil_dimension[0];
+ quad.ymax = brush->mask_stencil_dimension[1];
+ }
+ GPU_matrix_push();
+ if (primary)
+ GPU_matrix_translate_2fv(brush->stencil_pos);
+ else
+ GPU_matrix_translate_2fv(brush->mask_stencil_pos);
+ GPU_matrix_rotate_2d(RAD2DEGF(mtex->rot));
+ }
+
+ /* set quad color. Colored overlay does not get blending */
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ uint texCoord = GPU_vertformat_attr_add(format, "texCoord", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+
+ if (col) {
+ immBindBuiltinProgram(GPU_SHADER_2D_IMAGE_COLOR);
+ immUniformColor4f(1.0f, 1.0f, 1.0f, overlay_alpha * 0.01f);
+ }
+ else {
+ GPU_blend_set_func(GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
+ immBindBuiltinProgram(GPU_SHADER_2D_IMAGE_ALPHA_COLOR);
+ immUniformColor3fvAlpha(U.sculpt_paint_overlay_col, overlay_alpha * 0.01f);
+ }
+
+ /* draw textured quad */
+ immUniform1i("image", 0);
+
+ immBegin(GPU_PRIM_TRI_FAN, 4);
+ immAttr2f(texCoord, 0.0f, 0.0f);
+ immVertex2f(pos, quad.xmin, quad.ymin);
+ immAttr2f(texCoord, 1.0f, 0.0f);
+ immVertex2f(pos, quad.xmax, quad.ymin);
+ immAttr2f(texCoord, 1.0f, 1.0f);
+ immVertex2f(pos, quad.xmax, quad.ymax);
+ immAttr2f(texCoord, 0.0f, 1.0f);
+ immVertex2f(pos, quad.xmin, quad.ymax);
+ immEnd();
+
+ immUnbindProgram();
+ GPU_blend_set_func(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA);
+
+ if (ELEM(mtex->brush_map_mode, MTEX_MAP_MODE_STENCIL, MTEX_MAP_MODE_VIEW)) {
+ GPU_matrix_pop();
+ }
+ }
}
/* Draw an overlay that shows what effect the brush's texture will
* have on brush strength */
static void paint_draw_cursor_overlay(
- UnifiedPaintSettings *ups, Brush *brush,
- ViewContext *vc, int x, int y, float zoom)
+ UnifiedPaintSettings *ups, Brush *brush, ViewContext *vc, int x, int y, float zoom)
{
- rctf quad;
- /* check for overlay mode */
-
- if (!(brush->overlay_flags & BRUSH_OVERLAY_CURSOR)) {
- return;
- }
-
- if (load_tex_cursor(brush, vc, zoom)) {
- bool do_pop = false;
- float center[2];
- GPU_blend(true);
-
- glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
- glDepthMask(GL_FALSE);
- glDepthFunc(GL_ALWAYS);
-
- if (ups->draw_anchored) {
- copy_v2_v2(center, ups->anchored_initial_mouse);
- quad.xmin = ups->anchored_initial_mouse[0] - ups->anchored_size;
- quad.ymin = ups->anchored_initial_mouse[1] - ups->anchored_size;
- quad.xmax = ups->anchored_initial_mouse[0] + ups->anchored_size;
- quad.ymax = ups->anchored_initial_mouse[1] + ups->anchored_size;
- }
- else {
- const int radius = BKE_brush_size_get(vc->scene, brush) * zoom;
- center[0] = x;
- center[1] = y;
-
- quad.xmin = x - radius;
- quad.ymin = y - radius;
- quad.xmax = x + radius;
- quad.ymax = y + radius;
- }
-
- /* scale based on tablet pressure */
- if (ups->stroke_active && BKE_brush_use_size_pressure(vc->scene, brush)) {
- do_pop = true;
- GPU_matrix_push();
- GPU_matrix_translate_2fv(center);
- GPU_matrix_scale_1f(ups->size_pressure_value);
- GPU_matrix_translate_2f(-center[0], -center[1]);
- }
-
- GPUVertFormat *format = immVertexFormat();
- uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- uint texCoord = GPU_vertformat_attr_add(format, "texCoord", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
-
- GPU_blend_set_func(GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
- immBindBuiltinProgram(GPU_SHADER_2D_IMAGE_ALPHA_COLOR);
-
- immUniformColor3fvAlpha(U.sculpt_paint_overlay_col, brush->cursor_overlay_alpha * 0.01f);
-
- /* draw textured quad */
-
- /* draw textured quad */
- immUniform1i("image", 0);
-
- immBegin(GPU_PRIM_TRI_FAN, 4);
- immAttr2f(texCoord, 0.0f, 0.0f);
- immVertex2f(pos, quad.xmin, quad.ymin);
- immAttr2f(texCoord, 1.0f, 0.0f);
- immVertex2f(pos, quad.xmax, quad.ymin);
- immAttr2f(texCoord, 1.0f, 1.0f);
- immVertex2f(pos, quad.xmax, quad.ymax);
- immAttr2f(texCoord, 0.0f, 1.0f);
- immVertex2f(pos, quad.xmin, quad.ymax);
- immEnd();
-
- immUnbindProgram();
-
- GPU_blend_set_func(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA);
-
- if (do_pop)
- GPU_matrix_pop();
- }
+ rctf quad;
+ /* check for overlay mode */
+
+ if (!(brush->overlay_flags & BRUSH_OVERLAY_CURSOR)) {
+ return;
+ }
+
+ if (load_tex_cursor(brush, vc, zoom)) {
+ bool do_pop = false;
+ float center[2];
+ GPU_blend(true);
+
+ glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+ glDepthMask(GL_FALSE);
+ glDepthFunc(GL_ALWAYS);
+
+ if (ups->draw_anchored) {
+ copy_v2_v2(center, ups->anchored_initial_mouse);
+ quad.xmin = ups->anchored_initial_mouse[0] - ups->anchored_size;
+ quad.ymin = ups->anchored_initial_mouse[1] - ups->anchored_size;
+ quad.xmax = ups->anchored_initial_mouse[0] + ups->anchored_size;
+ quad.ymax = ups->anchored_initial_mouse[1] + ups->anchored_size;
+ }
+ else {
+ const int radius = BKE_brush_size_get(vc->scene, brush) * zoom;
+ center[0] = x;
+ center[1] = y;
+
+ quad.xmin = x - radius;
+ quad.ymin = y - radius;
+ quad.xmax = x + radius;
+ quad.ymax = y + radius;
+ }
+
+ /* scale based on tablet pressure */
+ if (ups->stroke_active && BKE_brush_use_size_pressure(vc->scene, brush)) {
+ do_pop = true;
+ GPU_matrix_push();
+ GPU_matrix_translate_2fv(center);
+ GPU_matrix_scale_1f(ups->size_pressure_value);
+ GPU_matrix_translate_2f(-center[0], -center[1]);
+ }
+
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ uint texCoord = GPU_vertformat_attr_add(format, "texCoord", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+
+ GPU_blend_set_func(GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
+ immBindBuiltinProgram(GPU_SHADER_2D_IMAGE_ALPHA_COLOR);
+
+ immUniformColor3fvAlpha(U.sculpt_paint_overlay_col, brush->cursor_overlay_alpha * 0.01f);
+
+ /* draw textured quad */
+
+ /* draw textured quad */
+ immUniform1i("image", 0);
+
+ immBegin(GPU_PRIM_TRI_FAN, 4);
+ immAttr2f(texCoord, 0.0f, 0.0f);
+ immVertex2f(pos, quad.xmin, quad.ymin);
+ immAttr2f(texCoord, 1.0f, 0.0f);
+ immVertex2f(pos, quad.xmax, quad.ymin);
+ immAttr2f(texCoord, 1.0f, 1.0f);
+ immVertex2f(pos, quad.xmax, quad.ymax);
+ immAttr2f(texCoord, 0.0f, 1.0f);
+ immVertex2f(pos, quad.xmin, quad.ymax);
+ immEnd();
+
+ immUnbindProgram();
+
+ GPU_blend_set_func(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA);
+
+ if (do_pop)
+ GPU_matrix_pop();
+ }
}
-static void paint_draw_alpha_overlay(
- UnifiedPaintSettings *ups, Brush *brush,
- ViewContext *vc, int x, int y, float zoom, ePaintMode mode)
+static void paint_draw_alpha_overlay(UnifiedPaintSettings *ups,
+ Brush *brush,
+ ViewContext *vc,
+ int x,
+ int y,
+ float zoom,
+ ePaintMode mode)
{
- /* Color means that primary brush texture is colored and
- * secondary is used for alpha/mask control. */
- bool col = ELEM(mode, PAINT_MODE_TEXTURE_3D, PAINT_MODE_TEXTURE_2D, PAINT_MODE_VERTEX);
- eOverlayControlFlags flags = BKE_paint_get_overlay_flags();
- gpuPushAttr(GPU_DEPTH_BUFFER_BIT | GPU_BLEND_BIT);
-
- /* Translate to region. */
- GPU_matrix_push();
- GPU_matrix_translate_2f(vc->ar->winrct.xmin, vc->ar->winrct.ymin);
- x -= vc->ar->winrct.xmin;
- y -= vc->ar->winrct.ymin;
-
- /* coloured overlay should be drawn separately */
- if (col) {
- if (!(flags & PAINT_OVERLAY_OVERRIDE_PRIMARY))
- paint_draw_tex_overlay(ups, brush, vc, x, y, zoom, true, true);
- if (!(flags & PAINT_OVERLAY_OVERRIDE_SECONDARY))
- paint_draw_tex_overlay(ups, brush, vc, x, y, zoom, false, false);
- if (!(flags & PAINT_OVERLAY_OVERRIDE_CURSOR))
- paint_draw_cursor_overlay(ups, brush, vc, x, y, zoom);
- }
- else {
- if (!(flags & PAINT_OVERLAY_OVERRIDE_PRIMARY) && (mode != PAINT_MODE_WEIGHT))
- paint_draw_tex_overlay(ups, brush, vc, x, y, zoom, false, true);
- if (!(flags & PAINT_OVERLAY_OVERRIDE_CURSOR))
- paint_draw_cursor_overlay(ups, brush, vc, x, y, zoom);
- }
-
- GPU_matrix_pop();
- gpuPopAttr();
+ /* Color means that primary brush texture is colored and
+ * secondary is used for alpha/mask control. */
+ bool col = ELEM(mode, PAINT_MODE_TEXTURE_3D, PAINT_MODE_TEXTURE_2D, PAINT_MODE_VERTEX);
+ eOverlayControlFlags flags = BKE_paint_get_overlay_flags();
+ gpuPushAttr(GPU_DEPTH_BUFFER_BIT | GPU_BLEND_BIT);
+
+ /* Translate to region. */
+ GPU_matrix_push();
+ GPU_matrix_translate_2f(vc->ar->winrct.xmin, vc->ar->winrct.ymin);
+ x -= vc->ar->winrct.xmin;
+ y -= vc->ar->winrct.ymin;
+
+ /* coloured overlay should be drawn separately */
+ if (col) {
+ if (!(flags & PAINT_OVERLAY_OVERRIDE_PRIMARY))
+ paint_draw_tex_overlay(ups, brush, vc, x, y, zoom, true, true);
+ if (!(flags & PAINT_OVERLAY_OVERRIDE_SECONDARY))
+ paint_draw_tex_overlay(ups, brush, vc, x, y, zoom, false, false);
+ if (!(flags & PAINT_OVERLAY_OVERRIDE_CURSOR))
+ paint_draw_cursor_overlay(ups, brush, vc, x, y, zoom);
+ }
+ else {
+ if (!(flags & PAINT_OVERLAY_OVERRIDE_PRIMARY) && (mode != PAINT_MODE_WEIGHT))
+ paint_draw_tex_overlay(ups, brush, vc, x, y, zoom, false, true);
+ if (!(flags & PAINT_OVERLAY_OVERRIDE_CURSOR))
+ paint_draw_cursor_overlay(ups, brush, vc, x, y, zoom);
+ }
+
+ GPU_matrix_pop();
+ gpuPopAttr();
}
-
BLI_INLINE void draw_tri_point(
- unsigned int pos, float sel_col[4], float pivot_col[4],
- float *co, float width, bool selected)
+ unsigned int pos, float sel_col[4], float pivot_col[4], float *co, float width, bool selected)
{
- immUniformColor4fv(selected ? sel_col : pivot_col);
-
- GPU_line_width(3.0f);
-
- float w = width / 2.0f;
- float tri[3][2] = {
- {co[0], co[1] + w},
- {co[0] - w, co[1] - w},
- {co[0] + w, co[1] - w},
- };
-
- immBegin(GPU_PRIM_LINE_LOOP, 3);
- immVertex2fv(pos, tri[0]);
- immVertex2fv(pos, tri[1]);
- immVertex2fv(pos, tri[2]);
- immEnd();
-
- immUniformColor4f(1.0f, 1.0f, 1.0f, 0.5f);
- GPU_line_width(1.0f);
-
- immBegin(GPU_PRIM_LINE_LOOP, 3);
- immVertex2fv(pos, tri[0]);
- immVertex2fv(pos, tri[1]);
- immVertex2fv(pos, tri[2]);
- immEnd();
+ immUniformColor4fv(selected ? sel_col : pivot_col);
+
+ GPU_line_width(3.0f);
+
+ float w = width / 2.0f;
+ float tri[3][2] = {
+ {co[0], co[1] + w},
+ {co[0] - w, co[1] - w},
+ {co[0] + w, co[1] - w},
+ };
+
+ immBegin(GPU_PRIM_LINE_LOOP, 3);
+ immVertex2fv(pos, tri[0]);
+ immVertex2fv(pos, tri[1]);
+ immVertex2fv(pos, tri[2]);
+ immEnd();
+
+ immUniformColor4f(1.0f, 1.0f, 1.0f, 0.5f);
+ GPU_line_width(1.0f);
+
+ immBegin(GPU_PRIM_LINE_LOOP, 3);
+ immVertex2fv(pos, tri[0]);
+ immVertex2fv(pos, tri[1]);
+ immVertex2fv(pos, tri[2]);
+ immEnd();
}
BLI_INLINE void draw_rect_point(
- unsigned int pos, float sel_col[4], float handle_col[4],
- float *co, float width, bool selected)
+ unsigned int pos, float sel_col[4], float handle_col[4], float *co, float width, bool selected)
{
- immUniformColor4fv(selected ? sel_col : handle_col);
+ immUniformColor4fv(selected ? sel_col : handle_col);
- GPU_line_width(3.0f);
+ GPU_line_width(3.0f);
- float w = width / 2.0f;
- float minx = co[0] - w;
- float miny = co[1] - w;
- float maxx = co[0] + w;
- float maxy = co[1] + w;
+ float w = width / 2.0f;
+ float minx = co[0] - w;
+ float miny = co[1] - w;
+ float maxx = co[0] + w;
+ float maxy = co[1] + w;
- imm_draw_box_wire_2d(pos, minx, miny, maxx, maxy);
+ imm_draw_box_wire_2d(pos, minx, miny, maxx, maxy);
- immUniformColor4f(1.0f, 1.0f, 1.0f, 0.5f);
- GPU_line_width(1.0f);
+ immUniformColor4f(1.0f, 1.0f, 1.0f, 0.5f);
+ GPU_line_width(1.0f);
- imm_draw_box_wire_2d(pos, minx, miny, maxx, maxy);
+ imm_draw_box_wire_2d(pos, minx, miny, maxx, maxy);
}
-
BLI_INLINE void draw_bezier_handle_lines(unsigned int pos, float sel_col[4], BezTriple *bez)
{
- immUniformColor4f(0.0f, 0.0f, 0.0f, 0.5f);
- GPU_line_width(3.0f);
-
- immBegin(GPU_PRIM_LINE_STRIP, 3);
- immVertex2fv(pos, bez->vec[0]);
- immVertex2fv(pos, bez->vec[1]);
- immVertex2fv(pos, bez->vec[2]);
- immEnd();
-
- GPU_line_width(1.0f);
-
- if (bez->f1 || bez->f2) {
- immUniformColor4fv(sel_col);
- }
- else {
- immUniformColor4f(1.0f, 1.0f, 1.0f, 0.5f);
- }
- immBegin(GPU_PRIM_LINES, 2);
- immVertex2fv(pos, bez->vec[0]);
- immVertex2fv(pos, bez->vec[1]);
- immEnd();
-
- if (bez->f3 || bez->f2) {
- immUniformColor4fv(sel_col);
- }
- else {
- immUniformColor4f(1.0f, 1.0f, 1.0f, 0.5f);
- }
- immBegin(GPU_PRIM_LINES, 2);
- immVertex2fv(pos, bez->vec[1]);
- immVertex2fv(pos, bez->vec[2]);
- immEnd();
+ immUniformColor4f(0.0f, 0.0f, 0.0f, 0.5f);
+ GPU_line_width(3.0f);
+
+ immBegin(GPU_PRIM_LINE_STRIP, 3);
+ immVertex2fv(pos, bez->vec[0]);
+ immVertex2fv(pos, bez->vec[1]);
+ immVertex2fv(pos, bez->vec[2]);
+ immEnd();
+
+ GPU_line_width(1.0f);
+
+ if (bez->f1 || bez->f2) {
+ immUniformColor4fv(sel_col);
+ }
+ else {
+ immUniformColor4f(1.0f, 1.0f, 1.0f, 0.5f);
+ }
+ immBegin(GPU_PRIM_LINES, 2);
+ immVertex2fv(pos, bez->vec[0]);
+ immVertex2fv(pos, bez->vec[1]);
+ immEnd();
+
+ if (bez->f3 || bez->f2) {
+ immUniformColor4fv(sel_col);
+ }
+ else {
+ immUniformColor4f(1.0f, 1.0f, 1.0f, 0.5f);
+ }
+ immBegin(GPU_PRIM_LINES, 2);
+ immVertex2fv(pos, bez->vec[1]);
+ immVertex2fv(pos, bez->vec[2]);
+ immEnd();
}
static void paint_draw_curve_cursor(Brush *brush, ViewContext *vc)
{
- GPU_matrix_push();
- GPU_matrix_translate_2f(vc->ar->winrct.xmin, vc->ar->winrct.ymin);
-
- if (brush->paint_curve && brush->paint_curve->points) {
- int i;
- PaintCurve *pc = brush->paint_curve;
- PaintCurvePoint *cp = pc->points;
-
- GPU_line_smooth(true);
- GPU_blend(true);
-
- /* draw the bezier handles and the curve segment between the current and next point */
- uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
-
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
-
- float selec_col[4], handle_col[4], pivot_col[4];
- UI_GetThemeColor4fv(TH_VERTEX_SELECT, selec_col);
- UI_GetThemeColor4fv(TH_PAINT_CURVE_HANDLE, handle_col);
- UI_GetThemeColor4fv(TH_PAINT_CURVE_PIVOT, pivot_col);
-
- for (i = 0; i < pc->tot_points - 1; i++, cp++) {
- int j;
- PaintCurvePoint *cp_next = cp + 1;
- float data[(PAINT_CURVE_NUM_SEGMENTS + 1) * 2];
- /* use color coding to distinguish handles vs curve segments */
- draw_bezier_handle_lines(pos, selec_col, &cp->bez);
- draw_tri_point(pos, selec_col, pivot_col, &cp->bez.vec[1][0], 10.0f, cp->bez.f2);
- draw_rect_point(pos, selec_col, handle_col, &cp->bez.vec[0][0], 8.0f, cp->bez.f1 || cp->bez.f2);
- draw_rect_point(pos, selec_col, handle_col, &cp->bez.vec[2][0], 8.0f, cp->bez.f3 || cp->bez.f2);
-
- for (j = 0; j < 2; j++)
- BKE_curve_forward_diff_bezier(
- cp->bez.vec[1][j],
- cp->bez.vec[2][j],
- cp_next->bez.vec[0][j],
- cp_next->bez.vec[1][j],
- data + j, PAINT_CURVE_NUM_SEGMENTS, sizeof(float[2]));
-
- float (*v)[2] = (float(*)[2])data;
-
- immUniformColor4f(0.0f, 0.0f, 0.0f, 0.5f);
- GPU_line_width(3.0f);
- immBegin(GPU_PRIM_LINE_STRIP, PAINT_CURVE_NUM_SEGMENTS + 1);
- for (j = 0; j <= PAINT_CURVE_NUM_SEGMENTS; j++) {
- immVertex2fv(pos, v[j]);
- }
- immEnd();
-
- immUniformColor4f(0.9f, 0.9f, 1.0f, 0.5f);
- GPU_line_width(1.0f);
- immBegin(GPU_PRIM_LINE_STRIP, PAINT_CURVE_NUM_SEGMENTS + 1);
- for (j = 0; j <= PAINT_CURVE_NUM_SEGMENTS; j++) {
- immVertex2fv(pos, v[j]);
- }
- immEnd();
- }
-
- /* draw last line segment */
- draw_bezier_handle_lines(pos, selec_col, &cp->bez);
- draw_tri_point(pos, selec_col, pivot_col, &cp->bez.vec[1][0], 10.0f, cp->bez.f2);
- draw_rect_point(pos, selec_col, handle_col, &cp->bez.vec[0][0], 8.0f, cp->bez.f1 || cp->bez.f2);
- draw_rect_point(pos, selec_col, handle_col, &cp->bez.vec[2][0], 8.0f, cp->bez.f3 || cp->bez.f2);
-
- GPU_blend(false);
- GPU_line_smooth(false);
-
- immUnbindProgram();
- }
- GPU_matrix_pop();
+ GPU_matrix_push();
+ GPU_matrix_translate_2f(vc->ar->winrct.xmin, vc->ar->winrct.ymin);
+
+ if (brush->paint_curve && brush->paint_curve->points) {
+ int i;
+ PaintCurve *pc = brush->paint_curve;
+ PaintCurvePoint *cp = pc->points;
+
+ GPU_line_smooth(true);
+ GPU_blend(true);
+
+ /* draw the bezier handles and the curve segment between the current and next point */
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
+ float selec_col[4], handle_col[4], pivot_col[4];
+ UI_GetThemeColor4fv(TH_VERTEX_SELECT, selec_col);
+ UI_GetThemeColor4fv(TH_PAINT_CURVE_HANDLE, handle_col);
+ UI_GetThemeColor4fv(TH_PAINT_CURVE_PIVOT, pivot_col);
+
+ for (i = 0; i < pc->tot_points - 1; i++, cp++) {
+ int j;
+ PaintCurvePoint *cp_next = cp + 1;
+ float data[(PAINT_CURVE_NUM_SEGMENTS + 1) * 2];
+ /* use color coding to distinguish handles vs curve segments */
+ draw_bezier_handle_lines(pos, selec_col, &cp->bez);
+ draw_tri_point(pos, selec_col, pivot_col, &cp->bez.vec[1][0], 10.0f, cp->bez.f2);
+ draw_rect_point(
+ pos, selec_col, handle_col, &cp->bez.vec[0][0], 8.0f, cp->bez.f1 || cp->bez.f2);
+ draw_rect_point(
+ pos, selec_col, handle_col, &cp->bez.vec[2][0], 8.0f, cp->bez.f3 || cp->bez.f2);
+
+ for (j = 0; j < 2; j++)
+ BKE_curve_forward_diff_bezier(cp->bez.vec[1][j],
+ cp->bez.vec[2][j],
+ cp_next->bez.vec[0][j],
+ cp_next->bez.vec[1][j],
+ data + j,
+ PAINT_CURVE_NUM_SEGMENTS,
+ sizeof(float[2]));
+
+ float(*v)[2] = (float(*)[2])data;
+
+ immUniformColor4f(0.0f, 0.0f, 0.0f, 0.5f);
+ GPU_line_width(3.0f);
+ immBegin(GPU_PRIM_LINE_STRIP, PAINT_CURVE_NUM_SEGMENTS + 1);
+ for (j = 0; j <= PAINT_CURVE_NUM_SEGMENTS; j++) {
+ immVertex2fv(pos, v[j]);
+ }
+ immEnd();
+
+ immUniformColor4f(0.9f, 0.9f, 1.0f, 0.5f);
+ GPU_line_width(1.0f);
+ immBegin(GPU_PRIM_LINE_STRIP, PAINT_CURVE_NUM_SEGMENTS + 1);
+ for (j = 0; j <= PAINT_CURVE_NUM_SEGMENTS; j++) {
+ immVertex2fv(pos, v[j]);
+ }
+ immEnd();
+ }
+
+ /* draw last line segment */
+ draw_bezier_handle_lines(pos, selec_col, &cp->bez);
+ draw_tri_point(pos, selec_col, pivot_col, &cp->bez.vec[1][0], 10.0f, cp->bez.f2);
+ draw_rect_point(
+ pos, selec_col, handle_col, &cp->bez.vec[0][0], 8.0f, cp->bez.f1 || cp->bez.f2);
+ draw_rect_point(
+ pos, selec_col, handle_col, &cp->bez.vec[2][0], 8.0f, cp->bez.f3 || cp->bez.f2);
+
+ GPU_blend(false);
+ GPU_line_smooth(false);
+
+ immUnbindProgram();
+ }
+ GPU_matrix_pop();
}
/* Special actions taken when paint cursor goes over mesh */
/* TODO: sculpt only for now */
-static void paint_cursor_on_hit(
- UnifiedPaintSettings *ups, Brush *brush, ViewContext *vc,
- const float location[3])
+static void paint_cursor_on_hit(UnifiedPaintSettings *ups,
+ Brush *brush,
+ ViewContext *vc,
+ const float location[3])
{
- float unprojected_radius, projected_radius;
-
- /* update the brush's cached 3D radius */
- if (!BKE_brush_use_locked_size(vc->scene, brush)) {
- /* get 2D brush radius */
- if (ups->draw_anchored)
- projected_radius = ups->anchored_size;
- else {
- if (brush->flag & BRUSH_ANCHORED)
- projected_radius = 8;
- else
- projected_radius = BKE_brush_size_get(vc->scene, brush);
- }
-
- /* convert brush radius from 2D to 3D */
- unprojected_radius = paint_calc_object_space_radius(
- vc, location, projected_radius);
-
- /* scale 3D brush radius by pressure */
- if (ups->stroke_active && BKE_brush_use_size_pressure(vc->scene, brush))
- unprojected_radius *= ups->size_pressure_value;
-
- /* set cached value in either Brush or UnifiedPaintSettings */
- BKE_brush_unprojected_radius_set(vc->scene, brush, unprojected_radius);
- }
+ float unprojected_radius, projected_radius;
+
+ /* update the brush's cached 3D radius */
+ if (!BKE_brush_use_locked_size(vc->scene, brush)) {
+ /* get 2D brush radius */
+ if (ups->draw_anchored)
+ projected_radius = ups->anchored_size;
+ else {
+ if (brush->flag & BRUSH_ANCHORED)
+ projected_radius = 8;
+ else
+ projected_radius = BKE_brush_size_get(vc->scene, brush);
+ }
+
+ /* convert brush radius from 2D to 3D */
+ unprojected_radius = paint_calc_object_space_radius(vc, location, projected_radius);
+
+ /* scale 3D brush radius by pressure */
+ if (ups->stroke_active && BKE_brush_use_size_pressure(vc->scene, brush))
+ unprojected_radius *= ups->size_pressure_value;
+
+ /* set cached value in either Brush or UnifiedPaintSettings */
+ BKE_brush_unprojected_radius_set(vc->scene, brush, unprojected_radius);
+ }
}
static bool ommit_cursor_drawing(Paint *paint, ePaintMode mode, Brush *brush)
{
- if (paint->flags & PAINT_SHOW_BRUSH) {
- if (ELEM(mode, PAINT_MODE_TEXTURE_2D, PAINT_MODE_TEXTURE_3D) && brush->imagepaint_tool == PAINT_TOOL_FILL) {
- return true;
- }
- return false;
- }
- return true;
+ if (paint->flags & PAINT_SHOW_BRUSH) {
+ if (ELEM(mode, PAINT_MODE_TEXTURE_2D, PAINT_MODE_TEXTURE_3D) &&
+ brush->imagepaint_tool == PAINT_TOOL_FILL) {
+ return true;
+ }
+ return false;
+ }
+ return true;
}
static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused))
{
- Scene *scene = CTX_data_scene(C);
- ARegion *ar = CTX_wm_region(C);
- UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
- Paint *paint = BKE_paint_get_active_from_context(C);
- Brush *brush = BKE_paint_brush(paint);
- ePaintMode mode = BKE_paintmode_get_active_from_context(C);
-
- /* check that brush drawing is enabled */
- if (ommit_cursor_drawing(paint, mode, brush))
- return;
-
- /* can't use stroke vc here because this will be called during
- * mouse over too, not just during a stroke */
- ViewContext vc;
- ED_view3d_viewcontext_init(C, &vc);
-
- if (vc.rv3d && (vc.rv3d->rflag & RV3D_NAVIGATING)) {
- return;
- }
-
- /* skip everything and draw brush here */
- if (brush->flag & BRUSH_CURVE) {
- paint_draw_curve_cursor(brush, &vc);
- return;
- }
-
- float zoomx, zoomy;
- get_imapaint_zoom(C, &zoomx, &zoomy);
- zoomx = max_ff(zoomx, zoomy);
-
- /* set various defaults */
- const float *outline_col = brush->add_col;
- const float outline_alpha = 0.5f;
- float translation[2] = { x, y };
- float final_radius = (BKE_brush_size_get(scene, brush) * zoomx);
-
- /* don't calculate rake angles while a stroke is active because the rake variables are global
- * and we may get interference with the stroke itself.
- * For line strokes, such interference is visible */
- if (!ups->stroke_active) {
- paint_calculate_rake_rotation(ups, brush, translation);
- }
-
- /* draw overlay */
- paint_draw_alpha_overlay(ups, brush, &vc, x, y, zoomx, mode);
-
- /* TODO: as sculpt and other paint modes are unified, this
- * special mode of drawing will go away */
- if ((mode == PAINT_MODE_SCULPT) && vc.obact->sculpt) {
- float location[3];
- int pixel_radius;
-
- /* test if brush is over the mesh */
- bool hit = sculpt_get_brush_geometry(C, &vc, x, y, &pixel_radius, location, ups);
-
- if (BKE_brush_use_locked_size(scene, brush))
- BKE_brush_size_set(scene, brush, pixel_radius);
-
- /* check if brush is subtracting, use different color then */
- /* TODO: no way currently to know state of pen flip or
- * invert key modifier without starting a stroke */
- if (((ups->draw_inverted == 0) ^ ((brush->flag & BRUSH_DIR_IN) == 0)) &&
- BKE_brush_sculpt_has_secondary_color(brush))
- {
- outline_col = brush->sub_col;
- }
-
- /* only do if brush is over the mesh */
- if (hit)
- paint_cursor_on_hit(ups, brush, &vc, location);
- }
-
- if (ups->draw_anchored) {
- final_radius = ups->anchored_size;
- copy_v2_fl2(translation,
- ups->anchored_initial_mouse[0] + ar->winrct.xmin,
- ups->anchored_initial_mouse[1] + ar->winrct.ymin);
- }
-
- /* make lines pretty */
- GPU_line_width(1.0f);
- GPU_blend(true); /* TODO: also set blend mode? */
- GPU_line_smooth(true);
-
- uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
-
- /* set brush color */
- immUniformColor3fvAlpha(outline_col, outline_alpha);
-
- /* draw brush outline */
- if (ups->stroke_active && BKE_brush_use_size_pressure(scene, brush)) {
- /* inner at full alpha */
- imm_draw_circle_wire_2d(pos, translation[0], translation[1], final_radius * ups->size_pressure_value, 40);
- /* outer at half alpha */
- immUniformColor3fvAlpha(outline_col, outline_alpha * 0.5f);
- }
- imm_draw_circle_wire_2d(pos, translation[0], translation[1], final_radius, 40);
-
- immUnbindProgram();
-
- /* restore GL state */
- GPU_blend(false);
- GPU_line_smooth(false);
+ Scene *scene = CTX_data_scene(C);
+ ARegion *ar = CTX_wm_region(C);
+ UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
+ Paint *paint = BKE_paint_get_active_from_context(C);
+ Brush *brush = BKE_paint_brush(paint);
+ ePaintMode mode = BKE_paintmode_get_active_from_context(C);
+
+ /* check that brush drawing is enabled */
+ if (ommit_cursor_drawing(paint, mode, brush))
+ return;
+
+ /* can't use stroke vc here because this will be called during
+ * mouse over too, not just during a stroke */
+ ViewContext vc;
+ ED_view3d_viewcontext_init(C, &vc);
+
+ if (vc.rv3d && (vc.rv3d->rflag & RV3D_NAVIGATING)) {
+ return;
+ }
+
+ /* skip everything and draw brush here */
+ if (brush->flag & BRUSH_CURVE) {
+ paint_draw_curve_cursor(brush, &vc);
+ return;
+ }
+
+ float zoomx, zoomy;
+ get_imapaint_zoom(C, &zoomx, &zoomy);
+ zoomx = max_ff(zoomx, zoomy);
+
+ /* set various defaults */
+ const float *outline_col = brush->add_col;
+ const float outline_alpha = 0.5f;
+ float translation[2] = {x, y};
+ float final_radius = (BKE_brush_size_get(scene, brush) * zoomx);
+
+ /* don't calculate rake angles while a stroke is active because the rake variables are global
+ * and we may get interference with the stroke itself.
+ * For line strokes, such interference is visible */
+ if (!ups->stroke_active) {
+ paint_calculate_rake_rotation(ups, brush, translation);
+ }
+
+ /* draw overlay */
+ paint_draw_alpha_overlay(ups, brush, &vc, x, y, zoomx, mode);
+
+ /* TODO: as sculpt and other paint modes are unified, this
+ * special mode of drawing will go away */
+ if ((mode == PAINT_MODE_SCULPT) && vc.obact->sculpt) {
+ float location[3];
+ int pixel_radius;
+
+ /* test if brush is over the mesh */
+ bool hit = sculpt_get_brush_geometry(C, &vc, x, y, &pixel_radius, location, ups);
+
+ if (BKE_brush_use_locked_size(scene, brush))
+ BKE_brush_size_set(scene, brush, pixel_radius);
+
+ /* check if brush is subtracting, use different color then */
+ /* TODO: no way currently to know state of pen flip or
+ * invert key modifier without starting a stroke */
+ if (((ups->draw_inverted == 0) ^ ((brush->flag & BRUSH_DIR_IN) == 0)) &&
+ BKE_brush_sculpt_has_secondary_color(brush)) {
+ outline_col = brush->sub_col;
+ }
+
+ /* only do if brush is over the mesh */
+ if (hit)
+ paint_cursor_on_hit(ups, brush, &vc, location);
+ }
+
+ if (ups->draw_anchored) {
+ final_radius = ups->anchored_size;
+ copy_v2_fl2(translation,
+ ups->anchored_initial_mouse[0] + ar->winrct.xmin,
+ ups->anchored_initial_mouse[1] + ar->winrct.ymin);
+ }
+
+ /* make lines pretty */
+ GPU_line_width(1.0f);
+ GPU_blend(true); /* TODO: also set blend mode? */
+ GPU_line_smooth(true);
+
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
+ /* set brush color */
+ immUniformColor3fvAlpha(outline_col, outline_alpha);
+
+ /* draw brush outline */
+ if (ups->stroke_active && BKE_brush_use_size_pressure(scene, brush)) {
+ /* inner at full alpha */
+ imm_draw_circle_wire_2d(
+ pos, translation[0], translation[1], final_radius * ups->size_pressure_value, 40);
+ /* outer at half alpha */
+ immUniformColor3fvAlpha(outline_col, outline_alpha * 0.5f);
+ }
+ imm_draw_circle_wire_2d(pos, translation[0], translation[1], final_radius, 40);
+
+ immUnbindProgram();
+
+ /* restore GL state */
+ GPU_blend(false);
+ GPU_line_smooth(false);
}
/* Public API */
void paint_cursor_start(bContext *C, bool (*poll)(bContext *C))
{
- Paint *p = BKE_paint_get_active_from_context(C);
-
- if (p && !p->paint_cursor) {
- p->paint_cursor = WM_paint_cursor_activate(
- CTX_wm_manager(C),
- SPACE_TYPE_ANY, RGN_TYPE_ANY,
- poll,
- paint_draw_cursor,
- NULL);
- }
-
- /* invalidate the paint cursors */
- BKE_paint_invalidate_overlay_all();
+ Paint *p = BKE_paint_get_active_from_context(C);
+
+ if (p && !p->paint_cursor) {
+ p->paint_cursor = WM_paint_cursor_activate(
+ CTX_wm_manager(C), SPACE_TYPE_ANY, RGN_TYPE_ANY, poll, paint_draw_cursor, NULL);
+ }
+
+ /* invalidate the paint cursors */
+ BKE_paint_invalidate_overlay_all();
}
void paint_cursor_start_explicit(Paint *p, wmWindowManager *wm, bool (*poll)(bContext *C))
{
- if (p && !p->paint_cursor) {
- p->paint_cursor = WM_paint_cursor_activate(
- wm,
- SPACE_TYPE_ANY, RGN_TYPE_ANY,
- poll,
- paint_draw_cursor,
- NULL);
- }
+ if (p && !p->paint_cursor) {
+ p->paint_cursor = WM_paint_cursor_activate(
+ wm, SPACE_TYPE_ANY, RGN_TYPE_ANY, poll, paint_draw_cursor, NULL);
+ }
}
diff --git a/source/blender/editors/sculpt_paint/paint_curve.c b/source/blender/editors/sculpt_paint/paint_curve.c
index 6e43c0ab492..bc6e019142a 100644
--- a/source/blender/editors/sculpt_paint/paint_curve.c
+++ b/source/blender/editors/sculpt_paint/paint_curve.c
@@ -55,26 +55,26 @@
bool paint_curve_poll(bContext *C)
{
- Object *ob = CTX_data_active_object(C);
- Paint *p;
- RegionView3D *rv3d = CTX_wm_region_view3d(C);
- SpaceImage *sima;
+ Object *ob = CTX_data_active_object(C);
+ Paint *p;
+ RegionView3D *rv3d = CTX_wm_region_view3d(C);
+ SpaceImage *sima;
- if (rv3d && !(ob && ((ob->mode & OB_MODE_ALL_PAINT) != 0)))
- return false;
+ if (rv3d && !(ob && ((ob->mode & OB_MODE_ALL_PAINT) != 0)))
+ return false;
- sima = CTX_wm_space_image(C);
+ sima = CTX_wm_space_image(C);
- if (sima && sima->mode != SI_MODE_PAINT)
- return false;
+ if (sima && sima->mode != SI_MODE_PAINT)
+ return false;
- p = BKE_paint_get_active_from_context(C);
+ p = BKE_paint_get_active_from_context(C);
- if (p && p->brush && (p->brush->flag & BRUSH_CURVE)) {
- return true;
- }
+ if (p && p->brush && (p->brush->flag & BRUSH_CURVE)) {
+ return true;
+ }
- return false;
+ return false;
}
#define SEL_F1 (1 << 0)
@@ -82,655 +82,670 @@ bool paint_curve_poll(bContext *C)
#define SEL_F3 (1 << 2)
/* returns 0, 1, or 2 in point according to handle 1, pivot or handle 2 */
-static PaintCurvePoint *paintcurve_point_get_closest(PaintCurve *pc, const float pos[2], bool ignore_pivot, const float threshold, char *point)
+static PaintCurvePoint *paintcurve_point_get_closest(
+ PaintCurve *pc, const float pos[2], bool ignore_pivot, const float threshold, char *point)
{
- PaintCurvePoint *pcp, *closest = NULL;
- int i;
- float dist, closest_dist = FLT_MAX;
-
- for (i = 0, pcp = pc->points; i < pc->tot_points; i++, pcp++) {
- dist = len_manhattan_v2v2(pos, pcp->bez.vec[0]);
- if (dist < threshold) {
- if (dist < closest_dist) {
- closest = pcp;
- closest_dist = dist;
- if (point)
- *point = SEL_F1;
- }
- }
- if (!ignore_pivot) {
- dist = len_manhattan_v2v2(pos, pcp->bez.vec[1]);
- if (dist < threshold) {
- if (dist < closest_dist) {
- closest = pcp;
- closest_dist = dist;
- if (point)
- *point = SEL_F2;
- }
- }
- }
- dist = len_manhattan_v2v2(pos, pcp->bez.vec[2]);
- if (dist < threshold) {
- if (dist < closest_dist) {
- closest = pcp;
- closest_dist = dist;
- if (point)
- *point = SEL_F3;
- }
- }
- }
-
- return closest;
+ PaintCurvePoint *pcp, *closest = NULL;
+ int i;
+ float dist, closest_dist = FLT_MAX;
+
+ for (i = 0, pcp = pc->points; i < pc->tot_points; i++, pcp++) {
+ dist = len_manhattan_v2v2(pos, pcp->bez.vec[0]);
+ if (dist < threshold) {
+ if (dist < closest_dist) {
+ closest = pcp;
+ closest_dist = dist;
+ if (point)
+ *point = SEL_F1;
+ }
+ }
+ if (!ignore_pivot) {
+ dist = len_manhattan_v2v2(pos, pcp->bez.vec[1]);
+ if (dist < threshold) {
+ if (dist < closest_dist) {
+ closest = pcp;
+ closest_dist = dist;
+ if (point)
+ *point = SEL_F2;
+ }
+ }
+ }
+ dist = len_manhattan_v2v2(pos, pcp->bez.vec[2]);
+ if (dist < threshold) {
+ if (dist < closest_dist) {
+ closest = pcp;
+ closest_dist = dist;
+ if (point)
+ *point = SEL_F3;
+ }
+ }
+ }
+
+ return closest;
}
static int paintcurve_point_co_index(char sel)
{
- char i = 0;
- while (sel != 1) {
- sel >>= 1;
- i++;
- }
- return i;
+ char i = 0;
+ while (sel != 1) {
+ sel >>= 1;
+ i++;
+ }
+ return i;
}
-static char paintcurve_point_side_index(const BezTriple *bezt, const bool is_first, const char fallback)
+static char paintcurve_point_side_index(const BezTriple *bezt,
+ const bool is_first,
+ const char fallback)
{
- /* when matching, guess based on endpoint side */
- if (BEZT_ISSEL_ANY(bezt)) {
- if ((bezt->f1 & SELECT) == (bezt->f3 & SELECT)) {
- return is_first ? SEL_F1 : SEL_F3;
- }
- else if (bezt->f1 & SELECT) {
- return SEL_F1;
- }
- else if (bezt->f3 & SELECT) {
- return SEL_F3;
- }
- else {
- return fallback;
- }
- }
- else {
- return 0;
- }
+ /* when matching, guess based on endpoint side */
+ if (BEZT_ISSEL_ANY(bezt)) {
+ if ((bezt->f1 & SELECT) == (bezt->f3 & SELECT)) {
+ return is_first ? SEL_F1 : SEL_F3;
+ }
+ else if (bezt->f1 & SELECT) {
+ return SEL_F1;
+ }
+ else if (bezt->f3 & SELECT) {
+ return SEL_F3;
+ }
+ else {
+ return fallback;
+ }
+ }
+ else {
+ return 0;
+ }
}
/******************* Operators *********************************/
static int paintcurve_new_exec(bContext *C, wmOperator *UNUSED(op))
{
- Paint *p = BKE_paint_get_active_from_context(C);
- Main *bmain = CTX_data_main(C);
+ Paint *p = BKE_paint_get_active_from_context(C);
+ Main *bmain = CTX_data_main(C);
- if (p && p->brush) {
- p->brush->paint_curve = BKE_paint_curve_add(bmain, "PaintCurve");
- }
+ if (p && p->brush) {
+ p->brush->paint_curve = BKE_paint_curve_add(bmain, "PaintCurve");
+ }
- WM_event_add_notifier(C, NC_PAINTCURVE | NA_ADDED, NULL);
+ WM_event_add_notifier(C, NC_PAINTCURVE | NA_ADDED, NULL);
- return OPERATOR_FINISHED;
+ return OPERATOR_FINISHED;
}
void PAINTCURVE_OT_new(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Add New Paint Curve";
- ot->description = "Add new paint curve";
- ot->idname = "PAINTCURVE_OT_new";
+ /* identifiers */
+ ot->name = "Add New Paint Curve";
+ ot->description = "Add new paint curve";
+ ot->idname = "PAINTCURVE_OT_new";
- /* api callbacks */
- ot->exec = paintcurve_new_exec;
- ot->poll = paint_curve_poll;
+ /* api callbacks */
+ ot->exec = paintcurve_new_exec;
+ ot->poll = paint_curve_poll;
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-static void paintcurve_point_add(bContext *C, wmOperator *op, const int loc[2])
+static void paintcurve_point_add(bContext *C, wmOperator *op, const int loc[2])
{
- Paint *p = BKE_paint_get_active_from_context(C);
- Brush *br = p->brush;
- Main *bmain = CTX_data_main(C);
- PaintCurve *pc;
- PaintCurvePoint *pcp;
- wmWindow *window = CTX_wm_window(C);
- ARegion *ar = CTX_wm_region(C);
- float vec[3] = {loc[0], loc[1], 0.0};
- int add_index;
- int i;
-
- pc = br->paint_curve;
- if (!pc) {
- br->paint_curve = pc = BKE_paint_curve_add(bmain, "PaintCurve");
- }
-
- ED_paintcurve_undo_push_begin(op->type->name);
-
- pcp = MEM_mallocN((pc->tot_points + 1) * sizeof(PaintCurvePoint), "PaintCurvePoint");
- add_index = pc->add_index;
-
- if (pc->points) {
- if (add_index > 0)
- memcpy(pcp, pc->points, add_index * sizeof(PaintCurvePoint));
- if (add_index < pc->tot_points)
- memcpy(pcp + add_index + 1, pc->points + add_index, (pc->tot_points - add_index) * sizeof(PaintCurvePoint));
-
- MEM_freeN(pc->points);
- }
- pc->points = pcp;
- pc->tot_points++;
-
- /* initialize new point */
- memset(&pcp[add_index], 0, sizeof(PaintCurvePoint));
- copy_v3_v3(pcp[add_index].bez.vec[0], vec);
- copy_v3_v3(pcp[add_index].bez.vec[1], vec);
- copy_v3_v3(pcp[add_index].bez.vec[2], vec);
-
- /* last step, clear selection from all bezier handles expect the next */
- for (i = 0; i < pc->tot_points; i++) {
- pcp[i].bez.f1 = pcp[i].bez.f2 = pcp[i].bez.f3 = 0;
- }
-
- BKE_paint_curve_clamp_endpoint_add_index(pc, add_index);
-
- if (pc->add_index != 0) {
- pcp[add_index].bez.f3 = SELECT;
- pcp[add_index].bez.h2 = HD_ALIGN;
- }
- else {
- pcp[add_index].bez.f1 = SELECT;
- pcp[add_index].bez.h1 = HD_ALIGN;
- }
-
- ED_paintcurve_undo_push_end();
-
- WM_paint_cursor_tag_redraw(window, ar);
+ Paint *p = BKE_paint_get_active_from_context(C);
+ Brush *br = p->brush;
+ Main *bmain = CTX_data_main(C);
+ PaintCurve *pc;
+ PaintCurvePoint *pcp;
+ wmWindow *window = CTX_wm_window(C);
+ ARegion *ar = CTX_wm_region(C);
+ float vec[3] = {loc[0], loc[1], 0.0};
+ int add_index;
+ int i;
+
+ pc = br->paint_curve;
+ if (!pc) {
+ br->paint_curve = pc = BKE_paint_curve_add(bmain, "PaintCurve");
+ }
+
+ ED_paintcurve_undo_push_begin(op->type->name);
+
+ pcp = MEM_mallocN((pc->tot_points + 1) * sizeof(PaintCurvePoint), "PaintCurvePoint");
+ add_index = pc->add_index;
+
+ if (pc->points) {
+ if (add_index > 0)
+ memcpy(pcp, pc->points, add_index * sizeof(PaintCurvePoint));
+ if (add_index < pc->tot_points)
+ memcpy(pcp + add_index + 1,
+ pc->points + add_index,
+ (pc->tot_points - add_index) * sizeof(PaintCurvePoint));
+
+ MEM_freeN(pc->points);
+ }
+ pc->points = pcp;
+ pc->tot_points++;
+
+ /* initialize new point */
+ memset(&pcp[add_index], 0, sizeof(PaintCurvePoint));
+ copy_v3_v3(pcp[add_index].bez.vec[0], vec);
+ copy_v3_v3(pcp[add_index].bez.vec[1], vec);
+ copy_v3_v3(pcp[add_index].bez.vec[2], vec);
+
+ /* last step, clear selection from all bezier handles expect the next */
+ for (i = 0; i < pc->tot_points; i++) {
+ pcp[i].bez.f1 = pcp[i].bez.f2 = pcp[i].bez.f3 = 0;
+ }
+
+ BKE_paint_curve_clamp_endpoint_add_index(pc, add_index);
+
+ if (pc->add_index != 0) {
+ pcp[add_index].bez.f3 = SELECT;
+ pcp[add_index].bez.h2 = HD_ALIGN;
+ }
+ else {
+ pcp[add_index].bez.f1 = SELECT;
+ pcp[add_index].bez.h1 = HD_ALIGN;
+ }
+
+ ED_paintcurve_undo_push_end();
+
+ WM_paint_cursor_tag_redraw(window, ar);
}
-
static int paintcurve_add_point_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
- int loc[2] = {event->mval[0], event->mval[1]};
- paintcurve_point_add(C, op, loc);
- RNA_int_set_array(op->ptr, "location", loc);
- return OPERATOR_FINISHED;
+ int loc[2] = {event->mval[0], event->mval[1]};
+ paintcurve_point_add(C, op, loc);
+ RNA_int_set_array(op->ptr, "location", loc);
+ return OPERATOR_FINISHED;
}
static int paintcurve_add_point_exec(bContext *C, wmOperator *op)
{
- int loc[2];
+ int loc[2];
- if (RNA_struct_property_is_set(op->ptr, "location")) {
- RNA_int_get_array(op->ptr, "location", loc);
- paintcurve_point_add(C, op, loc);
- return OPERATOR_FINISHED;
- }
+ if (RNA_struct_property_is_set(op->ptr, "location")) {
+ RNA_int_get_array(op->ptr, "location", loc);
+ paintcurve_point_add(C, op, loc);
+ return OPERATOR_FINISHED;
+ }
- return OPERATOR_CANCELLED;
+ return OPERATOR_CANCELLED;
}
void PAINTCURVE_OT_add_point(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Add New Paint Curve Point";
- ot->description = ot->name;
- ot->idname = "PAINTCURVE_OT_add_point";
-
- /* api callbacks */
- ot->invoke = paintcurve_add_point_invoke;
- ot->exec = paintcurve_add_point_exec;
- ot->poll = paint_curve_poll;
-
- /* flags */
- ot->flag = OPTYPE_UNDO | OPTYPE_REGISTER;
-
- /* properties */
- RNA_def_int_vector(ot->srna, "location", 2, NULL, 0, SHRT_MAX,
- "Location", "Location of vertex in area space", 0, SHRT_MAX);
+ /* identifiers */
+ ot->name = "Add New Paint Curve Point";
+ ot->description = ot->name;
+ ot->idname = "PAINTCURVE_OT_add_point";
+
+ /* api callbacks */
+ ot->invoke = paintcurve_add_point_invoke;
+ ot->exec = paintcurve_add_point_exec;
+ ot->poll = paint_curve_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_UNDO | OPTYPE_REGISTER;
+
+ /* properties */
+ RNA_def_int_vector(ot->srna,
+ "location",
+ 2,
+ NULL,
+ 0,
+ SHRT_MAX,
+ "Location",
+ "Location of vertex in area space",
+ 0,
+ SHRT_MAX);
}
static int paintcurve_delete_point_exec(bContext *C, wmOperator *op)
{
- Paint *p = BKE_paint_get_active_from_context(C);
- Brush *br = p->brush;
- PaintCurve *pc;
- PaintCurvePoint *pcp;
- wmWindow *window = CTX_wm_window(C);
- ARegion *ar = CTX_wm_region(C);
- int i;
- int tot_del = 0;
- pc = br->paint_curve;
-
- if (!pc || pc->tot_points == 0) {
- return OPERATOR_CANCELLED;
- }
-
- ED_paintcurve_undo_push_begin(op->type->name);
+ Paint *p = BKE_paint_get_active_from_context(C);
+ Brush *br = p->brush;
+ PaintCurve *pc;
+ PaintCurvePoint *pcp;
+ wmWindow *window = CTX_wm_window(C);
+ ARegion *ar = CTX_wm_region(C);
+ int i;
+ int tot_del = 0;
+ pc = br->paint_curve;
+
+ if (!pc || pc->tot_points == 0) {
+ return OPERATOR_CANCELLED;
+ }
+
+ ED_paintcurve_undo_push_begin(op->type->name);
#define DELETE_TAG 2
- for (i = 0, pcp = pc->points; i < pc->tot_points; i++, pcp++) {
- if (BEZT_ISSEL_ANY(&pcp->bez)) {
- pcp->bez.f2 |= DELETE_TAG;
- tot_del++;
- }
- }
-
- if (tot_del > 0) {
- int j = 0;
- int new_tot = pc->tot_points - tot_del;
- PaintCurvePoint *points_new = NULL;
- if (new_tot > 0)
- points_new = MEM_mallocN(new_tot * sizeof(PaintCurvePoint), "PaintCurvePoint");
-
- for (i = 0, pcp = pc->points; i < pc->tot_points; i++, pcp++) {
- if (!(pcp->bez.f2 & DELETE_TAG)) {
- points_new[j] = pc->points[i];
-
- if ((i + 1) == pc->add_index) {
- BKE_paint_curve_clamp_endpoint_add_index(pc, j);
- }
- j++;
- }
- else if ((i + 1) == pc->add_index) {
- /* prefer previous point */
- pc->add_index = j;
- }
- }
- MEM_freeN(pc->points);
-
- pc->points = points_new;
- pc->tot_points = new_tot;
- }
+ for (i = 0, pcp = pc->points; i < pc->tot_points; i++, pcp++) {
+ if (BEZT_ISSEL_ANY(&pcp->bez)) {
+ pcp->bez.f2 |= DELETE_TAG;
+ tot_del++;
+ }
+ }
+
+ if (tot_del > 0) {
+ int j = 0;
+ int new_tot = pc->tot_points - tot_del;
+ PaintCurvePoint *points_new = NULL;
+ if (new_tot > 0)
+ points_new = MEM_mallocN(new_tot * sizeof(PaintCurvePoint), "PaintCurvePoint");
+
+ for (i = 0, pcp = pc->points; i < pc->tot_points; i++, pcp++) {
+ if (!(pcp->bez.f2 & DELETE_TAG)) {
+ points_new[j] = pc->points[i];
+
+ if ((i + 1) == pc->add_index) {
+ BKE_paint_curve_clamp_endpoint_add_index(pc, j);
+ }
+ j++;
+ }
+ else if ((i + 1) == pc->add_index) {
+ /* prefer previous point */
+ pc->add_index = j;
+ }
+ }
+ MEM_freeN(pc->points);
+
+ pc->points = points_new;
+ pc->tot_points = new_tot;
+ }
#undef DELETE_TAG
- ED_paintcurve_undo_push_end();
+ ED_paintcurve_undo_push_end();
- WM_paint_cursor_tag_redraw(window, ar);
+ WM_paint_cursor_tag_redraw(window, ar);
- return OPERATOR_FINISHED;
+ return OPERATOR_FINISHED;
}
-
void PAINTCURVE_OT_delete_point(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Remove Paint Curve Point";
- ot->description = ot->name;
- ot->idname = "PAINTCURVE_OT_delete_point";
+ /* identifiers */
+ ot->name = "Remove Paint Curve Point";
+ ot->description = ot->name;
+ ot->idname = "PAINTCURVE_OT_delete_point";
- /* api callbacks */
- ot->exec = paintcurve_delete_point_exec;
- ot->poll = paint_curve_poll;
+ /* api callbacks */
+ ot->exec = paintcurve_delete_point_exec;
+ ot->poll = paint_curve_poll;
- /* flags */
- ot->flag = OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_UNDO;
}
-
-static bool paintcurve_point_select(bContext *C, wmOperator *op, const int loc[2], bool toggle, bool extend)
+static bool paintcurve_point_select(
+ bContext *C, wmOperator *op, const int loc[2], bool toggle, bool extend)
{
- wmWindow *window = CTX_wm_window(C);
- ARegion *ar = CTX_wm_region(C);
- Paint *p = BKE_paint_get_active_from_context(C);
- Brush *br = p->brush;
- PaintCurve *pc;
- int i;
- const float loc_fl[2] = {UNPACK2(loc)};
-
- pc = br->paint_curve;
-
- if (!pc)
- return false;
-
- ED_paintcurve_undo_push_begin(op->type->name);
-
- if (toggle) {
- PaintCurvePoint *pcp;
- char select = 0;
- bool selected = false;
-
- pcp = pc->points;
-
- for (i = 0; i < pc->tot_points; i++) {
- if (pcp[i].bez.f1 || pcp[i].bez.f2 || pcp[i].bez.f3) {
- selected = true;
- break;
- }
- }
-
- if (!selected) {
- select = SELECT;
- }
-
- for (i = 0; i < pc->tot_points; i++) {
- pc->points[i].bez.f1 = pc->points[i].bez.f2 = pc->points[i].bez.f3 = select;
- }
- }
- else {
- PaintCurvePoint *pcp;
- char selflag;
-
- pcp = paintcurve_point_get_closest(pc, loc_fl, false, PAINT_CURVE_SELECT_THRESHOLD, &selflag);
-
- if (pcp) {
- BKE_paint_curve_clamp_endpoint_add_index(pc, pcp - pc->points);
-
- if (selflag == SEL_F2) {
- if (extend)
- pcp->bez.f2 ^= SELECT;
- else
- pcp->bez.f2 |= SELECT;
- }
- else if (selflag == SEL_F1) {
- if (extend)
- pcp->bez.f1 ^= SELECT;
- else
- pcp->bez.f1 |= SELECT;
- }
- else if (selflag == SEL_F3) {
- if (extend)
- pcp->bez.f3 ^= SELECT;
- else
- pcp->bez.f3 |= SELECT;
- }
- }
-
- /* clear selection for unselected points if not extending and if a point has been selected */
- if (!extend && pcp) {
- for (i = 0; i < pc->tot_points; i++) {
- pc->points[i].bez.f1 = pc->points[i].bez.f2 = pc->points[i].bez.f3 = 0;
-
- if ((pc->points + i) == pcp) {
- char index = paintcurve_point_co_index(selflag);
- PAINT_CURVE_POINT_SELECT(pcp, index);
- }
- }
- }
-
- if (!pcp) {
- ED_paintcurve_undo_push_end();
- return false;
- }
- }
-
- ED_paintcurve_undo_push_end();
-
- WM_paint_cursor_tag_redraw(window, ar);
-
- return true;
+ wmWindow *window = CTX_wm_window(C);
+ ARegion *ar = CTX_wm_region(C);
+ Paint *p = BKE_paint_get_active_from_context(C);
+ Brush *br = p->brush;
+ PaintCurve *pc;
+ int i;
+ const float loc_fl[2] = {UNPACK2(loc)};
+
+ pc = br->paint_curve;
+
+ if (!pc)
+ return false;
+
+ ED_paintcurve_undo_push_begin(op->type->name);
+
+ if (toggle) {
+ PaintCurvePoint *pcp;
+ char select = 0;
+ bool selected = false;
+
+ pcp = pc->points;
+
+ for (i = 0; i < pc->tot_points; i++) {
+ if (pcp[i].bez.f1 || pcp[i].bez.f2 || pcp[i].bez.f3) {
+ selected = true;
+ break;
+ }
+ }
+
+ if (!selected) {
+ select = SELECT;
+ }
+
+ for (i = 0; i < pc->tot_points; i++) {
+ pc->points[i].bez.f1 = pc->points[i].bez.f2 = pc->points[i].bez.f3 = select;
+ }
+ }
+ else {
+ PaintCurvePoint *pcp;
+ char selflag;
+
+ pcp = paintcurve_point_get_closest(pc, loc_fl, false, PAINT_CURVE_SELECT_THRESHOLD, &selflag);
+
+ if (pcp) {
+ BKE_paint_curve_clamp_endpoint_add_index(pc, pcp - pc->points);
+
+ if (selflag == SEL_F2) {
+ if (extend)
+ pcp->bez.f2 ^= SELECT;
+ else
+ pcp->bez.f2 |= SELECT;
+ }
+ else if (selflag == SEL_F1) {
+ if (extend)
+ pcp->bez.f1 ^= SELECT;
+ else
+ pcp->bez.f1 |= SELECT;
+ }
+ else if (selflag == SEL_F3) {
+ if (extend)
+ pcp->bez.f3 ^= SELECT;
+ else
+ pcp->bez.f3 |= SELECT;
+ }
+ }
+
+ /* clear selection for unselected points if not extending and if a point has been selected */
+ if (!extend && pcp) {
+ for (i = 0; i < pc->tot_points; i++) {
+ pc->points[i].bez.f1 = pc->points[i].bez.f2 = pc->points[i].bez.f3 = 0;
+
+ if ((pc->points + i) == pcp) {
+ char index = paintcurve_point_co_index(selflag);
+ PAINT_CURVE_POINT_SELECT(pcp, index);
+ }
+ }
+ }
+
+ if (!pcp) {
+ ED_paintcurve_undo_push_end();
+ return false;
+ }
+ }
+
+ ED_paintcurve_undo_push_end();
+
+ WM_paint_cursor_tag_redraw(window, ar);
+
+ return true;
}
-
static int paintcurve_select_point_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
- int loc[2] = {UNPACK2(event->mval)};
- bool toggle = RNA_boolean_get(op->ptr, "toggle");
- bool extend = RNA_boolean_get(op->ptr, "extend");
- if (paintcurve_point_select(C, op, loc, toggle, extend)) {
- RNA_int_set_array(op->ptr, "location", loc);
- return OPERATOR_FINISHED;
- }
- else {
- return OPERATOR_CANCELLED;
- }
+ int loc[2] = {UNPACK2(event->mval)};
+ bool toggle = RNA_boolean_get(op->ptr, "toggle");
+ bool extend = RNA_boolean_get(op->ptr, "extend");
+ if (paintcurve_point_select(C, op, loc, toggle, extend)) {
+ RNA_int_set_array(op->ptr, "location", loc);
+ return OPERATOR_FINISHED;
+ }
+ else {
+ return OPERATOR_CANCELLED;
+ }
}
static int paintcurve_select_point_exec(bContext *C, wmOperator *op)
{
- int loc[2];
+ int loc[2];
- if (RNA_struct_property_is_set(op->ptr, "location")) {
- bool toggle = RNA_boolean_get(op->ptr, "toggle");
- bool extend = RNA_boolean_get(op->ptr, "extend");
- RNA_int_get_array(op->ptr, "location", loc);
- if (paintcurve_point_select(C, op, loc, toggle, extend))
- return OPERATOR_FINISHED;
- }
+ if (RNA_struct_property_is_set(op->ptr, "location")) {
+ bool toggle = RNA_boolean_get(op->ptr, "toggle");
+ bool extend = RNA_boolean_get(op->ptr, "extend");
+ RNA_int_get_array(op->ptr, "location", loc);
+ if (paintcurve_point_select(C, op, loc, toggle, extend))
+ return OPERATOR_FINISHED;
+ }
- return OPERATOR_CANCELLED;
+ return OPERATOR_CANCELLED;
}
void PAINTCURVE_OT_select(wmOperatorType *ot)
{
- PropertyRNA *prop;
-
- /* identifiers */
- ot->name = "Select Paint Curve Point";
- ot->description = "Select a paint curve point";
- ot->idname = "PAINTCURVE_OT_select";
-
- /* api callbacks */
- ot->invoke = paintcurve_select_point_invoke;
- ot->exec = paintcurve_select_point_exec;
- ot->poll = paint_curve_poll;
-
- /* flags */
- ot->flag = OPTYPE_UNDO | OPTYPE_REGISTER;
-
- /* properties */
- RNA_def_int_vector(ot->srna, "location", 2, NULL, 0, SHRT_MAX,
- "Location", "Location of vertex in area space", 0, SHRT_MAX);
- prop = RNA_def_boolean(ot->srna, "toggle", false, "Toggle", "(De)select all");
- RNA_def_property_flag(prop, PROP_SKIP_SAVE);
- prop = RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend selection");
- RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+ PropertyRNA *prop;
+
+ /* identifiers */
+ ot->name = "Select Paint Curve Point";
+ ot->description = "Select a paint curve point";
+ ot->idname = "PAINTCURVE_OT_select";
+
+ /* api callbacks */
+ ot->invoke = paintcurve_select_point_invoke;
+ ot->exec = paintcurve_select_point_exec;
+ ot->poll = paint_curve_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_UNDO | OPTYPE_REGISTER;
+
+ /* properties */
+ RNA_def_int_vector(ot->srna,
+ "location",
+ 2,
+ NULL,
+ 0,
+ SHRT_MAX,
+ "Location",
+ "Location of vertex in area space",
+ 0,
+ SHRT_MAX);
+ prop = RNA_def_boolean(ot->srna, "toggle", false, "Toggle", "(De)select all");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+ prop = RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend selection");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
typedef struct PointSlideData {
- PaintCurvePoint *pcp;
- char select;
- int initial_loc[2];
- float point_initial_loc[3][2];
- int event;
- bool align;
+ PaintCurvePoint *pcp;
+ char select;
+ int initial_loc[2];
+ float point_initial_loc[3][2];
+ int event;
+ bool align;
} PointSlideData;
static int paintcurve_slide_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
- Paint *p = BKE_paint_get_active_from_context(C);
- const float loc_fl[2] = {UNPACK2(event->mval)};
- char select;
- int i;
- bool do_select = RNA_boolean_get(op->ptr, "select");
- bool align = RNA_boolean_get(op->ptr, "align");
- Brush *br = p->brush;
- PaintCurve *pc = br->paint_curve;
- PaintCurvePoint *pcp;
-
- if (!pc)
- return OPERATOR_PASS_THROUGH;
-
- if (do_select) {
- pcp = paintcurve_point_get_closest(pc, loc_fl, align, PAINT_CURVE_SELECT_THRESHOLD, &select);
- }
- else {
- pcp = NULL;
- /* just find first selected point */
- for (i = 0; i < pc->tot_points; i++) {
- if ((select = paintcurve_point_side_index(&pc->points[i].bez, i == 0, SEL_F3))) {
- pcp = &pc->points[i];
- break;
- }
- }
- }
-
-
- if (pcp) {
- ARegion *ar = CTX_wm_region(C);
- wmWindow *window = CTX_wm_window(C);
- PointSlideData *psd = MEM_mallocN(sizeof(PointSlideData), "PointSlideData");
- copy_v2_v2_int(psd->initial_loc, event->mval);
- psd->event = event->type;
- psd->pcp = pcp;
- psd->select = paintcurve_point_co_index(select);
- for (i = 0; i < 3; i++) {
- copy_v2_v2(psd->point_initial_loc[i], pcp->bez.vec[i]);
- }
- psd->align = align;
- op->customdata = psd;
-
- /* first, clear all selection from points */
- for (i = 0; i < pc->tot_points; i++)
- pc->points[i].bez.f1 = pc->points[i].bez.f3 = pc->points[i].bez.f2 = 0;
-
- /* only select the active point */
- PAINT_CURVE_POINT_SELECT(pcp, psd->select);
- BKE_paint_curve_clamp_endpoint_add_index(pc, pcp - pc->points);
-
- WM_event_add_modal_handler(C, op);
- WM_paint_cursor_tag_redraw(window, ar);
- return OPERATOR_RUNNING_MODAL;
- }
-
- return OPERATOR_PASS_THROUGH;
+ Paint *p = BKE_paint_get_active_from_context(C);
+ const float loc_fl[2] = {UNPACK2(event->mval)};
+ char select;
+ int i;
+ bool do_select = RNA_boolean_get(op->ptr, "select");
+ bool align = RNA_boolean_get(op->ptr, "align");
+ Brush *br = p->brush;
+ PaintCurve *pc = br->paint_curve;
+ PaintCurvePoint *pcp;
+
+ if (!pc)
+ return OPERATOR_PASS_THROUGH;
+
+ if (do_select) {
+ pcp = paintcurve_point_get_closest(pc, loc_fl, align, PAINT_CURVE_SELECT_THRESHOLD, &select);
+ }
+ else {
+ pcp = NULL;
+ /* just find first selected point */
+ for (i = 0; i < pc->tot_points; i++) {
+ if ((select = paintcurve_point_side_index(&pc->points[i].bez, i == 0, SEL_F3))) {
+ pcp = &pc->points[i];
+ break;
+ }
+ }
+ }
+
+ if (pcp) {
+ ARegion *ar = CTX_wm_region(C);
+ wmWindow *window = CTX_wm_window(C);
+ PointSlideData *psd = MEM_mallocN(sizeof(PointSlideData), "PointSlideData");
+ copy_v2_v2_int(psd->initial_loc, event->mval);
+ psd->event = event->type;
+ psd->pcp = pcp;
+ psd->select = paintcurve_point_co_index(select);
+ for (i = 0; i < 3; i++) {
+ copy_v2_v2(psd->point_initial_loc[i], pcp->bez.vec[i]);
+ }
+ psd->align = align;
+ op->customdata = psd;
+
+ /* first, clear all selection from points */
+ for (i = 0; i < pc->tot_points; i++)
+ pc->points[i].bez.f1 = pc->points[i].bez.f3 = pc->points[i].bez.f2 = 0;
+
+ /* only select the active point */
+ PAINT_CURVE_POINT_SELECT(pcp, psd->select);
+ BKE_paint_curve_clamp_endpoint_add_index(pc, pcp - pc->points);
+
+ WM_event_add_modal_handler(C, op);
+ WM_paint_cursor_tag_redraw(window, ar);
+ return OPERATOR_RUNNING_MODAL;
+ }
+
+ return OPERATOR_PASS_THROUGH;
}
static int paintcurve_slide_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
- PointSlideData *psd = op->customdata;
-
- if (event->type == psd->event && event->val == KM_RELEASE) {
- MEM_freeN(psd);
- ED_paintcurve_undo_push_begin(op->type->name);
- ED_paintcurve_undo_push_end();
- return OPERATOR_FINISHED;
- }
-
- switch (event->type) {
- case MOUSEMOVE:
- {
- ARegion *ar = CTX_wm_region(C);
- wmWindow *window = CTX_wm_window(C);
- float diff[2] = {
- event->mval[0] - psd->initial_loc[0],
- event->mval[1] - psd->initial_loc[1]};
- if (psd->select == 1) {
- int i;
- for (i = 0; i < 3; i++)
- add_v2_v2v2(psd->pcp->bez.vec[i], diff, psd->point_initial_loc[i]);
- }
- else {
- add_v2_v2(diff, psd->point_initial_loc[psd->select]);
- copy_v2_v2(psd->pcp->bez.vec[psd->select], diff);
-
- if (psd->align) {
- char opposite = (psd->select == 0) ? 2 : 0;
- sub_v2_v2v2(diff, psd->pcp->bez.vec[1], psd->pcp->bez.vec[psd->select]);
- add_v2_v2v2(psd->pcp->bez.vec[opposite], psd->pcp->bez.vec[1], diff);
- }
- }
- WM_paint_cursor_tag_redraw(window, ar);
- break;
- }
- default:
- break;
- }
-
- return OPERATOR_RUNNING_MODAL;
+ PointSlideData *psd = op->customdata;
+
+ if (event->type == psd->event && event->val == KM_RELEASE) {
+ MEM_freeN(psd);
+ ED_paintcurve_undo_push_begin(op->type->name);
+ ED_paintcurve_undo_push_end();
+ return OPERATOR_FINISHED;
+ }
+
+ switch (event->type) {
+ case MOUSEMOVE: {
+ ARegion *ar = CTX_wm_region(C);
+ wmWindow *window = CTX_wm_window(C);
+ float diff[2] = {event->mval[0] - psd->initial_loc[0], event->mval[1] - psd->initial_loc[1]};
+ if (psd->select == 1) {
+ int i;
+ for (i = 0; i < 3; i++)
+ add_v2_v2v2(psd->pcp->bez.vec[i], diff, psd->point_initial_loc[i]);
+ }
+ else {
+ add_v2_v2(diff, psd->point_initial_loc[psd->select]);
+ copy_v2_v2(psd->pcp->bez.vec[psd->select], diff);
+
+ if (psd->align) {
+ char opposite = (psd->select == 0) ? 2 : 0;
+ sub_v2_v2v2(diff, psd->pcp->bez.vec[1], psd->pcp->bez.vec[psd->select]);
+ add_v2_v2v2(psd->pcp->bez.vec[opposite], psd->pcp->bez.vec[1], diff);
+ }
+ }
+ WM_paint_cursor_tag_redraw(window, ar);
+ break;
+ }
+ default:
+ break;
+ }
+
+ return OPERATOR_RUNNING_MODAL;
}
-
void PAINTCURVE_OT_slide(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Slide Paint Curve Point";
- ot->description = "Select and slide paint curve point";
- ot->idname = "PAINTCURVE_OT_slide";
-
- /* api callbacks */
- ot->invoke = paintcurve_slide_invoke;
- ot->modal = paintcurve_slide_modal;
- ot->poll = paint_curve_poll;
-
- /* flags */
- ot->flag = OPTYPE_UNDO;
-
- /* properties */
- RNA_def_boolean(ot->srna, "align", false, "Align Handles", "Aligns opposite point handle during transform");
- RNA_def_boolean(ot->srna, "select", true, "Select", "Attempt to select a point handle before transform");
+ /* identifiers */
+ ot->name = "Slide Paint Curve Point";
+ ot->description = "Select and slide paint curve point";
+ ot->idname = "PAINTCURVE_OT_slide";
+
+ /* api callbacks */
+ ot->invoke = paintcurve_slide_invoke;
+ ot->modal = paintcurve_slide_modal;
+ ot->poll = paint_curve_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_UNDO;
+
+ /* properties */
+ RNA_def_boolean(
+ ot->srna, "align", false, "Align Handles", "Aligns opposite point handle during transform");
+ RNA_def_boolean(
+ ot->srna, "select", true, "Select", "Attempt to select a point handle before transform");
}
static int paintcurve_draw_exec(bContext *C, wmOperator *UNUSED(op))
{
- ePaintMode mode = BKE_paintmode_get_active_from_context(C);
- const char *name;
-
- switch (mode) {
- case PAINT_MODE_TEXTURE_2D:
- case PAINT_MODE_TEXTURE_3D:
- name = "PAINT_OT_image_paint";
- break;
- case PAINT_MODE_WEIGHT:
- name = "PAINT_OT_weight_paint";
- break;
- case PAINT_MODE_VERTEX:
- name = "PAINT_OT_vertex_paint";
- break;
- case PAINT_MODE_SCULPT:
- name = "SCULPT_OT_brush_stroke";
- break;
- default:
- return OPERATOR_PASS_THROUGH;
- }
-
- return WM_operator_name_call(C, name, WM_OP_INVOKE_DEFAULT, NULL);
+ ePaintMode mode = BKE_paintmode_get_active_from_context(C);
+ const char *name;
+
+ switch (mode) {
+ case PAINT_MODE_TEXTURE_2D:
+ case PAINT_MODE_TEXTURE_3D:
+ name = "PAINT_OT_image_paint";
+ break;
+ case PAINT_MODE_WEIGHT:
+ name = "PAINT_OT_weight_paint";
+ break;
+ case PAINT_MODE_VERTEX:
+ name = "PAINT_OT_vertex_paint";
+ break;
+ case PAINT_MODE_SCULPT:
+ name = "SCULPT_OT_brush_stroke";
+ break;
+ default:
+ return OPERATOR_PASS_THROUGH;
+ }
+
+ return WM_operator_name_call(C, name, WM_OP_INVOKE_DEFAULT, NULL);
}
void PAINTCURVE_OT_draw(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Draw Curve";
- ot->description = "Draw curve";
- ot->idname = "PAINTCURVE_OT_draw";
+ /* identifiers */
+ ot->name = "Draw Curve";
+ ot->description = "Draw curve";
+ ot->idname = "PAINTCURVE_OT_draw";
- /* api callbacks */
- ot->exec = paintcurve_draw_exec;
- ot->poll = paint_curve_poll;
+ /* api callbacks */
+ ot->exec = paintcurve_draw_exec;
+ ot->poll = paint_curve_poll;
- /* flags */
- ot->flag = OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_UNDO;
}
static int paintcurve_cursor_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
{
- ePaintMode mode = BKE_paintmode_get_active_from_context(C);
-
- switch (mode) {
- case PAINT_MODE_TEXTURE_2D:
- {
- ARegion *ar = CTX_wm_region(C);
- SpaceImage *sima = CTX_wm_space_image(C);
- float location[2];
-
- if (!sima)
- return OPERATOR_CANCELLED;
-
- UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &location[0], &location[1]);
- copy_v2_v2(sima->cursor, location);
- WM_event_add_notifier(C, NC_SPACE | ND_SPACE_IMAGE, NULL);
- break;
- }
- default:
- ED_view3d_cursor3d_update(C, event->mval, true, V3D_CURSOR_ORIENT_VIEW);
- break;
- }
-
- return OPERATOR_FINISHED;
+ ePaintMode mode = BKE_paintmode_get_active_from_context(C);
+
+ switch (mode) {
+ case PAINT_MODE_TEXTURE_2D: {
+ ARegion *ar = CTX_wm_region(C);
+ SpaceImage *sima = CTX_wm_space_image(C);
+ float location[2];
+
+ if (!sima)
+ return OPERATOR_CANCELLED;
+
+ UI_view2d_region_to_view(
+ &ar->v2d, event->mval[0], event->mval[1], &location[0], &location[1]);
+ copy_v2_v2(sima->cursor, location);
+ WM_event_add_notifier(C, NC_SPACE | ND_SPACE_IMAGE, NULL);
+ break;
+ }
+ default:
+ ED_view3d_cursor3d_update(C, event->mval, true, V3D_CURSOR_ORIENT_VIEW);
+ break;
+ }
+
+ return OPERATOR_FINISHED;
}
void PAINTCURVE_OT_cursor(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Place Cursor";
- ot->description = "Place cursor";
- ot->idname = "PAINTCURVE_OT_cursor";
+ /* identifiers */
+ ot->name = "Place Cursor";
+ ot->description = "Place cursor";
+ ot->idname = "PAINTCURVE_OT_cursor";
- /* api callbacks */
- ot->invoke = paintcurve_cursor_invoke;
- ot->poll = paint_curve_poll;
+ /* api callbacks */
+ ot->invoke = paintcurve_cursor_invoke;
+ ot->poll = paint_curve_poll;
- /* flags */
- ot->flag = 0;
+ /* flags */
+ ot->flag = 0;
}
diff --git a/source/blender/editors/sculpt_paint/paint_curve_undo.c b/source/blender/editors/sculpt_paint/paint_curve_undo.c
index 1eaed8eabb8..c03cb69df88 100644
--- a/source/blender/editors/sculpt_paint/paint_curve_undo.c
+++ b/source/blender/editors/sculpt_paint/paint_curve_undo.c
@@ -44,30 +44,30 @@
* \{ */
typedef struct UndoCurve {
- PaintCurvePoint *points; /* points of curve */
- int tot_points;
- int add_index;
+ PaintCurvePoint *points; /* points of curve */
+ int tot_points;
+ int add_index;
} UndoCurve;
static void undocurve_from_paintcurve(UndoCurve *uc, const PaintCurve *pc)
{
- BLI_assert(BLI_array_is_zeroed(uc, 1));
- uc->points = MEM_dupallocN(pc->points);
- uc->tot_points = pc->tot_points;
- uc->add_index = pc->add_index;
+ BLI_assert(BLI_array_is_zeroed(uc, 1));
+ uc->points = MEM_dupallocN(pc->points);
+ uc->tot_points = pc->tot_points;
+ uc->add_index = pc->add_index;
}
static void undocurve_to_paintcurve(const UndoCurve *uc, PaintCurve *pc)
{
- MEM_SAFE_FREE(pc->points);
- pc->points = MEM_dupallocN(uc->points);
- pc->tot_points = uc->tot_points;
- pc->add_index = uc->add_index;
+ MEM_SAFE_FREE(pc->points);
+ pc->points = MEM_dupallocN(uc->points);
+ pc->tot_points = uc->tot_points;
+ pc->add_index = uc->add_index;
}
static void undocurve_free_data(UndoCurve *uc)
{
- MEM_SAFE_FREE(uc->points);
+ MEM_SAFE_FREE(uc->points);
}
/** \} */
@@ -77,92 +77,96 @@ static void undocurve_free_data(UndoCurve *uc)
* \{ */
typedef struct PaintCurveUndoStep {
- UndoStep step;
- PaintCurve *pc;
- UndoCurve data;
+ UndoStep step;
+ PaintCurve *pc;
+ UndoCurve data;
} PaintCurveUndoStep;
static bool paintcurve_undosys_poll(bContext *C)
{
- if (C == NULL || !paint_curve_poll(C)) {
- return false;
- }
- Paint *p = BKE_paint_get_active_from_context(C);
- return (p->brush && p->brush->paint_curve);
+ if (C == NULL || !paint_curve_poll(C)) {
+ return false;
+ }
+ Paint *p = BKE_paint_get_active_from_context(C);
+ return (p->brush && p->brush->paint_curve);
}
static void paintcurve_undosys_step_encode_init(struct bContext *C, UndoStep *us_p)
{
- /* XXX, use to set the undo type only. */
- UNUSED_VARS(C, us_p);
+ /* XXX, use to set the undo type only. */
+ UNUSED_VARS(C, us_p);
}
-static bool paintcurve_undosys_step_encode(struct bContext *C, struct Main *UNUSED(bmain), UndoStep *us_p)
+static bool paintcurve_undosys_step_encode(struct bContext *C,
+ struct Main *UNUSED(bmain),
+ UndoStep *us_p)
{
- if (C == NULL || !paint_curve_poll(C)) {
- return false;
- }
- Paint *p = BKE_paint_get_active_from_context(C);
- PaintCurve *pc = p ? (p->brush ? p->brush->paint_curve : NULL) : NULL;
- if (pc == NULL) {
- return false;
- }
-
- PaintCurveUndoStep *us = (PaintCurveUndoStep *)us_p;
- BLI_assert(us->step.data_size == 0);
-
- us->pc = pc;
- undocurve_from_paintcurve(&us->data, pc);
-
- return true;
+ if (C == NULL || !paint_curve_poll(C)) {
+ return false;
+ }
+ Paint *p = BKE_paint_get_active_from_context(C);
+ PaintCurve *pc = p ? (p->brush ? p->brush->paint_curve : NULL) : NULL;
+ if (pc == NULL) {
+ return false;
+ }
+
+ PaintCurveUndoStep *us = (PaintCurveUndoStep *)us_p;
+ BLI_assert(us->step.data_size == 0);
+
+ us->pc = pc;
+ undocurve_from_paintcurve(&us->data, pc);
+
+ return true;
}
-static void paintcurve_undosys_step_decode(struct bContext *UNUSED(C), struct Main *UNUSED(bmain), UndoStep *us_p, int UNUSED(dir))
+static void paintcurve_undosys_step_decode(struct bContext *UNUSED(C),
+ struct Main *UNUSED(bmain),
+ UndoStep *us_p,
+ int UNUSED(dir))
{
- PaintCurveUndoStep *us = (PaintCurveUndoStep *)us_p;
- undocurve_to_paintcurve(&us->data, us->pc);
+ PaintCurveUndoStep *us = (PaintCurveUndoStep *)us_p;
+ undocurve_to_paintcurve(&us->data, us->pc);
}
static void paintcurve_undosys_step_free(UndoStep *us_p)
{
- PaintCurveUndoStep *us = (PaintCurveUndoStep *)us_p;
- undocurve_free_data(&us->data);
+ PaintCurveUndoStep *us = (PaintCurveUndoStep *)us_p;
+ undocurve_free_data(&us->data);
}
/* Export for ED_undo_sys. */
void ED_paintcurve_undosys_type(UndoType *ut)
{
- ut->name = "Paint Curve";
- /* don't poll for now */
- ut->poll = paintcurve_undosys_poll;
- ut->step_encode_init = paintcurve_undosys_step_encode_init;
- ut->step_encode = paintcurve_undosys_step_encode;
- ut->step_decode = paintcurve_undosys_step_decode;
- ut->step_free = paintcurve_undosys_step_free;
+ ut->name = "Paint Curve";
+ /* don't poll for now */
+ ut->poll = paintcurve_undosys_poll;
+ ut->step_encode_init = paintcurve_undosys_step_encode_init;
+ ut->step_encode = paintcurve_undosys_step_encode;
+ ut->step_decode = paintcurve_undosys_step_decode;
+ ut->step_free = paintcurve_undosys_step_free;
- ut->use_context = false;
+ ut->use_context = false;
- ut->step_size = sizeof(PaintCurveUndoStep);
+ ut->step_size = sizeof(PaintCurveUndoStep);
}
/** \} */
-
/* -------------------------------------------------------------------- */
/** \name Utilities
* \{ */
void ED_paintcurve_undo_push_begin(const char *name)
{
- UndoStack *ustack = ED_undo_stack_get();
- bContext *C = NULL; /* special case, we never read from this. */
- BKE_undosys_step_push_init_with_type(ustack, C, name, BKE_UNDOSYS_TYPE_PAINTCURVE);
+ UndoStack *ustack = ED_undo_stack_get();
+ bContext *C = NULL; /* special case, we never read from this. */
+ BKE_undosys_step_push_init_with_type(ustack, C, name, BKE_UNDOSYS_TYPE_PAINTCURVE);
}
void ED_paintcurve_undo_push_end(void)
{
- UndoStack *ustack = ED_undo_stack_get();
- BKE_undosys_step_push(ustack, NULL, NULL);
+ UndoStack *ustack = ED_undo_stack_get();
+ BKE_undosys_step_push(ustack, NULL, NULL);
}
/** \} */
diff --git a/source/blender/editors/sculpt_paint/paint_hide.c b/source/blender/editors/sculpt_paint/paint_hide.c
index b64c23ad0b6..c1f87f676e2 100644
--- a/source/blender/editors/sculpt_paint/paint_hide.c
+++ b/source/blender/editors/sculpt_paint/paint_hide.c
@@ -61,273 +61,241 @@
#include <assert.h>
/* return true if the element should be hidden/shown */
-static bool is_effected(
- PartialVisArea area,
- float planes[4][4],
- const float co[3],
- const float mask)
+static bool is_effected(PartialVisArea area,
+ float planes[4][4],
+ const float co[3],
+ const float mask)
{
- if (area == PARTIALVIS_ALL)
- return 1;
- else if (area == PARTIALVIS_MASKED) {
- return mask > 0.5f;
- }
- else {
- bool inside = isect_point_planes_v3(planes, 4, co);
- return ((inside && area == PARTIALVIS_INSIDE) ||
- (!inside && area == PARTIALVIS_OUTSIDE));
- }
+ if (area == PARTIALVIS_ALL)
+ return 1;
+ else if (area == PARTIALVIS_MASKED) {
+ return mask > 0.5f;
+ }
+ else {
+ bool inside = isect_point_planes_v3(planes, 4, co);
+ return ((inside && area == PARTIALVIS_INSIDE) || (!inside && area == PARTIALVIS_OUTSIDE));
+ }
}
-static void partialvis_update_mesh(
- Object *ob,
- PBVH *pbvh,
- PBVHNode *node,
- PartialVisAction action,
- PartialVisArea area,
- float planes[4][4])
+static void partialvis_update_mesh(Object *ob,
+ PBVH *pbvh,
+ PBVHNode *node,
+ PartialVisAction action,
+ PartialVisArea area,
+ float planes[4][4])
{
- Mesh *me = ob->data;
- MVert *mvert;
- const float *paint_mask;
- const int *vert_indices;
- int totvert, i;
- bool any_changed = false, any_visible = false;
-
- BKE_pbvh_node_num_verts(pbvh, node, NULL, &totvert);
- BKE_pbvh_node_get_verts(pbvh, node, &vert_indices, &mvert);
- paint_mask = CustomData_get_layer(&me->vdata, CD_PAINT_MASK);
-
- sculpt_undo_push_node(ob, node, SCULPT_UNDO_HIDDEN);
-
- for (i = 0; i < totvert; i++) {
- MVert *v = &mvert[vert_indices[i]];
- float vmask = paint_mask ? paint_mask[vert_indices[i]] : 0;
-
- /* hide vertex if in the hide volume */
- if (is_effected(area, planes, v->co, vmask)) {
- if (action == PARTIALVIS_HIDE)
- v->flag |= ME_HIDE;
- else
- v->flag &= ~ME_HIDE;
- any_changed = true;
- }
-
- if (!(v->flag & ME_HIDE))
- any_visible = true;
- }
-
- if (any_changed) {
- BKE_pbvh_node_mark_rebuild_draw(node);
- BKE_pbvh_node_fully_hidden_set(node, !any_visible);
- }
+ Mesh *me = ob->data;
+ MVert *mvert;
+ const float *paint_mask;
+ const int *vert_indices;
+ int totvert, i;
+ bool any_changed = false, any_visible = false;
+
+ BKE_pbvh_node_num_verts(pbvh, node, NULL, &totvert);
+ BKE_pbvh_node_get_verts(pbvh, node, &vert_indices, &mvert);
+ paint_mask = CustomData_get_layer(&me->vdata, CD_PAINT_MASK);
+
+ sculpt_undo_push_node(ob, node, SCULPT_UNDO_HIDDEN);
+
+ for (i = 0; i < totvert; i++) {
+ MVert *v = &mvert[vert_indices[i]];
+ float vmask = paint_mask ? paint_mask[vert_indices[i]] : 0;
+
+ /* hide vertex if in the hide volume */
+ if (is_effected(area, planes, v->co, vmask)) {
+ if (action == PARTIALVIS_HIDE)
+ v->flag |= ME_HIDE;
+ else
+ v->flag &= ~ME_HIDE;
+ any_changed = true;
+ }
+
+ if (!(v->flag & ME_HIDE))
+ any_visible = true;
+ }
+
+ if (any_changed) {
+ BKE_pbvh_node_mark_rebuild_draw(node);
+ BKE_pbvh_node_fully_hidden_set(node, !any_visible);
+ }
}
/* Hide or show elements in multires grids with a special GridFlags
* customdata layer. */
-static void partialvis_update_grids(
- Object *ob,
- PBVH *pbvh,
- PBVHNode *node,
- PartialVisAction action,
- PartialVisArea area,
- float planes[4][4])
+static void partialvis_update_grids(Object *ob,
+ PBVH *pbvh,
+ PBVHNode *node,
+ PartialVisAction action,
+ PartialVisArea area,
+ float planes[4][4])
{
- CCGElem **grids;
- CCGKey key;
- BLI_bitmap **grid_hidden;
- int *grid_indices, totgrid, i;
- bool any_changed = false, any_visible = false;
-
-
- /* get PBVH data */
- BKE_pbvh_node_get_grids(
- pbvh, node,
- &grid_indices, &totgrid, NULL, NULL,
- &grids);
- grid_hidden = BKE_pbvh_grid_hidden(pbvh);
- BKE_pbvh_get_grid_key(pbvh, &key);
-
- sculpt_undo_push_node(ob, node, SCULPT_UNDO_HIDDEN);
-
- for (i = 0; i < totgrid; i++) {
- int any_hidden = 0;
- int g = grid_indices[i], x, y;
- BLI_bitmap *gh = grid_hidden[g];
-
- if (!gh) {
- switch (action) {
- case PARTIALVIS_HIDE:
- /* create grid flags data */
- gh = grid_hidden[g] = BLI_BITMAP_NEW(
- key.grid_area,
- "partialvis_update_grids");
- break;
- case PARTIALVIS_SHOW:
- /* entire grid is visible, nothing to show */
- continue;
- }
- }
- else if (action == PARTIALVIS_SHOW && area == PARTIALVIS_ALL) {
- /* special case if we're showing all, just free the
- * grid */
- MEM_freeN(gh);
- grid_hidden[g] = NULL;
- any_changed = true;
- any_visible = true;
- continue;
- }
-
- for (y = 0; y < key.grid_size; y++) {
- for (x = 0; x < key.grid_size; x++) {
- CCGElem *elem = CCG_grid_elem(&key, grids[g], x, y);
- const float *co = CCG_elem_co(&key, elem);
- float mask = key.has_mask ? *CCG_elem_mask(&key, elem) : 0.0f;
-
- /* skip grid element if not in the effected area */
- if (is_effected(area, planes, co, mask)) {
- /* set or clear the hide flag */
- BLI_BITMAP_SET(
- gh, y * key.grid_size + x,
- action == PARTIALVIS_HIDE);
-
- any_changed = true;
- }
-
- /* keep track of whether any elements are still hidden */
- if (BLI_BITMAP_TEST(gh, y * key.grid_size + x))
- any_hidden = true;
- else
- any_visible = true;
- }
- }
-
- /* if everything in the grid is now visible, free the grid
- * flags */
- if (!any_hidden) {
- MEM_freeN(gh);
- grid_hidden[g] = NULL;
- }
- }
-
- /* mark updates if anything was hidden/shown */
- if (any_changed) {
- BKE_pbvh_node_mark_rebuild_draw(node);
- BKE_pbvh_node_fully_hidden_set(node, !any_visible);
- multires_mark_as_modified(ob, MULTIRES_HIDDEN_MODIFIED);
- }
+ CCGElem **grids;
+ CCGKey key;
+ BLI_bitmap **grid_hidden;
+ int *grid_indices, totgrid, i;
+ bool any_changed = false, any_visible = false;
+
+ /* get PBVH data */
+ BKE_pbvh_node_get_grids(pbvh, node, &grid_indices, &totgrid, NULL, NULL, &grids);
+ grid_hidden = BKE_pbvh_grid_hidden(pbvh);
+ BKE_pbvh_get_grid_key(pbvh, &key);
+
+ sculpt_undo_push_node(ob, node, SCULPT_UNDO_HIDDEN);
+
+ for (i = 0; i < totgrid; i++) {
+ int any_hidden = 0;
+ int g = grid_indices[i], x, y;
+ BLI_bitmap *gh = grid_hidden[g];
+
+ if (!gh) {
+ switch (action) {
+ case PARTIALVIS_HIDE:
+ /* create grid flags data */
+ gh = grid_hidden[g] = BLI_BITMAP_NEW(key.grid_area, "partialvis_update_grids");
+ break;
+ case PARTIALVIS_SHOW:
+ /* entire grid is visible, nothing to show */
+ continue;
+ }
+ }
+ else if (action == PARTIALVIS_SHOW && area == PARTIALVIS_ALL) {
+ /* special case if we're showing all, just free the
+ * grid */
+ MEM_freeN(gh);
+ grid_hidden[g] = NULL;
+ any_changed = true;
+ any_visible = true;
+ continue;
+ }
+
+ for (y = 0; y < key.grid_size; y++) {
+ for (x = 0; x < key.grid_size; x++) {
+ CCGElem *elem = CCG_grid_elem(&key, grids[g], x, y);
+ const float *co = CCG_elem_co(&key, elem);
+ float mask = key.has_mask ? *CCG_elem_mask(&key, elem) : 0.0f;
+
+ /* skip grid element if not in the effected area */
+ if (is_effected(area, planes, co, mask)) {
+ /* set or clear the hide flag */
+ BLI_BITMAP_SET(gh, y * key.grid_size + x, action == PARTIALVIS_HIDE);
+
+ any_changed = true;
+ }
+
+ /* keep track of whether any elements are still hidden */
+ if (BLI_BITMAP_TEST(gh, y * key.grid_size + x))
+ any_hidden = true;
+ else
+ any_visible = true;
+ }
+ }
+
+ /* if everything in the grid is now visible, free the grid
+ * flags */
+ if (!any_hidden) {
+ MEM_freeN(gh);
+ grid_hidden[g] = NULL;
+ }
+ }
+
+ /* mark updates if anything was hidden/shown */
+ if (any_changed) {
+ BKE_pbvh_node_mark_rebuild_draw(node);
+ BKE_pbvh_node_fully_hidden_set(node, !any_visible);
+ multires_mark_as_modified(ob, MULTIRES_HIDDEN_MODIFIED);
+ }
}
-static void partialvis_update_bmesh_verts(
- BMesh *bm,
- GSet *verts,
- PartialVisAction action,
- PartialVisArea area,
- float planes[4][4],
- bool *any_changed,
- bool *any_visible)
+static void partialvis_update_bmesh_verts(BMesh *bm,
+ GSet *verts,
+ PartialVisAction action,
+ PartialVisArea area,
+ float planes[4][4],
+ bool *any_changed,
+ bool *any_visible)
{
- GSetIterator gs_iter;
-
- GSET_ITER (gs_iter, verts) {
- BMVert *v = BLI_gsetIterator_getKey(&gs_iter);
- float *vmask = CustomData_bmesh_get(
- &bm->vdata, v->head.data, CD_PAINT_MASK);
-
- /* hide vertex if in the hide volume */
- if (is_effected(area, planes, v->co, *vmask)) {
- if (action == PARTIALVIS_HIDE)
- BM_elem_flag_enable(v, BM_ELEM_HIDDEN);
- else
- BM_elem_flag_disable(v, BM_ELEM_HIDDEN);
- (*any_changed) = true;
- }
-
- if (!BM_elem_flag_test(v, BM_ELEM_HIDDEN))
- (*any_visible) = true;
- }
+ GSetIterator gs_iter;
+
+ GSET_ITER (gs_iter, verts) {
+ BMVert *v = BLI_gsetIterator_getKey(&gs_iter);
+ float *vmask = CustomData_bmesh_get(&bm->vdata, v->head.data, CD_PAINT_MASK);
+
+ /* hide vertex if in the hide volume */
+ if (is_effected(area, planes, v->co, *vmask)) {
+ if (action == PARTIALVIS_HIDE)
+ BM_elem_flag_enable(v, BM_ELEM_HIDDEN);
+ else
+ BM_elem_flag_disable(v, BM_ELEM_HIDDEN);
+ (*any_changed) = true;
+ }
+
+ if (!BM_elem_flag_test(v, BM_ELEM_HIDDEN))
+ (*any_visible) = true;
+ }
}
static void partialvis_update_bmesh_faces(GSet *faces)
{
- GSetIterator gs_iter;
+ GSetIterator gs_iter;
- GSET_ITER (gs_iter, faces) {
- BMFace *f = BLI_gsetIterator_getKey(&gs_iter);
+ GSET_ITER (gs_iter, faces) {
+ BMFace *f = BLI_gsetIterator_getKey(&gs_iter);
- if (paint_is_bmesh_face_hidden(f))
- BM_elem_flag_enable(f, BM_ELEM_HIDDEN);
- else
- BM_elem_flag_disable(f, BM_ELEM_HIDDEN);
- }
+ if (paint_is_bmesh_face_hidden(f))
+ BM_elem_flag_enable(f, BM_ELEM_HIDDEN);
+ else
+ BM_elem_flag_disable(f, BM_ELEM_HIDDEN);
+ }
}
-static void partialvis_update_bmesh(
- Object *ob,
- PBVH *pbvh,
- PBVHNode *node,
- PartialVisAction action,
- PartialVisArea area,
- float planes[4][4])
+static void partialvis_update_bmesh(Object *ob,
+ PBVH *pbvh,
+ PBVHNode *node,
+ PartialVisAction action,
+ PartialVisArea area,
+ float planes[4][4])
{
- BMesh *bm;
- GSet *unique, *other, *faces;
- bool any_changed = false, any_visible = false;
-
- bm = BKE_pbvh_get_bmesh(pbvh);
- unique = BKE_pbvh_bmesh_node_unique_verts(node);
- other = BKE_pbvh_bmesh_node_other_verts(node);
- faces = BKE_pbvh_bmesh_node_faces(node);
-
- sculpt_undo_push_node(ob, node, SCULPT_UNDO_HIDDEN);
-
- partialvis_update_bmesh_verts(
- bm,
- unique,
- action,
- area,
- planes,
- &any_changed,
- &any_visible);
-
- partialvis_update_bmesh_verts(
- bm,
- other,
- action,
- area,
- planes,
- &any_changed,
- &any_visible);
-
- /* finally loop over node faces and tag the ones that are fully hidden */
- partialvis_update_bmesh_faces(faces);
-
- if (any_changed) {
- BKE_pbvh_node_mark_rebuild_draw(node);
- BKE_pbvh_node_fully_hidden_set(node, !any_visible);
- }
+ BMesh *bm;
+ GSet *unique, *other, *faces;
+ bool any_changed = false, any_visible = false;
+
+ bm = BKE_pbvh_get_bmesh(pbvh);
+ unique = BKE_pbvh_bmesh_node_unique_verts(node);
+ other = BKE_pbvh_bmesh_node_other_verts(node);
+ faces = BKE_pbvh_bmesh_node_faces(node);
+
+ sculpt_undo_push_node(ob, node, SCULPT_UNDO_HIDDEN);
+
+ partialvis_update_bmesh_verts(bm, unique, action, area, planes, &any_changed, &any_visible);
+
+ partialvis_update_bmesh_verts(bm, other, action, area, planes, &any_changed, &any_visible);
+
+ /* finally loop over node faces and tag the ones that are fully hidden */
+ partialvis_update_bmesh_faces(faces);
+
+ if (any_changed) {
+ BKE_pbvh_node_mark_rebuild_draw(node);
+ BKE_pbvh_node_fully_hidden_set(node, !any_visible);
+ }
}
static void rect_from_props(rcti *rect, PointerRNA *ptr)
{
- rect->xmin = RNA_int_get(ptr, "xmin");
- rect->ymin = RNA_int_get(ptr, "ymin");
- rect->xmax = RNA_int_get(ptr, "xmax");
- rect->ymax = RNA_int_get(ptr, "ymax");
+ rect->xmin = RNA_int_get(ptr, "xmin");
+ rect->ymin = RNA_int_get(ptr, "ymin");
+ rect->xmax = RNA_int_get(ptr, "xmax");
+ rect->ymax = RNA_int_get(ptr, "ymax");
}
-static void clip_planes_from_rect(
- bContext *C,
- float clip_planes[4][4],
- const rcti *rect)
+static void clip_planes_from_rect(bContext *C, float clip_planes[4][4], const rcti *rect)
{
- ViewContext vc;
- BoundBox bb;
+ ViewContext vc;
+ BoundBox bb;
- view3d_operator_needs_opengl(C);
- ED_view3d_viewcontext_init(C, &vc);
- ED_view3d_clipping_calc(&bb, clip_planes, vc.ar, vc.obact, rect);
- negate_m4(clip_planes);
+ view3d_operator_needs_opengl(C);
+ ED_view3d_viewcontext_init(C, &vc);
+ ED_view3d_clipping_calc(&bb, clip_planes, vc.ar, vc.obact, rect);
+ negate_m4(clip_planes);
}
/* If mode is inside, get all PBVH nodes that lie at least partially
@@ -335,144 +303,148 @@ static void clip_planes_from_rect(
* that lie at least partially outside the volume. If showing all, get
* all nodes. */
static void get_pbvh_nodes(
- PBVH *pbvh,
- PBVHNode ***nodes,
- int *totnode,
- float clip_planes[4][4],
- PartialVisArea mode)
+ PBVH *pbvh, PBVHNode ***nodes, int *totnode, float clip_planes[4][4], PartialVisArea mode)
{
- BKE_pbvh_SearchCallback cb = NULL;
-
- /* select search callback */
- switch (mode) {
- case PARTIALVIS_INSIDE:
- cb = BKE_pbvh_node_planes_contain_AABB;
- break;
- case PARTIALVIS_OUTSIDE:
- cb = BKE_pbvh_node_planes_exclude_AABB;
- break;
- case PARTIALVIS_ALL:
- case PARTIALVIS_MASKED:
- break;
- }
-
- BKE_pbvh_search_gather(pbvh, cb, clip_planes, nodes, totnode);
+ BKE_pbvh_SearchCallback cb = NULL;
+
+ /* select search callback */
+ switch (mode) {
+ case PARTIALVIS_INSIDE:
+ cb = BKE_pbvh_node_planes_contain_AABB;
+ break;
+ case PARTIALVIS_OUTSIDE:
+ cb = BKE_pbvh_node_planes_exclude_AABB;
+ break;
+ case PARTIALVIS_ALL:
+ case PARTIALVIS_MASKED:
+ break;
+ }
+
+ BKE_pbvh_search_gather(pbvh, cb, clip_planes, nodes, totnode);
}
static int hide_show_exec(bContext *C, wmOperator *op)
{
- ARegion *ar = CTX_wm_region(C);
- Object *ob = CTX_data_active_object(C);
- Depsgraph *depsgraph = CTX_data_depsgraph(C);
- Mesh *me = ob->data;
- PartialVisAction action;
- PartialVisArea area;
- PBVH *pbvh;
- PBVHNode **nodes;
- PBVHType pbvh_type;
- float clip_planes[4][4];
- rcti rect;
- int totnode, i;
-
- /* read operator properties */
- action = RNA_enum_get(op->ptr, "action");
- area = RNA_enum_get(op->ptr, "area");
- rect_from_props(&rect, op->ptr);
-
- clip_planes_from_rect(C, clip_planes, &rect);
-
- pbvh = BKE_sculpt_object_pbvh_ensure(depsgraph, ob);
- BLI_assert(ob->sculpt->pbvh == pbvh);
-
- get_pbvh_nodes(pbvh, &nodes, &totnode, clip_planes, area);
- pbvh_type = BKE_pbvh_type(pbvh);
-
- /* start undo */
- switch (action) {
- case PARTIALVIS_HIDE:
- sculpt_undo_push_begin("Hide area");
- break;
- case PARTIALVIS_SHOW:
- sculpt_undo_push_begin("Show area");
- break;
- }
-
- for (i = 0; i < totnode; i++) {
- switch (pbvh_type) {
- case PBVH_FACES:
- partialvis_update_mesh(ob, pbvh, nodes[i], action, area, clip_planes);
- break;
- case PBVH_GRIDS:
- partialvis_update_grids(ob, pbvh, nodes[i], action, area, clip_planes);
- break;
- case PBVH_BMESH:
- partialvis_update_bmesh(ob, pbvh, nodes[i], action, area, clip_planes);
- break;
- }
- }
-
- if (nodes)
- MEM_freeN(nodes);
-
- /* end undo */
- sculpt_undo_push_end();
-
- /* ensure that edges and faces get hidden as well (not used by
- * sculpt but it looks wrong when entering editmode otherwise) */
- if (pbvh_type == PBVH_FACES) {
- BKE_mesh_flush_hidden_from_verts(me);
- }
-
- ED_region_tag_redraw(ar);
-
- return OPERATOR_FINISHED;
+ ARegion *ar = CTX_wm_region(C);
+ Object *ob = CTX_data_active_object(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ Mesh *me = ob->data;
+ PartialVisAction action;
+ PartialVisArea area;
+ PBVH *pbvh;
+ PBVHNode **nodes;
+ PBVHType pbvh_type;
+ float clip_planes[4][4];
+ rcti rect;
+ int totnode, i;
+
+ /* read operator properties */
+ action = RNA_enum_get(op->ptr, "action");
+ area = RNA_enum_get(op->ptr, "area");
+ rect_from_props(&rect, op->ptr);
+
+ clip_planes_from_rect(C, clip_planes, &rect);
+
+ pbvh = BKE_sculpt_object_pbvh_ensure(depsgraph, ob);
+ BLI_assert(ob->sculpt->pbvh == pbvh);
+
+ get_pbvh_nodes(pbvh, &nodes, &totnode, clip_planes, area);
+ pbvh_type = BKE_pbvh_type(pbvh);
+
+ /* start undo */
+ switch (action) {
+ case PARTIALVIS_HIDE:
+ sculpt_undo_push_begin("Hide area");
+ break;
+ case PARTIALVIS_SHOW:
+ sculpt_undo_push_begin("Show area");
+ break;
+ }
+
+ for (i = 0; i < totnode; i++) {
+ switch (pbvh_type) {
+ case PBVH_FACES:
+ partialvis_update_mesh(ob, pbvh, nodes[i], action, area, clip_planes);
+ break;
+ case PBVH_GRIDS:
+ partialvis_update_grids(ob, pbvh, nodes[i], action, area, clip_planes);
+ break;
+ case PBVH_BMESH:
+ partialvis_update_bmesh(ob, pbvh, nodes[i], action, area, clip_planes);
+ break;
+ }
+ }
+
+ if (nodes)
+ MEM_freeN(nodes);
+
+ /* end undo */
+ sculpt_undo_push_end();
+
+ /* ensure that edges and faces get hidden as well (not used by
+ * sculpt but it looks wrong when entering editmode otherwise) */
+ if (pbvh_type == PBVH_FACES) {
+ BKE_mesh_flush_hidden_from_verts(me);
+ }
+
+ ED_region_tag_redraw(ar);
+
+ return OPERATOR_FINISHED;
}
static int hide_show_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
- PartialVisArea area = RNA_enum_get(op->ptr, "area");
+ PartialVisArea area = RNA_enum_get(op->ptr, "area");
- if (!ELEM(area, PARTIALVIS_ALL, PARTIALVIS_MASKED))
- return WM_gesture_box_invoke(C, op, event);
- else
- return op->type->exec(C, op);
+ if (!ELEM(area, PARTIALVIS_ALL, PARTIALVIS_MASKED))
+ return WM_gesture_box_invoke(C, op, event);
+ else
+ return op->type->exec(C, op);
}
void PAINT_OT_hide_show(struct wmOperatorType *ot)
{
- static const EnumPropertyItem action_items[] = {
- {PARTIALVIS_HIDE, "HIDE", 0, "Hide", "Hide vertices"},
- {PARTIALVIS_SHOW, "SHOW", 0, "Show", "Show vertices"},
- {0, NULL, 0, NULL, NULL},
- };
-
- static const EnumPropertyItem area_items[] = {
- {PARTIALVIS_OUTSIDE, "OUTSIDE", 0, "Outside", "Hide or show vertices outside the selection"},
- {PARTIALVIS_INSIDE, "INSIDE", 0, "Inside", "Hide or show vertices inside the selection"},
- {PARTIALVIS_ALL, "ALL", 0, "All", "Hide or show all vertices"},
- {PARTIALVIS_MASKED, "MASKED", 0, "Masked", "Hide or show vertices that are masked (minimum mask value of 0.5)"},
- {0, NULL, 0, NULL, NULL},
- };
-
- /* identifiers */
- ot->name = "Hide/Show";
- ot->idname = "PAINT_OT_hide_show";
- ot->description = "Hide/show some vertices";
-
- /* api callbacks */
- ot->invoke = hide_show_invoke;
- ot->modal = WM_gesture_box_modal;
- ot->exec = hide_show_exec;
- /* sculpt-only for now */
- ot->poll = sculpt_mode_poll_view3d;
-
- ot->flag = OPTYPE_REGISTER;
-
- /* rna */
- RNA_def_enum(ot->srna, "action", action_items, PARTIALVIS_HIDE,
- "Action", "Whether to hide or show vertices");
- RNA_def_enum(ot->srna, "area", area_items, PARTIALVIS_INSIDE,
- "Area", "Which vertices to hide or show");
-
- WM_operator_properties_border(ot);
+ static const EnumPropertyItem action_items[] = {
+ {PARTIALVIS_HIDE, "HIDE", 0, "Hide", "Hide vertices"},
+ {PARTIALVIS_SHOW, "SHOW", 0, "Show", "Show vertices"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ static const EnumPropertyItem area_items[] = {
+ {PARTIALVIS_OUTSIDE, "OUTSIDE", 0, "Outside", "Hide or show vertices outside the selection"},
+ {PARTIALVIS_INSIDE, "INSIDE", 0, "Inside", "Hide or show vertices inside the selection"},
+ {PARTIALVIS_ALL, "ALL", 0, "All", "Hide or show all vertices"},
+ {PARTIALVIS_MASKED,
+ "MASKED",
+ 0,
+ "Masked",
+ "Hide or show vertices that are masked (minimum mask value of 0.5)"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ /* identifiers */
+ ot->name = "Hide/Show";
+ ot->idname = "PAINT_OT_hide_show";
+ ot->description = "Hide/show some vertices";
+
+ /* api callbacks */
+ ot->invoke = hide_show_invoke;
+ ot->modal = WM_gesture_box_modal;
+ ot->exec = hide_show_exec;
+ /* sculpt-only for now */
+ ot->poll = sculpt_mode_poll_view3d;
+
+ ot->flag = OPTYPE_REGISTER;
+
+ /* rna */
+ RNA_def_enum(ot->srna,
+ "action",
+ action_items,
+ PARTIALVIS_HIDE,
+ "Action",
+ "Whether to hide or show vertices");
+ RNA_def_enum(
+ ot->srna, "area", area_items, PARTIALVIS_INSIDE, "Area", "Which vertices to hide or show");
+
+ WM_operator_properties_border(ot);
}
diff --git a/source/blender/editors/sculpt_paint/paint_image.c b/source/blender/editors/sculpt_paint/paint_image.c
index 237e60cd5e0..3a3f4335fd5 100644
--- a/source/blender/editors/sculpt_paint/paint_image.c
+++ b/source/blender/editors/sculpt_paint/paint_image.c
@@ -54,7 +54,6 @@
#include "BKE_paint.h"
#include "BKE_undo_system.h"
-
#include "DEG_depsgraph.h"
#include "UI_interface.h"
@@ -78,7 +77,6 @@
#include "GPU_immediate.h"
#include "GPU_state.h"
-
#include "IMB_colormanagement.h"
#include "paint_intern.h"
@@ -90,662 +88,679 @@ static ImagePaintPartialRedraw imapaintpartial = {0, 0, 0, 0, 0};
ImagePaintPartialRedraw *get_imapaintpartial(void)
{
- return &imapaintpartial;
+ return &imapaintpartial;
}
void set_imapaintpartial(struct ImagePaintPartialRedraw *ippr)
{
- imapaintpartial = *ippr;
+ imapaintpartial = *ippr;
}
/* Imagepaint Partial Redraw & Dirty Region */
void ED_imapaint_clear_partial_redraw(void)
{
- memset(&imapaintpartial, 0, sizeof(imapaintpartial));
+ memset(&imapaintpartial, 0, sizeof(imapaintpartial));
}
-void imapaint_region_tiles(ImBuf *ibuf, int x, int y, int w, int h, int *tx, int *ty, int *tw, int *th)
+void imapaint_region_tiles(
+ ImBuf *ibuf, int x, int y, int w, int h, int *tx, int *ty, int *tw, int *th)
{
- int srcx = 0, srcy = 0;
+ int srcx = 0, srcy = 0;
- IMB_rectclip(ibuf, NULL, &x, &y, &srcx, &srcy, &w, &h);
+ IMB_rectclip(ibuf, NULL, &x, &y, &srcx, &srcy, &w, &h);
- *tw = ((x + w - 1) >> IMAPAINT_TILE_BITS);
- *th = ((y + h - 1) >> IMAPAINT_TILE_BITS);
- *tx = (x >> IMAPAINT_TILE_BITS);
- *ty = (y >> IMAPAINT_TILE_BITS);
+ *tw = ((x + w - 1) >> IMAPAINT_TILE_BITS);
+ *th = ((y + h - 1) >> IMAPAINT_TILE_BITS);
+ *tx = (x >> IMAPAINT_TILE_BITS);
+ *ty = (y >> IMAPAINT_TILE_BITS);
}
void ED_imapaint_dirty_region(Image *ima, ImBuf *ibuf, int x, int y, int w, int h, bool find_old)
{
- ImBuf *tmpibuf = NULL;
- int tilex, tiley, tilew, tileh, tx, ty;
- int srcx = 0, srcy = 0;
+ ImBuf *tmpibuf = NULL;
+ int tilex, tiley, tilew, tileh, tx, ty;
+ int srcx = 0, srcy = 0;
- IMB_rectclip(ibuf, NULL, &x, &y, &srcx, &srcy, &w, &h);
+ IMB_rectclip(ibuf, NULL, &x, &y, &srcx, &srcy, &w, &h);
- if (w == 0 || h == 0)
- return;
+ if (w == 0 || h == 0)
+ return;
- if (!imapaintpartial.enabled) {
- imapaintpartial.x1 = x;
- imapaintpartial.y1 = y;
- imapaintpartial.x2 = x + w;
- imapaintpartial.y2 = y + h;
- imapaintpartial.enabled = 1;
- }
- else {
- imapaintpartial.x1 = min_ii(imapaintpartial.x1, x);
- imapaintpartial.y1 = min_ii(imapaintpartial.y1, y);
- imapaintpartial.x2 = max_ii(imapaintpartial.x2, x + w);
- imapaintpartial.y2 = max_ii(imapaintpartial.y2, y + h);
- }
+ if (!imapaintpartial.enabled) {
+ imapaintpartial.x1 = x;
+ imapaintpartial.y1 = y;
+ imapaintpartial.x2 = x + w;
+ imapaintpartial.y2 = y + h;
+ imapaintpartial.enabled = 1;
+ }
+ else {
+ imapaintpartial.x1 = min_ii(imapaintpartial.x1, x);
+ imapaintpartial.y1 = min_ii(imapaintpartial.y1, y);
+ imapaintpartial.x2 = max_ii(imapaintpartial.x2, x + w);
+ imapaintpartial.y2 = max_ii(imapaintpartial.y2, y + h);
+ }
- imapaint_region_tiles(ibuf, x, y, w, h, &tilex, &tiley, &tilew, &tileh);
+ imapaint_region_tiles(ibuf, x, y, w, h, &tilex, &tiley, &tilew, &tileh);
- ListBase *undo_tiles = ED_image_undo_get_tiles();
+ ListBase *undo_tiles = ED_image_undo_get_tiles();
- for (ty = tiley; ty <= tileh; ty++)
- for (tx = tilex; tx <= tilew; tx++)
- image_undo_push_tile(undo_tiles, ima, ibuf, &tmpibuf, tx, ty, NULL, NULL, false, find_old);
+ for (ty = tiley; ty <= tileh; ty++)
+ for (tx = tilex; tx <= tilew; tx++)
+ image_undo_push_tile(undo_tiles, ima, ibuf, &tmpibuf, tx, ty, NULL, NULL, false, find_old);
- ibuf->userflags |= IB_BITMAPDIRTY;
+ ibuf->userflags |= IB_BITMAPDIRTY;
- if (tmpibuf)
- IMB_freeImBuf(tmpibuf);
+ if (tmpibuf)
+ IMB_freeImBuf(tmpibuf);
}
void imapaint_image_update(SpaceImage *sima, Image *image, ImBuf *ibuf, short texpaint)
{
- if (imapaintpartial.x1 != imapaintpartial.x2 &&
- imapaintpartial.y1 != imapaintpartial.y2)
- {
- IMB_partial_display_buffer_update_delayed(
- ibuf, imapaintpartial.x1, imapaintpartial.y1,
- imapaintpartial.x2, imapaintpartial.y2);
- }
-
- if (ibuf->mipmap[0])
- ibuf->userflags |= IB_MIPMAP_INVALID;
-
- /* todo: should set_tpage create ->rect? */
- if (texpaint || (sima && sima->lock)) {
- int w = imapaintpartial.x2 - imapaintpartial.x1;
- int h = imapaintpartial.y2 - imapaintpartial.y1;
- if (w && h) {
- /* Testing with partial update in uv editor too */
- GPU_paint_update_image(image, (sima ? &sima->iuser : NULL), imapaintpartial.x1, imapaintpartial.y1, w, h);
- }
- }
+ if (imapaintpartial.x1 != imapaintpartial.x2 && imapaintpartial.y1 != imapaintpartial.y2) {
+ IMB_partial_display_buffer_update_delayed(
+ ibuf, imapaintpartial.x1, imapaintpartial.y1, imapaintpartial.x2, imapaintpartial.y2);
+ }
+
+ if (ibuf->mipmap[0])
+ ibuf->userflags |= IB_MIPMAP_INVALID;
+
+ /* todo: should set_tpage create ->rect? */
+ if (texpaint || (sima && sima->lock)) {
+ int w = imapaintpartial.x2 - imapaintpartial.x1;
+ int h = imapaintpartial.y2 - imapaintpartial.y1;
+ if (w && h) {
+ /* Testing with partial update in uv editor too */
+ GPU_paint_update_image(
+ image, (sima ? &sima->iuser : NULL), imapaintpartial.x1, imapaintpartial.y1, w, h);
+ }
+ }
}
/* paint blur kernels. Projective painting enforces use of a 2x2 kernel due to lagging */
BlurKernel *paint_new_blur_kernel(Brush *br, bool proj)
{
- int i, j;
- BlurKernel *kernel = MEM_mallocN(sizeof(BlurKernel), "blur kernel");
- float radius;
- int side;
- eBlurKernelType type = br->blur_mode;
-
- if (proj) {
- radius = 0.5f;
-
- side = kernel->side = 2;
- kernel->side_squared = kernel->side * kernel->side;
- kernel->wdata = MEM_mallocN(sizeof(float) * kernel->side_squared, "blur kernel data");
- kernel->pixel_len = radius;
- }
- else {
- if (br->blur_kernel_radius <= 0)
- br->blur_kernel_radius = 1;
-
- radius = br->blur_kernel_radius;
-
- side = kernel->side = radius * 2 + 1;
- kernel->side_squared = kernel->side * kernel->side;
- kernel->wdata = MEM_mallocN(sizeof(float) * kernel->side_squared, "blur kernel data");
- kernel->pixel_len = br->blur_kernel_radius;
- }
-
- switch (type) {
- case KERNEL_BOX:
- for (i = 0; i < kernel->side_squared; i++)
- kernel->wdata[i] = 1.0;
- break;
-
- case KERNEL_GAUSSIAN:
- {
- /* at 3.0 standard deviations distance, kernel is about zero */
- float standard_dev = radius / 3.0f;
-
- /* make the necessary adjustment to the value for use in the normal distribution formula */
- standard_dev = -standard_dev * standard_dev * 2;
-
- for (i = 0; i < side; i++) {
- for (j = 0; j < side; j++) {
- float idist = radius - i;
- float jdist = radius - j;
- float value = exp((idist * idist + jdist * jdist) / standard_dev);
-
- kernel->wdata[i + j * side] = value;
- }
- }
-
- break;
- }
-
- default:
- printf("unidentified kernel type, aborting\n");
- MEM_freeN(kernel->wdata);
- MEM_freeN(kernel);
- return NULL;
- }
-
- return kernel;
+ int i, j;
+ BlurKernel *kernel = MEM_mallocN(sizeof(BlurKernel), "blur kernel");
+ float radius;
+ int side;
+ eBlurKernelType type = br->blur_mode;
+
+ if (proj) {
+ radius = 0.5f;
+
+ side = kernel->side = 2;
+ kernel->side_squared = kernel->side * kernel->side;
+ kernel->wdata = MEM_mallocN(sizeof(float) * kernel->side_squared, "blur kernel data");
+ kernel->pixel_len = radius;
+ }
+ else {
+ if (br->blur_kernel_radius <= 0)
+ br->blur_kernel_radius = 1;
+
+ radius = br->blur_kernel_radius;
+
+ side = kernel->side = radius * 2 + 1;
+ kernel->side_squared = kernel->side * kernel->side;
+ kernel->wdata = MEM_mallocN(sizeof(float) * kernel->side_squared, "blur kernel data");
+ kernel->pixel_len = br->blur_kernel_radius;
+ }
+
+ switch (type) {
+ case KERNEL_BOX:
+ for (i = 0; i < kernel->side_squared; i++)
+ kernel->wdata[i] = 1.0;
+ break;
+
+ case KERNEL_GAUSSIAN: {
+ /* at 3.0 standard deviations distance, kernel is about zero */
+ float standard_dev = radius / 3.0f;
+
+ /* make the necessary adjustment to the value for use in the normal distribution formula */
+ standard_dev = -standard_dev * standard_dev * 2;
+
+ for (i = 0; i < side; i++) {
+ for (j = 0; j < side; j++) {
+ float idist = radius - i;
+ float jdist = radius - j;
+ float value = exp((idist * idist + jdist * jdist) / standard_dev);
+
+ kernel->wdata[i + j * side] = value;
+ }
+ }
+
+ break;
+ }
+
+ default:
+ printf("unidentified kernel type, aborting\n");
+ MEM_freeN(kernel->wdata);
+ MEM_freeN(kernel);
+ return NULL;
+ }
+
+ return kernel;
}
void paint_delete_blur_kernel(BlurKernel *kernel)
{
- if (kernel->wdata)
- MEM_freeN(kernel->wdata);
+ if (kernel->wdata)
+ MEM_freeN(kernel->wdata);
}
/************************ image paint poll ************************/
static Brush *image_paint_brush(bContext *C)
{
- Scene *scene = CTX_data_scene(C);
- ToolSettings *settings = scene->toolsettings;
+ Scene *scene = CTX_data_scene(C);
+ ToolSettings *settings = scene->toolsettings;
- return BKE_paint_brush(&settings->imapaint.paint);
+ return BKE_paint_brush(&settings->imapaint.paint);
}
static bool image_paint_poll_ex(bContext *C, bool check_tool)
{
- Object *obact;
-
- if (!image_paint_brush(C))
- return 0;
-
- obact = CTX_data_active_object(C);
- if ((obact && obact->mode & OB_MODE_TEXTURE_PAINT) && CTX_wm_region_view3d(C)) {
- if (!check_tool || WM_toolsystem_active_tool_is_brush(C)) {
- return 1;
- }
- }
- else {
- SpaceImage *sima = CTX_wm_space_image(C);
-
- if (sima) {
- ARegion *ar = CTX_wm_region(C);
-
- if ((sima->mode == SI_MODE_PAINT) && ar->regiontype == RGN_TYPE_WINDOW) {
- return 1;
- }
- }
- }
-
- return 0;
+ Object *obact;
+
+ if (!image_paint_brush(C))
+ return 0;
+
+ obact = CTX_data_active_object(C);
+ if ((obact && obact->mode & OB_MODE_TEXTURE_PAINT) && CTX_wm_region_view3d(C)) {
+ if (!check_tool || WM_toolsystem_active_tool_is_brush(C)) {
+ return 1;
+ }
+ }
+ else {
+ SpaceImage *sima = CTX_wm_space_image(C);
+
+ if (sima) {
+ ARegion *ar = CTX_wm_region(C);
+
+ if ((sima->mode == SI_MODE_PAINT) && ar->regiontype == RGN_TYPE_WINDOW) {
+ return 1;
+ }
+ }
+ }
+
+ return 0;
}
static bool image_paint_poll(bContext *C)
{
- return image_paint_poll_ex(C, true);
+ return image_paint_poll_ex(C, true);
}
static bool image_paint_poll_ignore_tool(bContext *C)
{
- return image_paint_poll_ex(C, false);
+ return image_paint_poll_ex(C, false);
}
static bool image_paint_2d_clone_poll(bContext *C)
{
- Brush *brush = image_paint_brush(C);
+ Brush *brush = image_paint_brush(C);
- if (!CTX_wm_region_view3d(C) && image_paint_poll(C))
- if (brush && (brush->imagepaint_tool == PAINT_TOOL_CLONE))
- if (brush->clone.image)
- return 1;
+ if (!CTX_wm_region_view3d(C) && image_paint_poll(C))
+ if (brush && (brush->imagepaint_tool == PAINT_TOOL_CLONE))
+ if (brush->clone.image)
+ return 1;
- return 0;
+ return 0;
}
/************************ paint operator ************************/
typedef enum eTexPaintMode {
- PAINT_MODE_2D,
- PAINT_MODE_3D_PROJECT,
+ PAINT_MODE_2D,
+ PAINT_MODE_3D_PROJECT,
} eTexPaintMode;
typedef struct PaintOperation {
- eTexPaintMode mode;
+ eTexPaintMode mode;
- void *custom_paint;
+ void *custom_paint;
- float prevmouse[2];
- float startmouse[2];
- double starttime;
+ float prevmouse[2];
+ float startmouse[2];
+ double starttime;
- void *cursor;
- ViewContext vc;
+ void *cursor;
+ ViewContext vc;
} PaintOperation;
bool paint_use_opacity_masking(Brush *brush)
{
- return ((brush->flag & BRUSH_AIRBRUSH) ||
- (brush->flag & BRUSH_DRAG_DOT) ||
- (brush->flag & BRUSH_ANCHORED) ||
- (brush->imagepaint_tool == PAINT_TOOL_SMEAR) ||
- (brush->imagepaint_tool == PAINT_TOOL_SOFTEN) ||
- (brush->imagepaint_tool == PAINT_TOOL_FILL) ||
- (brush->flag & BRUSH_USE_GRADIENT) ||
- (brush->mtex.tex &&
- !ELEM(brush->mtex.brush_map_mode, MTEX_MAP_MODE_TILED, MTEX_MAP_MODE_STENCIL, MTEX_MAP_MODE_3D)) ?
- false : true);
+ return ((brush->flag & BRUSH_AIRBRUSH) || (brush->flag & BRUSH_DRAG_DOT) ||
+ (brush->flag & BRUSH_ANCHORED) || (brush->imagepaint_tool == PAINT_TOOL_SMEAR) ||
+ (brush->imagepaint_tool == PAINT_TOOL_SOFTEN) ||
+ (brush->imagepaint_tool == PAINT_TOOL_FILL) ||
+ (brush->flag & BRUSH_USE_GRADIENT) ||
+ (brush->mtex.tex && !ELEM(brush->mtex.brush_map_mode,
+ MTEX_MAP_MODE_TILED,
+ MTEX_MAP_MODE_STENCIL,
+ MTEX_MAP_MODE_3D)) ?
+ false :
+ true);
}
-void paint_brush_color_get(
- struct Scene *scene, struct Brush *br, bool color_correction, bool invert, float distance,
- float pressure, float color[3], struct ColorManagedDisplay *display)
+void paint_brush_color_get(struct Scene *scene,
+ struct Brush *br,
+ bool color_correction,
+ bool invert,
+ float distance,
+ float pressure,
+ float color[3],
+ struct ColorManagedDisplay *display)
{
- if (invert)
- copy_v3_v3(color, BKE_brush_secondary_color_get(scene, br));
- else {
- if (br->flag & BRUSH_USE_GRADIENT) {
- float color_gr[4];
- switch (br->gradient_stroke_mode) {
- case BRUSH_GRADIENT_PRESSURE:
- BKE_colorband_evaluate(br->gradient, pressure, color_gr);
- break;
- case BRUSH_GRADIENT_SPACING_REPEAT:
- {
- float coord = fmod(distance / br->gradient_spacing, 1.0);
- BKE_colorband_evaluate(br->gradient, coord, color_gr);
- break;
- }
- case BRUSH_GRADIENT_SPACING_CLAMP:
- {
- BKE_colorband_evaluate(br->gradient, distance / br->gradient_spacing, color_gr);
- break;
- }
- }
- copy_v3_v3(color, color_gr);
- }
- else
- copy_v3_v3(color, BKE_brush_color_get(scene, br));
- }
- if (color_correction)
- IMB_colormanagement_display_to_scene_linear_v3(color, display);
+ if (invert)
+ copy_v3_v3(color, BKE_brush_secondary_color_get(scene, br));
+ else {
+ if (br->flag & BRUSH_USE_GRADIENT) {
+ float color_gr[4];
+ switch (br->gradient_stroke_mode) {
+ case BRUSH_GRADIENT_PRESSURE:
+ BKE_colorband_evaluate(br->gradient, pressure, color_gr);
+ break;
+ case BRUSH_GRADIENT_SPACING_REPEAT: {
+ float coord = fmod(distance / br->gradient_spacing, 1.0);
+ BKE_colorband_evaluate(br->gradient, coord, color_gr);
+ break;
+ }
+ case BRUSH_GRADIENT_SPACING_CLAMP: {
+ BKE_colorband_evaluate(br->gradient, distance / br->gradient_spacing, color_gr);
+ break;
+ }
+ }
+ copy_v3_v3(color, color_gr);
+ }
+ else
+ copy_v3_v3(color, BKE_brush_color_get(scene, br));
+ }
+ if (color_correction)
+ IMB_colormanagement_display_to_scene_linear_v3(color, display);
}
void paint_brush_init_tex(Brush *brush)
{
- /* init mtex nodes */
- if (brush) {
- MTex *mtex = &brush->mtex;
- if (mtex->tex && mtex->tex->nodetree) {
- /* has internal flag to detect it only does it once */
- ntreeTexBeginExecTree(mtex->tex->nodetree);
- }
- mtex = &brush->mask_mtex;
- if (mtex->tex && mtex->tex->nodetree) {
- ntreeTexBeginExecTree(mtex->tex->nodetree);
- }
- }
+ /* init mtex nodes */
+ if (brush) {
+ MTex *mtex = &brush->mtex;
+ if (mtex->tex && mtex->tex->nodetree) {
+ /* has internal flag to detect it only does it once */
+ ntreeTexBeginExecTree(mtex->tex->nodetree);
+ }
+ mtex = &brush->mask_mtex;
+ if (mtex->tex && mtex->tex->nodetree) {
+ ntreeTexBeginExecTree(mtex->tex->nodetree);
+ }
+ }
}
void paint_brush_exit_tex(Brush *brush)
{
- if (brush) {
- MTex *mtex = &brush->mtex;
- if (mtex->tex && mtex->tex->nodetree)
- ntreeTexEndExecTree(mtex->tex->nodetree->execdata);
- mtex = &brush->mask_mtex;
- if (mtex->tex && mtex->tex->nodetree)
- ntreeTexEndExecTree(mtex->tex->nodetree->execdata);
- }
+ if (brush) {
+ MTex *mtex = &brush->mtex;
+ if (mtex->tex && mtex->tex->nodetree)
+ ntreeTexEndExecTree(mtex->tex->nodetree->execdata);
+ mtex = &brush->mask_mtex;
+ if (mtex->tex && mtex->tex->nodetree)
+ ntreeTexEndExecTree(mtex->tex->nodetree->execdata);
+ }
}
static void gradient_draw_line(bContext *UNUSED(C), int x, int y, void *customdata)
{
- PaintOperation *pop = (PaintOperation *)customdata;
+ PaintOperation *pop = (PaintOperation *)customdata;
- if (pop) {
- GPU_line_smooth(true);
- GPU_blend(true);
+ if (pop) {
+ GPU_line_smooth(true);
+ GPU_blend(true);
- GPUVertFormat *format = immVertexFormat();
- uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT);
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT);
- ARegion *ar = pop->vc.ar;
+ ARegion *ar = pop->vc.ar;
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
- GPU_line_width(4.0);
- immUniformColor4ub(0, 0, 0, 255);
+ GPU_line_width(4.0);
+ immUniformColor4ub(0, 0, 0, 255);
- immBegin(GPU_PRIM_LINES, 2);
- immVertex2i(pos, x, y);
- immVertex2i(pos, pop->startmouse[0] + ar->winrct.xmin, pop->startmouse[1] + ar->winrct.ymin);
- immEnd();
+ immBegin(GPU_PRIM_LINES, 2);
+ immVertex2i(pos, x, y);
+ immVertex2i(pos, pop->startmouse[0] + ar->winrct.xmin, pop->startmouse[1] + ar->winrct.ymin);
+ immEnd();
- GPU_line_width(2.0);
- immUniformColor4ub(255, 255, 255, 255);
+ GPU_line_width(2.0);
+ immUniformColor4ub(255, 255, 255, 255);
- immBegin(GPU_PRIM_LINES, 2);
- immVertex2i(pos, x, y);
- immVertex2i(pos, pop->startmouse[0] + ar->winrct.xmin, pop->startmouse[1] + ar->winrct.ymin);
- immEnd();
+ immBegin(GPU_PRIM_LINES, 2);
+ immVertex2i(pos, x, y);
+ immVertex2i(pos, pop->startmouse[0] + ar->winrct.xmin, pop->startmouse[1] + ar->winrct.ymin);
+ immEnd();
- immUnbindProgram();
+ immUnbindProgram();
- GPU_blend(false);
- GPU_line_smooth(false);
- }
+ GPU_blend(false);
+ GPU_line_smooth(false);
+ }
}
-
static PaintOperation *texture_paint_init(bContext *C, wmOperator *op, const float mouse[2])
{
- Scene *scene = CTX_data_scene(C);
- ToolSettings *settings = scene->toolsettings;
- PaintOperation *pop = MEM_callocN(sizeof(PaintOperation), "PaintOperation"); /* caller frees */
- Brush *brush = BKE_paint_brush(&settings->imapaint.paint);
- int mode = RNA_enum_get(op->ptr, "mode");
- ED_view3d_viewcontext_init(C, &pop->vc);
-
- copy_v2_v2(pop->prevmouse, mouse);
- copy_v2_v2(pop->startmouse, mouse);
-
- /* initialize from context */
- if (CTX_wm_region_view3d(C)) {
- ViewLayer *view_layer = CTX_data_view_layer(C);
- Object *ob = OBACT(view_layer);
- bool uvs, mat, tex, stencil;
- if (!BKE_paint_proj_mesh_data_check(scene, ob, &uvs, &mat, &tex, &stencil)) {
- BKE_paint_data_warning(op->reports, uvs, mat, tex, stencil);
- MEM_freeN(pop);
- WM_event_add_notifier(C, NC_SCENE | ND_TOOLSETTINGS, NULL);
- return NULL;
- }
- pop->mode = PAINT_MODE_3D_PROJECT;
- pop->custom_paint = paint_proj_new_stroke(C, ob, mouse, mode);
- }
- else {
- pop->mode = PAINT_MODE_2D;
- pop->custom_paint = paint_2d_new_stroke(C, op, mode);
- }
-
- if (!pop->custom_paint) {
- MEM_freeN(pop);
- return NULL;
- }
-
- if ((brush->imagepaint_tool == PAINT_TOOL_FILL) && (brush->flag & BRUSH_USE_GRADIENT)) {
- pop->cursor = WM_paint_cursor_activate(
- CTX_wm_manager(C),
- SPACE_TYPE_ANY, RGN_TYPE_ANY,
- image_paint_poll, gradient_draw_line,
- pop);
- }
-
- settings->imapaint.flag |= IMAGEPAINT_DRAWING;
- ED_image_undo_push_begin(op->type->name, PAINT_MODE_TEXTURE_2D);
-
- return pop;
+ Scene *scene = CTX_data_scene(C);
+ ToolSettings *settings = scene->toolsettings;
+ PaintOperation *pop = MEM_callocN(sizeof(PaintOperation), "PaintOperation"); /* caller frees */
+ Brush *brush = BKE_paint_brush(&settings->imapaint.paint);
+ int mode = RNA_enum_get(op->ptr, "mode");
+ ED_view3d_viewcontext_init(C, &pop->vc);
+
+ copy_v2_v2(pop->prevmouse, mouse);
+ copy_v2_v2(pop->startmouse, mouse);
+
+ /* initialize from context */
+ if (CTX_wm_region_view3d(C)) {
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Object *ob = OBACT(view_layer);
+ bool uvs, mat, tex, stencil;
+ if (!BKE_paint_proj_mesh_data_check(scene, ob, &uvs, &mat, &tex, &stencil)) {
+ BKE_paint_data_warning(op->reports, uvs, mat, tex, stencil);
+ MEM_freeN(pop);
+ WM_event_add_notifier(C, NC_SCENE | ND_TOOLSETTINGS, NULL);
+ return NULL;
+ }
+ pop->mode = PAINT_MODE_3D_PROJECT;
+ pop->custom_paint = paint_proj_new_stroke(C, ob, mouse, mode);
+ }
+ else {
+ pop->mode = PAINT_MODE_2D;
+ pop->custom_paint = paint_2d_new_stroke(C, op, mode);
+ }
+
+ if (!pop->custom_paint) {
+ MEM_freeN(pop);
+ return NULL;
+ }
+
+ if ((brush->imagepaint_tool == PAINT_TOOL_FILL) && (brush->flag & BRUSH_USE_GRADIENT)) {
+ pop->cursor = WM_paint_cursor_activate(CTX_wm_manager(C),
+ SPACE_TYPE_ANY,
+ RGN_TYPE_ANY,
+ image_paint_poll,
+ gradient_draw_line,
+ pop);
+ }
+
+ settings->imapaint.flag |= IMAGEPAINT_DRAWING;
+ ED_image_undo_push_begin(op->type->name, PAINT_MODE_TEXTURE_2D);
+
+ return pop;
}
static void paint_stroke_update_step(bContext *C, struct PaintStroke *stroke, PointerRNA *itemptr)
{
- PaintOperation *pop = paint_stroke_mode_data(stroke);
- Scene *scene = CTX_data_scene(C);
- ToolSettings *toolsettings = CTX_data_tool_settings(C);
- UnifiedPaintSettings *ups = &toolsettings->unified_paint_settings;
- Brush *brush = BKE_paint_brush(&toolsettings->imapaint.paint);
-
- float alphafac = (brush->flag & BRUSH_ACCUMULATE) ? ups->overlap_factor : 1.0f;
-
- /* initial brush values. Maybe it should be considered moving these to stroke system */
- float startalpha = BKE_brush_alpha_get(scene, brush);
-
- float mouse[2];
- float pressure;
- float size;
- float distance = paint_stroke_distance_get(stroke);
- int eraser;
-
- RNA_float_get_array(itemptr, "mouse", mouse);
- pressure = RNA_float_get(itemptr, "pressure");
- eraser = RNA_boolean_get(itemptr, "pen_flip");
- size = max_ff(1.0f, RNA_float_get(itemptr, "size"));
-
- /* stroking with fill tool only acts on stroke end */
- if (brush->imagepaint_tool == PAINT_TOOL_FILL) {
- copy_v2_v2(pop->prevmouse, mouse);
- return;
- }
-
- if (BKE_brush_use_alpha_pressure(scene, brush))
- BKE_brush_alpha_set(scene, brush, max_ff(0.0f, startalpha * pressure * alphafac));
- else
- BKE_brush_alpha_set(scene, brush, max_ff(0.0f, startalpha * alphafac));
-
- if ((brush->flag & BRUSH_DRAG_DOT) || (brush->flag & BRUSH_ANCHORED)) {
- UndoStack *ustack = CTX_wm_manager(C)->undo_stack;
- ED_image_undo_restore(ustack->step_init);
- }
-
- if (pop->mode == PAINT_MODE_3D_PROJECT) {
- paint_proj_stroke(C, pop->custom_paint, pop->prevmouse, mouse, eraser, pressure, distance, size);
- }
- else {
- paint_2d_stroke(pop->custom_paint, pop->prevmouse, mouse, eraser, pressure, distance, size);
- }
-
- copy_v2_v2(pop->prevmouse, mouse);
-
- /* restore brush values */
- BKE_brush_alpha_set(scene, brush, startalpha);
+ PaintOperation *pop = paint_stroke_mode_data(stroke);
+ Scene *scene = CTX_data_scene(C);
+ ToolSettings *toolsettings = CTX_data_tool_settings(C);
+ UnifiedPaintSettings *ups = &toolsettings->unified_paint_settings;
+ Brush *brush = BKE_paint_brush(&toolsettings->imapaint.paint);
+
+ float alphafac = (brush->flag & BRUSH_ACCUMULATE) ? ups->overlap_factor : 1.0f;
+
+ /* initial brush values. Maybe it should be considered moving these to stroke system */
+ float startalpha = BKE_brush_alpha_get(scene, brush);
+
+ float mouse[2];
+ float pressure;
+ float size;
+ float distance = paint_stroke_distance_get(stroke);
+ int eraser;
+
+ RNA_float_get_array(itemptr, "mouse", mouse);
+ pressure = RNA_float_get(itemptr, "pressure");
+ eraser = RNA_boolean_get(itemptr, "pen_flip");
+ size = max_ff(1.0f, RNA_float_get(itemptr, "size"));
+
+ /* stroking with fill tool only acts on stroke end */
+ if (brush->imagepaint_tool == PAINT_TOOL_FILL) {
+ copy_v2_v2(pop->prevmouse, mouse);
+ return;
+ }
+
+ if (BKE_brush_use_alpha_pressure(scene, brush))
+ BKE_brush_alpha_set(scene, brush, max_ff(0.0f, startalpha * pressure * alphafac));
+ else
+ BKE_brush_alpha_set(scene, brush, max_ff(0.0f, startalpha * alphafac));
+
+ if ((brush->flag & BRUSH_DRAG_DOT) || (brush->flag & BRUSH_ANCHORED)) {
+ UndoStack *ustack = CTX_wm_manager(C)->undo_stack;
+ ED_image_undo_restore(ustack->step_init);
+ }
+
+ if (pop->mode == PAINT_MODE_3D_PROJECT) {
+ paint_proj_stroke(
+ C, pop->custom_paint, pop->prevmouse, mouse, eraser, pressure, distance, size);
+ }
+ else {
+ paint_2d_stroke(pop->custom_paint, pop->prevmouse, mouse, eraser, pressure, distance, size);
+ }
+
+ copy_v2_v2(pop->prevmouse, mouse);
+
+ /* restore brush values */
+ BKE_brush_alpha_set(scene, brush, startalpha);
}
static void paint_stroke_redraw(const bContext *C, struct PaintStroke *stroke, bool final)
{
- PaintOperation *pop = paint_stroke_mode_data(stroke);
-
- if (pop->mode == PAINT_MODE_3D_PROJECT) {
- paint_proj_redraw(C, pop->custom_paint, final);
- }
- else {
- paint_2d_redraw(C, pop->custom_paint, final);
- }
+ PaintOperation *pop = paint_stroke_mode_data(stroke);
+
+ if (pop->mode == PAINT_MODE_3D_PROJECT) {
+ paint_proj_redraw(C, pop->custom_paint, final);
+ }
+ else {
+ paint_2d_redraw(C, pop->custom_paint, final);
+ }
}
static void paint_stroke_done(const bContext *C, struct PaintStroke *stroke)
{
- Scene *scene = CTX_data_scene(C);
- ToolSettings *toolsettings = scene->toolsettings;
- PaintOperation *pop = paint_stroke_mode_data(stroke);
- Brush *brush = BKE_paint_brush(&toolsettings->imapaint.paint);
-
- toolsettings->imapaint.flag &= ~IMAGEPAINT_DRAWING;
-
- if (brush->imagepaint_tool == PAINT_TOOL_FILL) {
- if (brush->flag & BRUSH_USE_GRADIENT) {
- if (pop->mode == PAINT_MODE_2D) {
- paint_2d_gradient_fill(C, brush, pop->startmouse, pop->prevmouse, pop->custom_paint);
- }
- else {
- paint_proj_stroke(
- C, pop->custom_paint, pop->startmouse, pop->prevmouse, paint_stroke_flipped(stroke),
- 1.0, 0.0, BKE_brush_size_get(scene, brush));
- /* two redraws, one for GPU update, one for notification */
- paint_proj_redraw(C, pop->custom_paint, false);
- paint_proj_redraw(C, pop->custom_paint, true);
- }
- }
- else {
- if (pop->mode == PAINT_MODE_2D) {
- float color[3];
- if (paint_stroke_inverted(stroke)) {
- srgb_to_linearrgb_v3_v3(color, BKE_brush_secondary_color_get(scene, brush));
- }
- else {
- srgb_to_linearrgb_v3_v3(color, BKE_brush_color_get(scene, brush));
- }
- paint_2d_bucket_fill(C, color, brush, pop->prevmouse, pop->custom_paint);
- }
- else {
- paint_proj_stroke(
- C, pop->custom_paint, pop->startmouse, pop->prevmouse, paint_stroke_flipped(stroke),
- 1.0, 0.0, BKE_brush_size_get(scene, brush));
- /* two redraws, one for GPU update, one for notification */
- paint_proj_redraw(C, pop->custom_paint, false);
- paint_proj_redraw(C, pop->custom_paint, true);
- }
- }
- }
- if (pop->mode == PAINT_MODE_3D_PROJECT) {
- paint_proj_stroke_done(pop->custom_paint);
- }
- else {
- paint_2d_stroke_done(pop->custom_paint);
- }
-
- if (pop->cursor) {
- WM_paint_cursor_end(CTX_wm_manager(C), pop->cursor);
- }
-
- ED_image_undo_push_end();
-
- /* duplicate warning, see texpaint_init */
+ Scene *scene = CTX_data_scene(C);
+ ToolSettings *toolsettings = scene->toolsettings;
+ PaintOperation *pop = paint_stroke_mode_data(stroke);
+ Brush *brush = BKE_paint_brush(&toolsettings->imapaint.paint);
+
+ toolsettings->imapaint.flag &= ~IMAGEPAINT_DRAWING;
+
+ if (brush->imagepaint_tool == PAINT_TOOL_FILL) {
+ if (brush->flag & BRUSH_USE_GRADIENT) {
+ if (pop->mode == PAINT_MODE_2D) {
+ paint_2d_gradient_fill(C, brush, pop->startmouse, pop->prevmouse, pop->custom_paint);
+ }
+ else {
+ paint_proj_stroke(C,
+ pop->custom_paint,
+ pop->startmouse,
+ pop->prevmouse,
+ paint_stroke_flipped(stroke),
+ 1.0,
+ 0.0,
+ BKE_brush_size_get(scene, brush));
+ /* two redraws, one for GPU update, one for notification */
+ paint_proj_redraw(C, pop->custom_paint, false);
+ paint_proj_redraw(C, pop->custom_paint, true);
+ }
+ }
+ else {
+ if (pop->mode == PAINT_MODE_2D) {
+ float color[3];
+ if (paint_stroke_inverted(stroke)) {
+ srgb_to_linearrgb_v3_v3(color, BKE_brush_secondary_color_get(scene, brush));
+ }
+ else {
+ srgb_to_linearrgb_v3_v3(color, BKE_brush_color_get(scene, brush));
+ }
+ paint_2d_bucket_fill(C, color, brush, pop->prevmouse, pop->custom_paint);
+ }
+ else {
+ paint_proj_stroke(C,
+ pop->custom_paint,
+ pop->startmouse,
+ pop->prevmouse,
+ paint_stroke_flipped(stroke),
+ 1.0,
+ 0.0,
+ BKE_brush_size_get(scene, brush));
+ /* two redraws, one for GPU update, one for notification */
+ paint_proj_redraw(C, pop->custom_paint, false);
+ paint_proj_redraw(C, pop->custom_paint, true);
+ }
+ }
+ }
+ if (pop->mode == PAINT_MODE_3D_PROJECT) {
+ paint_proj_stroke_done(pop->custom_paint);
+ }
+ else {
+ paint_2d_stroke_done(pop->custom_paint);
+ }
+
+ if (pop->cursor) {
+ WM_paint_cursor_end(CTX_wm_manager(C), pop->cursor);
+ }
+
+ ED_image_undo_push_end();
+
+ /* duplicate warning, see texpaint_init */
#if 0
- if (pop->s.warnmultifile)
- BKE_reportf(op->reports, RPT_WARNING, "Image requires 4 color channels to paint: %s", pop->s.warnmultifile);
- if (pop->s.warnpackedfile)
- BKE_reportf(op->reports, RPT_WARNING, "Packed MultiLayer files cannot be painted: %s", pop->s.warnpackedfile);
+ if (pop->s.warnmultifile)
+ BKE_reportf(op->reports, RPT_WARNING, "Image requires 4 color channels to paint: %s", pop->s.warnmultifile);
+ if (pop->s.warnpackedfile)
+ BKE_reportf(op->reports, RPT_WARNING, "Packed MultiLayer files cannot be painted: %s", pop->s.warnpackedfile);
#endif
- MEM_freeN(pop);
+ MEM_freeN(pop);
}
static bool paint_stroke_test_start(bContext *C, wmOperator *op, const float mouse[2])
{
- PaintOperation *pop;
+ PaintOperation *pop;
- /* TODO Should avoid putting this here. Instead, last position should be requested
- * from stroke system. */
+ /* TODO Should avoid putting this here. Instead, last position should be requested
+ * from stroke system. */
- if (!(pop = texture_paint_init(C, op, mouse))) {
- return false;
- }
+ if (!(pop = texture_paint_init(C, op, mouse))) {
+ return false;
+ }
- paint_stroke_set_mode_data(op->customdata, pop);
+ paint_stroke_set_mode_data(op->customdata, pop);
- return true;
+ return true;
}
-
static int paint_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
- int retval;
-
- op->customdata = paint_stroke_new(
- C, op, NULL, paint_stroke_test_start,
- paint_stroke_update_step,
- paint_stroke_redraw,
- paint_stroke_done, event->type);
-
- if ((retval = op->type->modal(C, op, event)) == OPERATOR_FINISHED) {
- paint_stroke_data_free(op);
- return OPERATOR_FINISHED;
- }
- /* add modal handler */
- WM_event_add_modal_handler(C, op);
-
- OPERATOR_RETVAL_CHECK(retval);
- BLI_assert(retval == OPERATOR_RUNNING_MODAL);
-
- return OPERATOR_RUNNING_MODAL;
+ int retval;
+
+ op->customdata = paint_stroke_new(C,
+ op,
+ NULL,
+ paint_stroke_test_start,
+ paint_stroke_update_step,
+ paint_stroke_redraw,
+ paint_stroke_done,
+ event->type);
+
+ if ((retval = op->type->modal(C, op, event)) == OPERATOR_FINISHED) {
+ paint_stroke_data_free(op);
+ return OPERATOR_FINISHED;
+ }
+ /* add modal handler */
+ WM_event_add_modal_handler(C, op);
+
+ OPERATOR_RETVAL_CHECK(retval);
+ BLI_assert(retval == OPERATOR_RUNNING_MODAL);
+
+ return OPERATOR_RUNNING_MODAL;
}
static int paint_exec(bContext *C, wmOperator *op)
{
- PropertyRNA *strokeprop;
- PointerRNA firstpoint;
- float mouse[2];
-
- strokeprop = RNA_struct_find_property(op->ptr, "stroke");
-
- if (!RNA_property_collection_lookup_int(op->ptr, strokeprop, 0, &firstpoint))
- return OPERATOR_CANCELLED;
-
- RNA_float_get_array(&firstpoint, "mouse", mouse);
-
- op->customdata = paint_stroke_new(
- C, op, NULL, paint_stroke_test_start,
- paint_stroke_update_step,
- paint_stroke_redraw,
- paint_stroke_done, 0);
- /* frees op->customdata */
- return paint_stroke_exec(C, op);
+ PropertyRNA *strokeprop;
+ PointerRNA firstpoint;
+ float mouse[2];
+
+ strokeprop = RNA_struct_find_property(op->ptr, "stroke");
+
+ if (!RNA_property_collection_lookup_int(op->ptr, strokeprop, 0, &firstpoint))
+ return OPERATOR_CANCELLED;
+
+ RNA_float_get_array(&firstpoint, "mouse", mouse);
+
+ op->customdata = paint_stroke_new(C,
+ op,
+ NULL,
+ paint_stroke_test_start,
+ paint_stroke_update_step,
+ paint_stroke_redraw,
+ paint_stroke_done,
+ 0);
+ /* frees op->customdata */
+ return paint_stroke_exec(C, op);
}
void PAINT_OT_image_paint(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Image Paint";
- ot->idname = "PAINT_OT_image_paint";
- ot->description = "Paint a stroke into the image";
-
- /* api callbacks */
- ot->invoke = paint_invoke;
- ot->modal = paint_stroke_modal;
- ot->exec = paint_exec;
- ot->poll = image_paint_poll;
- ot->cancel = paint_stroke_cancel;
-
- /* flags */
- ot->flag = OPTYPE_BLOCKING;
-
- paint_stroke_operator_properties(ot);
+ /* identifiers */
+ ot->name = "Image Paint";
+ ot->idname = "PAINT_OT_image_paint";
+ ot->description = "Paint a stroke into the image";
+
+ /* api callbacks */
+ ot->invoke = paint_invoke;
+ ot->modal = paint_stroke_modal;
+ ot->exec = paint_exec;
+ ot->poll = image_paint_poll;
+ ot->cancel = paint_stroke_cancel;
+
+ /* flags */
+ ot->flag = OPTYPE_BLOCKING;
+
+ paint_stroke_operator_properties(ot);
}
-
int get_imapaint_zoom(bContext *C, float *zoomx, float *zoomy)
{
- RegionView3D *rv3d = CTX_wm_region_view3d(C);
+ RegionView3D *rv3d = CTX_wm_region_view3d(C);
- if (!rv3d) {
- SpaceImage *sima = CTX_wm_space_image(C);
+ if (!rv3d) {
+ SpaceImage *sima = CTX_wm_space_image(C);
- if (sima->mode == SI_MODE_PAINT) {
- ARegion *ar = CTX_wm_region(C);
- ED_space_image_get_zoom(sima, ar, zoomx, zoomy);
+ if (sima->mode == SI_MODE_PAINT) {
+ ARegion *ar = CTX_wm_region(C);
+ ED_space_image_get_zoom(sima, ar, zoomx, zoomy);
- return 1;
- }
- }
+ return 1;
+ }
+ }
- *zoomx = *zoomy = 1;
+ *zoomx = *zoomy = 1;
- return 0;
+ return 0;
}
/************************ cursor drawing *******************************/
static void toggle_paint_cursor(bContext *C, int enable)
{
- wmWindowManager *wm = CTX_wm_manager(C);
- Scene *scene = CTX_data_scene(C);
- ToolSettings *settings = scene->toolsettings;
-
- if (settings->imapaint.paintcursor && !enable) {
- WM_paint_cursor_end(wm, settings->imapaint.paintcursor);
- settings->imapaint.paintcursor = NULL;
- paint_cursor_delete_textures();
- }
- else if (enable)
- paint_cursor_start(C, image_paint_poll);
+ wmWindowManager *wm = CTX_wm_manager(C);
+ Scene *scene = CTX_data_scene(C);
+ ToolSettings *settings = scene->toolsettings;
+
+ if (settings->imapaint.paintcursor && !enable) {
+ WM_paint_cursor_end(wm, settings->imapaint.paintcursor);
+ settings->imapaint.paintcursor = NULL;
+ paint_cursor_delete_textures();
+ }
+ else if (enable)
+ paint_cursor_start(C, image_paint_poll);
}
/* enable the paint cursor if it isn't already.
@@ -755,526 +770,534 @@ static void toggle_paint_cursor(bContext *C, int enable)
* ensure that the cursor is hidden when not in paint mode */
void ED_space_image_paint_update(Main *bmain, wmWindowManager *wm, Scene *scene)
{
- ToolSettings *settings = scene->toolsettings;
- ImagePaintSettings *imapaint = &settings->imapaint;
- bool enabled = false;
-
- for (wmWindow *win = wm->windows.first; win; win = win->next) {
- bScreen *screen = WM_window_get_active_screen(win);
-
- for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
- if (sa->spacetype == SPACE_IMAGE) {
- if (((SpaceImage *)sa->spacedata.first)->mode == SI_MODE_PAINT) {
- enabled = true;
- }
- }
- }
- }
-
- if (enabled) {
- BKE_paint_init(bmain, scene, PAINT_MODE_TEXTURE_2D, PAINT_CURSOR_TEXTURE_PAINT);
-
- paint_cursor_start_explicit(&imapaint->paint, wm, image_paint_poll);
- }
- else {
- paint_cursor_delete_textures();
- }
+ ToolSettings *settings = scene->toolsettings;
+ ImagePaintSettings *imapaint = &settings->imapaint;
+ bool enabled = false;
+
+ for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ bScreen *screen = WM_window_get_active_screen(win);
+
+ for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
+ if (sa->spacetype == SPACE_IMAGE) {
+ if (((SpaceImage *)sa->spacedata.first)->mode == SI_MODE_PAINT) {
+ enabled = true;
+ }
+ }
+ }
+ }
+
+ if (enabled) {
+ BKE_paint_init(bmain, scene, PAINT_MODE_TEXTURE_2D, PAINT_CURSOR_TEXTURE_PAINT);
+
+ paint_cursor_start_explicit(&imapaint->paint, wm, image_paint_poll);
+ }
+ else {
+ paint_cursor_delete_textures();
+ }
}
/************************ grab clone operator ************************/
typedef struct GrabClone {
- float startoffset[2];
- int startx, starty;
+ float startoffset[2];
+ int startx, starty;
} GrabClone;
static void grab_clone_apply(bContext *C, wmOperator *op)
{
- Brush *brush = image_paint_brush(C);
- float delta[2];
+ Brush *brush = image_paint_brush(C);
+ float delta[2];
- RNA_float_get_array(op->ptr, "delta", delta);
- add_v2_v2(brush->clone.offset, delta);
- ED_region_tag_redraw(CTX_wm_region(C));
+ RNA_float_get_array(op->ptr, "delta", delta);
+ add_v2_v2(brush->clone.offset, delta);
+ ED_region_tag_redraw(CTX_wm_region(C));
}
static int grab_clone_exec(bContext *C, wmOperator *op)
{
- grab_clone_apply(C, op);
+ grab_clone_apply(C, op);
- return OPERATOR_FINISHED;
+ return OPERATOR_FINISHED;
}
static int grab_clone_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
- Brush *brush = image_paint_brush(C);
- GrabClone *cmv;
+ Brush *brush = image_paint_brush(C);
+ GrabClone *cmv;
- cmv = MEM_callocN(sizeof(GrabClone), "GrabClone");
- copy_v2_v2(cmv->startoffset, brush->clone.offset);
- cmv->startx = event->x;
- cmv->starty = event->y;
- op->customdata = cmv;
+ cmv = MEM_callocN(sizeof(GrabClone), "GrabClone");
+ copy_v2_v2(cmv->startoffset, brush->clone.offset);
+ cmv->startx = event->x;
+ cmv->starty = event->y;
+ op->customdata = cmv;
- WM_event_add_modal_handler(C, op);
+ WM_event_add_modal_handler(C, op);
- return OPERATOR_RUNNING_MODAL;
+ return OPERATOR_RUNNING_MODAL;
}
static int grab_clone_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
- Brush *brush = image_paint_brush(C);
- ARegion *ar = CTX_wm_region(C);
- GrabClone *cmv = op->customdata;
- float startfx, startfy, fx, fy, delta[2];
- int xmin = ar->winrct.xmin, ymin = ar->winrct.ymin;
-
- switch (event->type) {
- case LEFTMOUSE:
- case MIDDLEMOUSE:
- case RIGHTMOUSE: // XXX hardcoded
- MEM_freeN(op->customdata);
- return OPERATOR_FINISHED;
- case MOUSEMOVE:
- /* mouse moved, so move the clone image */
- UI_view2d_region_to_view(&ar->v2d, cmv->startx - xmin, cmv->starty - ymin, &startfx, &startfy);
- UI_view2d_region_to_view(&ar->v2d, event->x - xmin, event->y - ymin, &fx, &fy);
-
- delta[0] = fx - startfx;
- delta[1] = fy - startfy;
- RNA_float_set_array(op->ptr, "delta", delta);
-
- copy_v2_v2(brush->clone.offset, cmv->startoffset);
-
- grab_clone_apply(C, op);
- break;
- }
-
- return OPERATOR_RUNNING_MODAL;
+ Brush *brush = image_paint_brush(C);
+ ARegion *ar = CTX_wm_region(C);
+ GrabClone *cmv = op->customdata;
+ float startfx, startfy, fx, fy, delta[2];
+ int xmin = ar->winrct.xmin, ymin = ar->winrct.ymin;
+
+ switch (event->type) {
+ case LEFTMOUSE:
+ case MIDDLEMOUSE:
+ case RIGHTMOUSE: // XXX hardcoded
+ MEM_freeN(op->customdata);
+ return OPERATOR_FINISHED;
+ case MOUSEMOVE:
+ /* mouse moved, so move the clone image */
+ UI_view2d_region_to_view(
+ &ar->v2d, cmv->startx - xmin, cmv->starty - ymin, &startfx, &startfy);
+ UI_view2d_region_to_view(&ar->v2d, event->x - xmin, event->y - ymin, &fx, &fy);
+
+ delta[0] = fx - startfx;
+ delta[1] = fy - startfy;
+ RNA_float_set_array(op->ptr, "delta", delta);
+
+ copy_v2_v2(brush->clone.offset, cmv->startoffset);
+
+ grab_clone_apply(C, op);
+ break;
+ }
+
+ return OPERATOR_RUNNING_MODAL;
}
static void grab_clone_cancel(bContext *UNUSED(C), wmOperator *op)
{
- MEM_freeN(op->customdata);
+ MEM_freeN(op->customdata);
}
void PAINT_OT_grab_clone(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Grab Clone";
- ot->idname = "PAINT_OT_grab_clone";
- ot->description = "Move the clone source image";
-
- /* api callbacks */
- ot->exec = grab_clone_exec;
- ot->invoke = grab_clone_invoke;
- ot->modal = grab_clone_modal;
- ot->cancel = grab_clone_cancel;
- ot->poll = image_paint_2d_clone_poll;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING;
-
- /* properties */
- RNA_def_float_vector(ot->srna, "delta", 2, NULL, -FLT_MAX, FLT_MAX, "Delta", "Delta offset of clone image in 0.0..1.0 coordinates", -1.0f, 1.0f);
+ /* identifiers */
+ ot->name = "Grab Clone";
+ ot->idname = "PAINT_OT_grab_clone";
+ ot->description = "Move the clone source image";
+
+ /* api callbacks */
+ ot->exec = grab_clone_exec;
+ ot->invoke = grab_clone_invoke;
+ ot->modal = grab_clone_modal;
+ ot->cancel = grab_clone_cancel;
+ ot->poll = image_paint_2d_clone_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING;
+
+ /* properties */
+ RNA_def_float_vector(ot->srna,
+ "delta",
+ 2,
+ NULL,
+ -FLT_MAX,
+ FLT_MAX,
+ "Delta",
+ "Delta offset of clone image in 0.0..1.0 coordinates",
+ -1.0f,
+ 1.0f);
}
/******************** sample color operator ********************/
typedef struct {
- bool show_cursor;
- short event_type;
- float initcolor[3];
- bool sample_palette;
-} SampleColorData;
-
+ bool show_cursor;
+ short event_type;
+ float initcolor[3];
+ bool sample_palette;
+} SampleColorData;
static void sample_color_update_header(SampleColorData *data, bContext *C)
{
- char msg[UI_MAX_DRAW_STR];
- ScrArea *sa = CTX_wm_area(C);
-
- if (sa) {
- BLI_snprintf(
- msg, sizeof(msg),
- IFACE_("Sample color for %s"),
- !data->sample_palette ?
- IFACE_("Brush. Use Left Click to sample for palette instead") :
- IFACE_("Palette. Use Left Click to sample more colors"));
- ED_workspace_status_text(C, msg);
- }
+ char msg[UI_MAX_DRAW_STR];
+ ScrArea *sa = CTX_wm_area(C);
+
+ if (sa) {
+ BLI_snprintf(msg,
+ sizeof(msg),
+ IFACE_("Sample color for %s"),
+ !data->sample_palette ?
+ IFACE_("Brush. Use Left Click to sample for palette instead") :
+ IFACE_("Palette. Use Left Click to sample more colors"));
+ ED_workspace_status_text(C, msg);
+ }
}
static int sample_color_exec(bContext *C, wmOperator *op)
{
- Paint *paint = BKE_paint_get_active_from_context(C);
- Brush *brush = BKE_paint_brush(paint);
- ePaintMode mode = BKE_paintmode_get_active_from_context(C);
- ARegion *ar = CTX_wm_region(C);
- wmWindow *win = CTX_wm_window(C);
- const bool show_cursor = ((paint->flags & PAINT_SHOW_BRUSH) != 0);
- int location[2];
- paint->flags &= ~PAINT_SHOW_BRUSH;
+ Paint *paint = BKE_paint_get_active_from_context(C);
+ Brush *brush = BKE_paint_brush(paint);
+ ePaintMode mode = BKE_paintmode_get_active_from_context(C);
+ ARegion *ar = CTX_wm_region(C);
+ wmWindow *win = CTX_wm_window(C);
+ const bool show_cursor = ((paint->flags & PAINT_SHOW_BRUSH) != 0);
+ int location[2];
+ paint->flags &= ~PAINT_SHOW_BRUSH;
- /* force redraw without cursor */
- WM_paint_cursor_tag_redraw(win, ar);
- WM_redraw_windows(C);
+ /* force redraw without cursor */
+ WM_paint_cursor_tag_redraw(win, ar);
+ WM_redraw_windows(C);
- RNA_int_get_array(op->ptr, "location", location);
- const bool use_palette = RNA_boolean_get(op->ptr, "palette");
- const bool use_sample_texture = (mode == PAINT_MODE_TEXTURE_3D) && !RNA_boolean_get(op->ptr, "merged");
+ RNA_int_get_array(op->ptr, "location", location);
+ const bool use_palette = RNA_boolean_get(op->ptr, "palette");
+ const bool use_sample_texture = (mode == PAINT_MODE_TEXTURE_3D) &&
+ !RNA_boolean_get(op->ptr, "merged");
- paint_sample_color(C, ar, location[0], location[1], use_sample_texture, use_palette);
+ paint_sample_color(C, ar, location[0], location[1], use_sample_texture, use_palette);
- if (show_cursor) {
- paint->flags |= PAINT_SHOW_BRUSH;
- }
+ if (show_cursor) {
+ paint->flags |= PAINT_SHOW_BRUSH;
+ }
- WM_event_add_notifier(C, NC_BRUSH | NA_EDITED, brush);
+ WM_event_add_notifier(C, NC_BRUSH | NA_EDITED, brush);
- return OPERATOR_FINISHED;
+ return OPERATOR_FINISHED;
}
static int sample_color_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
- Scene *scene = CTX_data_scene(C);
- Paint *paint = BKE_paint_get_active_from_context(C);
- Brush *brush = BKE_paint_brush(paint);
- SampleColorData *data = MEM_mallocN(sizeof(SampleColorData), "sample color custom data");
- ARegion *ar = CTX_wm_region(C);
- wmWindow *win = CTX_wm_window(C);
+ Scene *scene = CTX_data_scene(C);
+ Paint *paint = BKE_paint_get_active_from_context(C);
+ Brush *brush = BKE_paint_brush(paint);
+ SampleColorData *data = MEM_mallocN(sizeof(SampleColorData), "sample color custom data");
+ ARegion *ar = CTX_wm_region(C);
+ wmWindow *win = CTX_wm_window(C);
- data->event_type = event->type;
- data->show_cursor = ((paint->flags & PAINT_SHOW_BRUSH) != 0);
- copy_v3_v3(data->initcolor, BKE_brush_color_get(scene, brush));
- data->sample_palette = false;
- op->customdata = data;
- paint->flags &= ~PAINT_SHOW_BRUSH;
+ data->event_type = event->type;
+ data->show_cursor = ((paint->flags & PAINT_SHOW_BRUSH) != 0);
+ copy_v3_v3(data->initcolor, BKE_brush_color_get(scene, brush));
+ data->sample_palette = false;
+ op->customdata = data;
+ paint->flags &= ~PAINT_SHOW_BRUSH;
- sample_color_update_header(data, C);
+ sample_color_update_header(data, C);
- WM_event_add_modal_handler(C, op);
+ WM_event_add_modal_handler(C, op);
- /* force redraw without cursor */
- WM_paint_cursor_tag_redraw(win, ar);
- WM_redraw_windows(C);
+ /* force redraw without cursor */
+ WM_paint_cursor_tag_redraw(win, ar);
+ WM_redraw_windows(C);
- RNA_int_set_array(op->ptr, "location", event->mval);
+ RNA_int_set_array(op->ptr, "location", event->mval);
- ePaintMode mode = BKE_paintmode_get_active_from_context(C);
- const bool use_sample_texture = (mode == PAINT_MODE_TEXTURE_3D) && !RNA_boolean_get(op->ptr, "merged");
+ ePaintMode mode = BKE_paintmode_get_active_from_context(C);
+ const bool use_sample_texture = (mode == PAINT_MODE_TEXTURE_3D) &&
+ !RNA_boolean_get(op->ptr, "merged");
- paint_sample_color(C, ar, event->mval[0], event->mval[1], use_sample_texture, false);
- WM_cursor_modal_set(win, BC_EYEDROPPER_CURSOR);
+ paint_sample_color(C, ar, event->mval[0], event->mval[1], use_sample_texture, false);
+ WM_cursor_modal_set(win, BC_EYEDROPPER_CURSOR);
- WM_event_add_notifier(C, NC_BRUSH | NA_EDITED, brush);
+ WM_event_add_notifier(C, NC_BRUSH | NA_EDITED, brush);
- return OPERATOR_RUNNING_MODAL;
+ return OPERATOR_RUNNING_MODAL;
}
static int sample_color_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
- Scene *scene = CTX_data_scene(C);
- SampleColorData *data = op->customdata;
- Paint *paint = BKE_paint_get_active_from_context(C);
- Brush *brush = BKE_paint_brush(paint);
-
- if ((event->type == data->event_type) && (event->val == KM_RELEASE)) {
- if (data->show_cursor) {
- paint->flags |= PAINT_SHOW_BRUSH;
- }
-
- if (data->sample_palette) {
- BKE_brush_color_set(scene, brush, data->initcolor);
- RNA_boolean_set(op->ptr, "palette", true);
- }
- WM_cursor_modal_restore(CTX_wm_window(C));
- MEM_freeN(data);
- ED_workspace_status_text(C, NULL);
-
- return OPERATOR_FINISHED;
- }
-
- ePaintMode mode = BKE_paintmode_get_active_from_context(C);
- const bool use_sample_texture = (mode == PAINT_MODE_TEXTURE_3D) && !RNA_boolean_get(op->ptr, "merged");
-
- switch (event->type) {
- case MOUSEMOVE:
- {
- ARegion *ar = CTX_wm_region(C);
- RNA_int_set_array(op->ptr, "location", event->mval);
- paint_sample_color(C, ar, event->mval[0], event->mval[1], use_sample_texture, false);
- WM_event_add_notifier(C, NC_BRUSH | NA_EDITED, brush);
- break;
- }
-
- case LEFTMOUSE:
- if (event->val == KM_PRESS) {
- ARegion *ar = CTX_wm_region(C);
- RNA_int_set_array(op->ptr, "location", event->mval);
- paint_sample_color(C, ar, event->mval[0], event->mval[1], use_sample_texture, true);
- if (!data->sample_palette) {
- data->sample_palette = true;
- sample_color_update_header(data, C);
- }
- WM_event_add_notifier(C, NC_BRUSH | NA_EDITED, brush);
- }
- break;
- }
-
- return OPERATOR_RUNNING_MODAL;
+ Scene *scene = CTX_data_scene(C);
+ SampleColorData *data = op->customdata;
+ Paint *paint = BKE_paint_get_active_from_context(C);
+ Brush *brush = BKE_paint_brush(paint);
+
+ if ((event->type == data->event_type) && (event->val == KM_RELEASE)) {
+ if (data->show_cursor) {
+ paint->flags |= PAINT_SHOW_BRUSH;
+ }
+
+ if (data->sample_palette) {
+ BKE_brush_color_set(scene, brush, data->initcolor);
+ RNA_boolean_set(op->ptr, "palette", true);
+ }
+ WM_cursor_modal_restore(CTX_wm_window(C));
+ MEM_freeN(data);
+ ED_workspace_status_text(C, NULL);
+
+ return OPERATOR_FINISHED;
+ }
+
+ ePaintMode mode = BKE_paintmode_get_active_from_context(C);
+ const bool use_sample_texture = (mode == PAINT_MODE_TEXTURE_3D) &&
+ !RNA_boolean_get(op->ptr, "merged");
+
+ switch (event->type) {
+ case MOUSEMOVE: {
+ ARegion *ar = CTX_wm_region(C);
+ RNA_int_set_array(op->ptr, "location", event->mval);
+ paint_sample_color(C, ar, event->mval[0], event->mval[1], use_sample_texture, false);
+ WM_event_add_notifier(C, NC_BRUSH | NA_EDITED, brush);
+ break;
+ }
+
+ case LEFTMOUSE:
+ if (event->val == KM_PRESS) {
+ ARegion *ar = CTX_wm_region(C);
+ RNA_int_set_array(op->ptr, "location", event->mval);
+ paint_sample_color(C, ar, event->mval[0], event->mval[1], use_sample_texture, true);
+ if (!data->sample_palette) {
+ data->sample_palette = true;
+ sample_color_update_header(data, C);
+ }
+ WM_event_add_notifier(C, NC_BRUSH | NA_EDITED, brush);
+ }
+ break;
+ }
+
+ return OPERATOR_RUNNING_MODAL;
}
static bool sample_color_poll(bContext *C)
{
- return (image_paint_poll_ignore_tool(C) || vertex_paint_poll_ignore_tool(C));
+ return (image_paint_poll_ignore_tool(C) || vertex_paint_poll_ignore_tool(C));
}
void PAINT_OT_sample_color(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Sample Color";
- ot->idname = "PAINT_OT_sample_color";
- ot->description = "Use the mouse to sample a color in the image";
+ /* identifiers */
+ ot->name = "Sample Color";
+ ot->idname = "PAINT_OT_sample_color";
+ ot->description = "Use the mouse to sample a color in the image";
- /* api callbacks */
- ot->exec = sample_color_exec;
- ot->invoke = sample_color_invoke;
- ot->modal = sample_color_modal;
- ot->poll = sample_color_poll;
+ /* api callbacks */
+ ot->exec = sample_color_exec;
+ ot->invoke = sample_color_invoke;
+ ot->modal = sample_color_modal;
+ ot->poll = sample_color_poll;
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- /* properties */
- PropertyRNA *prop;
+ /* properties */
+ PropertyRNA *prop;
- prop = RNA_def_int_vector(ot->srna, "location", 2, NULL, 0, INT_MAX, "Location", "", 0, 16384);
- RNA_def_property_flag(prop, PROP_SKIP_SAVE | PROP_HIDDEN);
+ prop = RNA_def_int_vector(ot->srna, "location", 2, NULL, 0, INT_MAX, "Location", "", 0, 16384);
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE | PROP_HIDDEN);
- RNA_def_boolean(ot->srna, "merged", 0, "Sample Merged", "Sample the output display color");
- RNA_def_boolean(ot->srna, "palette", 0, "Add to Palette", "");
+ RNA_def_boolean(ot->srna, "merged", 0, "Sample Merged", "Sample the output display color");
+ RNA_def_boolean(ot->srna, "palette", 0, "Add to Palette", "");
}
/******************** texture paint toggle operator ********************/
static bool texture_paint_toggle_poll(bContext *C)
{
- Object *ob = CTX_data_active_object(C);
- if (ob == NULL || ob->type != OB_MESH)
- return 0;
- if (!ob->data || ID_IS_LINKED(ob->data))
- return 0;
- if (CTX_data_edit_object(C))
- return 0;
-
- return 1;
+ Object *ob = CTX_data_active_object(C);
+ if (ob == NULL || ob->type != OB_MESH)
+ return 0;
+ if (!ob->data || ID_IS_LINKED(ob->data))
+ return 0;
+ if (CTX_data_edit_object(C))
+ return 0;
+
+ return 1;
}
static int texture_paint_toggle_exec(bContext *C, wmOperator *op)
{
- struct wmMsgBus *mbus = CTX_wm_message_bus(C);
- Main *bmain = CTX_data_main(C);
- Scene *scene = CTX_data_scene(C);
- Object *ob = CTX_data_active_object(C);
- const int mode_flag = OB_MODE_TEXTURE_PAINT;
- const bool is_mode_set = (ob->mode & mode_flag) != 0;
-
- if (!is_mode_set) {
- if (!ED_object_mode_compat_set(C, ob, mode_flag, op->reports)) {
- return OPERATOR_CANCELLED;
- }
- }
-
- if (ob->mode & mode_flag) {
- ob->mode &= ~mode_flag;
-
- if (U.glreslimit != 0)
- GPU_free_images(bmain);
- GPU_paint_set_mipmap(bmain, 1);
-
- toggle_paint_cursor(C, 0);
- }
- else {
- bScreen *sc;
- Image *ima = NULL;
- ImagePaintSettings *imapaint = &scene->toolsettings->imapaint;
-
- /* This has to stay here to regenerate the texture paint
- * cache in case we are loading a file */
- BKE_texpaint_slots_refresh_object(scene, ob);
-
- BKE_paint_proj_mesh_data_check(scene, ob, NULL, NULL, NULL, NULL);
-
- /* entering paint mode also sets image to editors */
- if (imapaint->mode == IMAGEPAINT_MODE_MATERIAL) {
- /* set the current material active paint slot on image editor */
- Material *ma = give_current_material(ob, ob->actcol);
-
- if (ma && ma->texpaintslot)
- ima = ma->texpaintslot[ma->paint_active_slot].ima;
- }
- else if (imapaint->mode == IMAGEPAINT_MODE_IMAGE) {
- ima = imapaint->canvas;
- }
-
- if (ima) {
- for (sc = bmain->screens.first; sc; sc = sc->id.next) {
- ScrArea *sa;
- for (sa = sc->areabase.first; sa; sa = sa->next) {
- SpaceLink *sl;
- for (sl = sa->spacedata.first; sl; sl = sl->next) {
- if (sl->spacetype == SPACE_IMAGE) {
- SpaceImage *sima = (SpaceImage *)sl;
-
- if (!sima->pin) {
- Object *obedit = CTX_data_edit_object(C);
- ED_space_image_set(bmain, sima, obedit, ima, true);
- }
- }
- }
- }
- }
- }
-
- ob->mode |= mode_flag;
-
- BKE_paint_init(bmain, scene, PAINT_MODE_TEXTURE_3D, PAINT_CURSOR_TEXTURE_PAINT);
-
- BKE_paint_toolslots_brush_validate(bmain, &imapaint->paint);
-
- if (U.glreslimit != 0)
- GPU_free_images(bmain);
- GPU_paint_set_mipmap(bmain, 0);
-
- toggle_paint_cursor(C, 1);
- }
-
- Mesh *me = BKE_mesh_from_object(ob);
- BLI_assert(me != NULL);
- DEG_id_tag_update(&me->id, ID_RECALC_COPY_ON_WRITE);
-
- WM_event_add_notifier(C, NC_SCENE | ND_MODE, scene);
-
- WM_msg_publish_rna_prop(mbus, &ob->id, ob, Object, mode);
-
- WM_toolsystem_update_from_context_view3d(C);
-
- return OPERATOR_FINISHED;
+ struct wmMsgBus *mbus = CTX_wm_message_bus(C);
+ Main *bmain = CTX_data_main(C);
+ Scene *scene = CTX_data_scene(C);
+ Object *ob = CTX_data_active_object(C);
+ const int mode_flag = OB_MODE_TEXTURE_PAINT;
+ const bool is_mode_set = (ob->mode & mode_flag) != 0;
+
+ if (!is_mode_set) {
+ if (!ED_object_mode_compat_set(C, ob, mode_flag, op->reports)) {
+ return OPERATOR_CANCELLED;
+ }
+ }
+
+ if (ob->mode & mode_flag) {
+ ob->mode &= ~mode_flag;
+
+ if (U.glreslimit != 0)
+ GPU_free_images(bmain);
+ GPU_paint_set_mipmap(bmain, 1);
+
+ toggle_paint_cursor(C, 0);
+ }
+ else {
+ bScreen *sc;
+ Image *ima = NULL;
+ ImagePaintSettings *imapaint = &scene->toolsettings->imapaint;
+
+ /* This has to stay here to regenerate the texture paint
+ * cache in case we are loading a file */
+ BKE_texpaint_slots_refresh_object(scene, ob);
+
+ BKE_paint_proj_mesh_data_check(scene, ob, NULL, NULL, NULL, NULL);
+
+ /* entering paint mode also sets image to editors */
+ if (imapaint->mode == IMAGEPAINT_MODE_MATERIAL) {
+ /* set the current material active paint slot on image editor */
+ Material *ma = give_current_material(ob, ob->actcol);
+
+ if (ma && ma->texpaintslot)
+ ima = ma->texpaintslot[ma->paint_active_slot].ima;
+ }
+ else if (imapaint->mode == IMAGEPAINT_MODE_IMAGE) {
+ ima = imapaint->canvas;
+ }
+
+ if (ima) {
+ for (sc = bmain->screens.first; sc; sc = sc->id.next) {
+ ScrArea *sa;
+ for (sa = sc->areabase.first; sa; sa = sa->next) {
+ SpaceLink *sl;
+ for (sl = sa->spacedata.first; sl; sl = sl->next) {
+ if (sl->spacetype == SPACE_IMAGE) {
+ SpaceImage *sima = (SpaceImage *)sl;
+
+ if (!sima->pin) {
+ Object *obedit = CTX_data_edit_object(C);
+ ED_space_image_set(bmain, sima, obedit, ima, true);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ ob->mode |= mode_flag;
+
+ BKE_paint_init(bmain, scene, PAINT_MODE_TEXTURE_3D, PAINT_CURSOR_TEXTURE_PAINT);
+
+ BKE_paint_toolslots_brush_validate(bmain, &imapaint->paint);
+
+ if (U.glreslimit != 0)
+ GPU_free_images(bmain);
+ GPU_paint_set_mipmap(bmain, 0);
+
+ toggle_paint_cursor(C, 1);
+ }
+
+ Mesh *me = BKE_mesh_from_object(ob);
+ BLI_assert(me != NULL);
+ DEG_id_tag_update(&me->id, ID_RECALC_COPY_ON_WRITE);
+
+ WM_event_add_notifier(C, NC_SCENE | ND_MODE, scene);
+
+ WM_msg_publish_rna_prop(mbus, &ob->id, ob, Object, mode);
+
+ WM_toolsystem_update_from_context_view3d(C);
+
+ return OPERATOR_FINISHED;
}
void PAINT_OT_texture_paint_toggle(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Texture Paint Toggle";
- ot->idname = "PAINT_OT_texture_paint_toggle";
- ot->description = "Toggle texture paint mode in 3D view";
+ /* identifiers */
+ ot->name = "Texture Paint Toggle";
+ ot->idname = "PAINT_OT_texture_paint_toggle";
+ ot->description = "Toggle texture paint mode in 3D view";
- /* api callbacks */
- ot->exec = texture_paint_toggle_exec;
- ot->poll = texture_paint_toggle_poll;
+ /* api callbacks */
+ ot->exec = texture_paint_toggle_exec;
+ ot->poll = texture_paint_toggle_poll;
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_USE_EVAL_DATA;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_USE_EVAL_DATA;
}
-
static int brush_colors_flip_exec(bContext *C, wmOperator *UNUSED(op))
{
- Scene *scene = CTX_data_scene(C);
- UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
-
- ViewLayer *view_layer = CTX_data_view_layer(C);
- Paint *paint = BKE_paint_get_active(scene, view_layer);
- Brush *br = BKE_paint_brush(paint);
-
- if (ups->flag & UNIFIED_PAINT_COLOR) {
- swap_v3_v3(ups->rgb, ups->secondary_rgb);
- }
- else if (br) {
- swap_v3_v3(br->rgb, br->secondary_rgb);
- }
- WM_event_add_notifier(C, NC_BRUSH | NA_EDITED, br);
-
- return OPERATOR_FINISHED;
+ Scene *scene = CTX_data_scene(C);
+ UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
+
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Paint *paint = BKE_paint_get_active(scene, view_layer);
+ Brush *br = BKE_paint_brush(paint);
+
+ if (ups->flag & UNIFIED_PAINT_COLOR) {
+ swap_v3_v3(ups->rgb, ups->secondary_rgb);
+ }
+ else if (br) {
+ swap_v3_v3(br->rgb, br->secondary_rgb);
+ }
+ WM_event_add_notifier(C, NC_BRUSH | NA_EDITED, br);
+
+ return OPERATOR_FINISHED;
}
static bool brush_colors_flip_poll(bContext *C)
{
- if (image_paint_poll(C)) {
- Brush *br = image_paint_brush(C);
- if (ELEM(br->imagepaint_tool, PAINT_TOOL_DRAW, PAINT_TOOL_FILL))
- return true;
- }
- else {
- Object *ob = CTX_data_active_object(C);
- if (ob != NULL) {
- if (ob->mode & (OB_MODE_VERTEX_PAINT | OB_MODE_TEXTURE_PAINT)) {
- return true;
- }
- }
- }
- return false;
+ if (image_paint_poll(C)) {
+ Brush *br = image_paint_brush(C);
+ if (ELEM(br->imagepaint_tool, PAINT_TOOL_DRAW, PAINT_TOOL_FILL))
+ return true;
+ }
+ else {
+ Object *ob = CTX_data_active_object(C);
+ if (ob != NULL) {
+ if (ob->mode & (OB_MODE_VERTEX_PAINT | OB_MODE_TEXTURE_PAINT)) {
+ return true;
+ }
+ }
+ }
+ return false;
}
void PAINT_OT_brush_colors_flip(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Brush Colors Flip";
- ot->idname = "PAINT_OT_brush_colors_flip";
- ot->description = "Toggle foreground and background brush colors";
+ /* identifiers */
+ ot->name = "Brush Colors Flip";
+ ot->idname = "PAINT_OT_brush_colors_flip";
+ ot->description = "Toggle foreground and background brush colors";
- /* api callbacks */
- ot->exec = brush_colors_flip_exec;
- ot->poll = brush_colors_flip_poll;
+ /* api callbacks */
+ ot->exec = brush_colors_flip_exec;
+ ot->poll = brush_colors_flip_poll;
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-
void ED_imapaint_bucket_fill(struct bContext *C, float color[3], wmOperator *op)
{
- wmWindowManager *wm = CTX_wm_manager(C);
- SpaceImage *sima = CTX_wm_space_image(C);
- Image *ima = sima->image;
+ wmWindowManager *wm = CTX_wm_manager(C);
+ SpaceImage *sima = CTX_wm_space_image(C);
+ Image *ima = sima->image;
- BKE_undosys_step_push_init_with_type(wm->undo_stack, C, op->type->name, BKE_UNDOSYS_TYPE_IMAGE);
+ BKE_undosys_step_push_init_with_type(wm->undo_stack, C, op->type->name, BKE_UNDOSYS_TYPE_IMAGE);
- ED_image_undo_push_begin(op->type->name, PAINT_MODE_TEXTURE_2D);
+ ED_image_undo_push_begin(op->type->name, PAINT_MODE_TEXTURE_2D);
- paint_2d_bucket_fill(C, color, NULL, NULL, NULL);
+ paint_2d_bucket_fill(C, color, NULL, NULL, NULL);
- BKE_undosys_step_push(wm->undo_stack, C, op->type->name);
+ BKE_undosys_step_push(wm->undo_stack, C, op->type->name);
- DEG_id_tag_update(&ima->id, 0);
+ DEG_id_tag_update(&ima->id, 0);
}
-
static bool texture_paint_poll(bContext *C)
{
- if (texture_paint_toggle_poll(C))
- if (CTX_data_active_object(C)->mode & OB_MODE_TEXTURE_PAINT)
- return 1;
+ if (texture_paint_toggle_poll(C))
+ if (CTX_data_active_object(C)->mode & OB_MODE_TEXTURE_PAINT)
+ return 1;
- return 0;
+ return 0;
}
bool image_texture_paint_poll(bContext *C)
{
- return (texture_paint_poll(C) || image_paint_poll(C));
+ return (texture_paint_poll(C) || image_paint_poll(C));
}
bool facemask_paint_poll(bContext *C)
{
- return BKE_paint_select_face_test(CTX_data_active_object(C));
+ return BKE_paint_select_face_test(CTX_data_active_object(C));
}
bool vert_paint_poll(bContext *C)
{
- return BKE_paint_select_vert_test(CTX_data_active_object(C));
+ return BKE_paint_select_vert_test(CTX_data_active_object(C));
}
bool mask_paint_poll(bContext *C)
{
- return BKE_paint_select_elem_test(CTX_data_active_object(C));
+ return BKE_paint_select_elem_test(CTX_data_active_object(C));
}
diff --git a/source/blender/editors/sculpt_paint/paint_image_2d.c b/source/blender/editors/sculpt_paint/paint_image_2d.c
index cad75efbf56..5390f18304a 100644
--- a/source/blender/editors/sculpt_paint/paint_image_2d.c
+++ b/source/blender/editors/sculpt_paint/paint_image_2d.c
@@ -30,7 +30,6 @@
#include "DNA_space_types.h"
#include "DNA_object_types.h"
-
#include "BLI_math_color_blend.h"
#include "BLI_stack.h"
#include "BLI_bitmap.h"
@@ -57,7 +56,6 @@
#include "UI_view2d.h"
-
#include "GPU_draw.h"
#include "paint_intern.h"
@@ -67,1677 +65,1854 @@
/* Defines and Structs */
typedef struct BrushPainterCache {
- bool use_float; /* need float imbuf? */
- bool use_color_correction; /* use color correction for float */
- bool invert;
-
- bool is_texbrush;
- bool is_maskbrush;
-
- int lastdiameter;
- float last_tex_rotation;
- float last_mask_rotation;
- float last_pressure;
-
- ImBuf *ibuf;
- ImBuf *texibuf;
- unsigned short *curve_mask;
- unsigned short *tex_mask;
- unsigned short *tex_mask_old;
- unsigned int tex_mask_old_w;
- unsigned int tex_mask_old_h;
+ bool use_float; /* need float imbuf? */
+ bool use_color_correction; /* use color correction for float */
+ bool invert;
+
+ bool is_texbrush;
+ bool is_maskbrush;
+
+ int lastdiameter;
+ float last_tex_rotation;
+ float last_mask_rotation;
+ float last_pressure;
+
+ ImBuf *ibuf;
+ ImBuf *texibuf;
+ unsigned short *curve_mask;
+ unsigned short *tex_mask;
+ unsigned short *tex_mask_old;
+ unsigned int tex_mask_old_w;
+ unsigned int tex_mask_old_h;
} BrushPainterCache;
typedef struct BrushPainter {
- Scene *scene;
- Brush *brush;
+ Scene *scene;
+ Brush *brush;
- float lastpaintpos[2]; /* position of last paint op */
- float startpaintpos[2]; /* position of first paint */
+ float lastpaintpos[2]; /* position of last paint op */
+ float startpaintpos[2]; /* position of first paint */
- short firsttouch; /* first paint op */
+ short firsttouch; /* first paint op */
- struct ImagePool *pool; /* image pool */
- rctf tex_mapping; /* texture coordinate mapping */
- rctf mask_mapping; /* mask texture coordinate mapping */
+ struct ImagePool *pool; /* image pool */
+ rctf tex_mapping; /* texture coordinate mapping */
+ rctf mask_mapping; /* mask texture coordinate mapping */
- BrushPainterCache cache;
+ BrushPainterCache cache;
} BrushPainter;
typedef struct ImagePaintRegion {
- int destx, desty;
- int srcx, srcy;
- int width, height;
+ int destx, desty;
+ int srcx, srcy;
+ int width, height;
} ImagePaintRegion;
typedef struct ImagePaintState {
- BrushPainter *painter;
- SpaceImage *sima;
- View2D *v2d;
- Scene *scene;
- bScreen *screen;
- struct ImagePool *image_pool;
-
- Brush *brush;
- short tool, blend;
- Image *image;
- ImBuf *canvas;
- ImBuf *clonecanvas;
- const char *warnpackedfile;
- const char *warnmultifile;
-
- bool do_masking;
-
- /* viewport texture paint only, but _not_ project paint */
- Object *ob;
- int faceindex;
- float uv[2];
- int do_facesel;
- int symmetry;
-
- bool need_redraw;
-
- BlurKernel *blurkernel;
+ BrushPainter *painter;
+ SpaceImage *sima;
+ View2D *v2d;
+ Scene *scene;
+ bScreen *screen;
+ struct ImagePool *image_pool;
+
+ Brush *brush;
+ short tool, blend;
+ Image *image;
+ ImBuf *canvas;
+ ImBuf *clonecanvas;
+ const char *warnpackedfile;
+ const char *warnmultifile;
+
+ bool do_masking;
+
+ /* viewport texture paint only, but _not_ project paint */
+ Object *ob;
+ int faceindex;
+ float uv[2];
+ int do_facesel;
+ int symmetry;
+
+ bool need_redraw;
+
+ BlurKernel *blurkernel;
} ImagePaintState;
-
static BrushPainter *brush_painter_2d_new(Scene *scene, Brush *brush, bool invert)
{
- BrushPainter *painter = MEM_callocN(sizeof(BrushPainter), "BrushPainter");
+ BrushPainter *painter = MEM_callocN(sizeof(BrushPainter), "BrushPainter");
- painter->brush = brush;
- painter->scene = scene;
- painter->firsttouch = 1;
- painter->cache.lastdiameter = -1; /* force ibuf create in refresh */
- painter->cache.invert = invert;
+ painter->brush = brush;
+ painter->scene = scene;
+ painter->firsttouch = 1;
+ painter->cache.lastdiameter = -1; /* force ibuf create in refresh */
+ painter->cache.invert = invert;
- return painter;
+ return painter;
}
-
-static void brush_painter_2d_require_imbuf(BrushPainter *painter, bool use_float, bool use_color_correction)
+static void brush_painter_2d_require_imbuf(BrushPainter *painter,
+ bool use_float,
+ bool use_color_correction)
{
- Brush *brush = painter->brush;
-
- if ((painter->cache.use_float != use_float)) {
- if (painter->cache.ibuf) IMB_freeImBuf(painter->cache.ibuf);
- if (painter->cache.curve_mask) MEM_freeN(painter->cache.curve_mask);
- if (painter->cache.tex_mask) MEM_freeN(painter->cache.tex_mask);
- if (painter->cache.tex_mask_old) MEM_freeN(painter->cache.tex_mask_old);
- painter->cache.ibuf = NULL;
- painter->cache.curve_mask = NULL;
- painter->cache.tex_mask = NULL;
- painter->cache.lastdiameter = -1; /* force ibuf create in refresh */
- }
-
- painter->cache.use_float = use_float;
- painter->cache.use_color_correction = use_float && use_color_correction;
- painter->cache.is_texbrush = (brush->mtex.tex && brush->imagepaint_tool == PAINT_TOOL_DRAW) ? true : false;
- painter->cache.is_maskbrush = (brush->mask_mtex.tex) ? true : false;
+ Brush *brush = painter->brush;
+
+ if ((painter->cache.use_float != use_float)) {
+ if (painter->cache.ibuf)
+ IMB_freeImBuf(painter->cache.ibuf);
+ if (painter->cache.curve_mask)
+ MEM_freeN(painter->cache.curve_mask);
+ if (painter->cache.tex_mask)
+ MEM_freeN(painter->cache.tex_mask);
+ if (painter->cache.tex_mask_old)
+ MEM_freeN(painter->cache.tex_mask_old);
+ painter->cache.ibuf = NULL;
+ painter->cache.curve_mask = NULL;
+ painter->cache.tex_mask = NULL;
+ painter->cache.lastdiameter = -1; /* force ibuf create in refresh */
+ }
+
+ painter->cache.use_float = use_float;
+ painter->cache.use_color_correction = use_float && use_color_correction;
+ painter->cache.is_texbrush = (brush->mtex.tex && brush->imagepaint_tool == PAINT_TOOL_DRAW) ?
+ true :
+ false;
+ painter->cache.is_maskbrush = (brush->mask_mtex.tex) ? true : false;
}
static void brush_painter_2d_free(BrushPainter *painter)
{
- if (painter->cache.ibuf) IMB_freeImBuf(painter->cache.ibuf);
- if (painter->cache.texibuf) IMB_freeImBuf(painter->cache.texibuf);
- if (painter->cache.curve_mask) MEM_freeN(painter->cache.curve_mask);
- if (painter->cache.tex_mask) MEM_freeN(painter->cache.tex_mask);
- if (painter->cache.tex_mask_old) MEM_freeN(painter->cache.tex_mask_old);
- MEM_freeN(painter);
+ if (painter->cache.ibuf)
+ IMB_freeImBuf(painter->cache.ibuf);
+ if (painter->cache.texibuf)
+ IMB_freeImBuf(painter->cache.texibuf);
+ if (painter->cache.curve_mask)
+ MEM_freeN(painter->cache.curve_mask);
+ if (painter->cache.tex_mask)
+ MEM_freeN(painter->cache.tex_mask);
+ if (painter->cache.tex_mask_old)
+ MEM_freeN(painter->cache.tex_mask_old);
+ MEM_freeN(painter);
}
static void brush_imbuf_tex_co(rctf *mapping, int x, int y, float texco[3])
{
- texco[0] = mapping->xmin + x * mapping->xmax;
- texco[1] = mapping->ymin + y * mapping->ymax;
- texco[2] = 0.0f;
+ texco[0] = mapping->xmin + x * mapping->xmax;
+ texco[1] = mapping->ymin + y * mapping->ymax;
+ texco[2] = 0.0f;
}
/* create a mask with the mask texture */
static unsigned short *brush_painter_mask_ibuf_new(BrushPainter *painter, int size)
{
- Scene *scene = painter->scene;
- Brush *brush = painter->brush;
- rctf mask_mapping = painter->mask_mapping;
- struct ImagePool *pool = painter->pool;
-
- float texco[3];
- unsigned short *mask, *m;
- int x, y, thread = 0;
-
- mask = MEM_mallocN(sizeof(unsigned short) * size * size, "brush_painter_mask");
- m = mask;
-
- for (y = 0; y < size; y++) {
- for (x = 0; x < size; x++, m++) {
- float res;
- brush_imbuf_tex_co(&mask_mapping, x, y, texco);
- res = BKE_brush_sample_masktex(scene, brush, texco, thread, pool);
- *m = (unsigned short)(65535.0f * res);
- }
- }
-
- return mask;
+ Scene *scene = painter->scene;
+ Brush *brush = painter->brush;
+ rctf mask_mapping = painter->mask_mapping;
+ struct ImagePool *pool = painter->pool;
+
+ float texco[3];
+ unsigned short *mask, *m;
+ int x, y, thread = 0;
+
+ mask = MEM_mallocN(sizeof(unsigned short) * size * size, "brush_painter_mask");
+ m = mask;
+
+ for (y = 0; y < size; y++) {
+ for (x = 0; x < size; x++, m++) {
+ float res;
+ brush_imbuf_tex_co(&mask_mapping, x, y, texco);
+ res = BKE_brush_sample_masktex(scene, brush, texco, thread, pool);
+ *m = (unsigned short)(65535.0f * res);
+ }
+ }
+
+ return mask;
}
/* update rectangular section of the brush image */
-static void brush_painter_mask_imbuf_update(
- BrushPainter *painter, unsigned short *tex_mask_old,
- int origx, int origy, int w, int h, int xt, int yt, int diameter)
+static void brush_painter_mask_imbuf_update(BrushPainter *painter,
+ unsigned short *tex_mask_old,
+ int origx,
+ int origy,
+ int w,
+ int h,
+ int xt,
+ int yt,
+ int diameter)
{
- Scene *scene = painter->scene;
- Brush *brush = painter->brush;
- rctf tex_mapping = painter->mask_mapping;
- struct ImagePool *pool = painter->pool;
- unsigned short res;
-
- bool use_texture_old = (tex_mask_old != NULL);
-
- int x, y, thread = 0;
-
- unsigned short *tex_mask = painter->cache.tex_mask;
- unsigned short *tex_mask_cur = painter->cache.tex_mask_old;
-
- /* fill pixels */
- for (y = origy; y < h; y++) {
- for (x = origx; x < w; x++) {
- /* sample texture */
- float texco[3];
-
- /* handle byte pixel */
- unsigned short *b = tex_mask + (y * diameter + x);
- unsigned short *t = tex_mask_cur + (y * diameter + x);
-
- if (!use_texture_old) {
- brush_imbuf_tex_co(&tex_mapping, x, y, texco);
- res = (unsigned short)(65535.0f * BKE_brush_sample_masktex(scene, brush, texco, thread, pool));
- }
-
- /* read from old texture buffer */
- if (use_texture_old) {
- res = *(tex_mask_old + ((y - origy + yt) * painter->cache.tex_mask_old_w + (x - origx + xt)));
- }
-
- /* write to new texture mask */
- *t = res;
- /* write to mask image buffer */
- *b = res;
- }
- }
+ Scene *scene = painter->scene;
+ Brush *brush = painter->brush;
+ rctf tex_mapping = painter->mask_mapping;
+ struct ImagePool *pool = painter->pool;
+ unsigned short res;
+
+ bool use_texture_old = (tex_mask_old != NULL);
+
+ int x, y, thread = 0;
+
+ unsigned short *tex_mask = painter->cache.tex_mask;
+ unsigned short *tex_mask_cur = painter->cache.tex_mask_old;
+
+ /* fill pixels */
+ for (y = origy; y < h; y++) {
+ for (x = origx; x < w; x++) {
+ /* sample texture */
+ float texco[3];
+
+ /* handle byte pixel */
+ unsigned short *b = tex_mask + (y * diameter + x);
+ unsigned short *t = tex_mask_cur + (y * diameter + x);
+
+ if (!use_texture_old) {
+ brush_imbuf_tex_co(&tex_mapping, x, y, texco);
+ res = (unsigned short)(65535.0f *
+ BKE_brush_sample_masktex(scene, brush, texco, thread, pool));
+ }
+
+ /* read from old texture buffer */
+ if (use_texture_old) {
+ res = *(tex_mask_old +
+ ((y - origy + yt) * painter->cache.tex_mask_old_w + (x - origx + xt)));
+ }
+
+ /* write to new texture mask */
+ *t = res;
+ /* write to mask image buffer */
+ *b = res;
+ }
+ }
}
-
/**
* Update the brush mask image by trying to reuse the cached texture result.
* This can be considerably faster for brushes that change size due to pressure or
* textures that stick to the surface where only part of the pixels are new
*/
-static void brush_painter_mask_imbuf_partial_update(BrushPainter *painter, const float pos[2], int diameter)
+static void brush_painter_mask_imbuf_partial_update(BrushPainter *painter,
+ const float pos[2],
+ int diameter)
{
- BrushPainterCache *cache = &painter->cache;
- unsigned short *tex_mask_old;
- int destx, desty, srcx, srcy, w, h, x1, y1, x2, y2;
-
- /* create brush image buffer if it didn't exist yet */
- if (!cache->tex_mask)
- cache->tex_mask = MEM_mallocN(sizeof(unsigned short) * diameter * diameter, "brush_painter_mask");
-
- /* create new texture image buffer with coordinates relative to old */
- tex_mask_old = cache->tex_mask_old;
- cache->tex_mask_old = MEM_mallocN(sizeof(unsigned short) * diameter * diameter, "brush_painter_mask");
-
- if (tex_mask_old) {
- ImBuf maskibuf;
- ImBuf maskibuf_old;
- maskibuf.x = maskibuf.y = diameter;
- maskibuf_old.x = cache->tex_mask_old_w;
- maskibuf_old.y = cache->tex_mask_old_h;
-
- srcx = srcy = 0;
- w = cache->tex_mask_old_w;
- h = cache->tex_mask_old_h;
- destx = (int)floorf(painter->lastpaintpos[0]) - (int)floorf(pos[0]) + (diameter / 2 - w / 2);
- desty = (int)floorf(painter->lastpaintpos[1]) - (int)floorf(pos[1]) + (diameter / 2 - h / 2);
-
- /* hack, use temporary rects so that clipping works */
- IMB_rectclip(&maskibuf, &maskibuf_old, &destx, &desty, &srcx, &srcy, &w, &h);
- }
- else {
- srcx = srcy = 0;
- destx = desty = 0;
- w = h = 0;
- }
-
- x1 = min_ii(destx, diameter);
- y1 = min_ii(desty, diameter);
- x2 = min_ii(destx + w, diameter);
- y2 = min_ii(desty + h, diameter);
-
- /* blend existing texture in new position */
- if ((x1 < x2) && (y1 < y2))
- brush_painter_mask_imbuf_update(painter, tex_mask_old, x1, y1, x2, y2, srcx, srcy, diameter);
-
- if (tex_mask_old)
- MEM_freeN(tex_mask_old);
-
- /* sample texture in new areas */
- if ((0 < x1) && (0 < diameter))
- brush_painter_mask_imbuf_update(painter, NULL, 0, 0, x1, diameter, 0, 0, diameter);
- if ((x2 < diameter) && (0 < diameter))
- brush_painter_mask_imbuf_update(painter, NULL, x2, 0, diameter, diameter, 0, 0, diameter);
- if ((x1 < x2) && (0 < y1))
- brush_painter_mask_imbuf_update(painter, NULL, x1, 0, x2, y1, 0, 0, diameter);
- if ((x1 < x2) && (y2 < diameter))
- brush_painter_mask_imbuf_update(painter, NULL, x1, y2, x2, diameter, 0, 0, diameter);
-
- /* through with sampling, now update sizes */
- cache->tex_mask_old_w = diameter;
- cache->tex_mask_old_h = diameter;
+ BrushPainterCache *cache = &painter->cache;
+ unsigned short *tex_mask_old;
+ int destx, desty, srcx, srcy, w, h, x1, y1, x2, y2;
+
+ /* create brush image buffer if it didn't exist yet */
+ if (!cache->tex_mask)
+ cache->tex_mask = MEM_mallocN(sizeof(unsigned short) * diameter * diameter,
+ "brush_painter_mask");
+
+ /* create new texture image buffer with coordinates relative to old */
+ tex_mask_old = cache->tex_mask_old;
+ cache->tex_mask_old = MEM_mallocN(sizeof(unsigned short) * diameter * diameter,
+ "brush_painter_mask");
+
+ if (tex_mask_old) {
+ ImBuf maskibuf;
+ ImBuf maskibuf_old;
+ maskibuf.x = maskibuf.y = diameter;
+ maskibuf_old.x = cache->tex_mask_old_w;
+ maskibuf_old.y = cache->tex_mask_old_h;
+
+ srcx = srcy = 0;
+ w = cache->tex_mask_old_w;
+ h = cache->tex_mask_old_h;
+ destx = (int)floorf(painter->lastpaintpos[0]) - (int)floorf(pos[0]) + (diameter / 2 - w / 2);
+ desty = (int)floorf(painter->lastpaintpos[1]) - (int)floorf(pos[1]) + (diameter / 2 - h / 2);
+
+ /* hack, use temporary rects so that clipping works */
+ IMB_rectclip(&maskibuf, &maskibuf_old, &destx, &desty, &srcx, &srcy, &w, &h);
+ }
+ else {
+ srcx = srcy = 0;
+ destx = desty = 0;
+ w = h = 0;
+ }
+
+ x1 = min_ii(destx, diameter);
+ y1 = min_ii(desty, diameter);
+ x2 = min_ii(destx + w, diameter);
+ y2 = min_ii(desty + h, diameter);
+
+ /* blend existing texture in new position */
+ if ((x1 < x2) && (y1 < y2))
+ brush_painter_mask_imbuf_update(painter, tex_mask_old, x1, y1, x2, y2, srcx, srcy, diameter);
+
+ if (tex_mask_old)
+ MEM_freeN(tex_mask_old);
+
+ /* sample texture in new areas */
+ if ((0 < x1) && (0 < diameter))
+ brush_painter_mask_imbuf_update(painter, NULL, 0, 0, x1, diameter, 0, 0, diameter);
+ if ((x2 < diameter) && (0 < diameter))
+ brush_painter_mask_imbuf_update(painter, NULL, x2, 0, diameter, diameter, 0, 0, diameter);
+ if ((x1 < x2) && (0 < y1))
+ brush_painter_mask_imbuf_update(painter, NULL, x1, 0, x2, y1, 0, 0, diameter);
+ if ((x1 < x2) && (y2 < diameter))
+ brush_painter_mask_imbuf_update(painter, NULL, x1, y2, x2, diameter, 0, 0, diameter);
+
+ /* through with sampling, now update sizes */
+ cache->tex_mask_old_w = diameter;
+ cache->tex_mask_old_h = diameter;
}
/* create a mask with the falloff strength */
-static unsigned short *brush_painter_curve_mask_new(BrushPainter *painter, int diameter, float radius)
+static unsigned short *brush_painter_curve_mask_new(BrushPainter *painter,
+ int diameter,
+ float radius)
{
- Brush *brush = painter->brush;
+ Brush *brush = painter->brush;
- int xoff = -radius;
- int yoff = -radius;
+ int xoff = -radius;
+ int yoff = -radius;
- unsigned short *mask, *m;
- int x, y;
+ unsigned short *mask, *m;
+ int x, y;
- mask = MEM_mallocN(sizeof(unsigned short) * diameter * diameter, "brush_painter_mask");
- m = mask;
+ mask = MEM_mallocN(sizeof(unsigned short) * diameter * diameter, "brush_painter_mask");
+ m = mask;
- for (y = 0; y < diameter; y++) {
- for (x = 0; x < diameter; x++, m++) {
- float xy[2] = {x + xoff, y + yoff};
- float len = len_v2(xy);
+ for (y = 0; y < diameter; y++) {
+ for (x = 0; x < diameter; x++, m++) {
+ float xy[2] = {x + xoff, y + yoff};
+ float len = len_v2(xy);
- *m = (unsigned short)(65535.0f * BKE_brush_curve_strength_clamped(brush, len, radius));
- }
- }
+ *m = (unsigned short)(65535.0f * BKE_brush_curve_strength_clamped(brush, len, radius));
+ }
+ }
- return mask;
+ return mask;
}
-
/* create imbuf with brush color */
-static ImBuf *brush_painter_imbuf_new(BrushPainter *painter, int size, float pressure, float distance)
+static ImBuf *brush_painter_imbuf_new(BrushPainter *painter,
+ int size,
+ float pressure,
+ float distance)
{
- Scene *scene = painter->scene;
- Brush *brush = painter->brush;
-
- const char *display_device = scene->display_settings.display_device;
- struct ColorManagedDisplay *display = IMB_colormanagement_display_get_named(display_device);
-
- rctf tex_mapping = painter->tex_mapping;
- struct ImagePool *pool = painter->pool;
-
- bool use_color_correction = painter->cache.use_color_correction;
- bool use_float = painter->cache.use_float;
- bool is_texbrush = painter->cache.is_texbrush;
-
- int x, y, thread = 0;
- float brush_rgb[3];
-
- /* allocate image buffer */
- ImBuf *ibuf = IMB_allocImBuf(size, size, 32, (use_float) ? IB_rectfloat : IB_rect);
-
- /* get brush color */
- if (brush->imagepaint_tool == PAINT_TOOL_DRAW) {
- paint_brush_color_get(scene, brush, use_color_correction, painter->cache.invert, distance, pressure, brush_rgb, display);
- }
- else {
- brush_rgb[0] = 1.0f;
- brush_rgb[1] = 1.0f;
- brush_rgb[2] = 1.0f;
- }
-
- /* fill image buffer */
- for (y = 0; y < size; y++) {
- for (x = 0; x < size; x++) {
- /* sample texture and multiply with brush color */
- float texco[3], rgba[4];
-
- if (is_texbrush) {
- brush_imbuf_tex_co(&tex_mapping, x, y, texco);
- BKE_brush_sample_tex_3d(scene, brush, texco, rgba, thread, pool);
- /* TODO(sergey): Support texture paint color space. */
- if (!use_float) {
- IMB_colormanagement_scene_linear_to_display_v3(rgba, display);
- }
- mul_v3_v3(rgba, brush_rgb);
- }
- else {
- copy_v3_v3(rgba, brush_rgb);
- rgba[3] = 1.0f;
- }
-
- if (use_float) {
- /* write to float pixel */
- float *dstf = ibuf->rect_float + (y * size + x) * 4;
- mul_v3_v3fl(dstf, rgba, rgba[3]); /* premultiply */
- dstf[3] = rgba[3];
- }
- else {
- /* write to byte pixel */
- unsigned char *dst = (unsigned char *)ibuf->rect + (y * size + x) * 4;
-
- rgb_float_to_uchar(dst, rgba);
- dst[3] = unit_float_to_uchar_clamp(rgba[3]);
- }
- }
- }
-
- return ibuf;
+ Scene *scene = painter->scene;
+ Brush *brush = painter->brush;
+
+ const char *display_device = scene->display_settings.display_device;
+ struct ColorManagedDisplay *display = IMB_colormanagement_display_get_named(display_device);
+
+ rctf tex_mapping = painter->tex_mapping;
+ struct ImagePool *pool = painter->pool;
+
+ bool use_color_correction = painter->cache.use_color_correction;
+ bool use_float = painter->cache.use_float;
+ bool is_texbrush = painter->cache.is_texbrush;
+
+ int x, y, thread = 0;
+ float brush_rgb[3];
+
+ /* allocate image buffer */
+ ImBuf *ibuf = IMB_allocImBuf(size, size, 32, (use_float) ? IB_rectfloat : IB_rect);
+
+ /* get brush color */
+ if (brush->imagepaint_tool == PAINT_TOOL_DRAW) {
+ paint_brush_color_get(scene,
+ brush,
+ use_color_correction,
+ painter->cache.invert,
+ distance,
+ pressure,
+ brush_rgb,
+ display);
+ }
+ else {
+ brush_rgb[0] = 1.0f;
+ brush_rgb[1] = 1.0f;
+ brush_rgb[2] = 1.0f;
+ }
+
+ /* fill image buffer */
+ for (y = 0; y < size; y++) {
+ for (x = 0; x < size; x++) {
+ /* sample texture and multiply with brush color */
+ float texco[3], rgba[4];
+
+ if (is_texbrush) {
+ brush_imbuf_tex_co(&tex_mapping, x, y, texco);
+ BKE_brush_sample_tex_3d(scene, brush, texco, rgba, thread, pool);
+ /* TODO(sergey): Support texture paint color space. */
+ if (!use_float) {
+ IMB_colormanagement_scene_linear_to_display_v3(rgba, display);
+ }
+ mul_v3_v3(rgba, brush_rgb);
+ }
+ else {
+ copy_v3_v3(rgba, brush_rgb);
+ rgba[3] = 1.0f;
+ }
+
+ if (use_float) {
+ /* write to float pixel */
+ float *dstf = ibuf->rect_float + (y * size + x) * 4;
+ mul_v3_v3fl(dstf, rgba, rgba[3]); /* premultiply */
+ dstf[3] = rgba[3];
+ }
+ else {
+ /* write to byte pixel */
+ unsigned char *dst = (unsigned char *)ibuf->rect + (y * size + x) * 4;
+
+ rgb_float_to_uchar(dst, rgba);
+ dst[3] = unit_float_to_uchar_clamp(rgba[3]);
+ }
+ }
+ }
+
+ return ibuf;
}
/* update rectangular section of the brush image */
static void brush_painter_imbuf_update(
- BrushPainter *painter, ImBuf *oldtexibuf,
- int origx, int origy, int w, int h, int xt, int yt)
+ BrushPainter *painter, ImBuf *oldtexibuf, int origx, int origy, int w, int h, int xt, int yt)
{
- Scene *scene = painter->scene;
- Brush *brush = painter->brush;
-
- const char *display_device = scene->display_settings.display_device;
- struct ColorManagedDisplay *display = IMB_colormanagement_display_get_named(display_device);
-
- rctf tex_mapping = painter->tex_mapping;
- struct ImagePool *pool = painter->pool;
-
- bool use_color_correction = painter->cache.use_color_correction;
- bool use_float = painter->cache.use_float;
- bool is_texbrush = painter->cache.is_texbrush;
- bool use_texture_old = (oldtexibuf != NULL);
-
- int x, y, thread = 0;
- float brush_rgb[3];
-
- ImBuf *ibuf = painter->cache.ibuf;
- ImBuf *texibuf = painter->cache.texibuf;
-
- /* get brush color */
- if (brush->imagepaint_tool == PAINT_TOOL_DRAW) {
- paint_brush_color_get(scene, brush, use_color_correction, painter->cache.invert, 0.0, 1.0, brush_rgb, display);
- }
- else {
- brush_rgb[0] = 1.0f;
- brush_rgb[1] = 1.0f;
- brush_rgb[2] = 1.0f;
- }
-
- /* fill pixels */
- for (y = origy; y < h; y++) {
- for (x = origx; x < w; x++) {
- /* sample texture and multiply with brush color */
- float texco[3], rgba[4];
-
- if (!use_texture_old) {
- if (is_texbrush) {
- brush_imbuf_tex_co(&tex_mapping, x, y, texco);
- BKE_brush_sample_tex_3d(scene, brush, texco, rgba, thread, pool);
- /* TODO(sergey): Support texture paint color space. */
- if (!use_float) {
- IMB_colormanagement_scene_linear_to_display_v3(rgba, display);
- }
- mul_v3_v3(rgba, brush_rgb);
- }
- else {
- copy_v3_v3(rgba, brush_rgb);
- rgba[3] = 1.0f;
- }
- }
-
- if (use_float) {
- /* handle float pixel */
- float *bf = ibuf->rect_float + (y * ibuf->x + x) * 4;
- float *tf = texibuf->rect_float + (y * texibuf->x + x) * 4;
-
- /* read from old texture buffer */
- if (use_texture_old) {
- const float *otf = oldtexibuf->rect_float + ((y - origy + yt) * oldtexibuf->x + (x - origx + xt)) * 4;
- copy_v4_v4(rgba, otf);
- }
-
- /* write to new texture buffer */
- copy_v4_v4(tf, rgba);
-
- /* output premultiplied float image, mf was already premultiplied */
- mul_v3_v3fl(bf, rgba, rgba[3]);
- bf[3] = rgba[3];
- }
- else {
- unsigned char crgba[4];
-
- /* handle byte pixel */
- unsigned char *b = (unsigned char *)ibuf->rect + (y * ibuf->x + x) * 4;
- unsigned char *t = (unsigned char *)texibuf->rect + (y * texibuf->x + x) * 4;
-
- /* read from old texture buffer */
- if (use_texture_old) {
- unsigned char *ot = (unsigned char *)oldtexibuf->rect + ((y - origy + yt) * oldtexibuf->x + (x - origx + xt)) * 4;
- crgba[0] = ot[0];
- crgba[1] = ot[1];
- crgba[2] = ot[2];
- crgba[3] = ot[3];
- }
- else
- rgba_float_to_uchar(crgba, rgba);
-
- /* write to new texture buffer */
- t[0] = crgba[0];
- t[1] = crgba[1];
- t[2] = crgba[2];
- t[3] = crgba[3];
-
- /* write to brush image buffer */
- b[0] = crgba[0];
- b[1] = crgba[1];
- b[2] = crgba[2];
- b[3] = crgba[3];
- }
- }
- }
+ Scene *scene = painter->scene;
+ Brush *brush = painter->brush;
+
+ const char *display_device = scene->display_settings.display_device;
+ struct ColorManagedDisplay *display = IMB_colormanagement_display_get_named(display_device);
+
+ rctf tex_mapping = painter->tex_mapping;
+ struct ImagePool *pool = painter->pool;
+
+ bool use_color_correction = painter->cache.use_color_correction;
+ bool use_float = painter->cache.use_float;
+ bool is_texbrush = painter->cache.is_texbrush;
+ bool use_texture_old = (oldtexibuf != NULL);
+
+ int x, y, thread = 0;
+ float brush_rgb[3];
+
+ ImBuf *ibuf = painter->cache.ibuf;
+ ImBuf *texibuf = painter->cache.texibuf;
+
+ /* get brush color */
+ if (brush->imagepaint_tool == PAINT_TOOL_DRAW) {
+ paint_brush_color_get(
+ scene, brush, use_color_correction, painter->cache.invert, 0.0, 1.0, brush_rgb, display);
+ }
+ else {
+ brush_rgb[0] = 1.0f;
+ brush_rgb[1] = 1.0f;
+ brush_rgb[2] = 1.0f;
+ }
+
+ /* fill pixels */
+ for (y = origy; y < h; y++) {
+ for (x = origx; x < w; x++) {
+ /* sample texture and multiply with brush color */
+ float texco[3], rgba[4];
+
+ if (!use_texture_old) {
+ if (is_texbrush) {
+ brush_imbuf_tex_co(&tex_mapping, x, y, texco);
+ BKE_brush_sample_tex_3d(scene, brush, texco, rgba, thread, pool);
+ /* TODO(sergey): Support texture paint color space. */
+ if (!use_float) {
+ IMB_colormanagement_scene_linear_to_display_v3(rgba, display);
+ }
+ mul_v3_v3(rgba, brush_rgb);
+ }
+ else {
+ copy_v3_v3(rgba, brush_rgb);
+ rgba[3] = 1.0f;
+ }
+ }
+
+ if (use_float) {
+ /* handle float pixel */
+ float *bf = ibuf->rect_float + (y * ibuf->x + x) * 4;
+ float *tf = texibuf->rect_float + (y * texibuf->x + x) * 4;
+
+ /* read from old texture buffer */
+ if (use_texture_old) {
+ const float *otf = oldtexibuf->rect_float +
+ ((y - origy + yt) * oldtexibuf->x + (x - origx + xt)) * 4;
+ copy_v4_v4(rgba, otf);
+ }
+
+ /* write to new texture buffer */
+ copy_v4_v4(tf, rgba);
+
+ /* output premultiplied float image, mf was already premultiplied */
+ mul_v3_v3fl(bf, rgba, rgba[3]);
+ bf[3] = rgba[3];
+ }
+ else {
+ unsigned char crgba[4];
+
+ /* handle byte pixel */
+ unsigned char *b = (unsigned char *)ibuf->rect + (y * ibuf->x + x) * 4;
+ unsigned char *t = (unsigned char *)texibuf->rect + (y * texibuf->x + x) * 4;
+
+ /* read from old texture buffer */
+ if (use_texture_old) {
+ unsigned char *ot = (unsigned char *)oldtexibuf->rect +
+ ((y - origy + yt) * oldtexibuf->x + (x - origx + xt)) * 4;
+ crgba[0] = ot[0];
+ crgba[1] = ot[1];
+ crgba[2] = ot[2];
+ crgba[3] = ot[3];
+ }
+ else
+ rgba_float_to_uchar(crgba, rgba);
+
+ /* write to new texture buffer */
+ t[0] = crgba[0];
+ t[1] = crgba[1];
+ t[2] = crgba[2];
+ t[3] = crgba[3];
+
+ /* write to brush image buffer */
+ b[0] = crgba[0];
+ b[1] = crgba[1];
+ b[2] = crgba[2];
+ b[3] = crgba[3];
+ }
+ }
+ }
}
/* update the brush image by trying to reuse the cached texture result. this
* can be considerably faster for brushes that change size due to pressure or
* textures that stick to the surface where only part of the pixels are new */
-static void brush_painter_imbuf_partial_update(BrushPainter *painter, const float pos[2], int diameter)
+static void brush_painter_imbuf_partial_update(BrushPainter *painter,
+ const float pos[2],
+ int diameter)
{
- BrushPainterCache *cache = &painter->cache;
- ImBuf *oldtexibuf, *ibuf;
- int imbflag, destx, desty, srcx, srcy, w, h, x1, y1, x2, y2;
-
- /* create brush image buffer if it didn't exist yet */
- imbflag = (cache->use_float) ? IB_rectfloat : IB_rect;
- if (!cache->ibuf)
- cache->ibuf = IMB_allocImBuf(diameter, diameter, 32, imbflag);
- ibuf = cache->ibuf;
-
- /* create new texture image buffer with coordinates relative to old */
- oldtexibuf = cache->texibuf;
- cache->texibuf = IMB_allocImBuf(diameter, diameter, 32, imbflag);
-
- if (oldtexibuf) {
- srcx = srcy = 0;
- w = oldtexibuf->x;
- h = oldtexibuf->y;
- destx = (int)floorf(painter->lastpaintpos[0]) - (int)floorf(pos[0]) + (diameter / 2 - w / 2);
- desty = (int)floorf(painter->lastpaintpos[1]) - (int)floorf(pos[1]) + (diameter / 2 - h / 2);
-
- IMB_rectclip(cache->texibuf, oldtexibuf, &destx, &desty, &srcx, &srcy, &w, &h);
- }
- else {
- srcx = srcy = 0;
- destx = desty = 0;
- w = h = 0;
- }
-
- x1 = min_ii(destx, ibuf->x);
- y1 = min_ii(desty, ibuf->y);
- x2 = min_ii(destx + w, ibuf->x);
- y2 = min_ii(desty + h, ibuf->y);
-
- /* blend existing texture in new position */
- if ((x1 < x2) && (y1 < y2))
- brush_painter_imbuf_update(painter, oldtexibuf, x1, y1, x2, y2, srcx, srcy);
-
- if (oldtexibuf)
- IMB_freeImBuf(oldtexibuf);
-
- /* sample texture in new areas */
- if ((0 < x1) && (0 < ibuf->y))
- brush_painter_imbuf_update(painter, NULL, 0, 0, x1, ibuf->y, 0, 0);
- if ((x2 < ibuf->x) && (0 < ibuf->y))
- brush_painter_imbuf_update(painter, NULL, x2, 0, ibuf->x, ibuf->y, 0, 0);
- if ((x1 < x2) && (0 < y1))
- brush_painter_imbuf_update(painter, NULL, x1, 0, x2, y1, 0, 0);
- if ((x1 < x2) && (y2 < ibuf->y))
- brush_painter_imbuf_update(painter, NULL, x1, y2, x2, ibuf->y, 0, 0);
+ BrushPainterCache *cache = &painter->cache;
+ ImBuf *oldtexibuf, *ibuf;
+ int imbflag, destx, desty, srcx, srcy, w, h, x1, y1, x2, y2;
+
+ /* create brush image buffer if it didn't exist yet */
+ imbflag = (cache->use_float) ? IB_rectfloat : IB_rect;
+ if (!cache->ibuf)
+ cache->ibuf = IMB_allocImBuf(diameter, diameter, 32, imbflag);
+ ibuf = cache->ibuf;
+
+ /* create new texture image buffer with coordinates relative to old */
+ oldtexibuf = cache->texibuf;
+ cache->texibuf = IMB_allocImBuf(diameter, diameter, 32, imbflag);
+
+ if (oldtexibuf) {
+ srcx = srcy = 0;
+ w = oldtexibuf->x;
+ h = oldtexibuf->y;
+ destx = (int)floorf(painter->lastpaintpos[0]) - (int)floorf(pos[0]) + (diameter / 2 - w / 2);
+ desty = (int)floorf(painter->lastpaintpos[1]) - (int)floorf(pos[1]) + (diameter / 2 - h / 2);
+
+ IMB_rectclip(cache->texibuf, oldtexibuf, &destx, &desty, &srcx, &srcy, &w, &h);
+ }
+ else {
+ srcx = srcy = 0;
+ destx = desty = 0;
+ w = h = 0;
+ }
+
+ x1 = min_ii(destx, ibuf->x);
+ y1 = min_ii(desty, ibuf->y);
+ x2 = min_ii(destx + w, ibuf->x);
+ y2 = min_ii(desty + h, ibuf->y);
+
+ /* blend existing texture in new position */
+ if ((x1 < x2) && (y1 < y2))
+ brush_painter_imbuf_update(painter, oldtexibuf, x1, y1, x2, y2, srcx, srcy);
+
+ if (oldtexibuf)
+ IMB_freeImBuf(oldtexibuf);
+
+ /* sample texture in new areas */
+ if ((0 < x1) && (0 < ibuf->y))
+ brush_painter_imbuf_update(painter, NULL, 0, 0, x1, ibuf->y, 0, 0);
+ if ((x2 < ibuf->x) && (0 < ibuf->y))
+ brush_painter_imbuf_update(painter, NULL, x2, 0, ibuf->x, ibuf->y, 0, 0);
+ if ((x1 < x2) && (0 < y1))
+ brush_painter_imbuf_update(painter, NULL, x1, 0, x2, y1, 0, 0);
+ if ((x1 < x2) && (y2 < ibuf->y))
+ brush_painter_imbuf_update(painter, NULL, x1, y2, x2, ibuf->y, 0, 0);
}
-static void brush_painter_2d_tex_mapping(ImagePaintState *s, int diameter, const float startpos[2], const float pos[2], const float mouse[2], int mapmode, rctf *mapping)
+static void brush_painter_2d_tex_mapping(ImagePaintState *s,
+ int diameter,
+ const float startpos[2],
+ const float pos[2],
+ const float mouse[2],
+ int mapmode,
+ rctf *mapping)
{
- float invw = 1.0f / (float)s->canvas->x;
- float invh = 1.0f / (float)s->canvas->y;
- int xmin, ymin, xmax, ymax;
- int ipos[2];
-
- /* find start coordinate of brush in canvas */
- ipos[0] = (int)floorf((pos[0] - diameter / 2) + 1.0f);
- ipos[1] = (int)floorf((pos[1] - diameter / 2) + 1.0f);
-
- if (mapmode == MTEX_MAP_MODE_STENCIL) {
- /* map from view coordinates of brush to region coordinates */
- UI_view2d_view_to_region(s->v2d, ipos[0] * invw, ipos[1] * invh, &xmin, &ymin);
- UI_view2d_view_to_region(s->v2d, (ipos[0] + diameter) * invw, (ipos[1] + diameter) * invh, &xmax, &ymax);
-
- /* output mapping from brush ibuf x/y to region coordinates */
- mapping->xmin = xmin;
- mapping->ymin = ymin;
- mapping->xmax = (xmax - xmin) / (float)diameter;
- mapping->ymax = (ymax - ymin) / (float)diameter;
- }
- else if (mapmode == MTEX_MAP_MODE_3D) {
- /* 3D mapping, just mapping to canvas 0..1 */
- mapping->xmin = 2.0f * (ipos[0] * invw - 0.5f);
- mapping->ymin = 2.0f * (ipos[1] * invh - 0.5f);
- mapping->xmax = 2.0f * invw;
- mapping->ymax = 2.0f * invh;
- }
- else if (ELEM(mapmode, MTEX_MAP_MODE_VIEW, MTEX_MAP_MODE_RANDOM)) {
- /* view mapping */
- mapping->xmin = mouse[0] - diameter * 0.5f + 0.5f;
- mapping->ymin = mouse[1] - diameter * 0.5f + 0.5f;
- mapping->xmax = 1.0f;
- mapping->ymax = 1.0f;
- }
- else /* if (mapmode == MTEX_MAP_MODE_TILED) */ {
- mapping->xmin = (int)(-diameter * 0.5) + (int)floorf(pos[0]) - (int)floorf(startpos[0]);
- mapping->ymin = (int)(-diameter * 0.5) + (int)floorf(pos[1]) - (int)floorf(startpos[1]);
- mapping->xmax = 1.0f;
- mapping->ymax = 1.0f;
- }
+ float invw = 1.0f / (float)s->canvas->x;
+ float invh = 1.0f / (float)s->canvas->y;
+ int xmin, ymin, xmax, ymax;
+ int ipos[2];
+
+ /* find start coordinate of brush in canvas */
+ ipos[0] = (int)floorf((pos[0] - diameter / 2) + 1.0f);
+ ipos[1] = (int)floorf((pos[1] - diameter / 2) + 1.0f);
+
+ if (mapmode == MTEX_MAP_MODE_STENCIL) {
+ /* map from view coordinates of brush to region coordinates */
+ UI_view2d_view_to_region(s->v2d, ipos[0] * invw, ipos[1] * invh, &xmin, &ymin);
+ UI_view2d_view_to_region(
+ s->v2d, (ipos[0] + diameter) * invw, (ipos[1] + diameter) * invh, &xmax, &ymax);
+
+ /* output mapping from brush ibuf x/y to region coordinates */
+ mapping->xmin = xmin;
+ mapping->ymin = ymin;
+ mapping->xmax = (xmax - xmin) / (float)diameter;
+ mapping->ymax = (ymax - ymin) / (float)diameter;
+ }
+ else if (mapmode == MTEX_MAP_MODE_3D) {
+ /* 3D mapping, just mapping to canvas 0..1 */
+ mapping->xmin = 2.0f * (ipos[0] * invw - 0.5f);
+ mapping->ymin = 2.0f * (ipos[1] * invh - 0.5f);
+ mapping->xmax = 2.0f * invw;
+ mapping->ymax = 2.0f * invh;
+ }
+ else if (ELEM(mapmode, MTEX_MAP_MODE_VIEW, MTEX_MAP_MODE_RANDOM)) {
+ /* view mapping */
+ mapping->xmin = mouse[0] - diameter * 0.5f + 0.5f;
+ mapping->ymin = mouse[1] - diameter * 0.5f + 0.5f;
+ mapping->xmax = 1.0f;
+ mapping->ymax = 1.0f;
+ }
+ else /* if (mapmode == MTEX_MAP_MODE_TILED) */ {
+ mapping->xmin = (int)(-diameter * 0.5) + (int)floorf(pos[0]) - (int)floorf(startpos[0]);
+ mapping->ymin = (int)(-diameter * 0.5) + (int)floorf(pos[1]) - (int)floorf(startpos[1]);
+ mapping->xmax = 1.0f;
+ mapping->ymax = 1.0f;
+ }
}
-static void brush_painter_2d_refresh_cache(ImagePaintState *s, BrushPainter *painter, const float pos[2], const float mouse[2], float pressure, float distance, float size)
+static void brush_painter_2d_refresh_cache(ImagePaintState *s,
+ BrushPainter *painter,
+ const float pos[2],
+ const float mouse[2],
+ float pressure,
+ float distance,
+ float size)
{
- const Scene *scene = painter->scene;
- UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
- Brush *brush = painter->brush;
- BrushPainterCache *cache = &painter->cache;
- const int diameter = 2 * size;
-
- bool do_random = false;
- bool do_partial_update = false;
- bool update_color = (
- (brush->flag & BRUSH_USE_GRADIENT) &&
- ((ELEM(brush->gradient_stroke_mode,
- BRUSH_GRADIENT_SPACING_REPEAT,
- BRUSH_GRADIENT_SPACING_CLAMP)) ||
- (cache->last_pressure != pressure)));
- float tex_rotation = -brush->mtex.rot;
- float mask_rotation = -brush->mask_mtex.rot;
-
- painter->pool = BKE_image_pool_new();
-
- /* determine how can update based on textures used */
- if (painter->cache.is_texbrush) {
- if (brush->mtex.brush_map_mode == MTEX_MAP_MODE_VIEW) {
- tex_rotation += ups->brush_rotation;
- }
- else if (brush->mtex.brush_map_mode == MTEX_MAP_MODE_RANDOM)
- do_random = true;
- else if (!((brush->flag & BRUSH_ANCHORED) || update_color))
- do_partial_update = true;
-
- brush_painter_2d_tex_mapping(
- s, diameter, painter->startpaintpos, pos, mouse,
- brush->mtex.brush_map_mode, &painter->tex_mapping);
- }
-
- if (painter->cache.is_maskbrush) {
- bool renew_maxmask = false;
- bool do_partial_update_mask = false;
- /* invalidate case for all mapping modes */
- if (brush->mask_mtex.brush_map_mode == MTEX_MAP_MODE_VIEW) {
- mask_rotation += ups->brush_rotation_sec;
- }
- else if (brush->mask_mtex.brush_map_mode == MTEX_MAP_MODE_RANDOM) {
- renew_maxmask = true;
- }
- else if (!(brush->flag & BRUSH_ANCHORED)) {
- do_partial_update_mask = true;
- renew_maxmask = true;
- }
- /* explicitly disable partial update even if it has been enabled above */
- if (brush->mask_pressure) {
- do_partial_update_mask = false;
- renew_maxmask = true;
- }
-
- if ((diameter != cache->lastdiameter) ||
- (mask_rotation != cache->last_mask_rotation) ||
- renew_maxmask)
- {
- if (cache->tex_mask) {
- MEM_freeN(cache->tex_mask);
- cache->tex_mask = NULL;
- }
-
- brush_painter_2d_tex_mapping(
- s, diameter, painter->startpaintpos, pos, mouse,
- brush->mask_mtex.brush_map_mode, &painter->mask_mapping);
-
- if (do_partial_update_mask)
- brush_painter_mask_imbuf_partial_update(painter, pos, diameter);
- else
- cache->tex_mask = brush_painter_mask_ibuf_new(painter, diameter);
- cache->last_mask_rotation = mask_rotation;
- }
- }
-
- /* curve mask can only change if the size changes */
- if (diameter != cache->lastdiameter) {
- if (cache->curve_mask) {
- MEM_freeN(cache->curve_mask);
- cache->curve_mask = NULL;
- }
-
- cache->curve_mask = brush_painter_curve_mask_new(painter, diameter, size);
- }
-
- /* detect if we need to recreate image brush buffer */
- if ((diameter != cache->lastdiameter) ||
- (tex_rotation != cache->last_tex_rotation) ||
- do_random ||
- update_color)
- {
- if (cache->ibuf) {
- IMB_freeImBuf(cache->ibuf);
- cache->ibuf = NULL;
- }
-
- if (do_partial_update) {
- /* do partial update of texture */
- brush_painter_imbuf_partial_update(painter, pos, diameter);
- }
- else {
- /* create brush from scratch */
- cache->ibuf = brush_painter_imbuf_new(painter, diameter, pressure, distance);
- }
-
- cache->lastdiameter = diameter;
- cache->last_tex_rotation = tex_rotation;
- cache->last_pressure = pressure;
- }
- else if (do_partial_update) {
- /* do only partial update of texture */
- int dx = (int)floorf(painter->lastpaintpos[0]) - (int)floorf(pos[0]);
- int dy = (int)floorf(painter->lastpaintpos[1]) - (int)floorf(pos[1]);
-
- if ((dx != 0) || (dy != 0)) {
- brush_painter_imbuf_partial_update(painter, pos, diameter);
- }
- }
-
- BKE_image_pool_free(painter->pool);
- painter->pool = NULL;
+ const Scene *scene = painter->scene;
+ UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
+ Brush *brush = painter->brush;
+ BrushPainterCache *cache = &painter->cache;
+ const int diameter = 2 * size;
+
+ bool do_random = false;
+ bool do_partial_update = false;
+ bool update_color = ((brush->flag & BRUSH_USE_GRADIENT) &&
+ ((ELEM(brush->gradient_stroke_mode,
+ BRUSH_GRADIENT_SPACING_REPEAT,
+ BRUSH_GRADIENT_SPACING_CLAMP)) ||
+ (cache->last_pressure != pressure)));
+ float tex_rotation = -brush->mtex.rot;
+ float mask_rotation = -brush->mask_mtex.rot;
+
+ painter->pool = BKE_image_pool_new();
+
+ /* determine how can update based on textures used */
+ if (painter->cache.is_texbrush) {
+ if (brush->mtex.brush_map_mode == MTEX_MAP_MODE_VIEW) {
+ tex_rotation += ups->brush_rotation;
+ }
+ else if (brush->mtex.brush_map_mode == MTEX_MAP_MODE_RANDOM)
+ do_random = true;
+ else if (!((brush->flag & BRUSH_ANCHORED) || update_color))
+ do_partial_update = true;
+
+ brush_painter_2d_tex_mapping(s,
+ diameter,
+ painter->startpaintpos,
+ pos,
+ mouse,
+ brush->mtex.brush_map_mode,
+ &painter->tex_mapping);
+ }
+
+ if (painter->cache.is_maskbrush) {
+ bool renew_maxmask = false;
+ bool do_partial_update_mask = false;
+ /* invalidate case for all mapping modes */
+ if (brush->mask_mtex.brush_map_mode == MTEX_MAP_MODE_VIEW) {
+ mask_rotation += ups->brush_rotation_sec;
+ }
+ else if (brush->mask_mtex.brush_map_mode == MTEX_MAP_MODE_RANDOM) {
+ renew_maxmask = true;
+ }
+ else if (!(brush->flag & BRUSH_ANCHORED)) {
+ do_partial_update_mask = true;
+ renew_maxmask = true;
+ }
+ /* explicitly disable partial update even if it has been enabled above */
+ if (brush->mask_pressure) {
+ do_partial_update_mask = false;
+ renew_maxmask = true;
+ }
+
+ if ((diameter != cache->lastdiameter) || (mask_rotation != cache->last_mask_rotation) ||
+ renew_maxmask) {
+ if (cache->tex_mask) {
+ MEM_freeN(cache->tex_mask);
+ cache->tex_mask = NULL;
+ }
+
+ brush_painter_2d_tex_mapping(s,
+ diameter,
+ painter->startpaintpos,
+ pos,
+ mouse,
+ brush->mask_mtex.brush_map_mode,
+ &painter->mask_mapping);
+
+ if (do_partial_update_mask)
+ brush_painter_mask_imbuf_partial_update(painter, pos, diameter);
+ else
+ cache->tex_mask = brush_painter_mask_ibuf_new(painter, diameter);
+ cache->last_mask_rotation = mask_rotation;
+ }
+ }
+
+ /* curve mask can only change if the size changes */
+ if (diameter != cache->lastdiameter) {
+ if (cache->curve_mask) {
+ MEM_freeN(cache->curve_mask);
+ cache->curve_mask = NULL;
+ }
+
+ cache->curve_mask = brush_painter_curve_mask_new(painter, diameter, size);
+ }
+
+ /* detect if we need to recreate image brush buffer */
+ if ((diameter != cache->lastdiameter) || (tex_rotation != cache->last_tex_rotation) ||
+ do_random || update_color) {
+ if (cache->ibuf) {
+ IMB_freeImBuf(cache->ibuf);
+ cache->ibuf = NULL;
+ }
+
+ if (do_partial_update) {
+ /* do partial update of texture */
+ brush_painter_imbuf_partial_update(painter, pos, diameter);
+ }
+ else {
+ /* create brush from scratch */
+ cache->ibuf = brush_painter_imbuf_new(painter, diameter, pressure, distance);
+ }
+
+ cache->lastdiameter = diameter;
+ cache->last_tex_rotation = tex_rotation;
+ cache->last_pressure = pressure;
+ }
+ else if (do_partial_update) {
+ /* do only partial update of texture */
+ int dx = (int)floorf(painter->lastpaintpos[0]) - (int)floorf(pos[0]);
+ int dy = (int)floorf(painter->lastpaintpos[1]) - (int)floorf(pos[1]);
+
+ if ((dx != 0) || (dy != 0)) {
+ brush_painter_imbuf_partial_update(painter, pos, diameter);
+ }
+ }
+
+ BKE_image_pool_free(painter->pool);
+ painter->pool = NULL;
}
/* keep these functions in sync */
static void paint_2d_ibuf_rgb_get(ImBuf *ibuf, int x, int y, float r_rgb[4])
{
- if (ibuf->rect_float) {
- const float *rrgbf = ibuf->rect_float + (ibuf->x * y + x) * 4;
- copy_v4_v4(r_rgb, rrgbf);
- }
- else {
- unsigned char *rrgb = (unsigned char *)ibuf->rect + (ibuf->x * y + x) * 4;
- straight_uchar_to_premul_float(r_rgb, rrgb);
- }
+ if (ibuf->rect_float) {
+ const float *rrgbf = ibuf->rect_float + (ibuf->x * y + x) * 4;
+ copy_v4_v4(r_rgb, rrgbf);
+ }
+ else {
+ unsigned char *rrgb = (unsigned char *)ibuf->rect + (ibuf->x * y + x) * 4;
+ straight_uchar_to_premul_float(r_rgb, rrgb);
+ }
}
-static void paint_2d_ibuf_rgb_set(ImBuf *ibuf, int x, int y, const bool is_torus, const float rgb[4])
+static void paint_2d_ibuf_rgb_set(
+ ImBuf *ibuf, int x, int y, const bool is_torus, const float rgb[4])
{
- if (is_torus) {
- x %= ibuf->x;
- if (x < 0) x += ibuf->x;
- y %= ibuf->y;
- if (y < 0) y += ibuf->y;
- }
-
- if (ibuf->rect_float) {
- float *rrgbf = ibuf->rect_float + (ibuf->x * y + x) * 4;
- float map_alpha = (rgb[3] == 0.0f) ? rrgbf[3] : rrgbf[3] / rgb[3];
-
- mul_v3_v3fl(rrgbf, rgb, map_alpha);
- rrgbf[3] = rgb[3];
- }
- else {
- unsigned char straight[4];
- unsigned char *rrgb = (unsigned char *)ibuf->rect + (ibuf->x * y + x) * 4;
-
- premul_float_to_straight_uchar(straight, rgb);
- rrgb[0] = straight[0];
- rrgb[1] = straight[1];
- rrgb[2] = straight[2];
- rrgb[3] = straight[3];
- }
+ if (is_torus) {
+ x %= ibuf->x;
+ if (x < 0)
+ x += ibuf->x;
+ y %= ibuf->y;
+ if (y < 0)
+ y += ibuf->y;
+ }
+
+ if (ibuf->rect_float) {
+ float *rrgbf = ibuf->rect_float + (ibuf->x * y + x) * 4;
+ float map_alpha = (rgb[3] == 0.0f) ? rrgbf[3] : rrgbf[3] / rgb[3];
+
+ mul_v3_v3fl(rrgbf, rgb, map_alpha);
+ rrgbf[3] = rgb[3];
+ }
+ else {
+ unsigned char straight[4];
+ unsigned char *rrgb = (unsigned char *)ibuf->rect + (ibuf->x * y + x) * 4;
+
+ premul_float_to_straight_uchar(straight, rgb);
+ rrgb[0] = straight[0];
+ rrgb[1] = straight[1];
+ rrgb[2] = straight[2];
+ rrgb[3] = straight[3];
+ }
}
static void paint_2d_ibuf_tile_convert(ImBuf *ibuf, int *x, int *y, short tile)
{
- if (tile & PAINT_TILE_X) {
- *x %= ibuf->x;
- if (*x < 0) *x += ibuf->x;
- }
- if (tile & PAINT_TILE_Y) {
- *y %= ibuf->y;
- if (*y < 0) *y += ibuf->y;
- }
+ if (tile & PAINT_TILE_X) {
+ *x %= ibuf->x;
+ if (*x < 0)
+ *x += ibuf->x;
+ }
+ if (tile & PAINT_TILE_Y) {
+ *y %= ibuf->y;
+ if (*y < 0)
+ *y += ibuf->y;
+ }
}
-
static float paint_2d_ibuf_add_if(ImBuf *ibuf, int x, int y, float *outrgb, short tile, float w)
{
- float inrgb[4];
-
- if (tile) paint_2d_ibuf_tile_convert(ibuf, &x, &y, tile);
- /* need to also do clipping here always since tiled coordinates
- * are not always within bounds */
- if (x < ibuf->x && x >= 0 && y < ibuf->y && y >= 0) {
- paint_2d_ibuf_rgb_get(ibuf, x, y, inrgb);
- }
- else return 0;
-
- mul_v4_fl(inrgb, w);
- add_v4_v4(outrgb, inrgb);
-
- return w;
+ float inrgb[4];
+
+ if (tile)
+ paint_2d_ibuf_tile_convert(ibuf, &x, &y, tile);
+ /* need to also do clipping here always since tiled coordinates
+ * are not always within bounds */
+ if (x < ibuf->x && x >= 0 && y < ibuf->y && y >= 0) {
+ paint_2d_ibuf_rgb_get(ibuf, x, y, inrgb);
+ }
+ else
+ return 0;
+
+ mul_v4_fl(inrgb, w);
+ add_v4_v4(outrgb, inrgb);
+
+ return w;
}
-static void paint_2d_lift_soften(ImagePaintState *s, ImBuf *ibuf, ImBuf *ibufb, int *pos, const short tile)
+static void paint_2d_lift_soften(
+ ImagePaintState *s, ImBuf *ibuf, ImBuf *ibufb, int *pos, const short tile)
{
- bool sharpen = (s->painter->cache.invert ^ ((s->brush->flag & BRUSH_DIR_IN) != 0));
- float threshold = s->brush->sharp_threshold;
- int x, y, xi, yi, xo, yo, xk, yk;
- float count;
- int out_off[2], in_off[2], dim[2];
- int diff_pos[2];
- float outrgb[4];
- float rgba[4];
- BlurKernel *kernel = s->blurkernel;
-
- dim[0] = ibufb->x;
- dim[1] = ibufb->y;
- in_off[0] = pos[0];
- in_off[1] = pos[1];
- out_off[0] = out_off[1] = 0;
-
- if (!tile) {
- IMB_rectclip(
- ibuf, ibufb, &in_off[0], &in_off[1], &out_off[0],
- &out_off[1], &dim[0], &dim[1]);
-
- if ((dim[0] == 0) || (dim[1] == 0))
- return;
- }
-
- /* find offset inside mask buffers to sample them */
- sub_v2_v2v2_int(diff_pos, out_off, in_off);
-
- for (y = 0; y < dim[1]; y++) {
- for (x = 0; x < dim[0]; x++) {
- /* get input pixel */
- xi = in_off[0] + x;
- yi = in_off[1] + y;
-
- count = 0.0;
- if (tile) {
- paint_2d_ibuf_tile_convert(ibuf, &xi, &yi, tile);
- if (xi < ibuf->x && xi >= 0 && yi < ibuf->y && yi >= 0)
- paint_2d_ibuf_rgb_get(ibuf, xi, yi, rgba);
- else
- zero_v4(rgba);
- }
- else {
- /* coordinates have been clipped properly here, it should be safe to do this */
- paint_2d_ibuf_rgb_get(ibuf, xi, yi, rgba);
- }
- zero_v4(outrgb);
-
- for (yk = 0; yk < kernel->side; yk++) {
- for (xk = 0; xk < kernel->side; xk++) {
- count += paint_2d_ibuf_add_if(
- ibuf, xi + xk - kernel->pixel_len,
- yi + yk - kernel->pixel_len, outrgb, tile,
- kernel->wdata[xk + yk * kernel->side]);
- }
- }
-
- if (count > 0.0f) {
- mul_v4_fl(outrgb, 1.0f / (float)count);
-
- if (sharpen) {
- /* subtract blurred image from normal image gives high pass filter */
- sub_v3_v3v3(outrgb, rgba, outrgb);
-
- /* now rgba_ub contains the edge result, but this should be converted to luminance to avoid
- * colored speckles appearing in final image, and also to check for threshold */
- outrgb[0] = outrgb[1] = outrgb[2] = IMB_colormanagement_get_luminance(outrgb);
- if (fabsf(outrgb[0]) > threshold) {
- float mask = BKE_brush_alpha_get(s->scene, s->brush);
- float alpha = rgba[3];
- rgba[3] = outrgb[3] = mask;
-
- /* add to enhance edges */
- blend_color_add_float(outrgb, rgba, outrgb);
- outrgb[3] = alpha;
- }
- else
- copy_v4_v4(outrgb, rgba);
- }
- }
- else
- copy_v4_v4(outrgb, rgba);
- /* write into brush buffer */
- xo = out_off[0] + x;
- yo = out_off[1] + y;
- paint_2d_ibuf_rgb_set(ibufb, xo, yo, 0, outrgb);
- }
- }
+ bool sharpen = (s->painter->cache.invert ^ ((s->brush->flag & BRUSH_DIR_IN) != 0));
+ float threshold = s->brush->sharp_threshold;
+ int x, y, xi, yi, xo, yo, xk, yk;
+ float count;
+ int out_off[2], in_off[2], dim[2];
+ int diff_pos[2];
+ float outrgb[4];
+ float rgba[4];
+ BlurKernel *kernel = s->blurkernel;
+
+ dim[0] = ibufb->x;
+ dim[1] = ibufb->y;
+ in_off[0] = pos[0];
+ in_off[1] = pos[1];
+ out_off[0] = out_off[1] = 0;
+
+ if (!tile) {
+ IMB_rectclip(ibuf, ibufb, &in_off[0], &in_off[1], &out_off[0], &out_off[1], &dim[0], &dim[1]);
+
+ if ((dim[0] == 0) || (dim[1] == 0))
+ return;
+ }
+
+ /* find offset inside mask buffers to sample them */
+ sub_v2_v2v2_int(diff_pos, out_off, in_off);
+
+ for (y = 0; y < dim[1]; y++) {
+ for (x = 0; x < dim[0]; x++) {
+ /* get input pixel */
+ xi = in_off[0] + x;
+ yi = in_off[1] + y;
+
+ count = 0.0;
+ if (tile) {
+ paint_2d_ibuf_tile_convert(ibuf, &xi, &yi, tile);
+ if (xi < ibuf->x && xi >= 0 && yi < ibuf->y && yi >= 0)
+ paint_2d_ibuf_rgb_get(ibuf, xi, yi, rgba);
+ else
+ zero_v4(rgba);
+ }
+ else {
+ /* coordinates have been clipped properly here, it should be safe to do this */
+ paint_2d_ibuf_rgb_get(ibuf, xi, yi, rgba);
+ }
+ zero_v4(outrgb);
+
+ for (yk = 0; yk < kernel->side; yk++) {
+ for (xk = 0; xk < kernel->side; xk++) {
+ count += paint_2d_ibuf_add_if(ibuf,
+ xi + xk - kernel->pixel_len,
+ yi + yk - kernel->pixel_len,
+ outrgb,
+ tile,
+ kernel->wdata[xk + yk * kernel->side]);
+ }
+ }
+
+ if (count > 0.0f) {
+ mul_v4_fl(outrgb, 1.0f / (float)count);
+
+ if (sharpen) {
+ /* subtract blurred image from normal image gives high pass filter */
+ sub_v3_v3v3(outrgb, rgba, outrgb);
+
+ /* now rgba_ub contains the edge result, but this should be converted to luminance to avoid
+ * colored speckles appearing in final image, and also to check for threshold */
+ outrgb[0] = outrgb[1] = outrgb[2] = IMB_colormanagement_get_luminance(outrgb);
+ if (fabsf(outrgb[0]) > threshold) {
+ float mask = BKE_brush_alpha_get(s->scene, s->brush);
+ float alpha = rgba[3];
+ rgba[3] = outrgb[3] = mask;
+
+ /* add to enhance edges */
+ blend_color_add_float(outrgb, rgba, outrgb);
+ outrgb[3] = alpha;
+ }
+ else
+ copy_v4_v4(outrgb, rgba);
+ }
+ }
+ else
+ copy_v4_v4(outrgb, rgba);
+ /* write into brush buffer */
+ xo = out_off[0] + x;
+ yo = out_off[1] + y;
+ paint_2d_ibuf_rgb_set(ibufb, xo, yo, 0, outrgb);
+ }
+ }
}
-static void paint_2d_set_region(ImagePaintRegion *region, int destx, int desty, int srcx, int srcy, int width, int height)
+static void paint_2d_set_region(
+ ImagePaintRegion *region, int destx, int desty, int srcx, int srcy, int width, int height)
{
- region->destx = destx;
- region->desty = desty;
- region->srcx = srcx;
- region->srcy = srcy;
- region->width = width;
- region->height = height;
+ region->destx = destx;
+ region->desty = desty;
+ region->srcx = srcx;
+ region->srcy = srcy;
+ region->width = width;
+ region->height = height;
}
-static int paint_2d_torus_split_region(ImagePaintRegion region[4], ImBuf *dbuf, ImBuf *sbuf, short tile)
+static int paint_2d_torus_split_region(ImagePaintRegion region[4],
+ ImBuf *dbuf,
+ ImBuf *sbuf,
+ short tile)
{
- int destx = region->destx;
- int desty = region->desty;
- int srcx = region->srcx;
- int srcy = region->srcy;
- int width = region->width;
- int height = region->height;
- int origw, origh, w, h, tot = 0;
-
- /* convert destination and source coordinates to be within image */
- if (tile & PAINT_TILE_X) {
- destx = destx % dbuf->x;
- if (destx < 0) destx += dbuf->x;
- srcx = srcx % sbuf->x;
- if (srcx < 0) srcx += sbuf->x;
- }
- if (tile & PAINT_TILE_Y) {
- desty = desty % dbuf->y;
- if (desty < 0) desty += dbuf->y;
- srcy = srcy % sbuf->y;
- if (srcy < 0) srcy += sbuf->y;
- }
- /* clip width of blending area to destination imbuf, to avoid writing the
- * same pixel twice */
- origw = w = (width > dbuf->x) ? dbuf->x : width;
- origh = h = (height > dbuf->y) ? dbuf->y : height;
-
- /* clip within image */
- IMB_rectclip(dbuf, sbuf, &destx, &desty, &srcx, &srcy, &w, &h);
- paint_2d_set_region(&region[tot++], destx, desty, srcx, srcy, w, h);
-
- /* do 3 other rects if needed */
- if ((tile & PAINT_TILE_X) && w < origw)
- paint_2d_set_region(&region[tot++], (destx + w) % dbuf->x, desty, (srcx + w) % sbuf->x, srcy, origw - w, h);
- if ((tile & PAINT_TILE_Y) && h < origh)
- paint_2d_set_region(&region[tot++], destx, (desty + h) % dbuf->y, srcx, (srcy + h) % sbuf->y, w, origh - h);
- if ((tile & PAINT_TILE_X) && (tile & PAINT_TILE_Y) && (w < origw) && (h < origh))
- paint_2d_set_region(&region[tot++], (destx + w) % dbuf->x, (desty + h) % dbuf->y, (srcx + w) % sbuf->x, (srcy + h) % sbuf->y, origw - w, origh - h);
-
- return tot;
+ int destx = region->destx;
+ int desty = region->desty;
+ int srcx = region->srcx;
+ int srcy = region->srcy;
+ int width = region->width;
+ int height = region->height;
+ int origw, origh, w, h, tot = 0;
+
+ /* convert destination and source coordinates to be within image */
+ if (tile & PAINT_TILE_X) {
+ destx = destx % dbuf->x;
+ if (destx < 0)
+ destx += dbuf->x;
+ srcx = srcx % sbuf->x;
+ if (srcx < 0)
+ srcx += sbuf->x;
+ }
+ if (tile & PAINT_TILE_Y) {
+ desty = desty % dbuf->y;
+ if (desty < 0)
+ desty += dbuf->y;
+ srcy = srcy % sbuf->y;
+ if (srcy < 0)
+ srcy += sbuf->y;
+ }
+ /* clip width of blending area to destination imbuf, to avoid writing the
+ * same pixel twice */
+ origw = w = (width > dbuf->x) ? dbuf->x : width;
+ origh = h = (height > dbuf->y) ? dbuf->y : height;
+
+ /* clip within image */
+ IMB_rectclip(dbuf, sbuf, &destx, &desty, &srcx, &srcy, &w, &h);
+ paint_2d_set_region(&region[tot++], destx, desty, srcx, srcy, w, h);
+
+ /* do 3 other rects if needed */
+ if ((tile & PAINT_TILE_X) && w < origw)
+ paint_2d_set_region(
+ &region[tot++], (destx + w) % dbuf->x, desty, (srcx + w) % sbuf->x, srcy, origw - w, h);
+ if ((tile & PAINT_TILE_Y) && h < origh)
+ paint_2d_set_region(
+ &region[tot++], destx, (desty + h) % dbuf->y, srcx, (srcy + h) % sbuf->y, w, origh - h);
+ if ((tile & PAINT_TILE_X) && (tile & PAINT_TILE_Y) && (w < origw) && (h < origh))
+ paint_2d_set_region(&region[tot++],
+ (destx + w) % dbuf->x,
+ (desty + h) % dbuf->y,
+ (srcx + w) % sbuf->x,
+ (srcy + h) % sbuf->y,
+ origw - w,
+ origh - h);
+
+ return tot;
}
static void paint_2d_lift_smear(ImBuf *ibuf, ImBuf *ibufb, int *pos, short tile)
{
- ImagePaintRegion region[4];
- int a, tot;
-
- paint_2d_set_region(region, 0, 0, pos[0], pos[1], ibufb->x, ibufb->y);
- tot = paint_2d_torus_split_region(region, ibufb, ibuf, tile);
-
- for (a = 0; a < tot; a++)
- IMB_rectblend(
- ibufb, ibufb, ibuf, NULL, NULL, NULL, 0, region[a].destx, region[a].desty,
- region[a].destx, region[a].desty,
- region[a].srcx, region[a].srcy,
- region[a].width, region[a].height, IMB_BLEND_COPY, false);
+ ImagePaintRegion region[4];
+ int a, tot;
+
+ paint_2d_set_region(region, 0, 0, pos[0], pos[1], ibufb->x, ibufb->y);
+ tot = paint_2d_torus_split_region(region, ibufb, ibuf, tile);
+
+ for (a = 0; a < tot; a++)
+ IMB_rectblend(ibufb,
+ ibufb,
+ ibuf,
+ NULL,
+ NULL,
+ NULL,
+ 0,
+ region[a].destx,
+ region[a].desty,
+ region[a].destx,
+ region[a].desty,
+ region[a].srcx,
+ region[a].srcy,
+ region[a].width,
+ region[a].height,
+ IMB_BLEND_COPY,
+ false);
}
static ImBuf *paint_2d_lift_clone(ImBuf *ibuf, ImBuf *ibufb, int *pos)
{
- /* note: allocImbuf returns zero'd memory, so regions outside image will
- * have zero alpha, and hence not be blended onto the image */
- int w = ibufb->x, h = ibufb->y, destx = 0, desty = 0, srcx = pos[0], srcy = pos[1];
- ImBuf *clonebuf = IMB_allocImBuf(w, h, ibufb->planes, ibufb->flags);
-
- IMB_rectclip(clonebuf, ibuf, &destx, &desty, &srcx, &srcy, &w, &h);
- IMB_rectblend(
- clonebuf, clonebuf, ibufb, NULL, NULL, NULL, 0, destx, desty, destx, desty, destx, desty, w, h,
- IMB_BLEND_COPY_ALPHA, false);
- IMB_rectblend(
- clonebuf, clonebuf, ibuf, NULL, NULL, NULL, 0, destx, desty, destx, desty, srcx, srcy, w, h,
- IMB_BLEND_COPY_RGB, false);
-
- return clonebuf;
+ /* note: allocImbuf returns zero'd memory, so regions outside image will
+ * have zero alpha, and hence not be blended onto the image */
+ int w = ibufb->x, h = ibufb->y, destx = 0, desty = 0, srcx = pos[0], srcy = pos[1];
+ ImBuf *clonebuf = IMB_allocImBuf(w, h, ibufb->planes, ibufb->flags);
+
+ IMB_rectclip(clonebuf, ibuf, &destx, &desty, &srcx, &srcy, &w, &h);
+ IMB_rectblend(clonebuf,
+ clonebuf,
+ ibufb,
+ NULL,
+ NULL,
+ NULL,
+ 0,
+ destx,
+ desty,
+ destx,
+ desty,
+ destx,
+ desty,
+ w,
+ h,
+ IMB_BLEND_COPY_ALPHA,
+ false);
+ IMB_rectblend(clonebuf,
+ clonebuf,
+ ibuf,
+ NULL,
+ NULL,
+ NULL,
+ 0,
+ destx,
+ desty,
+ destx,
+ desty,
+ srcx,
+ srcy,
+ w,
+ h,
+ IMB_BLEND_COPY_RGB,
+ false);
+
+ return clonebuf;
}
static void paint_2d_convert_brushco(ImBuf *ibufb, const float pos[2], int ipos[2])
{
- ipos[0] = (int)floorf((pos[0] - ibufb->x / 2));
- ipos[1] = (int)floorf((pos[1] - ibufb->y / 2));
+ ipos[0] = (int)floorf((pos[0] - ibufb->x / 2));
+ ipos[1] = (int)floorf((pos[1] - ibufb->y / 2));
}
-static void paint_2d_do_making_brush(
- ImagePaintState *s,
- ImagePaintRegion *region,
- unsigned short *curveb,
- unsigned short *texmaskb,
- ImBuf *frombuf,
- float mask_max,
- short blend,
- int tilex, int tiley,
- int tilew, int tileh)
+static void paint_2d_do_making_brush(ImagePaintState *s,
+ ImagePaintRegion *region,
+ unsigned short *curveb,
+ unsigned short *texmaskb,
+ ImBuf *frombuf,
+ float mask_max,
+ short blend,
+ int tilex,
+ int tiley,
+ int tilew,
+ int tileh)
{
- ImBuf tmpbuf;
- IMB_initImBuf(&tmpbuf, IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, 32, 0);
-
- ListBase *undo_tiles = ED_image_undo_get_tiles();
-
- for (int ty = tiley; ty <= tileh; ty++) {
- for (int tx = tilex; tx <= tilew; tx++) {
- /* retrieve original pixels + mask from undo buffer */
- unsigned short *mask;
- int origx = region->destx - tx * IMAPAINT_TILE_SIZE;
- int origy = region->desty - ty * IMAPAINT_TILE_SIZE;
-
- if (s->canvas->rect_float)
- tmpbuf.rect_float = image_undo_find_tile(undo_tiles, s->image, s->canvas, tx, ty, &mask, false);
- else
- tmpbuf.rect = image_undo_find_tile(undo_tiles, s->image, s->canvas, tx, ty, &mask, false);
-
- IMB_rectblend(
- s->canvas, &tmpbuf, frombuf, mask,
- curveb, texmaskb, mask_max,
- region->destx, region->desty,
- origx, origy,
- region->srcx, region->srcy,
- region->width, region->height,
- blend, ((s->brush->flag & BRUSH_ACCUMULATE) != 0));
- }
- }
+ ImBuf tmpbuf;
+ IMB_initImBuf(&tmpbuf, IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, 32, 0);
+
+ ListBase *undo_tiles = ED_image_undo_get_tiles();
+
+ for (int ty = tiley; ty <= tileh; ty++) {
+ for (int tx = tilex; tx <= tilew; tx++) {
+ /* retrieve original pixels + mask from undo buffer */
+ unsigned short *mask;
+ int origx = region->destx - tx * IMAPAINT_TILE_SIZE;
+ int origy = region->desty - ty * IMAPAINT_TILE_SIZE;
+
+ if (s->canvas->rect_float)
+ tmpbuf.rect_float = image_undo_find_tile(
+ undo_tiles, s->image, s->canvas, tx, ty, &mask, false);
+ else
+ tmpbuf.rect = image_undo_find_tile(undo_tiles, s->image, s->canvas, tx, ty, &mask, false);
+
+ IMB_rectblend(s->canvas,
+ &tmpbuf,
+ frombuf,
+ mask,
+ curveb,
+ texmaskb,
+ mask_max,
+ region->destx,
+ region->desty,
+ origx,
+ origy,
+ region->srcx,
+ region->srcy,
+ region->width,
+ region->height,
+ blend,
+ ((s->brush->flag & BRUSH_ACCUMULATE) != 0));
+ }
+ }
}
typedef struct Paint2DForeachData {
- ImagePaintState *s;
- ImagePaintRegion *region;
- unsigned short *curveb;
- unsigned short *texmaskb;
- ImBuf *frombuf;
- float mask_max;
- short blend;
- int tilex;
- int tilew;
+ ImagePaintState *s;
+ ImagePaintRegion *region;
+ unsigned short *curveb;
+ unsigned short *texmaskb;
+ ImBuf *frombuf;
+ float mask_max;
+ short blend;
+ int tilex;
+ int tilew;
} Paint2DForeachData;
-static void paint_2d_op_foreach_do(
- void *__restrict data_v,
- const int iter,
- const ParallelRangeTLS *__restrict UNUSED(tls))
+static void paint_2d_op_foreach_do(void *__restrict data_v,
+ const int iter,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
- Paint2DForeachData *data = (Paint2DForeachData *)data_v;
- paint_2d_do_making_brush(
- data->s, data->region, data->curveb,
- data->texmaskb, data->frombuf, data->mask_max,
- data->blend,
- data->tilex, iter,
- data->tilew, iter);
+ Paint2DForeachData *data = (Paint2DForeachData *)data_v;
+ paint_2d_do_making_brush(data->s,
+ data->region,
+ data->curveb,
+ data->texmaskb,
+ data->frombuf,
+ data->mask_max,
+ data->blend,
+ data->tilex,
+ iter,
+ data->tilew,
+ iter);
}
-static int paint_2d_op(void *state, ImBuf *ibufb, unsigned short *curveb, unsigned short *texmaskb, const float lastpos[2], const float pos[2])
+static int paint_2d_op(void *state,
+ ImBuf *ibufb,
+ unsigned short *curveb,
+ unsigned short *texmaskb,
+ const float lastpos[2],
+ const float pos[2])
{
- ImagePaintState *s = ((ImagePaintState *)state);
- ImBuf *clonebuf = NULL, *frombuf;
- ImagePaintRegion region[4];
- short tile = s->symmetry & (PAINT_TILE_X | PAINT_TILE_Y);
- short blend = s->blend;
- const float *offset = s->brush->clone.offset;
- float liftpos[2];
- float mask_max = BKE_brush_alpha_get(s->scene, s->brush);
- int bpos[2], blastpos[2], bliftpos[2];
- int a, tot;
-
- paint_2d_convert_brushco(ibufb, pos, bpos);
-
- /* lift from canvas */
- if (s->tool == PAINT_TOOL_SOFTEN) {
- paint_2d_lift_soften(s, s->canvas, ibufb, bpos, tile);
- blend = IMB_BLEND_INTERPOLATE;
- }
- else if (s->tool == PAINT_TOOL_SMEAR) {
- if (lastpos[0] == pos[0] && lastpos[1] == pos[1])
- return 0;
-
- paint_2d_convert_brushco(ibufb, lastpos, blastpos);
- paint_2d_lift_smear(s->canvas, ibufb, blastpos, tile);
- blend = IMB_BLEND_INTERPOLATE;
- }
- else if (s->tool == PAINT_TOOL_CLONE && s->clonecanvas) {
- liftpos[0] = pos[0] - offset[0] * s->canvas->x;
- liftpos[1] = pos[1] - offset[1] * s->canvas->y;
-
- paint_2d_convert_brushco(ibufb, liftpos, bliftpos);
- clonebuf = paint_2d_lift_clone(s->clonecanvas, ibufb, bliftpos);
- }
-
- frombuf = (clonebuf) ? clonebuf : ibufb;
-
- if (tile) {
- paint_2d_set_region(region, bpos[0], bpos[1], 0, 0, frombuf->x, frombuf->y);
- tot = paint_2d_torus_split_region(region, s->canvas, frombuf, tile);
- }
- else {
- paint_2d_set_region(region, bpos[0], bpos[1], 0, 0, frombuf->x, frombuf->y);
- tot = 1;
- }
-
- /* blend into canvas */
- for (a = 0; a < tot; a++) {
- ED_imapaint_dirty_region(
- s->image, s->canvas,
- region[a].destx, region[a].desty,
- region[a].width, region[a].height, true);
-
- if (s->do_masking) {
- /* masking, find original pixels tiles from undo buffer to composite over */
- int tilex, tiley, tilew, tileh;
-
- imapaint_region_tiles(
- s->canvas, region[a].destx, region[a].desty,
- region[a].width, region[a].height,
- &tilex, &tiley, &tilew, &tileh);
-
- if (tiley == tileh) {
- paint_2d_do_making_brush(
- s, &region[a], curveb, texmaskb, frombuf,
- mask_max, blend, tilex, tiley, tilew, tileh);
- }
- else {
- Paint2DForeachData data;
- data.s = s;
- data.region = &region[a];
- data.curveb = curveb;
- data.texmaskb = texmaskb;
- data.frombuf = frombuf;
- data.mask_max = mask_max;
- data.blend = blend;
- data.tilex = tilex;
- data.tilew = tilew;
-
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- BLI_task_parallel_range(
- tiley, tileh + 1, &data,
- paint_2d_op_foreach_do,
- &settings);
-
- }
- }
- else {
- /* no masking, composite brush directly onto canvas */
- IMB_rectblend_threaded(
- s->canvas, s->canvas, frombuf, NULL, curveb, texmaskb, mask_max,
- region[a].destx, region[a].desty,
- region[a].destx, region[a].desty,
- region[a].srcx, region[a].srcy,
- region[a].width, region[a].height, blend, false);
- }
- }
-
- if (clonebuf) IMB_freeImBuf(clonebuf);
-
- return 1;
+ ImagePaintState *s = ((ImagePaintState *)state);
+ ImBuf *clonebuf = NULL, *frombuf;
+ ImagePaintRegion region[4];
+ short tile = s->symmetry & (PAINT_TILE_X | PAINT_TILE_Y);
+ short blend = s->blend;
+ const float *offset = s->brush->clone.offset;
+ float liftpos[2];
+ float mask_max = BKE_brush_alpha_get(s->scene, s->brush);
+ int bpos[2], blastpos[2], bliftpos[2];
+ int a, tot;
+
+ paint_2d_convert_brushco(ibufb, pos, bpos);
+
+ /* lift from canvas */
+ if (s->tool == PAINT_TOOL_SOFTEN) {
+ paint_2d_lift_soften(s, s->canvas, ibufb, bpos, tile);
+ blend = IMB_BLEND_INTERPOLATE;
+ }
+ else if (s->tool == PAINT_TOOL_SMEAR) {
+ if (lastpos[0] == pos[0] && lastpos[1] == pos[1])
+ return 0;
+
+ paint_2d_convert_brushco(ibufb, lastpos, blastpos);
+ paint_2d_lift_smear(s->canvas, ibufb, blastpos, tile);
+ blend = IMB_BLEND_INTERPOLATE;
+ }
+ else if (s->tool == PAINT_TOOL_CLONE && s->clonecanvas) {
+ liftpos[0] = pos[0] - offset[0] * s->canvas->x;
+ liftpos[1] = pos[1] - offset[1] * s->canvas->y;
+
+ paint_2d_convert_brushco(ibufb, liftpos, bliftpos);
+ clonebuf = paint_2d_lift_clone(s->clonecanvas, ibufb, bliftpos);
+ }
+
+ frombuf = (clonebuf) ? clonebuf : ibufb;
+
+ if (tile) {
+ paint_2d_set_region(region, bpos[0], bpos[1], 0, 0, frombuf->x, frombuf->y);
+ tot = paint_2d_torus_split_region(region, s->canvas, frombuf, tile);
+ }
+ else {
+ paint_2d_set_region(region, bpos[0], bpos[1], 0, 0, frombuf->x, frombuf->y);
+ tot = 1;
+ }
+
+ /* blend into canvas */
+ for (a = 0; a < tot; a++) {
+ ED_imapaint_dirty_region(s->image,
+ s->canvas,
+ region[a].destx,
+ region[a].desty,
+ region[a].width,
+ region[a].height,
+ true);
+
+ if (s->do_masking) {
+ /* masking, find original pixels tiles from undo buffer to composite over */
+ int tilex, tiley, tilew, tileh;
+
+ imapaint_region_tiles(s->canvas,
+ region[a].destx,
+ region[a].desty,
+ region[a].width,
+ region[a].height,
+ &tilex,
+ &tiley,
+ &tilew,
+ &tileh);
+
+ if (tiley == tileh) {
+ paint_2d_do_making_brush(
+ s, &region[a], curveb, texmaskb, frombuf, mask_max, blend, tilex, tiley, tilew, tileh);
+ }
+ else {
+ Paint2DForeachData data;
+ data.s = s;
+ data.region = &region[a];
+ data.curveb = curveb;
+ data.texmaskb = texmaskb;
+ data.frombuf = frombuf;
+ data.mask_max = mask_max;
+ data.blend = blend;
+ data.tilex = tilex;
+ data.tilew = tilew;
+
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ BLI_task_parallel_range(tiley, tileh + 1, &data, paint_2d_op_foreach_do, &settings);
+ }
+ }
+ else {
+ /* no masking, composite brush directly onto canvas */
+ IMB_rectblend_threaded(s->canvas,
+ s->canvas,
+ frombuf,
+ NULL,
+ curveb,
+ texmaskb,
+ mask_max,
+ region[a].destx,
+ region[a].desty,
+ region[a].destx,
+ region[a].desty,
+ region[a].srcx,
+ region[a].srcy,
+ region[a].width,
+ region[a].height,
+ blend,
+ false);
+ }
+ }
+
+ if (clonebuf)
+ IMB_freeImBuf(clonebuf);
+
+ return 1;
}
-
static int paint_2d_canvas_set(ImagePaintState *s, Image *ima)
{
- ImBuf *ibuf = BKE_image_acquire_ibuf(ima, s->sima ? &s->sima->iuser : NULL, NULL);
-
- /* verify that we can paint and set canvas */
- if (ima == NULL) {
- return 0;
- }
- else if (BKE_image_has_packedfile(ima) && ima->rr) {
- s->warnpackedfile = ima->id.name + 2;
- return 0;
- }
- else if (ibuf && ibuf->channels != 4) {
- s->warnmultifile = ima->id.name + 2;
- return 0;
- }
- else if (!ibuf || !(ibuf->rect || ibuf->rect_float))
- return 0;
-
- s->image = ima;
- s->canvas = ibuf;
-
- /* set clone canvas */
- if (s->tool == PAINT_TOOL_CLONE) {
- ima = s->brush->clone.image;
- ibuf = BKE_image_acquire_ibuf(ima, s->sima ? &s->sima->iuser : NULL, NULL);
-
- if (!ima || !ibuf || !(ibuf->rect || ibuf->rect_float)) {
- BKE_image_release_ibuf(ima, ibuf, NULL);
- BKE_image_release_ibuf(s->image, s->canvas, NULL);
- return 0;
- }
-
- s->clonecanvas = ibuf;
-
- /* temporarily add float rect for cloning */
- if (s->canvas->rect_float && !s->clonecanvas->rect_float) {
- IMB_float_from_rect(s->clonecanvas);
- }
- else if (!s->canvas->rect_float && !s->clonecanvas->rect)
- IMB_rect_from_float(s->clonecanvas);
- }
-
- /* set masking */
- s->do_masking = paint_use_opacity_masking(s->brush);
-
- return 1;
+ ImBuf *ibuf = BKE_image_acquire_ibuf(ima, s->sima ? &s->sima->iuser : NULL, NULL);
+
+ /* verify that we can paint and set canvas */
+ if (ima == NULL) {
+ return 0;
+ }
+ else if (BKE_image_has_packedfile(ima) && ima->rr) {
+ s->warnpackedfile = ima->id.name + 2;
+ return 0;
+ }
+ else if (ibuf && ibuf->channels != 4) {
+ s->warnmultifile = ima->id.name + 2;
+ return 0;
+ }
+ else if (!ibuf || !(ibuf->rect || ibuf->rect_float))
+ return 0;
+
+ s->image = ima;
+ s->canvas = ibuf;
+
+ /* set clone canvas */
+ if (s->tool == PAINT_TOOL_CLONE) {
+ ima = s->brush->clone.image;
+ ibuf = BKE_image_acquire_ibuf(ima, s->sima ? &s->sima->iuser : NULL, NULL);
+
+ if (!ima || !ibuf || !(ibuf->rect || ibuf->rect_float)) {
+ BKE_image_release_ibuf(ima, ibuf, NULL);
+ BKE_image_release_ibuf(s->image, s->canvas, NULL);
+ return 0;
+ }
+
+ s->clonecanvas = ibuf;
+
+ /* temporarily add float rect for cloning */
+ if (s->canvas->rect_float && !s->clonecanvas->rect_float) {
+ IMB_float_from_rect(s->clonecanvas);
+ }
+ else if (!s->canvas->rect_float && !s->clonecanvas->rect)
+ IMB_rect_from_float(s->clonecanvas);
+ }
+
+ /* set masking */
+ s->do_masking = paint_use_opacity_masking(s->brush);
+
+ return 1;
}
static void paint_2d_canvas_free(ImagePaintState *s)
{
- BKE_image_release_ibuf(s->image, s->canvas, NULL);
- BKE_image_release_ibuf(s->brush->clone.image, s->clonecanvas, NULL);
+ BKE_image_release_ibuf(s->image, s->canvas, NULL);
+ BKE_image_release_ibuf(s->brush->clone.image, s->clonecanvas, NULL);
- if (s->blurkernel) {
- paint_delete_blur_kernel(s->blurkernel);
- MEM_freeN(s->blurkernel);
- }
+ if (s->blurkernel) {
+ paint_delete_blur_kernel(s->blurkernel);
+ MEM_freeN(s->blurkernel);
+ }
- image_undo_remove_masks();
+ image_undo_remove_masks();
}
-void paint_2d_stroke(void *ps, const float prev_mval[2], const float mval[2], const bool eraser, float pressure, float distance, float size)
+void paint_2d_stroke(void *ps,
+ const float prev_mval[2],
+ const float mval[2],
+ const bool eraser,
+ float pressure,
+ float distance,
+ float size)
{
- float newuv[2], olduv[2];
- ImagePaintState *s = ps;
- BrushPainter *painter = s->painter;
- ImBuf *ibuf = BKE_image_acquire_ibuf(s->image, s->sima ? &s->sima->iuser : NULL, NULL);
- const bool is_data = (ibuf && ibuf->colormanage_flag & IMB_COLORMANAGE_IS_DATA);
+ float newuv[2], olduv[2];
+ ImagePaintState *s = ps;
+ BrushPainter *painter = s->painter;
+ ImBuf *ibuf = BKE_image_acquire_ibuf(s->image, s->sima ? &s->sima->iuser : NULL, NULL);
+ const bool is_data = (ibuf && ibuf->colormanage_flag & IMB_COLORMANAGE_IS_DATA);
- if (!ibuf)
- return;
+ if (!ibuf)
+ return;
- s->blend = s->brush->blend;
- if (eraser)
- s->blend = IMB_BLEND_ERASE_ALPHA;
+ s->blend = s->brush->blend;
+ if (eraser)
+ s->blend = IMB_BLEND_ERASE_ALPHA;
- UI_view2d_region_to_view(s->v2d, mval[0], mval[1], &newuv[0], &newuv[1]);
- UI_view2d_region_to_view(s->v2d, prev_mval[0], prev_mval[1], &olduv[0], &olduv[1]);
+ UI_view2d_region_to_view(s->v2d, mval[0], mval[1], &newuv[0], &newuv[1]);
+ UI_view2d_region_to_view(s->v2d, prev_mval[0], prev_mval[1], &olduv[0], &olduv[1]);
- newuv[0] *= ibuf->x;
- newuv[1] *= ibuf->y;
+ newuv[0] *= ibuf->x;
+ newuv[1] *= ibuf->y;
- olduv[0] *= ibuf->x;
- olduv[1] *= ibuf->y;
+ olduv[0] *= ibuf->x;
+ olduv[1] *= ibuf->y;
- if (painter->firsttouch) {
- float startuv[2];
+ if (painter->firsttouch) {
+ float startuv[2];
- UI_view2d_region_to_view(s->v2d, 0, 0, &startuv[0], &startuv[1]);
+ UI_view2d_region_to_view(s->v2d, 0, 0, &startuv[0], &startuv[1]);
- /* paint exactly once on first touch */
- painter->startpaintpos[0] = startuv[0] * ibuf->x;
- painter->startpaintpos[1] = startuv[1] * ibuf->y;
+ /* paint exactly once on first touch */
+ painter->startpaintpos[0] = startuv[0] * ibuf->x;
+ painter->startpaintpos[1] = startuv[1] * ibuf->y;
- painter->firsttouch = 0;
- copy_v2_v2(painter->lastpaintpos, newuv);
- }
- else {
- copy_v2_v2(painter->lastpaintpos, olduv);
- }
+ painter->firsttouch = 0;
+ copy_v2_v2(painter->lastpaintpos, newuv);
+ }
+ else {
+ copy_v2_v2(painter->lastpaintpos, olduv);
+ }
- /* OCIO_TODO: float buffers are now always linear, so always use color correction
- * this should probably be changed when texture painting color space is supported
- */
- brush_painter_2d_require_imbuf(painter, (ibuf->rect_float != NULL), !is_data);
+ /* OCIO_TODO: float buffers are now always linear, so always use color correction
+ * this should probably be changed when texture painting color space is supported
+ */
+ brush_painter_2d_require_imbuf(painter, (ibuf->rect_float != NULL), !is_data);
- brush_painter_2d_refresh_cache(s, painter, newuv, mval, pressure, distance, size);
+ brush_painter_2d_refresh_cache(s, painter, newuv, mval, pressure, distance, size);
- if (paint_2d_op(s, painter->cache.ibuf, painter->cache.curve_mask, painter->cache.tex_mask, olduv, newuv))
- s->need_redraw = true;
+ if (paint_2d_op(s,
+ painter->cache.ibuf,
+ painter->cache.curve_mask,
+ painter->cache.tex_mask,
+ olduv,
+ newuv))
+ s->need_redraw = true;
- BKE_image_release_ibuf(s->image, ibuf, NULL);
+ BKE_image_release_ibuf(s->image, ibuf, NULL);
}
void *paint_2d_new_stroke(bContext *C, wmOperator *op, int mode)
{
- Scene *scene = CTX_data_scene(C);
- ToolSettings *settings = scene->toolsettings;
- Brush *brush = BKE_paint_brush(&settings->imapaint.paint);
+ Scene *scene = CTX_data_scene(C);
+ ToolSettings *settings = scene->toolsettings;
+ Brush *brush = BKE_paint_brush(&settings->imapaint.paint);
- ImagePaintState *s = MEM_callocN(sizeof(ImagePaintState), "ImagePaintState");
+ ImagePaintState *s = MEM_callocN(sizeof(ImagePaintState), "ImagePaintState");
- s->sima = CTX_wm_space_image(C);
- s->v2d = &CTX_wm_region(C)->v2d;
- s->scene = scene;
- s->screen = CTX_wm_screen(C);
+ s->sima = CTX_wm_space_image(C);
+ s->v2d = &CTX_wm_region(C)->v2d;
+ s->scene = scene;
+ s->screen = CTX_wm_screen(C);
- s->brush = brush;
- s->tool = brush->imagepaint_tool;
- s->blend = brush->blend;
+ s->brush = brush;
+ s->tool = brush->imagepaint_tool;
+ s->blend = brush->blend;
- s->image = s->sima->image;
- s->symmetry = settings->imapaint.paint.symmetry_flags;
+ s->image = s->sima->image;
+ s->symmetry = settings->imapaint.paint.symmetry_flags;
- if (!paint_2d_canvas_set(s, s->image)) {
- if (s->warnmultifile)
- BKE_report(op->reports, RPT_WARNING, "Image requires 4 color channels to paint");
- if (s->warnpackedfile)
- BKE_report(op->reports, RPT_WARNING, "Packed MultiLayer files cannot be painted");
+ if (!paint_2d_canvas_set(s, s->image)) {
+ if (s->warnmultifile)
+ BKE_report(op->reports, RPT_WARNING, "Image requires 4 color channels to paint");
+ if (s->warnpackedfile)
+ BKE_report(op->reports, RPT_WARNING, "Packed MultiLayer files cannot be painted");
- MEM_freeN(s);
- return NULL;
- }
+ MEM_freeN(s);
+ return NULL;
+ }
- if (brush->imagepaint_tool == PAINT_TOOL_SOFTEN) {
- s->blurkernel = paint_new_blur_kernel(brush, false);
- }
+ if (brush->imagepaint_tool == PAINT_TOOL_SOFTEN) {
+ s->blurkernel = paint_new_blur_kernel(brush, false);
+ }
- paint_brush_init_tex(s->brush);
+ paint_brush_init_tex(s->brush);
- /* create painter */
- s->painter = brush_painter_2d_new(scene, s->brush, mode == BRUSH_STROKE_INVERT);
+ /* create painter */
+ s->painter = brush_painter_2d_new(scene, s->brush, mode == BRUSH_STROKE_INVERT);
- return s;
+ return s;
}
void paint_2d_redraw(const bContext *C, void *ps, bool final)
{
- ImagePaintState *s = ps;
-
- if (s->need_redraw) {
- ImBuf *ibuf = BKE_image_acquire_ibuf(s->image, s->sima ? &s->sima->iuser : NULL, NULL);
-
- imapaint_image_update(s->sima, s->image, ibuf, false);
- ED_imapaint_clear_partial_redraw();
-
- BKE_image_release_ibuf(s->image, ibuf, NULL);
-
- s->need_redraw = false;
- }
- else if (!final) {
- return;
- }
-
- if (final) {
- if (s->image && !(s->sima && s->sima->lock))
- GPU_free_image(s->image);
-
- /* compositor listener deals with updating */
- WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, s->image);
- DEG_id_tag_update(&s->image->id, 0);
- }
- else {
- if (!s->sima || !s->sima->lock)
- ED_region_tag_redraw(CTX_wm_region(C));
- else
- WM_event_add_notifier(C, NC_IMAGE | NA_PAINTING, s->image);
- }
+ ImagePaintState *s = ps;
+
+ if (s->need_redraw) {
+ ImBuf *ibuf = BKE_image_acquire_ibuf(s->image, s->sima ? &s->sima->iuser : NULL, NULL);
+
+ imapaint_image_update(s->sima, s->image, ibuf, false);
+ ED_imapaint_clear_partial_redraw();
+
+ BKE_image_release_ibuf(s->image, ibuf, NULL);
+
+ s->need_redraw = false;
+ }
+ else if (!final) {
+ return;
+ }
+
+ if (final) {
+ if (s->image && !(s->sima && s->sima->lock))
+ GPU_free_image(s->image);
+
+ /* compositor listener deals with updating */
+ WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, s->image);
+ DEG_id_tag_update(&s->image->id, 0);
+ }
+ else {
+ if (!s->sima || !s->sima->lock)
+ ED_region_tag_redraw(CTX_wm_region(C));
+ else
+ WM_event_add_notifier(C, NC_IMAGE | NA_PAINTING, s->image);
+ }
}
void paint_2d_stroke_done(void *ps)
{
- ImagePaintState *s = ps;
+ ImagePaintState *s = ps;
- paint_2d_canvas_free(s);
- brush_painter_2d_free(s->painter);
- paint_brush_exit_tex(s->brush);
+ paint_2d_canvas_free(s);
+ brush_painter_2d_free(s->painter);
+ paint_brush_exit_tex(s->brush);
- MEM_freeN(s);
+ MEM_freeN(s);
}
-static void paint_2d_fill_add_pixel_byte(
- const int x_px, const int y_px, ImBuf *ibuf, BLI_Stack *stack, BLI_bitmap *touched,
- const float color[4], float threshold_sq)
+static void paint_2d_fill_add_pixel_byte(const int x_px,
+ const int y_px,
+ ImBuf *ibuf,
+ BLI_Stack *stack,
+ BLI_bitmap *touched,
+ const float color[4],
+ float threshold_sq)
{
- size_t coordinate;
+ size_t coordinate;
- if (x_px >= ibuf->x || x_px < 0 || y_px >= ibuf->y || y_px < 0)
- return;
+ if (x_px >= ibuf->x || x_px < 0 || y_px >= ibuf->y || y_px < 0)
+ return;
- coordinate = ((size_t)y_px) * ibuf->x + x_px;
+ coordinate = ((size_t)y_px) * ibuf->x + x_px;
- if (!BLI_BITMAP_TEST(touched, coordinate)) {
- float color_f[4];
- unsigned char *color_b = (unsigned char *)(ibuf->rect + coordinate);
- rgba_uchar_to_float(color_f, color_b);
- straight_to_premul_v4(color_f);
+ if (!BLI_BITMAP_TEST(touched, coordinate)) {
+ float color_f[4];
+ unsigned char *color_b = (unsigned char *)(ibuf->rect + coordinate);
+ rgba_uchar_to_float(color_f, color_b);
+ straight_to_premul_v4(color_f);
- if (len_squared_v4v4(color_f, color) <= threshold_sq) {
- BLI_stack_push(stack, &coordinate);
- }
- BLI_BITMAP_SET(touched, coordinate, true);
- }
+ if (len_squared_v4v4(color_f, color) <= threshold_sq) {
+ BLI_stack_push(stack, &coordinate);
+ }
+ BLI_BITMAP_SET(touched, coordinate, true);
+ }
}
-static void paint_2d_fill_add_pixel_float(
- const int x_px, const int y_px, ImBuf *ibuf, BLI_Stack *stack, BLI_bitmap *touched,
- const float color[4], float threshold_sq)
+static void paint_2d_fill_add_pixel_float(const int x_px,
+ const int y_px,
+ ImBuf *ibuf,
+ BLI_Stack *stack,
+ BLI_bitmap *touched,
+ const float color[4],
+ float threshold_sq)
{
- size_t coordinate;
+ size_t coordinate;
- if (x_px >= ibuf->x || x_px < 0 || y_px >= ibuf->y || y_px < 0)
- return;
+ if (x_px >= ibuf->x || x_px < 0 || y_px >= ibuf->y || y_px < 0)
+ return;
- coordinate = ((size_t)y_px) * ibuf->x + x_px;
+ coordinate = ((size_t)y_px) * ibuf->x + x_px;
- if (!BLI_BITMAP_TEST(touched, coordinate)) {
- if (len_squared_v4v4(ibuf->rect_float + 4 * coordinate, color) <= threshold_sq) {
- BLI_stack_push(stack, &coordinate);
- }
- BLI_BITMAP_SET(touched, coordinate, true);
- }
+ if (!BLI_BITMAP_TEST(touched, coordinate)) {
+ if (len_squared_v4v4(ibuf->rect_float + 4 * coordinate, color) <= threshold_sq) {
+ BLI_stack_push(stack, &coordinate);
+ }
+ BLI_BITMAP_SET(touched, coordinate, true);
+ }
}
/* this function expects linear space color values */
void paint_2d_bucket_fill(
- const bContext *C, const float color[3], Brush *br,
- const float mouse_init[2],
- void *ps)
+ const bContext *C, const float color[3], Brush *br, const float mouse_init[2], void *ps)
{
- SpaceImage *sima = CTX_wm_space_image(C);
- Image *ima = sima->image;
-
- ImagePaintState *s = ps;
-
- ImBuf *ibuf;
- int x_px, y_px;
- unsigned int color_b;
- float color_f[4];
- float strength = br ? br->alpha : 1.0f;
-
- bool do_float;
-
- if (!ima)
- return;
-
- ibuf = BKE_image_acquire_ibuf(ima, &sima->iuser, NULL);
-
- if (!ibuf)
- return;
-
- do_float = (ibuf->rect_float != NULL);
- /* first check if our image is float. If it is not we should correct the color to
- * be in gamma space. strictly speaking this is not correct, but blender does not paint
- * byte images in linear space */
- if (!do_float) {
- linearrgb_to_srgb_uchar3((unsigned char *)&color_b, color);
- *(((char *)&color_b) + 3) = strength * 255;
- }
- else {
- copy_v3_v3(color_f, color);
- color_f[3] = strength;
- }
-
- if (!mouse_init || !br) {
- /* first case, no image UV, fill the whole image */
- ED_imapaint_dirty_region(ima, ibuf, 0, 0, ibuf->x, ibuf->y, false);
-
- if (do_float) {
- for (x_px = 0; x_px < ibuf->x; x_px++) {
- for (y_px = 0; y_px < ibuf->y; y_px++) {
- blend_color_mix_float(
- ibuf->rect_float + 4 * (((size_t)y_px) * ibuf->x + x_px),
- ibuf->rect_float + 4 * (((size_t)y_px) * ibuf->x + x_px), color_f);
- }
- }
- }
- else {
- for (x_px = 0; x_px < ibuf->x; x_px++) {
- for (y_px = 0; y_px < ibuf->y; y_px++) {
- blend_color_mix_byte(
- (unsigned char *)(ibuf->rect + ((size_t)y_px) * ibuf->x + x_px),
- (unsigned char *)(ibuf->rect + ((size_t)y_px) * ibuf->x + x_px), (unsigned char *)&color_b);
- }
- }
- }
- }
- else {
- /* second case, start sweeping the neighboring pixels, looking for pixels whose
- * value is within the brush fill threshold from the fill color */
- BLI_Stack *stack;
- BLI_bitmap *touched;
- size_t coordinate;
- int width = ibuf->x;
- float image_init[2];
- int minx = ibuf->x, miny = ibuf->y, maxx = 0, maxy = 0;
- float pixel_color[4];
- /* We are comparing to sum of three squared values
- * (assumed in range [0,1]), so need to multiply... */
- float threshold_sq = br->fill_threshold * br->fill_threshold * 3;
-
- UI_view2d_region_to_view(s->v2d, mouse_init[0], mouse_init[1], &image_init[0], &image_init[1]);
-
- x_px = image_init[0] * ibuf->x;
- y_px = image_init[1] * ibuf->y;
-
- if (x_px >= ibuf->x || x_px < 0 || y_px > ibuf->y || y_px < 0) {
- BKE_image_release_ibuf(ima, ibuf, NULL);
- return;
- }
-
- /* change image invalidation method later */
- ED_imapaint_dirty_region(ima, ibuf, 0, 0, ibuf->x, ibuf->y, false);
-
- stack = BLI_stack_new(sizeof(size_t), __func__);
- touched = BLI_BITMAP_NEW(((size_t)ibuf->x) * ibuf->y, "bucket_fill_bitmap");
-
- coordinate = (((size_t)y_px) * ibuf->x + x_px);
-
- if (do_float) {
- copy_v4_v4(pixel_color, ibuf->rect_float + 4 * coordinate);
- }
- else {
- int pixel_color_b = *(ibuf->rect + coordinate);
- rgba_uchar_to_float(pixel_color, (unsigned char *)&pixel_color_b);
- straight_to_premul_v4(pixel_color);
- }
-
- BLI_stack_push(stack, &coordinate);
- BLI_BITMAP_SET(touched, coordinate, true);
-
- if (do_float) {
- while (!BLI_stack_is_empty(stack)) {
- BLI_stack_pop(stack, &coordinate);
-
- IMB_blend_color_float(
- ibuf->rect_float + 4 * (coordinate),
- ibuf->rect_float + 4 * (coordinate),
- color_f, br->blend);
-
- /* reconstruct the coordinates here */
- x_px = coordinate % width;
- y_px = coordinate / width;
-
- paint_2d_fill_add_pixel_float(x_px - 1, y_px - 1, ibuf, stack, touched, pixel_color, threshold_sq);
- paint_2d_fill_add_pixel_float(x_px - 1, y_px, ibuf, stack, touched, pixel_color, threshold_sq);
- paint_2d_fill_add_pixel_float(x_px - 1, y_px + 1, ibuf, stack, touched, pixel_color, threshold_sq);
- paint_2d_fill_add_pixel_float(x_px, y_px + 1, ibuf, stack, touched, pixel_color, threshold_sq);
- paint_2d_fill_add_pixel_float(x_px, y_px - 1, ibuf, stack, touched, pixel_color, threshold_sq);
- paint_2d_fill_add_pixel_float(x_px + 1, y_px - 1, ibuf, stack, touched, pixel_color, threshold_sq);
- paint_2d_fill_add_pixel_float(x_px + 1, y_px, ibuf, stack, touched, pixel_color, threshold_sq);
- paint_2d_fill_add_pixel_float(x_px + 1, y_px + 1, ibuf, stack, touched, pixel_color, threshold_sq);
-
- if (x_px > maxx)
- maxx = x_px;
- if (x_px < minx)
- minx = x_px;
- if (y_px > maxy)
- maxy = y_px;
- if (x_px > miny)
- miny = y_px;
- }
- }
- else {
- while (!BLI_stack_is_empty(stack)) {
- BLI_stack_pop(stack, &coordinate);
-
- IMB_blend_color_byte(
- (unsigned char *)(ibuf->rect + coordinate),
- (unsigned char *)(ibuf->rect + coordinate),
- (unsigned char *)&color_b, br->blend);
-
- /* reconstruct the coordinates here */
- x_px = coordinate % width;
- y_px = coordinate / width;
-
- paint_2d_fill_add_pixel_byte(x_px - 1, y_px - 1, ibuf, stack, touched, pixel_color, threshold_sq);
- paint_2d_fill_add_pixel_byte(x_px - 1, y_px, ibuf, stack, touched, pixel_color, threshold_sq);
- paint_2d_fill_add_pixel_byte(x_px - 1, y_px + 1, ibuf, stack, touched, pixel_color, threshold_sq);
- paint_2d_fill_add_pixel_byte(x_px, y_px + 1, ibuf, stack, touched, pixel_color, threshold_sq);
- paint_2d_fill_add_pixel_byte(x_px, y_px - 1, ibuf, stack, touched, pixel_color, threshold_sq);
- paint_2d_fill_add_pixel_byte(x_px + 1, y_px - 1, ibuf, stack, touched, pixel_color, threshold_sq);
- paint_2d_fill_add_pixel_byte(x_px + 1, y_px, ibuf, stack, touched, pixel_color, threshold_sq);
- paint_2d_fill_add_pixel_byte(x_px + 1, y_px + 1, ibuf, stack, touched, pixel_color, threshold_sq);
-
- if (x_px > maxx)
- maxx = x_px;
- if (x_px < minx)
- minx = x_px;
- if (y_px > maxy)
- maxy = y_px;
- if (x_px > miny)
- miny = y_px;
- }
- }
-
- MEM_freeN(touched);
- BLI_stack_free(stack);
- }
-
- imapaint_image_update(sima, ima, ibuf, false);
- ED_imapaint_clear_partial_redraw();
-
- BKE_image_release_ibuf(ima, ibuf, NULL);
-
- WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, ima);
+ SpaceImage *sima = CTX_wm_space_image(C);
+ Image *ima = sima->image;
+
+ ImagePaintState *s = ps;
+
+ ImBuf *ibuf;
+ int x_px, y_px;
+ unsigned int color_b;
+ float color_f[4];
+ float strength = br ? br->alpha : 1.0f;
+
+ bool do_float;
+
+ if (!ima)
+ return;
+
+ ibuf = BKE_image_acquire_ibuf(ima, &sima->iuser, NULL);
+
+ if (!ibuf)
+ return;
+
+ do_float = (ibuf->rect_float != NULL);
+ /* first check if our image is float. If it is not we should correct the color to
+ * be in gamma space. strictly speaking this is not correct, but blender does not paint
+ * byte images in linear space */
+ if (!do_float) {
+ linearrgb_to_srgb_uchar3((unsigned char *)&color_b, color);
+ *(((char *)&color_b) + 3) = strength * 255;
+ }
+ else {
+ copy_v3_v3(color_f, color);
+ color_f[3] = strength;
+ }
+
+ if (!mouse_init || !br) {
+ /* first case, no image UV, fill the whole image */
+ ED_imapaint_dirty_region(ima, ibuf, 0, 0, ibuf->x, ibuf->y, false);
+
+ if (do_float) {
+ for (x_px = 0; x_px < ibuf->x; x_px++) {
+ for (y_px = 0; y_px < ibuf->y; y_px++) {
+ blend_color_mix_float(ibuf->rect_float + 4 * (((size_t)y_px) * ibuf->x + x_px),
+ ibuf->rect_float + 4 * (((size_t)y_px) * ibuf->x + x_px),
+ color_f);
+ }
+ }
+ }
+ else {
+ for (x_px = 0; x_px < ibuf->x; x_px++) {
+ for (y_px = 0; y_px < ibuf->y; y_px++) {
+ blend_color_mix_byte((unsigned char *)(ibuf->rect + ((size_t)y_px) * ibuf->x + x_px),
+ (unsigned char *)(ibuf->rect + ((size_t)y_px) * ibuf->x + x_px),
+ (unsigned char *)&color_b);
+ }
+ }
+ }
+ }
+ else {
+ /* second case, start sweeping the neighboring pixels, looking for pixels whose
+ * value is within the brush fill threshold from the fill color */
+ BLI_Stack *stack;
+ BLI_bitmap *touched;
+ size_t coordinate;
+ int width = ibuf->x;
+ float image_init[2];
+ int minx = ibuf->x, miny = ibuf->y, maxx = 0, maxy = 0;
+ float pixel_color[4];
+ /* We are comparing to sum of three squared values
+ * (assumed in range [0,1]), so need to multiply... */
+ float threshold_sq = br->fill_threshold * br->fill_threshold * 3;
+
+ UI_view2d_region_to_view(s->v2d, mouse_init[0], mouse_init[1], &image_init[0], &image_init[1]);
+
+ x_px = image_init[0] * ibuf->x;
+ y_px = image_init[1] * ibuf->y;
+
+ if (x_px >= ibuf->x || x_px < 0 || y_px > ibuf->y || y_px < 0) {
+ BKE_image_release_ibuf(ima, ibuf, NULL);
+ return;
+ }
+
+ /* change image invalidation method later */
+ ED_imapaint_dirty_region(ima, ibuf, 0, 0, ibuf->x, ibuf->y, false);
+
+ stack = BLI_stack_new(sizeof(size_t), __func__);
+ touched = BLI_BITMAP_NEW(((size_t)ibuf->x) * ibuf->y, "bucket_fill_bitmap");
+
+ coordinate = (((size_t)y_px) * ibuf->x + x_px);
+
+ if (do_float) {
+ copy_v4_v4(pixel_color, ibuf->rect_float + 4 * coordinate);
+ }
+ else {
+ int pixel_color_b = *(ibuf->rect + coordinate);
+ rgba_uchar_to_float(pixel_color, (unsigned char *)&pixel_color_b);
+ straight_to_premul_v4(pixel_color);
+ }
+
+ BLI_stack_push(stack, &coordinate);
+ BLI_BITMAP_SET(touched, coordinate, true);
+
+ if (do_float) {
+ while (!BLI_stack_is_empty(stack)) {
+ BLI_stack_pop(stack, &coordinate);
+
+ IMB_blend_color_float(ibuf->rect_float + 4 * (coordinate),
+ ibuf->rect_float + 4 * (coordinate),
+ color_f,
+ br->blend);
+
+ /* reconstruct the coordinates here */
+ x_px = coordinate % width;
+ y_px = coordinate / width;
+
+ paint_2d_fill_add_pixel_float(
+ x_px - 1, y_px - 1, ibuf, stack, touched, pixel_color, threshold_sq);
+ paint_2d_fill_add_pixel_float(
+ x_px - 1, y_px, ibuf, stack, touched, pixel_color, threshold_sq);
+ paint_2d_fill_add_pixel_float(
+ x_px - 1, y_px + 1, ibuf, stack, touched, pixel_color, threshold_sq);
+ paint_2d_fill_add_pixel_float(
+ x_px, y_px + 1, ibuf, stack, touched, pixel_color, threshold_sq);
+ paint_2d_fill_add_pixel_float(
+ x_px, y_px - 1, ibuf, stack, touched, pixel_color, threshold_sq);
+ paint_2d_fill_add_pixel_float(
+ x_px + 1, y_px - 1, ibuf, stack, touched, pixel_color, threshold_sq);
+ paint_2d_fill_add_pixel_float(
+ x_px + 1, y_px, ibuf, stack, touched, pixel_color, threshold_sq);
+ paint_2d_fill_add_pixel_float(
+ x_px + 1, y_px + 1, ibuf, stack, touched, pixel_color, threshold_sq);
+
+ if (x_px > maxx)
+ maxx = x_px;
+ if (x_px < minx)
+ minx = x_px;
+ if (y_px > maxy)
+ maxy = y_px;
+ if (x_px > miny)
+ miny = y_px;
+ }
+ }
+ else {
+ while (!BLI_stack_is_empty(stack)) {
+ BLI_stack_pop(stack, &coordinate);
+
+ IMB_blend_color_byte((unsigned char *)(ibuf->rect + coordinate),
+ (unsigned char *)(ibuf->rect + coordinate),
+ (unsigned char *)&color_b,
+ br->blend);
+
+ /* reconstruct the coordinates here */
+ x_px = coordinate % width;
+ y_px = coordinate / width;
+
+ paint_2d_fill_add_pixel_byte(
+ x_px - 1, y_px - 1, ibuf, stack, touched, pixel_color, threshold_sq);
+ paint_2d_fill_add_pixel_byte(
+ x_px - 1, y_px, ibuf, stack, touched, pixel_color, threshold_sq);
+ paint_2d_fill_add_pixel_byte(
+ x_px - 1, y_px + 1, ibuf, stack, touched, pixel_color, threshold_sq);
+ paint_2d_fill_add_pixel_byte(
+ x_px, y_px + 1, ibuf, stack, touched, pixel_color, threshold_sq);
+ paint_2d_fill_add_pixel_byte(
+ x_px, y_px - 1, ibuf, stack, touched, pixel_color, threshold_sq);
+ paint_2d_fill_add_pixel_byte(
+ x_px + 1, y_px - 1, ibuf, stack, touched, pixel_color, threshold_sq);
+ paint_2d_fill_add_pixel_byte(
+ x_px + 1, y_px, ibuf, stack, touched, pixel_color, threshold_sq);
+ paint_2d_fill_add_pixel_byte(
+ x_px + 1, y_px + 1, ibuf, stack, touched, pixel_color, threshold_sq);
+
+ if (x_px > maxx)
+ maxx = x_px;
+ if (x_px < minx)
+ minx = x_px;
+ if (y_px > maxy)
+ maxy = y_px;
+ if (x_px > miny)
+ miny = y_px;
+ }
+ }
+
+ MEM_freeN(touched);
+ BLI_stack_free(stack);
+ }
+
+ imapaint_image_update(sima, ima, ibuf, false);
+ ED_imapaint_clear_partial_redraw();
+
+ BKE_image_release_ibuf(ima, ibuf, NULL);
+
+ WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, ima);
}
void paint_2d_gradient_fill(
- const bContext *C, Brush *br,
- const float mouse_init[2], const float mouse_final[2],
- void *ps)
+ const bContext *C, Brush *br, const float mouse_init[2], const float mouse_final[2], void *ps)
{
- SpaceImage *sima = CTX_wm_space_image(C);
- Image *ima = sima->image;
- ImagePaintState *s = ps;
-
- ImBuf *ibuf;
- int x_px, y_px;
- unsigned int color_b;
- float color_f[4];
- float image_init[2], image_final[2];
- float tangent[2];
- float line_len_sq_inv, line_len;
-
- bool do_float;
-
- if (!ima)
- return;
-
- ibuf = BKE_image_acquire_ibuf(ima, &sima->iuser, NULL);
-
- if (!ibuf)
- return;
-
- UI_view2d_region_to_view(s->v2d, mouse_final[0], mouse_final[1], &image_final[0], &image_final[1]);
- UI_view2d_region_to_view(s->v2d, mouse_init[0], mouse_init[1], &image_init[0], &image_init[1]);
-
- image_final[0] *= ibuf->x;
- image_final[1] *= ibuf->y;
-
- image_init[0] *= ibuf->x;
- image_init[1] *= ibuf->y;
-
- /* some math to get needed gradient variables */
- sub_v2_v2v2(tangent, image_final, image_init);
- line_len = len_squared_v2(tangent);
- line_len_sq_inv = 1.0f / line_len;
- line_len = sqrtf(line_len);
-
- do_float = (ibuf->rect_float != NULL);
-
- /* this will be substituted by something else when selection is available */
- ED_imapaint_dirty_region(ima, ibuf, 0, 0, ibuf->x, ibuf->y, false);
-
- if (do_float) {
- for (x_px = 0; x_px < ibuf->x; x_px++) {
- for (y_px = 0; y_px < ibuf->y; y_px++) {
- float f;
- float p[2] = {x_px - image_init[0], y_px - image_init[1]};
-
- switch (br->gradient_fill_mode) {
- case BRUSH_GRADIENT_LINEAR:
- {
- f = dot_v2v2(p, tangent) * line_len_sq_inv;
- break;
- }
- case BRUSH_GRADIENT_RADIAL:
- default:
- {
- f = len_v2(p) / line_len;
- break;
- }
- }
- BKE_colorband_evaluate(br->gradient, f, color_f);
- /* convert to premultiplied */
- mul_v3_fl(color_f, color_f[3]);
- color_f[3] *= br->alpha;
- IMB_blend_color_float(
- ibuf->rect_float + 4 * (((size_t)y_px) * ibuf->x + x_px),
- ibuf->rect_float + 4 * (((size_t)y_px) * ibuf->x + x_px),
- color_f, br->blend);
- }
- }
- }
- else {
- for (x_px = 0; x_px < ibuf->x; x_px++) {
- for (y_px = 0; y_px < ibuf->y; y_px++) {
- float f;
- float p[2] = {x_px - image_init[0], y_px - image_init[1]};
-
- switch (br->gradient_fill_mode) {
- case BRUSH_GRADIENT_LINEAR:
- {
- f = dot_v2v2(p, tangent) * line_len_sq_inv;
- break;
- }
- case BRUSH_GRADIENT_RADIAL:
- default:
- {
- f = len_v2(p) / line_len;
- break;
- }
- }
-
- BKE_colorband_evaluate(br->gradient, f, color_f);
- linearrgb_to_srgb_v3_v3(color_f, color_f);
- rgba_float_to_uchar((unsigned char *)&color_b, color_f);
- ((unsigned char *)&color_b)[3] *= br->alpha;
- IMB_blend_color_byte(
- (unsigned char *)(ibuf->rect + ((size_t)y_px) * ibuf->x + x_px),
- (unsigned char *)(ibuf->rect + ((size_t)y_px) * ibuf->x + x_px),
- (unsigned char *)&color_b, br->blend);
- }
- }
- }
-
- imapaint_image_update(sima, ima, ibuf, false);
- ED_imapaint_clear_partial_redraw();
-
- BKE_image_release_ibuf(ima, ibuf, NULL);
-
- WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, ima);
+ SpaceImage *sima = CTX_wm_space_image(C);
+ Image *ima = sima->image;
+ ImagePaintState *s = ps;
+
+ ImBuf *ibuf;
+ int x_px, y_px;
+ unsigned int color_b;
+ float color_f[4];
+ float image_init[2], image_final[2];
+ float tangent[2];
+ float line_len_sq_inv, line_len;
+
+ bool do_float;
+
+ if (!ima)
+ return;
+
+ ibuf = BKE_image_acquire_ibuf(ima, &sima->iuser, NULL);
+
+ if (!ibuf)
+ return;
+
+ UI_view2d_region_to_view(
+ s->v2d, mouse_final[0], mouse_final[1], &image_final[0], &image_final[1]);
+ UI_view2d_region_to_view(s->v2d, mouse_init[0], mouse_init[1], &image_init[0], &image_init[1]);
+
+ image_final[0] *= ibuf->x;
+ image_final[1] *= ibuf->y;
+
+ image_init[0] *= ibuf->x;
+ image_init[1] *= ibuf->y;
+
+ /* some math to get needed gradient variables */
+ sub_v2_v2v2(tangent, image_final, image_init);
+ line_len = len_squared_v2(tangent);
+ line_len_sq_inv = 1.0f / line_len;
+ line_len = sqrtf(line_len);
+
+ do_float = (ibuf->rect_float != NULL);
+
+ /* this will be substituted by something else when selection is available */
+ ED_imapaint_dirty_region(ima, ibuf, 0, 0, ibuf->x, ibuf->y, false);
+
+ if (do_float) {
+ for (x_px = 0; x_px < ibuf->x; x_px++) {
+ for (y_px = 0; y_px < ibuf->y; y_px++) {
+ float f;
+ float p[2] = {x_px - image_init[0], y_px - image_init[1]};
+
+ switch (br->gradient_fill_mode) {
+ case BRUSH_GRADIENT_LINEAR: {
+ f = dot_v2v2(p, tangent) * line_len_sq_inv;
+ break;
+ }
+ case BRUSH_GRADIENT_RADIAL:
+ default: {
+ f = len_v2(p) / line_len;
+ break;
+ }
+ }
+ BKE_colorband_evaluate(br->gradient, f, color_f);
+ /* convert to premultiplied */
+ mul_v3_fl(color_f, color_f[3]);
+ color_f[3] *= br->alpha;
+ IMB_blend_color_float(ibuf->rect_float + 4 * (((size_t)y_px) * ibuf->x + x_px),
+ ibuf->rect_float + 4 * (((size_t)y_px) * ibuf->x + x_px),
+ color_f,
+ br->blend);
+ }
+ }
+ }
+ else {
+ for (x_px = 0; x_px < ibuf->x; x_px++) {
+ for (y_px = 0; y_px < ibuf->y; y_px++) {
+ float f;
+ float p[2] = {x_px - image_init[0], y_px - image_init[1]};
+
+ switch (br->gradient_fill_mode) {
+ case BRUSH_GRADIENT_LINEAR: {
+ f = dot_v2v2(p, tangent) * line_len_sq_inv;
+ break;
+ }
+ case BRUSH_GRADIENT_RADIAL:
+ default: {
+ f = len_v2(p) / line_len;
+ break;
+ }
+ }
+
+ BKE_colorband_evaluate(br->gradient, f, color_f);
+ linearrgb_to_srgb_v3_v3(color_f, color_f);
+ rgba_float_to_uchar((unsigned char *)&color_b, color_f);
+ ((unsigned char *)&color_b)[3] *= br->alpha;
+ IMB_blend_color_byte((unsigned char *)(ibuf->rect + ((size_t)y_px) * ibuf->x + x_px),
+ (unsigned char *)(ibuf->rect + ((size_t)y_px) * ibuf->x + x_px),
+ (unsigned char *)&color_b,
+ br->blend);
+ }
+ }
+ }
+
+ imapaint_image_update(sima, ima, ibuf, false);
+ ED_imapaint_clear_partial_redraw();
+
+ BKE_image_release_ibuf(ima, ibuf, NULL);
+
+ WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, ima);
}
diff --git a/source/blender/editors/sculpt_paint/paint_image_proj.c b/source/blender/editors/sculpt_paint/paint_image_proj.c
index 45ae3e9dc11..7a99f819913 100644
--- a/source/blender/editors/sculpt_paint/paint_image_proj.c
+++ b/source/blender/editors/sculpt_paint/paint_image_proj.c
@@ -45,7 +45,6 @@
#include "BLT_translation.h"
-
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
@@ -114,7 +113,7 @@ static void partial_redraw_array_init(ImagePaintPartialRedraw *pr);
/* unit_float_to_uchar_clamp as inline function */
BLI_INLINE unsigned char f_to_char(const float val)
{
- return unit_float_to_uchar_clamp(val);
+ return unit_float_to_uchar_clamp(val);
}
/* ProjectionPaint defines */
@@ -131,58 +130,56 @@ BLI_INLINE unsigned char f_to_char(const float val)
#define PROJ_BUCKET_RECT_MAX 256
#define PROJ_BOUNDBOX_DIV 8
-#define PROJ_BOUNDBOX_SQUARED (PROJ_BOUNDBOX_DIV * PROJ_BOUNDBOX_DIV)
+#define PROJ_BOUNDBOX_SQUARED (PROJ_BOUNDBOX_DIV * PROJ_BOUNDBOX_DIV)
//#define PROJ_DEBUG_PAINT 1
//#define PROJ_DEBUG_NOSEAMBLEED 1
//#define PROJ_DEBUG_PRINT_CLIP 1
#define PROJ_DEBUG_WINCLIP 1
-
#ifndef PROJ_DEBUG_NOSEAMBLEED
/* projectFaceSeamFlags options */
-//#define PROJ_FACE_IGNORE (1<<0) /* When the face is hidden, backfacing or occluded */
-//#define PROJ_FACE_INIT (1<<1) /* When we have initialized the faces data */
+//#define PROJ_FACE_IGNORE (1<<0) /* When the face is hidden, backfacing or occluded */
+//#define PROJ_FACE_INIT (1<<1) /* When we have initialized the faces data */
/* If this face has a seam on any of its edges. */
-#define PROJ_FACE_SEAM0 (1 << 0)
-#define PROJ_FACE_SEAM1 (1 << 1)
-#define PROJ_FACE_SEAM2 (1 << 2)
+# define PROJ_FACE_SEAM0 (1 << 0)
+# define PROJ_FACE_SEAM1 (1 << 1)
+# define PROJ_FACE_SEAM2 (1 << 2)
-#define PROJ_FACE_NOSEAM0 (1 << 4)
-#define PROJ_FACE_NOSEAM1 (1 << 5)
-#define PROJ_FACE_NOSEAM2 (1 << 6)
+# define PROJ_FACE_NOSEAM0 (1 << 4)
+# define PROJ_FACE_NOSEAM1 (1 << 5)
+# define PROJ_FACE_NOSEAM2 (1 << 6)
/* If the seam is completely initialized, including adjecent seams. */
-#define PROJ_FACE_SEAM_INIT0 (1 << 8)
-#define PROJ_FACE_SEAM_INIT1 (1 << 9)
-#define PROJ_FACE_SEAM_INIT2 (1 << 10)
+# define PROJ_FACE_SEAM_INIT0 (1 << 8)
+# define PROJ_FACE_SEAM_INIT1 (1 << 9)
+# define PROJ_FACE_SEAM_INIT2 (1 << 10)
-#define PROJ_FACE_DEGENERATE (1 << 12)
+# define PROJ_FACE_DEGENERATE (1 << 12)
/* face winding */
-#define PROJ_FACE_WINDING_INIT 1
-#define PROJ_FACE_WINDING_CW 2
+# define PROJ_FACE_WINDING_INIT 1
+# define PROJ_FACE_WINDING_CW 2
/* a slightly scaled down face is used to get fake 3D location for edge pixels in the seams
* as this number approaches 1.0f the likelihood increases of float precision errors where
* it is occluded by an adjacent face */
-#define PROJ_FACE_SCALE_SEAM 0.99f
-#endif /* PROJ_DEBUG_NOSEAMBLEED */
-
+# define PROJ_FACE_SCALE_SEAM 0.99f
+#endif /* PROJ_DEBUG_NOSEAMBLEED */
-#define PROJ_SRC_VIEW 1
-#define PROJ_SRC_IMAGE_CAM 2
+#define PROJ_SRC_VIEW 1
+#define PROJ_SRC_IMAGE_CAM 2
#define PROJ_SRC_IMAGE_VIEW 3
-#define PROJ_SRC_VIEW_FILL 4
+#define PROJ_SRC_VIEW_FILL 4
#define PROJ_VIEW_DATA_ID "view_data"
/* viewmat + winmat + clip_start + clip_end + is_ortho */
#define PROJ_VIEW_DATA_SIZE (4 * 4 + 4 * 4 + 3)
-#define PROJ_BUCKET_NULL 0
-#define PROJ_BUCKET_INIT (1 << 0)
-// #define PROJ_BUCKET_CLONE_INIT (1<<1)
+#define PROJ_BUCKET_NULL 0
+#define PROJ_BUCKET_INIT (1 << 0)
+// #define PROJ_BUCKET_CLONE_INIT (1<<1)
/* used for testing doubles, if a point is on a line etc */
#define PROJ_GEOM_TOLERANCE 0.00075f
@@ -198,605 +195,595 @@ BLI_INLINE unsigned char f_to_char(const float val)
* their imbufs, etc, in 1 array, When using threads this array is copied for each thread
* because 'partRedrawRect' and 'touch' values would not be thread safe */
typedef struct ProjPaintImage {
- Image *ima;
- ImBuf *ibuf;
- ImagePaintPartialRedraw *partRedrawRect;
- /** Only used to build undo tiles during painting. */
- volatile void **undoRect;
- /** The mask accumulation must happen on canvas, not on space screen bucket.
- * Here we store the mask rectangle. */
- unsigned short **maskRect;
- /** Store flag to enforce validation of undo rectangle. */
- bool **valid;
- bool touch;
+ Image *ima;
+ ImBuf *ibuf;
+ ImagePaintPartialRedraw *partRedrawRect;
+ /** Only used to build undo tiles during painting. */
+ volatile void **undoRect;
+ /** The mask accumulation must happen on canvas, not on space screen bucket.
+ * Here we store the mask rectangle. */
+ unsigned short **maskRect;
+ /** Store flag to enforce validation of undo rectangle. */
+ bool **valid;
+ bool touch;
} ProjPaintImage;
/**
* Handle for stroke (operator customdata)
*/
typedef struct ProjStrokeHandle {
- /* Support for painting from multiple views at once,
- * currently used to implement symmetry painting,
- * we can assume at least the first is set while painting. */
- struct ProjPaintState *ps_views[8];
- int ps_views_tot;
- int symmetry_flags;
+ /* Support for painting from multiple views at once,
+ * currently used to implement symmetry painting,
+ * we can assume at least the first is set while painting. */
+ struct ProjPaintState *ps_views[8];
+ int ps_views_tot;
+ int symmetry_flags;
- int orig_brush_size;
+ int orig_brush_size;
- bool need_redraw;
+ bool need_redraw;
- /* trick to bypass regular paint and allow clone picking */
- bool is_clone_cursor_pick;
+ /* trick to bypass regular paint and allow clone picking */
+ bool is_clone_cursor_pick;
- /* In ProjPaintState, only here for convenience */
- Scene *scene;
- Brush *brush;
+ /* In ProjPaintState, only here for convenience */
+ Scene *scene;
+ Brush *brush;
} ProjStrokeHandle;
typedef struct LoopSeamData {
- float seam_uvs[2][2];
- float seam_puvs[2][2];
- float corner_dist_sq[2];
+ float seam_uvs[2][2];
+ float seam_puvs[2][2];
+ float corner_dist_sq[2];
} LoopSeamData;
/* Main projection painting struct passed to all projection painting functions */
typedef struct ProjPaintState {
- View3D *v3d;
- RegionView3D *rv3d;
- ARegion *ar;
- Depsgraph *depsgraph;
- Scene *scene;
- /* PROJ_SRC_**** */
- int source;
-
- /* the paint color. It can change depending of inverted mode or not */
- float paint_color[3];
- float paint_color_linear[3];
- float dither;
-
- Brush *brush;
- short tool, blend, mode;
-
- float brush_size;
- Object *ob;
- /* for symmetry, we need to store modified object matrix */
- float obmat[4][4];
- float obmat_imat[4][4];
- /* end similarities with ImagePaintState */
-
- Image *stencil_ima;
- Image *canvas_ima;
- Image *clone_ima;
- float stencil_value;
-
- /* projection painting only */
- /** for multithreading, the first item is sometimes used for non threaded cases too. */
- MemArena *arena_mt[BLENDER_MAX_THREADS];
- /** screen sized 2D array, each pixel has a linked list of ProjPixel's */
- LinkNode **bucketRect;
- /** bucketRect aligned array linkList of faces overlapping each bucket. */
- LinkNode **bucketFaces;
- /** store if the bucks have been initialized. */
- unsigned char *bucketFlags;
-
- /** store options per vert, now only store if the vert is pointing away from the view. */
- char *vertFlags;
- /** The size of the bucket grid, the grid span's screenMin/screenMax
- * so you can paint outsize the screen or with 2 brushes at once. */
- int buckets_x;
- int buckets_y;
-
- /** result of project_paint_pixel_sizeof(), constant per stroke. */
- int pixel_sizeof;
-
- /** size of projectImages array. */
- int image_tot;
-
- /** verts projected into floating point screen space. */
- float (*screenCoords)[4];
- /** 2D bounds for mesh verts on the screen's plane (screenspace). */
- float screenMin[2];
- float screenMax[2];
- /** Calculated from screenMin & screenMax. */
- float screen_width;
- float screen_height;
- /** from the carea or from the projection render. */
- int winx, winy;
-
- /* options for projection painting */
- bool do_layer_clone;
- bool do_layer_stencil;
- bool do_layer_stencil_inv;
- bool do_stencil_brush;
- bool do_material_slots;
-
- /** Use raytraced occlusion? - ortherwise will paint right through to the back. */
- bool do_occlude;
- /** ignore faces with normals pointing away,
- * skips a lot of raycasts if your normals are correctly flipped. */
- bool do_backfacecull;
- /** mask out pixels based on their normals. */
- bool do_mask_normal;
- /** mask out pixels based on cavity. */
- bool do_mask_cavity;
- /** what angle to mask at. */
- float normal_angle;
- /** cos(normal_angle), faster to compare. */
- float normal_angle__cos;
- float normal_angle_inner;
- float normal_angle_inner__cos;
- /** difference between normal_angle and normal_angle_inner, for easy access. */
- float normal_angle_range;
-
- /** quick access to (me->editflag & ME_EDIT_PAINT_FACE_SEL) */
- bool do_face_sel;
- bool is_ortho;
- /** the object is negative scaled. */
- bool is_flip_object;
- /** use masking during painting. Some operations such as airbrush may disable. */
- bool do_masking;
- /** only to avoid running. */
- bool is_texbrush;
- /** mask brush is applied before masking. */
- bool is_maskbrush;
+ View3D *v3d;
+ RegionView3D *rv3d;
+ ARegion *ar;
+ Depsgraph *depsgraph;
+ Scene *scene;
+ /* PROJ_SRC_**** */
+ int source;
+
+ /* the paint color. It can change depending of inverted mode or not */
+ float paint_color[3];
+ float paint_color_linear[3];
+ float dither;
+
+ Brush *brush;
+ short tool, blend, mode;
+
+ float brush_size;
+ Object *ob;
+ /* for symmetry, we need to store modified object matrix */
+ float obmat[4][4];
+ float obmat_imat[4][4];
+ /* end similarities with ImagePaintState */
+
+ Image *stencil_ima;
+ Image *canvas_ima;
+ Image *clone_ima;
+ float stencil_value;
+
+ /* projection painting only */
+ /** for multithreading, the first item is sometimes used for non threaded cases too. */
+ MemArena *arena_mt[BLENDER_MAX_THREADS];
+ /** screen sized 2D array, each pixel has a linked list of ProjPixel's */
+ LinkNode **bucketRect;
+ /** bucketRect aligned array linkList of faces overlapping each bucket. */
+ LinkNode **bucketFaces;
+ /** store if the bucks have been initialized. */
+ unsigned char *bucketFlags;
+
+ /** store options per vert, now only store if the vert is pointing away from the view. */
+ char *vertFlags;
+ /** The size of the bucket grid, the grid span's screenMin/screenMax
+ * so you can paint outsize the screen or with 2 brushes at once. */
+ int buckets_x;
+ int buckets_y;
+
+ /** result of project_paint_pixel_sizeof(), constant per stroke. */
+ int pixel_sizeof;
+
+ /** size of projectImages array. */
+ int image_tot;
+
+ /** verts projected into floating point screen space. */
+ float (*screenCoords)[4];
+ /** 2D bounds for mesh verts on the screen's plane (screenspace). */
+ float screenMin[2];
+ float screenMax[2];
+ /** Calculated from screenMin & screenMax. */
+ float screen_width;
+ float screen_height;
+ /** from the carea or from the projection render. */
+ int winx, winy;
+
+ /* options for projection painting */
+ bool do_layer_clone;
+ bool do_layer_stencil;
+ bool do_layer_stencil_inv;
+ bool do_stencil_brush;
+ bool do_material_slots;
+
+ /** Use raytraced occlusion? - ortherwise will paint right through to the back. */
+ bool do_occlude;
+ /** ignore faces with normals pointing away,
+ * skips a lot of raycasts if your normals are correctly flipped. */
+ bool do_backfacecull;
+ /** mask out pixels based on their normals. */
+ bool do_mask_normal;
+ /** mask out pixels based on cavity. */
+ bool do_mask_cavity;
+ /** what angle to mask at. */
+ float normal_angle;
+ /** cos(normal_angle), faster to compare. */
+ float normal_angle__cos;
+ float normal_angle_inner;
+ float normal_angle_inner__cos;
+ /** difference between normal_angle and normal_angle_inner, for easy access. */
+ float normal_angle_range;
+
+ /** quick access to (me->editflag & ME_EDIT_PAINT_FACE_SEL) */
+ bool do_face_sel;
+ bool is_ortho;
+ /** the object is negative scaled. */
+ bool is_flip_object;
+ /** use masking during painting. Some operations such as airbrush may disable. */
+ bool do_masking;
+ /** only to avoid running. */
+ bool is_texbrush;
+ /** mask brush is applied before masking. */
+ bool is_maskbrush;
#ifndef PROJ_DEBUG_NOSEAMBLEED
- float seam_bleed_px;
- float seam_bleed_px_sq;
+ float seam_bleed_px;
+ float seam_bleed_px_sq;
#endif
- /* clone vars */
- float cloneOffset[2];
-
- /** Projection matrix, use for getting screen coords. */
- float projectMat[4][4];
- /** inverse of projectMat. */
- float projectMatInv[4][4];
- /** View vector, use for do_backfacecull and for ray casting with an ortho viewport. */
- float viewDir[3];
- /** View location in object relative 3D space, so can compare to verts. */
- float viewPos[3];
- float clip_start, clip_end;
-
- /* reproject vars */
- Image *reproject_image;
- ImBuf *reproject_ibuf;
- bool reproject_ibuf_free_float;
- bool reproject_ibuf_free_uchar;
-
- /* threads */
- int thread_tot;
- int bucketMin[2];
- int bucketMax[2];
- /** must lock threads while accessing these. */
- int context_bucket_x, context_bucket_y;
-
- struct CurveMapping *cavity_curve;
- BlurKernel *blurkernel;
-
-
-
- /* -------------------------------------------------------------------- */
- /* Vars shared between multiple views (keep last) */
- /**
- * This data is owned by ``ProjStrokeHandle.ps_views[0]``,
- * all other views re-use the data.
- */
+ /* clone vars */
+ float cloneOffset[2];
+
+ /** Projection matrix, use for getting screen coords. */
+ float projectMat[4][4];
+ /** inverse of projectMat. */
+ float projectMatInv[4][4];
+ /** View vector, use for do_backfacecull and for ray casting with an ortho viewport. */
+ float viewDir[3];
+ /** View location in object relative 3D space, so can compare to verts. */
+ float viewPos[3];
+ float clip_start, clip_end;
+
+ /* reproject vars */
+ Image *reproject_image;
+ ImBuf *reproject_ibuf;
+ bool reproject_ibuf_free_float;
+ bool reproject_ibuf_free_uchar;
+
+ /* threads */
+ int thread_tot;
+ int bucketMin[2];
+ int bucketMax[2];
+ /** must lock threads while accessing these. */
+ int context_bucket_x, context_bucket_y;
+
+ struct CurveMapping *cavity_curve;
+ BlurKernel *blurkernel;
+
+ /* -------------------------------------------------------------------- */
+ /* Vars shared between multiple views (keep last) */
+ /**
+ * This data is owned by ``ProjStrokeHandle.ps_views[0]``,
+ * all other views re-use the data.
+ */
#define PROJ_PAINT_STATE_SHARED_MEMCPY(ps_dst, ps_src) \
- MEMCPY_STRUCT_AFTER(ps_dst, ps_src, is_shared_user)
+ MEMCPY_STRUCT_AFTER(ps_dst, ps_src, is_shared_user)
-#define PROJ_PAINT_STATE_SHARED_CLEAR(ps) \
- MEMSET_STRUCT_AFTER(ps, 0, is_shared_user)
+#define PROJ_PAINT_STATE_SHARED_CLEAR(ps) MEMSET_STRUCT_AFTER(ps, 0, is_shared_user)
- bool is_shared_user;
+ bool is_shared_user;
- ProjPaintImage *projImages;
- /** cavity amount for vertices. */
- float *cavities;
+ ProjPaintImage *projImages;
+ /** cavity amount for vertices. */
+ float *cavities;
#ifndef PROJ_DEBUG_NOSEAMBLEED
- /** store info about faces, if they are initialized etc*/
- ushort *faceSeamFlags;
- /** save the winding of the face in uv space,
- * helps as an extra validation step for seam detection. */
- char *faceWindingFlags;
- /** expanded UVs for faces to use as seams. */
- LoopSeamData (*loopSeamData);
- /** Only needed for when seam_bleed_px is enabled, use to find UV seams. */
- LinkNode **vertFaces;
- /** Seams per vert, to find adjacent seams. */
- ListBase *vertSeams;
+ /** store info about faces, if they are initialized etc*/
+ ushort *faceSeamFlags;
+ /** save the winding of the face in uv space,
+ * helps as an extra validation step for seam detection. */
+ char *faceWindingFlags;
+ /** expanded UVs for faces to use as seams. */
+ LoopSeamData(*loopSeamData);
+ /** Only needed for when seam_bleed_px is enabled, use to find UV seams. */
+ LinkNode **vertFaces;
+ /** Seams per vert, to find adjacent seams. */
+ ListBase *vertSeams;
#endif
- SpinLock *tile_lock;
-
- Mesh *me_eval;
- bool me_eval_free;
- int totlooptri_eval;
- int totloop_eval;
- int totpoly_eval;
- int totedge_eval;
- int totvert_eval;
-
- const MVert *mvert_eval;
- const MEdge *medge_eval;
- const MPoly *mpoly_eval;
- const MLoop *mloop_eval;
- const MLoopTri *mlooptri_eval;
-
- const MLoopUV *mloopuv_stencil_eval;
-
- /**
- * \note These UV layers are aligned to \a mpoly_eval
- * but each pointer references the start of the layer,
- * so a loop indirection is needed as well.
- */
- const MLoopUV **poly_to_loop_uv;
- /** other UV map, use for cloning between layers. */
- const MLoopUV **poly_to_loop_uv_clone;
-
- /* Actual material for each index, either from object or Mesh datablock... */
- Material **mat_array;
-
- bool use_colormanagement;
+ SpinLock *tile_lock;
+
+ Mesh *me_eval;
+ bool me_eval_free;
+ int totlooptri_eval;
+ int totloop_eval;
+ int totpoly_eval;
+ int totedge_eval;
+ int totvert_eval;
+
+ const MVert *mvert_eval;
+ const MEdge *medge_eval;
+ const MPoly *mpoly_eval;
+ const MLoop *mloop_eval;
+ const MLoopTri *mlooptri_eval;
+
+ const MLoopUV *mloopuv_stencil_eval;
+
+ /**
+ * \note These UV layers are aligned to \a mpoly_eval
+ * but each pointer references the start of the layer,
+ * so a loop indirection is needed as well.
+ */
+ const MLoopUV **poly_to_loop_uv;
+ /** other UV map, use for cloning between layers. */
+ const MLoopUV **poly_to_loop_uv_clone;
+
+ /* Actual material for each index, either from object or Mesh datablock... */
+ Material **mat_array;
+
+ bool use_colormanagement;
} ProjPaintState;
typedef union pixelPointer {
- /** float buffer. */
- float *f_pt;
- /** 2 ways to access a char buffer. */
- unsigned int *uint_pt;
- unsigned char *ch_pt;
+ /** float buffer. */
+ float *f_pt;
+ /** 2 ways to access a char buffer. */
+ unsigned int *uint_pt;
+ unsigned char *ch_pt;
} PixelPointer;
typedef union pixelStore {
- unsigned char ch[4];
- unsigned int uint;
- float f[4];
+ unsigned char ch[4];
+ unsigned int uint;
+ float f[4];
} PixelStore;
typedef struct ProjPixel {
- /** the floating point screen projection of this pixel. */
- float projCoSS[2];
- float worldCoSS[3];
+ /** the floating point screen projection of this pixel. */
+ float projCoSS[2];
+ float worldCoSS[3];
- short x_px, y_px;
+ short x_px, y_px;
- /** if anyone wants to paint onto more than 65535 images they can bite me. */
- unsigned short image_index;
- unsigned char bb_cell_index;
+ /** if anyone wants to paint onto more than 65535 images they can bite me. */
+ unsigned short image_index;
+ unsigned char bb_cell_index;
- /* for various reasons we may want to mask out painting onto this pixel */
- unsigned short mask;
+ /* for various reasons we may want to mask out painting onto this pixel */
+ unsigned short mask;
- /* Only used when the airbrush is disabled.
- * Store the max mask value to avoid painting over an area with a lower opacity
- * with an advantage that we can avoid touching the pixel at all, if the
- * new mask value is lower then mask_accum */
- unsigned short *mask_accum;
+ /* Only used when the airbrush is disabled.
+ * Store the max mask value to avoid painting over an area with a lower opacity
+ * with an advantage that we can avoid touching the pixel at all, if the
+ * new mask value is lower then mask_accum */
+ unsigned short *mask_accum;
- /* horrible hack, store tile valid flag pointer here to re-validate tiles
- * used for anchored and drag-dot strokes */
- bool *valid;
+ /* horrible hack, store tile valid flag pointer here to re-validate tiles
+ * used for anchored and drag-dot strokes */
+ bool *valid;
- PixelPointer origColor;
- PixelStore newColor;
- PixelPointer pixel;
+ PixelPointer origColor;
+ PixelStore newColor;
+ PixelPointer pixel;
} ProjPixel;
typedef struct ProjPixelClone {
- struct ProjPixel __pp;
- PixelStore clonepx;
+ struct ProjPixel __pp;
+ PixelStore clonepx;
} ProjPixelClone;
/* undo tile pushing */
typedef struct {
- SpinLock *lock;
- bool masked;
- unsigned short tile_width;
- ImBuf **tmpibuf;
- ProjPaintImage *pjima;
+ SpinLock *lock;
+ bool masked;
+ unsigned short tile_width;
+ ImBuf **tmpibuf;
+ ProjPaintImage *pjima;
} TileInfo;
typedef struct VertSeam {
- struct VertSeam *next, *prev;
- int tri;
- uint loop;
- float angle;
- bool normal_cw;
- float uv[2];
+ struct VertSeam *next, *prev;
+ int tri;
+ uint loop;
+ float angle;
+ bool normal_cw;
+ float uv[2];
} VertSeam;
-
/* -------------------------------------------------------------------- */
/** \name MLoopTri accessor functions.
* \{ */
BLI_INLINE const MPoly *ps_tri_index_to_mpoly(const ProjPaintState *ps, int tri_index)
{
- return &ps->mpoly_eval[ps->mlooptri_eval[tri_index].poly];
+ return &ps->mpoly_eval[ps->mlooptri_eval[tri_index].poly];
}
#define PS_LOOPTRI_AS_VERT_INDEX_3(ps, lt) \
- ps->mloop_eval[lt->tri[0]].v, \
- ps->mloop_eval[lt->tri[1]].v, \
- ps->mloop_eval[lt->tri[2]].v,
+ ps->mloop_eval[lt->tri[0]].v, ps->mloop_eval[lt->tri[1]].v, ps->mloop_eval[lt->tri[2]].v,
#define PS_LOOPTRI_AS_UV_3(uvlayer, lt) \
- uvlayer[lt->poly][lt->tri[0]].uv, \
- uvlayer[lt->poly][lt->tri[1]].uv, \
- uvlayer[lt->poly][lt->tri[2]].uv,
+ uvlayer[lt->poly][lt->tri[0]].uv, uvlayer[lt->poly][lt->tri[1]].uv, \
+ uvlayer[lt->poly][lt->tri[2]].uv,
-#define PS_LOOPTRI_ASSIGN_UV_3(uv_tri, uvlayer, lt) { \
- (uv_tri)[0] = uvlayer[lt->poly][lt->tri[0]].uv; \
- (uv_tri)[1] = uvlayer[lt->poly][lt->tri[1]].uv; \
- (uv_tri)[2] = uvlayer[lt->poly][lt->tri[2]].uv; \
-} ((void)0)
+#define PS_LOOPTRI_ASSIGN_UV_3(uv_tri, uvlayer, lt) \
+ { \
+ (uv_tri)[0] = uvlayer[lt->poly][lt->tri[0]].uv; \
+ (uv_tri)[1] = uvlayer[lt->poly][lt->tri[1]].uv; \
+ (uv_tri)[2] = uvlayer[lt->poly][lt->tri[2]].uv; \
+ } \
+ ((void)0)
/** \} */
-
-
/* Finish projection painting structs */
static TexPaintSlot *project_paint_face_paint_slot(const ProjPaintState *ps, int tri_index)
{
- const MPoly *mp = ps_tri_index_to_mpoly(ps, tri_index);
- Material *ma = ps->mat_array[mp->mat_nr];
- return ma ? ma->texpaintslot + ma->paint_active_slot : NULL;
+ const MPoly *mp = ps_tri_index_to_mpoly(ps, tri_index);
+ Material *ma = ps->mat_array[mp->mat_nr];
+ return ma ? ma->texpaintslot + ma->paint_active_slot : NULL;
}
static Image *project_paint_face_paint_image(const ProjPaintState *ps, int tri_index)
{
- if (ps->do_stencil_brush) {
- return ps->stencil_ima;
- }
- else {
- const MPoly *mp = ps_tri_index_to_mpoly(ps, tri_index);
- Material *ma = ps->mat_array[mp->mat_nr];
- TexPaintSlot *slot = ma ? ma->texpaintslot + ma->paint_active_slot : NULL;
- return slot ? slot->ima : ps->canvas_ima;
- }
+ if (ps->do_stencil_brush) {
+ return ps->stencil_ima;
+ }
+ else {
+ const MPoly *mp = ps_tri_index_to_mpoly(ps, tri_index);
+ Material *ma = ps->mat_array[mp->mat_nr];
+ TexPaintSlot *slot = ma ? ma->texpaintslot + ma->paint_active_slot : NULL;
+ return slot ? slot->ima : ps->canvas_ima;
+ }
}
static TexPaintSlot *project_paint_face_clone_slot(const ProjPaintState *ps, int tri_index)
{
- const MPoly *mp = ps_tri_index_to_mpoly(ps, tri_index);
- Material *ma = ps->mat_array[mp->mat_nr];
- return ma ? ma->texpaintslot + ma->paint_clone_slot : NULL;
+ const MPoly *mp = ps_tri_index_to_mpoly(ps, tri_index);
+ Material *ma = ps->mat_array[mp->mat_nr];
+ return ma ? ma->texpaintslot + ma->paint_clone_slot : NULL;
}
static Image *project_paint_face_clone_image(const ProjPaintState *ps, int tri_index)
{
- const MPoly *mp = ps_tri_index_to_mpoly(ps, tri_index);
- Material *ma = ps->mat_array[mp->mat_nr];
- TexPaintSlot *slot = ma ? ma->texpaintslot + ma->paint_clone_slot : NULL;
- return slot ? slot->ima : ps->clone_ima;
+ const MPoly *mp = ps_tri_index_to_mpoly(ps, tri_index);
+ Material *ma = ps->mat_array[mp->mat_nr];
+ TexPaintSlot *slot = ma ? ma->texpaintslot + ma->paint_clone_slot : NULL;
+ return slot ? slot->ima : ps->clone_ima;
}
/* fast projection bucket array lookup, use the safe version for bound checking */
static int project_bucket_offset(const ProjPaintState *ps, const float projCoSS[2])
{
- /* If we were not dealing with screenspace 2D coords we could simple do...
- * ps->bucketRect[x + (y*ps->buckets_y)] */
-
- /* please explain?
- * projCoSS[0] - ps->screenMin[0] : zero origin
- * ... / ps->screen_width : range from 0.0 to 1.0
- * ... * ps->buckets_x : use as a bucket index
- *
- * Second multiplication does similar but for vertical offset
- */
- return ( (int)(((projCoSS[0] - ps->screenMin[0]) / ps->screen_width) * ps->buckets_x)) +
- (((int)(((projCoSS[1] - ps->screenMin[1]) / ps->screen_height) * ps->buckets_y)) * ps->buckets_x);
+ /* If we were not dealing with screenspace 2D coords we could simple do...
+ * ps->bucketRect[x + (y*ps->buckets_y)] */
+
+ /* please explain?
+ * projCoSS[0] - ps->screenMin[0] : zero origin
+ * ... / ps->screen_width : range from 0.0 to 1.0
+ * ... * ps->buckets_x : use as a bucket index
+ *
+ * Second multiplication does similar but for vertical offset
+ */
+ return ((int)(((projCoSS[0] - ps->screenMin[0]) / ps->screen_width) * ps->buckets_x)) +
+ (((int)(((projCoSS[1] - ps->screenMin[1]) / ps->screen_height) * ps->buckets_y)) *
+ ps->buckets_x);
}
static int project_bucket_offset_safe(const ProjPaintState *ps, const float projCoSS[2])
{
- int bucket_index = project_bucket_offset(ps, projCoSS);
-
- if (bucket_index < 0 || bucket_index >= ps->buckets_x * ps->buckets_y) {
- return -1;
- }
- else {
- return bucket_index;
- }
+ int bucket_index = project_bucket_offset(ps, projCoSS);
+
+ if (bucket_index < 0 || bucket_index >= ps->buckets_x * ps->buckets_y) {
+ return -1;
+ }
+ else {
+ return bucket_index;
+ }
}
static float VecZDepthOrtho(
- const float pt[2],
- const float v1[3], const float v2[3], const float v3[3],
- float w[3])
+ const float pt[2], const float v1[3], const float v2[3], const float v3[3], float w[3])
{
- barycentric_weights_v2(v1, v2, v3, pt, w);
- return (v1[2] * w[0]) + (v2[2] * w[1]) + (v3[2] * w[2]);
+ barycentric_weights_v2(v1, v2, v3, pt, w);
+ return (v1[2] * w[0]) + (v2[2] * w[1]) + (v3[2] * w[2]);
}
static float VecZDepthPersp(
- const float pt[2],
- const float v1[4], const float v2[4], const float v3[4],
- float w[3])
+ const float pt[2], const float v1[4], const float v2[4], const float v3[4], float w[3])
{
- float wtot_inv, wtot;
- float w_tmp[3];
-
- barycentric_weights_v2_persp(v1, v2, v3, pt, w);
- /* for the depth we need the weights to match what
- * barycentric_weights_v2 would return, in this case its easiest just to
- * undo the 4th axis division and make it unit-sum
- *
- * don't call barycentric_weights_v2() because our callers expect 'w'
- * to be weighted from the perspective */
- w_tmp[0] = w[0] * v1[3];
- w_tmp[1] = w[1] * v2[3];
- w_tmp[2] = w[2] * v3[3];
-
- wtot = w_tmp[0] + w_tmp[1] + w_tmp[2];
-
- if (wtot != 0.0f) {
- wtot_inv = 1.0f / wtot;
-
- w_tmp[0] = w_tmp[0] * wtot_inv;
- w_tmp[1] = w_tmp[1] * wtot_inv;
- w_tmp[2] = w_tmp[2] * wtot_inv;
- }
- else /* dummy values for zero area face */
- w_tmp[0] = w_tmp[1] = w_tmp[2] = 1.0f / 3.0f;
- /* done mimicking barycentric_weights_v2() */
-
- return (v1[2] * w_tmp[0]) + (v2[2] * w_tmp[1]) + (v3[2] * w_tmp[2]);
+ float wtot_inv, wtot;
+ float w_tmp[3];
+
+ barycentric_weights_v2_persp(v1, v2, v3, pt, w);
+ /* for the depth we need the weights to match what
+ * barycentric_weights_v2 would return, in this case its easiest just to
+ * undo the 4th axis division and make it unit-sum
+ *
+ * don't call barycentric_weights_v2() because our callers expect 'w'
+ * to be weighted from the perspective */
+ w_tmp[0] = w[0] * v1[3];
+ w_tmp[1] = w[1] * v2[3];
+ w_tmp[2] = w[2] * v3[3];
+
+ wtot = w_tmp[0] + w_tmp[1] + w_tmp[2];
+
+ if (wtot != 0.0f) {
+ wtot_inv = 1.0f / wtot;
+
+ w_tmp[0] = w_tmp[0] * wtot_inv;
+ w_tmp[1] = w_tmp[1] * wtot_inv;
+ w_tmp[2] = w_tmp[2] * wtot_inv;
+ }
+ else /* dummy values for zero area face */
+ w_tmp[0] = w_tmp[1] = w_tmp[2] = 1.0f / 3.0f;
+ /* done mimicking barycentric_weights_v2() */
+
+ return (v1[2] * w_tmp[0]) + (v2[2] * w_tmp[1]) + (v3[2] * w_tmp[2]);
}
-
/* Return the top-most face index that the screen space coord 'pt' touches (or -1) */
-static int project_paint_PickFace(
- const ProjPaintState *ps, const float pt[2],
- float w[3])
+static int project_paint_PickFace(const ProjPaintState *ps, const float pt[2], float w[3])
{
- LinkNode *node;
- float w_tmp[3];
- int bucket_index;
- int best_tri_index = -1;
- float z_depth_best = FLT_MAX, z_depth;
-
- bucket_index = project_bucket_offset_safe(ps, pt);
- if (bucket_index == -1)
- return -1;
-
-
-
- /* we could return 0 for 1 face buckets, as long as this function assumes
- * that the point its testing is only every originated from an existing face */
-
- for (node = ps->bucketFaces[bucket_index]; node; node = node->next) {
- const int tri_index = POINTER_AS_INT(node->link);
- const MLoopTri *lt = &ps->mlooptri_eval[tri_index];
- const float *vtri_ss[3] = {
- ps->screenCoords[ps->mloop_eval[lt->tri[0]].v],
- ps->screenCoords[ps->mloop_eval[lt->tri[1]].v],
- ps->screenCoords[ps->mloop_eval[lt->tri[2]].v],
- };
-
-
- if (isect_point_tri_v2(pt, UNPACK3(vtri_ss))) {
- if (ps->is_ortho) {
- z_depth = VecZDepthOrtho(pt, UNPACK3(vtri_ss), w_tmp);
- }
- else {
- z_depth = VecZDepthPersp(pt, UNPACK3(vtri_ss), w_tmp);
- }
-
- if (z_depth < z_depth_best) {
- best_tri_index = tri_index;
- z_depth_best = z_depth;
- copy_v3_v3(w, w_tmp);
- }
- }
- }
-
- /** will be -1 or a valid face. */
- return best_tri_index;
+ LinkNode *node;
+ float w_tmp[3];
+ int bucket_index;
+ int best_tri_index = -1;
+ float z_depth_best = FLT_MAX, z_depth;
+
+ bucket_index = project_bucket_offset_safe(ps, pt);
+ if (bucket_index == -1)
+ return -1;
+
+ /* we could return 0 for 1 face buckets, as long as this function assumes
+ * that the point its testing is only every originated from an existing face */
+
+ for (node = ps->bucketFaces[bucket_index]; node; node = node->next) {
+ const int tri_index = POINTER_AS_INT(node->link);
+ const MLoopTri *lt = &ps->mlooptri_eval[tri_index];
+ const float *vtri_ss[3] = {
+ ps->screenCoords[ps->mloop_eval[lt->tri[0]].v],
+ ps->screenCoords[ps->mloop_eval[lt->tri[1]].v],
+ ps->screenCoords[ps->mloop_eval[lt->tri[2]].v],
+ };
+
+ if (isect_point_tri_v2(pt, UNPACK3(vtri_ss))) {
+ if (ps->is_ortho) {
+ z_depth = VecZDepthOrtho(pt, UNPACK3(vtri_ss), w_tmp);
+ }
+ else {
+ z_depth = VecZDepthPersp(pt, UNPACK3(vtri_ss), w_tmp);
+ }
+
+ if (z_depth < z_depth_best) {
+ best_tri_index = tri_index;
+ z_depth_best = z_depth;
+ copy_v3_v3(w, w_tmp);
+ }
+ }
+ }
+
+ /** will be -1 or a valid face. */
+ return best_tri_index;
}
/* Converts a uv coord into a pixel location wrapping if the uv is outside 0-1 range */
static void uvco_to_wrapped_pxco(const float uv[2], int ibuf_x, int ibuf_y, float *x, float *y)
{
- /* use */
- *x = fmodf(uv[0], 1.0f);
- *y = fmodf(uv[1], 1.0f);
+ /* use */
+ *x = fmodf(uv[0], 1.0f);
+ *y = fmodf(uv[1], 1.0f);
- if (*x < 0.0f) *x += 1.0f;
- if (*y < 0.0f) *y += 1.0f;
+ if (*x < 0.0f)
+ *x += 1.0f;
+ if (*y < 0.0f)
+ *y += 1.0f;
- *x = *x * ibuf_x - 0.5f;
- *y = *y * ibuf_y - 0.5f;
+ *x = *x * ibuf_x - 0.5f;
+ *y = *y * ibuf_y - 0.5f;
}
/* Set the top-most face color that the screen space coord 'pt' touches
* (or return 0 if none touch) */
-static bool project_paint_PickColor(
- const ProjPaintState *ps, const float pt[2],
- float *rgba_fp, unsigned char *rgba, const bool interp)
+static bool project_paint_PickColor(const ProjPaintState *ps,
+ const float pt[2],
+ float *rgba_fp,
+ unsigned char *rgba,
+ const bool interp)
{
- const MLoopTri *lt;
- const float *lt_tri_uv[3];
- float w[3], uv[2];
- int tri_index;
- Image *ima;
- ImBuf *ibuf;
- int xi, yi;
-
- tri_index = project_paint_PickFace(ps, pt, w);
-
- if (tri_index == -1)
- return 0;
-
- lt = &ps->mlooptri_eval[tri_index];
- PS_LOOPTRI_ASSIGN_UV_3(lt_tri_uv, ps->poly_to_loop_uv, lt);
-
- interp_v2_v2v2v2(uv, UNPACK3(lt_tri_uv), w);
-
- ima = project_paint_face_paint_image(ps, tri_index);
- /** we must have got the imbuf before getting here. */
- ibuf = BKE_image_get_first_ibuf(ima);
- if (!ibuf) return 0;
-
- if (interp) {
- float x, y;
- uvco_to_wrapped_pxco(uv, ibuf->x, ibuf->y, &x, &y);
-
- if (ibuf->rect_float) {
- if (rgba_fp) {
- bilinear_interpolation_color_wrap(ibuf, NULL, rgba_fp, x, y);
- }
- else {
- float rgba_tmp_f[4];
- bilinear_interpolation_color_wrap(ibuf, NULL, rgba_tmp_f, x, y);
- premul_float_to_straight_uchar(rgba, rgba_tmp_f);
- }
- }
- else {
- if (rgba) {
- bilinear_interpolation_color_wrap(ibuf, rgba, NULL, x, y);
- }
- else {
- unsigned char rgba_tmp[4];
- bilinear_interpolation_color_wrap(ibuf, rgba_tmp, NULL, x, y);
- straight_uchar_to_premul_float(rgba_fp, rgba_tmp);
- }
- }
- }
- else {
- //xi = (int)((uv[0]*ibuf->x) + 0.5f);
- //yi = (int)((uv[1]*ibuf->y) + 0.5f);
- //if (xi < 0 || xi >= ibuf->x || yi < 0 || yi >= ibuf->y) return 0;
-
- /* wrap */
- xi = mod_i((int)(uv[0] * ibuf->x), ibuf->x);
- yi = mod_i((int)(uv[1] * ibuf->y), ibuf->y);
-
- if (rgba) {
- if (ibuf->rect_float) {
- const float *rgba_tmp_fp = ibuf->rect_float + (xi + yi * ibuf->x * 4);
- premul_float_to_straight_uchar(rgba, rgba_tmp_fp);
- }
- else {
- *((unsigned int *)rgba) = *(unsigned int *)(((char *)ibuf->rect) + ((xi + yi * ibuf->x) * 4));
- }
- }
-
- if (rgba_fp) {
- if (ibuf->rect_float) {
- copy_v4_v4(rgba_fp, (ibuf->rect_float + ((xi + yi * ibuf->x) * 4)));
- }
- else {
- unsigned char *tmp_ch = ((unsigned char *)ibuf->rect) + ((xi + yi * ibuf->x) * 4);
- straight_uchar_to_premul_float(rgba_fp, tmp_ch);
- }
- }
- }
- BKE_image_release_ibuf(ima, ibuf, NULL);
- return 1;
+ const MLoopTri *lt;
+ const float *lt_tri_uv[3];
+ float w[3], uv[2];
+ int tri_index;
+ Image *ima;
+ ImBuf *ibuf;
+ int xi, yi;
+
+ tri_index = project_paint_PickFace(ps, pt, w);
+
+ if (tri_index == -1)
+ return 0;
+
+ lt = &ps->mlooptri_eval[tri_index];
+ PS_LOOPTRI_ASSIGN_UV_3(lt_tri_uv, ps->poly_to_loop_uv, lt);
+
+ interp_v2_v2v2v2(uv, UNPACK3(lt_tri_uv), w);
+
+ ima = project_paint_face_paint_image(ps, tri_index);
+ /** we must have got the imbuf before getting here. */
+ ibuf = BKE_image_get_first_ibuf(ima);
+ if (!ibuf)
+ return 0;
+
+ if (interp) {
+ float x, y;
+ uvco_to_wrapped_pxco(uv, ibuf->x, ibuf->y, &x, &y);
+
+ if (ibuf->rect_float) {
+ if (rgba_fp) {
+ bilinear_interpolation_color_wrap(ibuf, NULL, rgba_fp, x, y);
+ }
+ else {
+ float rgba_tmp_f[4];
+ bilinear_interpolation_color_wrap(ibuf, NULL, rgba_tmp_f, x, y);
+ premul_float_to_straight_uchar(rgba, rgba_tmp_f);
+ }
+ }
+ else {
+ if (rgba) {
+ bilinear_interpolation_color_wrap(ibuf, rgba, NULL, x, y);
+ }
+ else {
+ unsigned char rgba_tmp[4];
+ bilinear_interpolation_color_wrap(ibuf, rgba_tmp, NULL, x, y);
+ straight_uchar_to_premul_float(rgba_fp, rgba_tmp);
+ }
+ }
+ }
+ else {
+ //xi = (int)((uv[0]*ibuf->x) + 0.5f);
+ //yi = (int)((uv[1]*ibuf->y) + 0.5f);
+ //if (xi < 0 || xi >= ibuf->x || yi < 0 || yi >= ibuf->y) return 0;
+
+ /* wrap */
+ xi = mod_i((int)(uv[0] * ibuf->x), ibuf->x);
+ yi = mod_i((int)(uv[1] * ibuf->y), ibuf->y);
+
+ if (rgba) {
+ if (ibuf->rect_float) {
+ const float *rgba_tmp_fp = ibuf->rect_float + (xi + yi * ibuf->x * 4);
+ premul_float_to_straight_uchar(rgba, rgba_tmp_fp);
+ }
+ else {
+ *((unsigned int *)rgba) = *(unsigned int *)(((char *)ibuf->rect) +
+ ((xi + yi * ibuf->x) * 4));
+ }
+ }
+
+ if (rgba_fp) {
+ if (ibuf->rect_float) {
+ copy_v4_v4(rgba_fp, (ibuf->rect_float + ((xi + yi * ibuf->x) * 4)));
+ }
+ else {
+ unsigned char *tmp_ch = ((unsigned char *)ibuf->rect) + ((xi + yi * ibuf->x) * 4);
+ straight_uchar_to_premul_float(rgba_fp, tmp_ch);
+ }
+ }
+ }
+ BKE_image_release_ibuf(ima, ibuf, NULL);
+ return 1;
}
/**
@@ -807,121 +794,125 @@ static bool project_paint_PickColor(
* - `1`: occluded
* - `2`: occluded with `w[3]` weights set (need to know in some cases)
*/
-static int project_paint_occlude_ptv(
- const float pt[3],
- const float v1[4], const float v2[4], const float v3[4],
- float w[3], const bool is_ortho)
+static int project_paint_occlude_ptv(const float pt[3],
+ const float v1[4],
+ const float v2[4],
+ const float v3[4],
+ float w[3],
+ const bool is_ortho)
{
- /* if all are behind us, return false */
- if (v1[2] > pt[2] && v2[2] > pt[2] && v3[2] > pt[2])
- return 0;
-
- /* do a 2D point in try intersection */
- if (!isect_point_tri_v2(pt, v1, v2, v3))
- return 0;
-
-
- /* From here on we know there IS an intersection */
- /* if ALL of the verts are infront of us then we know it intersects ? */
- if (v1[2] < pt[2] && v2[2] < pt[2] && v3[2] < pt[2]) {
- return 1;
- }
- else {
- /* we intersect? - find the exact depth at the point of intersection */
- /* Is this point is occluded by another face? */
- if (is_ortho) {
- if (VecZDepthOrtho(pt, v1, v2, v3, w) < pt[2]) return 2;
- }
- else {
- if (VecZDepthPersp(pt, v1, v2, v3, w) < pt[2]) return 2;
- }
- }
- return -1;
+ /* if all are behind us, return false */
+ if (v1[2] > pt[2] && v2[2] > pt[2] && v3[2] > pt[2])
+ return 0;
+
+ /* do a 2D point in try intersection */
+ if (!isect_point_tri_v2(pt, v1, v2, v3))
+ return 0;
+
+ /* From here on we know there IS an intersection */
+ /* if ALL of the verts are infront of us then we know it intersects ? */
+ if (v1[2] < pt[2] && v2[2] < pt[2] && v3[2] < pt[2]) {
+ return 1;
+ }
+ else {
+ /* we intersect? - find the exact depth at the point of intersection */
+ /* Is this point is occluded by another face? */
+ if (is_ortho) {
+ if (VecZDepthOrtho(pt, v1, v2, v3, w) < pt[2])
+ return 2;
+ }
+ else {
+ if (VecZDepthPersp(pt, v1, v2, v3, w) < pt[2])
+ return 2;
+ }
+ }
+ return -1;
}
-
-static int project_paint_occlude_ptv_clip(
- const float pt[3],
- const float v1[4], const float v2[4], const float v3[4],
- const float v1_3d[3], const float v2_3d[3], const float v3_3d[3],
- float w[3], const bool is_ortho, RegionView3D *rv3d)
+static int project_paint_occlude_ptv_clip(const float pt[3],
+ const float v1[4],
+ const float v2[4],
+ const float v3[4],
+ const float v1_3d[3],
+ const float v2_3d[3],
+ const float v3_3d[3],
+ float w[3],
+ const bool is_ortho,
+ RegionView3D *rv3d)
{
- float wco[3];
- int ret = project_paint_occlude_ptv(pt, v1, v2, v3, w, is_ortho);
+ float wco[3];
+ int ret = project_paint_occlude_ptv(pt, v1, v2, v3, w, is_ortho);
- if (ret <= 0)
- return ret;
+ if (ret <= 0)
+ return ret;
- if (ret == 1) { /* weights not calculated */
- if (is_ortho) {
- barycentric_weights_v2(v1, v2, v3, pt, w);
- }
- else {
- barycentric_weights_v2_persp(v1, v2, v3, pt, w);
- }
- }
+ if (ret == 1) { /* weights not calculated */
+ if (is_ortho) {
+ barycentric_weights_v2(v1, v2, v3, pt, w);
+ }
+ else {
+ barycentric_weights_v2_persp(v1, v2, v3, pt, w);
+ }
+ }
- /* Test if we're in the clipped area, */
- interp_v3_v3v3v3(wco, v1_3d, v2_3d, v3_3d, w);
+ /* Test if we're in the clipped area, */
+ interp_v3_v3v3v3(wco, v1_3d, v2_3d, v3_3d, w);
- if (!ED_view3d_clipping_test(rv3d, wco, true)) {
- return 1;
- }
+ if (!ED_view3d_clipping_test(rv3d, wco, true)) {
+ return 1;
+ }
- return -1;
+ return -1;
}
-
/* Check if a screenspace location is occluded by any other faces
* check, pixelScreenCo must be in screenspace, its Z-Depth only needs to be used for comparison
* and doesn't need to be correct in relation to X and Y coords
* (this is the case in perspective view) */
-static bool project_bucket_point_occluded(
- const ProjPaintState *ps, LinkNode *bucketFace,
- const int orig_face, const float pixelScreenCo[4])
+static bool project_bucket_point_occluded(const ProjPaintState *ps,
+ LinkNode *bucketFace,
+ const int orig_face,
+ const float pixelScreenCo[4])
{
- int isect_ret;
- const bool do_clip = ps->rv3d ? (ps->rv3d->rflag & RV3D_CLIPPING) != 0 : 0;
-
- /* we could return 0 for 1 face buckets, as long as this function assumes
- * that the point its testing is only every originated from an existing face */
-
- for (; bucketFace; bucketFace = bucketFace->next) {
- const int tri_index = POINTER_AS_INT(bucketFace->link);
-
- if (orig_face != tri_index) {
- const MLoopTri *lt = &ps->mlooptri_eval[tri_index];
- const float *vtri_ss[3] = {
- ps->screenCoords[ps->mloop_eval[lt->tri[0]].v],
- ps->screenCoords[ps->mloop_eval[lt->tri[1]].v],
- ps->screenCoords[ps->mloop_eval[lt->tri[2]].v],
- };
- float w[3];
-
- if (do_clip) {
- const float *vtri_co[3] = {
- ps->mvert_eval[ps->mloop_eval[lt->tri[0]].v].co,
- ps->mvert_eval[ps->mloop_eval[lt->tri[1]].v].co,
- ps->mvert_eval[ps->mloop_eval[lt->tri[2]].v].co,
- };
- isect_ret = project_paint_occlude_ptv_clip(
- pixelScreenCo, UNPACK3(vtri_ss), UNPACK3(vtri_co),
- w, ps->is_ortho, ps->rv3d);
- }
- else {
- isect_ret = project_paint_occlude_ptv(
- pixelScreenCo, UNPACK3(vtri_ss),
- w, ps->is_ortho);
- }
-
- if (isect_ret >= 1) {
- /* TODO - we may want to cache the first hit,
- * it is not possible to swap the face order in the list anymore */
- return true;
- }
- }
- }
- return false;
+ int isect_ret;
+ const bool do_clip = ps->rv3d ? (ps->rv3d->rflag & RV3D_CLIPPING) != 0 : 0;
+
+ /* we could return 0 for 1 face buckets, as long as this function assumes
+ * that the point its testing is only every originated from an existing face */
+
+ for (; bucketFace; bucketFace = bucketFace->next) {
+ const int tri_index = POINTER_AS_INT(bucketFace->link);
+
+ if (orig_face != tri_index) {
+ const MLoopTri *lt = &ps->mlooptri_eval[tri_index];
+ const float *vtri_ss[3] = {
+ ps->screenCoords[ps->mloop_eval[lt->tri[0]].v],
+ ps->screenCoords[ps->mloop_eval[lt->tri[1]].v],
+ ps->screenCoords[ps->mloop_eval[lt->tri[2]].v],
+ };
+ float w[3];
+
+ if (do_clip) {
+ const float *vtri_co[3] = {
+ ps->mvert_eval[ps->mloop_eval[lt->tri[0]].v].co,
+ ps->mvert_eval[ps->mloop_eval[lt->tri[1]].v].co,
+ ps->mvert_eval[ps->mloop_eval[lt->tri[2]].v].co,
+ };
+ isect_ret = project_paint_occlude_ptv_clip(
+ pixelScreenCo, UNPACK3(vtri_ss), UNPACK3(vtri_co), w, ps->is_ortho, ps->rv3d);
+ }
+ else {
+ isect_ret = project_paint_occlude_ptv(pixelScreenCo, UNPACK3(vtri_ss), w, ps->is_ortho);
+ }
+
+ if (isect_ret >= 1) {
+ /* TODO - we may want to cache the first hit,
+ * it is not possible to swap the face order in the list anymore */
+ return true;
+ }
+ }
+ }
+ return false;
}
/* Basic line intersection, could move to math_geom.c, 2 points with a horizontal line
@@ -931,77 +922,77 @@ static bool project_bucket_point_occluded(
#define ISECT_TRUE_P2 3
static int line_isect_y(const float p1[2], const float p2[2], const float y_level, float *x_isect)
{
- float y_diff;
-
- /* are we touching the first point? - no interpolation needed */
- if (y_level == p1[1]) {
- *x_isect = p1[0];
- return ISECT_TRUE_P1;
- }
- /* are we touching the second point? - no interpolation needed */
- if (y_level == p2[1]) {
- *x_isect = p2[0];
- return ISECT_TRUE_P2;
- }
-
- /** yuck, horizontal line, we cant do much here. */
- y_diff = fabsf(p1[1] - p2[1]);
-
- if (y_diff < 0.000001f) {
- *x_isect = (p1[0] + p2[0]) * 0.5f;
- return ISECT_TRUE;
- }
-
- if (p1[1] > y_level && p2[1] < y_level) {
- /* (p1[1] - p2[1]); */
- *x_isect = (p2[0] * (p1[1] - y_level) + p1[0] * (y_level - p2[1])) / y_diff;
- return ISECT_TRUE;
- }
- else if (p1[1] < y_level && p2[1] > y_level) {
- /* (p2[1] - p1[1]); */
- *x_isect = (p2[0] * (y_level - p1[1]) + p1[0] * (p2[1] - y_level)) / y_diff;
- return ISECT_TRUE;
- }
- else {
- return 0;
- }
+ float y_diff;
+
+ /* are we touching the first point? - no interpolation needed */
+ if (y_level == p1[1]) {
+ *x_isect = p1[0];
+ return ISECT_TRUE_P1;
+ }
+ /* are we touching the second point? - no interpolation needed */
+ if (y_level == p2[1]) {
+ *x_isect = p2[0];
+ return ISECT_TRUE_P2;
+ }
+
+ /** yuck, horizontal line, we cant do much here. */
+ y_diff = fabsf(p1[1] - p2[1]);
+
+ if (y_diff < 0.000001f) {
+ *x_isect = (p1[0] + p2[0]) * 0.5f;
+ return ISECT_TRUE;
+ }
+
+ if (p1[1] > y_level && p2[1] < y_level) {
+ /* (p1[1] - p2[1]); */
+ *x_isect = (p2[0] * (p1[1] - y_level) + p1[0] * (y_level - p2[1])) / y_diff;
+ return ISECT_TRUE;
+ }
+ else if (p1[1] < y_level && p2[1] > y_level) {
+ /* (p2[1] - p1[1]); */
+ *x_isect = (p2[0] * (y_level - p1[1]) + p1[0] * (p2[1] - y_level)) / y_diff;
+ return ISECT_TRUE;
+ }
+ else {
+ return 0;
+ }
}
static int line_isect_x(const float p1[2], const float p2[2], const float x_level, float *y_isect)
{
- float x_diff;
-
- if (x_level == p1[0]) { /* are we touching the first point? - no interpolation needed */
- *y_isect = p1[1];
- return ISECT_TRUE_P1;
- }
- if (x_level == p2[0]) { /* are we touching the second point? - no interpolation needed */
- *y_isect = p2[1];
- return ISECT_TRUE_P2;
- }
-
- /* yuck, horizontal line, we cant do much here */
- x_diff = fabsf(p1[0] - p2[0]);
-
- /* yuck, vertical line, we cant do much here */
- if (x_diff < 0.000001f) {
- *y_isect = (p1[0] + p2[0]) * 0.5f;
- return ISECT_TRUE;
- }
-
- if (p1[0] > x_level && p2[0] < x_level) {
- /* (p1[0] - p2[0]); */
- *y_isect = (p2[1] * (p1[0] - x_level) + p1[1] * (x_level - p2[0])) / x_diff;
- return ISECT_TRUE;
- }
- else if (p1[0] < x_level && p2[0] > x_level) {
- /* (p2[0] - p1[0]); */
- *y_isect = (p2[1] * (x_level - p1[0]) + p1[1] * (p2[0] - x_level)) / x_diff;
- return ISECT_TRUE;
- }
- else {
- return 0;
- }
+ float x_diff;
+
+ if (x_level == p1[0]) { /* are we touching the first point? - no interpolation needed */
+ *y_isect = p1[1];
+ return ISECT_TRUE_P1;
+ }
+ if (x_level == p2[0]) { /* are we touching the second point? - no interpolation needed */
+ *y_isect = p2[1];
+ return ISECT_TRUE_P2;
+ }
+
+ /* yuck, horizontal line, we cant do much here */
+ x_diff = fabsf(p1[0] - p2[0]);
+
+ /* yuck, vertical line, we cant do much here */
+ if (x_diff < 0.000001f) {
+ *y_isect = (p1[0] + p2[0]) * 0.5f;
+ return ISECT_TRUE;
+ }
+
+ if (p1[0] > x_level && p2[0] < x_level) {
+ /* (p1[0] - p2[0]); */
+ *y_isect = (p2[1] * (p1[0] - x_level) + p1[1] * (x_level - p2[0])) / x_diff;
+ return ISECT_TRUE;
+ }
+ else if (p1[0] < x_level && p2[0] > x_level) {
+ /* (p2[0] - p1[0]); */
+ *y_isect = (p2[1] * (x_level - p1[0]) + p1[1] * (p2[0] - x_level)) / x_diff;
+ return ISECT_TRUE;
+ }
+ else {
+ return 0;
+ }
}
/* simple func use for comparing UV locations to check if there are seams.
@@ -1011,389 +1002,394 @@ static int line_isect_x(const float p1[2], const float p2[2], const float x_leve
#ifndef PROJ_DEBUG_NOSEAMBLEED
static bool cmp_uv(const float vec2a[2], const float vec2b[2])
{
- /* if the UV's are not between 0.0 and 1.0 */
- float xa = fmodf(vec2a[0], 1.0f);
- float ya = fmodf(vec2a[1], 1.0f);
+ /* if the UV's are not between 0.0 and 1.0 */
+ float xa = fmodf(vec2a[0], 1.0f);
+ float ya = fmodf(vec2a[1], 1.0f);
- float xb = fmodf(vec2b[0], 1.0f);
- float yb = fmodf(vec2b[1], 1.0f);
+ float xb = fmodf(vec2b[0], 1.0f);
+ float yb = fmodf(vec2b[1], 1.0f);
- if (xa < 0.0f) xa += 1.0f;
- if (ya < 0.0f) ya += 1.0f;
+ if (xa < 0.0f)
+ xa += 1.0f;
+ if (ya < 0.0f)
+ ya += 1.0f;
- if (xb < 0.0f) xb += 1.0f;
- if (yb < 0.0f) yb += 1.0f;
+ if (xb < 0.0f)
+ xb += 1.0f;
+ if (yb < 0.0f)
+ yb += 1.0f;
- return ((fabsf(xa - xb) < PROJ_GEOM_TOLERANCE) && (fabsf(ya - yb) < PROJ_GEOM_TOLERANCE)) ? 1 : 0;
+ return ((fabsf(xa - xb) < PROJ_GEOM_TOLERANCE) && (fabsf(ya - yb) < PROJ_GEOM_TOLERANCE)) ? 1 :
+ 0;
}
#endif
/* set min_px and max_px to the image space bounds of the UV coords
* return zero if there is no area in the returned rectangle */
#ifndef PROJ_DEBUG_NOSEAMBLEED
-static bool pixel_bounds_uv(
- const float uv_quad[4][2],
- rcti *bounds_px,
- const int ibuf_x, const int ibuf_y
- )
+static bool pixel_bounds_uv(const float uv_quad[4][2],
+ rcti *bounds_px,
+ const int ibuf_x,
+ const int ibuf_y)
{
- /* UV bounds */
- float min_uv[2], max_uv[2];
+ /* UV bounds */
+ float min_uv[2], max_uv[2];
- INIT_MINMAX2(min_uv, max_uv);
+ INIT_MINMAX2(min_uv, max_uv);
- minmax_v2v2_v2(min_uv, max_uv, uv_quad[0]);
- minmax_v2v2_v2(min_uv, max_uv, uv_quad[1]);
- minmax_v2v2_v2(min_uv, max_uv, uv_quad[2]);
- minmax_v2v2_v2(min_uv, max_uv, uv_quad[3]);
+ minmax_v2v2_v2(min_uv, max_uv, uv_quad[0]);
+ minmax_v2v2_v2(min_uv, max_uv, uv_quad[1]);
+ minmax_v2v2_v2(min_uv, max_uv, uv_quad[2]);
+ minmax_v2v2_v2(min_uv, max_uv, uv_quad[3]);
- bounds_px->xmin = (int)(ibuf_x * min_uv[0]);
- bounds_px->ymin = (int)(ibuf_y * min_uv[1]);
+ bounds_px->xmin = (int)(ibuf_x * min_uv[0]);
+ bounds_px->ymin = (int)(ibuf_y * min_uv[1]);
- bounds_px->xmax = (int)(ibuf_x * max_uv[0]) + 1;
- bounds_px->ymax = (int)(ibuf_y * max_uv[1]) + 1;
+ bounds_px->xmax = (int)(ibuf_x * max_uv[0]) + 1;
+ bounds_px->ymax = (int)(ibuf_y * max_uv[1]) + 1;
- /*printf("%d %d %d %d\n", min_px[0], min_px[1], max_px[0], max_px[1]);*/
+ /*printf("%d %d %d %d\n", min_px[0], min_px[1], max_px[0], max_px[1]);*/
- /* face uses no UV area when quantized to pixels? */
- return (bounds_px->xmin == bounds_px->xmax || bounds_px->ymin == bounds_px->ymax) ? 0 : 1;
+ /* face uses no UV area when quantized to pixels? */
+ return (bounds_px->xmin == bounds_px->xmax || bounds_px->ymin == bounds_px->ymax) ? 0 : 1;
}
#endif
-static bool pixel_bounds_array(float (*uv)[2], rcti *bounds_px, const int ibuf_x, const int ibuf_y, int tot)
+static bool pixel_bounds_array(
+ float (*uv)[2], rcti *bounds_px, const int ibuf_x, const int ibuf_y, int tot)
{
- /* UV bounds */
- float min_uv[2], max_uv[2];
+ /* UV bounds */
+ float min_uv[2], max_uv[2];
- if (tot == 0) {
- return 0;
- }
+ if (tot == 0) {
+ return 0;
+ }
- INIT_MINMAX2(min_uv, max_uv);
+ INIT_MINMAX2(min_uv, max_uv);
- while (tot--) {
- minmax_v2v2_v2(min_uv, max_uv, (*uv));
- uv++;
- }
+ while (tot--) {
+ minmax_v2v2_v2(min_uv, max_uv, (*uv));
+ uv++;
+ }
- bounds_px->xmin = (int)(ibuf_x * min_uv[0]);
- bounds_px->ymin = (int)(ibuf_y * min_uv[1]);
+ bounds_px->xmin = (int)(ibuf_x * min_uv[0]);
+ bounds_px->ymin = (int)(ibuf_y * min_uv[1]);
- bounds_px->xmax = (int)(ibuf_x * max_uv[0]) + 1;
- bounds_px->ymax = (int)(ibuf_y * max_uv[1]) + 1;
+ bounds_px->xmax = (int)(ibuf_x * max_uv[0]) + 1;
+ bounds_px->ymax = (int)(ibuf_y * max_uv[1]) + 1;
- /*printf("%d %d %d %d\n", min_px[0], min_px[1], max_px[0], max_px[1]);*/
+ /*printf("%d %d %d %d\n", min_px[0], min_px[1], max_px[0], max_px[1]);*/
- /* face uses no UV area when quantized to pixels? */
- return (bounds_px->xmin == bounds_px->xmax || bounds_px->ymin == bounds_px->ymax) ? 0 : 1;
+ /* face uses no UV area when quantized to pixels? */
+ return (bounds_px->xmin == bounds_px->xmax || bounds_px->ymin == bounds_px->ymax) ? 0 : 1;
}
#ifndef PROJ_DEBUG_NOSEAMBLEED
static void project_face_winding_init(const ProjPaintState *ps, const int tri_index)
{
- /* detect the winding of faces in uv space */
- const MLoopTri *lt = &ps->mlooptri_eval[tri_index];
- const float *lt_tri_uv[3] = { PS_LOOPTRI_AS_UV_3(ps->poly_to_loop_uv, lt) };
- float winding = cross_tri_v2(lt_tri_uv[0], lt_tri_uv[1], lt_tri_uv[2]);
+ /* detect the winding of faces in uv space */
+ const MLoopTri *lt = &ps->mlooptri_eval[tri_index];
+ const float *lt_tri_uv[3] = {PS_LOOPTRI_AS_UV_3(ps->poly_to_loop_uv, lt)};
+ float winding = cross_tri_v2(lt_tri_uv[0], lt_tri_uv[1], lt_tri_uv[2]);
- if (winding > 0)
- ps->faceWindingFlags[tri_index] |= PROJ_FACE_WINDING_CW;
+ if (winding > 0)
+ ps->faceWindingFlags[tri_index] |= PROJ_FACE_WINDING_CW;
- ps->faceWindingFlags[tri_index] |= PROJ_FACE_WINDING_INIT;
+ ps->faceWindingFlags[tri_index] |= PROJ_FACE_WINDING_INIT;
}
/* This function returns 1 if this face has a seam along the 2 face-vert indices
* 'orig_i1_fidx' and 'orig_i2_fidx' */
-static bool check_seam(
- const ProjPaintState *ps,
- const int orig_face, const int orig_i1_fidx, const int orig_i2_fidx,
- int *other_face, int *orig_fidx)
+static bool check_seam(const ProjPaintState *ps,
+ const int orig_face,
+ const int orig_i1_fidx,
+ const int orig_i2_fidx,
+ int *other_face,
+ int *orig_fidx)
{
- const MLoopTri *orig_lt = &ps->mlooptri_eval[orig_face];
- const float *orig_lt_tri_uv[3] = { PS_LOOPTRI_AS_UV_3(ps->poly_to_loop_uv, orig_lt) };
- /* vert indices from face vert order indices */
- const unsigned int i1 = ps->mloop_eval[orig_lt->tri[orig_i1_fidx]].v;
- const unsigned int i2 = ps->mloop_eval[orig_lt->tri[orig_i2_fidx]].v;
- LinkNode *node;
- /* index in face */
- int i1_fidx = -1, i2_fidx = -1;
-
- for (node = ps->vertFaces[i1]; node; node = node->next) {
- const int tri_index = POINTER_AS_INT(node->link);
-
- if (tri_index != orig_face) {
- const MLoopTri *lt = &ps->mlooptri_eval[tri_index];
- const int lt_vtri[3] = { PS_LOOPTRI_AS_VERT_INDEX_3(ps, lt) };
- /* could check if the 2 faces images match here,
- * but then there wouldn't be a way to return the opposite face's info */
-
-
- /* We need to know the order of the verts in the adjacent face
- * set the i1_fidx and i2_fidx to (0,1,2,3) */
- i1_fidx = BKE_MESH_TESSTRI_VINDEX_ORDER(lt_vtri, i1);
- i2_fidx = BKE_MESH_TESSTRI_VINDEX_ORDER(lt_vtri, i2);
-
- /* Only need to check if 'i2_fidx' is valid because we know i1_fidx is the same vert on both faces */
- if (i2_fidx != -1) {
- const float *lt_tri_uv[3] = { PS_LOOPTRI_AS_UV_3(ps->poly_to_loop_uv, lt) };
- Image *tpage = project_paint_face_paint_image(ps, tri_index);
- Image *orig_tpage = project_paint_face_paint_image(ps, orig_face);
-
- BLI_assert(i1_fidx != -1);
-
- /* This IS an adjacent face!, now lets check if the UVs are ok */
-
- /* set up the other face */
- *other_face = tri_index;
-
- /* we check if difference is 1 here, else we might have a case of edge 2-0 for a tri */
- *orig_fidx = (i1_fidx < i2_fidx && (i2_fidx - i1_fidx == 1)) ? i1_fidx : i2_fidx;
-
- /* initialize face winding if needed */
- if ((ps->faceWindingFlags[tri_index] & PROJ_FACE_WINDING_INIT) == 0)
- project_face_winding_init(ps, tri_index);
-
- /* first test if they have the same image */
- if ((orig_tpage == tpage) &&
- cmp_uv(orig_lt_tri_uv[orig_i1_fidx], lt_tri_uv[i1_fidx]) &&
- cmp_uv(orig_lt_tri_uv[orig_i2_fidx], lt_tri_uv[i2_fidx]))
- {
- /* if faces don't have the same winding in uv space,
- * they are on the same side so edge is boundary */
- if ((ps->faceWindingFlags[tri_index] & PROJ_FACE_WINDING_CW) !=
- (ps->faceWindingFlags[orig_face] & PROJ_FACE_WINDING_CW))
- {
- return 1;
- }
-
- // printf("SEAM (NONE)\n");
- return 0;
-
- }
- else {
- // printf("SEAM (UV GAP)\n");
- return 1;
- }
- }
- }
- }
- // printf("SEAM (NO FACE)\n");
- *other_face = -1;
- return 1;
+ const MLoopTri *orig_lt = &ps->mlooptri_eval[orig_face];
+ const float *orig_lt_tri_uv[3] = {PS_LOOPTRI_AS_UV_3(ps->poly_to_loop_uv, orig_lt)};
+ /* vert indices from face vert order indices */
+ const unsigned int i1 = ps->mloop_eval[orig_lt->tri[orig_i1_fidx]].v;
+ const unsigned int i2 = ps->mloop_eval[orig_lt->tri[orig_i2_fidx]].v;
+ LinkNode *node;
+ /* index in face */
+ int i1_fidx = -1, i2_fidx = -1;
+
+ for (node = ps->vertFaces[i1]; node; node = node->next) {
+ const int tri_index = POINTER_AS_INT(node->link);
+
+ if (tri_index != orig_face) {
+ const MLoopTri *lt = &ps->mlooptri_eval[tri_index];
+ const int lt_vtri[3] = {PS_LOOPTRI_AS_VERT_INDEX_3(ps, lt)};
+ /* could check if the 2 faces images match here,
+ * but then there wouldn't be a way to return the opposite face's info */
+
+ /* We need to know the order of the verts in the adjacent face
+ * set the i1_fidx and i2_fidx to (0,1,2,3) */
+ i1_fidx = BKE_MESH_TESSTRI_VINDEX_ORDER(lt_vtri, i1);
+ i2_fidx = BKE_MESH_TESSTRI_VINDEX_ORDER(lt_vtri, i2);
+
+ /* Only need to check if 'i2_fidx' is valid because we know i1_fidx is the same vert on both faces */
+ if (i2_fidx != -1) {
+ const float *lt_tri_uv[3] = {PS_LOOPTRI_AS_UV_3(ps->poly_to_loop_uv, lt)};
+ Image *tpage = project_paint_face_paint_image(ps, tri_index);
+ Image *orig_tpage = project_paint_face_paint_image(ps, orig_face);
+
+ BLI_assert(i1_fidx != -1);
+
+ /* This IS an adjacent face!, now lets check if the UVs are ok */
+
+ /* set up the other face */
+ *other_face = tri_index;
+
+ /* we check if difference is 1 here, else we might have a case of edge 2-0 for a tri */
+ *orig_fidx = (i1_fidx < i2_fidx && (i2_fidx - i1_fidx == 1)) ? i1_fidx : i2_fidx;
+
+ /* initialize face winding if needed */
+ if ((ps->faceWindingFlags[tri_index] & PROJ_FACE_WINDING_INIT) == 0)
+ project_face_winding_init(ps, tri_index);
+
+ /* first test if they have the same image */
+ if ((orig_tpage == tpage) && cmp_uv(orig_lt_tri_uv[orig_i1_fidx], lt_tri_uv[i1_fidx]) &&
+ cmp_uv(orig_lt_tri_uv[orig_i2_fidx], lt_tri_uv[i2_fidx])) {
+ /* if faces don't have the same winding in uv space,
+ * they are on the same side so edge is boundary */
+ if ((ps->faceWindingFlags[tri_index] & PROJ_FACE_WINDING_CW) !=
+ (ps->faceWindingFlags[orig_face] & PROJ_FACE_WINDING_CW)) {
+ return 1;
+ }
+
+ // printf("SEAM (NONE)\n");
+ return 0;
+ }
+ else {
+ // printf("SEAM (UV GAP)\n");
+ return 1;
+ }
+ }
+ }
+ }
+ // printf("SEAM (NO FACE)\n");
+ *other_face = -1;
+ return 1;
}
-static VertSeam *find_adjacent_seam(const ProjPaintState *ps, uint loop_index, uint vert_index, VertSeam **r_seam)
+static VertSeam *find_adjacent_seam(const ProjPaintState *ps,
+ uint loop_index,
+ uint vert_index,
+ VertSeam **r_seam)
{
- ListBase *vert_seams = &ps->vertSeams[vert_index];
- VertSeam *seam = vert_seams->first;
- VertSeam *adjacent = NULL;
-
- while (seam->loop != loop_index) {
- seam = seam->next;
- }
-
- if (r_seam) {
- *r_seam = seam;
- }
-
- /* Circulate through the (sorted) vert seam array, in the direction of the seam normal,
- * until we find the first opposing seam, matching in UV space. */
- if (seam->normal_cw) {
- LISTBASE_CIRCULAR_BACKWARD_BEGIN(vert_seams, adjacent, seam)
- {
- if ((adjacent->normal_cw != seam->normal_cw) &&
- cmp_uv(adjacent->uv, seam->uv))
- {
- break;
- }
- }
- LISTBASE_CIRCULAR_BACKWARD_END(vert_seams, adjacent, seam);
- }
- else {
- LISTBASE_CIRCULAR_FORWARD_BEGIN(vert_seams, adjacent, seam)
- {
- if ((adjacent->normal_cw != seam->normal_cw) &&
- cmp_uv(adjacent->uv, seam->uv))
- {
- break;
- }
- }
- LISTBASE_CIRCULAR_FORWARD_END(vert_seams, adjacent, seam);
- }
-
- BLI_assert(adjacent);
-
- return adjacent;
+ ListBase *vert_seams = &ps->vertSeams[vert_index];
+ VertSeam *seam = vert_seams->first;
+ VertSeam *adjacent = NULL;
+
+ while (seam->loop != loop_index) {
+ seam = seam->next;
+ }
+
+ if (r_seam) {
+ *r_seam = seam;
+ }
+
+ /* Circulate through the (sorted) vert seam array, in the direction of the seam normal,
+ * until we find the first opposing seam, matching in UV space. */
+ if (seam->normal_cw) {
+ LISTBASE_CIRCULAR_BACKWARD_BEGIN (vert_seams, adjacent, seam) {
+ if ((adjacent->normal_cw != seam->normal_cw) && cmp_uv(adjacent->uv, seam->uv)) {
+ break;
+ }
+ }
+ LISTBASE_CIRCULAR_BACKWARD_END(vert_seams, adjacent, seam);
+ }
+ else {
+ LISTBASE_CIRCULAR_FORWARD_BEGIN (vert_seams, adjacent, seam) {
+ if ((adjacent->normal_cw != seam->normal_cw) && cmp_uv(adjacent->uv, seam->uv)) {
+ break;
+ }
+ }
+ LISTBASE_CIRCULAR_FORWARD_END(vert_seams, adjacent, seam);
+ }
+
+ BLI_assert(adjacent);
+
+ return adjacent;
}
/* Computes the normal of two seams at their intersection,
* and returns the angle between the seam and its normal. */
static float compute_seam_normal(VertSeam *seam, VertSeam *adj, float r_no[2])
{
- const float PI_2 = M_PI * 2.0f;
- float angle[2];
- float angle_rel, angle_no;
+ const float PI_2 = M_PI * 2.0f;
+ float angle[2];
+ float angle_rel, angle_no;
- if (seam->normal_cw) {
- angle[0] = adj->angle;
- angle[1] = seam->angle;
- }
- else {
- angle[0] = seam->angle;
- angle[1] = adj->angle;
- }
+ if (seam->normal_cw) {
+ angle[0] = adj->angle;
+ angle[1] = seam->angle;
+ }
+ else {
+ angle[0] = seam->angle;
+ angle[1] = adj->angle;
+ }
- angle_rel = angle[1] - angle[0];
+ angle_rel = angle[1] - angle[0];
- if (angle_rel < 0.0f) {
- angle_rel += PI_2;
- }
+ if (angle_rel < 0.0f) {
+ angle_rel += PI_2;
+ }
- angle_rel *= 0.5f;
+ angle_rel *= 0.5f;
- angle_no = angle_rel + angle[0];
+ angle_no = angle_rel + angle[0];
- if (angle_no > M_PI) {
- angle_no -= PI_2;
- }
+ if (angle_no > M_PI) {
+ angle_no -= PI_2;
+ }
- r_no[0] = cosf(angle_no);
- r_no[1] = sinf(angle_no);
+ r_no[0] = cosf(angle_no);
+ r_no[1] = sinf(angle_no);
- return angle_rel;
+ return angle_rel;
}
/* Calculate outset UV's, this is not the same as simply scaling the UVs,
* since the outset coords are a margin that keep an even distance from the original UV's,
* note that the image aspect is taken into account */
-static void uv_image_outset(
- const ProjPaintState *ps, float (*orig_uv)[2], float (*puv)[2],
- uint tri_index, const int ibuf_x, const int ibuf_y)
+static void uv_image_outset(const ProjPaintState *ps,
+ float (*orig_uv)[2],
+ float (*puv)[2],
+ uint tri_index,
+ const int ibuf_x,
+ const int ibuf_y)
{
- int fidx[2];
- uint loop_index;
- uint vert[2];
- const MLoopTri *ltri = &ps->mlooptri_eval[tri_index];
+ int fidx[2];
+ uint loop_index;
+ uint vert[2];
+ const MLoopTri *ltri = &ps->mlooptri_eval[tri_index];
- float ibuf_inv[2];
+ float ibuf_inv[2];
- ibuf_inv[0] = 1.0f / (float)ibuf_x;
- ibuf_inv[1] = 1.0f / (float)ibuf_y;
+ ibuf_inv[0] = 1.0f / (float)ibuf_x;
+ ibuf_inv[1] = 1.0f / (float)ibuf_y;
- for (fidx[0] = 0; fidx[0] < 3; fidx[0]++) {
- LoopSeamData *seam_data;
- float (*seam_uvs)[2];
- float ang[2];
+ for (fidx[0] = 0; fidx[0] < 3; fidx[0]++) {
+ LoopSeamData *seam_data;
+ float(*seam_uvs)[2];
+ float ang[2];
- if ((ps->faceSeamFlags[tri_index] & (PROJ_FACE_SEAM0 << fidx[0])) == 0) {
- continue;
- }
+ if ((ps->faceSeamFlags[tri_index] & (PROJ_FACE_SEAM0 << fidx[0])) == 0) {
+ continue;
+ }
- loop_index = ltri->tri[fidx[0]];
+ loop_index = ltri->tri[fidx[0]];
- seam_data = &ps->loopSeamData[loop_index];
- seam_uvs = seam_data->seam_uvs;
+ seam_data = &ps->loopSeamData[loop_index];
+ seam_uvs = seam_data->seam_uvs;
- if (seam_uvs[0][0] != FLT_MAX) {
- continue;
- }
+ if (seam_uvs[0][0] != FLT_MAX) {
+ continue;
+ }
- fidx[1] = (fidx[0] == 2) ? 0 : fidx[0] + 1;
+ fidx[1] = (fidx[0] == 2) ? 0 : fidx[0] + 1;
- vert[0] = ps->mloop_eval[loop_index].v;
- vert[1] = ps->mloop_eval[ltri->tri[fidx[1]]].v;
+ vert[0] = ps->mloop_eval[loop_index].v;
+ vert[1] = ps->mloop_eval[ltri->tri[fidx[1]]].v;
- for (uint i = 0; i < 2; i++) {
- VertSeam *seam;
- VertSeam *adj = find_adjacent_seam(ps, loop_index, vert[i], &seam);
- float no[2];
- float len_fact;
- float tri_ang;
+ for (uint i = 0; i < 2; i++) {
+ VertSeam *seam;
+ VertSeam *adj = find_adjacent_seam(ps, loop_index, vert[i], &seam);
+ float no[2];
+ float len_fact;
+ float tri_ang;
- ang[i] = compute_seam_normal(seam, adj, no);
- tri_ang = ang[i] - M_PI_2;
+ ang[i] = compute_seam_normal(seam, adj, no);
+ tri_ang = ang[i] - M_PI_2;
- if (tri_ang > 0.0f) {
- const float dist = ps->seam_bleed_px * tanf(tri_ang);
- seam_data->corner_dist_sq[i] = SQUARE(dist);
- }
- else {
- seam_data->corner_dist_sq[i] = 0.0f;
- }
+ if (tri_ang > 0.0f) {
+ const float dist = ps->seam_bleed_px * tanf(tri_ang);
+ seam_data->corner_dist_sq[i] = SQUARE(dist);
+ }
+ else {
+ seam_data->corner_dist_sq[i] = 0.0f;
+ }
- len_fact = cosf(tri_ang);
- len_fact = UNLIKELY(len_fact < FLT_EPSILON) ? FLT_MAX : (1.0f / len_fact);
+ len_fact = cosf(tri_ang);
+ len_fact = UNLIKELY(len_fact < FLT_EPSILON) ? FLT_MAX : (1.0f / len_fact);
- /* Clamp the length factor, see: T62236. */
- len_fact = MIN2(len_fact, 10.0f);
+ /* Clamp the length factor, see: T62236. */
+ len_fact = MIN2(len_fact, 10.0f);
- mul_v2_fl(no, ps->seam_bleed_px * len_fact);
+ mul_v2_fl(no, ps->seam_bleed_px * len_fact);
- add_v2_v2v2(seam_data->seam_puvs[i], puv[fidx[i]], no);
+ add_v2_v2v2(seam_data->seam_puvs[i], puv[fidx[i]], no);
- mul_v2_v2v2(seam_uvs[i], seam_data->seam_puvs[i], ibuf_inv);
- }
+ mul_v2_v2v2(seam_uvs[i], seam_data->seam_puvs[i], ibuf_inv);
+ }
- /* Handle convergent normals (can self-intersect). */
- if ((ang[0] + ang[1]) < M_PI) {
- if (isect_seg_seg_v2_simple(orig_uv[fidx[0]], seam_uvs[0], orig_uv[fidx[1]], seam_uvs[1])) {
- float isect_co[2];
+ /* Handle convergent normals (can self-intersect). */
+ if ((ang[0] + ang[1]) < M_PI) {
+ if (isect_seg_seg_v2_simple(orig_uv[fidx[0]], seam_uvs[0], orig_uv[fidx[1]], seam_uvs[1])) {
+ float isect_co[2];
- isect_seg_seg_v2_point(orig_uv[fidx[0]], seam_uvs[0], orig_uv[fidx[1]], seam_uvs[1], isect_co);
+ isect_seg_seg_v2_point(
+ orig_uv[fidx[0]], seam_uvs[0], orig_uv[fidx[1]], seam_uvs[1], isect_co);
- copy_v2_v2(seam_uvs[0], isect_co);
- copy_v2_v2(seam_uvs[1], isect_co);
- }
- }
-
- }
+ copy_v2_v2(seam_uvs[0], isect_co);
+ copy_v2_v2(seam_uvs[1], isect_co);
+ }
+ }
+ }
}
-static void insert_seam_vert_array(
- const ProjPaintState *ps, MemArena *arena, const int tri_index,
- const int fidx1, const int ibuf_x, const int ibuf_y)
+static void insert_seam_vert_array(const ProjPaintState *ps,
+ MemArena *arena,
+ const int tri_index,
+ const int fidx1,
+ const int ibuf_x,
+ const int ibuf_y)
{
- const MLoopTri *lt = &ps->mlooptri_eval[tri_index];
- const float *lt_tri_uv[3] = {PS_LOOPTRI_AS_UV_3(ps->poly_to_loop_uv, lt)};
- const int fidx[2] = {fidx1, ((fidx1 + 1) % 3)};
- float vec[2];
+ const MLoopTri *lt = &ps->mlooptri_eval[tri_index];
+ const float *lt_tri_uv[3] = {PS_LOOPTRI_AS_UV_3(ps->poly_to_loop_uv, lt)};
+ const int fidx[2] = {fidx1, ((fidx1 + 1) % 3)};
+ float vec[2];
- VertSeam *vseam = BLI_memarena_alloc(arena, sizeof(VertSeam) * 2);
+ VertSeam *vseam = BLI_memarena_alloc(arena, sizeof(VertSeam) * 2);
- vseam->prev = NULL;
- vseam->next = NULL;
+ vseam->prev = NULL;
+ vseam->next = NULL;
- vseam->tri = tri_index;
- vseam->loop = lt->tri[fidx[0]];
+ vseam->tri = tri_index;
+ vseam->loop = lt->tri[fidx[0]];
- sub_v2_v2v2(vec, lt_tri_uv[fidx[1]], lt_tri_uv[fidx[0]]);
- vec[0] *= ibuf_x;
- vec[1] *= ibuf_y;
- vseam->angle = atan2f(vec[1], vec[0]);
+ sub_v2_v2v2(vec, lt_tri_uv[fidx[1]], lt_tri_uv[fidx[0]]);
+ vec[0] *= ibuf_x;
+ vec[1] *= ibuf_y;
+ vseam->angle = atan2f(vec[1], vec[0]);
- /* If face windings are not initialized, something must be wrong. */
- BLI_assert((ps->faceWindingFlags[tri_index] & PROJ_FACE_WINDING_INIT) != 0);
- vseam->normal_cw = (ps->faceWindingFlags[tri_index] & PROJ_FACE_WINDING_CW);
+ /* If face windings are not initialized, something must be wrong. */
+ BLI_assert((ps->faceWindingFlags[tri_index] & PROJ_FACE_WINDING_INIT) != 0);
+ vseam->normal_cw = (ps->faceWindingFlags[tri_index] & PROJ_FACE_WINDING_CW);
- copy_v2_v2(vseam->uv, lt_tri_uv[fidx[0]]);
+ copy_v2_v2(vseam->uv, lt_tri_uv[fidx[0]]);
- vseam[1] = vseam[0];
- vseam[1].angle += vseam[1].angle > 0.0f ? -M_PI : M_PI;
- vseam[1].normal_cw = !vseam[1].normal_cw;
- copy_v2_v2(vseam[1].uv, lt_tri_uv[fidx[1]]);
+ vseam[1] = vseam[0];
+ vseam[1].angle += vseam[1].angle > 0.0f ? -M_PI : M_PI;
+ vseam[1].normal_cw = !vseam[1].normal_cw;
+ copy_v2_v2(vseam[1].uv, lt_tri_uv[fidx[1]]);
- for (uint i = 0; i < 2; i++) {
- uint vert = ps->mloop_eval[lt->tri[fidx[i]]].v;
- ListBase *list = &ps->vertSeams[vert];
- VertSeam *item = list->first;
+ for (uint i = 0; i < 2; i++) {
+ uint vert = ps->mloop_eval[lt->tri[fidx[i]]].v;
+ ListBase *list = &ps->vertSeams[vert];
+ VertSeam *item = list->first;
- while (item && item->angle < vseam[i].angle) {
- item = item->next;
- }
+ while (item && item->angle < vseam[i].angle) {
+ item = item->next;
+ }
- BLI_insertlinkbefore(list, item, &vseam[i]);
- }
+ BLI_insertlinkbefore(list, item, &vseam[i]);
+ }
}
/*
@@ -1402,144 +1398,151 @@ static void insert_seam_vert_array(
*
* If we're multithreadng, make sure threads are locked when this is called
*/
-static void project_face_seams_init(
- const ProjPaintState *ps, MemArena *arena, const int tri_index, const uint vert_index,
- bool init_all, const int ibuf_x, const int ibuf_y)
+static void project_face_seams_init(const ProjPaintState *ps,
+ MemArena *arena,
+ const int tri_index,
+ const uint vert_index,
+ bool init_all,
+ const int ibuf_x,
+ const int ibuf_y)
{
- /* vars for the other face, we also set its flag */
- int other_face, other_fidx;
- /* next fidx in the face (0,1,2,3) -> (1,2,3,0) or (0,1,2) -> (1,2,0) for a tri */
- int fidx[2] = {2, 0};
- const MLoopTri *lt = &ps->mlooptri_eval[tri_index];
- LinkNode *node;
-
- /* initialize face winding if needed */
- if ((ps->faceWindingFlags[tri_index] & PROJ_FACE_WINDING_INIT) == 0)
- project_face_winding_init(ps, tri_index);
-
- do {
- if (init_all ||
- (ps->mloop_eval[lt->tri[fidx[0]]].v == vert_index) ||
- (ps->mloop_eval[lt->tri[fidx[1]]].v == vert_index))
- {
- if ((ps->faceSeamFlags[tri_index] & (PROJ_FACE_SEAM0 << fidx[0] | PROJ_FACE_NOSEAM0 << fidx[0])) == 0) {
- if (check_seam(ps, tri_index, fidx[0], fidx[1], &other_face, &other_fidx)) {
- ps->faceSeamFlags[tri_index] |= PROJ_FACE_SEAM0 << fidx[0];
- insert_seam_vert_array(ps, arena, tri_index, fidx[0], ibuf_x, ibuf_y);
-
- if (other_face != -1) {
- /* Check if the other seam is already set. We don't want to insert it in the list twice. */
- if ((ps->faceSeamFlags[other_face] & (PROJ_FACE_SEAM0 << other_fidx)) == 0) {
- ps->faceSeamFlags[other_face] |= PROJ_FACE_SEAM0 << other_fidx;
- insert_seam_vert_array(ps, arena, other_face, other_fidx, ibuf_x, ibuf_y);
- }
- }
- }
- else {
- ps->faceSeamFlags[tri_index] |= PROJ_FACE_NOSEAM0 << fidx[0];
- ps->faceSeamFlags[tri_index] |= PROJ_FACE_SEAM_INIT0 << fidx[0];
-
- if (other_face != -1) {
- /* second 4 bits for disabled */
- ps->faceSeamFlags[other_face] |= PROJ_FACE_NOSEAM0 << other_fidx;
- ps->faceSeamFlags[other_face] |= PROJ_FACE_SEAM_INIT0 << other_fidx;
- }
- }
- }
- }
-
- fidx[1] = fidx[0];
- } while (fidx[0]--);
-
- if (init_all) {
- char checked_verts = 0;
-
- fidx[0] = 2;
- fidx[1] = 0;
-
- do {
- if ((ps->faceSeamFlags[tri_index] & (PROJ_FACE_SEAM_INIT0 << fidx[0])) == 0) {
- for (uint i = 0; i < 2; i++) {
- uint vert;
-
- if ((checked_verts & (1 << fidx[i])) != 0) {
- continue;
- }
-
- vert = ps->mloop_eval[lt->tri[fidx[i]]].v;
-
- for (node = ps->vertFaces[vert]; node; node = node->next) {
- const int tri = POINTER_AS_INT(node->link);
-
- project_face_seams_init(ps, arena, tri, vert, false, ibuf_x, ibuf_y);
- }
-
- checked_verts |= 1 << fidx[i];
- }
-
- ps->faceSeamFlags[tri_index] |= PROJ_FACE_SEAM_INIT0 << fidx[0];
- }
-
- fidx[1] = fidx[0];
- } while (fidx[0]--);
- }
+ /* vars for the other face, we also set its flag */
+ int other_face, other_fidx;
+ /* next fidx in the face (0,1,2,3) -> (1,2,3,0) or (0,1,2) -> (1,2,0) for a tri */
+ int fidx[2] = {2, 0};
+ const MLoopTri *lt = &ps->mlooptri_eval[tri_index];
+ LinkNode *node;
+
+ /* initialize face winding if needed */
+ if ((ps->faceWindingFlags[tri_index] & PROJ_FACE_WINDING_INIT) == 0)
+ project_face_winding_init(ps, tri_index);
+
+ do {
+ if (init_all || (ps->mloop_eval[lt->tri[fidx[0]]].v == vert_index) ||
+ (ps->mloop_eval[lt->tri[fidx[1]]].v == vert_index)) {
+ if ((ps->faceSeamFlags[tri_index] &
+ (PROJ_FACE_SEAM0 << fidx[0] | PROJ_FACE_NOSEAM0 << fidx[0])) == 0) {
+ if (check_seam(ps, tri_index, fidx[0], fidx[1], &other_face, &other_fidx)) {
+ ps->faceSeamFlags[tri_index] |= PROJ_FACE_SEAM0 << fidx[0];
+ insert_seam_vert_array(ps, arena, tri_index, fidx[0], ibuf_x, ibuf_y);
+
+ if (other_face != -1) {
+ /* Check if the other seam is already set. We don't want to insert it in the list twice. */
+ if ((ps->faceSeamFlags[other_face] & (PROJ_FACE_SEAM0 << other_fidx)) == 0) {
+ ps->faceSeamFlags[other_face] |= PROJ_FACE_SEAM0 << other_fidx;
+ insert_seam_vert_array(ps, arena, other_face, other_fidx, ibuf_x, ibuf_y);
+ }
+ }
+ }
+ else {
+ ps->faceSeamFlags[tri_index] |= PROJ_FACE_NOSEAM0 << fidx[0];
+ ps->faceSeamFlags[tri_index] |= PROJ_FACE_SEAM_INIT0 << fidx[0];
+
+ if (other_face != -1) {
+ /* second 4 bits for disabled */
+ ps->faceSeamFlags[other_face] |= PROJ_FACE_NOSEAM0 << other_fidx;
+ ps->faceSeamFlags[other_face] |= PROJ_FACE_SEAM_INIT0 << other_fidx;
+ }
+ }
+ }
+ }
+
+ fidx[1] = fidx[0];
+ } while (fidx[0]--);
+
+ if (init_all) {
+ char checked_verts = 0;
+
+ fidx[0] = 2;
+ fidx[1] = 0;
+
+ do {
+ if ((ps->faceSeamFlags[tri_index] & (PROJ_FACE_SEAM_INIT0 << fidx[0])) == 0) {
+ for (uint i = 0; i < 2; i++) {
+ uint vert;
+
+ if ((checked_verts & (1 << fidx[i])) != 0) {
+ continue;
+ }
+
+ vert = ps->mloop_eval[lt->tri[fidx[i]]].v;
+
+ for (node = ps->vertFaces[vert]; node; node = node->next) {
+ const int tri = POINTER_AS_INT(node->link);
+
+ project_face_seams_init(ps, arena, tri, vert, false, ibuf_x, ibuf_y);
+ }
+
+ checked_verts |= 1 << fidx[i];
+ }
+
+ ps->faceSeamFlags[tri_index] |= PROJ_FACE_SEAM_INIT0 << fidx[0];
+ }
+
+ fidx[1] = fidx[0];
+ } while (fidx[0]--);
+ }
}
-#endif // PROJ_DEBUG_NOSEAMBLEED
-
+#endif // PROJ_DEBUG_NOSEAMBLEED
/* Converts a UV location to a 3D screenspace location
* Takes a 'uv' and 3 UV coords, and sets the values of pixelScreenCo
*
* This is used for finding a pixels location in screenspace for painting */
-static void screen_px_from_ortho(
- const float uv[2],
- const float v1co[3], const float v2co[3], const float v3co[3], /* Screenspace coords */
- const float uv1co[2], const float uv2co[2], const float uv3co[2],
- float pixelScreenCo[4],
- float w[3])
+static void screen_px_from_ortho(const float uv[2],
+ const float v1co[3],
+ const float v2co[3],
+ const float v3co[3], /* Screenspace coords */
+ const float uv1co[2],
+ const float uv2co[2],
+ const float uv3co[2],
+ float pixelScreenCo[4],
+ float w[3])
{
- barycentric_weights_v2(uv1co, uv2co, uv3co, uv, w);
- interp_v3_v3v3v3(pixelScreenCo, v1co, v2co, v3co, w);
+ barycentric_weights_v2(uv1co, uv2co, uv3co, uv, w);
+ interp_v3_v3v3v3(pixelScreenCo, v1co, v2co, v3co, w);
}
/* same as screen_px_from_ortho except we
* do perspective correction on the pixel coordinate */
-static void screen_px_from_persp(
- const float uv[2],
- const float v1co[4], const float v2co[4], const float v3co[4], /* screenspace coords */
- const float uv1co[2], const float uv2co[2], const float uv3co[2],
- float pixelScreenCo[4],
- float w[3])
+static void screen_px_from_persp(const float uv[2],
+ const float v1co[4],
+ const float v2co[4],
+ const float v3co[4], /* screenspace coords */
+ const float uv1co[2],
+ const float uv2co[2],
+ const float uv3co[2],
+ float pixelScreenCo[4],
+ float w[3])
{
- float w_int[3];
- float wtot_inv, wtot;
- barycentric_weights_v2(uv1co, uv2co, uv3co, uv, w);
-
- /* re-weight from the 4th coord of each screen vert */
- w_int[0] = w[0] * v1co[3];
- w_int[1] = w[1] * v2co[3];
- w_int[2] = w[2] * v3co[3];
-
- wtot = w_int[0] + w_int[1] + w_int[2];
-
- if (wtot > 0.0f) {
- wtot_inv = 1.0f / wtot;
- w_int[0] *= wtot_inv;
- w_int[1] *= wtot_inv;
- w_int[2] *= wtot_inv;
- }
- else {
- w[0] = w[1] = w[2] =
- /* dummy values for zero area face */
- w_int[0] = w_int[1] = w_int[2] = 1.0f / 3.0f;
- }
- /* done re-weighting */
-
- /* do interpolation based on projected weight */
- interp_v3_v3v3v3(pixelScreenCo, v1co, v2co, v3co, w_int);
+ float w_int[3];
+ float wtot_inv, wtot;
+ barycentric_weights_v2(uv1co, uv2co, uv3co, uv, w);
+
+ /* re-weight from the 4th coord of each screen vert */
+ w_int[0] = w[0] * v1co[3];
+ w_int[1] = w[1] * v2co[3];
+ w_int[2] = w[2] * v3co[3];
+
+ wtot = w_int[0] + w_int[1] + w_int[2];
+
+ if (wtot > 0.0f) {
+ wtot_inv = 1.0f / wtot;
+ w_int[0] *= wtot_inv;
+ w_int[1] *= wtot_inv;
+ w_int[2] *= wtot_inv;
+ }
+ else {
+ w[0] = w[1] = w[2] =
+ /* dummy values for zero area face */
+ w_int[0] = w_int[1] = w_int[2] = 1.0f / 3.0f;
+ }
+ /* done re-weighting */
+
+ /* do interpolation based on projected weight */
+ interp_v3_v3v3v3(pixelScreenCo, v1co, v2co, v3co, w_int);
}
-
/**
* Set a direction vector based on a screen location.
* (use for perspective view, else we can simply use `ps->viewDir`)
@@ -1548,16 +1551,18 @@ static void screen_px_from_persp(
*
* \param r_dir: Resulting direction (length is undefined).
*/
-static void screen_px_to_vector_persp(
- int winx, int winy, const float projmat_inv[4][4], const float view_pos[3],
- const float co_px[2],
- float r_dir[3])
+static void screen_px_to_vector_persp(int winx,
+ int winy,
+ const float projmat_inv[4][4],
+ const float view_pos[3],
+ const float co_px[2],
+ float r_dir[3])
{
- r_dir[0] = 2.0f * (co_px[0] / winx) - 1.0f;
- r_dir[1] = 2.0f * (co_px[1] / winy) - 1.0f;
- r_dir[2] = -0.5f;
- mul_project_m4_v3((float(*)[4])projmat_inv, r_dir);
- sub_v3_v3(r_dir, view_pos);
+ r_dir[0] = 2.0f * (co_px[0] / winx) - 1.0f;
+ r_dir[1] = 2.0f * (co_px[1] / winy) - 1.0f;
+ r_dir[2] = -0.5f;
+ mul_project_m4_v3((float(*)[4])projmat_inv, r_dir);
+ sub_v3_v3(r_dir, view_pos);
}
/**
@@ -1568,578 +1573,601 @@ static void screen_px_to_vector_persp(
* \param p: 2D screen-space location.
* \param v1, v2: 3D object-space locations.
*/
-static float screen_px_line_point_factor_v2_persp(
- const ProjPaintState *ps,
- const float p[2],
- const float v1[3], const float v2[3])
+static float screen_px_line_point_factor_v2_persp(const ProjPaintState *ps,
+ const float p[2],
+ const float v1[3],
+ const float v2[3])
{
- const float zero[3] = {0};
- float v1_proj[3], v2_proj[3];
- float dir[3];
+ const float zero[3] = {0};
+ float v1_proj[3], v2_proj[3];
+ float dir[3];
- screen_px_to_vector_persp(ps->winx, ps->winy, ps->projectMatInv, ps->viewPos, p, dir);
+ screen_px_to_vector_persp(ps->winx, ps->winy, ps->projectMatInv, ps->viewPos, p, dir);
- sub_v3_v3v3(v1_proj, v1, ps->viewPos);
- sub_v3_v3v3(v2_proj, v2, ps->viewPos);
+ sub_v3_v3v3(v1_proj, v1, ps->viewPos);
+ sub_v3_v3v3(v2_proj, v2, ps->viewPos);
- project_plane_v3_v3v3(v1_proj, v1_proj, dir);
- project_plane_v3_v3v3(v2_proj, v2_proj, dir);
+ project_plane_v3_v3v3(v1_proj, v1_proj, dir);
+ project_plane_v3_v3v3(v2_proj, v2_proj, dir);
- return line_point_factor_v2(zero, v1_proj, v2_proj);
+ return line_point_factor_v2(zero, v1_proj, v2_proj);
}
-
-static void project_face_pixel(
- const float *lt_tri_uv[3], ImBuf *ibuf_other, const float w[3],
- unsigned char rgba_ub[4], float rgba_f[4])
+static void project_face_pixel(const float *lt_tri_uv[3],
+ ImBuf *ibuf_other,
+ const float w[3],
+ unsigned char rgba_ub[4],
+ float rgba_f[4])
{
- float uv_other[2], x, y;
-
- interp_v2_v2v2v2(uv_other, UNPACK3(lt_tri_uv), w);
+ float uv_other[2], x, y;
- /* use */
- uvco_to_wrapped_pxco(uv_other, ibuf_other->x, ibuf_other->y, &x, &y);
+ interp_v2_v2v2v2(uv_other, UNPACK3(lt_tri_uv), w);
- if (ibuf_other->rect_float) { /* from float to float */
- bilinear_interpolation_color_wrap(ibuf_other, NULL, rgba_f, x, y);
- }
- else { /* from char to float */
- bilinear_interpolation_color_wrap(ibuf_other, rgba_ub, NULL, x, y);
- }
+ /* use */
+ uvco_to_wrapped_pxco(uv_other, ibuf_other->x, ibuf_other->y, &x, &y);
+ if (ibuf_other->rect_float) { /* from float to float */
+ bilinear_interpolation_color_wrap(ibuf_other, NULL, rgba_f, x, y);
+ }
+ else { /* from char to float */
+ bilinear_interpolation_color_wrap(ibuf_other, rgba_ub, NULL, x, y);
+ }
}
/* run this outside project_paint_uvpixel_init since pixels with mask 0 don't need init */
-static float project_paint_uvpixel_mask(
- const ProjPaintState *ps,
- const int tri_index,
- const float w[3])
+static float project_paint_uvpixel_mask(const ProjPaintState *ps,
+ const int tri_index,
+ const float w[3])
{
- float mask;
-
- /* Image Mask */
- if (ps->do_layer_stencil) {
- /* another UV maps image is masking this one's */
- ImBuf *ibuf_other;
- Image *other_tpage = ps->stencil_ima;
-
- if (other_tpage && (ibuf_other = BKE_image_acquire_ibuf(other_tpage, NULL, NULL))) {
- const MLoopTri *lt_other = &ps->mlooptri_eval[tri_index];
- const float *lt_other_tri_uv[3] = { PS_LOOPTRI_AS_UV_3(ps->poly_to_loop_uv, lt_other) };
-
- /* BKE_image_acquire_ibuf - TODO - this may be slow */
- unsigned char rgba_ub[4];
- float rgba_f[4];
-
- project_face_pixel(lt_other_tri_uv, ibuf_other, w, rgba_ub, rgba_f);
-
- if (ibuf_other->rect_float) { /* from float to float */
- mask = ((rgba_f[0] + rgba_f[1] + rgba_f[2]) * (1.0f / 3.0f)) * rgba_f[3];
- }
- else { /* from char to float */
- mask = ((rgba_ub[0] + rgba_ub[1] + rgba_ub[2]) * (1.0f / (255.0f * 3.0f))) * (rgba_ub[3] * (1.0f / 255.0f));
- }
-
- BKE_image_release_ibuf(other_tpage, ibuf_other, NULL);
-
- if (!ps->do_layer_stencil_inv) {
- /* matching the gimps layer mask black/white rules, white==full opacity */
- mask = (1.0f - mask);
- }
-
- if (mask == 0.0f) {
- return 0.0f;
- }
- }
- else {
- return 0.0f;
- }
- }
- else {
- mask = 1.0f;
- }
-
- if (ps->do_mask_cavity) {
- const MLoopTri *lt = &ps->mlooptri_eval[tri_index];
- const int lt_vtri[3] = { PS_LOOPTRI_AS_VERT_INDEX_3(ps, lt) };
- float ca1, ca2, ca3, ca_mask;
- ca1 = ps->cavities[lt_vtri[0]];
- ca2 = ps->cavities[lt_vtri[1]];
- ca3 = ps->cavities[lt_vtri[2]];
-
- ca_mask = w[0] * ca1 + w[1] * ca2 + w[2] * ca3;
- ca_mask = curvemapping_evaluateF(ps->cavity_curve, 0, ca_mask);
- CLAMP(ca_mask, 0.0f, 1.0f);
- mask *= ca_mask;
- }
-
- /* calculate mask */
- if (ps->do_mask_normal) {
- const MLoopTri *lt = &ps->mlooptri_eval[tri_index];
- const int lt_vtri[3] = { PS_LOOPTRI_AS_VERT_INDEX_3(ps, lt) };
- const MPoly *mp = &ps->mpoly_eval[lt->poly];
- float no[3], angle_cos;
-
- if (mp->flag & ME_SMOOTH) {
- const short *no1, *no2, *no3;
- no1 = ps->mvert_eval[lt_vtri[0]].no;
- no2 = ps->mvert_eval[lt_vtri[1]].no;
- no3 = ps->mvert_eval[lt_vtri[2]].no;
-
- no[0] = w[0] * no1[0] + w[1] * no2[0] + w[2] * no3[0];
- no[1] = w[0] * no1[1] + w[1] * no2[1] + w[2] * no3[1];
- no[2] = w[0] * no1[2] + w[1] * no2[2] + w[2] * no3[2];
- normalize_v3(no);
- }
- else {
- /* incase the */
+ float mask;
+
+ /* Image Mask */
+ if (ps->do_layer_stencil) {
+ /* another UV maps image is masking this one's */
+ ImBuf *ibuf_other;
+ Image *other_tpage = ps->stencil_ima;
+
+ if (other_tpage && (ibuf_other = BKE_image_acquire_ibuf(other_tpage, NULL, NULL))) {
+ const MLoopTri *lt_other = &ps->mlooptri_eval[tri_index];
+ const float *lt_other_tri_uv[3] = {PS_LOOPTRI_AS_UV_3(ps->poly_to_loop_uv, lt_other)};
+
+ /* BKE_image_acquire_ibuf - TODO - this may be slow */
+ unsigned char rgba_ub[4];
+ float rgba_f[4];
+
+ project_face_pixel(lt_other_tri_uv, ibuf_other, w, rgba_ub, rgba_f);
+
+ if (ibuf_other->rect_float) { /* from float to float */
+ mask = ((rgba_f[0] + rgba_f[1] + rgba_f[2]) * (1.0f / 3.0f)) * rgba_f[3];
+ }
+ else { /* from char to float */
+ mask = ((rgba_ub[0] + rgba_ub[1] + rgba_ub[2]) * (1.0f / (255.0f * 3.0f))) *
+ (rgba_ub[3] * (1.0f / 255.0f));
+ }
+
+ BKE_image_release_ibuf(other_tpage, ibuf_other, NULL);
+
+ if (!ps->do_layer_stencil_inv) {
+ /* matching the gimps layer mask black/white rules, white==full opacity */
+ mask = (1.0f - mask);
+ }
+
+ if (mask == 0.0f) {
+ return 0.0f;
+ }
+ }
+ else {
+ return 0.0f;
+ }
+ }
+ else {
+ mask = 1.0f;
+ }
+
+ if (ps->do_mask_cavity) {
+ const MLoopTri *lt = &ps->mlooptri_eval[tri_index];
+ const int lt_vtri[3] = {PS_LOOPTRI_AS_VERT_INDEX_3(ps, lt)};
+ float ca1, ca2, ca3, ca_mask;
+ ca1 = ps->cavities[lt_vtri[0]];
+ ca2 = ps->cavities[lt_vtri[1]];
+ ca3 = ps->cavities[lt_vtri[2]];
+
+ ca_mask = w[0] * ca1 + w[1] * ca2 + w[2] * ca3;
+ ca_mask = curvemapping_evaluateF(ps->cavity_curve, 0, ca_mask);
+ CLAMP(ca_mask, 0.0f, 1.0f);
+ mask *= ca_mask;
+ }
+
+ /* calculate mask */
+ if (ps->do_mask_normal) {
+ const MLoopTri *lt = &ps->mlooptri_eval[tri_index];
+ const int lt_vtri[3] = {PS_LOOPTRI_AS_VERT_INDEX_3(ps, lt)};
+ const MPoly *mp = &ps->mpoly_eval[lt->poly];
+ float no[3], angle_cos;
+
+ if (mp->flag & ME_SMOOTH) {
+ const short *no1, *no2, *no3;
+ no1 = ps->mvert_eval[lt_vtri[0]].no;
+ no2 = ps->mvert_eval[lt_vtri[1]].no;
+ no3 = ps->mvert_eval[lt_vtri[2]].no;
+
+ no[0] = w[0] * no1[0] + w[1] * no2[0] + w[2] * no3[0];
+ no[1] = w[0] * no1[1] + w[1] * no2[1] + w[2] * no3[1];
+ no[2] = w[0] * no1[2] + w[1] * no2[2] + w[2] * no3[2];
+ normalize_v3(no);
+ }
+ else {
+ /* incase the */
#if 1
- /* normalizing per pixel isn't optimal, we could cache or check ps->*/
- normal_tri_v3(no,
- ps->mvert_eval[lt_vtri[0]].co,
- ps->mvert_eval[lt_vtri[1]].co,
- ps->mvert_eval[lt_vtri[2]].co);
+ /* normalizing per pixel isn't optimal, we could cache or check ps->*/
+ normal_tri_v3(no,
+ ps->mvert_eval[lt_vtri[0]].co,
+ ps->mvert_eval[lt_vtri[1]].co,
+ ps->mvert_eval[lt_vtri[2]].co);
#else
- /* don't use because some modifiers dont have normal data (subsurf for eg) */
- copy_v3_v3(no, (float *)ps->dm->getTessFaceData(ps->dm, tri_index, CD_NORMAL));
+ /* don't use because some modifiers dont have normal data (subsurf for eg) */
+ copy_v3_v3(no, (float *)ps->dm->getTessFaceData(ps->dm, tri_index, CD_NORMAL));
#endif
- }
-
- if (UNLIKELY(ps->is_flip_object)) {
- negate_v3(no);
- }
-
- /* now we can use the normal as a mask */
- if (ps->is_ortho) {
- angle_cos = dot_v3v3(ps->viewDir, no);
- }
- else {
- /* Annoying but for the perspective view we need to get the pixels location in 3D space :/ */
- float viewDirPersp[3];
- const float *co1, *co2, *co3;
- co1 = ps->mvert_eval[lt_vtri[0]].co;
- co2 = ps->mvert_eval[lt_vtri[1]].co;
- co3 = ps->mvert_eval[lt_vtri[2]].co;
-
- /* Get the direction from the viewPoint to the pixel and normalize */
- viewDirPersp[0] = (ps->viewPos[0] - (w[0] * co1[0] + w[1] * co2[0] + w[2] * co3[0]));
- viewDirPersp[1] = (ps->viewPos[1] - (w[0] * co1[1] + w[1] * co2[1] + w[2] * co3[1]));
- viewDirPersp[2] = (ps->viewPos[2] - (w[0] * co1[2] + w[1] * co2[2] + w[2] * co3[2]));
- normalize_v3(viewDirPersp);
- if (UNLIKELY(ps->is_flip_object)) {
- negate_v3(viewDirPersp);
- }
-
- angle_cos = dot_v3v3(viewDirPersp, no);
- }
-
- /* If backface culling is disabled, allow painting on back faces. */
- if (!ps->do_backfacecull) {
- angle_cos = fabsf(angle_cos);
- }
-
- if (angle_cos <= ps->normal_angle__cos) {
- /* outsize the normal limit*/
- return 0.0f;
- }
- else if (angle_cos < ps->normal_angle_inner__cos) {
- mask *= (ps->normal_angle - acosf(angle_cos)) / ps->normal_angle_range;
- } /* otherwise no mask normal is needed, were within the limit */
- }
-
- /* This only works when the opacity doesn't change while painting, stylus pressure messes with this
- * so don't use it. */
- // if (ps->is_airbrush == 0) mask *= BKE_brush_alpha_get(ps->brush);
-
- return mask;
+ }
+
+ if (UNLIKELY(ps->is_flip_object)) {
+ negate_v3(no);
+ }
+
+ /* now we can use the normal as a mask */
+ if (ps->is_ortho) {
+ angle_cos = dot_v3v3(ps->viewDir, no);
+ }
+ else {
+ /* Annoying but for the perspective view we need to get the pixels location in 3D space :/ */
+ float viewDirPersp[3];
+ const float *co1, *co2, *co3;
+ co1 = ps->mvert_eval[lt_vtri[0]].co;
+ co2 = ps->mvert_eval[lt_vtri[1]].co;
+ co3 = ps->mvert_eval[lt_vtri[2]].co;
+
+ /* Get the direction from the viewPoint to the pixel and normalize */
+ viewDirPersp[0] = (ps->viewPos[0] - (w[0] * co1[0] + w[1] * co2[0] + w[2] * co3[0]));
+ viewDirPersp[1] = (ps->viewPos[1] - (w[0] * co1[1] + w[1] * co2[1] + w[2] * co3[1]));
+ viewDirPersp[2] = (ps->viewPos[2] - (w[0] * co1[2] + w[1] * co2[2] + w[2] * co3[2]));
+ normalize_v3(viewDirPersp);
+ if (UNLIKELY(ps->is_flip_object)) {
+ negate_v3(viewDirPersp);
+ }
+
+ angle_cos = dot_v3v3(viewDirPersp, no);
+ }
+
+ /* If backface culling is disabled, allow painting on back faces. */
+ if (!ps->do_backfacecull) {
+ angle_cos = fabsf(angle_cos);
+ }
+
+ if (angle_cos <= ps->normal_angle__cos) {
+ /* outsize the normal limit*/
+ return 0.0f;
+ }
+ else if (angle_cos < ps->normal_angle_inner__cos) {
+ mask *= (ps->normal_angle - acosf(angle_cos)) / ps->normal_angle_range;
+ } /* otherwise no mask normal is needed, were within the limit */
+ }
+
+ /* This only works when the opacity doesn't change while painting, stylus pressure messes with this
+ * so don't use it. */
+ // if (ps->is_airbrush == 0) mask *= BKE_brush_alpha_get(ps->brush);
+
+ return mask;
}
static int project_paint_pixel_sizeof(const short tool)
{
- if ((tool == PAINT_TOOL_CLONE) || (tool == PAINT_TOOL_SMEAR)) {
- return sizeof(ProjPixelClone);
- }
- else {
- return sizeof(ProjPixel);
- }
+ if ((tool == PAINT_TOOL_CLONE) || (tool == PAINT_TOOL_SMEAR)) {
+ return sizeof(ProjPixelClone);
+ }
+ else {
+ return sizeof(ProjPixel);
+ }
}
static int project_paint_undo_subtiles(const TileInfo *tinf, int tx, int ty)
{
- ProjPaintImage *pjIma = tinf->pjima;
- int tile_index = tx + ty * tinf->tile_width;
- bool generate_tile = false;
-
- /* double check lock to avoid locking */
- if (UNLIKELY(!pjIma->undoRect[tile_index])) {
- if (tinf->lock)
- BLI_spin_lock(tinf->lock);
- if (LIKELY(!pjIma->undoRect[tile_index])) {
- pjIma->undoRect[tile_index] = TILE_PENDING;
- generate_tile = true;
- }
- if (tinf->lock)
- BLI_spin_unlock(tinf->lock);
- }
-
-
- if (generate_tile) {
- ListBase *undo_tiles = ED_image_undo_get_tiles();
- volatile void *undorect;
- if (tinf->masked) {
- undorect = image_undo_push_tile(
- undo_tiles, pjIma->ima, pjIma->ibuf, tinf->tmpibuf,
- tx, ty, &pjIma->maskRect[tile_index], &pjIma->valid[tile_index], true, false);
- }
- else {
- undorect = image_undo_push_tile(
- undo_tiles, pjIma->ima, pjIma->ibuf, tinf->tmpibuf,
- tx, ty, NULL, &pjIma->valid[tile_index], true, false);
- }
-
- pjIma->ibuf->userflags |= IB_BITMAPDIRTY;
- /* tile ready, publish */
- if (tinf->lock)
- BLI_spin_lock(tinf->lock);
- pjIma->undoRect[tile_index] = undorect;
- if (tinf->lock)
- BLI_spin_unlock(tinf->lock);
-
- }
-
- return tile_index;
+ ProjPaintImage *pjIma = tinf->pjima;
+ int tile_index = tx + ty * tinf->tile_width;
+ bool generate_tile = false;
+
+ /* double check lock to avoid locking */
+ if (UNLIKELY(!pjIma->undoRect[tile_index])) {
+ if (tinf->lock)
+ BLI_spin_lock(tinf->lock);
+ if (LIKELY(!pjIma->undoRect[tile_index])) {
+ pjIma->undoRect[tile_index] = TILE_PENDING;
+ generate_tile = true;
+ }
+ if (tinf->lock)
+ BLI_spin_unlock(tinf->lock);
+ }
+
+ if (generate_tile) {
+ ListBase *undo_tiles = ED_image_undo_get_tiles();
+ volatile void *undorect;
+ if (tinf->masked) {
+ undorect = image_undo_push_tile(undo_tiles,
+ pjIma->ima,
+ pjIma->ibuf,
+ tinf->tmpibuf,
+ tx,
+ ty,
+ &pjIma->maskRect[tile_index],
+ &pjIma->valid[tile_index],
+ true,
+ false);
+ }
+ else {
+ undorect = image_undo_push_tile(undo_tiles,
+ pjIma->ima,
+ pjIma->ibuf,
+ tinf->tmpibuf,
+ tx,
+ ty,
+ NULL,
+ &pjIma->valid[tile_index],
+ true,
+ false);
+ }
+
+ pjIma->ibuf->userflags |= IB_BITMAPDIRTY;
+ /* tile ready, publish */
+ if (tinf->lock)
+ BLI_spin_lock(tinf->lock);
+ pjIma->undoRect[tile_index] = undorect;
+ if (tinf->lock)
+ BLI_spin_unlock(tinf->lock);
+ }
+
+ return tile_index;
}
/* run this function when we know a bucket's, face's pixel can be initialized,
* return the ProjPixel which is added to 'ps->bucketRect[bucket_index]' */
-static ProjPixel *project_paint_uvpixel_init(
- const ProjPaintState *ps,
- MemArena *arena,
- const TileInfo *tinf,
- int x_px, int y_px,
- const float mask,
- const int tri_index,
- const float pixelScreenCo[4],
- const float world_spaceCo[3],
- const float w[3])
+static ProjPixel *project_paint_uvpixel_init(const ProjPaintState *ps,
+ MemArena *arena,
+ const TileInfo *tinf,
+ int x_px,
+ int y_px,
+ const float mask,
+ const int tri_index,
+ const float pixelScreenCo[4],
+ const float world_spaceCo[3],
+ const float w[3])
{
- ProjPixel *projPixel;
- int x_tile, y_tile;
- int x_round, y_round;
- int tile_offset;
- /* volatile is important here to ensure pending check is not optimized away by compiler*/
- volatile int tile_index;
-
- ProjPaintImage *projima = tinf->pjima;
- ImBuf *ibuf = projima->ibuf;
- /* wrap pixel location */
-
- x_px = mod_i(x_px, ibuf->x);
- y_px = mod_i(y_px, ibuf->y);
-
- BLI_assert(ps->pixel_sizeof == project_paint_pixel_sizeof(ps->tool));
- projPixel = BLI_memarena_alloc(arena, ps->pixel_sizeof);
-
- /* calculate the undo tile offset of the pixel, used to store the original
- * pixel color and accumulated mask if any */
- x_tile = x_px >> IMAPAINT_TILE_BITS;
- y_tile = y_px >> IMAPAINT_TILE_BITS;
-
- x_round = x_tile * IMAPAINT_TILE_SIZE;
- y_round = y_tile * IMAPAINT_TILE_SIZE;
- //memset(projPixel, 0, size);
-
- tile_offset = (x_px - x_round) + (y_px - y_round) * IMAPAINT_TILE_SIZE;
- tile_index = project_paint_undo_subtiles(tinf, x_tile, y_tile);
-
- /* other thread may be initializing the tile so wait here */
- while (projima->undoRect[tile_index] == TILE_PENDING)
- ;
-
- BLI_assert(tile_index < (IMAPAINT_TILE_NUMBER(ibuf->x) * IMAPAINT_TILE_NUMBER(ibuf->y)));
- BLI_assert(tile_offset < (IMAPAINT_TILE_SIZE * IMAPAINT_TILE_SIZE));
-
- projPixel->valid = projima->valid[tile_index];
-
- if (ibuf->rect_float) {
- projPixel->pixel.f_pt = ibuf->rect_float + ((x_px + y_px * ibuf->x) * 4);
- projPixel->origColor.f_pt = (float *)projima->undoRect[tile_index] + 4 * tile_offset;
- zero_v4(projPixel->newColor.f);
- }
- else {
- projPixel->pixel.ch_pt = (unsigned char *)(ibuf->rect + (x_px + y_px * ibuf->x));
- projPixel->origColor.uint_pt = (unsigned int *)projima->undoRect[tile_index] + tile_offset;
- projPixel->newColor.uint = 0;
- }
-
- /* screenspace unclamped, we could keep its z and w values but don't need them at the moment */
- if (ps->brush->mtex.brush_map_mode == MTEX_MAP_MODE_3D) {
- copy_v3_v3(projPixel->worldCoSS, world_spaceCo);
- }
-
- copy_v2_v2(projPixel->projCoSS, pixelScreenCo);
-
- projPixel->x_px = x_px;
- projPixel->y_px = y_px;
-
- projPixel->mask = (unsigned short)(mask * 65535);
- if (ps->do_masking)
- projPixel->mask_accum = projima->maskRect[tile_index] + tile_offset;
- else
- projPixel->mask_accum = NULL;
-
- /* which bounding box cell are we in?, needed for undo */
- projPixel->bb_cell_index = ((int)(((float)x_px / (float)ibuf->x) * PROJ_BOUNDBOX_DIV)) +
- ((int)(((float)y_px / (float)ibuf->y) * PROJ_BOUNDBOX_DIV)) * PROJ_BOUNDBOX_DIV;
-
- /* done with view3d_project_float inline */
- if (ps->tool == PAINT_TOOL_CLONE) {
- if (ps->poly_to_loop_uv_clone) {
- ImBuf *ibuf_other;
- Image *other_tpage = project_paint_face_clone_image(ps, tri_index);
-
- if (other_tpage && (ibuf_other = BKE_image_acquire_ibuf(other_tpage, NULL, NULL))) {
- const MLoopTri *lt_other = &ps->mlooptri_eval[tri_index];
- const float *lt_other_tri_uv[3] = { PS_LOOPTRI_AS_UV_3(ps->poly_to_loop_uv_clone, lt_other) };
-
- /* BKE_image_acquire_ibuf - TODO - this may be slow */
-
- if (ibuf->rect_float) {
- if (ibuf_other->rect_float) { /* from float to float */
- project_face_pixel(lt_other_tri_uv, ibuf_other, w, NULL, ((ProjPixelClone *)projPixel)->clonepx.f);
- }
- else { /* from char to float */
- unsigned char rgba_ub[4];
- float rgba[4];
- project_face_pixel(lt_other_tri_uv, ibuf_other, w, rgba_ub, NULL);
- if (ps->use_colormanagement) {
- srgb_to_linearrgb_uchar4(rgba, rgba_ub);
- }
- else {
- rgba_uchar_to_float(rgba, rgba_ub);
- }
- straight_to_premul_v4_v4(((ProjPixelClone *)projPixel)->clonepx.f, rgba);
- }
- }
- else {
- if (ibuf_other->rect_float) { /* float to char */
- float rgba[4];
- project_face_pixel(lt_other_tri_uv, ibuf_other, w, NULL, rgba);
- premul_to_straight_v4(rgba);
- if (ps->use_colormanagement) {
- linearrgb_to_srgb_uchar3(((ProjPixelClone *)projPixel)->clonepx.ch, rgba);
- }
- else {
- rgb_float_to_uchar(((ProjPixelClone *)projPixel)->clonepx.ch, rgba);
- }
- ((ProjPixelClone *)projPixel)->clonepx.ch[3] = rgba[3] * 255;
- }
- else { /* char to char */
- project_face_pixel(lt_other_tri_uv, ibuf_other, w, ((ProjPixelClone *)projPixel)->clonepx.ch, NULL);
- }
- }
-
- BKE_image_release_ibuf(other_tpage, ibuf_other, NULL);
- }
- else {
- if (ibuf->rect_float) {
- ((ProjPixelClone *)projPixel)->clonepx.f[3] = 0;
- }
- else {
- ((ProjPixelClone *)projPixel)->clonepx.ch[3] = 0;
- }
- }
-
- }
- else {
- float co[2];
- sub_v2_v2v2(co, projPixel->projCoSS, ps->cloneOffset);
-
- /* no need to initialize the bucket, we're only checking buckets faces and for this
- * the faces are already initialized in project_paint_delayed_face_init(...) */
- if (ibuf->rect_float) {
- if (!project_paint_PickColor(ps, co, ((ProjPixelClone *)projPixel)->clonepx.f, NULL, 1)) {
- /* zero alpha - ignore */
- ((ProjPixelClone *)projPixel)->clonepx.f[3] = 0;
- }
- }
- else {
- if (!project_paint_PickColor(ps, co, NULL, ((ProjPixelClone *)projPixel)->clonepx.ch, 1)) {
- /* zero alpha - ignore */
- ((ProjPixelClone *)projPixel)->clonepx.ch[3] = 0;
- }
- }
- }
- }
+ ProjPixel *projPixel;
+ int x_tile, y_tile;
+ int x_round, y_round;
+ int tile_offset;
+ /* volatile is important here to ensure pending check is not optimized away by compiler*/
+ volatile int tile_index;
+
+ ProjPaintImage *projima = tinf->pjima;
+ ImBuf *ibuf = projima->ibuf;
+ /* wrap pixel location */
+
+ x_px = mod_i(x_px, ibuf->x);
+ y_px = mod_i(y_px, ibuf->y);
+
+ BLI_assert(ps->pixel_sizeof == project_paint_pixel_sizeof(ps->tool));
+ projPixel = BLI_memarena_alloc(arena, ps->pixel_sizeof);
+
+ /* calculate the undo tile offset of the pixel, used to store the original
+ * pixel color and accumulated mask if any */
+ x_tile = x_px >> IMAPAINT_TILE_BITS;
+ y_tile = y_px >> IMAPAINT_TILE_BITS;
+
+ x_round = x_tile * IMAPAINT_TILE_SIZE;
+ y_round = y_tile * IMAPAINT_TILE_SIZE;
+ //memset(projPixel, 0, size);
+
+ tile_offset = (x_px - x_round) + (y_px - y_round) * IMAPAINT_TILE_SIZE;
+ tile_index = project_paint_undo_subtiles(tinf, x_tile, y_tile);
+
+ /* other thread may be initializing the tile so wait here */
+ while (projima->undoRect[tile_index] == TILE_PENDING)
+ ;
+
+ BLI_assert(tile_index < (IMAPAINT_TILE_NUMBER(ibuf->x) * IMAPAINT_TILE_NUMBER(ibuf->y)));
+ BLI_assert(tile_offset < (IMAPAINT_TILE_SIZE * IMAPAINT_TILE_SIZE));
+
+ projPixel->valid = projima->valid[tile_index];
+
+ if (ibuf->rect_float) {
+ projPixel->pixel.f_pt = ibuf->rect_float + ((x_px + y_px * ibuf->x) * 4);
+ projPixel->origColor.f_pt = (float *)projima->undoRect[tile_index] + 4 * tile_offset;
+ zero_v4(projPixel->newColor.f);
+ }
+ else {
+ projPixel->pixel.ch_pt = (unsigned char *)(ibuf->rect + (x_px + y_px * ibuf->x));
+ projPixel->origColor.uint_pt = (unsigned int *)projima->undoRect[tile_index] + tile_offset;
+ projPixel->newColor.uint = 0;
+ }
+
+ /* screenspace unclamped, we could keep its z and w values but don't need them at the moment */
+ if (ps->brush->mtex.brush_map_mode == MTEX_MAP_MODE_3D) {
+ copy_v3_v3(projPixel->worldCoSS, world_spaceCo);
+ }
+
+ copy_v2_v2(projPixel->projCoSS, pixelScreenCo);
+
+ projPixel->x_px = x_px;
+ projPixel->y_px = y_px;
+
+ projPixel->mask = (unsigned short)(mask * 65535);
+ if (ps->do_masking)
+ projPixel->mask_accum = projima->maskRect[tile_index] + tile_offset;
+ else
+ projPixel->mask_accum = NULL;
+
+ /* which bounding box cell are we in?, needed for undo */
+ projPixel->bb_cell_index = ((int)(((float)x_px / (float)ibuf->x) * PROJ_BOUNDBOX_DIV)) +
+ ((int)(((float)y_px / (float)ibuf->y) * PROJ_BOUNDBOX_DIV)) *
+ PROJ_BOUNDBOX_DIV;
+
+ /* done with view3d_project_float inline */
+ if (ps->tool == PAINT_TOOL_CLONE) {
+ if (ps->poly_to_loop_uv_clone) {
+ ImBuf *ibuf_other;
+ Image *other_tpage = project_paint_face_clone_image(ps, tri_index);
+
+ if (other_tpage && (ibuf_other = BKE_image_acquire_ibuf(other_tpage, NULL, NULL))) {
+ const MLoopTri *lt_other = &ps->mlooptri_eval[tri_index];
+ const float *lt_other_tri_uv[3] = {
+ PS_LOOPTRI_AS_UV_3(ps->poly_to_loop_uv_clone, lt_other)};
+
+ /* BKE_image_acquire_ibuf - TODO - this may be slow */
+
+ if (ibuf->rect_float) {
+ if (ibuf_other->rect_float) { /* from float to float */
+ project_face_pixel(
+ lt_other_tri_uv, ibuf_other, w, NULL, ((ProjPixelClone *)projPixel)->clonepx.f);
+ }
+ else { /* from char to float */
+ unsigned char rgba_ub[4];
+ float rgba[4];
+ project_face_pixel(lt_other_tri_uv, ibuf_other, w, rgba_ub, NULL);
+ if (ps->use_colormanagement) {
+ srgb_to_linearrgb_uchar4(rgba, rgba_ub);
+ }
+ else {
+ rgba_uchar_to_float(rgba, rgba_ub);
+ }
+ straight_to_premul_v4_v4(((ProjPixelClone *)projPixel)->clonepx.f, rgba);
+ }
+ }
+ else {
+ if (ibuf_other->rect_float) { /* float to char */
+ float rgba[4];
+ project_face_pixel(lt_other_tri_uv, ibuf_other, w, NULL, rgba);
+ premul_to_straight_v4(rgba);
+ if (ps->use_colormanagement) {
+ linearrgb_to_srgb_uchar3(((ProjPixelClone *)projPixel)->clonepx.ch, rgba);
+ }
+ else {
+ rgb_float_to_uchar(((ProjPixelClone *)projPixel)->clonepx.ch, rgba);
+ }
+ ((ProjPixelClone *)projPixel)->clonepx.ch[3] = rgba[3] * 255;
+ }
+ else { /* char to char */
+ project_face_pixel(
+ lt_other_tri_uv, ibuf_other, w, ((ProjPixelClone *)projPixel)->clonepx.ch, NULL);
+ }
+ }
+
+ BKE_image_release_ibuf(other_tpage, ibuf_other, NULL);
+ }
+ else {
+ if (ibuf->rect_float) {
+ ((ProjPixelClone *)projPixel)->clonepx.f[3] = 0;
+ }
+ else {
+ ((ProjPixelClone *)projPixel)->clonepx.ch[3] = 0;
+ }
+ }
+ }
+ else {
+ float co[2];
+ sub_v2_v2v2(co, projPixel->projCoSS, ps->cloneOffset);
+
+ /* no need to initialize the bucket, we're only checking buckets faces and for this
+ * the faces are already initialized in project_paint_delayed_face_init(...) */
+ if (ibuf->rect_float) {
+ if (!project_paint_PickColor(ps, co, ((ProjPixelClone *)projPixel)->clonepx.f, NULL, 1)) {
+ /* zero alpha - ignore */
+ ((ProjPixelClone *)projPixel)->clonepx.f[3] = 0;
+ }
+ }
+ else {
+ if (!project_paint_PickColor(ps, co, NULL, ((ProjPixelClone *)projPixel)->clonepx.ch, 1)) {
+ /* zero alpha - ignore */
+ ((ProjPixelClone *)projPixel)->clonepx.ch[3] = 0;
+ }
+ }
+ }
+ }
#ifdef PROJ_DEBUG_PAINT
- if (ibuf->rect_float) projPixel->pixel.f_pt[0] = 0;
- else projPixel->pixel.ch_pt[0] = 0;
+ if (ibuf->rect_float)
+ projPixel->pixel.f_pt[0] = 0;
+ else
+ projPixel->pixel.ch_pt[0] = 0;
#endif
- /* pointer arithmetic */
- projPixel->image_index = projima - ps->projImages;
+ /* pointer arithmetic */
+ projPixel->image_index = projima - ps->projImages;
- return projPixel;
+ return projPixel;
}
-static bool line_clip_rect2f(
- const rctf *cliprect,
- const rctf *rect,
- const float l1[2], const float l2[2],
- float l1_clip[2], float l2_clip[2])
+static bool line_clip_rect2f(const rctf *cliprect,
+ const rctf *rect,
+ const float l1[2],
+ const float l2[2],
+ float l1_clip[2],
+ float l2_clip[2])
{
- /* first account for horizontal, then vertical lines */
- /* horiz */
- if (fabsf(l1[1] - l2[1]) < PROJ_PIXEL_TOLERANCE) {
- /* is the line out of range on its Y axis? */
- if (l1[1] < rect->ymin || l1[1] > rect->ymax) {
- return 0;
- }
- /* line is out of range on its X axis */
- if ((l1[0] < rect->xmin && l2[0] < rect->xmin) || (l1[0] > rect->xmax && l2[0] > rect->xmax)) {
- return 0;
- }
-
-
- /* this is a single point (or close to)*/
- if (fabsf(l1[0] - l2[0]) < PROJ_PIXEL_TOLERANCE) {
- if (BLI_rctf_isect_pt_v(rect, l1)) {
- copy_v2_v2(l1_clip, l1);
- copy_v2_v2(l2_clip, l2);
- return 1;
- }
- else {
- return 0;
- }
- }
-
- copy_v2_v2(l1_clip, l1);
- copy_v2_v2(l2_clip, l2);
- CLAMP(l1_clip[0], rect->xmin, rect->xmax);
- CLAMP(l2_clip[0], rect->xmin, rect->xmax);
- return 1;
- }
- else if (fabsf(l1[0] - l2[0]) < PROJ_PIXEL_TOLERANCE) {
- /* is the line out of range on its X axis? */
- if (l1[0] < rect->xmin || l1[0] > rect->xmax) {
- return 0;
- }
-
- /* line is out of range on its Y axis */
- if ((l1[1] < rect->ymin && l2[1] < rect->ymin) || (l1[1] > rect->ymax && l2[1] > rect->ymax)) {
- return 0;
- }
-
- /* this is a single point (or close to)*/
- if (fabsf(l1[1] - l2[1]) < PROJ_PIXEL_TOLERANCE) {
- if (BLI_rctf_isect_pt_v(rect, l1)) {
- copy_v2_v2(l1_clip, l1);
- copy_v2_v2(l2_clip, l2);
- return 1;
- }
- else {
- return 0;
- }
- }
-
- copy_v2_v2(l1_clip, l1);
- copy_v2_v2(l2_clip, l2);
- CLAMP(l1_clip[1], rect->ymin, rect->ymax);
- CLAMP(l2_clip[1], rect->ymin, rect->ymax);
- return 1;
- }
- else {
- float isect;
- short ok1 = 0;
- short ok2 = 0;
-
- /* Done with vertical lines */
-
- /* are either of the points inside the rectangle ? */
- if (BLI_rctf_isect_pt_v(rect, l1)) {
- copy_v2_v2(l1_clip, l1);
- ok1 = 1;
- }
-
- if (BLI_rctf_isect_pt_v(rect, l2)) {
- copy_v2_v2(l2_clip, l2);
- ok2 = 1;
- }
-
- /* line inside rect */
- if (ok1 && ok2) return 1;
-
- /* top/bottom */
- if (line_isect_y(l1, l2, rect->ymin, &isect) && (isect >= cliprect->xmin) && (isect <= cliprect->xmax)) {
- if (l1[1] < l2[1]) { /* line 1 is outside */
- l1_clip[0] = isect;
- l1_clip[1] = rect->ymin;
- ok1 = 1;
- }
- else {
- l2_clip[0] = isect;
- l2_clip[1] = rect->ymin;
- ok2 = 2;
- }
- }
-
- if (ok1 && ok2) return 1;
-
- if (line_isect_y(l1, l2, rect->ymax, &isect) && (isect >= cliprect->xmin) && (isect <= cliprect->xmax)) {
- if (l1[1] > l2[1]) { /* line 1 is outside */
- l1_clip[0] = isect;
- l1_clip[1] = rect->ymax;
- ok1 = 1;
- }
- else {
- l2_clip[0] = isect;
- l2_clip[1] = rect->ymax;
- ok2 = 2;
- }
- }
-
- if (ok1 && ok2) return 1;
-
- /* left/right */
- if (line_isect_x(l1, l2, rect->xmin, &isect) && (isect >= cliprect->ymin) && (isect <= cliprect->ymax)) {
- if (l1[0] < l2[0]) { /* line 1 is outside */
- l1_clip[0] = rect->xmin;
- l1_clip[1] = isect;
- ok1 = 1;
- }
- else {
- l2_clip[0] = rect->xmin;
- l2_clip[1] = isect;
- ok2 = 2;
- }
- }
-
- if (ok1 && ok2) return 1;
-
- if (line_isect_x(l1, l2, rect->xmax, &isect) && (isect >= cliprect->ymin) && (isect <= cliprect->ymax)) {
- if (l1[0] > l2[0]) { /* line 1 is outside */
- l1_clip[0] = rect->xmax;
- l1_clip[1] = isect;
- ok1 = 1;
- }
- else {
- l2_clip[0] = rect->xmax;
- l2_clip[1] = isect;
- ok2 = 2;
- }
- }
-
- if (ok1 && ok2) {
- return 1;
- }
- else {
- return 0;
- }
- }
+ /* first account for horizontal, then vertical lines */
+ /* horiz */
+ if (fabsf(l1[1] - l2[1]) < PROJ_PIXEL_TOLERANCE) {
+ /* is the line out of range on its Y axis? */
+ if (l1[1] < rect->ymin || l1[1] > rect->ymax) {
+ return 0;
+ }
+ /* line is out of range on its X axis */
+ if ((l1[0] < rect->xmin && l2[0] < rect->xmin) || (l1[0] > rect->xmax && l2[0] > rect->xmax)) {
+ return 0;
+ }
+
+ /* this is a single point (or close to)*/
+ if (fabsf(l1[0] - l2[0]) < PROJ_PIXEL_TOLERANCE) {
+ if (BLI_rctf_isect_pt_v(rect, l1)) {
+ copy_v2_v2(l1_clip, l1);
+ copy_v2_v2(l2_clip, l2);
+ return 1;
+ }
+ else {
+ return 0;
+ }
+ }
+
+ copy_v2_v2(l1_clip, l1);
+ copy_v2_v2(l2_clip, l2);
+ CLAMP(l1_clip[0], rect->xmin, rect->xmax);
+ CLAMP(l2_clip[0], rect->xmin, rect->xmax);
+ return 1;
+ }
+ else if (fabsf(l1[0] - l2[0]) < PROJ_PIXEL_TOLERANCE) {
+ /* is the line out of range on its X axis? */
+ if (l1[0] < rect->xmin || l1[0] > rect->xmax) {
+ return 0;
+ }
+
+ /* line is out of range on its Y axis */
+ if ((l1[1] < rect->ymin && l2[1] < rect->ymin) || (l1[1] > rect->ymax && l2[1] > rect->ymax)) {
+ return 0;
+ }
+
+ /* this is a single point (or close to)*/
+ if (fabsf(l1[1] - l2[1]) < PROJ_PIXEL_TOLERANCE) {
+ if (BLI_rctf_isect_pt_v(rect, l1)) {
+ copy_v2_v2(l1_clip, l1);
+ copy_v2_v2(l2_clip, l2);
+ return 1;
+ }
+ else {
+ return 0;
+ }
+ }
+
+ copy_v2_v2(l1_clip, l1);
+ copy_v2_v2(l2_clip, l2);
+ CLAMP(l1_clip[1], rect->ymin, rect->ymax);
+ CLAMP(l2_clip[1], rect->ymin, rect->ymax);
+ return 1;
+ }
+ else {
+ float isect;
+ short ok1 = 0;
+ short ok2 = 0;
+
+ /* Done with vertical lines */
+
+ /* are either of the points inside the rectangle ? */
+ if (BLI_rctf_isect_pt_v(rect, l1)) {
+ copy_v2_v2(l1_clip, l1);
+ ok1 = 1;
+ }
+
+ if (BLI_rctf_isect_pt_v(rect, l2)) {
+ copy_v2_v2(l2_clip, l2);
+ ok2 = 1;
+ }
+
+ /* line inside rect */
+ if (ok1 && ok2)
+ return 1;
+
+ /* top/bottom */
+ if (line_isect_y(l1, l2, rect->ymin, &isect) && (isect >= cliprect->xmin) &&
+ (isect <= cliprect->xmax)) {
+ if (l1[1] < l2[1]) { /* line 1 is outside */
+ l1_clip[0] = isect;
+ l1_clip[1] = rect->ymin;
+ ok1 = 1;
+ }
+ else {
+ l2_clip[0] = isect;
+ l2_clip[1] = rect->ymin;
+ ok2 = 2;
+ }
+ }
+
+ if (ok1 && ok2)
+ return 1;
+
+ if (line_isect_y(l1, l2, rect->ymax, &isect) && (isect >= cliprect->xmin) &&
+ (isect <= cliprect->xmax)) {
+ if (l1[1] > l2[1]) { /* line 1 is outside */
+ l1_clip[0] = isect;
+ l1_clip[1] = rect->ymax;
+ ok1 = 1;
+ }
+ else {
+ l2_clip[0] = isect;
+ l2_clip[1] = rect->ymax;
+ ok2 = 2;
+ }
+ }
+
+ if (ok1 && ok2)
+ return 1;
+
+ /* left/right */
+ if (line_isect_x(l1, l2, rect->xmin, &isect) && (isect >= cliprect->ymin) &&
+ (isect <= cliprect->ymax)) {
+ if (l1[0] < l2[0]) { /* line 1 is outside */
+ l1_clip[0] = rect->xmin;
+ l1_clip[1] = isect;
+ ok1 = 1;
+ }
+ else {
+ l2_clip[0] = rect->xmin;
+ l2_clip[1] = isect;
+ ok2 = 2;
+ }
+ }
+
+ if (ok1 && ok2)
+ return 1;
+
+ if (line_isect_x(l1, l2, rect->xmax, &isect) && (isect >= cliprect->ymin) &&
+ (isect <= cliprect->ymax)) {
+ if (l1[0] > l2[0]) { /* line 1 is outside */
+ l1_clip[0] = rect->xmax;
+ l1_clip[1] = isect;
+ ok1 = 1;
+ }
+ else {
+ l2_clip[0] = rect->xmax;
+ l2_clip[1] = isect;
+ ok2 = 2;
+ }
+ }
+
+ if (ok1 && ok2) {
+ return 1;
+ }
+ else {
+ return 0;
+ }
+ }
}
-
-
/**
* Scale the tri about its center
* scaling by #PROJ_FACE_SCALE_SEAM (0.99x) is used for getting fake UV pixel coords that are on the
@@ -2149,82 +2177,93 @@ static bool line_clip_rect2f(
static void scale_tri(float insetCos[3][3], const float *origCos[4], const float inset)
{
- float cent[3];
- cent[0] = (origCos[0][0] + origCos[1][0] + origCos[2][0]) * (1.0f / 3.0f);
- cent[1] = (origCos[0][1] + origCos[1][1] + origCos[2][1]) * (1.0f / 3.0f);
- cent[2] = (origCos[0][2] + origCos[1][2] + origCos[2][2]) * (1.0f / 3.0f);
-
- sub_v3_v3v3(insetCos[0], origCos[0], cent);
- sub_v3_v3v3(insetCos[1], origCos[1], cent);
- sub_v3_v3v3(insetCos[2], origCos[2], cent);
-
- mul_v3_fl(insetCos[0], inset);
- mul_v3_fl(insetCos[1], inset);
- mul_v3_fl(insetCos[2], inset);
-
- add_v3_v3(insetCos[0], cent);
- add_v3_v3(insetCos[1], cent);
- add_v3_v3(insetCos[2], cent);
+ float cent[3];
+ cent[0] = (origCos[0][0] + origCos[1][0] + origCos[2][0]) * (1.0f / 3.0f);
+ cent[1] = (origCos[0][1] + origCos[1][1] + origCos[2][1]) * (1.0f / 3.0f);
+ cent[2] = (origCos[0][2] + origCos[1][2] + origCos[2][2]) * (1.0f / 3.0f);
+
+ sub_v3_v3v3(insetCos[0], origCos[0], cent);
+ sub_v3_v3v3(insetCos[1], origCos[1], cent);
+ sub_v3_v3v3(insetCos[2], origCos[2], cent);
+
+ mul_v3_fl(insetCos[0], inset);
+ mul_v3_fl(insetCos[1], inset);
+ mul_v3_fl(insetCos[2], inset);
+
+ add_v3_v3(insetCos[0], cent);
+ add_v3_v3(insetCos[1], cent);
+ add_v3_v3(insetCos[2], cent);
}
-#endif //PROJ_DEBUG_NOSEAMBLEED
+#endif //PROJ_DEBUG_NOSEAMBLEED
static float len_squared_v2v2_alt(const float v1[2], const float v2_1, const float v2_2)
{
- float x, y;
+ float x, y;
- x = v1[0] - v2_1;
- y = v1[1] - v2_2;
- return x * x + y * y;
+ x = v1[0] - v2_1;
+ y = v1[1] - v2_2;
+ return x * x + y * y;
}
/* note, use a squared value so we can use len_squared_v2v2
* be sure that you have done a bounds check first or this may fail */
/* only give bucket_bounds as an arg because we need it elsewhere */
-static bool project_bucket_isect_circle(const float cent[2], const float radius_squared, const rctf *bucket_bounds)
+static bool project_bucket_isect_circle(const float cent[2],
+ const float radius_squared,
+ const rctf *bucket_bounds)
{
- /* Would normally to a simple intersection test, however we know the bounds of these 2 already intersect
- * so we only need to test if the center is inside the vertical or horizontal bounds on either axis,
- * this is even less work then an intersection test
- */
+ /* Would normally to a simple intersection test, however we know the bounds of these 2 already intersect
+ * so we only need to test if the center is inside the vertical or horizontal bounds on either axis,
+ * this is even less work then an intersection test
+ */
#if 0
- if (BLI_rctf_isect_pt_v(bucket_bounds, cent))
- return 1;
+ if (BLI_rctf_isect_pt_v(bucket_bounds, cent))
+ return 1;
#endif
- if ((bucket_bounds->xmin <= cent[0] && bucket_bounds->xmax >= cent[0]) ||
- (bucket_bounds->ymin <= cent[1] && bucket_bounds->ymax >= cent[1]))
- {
- return 1;
- }
-
- /* out of bounds left */
- if (cent[0] < bucket_bounds->xmin) {
- /* lower left out of radius test */
- if (cent[1] < bucket_bounds->ymin) {
- return (len_squared_v2v2_alt(cent, bucket_bounds->xmin, bucket_bounds->ymin) < radius_squared) ? 1 : 0;
- }
- /* top left test */
- else if (cent[1] > bucket_bounds->ymax) {
- return (len_squared_v2v2_alt(cent, bucket_bounds->xmin, bucket_bounds->ymax) < radius_squared) ? 1 : 0;
- }
- }
- else if (cent[0] > bucket_bounds->xmax) {
- /* lower right out of radius test */
- if (cent[1] < bucket_bounds->ymin) {
- return (len_squared_v2v2_alt(cent, bucket_bounds->xmax, bucket_bounds->ymin) < radius_squared) ? 1 : 0;
- }
- /* top right test */
- else if (cent[1] > bucket_bounds->ymax) {
- return (len_squared_v2v2_alt(cent, bucket_bounds->xmax, bucket_bounds->ymax) < radius_squared) ? 1 : 0;
- }
- }
-
- return 0;
+ if ((bucket_bounds->xmin <= cent[0] && bucket_bounds->xmax >= cent[0]) ||
+ (bucket_bounds->ymin <= cent[1] && bucket_bounds->ymax >= cent[1])) {
+ return 1;
+ }
+
+ /* out of bounds left */
+ if (cent[0] < bucket_bounds->xmin) {
+ /* lower left out of radius test */
+ if (cent[1] < bucket_bounds->ymin) {
+ return (len_squared_v2v2_alt(cent, bucket_bounds->xmin, bucket_bounds->ymin) <
+ radius_squared) ?
+ 1 :
+ 0;
+ }
+ /* top left test */
+ else if (cent[1] > bucket_bounds->ymax) {
+ return (len_squared_v2v2_alt(cent, bucket_bounds->xmin, bucket_bounds->ymax) <
+ radius_squared) ?
+ 1 :
+ 0;
+ }
+ }
+ else if (cent[0] > bucket_bounds->xmax) {
+ /* lower right out of radius test */
+ if (cent[1] < bucket_bounds->ymin) {
+ return (len_squared_v2v2_alt(cent, bucket_bounds->xmax, bucket_bounds->ymin) <
+ radius_squared) ?
+ 1 :
+ 0;
+ }
+ /* top right test */
+ else if (cent[1] > bucket_bounds->ymax) {
+ return (len_squared_v2v2_alt(cent, bucket_bounds->xmax, bucket_bounds->ymax) <
+ radius_squared) ?
+ 1 :
+ 0;
+ }
+ }
+
+ return 0;
}
-
-
/* Note for rect_to_uvspace_ortho() and rect_to_uvspace_persp()
* in ortho view this function gives good results when bucket_bounds are outside the triangle
* however in some cases, perspective view will mess up with faces that have minimal screenspace area
@@ -2234,70 +2273,75 @@ static bool project_bucket_isect_circle(const float cent[2], const float radius_
* funcs that only account for points inside the triangle.
* however switching back to this for ortho is always an option */
-static void rect_to_uvspace_ortho(
- const rctf *bucket_bounds,
- const float *v1coSS, const float *v2coSS, const float *v3coSS,
- const float *uv1co, const float *uv2co, const float *uv3co,
- float bucket_bounds_uv[4][2],
- const int flip)
+static void rect_to_uvspace_ortho(const rctf *bucket_bounds,
+ const float *v1coSS,
+ const float *v2coSS,
+ const float *v3coSS,
+ const float *uv1co,
+ const float *uv2co,
+ const float *uv3co,
+ float bucket_bounds_uv[4][2],
+ const int flip)
{
- float uv[2];
- float w[3];
-
- /* get the UV space bounding box */
- uv[0] = bucket_bounds->xmax;
- uv[1] = bucket_bounds->ymin;
- barycentric_weights_v2(v1coSS, v2coSS, v3coSS, uv, w);
- interp_v2_v2v2v2(bucket_bounds_uv[flip ? 3 : 0], uv1co, uv2co, uv3co, w);
-
- //uv[0] = bucket_bounds->xmax; // set above
- uv[1] = bucket_bounds->ymax;
- barycentric_weights_v2(v1coSS, v2coSS, v3coSS, uv, w);
- interp_v2_v2v2v2(bucket_bounds_uv[flip ? 2 : 1], uv1co, uv2co, uv3co, w);
-
- uv[0] = bucket_bounds->xmin;
- //uv[1] = bucket_bounds->ymax; // set above
- barycentric_weights_v2(v1coSS, v2coSS, v3coSS, uv, w);
- interp_v2_v2v2v2(bucket_bounds_uv[flip ? 1 : 2], uv1co, uv2co, uv3co, w);
-
- //uv[0] = bucket_bounds->xmin; // set above
- uv[1] = bucket_bounds->ymin;
- barycentric_weights_v2(v1coSS, v2coSS, v3coSS, uv, w);
- interp_v2_v2v2v2(bucket_bounds_uv[flip ? 0 : 3], uv1co, uv2co, uv3co, w);
+ float uv[2];
+ float w[3];
+
+ /* get the UV space bounding box */
+ uv[0] = bucket_bounds->xmax;
+ uv[1] = bucket_bounds->ymin;
+ barycentric_weights_v2(v1coSS, v2coSS, v3coSS, uv, w);
+ interp_v2_v2v2v2(bucket_bounds_uv[flip ? 3 : 0], uv1co, uv2co, uv3co, w);
+
+ //uv[0] = bucket_bounds->xmax; // set above
+ uv[1] = bucket_bounds->ymax;
+ barycentric_weights_v2(v1coSS, v2coSS, v3coSS, uv, w);
+ interp_v2_v2v2v2(bucket_bounds_uv[flip ? 2 : 1], uv1co, uv2co, uv3co, w);
+
+ uv[0] = bucket_bounds->xmin;
+ //uv[1] = bucket_bounds->ymax; // set above
+ barycentric_weights_v2(v1coSS, v2coSS, v3coSS, uv, w);
+ interp_v2_v2v2v2(bucket_bounds_uv[flip ? 1 : 2], uv1co, uv2co, uv3co, w);
+
+ //uv[0] = bucket_bounds->xmin; // set above
+ uv[1] = bucket_bounds->ymin;
+ barycentric_weights_v2(v1coSS, v2coSS, v3coSS, uv, w);
+ interp_v2_v2v2v2(bucket_bounds_uv[flip ? 0 : 3], uv1co, uv2co, uv3co, w);
}
/* same as above but use barycentric_weights_v2_persp */
-static void rect_to_uvspace_persp(
- const rctf *bucket_bounds,
- const float *v1coSS, const float *v2coSS, const float *v3coSS,
- const float *uv1co, const float *uv2co, const float *uv3co,
- float bucket_bounds_uv[4][2],
- const int flip
- )
+static void rect_to_uvspace_persp(const rctf *bucket_bounds,
+ const float *v1coSS,
+ const float *v2coSS,
+ const float *v3coSS,
+ const float *uv1co,
+ const float *uv2co,
+ const float *uv3co,
+ float bucket_bounds_uv[4][2],
+ const int flip)
{
- float uv[2];
- float w[3];
-
- /* get the UV space bounding box */
- uv[0] = bucket_bounds->xmax;
- uv[1] = bucket_bounds->ymin;
- barycentric_weights_v2_persp(v1coSS, v2coSS, v3coSS, uv, w);
- interp_v2_v2v2v2(bucket_bounds_uv[flip ? 3 : 0], uv1co, uv2co, uv3co, w);
-
- //uv[0] = bucket_bounds->xmax; // set above
- uv[1] = bucket_bounds->ymax;
- barycentric_weights_v2_persp(v1coSS, v2coSS, v3coSS, uv, w);
- interp_v2_v2v2v2(bucket_bounds_uv[flip ? 2 : 1], uv1co, uv2co, uv3co, w);
-
- uv[0] = bucket_bounds->xmin;
- //uv[1] = bucket_bounds->ymax; // set above
- barycentric_weights_v2_persp(v1coSS, v2coSS, v3coSS, uv, w);
- interp_v2_v2v2v2(bucket_bounds_uv[flip ? 1 : 2], uv1co, uv2co, uv3co, w);
-
- //uv[0] = bucket_bounds->xmin; // set above
- uv[1] = bucket_bounds->ymin;
- barycentric_weights_v2_persp(v1coSS, v2coSS, v3coSS, uv, w);
- interp_v2_v2v2v2(bucket_bounds_uv[flip ? 0 : 3], uv1co, uv2co, uv3co, w);
+ float uv[2];
+ float w[3];
+
+ /* get the UV space bounding box */
+ uv[0] = bucket_bounds->xmax;
+ uv[1] = bucket_bounds->ymin;
+ barycentric_weights_v2_persp(v1coSS, v2coSS, v3coSS, uv, w);
+ interp_v2_v2v2v2(bucket_bounds_uv[flip ? 3 : 0], uv1co, uv2co, uv3co, w);
+
+ //uv[0] = bucket_bounds->xmax; // set above
+ uv[1] = bucket_bounds->ymax;
+ barycentric_weights_v2_persp(v1coSS, v2coSS, v3coSS, uv, w);
+ interp_v2_v2v2v2(bucket_bounds_uv[flip ? 2 : 1], uv1co, uv2co, uv3co, w);
+
+ uv[0] = bucket_bounds->xmin;
+ //uv[1] = bucket_bounds->ymax; // set above
+ barycentric_weights_v2_persp(v1coSS, v2coSS, v3coSS, uv, w);
+ interp_v2_v2v2v2(bucket_bounds_uv[flip ? 1 : 2], uv1co, uv2co, uv3co, w);
+
+ //uv[0] = bucket_bounds->xmin; // set above
+ uv[1] = bucket_bounds->ymin;
+ barycentric_weights_v2_persp(v1coSS, v2coSS, v3coSS, uv, w);
+ interp_v2_v2v2v2(bucket_bounds_uv[flip ? 0 : 3], uv1co, uv2co, uv3co, w);
}
/* This works as we need it to but we can save a few steps and not use it */
@@ -2305,12 +2349,12 @@ static void rect_to_uvspace_persp(
#if 0
static float angle_2d_clockwise(const float p1[2], const float p2[2], const float p3[2])
{
- float v1[2], v2[2];
+ float v1[2], v2[2];
- v1[0] = p1[0] - p2[0]; v1[1] = p1[1] - p2[1];
- v2[0] = p3[0] - p2[0]; v2[1] = p3[1] - p2[1];
+ v1[0] = p1[0] - p2[0]; v1[1] = p1[1] - p2[1];
+ v2[0] = p3[0] - p2[0]; v2[1] = p3[1] - p2[1];
- return -atan2f(v1[0] * v2[1] - v1[1] * v2[0], v1[0] * v2[0] + v1[1] * v2[1]);
+ return -atan2f(v1[0] * v2[1] - v1[1] * v2[0], v1[0] * v2[0] + v1[1] * v2[1]);
}
#endif
@@ -2323,13 +2367,10 @@ static float angle_2d_clockwise(const float p1[2], const float p2[2], const floa
/* limit must be a fraction over 1.0f */
static bool IsectPT2Df_limit(
- const float pt[2],
- const float v1[2], const float v2[2], const float v3[2],
- const float limit)
+ const float pt[2], const float v1[2], const float v2[2], const float v3[2], const float limit)
{
- return ((area_tri_v2(pt, v1, v2) +
- area_tri_v2(pt, v2, v3) +
- area_tri_v2(pt, v3, v1)) / (area_tri_v2(v1, v2, v3))) < limit;
+ return ((area_tri_v2(pt, v1, v2) + area_tri_v2(pt, v2, v3) + area_tri_v2(pt, v3, v1)) /
+ (area_tri_v2(v1, v2, v3))) < limit;
}
/* Clip the face by a bucket and set the uv-space bucket_bounds_uv
@@ -2337,360 +2378,445 @@ static bool IsectPT2Df_limit(
* */
static int float_z_sort_flip(const void *p1, const void *p2)
{
- return (((float *)p1)[2] < ((float *)p2)[2] ? 1 : -1);
+ return (((float *)p1)[2] < ((float *)p2)[2] ? 1 : -1);
}
static int float_z_sort(const void *p1, const void *p2)
{
- return (((float *)p1)[2] < ((float *)p2)[2] ? -1 : 1);
+ return (((float *)p1)[2] < ((float *)p2)[2] ? -1 : 1);
}
/* assumes one point is within the rectangle */
-static bool line_rect_clip(
- const rctf *rect,
- const float l1[4], const float l2[4],
- const float uv1[2], const float uv2[2],
- float uv[2], bool is_ortho)
+static bool line_rect_clip(const rctf *rect,
+ const float l1[4],
+ const float l2[4],
+ const float uv1[2],
+ const float uv2[2],
+ float uv[2],
+ bool is_ortho)
{
- float min = FLT_MAX, tmp;
- float xlen = l2[0] - l1[0];
- float ylen = l2[1] - l1[1];
-
- /* 0.1 might seem too much, but remember, this is pixels! */
- if (xlen > 0.1f) {
- if ((l1[0] - rect->xmin) * (l2[0] - rect->xmin) <= 0) {
- tmp = rect->xmin;
- min = min_ff((tmp - l1[0]) / xlen, min);
- }
- else if ((l1[0] - rect->xmax) * (l2[0] - rect->xmax) < 0) {
- tmp = rect->xmax;
- min = min_ff((tmp - l1[0]) / xlen, min);
- }
- }
-
- if (ylen > 0.1f) {
- if ((l1[1] - rect->ymin) * (l2[1] - rect->ymin) <= 0) {
- tmp = rect->ymin;
- min = min_ff((tmp - l1[1]) / ylen, min);
- }
- else if ((l1[1] - rect->ymax) * (l2[1] - rect->ymax) < 0) {
- tmp = rect->ymax;
- min = min_ff((tmp - l1[1]) / ylen, min);
- }
- }
-
- if (min == FLT_MAX)
- return false;
-
- tmp = (is_ortho) ? 1.0f : (l1[3] + min * (l2[3] - l1[3]));
-
- uv[0] = (uv1[0] + min / tmp * (uv2[0] - uv1[0]));
- uv[1] = (uv1[1] + min / tmp * (uv2[1] - uv1[1]));
-
- return true;
+ float min = FLT_MAX, tmp;
+ float xlen = l2[0] - l1[0];
+ float ylen = l2[1] - l1[1];
+
+ /* 0.1 might seem too much, but remember, this is pixels! */
+ if (xlen > 0.1f) {
+ if ((l1[0] - rect->xmin) * (l2[0] - rect->xmin) <= 0) {
+ tmp = rect->xmin;
+ min = min_ff((tmp - l1[0]) / xlen, min);
+ }
+ else if ((l1[0] - rect->xmax) * (l2[0] - rect->xmax) < 0) {
+ tmp = rect->xmax;
+ min = min_ff((tmp - l1[0]) / xlen, min);
+ }
+ }
+
+ if (ylen > 0.1f) {
+ if ((l1[1] - rect->ymin) * (l2[1] - rect->ymin) <= 0) {
+ tmp = rect->ymin;
+ min = min_ff((tmp - l1[1]) / ylen, min);
+ }
+ else if ((l1[1] - rect->ymax) * (l2[1] - rect->ymax) < 0) {
+ tmp = rect->ymax;
+ min = min_ff((tmp - l1[1]) / ylen, min);
+ }
+ }
+
+ if (min == FLT_MAX)
+ return false;
+
+ tmp = (is_ortho) ? 1.0f : (l1[3] + min * (l2[3] - l1[3]));
+
+ uv[0] = (uv1[0] + min / tmp * (uv2[0] - uv1[0]));
+ uv[1] = (uv1[1] + min / tmp * (uv2[1] - uv1[1]));
+
+ return true;
}
-
-static void project_bucket_clip_face(
- const bool is_ortho, const bool is_flip_object,
- const rctf *cliprect,
- const rctf *bucket_bounds,
- const float *v1coSS, const float *v2coSS, const float *v3coSS,
- const float *uv1co, const float *uv2co, const float *uv3co,
- float bucket_bounds_uv[8][2],
- int *tot, bool cull)
+static void project_bucket_clip_face(const bool is_ortho,
+ const bool is_flip_object,
+ const rctf *cliprect,
+ const rctf *bucket_bounds,
+ const float *v1coSS,
+ const float *v2coSS,
+ const float *v3coSS,
+ const float *uv1co,
+ const float *uv2co,
+ const float *uv3co,
+ float bucket_bounds_uv[8][2],
+ int *tot,
+ bool cull)
{
- int inside_bucket_flag = 0;
- int inside_face_flag = 0;
- int flip;
- bool collinear = false;
-
- float bucket_bounds_ss[4][2];
-
- /* detect pathological case where face the three vertices are almost collinear in screen space.
- * mostly those will be culled but when flood filling or with
- * smooth shading it's a possibility */
- if (min_fff(dist_squared_to_line_v2(v1coSS, v2coSS, v3coSS),
- dist_squared_to_line_v2(v2coSS, v3coSS, v1coSS),
- dist_squared_to_line_v2(v3coSS, v1coSS, v2coSS)) < PROJ_PIXEL_TOLERANCE)
- {
- collinear = true;
- }
-
- /* get the UV space bounding box */
- inside_bucket_flag |= BLI_rctf_isect_pt_v(bucket_bounds, v1coSS);
- inside_bucket_flag |= BLI_rctf_isect_pt_v(bucket_bounds, v2coSS) << 1;
- inside_bucket_flag |= BLI_rctf_isect_pt_v(bucket_bounds, v3coSS) << 2;
-
- if (inside_bucket_flag == ISECT_ALL3) {
- /* is_flip_object is used here because we use the face winding */
- flip = (((line_point_side_v2(v1coSS, v2coSS, v3coSS) > 0.0f) != is_flip_object) !=
- (line_point_side_v2(uv1co, uv2co, uv3co) > 0.0f));
-
- /* all screenspace points are inside the bucket bounding box,
- * this means we don't need to clip and can simply return the UVs */
- if (flip) { /* facing the back? */
- copy_v2_v2(bucket_bounds_uv[0], uv3co);
- copy_v2_v2(bucket_bounds_uv[1], uv2co);
- copy_v2_v2(bucket_bounds_uv[2], uv1co);
- }
- else {
- copy_v2_v2(bucket_bounds_uv[0], uv1co);
- copy_v2_v2(bucket_bounds_uv[1], uv2co);
- copy_v2_v2(bucket_bounds_uv[2], uv3co);
- }
-
- *tot = 3;
- return;
- }
- /* Handle pathological case here,
- * no need for further intersections below since triangle area is almost zero. */
- if (collinear) {
- int flag;
-
- (*tot) = 0;
-
- if (cull)
- return;
-
- if (inside_bucket_flag & ISECT_1) { copy_v2_v2(bucket_bounds_uv[*tot], uv1co); (*tot)++; }
-
- flag = inside_bucket_flag & (ISECT_1 | ISECT_2);
- if (flag && flag != (ISECT_1 | ISECT_2)) {
- if (line_rect_clip(bucket_bounds, v1coSS, v2coSS, uv1co, uv2co, bucket_bounds_uv[*tot], is_ortho))
- (*tot)++;
- }
-
- if (inside_bucket_flag & ISECT_2) { copy_v2_v2(bucket_bounds_uv[*tot], uv2co); (*tot)++; }
-
- flag = inside_bucket_flag & (ISECT_2 | ISECT_3);
- if (flag && flag != (ISECT_2 | ISECT_3)) {
- if (line_rect_clip(bucket_bounds, v2coSS, v3coSS, uv2co, uv3co, bucket_bounds_uv[*tot], is_ortho))
- (*tot)++;
- }
-
- if (inside_bucket_flag & ISECT_3) { copy_v2_v2(bucket_bounds_uv[*tot], uv3co); (*tot)++; }
-
- flag = inside_bucket_flag & (ISECT_3 | ISECT_1);
- if (flag && flag != (ISECT_3 | ISECT_1)) {
- if (line_rect_clip(bucket_bounds, v3coSS, v1coSS, uv3co, uv1co, bucket_bounds_uv[*tot], is_ortho))
- (*tot)++;
- }
-
- if ((*tot) < 3) {
- /* no intersections to speak of, but more probable is that all face is just outside the
- * rectangle and culled due to float precision issues. Since above tests have failed,
- * just dump triangle as is for painting */
- *tot = 0;
- copy_v2_v2(bucket_bounds_uv[*tot], uv1co); (*tot)++;
- copy_v2_v2(bucket_bounds_uv[*tot], uv2co); (*tot)++;
- copy_v2_v2(bucket_bounds_uv[*tot], uv3co); (*tot)++;
- return;
- }
-
- return;
- }
-
- /* get the UV space bounding box */
- /* use IsectPT2Df_limit here so we catch points are are touching the tri edge
- * (or a small fraction over) */
- bucket_bounds_ss[0][0] = bucket_bounds->xmax;
- bucket_bounds_ss[0][1] = bucket_bounds->ymin;
- inside_face_flag |= (IsectPT2Df_limit(bucket_bounds_ss[0], v1coSS, v2coSS, v3coSS, 1 + PROJ_GEOM_TOLERANCE) ? ISECT_1 : 0);
-
- bucket_bounds_ss[1][0] = bucket_bounds->xmax;
- bucket_bounds_ss[1][1] = bucket_bounds->ymax;
- inside_face_flag |= (IsectPT2Df_limit(bucket_bounds_ss[1], v1coSS, v2coSS, v3coSS, 1 + PROJ_GEOM_TOLERANCE) ? ISECT_2 : 0);
-
- bucket_bounds_ss[2][0] = bucket_bounds->xmin;
- bucket_bounds_ss[2][1] = bucket_bounds->ymax;
- inside_face_flag |= (IsectPT2Df_limit(bucket_bounds_ss[2], v1coSS, v2coSS, v3coSS, 1 + PROJ_GEOM_TOLERANCE) ? ISECT_3 : 0);
-
- bucket_bounds_ss[3][0] = bucket_bounds->xmin;
- bucket_bounds_ss[3][1] = bucket_bounds->ymin;
- inside_face_flag |= (IsectPT2Df_limit(bucket_bounds_ss[3], v1coSS, v2coSS, v3coSS, 1 + PROJ_GEOM_TOLERANCE) ? ISECT_4 : 0);
-
- flip = ((line_point_side_v2(v1coSS, v2coSS, v3coSS) > 0.0f) !=
- (line_point_side_v2(uv1co, uv2co, uv3co) > 0.0f));
-
- if (inside_face_flag == ISECT_ALL4) {
- /* bucket is totally inside the screenspace face, we can safely use weights */
-
- if (is_ortho) {
- rect_to_uvspace_ortho(bucket_bounds, v1coSS, v2coSS, v3coSS, uv1co, uv2co, uv3co, bucket_bounds_uv, flip);
- }
- else {
- rect_to_uvspace_persp(bucket_bounds, v1coSS, v2coSS, v3coSS, uv1co, uv2co, uv3co, bucket_bounds_uv, flip);
- }
-
- *tot = 4;
- return;
- }
- else {
- /* The Complicated Case!
- *
- * The 2 cases above are where the face is inside the bucket
- * or the bucket is inside the face.
- *
- * we need to make a convex polyline from the intersection between the screenspace face
- * and the bucket bounds.
- *
- * There are a number of ways this could be done, currently it just collects all
- * intersecting verts, and line intersections, then sorts them clockwise, this is
- * a lot easier then evaluating the geometry to do a correct clipping on both shapes.
- */
-
-
- /* Add a bunch of points, we know must make up the convex hull
- * which is the clipped rect and triangle */
-
- /* Maximum possible 6 intersections when using a rectangle and triangle */
-
- /* The 3rd float is used to store angle for qsort(), NOT as a Z location */
- float isectVCosSS[8][3];
- float v1_clipSS[2], v2_clipSS[2];
- float w[3];
-
- /* calc center */
- float cent[2] = {0.0f, 0.0f};
- /*float up[2] = {0.0f, 1.0f};*/
- int i;
- bool doubles;
-
- (*tot) = 0;
-
- if (inside_face_flag & ISECT_1) { copy_v2_v2(isectVCosSS[*tot], bucket_bounds_ss[0]); (*tot)++; }
- if (inside_face_flag & ISECT_2) { copy_v2_v2(isectVCosSS[*tot], bucket_bounds_ss[1]); (*tot)++; }
- if (inside_face_flag & ISECT_3) { copy_v2_v2(isectVCosSS[*tot], bucket_bounds_ss[2]); (*tot)++; }
- if (inside_face_flag & ISECT_4) { copy_v2_v2(isectVCosSS[*tot], bucket_bounds_ss[3]); (*tot)++; }
-
- if (inside_bucket_flag & ISECT_1) { copy_v2_v2(isectVCosSS[*tot], v1coSS); (*tot)++; }
- if (inside_bucket_flag & ISECT_2) { copy_v2_v2(isectVCosSS[*tot], v2coSS); (*tot)++; }
- if (inside_bucket_flag & ISECT_3) { copy_v2_v2(isectVCosSS[*tot], v3coSS); (*tot)++; }
-
- if ((inside_bucket_flag & (ISECT_1 | ISECT_2)) != (ISECT_1 | ISECT_2)) {
- if (line_clip_rect2f(cliprect, bucket_bounds, v1coSS, v2coSS, v1_clipSS, v2_clipSS)) {
- if ((inside_bucket_flag & ISECT_1) == 0) { copy_v2_v2(isectVCosSS[*tot], v1_clipSS); (*tot)++; }
- if ((inside_bucket_flag & ISECT_2) == 0) { copy_v2_v2(isectVCosSS[*tot], v2_clipSS); (*tot)++; }
- }
- }
-
- if ((inside_bucket_flag & (ISECT_2 | ISECT_3)) != (ISECT_2 | ISECT_3)) {
- if (line_clip_rect2f(cliprect, bucket_bounds, v2coSS, v3coSS, v1_clipSS, v2_clipSS)) {
- if ((inside_bucket_flag & ISECT_2) == 0) { copy_v2_v2(isectVCosSS[*tot], v1_clipSS); (*tot)++; }
- if ((inside_bucket_flag & ISECT_3) == 0) { copy_v2_v2(isectVCosSS[*tot], v2_clipSS); (*tot)++; }
- }
- }
-
- if ((inside_bucket_flag & (ISECT_3 | ISECT_1)) != (ISECT_3 | ISECT_1)) {
- if (line_clip_rect2f(cliprect, bucket_bounds, v3coSS, v1coSS, v1_clipSS, v2_clipSS)) {
- if ((inside_bucket_flag & ISECT_3) == 0) { copy_v2_v2(isectVCosSS[*tot], v1_clipSS); (*tot)++; }
- if ((inside_bucket_flag & ISECT_1) == 0) { copy_v2_v2(isectVCosSS[*tot], v2_clipSS); (*tot)++; }
- }
- }
-
-
- if ((*tot) < 3) { /* no intersections to speak of */
- *tot = 0;
- return;
- }
-
- /* now we have all points we need, collect their angles and sort them clockwise */
-
- for (i = 0; i < (*tot); i++) {
- cent[0] += isectVCosSS[i][0];
- cent[1] += isectVCosSS[i][1];
- }
- cent[0] = cent[0] / (float)(*tot);
- cent[1] = cent[1] / (float)(*tot);
-
-
-
- /* Collect angles for every point around the center point */
-
-
-#if 0 /* uses a few more cycles then the above loop */
- for (i = 0; i < (*tot); i++) {
- isectVCosSS[i][2] = angle_2d_clockwise(up, cent, isectVCosSS[i]);
- }
+ int inside_bucket_flag = 0;
+ int inside_face_flag = 0;
+ int flip;
+ bool collinear = false;
+
+ float bucket_bounds_ss[4][2];
+
+ /* detect pathological case where face the three vertices are almost collinear in screen space.
+ * mostly those will be culled but when flood filling or with
+ * smooth shading it's a possibility */
+ if (min_fff(dist_squared_to_line_v2(v1coSS, v2coSS, v3coSS),
+ dist_squared_to_line_v2(v2coSS, v3coSS, v1coSS),
+ dist_squared_to_line_v2(v3coSS, v1coSS, v2coSS)) < PROJ_PIXEL_TOLERANCE) {
+ collinear = true;
+ }
+
+ /* get the UV space bounding box */
+ inside_bucket_flag |= BLI_rctf_isect_pt_v(bucket_bounds, v1coSS);
+ inside_bucket_flag |= BLI_rctf_isect_pt_v(bucket_bounds, v2coSS) << 1;
+ inside_bucket_flag |= BLI_rctf_isect_pt_v(bucket_bounds, v3coSS) << 2;
+
+ if (inside_bucket_flag == ISECT_ALL3) {
+ /* is_flip_object is used here because we use the face winding */
+ flip = (((line_point_side_v2(v1coSS, v2coSS, v3coSS) > 0.0f) != is_flip_object) !=
+ (line_point_side_v2(uv1co, uv2co, uv3co) > 0.0f));
+
+ /* all screenspace points are inside the bucket bounding box,
+ * this means we don't need to clip and can simply return the UVs */
+ if (flip) { /* facing the back? */
+ copy_v2_v2(bucket_bounds_uv[0], uv3co);
+ copy_v2_v2(bucket_bounds_uv[1], uv2co);
+ copy_v2_v2(bucket_bounds_uv[2], uv1co);
+ }
+ else {
+ copy_v2_v2(bucket_bounds_uv[0], uv1co);
+ copy_v2_v2(bucket_bounds_uv[1], uv2co);
+ copy_v2_v2(bucket_bounds_uv[2], uv3co);
+ }
+
+ *tot = 3;
+ return;
+ }
+ /* Handle pathological case here,
+ * no need for further intersections below since triangle area is almost zero. */
+ if (collinear) {
+ int flag;
+
+ (*tot) = 0;
+
+ if (cull)
+ return;
+
+ if (inside_bucket_flag & ISECT_1) {
+ copy_v2_v2(bucket_bounds_uv[*tot], uv1co);
+ (*tot)++;
+ }
+
+ flag = inside_bucket_flag & (ISECT_1 | ISECT_2);
+ if (flag && flag != (ISECT_1 | ISECT_2)) {
+ if (line_rect_clip(
+ bucket_bounds, v1coSS, v2coSS, uv1co, uv2co, bucket_bounds_uv[*tot], is_ortho))
+ (*tot)++;
+ }
+
+ if (inside_bucket_flag & ISECT_2) {
+ copy_v2_v2(bucket_bounds_uv[*tot], uv2co);
+ (*tot)++;
+ }
+
+ flag = inside_bucket_flag & (ISECT_2 | ISECT_3);
+ if (flag && flag != (ISECT_2 | ISECT_3)) {
+ if (line_rect_clip(
+ bucket_bounds, v2coSS, v3coSS, uv2co, uv3co, bucket_bounds_uv[*tot], is_ortho))
+ (*tot)++;
+ }
+
+ if (inside_bucket_flag & ISECT_3) {
+ copy_v2_v2(bucket_bounds_uv[*tot], uv3co);
+ (*tot)++;
+ }
+
+ flag = inside_bucket_flag & (ISECT_3 | ISECT_1);
+ if (flag && flag != (ISECT_3 | ISECT_1)) {
+ if (line_rect_clip(
+ bucket_bounds, v3coSS, v1coSS, uv3co, uv1co, bucket_bounds_uv[*tot], is_ortho))
+ (*tot)++;
+ }
+
+ if ((*tot) < 3) {
+ /* no intersections to speak of, but more probable is that all face is just outside the
+ * rectangle and culled due to float precision issues. Since above tests have failed,
+ * just dump triangle as is for painting */
+ *tot = 0;
+ copy_v2_v2(bucket_bounds_uv[*tot], uv1co);
+ (*tot)++;
+ copy_v2_v2(bucket_bounds_uv[*tot], uv2co);
+ (*tot)++;
+ copy_v2_v2(bucket_bounds_uv[*tot], uv3co);
+ (*tot)++;
+ return;
+ }
+
+ return;
+ }
+
+ /* get the UV space bounding box */
+ /* use IsectPT2Df_limit here so we catch points are are touching the tri edge
+ * (or a small fraction over) */
+ bucket_bounds_ss[0][0] = bucket_bounds->xmax;
+ bucket_bounds_ss[0][1] = bucket_bounds->ymin;
+ inside_face_flag |= (IsectPT2Df_limit(
+ bucket_bounds_ss[0], v1coSS, v2coSS, v3coSS, 1 + PROJ_GEOM_TOLERANCE) ?
+ ISECT_1 :
+ 0);
+
+ bucket_bounds_ss[1][0] = bucket_bounds->xmax;
+ bucket_bounds_ss[1][1] = bucket_bounds->ymax;
+ inside_face_flag |= (IsectPT2Df_limit(
+ bucket_bounds_ss[1], v1coSS, v2coSS, v3coSS, 1 + PROJ_GEOM_TOLERANCE) ?
+ ISECT_2 :
+ 0);
+
+ bucket_bounds_ss[2][0] = bucket_bounds->xmin;
+ bucket_bounds_ss[2][1] = bucket_bounds->ymax;
+ inside_face_flag |= (IsectPT2Df_limit(
+ bucket_bounds_ss[2], v1coSS, v2coSS, v3coSS, 1 + PROJ_GEOM_TOLERANCE) ?
+ ISECT_3 :
+ 0);
+
+ bucket_bounds_ss[3][0] = bucket_bounds->xmin;
+ bucket_bounds_ss[3][1] = bucket_bounds->ymin;
+ inside_face_flag |= (IsectPT2Df_limit(
+ bucket_bounds_ss[3], v1coSS, v2coSS, v3coSS, 1 + PROJ_GEOM_TOLERANCE) ?
+ ISECT_4 :
+ 0);
+
+ flip = ((line_point_side_v2(v1coSS, v2coSS, v3coSS) > 0.0f) !=
+ (line_point_side_v2(uv1co, uv2co, uv3co) > 0.0f));
+
+ if (inside_face_flag == ISECT_ALL4) {
+ /* bucket is totally inside the screenspace face, we can safely use weights */
+
+ if (is_ortho) {
+ rect_to_uvspace_ortho(
+ bucket_bounds, v1coSS, v2coSS, v3coSS, uv1co, uv2co, uv3co, bucket_bounds_uv, flip);
+ }
+ else {
+ rect_to_uvspace_persp(
+ bucket_bounds, v1coSS, v2coSS, v3coSS, uv1co, uv2co, uv3co, bucket_bounds_uv, flip);
+ }
+
+ *tot = 4;
+ return;
+ }
+ else {
+ /* The Complicated Case!
+ *
+ * The 2 cases above are where the face is inside the bucket
+ * or the bucket is inside the face.
+ *
+ * we need to make a convex polyline from the intersection between the screenspace face
+ * and the bucket bounds.
+ *
+ * There are a number of ways this could be done, currently it just collects all
+ * intersecting verts, and line intersections, then sorts them clockwise, this is
+ * a lot easier then evaluating the geometry to do a correct clipping on both shapes.
+ */
+
+ /* Add a bunch of points, we know must make up the convex hull
+ * which is the clipped rect and triangle */
+
+ /* Maximum possible 6 intersections when using a rectangle and triangle */
+
+ /* The 3rd float is used to store angle for qsort(), NOT as a Z location */
+ float isectVCosSS[8][3];
+ float v1_clipSS[2], v2_clipSS[2];
+ float w[3];
+
+ /* calc center */
+ float cent[2] = {0.0f, 0.0f};
+ /*float up[2] = {0.0f, 1.0f};*/
+ int i;
+ bool doubles;
+
+ (*tot) = 0;
+
+ if (inside_face_flag & ISECT_1) {
+ copy_v2_v2(isectVCosSS[*tot], bucket_bounds_ss[0]);
+ (*tot)++;
+ }
+ if (inside_face_flag & ISECT_2) {
+ copy_v2_v2(isectVCosSS[*tot], bucket_bounds_ss[1]);
+ (*tot)++;
+ }
+ if (inside_face_flag & ISECT_3) {
+ copy_v2_v2(isectVCosSS[*tot], bucket_bounds_ss[2]);
+ (*tot)++;
+ }
+ if (inside_face_flag & ISECT_4) {
+ copy_v2_v2(isectVCosSS[*tot], bucket_bounds_ss[3]);
+ (*tot)++;
+ }
+
+ if (inside_bucket_flag & ISECT_1) {
+ copy_v2_v2(isectVCosSS[*tot], v1coSS);
+ (*tot)++;
+ }
+ if (inside_bucket_flag & ISECT_2) {
+ copy_v2_v2(isectVCosSS[*tot], v2coSS);
+ (*tot)++;
+ }
+ if (inside_bucket_flag & ISECT_3) {
+ copy_v2_v2(isectVCosSS[*tot], v3coSS);
+ (*tot)++;
+ }
+
+ if ((inside_bucket_flag & (ISECT_1 | ISECT_2)) != (ISECT_1 | ISECT_2)) {
+ if (line_clip_rect2f(cliprect, bucket_bounds, v1coSS, v2coSS, v1_clipSS, v2_clipSS)) {
+ if ((inside_bucket_flag & ISECT_1) == 0) {
+ copy_v2_v2(isectVCosSS[*tot], v1_clipSS);
+ (*tot)++;
+ }
+ if ((inside_bucket_flag & ISECT_2) == 0) {
+ copy_v2_v2(isectVCosSS[*tot], v2_clipSS);
+ (*tot)++;
+ }
+ }
+ }
+
+ if ((inside_bucket_flag & (ISECT_2 | ISECT_3)) != (ISECT_2 | ISECT_3)) {
+ if (line_clip_rect2f(cliprect, bucket_bounds, v2coSS, v3coSS, v1_clipSS, v2_clipSS)) {
+ if ((inside_bucket_flag & ISECT_2) == 0) {
+ copy_v2_v2(isectVCosSS[*tot], v1_clipSS);
+ (*tot)++;
+ }
+ if ((inside_bucket_flag & ISECT_3) == 0) {
+ copy_v2_v2(isectVCosSS[*tot], v2_clipSS);
+ (*tot)++;
+ }
+ }
+ }
+
+ if ((inside_bucket_flag & (ISECT_3 | ISECT_1)) != (ISECT_3 | ISECT_1)) {
+ if (line_clip_rect2f(cliprect, bucket_bounds, v3coSS, v1coSS, v1_clipSS, v2_clipSS)) {
+ if ((inside_bucket_flag & ISECT_3) == 0) {
+ copy_v2_v2(isectVCosSS[*tot], v1_clipSS);
+ (*tot)++;
+ }
+ if ((inside_bucket_flag & ISECT_1) == 0) {
+ copy_v2_v2(isectVCosSS[*tot], v2_clipSS);
+ (*tot)++;
+ }
+ }
+ }
+
+ if ((*tot) < 3) { /* no intersections to speak of */
+ *tot = 0;
+ return;
+ }
+
+ /* now we have all points we need, collect their angles and sort them clockwise */
+
+ for (i = 0; i < (*tot); i++) {
+ cent[0] += isectVCosSS[i][0];
+ cent[1] += isectVCosSS[i][1];
+ }
+ cent[0] = cent[0] / (float)(*tot);
+ cent[1] = cent[1] / (float)(*tot);
+
+ /* Collect angles for every point around the center point */
+
+#if 0 /* uses a few more cycles then the above loop */
+ for (i = 0; i < (*tot); i++) {
+ isectVCosSS[i][2] = angle_2d_clockwise(up, cent, isectVCosSS[i]);
+ }
#endif
- /* Abuse this var for the loop below */
- v1_clipSS[0] = cent[0];
- v1_clipSS[1] = cent[1] + 1.0f;
-
- for (i = 0; i < (*tot); i++) {
- v2_clipSS[0] = isectVCosSS[i][0] - cent[0];
- v2_clipSS[1] = isectVCosSS[i][1] - cent[1];
- isectVCosSS[i][2] = atan2f(v1_clipSS[0] * v2_clipSS[1] - v1_clipSS[1] * v2_clipSS[0],
- v1_clipSS[0] * v2_clipSS[0] + v1_clipSS[1] * v2_clipSS[1]);
- }
-
- if (flip) qsort(isectVCosSS, *tot, sizeof(float) * 3, float_z_sort_flip);
- else qsort(isectVCosSS, *tot, sizeof(float) * 3, float_z_sort);
-
- doubles = true;
- while (doubles == true) {
- doubles = false;
-
- for (i = 0; i < (*tot); i++) {
- if (fabsf(isectVCosSS[(i + 1) % *tot][0] - isectVCosSS[i][0]) < PROJ_PIXEL_TOLERANCE &&
- fabsf(isectVCosSS[(i + 1) % *tot][1] - isectVCosSS[i][1]) < PROJ_PIXEL_TOLERANCE)
- {
- int j;
- for (j = i; j < (*tot) - 1; j++) {
- isectVCosSS[j][0] = isectVCosSS[j + 1][0];
- isectVCosSS[j][1] = isectVCosSS[j + 1][1];
- }
- /* keep looking for more doubles */
- doubles = true;
- (*tot)--;
- }
- }
-
- /* its possible there is only a few left after remove doubles */
- if ((*tot) < 3) {
- // printf("removed too many doubles B\n");
- *tot = 0;
- return;
- }
- }
-
- if (is_ortho) {
- for (i = 0; i < (*tot); i++) {
- barycentric_weights_v2(v1coSS, v2coSS, v3coSS, isectVCosSS[i], w);
- interp_v2_v2v2v2(bucket_bounds_uv[i], uv1co, uv2co, uv3co, w);
- }
- }
- else {
- for (i = 0; i < (*tot); i++) {
- barycentric_weights_v2_persp(v1coSS, v2coSS, v3coSS, isectVCosSS[i], w);
- interp_v2_v2v2v2(bucket_bounds_uv[i], uv1co, uv2co, uv3co, w);
- }
- }
- }
+ /* Abuse this var for the loop below */
+ v1_clipSS[0] = cent[0];
+ v1_clipSS[1] = cent[1] + 1.0f;
+
+ for (i = 0; i < (*tot); i++) {
+ v2_clipSS[0] = isectVCosSS[i][0] - cent[0];
+ v2_clipSS[1] = isectVCosSS[i][1] - cent[1];
+ isectVCosSS[i][2] = atan2f(v1_clipSS[0] * v2_clipSS[1] - v1_clipSS[1] * v2_clipSS[0],
+ v1_clipSS[0] * v2_clipSS[0] + v1_clipSS[1] * v2_clipSS[1]);
+ }
+
+ if (flip)
+ qsort(isectVCosSS, *tot, sizeof(float) * 3, float_z_sort_flip);
+ else
+ qsort(isectVCosSS, *tot, sizeof(float) * 3, float_z_sort);
+
+ doubles = true;
+ while (doubles == true) {
+ doubles = false;
+
+ for (i = 0; i < (*tot); i++) {
+ if (fabsf(isectVCosSS[(i + 1) % *tot][0] - isectVCosSS[i][0]) < PROJ_PIXEL_TOLERANCE &&
+ fabsf(isectVCosSS[(i + 1) % *tot][1] - isectVCosSS[i][1]) < PROJ_PIXEL_TOLERANCE) {
+ int j;
+ for (j = i; j < (*tot) - 1; j++) {
+ isectVCosSS[j][0] = isectVCosSS[j + 1][0];
+ isectVCosSS[j][1] = isectVCosSS[j + 1][1];
+ }
+ /* keep looking for more doubles */
+ doubles = true;
+ (*tot)--;
+ }
+ }
+
+ /* its possible there is only a few left after remove doubles */
+ if ((*tot) < 3) {
+ // printf("removed too many doubles B\n");
+ *tot = 0;
+ return;
+ }
+ }
+
+ if (is_ortho) {
+ for (i = 0; i < (*tot); i++) {
+ barycentric_weights_v2(v1coSS, v2coSS, v3coSS, isectVCosSS[i], w);
+ interp_v2_v2v2v2(bucket_bounds_uv[i], uv1co, uv2co, uv3co, w);
+ }
+ }
+ else {
+ for (i = 0; i < (*tot); i++) {
+ barycentric_weights_v2_persp(v1coSS, v2coSS, v3coSS, isectVCosSS[i], w);
+ interp_v2_v2v2v2(bucket_bounds_uv[i], uv1co, uv2co, uv3co, w);
+ }
+ }
+ }
#ifdef PROJ_DEBUG_PRINT_CLIP
- /* include this at the bottom of the above function to debug the output */
-
- {
- /* If there are ever any problems, */
- float test_uv[4][2];
- int i;
- if (is_ortho) rect_to_uvspace_ortho(bucket_bounds, v1coSS, v2coSS, v3coSS, uv1co, uv2co, uv3co, test_uv, flip);
- else rect_to_uvspace_persp(bucket_bounds, v1coSS, v2coSS, v3coSS, uv1co, uv2co, uv3co, test_uv, flip);
- printf("( [(%f,%f), (%f,%f), (%f,%f), (%f,%f)], ",
- test_uv[0][0], test_uv[0][1], test_uv[1][0], test_uv[1][1],
- test_uv[2][0], test_uv[2][1], test_uv[3][0], test_uv[3][1]);
-
- printf(" [(%f,%f), (%f,%f), (%f,%f)], ", uv1co[0], uv1co[1], uv2co[0], uv2co[1], uv3co[0], uv3co[1]);
-
- printf("[");
- for (i = 0; i < (*tot); i++) {
- printf("(%f, %f),", bucket_bounds_uv[i][0], bucket_bounds_uv[i][1]);
- }
- printf("]),\\\n");
- }
+ /* include this at the bottom of the above function to debug the output */
+
+ {
+ /* If there are ever any problems, */
+ float test_uv[4][2];
+ int i;
+ if (is_ortho)
+ rect_to_uvspace_ortho(
+ bucket_bounds, v1coSS, v2coSS, v3coSS, uv1co, uv2co, uv3co, test_uv, flip);
+ else
+ rect_to_uvspace_persp(
+ bucket_bounds, v1coSS, v2coSS, v3coSS, uv1co, uv2co, uv3co, test_uv, flip);
+ printf("( [(%f,%f), (%f,%f), (%f,%f), (%f,%f)], ",
+ test_uv[0][0],
+ test_uv[0][1],
+ test_uv[1][0],
+ test_uv[1][1],
+ test_uv[2][0],
+ test_uv[2][1],
+ test_uv[3][0],
+ test_uv[3][1]);
+
+ printf(" [(%f,%f), (%f,%f), (%f,%f)], ",
+ uv1co[0],
+ uv1co[1],
+ uv2co[0],
+ uv2co[1],
+ uv3co[0],
+ uv3co[1]);
+
+ printf("[");
+ for (i = 0; i < (*tot); i++) {
+ printf("(%f, %f),", bucket_bounds_uv[i][0], bucket_bounds_uv[i][1]);
+ }
+ printf("]),\\\n");
+ }
#endif
}
@@ -2740,7 +2866,6 @@ static void project_bucket_clip_face(
* main()
*/
-
#undef ISECT_1
#undef ISECT_2
#undef ISECT_3
@@ -2748,35 +2873,32 @@ static void project_bucket_clip_face(
#undef ISECT_ALL3
#undef ISECT_ALL4
-
/* checks if pt is inside a convex 2D polyline, the polyline must be ordered rotating clockwise
* otherwise it would have to test for mixed (line_point_side_v2 > 0.0f) cases */
static bool IsectPoly2Df(const float pt[2], float uv[][2], const int tot)
{
- int i;
- if (line_point_side_v2(uv[tot - 1], uv[0], pt) < 0.0f)
- return 0;
+ int i;
+ if (line_point_side_v2(uv[tot - 1], uv[0], pt) < 0.0f)
+ return 0;
- for (i = 1; i < tot; i++) {
- if (line_point_side_v2(uv[i - 1], uv[i], pt) < 0.0f)
- return 0;
+ for (i = 1; i < tot; i++) {
+ if (line_point_side_v2(uv[i - 1], uv[i], pt) < 0.0f)
+ return 0;
+ }
- }
-
- return 1;
+ return 1;
}
static bool IsectPoly2Df_twoside(const float pt[2], float uv[][2], const int tot)
{
- int i;
- bool side = (line_point_side_v2(uv[tot - 1], uv[0], pt) > 0.0f);
-
- for (i = 1; i < tot; i++) {
- if ((line_point_side_v2(uv[i - 1], uv[i], pt) > 0.0f) != side)
- return 0;
+ int i;
+ bool side = (line_point_side_v2(uv[tot - 1], uv[0], pt) > 0.0f);
- }
+ for (i = 1; i < tot; i++) {
+ if ((line_point_side_v2(uv[i - 1], uv[i], pt) > 0.0f) != side)
+ return 0;
+ }
- return 1;
+ return 1;
}
/* One of the most important function for projection painting,
@@ -2784,1824 +2906,1853 @@ static bool IsectPoly2Df_twoside(const float pt[2], float uv[][2], const int tot
*
* initialize pixels from this face where it intersects with the bucket_index,
* optionally initialize pixels for removing seams */
-static void project_paint_face_init(
- const ProjPaintState *ps,
- const int thread_index, const int bucket_index, const int tri_index, const int image_index,
- const rctf *clip_rect, const rctf *bucket_bounds, ImBuf *ibuf, ImBuf **tmpibuf)
+static void project_paint_face_init(const ProjPaintState *ps,
+ const int thread_index,
+ const int bucket_index,
+ const int tri_index,
+ const int image_index,
+ const rctf *clip_rect,
+ const rctf *bucket_bounds,
+ ImBuf *ibuf,
+ ImBuf **tmpibuf)
{
- /* Projection vars, to get the 3D locations into screen space */
- MemArena *arena = ps->arena_mt[thread_index];
- LinkNode **bucketPixelNodes = ps->bucketRect + bucket_index;
- LinkNode *bucketFaceNodes = ps->bucketFaces[bucket_index];
- bool threaded = (ps->thread_tot > 1);
-
- TileInfo tinf = {
- ps->tile_lock,
- ps->do_masking,
- IMAPAINT_TILE_NUMBER(ibuf->x),
- tmpibuf,
- ps->projImages + image_index,
- };
-
- const MLoopTri *lt = &ps->mlooptri_eval[tri_index];
- const int lt_vtri[3] = { PS_LOOPTRI_AS_VERT_INDEX_3(ps, lt) };
- const float *lt_tri_uv[3] = { PS_LOOPTRI_AS_UV_3(ps->poly_to_loop_uv, lt) };
-
- /* UV/pixel seeking data */
- /* Image X/Y-Pixel */
- int x, y;
- float mask;
- /* Image floating point UV - same as x, y but from 0.0-1.0 */
- float uv[2];
-
- /* vert co screen-space, these will be assigned to lt_vtri[0-2] */
- const float *v1coSS, *v2coSS, *v3coSS;
-
- /* vertex screenspace coords */
- const float *vCo[3];
-
- float w[3], wco[3];
-
- /* for convenience only, these will be assigned to lt_tri_uv[0],1,2 or lt_tri_uv[0],2,3 */
- float *uv1co, *uv2co, *uv3co;
- float pixelScreenCo[4];
- bool do_3d_mapping = ps->brush->mtex.brush_map_mode == MTEX_MAP_MODE_3D;
-
- /* ispace bounds */
- rcti bounds_px;
- /* vars for getting uvspace bounds */
-
- /* bucket bounds in UV space so we can init pixels only for this face, */
- float lt_uv_pxoffset[3][2];
- float xhalfpx, yhalfpx;
- const float ibuf_xf = (float)ibuf->x, ibuf_yf = (float)ibuf->y;
-
- /* for early loop exit */
- int has_x_isect = 0, has_isect = 0;
-
- float uv_clip[8][2];
- int uv_clip_tot;
- const bool is_ortho = ps->is_ortho;
- const bool is_flip_object = ps->is_flip_object;
- const bool do_backfacecull = ps->do_backfacecull;
- const bool do_clip = ps->rv3d ? ps->rv3d->rflag & RV3D_CLIPPING : 0;
-
- vCo[0] = ps->mvert_eval[lt_vtri[0]].co;
- vCo[1] = ps->mvert_eval[lt_vtri[1]].co;
- vCo[2] = ps->mvert_eval[lt_vtri[2]].co;
-
-
- /* Use lt_uv_pxoffset instead of lt_tri_uv so we can offset the UV half a pixel
- * this is done so we can avoid offsetting all the pixels by 0.5 which causes
- * problems when wrapping negative coords */
- xhalfpx = (0.5f + (PROJ_PIXEL_TOLERANCE * (1.0f / 3.0f))) / ibuf_xf;
- yhalfpx = (0.5f + (PROJ_PIXEL_TOLERANCE * (1.0f / 4.0f))) / ibuf_yf;
-
- /* Note about (PROJ_GEOM_TOLERANCE/x) above...
- * Needed to add this offset since UV coords are often quads aligned to pixels.
- * In this case pixels can be exactly between 2 triangles causing nasty
- * artifacts.
- *
- * This workaround can be removed and painting will still work on most cases
- * but since the first thing most people try is painting onto a quad- better make it work.
- */
-
- lt_uv_pxoffset[0][0] = lt_tri_uv[0][0] - xhalfpx;
- lt_uv_pxoffset[0][1] = lt_tri_uv[0][1] - yhalfpx;
-
- lt_uv_pxoffset[1][0] = lt_tri_uv[1][0] - xhalfpx;
- lt_uv_pxoffset[1][1] = lt_tri_uv[1][1] - yhalfpx;
-
- lt_uv_pxoffset[2][0] = lt_tri_uv[2][0] - xhalfpx;
- lt_uv_pxoffset[2][1] = lt_tri_uv[2][1] - yhalfpx;
-
- {
- uv1co = lt_uv_pxoffset[0]; // was lt_tri_uv[i1];
- uv2co = lt_uv_pxoffset[1]; // was lt_tri_uv[i2];
- uv3co = lt_uv_pxoffset[2]; // was lt_tri_uv[i3];
-
- v1coSS = ps->screenCoords[lt_vtri[0]];
- v2coSS = ps->screenCoords[lt_vtri[1]];
- v3coSS = ps->screenCoords[lt_vtri[2]];
-
- /* This function gives is a concave polyline in UV space from the clipped tri*/
- project_bucket_clip_face(
- is_ortho, is_flip_object,
- clip_rect, bucket_bounds,
- v1coSS, v2coSS, v3coSS,
- uv1co, uv2co, uv3co,
- uv_clip, &uv_clip_tot,
- do_backfacecull || ps->do_occlude);
-
- /* sometimes this happens, better just allow for 8 intersectiosn even though there should be max 6 */
+ /* Projection vars, to get the 3D locations into screen space */
+ MemArena *arena = ps->arena_mt[thread_index];
+ LinkNode **bucketPixelNodes = ps->bucketRect + bucket_index;
+ LinkNode *bucketFaceNodes = ps->bucketFaces[bucket_index];
+ bool threaded = (ps->thread_tot > 1);
+
+ TileInfo tinf = {
+ ps->tile_lock,
+ ps->do_masking,
+ IMAPAINT_TILE_NUMBER(ibuf->x),
+ tmpibuf,
+ ps->projImages + image_index,
+ };
+
+ const MLoopTri *lt = &ps->mlooptri_eval[tri_index];
+ const int lt_vtri[3] = {PS_LOOPTRI_AS_VERT_INDEX_3(ps, lt)};
+ const float *lt_tri_uv[3] = {PS_LOOPTRI_AS_UV_3(ps->poly_to_loop_uv, lt)};
+
+ /* UV/pixel seeking data */
+ /* Image X/Y-Pixel */
+ int x, y;
+ float mask;
+ /* Image floating point UV - same as x, y but from 0.0-1.0 */
+ float uv[2];
+
+ /* vert co screen-space, these will be assigned to lt_vtri[0-2] */
+ const float *v1coSS, *v2coSS, *v3coSS;
+
+ /* vertex screenspace coords */
+ const float *vCo[3];
+
+ float w[3], wco[3];
+
+ /* for convenience only, these will be assigned to lt_tri_uv[0],1,2 or lt_tri_uv[0],2,3 */
+ float *uv1co, *uv2co, *uv3co;
+ float pixelScreenCo[4];
+ bool do_3d_mapping = ps->brush->mtex.brush_map_mode == MTEX_MAP_MODE_3D;
+
+ /* ispace bounds */
+ rcti bounds_px;
+ /* vars for getting uvspace bounds */
+
+ /* bucket bounds in UV space so we can init pixels only for this face, */
+ float lt_uv_pxoffset[3][2];
+ float xhalfpx, yhalfpx;
+ const float ibuf_xf = (float)ibuf->x, ibuf_yf = (float)ibuf->y;
+
+ /* for early loop exit */
+ int has_x_isect = 0, has_isect = 0;
+
+ float uv_clip[8][2];
+ int uv_clip_tot;
+ const bool is_ortho = ps->is_ortho;
+ const bool is_flip_object = ps->is_flip_object;
+ const bool do_backfacecull = ps->do_backfacecull;
+ const bool do_clip = ps->rv3d ? ps->rv3d->rflag & RV3D_CLIPPING : 0;
+
+ vCo[0] = ps->mvert_eval[lt_vtri[0]].co;
+ vCo[1] = ps->mvert_eval[lt_vtri[1]].co;
+ vCo[2] = ps->mvert_eval[lt_vtri[2]].co;
+
+ /* Use lt_uv_pxoffset instead of lt_tri_uv so we can offset the UV half a pixel
+ * this is done so we can avoid offsetting all the pixels by 0.5 which causes
+ * problems when wrapping negative coords */
+ xhalfpx = (0.5f + (PROJ_PIXEL_TOLERANCE * (1.0f / 3.0f))) / ibuf_xf;
+ yhalfpx = (0.5f + (PROJ_PIXEL_TOLERANCE * (1.0f / 4.0f))) / ibuf_yf;
+
+ /* Note about (PROJ_GEOM_TOLERANCE/x) above...
+ * Needed to add this offset since UV coords are often quads aligned to pixels.
+ * In this case pixels can be exactly between 2 triangles causing nasty
+ * artifacts.
+ *
+ * This workaround can be removed and painting will still work on most cases
+ * but since the first thing most people try is painting onto a quad- better make it work.
+ */
+
+ lt_uv_pxoffset[0][0] = lt_tri_uv[0][0] - xhalfpx;
+ lt_uv_pxoffset[0][1] = lt_tri_uv[0][1] - yhalfpx;
+
+ lt_uv_pxoffset[1][0] = lt_tri_uv[1][0] - xhalfpx;
+ lt_uv_pxoffset[1][1] = lt_tri_uv[1][1] - yhalfpx;
+
+ lt_uv_pxoffset[2][0] = lt_tri_uv[2][0] - xhalfpx;
+ lt_uv_pxoffset[2][1] = lt_tri_uv[2][1] - yhalfpx;
+
+ {
+ uv1co = lt_uv_pxoffset[0]; // was lt_tri_uv[i1];
+ uv2co = lt_uv_pxoffset[1]; // was lt_tri_uv[i2];
+ uv3co = lt_uv_pxoffset[2]; // was lt_tri_uv[i3];
+
+ v1coSS = ps->screenCoords[lt_vtri[0]];
+ v2coSS = ps->screenCoords[lt_vtri[1]];
+ v3coSS = ps->screenCoords[lt_vtri[2]];
+
+ /* This function gives is a concave polyline in UV space from the clipped tri*/
+ project_bucket_clip_face(is_ortho,
+ is_flip_object,
+ clip_rect,
+ bucket_bounds,
+ v1coSS,
+ v2coSS,
+ v3coSS,
+ uv1co,
+ uv2co,
+ uv3co,
+ uv_clip,
+ &uv_clip_tot,
+ do_backfacecull || ps->do_occlude);
+
+ /* sometimes this happens, better just allow for 8 intersectiosn even though there should be max 6 */
#if 0
- if (uv_clip_tot > 6) {
- printf("this should never happen! %d\n", uv_clip_tot);
- }
+ if (uv_clip_tot > 6) {
+ printf("this should never happen! %d\n", uv_clip_tot);
+ }
#endif
- if (pixel_bounds_array(uv_clip, &bounds_px, ibuf->x, ibuf->y, uv_clip_tot)) {
+ if (pixel_bounds_array(uv_clip, &bounds_px, ibuf->x, ibuf->y, uv_clip_tot)) {
#if 0
- project_paint_undo_tiles_init(
- &bounds_px, ps->projImages + image_index, tmpibuf,
- tile_width, threaded, ps->do_masking);
+ project_paint_undo_tiles_init(
+ &bounds_px, ps->projImages + image_index, tmpibuf,
+ tile_width, threaded, ps->do_masking);
#endif
- /* clip face and */
-
- has_isect = 0;
- for (y = bounds_px.ymin; y < bounds_px.ymax; y++) {
- //uv[1] = (((float)y) + 0.5f) / (float)ibuf->y;
- /* use pixel offset UV coords instead */
- uv[1] = (float)y / ibuf_yf;
-
- has_x_isect = 0;
- for (x = bounds_px.xmin; x < bounds_px.xmax; x++) {
- //uv[0] = (((float)x) + 0.5f) / ibuf->x;
- /* use pixel offset UV coords instead */
- uv[0] = (float)x / ibuf_xf;
-
- /* Note about IsectPoly2Df_twoside, checking the face or uv flipping doesn't work,
- * could check the poly direction but better to do this */
- if ((do_backfacecull == true && IsectPoly2Df(uv, uv_clip, uv_clip_tot)) ||
- (do_backfacecull == false && IsectPoly2Df_twoside(uv, uv_clip, uv_clip_tot)))
- {
-
- has_x_isect = has_isect = 1;
-
- if (is_ortho) screen_px_from_ortho(uv, v1coSS, v2coSS, v3coSS, uv1co, uv2co, uv3co, pixelScreenCo, w);
- else screen_px_from_persp(uv, v1coSS, v2coSS, v3coSS, uv1co, uv2co, uv3co, pixelScreenCo, w);
-
- /* a pity we need to get the worldspace pixel location here */
- if (do_clip || do_3d_mapping) {
- interp_v3_v3v3v3(
- wco,
- ps->mvert_eval[lt_vtri[0]].co,
- ps->mvert_eval[lt_vtri[1]].co,
- ps->mvert_eval[lt_vtri[2]].co,
- w);
- if (do_clip && ED_view3d_clipping_test(ps->rv3d, wco, true)) {
- /* Watch out that no code below this needs to run */
- continue;
- }
- }
-
- /* Is this UV visible from the view? - raytrace */
- /* project_paint_PickFace is less complex, use for testing */
- //if (project_paint_PickFace(ps, pixelScreenCo, w, &side) == tri_index) {
- if ((ps->do_occlude == false) ||
- !project_bucket_point_occluded(ps, bucketFaceNodes, tri_index, pixelScreenCo))
- {
- mask = project_paint_uvpixel_mask(ps, tri_index, w);
-
- if (mask > 0.0f) {
- BLI_linklist_prepend_arena(
- bucketPixelNodes,
- project_paint_uvpixel_init(
- ps, arena, &tinf, x, y, mask, tri_index,
- pixelScreenCo, wco, w),
- arena);
- }
- }
-
- }
-//#if 0
- else if (has_x_isect) {
- /* assuming the face is not a bow-tie - we know we cant intersect again on the X */
- break;
- }
-//#endif
- }
-
-
-#if 0 /* TODO - investigate why this dosnt work sometimes! it should! */
- /* no intersection for this entire row,
- * after some intersection above means we can quit now */
- if (has_x_isect == 0 && has_isect) {
- break;
- }
+ /* clip face and */
+
+ has_isect = 0;
+ for (y = bounds_px.ymin; y < bounds_px.ymax; y++) {
+ //uv[1] = (((float)y) + 0.5f) / (float)ibuf->y;
+ /* use pixel offset UV coords instead */
+ uv[1] = (float)y / ibuf_yf;
+
+ has_x_isect = 0;
+ for (x = bounds_px.xmin; x < bounds_px.xmax; x++) {
+ //uv[0] = (((float)x) + 0.5f) / ibuf->x;
+ /* use pixel offset UV coords instead */
+ uv[0] = (float)x / ibuf_xf;
+
+ /* Note about IsectPoly2Df_twoside, checking the face or uv flipping doesn't work,
+ * could check the poly direction but better to do this */
+ if ((do_backfacecull == true && IsectPoly2Df(uv, uv_clip, uv_clip_tot)) ||
+ (do_backfacecull == false && IsectPoly2Df_twoside(uv, uv_clip, uv_clip_tot))) {
+
+ has_x_isect = has_isect = 1;
+
+ if (is_ortho)
+ screen_px_from_ortho(
+ uv, v1coSS, v2coSS, v3coSS, uv1co, uv2co, uv3co, pixelScreenCo, w);
+ else
+ screen_px_from_persp(
+ uv, v1coSS, v2coSS, v3coSS, uv1co, uv2co, uv3co, pixelScreenCo, w);
+
+ /* a pity we need to get the worldspace pixel location here */
+ if (do_clip || do_3d_mapping) {
+ interp_v3_v3v3v3(wco,
+ ps->mvert_eval[lt_vtri[0]].co,
+ ps->mvert_eval[lt_vtri[1]].co,
+ ps->mvert_eval[lt_vtri[2]].co,
+ w);
+ if (do_clip && ED_view3d_clipping_test(ps->rv3d, wco, true)) {
+ /* Watch out that no code below this needs to run */
+ continue;
+ }
+ }
+
+ /* Is this UV visible from the view? - raytrace */
+ /* project_paint_PickFace is less complex, use for testing */
+ //if (project_paint_PickFace(ps, pixelScreenCo, w, &side) == tri_index) {
+ if ((ps->do_occlude == false) ||
+ !project_bucket_point_occluded(ps, bucketFaceNodes, tri_index, pixelScreenCo)) {
+ mask = project_paint_uvpixel_mask(ps, tri_index, w);
+
+ if (mask > 0.0f) {
+ BLI_linklist_prepend_arena(
+ bucketPixelNodes,
+ project_paint_uvpixel_init(
+ ps, arena, &tinf, x, y, mask, tri_index, pixelScreenCo, wco, w),
+ arena);
+ }
+ }
+ }
+ //#if 0
+ else if (has_x_isect) {
+ /* assuming the face is not a bow-tie - we know we cant intersect again on the X */
+ break;
+ }
+ //#endif
+ }
+
+#if 0 /* TODO - investigate why this dosnt work sometimes! it should! */
+ /* no intersection for this entire row,
+ * after some intersection above means we can quit now */
+ if (has_x_isect == 0 && has_isect) {
+ break;
+ }
#endif
- }
- }
- }
-
+ }
+ }
+ }
#ifndef PROJ_DEBUG_NOSEAMBLEED
- if (ps->seam_bleed_px > 0.0f && !(ps->faceSeamFlags[tri_index] & PROJ_FACE_DEGENERATE)) {
- int face_seam_flag;
-
- if (threaded) {
- /* Other threads could be modifying these vars. */
- BLI_thread_lock(LOCK_CUSTOM1);
- }
-
- face_seam_flag = ps->faceSeamFlags[tri_index];
-
- /* are any of our edges un-initialized? */
- if ((face_seam_flag & PROJ_FACE_SEAM_INIT0) == 0 ||
- (face_seam_flag & PROJ_FACE_SEAM_INIT1) == 0 ||
- (face_seam_flag & PROJ_FACE_SEAM_INIT2) == 0)
- {
- project_face_seams_init(ps, arena, tri_index, 0, true, ibuf->x, ibuf->y);
- face_seam_flag = ps->faceSeamFlags[tri_index];
- //printf("seams - %d %d %d %d\n", flag&PROJ_FACE_SEAM0, flag&PROJ_FACE_SEAM1, flag&PROJ_FACE_SEAM2);
- }
-
- if ((face_seam_flag & (PROJ_FACE_SEAM0 | PROJ_FACE_SEAM1 | PROJ_FACE_SEAM2)) == 0) {
-
- if (threaded) {
- /* Other threads could be modifying these vars. */
- BLI_thread_unlock(LOCK_CUSTOM1);
- }
-
- }
- else {
- /* we have a seam - deal with it! */
-
- /* inset face coords. NOTE!!! ScreenSace for ortho, Worldspace in perspective view */
- float insetCos[3][3];
-
- /* vertex screenspace coords */
- const float *vCoSS[3];
-
- /* Store the screenspace coords of the face,
- * clipped by the bucket's screen aligned rectangle. */
- float bucket_clip_edges[2][2];
- float edge_verts_inset_clip[2][3];
- /* face edge pairs - loop throuh these:
- * ((0,1), (1,2), (2,3), (3,0)) or ((0,1), (1,2), (2,0)) for a tri */
- int fidx1, fidx2;
-
- float seam_subsection[4][2];
- float fac1, fac2;
-
- /* Pixelspace UVs. */
- float lt_puv[3][2];
-
- lt_puv[0][0] = lt_uv_pxoffset[0][0] * ibuf->x;
- lt_puv[0][1] = lt_uv_pxoffset[0][1] * ibuf->y;
-
- lt_puv[1][0] = lt_uv_pxoffset[1][0] * ibuf->x;
- lt_puv[1][1] = lt_uv_pxoffset[1][1] * ibuf->y;
-
- lt_puv[2][0] = lt_uv_pxoffset[2][0] * ibuf->x;
- lt_puv[2][1] = lt_uv_pxoffset[2][1] * ibuf->y;
-
- if ((ps->faceSeamFlags[tri_index] & PROJ_FACE_SEAM0) ||
- (ps->faceSeamFlags[tri_index] & PROJ_FACE_SEAM1) ||
- (ps->faceSeamFlags[tri_index] & PROJ_FACE_SEAM2))
- {
- uv_image_outset(ps, lt_uv_pxoffset, lt_puv, tri_index, ibuf->x, ibuf->y);
- }
-
- /* ps->loopSeamUVs cant be modified when threading, now this is done we can unlock. */
- if (threaded) {
- /* Other threads could be modifying these vars */
- BLI_thread_unlock(LOCK_CUSTOM1);
- }
-
- vCoSS[0] = ps->screenCoords[lt_vtri[0]];
- vCoSS[1] = ps->screenCoords[lt_vtri[1]];
- vCoSS[2] = ps->screenCoords[lt_vtri[2]];
-
- /* PROJ_FACE_SCALE_SEAM must be slightly less then 1.0f */
- if (is_ortho) {
- scale_tri(insetCos, vCoSS, PROJ_FACE_SCALE_SEAM);
- }
- else {
- scale_tri(insetCos, vCo, PROJ_FACE_SCALE_SEAM);
- }
-
- for (fidx1 = 0; fidx1 < 3; fidx1++) {
- /* next fidx in the face (0,1,2) -> (1,2,0) */
- fidx2 = (fidx1 == 2) ? 0 : fidx1 + 1;
-
- if ((face_seam_flag & (1 << fidx1)) && /* 1<<fidx1 -> PROJ_FACE_SEAM# */
- line_clip_rect2f(clip_rect, bucket_bounds, vCoSS[fidx1], vCoSS[fidx2], bucket_clip_edges[0], bucket_clip_edges[1]))
- {
- /* Avoid div by zero. */
- if (len_squared_v2v2(vCoSS[fidx1], vCoSS[fidx2]) > FLT_EPSILON) {
- uint loop_idx = ps->mlooptri_eval[tri_index].tri[fidx1];
- LoopSeamData *seam_data = &ps->loopSeamData[loop_idx];
- float (*seam_uvs)[2] = seam_data->seam_uvs;
-
- if (is_ortho) {
- fac1 = line_point_factor_v2(bucket_clip_edges[0], vCoSS[fidx1], vCoSS[fidx2]);
- fac2 = line_point_factor_v2(bucket_clip_edges[1], vCoSS[fidx1], vCoSS[fidx2]);
- }
- else {
- fac1 = screen_px_line_point_factor_v2_persp(ps, bucket_clip_edges[0], vCo[fidx1], vCo[fidx2]);
- fac2 = screen_px_line_point_factor_v2_persp(ps, bucket_clip_edges[1], vCo[fidx1], vCo[fidx2]);
- }
-
- interp_v2_v2v2(seam_subsection[0], lt_uv_pxoffset[fidx1], lt_uv_pxoffset[fidx2], fac1);
- interp_v2_v2v2(seam_subsection[1], lt_uv_pxoffset[fidx1], lt_uv_pxoffset[fidx2], fac2);
-
- interp_v2_v2v2(seam_subsection[2], seam_uvs[0], seam_uvs[1], fac2);
- interp_v2_v2v2(seam_subsection[3], seam_uvs[0], seam_uvs[1], fac1);
-
- /* if the bucket_clip_edges values Z values was kept we could avoid this
- * Inset needs to be added so occlusion tests wont hit adjacent faces */
- interp_v3_v3v3(edge_verts_inset_clip[0], insetCos[fidx1], insetCos[fidx2], fac1);
- interp_v3_v3v3(edge_verts_inset_clip[1], insetCos[fidx1], insetCos[fidx2], fac2);
-
-
- if (pixel_bounds_uv(seam_subsection, &bounds_px, ibuf->x, ibuf->y)) {
- /* bounds between the seam rect and the uvspace bucket pixels */
-
- has_isect = 0;
- for (y = bounds_px.ymin; y < bounds_px.ymax; y++) {
- // uv[1] = (((float)y) + 0.5f) / (float)ibuf->y;
- /* use offset uvs instead */
- uv[1] = (float)y / ibuf_yf;
-
- has_x_isect = 0;
- for (x = bounds_px.xmin; x < bounds_px.xmax; x++) {
- float puv[2] = {(float)x, (float)y};
- bool in_bounds;
- //uv[0] = (((float)x) + 0.5f) / (float)ibuf->x;
- /* use offset uvs instead */
- uv[0] = (float)x / ibuf_xf;
-
- /* test we're inside uvspace bucket and triangle bounds */
- if (equals_v2v2(seam_uvs[0], seam_uvs[1])) {
- in_bounds = isect_point_tri_v2(uv, UNPACK3(seam_subsection));
- }
- else {
- in_bounds = isect_point_quad_v2(uv, UNPACK4(seam_subsection));
- }
-
- if (in_bounds) {
- if ((seam_data->corner_dist_sq[0] > 0.0f) &&
- (len_squared_v2v2(puv, seam_data->seam_puvs[0]) < seam_data->corner_dist_sq[0]) &&
- (len_squared_v2v2(puv, lt_puv[fidx1]) > ps->seam_bleed_px_sq))
- {
- in_bounds = false;
- }
- else if ((seam_data->corner_dist_sq[1] > 0.0f) &&
- (len_squared_v2v2(puv, seam_data->seam_puvs[1]) < seam_data->corner_dist_sq[1]) &&
- (len_squared_v2v2(puv, lt_puv[fidx2]) > ps->seam_bleed_px_sq))
- {
- in_bounds = false;
- }
- }
-
- if (in_bounds) {
- float pixel_on_edge[4];
- float fac;
-
- if (is_ortho) {
- screen_px_from_ortho(uv, v1coSS, v2coSS, v3coSS, uv1co, uv2co, uv3co, pixelScreenCo, w);
- }
- else {
- screen_px_from_persp(uv, v1coSS, v2coSS, v3coSS, uv1co, uv2co, uv3co, pixelScreenCo, w);
- }
-
- /* We need the coord of the pixel on the edge, for the occlusion query. */
- fac = resolve_quad_u_v2(uv, UNPACK4(seam_subsection));
- interp_v3_v3v3(pixel_on_edge, edge_verts_inset_clip[0], edge_verts_inset_clip[1], fac);
-
- if (!is_ortho) {
- pixel_on_edge[3] = 1.0f;
- /* cast because of const */
- mul_m4_v4((float(*)[4])ps->projectMat, pixel_on_edge);
- pixel_on_edge[0] = (float)(ps->winx * 0.5f) + (ps->winx * 0.5f) * pixel_on_edge[0] / pixel_on_edge[3];
- pixel_on_edge[1] = (float)(ps->winy * 0.5f) + (ps->winy * 0.5f) * pixel_on_edge[1] / pixel_on_edge[3];
- /* Use the depth for bucket point occlusion */
- pixel_on_edge[2] = pixel_on_edge[2] / pixel_on_edge[3];
- }
-
- if ((ps->do_occlude == false) ||
- !project_bucket_point_occluded(ps, bucketFaceNodes, tri_index, pixel_on_edge))
- {
- /* a pity we need to get the worldspace
- * pixel location here */
- if (do_clip || do_3d_mapping) {
- interp_v3_v3v3v3(wco, vCo[0], vCo[1], vCo[2], w);
-
- if (do_clip && ED_view3d_clipping_test(ps->rv3d, wco, true)) {
- /* Watch out that no code below
- * this needs to run */
- continue;
- }
- }
-
- mask = project_paint_uvpixel_mask(ps, tri_index, w);
-
- if (mask > 0.0f) {
- BLI_linklist_prepend_arena(
- bucketPixelNodes,
- project_paint_uvpixel_init(ps, arena, &tinf, x, y, mask, tri_index,
- pixelScreenCo, wco, w),
- arena
- );
- }
-
- }
- }
- else if (has_x_isect) {
- /* assuming the face is not a bow-tie - we know
- * we cant intersect again on the X */
- break;
- }
- }
-
-#if 0 /* TODO - investigate why this dosnt work sometimes! it should! */
- /* no intersection for this entire row,
- * after some intersection above means we can quit now */
- if (has_x_isect == 0 && has_isect) {
- break;
- }
-#endif
- }
- }
- }
- }
- }
- }
- }
+ if (ps->seam_bleed_px > 0.0f && !(ps->faceSeamFlags[tri_index] & PROJ_FACE_DEGENERATE)) {
+ int face_seam_flag;
+
+ if (threaded) {
+ /* Other threads could be modifying these vars. */
+ BLI_thread_lock(LOCK_CUSTOM1);
+ }
+
+ face_seam_flag = ps->faceSeamFlags[tri_index];
+
+ /* are any of our edges un-initialized? */
+ if ((face_seam_flag & PROJ_FACE_SEAM_INIT0) == 0 ||
+ (face_seam_flag & PROJ_FACE_SEAM_INIT1) == 0 ||
+ (face_seam_flag & PROJ_FACE_SEAM_INIT2) == 0) {
+ project_face_seams_init(ps, arena, tri_index, 0, true, ibuf->x, ibuf->y);
+ face_seam_flag = ps->faceSeamFlags[tri_index];
+ //printf("seams - %d %d %d %d\n", flag&PROJ_FACE_SEAM0, flag&PROJ_FACE_SEAM1, flag&PROJ_FACE_SEAM2);
+ }
+
+ if ((face_seam_flag & (PROJ_FACE_SEAM0 | PROJ_FACE_SEAM1 | PROJ_FACE_SEAM2)) == 0) {
+
+ if (threaded) {
+ /* Other threads could be modifying these vars. */
+ BLI_thread_unlock(LOCK_CUSTOM1);
+ }
+ }
+ else {
+ /* we have a seam - deal with it! */
+
+ /* inset face coords. NOTE!!! ScreenSace for ortho, Worldspace in perspective view */
+ float insetCos[3][3];
+
+ /* vertex screenspace coords */
+ const float *vCoSS[3];
+
+ /* Store the screenspace coords of the face,
+ * clipped by the bucket's screen aligned rectangle. */
+ float bucket_clip_edges[2][2];
+ float edge_verts_inset_clip[2][3];
+ /* face edge pairs - loop throuh these:
+ * ((0,1), (1,2), (2,3), (3,0)) or ((0,1), (1,2), (2,0)) for a tri */
+ int fidx1, fidx2;
+
+ float seam_subsection[4][2];
+ float fac1, fac2;
+
+ /* Pixelspace UVs. */
+ float lt_puv[3][2];
+
+ lt_puv[0][0] = lt_uv_pxoffset[0][0] * ibuf->x;
+ lt_puv[0][1] = lt_uv_pxoffset[0][1] * ibuf->y;
+
+ lt_puv[1][0] = lt_uv_pxoffset[1][0] * ibuf->x;
+ lt_puv[1][1] = lt_uv_pxoffset[1][1] * ibuf->y;
+
+ lt_puv[2][0] = lt_uv_pxoffset[2][0] * ibuf->x;
+ lt_puv[2][1] = lt_uv_pxoffset[2][1] * ibuf->y;
+
+ if ((ps->faceSeamFlags[tri_index] & PROJ_FACE_SEAM0) ||
+ (ps->faceSeamFlags[tri_index] & PROJ_FACE_SEAM1) ||
+ (ps->faceSeamFlags[tri_index] & PROJ_FACE_SEAM2)) {
+ uv_image_outset(ps, lt_uv_pxoffset, lt_puv, tri_index, ibuf->x, ibuf->y);
+ }
+
+ /* ps->loopSeamUVs cant be modified when threading, now this is done we can unlock. */
+ if (threaded) {
+ /* Other threads could be modifying these vars */
+ BLI_thread_unlock(LOCK_CUSTOM1);
+ }
+
+ vCoSS[0] = ps->screenCoords[lt_vtri[0]];
+ vCoSS[1] = ps->screenCoords[lt_vtri[1]];
+ vCoSS[2] = ps->screenCoords[lt_vtri[2]];
+
+ /* PROJ_FACE_SCALE_SEAM must be slightly less then 1.0f */
+ if (is_ortho) {
+ scale_tri(insetCos, vCoSS, PROJ_FACE_SCALE_SEAM);
+ }
+ else {
+ scale_tri(insetCos, vCo, PROJ_FACE_SCALE_SEAM);
+ }
+
+ for (fidx1 = 0; fidx1 < 3; fidx1++) {
+ /* next fidx in the face (0,1,2) -> (1,2,0) */
+ fidx2 = (fidx1 == 2) ? 0 : fidx1 + 1;
+
+ if ((face_seam_flag & (1 << fidx1)) && /* 1<<fidx1 -> PROJ_FACE_SEAM# */
+ line_clip_rect2f(clip_rect,
+ bucket_bounds,
+ vCoSS[fidx1],
+ vCoSS[fidx2],
+ bucket_clip_edges[0],
+ bucket_clip_edges[1])) {
+ /* Avoid div by zero. */
+ if (len_squared_v2v2(vCoSS[fidx1], vCoSS[fidx2]) > FLT_EPSILON) {
+ uint loop_idx = ps->mlooptri_eval[tri_index].tri[fidx1];
+ LoopSeamData *seam_data = &ps->loopSeamData[loop_idx];
+ float(*seam_uvs)[2] = seam_data->seam_uvs;
+
+ if (is_ortho) {
+ fac1 = line_point_factor_v2(bucket_clip_edges[0], vCoSS[fidx1], vCoSS[fidx2]);
+ fac2 = line_point_factor_v2(bucket_clip_edges[1], vCoSS[fidx1], vCoSS[fidx2]);
+ }
+ else {
+ fac1 = screen_px_line_point_factor_v2_persp(
+ ps, bucket_clip_edges[0], vCo[fidx1], vCo[fidx2]);
+ fac2 = screen_px_line_point_factor_v2_persp(
+ ps, bucket_clip_edges[1], vCo[fidx1], vCo[fidx2]);
+ }
+
+ interp_v2_v2v2(seam_subsection[0], lt_uv_pxoffset[fidx1], lt_uv_pxoffset[fidx2], fac1);
+ interp_v2_v2v2(seam_subsection[1], lt_uv_pxoffset[fidx1], lt_uv_pxoffset[fidx2], fac2);
+
+ interp_v2_v2v2(seam_subsection[2], seam_uvs[0], seam_uvs[1], fac2);
+ interp_v2_v2v2(seam_subsection[3], seam_uvs[0], seam_uvs[1], fac1);
+
+ /* if the bucket_clip_edges values Z values was kept we could avoid this
+ * Inset needs to be added so occlusion tests wont hit adjacent faces */
+ interp_v3_v3v3(edge_verts_inset_clip[0], insetCos[fidx1], insetCos[fidx2], fac1);
+ interp_v3_v3v3(edge_verts_inset_clip[1], insetCos[fidx1], insetCos[fidx2], fac2);
+
+ if (pixel_bounds_uv(seam_subsection, &bounds_px, ibuf->x, ibuf->y)) {
+ /* bounds between the seam rect and the uvspace bucket pixels */
+
+ has_isect = 0;
+ for (y = bounds_px.ymin; y < bounds_px.ymax; y++) {
+ // uv[1] = (((float)y) + 0.5f) / (float)ibuf->y;
+ /* use offset uvs instead */
+ uv[1] = (float)y / ibuf_yf;
+
+ has_x_isect = 0;
+ for (x = bounds_px.xmin; x < bounds_px.xmax; x++) {
+ float puv[2] = {(float)x, (float)y};
+ bool in_bounds;
+ //uv[0] = (((float)x) + 0.5f) / (float)ibuf->x;
+ /* use offset uvs instead */
+ uv[0] = (float)x / ibuf_xf;
+
+ /* test we're inside uvspace bucket and triangle bounds */
+ if (equals_v2v2(seam_uvs[0], seam_uvs[1])) {
+ in_bounds = isect_point_tri_v2(uv, UNPACK3(seam_subsection));
+ }
+ else {
+ in_bounds = isect_point_quad_v2(uv, UNPACK4(seam_subsection));
+ }
+
+ if (in_bounds) {
+ if ((seam_data->corner_dist_sq[0] > 0.0f) &&
+ (len_squared_v2v2(puv, seam_data->seam_puvs[0]) <
+ seam_data->corner_dist_sq[0]) &&
+ (len_squared_v2v2(puv, lt_puv[fidx1]) > ps->seam_bleed_px_sq)) {
+ in_bounds = false;
+ }
+ else if ((seam_data->corner_dist_sq[1] > 0.0f) &&
+ (len_squared_v2v2(puv, seam_data->seam_puvs[1]) <
+ seam_data->corner_dist_sq[1]) &&
+ (len_squared_v2v2(puv, lt_puv[fidx2]) > ps->seam_bleed_px_sq)) {
+ in_bounds = false;
+ }
+ }
+
+ if (in_bounds) {
+ float pixel_on_edge[4];
+ float fac;
+
+ if (is_ortho) {
+ screen_px_from_ortho(
+ uv, v1coSS, v2coSS, v3coSS, uv1co, uv2co, uv3co, pixelScreenCo, w);
+ }
+ else {
+ screen_px_from_persp(
+ uv, v1coSS, v2coSS, v3coSS, uv1co, uv2co, uv3co, pixelScreenCo, w);
+ }
+
+ /* We need the coord of the pixel on the edge, for the occlusion query. */
+ fac = resolve_quad_u_v2(uv, UNPACK4(seam_subsection));
+ interp_v3_v3v3(
+ pixel_on_edge, edge_verts_inset_clip[0], edge_verts_inset_clip[1], fac);
+
+ if (!is_ortho) {
+ pixel_on_edge[3] = 1.0f;
+ /* cast because of const */
+ mul_m4_v4((float(*)[4])ps->projectMat, pixel_on_edge);
+ pixel_on_edge[0] = (float)(ps->winx * 0.5f) +
+ (ps->winx * 0.5f) * pixel_on_edge[0] / pixel_on_edge[3];
+ pixel_on_edge[1] = (float)(ps->winy * 0.5f) +
+ (ps->winy * 0.5f) * pixel_on_edge[1] / pixel_on_edge[3];
+ /* Use the depth for bucket point occlusion */
+ pixel_on_edge[2] = pixel_on_edge[2] / pixel_on_edge[3];
+ }
+
+ if ((ps->do_occlude == false) ||
+ !project_bucket_point_occluded(
+ ps, bucketFaceNodes, tri_index, pixel_on_edge)) {
+ /* a pity we need to get the worldspace
+ * pixel location here */
+ if (do_clip || do_3d_mapping) {
+ interp_v3_v3v3v3(wco, vCo[0], vCo[1], vCo[2], w);
+
+ if (do_clip && ED_view3d_clipping_test(ps->rv3d, wco, true)) {
+ /* Watch out that no code below
+ * this needs to run */
+ continue;
+ }
+ }
+
+ mask = project_paint_uvpixel_mask(ps, tri_index, w);
+
+ if (mask > 0.0f) {
+ BLI_linklist_prepend_arena(
+ bucketPixelNodes,
+ project_paint_uvpixel_init(
+ ps, arena, &tinf, x, y, mask, tri_index, pixelScreenCo, wco, w),
+ arena);
+ }
+ }
+ }
+ else if (has_x_isect) {
+ /* assuming the face is not a bow-tie - we know
+ * we cant intersect again on the X */
+ break;
+ }
+ }
+
+# if 0 /* TODO - investigate why this dosnt work sometimes! it should! */
+ /* no intersection for this entire row,
+ * after some intersection above means we can quit now */
+ if (has_x_isect == 0 && has_isect) {
+ break;
+ }
+# endif
+ }
+ }
+ }
+ }
+ }
+ }
+ }
#else
- UNUSED_VARS(vCo, threaded);
-#endif // PROJ_DEBUG_NOSEAMBLEED
+ UNUSED_VARS(vCo, threaded);
+#endif // PROJ_DEBUG_NOSEAMBLEED
}
-
/**
* Takes floating point screenspace min/max and
* returns int min/max to be used as indices for ps->bucketRect, ps->bucketFlags
*/
-static void project_paint_bucket_bounds(
- const ProjPaintState *ps,
- const float min[2], const float max[2],
- int bucketMin[2], int bucketMax[2])
+static void project_paint_bucket_bounds(const ProjPaintState *ps,
+ const float min[2],
+ const float max[2],
+ int bucketMin[2],
+ int bucketMax[2])
{
- /* divide by bucketWidth & bucketHeight so the bounds are offset in bucket grid units */
-
- /* XXX: the offset of 0.5 is always truncated to zero and the offset of 1.5f
- * is always truncated to 1, is this really correct?? - jwilkins */
-
- /* these offsets of 0.5 and 1.5 seem odd but they are correct */
- bucketMin[0] = (int)((int)(((float)(min[0] - ps->screenMin[0]) / ps->screen_width) * ps->buckets_x) + 0.5f);
- bucketMin[1] = (int)((int)(((float)(min[1] - ps->screenMin[1]) / ps->screen_height) * ps->buckets_y) + 0.5f);
-
- bucketMax[0] = (int)((int)(((float)(max[0] - ps->screenMin[0]) / ps->screen_width) * ps->buckets_x) + 1.5f);
- bucketMax[1] = (int)((int)(((float)(max[1] - ps->screenMin[1]) / ps->screen_height) * ps->buckets_y) + 1.5f);
-
- /* in case the rect is outside the mesh 2d bounds */
- CLAMP(bucketMin[0], 0, ps->buckets_x);
- CLAMP(bucketMin[1], 0, ps->buckets_y);
-
- CLAMP(bucketMax[0], 0, ps->buckets_x);
- CLAMP(bucketMax[1], 0, ps->buckets_y);
+ /* divide by bucketWidth & bucketHeight so the bounds are offset in bucket grid units */
+
+ /* XXX: the offset of 0.5 is always truncated to zero and the offset of 1.5f
+ * is always truncated to 1, is this really correct?? - jwilkins */
+
+ /* these offsets of 0.5 and 1.5 seem odd but they are correct */
+ bucketMin[0] =
+ (int)((int)(((float)(min[0] - ps->screenMin[0]) / ps->screen_width) * ps->buckets_x) + 0.5f);
+ bucketMin[1] = (int)((int)(((float)(min[1] - ps->screenMin[1]) / ps->screen_height) *
+ ps->buckets_y) +
+ 0.5f);
+
+ bucketMax[0] =
+ (int)((int)(((float)(max[0] - ps->screenMin[0]) / ps->screen_width) * ps->buckets_x) + 1.5f);
+ bucketMax[1] = (int)((int)(((float)(max[1] - ps->screenMin[1]) / ps->screen_height) *
+ ps->buckets_y) +
+ 1.5f);
+
+ /* in case the rect is outside the mesh 2d bounds */
+ CLAMP(bucketMin[0], 0, ps->buckets_x);
+ CLAMP(bucketMin[1], 0, ps->buckets_y);
+
+ CLAMP(bucketMax[0], 0, ps->buckets_x);
+ CLAMP(bucketMax[1], 0, ps->buckets_y);
}
/* set bucket_bounds to a screen space-aligned floating point bound-box */
-static void project_bucket_bounds(
- const ProjPaintState *ps, const int bucket_x, const int bucket_y, rctf *bucket_bounds)
+static void project_bucket_bounds(const ProjPaintState *ps,
+ const int bucket_x,
+ const int bucket_y,
+ rctf *bucket_bounds)
{
- /* left */
- bucket_bounds->xmin = (
- ps->screenMin[0] + ((bucket_x) * (ps->screen_width / ps->buckets_x)));
- /* right */
- bucket_bounds->xmax = (
- ps->screenMin[0] + ((bucket_x + 1) * (ps->screen_width / ps->buckets_x)));
-
- /* bottom */
- bucket_bounds->ymin = (
- ps->screenMin[1] + ((bucket_y) * (ps->screen_height / ps->buckets_y)));
- /* top */
- bucket_bounds->ymax = (
- ps->screenMin[1] + ((bucket_y + 1) * (ps->screen_height / ps->buckets_y)));
+ /* left */
+ bucket_bounds->xmin = (ps->screenMin[0] + ((bucket_x) * (ps->screen_width / ps->buckets_x)));
+ /* right */
+ bucket_bounds->xmax = (ps->screenMin[0] + ((bucket_x + 1) * (ps->screen_width / ps->buckets_x)));
+
+ /* bottom */
+ bucket_bounds->ymin = (ps->screenMin[1] + ((bucket_y) * (ps->screen_height / ps->buckets_y)));
+ /* top */
+ bucket_bounds->ymax = (ps->screenMin[1] +
+ ((bucket_y + 1) * (ps->screen_height / ps->buckets_y)));
}
/* Fill this bucket with pixels from the faces that intersect it.
*
* have bucket_bounds as an argument so we don't need to give bucket_x/y the rect function needs */
-static void project_bucket_init(
- const ProjPaintState *ps, const int thread_index, const int bucket_index,
- const rctf *clip_rect, const rctf *bucket_bounds)
+static void project_bucket_init(const ProjPaintState *ps,
+ const int thread_index,
+ const int bucket_index,
+ const rctf *clip_rect,
+ const rctf *bucket_bounds)
{
- LinkNode *node;
- int tri_index, image_index = 0;
- ImBuf *ibuf = NULL;
- Image *tpage_last = NULL, *tpage;
- ImBuf *tmpibuf = NULL;
-
- if (ps->image_tot == 1) {
- /* Simple loop, no context switching */
- ibuf = ps->projImages[0].ibuf;
-
- for (node = ps->bucketFaces[bucket_index]; node; node = node->next) {
- project_paint_face_init(
- ps, thread_index, bucket_index, POINTER_AS_INT(node->link), 0,
- clip_rect, bucket_bounds, ibuf, &tmpibuf);
- }
- }
- else {
-
- /* More complicated loop, switch between images */
- for (node = ps->bucketFaces[bucket_index]; node; node = node->next) {
- tri_index = POINTER_AS_INT(node->link);
-
- /* Image context switching */
- tpage = project_paint_face_paint_image(ps, tri_index);
- if (tpage_last != tpage) {
- tpage_last = tpage;
-
- for (image_index = 0; image_index < ps->image_tot; image_index++) {
- if (ps->projImages[image_index].ima == tpage_last) {
- ibuf = ps->projImages[image_index].ibuf;
- break;
- }
- }
- }
- /* context switching done */
-
- project_paint_face_init(
- ps, thread_index, bucket_index, tri_index, image_index,
- clip_rect, bucket_bounds, ibuf, &tmpibuf);
- }
- }
-
- if (tmpibuf)
- IMB_freeImBuf(tmpibuf);
-
- ps->bucketFlags[bucket_index] |= PROJ_BUCKET_INIT;
+ LinkNode *node;
+ int tri_index, image_index = 0;
+ ImBuf *ibuf = NULL;
+ Image *tpage_last = NULL, *tpage;
+ ImBuf *tmpibuf = NULL;
+
+ if (ps->image_tot == 1) {
+ /* Simple loop, no context switching */
+ ibuf = ps->projImages[0].ibuf;
+
+ for (node = ps->bucketFaces[bucket_index]; node; node = node->next) {
+ project_paint_face_init(ps,
+ thread_index,
+ bucket_index,
+ POINTER_AS_INT(node->link),
+ 0,
+ clip_rect,
+ bucket_bounds,
+ ibuf,
+ &tmpibuf);
+ }
+ }
+ else {
+
+ /* More complicated loop, switch between images */
+ for (node = ps->bucketFaces[bucket_index]; node; node = node->next) {
+ tri_index = POINTER_AS_INT(node->link);
+
+ /* Image context switching */
+ tpage = project_paint_face_paint_image(ps, tri_index);
+ if (tpage_last != tpage) {
+ tpage_last = tpage;
+
+ for (image_index = 0; image_index < ps->image_tot; image_index++) {
+ if (ps->projImages[image_index].ima == tpage_last) {
+ ibuf = ps->projImages[image_index].ibuf;
+ break;
+ }
+ }
+ }
+ /* context switching done */
+
+ project_paint_face_init(ps,
+ thread_index,
+ bucket_index,
+ tri_index,
+ image_index,
+ clip_rect,
+ bucket_bounds,
+ ibuf,
+ &tmpibuf);
+ }
+ }
+
+ if (tmpibuf)
+ IMB_freeImBuf(tmpibuf);
+
+ ps->bucketFlags[bucket_index] |= PROJ_BUCKET_INIT;
}
-
/* We want to know if a bucket and a face overlap in screen-space
*
* Note, if this ever returns false positives its not that bad, since a face in the bounding area
* will have its pixels calculated when it might not be needed later, (at the moment at least)
* obviously it shouldn't have bugs though */
-static bool project_bucket_face_isect(ProjPaintState *ps, int bucket_x, int bucket_y, const MLoopTri *lt)
+static bool project_bucket_face_isect(ProjPaintState *ps,
+ int bucket_x,
+ int bucket_y,
+ const MLoopTri *lt)
{
- /* TODO - replace this with a tricker method that uses sideofline for all
- * screenCoords's edges against the closest bucket corner */
- const int lt_vtri[3] = { PS_LOOPTRI_AS_VERT_INDEX_3(ps, lt) };
- rctf bucket_bounds;
- float p1[2], p2[2], p3[2], p4[2];
- const float *v, *v1, *v2, *v3;
- int fidx;
-
- project_bucket_bounds(ps, bucket_x, bucket_y, &bucket_bounds);
-
- /* Is one of the faces verts in the bucket bounds? */
-
- fidx = 2;
- do {
- v = ps->screenCoords[lt_vtri[fidx]];
- if (BLI_rctf_isect_pt_v(&bucket_bounds, v)) {
- return 1;
- }
- } while (fidx--);
-
- v1 = ps->screenCoords[lt_vtri[0]];
- v2 = ps->screenCoords[lt_vtri[1]];
- v3 = ps->screenCoords[lt_vtri[2]];
-
- p1[0] = bucket_bounds.xmin; p1[1] = bucket_bounds.ymin;
- p2[0] = bucket_bounds.xmin; p2[1] = bucket_bounds.ymax;
- p3[0] = bucket_bounds.xmax; p3[1] = bucket_bounds.ymax;
- p4[0] = bucket_bounds.xmax; p4[1] = bucket_bounds.ymin;
-
- if (isect_point_tri_v2(p1, v1, v2, v3) ||
- isect_point_tri_v2(p2, v1, v2, v3) ||
- isect_point_tri_v2(p3, v1, v2, v3) ||
- isect_point_tri_v2(p4, v1, v2, v3) ||
- /* we can avoid testing v3,v1 because another intersection MUST exist if this intersects */
- (isect_seg_seg_v2(p1, p2, v1, v2) || isect_seg_seg_v2(p1, p2, v2, v3)) ||
- (isect_seg_seg_v2(p2, p3, v1, v2) || isect_seg_seg_v2(p2, p3, v2, v3)) ||
- (isect_seg_seg_v2(p3, p4, v1, v2) || isect_seg_seg_v2(p3, p4, v2, v3)) ||
- (isect_seg_seg_v2(p4, p1, v1, v2) || isect_seg_seg_v2(p4, p1, v2, v3)))
- {
- return 1;
- }
-
- return 0;
+ /* TODO - replace this with a tricker method that uses sideofline for all
+ * screenCoords's edges against the closest bucket corner */
+ const int lt_vtri[3] = {PS_LOOPTRI_AS_VERT_INDEX_3(ps, lt)};
+ rctf bucket_bounds;
+ float p1[2], p2[2], p3[2], p4[2];
+ const float *v, *v1, *v2, *v3;
+ int fidx;
+
+ project_bucket_bounds(ps, bucket_x, bucket_y, &bucket_bounds);
+
+ /* Is one of the faces verts in the bucket bounds? */
+
+ fidx = 2;
+ do {
+ v = ps->screenCoords[lt_vtri[fidx]];
+ if (BLI_rctf_isect_pt_v(&bucket_bounds, v)) {
+ return 1;
+ }
+ } while (fidx--);
+
+ v1 = ps->screenCoords[lt_vtri[0]];
+ v2 = ps->screenCoords[lt_vtri[1]];
+ v3 = ps->screenCoords[lt_vtri[2]];
+
+ p1[0] = bucket_bounds.xmin;
+ p1[1] = bucket_bounds.ymin;
+ p2[0] = bucket_bounds.xmin;
+ p2[1] = bucket_bounds.ymax;
+ p3[0] = bucket_bounds.xmax;
+ p3[1] = bucket_bounds.ymax;
+ p4[0] = bucket_bounds.xmax;
+ p4[1] = bucket_bounds.ymin;
+
+ if (isect_point_tri_v2(p1, v1, v2, v3) || isect_point_tri_v2(p2, v1, v2, v3) ||
+ isect_point_tri_v2(p3, v1, v2, v3) || isect_point_tri_v2(p4, v1, v2, v3) ||
+ /* we can avoid testing v3,v1 because another intersection MUST exist if this intersects */
+ (isect_seg_seg_v2(p1, p2, v1, v2) || isect_seg_seg_v2(p1, p2, v2, v3)) ||
+ (isect_seg_seg_v2(p2, p3, v1, v2) || isect_seg_seg_v2(p2, p3, v2, v3)) ||
+ (isect_seg_seg_v2(p3, p4, v1, v2) || isect_seg_seg_v2(p3, p4, v2, v3)) ||
+ (isect_seg_seg_v2(p4, p1, v1, v2) || isect_seg_seg_v2(p4, p1, v2, v3))) {
+ return 1;
+ }
+
+ return 0;
}
/* Add faces to the bucket but don't initialize its pixels
* TODO - when painting occluded, sort the faces on their min-Z
* and only add faces that faces that are not occluded */
-static void project_paint_delayed_face_init(ProjPaintState *ps, const MLoopTri *lt, const int tri_index)
+static void project_paint_delayed_face_init(ProjPaintState *ps,
+ const MLoopTri *lt,
+ const int tri_index)
{
- const int lt_vtri[3] = { PS_LOOPTRI_AS_VERT_INDEX_3(ps, lt) };
- float min[2], max[2], *vCoSS;
- /* for ps->bucketRect indexing */
- int bucketMin[2], bucketMax[2];
- int fidx, bucket_x, bucket_y;
- /* for early loop exit */
- int has_x_isect = -1, has_isect = 0;
- /* just use the first thread arena since threading has not started yet */
- MemArena *arena = ps->arena_mt[0];
-
- INIT_MINMAX2(min, max);
-
- fidx = 2;
- do {
- vCoSS = ps->screenCoords[lt_vtri[fidx]];
- minmax_v2v2_v2(min, max, vCoSS);
- } while (fidx--);
-
- project_paint_bucket_bounds(ps, min, max, bucketMin, bucketMax);
-
- for (bucket_y = bucketMin[1]; bucket_y < bucketMax[1]; bucket_y++) {
- has_x_isect = 0;
- for (bucket_x = bucketMin[0]; bucket_x < bucketMax[0]; bucket_x++) {
- if (project_bucket_face_isect(ps, bucket_x, bucket_y, lt)) {
- int bucket_index = bucket_x + (bucket_y * ps->buckets_x);
- BLI_linklist_prepend_arena(
- &ps->bucketFaces[bucket_index],
- /* cast to a pointer to shut up the compiler */
- POINTER_FROM_INT(tri_index),
- arena
- );
-
- has_x_isect = has_isect = 1;
- }
- else if (has_x_isect) {
- /* assuming the face is not a bow-tie - we know we cant intersect again on the X */
- break;
- }
- }
-
- /* no intersection for this entire row,
- * after some intersection above means we can quit now */
- if (has_x_isect == 0 && has_isect) {
- break;
- }
- }
+ const int lt_vtri[3] = {PS_LOOPTRI_AS_VERT_INDEX_3(ps, lt)};
+ float min[2], max[2], *vCoSS;
+ /* for ps->bucketRect indexing */
+ int bucketMin[2], bucketMax[2];
+ int fidx, bucket_x, bucket_y;
+ /* for early loop exit */
+ int has_x_isect = -1, has_isect = 0;
+ /* just use the first thread arena since threading has not started yet */
+ MemArena *arena = ps->arena_mt[0];
+
+ INIT_MINMAX2(min, max);
+
+ fidx = 2;
+ do {
+ vCoSS = ps->screenCoords[lt_vtri[fidx]];
+ minmax_v2v2_v2(min, max, vCoSS);
+ } while (fidx--);
+
+ project_paint_bucket_bounds(ps, min, max, bucketMin, bucketMax);
+
+ for (bucket_y = bucketMin[1]; bucket_y < bucketMax[1]; bucket_y++) {
+ has_x_isect = 0;
+ for (bucket_x = bucketMin[0]; bucket_x < bucketMax[0]; bucket_x++) {
+ if (project_bucket_face_isect(ps, bucket_x, bucket_y, lt)) {
+ int bucket_index = bucket_x + (bucket_y * ps->buckets_x);
+ BLI_linklist_prepend_arena(&ps->bucketFaces[bucket_index],
+ /* cast to a pointer to shut up the compiler */
+ POINTER_FROM_INT(tri_index),
+ arena);
+
+ has_x_isect = has_isect = 1;
+ }
+ else if (has_x_isect) {
+ /* assuming the face is not a bow-tie - we know we cant intersect again on the X */
+ break;
+ }
+ }
+
+ /* no intersection for this entire row,
+ * after some intersection above means we can quit now */
+ if (has_x_isect == 0 && has_isect) {
+ break;
+ }
+ }
#ifndef PROJ_DEBUG_NOSEAMBLEED
- if (ps->seam_bleed_px > 0.0f) {
- /* set as uninitialized */
- ps->loopSeamData[lt->tri[0]].seam_uvs[0][0] = FLT_MAX;
- ps->loopSeamData[lt->tri[1]].seam_uvs[0][0] = FLT_MAX;
- ps->loopSeamData[lt->tri[2]].seam_uvs[0][0] = FLT_MAX;
- }
+ if (ps->seam_bleed_px > 0.0f) {
+ /* set as uninitialized */
+ ps->loopSeamData[lt->tri[0]].seam_uvs[0][0] = FLT_MAX;
+ ps->loopSeamData[lt->tri[1]].seam_uvs[0][0] = FLT_MAX;
+ ps->loopSeamData[lt->tri[2]].seam_uvs[0][0] = FLT_MAX;
+ }
#endif
}
static void proj_paint_state_viewport_init(ProjPaintState *ps, const char symmetry_flag)
{
- float mat[3][3];
- float viewmat[4][4];
- float viewinv[4][4];
-
- ps->viewDir[0] = 0.0f;
- ps->viewDir[1] = 0.0f;
- ps->viewDir[2] = 1.0f;
-
- copy_m4_m4(ps->obmat, ps->ob->obmat);
-
- if (symmetry_flag) {
- int i;
- for (i = 0; i < 3; i++) {
- if ((symmetry_flag >> i) & 1) {
- negate_v3(ps->obmat[i]);
- ps->is_flip_object = !ps->is_flip_object;
- }
- }
- }
-
- invert_m4_m4(ps->obmat_imat, ps->obmat);
-
- if (ELEM(ps->source, PROJ_SRC_VIEW, PROJ_SRC_VIEW_FILL)) {
- /* normal drawing */
- ps->winx = ps->ar->winx;
- ps->winy = ps->ar->winy;
-
- copy_m4_m4(viewmat, ps->rv3d->viewmat);
- copy_m4_m4(viewinv, ps->rv3d->viewinv);
-
- ED_view3d_ob_project_mat_get_from_obmat(ps->rv3d, ps->obmat, ps->projectMat);
-
- ps->is_ortho = ED_view3d_clip_range_get(ps->depsgraph, ps->v3d, ps->rv3d, &ps->clip_start, &ps->clip_end, true);
- }
- else {
- /* re-projection */
- float winmat[4][4];
- float vmat[4][4];
-
- ps->winx = ps->reproject_ibuf->x;
- ps->winy = ps->reproject_ibuf->y;
-
- if (ps->source == PROJ_SRC_IMAGE_VIEW) {
- /* image stores camera data, tricky */
- IDProperty *idgroup = IDP_GetProperties(&ps->reproject_image->id, 0);
- IDProperty *view_data = IDP_GetPropertyFromGroup(idgroup, PROJ_VIEW_DATA_ID);
-
- const float *array = (float *)IDP_Array(view_data);
-
- /* use image array, written when creating image */
- memcpy(winmat, array, sizeof(winmat)); array += sizeof(winmat) / sizeof(float);
- memcpy(viewmat, array, sizeof(viewmat)); array += sizeof(viewmat) / sizeof(float);
- ps->clip_start = array[0];
- ps->clip_end = array[1];
- ps->is_ortho = array[2] ? 1 : 0;
-
- invert_m4_m4(viewinv, viewmat);
- }
- else if (ps->source == PROJ_SRC_IMAGE_CAM) {
- Object *cam_ob_eval = DEG_get_evaluated_object(ps->depsgraph, ps->scene->camera);
- CameraParams params;
-
- /* viewmat & viewinv */
- copy_m4_m4(viewinv, cam_ob_eval->obmat);
- normalize_m4(viewinv);
- invert_m4_m4(viewmat, viewinv);
-
- /* window matrix, clipping and ortho */
- BKE_camera_params_init(&params);
- BKE_camera_params_from_object(&params, cam_ob_eval);
- BKE_camera_params_compute_viewplane(&params, ps->winx, ps->winy, 1.0f, 1.0f);
- BKE_camera_params_compute_matrix(&params);
-
- copy_m4_m4(winmat, params.winmat);
- ps->clip_start = params.clip_start;
- ps->clip_end = params.clip_end;
- ps->is_ortho = params.is_ortho;
- }
- else {
- BLI_assert(0);
- }
-
- /* same as #ED_view3d_ob_project_mat_get */
- mul_m4_m4m4(vmat, viewmat, ps->obmat);
- mul_m4_m4m4(ps->projectMat, winmat, vmat);
- }
-
- invert_m4_m4(ps->projectMatInv, ps->projectMat);
-
- /* viewDir - object relative */
- copy_m3_m4(mat, viewinv);
- mul_m3_v3(mat, ps->viewDir);
- copy_m3_m4(mat, ps->obmat_imat);
- mul_m3_v3(mat, ps->viewDir);
- normalize_v3(ps->viewDir);
-
- if (UNLIKELY(ps->is_flip_object)) {
- negate_v3(ps->viewDir);
- }
-
- /* viewPos - object relative */
- copy_v3_v3(ps->viewPos, viewinv[3]);
- copy_m3_m4(mat, ps->obmat_imat);
- mul_m3_v3(mat, ps->viewPos);
- add_v3_v3(ps->viewPos, ps->obmat_imat[3]);
+ float mat[3][3];
+ float viewmat[4][4];
+ float viewinv[4][4];
+
+ ps->viewDir[0] = 0.0f;
+ ps->viewDir[1] = 0.0f;
+ ps->viewDir[2] = 1.0f;
+
+ copy_m4_m4(ps->obmat, ps->ob->obmat);
+
+ if (symmetry_flag) {
+ int i;
+ for (i = 0; i < 3; i++) {
+ if ((symmetry_flag >> i) & 1) {
+ negate_v3(ps->obmat[i]);
+ ps->is_flip_object = !ps->is_flip_object;
+ }
+ }
+ }
+
+ invert_m4_m4(ps->obmat_imat, ps->obmat);
+
+ if (ELEM(ps->source, PROJ_SRC_VIEW, PROJ_SRC_VIEW_FILL)) {
+ /* normal drawing */
+ ps->winx = ps->ar->winx;
+ ps->winy = ps->ar->winy;
+
+ copy_m4_m4(viewmat, ps->rv3d->viewmat);
+ copy_m4_m4(viewinv, ps->rv3d->viewinv);
+
+ ED_view3d_ob_project_mat_get_from_obmat(ps->rv3d, ps->obmat, ps->projectMat);
+
+ ps->is_ortho = ED_view3d_clip_range_get(
+ ps->depsgraph, ps->v3d, ps->rv3d, &ps->clip_start, &ps->clip_end, true);
+ }
+ else {
+ /* re-projection */
+ float winmat[4][4];
+ float vmat[4][4];
+
+ ps->winx = ps->reproject_ibuf->x;
+ ps->winy = ps->reproject_ibuf->y;
+
+ if (ps->source == PROJ_SRC_IMAGE_VIEW) {
+ /* image stores camera data, tricky */
+ IDProperty *idgroup = IDP_GetProperties(&ps->reproject_image->id, 0);
+ IDProperty *view_data = IDP_GetPropertyFromGroup(idgroup, PROJ_VIEW_DATA_ID);
+
+ const float *array = (float *)IDP_Array(view_data);
+
+ /* use image array, written when creating image */
+ memcpy(winmat, array, sizeof(winmat));
+ array += sizeof(winmat) / sizeof(float);
+ memcpy(viewmat, array, sizeof(viewmat));
+ array += sizeof(viewmat) / sizeof(float);
+ ps->clip_start = array[0];
+ ps->clip_end = array[1];
+ ps->is_ortho = array[2] ? 1 : 0;
+
+ invert_m4_m4(viewinv, viewmat);
+ }
+ else if (ps->source == PROJ_SRC_IMAGE_CAM) {
+ Object *cam_ob_eval = DEG_get_evaluated_object(ps->depsgraph, ps->scene->camera);
+ CameraParams params;
+
+ /* viewmat & viewinv */
+ copy_m4_m4(viewinv, cam_ob_eval->obmat);
+ normalize_m4(viewinv);
+ invert_m4_m4(viewmat, viewinv);
+
+ /* window matrix, clipping and ortho */
+ BKE_camera_params_init(&params);
+ BKE_camera_params_from_object(&params, cam_ob_eval);
+ BKE_camera_params_compute_viewplane(&params, ps->winx, ps->winy, 1.0f, 1.0f);
+ BKE_camera_params_compute_matrix(&params);
+
+ copy_m4_m4(winmat, params.winmat);
+ ps->clip_start = params.clip_start;
+ ps->clip_end = params.clip_end;
+ ps->is_ortho = params.is_ortho;
+ }
+ else {
+ BLI_assert(0);
+ }
+
+ /* same as #ED_view3d_ob_project_mat_get */
+ mul_m4_m4m4(vmat, viewmat, ps->obmat);
+ mul_m4_m4m4(ps->projectMat, winmat, vmat);
+ }
+
+ invert_m4_m4(ps->projectMatInv, ps->projectMat);
+
+ /* viewDir - object relative */
+ copy_m3_m4(mat, viewinv);
+ mul_m3_v3(mat, ps->viewDir);
+ copy_m3_m4(mat, ps->obmat_imat);
+ mul_m3_v3(mat, ps->viewDir);
+ normalize_v3(ps->viewDir);
+
+ if (UNLIKELY(ps->is_flip_object)) {
+ negate_v3(ps->viewDir);
+ }
+
+ /* viewPos - object relative */
+ copy_v3_v3(ps->viewPos, viewinv[3]);
+ copy_m3_m4(mat, ps->obmat_imat);
+ mul_m3_v3(mat, ps->viewPos);
+ add_v3_v3(ps->viewPos, ps->obmat_imat[3]);
}
static void proj_paint_state_screen_coords_init(ProjPaintState *ps, const int diameter)
{
- const MVert *mv;
- float *projScreenCo;
- float projMargin;
- int a;
-
- INIT_MINMAX2(ps->screenMin, ps->screenMax);
-
- ps->screenCoords = MEM_mallocN(sizeof(float) * ps->totvert_eval * 4, "ProjectPaint ScreenVerts");
- projScreenCo = *ps->screenCoords;
-
- if (ps->is_ortho) {
- for (a = 0, mv = ps->mvert_eval; a < ps->totvert_eval; a++, mv++, projScreenCo += 4) {
- mul_v3_m4v3(projScreenCo, ps->projectMat, mv->co);
-
- /* screen space, not clamped */
- projScreenCo[0] = (float)(ps->winx * 0.5f) + (ps->winx * 0.5f) * projScreenCo[0];
- projScreenCo[1] = (float)(ps->winy * 0.5f) + (ps->winy * 0.5f) * projScreenCo[1];
- minmax_v2v2_v2(ps->screenMin, ps->screenMax, projScreenCo);
- }
- }
- else {
- for (a = 0, mv = ps->mvert_eval; a < ps->totvert_eval; a++, mv++, projScreenCo += 4) {
- copy_v3_v3(projScreenCo, mv->co);
- projScreenCo[3] = 1.0f;
-
- mul_m4_v4(ps->projectMat, projScreenCo);
-
- if (projScreenCo[3] > ps->clip_start) {
- /* screen space, not clamped */
- projScreenCo[0] = (float)(ps->winx * 0.5f) + (ps->winx * 0.5f) * projScreenCo[0] / projScreenCo[3];
- projScreenCo[1] = (float)(ps->winy * 0.5f) + (ps->winy * 0.5f) * projScreenCo[1] / projScreenCo[3];
- /* Use the depth for bucket point occlusion */
- projScreenCo[2] = projScreenCo[2] / projScreenCo[3];
- minmax_v2v2_v2(ps->screenMin, ps->screenMax, projScreenCo);
- }
- else {
- /* TODO - deal with cases where 1 side of a face goes behind the view ?
- *
- * After some research this is actually very tricky, only option is to
- * clip the derived mesh before painting, which is a Pain */
- projScreenCo[0] = FLT_MAX;
- }
- }
- }
-
- /* If this border is not added we get artifacts for faces that
- * have a parallel edge and at the bounds of the 2D projected verts eg
- * - a single screen aligned quad */
- projMargin = (ps->screenMax[0] - ps->screenMin[0]) * 0.000001f;
- ps->screenMax[0] += projMargin;
- ps->screenMin[0] -= projMargin;
- projMargin = (ps->screenMax[1] - ps->screenMin[1]) * 0.000001f;
- ps->screenMax[1] += projMargin;
- ps->screenMin[1] -= projMargin;
-
- if (ps->source == PROJ_SRC_VIEW) {
+ const MVert *mv;
+ float *projScreenCo;
+ float projMargin;
+ int a;
+
+ INIT_MINMAX2(ps->screenMin, ps->screenMax);
+
+ ps->screenCoords = MEM_mallocN(sizeof(float) * ps->totvert_eval * 4, "ProjectPaint ScreenVerts");
+ projScreenCo = *ps->screenCoords;
+
+ if (ps->is_ortho) {
+ for (a = 0, mv = ps->mvert_eval; a < ps->totvert_eval; a++, mv++, projScreenCo += 4) {
+ mul_v3_m4v3(projScreenCo, ps->projectMat, mv->co);
+
+ /* screen space, not clamped */
+ projScreenCo[0] = (float)(ps->winx * 0.5f) + (ps->winx * 0.5f) * projScreenCo[0];
+ projScreenCo[1] = (float)(ps->winy * 0.5f) + (ps->winy * 0.5f) * projScreenCo[1];
+ minmax_v2v2_v2(ps->screenMin, ps->screenMax, projScreenCo);
+ }
+ }
+ else {
+ for (a = 0, mv = ps->mvert_eval; a < ps->totvert_eval; a++, mv++, projScreenCo += 4) {
+ copy_v3_v3(projScreenCo, mv->co);
+ projScreenCo[3] = 1.0f;
+
+ mul_m4_v4(ps->projectMat, projScreenCo);
+
+ if (projScreenCo[3] > ps->clip_start) {
+ /* screen space, not clamped */
+ projScreenCo[0] = (float)(ps->winx * 0.5f) +
+ (ps->winx * 0.5f) * projScreenCo[0] / projScreenCo[3];
+ projScreenCo[1] = (float)(ps->winy * 0.5f) +
+ (ps->winy * 0.5f) * projScreenCo[1] / projScreenCo[3];
+ /* Use the depth for bucket point occlusion */
+ projScreenCo[2] = projScreenCo[2] / projScreenCo[3];
+ minmax_v2v2_v2(ps->screenMin, ps->screenMax, projScreenCo);
+ }
+ else {
+ /* TODO - deal with cases where 1 side of a face goes behind the view ?
+ *
+ * After some research this is actually very tricky, only option is to
+ * clip the derived mesh before painting, which is a Pain */
+ projScreenCo[0] = FLT_MAX;
+ }
+ }
+ }
+
+ /* If this border is not added we get artifacts for faces that
+ * have a parallel edge and at the bounds of the 2D projected verts eg
+ * - a single screen aligned quad */
+ projMargin = (ps->screenMax[0] - ps->screenMin[0]) * 0.000001f;
+ ps->screenMax[0] += projMargin;
+ ps->screenMin[0] -= projMargin;
+ projMargin = (ps->screenMax[1] - ps->screenMin[1]) * 0.000001f;
+ ps->screenMax[1] += projMargin;
+ ps->screenMin[1] -= projMargin;
+
+ if (ps->source == PROJ_SRC_VIEW) {
#ifdef PROJ_DEBUG_WINCLIP
- CLAMP(ps->screenMin[0], (float)(-diameter), (float)(ps->winx + diameter));
- CLAMP(ps->screenMax[0], (float)(-diameter), (float)(ps->winx + diameter));
+ CLAMP(ps->screenMin[0], (float)(-diameter), (float)(ps->winx + diameter));
+ CLAMP(ps->screenMax[0], (float)(-diameter), (float)(ps->winx + diameter));
- CLAMP(ps->screenMin[1], (float)(-diameter), (float)(ps->winy + diameter));
- CLAMP(ps->screenMax[1], (float)(-diameter), (float)(ps->winy + diameter));
+ CLAMP(ps->screenMin[1], (float)(-diameter), (float)(ps->winy + diameter));
+ CLAMP(ps->screenMax[1], (float)(-diameter), (float)(ps->winy + diameter));
#else
- UNUSED_VARS(diameter);
+ UNUSED_VARS(diameter);
#endif
- }
- else if (ps->source != PROJ_SRC_VIEW_FILL) { /* re-projection, use bounds */
- ps->screenMin[0] = 0;
- ps->screenMax[0] = (float)(ps->winx);
-
- ps->screenMin[1] = 0;
- ps->screenMax[1] = (float)(ps->winy);
- }
+ }
+ else if (ps->source != PROJ_SRC_VIEW_FILL) { /* re-projection, use bounds */
+ ps->screenMin[0] = 0;
+ ps->screenMax[0] = (float)(ps->winx);
+
+ ps->screenMin[1] = 0;
+ ps->screenMax[1] = (float)(ps->winy);
+ }
}
static void proj_paint_state_cavity_init(ProjPaintState *ps)
{
- const MVert *mv;
- const MEdge *me;
- float *cavities;
- int a;
-
- if (ps->do_mask_cavity) {
- int *counter = MEM_callocN(sizeof(int) * ps->totvert_eval, "counter");
- float (*edges)[3] = MEM_callocN(sizeof(float) * 3 * ps->totvert_eval, "edges");
- ps->cavities = MEM_mallocN(sizeof(float) * ps->totvert_eval, "ProjectPaint Cavities");
- cavities = ps->cavities;
-
- for (a = 0, me = ps->medge_eval; a < ps->totedge_eval; a++, me++) {
- float e[3];
- sub_v3_v3v3(e, ps->mvert_eval[me->v1].co, ps->mvert_eval[me->v2].co);
- normalize_v3(e);
- add_v3_v3(edges[me->v2], e);
- counter[me->v2]++;
- sub_v3_v3(edges[me->v1], e);
- counter[me->v1]++;
- }
- for (a = 0, mv = ps->mvert_eval; a < ps->totvert_eval; a++, mv++) {
- if (counter[a] > 0) {
- float no[3];
- mul_v3_fl(edges[a], 1.0f / counter[a]);
- normal_short_to_float_v3(no, mv->no);
- /* augment the diffe*/
- cavities[a] = saacos(10.0f * dot_v3v3(no, edges[a])) * (float)M_1_PI;
- }
- else
- cavities[a] = 0.0;
- }
-
- MEM_freeN(counter);
- MEM_freeN(edges);
- }
+ const MVert *mv;
+ const MEdge *me;
+ float *cavities;
+ int a;
+
+ if (ps->do_mask_cavity) {
+ int *counter = MEM_callocN(sizeof(int) * ps->totvert_eval, "counter");
+ float(*edges)[3] = MEM_callocN(sizeof(float) * 3 * ps->totvert_eval, "edges");
+ ps->cavities = MEM_mallocN(sizeof(float) * ps->totvert_eval, "ProjectPaint Cavities");
+ cavities = ps->cavities;
+
+ for (a = 0, me = ps->medge_eval; a < ps->totedge_eval; a++, me++) {
+ float e[3];
+ sub_v3_v3v3(e, ps->mvert_eval[me->v1].co, ps->mvert_eval[me->v2].co);
+ normalize_v3(e);
+ add_v3_v3(edges[me->v2], e);
+ counter[me->v2]++;
+ sub_v3_v3(edges[me->v1], e);
+ counter[me->v1]++;
+ }
+ for (a = 0, mv = ps->mvert_eval; a < ps->totvert_eval; a++, mv++) {
+ if (counter[a] > 0) {
+ float no[3];
+ mul_v3_fl(edges[a], 1.0f / counter[a]);
+ normal_short_to_float_v3(no, mv->no);
+ /* augment the diffe*/
+ cavities[a] = saacos(10.0f * dot_v3v3(no, edges[a])) * (float)M_1_PI;
+ }
+ else
+ cavities[a] = 0.0;
+ }
+
+ MEM_freeN(counter);
+ MEM_freeN(edges);
+ }
}
#ifndef PROJ_DEBUG_NOSEAMBLEED
static void proj_paint_state_seam_bleed_init(ProjPaintState *ps)
{
- if (ps->seam_bleed_px > 0.0f) {
- ps->vertFaces = MEM_callocN(sizeof(LinkNode *) * ps->totvert_eval, "paint-vertFaces");
- ps->faceSeamFlags = MEM_callocN(sizeof(ushort) * ps->totlooptri_eval, "paint-faceSeamFlags");
- ps->faceWindingFlags = MEM_callocN(sizeof(char) * ps->totlooptri_eval, "paint-faceWindindFlags");
- ps->loopSeamData = MEM_mallocN(sizeof(LoopSeamData) * ps->totloop_eval, "paint-loopSeamUVs");
- ps->vertSeams = MEM_callocN(sizeof(ListBase) * ps->totvert_eval, "paint-vertSeams");
- }
+ if (ps->seam_bleed_px > 0.0f) {
+ ps->vertFaces = MEM_callocN(sizeof(LinkNode *) * ps->totvert_eval, "paint-vertFaces");
+ ps->faceSeamFlags = MEM_callocN(sizeof(ushort) * ps->totlooptri_eval, "paint-faceSeamFlags");
+ ps->faceWindingFlags = MEM_callocN(sizeof(char) * ps->totlooptri_eval,
+ "paint-faceWindindFlags");
+ ps->loopSeamData = MEM_mallocN(sizeof(LoopSeamData) * ps->totloop_eval, "paint-loopSeamUVs");
+ ps->vertSeams = MEM_callocN(sizeof(ListBase) * ps->totvert_eval, "paint-vertSeams");
+ }
}
#endif
static void proj_paint_state_thread_init(ProjPaintState *ps, const bool reset_threads)
{
- int a;
+ int a;
- /* Thread stuff
- *
- * very small brushes run a lot slower multithreaded since the advantage with
- * threads is being able to fill in multiple buckets at once.
- * Only use threads for bigger brushes. */
+ /* Thread stuff
+ *
+ * very small brushes run a lot slower multithreaded since the advantage with
+ * threads is being able to fill in multiple buckets at once.
+ * Only use threads for bigger brushes. */
- ps->thread_tot = BKE_scene_num_threads(ps->scene);
+ ps->thread_tot = BKE_scene_num_threads(ps->scene);
- /* workaround for #35057, disable threading if diameter is less than is possible for
- * optimum bucket number generation */
- if (reset_threads)
- ps->thread_tot = 1;
+ /* workaround for #35057, disable threading if diameter is less than is possible for
+ * optimum bucket number generation */
+ if (reset_threads)
+ ps->thread_tot = 1;
- if (ps->is_shared_user == false) {
- if (ps->thread_tot > 1) {
- ps->tile_lock = MEM_mallocN(sizeof(SpinLock), "projpaint_tile_lock");
- BLI_spin_init(ps->tile_lock);
- }
+ if (ps->is_shared_user == false) {
+ if (ps->thread_tot > 1) {
+ ps->tile_lock = MEM_mallocN(sizeof(SpinLock), "projpaint_tile_lock");
+ BLI_spin_init(ps->tile_lock);
+ }
- image_undo_init_locks();
- }
+ image_undo_init_locks();
+ }
- for (a = 0; a < ps->thread_tot; a++) {
- ps->arena_mt[a] = BLI_memarena_new(MEM_SIZE_OPTIMAL(1 << 16), "project paint arena");
- }
+ for (a = 0; a < ps->thread_tot; a++) {
+ ps->arena_mt[a] = BLI_memarena_new(MEM_SIZE_OPTIMAL(1 << 16), "project paint arena");
+ }
}
static void proj_paint_state_vert_flags_init(ProjPaintState *ps)
{
- if (ps->do_backfacecull && ps->do_mask_normal) {
- float viewDirPersp[3];
- const MVert *mv;
- float no[3];
- int a;
-
- ps->vertFlags = MEM_callocN(sizeof(char) * ps->totvert_eval, "paint-vertFlags");
-
- for (a = 0, mv = ps->mvert_eval; a < ps->totvert_eval; a++, mv++) {
- normal_short_to_float_v3(no, mv->no);
- if (UNLIKELY(ps->is_flip_object)) {
- negate_v3(no);
- }
-
- if (ps->is_ortho) {
- if (dot_v3v3(ps->viewDir, no) <= ps->normal_angle__cos) {
- /* 1 vert of this face is towards us */
- ps->vertFlags[a] |= PROJ_VERT_CULL;
- }
- }
- else {
- sub_v3_v3v3(viewDirPersp, ps->viewPos, mv->co);
- normalize_v3(viewDirPersp);
- if (UNLIKELY(ps->is_flip_object)) {
- negate_v3(viewDirPersp);
- }
- if (dot_v3v3(viewDirPersp, no) <= ps->normal_angle__cos) {
- /* 1 vert of this face is towards us */
- ps->vertFlags[a] |= PROJ_VERT_CULL;
- }
- }
- }
- }
- else {
- ps->vertFlags = NULL;
- }
+ if (ps->do_backfacecull && ps->do_mask_normal) {
+ float viewDirPersp[3];
+ const MVert *mv;
+ float no[3];
+ int a;
+
+ ps->vertFlags = MEM_callocN(sizeof(char) * ps->totvert_eval, "paint-vertFlags");
+
+ for (a = 0, mv = ps->mvert_eval; a < ps->totvert_eval; a++, mv++) {
+ normal_short_to_float_v3(no, mv->no);
+ if (UNLIKELY(ps->is_flip_object)) {
+ negate_v3(no);
+ }
+
+ if (ps->is_ortho) {
+ if (dot_v3v3(ps->viewDir, no) <= ps->normal_angle__cos) {
+ /* 1 vert of this face is towards us */
+ ps->vertFlags[a] |= PROJ_VERT_CULL;
+ }
+ }
+ else {
+ sub_v3_v3v3(viewDirPersp, ps->viewPos, mv->co);
+ normalize_v3(viewDirPersp);
+ if (UNLIKELY(ps->is_flip_object)) {
+ negate_v3(viewDirPersp);
+ }
+ if (dot_v3v3(viewDirPersp, no) <= ps->normal_angle__cos) {
+ /* 1 vert of this face is towards us */
+ ps->vertFlags[a] |= PROJ_VERT_CULL;
+ }
+ }
+ }
+ }
+ else {
+ ps->vertFlags = NULL;
+ }
}
#ifndef PROJ_DEBUG_NOSEAMBLEED
-static void project_paint_bleed_add_face_user(
- const ProjPaintState *ps, MemArena *arena,
- const MLoopTri *lt, const int tri_index)
+static void project_paint_bleed_add_face_user(const ProjPaintState *ps,
+ MemArena *arena,
+ const MLoopTri *lt,
+ const int tri_index)
{
- /* add face user if we have bleed enabled, set the UV seam flags later */
- /* annoying but we need to add all faces even ones we never use elsewhere */
- if (ps->seam_bleed_px > 0.0f) {
- const float *lt_tri_uv[3] = { PS_LOOPTRI_AS_UV_3(ps->poly_to_loop_uv, lt) };
-
- /* Check for degenerate triangles. Degenerate faces cause trouble with bleed computations.
- * Ideally this would be checked later, not to add to the cost of computing non-degenerate
- * triangles, but that would allow other triangles to still find adjacent seams on degenerate
- * triangles, potentially causing incorrect results. */
- if (area_tri_v2(UNPACK3(lt_tri_uv)) > FLT_EPSILON) {
- const int lt_vtri[3] = { PS_LOOPTRI_AS_VERT_INDEX_3(ps, lt) };
- void *tri_index_p = POINTER_FROM_INT(tri_index);
-
- BLI_linklist_prepend_arena(&ps->vertFaces[lt_vtri[0]], tri_index_p, arena);
- BLI_linklist_prepend_arena(&ps->vertFaces[lt_vtri[1]], tri_index_p, arena);
- BLI_linklist_prepend_arena(&ps->vertFaces[lt_vtri[2]], tri_index_p, arena);
- }
- else {
- ps->faceSeamFlags[tri_index] |= PROJ_FACE_DEGENERATE;
- }
- }
+ /* add face user if we have bleed enabled, set the UV seam flags later */
+ /* annoying but we need to add all faces even ones we never use elsewhere */
+ if (ps->seam_bleed_px > 0.0f) {
+ const float *lt_tri_uv[3] = {PS_LOOPTRI_AS_UV_3(ps->poly_to_loop_uv, lt)};
+
+ /* Check for degenerate triangles. Degenerate faces cause trouble with bleed computations.
+ * Ideally this would be checked later, not to add to the cost of computing non-degenerate
+ * triangles, but that would allow other triangles to still find adjacent seams on degenerate
+ * triangles, potentially causing incorrect results. */
+ if (area_tri_v2(UNPACK3(lt_tri_uv)) > FLT_EPSILON) {
+ const int lt_vtri[3] = {PS_LOOPTRI_AS_VERT_INDEX_3(ps, lt)};
+ void *tri_index_p = POINTER_FROM_INT(tri_index);
+
+ BLI_linklist_prepend_arena(&ps->vertFaces[lt_vtri[0]], tri_index_p, arena);
+ BLI_linklist_prepend_arena(&ps->vertFaces[lt_vtri[1]], tri_index_p, arena);
+ BLI_linklist_prepend_arena(&ps->vertFaces[lt_vtri[2]], tri_index_p, arena);
+ }
+ else {
+ ps->faceSeamFlags[tri_index] |= PROJ_FACE_DEGENERATE;
+ }
+ }
}
#endif
/* Return true if evaluated mesh can be painted on, false otherwise */
static bool proj_paint_state_mesh_eval_init(const bContext *C, ProjPaintState *ps)
{
- Depsgraph *depsgraph = CTX_data_depsgraph(C);
- Object *ob = ps->ob;
-
- Scene *scene_eval = DEG_get_evaluated_scene(depsgraph);
- Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
-
- if (scene_eval == NULL || ob_eval == NULL) {
- return false;
- }
-
- CustomData_MeshMasks cddata_masks = scene_eval->customdata_mask;
- cddata_masks.fmask |= CD_MASK_MTFACE;
- cddata_masks.lmask |= CD_MASK_MLOOPUV;
-
- /* Workaround for subsurf selection, try the display mesh first */
- if (ps->source == PROJ_SRC_IMAGE_CAM) {
- /* using render mesh, assume only camera was rendered from */
- ps->me_eval = mesh_create_eval_final_render(
- depsgraph, scene_eval, ob_eval, &cddata_masks);
- ps->me_eval_free = true;
- }
- else {
- if (ps->do_face_sel) {
- cddata_masks.vmask |= CD_MASK_ORIGINDEX;
- cddata_masks.emask |= CD_MASK_ORIGINDEX;
- cddata_masks.pmask |= CD_MASK_ORIGINDEX;
- }
- ps->me_eval = mesh_get_eval_final(
- depsgraph, scene_eval, ob_eval,
- &cddata_masks);
- ps->me_eval_free = false;
- }
-
- if (!CustomData_has_layer(&ps->me_eval->ldata, CD_MLOOPUV)) {
- if (ps->me_eval_free) {
- BKE_id_free(NULL, ps->me_eval);
- }
- ps->me_eval = NULL;
- return false;
- }
-
- /* Build final material array, we use this a lot here. */
- /* materials start from 1, default material is 0 */
- const int totmat = ob->totcol + 1;
- ps->mat_array = MEM_malloc_arrayN(totmat, sizeof(*ps->mat_array), __func__);
- /* We leave last material as empty - rationale here is being able to index
- * the materials by using the mf->mat_nr directly and leaving the last
- * material as NULL in case no materials exist on mesh, so indexing will not fail. */
- for (int i = 0; i < totmat - 1; i++) {
- ps->mat_array[i] = give_current_material(ob, i + 1);
- }
- ps->mat_array[totmat - 1] = NULL;
-
- ps->mvert_eval = ps->me_eval->mvert;
- if (ps->do_mask_cavity) {
- ps->medge_eval = ps->me_eval->medge;
- }
- ps->mloop_eval = ps->me_eval->mloop;
- ps->mpoly_eval = ps->me_eval->mpoly;
-
- ps->totvert_eval = ps->me_eval->totvert;
- ps->totedge_eval = ps->me_eval->totedge;
- ps->totpoly_eval = ps->me_eval->totpoly;
- ps->totloop_eval = ps->me_eval->totloop;
-
- ps->mlooptri_eval = BKE_mesh_runtime_looptri_ensure(ps->me_eval);
- ps->totlooptri_eval = ps->me_eval->runtime.looptris.len;
-
- ps->poly_to_loop_uv = MEM_mallocN(ps->totpoly_eval * sizeof(MLoopUV *), "proj_paint_mtfaces");
-
- return true;
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ Object *ob = ps->ob;
+
+ Scene *scene_eval = DEG_get_evaluated_scene(depsgraph);
+ Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
+
+ if (scene_eval == NULL || ob_eval == NULL) {
+ return false;
+ }
+
+ CustomData_MeshMasks cddata_masks = scene_eval->customdata_mask;
+ cddata_masks.fmask |= CD_MASK_MTFACE;
+ cddata_masks.lmask |= CD_MASK_MLOOPUV;
+
+ /* Workaround for subsurf selection, try the display mesh first */
+ if (ps->source == PROJ_SRC_IMAGE_CAM) {
+ /* using render mesh, assume only camera was rendered from */
+ ps->me_eval = mesh_create_eval_final_render(depsgraph, scene_eval, ob_eval, &cddata_masks);
+ ps->me_eval_free = true;
+ }
+ else {
+ if (ps->do_face_sel) {
+ cddata_masks.vmask |= CD_MASK_ORIGINDEX;
+ cddata_masks.emask |= CD_MASK_ORIGINDEX;
+ cddata_masks.pmask |= CD_MASK_ORIGINDEX;
+ }
+ ps->me_eval = mesh_get_eval_final(depsgraph, scene_eval, ob_eval, &cddata_masks);
+ ps->me_eval_free = false;
+ }
+
+ if (!CustomData_has_layer(&ps->me_eval->ldata, CD_MLOOPUV)) {
+ if (ps->me_eval_free) {
+ BKE_id_free(NULL, ps->me_eval);
+ }
+ ps->me_eval = NULL;
+ return false;
+ }
+
+ /* Build final material array, we use this a lot here. */
+ /* materials start from 1, default material is 0 */
+ const int totmat = ob->totcol + 1;
+ ps->mat_array = MEM_malloc_arrayN(totmat, sizeof(*ps->mat_array), __func__);
+ /* We leave last material as empty - rationale here is being able to index
+ * the materials by using the mf->mat_nr directly and leaving the last
+ * material as NULL in case no materials exist on mesh, so indexing will not fail. */
+ for (int i = 0; i < totmat - 1; i++) {
+ ps->mat_array[i] = give_current_material(ob, i + 1);
+ }
+ ps->mat_array[totmat - 1] = NULL;
+
+ ps->mvert_eval = ps->me_eval->mvert;
+ if (ps->do_mask_cavity) {
+ ps->medge_eval = ps->me_eval->medge;
+ }
+ ps->mloop_eval = ps->me_eval->mloop;
+ ps->mpoly_eval = ps->me_eval->mpoly;
+
+ ps->totvert_eval = ps->me_eval->totvert;
+ ps->totedge_eval = ps->me_eval->totedge;
+ ps->totpoly_eval = ps->me_eval->totpoly;
+ ps->totloop_eval = ps->me_eval->totloop;
+
+ ps->mlooptri_eval = BKE_mesh_runtime_looptri_ensure(ps->me_eval);
+ ps->totlooptri_eval = ps->me_eval->runtime.looptris.len;
+
+ ps->poly_to_loop_uv = MEM_mallocN(ps->totpoly_eval * sizeof(MLoopUV *), "proj_paint_mtfaces");
+
+ return true;
}
typedef struct {
- const MLoopUV *mloopuv_clone_base;
- const TexPaintSlot *slot_last_clone;
- const TexPaintSlot *slot_clone;
+ const MLoopUV *mloopuv_clone_base;
+ const TexPaintSlot *slot_last_clone;
+ const TexPaintSlot *slot_clone;
} ProjPaintLayerClone;
-static void proj_paint_layer_clone_init(
- ProjPaintState *ps,
- ProjPaintLayerClone *layer_clone)
+static void proj_paint_layer_clone_init(ProjPaintState *ps, ProjPaintLayerClone *layer_clone)
{
- MLoopUV *mloopuv_clone_base = NULL;
+ MLoopUV *mloopuv_clone_base = NULL;
- /* use clone mtface? */
- if (ps->do_layer_clone) {
- const int layer_num = CustomData_get_clone_layer(&((Mesh *)ps->ob->data)->ldata, CD_MLOOPUV);
+ /* use clone mtface? */
+ if (ps->do_layer_clone) {
+ const int layer_num = CustomData_get_clone_layer(&((Mesh *)ps->ob->data)->ldata, CD_MLOOPUV);
- ps->poly_to_loop_uv_clone = MEM_mallocN(ps->totpoly_eval * sizeof(MLoopUV *), "proj_paint_mtfaces");
+ ps->poly_to_loop_uv_clone = MEM_mallocN(ps->totpoly_eval * sizeof(MLoopUV *),
+ "proj_paint_mtfaces");
- if (layer_num != -1)
- mloopuv_clone_base = CustomData_get_layer_n(&ps->me_eval->ldata, CD_MLOOPUV, layer_num);
+ if (layer_num != -1)
+ mloopuv_clone_base = CustomData_get_layer_n(&ps->me_eval->ldata, CD_MLOOPUV, layer_num);
- if (mloopuv_clone_base == NULL) {
- /* get active instead */
- mloopuv_clone_base = CustomData_get_layer(&ps->me_eval->ldata, CD_MLOOPUV);
- }
+ if (mloopuv_clone_base == NULL) {
+ /* get active instead */
+ mloopuv_clone_base = CustomData_get_layer(&ps->me_eval->ldata, CD_MLOOPUV);
+ }
+ }
- }
-
- memset(layer_clone, 0, sizeof(*layer_clone));
- layer_clone->mloopuv_clone_base = mloopuv_clone_base;
+ memset(layer_clone, 0, sizeof(*layer_clone));
+ layer_clone->mloopuv_clone_base = mloopuv_clone_base;
}
/* Return true if face should be skipped, false otherwise */
-static bool project_paint_clone_face_skip(
- ProjPaintState *ps,
- ProjPaintLayerClone *lc,
- const TexPaintSlot *slot,
- const int tri_index)
+static bool project_paint_clone_face_skip(ProjPaintState *ps,
+ ProjPaintLayerClone *lc,
+ const TexPaintSlot *slot,
+ const int tri_index)
{
- if (ps->do_layer_clone) {
- if (ps->do_material_slots) {
- lc->slot_clone = project_paint_face_clone_slot(ps, tri_index);
- /* all faces should have a valid slot, reassert here */
- if (ELEM(lc->slot_clone, NULL, slot))
- return true;
- }
- else if (ps->clone_ima == ps->canvas_ima)
- return true;
-
- if (ps->do_material_slots) {
- if (lc->slot_clone != lc->slot_last_clone) {
- if (!slot->uvname ||
- !(lc->mloopuv_clone_base = CustomData_get_layer_named(
- &ps->me_eval->ldata, CD_MLOOPUV,
- lc->slot_clone->uvname)))
- {
- lc->mloopuv_clone_base = CustomData_get_layer(&ps->me_eval->ldata, CD_MLOOPUV);
- }
- lc->slot_last_clone = lc->slot_clone;
- }
- }
-
- /* will set multiple times for 4+ sided poly */
- ps->poly_to_loop_uv_clone[ps->mlooptri_eval[tri_index].poly] = lc->mloopuv_clone_base;
- }
- return false;
+ if (ps->do_layer_clone) {
+ if (ps->do_material_slots) {
+ lc->slot_clone = project_paint_face_clone_slot(ps, tri_index);
+ /* all faces should have a valid slot, reassert here */
+ if (ELEM(lc->slot_clone, NULL, slot))
+ return true;
+ }
+ else if (ps->clone_ima == ps->canvas_ima)
+ return true;
+
+ if (ps->do_material_slots) {
+ if (lc->slot_clone != lc->slot_last_clone) {
+ if (!slot->uvname || !(lc->mloopuv_clone_base = CustomData_get_layer_named(
+ &ps->me_eval->ldata, CD_MLOOPUV, lc->slot_clone->uvname))) {
+ lc->mloopuv_clone_base = CustomData_get_layer(&ps->me_eval->ldata, CD_MLOOPUV);
+ }
+ lc->slot_last_clone = lc->slot_clone;
+ }
+ }
+
+ /* will set multiple times for 4+ sided poly */
+ ps->poly_to_loop_uv_clone[ps->mlooptri_eval[tri_index].poly] = lc->mloopuv_clone_base;
+ }
+ return false;
}
typedef struct {
- const MPoly *mpoly_orig;
+ const MPoly *mpoly_orig;
- const int *index_mp_to_orig;
+ const int *index_mp_to_orig;
} ProjPaintFaceLookup;
-static void proj_paint_face_lookup_init(
- const ProjPaintState *ps,
- ProjPaintFaceLookup *face_lookup)
+static void proj_paint_face_lookup_init(const ProjPaintState *ps, ProjPaintFaceLookup *face_lookup)
{
- memset(face_lookup, 0, sizeof(*face_lookup));
- if (ps->do_face_sel) {
- face_lookup->index_mp_to_orig = CustomData_get_layer(&ps->me_eval->pdata, CD_ORIGINDEX);
- face_lookup->mpoly_orig = ((Mesh *)ps->ob->data)->mpoly;
- }
+ memset(face_lookup, 0, sizeof(*face_lookup));
+ if (ps->do_face_sel) {
+ face_lookup->index_mp_to_orig = CustomData_get_layer(&ps->me_eval->pdata, CD_ORIGINDEX);
+ face_lookup->mpoly_orig = ((Mesh *)ps->ob->data)->mpoly;
+ }
}
/* Return true if face should be considered selected, false otherwise */
-static bool project_paint_check_face_sel(
- const ProjPaintState *ps,
- const ProjPaintFaceLookup *face_lookup,
- const MLoopTri *lt)
+static bool project_paint_check_face_sel(const ProjPaintState *ps,
+ const ProjPaintFaceLookup *face_lookup,
+ const MLoopTri *lt)
{
- if (ps->do_face_sel) {
- int orig_index;
- const MPoly *mp;
-
- if ((face_lookup->index_mp_to_orig != NULL) &&
- (((orig_index = (face_lookup->index_mp_to_orig[lt->poly]))) != ORIGINDEX_NONE))
- {
- mp = &face_lookup->mpoly_orig[orig_index];
- }
- else {
- mp = &ps->mpoly_eval[lt->poly];
- }
-
- return ((mp->flag & ME_FACE_SEL) != 0);
- }
- else {
- return true;
- }
+ if (ps->do_face_sel) {
+ int orig_index;
+ const MPoly *mp;
+
+ if ((face_lookup->index_mp_to_orig != NULL) &&
+ (((orig_index = (face_lookup->index_mp_to_orig[lt->poly]))) != ORIGINDEX_NONE)) {
+ mp = &face_lookup->mpoly_orig[orig_index];
+ }
+ else {
+ mp = &ps->mpoly_eval[lt->poly];
+ }
+
+ return ((mp->flag & ME_FACE_SEL) != 0);
+ }
+ else {
+ return true;
+ }
}
typedef struct {
- const float *v1;
- const float *v2;
- const float *v3;
+ const float *v1;
+ const float *v2;
+ const float *v3;
} ProjPaintFaceCoSS;
-static void proj_paint_face_coSS_init(
- const ProjPaintState *ps, const MLoopTri *lt,
- ProjPaintFaceCoSS *coSS)
+static void proj_paint_face_coSS_init(const ProjPaintState *ps,
+ const MLoopTri *lt,
+ ProjPaintFaceCoSS *coSS)
{
- const int lt_vtri[3] = { PS_LOOPTRI_AS_VERT_INDEX_3(ps, lt) };
- coSS->v1 = ps->screenCoords[lt_vtri[0]];
- coSS->v2 = ps->screenCoords[lt_vtri[1]];
- coSS->v3 = ps->screenCoords[lt_vtri[2]];
+ const int lt_vtri[3] = {PS_LOOPTRI_AS_VERT_INDEX_3(ps, lt)};
+ coSS->v1 = ps->screenCoords[lt_vtri[0]];
+ coSS->v2 = ps->screenCoords[lt_vtri[1]];
+ coSS->v3 = ps->screenCoords[lt_vtri[2]];
}
/* Return true if face should be culled, false otherwise */
-static bool project_paint_flt_max_cull(
- const ProjPaintState *ps,
- const ProjPaintFaceCoSS *coSS)
+static bool project_paint_flt_max_cull(const ProjPaintState *ps, const ProjPaintFaceCoSS *coSS)
{
- if (!ps->is_ortho) {
- if (coSS->v1[0] == FLT_MAX ||
- coSS->v2[0] == FLT_MAX ||
- coSS->v3[0] == FLT_MAX)
- {
- return true;
- }
- }
- return false;
+ if (!ps->is_ortho) {
+ if (coSS->v1[0] == FLT_MAX || coSS->v2[0] == FLT_MAX || coSS->v3[0] == FLT_MAX) {
+ return true;
+ }
+ }
+ return false;
}
#ifdef PROJ_DEBUG_WINCLIP
/* Return true if face should be culled, false otherwise */
-static bool project_paint_winclip(
- const ProjPaintState *ps,
- const ProjPaintFaceCoSS *coSS)
+static bool project_paint_winclip(const ProjPaintState *ps, const ProjPaintFaceCoSS *coSS)
{
- /* ignore faces outside the view */
- return ((ps->source != PROJ_SRC_VIEW_FILL) &&
- ((coSS->v1[0] < ps->screenMin[0] &&
- coSS->v2[0] < ps->screenMin[0] &&
- coSS->v3[0] < ps->screenMin[0]) ||
-
- (coSS->v1[0] > ps->screenMax[0] &&
- coSS->v2[0] > ps->screenMax[0] &&
- coSS->v3[0] > ps->screenMax[0]) ||
-
- (coSS->v1[1] < ps->screenMin[1] &&
- coSS->v2[1] < ps->screenMin[1] &&
- coSS->v3[1] < ps->screenMin[1]) ||
-
- (coSS->v1[1] > ps->screenMax[1] &&
- coSS->v2[1] > ps->screenMax[1] &&
- coSS->v3[1] > ps->screenMax[1])));
-}
-#endif //PROJ_DEBUG_WINCLIP
+ /* ignore faces outside the view */
+ return ((ps->source != PROJ_SRC_VIEW_FILL) &&
+ ((coSS->v1[0] < ps->screenMin[0] && coSS->v2[0] < ps->screenMin[0] &&
+ coSS->v3[0] < ps->screenMin[0]) ||
+ (coSS->v1[0] > ps->screenMax[0] && coSS->v2[0] > ps->screenMax[0] &&
+ coSS->v3[0] > ps->screenMax[0]) ||
-static void project_paint_build_proj_ima(
- ProjPaintState *ps, MemArena *arena,
- LinkNode *image_LinkList)
+ (coSS->v1[1] < ps->screenMin[1] && coSS->v2[1] < ps->screenMin[1] &&
+ coSS->v3[1] < ps->screenMin[1]) ||
+
+ (coSS->v1[1] > ps->screenMax[1] && coSS->v2[1] > ps->screenMax[1] &&
+ coSS->v3[1] > ps->screenMax[1])));
+}
+#endif //PROJ_DEBUG_WINCLIP
+
+static void project_paint_build_proj_ima(ProjPaintState *ps,
+ MemArena *arena,
+ LinkNode *image_LinkList)
{
- ProjPaintImage *projIma;
- LinkNode *node;
- int i;
-
- /* build an array of images we use */
- projIma = ps->projImages = BLI_memarena_alloc(arena, sizeof(ProjPaintImage) * ps->image_tot);
-
- for (node = image_LinkList, i = 0; node; node = node->next, i++, projIma++) {
- int size;
- projIma->ima = node->link;
- projIma->touch = 0;
- projIma->ibuf = BKE_image_acquire_ibuf(projIma->ima, NULL, NULL);
- size = sizeof(void **) * IMAPAINT_TILE_NUMBER(projIma->ibuf->x) * IMAPAINT_TILE_NUMBER(projIma->ibuf->y);
- projIma->partRedrawRect = BLI_memarena_alloc(arena, sizeof(ImagePaintPartialRedraw) * PROJ_BOUNDBOX_SQUARED);
- partial_redraw_array_init(projIma->partRedrawRect);
- projIma->undoRect = (volatile void **) BLI_memarena_alloc(arena, size);
- memset((void *)projIma->undoRect, 0, size);
- projIma->maskRect = BLI_memarena_alloc(arena, size);
- memset(projIma->maskRect, 0, size);
- projIma->valid = BLI_memarena_alloc(arena, size);
- memset(projIma->valid, 0, size);
- }
+ ProjPaintImage *projIma;
+ LinkNode *node;
+ int i;
+
+ /* build an array of images we use */
+ projIma = ps->projImages = BLI_memarena_alloc(arena, sizeof(ProjPaintImage) * ps->image_tot);
+
+ for (node = image_LinkList, i = 0; node; node = node->next, i++, projIma++) {
+ int size;
+ projIma->ima = node->link;
+ projIma->touch = 0;
+ projIma->ibuf = BKE_image_acquire_ibuf(projIma->ima, NULL, NULL);
+ size = sizeof(void **) * IMAPAINT_TILE_NUMBER(projIma->ibuf->x) *
+ IMAPAINT_TILE_NUMBER(projIma->ibuf->y);
+ projIma->partRedrawRect = BLI_memarena_alloc(
+ arena, sizeof(ImagePaintPartialRedraw) * PROJ_BOUNDBOX_SQUARED);
+ partial_redraw_array_init(projIma->partRedrawRect);
+ projIma->undoRect = (volatile void **)BLI_memarena_alloc(arena, size);
+ memset((void *)projIma->undoRect, 0, size);
+ projIma->maskRect = BLI_memarena_alloc(arena, size);
+ memset(projIma->maskRect, 0, size);
+ projIma->valid = BLI_memarena_alloc(arena, size);
+ memset(projIma->valid, 0, size);
+ }
}
-static void project_paint_prepare_all_faces(
- ProjPaintState *ps, MemArena *arena,
- const ProjPaintFaceLookup *face_lookup,
- ProjPaintLayerClone *layer_clone,
- const MLoopUV *mloopuv_base,
- const bool is_multi_view)
+static void project_paint_prepare_all_faces(ProjPaintState *ps,
+ MemArena *arena,
+ const ProjPaintFaceLookup *face_lookup,
+ ProjPaintLayerClone *layer_clone,
+ const MLoopUV *mloopuv_base,
+ const bool is_multi_view)
{
- /* Image Vars - keep track of images we have used */
- LinkNodePair image_LinkList = {NULL, NULL};
-
- Image *tpage_last = NULL, *tpage;
- TexPaintSlot *slot_last = NULL;
- TexPaintSlot *slot = NULL;
- const MLoopTri *lt;
- int image_index = -1, tri_index;
- int prev_poly = -1;
-
- for (tri_index = 0, lt = ps->mlooptri_eval; tri_index < ps->totlooptri_eval; tri_index++, lt++) {
- bool is_face_sel;
- bool skip_tri = false;
-
- is_face_sel = project_paint_check_face_sel(ps, face_lookup, lt);
-
- if (!ps->do_stencil_brush) {
- slot = project_paint_face_paint_slot(ps, tri_index);
- /* all faces should have a valid slot, reassert here */
- if (slot == NULL) {
- mloopuv_base = CustomData_get_layer(&ps->me_eval->ldata, CD_MLOOPUV);
- tpage = ps->canvas_ima;
- }
- else {
- if (slot != slot_last) {
- if (!slot->uvname || !(mloopuv_base = CustomData_get_layer_named(&ps->me_eval->ldata, CD_MLOOPUV, slot->uvname)))
- mloopuv_base = CustomData_get_layer(&ps->me_eval->ldata, CD_MLOOPUV);
- slot_last = slot;
- }
-
- /* don't allow using the same inage for painting and stencilling */
- if (slot->ima == ps->stencil_ima) {
- /* Delay continuing the loop until after loop_uvs and bleed faces are initialized.
- * While this shouldn't be used, face-winding reads all polys.
- * It's less trouble to set all faces to valid UV's,
- * avoiding NULL checks all over. */
- skip_tri = true;
- }
- else {
- tpage = slot->ima;
- }
- }
- }
- else {
- tpage = ps->stencil_ima;
- }
-
- ps->poly_to_loop_uv[lt->poly] = mloopuv_base;
+ /* Image Vars - keep track of images we have used */
+ LinkNodePair image_LinkList = {NULL, NULL};
+
+ Image *tpage_last = NULL, *tpage;
+ TexPaintSlot *slot_last = NULL;
+ TexPaintSlot *slot = NULL;
+ const MLoopTri *lt;
+ int image_index = -1, tri_index;
+ int prev_poly = -1;
+
+ for (tri_index = 0, lt = ps->mlooptri_eval; tri_index < ps->totlooptri_eval; tri_index++, lt++) {
+ bool is_face_sel;
+ bool skip_tri = false;
+
+ is_face_sel = project_paint_check_face_sel(ps, face_lookup, lt);
+
+ if (!ps->do_stencil_brush) {
+ slot = project_paint_face_paint_slot(ps, tri_index);
+ /* all faces should have a valid slot, reassert here */
+ if (slot == NULL) {
+ mloopuv_base = CustomData_get_layer(&ps->me_eval->ldata, CD_MLOOPUV);
+ tpage = ps->canvas_ima;
+ }
+ else {
+ if (slot != slot_last) {
+ if (!slot->uvname || !(mloopuv_base = CustomData_get_layer_named(
+ &ps->me_eval->ldata, CD_MLOOPUV, slot->uvname)))
+ mloopuv_base = CustomData_get_layer(&ps->me_eval->ldata, CD_MLOOPUV);
+ slot_last = slot;
+ }
+
+ /* don't allow using the same inage for painting and stencilling */
+ if (slot->ima == ps->stencil_ima) {
+ /* Delay continuing the loop until after loop_uvs and bleed faces are initialized.
+ * While this shouldn't be used, face-winding reads all polys.
+ * It's less trouble to set all faces to valid UV's,
+ * avoiding NULL checks all over. */
+ skip_tri = true;
+ }
+ else {
+ tpage = slot->ima;
+ }
+ }
+ }
+ else {
+ tpage = ps->stencil_ima;
+ }
+
+ ps->poly_to_loop_uv[lt->poly] = mloopuv_base;
#ifndef PROJ_DEBUG_NOSEAMBLEED
- project_paint_bleed_add_face_user(ps, arena, lt, tri_index);
+ project_paint_bleed_add_face_user(ps, arena, lt, tri_index);
#endif
- if (skip_tri || project_paint_clone_face_skip(ps, layer_clone, slot, tri_index)) {
- continue;
- }
+ if (skip_tri || project_paint_clone_face_skip(ps, layer_clone, slot, tri_index)) {
+ continue;
+ }
- /* tfbase here should be non-null! */
- BLI_assert(mloopuv_base != NULL);
+ /* tfbase here should be non-null! */
+ BLI_assert(mloopuv_base != NULL);
- if (is_face_sel && tpage) {
- ProjPaintFaceCoSS coSS;
- proj_paint_face_coSS_init(ps, lt, &coSS);
+ if (is_face_sel && tpage) {
+ ProjPaintFaceCoSS coSS;
+ proj_paint_face_coSS_init(ps, lt, &coSS);
- if (is_multi_view == false) {
- if (project_paint_flt_max_cull(ps, &coSS)) {
- continue;
- }
+ if (is_multi_view == false) {
+ if (project_paint_flt_max_cull(ps, &coSS)) {
+ continue;
+ }
#ifdef PROJ_DEBUG_WINCLIP
- if (project_paint_winclip(ps, &coSS)) {
- continue;
- }
-
-#endif //PROJ_DEBUG_WINCLIP
-
- /* backface culls individual triangles but mask normal will use polygon */
- if (ps->do_backfacecull) {
- if (ps->do_mask_normal) {
- if (prev_poly != lt->poly) {
- int iloop;
- bool culled = true;
- const MPoly *poly = ps->mpoly_eval + lt->poly;
- int poly_loops = poly->totloop;
- prev_poly = lt->poly;
- for (iloop = 0; iloop < poly_loops; iloop++) {
- if (!(ps->vertFlags[ps->mloop_eval[poly->loopstart + iloop].v] & PROJ_VERT_CULL)) {
- culled = false;
- break;
- }
- }
-
- if (culled) {
- /* poly loops - 2 is number of triangles for poly,
- * but counter gets incremented when continuing, so decrease by 3 */
- int poly_tri = poly_loops - 3;
- tri_index += poly_tri;
- lt += poly_tri;
- continue;
- }
- }
- }
- else {
- if ((line_point_side_v2(coSS.v1, coSS.v2, coSS.v3) < 0.0f) != ps->is_flip_object) {
- continue;
- }
- }
- }
- }
-
- if (tpage_last != tpage) {
-
- image_index = BLI_linklist_index(image_LinkList.list, tpage);
-
- if (image_index == -1 && BKE_image_has_ibuf(tpage, NULL)) {
- /* MemArena dosnt have an append func */
- BLI_linklist_append(&image_LinkList, tpage);
- image_index = ps->image_tot;
- ps->image_tot++;
- }
-
- tpage_last = tpage;
- }
-
- if (image_index != -1) {
- /* Initialize the faces screen pixels */
- /* Add this to a list to initialize later */
- project_paint_delayed_face_init(ps, lt, tri_index);
- }
- }
- }
-
- /* build an array of images we use*/
- if (ps->is_shared_user == false) {
- project_paint_build_proj_ima(ps, arena, image_LinkList.list);
- }
-
- /* we have built the array, discard the linked list */
- BLI_linklist_free(image_LinkList.list, NULL);
+ if (project_paint_winclip(ps, &coSS)) {
+ continue;
+ }
+
+#endif //PROJ_DEBUG_WINCLIP
+
+ /* backface culls individual triangles but mask normal will use polygon */
+ if (ps->do_backfacecull) {
+ if (ps->do_mask_normal) {
+ if (prev_poly != lt->poly) {
+ int iloop;
+ bool culled = true;
+ const MPoly *poly = ps->mpoly_eval + lt->poly;
+ int poly_loops = poly->totloop;
+ prev_poly = lt->poly;
+ for (iloop = 0; iloop < poly_loops; iloop++) {
+ if (!(ps->vertFlags[ps->mloop_eval[poly->loopstart + iloop].v] & PROJ_VERT_CULL)) {
+ culled = false;
+ break;
+ }
+ }
+
+ if (culled) {
+ /* poly loops - 2 is number of triangles for poly,
+ * but counter gets incremented when continuing, so decrease by 3 */
+ int poly_tri = poly_loops - 3;
+ tri_index += poly_tri;
+ lt += poly_tri;
+ continue;
+ }
+ }
+ }
+ else {
+ if ((line_point_side_v2(coSS.v1, coSS.v2, coSS.v3) < 0.0f) != ps->is_flip_object) {
+ continue;
+ }
+ }
+ }
+ }
+
+ if (tpage_last != tpage) {
+
+ image_index = BLI_linklist_index(image_LinkList.list, tpage);
+
+ if (image_index == -1 && BKE_image_has_ibuf(tpage, NULL)) {
+ /* MemArena dosnt have an append func */
+ BLI_linklist_append(&image_LinkList, tpage);
+ image_index = ps->image_tot;
+ ps->image_tot++;
+ }
+
+ tpage_last = tpage;
+ }
+
+ if (image_index != -1) {
+ /* Initialize the faces screen pixels */
+ /* Add this to a list to initialize later */
+ project_paint_delayed_face_init(ps, lt, tri_index);
+ }
+ }
+ }
+
+ /* build an array of images we use*/
+ if (ps->is_shared_user == false) {
+ project_paint_build_proj_ima(ps, arena, image_LinkList.list);
+ }
+
+ /* we have built the array, discard the linked list */
+ BLI_linklist_free(image_LinkList.list, NULL);
}
/* run once per stroke before projection painting */
-static void project_paint_begin(
- const bContext *C, ProjPaintState *ps,
- const bool is_multi_view, const char symmetry_flag)
+static void project_paint_begin(const bContext *C,
+ ProjPaintState *ps,
+ const bool is_multi_view,
+ const char symmetry_flag)
{
- ProjPaintLayerClone layer_clone;
- ProjPaintFaceLookup face_lookup;
- const MLoopUV *mloopuv_base = NULL;
+ ProjPaintLayerClone layer_clone;
+ ProjPaintFaceLookup face_lookup;
+ const MLoopUV *mloopuv_base = NULL;
- /* at the moment this is just ps->arena_mt[0], but use this to show were not multithreading */
- MemArena *arena;
+ /* at the moment this is just ps->arena_mt[0], but use this to show were not multithreading */
+ MemArena *arena;
- const int diameter = 2 * BKE_brush_size_get(ps->scene, ps->brush);
+ const int diameter = 2 * BKE_brush_size_get(ps->scene, ps->brush);
- bool reset_threads = false;
+ bool reset_threads = false;
- /* ---- end defines ---- */
+ /* ---- end defines ---- */
- if (ps->source == PROJ_SRC_VIEW) {
- /* faster clipping lookups */
- ED_view3d_clipping_local(ps->rv3d, ps->ob->obmat);
- }
+ if (ps->source == PROJ_SRC_VIEW) {
+ /* faster clipping lookups */
+ ED_view3d_clipping_local(ps->rv3d, ps->ob->obmat);
+ }
- ps->do_face_sel = ((((Mesh *)ps->ob->data)->editflag & ME_EDIT_PAINT_FACE_SEL) != 0);
- ps->is_flip_object = (ps->ob->transflag & OB_NEG_SCALE) != 0;
+ ps->do_face_sel = ((((Mesh *)ps->ob->data)->editflag & ME_EDIT_PAINT_FACE_SEL) != 0);
+ ps->is_flip_object = (ps->ob->transflag & OB_NEG_SCALE) != 0;
- /* paint onto the derived mesh */
- if (ps->is_shared_user == false) {
- if (!proj_paint_state_mesh_eval_init(C, ps)) {
- return;
- }
- }
+ /* paint onto the derived mesh */
+ if (ps->is_shared_user == false) {
+ if (!proj_paint_state_mesh_eval_init(C, ps)) {
+ return;
+ }
+ }
- proj_paint_face_lookup_init(ps, &face_lookup);
- proj_paint_layer_clone_init(ps, &layer_clone);
+ proj_paint_face_lookup_init(ps, &face_lookup);
+ proj_paint_layer_clone_init(ps, &layer_clone);
- if (ps->do_layer_stencil || ps->do_stencil_brush) {
- //int layer_num = CustomData_get_stencil_layer(&ps->me_eval->ldata, CD_MLOOPUV);
- int layer_num = CustomData_get_stencil_layer(&((Mesh *)ps->ob->data)->ldata, CD_MLOOPUV);
- if (layer_num != -1)
- ps->mloopuv_stencil_eval = CustomData_get_layer_n(&ps->me_eval->ldata, CD_MLOOPUV, layer_num);
+ if (ps->do_layer_stencil || ps->do_stencil_brush) {
+ //int layer_num = CustomData_get_stencil_layer(&ps->me_eval->ldata, CD_MLOOPUV);
+ int layer_num = CustomData_get_stencil_layer(&((Mesh *)ps->ob->data)->ldata, CD_MLOOPUV);
+ if (layer_num != -1)
+ ps->mloopuv_stencil_eval = CustomData_get_layer_n(
+ &ps->me_eval->ldata, CD_MLOOPUV, layer_num);
- if (ps->mloopuv_stencil_eval == NULL) {
- /* get active instead */
- ps->mloopuv_stencil_eval = CustomData_get_layer(&ps->me_eval->ldata, CD_MLOOPUV);
- }
+ if (ps->mloopuv_stencil_eval == NULL) {
+ /* get active instead */
+ ps->mloopuv_stencil_eval = CustomData_get_layer(&ps->me_eval->ldata, CD_MLOOPUV);
+ }
- if (ps->do_stencil_brush)
- mloopuv_base = ps->mloopuv_stencil_eval;
- }
+ if (ps->do_stencil_brush)
+ mloopuv_base = ps->mloopuv_stencil_eval;
+ }
- /* when using subsurf or multires, mface arrays are thrown away, we need to keep a copy */
- if (ps->is_shared_user == false) {
- proj_paint_state_cavity_init(ps);
- }
+ /* when using subsurf or multires, mface arrays are thrown away, we need to keep a copy */
+ if (ps->is_shared_user == false) {
+ proj_paint_state_cavity_init(ps);
+ }
- proj_paint_state_viewport_init(ps, symmetry_flag);
+ proj_paint_state_viewport_init(ps, symmetry_flag);
- /* calculate vert screen coords
- * run this early so we can calculate the x/y resolution of our bucket rect */
- proj_paint_state_screen_coords_init(ps, diameter);
+ /* calculate vert screen coords
+ * run this early so we can calculate the x/y resolution of our bucket rect */
+ proj_paint_state_screen_coords_init(ps, diameter);
- /* only for convenience */
- ps->screen_width = ps->screenMax[0] - ps->screenMin[0];
- ps->screen_height = ps->screenMax[1] - ps->screenMin[1];
+ /* only for convenience */
+ ps->screen_width = ps->screenMax[0] - ps->screenMin[0];
+ ps->screen_height = ps->screenMax[1] - ps->screenMin[1];
- ps->buckets_x = (int)(ps->screen_width / (((float)diameter) / PROJ_BUCKET_BRUSH_DIV));
- ps->buckets_y = (int)(ps->screen_height / (((float)diameter) / PROJ_BUCKET_BRUSH_DIV));
+ ps->buckets_x = (int)(ps->screen_width / (((float)diameter) / PROJ_BUCKET_BRUSH_DIV));
+ ps->buckets_y = (int)(ps->screen_height / (((float)diameter) / PROJ_BUCKET_BRUSH_DIV));
- /* printf("\tscreenspace bucket division x:%d y:%d\n", ps->buckets_x, ps->buckets_y); */
+ /* printf("\tscreenspace bucket division x:%d y:%d\n", ps->buckets_x, ps->buckets_y); */
- if (ps->buckets_x > PROJ_BUCKET_RECT_MAX || ps->buckets_y > PROJ_BUCKET_RECT_MAX) {
- reset_threads = true;
- }
+ if (ps->buckets_x > PROJ_BUCKET_RECT_MAX || ps->buckets_y > PROJ_BUCKET_RECT_MAX) {
+ reset_threads = true;
+ }
- /* really high values could cause problems since it has to allocate a few
- * (ps->buckets_x*ps->buckets_y) sized arrays */
- CLAMP(ps->buckets_x, PROJ_BUCKET_RECT_MIN, PROJ_BUCKET_RECT_MAX);
- CLAMP(ps->buckets_y, PROJ_BUCKET_RECT_MIN, PROJ_BUCKET_RECT_MAX);
+ /* really high values could cause problems since it has to allocate a few
+ * (ps->buckets_x*ps->buckets_y) sized arrays */
+ CLAMP(ps->buckets_x, PROJ_BUCKET_RECT_MIN, PROJ_BUCKET_RECT_MAX);
+ CLAMP(ps->buckets_y, PROJ_BUCKET_RECT_MIN, PROJ_BUCKET_RECT_MAX);
- ps->bucketRect = MEM_callocN(sizeof(LinkNode *) * ps->buckets_x * ps->buckets_y, "paint-bucketRect");
- ps->bucketFaces = MEM_callocN(sizeof(LinkNode *) * ps->buckets_x * ps->buckets_y, "paint-bucketFaces");
+ ps->bucketRect = MEM_callocN(sizeof(LinkNode *) * ps->buckets_x * ps->buckets_y,
+ "paint-bucketRect");
+ ps->bucketFaces = MEM_callocN(sizeof(LinkNode *) * ps->buckets_x * ps->buckets_y,
+ "paint-bucketFaces");
- ps->bucketFlags = MEM_callocN(sizeof(char) * ps->buckets_x * ps->buckets_y, "paint-bucketFaces");
+ ps->bucketFlags = MEM_callocN(sizeof(char) * ps->buckets_x * ps->buckets_y, "paint-bucketFaces");
#ifndef PROJ_DEBUG_NOSEAMBLEED
- if (ps->is_shared_user == false) {
- proj_paint_state_seam_bleed_init(ps);
- }
+ if (ps->is_shared_user == false) {
+ proj_paint_state_seam_bleed_init(ps);
+ }
#endif
- proj_paint_state_thread_init(ps, reset_threads);
- arena = ps->arena_mt[0];
+ proj_paint_state_thread_init(ps, reset_threads);
+ arena = ps->arena_mt[0];
- proj_paint_state_vert_flags_init(ps);
+ proj_paint_state_vert_flags_init(ps);
- project_paint_prepare_all_faces(ps, arena, &face_lookup, &layer_clone, mloopuv_base, is_multi_view);
+ project_paint_prepare_all_faces(
+ ps, arena, &face_lookup, &layer_clone, mloopuv_base, is_multi_view);
}
static void paint_proj_begin_clone(ProjPaintState *ps, const float mouse[2])
{
- /* setup clone offset */
- if (ps->tool == PAINT_TOOL_CLONE) {
- float projCo[4];
- copy_v3_v3(projCo, ps->scene->cursor.location);
- mul_m4_v3(ps->obmat_imat, projCo);
-
- projCo[3] = 1.0f;
- mul_m4_v4(ps->projectMat, projCo);
- ps->cloneOffset[0] = mouse[0] - ((float)(ps->winx * 0.5f) + (ps->winx * 0.5f) * projCo[0] / projCo[3]);
- ps->cloneOffset[1] = mouse[1] - ((float)(ps->winy * 0.5f) + (ps->winy * 0.5f) * projCo[1] / projCo[3]);
- }
+ /* setup clone offset */
+ if (ps->tool == PAINT_TOOL_CLONE) {
+ float projCo[4];
+ copy_v3_v3(projCo, ps->scene->cursor.location);
+ mul_m4_v3(ps->obmat_imat, projCo);
+
+ projCo[3] = 1.0f;
+ mul_m4_v4(ps->projectMat, projCo);
+ ps->cloneOffset[0] = mouse[0] -
+ ((float)(ps->winx * 0.5f) + (ps->winx * 0.5f) * projCo[0] / projCo[3]);
+ ps->cloneOffset[1] = mouse[1] -
+ ((float)(ps->winy * 0.5f) + (ps->winy * 0.5f) * projCo[1] / projCo[3]);
+ }
}
static void project_paint_end(ProjPaintState *ps)
{
- int a;
-
- image_undo_remove_masks();
-
- /* dereference used image buffers */
- if (ps->is_shared_user == false) {
- ProjPaintImage *projIma;
- for (a = 0, projIma = ps->projImages; a < ps->image_tot; a++, projIma++) {
- BKE_image_release_ibuf(projIma->ima, projIma->ibuf, NULL);
- DEG_id_tag_update(&projIma->ima->id, 0);
- }
- }
-
- if (ps->reproject_ibuf_free_float) {
- imb_freerectfloatImBuf(ps->reproject_ibuf);
- }
- if (ps->reproject_ibuf_free_uchar) {
- imb_freerectImBuf(ps->reproject_ibuf);
- }
- BKE_image_release_ibuf(ps->reproject_image, ps->reproject_ibuf, NULL);
-
- MEM_freeN(ps->screenCoords);
- MEM_freeN(ps->bucketRect);
- MEM_freeN(ps->bucketFaces);
- MEM_freeN(ps->bucketFlags);
-
- if (ps->is_shared_user == false) {
- if (ps->mat_array != NULL) {
- MEM_freeN(ps->mat_array);
- }
-
- /* must be set for non-shared */
- BLI_assert(ps->poly_to_loop_uv || ps->is_shared_user);
- if (ps->poly_to_loop_uv)
- MEM_freeN((void *)ps->poly_to_loop_uv);
-
- if (ps->do_layer_clone)
- MEM_freeN((void *)ps->poly_to_loop_uv_clone);
- if (ps->thread_tot > 1) {
- BLI_spin_end(ps->tile_lock);
- MEM_freeN((void *)ps->tile_lock);
- }
-
- image_undo_end_locks();
+ int a;
+
+ image_undo_remove_masks();
+
+ /* dereference used image buffers */
+ if (ps->is_shared_user == false) {
+ ProjPaintImage *projIma;
+ for (a = 0, projIma = ps->projImages; a < ps->image_tot; a++, projIma++) {
+ BKE_image_release_ibuf(projIma->ima, projIma->ibuf, NULL);
+ DEG_id_tag_update(&projIma->ima->id, 0);
+ }
+ }
+
+ if (ps->reproject_ibuf_free_float) {
+ imb_freerectfloatImBuf(ps->reproject_ibuf);
+ }
+ if (ps->reproject_ibuf_free_uchar) {
+ imb_freerectImBuf(ps->reproject_ibuf);
+ }
+ BKE_image_release_ibuf(ps->reproject_image, ps->reproject_ibuf, NULL);
+
+ MEM_freeN(ps->screenCoords);
+ MEM_freeN(ps->bucketRect);
+ MEM_freeN(ps->bucketFaces);
+ MEM_freeN(ps->bucketFlags);
+
+ if (ps->is_shared_user == false) {
+ if (ps->mat_array != NULL) {
+ MEM_freeN(ps->mat_array);
+ }
+
+ /* must be set for non-shared */
+ BLI_assert(ps->poly_to_loop_uv || ps->is_shared_user);
+ if (ps->poly_to_loop_uv)
+ MEM_freeN((void *)ps->poly_to_loop_uv);
+
+ if (ps->do_layer_clone)
+ MEM_freeN((void *)ps->poly_to_loop_uv_clone);
+ if (ps->thread_tot > 1) {
+ BLI_spin_end(ps->tile_lock);
+ MEM_freeN((void *)ps->tile_lock);
+ }
+
+ image_undo_end_locks();
#ifndef PROJ_DEBUG_NOSEAMBLEED
- if (ps->seam_bleed_px > 0.0f) {
- MEM_freeN(ps->vertFaces);
- MEM_freeN(ps->faceSeamFlags);
- MEM_freeN(ps->faceWindingFlags);
- MEM_freeN(ps->loopSeamData);
- MEM_freeN(ps->vertSeams);
- }
+ if (ps->seam_bleed_px > 0.0f) {
+ MEM_freeN(ps->vertFaces);
+ MEM_freeN(ps->faceSeamFlags);
+ MEM_freeN(ps->faceWindingFlags);
+ MEM_freeN(ps->loopSeamData);
+ MEM_freeN(ps->vertSeams);
+ }
#endif
- if (ps->do_mask_cavity) {
- MEM_freeN(ps->cavities);
- }
+ if (ps->do_mask_cavity) {
+ MEM_freeN(ps->cavities);
+ }
- if (ps->me_eval_free) {
- BKE_id_free(NULL, ps->me_eval);
- }
- ps->me_eval = NULL;
- }
+ if (ps->me_eval_free) {
+ BKE_id_free(NULL, ps->me_eval);
+ }
+ ps->me_eval = NULL;
+ }
- if (ps->blurkernel) {
- paint_delete_blur_kernel(ps->blurkernel);
- MEM_freeN(ps->blurkernel);
- }
+ if (ps->blurkernel) {
+ paint_delete_blur_kernel(ps->blurkernel);
+ MEM_freeN(ps->blurkernel);
+ }
- if (ps->vertFlags) MEM_freeN(ps->vertFlags);
+ if (ps->vertFlags)
+ MEM_freeN(ps->vertFlags);
- for (a = 0; a < ps->thread_tot; a++) {
- BLI_memarena_free(ps->arena_mt[a]);
- }
+ for (a = 0; a < ps->thread_tot; a++) {
+ BLI_memarena_free(ps->arena_mt[a]);
+ }
}
/* 1 = an undo, -1 is a redo. */
static void partial_redraw_single_init(ImagePaintPartialRedraw *pr)
{
- pr->x1 = INT_MAX;
- pr->y1 = INT_MAX;
+ pr->x1 = INT_MAX;
+ pr->y1 = INT_MAX;
- pr->x2 = -1;
- pr->y2 = -1;
+ pr->x2 = -1;
+ pr->y2 = -1;
- pr->enabled = 1;
+ pr->enabled = 1;
}
static void partial_redraw_array_init(ImagePaintPartialRedraw *pr)
{
- int tot = PROJ_BOUNDBOX_SQUARED;
- while (tot--) {
- partial_redraw_single_init(pr);
- pr++;
- }
+ int tot = PROJ_BOUNDBOX_SQUARED;
+ while (tot--) {
+ partial_redraw_single_init(pr);
+ pr++;
+ }
}
-
-static bool partial_redraw_array_merge(ImagePaintPartialRedraw *pr, ImagePaintPartialRedraw *pr_other, int tot)
+static bool partial_redraw_array_merge(ImagePaintPartialRedraw *pr,
+ ImagePaintPartialRedraw *pr_other,
+ int tot)
{
- bool touch = 0;
- while (tot--) {
- pr->x1 = min_ii(pr->x1, pr_other->x1);
- pr->y1 = min_ii(pr->y1, pr_other->y1);
+ bool touch = 0;
+ while (tot--) {
+ pr->x1 = min_ii(pr->x1, pr_other->x1);
+ pr->y1 = min_ii(pr->y1, pr_other->y1);
- pr->x2 = max_ii(pr->x2, pr_other->x2);
- pr->y2 = max_ii(pr->y2, pr_other->y2);
+ pr->x2 = max_ii(pr->x2, pr_other->x2);
+ pr->y2 = max_ii(pr->y2, pr_other->y2);
- if (pr->x2 != -1)
- touch = 1;
+ if (pr->x2 != -1)
+ touch = 1;
- pr++; pr_other++;
- }
+ pr++;
+ pr_other++;
+ }
- return touch;
+ return touch;
}
/* Loop over all images on this mesh and update any we have touched */
static bool project_image_refresh_tagged(ProjPaintState *ps)
{
- ImagePaintPartialRedraw *pr;
- ProjPaintImage *projIma;
- int a, i;
- bool redraw = false;
-
-
- for (a = 0, projIma = ps->projImages; a < ps->image_tot; a++, projIma++) {
- if (projIma->touch) {
- /* look over each bound cell */
- for (i = 0; i < PROJ_BOUNDBOX_SQUARED; i++) {
- pr = &(projIma->partRedrawRect[i]);
- if (pr->x2 != -1) { /* TODO - use 'enabled' ? */
- set_imapaintpartial(pr);
- imapaint_image_update(NULL, projIma->ima, projIma->ibuf, true);
- redraw = 1;
- }
-
- partial_redraw_single_init(pr);
- }
-
- /* clear for reuse */
- projIma->touch = 0;
- }
- }
-
- return redraw;
+ ImagePaintPartialRedraw *pr;
+ ProjPaintImage *projIma;
+ int a, i;
+ bool redraw = false;
+
+ for (a = 0, projIma = ps->projImages; a < ps->image_tot; a++, projIma++) {
+ if (projIma->touch) {
+ /* look over each bound cell */
+ for (i = 0; i < PROJ_BOUNDBOX_SQUARED; i++) {
+ pr = &(projIma->partRedrawRect[i]);
+ if (pr->x2 != -1) { /* TODO - use 'enabled' ? */
+ set_imapaintpartial(pr);
+ imapaint_image_update(NULL, projIma->ima, projIma->ibuf, true);
+ redraw = 1;
+ }
+
+ partial_redraw_single_init(pr);
+ }
+
+ /* clear for reuse */
+ projIma->touch = 0;
+ }
+ }
+
+ return redraw;
}
/* run this per painting onto each mouse location */
static bool project_bucket_iter_init(ProjPaintState *ps, const float mval_f[2])
{
- if (ps->source == PROJ_SRC_VIEW) {
- float min_brush[2], max_brush[2];
- const float radius = ps->brush_size;
+ if (ps->source == PROJ_SRC_VIEW) {
+ float min_brush[2], max_brush[2];
+ const float radius = ps->brush_size;
- /* so we don't have a bucket bounds that is way too small to paint into */
- // if (radius < 1.0f) radius = 1.0f; // this doesn't work yet :/
+ /* so we don't have a bucket bounds that is way too small to paint into */
+ // if (radius < 1.0f) radius = 1.0f; // this doesn't work yet :/
- min_brush[0] = mval_f[0] - radius;
- min_brush[1] = mval_f[1] - radius;
+ min_brush[0] = mval_f[0] - radius;
+ min_brush[1] = mval_f[1] - radius;
- max_brush[0] = mval_f[0] + radius;
- max_brush[1] = mval_f[1] + radius;
+ max_brush[0] = mval_f[0] + radius;
+ max_brush[1] = mval_f[1] + radius;
- /* offset to make this a valid bucket index */
- project_paint_bucket_bounds(ps, min_brush, max_brush, ps->bucketMin, ps->bucketMax);
+ /* offset to make this a valid bucket index */
+ project_paint_bucket_bounds(ps, min_brush, max_brush, ps->bucketMin, ps->bucketMax);
- /* mouse outside the model areas? */
- if (ps->bucketMin[0] == ps->bucketMax[0] || ps->bucketMin[1] == ps->bucketMax[1]) {
- return 0;
- }
+ /* mouse outside the model areas? */
+ if (ps->bucketMin[0] == ps->bucketMax[0] || ps->bucketMin[1] == ps->bucketMax[1]) {
+ return 0;
+ }
- ps->context_bucket_x = ps->bucketMin[0];
- ps->context_bucket_y = ps->bucketMin[1];
- }
- else { /* reproject: PROJ_SRC_* */
- ps->bucketMin[0] = 0;
- ps->bucketMin[1] = 0;
+ ps->context_bucket_x = ps->bucketMin[0];
+ ps->context_bucket_y = ps->bucketMin[1];
+ }
+ else { /* reproject: PROJ_SRC_* */
+ ps->bucketMin[0] = 0;
+ ps->bucketMin[1] = 0;
- ps->bucketMax[0] = ps->buckets_x;
- ps->bucketMax[1] = ps->buckets_y;
+ ps->bucketMax[0] = ps->buckets_x;
+ ps->bucketMax[1] = ps->buckets_y;
- ps->context_bucket_x = 0;
- ps->context_bucket_y = 0;
- }
- return 1;
+ ps->context_bucket_x = 0;
+ ps->context_bucket_y = 0;
+ }
+ return 1;
}
-
-static bool project_bucket_iter_next(
- ProjPaintState *ps, int *bucket_index,
- rctf *bucket_bounds, const float mval[2])
+static bool project_bucket_iter_next(ProjPaintState *ps,
+ int *bucket_index,
+ rctf *bucket_bounds,
+ const float mval[2])
{
- const int diameter = 2 * ps->brush_size;
+ const int diameter = 2 * ps->brush_size;
- if (ps->thread_tot > 1)
- BLI_thread_lock(LOCK_CUSTOM1);
+ if (ps->thread_tot > 1)
+ BLI_thread_lock(LOCK_CUSTOM1);
- //printf("%d %d\n", ps->context_bucket_x, ps->context_bucket_y);
+ //printf("%d %d\n", ps->context_bucket_x, ps->context_bucket_y);
- for (; ps->context_bucket_y < ps->bucketMax[1]; ps->context_bucket_y++) {
- for (; ps->context_bucket_x < ps->bucketMax[0]; ps->context_bucket_x++) {
+ for (; ps->context_bucket_y < ps->bucketMax[1]; ps->context_bucket_y++) {
+ for (; ps->context_bucket_x < ps->bucketMax[0]; ps->context_bucket_x++) {
- /* use bucket_bounds for project_bucket_isect_circle and project_bucket_init*/
- project_bucket_bounds(ps, ps->context_bucket_x, ps->context_bucket_y, bucket_bounds);
+ /* use bucket_bounds for project_bucket_isect_circle and project_bucket_init*/
+ project_bucket_bounds(ps, ps->context_bucket_x, ps->context_bucket_y, bucket_bounds);
- if ((ps->source != PROJ_SRC_VIEW) ||
- project_bucket_isect_circle(mval, (float)(diameter * diameter), bucket_bounds))
- {
- *bucket_index = ps->context_bucket_x + (ps->context_bucket_y * ps->buckets_x);
- ps->context_bucket_x++;
+ if ((ps->source != PROJ_SRC_VIEW) ||
+ project_bucket_isect_circle(mval, (float)(diameter * diameter), bucket_bounds)) {
+ *bucket_index = ps->context_bucket_x + (ps->context_bucket_y * ps->buckets_x);
+ ps->context_bucket_x++;
- if (ps->thread_tot > 1)
- BLI_thread_unlock(LOCK_CUSTOM1);
+ if (ps->thread_tot > 1)
+ BLI_thread_unlock(LOCK_CUSTOM1);
- return 1;
- }
- }
- ps->context_bucket_x = ps->bucketMin[0];
- }
+ return 1;
+ }
+ }
+ ps->context_bucket_x = ps->bucketMin[0];
+ }
- if (ps->thread_tot > 1)
- BLI_thread_unlock(LOCK_CUSTOM1);
- return 0;
+ if (ps->thread_tot > 1)
+ BLI_thread_unlock(LOCK_CUSTOM1);
+ return 0;
}
/* Each thread gets one of these, also used as an argument to pass to project_paint_op */
typedef struct ProjectHandle {
- /* args */
- ProjPaintState *ps;
- float prevmval[2];
- float mval[2];
+ /* args */
+ ProjPaintState *ps;
+ float prevmval[2];
+ float mval[2];
- /* Annoying but we need to have image bounds per thread,
- * then merge into ps->projectPartialRedraws. */
+ /* Annoying but we need to have image bounds per thread,
+ * then merge into ps->projectPartialRedraws. */
- /* array of partial redraws */
- ProjPaintImage *projImages;
+ /* array of partial redraws */
+ ProjPaintImage *projImages;
- /* thread settings */
- int thread_index;
+ /* thread settings */
+ int thread_index;
- struct ImagePool *pool;
+ struct ImagePool *pool;
} ProjectHandle;
static void do_projectpaint_clone(ProjPaintState *ps, ProjPixel *projPixel, float mask)
{
- const unsigned char *clone_pt = ((ProjPixelClone *)projPixel)->clonepx.ch;
-
- if (clone_pt[3]) {
- unsigned char clone_rgba[4];
-
- clone_rgba[0] = clone_pt[0];
- clone_rgba[1] = clone_pt[1];
- clone_rgba[2] = clone_pt[2];
- clone_rgba[3] = (unsigned char)(clone_pt[3] * mask);
-
- if (ps->do_masking) {
- IMB_blend_color_byte(projPixel->pixel.ch_pt, projPixel->origColor.ch_pt, clone_rgba, ps->blend);
- }
- else {
- IMB_blend_color_byte(projPixel->pixel.ch_pt, projPixel->pixel.ch_pt, clone_rgba, ps->blend);
- }
- }
+ const unsigned char *clone_pt = ((ProjPixelClone *)projPixel)->clonepx.ch;
+
+ if (clone_pt[3]) {
+ unsigned char clone_rgba[4];
+
+ clone_rgba[0] = clone_pt[0];
+ clone_rgba[1] = clone_pt[1];
+ clone_rgba[2] = clone_pt[2];
+ clone_rgba[3] = (unsigned char)(clone_pt[3] * mask);
+
+ if (ps->do_masking) {
+ IMB_blend_color_byte(
+ projPixel->pixel.ch_pt, projPixel->origColor.ch_pt, clone_rgba, ps->blend);
+ }
+ else {
+ IMB_blend_color_byte(projPixel->pixel.ch_pt, projPixel->pixel.ch_pt, clone_rgba, ps->blend);
+ }
+ }
}
static void do_projectpaint_clone_f(ProjPaintState *ps, ProjPixel *projPixel, float mask)
{
- const float *clone_pt = ((ProjPixelClone *)projPixel)->clonepx.f;
+ const float *clone_pt = ((ProjPixelClone *)projPixel)->clonepx.f;
- if (clone_pt[3]) {
- float clone_rgba[4];
+ if (clone_pt[3]) {
+ float clone_rgba[4];
- mul_v4_v4fl(clone_rgba, clone_pt, mask);
+ mul_v4_v4fl(clone_rgba, clone_pt, mask);
- if (ps->do_masking) {
- IMB_blend_color_float(projPixel->pixel.f_pt, projPixel->origColor.f_pt, clone_rgba, ps->blend);
- }
- else {
- IMB_blend_color_float(projPixel->pixel.f_pt, projPixel->pixel.f_pt, clone_rgba, ps->blend);
- }
- }
+ if (ps->do_masking) {
+ IMB_blend_color_float(
+ projPixel->pixel.f_pt, projPixel->origColor.f_pt, clone_rgba, ps->blend);
+ }
+ else {
+ IMB_blend_color_float(projPixel->pixel.f_pt, projPixel->pixel.f_pt, clone_rgba, ps->blend);
+ }
+ }
}
/**
@@ -4609,1342 +4760,1396 @@ static void do_projectpaint_clone_f(ProjPaintState *ps, ProjPixel *projPixel, fl
* accumulation of color greater than 'projPixel->mask' however in the case of smear its not
* really that important to be correct as it is with clone and painting
*/
-static void do_projectpaint_smear(
- ProjPaintState *ps, ProjPixel *projPixel, float mask,
- MemArena *smearArena, LinkNode **smearPixels, const float co[2])
+static void do_projectpaint_smear(ProjPaintState *ps,
+ ProjPixel *projPixel,
+ float mask,
+ MemArena *smearArena,
+ LinkNode **smearPixels,
+ const float co[2])
{
- unsigned char rgba_ub[4];
+ unsigned char rgba_ub[4];
- if (project_paint_PickColor(ps, co, NULL, rgba_ub, 1) == 0)
- return;
+ if (project_paint_PickColor(ps, co, NULL, rgba_ub, 1) == 0)
+ return;
- blend_color_interpolate_byte(((ProjPixelClone *)projPixel)->clonepx.ch, projPixel->pixel.ch_pt, rgba_ub, mask);
- BLI_linklist_prepend_arena(smearPixels, (void *)projPixel, smearArena);
+ blend_color_interpolate_byte(
+ ((ProjPixelClone *)projPixel)->clonepx.ch, projPixel->pixel.ch_pt, rgba_ub, mask);
+ BLI_linklist_prepend_arena(smearPixels, (void *)projPixel, smearArena);
}
-static void do_projectpaint_smear_f(
- ProjPaintState *ps, ProjPixel *projPixel, float mask,
- MemArena *smearArena, LinkNode **smearPixels_f, const float co[2])
+static void do_projectpaint_smear_f(ProjPaintState *ps,
+ ProjPixel *projPixel,
+ float mask,
+ MemArena *smearArena,
+ LinkNode **smearPixels_f,
+ const float co[2])
{
- float rgba[4];
+ float rgba[4];
- if (project_paint_PickColor(ps, co, rgba, NULL, 1) == 0)
- return;
+ if (project_paint_PickColor(ps, co, rgba, NULL, 1) == 0)
+ return;
- blend_color_interpolate_float(((ProjPixelClone *)projPixel)->clonepx.f, projPixel->pixel.f_pt, rgba, mask);
- BLI_linklist_prepend_arena(smearPixels_f, (void *)projPixel, smearArena);
+ blend_color_interpolate_float(
+ ((ProjPixelClone *)projPixel)->clonepx.f, projPixel->pixel.f_pt, rgba, mask);
+ BLI_linklist_prepend_arena(smearPixels_f, (void *)projPixel, smearArena);
}
-static void do_projectpaint_soften_f(
- ProjPaintState *ps, ProjPixel *projPixel, float mask,
- MemArena *softenArena, LinkNode **softenPixels)
+static void do_projectpaint_soften_f(ProjPaintState *ps,
+ ProjPixel *projPixel,
+ float mask,
+ MemArena *softenArena,
+ LinkNode **softenPixels)
{
- float accum_tot = 0.0f;
- int xk, yk;
- BlurKernel *kernel = ps->blurkernel;
- float *rgba = projPixel->newColor.f;
-
- /* rather then painting, accumulate surrounding colors */
- zero_v4(rgba);
-
- for (yk = 0; yk < kernel->side; yk++) {
- for (xk = 0; xk < kernel->side; xk++) {
- float rgba_tmp[4];
- float co_ofs[2] = {2.0f * xk - 1.0f, 2.0f * yk - 1.0f};
-
- add_v2_v2(co_ofs, projPixel->projCoSS);
-
- if (project_paint_PickColor(ps, co_ofs, rgba_tmp, NULL, true)) {
- float weight = kernel->wdata[xk + yk * kernel->side];
- mul_v4_fl(rgba_tmp, weight);
- add_v4_v4(rgba, rgba_tmp);
- accum_tot += weight;
- }
- }
- }
-
- if (LIKELY(accum_tot != 0)) {
- mul_v4_fl(rgba, 1.0f / (float)accum_tot);
-
- if (ps->mode == BRUSH_STROKE_INVERT) {
- /* subtract blurred image from normal image gives high pass filter */
- sub_v3_v3v3(rgba, projPixel->pixel.f_pt, rgba);
-
- /* now rgba_ub contains the edge result, but this should be converted to luminance to avoid
- * colored speckles appearing in final image, and also to check for threshold */
- rgba[0] = rgba[1] = rgba[2] = IMB_colormanagement_get_luminance(rgba);
- if (fabsf(rgba[0]) > ps->brush->sharp_threshold) {
- float alpha = projPixel->pixel.f_pt[3];
- projPixel->pixel.f_pt[3] = rgba[3] = mask;
-
- /* add to enhance edges */
- blend_color_add_float(rgba, projPixel->pixel.f_pt, rgba);
- rgba[3] = alpha;
- }
- else
- return;
- }
- else {
- blend_color_interpolate_float(rgba, projPixel->pixel.f_pt, rgba, mask);
- }
-
- BLI_linklist_prepend_arena(softenPixels, (void *)projPixel, softenArena);
- }
+ float accum_tot = 0.0f;
+ int xk, yk;
+ BlurKernel *kernel = ps->blurkernel;
+ float *rgba = projPixel->newColor.f;
+
+ /* rather then painting, accumulate surrounding colors */
+ zero_v4(rgba);
+
+ for (yk = 0; yk < kernel->side; yk++) {
+ for (xk = 0; xk < kernel->side; xk++) {
+ float rgba_tmp[4];
+ float co_ofs[2] = {2.0f * xk - 1.0f, 2.0f * yk - 1.0f};
+
+ add_v2_v2(co_ofs, projPixel->projCoSS);
+
+ if (project_paint_PickColor(ps, co_ofs, rgba_tmp, NULL, true)) {
+ float weight = kernel->wdata[xk + yk * kernel->side];
+ mul_v4_fl(rgba_tmp, weight);
+ add_v4_v4(rgba, rgba_tmp);
+ accum_tot += weight;
+ }
+ }
+ }
+
+ if (LIKELY(accum_tot != 0)) {
+ mul_v4_fl(rgba, 1.0f / (float)accum_tot);
+
+ if (ps->mode == BRUSH_STROKE_INVERT) {
+ /* subtract blurred image from normal image gives high pass filter */
+ sub_v3_v3v3(rgba, projPixel->pixel.f_pt, rgba);
+
+ /* now rgba_ub contains the edge result, but this should be converted to luminance to avoid
+ * colored speckles appearing in final image, and also to check for threshold */
+ rgba[0] = rgba[1] = rgba[2] = IMB_colormanagement_get_luminance(rgba);
+ if (fabsf(rgba[0]) > ps->brush->sharp_threshold) {
+ float alpha = projPixel->pixel.f_pt[3];
+ projPixel->pixel.f_pt[3] = rgba[3] = mask;
+
+ /* add to enhance edges */
+ blend_color_add_float(rgba, projPixel->pixel.f_pt, rgba);
+ rgba[3] = alpha;
+ }
+ else
+ return;
+ }
+ else {
+ blend_color_interpolate_float(rgba, projPixel->pixel.f_pt, rgba, mask);
+ }
+
+ BLI_linklist_prepend_arena(softenPixels, (void *)projPixel, softenArena);
+ }
}
-static void do_projectpaint_soften(
- ProjPaintState *ps, ProjPixel *projPixel, float mask,
- MemArena *softenArena, LinkNode **softenPixels)
+static void do_projectpaint_soften(ProjPaintState *ps,
+ ProjPixel *projPixel,
+ float mask,
+ MemArena *softenArena,
+ LinkNode **softenPixels)
{
- float accum_tot = 0;
- int xk, yk;
- BlurKernel *kernel = ps->blurkernel;
- /* convert to byte after */
- float rgba[4];
-
- /* rather then painting, accumulate surrounding colors */
- zero_v4(rgba);
-
- for (yk = 0; yk < kernel->side; yk++) {
- for (xk = 0; xk < kernel->side; xk++) {
- float rgba_tmp[4];
- float co_ofs[2] = {2.0f * xk - 1.0f, 2.0f * yk - 1.0f};
-
- add_v2_v2(co_ofs, projPixel->projCoSS);
-
- if (project_paint_PickColor(ps, co_ofs, rgba_tmp, NULL, true)) {
- float weight = kernel->wdata[xk + yk * kernel->side];
- mul_v4_fl(rgba_tmp, weight);
- add_v4_v4(rgba, rgba_tmp);
- accum_tot += weight;
- }
- }
- }
-
- if (LIKELY(accum_tot != 0)) {
- unsigned char *rgba_ub = projPixel->newColor.ch;
-
- mul_v4_fl(rgba, 1.0f / (float)accum_tot);
-
- if (ps->mode == BRUSH_STROKE_INVERT) {
- float rgba_pixel[4];
-
- straight_uchar_to_premul_float(rgba_pixel, projPixel->pixel.ch_pt);
-
- /* subtract blurred image from normal image gives high pass filter */
- sub_v3_v3v3(rgba, rgba_pixel, rgba);
- /* now rgba_ub contains the edge result, but this should be converted to luminance to avoid
- * colored speckles appearing in final image, and also to check for threshold */
- rgba[0] = rgba[1] = rgba[2] = IMB_colormanagement_get_luminance(rgba);
- if (fabsf(rgba[0]) > ps->brush->sharp_threshold) {
- float alpha = rgba_pixel[3];
- rgba[3] = rgba_pixel[3] = mask;
-
- /* add to enhance edges */
- blend_color_add_float(rgba, rgba_pixel, rgba);
-
- rgba[3] = alpha;
- premul_float_to_straight_uchar(rgba_ub, rgba);
- }
- else
- return;
- }
- else {
- premul_float_to_straight_uchar(rgba_ub, rgba);
- blend_color_interpolate_byte(rgba_ub, projPixel->pixel.ch_pt, rgba_ub, mask);
- }
- BLI_linklist_prepend_arena(softenPixels, (void *)projPixel, softenArena);
- }
+ float accum_tot = 0;
+ int xk, yk;
+ BlurKernel *kernel = ps->blurkernel;
+ /* convert to byte after */
+ float rgba[4];
+
+ /* rather then painting, accumulate surrounding colors */
+ zero_v4(rgba);
+
+ for (yk = 0; yk < kernel->side; yk++) {
+ for (xk = 0; xk < kernel->side; xk++) {
+ float rgba_tmp[4];
+ float co_ofs[2] = {2.0f * xk - 1.0f, 2.0f * yk - 1.0f};
+
+ add_v2_v2(co_ofs, projPixel->projCoSS);
+
+ if (project_paint_PickColor(ps, co_ofs, rgba_tmp, NULL, true)) {
+ float weight = kernel->wdata[xk + yk * kernel->side];
+ mul_v4_fl(rgba_tmp, weight);
+ add_v4_v4(rgba, rgba_tmp);
+ accum_tot += weight;
+ }
+ }
+ }
+
+ if (LIKELY(accum_tot != 0)) {
+ unsigned char *rgba_ub = projPixel->newColor.ch;
+
+ mul_v4_fl(rgba, 1.0f / (float)accum_tot);
+
+ if (ps->mode == BRUSH_STROKE_INVERT) {
+ float rgba_pixel[4];
+
+ straight_uchar_to_premul_float(rgba_pixel, projPixel->pixel.ch_pt);
+
+ /* subtract blurred image from normal image gives high pass filter */
+ sub_v3_v3v3(rgba, rgba_pixel, rgba);
+ /* now rgba_ub contains the edge result, but this should be converted to luminance to avoid
+ * colored speckles appearing in final image, and also to check for threshold */
+ rgba[0] = rgba[1] = rgba[2] = IMB_colormanagement_get_luminance(rgba);
+ if (fabsf(rgba[0]) > ps->brush->sharp_threshold) {
+ float alpha = rgba_pixel[3];
+ rgba[3] = rgba_pixel[3] = mask;
+
+ /* add to enhance edges */
+ blend_color_add_float(rgba, rgba_pixel, rgba);
+
+ rgba[3] = alpha;
+ premul_float_to_straight_uchar(rgba_ub, rgba);
+ }
+ else
+ return;
+ }
+ else {
+ premul_float_to_straight_uchar(rgba_ub, rgba);
+ blend_color_interpolate_byte(rgba_ub, projPixel->pixel.ch_pt, rgba_ub, mask);
+ }
+ BLI_linklist_prepend_arena(softenPixels, (void *)projPixel, softenArena);
+ }
}
-static void do_projectpaint_draw(
- ProjPaintState *ps, ProjPixel *projPixel, const float texrgb[3], float mask,
- float dither, float u, float v)
+static void do_projectpaint_draw(ProjPaintState *ps,
+ ProjPixel *projPixel,
+ const float texrgb[3],
+ float mask,
+ float dither,
+ float u,
+ float v)
{
- float rgb[3];
- unsigned char rgba_ub[4];
-
- if (ps->is_texbrush) {
- mul_v3_v3v3(rgb, texrgb, ps->paint_color_linear);
- /* TODO(sergey): Support texture paint color space. */
- if (ps->use_colormanagement) {
- linearrgb_to_srgb_v3_v3(rgb, rgb);
- }
- else {
- copy_v3_v3(rgb, rgb);
- }
- }
- else {
- copy_v3_v3(rgb, ps->paint_color);
- }
-
- if (dither > 0.0f) {
- float_to_byte_dither_v3(rgba_ub, rgb, dither, u, v);
- }
- else {
- unit_float_to_uchar_clamp_v3(rgba_ub, rgb);
- }
- rgba_ub[3] = f_to_char(mask);
-
- if (ps->do_masking) {
- IMB_blend_color_byte(projPixel->pixel.ch_pt, projPixel->origColor.ch_pt, rgba_ub, ps->blend);
- }
- else {
- IMB_blend_color_byte(projPixel->pixel.ch_pt, projPixel->pixel.ch_pt, rgba_ub, ps->blend);
- }
+ float rgb[3];
+ unsigned char rgba_ub[4];
+
+ if (ps->is_texbrush) {
+ mul_v3_v3v3(rgb, texrgb, ps->paint_color_linear);
+ /* TODO(sergey): Support texture paint color space. */
+ if (ps->use_colormanagement) {
+ linearrgb_to_srgb_v3_v3(rgb, rgb);
+ }
+ else {
+ copy_v3_v3(rgb, rgb);
+ }
+ }
+ else {
+ copy_v3_v3(rgb, ps->paint_color);
+ }
+
+ if (dither > 0.0f) {
+ float_to_byte_dither_v3(rgba_ub, rgb, dither, u, v);
+ }
+ else {
+ unit_float_to_uchar_clamp_v3(rgba_ub, rgb);
+ }
+ rgba_ub[3] = f_to_char(mask);
+
+ if (ps->do_masking) {
+ IMB_blend_color_byte(projPixel->pixel.ch_pt, projPixel->origColor.ch_pt, rgba_ub, ps->blend);
+ }
+ else {
+ IMB_blend_color_byte(projPixel->pixel.ch_pt, projPixel->pixel.ch_pt, rgba_ub, ps->blend);
+ }
}
-static void do_projectpaint_draw_f(ProjPaintState *ps, ProjPixel *projPixel, const float texrgb[3], float mask)
+static void do_projectpaint_draw_f(ProjPaintState *ps,
+ ProjPixel *projPixel,
+ const float texrgb[3],
+ float mask)
{
- float rgba[4];
+ float rgba[4];
- copy_v3_v3(rgba, ps->paint_color_linear);
+ copy_v3_v3(rgba, ps->paint_color_linear);
- if (ps->is_texbrush)
- mul_v3_v3(rgba, texrgb);
+ if (ps->is_texbrush)
+ mul_v3_v3(rgba, texrgb);
- mul_v3_fl(rgba, mask);
- rgba[3] = mask;
+ mul_v3_fl(rgba, mask);
+ rgba[3] = mask;
- if (ps->do_masking) {
- IMB_blend_color_float(projPixel->pixel.f_pt, projPixel->origColor.f_pt, rgba, ps->blend);
- }
- else {
- IMB_blend_color_float(projPixel->pixel.f_pt, projPixel->pixel.f_pt, rgba, ps->blend);
- }
+ if (ps->do_masking) {
+ IMB_blend_color_float(projPixel->pixel.f_pt, projPixel->origColor.f_pt, rgba, ps->blend);
+ }
+ else {
+ IMB_blend_color_float(projPixel->pixel.f_pt, projPixel->pixel.f_pt, rgba, ps->blend);
+ }
}
static void do_projectpaint_mask(ProjPaintState *ps, ProjPixel *projPixel, float mask)
{
- unsigned char rgba_ub[4];
- rgba_ub[0] = rgba_ub[1] = rgba_ub[2] = ps->stencil_value * 255.0f;
- rgba_ub[3] = f_to_char(mask);
-
- if (ps->do_masking) {
- IMB_blend_color_byte(projPixel->pixel.ch_pt, projPixel->origColor.ch_pt, rgba_ub, ps->blend);
- }
- else {
- IMB_blend_color_byte(projPixel->pixel.ch_pt, projPixel->pixel.ch_pt, rgba_ub, ps->blend);
- }
+ unsigned char rgba_ub[4];
+ rgba_ub[0] = rgba_ub[1] = rgba_ub[2] = ps->stencil_value * 255.0f;
+ rgba_ub[3] = f_to_char(mask);
+
+ if (ps->do_masking) {
+ IMB_blend_color_byte(projPixel->pixel.ch_pt, projPixel->origColor.ch_pt, rgba_ub, ps->blend);
+ }
+ else {
+ IMB_blend_color_byte(projPixel->pixel.ch_pt, projPixel->pixel.ch_pt, rgba_ub, ps->blend);
+ }
}
static void do_projectpaint_mask_f(ProjPaintState *ps, ProjPixel *projPixel, float mask)
{
- float rgba[4];
- rgba[0] = rgba[1] = rgba[2] = ps->stencil_value;
- rgba[3] = mask;
-
- if (ps->do_masking) {
- IMB_blend_color_float(projPixel->pixel.f_pt, projPixel->origColor.f_pt, rgba, ps->blend);
- }
- else {
- IMB_blend_color_float(projPixel->pixel.f_pt, projPixel->pixel.f_pt, rgba, ps->blend);
- }
+ float rgba[4];
+ rgba[0] = rgba[1] = rgba[2] = ps->stencil_value;
+ rgba[3] = mask;
+
+ if (ps->do_masking) {
+ IMB_blend_color_float(projPixel->pixel.f_pt, projPixel->origColor.f_pt, rgba, ps->blend);
+ }
+ else {
+ IMB_blend_color_float(projPixel->pixel.f_pt, projPixel->pixel.f_pt, rgba, ps->blend);
+ }
}
-static void image_paint_partial_redraw_expand(
- ImagePaintPartialRedraw *cell,
- const ProjPixel *projPixel)
+static void image_paint_partial_redraw_expand(ImagePaintPartialRedraw *cell,
+ const ProjPixel *projPixel)
{
- cell->x1 = min_ii(cell->x1, (int)projPixel->x_px);
- cell->y1 = min_ii(cell->y1, (int)projPixel->y_px);
+ cell->x1 = min_ii(cell->x1, (int)projPixel->x_px);
+ cell->y1 = min_ii(cell->y1, (int)projPixel->y_px);
- cell->x2 = max_ii(cell->x2, (int)projPixel->x_px + 1);
- cell->y2 = max_ii(cell->y2, (int)projPixel->y_px + 1);
+ cell->x2 = max_ii(cell->x2, (int)projPixel->x_px + 1);
+ cell->y2 = max_ii(cell->y2, (int)projPixel->y_px + 1);
}
/* run this for single and multithreaded painting */
static void *do_projectpaint_thread(void *ph_v)
{
- /* First unpack args from the struct */
- ProjPaintState *ps = ((ProjectHandle *)ph_v)->ps;
- ProjPaintImage *projImages = ((ProjectHandle *)ph_v)->projImages;
- const float *lastpos = ((ProjectHandle *)ph_v)->prevmval;
- const float *pos = ((ProjectHandle *)ph_v)->mval;
- const int thread_index = ((ProjectHandle *)ph_v)->thread_index;
- struct ImagePool *pool = ((ProjectHandle *)ph_v)->pool;
- /* Done with args from ProjectHandle */
-
- LinkNode *node;
- ProjPixel *projPixel;
- Brush *brush = ps->brush;
-
- int last_index = -1;
- ProjPaintImage *last_projIma = NULL;
- ImagePaintPartialRedraw *last_partial_redraw_cell;
-
- float dist_sq, dist;
-
- float falloff;
- int bucket_index;
- bool is_floatbuf = false;
- const short tool = ps->tool;
- rctf bucket_bounds;
-
- /* for smear only */
- float pos_ofs[2] = {0};
- float co[2];
- unsigned short mask_short;
- const float brush_alpha = BKE_brush_alpha_get(ps->scene, brush);
- const float brush_radius = ps->brush_size;
- /* avoid a square root with every dist comparison */
- const float brush_radius_sq = brush_radius * brush_radius;
-
- const bool lock_alpha = ELEM(brush->blend, IMB_BLEND_ERASE_ALPHA, IMB_BLEND_ADD_ALPHA) ?
- 0 : (brush->flag & BRUSH_LOCK_ALPHA) != 0;
-
- LinkNode *smearPixels = NULL;
- LinkNode *smearPixels_f = NULL;
- /* mem arena for this brush projection only */
- MemArena *smearArena = NULL;
-
- LinkNode *softenPixels = NULL;
- LinkNode *softenPixels_f = NULL;
- /* mem arena for this brush projection only */
- MemArena *softenArena = NULL;
-
- if (tool == PAINT_TOOL_SMEAR) {
- pos_ofs[0] = pos[0] - lastpos[0];
- pos_ofs[1] = pos[1] - lastpos[1];
-
- smearArena = BLI_memarena_new(MEM_SIZE_OPTIMAL(1 << 16), "paint smear arena");
- }
- else if (tool == PAINT_TOOL_SOFTEN) {
- softenArena = BLI_memarena_new(MEM_SIZE_OPTIMAL(1 << 16), "paint soften arena");
- }
-
- /* printf("brush bounds %d %d %d %d\n",
- * bucketMin[0], bucketMin[1], bucketMax[0], bucketMax[1]); */
-
- while (project_bucket_iter_next(ps, &bucket_index, &bucket_bounds, pos)) {
-
- /* Check this bucket and its faces are initialized */
- if (ps->bucketFlags[bucket_index] == PROJ_BUCKET_NULL) {
- rctf clip_rect = bucket_bounds;
- clip_rect.xmin -= PROJ_PIXEL_TOLERANCE;
- clip_rect.xmax += PROJ_PIXEL_TOLERANCE;
- clip_rect.ymin -= PROJ_PIXEL_TOLERANCE;
- clip_rect.ymax += PROJ_PIXEL_TOLERANCE;
- /* No pixels initialized */
- project_bucket_init(ps, thread_index, bucket_index, &clip_rect, &bucket_bounds);
- }
-
- if (ps->source != PROJ_SRC_VIEW) {
-
- /* Re-Projection, simple, no brushes! */
-
- for (node = ps->bucketRect[bucket_index]; node; node = node->next) {
- projPixel = (ProjPixel *)node->link;
-
- /* copy of code below */
- if (last_index != projPixel->image_index) {
- last_index = projPixel->image_index;
- last_projIma = projImages + last_index;
-
- last_projIma->touch = 1;
- is_floatbuf = (last_projIma->ibuf->rect_float != NULL);
- }
- /* end copy */
-
- /* fill tools */
- if (ps->source == PROJ_SRC_VIEW_FILL) {
- if (brush->flag & BRUSH_USE_GRADIENT) {
- /* these could probably be cached instead of being done per pixel */
- float tangent[2];
- float line_len_sq_inv, line_len;
- float f;
- float color_f[4];
- float p[2] = {projPixel->projCoSS[0] - lastpos[0], projPixel->projCoSS[1] - lastpos[1]};
-
- sub_v2_v2v2(tangent, pos, lastpos);
- line_len = len_squared_v2(tangent);
- line_len_sq_inv = 1.0f / line_len;
- line_len = sqrtf(line_len);
-
- switch (brush->gradient_fill_mode) {
- case BRUSH_GRADIENT_LINEAR:
- {
- f = dot_v2v2(p, tangent) * line_len_sq_inv;
- break;
- }
- case BRUSH_GRADIENT_RADIAL:
- default:
- {
- f = len_v2(p) / line_len;
- break;
- }
- }
- BKE_colorband_evaluate(brush->gradient, f, color_f);
- color_f[3] *= ((float)projPixel->mask) * (1.0f / 65535.0f) * brush->alpha;
-
- if (is_floatbuf) {
- /* convert to premultipied */
- mul_v3_fl(color_f, color_f[3]);
- IMB_blend_color_float(
- projPixel->pixel.f_pt, projPixel->origColor.f_pt,
- color_f, ps->blend);
- }
- else {
- linearrgb_to_srgb_v3_v3(color_f, color_f);
-
- if (ps->dither > 0.0f) {
- float_to_byte_dither_v3(projPixel->newColor.ch, color_f, ps->dither, projPixel->x_px, projPixel->y_px);
- }
- else {
- unit_float_to_uchar_clamp_v3(projPixel->newColor.ch, color_f);
- }
- projPixel->newColor.ch[3] = unit_float_to_uchar_clamp(color_f[3]);
- IMB_blend_color_byte(
- projPixel->pixel.ch_pt, projPixel->origColor.ch_pt,
- projPixel->newColor.ch, ps->blend);
- }
- }
- else {
- if (is_floatbuf) {
- float newColor_f[4];
- newColor_f[3] = ((float)projPixel->mask) * (1.0f / 65535.0f) * brush->alpha;
- copy_v3_v3(newColor_f, ps->paint_color_linear);
-
- IMB_blend_color_float(
- projPixel->pixel.f_pt, projPixel->origColor.f_pt,
- newColor_f, ps->blend);
- }
- else {
- float mask = ((float)projPixel->mask) * (1.0f / 65535.0f);
- projPixel->newColor.ch[3] = mask * 255 * brush->alpha;
-
- rgb_float_to_uchar(projPixel->newColor.ch, ps->paint_color);
- IMB_blend_color_byte(
- projPixel->pixel.ch_pt, projPixel->origColor.ch_pt,
- projPixel->newColor.ch, ps->blend);
- }
- }
-
- if (lock_alpha) {
- if (is_floatbuf) {
- /* slightly more involved case since floats are in premultiplied space we need
- * to make sure alpha is consistent, see T44627 */
- float rgb_straight[4];
- premul_to_straight_v4_v4(rgb_straight, projPixel->pixel.f_pt);
- rgb_straight[3] = projPixel->origColor.f_pt[3];
- straight_to_premul_v4_v4(projPixel->pixel.f_pt, rgb_straight);
- }
- else {
- projPixel->pixel.ch_pt[3] = projPixel->origColor.ch_pt[3];
- }
- }
-
- last_partial_redraw_cell = last_projIma->partRedrawRect + projPixel->bb_cell_index;
- image_paint_partial_redraw_expand(last_partial_redraw_cell, projPixel);
- }
- else {
- if (is_floatbuf) {
- if (UNLIKELY(ps->reproject_ibuf->rect_float == NULL)) {
- IMB_float_from_rect(ps->reproject_ibuf);
- ps->reproject_ibuf_free_float = true;
- }
-
- bicubic_interpolation_color(
- ps->reproject_ibuf, NULL, projPixel->newColor.f,
- projPixel->projCoSS[0], projPixel->projCoSS[1]);
- if (projPixel->newColor.f[3]) {
- float mask = ((float)projPixel->mask) * (1.0f / 65535.0f);
-
- mul_v4_v4fl(projPixel->newColor.f, projPixel->newColor.f, mask);
-
- blend_color_mix_float(
- projPixel->pixel.f_pt, projPixel->origColor.f_pt,
- projPixel->newColor.f);
- }
- }
- else {
- if (UNLIKELY(ps->reproject_ibuf->rect == NULL)) {
- IMB_rect_from_float(ps->reproject_ibuf);
- ps->reproject_ibuf_free_uchar = true;
- }
-
- bicubic_interpolation_color(
- ps->reproject_ibuf, projPixel->newColor.ch, NULL,
- projPixel->projCoSS[0], projPixel->projCoSS[1]);
- if (projPixel->newColor.ch[3]) {
- float mask = ((float)projPixel->mask) * (1.0f / 65535.0f);
- projPixel->newColor.ch[3] *= mask;
-
- blend_color_mix_byte(
- projPixel->pixel.ch_pt, projPixel->origColor.ch_pt,
- projPixel->newColor.ch);
- }
- }
- }
- }
- }
- else {
- /* Normal brush painting */
-
- for (node = ps->bucketRect[bucket_index]; node; node = node->next) {
-
- projPixel = (ProjPixel *)node->link;
-
- dist_sq = len_squared_v2v2(projPixel->projCoSS, pos);
-
- /*if (dist < radius) {*/ /* correct but uses a sqrtf */
- if (dist_sq <= brush_radius_sq) {
- dist = sqrtf(dist_sq);
-
- falloff = BKE_brush_curve_strength_clamped(ps->brush, dist, brush_radius);
-
- if (falloff > 0.0f) {
- float texrgb[3];
- float mask;
-
- /* Extra mask for normal, layer stencil, .. */
- float custom_mask = ((float)projPixel->mask) * (1.0f / 65535.0f);
-
- /* Mask texture. */
- if (ps->is_maskbrush) {
- float texmask = BKE_brush_sample_masktex(ps->scene, ps->brush, projPixel->projCoSS, thread_index, pool);
- CLAMP(texmask, 0.0f, 1.0f);
- custom_mask *= texmask;
- }
-
- /* Color texture (alpha used as mask). */
- if (ps->is_texbrush) {
- MTex *mtex = &brush->mtex;
- float samplecos[3];
- float texrgba[4];
-
- /* taking 3d copy to account for 3D mapping too.
- * It gets concatenated during sampling */
- if (mtex->brush_map_mode == MTEX_MAP_MODE_3D) {
- copy_v3_v3(samplecos, projPixel->worldCoSS);
- }
- else {
- copy_v2_v2(samplecos, projPixel->projCoSS);
- samplecos[2] = 0.0f;
- }
-
- /* note, for clone and smear,
- * we only use the alpha, could be a special function */
- BKE_brush_sample_tex_3d(ps->scene, brush, samplecos, texrgba, thread_index, pool);
-
- copy_v3_v3(texrgb, texrgba);
- custom_mask *= texrgba[3];
- }
- else {
- zero_v3(texrgb);
- }
-
- if (ps->do_masking) {
- /* masking to keep brush contribution to a pixel limited. note we do not do
- * a simple max(mask, mask_accum), as this is very sensitive to spacing and
- * gives poor results for strokes crossing themselves.
- *
- * Instead we use a formula that adds up but approaches brush_alpha slowly
- * and never exceeds it, which gives nice smooth results. */
- float mask_accum = *projPixel->mask_accum;
- float max_mask = brush_alpha * custom_mask * falloff * 65535.0f;
-
- if (brush->flag & BRUSH_ACCUMULATE)
- mask = mask_accum + max_mask;
- else
- mask = mask_accum + (max_mask - mask_accum * falloff);
-
- mask = min_ff(mask, 65535.0f);
- mask_short = (unsigned short)mask;
-
- if (mask_short > *projPixel->mask_accum) {
- *projPixel->mask_accum = mask_short;
- mask = mask_short * (1.0f / 65535.0f);
- }
- else {
- /* Go onto the next pixel */
- continue;
- }
- }
- else {
- mask = brush_alpha * custom_mask * falloff;
- }
-
- if (mask > 0.0f) {
-
- /* copy of code above */
- if (last_index != projPixel->image_index) {
- last_index = projPixel->image_index;
- last_projIma = projImages + last_index;
-
- last_projIma->touch = 1;
- is_floatbuf = (last_projIma->ibuf->rect_float != NULL);
- }
- /* end copy */
-
- /* validate undo tile, since we will modify t*/
- *projPixel->valid = true;
-
- last_partial_redraw_cell = last_projIma->partRedrawRect + projPixel->bb_cell_index;
- image_paint_partial_redraw_expand(last_partial_redraw_cell, projPixel);
-
- /* texrgb is not used for clone, smear or soften */
- switch (tool) {
- case PAINT_TOOL_CLONE:
- if (is_floatbuf) do_projectpaint_clone_f(ps, projPixel, mask);
- else do_projectpaint_clone(ps, projPixel, mask);
- break;
- case PAINT_TOOL_SMEAR:
- sub_v2_v2v2(co, projPixel->projCoSS, pos_ofs);
-
- if (is_floatbuf) do_projectpaint_smear_f(ps, projPixel, mask, smearArena, &smearPixels_f, co);
- else do_projectpaint_smear(ps, projPixel, mask, smearArena, &smearPixels, co);
- break;
- case PAINT_TOOL_SOFTEN:
- if (is_floatbuf) do_projectpaint_soften_f(ps, projPixel, mask, softenArena, &softenPixels_f);
- else do_projectpaint_soften(ps, projPixel, mask, softenArena, &softenPixels);
- break;
- case PAINT_TOOL_MASK:
- if (is_floatbuf) do_projectpaint_mask_f(ps, projPixel, mask);
- else do_projectpaint_mask(ps, projPixel, mask);
- break;
- default:
- if (is_floatbuf) do_projectpaint_draw_f(ps, projPixel, texrgb, mask);
- else do_projectpaint_draw(ps, projPixel, texrgb, mask, ps->dither, projPixel->x_px, projPixel->y_px);
- break;
- }
-
- if (lock_alpha) {
- if (is_floatbuf) {
- /* slightly more involved case since floats are in premultiplied space we need
- * to make sure alpha is consistent, see T44627 */
- float rgb_straight[4];
- premul_to_straight_v4_v4(rgb_straight, projPixel->pixel.f_pt);
- rgb_straight[3] = projPixel->origColor.f_pt[3];
- straight_to_premul_v4_v4(projPixel->pixel.f_pt, rgb_straight);
- }
- else {
- projPixel->pixel.ch_pt[3] = projPixel->origColor.ch_pt[3];
- }
- }
- }
-
- /* done painting */
- }
- }
- }
- }
- }
-
-
- if (tool == PAINT_TOOL_SMEAR) {
-
- for (node = smearPixels; node; node = node->next) { /* this wont run for a float image */
- projPixel = node->link;
- *projPixel->pixel.uint_pt = ((ProjPixelClone *)projPixel)->clonepx.uint;
- }
-
- for (node = smearPixels_f; node; node = node->next) {
- projPixel = node->link;
- copy_v4_v4(projPixel->pixel.f_pt, ((ProjPixelClone *)projPixel)->clonepx.f);
- }
-
- BLI_memarena_free(smearArena);
- }
- else if (tool == PAINT_TOOL_SOFTEN) {
-
- for (node = softenPixels; node; node = node->next) { /* this wont run for a float image */
- projPixel = node->link;
- *projPixel->pixel.uint_pt = projPixel->newColor.uint;
- }
-
- for (node = softenPixels_f; node; node = node->next) {
- projPixel = node->link;
- copy_v4_v4(projPixel->pixel.f_pt, projPixel->newColor.f);
- }
-
- BLI_memarena_free(softenArena);
- }
-
- return NULL;
+ /* First unpack args from the struct */
+ ProjPaintState *ps = ((ProjectHandle *)ph_v)->ps;
+ ProjPaintImage *projImages = ((ProjectHandle *)ph_v)->projImages;
+ const float *lastpos = ((ProjectHandle *)ph_v)->prevmval;
+ const float *pos = ((ProjectHandle *)ph_v)->mval;
+ const int thread_index = ((ProjectHandle *)ph_v)->thread_index;
+ struct ImagePool *pool = ((ProjectHandle *)ph_v)->pool;
+ /* Done with args from ProjectHandle */
+
+ LinkNode *node;
+ ProjPixel *projPixel;
+ Brush *brush = ps->brush;
+
+ int last_index = -1;
+ ProjPaintImage *last_projIma = NULL;
+ ImagePaintPartialRedraw *last_partial_redraw_cell;
+
+ float dist_sq, dist;
+
+ float falloff;
+ int bucket_index;
+ bool is_floatbuf = false;
+ const short tool = ps->tool;
+ rctf bucket_bounds;
+
+ /* for smear only */
+ float pos_ofs[2] = {0};
+ float co[2];
+ unsigned short mask_short;
+ const float brush_alpha = BKE_brush_alpha_get(ps->scene, brush);
+ const float brush_radius = ps->brush_size;
+ /* avoid a square root with every dist comparison */
+ const float brush_radius_sq = brush_radius * brush_radius;
+
+ const bool lock_alpha = ELEM(brush->blend, IMB_BLEND_ERASE_ALPHA, IMB_BLEND_ADD_ALPHA) ?
+ 0 :
+ (brush->flag & BRUSH_LOCK_ALPHA) != 0;
+
+ LinkNode *smearPixels = NULL;
+ LinkNode *smearPixels_f = NULL;
+ /* mem arena for this brush projection only */
+ MemArena *smearArena = NULL;
+
+ LinkNode *softenPixels = NULL;
+ LinkNode *softenPixels_f = NULL;
+ /* mem arena for this brush projection only */
+ MemArena *softenArena = NULL;
+
+ if (tool == PAINT_TOOL_SMEAR) {
+ pos_ofs[0] = pos[0] - lastpos[0];
+ pos_ofs[1] = pos[1] - lastpos[1];
+
+ smearArena = BLI_memarena_new(MEM_SIZE_OPTIMAL(1 << 16), "paint smear arena");
+ }
+ else if (tool == PAINT_TOOL_SOFTEN) {
+ softenArena = BLI_memarena_new(MEM_SIZE_OPTIMAL(1 << 16), "paint soften arena");
+ }
+
+ /* printf("brush bounds %d %d %d %d\n",
+ * bucketMin[0], bucketMin[1], bucketMax[0], bucketMax[1]); */
+
+ while (project_bucket_iter_next(ps, &bucket_index, &bucket_bounds, pos)) {
+
+ /* Check this bucket and its faces are initialized */
+ if (ps->bucketFlags[bucket_index] == PROJ_BUCKET_NULL) {
+ rctf clip_rect = bucket_bounds;
+ clip_rect.xmin -= PROJ_PIXEL_TOLERANCE;
+ clip_rect.xmax += PROJ_PIXEL_TOLERANCE;
+ clip_rect.ymin -= PROJ_PIXEL_TOLERANCE;
+ clip_rect.ymax += PROJ_PIXEL_TOLERANCE;
+ /* No pixels initialized */
+ project_bucket_init(ps, thread_index, bucket_index, &clip_rect, &bucket_bounds);
+ }
+
+ if (ps->source != PROJ_SRC_VIEW) {
+
+ /* Re-Projection, simple, no brushes! */
+
+ for (node = ps->bucketRect[bucket_index]; node; node = node->next) {
+ projPixel = (ProjPixel *)node->link;
+
+ /* copy of code below */
+ if (last_index != projPixel->image_index) {
+ last_index = projPixel->image_index;
+ last_projIma = projImages + last_index;
+
+ last_projIma->touch = 1;
+ is_floatbuf = (last_projIma->ibuf->rect_float != NULL);
+ }
+ /* end copy */
+
+ /* fill tools */
+ if (ps->source == PROJ_SRC_VIEW_FILL) {
+ if (brush->flag & BRUSH_USE_GRADIENT) {
+ /* these could probably be cached instead of being done per pixel */
+ float tangent[2];
+ float line_len_sq_inv, line_len;
+ float f;
+ float color_f[4];
+ float p[2] = {projPixel->projCoSS[0] - lastpos[0],
+ projPixel->projCoSS[1] - lastpos[1]};
+
+ sub_v2_v2v2(tangent, pos, lastpos);
+ line_len = len_squared_v2(tangent);
+ line_len_sq_inv = 1.0f / line_len;
+ line_len = sqrtf(line_len);
+
+ switch (brush->gradient_fill_mode) {
+ case BRUSH_GRADIENT_LINEAR: {
+ f = dot_v2v2(p, tangent) * line_len_sq_inv;
+ break;
+ }
+ case BRUSH_GRADIENT_RADIAL:
+ default: {
+ f = len_v2(p) / line_len;
+ break;
+ }
+ }
+ BKE_colorband_evaluate(brush->gradient, f, color_f);
+ color_f[3] *= ((float)projPixel->mask) * (1.0f / 65535.0f) * brush->alpha;
+
+ if (is_floatbuf) {
+ /* convert to premultipied */
+ mul_v3_fl(color_f, color_f[3]);
+ IMB_blend_color_float(
+ projPixel->pixel.f_pt, projPixel->origColor.f_pt, color_f, ps->blend);
+ }
+ else {
+ linearrgb_to_srgb_v3_v3(color_f, color_f);
+
+ if (ps->dither > 0.0f) {
+ float_to_byte_dither_v3(
+ projPixel->newColor.ch, color_f, ps->dither, projPixel->x_px, projPixel->y_px);
+ }
+ else {
+ unit_float_to_uchar_clamp_v3(projPixel->newColor.ch, color_f);
+ }
+ projPixel->newColor.ch[3] = unit_float_to_uchar_clamp(color_f[3]);
+ IMB_blend_color_byte(projPixel->pixel.ch_pt,
+ projPixel->origColor.ch_pt,
+ projPixel->newColor.ch,
+ ps->blend);
+ }
+ }
+ else {
+ if (is_floatbuf) {
+ float newColor_f[4];
+ newColor_f[3] = ((float)projPixel->mask) * (1.0f / 65535.0f) * brush->alpha;
+ copy_v3_v3(newColor_f, ps->paint_color_linear);
+
+ IMB_blend_color_float(
+ projPixel->pixel.f_pt, projPixel->origColor.f_pt, newColor_f, ps->blend);
+ }
+ else {
+ float mask = ((float)projPixel->mask) * (1.0f / 65535.0f);
+ projPixel->newColor.ch[3] = mask * 255 * brush->alpha;
+
+ rgb_float_to_uchar(projPixel->newColor.ch, ps->paint_color);
+ IMB_blend_color_byte(projPixel->pixel.ch_pt,
+ projPixel->origColor.ch_pt,
+ projPixel->newColor.ch,
+ ps->blend);
+ }
+ }
+
+ if (lock_alpha) {
+ if (is_floatbuf) {
+ /* slightly more involved case since floats are in premultiplied space we need
+ * to make sure alpha is consistent, see T44627 */
+ float rgb_straight[4];
+ premul_to_straight_v4_v4(rgb_straight, projPixel->pixel.f_pt);
+ rgb_straight[3] = projPixel->origColor.f_pt[3];
+ straight_to_premul_v4_v4(projPixel->pixel.f_pt, rgb_straight);
+ }
+ else {
+ projPixel->pixel.ch_pt[3] = projPixel->origColor.ch_pt[3];
+ }
+ }
+
+ last_partial_redraw_cell = last_projIma->partRedrawRect + projPixel->bb_cell_index;
+ image_paint_partial_redraw_expand(last_partial_redraw_cell, projPixel);
+ }
+ else {
+ if (is_floatbuf) {
+ if (UNLIKELY(ps->reproject_ibuf->rect_float == NULL)) {
+ IMB_float_from_rect(ps->reproject_ibuf);
+ ps->reproject_ibuf_free_float = true;
+ }
+
+ bicubic_interpolation_color(ps->reproject_ibuf,
+ NULL,
+ projPixel->newColor.f,
+ projPixel->projCoSS[0],
+ projPixel->projCoSS[1]);
+ if (projPixel->newColor.f[3]) {
+ float mask = ((float)projPixel->mask) * (1.0f / 65535.0f);
+
+ mul_v4_v4fl(projPixel->newColor.f, projPixel->newColor.f, mask);
+
+ blend_color_mix_float(
+ projPixel->pixel.f_pt, projPixel->origColor.f_pt, projPixel->newColor.f);
+ }
+ }
+ else {
+ if (UNLIKELY(ps->reproject_ibuf->rect == NULL)) {
+ IMB_rect_from_float(ps->reproject_ibuf);
+ ps->reproject_ibuf_free_uchar = true;
+ }
+
+ bicubic_interpolation_color(ps->reproject_ibuf,
+ projPixel->newColor.ch,
+ NULL,
+ projPixel->projCoSS[0],
+ projPixel->projCoSS[1]);
+ if (projPixel->newColor.ch[3]) {
+ float mask = ((float)projPixel->mask) * (1.0f / 65535.0f);
+ projPixel->newColor.ch[3] *= mask;
+
+ blend_color_mix_byte(
+ projPixel->pixel.ch_pt, projPixel->origColor.ch_pt, projPixel->newColor.ch);
+ }
+ }
+ }
+ }
+ }
+ else {
+ /* Normal brush painting */
+
+ for (node = ps->bucketRect[bucket_index]; node; node = node->next) {
+
+ projPixel = (ProjPixel *)node->link;
+
+ dist_sq = len_squared_v2v2(projPixel->projCoSS, pos);
+
+ /*if (dist < radius) {*/ /* correct but uses a sqrtf */
+ if (dist_sq <= brush_radius_sq) {
+ dist = sqrtf(dist_sq);
+
+ falloff = BKE_brush_curve_strength_clamped(ps->brush, dist, brush_radius);
+
+ if (falloff > 0.0f) {
+ float texrgb[3];
+ float mask;
+
+ /* Extra mask for normal, layer stencil, .. */
+ float custom_mask = ((float)projPixel->mask) * (1.0f / 65535.0f);
+
+ /* Mask texture. */
+ if (ps->is_maskbrush) {
+ float texmask = BKE_brush_sample_masktex(
+ ps->scene, ps->brush, projPixel->projCoSS, thread_index, pool);
+ CLAMP(texmask, 0.0f, 1.0f);
+ custom_mask *= texmask;
+ }
+
+ /* Color texture (alpha used as mask). */
+ if (ps->is_texbrush) {
+ MTex *mtex = &brush->mtex;
+ float samplecos[3];
+ float texrgba[4];
+
+ /* taking 3d copy to account for 3D mapping too.
+ * It gets concatenated during sampling */
+ if (mtex->brush_map_mode == MTEX_MAP_MODE_3D) {
+ copy_v3_v3(samplecos, projPixel->worldCoSS);
+ }
+ else {
+ copy_v2_v2(samplecos, projPixel->projCoSS);
+ samplecos[2] = 0.0f;
+ }
+
+ /* note, for clone and smear,
+ * we only use the alpha, could be a special function */
+ BKE_brush_sample_tex_3d(ps->scene, brush, samplecos, texrgba, thread_index, pool);
+
+ copy_v3_v3(texrgb, texrgba);
+ custom_mask *= texrgba[3];
+ }
+ else {
+ zero_v3(texrgb);
+ }
+
+ if (ps->do_masking) {
+ /* masking to keep brush contribution to a pixel limited. note we do not do
+ * a simple max(mask, mask_accum), as this is very sensitive to spacing and
+ * gives poor results for strokes crossing themselves.
+ *
+ * Instead we use a formula that adds up but approaches brush_alpha slowly
+ * and never exceeds it, which gives nice smooth results. */
+ float mask_accum = *projPixel->mask_accum;
+ float max_mask = brush_alpha * custom_mask * falloff * 65535.0f;
+
+ if (brush->flag & BRUSH_ACCUMULATE)
+ mask = mask_accum + max_mask;
+ else
+ mask = mask_accum + (max_mask - mask_accum * falloff);
+
+ mask = min_ff(mask, 65535.0f);
+ mask_short = (unsigned short)mask;
+
+ if (mask_short > *projPixel->mask_accum) {
+ *projPixel->mask_accum = mask_short;
+ mask = mask_short * (1.0f / 65535.0f);
+ }
+ else {
+ /* Go onto the next pixel */
+ continue;
+ }
+ }
+ else {
+ mask = brush_alpha * custom_mask * falloff;
+ }
+
+ if (mask > 0.0f) {
+
+ /* copy of code above */
+ if (last_index != projPixel->image_index) {
+ last_index = projPixel->image_index;
+ last_projIma = projImages + last_index;
+
+ last_projIma->touch = 1;
+ is_floatbuf = (last_projIma->ibuf->rect_float != NULL);
+ }
+ /* end copy */
+
+ /* validate undo tile, since we will modify t*/
+ *projPixel->valid = true;
+
+ last_partial_redraw_cell = last_projIma->partRedrawRect + projPixel->bb_cell_index;
+ image_paint_partial_redraw_expand(last_partial_redraw_cell, projPixel);
+
+ /* texrgb is not used for clone, smear or soften */
+ switch (tool) {
+ case PAINT_TOOL_CLONE:
+ if (is_floatbuf)
+ do_projectpaint_clone_f(ps, projPixel, mask);
+ else
+ do_projectpaint_clone(ps, projPixel, mask);
+ break;
+ case PAINT_TOOL_SMEAR:
+ sub_v2_v2v2(co, projPixel->projCoSS, pos_ofs);
+
+ if (is_floatbuf)
+ do_projectpaint_smear_f(ps, projPixel, mask, smearArena, &smearPixels_f, co);
+ else
+ do_projectpaint_smear(ps, projPixel, mask, smearArena, &smearPixels, co);
+ break;
+ case PAINT_TOOL_SOFTEN:
+ if (is_floatbuf)
+ do_projectpaint_soften_f(ps, projPixel, mask, softenArena, &softenPixels_f);
+ else
+ do_projectpaint_soften(ps, projPixel, mask, softenArena, &softenPixels);
+ break;
+ case PAINT_TOOL_MASK:
+ if (is_floatbuf)
+ do_projectpaint_mask_f(ps, projPixel, mask);
+ else
+ do_projectpaint_mask(ps, projPixel, mask);
+ break;
+ default:
+ if (is_floatbuf)
+ do_projectpaint_draw_f(ps, projPixel, texrgb, mask);
+ else
+ do_projectpaint_draw(
+ ps, projPixel, texrgb, mask, ps->dither, projPixel->x_px, projPixel->y_px);
+ break;
+ }
+
+ if (lock_alpha) {
+ if (is_floatbuf) {
+ /* slightly more involved case since floats are in premultiplied space we need
+ * to make sure alpha is consistent, see T44627 */
+ float rgb_straight[4];
+ premul_to_straight_v4_v4(rgb_straight, projPixel->pixel.f_pt);
+ rgb_straight[3] = projPixel->origColor.f_pt[3];
+ straight_to_premul_v4_v4(projPixel->pixel.f_pt, rgb_straight);
+ }
+ else {
+ projPixel->pixel.ch_pt[3] = projPixel->origColor.ch_pt[3];
+ }
+ }
+ }
+
+ /* done painting */
+ }
+ }
+ }
+ }
+ }
+
+ if (tool == PAINT_TOOL_SMEAR) {
+
+ for (node = smearPixels; node; node = node->next) { /* this wont run for a float image */
+ projPixel = node->link;
+ *projPixel->pixel.uint_pt = ((ProjPixelClone *)projPixel)->clonepx.uint;
+ }
+
+ for (node = smearPixels_f; node; node = node->next) {
+ projPixel = node->link;
+ copy_v4_v4(projPixel->pixel.f_pt, ((ProjPixelClone *)projPixel)->clonepx.f);
+ }
+
+ BLI_memarena_free(smearArena);
+ }
+ else if (tool == PAINT_TOOL_SOFTEN) {
+
+ for (node = softenPixels; node; node = node->next) { /* this wont run for a float image */
+ projPixel = node->link;
+ *projPixel->pixel.uint_pt = projPixel->newColor.uint;
+ }
+
+ for (node = softenPixels_f; node; node = node->next) {
+ projPixel = node->link;
+ copy_v4_v4(projPixel->pixel.f_pt, projPixel->newColor.f);
+ }
+
+ BLI_memarena_free(softenArena);
+ }
+
+ return NULL;
}
static bool project_paint_op(void *state, const float lastpos[2], const float pos[2])
{
- /* First unpack args from the struct */
- ProjPaintState *ps = (ProjPaintState *)state;
- bool touch_any = false;
-
- ProjectHandle handles[BLENDER_MAX_THREADS];
- ListBase threads;
- int a, i;
-
- struct ImagePool *pool;
-
- if (!project_bucket_iter_init(ps, pos)) {
- return touch_any;
- }
-
- if (ps->thread_tot > 1)
- BLI_threadpool_init(&threads, do_projectpaint_thread, ps->thread_tot);
-
- pool = BKE_image_pool_new();
-
- /* get the threads running */
- for (a = 0; a < ps->thread_tot; a++) {
-
- /* set defaults in handles */
- //memset(&handles[a], 0, sizeof(BakeShade));
-
- handles[a].ps = ps;
- copy_v2_v2(handles[a].mval, pos);
- copy_v2_v2(handles[a].prevmval, lastpos);
-
- /* thread specific */
- handles[a].thread_index = a;
-
- handles[a].projImages = BLI_memarena_alloc(ps->arena_mt[a], ps->image_tot * sizeof(ProjPaintImage));
-
- memcpy(handles[a].projImages, ps->projImages, ps->image_tot * sizeof(ProjPaintImage));
-
- /* image bounds */
- for (i = 0; i < ps->image_tot; i++) {
- handles[a].projImages[i].partRedrawRect = BLI_memarena_alloc(ps->arena_mt[a], sizeof(ImagePaintPartialRedraw) * PROJ_BOUNDBOX_SQUARED);
- memcpy(handles[a].projImages[i].partRedrawRect, ps->projImages[i].partRedrawRect, sizeof(ImagePaintPartialRedraw) * PROJ_BOUNDBOX_SQUARED);
- }
-
- handles[a].pool = pool;
-
- if (ps->thread_tot > 1)
- BLI_threadpool_insert(&threads, &handles[a]);
- }
-
- if (ps->thread_tot > 1) /* wait for everything to be done */
- BLI_threadpool_end(&threads);
- else
- do_projectpaint_thread(&handles[0]);
-
-
- BKE_image_pool_free(pool);
-
- /* move threaded bounds back into ps->projectPartialRedraws */
- for (i = 0; i < ps->image_tot; i++) {
- int touch = 0;
- for (a = 0; a < ps->thread_tot; a++) {
- touch |= partial_redraw_array_merge(ps->projImages[i].partRedrawRect, handles[a].projImages[i].partRedrawRect, PROJ_BOUNDBOX_SQUARED);
- }
-
- if (touch) {
- ps->projImages[i].touch = 1;
- touch_any = 1;
- }
- }
-
- /* calculate pivot for rotation around seletion if needed */
- if (U.uiflag & USER_ORBIT_SELECTION) {
- float w[3];
- int tri_index;
-
- tri_index = project_paint_PickFace(ps, pos, w);
-
- if (tri_index != -1) {
- const MLoopTri *lt = &ps->mlooptri_eval[tri_index];
- const int lt_vtri[3] = { PS_LOOPTRI_AS_VERT_INDEX_3(ps, lt) };
- float world[3];
- UnifiedPaintSettings *ups = &ps->scene->toolsettings->unified_paint_settings;
-
- interp_v3_v3v3v3(
- world,
- ps->mvert_eval[lt_vtri[0]].co,
- ps->mvert_eval[lt_vtri[1]].co,
- ps->mvert_eval[lt_vtri[2]].co,
- w);
-
- ups->average_stroke_counter++;
- mul_m4_v3(ps->obmat, world);
- add_v3_v3(ups->average_stroke_accum, world);
- ups->last_stroke_valid = true;
- }
- }
-
- return touch_any;
+ /* First unpack args from the struct */
+ ProjPaintState *ps = (ProjPaintState *)state;
+ bool touch_any = false;
+
+ ProjectHandle handles[BLENDER_MAX_THREADS];
+ ListBase threads;
+ int a, i;
+
+ struct ImagePool *pool;
+
+ if (!project_bucket_iter_init(ps, pos)) {
+ return touch_any;
+ }
+
+ if (ps->thread_tot > 1)
+ BLI_threadpool_init(&threads, do_projectpaint_thread, ps->thread_tot);
+
+ pool = BKE_image_pool_new();
+
+ /* get the threads running */
+ for (a = 0; a < ps->thread_tot; a++) {
+
+ /* set defaults in handles */
+ //memset(&handles[a], 0, sizeof(BakeShade));
+
+ handles[a].ps = ps;
+ copy_v2_v2(handles[a].mval, pos);
+ copy_v2_v2(handles[a].prevmval, lastpos);
+
+ /* thread specific */
+ handles[a].thread_index = a;
+
+ handles[a].projImages = BLI_memarena_alloc(ps->arena_mt[a],
+ ps->image_tot * sizeof(ProjPaintImage));
+
+ memcpy(handles[a].projImages, ps->projImages, ps->image_tot * sizeof(ProjPaintImage));
+
+ /* image bounds */
+ for (i = 0; i < ps->image_tot; i++) {
+ handles[a].projImages[i].partRedrawRect = BLI_memarena_alloc(
+ ps->arena_mt[a], sizeof(ImagePaintPartialRedraw) * PROJ_BOUNDBOX_SQUARED);
+ memcpy(handles[a].projImages[i].partRedrawRect,
+ ps->projImages[i].partRedrawRect,
+ sizeof(ImagePaintPartialRedraw) * PROJ_BOUNDBOX_SQUARED);
+ }
+
+ handles[a].pool = pool;
+
+ if (ps->thread_tot > 1)
+ BLI_threadpool_insert(&threads, &handles[a]);
+ }
+
+ if (ps->thread_tot > 1) /* wait for everything to be done */
+ BLI_threadpool_end(&threads);
+ else
+ do_projectpaint_thread(&handles[0]);
+
+ BKE_image_pool_free(pool);
+
+ /* move threaded bounds back into ps->projectPartialRedraws */
+ for (i = 0; i < ps->image_tot; i++) {
+ int touch = 0;
+ for (a = 0; a < ps->thread_tot; a++) {
+ touch |= partial_redraw_array_merge(ps->projImages[i].partRedrawRect,
+ handles[a].projImages[i].partRedrawRect,
+ PROJ_BOUNDBOX_SQUARED);
+ }
+
+ if (touch) {
+ ps->projImages[i].touch = 1;
+ touch_any = 1;
+ }
+ }
+
+ /* calculate pivot for rotation around seletion if needed */
+ if (U.uiflag & USER_ORBIT_SELECTION) {
+ float w[3];
+ int tri_index;
+
+ tri_index = project_paint_PickFace(ps, pos, w);
+
+ if (tri_index != -1) {
+ const MLoopTri *lt = &ps->mlooptri_eval[tri_index];
+ const int lt_vtri[3] = {PS_LOOPTRI_AS_VERT_INDEX_3(ps, lt)};
+ float world[3];
+ UnifiedPaintSettings *ups = &ps->scene->toolsettings->unified_paint_settings;
+
+ interp_v3_v3v3v3(world,
+ ps->mvert_eval[lt_vtri[0]].co,
+ ps->mvert_eval[lt_vtri[1]].co,
+ ps->mvert_eval[lt_vtri[2]].co,
+ w);
+
+ ups->average_stroke_counter++;
+ mul_m4_v3(ps->obmat, world);
+ add_v3_v3(ups->average_stroke_accum, world);
+ ups->last_stroke_valid = true;
+ }
+ }
+
+ return touch_any;
}
-
-static void paint_proj_stroke_ps(
- const bContext *UNUSED(C), void *ps_handle_p, const float prev_pos[2], const float pos[2],
- const bool eraser, float pressure, float distance, float size,
- /* extra view */
- ProjPaintState *ps
- )
+static void paint_proj_stroke_ps(const bContext *UNUSED(C),
+ void *ps_handle_p,
+ const float prev_pos[2],
+ const float pos[2],
+ const bool eraser,
+ float pressure,
+ float distance,
+ float size,
+ /* extra view */
+ ProjPaintState *ps)
{
- ProjStrokeHandle *ps_handle = ps_handle_p;
- Brush *brush = ps->brush;
- Scene *scene = ps->scene;
-
- ps->brush_size = size;
- ps->blend = brush->blend;
- if (eraser)
- ps->blend = IMB_BLEND_ERASE_ALPHA;
-
- /* handle gradient and inverted stroke color here */
- if (ELEM(ps->tool, PAINT_TOOL_DRAW, PAINT_TOOL_FILL)) {
- paint_brush_color_get(scene, brush, false, ps->mode == BRUSH_STROKE_INVERT, distance, pressure, ps->paint_color, NULL);
- if (ps->use_colormanagement) {
- srgb_to_linearrgb_v3_v3(ps->paint_color_linear, ps->paint_color);
- }
- else {
- copy_v3_v3(ps->paint_color_linear, ps->paint_color);
- }
- }
- else if (ps->tool == PAINT_TOOL_MASK) {
- ps->stencil_value = brush->weight;
-
- if ((ps->mode == BRUSH_STROKE_INVERT) ^
- ((scene->toolsettings->imapaint.flag & IMAGEPAINT_PROJECT_LAYER_STENCIL_INV) != 0))
- {
- ps->stencil_value = 1.0f - ps->stencil_value;
- }
- }
-
- if (project_paint_op(ps, prev_pos, pos)) {
- ps_handle->need_redraw = true;
- project_image_refresh_tagged(ps);
- }
+ ProjStrokeHandle *ps_handle = ps_handle_p;
+ Brush *brush = ps->brush;
+ Scene *scene = ps->scene;
+
+ ps->brush_size = size;
+ ps->blend = brush->blend;
+ if (eraser)
+ ps->blend = IMB_BLEND_ERASE_ALPHA;
+
+ /* handle gradient and inverted stroke color here */
+ if (ELEM(ps->tool, PAINT_TOOL_DRAW, PAINT_TOOL_FILL)) {
+ paint_brush_color_get(scene,
+ brush,
+ false,
+ ps->mode == BRUSH_STROKE_INVERT,
+ distance,
+ pressure,
+ ps->paint_color,
+ NULL);
+ if (ps->use_colormanagement) {
+ srgb_to_linearrgb_v3_v3(ps->paint_color_linear, ps->paint_color);
+ }
+ else {
+ copy_v3_v3(ps->paint_color_linear, ps->paint_color);
+ }
+ }
+ else if (ps->tool == PAINT_TOOL_MASK) {
+ ps->stencil_value = brush->weight;
+
+ if ((ps->mode == BRUSH_STROKE_INVERT) ^
+ ((scene->toolsettings->imapaint.flag & IMAGEPAINT_PROJECT_LAYER_STENCIL_INV) != 0)) {
+ ps->stencil_value = 1.0f - ps->stencil_value;
+ }
+ }
+
+ if (project_paint_op(ps, prev_pos, pos)) {
+ ps_handle->need_redraw = true;
+ project_image_refresh_tagged(ps);
+ }
}
-
-void paint_proj_stroke(
- const bContext *C, void *ps_handle_p, const float prev_pos[2], const float pos[2],
- const bool eraser, float pressure, float distance, float size)
+void paint_proj_stroke(const bContext *C,
+ void *ps_handle_p,
+ const float prev_pos[2],
+ const float pos[2],
+ const bool eraser,
+ float pressure,
+ float distance,
+ float size)
{
- int i;
- ProjStrokeHandle *ps_handle = ps_handle_p;
+ int i;
+ ProjStrokeHandle *ps_handle = ps_handle_p;
- /* clone gets special treatment here to avoid going through image initialization */
- if (ps_handle->is_clone_cursor_pick) {
- Scene *scene = ps_handle->scene;
- struct Depsgraph *depsgraph = CTX_data_depsgraph(C);
- View3D *v3d = CTX_wm_view3d(C);
- ARegion *ar = CTX_wm_region(C);
- float *cursor = scene->cursor.location;
- int mval_i[2] = {(int)pos[0], (int)pos[1]};
+ /* clone gets special treatment here to avoid going through image initialization */
+ if (ps_handle->is_clone_cursor_pick) {
+ Scene *scene = ps_handle->scene;
+ struct Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ View3D *v3d = CTX_wm_view3d(C);
+ ARegion *ar = CTX_wm_region(C);
+ float *cursor = scene->cursor.location;
+ int mval_i[2] = {(int)pos[0], (int)pos[1]};
- view3d_operator_needs_opengl(C);
+ view3d_operator_needs_opengl(C);
- if (!ED_view3d_autodist(depsgraph, ar, v3d, mval_i, cursor, false, NULL)) {
- return;
- }
+ if (!ED_view3d_autodist(depsgraph, ar, v3d, mval_i, cursor, false, NULL)) {
+ return;
+ }
- ED_region_tag_redraw(ar);
+ ED_region_tag_redraw(ar);
- return;
- }
+ return;
+ }
- for (i = 0; i < ps_handle->ps_views_tot; i++) {
- ProjPaintState *ps = ps_handle->ps_views[i];
- paint_proj_stroke_ps(C, ps_handle_p, prev_pos, pos, eraser, pressure, distance, size, ps);
- }
+ for (i = 0; i < ps_handle->ps_views_tot; i++) {
+ ProjPaintState *ps = ps_handle->ps_views[i];
+ paint_proj_stroke_ps(C, ps_handle_p, prev_pos, pos, eraser, pressure, distance, size, ps);
+ }
}
-
/* initialize project paint settings from context */
static void project_state_init(bContext *C, Object *ob, ProjPaintState *ps, int mode)
{
- Scene *scene = CTX_data_scene(C);
- ToolSettings *settings = scene->toolsettings;
-
- /* brush */
- ps->mode = mode;
- ps->brush = BKE_paint_brush(&settings->imapaint.paint);
- if (ps->brush) {
- Brush *brush = ps->brush;
- ps->tool = brush->imagepaint_tool;
- ps->blend = brush->blend;
- /* only check for inversion for the soften tool, elsewhere,
- * a resident brush inversion flag can cause issues */
- if (brush->imagepaint_tool == PAINT_TOOL_SOFTEN) {
- ps->mode = (((ps->mode == BRUSH_STROKE_INVERT) ^ ((brush->flag & BRUSH_DIR_IN) != 0)) ?
- BRUSH_STROKE_INVERT : BRUSH_STROKE_NORMAL);
-
- ps->blurkernel = paint_new_blur_kernel(brush, true);
- }
-
- /* disable for 3d mapping also because painting on mirrored mesh can create "stripes" */
- ps->do_masking = paint_use_opacity_masking(brush);
- ps->is_texbrush = (brush->mtex.tex && brush->imagepaint_tool == PAINT_TOOL_DRAW) ? true : false;
- ps->is_maskbrush = (brush->mask_mtex.tex) ? true : false;
- }
- else {
- /* brush may be NULL*/
- ps->do_masking = false;
- ps->is_texbrush = false;
- ps->is_maskbrush = false;
- }
-
- /* sizeof(ProjPixel), since we alloc this a _lot_ */
- ps->pixel_sizeof = project_paint_pixel_sizeof(ps->tool);
- BLI_assert(ps->pixel_sizeof >= sizeof(ProjPixel));
-
- /* these can be NULL */
- ps->v3d = CTX_wm_view3d(C);
- ps->rv3d = CTX_wm_region_view3d(C);
- ps->ar = CTX_wm_region(C);
-
- ps->depsgraph = CTX_data_depsgraph(C);
- ps->scene = scene;
- /* allow override of active object */
- ps->ob = ob;
-
- ps->do_material_slots = (settings->imapaint.mode == IMAGEPAINT_MODE_MATERIAL);
- ps->stencil_ima = settings->imapaint.stencil;
- ps->canvas_ima = (!ps->do_material_slots) ?
- settings->imapaint.canvas : NULL;
- ps->clone_ima = (!ps->do_material_slots) ?
- settings->imapaint.clone : NULL;
-
- ps->do_mask_cavity = (settings->imapaint.paint.flags & PAINT_USE_CAVITY_MASK) ? true : false;
- ps->cavity_curve = settings->imapaint.paint.cavity_curve;
-
- /* setup projection painting data */
- if (ps->tool != PAINT_TOOL_FILL) {
- ps->do_backfacecull = (settings->imapaint.flag & IMAGEPAINT_PROJECT_BACKFACE) ? false : true;
- ps->do_occlude = (settings->imapaint.flag & IMAGEPAINT_PROJECT_XRAY) ? false : true;
- ps->do_mask_normal = (settings->imapaint.flag & IMAGEPAINT_PROJECT_FLAT) ? false : true;
- }
- else {
- ps->do_backfacecull = ps->do_occlude = ps->do_mask_normal = 0;
- }
-
- if (ps->tool == PAINT_TOOL_CLONE)
- ps->do_layer_clone = (settings->imapaint.flag & IMAGEPAINT_PROJECT_LAYER_CLONE) ? 1 : 0;
-
-
- ps->do_stencil_brush = (ps->brush && ps->brush->imagepaint_tool == PAINT_TOOL_MASK);
- /* deactivate stenciling for the stencil brush :) */
- ps->do_layer_stencil = ((settings->imapaint.flag & IMAGEPAINT_PROJECT_LAYER_STENCIL) &&
- !(ps->do_stencil_brush) && ps->stencil_ima);
- ps->do_layer_stencil_inv = ((settings->imapaint.flag & IMAGEPAINT_PROJECT_LAYER_STENCIL_INV) != 0);
-
+ Scene *scene = CTX_data_scene(C);
+ ToolSettings *settings = scene->toolsettings;
+
+ /* brush */
+ ps->mode = mode;
+ ps->brush = BKE_paint_brush(&settings->imapaint.paint);
+ if (ps->brush) {
+ Brush *brush = ps->brush;
+ ps->tool = brush->imagepaint_tool;
+ ps->blend = brush->blend;
+ /* only check for inversion for the soften tool, elsewhere,
+ * a resident brush inversion flag can cause issues */
+ if (brush->imagepaint_tool == PAINT_TOOL_SOFTEN) {
+ ps->mode = (((ps->mode == BRUSH_STROKE_INVERT) ^ ((brush->flag & BRUSH_DIR_IN) != 0)) ?
+ BRUSH_STROKE_INVERT :
+ BRUSH_STROKE_NORMAL);
+
+ ps->blurkernel = paint_new_blur_kernel(brush, true);
+ }
+
+ /* disable for 3d mapping also because painting on mirrored mesh can create "stripes" */
+ ps->do_masking = paint_use_opacity_masking(brush);
+ ps->is_texbrush = (brush->mtex.tex && brush->imagepaint_tool == PAINT_TOOL_DRAW) ? true :
+ false;
+ ps->is_maskbrush = (brush->mask_mtex.tex) ? true : false;
+ }
+ else {
+ /* brush may be NULL*/
+ ps->do_masking = false;
+ ps->is_texbrush = false;
+ ps->is_maskbrush = false;
+ }
+
+ /* sizeof(ProjPixel), since we alloc this a _lot_ */
+ ps->pixel_sizeof = project_paint_pixel_sizeof(ps->tool);
+ BLI_assert(ps->pixel_sizeof >= sizeof(ProjPixel));
+
+ /* these can be NULL */
+ ps->v3d = CTX_wm_view3d(C);
+ ps->rv3d = CTX_wm_region_view3d(C);
+ ps->ar = CTX_wm_region(C);
+
+ ps->depsgraph = CTX_data_depsgraph(C);
+ ps->scene = scene;
+ /* allow override of active object */
+ ps->ob = ob;
+
+ ps->do_material_slots = (settings->imapaint.mode == IMAGEPAINT_MODE_MATERIAL);
+ ps->stencil_ima = settings->imapaint.stencil;
+ ps->canvas_ima = (!ps->do_material_slots) ? settings->imapaint.canvas : NULL;
+ ps->clone_ima = (!ps->do_material_slots) ? settings->imapaint.clone : NULL;
+
+ ps->do_mask_cavity = (settings->imapaint.paint.flags & PAINT_USE_CAVITY_MASK) ? true : false;
+ ps->cavity_curve = settings->imapaint.paint.cavity_curve;
+
+ /* setup projection painting data */
+ if (ps->tool != PAINT_TOOL_FILL) {
+ ps->do_backfacecull = (settings->imapaint.flag & IMAGEPAINT_PROJECT_BACKFACE) ? false : true;
+ ps->do_occlude = (settings->imapaint.flag & IMAGEPAINT_PROJECT_XRAY) ? false : true;
+ ps->do_mask_normal = (settings->imapaint.flag & IMAGEPAINT_PROJECT_FLAT) ? false : true;
+ }
+ else {
+ ps->do_backfacecull = ps->do_occlude = ps->do_mask_normal = 0;
+ }
+
+ if (ps->tool == PAINT_TOOL_CLONE)
+ ps->do_layer_clone = (settings->imapaint.flag & IMAGEPAINT_PROJECT_LAYER_CLONE) ? 1 : 0;
+
+ ps->do_stencil_brush = (ps->brush && ps->brush->imagepaint_tool == PAINT_TOOL_MASK);
+ /* deactivate stenciling for the stencil brush :) */
+ ps->do_layer_stencil = ((settings->imapaint.flag & IMAGEPAINT_PROJECT_LAYER_STENCIL) &&
+ !(ps->do_stencil_brush) && ps->stencil_ima);
+ ps->do_layer_stencil_inv = ((settings->imapaint.flag & IMAGEPAINT_PROJECT_LAYER_STENCIL_INV) !=
+ 0);
#ifndef PROJ_DEBUG_NOSEAMBLEED
- /* pixel num to bleed */
- ps->seam_bleed_px = settings->imapaint.seam_bleed;
- ps->seam_bleed_px_sq = SQUARE(settings->imapaint.seam_bleed);
+ /* pixel num to bleed */
+ ps->seam_bleed_px = settings->imapaint.seam_bleed;
+ ps->seam_bleed_px_sq = SQUARE(settings->imapaint.seam_bleed);
#endif
- if (ps->do_mask_normal) {
- ps->normal_angle_inner = settings->imapaint.normal_angle;
- ps->normal_angle = (ps->normal_angle_inner + 90.0f) * 0.5f;
- }
- else {
- ps->normal_angle_inner = ps->normal_angle = settings->imapaint.normal_angle;
- }
+ if (ps->do_mask_normal) {
+ ps->normal_angle_inner = settings->imapaint.normal_angle;
+ ps->normal_angle = (ps->normal_angle_inner + 90.0f) * 0.5f;
+ }
+ else {
+ ps->normal_angle_inner = ps->normal_angle = settings->imapaint.normal_angle;
+ }
- ps->normal_angle_inner *= (float)(M_PI_2 / 90);
- ps->normal_angle *= (float)(M_PI_2 / 90);
- ps->normal_angle_range = ps->normal_angle - ps->normal_angle_inner;
+ ps->normal_angle_inner *= (float)(M_PI_2 / 90);
+ ps->normal_angle *= (float)(M_PI_2 / 90);
+ ps->normal_angle_range = ps->normal_angle - ps->normal_angle_inner;
- if (ps->normal_angle_range <= 0.0f) {
- /* no need to do blending */
- ps->do_mask_normal = false;
- }
+ if (ps->normal_angle_range <= 0.0f) {
+ /* no need to do blending */
+ ps->do_mask_normal = false;
+ }
- ps->normal_angle__cos = cosf(ps->normal_angle);
- ps->normal_angle_inner__cos = cosf(ps->normal_angle_inner);
+ ps->normal_angle__cos = cosf(ps->normal_angle);
+ ps->normal_angle_inner__cos = cosf(ps->normal_angle_inner);
- ps->dither = settings->imapaint.dither;
+ ps->dither = settings->imapaint.dither;
- ps->use_colormanagement = BKE_scene_check_color_management_enabled(CTX_data_scene(C));
+ ps->use_colormanagement = BKE_scene_check_color_management_enabled(CTX_data_scene(C));
- return;
+ return;
}
void *paint_proj_new_stroke(bContext *C, Object *ob, const float mouse[2], int mode)
{
- ProjStrokeHandle *ps_handle;
- Scene *scene = CTX_data_scene(C);
- ToolSettings *settings = scene->toolsettings;
- int i;
- bool is_multi_view;
- char symmetry_flag_views[ARRAY_SIZE(ps_handle->ps_views)] = {0};
-
- ps_handle = MEM_callocN(sizeof(ProjStrokeHandle), "ProjStrokeHandle");
- ps_handle->scene = scene;
- ps_handle->brush = BKE_paint_brush(&settings->imapaint.paint);
-
- /* bypass regular stroke logic */
- if ((ps_handle->brush->imagepaint_tool == PAINT_TOOL_CLONE) &&
- (mode == BRUSH_STROKE_INVERT))
- {
- view3d_operator_needs_opengl(C);
- ps_handle->is_clone_cursor_pick = true;
- return ps_handle;
- }
-
- ps_handle->orig_brush_size = BKE_brush_size_get(scene, ps_handle->brush);
-
- ps_handle->symmetry_flags = settings->imapaint.paint.symmetry_flags & PAINT_SYMM_AXIS_ALL;
- ps_handle->ps_views_tot = 1 + (pow_i(2, count_bits_i(ps_handle->symmetry_flags)) - 1);
- is_multi_view = (ps_handle->ps_views_tot != 1);
-
- for (i = 0; i < ps_handle->ps_views_tot; i++) {
- ProjPaintState *ps = MEM_callocN(sizeof(ProjPaintState), "ProjectionPaintState");
- ps_handle->ps_views[i] = ps;
- }
-
- if (ps_handle->symmetry_flags) {
- int index = 0;
-
- int x = 0;
- do {
- int y = 0;
- do {
- int z = 0;
- do {
- symmetry_flag_views[index++] = (
- (x ? PAINT_SYMM_X : 0) |
- (y ? PAINT_SYMM_Y : 0) |
- (z ? PAINT_SYMM_Z : 0));
- BLI_assert(index <= ps_handle->ps_views_tot);
- } while ((z++ == 0) && (ps_handle->symmetry_flags & PAINT_SYMM_Z));
- } while ((y++ == 0) && (ps_handle->symmetry_flags & PAINT_SYMM_Y));
- } while ((x++ == 0) && (ps_handle->symmetry_flags & PAINT_SYMM_X));
- BLI_assert(index == ps_handle->ps_views_tot);
- }
-
- for (i = 0; i < ps_handle->ps_views_tot; i++) {
- ProjPaintState *ps = ps_handle->ps_views[i];
-
- project_state_init(C, ob, ps, mode);
-
- if (ps->ob == NULL) {
- ps_handle->ps_views_tot = i + 1;
- goto fail;
- }
- }
-
- /* Don't allow brush size below 2 */
- if (BKE_brush_size_get(scene, ps_handle->brush) < 2)
- BKE_brush_size_set(scene, ps_handle->brush, 2 * U.pixelsize);
-
- /* allocate and initialize spatial data structures */
-
- for (i = 0; i < ps_handle->ps_views_tot; i++) {
- ProjPaintState *ps = ps_handle->ps_views[i];
-
- ps->source = (ps->tool == PAINT_TOOL_FILL) ? PROJ_SRC_VIEW_FILL : PROJ_SRC_VIEW;
- project_image_refresh_tagged(ps);
-
- /* re-use! */
- if (i != 0) {
- ps->is_shared_user = true;
- PROJ_PAINT_STATE_SHARED_MEMCPY(ps, ps_handle->ps_views[0]);
- }
-
- project_paint_begin(C, ps, is_multi_view, symmetry_flag_views[i]);
- if (ps->me_eval == NULL) {
- goto fail;
- }
-
- paint_proj_begin_clone(ps, mouse);
- }
-
- paint_brush_init_tex(ps_handle->brush);
-
- return ps_handle;
-
+ ProjStrokeHandle *ps_handle;
+ Scene *scene = CTX_data_scene(C);
+ ToolSettings *settings = scene->toolsettings;
+ int i;
+ bool is_multi_view;
+ char symmetry_flag_views[ARRAY_SIZE(ps_handle->ps_views)] = {0};
+
+ ps_handle = MEM_callocN(sizeof(ProjStrokeHandle), "ProjStrokeHandle");
+ ps_handle->scene = scene;
+ ps_handle->brush = BKE_paint_brush(&settings->imapaint.paint);
+
+ /* bypass regular stroke logic */
+ if ((ps_handle->brush->imagepaint_tool == PAINT_TOOL_CLONE) && (mode == BRUSH_STROKE_INVERT)) {
+ view3d_operator_needs_opengl(C);
+ ps_handle->is_clone_cursor_pick = true;
+ return ps_handle;
+ }
+
+ ps_handle->orig_brush_size = BKE_brush_size_get(scene, ps_handle->brush);
+
+ ps_handle->symmetry_flags = settings->imapaint.paint.symmetry_flags & PAINT_SYMM_AXIS_ALL;
+ ps_handle->ps_views_tot = 1 + (pow_i(2, count_bits_i(ps_handle->symmetry_flags)) - 1);
+ is_multi_view = (ps_handle->ps_views_tot != 1);
+
+ for (i = 0; i < ps_handle->ps_views_tot; i++) {
+ ProjPaintState *ps = MEM_callocN(sizeof(ProjPaintState), "ProjectionPaintState");
+ ps_handle->ps_views[i] = ps;
+ }
+
+ if (ps_handle->symmetry_flags) {
+ int index = 0;
+
+ int x = 0;
+ do {
+ int y = 0;
+ do {
+ int z = 0;
+ do {
+ symmetry_flag_views[index++] = ((x ? PAINT_SYMM_X : 0) | (y ? PAINT_SYMM_Y : 0) |
+ (z ? PAINT_SYMM_Z : 0));
+ BLI_assert(index <= ps_handle->ps_views_tot);
+ } while ((z++ == 0) && (ps_handle->symmetry_flags & PAINT_SYMM_Z));
+ } while ((y++ == 0) && (ps_handle->symmetry_flags & PAINT_SYMM_Y));
+ } while ((x++ == 0) && (ps_handle->symmetry_flags & PAINT_SYMM_X));
+ BLI_assert(index == ps_handle->ps_views_tot);
+ }
+
+ for (i = 0; i < ps_handle->ps_views_tot; i++) {
+ ProjPaintState *ps = ps_handle->ps_views[i];
+
+ project_state_init(C, ob, ps, mode);
+
+ if (ps->ob == NULL) {
+ ps_handle->ps_views_tot = i + 1;
+ goto fail;
+ }
+ }
+
+ /* Don't allow brush size below 2 */
+ if (BKE_brush_size_get(scene, ps_handle->brush) < 2)
+ BKE_brush_size_set(scene, ps_handle->brush, 2 * U.pixelsize);
+
+ /* allocate and initialize spatial data structures */
+
+ for (i = 0; i < ps_handle->ps_views_tot; i++) {
+ ProjPaintState *ps = ps_handle->ps_views[i];
+
+ ps->source = (ps->tool == PAINT_TOOL_FILL) ? PROJ_SRC_VIEW_FILL : PROJ_SRC_VIEW;
+ project_image_refresh_tagged(ps);
+
+ /* re-use! */
+ if (i != 0) {
+ ps->is_shared_user = true;
+ PROJ_PAINT_STATE_SHARED_MEMCPY(ps, ps_handle->ps_views[0]);
+ }
+
+ project_paint_begin(C, ps, is_multi_view, symmetry_flag_views[i]);
+ if (ps->me_eval == NULL) {
+ goto fail;
+ }
+
+ paint_proj_begin_clone(ps, mouse);
+ }
+
+ paint_brush_init_tex(ps_handle->brush);
+
+ return ps_handle;
fail:
- for (i = 0; i < ps_handle->ps_views_tot; i++) {
- ProjPaintState *ps = ps_handle->ps_views[i];
- MEM_freeN(ps);
- }
- MEM_freeN(ps_handle);
- return NULL;
+ for (i = 0; i < ps_handle->ps_views_tot; i++) {
+ ProjPaintState *ps = ps_handle->ps_views[i];
+ MEM_freeN(ps);
+ }
+ MEM_freeN(ps_handle);
+ return NULL;
}
void paint_proj_redraw(const bContext *C, void *ps_handle_p, bool final)
{
- ProjStrokeHandle *ps_handle = ps_handle_p;
-
- if (ps_handle->need_redraw) {
- ps_handle->need_redraw = false;
- }
- else if (!final) {
- return;
- }
-
- if (final) {
- /* compositor listener deals with updating */
- WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, NULL);
- }
- else {
- ED_region_tag_redraw(CTX_wm_region(C));
- }
+ ProjStrokeHandle *ps_handle = ps_handle_p;
+
+ if (ps_handle->need_redraw) {
+ ps_handle->need_redraw = false;
+ }
+ else if (!final) {
+ return;
+ }
+
+ if (final) {
+ /* compositor listener deals with updating */
+ WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, NULL);
+ }
+ else {
+ ED_region_tag_redraw(CTX_wm_region(C));
+ }
}
void paint_proj_stroke_done(void *ps_handle_p)
{
- ProjStrokeHandle *ps_handle = ps_handle_p;
- Scene *scene = ps_handle->scene;
- int i;
+ ProjStrokeHandle *ps_handle = ps_handle_p;
+ Scene *scene = ps_handle->scene;
+ int i;
- if (ps_handle->is_clone_cursor_pick) {
- MEM_freeN(ps_handle);
- return;
- }
+ if (ps_handle->is_clone_cursor_pick) {
+ MEM_freeN(ps_handle);
+ return;
+ }
- for (i = 1; i < ps_handle->ps_views_tot; i++) {
- PROJ_PAINT_STATE_SHARED_CLEAR(ps_handle->ps_views[i]);
- }
+ for (i = 1; i < ps_handle->ps_views_tot; i++) {
+ PROJ_PAINT_STATE_SHARED_CLEAR(ps_handle->ps_views[i]);
+ }
- BKE_brush_size_set(scene, ps_handle->brush, ps_handle->orig_brush_size);
+ BKE_brush_size_set(scene, ps_handle->brush, ps_handle->orig_brush_size);
- paint_brush_exit_tex(ps_handle->brush);
+ paint_brush_exit_tex(ps_handle->brush);
- for (i = 0; i < ps_handle->ps_views_tot; i++) {
- ProjPaintState *ps;
- ps = ps_handle->ps_views[i];
- project_paint_end(ps);
- MEM_freeN(ps);
+ for (i = 0; i < ps_handle->ps_views_tot; i++) {
+ ProjPaintState *ps;
+ ps = ps_handle->ps_views[i];
+ project_paint_end(ps);
+ MEM_freeN(ps);
+ }
- }
-
- MEM_freeN(ps_handle);
+ MEM_freeN(ps_handle);
}
/* use project paint to re-apply an image */
static int texture_paint_camera_project_exec(bContext *C, wmOperator *op)
{
- Image *image = BLI_findlink(&CTX_data_main(C)->images, RNA_enum_get(op->ptr, "image"));
- Scene *scene = CTX_data_scene(C);
- ViewLayer *view_layer = CTX_data_view_layer(C);
- ProjPaintState ps = {NULL};
- int orig_brush_size;
- IDProperty *idgroup;
- IDProperty *view_data = NULL;
- Object *ob = OBACT(view_layer);
- bool uvs, mat, tex;
-
- if (ob == NULL || ob->type != OB_MESH) {
- BKE_report(op->reports, RPT_ERROR, "No active mesh object");
- return OPERATOR_CANCELLED;
- }
-
- if (!BKE_paint_proj_mesh_data_check(scene, ob, &uvs, &mat, &tex, NULL)) {
- BKE_paint_data_warning(op->reports, uvs, mat, tex, true);
- WM_event_add_notifier(C, NC_SCENE | ND_TOOLSETTINGS, NULL);
- return OPERATOR_CANCELLED;
- }
-
- project_state_init(C, ob, &ps, BRUSH_STROKE_NORMAL);
-
- if (image == NULL) {
- BKE_report(op->reports, RPT_ERROR, "Image could not be found");
- return OPERATOR_CANCELLED;
- }
-
- ps.reproject_image = image;
- ps.reproject_ibuf = BKE_image_acquire_ibuf(image, NULL, NULL);
-
- if ((ps.reproject_ibuf == NULL) ||
- ((ps.reproject_ibuf->rect || ps.reproject_ibuf->rect_float) == false))
- {
- BKE_report(op->reports, RPT_ERROR, "Image data could not be found");
- return OPERATOR_CANCELLED;
- }
-
- idgroup = IDP_GetProperties(&image->id, 0);
-
- if (idgroup) {
- view_data = IDP_GetPropertyTypeFromGroup(idgroup, PROJ_VIEW_DATA_ID, IDP_ARRAY);
-
- /* type check to make sure its ok */
- if (view_data->len != PROJ_VIEW_DATA_SIZE || view_data->subtype != IDP_FLOAT) {
- BKE_report(op->reports, RPT_ERROR, "Image project data invalid");
- return OPERATOR_CANCELLED;
- }
- }
-
- if (view_data) {
- /* image has stored view projection info */
- ps.source = PROJ_SRC_IMAGE_VIEW;
- }
- else {
- ps.source = PROJ_SRC_IMAGE_CAM;
-
- if (scene->camera == NULL) {
- BKE_report(op->reports, RPT_ERROR, "No active camera set");
- return OPERATOR_CANCELLED;
- }
- }
-
- /* override */
- ps.is_texbrush = false;
- ps.is_maskbrush = false;
- ps.do_masking = false;
- orig_brush_size = BKE_brush_size_get(scene, ps.brush);
- /* cover the whole image */
- BKE_brush_size_set(scene, ps.brush, 32 * U.pixelsize);
-
- /* so pixels are initialized with minimal info */
- ps.tool = PAINT_TOOL_DRAW;
-
- scene->toolsettings->imapaint.flag |= IMAGEPAINT_DRAWING;
-
- ED_image_undo_push_begin(op->type->name, PAINT_MODE_TEXTURE_3D);
-
- /* allocate and initialize spatial data structures */
- project_paint_begin(C, &ps, false, 0);
-
- if (ps.me_eval == NULL) {
- BKE_brush_size_set(scene, ps.brush, orig_brush_size);
- BKE_report(op->reports, RPT_ERROR, "Could not get valid evaluated mesh");
- return OPERATOR_CANCELLED;
- }
- else {
- float pos[2] = {0.0, 0.0};
- float lastpos[2] = {0.0, 0.0};
- int a;
-
- project_paint_op(&ps, lastpos, pos);
-
- project_image_refresh_tagged(&ps);
-
- for (a = 0; a < ps.image_tot; a++) {
- GPU_free_image(ps.projImages[a].ima);
- WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, ps.projImages[a].ima);
- }
- }
-
- project_paint_end(&ps);
-
- scene->toolsettings->imapaint.flag &= ~IMAGEPAINT_DRAWING;
- BKE_brush_size_set(scene, ps.brush, orig_brush_size);
-
- return OPERATOR_FINISHED;
+ Image *image = BLI_findlink(&CTX_data_main(C)->images, RNA_enum_get(op->ptr, "image"));
+ Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ ProjPaintState ps = {NULL};
+ int orig_brush_size;
+ IDProperty *idgroup;
+ IDProperty *view_data = NULL;
+ Object *ob = OBACT(view_layer);
+ bool uvs, mat, tex;
+
+ if (ob == NULL || ob->type != OB_MESH) {
+ BKE_report(op->reports, RPT_ERROR, "No active mesh object");
+ return OPERATOR_CANCELLED;
+ }
+
+ if (!BKE_paint_proj_mesh_data_check(scene, ob, &uvs, &mat, &tex, NULL)) {
+ BKE_paint_data_warning(op->reports, uvs, mat, tex, true);
+ WM_event_add_notifier(C, NC_SCENE | ND_TOOLSETTINGS, NULL);
+ return OPERATOR_CANCELLED;
+ }
+
+ project_state_init(C, ob, &ps, BRUSH_STROKE_NORMAL);
+
+ if (image == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "Image could not be found");
+ return OPERATOR_CANCELLED;
+ }
+
+ ps.reproject_image = image;
+ ps.reproject_ibuf = BKE_image_acquire_ibuf(image, NULL, NULL);
+
+ if ((ps.reproject_ibuf == NULL) ||
+ ((ps.reproject_ibuf->rect || ps.reproject_ibuf->rect_float) == false)) {
+ BKE_report(op->reports, RPT_ERROR, "Image data could not be found");
+ return OPERATOR_CANCELLED;
+ }
+
+ idgroup = IDP_GetProperties(&image->id, 0);
+
+ if (idgroup) {
+ view_data = IDP_GetPropertyTypeFromGroup(idgroup, PROJ_VIEW_DATA_ID, IDP_ARRAY);
+
+ /* type check to make sure its ok */
+ if (view_data->len != PROJ_VIEW_DATA_SIZE || view_data->subtype != IDP_FLOAT) {
+ BKE_report(op->reports, RPT_ERROR, "Image project data invalid");
+ return OPERATOR_CANCELLED;
+ }
+ }
+
+ if (view_data) {
+ /* image has stored view projection info */
+ ps.source = PROJ_SRC_IMAGE_VIEW;
+ }
+ else {
+ ps.source = PROJ_SRC_IMAGE_CAM;
+
+ if (scene->camera == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "No active camera set");
+ return OPERATOR_CANCELLED;
+ }
+ }
+
+ /* override */
+ ps.is_texbrush = false;
+ ps.is_maskbrush = false;
+ ps.do_masking = false;
+ orig_brush_size = BKE_brush_size_get(scene, ps.brush);
+ /* cover the whole image */
+ BKE_brush_size_set(scene, ps.brush, 32 * U.pixelsize);
+
+ /* so pixels are initialized with minimal info */
+ ps.tool = PAINT_TOOL_DRAW;
+
+ scene->toolsettings->imapaint.flag |= IMAGEPAINT_DRAWING;
+
+ ED_image_undo_push_begin(op->type->name, PAINT_MODE_TEXTURE_3D);
+
+ /* allocate and initialize spatial data structures */
+ project_paint_begin(C, &ps, false, 0);
+
+ if (ps.me_eval == NULL) {
+ BKE_brush_size_set(scene, ps.brush, orig_brush_size);
+ BKE_report(op->reports, RPT_ERROR, "Could not get valid evaluated mesh");
+ return OPERATOR_CANCELLED;
+ }
+ else {
+ float pos[2] = {0.0, 0.0};
+ float lastpos[2] = {0.0, 0.0};
+ int a;
+
+ project_paint_op(&ps, lastpos, pos);
+
+ project_image_refresh_tagged(&ps);
+
+ for (a = 0; a < ps.image_tot; a++) {
+ GPU_free_image(ps.projImages[a].ima);
+ WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, ps.projImages[a].ima);
+ }
+ }
+
+ project_paint_end(&ps);
+
+ scene->toolsettings->imapaint.flag &= ~IMAGEPAINT_DRAWING;
+ BKE_brush_size_set(scene, ps.brush, orig_brush_size);
+
+ return OPERATOR_FINISHED;
}
void PAINT_OT_project_image(wmOperatorType *ot)
{
- PropertyRNA *prop;
+ PropertyRNA *prop;
- /* identifiers */
- ot->name = "Project Image";
- ot->idname = "PAINT_OT_project_image";
- ot->description = "Project an edited render from the active camera back onto the object";
+ /* identifiers */
+ ot->name = "Project Image";
+ ot->idname = "PAINT_OT_project_image";
+ ot->description = "Project an edited render from the active camera back onto the object";
- /* api callbacks */
- ot->invoke = WM_enum_search_invoke;
- ot->exec = texture_paint_camera_project_exec;
+ /* api callbacks */
+ ot->invoke = WM_enum_search_invoke;
+ ot->exec = texture_paint_camera_project_exec;
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- prop = RNA_def_enum(ot->srna, "image", DummyRNA_NULL_items, 0, "Image", "");
- RNA_def_enum_funcs(prop, RNA_image_itemf);
- RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE);
- ot->prop = prop;
+ prop = RNA_def_enum(ot->srna, "image", DummyRNA_NULL_items, 0, "Image", "");
+ RNA_def_enum_funcs(prop, RNA_image_itemf);
+ RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE);
+ ot->prop = prop;
}
static bool texture_paint_image_from_view_poll(bContext *C)
{
- if (BKE_screen_find_big_area(CTX_wm_screen(C), SPACE_VIEW3D, 0) == NULL) {
- CTX_wm_operator_poll_msg_set(C, "No 3D viewport found to create image from");
- return false;
- }
- return true;
+ if (BKE_screen_find_big_area(CTX_wm_screen(C), SPACE_VIEW3D, 0) == NULL) {
+ CTX_wm_operator_poll_msg_set(C, "No 3D viewport found to create image from");
+ return false;
+ }
+ return true;
}
static int texture_paint_image_from_view_exec(bContext *C, wmOperator *op)
{
- Image *image;
- ImBuf *ibuf;
- char filename[FILE_MAX];
-
- Main *bmain = CTX_data_main(C);
- Depsgraph *depsgraph = CTX_data_depsgraph(C);
- Scene *scene = CTX_data_scene(C);
- ToolSettings *settings = scene->toolsettings;
- int w = settings->imapaint.screen_grab_size[0];
- int h = settings->imapaint.screen_grab_size[1];
- int maxsize;
- char err_out[256] = "unknown";
-
- ScrArea *sa = BKE_screen_find_big_area(CTX_wm_screen(C), SPACE_VIEW3D, 0);
- if (!sa) {
- BKE_report(op->reports, RPT_ERROR, "No 3D viewport found to create image from");
- return OPERATOR_CANCELLED;
- }
- View3D *v3d = sa->spacedata.first;
- ARegion *ar = BKE_area_find_region_active_win(sa);
- if (!ar) {
- BKE_report(op->reports, RPT_ERROR, "No 3D viewport found to create image from");
- return OPERATOR_CANCELLED;
- }
- RegionView3D *rv3d = ar->regiondata;
-
- RNA_string_get(op->ptr, "filepath", filename);
-
- maxsize = GPU_max_texture_size();
-
- if (w > maxsize) w = maxsize;
- if (h > maxsize) h = maxsize;
-
- ibuf = ED_view3d_draw_offscreen_imbuf(
- depsgraph, scene, v3d->shading.type,
- v3d, ar,
- w, h, IB_rect, V3D_OFSDRAW_NONE, R_ALPHAPREMUL, 0, NULL,
- NULL, err_out);
- if (!ibuf) {
- /* Mostly happens when OpenGL offscreen buffer was failed to create, */
- /* but could be other reasons. Should be handled in the future. nazgul */
- BKE_reportf(op->reports, RPT_ERROR, "Failed to create OpenGL off-screen buffer: %s", err_out);
- return OPERATOR_CANCELLED;
- }
-
- image = BKE_image_add_from_imbuf(bmain, ibuf, "image_view");
-
- /* Drop reference to ibuf so that the image owns it */
- IMB_freeImBuf(ibuf);
-
- if (image) {
- /* now for the trickiness. store the view projection here!
- * re-projection will reuse this */
- IDPropertyTemplate val;
- IDProperty *idgroup = IDP_GetProperties(&image->id, 1);
- IDProperty *view_data;
- bool is_ortho;
- float *array;
-
- val.array.len = PROJ_VIEW_DATA_SIZE;
- val.array.type = IDP_FLOAT;
- view_data = IDP_New(IDP_ARRAY, &val, PROJ_VIEW_DATA_ID);
-
- array = (float *)IDP_Array(view_data);
- memcpy(array, rv3d->winmat, sizeof(rv3d->winmat)); array += sizeof(rv3d->winmat) / sizeof(float);
- memcpy(array, rv3d->viewmat, sizeof(rv3d->viewmat)); array += sizeof(rv3d->viewmat) / sizeof(float);
- is_ortho = ED_view3d_clip_range_get(CTX_data_depsgraph(C), v3d, rv3d, &array[0], &array[1], true);
- /* using float for a bool is dodgy but since its an extra member in the array...
- * easier then adding a single bool prop */
- array[2] = is_ortho ? 1.0f : 0.0f;
-
- IDP_AddToGroup(idgroup, view_data);
- }
-
- return OPERATOR_FINISHED;
+ Image *image;
+ ImBuf *ibuf;
+ char filename[FILE_MAX];
+
+ Main *bmain = CTX_data_main(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ Scene *scene = CTX_data_scene(C);
+ ToolSettings *settings = scene->toolsettings;
+ int w = settings->imapaint.screen_grab_size[0];
+ int h = settings->imapaint.screen_grab_size[1];
+ int maxsize;
+ char err_out[256] = "unknown";
+
+ ScrArea *sa = BKE_screen_find_big_area(CTX_wm_screen(C), SPACE_VIEW3D, 0);
+ if (!sa) {
+ BKE_report(op->reports, RPT_ERROR, "No 3D viewport found to create image from");
+ return OPERATOR_CANCELLED;
+ }
+ View3D *v3d = sa->spacedata.first;
+ ARegion *ar = BKE_area_find_region_active_win(sa);
+ if (!ar) {
+ BKE_report(op->reports, RPT_ERROR, "No 3D viewport found to create image from");
+ return OPERATOR_CANCELLED;
+ }
+ RegionView3D *rv3d = ar->regiondata;
+
+ RNA_string_get(op->ptr, "filepath", filename);
+
+ maxsize = GPU_max_texture_size();
+
+ if (w > maxsize)
+ w = maxsize;
+ if (h > maxsize)
+ h = maxsize;
+
+ ibuf = ED_view3d_draw_offscreen_imbuf(depsgraph,
+ scene,
+ v3d->shading.type,
+ v3d,
+ ar,
+ w,
+ h,
+ IB_rect,
+ V3D_OFSDRAW_NONE,
+ R_ALPHAPREMUL,
+ 0,
+ NULL,
+ NULL,
+ err_out);
+ if (!ibuf) {
+ /* Mostly happens when OpenGL offscreen buffer was failed to create, */
+ /* but could be other reasons. Should be handled in the future. nazgul */
+ BKE_reportf(op->reports, RPT_ERROR, "Failed to create OpenGL off-screen buffer: %s", err_out);
+ return OPERATOR_CANCELLED;
+ }
+
+ image = BKE_image_add_from_imbuf(bmain, ibuf, "image_view");
+
+ /* Drop reference to ibuf so that the image owns it */
+ IMB_freeImBuf(ibuf);
+
+ if (image) {
+ /* now for the trickiness. store the view projection here!
+ * re-projection will reuse this */
+ IDPropertyTemplate val;
+ IDProperty *idgroup = IDP_GetProperties(&image->id, 1);
+ IDProperty *view_data;
+ bool is_ortho;
+ float *array;
+
+ val.array.len = PROJ_VIEW_DATA_SIZE;
+ val.array.type = IDP_FLOAT;
+ view_data = IDP_New(IDP_ARRAY, &val, PROJ_VIEW_DATA_ID);
+
+ array = (float *)IDP_Array(view_data);
+ memcpy(array, rv3d->winmat, sizeof(rv3d->winmat));
+ array += sizeof(rv3d->winmat) / sizeof(float);
+ memcpy(array, rv3d->viewmat, sizeof(rv3d->viewmat));
+ array += sizeof(rv3d->viewmat) / sizeof(float);
+ is_ortho = ED_view3d_clip_range_get(
+ CTX_data_depsgraph(C), v3d, rv3d, &array[0], &array[1], true);
+ /* using float for a bool is dodgy but since its an extra member in the array...
+ * easier then adding a single bool prop */
+ array[2] = is_ortho ? 1.0f : 0.0f;
+
+ IDP_AddToGroup(idgroup, view_data);
+ }
+
+ return OPERATOR_FINISHED;
}
void PAINT_OT_image_from_view(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Image from View";
- ot->idname = "PAINT_OT_image_from_view";
- ot->description = "Make an image from biggest 3D view for re-projection";
+ /* identifiers */
+ ot->name = "Image from View";
+ ot->idname = "PAINT_OT_image_from_view";
+ ot->description = "Make an image from biggest 3D view for re-projection";
- /* api callbacks */
- ot->exec = texture_paint_image_from_view_exec;
- ot->poll = texture_paint_image_from_view_poll;
+ /* api callbacks */
+ ot->exec = texture_paint_image_from_view_exec;
+ ot->poll = texture_paint_image_from_view_poll;
- /* flags */
- ot->flag = OPTYPE_REGISTER;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER;
- RNA_def_string_file_name(ot->srna, "filepath", NULL, FILE_MAX, "File Path", "Name of the file");
+ RNA_def_string_file_name(ot->srna, "filepath", NULL, FILE_MAX, "File Path", "Name of the file");
}
/*********************************************
@@ -5953,462 +6158,476 @@ void PAINT_OT_image_from_view(wmOperatorType *ot)
void BKE_paint_data_warning(struct ReportList *reports, bool uvs, bool mat, bool tex, bool stencil)
{
- BKE_reportf(
- reports, RPT_WARNING, "Missing%s%s%s%s detected!",
- !uvs ? " UVs," : "",
- !mat ? " Materials," : "",
- !tex ? " Textures," : "",
- !stencil ? " Stencil," : ""
- );
+ BKE_reportf(reports,
+ RPT_WARNING,
+ "Missing%s%s%s%s detected!",
+ !uvs ? " UVs," : "",
+ !mat ? " Materials," : "",
+ !tex ? " Textures," : "",
+ !stencil ? " Stencil," : "");
}
/* Make sure that active object has a material,
* and assign UVs and image layers if they do not exist */
-bool BKE_paint_proj_mesh_data_check(Scene *scene, Object *ob, bool *uvs, bool *mat, bool *tex, bool *stencil)
+bool BKE_paint_proj_mesh_data_check(
+ Scene *scene, Object *ob, bool *uvs, bool *mat, bool *tex, bool *stencil)
{
- Mesh *me;
- int layernum;
- ImagePaintSettings *imapaint = &scene->toolsettings->imapaint;
- Brush *br = BKE_paint_brush(&imapaint->paint);
- bool hasmat = true;
- bool hastex = true;
- bool hasstencil = true;
- bool hasuvs = true;
-
- imapaint->missing_data = 0;
-
- BLI_assert(ob->type == OB_MESH);
-
- if (imapaint->mode == IMAGEPAINT_MODE_MATERIAL) {
- /* no material, add one */
- if (ob->totcol == 0) {
- hasmat = false;
- hastex = false;
- }
- else {
- /* there may be material slots but they may be empty, check */
- int i;
- hasmat = false;
- hastex = false;
-
- for (i = 1; i < ob->totcol + 1; i++) {
- Material *ma = give_current_material(ob, i);
-
- if (ma) {
- hasmat = true;
- if (!ma->texpaintslot) {
- /* refresh here just in case */
- BKE_texpaint_slot_refresh_cache(scene, ma);
-
- /* if still no slots, we have to add */
- if (ma->texpaintslot) {
- hastex = true;
- break;
- }
- }
- else {
- hastex = true;
- break;
- }
- }
- }
- }
- }
- else if (imapaint->mode == IMAGEPAINT_MODE_IMAGE) {
- if (imapaint->canvas == NULL) {
- hastex = false;
- }
- }
-
- me = BKE_mesh_from_object(ob);
- layernum = CustomData_number_of_layers(&me->ldata, CD_MLOOPUV);
-
- if (layernum == 0) {
- hasuvs = false;
- }
-
- /* Make sure we have a stencil to paint on! */
- if (br && br->imagepaint_tool == PAINT_TOOL_MASK) {
- imapaint->flag |= IMAGEPAINT_PROJECT_LAYER_STENCIL;
-
- if (imapaint->stencil == NULL) {
- hasstencil = false;
- }
- }
-
- if (!hasuvs) imapaint->missing_data |= IMAGEPAINT_MISSING_UVS;
- if (!hasmat) imapaint->missing_data |= IMAGEPAINT_MISSING_MATERIAL;
- if (!hastex) imapaint->missing_data |= IMAGEPAINT_MISSING_TEX;
- if (!hasstencil) imapaint->missing_data |= IMAGEPAINT_MISSING_STENCIL;
-
- if (uvs) {
- *uvs = hasuvs;
- }
- if (mat) {
- *mat = hasmat;
- }
- if (tex) {
- *tex = hastex;
- }
- if (stencil) {
- *stencil = hasstencil;
- }
-
- return hasuvs && hasmat && hastex && hasstencil;
+ Mesh *me;
+ int layernum;
+ ImagePaintSettings *imapaint = &scene->toolsettings->imapaint;
+ Brush *br = BKE_paint_brush(&imapaint->paint);
+ bool hasmat = true;
+ bool hastex = true;
+ bool hasstencil = true;
+ bool hasuvs = true;
+
+ imapaint->missing_data = 0;
+
+ BLI_assert(ob->type == OB_MESH);
+
+ if (imapaint->mode == IMAGEPAINT_MODE_MATERIAL) {
+ /* no material, add one */
+ if (ob->totcol == 0) {
+ hasmat = false;
+ hastex = false;
+ }
+ else {
+ /* there may be material slots but they may be empty, check */
+ int i;
+ hasmat = false;
+ hastex = false;
+
+ for (i = 1; i < ob->totcol + 1; i++) {
+ Material *ma = give_current_material(ob, i);
+
+ if (ma) {
+ hasmat = true;
+ if (!ma->texpaintslot) {
+ /* refresh here just in case */
+ BKE_texpaint_slot_refresh_cache(scene, ma);
+
+ /* if still no slots, we have to add */
+ if (ma->texpaintslot) {
+ hastex = true;
+ break;
+ }
+ }
+ else {
+ hastex = true;
+ break;
+ }
+ }
+ }
+ }
+ }
+ else if (imapaint->mode == IMAGEPAINT_MODE_IMAGE) {
+ if (imapaint->canvas == NULL) {
+ hastex = false;
+ }
+ }
+
+ me = BKE_mesh_from_object(ob);
+ layernum = CustomData_number_of_layers(&me->ldata, CD_MLOOPUV);
+
+ if (layernum == 0) {
+ hasuvs = false;
+ }
+
+ /* Make sure we have a stencil to paint on! */
+ if (br && br->imagepaint_tool == PAINT_TOOL_MASK) {
+ imapaint->flag |= IMAGEPAINT_PROJECT_LAYER_STENCIL;
+
+ if (imapaint->stencil == NULL) {
+ hasstencil = false;
+ }
+ }
+
+ if (!hasuvs)
+ imapaint->missing_data |= IMAGEPAINT_MISSING_UVS;
+ if (!hasmat)
+ imapaint->missing_data |= IMAGEPAINT_MISSING_MATERIAL;
+ if (!hastex)
+ imapaint->missing_data |= IMAGEPAINT_MISSING_TEX;
+ if (!hasstencil)
+ imapaint->missing_data |= IMAGEPAINT_MISSING_STENCIL;
+
+ if (uvs) {
+ *uvs = hasuvs;
+ }
+ if (mat) {
+ *mat = hasmat;
+ }
+ if (tex) {
+ *tex = hastex;
+ }
+ if (stencil) {
+ *stencil = hasstencil;
+ }
+
+ return hasuvs && hasmat && hastex && hasstencil;
}
/* Add layer operator */
enum {
- LAYER_BASE_COLOR,
- LAYER_SPECULAR,
- LAYER_ROUGHNESS,
- LAYER_METALLIC,
- LAYER_NORMAL,
- LAYER_BUMP,
- LAYER_DISPLACEMENT,
+ LAYER_BASE_COLOR,
+ LAYER_SPECULAR,
+ LAYER_ROUGHNESS,
+ LAYER_METALLIC,
+ LAYER_NORMAL,
+ LAYER_BUMP,
+ LAYER_DISPLACEMENT,
};
static const EnumPropertyItem layer_type_items[] = {
- {LAYER_BASE_COLOR, "BASE_COLOR", 0, "Base Color", ""},
- {LAYER_SPECULAR, "SPECULAR", 0, "Specular", ""},
- {LAYER_ROUGHNESS, "ROUGHNESS", 0, "Roughness", ""},
- {LAYER_METALLIC, "METALLIC", 0, "Metallic", ""},
- {LAYER_NORMAL, "NORMAL", 0, "Normal", ""},
- {LAYER_BUMP, "BUMP", 0, "Bump", ""},
- {LAYER_DISPLACEMENT, "DISPLACEMENT", 0, "Displacement", ""},
- {0, NULL, 0, NULL, NULL},
+ {LAYER_BASE_COLOR, "BASE_COLOR", 0, "Base Color", ""},
+ {LAYER_SPECULAR, "SPECULAR", 0, "Specular", ""},
+ {LAYER_ROUGHNESS, "ROUGHNESS", 0, "Roughness", ""},
+ {LAYER_METALLIC, "METALLIC", 0, "Metallic", ""},
+ {LAYER_NORMAL, "NORMAL", 0, "Normal", ""},
+ {LAYER_BUMP, "BUMP", 0, "Bump", ""},
+ {LAYER_DISPLACEMENT, "DISPLACEMENT", 0, "Displacement", ""},
+ {0, NULL, 0, NULL, NULL},
};
static Image *proj_paint_image_create(wmOperator *op, Main *bmain)
{
- Image *ima;
- float color[4] = {0.0f, 0.0f, 0.0f, 1.0f};
- char imagename[MAX_ID_NAME - 2] = "Material Diffuse Color";
- int width = 1024;
- int height = 1024;
- bool use_float = false;
- short gen_type = IMA_GENTYPE_BLANK;
- bool alpha = false;
-
- if (op) {
- width = RNA_int_get(op->ptr, "width");
- height = RNA_int_get(op->ptr, "height");
- use_float = RNA_boolean_get(op->ptr, "float");
- gen_type = RNA_enum_get(op->ptr, "generated_type");
- RNA_float_get_array(op->ptr, "color", color);
- alpha = RNA_boolean_get(op->ptr, "alpha");
- RNA_string_get(op->ptr, "name", imagename);
- }
- ima = BKE_image_add_generated(
- bmain, width, height, imagename, alpha ? 32 : 24, use_float,
- gen_type, color, false);
-
- return ima;
+ Image *ima;
+ float color[4] = {0.0f, 0.0f, 0.0f, 1.0f};
+ char imagename[MAX_ID_NAME - 2] = "Material Diffuse Color";
+ int width = 1024;
+ int height = 1024;
+ bool use_float = false;
+ short gen_type = IMA_GENTYPE_BLANK;
+ bool alpha = false;
+
+ if (op) {
+ width = RNA_int_get(op->ptr, "width");
+ height = RNA_int_get(op->ptr, "height");
+ use_float = RNA_boolean_get(op->ptr, "float");
+ gen_type = RNA_enum_get(op->ptr, "generated_type");
+ RNA_float_get_array(op->ptr, "color", color);
+ alpha = RNA_boolean_get(op->ptr, "alpha");
+ RNA_string_get(op->ptr, "name", imagename);
+ }
+ ima = BKE_image_add_generated(
+ bmain, width, height, imagename, alpha ? 32 : 24, use_float, gen_type, color, false);
+
+ return ima;
}
static void proj_paint_default_color(wmOperator *op, int type, Material *ma)
{
- if (RNA_struct_property_is_set(op->ptr, "color")) {
- return;
- }
-
- bNode *in_node = ntreeFindType(ma->nodetree, SH_NODE_BSDF_PRINCIPLED);
- if (in_node == NULL) {
- return;
- }
-
- float color[4];
-
- if (type >= LAYER_BASE_COLOR && type < LAYER_NORMAL) {
- /* Copy color from node, so result is unchanged after assigning textures. */
- bNodeSocket *in_sock = nodeFindSocket(in_node, SOCK_IN, layer_type_items[type].name);
-
- switch (in_sock->type) {
- case SOCK_FLOAT: {
- bNodeSocketValueFloat *socket_data = in_sock->default_value;
- copy_v3_fl(color, socket_data->value);
- color[3] = 1.0f;
- break;
- }
- case SOCK_VECTOR:
- case SOCK_RGBA: {
- bNodeSocketValueRGBA *socket_data = in_sock->default_value;
- copy_v3_v3(color, socket_data->value);
- color[3] = 1.0f;
- break;
- }
- default: {
- return;
- }
- }
- }
- else if (type == LAYER_NORMAL) {
- /* Neutral tangent space normal map. */
- rgba_float_args_set(color, 0.5f, 0.5f, 1.0f, 1.0f);
- }
- else if (ELEM(type, LAYER_BUMP, LAYER_DISPLACEMENT)) {
- /* Neutral displacement and bump map. */
- rgba_float_args_set(color, 0.5f, 0.5f, 0.5f, 1.0f);
- }
- else {
- return;
- }
-
- RNA_float_set_array(op->ptr, "color", color);
+ if (RNA_struct_property_is_set(op->ptr, "color")) {
+ return;
+ }
+
+ bNode *in_node = ntreeFindType(ma->nodetree, SH_NODE_BSDF_PRINCIPLED);
+ if (in_node == NULL) {
+ return;
+ }
+
+ float color[4];
+
+ if (type >= LAYER_BASE_COLOR && type < LAYER_NORMAL) {
+ /* Copy color from node, so result is unchanged after assigning textures. */
+ bNodeSocket *in_sock = nodeFindSocket(in_node, SOCK_IN, layer_type_items[type].name);
+
+ switch (in_sock->type) {
+ case SOCK_FLOAT: {
+ bNodeSocketValueFloat *socket_data = in_sock->default_value;
+ copy_v3_fl(color, socket_data->value);
+ color[3] = 1.0f;
+ break;
+ }
+ case SOCK_VECTOR:
+ case SOCK_RGBA: {
+ bNodeSocketValueRGBA *socket_data = in_sock->default_value;
+ copy_v3_v3(color, socket_data->value);
+ color[3] = 1.0f;
+ break;
+ }
+ default: {
+ return;
+ }
+ }
+ }
+ else if (type == LAYER_NORMAL) {
+ /* Neutral tangent space normal map. */
+ rgba_float_args_set(color, 0.5f, 0.5f, 1.0f, 1.0f);
+ }
+ else if (ELEM(type, LAYER_BUMP, LAYER_DISPLACEMENT)) {
+ /* Neutral displacement and bump map. */
+ rgba_float_args_set(color, 0.5f, 0.5f, 0.5f, 1.0f);
+ }
+ else {
+ return;
+ }
+
+ RNA_float_set_array(op->ptr, "color", color);
}
static bool proj_paint_add_slot(bContext *C, wmOperator *op)
{
- Object *ob = ED_object_active_context(C);
- Scene *scene = CTX_data_scene(C);
- Material *ma;
- Image *ima = NULL;
-
- if (!ob)
- return false;
-
- ma = give_current_material(ob, ob->actcol);
+ Object *ob = ED_object_active_context(C);
+ Scene *scene = CTX_data_scene(C);
+ Material *ma;
+ Image *ima = NULL;
+
+ if (!ob)
+ return false;
+
+ ma = give_current_material(ob, ob->actcol);
- if (ma) {
- Main *bmain = CTX_data_main(C);
- int type = RNA_enum_get(op->ptr, "type");
+ if (ma) {
+ Main *bmain = CTX_data_main(C);
+ int type = RNA_enum_get(op->ptr, "type");
- bNode *imanode;
- bNodeTree *ntree = ma->nodetree;
+ bNode *imanode;
+ bNodeTree *ntree = ma->nodetree;
- if (!ntree) {
- ED_node_shader_default(C, &ma->id);
- ntree = ma->nodetree;
- }
+ if (!ntree) {
+ ED_node_shader_default(C, &ma->id);
+ ntree = ma->nodetree;
+ }
- ma->use_nodes = true;
+ ma->use_nodes = true;
- /* try to add an image node */
- imanode = nodeAddStaticNode(C, ntree, SH_NODE_TEX_IMAGE);
+ /* try to add an image node */
+ imanode = nodeAddStaticNode(C, ntree, SH_NODE_TEX_IMAGE);
- ima = proj_paint_image_create(op, bmain);
- imanode->id = &ima->id;
+ ima = proj_paint_image_create(op, bmain);
+ imanode->id = &ima->id;
- nodeSetActive(ntree, imanode);
+ nodeSetActive(ntree, imanode);
- /* Connect to first available principled bsdf node. */
- bNode *in_node = ntreeFindType(ntree, SH_NODE_BSDF_PRINCIPLED);
- bNode *out_node = imanode;
+ /* Connect to first available principled bsdf node. */
+ bNode *in_node = ntreeFindType(ntree, SH_NODE_BSDF_PRINCIPLED);
+ bNode *out_node = imanode;
- if (in_node != NULL) {
- bNodeSocket *out_sock = nodeFindSocket(out_node, SOCK_OUT, "Color");
- bNodeSocket *in_sock = NULL;
+ if (in_node != NULL) {
+ bNodeSocket *out_sock = nodeFindSocket(out_node, SOCK_OUT, "Color");
+ bNodeSocket *in_sock = NULL;
- if (type >= LAYER_BASE_COLOR && type < LAYER_NORMAL) {
- in_sock = nodeFindSocket(in_node, SOCK_IN, layer_type_items[type].name);
- }
- else if (type == LAYER_NORMAL) {
- bNode *nor_node;
- nor_node = nodeAddStaticNode(C, ntree, SH_NODE_NORMAL_MAP);
+ if (type >= LAYER_BASE_COLOR && type < LAYER_NORMAL) {
+ in_sock = nodeFindSocket(in_node, SOCK_IN, layer_type_items[type].name);
+ }
+ else if (type == LAYER_NORMAL) {
+ bNode *nor_node;
+ nor_node = nodeAddStaticNode(C, ntree, SH_NODE_NORMAL_MAP);
- in_sock = nodeFindSocket(nor_node, SOCK_IN, "Color");
- nodeAddLink(ntree, out_node, out_sock, nor_node, in_sock);
+ in_sock = nodeFindSocket(nor_node, SOCK_IN, "Color");
+ nodeAddLink(ntree, out_node, out_sock, nor_node, in_sock);
- in_sock = nodeFindSocket(in_node, SOCK_IN, "Normal");
- out_sock = nodeFindSocket(nor_node, SOCK_OUT, "Normal");
+ in_sock = nodeFindSocket(in_node, SOCK_IN, "Normal");
+ out_sock = nodeFindSocket(nor_node, SOCK_OUT, "Normal");
- out_node = nor_node;
- }
- else if (type == LAYER_BUMP) {
- bNode *bump_node;
- bump_node = nodeAddStaticNode(C, ntree, SH_NODE_BUMP);
+ out_node = nor_node;
+ }
+ else if (type == LAYER_BUMP) {
+ bNode *bump_node;
+ bump_node = nodeAddStaticNode(C, ntree, SH_NODE_BUMP);
- in_sock = nodeFindSocket(bump_node, SOCK_IN, "Height");
- nodeAddLink(ntree, out_node, out_sock, bump_node, in_sock);
+ in_sock = nodeFindSocket(bump_node, SOCK_IN, "Height");
+ nodeAddLink(ntree, out_node, out_sock, bump_node, in_sock);
- in_sock = nodeFindSocket(in_node, SOCK_IN, "Normal");
- out_sock = nodeFindSocket(bump_node, SOCK_OUT, "Normal");
+ in_sock = nodeFindSocket(in_node, SOCK_IN, "Normal");
+ out_sock = nodeFindSocket(bump_node, SOCK_OUT, "Normal");
- out_node = bump_node;
- }
- else if (type == LAYER_DISPLACEMENT) {
- /* Connect to the displacement output socket */
- in_node = ntreeFindType(ntree, SH_NODE_OUTPUT_MATERIAL);
+ out_node = bump_node;
+ }
+ else if (type == LAYER_DISPLACEMENT) {
+ /* Connect to the displacement output socket */
+ in_node = ntreeFindType(ntree, SH_NODE_OUTPUT_MATERIAL);
- if (in_node != NULL) {
- in_sock = nodeFindSocket(in_node, SOCK_IN, layer_type_items[type].name);
- }
- else {
- in_sock = NULL;
- }
- }
+ if (in_node != NULL) {
+ in_sock = nodeFindSocket(in_node, SOCK_IN, layer_type_items[type].name);
+ }
+ else {
+ in_sock = NULL;
+ }
+ }
- if (type > LAYER_BASE_COLOR) {
- /* This is a "non color data" image */
- NodeTexImage *tex = imanode->storage;
- tex->color_space = SHD_COLORSPACE_NONE;
- }
+ if (type > LAYER_BASE_COLOR) {
+ /* This is a "non color data" image */
+ NodeTexImage *tex = imanode->storage;
+ tex->color_space = SHD_COLORSPACE_NONE;
+ }
- /* Check if the socket in already connected to something */
- bNodeLink *link = in_sock ? in_sock->link : NULL;
- if (in_sock != NULL && link == NULL) {
- nodeAddLink(ntree, out_node, out_sock, in_node, in_sock);
+ /* Check if the socket in already connected to something */
+ bNodeLink *link = in_sock ? in_sock->link : NULL;
+ if (in_sock != NULL && link == NULL) {
+ nodeAddLink(ntree, out_node, out_sock, in_node, in_sock);
- nodePositionRelative(out_node, in_node, out_sock, in_sock);
- }
- }
+ nodePositionRelative(out_node, in_node, out_sock, in_sock);
+ }
+ }
- ntreeUpdateTree(CTX_data_main(C), ntree);
- /* In case we added more than one node, position them too. */
- nodePositionPropagate(out_node);
+ ntreeUpdateTree(CTX_data_main(C), ntree);
+ /* In case we added more than one node, position them too. */
+ nodePositionPropagate(out_node);
- if (ima) {
- BKE_texpaint_slot_refresh_cache(scene, ma);
- BKE_image_signal(bmain, ima, NULL, IMA_SIGNAL_USER_NEW_IMAGE);
- WM_event_add_notifier(C, NC_IMAGE | NA_ADDED, ima);
- }
+ if (ima) {
+ BKE_texpaint_slot_refresh_cache(scene, ma);
+ BKE_image_signal(bmain, ima, NULL, IMA_SIGNAL_USER_NEW_IMAGE);
+ WM_event_add_notifier(C, NC_IMAGE | NA_ADDED, ima);
+ }
- DEG_id_tag_update(&ntree->id, 0);
- DEG_id_tag_update(&ma->id, ID_RECALC_SHADING);
- ED_area_tag_redraw(CTX_wm_area(C));
+ DEG_id_tag_update(&ntree->id, 0);
+ DEG_id_tag_update(&ma->id, ID_RECALC_SHADING);
+ ED_area_tag_redraw(CTX_wm_area(C));
- BKE_paint_proj_mesh_data_check(scene, ob, NULL, NULL, NULL, NULL);
+ BKE_paint_proj_mesh_data_check(scene, ob, NULL, NULL, NULL, NULL);
- return true;
- }
+ return true;
+ }
- return false;
+ return false;
}
static int get_texture_layer_type(wmOperator *op, const char *prop_name)
{
- int type_value = RNA_enum_get(op->ptr, prop_name);
- int type = RNA_enum_from_value(layer_type_items, type_value);
- BLI_assert(type != -1);
- return type;
+ int type_value = RNA_enum_get(op->ptr, prop_name);
+ int type = RNA_enum_from_value(layer_type_items, type_value);
+ BLI_assert(type != -1);
+ return type;
}
static Material *get_or_create_current_material(bContext *C, Object *ob)
{
- Material *ma = give_current_material(ob, ob->actcol);
- if (!ma) {
- Main *bmain = CTX_data_main(C);
- ma = BKE_material_add(bmain, "Material");
- assign_material(bmain, ob, ma, ob->actcol, BKE_MAT_ASSIGN_USERPREF);
- }
- return ma;
+ Material *ma = give_current_material(ob, ob->actcol);
+ if (!ma) {
+ Main *bmain = CTX_data_main(C);
+ ma = BKE_material_add(bmain, "Material");
+ assign_material(bmain, ob, ma, ob->actcol, BKE_MAT_ASSIGN_USERPREF);
+ }
+ return ma;
}
static int texture_paint_add_texture_paint_slot_exec(bContext *C, wmOperator *op)
{
- Object *ob = ED_object_active_context(C);
- Material *ma = get_or_create_current_material(C, ob);
-
- int type = get_texture_layer_type(op, "type");
- proj_paint_default_color(op, type, ma);
-
- if (proj_paint_add_slot(C, op)) {
- return OPERATOR_FINISHED;
- }
- else {
- return OPERATOR_CANCELLED;
- }
+ Object *ob = ED_object_active_context(C);
+ Material *ma = get_or_create_current_material(C, ob);
+
+ int type = get_texture_layer_type(op, "type");
+ proj_paint_default_color(op, type, ma);
+
+ if (proj_paint_add_slot(C, op)) {
+ return OPERATOR_FINISHED;
+ }
+ else {
+ return OPERATOR_CANCELLED;
+ }
}
-static void get_default_texture_layer_name_for_object(Object *ob, int texture_type, char *dst, int dst_length)
+static void get_default_texture_layer_name_for_object(Object *ob,
+ int texture_type,
+ char *dst,
+ int dst_length)
{
- Material *ma = give_current_material(ob, ob->actcol);
- const char *base_name = ma ? &ma->id.name[2] : &ob->id.name[2];
- BLI_snprintf(dst, dst_length, "%s %s", base_name, layer_type_items[texture_type].name);
+ Material *ma = give_current_material(ob, ob->actcol);
+ const char *base_name = ma ? &ma->id.name[2] : &ob->id.name[2];
+ BLI_snprintf(dst, dst_length, "%s %s", base_name, layer_type_items[texture_type].name);
}
-static int texture_paint_add_texture_paint_slot_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+static int texture_paint_add_texture_paint_slot_invoke(bContext *C,
+ wmOperator *op,
+ const wmEvent *UNUSED(event))
{
- /* Get material and default color to display in the popup. */
- Object *ob = ED_object_active_context(C);
- Material *ma = get_or_create_current_material(C, ob);
+ /* Get material and default color to display in the popup. */
+ Object *ob = ED_object_active_context(C);
+ Material *ma = get_or_create_current_material(C, ob);
- int type = get_texture_layer_type(op, "type");
- proj_paint_default_color(op, type, ma);
+ int type = get_texture_layer_type(op, "type");
+ proj_paint_default_color(op, type, ma);
- char imagename[MAX_ID_NAME - 2];
- get_default_texture_layer_name_for_object(ob, type, (char *)&imagename, sizeof(imagename));
- RNA_string_set(op->ptr, "name", imagename);
+ char imagename[MAX_ID_NAME - 2];
+ get_default_texture_layer_name_for_object(ob, type, (char *)&imagename, sizeof(imagename));
+ RNA_string_set(op->ptr, "name", imagename);
- return WM_operator_props_dialog_popup(C, op, 300, 100);
+ return WM_operator_props_dialog_popup(C, op, 300, 100);
}
#define IMA_DEF_NAME N_("Untitled")
-
void PAINT_OT_add_texture_paint_slot(wmOperatorType *ot)
{
- PropertyRNA *prop;
- static float default_color[4] = {0.0f, 0.0f, 0.0f, 1.0f};
-
- /* identifiers */
- ot->name = "Add Texture Paint Slot";
- ot->description = "Add a texture paint slot";
- ot->idname = "PAINT_OT_add_texture_paint_slot";
-
- /* api callbacks */
- ot->invoke = texture_paint_add_texture_paint_slot_invoke;
- ot->exec = texture_paint_add_texture_paint_slot_exec;
- ot->poll = ED_operator_object_active;
-
- /* flags */
- ot->flag = OPTYPE_UNDO;
-
- /* properties */
- prop = RNA_def_enum(ot->srna, "type", layer_type_items, 0, "Type", "Merge method to use");
- RNA_def_property_flag(prop, PROP_HIDDEN);
- RNA_def_string(ot->srna, "name", IMA_DEF_NAME, MAX_ID_NAME - 2, "Name", "Image data-block name");
- prop = RNA_def_int(ot->srna, "width", 1024, 1, INT_MAX, "Width", "Image width", 1, 16384);
- RNA_def_property_subtype(prop, PROP_PIXEL);
- prop = RNA_def_int(ot->srna, "height", 1024, 1, INT_MAX, "Height", "Image height", 1, 16384);
- RNA_def_property_subtype(prop, PROP_PIXEL);
- prop = RNA_def_float_color(ot->srna, "color", 4, NULL, 0.0f, FLT_MAX, "Color", "Default fill color", 0.0f, 1.0f);
- RNA_def_property_subtype(prop, PROP_COLOR_GAMMA);
- RNA_def_property_float_array_default(prop, default_color);
- RNA_def_boolean(ot->srna, "alpha", 1, "Alpha", "Create an image with an alpha channel");
- RNA_def_enum(ot->srna, "generated_type", rna_enum_image_generated_type_items, IMA_GENTYPE_BLANK,
- "Generated Type", "Fill the image with a grid for UV map testing");
- RNA_def_boolean(ot->srna, "float", 0, "32 bit Float", "Create image with 32 bit floating point bit depth");
+ PropertyRNA *prop;
+ static float default_color[4] = {0.0f, 0.0f, 0.0f, 1.0f};
+
+ /* identifiers */
+ ot->name = "Add Texture Paint Slot";
+ ot->description = "Add a texture paint slot";
+ ot->idname = "PAINT_OT_add_texture_paint_slot";
+
+ /* api callbacks */
+ ot->invoke = texture_paint_add_texture_paint_slot_invoke;
+ ot->exec = texture_paint_add_texture_paint_slot_exec;
+ ot->poll = ED_operator_object_active;
+
+ /* flags */
+ ot->flag = OPTYPE_UNDO;
+
+ /* properties */
+ prop = RNA_def_enum(ot->srna, "type", layer_type_items, 0, "Type", "Merge method to use");
+ RNA_def_property_flag(prop, PROP_HIDDEN);
+ RNA_def_string(ot->srna, "name", IMA_DEF_NAME, MAX_ID_NAME - 2, "Name", "Image data-block name");
+ prop = RNA_def_int(ot->srna, "width", 1024, 1, INT_MAX, "Width", "Image width", 1, 16384);
+ RNA_def_property_subtype(prop, PROP_PIXEL);
+ prop = RNA_def_int(ot->srna, "height", 1024, 1, INT_MAX, "Height", "Image height", 1, 16384);
+ RNA_def_property_subtype(prop, PROP_PIXEL);
+ prop = RNA_def_float_color(
+ ot->srna, "color", 4, NULL, 0.0f, FLT_MAX, "Color", "Default fill color", 0.0f, 1.0f);
+ RNA_def_property_subtype(prop, PROP_COLOR_GAMMA);
+ RNA_def_property_float_array_default(prop, default_color);
+ RNA_def_boolean(ot->srna, "alpha", 1, "Alpha", "Create an image with an alpha channel");
+ RNA_def_enum(ot->srna,
+ "generated_type",
+ rna_enum_image_generated_type_items,
+ IMA_GENTYPE_BLANK,
+ "Generated Type",
+ "Fill the image with a grid for UV map testing");
+ RNA_def_boolean(
+ ot->srna, "float", 0, "32 bit Float", "Create image with 32 bit floating point bit depth");
}
static int add_simple_uvs_exec(bContext *C, wmOperator *UNUSED(op))
{
- /* no checks here, poll function does them for us */
- Main *bmain = CTX_data_main(C);
- Object *ob = CTX_data_active_object(C);
- Scene *scene = CTX_data_scene(C);
+ /* no checks here, poll function does them for us */
+ Main *bmain = CTX_data_main(C);
+ Object *ob = CTX_data_active_object(C);
+ Scene *scene = CTX_data_scene(C);
- ED_uvedit_add_simple_uvs(bmain, scene, ob);
+ ED_uvedit_add_simple_uvs(bmain, scene, ob);
- BKE_paint_proj_mesh_data_check(scene, ob, NULL, NULL, NULL, NULL);
+ BKE_paint_proj_mesh_data_check(scene, ob, NULL, NULL, NULL, NULL);
- DEG_id_tag_update(ob->data, 0);
- WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data);
- WM_event_add_notifier(C, NC_SCENE | ND_TOOLSETTINGS, scene);
- return OPERATOR_FINISHED;
+ DEG_id_tag_update(ob->data, 0);
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data);
+ WM_event_add_notifier(C, NC_SCENE | ND_TOOLSETTINGS, scene);
+ return OPERATOR_FINISHED;
}
static bool add_simple_uvs_poll(bContext *C)
{
- Object *ob = CTX_data_active_object(C);
+ Object *ob = CTX_data_active_object(C);
- if (!ob || ob->type != OB_MESH || ob->mode != OB_MODE_TEXTURE_PAINT) {
- return false;
- }
- return true;
+ if (!ob || ob->type != OB_MESH || ob->mode != OB_MODE_TEXTURE_PAINT) {
+ return false;
+ }
+ return true;
}
void PAINT_OT_add_simple_uvs(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Add simple UVs";
- ot->description = "Add cube map uvs on mesh";
- ot->idname = "PAINT_OT_add_simple_uvs";
+ /* identifiers */
+ ot->name = "Add simple UVs";
+ ot->description = "Add cube map uvs on mesh";
+ ot->idname = "PAINT_OT_add_simple_uvs";
- /* api callbacks */
- ot->exec = add_simple_uvs_exec;
- ot->poll = add_simple_uvs_poll;
+ /* api callbacks */
+ ot->exec = add_simple_uvs_exec;
+ ot->poll = add_simple_uvs_poll;
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
diff --git a/source/blender/editors/sculpt_paint/paint_image_undo.c b/source/blender/editors/sculpt_paint/paint_image_undo.c
index 8c4bfe00654..68abdfbf95b 100644
--- a/source/blender/editors/sculpt_paint/paint_image_undo.c
+++ b/source/blender/editors/sculpt_paint/paint_image_undo.c
@@ -55,26 +55,26 @@
* \{ */
typedef struct UndoImageTile {
- struct UndoImageTile *next, *prev;
+ struct UndoImageTile *next, *prev;
- char ibufname[IMB_FILENAME_SIZE];
+ char ibufname[IMB_FILENAME_SIZE];
- union {
- float *fp;
- unsigned int *uint;
- void *pt;
- } rect;
+ union {
+ float *fp;
+ unsigned int *uint;
+ void *pt;
+ } rect;
- unsigned short *mask;
+ unsigned short *mask;
- int x, y;
+ int x, y;
- Image *ima;
- short source, use_float;
- char gen_type;
- bool valid;
+ Image *ima;
+ short source, use_float;
+ char gen_type;
+ bool valid;
- size_t undo_size;
+ size_t undo_size;
} UndoImageTile;
/* this is a static resource for non-globality,
@@ -84,281 +84,305 @@ static SpinLock undolock;
void image_undo_init_locks(void)
{
- BLI_spin_init(&undolock);
+ BLI_spin_init(&undolock);
}
void image_undo_end_locks(void)
{
- BLI_spin_end(&undolock);
+ BLI_spin_end(&undolock);
}
/* UNDO */
typedef enum {
- COPY = 0,
- RESTORE = 1,
- RESTORE_COPY = 2,
+ COPY = 0,
+ RESTORE = 1,
+ RESTORE_COPY = 2,
} CopyMode;
static void undo_copy_tile(UndoImageTile *tile, ImBuf *tmpibuf, ImBuf *ibuf, CopyMode mode)
{
- if (mode == COPY) {
- /* copy or swap contents of tile->rect and region in ibuf->rect */
- IMB_rectcpy(
- tmpibuf, ibuf, 0, 0, tile->x * IMAPAINT_TILE_SIZE,
- tile->y * IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE);
-
- if (ibuf->rect_float) {
- SWAP(float *, tmpibuf->rect_float, tile->rect.fp);
- }
- else {
- SWAP(unsigned int *, tmpibuf->rect, tile->rect.uint);
- }
- }
- else {
- if (mode == RESTORE_COPY) {
- IMB_rectcpy(
- tmpibuf, ibuf, 0, 0, tile->x * IMAPAINT_TILE_SIZE,
- tile->y * IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE);
- }
- /* swap to the tmpbuf for easy copying */
- if (ibuf->rect_float) {
- SWAP(float *, tmpibuf->rect_float, tile->rect.fp);
- }
- else {
- SWAP(unsigned int *, tmpibuf->rect, tile->rect.uint);
- }
-
- IMB_rectcpy(
- ibuf, tmpibuf, tile->x * IMAPAINT_TILE_SIZE,
- tile->y * IMAPAINT_TILE_SIZE, 0, 0, IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE);
-
- if (mode == RESTORE) {
- if (ibuf->rect_float) {
- SWAP(float *, tmpibuf->rect_float, tile->rect.fp);
- }
- else {
- SWAP(unsigned int *, tmpibuf->rect, tile->rect.uint);
- }
- }
- }
+ if (mode == COPY) {
+ /* copy or swap contents of tile->rect and region in ibuf->rect */
+ IMB_rectcpy(tmpibuf,
+ ibuf,
+ 0,
+ 0,
+ tile->x * IMAPAINT_TILE_SIZE,
+ tile->y * IMAPAINT_TILE_SIZE,
+ IMAPAINT_TILE_SIZE,
+ IMAPAINT_TILE_SIZE);
+
+ if (ibuf->rect_float) {
+ SWAP(float *, tmpibuf->rect_float, tile->rect.fp);
+ }
+ else {
+ SWAP(unsigned int *, tmpibuf->rect, tile->rect.uint);
+ }
+ }
+ else {
+ if (mode == RESTORE_COPY) {
+ IMB_rectcpy(tmpibuf,
+ ibuf,
+ 0,
+ 0,
+ tile->x * IMAPAINT_TILE_SIZE,
+ tile->y * IMAPAINT_TILE_SIZE,
+ IMAPAINT_TILE_SIZE,
+ IMAPAINT_TILE_SIZE);
+ }
+ /* swap to the tmpbuf for easy copying */
+ if (ibuf->rect_float) {
+ SWAP(float *, tmpibuf->rect_float, tile->rect.fp);
+ }
+ else {
+ SWAP(unsigned int *, tmpibuf->rect, tile->rect.uint);
+ }
+
+ IMB_rectcpy(ibuf,
+ tmpibuf,
+ tile->x * IMAPAINT_TILE_SIZE,
+ tile->y * IMAPAINT_TILE_SIZE,
+ 0,
+ 0,
+ IMAPAINT_TILE_SIZE,
+ IMAPAINT_TILE_SIZE);
+
+ if (mode == RESTORE) {
+ if (ibuf->rect_float) {
+ SWAP(float *, tmpibuf->rect_float, tile->rect.fp);
+ }
+ else {
+ SWAP(unsigned int *, tmpibuf->rect, tile->rect.uint);
+ }
+ }
+ }
}
-void *image_undo_find_tile(
- ListBase *undo_tiles,
- Image *ima, ImBuf *ibuf, int x_tile, int y_tile, unsigned short **mask, bool validate)
+void *image_undo_find_tile(ListBase *undo_tiles,
+ Image *ima,
+ ImBuf *ibuf,
+ int x_tile,
+ int y_tile,
+ unsigned short **mask,
+ bool validate)
{
- UndoImageTile *tile;
- short use_float = ibuf->rect_float ? 1 : 0;
-
- for (tile = undo_tiles->first; tile; tile = tile->next) {
- if (tile->x == x_tile && tile->y == y_tile && ima->gen_type == tile->gen_type && ima->source == tile->source) {
- if (tile->use_float == use_float) {
- if (STREQ(tile->ibufname, ibuf->name)) {
- if (mask) {
- /* allocate mask if requested */
- if (!tile->mask) {
- tile->mask = MEM_callocN(
- sizeof(unsigned short) * IMAPAINT_TILE_SIZE * IMAPAINT_TILE_SIZE,
- "UndoImageTile.mask");
- }
-
- *mask = tile->mask;
- }
- if (validate) {
- tile->valid = true;
- }
- return tile->rect.pt;
- }
- }
- }
- }
-
- return NULL;
+ UndoImageTile *tile;
+ short use_float = ibuf->rect_float ? 1 : 0;
+
+ for (tile = undo_tiles->first; tile; tile = tile->next) {
+ if (tile->x == x_tile && tile->y == y_tile && ima->gen_type == tile->gen_type &&
+ ima->source == tile->source) {
+ if (tile->use_float == use_float) {
+ if (STREQ(tile->ibufname, ibuf->name)) {
+ if (mask) {
+ /* allocate mask if requested */
+ if (!tile->mask) {
+ tile->mask = MEM_callocN(sizeof(unsigned short) * IMAPAINT_TILE_SIZE *
+ IMAPAINT_TILE_SIZE,
+ "UndoImageTile.mask");
+ }
+
+ *mask = tile->mask;
+ }
+ if (validate) {
+ tile->valid = true;
+ }
+ return tile->rect.pt;
+ }
+ }
+ }
+ }
+
+ return NULL;
}
-void *image_undo_push_tile(
- ListBase *undo_tiles,
- Image *ima, ImBuf *ibuf, ImBuf **tmpibuf, int x_tile, int y_tile,
- unsigned short **mask, bool **valid, bool proj, bool find_prev)
+void *image_undo_push_tile(ListBase *undo_tiles,
+ Image *ima,
+ ImBuf *ibuf,
+ ImBuf **tmpibuf,
+ int x_tile,
+ int y_tile,
+ unsigned short **mask,
+ bool **valid,
+ bool proj,
+ bool find_prev)
{
- UndoImageTile *tile;
- int allocsize;
- short use_float = ibuf->rect_float ? 1 : 0;
- void *data;
-
- /* check if tile is already pushed */
-
- /* in projective painting we keep accounting of tiles, so if we need one pushed, just push! */
- if (find_prev) {
- data = image_undo_find_tile(undo_tiles, ima, ibuf, x_tile, y_tile, mask, true);
- if (data) {
- return data;
- }
- }
-
- if (*tmpibuf == NULL) {
- *tmpibuf = IMB_allocImBuf(IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, 32, IB_rectfloat | IB_rect);
- }
-
- tile = MEM_callocN(sizeof(UndoImageTile), "UndoImageTile");
- tile->x = x_tile;
- tile->y = y_tile;
-
- /* add mask explicitly here */
- if (mask) {
- *mask = tile->mask = MEM_callocN(
- sizeof(unsigned short) * IMAPAINT_TILE_SIZE * IMAPAINT_TILE_SIZE,
- "UndoImageTile.mask");
- }
- allocsize = IMAPAINT_TILE_SIZE * IMAPAINT_TILE_SIZE * 4;
- allocsize *= (ibuf->rect_float) ? sizeof(float) : sizeof(char);
- tile->rect.pt = MEM_mapallocN(allocsize, "UndeImageTile.rect");
-
- BLI_strncpy(tile->ibufname, ibuf->name, sizeof(tile->ibufname));
-
- tile->gen_type = ima->gen_type;
- tile->source = ima->source;
- tile->use_float = use_float;
- tile->valid = true;
- tile->ima = ima;
-
- if (valid) {
- *valid = &tile->valid;
- }
- undo_copy_tile(tile, *tmpibuf, ibuf, COPY);
-
- if (proj) {
- BLI_spin_lock(&undolock);
- }
- BLI_addtail(undo_tiles, tile);
-
- if (proj) {
- BLI_spin_unlock(&undolock);
- }
- return tile->rect.pt;
+ UndoImageTile *tile;
+ int allocsize;
+ short use_float = ibuf->rect_float ? 1 : 0;
+ void *data;
+
+ /* check if tile is already pushed */
+
+ /* in projective painting we keep accounting of tiles, so if we need one pushed, just push! */
+ if (find_prev) {
+ data = image_undo_find_tile(undo_tiles, ima, ibuf, x_tile, y_tile, mask, true);
+ if (data) {
+ return data;
+ }
+ }
+
+ if (*tmpibuf == NULL) {
+ *tmpibuf = IMB_allocImBuf(IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, 32, IB_rectfloat | IB_rect);
+ }
+
+ tile = MEM_callocN(sizeof(UndoImageTile), "UndoImageTile");
+ tile->x = x_tile;
+ tile->y = y_tile;
+
+ /* add mask explicitly here */
+ if (mask) {
+ *mask = tile->mask = MEM_callocN(
+ sizeof(unsigned short) * IMAPAINT_TILE_SIZE * IMAPAINT_TILE_SIZE, "UndoImageTile.mask");
+ }
+ allocsize = IMAPAINT_TILE_SIZE * IMAPAINT_TILE_SIZE * 4;
+ allocsize *= (ibuf->rect_float) ? sizeof(float) : sizeof(char);
+ tile->rect.pt = MEM_mapallocN(allocsize, "UndeImageTile.rect");
+
+ BLI_strncpy(tile->ibufname, ibuf->name, sizeof(tile->ibufname));
+
+ tile->gen_type = ima->gen_type;
+ tile->source = ima->source;
+ tile->use_float = use_float;
+ tile->valid = true;
+ tile->ima = ima;
+
+ if (valid) {
+ *valid = &tile->valid;
+ }
+ undo_copy_tile(tile, *tmpibuf, ibuf, COPY);
+
+ if (proj) {
+ BLI_spin_lock(&undolock);
+ }
+ BLI_addtail(undo_tiles, tile);
+
+ if (proj) {
+ BLI_spin_unlock(&undolock);
+ }
+ return tile->rect.pt;
}
void image_undo_remove_masks(void)
{
- ListBase *undo_tiles = ED_image_undo_get_tiles();
- UndoImageTile *tile;
-
- for (tile = undo_tiles->first; tile; tile = tile->next) {
- if (tile->mask) {
- MEM_freeN(tile->mask);
- tile->mask = NULL;
- }
- }
+ ListBase *undo_tiles = ED_image_undo_get_tiles();
+ UndoImageTile *tile;
+
+ for (tile = undo_tiles->first; tile; tile = tile->next) {
+ if (tile->mask) {
+ MEM_freeN(tile->mask);
+ tile->mask = NULL;
+ }
+ }
}
static void image_undo_restore_runtime(ListBase *lb)
{
- ImBuf *ibuf, *tmpibuf;
- UndoImageTile *tile;
+ ImBuf *ibuf, *tmpibuf;
+ UndoImageTile *tile;
- tmpibuf = IMB_allocImBuf(
- IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, 32,
- IB_rectfloat | IB_rect);
+ tmpibuf = IMB_allocImBuf(IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, 32, IB_rectfloat | IB_rect);
- for (tile = lb->first; tile; tile = tile->next) {
- Image *ima = tile->ima;
- ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL);
+ for (tile = lb->first; tile; tile = tile->next) {
+ Image *ima = tile->ima;
+ ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL);
- undo_copy_tile(tile, tmpibuf, ibuf, RESTORE);
+ undo_copy_tile(tile, tmpibuf, ibuf, RESTORE);
- GPU_free_image(ima); /* force OpenGL reload (maybe partial update will operate better?) */
- if (ibuf->rect_float) {
- ibuf->userflags |= IB_RECT_INVALID; /* force recreate of char rect */
- }
- if (ibuf->mipmap[0]) {
- ibuf->userflags |= IB_MIPMAP_INVALID; /* force mipmap recreatiom */
- }
- ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID;
+ GPU_free_image(ima); /* force OpenGL reload (maybe partial update will operate better?) */
+ if (ibuf->rect_float) {
+ ibuf->userflags |= IB_RECT_INVALID; /* force recreate of char rect */
+ }
+ if (ibuf->mipmap[0]) {
+ ibuf->userflags |= IB_MIPMAP_INVALID; /* force mipmap recreatiom */
+ }
+ ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID;
- BKE_image_release_ibuf(ima, ibuf, NULL);
- }
+ BKE_image_release_ibuf(ima, ibuf, NULL);
+ }
- IMB_freeImBuf(tmpibuf);
+ IMB_freeImBuf(tmpibuf);
}
static void image_undo_restore_list(ListBase *lb, struct UndoIDPtrMap *id_map)
{
- ImBuf *tmpibuf = IMB_allocImBuf(IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, 32, IB_rectfloat | IB_rect);
+ ImBuf *tmpibuf = IMB_allocImBuf(
+ IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, 32, IB_rectfloat | IB_rect);
- /* Store last found image. */
- ID *image_prev[2] = {NULL};
+ /* Store last found image. */
+ ID *image_prev[2] = {NULL};
- for (UndoImageTile *tile = lb->first; tile; tile = tile->next) {
- short use_float;
+ for (UndoImageTile *tile = lb->first; tile; tile = tile->next) {
+ short use_float;
- Image *ima = (Image *)BKE_undosys_ID_map_lookup_with_prev(id_map, &tile->ima->id, image_prev);
+ Image *ima = (Image *)BKE_undosys_ID_map_lookup_with_prev(id_map, &tile->ima->id, image_prev);
- ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL);
+ ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL);
- if (ima && ibuf && !STREQ(tile->ibufname, ibuf->name)) {
- /* current ImBuf filename was changed, probably current frame
- * was changed when painting on image sequence, rather than storing
- * full image user (which isn't so obvious, btw) try to find ImBuf with
- * matched file name in list of already loaded images */
+ if (ima && ibuf && !STREQ(tile->ibufname, ibuf->name)) {
+ /* current ImBuf filename was changed, probably current frame
+ * was changed when painting on image sequence, rather than storing
+ * full image user (which isn't so obvious, btw) try to find ImBuf with
+ * matched file name in list of already loaded images */
- BKE_image_release_ibuf(ima, ibuf, NULL);
+ BKE_image_release_ibuf(ima, ibuf, NULL);
- ibuf = BKE_image_get_ibuf_with_name(ima, tile->ibufname);
- }
+ ibuf = BKE_image_get_ibuf_with_name(ima, tile->ibufname);
+ }
- if (!ima || !ibuf || !(ibuf->rect || ibuf->rect_float)) {
- BKE_image_release_ibuf(ima, ibuf, NULL);
- continue;
- }
+ if (!ima || !ibuf || !(ibuf->rect || ibuf->rect_float)) {
+ BKE_image_release_ibuf(ima, ibuf, NULL);
+ continue;
+ }
- if (ima->gen_type != tile->gen_type || ima->source != tile->source) {
- BKE_image_release_ibuf(ima, ibuf, NULL);
- continue;
- }
+ if (ima->gen_type != tile->gen_type || ima->source != tile->source) {
+ BKE_image_release_ibuf(ima, ibuf, NULL);
+ continue;
+ }
- use_float = ibuf->rect_float ? 1 : 0;
+ use_float = ibuf->rect_float ? 1 : 0;
- if (use_float != tile->use_float) {
- BKE_image_release_ibuf(ima, ibuf, NULL);
- continue;
- }
+ if (use_float != tile->use_float) {
+ BKE_image_release_ibuf(ima, ibuf, NULL);
+ continue;
+ }
- undo_copy_tile(tile, tmpibuf, ibuf, RESTORE_COPY);
+ undo_copy_tile(tile, tmpibuf, ibuf, RESTORE_COPY);
- GPU_free_image(ima); /* force OpenGL reload */
- if (ibuf->rect_float) {
- ibuf->userflags |= IB_RECT_INVALID; /* force recreate of char rect */
- }
- if (ibuf->mipmap[0]) {
- ibuf->userflags |= IB_MIPMAP_INVALID; /* force mipmap recreatiom */
- }
- ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID;
+ GPU_free_image(ima); /* force OpenGL reload */
+ if (ibuf->rect_float) {
+ ibuf->userflags |= IB_RECT_INVALID; /* force recreate of char rect */
+ }
+ if (ibuf->mipmap[0]) {
+ ibuf->userflags |= IB_MIPMAP_INVALID; /* force mipmap recreatiom */
+ }
+ ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID;
- DEG_id_tag_update(&ima->id, 0);
+ DEG_id_tag_update(&ima->id, 0);
- BKE_image_release_ibuf(ima, ibuf, NULL);
- }
+ BKE_image_release_ibuf(ima, ibuf, NULL);
+ }
- IMB_freeImBuf(tmpibuf);
+ IMB_freeImBuf(tmpibuf);
}
static void image_undo_free_list(ListBase *lb)
{
- for (UndoImageTile *tile = lb->first, *tile_next; tile; tile = tile_next) {
- tile_next = tile->next;
- MEM_freeN(tile->rect.pt);
- MEM_freeN(tile);
- }
+ for (UndoImageTile *tile = lb->first, *tile_next; tile; tile = tile_next) {
+ tile_next = tile->next;
+ MEM_freeN(tile->rect.pt);
+ MEM_freeN(tile);
+ }
}
static void image_undo_invalidate(void)
{
- UndoImageTile *tile;
- ListBase *lb = ED_image_undo_get_tiles();
+ UndoImageTile *tile;
+ ListBase *lb = ED_image_undo_get_tiles();
- for (tile = lb->first; tile; tile = tile->next) {
- tile->valid = false;
- }
+ for (tile = lb->first; tile; tile = tile->next) {
+ tile->valid = false;
+ }
}
/** \} */
@@ -368,258 +392,260 @@ static void image_undo_invalidate(void)
* \{ */
typedef struct ImageUndoStep {
- UndoStep step;
- ListBase tiles;
- bool is_encode_init;
- ePaintMode paint_mode;
+ UndoStep step;
+ ListBase tiles;
+ bool is_encode_init;
+ ePaintMode paint_mode;
- /* Use for all ID lookups (can be NULL). */
- struct UndoIDPtrMap *id_map;
+ /* Use for all ID lookups (can be NULL). */
+ struct UndoIDPtrMap *id_map;
} ImageUndoStep;
static void image_undosys_step_encode_store_ids(ImageUndoStep *us)
{
- us->id_map = BKE_undosys_ID_map_create();
+ us->id_map = BKE_undosys_ID_map_create();
- ID *image_prev = NULL;
- for (UndoImageTile *tile = us->tiles.first; tile; tile = tile->next) {
- BKE_undosys_ID_map_add_with_prev(us->id_map, &tile->ima->id, &image_prev);
- }
+ ID *image_prev = NULL;
+ for (UndoImageTile *tile = us->tiles.first; tile; tile = tile->next) {
+ BKE_undosys_ID_map_add_with_prev(us->id_map, &tile->ima->id, &image_prev);
+ }
}
/* Restore at runtime. */
#if 0
static void paint_undosys_step_decode_restore_ids(ImageUndoStep *us)
{
- ID *image_prev[2] = {NULL};
- for (UndoImageTile *tile = us->tiles.first; tile; tile = tile->next) {
- tile->ima = (Image *)BKE_undosys_ID_map_lookup_with_prev(us->id_map, &tile->ima->id, image_prev);
- }
+ ID *image_prev[2] = {NULL};
+ for (UndoImageTile *tile = us->tiles.first; tile; tile = tile->next) {
+ tile->ima = (Image *)BKE_undosys_ID_map_lookup_with_prev(us->id_map, &tile->ima->id, image_prev);
+ }
}
#endif
static bool image_undosys_poll(bContext *C)
{
- Object *obact = CTX_data_active_object(C);
-
- ScrArea *sa = CTX_wm_area(C);
- if (sa && (sa->spacetype == SPACE_IMAGE)) {
- SpaceImage *sima = (SpaceImage *)sa->spacedata.first;
- if ((obact && (obact->mode & OB_MODE_TEXTURE_PAINT)) ||
- (sima->mode == SI_MODE_PAINT))
- {
- return true;
- }
- }
- else {
- if (obact && (obact->mode & OB_MODE_TEXTURE_PAINT)) {
- return true;
- }
- }
- return false;
+ Object *obact = CTX_data_active_object(C);
+
+ ScrArea *sa = CTX_wm_area(C);
+ if (sa && (sa->spacetype == SPACE_IMAGE)) {
+ SpaceImage *sima = (SpaceImage *)sa->spacedata.first;
+ if ((obact && (obact->mode & OB_MODE_TEXTURE_PAINT)) || (sima->mode == SI_MODE_PAINT)) {
+ return true;
+ }
+ }
+ else {
+ if (obact && (obact->mode & OB_MODE_TEXTURE_PAINT)) {
+ return true;
+ }
+ }
+ return false;
}
static void image_undosys_step_encode_init(struct bContext *UNUSED(C), UndoStep *us_p)
{
- ImageUndoStep *us = (ImageUndoStep *)us_p;
- /* dummy, memory is cleared anyway. */
- us->is_encode_init = true;
- BLI_listbase_clear(&us->tiles);
+ ImageUndoStep *us = (ImageUndoStep *)us_p;
+ /* dummy, memory is cleared anyway. */
+ us->is_encode_init = true;
+ BLI_listbase_clear(&us->tiles);
}
-static bool image_undosys_step_encode(struct bContext *C, struct Main *UNUSED(bmain), UndoStep *us_p)
+static bool image_undosys_step_encode(struct bContext *C,
+ struct Main *UNUSED(bmain),
+ UndoStep *us_p)
{
- /* dummy, encoding is done along the way by adding tiles
- * to the current 'ImageUndoStep' added by encode_init. */
- ImageUndoStep *us = (ImageUndoStep *)us_p;
-
- BLI_assert(us->step.data_size == 0);
-
- int allocsize = IMAPAINT_TILE_SIZE * IMAPAINT_TILE_SIZE * 4;
-
- if (us->is_encode_init) {
- /* first dispose of invalid tiles (may happen due to drag dot for instance) */
- for (UndoImageTile *tile = us->tiles.first; tile;) {
- if (!tile->valid) {
- UndoImageTile *tmp_tile = tile->next;
- MEM_freeN(tile->rect.pt);
- BLI_freelinkN(&us->tiles, tile);
- tile = tmp_tile;
- }
- else {
- us->step.data_size += allocsize * ((tile->use_float) ? sizeof(float) : sizeof(char));
- tile = tile->next;
- }
- }
- }
- else {
- /* Happens when switching modes. */
- ePaintMode paint_mode = BKE_paintmode_get_active_from_context(C);
- BLI_assert(ELEM(paint_mode, PAINT_MODE_TEXTURE_2D, PAINT_MODE_TEXTURE_3D));
- us->paint_mode = paint_mode;
- }
-
- image_undosys_step_encode_store_ids(us);
-
- us_p->is_applied = true;
-
- return true;
+ /* dummy, encoding is done along the way by adding tiles
+ * to the current 'ImageUndoStep' added by encode_init. */
+ ImageUndoStep *us = (ImageUndoStep *)us_p;
+
+ BLI_assert(us->step.data_size == 0);
+
+ int allocsize = IMAPAINT_TILE_SIZE * IMAPAINT_TILE_SIZE * 4;
+
+ if (us->is_encode_init) {
+ /* first dispose of invalid tiles (may happen due to drag dot for instance) */
+ for (UndoImageTile *tile = us->tiles.first; tile;) {
+ if (!tile->valid) {
+ UndoImageTile *tmp_tile = tile->next;
+ MEM_freeN(tile->rect.pt);
+ BLI_freelinkN(&us->tiles, tile);
+ tile = tmp_tile;
+ }
+ else {
+ us->step.data_size += allocsize * ((tile->use_float) ? sizeof(float) : sizeof(char));
+ tile = tile->next;
+ }
+ }
+ }
+ else {
+ /* Happens when switching modes. */
+ ePaintMode paint_mode = BKE_paintmode_get_active_from_context(C);
+ BLI_assert(ELEM(paint_mode, PAINT_MODE_TEXTURE_2D, PAINT_MODE_TEXTURE_3D));
+ us->paint_mode = paint_mode;
+ }
+
+ image_undosys_step_encode_store_ids(us);
+
+ us_p->is_applied = true;
+
+ return true;
}
-
static void image_undosys_step_decode_undo_impl(ImageUndoStep *us)
{
- BLI_assert(us->step.is_applied == true);
- image_undo_restore_list(&us->tiles, us->id_map);
- us->step.is_applied = false;
+ BLI_assert(us->step.is_applied == true);
+ image_undo_restore_list(&us->tiles, us->id_map);
+ us->step.is_applied = false;
}
static void image_undosys_step_decode_redo_impl(ImageUndoStep *us)
{
- BLI_assert(us->step.is_applied == false);
- image_undo_restore_list(&us->tiles, us->id_map);
- us->step.is_applied = true;
+ BLI_assert(us->step.is_applied == false);
+ image_undo_restore_list(&us->tiles, us->id_map);
+ us->step.is_applied = true;
}
static void image_undosys_step_decode_undo(ImageUndoStep *us)
{
- ImageUndoStep *us_iter = us;
- while (us_iter->step.next && (us_iter->step.next->type == us_iter->step.type)) {
- if (us_iter->step.next->is_applied == false) {
- break;
- }
- us_iter = (ImageUndoStep *)us_iter->step.next;
- }
- while (us_iter != us) {
- image_undosys_step_decode_undo_impl(us_iter);
- us_iter = (ImageUndoStep *)us_iter->step.prev;
- }
+ ImageUndoStep *us_iter = us;
+ while (us_iter->step.next && (us_iter->step.next->type == us_iter->step.type)) {
+ if (us_iter->step.next->is_applied == false) {
+ break;
+ }
+ us_iter = (ImageUndoStep *)us_iter->step.next;
+ }
+ while (us_iter != us) {
+ image_undosys_step_decode_undo_impl(us_iter);
+ us_iter = (ImageUndoStep *)us_iter->step.prev;
+ }
}
static void image_undosys_step_decode_redo(ImageUndoStep *us)
{
- ImageUndoStep *us_iter = us;
- while (us_iter->step.prev && (us_iter->step.prev->type == us_iter->step.type)) {
- if (us_iter->step.prev->is_applied == true) {
- break;
- }
- us_iter = (ImageUndoStep *)us_iter->step.prev;
- }
- while (us_iter && (us_iter->step.is_applied == false)) {
- image_undosys_step_decode_redo_impl(us_iter);
- if (us_iter == us) {
- break;
- }
- us_iter = (ImageUndoStep *)us_iter->step.next;
- }
+ ImageUndoStep *us_iter = us;
+ while (us_iter->step.prev && (us_iter->step.prev->type == us_iter->step.type)) {
+ if (us_iter->step.prev->is_applied == true) {
+ break;
+ }
+ us_iter = (ImageUndoStep *)us_iter->step.prev;
+ }
+ while (us_iter && (us_iter->step.is_applied == false)) {
+ image_undosys_step_decode_redo_impl(us_iter);
+ if (us_iter == us) {
+ break;
+ }
+ us_iter = (ImageUndoStep *)us_iter->step.next;
+ }
}
-static void image_undosys_step_decode(struct bContext *C, struct Main *bmain, UndoStep *us_p, int dir)
+static void image_undosys_step_decode(struct bContext *C,
+ struct Main *bmain,
+ UndoStep *us_p,
+ int dir)
{
- ImageUndoStep *us = (ImageUndoStep *)us_p;
+ ImageUndoStep *us = (ImageUndoStep *)us_p;
#if 0
- paint_undosys_step_decode_restore_ids(us);
+ paint_undosys_step_decode_restore_ids(us);
#endif
- if (dir < 0) {
- image_undosys_step_decode_undo(us);
- }
- else {
- image_undosys_step_decode_redo(us);
- }
+ if (dir < 0) {
+ image_undosys_step_decode_undo(us);
+ }
+ else {
+ image_undosys_step_decode_redo(us);
+ }
- if (us->paint_mode == PAINT_MODE_TEXTURE_3D) {
- ED_object_mode_set(C, OB_MODE_TEXTURE_PAINT);
- }
+ if (us->paint_mode == PAINT_MODE_TEXTURE_3D) {
+ ED_object_mode_set(C, OB_MODE_TEXTURE_PAINT);
+ }
- /* Refresh texture slots. */
- ED_editors_init_for_undo(bmain);
+ /* Refresh texture slots. */
+ ED_editors_init_for_undo(bmain);
}
static void image_undosys_step_free(UndoStep *us_p)
{
- ImageUndoStep *us = (ImageUndoStep *)us_p;
- image_undo_free_list(&us->tiles);
- BKE_undosys_ID_map_destroy(us->id_map);
+ ImageUndoStep *us = (ImageUndoStep *)us_p;
+ image_undo_free_list(&us->tiles);
+ BKE_undosys_ID_map_destroy(us->id_map);
}
-static void image_undosys_foreach_ID_ref(
- UndoStep *us_p, UndoTypeForEachIDRefFn foreach_ID_ref_fn, void *user_data)
+static void image_undosys_foreach_ID_ref(UndoStep *us_p,
+ UndoTypeForEachIDRefFn foreach_ID_ref_fn,
+ void *user_data)
{
- ImageUndoStep *us = (ImageUndoStep *)us_p;
- if (us->id_map != NULL) {
- BKE_undosys_ID_map_foreach_ID_ref(us->id_map, foreach_ID_ref_fn, user_data);
- }
+ ImageUndoStep *us = (ImageUndoStep *)us_p;
+ if (us->id_map != NULL) {
+ BKE_undosys_ID_map_foreach_ID_ref(us->id_map, foreach_ID_ref_fn, user_data);
+ }
}
/* Export for ED_undo_sys. */
void ED_image_undosys_type(UndoType *ut)
{
- ut->name = "Image";
- ut->poll = image_undosys_poll;
- ut->step_encode_init = image_undosys_step_encode_init;
- ut->step_encode = image_undosys_step_encode;
- ut->step_decode = image_undosys_step_decode;
- ut->step_free = image_undosys_step_free;
+ ut->name = "Image";
+ ut->poll = image_undosys_poll;
+ ut->step_encode_init = image_undosys_step_encode_init;
+ ut->step_encode = image_undosys_step_encode;
+ ut->step_decode = image_undosys_step_decode;
+ ut->step_free = image_undosys_step_free;
- ut->step_foreach_ID_ref = image_undosys_foreach_ID_ref;
+ ut->step_foreach_ID_ref = image_undosys_foreach_ID_ref;
- ut->use_context = true;
+ ut->use_context = true;
- ut->step_size = sizeof(ImageUndoStep);
+ ut->step_size = sizeof(ImageUndoStep);
}
/** \} */
-
/* -------------------------------------------------------------------- */
/** \name Utilities
* \{ */
ListBase *ED_image_undosys_step_get_tiles(UndoStep *us_p)
{
- ImageUndoStep *us = (ImageUndoStep *)us_p;
- return &us->tiles;
+ ImageUndoStep *us = (ImageUndoStep *)us_p;
+ return &us->tiles;
}
ListBase *ED_image_undo_get_tiles(void)
{
- UndoStack *ustack = ED_undo_stack_get();
- UndoStep *us_prev = ustack->step_init;
- UndoStep *us_p = BKE_undosys_stack_init_or_active_with_type(ustack, BKE_UNDOSYS_TYPE_IMAGE);
- ImageUndoStep *us = (ImageUndoStep *)us_p;
- /* We should always have an undo push started when accessing tiles,
- * not doing this means we won't have paint_mode correctly set. */
- BLI_assert(us_p == us_prev);
- if (us_p != us_prev) {
- /* Fallback value until we can be sure this never happens. */
- us->paint_mode = PAINT_MODE_TEXTURE_2D;
- }
- return ED_image_undosys_step_get_tiles(us_p);
+ UndoStack *ustack = ED_undo_stack_get();
+ UndoStep *us_prev = ustack->step_init;
+ UndoStep *us_p = BKE_undosys_stack_init_or_active_with_type(ustack, BKE_UNDOSYS_TYPE_IMAGE);
+ ImageUndoStep *us = (ImageUndoStep *)us_p;
+ /* We should always have an undo push started when accessing tiles,
+ * not doing this means we won't have paint_mode correctly set. */
+ BLI_assert(us_p == us_prev);
+ if (us_p != us_prev) {
+ /* Fallback value until we can be sure this never happens. */
+ us->paint_mode = PAINT_MODE_TEXTURE_2D;
+ }
+ return ED_image_undosys_step_get_tiles(us_p);
}
/* restore painting image to previous state. Used for anchored and drag-dot style brushes*/
void ED_image_undo_restore(UndoStep *us)
{
- ListBase *lb = ED_image_undosys_step_get_tiles(us);
- image_undo_restore_runtime(lb);
- image_undo_invalidate();
+ ListBase *lb = ED_image_undosys_step_get_tiles(us);
+ image_undo_restore_runtime(lb);
+ image_undo_invalidate();
}
void ED_image_undo_push_begin(const char *name, int paint_mode)
{
- UndoStack *ustack = ED_undo_stack_get();
- bContext *C = NULL; /* special case, we never read from this. */
- UndoStep *us_p = BKE_undosys_step_push_init_with_type(ustack, C, name, BKE_UNDOSYS_TYPE_IMAGE);
- ImageUndoStep *us = (ImageUndoStep *)us_p;
- BLI_assert(ELEM(paint_mode, PAINT_MODE_TEXTURE_2D, PAINT_MODE_TEXTURE_3D));
- us->paint_mode = paint_mode;
+ UndoStack *ustack = ED_undo_stack_get();
+ bContext *C = NULL; /* special case, we never read from this. */
+ UndoStep *us_p = BKE_undosys_step_push_init_with_type(ustack, C, name, BKE_UNDOSYS_TYPE_IMAGE);
+ ImageUndoStep *us = (ImageUndoStep *)us_p;
+ BLI_assert(ELEM(paint_mode, PAINT_MODE_TEXTURE_2D, PAINT_MODE_TEXTURE_3D));
+ us->paint_mode = paint_mode;
}
void ED_image_undo_push_end(void)
{
- UndoStack *ustack = ED_undo_stack_get();
- BKE_undosys_step_push(ustack, NULL, NULL);
+ UndoStack *ustack = ED_undo_stack_get();
+ BKE_undosys_step_push(ustack, NULL, NULL);
}
/** \} */
diff --git a/source/blender/editors/sculpt_paint/paint_intern.h b/source/blender/editors/sculpt_paint/paint_intern.h
index 0e8262bd82f..1a8d2f79290 100644
--- a/source/blender/editors/sculpt_paint/paint_intern.h
+++ b/source/blender/editors/sculpt_paint/paint_intern.h
@@ -21,7 +21,6 @@
* \ingroup edsculpt
*/
-
#ifndef __PAINT_INTERN_H__
#define __PAINT_INTERN_H__
@@ -51,22 +50,27 @@ struct wmWindowManager;
enum ePaintMode;
typedef struct CoNo {
- float co[3];
- float no[3];
+ float co[3];
+ float no[3];
} CoNo;
/* paint_stroke.c */
typedef bool (*StrokeGetLocation)(struct bContext *C, float location[3], const float mouse[2]);
typedef bool (*StrokeTestStart)(struct bContext *C, struct wmOperator *op, const float mouse[2]);
-typedef void (*StrokeUpdateStep)(struct bContext *C, struct PaintStroke *stroke, struct PointerRNA *itemptr);
+typedef void (*StrokeUpdateStep)(struct bContext *C,
+ struct PaintStroke *stroke,
+ struct PointerRNA *itemptr);
typedef void (*StrokeRedraw)(const struct bContext *C, struct PaintStroke *stroke, bool final);
typedef void (*StrokeDone)(const struct bContext *C, struct PaintStroke *stroke);
-struct PaintStroke *paint_stroke_new(
- struct bContext *C, struct wmOperator *op,
- StrokeGetLocation get_location, StrokeTestStart test_start,
- StrokeUpdateStep update_step, StrokeRedraw redraw,
- StrokeDone done, int event_type);
+struct PaintStroke *paint_stroke_new(struct bContext *C,
+ struct wmOperator *op,
+ StrokeGetLocation get_location,
+ StrokeTestStart test_start,
+ StrokeUpdateStep update_step,
+ StrokeRedraw redraw,
+ StrokeDone done,
+ int event_type);
void paint_stroke_data_free(struct wmOperator *op);
bool paint_space_stroke_enabled(struct Brush *br, enum ePaintMode mode);
@@ -88,7 +92,9 @@ float paint_stroke_distance_get(struct PaintStroke *stroke);
void paint_stroke_set_mode_data(struct PaintStroke *stroke, void *mode_data);
bool paint_poll(struct bContext *C);
void paint_cursor_start(struct bContext *C, bool (*poll)(struct bContext *C));
-void paint_cursor_start_explicit(struct Paint *p, struct wmWindowManager *wm, bool (*poll)(struct bContext *C));
+void paint_cursor_start_explicit(struct Paint *p,
+ struct wmWindowManager *wm,
+ bool (*poll)(struct bContext *C));
void paint_cursor_delete_textures(void);
/* paint_vertex.c */
@@ -99,15 +105,17 @@ bool vertex_paint_poll(struct bContext *C);
bool vertex_paint_poll_ignore_tool(struct bContext *C);
bool vertex_paint_mode_poll(struct bContext *C);
-typedef void (*VPaintTransform_Callback)(const float col[3], const void *user_data, float r_col[3]);
+typedef void (*VPaintTransform_Callback)(const float col[3],
+ const void *user_data,
+ float r_col[3]);
void PAINT_OT_weight_paint_toggle(struct wmOperatorType *ot);
void PAINT_OT_weight_paint(struct wmOperatorType *ot);
void PAINT_OT_weight_set(struct wmOperatorType *ot);
enum {
- WPAINT_GRADIENT_TYPE_LINEAR,
- WPAINT_GRADIENT_TYPE_RADIAL,
+ WPAINT_GRADIENT_TYPE_LINEAR,
+ WPAINT_GRADIENT_TYPE_RADIAL,
};
void PAINT_OT_weight_gradient(struct wmOperatorType *ot);
@@ -117,28 +125,31 @@ void PAINT_OT_vertex_paint(struct wmOperatorType *ot);
unsigned int vpaint_get_current_col(struct Scene *scene, struct VPaint *vp, bool secondary);
/* paint_vertex_color_utils.c */
-unsigned int ED_vpaint_blend_tool(
- const int tool, const uint col,
- const uint paintcol, const int alpha_i);
-bool ED_vpaint_color_transform(
- struct Object *ob, VPaintTransform_Callback vpaint_tx_fn, const void *user_data);
+unsigned int ED_vpaint_blend_tool(const int tool,
+ const uint col,
+ const uint paintcol,
+ const int alpha_i);
+bool ED_vpaint_color_transform(struct Object *ob,
+ VPaintTransform_Callback vpaint_tx_fn,
+ const void *user_data);
/* paint_vertex_weight_utils.c */
-float ED_wpaint_blend_tool(
- const int tool,
- const float weight,
- const float paintval, const float alpha);
+float ED_wpaint_blend_tool(const int tool,
+ const float weight,
+ const float paintval,
+ const float alpha);
/* Utility for tools to ensure vertex groups exist before they begin. */
enum eWPaintFlag {
- WPAINT_ENSURE_MIRROR = (1 << 0),
+ WPAINT_ENSURE_MIRROR = (1 << 0),
};
struct WPaintVGroupIndex {
- int active;
- int mirror;
+ int active;
+ int mirror;
};
-bool ED_wpaint_ensure_data(
- struct bContext *C, struct ReportList *reports,
- enum eWPaintFlag flag, struct WPaintVGroupIndex *vgroup_index);
+bool ED_wpaint_ensure_data(struct bContext *C,
+ struct ReportList *reports,
+ enum eWPaintFlag flag,
+ struct WPaintVGroupIndex *vgroup_index);
int ED_wpaint_mirror_vgroup_ensure(struct Object *ob, const int vgroup_active);
/* paint_vertex_color_ops.c */
@@ -157,55 +168,77 @@ void PAINT_OT_weight_sample_group(struct wmOperatorType *ot);
/* paint_vertex_proj.c */
struct VertProjHandle;
-struct VertProjHandle *ED_vpaint_proj_handle_create(
- struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob,
- struct CoNo **r_vcosnos);
-void ED_vpaint_proj_handle_update(
- struct Depsgraph *depsgraph, struct VertProjHandle *vp_handle,
- /* runtime vars */
- struct ARegion *ar, const float mval_fl[2]);
-void ED_vpaint_proj_handle_free(
- struct VertProjHandle *vp_handle);
-
+struct VertProjHandle *ED_vpaint_proj_handle_create(struct Depsgraph *depsgraph,
+ struct Scene *scene,
+ struct Object *ob,
+ struct CoNo **r_vcosnos);
+void ED_vpaint_proj_handle_update(struct Depsgraph *depsgraph,
+ struct VertProjHandle *vp_handle,
+ /* runtime vars */
+ struct ARegion *ar,
+ const float mval_fl[2]);
+void ED_vpaint_proj_handle_free(struct VertProjHandle *vp_handle);
/* paint_image.c */
typedef struct ImagePaintPartialRedraw {
- int x1, y1, x2, y2; /* XXX, could use 'rcti' */
- int enabled;
+ int x1, y1, x2, y2; /* XXX, could use 'rcti' */
+ int enabled;
} ImagePaintPartialRedraw;
-#define IMAPAINT_TILE_BITS 6
-#define IMAPAINT_TILE_SIZE (1 << IMAPAINT_TILE_BITS)
-#define IMAPAINT_TILE_NUMBER(size) (((size) + IMAPAINT_TILE_SIZE - 1) >> IMAPAINT_TILE_BITS)
+#define IMAPAINT_TILE_BITS 6
+#define IMAPAINT_TILE_SIZE (1 << IMAPAINT_TILE_BITS)
+#define IMAPAINT_TILE_NUMBER(size) (((size) + IMAPAINT_TILE_SIZE - 1) >> IMAPAINT_TILE_BITS)
bool image_texture_paint_poll(struct bContext *C);
-void imapaint_image_update(struct SpaceImage *sima, struct Image *image, struct ImBuf *ibuf, short texpaint);
+void imapaint_image_update(struct SpaceImage *sima,
+ struct Image *image,
+ struct ImBuf *ibuf,
+ short texpaint);
struct ImagePaintPartialRedraw *get_imapaintpartial(void);
void set_imapaintpartial(struct ImagePaintPartialRedraw *ippr);
-void imapaint_region_tiles(struct ImBuf *ibuf, int x, int y, int w, int h, int *tx, int *ty, int *tw, int *th);
+void imapaint_region_tiles(
+ struct ImBuf *ibuf, int x, int y, int w, int h, int *tx, int *ty, int *tw, int *th);
int get_imapaint_zoom(struct bContext *C, float *zoomx, float *zoomy);
void *paint_2d_new_stroke(struct bContext *, struct wmOperator *, int mode);
void paint_2d_redraw(const struct bContext *C, void *ps, bool final);
void paint_2d_stroke_done(void *ps);
-void paint_2d_stroke(
- void *ps, const float prev_mval[2], const float mval[2],
- const bool eraser, float pressure, float distance, float size);
-void paint_2d_bucket_fill(
- const struct bContext *C, const float color[3], struct Brush *br, const float mouse_init[2], void *ps);
-void paint_2d_gradient_fill(
- const struct bContext *C, struct Brush *br, const float mouse_init[2], const float mouse_final[2], void *ps);
-void *paint_proj_new_stroke(
- struct bContext *C, struct Object *ob, const float mouse[2], int mode);
-void paint_proj_stroke(
- const struct bContext *C, void *ps, const float prevmval_i[2], const float mval_i[2],
- const bool eraser, float pressure, float distance, float size);
+void paint_2d_stroke(void *ps,
+ const float prev_mval[2],
+ const float mval[2],
+ const bool eraser,
+ float pressure,
+ float distance,
+ float size);
+void paint_2d_bucket_fill(const struct bContext *C,
+ const float color[3],
+ struct Brush *br,
+ const float mouse_init[2],
+ void *ps);
+void paint_2d_gradient_fill(const struct bContext *C,
+ struct Brush *br,
+ const float mouse_init[2],
+ const float mouse_final[2],
+ void *ps);
+void *paint_proj_new_stroke(struct bContext *C, struct Object *ob, const float mouse[2], int mode);
+void paint_proj_stroke(const struct bContext *C,
+ void *ps,
+ const float prevmval_i[2],
+ const float mval_i[2],
+ const bool eraser,
+ float pressure,
+ float distance,
+ float size);
void paint_proj_redraw(const struct bContext *C, void *pps, bool final);
void paint_proj_stroke_done(void *ps);
-void paint_brush_color_get(
- struct Scene *scene, struct Brush *br,
- bool color_correction, bool invert, float distance, float pressure, float color[3],
- struct ColorManagedDisplay *display);
+void paint_brush_color_get(struct Scene *scene,
+ struct Brush *br,
+ bool color_correction,
+ bool invert,
+ float distance,
+ float pressure,
+ float color[3],
+ struct ColorManagedDisplay *display);
bool paint_use_opacity_masking(struct Brush *brush);
void paint_brush_init_tex(struct Brush *brush);
void paint_brush_exit_tex(struct Brush *brush);
@@ -221,14 +254,23 @@ void PAINT_OT_image_paint(struct wmOperatorType *ot);
void PAINT_OT_add_simple_uvs(struct wmOperatorType *ot);
/* paint_image_undo.c */
-void *image_undo_find_tile(
- ListBase *undo_tiles,
- struct Image *ima, struct ImBuf *ibuf, int x_tile, int y_tile,
- unsigned short **mask, bool validate);
-void *image_undo_push_tile(
- ListBase *undo_tiles,
- struct Image *ima, struct ImBuf *ibuf, struct ImBuf **tmpibuf, int x_tile, int y_tile,
- unsigned short **, bool **valid, bool proj, bool find_prev);
+void *image_undo_find_tile(ListBase *undo_tiles,
+ struct Image *ima,
+ struct ImBuf *ibuf,
+ int x_tile,
+ int y_tile,
+ unsigned short **mask,
+ bool validate);
+void *image_undo_push_tile(ListBase *undo_tiles,
+ struct Image *ima,
+ struct ImBuf *ibuf,
+ struct ImBuf **tmpibuf,
+ int x_tile,
+ int y_tile,
+ unsigned short **,
+ bool **valid,
+ bool proj,
+ bool find_prev);
void image_undo_remove_masks(void);
void image_undo_init_locks(void);
void image_undo_end_locks(void);
@@ -247,30 +289,37 @@ void SCULPT_OT_uv_sculpt_stroke(struct wmOperatorType *ot);
/* Convert the object-space axis-aligned bounding box (expressed as
* its minimum and maximum corners) into a screen-space rectangle,
* returns zero if the result is empty */
-bool paint_convert_bb_to_rect(
- struct rcti *rect,
- const float bb_min[3],
- const float bb_max[3],
- const struct ARegion *ar,
- struct RegionView3D *rv3d,
- struct Object *ob);
+bool paint_convert_bb_to_rect(struct rcti *rect,
+ const float bb_min[3],
+ const float bb_max[3],
+ const struct ARegion *ar,
+ struct RegionView3D *rv3d,
+ struct Object *ob);
/* Get four planes in object-space that describe the projection of
* screen_rect from screen into object-space (essentially converting a
* 2D screens-space bounding box into four 3D planes) */
-void paint_calc_redraw_planes(
- float planes[4][4],
- const struct ARegion *ar,
- struct Object *ob,
- const struct rcti *screen_rect);
-
-float paint_calc_object_space_radius(struct ViewContext *vc, const float center[3], float pixel_radius);
-float paint_get_tex_pixel(const struct MTex *mtex, float u, float v, struct ImagePool *pool, int thread);
-void paint_get_tex_pixel_col(
- const struct MTex *mtex, float u, float v, float rgba[4],
- struct ImagePool *pool, int thread, bool convert, struct ColorSpace *colorspace);
-
-void paint_sample_color(struct bContext *C, struct ARegion *ar, int x, int y, bool texpaint_proj, bool palette);
+void paint_calc_redraw_planes(float planes[4][4],
+ const struct ARegion *ar,
+ struct Object *ob,
+ const struct rcti *screen_rect);
+
+float paint_calc_object_space_radius(struct ViewContext *vc,
+ const float center[3],
+ float pixel_radius);
+float paint_get_tex_pixel(
+ const struct MTex *mtex, float u, float v, struct ImagePool *pool, int thread);
+void paint_get_tex_pixel_col(const struct MTex *mtex,
+ float u,
+ float v,
+ float rgba[4],
+ struct ImagePool *pool,
+ int thread,
+ bool convert,
+ struct ColorSpace *colorspace);
+
+void paint_sample_color(
+ struct bContext *C, struct ARegion *ar, int x, int y, bool texpaint_proj, bool palette);
void paint_stroke_operator_properties(struct wmOperatorType *ot);
@@ -295,23 +344,23 @@ void flip_qt_qt(float out[3], const float in[3], const char symm);
/* stroke operator */
typedef enum BrushStrokeMode {
- BRUSH_STROKE_NORMAL,
- BRUSH_STROKE_INVERT,
- BRUSH_STROKE_SMOOTH,
+ BRUSH_STROKE_NORMAL,
+ BRUSH_STROKE_INVERT,
+ BRUSH_STROKE_SMOOTH,
} BrushStrokeMode;
/* paint_hide.c */
typedef enum {
- PARTIALVIS_HIDE,
- PARTIALVIS_SHOW,
+ PARTIALVIS_HIDE,
+ PARTIALVIS_SHOW,
} PartialVisAction;
typedef enum {
- PARTIALVIS_INSIDE,
- PARTIALVIS_OUTSIDE,
- PARTIALVIS_ALL,
- PARTIALVIS_MASKED,
+ PARTIALVIS_INSIDE,
+ PARTIALVIS_OUTSIDE,
+ PARTIALVIS_ALL,
+ PARTIALVIS_MASKED,
} PartialVisArea;
void PAINT_OT_hide_show(struct wmOperatorType *ot);
@@ -319,9 +368,9 @@ void PAINT_OT_hide_show(struct wmOperatorType *ot);
/* paint_mask.c */
typedef enum {
- PAINT_MASK_FLOOD_VALUE,
- PAINT_MASK_FLOOD_VALUE_INVERSE,
- PAINT_MASK_INVERT,
+ PAINT_MASK_FLOOD_VALUE,
+ PAINT_MASK_FLOOD_VALUE_INVERSE,
+ PAINT_MASK_INVERT,
} PaintMaskFloodMode;
void PAINT_OT_mask_flood_fill(struct wmOperatorType *ot);
@@ -338,10 +387,10 @@ void PAINTCURVE_OT_cursor(struct wmOperatorType *ot);
/* image painting blur kernel */
typedef struct {
- float *wdata; /* actual kernel */
- int side; /* kernel side */
- int side_squared; /* data side */
- int pixel_len; /* pixels around center that kernel is wide */
+ float *wdata; /* actual kernel */
+ int side; /* kernel side */
+ int side_squared; /* data side */
+ int pixel_len; /* pixels around center that kernel is wide */
} BlurKernel;
enum eBlurKernelType;
diff --git a/source/blender/editors/sculpt_paint/paint_mask.c b/source/blender/editors/sculpt_paint/paint_mask.c
index b88ae861229..ca48030daed 100644
--- a/source/blender/editors/sculpt_paint/paint_mask.c
+++ b/source/blender/editors/sculpt_paint/paint_mask.c
@@ -60,478 +60,503 @@
#include <stdlib.h>
static const EnumPropertyItem mode_items[] = {
- {PAINT_MASK_FLOOD_VALUE, "VALUE", 0, "Value", "Set mask to the level specified by the 'value' property"},
- {PAINT_MASK_FLOOD_VALUE_INVERSE, "VALUE_INVERSE", 0, "Value Inverted", "Set mask to the level specified by the inverted 'value' property"},
- {PAINT_MASK_INVERT, "INVERT", 0, "Invert", "Invert the mask"},
- {0}};
-
-
-static void mask_flood_fill_set_elem(
- float *elem,
- PaintMaskFloodMode mode,
- float value)
+ {PAINT_MASK_FLOOD_VALUE,
+ "VALUE",
+ 0,
+ "Value",
+ "Set mask to the level specified by the 'value' property"},
+ {PAINT_MASK_FLOOD_VALUE_INVERSE,
+ "VALUE_INVERSE",
+ 0,
+ "Value Inverted",
+ "Set mask to the level specified by the inverted 'value' property"},
+ {PAINT_MASK_INVERT, "INVERT", 0, "Invert", "Invert the mask"},
+ {0}};
+
+static void mask_flood_fill_set_elem(float *elem, PaintMaskFloodMode mode, float value)
{
- switch (mode) {
- case PAINT_MASK_FLOOD_VALUE:
- (*elem) = value;
- break;
- case PAINT_MASK_FLOOD_VALUE_INVERSE:
- (*elem) = 1.0f - value;
- break;
- case PAINT_MASK_INVERT:
- (*elem) = 1.0f - (*elem);
- break;
- }
+ switch (mode) {
+ case PAINT_MASK_FLOOD_VALUE:
+ (*elem) = value;
+ break;
+ case PAINT_MASK_FLOOD_VALUE_INVERSE:
+ (*elem) = 1.0f - value;
+ break;
+ case PAINT_MASK_INVERT:
+ (*elem) = 1.0f - (*elem);
+ break;
+ }
}
typedef struct MaskTaskData {
- Object *ob;
- PBVH *pbvh;
- PBVHNode **nodes;
- bool multires;
-
- PaintMaskFloodMode mode;
- float value;
- float (*clip_planes_final)[4];
+ Object *ob;
+ PBVH *pbvh;
+ PBVHNode **nodes;
+ bool multires;
+
+ PaintMaskFloodMode mode;
+ float value;
+ float (*clip_planes_final)[4];
} MaskTaskData;
-static void mask_flood_fill_task_cb(
- void *__restrict userdata,
- const int i,
- const ParallelRangeTLS *__restrict UNUSED(tls))
+static void mask_flood_fill_task_cb(void *__restrict userdata,
+ const int i,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
- MaskTaskData *data = userdata;
+ MaskTaskData *data = userdata;
- PBVHNode *node = data->nodes[i];
+ PBVHNode *node = data->nodes[i];
- const PaintMaskFloodMode mode = data->mode;
- const float value = data->value;
+ const PaintMaskFloodMode mode = data->mode;
+ const float value = data->value;
- PBVHVertexIter vi;
+ PBVHVertexIter vi;
- sculpt_undo_push_node(data->ob, node, SCULPT_UNDO_MASK);
+ sculpt_undo_push_node(data->ob, node, SCULPT_UNDO_MASK);
- BKE_pbvh_vertex_iter_begin(data->pbvh, node, vi, PBVH_ITER_UNIQUE) {
- mask_flood_fill_set_elem(vi.mask, mode, value);
- } BKE_pbvh_vertex_iter_end;
+ BKE_pbvh_vertex_iter_begin(data->pbvh, node, vi, PBVH_ITER_UNIQUE)
+ {
+ mask_flood_fill_set_elem(vi.mask, mode, value);
+ }
+ BKE_pbvh_vertex_iter_end;
- BKE_pbvh_node_mark_redraw(node);
- if (data->multires)
- BKE_pbvh_node_mark_normals_update(node);
+ BKE_pbvh_node_mark_redraw(node);
+ if (data->multires)
+ BKE_pbvh_node_mark_normals_update(node);
}
static int mask_flood_fill_exec(bContext *C, wmOperator *op)
{
- ARegion *ar = CTX_wm_region(C);
- struct Scene *scene = CTX_data_scene(C);
- Object *ob = CTX_data_active_object(C);
- Depsgraph *depsgraph = CTX_data_depsgraph(C);
- PaintMaskFloodMode mode;
- float value;
- PBVH *pbvh;
- PBVHNode **nodes;
- int totnode;
- bool multires;
- Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
+ ARegion *ar = CTX_wm_region(C);
+ struct Scene *scene = CTX_data_scene(C);
+ Object *ob = CTX_data_active_object(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ PaintMaskFloodMode mode;
+ float value;
+ PBVH *pbvh;
+ PBVHNode **nodes;
+ int totnode;
+ bool multires;
+ Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
- mode = RNA_enum_get(op->ptr, "mode");
- value = RNA_float_get(op->ptr, "value");
+ mode = RNA_enum_get(op->ptr, "mode");
+ value = RNA_float_get(op->ptr, "value");
- BKE_sculpt_update_mesh_elements(depsgraph, scene, sd, ob, false, true);
- pbvh = ob->sculpt->pbvh;
- multires = (BKE_pbvh_type(pbvh) == PBVH_GRIDS);
+ BKE_sculpt_update_mesh_elements(depsgraph, scene, sd, ob, false, true);
+ pbvh = ob->sculpt->pbvh;
+ multires = (BKE_pbvh_type(pbvh) == PBVH_GRIDS);
- BKE_pbvh_search_gather(pbvh, NULL, NULL, &nodes, &totnode);
+ BKE_pbvh_search_gather(pbvh, NULL, NULL, &nodes, &totnode);
- sculpt_undo_push_begin("Mask flood fill");
+ sculpt_undo_push_begin("Mask flood fill");
- MaskTaskData data = {
- .ob = ob, .pbvh = pbvh, .nodes = nodes, .multires = multires,
- .mode = mode, .value = value,
- };
+ MaskTaskData data = {
+ .ob = ob,
+ .pbvh = pbvh,
+ .nodes = nodes,
+ .multires = multires,
+ .mode = mode,
+ .value = value,
+ };
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
- BLI_task_parallel_range(
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
+ BLI_task_parallel_range(
- 0, totnode, &data, mask_flood_fill_task_cb,
- &settings);
+ 0, totnode, &data, mask_flood_fill_task_cb, &settings);
- if (multires)
- multires_mark_as_modified(ob, MULTIRES_COORDS_MODIFIED);
+ if (multires)
+ multires_mark_as_modified(ob, MULTIRES_COORDS_MODIFIED);
- sculpt_undo_push_end();
+ sculpt_undo_push_end();
- if (nodes)
- MEM_freeN(nodes);
+ if (nodes)
+ MEM_freeN(nodes);
- ED_region_tag_redraw(ar);
+ ED_region_tag_redraw(ar);
- WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
- return OPERATOR_FINISHED;
+ return OPERATOR_FINISHED;
}
void PAINT_OT_mask_flood_fill(struct wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Mask Flood Fill";
- ot->idname = "PAINT_OT_mask_flood_fill";
- ot->description = "Fill the whole mask with a given value, or invert its values";
-
- /* api callbacks */
- ot->exec = mask_flood_fill_exec;
- ot->poll = sculpt_mode_poll;
-
- ot->flag = OPTYPE_REGISTER;
-
- /* rna */
- RNA_def_enum(ot->srna, "mode", mode_items, PAINT_MASK_FLOOD_VALUE, "Mode", NULL);
- RNA_def_float(ot->srna, "value", 0, 0, 1, "Value",
- "Mask level to use when mode is 'Value'; zero means no masking and one is fully masked", 0, 1);
+ /* identifiers */
+ ot->name = "Mask Flood Fill";
+ ot->idname = "PAINT_OT_mask_flood_fill";
+ ot->description = "Fill the whole mask with a given value, or invert its values";
+
+ /* api callbacks */
+ ot->exec = mask_flood_fill_exec;
+ ot->poll = sculpt_mode_poll;
+
+ ot->flag = OPTYPE_REGISTER;
+
+ /* rna */
+ RNA_def_enum(ot->srna, "mode", mode_items, PAINT_MASK_FLOOD_VALUE, "Mode", NULL);
+ RNA_def_float(
+ ot->srna,
+ "value",
+ 0,
+ 0,
+ 1,
+ "Value",
+ "Mask level to use when mode is 'Value'; zero means no masking and one is fully masked",
+ 0,
+ 1);
}
/* Box select, operator is VIEW3D_OT_select_box, defined in view3d_select.c */
static bool is_effected(float planes[4][4], const float co[3])
{
- return isect_point_planes_v3(planes, 4, co);
+ return isect_point_planes_v3(planes, 4, co);
}
static void flip_plane(float out[4], const float in[4], const char symm)
{
- if (symm & PAINT_SYMM_X)
- out[0] = -in[0];
- else
- out[0] = in[0];
- if (symm & PAINT_SYMM_Y)
- out[1] = -in[1];
- else
- out[1] = in[1];
- if (symm & PAINT_SYMM_Z)
- out[2] = -in[2];
- else
- out[2] = in[2];
-
- out[3] = in[3];
+ if (symm & PAINT_SYMM_X)
+ out[0] = -in[0];
+ else
+ out[0] = in[0];
+ if (symm & PAINT_SYMM_Y)
+ out[1] = -in[1];
+ else
+ out[1] = in[1];
+ if (symm & PAINT_SYMM_Z)
+ out[2] = -in[2];
+ else
+ out[2] = in[2];
+
+ out[3] = in[3];
}
-static void mask_box_select_task_cb(
- void *__restrict userdata,
- const int i,
- const ParallelRangeTLS *__restrict UNUSED(tls))
+static void mask_box_select_task_cb(void *__restrict userdata,
+ const int i,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
- MaskTaskData *data = userdata;
+ MaskTaskData *data = userdata;
- PBVHNode *node = data->nodes[i];
+ PBVHNode *node = data->nodes[i];
- const PaintMaskFloodMode mode = data->mode;
- const float value = data->value;
- float (*clip_planes_final)[4] = data->clip_planes_final;
+ const PaintMaskFloodMode mode = data->mode;
+ const float value = data->value;
+ float(*clip_planes_final)[4] = data->clip_planes_final;
- PBVHVertexIter vi;
- bool any_masked = false;
+ PBVHVertexIter vi;
+ bool any_masked = false;
- BKE_pbvh_vertex_iter_begin(data->pbvh, node, vi, PBVH_ITER_UNIQUE) {
- if (is_effected(clip_planes_final, vi.co)) {
- if (!any_masked) {
- any_masked = true;
+ BKE_pbvh_vertex_iter_begin(data->pbvh, node, vi, PBVH_ITER_UNIQUE)
+ {
+ if (is_effected(clip_planes_final, vi.co)) {
+ if (!any_masked) {
+ any_masked = true;
- sculpt_undo_push_node(data->ob, node, SCULPT_UNDO_MASK);
+ sculpt_undo_push_node(data->ob, node, SCULPT_UNDO_MASK);
- BKE_pbvh_node_mark_redraw(node);
- if (data->multires)
- BKE_pbvh_node_mark_normals_update(node);
- }
- mask_flood_fill_set_elem(vi.mask, mode, value);
- }
- } BKE_pbvh_vertex_iter_end;
+ BKE_pbvh_node_mark_redraw(node);
+ if (data->multires)
+ BKE_pbvh_node_mark_normals_update(node);
+ }
+ mask_flood_fill_set_elem(vi.mask, mode, value);
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
}
bool ED_sculpt_mask_box_select(struct bContext *C, ViewContext *vc, const rcti *rect, bool select)
{
- Depsgraph *depsgraph = CTX_data_depsgraph(C);
- Sculpt *sd = vc->scene->toolsettings->sculpt;
- BoundBox bb;
- float clip_planes[4][4];
- float clip_planes_final[4][4];
- ARegion *ar = vc->ar;
- struct Scene *scene = vc->scene;
- Object *ob = vc->obact;
- PaintMaskFloodMode mode;
- float value;
- bool multires;
- PBVH *pbvh;
- PBVHNode **nodes;
- int totnode, symmpass;
- int symm = sd->paint.symmetry_flags & PAINT_SYMM_AXIS_ALL;
-
- mode = PAINT_MASK_FLOOD_VALUE;
- value = select ? 1.0 : 0.0;
-
- /* transform the clip planes in object space */
- ED_view3d_clipping_calc(&bb, clip_planes, vc->ar, vc->obact, rect);
- negate_m4(clip_planes);
-
- BKE_sculpt_update_mesh_elements(depsgraph, scene, sd, ob, false, true);
- pbvh = ob->sculpt->pbvh;
- multires = (BKE_pbvh_type(pbvh) == PBVH_GRIDS);
-
- sculpt_undo_push_begin("Mask box fill");
-
- for (symmpass = 0; symmpass <= symm; ++symmpass) {
- if (symmpass == 0 ||
- (symm & symmpass &&
- (symm != 5 || symmpass != 3) &&
- (symm != 6 || (symmpass != 3 && symmpass != 5))))
- {
- int j = 0;
-
- /* flip the planes symmetrically as needed */
- for (; j < 4; j++) {
- flip_plane(clip_planes_final[j], clip_planes[j], symmpass);
- }
-
- BKE_pbvh_search_gather(pbvh, BKE_pbvh_node_planes_contain_AABB, clip_planes_final, &nodes, &totnode);
-
- MaskTaskData data = {
- .ob = ob, .pbvh = pbvh, .nodes = nodes, .multires = multires,
- .mode = mode, .value = value, .clip_planes_final = clip_planes_final,
- };
-
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
- BLI_task_parallel_range(
- 0, totnode, &data, mask_box_select_task_cb,
- &settings);
-
- if (nodes)
- MEM_freeN(nodes);
- }
- }
-
- if (multires)
- multires_mark_as_modified(ob, MULTIRES_COORDS_MODIFIED);
-
- sculpt_undo_push_end();
-
- ED_region_tag_redraw(ar);
-
- WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
-
- return true;
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ Sculpt *sd = vc->scene->toolsettings->sculpt;
+ BoundBox bb;
+ float clip_planes[4][4];
+ float clip_planes_final[4][4];
+ ARegion *ar = vc->ar;
+ struct Scene *scene = vc->scene;
+ Object *ob = vc->obact;
+ PaintMaskFloodMode mode;
+ float value;
+ bool multires;
+ PBVH *pbvh;
+ PBVHNode **nodes;
+ int totnode, symmpass;
+ int symm = sd->paint.symmetry_flags & PAINT_SYMM_AXIS_ALL;
+
+ mode = PAINT_MASK_FLOOD_VALUE;
+ value = select ? 1.0 : 0.0;
+
+ /* transform the clip planes in object space */
+ ED_view3d_clipping_calc(&bb, clip_planes, vc->ar, vc->obact, rect);
+ negate_m4(clip_planes);
+
+ BKE_sculpt_update_mesh_elements(depsgraph, scene, sd, ob, false, true);
+ pbvh = ob->sculpt->pbvh;
+ multires = (BKE_pbvh_type(pbvh) == PBVH_GRIDS);
+
+ sculpt_undo_push_begin("Mask box fill");
+
+ for (symmpass = 0; symmpass <= symm; ++symmpass) {
+ if (symmpass == 0 || (symm & symmpass && (symm != 5 || symmpass != 3) &&
+ (symm != 6 || (symmpass != 3 && symmpass != 5)))) {
+ int j = 0;
+
+ /* flip the planes symmetrically as needed */
+ for (; j < 4; j++) {
+ flip_plane(clip_planes_final[j], clip_planes[j], symmpass);
+ }
+
+ BKE_pbvh_search_gather(
+ pbvh, BKE_pbvh_node_planes_contain_AABB, clip_planes_final, &nodes, &totnode);
+
+ MaskTaskData data = {
+ .ob = ob,
+ .pbvh = pbvh,
+ .nodes = nodes,
+ .multires = multires,
+ .mode = mode,
+ .value = value,
+ .clip_planes_final = clip_planes_final,
+ };
+
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) &&
+ totnode > SCULPT_THREADED_LIMIT);
+ BLI_task_parallel_range(0, totnode, &data, mask_box_select_task_cb, &settings);
+
+ if (nodes)
+ MEM_freeN(nodes);
+ }
+ }
+
+ if (multires)
+ multires_mark_as_modified(ob, MULTIRES_COORDS_MODIFIED);
+
+ sculpt_undo_push_end();
+
+ ED_region_tag_redraw(ar);
+
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
+
+ return true;
}
typedef struct LassoMaskData {
- struct ViewContext *vc;
- float projviewobjmat[4][4];
- BLI_bitmap *px;
- int width;
- rcti rect; /* bounding box for scanfilling */
- int symmpass;
-
- MaskTaskData task_data;
+ struct ViewContext *vc;
+ float projviewobjmat[4][4];
+ BLI_bitmap *px;
+ int width;
+ rcti rect; /* bounding box for scanfilling */
+ int symmpass;
+
+ MaskTaskData task_data;
} LassoMaskData;
-
/* Lasso select. This could be defined as part of VIEW3D_OT_select_lasso, still the shortcuts conflict,
* so we will use a separate operator */
static bool is_effected_lasso(LassoMaskData *data, float co[3])
{
- float scr_co_f[2];
- int scr_co_s[2];
- float co_final[3];
-
- flip_v3_v3(co_final, co, data->symmpass);
- /* first project point to 2d space */
- ED_view3d_project_float_v2_m4(data->vc->ar, co_final, scr_co_f, data->projviewobjmat);
-
- scr_co_s[0] = scr_co_f[0];
- scr_co_s[1] = scr_co_f[1];
-
- /* clip against screen, because lasso is limited to screen only */
- if ((scr_co_s[0] < data->rect.xmin) ||
- (scr_co_s[1] < data->rect.ymin) ||
- (scr_co_s[0] >= data->rect.xmax) ||
- (scr_co_s[1] >= data->rect.ymax))
- {
- return false;
- }
-
- scr_co_s[0] -= data->rect.xmin;
- scr_co_s[1] -= data->rect.ymin;
-
- return BLI_BITMAP_TEST_BOOL(data->px, scr_co_s[1] * data->width + scr_co_s[0]);
+ float scr_co_f[2];
+ int scr_co_s[2];
+ float co_final[3];
+
+ flip_v3_v3(co_final, co, data->symmpass);
+ /* first project point to 2d space */
+ ED_view3d_project_float_v2_m4(data->vc->ar, co_final, scr_co_f, data->projviewobjmat);
+
+ scr_co_s[0] = scr_co_f[0];
+ scr_co_s[1] = scr_co_f[1];
+
+ /* clip against screen, because lasso is limited to screen only */
+ if ((scr_co_s[0] < data->rect.xmin) || (scr_co_s[1] < data->rect.ymin) ||
+ (scr_co_s[0] >= data->rect.xmax) || (scr_co_s[1] >= data->rect.ymax)) {
+ return false;
+ }
+
+ scr_co_s[0] -= data->rect.xmin;
+ scr_co_s[1] -= data->rect.ymin;
+
+ return BLI_BITMAP_TEST_BOOL(data->px, scr_co_s[1] * data->width + scr_co_s[0]);
}
static void mask_lasso_px_cb(int x, int x_end, int y, void *user_data)
{
- LassoMaskData *data = user_data;
- int index = (y * data->width) + x;
- int index_end = (y * data->width) + x_end;
- do {
- BLI_BITMAP_ENABLE(data->px, index);
- } while (++index != index_end);
+ LassoMaskData *data = user_data;
+ int index = (y * data->width) + x;
+ int index_end = (y * data->width) + x_end;
+ do {
+ BLI_BITMAP_ENABLE(data->px, index);
+ } while (++index != index_end);
}
-static void mask_gesture_lasso_task_cb(
- void *__restrict userdata,
- const int i,
- const ParallelRangeTLS *__restrict UNUSED(tls))
+static void mask_gesture_lasso_task_cb(void *__restrict userdata,
+ const int i,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
- LassoMaskData *lasso_data = userdata;
- MaskTaskData *data = &lasso_data->task_data;
+ LassoMaskData *lasso_data = userdata;
+ MaskTaskData *data = &lasso_data->task_data;
- PBVHNode *node = data->nodes[i];
+ PBVHNode *node = data->nodes[i];
- const PaintMaskFloodMode mode = data->mode;
- const float value = data->value;
+ const PaintMaskFloodMode mode = data->mode;
+ const float value = data->value;
- PBVHVertexIter vi;
- bool any_masked = false;
+ PBVHVertexIter vi;
+ bool any_masked = false;
- BKE_pbvh_vertex_iter_begin(data->pbvh, node, vi, PBVH_ITER_UNIQUE) {
- if (is_effected_lasso(lasso_data, vi.co)) {
- if (!any_masked) {
- any_masked = true;
+ BKE_pbvh_vertex_iter_begin(data->pbvh, node, vi, PBVH_ITER_UNIQUE)
+ {
+ if (is_effected_lasso(lasso_data, vi.co)) {
+ if (!any_masked) {
+ any_masked = true;
- sculpt_undo_push_node(data->ob, node, SCULPT_UNDO_MASK);
+ sculpt_undo_push_node(data->ob, node, SCULPT_UNDO_MASK);
- BKE_pbvh_node_mark_redraw(node);
- if (data->multires)
- BKE_pbvh_node_mark_normals_update(node);
- }
+ BKE_pbvh_node_mark_redraw(node);
+ if (data->multires)
+ BKE_pbvh_node_mark_normals_update(node);
+ }
- mask_flood_fill_set_elem(vi.mask, mode, value);
- }
- } BKE_pbvh_vertex_iter_end;
+ mask_flood_fill_set_elem(vi.mask, mode, value);
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
}
static int paint_mask_gesture_lasso_exec(bContext *C, wmOperator *op)
{
- int mcords_tot;
- const int (*mcords)[2] = WM_gesture_lasso_path_to_array(C, op, &mcords_tot);
-
- if (mcords) {
- Depsgraph *depsgraph = CTX_data_depsgraph(C);
- float clip_planes[4][4], clip_planes_final[4][4];
- BoundBox bb;
- Object *ob;
- ViewContext vc;
- LassoMaskData data;
- struct Scene *scene = CTX_data_scene(C);
- Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
- int symm = sd->paint.symmetry_flags & PAINT_SYMM_AXIS_ALL;
- PBVH *pbvh;
- PBVHNode **nodes;
- int totnode, symmpass;
- bool multires;
- PaintMaskFloodMode mode = RNA_enum_get(op->ptr, "mode");
- float value = RNA_float_get(op->ptr, "value");
-
- /* Calculations of individual vertices are done in 2D screen space to diminish the amount of
- * calculations done. Bounding box PBVH collision is not computed against enclosing rectangle
- * of lasso */
- ED_view3d_viewcontext_init(C, &vc);
-
- /* lasso data calculations */
- data.vc = &vc;
- ob = vc.obact;
- ED_view3d_ob_project_mat_get(vc.rv3d, ob, data.projviewobjmat);
-
- BLI_lasso_boundbox(&data.rect, mcords, mcords_tot);
- data.width = data.rect.xmax - data.rect.xmin;
- data.px = BLI_BITMAP_NEW(data.width * (data.rect.ymax - data.rect.ymin), __func__);
-
- BLI_bitmap_draw_2d_poly_v2i_n(
- data.rect.xmin, data.rect.ymin, data.rect.xmax, data.rect.ymax,
- mcords, mcords_tot,
- mask_lasso_px_cb, &data);
-
- ED_view3d_clipping_calc(&bb, clip_planes, vc.ar, vc.obact, &data.rect);
- negate_m4(clip_planes);
-
- BKE_sculpt_update_mesh_elements(depsgraph, scene, sd, ob, false, true);
- pbvh = ob->sculpt->pbvh;
- multires = (BKE_pbvh_type(pbvh) == PBVH_GRIDS);
-
- sculpt_undo_push_begin("Mask lasso fill");
-
- for (symmpass = 0; symmpass <= symm; ++symmpass) {
- if ((symmpass == 0) ||
- (symm & symmpass &&
- (symm != 5 || symmpass != 3) &&
- (symm != 6 || (symmpass != 3 && symmpass != 5))))
- {
- int j = 0;
-
- /* flip the planes symmetrically as needed */
- for (; j < 4; j++) {
- flip_plane(clip_planes_final[j], clip_planes[j], symmpass);
- }
-
- data.symmpass = symmpass;
-
- /* gather nodes inside lasso's enclosing rectangle
- * (should greatly help with bigger meshes) */
- BKE_pbvh_search_gather(pbvh, BKE_pbvh_node_planes_contain_AABB, clip_planes_final, &nodes, &totnode);
-
- data.task_data.ob = ob;
- data.task_data.pbvh = pbvh;
- data.task_data.nodes = nodes;
- data.task_data.multires = multires;
- data.task_data.mode = mode;
- data.task_data.value = value;
-
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && (totnode > SCULPT_THREADED_LIMIT));
- BLI_task_parallel_range(
- 0, totnode, &data, mask_gesture_lasso_task_cb,
- &settings);
-
- if (nodes)
- MEM_freeN(nodes);
- }
- }
-
- if (multires)
- multires_mark_as_modified(ob, MULTIRES_COORDS_MODIFIED);
-
- sculpt_undo_push_end();
-
- ED_region_tag_redraw(vc.ar);
- MEM_freeN((void *)mcords);
- MEM_freeN(data.px);
-
- WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
-
- return OPERATOR_FINISHED;
- }
- return OPERATOR_PASS_THROUGH;
+ int mcords_tot;
+ const int(*mcords)[2] = WM_gesture_lasso_path_to_array(C, op, &mcords_tot);
+
+ if (mcords) {
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ float clip_planes[4][4], clip_planes_final[4][4];
+ BoundBox bb;
+ Object *ob;
+ ViewContext vc;
+ LassoMaskData data;
+ struct Scene *scene = CTX_data_scene(C);
+ Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
+ int symm = sd->paint.symmetry_flags & PAINT_SYMM_AXIS_ALL;
+ PBVH *pbvh;
+ PBVHNode **nodes;
+ int totnode, symmpass;
+ bool multires;
+ PaintMaskFloodMode mode = RNA_enum_get(op->ptr, "mode");
+ float value = RNA_float_get(op->ptr, "value");
+
+ /* Calculations of individual vertices are done in 2D screen space to diminish the amount of
+ * calculations done. Bounding box PBVH collision is not computed against enclosing rectangle
+ * of lasso */
+ ED_view3d_viewcontext_init(C, &vc);
+
+ /* lasso data calculations */
+ data.vc = &vc;
+ ob = vc.obact;
+ ED_view3d_ob_project_mat_get(vc.rv3d, ob, data.projviewobjmat);
+
+ BLI_lasso_boundbox(&data.rect, mcords, mcords_tot);
+ data.width = data.rect.xmax - data.rect.xmin;
+ data.px = BLI_BITMAP_NEW(data.width * (data.rect.ymax - data.rect.ymin), __func__);
+
+ BLI_bitmap_draw_2d_poly_v2i_n(data.rect.xmin,
+ data.rect.ymin,
+ data.rect.xmax,
+ data.rect.ymax,
+ mcords,
+ mcords_tot,
+ mask_lasso_px_cb,
+ &data);
+
+ ED_view3d_clipping_calc(&bb, clip_planes, vc.ar, vc.obact, &data.rect);
+ negate_m4(clip_planes);
+
+ BKE_sculpt_update_mesh_elements(depsgraph, scene, sd, ob, false, true);
+ pbvh = ob->sculpt->pbvh;
+ multires = (BKE_pbvh_type(pbvh) == PBVH_GRIDS);
+
+ sculpt_undo_push_begin("Mask lasso fill");
+
+ for (symmpass = 0; symmpass <= symm; ++symmpass) {
+ if ((symmpass == 0) || (symm & symmpass && (symm != 5 || symmpass != 3) &&
+ (symm != 6 || (symmpass != 3 && symmpass != 5)))) {
+ int j = 0;
+
+ /* flip the planes symmetrically as needed */
+ for (; j < 4; j++) {
+ flip_plane(clip_planes_final[j], clip_planes[j], symmpass);
+ }
+
+ data.symmpass = symmpass;
+
+ /* gather nodes inside lasso's enclosing rectangle
+ * (should greatly help with bigger meshes) */
+ BKE_pbvh_search_gather(
+ pbvh, BKE_pbvh_node_planes_contain_AABB, clip_planes_final, &nodes, &totnode);
+
+ data.task_data.ob = ob;
+ data.task_data.pbvh = pbvh;
+ data.task_data.nodes = nodes;
+ data.task_data.multires = multires;
+ data.task_data.mode = mode;
+ data.task_data.value = value;
+
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) &&
+ (totnode > SCULPT_THREADED_LIMIT));
+ BLI_task_parallel_range(0, totnode, &data, mask_gesture_lasso_task_cb, &settings);
+
+ if (nodes)
+ MEM_freeN(nodes);
+ }
+ }
+
+ if (multires)
+ multires_mark_as_modified(ob, MULTIRES_COORDS_MODIFIED);
+
+ sculpt_undo_push_end();
+
+ ED_region_tag_redraw(vc.ar);
+ MEM_freeN((void *)mcords);
+ MEM_freeN(data.px);
+
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
+
+ return OPERATOR_FINISHED;
+ }
+ return OPERATOR_PASS_THROUGH;
}
void PAINT_OT_mask_lasso_gesture(wmOperatorType *ot)
{
- ot->name = "Mask Lasso Gesture";
- ot->idname = "PAINT_OT_mask_lasso_gesture";
- ot->description = "Add mask within the lasso as you move the brush";
-
- ot->invoke = WM_gesture_lasso_invoke;
- ot->modal = WM_gesture_lasso_modal;
- ot->exec = paint_mask_gesture_lasso_exec;
-
- ot->poll = sculpt_mode_poll;
-
- ot->flag = OPTYPE_REGISTER;
-
- /* properties */
- WM_operator_properties_gesture_lasso(ot);
-
- RNA_def_enum(ot->srna, "mode", mode_items, PAINT_MASK_FLOOD_VALUE, "Mode", NULL);
- RNA_def_float(ot->srna, "value", 1.0, 0, 1.0, "Value",
- "Mask level to use when mode is 'Value'; zero means no masking and one is fully masked", 0, 1);
+ ot->name = "Mask Lasso Gesture";
+ ot->idname = "PAINT_OT_mask_lasso_gesture";
+ ot->description = "Add mask within the lasso as you move the brush";
+
+ ot->invoke = WM_gesture_lasso_invoke;
+ ot->modal = WM_gesture_lasso_modal;
+ ot->exec = paint_mask_gesture_lasso_exec;
+
+ ot->poll = sculpt_mode_poll;
+
+ ot->flag = OPTYPE_REGISTER;
+
+ /* properties */
+ WM_operator_properties_gesture_lasso(ot);
+
+ RNA_def_enum(ot->srna, "mode", mode_items, PAINT_MASK_FLOOD_VALUE, "Mode", NULL);
+ RNA_def_float(
+ ot->srna,
+ "value",
+ 1.0,
+ 0,
+ 1.0,
+ "Value",
+ "Mask level to use when mode is 'Value'; zero means no masking and one is fully masked",
+ 0,
+ 1);
}
diff --git a/source/blender/editors/sculpt_paint/paint_ops.c b/source/blender/editors/sculpt_paint/paint_ops.c
index 218d3ce4273..6686e255b08 100644
--- a/source/blender/editors/sculpt_paint/paint_ops.c
+++ b/source/blender/editors/sculpt_paint/paint_ops.c
@@ -66,1030 +66,1027 @@
/* Brush operators */
static int brush_add_exec(bContext *C, wmOperator *UNUSED(op))
{
- /*int type = RNA_enum_get(op->ptr, "type");*/
- Paint *paint = BKE_paint_get_active_from_context(C);
- Brush *br = BKE_paint_brush(paint);
- Main *bmain = CTX_data_main(C);
- ePaintMode mode = BKE_paintmode_get_active_from_context(C);
-
- if (br) {
- br = BKE_brush_copy(bmain, br);
- }
- else {
- br = BKE_brush_add(bmain, "Brush", BKE_paint_object_mode_from_paintmode(mode));
- id_us_min(&br->id); /* fake user only */
- }
-
- BKE_paint_brush_set(paint, br);
-
- return OPERATOR_FINISHED;
+ /*int type = RNA_enum_get(op->ptr, "type");*/
+ Paint *paint = BKE_paint_get_active_from_context(C);
+ Brush *br = BKE_paint_brush(paint);
+ Main *bmain = CTX_data_main(C);
+ ePaintMode mode = BKE_paintmode_get_active_from_context(C);
+
+ if (br) {
+ br = BKE_brush_copy(bmain, br);
+ }
+ else {
+ br = BKE_brush_add(bmain, "Brush", BKE_paint_object_mode_from_paintmode(mode));
+ id_us_min(&br->id); /* fake user only */
+ }
+
+ BKE_paint_brush_set(paint, br);
+
+ return OPERATOR_FINISHED;
}
static void BRUSH_OT_add(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Add Brush";
- ot->description = "Add brush by mode type";
- ot->idname = "BRUSH_OT_add";
+ /* identifiers */
+ ot->name = "Add Brush";
+ ot->description = "Add brush by mode type";
+ ot->idname = "BRUSH_OT_add";
- /* api callbacks */
- ot->exec = brush_add_exec;
+ /* api callbacks */
+ ot->exec = brush_add_exec;
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
static int brush_add_gpencil_exec(bContext *C, wmOperator *UNUSED(op))
{
- /*int type = RNA_enum_get(op->ptr, "type");*/
- ToolSettings *ts = CTX_data_tool_settings(C);
- Paint *paint = &ts->gp_paint->paint;
- Brush *br = BKE_paint_brush(paint);
- Main *bmain = CTX_data_main(C);
- // ePaintMode mode = PAINT_MODE_GPENCIL;
-
- if (br) {
- br = BKE_brush_copy(bmain, br);
- }
- else {
- br = BKE_brush_add(bmain, "Brush", OB_MODE_PAINT_GPENCIL);
- id_us_min(&br->id); /* fake user only */
- }
-
- BKE_paint_brush_set(paint, br);
-
- /* init grease pencil specific data */
- BKE_brush_init_gpencil_settings(br);
-
- return OPERATOR_FINISHED;
+ /*int type = RNA_enum_get(op->ptr, "type");*/
+ ToolSettings *ts = CTX_data_tool_settings(C);
+ Paint *paint = &ts->gp_paint->paint;
+ Brush *br = BKE_paint_brush(paint);
+ Main *bmain = CTX_data_main(C);
+ // ePaintMode mode = PAINT_MODE_GPENCIL;
+
+ if (br) {
+ br = BKE_brush_copy(bmain, br);
+ }
+ else {
+ br = BKE_brush_add(bmain, "Brush", OB_MODE_PAINT_GPENCIL);
+ id_us_min(&br->id); /* fake user only */
+ }
+
+ BKE_paint_brush_set(paint, br);
+
+ /* init grease pencil specific data */
+ BKE_brush_init_gpencil_settings(br);
+
+ return OPERATOR_FINISHED;
}
static void BRUSH_OT_add_gpencil(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Add Drawing Brush";
- ot->description = "Add brush for Grease Pencil";
- ot->idname = "BRUSH_OT_add_gpencil";
+ /* identifiers */
+ ot->name = "Add Drawing Brush";
+ ot->description = "Add brush for Grease Pencil";
+ ot->idname = "BRUSH_OT_add_gpencil";
- /* api callbacks */
- ot->exec = brush_add_gpencil_exec;
+ /* api callbacks */
+ ot->exec = brush_add_gpencil_exec;
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
static int brush_scale_size_exec(bContext *C, wmOperator *op)
{
- Scene *scene = CTX_data_scene(C);
- Paint *paint = BKE_paint_get_active_from_context(C);
- Brush *brush = BKE_paint_brush(paint);
- // Object *ob = CTX_data_active_object(C);
- float scalar = RNA_float_get(op->ptr, "scalar");
-
- if (brush) {
- // pixel radius
- {
- const int old_size = BKE_brush_size_get(scene, brush);
- int size = (int)(scalar * old_size);
-
- if (abs(old_size - size) < U.pixelsize) {
- if (scalar > 1) {
- size += U.pixelsize;
- }
- else if (scalar < 1) {
- size -= U.pixelsize;
- }
- }
-
- BKE_brush_size_set(scene, brush, size);
- }
-
- // unprojected radius
- {
- float unprojected_radius = scalar * BKE_brush_unprojected_radius_get(scene, brush);
-
- if (unprojected_radius < 0.001f) // XXX magic number
- unprojected_radius = 0.001f;
-
- BKE_brush_unprojected_radius_set(scene, brush, unprojected_radius);
- }
-
- WM_main_add_notifier(NC_BRUSH | NA_EDITED, brush);
- }
-
- return OPERATOR_FINISHED;
+ Scene *scene = CTX_data_scene(C);
+ Paint *paint = BKE_paint_get_active_from_context(C);
+ Brush *brush = BKE_paint_brush(paint);
+ // Object *ob = CTX_data_active_object(C);
+ float scalar = RNA_float_get(op->ptr, "scalar");
+
+ if (brush) {
+ // pixel radius
+ {
+ const int old_size = BKE_brush_size_get(scene, brush);
+ int size = (int)(scalar * old_size);
+
+ if (abs(old_size - size) < U.pixelsize) {
+ if (scalar > 1) {
+ size += U.pixelsize;
+ }
+ else if (scalar < 1) {
+ size -= U.pixelsize;
+ }
+ }
+
+ BKE_brush_size_set(scene, brush, size);
+ }
+
+ // unprojected radius
+ {
+ float unprojected_radius = scalar * BKE_brush_unprojected_radius_get(scene, brush);
+
+ if (unprojected_radius < 0.001f) // XXX magic number
+ unprojected_radius = 0.001f;
+
+ BKE_brush_unprojected_radius_set(scene, brush, unprojected_radius);
+ }
+
+ WM_main_add_notifier(NC_BRUSH | NA_EDITED, brush);
+ }
+
+ return OPERATOR_FINISHED;
}
static void BRUSH_OT_scale_size(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Scale Sculpt/Paint Brush Size";
- ot->description = "Change brush size by a scalar";
- ot->idname = "BRUSH_OT_scale_size";
+ /* identifiers */
+ ot->name = "Scale Sculpt/Paint Brush Size";
+ ot->description = "Change brush size by a scalar";
+ ot->idname = "BRUSH_OT_scale_size";
- /* api callbacks */
- ot->exec = brush_scale_size_exec;
+ /* api callbacks */
+ ot->exec = brush_scale_size_exec;
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- RNA_def_float(ot->srna, "scalar", 1, 0, 2, "Scalar", "Factor to scale brush size by", 0, 2);
+ RNA_def_float(ot->srna, "scalar", 1, 0, 2, "Scalar", "Factor to scale brush size by", 0, 2);
}
/* Palette operators */
static int palette_new_exec(bContext *C, wmOperator *UNUSED(op))
{
- Paint *paint = BKE_paint_get_active_from_context(C);
- Main *bmain = CTX_data_main(C);
- Palette *palette;
+ Paint *paint = BKE_paint_get_active_from_context(C);
+ Main *bmain = CTX_data_main(C);
+ Palette *palette;
- palette = BKE_palette_add(bmain, "Palette");
+ palette = BKE_palette_add(bmain, "Palette");
- BKE_paint_palette_set(paint, palette);
+ BKE_paint_palette_set(paint, palette);
- return OPERATOR_FINISHED;
+ return OPERATOR_FINISHED;
}
static void PALETTE_OT_new(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Add New Palette";
- ot->description = "Add new palette";
- ot->idname = "PALETTE_OT_new";
+ /* identifiers */
+ ot->name = "Add New Palette";
+ ot->description = "Add new palette";
+ ot->idname = "PALETTE_OT_new";
- /* api callbacks */
- ot->exec = palette_new_exec;
+ /* api callbacks */
+ ot->exec = palette_new_exec;
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
static bool palette_poll(bContext *C)
{
- Paint *paint = BKE_paint_get_active_from_context(C);
+ Paint *paint = BKE_paint_get_active_from_context(C);
- if (paint && paint->palette != NULL)
- return true;
+ if (paint && paint->palette != NULL)
+ return true;
- return false;
+ return false;
}
static int palette_color_add_exec(bContext *C, wmOperator *UNUSED(op))
{
- Scene *scene = CTX_data_scene(C);
- Paint *paint = BKE_paint_get_active_from_context(C);
- Brush *brush = paint->brush;
- ePaintMode mode = BKE_paintmode_get_active_from_context(C);
- Palette *palette = paint->palette;
- PaletteColor *color;
-
- color = BKE_palette_color_add(palette);
- palette->active_color = BLI_listbase_count(&palette->colors) - 1;
-
- if (ELEM(mode, PAINT_MODE_TEXTURE_3D, PAINT_MODE_TEXTURE_2D, PAINT_MODE_VERTEX)) {
- copy_v3_v3(color->rgb, BKE_brush_color_get(scene, brush));
- color->value = 0.0;
- }
- else if (mode == PAINT_MODE_WEIGHT) {
- zero_v3(color->rgb);
- color->value = brush->weight;
- }
-
- return OPERATOR_FINISHED;
+ Scene *scene = CTX_data_scene(C);
+ Paint *paint = BKE_paint_get_active_from_context(C);
+ Brush *brush = paint->brush;
+ ePaintMode mode = BKE_paintmode_get_active_from_context(C);
+ Palette *palette = paint->palette;
+ PaletteColor *color;
+
+ color = BKE_palette_color_add(palette);
+ palette->active_color = BLI_listbase_count(&palette->colors) - 1;
+
+ if (ELEM(mode, PAINT_MODE_TEXTURE_3D, PAINT_MODE_TEXTURE_2D, PAINT_MODE_VERTEX)) {
+ copy_v3_v3(color->rgb, BKE_brush_color_get(scene, brush));
+ color->value = 0.0;
+ }
+ else if (mode == PAINT_MODE_WEIGHT) {
+ zero_v3(color->rgb);
+ color->value = brush->weight;
+ }
+
+ return OPERATOR_FINISHED;
}
static void PALETTE_OT_color_add(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "New Palette Color";
- ot->description = "Add new color to active palette";
- ot->idname = "PALETTE_OT_color_add";
-
- /* api callbacks */
- ot->exec = palette_color_add_exec;
- ot->poll = palette_poll;
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* identifiers */
+ ot->name = "New Palette Color";
+ ot->description = "Add new color to active palette";
+ ot->idname = "PALETTE_OT_color_add";
+
+ /* api callbacks */
+ ot->exec = palette_color_add_exec;
+ ot->poll = palette_poll;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
static int palette_color_delete_exec(bContext *C, wmOperator *UNUSED(op))
{
- Paint *paint = BKE_paint_get_active_from_context(C);
- Palette *palette = paint->palette;
- PaletteColor *color = BLI_findlink(&palette->colors, palette->active_color);
+ Paint *paint = BKE_paint_get_active_from_context(C);
+ Palette *palette = paint->palette;
+ PaletteColor *color = BLI_findlink(&palette->colors, palette->active_color);
- if (color) {
- BKE_palette_color_remove(palette, color);
- }
+ if (color) {
+ BKE_palette_color_remove(palette, color);
+ }
- return OPERATOR_FINISHED;
+ return OPERATOR_FINISHED;
}
static void PALETTE_OT_color_delete(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Delete Palette Color";
- ot->description = "Remove active color from palette";
- ot->idname = "PALETTE_OT_color_delete";
-
- /* api callbacks */
- ot->exec = palette_color_delete_exec;
- ot->poll = palette_poll;
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* identifiers */
+ ot->name = "Delete Palette Color";
+ ot->description = "Remove active color from palette";
+ ot->idname = "PALETTE_OT_color_delete";
+
+ /* api callbacks */
+ ot->exec = palette_color_delete_exec;
+ ot->poll = palette_poll;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
static int brush_reset_exec(bContext *C, wmOperator *UNUSED(op))
{
- Paint *paint = BKE_paint_get_active_from_context(C);
- Brush *brush = BKE_paint_brush(paint);
- Object *ob = CTX_data_active_object(C);
-
- if (!ob || !brush) return OPERATOR_CANCELLED;
-
- /* TODO: other modes */
- if (ob->mode & OB_MODE_SCULPT) {
- BKE_brush_sculpt_reset(brush);
- }
- else {
- return OPERATOR_CANCELLED;
- }
- WM_event_add_notifier(C, NC_BRUSH | NA_EDITED, brush);
-
- return OPERATOR_FINISHED;
+ Paint *paint = BKE_paint_get_active_from_context(C);
+ Brush *brush = BKE_paint_brush(paint);
+ Object *ob = CTX_data_active_object(C);
+
+ if (!ob || !brush)
+ return OPERATOR_CANCELLED;
+
+ /* TODO: other modes */
+ if (ob->mode & OB_MODE_SCULPT) {
+ BKE_brush_sculpt_reset(brush);
+ }
+ else {
+ return OPERATOR_CANCELLED;
+ }
+ WM_event_add_notifier(C, NC_BRUSH | NA_EDITED, brush);
+
+ return OPERATOR_FINISHED;
}
static void BRUSH_OT_reset(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Reset Brush";
- ot->description = "Return brush to defaults based on current tool";
- ot->idname = "BRUSH_OT_reset";
+ /* identifiers */
+ ot->name = "Reset Brush";
+ ot->description = "Return brush to defaults based on current tool";
+ ot->idname = "BRUSH_OT_reset";
- /* api callbacks */
- ot->exec = brush_reset_exec;
+ /* api callbacks */
+ ot->exec = brush_reset_exec;
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
static int brush_tool(const Brush *brush, size_t tool_offset)
{
- return *(((char *)brush) + tool_offset);
+ return *(((char *)brush) + tool_offset);
}
static void brush_tool_set(const Brush *brush, size_t tool_offset, int tool)
{
- *(((char *)brush) + tool_offset) = tool;
+ *(((char *)brush) + tool_offset) = tool;
}
static Brush *brush_tool_cycle(Main *bmain, Paint *paint, Brush *brush_orig, const int tool)
{
- Brush *brush, *first_brush;
-
- if (!brush_orig && !(brush_orig = bmain->brushes.first)) {
- return NULL;
- }
-
- if (brush_tool(brush_orig, paint->runtime.tool_offset) != tool) {
- /* If current brush's tool is different from what we need,
- * start cycling from the beginning of the list.
- * Such logic will activate the same exact brush not relating from
- * which tool user requests other tool.
- */
-
- /* Try to tool-slot first. */
- first_brush = BKE_paint_toolslots_brush_get(paint, tool);
- if (first_brush == NULL) {
- first_brush = bmain->brushes.first;
- }
- }
- else {
- /* If user wants to switch to brush with the same tool as
- * currently active brush do a cycling via all possible
- * brushes with requested tool.
- */
- first_brush = brush_orig->id.next ? brush_orig->id.next : bmain->brushes.first;
- }
-
- /* get the next brush with the active tool */
- brush = first_brush;
- do {
- if ((brush->ob_mode & paint->runtime.ob_mode) &&
- (brush_tool(brush, paint->runtime.tool_offset) == tool))
- {
- return brush;
- }
-
- brush = brush->id.next ? brush->id.next : bmain->brushes.first;
- } while (brush != first_brush);
-
- return NULL;
+ Brush *brush, *first_brush;
+
+ if (!brush_orig && !(brush_orig = bmain->brushes.first)) {
+ return NULL;
+ }
+
+ if (brush_tool(brush_orig, paint->runtime.tool_offset) != tool) {
+ /* If current brush's tool is different from what we need,
+ * start cycling from the beginning of the list.
+ * Such logic will activate the same exact brush not relating from
+ * which tool user requests other tool.
+ */
+
+ /* Try to tool-slot first. */
+ first_brush = BKE_paint_toolslots_brush_get(paint, tool);
+ if (first_brush == NULL) {
+ first_brush = bmain->brushes.first;
+ }
+ }
+ else {
+ /* If user wants to switch to brush with the same tool as
+ * currently active brush do a cycling via all possible
+ * brushes with requested tool.
+ */
+ first_brush = brush_orig->id.next ? brush_orig->id.next : bmain->brushes.first;
+ }
+
+ /* get the next brush with the active tool */
+ brush = first_brush;
+ do {
+ if ((brush->ob_mode & paint->runtime.ob_mode) &&
+ (brush_tool(brush, paint->runtime.tool_offset) == tool)) {
+ return brush;
+ }
+
+ brush = brush->id.next ? brush->id.next : bmain->brushes.first;
+ } while (brush != first_brush);
+
+ return NULL;
}
static Brush *brush_tool_toggle(Main *bmain, Paint *paint, Brush *brush_orig, const int tool)
{
- if (!brush_orig || brush_tool(brush_orig, paint->runtime.tool_offset) != tool) {
- Brush *br;
- /* if the current brush is not using the desired tool, look
- * for one that is */
- br = brush_tool_cycle(bmain, paint, brush_orig, tool);
- /* store the previously-selected brush */
- if (br)
- br->toggle_brush = brush_orig;
-
- return br;
- }
- else if (brush_orig->toggle_brush) {
- /* if current brush is using the desired tool, try to toggle
- * back to the previously selected brush. */
- return brush_orig->toggle_brush;
- }
- else
- return NULL;
+ if (!brush_orig || brush_tool(brush_orig, paint->runtime.tool_offset) != tool) {
+ Brush *br;
+ /* if the current brush is not using the desired tool, look
+ * for one that is */
+ br = brush_tool_cycle(bmain, paint, brush_orig, tool);
+ /* store the previously-selected brush */
+ if (br)
+ br->toggle_brush = brush_orig;
+
+ return br;
+ }
+ else if (brush_orig->toggle_brush) {
+ /* if current brush is using the desired tool, try to toggle
+ * back to the previously selected brush. */
+ return brush_orig->toggle_brush;
+ }
+ else
+ return NULL;
}
-static int brush_generic_tool_set(
- Main *bmain, Paint *paint, const int tool,
- const char *tool_name, const bool create_missing,
- const bool toggle)
+static int brush_generic_tool_set(Main *bmain,
+ Paint *paint,
+ const int tool,
+ const char *tool_name,
+ const bool create_missing,
+ const bool toggle)
{
- Brush *brush, *brush_orig = BKE_paint_brush(paint);
-
- if (toggle) {
- brush = brush_tool_toggle(bmain, paint, brush_orig, tool);
- }
- else {
- brush = brush_tool_cycle(bmain, paint, brush_orig, tool);
- }
-
- if (!brush && brush_tool(brush_orig, paint->runtime.tool_offset) != tool && create_missing) {
- brush = BKE_brush_add(bmain, tool_name, paint->runtime.ob_mode);
- id_us_min(&brush->id); /* fake user only */
- brush_tool_set(brush, paint->runtime.tool_offset, tool);
- brush->toggle_brush = brush_orig;
- }
-
- if (brush) {
- BKE_paint_brush_set(paint, brush);
- BKE_paint_invalidate_overlay_all();
-
- WM_main_add_notifier(NC_BRUSH | NA_EDITED, brush);
- return OPERATOR_FINISHED;
- }
- else {
- return OPERATOR_CANCELLED;
- }
+ Brush *brush, *brush_orig = BKE_paint_brush(paint);
+
+ if (toggle) {
+ brush = brush_tool_toggle(bmain, paint, brush_orig, tool);
+ }
+ else {
+ brush = brush_tool_cycle(bmain, paint, brush_orig, tool);
+ }
+
+ if (!brush && brush_tool(brush_orig, paint->runtime.tool_offset) != tool && create_missing) {
+ brush = BKE_brush_add(bmain, tool_name, paint->runtime.ob_mode);
+ id_us_min(&brush->id); /* fake user only */
+ brush_tool_set(brush, paint->runtime.tool_offset, tool);
+ brush->toggle_brush = brush_orig;
+ }
+
+ if (brush) {
+ BKE_paint_brush_set(paint, brush);
+ BKE_paint_invalidate_overlay_all();
+
+ WM_main_add_notifier(NC_BRUSH | NA_EDITED, brush);
+ return OPERATOR_FINISHED;
+ }
+ else {
+ return OPERATOR_CANCELLED;
+ }
}
static const ePaintMode brush_select_paint_modes[] = {
- PAINT_MODE_SCULPT,
- PAINT_MODE_VERTEX,
- PAINT_MODE_WEIGHT,
- PAINT_MODE_TEXTURE_3D,
- PAINT_MODE_GPENCIL,
+ PAINT_MODE_SCULPT,
+ PAINT_MODE_VERTEX,
+ PAINT_MODE_WEIGHT,
+ PAINT_MODE_TEXTURE_3D,
+ PAINT_MODE_GPENCIL,
};
static int brush_select_exec(bContext *C, wmOperator *op)
{
- Main *bmain = CTX_data_main(C);
- Scene *scene = CTX_data_scene(C);
- const bool create_missing = RNA_boolean_get(op->ptr, "create_missing");
- const bool toggle = RNA_boolean_get(op->ptr, "toggle");
- const char *tool_name = "Brush";
- int tool = 0;
-
- ePaintMode paint_mode = PAINT_MODE_INVALID;
- for (int i = 0; i < ARRAY_SIZE(brush_select_paint_modes); i++) {
- paint_mode = brush_select_paint_modes[i];
- const char *op_prop_id = BKE_paint_get_tool_prop_id_from_paintmode(paint_mode);
- PropertyRNA *prop = RNA_struct_find_property(op->ptr, op_prop_id);
- if (RNA_property_is_set(op->ptr, prop)) {
- tool = RNA_property_enum_get(op->ptr, prop);
- break;
- }
- }
-
- if (paint_mode == PAINT_MODE_INVALID) {
- return OPERATOR_CANCELLED;
- }
-
- Paint *paint = BKE_paint_get_active_from_paintmode(scene, paint_mode);
- const EnumPropertyItem *items = BKE_paint_get_tool_enum_from_paintmode(paint_mode);
- RNA_enum_name_from_value(items, tool, &tool_name);
- return brush_generic_tool_set(
- bmain, paint, tool,
- tool_name, create_missing,
- toggle);
+ Main *bmain = CTX_data_main(C);
+ Scene *scene = CTX_data_scene(C);
+ const bool create_missing = RNA_boolean_get(op->ptr, "create_missing");
+ const bool toggle = RNA_boolean_get(op->ptr, "toggle");
+ const char *tool_name = "Brush";
+ int tool = 0;
+
+ ePaintMode paint_mode = PAINT_MODE_INVALID;
+ for (int i = 0; i < ARRAY_SIZE(brush_select_paint_modes); i++) {
+ paint_mode = brush_select_paint_modes[i];
+ const char *op_prop_id = BKE_paint_get_tool_prop_id_from_paintmode(paint_mode);
+ PropertyRNA *prop = RNA_struct_find_property(op->ptr, op_prop_id);
+ if (RNA_property_is_set(op->ptr, prop)) {
+ tool = RNA_property_enum_get(op->ptr, prop);
+ break;
+ }
+ }
+
+ if (paint_mode == PAINT_MODE_INVALID) {
+ return OPERATOR_CANCELLED;
+ }
+
+ Paint *paint = BKE_paint_get_active_from_paintmode(scene, paint_mode);
+ const EnumPropertyItem *items = BKE_paint_get_tool_enum_from_paintmode(paint_mode);
+ RNA_enum_name_from_value(items, tool, &tool_name);
+ return brush_generic_tool_set(bmain, paint, tool, tool_name, create_missing, toggle);
}
static void PAINT_OT_brush_select(wmOperatorType *ot)
{
- PropertyRNA *prop;
-
- /* identifiers */
- ot->name = "Brush Select";
- ot->description = "Select a paint mode's brush by tool type";
- ot->idname = "PAINT_OT_brush_select";
-
- /* api callbacks */
- ot->exec = brush_select_exec;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* props */
- /* All properties are hidden, so as not to show the redo panel. */
- for (int i = 0; i < ARRAY_SIZE(brush_select_paint_modes); i++) {
- const ePaintMode paint_mode = brush_select_paint_modes[i];
- const char *prop_id = BKE_paint_get_tool_prop_id_from_paintmode(paint_mode);
- prop = RNA_def_enum(ot->srna, prop_id, BKE_paint_get_tool_enum_from_paintmode(paint_mode), 0, prop_id, "");
- RNA_def_property_flag(prop, PROP_HIDDEN);
- }
-
- prop = RNA_def_boolean(ot->srna, "toggle", 0, "Toggle", "Toggle between two brushes rather than cycling");
- RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
- prop = RNA_def_boolean(ot->srna, "create_missing", 0, "Create Missing", "If the requested brush type does not exist, create a new brush");
- RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+ PropertyRNA *prop;
+
+ /* identifiers */
+ ot->name = "Brush Select";
+ ot->description = "Select a paint mode's brush by tool type";
+ ot->idname = "PAINT_OT_brush_select";
+
+ /* api callbacks */
+ ot->exec = brush_select_exec;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* props */
+ /* All properties are hidden, so as not to show the redo panel. */
+ for (int i = 0; i < ARRAY_SIZE(brush_select_paint_modes); i++) {
+ const ePaintMode paint_mode = brush_select_paint_modes[i];
+ const char *prop_id = BKE_paint_get_tool_prop_id_from_paintmode(paint_mode);
+ prop = RNA_def_enum(
+ ot->srna, prop_id, BKE_paint_get_tool_enum_from_paintmode(paint_mode), 0, prop_id, "");
+ RNA_def_property_flag(prop, PROP_HIDDEN);
+ }
+
+ prop = RNA_def_boolean(
+ ot->srna, "toggle", 0, "Toggle", "Toggle between two brushes rather than cycling");
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+ prop = RNA_def_boolean(ot->srna,
+ "create_missing",
+ 0,
+ "Create Missing",
+ "If the requested brush type does not exist, create a new brush");
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
}
static int brush_uv_sculpt_tool_set_exec(bContext *C, wmOperator *op)
{
- Brush *brush;
- Scene *scene = CTX_data_scene(C);
- ToolSettings *ts = scene->toolsettings;
- ts->uv_sculpt_tool = RNA_enum_get(op->ptr, "tool");
- brush = ts->uvsculpt->paint.brush;
- /* To update toolshelf */
- WM_event_add_notifier(C, NC_BRUSH | NA_EDITED, brush);
-
- return OPERATOR_FINISHED;
+ Brush *brush;
+ Scene *scene = CTX_data_scene(C);
+ ToolSettings *ts = scene->toolsettings;
+ ts->uv_sculpt_tool = RNA_enum_get(op->ptr, "tool");
+ brush = ts->uvsculpt->paint.brush;
+ /* To update toolshelf */
+ WM_event_add_notifier(C, NC_BRUSH | NA_EDITED, brush);
+
+ return OPERATOR_FINISHED;
}
static void BRUSH_OT_uv_sculpt_tool_set(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "UV Sculpt Tool Set";
- ot->description = "Set the UV sculpt tool";
- ot->idname = "BRUSH_OT_uv_sculpt_tool_set";
+ /* identifiers */
+ ot->name = "UV Sculpt Tool Set";
+ ot->description = "Set the UV sculpt tool";
+ ot->idname = "BRUSH_OT_uv_sculpt_tool_set";
- /* api callbacks */
- ot->exec = brush_uv_sculpt_tool_set_exec;
- ot->poll = uv_sculpt_poll;
+ /* api callbacks */
+ ot->exec = brush_uv_sculpt_tool_set_exec;
+ ot->poll = uv_sculpt_poll;
- /* flags */
- ot->flag = 0;
+ /* flags */
+ ot->flag = 0;
- /* props */
- ot->prop = RNA_def_enum(ot->srna, "tool", rna_enum_uv_sculpt_tool_items, 0, "Tool", "");
+ /* props */
+ ot->prop = RNA_def_enum(ot->srna, "tool", rna_enum_uv_sculpt_tool_items, 0, "Tool", "");
}
/***** Stencil Control *****/
typedef enum {
- STENCIL_TRANSLATE,
- STENCIL_SCALE,
- STENCIL_ROTATE,
+ STENCIL_TRANSLATE,
+ STENCIL_SCALE,
+ STENCIL_ROTATE,
} StencilControlMode;
typedef enum {
- STENCIL_PRIMARY = 0,
- STENCIL_SECONDARY = 1,
+ STENCIL_PRIMARY = 0,
+ STENCIL_SECONDARY = 1,
} StencilTextureMode;
-
typedef enum {
- STENCIL_CONSTRAINT_X = 1,
- STENCIL_CONSTRAINT_Y = 2,
+ STENCIL_CONSTRAINT_X = 1,
+ STENCIL_CONSTRAINT_Y = 2,
} StencilConstraint;
typedef struct {
- float init_mouse[2];
- float init_spos[2];
- float init_sdim[2];
- float init_rot;
- float init_angle;
- float lenorig;
- float area_size[2];
- StencilControlMode mode;
- StencilConstraint constrain_mode;
- int mask; /* we are twaking mask or colour stencil */
- Brush *br;
- float *dim_target;
- float *rot_target;
- float *pos_target;
- short event_type;
+ float init_mouse[2];
+ float init_spos[2];
+ float init_sdim[2];
+ float init_rot;
+ float init_angle;
+ float lenorig;
+ float area_size[2];
+ StencilControlMode mode;
+ StencilConstraint constrain_mode;
+ int mask; /* we are twaking mask or colour stencil */
+ Brush *br;
+ float *dim_target;
+ float *rot_target;
+ float *pos_target;
+ short event_type;
} StencilControlData;
static void stencil_set_target(StencilControlData *scd)
{
- Brush *br = scd->br;
- float mdiff[2];
- if (scd->mask) {
- copy_v2_v2(scd->init_sdim, br->mask_stencil_dimension);
- copy_v2_v2(scd->init_spos, br->mask_stencil_pos);
- scd->init_rot = br->mask_mtex.rot;
-
- scd->dim_target = br->mask_stencil_dimension;
- scd->rot_target = &br->mask_mtex.rot;
- scd->pos_target = br->mask_stencil_pos;
-
- sub_v2_v2v2(mdiff, scd->init_mouse, br->mask_stencil_pos);
- }
- else {
- copy_v2_v2(scd->init_sdim, br->stencil_dimension);
- copy_v2_v2(scd->init_spos, br->stencil_pos);
- scd->init_rot = br->mtex.rot;
-
- scd->dim_target = br->stencil_dimension;
- scd->rot_target = &br->mtex.rot;
- scd->pos_target = br->stencil_pos;
-
- sub_v2_v2v2(mdiff, scd->init_mouse, br->stencil_pos);
- }
-
- scd->lenorig = len_v2(mdiff);
-
- scd->init_angle = atan2f(mdiff[1], mdiff[0]);
+ Brush *br = scd->br;
+ float mdiff[2];
+ if (scd->mask) {
+ copy_v2_v2(scd->init_sdim, br->mask_stencil_dimension);
+ copy_v2_v2(scd->init_spos, br->mask_stencil_pos);
+ scd->init_rot = br->mask_mtex.rot;
+
+ scd->dim_target = br->mask_stencil_dimension;
+ scd->rot_target = &br->mask_mtex.rot;
+ scd->pos_target = br->mask_stencil_pos;
+
+ sub_v2_v2v2(mdiff, scd->init_mouse, br->mask_stencil_pos);
+ }
+ else {
+ copy_v2_v2(scd->init_sdim, br->stencil_dimension);
+ copy_v2_v2(scd->init_spos, br->stencil_pos);
+ scd->init_rot = br->mtex.rot;
+
+ scd->dim_target = br->stencil_dimension;
+ scd->rot_target = &br->mtex.rot;
+ scd->pos_target = br->stencil_pos;
+
+ sub_v2_v2v2(mdiff, scd->init_mouse, br->stencil_pos);
+ }
+
+ scd->lenorig = len_v2(mdiff);
+
+ scd->init_angle = atan2f(mdiff[1], mdiff[0]);
}
static int stencil_control_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
- Paint *paint = BKE_paint_get_active_from_context(C);
- Brush *br = BKE_paint_brush(paint);
- float mvalf[2] = {event->mval[0], event->mval[1]};
- ARegion *ar = CTX_wm_region(C);
- StencilControlData *scd;
- int mask = RNA_enum_get(op->ptr, "texmode");
-
- if (mask) {
- if (br->mask_mtex.brush_map_mode != MTEX_MAP_MODE_STENCIL)
- return OPERATOR_CANCELLED;
- }
- else {
- if (br->mtex.brush_map_mode != MTEX_MAP_MODE_STENCIL)
- return OPERATOR_CANCELLED;
- }
-
- scd = MEM_mallocN(sizeof(StencilControlData), "stencil_control");
- scd->mask = mask;
- scd->br = br;
-
- copy_v2_v2(scd->init_mouse, mvalf);
-
- stencil_set_target(scd);
-
- scd->mode = RNA_enum_get(op->ptr, "mode");
- scd->event_type = event->type;
- scd->area_size[0] = ar->winx;
- scd->area_size[1] = ar->winy;
-
-
- op->customdata = scd;
- WM_event_add_modal_handler(C, op);
-
- return OPERATOR_RUNNING_MODAL;
+ Paint *paint = BKE_paint_get_active_from_context(C);
+ Brush *br = BKE_paint_brush(paint);
+ float mvalf[2] = {event->mval[0], event->mval[1]};
+ ARegion *ar = CTX_wm_region(C);
+ StencilControlData *scd;
+ int mask = RNA_enum_get(op->ptr, "texmode");
+
+ if (mask) {
+ if (br->mask_mtex.brush_map_mode != MTEX_MAP_MODE_STENCIL)
+ return OPERATOR_CANCELLED;
+ }
+ else {
+ if (br->mtex.brush_map_mode != MTEX_MAP_MODE_STENCIL)
+ return OPERATOR_CANCELLED;
+ }
+
+ scd = MEM_mallocN(sizeof(StencilControlData), "stencil_control");
+ scd->mask = mask;
+ scd->br = br;
+
+ copy_v2_v2(scd->init_mouse, mvalf);
+
+ stencil_set_target(scd);
+
+ scd->mode = RNA_enum_get(op->ptr, "mode");
+ scd->event_type = event->type;
+ scd->area_size[0] = ar->winx;
+ scd->area_size[1] = ar->winy;
+
+ op->customdata = scd;
+ WM_event_add_modal_handler(C, op);
+
+ return OPERATOR_RUNNING_MODAL;
}
static void stencil_restore(StencilControlData *scd)
{
- copy_v2_v2(scd->dim_target, scd->init_sdim);
- copy_v2_v2(scd->pos_target, scd->init_spos);
- *scd->rot_target = scd->init_rot;
+ copy_v2_v2(scd->dim_target, scd->init_sdim);
+ copy_v2_v2(scd->pos_target, scd->init_spos);
+ *scd->rot_target = scd->init_rot;
}
static void stencil_control_cancel(bContext *UNUSED(C), wmOperator *op)
{
- StencilControlData *scd = op->customdata;
+ StencilControlData *scd = op->customdata;
- stencil_restore(scd);
- MEM_freeN(op->customdata);
+ stencil_restore(scd);
+ MEM_freeN(op->customdata);
}
static void stencil_control_calculate(StencilControlData *scd, const int mval[2])
{
#define PIXEL_MARGIN 5
- float mdiff[2];
- float mvalf[2] = {mval[0], mval[1]};
- switch (scd->mode) {
- case STENCIL_TRANSLATE:
- sub_v2_v2v2(mdiff, mvalf, scd->init_mouse);
- add_v2_v2v2(scd->pos_target, scd->init_spos, mdiff);
- CLAMP(scd->pos_target[0],
- -scd->dim_target[0] + PIXEL_MARGIN,
- scd->area_size[0] + scd->dim_target[0] - PIXEL_MARGIN);
-
- CLAMP(scd->pos_target[1],
- -scd->dim_target[1] + PIXEL_MARGIN,
- scd->area_size[1] + scd->dim_target[1] - PIXEL_MARGIN);
-
- break;
- case STENCIL_SCALE:
- {
- float len, factor;
- sub_v2_v2v2(mdiff, mvalf, scd->pos_target);
- len = len_v2(mdiff);
- factor = len / scd->lenorig;
- copy_v2_v2(mdiff, scd->init_sdim);
- if (scd->constrain_mode != STENCIL_CONSTRAINT_Y)
- mdiff[0] = factor * scd->init_sdim[0];
- if (scd->constrain_mode != STENCIL_CONSTRAINT_X)
- mdiff[1] = factor * scd->init_sdim[1];
- CLAMP(mdiff[0], 5.0f, 10000.0f);
- CLAMP(mdiff[1], 5.0f, 10000.0f);
- copy_v2_v2(scd->dim_target, mdiff);
- break;
- }
- case STENCIL_ROTATE:
- {
- float angle;
- sub_v2_v2v2(mdiff, mvalf, scd->pos_target);
- angle = atan2f(mdiff[1], mdiff[0]);
- angle = scd->init_rot + angle - scd->init_angle;
- if (angle < 0.0f)
- angle += (float)(2 * M_PI);
- if (angle > (float)(2 * M_PI))
- angle -= (float)(2 * M_PI);
- *scd->rot_target = angle;
- break;
- }
- }
+ float mdiff[2];
+ float mvalf[2] = {mval[0], mval[1]};
+ switch (scd->mode) {
+ case STENCIL_TRANSLATE:
+ sub_v2_v2v2(mdiff, mvalf, scd->init_mouse);
+ add_v2_v2v2(scd->pos_target, scd->init_spos, mdiff);
+ CLAMP(scd->pos_target[0],
+ -scd->dim_target[0] + PIXEL_MARGIN,
+ scd->area_size[0] + scd->dim_target[0] - PIXEL_MARGIN);
+
+ CLAMP(scd->pos_target[1],
+ -scd->dim_target[1] + PIXEL_MARGIN,
+ scd->area_size[1] + scd->dim_target[1] - PIXEL_MARGIN);
+
+ break;
+ case STENCIL_SCALE: {
+ float len, factor;
+ sub_v2_v2v2(mdiff, mvalf, scd->pos_target);
+ len = len_v2(mdiff);
+ factor = len / scd->lenorig;
+ copy_v2_v2(mdiff, scd->init_sdim);
+ if (scd->constrain_mode != STENCIL_CONSTRAINT_Y)
+ mdiff[0] = factor * scd->init_sdim[0];
+ if (scd->constrain_mode != STENCIL_CONSTRAINT_X)
+ mdiff[1] = factor * scd->init_sdim[1];
+ CLAMP(mdiff[0], 5.0f, 10000.0f);
+ CLAMP(mdiff[1], 5.0f, 10000.0f);
+ copy_v2_v2(scd->dim_target, mdiff);
+ break;
+ }
+ case STENCIL_ROTATE: {
+ float angle;
+ sub_v2_v2v2(mdiff, mvalf, scd->pos_target);
+ angle = atan2f(mdiff[1], mdiff[0]);
+ angle = scd->init_rot + angle - scd->init_angle;
+ if (angle < 0.0f)
+ angle += (float)(2 * M_PI);
+ if (angle > (float)(2 * M_PI))
+ angle -= (float)(2 * M_PI);
+ *scd->rot_target = angle;
+ break;
+ }
+ }
#undef PIXEL_MARGIN
}
static int stencil_control_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
- StencilControlData *scd = op->customdata;
-
- if (event->type == scd->event_type && event->val == KM_RELEASE) {
- MEM_freeN(op->customdata);
- WM_event_add_notifier(C, NC_WINDOW, NULL);
- return OPERATOR_FINISHED;
- }
-
- switch (event->type) {
- case MOUSEMOVE:
- stencil_control_calculate(scd, event->mval);
- break;
- case ESCKEY:
- if (event->val == KM_PRESS) {
- stencil_control_cancel(C, op);
- WM_event_add_notifier(C, NC_WINDOW, NULL);
- return OPERATOR_CANCELLED;
- }
- break;
- case XKEY:
- if (event->val == KM_PRESS) {
-
- if (scd->constrain_mode == STENCIL_CONSTRAINT_X)
- scd->constrain_mode = 0;
- else
- scd->constrain_mode = STENCIL_CONSTRAINT_X;
-
- stencil_control_calculate(scd, event->mval);
- }
- break;
- case YKEY:
- if (event->val == KM_PRESS) {
- if (scd->constrain_mode == STENCIL_CONSTRAINT_Y)
- scd->constrain_mode = 0;
- else
- scd->constrain_mode = STENCIL_CONSTRAINT_Y;
-
- stencil_control_calculate(scd, event->mval);
- }
- break;
- default:
- break;
- }
-
- ED_region_tag_redraw(CTX_wm_region(C));
-
- return OPERATOR_RUNNING_MODAL;
+ StencilControlData *scd = op->customdata;
+
+ if (event->type == scd->event_type && event->val == KM_RELEASE) {
+ MEM_freeN(op->customdata);
+ WM_event_add_notifier(C, NC_WINDOW, NULL);
+ return OPERATOR_FINISHED;
+ }
+
+ switch (event->type) {
+ case MOUSEMOVE:
+ stencil_control_calculate(scd, event->mval);
+ break;
+ case ESCKEY:
+ if (event->val == KM_PRESS) {
+ stencil_control_cancel(C, op);
+ WM_event_add_notifier(C, NC_WINDOW, NULL);
+ return OPERATOR_CANCELLED;
+ }
+ break;
+ case XKEY:
+ if (event->val == KM_PRESS) {
+
+ if (scd->constrain_mode == STENCIL_CONSTRAINT_X)
+ scd->constrain_mode = 0;
+ else
+ scd->constrain_mode = STENCIL_CONSTRAINT_X;
+
+ stencil_control_calculate(scd, event->mval);
+ }
+ break;
+ case YKEY:
+ if (event->val == KM_PRESS) {
+ if (scd->constrain_mode == STENCIL_CONSTRAINT_Y)
+ scd->constrain_mode = 0;
+ else
+ scd->constrain_mode = STENCIL_CONSTRAINT_Y;
+
+ stencil_control_calculate(scd, event->mval);
+ }
+ break;
+ default:
+ break;
+ }
+
+ ED_region_tag_redraw(CTX_wm_region(C));
+
+ return OPERATOR_RUNNING_MODAL;
}
static bool stencil_control_poll(bContext *C)
{
- ePaintMode mode = BKE_paintmode_get_active_from_context(C);
+ ePaintMode mode = BKE_paintmode_get_active_from_context(C);
- Paint *paint;
- Brush *br;
+ Paint *paint;
+ Brush *br;
- if (!paint_supports_texture(mode))
- return false;
+ if (!paint_supports_texture(mode))
+ return false;
- paint = BKE_paint_get_active_from_context(C);
- br = BKE_paint_brush(paint);
- return (br &&
- (br->mtex.brush_map_mode == MTEX_MAP_MODE_STENCIL ||
- br->mask_mtex.brush_map_mode == MTEX_MAP_MODE_STENCIL));
+ paint = BKE_paint_get_active_from_context(C);
+ br = BKE_paint_brush(paint);
+ return (br && (br->mtex.brush_map_mode == MTEX_MAP_MODE_STENCIL ||
+ br->mask_mtex.brush_map_mode == MTEX_MAP_MODE_STENCIL));
}
static void BRUSH_OT_stencil_control(wmOperatorType *ot)
{
- static const EnumPropertyItem stencil_control_items[] = {
- {STENCIL_TRANSLATE, "TRANSLATION", 0, "Translation", ""},
- {STENCIL_SCALE, "SCALE", 0, "Scale", ""},
- {STENCIL_ROTATE, "ROTATION", 0, "Rotation", ""},
- {0, NULL, 0, NULL, NULL},
- };
-
- static const EnumPropertyItem stencil_texture_items[] = {
- {STENCIL_PRIMARY, "PRIMARY", 0, "Primary", ""},
- {STENCIL_SECONDARY, "SECONDARY", 0, "Secondary", ""},
- {0, NULL, 0, NULL, NULL},
- };
- /* identifiers */
- ot->name = "Stencil Brush Control";
- ot->description = "Control the stencil brush";
- ot->idname = "BRUSH_OT_stencil_control";
-
- /* api callbacks */
- ot->invoke = stencil_control_invoke;
- ot->modal = stencil_control_modal;
- ot->cancel = stencil_control_cancel;
- ot->poll = stencil_control_poll;
-
- /* flags */
- ot->flag = 0;
-
- PropertyRNA *prop;
- prop = RNA_def_enum(ot->srna, "mode", stencil_control_items, STENCIL_TRANSLATE, "Tool", "");
- RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
- prop = RNA_def_enum(ot->srna, "texmode", stencil_texture_items, STENCIL_PRIMARY, "Tool", "");
- RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+ static const EnumPropertyItem stencil_control_items[] = {
+ {STENCIL_TRANSLATE, "TRANSLATION", 0, "Translation", ""},
+ {STENCIL_SCALE, "SCALE", 0, "Scale", ""},
+ {STENCIL_ROTATE, "ROTATION", 0, "Rotation", ""},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ static const EnumPropertyItem stencil_texture_items[] = {
+ {STENCIL_PRIMARY, "PRIMARY", 0, "Primary", ""},
+ {STENCIL_SECONDARY, "SECONDARY", 0, "Secondary", ""},
+ {0, NULL, 0, NULL, NULL},
+ };
+ /* identifiers */
+ ot->name = "Stencil Brush Control";
+ ot->description = "Control the stencil brush";
+ ot->idname = "BRUSH_OT_stencil_control";
+
+ /* api callbacks */
+ ot->invoke = stencil_control_invoke;
+ ot->modal = stencil_control_modal;
+ ot->cancel = stencil_control_cancel;
+ ot->poll = stencil_control_poll;
+
+ /* flags */
+ ot->flag = 0;
+
+ PropertyRNA *prop;
+ prop = RNA_def_enum(ot->srna, "mode", stencil_control_items, STENCIL_TRANSLATE, "Tool", "");
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+ prop = RNA_def_enum(ot->srna, "texmode", stencil_texture_items, STENCIL_PRIMARY, "Tool", "");
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
}
-
static int stencil_fit_image_aspect_exec(bContext *C, wmOperator *op)
{
- Paint *paint = BKE_paint_get_active_from_context(C);
- Brush *br = BKE_paint_brush(paint);
- bool use_scale = RNA_boolean_get(op->ptr, "use_scale");
- bool use_repeat = RNA_boolean_get(op->ptr, "use_repeat");
- bool do_mask = RNA_boolean_get(op->ptr, "mask");
- Tex *tex = NULL;
- MTex *mtex = NULL;
- if (br) {
- mtex = do_mask ? &br->mask_mtex : &br->mtex;
- tex = mtex->tex;
- }
-
- if (tex && tex->type == TEX_IMAGE && tex->ima) {
- float aspx, aspy;
- Image *ima = tex->ima;
- float orig_area, stencil_area, factor;
- ED_image_get_uv_aspect(ima, NULL, &aspx, &aspy);
-
- if (use_scale) {
- aspx *= mtex->size[0];
- aspy *= mtex->size[1];
- }
-
- if (use_repeat && tex->extend == TEX_REPEAT) {
- aspx *= tex->xrepeat;
- aspy *= tex->yrepeat;
- }
-
- orig_area = aspx * aspy;
-
- if (do_mask) {
- stencil_area = br->mask_stencil_dimension[0] * br->mask_stencil_dimension[1];
- }
- else {
- stencil_area = br->stencil_dimension[0] * br->stencil_dimension[1];
- }
-
- factor = sqrtf(stencil_area / orig_area);
-
- if (do_mask) {
- br->mask_stencil_dimension[0] = factor * aspx;
- br->mask_stencil_dimension[1] = factor * aspy;
-
- }
- else {
- br->stencil_dimension[0] = factor * aspx;
- br->stencil_dimension[1] = factor * aspy;
- }
- }
-
- WM_event_add_notifier(C, NC_WINDOW, NULL);
-
- return OPERATOR_FINISHED;
+ Paint *paint = BKE_paint_get_active_from_context(C);
+ Brush *br = BKE_paint_brush(paint);
+ bool use_scale = RNA_boolean_get(op->ptr, "use_scale");
+ bool use_repeat = RNA_boolean_get(op->ptr, "use_repeat");
+ bool do_mask = RNA_boolean_get(op->ptr, "mask");
+ Tex *tex = NULL;
+ MTex *mtex = NULL;
+ if (br) {
+ mtex = do_mask ? &br->mask_mtex : &br->mtex;
+ tex = mtex->tex;
+ }
+
+ if (tex && tex->type == TEX_IMAGE && tex->ima) {
+ float aspx, aspy;
+ Image *ima = tex->ima;
+ float orig_area, stencil_area, factor;
+ ED_image_get_uv_aspect(ima, NULL, &aspx, &aspy);
+
+ if (use_scale) {
+ aspx *= mtex->size[0];
+ aspy *= mtex->size[1];
+ }
+
+ if (use_repeat && tex->extend == TEX_REPEAT) {
+ aspx *= tex->xrepeat;
+ aspy *= tex->yrepeat;
+ }
+
+ orig_area = aspx * aspy;
+
+ if (do_mask) {
+ stencil_area = br->mask_stencil_dimension[0] * br->mask_stencil_dimension[1];
+ }
+ else {
+ stencil_area = br->stencil_dimension[0] * br->stencil_dimension[1];
+ }
+
+ factor = sqrtf(stencil_area / orig_area);
+
+ if (do_mask) {
+ br->mask_stencil_dimension[0] = factor * aspx;
+ br->mask_stencil_dimension[1] = factor * aspy;
+ }
+ else {
+ br->stencil_dimension[0] = factor * aspx;
+ br->stencil_dimension[1] = factor * aspy;
+ }
+ }
+
+ WM_event_add_notifier(C, NC_WINDOW, NULL);
+
+ return OPERATOR_FINISHED;
}
-
static void BRUSH_OT_stencil_fit_image_aspect(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Image Aspect";
- ot->description = "When using an image texture, adjust the stencil size to fit the image aspect ratio";
- ot->idname = "BRUSH_OT_stencil_fit_image_aspect";
-
- /* api callbacks */
- ot->exec = stencil_fit_image_aspect_exec;
- ot->poll = stencil_control_poll;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- RNA_def_boolean(ot->srna, "use_repeat", 1, "Use Repeat", "Use repeat mapping values");
- RNA_def_boolean(ot->srna, "use_scale", 1, "Use Scale", "Use texture scale values");
- RNA_def_boolean(ot->srna, "mask", 0, "Modify Mask Stencil", "Modify either the primary or mask stencil");
+ /* identifiers */
+ ot->name = "Image Aspect";
+ ot->description =
+ "When using an image texture, adjust the stencil size to fit the image aspect ratio";
+ ot->idname = "BRUSH_OT_stencil_fit_image_aspect";
+
+ /* api callbacks */
+ ot->exec = stencil_fit_image_aspect_exec;
+ ot->poll = stencil_control_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ RNA_def_boolean(ot->srna, "use_repeat", 1, "Use Repeat", "Use repeat mapping values");
+ RNA_def_boolean(ot->srna, "use_scale", 1, "Use Scale", "Use texture scale values");
+ RNA_def_boolean(
+ ot->srna, "mask", 0, "Modify Mask Stencil", "Modify either the primary or mask stencil");
}
-
static int stencil_reset_transform_exec(bContext *C, wmOperator *op)
{
- Paint *paint = BKE_paint_get_active_from_context(C);
- Brush *br = BKE_paint_brush(paint);
- bool do_mask = RNA_boolean_get(op->ptr, "mask");
+ Paint *paint = BKE_paint_get_active_from_context(C);
+ Brush *br = BKE_paint_brush(paint);
+ bool do_mask = RNA_boolean_get(op->ptr, "mask");
- if (!br)
- return OPERATOR_CANCELLED;
+ if (!br)
+ return OPERATOR_CANCELLED;
- if (do_mask) {
- br->mask_stencil_pos[0] = 256;
- br->mask_stencil_pos[1] = 256;
+ if (do_mask) {
+ br->mask_stencil_pos[0] = 256;
+ br->mask_stencil_pos[1] = 256;
- br->mask_stencil_dimension[0] = 256;
- br->mask_stencil_dimension[1] = 256;
+ br->mask_stencil_dimension[0] = 256;
+ br->mask_stencil_dimension[1] = 256;
- br->mask_mtex.rot = 0;
- }
- else {
- br->stencil_pos[0] = 256;
- br->stencil_pos[1] = 256;
+ br->mask_mtex.rot = 0;
+ }
+ else {
+ br->stencil_pos[0] = 256;
+ br->stencil_pos[1] = 256;
- br->stencil_dimension[0] = 256;
- br->stencil_dimension[1] = 256;
+ br->stencil_dimension[0] = 256;
+ br->stencil_dimension[1] = 256;
- br->mtex.rot = 0;
- }
+ br->mtex.rot = 0;
+ }
- WM_event_add_notifier(C, NC_WINDOW, NULL);
+ WM_event_add_notifier(C, NC_WINDOW, NULL);
- return OPERATOR_FINISHED;
+ return OPERATOR_FINISHED;
}
-
static void BRUSH_OT_stencil_reset_transform(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Reset Transform";
- ot->description = "Reset the stencil transformation to the default";
- ot->idname = "BRUSH_OT_stencil_reset_transform";
+ /* identifiers */
+ ot->name = "Reset Transform";
+ ot->description = "Reset the stencil transformation to the default";
+ ot->idname = "BRUSH_OT_stencil_reset_transform";
- /* api callbacks */
- ot->exec = stencil_reset_transform_exec;
- ot->poll = stencil_control_poll;
+ /* api callbacks */
+ ot->exec = stencil_reset_transform_exec;
+ ot->poll = stencil_control_poll;
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- RNA_def_boolean(ot->srna, "mask", 0, "Modify Mask Stencil", "Modify either the primary or mask stencil");
+ RNA_def_boolean(
+ ot->srna, "mask", 0, "Modify Mask Stencil", "Modify either the primary or mask stencil");
}
-
/**************************** registration **********************************/
void ED_operatormacros_paint(void)
{
- wmOperatorType *ot;
- wmOperatorTypeMacro *otmacro;
-
- ot = WM_operatortype_append_macro(
- "PAINTCURVE_OT_add_point_slide", "Add Curve Point and Slide",
- "Add new curve point and slide it", OPTYPE_UNDO);
- ot->description = "Add new curve point and slide it";
- WM_operatortype_macro_define(ot, "PAINTCURVE_OT_add_point");
- otmacro = WM_operatortype_macro_define(ot, "PAINTCURVE_OT_slide");
- RNA_boolean_set(otmacro->ptr, "align", true);
- RNA_boolean_set(otmacro->ptr, "select", false);
+ wmOperatorType *ot;
+ wmOperatorTypeMacro *otmacro;
+
+ ot = WM_operatortype_append_macro("PAINTCURVE_OT_add_point_slide",
+ "Add Curve Point and Slide",
+ "Add new curve point and slide it",
+ OPTYPE_UNDO);
+ ot->description = "Add new curve point and slide it";
+ WM_operatortype_macro_define(ot, "PAINTCURVE_OT_add_point");
+ otmacro = WM_operatortype_macro_define(ot, "PAINTCURVE_OT_slide");
+ RNA_boolean_set(otmacro->ptr, "align", true);
+ RNA_boolean_set(otmacro->ptr, "select", false);
}
-
void ED_operatortypes_paint(void)
{
- /* palette */
- WM_operatortype_append(PALETTE_OT_new);
- WM_operatortype_append(PALETTE_OT_color_add);
- WM_operatortype_append(PALETTE_OT_color_delete);
-
- /* paint curve */
- WM_operatortype_append(PAINTCURVE_OT_new);
- WM_operatortype_append(PAINTCURVE_OT_add_point);
- WM_operatortype_append(PAINTCURVE_OT_delete_point);
- WM_operatortype_append(PAINTCURVE_OT_select);
- WM_operatortype_append(PAINTCURVE_OT_slide);
- WM_operatortype_append(PAINTCURVE_OT_draw);
- WM_operatortype_append(PAINTCURVE_OT_cursor);
-
- /* brush */
- WM_operatortype_append(BRUSH_OT_add);
- WM_operatortype_append(BRUSH_OT_add_gpencil);
- WM_operatortype_append(BRUSH_OT_scale_size);
- WM_operatortype_append(BRUSH_OT_curve_preset);
- WM_operatortype_append(BRUSH_OT_reset);
- WM_operatortype_append(BRUSH_OT_stencil_control);
- WM_operatortype_append(BRUSH_OT_stencil_fit_image_aspect);
- WM_operatortype_append(BRUSH_OT_stencil_reset_transform);
-
- /* note, particle uses a different system, can be added with existing operators in wm.py */
- WM_operatortype_append(PAINT_OT_brush_select);
- WM_operatortype_append(BRUSH_OT_uv_sculpt_tool_set);
-
- /* image */
- WM_operatortype_append(PAINT_OT_texture_paint_toggle);
- WM_operatortype_append(PAINT_OT_image_paint);
- WM_operatortype_append(PAINT_OT_sample_color);
- WM_operatortype_append(PAINT_OT_grab_clone);
- WM_operatortype_append(PAINT_OT_project_image);
- WM_operatortype_append(PAINT_OT_image_from_view);
- WM_operatortype_append(PAINT_OT_brush_colors_flip);
- WM_operatortype_append(PAINT_OT_add_texture_paint_slot);
- WM_operatortype_append(PAINT_OT_add_simple_uvs);
-
- /* weight */
- WM_operatortype_append(PAINT_OT_weight_paint_toggle);
- WM_operatortype_append(PAINT_OT_weight_paint);
- WM_operatortype_append(PAINT_OT_weight_set);
- WM_operatortype_append(PAINT_OT_weight_from_bones);
- WM_operatortype_append(PAINT_OT_weight_gradient);
- WM_operatortype_append(PAINT_OT_weight_sample);
- WM_operatortype_append(PAINT_OT_weight_sample_group);
-
- /* uv */
- WM_operatortype_append(SCULPT_OT_uv_sculpt_stroke);
-
- /* vertex selection */
- WM_operatortype_append(PAINT_OT_vert_select_all);
- WM_operatortype_append(PAINT_OT_vert_select_ungrouped);
-
- /* vertex */
- WM_operatortype_append(PAINT_OT_vertex_paint_toggle);
- WM_operatortype_append(PAINT_OT_vertex_paint);
- WM_operatortype_append(PAINT_OT_vertex_color_set);
- WM_operatortype_append(PAINT_OT_vertex_color_smooth);
-
- WM_operatortype_append(PAINT_OT_vertex_color_brightness_contrast);
- WM_operatortype_append(PAINT_OT_vertex_color_hsv);
- WM_operatortype_append(PAINT_OT_vertex_color_invert);
- WM_operatortype_append(PAINT_OT_vertex_color_levels);
- WM_operatortype_append(PAINT_OT_vertex_color_from_weight);
-
- /* face-select */
- WM_operatortype_append(PAINT_OT_face_select_linked);
- WM_operatortype_append(PAINT_OT_face_select_linked_pick);
- WM_operatortype_append(PAINT_OT_face_select_all);
- WM_operatortype_append(PAINT_OT_face_select_hide);
- WM_operatortype_append(PAINT_OT_face_select_reveal);
-
- /* partial visibility */
- WM_operatortype_append(PAINT_OT_hide_show);
-
- /* paint masking */
- WM_operatortype_append(PAINT_OT_mask_flood_fill);
- WM_operatortype_append(PAINT_OT_mask_lasso_gesture);
+ /* palette */
+ WM_operatortype_append(PALETTE_OT_new);
+ WM_operatortype_append(PALETTE_OT_color_add);
+ WM_operatortype_append(PALETTE_OT_color_delete);
+
+ /* paint curve */
+ WM_operatortype_append(PAINTCURVE_OT_new);
+ WM_operatortype_append(PAINTCURVE_OT_add_point);
+ WM_operatortype_append(PAINTCURVE_OT_delete_point);
+ WM_operatortype_append(PAINTCURVE_OT_select);
+ WM_operatortype_append(PAINTCURVE_OT_slide);
+ WM_operatortype_append(PAINTCURVE_OT_draw);
+ WM_operatortype_append(PAINTCURVE_OT_cursor);
+
+ /* brush */
+ WM_operatortype_append(BRUSH_OT_add);
+ WM_operatortype_append(BRUSH_OT_add_gpencil);
+ WM_operatortype_append(BRUSH_OT_scale_size);
+ WM_operatortype_append(BRUSH_OT_curve_preset);
+ WM_operatortype_append(BRUSH_OT_reset);
+ WM_operatortype_append(BRUSH_OT_stencil_control);
+ WM_operatortype_append(BRUSH_OT_stencil_fit_image_aspect);
+ WM_operatortype_append(BRUSH_OT_stencil_reset_transform);
+
+ /* note, particle uses a different system, can be added with existing operators in wm.py */
+ WM_operatortype_append(PAINT_OT_brush_select);
+ WM_operatortype_append(BRUSH_OT_uv_sculpt_tool_set);
+
+ /* image */
+ WM_operatortype_append(PAINT_OT_texture_paint_toggle);
+ WM_operatortype_append(PAINT_OT_image_paint);
+ WM_operatortype_append(PAINT_OT_sample_color);
+ WM_operatortype_append(PAINT_OT_grab_clone);
+ WM_operatortype_append(PAINT_OT_project_image);
+ WM_operatortype_append(PAINT_OT_image_from_view);
+ WM_operatortype_append(PAINT_OT_brush_colors_flip);
+ WM_operatortype_append(PAINT_OT_add_texture_paint_slot);
+ WM_operatortype_append(PAINT_OT_add_simple_uvs);
+
+ /* weight */
+ WM_operatortype_append(PAINT_OT_weight_paint_toggle);
+ WM_operatortype_append(PAINT_OT_weight_paint);
+ WM_operatortype_append(PAINT_OT_weight_set);
+ WM_operatortype_append(PAINT_OT_weight_from_bones);
+ WM_operatortype_append(PAINT_OT_weight_gradient);
+ WM_operatortype_append(PAINT_OT_weight_sample);
+ WM_operatortype_append(PAINT_OT_weight_sample_group);
+
+ /* uv */
+ WM_operatortype_append(SCULPT_OT_uv_sculpt_stroke);
+
+ /* vertex selection */
+ WM_operatortype_append(PAINT_OT_vert_select_all);
+ WM_operatortype_append(PAINT_OT_vert_select_ungrouped);
+
+ /* vertex */
+ WM_operatortype_append(PAINT_OT_vertex_paint_toggle);
+ WM_operatortype_append(PAINT_OT_vertex_paint);
+ WM_operatortype_append(PAINT_OT_vertex_color_set);
+ WM_operatortype_append(PAINT_OT_vertex_color_smooth);
+
+ WM_operatortype_append(PAINT_OT_vertex_color_brightness_contrast);
+ WM_operatortype_append(PAINT_OT_vertex_color_hsv);
+ WM_operatortype_append(PAINT_OT_vertex_color_invert);
+ WM_operatortype_append(PAINT_OT_vertex_color_levels);
+ WM_operatortype_append(PAINT_OT_vertex_color_from_weight);
+
+ /* face-select */
+ WM_operatortype_append(PAINT_OT_face_select_linked);
+ WM_operatortype_append(PAINT_OT_face_select_linked_pick);
+ WM_operatortype_append(PAINT_OT_face_select_all);
+ WM_operatortype_append(PAINT_OT_face_select_hide);
+ WM_operatortype_append(PAINT_OT_face_select_reveal);
+
+ /* partial visibility */
+ WM_operatortype_append(PAINT_OT_hide_show);
+
+ /* paint masking */
+ WM_operatortype_append(PAINT_OT_mask_flood_fill);
+ WM_operatortype_append(PAINT_OT_mask_lasso_gesture);
}
void ED_keymap_paint(wmKeyConfig *keyconf)
{
- wmKeyMap *keymap;
+ wmKeyMap *keymap;
- keymap = WM_keymap_ensure(keyconf, "Paint Curve", 0, 0);
- keymap->poll = paint_curve_poll;
+ keymap = WM_keymap_ensure(keyconf, "Paint Curve", 0, 0);
+ keymap->poll = paint_curve_poll;
- /* Sculpt mode */
- keymap = WM_keymap_ensure(keyconf, "Sculpt", 0, 0);
- keymap->poll = sculpt_mode_poll;
+ /* Sculpt mode */
+ keymap = WM_keymap_ensure(keyconf, "Sculpt", 0, 0);
+ keymap->poll = sculpt_mode_poll;
- /* Vertex Paint mode */
- keymap = WM_keymap_ensure(keyconf, "Vertex Paint", 0, 0);
- keymap->poll = vertex_paint_mode_poll;
+ /* Vertex Paint mode */
+ keymap = WM_keymap_ensure(keyconf, "Vertex Paint", 0, 0);
+ keymap->poll = vertex_paint_mode_poll;
- /* Weight Paint mode */
- keymap = WM_keymap_ensure(keyconf, "Weight Paint", 0, 0);
- keymap->poll = weight_paint_mode_poll;
+ /* Weight Paint mode */
+ keymap = WM_keymap_ensure(keyconf, "Weight Paint", 0, 0);
+ keymap->poll = weight_paint_mode_poll;
- /*Weight paint's Vertex Selection Mode */
- keymap = WM_keymap_ensure(keyconf, "Weight Paint Vertex Selection", 0, 0);
- keymap->poll = vert_paint_poll;
+ /*Weight paint's Vertex Selection Mode */
+ keymap = WM_keymap_ensure(keyconf, "Weight Paint Vertex Selection", 0, 0);
+ keymap->poll = vert_paint_poll;
- /* Image/Texture Paint mode */
- keymap = WM_keymap_ensure(keyconf, "Image Paint", 0, 0);
- keymap->poll = image_texture_paint_poll;
+ /* Image/Texture Paint mode */
+ keymap = WM_keymap_ensure(keyconf, "Image Paint", 0, 0);
+ keymap->poll = image_texture_paint_poll;
- /* face-mask mode */
- keymap = WM_keymap_ensure(keyconf, "Face Mask", 0, 0);
- keymap->poll = facemask_paint_poll;
+ /* face-mask mode */
+ keymap = WM_keymap_ensure(keyconf, "Face Mask", 0, 0);
+ keymap->poll = facemask_paint_poll;
- keymap = WM_keymap_ensure(keyconf, "UV Sculpt", 0, 0);
- keymap->poll = uv_sculpt_keymap_poll;
+ keymap = WM_keymap_ensure(keyconf, "UV Sculpt", 0, 0);
+ keymap->poll = uv_sculpt_keymap_poll;
- /* paint stroke */
- keymap = paint_stroke_modal_keymap(keyconf);
- WM_modalkeymap_assign(keymap, "SCULPT_OT_brush_stroke");
+ /* paint stroke */
+ keymap = paint_stroke_modal_keymap(keyconf);
+ WM_modalkeymap_assign(keymap, "SCULPT_OT_brush_stroke");
}
diff --git a/source/blender/editors/sculpt_paint/paint_stroke.c b/source/blender/editors/sculpt_paint/paint_stroke.c
index d66224034eb..4a586f4f7df 100644
--- a/source/blender/editors/sculpt_paint/paint_stroke.c
+++ b/source/blender/editors/sculpt_paint/paint_stroke.c
@@ -21,7 +21,6 @@
* \ingroup edsculpt
*/
-
#include "MEM_guardedalloc.h"
#include "BLI_math.h"
@@ -49,7 +48,6 @@
#include "WM_api.h"
#include "WM_types.h"
-
#include "GPU_immediate.h"
#include "GPU_state.h"
@@ -70,844 +68,847 @@
#endif
typedef struct PaintSample {
- float mouse[2];
- float pressure;
+ float mouse[2];
+ float pressure;
} PaintSample;
typedef struct PaintStroke {
- void *mode_data;
- void *stroke_cursor;
- wmTimer *timer;
- struct RNG *rng;
-
- /* Cached values */
- ViewContext vc;
- Brush *brush;
- UnifiedPaintSettings *ups;
-
- /* used for lines and curves */
- ListBase line;
-
- /* Paint stroke can use up to PAINT_MAX_INPUT_SAMPLES prior inputs
- * to smooth the stroke */
- PaintSample samples[PAINT_MAX_INPUT_SAMPLES];
- int num_samples;
- int cur_sample;
-
- float last_mouse_position[2];
- /* space distance covered so far */
- float stroke_distance;
-
- /* Set whether any stroke step has yet occurred
- * e.g. in sculpt mode, stroke doesn't start until cursor
- * passes over the mesh */
- bool stroke_started;
- /* Set when enough motion was found for rake rotation */
- bool rake_started;
- /* event that started stroke, for modal() return */
- int event_type;
- /* check if stroke variables have been initialized */
- bool stroke_init;
- /* check if various brush mapping variables have been initialized */
- bool brush_init;
- float initial_mouse[2];
- /* cached_pressure stores initial pressure for size pressure influence mainly */
- float cached_size_pressure;
- /* last pressure will store last pressure value for use in interpolation for space strokes */
- float last_pressure;
- int stroke_mode;
-
- float zoom_2d;
- int pen_flip;
-
- /* line constraint */
- bool constrain_line;
- float constrained_pos[2];
-
- StrokeGetLocation get_location;
- StrokeTestStart test_start;
- StrokeUpdateStep update_step;
- StrokeRedraw redraw;
- StrokeDone done;
+ void *mode_data;
+ void *stroke_cursor;
+ wmTimer *timer;
+ struct RNG *rng;
+
+ /* Cached values */
+ ViewContext vc;
+ Brush *brush;
+ UnifiedPaintSettings *ups;
+
+ /* used for lines and curves */
+ ListBase line;
+
+ /* Paint stroke can use up to PAINT_MAX_INPUT_SAMPLES prior inputs
+ * to smooth the stroke */
+ PaintSample samples[PAINT_MAX_INPUT_SAMPLES];
+ int num_samples;
+ int cur_sample;
+
+ float last_mouse_position[2];
+ /* space distance covered so far */
+ float stroke_distance;
+
+ /* Set whether any stroke step has yet occurred
+ * e.g. in sculpt mode, stroke doesn't start until cursor
+ * passes over the mesh */
+ bool stroke_started;
+ /* Set when enough motion was found for rake rotation */
+ bool rake_started;
+ /* event that started stroke, for modal() return */
+ int event_type;
+ /* check if stroke variables have been initialized */
+ bool stroke_init;
+ /* check if various brush mapping variables have been initialized */
+ bool brush_init;
+ float initial_mouse[2];
+ /* cached_pressure stores initial pressure for size pressure influence mainly */
+ float cached_size_pressure;
+ /* last pressure will store last pressure value for use in interpolation for space strokes */
+ float last_pressure;
+ int stroke_mode;
+
+ float zoom_2d;
+ int pen_flip;
+
+ /* line constraint */
+ bool constrain_line;
+ float constrained_pos[2];
+
+ StrokeGetLocation get_location;
+ StrokeTestStart test_start;
+ StrokeUpdateStep update_step;
+ StrokeRedraw redraw;
+ StrokeDone done;
} PaintStroke;
/*** Cursors ***/
static void paint_draw_smooth_cursor(bContext *C, int x, int y, void *customdata)
{
- Paint *paint = BKE_paint_get_active_from_context(C);
- Brush *brush = BKE_paint_brush(paint);
- PaintStroke *stroke = customdata;
+ Paint *paint = BKE_paint_get_active_from_context(C);
+ Brush *brush = BKE_paint_brush(paint);
+ PaintStroke *stroke = customdata;
- if (stroke && brush) {
- GPU_line_smooth(true);
- GPU_blend(true);
+ if (stroke && brush) {
+ GPU_line_smooth(true);
+ GPU_blend(true);
- ARegion *ar = stroke->vc.ar;
+ ARegion *ar = stroke->vc.ar;
- uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
- immUniformColor4ubv(paint->paint_cursor_col);
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immUniformColor4ubv(paint->paint_cursor_col);
- immBegin(GPU_PRIM_LINES, 2);
- immVertex2f(pos, x, y);
- immVertex2f(pos,
- stroke->last_mouse_position[0] + ar->winrct.xmin,
- stroke->last_mouse_position[1] + ar->winrct.ymin);
+ immBegin(GPU_PRIM_LINES, 2);
+ immVertex2f(pos, x, y);
+ immVertex2f(pos,
+ stroke->last_mouse_position[0] + ar->winrct.xmin,
+ stroke->last_mouse_position[1] + ar->winrct.ymin);
- immEnd();
+ immEnd();
- immUnbindProgram();
+ immUnbindProgram();
- GPU_blend(false);
- GPU_line_smooth(false);
- }
+ GPU_blend(false);
+ GPU_line_smooth(false);
+ }
}
static void paint_draw_line_cursor(bContext *C, int x, int y, void *customdata)
{
- Paint *paint = BKE_paint_get_active_from_context(C);
- PaintStroke *stroke = customdata;
+ Paint *paint = BKE_paint_get_active_from_context(C);
+ PaintStroke *stroke = customdata;
- GPU_line_smooth(true);
+ GPU_line_smooth(true);
- uint shdr_pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ uint shdr_pos = GPU_vertformat_attr_add(
+ immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
- float viewport_size[4];
- GPU_viewport_size_get_f(viewport_size);
- immUniform2f("viewport_size", viewport_size[2], viewport_size[3]);
+ float viewport_size[4];
+ GPU_viewport_size_get_f(viewport_size);
+ immUniform2f("viewport_size", viewport_size[2], viewport_size[3]);
- immUniform1i("colors_len", 2); /* "advanced" mode */
- const float alpha = (float)paint->paint_cursor_col[3] / 255.0f;
- immUniformArray4fv("colors", (float *)(float[][4]){{0.0f, 0.0f, 0.0f, alpha}, {1.0f, 1.0f, 1.0f, alpha}}, 2);
- immUniform1f("dash_width", 6.0f);
+ immUniform1i("colors_len", 2); /* "advanced" mode */
+ const float alpha = (float)paint->paint_cursor_col[3] / 255.0f;
+ immUniformArray4fv(
+ "colors", (float *)(float[][4]){{0.0f, 0.0f, 0.0f, alpha}, {1.0f, 1.0f, 1.0f, alpha}}, 2);
+ immUniform1f("dash_width", 6.0f);
- immBegin(GPU_PRIM_LINES, 2);
+ immBegin(GPU_PRIM_LINES, 2);
- ARegion *ar = stroke->vc.ar;
+ ARegion *ar = stroke->vc.ar;
- if (stroke->constrain_line) {
- immVertex2f(shdr_pos,
- stroke->last_mouse_position[0] + ar->winrct.xmin,
- stroke->last_mouse_position[1] + ar->winrct.ymin);
+ if (stroke->constrain_line) {
+ immVertex2f(shdr_pos,
+ stroke->last_mouse_position[0] + ar->winrct.xmin,
+ stroke->last_mouse_position[1] + ar->winrct.ymin);
- immVertex2f(shdr_pos,
- stroke->constrained_pos[0] + ar->winrct.xmin,
- stroke->constrained_pos[1] + ar->winrct.ymin);
- }
- else {
- immVertex2f(shdr_pos,
- stroke->last_mouse_position[0] + ar->winrct.xmin,
- stroke->last_mouse_position[1] + ar->winrct.ymin);
+ immVertex2f(shdr_pos,
+ stroke->constrained_pos[0] + ar->winrct.xmin,
+ stroke->constrained_pos[1] + ar->winrct.ymin);
+ }
+ else {
+ immVertex2f(shdr_pos,
+ stroke->last_mouse_position[0] + ar->winrct.xmin,
+ stroke->last_mouse_position[1] + ar->winrct.ymin);
- immVertex2f(shdr_pos, x, y);
- }
+ immVertex2f(shdr_pos, x, y);
+ }
- immEnd();
+ immEnd();
- immUnbindProgram();
+ immUnbindProgram();
- GPU_line_smooth(false);
+ GPU_line_smooth(false);
}
static bool paint_tool_require_location(Brush *brush, ePaintMode mode)
{
- switch (mode) {
- case PAINT_MODE_SCULPT:
- if (ELEM(brush->sculpt_tool,
- SCULPT_TOOL_GRAB, SCULPT_TOOL_ROTATE,
- SCULPT_TOOL_SNAKE_HOOK, SCULPT_TOOL_THUMB))
- {
- return false;
- }
- else {
- return true;
- }
- default:
- break;
- }
-
- return true;
+ switch (mode) {
+ case PAINT_MODE_SCULPT:
+ if (ELEM(brush->sculpt_tool,
+ SCULPT_TOOL_GRAB,
+ SCULPT_TOOL_ROTATE,
+ SCULPT_TOOL_SNAKE_HOOK,
+ SCULPT_TOOL_THUMB)) {
+ return false;
+ }
+ else {
+ return true;
+ }
+ default:
+ break;
+ }
+
+ return true;
}
/* Initialize the stroke cache variants from operator properties */
-static bool paint_brush_update(
- bContext *C,
- Brush *brush,
- ePaintMode mode,
- struct PaintStroke *stroke,
- const float mouse_init[2],
- float mouse[2], float pressure,
- float r_location[3], bool *r_location_is_set)
+static bool paint_brush_update(bContext *C,
+ Brush *brush,
+ ePaintMode mode,
+ struct PaintStroke *stroke,
+ const float mouse_init[2],
+ float mouse[2],
+ float pressure,
+ float r_location[3],
+ bool *r_location_is_set)
{
- Scene *scene = CTX_data_scene(C);
- UnifiedPaintSettings *ups = stroke->ups;
- bool location_sampled = false;
- bool location_success = false;
- /* Use to perform all operations except applying the stroke,
- * needed for operations that require cursor motion (rake). */
- bool is_dry_run = false;
- bool do_random = false;
- bool do_random_mask = false;
- *r_location_is_set = false;
- /* XXX: Use pressure value from first brush step for brushes which don't
- * support strokes (grab, thumb). They depends on initial state and
- * brush coord/pressure/etc.
- * It's more an events design issue, which doesn't split coordinate/pressure/angle
- * changing events. We should avoid this after events system re-design */
- if (!stroke->brush_init) {
- copy_v2_v2(stroke->initial_mouse, mouse);
- copy_v2_v2(ups->last_rake, mouse);
- copy_v2_v2(ups->tex_mouse, mouse);
- copy_v2_v2(ups->mask_tex_mouse, mouse);
- stroke->cached_size_pressure = pressure;
-
- ups->do_linear_conversion = false;
- ups->colorspace = NULL;
-
- /* check here if color sampling the main brush should do color conversion. This is done here
- * to avoid locking up to get the image buffer during sampling */
- if (brush->mtex.tex && brush->mtex.tex->type == TEX_IMAGE && brush->mtex.tex->ima) {
- ImBuf *tex_ibuf = BKE_image_pool_acquire_ibuf(brush->mtex.tex->ima, &brush->mtex.tex->iuser, NULL);
- if (tex_ibuf && tex_ibuf->rect_float == NULL) {
- ups->do_linear_conversion = true;
- ups->colorspace = tex_ibuf->rect_colorspace;
- }
- BKE_image_pool_release_ibuf(brush->mtex.tex->ima, tex_ibuf, NULL);
- }
-
- stroke->brush_init = true;
- }
-
- if (paint_supports_dynamic_size(brush, mode)) {
- copy_v2_v2(ups->tex_mouse, mouse);
- copy_v2_v2(ups->mask_tex_mouse, mouse);
- stroke->cached_size_pressure = pressure;
- }
-
- /* Truly temporary data that isn't stored in properties */
-
- ups->stroke_active = true;
- ups->size_pressure_value = stroke->cached_size_pressure;
-
- ups->pixel_radius = BKE_brush_size_get(scene, brush);
-
- if (BKE_brush_use_size_pressure(scene, brush) && paint_supports_dynamic_size(brush, mode)) {
- ups->pixel_radius *= stroke->cached_size_pressure;
- }
-
- if (paint_supports_dynamic_tex_coords(brush, mode)) {
-
- if (ELEM(brush->mtex.brush_map_mode,
- MTEX_MAP_MODE_VIEW,
- MTEX_MAP_MODE_AREA,
- MTEX_MAP_MODE_RANDOM))
- {
- do_random = true;
- }
-
- if (brush->mtex.brush_map_mode == MTEX_MAP_MODE_RANDOM)
- BKE_brush_randomize_texture_coords(ups, false);
- else {
- copy_v2_v2(ups->tex_mouse, mouse);
- }
-
- /* take care of mask texture, if any */
- if (brush->mask_mtex.tex) {
-
- if (ELEM(brush->mask_mtex.brush_map_mode,
- MTEX_MAP_MODE_VIEW,
- MTEX_MAP_MODE_AREA,
- MTEX_MAP_MODE_RANDOM))
- {
- do_random_mask = true;
- }
-
- if (brush->mask_mtex.brush_map_mode == MTEX_MAP_MODE_RANDOM)
- BKE_brush_randomize_texture_coords(ups, true);
- else {
- copy_v2_v2(ups->mask_tex_mouse, mouse);
- }
- }
- }
-
-
- if (brush->flag & BRUSH_ANCHORED) {
- bool hit = false;
- float halfway[2];
-
- const float dx = mouse[0] - stroke->initial_mouse[0];
- const float dy = mouse[1] - stroke->initial_mouse[1];
-
- ups->anchored_size = ups->pixel_radius = sqrtf(dx * dx + dy * dy);
-
- ups->brush_rotation = ups->brush_rotation_sec = atan2f(dx, dy) + (float)M_PI;
-
- if (brush->flag & BRUSH_EDGE_TO_EDGE) {
- halfway[0] = dx * 0.5f + stroke->initial_mouse[0];
- halfway[1] = dy * 0.5f + stroke->initial_mouse[1];
-
- if (stroke->get_location) {
- if (stroke->get_location(C, r_location, halfway)) {
- hit = true;
- location_sampled = true;
- location_success = true;
- *r_location_is_set = true;
- }
- else if (!paint_tool_require_location(brush, mode)) {
- hit = true;
- }
- }
- else {
- hit = true;
- }
- }
- if (hit) {
- copy_v2_v2(ups->anchored_initial_mouse, halfway);
- copy_v2_v2(ups->tex_mouse, halfway);
- copy_v2_v2(ups->mask_tex_mouse, halfway);
- copy_v2_v2(mouse, halfway);
- ups->anchored_size /= 2.0f;
- ups->pixel_radius /= 2.0f;
- stroke->stroke_distance = ups->pixel_radius;
- }
- else {
- copy_v2_v2(ups->anchored_initial_mouse, stroke->initial_mouse);
- copy_v2_v2(mouse, stroke->initial_mouse);
- stroke->stroke_distance = ups->pixel_radius;
- }
- ups->pixel_radius /= stroke->zoom_2d;
- ups->draw_anchored = true;
- }
- else {
- /* here we are using the initial mouse coordinate because we do not want the rake
- * result to depend on jittering */
- if (!stroke->brush_init) {
- copy_v2_v2(ups->last_rake, mouse_init);
- }
- /* curve strokes do their own rake calculation */
- else if (!(brush->flag & BRUSH_CURVE)) {
- if (!paint_calculate_rake_rotation(ups, brush, mouse_init)) {
- /* Not enough motion to define an angle. */
- if (!stroke->rake_started) {
- is_dry_run = true;
- }
- }
- else {
- stroke->rake_started = true;
- }
- }
- }
-
- if ((do_random || do_random_mask) && stroke->rng == NULL) {
- /* Lazy initialization. */
- uint rng_seed = (uint)(PIL_check_seconds_timer_i() & UINT_MAX);
- rng_seed ^= (uint)POINTER_AS_INT(brush);
- stroke->rng = BLI_rng_new(rng_seed);
- }
-
- if (do_random) {
- if (brush->mtex.brush_angle_mode & MTEX_ANGLE_RANDOM) {
- ups->brush_rotation += -brush->mtex.random_angle / 2.0f +
- brush->mtex.random_angle * BLI_rng_get_float(stroke->rng);
- }
- }
-
- if (do_random_mask) {
- if (brush->mask_mtex.brush_angle_mode & MTEX_ANGLE_RANDOM) {
- ups->brush_rotation_sec += -brush->mask_mtex.random_angle / 2.0f +
- brush->mask_mtex.random_angle * BLI_rng_get_float(stroke->rng);
- }
- }
-
- if (!location_sampled) {
- if (stroke->get_location) {
- if (stroke->get_location(C, r_location, mouse)) {
- location_success = true;
- *r_location_is_set = true;
- }
- else if (!paint_tool_require_location(brush, mode))
- location_success = true;
- }
- else {
- zero_v3(r_location);
- location_success = true;
- /* don't set 'r_location_is_set', since we don't want to use the value. */
- }
- }
-
- return location_success && (is_dry_run == false);
+ Scene *scene = CTX_data_scene(C);
+ UnifiedPaintSettings *ups = stroke->ups;
+ bool location_sampled = false;
+ bool location_success = false;
+ /* Use to perform all operations except applying the stroke,
+ * needed for operations that require cursor motion (rake). */
+ bool is_dry_run = false;
+ bool do_random = false;
+ bool do_random_mask = false;
+ *r_location_is_set = false;
+ /* XXX: Use pressure value from first brush step for brushes which don't
+ * support strokes (grab, thumb). They depends on initial state and
+ * brush coord/pressure/etc.
+ * It's more an events design issue, which doesn't split coordinate/pressure/angle
+ * changing events. We should avoid this after events system re-design */
+ if (!stroke->brush_init) {
+ copy_v2_v2(stroke->initial_mouse, mouse);
+ copy_v2_v2(ups->last_rake, mouse);
+ copy_v2_v2(ups->tex_mouse, mouse);
+ copy_v2_v2(ups->mask_tex_mouse, mouse);
+ stroke->cached_size_pressure = pressure;
+
+ ups->do_linear_conversion = false;
+ ups->colorspace = NULL;
+
+ /* check here if color sampling the main brush should do color conversion. This is done here
+ * to avoid locking up to get the image buffer during sampling */
+ if (brush->mtex.tex && brush->mtex.tex->type == TEX_IMAGE && brush->mtex.tex->ima) {
+ ImBuf *tex_ibuf = BKE_image_pool_acquire_ibuf(
+ brush->mtex.tex->ima, &brush->mtex.tex->iuser, NULL);
+ if (tex_ibuf && tex_ibuf->rect_float == NULL) {
+ ups->do_linear_conversion = true;
+ ups->colorspace = tex_ibuf->rect_colorspace;
+ }
+ BKE_image_pool_release_ibuf(brush->mtex.tex->ima, tex_ibuf, NULL);
+ }
+
+ stroke->brush_init = true;
+ }
+
+ if (paint_supports_dynamic_size(brush, mode)) {
+ copy_v2_v2(ups->tex_mouse, mouse);
+ copy_v2_v2(ups->mask_tex_mouse, mouse);
+ stroke->cached_size_pressure = pressure;
+ }
+
+ /* Truly temporary data that isn't stored in properties */
+
+ ups->stroke_active = true;
+ ups->size_pressure_value = stroke->cached_size_pressure;
+
+ ups->pixel_radius = BKE_brush_size_get(scene, brush);
+
+ if (BKE_brush_use_size_pressure(scene, brush) && paint_supports_dynamic_size(brush, mode)) {
+ ups->pixel_radius *= stroke->cached_size_pressure;
+ }
+
+ if (paint_supports_dynamic_tex_coords(brush, mode)) {
+
+ if (ELEM(brush->mtex.brush_map_mode,
+ MTEX_MAP_MODE_VIEW,
+ MTEX_MAP_MODE_AREA,
+ MTEX_MAP_MODE_RANDOM)) {
+ do_random = true;
+ }
+
+ if (brush->mtex.brush_map_mode == MTEX_MAP_MODE_RANDOM)
+ BKE_brush_randomize_texture_coords(ups, false);
+ else {
+ copy_v2_v2(ups->tex_mouse, mouse);
+ }
+
+ /* take care of mask texture, if any */
+ if (brush->mask_mtex.tex) {
+
+ if (ELEM(brush->mask_mtex.brush_map_mode,
+ MTEX_MAP_MODE_VIEW,
+ MTEX_MAP_MODE_AREA,
+ MTEX_MAP_MODE_RANDOM)) {
+ do_random_mask = true;
+ }
+
+ if (brush->mask_mtex.brush_map_mode == MTEX_MAP_MODE_RANDOM)
+ BKE_brush_randomize_texture_coords(ups, true);
+ else {
+ copy_v2_v2(ups->mask_tex_mouse, mouse);
+ }
+ }
+ }
+
+ if (brush->flag & BRUSH_ANCHORED) {
+ bool hit = false;
+ float halfway[2];
+
+ const float dx = mouse[0] - stroke->initial_mouse[0];
+ const float dy = mouse[1] - stroke->initial_mouse[1];
+
+ ups->anchored_size = ups->pixel_radius = sqrtf(dx * dx + dy * dy);
+
+ ups->brush_rotation = ups->brush_rotation_sec = atan2f(dx, dy) + (float)M_PI;
+
+ if (brush->flag & BRUSH_EDGE_TO_EDGE) {
+ halfway[0] = dx * 0.5f + stroke->initial_mouse[0];
+ halfway[1] = dy * 0.5f + stroke->initial_mouse[1];
+
+ if (stroke->get_location) {
+ if (stroke->get_location(C, r_location, halfway)) {
+ hit = true;
+ location_sampled = true;
+ location_success = true;
+ *r_location_is_set = true;
+ }
+ else if (!paint_tool_require_location(brush, mode)) {
+ hit = true;
+ }
+ }
+ else {
+ hit = true;
+ }
+ }
+ if (hit) {
+ copy_v2_v2(ups->anchored_initial_mouse, halfway);
+ copy_v2_v2(ups->tex_mouse, halfway);
+ copy_v2_v2(ups->mask_tex_mouse, halfway);
+ copy_v2_v2(mouse, halfway);
+ ups->anchored_size /= 2.0f;
+ ups->pixel_radius /= 2.0f;
+ stroke->stroke_distance = ups->pixel_radius;
+ }
+ else {
+ copy_v2_v2(ups->anchored_initial_mouse, stroke->initial_mouse);
+ copy_v2_v2(mouse, stroke->initial_mouse);
+ stroke->stroke_distance = ups->pixel_radius;
+ }
+ ups->pixel_radius /= stroke->zoom_2d;
+ ups->draw_anchored = true;
+ }
+ else {
+ /* here we are using the initial mouse coordinate because we do not want the rake
+ * result to depend on jittering */
+ if (!stroke->brush_init) {
+ copy_v2_v2(ups->last_rake, mouse_init);
+ }
+ /* curve strokes do their own rake calculation */
+ else if (!(brush->flag & BRUSH_CURVE)) {
+ if (!paint_calculate_rake_rotation(ups, brush, mouse_init)) {
+ /* Not enough motion to define an angle. */
+ if (!stroke->rake_started) {
+ is_dry_run = true;
+ }
+ }
+ else {
+ stroke->rake_started = true;
+ }
+ }
+ }
+
+ if ((do_random || do_random_mask) && stroke->rng == NULL) {
+ /* Lazy initialization. */
+ uint rng_seed = (uint)(PIL_check_seconds_timer_i() & UINT_MAX);
+ rng_seed ^= (uint)POINTER_AS_INT(brush);
+ stroke->rng = BLI_rng_new(rng_seed);
+ }
+
+ if (do_random) {
+ if (brush->mtex.brush_angle_mode & MTEX_ANGLE_RANDOM) {
+ ups->brush_rotation += -brush->mtex.random_angle / 2.0f +
+ brush->mtex.random_angle * BLI_rng_get_float(stroke->rng);
+ }
+ }
+
+ if (do_random_mask) {
+ if (brush->mask_mtex.brush_angle_mode & MTEX_ANGLE_RANDOM) {
+ ups->brush_rotation_sec += -brush->mask_mtex.random_angle / 2.0f +
+ brush->mask_mtex.random_angle * BLI_rng_get_float(stroke->rng);
+ }
+ }
+
+ if (!location_sampled) {
+ if (stroke->get_location) {
+ if (stroke->get_location(C, r_location, mouse)) {
+ location_success = true;
+ *r_location_is_set = true;
+ }
+ else if (!paint_tool_require_location(brush, mode))
+ location_success = true;
+ }
+ else {
+ zero_v3(r_location);
+ location_success = true;
+ /* don't set 'r_location_is_set', since we don't want to use the value. */
+ }
+ }
+
+ return location_success && (is_dry_run == false);
}
static bool paint_stroke_use_jitter(ePaintMode mode, Brush *brush, bool invert)
{
- bool use_jitter = (brush->flag & BRUSH_ABSOLUTE_JITTER) ?
- (brush->jitter_absolute != 0) : (brush->jitter != 0);
-
- /* jitter-ed brush gives weird and unpredictable result for this
- * kinds of stroke, so manually disable jitter usage (sergey) */
- use_jitter &= (brush->flag & (BRUSH_DRAG_DOT | BRUSH_ANCHORED)) == 0;
- use_jitter &= (!ELEM(mode, PAINT_MODE_TEXTURE_2D, PAINT_MODE_TEXTURE_3D) ||
- !(invert && brush->imagepaint_tool == PAINT_TOOL_CLONE));
+ bool use_jitter = (brush->flag & BRUSH_ABSOLUTE_JITTER) ? (brush->jitter_absolute != 0) :
+ (brush->jitter != 0);
+ /* jitter-ed brush gives weird and unpredictable result for this
+ * kinds of stroke, so manually disable jitter usage (sergey) */
+ use_jitter &= (brush->flag & (BRUSH_DRAG_DOT | BRUSH_ANCHORED)) == 0;
+ use_jitter &= (!ELEM(mode, PAINT_MODE_TEXTURE_2D, PAINT_MODE_TEXTURE_3D) ||
+ !(invert && brush->imagepaint_tool == PAINT_TOOL_CLONE));
- return use_jitter;
+ return use_jitter;
}
/* Put the location of the next stroke dot into the stroke RNA and apply it to the mesh */
-static void paint_brush_stroke_add_step(bContext *C, wmOperator *op, const float mouse_in[2], float pressure)
+static void paint_brush_stroke_add_step(bContext *C,
+ wmOperator *op,
+ const float mouse_in[2],
+ float pressure)
{
- Scene *scene = CTX_data_scene(C);
- Paint *paint = BKE_paint_get_active_from_context(C);
- ePaintMode mode = BKE_paintmode_get_active_from_context(C);
- Brush *brush = BKE_paint_brush(paint);
- PaintStroke *stroke = op->customdata;
- UnifiedPaintSettings *ups = stroke->ups;
- float mouse_out[2];
- PointerRNA itemptr;
- float location[3];
+ Scene *scene = CTX_data_scene(C);
+ Paint *paint = BKE_paint_get_active_from_context(C);
+ ePaintMode mode = BKE_paintmode_get_active_from_context(C);
+ Brush *brush = BKE_paint_brush(paint);
+ PaintStroke *stroke = op->customdata;
+ UnifiedPaintSettings *ups = stroke->ups;
+ float mouse_out[2];
+ PointerRNA itemptr;
+ float location[3];
/* the following code is adapted from texture paint. It may not be needed but leaving here
* just in case for reference (code in texpaint removed as part of refactoring).
* It's strange that only texpaint had these guards. */
#if 0
- /* special exception here for too high pressure values on first touch in
- * windows for some tablets, then we just skip first touch .. */
- if (tablet && (pressure >= 0.99f) &&
- ((pop->s.brush->flag & BRUSH_SPACING_PRESSURE) ||
- BKE_brush_use_alpha_pressure(scene, pop->s.brush) ||
- BKE_brush_use_size_pressure(scene, pop->s.brush)))
- {
- return;
- }
-
- /* This can be removed once fixed properly in
- * BKE_brush_painter_paint(
- * BrushPainter *painter, BrushFunc func,
- * float *pos, double time, float pressure, void *user);
- * at zero pressure we should do nothing 1/2^12 is 0.0002
- * which is the sensitivity of the most sensitive pen tablet available */
- if (tablet && (pressure < 0.0002f) &&
- ((pop->s.brush->flag & BRUSH_SPACING_PRESSURE) ||
- BKE_brush_use_alpha_pressure(scene, pop->s.brush) ||
- BKE_brush_use_size_pressure(scene, pop->s.brush)))
- {
- return;
- }
+ /* special exception here for too high pressure values on first touch in
+ * windows for some tablets, then we just skip first touch .. */
+ if (tablet && (pressure >= 0.99f) &&
+ ((pop->s.brush->flag & BRUSH_SPACING_PRESSURE) ||
+ BKE_brush_use_alpha_pressure(scene, pop->s.brush) ||
+ BKE_brush_use_size_pressure(scene, pop->s.brush)))
+ {
+ return;
+ }
+
+ /* This can be removed once fixed properly in
+ * BKE_brush_painter_paint(
+ * BrushPainter *painter, BrushFunc func,
+ * float *pos, double time, float pressure, void *user);
+ * at zero pressure we should do nothing 1/2^12 is 0.0002
+ * which is the sensitivity of the most sensitive pen tablet available */
+ if (tablet && (pressure < 0.0002f) &&
+ ((pop->s.brush->flag & BRUSH_SPACING_PRESSURE) ||
+ BKE_brush_use_alpha_pressure(scene, pop->s.brush) ||
+ BKE_brush_use_size_pressure(scene, pop->s.brush)))
+ {
+ return;
+ }
#endif
- /* copy last position -before- jittering, or space fill code
- * will create too many dabs */
- copy_v2_v2(stroke->last_mouse_position, mouse_in);
- stroke->last_pressure = pressure;
-
- if (paint_stroke_use_jitter(mode, brush, stroke->stroke_mode == BRUSH_STROKE_INVERT)) {
- float delta[2];
- float factor = stroke->zoom_2d;
-
- if (brush->flag & BRUSH_JITTER_PRESSURE)
- factor *= pressure;
-
- BKE_brush_jitter_pos(scene, brush, mouse_in, mouse_out);
-
- /* XXX: meh, this is round about because
- * BKE_brush_jitter_pos isn't written in the best way to
- * be reused here */
- if (factor != 1.0f) {
- sub_v2_v2v2(delta, mouse_out, mouse_in);
- mul_v2_fl(delta, factor);
- add_v2_v2v2(mouse_out, mouse_in, delta);
- }
- }
- else {
- copy_v2_v2(mouse_out, mouse_in);
- }
-
-
- 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) {
- copy_v3_v3(ups->last_location, location);
- }
- if (!ups->last_hit) {
- return;
- }
-
- /* Add to stroke */
- RNA_collection_add(op->ptr, "stroke", &itemptr);
- RNA_float_set(&itemptr, "size", ups->pixel_radius);
- RNA_float_set_array(&itemptr, "location", location);
- RNA_float_set_array(&itemptr, "mouse", mouse_out);
- RNA_boolean_set(&itemptr, "pen_flip", stroke->pen_flip);
- RNA_float_set(&itemptr, "pressure", pressure);
-
- stroke->update_step(C, stroke, &itemptr);
-
- /* don't record this for now, it takes up a lot of memory when doing long
- * strokes with small brush size, and operators have register disabled */
- RNA_collection_clear(op->ptr, "stroke");
+ /* copy last position -before- jittering, or space fill code
+ * will create too many dabs */
+ copy_v2_v2(stroke->last_mouse_position, mouse_in);
+ stroke->last_pressure = pressure;
+
+ if (paint_stroke_use_jitter(mode, brush, stroke->stroke_mode == BRUSH_STROKE_INVERT)) {
+ float delta[2];
+ float factor = stroke->zoom_2d;
+
+ if (brush->flag & BRUSH_JITTER_PRESSURE)
+ factor *= pressure;
+
+ BKE_brush_jitter_pos(scene, brush, mouse_in, mouse_out);
+
+ /* XXX: meh, this is round about because
+ * BKE_brush_jitter_pos isn't written in the best way to
+ * be reused here */
+ if (factor != 1.0f) {
+ sub_v2_v2v2(delta, mouse_out, mouse_in);
+ mul_v2_fl(delta, factor);
+ add_v2_v2v2(mouse_out, mouse_in, delta);
+ }
+ }
+ else {
+ copy_v2_v2(mouse_out, mouse_in);
+ }
+
+ 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) {
+ copy_v3_v3(ups->last_location, location);
+ }
+ if (!ups->last_hit) {
+ return;
+ }
+
+ /* Add to stroke */
+ RNA_collection_add(op->ptr, "stroke", &itemptr);
+ RNA_float_set(&itemptr, "size", ups->pixel_radius);
+ RNA_float_set_array(&itemptr, "location", location);
+ RNA_float_set_array(&itemptr, "mouse", mouse_out);
+ RNA_boolean_set(&itemptr, "pen_flip", stroke->pen_flip);
+ RNA_float_set(&itemptr, "pressure", pressure);
+
+ stroke->update_step(C, stroke, &itemptr);
+
+ /* don't record this for now, it takes up a lot of memory when doing long
+ * strokes with small brush size, and operators have register disabled */
+ RNA_collection_clear(op->ptr, "stroke");
}
/* Returns zero if no sculpt changes should be made, non-zero otherwise */
-static bool paint_smooth_stroke(
- PaintStroke *stroke, const PaintSample *sample, ePaintMode mode,
- float r_mouse[2], float *r_pressure)
+static bool paint_smooth_stroke(PaintStroke *stroke,
+ const PaintSample *sample,
+ ePaintMode mode,
+ float r_mouse[2],
+ float *r_pressure)
{
- if (paint_supports_smooth_stroke(stroke->brush, mode)) {
- float radius = stroke->brush->smooth_stroke_radius * stroke->zoom_2d;
- float u = stroke->brush->smooth_stroke_factor;
-
- /* If the mouse is moving within the radius of the last move,
- * don't update the mouse position. This allows sharp turns. */
- if (len_squared_v2v2(stroke->last_mouse_position, sample->mouse) < SQUARE(radius)) {
- return false;
- }
-
- interp_v2_v2v2(r_mouse, sample->mouse, stroke->last_mouse_position, u);
- *r_pressure = interpf(sample->pressure, stroke->last_pressure, u);
- }
- else {
- r_mouse[0] = sample->mouse[0];
- r_mouse[1] = sample->mouse[1];
- *r_pressure = sample->pressure;
- }
-
- return true;
+ if (paint_supports_smooth_stroke(stroke->brush, mode)) {
+ float radius = stroke->brush->smooth_stroke_radius * stroke->zoom_2d;
+ float u = stroke->brush->smooth_stroke_factor;
+
+ /* If the mouse is moving within the radius of the last move,
+ * don't update the mouse position. This allows sharp turns. */
+ if (len_squared_v2v2(stroke->last_mouse_position, sample->mouse) < SQUARE(radius)) {
+ return false;
+ }
+
+ interp_v2_v2v2(r_mouse, sample->mouse, stroke->last_mouse_position, u);
+ *r_pressure = interpf(sample->pressure, stroke->last_pressure, u);
+ }
+ else {
+ r_mouse[0] = sample->mouse[0];
+ r_mouse[1] = sample->mouse[1];
+ *r_pressure = sample->pressure;
+ }
+
+ return true;
}
-static float paint_space_stroke_spacing(
- const Scene *scene, PaintStroke *stroke, float size_pressure, float spacing_pressure)
+static float paint_space_stroke_spacing(const Scene *scene,
+ PaintStroke *stroke,
+ float size_pressure,
+ float spacing_pressure)
{
- /* 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;
+ /* 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;
- /* apply spacing pressure */
- if (stroke->brush->flag & BRUSH_SPACING_PRESSURE)
- spacing = spacing * (1.5f - spacing_pressure);
+ /* apply spacing pressure */
+ if (stroke->brush->flag & BRUSH_SPACING_PRESSURE)
+ spacing = spacing * (1.5f - spacing_pressure);
- /* 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;
+ /* 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(1.0, size_clamp * spacing / 50.0f);
}
-
-
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;
+ int i;
+ const int n = 100 / spacing;
+ const float h = spacing / 50.0f;
+ const float x0 = x - 1;
- float sum;
+ float sum;
- sum = 0;
- for (i = 0; i < n; i++) {
- float xx;
+ sum = 0;
+ for (i = 0; i < n; i++) {
+ float xx;
- xx = fabsf(x0 + i * h);
+ xx = fabsf(x0 + i * h);
- if (xx < 1.0f)
- sum += BKE_brush_curve_strength(br, xx, 1);
- }
+ if (xx < 1.0f)
+ sum += BKE_brush_curve_strength(br, xx, 1);
+ }
- return sum;
+ return sum;
}
static float paint_stroke_integrate_overlap(Brush *br, float factor)
{
- int i;
- int m;
- float g;
- float max;
-
- float spacing = br->spacing * factor;
-
- if (!(br->flag & BRUSH_SPACE_ATTEN && (br->spacing < 100)))
- return 1.0;
-
- m = 10;
- g = 1.0f / m;
- max = 0;
- for (i = 0; i < m; i++) {
- float overlap = fabs(paint_stroke_overlapped_curve(br, i * g, spacing));
-
- if (overlap > max)
- max = overlap;
- }
-
- if (max == 0.0f)
- return 1.0f;
- else
- return 1.0f / max;
+ int i;
+ int m;
+ float g;
+ float max;
+
+ float spacing = br->spacing * factor;
+
+ if (!(br->flag & BRUSH_SPACE_ATTEN && (br->spacing < 100)))
+ return 1.0;
+
+ m = 10;
+ g = 1.0f / m;
+ max = 0;
+ for (i = 0; i < m; i++) {
+ float overlap = fabs(paint_stroke_overlapped_curve(br, i * g, spacing));
+
+ if (overlap > max)
+ max = overlap;
+ }
+
+ if (max == 0.0f)
+ return 1.0f;
+ else
+ return 1.0f / max;
}
static float paint_space_stroke_spacing_variable(
- const Scene *scene, PaintStroke *stroke, float pressure, float dpressure, float length)
+ const Scene *scene, PaintStroke *stroke, float pressure, float dpressure, float length)
{
- 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 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);
-
- return 0.5f * (last_spacing + new_spacing);
- }
- else {
- /* no size pressure */
- return paint_space_stroke_spacing(scene, stroke, 1.0f, pressure);
- }
+ 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 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);
+
+ return 0.5f * (last_spacing + new_spacing);
+ }
+ else {
+ /* no size pressure */
+ return paint_space_stroke_spacing(scene, stroke, 1.0f, pressure);
+ }
}
/* 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)
+static int paint_space_stroke(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;
+ const Scene *scene = CTX_data_scene(C);
+ PaintStroke *stroke = op->customdata;
+ UnifiedPaintSettings *ups = stroke->ups;
+ int cnt = 0;
- 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 pressure, dpressure;
+ float mouse[2], dmouse[2];
+ float length;
+ float no_pressure_spacing = paint_space_stroke_spacing(scene, stroke, 1.0f, 1.0f);
- sub_v2_v2v2(dmouse, final_mouse, stroke->last_mouse_position);
+ sub_v2_v2v2(dmouse, final_mouse, stroke->last_mouse_position);
- pressure = stroke->last_pressure;
- dpressure = final_pressure - stroke->last_pressure;
+ pressure = stroke->last_pressure;
+ dpressure = final_pressure - stroke->last_pressure;
- length = normalize_v2(dmouse);
+ length = normalize_v2(dmouse);
- while (length > 0.0f) {
- float spacing = paint_space_stroke_spacing_variable(scene, stroke, pressure, dpressure, length);
+ while (length > 0.0f) {
+ float spacing = paint_space_stroke_spacing_variable(
+ scene, stroke, pressure, dpressure, length);
- if (length >= spacing) {
- mouse[0] = stroke->last_mouse_position[0] + dmouse[0] * spacing;
- mouse[1] = stroke->last_mouse_position[1] + dmouse[1] * spacing;
- pressure = stroke->last_pressure + (spacing / length) * dpressure;
+ if (length >= spacing) {
+ mouse[0] = stroke->last_mouse_position[0] + dmouse[0] * spacing;
+ mouse[1] = stroke->last_mouse_position[1] + dmouse[1] * spacing;
+ pressure = stroke->last_pressure + (spacing / length) * dpressure;
- ups->overlap_factor = paint_stroke_integrate_overlap(stroke->brush, spacing / no_pressure_spacing);
+ ups->overlap_factor = paint_stroke_integrate_overlap(stroke->brush,
+ spacing / no_pressure_spacing);
- stroke->stroke_distance += spacing / stroke->zoom_2d;
- paint_brush_stroke_add_step(C, op, mouse, pressure);
+ stroke->stroke_distance += spacing / stroke->zoom_2d;
+ paint_brush_stroke_add_step(C, op, mouse, pressure);
- length -= spacing;
- pressure = stroke->last_pressure;
- dpressure = final_pressure - stroke->last_pressure;
+ length -= spacing;
+ pressure = stroke->last_pressure;
+ dpressure = final_pressure - stroke->last_pressure;
- cnt++;
- }
- else {
- break;
- }
- }
+ cnt++;
+ }
+ else {
+ break;
+ }
+ }
- return cnt;
+ return cnt;
}
/**** Public API ****/
-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)
{
- PaintStroke *stroke = MEM_callocN(sizeof(PaintStroke), "PaintStroke");
- ToolSettings *toolsettings = CTX_data_tool_settings(C);
- UnifiedPaintSettings *ups = &toolsettings->unified_paint_settings;
- Paint *p = BKE_paint_get_active_from_context(C);
- Brush *br = stroke->brush = BKE_paint_brush(p);
- float zoomx, zoomy;
-
- ED_view3d_viewcontext_init(C, &stroke->vc);
-
- stroke->get_location = get_location;
- stroke->test_start = test_start;
- stroke->update_step = update_step;
- stroke->redraw = redraw;
- stroke->done = done;
- stroke->event_type = event_type; /* for modal, return event */
- stroke->ups = ups;
- stroke->stroke_mode = RNA_enum_get(op->ptr, "mode");
-
- get_imapaint_zoom(C, &zoomx, &zoomy);
- stroke->zoom_2d = max_ff(zoomx, zoomy);
-
- if (stroke->stroke_mode == BRUSH_STROKE_INVERT) {
- if (br->flag & (BRUSH_CURVE)) {
- RNA_enum_set(op->ptr, "mode", BRUSH_STROKE_NORMAL);
- }
- }
- /* initialize here */
- ups->overlap_factor = 1.0;
- ups->stroke_active = true;
-
- zero_v3(ups->average_stroke_accum);
- ups->average_stroke_counter = 0;
-
- /* initialize here to avoid initialization conflict with threaded strokes */
- curvemapping_initialize(br->curve);
- if (p->flags & PAINT_USE_CAVITY_MASK)
- curvemapping_initialize(p->cavity_curve);
-
- BKE_paint_set_overlay_override(br->overlay_flags);
-
- return stroke;
+ PaintStroke *stroke = MEM_callocN(sizeof(PaintStroke), "PaintStroke");
+ ToolSettings *toolsettings = CTX_data_tool_settings(C);
+ UnifiedPaintSettings *ups = &toolsettings->unified_paint_settings;
+ Paint *p = BKE_paint_get_active_from_context(C);
+ Brush *br = stroke->brush = BKE_paint_brush(p);
+ float zoomx, zoomy;
+
+ ED_view3d_viewcontext_init(C, &stroke->vc);
+
+ stroke->get_location = get_location;
+ stroke->test_start = test_start;
+ stroke->update_step = update_step;
+ stroke->redraw = redraw;
+ stroke->done = done;
+ stroke->event_type = event_type; /* for modal, return event */
+ stroke->ups = ups;
+ stroke->stroke_mode = RNA_enum_get(op->ptr, "mode");
+
+ get_imapaint_zoom(C, &zoomx, &zoomy);
+ stroke->zoom_2d = max_ff(zoomx, zoomy);
+
+ if (stroke->stroke_mode == BRUSH_STROKE_INVERT) {
+ if (br->flag & (BRUSH_CURVE)) {
+ RNA_enum_set(op->ptr, "mode", BRUSH_STROKE_NORMAL);
+ }
+ }
+ /* initialize here */
+ ups->overlap_factor = 1.0;
+ ups->stroke_active = true;
+
+ zero_v3(ups->average_stroke_accum);
+ ups->average_stroke_counter = 0;
+
+ /* initialize here to avoid initialization conflict with threaded strokes */
+ curvemapping_initialize(br->curve);
+ if (p->flags & PAINT_USE_CAVITY_MASK)
+ curvemapping_initialize(p->cavity_curve);
+
+ BKE_paint_set_overlay_override(br->overlay_flags);
+
+ return stroke;
}
void paint_stroke_data_free(struct wmOperator *op)
{
- BKE_paint_set_overlay_override(0);
- MEM_SAFE_FREE(op->customdata);
+ BKE_paint_set_overlay_override(0);
+ MEM_SAFE_FREE(op->customdata);
}
static void stroke_done(struct bContext *C, struct wmOperator *op)
{
- struct PaintStroke *stroke = op->customdata;
- UnifiedPaintSettings *ups = stroke->ups;
+ struct PaintStroke *stroke = op->customdata;
+ UnifiedPaintSettings *ups = stroke->ups;
- ups->draw_anchored = false;
- ups->stroke_active = false;
+ ups->draw_anchored = false;
+ ups->stroke_active = false;
- /* reset rotation here to avoid doing so in cursor display */
- if (!(stroke->brush->mtex.brush_angle_mode & MTEX_ANGLE_RAKE))
- ups->brush_rotation = 0.0f;
+ /* reset rotation here to avoid doing so in cursor display */
+ if (!(stroke->brush->mtex.brush_angle_mode & MTEX_ANGLE_RAKE))
+ ups->brush_rotation = 0.0f;
- if (!(stroke->brush->mask_mtex.brush_angle_mode & MTEX_ANGLE_RAKE))
- ups->brush_rotation_sec = 0.0f;
+ if (!(stroke->brush->mask_mtex.brush_angle_mode & MTEX_ANGLE_RAKE))
+ ups->brush_rotation_sec = 0.0f;
- if (stroke->stroke_started) {
- if (stroke->redraw)
- stroke->redraw(C, stroke, true);
+ if (stroke->stroke_started) {
+ if (stroke->redraw)
+ stroke->redraw(C, stroke, true);
- if (stroke->done)
- stroke->done(C, stroke);
- }
+ if (stroke->done)
+ stroke->done(C, stroke);
+ }
- if (stroke->timer) {
- WM_event_remove_timer(
- CTX_wm_manager(C),
- CTX_wm_window(C),
- stroke->timer);
- }
+ if (stroke->timer) {
+ WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), stroke->timer);
+ }
- if (stroke->rng) {
- BLI_rng_free(stroke->rng);
- }
+ if (stroke->rng) {
+ BLI_rng_free(stroke->rng);
+ }
- if (stroke->stroke_cursor)
- WM_paint_cursor_end(CTX_wm_manager(C), stroke->stroke_cursor);
+ if (stroke->stroke_cursor)
+ WM_paint_cursor_end(CTX_wm_manager(C), stroke->stroke_cursor);
- BLI_freelistN(&stroke->line);
+ BLI_freelistN(&stroke->line);
- paint_stroke_data_free(op);
+ paint_stroke_data_free(op);
}
/* Returns zero if the stroke dots should not be spaced, non-zero otherwise */
bool paint_space_stroke_enabled(Brush *br, ePaintMode mode)
{
- return (br->flag & BRUSH_SPACE) && paint_supports_dynamic_size(br, mode);
+ return (br->flag & BRUSH_SPACE) && paint_supports_dynamic_size(br, mode);
}
static bool sculpt_is_grab_tool(Brush *br)
{
- return ELEM(
- br->sculpt_tool,
- SCULPT_TOOL_GRAB,
- SCULPT_TOOL_THUMB,
- SCULPT_TOOL_ROTATE,
- SCULPT_TOOL_SNAKE_HOOK);
+ return ELEM(br->sculpt_tool,
+ SCULPT_TOOL_GRAB,
+ SCULPT_TOOL_THUMB,
+ SCULPT_TOOL_ROTATE,
+ SCULPT_TOOL_SNAKE_HOOK);
}
/* return true if the brush size can change during paint (normally used for pressure) */
bool paint_supports_dynamic_size(Brush *br, ePaintMode mode)
{
- if (br->flag & BRUSH_ANCHORED)
- return false;
-
- switch (mode) {
- case PAINT_MODE_SCULPT:
- if (sculpt_is_grab_tool(br))
- return false;
- break;
-
- case PAINT_MODE_TEXTURE_2D: /* fall through */
- case PAINT_MODE_TEXTURE_3D:
- if ((br->imagepaint_tool == PAINT_TOOL_FILL) &&
- (br->flag & BRUSH_USE_GRADIENT))
- {
- return false;
- }
- break;
-
- default:
- break;
- }
- return true;
+ if (br->flag & BRUSH_ANCHORED)
+ return false;
+
+ switch (mode) {
+ case PAINT_MODE_SCULPT:
+ if (sculpt_is_grab_tool(br))
+ return false;
+ break;
+
+ case PAINT_MODE_TEXTURE_2D: /* fall through */
+ case PAINT_MODE_TEXTURE_3D:
+ if ((br->imagepaint_tool == PAINT_TOOL_FILL) && (br->flag & BRUSH_USE_GRADIENT)) {
+ return false;
+ }
+ break;
+
+ default:
+ break;
+ }
+ return true;
}
bool paint_supports_smooth_stroke(Brush *br, ePaintMode mode)
{
- if (!(br->flag & BRUSH_SMOOTH_STROKE) ||
- (br->flag & (BRUSH_ANCHORED | BRUSH_DRAG_DOT | BRUSH_LINE)))
- {
- return false;
- }
-
- switch (mode) {
- case PAINT_MODE_SCULPT:
- if (sculpt_is_grab_tool(br))
- return false;
- break;
- default:
- break;
- }
- return true;
+ if (!(br->flag & BRUSH_SMOOTH_STROKE) ||
+ (br->flag & (BRUSH_ANCHORED | BRUSH_DRAG_DOT | BRUSH_LINE))) {
+ return false;
+ }
+
+ switch (mode) {
+ case PAINT_MODE_SCULPT:
+ if (sculpt_is_grab_tool(br))
+ return false;
+ break;
+ default:
+ break;
+ }
+ return true;
}
bool paint_supports_texture(ePaintMode mode)
{
- /* omit: PAINT_WEIGHT, PAINT_SCULPT_UV, PAINT_INVALID */
- return ELEM(mode, PAINT_MODE_SCULPT, PAINT_MODE_VERTEX, PAINT_MODE_TEXTURE_3D, PAINT_MODE_TEXTURE_2D);
+ /* omit: PAINT_WEIGHT, PAINT_SCULPT_UV, PAINT_INVALID */
+ return ELEM(
+ mode, PAINT_MODE_SCULPT, PAINT_MODE_VERTEX, PAINT_MODE_TEXTURE_3D, PAINT_MODE_TEXTURE_2D);
}
/* return true if the brush size can change during paint (normally used for pressure) */
bool paint_supports_dynamic_tex_coords(Brush *br, ePaintMode mode)
{
- if (br->flag & BRUSH_ANCHORED)
- return false;
-
- switch (mode) {
- case PAINT_MODE_SCULPT:
- if (sculpt_is_grab_tool(br))
- return false;
- break;
- default:
- break;
- }
- return true;
+ if (br->flag & BRUSH_ANCHORED)
+ return false;
+
+ switch (mode) {
+ case PAINT_MODE_SCULPT:
+ if (sculpt_is_grab_tool(br))
+ return false;
+ break;
+ default:
+ break;
+ }
+ return true;
}
#define PAINT_STROKE_MODAL_CANCEL 1
@@ -915,487 +916,486 @@ bool paint_supports_dynamic_tex_coords(Brush *br, ePaintMode mode)
/* called in paint_ops.c, on each regeneration of keymaps */
struct wmKeyMap *paint_stroke_modal_keymap(struct wmKeyConfig *keyconf)
{
- static struct EnumPropertyItem modal_items[] = {
- {PAINT_STROKE_MODAL_CANCEL, "CANCEL", 0,
- "Cancel",
- "Cancel and undo a stroke in progress"},
+ static struct EnumPropertyItem modal_items[] = {
+ {PAINT_STROKE_MODAL_CANCEL, "CANCEL", 0, "Cancel", "Cancel and undo a stroke in progress"},
- { 0 }
- };
+ {0}};
- static const char *name = "Paint Stroke Modal";
+ static const char *name = "Paint Stroke Modal";
- struct wmKeyMap *keymap = WM_modalkeymap_get(keyconf, name);
+ struct wmKeyMap *keymap = WM_modalkeymap_get(keyconf, name);
- /* this function is called for each spacetype, only needs to add map once */
- if (!keymap) {
- keymap = WM_modalkeymap_add(keyconf, name, modal_items);
- }
+ /* this function is called for each spacetype, only needs to add map once */
+ if (!keymap) {
+ keymap = WM_modalkeymap_add(keyconf, name, modal_items);
+ }
- return keymap;
+ return keymap;
}
static void paint_stroke_add_sample(
- const Paint *paint,
- PaintStroke *stroke,
- float x, float y, float pressure)
+ 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);
-
- sample->mouse[0] = x;
- sample->mouse[1] = y;
- sample->pressure = pressure;
-
- stroke->cur_sample++;
- if (stroke->cur_sample >= max_samples)
- stroke->cur_sample = 0;
- if (stroke->num_samples < max_samples)
- stroke->num_samples++;
+ PaintSample *sample = &stroke->samples[stroke->cur_sample];
+ int max_samples = CLAMPIS(paint->num_input_samples, 1, PAINT_MAX_INPUT_SAMPLES);
+
+ sample->mouse[0] = x;
+ sample->mouse[1] = y;
+ sample->pressure = pressure;
+
+ stroke->cur_sample++;
+ if (stroke->cur_sample >= max_samples)
+ stroke->cur_sample = 0;
+ if (stroke->num_samples < max_samples)
+ stroke->num_samples++;
}
-static void paint_stroke_sample_average(
- const PaintStroke *stroke,
- PaintSample *average)
+static void paint_stroke_sample_average(const PaintStroke *stroke, PaintSample *average)
{
- int i;
+ int i;
- memset(average, 0, sizeof(*average));
+ memset(average, 0, sizeof(*average));
- BLI_assert(stroke->num_samples > 0);
+ BLI_assert(stroke->num_samples > 0);
- for (i = 0; i < stroke->num_samples; i++) {
- add_v2_v2(average->mouse, stroke->samples[i].mouse);
- average->pressure += stroke->samples[i].pressure;
- }
+ for (i = 0; i < stroke->num_samples; i++) {
+ add_v2_v2(average->mouse, stroke->samples[i].mouse);
+ average->pressure += stroke->samples[i].pressure;
+ }
- mul_v2_fl(average->mouse, 1.0f / stroke->num_samples);
- average->pressure /= stroke->num_samples;
+ mul_v2_fl(average->mouse, 1.0f / stroke->num_samples);
+ average->pressure /= stroke->num_samples;
- // printf("avg=(%f, %f), num=%d\n", average->mouse[0], average->mouse[1], stroke->num_samples);
+ // printf("avg=(%f, %f), num=%d\n", average->mouse[0], average->mouse[1], stroke->num_samples);
}
/**
* Slightly different version of spacing for line/curve strokes,
* makes sure the dabs stay on the line path.
*/
-static void paint_line_strokes_spacing(
- bContext *C, wmOperator *op, PaintStroke *stroke, float spacing, float *length_residue,
- const float old_pos[2], const float new_pos[2])
+static void paint_line_strokes_spacing(bContext *C,
+ wmOperator *op,
+ PaintStroke *stroke,
+ float spacing,
+ float *length_residue,
+ const float old_pos[2],
+ const float new_pos[2])
{
- UnifiedPaintSettings *ups = stroke->ups;
+ UnifiedPaintSettings *ups = stroke->ups;
- float mouse[2], dmouse[2];
- float length;
+ float mouse[2], dmouse[2];
+ float length;
- sub_v2_v2v2(dmouse, new_pos, old_pos);
- copy_v2_v2(stroke->last_mouse_position, old_pos);
+ sub_v2_v2v2(dmouse, new_pos, old_pos);
+ copy_v2_v2(stroke->last_mouse_position, old_pos);
- length = normalize_v2(dmouse);
+ length = normalize_v2(dmouse);
- BLI_assert(length >= 0.0f);
+ BLI_assert(length >= 0.0f);
- if (length == 0.0f)
- return;
+ if (length == 0.0f)
+ return;
- while (length > 0.0f) {
- float spacing_final = spacing - *length_residue;
- length += *length_residue;
- *length_residue = 0.0;
+ while (length > 0.0f) {
+ float spacing_final = spacing - *length_residue;
+ length += *length_residue;
+ *length_residue = 0.0;
- if (length >= spacing) {
- mouse[0] = stroke->last_mouse_position[0] + dmouse[0] * spacing_final;
- mouse[1] = stroke->last_mouse_position[1] + dmouse[1] * spacing_final;
+ if (length >= spacing) {
+ mouse[0] = stroke->last_mouse_position[0] + dmouse[0] * spacing_final;
+ mouse[1] = stroke->last_mouse_position[1] + dmouse[1] * spacing_final;
- ups->overlap_factor = paint_stroke_integrate_overlap(stroke->brush, 1.0);
+ ups->overlap_factor = paint_stroke_integrate_overlap(stroke->brush, 1.0);
- stroke->stroke_distance += spacing / stroke->zoom_2d;
- paint_brush_stroke_add_step(C, op, mouse, 1.0);
+ stroke->stroke_distance += spacing / stroke->zoom_2d;
+ paint_brush_stroke_add_step(C, op, mouse, 1.0);
- length -= spacing;
- spacing_final = spacing;
- }
- else {
- break;
- }
- }
+ length -= spacing;
+ spacing_final = spacing;
+ }
+ else {
+ break;
+ }
+ }
- *length_residue = length;
+ *length_residue = length;
}
-
static void paint_stroke_line_end(bContext *C, wmOperator *op, PaintStroke *stroke, float mouse[2])
{
- Brush *br = stroke->brush;
- if (stroke->stroke_started && (br->flag & BRUSH_LINE)) {
- stroke->ups->overlap_factor = paint_stroke_integrate_overlap(br, 1.0);
+ Brush *br = stroke->brush;
+ if (stroke->stroke_started && (br->flag & BRUSH_LINE)) {
+ 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);
- }
+ paint_brush_stroke_add_step(C, op, stroke->last_mouse_position, 1.0);
+ paint_space_stroke(C, op, mouse, 1.0);
+ }
}
static bool paint_stroke_curve_end(bContext *C, wmOperator *op, PaintStroke *stroke)
{
- Brush *br = stroke->brush;
+ Brush *br = stroke->brush;
- 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);
- PaintCurve *pc = br->paint_curve;
- PaintCurvePoint *pcp;
- float length_residue = 0.0f;
- int i;
+ 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);
+ PaintCurve *pc = br->paint_curve;
+ PaintCurvePoint *pcp;
+ float length_residue = 0.0f;
+ int i;
- if (!pc)
- return true;
+ if (!pc)
+ return true;
#ifdef DEBUG_TIME
- TIMEIT_START_AVERAGED(whole_stroke);
+ TIMEIT_START_AVERAGED(whole_stroke);
#endif
- pcp = pc->points;
- stroke->ups->overlap_factor = paint_stroke_integrate_overlap(br, 1.0);
-
- for (i = 0; i < pc->tot_points - 1; i++, pcp++) {
- int j;
- float data[(PAINT_CURVE_NUM_SEGMENTS + 1) * 2];
- float tangents[(PAINT_CURVE_NUM_SEGMENTS + 1) * 2];
- PaintCurvePoint *pcp_next = pcp + 1;
- bool do_rake = false;
-
- for (j = 0; j < 2; j++) {
- BKE_curve_forward_diff_bezier(
- pcp->bez.vec[1][j],
- pcp->bez.vec[2][j],
- pcp_next->bez.vec[0][j],
- pcp_next->bez.vec[1][j],
- data + j, PAINT_CURVE_NUM_SEGMENTS, sizeof(float[2]));
- }
-
- if ((br->mtex.brush_angle_mode & MTEX_ANGLE_RAKE) ||
- (br->mask_mtex.brush_angle_mode & MTEX_ANGLE_RAKE))
- {
- do_rake = true;
- for (j = 0; j < 2; j++) {
- BKE_curve_forward_diff_tangent_bezier(
- pcp->bez.vec[1][j],
- pcp->bez.vec[2][j],
- pcp_next->bez.vec[0][j],
- pcp_next->bez.vec[1][j],
- tangents + j, PAINT_CURVE_NUM_SEGMENTS, sizeof(float[2]));
- }
- }
-
- for (j = 0; j < PAINT_CURVE_NUM_SEGMENTS; j++) {
- if (do_rake) {
- float rotation = atan2f(tangents[2 * j], tangents[2 * j + 1]);
- paint_update_brush_rake_rotation(ups, br, rotation);
- }
-
- if (!stroke->stroke_started) {
- stroke->last_pressure = 1.0;
- copy_v2_v2(stroke->last_mouse_position, data + 2 * j);
- stroke->stroke_started = stroke->test_start(C, op, stroke->last_mouse_position);
-
- if (stroke->stroke_started) {
- paint_brush_stroke_add_step(C, op, data + 2 * j, 1.0);
- paint_line_strokes_spacing(
- C, op, stroke, spacing, &length_residue, data + 2 * j, data + 2 * (j + 1));
- }
- }
- else {
- paint_line_strokes_spacing(
- C, op, stroke, spacing, &length_residue, data + 2 * j, data + 2 * (j + 1));
- }
- }
- }
-
- stroke_done(C, op);
+ pcp = pc->points;
+ stroke->ups->overlap_factor = paint_stroke_integrate_overlap(br, 1.0);
+
+ for (i = 0; i < pc->tot_points - 1; i++, pcp++) {
+ int j;
+ float data[(PAINT_CURVE_NUM_SEGMENTS + 1) * 2];
+ float tangents[(PAINT_CURVE_NUM_SEGMENTS + 1) * 2];
+ PaintCurvePoint *pcp_next = pcp + 1;
+ bool do_rake = false;
+
+ for (j = 0; j < 2; j++) {
+ BKE_curve_forward_diff_bezier(pcp->bez.vec[1][j],
+ pcp->bez.vec[2][j],
+ pcp_next->bez.vec[0][j],
+ pcp_next->bez.vec[1][j],
+ data + j,
+ PAINT_CURVE_NUM_SEGMENTS,
+ sizeof(float[2]));
+ }
+
+ if ((br->mtex.brush_angle_mode & MTEX_ANGLE_RAKE) ||
+ (br->mask_mtex.brush_angle_mode & MTEX_ANGLE_RAKE)) {
+ do_rake = true;
+ for (j = 0; j < 2; j++) {
+ BKE_curve_forward_diff_tangent_bezier(pcp->bez.vec[1][j],
+ pcp->bez.vec[2][j],
+ pcp_next->bez.vec[0][j],
+ pcp_next->bez.vec[1][j],
+ tangents + j,
+ PAINT_CURVE_NUM_SEGMENTS,
+ sizeof(float[2]));
+ }
+ }
+
+ for (j = 0; j < PAINT_CURVE_NUM_SEGMENTS; j++) {
+ if (do_rake) {
+ float rotation = atan2f(tangents[2 * j], tangents[2 * j + 1]);
+ paint_update_brush_rake_rotation(ups, br, rotation);
+ }
+
+ if (!stroke->stroke_started) {
+ stroke->last_pressure = 1.0;
+ copy_v2_v2(stroke->last_mouse_position, data + 2 * j);
+ stroke->stroke_started = stroke->test_start(C, op, stroke->last_mouse_position);
+
+ if (stroke->stroke_started) {
+ paint_brush_stroke_add_step(C, op, data + 2 * j, 1.0);
+ paint_line_strokes_spacing(
+ C, op, stroke, spacing, &length_residue, data + 2 * j, data + 2 * (j + 1));
+ }
+ }
+ else {
+ paint_line_strokes_spacing(
+ C, op, stroke, spacing, &length_residue, data + 2 * j, data + 2 * (j + 1));
+ }
+ }
+ }
+
+ stroke_done(C, op);
#ifdef DEBUG_TIME
- TIMEIT_END_AVERAGED(whole_stroke);
+ TIMEIT_END_AVERAGED(whole_stroke);
#endif
- return true;
- }
+ return true;
+ }
- return false;
+ return false;
}
static void paint_stroke_line_constrain(PaintStroke *stroke, float mouse[2])
{
- if (stroke->constrain_line) {
- float line[2];
- float angle, len, res;
-
- sub_v2_v2v2(line, mouse, stroke->last_mouse_position);
- angle = atan2f(line[1], line[0]);
- len = len_v2(line);
-
- /* divide angle by PI/4 */
- angle = 4.0f * angle / (float)M_PI;
-
- /* now take residue */
- res = angle - floorf(angle);
-
- /* residue decides how close we are at a certain angle */
- if (res <= 0.5f) {
- angle = floorf(angle) * (float)M_PI_4;
- }
- else {
- angle = (floorf(angle) + 1.0f) * (float)M_PI_4;
- }
-
- mouse[0] = stroke->constrained_pos[0] = len * cosf(angle) + stroke->last_mouse_position[0];
- mouse[1] = stroke->constrained_pos[1] = len * sinf(angle) + stroke->last_mouse_position[1];
- }
+ if (stroke->constrain_line) {
+ float line[2];
+ float angle, len, res;
+
+ sub_v2_v2v2(line, mouse, stroke->last_mouse_position);
+ angle = atan2f(line[1], line[0]);
+ len = len_v2(line);
+
+ /* divide angle by PI/4 */
+ angle = 4.0f * angle / (float)M_PI;
+
+ /* now take residue */
+ res = angle - floorf(angle);
+
+ /* residue decides how close we are at a certain angle */
+ if (res <= 0.5f) {
+ angle = floorf(angle) * (float)M_PI_4;
+ }
+ else {
+ angle = (floorf(angle) + 1.0f) * (float)M_PI_4;
+ }
+
+ mouse[0] = stroke->constrained_pos[0] = len * cosf(angle) + stroke->last_mouse_position[0];
+ mouse[1] = stroke->constrained_pos[1] = len * sinf(angle) + stroke->last_mouse_position[1];
+ }
}
int paint_stroke_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
- Paint *p = BKE_paint_get_active_from_context(C);
- ePaintMode mode = BKE_paintmode_get_active_from_context(C);
- PaintStroke *stroke = op->customdata;
- Brush *br = stroke->brush;
- PaintSample sample_average;
- float mouse[2];
- bool first_dab = false;
- bool first_modal = false;
- bool redraw = false;
- float pressure;
-
- /* see if tablet affects event. Line, anchored and drag dot strokes do not support pressure */
- pressure = (
- (br->flag & (BRUSH_LINE | BRUSH_ANCHORED | BRUSH_DRAG_DOT)) ?
- 1.0f : WM_event_tablet_data(event, &stroke->pen_flip, NULL));
-
- paint_stroke_add_sample(p, stroke, event->mval[0], event->mval[1], pressure);
- paint_stroke_sample_average(stroke, &sample_average);
+ Paint *p = BKE_paint_get_active_from_context(C);
+ ePaintMode mode = BKE_paintmode_get_active_from_context(C);
+ PaintStroke *stroke = op->customdata;
+ Brush *br = stroke->brush;
+ PaintSample sample_average;
+ float mouse[2];
+ bool first_dab = false;
+ bool first_modal = false;
+ bool redraw = false;
+ float pressure;
+
+ /* see if tablet affects event. Line, anchored and drag dot strokes do not support pressure */
+ pressure = ((br->flag & (BRUSH_LINE | BRUSH_ANCHORED | BRUSH_DRAG_DOT)) ?
+ 1.0f :
+ WM_event_tablet_data(event, &stroke->pen_flip, NULL));
+
+ paint_stroke_add_sample(p, stroke, event->mval[0], event->mval[1], pressure);
+ paint_stroke_sample_average(stroke, &sample_average);
#ifdef WITH_INPUT_NDOF
- /* let NDOF motion pass through to the 3D view so we can paint and rotate simultaneously!
- * this isn't perfect... even when an extra MOUSEMOVE is spoofed, the stroke discards it
- * since the 2D deltas are zero -- code in this file needs to be updated to use the
- * post-NDOF_MOTION MOUSEMOVE */
- if (event->type == NDOF_MOTION)
- return OPERATOR_PASS_THROUGH;
+ /* let NDOF motion pass through to the 3D view so we can paint and rotate simultaneously!
+ * this isn't perfect... even when an extra MOUSEMOVE is spoofed, the stroke discards it
+ * since the 2D deltas are zero -- code in this file needs to be updated to use the
+ * post-NDOF_MOTION MOUSEMOVE */
+ if (event->type == NDOF_MOTION)
+ return OPERATOR_PASS_THROUGH;
#endif
- /* one time initialization */
- if (!stroke->stroke_init) {
- if (paint_stroke_curve_end(C, op, stroke))
- return OPERATOR_FINISHED;
-
- if (paint_supports_smooth_stroke(br, mode))
- stroke->stroke_cursor = WM_paint_cursor_activate(
- CTX_wm_manager(C),
- SPACE_TYPE_ANY, RGN_TYPE_ANY,
- paint_poll, paint_draw_smooth_cursor, stroke);
-
- stroke->stroke_init = true;
- first_modal = true;
- }
-
- /* one time stroke initialization */
- if (!stroke->stroke_started) {
- stroke->last_pressure = sample_average.pressure;
- copy_v2_v2(stroke->last_mouse_position, sample_average.mouse);
- stroke->stroke_started = stroke->test_start(C, op, sample_average.mouse);
- BLI_assert((stroke->stroke_started & ~1) == 0); /* 0/1 */
-
- if (stroke->stroke_started) {
- if (br->flag & BRUSH_AIRBRUSH)
- stroke->timer = WM_event_add_timer(CTX_wm_manager(C), CTX_wm_window(C), TIMER, stroke->brush->rate);
-
- if (br->flag & BRUSH_LINE) {
- stroke->stroke_cursor = WM_paint_cursor_activate(
- CTX_wm_manager(C),
- SPACE_TYPE_ANY, RGN_TYPE_ANY,
- paint_poll, paint_draw_line_cursor, stroke);
- }
-
- first_dab = true;
- }
- }
-
- /* Cancel */
- if (event->type == EVT_MODAL_MAP && event->val == PAINT_STROKE_MODAL_CANCEL) {
- if (op->type->cancel) {
- op->type->cancel(C, op);
- }
- else {
- paint_stroke_cancel(C, op);
- }
- return OPERATOR_CANCELLED;
- }
-
- if (event->type == stroke->event_type && !first_modal) {
- if (event->val == KM_RELEASE) {
- copy_v2_fl2(mouse, event->mval[0], event->mval[1]);
- paint_stroke_line_constrain(stroke, mouse);
- paint_stroke_line_end(C, op, stroke, mouse);
- stroke_done(C, op);
- return OPERATOR_FINISHED;
- }
- }
- else if (ELEM(event->type, RETKEY, SPACEKEY)) {
- paint_stroke_line_end(C, op, stroke, sample_average.mouse);
- stroke_done(C, op);
- return OPERATOR_FINISHED;
- }
- else if (br->flag & BRUSH_LINE) {
- if (event->alt)
- stroke->constrain_line = true;
- else
- stroke->constrain_line = false;
-
- copy_v2_fl2(mouse, event->mval[0], event->mval[1]);
- paint_stroke_line_constrain(stroke, mouse);
-
- if (stroke->stroke_started && (first_modal || (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)))) {
- if ((br->mtex.brush_angle_mode & MTEX_ANGLE_RAKE) || (br->mask_mtex.brush_angle_mode & MTEX_ANGLE_RAKE)) {
- copy_v2_v2(stroke->ups->last_rake, stroke->last_mouse_position);
- }
- paint_calculate_rake_rotation(stroke->ups, br, mouse);
- }
- }
- else if (first_modal ||
- /* regular dabs */
- (!(br->flag & (BRUSH_AIRBRUSH)) && (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE))) ||
- /* airbrush */
- ((br->flag & BRUSH_AIRBRUSH) && event->type == TIMER && event->customdata == stroke->timer))
- {
- 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;
- }
- else {
- float dmouse[2];
- sub_v2_v2v2(dmouse, mouse, stroke->last_mouse_position);
- stroke->stroke_distance += len_v2(dmouse);
- paint_brush_stroke_add_step(C, op, mouse, pressure);
- redraw = true;
- }
- }
- }
- }
-
- /* we want the stroke to have the first daub at the start location
- * instead of waiting till we have moved the space distance */
- if (first_dab &&
- paint_space_stroke_enabled(br, mode) &&
- !(br->flag & BRUSH_SMOOTH_STROKE))
- {
- stroke->ups->overlap_factor = paint_stroke_integrate_overlap(br, 1.0);
- paint_brush_stroke_add_step(C, op, sample_average.mouse, sample_average.pressure);
- redraw = true;
- }
-
- /* do updates for redraw. if event is inbetween mousemove there are more
- * coming, so postpone potentially slow redraw updates until all are done */
- if (event->type != INBETWEEN_MOUSEMOVE) {
- wmWindow *window = CTX_wm_window(C);
- ARegion *ar = CTX_wm_region(C);
-
- /* At the very least, invalidate the cursor */
- if (ar && (p->flags & PAINT_SHOW_BRUSH))
- WM_paint_cursor_tag_redraw(window, ar);
-
- if (redraw && stroke->redraw)
- stroke->redraw(C, stroke, false);
- }
-
- return OPERATOR_RUNNING_MODAL;
+ /* one time initialization */
+ if (!stroke->stroke_init) {
+ if (paint_stroke_curve_end(C, op, stroke))
+ return OPERATOR_FINISHED;
+
+ if (paint_supports_smooth_stroke(br, mode))
+ stroke->stroke_cursor = WM_paint_cursor_activate(CTX_wm_manager(C),
+ SPACE_TYPE_ANY,
+ RGN_TYPE_ANY,
+ paint_poll,
+ paint_draw_smooth_cursor,
+ stroke);
+
+ stroke->stroke_init = true;
+ first_modal = true;
+ }
+
+ /* one time stroke initialization */
+ if (!stroke->stroke_started) {
+ stroke->last_pressure = sample_average.pressure;
+ copy_v2_v2(stroke->last_mouse_position, sample_average.mouse);
+ stroke->stroke_started = stroke->test_start(C, op, sample_average.mouse);
+ BLI_assert((stroke->stroke_started & ~1) == 0); /* 0/1 */
+
+ if (stroke->stroke_started) {
+ if (br->flag & BRUSH_AIRBRUSH)
+ stroke->timer = WM_event_add_timer(
+ CTX_wm_manager(C), CTX_wm_window(C), TIMER, stroke->brush->rate);
+
+ if (br->flag & BRUSH_LINE) {
+ stroke->stroke_cursor = WM_paint_cursor_activate(CTX_wm_manager(C),
+ SPACE_TYPE_ANY,
+ RGN_TYPE_ANY,
+ paint_poll,
+ paint_draw_line_cursor,
+ stroke);
+ }
+
+ first_dab = true;
+ }
+ }
+
+ /* Cancel */
+ if (event->type == EVT_MODAL_MAP && event->val == PAINT_STROKE_MODAL_CANCEL) {
+ if (op->type->cancel) {
+ op->type->cancel(C, op);
+ }
+ else {
+ paint_stroke_cancel(C, op);
+ }
+ return OPERATOR_CANCELLED;
+ }
+
+ if (event->type == stroke->event_type && !first_modal) {
+ if (event->val == KM_RELEASE) {
+ copy_v2_fl2(mouse, event->mval[0], event->mval[1]);
+ paint_stroke_line_constrain(stroke, mouse);
+ paint_stroke_line_end(C, op, stroke, mouse);
+ stroke_done(C, op);
+ return OPERATOR_FINISHED;
+ }
+ }
+ else if (ELEM(event->type, RETKEY, SPACEKEY)) {
+ paint_stroke_line_end(C, op, stroke, sample_average.mouse);
+ stroke_done(C, op);
+ return OPERATOR_FINISHED;
+ }
+ else if (br->flag & BRUSH_LINE) {
+ if (event->alt)
+ stroke->constrain_line = true;
+ else
+ stroke->constrain_line = false;
+
+ copy_v2_fl2(mouse, event->mval[0], event->mval[1]);
+ paint_stroke_line_constrain(stroke, mouse);
+
+ if (stroke->stroke_started &&
+ (first_modal || (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)))) {
+ if ((br->mtex.brush_angle_mode & MTEX_ANGLE_RAKE) ||
+ (br->mask_mtex.brush_angle_mode & MTEX_ANGLE_RAKE)) {
+ copy_v2_v2(stroke->ups->last_rake, stroke->last_mouse_position);
+ }
+ paint_calculate_rake_rotation(stroke->ups, br, mouse);
+ }
+ }
+ else if (first_modal ||
+ /* regular dabs */
+ (!(br->flag & (BRUSH_AIRBRUSH)) &&
+ (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE))) ||
+ /* airbrush */
+ ((br->flag & BRUSH_AIRBRUSH) && event->type == TIMER &&
+ event->customdata == stroke->timer)) {
+ 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;
+ }
+ else {
+ float dmouse[2];
+ sub_v2_v2v2(dmouse, mouse, stroke->last_mouse_position);
+ stroke->stroke_distance += len_v2(dmouse);
+ paint_brush_stroke_add_step(C, op, mouse, pressure);
+ redraw = true;
+ }
+ }
+ }
+ }
+
+ /* we want the stroke to have the first daub at the start location
+ * instead of waiting till we have moved the space distance */
+ if (first_dab && paint_space_stroke_enabled(br, mode) && !(br->flag & BRUSH_SMOOTH_STROKE)) {
+ stroke->ups->overlap_factor = paint_stroke_integrate_overlap(br, 1.0);
+ paint_brush_stroke_add_step(C, op, sample_average.mouse, sample_average.pressure);
+ redraw = true;
+ }
+
+ /* do updates for redraw. if event is inbetween mousemove there are more
+ * coming, so postpone potentially slow redraw updates until all are done */
+ if (event->type != INBETWEEN_MOUSEMOVE) {
+ wmWindow *window = CTX_wm_window(C);
+ ARegion *ar = CTX_wm_region(C);
+
+ /* At the very least, invalidate the cursor */
+ if (ar && (p->flags & PAINT_SHOW_BRUSH))
+ WM_paint_cursor_tag_redraw(window, ar);
+
+ if (redraw && stroke->redraw)
+ stroke->redraw(C, stroke, false);
+ }
+
+ return OPERATOR_RUNNING_MODAL;
}
int paint_stroke_exec(bContext *C, wmOperator *op)
{
- PaintStroke *stroke = op->customdata;
+ PaintStroke *stroke = op->customdata;
- /* only when executed for the first time */
- if (stroke->stroke_started == 0) {
- PropertyRNA *strokeprop;
- PointerRNA firstpoint;
- float mouse[2];
+ /* only when executed for the first time */
+ if (stroke->stroke_started == 0) {
+ PropertyRNA *strokeprop;
+ PointerRNA firstpoint;
+ float mouse[2];
- strokeprop = RNA_struct_find_property(op->ptr, "stroke");
+ strokeprop = RNA_struct_find_property(op->ptr, "stroke");
- if (RNA_property_collection_lookup_int(op->ptr, strokeprop, 0, &firstpoint)) {
- RNA_float_get_array(&firstpoint, "mouse", mouse);
- stroke->stroke_started = stroke->test_start(C, op, mouse);
- }
- }
+ if (RNA_property_collection_lookup_int(op->ptr, strokeprop, 0, &firstpoint)) {
+ RNA_float_get_array(&firstpoint, "mouse", mouse);
+ stroke->stroke_started = stroke->test_start(C, op, mouse);
+ }
+ }
- if (stroke->stroke_started) {
- RNA_BEGIN (op->ptr, itemptr, "stroke")
- {
- stroke->update_step(C, stroke, &itemptr);
- }
- RNA_END;
- }
+ if (stroke->stroke_started) {
+ RNA_BEGIN (op->ptr, itemptr, "stroke") {
+ stroke->update_step(C, stroke, &itemptr);
+ }
+ RNA_END;
+ }
- bool ok = (stroke->stroke_started != 0);
+ bool ok = (stroke->stroke_started != 0);
- stroke_done(C, op);
+ stroke_done(C, op);
- return ok ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
+ return ok ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
}
void paint_stroke_cancel(bContext *C, wmOperator *op)
{
- stroke_done(C, op);
+ stroke_done(C, op);
}
ViewContext *paint_stroke_view_context(PaintStroke *stroke)
{
- return &stroke->vc;
+ return &stroke->vc;
}
void *paint_stroke_mode_data(struct PaintStroke *stroke)
{
- return stroke->mode_data;
+ return stroke->mode_data;
}
bool paint_stroke_flipped(struct PaintStroke *stroke)
{
- return stroke->pen_flip;
+ return stroke->pen_flip;
}
bool paint_stroke_inverted(struct PaintStroke *stroke)
{
- return stroke->stroke_mode == BRUSH_STROKE_INVERT;
+ return stroke->stroke_mode == BRUSH_STROKE_INVERT;
}
float paint_stroke_distance_get(struct PaintStroke *stroke)
{
- return stroke->stroke_distance;
+ return stroke->stroke_distance;
}
void paint_stroke_set_mode_data(PaintStroke *stroke, void *mode_data)
{
- stroke->mode_data = mode_data;
+ stroke->mode_data = mode_data;
}
bool paint_poll(bContext *C)
{
- Paint *p = BKE_paint_get_active_from_context(C);
- Object *ob = CTX_data_active_object(C);
- ScrArea *sa = CTX_wm_area(C);
- ARegion *ar = CTX_wm_region(C);
-
- if (p && ob && BKE_paint_brush(p) &&
- (sa && ELEM(sa->spacetype, SPACE_VIEW3D, SPACE_IMAGE)) &&
- (ar && ar->regiontype == RGN_TYPE_WINDOW))
- {
- /* Check the current tool is a brush. */
- bToolRef *tref = sa->runtime.tool;
- if (tref && tref->runtime && tref->runtime->data_block[0]) {
- return true;
- }
- }
- return false;
+ Paint *p = BKE_paint_get_active_from_context(C);
+ Object *ob = CTX_data_active_object(C);
+ ScrArea *sa = CTX_wm_area(C);
+ ARegion *ar = CTX_wm_region(C);
+
+ if (p && ob && BKE_paint_brush(p) && (sa && ELEM(sa->spacetype, SPACE_VIEW3D, SPACE_IMAGE)) &&
+ (ar && ar->regiontype == RGN_TYPE_WINDOW)) {
+ /* Check the current tool is a brush. */
+ bToolRef *tref = sa->runtime.tool;
+ if (tref && tref->runtime && tref->runtime->data_block[0]) {
+ return true;
+ }
+ }
+ return false;
}
diff --git a/source/blender/editors/sculpt_paint/paint_utils.c b/source/blender/editors/sculpt_paint/paint_utils.c
index 35401c470cc..098e38dbdb5 100644
--- a/source/blender/editors/sculpt_paint/paint_utils.c
+++ b/source/blender/editors/sculpt_paint/paint_utils.c
@@ -80,699 +80,720 @@
/* Convert the object-space axis-aligned bounding box (expressed as
* its minimum and maximum corners) into a screen-space rectangle,
* returns zero if the result is empty */
-bool paint_convert_bb_to_rect(
- rcti *rect,
- const float bb_min[3],
- const float bb_max[3],
- const ARegion *ar,
- RegionView3D *rv3d,
- Object *ob)
+bool paint_convert_bb_to_rect(rcti *rect,
+ const float bb_min[3],
+ const float bb_max[3],
+ const ARegion *ar,
+ RegionView3D *rv3d,
+ Object *ob)
{
- float projection_mat[4][4];
- int i, j, k;
-
- BLI_rcti_init_minmax(rect);
-
- /* return zero if the bounding box has non-positive volume */
- if (bb_min[0] > bb_max[0] || bb_min[1] > bb_max[1] || bb_min[2] > bb_max[2])
- return 0;
-
- ED_view3d_ob_project_mat_get(rv3d, ob, projection_mat);
-
- for (i = 0; i < 2; ++i) {
- for (j = 0; j < 2; ++j) {
- for (k = 0; k < 2; ++k) {
- float vec[3], proj[2];
- int proj_i[2];
- vec[0] = i ? bb_min[0] : bb_max[0];
- vec[1] = j ? bb_min[1] : bb_max[1];
- vec[2] = k ? bb_min[2] : bb_max[2];
- /* convert corner to screen space */
- ED_view3d_project_float_v2_m4(ar, vec, proj, projection_mat);
- /* expand 2D rectangle */
-
- /* we could project directly to int? */
- proj_i[0] = proj[0];
- proj_i[1] = proj[1];
-
- BLI_rcti_do_minmax_v(rect, proj_i);
- }
- }
- }
-
- /* return false if the rectangle has non-positive area */
- return rect->xmin < rect->xmax && rect->ymin < rect->ymax;
+ float projection_mat[4][4];
+ int i, j, k;
+
+ BLI_rcti_init_minmax(rect);
+
+ /* return zero if the bounding box has non-positive volume */
+ if (bb_min[0] > bb_max[0] || bb_min[1] > bb_max[1] || bb_min[2] > bb_max[2])
+ return 0;
+
+ ED_view3d_ob_project_mat_get(rv3d, ob, projection_mat);
+
+ for (i = 0; i < 2; ++i) {
+ for (j = 0; j < 2; ++j) {
+ for (k = 0; k < 2; ++k) {
+ float vec[3], proj[2];
+ int proj_i[2];
+ vec[0] = i ? bb_min[0] : bb_max[0];
+ vec[1] = j ? bb_min[1] : bb_max[1];
+ vec[2] = k ? bb_min[2] : bb_max[2];
+ /* convert corner to screen space */
+ ED_view3d_project_float_v2_m4(ar, vec, proj, projection_mat);
+ /* expand 2D rectangle */
+
+ /* we could project directly to int? */
+ proj_i[0] = proj[0];
+ proj_i[1] = proj[1];
+
+ BLI_rcti_do_minmax_v(rect, proj_i);
+ }
+ }
+ }
+
+ /* return false if the rectangle has non-positive area */
+ return rect->xmin < rect->xmax && rect->ymin < rect->ymax;
}
/* Get four planes in object-space that describe the projection of
* screen_rect from screen into object-space (essentially converting a
* 2D screens-space bounding box into four 3D planes) */
-void paint_calc_redraw_planes(
- float planes[4][4],
- const ARegion *ar,
- Object *ob,
- const rcti *screen_rect)
+void paint_calc_redraw_planes(float planes[4][4],
+ const ARegion *ar,
+ Object *ob,
+ const rcti *screen_rect)
{
- BoundBox bb;
- rcti rect;
-
- /* use some extra space just in case */
- rect = *screen_rect;
- rect.xmin -= 2;
- rect.xmax += 2;
- rect.ymin -= 2;
- rect.ymax += 2;
-
- ED_view3d_clipping_calc(&bb, planes, ar, ob, &rect);
- negate_m4(planes);
+ BoundBox bb;
+ rcti rect;
+
+ /* use some extra space just in case */
+ rect = *screen_rect;
+ rect.xmin -= 2;
+ rect.xmax += 2;
+ rect.ymin -= 2;
+ rect.ymax += 2;
+
+ ED_view3d_clipping_calc(&bb, planes, ar, ob, &rect);
+ negate_m4(planes);
}
-float paint_calc_object_space_radius(
- ViewContext *vc, const float center[3],
- float pixel_radius)
+float paint_calc_object_space_radius(ViewContext *vc, const float center[3], float pixel_radius)
{
- Object *ob = vc->obact;
- float delta[3], scale, loc[3];
- const float mval_f[2] = {pixel_radius, 0.0f};
- float zfac;
+ Object *ob = vc->obact;
+ float delta[3], scale, loc[3];
+ const float mval_f[2] = {pixel_radius, 0.0f};
+ float zfac;
- mul_v3_m4v3(loc, ob->obmat, center);
+ mul_v3_m4v3(loc, ob->obmat, center);
- zfac = ED_view3d_calc_zfac(vc->rv3d, loc, NULL);
- ED_view3d_win_to_delta(vc->ar, mval_f, delta, zfac);
+ zfac = ED_view3d_calc_zfac(vc->rv3d, loc, NULL);
+ ED_view3d_win_to_delta(vc->ar, mval_f, delta, zfac);
- scale = fabsf(mat4_to_scale(ob->obmat));
- scale = (scale == 0.0f) ? 1.0f : scale;
+ scale = fabsf(mat4_to_scale(ob->obmat));
+ scale = (scale == 0.0f) ? 1.0f : scale;
- return len_v3(delta) / scale;
+ return len_v3(delta) / scale;
}
float paint_get_tex_pixel(const MTex *mtex, float u, float v, struct ImagePool *pool, int thread)
{
- float intensity, rgba[4];
- float co[3] = {u, v, 0.0f};
+ float intensity, rgba[4];
+ float co[3] = {u, v, 0.0f};
- externtex(mtex, co, &intensity,
- rgba, rgba + 1, rgba + 2, rgba + 3, thread, pool, false, false);
+ externtex(mtex, co, &intensity, rgba, rgba + 1, rgba + 2, rgba + 3, thread, pool, false, false);
- return intensity;
+ return intensity;
}
-void paint_get_tex_pixel_col(
- const MTex *mtex, float u, float v, float rgba[4], struct ImagePool *pool,
- int thread, bool convert_to_linear, struct ColorSpace *colorspace)
+void paint_get_tex_pixel_col(const MTex *mtex,
+ float u,
+ float v,
+ float rgba[4],
+ struct ImagePool *pool,
+ int thread,
+ bool convert_to_linear,
+ struct ColorSpace *colorspace)
{
- float co[3] = {u, v, 0.0f};
- int hasrgb;
- float intensity;
-
- hasrgb = externtex(mtex, co, &intensity,
- rgba, rgba + 1, rgba + 2, rgba + 3, thread, pool, false, false);
- if (!hasrgb) {
- rgba[0] = intensity;
- rgba[1] = intensity;
- rgba[2] = intensity;
- rgba[3] = 1.0f;
- }
-
- if (convert_to_linear)
- IMB_colormanagement_colorspace_to_scene_linear_v3(rgba, colorspace);
-
- linearrgb_to_srgb_v3_v3(rgba, rgba);
-
- CLAMP(rgba[0], 0.0f, 1.0f);
- CLAMP(rgba[1], 0.0f, 1.0f);
- CLAMP(rgba[2], 0.0f, 1.0f);
- CLAMP(rgba[3], 0.0f, 1.0f);
+ float co[3] = {u, v, 0.0f};
+ int hasrgb;
+ float intensity;
+
+ hasrgb = externtex(
+ mtex, co, &intensity, rgba, rgba + 1, rgba + 2, rgba + 3, thread, pool, false, false);
+ if (!hasrgb) {
+ rgba[0] = intensity;
+ rgba[1] = intensity;
+ rgba[2] = intensity;
+ rgba[3] = 1.0f;
+ }
+
+ if (convert_to_linear)
+ IMB_colormanagement_colorspace_to_scene_linear_v3(rgba, colorspace);
+
+ linearrgb_to_srgb_v3_v3(rgba, rgba);
+
+ CLAMP(rgba[0], 0.0f, 1.0f);
+ CLAMP(rgba[1], 0.0f, 1.0f);
+ CLAMP(rgba[2], 0.0f, 1.0f);
+ CLAMP(rgba[3], 0.0f, 1.0f);
}
void paint_stroke_operator_properties(wmOperatorType *ot)
{
- static const EnumPropertyItem stroke_mode_items[] = {
- {BRUSH_STROKE_NORMAL, "NORMAL", 0, "Regular", "Apply brush normally"},
- {BRUSH_STROKE_INVERT, "INVERT", 0, "Invert", "Invert action of brush for duration of stroke"},
- {BRUSH_STROKE_SMOOTH, "SMOOTH", 0, "Smooth", "Switch brush to smooth mode for duration of stroke"},
- {0},
- };
-
- PropertyRNA *prop;
-
- prop = RNA_def_collection_runtime(ot->srna, "stroke", &RNA_OperatorStrokeElement, "Stroke", "");
- RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
-
- RNA_def_enum(ot->srna, "mode", stroke_mode_items, BRUSH_STROKE_NORMAL,
- "Stroke Mode",
- "Action taken when a paint stroke is made");
-
+ static const EnumPropertyItem stroke_mode_items[] = {
+ {BRUSH_STROKE_NORMAL, "NORMAL", 0, "Regular", "Apply brush normally"},
+ {BRUSH_STROKE_INVERT,
+ "INVERT",
+ 0,
+ "Invert",
+ "Invert action of brush for duration of stroke"},
+ {BRUSH_STROKE_SMOOTH,
+ "SMOOTH",
+ 0,
+ "Smooth",
+ "Switch brush to smooth mode for duration of stroke"},
+ {0},
+ };
+
+ PropertyRNA *prop;
+
+ prop = RNA_def_collection_runtime(ot->srna, "stroke", &RNA_OperatorStrokeElement, "Stroke", "");
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+
+ RNA_def_enum(ot->srna,
+ "mode",
+ stroke_mode_items,
+ BRUSH_STROKE_NORMAL,
+ "Stroke Mode",
+ "Action taken when a paint stroke is made");
}
/* 3D Paint */
static void imapaint_project(float matrix[4][4], const float co[3], float pco[4])
{
- copy_v3_v3(pco, co);
- pco[3] = 1.0f;
+ copy_v3_v3(pco, co);
+ pco[3] = 1.0f;
- mul_m4_v4(matrix, pco);
+ mul_m4_v4(matrix, pco);
}
-static void imapaint_tri_weights(
- float matrix[4][4], GLint view[4],
- const float v1[3], const float v2[3], const float v3[3],
- const float co[2], float w[3])
+static void imapaint_tri_weights(float matrix[4][4],
+ GLint view[4],
+ const float v1[3],
+ const float v2[3],
+ const float v3[3],
+ const float co[2],
+ float w[3])
{
- float pv1[4], pv2[4], pv3[4], h[3], divw;
- float wmat[3][3], invwmat[3][3];
-
- /* compute barycentric coordinates */
-
- /* project the verts */
- imapaint_project(matrix, v1, pv1);
- imapaint_project(matrix, v2, pv2);
- imapaint_project(matrix, v3, pv3);
-
- /* do inverse view mapping, see gluProject man page */
- h[0] = (co[0] - view[0]) * 2.0f / view[2] - 1.0f;
- h[1] = (co[1] - view[1]) * 2.0f / view[3] - 1.0f;
- h[2] = 1.0f;
-
- /* solve for (w1,w2,w3)/perspdiv in:
- * h * perspdiv = Project * Model * (w1 * v1 + w2 * v2 + w3 * v3) */
-
- wmat[0][0] = pv1[0]; wmat[1][0] = pv2[0]; wmat[2][0] = pv3[0];
- wmat[0][1] = pv1[1]; wmat[1][1] = pv2[1]; wmat[2][1] = pv3[1];
- wmat[0][2] = pv1[3]; wmat[1][2] = pv2[3]; wmat[2][2] = pv3[3];
-
- invert_m3_m3(invwmat, wmat);
- mul_m3_v3(invwmat, h);
-
- copy_v3_v3(w, h);
-
- /* w is still divided by perspdiv, make it sum to one */
- divw = w[0] + w[1] + w[2];
- if (divw != 0.0f) {
- mul_v3_fl(w, 1.0f / divw);
- }
+ float pv1[4], pv2[4], pv3[4], h[3], divw;
+ float wmat[3][3], invwmat[3][3];
+
+ /* compute barycentric coordinates */
+
+ /* project the verts */
+ imapaint_project(matrix, v1, pv1);
+ imapaint_project(matrix, v2, pv2);
+ imapaint_project(matrix, v3, pv3);
+
+ /* do inverse view mapping, see gluProject man page */
+ h[0] = (co[0] - view[0]) * 2.0f / view[2] - 1.0f;
+ h[1] = (co[1] - view[1]) * 2.0f / view[3] - 1.0f;
+ h[2] = 1.0f;
+
+ /* solve for (w1,w2,w3)/perspdiv in:
+ * h * perspdiv = Project * Model * (w1 * v1 + w2 * v2 + w3 * v3) */
+
+ wmat[0][0] = pv1[0];
+ wmat[1][0] = pv2[0];
+ wmat[2][0] = pv3[0];
+ wmat[0][1] = pv1[1];
+ wmat[1][1] = pv2[1];
+ wmat[2][1] = pv3[1];
+ wmat[0][2] = pv1[3];
+ wmat[1][2] = pv2[3];
+ wmat[2][2] = pv3[3];
+
+ invert_m3_m3(invwmat, wmat);
+ mul_m3_v3(invwmat, h);
+
+ copy_v3_v3(w, h);
+
+ /* w is still divided by perspdiv, make it sum to one */
+ divw = w[0] + w[1] + w[2];
+ if (divw != 0.0f) {
+ mul_v3_fl(w, 1.0f / divw);
+ }
}
/* compute uv coordinates of mouse in face */
-static void imapaint_pick_uv(Mesh *me_eval, Scene *scene, Object *ob_eval, unsigned int faceindex, const int xy[2], float uv[2])
+static void imapaint_pick_uv(Mesh *me_eval,
+ Scene *scene,
+ Object *ob_eval,
+ unsigned int faceindex,
+ const int xy[2],
+ float uv[2])
{
- int i, findex;
- float p[2], w[3], absw, minabsw;
- float matrix[4][4], proj[4][4];
- GLint view[4];
- const eImagePaintMode mode = scene->toolsettings->imapaint.mode;
-
- const MLoopTri *lt = BKE_mesh_runtime_looptri_ensure(me_eval);
- const int tottri = me_eval->runtime.looptris.len;
-
- const MVert *mvert = me_eval->mvert;
- const MPoly *mpoly = me_eval->mpoly;
- const MLoop *mloop = me_eval->mloop;
- const int *index_mp_to_orig = CustomData_get_layer(&me_eval->pdata, CD_ORIGINDEX);
-
- /* get the needed opengl matrices */
- GPU_viewport_size_get_i(view);
- GPU_matrix_model_view_get(matrix);
- GPU_matrix_projection_get(proj);
- view[0] = view[1] = 0;
- mul_m4_m4m4(matrix, matrix, ob_eval->obmat);
- mul_m4_m4m4(matrix, proj, matrix);
-
- minabsw = 1e10;
- uv[0] = uv[1] = 0.0;
-
- /* test all faces in the derivedmesh with the original index of the picked face */
- /* face means poly here, not triangle, indeed */
- for (i = 0; i < tottri; i++, lt++) {
- findex = index_mp_to_orig ? index_mp_to_orig[lt->poly] : lt->poly;
-
- if (findex == faceindex) {
- const MLoopUV *mloopuv;
- const MPoly *mp = &mpoly[lt->poly];
- const MLoopUV *tri_uv[3];
- float tri_co[3][3];
-
- for (int j = 3; j--; ) {
- copy_v3_v3(tri_co[j], mvert[mloop[lt->tri[j]].v].co);
- }
-
- if (mode == IMAGEPAINT_MODE_MATERIAL) {
- const Material *ma;
- const TexPaintSlot *slot;
-
- ma = give_current_material(ob_eval, mp->mat_nr + 1);
- slot = &ma->texpaintslot[ma->paint_active_slot];
-
- if (!(slot && slot->uvname &&
- (mloopuv = CustomData_get_layer_named(&me_eval->ldata, CD_MLOOPUV, slot->uvname))))
- {
- mloopuv = CustomData_get_layer(&me_eval->ldata, CD_MLOOPUV);
- }
- }
- else {
- mloopuv = CustomData_get_layer(&me_eval->ldata, CD_MLOOPUV);
- }
-
- tri_uv[0] = &mloopuv[lt->tri[0]];
- tri_uv[1] = &mloopuv[lt->tri[1]];
- tri_uv[2] = &mloopuv[lt->tri[2]];
-
- p[0] = xy[0];
- p[1] = xy[1];
-
- imapaint_tri_weights(matrix, view, UNPACK3(tri_co), p, w);
- absw = fabsf(w[0]) + fabsf(w[1]) + fabsf(w[2]);
- if (absw < minabsw) {
- uv[0] = tri_uv[0]->uv[0] * w[0] + tri_uv[1]->uv[0] * w[1] + tri_uv[2]->uv[0] * w[2];
- uv[1] = tri_uv[0]->uv[1] * w[0] + tri_uv[1]->uv[1] * w[1] + tri_uv[2]->uv[1] * w[2];
- minabsw = absw;
- }
- }
- }
+ int i, findex;
+ float p[2], w[3], absw, minabsw;
+ float matrix[4][4], proj[4][4];
+ GLint view[4];
+ const eImagePaintMode mode = scene->toolsettings->imapaint.mode;
+
+ const MLoopTri *lt = BKE_mesh_runtime_looptri_ensure(me_eval);
+ const int tottri = me_eval->runtime.looptris.len;
+
+ const MVert *mvert = me_eval->mvert;
+ const MPoly *mpoly = me_eval->mpoly;
+ const MLoop *mloop = me_eval->mloop;
+ const int *index_mp_to_orig = CustomData_get_layer(&me_eval->pdata, CD_ORIGINDEX);
+
+ /* get the needed opengl matrices */
+ GPU_viewport_size_get_i(view);
+ GPU_matrix_model_view_get(matrix);
+ GPU_matrix_projection_get(proj);
+ view[0] = view[1] = 0;
+ mul_m4_m4m4(matrix, matrix, ob_eval->obmat);
+ mul_m4_m4m4(matrix, proj, matrix);
+
+ minabsw = 1e10;
+ uv[0] = uv[1] = 0.0;
+
+ /* test all faces in the derivedmesh with the original index of the picked face */
+ /* face means poly here, not triangle, indeed */
+ for (i = 0; i < tottri; i++, lt++) {
+ findex = index_mp_to_orig ? index_mp_to_orig[lt->poly] : lt->poly;
+
+ if (findex == faceindex) {
+ const MLoopUV *mloopuv;
+ const MPoly *mp = &mpoly[lt->poly];
+ const MLoopUV *tri_uv[3];
+ float tri_co[3][3];
+
+ for (int j = 3; j--;) {
+ copy_v3_v3(tri_co[j], mvert[mloop[lt->tri[j]].v].co);
+ }
+
+ if (mode == IMAGEPAINT_MODE_MATERIAL) {
+ const Material *ma;
+ const TexPaintSlot *slot;
+
+ ma = give_current_material(ob_eval, mp->mat_nr + 1);
+ slot = &ma->texpaintslot[ma->paint_active_slot];
+
+ if (!(slot && slot->uvname &&
+ (mloopuv = CustomData_get_layer_named(&me_eval->ldata, CD_MLOOPUV, slot->uvname)))) {
+ mloopuv = CustomData_get_layer(&me_eval->ldata, CD_MLOOPUV);
+ }
+ }
+ else {
+ mloopuv = CustomData_get_layer(&me_eval->ldata, CD_MLOOPUV);
+ }
+
+ tri_uv[0] = &mloopuv[lt->tri[0]];
+ tri_uv[1] = &mloopuv[lt->tri[1]];
+ tri_uv[2] = &mloopuv[lt->tri[2]];
+
+ p[0] = xy[0];
+ p[1] = xy[1];
+
+ imapaint_tri_weights(matrix, view, UNPACK3(tri_co), p, w);
+ absw = fabsf(w[0]) + fabsf(w[1]) + fabsf(w[2]);
+ if (absw < minabsw) {
+ uv[0] = tri_uv[0]->uv[0] * w[0] + tri_uv[1]->uv[0] * w[1] + tri_uv[2]->uv[0] * w[2];
+ uv[1] = tri_uv[0]->uv[1] * w[0] + tri_uv[1]->uv[1] * w[1] + tri_uv[2]->uv[1] * w[2];
+ minabsw = absw;
+ }
+ }
+ }
}
/* returns 0 if not found, otherwise 1 */
-static int imapaint_pick_face(
- ViewContext *vc, const int mval[2],
- unsigned int *r_index, unsigned int totpoly)
+static int imapaint_pick_face(ViewContext *vc,
+ const int mval[2],
+ unsigned int *r_index,
+ unsigned int totpoly)
{
- if (totpoly == 0)
- return 0;
+ if (totpoly == 0)
+ return 0;
- /* sample only on the exact position */
- *r_index = ED_view3d_select_id_sample(vc, mval[0], mval[1]);
+ /* sample only on the exact position */
+ *r_index = ED_view3d_select_id_sample(vc, mval[0], mval[1]);
- if ((*r_index) == 0 || (*r_index) > (unsigned int)totpoly) {
- return 0;
- }
+ if ((*r_index) == 0 || (*r_index) > (unsigned int)totpoly) {
+ return 0;
+ }
- (*r_index)--;
+ (*r_index)--;
- return 1;
+ return 1;
}
-
static Image *imapaint_face_image(Object *ob, Mesh *me, int face_index)
{
- Image *ima;
- MPoly *mp = me->mpoly + face_index;
- Material *ma = give_current_material(ob, mp->mat_nr + 1);
- ima = ma && ma->texpaintslot ? ma->texpaintslot[ma->paint_active_slot].ima : NULL;
+ Image *ima;
+ MPoly *mp = me->mpoly + face_index;
+ Material *ma = give_current_material(ob, mp->mat_nr + 1);
+ ima = ma && ma->texpaintslot ? ma->texpaintslot[ma->paint_active_slot].ima : NULL;
- return ima;
+ return ima;
}
/* Uses symm to selectively flip any axis of a coordinate. */
void flip_v3_v3(float out[3], const float in[3], const char symm)
{
- if (symm & PAINT_SYMM_X)
- out[0] = -in[0];
- else
- out[0] = in[0];
- if (symm & PAINT_SYMM_Y)
- out[1] = -in[1];
- else
- out[1] = in[1];
- if (symm & PAINT_SYMM_Z)
- out[2] = -in[2];
- else
- out[2] = in[2];
+ if (symm & PAINT_SYMM_X)
+ out[0] = -in[0];
+ else
+ out[0] = in[0];
+ if (symm & PAINT_SYMM_Y)
+ out[1] = -in[1];
+ else
+ out[1] = in[1];
+ if (symm & PAINT_SYMM_Z)
+ out[2] = -in[2];
+ else
+ out[2] = in[2];
}
void flip_qt_qt(float out[4], const float in[4], const char symm)
{
- float axis[3], angle;
-
- quat_to_axis_angle(axis, &angle, in);
- normalize_v3(axis);
-
- if (symm & PAINT_SYMM_X) {
- axis[0] *= -1.0f;
- angle *= -1.0f;
- }
- if (symm & PAINT_SYMM_Y) {
- axis[1] *= -1.0f;
- angle *= -1.0f;
- }
- if (symm & PAINT_SYMM_Z) {
- axis[2] *= -1.0f;
- angle *= -1.0f;
- }
-
- axis_angle_normalized_to_quat(out, axis, angle);
+ float axis[3], angle;
+
+ quat_to_axis_angle(axis, &angle, in);
+ normalize_v3(axis);
+
+ if (symm & PAINT_SYMM_X) {
+ axis[0] *= -1.0f;
+ angle *= -1.0f;
+ }
+ if (symm & PAINT_SYMM_Y) {
+ axis[1] *= -1.0f;
+ angle *= -1.0f;
+ }
+ if (symm & PAINT_SYMM_Z) {
+ axis[2] *= -1.0f;
+ angle *= -1.0f;
+ }
+
+ axis_angle_normalized_to_quat(out, axis, angle);
}
/* used for both 3d view and image window */
-void paint_sample_color(bContext *C, ARegion *ar, int x, int y, bool texpaint_proj, bool use_palette)
+void paint_sample_color(
+ bContext *C, ARegion *ar, int x, int y, bool texpaint_proj, bool use_palette)
{
- Scene *scene = CTX_data_scene(C);
- Depsgraph *depsgraph = CTX_data_depsgraph(C);
- Paint *paint = BKE_paint_get_active_from_context(C);
- Palette *palette = BKE_paint_palette(paint);
- PaletteColor *color = NULL;
- Brush *br = BKE_paint_brush(BKE_paint_get_active_from_context(C));
- unsigned int col;
- const unsigned char *cp;
-
- CLAMP(x, 0, ar->winx);
- CLAMP(y, 0, ar->winy);
-
- if (use_palette) {
- if (!palette) {
- palette = BKE_palette_add(CTX_data_main(C), "Palette");
- BKE_paint_palette_set(paint, palette);
- }
-
- color = BKE_palette_color_add(palette);
- palette->active_color = BLI_listbase_count(&palette->colors) - 1;
- }
-
-
- if (CTX_wm_view3d(C) && texpaint_proj) {
- /* first try getting a colour directly from the mesh faces if possible */
- ViewLayer *view_layer = CTX_data_view_layer(C);
- Object *ob = OBACT(view_layer);
- Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
- bool sample_success = false;
- ImagePaintSettings *imapaint = &scene->toolsettings->imapaint;
- bool use_material = (imapaint->mode == IMAGEPAINT_MODE_MATERIAL);
-
- if (ob) {
- CustomData_MeshMasks cddata_masks = CD_MASK_BAREMESH;
- cddata_masks.pmask |= CD_MASK_ORIGINDEX;
- Mesh *me = (Mesh *)ob->data;
- Mesh *me_eval = mesh_get_eval_final(depsgraph, scene, ob_eval, &cddata_masks);
-
- ViewContext vc;
- const int mval[2] = {x, y};
- unsigned int faceindex;
- unsigned int totpoly = me->totpoly;
-
- if (CustomData_has_layer(&me_eval->ldata, CD_MLOOPUV)) {
- ED_view3d_viewcontext_init(C, &vc);
-
- view3d_operator_needs_opengl(C);
-
- if (imapaint_pick_face(&vc, mval, &faceindex, totpoly)) {
- Image *image;
-
- if (use_material)
- image = imapaint_face_image(ob_eval, me_eval, faceindex);
- else
- image = imapaint->canvas;
-
- if (image) {
- ImBuf *ibuf = BKE_image_acquire_ibuf(image, NULL, NULL);
- if (ibuf && ibuf->rect) {
- float uv[2];
- float u, v;
- imapaint_pick_uv(me_eval, scene, ob_eval, faceindex, mval, uv);
- sample_success = true;
-
- u = fmodf(uv[0], 1.0f);
- v = fmodf(uv[1], 1.0f);
-
- if (u < 0.0f) u += 1.0f;
- if (v < 0.0f) v += 1.0f;
-
- u = u * ibuf->x;
- v = v * ibuf->y;
-
- if (ibuf->rect_float) {
- float rgba_f[4];
- bilinear_interpolation_color_wrap(ibuf, NULL, rgba_f, u, v);
- straight_to_premul_v4(rgba_f);
- if (use_palette) {
- linearrgb_to_srgb_v3_v3(color->rgb, rgba_f);
- }
- else {
- linearrgb_to_srgb_v3_v3(rgba_f, rgba_f);
- BKE_brush_color_set(scene, br, rgba_f);
- }
- }
- else {
- unsigned char rgba[4];
- bilinear_interpolation_color_wrap(ibuf, rgba, NULL, u, v);
- if (use_palette) {
- rgb_uchar_to_float(color->rgb, rgba);
- }
- else {
- float rgba_f[3];
- rgb_uchar_to_float(rgba_f, rgba);
- BKE_brush_color_set(scene, br, rgba_f);
- }
- }
- }
-
- BKE_image_release_ibuf(image, ibuf, NULL);
- }
- }
- }
- }
-
- if (!sample_success) {
- glReadBuffer(GL_FRONT);
- glReadPixels(x + ar->winrct.xmin, y + ar->winrct.ymin, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &col);
- glReadBuffer(GL_BACK);
- }
- else
- return;
- }
- else {
- glReadBuffer(GL_FRONT);
- glReadPixels(x + ar->winrct.xmin, y + ar->winrct.ymin, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &col);
- glReadBuffer(GL_BACK);
- }
- cp = (unsigned char *)&col;
-
- if (use_palette) {
- rgb_uchar_to_float(color->rgb, cp);
- }
- else {
- float rgba_f[3];
- rgb_uchar_to_float(rgba_f, cp);
- BKE_brush_color_set(scene, br, rgba_f);
- }
+ Scene *scene = CTX_data_scene(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ Paint *paint = BKE_paint_get_active_from_context(C);
+ Palette *palette = BKE_paint_palette(paint);
+ PaletteColor *color = NULL;
+ Brush *br = BKE_paint_brush(BKE_paint_get_active_from_context(C));
+ unsigned int col;
+ const unsigned char *cp;
+
+ CLAMP(x, 0, ar->winx);
+ CLAMP(y, 0, ar->winy);
+
+ if (use_palette) {
+ if (!palette) {
+ palette = BKE_palette_add(CTX_data_main(C), "Palette");
+ BKE_paint_palette_set(paint, palette);
+ }
+
+ color = BKE_palette_color_add(palette);
+ palette->active_color = BLI_listbase_count(&palette->colors) - 1;
+ }
+
+ if (CTX_wm_view3d(C) && texpaint_proj) {
+ /* first try getting a colour directly from the mesh faces if possible */
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Object *ob = OBACT(view_layer);
+ Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
+ bool sample_success = false;
+ ImagePaintSettings *imapaint = &scene->toolsettings->imapaint;
+ bool use_material = (imapaint->mode == IMAGEPAINT_MODE_MATERIAL);
+
+ if (ob) {
+ CustomData_MeshMasks cddata_masks = CD_MASK_BAREMESH;
+ cddata_masks.pmask |= CD_MASK_ORIGINDEX;
+ Mesh *me = (Mesh *)ob->data;
+ Mesh *me_eval = mesh_get_eval_final(depsgraph, scene, ob_eval, &cddata_masks);
+
+ ViewContext vc;
+ const int mval[2] = {x, y};
+ unsigned int faceindex;
+ unsigned int totpoly = me->totpoly;
+
+ if (CustomData_has_layer(&me_eval->ldata, CD_MLOOPUV)) {
+ ED_view3d_viewcontext_init(C, &vc);
+
+ view3d_operator_needs_opengl(C);
+
+ if (imapaint_pick_face(&vc, mval, &faceindex, totpoly)) {
+ Image *image;
+
+ if (use_material)
+ image = imapaint_face_image(ob_eval, me_eval, faceindex);
+ else
+ image = imapaint->canvas;
+
+ if (image) {
+ ImBuf *ibuf = BKE_image_acquire_ibuf(image, NULL, NULL);
+ if (ibuf && ibuf->rect) {
+ float uv[2];
+ float u, v;
+ imapaint_pick_uv(me_eval, scene, ob_eval, faceindex, mval, uv);
+ sample_success = true;
+
+ u = fmodf(uv[0], 1.0f);
+ v = fmodf(uv[1], 1.0f);
+
+ if (u < 0.0f)
+ u += 1.0f;
+ if (v < 0.0f)
+ v += 1.0f;
+
+ u = u * ibuf->x;
+ v = v * ibuf->y;
+
+ if (ibuf->rect_float) {
+ float rgba_f[4];
+ bilinear_interpolation_color_wrap(ibuf, NULL, rgba_f, u, v);
+ straight_to_premul_v4(rgba_f);
+ if (use_palette) {
+ linearrgb_to_srgb_v3_v3(color->rgb, rgba_f);
+ }
+ else {
+ linearrgb_to_srgb_v3_v3(rgba_f, rgba_f);
+ BKE_brush_color_set(scene, br, rgba_f);
+ }
+ }
+ else {
+ unsigned char rgba[4];
+ bilinear_interpolation_color_wrap(ibuf, rgba, NULL, u, v);
+ if (use_palette) {
+ rgb_uchar_to_float(color->rgb, rgba);
+ }
+ else {
+ float rgba_f[3];
+ rgb_uchar_to_float(rgba_f, rgba);
+ BKE_brush_color_set(scene, br, rgba_f);
+ }
+ }
+ }
+
+ BKE_image_release_ibuf(image, ibuf, NULL);
+ }
+ }
+ }
+ }
+
+ if (!sample_success) {
+ glReadBuffer(GL_FRONT);
+ glReadPixels(
+ x + ar->winrct.xmin, y + ar->winrct.ymin, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &col);
+ glReadBuffer(GL_BACK);
+ }
+ else
+ return;
+ }
+ else {
+ glReadBuffer(GL_FRONT);
+ glReadPixels(x + ar->winrct.xmin, y + ar->winrct.ymin, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &col);
+ glReadBuffer(GL_BACK);
+ }
+ cp = (unsigned char *)&col;
+
+ if (use_palette) {
+ rgb_uchar_to_float(color->rgb, cp);
+ }
+ else {
+ float rgba_f[3];
+ rgb_uchar_to_float(rgba_f, cp);
+ BKE_brush_color_set(scene, br, rgba_f);
+ }
}
static int brush_curve_preset_exec(bContext *C, wmOperator *op)
{
- Brush *br = BKE_paint_brush(BKE_paint_get_active_from_context(C));
+ Brush *br = BKE_paint_brush(BKE_paint_get_active_from_context(C));
- if (br) {
- Scene *scene = CTX_data_scene(C);
- ViewLayer *view_layer = CTX_data_view_layer(C);
- BKE_brush_curve_preset(br, RNA_enum_get(op->ptr, "shape"));
- BKE_paint_invalidate_cursor_overlay(scene, view_layer, br->curve);
- }
+ if (br) {
+ Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ BKE_brush_curve_preset(br, RNA_enum_get(op->ptr, "shape"));
+ BKE_paint_invalidate_cursor_overlay(scene, view_layer, br->curve);
+ }
- return OPERATOR_FINISHED;
+ return OPERATOR_FINISHED;
}
static bool brush_curve_preset_poll(bContext *C)
{
- Brush *br = BKE_paint_brush(BKE_paint_get_active_from_context(C));
+ Brush *br = BKE_paint_brush(BKE_paint_get_active_from_context(C));
- return br && br->curve;
+ return br && br->curve;
}
void BRUSH_OT_curve_preset(wmOperatorType *ot)
{
- PropertyRNA *prop;
- static const EnumPropertyItem prop_shape_items[] = {
- {CURVE_PRESET_SHARP, "SHARP", 0, "Sharp", ""},
- {CURVE_PRESET_SMOOTH, "SMOOTH", 0, "Smooth", ""},
- {CURVE_PRESET_MAX, "MAX", 0, "Max", ""},
- {CURVE_PRESET_LINE, "LINE", 0, "Line", ""},
- {CURVE_PRESET_ROUND, "ROUND", 0, "Round", ""},
- {CURVE_PRESET_ROOT, "ROOT", 0, "Root", ""},
- {0, NULL, 0, NULL, NULL},
- };
-
- ot->name = "Preset";
- ot->description = "Set brush shape";
- ot->idname = "BRUSH_OT_curve_preset";
-
- ot->exec = brush_curve_preset_exec;
- ot->poll = brush_curve_preset_poll;
-
- prop = RNA_def_enum(ot->srna, "shape", prop_shape_items, CURVE_PRESET_SMOOTH, "Mode", "");
- RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_CURVE); /* Abusing id_curve :/ */
+ PropertyRNA *prop;
+ static const EnumPropertyItem prop_shape_items[] = {
+ {CURVE_PRESET_SHARP, "SHARP", 0, "Sharp", ""},
+ {CURVE_PRESET_SMOOTH, "SMOOTH", 0, "Smooth", ""},
+ {CURVE_PRESET_MAX, "MAX", 0, "Max", ""},
+ {CURVE_PRESET_LINE, "LINE", 0, "Line", ""},
+ {CURVE_PRESET_ROUND, "ROUND", 0, "Round", ""},
+ {CURVE_PRESET_ROOT, "ROOT", 0, "Root", ""},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ ot->name = "Preset";
+ ot->description = "Set brush shape";
+ ot->idname = "BRUSH_OT_curve_preset";
+
+ ot->exec = brush_curve_preset_exec;
+ ot->poll = brush_curve_preset_poll;
+
+ prop = RNA_def_enum(ot->srna, "shape", prop_shape_items, CURVE_PRESET_SMOOTH, "Mode", "");
+ RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_CURVE); /* Abusing id_curve :/ */
}
-
/* face-select ops */
static int paint_select_linked_exec(bContext *C, wmOperator *UNUSED(op))
{
- paintface_select_linked(C, CTX_data_active_object(C), NULL, true);
- ED_region_tag_redraw(CTX_wm_region(C));
- return OPERATOR_FINISHED;
+ paintface_select_linked(C, CTX_data_active_object(C), NULL, true);
+ ED_region_tag_redraw(CTX_wm_region(C));
+ return OPERATOR_FINISHED;
}
void PAINT_OT_face_select_linked(wmOperatorType *ot)
{
- ot->name = "Select Linked";
- ot->description = "Select linked faces";
- ot->idname = "PAINT_OT_face_select_linked";
+ ot->name = "Select Linked";
+ ot->description = "Select linked faces";
+ ot->idname = "PAINT_OT_face_select_linked";
- ot->exec = paint_select_linked_exec;
- ot->poll = facemask_paint_poll;
+ ot->exec = paint_select_linked_exec;
+ ot->poll = facemask_paint_poll;
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
static int paint_select_linked_pick_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
- const bool select = !RNA_boolean_get(op->ptr, "deselect");
- view3d_operator_needs_opengl(C);
- paintface_select_linked(C, CTX_data_active_object(C), event->mval, select);
- ED_region_tag_redraw(CTX_wm_region(C));
- return OPERATOR_FINISHED;
+ const bool select = !RNA_boolean_get(op->ptr, "deselect");
+ view3d_operator_needs_opengl(C);
+ paintface_select_linked(C, CTX_data_active_object(C), event->mval, select);
+ ED_region_tag_redraw(CTX_wm_region(C));
+ return OPERATOR_FINISHED;
}
void PAINT_OT_face_select_linked_pick(wmOperatorType *ot)
{
- ot->name = "Select Linked Pick";
- ot->description = "Select linked faces under the cursor";
- ot->idname = "PAINT_OT_face_select_linked_pick";
+ ot->name = "Select Linked Pick";
+ ot->description = "Select linked faces under the cursor";
+ ot->idname = "PAINT_OT_face_select_linked_pick";
- ot->invoke = paint_select_linked_pick_invoke;
- ot->poll = facemask_paint_poll;
+ ot->invoke = paint_select_linked_pick_invoke;
+ ot->poll = facemask_paint_poll;
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- RNA_def_boolean(ot->srna, "deselect", 0, "Deselect", "Deselect rather than select items");
+ RNA_def_boolean(ot->srna, "deselect", 0, "Deselect", "Deselect rather than select items");
}
-
static int face_select_all_exec(bContext *C, wmOperator *op)
{
- Object *ob = CTX_data_active_object(C);
- if (paintface_deselect_all_visible(C, ob, RNA_enum_get(op->ptr, "action"), true)) {
- ED_region_tag_redraw(CTX_wm_region(C));
- return OPERATOR_FINISHED;
- }
- return OPERATOR_CANCELLED;
+ Object *ob = CTX_data_active_object(C);
+ if (paintface_deselect_all_visible(C, ob, RNA_enum_get(op->ptr, "action"), true)) {
+ ED_region_tag_redraw(CTX_wm_region(C));
+ return OPERATOR_FINISHED;
+ }
+ return OPERATOR_CANCELLED;
}
-
void PAINT_OT_face_select_all(wmOperatorType *ot)
{
- ot->name = "(De)select All";
- ot->description = "Change selection for all faces";
- ot->idname = "PAINT_OT_face_select_all";
+ ot->name = "(De)select All";
+ ot->description = "Change selection for all faces";
+ ot->idname = "PAINT_OT_face_select_all";
- ot->exec = face_select_all_exec;
- ot->poll = facemask_paint_poll;
+ ot->exec = face_select_all_exec;
+ ot->poll = facemask_paint_poll;
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- WM_operator_properties_select_all(ot);
+ WM_operator_properties_select_all(ot);
}
-
static int vert_select_all_exec(bContext *C, wmOperator *op)
{
- Object *ob = CTX_data_active_object(C);
- paintvert_deselect_all_visible(ob, RNA_enum_get(op->ptr, "action"), true);
- paintvert_tag_select_update(C, ob);
- ED_region_tag_redraw(CTX_wm_region(C));
- return OPERATOR_FINISHED;
+ Object *ob = CTX_data_active_object(C);
+ paintvert_deselect_all_visible(ob, RNA_enum_get(op->ptr, "action"), true);
+ paintvert_tag_select_update(C, ob);
+ ED_region_tag_redraw(CTX_wm_region(C));
+ return OPERATOR_FINISHED;
}
-
void PAINT_OT_vert_select_all(wmOperatorType *ot)
{
- ot->name = "(De)select All";
- ot->description = "Change selection for all vertices";
- ot->idname = "PAINT_OT_vert_select_all";
+ ot->name = "(De)select All";
+ ot->description = "Change selection for all vertices";
+ ot->idname = "PAINT_OT_vert_select_all";
- ot->exec = vert_select_all_exec;
- ot->poll = vert_paint_poll;
+ ot->exec = vert_select_all_exec;
+ ot->poll = vert_paint_poll;
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- WM_operator_properties_select_all(ot);
+ WM_operator_properties_select_all(ot);
}
-
static int vert_select_ungrouped_exec(bContext *C, wmOperator *op)
{
- Object *ob = CTX_data_active_object(C);
- Mesh *me = ob->data;
-
- if (BLI_listbase_is_empty(&ob->defbase) || (me->dvert == NULL)) {
- BKE_report(op->reports, RPT_ERROR, "No weights/vertex groups on object");
- return OPERATOR_CANCELLED;
- }
-
- paintvert_select_ungrouped(ob, RNA_boolean_get(op->ptr, "extend"), true);
- paintvert_tag_select_update(C, ob);
- ED_region_tag_redraw(CTX_wm_region(C));
- return OPERATOR_FINISHED;
+ Object *ob = CTX_data_active_object(C);
+ Mesh *me = ob->data;
+
+ if (BLI_listbase_is_empty(&ob->defbase) || (me->dvert == NULL)) {
+ BKE_report(op->reports, RPT_ERROR, "No weights/vertex groups on object");
+ return OPERATOR_CANCELLED;
+ }
+
+ paintvert_select_ungrouped(ob, RNA_boolean_get(op->ptr, "extend"), true);
+ paintvert_tag_select_update(C, ob);
+ ED_region_tag_redraw(CTX_wm_region(C));
+ return OPERATOR_FINISHED;
}
void PAINT_OT_vert_select_ungrouped(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Select Ungrouped";
- ot->idname = "PAINT_OT_vert_select_ungrouped";
- ot->description = "Select vertices without a group";
+ /* identifiers */
+ ot->name = "Select Ungrouped";
+ ot->idname = "PAINT_OT_vert_select_ungrouped";
+ ot->description = "Select vertices without a group";
- /* api callbacks */
- ot->exec = vert_select_ungrouped_exec;
- ot->poll = vert_paint_poll;
+ /* api callbacks */
+ ot->exec = vert_select_ungrouped_exec;
+ ot->poll = vert_paint_poll;
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend the selection");
+ RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend the selection");
}
static int face_select_hide_exec(bContext *C, wmOperator *op)
{
- const bool unselected = RNA_boolean_get(op->ptr, "unselected");
- Object *ob = CTX_data_active_object(C);
- paintface_hide(C, ob, unselected);
- ED_region_tag_redraw(CTX_wm_region(C));
- return OPERATOR_FINISHED;
+ const bool unselected = RNA_boolean_get(op->ptr, "unselected");
+ Object *ob = CTX_data_active_object(C);
+ paintface_hide(C, ob, unselected);
+ ED_region_tag_redraw(CTX_wm_region(C));
+ return OPERATOR_FINISHED;
}
void PAINT_OT_face_select_hide(wmOperatorType *ot)
{
- ot->name = "Face Select Hide";
- ot->description = "Hide selected faces";
- ot->idname = "PAINT_OT_face_select_hide";
+ ot->name = "Face Select Hide";
+ ot->description = "Hide selected faces";
+ ot->idname = "PAINT_OT_face_select_hide";
- ot->exec = face_select_hide_exec;
- ot->poll = facemask_paint_poll;
+ ot->exec = face_select_hide_exec;
+ ot->poll = facemask_paint_poll;
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected rather than selected objects");
+ RNA_def_boolean(
+ ot->srna, "unselected", 0, "Unselected", "Hide unselected rather than selected objects");
}
static int face_select_reveal_exec(bContext *C, wmOperator *op)
{
- const bool select = RNA_boolean_get(op->ptr, "select");
- Object *ob = CTX_data_active_object(C);
- paintface_reveal(C, ob, select);
- ED_region_tag_redraw(CTX_wm_region(C));
- return OPERATOR_FINISHED;
+ const bool select = RNA_boolean_get(op->ptr, "select");
+ Object *ob = CTX_data_active_object(C);
+ paintface_reveal(C, ob, select);
+ ED_region_tag_redraw(CTX_wm_region(C));
+ return OPERATOR_FINISHED;
}
void PAINT_OT_face_select_reveal(wmOperatorType *ot)
{
- ot->name = "Face Select Reveal";
- ot->description = "Reveal hidden faces";
- ot->idname = "PAINT_OT_face_select_reveal";
+ ot->name = "Face Select Reveal";
+ ot->description = "Reveal hidden faces";
+ ot->idname = "PAINT_OT_face_select_reveal";
- ot->exec = face_select_reveal_exec;
- ot->poll = facemask_paint_poll;
+ ot->exec = face_select_reveal_exec;
+ ot->poll = facemask_paint_poll;
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- RNA_def_boolean(ot->srna, "select", true, "Select", "");
+ RNA_def_boolean(ot->srna, "select", true, "Select", "");
}
diff --git a/source/blender/editors/sculpt_paint/paint_vertex.c b/source/blender/editors/sculpt_paint/paint_vertex.c
index 85bdba683cd..70783ff004e 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex.c
+++ b/source/blender/editors/sculpt_paint/paint_vertex.c
@@ -77,130 +77,130 @@
#include "BKE_ccg.h"
#include "sculpt_intern.h"
-#include "paint_intern.h" /* own include */
+#include "paint_intern.h" /* own include */
/* Use for 'blur' brush, align with PBVH nodes, created and freed on each update. */
struct VPaintAverageAccum {
- uint len;
- uint value[3];
+ uint len;
+ uint value[3];
};
struct WPaintAverageAccum {
- uint len;
- double value;
+ uint len;
+ double value;
};
struct NormalAnglePrecalc {
- bool do_mask_normal;
- /* what angle to mask at */
- float angle;
- /* cos(angle), faster to compare */
- float angle__cos;
- float angle_inner;
- float angle_inner__cos;
- /* difference between angle and angle_inner, for easy access */
- float angle_range;
+ bool do_mask_normal;
+ /* what angle to mask at */
+ float angle;
+ /* cos(angle), faster to compare */
+ float angle__cos;
+ float angle_inner;
+ float angle_inner__cos;
+ /* difference between angle and angle_inner, for easy access */
+ float angle_range;
};
-
-static void view_angle_limits_init(
- struct NormalAnglePrecalc *a, float angle, bool do_mask_normal)
+static void view_angle_limits_init(struct NormalAnglePrecalc *a, float angle, bool do_mask_normal)
{
- angle = RAD2DEGF(angle);
- a->do_mask_normal = do_mask_normal;
- if (do_mask_normal) {
- a->angle_inner = angle;
- a->angle = (a->angle_inner + 90.0f) * 0.5f;
- }
- else {
- a->angle_inner = a->angle = angle;
- }
+ angle = RAD2DEGF(angle);
+ a->do_mask_normal = do_mask_normal;
+ if (do_mask_normal) {
+ a->angle_inner = angle;
+ a->angle = (a->angle_inner + 90.0f) * 0.5f;
+ }
+ else {
+ a->angle_inner = a->angle = angle;
+ }
- a->angle_inner *= (float)(M_PI_2 / 90);
- a->angle *= (float)(M_PI_2 / 90);
- a->angle_range = a->angle - a->angle_inner;
+ a->angle_inner *= (float)(M_PI_2 / 90);
+ a->angle *= (float)(M_PI_2 / 90);
+ a->angle_range = a->angle - a->angle_inner;
- if (a->angle_range <= 0.0f) {
- a->do_mask_normal = false; /* no need to do blending */
- }
+ if (a->angle_range <= 0.0f) {
+ a->do_mask_normal = false; /* no need to do blending */
+ }
- a->angle__cos = cosf(a->angle);
- a->angle_inner__cos = cosf(a->angle_inner);
+ a->angle__cos = cosf(a->angle);
+ a->angle_inner__cos = cosf(a->angle_inner);
}
-static float view_angle_limits_apply_falloff(
- const struct NormalAnglePrecalc *a, float angle_cos, float *mask_p)
+static float view_angle_limits_apply_falloff(const struct NormalAnglePrecalc *a,
+ float angle_cos,
+ float *mask_p)
{
- if (angle_cos <= a->angle__cos) {
- /* outsize the normal limit */
- return false;
- }
- else if (angle_cos < a->angle_inner__cos) {
- *mask_p *= (a->angle - acosf(angle_cos)) / a->angle_range;
- return true;
- }
- else {
- return true;
- }
+ if (angle_cos <= a->angle__cos) {
+ /* outsize the normal limit */
+ return false;
+ }
+ else if (angle_cos < a->angle_inner__cos) {
+ *mask_p *= (a->angle - acosf(angle_cos)) / a->angle_range;
+ return true;
+ }
+ else {
+ return true;
+ }
}
static bool vwpaint_use_normal(const VPaint *vp)
{
- return ((vp->paint.brush->flag & BRUSH_FRONTFACE) != 0) ||
- ((vp->paint.brush->flag & BRUSH_FRONTFACE_FALLOFF) != 0);
+ return ((vp->paint.brush->flag & BRUSH_FRONTFACE) != 0) ||
+ ((vp->paint.brush->flag & BRUSH_FRONTFACE_FALLOFF) != 0);
}
static bool brush_use_accumulate_ex(const Brush *brush, const int ob_mode)
{
- return ((brush->flag & BRUSH_ACCUMULATE) != 0 ||
- (ob_mode == OB_MODE_VERTEX_PAINT ?
- (brush->vertexpaint_tool == VPAINT_TOOL_SMEAR) :
- (brush->weightpaint_tool == WPAINT_TOOL_SMEAR)));
+ return ((brush->flag & BRUSH_ACCUMULATE) != 0 ||
+ (ob_mode == OB_MODE_VERTEX_PAINT ? (brush->vertexpaint_tool == VPAINT_TOOL_SMEAR) :
+ (brush->weightpaint_tool == WPAINT_TOOL_SMEAR)));
}
static bool brush_use_accumulate(const VPaint *vp)
{
- return brush_use_accumulate_ex(vp->paint.brush, vp->paint.runtime.ob_mode);
+ return brush_use_accumulate_ex(vp->paint.brush, vp->paint.runtime.ob_mode);
}
-static MDeformVert *defweight_prev_init(MDeformVert *dvert_prev, MDeformVert *dvert_curr, int index)
+static MDeformVert *defweight_prev_init(MDeformVert *dvert_prev,
+ MDeformVert *dvert_curr,
+ int index)
{
- MDeformVert *dv_curr = &dvert_curr[index];
- MDeformVert *dv_prev = &dvert_prev[index];
- if (dv_prev->flag == 1) {
- dv_prev->flag = 0;
- defvert_copy(dv_prev, dv_curr);
- }
- return dv_prev;
+ MDeformVert *dv_curr = &dvert_curr[index];
+ MDeformVert *dv_prev = &dvert_prev[index];
+ if (dv_prev->flag == 1) {
+ dv_prev->flag = 0;
+ defvert_copy(dv_prev, dv_curr);
+ }
+ return dv_prev;
}
/* check if we can do partial updates and have them draw realtime
* (without evaluating modifiers) */
static bool vertex_paint_use_fast_update_check(Object *ob)
{
- Mesh *me_eval = ob->runtime.mesh_eval;
+ Mesh *me_eval = ob->runtime.mesh_eval;
- if (me_eval != NULL) {
- Mesh *me = BKE_mesh_from_object(ob);
- if (me && me->mloopcol) {
- return (me->mloopcol == CustomData_get_layer(&me_eval->ldata, CD_MLOOPCOL));
- }
- }
+ if (me_eval != NULL) {
+ Mesh *me = BKE_mesh_from_object(ob);
+ if (me && me->mloopcol) {
+ return (me->mloopcol == CustomData_get_layer(&me_eval->ldata, CD_MLOOPCOL));
+ }
+ }
- return false;
+ return false;
}
static void paint_last_stroke_update(Scene *scene, ARegion *ar, const float mval[2])
{
- const int mval_i[2] = {mval[0], mval[1]};
- float world[3];
+ const int mval_i[2] = {mval[0], mval[1]};
+ float world[3];
- if (ED_view3d_autodist_simple(ar, mval_i, world, 0, NULL)) {
- UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
- ups->average_stroke_counter++;
- add_v3_v3(ups->average_stroke_accum, world);
- ups->last_stroke_valid = true;
- }
+ if (ED_view3d_autodist_simple(ar, mval_i, world, 0, NULL)) {
+ UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
+ ups->average_stroke_counter++;
+ add_v3_v3(ups->average_stroke_accum, world);
+ ups->last_stroke_valid = true;
+ }
}
/* polling - retrieve whether cursor should be set or operator should be done */
@@ -208,349 +208,360 @@ static void paint_last_stroke_update(Scene *scene, ARegion *ar, const float mval
/* Returns true if vertex paint mode is active */
bool vertex_paint_mode_poll(bContext *C)
{
- Object *ob = CTX_data_active_object(C);
+ Object *ob = CTX_data_active_object(C);
- return ob && ob->mode == OB_MODE_VERTEX_PAINT && ((Mesh *)ob->data)->totpoly;
+ return ob && ob->mode == OB_MODE_VERTEX_PAINT && ((Mesh *)ob->data)->totpoly;
}
static bool vertex_paint_poll_ex(bContext *C, bool check_tool)
{
- if (vertex_paint_mode_poll(C) &&
- BKE_paint_brush(&CTX_data_tool_settings(C)->vpaint->paint))
- {
- ScrArea *sa = CTX_wm_area(C);
- if (sa && sa->spacetype == SPACE_VIEW3D) {
- ARegion *ar = CTX_wm_region(C);
- if (ar->regiontype == RGN_TYPE_WINDOW) {
- if (!check_tool || WM_toolsystem_active_tool_is_brush(C)) {
- return 1;
- }
- }
- }
- }
- return 0;
+ if (vertex_paint_mode_poll(C) && BKE_paint_brush(&CTX_data_tool_settings(C)->vpaint->paint)) {
+ ScrArea *sa = CTX_wm_area(C);
+ if (sa && sa->spacetype == SPACE_VIEW3D) {
+ ARegion *ar = CTX_wm_region(C);
+ if (ar->regiontype == RGN_TYPE_WINDOW) {
+ if (!check_tool || WM_toolsystem_active_tool_is_brush(C)) {
+ return 1;
+ }
+ }
+ }
+ }
+ return 0;
}
bool vertex_paint_poll(bContext *C)
{
- return vertex_paint_poll_ex(C, true);
+ return vertex_paint_poll_ex(C, true);
}
bool vertex_paint_poll_ignore_tool(bContext *C)
{
- return vertex_paint_poll_ex(C, false);
+ return vertex_paint_poll_ex(C, false);
}
bool weight_paint_mode_poll(bContext *C)
{
- Object *ob = CTX_data_active_object(C);
+ Object *ob = CTX_data_active_object(C);
- return ob && ob->mode == OB_MODE_WEIGHT_PAINT && ((Mesh *)ob->data)->totpoly;
+ return ob && ob->mode == OB_MODE_WEIGHT_PAINT && ((Mesh *)ob->data)->totpoly;
}
static bool weight_paint_poll_ex(bContext *C, bool check_tool)
{
- Object *ob = CTX_data_active_object(C);
- ScrArea *sa;
-
- if ((ob != NULL) &&
- (ob->mode & OB_MODE_WEIGHT_PAINT) &&
- (BKE_paint_brush(&CTX_data_tool_settings(C)->wpaint->paint) != NULL) &&
- (sa = CTX_wm_area(C)) &&
- (sa->spacetype == SPACE_VIEW3D))
- {
- ARegion *ar = CTX_wm_region(C);
- if (ar->regiontype == RGN_TYPE_WINDOW) {
- if (!check_tool || WM_toolsystem_active_tool_is_brush(C)) {
- return 1;
- }
- }
- }
- return 0;
+ Object *ob = CTX_data_active_object(C);
+ ScrArea *sa;
+
+ if ((ob != NULL) && (ob->mode & OB_MODE_WEIGHT_PAINT) &&
+ (BKE_paint_brush(&CTX_data_tool_settings(C)->wpaint->paint) != NULL) &&
+ (sa = CTX_wm_area(C)) && (sa->spacetype == SPACE_VIEW3D)) {
+ ARegion *ar = CTX_wm_region(C);
+ if (ar->regiontype == RGN_TYPE_WINDOW) {
+ if (!check_tool || WM_toolsystem_active_tool_is_brush(C)) {
+ return 1;
+ }
+ }
+ }
+ return 0;
}
bool weight_paint_poll(bContext *C)
{
- return weight_paint_poll_ex(C, true);
+ return weight_paint_poll_ex(C, true);
}
bool weight_paint_poll_ignore_tool(bContext *C)
{
- return weight_paint_poll_ex(C, false);
+ return weight_paint_poll_ex(C, false);
}
uint vpaint_get_current_col(Scene *scene, VPaint *vp, bool secondary)
{
- Brush *brush = BKE_paint_brush(&vp->paint);
- uchar col[4];
- rgb_float_to_uchar(col, secondary ? BKE_brush_secondary_color_get(scene, brush) : BKE_brush_color_get(scene, brush));
- col[3] = 255; /* alpha isn't used, could even be removed to speedup paint a little */
- return *(uint *)col;
+ Brush *brush = BKE_paint_brush(&vp->paint);
+ uchar col[4];
+ rgb_float_to_uchar(col,
+ secondary ? BKE_brush_secondary_color_get(scene, brush) :
+ BKE_brush_color_get(scene, brush));
+ col[3] = 255; /* alpha isn't used, could even be removed to speedup paint a little */
+ return *(uint *)col;
}
/* wpaint has 'wpaint_blend' */
-static uint vpaint_blend(
- const VPaint *vp, uint color_curr, uint color_orig,
- uint color_paint, const int alpha_i,
- /* pre scaled from [0-1] --> [0-255] */
- const int brush_alpha_value_i)
-{
- const Brush *brush = vp->paint.brush;
- const IMB_BlendMode blend = brush->blend;
-
- uint color_blend = ED_vpaint_blend_tool(blend, color_curr, color_paint, alpha_i);
-
- /* if no accumulate, clip color adding with colorig & orig alpha */
- if (!brush_use_accumulate(vp)) {
- uint color_test, a;
- char *cp, *ct, *co;
-
- color_test = ED_vpaint_blend_tool(blend, color_orig, color_paint, brush_alpha_value_i);
-
- cp = (char *)&color_blend;
- ct = (char *)&color_test;
- co = (char *)&color_orig;
-
- for (a = 0; a < 4; a++) {
- if (ct[a] < co[a]) {
- if (cp[a] < ct[a]) cp[a] = ct[a];
- else if (cp[a] > co[a]) cp[a] = co[a];
- }
- else {
- if (cp[a] < co[a]) cp[a] = co[a];
- else if (cp[a] > ct[a]) cp[a] = ct[a];
- }
- }
- }
-
- if ((brush->flag & BRUSH_LOCK_ALPHA) &&
- !ELEM(blend, IMB_BLEND_ERASE_ALPHA, IMB_BLEND_ADD_ALPHA))
- {
- char *cp, *cc;
- cp = (char *)&color_blend;
- cc = (char *)&color_curr;
- cp[3] = cc[3];
- }
-
- return color_blend;
-}
-
-static void tex_color_alpha(
- VPaint *vp, const ViewContext *vc, const float co[3],
- float r_rgba[4])
-{
- const Brush *brush = BKE_paint_brush(&vp->paint);
- BLI_assert(brush->mtex.tex != NULL);
- if (brush->mtex.brush_map_mode == MTEX_MAP_MODE_3D) {
- BKE_brush_sample_tex_3d(vc->scene, brush, co, r_rgba, 0, NULL);
- }
- else {
- float co_ss[2]; /* screenspace */
- if (ED_view3d_project_float_object(
- vc->ar,
- co, co_ss,
- V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_NEAR) == V3D_PROJ_RET_OK)
- {
- const float co_ss_3d[3] = {co_ss[0], co_ss[1], 0.0f}; /* we need a 3rd empty value */
- BKE_brush_sample_tex_3d(vc->scene, brush, co_ss_3d, r_rgba, 0, NULL);
- }
- else {
- zero_v4(r_rgba);
- }
- }
+static uint vpaint_blend(const VPaint *vp,
+ uint color_curr,
+ uint color_orig,
+ uint color_paint,
+ const int alpha_i,
+ /* pre scaled from [0-1] --> [0-255] */
+ const int brush_alpha_value_i)
+{
+ const Brush *brush = vp->paint.brush;
+ const IMB_BlendMode blend = brush->blend;
+
+ uint color_blend = ED_vpaint_blend_tool(blend, color_curr, color_paint, alpha_i);
+
+ /* if no accumulate, clip color adding with colorig & orig alpha */
+ if (!brush_use_accumulate(vp)) {
+ uint color_test, a;
+ char *cp, *ct, *co;
+
+ color_test = ED_vpaint_blend_tool(blend, color_orig, color_paint, brush_alpha_value_i);
+
+ cp = (char *)&color_blend;
+ ct = (char *)&color_test;
+ co = (char *)&color_orig;
+
+ for (a = 0; a < 4; a++) {
+ if (ct[a] < co[a]) {
+ if (cp[a] < ct[a])
+ cp[a] = ct[a];
+ else if (cp[a] > co[a])
+ cp[a] = co[a];
+ }
+ else {
+ if (cp[a] < co[a])
+ cp[a] = co[a];
+ else if (cp[a] > ct[a])
+ cp[a] = ct[a];
+ }
+ }
+ }
+
+ if ((brush->flag & BRUSH_LOCK_ALPHA) &&
+ !ELEM(blend, IMB_BLEND_ERASE_ALPHA, IMB_BLEND_ADD_ALPHA)) {
+ char *cp, *cc;
+ cp = (char *)&color_blend;
+ cc = (char *)&color_curr;
+ cp[3] = cc[3];
+ }
+
+ return color_blend;
+}
+
+static void tex_color_alpha(VPaint *vp, const ViewContext *vc, const float co[3], float r_rgba[4])
+{
+ const Brush *brush = BKE_paint_brush(&vp->paint);
+ BLI_assert(brush->mtex.tex != NULL);
+ if (brush->mtex.brush_map_mode == MTEX_MAP_MODE_3D) {
+ BKE_brush_sample_tex_3d(vc->scene, brush, co, r_rgba, 0, NULL);
+ }
+ else {
+ float co_ss[2]; /* screenspace */
+ if (ED_view3d_project_float_object(
+ vc->ar, co, co_ss, V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_NEAR) ==
+ V3D_PROJ_RET_OK) {
+ const float co_ss_3d[3] = {co_ss[0], co_ss[1], 0.0f}; /* we need a 3rd empty value */
+ BKE_brush_sample_tex_3d(vc->scene, brush, co_ss_3d, r_rgba, 0, NULL);
+ }
+ else {
+ zero_v4(r_rgba);
+ }
+ }
}
/* vpaint has 'vpaint_blend' */
-static float wpaint_blend(
- const VPaint *wp, float weight,
- const float alpha, float paintval,
- const float UNUSED(brush_alpha_value),
- const short do_flip)
-{
- const Brush *brush = wp->paint.brush;
- IMB_BlendMode blend = brush->blend;
-
- if (do_flip) {
- switch (blend) {
- case IMB_BLEND_MIX:
- paintval = 1.f - paintval; break;
- case IMB_BLEND_ADD:
- blend = IMB_BLEND_SUB; break;
- case IMB_BLEND_SUB:
- blend = IMB_BLEND_ADD; break;
- case IMB_BLEND_LIGHTEN:
- blend = IMB_BLEND_DARKEN; break;
- case IMB_BLEND_DARKEN:
- blend = IMB_BLEND_LIGHTEN; break;
- default: break;
- }
- }
-
- weight = ED_wpaint_blend_tool(blend, weight, paintval, alpha);
-
- CLAMP(weight, 0.0f, 1.0f);
-
- return weight;
+static float wpaint_blend(const VPaint *wp,
+ float weight,
+ const float alpha,
+ float paintval,
+ const float UNUSED(brush_alpha_value),
+ const short do_flip)
+{
+ const Brush *brush = wp->paint.brush;
+ IMB_BlendMode blend = brush->blend;
+
+ if (do_flip) {
+ switch (blend) {
+ case IMB_BLEND_MIX:
+ paintval = 1.f - paintval;
+ break;
+ case IMB_BLEND_ADD:
+ blend = IMB_BLEND_SUB;
+ break;
+ case IMB_BLEND_SUB:
+ blend = IMB_BLEND_ADD;
+ break;
+ case IMB_BLEND_LIGHTEN:
+ blend = IMB_BLEND_DARKEN;
+ break;
+ case IMB_BLEND_DARKEN:
+ blend = IMB_BLEND_LIGHTEN;
+ break;
+ default:
+ break;
+ }
+ }
+
+ weight = ED_wpaint_blend_tool(blend, weight, paintval, alpha);
+
+ CLAMP(weight, 0.0f, 1.0f);
+
+ return weight;
}
static float wpaint_clamp_monotonic(float oldval, float curval, float newval)
{
- if (newval < oldval)
- return MIN2(newval, curval);
- else if (newval > oldval)
- return MAX2(newval, curval);
- else
- return newval;
+ if (newval < oldval)
+ return MIN2(newval, curval);
+ else if (newval > oldval)
+ return MAX2(newval, curval);
+ else
+ return newval;
}
/* ----------------------------------------------------- */
-static void do_weight_paint_normalize_all(MDeformVert *dvert, const int defbase_tot, const bool *vgroup_validmap)
-{
- float sum = 0.0f, fac;
- uint i, tot = 0;
- MDeformWeight *dw;
-
- for (i = dvert->totweight, dw = dvert->dw; i != 0; i--, dw++) {
- if (dw->def_nr < defbase_tot && vgroup_validmap[dw->def_nr]) {
- tot++;
- sum += dw->weight;
- }
- }
-
- if ((tot == 0) || (sum == 1.0f)) {
- return;
- }
-
- if (sum != 0.0f) {
- fac = 1.0f / sum;
-
- for (i = dvert->totweight, dw = dvert->dw; i != 0; i--, dw++) {
- if (dw->def_nr < defbase_tot && vgroup_validmap[dw->def_nr]) {
- dw->weight *= fac;
- }
- }
- }
- else {
- /* hrmf, not a factor in this case */
- fac = 1.0f / tot;
-
- for (i = dvert->totweight, dw = dvert->dw; i != 0; i--, dw++) {
- if (dw->def_nr < defbase_tot && vgroup_validmap[dw->def_nr]) {
- dw->weight = fac;
- }
- }
- }
+static void do_weight_paint_normalize_all(MDeformVert *dvert,
+ const int defbase_tot,
+ const bool *vgroup_validmap)
+{
+ float sum = 0.0f, fac;
+ uint i, tot = 0;
+ MDeformWeight *dw;
+
+ for (i = dvert->totweight, dw = dvert->dw; i != 0; i--, dw++) {
+ if (dw->def_nr < defbase_tot && vgroup_validmap[dw->def_nr]) {
+ tot++;
+ sum += dw->weight;
+ }
+ }
+
+ if ((tot == 0) || (sum == 1.0f)) {
+ return;
+ }
+
+ if (sum != 0.0f) {
+ fac = 1.0f / sum;
+
+ for (i = dvert->totweight, dw = dvert->dw; i != 0; i--, dw++) {
+ if (dw->def_nr < defbase_tot && vgroup_validmap[dw->def_nr]) {
+ dw->weight *= fac;
+ }
+ }
+ }
+ else {
+ /* hrmf, not a factor in this case */
+ fac = 1.0f / tot;
+
+ for (i = dvert->totweight, dw = dvert->dw; i != 0; i--, dw++) {
+ if (dw->def_nr < defbase_tot && vgroup_validmap[dw->def_nr]) {
+ dw->weight = fac;
+ }
+ }
+ }
}
/**
* A version of #do_weight_paint_normalize_all that includes locked weights
* but only changes unlocked weights.
*/
-static bool do_weight_paint_normalize_all_locked(
- MDeformVert *dvert, const int defbase_tot, const bool *vgroup_validmap,
- const bool *lock_flags)
-{
- float sum = 0.0f, fac;
- float sum_unlock = 0.0f;
- float lock_weight = 0.0f;
- uint i, tot = 0;
- MDeformWeight *dw;
-
- if (lock_flags == NULL) {
- do_weight_paint_normalize_all(dvert, defbase_tot, vgroup_validmap);
- return true;
- }
-
- for (i = dvert->totweight, dw = dvert->dw; i != 0; i--, dw++) {
- if (dw->def_nr < defbase_tot && vgroup_validmap[dw->def_nr]) {
- sum += dw->weight;
-
- if (lock_flags[dw->def_nr]) {
- lock_weight += dw->weight;
- }
- else {
- tot++;
- sum_unlock += dw->weight;
- }
- }
- }
-
- if (sum == 1.0f) {
- return true;
- }
-
- if (tot == 0) {
- return false;
- }
-
- if (lock_weight >= 1.0f) {
- /* locked groups make it impossible to fully normalize,
- * zero out what we can and return false */
- for (i = dvert->totweight, dw = dvert->dw; i != 0; i--, dw++) {
- if (dw->def_nr < defbase_tot && vgroup_validmap[dw->def_nr]) {
- if (lock_flags[dw->def_nr] == false) {
- dw->weight = 0.0f;
- }
- }
- }
-
- return (lock_weight == 1.0f);
- }
- else if (sum_unlock != 0.0f) {
- fac = (1.0f - lock_weight) / sum_unlock;
-
- for (i = dvert->totweight, dw = dvert->dw; i != 0; i--, dw++) {
- if (dw->def_nr < defbase_tot && vgroup_validmap[dw->def_nr]) {
- if (lock_flags[dw->def_nr] == false) {
- dw->weight *= fac;
- /* paranoid but possibly with float error */
- CLAMP(dw->weight, 0.0f, 1.0f);
- }
- }
- }
- }
- else {
- /* hrmf, not a factor in this case */
- fac = (1.0f - lock_weight) / tot;
- /* paranoid but possibly with float error */
- CLAMP(fac, 0.0f, 1.0f);
-
- for (i = dvert->totweight, dw = dvert->dw; i != 0; i--, dw++) {
- if (dw->def_nr < defbase_tot && vgroup_validmap[dw->def_nr]) {
- if (lock_flags[dw->def_nr] == false) {
- dw->weight = fac;
- }
- }
- }
- }
-
- return true;
+static bool do_weight_paint_normalize_all_locked(MDeformVert *dvert,
+ const int defbase_tot,
+ const bool *vgroup_validmap,
+ const bool *lock_flags)
+{
+ float sum = 0.0f, fac;
+ float sum_unlock = 0.0f;
+ float lock_weight = 0.0f;
+ uint i, tot = 0;
+ MDeformWeight *dw;
+
+ if (lock_flags == NULL) {
+ do_weight_paint_normalize_all(dvert, defbase_tot, vgroup_validmap);
+ return true;
+ }
+
+ for (i = dvert->totweight, dw = dvert->dw; i != 0; i--, dw++) {
+ if (dw->def_nr < defbase_tot && vgroup_validmap[dw->def_nr]) {
+ sum += dw->weight;
+
+ if (lock_flags[dw->def_nr]) {
+ lock_weight += dw->weight;
+ }
+ else {
+ tot++;
+ sum_unlock += dw->weight;
+ }
+ }
+ }
+
+ if (sum == 1.0f) {
+ return true;
+ }
+
+ if (tot == 0) {
+ return false;
+ }
+
+ if (lock_weight >= 1.0f) {
+ /* locked groups make it impossible to fully normalize,
+ * zero out what we can and return false */
+ for (i = dvert->totweight, dw = dvert->dw; i != 0; i--, dw++) {
+ if (dw->def_nr < defbase_tot && vgroup_validmap[dw->def_nr]) {
+ if (lock_flags[dw->def_nr] == false) {
+ dw->weight = 0.0f;
+ }
+ }
+ }
+
+ return (lock_weight == 1.0f);
+ }
+ else if (sum_unlock != 0.0f) {
+ fac = (1.0f - lock_weight) / sum_unlock;
+
+ for (i = dvert->totweight, dw = dvert->dw; i != 0; i--, dw++) {
+ if (dw->def_nr < defbase_tot && vgroup_validmap[dw->def_nr]) {
+ if (lock_flags[dw->def_nr] == false) {
+ dw->weight *= fac;
+ /* paranoid but possibly with float error */
+ CLAMP(dw->weight, 0.0f, 1.0f);
+ }
+ }
+ }
+ }
+ else {
+ /* hrmf, not a factor in this case */
+ fac = (1.0f - lock_weight) / tot;
+ /* paranoid but possibly with float error */
+ CLAMP(fac, 0.0f, 1.0f);
+
+ for (i = dvert->totweight, dw = dvert->dw; i != 0; i--, dw++) {
+ if (dw->def_nr < defbase_tot && vgroup_validmap[dw->def_nr]) {
+ if (lock_flags[dw->def_nr] == false) {
+ dw->weight = fac;
+ }
+ }
+ }
+ }
+
+ return true;
}
/**
* \note same as function above except it does a second pass without active group
* if normalize fails with it.
*/
-static void do_weight_paint_normalize_all_locked_try_active(
- MDeformVert *dvert, const int defbase_tot, const bool *vgroup_validmap,
- const bool *lock_flags, const bool *lock_with_active)
-{
- /* first pass with both active and explicitly locked groups restricted from change */
-
- bool success = do_weight_paint_normalize_all_locked(dvert, defbase_tot, vgroup_validmap, lock_with_active);
-
- if (!success) {
- /**
- * Locks prevented the first pass from full completion, so remove restriction on active group; e.g:
- *
- * - With 1.0 weight painted into active:
- * nonzero locked weight; first pass zeroed out unlocked weight; scale 1 down to fit.
- * - With 0.0 weight painted into active:
- * no unlocked groups; first pass did nothing; increase 0 to fit.
- */
- do_weight_paint_normalize_all_locked(dvert, defbase_tot, vgroup_validmap, lock_flags);
- }
+static void do_weight_paint_normalize_all_locked_try_active(MDeformVert *dvert,
+ const int defbase_tot,
+ const bool *vgroup_validmap,
+ const bool *lock_flags,
+ const bool *lock_with_active)
+{
+ /* first pass with both active and explicitly locked groups restricted from change */
+
+ bool success = do_weight_paint_normalize_all_locked(
+ dvert, defbase_tot, vgroup_validmap, lock_with_active);
+
+ if (!success) {
+ /**
+ * Locks prevented the first pass from full completion, so remove restriction on active group; e.g:
+ *
+ * - With 1.0 weight painted into active:
+ * nonzero locked weight; first pass zeroed out unlocked weight; scale 1 down to fit.
+ * - With 0.0 weight painted into active:
+ * no unlocked groups; first pass did nothing; increase 0 to fit.
+ */
+ do_weight_paint_normalize_all_locked(dvert, defbase_tot, vgroup_validmap, lock_flags);
+ }
}
#if 0 /* UNUSED */
@@ -558,101 +569,108 @@ static bool has_unselected_unlocked_bone_group(
int defbase_tot, bool *defbase_sel, int selected,
const bool *lock_flags, const bool *vgroup_validmap)
{
- int i;
- if (defbase_tot == selected) {
- return false;
- }
- for (i = 0; i < defbase_tot; i++) {
- if (vgroup_validmap[i] && !defbase_sel[i] && !lock_flags[i]) {
- return true;
- }
- }
- return false;
+ int i;
+ if (defbase_tot == selected) {
+ return false;
+ }
+ for (i = 0; i < defbase_tot; i++) {
+ if (vgroup_validmap[i] && !defbase_sel[i] && !lock_flags[i]) {
+ return true;
+ }
+ }
+ return false;
}
#endif
-static void multipaint_clamp_change(
- MDeformVert *dvert, const int defbase_tot, const bool *defbase_sel,
- float *change_p)
-{
- int i;
- MDeformWeight *dw;
- float val;
- float change = *change_p;
-
- /* verify that the change does not cause values exceeding 1 and clamp it */
- for (i = dvert->totweight, dw = dvert->dw; i != 0; i--, dw++) {
- if (dw->def_nr < defbase_tot && defbase_sel[dw->def_nr]) {
- if (dw->weight) {
- val = dw->weight * change;
- if (val > 1) {
- change = 1.0f / dw->weight;
- }
- }
- }
- }
-
- *change_p = change;
-}
-
-static bool multipaint_verify_change(MDeformVert *dvert, const int defbase_tot, float change, const bool *defbase_sel)
-{
- int i;
- MDeformWeight *dw;
- float val;
-
- /* in case the change is reduced, you need to recheck
- * the earlier values to make sure they are not 0
- * (precision error) */
- for (i = dvert->totweight, dw = dvert->dw; i != 0; i--, dw++) {
- if (dw->def_nr < defbase_tot && defbase_sel[dw->def_nr]) {
- if (dw->weight) {
- val = dw->weight * change;
- /* the value should never reach zero while multi-painting if it
- * was nonzero beforehand */
- if (val <= 0) {
- return false;
- }
- }
- }
- }
-
- return true;
-}
-
-static void multipaint_apply_change(MDeformVert *dvert, const int defbase_tot, float change, const bool *defbase_sel)
-{
- int i;
- MDeformWeight *dw;
-
- /* apply the valid change */
- for (i = dvert->totweight, dw = dvert->dw; i != 0; i--, dw++) {
- if (dw->def_nr < defbase_tot && defbase_sel[dw->def_nr]) {
- if (dw->weight) {
- dw->weight = dw->weight * change;
- CLAMP(dw->weight, 0.0f, 1.0f);
- }
- }
- }
+static void multipaint_clamp_change(MDeformVert *dvert,
+ const int defbase_tot,
+ const bool *defbase_sel,
+ float *change_p)
+{
+ int i;
+ MDeformWeight *dw;
+ float val;
+ float change = *change_p;
+
+ /* verify that the change does not cause values exceeding 1 and clamp it */
+ for (i = dvert->totweight, dw = dvert->dw; i != 0; i--, dw++) {
+ if (dw->def_nr < defbase_tot && defbase_sel[dw->def_nr]) {
+ if (dw->weight) {
+ val = dw->weight * change;
+ if (val > 1) {
+ change = 1.0f / dw->weight;
+ }
+ }
+ }
+ }
+
+ *change_p = change;
+}
+
+static bool multipaint_verify_change(MDeformVert *dvert,
+ const int defbase_tot,
+ float change,
+ const bool *defbase_sel)
+{
+ int i;
+ MDeformWeight *dw;
+ float val;
+
+ /* in case the change is reduced, you need to recheck
+ * the earlier values to make sure they are not 0
+ * (precision error) */
+ for (i = dvert->totweight, dw = dvert->dw; i != 0; i--, dw++) {
+ if (dw->def_nr < defbase_tot && defbase_sel[dw->def_nr]) {
+ if (dw->weight) {
+ val = dw->weight * change;
+ /* the value should never reach zero while multi-painting if it
+ * was nonzero beforehand */
+ if (val <= 0) {
+ return false;
+ }
+ }
+ }
+ }
+
+ return true;
+}
+
+static void multipaint_apply_change(MDeformVert *dvert,
+ const int defbase_tot,
+ float change,
+ const bool *defbase_sel)
+{
+ int i;
+ MDeformWeight *dw;
+
+ /* apply the valid change */
+ for (i = dvert->totweight, dw = dvert->dw; i != 0; i--, dw++) {
+ if (dw->def_nr < defbase_tot && defbase_sel[dw->def_nr]) {
+ if (dw->weight) {
+ dw->weight = dw->weight * change;
+ CLAMP(dw->weight, 0.0f, 1.0f);
+ }
+ }
+ }
}
/**
* Variables stored both for 'active' and 'mirror' sides.
*/
struct WeightPaintGroupData {
- /** index of active group or its mirror
- *
- * - 'active' is always `ob->actdef`.
- * - 'mirror' is -1 when 'ME_EDIT_MIRROR_X' flag id disabled,
- * otherwise this will be set to the mirror or the active group (if the group isn't mirrored).
- */
- int index;
- /** lock that includes the 'index' as locked too
- *
- * - 'active' is set of locked or active/selected groups
- * - 'mirror' is set of locked or mirror groups
- */
- const bool *lock;
+ /** index of active group or its mirror
+ *
+ * - 'active' is always `ob->actdef`.
+ * - 'mirror' is -1 when 'ME_EDIT_MIRROR_X' flag id disabled,
+ * otherwise this will be set to the mirror or the active group (if the group isn't mirrored).
+ */
+ int index;
+ /** lock that includes the 'index' as locked too
+ *
+ * - 'active' is set of locked or active/selected groups
+ * - 'mirror' is set of locked or mirror groups
+ */
+ const bool *lock;
};
/* struct to avoid passing many args each call to do_weight_paint_vertex()
@@ -661,490 +679,504 @@ struct WeightPaintGroupData {
* paint stroke update - campbell */
typedef struct WeightPaintInfo {
- int defbase_tot;
+ int defbase_tot;
- /* both must add up to 'defbase_tot' */
- int defbase_tot_sel;
- int defbase_tot_unsel;
+ /* both must add up to 'defbase_tot' */
+ int defbase_tot_sel;
+ int defbase_tot_unsel;
- struct WeightPaintGroupData active, mirror;
+ struct WeightPaintGroupData active, mirror;
- /* boolean array for locked bones,
- * length of defbase_tot */
- const bool *lock_flags;
- /* boolean array for selected bones,
- * length of defbase_tot, cant be const because of how its passed */
- const bool *defbase_sel;
- /* same as WeightPaintData.vgroup_validmap,
- * only added here for convenience */
- const bool *vgroup_validmap;
+ /* boolean array for locked bones,
+ * length of defbase_tot */
+ const bool *lock_flags;
+ /* boolean array for selected bones,
+ * length of defbase_tot, cant be const because of how its passed */
+ const bool *defbase_sel;
+ /* same as WeightPaintData.vgroup_validmap,
+ * only added here for convenience */
+ const bool *vgroup_validmap;
- bool do_flip;
- bool do_multipaint;
- bool do_auto_normalize;
+ bool do_flip;
+ bool do_multipaint;
+ bool do_auto_normalize;
- float brush_alpha_value; /* result of BKE_brush_alpha_get() */
+ float brush_alpha_value; /* result of BKE_brush_alpha_get() */
} WeightPaintInfo;
static void do_weight_paint_vertex_single(
- /* vars which remain the same for every vert */
- const VPaint *wp, Object *ob, const WeightPaintInfo *wpi,
- /* vars which change on each stroke */
- const uint index, float alpha, float paintweight)
-{
- Mesh *me = ob->data;
- MDeformVert *dv = &me->dvert[index];
- bool topology = (me->editflag & ME_EDIT_MIRROR_TOPO) != 0;
-
- MDeformWeight *dw;
- float weight_prev;
-
- /* mirror vars */
- int index_mirr;
- int vgroup_mirr;
-
- MDeformVert *dv_mirr;
- MDeformWeight *dw_mirr;
-
- /* from now on we can check if mirrors enabled if this var is -1 and not bother with the flag */
- if (me->editflag & ME_EDIT_MIRROR_X) {
- index_mirr = mesh_get_x_mirror_vert(ob, NULL, index, topology);
- vgroup_mirr = wpi->mirror.index;
-
- /* another possible error - mirror group _and_ active group are the same (which is fine),
- * but we also are painting onto a center vertex - this would paint the same weight twice */
- if (index_mirr == index && vgroup_mirr == wpi->active.index) {
- index_mirr = vgroup_mirr = -1;
- }
- }
- else {
- index_mirr = vgroup_mirr = -1;
- }
-
- if (wp->flag & VP_FLAG_VGROUP_RESTRICT) {
- dw = defvert_find_index(dv, wpi->active.index);
- }
- else {
- dw = defvert_verify_index(dv, wpi->active.index);
- }
-
- if (dw == NULL) {
- return;
- }
-
- /* get the mirror def vars */
- if (index_mirr != -1) {
- dv_mirr = &me->dvert[index_mirr];
- if (wp->flag & VP_FLAG_VGROUP_RESTRICT) {
- dw_mirr = defvert_find_index(dv_mirr, vgroup_mirr);
-
- if (dw_mirr == NULL) {
- index_mirr = vgroup_mirr = -1;
- dv_mirr = NULL;
- }
- }
- else {
- if (index != index_mirr) {
- dw_mirr = defvert_verify_index(dv_mirr, vgroup_mirr);
- }
- else {
- /* dv and dv_mirr are the same */
- int totweight_prev = dv_mirr->totweight;
- int dw_offset = (int)(dw - dv_mirr->dw);
- dw_mirr = defvert_verify_index(dv_mirr, vgroup_mirr);
-
- /* if we added another, get our old one back */
- if (totweight_prev != dv_mirr->totweight) {
- dw = &dv_mirr->dw[dw_offset];
- }
- }
- }
- }
- else {
- dv_mirr = NULL;
- dw_mirr = NULL;
- }
-
- if (!brush_use_accumulate(wp)) {
- MDeformVert *dvert_prev = ob->sculpt->mode.wpaint.dvert_prev;
- MDeformVert *dv_prev = defweight_prev_init(dvert_prev, me->dvert, index);
- if (index_mirr != -1) {
- defweight_prev_init(dvert_prev, me->dvert, index_mirr);
- }
-
- weight_prev = defvert_find_weight(dv_prev, wpi->active.index);
- }
- else {
- weight_prev = dw->weight;
- }
-
- /* If there are no normalize-locks or multipaint,
- * then there is no need to run the more complicated checks */
-
- {
- float new_weight = wpaint_blend(
- wp, weight_prev, alpha, paintweight,
- wpi->brush_alpha_value, wpi->do_flip);
-
- dw->weight = wpaint_clamp_monotonic(weight_prev, dw->weight, new_weight);
-
- /* WATCH IT: take care of the ordering of applying mirror -> normalize,
- * can give wrong results [#26193], least confusing if normalize is done last */
-
- /* apply mirror */
- if (index_mirr != -1) {
- /* copy, not paint again */
- dw_mirr->weight = dw->weight;
- }
-
- /* apply normalize */
- if (wpi->do_auto_normalize) {
- /* note on normalize - this used to be applied after painting and normalize all weights,
- * in some ways this is good because there is feedback where the more weights involved would
- * 'resist' so you couldn't instantly zero out other weights by painting 1.0 on the active.
- *
- * However this gave a problem since applying mirror, then normalize both verts
- * the resulting weight wont match on both sides.
- *
- * If this 'resisting', slower normalize is nicer, we could call
- * do_weight_paint_normalize_all() and only use...
- * do_weight_paint_normalize_all_active() when normalizing the mirror vertex.
- * - campbell
- */
- do_weight_paint_normalize_all_locked_try_active(
- dv, wpi->defbase_tot, wpi->vgroup_validmap, wpi->lock_flags, wpi->active.lock);
-
- if (index_mirr != -1) {
- /* only normalize if this is not a center vertex,
- * else we get a conflict, normalizing twice */
- if (index != index_mirr) {
- do_weight_paint_normalize_all_locked_try_active(
- dv_mirr, wpi->defbase_tot, wpi->vgroup_validmap, wpi->lock_flags, wpi->mirror.lock);
- }
- else {
- /* this case accounts for...
- * - painting onto a center vertex of a mesh
- * - x mirror is enabled
- * - auto normalize is enabled
- * - the group you are painting onto has a L / R version
- *
- * We want L/R vgroups to have the same weight but this cant be if both are over 0.5,
- * We _could_ have special check for that, but this would need its own normalize function which
- * holds 2 groups from changing at once.
- *
- * So! just balance out the 2 weights, it keeps them equal and everything normalized.
- *
- * While it wont hit the desired weight immediately as the user waggles their mouse,
- * constant painting and re-normalizing will get there. this is also just simpler logic.
- * - campbell */
- dw_mirr->weight = dw->weight = (dw_mirr->weight + dw->weight) * 0.5f;
- }
- }
- }
- }
+ /* vars which remain the same for every vert */
+ const VPaint *wp,
+ Object *ob,
+ const WeightPaintInfo *wpi,
+ /* vars which change on each stroke */
+ const uint index,
+ float alpha,
+ float paintweight)
+{
+ Mesh *me = ob->data;
+ MDeformVert *dv = &me->dvert[index];
+ bool topology = (me->editflag & ME_EDIT_MIRROR_TOPO) != 0;
+
+ MDeformWeight *dw;
+ float weight_prev;
+
+ /* mirror vars */
+ int index_mirr;
+ int vgroup_mirr;
+
+ MDeformVert *dv_mirr;
+ MDeformWeight *dw_mirr;
+
+ /* from now on we can check if mirrors enabled if this var is -1 and not bother with the flag */
+ if (me->editflag & ME_EDIT_MIRROR_X) {
+ index_mirr = mesh_get_x_mirror_vert(ob, NULL, index, topology);
+ vgroup_mirr = wpi->mirror.index;
+
+ /* another possible error - mirror group _and_ active group are the same (which is fine),
+ * but we also are painting onto a center vertex - this would paint the same weight twice */
+ if (index_mirr == index && vgroup_mirr == wpi->active.index) {
+ index_mirr = vgroup_mirr = -1;
+ }
+ }
+ else {
+ index_mirr = vgroup_mirr = -1;
+ }
+
+ if (wp->flag & VP_FLAG_VGROUP_RESTRICT) {
+ dw = defvert_find_index(dv, wpi->active.index);
+ }
+ else {
+ dw = defvert_verify_index(dv, wpi->active.index);
+ }
+
+ if (dw == NULL) {
+ return;
+ }
+
+ /* get the mirror def vars */
+ if (index_mirr != -1) {
+ dv_mirr = &me->dvert[index_mirr];
+ if (wp->flag & VP_FLAG_VGROUP_RESTRICT) {
+ dw_mirr = defvert_find_index(dv_mirr, vgroup_mirr);
+
+ if (dw_mirr == NULL) {
+ index_mirr = vgroup_mirr = -1;
+ dv_mirr = NULL;
+ }
+ }
+ else {
+ if (index != index_mirr) {
+ dw_mirr = defvert_verify_index(dv_mirr, vgroup_mirr);
+ }
+ else {
+ /* dv and dv_mirr are the same */
+ int totweight_prev = dv_mirr->totweight;
+ int dw_offset = (int)(dw - dv_mirr->dw);
+ dw_mirr = defvert_verify_index(dv_mirr, vgroup_mirr);
+
+ /* if we added another, get our old one back */
+ if (totweight_prev != dv_mirr->totweight) {
+ dw = &dv_mirr->dw[dw_offset];
+ }
+ }
+ }
+ }
+ else {
+ dv_mirr = NULL;
+ dw_mirr = NULL;
+ }
+
+ if (!brush_use_accumulate(wp)) {
+ MDeformVert *dvert_prev = ob->sculpt->mode.wpaint.dvert_prev;
+ MDeformVert *dv_prev = defweight_prev_init(dvert_prev, me->dvert, index);
+ if (index_mirr != -1) {
+ defweight_prev_init(dvert_prev, me->dvert, index_mirr);
+ }
+
+ weight_prev = defvert_find_weight(dv_prev, wpi->active.index);
+ }
+ else {
+ weight_prev = dw->weight;
+ }
+
+ /* If there are no normalize-locks or multipaint,
+ * then there is no need to run the more complicated checks */
+
+ {
+ float new_weight = wpaint_blend(
+ wp, weight_prev, alpha, paintweight, wpi->brush_alpha_value, wpi->do_flip);
+
+ dw->weight = wpaint_clamp_monotonic(weight_prev, dw->weight, new_weight);
+
+ /* WATCH IT: take care of the ordering of applying mirror -> normalize,
+ * can give wrong results [#26193], least confusing if normalize is done last */
+
+ /* apply mirror */
+ if (index_mirr != -1) {
+ /* copy, not paint again */
+ dw_mirr->weight = dw->weight;
+ }
+
+ /* apply normalize */
+ if (wpi->do_auto_normalize) {
+ /* note on normalize - this used to be applied after painting and normalize all weights,
+ * in some ways this is good because there is feedback where the more weights involved would
+ * 'resist' so you couldn't instantly zero out other weights by painting 1.0 on the active.
+ *
+ * However this gave a problem since applying mirror, then normalize both verts
+ * the resulting weight wont match on both sides.
+ *
+ * If this 'resisting', slower normalize is nicer, we could call
+ * do_weight_paint_normalize_all() and only use...
+ * do_weight_paint_normalize_all_active() when normalizing the mirror vertex.
+ * - campbell
+ */
+ do_weight_paint_normalize_all_locked_try_active(
+ dv, wpi->defbase_tot, wpi->vgroup_validmap, wpi->lock_flags, wpi->active.lock);
+
+ if (index_mirr != -1) {
+ /* only normalize if this is not a center vertex,
+ * else we get a conflict, normalizing twice */
+ if (index != index_mirr) {
+ do_weight_paint_normalize_all_locked_try_active(
+ dv_mirr, wpi->defbase_tot, wpi->vgroup_validmap, wpi->lock_flags, wpi->mirror.lock);
+ }
+ else {
+ /* this case accounts for...
+ * - painting onto a center vertex of a mesh
+ * - x mirror is enabled
+ * - auto normalize is enabled
+ * - the group you are painting onto has a L / R version
+ *
+ * We want L/R vgroups to have the same weight but this cant be if both are over 0.5,
+ * We _could_ have special check for that, but this would need its own normalize function which
+ * holds 2 groups from changing at once.
+ *
+ * So! just balance out the 2 weights, it keeps them equal and everything normalized.
+ *
+ * While it wont hit the desired weight immediately as the user waggles their mouse,
+ * constant painting and re-normalizing will get there. this is also just simpler logic.
+ * - campbell */
+ dw_mirr->weight = dw->weight = (dw_mirr->weight + dw->weight) * 0.5f;
+ }
+ }
+ }
+ }
}
static void do_weight_paint_vertex_multi(
- /* vars which remain the same for every vert */
- const VPaint *wp, Object *ob, const WeightPaintInfo *wpi,
- /* vars which change on each stroke */
- const uint index, float alpha, float paintweight)
-{
- Mesh *me = ob->data;
- MDeformVert *dv = &me->dvert[index];
- bool topology = (me->editflag & ME_EDIT_MIRROR_TOPO) != 0;
-
- /* mirror vars */
- int index_mirr = -1;
- MDeformVert *dv_mirr = NULL;
-
- /* weights */
- float curw, oldw, neww, change, curw_mirr, change_mirr;
-
- /* from now on we can check if mirrors enabled if this var is -1 and not bother with the flag */
- if (me->editflag & ME_EDIT_MIRROR_X) {
- index_mirr = mesh_get_x_mirror_vert(ob, NULL, index, topology);
-
- if (index_mirr != -1 && index_mirr != index) {
- dv_mirr = &me->dvert[index_mirr];
- }
- else {
- index_mirr = -1;
- }
- }
-
- /* compute weight change by applying the brush to average or sum of group weights */
- curw = BKE_defvert_multipaint_collective_weight(
- dv, wpi->defbase_tot, wpi->defbase_sel, wpi->defbase_tot_sel, wpi->do_auto_normalize);
-
- if (curw == 0.0f) {
- /* note: no weight to assign to this vertex, could add all groups? */
- return;
- }
-
- if (!brush_use_accumulate(wp)) {
- MDeformVert *dvert_prev = ob->sculpt->mode.wpaint.dvert_prev;
- MDeformVert *dv_prev = defweight_prev_init(dvert_prev, me->dvert, index);
- if (index_mirr != -1) {
- defweight_prev_init(dvert_prev, me->dvert, index_mirr);
- }
-
- oldw = BKE_defvert_multipaint_collective_weight(
- dv_prev, wpi->defbase_tot, wpi->defbase_sel, wpi->defbase_tot_sel, wpi->do_auto_normalize);
- }
- else {
- oldw = curw;
- }
-
- neww = wpaint_blend(wp, oldw, alpha, paintweight, wpi->brush_alpha_value, wpi->do_flip);
- neww = wpaint_clamp_monotonic(oldw, curw, neww);
-
- change = neww / curw;
-
- /* verify for all groups that 0 < result <= 1 */
- multipaint_clamp_change(dv, wpi->defbase_tot, wpi->defbase_sel, &change);
-
- if (dv_mirr != NULL) {
- curw_mirr = BKE_defvert_multipaint_collective_weight(
- dv_mirr, wpi->defbase_tot, wpi->defbase_sel, wpi->defbase_tot_sel, wpi->do_auto_normalize);
-
- if (curw_mirr == 0.0f) {
- /* can't mirror into a zero weight vertex */
- dv_mirr = NULL;
- }
- else {
- /* mirror is changed to achieve the same collective weight value */
- float orig = change_mirr = curw * change / curw_mirr;
-
- multipaint_clamp_change(dv_mirr, wpi->defbase_tot, wpi->defbase_sel, &change_mirr);
-
- if (!multipaint_verify_change(dv_mirr, wpi->defbase_tot, change_mirr, wpi->defbase_sel)) {
- return;
- }
-
- change *= change_mirr / orig;
- }
- }
-
- if (!multipaint_verify_change(dv, wpi->defbase_tot, change, wpi->defbase_sel)) {
- return;
- }
-
- /* apply validated change to vertex and mirror */
- multipaint_apply_change(dv, wpi->defbase_tot, change, wpi->defbase_sel);
-
- if (dv_mirr != NULL) {
- multipaint_apply_change(dv_mirr, wpi->defbase_tot, change_mirr, wpi->defbase_sel);
- }
-
- /* normalize */
- if (wpi->do_auto_normalize) {
- do_weight_paint_normalize_all_locked_try_active(
- dv, wpi->defbase_tot, wpi->vgroup_validmap, wpi->lock_flags, wpi->active.lock);
-
- if (dv_mirr != NULL) {
- do_weight_paint_normalize_all_locked_try_active(
- dv_mirr, wpi->defbase_tot, wpi->vgroup_validmap, wpi->lock_flags, wpi->active.lock);
- }
- }
+ /* vars which remain the same for every vert */
+ const VPaint *wp,
+ Object *ob,
+ const WeightPaintInfo *wpi,
+ /* vars which change on each stroke */
+ const uint index,
+ float alpha,
+ float paintweight)
+{
+ Mesh *me = ob->data;
+ MDeformVert *dv = &me->dvert[index];
+ bool topology = (me->editflag & ME_EDIT_MIRROR_TOPO) != 0;
+
+ /* mirror vars */
+ int index_mirr = -1;
+ MDeformVert *dv_mirr = NULL;
+
+ /* weights */
+ float curw, oldw, neww, change, curw_mirr, change_mirr;
+
+ /* from now on we can check if mirrors enabled if this var is -1 and not bother with the flag */
+ if (me->editflag & ME_EDIT_MIRROR_X) {
+ index_mirr = mesh_get_x_mirror_vert(ob, NULL, index, topology);
+
+ if (index_mirr != -1 && index_mirr != index) {
+ dv_mirr = &me->dvert[index_mirr];
+ }
+ else {
+ index_mirr = -1;
+ }
+ }
+
+ /* compute weight change by applying the brush to average or sum of group weights */
+ curw = BKE_defvert_multipaint_collective_weight(
+ dv, wpi->defbase_tot, wpi->defbase_sel, wpi->defbase_tot_sel, wpi->do_auto_normalize);
+
+ if (curw == 0.0f) {
+ /* note: no weight to assign to this vertex, could add all groups? */
+ return;
+ }
+
+ if (!brush_use_accumulate(wp)) {
+ MDeformVert *dvert_prev = ob->sculpt->mode.wpaint.dvert_prev;
+ MDeformVert *dv_prev = defweight_prev_init(dvert_prev, me->dvert, index);
+ if (index_mirr != -1) {
+ defweight_prev_init(dvert_prev, me->dvert, index_mirr);
+ }
+
+ oldw = BKE_defvert_multipaint_collective_weight(
+ dv_prev, wpi->defbase_tot, wpi->defbase_sel, wpi->defbase_tot_sel, wpi->do_auto_normalize);
+ }
+ else {
+ oldw = curw;
+ }
+
+ neww = wpaint_blend(wp, oldw, alpha, paintweight, wpi->brush_alpha_value, wpi->do_flip);
+ neww = wpaint_clamp_monotonic(oldw, curw, neww);
+
+ change = neww / curw;
+
+ /* verify for all groups that 0 < result <= 1 */
+ multipaint_clamp_change(dv, wpi->defbase_tot, wpi->defbase_sel, &change);
+
+ if (dv_mirr != NULL) {
+ curw_mirr = BKE_defvert_multipaint_collective_weight(
+ dv_mirr, wpi->defbase_tot, wpi->defbase_sel, wpi->defbase_tot_sel, wpi->do_auto_normalize);
+
+ if (curw_mirr == 0.0f) {
+ /* can't mirror into a zero weight vertex */
+ dv_mirr = NULL;
+ }
+ else {
+ /* mirror is changed to achieve the same collective weight value */
+ float orig = change_mirr = curw * change / curw_mirr;
+
+ multipaint_clamp_change(dv_mirr, wpi->defbase_tot, wpi->defbase_sel, &change_mirr);
+
+ if (!multipaint_verify_change(dv_mirr, wpi->defbase_tot, change_mirr, wpi->defbase_sel)) {
+ return;
+ }
+
+ change *= change_mirr / orig;
+ }
+ }
+
+ if (!multipaint_verify_change(dv, wpi->defbase_tot, change, wpi->defbase_sel)) {
+ return;
+ }
+
+ /* apply validated change to vertex and mirror */
+ multipaint_apply_change(dv, wpi->defbase_tot, change, wpi->defbase_sel);
+
+ if (dv_mirr != NULL) {
+ multipaint_apply_change(dv_mirr, wpi->defbase_tot, change_mirr, wpi->defbase_sel);
+ }
+
+ /* normalize */
+ if (wpi->do_auto_normalize) {
+ do_weight_paint_normalize_all_locked_try_active(
+ dv, wpi->defbase_tot, wpi->vgroup_validmap, wpi->lock_flags, wpi->active.lock);
+
+ if (dv_mirr != NULL) {
+ do_weight_paint_normalize_all_locked_try_active(
+ dv_mirr, wpi->defbase_tot, wpi->vgroup_validmap, wpi->lock_flags, wpi->active.lock);
+ }
+ }
}
static void do_weight_paint_vertex(
- /* vars which remain the same for every vert */
- const VPaint *wp, Object *ob, const WeightPaintInfo *wpi,
- /* vars which change on each stroke */
- const uint index, float alpha, float paintweight)
-{
- if (wpi->do_multipaint) {
- do_weight_paint_vertex_multi(wp, ob, wpi, index, alpha, paintweight);
- }
- else {
- do_weight_paint_vertex_single(wp, ob, wpi, index, alpha, paintweight);
- }
+ /* vars which remain the same for every vert */
+ const VPaint *wp,
+ Object *ob,
+ const WeightPaintInfo *wpi,
+ /* vars which change on each stroke */
+ const uint index,
+ float alpha,
+ float paintweight)
+{
+ if (wpi->do_multipaint) {
+ do_weight_paint_vertex_multi(wp, ob, wpi, index, alpha, paintweight);
+ }
+ else {
+ do_weight_paint_vertex_single(wp, ob, wpi, index, alpha, paintweight);
+ }
}
-
/* Toggle operator for turning vertex paint mode on or off (copied from sculpt.c) */
-static void vertex_paint_init_session(Depsgraph *depsgraph, Scene *scene, Object *ob, eObjectMode object_mode)
+static void vertex_paint_init_session(Depsgraph *depsgraph,
+ Scene *scene,
+ Object *ob,
+ eObjectMode object_mode)
{
- /* Create persistent sculpt mode data */
- BKE_sculpt_toolsettings_data_ensure(scene);
+ /* Create persistent sculpt mode data */
+ BKE_sculpt_toolsettings_data_ensure(scene);
- BLI_assert(ob->sculpt == NULL);
- ob->sculpt = MEM_callocN(sizeof(SculptSession), "sculpt session");
- ob->sculpt->mode_type = object_mode;
- BKE_sculpt_update_mesh_elements(depsgraph, scene, scene->toolsettings->sculpt, ob, false, false);
+ BLI_assert(ob->sculpt == NULL);
+ ob->sculpt = MEM_callocN(sizeof(SculptSession), "sculpt session");
+ ob->sculpt->mode_type = object_mode;
+ BKE_sculpt_update_mesh_elements(depsgraph, scene, scene->toolsettings->sculpt, ob, false, false);
}
static void vertex_paint_init_stroke(Depsgraph *depsgraph, Scene *scene, Object *ob)
{
- BKE_sculpt_update_mesh_elements(depsgraph, scene, scene->toolsettings->sculpt, ob, false, false);
+ BKE_sculpt_update_mesh_elements(depsgraph, scene, scene->toolsettings->sculpt, ob, false, false);
}
static void vertex_paint_init_session_data(const ToolSettings *ts, Object *ob)
{
- /* Create maps */
- struct SculptVertexPaintGeomMap *gmap = NULL;
- if (ob->mode == OB_MODE_VERTEX_PAINT) {
- gmap = &ob->sculpt->mode.vpaint.gmap;
- BLI_assert(ob->sculpt->mode_type == OB_MODE_VERTEX_PAINT);
- }
- else if (ob->mode == OB_MODE_WEIGHT_PAINT) {
- gmap = &ob->sculpt->mode.wpaint.gmap;
- BLI_assert(ob->sculpt->mode_type == OB_MODE_WEIGHT_PAINT);
- }
- else {
- ob->sculpt->mode_type = 0;
- BLI_assert(0);
- return;
- }
-
- Mesh *me = ob->data;
-
- if (gmap->vert_to_loop == NULL) {
- gmap->vert_map_mem = NULL;
- gmap->vert_to_loop = NULL;
- gmap->poly_map_mem = NULL;
- gmap->vert_to_poly = NULL;
- BKE_mesh_vert_loop_map_create(
- &gmap->vert_to_loop,
- &gmap->vert_map_mem,
- me->mpoly, me->mloop, me->totvert, me->totpoly, me->totloop);
- BKE_mesh_vert_poly_map_create(
- &gmap->vert_to_poly,
- &gmap->poly_map_mem,
- me->mpoly, me->mloop, me->totvert, me->totpoly, me->totloop);
- }
-
- /* Create average brush arrays */
- if (ob->mode == OB_MODE_VERTEX_PAINT) {
- if (!brush_use_accumulate(ts->vpaint)) {
- if (ob->sculpt->mode.vpaint.previous_color == NULL) {
- ob->sculpt->mode.vpaint.previous_color =
- MEM_callocN(me->totloop * sizeof(uint), __func__);
- }
- }
- else {
- MEM_SAFE_FREE(ob->sculpt->mode.vpaint.previous_color);
- }
- }
- else if (ob->mode == OB_MODE_WEIGHT_PAINT) {
- if (!brush_use_accumulate(ts->wpaint)) {
- if (ob->sculpt->mode.wpaint.alpha_weight == NULL) {
- ob->sculpt->mode.wpaint.alpha_weight =
- MEM_callocN(me->totvert * sizeof(float), __func__);
- }
- if (ob->sculpt->mode.wpaint.dvert_prev == NULL) {
- ob->sculpt->mode.wpaint.dvert_prev =
- MEM_callocN(me->totvert * sizeof(MDeformVert), __func__);
- MDeformVert *dv = ob->sculpt->mode.wpaint.dvert_prev;
- for (int i = 0; i < me->totvert; i++, dv++) {
- /* Use to show this isn't initialized, never apply to the mesh data. */
- dv->flag = 1;
- }
- }
- }
- else {
- MEM_SAFE_FREE(ob->sculpt->mode.wpaint.alpha_weight);
- if (ob->sculpt->mode.wpaint.dvert_prev != NULL) {
- BKE_defvert_array_free_elems(ob->sculpt->mode.wpaint.dvert_prev, me->totvert);
- MEM_freeN(ob->sculpt->mode.wpaint.dvert_prev);
- ob->sculpt->mode.wpaint.dvert_prev = NULL;
- }
- }
- }
-
+ /* Create maps */
+ struct SculptVertexPaintGeomMap *gmap = NULL;
+ if (ob->mode == OB_MODE_VERTEX_PAINT) {
+ gmap = &ob->sculpt->mode.vpaint.gmap;
+ BLI_assert(ob->sculpt->mode_type == OB_MODE_VERTEX_PAINT);
+ }
+ else if (ob->mode == OB_MODE_WEIGHT_PAINT) {
+ gmap = &ob->sculpt->mode.wpaint.gmap;
+ BLI_assert(ob->sculpt->mode_type == OB_MODE_WEIGHT_PAINT);
+ }
+ else {
+ ob->sculpt->mode_type = 0;
+ BLI_assert(0);
+ return;
+ }
+
+ Mesh *me = ob->data;
+
+ if (gmap->vert_to_loop == NULL) {
+ gmap->vert_map_mem = NULL;
+ gmap->vert_to_loop = NULL;
+ gmap->poly_map_mem = NULL;
+ gmap->vert_to_poly = NULL;
+ BKE_mesh_vert_loop_map_create(&gmap->vert_to_loop,
+ &gmap->vert_map_mem,
+ me->mpoly,
+ me->mloop,
+ me->totvert,
+ me->totpoly,
+ me->totloop);
+ BKE_mesh_vert_poly_map_create(&gmap->vert_to_poly,
+ &gmap->poly_map_mem,
+ me->mpoly,
+ me->mloop,
+ me->totvert,
+ me->totpoly,
+ me->totloop);
+ }
+
+ /* Create average brush arrays */
+ if (ob->mode == OB_MODE_VERTEX_PAINT) {
+ if (!brush_use_accumulate(ts->vpaint)) {
+ if (ob->sculpt->mode.vpaint.previous_color == NULL) {
+ ob->sculpt->mode.vpaint.previous_color = MEM_callocN(me->totloop * sizeof(uint), __func__);
+ }
+ }
+ else {
+ MEM_SAFE_FREE(ob->sculpt->mode.vpaint.previous_color);
+ }
+ }
+ else if (ob->mode == OB_MODE_WEIGHT_PAINT) {
+ if (!brush_use_accumulate(ts->wpaint)) {
+ if (ob->sculpt->mode.wpaint.alpha_weight == NULL) {
+ ob->sculpt->mode.wpaint.alpha_weight = MEM_callocN(me->totvert * sizeof(float), __func__);
+ }
+ if (ob->sculpt->mode.wpaint.dvert_prev == NULL) {
+ ob->sculpt->mode.wpaint.dvert_prev = MEM_callocN(me->totvert * sizeof(MDeformVert),
+ __func__);
+ MDeformVert *dv = ob->sculpt->mode.wpaint.dvert_prev;
+ for (int i = 0; i < me->totvert; i++, dv++) {
+ /* Use to show this isn't initialized, never apply to the mesh data. */
+ dv->flag = 1;
+ }
+ }
+ }
+ else {
+ MEM_SAFE_FREE(ob->sculpt->mode.wpaint.alpha_weight);
+ if (ob->sculpt->mode.wpaint.dvert_prev != NULL) {
+ BKE_defvert_array_free_elems(ob->sculpt->mode.wpaint.dvert_prev, me->totvert);
+ MEM_freeN(ob->sculpt->mode.wpaint.dvert_prev);
+ ob->sculpt->mode.wpaint.dvert_prev = NULL;
+ }
+ }
+ }
}
/* -------------------------------------------------------------------- */
/** \name Enter Vertex/Weight Paint Mode
* \{ */
-static void ed_vwpaintmode_enter_generic(
- Main *bmain, Depsgraph *depsgraph,
- wmWindowManager *wm, Scene *scene,
- Object *ob, const eObjectMode mode_flag)
-{
- ob->mode |= mode_flag;
- Mesh *me = BKE_mesh_from_object(ob);
-
- /* Same as sculpt mode, make sure we don't have cached derived mesh which
- * points to freed arrays.
- */
- BKE_object_free_derived_caches(ob);
-
- if (mode_flag == OB_MODE_VERTEX_PAINT) {
- const ePaintMode paint_mode = PAINT_MODE_VERTEX;
- ED_mesh_color_ensure(me, NULL);
-
- BKE_paint_ensure(scene->toolsettings, (Paint **)&scene->toolsettings->vpaint);
- Paint *paint = BKE_paint_get_active_from_paintmode(scene, paint_mode);
- paint_cursor_start_explicit(paint, wm, vertex_paint_poll);
- BKE_paint_init(bmain, scene, paint_mode, PAINT_CURSOR_VERTEX_PAINT);
- }
- else if (mode_flag == OB_MODE_WEIGHT_PAINT) {
- const ePaintMode paint_mode = PAINT_MODE_WEIGHT;
-
- BKE_paint_ensure(scene->toolsettings, (Paint **)&scene->toolsettings->wpaint);
- Paint *paint = BKE_paint_get_active_from_paintmode(scene, paint_mode);
- paint_cursor_start_explicit(paint, wm, weight_paint_poll);
- BKE_paint_init(bmain, scene, paint_mode, PAINT_CURSOR_WEIGHT_PAINT);
-
- /* weight paint specific */
- ED_mesh_mirror_spatial_table(ob, NULL, NULL, NULL, 's');
- ED_vgroup_sync_from_pose(ob);
- }
- else {
- BLI_assert(0);
- }
-
- /* Create vertex/weight paint mode session data */
- if (ob->sculpt) {
- if (ob->sculpt->cache) {
- sculpt_cache_free(ob->sculpt->cache);
- ob->sculpt->cache = NULL;
- }
- BKE_sculptsession_free(ob);
- }
-
- vertex_paint_init_session(depsgraph, scene, ob, mode_flag);
-
- /* Flush object mode. */
- DEG_id_tag_update(&ob->id, ID_RECALC_COPY_ON_WRITE);
+static void ed_vwpaintmode_enter_generic(Main *bmain,
+ Depsgraph *depsgraph,
+ wmWindowManager *wm,
+ Scene *scene,
+ Object *ob,
+ const eObjectMode mode_flag)
+{
+ ob->mode |= mode_flag;
+ Mesh *me = BKE_mesh_from_object(ob);
+
+ /* Same as sculpt mode, make sure we don't have cached derived mesh which
+ * points to freed arrays.
+ */
+ BKE_object_free_derived_caches(ob);
+
+ if (mode_flag == OB_MODE_VERTEX_PAINT) {
+ const ePaintMode paint_mode = PAINT_MODE_VERTEX;
+ ED_mesh_color_ensure(me, NULL);
+
+ BKE_paint_ensure(scene->toolsettings, (Paint **)&scene->toolsettings->vpaint);
+ Paint *paint = BKE_paint_get_active_from_paintmode(scene, paint_mode);
+ paint_cursor_start_explicit(paint, wm, vertex_paint_poll);
+ BKE_paint_init(bmain, scene, paint_mode, PAINT_CURSOR_VERTEX_PAINT);
+ }
+ else if (mode_flag == OB_MODE_WEIGHT_PAINT) {
+ const ePaintMode paint_mode = PAINT_MODE_WEIGHT;
+
+ BKE_paint_ensure(scene->toolsettings, (Paint **)&scene->toolsettings->wpaint);
+ Paint *paint = BKE_paint_get_active_from_paintmode(scene, paint_mode);
+ paint_cursor_start_explicit(paint, wm, weight_paint_poll);
+ BKE_paint_init(bmain, scene, paint_mode, PAINT_CURSOR_WEIGHT_PAINT);
+
+ /* weight paint specific */
+ ED_mesh_mirror_spatial_table(ob, NULL, NULL, NULL, 's');
+ ED_vgroup_sync_from_pose(ob);
+ }
+ else {
+ BLI_assert(0);
+ }
+
+ /* Create vertex/weight paint mode session data */
+ if (ob->sculpt) {
+ if (ob->sculpt->cache) {
+ sculpt_cache_free(ob->sculpt->cache);
+ ob->sculpt->cache = NULL;
+ }
+ BKE_sculptsession_free(ob);
+ }
+
+ vertex_paint_init_session(depsgraph, scene, ob, mode_flag);
+
+ /* Flush object mode. */
+ DEG_id_tag_update(&ob->id, ID_RECALC_COPY_ON_WRITE);
}
void ED_object_vpaintmode_enter_ex(
- Main *bmain, Depsgraph *depsgraph, wmWindowManager *wm,
- Scene *scene, Object *ob)
+ Main *bmain, Depsgraph *depsgraph, wmWindowManager *wm, Scene *scene, Object *ob)
{
- ed_vwpaintmode_enter_generic(
- bmain, depsgraph, wm, scene, ob, OB_MODE_VERTEX_PAINT);
+ ed_vwpaintmode_enter_generic(bmain, depsgraph, wm, scene, ob, OB_MODE_VERTEX_PAINT);
}
void ED_object_vpaintmode_enter(struct bContext *C)
{
- Main *bmain = CTX_data_main(C);
- Depsgraph *depsgraph = CTX_data_depsgraph(C);
- wmWindowManager *wm = CTX_wm_manager(C);
- Scene *scene = CTX_data_scene(C);
- Object *ob = CTX_data_active_object(C);
- ED_object_vpaintmode_enter_ex(bmain, depsgraph, wm, scene, ob);
+ Main *bmain = CTX_data_main(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ wmWindowManager *wm = CTX_wm_manager(C);
+ Scene *scene = CTX_data_scene(C);
+ Object *ob = CTX_data_active_object(C);
+ ED_object_vpaintmode_enter_ex(bmain, depsgraph, wm, scene, ob);
}
void ED_object_wpaintmode_enter_ex(
- Main *bmain, Depsgraph *depsgraph, wmWindowManager *wm,
- Scene *scene, Object *ob)
+ Main *bmain, Depsgraph *depsgraph, wmWindowManager *wm, Scene *scene, Object *ob)
{
- ed_vwpaintmode_enter_generic(
- bmain, depsgraph, wm, scene, ob, OB_MODE_WEIGHT_PAINT);
+ ed_vwpaintmode_enter_generic(bmain, depsgraph, wm, scene, ob, OB_MODE_WEIGHT_PAINT);
}
void ED_object_wpaintmode_enter(struct bContext *C)
{
- Main *bmain = CTX_data_main(C);
- Depsgraph *depsgraph = CTX_data_depsgraph(C);
- wmWindowManager *wm = CTX_wm_manager(C);
- Scene *scene = CTX_data_scene(C);
- Object *ob = CTX_data_active_object(C);
- ED_object_wpaintmode_enter_ex(bmain, depsgraph, wm, scene, ob);
+ Main *bmain = CTX_data_main(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ wmWindowManager *wm = CTX_wm_manager(C);
+ Scene *scene = CTX_data_scene(C);
+ Object *ob = CTX_data_active_object(C);
+ ED_object_wpaintmode_enter_ex(bmain, depsgraph, wm, scene, ob);
}
/** \} */
@@ -1153,72 +1185,71 @@ void ED_object_wpaintmode_enter(struct bContext *C)
/** \name Exit Vertex/Weight Paint Mode
* \{ */
-static void ed_vwpaintmode_exit_generic(
- Object *ob, const eObjectMode mode_flag)
-{
- Mesh *me = BKE_mesh_from_object(ob);
- ob->mode &= ~mode_flag;
-
- if (mode_flag == OB_MODE_VERTEX_PAINT) {
- if (me->editflag & ME_EDIT_PAINT_FACE_SEL) {
- BKE_mesh_flush_select_from_polys(me);
- }
- else if (me->editflag & ME_EDIT_PAINT_VERT_SEL) {
- BKE_mesh_flush_select_from_verts(me);
- }
- }
- else if (mode_flag == OB_MODE_WEIGHT_PAINT) {
- if (me->editflag & ME_EDIT_PAINT_VERT_SEL) {
- BKE_mesh_flush_select_from_verts(me);
- }
- else if (me->editflag & ME_EDIT_PAINT_FACE_SEL) {
- BKE_mesh_flush_select_from_polys(me);
- }
- }
- else {
- BLI_assert(0);
- }
-
- /* If the cache is not released by a cancel or a done, free it now. */
- if (ob->sculpt && ob->sculpt->cache) {
- sculpt_cache_free(ob->sculpt->cache);
- ob->sculpt->cache = NULL;
- }
-
- BKE_sculptsession_free(ob);
-
- paint_cursor_delete_textures();
-
- if (mode_flag == OB_MODE_WEIGHT_PAINT) {
- ED_mesh_mirror_spatial_table(NULL, NULL, NULL, NULL, 'e');
- ED_mesh_mirror_topo_table(NULL, NULL, 'e');
- }
-
- /* Never leave derived meshes behind. */
- BKE_object_free_derived_caches(ob);
-
- /* Flush object mode. */
- DEG_id_tag_update(&ob->id, ID_RECALC_COPY_ON_WRITE);
+static void ed_vwpaintmode_exit_generic(Object *ob, const eObjectMode mode_flag)
+{
+ Mesh *me = BKE_mesh_from_object(ob);
+ ob->mode &= ~mode_flag;
+
+ if (mode_flag == OB_MODE_VERTEX_PAINT) {
+ if (me->editflag & ME_EDIT_PAINT_FACE_SEL) {
+ BKE_mesh_flush_select_from_polys(me);
+ }
+ else if (me->editflag & ME_EDIT_PAINT_VERT_SEL) {
+ BKE_mesh_flush_select_from_verts(me);
+ }
+ }
+ else if (mode_flag == OB_MODE_WEIGHT_PAINT) {
+ if (me->editflag & ME_EDIT_PAINT_VERT_SEL) {
+ BKE_mesh_flush_select_from_verts(me);
+ }
+ else if (me->editflag & ME_EDIT_PAINT_FACE_SEL) {
+ BKE_mesh_flush_select_from_polys(me);
+ }
+ }
+ else {
+ BLI_assert(0);
+ }
+
+ /* If the cache is not released by a cancel or a done, free it now. */
+ if (ob->sculpt && ob->sculpt->cache) {
+ sculpt_cache_free(ob->sculpt->cache);
+ ob->sculpt->cache = NULL;
+ }
+
+ BKE_sculptsession_free(ob);
+
+ paint_cursor_delete_textures();
+
+ if (mode_flag == OB_MODE_WEIGHT_PAINT) {
+ ED_mesh_mirror_spatial_table(NULL, NULL, NULL, NULL, 'e');
+ ED_mesh_mirror_topo_table(NULL, NULL, 'e');
+ }
+
+ /* Never leave derived meshes behind. */
+ BKE_object_free_derived_caches(ob);
+
+ /* Flush object mode. */
+ DEG_id_tag_update(&ob->id, ID_RECALC_COPY_ON_WRITE);
}
void ED_object_vpaintmode_exit_ex(Object *ob)
{
- ed_vwpaintmode_exit_generic(ob, OB_MODE_VERTEX_PAINT);
+ ed_vwpaintmode_exit_generic(ob, OB_MODE_VERTEX_PAINT);
}
void ED_object_vpaintmode_exit(struct bContext *C)
{
- Object *ob = CTX_data_active_object(C);
- ED_object_vpaintmode_exit_ex(ob);
+ Object *ob = CTX_data_active_object(C);
+ ED_object_vpaintmode_exit_ex(ob);
}
void ED_object_wpaintmode_exit_ex(Object *ob)
{
- ed_vwpaintmode_exit_generic(ob, OB_MODE_WEIGHT_PAINT);
+ ed_vwpaintmode_exit_generic(ob, OB_MODE_WEIGHT_PAINT);
}
void ED_object_wpaintmode_exit(struct bContext *C)
{
- Object *ob = CTX_data_active_object(C);
- ED_object_wpaintmode_exit_ex(ob);
+ Object *ob = CTX_data_active_object(C);
+ ED_object_wpaintmode_exit_ex(ob);
}
/** \} */
@@ -1230,1159 +1261,1182 @@ void ED_object_wpaintmode_exit(struct bContext *C)
*/
static int wpaint_mode_toggle_exec(bContext *C, wmOperator *op)
{
- Main *bmain = CTX_data_main(C);
- struct wmMsgBus *mbus = CTX_wm_message_bus(C);
- Object *ob = CTX_data_active_object(C);
- const int mode_flag = OB_MODE_WEIGHT_PAINT;
- const bool is_mode_set = (ob->mode & mode_flag) != 0;
- Scene *scene = CTX_data_scene(C);
- ToolSettings *ts = scene->toolsettings;
-
- if (!is_mode_set) {
- if (!ED_object_mode_compat_set(C, ob, mode_flag, op->reports)) {
- return OPERATOR_CANCELLED;
- }
- }
-
- Mesh *me = BKE_mesh_from_object(ob);
-
- if (is_mode_set) {
- ED_object_wpaintmode_exit_ex(ob);
- }
- else {
- Depsgraph *depsgraph = CTX_data_depsgraph_on_load(C);
- wmWindowManager *wm = CTX_wm_manager(C);
- ED_object_wpaintmode_enter_ex(bmain, depsgraph, wm, scene, ob);
- BKE_paint_toolslots_brush_validate(bmain, &ts->wpaint->paint);
- }
-
- /* When locked, it's almost impossible to select the pose then the object to enter weight paint mode.
- * In this case move our pose object in/out of pose mode.
- * This is in fits with the convention of selecting multiple objects and entering a mode. */
- if (scene->toolsettings->object_flag & SCE_OBJECT_MODE_LOCK) {
- Object *ob_arm = modifiers_isDeformedByArmature(ob);
- if (ob_arm && (ob_arm->base_flag & BASE_SELECTED)) {
- if (ob_arm->mode & OB_MODE_POSE) {
- ED_object_posemode_exit_ex(bmain, ob_arm);
- }
- else {
- ED_object_posemode_enter_ex(bmain, ob_arm);
- }
- }
- }
-
- /* Weightpaint works by overriding colors in mesh,
- * so need to make sure we recalc on enter and
- * exit (exit needs doing regardless because we
- * should redeform).
- */
- DEG_id_tag_update(&me->id, 0);
-
- WM_event_add_notifier(C, NC_SCENE | ND_MODE, scene);
-
- WM_msg_publish_rna_prop(mbus, &ob->id, ob, Object, mode);
-
- WM_toolsystem_update_from_context_view3d(C);
-
- return OPERATOR_FINISHED;
+ Main *bmain = CTX_data_main(C);
+ struct wmMsgBus *mbus = CTX_wm_message_bus(C);
+ Object *ob = CTX_data_active_object(C);
+ const int mode_flag = OB_MODE_WEIGHT_PAINT;
+ const bool is_mode_set = (ob->mode & mode_flag) != 0;
+ Scene *scene = CTX_data_scene(C);
+ ToolSettings *ts = scene->toolsettings;
+
+ if (!is_mode_set) {
+ if (!ED_object_mode_compat_set(C, ob, mode_flag, op->reports)) {
+ return OPERATOR_CANCELLED;
+ }
+ }
+
+ Mesh *me = BKE_mesh_from_object(ob);
+
+ if (is_mode_set) {
+ ED_object_wpaintmode_exit_ex(ob);
+ }
+ else {
+ Depsgraph *depsgraph = CTX_data_depsgraph_on_load(C);
+ wmWindowManager *wm = CTX_wm_manager(C);
+ ED_object_wpaintmode_enter_ex(bmain, depsgraph, wm, scene, ob);
+ BKE_paint_toolslots_brush_validate(bmain, &ts->wpaint->paint);
+ }
+
+ /* When locked, it's almost impossible to select the pose then the object to enter weight paint mode.
+ * In this case move our pose object in/out of pose mode.
+ * This is in fits with the convention of selecting multiple objects and entering a mode. */
+ if (scene->toolsettings->object_flag & SCE_OBJECT_MODE_LOCK) {
+ Object *ob_arm = modifiers_isDeformedByArmature(ob);
+ if (ob_arm && (ob_arm->base_flag & BASE_SELECTED)) {
+ if (ob_arm->mode & OB_MODE_POSE) {
+ ED_object_posemode_exit_ex(bmain, ob_arm);
+ }
+ else {
+ ED_object_posemode_enter_ex(bmain, ob_arm);
+ }
+ }
+ }
+
+ /* Weightpaint works by overriding colors in mesh,
+ * so need to make sure we recalc on enter and
+ * exit (exit needs doing regardless because we
+ * should redeform).
+ */
+ DEG_id_tag_update(&me->id, 0);
+
+ WM_event_add_notifier(C, NC_SCENE | ND_MODE, scene);
+
+ WM_msg_publish_rna_prop(mbus, &ob->id, ob, Object, mode);
+
+ WM_toolsystem_update_from_context_view3d(C);
+
+ return OPERATOR_FINISHED;
}
/* for switching to/from mode */
static bool paint_poll_test(bContext *C)
{
- Object *ob = CTX_data_active_object(C);
- if (ob == NULL || ob->type != OB_MESH)
- return 0;
- if (!ob->data || ID_IS_LINKED(ob->data))
- return 0;
- if (CTX_data_edit_object(C))
- return 0;
- return 1;
+ Object *ob = CTX_data_active_object(C);
+ if (ob == NULL || ob->type != OB_MESH)
+ return 0;
+ if (!ob->data || ID_IS_LINKED(ob->data))
+ return 0;
+ if (CTX_data_edit_object(C))
+ return 0;
+ return 1;
}
void PAINT_OT_weight_paint_toggle(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Weight Paint Mode";
- ot->idname = "PAINT_OT_weight_paint_toggle";
- ot->description = "Toggle weight paint mode in 3D view";
+ /* identifiers */
+ ot->name = "Weight Paint Mode";
+ ot->idname = "PAINT_OT_weight_paint_toggle";
+ ot->description = "Toggle weight paint mode in 3D view";
- /* api callbacks */
- ot->exec = wpaint_mode_toggle_exec;
- ot->poll = paint_poll_test;
+ /* api callbacks */
+ ot->exec = wpaint_mode_toggle_exec;
+ ot->poll = paint_poll_test;
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_USE_EVAL_DATA;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_USE_EVAL_DATA;
}
/* ************ weight paint operator ********** */
struct WPaintData {
- ViewContext vc;
- struct NormalAnglePrecalc normal_angle_precalc;
+ ViewContext vc;
+ struct NormalAnglePrecalc normal_angle_precalc;
- struct WeightPaintGroupData active, mirror;
+ struct WeightPaintGroupData active, mirror;
- /* variables for auto normalize */
- const bool *vgroup_validmap; /* stores if vgroups tie to deforming bones or not */
- const bool *lock_flags;
+ /* variables for auto normalize */
+ const bool *vgroup_validmap; /* stores if vgroups tie to deforming bones or not */
+ const bool *lock_flags;
- /* variables for multipaint */
- const bool *defbase_sel; /* set of selected groups */
- int defbase_tot_sel; /* number of selected groups */
- bool do_multipaint; /* true if multipaint enabled and multiple groups selected */
+ /* variables for multipaint */
+ const bool *defbase_sel; /* set of selected groups */
+ int defbase_tot_sel; /* number of selected groups */
+ bool do_multipaint; /* true if multipaint enabled and multiple groups selected */
- int defbase_tot;
+ int defbase_tot;
- /* original weight values for use in blur/smear */
- float *precomputed_weight;
- bool precomputed_weight_ready;
+ /* original weight values for use in blur/smear */
+ float *precomputed_weight;
+ bool precomputed_weight_ready;
};
/* Initialize the stroke cache invariants from operator properties */
static void vwpaint_update_cache_invariants(
- bContext *C, const VPaint *vp, SculptSession *ss, wmOperator *op, const float mouse[2])
-{
- StrokeCache *cache;
- Scene *scene = CTX_data_scene(C);
- UnifiedPaintSettings *ups = &CTX_data_tool_settings(C)->unified_paint_settings;
- const Brush *brush = vp->paint.brush;
- ViewContext *vc = paint_stroke_view_context(op->customdata);
- Object *ob = CTX_data_active_object(C);
- float mat[3][3];
- float view_dir[3] = {0.0f, 0.0f, 1.0f};
- int mode;
-
- /* VW paint needs to allocate stroke cache before update is called. */
- if (!ss->cache) {
- cache = MEM_callocN(sizeof(StrokeCache), "stroke cache");
- ss->cache = cache;
- }
- else {
- cache = ss->cache;
- }
-
- /* Initial mouse location */
- if (mouse)
- copy_v2_v2(cache->initial_mouse, mouse);
- else
- zero_v2(cache->initial_mouse);
-
- mode = RNA_enum_get(op->ptr, "mode");
- cache->invert = mode == BRUSH_STROKE_INVERT;
- cache->alt_smooth = mode == BRUSH_STROKE_SMOOTH;
- /* not very nice, but with current events system implementation
- * we can't handle brush appearance inversion hotkey separately (sergey) */
- if (cache->invert) ups->draw_inverted = true;
- else ups->draw_inverted = false;
-
- copy_v2_v2(cache->mouse, cache->initial_mouse);
- /* Truly temporary data that isn't stored in properties */
- cache->vc = vc;
- cache->brush = brush;
- cache->first_time = 1;
-
- /* cache projection matrix */
- ED_view3d_ob_project_mat_get(cache->vc->rv3d, ob, cache->projection_mat);
-
- invert_m4_m4(ob->imat, ob->obmat);
- copy_m3_m4(mat, cache->vc->rv3d->viewinv);
- mul_m3_v3(mat, view_dir);
- copy_m3_m4(mat, ob->imat);
- mul_m3_v3(mat, view_dir);
- normalize_v3_v3(cache->true_view_normal, view_dir);
-
- copy_v3_v3(cache->view_normal, cache->true_view_normal);
- cache->bstrength = BKE_brush_alpha_get(scene, brush);
- cache->is_last_valid = false;
+ bContext *C, const VPaint *vp, SculptSession *ss, wmOperator *op, const float mouse[2])
+{
+ StrokeCache *cache;
+ Scene *scene = CTX_data_scene(C);
+ UnifiedPaintSettings *ups = &CTX_data_tool_settings(C)->unified_paint_settings;
+ const Brush *brush = vp->paint.brush;
+ ViewContext *vc = paint_stroke_view_context(op->customdata);
+ Object *ob = CTX_data_active_object(C);
+ float mat[3][3];
+ float view_dir[3] = {0.0f, 0.0f, 1.0f};
+ int mode;
+
+ /* VW paint needs to allocate stroke cache before update is called. */
+ if (!ss->cache) {
+ cache = MEM_callocN(sizeof(StrokeCache), "stroke cache");
+ ss->cache = cache;
+ }
+ else {
+ cache = ss->cache;
+ }
+
+ /* Initial mouse location */
+ if (mouse)
+ copy_v2_v2(cache->initial_mouse, mouse);
+ else
+ zero_v2(cache->initial_mouse);
+
+ mode = RNA_enum_get(op->ptr, "mode");
+ cache->invert = mode == BRUSH_STROKE_INVERT;
+ cache->alt_smooth = mode == BRUSH_STROKE_SMOOTH;
+ /* not very nice, but with current events system implementation
+ * we can't handle brush appearance inversion hotkey separately (sergey) */
+ if (cache->invert)
+ ups->draw_inverted = true;
+ else
+ ups->draw_inverted = false;
+
+ copy_v2_v2(cache->mouse, cache->initial_mouse);
+ /* Truly temporary data that isn't stored in properties */
+ cache->vc = vc;
+ cache->brush = brush;
+ cache->first_time = 1;
+
+ /* cache projection matrix */
+ ED_view3d_ob_project_mat_get(cache->vc->rv3d, ob, cache->projection_mat);
+
+ invert_m4_m4(ob->imat, ob->obmat);
+ copy_m3_m4(mat, cache->vc->rv3d->viewinv);
+ mul_m3_v3(mat, view_dir);
+ copy_m3_m4(mat, ob->imat);
+ mul_m3_v3(mat, view_dir);
+ normalize_v3_v3(cache->true_view_normal, view_dir);
+
+ copy_v3_v3(cache->view_normal, cache->true_view_normal);
+ cache->bstrength = BKE_brush_alpha_get(scene, brush);
+ cache->is_last_valid = false;
}
/* Initialize the stroke cache variants from operator properties */
static void vwpaint_update_cache_variants(bContext *C, VPaint *vp, Object *ob, PointerRNA *ptr)
{
- Scene *scene = CTX_data_scene(C);
- SculptSession *ss = ob->sculpt;
- StrokeCache *cache = ss->cache;
- Brush *brush = BKE_paint_brush(&vp->paint);
-
- /* This effects the actual brush radius, so things farther away
- * are compared with a larger radius and vice versa. */
- if (cache->first_time) {
- RNA_float_get_array(ptr, "location", cache->true_location);
- }
-
- RNA_float_get_array(ptr, "mouse", cache->mouse);
-
- /* XXX: Use pressure value from first brush step for brushes which don't
- * support strokes (grab, thumb). They depends on initial state and
- * brush coord/pressure/etc.
- * It's more an events design issue, which doesn't split coordinate/pressure/angle
- * changing events. We should avoid this after events system re-design */
- if (paint_supports_dynamic_size(brush, PAINT_MODE_SCULPT) || cache->first_time) {
- cache->pressure = RNA_float_get(ptr, "pressure");
- }
-
- /* Truly temporary data that isn't stored in properties */
- if (cache->first_time) {
- if (!BKE_brush_use_locked_size(scene, brush)) {
- cache->initial_radius = paint_calc_object_space_radius(
- cache->vc, cache->true_location, BKE_brush_size_get(scene, brush));
- BKE_brush_unprojected_radius_set(scene, brush, cache->initial_radius);
- }
- else {
- cache->initial_radius = BKE_brush_unprojected_radius_get(scene, brush);
- }
- }
-
- if (BKE_brush_use_size_pressure(scene, brush) && paint_supports_dynamic_size(brush, PAINT_MODE_SCULPT)) {
- cache->radius = cache->initial_radius * cache->pressure;
- }
- else {
- cache->radius = cache->initial_radius;
- }
-
- cache->radius_squared = cache->radius * cache->radius;
-
- if (ss->pbvh) {
- BKE_pbvh_update(ss->pbvh, PBVH_UpdateRedraw, NULL);
- BKE_pbvh_update(ss->pbvh, PBVH_UpdateBB, NULL);
- }
+ Scene *scene = CTX_data_scene(C);
+ SculptSession *ss = ob->sculpt;
+ StrokeCache *cache = ss->cache;
+ Brush *brush = BKE_paint_brush(&vp->paint);
+
+ /* This effects the actual brush radius, so things farther away
+ * are compared with a larger radius and vice versa. */
+ if (cache->first_time) {
+ RNA_float_get_array(ptr, "location", cache->true_location);
+ }
+
+ RNA_float_get_array(ptr, "mouse", cache->mouse);
+
+ /* XXX: Use pressure value from first brush step for brushes which don't
+ * support strokes (grab, thumb). They depends on initial state and
+ * brush coord/pressure/etc.
+ * It's more an events design issue, which doesn't split coordinate/pressure/angle
+ * changing events. We should avoid this after events system re-design */
+ if (paint_supports_dynamic_size(brush, PAINT_MODE_SCULPT) || cache->first_time) {
+ cache->pressure = RNA_float_get(ptr, "pressure");
+ }
+
+ /* Truly temporary data that isn't stored in properties */
+ if (cache->first_time) {
+ if (!BKE_brush_use_locked_size(scene, brush)) {
+ cache->initial_radius = paint_calc_object_space_radius(
+ cache->vc, cache->true_location, BKE_brush_size_get(scene, brush));
+ BKE_brush_unprojected_radius_set(scene, brush, cache->initial_radius);
+ }
+ else {
+ cache->initial_radius = BKE_brush_unprojected_radius_get(scene, brush);
+ }
+ }
+
+ if (BKE_brush_use_size_pressure(scene, brush) &&
+ paint_supports_dynamic_size(brush, PAINT_MODE_SCULPT)) {
+ cache->radius = cache->initial_radius * cache->pressure;
+ }
+ else {
+ cache->radius = cache->initial_radius;
+ }
+
+ cache->radius_squared = cache->radius * cache->radius;
+
+ if (ss->pbvh) {
+ BKE_pbvh_update(ss->pbvh, PBVH_UpdateRedraw, NULL);
+ BKE_pbvh_update(ss->pbvh, PBVH_UpdateBB, NULL);
+ }
}
static bool wpaint_stroke_test_start(bContext *C, wmOperator *op, const float mouse[2])
{
- Scene *scene = CTX_data_scene(C);
- struct PaintStroke *stroke = op->customdata;
- ToolSettings *ts = scene->toolsettings;
- Object *ob = CTX_data_active_object(C);
- Mesh *me = BKE_mesh_from_object(ob);
- struct WPaintData *wpd;
- struct WPaintVGroupIndex vgroup_index;
- int defbase_tot, defbase_tot_sel;
- bool *defbase_sel;
- SculptSession *ss = ob->sculpt;
- VPaint *vp = CTX_data_tool_settings(C)->wpaint;
- Depsgraph *depsgraph = CTX_data_depsgraph(C);
-
- if (ED_wpaint_ensure_data(C, op->reports, WPAINT_ENSURE_MIRROR, &vgroup_index) == false) {
- return false;
- }
-
- {
- /* check if we are attempting to paint onto a locked vertex group,
- * and other options disallow it from doing anything useful */
- bDeformGroup *dg;
- dg = BLI_findlink(&ob->defbase, vgroup_index.active);
- if (dg->flag & DG_LOCK_WEIGHT) {
- BKE_report(op->reports, RPT_WARNING, "Active group is locked, aborting");
- return false;
- }
- if (vgroup_index.mirror != -1) {
- dg = BLI_findlink(&ob->defbase, vgroup_index.mirror);
- if (dg->flag & DG_LOCK_WEIGHT) {
- BKE_report(op->reports, RPT_WARNING, "Mirror group is locked, aborting");
- return false;
- }
- }
- }
-
- /* check that multipaint groups are unlocked */
- defbase_tot = BLI_listbase_count(&ob->defbase);
- defbase_sel = BKE_object_defgroup_selected_get(ob, defbase_tot, &defbase_tot_sel);
-
- if (ts->multipaint && defbase_tot_sel > 1) {
- int i;
- bDeformGroup *dg;
-
- if (me->editflag & ME_EDIT_MIRROR_X) {
- BKE_object_defgroup_mirror_selection(ob, defbase_tot, defbase_sel, defbase_sel, &defbase_tot_sel);
- }
-
- for (i = 0; i < defbase_tot; i++) {
- if (defbase_sel[i]) {
- dg = BLI_findlink(&ob->defbase, i);
- if (dg->flag & DG_LOCK_WEIGHT) {
- BKE_report(op->reports, RPT_WARNING, "Multipaint group is locked, aborting");
- MEM_freeN(defbase_sel);
- return false;
- }
- }
- }
- }
-
- /* ALLOCATIONS! no return after this line */
- /* make mode data storage */
- wpd = MEM_callocN(sizeof(struct WPaintData), "WPaintData");
- paint_stroke_set_mode_data(stroke, wpd);
- ED_view3d_viewcontext_init(C, &wpd->vc);
- view_angle_limits_init(
- &wpd->normal_angle_precalc, vp->paint.brush->falloff_angle,
- (vp->paint.brush->flag & BRUSH_FRONTFACE_FALLOFF) != 0);
-
- wpd->active.index = vgroup_index.active;
- wpd->mirror.index = vgroup_index.mirror;
-
- /* multipaint */
- wpd->defbase_tot = defbase_tot;
- wpd->defbase_sel = defbase_sel;
- wpd->defbase_tot_sel = defbase_tot_sel > 1 ? defbase_tot_sel : 1;
- wpd->do_multipaint = (ts->multipaint && defbase_tot_sel > 1);
-
- /* set up auto-normalize, and generate map for detecting which
- * vgroups affect deform bones */
- wpd->lock_flags = BKE_object_defgroup_lock_flags_get(ob, wpd->defbase_tot);
- if (ts->auto_normalize || ts->multipaint || wpd->lock_flags) {
- wpd->vgroup_validmap = BKE_object_defgroup_validmap_get(ob, wpd->defbase_tot);
- }
-
- if (wpd->do_multipaint && ts->auto_normalize) {
- bool *tmpflags;
- tmpflags = MEM_mallocN(sizeof(bool) * defbase_tot, __func__);
- if (wpd->lock_flags) {
- BLI_array_binary_or(tmpflags, wpd->defbase_sel, wpd->lock_flags, wpd->defbase_tot);
- }
- else {
- memcpy(tmpflags, wpd->defbase_sel, sizeof(*tmpflags) * wpd->defbase_tot);
- }
- wpd->active.lock = tmpflags;
- }
- else if (ts->auto_normalize) {
- bool *tmpflags;
-
- tmpflags = wpd->lock_flags ?
- MEM_dupallocN(wpd->lock_flags) :
- MEM_callocN(sizeof(bool) * defbase_tot, __func__);
- tmpflags[wpd->active.index] = true;
- wpd->active.lock = tmpflags;
-
- tmpflags = wpd->lock_flags ?
- MEM_dupallocN(wpd->lock_flags) :
- MEM_callocN(sizeof(bool) * defbase_tot, __func__);
- tmpflags[(wpd->mirror.index != -1) ? wpd->mirror.index : wpd->active.index] = true;
- wpd->mirror.lock = tmpflags;
- }
-
- if (ELEM(vp->paint.brush->weightpaint_tool, WPAINT_TOOL_SMEAR, WPAINT_TOOL_BLUR)) {
- wpd->precomputed_weight = MEM_mallocN(sizeof(float) * me->totvert, __func__);
- }
-
- /* If not previously created, create vertex/weight paint mode session data */
- vertex_paint_init_stroke(depsgraph, scene, ob);
- vwpaint_update_cache_invariants(C, vp, ss, op, mouse);
- vertex_paint_init_session_data(ts, ob);
-
- if (ob->sculpt->mode.wpaint.dvert_prev != NULL) {
- MDeformVert *dv = ob->sculpt->mode.wpaint.dvert_prev;
- for (int i = 0; i < me->totvert; i++, dv++) {
- /* Use to show this isn't initialized, never apply to the mesh data. */
- dv->flag = 1;
- }
- }
-
- return true;
+ Scene *scene = CTX_data_scene(C);
+ struct PaintStroke *stroke = op->customdata;
+ ToolSettings *ts = scene->toolsettings;
+ Object *ob = CTX_data_active_object(C);
+ Mesh *me = BKE_mesh_from_object(ob);
+ struct WPaintData *wpd;
+ struct WPaintVGroupIndex vgroup_index;
+ int defbase_tot, defbase_tot_sel;
+ bool *defbase_sel;
+ SculptSession *ss = ob->sculpt;
+ VPaint *vp = CTX_data_tool_settings(C)->wpaint;
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+
+ if (ED_wpaint_ensure_data(C, op->reports, WPAINT_ENSURE_MIRROR, &vgroup_index) == false) {
+ return false;
+ }
+
+ {
+ /* check if we are attempting to paint onto a locked vertex group,
+ * and other options disallow it from doing anything useful */
+ bDeformGroup *dg;
+ dg = BLI_findlink(&ob->defbase, vgroup_index.active);
+ if (dg->flag & DG_LOCK_WEIGHT) {
+ BKE_report(op->reports, RPT_WARNING, "Active group is locked, aborting");
+ return false;
+ }
+ if (vgroup_index.mirror != -1) {
+ dg = BLI_findlink(&ob->defbase, vgroup_index.mirror);
+ if (dg->flag & DG_LOCK_WEIGHT) {
+ BKE_report(op->reports, RPT_WARNING, "Mirror group is locked, aborting");
+ return false;
+ }
+ }
+ }
+
+ /* check that multipaint groups are unlocked */
+ defbase_tot = BLI_listbase_count(&ob->defbase);
+ defbase_sel = BKE_object_defgroup_selected_get(ob, defbase_tot, &defbase_tot_sel);
+
+ if (ts->multipaint && defbase_tot_sel > 1) {
+ int i;
+ bDeformGroup *dg;
+
+ if (me->editflag & ME_EDIT_MIRROR_X) {
+ BKE_object_defgroup_mirror_selection(
+ ob, defbase_tot, defbase_sel, defbase_sel, &defbase_tot_sel);
+ }
+
+ for (i = 0; i < defbase_tot; i++) {
+ if (defbase_sel[i]) {
+ dg = BLI_findlink(&ob->defbase, i);
+ if (dg->flag & DG_LOCK_WEIGHT) {
+ BKE_report(op->reports, RPT_WARNING, "Multipaint group is locked, aborting");
+ MEM_freeN(defbase_sel);
+ return false;
+ }
+ }
+ }
+ }
+
+ /* ALLOCATIONS! no return after this line */
+ /* make mode data storage */
+ wpd = MEM_callocN(sizeof(struct WPaintData), "WPaintData");
+ paint_stroke_set_mode_data(stroke, wpd);
+ ED_view3d_viewcontext_init(C, &wpd->vc);
+ view_angle_limits_init(&wpd->normal_angle_precalc,
+ vp->paint.brush->falloff_angle,
+ (vp->paint.brush->flag & BRUSH_FRONTFACE_FALLOFF) != 0);
+
+ wpd->active.index = vgroup_index.active;
+ wpd->mirror.index = vgroup_index.mirror;
+
+ /* multipaint */
+ wpd->defbase_tot = defbase_tot;
+ wpd->defbase_sel = defbase_sel;
+ wpd->defbase_tot_sel = defbase_tot_sel > 1 ? defbase_tot_sel : 1;
+ wpd->do_multipaint = (ts->multipaint && defbase_tot_sel > 1);
+
+ /* set up auto-normalize, and generate map for detecting which
+ * vgroups affect deform bones */
+ wpd->lock_flags = BKE_object_defgroup_lock_flags_get(ob, wpd->defbase_tot);
+ if (ts->auto_normalize || ts->multipaint || wpd->lock_flags) {
+ wpd->vgroup_validmap = BKE_object_defgroup_validmap_get(ob, wpd->defbase_tot);
+ }
+
+ if (wpd->do_multipaint && ts->auto_normalize) {
+ bool *tmpflags;
+ tmpflags = MEM_mallocN(sizeof(bool) * defbase_tot, __func__);
+ if (wpd->lock_flags) {
+ BLI_array_binary_or(tmpflags, wpd->defbase_sel, wpd->lock_flags, wpd->defbase_tot);
+ }
+ else {
+ memcpy(tmpflags, wpd->defbase_sel, sizeof(*tmpflags) * wpd->defbase_tot);
+ }
+ wpd->active.lock = tmpflags;
+ }
+ else if (ts->auto_normalize) {
+ bool *tmpflags;
+
+ tmpflags = wpd->lock_flags ? MEM_dupallocN(wpd->lock_flags) :
+ MEM_callocN(sizeof(bool) * defbase_tot, __func__);
+ tmpflags[wpd->active.index] = true;
+ wpd->active.lock = tmpflags;
+
+ tmpflags = wpd->lock_flags ? MEM_dupallocN(wpd->lock_flags) :
+ MEM_callocN(sizeof(bool) * defbase_tot, __func__);
+ tmpflags[(wpd->mirror.index != -1) ? wpd->mirror.index : wpd->active.index] = true;
+ wpd->mirror.lock = tmpflags;
+ }
+
+ if (ELEM(vp->paint.brush->weightpaint_tool, WPAINT_TOOL_SMEAR, WPAINT_TOOL_BLUR)) {
+ wpd->precomputed_weight = MEM_mallocN(sizeof(float) * me->totvert, __func__);
+ }
+
+ /* If not previously created, create vertex/weight paint mode session data */
+ vertex_paint_init_stroke(depsgraph, scene, ob);
+ vwpaint_update_cache_invariants(C, vp, ss, op, mouse);
+ vertex_paint_init_session_data(ts, ob);
+
+ if (ob->sculpt->mode.wpaint.dvert_prev != NULL) {
+ MDeformVert *dv = ob->sculpt->mode.wpaint.dvert_prev;
+ for (int i = 0; i < me->totvert; i++, dv++) {
+ /* Use to show this isn't initialized, never apply to the mesh data. */
+ dv->flag = 1;
+ }
+ }
+
+ return true;
}
static float dot_vf3vs3(const float brushNormal[3], const short vertexNormal[3])
{
- float normal[3];
- normal_short_to_float_v3(normal, vertexNormal);
- return dot_v3v3(brushNormal, normal);
+ float normal[3];
+ normal_short_to_float_v3(normal, vertexNormal);
+ return dot_v3v3(brushNormal, normal);
}
-static void get_brush_alpha_data(
- const Scene *scene, const SculptSession *ss, const Brush *brush,
- float *r_brush_size_pressure, float *r_brush_alpha_value, float *r_brush_alpha_pressure)
+static void get_brush_alpha_data(const Scene *scene,
+ const SculptSession *ss,
+ const Brush *brush,
+ float *r_brush_size_pressure,
+ float *r_brush_alpha_value,
+ float *r_brush_alpha_pressure)
{
- *r_brush_size_pressure =
- BKE_brush_size_get(scene, brush) *
- (BKE_brush_use_size_pressure(scene, brush) ? ss->cache->pressure : 1.0f);
- *r_brush_alpha_value =
- BKE_brush_alpha_get(scene, brush);
- *r_brush_alpha_pressure =
- (BKE_brush_use_alpha_pressure(scene, brush) ? ss->cache->pressure : 1.0f);
+ *r_brush_size_pressure = BKE_brush_size_get(scene, brush) *
+ (BKE_brush_use_size_pressure(scene, brush) ? ss->cache->pressure :
+ 1.0f);
+ *r_brush_alpha_value = BKE_brush_alpha_get(scene, brush);
+ *r_brush_alpha_pressure = (BKE_brush_use_alpha_pressure(scene, brush) ? ss->cache->pressure :
+ 1.0f);
}
static float wpaint_get_active_weight(const MDeformVert *dv, const WeightPaintInfo *wpi)
{
- if (wpi->do_multipaint) {
- float weight = BKE_defvert_multipaint_collective_weight(
- dv, wpi->defbase_tot, wpi->defbase_sel, wpi->defbase_tot_sel, wpi->do_auto_normalize);
+ if (wpi->do_multipaint) {
+ float weight = BKE_defvert_multipaint_collective_weight(
+ dv, wpi->defbase_tot, wpi->defbase_sel, wpi->defbase_tot_sel, wpi->do_auto_normalize);
- CLAMP(weight, 0.0f, 1.0f);
- return weight;
- }
- else {
- return defvert_find_weight(dv, wpi->active.index);
- }
+ CLAMP(weight, 0.0f, 1.0f);
+ return weight;
+ }
+ else {
+ return defvert_find_weight(dv, wpi->active.index);
+ }
}
-static void do_wpaint_precompute_weight_cb_ex(
- void *__restrict userdata,
- const int n,
- const ParallelRangeTLS *__restrict UNUSED(tls))
+static void do_wpaint_precompute_weight_cb_ex(void *__restrict userdata,
+ const int n,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
- SculptThreadedTaskData *data = userdata;
- const MDeformVert *dv = &data->me->dvert[n];
+ SculptThreadedTaskData *data = userdata;
+ const MDeformVert *dv = &data->me->dvert[n];
- data->wpd->precomputed_weight[n] = wpaint_get_active_weight(dv, data->wpi);
+ data->wpd->precomputed_weight[n] = wpaint_get_active_weight(dv, data->wpi);
}
static void precompute_weight_values(
- bContext *C, Object *ob, Brush *brush, struct WPaintData *wpd, WeightPaintInfo *wpi, Mesh *me)
-{
- if (wpd->precomputed_weight_ready && !brush_use_accumulate_ex(brush, ob->mode))
- return;
-
- /* threaded loop over vertices */
- SculptThreadedTaskData data = {
- .C = C, .ob = ob, .wpd = wpd, .wpi = wpi, .me = me,
- };
-
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- BLI_task_parallel_range(
- 0, me->totvert,
- &data,
- do_wpaint_precompute_weight_cb_ex,
- &settings);
-
- wpd->precomputed_weight_ready = true;
-}
-
-static void do_wpaint_brush_blur_task_cb_ex(
- void *__restrict userdata,
- const int n,
- const ParallelRangeTLS *__restrict UNUSED(tls))
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- const PBVHType pbvh_type = BKE_pbvh_type(ss->pbvh);
- const bool has_grids = (pbvh_type == PBVH_GRIDS);
- const struct SculptVertexPaintGeomMap *gmap = &ss->mode.wpaint.gmap;
-
- const Brush *brush = data->brush;
- const StrokeCache *cache = ss->cache;
- Scene *scene = CTX_data_scene(data->C);
-
- float brush_size_pressure, brush_alpha_value, brush_alpha_pressure;
- get_brush_alpha_data(scene, ss, brush, &brush_size_pressure, &brush_alpha_value, &brush_alpha_pressure);
- const bool use_normal = vwpaint_use_normal(data->vp);
- const bool use_face_sel = (data->me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
- 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);
- const float *sculpt_normal_frontface =
- sculpt_brush_frontface_normal_from_falloff_shape(ss, data->brush->falloff_shape);
-
- /* For each vertex */
- PBVHVertexIter vd;
- BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
- {
- /* Test to see if the vertex coordinates are within the spherical brush region. */
- if (sculpt_brush_test_sq_fn(&test, vd.co)) {
- /* For grid based pbvh, take the vert whose loop corresponds to the current grid.
- * Otherwise, take the current vert. */
- const int v_index = has_grids ? data->me->mloop[vd.grid_indices[vd.g]].v : vd.vert_indices[vd.i];
- const float grid_alpha = has_grids ? 1.0f / vd.gridsize : 1.0f;
- const char v_flag = data->me->mvert[v_index].flag;
- /* If the vertex is selected */
- if (!(use_face_sel || use_vert_sel) || v_flag & SELECT) {
- /* Get the average poly weight */
- int total_hit_loops = 0;
- float weight_final = 0.0f;
- for (int j = 0; j < gmap->vert_to_poly[v_index].count; j++) {
- const int p_index = gmap->vert_to_poly[v_index].indices[j];
- const MPoly *mp = &data->me->mpoly[p_index];
-
- total_hit_loops += mp->totloop;
- for (int k = 0; k < mp->totloop; k++) {
- const int l_index = mp->loopstart + k;
- const MLoop *ml = &data->me->mloop[l_index];
- weight_final += data->wpd->precomputed_weight[ml->v];
- }
- }
-
- /* Apply the weight to the vertex. */
- if (total_hit_loops != 0) {
- float brush_strength = cache->bstrength;
- const float angle_cos = (use_normal && vd.no) ?
- dot_vf3vs3(sculpt_normal_frontface, vd.no) : 1.0f;
- if (((brush->flag & BRUSH_FRONTFACE) == 0 ||
- (angle_cos > 0.0f)) &&
- ((brush->flag & BRUSH_FRONTFACE_FALLOFF) == 0 ||
- view_angle_limits_apply_falloff(&data->wpd->normal_angle_precalc, angle_cos, &brush_strength)))
- {
- const float brush_fade = BKE_brush_curve_strength(brush, sqrtf(test.dist), cache->radius);
- const float final_alpha =
- brush_fade * brush_strength *
- grid_alpha * brush_alpha_pressure;
-
- if ((brush->flag & BRUSH_ACCUMULATE) == 0) {
- if (ss->mode.wpaint.alpha_weight[v_index] < final_alpha) {
- ss->mode.wpaint.alpha_weight[v_index] = final_alpha;
- }
- else {
- continue;
- }
- }
-
- weight_final /= total_hit_loops;
- /* Only paint visible verts */
- do_weight_paint_vertex(
- data->vp, data->ob, data->wpi,
- v_index, final_alpha, weight_final);
- }
- }
- }
- }
- }
- BKE_pbvh_vertex_iter_end;
-}
-
-static void do_wpaint_brush_smear_task_cb_ex(
- void *__restrict userdata,
- const int n,
- const ParallelRangeTLS *__restrict UNUSED(tls))
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- const PBVHType pbvh_type = BKE_pbvh_type(ss->pbvh);
- const bool has_grids = (pbvh_type == PBVH_GRIDS);
- const struct SculptVertexPaintGeomMap *gmap = &ss->mode.wpaint.gmap;
-
- const Brush *brush = data->brush;
- const Scene *scene = CTX_data_scene(data->C);
- const StrokeCache *cache = ss->cache;
- float brush_size_pressure, brush_alpha_value, brush_alpha_pressure;
- get_brush_alpha_data(scene, ss, brush, &brush_size_pressure, &brush_alpha_value, &brush_alpha_pressure);
- const bool use_normal = vwpaint_use_normal(data->vp);
- const bool use_face_sel = (data->me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
- const bool use_vert_sel = (data->me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0;
- float brush_dir[3];
-
- sub_v3_v3v3(brush_dir, cache->location, cache->last_location);
- project_plane_v3_v3v3(brush_dir, brush_dir, cache->view_normal);
-
- 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);
- const float *sculpt_normal_frontface =
- sculpt_brush_frontface_normal_from_falloff_shape(ss, data->brush->falloff_shape);
-
- /* For each vertex */
- PBVHVertexIter vd;
- BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
- {
- /* Test to see if the vertex coordinates are within the spherical brush region. */
- if (sculpt_brush_test_sq_fn(&test, vd.co)) {
- /* For grid based pbvh, take the vert whose loop corresponds to the current grid.
- * Otherwise, take the current vert. */
- const int v_index = has_grids ? data->me->mloop[vd.grid_indices[vd.g]].v : vd.vert_indices[vd.i];
- const float grid_alpha = has_grids ? 1.0f / vd.gridsize : 1.0f;
- const MVert *mv_curr = &data->me->mvert[v_index];
-
- /* If the vertex is selected */
- if (!(use_face_sel || use_vert_sel) || mv_curr->flag & SELECT) {
- float brush_strength = cache->bstrength;
- const float angle_cos = (use_normal && vd.no) ?
- dot_vf3vs3(sculpt_normal_frontface, vd.no) : 1.0f;
- if (((brush->flag & BRUSH_FRONTFACE) == 0 ||
- (angle_cos > 0.0f)) &&
- ((brush->flag & BRUSH_FRONTFACE_FALLOFF) == 0 ||
- view_angle_limits_apply_falloff(&data->wpd->normal_angle_precalc, angle_cos, &brush_strength)))
- {
- bool do_color = false;
- /* Minimum dot product between brush direction and current
- * to neighbor direction is 0.0, meaning orthogonal. */
- float stroke_dot_max = 0.0f;
-
- /* Get the color of the loop in the opposite direction of the brush movement
- * (this callback is specifically for smear.) */
- float weight_final = 0.0;
- for (int j = 0; j < gmap->vert_to_poly[v_index].count; j++) {
- const int p_index = gmap->vert_to_poly[v_index].indices[j];
- const MPoly *mp = &data->me->mpoly[p_index];
- const MLoop *ml_other = &data->me->mloop[mp->loopstart];
- for (int k = 0; k < mp->totloop; k++, ml_other++) {
- const uint v_other_index = ml_other->v;
- if (v_other_index != v_index) {
- const MVert *mv_other = &data->me->mvert[v_other_index];
-
- /* Get the direction from the selected vert to the neighbor. */
- float other_dir[3];
- sub_v3_v3v3(other_dir, mv_curr->co, mv_other->co);
- project_plane_v3_v3v3(other_dir, other_dir, cache->view_normal);
-
- normalize_v3(other_dir);
-
- const float stroke_dot = dot_v3v3(other_dir, brush_dir);
-
- if (stroke_dot > stroke_dot_max) {
- stroke_dot_max = stroke_dot;
- weight_final = data->wpd->precomputed_weight[v_other_index];
- do_color = true;
- }
- }
- }
- }
- /* Apply weight to vertex */
- if (do_color) {
- const float brush_fade = BKE_brush_curve_strength(brush, sqrtf(test.dist), cache->radius);
- const float final_alpha =
- brush_fade * brush_strength *
- grid_alpha * brush_alpha_pressure;
-
- if (final_alpha <= 0.0f)
- continue;
-
- do_weight_paint_vertex(
- data->vp, data->ob, data->wpi,
- v_index, final_alpha, (float)weight_final);
- }
- }
- }
- }
- }
- BKE_pbvh_vertex_iter_end;
- }
-}
-
-static void do_wpaint_brush_draw_task_cb_ex(
- void *__restrict userdata,
- const int n,
- const ParallelRangeTLS *__restrict UNUSED(tls))
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- const PBVHType pbvh_type = BKE_pbvh_type(ss->pbvh);
- const bool has_grids = (pbvh_type == PBVH_GRIDS);
- const Scene *scene = CTX_data_scene(data->C);
-
- const Brush *brush = data->brush;
- const StrokeCache *cache = ss->cache;
- /* note: normally `BKE_brush_weight_get(scene, brush)` is used,
- * however in this case we calculate a new weight each time. */
- const float paintweight = data->strength;
- float brush_size_pressure, brush_alpha_value, brush_alpha_pressure;
- get_brush_alpha_data(scene, ss, brush, &brush_size_pressure, &brush_alpha_value, &brush_alpha_pressure);
- const bool use_normal = vwpaint_use_normal(data->vp);
- const bool use_face_sel = (data->me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
- 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);
- const float *sculpt_normal_frontface =
- sculpt_brush_frontface_normal_from_falloff_shape(ss, data->brush->falloff_shape);
-
- /* For each vertex */
- PBVHVertexIter vd;
- BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
- {
- /* Test to see if the vertex coordinates are within the spherical brush region. */
- if (sculpt_brush_test_sq_fn(&test, vd.co)) {
- /* Note: grids are 1:1 with corners (aka loops).
- * For multires, take the vert whose loop corresponds to the current grid.
- * Otherwise, take the current vert. */
- const int v_index = has_grids ? data->me->mloop[vd.grid_indices[vd.g]].v : vd.vert_indices[vd.i];
- const float grid_alpha = has_grids ? 1.0f / vd.gridsize : 1.0f;
-
- const char v_flag = data->me->mvert[v_index].flag;
- /* If the vertex is selected */
- if (!(use_face_sel || use_vert_sel) || v_flag & SELECT) {
- float brush_strength = cache->bstrength;
- const float angle_cos = (use_normal && vd.no) ?
- dot_vf3vs3(sculpt_normal_frontface, vd.no) : 1.0f;
- if (((brush->flag & BRUSH_FRONTFACE) == 0 ||
- (angle_cos > 0.0f)) &&
- ((brush->flag & BRUSH_FRONTFACE_FALLOFF) == 0 ||
- view_angle_limits_apply_falloff(&data->wpd->normal_angle_precalc, angle_cos, &brush_strength)))
- {
- const float brush_fade = BKE_brush_curve_strength(brush, sqrtf(test.dist), cache->radius);
- const float final_alpha = brush_fade * brush_strength * grid_alpha * brush_alpha_pressure;
-
- if ((brush->flag & BRUSH_ACCUMULATE) == 0) {
- if (ss->mode.wpaint.alpha_weight[v_index] < final_alpha) {
- ss->mode.wpaint.alpha_weight[v_index] = final_alpha;
- }
- else {
- continue;
- }
- }
-
- do_weight_paint_vertex(
- data->vp, data->ob, data->wpi,
- v_index, final_alpha, paintweight);
- }
- }
- }
- }
- BKE_pbvh_vertex_iter_end;
+ bContext *C, Object *ob, Brush *brush, struct WPaintData *wpd, WeightPaintInfo *wpi, Mesh *me)
+{
+ if (wpd->precomputed_weight_ready && !brush_use_accumulate_ex(brush, ob->mode))
+ return;
+
+ /* threaded loop over vertices */
+ SculptThreadedTaskData data = {
+ .C = C,
+ .ob = ob,
+ .wpd = wpd,
+ .wpi = wpi,
+ .me = me,
+ };
+
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ BLI_task_parallel_range(0, me->totvert, &data, do_wpaint_precompute_weight_cb_ex, &settings);
+
+ wpd->precomputed_weight_ready = true;
+}
+
+static void do_wpaint_brush_blur_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ const PBVHType pbvh_type = BKE_pbvh_type(ss->pbvh);
+ const bool has_grids = (pbvh_type == PBVH_GRIDS);
+ const struct SculptVertexPaintGeomMap *gmap = &ss->mode.wpaint.gmap;
+
+ const Brush *brush = data->brush;
+ const StrokeCache *cache = ss->cache;
+ Scene *scene = CTX_data_scene(data->C);
+
+ float brush_size_pressure, brush_alpha_value, brush_alpha_pressure;
+ get_brush_alpha_data(
+ scene, ss, brush, &brush_size_pressure, &brush_alpha_value, &brush_alpha_pressure);
+ const bool use_normal = vwpaint_use_normal(data->vp);
+ const bool use_face_sel = (data->me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
+ 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);
+ const float *sculpt_normal_frontface = sculpt_brush_frontface_normal_from_falloff_shape(
+ ss, data->brush->falloff_shape);
+
+ /* For each vertex */
+ PBVHVertexIter vd;
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
+ {
+ /* Test to see if the vertex coordinates are within the spherical brush region. */
+ if (sculpt_brush_test_sq_fn(&test, vd.co)) {
+ /* For grid based pbvh, take the vert whose loop corresponds to the current grid.
+ * Otherwise, take the current vert. */
+ const int v_index = has_grids ? data->me->mloop[vd.grid_indices[vd.g]].v :
+ vd.vert_indices[vd.i];
+ const float grid_alpha = has_grids ? 1.0f / vd.gridsize : 1.0f;
+ const char v_flag = data->me->mvert[v_index].flag;
+ /* If the vertex is selected */
+ if (!(use_face_sel || use_vert_sel) || v_flag & SELECT) {
+ /* Get the average poly weight */
+ int total_hit_loops = 0;
+ float weight_final = 0.0f;
+ for (int j = 0; j < gmap->vert_to_poly[v_index].count; j++) {
+ const int p_index = gmap->vert_to_poly[v_index].indices[j];
+ const MPoly *mp = &data->me->mpoly[p_index];
+
+ total_hit_loops += mp->totloop;
+ for (int k = 0; k < mp->totloop; k++) {
+ const int l_index = mp->loopstart + k;
+ const MLoop *ml = &data->me->mloop[l_index];
+ weight_final += data->wpd->precomputed_weight[ml->v];
+ }
+ }
+
+ /* Apply the weight to the vertex. */
+ if (total_hit_loops != 0) {
+ float brush_strength = cache->bstrength;
+ const float angle_cos = (use_normal && vd.no) ?
+ dot_vf3vs3(sculpt_normal_frontface, vd.no) :
+ 1.0f;
+ if (((brush->flag & BRUSH_FRONTFACE) == 0 || (angle_cos > 0.0f)) &&
+ ((brush->flag & BRUSH_FRONTFACE_FALLOFF) == 0 ||
+ view_angle_limits_apply_falloff(
+ &data->wpd->normal_angle_precalc, angle_cos, &brush_strength))) {
+ const float brush_fade = BKE_brush_curve_strength(
+ brush, sqrtf(test.dist), cache->radius);
+ const float final_alpha = brush_fade * brush_strength * grid_alpha *
+ brush_alpha_pressure;
+
+ if ((brush->flag & BRUSH_ACCUMULATE) == 0) {
+ if (ss->mode.wpaint.alpha_weight[v_index] < final_alpha) {
+ ss->mode.wpaint.alpha_weight[v_index] = final_alpha;
+ }
+ else {
+ continue;
+ }
+ }
+
+ weight_final /= total_hit_loops;
+ /* Only paint visible verts */
+ do_weight_paint_vertex(
+ data->vp, data->ob, data->wpi, v_index, final_alpha, weight_final);
+ }
+ }
+ }
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+static void do_wpaint_brush_smear_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ const PBVHType pbvh_type = BKE_pbvh_type(ss->pbvh);
+ const bool has_grids = (pbvh_type == PBVH_GRIDS);
+ const struct SculptVertexPaintGeomMap *gmap = &ss->mode.wpaint.gmap;
+
+ const Brush *brush = data->brush;
+ const Scene *scene = CTX_data_scene(data->C);
+ const StrokeCache *cache = ss->cache;
+ float brush_size_pressure, brush_alpha_value, brush_alpha_pressure;
+ get_brush_alpha_data(
+ scene, ss, brush, &brush_size_pressure, &brush_alpha_value, &brush_alpha_pressure);
+ const bool use_normal = vwpaint_use_normal(data->vp);
+ const bool use_face_sel = (data->me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
+ const bool use_vert_sel = (data->me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0;
+ float brush_dir[3];
+
+ sub_v3_v3v3(brush_dir, cache->location, cache->last_location);
+ project_plane_v3_v3v3(brush_dir, brush_dir, cache->view_normal);
+
+ 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);
+ const float *sculpt_normal_frontface = sculpt_brush_frontface_normal_from_falloff_shape(
+ ss, data->brush->falloff_shape);
+
+ /* For each vertex */
+ PBVHVertexIter vd;
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
+ {
+ /* Test to see if the vertex coordinates are within the spherical brush region. */
+ if (sculpt_brush_test_sq_fn(&test, vd.co)) {
+ /* For grid based pbvh, take the vert whose loop corresponds to the current grid.
+ * Otherwise, take the current vert. */
+ const int v_index = has_grids ? data->me->mloop[vd.grid_indices[vd.g]].v :
+ vd.vert_indices[vd.i];
+ const float grid_alpha = has_grids ? 1.0f / vd.gridsize : 1.0f;
+ const MVert *mv_curr = &data->me->mvert[v_index];
+
+ /* If the vertex is selected */
+ if (!(use_face_sel || use_vert_sel) || mv_curr->flag & SELECT) {
+ float brush_strength = cache->bstrength;
+ const float angle_cos = (use_normal && vd.no) ?
+ dot_vf3vs3(sculpt_normal_frontface, vd.no) :
+ 1.0f;
+ if (((brush->flag & BRUSH_FRONTFACE) == 0 || (angle_cos > 0.0f)) &&
+ ((brush->flag & BRUSH_FRONTFACE_FALLOFF) == 0 ||
+ view_angle_limits_apply_falloff(
+ &data->wpd->normal_angle_precalc, angle_cos, &brush_strength))) {
+ bool do_color = false;
+ /* Minimum dot product between brush direction and current
+ * to neighbor direction is 0.0, meaning orthogonal. */
+ float stroke_dot_max = 0.0f;
+
+ /* Get the color of the loop in the opposite direction of the brush movement
+ * (this callback is specifically for smear.) */
+ float weight_final = 0.0;
+ for (int j = 0; j < gmap->vert_to_poly[v_index].count; j++) {
+ const int p_index = gmap->vert_to_poly[v_index].indices[j];
+ const MPoly *mp = &data->me->mpoly[p_index];
+ const MLoop *ml_other = &data->me->mloop[mp->loopstart];
+ for (int k = 0; k < mp->totloop; k++, ml_other++) {
+ const uint v_other_index = ml_other->v;
+ if (v_other_index != v_index) {
+ const MVert *mv_other = &data->me->mvert[v_other_index];
+
+ /* Get the direction from the selected vert to the neighbor. */
+ float other_dir[3];
+ sub_v3_v3v3(other_dir, mv_curr->co, mv_other->co);
+ project_plane_v3_v3v3(other_dir, other_dir, cache->view_normal);
+
+ normalize_v3(other_dir);
+
+ const float stroke_dot = dot_v3v3(other_dir, brush_dir);
+
+ if (stroke_dot > stroke_dot_max) {
+ stroke_dot_max = stroke_dot;
+ weight_final = data->wpd->precomputed_weight[v_other_index];
+ do_color = true;
+ }
+ }
+ }
+ }
+ /* Apply weight to vertex */
+ if (do_color) {
+ const float brush_fade = BKE_brush_curve_strength(
+ brush, sqrtf(test.dist), cache->radius);
+ const float final_alpha = brush_fade * brush_strength * grid_alpha *
+ brush_alpha_pressure;
+
+ if (final_alpha <= 0.0f)
+ continue;
+
+ do_weight_paint_vertex(
+ data->vp, data->ob, data->wpi, v_index, final_alpha, (float)weight_final);
+ }
+ }
+ }
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+ }
+}
+
+static void do_wpaint_brush_draw_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ const PBVHType pbvh_type = BKE_pbvh_type(ss->pbvh);
+ const bool has_grids = (pbvh_type == PBVH_GRIDS);
+ const Scene *scene = CTX_data_scene(data->C);
+
+ const Brush *brush = data->brush;
+ const StrokeCache *cache = ss->cache;
+ /* note: normally `BKE_brush_weight_get(scene, brush)` is used,
+ * however in this case we calculate a new weight each time. */
+ const float paintweight = data->strength;
+ float brush_size_pressure, brush_alpha_value, brush_alpha_pressure;
+ get_brush_alpha_data(
+ scene, ss, brush, &brush_size_pressure, &brush_alpha_value, &brush_alpha_pressure);
+ const bool use_normal = vwpaint_use_normal(data->vp);
+ const bool use_face_sel = (data->me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
+ 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);
+ const float *sculpt_normal_frontface = sculpt_brush_frontface_normal_from_falloff_shape(
+ ss, data->brush->falloff_shape);
+
+ /* For each vertex */
+ PBVHVertexIter vd;
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
+ {
+ /* Test to see if the vertex coordinates are within the spherical brush region. */
+ if (sculpt_brush_test_sq_fn(&test, vd.co)) {
+ /* Note: grids are 1:1 with corners (aka loops).
+ * For multires, take the vert whose loop corresponds to the current grid.
+ * Otherwise, take the current vert. */
+ const int v_index = has_grids ? data->me->mloop[vd.grid_indices[vd.g]].v :
+ vd.vert_indices[vd.i];
+ const float grid_alpha = has_grids ? 1.0f / vd.gridsize : 1.0f;
+
+ const char v_flag = data->me->mvert[v_index].flag;
+ /* If the vertex is selected */
+ if (!(use_face_sel || use_vert_sel) || v_flag & SELECT) {
+ float brush_strength = cache->bstrength;
+ const float angle_cos = (use_normal && vd.no) ?
+ dot_vf3vs3(sculpt_normal_frontface, vd.no) :
+ 1.0f;
+ if (((brush->flag & BRUSH_FRONTFACE) == 0 || (angle_cos > 0.0f)) &&
+ ((brush->flag & BRUSH_FRONTFACE_FALLOFF) == 0 ||
+ view_angle_limits_apply_falloff(
+ &data->wpd->normal_angle_precalc, angle_cos, &brush_strength))) {
+ const float brush_fade = BKE_brush_curve_strength(
+ brush, sqrtf(test.dist), cache->radius);
+ const float final_alpha = brush_fade * brush_strength * grid_alpha *
+ brush_alpha_pressure;
+
+ if ((brush->flag & BRUSH_ACCUMULATE) == 0) {
+ if (ss->mode.wpaint.alpha_weight[v_index] < final_alpha) {
+ ss->mode.wpaint.alpha_weight[v_index] = final_alpha;
+ }
+ else {
+ continue;
+ }
+ }
+
+ do_weight_paint_vertex(data->vp, data->ob, data->wpi, v_index, final_alpha, paintweight);
+ }
+ }
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
}
static void do_wpaint_brush_calc_average_weight_cb_ex(
- void *__restrict userdata,
- const int n,
- const ParallelRangeTLS *__restrict UNUSED(tls))
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- StrokeCache *cache = ss->cache;
- const PBVHType pbvh_type = BKE_pbvh_type(ss->pbvh);
- const bool has_grids = (pbvh_type == PBVH_GRIDS);
-
- const bool use_normal = vwpaint_use_normal(data->vp);
- const bool use_face_sel = (data->me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
- const bool use_vert_sel = (data->me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0;
-
- struct WPaintAverageAccum *accum = (struct WPaintAverageAccum *)data->custom_data + n;
- accum->len = 0;
- 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);
- const float *sculpt_normal_frontface =
- sculpt_brush_frontface_normal_from_falloff_shape(ss, data->brush->falloff_shape);
-
- /* For each vertex */
- PBVHVertexIter vd;
- BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
- {
- /* Test to see if the vertex coordinates are within the spherical brush region. */
- if (sculpt_brush_test_sq_fn(&test, vd.co)) {
- const float angle_cos = (use_normal && vd.no) ?
- dot_vf3vs3(sculpt_normal_frontface, vd.no) : 1.0f;
- if (angle_cos > 0.0 && BKE_brush_curve_strength(data->brush, sqrtf(test.dist), cache->radius) > 0.0) {
- const int v_index = has_grids ? data->me->mloop[vd.grid_indices[vd.g]].v : vd.vert_indices[vd.i];
- // const float grid_alpha = has_grids ? 1.0f / vd.gridsize : 1.0f;
- const char v_flag = data->me->mvert[v_index].flag;
-
- /* If the vertex is selected. */
- if (!(use_face_sel || use_vert_sel) || v_flag & SELECT) {
- const MDeformVert *dv = &data->me->dvert[v_index];
- accum->len += 1;
- accum->value += wpaint_get_active_weight(dv, data->wpi);
- }
- }
- }
- }
- BKE_pbvh_vertex_iter_end;
-}
-
-static void calculate_average_weight(SculptThreadedTaskData *data, PBVHNode **UNUSED(nodes), int totnode)
-{
- struct WPaintAverageAccum *accum = MEM_mallocN(sizeof(*accum) * totnode, __func__);
- data->custom_data = accum;
-
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((data->sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
- BLI_task_parallel_range(
- 0, totnode,
- data,
- do_wpaint_brush_calc_average_weight_cb_ex,
- &settings);
-
- uint accum_len = 0;
- double accum_weight = 0.0;
- for (int i = 0; i < totnode; i++) {
- accum_len += accum[i].len;
- accum_weight += accum[i].value;
- }
- if (accum_len != 0) {
- accum_weight /= accum_len;
- data->strength = (float)accum_weight;
- }
-
- MEM_SAFE_FREE(data->custom_data); /* 'accum' */
-}
-
-
-static void wpaint_paint_leaves(
- bContext *C, Object *ob, Sculpt *sd, VPaint *vp, struct WPaintData *wpd, WeightPaintInfo *wpi,
- Mesh *me, PBVHNode **nodes, int totnode)
-{
- Scene *scene = CTX_data_scene(C);
- const Brush *brush = ob->sculpt->cache->brush;
-
- /* threaded loop over nodes */
- SculptThreadedTaskData data = {
- .C = C, .sd = sd, .ob = ob, .brush = brush, .nodes = nodes,
- .vp = vp, .wpd = wpd, .wpi = wpi, .me = me,
- };
-
- /* Use this so average can modify its weight without touching the brush. */
- data.strength = BKE_brush_weight_get(scene, brush);
-
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- /* NOTE: current mirroring code cannot be run in parallel */
- settings.use_threading = !(me->editflag & ME_EDIT_MIRROR_X);
-
- switch ((eBrushWeightPaintTool)brush->weightpaint_tool) {
- case WPAINT_TOOL_AVERAGE:
- calculate_average_weight(&data, nodes, totnode);
- BLI_task_parallel_range(
- 0, totnode,
- &data,
- do_wpaint_brush_draw_task_cb_ex,
- &settings);
- break;
- case WPAINT_TOOL_SMEAR:
- BLI_task_parallel_range(
- 0, totnode,
- &data,
- do_wpaint_brush_smear_task_cb_ex,
- &settings);
- break;
- case WPAINT_TOOL_BLUR:
- BLI_task_parallel_range(
- 0, totnode,
- &data,
- do_wpaint_brush_blur_task_cb_ex,
- &settings);
- break;
- case WPAINT_TOOL_DRAW:
- BLI_task_parallel_range(
- 0, totnode,
- &data,
- do_wpaint_brush_draw_task_cb_ex,
- &settings);
- break;
- }
+ void *__restrict userdata, const int n, const ParallelRangeTLS *__restrict UNUSED(tls))
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ StrokeCache *cache = ss->cache;
+ const PBVHType pbvh_type = BKE_pbvh_type(ss->pbvh);
+ const bool has_grids = (pbvh_type == PBVH_GRIDS);
+
+ const bool use_normal = vwpaint_use_normal(data->vp);
+ const bool use_face_sel = (data->me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
+ const bool use_vert_sel = (data->me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0;
+
+ struct WPaintAverageAccum *accum = (struct WPaintAverageAccum *)data->custom_data + n;
+ accum->len = 0;
+ 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);
+ const float *sculpt_normal_frontface = sculpt_brush_frontface_normal_from_falloff_shape(
+ ss, data->brush->falloff_shape);
+
+ /* For each vertex */
+ PBVHVertexIter vd;
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
+ {
+ /* Test to see if the vertex coordinates are within the spherical brush region. */
+ if (sculpt_brush_test_sq_fn(&test, vd.co)) {
+ const float angle_cos = (use_normal && vd.no) ? dot_vf3vs3(sculpt_normal_frontface, vd.no) :
+ 1.0f;
+ if (angle_cos > 0.0 &&
+ BKE_brush_curve_strength(data->brush, sqrtf(test.dist), cache->radius) > 0.0) {
+ const int v_index = has_grids ? data->me->mloop[vd.grid_indices[vd.g]].v :
+ vd.vert_indices[vd.i];
+ // const float grid_alpha = has_grids ? 1.0f / vd.gridsize : 1.0f;
+ const char v_flag = data->me->mvert[v_index].flag;
+
+ /* If the vertex is selected. */
+ if (!(use_face_sel || use_vert_sel) || v_flag & SELECT) {
+ const MDeformVert *dv = &data->me->dvert[v_index];
+ accum->len += 1;
+ accum->value += wpaint_get_active_weight(dv, data->wpi);
+ }
+ }
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+static void calculate_average_weight(SculptThreadedTaskData *data,
+ PBVHNode **UNUSED(nodes),
+ int totnode)
+{
+ struct WPaintAverageAccum *accum = MEM_mallocN(sizeof(*accum) * totnode, __func__);
+ data->custom_data = accum;
+
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = ((data->sd->flags & SCULPT_USE_OPENMP) &&
+ totnode > SCULPT_THREADED_LIMIT);
+ BLI_task_parallel_range(0, totnode, data, do_wpaint_brush_calc_average_weight_cb_ex, &settings);
+
+ uint accum_len = 0;
+ double accum_weight = 0.0;
+ for (int i = 0; i < totnode; i++) {
+ accum_len += accum[i].len;
+ accum_weight += accum[i].value;
+ }
+ if (accum_len != 0) {
+ accum_weight /= accum_len;
+ data->strength = (float)accum_weight;
+ }
+
+ MEM_SAFE_FREE(data->custom_data); /* 'accum' */
+}
+
+static void wpaint_paint_leaves(bContext *C,
+ Object *ob,
+ Sculpt *sd,
+ VPaint *vp,
+ struct WPaintData *wpd,
+ WeightPaintInfo *wpi,
+ Mesh *me,
+ PBVHNode **nodes,
+ int totnode)
+{
+ Scene *scene = CTX_data_scene(C);
+ const Brush *brush = ob->sculpt->cache->brush;
+
+ /* threaded loop over nodes */
+ SculptThreadedTaskData data = {
+ .C = C,
+ .sd = sd,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ .vp = vp,
+ .wpd = wpd,
+ .wpi = wpi,
+ .me = me,
+ };
+
+ /* Use this so average can modify its weight without touching the brush. */
+ data.strength = BKE_brush_weight_get(scene, brush);
+
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ /* NOTE: current mirroring code cannot be run in parallel */
+ settings.use_threading = !(me->editflag & ME_EDIT_MIRROR_X);
+
+ switch ((eBrushWeightPaintTool)brush->weightpaint_tool) {
+ case WPAINT_TOOL_AVERAGE:
+ calculate_average_weight(&data, nodes, totnode);
+ BLI_task_parallel_range(0, totnode, &data, do_wpaint_brush_draw_task_cb_ex, &settings);
+ break;
+ case WPAINT_TOOL_SMEAR:
+ BLI_task_parallel_range(0, totnode, &data, do_wpaint_brush_smear_task_cb_ex, &settings);
+ break;
+ case WPAINT_TOOL_BLUR:
+ BLI_task_parallel_range(0, totnode, &data, do_wpaint_brush_blur_task_cb_ex, &settings);
+ break;
+ case WPAINT_TOOL_DRAW:
+ BLI_task_parallel_range(0, totnode, &data, do_wpaint_brush_draw_task_cb_ex, &settings);
+ break;
+ }
}
static PBVHNode **vwpaint_pbvh_gather_generic(
- Object *ob, VPaint *wp, Sculpt *sd, Brush *brush, int *r_totnode)
-{
- SculptSession *ss = ob->sculpt;
- const bool use_normal = vwpaint_use_normal(wp);
- PBVHNode **nodes = NULL;
-
- /* Build a list of all nodes that are potentially within the brush's area of influence */
- if (brush->falloff_shape == PAINT_FALLOFF_SHAPE_SPHERE) {
- SculptSearchSphereData data = {
- .ss = ss,
- .sd = sd,
- .radius_squared = ss->cache->radius_squared,
- .original = true,
- };
- BKE_pbvh_search_gather(ss->pbvh, sculpt_search_sphere_cb, &data, &nodes, r_totnode);
- if (use_normal) {
- sculpt_pbvh_calc_area_normal(brush, ob, nodes, *r_totnode, true, ss->cache->sculpt_normal_symm);
- }
- else {
- zero_v3(ss->cache->sculpt_normal_symm);
- }
- }
- else {
- struct DistRayAABB_Precalc dist_ray_to_aabb_precalc;
- dist_squared_ray_to_aabb_v3_precalc(&dist_ray_to_aabb_precalc, ss->cache->location, ss->cache->view_normal);
- SculptSearchCircleData data = {
- .ss = ss,
- .sd = sd,
- .radius_squared = ss->cache->radius_squared,
- .original = true,
- .dist_ray_to_aabb_precalc = &dist_ray_to_aabb_precalc,
- };
- BKE_pbvh_search_gather(ss->pbvh, sculpt_search_circle_cb, &data, &nodes, r_totnode);
- if (use_normal) {
- copy_v3_v3(ss->cache->sculpt_normal_symm, ss->cache->view_normal);
- }
- else {
- zero_v3(ss->cache->sculpt_normal_symm);
- }
- }
- return nodes;
-}
-
-static void wpaint_do_paint(
- bContext *C, Object *ob, VPaint *wp, Sculpt *sd, struct WPaintData *wpd, WeightPaintInfo *wpi,
- Mesh *me, Brush *brush, const char symm, const int axis, const int i, const float angle)
-{
- SculptSession *ss = ob->sculpt;
- ss->cache->radial_symmetry_pass = i;
- sculpt_cache_calc_brushdata_symm(ss->cache, symm, axis, angle);
-
- int totnode;
- PBVHNode **nodes = vwpaint_pbvh_gather_generic(ob, wp, sd, brush, &totnode);
-
- wpaint_paint_leaves(C, ob, sd, wp, wpd, wpi, me, nodes, totnode);
-
- if (nodes)
- MEM_freeN(nodes);
-}
-
-static void wpaint_do_radial_symmetry(
- bContext *C, Object *ob, VPaint *wp, Sculpt *sd, struct WPaintData *wpd, WeightPaintInfo *wpi,
- Mesh *me, Brush *brush, const char symm, const int axis)
-{
- for (int i = 1; i < wp->radial_symm[axis - 'X']; i++) {
- const float angle = (2.0 * M_PI) * i / wp->radial_symm[axis - 'X'];
- wpaint_do_paint(C, ob, wp, sd, wpd, wpi, me, brush, symm, axis, i, angle);
- }
+ Object *ob, VPaint *wp, Sculpt *sd, Brush *brush, int *r_totnode)
+{
+ SculptSession *ss = ob->sculpt;
+ const bool use_normal = vwpaint_use_normal(wp);
+ PBVHNode **nodes = NULL;
+
+ /* Build a list of all nodes that are potentially within the brush's area of influence */
+ if (brush->falloff_shape == PAINT_FALLOFF_SHAPE_SPHERE) {
+ SculptSearchSphereData data = {
+ .ss = ss,
+ .sd = sd,
+ .radius_squared = ss->cache->radius_squared,
+ .original = true,
+ };
+ BKE_pbvh_search_gather(ss->pbvh, sculpt_search_sphere_cb, &data, &nodes, r_totnode);
+ if (use_normal) {
+ sculpt_pbvh_calc_area_normal(
+ brush, ob, nodes, *r_totnode, true, ss->cache->sculpt_normal_symm);
+ }
+ else {
+ zero_v3(ss->cache->sculpt_normal_symm);
+ }
+ }
+ else {
+ struct DistRayAABB_Precalc dist_ray_to_aabb_precalc;
+ dist_squared_ray_to_aabb_v3_precalc(
+ &dist_ray_to_aabb_precalc, ss->cache->location, ss->cache->view_normal);
+ SculptSearchCircleData data = {
+ .ss = ss,
+ .sd = sd,
+ .radius_squared = ss->cache->radius_squared,
+ .original = true,
+ .dist_ray_to_aabb_precalc = &dist_ray_to_aabb_precalc,
+ };
+ BKE_pbvh_search_gather(ss->pbvh, sculpt_search_circle_cb, &data, &nodes, r_totnode);
+ if (use_normal) {
+ copy_v3_v3(ss->cache->sculpt_normal_symm, ss->cache->view_normal);
+ }
+ else {
+ zero_v3(ss->cache->sculpt_normal_symm);
+ }
+ }
+ return nodes;
+}
+
+static void wpaint_do_paint(bContext *C,
+ Object *ob,
+ VPaint *wp,
+ Sculpt *sd,
+ struct WPaintData *wpd,
+ WeightPaintInfo *wpi,
+ Mesh *me,
+ Brush *brush,
+ const char symm,
+ const int axis,
+ const int i,
+ const float angle)
+{
+ SculptSession *ss = ob->sculpt;
+ ss->cache->radial_symmetry_pass = i;
+ sculpt_cache_calc_brushdata_symm(ss->cache, symm, axis, angle);
+
+ int totnode;
+ PBVHNode **nodes = vwpaint_pbvh_gather_generic(ob, wp, sd, brush, &totnode);
+
+ wpaint_paint_leaves(C, ob, sd, wp, wpd, wpi, me, nodes, totnode);
+
+ if (nodes)
+ MEM_freeN(nodes);
+}
+
+static void wpaint_do_radial_symmetry(bContext *C,
+ Object *ob,
+ VPaint *wp,
+ Sculpt *sd,
+ struct WPaintData *wpd,
+ WeightPaintInfo *wpi,
+ Mesh *me,
+ Brush *brush,
+ const char symm,
+ const int axis)
+{
+ for (int i = 1; i < wp->radial_symm[axis - 'X']; i++) {
+ const float angle = (2.0 * M_PI) * i / wp->radial_symm[axis - 'X'];
+ wpaint_do_paint(C, ob, wp, sd, wpd, wpi, me, brush, symm, axis, i, angle);
+ }
}
/* near duplicate of: sculpt.c's,
* 'do_symmetrical_brush_actions' and 'vpaint_do_symmetrical_brush_actions'. */
static void wpaint_do_symmetrical_brush_actions(
- bContext *C, Object *ob, VPaint *wp, Sculpt *sd, struct WPaintData *wpd, WeightPaintInfo *wpi)
-{
- Brush *brush = BKE_paint_brush(&wp->paint);
- Mesh *me = ob->data;
- SculptSession *ss = ob->sculpt;
- StrokeCache *cache = ss->cache;
- const char symm = wp->paint.symmetry_flags & PAINT_SYMM_AXIS_ALL;
- int i = 0;
-
- /* initial stroke */
- wpaint_do_paint(C, ob, wp, sd, wpd, wpi, me, brush, 0, 'X', 0, 0);
- wpaint_do_radial_symmetry(C, ob, wp, sd, wpd, wpi, me, brush, 0, 'X');
- wpaint_do_radial_symmetry(C, ob, wp, sd, wpd, wpi, me, brush, 0, 'Y');
- wpaint_do_radial_symmetry(C, ob, wp, sd, wpd, wpi, me, brush, 0, 'Z');
-
- cache->symmetry = symm;
-
- /* symm is a bit combination of XYZ - 1 is mirror
- * X; 2 is Y; 3 is XY; 4 is Z; 5 is XZ; 6 is YZ; 7 is XYZ */
- for (i = 1; i <= symm; i++) {
- if ((symm & i && (symm != 5 || i != 3) && (symm != 6 || (i != 3 && i != 5)))) {
- cache->mirror_symmetry_pass = i;
- cache->radial_symmetry_pass = 0;
- sculpt_cache_calc_brushdata_symm(cache, i, 0, 0);
-
- if (i & (1 << 0)) {
- wpaint_do_paint(C, ob, wp, sd, wpd, wpi, me, brush, i, 'X', 0, 0);
- wpaint_do_radial_symmetry(C, ob, wp, sd, wpd, wpi, me, brush, i, 'X');
- }
- if (i & (1 << 1)) {
- wpaint_do_paint(C, ob, wp, sd, wpd, wpi, me, brush, i, 'Y', 0, 0);
- wpaint_do_radial_symmetry(C, ob, wp, sd, wpd, wpi, me, brush, i, 'Y');
- }
- if (i & (1 << 2)) {
- wpaint_do_paint(C, ob, wp, sd, wpd, wpi, me, brush, i, 'Z', 0, 0);
- wpaint_do_radial_symmetry(C, ob, wp, sd, wpd, wpi, me, brush, i, 'Z');
- }
- }
- }
- copy_v3_v3(cache->true_last_location, cache->true_location);
- cache->is_last_valid = true;
+ bContext *C, Object *ob, VPaint *wp, Sculpt *sd, struct WPaintData *wpd, WeightPaintInfo *wpi)
+{
+ Brush *brush = BKE_paint_brush(&wp->paint);
+ Mesh *me = ob->data;
+ SculptSession *ss = ob->sculpt;
+ StrokeCache *cache = ss->cache;
+ const char symm = wp->paint.symmetry_flags & PAINT_SYMM_AXIS_ALL;
+ int i = 0;
+
+ /* initial stroke */
+ wpaint_do_paint(C, ob, wp, sd, wpd, wpi, me, brush, 0, 'X', 0, 0);
+ wpaint_do_radial_symmetry(C, ob, wp, sd, wpd, wpi, me, brush, 0, 'X');
+ wpaint_do_radial_symmetry(C, ob, wp, sd, wpd, wpi, me, brush, 0, 'Y');
+ wpaint_do_radial_symmetry(C, ob, wp, sd, wpd, wpi, me, brush, 0, 'Z');
+
+ cache->symmetry = symm;
+
+ /* symm is a bit combination of XYZ - 1 is mirror
+ * X; 2 is Y; 3 is XY; 4 is Z; 5 is XZ; 6 is YZ; 7 is XYZ */
+ for (i = 1; i <= symm; i++) {
+ if ((symm & i && (symm != 5 || i != 3) && (symm != 6 || (i != 3 && i != 5)))) {
+ cache->mirror_symmetry_pass = i;
+ cache->radial_symmetry_pass = 0;
+ sculpt_cache_calc_brushdata_symm(cache, i, 0, 0);
+
+ if (i & (1 << 0)) {
+ wpaint_do_paint(C, ob, wp, sd, wpd, wpi, me, brush, i, 'X', 0, 0);
+ wpaint_do_radial_symmetry(C, ob, wp, sd, wpd, wpi, me, brush, i, 'X');
+ }
+ if (i & (1 << 1)) {
+ wpaint_do_paint(C, ob, wp, sd, wpd, wpi, me, brush, i, 'Y', 0, 0);
+ wpaint_do_radial_symmetry(C, ob, wp, sd, wpd, wpi, me, brush, i, 'Y');
+ }
+ if (i & (1 << 2)) {
+ wpaint_do_paint(C, ob, wp, sd, wpd, wpi, me, brush, i, 'Z', 0, 0);
+ wpaint_do_radial_symmetry(C, ob, wp, sd, wpd, wpi, me, brush, i, 'Z');
+ }
+ }
+ }
+ copy_v3_v3(cache->true_last_location, cache->true_location);
+ cache->is_last_valid = true;
}
static void wpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, PointerRNA *itemptr)
{
- Scene *scene = CTX_data_scene(C);
- ToolSettings *ts = CTX_data_tool_settings(C);
- VPaint *wp = ts->wpaint;
- Brush *brush = BKE_paint_brush(&wp->paint);
- struct WPaintData *wpd = paint_stroke_mode_data(stroke);
- ViewContext *vc;
- Object *ob = CTX_data_active_object(C);
-
- SculptSession *ss = ob->sculpt;
- Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
+ Scene *scene = CTX_data_scene(C);
+ ToolSettings *ts = CTX_data_tool_settings(C);
+ VPaint *wp = ts->wpaint;
+ Brush *brush = BKE_paint_brush(&wp->paint);
+ struct WPaintData *wpd = paint_stroke_mode_data(stroke);
+ ViewContext *vc;
+ Object *ob = CTX_data_active_object(C);
- vwpaint_update_cache_variants(C, wp, ob, itemptr);
+ SculptSession *ss = ob->sculpt;
+ Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
- float mat[4][4];
- float mval[2];
+ vwpaint_update_cache_variants(C, wp, ob, itemptr);
- const float brush_alpha_value = BKE_brush_alpha_get(scene, brush);
+ float mat[4][4];
+ float mval[2];
- /* intentionally don't initialize as NULL, make sure we initialize all members below */
- WeightPaintInfo wpi;
+ const float brush_alpha_value = BKE_brush_alpha_get(scene, brush);
- /* cannot paint if there is no stroke data */
- if (wpd == NULL) {
- /* XXX: force a redraw here, since even though we can't paint,
- * at least view won't freeze until stroke ends */
- ED_region_tag_redraw(CTX_wm_region(C));
- return;
- }
+ /* intentionally don't initialize as NULL, make sure we initialize all members below */
+ WeightPaintInfo wpi;
- vc = &wpd->vc;
- ob = vc->obact;
+ /* cannot paint if there is no stroke data */
+ if (wpd == NULL) {
+ /* XXX: force a redraw here, since even though we can't paint,
+ * at least view won't freeze until stroke ends */
+ ED_region_tag_redraw(CTX_wm_region(C));
+ return;
+ }
- view3d_operator_needs_opengl(C);
- ED_view3d_init_mats_rv3d(ob, vc->rv3d);
+ vc = &wpd->vc;
+ ob = vc->obact;
- /* load projection matrix */
- mul_m4_m4m4(mat, vc->rv3d->persmat, ob->obmat);
+ view3d_operator_needs_opengl(C);
+ ED_view3d_init_mats_rv3d(ob, vc->rv3d);
+ /* load projection matrix */
+ mul_m4_m4m4(mat, vc->rv3d->persmat, ob->obmat);
- /* *** setup WeightPaintInfo - pass onto do_weight_paint_vertex *** */
- wpi.defbase_tot = wpd->defbase_tot;
- wpi.defbase_sel = wpd->defbase_sel;
- wpi.defbase_tot_sel = wpd->defbase_tot_sel;
+ /* *** setup WeightPaintInfo - pass onto do_weight_paint_vertex *** */
+ wpi.defbase_tot = wpd->defbase_tot;
+ wpi.defbase_sel = wpd->defbase_sel;
+ wpi.defbase_tot_sel = wpd->defbase_tot_sel;
- wpi.defbase_tot_unsel = wpi.defbase_tot - wpi.defbase_tot_sel;
- wpi.active = wpd->active;
- wpi.mirror = wpd->mirror;
- wpi.lock_flags = wpd->lock_flags;
- wpi.vgroup_validmap = wpd->vgroup_validmap;
- wpi.do_flip = RNA_boolean_get(itemptr, "pen_flip");
- wpi.do_multipaint = wpd->do_multipaint;
- wpi.do_auto_normalize = ((ts->auto_normalize != 0) && (wpi.vgroup_validmap != NULL));
- wpi.brush_alpha_value = brush_alpha_value;
- /* *** done setting up WeightPaintInfo *** */
+ wpi.defbase_tot_unsel = wpi.defbase_tot - wpi.defbase_tot_sel;
+ wpi.active = wpd->active;
+ wpi.mirror = wpd->mirror;
+ wpi.lock_flags = wpd->lock_flags;
+ wpi.vgroup_validmap = wpd->vgroup_validmap;
+ wpi.do_flip = RNA_boolean_get(itemptr, "pen_flip");
+ wpi.do_multipaint = wpd->do_multipaint;
+ wpi.do_auto_normalize = ((ts->auto_normalize != 0) && (wpi.vgroup_validmap != NULL));
+ wpi.brush_alpha_value = brush_alpha_value;
+ /* *** done setting up WeightPaintInfo *** */
- if (wpd->precomputed_weight) {
- precompute_weight_values(C, ob, brush, wpd, &wpi, ob->data);
- }
+ if (wpd->precomputed_weight) {
+ precompute_weight_values(C, ob, brush, wpd, &wpi, ob->data);
+ }
- wpaint_do_symmetrical_brush_actions(C, ob, wp, sd, wpd, &wpi);
+ wpaint_do_symmetrical_brush_actions(C, ob, wp, sd, wpd, &wpi);
- swap_m4m4(vc->rv3d->persmat, mat);
+ swap_m4m4(vc->rv3d->persmat, mat);
- /* calculate pivot for rotation around seletion if needed */
- /* also needed for "View Selected" on last stroke */
- paint_last_stroke_update(scene, vc->ar, mval);
+ /* calculate pivot for rotation around seletion if needed */
+ /* also needed for "View Selected" on last stroke */
+ paint_last_stroke_update(scene, vc->ar, mval);
- BKE_mesh_batch_cache_dirty_tag(ob->data, BKE_MESH_BATCH_DIRTY_ALL);
+ BKE_mesh_batch_cache_dirty_tag(ob->data, BKE_MESH_BATCH_DIRTY_ALL);
- DEG_id_tag_update(ob->data, 0);
- WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
- swap_m4m4(wpd->vc.rv3d->persmat, mat);
+ DEG_id_tag_update(ob->data, 0);
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
+ swap_m4m4(wpd->vc.rv3d->persmat, mat);
- rcti r;
- if (sculpt_get_redraw_rect(vc->ar, CTX_wm_region_view3d(C), ob, &r)) {
- if (ss->cache) {
- ss->cache->current_r = r;
- }
+ rcti r;
+ if (sculpt_get_redraw_rect(vc->ar, CTX_wm_region_view3d(C), ob, &r)) {
+ if (ss->cache) {
+ ss->cache->current_r = r;
+ }
- /* previous is not set in the current cache else
- * the partial rect will always grow */
- if (ss->cache) {
- if (!BLI_rcti_is_empty(&ss->cache->previous_r))
- BLI_rcti_union(&r, &ss->cache->previous_r);
- }
+ /* previous is not set in the current cache else
+ * the partial rect will always grow */
+ if (ss->cache) {
+ if (!BLI_rcti_is_empty(&ss->cache->previous_r))
+ BLI_rcti_union(&r, &ss->cache->previous_r);
+ }
- r.xmin += vc->ar->winrct.xmin - 2;
- r.xmax += vc->ar->winrct.xmin + 2;
- r.ymin += vc->ar->winrct.ymin - 2;
- r.ymax += vc->ar->winrct.ymin + 2;
+ r.xmin += vc->ar->winrct.xmin - 2;
+ r.xmax += vc->ar->winrct.xmin + 2;
+ r.ymin += vc->ar->winrct.ymin - 2;
+ r.ymax += vc->ar->winrct.ymin + 2;
- ss->partial_redraw = 1;
- }
- ED_region_tag_redraw_partial(vc->ar, &r);
+ ss->partial_redraw = 1;
+ }
+ ED_region_tag_redraw_partial(vc->ar, &r);
}
static void wpaint_stroke_done(const bContext *C, struct PaintStroke *stroke)
{
- Object *ob = CTX_data_active_object(C);
- struct WPaintData *wpd = paint_stroke_mode_data(stroke);
-
- if (wpd) {
- if (wpd->defbase_sel)
- MEM_freeN((void *)wpd->defbase_sel);
- if (wpd->vgroup_validmap)
- MEM_freeN((void *)wpd->vgroup_validmap);
- if (wpd->lock_flags)
- MEM_freeN((void *)wpd->lock_flags);
- if (wpd->active.lock)
- MEM_freeN((void *)wpd->active.lock);
- if (wpd->mirror.lock)
- MEM_freeN((void *)wpd->mirror.lock);
- if (wpd->precomputed_weight)
- MEM_freeN(wpd->precomputed_weight);
-
- MEM_freeN(wpd);
- }
-
- /* and particles too */
- if (ob->particlesystem.first) {
- ParticleSystem *psys;
- int i;
-
- for (psys = ob->particlesystem.first; psys; psys = psys->next) {
- for (i = 0; i < PSYS_TOT_VG; i++) {
- if (psys->vgroup[i] == ob->actdef) {
- psys->recalc |= ID_RECALC_PSYS_RESET;
- break;
- }
- }
- }
- }
-
- DEG_id_tag_update(ob->data, 0);
-
- WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
-
- sculpt_cache_free(ob->sculpt->cache);
- ob->sculpt->cache = NULL;
+ Object *ob = CTX_data_active_object(C);
+ struct WPaintData *wpd = paint_stroke_mode_data(stroke);
+
+ if (wpd) {
+ if (wpd->defbase_sel)
+ MEM_freeN((void *)wpd->defbase_sel);
+ if (wpd->vgroup_validmap)
+ MEM_freeN((void *)wpd->vgroup_validmap);
+ if (wpd->lock_flags)
+ MEM_freeN((void *)wpd->lock_flags);
+ if (wpd->active.lock)
+ MEM_freeN((void *)wpd->active.lock);
+ if (wpd->mirror.lock)
+ MEM_freeN((void *)wpd->mirror.lock);
+ if (wpd->precomputed_weight)
+ MEM_freeN(wpd->precomputed_weight);
+
+ MEM_freeN(wpd);
+ }
+
+ /* and particles too */
+ if (ob->particlesystem.first) {
+ ParticleSystem *psys;
+ int i;
+
+ for (psys = ob->particlesystem.first; psys; psys = psys->next) {
+ for (i = 0; i < PSYS_TOT_VG; i++) {
+ if (psys->vgroup[i] == ob->actdef) {
+ psys->recalc |= ID_RECALC_PSYS_RESET;
+ break;
+ }
+ }
+ }
+ }
+
+ DEG_id_tag_update(ob->data, 0);
+
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
+
+ sculpt_cache_free(ob->sculpt->cache);
+ ob->sculpt->cache = NULL;
}
-
static int wpaint_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
- int retval;
+ int retval;
- op->customdata = paint_stroke_new(
- C, op, sculpt_stroke_get_location, wpaint_stroke_test_start,
- wpaint_stroke_update_step, NULL,
- wpaint_stroke_done, event->type);
+ op->customdata = paint_stroke_new(C,
+ op,
+ sculpt_stroke_get_location,
+ wpaint_stroke_test_start,
+ wpaint_stroke_update_step,
+ NULL,
+ wpaint_stroke_done,
+ event->type);
- if ((retval = op->type->modal(C, op, event)) == OPERATOR_FINISHED) {
- paint_stroke_data_free(op);
- return OPERATOR_FINISHED;
- }
- /* add modal handler */
- WM_event_add_modal_handler(C, op);
+ if ((retval = op->type->modal(C, op, event)) == OPERATOR_FINISHED) {
+ paint_stroke_data_free(op);
+ return OPERATOR_FINISHED;
+ }
+ /* add modal handler */
+ WM_event_add_modal_handler(C, op);
- OPERATOR_RETVAL_CHECK(retval);
- BLI_assert(retval == OPERATOR_RUNNING_MODAL);
+ OPERATOR_RETVAL_CHECK(retval);
+ BLI_assert(retval == OPERATOR_RUNNING_MODAL);
- return OPERATOR_RUNNING_MODAL;
+ return OPERATOR_RUNNING_MODAL;
}
static int wpaint_exec(bContext *C, wmOperator *op)
{
- op->customdata = paint_stroke_new(
- C, op, sculpt_stroke_get_location, wpaint_stroke_test_start,
- wpaint_stroke_update_step, NULL,
- wpaint_stroke_done, 0);
+ op->customdata = paint_stroke_new(C,
+ op,
+ sculpt_stroke_get_location,
+ wpaint_stroke_test_start,
+ wpaint_stroke_update_step,
+ NULL,
+ wpaint_stroke_done,
+ 0);
- /* frees op->customdata */
- paint_stroke_exec(C, op);
+ /* frees op->customdata */
+ paint_stroke_exec(C, op);
- return OPERATOR_FINISHED;
+ return OPERATOR_FINISHED;
}
static void wpaint_cancel(bContext *C, wmOperator *op)
{
- Object *ob = CTX_data_active_object(C);
- if (ob->sculpt->cache) {
- sculpt_cache_free(ob->sculpt->cache);
- ob->sculpt->cache = NULL;
- }
+ Object *ob = CTX_data_active_object(C);
+ if (ob->sculpt->cache) {
+ sculpt_cache_free(ob->sculpt->cache);
+ ob->sculpt->cache = NULL;
+ }
- paint_stroke_cancel(C, op);
+ paint_stroke_cancel(C, op);
}
void PAINT_OT_weight_paint(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Weight Paint";
- ot->idname = "PAINT_OT_weight_paint";
- ot->description = "Paint a stroke in the current vertex group's weights";
+ /* identifiers */
+ ot->name = "Weight Paint";
+ ot->idname = "PAINT_OT_weight_paint";
+ ot->description = "Paint a stroke in the current vertex group's weights";
- /* api callbacks */
- ot->invoke = wpaint_invoke;
- ot->modal = paint_stroke_modal;
- ot->exec = wpaint_exec;
- ot->poll = weight_paint_poll;
- ot->cancel = wpaint_cancel;
+ /* api callbacks */
+ ot->invoke = wpaint_invoke;
+ ot->modal = paint_stroke_modal;
+ ot->exec = wpaint_exec;
+ ot->poll = weight_paint_poll;
+ ot->cancel = wpaint_cancel;
- /* flags */
- ot->flag = OPTYPE_UNDO | OPTYPE_BLOCKING;
+ /* flags */
+ ot->flag = OPTYPE_UNDO | OPTYPE_BLOCKING;
- paint_stroke_operator_properties(ot);
+ paint_stroke_operator_properties(ot);
}
/* ************ set / clear vertex paint mode ********** */
@@ -2392,64 +2446,62 @@ void PAINT_OT_weight_paint(wmOperatorType *ot)
*/
static int vpaint_mode_toggle_exec(bContext *C, wmOperator *op)
{
- Main *bmain = CTX_data_main(C);
- struct wmMsgBus *mbus = CTX_wm_message_bus(C);
- Object *ob = CTX_data_active_object(C);
- const int mode_flag = OB_MODE_VERTEX_PAINT;
- const bool is_mode_set = (ob->mode & mode_flag) != 0;
- Scene *scene = CTX_data_scene(C);
- ToolSettings *ts = scene->toolsettings;
+ Main *bmain = CTX_data_main(C);
+ struct wmMsgBus *mbus = CTX_wm_message_bus(C);
+ Object *ob = CTX_data_active_object(C);
+ const int mode_flag = OB_MODE_VERTEX_PAINT;
+ const bool is_mode_set = (ob->mode & mode_flag) != 0;
+ Scene *scene = CTX_data_scene(C);
+ ToolSettings *ts = scene->toolsettings;
- if (!is_mode_set) {
- if (!ED_object_mode_compat_set(C, ob, mode_flag, op->reports)) {
- return OPERATOR_CANCELLED;
- }
- }
+ if (!is_mode_set) {
+ if (!ED_object_mode_compat_set(C, ob, mode_flag, op->reports)) {
+ return OPERATOR_CANCELLED;
+ }
+ }
- Mesh *me = BKE_mesh_from_object(ob);
+ Mesh *me = BKE_mesh_from_object(ob);
- /* toggle: end vpaint */
- if (is_mode_set) {
- ED_object_vpaintmode_exit_ex(ob);
- }
- else {
- Depsgraph *depsgraph = CTX_data_depsgraph_on_load(C);
- wmWindowManager *wm = CTX_wm_manager(C);
- ED_object_vpaintmode_enter_ex(bmain, depsgraph, wm, scene, ob);
- BKE_paint_toolslots_brush_validate(bmain, &ts->vpaint->paint);
- }
+ /* toggle: end vpaint */
+ if (is_mode_set) {
+ ED_object_vpaintmode_exit_ex(ob);
+ }
+ else {
+ Depsgraph *depsgraph = CTX_data_depsgraph_on_load(C);
+ wmWindowManager *wm = CTX_wm_manager(C);
+ ED_object_vpaintmode_enter_ex(bmain, depsgraph, wm, scene, ob);
+ BKE_paint_toolslots_brush_validate(bmain, &ts->vpaint->paint);
+ }
- BKE_mesh_batch_cache_dirty_tag(ob->data, BKE_MESH_BATCH_DIRTY_ALL);
+ BKE_mesh_batch_cache_dirty_tag(ob->data, BKE_MESH_BATCH_DIRTY_ALL);
- /* update modifier stack for mapping requirements */
- DEG_id_tag_update(&me->id, 0);
+ /* update modifier stack for mapping requirements */
+ DEG_id_tag_update(&me->id, 0);
- WM_event_add_notifier(C, NC_SCENE | ND_MODE, scene);
+ WM_event_add_notifier(C, NC_SCENE | ND_MODE, scene);
- WM_msg_publish_rna_prop(mbus, &ob->id, ob, Object, mode);
+ WM_msg_publish_rna_prop(mbus, &ob->id, ob, Object, mode);
- WM_toolsystem_update_from_context_view3d(C);
+ WM_toolsystem_update_from_context_view3d(C);
- return OPERATOR_FINISHED;
+ return OPERATOR_FINISHED;
}
void PAINT_OT_vertex_paint_toggle(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Vertex Paint Mode";
- ot->idname = "PAINT_OT_vertex_paint_toggle";
- ot->description = "Toggle the vertex paint mode in 3D view";
+ /* identifiers */
+ ot->name = "Vertex Paint Mode";
+ ot->idname = "PAINT_OT_vertex_paint_toggle";
+ ot->description = "Toggle the vertex paint mode in 3D view";
- /* api callbacks */
- ot->exec = vpaint_mode_toggle_exec;
- ot->poll = paint_poll_test;
+ /* api callbacks */
+ ot->exec = vpaint_mode_toggle_exec;
+ ot->poll = paint_poll_test;
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_USE_EVAL_DATA;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_USE_EVAL_DATA;
}
-
-
/* ********************** vertex paint operator ******************* */
/* Implementation notes:
@@ -2471,815 +2523,847 @@ void PAINT_OT_vertex_paint_toggle(wmOperatorType *ot)
*/
typedef struct PolyFaceMap {
- struct PolyFaceMap *next, *prev;
- int facenr;
+ struct PolyFaceMap *next, *prev;
+ int facenr;
} PolyFaceMap;
struct VPaintData {
- ViewContext vc;
- struct NormalAnglePrecalc normal_angle_precalc;
+ ViewContext vc;
+ struct NormalAnglePrecalc normal_angle_precalc;
- uint paintcol;
+ uint paintcol;
- struct VertProjHandle *vp_handle;
- struct CoNo *vertexcosnos;
+ struct VertProjHandle *vp_handle;
+ struct CoNo *vertexcosnos;
- /* modify 'me->mcol' directly, since the derived mesh is drawing from this
- * array, otherwise we need to refresh the modifier stack */
- bool use_fast_update;
+ /* modify 'me->mcol' directly, since the derived mesh is drawing from this
+ * array, otherwise we need to refresh the modifier stack */
+ bool use_fast_update;
- /* loops tagged as having been painted, to apply shared vertex color
- * blending only to modified loops */
- bool *mlooptag;
+ /* loops tagged as having been painted, to apply shared vertex color
+ * blending only to modified loops */
+ bool *mlooptag;
- bool is_texbrush;
+ bool is_texbrush;
- /* Special storage for smear brush, avoid feedback loop - update each step. */
- struct {
- uint *color_prev;
- uint *color_curr;
- } smear;
+ /* Special storage for smear brush, avoid feedback loop - update each step. */
+ struct {
+ uint *color_prev;
+ uint *color_curr;
+ } smear;
};
static bool vpaint_stroke_test_start(bContext *C, struct wmOperator *op, const float mouse[2])
{
- Scene *scene = CTX_data_scene(C);
- ToolSettings *ts = scene->toolsettings;
- struct PaintStroke *stroke = op->customdata;
- VPaint *vp = ts->vpaint;
- Brush *brush = BKE_paint_brush(&vp->paint);
- struct VPaintData *vpd;
- Object *ob = CTX_data_active_object(C);
- Mesh *me;
- SculptSession *ss = ob->sculpt;
- Depsgraph *depsgraph = CTX_data_depsgraph(C);
-
- /* context checks could be a poll() */
- me = BKE_mesh_from_object(ob);
- if (me == NULL || me->totpoly == 0)
- return false;
-
- ED_mesh_color_ensure(me, NULL);
- if (me->mloopcol == NULL)
- return false;
-
- /* make mode data storage */
- vpd = MEM_callocN(sizeof(*vpd), "VPaintData");
- paint_stroke_set_mode_data(stroke, vpd);
- ED_view3d_viewcontext_init(C, &vpd->vc);
- view_angle_limits_init(
- &vpd->normal_angle_precalc, vp->paint.brush->falloff_angle,
- (vp->paint.brush->flag & BRUSH_FRONTFACE_FALLOFF) != 0);
-
- vpd->paintcol = vpaint_get_current_col(scene, vp, (RNA_enum_get(op->ptr, "mode") == BRUSH_STROKE_INVERT));
-
- vpd->is_texbrush = !(brush->vertexpaint_tool == VPAINT_TOOL_BLUR) && brush->mtex.tex;
-
- /* are we painting onto a modified mesh?,
- * if not we can skip face map trickiness */
- if (vertex_paint_use_fast_update_check(ob)) {
- vpd->use_fast_update = true;
-/* printf("Fast update!\n");*/
- }
- else {
- vpd->use_fast_update = false;
-/* printf("No fast update!\n");*/
- }
-
- /* to keep tracked of modified loops for shared vertex color blending */
- if (brush->vertexpaint_tool == VPAINT_TOOL_BLUR) {
- vpd->mlooptag = MEM_mallocN(sizeof(bool) * me->totloop, "VPaintData mlooptag");
- }
-
- if (brush->vertexpaint_tool == VPAINT_TOOL_SMEAR) {
- vpd->smear.color_prev = MEM_mallocN(sizeof(uint) * me->totloop, __func__);
- memcpy(vpd->smear.color_prev, me->mloopcol, sizeof(uint) * me->totloop);
- vpd->smear.color_curr = MEM_dupallocN(vpd->smear.color_prev);
- }
-
- /* Create projection handle */
- if (vpd->is_texbrush) {
- ob->sculpt->building_vp_handle = true;
- vpd->vp_handle = ED_vpaint_proj_handle_create(depsgraph, scene, ob, &vpd->vertexcosnos);
- ob->sculpt->building_vp_handle = false;
- }
-
- /* If not previously created, create vertex/weight paint mode session data */
- vertex_paint_init_stroke(depsgraph, scene, ob);
- vwpaint_update_cache_invariants(C, vp, ss, op, mouse);
- vertex_paint_init_session_data(ts, ob);
-
- if (ob->sculpt->mode.vpaint.previous_color != NULL) {
- memset(ob->sculpt->mode.vpaint.previous_color, 0, sizeof(uint) * me->totloop);
- }
-
- return 1;
+ Scene *scene = CTX_data_scene(C);
+ ToolSettings *ts = scene->toolsettings;
+ struct PaintStroke *stroke = op->customdata;
+ VPaint *vp = ts->vpaint;
+ Brush *brush = BKE_paint_brush(&vp->paint);
+ struct VPaintData *vpd;
+ Object *ob = CTX_data_active_object(C);
+ Mesh *me;
+ SculptSession *ss = ob->sculpt;
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+
+ /* context checks could be a poll() */
+ me = BKE_mesh_from_object(ob);
+ if (me == NULL || me->totpoly == 0)
+ return false;
+
+ ED_mesh_color_ensure(me, NULL);
+ if (me->mloopcol == NULL)
+ return false;
+
+ /* make mode data storage */
+ vpd = MEM_callocN(sizeof(*vpd), "VPaintData");
+ paint_stroke_set_mode_data(stroke, vpd);
+ ED_view3d_viewcontext_init(C, &vpd->vc);
+ view_angle_limits_init(&vpd->normal_angle_precalc,
+ vp->paint.brush->falloff_angle,
+ (vp->paint.brush->flag & BRUSH_FRONTFACE_FALLOFF) != 0);
+
+ vpd->paintcol = vpaint_get_current_col(
+ scene, vp, (RNA_enum_get(op->ptr, "mode") == BRUSH_STROKE_INVERT));
+
+ vpd->is_texbrush = !(brush->vertexpaint_tool == VPAINT_TOOL_BLUR) && brush->mtex.tex;
+
+ /* are we painting onto a modified mesh?,
+ * if not we can skip face map trickiness */
+ if (vertex_paint_use_fast_update_check(ob)) {
+ vpd->use_fast_update = true;
+ /* printf("Fast update!\n");*/
+ }
+ else {
+ vpd->use_fast_update = false;
+ /* printf("No fast update!\n");*/
+ }
+
+ /* to keep tracked of modified loops for shared vertex color blending */
+ if (brush->vertexpaint_tool == VPAINT_TOOL_BLUR) {
+ vpd->mlooptag = MEM_mallocN(sizeof(bool) * me->totloop, "VPaintData mlooptag");
+ }
+
+ if (brush->vertexpaint_tool == VPAINT_TOOL_SMEAR) {
+ vpd->smear.color_prev = MEM_mallocN(sizeof(uint) * me->totloop, __func__);
+ memcpy(vpd->smear.color_prev, me->mloopcol, sizeof(uint) * me->totloop);
+ vpd->smear.color_curr = MEM_dupallocN(vpd->smear.color_prev);
+ }
+
+ /* Create projection handle */
+ if (vpd->is_texbrush) {
+ ob->sculpt->building_vp_handle = true;
+ vpd->vp_handle = ED_vpaint_proj_handle_create(depsgraph, scene, ob, &vpd->vertexcosnos);
+ ob->sculpt->building_vp_handle = false;
+ }
+
+ /* If not previously created, create vertex/weight paint mode session data */
+ vertex_paint_init_stroke(depsgraph, scene, ob);
+ vwpaint_update_cache_invariants(C, vp, ss, op, mouse);
+ vertex_paint_init_session_data(ts, ob);
+
+ if (ob->sculpt->mode.vpaint.previous_color != NULL) {
+ memset(ob->sculpt->mode.vpaint.previous_color, 0, sizeof(uint) * me->totloop);
+ }
+
+ return 1;
}
static void do_vpaint_brush_calc_average_color_cb_ex(
- void *__restrict userdata,
- const int n,
- const ParallelRangeTLS *__restrict UNUSED(tls))
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- const PBVHType pbvh_type = BKE_pbvh_type(ss->pbvh);
- const bool has_grids = (pbvh_type == PBVH_GRIDS);
- const struct SculptVertexPaintGeomMap *gmap = &ss->mode.vpaint.gmap;
-
- StrokeCache *cache = ss->cache;
- uint *lcol = data->lcol;
- char *col;
- const bool use_vert_sel = (data->me->editflag & (ME_EDIT_PAINT_FACE_SEL | ME_EDIT_PAINT_VERT_SEL)) != 0;
-
- struct VPaintAverageAccum *accum = (struct VPaintAverageAccum *)data->custom_data + n;
- accum->len = 0;
- memset(accum->value, 0, sizeof(accum->value));
-
- SculptBrushTest test;
- SculptBrushTestFn sculpt_brush_test_sq_fn =
- sculpt_brush_test_init_with_falloff_shape(ss, &test, data->brush->falloff_shape);
-
- /* For each vertex */
- PBVHVertexIter vd;
- BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
- {
- /* Test to see if the vertex coordinates are within the spherical brush region. */
- if (sculpt_brush_test_sq_fn(&test, vd.co)) {
- const int v_index = has_grids ? data->me->mloop[vd.grid_indices[vd.g]].v : vd.vert_indices[vd.i];
- if (BKE_brush_curve_strength(data->brush, 0.0, cache->radius) > 0.0) {
- /* If the vertex is selected for painting. */
- const MVert *mv = &data->me->mvert[v_index];
- if (!use_vert_sel || mv->flag & SELECT) {
- accum->len += gmap->vert_to_loop[v_index].count;
- /* if a vertex is within the brush region, then add it's color to the blend. */
- for (int j = 0; j < gmap->vert_to_loop[v_index].count; j++) {
- const int l_index = gmap->vert_to_loop[v_index].indices[j];
- col = (char *)(&lcol[l_index]);
- /* Color is squared to compensate the sqrt color encoding. */
- accum->value[0] += col[0] * col[0];
- accum->value[1] += col[1] * col[1];
- accum->value[2] += col[2] * col[2];
- }
- }
- }
- }
- }
- BKE_pbvh_vertex_iter_end;
-}
-
-static float tex_color_alpha_ubyte(
- SculptThreadedTaskData *data, const float v_co[3],
- uint *r_color)
-{
- float rgba[4];
- float rgba_br[3];
- tex_color_alpha(data->vp, &data->vpd->vc, v_co, rgba);
- rgb_uchar_to_float(rgba_br, (const uchar *)&data->vpd->paintcol);
- mul_v3_v3(rgba_br, rgba);
- rgb_float_to_uchar((uchar *)r_color, rgba_br);
- return rgba[3];
-}
-
-static void do_vpaint_brush_draw_task_cb_ex(
- void *__restrict userdata,
- const int n,
- const ParallelRangeTLS *__restrict UNUSED(tls))
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- const PBVHType pbvh_type = BKE_pbvh_type(ss->pbvh);
- const bool has_grids = (pbvh_type == PBVH_GRIDS);
- const struct SculptVertexPaintGeomMap *gmap = &ss->mode.vpaint.gmap;
-
- const Brush *brush = data->brush;
- const StrokeCache *cache = ss->cache;
- uint *lcol = data->lcol;
- const Scene *scene = CTX_data_scene(data->C);
- float brush_size_pressure, brush_alpha_value, brush_alpha_pressure;
- get_brush_alpha_data(scene, ss, brush, &brush_size_pressure, &brush_alpha_value, &brush_alpha_pressure);
- const bool use_normal = vwpaint_use_normal(data->vp);
- const bool use_vert_sel = (data->me->editflag & (ME_EDIT_PAINT_FACE_SEL | ME_EDIT_PAINT_VERT_SEL)) != 0;
- const bool use_face_sel = (data->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, data->brush->falloff_shape);
- const float *sculpt_normal_frontface =
- sculpt_brush_frontface_normal_from_falloff_shape(ss, data->brush->falloff_shape);
-
- /* For each vertex */
- PBVHVertexIter vd;
- BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
- {
- /* Test to see if the vertex coordinates are within the spherical brush region. */
- if (sculpt_brush_test_sq_fn(&test, vd.co)) {
- /* Note: Grids are 1:1 with corners (aka loops).
- * For grid based pbvh, take the vert whose loop corresponds to the current grid.
- * Otherwise, take the current vert. */
- const int v_index = has_grids ? data->me->mloop[vd.grid_indices[vd.g]].v : vd.vert_indices[vd.i];
- const float grid_alpha = has_grids ? 1.0f / vd.gridsize : 1.0f;
- const MVert *mv = &data->me->mvert[v_index];
-
- /* If the vertex is selected for painting. */
- if (!use_vert_sel || mv->flag & SELECT) {
- /* Calc the dot prod. between ray norm on surf and current vert
- * (ie splash prevention factor), and only paint front facing verts. */
- float brush_strength = cache->bstrength;
- const float angle_cos = (use_normal && vd.no) ?
- dot_vf3vs3(sculpt_normal_frontface, vd.no) : 1.0f;
- if (((brush->flag & BRUSH_FRONTFACE) == 0 ||
- (angle_cos > 0.0f)) &&
- ((brush->flag & BRUSH_FRONTFACE_FALLOFF) == 0 ||
- view_angle_limits_apply_falloff(&data->vpd->normal_angle_precalc, angle_cos, &brush_strength)))
- {
- const float brush_fade = BKE_brush_curve_strength(brush, sqrtf(test.dist), cache->radius);
- uint color_final = data->vpd->paintcol;
-
- /* If we're painting with a texture, sample the texture color and alpha. */
- float tex_alpha = 1.0;
- if (data->vpd->is_texbrush) {
- /* Note: we may want to paint alpha as vertex color alpha. */
- tex_alpha = tex_color_alpha_ubyte(
- data, data->vpd->vertexcosnos[v_index].co,
- &color_final);
- }
- /* For each poly owning this vert, paint each loop belonging to this vert. */
- for (int j = 0; j < gmap->vert_to_poly[v_index].count; j++) {
- const int p_index = gmap->vert_to_poly[v_index].indices[j];
- const int l_index = gmap->vert_to_loop[v_index].indices[j];
- BLI_assert(data->me->mloop[l_index].v == v_index);
- const MPoly *mp = &data->me->mpoly[p_index];
- if (!use_face_sel || mp->flag & ME_FACE_SEL) {
- uint color_orig = 0; /* unused when array is NULL */
- if (ss->mode.vpaint.previous_color != NULL) {
- /* Get the previous loop color */
- if (ss->mode.vpaint.previous_color[l_index] == 0) {
- ss->mode.vpaint.previous_color[l_index] = lcol[l_index];
- }
- color_orig = ss->mode.vpaint.previous_color[l_index];
- }
- const float final_alpha =
- 255 * brush_fade * brush_strength *
- tex_alpha * brush_alpha_pressure * grid_alpha;
-
- /* Mix the new color with the original based on final_alpha. */
- lcol[l_index] = vpaint_blend(
- data->vp, lcol[l_index], color_orig, color_final,
- final_alpha, 255 * brush_strength);
- }
- }
- }
- }
- }
- }
- BKE_pbvh_vertex_iter_end;
-}
-
-static void do_vpaint_brush_blur_task_cb_ex(
- void *__restrict userdata,
- const int n,
- const ParallelRangeTLS *__restrict UNUSED(tls))
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- const PBVHType pbvh_type = BKE_pbvh_type(ss->pbvh);
- const bool has_grids = (pbvh_type == PBVH_GRIDS);
-
- Scene *scene = CTX_data_scene(data->C);
- const struct SculptVertexPaintGeomMap *gmap = &ss->mode.vpaint.gmap;
- const Brush *brush = data->brush;
- const StrokeCache *cache = ss->cache;
- uint *lcol = data->lcol;
- float brush_size_pressure, brush_alpha_value, brush_alpha_pressure;
- get_brush_alpha_data(scene, ss, brush, &brush_size_pressure, &brush_alpha_value, &brush_alpha_pressure);
- const bool use_normal = vwpaint_use_normal(data->vp);
- const bool use_vert_sel = (data->me->editflag & (ME_EDIT_PAINT_FACE_SEL | ME_EDIT_PAINT_VERT_SEL)) != 0;
- const bool use_face_sel = (data->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, data->brush->falloff_shape);
- const float *sculpt_normal_frontface =
- sculpt_brush_frontface_normal_from_falloff_shape(ss, data->brush->falloff_shape);
-
- /* For each vertex */
- PBVHVertexIter vd;
- BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
- {
- /* Test to see if the vertex coordinates are within the spherical brush region. */
- if (sculpt_brush_test_sq_fn(&test, vd.co)) {
- /* For grid based pbvh, take the vert whose loop corresponds to the current grid.
- * Otherwise, take the current vert. */
- const int v_index = has_grids ? data->me->mloop[vd.grid_indices[vd.g]].v : vd.vert_indices[vd.i];
- const float grid_alpha = has_grids ? 1.0f / vd.gridsize : 1.0f;
- const MVert *mv = &data->me->mvert[v_index];
-
- /* If the vertex is selected for painting. */
- if (!use_vert_sel || mv->flag & SELECT) {
- float brush_strength = cache->bstrength;
- const float angle_cos = (use_normal && vd.no) ?
- dot_vf3vs3(sculpt_normal_frontface, vd.no) : 1.0f;
- if (((brush->flag & BRUSH_FRONTFACE) == 0 ||
- (angle_cos > 0.0f)) &&
- ((brush->flag & BRUSH_FRONTFACE_FALLOFF) == 0 ||
- view_angle_limits_apply_falloff(&data->vpd->normal_angle_precalc, angle_cos, &brush_strength)))
- {
- const float brush_fade = BKE_brush_curve_strength(brush, sqrtf(test.dist), cache->radius);
-
- /* Get the average poly color */
- uint color_final = 0;
- int total_hit_loops = 0;
- uint blend[4] = {0};
- for (int j = 0; j < gmap->vert_to_poly[v_index].count; j++) {
- int p_index = gmap->vert_to_poly[v_index].indices[j];
- const MPoly *mp = &data->me->mpoly[p_index];
- if (!use_face_sel || mp->flag & ME_FACE_SEL) {
- total_hit_loops += mp->totloop;
- for (int k = 0; k < mp->totloop; k++) {
- const uint l_index = mp->loopstart + k;
- const char *col = (const char *)(&lcol[l_index]);
- /* Color is squared to compensate the sqrt color encoding. */
- blend[0] += (uint)col[0] * (uint)col[0];
- blend[1] += (uint)col[1] * (uint)col[1];
- blend[2] += (uint)col[2] * (uint)col[2];
- blend[3] += (uint)col[3] * (uint)col[3];
- }
- }
- }
- if (total_hit_loops != 0) {
- /* Use rgb^2 color averaging. */
- char *col = (char *)(&color_final);
- col[0] = round_fl_to_uchar(sqrtf(divide_round_i(blend[0], total_hit_loops)));
- col[1] = round_fl_to_uchar(sqrtf(divide_round_i(blend[1], total_hit_loops)));
- col[2] = round_fl_to_uchar(sqrtf(divide_round_i(blend[2], total_hit_loops)));
- col[3] = round_fl_to_uchar(sqrtf(divide_round_i(blend[3], total_hit_loops)));
-
- /* For each poly owning this vert,
- * paint each loop belonging to this vert. */
- for (int j = 0; j < gmap->vert_to_poly[v_index].count; j++) {
- const int p_index = gmap->vert_to_poly[v_index].indices[j];
- const int l_index = gmap->vert_to_loop[v_index].indices[j];
- BLI_assert(data->me->mloop[l_index].v == v_index);
- const MPoly *mp = &data->me->mpoly[p_index];
- if (!use_face_sel || mp->flag & ME_FACE_SEL) {
- uint color_orig = 0; /* unused when array is NULL */
- if (ss->mode.vpaint.previous_color != NULL) {
- /* Get the previous loop color */
- if (ss->mode.vpaint.previous_color[l_index] == 0) {
- ss->mode.vpaint.previous_color[l_index] = lcol[l_index];
- }
- color_orig = ss->mode.vpaint.previous_color[l_index];
- }
- const float final_alpha =
- 255 * brush_fade * brush_strength *
- brush_alpha_pressure * grid_alpha;
- /* Mix the new color with the original
- * based on the brush strength and the curve. */
- lcol[l_index] = vpaint_blend(
- data->vp, lcol[l_index], color_orig, *((uint *)col),
- final_alpha, 255 * brush_strength);
- }
- }
- }
- }
- }
- }
- }
- BKE_pbvh_vertex_iter_end;
-}
-
-static void do_vpaint_brush_smear_task_cb_ex(
- void *__restrict userdata,
- const int n,
- const ParallelRangeTLS *__restrict UNUSED(tls))
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- const PBVHType pbvh_type = BKE_pbvh_type(ss->pbvh);
- const bool has_grids = (pbvh_type == PBVH_GRIDS);
-
- Scene *scene = CTX_data_scene(data->C);
- const struct SculptVertexPaintGeomMap *gmap = &ss->mode.vpaint.gmap;
- const Brush *brush = data->brush;
- const StrokeCache *cache = ss->cache;
- uint *lcol = data->lcol;
- float brush_size_pressure, brush_alpha_value, brush_alpha_pressure;
- get_brush_alpha_data(scene, ss, brush, &brush_size_pressure, &brush_alpha_value, &brush_alpha_pressure);
- float brush_dir[3];
- const bool use_normal = vwpaint_use_normal(data->vp);
- const bool use_vert_sel = (data->me->editflag & (ME_EDIT_PAINT_FACE_SEL | ME_EDIT_PAINT_VERT_SEL)) != 0;
- const bool use_face_sel = (data->me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
-
- sub_v3_v3v3(brush_dir, cache->location, cache->last_location);
- project_plane_v3_v3v3(brush_dir, brush_dir, cache->view_normal);
-
- 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);
- const float *sculpt_normal_frontface =
- sculpt_brush_frontface_normal_from_falloff_shape(ss, data->brush->falloff_shape);
-
- /* For each vertex */
- PBVHVertexIter vd;
- BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
- {
- /* Test to see if the vertex coordinates are within the spherical brush region. */
- if (sculpt_brush_test_sq_fn(&test, vd.co)) {
- /* For grid based pbvh, take the vert whose loop corresponds to the current grid.
- * Otherwise, take the current vert. */
- const int v_index = has_grids ? data->me->mloop[vd.grid_indices[vd.g]].v : vd.vert_indices[vd.i];
- const float grid_alpha = has_grids ? 1.0f / vd.gridsize : 1.0f;
- const MVert *mv_curr = &data->me->mvert[v_index];
-
- /* if the vertex is selected for painting. */
- if (!use_vert_sel || mv_curr->flag & SELECT) {
- /* Calc the dot prod. between ray norm on surf and current vert
- * (ie splash prevention factor), and only paint front facing verts. */
- float brush_strength = cache->bstrength;
- const float angle_cos = (use_normal && vd.no) ?
- dot_vf3vs3(sculpt_normal_frontface, vd.no) : 1.0f;
- if (((brush->flag & BRUSH_FRONTFACE) == 0 ||
- (angle_cos > 0.0f)) &&
- ((brush->flag & BRUSH_FRONTFACE_FALLOFF) == 0 ||
- view_angle_limits_apply_falloff(&data->vpd->normal_angle_precalc, angle_cos, &brush_strength)))
- {
- const float brush_fade = BKE_brush_curve_strength(brush, sqrtf(test.dist), cache->radius);
-
- bool do_color = false;
- /* Minimum dot product between brush direction and current
- * to neighbor direction is 0.0, meaning orthogonal. */
- float stroke_dot_max = 0.0f;
-
- /* Get the color of the loop in the opposite
- * direction of the brush movement */
- uint color_final = 0;
- for (int j = 0; j < gmap->vert_to_poly[v_index].count; j++) {
- const int p_index = gmap->vert_to_poly[v_index].indices[j];
- const int l_index = gmap->vert_to_loop[v_index].indices[j];
- BLI_assert(data->me->mloop[l_index].v == v_index);
- UNUSED_VARS_NDEBUG(l_index);
- const MPoly *mp = &data->me->mpoly[p_index];
- if (!use_face_sel || mp->flag & ME_FACE_SEL) {
- const MLoop *ml_other = &data->me->mloop[mp->loopstart];
- for (int k = 0; k < mp->totloop; k++, ml_other++) {
- const uint v_other_index = ml_other->v;
- if (v_other_index != v_index) {
- const MVert *mv_other = &data->me->mvert[v_other_index];
-
- /* Get the direction from the
- * selected vert to the neighbor. */
- float other_dir[3];
- sub_v3_v3v3(other_dir, mv_curr->co, mv_other->co);
- project_plane_v3_v3v3(other_dir, other_dir, cache->view_normal);
-
- normalize_v3(other_dir);
-
- const float stroke_dot = dot_v3v3(other_dir, brush_dir);
-
- if (stroke_dot > stroke_dot_max) {
- stroke_dot_max = stroke_dot;
- color_final = data->vpd->smear.color_prev[mp->loopstart + k];
- do_color = true;
- }
- }
- }
- }
- }
-
- if (do_color) {
- const float final_alpha =
- 255 * brush_fade * brush_strength *
- brush_alpha_pressure * grid_alpha;
-
- /* For each poly owning this vert,
- * paint each loop belonging to this vert. */
- for (int j = 0; j < gmap->vert_to_poly[v_index].count; j++) {
- const int p_index = gmap->vert_to_poly[v_index].indices[j];
- const int l_index = gmap->vert_to_loop[v_index].indices[j];
- BLI_assert(data->me->mloop[l_index].v == v_index);
- const MPoly *mp = &data->me->mpoly[p_index];
- if (!use_face_sel || mp->flag & ME_FACE_SEL) {
- /* Get the previous loop color */
- uint color_orig = 0; /* unused when array is NULL */
- if (ss->mode.vpaint.previous_color != NULL) {
- /* Get the previous loop color */
- if (ss->mode.vpaint.previous_color[l_index] == 0) {
- ss->mode.vpaint.previous_color[l_index] = lcol[l_index];
- }
- color_orig = ss->mode.vpaint.previous_color[l_index];
- }
- /* Mix the new color with the original
- * based on the brush strength and the curve. */
- lcol[l_index] = vpaint_blend(
- data->vp, lcol[l_index], color_orig, color_final,
- final_alpha, 255 * brush_strength);
-
- data->vpd->smear.color_curr[l_index] = lcol[l_index];
- }
- }
- }
- }
- }
- }
- }
- BKE_pbvh_vertex_iter_end;
- }
-}
-
-static void calculate_average_color(SculptThreadedTaskData *data, PBVHNode **UNUSED(nodes), int totnode)
-{
- struct VPaintAverageAccum *accum = MEM_mallocN(sizeof(*accum) * totnode, __func__);
- data->custom_data = accum;
-
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- BLI_task_parallel_range(
- 0, totnode,
- data,
- do_vpaint_brush_calc_average_color_cb_ex,
- &settings);
-
- uint accum_len = 0;
- uint accum_value[3] = {0};
- uchar blend[4] = {0};
- for (int i = 0; i < totnode; i++) {
- accum_len += accum[i].len;
- accum_value[0] += accum[i].value[0];
- accum_value[1] += accum[i].value[1];
- accum_value[2] += accum[i].value[2];
- }
- if (accum_len != 0) {
- blend[0] = round_fl_to_uchar(sqrtf(divide_round_i(accum_value[0], accum_len)));
- blend[1] = round_fl_to_uchar(sqrtf(divide_round_i(accum_value[1], accum_len)));
- blend[2] = round_fl_to_uchar(sqrtf(divide_round_i(accum_value[2], accum_len)));
- blend[3] = 255;
- data->vpd->paintcol = *((uint *)blend);
- }
-
- MEM_SAFE_FREE(data->custom_data); /* 'accum' */
-}
-
-static void vpaint_paint_leaves(
- bContext *C, Sculpt *sd, VPaint *vp, struct VPaintData *vpd,
- Object *ob, Mesh *me, PBVHNode **nodes, int totnode)
-{
- const Brush *brush = ob->sculpt->cache->brush;
-
- SculptThreadedTaskData data = {
- .C = C, .sd = sd, .ob = ob, .brush = brush, .nodes = nodes, .vp = vp, .vpd = vpd,
- .lcol = (uint *)me->mloopcol, .me = me,
- };
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- switch ((eBrushVertexPaintTool)brush->vertexpaint_tool) {
- case VPAINT_TOOL_AVERAGE:
- calculate_average_color(&data, nodes, totnode);
- BLI_task_parallel_range(
- 0, totnode,
- &data,
- do_vpaint_brush_draw_task_cb_ex,
- &settings);
- break;
- case VPAINT_TOOL_BLUR:
- BLI_task_parallel_range(
- 0, totnode,
- &data,
- do_vpaint_brush_blur_task_cb_ex,
- &settings);
- break;
- case VPAINT_TOOL_SMEAR:
- BLI_task_parallel_range(
- 0, totnode,
- &data,
- do_vpaint_brush_smear_task_cb_ex,
- &settings);
- break;
- case VPAINT_TOOL_DRAW:
- BLI_task_parallel_range(
- 0, totnode,
- &data,
- do_vpaint_brush_draw_task_cb_ex,
- &settings);
- break;
- }
-}
-
-static void vpaint_do_paint(
- bContext *C, Sculpt *sd, VPaint *vp, struct VPaintData *vpd,
- Object *ob, Mesh *me, Brush *brush, const char symm, const int axis, const int i, const float angle)
-{
- SculptSession *ss = ob->sculpt;
- ss->cache->radial_symmetry_pass = i;
- sculpt_cache_calc_brushdata_symm(ss->cache, symm, axis, angle);
-
- int totnode;
- PBVHNode **nodes = vwpaint_pbvh_gather_generic(ob, vp, sd, brush, &totnode);
-
- /* Paint those leaves. */
- vpaint_paint_leaves(C, sd, vp, vpd, ob, me, nodes, totnode);
-
- if (nodes) {
- MEM_freeN(nodes);
- }
-}
-
-static void vpaint_do_radial_symmetry(
- bContext *C, Sculpt *sd, VPaint *vp, struct VPaintData *vpd, Object *ob, Mesh *me,
- Brush *brush, const char symm, const int axis)
-{
- for (int i = 1; i < vp->radial_symm[axis - 'X']; i++) {
- const float angle = (2.0 * M_PI) * i / vp->radial_symm[axis - 'X'];
- vpaint_do_paint(C, sd, vp, vpd, ob, me, brush, symm, axis, i, angle);
- }
+ void *__restrict userdata, const int n, const ParallelRangeTLS *__restrict UNUSED(tls))
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ const PBVHType pbvh_type = BKE_pbvh_type(ss->pbvh);
+ const bool has_grids = (pbvh_type == PBVH_GRIDS);
+ const struct SculptVertexPaintGeomMap *gmap = &ss->mode.vpaint.gmap;
+
+ StrokeCache *cache = ss->cache;
+ uint *lcol = data->lcol;
+ char *col;
+ const bool use_vert_sel = (data->me->editflag &
+ (ME_EDIT_PAINT_FACE_SEL | ME_EDIT_PAINT_VERT_SEL)) != 0;
+
+ struct VPaintAverageAccum *accum = (struct VPaintAverageAccum *)data->custom_data + n;
+ accum->len = 0;
+ memset(accum->value, 0, sizeof(accum->value));
+
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = sculpt_brush_test_init_with_falloff_shape(
+ ss, &test, data->brush->falloff_shape);
+
+ /* For each vertex */
+ PBVHVertexIter vd;
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
+ {
+ /* Test to see if the vertex coordinates are within the spherical brush region. */
+ if (sculpt_brush_test_sq_fn(&test, vd.co)) {
+ const int v_index = has_grids ? data->me->mloop[vd.grid_indices[vd.g]].v :
+ vd.vert_indices[vd.i];
+ if (BKE_brush_curve_strength(data->brush, 0.0, cache->radius) > 0.0) {
+ /* If the vertex is selected for painting. */
+ const MVert *mv = &data->me->mvert[v_index];
+ if (!use_vert_sel || mv->flag & SELECT) {
+ accum->len += gmap->vert_to_loop[v_index].count;
+ /* if a vertex is within the brush region, then add it's color to the blend. */
+ for (int j = 0; j < gmap->vert_to_loop[v_index].count; j++) {
+ const int l_index = gmap->vert_to_loop[v_index].indices[j];
+ col = (char *)(&lcol[l_index]);
+ /* Color is squared to compensate the sqrt color encoding. */
+ accum->value[0] += col[0] * col[0];
+ accum->value[1] += col[1] * col[1];
+ accum->value[2] += col[2] * col[2];
+ }
+ }
+ }
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+static float tex_color_alpha_ubyte(SculptThreadedTaskData *data,
+ const float v_co[3],
+ uint *r_color)
+{
+ float rgba[4];
+ float rgba_br[3];
+ tex_color_alpha(data->vp, &data->vpd->vc, v_co, rgba);
+ rgb_uchar_to_float(rgba_br, (const uchar *)&data->vpd->paintcol);
+ mul_v3_v3(rgba_br, rgba);
+ rgb_float_to_uchar((uchar *)r_color, rgba_br);
+ return rgba[3];
+}
+
+static void do_vpaint_brush_draw_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ const PBVHType pbvh_type = BKE_pbvh_type(ss->pbvh);
+ const bool has_grids = (pbvh_type == PBVH_GRIDS);
+ const struct SculptVertexPaintGeomMap *gmap = &ss->mode.vpaint.gmap;
+
+ const Brush *brush = data->brush;
+ const StrokeCache *cache = ss->cache;
+ uint *lcol = data->lcol;
+ const Scene *scene = CTX_data_scene(data->C);
+ float brush_size_pressure, brush_alpha_value, brush_alpha_pressure;
+ get_brush_alpha_data(
+ scene, ss, brush, &brush_size_pressure, &brush_alpha_value, &brush_alpha_pressure);
+ const bool use_normal = vwpaint_use_normal(data->vp);
+ const bool use_vert_sel = (data->me->editflag &
+ (ME_EDIT_PAINT_FACE_SEL | ME_EDIT_PAINT_VERT_SEL)) != 0;
+ const bool use_face_sel = (data->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, data->brush->falloff_shape);
+ const float *sculpt_normal_frontface = sculpt_brush_frontface_normal_from_falloff_shape(
+ ss, data->brush->falloff_shape);
+
+ /* For each vertex */
+ PBVHVertexIter vd;
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
+ {
+ /* Test to see if the vertex coordinates are within the spherical brush region. */
+ if (sculpt_brush_test_sq_fn(&test, vd.co)) {
+ /* Note: Grids are 1:1 with corners (aka loops).
+ * For grid based pbvh, take the vert whose loop corresponds to the current grid.
+ * Otherwise, take the current vert. */
+ const int v_index = has_grids ? data->me->mloop[vd.grid_indices[vd.g]].v :
+ vd.vert_indices[vd.i];
+ const float grid_alpha = has_grids ? 1.0f / vd.gridsize : 1.0f;
+ const MVert *mv = &data->me->mvert[v_index];
+
+ /* If the vertex is selected for painting. */
+ if (!use_vert_sel || mv->flag & SELECT) {
+ /* Calc the dot prod. between ray norm on surf and current vert
+ * (ie splash prevention factor), and only paint front facing verts. */
+ float brush_strength = cache->bstrength;
+ const float angle_cos = (use_normal && vd.no) ?
+ dot_vf3vs3(sculpt_normal_frontface, vd.no) :
+ 1.0f;
+ if (((brush->flag & BRUSH_FRONTFACE) == 0 || (angle_cos > 0.0f)) &&
+ ((brush->flag & BRUSH_FRONTFACE_FALLOFF) == 0 ||
+ view_angle_limits_apply_falloff(
+ &data->vpd->normal_angle_precalc, angle_cos, &brush_strength))) {
+ const float brush_fade = BKE_brush_curve_strength(
+ brush, sqrtf(test.dist), cache->radius);
+ uint color_final = data->vpd->paintcol;
+
+ /* If we're painting with a texture, sample the texture color and alpha. */
+ float tex_alpha = 1.0;
+ if (data->vpd->is_texbrush) {
+ /* Note: we may want to paint alpha as vertex color alpha. */
+ tex_alpha = tex_color_alpha_ubyte(
+ data, data->vpd->vertexcosnos[v_index].co, &color_final);
+ }
+ /* For each poly owning this vert, paint each loop belonging to this vert. */
+ for (int j = 0; j < gmap->vert_to_poly[v_index].count; j++) {
+ const int p_index = gmap->vert_to_poly[v_index].indices[j];
+ const int l_index = gmap->vert_to_loop[v_index].indices[j];
+ BLI_assert(data->me->mloop[l_index].v == v_index);
+ const MPoly *mp = &data->me->mpoly[p_index];
+ if (!use_face_sel || mp->flag & ME_FACE_SEL) {
+ uint color_orig = 0; /* unused when array is NULL */
+ if (ss->mode.vpaint.previous_color != NULL) {
+ /* Get the previous loop color */
+ if (ss->mode.vpaint.previous_color[l_index] == 0) {
+ ss->mode.vpaint.previous_color[l_index] = lcol[l_index];
+ }
+ color_orig = ss->mode.vpaint.previous_color[l_index];
+ }
+ const float final_alpha = 255 * brush_fade * brush_strength * tex_alpha *
+ brush_alpha_pressure * grid_alpha;
+
+ /* Mix the new color with the original based on final_alpha. */
+ lcol[l_index] = vpaint_blend(data->vp,
+ lcol[l_index],
+ color_orig,
+ color_final,
+ final_alpha,
+ 255 * brush_strength);
+ }
+ }
+ }
+ }
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+static void do_vpaint_brush_blur_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ const PBVHType pbvh_type = BKE_pbvh_type(ss->pbvh);
+ const bool has_grids = (pbvh_type == PBVH_GRIDS);
+
+ Scene *scene = CTX_data_scene(data->C);
+ const struct SculptVertexPaintGeomMap *gmap = &ss->mode.vpaint.gmap;
+ const Brush *brush = data->brush;
+ const StrokeCache *cache = ss->cache;
+ uint *lcol = data->lcol;
+ float brush_size_pressure, brush_alpha_value, brush_alpha_pressure;
+ get_brush_alpha_data(
+ scene, ss, brush, &brush_size_pressure, &brush_alpha_value, &brush_alpha_pressure);
+ const bool use_normal = vwpaint_use_normal(data->vp);
+ const bool use_vert_sel = (data->me->editflag &
+ (ME_EDIT_PAINT_FACE_SEL | ME_EDIT_PAINT_VERT_SEL)) != 0;
+ const bool use_face_sel = (data->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, data->brush->falloff_shape);
+ const float *sculpt_normal_frontface = sculpt_brush_frontface_normal_from_falloff_shape(
+ ss, data->brush->falloff_shape);
+
+ /* For each vertex */
+ PBVHVertexIter vd;
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
+ {
+ /* Test to see if the vertex coordinates are within the spherical brush region. */
+ if (sculpt_brush_test_sq_fn(&test, vd.co)) {
+ /* For grid based pbvh, take the vert whose loop corresponds to the current grid.
+ * Otherwise, take the current vert. */
+ const int v_index = has_grids ? data->me->mloop[vd.grid_indices[vd.g]].v :
+ vd.vert_indices[vd.i];
+ const float grid_alpha = has_grids ? 1.0f / vd.gridsize : 1.0f;
+ const MVert *mv = &data->me->mvert[v_index];
+
+ /* If the vertex is selected for painting. */
+ if (!use_vert_sel || mv->flag & SELECT) {
+ float brush_strength = cache->bstrength;
+ const float angle_cos = (use_normal && vd.no) ?
+ dot_vf3vs3(sculpt_normal_frontface, vd.no) :
+ 1.0f;
+ if (((brush->flag & BRUSH_FRONTFACE) == 0 || (angle_cos > 0.0f)) &&
+ ((brush->flag & BRUSH_FRONTFACE_FALLOFF) == 0 ||
+ view_angle_limits_apply_falloff(
+ &data->vpd->normal_angle_precalc, angle_cos, &brush_strength))) {
+ const float brush_fade = BKE_brush_curve_strength(
+ brush, sqrtf(test.dist), cache->radius);
+
+ /* Get the average poly color */
+ uint color_final = 0;
+ int total_hit_loops = 0;
+ uint blend[4] = {0};
+ for (int j = 0; j < gmap->vert_to_poly[v_index].count; j++) {
+ int p_index = gmap->vert_to_poly[v_index].indices[j];
+ const MPoly *mp = &data->me->mpoly[p_index];
+ if (!use_face_sel || mp->flag & ME_FACE_SEL) {
+ total_hit_loops += mp->totloop;
+ for (int k = 0; k < mp->totloop; k++) {
+ const uint l_index = mp->loopstart + k;
+ const char *col = (const char *)(&lcol[l_index]);
+ /* Color is squared to compensate the sqrt color encoding. */
+ blend[0] += (uint)col[0] * (uint)col[0];
+ blend[1] += (uint)col[1] * (uint)col[1];
+ blend[2] += (uint)col[2] * (uint)col[2];
+ blend[3] += (uint)col[3] * (uint)col[3];
+ }
+ }
+ }
+ if (total_hit_loops != 0) {
+ /* Use rgb^2 color averaging. */
+ char *col = (char *)(&color_final);
+ col[0] = round_fl_to_uchar(sqrtf(divide_round_i(blend[0], total_hit_loops)));
+ col[1] = round_fl_to_uchar(sqrtf(divide_round_i(blend[1], total_hit_loops)));
+ col[2] = round_fl_to_uchar(sqrtf(divide_round_i(blend[2], total_hit_loops)));
+ col[3] = round_fl_to_uchar(sqrtf(divide_round_i(blend[3], total_hit_loops)));
+
+ /* For each poly owning this vert,
+ * paint each loop belonging to this vert. */
+ for (int j = 0; j < gmap->vert_to_poly[v_index].count; j++) {
+ const int p_index = gmap->vert_to_poly[v_index].indices[j];
+ const int l_index = gmap->vert_to_loop[v_index].indices[j];
+ BLI_assert(data->me->mloop[l_index].v == v_index);
+ const MPoly *mp = &data->me->mpoly[p_index];
+ if (!use_face_sel || mp->flag & ME_FACE_SEL) {
+ uint color_orig = 0; /* unused when array is NULL */
+ if (ss->mode.vpaint.previous_color != NULL) {
+ /* Get the previous loop color */
+ if (ss->mode.vpaint.previous_color[l_index] == 0) {
+ ss->mode.vpaint.previous_color[l_index] = lcol[l_index];
+ }
+ color_orig = ss->mode.vpaint.previous_color[l_index];
+ }
+ const float final_alpha = 255 * brush_fade * brush_strength *
+ brush_alpha_pressure * grid_alpha;
+ /* Mix the new color with the original
+ * based on the brush strength and the curve. */
+ lcol[l_index] = vpaint_blend(data->vp,
+ lcol[l_index],
+ color_orig,
+ *((uint *)col),
+ final_alpha,
+ 255 * brush_strength);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+static void do_vpaint_brush_smear_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ const PBVHType pbvh_type = BKE_pbvh_type(ss->pbvh);
+ const bool has_grids = (pbvh_type == PBVH_GRIDS);
+
+ Scene *scene = CTX_data_scene(data->C);
+ const struct SculptVertexPaintGeomMap *gmap = &ss->mode.vpaint.gmap;
+ const Brush *brush = data->brush;
+ const StrokeCache *cache = ss->cache;
+ uint *lcol = data->lcol;
+ float brush_size_pressure, brush_alpha_value, brush_alpha_pressure;
+ get_brush_alpha_data(
+ scene, ss, brush, &brush_size_pressure, &brush_alpha_value, &brush_alpha_pressure);
+ float brush_dir[3];
+ const bool use_normal = vwpaint_use_normal(data->vp);
+ const bool use_vert_sel = (data->me->editflag &
+ (ME_EDIT_PAINT_FACE_SEL | ME_EDIT_PAINT_VERT_SEL)) != 0;
+ const bool use_face_sel = (data->me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
+
+ sub_v3_v3v3(brush_dir, cache->location, cache->last_location);
+ project_plane_v3_v3v3(brush_dir, brush_dir, cache->view_normal);
+
+ 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);
+ const float *sculpt_normal_frontface = sculpt_brush_frontface_normal_from_falloff_shape(
+ ss, data->brush->falloff_shape);
+
+ /* For each vertex */
+ PBVHVertexIter vd;
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
+ {
+ /* Test to see if the vertex coordinates are within the spherical brush region. */
+ if (sculpt_brush_test_sq_fn(&test, vd.co)) {
+ /* For grid based pbvh, take the vert whose loop corresponds to the current grid.
+ * Otherwise, take the current vert. */
+ const int v_index = has_grids ? data->me->mloop[vd.grid_indices[vd.g]].v :
+ vd.vert_indices[vd.i];
+ const float grid_alpha = has_grids ? 1.0f / vd.gridsize : 1.0f;
+ const MVert *mv_curr = &data->me->mvert[v_index];
+
+ /* if the vertex is selected for painting. */
+ if (!use_vert_sel || mv_curr->flag & SELECT) {
+ /* Calc the dot prod. between ray norm on surf and current vert
+ * (ie splash prevention factor), and only paint front facing verts. */
+ float brush_strength = cache->bstrength;
+ const float angle_cos = (use_normal && vd.no) ?
+ dot_vf3vs3(sculpt_normal_frontface, vd.no) :
+ 1.0f;
+ if (((brush->flag & BRUSH_FRONTFACE) == 0 || (angle_cos > 0.0f)) &&
+ ((brush->flag & BRUSH_FRONTFACE_FALLOFF) == 0 ||
+ view_angle_limits_apply_falloff(
+ &data->vpd->normal_angle_precalc, angle_cos, &brush_strength))) {
+ const float brush_fade = BKE_brush_curve_strength(
+ brush, sqrtf(test.dist), cache->radius);
+
+ bool do_color = false;
+ /* Minimum dot product between brush direction and current
+ * to neighbor direction is 0.0, meaning orthogonal. */
+ float stroke_dot_max = 0.0f;
+
+ /* Get the color of the loop in the opposite
+ * direction of the brush movement */
+ uint color_final = 0;
+ for (int j = 0; j < gmap->vert_to_poly[v_index].count; j++) {
+ const int p_index = gmap->vert_to_poly[v_index].indices[j];
+ const int l_index = gmap->vert_to_loop[v_index].indices[j];
+ BLI_assert(data->me->mloop[l_index].v == v_index);
+ UNUSED_VARS_NDEBUG(l_index);
+ const MPoly *mp = &data->me->mpoly[p_index];
+ if (!use_face_sel || mp->flag & ME_FACE_SEL) {
+ const MLoop *ml_other = &data->me->mloop[mp->loopstart];
+ for (int k = 0; k < mp->totloop; k++, ml_other++) {
+ const uint v_other_index = ml_other->v;
+ if (v_other_index != v_index) {
+ const MVert *mv_other = &data->me->mvert[v_other_index];
+
+ /* Get the direction from the
+ * selected vert to the neighbor. */
+ float other_dir[3];
+ sub_v3_v3v3(other_dir, mv_curr->co, mv_other->co);
+ project_plane_v3_v3v3(other_dir, other_dir, cache->view_normal);
+
+ normalize_v3(other_dir);
+
+ const float stroke_dot = dot_v3v3(other_dir, brush_dir);
+
+ if (stroke_dot > stroke_dot_max) {
+ stroke_dot_max = stroke_dot;
+ color_final = data->vpd->smear.color_prev[mp->loopstart + k];
+ do_color = true;
+ }
+ }
+ }
+ }
+ }
+
+ if (do_color) {
+ const float final_alpha = 255 * brush_fade * brush_strength * brush_alpha_pressure *
+ grid_alpha;
+
+ /* For each poly owning this vert,
+ * paint each loop belonging to this vert. */
+ for (int j = 0; j < gmap->vert_to_poly[v_index].count; j++) {
+ const int p_index = gmap->vert_to_poly[v_index].indices[j];
+ const int l_index = gmap->vert_to_loop[v_index].indices[j];
+ BLI_assert(data->me->mloop[l_index].v == v_index);
+ const MPoly *mp = &data->me->mpoly[p_index];
+ if (!use_face_sel || mp->flag & ME_FACE_SEL) {
+ /* Get the previous loop color */
+ uint color_orig = 0; /* unused when array is NULL */
+ if (ss->mode.vpaint.previous_color != NULL) {
+ /* Get the previous loop color */
+ if (ss->mode.vpaint.previous_color[l_index] == 0) {
+ ss->mode.vpaint.previous_color[l_index] = lcol[l_index];
+ }
+ color_orig = ss->mode.vpaint.previous_color[l_index];
+ }
+ /* Mix the new color with the original
+ * based on the brush strength and the curve. */
+ lcol[l_index] = vpaint_blend(data->vp,
+ lcol[l_index],
+ color_orig,
+ color_final,
+ final_alpha,
+ 255 * brush_strength);
+
+ data->vpd->smear.color_curr[l_index] = lcol[l_index];
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+ }
+}
+
+static void calculate_average_color(SculptThreadedTaskData *data,
+ PBVHNode **UNUSED(nodes),
+ int totnode)
+{
+ struct VPaintAverageAccum *accum = MEM_mallocN(sizeof(*accum) * totnode, __func__);
+ data->custom_data = accum;
+
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ BLI_task_parallel_range(0, totnode, data, do_vpaint_brush_calc_average_color_cb_ex, &settings);
+
+ uint accum_len = 0;
+ uint accum_value[3] = {0};
+ uchar blend[4] = {0};
+ for (int i = 0; i < totnode; i++) {
+ accum_len += accum[i].len;
+ accum_value[0] += accum[i].value[0];
+ accum_value[1] += accum[i].value[1];
+ accum_value[2] += accum[i].value[2];
+ }
+ if (accum_len != 0) {
+ blend[0] = round_fl_to_uchar(sqrtf(divide_round_i(accum_value[0], accum_len)));
+ blend[1] = round_fl_to_uchar(sqrtf(divide_round_i(accum_value[1], accum_len)));
+ blend[2] = round_fl_to_uchar(sqrtf(divide_round_i(accum_value[2], accum_len)));
+ blend[3] = 255;
+ data->vpd->paintcol = *((uint *)blend);
+ }
+
+ MEM_SAFE_FREE(data->custom_data); /* 'accum' */
+}
+
+static void vpaint_paint_leaves(bContext *C,
+ Sculpt *sd,
+ VPaint *vp,
+ struct VPaintData *vpd,
+ Object *ob,
+ Mesh *me,
+ PBVHNode **nodes,
+ int totnode)
+{
+ const Brush *brush = ob->sculpt->cache->brush;
+
+ SculptThreadedTaskData data = {
+ .C = C,
+ .sd = sd,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ .vp = vp,
+ .vpd = vpd,
+ .lcol = (uint *)me->mloopcol,
+ .me = me,
+ };
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ switch ((eBrushVertexPaintTool)brush->vertexpaint_tool) {
+ case VPAINT_TOOL_AVERAGE:
+ calculate_average_color(&data, nodes, totnode);
+ BLI_task_parallel_range(0, totnode, &data, do_vpaint_brush_draw_task_cb_ex, &settings);
+ break;
+ case VPAINT_TOOL_BLUR:
+ BLI_task_parallel_range(0, totnode, &data, do_vpaint_brush_blur_task_cb_ex, &settings);
+ break;
+ case VPAINT_TOOL_SMEAR:
+ BLI_task_parallel_range(0, totnode, &data, do_vpaint_brush_smear_task_cb_ex, &settings);
+ break;
+ case VPAINT_TOOL_DRAW:
+ BLI_task_parallel_range(0, totnode, &data, do_vpaint_brush_draw_task_cb_ex, &settings);
+ break;
+ }
+}
+
+static void vpaint_do_paint(bContext *C,
+ Sculpt *sd,
+ VPaint *vp,
+ struct VPaintData *vpd,
+ Object *ob,
+ Mesh *me,
+ Brush *brush,
+ const char symm,
+ const int axis,
+ const int i,
+ const float angle)
+{
+ SculptSession *ss = ob->sculpt;
+ ss->cache->radial_symmetry_pass = i;
+ sculpt_cache_calc_brushdata_symm(ss->cache, symm, axis, angle);
+
+ int totnode;
+ PBVHNode **nodes = vwpaint_pbvh_gather_generic(ob, vp, sd, brush, &totnode);
+
+ /* Paint those leaves. */
+ vpaint_paint_leaves(C, sd, vp, vpd, ob, me, nodes, totnode);
+
+ if (nodes) {
+ MEM_freeN(nodes);
+ }
+}
+
+static void vpaint_do_radial_symmetry(bContext *C,
+ Sculpt *sd,
+ VPaint *vp,
+ struct VPaintData *vpd,
+ Object *ob,
+ Mesh *me,
+ Brush *brush,
+ const char symm,
+ const int axis)
+{
+ for (int i = 1; i < vp->radial_symm[axis - 'X']; i++) {
+ const float angle = (2.0 * M_PI) * i / vp->radial_symm[axis - 'X'];
+ vpaint_do_paint(C, sd, vp, vpd, ob, me, brush, symm, axis, i, angle);
+ }
}
/* near duplicate of: sculpt.c's,
* 'do_symmetrical_brush_actions' and 'wpaint_do_symmetrical_brush_actions'. */
static void vpaint_do_symmetrical_brush_actions(
- bContext *C, Sculpt *sd, VPaint *vp, struct VPaintData *vpd, Object *ob)
-{
- Brush *brush = BKE_paint_brush(&vp->paint);
- Mesh *me = ob->data;
- SculptSession *ss = ob->sculpt;
- StrokeCache *cache = ss->cache;
- const char symm = vp->paint.symmetry_flags & PAINT_SYMM_AXIS_ALL;
- int i = 0;
-
- /* initial stroke */
- vpaint_do_paint(C, sd, vp, vpd, ob, me, brush, i, 'X', 0, 0);
- vpaint_do_radial_symmetry(C, sd, vp, vpd, ob, me, brush, i, 'X');
- vpaint_do_radial_symmetry(C, sd, vp, vpd, ob, me, brush, i, 'Y');
- vpaint_do_radial_symmetry(C, sd, vp, vpd, ob, me, brush, i, 'Z');
-
- cache->symmetry = symm;
-
- /* symm is a bit combination of XYZ - 1 is mirror
- * X; 2 is Y; 3 is XY; 4 is Z; 5 is XZ; 6 is YZ; 7 is XYZ */
- for (i = 1; i <= symm; i++) {
- if (symm & i && (symm != 5 || i != 3) && (symm != 6 || (i != 3 && i != 5))) {
- cache->mirror_symmetry_pass = i;
- cache->radial_symmetry_pass = 0;
- sculpt_cache_calc_brushdata_symm(cache, i, 0, 0);
-
- if (i & (1 << 0)) {
- vpaint_do_paint(C, sd, vp, vpd, ob, me, brush, i, 'X', 0, 0);
- vpaint_do_radial_symmetry(C, sd, vp, vpd, ob, me, brush, i, 'X');
- }
- if (i & (1 << 1)) {
- vpaint_do_paint(C, sd, vp, vpd, ob, me, brush, i, 'Y', 0, 0);
- vpaint_do_radial_symmetry(C, sd, vp, vpd, ob, me, brush, i, 'Y');
- }
- if (i & (1 << 2)) {
- vpaint_do_paint(C, sd, vp, vpd, ob, me, brush, i, 'Z', 0, 0);
- vpaint_do_radial_symmetry(C, sd, vp, vpd, ob, me, brush, i, 'Z');
- }
- }
- }
-
- copy_v3_v3(cache->true_last_location, cache->true_location);
- cache->is_last_valid = true;
+ bContext *C, Sculpt *sd, VPaint *vp, struct VPaintData *vpd, Object *ob)
+{
+ Brush *brush = BKE_paint_brush(&vp->paint);
+ Mesh *me = ob->data;
+ SculptSession *ss = ob->sculpt;
+ StrokeCache *cache = ss->cache;
+ const char symm = vp->paint.symmetry_flags & PAINT_SYMM_AXIS_ALL;
+ int i = 0;
+
+ /* initial stroke */
+ vpaint_do_paint(C, sd, vp, vpd, ob, me, brush, i, 'X', 0, 0);
+ vpaint_do_radial_symmetry(C, sd, vp, vpd, ob, me, brush, i, 'X');
+ vpaint_do_radial_symmetry(C, sd, vp, vpd, ob, me, brush, i, 'Y');
+ vpaint_do_radial_symmetry(C, sd, vp, vpd, ob, me, brush, i, 'Z');
+
+ cache->symmetry = symm;
+
+ /* symm is a bit combination of XYZ - 1 is mirror
+ * X; 2 is Y; 3 is XY; 4 is Z; 5 is XZ; 6 is YZ; 7 is XYZ */
+ for (i = 1; i <= symm; i++) {
+ if (symm & i && (symm != 5 || i != 3) && (symm != 6 || (i != 3 && i != 5))) {
+ cache->mirror_symmetry_pass = i;
+ cache->radial_symmetry_pass = 0;
+ sculpt_cache_calc_brushdata_symm(cache, i, 0, 0);
+
+ if (i & (1 << 0)) {
+ vpaint_do_paint(C, sd, vp, vpd, ob, me, brush, i, 'X', 0, 0);
+ vpaint_do_radial_symmetry(C, sd, vp, vpd, ob, me, brush, i, 'X');
+ }
+ if (i & (1 << 1)) {
+ vpaint_do_paint(C, sd, vp, vpd, ob, me, brush, i, 'Y', 0, 0);
+ vpaint_do_radial_symmetry(C, sd, vp, vpd, ob, me, brush, i, 'Y');
+ }
+ if (i & (1 << 2)) {
+ vpaint_do_paint(C, sd, vp, vpd, ob, me, brush, i, 'Z', 0, 0);
+ vpaint_do_radial_symmetry(C, sd, vp, vpd, ob, me, brush, i, 'Z');
+ }
+ }
+ }
+
+ copy_v3_v3(cache->true_last_location, cache->true_location);
+ cache->is_last_valid = true;
}
static void vpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, PointerRNA *itemptr)
{
- Scene *scene = CTX_data_scene(C);
- ToolSettings *ts = CTX_data_tool_settings(C);
- struct VPaintData *vpd = paint_stroke_mode_data(stroke);
- VPaint *vp = ts->vpaint;
- ViewContext *vc = &vpd->vc;
- Object *ob = vc->obact;
- Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
+ Scene *scene = CTX_data_scene(C);
+ ToolSettings *ts = CTX_data_tool_settings(C);
+ struct VPaintData *vpd = paint_stroke_mode_data(stroke);
+ VPaint *vp = ts->vpaint;
+ ViewContext *vc = &vpd->vc;
+ Object *ob = vc->obact;
+ Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
- vwpaint_update_cache_variants(C, vp, ob, itemptr);
+ vwpaint_update_cache_variants(C, vp, ob, itemptr);
- float mat[4][4];
- float mval[2];
+ float mat[4][4];
+ float mval[2];
- ED_view3d_init_mats_rv3d(ob, vc->rv3d);
+ ED_view3d_init_mats_rv3d(ob, vc->rv3d);
- /* load projection matrix */
- mul_m4_m4m4(mat, vc->rv3d->persmat, ob->obmat);
+ /* load projection matrix */
+ mul_m4_m4m4(mat, vc->rv3d->persmat, ob->obmat);
- swap_m4m4(vc->rv3d->persmat, mat);
+ swap_m4m4(vc->rv3d->persmat, mat);
- vpaint_do_symmetrical_brush_actions(C, sd, vp, vpd, ob);
+ vpaint_do_symmetrical_brush_actions(C, sd, vp, vpd, ob);
- swap_m4m4(vc->rv3d->persmat, mat);
+ swap_m4m4(vc->rv3d->persmat, mat);
- BKE_mesh_batch_cache_dirty_tag(ob->data, BKE_MESH_BATCH_DIRTY_ALL);
+ BKE_mesh_batch_cache_dirty_tag(ob->data, BKE_MESH_BATCH_DIRTY_ALL);
- if (vp->paint.brush->vertexpaint_tool == VPAINT_TOOL_SMEAR) {
- memcpy(vpd->smear.color_prev, vpd->smear.color_curr, sizeof(uint) * ((Mesh *)ob->data)->totloop);
- }
+ if (vp->paint.brush->vertexpaint_tool == VPAINT_TOOL_SMEAR) {
+ memcpy(
+ vpd->smear.color_prev, vpd->smear.color_curr, sizeof(uint) * ((Mesh *)ob->data)->totloop);
+ }
- /* calculate pivot for rotation around seletion if needed */
- /* also needed for "View Selected" on last stroke */
- paint_last_stroke_update(scene, vc->ar, mval);
+ /* calculate pivot for rotation around seletion if needed */
+ /* also needed for "View Selected" on last stroke */
+ paint_last_stroke_update(scene, vc->ar, mval);
- ED_region_tag_redraw(vc->ar);
+ ED_region_tag_redraw(vc->ar);
- if (vpd->use_fast_update == false) {
- /* recalculate modifier stack to get new colors, slow,
- * avoid this if we can! */
- DEG_id_tag_update(ob->data, 0);
- }
- else {
- /* Flush changes through DEG. */
- DEG_id_tag_update(ob->data, ID_RECALC_COPY_ON_WRITE);
- }
+ if (vpd->use_fast_update == false) {
+ /* recalculate modifier stack to get new colors, slow,
+ * avoid this if we can! */
+ DEG_id_tag_update(ob->data, 0);
+ }
+ else {
+ /* Flush changes through DEG. */
+ DEG_id_tag_update(ob->data, ID_RECALC_COPY_ON_WRITE);
+ }
}
static void vpaint_stroke_done(const bContext *C, struct PaintStroke *stroke)
{
- struct VPaintData *vpd = paint_stroke_mode_data(stroke);
- ViewContext *vc = &vpd->vc;
- Object *ob = vc->obact;
+ struct VPaintData *vpd = paint_stroke_mode_data(stroke);
+ ViewContext *vc = &vpd->vc;
+ Object *ob = vc->obact;
- if (vpd->is_texbrush) {
- ED_vpaint_proj_handle_free(vpd->vp_handle);
- }
+ if (vpd->is_texbrush) {
+ ED_vpaint_proj_handle_free(vpd->vp_handle);
+ }
- if (vpd->mlooptag)
- MEM_freeN(vpd->mlooptag);
- if (vpd->smear.color_prev)
- MEM_freeN(vpd->smear.color_prev);
- if (vpd->smear.color_curr)
- MEM_freeN(vpd->smear.color_curr);
+ if (vpd->mlooptag)
+ MEM_freeN(vpd->mlooptag);
+ if (vpd->smear.color_prev)
+ MEM_freeN(vpd->smear.color_prev);
+ if (vpd->smear.color_curr)
+ MEM_freeN(vpd->smear.color_curr);
- WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
- MEM_freeN(vpd);
+ MEM_freeN(vpd);
- sculpt_cache_free(ob->sculpt->cache);
- ob->sculpt->cache = NULL;
+ sculpt_cache_free(ob->sculpt->cache);
+ ob->sculpt->cache = NULL;
}
static int vpaint_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
- int retval;
+ int retval;
- op->customdata = paint_stroke_new(
- C, op, sculpt_stroke_get_location, vpaint_stroke_test_start,
- vpaint_stroke_update_step, NULL,
- vpaint_stroke_done, event->type);
+ op->customdata = paint_stroke_new(C,
+ op,
+ sculpt_stroke_get_location,
+ vpaint_stroke_test_start,
+ vpaint_stroke_update_step,
+ NULL,
+ vpaint_stroke_done,
+ event->type);
- if ((retval = op->type->modal(C, op, event)) == OPERATOR_FINISHED) {
- paint_stroke_data_free(op);
- return OPERATOR_FINISHED;
- }
+ if ((retval = op->type->modal(C, op, event)) == OPERATOR_FINISHED) {
+ paint_stroke_data_free(op);
+ return OPERATOR_FINISHED;
+ }
- /* add modal handler */
- WM_event_add_modal_handler(C, op);
+ /* add modal handler */
+ WM_event_add_modal_handler(C, op);
- OPERATOR_RETVAL_CHECK(retval);
- BLI_assert(retval == OPERATOR_RUNNING_MODAL);
+ OPERATOR_RETVAL_CHECK(retval);
+ BLI_assert(retval == OPERATOR_RUNNING_MODAL);
- return OPERATOR_RUNNING_MODAL;
+ return OPERATOR_RUNNING_MODAL;
}
static int vpaint_exec(bContext *C, wmOperator *op)
{
- op->customdata = paint_stroke_new(
- C, op, sculpt_stroke_get_location, vpaint_stroke_test_start,
- vpaint_stroke_update_step, NULL,
- vpaint_stroke_done, 0);
+ op->customdata = paint_stroke_new(C,
+ op,
+ sculpt_stroke_get_location,
+ vpaint_stroke_test_start,
+ vpaint_stroke_update_step,
+ NULL,
+ vpaint_stroke_done,
+ 0);
- /* frees op->customdata */
- paint_stroke_exec(C, op);
+ /* frees op->customdata */
+ paint_stroke_exec(C, op);
- return OPERATOR_FINISHED;
+ return OPERATOR_FINISHED;
}
static void vpaint_cancel(bContext *C, wmOperator *op)
{
- Object *ob = CTX_data_active_object(C);
- if (ob->sculpt->cache) {
- sculpt_cache_free(ob->sculpt->cache);
- ob->sculpt->cache = NULL;
- }
+ Object *ob = CTX_data_active_object(C);
+ if (ob->sculpt->cache) {
+ sculpt_cache_free(ob->sculpt->cache);
+ ob->sculpt->cache = NULL;
+ }
- paint_stroke_cancel(C, op);
+ paint_stroke_cancel(C, op);
}
void PAINT_OT_vertex_paint(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Vertex Paint";
- ot->idname = "PAINT_OT_vertex_paint";
- ot->description = "Paint a stroke in the active vertex color layer";
+ /* identifiers */
+ ot->name = "Vertex Paint";
+ ot->idname = "PAINT_OT_vertex_paint";
+ ot->description = "Paint a stroke in the active vertex color layer";
- /* api callbacks */
- ot->invoke = vpaint_invoke;
- ot->modal = paint_stroke_modal;
- ot->exec = vpaint_exec;
- ot->poll = vertex_paint_poll;
- ot->cancel = vpaint_cancel;
+ /* api callbacks */
+ ot->invoke = vpaint_invoke;
+ ot->modal = paint_stroke_modal;
+ ot->exec = vpaint_exec;
+ ot->poll = vertex_paint_poll;
+ ot->cancel = vpaint_cancel;
- /* flags */
- ot->flag = OPTYPE_UNDO | OPTYPE_BLOCKING;
+ /* flags */
+ ot->flag = OPTYPE_UNDO | OPTYPE_BLOCKING;
- paint_stroke_operator_properties(ot);
+ paint_stroke_operator_properties(ot);
}
diff --git a/source/blender/editors/sculpt_paint/paint_vertex_color_ops.c b/source/blender/editors/sculpt_paint/paint_vertex_color_ops.c
index ae1736581fe..ad7cfebb8d5 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex_color_ops.c
+++ b/source/blender/editors/sculpt_paint/paint_vertex_color_ops.c
@@ -42,24 +42,23 @@
#include "ED_mesh.h"
-#include "paint_intern.h" /* own include */
-
+#include "paint_intern.h" /* own include */
static bool vertex_weight_paint_mode_poll(bContext *C)
{
- Object *ob = CTX_data_active_object(C);
- Mesh *me = BKE_mesh_from_object(ob);
- return (ob && (ob->mode == OB_MODE_VERTEX_PAINT || ob->mode == OB_MODE_WEIGHT_PAINT)) &&
- (me && me->totpoly && me->dvert);
+ Object *ob = CTX_data_active_object(C);
+ Mesh *me = BKE_mesh_from_object(ob);
+ return (ob && (ob->mode == OB_MODE_VERTEX_PAINT || ob->mode == OB_MODE_WEIGHT_PAINT)) &&
+ (me && me->totpoly && me->dvert);
}
static void tag_object_after_update(Object *object)
{
- BLI_assert(object->type == OB_MESH);
- Mesh *mesh = object->data;
- DEG_id_tag_update(&mesh->id, ID_RECALC_COPY_ON_WRITE);
- /* NOTE: Original mesh is used for display, so tag it directly here. */
- BKE_mesh_batch_cache_dirty_tag(mesh, BKE_MESH_BATCH_DIRTY_ALL);
+ BLI_assert(object->type == OB_MESH);
+ Mesh *mesh = object->data;
+ DEG_id_tag_update(&mesh->id, ID_RECALC_COPY_ON_WRITE);
+ /* NOTE: Original mesh is used for display, so tag it directly here. */
+ BKE_mesh_batch_cache_dirty_tag(mesh, BKE_MESH_BATCH_DIRTY_ALL);
}
/* -------------------------------------------------------------------- */
@@ -68,74 +67,71 @@ static void tag_object_after_update(Object *object)
static bool vertex_color_set(Object *ob, uint paintcol)
{
- Mesh *me;
- const MPoly *mp;
- int i, j;
-
- if (((me = BKE_mesh_from_object(ob)) == NULL) ||
- (ED_mesh_color_ensure(me, NULL) == false))
- {
- return false;
- }
+ Mesh *me;
+ const MPoly *mp;
+ int i, j;
- const bool use_face_sel = (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
- const bool use_vert_sel = (me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0;
+ if (((me = BKE_mesh_from_object(ob)) == NULL) || (ED_mesh_color_ensure(me, NULL) == false)) {
+ return false;
+ }
- mp = me->mpoly;
- for (i = 0; i < me->totpoly; i++, mp++) {
- MLoopCol *lcol = me->mloopcol + mp->loopstart;
+ const bool use_face_sel = (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
+ const bool use_vert_sel = (me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0;
- if (use_face_sel && !(mp->flag & ME_FACE_SEL))
- continue;
+ mp = me->mpoly;
+ for (i = 0; i < me->totpoly; i++, mp++) {
+ MLoopCol *lcol = me->mloopcol + mp->loopstart;
- j = 0;
- do {
- uint vidx = me->mloop[mp->loopstart + j].v;
- if (!(use_vert_sel && !(me->mvert[vidx].flag & SELECT))) {
- *(int *)lcol = paintcol;
- }
- lcol++;
- j++;
- } while (j < mp->totloop);
+ if (use_face_sel && !(mp->flag & ME_FACE_SEL))
+ continue;
- }
+ j = 0;
+ do {
+ uint vidx = me->mloop[mp->loopstart + j].v;
+ if (!(use_vert_sel && !(me->mvert[vidx].flag & SELECT))) {
+ *(int *)lcol = paintcol;
+ }
+ lcol++;
+ j++;
+ } while (j < mp->totloop);
+ }
- /* remove stale me->mcol, will be added later */
- BKE_mesh_tessface_clear(me);
+ /* remove stale me->mcol, will be added later */
+ BKE_mesh_tessface_clear(me);
- tag_object_after_update(ob);
+ tag_object_after_update(ob);
- return true;
+ return true;
}
static int vertex_color_set_exec(bContext *C, wmOperator *UNUSED(op))
{
- Scene *scene = CTX_data_scene(C);
- Object *obact = CTX_data_active_object(C);
- unsigned int paintcol = vpaint_get_current_col(scene, scene->toolsettings->vpaint, false);
-
- if (vertex_color_set(obact, paintcol)) {
- WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, obact);
- return OPERATOR_FINISHED;
- }
- else {
- return OPERATOR_CANCELLED;
- }
+ Scene *scene = CTX_data_scene(C);
+ Object *obact = CTX_data_active_object(C);
+ unsigned int paintcol = vpaint_get_current_col(scene, scene->toolsettings->vpaint, false);
+
+ if (vertex_color_set(obact, paintcol)) {
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, obact);
+ return OPERATOR_FINISHED;
+ }
+ else {
+ return OPERATOR_CANCELLED;
+ }
}
void PAINT_OT_vertex_color_set(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Set Vertex Colors";
- ot->idname = "PAINT_OT_vertex_color_set";
- ot->description = "Fill the active vertex color layer with the current paint color";
+ /* identifiers */
+ ot->name = "Set Vertex Colors";
+ ot->idname = "PAINT_OT_vertex_color_set";
+ ot->description = "Fill the active vertex color layer with the current paint color";
- /* api callbacks */
- ot->exec = vertex_color_set_exec;
- ot->poll = vertex_paint_mode_poll;
+ /* api callbacks */
+ ot->exec = vertex_color_set_exec;
+ ot->poll = vertex_paint_mode_poll;
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
/** \} */
@@ -146,67 +142,65 @@ void PAINT_OT_vertex_color_set(wmOperatorType *ot)
static bool vertex_paint_from_weight(Object *ob)
{
- Mesh *me;
- const MPoly *mp;
- int vgroup_active;
-
- if (((me = BKE_mesh_from_object(ob)) == NULL ||
- (ED_mesh_color_ensure(me, NULL)) == false))
- {
- return false;
- }
-
- /* TODO: respect selection. */
- /* TODO: Do we want to take weights from evaluated mesh instead? 2.7x was not doing it anyway... */
- mp = me->mpoly;
- vgroup_active = ob->actdef - 1;
- for (int i = 0; i < me->totpoly; i++, mp++) {
- MLoopCol *lcol = &me->mloopcol[mp->loopstart];
- uint j = 0;
- do {
- uint vidx = me->mloop[mp->loopstart + j].v;
- const float weight = defvert_find_weight(&me->dvert[vidx], vgroup_active);
- const uchar grayscale = weight * 255;
- lcol->r = grayscale;
- lcol->b = grayscale;
- lcol->g = grayscale;
- lcol++;
- j++;
- } while (j < mp->totloop);
- }
-
- tag_object_after_update(ob);
-
- return true;
+ Mesh *me;
+ const MPoly *mp;
+ int vgroup_active;
+
+ if (((me = BKE_mesh_from_object(ob)) == NULL || (ED_mesh_color_ensure(me, NULL)) == false)) {
+ return false;
+ }
+
+ /* TODO: respect selection. */
+ /* TODO: Do we want to take weights from evaluated mesh instead? 2.7x was not doing it anyway... */
+ mp = me->mpoly;
+ vgroup_active = ob->actdef - 1;
+ for (int i = 0; i < me->totpoly; i++, mp++) {
+ MLoopCol *lcol = &me->mloopcol[mp->loopstart];
+ uint j = 0;
+ do {
+ uint vidx = me->mloop[mp->loopstart + j].v;
+ const float weight = defvert_find_weight(&me->dvert[vidx], vgroup_active);
+ const uchar grayscale = weight * 255;
+ lcol->r = grayscale;
+ lcol->b = grayscale;
+ lcol->g = grayscale;
+ lcol++;
+ j++;
+ } while (j < mp->totloop);
+ }
+
+ tag_object_after_update(ob);
+
+ return true;
}
static int vertex_paint_from_weight_exec(bContext *C, wmOperator *UNUSED(op))
{
- Object *obact = CTX_data_active_object(C);
- if (vertex_paint_from_weight(obact)) {
- WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, obact);
- return OPERATOR_FINISHED;
- }
- else {
- return OPERATOR_CANCELLED;
- }
+ Object *obact = CTX_data_active_object(C);
+ if (vertex_paint_from_weight(obact)) {
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, obact);
+ return OPERATOR_FINISHED;
+ }
+ else {
+ return OPERATOR_CANCELLED;
+ }
}
void PAINT_OT_vertex_color_from_weight(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Vertex Color from Weight";
- ot->idname = "PAINT_OT_vertex_color_from_weight";
- ot->description = "Convert active weight into gray scale vertex colors";
+ /* identifiers */
+ ot->name = "Vertex Color from Weight";
+ ot->idname = "PAINT_OT_vertex_color_from_weight";
+ ot->description = "Convert active weight into gray scale vertex colors";
- /* api callback */
- ot->exec = vertex_paint_from_weight_exec;
- ot->poll = vertex_weight_paint_mode_poll;
+ /* api callback */
+ ot->exec = vertex_paint_from_weight_exec;
+ ot->poll = vertex_weight_paint_mode_poll;
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- /* TODO: invert, alpha */
+ /* TODO: invert, alpha */
}
/** \} */
@@ -217,131 +211,129 @@ void PAINT_OT_vertex_color_from_weight(wmOperatorType *ot)
static void vertex_color_smooth_looptag(Mesh *me, bool *mlooptag)
{
- const bool use_face_sel = (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
- const MPoly *mp;
- int (*scol)[4];
- int i, j;
- bool has_shared = false;
-
- /* if no mloopcol: do not do */
- /* if mtexpoly: only the involved faces, otherwise all */
-
- if (me->mloopcol == NULL || me->totvert == 0 || me->totpoly == 0) return;
-
- scol = MEM_callocN(sizeof(int) * me->totvert * 5, "scol");
-
- for (i = 0, mp = me->mpoly; i < me->totpoly; i++, mp++) {
- if ((use_face_sel == false) || (mp->flag & ME_FACE_SEL)) {
- const MLoop *ml = me->mloop + mp->loopstart;
- MLoopCol *lcol = me->mloopcol + mp->loopstart;
- for (j = 0; j < mp->totloop; j++, ml++, lcol++) {
- scol[ml->v][0] += lcol->r;
- scol[ml->v][1] += lcol->g;
- scol[ml->v][2] += lcol->b;
- scol[ml->v][3] += 1;
- has_shared = 1;
- }
- }
- }
-
- if (has_shared) {
- for (i = 0; i < me->totvert; i++) {
- if (scol[i][3] != 0) {
- scol[i][0] = divide_round_i(scol[i][0], scol[i][3]);
- scol[i][1] = divide_round_i(scol[i][1], scol[i][3]);
- scol[i][2] = divide_round_i(scol[i][2], scol[i][3]);
- }
- }
-
- for (i = 0, mp = me->mpoly; i < me->totpoly; i++, mp++) {
- if ((use_face_sel == false) || (mp->flag & ME_FACE_SEL)) {
- const MLoop *ml = me->mloop + mp->loopstart;
- MLoopCol *lcol = me->mloopcol + mp->loopstart;
- for (j = 0; j < mp->totloop; j++, ml++, lcol++) {
- if (mlooptag[mp->loopstart + j]) {
- lcol->r = scol[ml->v][0];
- lcol->g = scol[ml->v][1];
- lcol->b = scol[ml->v][2];
- }
- }
- }
- }
- }
-
- MEM_freeN(scol);
+ const bool use_face_sel = (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
+ const MPoly *mp;
+ int(*scol)[4];
+ int i, j;
+ bool has_shared = false;
+
+ /* if no mloopcol: do not do */
+ /* if mtexpoly: only the involved faces, otherwise all */
+
+ if (me->mloopcol == NULL || me->totvert == 0 || me->totpoly == 0)
+ return;
+
+ scol = MEM_callocN(sizeof(int) * me->totvert * 5, "scol");
+
+ for (i = 0, mp = me->mpoly; i < me->totpoly; i++, mp++) {
+ if ((use_face_sel == false) || (mp->flag & ME_FACE_SEL)) {
+ const MLoop *ml = me->mloop + mp->loopstart;
+ MLoopCol *lcol = me->mloopcol + mp->loopstart;
+ for (j = 0; j < mp->totloop; j++, ml++, lcol++) {
+ scol[ml->v][0] += lcol->r;
+ scol[ml->v][1] += lcol->g;
+ scol[ml->v][2] += lcol->b;
+ scol[ml->v][3] += 1;
+ has_shared = 1;
+ }
+ }
+ }
+
+ if (has_shared) {
+ for (i = 0; i < me->totvert; i++) {
+ if (scol[i][3] != 0) {
+ scol[i][0] = divide_round_i(scol[i][0], scol[i][3]);
+ scol[i][1] = divide_round_i(scol[i][1], scol[i][3]);
+ scol[i][2] = divide_round_i(scol[i][2], scol[i][3]);
+ }
+ }
+
+ for (i = 0, mp = me->mpoly; i < me->totpoly; i++, mp++) {
+ if ((use_face_sel == false) || (mp->flag & ME_FACE_SEL)) {
+ const MLoop *ml = me->mloop + mp->loopstart;
+ MLoopCol *lcol = me->mloopcol + mp->loopstart;
+ for (j = 0; j < mp->totloop; j++, ml++, lcol++) {
+ if (mlooptag[mp->loopstart + j]) {
+ lcol->r = scol[ml->v][0];
+ lcol->g = scol[ml->v][1];
+ lcol->b = scol[ml->v][2];
+ }
+ }
+ }
+ }
+ }
+
+ MEM_freeN(scol);
}
static bool vertex_color_smooth(Object *ob)
{
- Mesh *me;
- const MPoly *mp;
+ Mesh *me;
+ const MPoly *mp;
- int i, j;
+ int i, j;
- bool *mlooptag;
+ bool *mlooptag;
- if (((me = BKE_mesh_from_object(ob)) == NULL) ||
- (ED_mesh_color_ensure(me, NULL) == false))
- {
- return false;
- }
+ if (((me = BKE_mesh_from_object(ob)) == NULL) || (ED_mesh_color_ensure(me, NULL) == false)) {
+ return false;
+ }
- const bool use_face_sel = (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
+ const bool use_face_sel = (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
- mlooptag = MEM_callocN(sizeof(bool) * me->totloop, "VPaintData mlooptag");
+ mlooptag = MEM_callocN(sizeof(bool) * me->totloop, "VPaintData mlooptag");
- /* simply tag loops of selected faces */
- mp = me->mpoly;
- for (i = 0; i < me->totpoly; i++, mp++) {
- const MLoop *ml = me->mloop + mp->loopstart;
- int ml_index = mp->loopstart;
+ /* simply tag loops of selected faces */
+ mp = me->mpoly;
+ for (i = 0; i < me->totpoly; i++, mp++) {
+ const MLoop *ml = me->mloop + mp->loopstart;
+ int ml_index = mp->loopstart;
- if (use_face_sel && !(mp->flag & ME_FACE_SEL))
- continue;
+ if (use_face_sel && !(mp->flag & ME_FACE_SEL))
+ continue;
- for (j = 0; j < mp->totloop; j++, ml_index++, ml++) {
- mlooptag[ml_index] = true;
- }
- }
+ for (j = 0; j < mp->totloop; j++, ml_index++, ml++) {
+ mlooptag[ml_index] = true;
+ }
+ }
- /* remove stale me->mcol, will be added later */
- BKE_mesh_tessface_clear(me);
+ /* remove stale me->mcol, will be added later */
+ BKE_mesh_tessface_clear(me);
- vertex_color_smooth_looptag(me, mlooptag);
+ vertex_color_smooth_looptag(me, mlooptag);
- MEM_freeN(mlooptag);
+ MEM_freeN(mlooptag);
- tag_object_after_update(ob);
+ tag_object_after_update(ob);
- return true;
+ return true;
}
-
static int vertex_color_smooth_exec(bContext *C, wmOperator *UNUSED(op))
{
- Object *obact = CTX_data_active_object(C);
- if (vertex_color_smooth(obact)) {
- WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, obact);
- return OPERATOR_FINISHED;
- }
- else {
- return OPERATOR_CANCELLED;
- }
+ Object *obact = CTX_data_active_object(C);
+ if (vertex_color_smooth(obact)) {
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, obact);
+ return OPERATOR_FINISHED;
+ }
+ else {
+ return OPERATOR_CANCELLED;
+ }
}
void PAINT_OT_vertex_color_smooth(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Smooth Vertex Colors";
- ot->idname = "PAINT_OT_vertex_color_smooth";
- ot->description = "Smooth colors across vertices";
+ /* identifiers */
+ ot->name = "Smooth Vertex Colors";
+ ot->idname = "PAINT_OT_vertex_color_smooth";
+ ot->description = "Smooth colors across vertices";
- /* api callbacks */
- ot->exec = vertex_color_smooth_exec;
- ot->poll = vertex_paint_mode_poll;
+ /* api callbacks */
+ ot->exec = vertex_color_smooth_exec;
+ ot->poll = vertex_paint_mode_poll;
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
/** \} */
@@ -351,231 +343,234 @@ void PAINT_OT_vertex_color_smooth(wmOperatorType *ot)
* \{ */
struct VPaintTx_BrightContrastData {
- /* pre-calculated */
- float gain;
- float offset;
+ /* pre-calculated */
+ float gain;
+ float offset;
};
-static void vpaint_tx_brightness_contrast(const float col[3], const void *user_data, float r_col[3])
+static void vpaint_tx_brightness_contrast(const float col[3],
+ const void *user_data,
+ float r_col[3])
{
- const struct VPaintTx_BrightContrastData *data = user_data;
+ const struct VPaintTx_BrightContrastData *data = user_data;
- for (int i = 0; i < 3; i++) {
- r_col[i] = data->gain * col[i] + data->offset;
- }
+ for (int i = 0; i < 3; i++) {
+ r_col[i] = data->gain * col[i] + data->offset;
+ }
}
static int vertex_color_brightness_contrast_exec(bContext *C, wmOperator *op)
{
- Object *obact = CTX_data_active_object(C);
-
- float gain, offset;
- {
- float brightness = RNA_float_get(op->ptr, "brightness");
- float contrast = RNA_float_get(op->ptr, "contrast");
- brightness /= 100.0f;
- float delta = contrast / 200.0f;
- gain = 1.0f - delta * 2.0f;
- /*
- * The algorithm is by Werner D. Streidt
- * (http://visca.com/ffactory/archives/5-99/msg00021.html)
- * Extracted of OpenCV demhist.c
- */
- if (contrast > 0) {
- gain = 1.0f / ((gain != 0.0f) ? gain : FLT_EPSILON);
- offset = gain * (brightness - delta);
- }
- else {
- delta *= -1;
- offset = gain * (brightness + delta);
- }
- }
-
- const struct VPaintTx_BrightContrastData user_data = {
- .gain = gain,
- .offset = offset,
- };
-
- if (ED_vpaint_color_transform(obact, vpaint_tx_brightness_contrast, &user_data)) {
- WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, obact);
- return OPERATOR_FINISHED;
- }
- else {
- return OPERATOR_CANCELLED;
- }
+ Object *obact = CTX_data_active_object(C);
+
+ float gain, offset;
+ {
+ float brightness = RNA_float_get(op->ptr, "brightness");
+ float contrast = RNA_float_get(op->ptr, "contrast");
+ brightness /= 100.0f;
+ float delta = contrast / 200.0f;
+ gain = 1.0f - delta * 2.0f;
+ /*
+ * The algorithm is by Werner D. Streidt
+ * (http://visca.com/ffactory/archives/5-99/msg00021.html)
+ * Extracted of OpenCV demhist.c
+ */
+ if (contrast > 0) {
+ gain = 1.0f / ((gain != 0.0f) ? gain : FLT_EPSILON);
+ offset = gain * (brightness - delta);
+ }
+ else {
+ delta *= -1;
+ offset = gain * (brightness + delta);
+ }
+ }
+
+ const struct VPaintTx_BrightContrastData user_data = {
+ .gain = gain,
+ .offset = offset,
+ };
+
+ if (ED_vpaint_color_transform(obact, vpaint_tx_brightness_contrast, &user_data)) {
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, obact);
+ return OPERATOR_FINISHED;
+ }
+ else {
+ return OPERATOR_CANCELLED;
+ }
}
void PAINT_OT_vertex_color_brightness_contrast(wmOperatorType *ot)
{
- PropertyRNA *prop;
+ PropertyRNA *prop;
- /* identifiers */
- ot->name = "Vertex Paint Bright/Contrast";
- ot->idname = "PAINT_OT_vertex_color_brightness_contrast";
- ot->description = "Adjust vertex color brightness/contrast";
+ /* identifiers */
+ ot->name = "Vertex Paint Bright/Contrast";
+ ot->idname = "PAINT_OT_vertex_color_brightness_contrast";
+ ot->description = "Adjust vertex color brightness/contrast";
- /* api callbacks */
- ot->exec = vertex_color_brightness_contrast_exec;
- ot->poll = vertex_paint_mode_poll;
+ /* api callbacks */
+ ot->exec = vertex_color_brightness_contrast_exec;
+ ot->poll = vertex_paint_mode_poll;
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- /* params */
- const float min = -100, max = +100;
- prop = RNA_def_float(ot->srna, "brightness", 0.0f, min, max, "Brightness", "", min, max);
- prop = RNA_def_float(ot->srna, "contrast", 0.0f, min, max, "Contrast", "", min, max);
- RNA_def_property_ui_range(prop, min, max, 1, 1);
+ /* params */
+ const float min = -100, max = +100;
+ prop = RNA_def_float(ot->srna, "brightness", 0.0f, min, max, "Brightness", "", min, max);
+ prop = RNA_def_float(ot->srna, "contrast", 0.0f, min, max, "Contrast", "", min, max);
+ RNA_def_property_ui_range(prop, min, max, 1, 1);
}
struct VPaintTx_HueSatData {
- float hue;
- float sat;
- float val;
+ float hue;
+ float sat;
+ float val;
};
static void vpaint_tx_hsv(const float col[3], const void *user_data, float r_col[3])
{
- const struct VPaintTx_HueSatData *data = user_data;
- float hsv[3];
- rgb_to_hsv_v(col, hsv);
-
- hsv[0] += (data->hue - 0.5f);
- if (hsv[0] > 1.0f) {
- hsv[0] -= 1.0f;
- }
- else if (hsv[0] < 0.0f) {
- hsv[0] += 1.0f;
- }
- hsv[1] *= data->sat;
- hsv[2] *= data->val;
-
- hsv_to_rgb_v(hsv, r_col);
+ const struct VPaintTx_HueSatData *data = user_data;
+ float hsv[3];
+ rgb_to_hsv_v(col, hsv);
+
+ hsv[0] += (data->hue - 0.5f);
+ if (hsv[0] > 1.0f) {
+ hsv[0] -= 1.0f;
+ }
+ else if (hsv[0] < 0.0f) {
+ hsv[0] += 1.0f;
+ }
+ hsv[1] *= data->sat;
+ hsv[2] *= data->val;
+
+ hsv_to_rgb_v(hsv, r_col);
}
static int vertex_color_hsv_exec(bContext *C, wmOperator *op)
{
- Object *obact = CTX_data_active_object(C);
-
- const struct VPaintTx_HueSatData user_data = {
- .hue = RNA_float_get(op->ptr, "h"),
- .sat = RNA_float_get(op->ptr, "s"),
- .val = RNA_float_get(op->ptr, "v"),
- };
-
- if (ED_vpaint_color_transform(obact, vpaint_tx_hsv, &user_data)) {
- WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, obact);
- return OPERATOR_FINISHED;
- }
- else {
- return OPERATOR_CANCELLED;
- }
+ Object *obact = CTX_data_active_object(C);
+
+ const struct VPaintTx_HueSatData user_data = {
+ .hue = RNA_float_get(op->ptr, "h"),
+ .sat = RNA_float_get(op->ptr, "s"),
+ .val = RNA_float_get(op->ptr, "v"),
+ };
+
+ if (ED_vpaint_color_transform(obact, vpaint_tx_hsv, &user_data)) {
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, obact);
+ return OPERATOR_FINISHED;
+ }
+ else {
+ return OPERATOR_CANCELLED;
+ }
}
void PAINT_OT_vertex_color_hsv(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Vertex Paint Hue Saturation Value";
- ot->idname = "PAINT_OT_vertex_color_hsv";
- ot->description = "Adjust vertex color HSV values";
-
- /* api callbacks */
- ot->exec = vertex_color_hsv_exec;
- ot->poll = vertex_paint_mode_poll;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* params */
- RNA_def_float(ot->srna, "h", 0.5f, 0.0f, 1.0f, "Hue", "", 0.0f, 1.0f);
- RNA_def_float(ot->srna, "s", 1.0f, 0.0f, 2.0f, "Saturation", "", 0.0f, 2.0f);
- RNA_def_float(ot->srna, "v", 1.0f, 0.0f, 2.0f, "Value", "", 0.0f, 2.0f);
+ /* identifiers */
+ ot->name = "Vertex Paint Hue Saturation Value";
+ ot->idname = "PAINT_OT_vertex_color_hsv";
+ ot->description = "Adjust vertex color HSV values";
+
+ /* api callbacks */
+ ot->exec = vertex_color_hsv_exec;
+ ot->poll = vertex_paint_mode_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* params */
+ RNA_def_float(ot->srna, "h", 0.5f, 0.0f, 1.0f, "Hue", "", 0.0f, 1.0f);
+ RNA_def_float(ot->srna, "s", 1.0f, 0.0f, 2.0f, "Saturation", "", 0.0f, 2.0f);
+ RNA_def_float(ot->srna, "v", 1.0f, 0.0f, 2.0f, "Value", "", 0.0f, 2.0f);
}
static void vpaint_tx_invert(const float col[3], const void *UNUSED(user_data), float r_col[3])
{
- for (int i = 0; i < 3; i++) {
- r_col[i] = 1.0f - col[i];
- }
+ for (int i = 0; i < 3; i++) {
+ r_col[i] = 1.0f - col[i];
+ }
}
static int vertex_color_invert_exec(bContext *C, wmOperator *UNUSED(op))
{
- Object *obact = CTX_data_active_object(C);
-
- if (ED_vpaint_color_transform(obact, vpaint_tx_invert, NULL)) {
- WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, obact);
- return OPERATOR_FINISHED;
- }
- else {
- return OPERATOR_CANCELLED;
- }
+ Object *obact = CTX_data_active_object(C);
+
+ if (ED_vpaint_color_transform(obact, vpaint_tx_invert, NULL)) {
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, obact);
+ return OPERATOR_FINISHED;
+ }
+ else {
+ return OPERATOR_CANCELLED;
+ }
}
void PAINT_OT_vertex_color_invert(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Vertex Paint Invert";
- ot->idname = "PAINT_OT_vertex_color_invert";
- ot->description = "Invert RGB values";
+ /* identifiers */
+ ot->name = "Vertex Paint Invert";
+ ot->idname = "PAINT_OT_vertex_color_invert";
+ ot->description = "Invert RGB values";
- /* api callbacks */
- ot->exec = vertex_color_invert_exec;
- ot->poll = vertex_paint_mode_poll;
+ /* api callbacks */
+ ot->exec = vertex_color_invert_exec;
+ ot->poll = vertex_paint_mode_poll;
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-
struct VPaintTx_LevelsData {
- float gain;
- float offset;
+ float gain;
+ float offset;
};
static void vpaint_tx_levels(const float col[3], const void *user_data, float r_col[3])
{
- const struct VPaintTx_LevelsData *data = user_data;
- for (int i = 0; i < 3; i++) {
- r_col[i] = data->gain * (col[i] + data->offset);
- }
+ const struct VPaintTx_LevelsData *data = user_data;
+ for (int i = 0; i < 3; i++) {
+ r_col[i] = data->gain * (col[i] + data->offset);
+ }
}
static int vertex_color_levels_exec(bContext *C, wmOperator *op)
{
- Object *obact = CTX_data_active_object(C);
-
- const struct VPaintTx_LevelsData user_data = {
- .gain = RNA_float_get(op->ptr, "gain"),
- .offset = RNA_float_get(op->ptr, "offset"),
- };
-
- if (ED_vpaint_color_transform(obact, vpaint_tx_levels, &user_data)) {
- WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, obact);
- return OPERATOR_FINISHED;
- }
- else {
- return OPERATOR_CANCELLED;
- }
+ Object *obact = CTX_data_active_object(C);
+
+ const struct VPaintTx_LevelsData user_data = {
+ .gain = RNA_float_get(op->ptr, "gain"),
+ .offset = RNA_float_get(op->ptr, "offset"),
+ };
+
+ if (ED_vpaint_color_transform(obact, vpaint_tx_levels, &user_data)) {
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, obact);
+ return OPERATOR_FINISHED;
+ }
+ else {
+ return OPERATOR_CANCELLED;
+ }
}
void PAINT_OT_vertex_color_levels(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Vertex Paint Levels";
- ot->idname = "PAINT_OT_vertex_color_levels";
- ot->description = "Adjust levels of vertex colors";
-
- /* api callbacks */
- ot->exec = vertex_color_levels_exec;
- ot->poll = vertex_paint_mode_poll;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* params */
- RNA_def_float(ot->srna, "offset", 0.0f, -1.0f, 1.0f, "Offset", "Value to add to colors", -1.0f, 1.0f);
- RNA_def_float(ot->srna, "gain", 1.0f, 0.0f, FLT_MAX, "Gain", "Value to multiply colors by", 0.0f, 10.0f);
+ /* identifiers */
+ ot->name = "Vertex Paint Levels";
+ ot->idname = "PAINT_OT_vertex_color_levels";
+ ot->description = "Adjust levels of vertex colors";
+
+ /* api callbacks */
+ ot->exec = vertex_color_levels_exec;
+ ot->poll = vertex_paint_mode_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* params */
+ RNA_def_float(
+ ot->srna, "offset", 0.0f, -1.0f, 1.0f, "Offset", "Value to add to colors", -1.0f, 1.0f);
+ RNA_def_float(
+ ot->srna, "gain", 1.0f, 0.0f, FLT_MAX, "Gain", "Value to multiply colors by", 0.0f, 10.0f);
}
/** \} */
diff --git a/source/blender/editors/sculpt_paint/paint_vertex_color_utils.c b/source/blender/editors/sculpt_paint/paint_vertex_color_utils.c
index 4a5c72e5199..6511c90f5e1 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex_color_utils.c
+++ b/source/blender/editors/sculpt_paint/paint_vertex_color_utils.c
@@ -41,53 +41,50 @@
#include "ED_mesh.h"
-#include "paint_intern.h" /* own include */
+#include "paint_intern.h" /* own include */
#define EPS_SATURATION 0.0005f
/**
* Apply callback to each vertex of the active vertex color layer.
*/
-bool ED_vpaint_color_transform(
- struct Object *ob,
- VPaintTransform_Callback vpaint_tx_fn,
- const void *user_data)
+bool ED_vpaint_color_transform(struct Object *ob,
+ VPaintTransform_Callback vpaint_tx_fn,
+ const void *user_data)
{
- Mesh *me;
- const MPoly *mp;
+ Mesh *me;
+ const MPoly *mp;
- if (((me = BKE_mesh_from_object(ob)) == NULL) ||
- (ED_mesh_color_ensure(me, NULL) == false))
- {
- return false;
- }
+ if (((me = BKE_mesh_from_object(ob)) == NULL) || (ED_mesh_color_ensure(me, NULL) == false)) {
+ return false;
+ }
- const bool use_face_sel = (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
- mp = me->mpoly;
+ const bool use_face_sel = (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
+ mp = me->mpoly;
- for (int i = 0; i < me->totpoly; i++, mp++) {
- MLoopCol *lcol = &me->mloopcol[mp->loopstart];
+ for (int i = 0; i < me->totpoly; i++, mp++) {
+ MLoopCol *lcol = &me->mloopcol[mp->loopstart];
- if (use_face_sel && !(mp->flag & ME_FACE_SEL)) {
- continue;
- }
+ if (use_face_sel && !(mp->flag & ME_FACE_SEL)) {
+ continue;
+ }
- for (int j = 0; j < mp->totloop; j++, lcol++) {
- float col_mix[3];
- rgb_uchar_to_float(col_mix, &lcol->r);
+ for (int j = 0; j < mp->totloop; j++, lcol++) {
+ float col_mix[3];
+ rgb_uchar_to_float(col_mix, &lcol->r);
- vpaint_tx_fn(col_mix, user_data, col_mix);
+ vpaint_tx_fn(col_mix, user_data, col_mix);
- rgb_float_to_uchar(&lcol->r, col_mix);
- }
- }
+ rgb_float_to_uchar(&lcol->r, col_mix);
+ }
+ }
- /* remove stale me->mcol, will be added later */
- BKE_mesh_tessface_clear(me);
+ /* remove stale me->mcol, will be added later */
+ BKE_mesh_tessface_clear(me);
- DEG_id_tag_update(&me->id, 0);
+ DEG_id_tag_update(&me->id, 0);
- return true;
+ return true;
}
/* -------------------------------------------------------------------- */
@@ -96,548 +93,566 @@ bool ED_vpaint_color_transform(
BLI_INLINE uint mcol_blend(uint col_src, uint col_dst, int fac)
{
- uchar *cp_src, *cp_dst, *cp_mix;
- int mfac;
- uint col_mix = 0;
+ uchar *cp_src, *cp_dst, *cp_mix;
+ int mfac;
+ uint col_mix = 0;
- if (fac == 0) {
- return col_src;
- }
+ if (fac == 0) {
+ return col_src;
+ }
- if (fac >= 255) {
- return col_dst;
- }
+ if (fac >= 255) {
+ return col_dst;
+ }
- mfac = 255 - fac;
+ mfac = 255 - fac;
- cp_src = (uchar *)&col_src;
- cp_dst = (uchar *)&col_dst;
- cp_mix = (uchar *)&col_mix;
+ cp_src = (uchar *)&col_src;
+ cp_dst = (uchar *)&col_dst;
+ cp_mix = (uchar *)&col_mix;
- /* Updated to use the rgb squared color model which blends nicer. */
- int r1 = cp_src[0] * cp_src[0];
- int g1 = cp_src[1] * cp_src[1];
- int b1 = cp_src[2] * cp_src[2];
- int a1 = cp_src[3] * cp_src[3];
+ /* Updated to use the rgb squared color model which blends nicer. */
+ int r1 = cp_src[0] * cp_src[0];
+ int g1 = cp_src[1] * cp_src[1];
+ int b1 = cp_src[2] * cp_src[2];
+ int a1 = cp_src[3] * cp_src[3];
- int r2 = cp_dst[0] * cp_dst[0];
- int g2 = cp_dst[1] * cp_dst[1];
- int b2 = cp_dst[2] * cp_dst[2];
- int a2 = cp_dst[3] * cp_dst[3];
+ int r2 = cp_dst[0] * cp_dst[0];
+ int g2 = cp_dst[1] * cp_dst[1];
+ int b2 = cp_dst[2] * cp_dst[2];
+ int a2 = cp_dst[3] * cp_dst[3];
- cp_mix[0] = round_fl_to_uchar(sqrtf(divide_round_i((mfac * r1 + fac * r2), 255)));
- cp_mix[1] = round_fl_to_uchar(sqrtf(divide_round_i((mfac * g1 + fac * g2), 255)));
- cp_mix[2] = round_fl_to_uchar(sqrtf(divide_round_i((mfac * b1 + fac * b2), 255)));
- cp_mix[3] = round_fl_to_uchar(sqrtf(divide_round_i((mfac * a1 + fac * a2), 255)));
+ cp_mix[0] = round_fl_to_uchar(sqrtf(divide_round_i((mfac * r1 + fac * r2), 255)));
+ cp_mix[1] = round_fl_to_uchar(sqrtf(divide_round_i((mfac * g1 + fac * g2), 255)));
+ cp_mix[2] = round_fl_to_uchar(sqrtf(divide_round_i((mfac * b1 + fac * b2), 255)));
+ cp_mix[3] = round_fl_to_uchar(sqrtf(divide_round_i((mfac * a1 + fac * a2), 255)));
- return col_mix;
+ return col_mix;
}
BLI_INLINE uint mcol_add(uint col_src, uint col_dst, int fac)
{
- uchar *cp_src, *cp_dst, *cp_mix;
- int temp;
- uint col_mix = 0;
-
- if (fac == 0) {
- return col_src;
- }
-
- cp_src = (uchar *)&col_src;
- cp_dst = (uchar *)&col_dst;
- cp_mix = (uchar *)&col_mix;
-
- temp = cp_src[0] + divide_round_i((fac * cp_dst[0]), 255);
- cp_mix[0] = (temp > 254) ? 255 : temp;
- temp = cp_src[1] + divide_round_i((fac * cp_dst[1]), 255);
- cp_mix[1] = (temp > 254) ? 255 : temp;
- temp = cp_src[2] + divide_round_i((fac * cp_dst[2]), 255);
- cp_mix[2] = (temp > 254) ? 255 : temp;
- temp = cp_src[3] + divide_round_i((fac * cp_dst[3]), 255);
- cp_mix[3] = (temp > 254) ? 255 : temp;
-
- return col_mix;
+ uchar *cp_src, *cp_dst, *cp_mix;
+ int temp;
+ uint col_mix = 0;
+
+ if (fac == 0) {
+ return col_src;
+ }
+
+ cp_src = (uchar *)&col_src;
+ cp_dst = (uchar *)&col_dst;
+ cp_mix = (uchar *)&col_mix;
+
+ temp = cp_src[0] + divide_round_i((fac * cp_dst[0]), 255);
+ cp_mix[0] = (temp > 254) ? 255 : temp;
+ temp = cp_src[1] + divide_round_i((fac * cp_dst[1]), 255);
+ cp_mix[1] = (temp > 254) ? 255 : temp;
+ temp = cp_src[2] + divide_round_i((fac * cp_dst[2]), 255);
+ cp_mix[2] = (temp > 254) ? 255 : temp;
+ temp = cp_src[3] + divide_round_i((fac * cp_dst[3]), 255);
+ cp_mix[3] = (temp > 254) ? 255 : temp;
+
+ return col_mix;
}
BLI_INLINE uint mcol_sub(uint col_src, uint col_dst, int fac)
{
- uchar *cp_src, *cp_dst, *cp_mix;
- int temp;
- uint col_mix = 0;
-
- if (fac == 0) {
- return col_src;
- }
-
- cp_src = (uchar *)&col_src;
- cp_dst = (uchar *)&col_dst;
- cp_mix = (uchar *)&col_mix;
-
- temp = cp_src[0] - divide_round_i((fac * cp_dst[0]), 255);
- cp_mix[0] = (temp < 0) ? 0 : temp;
- temp = cp_src[1] - divide_round_i((fac * cp_dst[1]), 255);
- cp_mix[1] = (temp < 0) ? 0 : temp;
- temp = cp_src[2] - divide_round_i((fac * cp_dst[2]), 255);
- cp_mix[2] = (temp < 0) ? 0 : temp;
- temp = cp_src[3] - divide_round_i((fac * cp_dst[3]), 255);
- cp_mix[3] = (temp < 0) ? 0 : temp;
-
- return col_mix;
+ uchar *cp_src, *cp_dst, *cp_mix;
+ int temp;
+ uint col_mix = 0;
+
+ if (fac == 0) {
+ return col_src;
+ }
+
+ cp_src = (uchar *)&col_src;
+ cp_dst = (uchar *)&col_dst;
+ cp_mix = (uchar *)&col_mix;
+
+ temp = cp_src[0] - divide_round_i((fac * cp_dst[0]), 255);
+ cp_mix[0] = (temp < 0) ? 0 : temp;
+ temp = cp_src[1] - divide_round_i((fac * cp_dst[1]), 255);
+ cp_mix[1] = (temp < 0) ? 0 : temp;
+ temp = cp_src[2] - divide_round_i((fac * cp_dst[2]), 255);
+ cp_mix[2] = (temp < 0) ? 0 : temp;
+ temp = cp_src[3] - divide_round_i((fac * cp_dst[3]), 255);
+ cp_mix[3] = (temp < 0) ? 0 : temp;
+
+ return col_mix;
}
BLI_INLINE uint mcol_mul(uint col_src, uint col_dst, int fac)
{
- uchar *cp_src, *cp_dst, *cp_mix;
- int mfac;
- uint col_mix = 0;
+ uchar *cp_src, *cp_dst, *cp_mix;
+ int mfac;
+ uint col_mix = 0;
- if (fac == 0) {
- return col_src;
- }
+ if (fac == 0) {
+ return col_src;
+ }
- mfac = 255 - fac;
+ mfac = 255 - fac;
- cp_src = (uchar *)&col_src;
- cp_dst = (uchar *)&col_dst;
- cp_mix = (uchar *)&col_mix;
+ cp_src = (uchar *)&col_src;
+ cp_dst = (uchar *)&col_dst;
+ cp_mix = (uchar *)&col_mix;
- /* first mul, then blend the fac */
- cp_mix[0] = divide_round_i(mfac * cp_src[0] * 255 + fac * cp_dst[0] * cp_src[0], 255 * 255);
- cp_mix[1] = divide_round_i(mfac * cp_src[1] * 255 + fac * cp_dst[1] * cp_src[1], 255 * 255);
- cp_mix[2] = divide_round_i(mfac * cp_src[2] * 255 + fac * cp_dst[2] * cp_src[2], 255 * 255);
- cp_mix[3] = divide_round_i(mfac * cp_src[3] * 255 + fac * cp_dst[3] * cp_src[3], 255 * 255);
+ /* first mul, then blend the fac */
+ cp_mix[0] = divide_round_i(mfac * cp_src[0] * 255 + fac * cp_dst[0] * cp_src[0], 255 * 255);
+ cp_mix[1] = divide_round_i(mfac * cp_src[1] * 255 + fac * cp_dst[1] * cp_src[1], 255 * 255);
+ cp_mix[2] = divide_round_i(mfac * cp_src[2] * 255 + fac * cp_dst[2] * cp_src[2], 255 * 255);
+ cp_mix[3] = divide_round_i(mfac * cp_src[3] * 255 + fac * cp_dst[3] * cp_src[3], 255 * 255);
- return col_mix;
+ return col_mix;
}
BLI_INLINE uint mcol_lighten(uint col_src, uint col_dst, int fac)
{
- uchar *cp_src, *cp_dst, *cp_mix;
- int mfac;
- uint col_mix = 0;
-
- if (fac == 0) {
- return col_src;
- }
- else if (fac >= 255) {
- return col_dst;
- }
-
- mfac = 255 - fac;
-
- cp_src = (uchar *)&col_src;
- cp_dst = (uchar *)&col_dst;
- cp_mix = (uchar *)&col_mix;
-
- /* See if are lighter, if so mix, else don't do anything.
- * if the paint color is darker then the original, then ignore */
- if (IMB_colormanagement_get_luminance_byte(cp_src) > IMB_colormanagement_get_luminance_byte(cp_dst)) {
- return col_src;
- }
-
- cp_mix[0] = divide_round_i(mfac * cp_src[0] + fac * cp_dst[0], 255);
- cp_mix[1] = divide_round_i(mfac * cp_src[1] + fac * cp_dst[1], 255);
- cp_mix[2] = divide_round_i(mfac * cp_src[2] + fac * cp_dst[2], 255);
- cp_mix[3] = divide_round_i(mfac * cp_src[3] + fac * cp_dst[3], 255);
-
- return col_mix;
+ uchar *cp_src, *cp_dst, *cp_mix;
+ int mfac;
+ uint col_mix = 0;
+
+ if (fac == 0) {
+ return col_src;
+ }
+ else if (fac >= 255) {
+ return col_dst;
+ }
+
+ mfac = 255 - fac;
+
+ cp_src = (uchar *)&col_src;
+ cp_dst = (uchar *)&col_dst;
+ cp_mix = (uchar *)&col_mix;
+
+ /* See if are lighter, if so mix, else don't do anything.
+ * if the paint color is darker then the original, then ignore */
+ if (IMB_colormanagement_get_luminance_byte(cp_src) >
+ IMB_colormanagement_get_luminance_byte(cp_dst)) {
+ return col_src;
+ }
+
+ cp_mix[0] = divide_round_i(mfac * cp_src[0] + fac * cp_dst[0], 255);
+ cp_mix[1] = divide_round_i(mfac * cp_src[1] + fac * cp_dst[1], 255);
+ cp_mix[2] = divide_round_i(mfac * cp_src[2] + fac * cp_dst[2], 255);
+ cp_mix[3] = divide_round_i(mfac * cp_src[3] + fac * cp_dst[3], 255);
+
+ return col_mix;
}
BLI_INLINE uint mcol_darken(uint col_src, uint col_dst, int fac)
{
- uchar *cp_src, *cp_dst, *cp_mix;
- int mfac;
- uint col_mix = 0;
-
- if (fac == 0) {
- return col_src;
- }
- else if (fac >= 255) {
- return col_dst;
- }
-
- mfac = 255 - fac;
-
- cp_src = (uchar *)&col_src;
- cp_dst = (uchar *)&col_dst;
- cp_mix = (uchar *)&col_mix;
-
- /* See if were darker, if so mix, else don't do anything.
- * if the paint color is brighter then the original, then ignore */
- if (IMB_colormanagement_get_luminance_byte(cp_src) < IMB_colormanagement_get_luminance_byte(cp_dst)) {
- return col_src;
- }
-
- cp_mix[0] = divide_round_i((mfac * cp_src[0] + fac * cp_dst[0]), 255);
- cp_mix[1] = divide_round_i((mfac * cp_src[1] + fac * cp_dst[1]), 255);
- cp_mix[2] = divide_round_i((mfac * cp_src[2] + fac * cp_dst[2]), 255);
- cp_mix[3] = divide_round_i((mfac * cp_src[3] + fac * cp_dst[3]), 255);
- return col_mix;
+ uchar *cp_src, *cp_dst, *cp_mix;
+ int mfac;
+ uint col_mix = 0;
+
+ if (fac == 0) {
+ return col_src;
+ }
+ else if (fac >= 255) {
+ return col_dst;
+ }
+
+ mfac = 255 - fac;
+
+ cp_src = (uchar *)&col_src;
+ cp_dst = (uchar *)&col_dst;
+ cp_mix = (uchar *)&col_mix;
+
+ /* See if were darker, if so mix, else don't do anything.
+ * if the paint color is brighter then the original, then ignore */
+ if (IMB_colormanagement_get_luminance_byte(cp_src) <
+ IMB_colormanagement_get_luminance_byte(cp_dst)) {
+ return col_src;
+ }
+
+ cp_mix[0] = divide_round_i((mfac * cp_src[0] + fac * cp_dst[0]), 255);
+ cp_mix[1] = divide_round_i((mfac * cp_src[1] + fac * cp_dst[1]), 255);
+ cp_mix[2] = divide_round_i((mfac * cp_src[2] + fac * cp_dst[2]), 255);
+ cp_mix[3] = divide_round_i((mfac * cp_src[3] + fac * cp_dst[3]), 255);
+ return col_mix;
}
BLI_INLINE uint mcol_colordodge(uint col_src, uint col_dst, int fac)
{
- uchar *cp_src, *cp_dst, *cp_mix;
- int mfac, temp;
- uint col_mix = 0;
-
- if (fac == 0) {
- return col_src;
- }
-
- mfac = 255 - fac;
-
- cp_src = (uchar *)&col_src;
- cp_dst = (uchar *)&col_dst;
- cp_mix = (uchar *)&col_mix;
-
- temp = (cp_dst[0] == 255) ? 255 : min_ii((cp_src[0] * 225) / (255 - cp_dst[0]), 255);
- cp_mix[0] = (mfac * cp_src[0] + temp * fac) / 255;
- temp = (cp_dst[1] == 255) ? 255 : min_ii((cp_src[1] * 225) / (255 - cp_dst[1]), 255);
- cp_mix[1] = (mfac * cp_src[1] + temp * fac) / 255;
- temp = (cp_dst[2] == 255) ? 255 : min_ii((cp_src[2] * 225) / (255 - cp_dst[2]), 255);
- cp_mix[2] = (mfac * cp_src[2] + temp * fac) / 255;
- temp = (cp_dst[3] == 255) ? 255 : min_ii((cp_src[3] * 225) / (255 - cp_dst[3]), 255);
- cp_mix[3] = (mfac * cp_src[3] + temp * fac) / 255;
- return col_mix;
+ uchar *cp_src, *cp_dst, *cp_mix;
+ int mfac, temp;
+ uint col_mix = 0;
+
+ if (fac == 0) {
+ return col_src;
+ }
+
+ mfac = 255 - fac;
+
+ cp_src = (uchar *)&col_src;
+ cp_dst = (uchar *)&col_dst;
+ cp_mix = (uchar *)&col_mix;
+
+ temp = (cp_dst[0] == 255) ? 255 : min_ii((cp_src[0] * 225) / (255 - cp_dst[0]), 255);
+ cp_mix[0] = (mfac * cp_src[0] + temp * fac) / 255;
+ temp = (cp_dst[1] == 255) ? 255 : min_ii((cp_src[1] * 225) / (255 - cp_dst[1]), 255);
+ cp_mix[1] = (mfac * cp_src[1] + temp * fac) / 255;
+ temp = (cp_dst[2] == 255) ? 255 : min_ii((cp_src[2] * 225) / (255 - cp_dst[2]), 255);
+ cp_mix[2] = (mfac * cp_src[2] + temp * fac) / 255;
+ temp = (cp_dst[3] == 255) ? 255 : min_ii((cp_src[3] * 225) / (255 - cp_dst[3]), 255);
+ cp_mix[3] = (mfac * cp_src[3] + temp * fac) / 255;
+ return col_mix;
}
BLI_INLINE uint mcol_difference(uint col_src, uint col_dst, int fac)
{
- uchar *cp_src, *cp_dst, *cp_mix;
- int mfac, temp;
- uint col_mix = 0;
-
- if (fac == 0) {
- return col_src;
- }
-
- mfac = 255 - fac;
-
- cp_src = (uchar *)&col_src;
- cp_dst = (uchar *)&col_dst;
- cp_mix = (uchar *)&col_mix;
-
- temp = abs(cp_src[0] - cp_dst[0]);
- cp_mix[0] = (mfac * cp_src[0] + temp * fac) / 255;
- temp = abs(cp_src[1] - cp_dst[1]);
- cp_mix[1] = (mfac * cp_src[1] + temp * fac) / 255;
- temp = abs(cp_src[2] - cp_dst[2]);
- cp_mix[2] = (mfac * cp_src[2] + temp * fac) / 255;
- temp = abs(cp_src[3] - cp_dst[3]);
- cp_mix[3] = (mfac * cp_src[3] + temp * fac) / 255;
- return col_mix;
+ uchar *cp_src, *cp_dst, *cp_mix;
+ int mfac, temp;
+ uint col_mix = 0;
+
+ if (fac == 0) {
+ return col_src;
+ }
+
+ mfac = 255 - fac;
+
+ cp_src = (uchar *)&col_src;
+ cp_dst = (uchar *)&col_dst;
+ cp_mix = (uchar *)&col_mix;
+
+ temp = abs(cp_src[0] - cp_dst[0]);
+ cp_mix[0] = (mfac * cp_src[0] + temp * fac) / 255;
+ temp = abs(cp_src[1] - cp_dst[1]);
+ cp_mix[1] = (mfac * cp_src[1] + temp * fac) / 255;
+ temp = abs(cp_src[2] - cp_dst[2]);
+ cp_mix[2] = (mfac * cp_src[2] + temp * fac) / 255;
+ temp = abs(cp_src[3] - cp_dst[3]);
+ cp_mix[3] = (mfac * cp_src[3] + temp * fac) / 255;
+ return col_mix;
}
BLI_INLINE uint mcol_screen(uint col_src, uint col_dst, int fac)
{
- uchar *cp_src, *cp_dst, *cp_mix;
- int mfac, temp;
- uint col_mix = 0;
-
- if (fac == 0) {
- return col_src;
- }
-
- mfac = 255 - fac;
-
- cp_src = (uchar *)&col_src;
- cp_dst = (uchar *)&col_dst;
- cp_mix = (uchar *)&col_mix;
-
- temp = max_ii(255 - (((255 - cp_src[0]) * (255 - cp_dst[0])) / 255), 0);
- cp_mix[0] = (mfac * cp_src[0] + temp * fac) / 255;
- temp = max_ii(255 - (((255 - cp_src[1]) * (255 - cp_dst[1])) / 255), 0);
- cp_mix[1] = (mfac * cp_src[1] + temp * fac) / 255;
- temp = max_ii(255 - (((255 - cp_src[2]) * (255 - cp_dst[2])) / 255), 0);
- cp_mix[2] = (mfac * cp_src[2] + temp * fac) / 255;
- temp = max_ii(255 - (((255 - cp_src[3]) * (255 - cp_dst[3])) / 255), 0);
- cp_mix[3] = (mfac * cp_src[3] + temp * fac) / 255;
- return col_mix;
+ uchar *cp_src, *cp_dst, *cp_mix;
+ int mfac, temp;
+ uint col_mix = 0;
+
+ if (fac == 0) {
+ return col_src;
+ }
+
+ mfac = 255 - fac;
+
+ cp_src = (uchar *)&col_src;
+ cp_dst = (uchar *)&col_dst;
+ cp_mix = (uchar *)&col_mix;
+
+ temp = max_ii(255 - (((255 - cp_src[0]) * (255 - cp_dst[0])) / 255), 0);
+ cp_mix[0] = (mfac * cp_src[0] + temp * fac) / 255;
+ temp = max_ii(255 - (((255 - cp_src[1]) * (255 - cp_dst[1])) / 255), 0);
+ cp_mix[1] = (mfac * cp_src[1] + temp * fac) / 255;
+ temp = max_ii(255 - (((255 - cp_src[2]) * (255 - cp_dst[2])) / 255), 0);
+ cp_mix[2] = (mfac * cp_src[2] + temp * fac) / 255;
+ temp = max_ii(255 - (((255 - cp_src[3]) * (255 - cp_dst[3])) / 255), 0);
+ cp_mix[3] = (mfac * cp_src[3] + temp * fac) / 255;
+ return col_mix;
}
BLI_INLINE uint mcol_hardlight(uint col_src, uint col_dst, int fac)
{
- uchar *cp_src, *cp_dst, *cp_mix;
- int mfac, temp;
- uint col_mix = 0;
-
- if (fac == 0) {
- return col_src;
- }
-
- mfac = 255 - fac;
-
- cp_src = (uchar *)&col_src;
- cp_dst = (uchar *)&col_dst;
- cp_mix = (uchar *)&col_mix;
-
- int i = 0;
-
- for (i = 0; i < 4; i++) {
- if (cp_dst[i] > 127) {
- temp = 255 - ((255 - 2 * (cp_dst[i] - 127)) * (255 - cp_src[i]) / 255);
- }
- else {
- temp = (2 * cp_dst[i] * cp_src[i]) >> 8;
- }
- cp_mix[i] = min_ii((mfac * cp_src[i] + temp * fac) / 255, 255);
- }
- return col_mix;
+ uchar *cp_src, *cp_dst, *cp_mix;
+ int mfac, temp;
+ uint col_mix = 0;
+
+ if (fac == 0) {
+ return col_src;
+ }
+
+ mfac = 255 - fac;
+
+ cp_src = (uchar *)&col_src;
+ cp_dst = (uchar *)&col_dst;
+ cp_mix = (uchar *)&col_mix;
+
+ int i = 0;
+
+ for (i = 0; i < 4; i++) {
+ if (cp_dst[i] > 127) {
+ temp = 255 - ((255 - 2 * (cp_dst[i] - 127)) * (255 - cp_src[i]) / 255);
+ }
+ else {
+ temp = (2 * cp_dst[i] * cp_src[i]) >> 8;
+ }
+ cp_mix[i] = min_ii((mfac * cp_src[i] + temp * fac) / 255, 255);
+ }
+ return col_mix;
}
BLI_INLINE uint mcol_overlay(uint col_src, uint col_dst, int fac)
{
- uchar *cp_src, *cp_dst, *cp_mix;
- int mfac, temp;
- uint col_mix = 0;
-
- if (fac == 0) {
- return col_src;
- }
-
- mfac = 255 - fac;
-
- cp_src = (uchar *)&col_src;
- cp_dst = (uchar *)&col_dst;
- cp_mix = (uchar *)&col_mix;
-
- int i = 0;
-
- for (i = 0; i < 4; i++) {
- if (cp_src[i] > 127) {
- temp = 255 - ((255 - 2 * (cp_src[i] - 127)) * (255 - cp_dst[i]) / 255);
- }
- else {
- temp = (2 * cp_dst[i] * cp_src[i]) >> 8;
- }
- cp_mix[i] = min_ii((mfac * cp_src[i] + temp * fac) / 255, 255);
- }
- return col_mix;
+ uchar *cp_src, *cp_dst, *cp_mix;
+ int mfac, temp;
+ uint col_mix = 0;
+
+ if (fac == 0) {
+ return col_src;
+ }
+
+ mfac = 255 - fac;
+
+ cp_src = (uchar *)&col_src;
+ cp_dst = (uchar *)&col_dst;
+ cp_mix = (uchar *)&col_mix;
+
+ int i = 0;
+
+ for (i = 0; i < 4; i++) {
+ if (cp_src[i] > 127) {
+ temp = 255 - ((255 - 2 * (cp_src[i] - 127)) * (255 - cp_dst[i]) / 255);
+ }
+ else {
+ temp = (2 * cp_dst[i] * cp_src[i]) >> 8;
+ }
+ cp_mix[i] = min_ii((mfac * cp_src[i] + temp * fac) / 255, 255);
+ }
+ return col_mix;
}
BLI_INLINE uint mcol_softlight(uint col_src, uint col_dst, int fac)
{
- uchar *cp_src, *cp_dst, *cp_mix;
- int mfac, temp;
- uint col_mix = 0;
-
- if (fac == 0) {
- return col_src;
- }
-
- mfac = 255 - fac;
-
- cp_src = (uchar *)&col_src;
- cp_dst = (uchar *)&col_dst;
- cp_mix = (uchar *)&col_mix;
-
- int i = 0;
-
- for (i = 0; i < 4; i++) {
- if (cp_src[i] < 127) {
- temp = ((2 * ((cp_dst[i] / 2) + 64)) * cp_src[i]) / 255;
- }
- else {
- temp = 255 - (2 * (255 - ((cp_dst[i] / 2) + 64)) * (255 - cp_src[i]) / 255);
- }
- cp_mix[i] = (temp * fac + cp_src[i] * mfac) / 255;
- }
- return col_mix;
+ uchar *cp_src, *cp_dst, *cp_mix;
+ int mfac, temp;
+ uint col_mix = 0;
+
+ if (fac == 0) {
+ return col_src;
+ }
+
+ mfac = 255 - fac;
+
+ cp_src = (uchar *)&col_src;
+ cp_dst = (uchar *)&col_dst;
+ cp_mix = (uchar *)&col_mix;
+
+ int i = 0;
+
+ for (i = 0; i < 4; i++) {
+ if (cp_src[i] < 127) {
+ temp = ((2 * ((cp_dst[i] / 2) + 64)) * cp_src[i]) / 255;
+ }
+ else {
+ temp = 255 - (2 * (255 - ((cp_dst[i] / 2) + 64)) * (255 - cp_src[i]) / 255);
+ }
+ cp_mix[i] = (temp * fac + cp_src[i] * mfac) / 255;
+ }
+ return col_mix;
}
BLI_INLINE uint mcol_exclusion(uint col_src, uint col_dst, int fac)
{
- uchar *cp_src, *cp_dst, *cp_mix;
- int mfac, temp;
- uint col_mix = 0;
+ uchar *cp_src, *cp_dst, *cp_mix;
+ int mfac, temp;
+ uint col_mix = 0;
- if (fac == 0) {
- return col_src;
- }
+ if (fac == 0) {
+ return col_src;
+ }
- mfac = 255 - fac;
+ mfac = 255 - fac;
- cp_src = (uchar *)&col_src;
- cp_dst = (uchar *)&col_dst;
- cp_mix = (uchar *)&col_mix;
+ cp_src = (uchar *)&col_src;
+ cp_dst = (uchar *)&col_dst;
+ cp_mix = (uchar *)&col_mix;
- int i = 0;
+ int i = 0;
- for (i = 0; i < 4; i++) {
- temp = 127 - ((2 * (cp_src[i] - 127) * (cp_dst[i] - 127)) / 255);
- cp_mix[i] = (temp * fac + cp_src[i] * mfac) / 255;
- }
- return col_mix;
+ for (i = 0; i < 4; i++) {
+ temp = 127 - ((2 * (cp_src[i] - 127) * (cp_dst[i] - 127)) / 255);
+ cp_mix[i] = (temp * fac + cp_src[i] * mfac) / 255;
+ }
+ return col_mix;
}
BLI_INLINE uint mcol_luminosity(uint col_src, uint col_dst, int fac)
{
- uchar *cp_src, *cp_dst, *cp_mix;
- int mfac;
- uint col_mix = 0;
+ uchar *cp_src, *cp_dst, *cp_mix;
+ int mfac;
+ uint col_mix = 0;
- if (fac == 0) {
- return col_src;
- }
+ if (fac == 0) {
+ return col_src;
+ }
- mfac = 255 - fac;
+ mfac = 255 - fac;
- cp_src = (uchar *)&col_src;
- cp_dst = (uchar *)&col_dst;
- cp_mix = (uchar *)&col_mix;
+ cp_src = (uchar *)&col_src;
+ cp_dst = (uchar *)&col_dst;
+ cp_mix = (uchar *)&col_mix;
- float h1, s1, v1;
- float h2, s2, v2;
- float r, g, b;
- rgb_to_hsv(cp_src[0] / 255.0f, cp_src[1] / 255.0f, cp_src[2] / 255.0f, &h1, &s1, &v1);
- rgb_to_hsv(cp_dst[0] / 255.0f, cp_dst[1] / 255.0f, cp_dst[2] / 255.0f, &h2, &s2, &v2);
+ float h1, s1, v1;
+ float h2, s2, v2;
+ float r, g, b;
+ rgb_to_hsv(cp_src[0] / 255.0f, cp_src[1] / 255.0f, cp_src[2] / 255.0f, &h1, &s1, &v1);
+ rgb_to_hsv(cp_dst[0] / 255.0f, cp_dst[1] / 255.0f, cp_dst[2] / 255.0f, &h2, &s2, &v2);
- v1 = v2;
+ v1 = v2;
- hsv_to_rgb(h1, s1, v1, &r, &g, &b);
+ hsv_to_rgb(h1, s1, v1, &r, &g, &b);
- cp_mix[0] = ((int)(r * 255.0f) * fac + mfac * cp_src[0]) / 255;
- cp_mix[1] = ((int)(g * 255.0f) * fac + mfac * cp_src[1]) / 255;
- cp_mix[2] = ((int)(b * 255.0f) * fac + mfac * cp_src[2]) / 255;
- cp_mix[3] = ((int)(cp_dst[3]) * fac + mfac * cp_src[3]) / 255;
- return col_mix;
+ cp_mix[0] = ((int)(r * 255.0f) * fac + mfac * cp_src[0]) / 255;
+ cp_mix[1] = ((int)(g * 255.0f) * fac + mfac * cp_src[1]) / 255;
+ cp_mix[2] = ((int)(b * 255.0f) * fac + mfac * cp_src[2]) / 255;
+ cp_mix[3] = ((int)(cp_dst[3]) * fac + mfac * cp_src[3]) / 255;
+ return col_mix;
}
BLI_INLINE uint mcol_saturation(uint col_src, uint col_dst, int fac)
{
- uchar *cp_src, *cp_dst, *cp_mix;
- int mfac;
- uint col_mix = 0;
+ uchar *cp_src, *cp_dst, *cp_mix;
+ int mfac;
+ uint col_mix = 0;
- if (fac == 0) {
- return col_src;
- }
+ if (fac == 0) {
+ return col_src;
+ }
- mfac = 255 - fac;
+ mfac = 255 - fac;
- cp_src = (uchar *)&col_src;
- cp_dst = (uchar *)&col_dst;
- cp_mix = (uchar *)&col_mix;
+ cp_src = (uchar *)&col_src;
+ cp_dst = (uchar *)&col_dst;
+ cp_mix = (uchar *)&col_mix;
- float h1, s1, v1;
- float h2, s2, v2;
- float r, g, b;
- rgb_to_hsv(cp_src[0] / 255.0f, cp_src[1] / 255.0f, cp_src[2] / 255.0f, &h1, &s1, &v1);
- rgb_to_hsv(cp_dst[0] / 255.0f, cp_dst[1] / 255.0f, cp_dst[2] / 255.0f, &h2, &s2, &v2);
+ float h1, s1, v1;
+ float h2, s2, v2;
+ float r, g, b;
+ rgb_to_hsv(cp_src[0] / 255.0f, cp_src[1] / 255.0f, cp_src[2] / 255.0f, &h1, &s1, &v1);
+ rgb_to_hsv(cp_dst[0] / 255.0f, cp_dst[1] / 255.0f, cp_dst[2] / 255.0f, &h2, &s2, &v2);
- if (s1 > EPS_SATURATION) {
- s1 = s2;
- }
+ if (s1 > EPS_SATURATION) {
+ s1 = s2;
+ }
- hsv_to_rgb(h1, s1, v1, &r, &g, &b);
+ hsv_to_rgb(h1, s1, v1, &r, &g, &b);
- cp_mix[0] = ((int)(r * 255.0f) * fac + mfac * cp_src[0]) / 255;
- cp_mix[1] = ((int)(g * 255.0f) * fac + mfac * cp_src[1]) / 255;
- cp_mix[2] = ((int)(b * 255.0f) * fac + mfac * cp_src[2]) / 255;
- return col_mix;
+ cp_mix[0] = ((int)(r * 255.0f) * fac + mfac * cp_src[0]) / 255;
+ cp_mix[1] = ((int)(g * 255.0f) * fac + mfac * cp_src[1]) / 255;
+ cp_mix[2] = ((int)(b * 255.0f) * fac + mfac * cp_src[2]) / 255;
+ return col_mix;
}
BLI_INLINE uint mcol_hue(uint col_src, uint col_dst, int fac)
{
- uchar *cp_src, *cp_dst, *cp_mix;
- int mfac;
- uint col_mix = 0;
+ uchar *cp_src, *cp_dst, *cp_mix;
+ int mfac;
+ uint col_mix = 0;
- if (fac == 0) {
- return col_src;
- }
+ if (fac == 0) {
+ return col_src;
+ }
- mfac = 255 - fac;
+ mfac = 255 - fac;
- cp_src = (uchar *)&col_src;
- cp_dst = (uchar *)&col_dst;
- cp_mix = (uchar *)&col_mix;
+ cp_src = (uchar *)&col_src;
+ cp_dst = (uchar *)&col_dst;
+ cp_mix = (uchar *)&col_mix;
- float h1, s1, v1;
- float h2, s2, v2;
- float r, g, b;
- rgb_to_hsv(cp_src[0] / 255.0f, cp_src[1] / 255.0f, cp_src[2] / 255.0f, &h1, &s1, &v1);
- rgb_to_hsv(cp_dst[0] / 255.0f, cp_dst[1] / 255.0f, cp_dst[2] / 255.0f, &h2, &s2, &v2);
+ float h1, s1, v1;
+ float h2, s2, v2;
+ float r, g, b;
+ rgb_to_hsv(cp_src[0] / 255.0f, cp_src[1] / 255.0f, cp_src[2] / 255.0f, &h1, &s1, &v1);
+ rgb_to_hsv(cp_dst[0] / 255.0f, cp_dst[1] / 255.0f, cp_dst[2] / 255.0f, &h2, &s2, &v2);
- h1 = h2;
+ h1 = h2;
- hsv_to_rgb(h1, s1, v1, &r, &g, &b);
+ hsv_to_rgb(h1, s1, v1, &r, &g, &b);
- cp_mix[0] = ((int)(r * 255.0f) * fac + mfac * cp_src[0]) / 255;
- cp_mix[1] = ((int)(g * 255.0f) * fac + mfac * cp_src[1]) / 255;
- cp_mix[2] = ((int)(b * 255.0f) * fac + mfac * cp_src[2]) / 255;
- cp_mix[3] = ((int)(cp_dst[3]) * fac + mfac * cp_src[3]) / 255;
- return col_mix;
+ cp_mix[0] = ((int)(r * 255.0f) * fac + mfac * cp_src[0]) / 255;
+ cp_mix[1] = ((int)(g * 255.0f) * fac + mfac * cp_src[1]) / 255;
+ cp_mix[2] = ((int)(b * 255.0f) * fac + mfac * cp_src[2]) / 255;
+ cp_mix[3] = ((int)(cp_dst[3]) * fac + mfac * cp_src[3]) / 255;
+ return col_mix;
}
BLI_INLINE uint mcol_alpha_add(uint col_src, int fac)
{
- uchar *cp_src, *cp_mix;
- int temp;
- uint col_mix = col_src;
+ uchar *cp_src, *cp_mix;
+ int temp;
+ uint col_mix = col_src;
- if (fac == 0) {
- return col_src;
- }
+ if (fac == 0) {
+ return col_src;
+ }
- cp_src = (uchar *)&col_src;
- cp_mix = (uchar *)&col_mix;
+ cp_src = (uchar *)&col_src;
+ cp_mix = (uchar *)&col_mix;
- temp = cp_src[3] + fac;
- cp_mix[3] = (temp > 254) ? 255 : temp;
+ temp = cp_src[3] + fac;
+ cp_mix[3] = (temp > 254) ? 255 : temp;
- return col_mix;
+ return col_mix;
}
BLI_INLINE uint mcol_alpha_sub(uint col_src, int fac)
{
- uchar *cp_src, *cp_mix;
- int temp;
- uint col_mix = col_src;
+ uchar *cp_src, *cp_mix;
+ int temp;
+ uint col_mix = col_src;
- if (fac == 0) {
- return col_src;
- }
+ if (fac == 0) {
+ return col_src;
+ }
- cp_src = (uchar *)&col_src;
- cp_mix = (uchar *)&col_mix;
+ cp_src = (uchar *)&col_src;
+ cp_mix = (uchar *)&col_mix;
- temp = cp_src[3] - fac;
- cp_mix[3] = temp < 0 ? 0 : temp;
+ temp = cp_src[3] - fac;
+ cp_mix[3] = temp < 0 ? 0 : temp;
- return col_mix;
+ return col_mix;
}
/* wpaint has 'ED_wpaint_blend_tool' */
-uint ED_vpaint_blend_tool(
- const int tool, const uint col,
- const uint paintcol, const int alpha_i)
+uint ED_vpaint_blend_tool(const int tool, const uint col, const uint paintcol, const int alpha_i)
{
- switch ((IMB_BlendMode)tool) {
- case IMB_BLEND_MIX: return mcol_blend(col, paintcol, alpha_i);
- case IMB_BLEND_ADD: return mcol_add(col, paintcol, alpha_i);
- case IMB_BLEND_SUB: return mcol_sub(col, paintcol, alpha_i);
- case IMB_BLEND_MUL: return mcol_mul(col, paintcol, alpha_i);
- case IMB_BLEND_LIGHTEN: return mcol_lighten(col, paintcol, alpha_i);
- case IMB_BLEND_DARKEN: return mcol_darken(col, paintcol, alpha_i);
- case IMB_BLEND_COLORDODGE: return mcol_colordodge(col, paintcol, alpha_i);
- case IMB_BLEND_DIFFERENCE: return mcol_difference(col, paintcol, alpha_i);
- case IMB_BLEND_SCREEN: return mcol_screen(col, paintcol, alpha_i);
- case IMB_BLEND_HARDLIGHT: return mcol_hardlight(col, paintcol, alpha_i);
- case IMB_BLEND_OVERLAY: return mcol_overlay(col, paintcol, alpha_i);
- case IMB_BLEND_SOFTLIGHT: return mcol_softlight(col, paintcol, alpha_i);
- case IMB_BLEND_EXCLUSION: return mcol_exclusion(col, paintcol, alpha_i);
- case IMB_BLEND_LUMINOSITY: return mcol_luminosity(col, paintcol, alpha_i);
- case IMB_BLEND_SATURATION: return mcol_saturation(col, paintcol, alpha_i);
- case IMB_BLEND_HUE: return mcol_hue(col, paintcol, alpha_i);
- /* non-color */
- case IMB_BLEND_ERASE_ALPHA: return mcol_alpha_sub(col, alpha_i);
- case IMB_BLEND_ADD_ALPHA: return mcol_alpha_add(col, alpha_i);
- default:
- BLI_assert(0);
- return 0;
- }
+ switch ((IMB_BlendMode)tool) {
+ case IMB_BLEND_MIX:
+ return mcol_blend(col, paintcol, alpha_i);
+ case IMB_BLEND_ADD:
+ return mcol_add(col, paintcol, alpha_i);
+ case IMB_BLEND_SUB:
+ return mcol_sub(col, paintcol, alpha_i);
+ case IMB_BLEND_MUL:
+ return mcol_mul(col, paintcol, alpha_i);
+ case IMB_BLEND_LIGHTEN:
+ return mcol_lighten(col, paintcol, alpha_i);
+ case IMB_BLEND_DARKEN:
+ return mcol_darken(col, paintcol, alpha_i);
+ case IMB_BLEND_COLORDODGE:
+ return mcol_colordodge(col, paintcol, alpha_i);
+ case IMB_BLEND_DIFFERENCE:
+ return mcol_difference(col, paintcol, alpha_i);
+ case IMB_BLEND_SCREEN:
+ return mcol_screen(col, paintcol, alpha_i);
+ case IMB_BLEND_HARDLIGHT:
+ return mcol_hardlight(col, paintcol, alpha_i);
+ case IMB_BLEND_OVERLAY:
+ return mcol_overlay(col, paintcol, alpha_i);
+ case IMB_BLEND_SOFTLIGHT:
+ return mcol_softlight(col, paintcol, alpha_i);
+ case IMB_BLEND_EXCLUSION:
+ return mcol_exclusion(col, paintcol, alpha_i);
+ case IMB_BLEND_LUMINOSITY:
+ return mcol_luminosity(col, paintcol, alpha_i);
+ case IMB_BLEND_SATURATION:
+ return mcol_saturation(col, paintcol, alpha_i);
+ case IMB_BLEND_HUE:
+ return mcol_hue(col, paintcol, alpha_i);
+ /* non-color */
+ case IMB_BLEND_ERASE_ALPHA:
+ return mcol_alpha_sub(col, alpha_i);
+ case IMB_BLEND_ADD_ALPHA:
+ return mcol_alpha_add(col, alpha_i);
+ default:
+ BLI_assert(0);
+ return 0;
+ }
}
/** \} */
diff --git a/source/blender/editors/sculpt_paint/paint_vertex_proj.c b/source/blender/editors/sculpt_paint/paint_vertex_proj.c
index 9246c852b3a..7bca7745ca0 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex_proj.c
+++ b/source/blender/editors/sculpt_paint/paint_vertex_proj.c
@@ -43,195 +43,193 @@
#include "ED_screen.h"
#include "ED_view3d.h"
-#include "paint_intern.h" /* own include */
-
+#include "paint_intern.h" /* own include */
/* Opaque Structs for internal use */
/* stored while painting */
struct VertProjHandle {
- CoNo *vcosnos;
+ CoNo *vcosnos;
- bool use_update;
+ bool use_update;
- /* use for update */
- float *dists_sq;
+ /* use for update */
+ float *dists_sq;
- Object *ob;
- Scene *scene;
+ Object *ob;
+ Scene *scene;
};
/* only for passing to the callbacks */
struct VertProjUpdate {
- struct VertProjHandle *vp_handle;
+ struct VertProjHandle *vp_handle;
- /* runtime */
- ARegion *ar;
- const float *mval_fl;
+ /* runtime */
+ ARegion *ar;
+ const float *mval_fl;
};
-
/* -------------------------------------------------------------------- */
/* Internal Init */
static void vpaint_proj_dm_map_cosnos_init__map_cb(
- void *userData, int index, const float co[3],
- const float no_f[3], const short no_s[3])
+ void *userData, int index, const float co[3], const float no_f[3], const short no_s[3])
{
- struct VertProjHandle *vp_handle = userData;
- CoNo *co_no = &vp_handle->vcosnos[index];
-
- /* check if we've been here before (normal should not be 0) */
- if (!is_zero_v3(co_no->no)) {
- /* remember that multiple dm verts share the same source vert */
- vp_handle->use_update = true;
- return;
- }
-
- copy_v3_v3(co_no->co, co);
- if (no_f) {
- copy_v3_v3(co_no->no, no_f);
- }
- else {
- normal_short_to_float_v3(co_no->no, no_s);
- }
+ struct VertProjHandle *vp_handle = userData;
+ CoNo *co_no = &vp_handle->vcosnos[index];
+
+ /* check if we've been here before (normal should not be 0) */
+ if (!is_zero_v3(co_no->no)) {
+ /* remember that multiple dm verts share the same source vert */
+ vp_handle->use_update = true;
+ return;
+ }
+
+ copy_v3_v3(co_no->co, co);
+ if (no_f) {
+ copy_v3_v3(co_no->no, no_f);
+ }
+ else {
+ normal_short_to_float_v3(co_no->no, no_s);
+ }
}
-static void vpaint_proj_dm_map_cosnos_init(
- struct Depsgraph *depsgraph, Scene *UNUSED(scene), Object *ob,
- struct VertProjHandle *vp_handle)
+static void vpaint_proj_dm_map_cosnos_init(struct Depsgraph *depsgraph,
+ Scene *UNUSED(scene),
+ Object *ob,
+ struct VertProjHandle *vp_handle)
{
- Scene *scene_eval = DEG_get_evaluated_scene(depsgraph);
- Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
- Mesh *me = ob->data;
+ Scene *scene_eval = DEG_get_evaluated_scene(depsgraph);
+ Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
+ Mesh *me = ob->data;
- CustomData_MeshMasks cddata_masks = CD_MASK_BAREMESH_ORIGINDEX;
- Mesh *me_eval = mesh_get_eval_final(depsgraph, scene_eval, ob_eval, &cddata_masks);
+ CustomData_MeshMasks cddata_masks = CD_MASK_BAREMESH_ORIGINDEX;
+ Mesh *me_eval = mesh_get_eval_final(depsgraph, scene_eval, ob_eval, &cddata_masks);
- memset(vp_handle->vcosnos, 0, sizeof(*vp_handle->vcosnos) * me->totvert);
- BKE_mesh_foreach_mapped_vert(me_eval, vpaint_proj_dm_map_cosnos_init__map_cb, vp_handle, MESH_FOREACH_USE_NORMAL);
+ memset(vp_handle->vcosnos, 0, sizeof(*vp_handle->vcosnos) * me->totvert);
+ BKE_mesh_foreach_mapped_vert(
+ me_eval, vpaint_proj_dm_map_cosnos_init__map_cb, vp_handle, MESH_FOREACH_USE_NORMAL);
}
-
/* -------------------------------------------------------------------- */
/* Internal Update */
/* Same as init but take mouse location into account */
static void vpaint_proj_dm_map_cosnos_update__map_cb(
- void *userData, int index, const float co[3],
- const float no_f[3], const short no_s[3])
+ void *userData, int index, const float co[3], const float no_f[3], const short no_s[3])
{
- struct VertProjUpdate *vp_update = userData;
- struct VertProjHandle *vp_handle = vp_update->vp_handle;
-
- CoNo *co_no = &vp_handle->vcosnos[index];
-
- /* find closest vertex */
- {
- /* first find distance to this vertex */
- float co_ss[2]; /* screenspace */
-
- if (ED_view3d_project_float_object(
- vp_update->ar,
- co, co_ss,
- V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_NEAR) == V3D_PROJ_RET_OK)
- {
- const float dist_sq = len_squared_v2v2(vp_update->mval_fl, co_ss);
- if (dist_sq > vp_handle->dists_sq[index]) {
- /* bail out! */
- return;
- }
-
- vp_handle->dists_sq[index] = dist_sq;
- }
- else if (vp_handle->dists_sq[index] != FLT_MAX) {
- /* already initialized & couldn't project this 'co' */
- return;
- }
- }
- /* continue with regular functionality */
-
- copy_v3_v3(co_no->co, co);
- if (no_f) {
- copy_v3_v3(co_no->no, no_f);
- }
- else {
- normal_short_to_float_v3(co_no->no, no_s);
- }
+ struct VertProjUpdate *vp_update = userData;
+ struct VertProjHandle *vp_handle = vp_update->vp_handle;
+
+ CoNo *co_no = &vp_handle->vcosnos[index];
+
+ /* find closest vertex */
+ {
+ /* first find distance to this vertex */
+ float co_ss[2]; /* screenspace */
+
+ if (ED_view3d_project_float_object(
+ vp_update->ar, co, co_ss, V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_NEAR) ==
+ V3D_PROJ_RET_OK) {
+ const float dist_sq = len_squared_v2v2(vp_update->mval_fl, co_ss);
+ if (dist_sq > vp_handle->dists_sq[index]) {
+ /* bail out! */
+ return;
+ }
+
+ vp_handle->dists_sq[index] = dist_sq;
+ }
+ else if (vp_handle->dists_sq[index] != FLT_MAX) {
+ /* already initialized & couldn't project this 'co' */
+ return;
+ }
+ }
+ /* continue with regular functionality */
+
+ copy_v3_v3(co_no->co, co);
+ if (no_f) {
+ copy_v3_v3(co_no->no, no_f);
+ }
+ else {
+ normal_short_to_float_v3(co_no->no, no_s);
+ }
}
-static void vpaint_proj_dm_map_cosnos_update(
- struct Depsgraph *depsgraph, struct VertProjHandle *vp_handle,
- ARegion *ar, const float mval_fl[2])
+static void vpaint_proj_dm_map_cosnos_update(struct Depsgraph *depsgraph,
+ struct VertProjHandle *vp_handle,
+ ARegion *ar,
+ const float mval_fl[2])
{
- struct VertProjUpdate vp_update = {vp_handle, ar, mval_fl};
+ struct VertProjUpdate vp_update = {vp_handle, ar, mval_fl};
- Object *ob = vp_handle->ob;
- Scene *scene_eval = DEG_get_evaluated_scene(depsgraph);
- Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
- Mesh *me = ob->data;
+ Object *ob = vp_handle->ob;
+ Scene *scene_eval = DEG_get_evaluated_scene(depsgraph);
+ Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
+ Mesh *me = ob->data;
- CustomData_MeshMasks cddata_masks = CD_MASK_BAREMESH_ORIGINDEX;
- Mesh *me_eval = mesh_get_eval_final(depsgraph, scene_eval, ob_eval, &cddata_masks);
+ CustomData_MeshMasks cddata_masks = CD_MASK_BAREMESH_ORIGINDEX;
+ Mesh *me_eval = mesh_get_eval_final(depsgraph, scene_eval, ob_eval, &cddata_masks);
- /* quick sanity check - we shouldn't have to run this if there are no modifiers */
- BLI_assert(BLI_listbase_is_empty(&ob->modifiers) == false);
+ /* quick sanity check - we shouldn't have to run this if there are no modifiers */
+ BLI_assert(BLI_listbase_is_empty(&ob->modifiers) == false);
- copy_vn_fl(vp_handle->dists_sq, me->totvert, FLT_MAX);
- BKE_mesh_foreach_mapped_vert(me_eval, vpaint_proj_dm_map_cosnos_update__map_cb, &vp_update, MESH_FOREACH_USE_NORMAL);
+ copy_vn_fl(vp_handle->dists_sq, me->totvert, FLT_MAX);
+ BKE_mesh_foreach_mapped_vert(
+ me_eval, vpaint_proj_dm_map_cosnos_update__map_cb, &vp_update, MESH_FOREACH_USE_NORMAL);
}
-
/* -------------------------------------------------------------------- */
/* Public Functions */
-struct VertProjHandle *ED_vpaint_proj_handle_create(
- struct Depsgraph *depsgraph, Scene *scene, Object *ob,
- CoNo **r_vcosnos)
+struct VertProjHandle *ED_vpaint_proj_handle_create(struct Depsgraph *depsgraph,
+ Scene *scene,
+ Object *ob,
+ CoNo **r_vcosnos)
{
- struct VertProjHandle *vp_handle = MEM_mallocN(sizeof(struct VertProjHandle), __func__);
- Mesh *me = ob->data;
+ struct VertProjHandle *vp_handle = MEM_mallocN(sizeof(struct VertProjHandle), __func__);
+ Mesh *me = ob->data;
- /* setup the handle */
- vp_handle->vcosnos = MEM_mallocN(sizeof(CoNo) * me->totvert, "vertexcosnos map");
- vp_handle->use_update = false;
+ /* setup the handle */
+ vp_handle->vcosnos = MEM_mallocN(sizeof(CoNo) * me->totvert, "vertexcosnos map");
+ vp_handle->use_update = false;
- /* sets 'use_update' if needed */
- vpaint_proj_dm_map_cosnos_init(depsgraph, scene, ob, vp_handle);
+ /* sets 'use_update' if needed */
+ vpaint_proj_dm_map_cosnos_init(depsgraph, scene, ob, vp_handle);
- if (vp_handle->use_update) {
- vp_handle->dists_sq = MEM_mallocN(sizeof(float) * me->totvert, __func__);
+ if (vp_handle->use_update) {
+ vp_handle->dists_sq = MEM_mallocN(sizeof(float) * me->totvert, __func__);
- vp_handle->ob = ob;
- vp_handle->scene = scene;
- }
- else {
- vp_handle->dists_sq = NULL;
+ vp_handle->ob = ob;
+ vp_handle->scene = scene;
+ }
+ else {
+ vp_handle->dists_sq = NULL;
- vp_handle->ob = NULL;
- vp_handle->scene = NULL;
- }
+ vp_handle->ob = NULL;
+ vp_handle->scene = NULL;
+ }
- *r_vcosnos = vp_handle->vcosnos;
- return vp_handle;
+ *r_vcosnos = vp_handle->vcosnos;
+ return vp_handle;
}
-void ED_vpaint_proj_handle_update(
- struct Depsgraph *depsgraph, struct VertProjHandle *vp_handle,
- ARegion *ar, const float mval_fl[2])
+void ED_vpaint_proj_handle_update(struct Depsgraph *depsgraph,
+ struct VertProjHandle *vp_handle,
+ ARegion *ar,
+ const float mval_fl[2])
{
- if (vp_handle->use_update) {
- vpaint_proj_dm_map_cosnos_update(depsgraph, vp_handle, ar, mval_fl);
- }
+ if (vp_handle->use_update) {
+ vpaint_proj_dm_map_cosnos_update(depsgraph, vp_handle, ar, mval_fl);
+ }
}
-void ED_vpaint_proj_handle_free(struct VertProjHandle *vp_handle)
+void ED_vpaint_proj_handle_free(struct VertProjHandle *vp_handle)
{
- if (vp_handle->use_update) {
- MEM_freeN(vp_handle->dists_sq);
- }
+ if (vp_handle->use_update) {
+ MEM_freeN(vp_handle->dists_sq);
+ }
- MEM_freeN(vp_handle->vcosnos);
- MEM_freeN(vp_handle);
+ MEM_freeN(vp_handle->vcosnos);
+ MEM_freeN(vp_handle);
}
diff --git a/source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c b/source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c
index cd366ecff3b..29d150c44fe 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c
+++ b/source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c
@@ -63,7 +63,7 @@
#include "ED_screen.h"
#include "ED_view3d.h"
-#include "paint_intern.h" /* own include */
+#include "paint_intern.h" /* own include */
/* -------------------------------------------------------------------- */
/** \name Store Previous Weights
@@ -72,37 +72,36 @@
* \{ */
struct WPaintPrev {
- /* previous vertex weights */
- struct MDeformVert *wpaint_prev;
- /* allocation size of prev buffers */
- int tot;
+ /* previous vertex weights */
+ struct MDeformVert *wpaint_prev;
+ /* allocation size of prev buffers */
+ int tot;
};
-
static void wpaint_prev_init(struct WPaintPrev *wpp)
{
- wpp->wpaint_prev = NULL;
- wpp->tot = 0;
+ wpp->wpaint_prev = NULL;
+ wpp->tot = 0;
}
static void wpaint_prev_create(struct WPaintPrev *wpp, MDeformVert *dverts, int dcount)
{
- wpaint_prev_init(wpp);
+ wpaint_prev_init(wpp);
- if (dverts && dcount) {
- wpp->wpaint_prev = MEM_mallocN(sizeof(MDeformVert) * dcount, "wpaint prev");
- wpp->tot = dcount;
- BKE_defvert_array_copy(wpp->wpaint_prev, dverts, dcount);
- }
+ if (dverts && dcount) {
+ wpp->wpaint_prev = MEM_mallocN(sizeof(MDeformVert) * dcount, "wpaint prev");
+ wpp->tot = dcount;
+ BKE_defvert_array_copy(wpp->wpaint_prev, dverts, dcount);
+ }
}
static void wpaint_prev_destroy(struct WPaintPrev *wpp)
{
- if (wpp->wpaint_prev) {
- BKE_defvert_array_free(wpp->wpaint_prev, wpp->tot);
- }
- wpp->wpaint_prev = NULL;
- wpp->tot = 0;
+ if (wpp->wpaint_prev) {
+ BKE_defvert_array_free(wpp->wpaint_prev, wpp->tot);
+ }
+ wpp->wpaint_prev = NULL;
+ wpp->tot = 0;
}
/** \} */
@@ -113,53 +112,59 @@ static void wpaint_prev_destroy(struct WPaintPrev *wpp)
static bool weight_from_bones_poll(bContext *C)
{
- Object *ob = CTX_data_active_object(C);
+ Object *ob = CTX_data_active_object(C);
- return (ob && (ob->mode & OB_MODE_WEIGHT_PAINT) && modifiers_isDeformedByArmature(ob));
+ return (ob && (ob->mode & OB_MODE_WEIGHT_PAINT) && modifiers_isDeformedByArmature(ob));
}
static int weight_from_bones_exec(bContext *C, wmOperator *op)
{
- Depsgraph *depsgraph = CTX_data_depsgraph(C);
- Scene *scene = CTX_data_scene(C);
- Object *ob = CTX_data_active_object(C);
- Object *armob = modifiers_isDeformedByArmature(ob);
- Mesh *me = ob->data;
- int type = RNA_enum_get(op->ptr, "type");
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ Scene *scene = CTX_data_scene(C);
+ Object *ob = CTX_data_active_object(C);
+ Object *armob = modifiers_isDeformedByArmature(ob);
+ Mesh *me = ob->data;
+ int type = RNA_enum_get(op->ptr, "type");
- ED_object_vgroup_calc_from_armature(op->reports, depsgraph, scene, ob, armob, type, (me->editflag & ME_EDIT_MIRROR_X));
+ ED_object_vgroup_calc_from_armature(
+ op->reports, depsgraph, scene, ob, armob, type, (me->editflag & ME_EDIT_MIRROR_X));
- DEG_id_tag_update(&me->id, 0);
- WM_event_add_notifier(C, NC_GEOM | ND_DATA, me);
+ DEG_id_tag_update(&me->id, 0);
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, me);
- return OPERATOR_FINISHED;
+ return OPERATOR_FINISHED;
}
void PAINT_OT_weight_from_bones(wmOperatorType *ot)
{
- static const EnumPropertyItem type_items[] = {
- {ARM_GROUPS_AUTO, "AUTOMATIC", 0, "Automatic", "Automatic weights from bones"},
- {ARM_GROUPS_ENVELOPE, "ENVELOPES", 0, "From Envelopes", "Weights from envelopes with user defined radius"},
- {0, NULL, 0, NULL, NULL},
- };
-
- /* identifiers */
- ot->name = "Weight from Bones";
- ot->idname = "PAINT_OT_weight_from_bones";
- ot->description = (
- "Set the weights of the groups matching the attached armature's selected bones, "
- "using the distance between the vertices and the bones");
-
- /* api callbacks */
- ot->exec = weight_from_bones_exec;
- ot->invoke = WM_menu_invoke;
- ot->poll = weight_from_bones_poll;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* properties */
- ot->prop = RNA_def_enum(ot->srna, "type", type_items, 0, "Type", "Method to use for assigning weights");
+ static const EnumPropertyItem type_items[] = {
+ {ARM_GROUPS_AUTO, "AUTOMATIC", 0, "Automatic", "Automatic weights from bones"},
+ {ARM_GROUPS_ENVELOPE,
+ "ENVELOPES",
+ 0,
+ "From Envelopes",
+ "Weights from envelopes with user defined radius"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ /* identifiers */
+ ot->name = "Weight from Bones";
+ ot->idname = "PAINT_OT_weight_from_bones";
+ ot->description =
+ ("Set the weights of the groups matching the attached armature's selected bones, "
+ "using the distance between the vertices and the bones");
+
+ /* api callbacks */
+ ot->exec = weight_from_bones_exec;
+ ot->invoke = WM_menu_invoke;
+ ot->poll = weight_from_bones_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ ot->prop = RNA_def_enum(
+ ot->srna, "type", type_items, 0, "Type", "Method to use for assigning weights");
}
/** \} */
@@ -172,95 +177,103 @@ void PAINT_OT_weight_from_bones(wmOperatorType *ot)
/* note: we cant sample frontbuf, weight colors are interpolated too unpredictable */
static int weight_sample_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
- ViewContext vc;
- Mesh *me;
- bool changed = false;
-
- ED_view3d_viewcontext_init(C, &vc);
- me = BKE_mesh_from_object(vc.obact);
-
- if (me && me->dvert && vc.v3d && vc.rv3d && (vc.obact->actdef != 0)) {
- const bool use_vert_sel = (me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0;
- int v_idx_best = -1;
- uint index;
-
- view3d_operator_needs_opengl(C);
- ED_view3d_init_mats_rv3d(vc.obact, vc.rv3d);
-
- if (use_vert_sel) {
- if (ED_mesh_pick_vert(C, vc.obact, event->mval, ED_MESH_PICK_DEFAULT_VERT_DIST, true, &index)) {
- v_idx_best = index;
- }
- }
- else {
- if (ED_mesh_pick_face_vert(C, vc.obact, event->mval, ED_MESH_PICK_DEFAULT_FACE_DIST, &index)) {
- v_idx_best = index;
- }
- else if (ED_mesh_pick_face(C, vc.obact, event->mval, ED_MESH_PICK_DEFAULT_FACE_DIST, &index)) {
- /* this relies on knowning the internal worksings of ED_mesh_pick_face_vert() */
- BKE_report(op->reports, RPT_WARNING, "The modifier used does not support deformed locations");
- }
- }
-
- if (v_idx_best != -1) { /* should always be valid */
- ToolSettings *ts = vc.scene->toolsettings;
- Brush *brush = BKE_paint_brush(&ts->wpaint->paint);
- const int vgroup_active = vc.obact->actdef - 1;
- float vgroup_weight = defvert_find_weight(&me->dvert[v_idx_best], vgroup_active);
-
- /* use combined weight in multipaint mode,
- * since that's what is displayed to the user in the colors */
- if (ts->multipaint) {
- int defbase_tot_sel;
- const int defbase_tot = BLI_listbase_count(&vc.obact->defbase);
- bool *defbase_sel = BKE_object_defgroup_selected_get(vc.obact, defbase_tot, &defbase_tot_sel);
-
- if (defbase_tot_sel > 1) {
- if (me->editflag & ME_EDIT_MIRROR_X) {
- BKE_object_defgroup_mirror_selection(
- vc.obact, defbase_tot, defbase_sel, defbase_sel, &defbase_tot_sel);
- }
-
- vgroup_weight = BKE_defvert_multipaint_collective_weight(
- &me->dvert[v_idx_best], defbase_tot, defbase_sel, defbase_tot_sel, ts->auto_normalize);
-
- /* If auto-normalize is enabled, but weights are not normalized,
- * the value can exceed 1. */
- CLAMP(vgroup_weight, 0.0f, 1.0f);
- }
-
- MEM_freeN(defbase_sel);
- }
-
- BKE_brush_weight_set(vc.scene, brush, vgroup_weight);
- changed = true;
- }
- }
-
- if (changed) {
- /* not really correct since the brush didn't change, but redraws the toolbar */
- WM_main_add_notifier(NC_BRUSH | NA_EDITED, NULL); /* ts->wpaint->paint.brush */
-
- return OPERATOR_FINISHED;
- }
- else {
- return OPERATOR_CANCELLED;
- }
+ ViewContext vc;
+ Mesh *me;
+ bool changed = false;
+
+ ED_view3d_viewcontext_init(C, &vc);
+ me = BKE_mesh_from_object(vc.obact);
+
+ if (me && me->dvert && vc.v3d && vc.rv3d && (vc.obact->actdef != 0)) {
+ const bool use_vert_sel = (me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0;
+ int v_idx_best = -1;
+ uint index;
+
+ view3d_operator_needs_opengl(C);
+ ED_view3d_init_mats_rv3d(vc.obact, vc.rv3d);
+
+ if (use_vert_sel) {
+ if (ED_mesh_pick_vert(
+ C, vc.obact, event->mval, ED_MESH_PICK_DEFAULT_VERT_DIST, true, &index)) {
+ v_idx_best = index;
+ }
+ }
+ else {
+ if (ED_mesh_pick_face_vert(
+ C, vc.obact, event->mval, ED_MESH_PICK_DEFAULT_FACE_DIST, &index)) {
+ v_idx_best = index;
+ }
+ else if (ED_mesh_pick_face(
+ C, vc.obact, event->mval, ED_MESH_PICK_DEFAULT_FACE_DIST, &index)) {
+ /* this relies on knowning the internal worksings of ED_mesh_pick_face_vert() */
+ BKE_report(
+ op->reports, RPT_WARNING, "The modifier used does not support deformed locations");
+ }
+ }
+
+ if (v_idx_best != -1) { /* should always be valid */
+ ToolSettings *ts = vc.scene->toolsettings;
+ Brush *brush = BKE_paint_brush(&ts->wpaint->paint);
+ const int vgroup_active = vc.obact->actdef - 1;
+ float vgroup_weight = defvert_find_weight(&me->dvert[v_idx_best], vgroup_active);
+
+ /* use combined weight in multipaint mode,
+ * since that's what is displayed to the user in the colors */
+ if (ts->multipaint) {
+ int defbase_tot_sel;
+ const int defbase_tot = BLI_listbase_count(&vc.obact->defbase);
+ bool *defbase_sel = BKE_object_defgroup_selected_get(
+ vc.obact, defbase_tot, &defbase_tot_sel);
+
+ if (defbase_tot_sel > 1) {
+ if (me->editflag & ME_EDIT_MIRROR_X) {
+ BKE_object_defgroup_mirror_selection(
+ vc.obact, defbase_tot, defbase_sel, defbase_sel, &defbase_tot_sel);
+ }
+
+ vgroup_weight = BKE_defvert_multipaint_collective_weight(&me->dvert[v_idx_best],
+ defbase_tot,
+ defbase_sel,
+ defbase_tot_sel,
+ ts->auto_normalize);
+
+ /* If auto-normalize is enabled, but weights are not normalized,
+ * the value can exceed 1. */
+ CLAMP(vgroup_weight, 0.0f, 1.0f);
+ }
+
+ MEM_freeN(defbase_sel);
+ }
+
+ BKE_brush_weight_set(vc.scene, brush, vgroup_weight);
+ changed = true;
+ }
+ }
+
+ if (changed) {
+ /* not really correct since the brush didn't change, but redraws the toolbar */
+ WM_main_add_notifier(NC_BRUSH | NA_EDITED, NULL); /* ts->wpaint->paint.brush */
+
+ return OPERATOR_FINISHED;
+ }
+ else {
+ return OPERATOR_CANCELLED;
+ }
}
void PAINT_OT_weight_sample(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Weight Paint Sample Weight";
- ot->idname = "PAINT_OT_weight_sample";
- ot->description = "Use the mouse to sample a weight in the 3D view";
+ /* identifiers */
+ ot->name = "Weight Paint Sample Weight";
+ ot->idname = "PAINT_OT_weight_sample";
+ ot->description = "Use the mouse to sample a weight in the 3D view";
- /* api callbacks */
- ot->invoke = weight_sample_invoke;
- ot->poll = weight_paint_mode_poll;
+ /* api callbacks */
+ ot->invoke = weight_sample_invoke;
+ ot->poll = weight_paint_mode_poll;
- /* flags */
- ot->flag = OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_UNDO;
}
/** \} */
@@ -270,132 +283,137 @@ void PAINT_OT_weight_sample(wmOperatorType *ot)
* \{ */
/* samples cursor location, and gives menu with vertex groups to activate */
-static bool weight_paint_sample_enum_itemf__helper(const MDeformVert *dvert, const int defbase_tot, int *groups)
+static bool weight_paint_sample_enum_itemf__helper(const MDeformVert *dvert,
+ const int defbase_tot,
+ int *groups)
{
- /* this func fills in used vgroup's */
- bool found = false;
- int i = dvert->totweight;
- MDeformWeight *dw;
- for (dw = dvert->dw; i > 0; dw++, i--) {
- if (dw->def_nr < defbase_tot) {
- groups[dw->def_nr] = true;
- found = true;
- }
- }
- return found;
+ /* this func fills in used vgroup's */
+ bool found = false;
+ int i = dvert->totweight;
+ MDeformWeight *dw;
+ for (dw = dvert->dw; i > 0; dw++, i--) {
+ if (dw->def_nr < defbase_tot) {
+ groups[dw->def_nr] = true;
+ found = true;
+ }
+ }
+ return found;
}
-static const EnumPropertyItem *weight_paint_sample_enum_itemf(
- bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free)
+static const EnumPropertyItem *weight_paint_sample_enum_itemf(bContext *C,
+ PointerRNA *UNUSED(ptr),
+ PropertyRNA *UNUSED(prop),
+ bool *r_free)
{
- if (C) {
- wmWindow *win = CTX_wm_window(C);
- if (win && win->eventstate) {
- ViewContext vc;
- Mesh *me;
-
- ED_view3d_viewcontext_init(C, &vc);
- me = BKE_mesh_from_object(vc.obact);
-
- if (me && me->dvert && vc.v3d && vc.rv3d && vc.obact->defbase.first) {
- const int defbase_tot = BLI_listbase_count(&vc.obact->defbase);
- const bool use_vert_sel = (me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0;
- int *groups = MEM_callocN(defbase_tot * sizeof(int), "groups");
- bool found = false;
- uint index;
-
- const int mval[2] = {
- win->eventstate->x - vc.ar->winrct.xmin,
- win->eventstate->y - vc.ar->winrct.ymin,
- };
-
- view3d_operator_needs_opengl(C);
- ED_view3d_init_mats_rv3d(vc.obact, vc.rv3d);
-
- if (use_vert_sel) {
- if (ED_mesh_pick_vert(C, vc.obact, mval, ED_MESH_PICK_DEFAULT_VERT_DIST, true, &index)) {
- MDeformVert *dvert = &me->dvert[index];
- found |= weight_paint_sample_enum_itemf__helper(dvert, defbase_tot, groups);
- }
- }
- else {
- if (ED_mesh_pick_face(C, vc.obact, mval, ED_MESH_PICK_DEFAULT_FACE_DIST, &index)) {
- const MPoly *mp = &me->mpoly[index];
- uint fidx = mp->totloop - 1;
-
- do {
- MDeformVert *dvert = &me->dvert[me->mloop[mp->loopstart + fidx].v];
- found |= weight_paint_sample_enum_itemf__helper(dvert, defbase_tot, groups);
- } while (fidx--);
- }
- }
-
- if (found == false) {
- MEM_freeN(groups);
- }
- else {
- EnumPropertyItem *item = NULL, item_tmp = {0};
- int totitem = 0;
- int i = 0;
- bDeformGroup *dg;
- for (dg = vc.obact->defbase.first; dg && i < defbase_tot; i++, dg = dg->next) {
- if (groups[i]) {
- item_tmp.identifier = item_tmp.name = dg->name;
- item_tmp.value = i;
- RNA_enum_item_add(&item, &totitem, &item_tmp);
- }
- }
-
- RNA_enum_item_end(&item, &totitem);
- *r_free = true;
-
- MEM_freeN(groups);
- return item;
- }
- }
- }
- }
-
- return DummyRNA_NULL_items;
+ if (C) {
+ wmWindow *win = CTX_wm_window(C);
+ if (win && win->eventstate) {
+ ViewContext vc;
+ Mesh *me;
+
+ ED_view3d_viewcontext_init(C, &vc);
+ me = BKE_mesh_from_object(vc.obact);
+
+ if (me && me->dvert && vc.v3d && vc.rv3d && vc.obact->defbase.first) {
+ const int defbase_tot = BLI_listbase_count(&vc.obact->defbase);
+ const bool use_vert_sel = (me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0;
+ int *groups = MEM_callocN(defbase_tot * sizeof(int), "groups");
+ bool found = false;
+ uint index;
+
+ const int mval[2] = {
+ win->eventstate->x - vc.ar->winrct.xmin,
+ win->eventstate->y - vc.ar->winrct.ymin,
+ };
+
+ view3d_operator_needs_opengl(C);
+ ED_view3d_init_mats_rv3d(vc.obact, vc.rv3d);
+
+ if (use_vert_sel) {
+ if (ED_mesh_pick_vert(C, vc.obact, mval, ED_MESH_PICK_DEFAULT_VERT_DIST, true, &index)) {
+ MDeformVert *dvert = &me->dvert[index];
+ found |= weight_paint_sample_enum_itemf__helper(dvert, defbase_tot, groups);
+ }
+ }
+ else {
+ if (ED_mesh_pick_face(C, vc.obact, mval, ED_MESH_PICK_DEFAULT_FACE_DIST, &index)) {
+ const MPoly *mp = &me->mpoly[index];
+ uint fidx = mp->totloop - 1;
+
+ do {
+ MDeformVert *dvert = &me->dvert[me->mloop[mp->loopstart + fidx].v];
+ found |= weight_paint_sample_enum_itemf__helper(dvert, defbase_tot, groups);
+ } while (fidx--);
+ }
+ }
+
+ if (found == false) {
+ MEM_freeN(groups);
+ }
+ else {
+ EnumPropertyItem *item = NULL, item_tmp = {0};
+ int totitem = 0;
+ int i = 0;
+ bDeformGroup *dg;
+ for (dg = vc.obact->defbase.first; dg && i < defbase_tot; i++, dg = dg->next) {
+ if (groups[i]) {
+ item_tmp.identifier = item_tmp.name = dg->name;
+ item_tmp.value = i;
+ RNA_enum_item_add(&item, &totitem, &item_tmp);
+ }
+ }
+
+ RNA_enum_item_end(&item, &totitem);
+ *r_free = true;
+
+ MEM_freeN(groups);
+ return item;
+ }
+ }
+ }
+ }
+
+ return DummyRNA_NULL_items;
}
static int weight_sample_group_exec(bContext *C, wmOperator *op)
{
- int type = RNA_enum_get(op->ptr, "group");
- ViewContext vc;
- ED_view3d_viewcontext_init(C, &vc);
+ int type = RNA_enum_get(op->ptr, "group");
+ ViewContext vc;
+ ED_view3d_viewcontext_init(C, &vc);
- BLI_assert(type + 1 >= 0);
- vc.obact->actdef = type + 1;
+ BLI_assert(type + 1 >= 0);
+ vc.obact->actdef = type + 1;
- DEG_id_tag_update(&vc.obact->id, ID_RECALC_GEOMETRY);
- WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, vc.obact);
- return OPERATOR_FINISHED;
+ DEG_id_tag_update(&vc.obact->id, ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, vc.obact);
+ return OPERATOR_FINISHED;
}
/* TODO, we could make this a menu into OBJECT_OT_vertex_group_set_active
* rather than its own operator */
void PAINT_OT_weight_sample_group(wmOperatorType *ot)
{
- PropertyRNA *prop = NULL;
-
- /* identifiers */
- ot->name = "Weight Paint Sample Group";
- ot->idname = "PAINT_OT_weight_sample_group";
- ot->description = "Select one of the vertex groups available under current mouse position";
-
- /* api callbacks */
- ot->exec = weight_sample_group_exec;
- ot->invoke = WM_menu_invoke;
- ot->poll = weight_paint_mode_poll;
-
- /* flags */
- ot->flag = OPTYPE_UNDO;
-
- /* keyingset to use (dynamic enum) */
- prop = RNA_def_enum(ot->srna, "group", DummyRNA_DEFAULT_items, 0, "Keying Set", "The Keying Set to use");
- RNA_def_enum_funcs(prop, weight_paint_sample_enum_itemf);
- RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE);
- ot->prop = prop;
+ PropertyRNA *prop = NULL;
+
+ /* identifiers */
+ ot->name = "Weight Paint Sample Group";
+ ot->idname = "PAINT_OT_weight_sample_group";
+ ot->description = "Select one of the vertex groups available under current mouse position";
+
+ /* api callbacks */
+ ot->exec = weight_sample_group_exec;
+ ot->invoke = WM_menu_invoke;
+ ot->poll = weight_paint_mode_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_UNDO;
+
+ /* keyingset to use (dynamic enum) */
+ prop = RNA_def_enum(
+ ot->srna, "group", DummyRNA_DEFAULT_items, 0, "Keying Set", "The Keying Set to use");
+ RNA_def_enum_funcs(prop, weight_paint_sample_enum_itemf);
+ RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE);
+ ot->prop = prop;
}
/** \} */
@@ -407,123 +425,122 @@ void PAINT_OT_weight_sample_group(wmOperatorType *ot)
/* fills in the selected faces with the current weight and vertex group */
static bool weight_paint_set(Object *ob, float paintweight)
{
- Mesh *me = ob->data;
- const MPoly *mp;
- MDeformWeight *dw, *dw_prev;
- int vgroup_active, vgroup_mirror = -1;
- uint index;
- const bool topology = (me->editflag & ME_EDIT_MIRROR_TOPO) != 0;
-
- /* mutually exclusive, could be made into a */
- const short paint_selmode = ME_EDIT_PAINT_SEL_MODE(me);
-
- if (me->totpoly == 0 || me->dvert == NULL || !me->mpoly) {
- return false;
- }
-
- vgroup_active = ob->actdef - 1;
-
- /* if mirror painting, find the other group */
- if (me->editflag & ME_EDIT_MIRROR_X) {
- vgroup_mirror = ED_wpaint_mirror_vgroup_ensure(ob, vgroup_active);
- }
-
- struct WPaintPrev wpp;
- wpaint_prev_create(&wpp, me->dvert, me->totvert);
-
- for (index = 0, mp = me->mpoly; index < me->totpoly; index++, mp++) {
- uint fidx = mp->totloop - 1;
-
- if ((paint_selmode == SCE_SELECT_FACE) && !(mp->flag & ME_FACE_SEL)) {
- continue;
- }
-
- do {
- uint vidx = me->mloop[mp->loopstart + fidx].v;
-
- if (!me->dvert[vidx].flag) {
- if ((paint_selmode == SCE_SELECT_VERTEX) && !(me->mvert[vidx].flag & SELECT)) {
- continue;
- }
-
- dw = defvert_verify_index(&me->dvert[vidx], vgroup_active);
- if (dw) {
- dw_prev = defvert_verify_index(wpp.wpaint_prev + vidx, vgroup_active);
- dw_prev->weight = dw->weight; /* set the undo weight */
- dw->weight = paintweight;
-
- if (me->editflag & ME_EDIT_MIRROR_X) { /* x mirror painting */
- int j = mesh_get_x_mirror_vert(ob, NULL, vidx, topology);
- if (j >= 0) {
- /* copy, not paint again */
- if (vgroup_mirror != -1) {
- dw = defvert_verify_index(me->dvert + j, vgroup_mirror);
- dw_prev = defvert_verify_index(wpp.wpaint_prev + j, vgroup_mirror);
- }
- else {
- dw = defvert_verify_index(me->dvert + j, vgroup_active);
- dw_prev = defvert_verify_index(wpp.wpaint_prev + j, vgroup_active);
- }
- dw_prev->weight = dw->weight; /* set the undo weight */
- dw->weight = paintweight;
- }
- }
- }
- me->dvert[vidx].flag = 1;
- }
-
- } while (fidx--);
- }
-
- {
- MDeformVert *dv = me->dvert;
- for (index = me->totvert; index != 0; index--, dv++) {
- dv->flag = 0;
- }
- }
-
- wpaint_prev_destroy(&wpp);
-
- DEG_id_tag_update(&me->id, 0);
-
- return true;
+ Mesh *me = ob->data;
+ const MPoly *mp;
+ MDeformWeight *dw, *dw_prev;
+ int vgroup_active, vgroup_mirror = -1;
+ uint index;
+ const bool topology = (me->editflag & ME_EDIT_MIRROR_TOPO) != 0;
+
+ /* mutually exclusive, could be made into a */
+ const short paint_selmode = ME_EDIT_PAINT_SEL_MODE(me);
+
+ if (me->totpoly == 0 || me->dvert == NULL || !me->mpoly) {
+ return false;
+ }
+
+ vgroup_active = ob->actdef - 1;
+
+ /* if mirror painting, find the other group */
+ if (me->editflag & ME_EDIT_MIRROR_X) {
+ vgroup_mirror = ED_wpaint_mirror_vgroup_ensure(ob, vgroup_active);
+ }
+
+ struct WPaintPrev wpp;
+ wpaint_prev_create(&wpp, me->dvert, me->totvert);
+
+ for (index = 0, mp = me->mpoly; index < me->totpoly; index++, mp++) {
+ uint fidx = mp->totloop - 1;
+
+ if ((paint_selmode == SCE_SELECT_FACE) && !(mp->flag & ME_FACE_SEL)) {
+ continue;
+ }
+
+ do {
+ uint vidx = me->mloop[mp->loopstart + fidx].v;
+
+ if (!me->dvert[vidx].flag) {
+ if ((paint_selmode == SCE_SELECT_VERTEX) && !(me->mvert[vidx].flag & SELECT)) {
+ continue;
+ }
+
+ dw = defvert_verify_index(&me->dvert[vidx], vgroup_active);
+ if (dw) {
+ dw_prev = defvert_verify_index(wpp.wpaint_prev + vidx, vgroup_active);
+ dw_prev->weight = dw->weight; /* set the undo weight */
+ dw->weight = paintweight;
+
+ if (me->editflag & ME_EDIT_MIRROR_X) { /* x mirror painting */
+ int j = mesh_get_x_mirror_vert(ob, NULL, vidx, topology);
+ if (j >= 0) {
+ /* copy, not paint again */
+ if (vgroup_mirror != -1) {
+ dw = defvert_verify_index(me->dvert + j, vgroup_mirror);
+ dw_prev = defvert_verify_index(wpp.wpaint_prev + j, vgroup_mirror);
+ }
+ else {
+ dw = defvert_verify_index(me->dvert + j, vgroup_active);
+ dw_prev = defvert_verify_index(wpp.wpaint_prev + j, vgroup_active);
+ }
+ dw_prev->weight = dw->weight; /* set the undo weight */
+ dw->weight = paintweight;
+ }
+ }
+ }
+ me->dvert[vidx].flag = 1;
+ }
+
+ } while (fidx--);
+ }
+
+ {
+ MDeformVert *dv = me->dvert;
+ for (index = me->totvert; index != 0; index--, dv++) {
+ dv->flag = 0;
+ }
+ }
+
+ wpaint_prev_destroy(&wpp);
+
+ DEG_id_tag_update(&me->id, 0);
+
+ return true;
}
-
static int weight_paint_set_exec(bContext *C, wmOperator *op)
{
- struct Scene *scene = CTX_data_scene(C);
- Object *obact = CTX_data_active_object(C);
- ToolSettings *ts = CTX_data_tool_settings(C);
- Brush *brush = BKE_paint_brush(&ts->wpaint->paint);
- float vgroup_weight = BKE_brush_weight_get(scene, brush);
-
- if (ED_wpaint_ensure_data(C, op->reports, WPAINT_ENSURE_MIRROR, NULL) == false) {
- return OPERATOR_CANCELLED;
- }
-
- if (weight_paint_set(obact, vgroup_weight)) {
- ED_region_tag_redraw(CTX_wm_region(C)); /* XXX - should redraw all 3D views */
- return OPERATOR_FINISHED;
- }
- else {
- return OPERATOR_CANCELLED;
- }
+ struct Scene *scene = CTX_data_scene(C);
+ Object *obact = CTX_data_active_object(C);
+ ToolSettings *ts = CTX_data_tool_settings(C);
+ Brush *brush = BKE_paint_brush(&ts->wpaint->paint);
+ float vgroup_weight = BKE_brush_weight_get(scene, brush);
+
+ if (ED_wpaint_ensure_data(C, op->reports, WPAINT_ENSURE_MIRROR, NULL) == false) {
+ return OPERATOR_CANCELLED;
+ }
+
+ if (weight_paint_set(obact, vgroup_weight)) {
+ ED_region_tag_redraw(CTX_wm_region(C)); /* XXX - should redraw all 3D views */
+ return OPERATOR_FINISHED;
+ }
+ else {
+ return OPERATOR_CANCELLED;
+ }
}
void PAINT_OT_weight_set(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Set Weight";
- ot->idname = "PAINT_OT_weight_set";
- ot->description = "Fill the active vertex group with the current paint weight";
+ /* identifiers */
+ ot->name = "Set Weight";
+ ot->idname = "PAINT_OT_weight_set";
+ ot->description = "Fill the active vertex group with the current paint weight";
- /* api callbacks */
- ot->exec = weight_paint_set_exec;
- ot->poll = mask_paint_poll;
+ /* api callbacks */
+ ot->exec = weight_paint_set_exec;
+ ot->poll = mask_paint_poll;
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
/** \} */
@@ -534,339 +551,340 @@ void PAINT_OT_weight_set(wmOperatorType *ot)
/* *** VGroups Gradient *** */
typedef struct WPGradient_vertStore {
- float sco[2];
- float weight_orig;
- enum {
- VGRAD_STORE_NOP = 0,
- VGRAD_STORE_DW_EXIST = (1 << 0),
- } flag;
+ float sco[2];
+ float weight_orig;
+ enum {
+ VGRAD_STORE_NOP = 0,
+ VGRAD_STORE_DW_EXIST = (1 << 0),
+ } flag;
} WPGradient_vertStore;
typedef struct WPGradient_vertStoreBase {
- struct WPaintPrev wpp;
- WPGradient_vertStore elem[0];
+ struct WPaintPrev wpp;
+ WPGradient_vertStore elem[0];
} WPGradient_vertStoreBase;
typedef struct WPGradient_userData {
- struct ARegion *ar;
- Scene *scene;
- Mesh *me;
- Brush *brush;
- const float *sco_start; /* [2] */
- const float *sco_end; /* [2] */
- float sco_line_div; /* store (1.0f / len_v2v2(sco_start, sco_end)) */
- int def_nr;
- bool is_init;
- WPGradient_vertStoreBase *vert_cache;
- /* only for init */
- BLI_bitmap *vert_visit;
-
- /* options */
- short use_select;
- short type;
- float weightpaint;
+ struct ARegion *ar;
+ Scene *scene;
+ Mesh *me;
+ Brush *brush;
+ const float *sco_start; /* [2] */
+ const float *sco_end; /* [2] */
+ float sco_line_div; /* store (1.0f / len_v2v2(sco_start, sco_end)) */
+ int def_nr;
+ bool is_init;
+ WPGradient_vertStoreBase *vert_cache;
+ /* only for init */
+ BLI_bitmap *vert_visit;
+
+ /* options */
+ short use_select;
+ short type;
+ float weightpaint;
} WPGradient_userData;
static void gradientVert_update(WPGradient_userData *grad_data, int index)
{
- Mesh *me = grad_data->me;
- WPGradient_vertStore *vs = &grad_data->vert_cache->elem[index];
- float alpha;
-
- if (grad_data->type == WPAINT_GRADIENT_TYPE_LINEAR) {
- alpha = line_point_factor_v2(vs->sco, grad_data->sco_start, grad_data->sco_end);
- }
- else {
- BLI_assert(grad_data->type == WPAINT_GRADIENT_TYPE_RADIAL);
- alpha = len_v2v2(grad_data->sco_start, vs->sco) * grad_data->sco_line_div;
- }
- /* no need to clamp 'alpha' yet */
-
- /* adjust weight */
- alpha = BKE_brush_curve_strength_clamped(grad_data->brush, alpha, 1.0f);
-
- if (alpha != 0.0f) {
- MDeformVert *dv = &me->dvert[index];
- MDeformWeight *dw = defvert_verify_index(dv, grad_data->def_nr);
- // dw->weight = alpha; // testing
- int tool = grad_data->brush->blend;
- float testw;
-
- /* init if we just added */
- testw = ED_wpaint_blend_tool(tool, vs->weight_orig, grad_data->weightpaint, alpha * grad_data->brush->alpha);
- CLAMP(testw, 0.0f, 1.0f);
- dw->weight = testw;
- }
- else {
- MDeformVert *dv = &me->dvert[index];
- if (vs->flag & VGRAD_STORE_DW_EXIST) {
- /* normally we NULL check, but in this case we know it exists */
- MDeformWeight *dw = defvert_find_index(dv, grad_data->def_nr);
- dw->weight = vs->weight_orig;
- }
- else {
- /* wasn't originally existing, remove */
- MDeformWeight *dw = defvert_find_index(dv, grad_data->def_nr);
- if (dw) {
- defvert_remove_group(dv, dw);
- }
- }
- }
+ Mesh *me = grad_data->me;
+ WPGradient_vertStore *vs = &grad_data->vert_cache->elem[index];
+ float alpha;
+
+ if (grad_data->type == WPAINT_GRADIENT_TYPE_LINEAR) {
+ alpha = line_point_factor_v2(vs->sco, grad_data->sco_start, grad_data->sco_end);
+ }
+ else {
+ BLI_assert(grad_data->type == WPAINT_GRADIENT_TYPE_RADIAL);
+ alpha = len_v2v2(grad_data->sco_start, vs->sco) * grad_data->sco_line_div;
+ }
+ /* no need to clamp 'alpha' yet */
+
+ /* adjust weight */
+ alpha = BKE_brush_curve_strength_clamped(grad_data->brush, alpha, 1.0f);
+
+ if (alpha != 0.0f) {
+ MDeformVert *dv = &me->dvert[index];
+ MDeformWeight *dw = defvert_verify_index(dv, grad_data->def_nr);
+ // dw->weight = alpha; // testing
+ int tool = grad_data->brush->blend;
+ float testw;
+
+ /* init if we just added */
+ testw = ED_wpaint_blend_tool(
+ tool, vs->weight_orig, grad_data->weightpaint, alpha * grad_data->brush->alpha);
+ CLAMP(testw, 0.0f, 1.0f);
+ dw->weight = testw;
+ }
+ else {
+ MDeformVert *dv = &me->dvert[index];
+ if (vs->flag & VGRAD_STORE_DW_EXIST) {
+ /* normally we NULL check, but in this case we know it exists */
+ MDeformWeight *dw = defvert_find_index(dv, grad_data->def_nr);
+ dw->weight = vs->weight_orig;
+ }
+ else {
+ /* wasn't originally existing, remove */
+ MDeformWeight *dw = defvert_find_index(dv, grad_data->def_nr);
+ if (dw) {
+ defvert_remove_group(dv, dw);
+ }
+ }
+ }
}
-static void gradientVertUpdate__mapFunc(
- void *userData, int index, const float UNUSED(co[3]),
- const float UNUSED(no_f[3]), const short UNUSED(no_s[3]))
+static void gradientVertUpdate__mapFunc(void *userData,
+ int index,
+ const float UNUSED(co[3]),
+ const float UNUSED(no_f[3]),
+ const short UNUSED(no_s[3]))
{
- WPGradient_userData *grad_data = userData;
- WPGradient_vertStore *vs = &grad_data->vert_cache->elem[index];
+ WPGradient_userData *grad_data = userData;
+ WPGradient_vertStore *vs = &grad_data->vert_cache->elem[index];
- if (vs->sco[0] == FLT_MAX) {
- return;
- }
+ if (vs->sco[0] == FLT_MAX) {
+ return;
+ }
- gradientVert_update(grad_data, index);
+ gradientVert_update(grad_data, index);
}
-static void gradientVertInit__mapFunc(
- void *userData, int index, const float co[3],
- const float UNUSED(no_f[3]), const short UNUSED(no_s[3]))
+static void gradientVertInit__mapFunc(void *userData,
+ int index,
+ const float co[3],
+ const float UNUSED(no_f[3]),
+ const short UNUSED(no_s[3]))
{
- WPGradient_userData *grad_data = userData;
- Mesh *me = grad_data->me;
- WPGradient_vertStore *vs = &grad_data->vert_cache->elem[index];
-
- if (grad_data->use_select && !(me->mvert[index].flag & SELECT)) {
- copy_v2_fl(vs->sco, FLT_MAX);
- return;
- }
-
- /* run first pass only,
- * the screen coords of the verts need to be cached because
- * updating the mesh may move them about (entering feedback loop) */
- if (BLI_BITMAP_TEST(grad_data->vert_visit, index)) {
- copy_v2_fl(vs->sco, FLT_MAX);
- return;
- }
-
- if (ED_view3d_project_float_object(
- grad_data->ar,
- co, vs->sco,
- V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_NEAR) != V3D_PROJ_RET_OK)
- {
- return;
- }
-
- MDeformVert *dv = &me->dvert[index];
- const MDeformWeight *dw = defvert_find_index(dv, grad_data->def_nr);
- if (dw) {
- vs->weight_orig = dw->weight;
- vs->flag = VGRAD_STORE_DW_EXIST;
- }
- else {
- vs->weight_orig = 0.0f;
- vs->flag = VGRAD_STORE_NOP;
- }
- BLI_BITMAP_ENABLE(grad_data->vert_visit, index);
- gradientVert_update(grad_data, index);
+ WPGradient_userData *grad_data = userData;
+ Mesh *me = grad_data->me;
+ WPGradient_vertStore *vs = &grad_data->vert_cache->elem[index];
+
+ if (grad_data->use_select && !(me->mvert[index].flag & SELECT)) {
+ copy_v2_fl(vs->sco, FLT_MAX);
+ return;
+ }
+
+ /* run first pass only,
+ * the screen coords of the verts need to be cached because
+ * updating the mesh may move them about (entering feedback loop) */
+ if (BLI_BITMAP_TEST(grad_data->vert_visit, index)) {
+ copy_v2_fl(vs->sco, FLT_MAX);
+ return;
+ }
+
+ if (ED_view3d_project_float_object(
+ grad_data->ar, co, vs->sco, V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_NEAR) !=
+ V3D_PROJ_RET_OK) {
+ return;
+ }
+
+ MDeformVert *dv = &me->dvert[index];
+ const MDeformWeight *dw = defvert_find_index(dv, grad_data->def_nr);
+ if (dw) {
+ vs->weight_orig = dw->weight;
+ vs->flag = VGRAD_STORE_DW_EXIST;
+ }
+ else {
+ vs->weight_orig = 0.0f;
+ vs->flag = VGRAD_STORE_NOP;
+ }
+ BLI_BITMAP_ENABLE(grad_data->vert_visit, index);
+ gradientVert_update(grad_data, index);
}
static int paint_weight_gradient_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
- wmGesture *gesture = op->customdata;
- WPGradient_vertStoreBase *vert_cache = gesture->userdata;
- int ret = WM_gesture_straightline_modal(C, op, event);
-
- if (ret & OPERATOR_RUNNING_MODAL) {
- if (event->type == LEFTMOUSE && event->val == KM_RELEASE) { /* XXX, hardcoded */
- /* generally crap! redo! */
- WM_gesture_straightline_cancel(C, op);
- ret &= ~OPERATOR_RUNNING_MODAL;
- ret |= OPERATOR_FINISHED;
- }
- }
-
- if (ret & OPERATOR_CANCELLED) {
- Object *ob = CTX_data_active_object(C);
- if (vert_cache != NULL) {
- Mesh *me = ob->data;
- if (vert_cache->wpp.wpaint_prev) {
- BKE_defvert_array_free_elems(me->dvert, me->totvert);
- BKE_defvert_array_copy(me->dvert, vert_cache->wpp.wpaint_prev, me->totvert);
- wpaint_prev_destroy(&vert_cache->wpp);
- }
- MEM_freeN(vert_cache);
- }
-
- DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
- WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
- }
- else if (ret & OPERATOR_FINISHED) {
- wpaint_prev_destroy(&vert_cache->wpp);
- MEM_freeN(vert_cache);
- }
-
- return ret;
+ wmGesture *gesture = op->customdata;
+ WPGradient_vertStoreBase *vert_cache = gesture->userdata;
+ int ret = WM_gesture_straightline_modal(C, op, event);
+
+ if (ret & OPERATOR_RUNNING_MODAL) {
+ if (event->type == LEFTMOUSE && event->val == KM_RELEASE) { /* XXX, hardcoded */
+ /* generally crap! redo! */
+ WM_gesture_straightline_cancel(C, op);
+ ret &= ~OPERATOR_RUNNING_MODAL;
+ ret |= OPERATOR_FINISHED;
+ }
+ }
+
+ if (ret & OPERATOR_CANCELLED) {
+ Object *ob = CTX_data_active_object(C);
+ if (vert_cache != NULL) {
+ Mesh *me = ob->data;
+ if (vert_cache->wpp.wpaint_prev) {
+ BKE_defvert_array_free_elems(me->dvert, me->totvert);
+ BKE_defvert_array_copy(me->dvert, vert_cache->wpp.wpaint_prev, me->totvert);
+ wpaint_prev_destroy(&vert_cache->wpp);
+ }
+ MEM_freeN(vert_cache);
+ }
+
+ DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
+ }
+ else if (ret & OPERATOR_FINISHED) {
+ wpaint_prev_destroy(&vert_cache->wpp);
+ MEM_freeN(vert_cache);
+ }
+
+ return ret;
}
static int paint_weight_gradient_exec(bContext *C, wmOperator *op)
{
- wmGesture *gesture = op->customdata;
- WPGradient_vertStoreBase *vert_cache;
- struct ARegion *ar = CTX_wm_region(C);
- Scene *scene = CTX_data_scene(C);
- Object *ob = CTX_data_active_object(C);
- Mesh *me = ob->data;
- int x_start = RNA_int_get(op->ptr, "xstart");
- int y_start = RNA_int_get(op->ptr, "ystart");
- int x_end = RNA_int_get(op->ptr, "xend");
- int y_end = RNA_int_get(op->ptr, "yend");
- float sco_start[2] = {x_start, y_start};
- float sco_end[2] = {x_end, y_end};
- const bool is_interactive = (gesture != NULL);
-
- Depsgraph *depsgraph = CTX_data_depsgraph(C);
-
- WPGradient_userData data = {NULL};
-
- if (is_interactive) {
- if (gesture->userdata == NULL) {
- gesture->userdata = MEM_mallocN(
- sizeof(WPGradient_vertStoreBase) +
- (sizeof(WPGradient_vertStore) * me->totvert),
- __func__);
- gesture->userdata_free = false;
- data.is_init = true;
-
- wpaint_prev_create(&((WPGradient_vertStoreBase *)gesture->userdata)->wpp, me->dvert, me->totvert);
-
- /* on init only, convert face -> vert sel */
- if (me->editflag & ME_EDIT_PAINT_FACE_SEL) {
- BKE_mesh_flush_select_from_polys(me);
- }
- }
-
- vert_cache = gesture->userdata;
- }
- else {
- if (ED_wpaint_ensure_data(C, op->reports, 0, NULL) == false) {
- return OPERATOR_CANCELLED;
- }
-
- data.is_init = true;
- vert_cache = MEM_mallocN(
- sizeof(WPGradient_vertStoreBase) +
- (sizeof(WPGradient_vertStore) * me->totvert),
- __func__);
- }
-
- data.ar = ar;
- data.scene = scene;
- data.me = ob->data;
- data.sco_start = sco_start;
- data.sco_end = sco_end;
- data.sco_line_div = 1.0f / len_v2v2(sco_start, sco_end);
- data.def_nr = ob->actdef - 1;
- data.use_select = (me->editflag & (ME_EDIT_PAINT_FACE_SEL | ME_EDIT_PAINT_VERT_SEL));
- data.vert_cache = vert_cache;
- data.vert_visit = NULL;
- data.type = RNA_enum_get(op->ptr, "type");
-
- {
- ToolSettings *ts = CTX_data_tool_settings(C);
- VPaint *wp = ts->wpaint;
- struct Brush *brush = BKE_paint_brush(&wp->paint);
-
- curvemapping_initialize(brush->curve);
-
- data.brush = brush;
- data.weightpaint = BKE_brush_weight_get(scene, brush);
- }
-
- ED_view3d_init_mats_rv3d(ob, ar->regiondata);
-
- Scene *scene_eval = DEG_get_evaluated_scene(depsgraph);
- Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
-
- CustomData_MeshMasks cddata_masks = scene->customdata_mask;
- cddata_masks.vmask |= CD_MASK_ORIGINDEX;
- cddata_masks.emask |= CD_MASK_ORIGINDEX;
- cddata_masks.pmask |= CD_MASK_ORIGINDEX;
- Mesh *me_eval = mesh_get_eval_final(depsgraph, scene_eval, ob_eval, &cddata_masks);
- if (data.is_init) {
- data.vert_visit = BLI_BITMAP_NEW(me->totvert, __func__);
-
- BKE_mesh_foreach_mapped_vert(me_eval, gradientVertInit__mapFunc, &data, MESH_FOREACH_NOP);
-
- MEM_freeN(data.vert_visit);
- data.vert_visit = NULL;
- }
- else {
- BKE_mesh_foreach_mapped_vert(me_eval, gradientVertUpdate__mapFunc, &data, MESH_FOREACH_NOP);
- }
-
- DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
- WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
-
- if (is_interactive == false) {
- MEM_freeN(vert_cache);
- }
-
- return OPERATOR_FINISHED;
+ wmGesture *gesture = op->customdata;
+ WPGradient_vertStoreBase *vert_cache;
+ struct ARegion *ar = CTX_wm_region(C);
+ Scene *scene = CTX_data_scene(C);
+ Object *ob = CTX_data_active_object(C);
+ Mesh *me = ob->data;
+ int x_start = RNA_int_get(op->ptr, "xstart");
+ int y_start = RNA_int_get(op->ptr, "ystart");
+ int x_end = RNA_int_get(op->ptr, "xend");
+ int y_end = RNA_int_get(op->ptr, "yend");
+ float sco_start[2] = {x_start, y_start};
+ float sco_end[2] = {x_end, y_end};
+ const bool is_interactive = (gesture != NULL);
+
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+
+ WPGradient_userData data = {NULL};
+
+ if (is_interactive) {
+ if (gesture->userdata == NULL) {
+ gesture->userdata = MEM_mallocN(sizeof(WPGradient_vertStoreBase) +
+ (sizeof(WPGradient_vertStore) * me->totvert),
+ __func__);
+ gesture->userdata_free = false;
+ data.is_init = true;
+
+ wpaint_prev_create(
+ &((WPGradient_vertStoreBase *)gesture->userdata)->wpp, me->dvert, me->totvert);
+
+ /* on init only, convert face -> vert sel */
+ if (me->editflag & ME_EDIT_PAINT_FACE_SEL) {
+ BKE_mesh_flush_select_from_polys(me);
+ }
+ }
+
+ vert_cache = gesture->userdata;
+ }
+ else {
+ if (ED_wpaint_ensure_data(C, op->reports, 0, NULL) == false) {
+ return OPERATOR_CANCELLED;
+ }
+
+ data.is_init = true;
+ vert_cache = MEM_mallocN(
+ sizeof(WPGradient_vertStoreBase) + (sizeof(WPGradient_vertStore) * me->totvert), __func__);
+ }
+
+ data.ar = ar;
+ data.scene = scene;
+ data.me = ob->data;
+ data.sco_start = sco_start;
+ data.sco_end = sco_end;
+ data.sco_line_div = 1.0f / len_v2v2(sco_start, sco_end);
+ data.def_nr = ob->actdef - 1;
+ data.use_select = (me->editflag & (ME_EDIT_PAINT_FACE_SEL | ME_EDIT_PAINT_VERT_SEL));
+ data.vert_cache = vert_cache;
+ data.vert_visit = NULL;
+ data.type = RNA_enum_get(op->ptr, "type");
+
+ {
+ ToolSettings *ts = CTX_data_tool_settings(C);
+ VPaint *wp = ts->wpaint;
+ struct Brush *brush = BKE_paint_brush(&wp->paint);
+
+ curvemapping_initialize(brush->curve);
+
+ data.brush = brush;
+ data.weightpaint = BKE_brush_weight_get(scene, brush);
+ }
+
+ ED_view3d_init_mats_rv3d(ob, ar->regiondata);
+
+ Scene *scene_eval = DEG_get_evaluated_scene(depsgraph);
+ Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
+
+ CustomData_MeshMasks cddata_masks = scene->customdata_mask;
+ cddata_masks.vmask |= CD_MASK_ORIGINDEX;
+ cddata_masks.emask |= CD_MASK_ORIGINDEX;
+ cddata_masks.pmask |= CD_MASK_ORIGINDEX;
+ Mesh *me_eval = mesh_get_eval_final(depsgraph, scene_eval, ob_eval, &cddata_masks);
+ if (data.is_init) {
+ data.vert_visit = BLI_BITMAP_NEW(me->totvert, __func__);
+
+ BKE_mesh_foreach_mapped_vert(me_eval, gradientVertInit__mapFunc, &data, MESH_FOREACH_NOP);
+
+ MEM_freeN(data.vert_visit);
+ data.vert_visit = NULL;
+ }
+ else {
+ BKE_mesh_foreach_mapped_vert(me_eval, gradientVertUpdate__mapFunc, &data, MESH_FOREACH_NOP);
+ }
+
+ DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
+
+ if (is_interactive == false) {
+ MEM_freeN(vert_cache);
+ }
+
+ return OPERATOR_FINISHED;
}
static int paint_weight_gradient_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
- int ret;
-
- if (ED_wpaint_ensure_data(C, op->reports, 0, NULL) == false) {
- return OPERATOR_CANCELLED;
- }
-
- ret = WM_gesture_straightline_invoke(C, op, event);
- if (ret & OPERATOR_RUNNING_MODAL) {
- struct ARegion *ar = CTX_wm_region(C);
- if (ar->regiontype == RGN_TYPE_WINDOW) {
- /* TODO, hardcoded, extend WM_gesture_straightline_ */
- if (event->type == LEFTMOUSE && event->val == KM_PRESS) {
- wmGesture *gesture = op->customdata;
- gesture->is_active = true;
- }
- }
- }
- return ret;
+ int ret;
+
+ if (ED_wpaint_ensure_data(C, op->reports, 0, NULL) == false) {
+ return OPERATOR_CANCELLED;
+ }
+
+ ret = WM_gesture_straightline_invoke(C, op, event);
+ if (ret & OPERATOR_RUNNING_MODAL) {
+ struct ARegion *ar = CTX_wm_region(C);
+ if (ar->regiontype == RGN_TYPE_WINDOW) {
+ /* TODO, hardcoded, extend WM_gesture_straightline_ */
+ if (event->type == LEFTMOUSE && event->val == KM_PRESS) {
+ wmGesture *gesture = op->customdata;
+ gesture->is_active = true;
+ }
+ }
+ }
+ return ret;
}
void PAINT_OT_weight_gradient(wmOperatorType *ot)
{
- /* defined in DNA_space_types.h */
- static const EnumPropertyItem gradient_types[] = {
- {WPAINT_GRADIENT_TYPE_LINEAR, "LINEAR", 0, "Linear", ""},
- {WPAINT_GRADIENT_TYPE_RADIAL, "RADIAL", 0, "Radial", ""},
- {0, NULL, 0, NULL, NULL},
- };
-
- PropertyRNA *prop;
-
- /* identifiers */
- ot->name = "Weight Gradient";
- ot->idname = "PAINT_OT_weight_gradient";
- ot->description = "Draw a line to apply a weight gradient to selected vertices";
-
- /* api callbacks */
- ot->invoke = paint_weight_gradient_invoke;
- ot->modal = paint_weight_gradient_modal;
- ot->exec = paint_weight_gradient_exec;
- ot->poll = weight_paint_poll_ignore_tool;
- ot->cancel = WM_gesture_straightline_cancel;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- prop = RNA_def_enum(ot->srna, "type", gradient_types, 0, "Type", "");
- RNA_def_property_flag(prop, PROP_SKIP_SAVE);
-
- WM_operator_properties_gesture_straightline(ot, CURSOR_EDIT);
+ /* defined in DNA_space_types.h */
+ static const EnumPropertyItem gradient_types[] = {
+ {WPAINT_GRADIENT_TYPE_LINEAR, "LINEAR", 0, "Linear", ""},
+ {WPAINT_GRADIENT_TYPE_RADIAL, "RADIAL", 0, "Radial", ""},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ PropertyRNA *prop;
+
+ /* identifiers */
+ ot->name = "Weight Gradient";
+ ot->idname = "PAINT_OT_weight_gradient";
+ ot->description = "Draw a line to apply a weight gradient to selected vertices";
+
+ /* api callbacks */
+ ot->invoke = paint_weight_gradient_invoke;
+ ot->modal = paint_weight_gradient_modal;
+ ot->exec = paint_weight_gradient_exec;
+ ot->poll = weight_paint_poll_ignore_tool;
+ ot->cancel = WM_gesture_straightline_cancel;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ prop = RNA_def_enum(ot->srna, "type", gradient_types, 0, "Type", "");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+
+ WM_operator_properties_gesture_straightline(ot, CURSOR_EDIT);
}
/** \} */
diff --git a/source/blender/editors/sculpt_paint/paint_vertex_weight_utils.c b/source/blender/editors/sculpt_paint/paint_vertex_weight_utils.c
index 38f9f1dfa9f..88aed201b48 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex_weight_utils.c
+++ b/source/blender/editors/sculpt_paint/paint_vertex_weight_utils.c
@@ -47,111 +47,112 @@
#include "WM_api.h"
#include "WM_types.h"
-#include "paint_intern.h" /* own include */
+#include "paint_intern.h" /* own include */
/* -------------------------------------------------------------------- */
/** \name Weight Paint Sanity Checks
* \{ */
/* ensure we have data on wpaint start, add if needed */
-bool ED_wpaint_ensure_data(
- bContext *C, struct ReportList *reports,
- enum eWPaintFlag flag, struct WPaintVGroupIndex *vgroup_index)
+bool ED_wpaint_ensure_data(bContext *C,
+ struct ReportList *reports,
+ enum eWPaintFlag flag,
+ struct WPaintVGroupIndex *vgroup_index)
{
- Object *ob = CTX_data_active_object(C);
- Mesh *me = BKE_mesh_from_object(ob);
+ Object *ob = CTX_data_active_object(C);
+ Mesh *me = BKE_mesh_from_object(ob);
- if (vgroup_index) {
- vgroup_index->active = -1;
- vgroup_index->mirror = -1;
- }
+ if (vgroup_index) {
+ vgroup_index->active = -1;
+ vgroup_index->mirror = -1;
+ }
- if (BKE_object_is_in_editmode(ob)) {
- return false;
- }
+ if (BKE_object_is_in_editmode(ob)) {
+ return false;
+ }
- if (me == NULL || me->totpoly == 0) {
- return false;
- }
+ if (me == NULL || me->totpoly == 0) {
+ return false;
+ }
- /* if nothing was added yet, we make dverts and a vertex deform group */
- if (!me->dvert) {
- BKE_object_defgroup_data_create(&me->id);
- WM_event_add_notifier(C, NC_GEOM | ND_DATA, me);
- }
+ /* if nothing was added yet, we make dverts and a vertex deform group */
+ if (!me->dvert) {
+ BKE_object_defgroup_data_create(&me->id);
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, me);
+ }
- /* this happens on a Bone select, when no vgroup existed yet */
- if (ob->actdef <= 0) {
- Object *modob;
- if ((modob = modifiers_isDeformedByArmature(ob))) {
- Bone *actbone = ((bArmature *)modob->data)->act_bone;
- if (actbone) {
- bPoseChannel *pchan = BKE_pose_channel_find_name(modob->pose, actbone->name);
+ /* this happens on a Bone select, when no vgroup existed yet */
+ if (ob->actdef <= 0) {
+ Object *modob;
+ if ((modob = modifiers_isDeformedByArmature(ob))) {
+ Bone *actbone = ((bArmature *)modob->data)->act_bone;
+ if (actbone) {
+ bPoseChannel *pchan = BKE_pose_channel_find_name(modob->pose, actbone->name);
- if (pchan) {
- bDeformGroup *dg = defgroup_find_name(ob, pchan->name);
- if (dg == NULL) {
- dg = BKE_object_defgroup_add_name(ob, pchan->name); /* sets actdef */
- }
- else {
- int actdef = 1 + BLI_findindex(&ob->defbase, dg);
- BLI_assert(actdef >= 0);
- ob->actdef = actdef;
- }
- }
- }
- }
- }
- if (BLI_listbase_is_empty(&ob->defbase)) {
- BKE_object_defgroup_add(ob);
- }
+ if (pchan) {
+ bDeformGroup *dg = defgroup_find_name(ob, pchan->name);
+ if (dg == NULL) {
+ dg = BKE_object_defgroup_add_name(ob, pchan->name); /* sets actdef */
+ }
+ else {
+ int actdef = 1 + BLI_findindex(&ob->defbase, dg);
+ BLI_assert(actdef >= 0);
+ ob->actdef = actdef;
+ }
+ }
+ }
+ }
+ }
+ if (BLI_listbase_is_empty(&ob->defbase)) {
+ BKE_object_defgroup_add(ob);
+ }
- /* ensure we don't try paint onto an invalid group */
- if (ob->actdef <= 0) {
- BKE_report(reports, RPT_WARNING, "No active vertex group for painting, aborting");
- return false;
- }
+ /* ensure we don't try paint onto an invalid group */
+ if (ob->actdef <= 0) {
+ BKE_report(reports, RPT_WARNING, "No active vertex group for painting, aborting");
+ return false;
+ }
- if (vgroup_index) {
- vgroup_index->active = ob->actdef - 1;
- }
+ if (vgroup_index) {
+ vgroup_index->active = ob->actdef - 1;
+ }
- if (flag & WPAINT_ENSURE_MIRROR) {
- if (me->editflag & ME_EDIT_MIRROR_X) {
- int mirror = ED_wpaint_mirror_vgroup_ensure(ob, ob->actdef - 1);
- if (vgroup_index) {
- vgroup_index->mirror = mirror;
- }
- }
- }
+ if (flag & WPAINT_ENSURE_MIRROR) {
+ if (me->editflag & ME_EDIT_MIRROR_X) {
+ int mirror = ED_wpaint_mirror_vgroup_ensure(ob, ob->actdef - 1);
+ if (vgroup_index) {
+ vgroup_index->mirror = mirror;
+ }
+ }
+ }
- return true;
+ return true;
}
/** \} */
/* mirror_vgroup is set to -1 when invalid */
int ED_wpaint_mirror_vgroup_ensure(Object *ob, const int vgroup_active)
{
- bDeformGroup *defgroup = BLI_findlink(&ob->defbase, vgroup_active);
+ bDeformGroup *defgroup = BLI_findlink(&ob->defbase, vgroup_active);
- if (defgroup) {
- int mirrdef;
- char name_flip[MAXBONENAME];
+ if (defgroup) {
+ int mirrdef;
+ char name_flip[MAXBONENAME];
- BLI_string_flip_side_name(name_flip, defgroup->name, false, sizeof(name_flip));
- mirrdef = defgroup_name_index(ob, name_flip);
- if (mirrdef == -1) {
- if (BKE_defgroup_new(ob, name_flip)) {
- mirrdef = BLI_listbase_count(&ob->defbase) - 1;
- }
- }
+ BLI_string_flip_side_name(name_flip, defgroup->name, false, sizeof(name_flip));
+ mirrdef = defgroup_name_index(ob, name_flip);
+ if (mirrdef == -1) {
+ if (BKE_defgroup_new(ob, name_flip)) {
+ mirrdef = BLI_listbase_count(&ob->defbase) - 1;
+ }
+ }
- /* curdef should never be NULL unless this is
- * a light and BKE_object_defgroup_add_name fails */
- return mirrdef;
- }
+ /* curdef should never be NULL unless this is
+ * a light and BKE_object_defgroup_add_name fails */
+ return mirrdef;
+ }
- return -1;
+ return -1;
}
/* -------------------------------------------------------------------- */
@@ -160,144 +161,158 @@ int ED_wpaint_mirror_vgroup_ensure(Object *ob, const int vgroup_active)
BLI_INLINE float wval_blend(const float weight, const float paintval, const float alpha)
{
- const float talpha = min_ff(alpha, 1.0f); /* blending with values over 1 doesn't make sense */
- return (paintval * talpha) + (weight * (1.0f - talpha));
+ const float talpha = min_ff(alpha, 1.0f); /* blending with values over 1 doesn't make sense */
+ return (paintval * talpha) + (weight * (1.0f - talpha));
}
BLI_INLINE float wval_add(const float weight, const float paintval, const float alpha)
{
- return weight + (paintval * alpha);
+ return weight + (paintval * alpha);
}
BLI_INLINE float wval_sub(const float weight, const float paintval, const float alpha)
{
- return weight - (paintval * alpha);
+ return weight - (paintval * alpha);
}
BLI_INLINE float wval_mul(const float weight, const float paintval, const float alpha)
-{ /* first mul, then blend the fac */
- return ((1.0f - alpha) + (alpha * paintval)) * weight;
+{ /* first mul, then blend the fac */
+ return ((1.0f - alpha) + (alpha * paintval)) * weight;
}
BLI_INLINE float wval_lighten(const float weight, const float paintval, const float alpha)
{
- return (weight < paintval) ? wval_blend(weight, paintval, alpha) : weight;
+ return (weight < paintval) ? wval_blend(weight, paintval, alpha) : weight;
}
BLI_INLINE float wval_darken(const float weight, const float paintval, const float alpha)
{
- return (weight > paintval) ? wval_blend(weight, paintval, alpha) : weight;
+ return (weight > paintval) ? wval_blend(weight, paintval, alpha) : weight;
}
/* mainly for color */
BLI_INLINE float wval_colordodge(float weight, float paintval, float fac)
{
- float mfac, temp;
- if (fac == 0.0f) {
- return weight;
- }
- mfac = 1.0f - fac;
- temp = (paintval == 1.0f) ? 1.0f : min_ff((weight * (225.0f / 255.0f)) / (1.0f - paintval), 1.0f);
- return mfac * weight + temp * fac;
+ float mfac, temp;
+ if (fac == 0.0f) {
+ return weight;
+ }
+ mfac = 1.0f - fac;
+ temp = (paintval == 1.0f) ? 1.0f :
+ min_ff((weight * (225.0f / 255.0f)) / (1.0f - paintval), 1.0f);
+ return mfac * weight + temp * fac;
}
BLI_INLINE float wval_difference(float weight, float paintval, float fac)
{
- float mfac, temp;
- if (fac == 0.0f) {
- return weight;
- }
- mfac = 1.0f - fac;
- temp = fabsf(weight - paintval);
- return mfac * weight + temp * fac;
+ float mfac, temp;
+ if (fac == 0.0f) {
+ return weight;
+ }
+ mfac = 1.0f - fac;
+ temp = fabsf(weight - paintval);
+ return mfac * weight + temp * fac;
}
BLI_INLINE float wval_screen(float weight, float paintval, float fac)
{
- float mfac, temp;
- if (fac == 0.0f) {
- return weight;
- }
- mfac = 1.0f - fac;
- temp = max_ff(1.0f - (((1.0f - weight) * (1.0f - paintval))), 0);
- return mfac * weight + temp * fac;
+ float mfac, temp;
+ if (fac == 0.0f) {
+ return weight;
+ }
+ mfac = 1.0f - fac;
+ temp = max_ff(1.0f - (((1.0f - weight) * (1.0f - paintval))), 0);
+ return mfac * weight + temp * fac;
}
BLI_INLINE float wval_hardlight(float weight, float paintval, float fac)
{
- float mfac, temp;
- if (fac == 0.0f) {
- return weight;
- }
- mfac = 1.0f - fac;
- if (paintval > 0.5f) {
- temp = 1.0f - ((1.0f - 2.0f * (paintval - 0.5f)) * (1.0f - weight));
- }
- else {
- temp = (2.0f * paintval * weight);
- }
- return mfac * weight + temp * fac;
+ float mfac, temp;
+ if (fac == 0.0f) {
+ return weight;
+ }
+ mfac = 1.0f - fac;
+ if (paintval > 0.5f) {
+ temp = 1.0f - ((1.0f - 2.0f * (paintval - 0.5f)) * (1.0f - weight));
+ }
+ else {
+ temp = (2.0f * paintval * weight);
+ }
+ return mfac * weight + temp * fac;
}
BLI_INLINE float wval_overlay(float weight, float paintval, float fac)
{
- float mfac, temp;
- if (fac == 0.0f) {
- return weight;
- }
- mfac = 1.0f - fac;
- if (weight > 0.5f) {
- temp = 1.0f - ((1.0f - 2.0f * (weight - 0.5f)) * (1.0f - paintval));
- }
- else {
- temp = (2.0f * paintval * weight);
- }
- return mfac * weight + temp * fac;
+ float mfac, temp;
+ if (fac == 0.0f) {
+ return weight;
+ }
+ mfac = 1.0f - fac;
+ if (weight > 0.5f) {
+ temp = 1.0f - ((1.0f - 2.0f * (weight - 0.5f)) * (1.0f - paintval));
+ }
+ else {
+ temp = (2.0f * paintval * weight);
+ }
+ return mfac * weight + temp * fac;
}
BLI_INLINE float wval_softlight(float weight, float paintval, float fac)
{
- float mfac, temp;
- if (fac == 0.0f) {
- return weight;
- }
- mfac = 1.0f - fac;
- if (weight < 0.5f) {
- temp = ((2.0f * ((paintval / 2.0f) + 0.25f)) * weight);
- }
- else {
- temp = 1.0f - (2.0f * (1.0f - ((paintval / 2.0f) + 0.25f)) * (1.0f - weight));
- }
- return temp * fac + weight * mfac;
+ float mfac, temp;
+ if (fac == 0.0f) {
+ return weight;
+ }
+ mfac = 1.0f - fac;
+ if (weight < 0.5f) {
+ temp = ((2.0f * ((paintval / 2.0f) + 0.25f)) * weight);
+ }
+ else {
+ temp = 1.0f - (2.0f * (1.0f - ((paintval / 2.0f) + 0.25f)) * (1.0f - weight));
+ }
+ return temp * fac + weight * mfac;
}
BLI_INLINE float wval_exclusion(float weight, float paintval, float fac)
{
- float mfac, temp;
- if (fac == 0.0f) {
- return weight;
- }
- mfac = 1.0f - fac;
- temp = 0.5f - ((2.0f * (weight - 0.5f) * (paintval - 0.5f)));
- return temp * fac + weight * mfac;
+ float mfac, temp;
+ if (fac == 0.0f) {
+ return weight;
+ }
+ mfac = 1.0f - fac;
+ temp = 0.5f - ((2.0f * (weight - 0.5f) * (paintval - 0.5f)));
+ return temp * fac + weight * mfac;
}
/* vpaint has 'vpaint_blend_tool' */
/* result is not clamped from [0-1] */
-float ED_wpaint_blend_tool(
- const int tool,
- /* dw->weight */
- const float weight,
- const float paintval, const float alpha)
+float ED_wpaint_blend_tool(const int tool,
+ /* dw->weight */
+ const float weight,
+ const float paintval,
+ const float alpha)
{
- switch ((IMB_BlendMode)tool) {
- case IMB_BLEND_MIX: return wval_blend(weight, paintval, alpha);
- case IMB_BLEND_ADD: return wval_add(weight, paintval, alpha);
- case IMB_BLEND_SUB: return wval_sub(weight, paintval, alpha);
- case IMB_BLEND_MUL: return wval_mul(weight, paintval, alpha);
- case IMB_BLEND_LIGHTEN: return wval_lighten(weight, paintval, alpha);
- case IMB_BLEND_DARKEN: return wval_darken(weight, paintval, alpha);
- /* Mostly make sense for color: support anyway. */
- case IMB_BLEND_COLORDODGE: return wval_colordodge(weight, paintval, alpha);
- case IMB_BLEND_DIFFERENCE: return wval_difference(weight, paintval, alpha);
- case IMB_BLEND_SCREEN: return wval_screen(weight, paintval, alpha);
- case IMB_BLEND_HARDLIGHT: return wval_hardlight(weight, paintval, alpha);
- case IMB_BLEND_OVERLAY: return wval_overlay(weight, paintval, alpha);
- case IMB_BLEND_SOFTLIGHT: return wval_softlight(weight, paintval, alpha);
- case IMB_BLEND_EXCLUSION: return wval_exclusion(weight, paintval, alpha);
- /* Only for color: just use blend. */
- default:
- return wval_blend(weight, paintval, alpha);
- }
+ switch ((IMB_BlendMode)tool) {
+ case IMB_BLEND_MIX:
+ return wval_blend(weight, paintval, alpha);
+ case IMB_BLEND_ADD:
+ return wval_add(weight, paintval, alpha);
+ case IMB_BLEND_SUB:
+ return wval_sub(weight, paintval, alpha);
+ case IMB_BLEND_MUL:
+ return wval_mul(weight, paintval, alpha);
+ case IMB_BLEND_LIGHTEN:
+ return wval_lighten(weight, paintval, alpha);
+ case IMB_BLEND_DARKEN:
+ return wval_darken(weight, paintval, alpha);
+ /* Mostly make sense for color: support anyway. */
+ case IMB_BLEND_COLORDODGE:
+ return wval_colordodge(weight, paintval, alpha);
+ case IMB_BLEND_DIFFERENCE:
+ return wval_difference(weight, paintval, alpha);
+ case IMB_BLEND_SCREEN:
+ return wval_screen(weight, paintval, alpha);
+ case IMB_BLEND_HARDLIGHT:
+ return wval_hardlight(weight, paintval, alpha);
+ case IMB_BLEND_OVERLAY:
+ return wval_overlay(weight, paintval, alpha);
+ case IMB_BLEND_SOFTLIGHT:
+ return wval_softlight(weight, paintval, alpha);
+ case IMB_BLEND_EXCLUSION:
+ return wval_exclusion(weight, paintval, alpha);
+ /* Only for color: just use blend. */
+ default:
+ return wval_blend(weight, paintval, alpha);
+ }
}
/** \} */
diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c
index ad2cfb5f9fc..9309def4a77 100644
--- a/source/blender/editors/sculpt_paint/sculpt.c
+++ b/source/blender/editors/sculpt_paint/sculpt.c
@@ -22,7 +22,6 @@
* \ingroup edsculpt
*/
-
#include "MEM_guardedalloc.h"
#include "BLI_math.h"
@@ -103,188 +102,175 @@
* (used for flushing updates at enter/exit sculpt mode) */
static bool sculpt_has_active_modifiers(Scene *scene, Object *ob)
{
- ModifierData *md;
- VirtualModifierData virtualModifierData;
+ ModifierData *md;
+ VirtualModifierData virtualModifierData;
- md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
+ md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
- /* exception for shape keys because we can edit those */
- for (; md; md = md->next) {
- if (modifier_isEnabled(scene, md, eModifierMode_Realtime))
- return 1;
- }
+ /* exception for shape keys because we can edit those */
+ for (; md; md = md->next) {
+ if (modifier_isEnabled(scene, md, eModifierMode_Realtime))
+ return 1;
+ }
- return 0;
+ return 0;
}
static bool sculpt_tool_needs_original(const char sculpt_tool)
{
- return ELEM(sculpt_tool,
- SCULPT_TOOL_GRAB,
- SCULPT_TOOL_ROTATE,
- SCULPT_TOOL_THUMB,
- SCULPT_TOOL_LAYER);
+ return ELEM(
+ sculpt_tool, SCULPT_TOOL_GRAB, SCULPT_TOOL_ROTATE, SCULPT_TOOL_THUMB, SCULPT_TOOL_LAYER);
}
static bool sculpt_tool_is_proxy_used(const char sculpt_tool)
{
- return ELEM(sculpt_tool,
- SCULPT_TOOL_SMOOTH,
- SCULPT_TOOL_LAYER);
+ return ELEM(sculpt_tool, SCULPT_TOOL_SMOOTH, SCULPT_TOOL_LAYER);
}
-static bool sculpt_brush_use_topology_rake(
- const SculptSession *ss, const Brush *brush)
+static bool sculpt_brush_use_topology_rake(const SculptSession *ss, const Brush *brush)
{
- return SCULPT_TOOL_HAS_TOPOLOGY_RAKE(brush->sculpt_tool) &&
- (brush->topology_rake_factor > 0.0f) &&
- (ss->bm != NULL);
+ return SCULPT_TOOL_HAS_TOPOLOGY_RAKE(brush->sculpt_tool) &&
+ (brush->topology_rake_factor > 0.0f) && (ss->bm != NULL);
}
/**
* Test whether the #StrokeCache.sculpt_normal needs update in #do_brush_action
*/
-static int sculpt_brush_needs_normal(
- const SculptSession *ss, const Brush *brush)
+static int sculpt_brush_needs_normal(const SculptSession *ss, const Brush *brush)
{
- return ((SCULPT_TOOL_HAS_NORMAL_WEIGHT(brush->sculpt_tool) &&
- (ss->cache->normal_weight > 0.0f)) ||
+ return ((SCULPT_TOOL_HAS_NORMAL_WEIGHT(brush->sculpt_tool) &&
+ (ss->cache->normal_weight > 0.0f)) ||
- ELEM(brush->sculpt_tool,
- SCULPT_TOOL_BLOB,
- SCULPT_TOOL_CREASE,
- SCULPT_TOOL_DRAW,
- SCULPT_TOOL_LAYER,
- SCULPT_TOOL_NUDGE,
- SCULPT_TOOL_ROTATE,
- SCULPT_TOOL_THUMB) ||
+ ELEM(brush->sculpt_tool,
+ SCULPT_TOOL_BLOB,
+ SCULPT_TOOL_CREASE,
+ SCULPT_TOOL_DRAW,
+ SCULPT_TOOL_LAYER,
+ SCULPT_TOOL_NUDGE,
+ SCULPT_TOOL_ROTATE,
+ SCULPT_TOOL_THUMB) ||
- (brush->mtex.brush_map_mode == MTEX_MAP_MODE_AREA)) ||
- sculpt_brush_use_topology_rake(ss, brush);
+ (brush->mtex.brush_map_mode == MTEX_MAP_MODE_AREA)) ||
+ sculpt_brush_use_topology_rake(ss, brush);
}
/** \} */
static bool sculpt_brush_needs_rake_rotation(const Brush *brush)
{
- return SCULPT_TOOL_HAS_RAKE(brush->sculpt_tool) && (brush->rake_factor != 0.0f);
+ return SCULPT_TOOL_HAS_RAKE(brush->sculpt_tool) && (brush->rake_factor != 0.0f);
}
typedef enum StrokeFlags {
- CLIP_X = 1,
- CLIP_Y = 2,
- CLIP_Z = 4,
+ CLIP_X = 1,
+ CLIP_Y = 2,
+ CLIP_Z = 4,
} StrokeFlags;
/************** Access to original unmodified vertex data *************/
typedef struct {
- BMLog *bm_log;
+ BMLog *bm_log;
- SculptUndoNode *unode;
- float (*coords)[3];
- short (*normals)[3];
- const float *vmasks;
+ SculptUndoNode *unode;
+ float (*coords)[3];
+ short (*normals)[3];
+ const float *vmasks;
- /* Original coordinate, normal, and mask */
- const float *co;
- const short *no;
- float mask;
+ /* Original coordinate, normal, and mask */
+ const float *co;
+ const short *no;
+ float mask;
} SculptOrigVertData;
-
/* Initialize a SculptOrigVertData for accessing original vertex data;
* handles BMesh, mesh, and multires */
static void sculpt_orig_vert_data_unode_init(SculptOrigVertData *data,
Object *ob,
SculptUndoNode *unode)
{
- SculptSession *ss = ob->sculpt;
- BMesh *bm = ss->bm;
+ SculptSession *ss = ob->sculpt;
+ BMesh *bm = ss->bm;
- memset(data, 0, sizeof(*data));
- data->unode = unode;
+ memset(data, 0, sizeof(*data));
+ data->unode = unode;
- if (bm) {
- data->bm_log = ss->bm_log;
- }
- else {
- data->coords = data->unode->co;
- data->normals = data->unode->no;
- data->vmasks = data->unode->mask;
- }
+ if (bm) {
+ data->bm_log = ss->bm_log;
+ }
+ else {
+ data->coords = data->unode->co;
+ data->normals = data->unode->no;
+ data->vmasks = data->unode->mask;
+ }
}
/* Initialize a SculptOrigVertData for accessing original vertex data;
* handles BMesh, mesh, and multires */
-static void sculpt_orig_vert_data_init(SculptOrigVertData *data,
- Object *ob,
- PBVHNode *node)
+static void sculpt_orig_vert_data_init(SculptOrigVertData *data, Object *ob, PBVHNode *node)
{
- SculptUndoNode *unode;
- unode = sculpt_undo_push_node(ob, node, SCULPT_UNDO_COORDS);
- sculpt_orig_vert_data_unode_init(data, ob, unode);
+ SculptUndoNode *unode;
+ unode = sculpt_undo_push_node(ob, node, SCULPT_UNDO_COORDS);
+ sculpt_orig_vert_data_unode_init(data, ob, unode);
}
/* Update a SculptOrigVertData for a particular vertex from the PBVH
* iterator */
-static void sculpt_orig_vert_data_update(SculptOrigVertData *orig_data,
- PBVHVertexIter *iter)
-{
- if (orig_data->unode->type == SCULPT_UNDO_COORDS) {
- if (orig_data->bm_log) {
- BM_log_original_vert_data(
- orig_data->bm_log, iter->bm_vert,
- &orig_data->co, &orig_data->no);
- }
- else {
- orig_data->co = orig_data->coords[iter->i];
- orig_data->no = orig_data->normals[iter->i];
- }
- }
- else if (orig_data->unode->type == SCULPT_UNDO_MASK) {
- if (orig_data->bm_log) {
- orig_data->mask = BM_log_original_mask(orig_data->bm_log, iter->bm_vert);
- }
- else {
- orig_data->mask = orig_data->vmasks[iter->i];
- }
- }
+static void sculpt_orig_vert_data_update(SculptOrigVertData *orig_data, PBVHVertexIter *iter)
+{
+ if (orig_data->unode->type == SCULPT_UNDO_COORDS) {
+ if (orig_data->bm_log) {
+ BM_log_original_vert_data(orig_data->bm_log, iter->bm_vert, &orig_data->co, &orig_data->no);
+ }
+ else {
+ orig_data->co = orig_data->coords[iter->i];
+ orig_data->no = orig_data->normals[iter->i];
+ }
+ }
+ else if (orig_data->unode->type == SCULPT_UNDO_MASK) {
+ if (orig_data->bm_log) {
+ orig_data->mask = BM_log_original_mask(orig_data->bm_log, iter->bm_vert);
+ }
+ else {
+ orig_data->mask = orig_data->vmasks[iter->i];
+ }
+ }
}
static void sculpt_rake_data_update(struct SculptRakeData *srd, const float co[3])
{
- float rake_dist = len_v3v3(srd->follow_co, co);
- if (rake_dist > srd->follow_dist) {
- interp_v3_v3v3(srd->follow_co, srd->follow_co, co, rake_dist - srd->follow_dist);
- }
+ float rake_dist = len_v3v3(srd->follow_co, co);
+ if (rake_dist > srd->follow_dist) {
+ interp_v3_v3v3(srd->follow_co, srd->follow_co, co, rake_dist - srd->follow_dist);
+ }
}
-
-static void sculpt_rake_rotate(
- const SculptSession *ss, const float sculpt_co[3], const float v_co[3], float factor, float r_delta[3])
+static void sculpt_rake_rotate(const SculptSession *ss,
+ const float sculpt_co[3],
+ const float v_co[3],
+ float factor,
+ float r_delta[3])
{
- float vec_rot[3];
+ float vec_rot[3];
#if 0
- /* lerp */
- sub_v3_v3v3(vec_rot, v_co, sculpt_co);
- mul_qt_v3(ss->cache->rake_rotation_symmetry, vec_rot);
- add_v3_v3(vec_rot, sculpt_co);
- sub_v3_v3v3(r_delta, vec_rot, v_co);
- mul_v3_fl(r_delta, factor);
+ /* lerp */
+ sub_v3_v3v3(vec_rot, v_co, sculpt_co);
+ mul_qt_v3(ss->cache->rake_rotation_symmetry, vec_rot);
+ add_v3_v3(vec_rot, sculpt_co);
+ sub_v3_v3v3(r_delta, vec_rot, v_co);
+ mul_v3_fl(r_delta, factor);
#else
- /* slerp */
- float q_interp[4];
- sub_v3_v3v3(vec_rot, v_co, sculpt_co);
+ /* slerp */
+ float q_interp[4];
+ sub_v3_v3v3(vec_rot, v_co, sculpt_co);
- copy_qt_qt(q_interp, ss->cache->rake_rotation_symmetry);
- pow_qt_fl_normalized(q_interp, factor);
- mul_qt_v3(q_interp, vec_rot);
+ copy_qt_qt(q_interp, ss->cache->rake_rotation_symmetry);
+ pow_qt_fl_normalized(q_interp, factor);
+ mul_qt_v3(q_interp, vec_rot);
- add_v3_v3(vec_rot, sculpt_co);
- sub_v3_v3v3(r_delta, vec_rot, v_co);
+ add_v3_v3(vec_rot, sculpt_co);
+ sub_v3_v3v3(r_delta, vec_rot, v_co);
#endif
-
}
/**
@@ -292,26 +278,29 @@ static void sculpt_rake_rotate(
*
* \param grab_delta: Typically from `ss->cache->grab_delta_symmetry`.
*/
-static void sculpt_project_v3_normal_align(SculptSession *ss, const float normal_weight, float grab_delta[3])
+static void sculpt_project_v3_normal_align(SculptSession *ss,
+ const float normal_weight,
+ float grab_delta[3])
{
- /* signed to support grabbing in (to make a hole) as well as out. */
- const float len_signed = dot_v3v3(ss->cache->sculpt_normal_symm, grab_delta);
+ /* signed to support grabbing in (to make a hole) as well as out. */
+ const float len_signed = dot_v3v3(ss->cache->sculpt_normal_symm, grab_delta);
- /* this scale effectively projects the offset so dragging follows the cursor,
- * as the normal points towards the view, the scale increases. */
- float len_view_scale;
- {
- float view_aligned_normal[3];
- project_plane_v3_v3v3(view_aligned_normal, ss->cache->sculpt_normal_symm, ss->cache->view_normal);
- len_view_scale = fabsf(dot_v3v3(view_aligned_normal, ss->cache->sculpt_normal_symm));
- len_view_scale = (len_view_scale > FLT_EPSILON) ? 1.0f / len_view_scale : 1.0f;
- }
+ /* this scale effectively projects the offset so dragging follows the cursor,
+ * as the normal points towards the view, the scale increases. */
+ float len_view_scale;
+ {
+ float view_aligned_normal[3];
+ project_plane_v3_v3v3(
+ view_aligned_normal, ss->cache->sculpt_normal_symm, ss->cache->view_normal);
+ len_view_scale = fabsf(dot_v3v3(view_aligned_normal, ss->cache->sculpt_normal_symm));
+ len_view_scale = (len_view_scale > FLT_EPSILON) ? 1.0f / len_view_scale : 1.0f;
+ }
- mul_v3_fl(grab_delta, 1.0f - normal_weight);
- madd_v3_v3fl(grab_delta, ss->cache->sculpt_normal_symm, (len_signed * normal_weight) * len_view_scale);
+ mul_v3_fl(grab_delta, 1.0f - normal_weight);
+ madd_v3_v3fl(
+ grab_delta, ss->cache->sculpt_normal_symm, (len_signed * normal_weight) * len_view_scale);
}
-
/** \name SculptProjectVector
*
* Fast-path for #project_plane_v3_v3v3
@@ -319,43 +308,39 @@ static void sculpt_project_v3_normal_align(SculptSession *ss, const float normal
* \{ */
typedef struct SculptProjectVector {
- float plane[3];
- float len_sq;
- float len_sq_inv_neg;
- bool is_valid;
+ float plane[3];
+ float len_sq;
+ float len_sq_inv_neg;
+ bool is_valid;
} SculptProjectVector;
/**
* \param plane: Direction, can be any length.
*/
-static void sculpt_project_v3_cache_init(
- SculptProjectVector *spvc, const float plane[3])
+static void sculpt_project_v3_cache_init(SculptProjectVector *spvc, const float plane[3])
{
- copy_v3_v3(spvc->plane, plane);
- spvc->len_sq = len_squared_v3(spvc->plane);
- spvc->is_valid = (spvc->len_sq > FLT_EPSILON);
- spvc->len_sq_inv_neg = (spvc->is_valid) ? -1.0f / spvc->len_sq : 0.0f;
+ copy_v3_v3(spvc->plane, plane);
+ spvc->len_sq = len_squared_v3(spvc->plane);
+ spvc->is_valid = (spvc->len_sq > FLT_EPSILON);
+ spvc->len_sq_inv_neg = (spvc->is_valid) ? -1.0f / spvc->len_sq : 0.0f;
}
/**
* Calculate the projection.
*/
-static void sculpt_project_v3(
- const SculptProjectVector *spvc, const float vec[3],
- float r_vec[3])
+static void sculpt_project_v3(const SculptProjectVector *spvc, const float vec[3], float r_vec[3])
{
#if 0
- project_plane_v3_v3v3(r_vec, vec, spvc->plane);
+ project_plane_v3_v3v3(r_vec, vec, spvc->plane);
#else
- /* inline the projection, cache `-1.0 / dot_v3_v3(v_proj, v_proj)` */
- madd_v3_v3fl(r_vec, spvc->plane, dot_v3v3(vec, spvc->plane) * spvc->len_sq_inv_neg);
+ /* inline the projection, cache `-1.0 / dot_v3_v3(v_proj, v_proj)` */
+ madd_v3_v3fl(r_vec, spvc->plane, dot_v3v3(vec, spvc->plane) * spvc->len_sq_inv_neg);
#endif
}
/** \} */
-
/**********************************************************************/
/* Returns true if the stroke will use dynamic topology, false
@@ -364,360 +349,351 @@ static void sculpt_project_v3(
* Factors: some brushes like grab cannot do dynamic topology.
* Others, like smooth, are better without. Same goes for alt-
* key smoothing. */
-static bool sculpt_stroke_is_dynamic_topology(
- const SculptSession *ss, const Brush *brush)
+static bool sculpt_stroke_is_dynamic_topology(const SculptSession *ss, const Brush *brush)
{
- return ((BKE_pbvh_type(ss->pbvh) == PBVH_BMESH) &&
+ return ((BKE_pbvh_type(ss->pbvh) == PBVH_BMESH) &&
- (!ss->cache || (!ss->cache->alt_smooth)) &&
+ (!ss->cache || (!ss->cache->alt_smooth)) &&
- /* Requires mesh restore, which doesn't work with
- * dynamic-topology */
- !(brush->flag & BRUSH_ANCHORED) &&
- !(brush->flag & BRUSH_DRAG_DOT) &&
+ /* Requires mesh restore, which doesn't work with
+ * dynamic-topology */
+ !(brush->flag & BRUSH_ANCHORED) && !(brush->flag & BRUSH_DRAG_DOT) &&
- SCULPT_TOOL_HAS_DYNTOPO(brush->sculpt_tool));
+ SCULPT_TOOL_HAS_DYNTOPO(brush->sculpt_tool));
}
/*** paint mesh ***/
-static void paint_mesh_restore_co_task_cb(
- void *__restrict userdata,
- const int n,
- const ParallelRangeTLS *__restrict UNUSED(tls))
+static void paint_mesh_restore_co_task_cb(void *__restrict userdata,
+ const int n,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
- SculptUndoNode *unode;
- SculptUndoType type = (data->brush->sculpt_tool == SCULPT_TOOL_MASK ? SCULPT_UNDO_MASK : SCULPT_UNDO_COORDS);
+ SculptUndoNode *unode;
+ SculptUndoType type = (data->brush->sculpt_tool == SCULPT_TOOL_MASK ? SCULPT_UNDO_MASK :
+ SCULPT_UNDO_COORDS);
- if (ss->bm) {
- unode = sculpt_undo_push_node(data->ob, data->nodes[n], type);
- }
- else {
- unode = sculpt_undo_get_node(data->nodes[n]);
- }
+ if (ss->bm) {
+ unode = sculpt_undo_push_node(data->ob, data->nodes[n], type);
+ }
+ else {
+ unode = sculpt_undo_get_node(data->nodes[n]);
+ }
- if (unode) {
- PBVHVertexIter vd;
- SculptOrigVertData orig_data;
+ if (unode) {
+ PBVHVertexIter vd;
+ SculptOrigVertData orig_data;
- sculpt_orig_vert_data_unode_init(&orig_data, data->ob, unode);
+ sculpt_orig_vert_data_unode_init(&orig_data, data->ob, unode);
- BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
- {
- sculpt_orig_vert_data_update(&orig_data, &vd);
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
+ {
+ sculpt_orig_vert_data_update(&orig_data, &vd);
- if (orig_data.unode->type == SCULPT_UNDO_COORDS) {
- copy_v3_v3(vd.co, orig_data.co);
- if (vd.no)
- copy_v3_v3_short(vd.no, orig_data.no);
- else
- normal_short_to_float_v3(vd.fno, orig_data.no);
- }
- else if (orig_data.unode->type == SCULPT_UNDO_MASK) {
- *vd.mask = orig_data.mask;
- }
+ if (orig_data.unode->type == SCULPT_UNDO_COORDS) {
+ copy_v3_v3(vd.co, orig_data.co);
+ if (vd.no)
+ copy_v3_v3_short(vd.no, orig_data.no);
+ else
+ normal_short_to_float_v3(vd.fno, orig_data.no);
+ }
+ else if (orig_data.unode->type == SCULPT_UNDO_MASK) {
+ *vd.mask = orig_data.mask;
+ }
- if (vd.mvert)
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- BKE_pbvh_vertex_iter_end;
+ if (vd.mvert)
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ BKE_pbvh_vertex_iter_end;
- BKE_pbvh_node_mark_update(data->nodes[n]);
- }
+ BKE_pbvh_node_mark_update(data->nodes[n]);
+ }
}
static void paint_mesh_restore_co(Sculpt *sd, Object *ob)
{
- SculptSession *ss = ob->sculpt;
- Brush *brush = BKE_paint_brush(&sd->paint);
+ SculptSession *ss = ob->sculpt;
+ Brush *brush = BKE_paint_brush(&sd->paint);
- PBVHNode **nodes;
- int totnode;
+ PBVHNode **nodes;
+ int totnode;
- BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode);
+ BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode);
- /* Disable OpenMP when dynamic-topology is enabled. Otherwise, new entries might be inserted by
- * sculpt_undo_push_node() into the GHash used internally by BM_log_original_vert_co() by a different thread.
- * See T33787. */
- SculptThreadedTaskData data = {
- .sd = sd, .ob = ob, .brush = brush, .nodes = nodes,
- };
+ /* Disable OpenMP when dynamic-topology is enabled. Otherwise, new entries might be inserted by
+ * sculpt_undo_push_node() into the GHash used internally by BM_log_original_vert_co() by a different thread.
+ * See T33787. */
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ };
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && !ss->bm && totnode > SCULPT_THREADED_LIMIT);
- BLI_task_parallel_range(
- 0, totnode,
- &data,
- paint_mesh_restore_co_task_cb,
- &settings);
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && !ss->bm &&
+ totnode > SCULPT_THREADED_LIMIT);
+ BLI_task_parallel_range(0, totnode, &data, paint_mesh_restore_co_task_cb, &settings);
- if (nodes)
- MEM_freeN(nodes);
+ if (nodes)
+ MEM_freeN(nodes);
}
/*** BVH Tree ***/
static void sculpt_extend_redraw_rect_previous(Object *ob, rcti *rect)
{
- /* expand redraw rect with redraw rect from previous step to
- * prevent partial-redraw issues caused by fast strokes. This is
- * needed here (not in sculpt_flush_update) as it was before
- * because redraw rectangle should be the same in both of
- * optimized PBVH draw function and 3d view redraw (if not -- some
- * mesh parts could disappear from screen (sergey) */
- SculptSession *ss = ob->sculpt;
+ /* expand redraw rect with redraw rect from previous step to
+ * prevent partial-redraw issues caused by fast strokes. This is
+ * needed here (not in sculpt_flush_update) as it was before
+ * because redraw rectangle should be the same in both of
+ * optimized PBVH draw function and 3d view redraw (if not -- some
+ * mesh parts could disappear from screen (sergey) */
+ SculptSession *ss = ob->sculpt;
- if (ss->cache) {
- if (!BLI_rcti_is_empty(&ss->cache->previous_r))
- BLI_rcti_union(rect, &ss->cache->previous_r);
- }
+ if (ss->cache) {
+ if (!BLI_rcti_is_empty(&ss->cache->previous_r))
+ BLI_rcti_union(rect, &ss->cache->previous_r);
+ }
}
/* Get a screen-space rectangle of the modified area */
-bool sculpt_get_redraw_rect(ARegion *ar, RegionView3D *rv3d,
- Object *ob, rcti *rect)
+bool sculpt_get_redraw_rect(ARegion *ar, RegionView3D *rv3d, Object *ob, rcti *rect)
{
- PBVH *pbvh = ob->sculpt->pbvh;
- float bb_min[3], bb_max[3];
+ PBVH *pbvh = ob->sculpt->pbvh;
+ float bb_min[3], bb_max[3];
- if (!pbvh)
- return 0;
+ if (!pbvh)
+ return 0;
- BKE_pbvh_redraw_BB(pbvh, bb_min, bb_max);
+ BKE_pbvh_redraw_BB(pbvh, bb_min, bb_max);
- /* convert 3D bounding box to screen space */
- if (!paint_convert_bb_to_rect(rect,
- bb_min,
- bb_max,
- ar,
- rv3d,
- ob))
- {
- return 0;
- }
+ /* convert 3D bounding box to screen space */
+ if (!paint_convert_bb_to_rect(rect, bb_min, bb_max, ar, rv3d, ob)) {
+ return 0;
+ }
-
- return 1;
+ return 1;
}
void ED_sculpt_redraw_planes_get(float planes[4][4], ARegion *ar, Object *ob)
{
- PBVH *pbvh = ob->sculpt->pbvh;
- /* copy here, original will be used below */
- rcti rect = ob->sculpt->cache->current_r;
+ PBVH *pbvh = ob->sculpt->pbvh;
+ /* copy here, original will be used below */
+ rcti rect = ob->sculpt->cache->current_r;
- sculpt_extend_redraw_rect_previous(ob, &rect);
+ sculpt_extend_redraw_rect_previous(ob, &rect);
- paint_calc_redraw_planes(planes, ar, ob, &rect);
+ paint_calc_redraw_planes(planes, ar, ob, &rect);
- /* we will draw this rect, so now we can set it as the previous partial rect.
- * Note that we don't update with the union of previous/current (rect), only with
- * the current. Thus we avoid the rectangle needlessly growing to include
- * all the stroke area */
- ob->sculpt->cache->previous_r = ob->sculpt->cache->current_r;
+ /* we will draw this rect, so now we can set it as the previous partial rect.
+ * Note that we don't update with the union of previous/current (rect), only with
+ * the current. Thus we avoid the rectangle needlessly growing to include
+ * all the stroke area */
+ ob->sculpt->cache->previous_r = ob->sculpt->cache->current_r;
- /* clear redraw flag from nodes */
- if (pbvh)
- BKE_pbvh_update(pbvh, PBVH_UpdateRedraw, NULL);
+ /* clear redraw flag from nodes */
+ if (pbvh)
+ BKE_pbvh_update(pbvh, PBVH_UpdateRedraw, NULL);
}
/************************ Brush Testing *******************/
void sculpt_brush_test_init(SculptSession *ss, SculptBrushTest *test)
{
- RegionView3D *rv3d = ss->cache->vc->rv3d;
+ RegionView3D *rv3d = ss->cache->vc->rv3d;
- test->radius_squared = ss->cache->radius_squared;
- copy_v3_v3(test->location, ss->cache->location);
- test->dist = 0.0f; /* just for initialize */
+ test->radius_squared = ss->cache->radius_squared;
+ copy_v3_v3(test->location, ss->cache->location);
+ test->dist = 0.0f; /* just for initialize */
- /* Only for 2D projection. */
- zero_v4(test->plane_view);
- zero_v4(test->plane_tool);
+ /* Only for 2D projection. */
+ zero_v4(test->plane_view);
+ zero_v4(test->plane_tool);
- test->mirror_symmetry_pass = ss->cache->mirror_symmetry_pass;
+ test->mirror_symmetry_pass = ss->cache->mirror_symmetry_pass;
- if (rv3d->rflag & RV3D_CLIPPING) {
- test->clip_rv3d = rv3d;
- }
- else {
- test->clip_rv3d = NULL;
- }
+ if (rv3d->rflag & RV3D_CLIPPING) {
+ test->clip_rv3d = rv3d;
+ }
+ else {
+ test->clip_rv3d = NULL;
+ }
}
BLI_INLINE bool sculpt_brush_test_clipping(const SculptBrushTest *test, const float co[3])
{
- RegionView3D *rv3d = test->clip_rv3d;
- if (!rv3d) {
- return false;
- }
- float symm_co[3];
- flip_v3_v3(symm_co, co, test->mirror_symmetry_pass);
- return ED_view3d_clipping_test(rv3d, symm_co, true);
+ RegionView3D *rv3d = test->clip_rv3d;
+ if (!rv3d) {
+ return false;
+ }
+ float symm_co[3];
+ flip_v3_v3(symm_co, co, test->mirror_symmetry_pass);
+ return ED_view3d_clipping_test(rv3d, symm_co, true);
}
bool sculpt_brush_test_sphere(SculptBrushTest *test, const float co[3])
{
- float distsq = len_squared_v3v3(co, test->location);
+ float distsq = len_squared_v3v3(co, test->location);
- if (distsq <= test->radius_squared) {
- if (sculpt_brush_test_clipping(test, co)) {
- return 0;
- }
- test->dist = sqrtf(distsq);
- return 1;
- }
- else {
- return 0;
- }
+ if (distsq <= test->radius_squared) {
+ if (sculpt_brush_test_clipping(test, co)) {
+ return 0;
+ }
+ test->dist = sqrtf(distsq);
+ return 1;
+ }
+ else {
+ return 0;
+ }
}
bool sculpt_brush_test_sphere_sq(SculptBrushTest *test, const float co[3])
{
- float distsq = len_squared_v3v3(co, test->location);
+ float distsq = len_squared_v3v3(co, test->location);
- if (distsq <= test->radius_squared) {
- if (sculpt_brush_test_clipping(test, co)) {
- return 0;
- }
- test->dist = distsq;
- return 1;
- }
- else {
- return 0;
- }
+ if (distsq <= test->radius_squared) {
+ if (sculpt_brush_test_clipping(test, co)) {
+ return 0;
+ }
+ test->dist = distsq;
+ return 1;
+ }
+ else {
+ return 0;
+ }
}
bool sculpt_brush_test_sphere_fast(const SculptBrushTest *test, const float co[3])
{
- if (sculpt_brush_test_clipping(test, co)) {
- return 0;
- }
- return len_squared_v3v3(co, test->location) <= test->radius_squared;
+ if (sculpt_brush_test_clipping(test, co)) {
+ return 0;
+ }
+ return len_squared_v3v3(co, test->location) <= test->radius_squared;
}
bool sculpt_brush_test_circle_sq(SculptBrushTest *test, const float co[3])
{
- float co_proj[3];
- closest_to_plane_normalized_v3(co_proj, test->plane_view, co);
- float distsq = len_squared_v3v3(co_proj, test->location);
+ float co_proj[3];
+ closest_to_plane_normalized_v3(co_proj, test->plane_view, co);
+ float distsq = len_squared_v3v3(co_proj, test->location);
- if (distsq <= test->radius_squared) {
- if (sculpt_brush_test_clipping(test, co)) {
- return 0;
- }
- test->dist = distsq;
- return 1;
- }
- else {
- return 0;
- }
+ if (distsq <= test->radius_squared) {
+ if (sculpt_brush_test_clipping(test, co)) {
+ return 0;
+ }
+ test->dist = distsq;
+ return 1;
+ }
+ else {
+ return 0;
+ }
}
bool sculpt_brush_test_cube(SculptBrushTest *test, const float co[3], float local[4][4])
{
- float side = M_SQRT1_2;
- float local_co[3];
+ float side = M_SQRT1_2;
+ float local_co[3];
- if (sculpt_brush_test_clipping(test, co)) {
- return 0;
- }
+ if (sculpt_brush_test_clipping(test, co)) {
+ return 0;
+ }
- mul_v3_m4v3(local_co, local, co);
+ mul_v3_m4v3(local_co, local, co);
- local_co[0] = fabsf(local_co[0]);
- local_co[1] = fabsf(local_co[1]);
- local_co[2] = fabsf(local_co[2]);
+ local_co[0] = fabsf(local_co[0]);
+ local_co[1] = fabsf(local_co[1]);
+ local_co[2] = fabsf(local_co[2]);
- if (local_co[0] <= side && local_co[1] <= side && local_co[2] <= side) {
- float p = 4.0f;
+ if (local_co[0] <= side && local_co[1] <= side && local_co[2] <= side) {
+ float p = 4.0f;
- test->dist = ((powf(local_co[0], p) +
- powf(local_co[1], p) +
- powf(local_co[2], p)) / powf(side, p));
+ test->dist = ((powf(local_co[0], p) + powf(local_co[1], p) + powf(local_co[2], p)) /
+ powf(side, p));
- return 1;
- }
- else {
- return 0;
- }
+ return 1;
+ }
+ else {
+ return 0;
+ }
}
-SculptBrushTestFn sculpt_brush_test_init_with_falloff_shape(
- SculptSession *ss, SculptBrushTest *test, char falloff_shape)
+SculptBrushTestFn sculpt_brush_test_init_with_falloff_shape(SculptSession *ss,
+ SculptBrushTest *test,
+ char falloff_shape)
{
- 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;
- }
- 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;
- }
- return sculpt_brush_test_sq_fn;
+ 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;
+ }
+ 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;
+ }
+ return sculpt_brush_test_sq_fn;
}
-const float *sculpt_brush_frontface_normal_from_falloff_shape(
- SculptSession *ss, char falloff_shape)
+const float *sculpt_brush_frontface_normal_from_falloff_shape(SculptSession *ss,
+ char falloff_shape)
{
- if (falloff_shape == PAINT_FALLOFF_SHAPE_SPHERE) {
- return ss->cache->sculpt_normal_symm;
- }
- else {
- /* PAINT_FALLOFF_SHAPE_TUBE */
- return ss->cache->view_normal;
- }
+ if (falloff_shape == PAINT_FALLOFF_SHAPE_SPHERE) {
+ return ss->cache->sculpt_normal_symm;
+ }
+ else {
+ /* PAINT_FALLOFF_SHAPE_TUBE */
+ return ss->cache->view_normal;
+ }
}
-
-static float frontface(const Brush *br, const float sculpt_normal[3],
- const short no[3], const float fno[3])
+static float frontface(const Brush *br,
+ const float sculpt_normal[3],
+ const short no[3],
+ const float fno[3])
{
- if (br->flag & BRUSH_FRONTFACE) {
- float dot;
+ if (br->flag & BRUSH_FRONTFACE) {
+ float dot;
- if (no) {
- float tmp[3];
+ if (no) {
+ float tmp[3];
- normal_short_to_float_v3(tmp, no);
- dot = dot_v3v3(tmp, sculpt_normal);
- }
- else {
- dot = dot_v3v3(fno, sculpt_normal);
- }
- return dot > 0 ? dot : 0;
- }
- else {
- return 1;
- }
+ normal_short_to_float_v3(tmp, no);
+ dot = dot_v3v3(tmp, sculpt_normal);
+ }
+ else {
+ dot = dot_v3v3(fno, sculpt_normal);
+ }
+ return dot > 0 ? dot : 0;
+ }
+ else {
+ return 1;
+ }
}
#if 0
static bool sculpt_brush_test_cyl(SculptBrushTest *test, float co[3], float location[3], const float area_no[3])
{
- if (sculpt_brush_test_sphere_fast(test, co)) {
- float t1[3], t2[3], t3[3], dist;
+ if (sculpt_brush_test_sphere_fast(test, co)) {
+ float t1[3], t2[3], t3[3], dist;
- sub_v3_v3v3(t1, location, co);
- sub_v3_v3v3(t2, x2, location);
+ sub_v3_v3v3(t1, location, co);
+ sub_v3_v3v3(t2, x2, location);
- cross_v3_v3v3(t3, area_no, t1);
+ cross_v3_v3v3(t3, area_no, t1);
- dist = len_v3(t3) / len_v3(t2);
+ dist = len_v3(t3) / len_v3(t2);
- test->dist = dist;
+ test->dist = dist;
- return 1;
- }
+ return 1;
+ }
- return 0;
+ return 0;
}
#endif
@@ -726,70 +702,73 @@ static bool sculpt_brush_test_cyl(SculptBrushTest *test, float co[3], float loca
*/
static void flip_v3(float v[3], const char symm)
{
- flip_v3_v3(v, v, symm);
+ flip_v3_v3(v, v, symm);
}
static float calc_overlap(StrokeCache *cache, const char symm, const char axis, const float angle)
{
- float mirror[3];
- float distsq;
+ float mirror[3];
+ float distsq;
- /* flip_v3_v3(mirror, cache->traced_location, symm); */
- flip_v3_v3(mirror, cache->true_location, symm);
+ /* flip_v3_v3(mirror, cache->traced_location, symm); */
+ flip_v3_v3(mirror, cache->true_location, symm);
- if (axis != 0) {
- float mat[3][3];
- axis_angle_to_mat3_single(mat, axis, angle);
- mul_m3_v3(mat, mirror);
- }
+ if (axis != 0) {
+ float mat[3][3];
+ axis_angle_to_mat3_single(mat, axis, angle);
+ mul_m3_v3(mat, mirror);
+ }
- /* distsq = len_squared_v3v3(mirror, cache->traced_location); */
- distsq = len_squared_v3v3(mirror, cache->true_location);
+ /* distsq = len_squared_v3v3(mirror, cache->traced_location); */
+ distsq = len_squared_v3v3(mirror, cache->true_location);
- if (distsq <= 4.0f * (cache->radius_squared))
- return (2.0f * (cache->radius) - sqrtf(distsq)) / (2.0f * (cache->radius));
- else
- return 0;
+ if (distsq <= 4.0f * (cache->radius_squared))
+ return (2.0f * (cache->radius) - sqrtf(distsq)) / (2.0f * (cache->radius));
+ else
+ return 0;
}
-static float calc_radial_symmetry_feather(Sculpt *sd, StrokeCache *cache, const char symm, const char axis)
+static float calc_radial_symmetry_feather(Sculpt *sd,
+ StrokeCache *cache,
+ const char symm,
+ const char axis)
{
- int i;
- float overlap;
+ int i;
+ float overlap;
- overlap = 0;
- for (i = 1; i < sd->radial_symm[axis - 'X']; ++i) {
- const float angle = 2 * M_PI * i / sd->radial_symm[axis - 'X'];
- overlap += calc_overlap(cache, symm, axis, angle);
- }
+ overlap = 0;
+ for (i = 1; i < sd->radial_symm[axis - 'X']; ++i) {
+ const float angle = 2 * M_PI * i / sd->radial_symm[axis - 'X'];
+ overlap += calc_overlap(cache, symm, axis, angle);
+ }
- return overlap;
+ return overlap;
}
static float calc_symmetry_feather(Sculpt *sd, StrokeCache *cache)
{
- if (sd->paint.symmetry_flags & PAINT_SYMMETRY_FEATHER) {
- float overlap;
- int symm = cache->symmetry;
- int i;
+ if (sd->paint.symmetry_flags & PAINT_SYMMETRY_FEATHER) {
+ float overlap;
+ int symm = cache->symmetry;
+ int i;
- overlap = 0;
- for (i = 0; i <= symm; i++) {
- if (i == 0 || (symm & i && (symm != 5 || i != 3) && (symm != 6 || (i != 3 && i != 5)))) {
+ overlap = 0;
+ for (i = 0; i <= symm; i++) {
+ if (i == 0 || (symm & i && (symm != 5 || i != 3) && (symm != 6 || (i != 3 && i != 5)))) {
- overlap += calc_overlap(cache, i, 0, 0);
+ overlap += calc_overlap(cache, i, 0, 0);
- overlap += calc_radial_symmetry_feather(sd, cache, i, 'X');
- overlap += calc_radial_symmetry_feather(sd, cache, i, 'Y');
- overlap += calc_radial_symmetry_feather(sd, cache, i, 'Z');
- }
- }
+ overlap += calc_radial_symmetry_feather(sd, cache, i, 'X');
+ overlap += calc_radial_symmetry_feather(sd, cache, i, 'Y');
+ overlap += calc_radial_symmetry_feather(sd, cache, i, 'Z');
+ }
+ }
- return 1 / overlap;
- }
- else {
- return 1;
- }
+ return 1 / overlap;
+ }
+ else {
+ return 1;
+ }
}
/** \name Calculate Normal and Center
@@ -805,393 +784,395 @@ static float calc_symmetry_feather(Sculpt *sd, StrokeCache *cache)
* \note These are all _very_ similar, when changing one, check others.
* \{ */
-static void calc_area_normal_and_center_task_cb(
- void *__restrict userdata,
- const int n,
- const ParallelRangeTLS *__restrict UNUSED(tls))
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- float (*area_nos)[3] = data->area_nos;
- float (*area_cos)[3] = data->area_cos;
-
- PBVHVertexIter vd;
- SculptUndoNode *unode = NULL;
-
- float private_co[2][3] = {{0.0f}};
- float private_no[2][3] = {{0.0f}};
- int private_count[2] = {0};
- bool use_original = false;
-
- if (ss->cache->original) {
- unode = sculpt_undo_push_node(data->ob, data->nodes[n], SCULPT_UNDO_COORDS);
- use_original = (unode->co || unode->bm_entry);
- }
-
- SculptBrushTest test;
- SculptBrushTestFn sculpt_brush_test_sq_fn =
- sculpt_brush_test_init_with_falloff_shape(ss, &test, data->brush->falloff_shape);
-
-
- /* when the mesh is edited we can't rely on original coords
- * (original mesh may not even have verts in brush radius) */
- if (use_original && data->has_bm_orco) {
- float (*orco_coords)[3];
- int (*orco_tris)[3];
- int orco_tris_num;
- int i;
-
- BKE_pbvh_node_get_bm_orco_data(data->nodes[n], &orco_tris, &orco_tris_num, &orco_coords);
-
- for (i = 0; i < orco_tris_num; i++) {
- const float *co_tri[3] = {
- orco_coords[orco_tris[i][0]],
- orco_coords[orco_tris[i][1]],
- orco_coords[orco_tris[i][2]],
- };
- float co[3];
-
- closest_on_tri_to_point_v3(co, test.location, UNPACK3(co_tri));
-
- if (sculpt_brush_test_sq_fn(&test, co)) {
- float no[3];
- int flip_index;
-
- normal_tri_v3(no, UNPACK3(co_tri));
-
- flip_index = (dot_v3v3(ss->cache->view_normal, no) <= 0.0f);
- if (area_cos)
- add_v3_v3(private_co[flip_index], co);
- if (area_nos)
- add_v3_v3(private_no[flip_index], no);
- private_count[flip_index] += 1;
- }
- }
- }
- else {
- BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
- {
- const float *co;
- const short *no_s; /* bm_vert only */
-
- if (use_original) {
- if (unode->bm_entry) {
- BM_log_original_vert_data(ss->bm_log, vd.bm_vert, &co, &no_s);
- }
- else {
- co = unode->co[vd.i];
- no_s = unode->no[vd.i];
- }
- }
- else {
- co = vd.co;
- }
-
- if (sculpt_brush_test_sq_fn(&test, co)) {
- float no_buf[3];
- const float *no;
- int flip_index;
-
- if (use_original) {
- normal_short_to_float_v3(no_buf, no_s);
- no = no_buf;
- }
- else {
- if (vd.no) {
- normal_short_to_float_v3(no_buf, vd.no);
- no = no_buf;
- }
- else {
- no = vd.fno;
- }
- }
-
- flip_index = (dot_v3v3(ss->cache->view_normal, no) <= 0.0f);
- if (area_cos)
- add_v3_v3(private_co[flip_index], co);
- if (area_nos)
- add_v3_v3(private_no[flip_index], no);
- private_count[flip_index] += 1;
- }
- }
- BKE_pbvh_vertex_iter_end;
- }
-
- BLI_mutex_lock(&data->mutex);
-
- /* for flatten center */
- if (area_cos) {
- add_v3_v3(area_cos[0], private_co[0]);
- add_v3_v3(area_cos[1], private_co[1]);
- }
-
- /* for area normal */
- if (area_nos) {
- add_v3_v3(area_nos[0], private_no[0]);
- add_v3_v3(area_nos[1], private_no[1]);
- }
-
- /* weights */
- data->count[0] += private_count[0];
- data->count[1] += private_count[1];
-
- BLI_mutex_unlock(&data->mutex);
+static void calc_area_normal_and_center_task_cb(void *__restrict userdata,
+ const int n,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ float(*area_nos)[3] = data->area_nos;
+ float(*area_cos)[3] = data->area_cos;
+
+ PBVHVertexIter vd;
+ SculptUndoNode *unode = NULL;
+
+ float private_co[2][3] = {{0.0f}};
+ float private_no[2][3] = {{0.0f}};
+ int private_count[2] = {0};
+ bool use_original = false;
+
+ if (ss->cache->original) {
+ unode = sculpt_undo_push_node(data->ob, data->nodes[n], SCULPT_UNDO_COORDS);
+ use_original = (unode->co || unode->bm_entry);
+ }
+
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = sculpt_brush_test_init_with_falloff_shape(
+ ss, &test, data->brush->falloff_shape);
+
+ /* when the mesh is edited we can't rely on original coords
+ * (original mesh may not even have verts in brush radius) */
+ if (use_original && data->has_bm_orco) {
+ float(*orco_coords)[3];
+ int(*orco_tris)[3];
+ int orco_tris_num;
+ int i;
+
+ BKE_pbvh_node_get_bm_orco_data(data->nodes[n], &orco_tris, &orco_tris_num, &orco_coords);
+
+ for (i = 0; i < orco_tris_num; i++) {
+ const float *co_tri[3] = {
+ orco_coords[orco_tris[i][0]],
+ orco_coords[orco_tris[i][1]],
+ orco_coords[orco_tris[i][2]],
+ };
+ float co[3];
+
+ closest_on_tri_to_point_v3(co, test.location, UNPACK3(co_tri));
+
+ if (sculpt_brush_test_sq_fn(&test, co)) {
+ float no[3];
+ int flip_index;
+
+ normal_tri_v3(no, UNPACK3(co_tri));
+
+ flip_index = (dot_v3v3(ss->cache->view_normal, no) <= 0.0f);
+ if (area_cos)
+ add_v3_v3(private_co[flip_index], co);
+ if (area_nos)
+ add_v3_v3(private_no[flip_index], no);
+ private_count[flip_index] += 1;
+ }
+ }
+ }
+ else {
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
+ {
+ const float *co;
+ const short *no_s; /* bm_vert only */
+
+ if (use_original) {
+ if (unode->bm_entry) {
+ BM_log_original_vert_data(ss->bm_log, vd.bm_vert, &co, &no_s);
+ }
+ else {
+ co = unode->co[vd.i];
+ no_s = unode->no[vd.i];
+ }
+ }
+ else {
+ co = vd.co;
+ }
+
+ if (sculpt_brush_test_sq_fn(&test, co)) {
+ float no_buf[3];
+ const float *no;
+ int flip_index;
+
+ if (use_original) {
+ normal_short_to_float_v3(no_buf, no_s);
+ no = no_buf;
+ }
+ else {
+ if (vd.no) {
+ normal_short_to_float_v3(no_buf, vd.no);
+ no = no_buf;
+ }
+ else {
+ no = vd.fno;
+ }
+ }
+
+ flip_index = (dot_v3v3(ss->cache->view_normal, no) <= 0.0f);
+ if (area_cos)
+ add_v3_v3(private_co[flip_index], co);
+ if (area_nos)
+ add_v3_v3(private_no[flip_index], no);
+ private_count[flip_index] += 1;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+ }
+
+ BLI_mutex_lock(&data->mutex);
+
+ /* for flatten center */
+ if (area_cos) {
+ add_v3_v3(area_cos[0], private_co[0]);
+ add_v3_v3(area_cos[1], private_co[1]);
+ }
+
+ /* for area normal */
+ if (area_nos) {
+ add_v3_v3(area_nos[0], private_no[0]);
+ add_v3_v3(area_nos[1], private_no[1]);
+ }
+
+ /* weights */
+ data->count[0] += private_count[0];
+ data->count[1] += private_count[1];
+
+ BLI_mutex_unlock(&data->mutex);
}
static void calc_area_center(
- Sculpt *sd, Object *ob,
- PBVHNode **nodes, int totnode,
- float r_area_co[3])
-{
- const Brush *brush = BKE_paint_brush(&sd->paint);
- SculptSession *ss = ob->sculpt;
- const bool has_bm_orco = ss->bm && sculpt_stroke_is_dynamic_topology(ss, brush);
- int n;
-
- /* 0=towards view, 1=flipped */
- float area_cos[2][3] = {{0.0f}};
-
- int count[2] = {0};
-
- /* Intentionally set 'sd' to NULL since we share logic with vertex paint. */
- SculptThreadedTaskData data = {
- .sd = NULL, .ob = ob, .brush = brush, .nodes = nodes, .totnode = totnode,
- .has_bm_orco = has_bm_orco, .area_cos = area_cos, .area_nos = NULL, .count = count,
- };
- BLI_mutex_init(&data.mutex);
-
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
- BLI_task_parallel_range(
- 0, totnode,
- &data,
- calc_area_normal_and_center_task_cb,
- &settings);
-
- BLI_mutex_end(&data.mutex);
-
- /* for flatten center */
- for (n = 0; n < ARRAY_SIZE(area_cos); n++) {
- if (count[n] != 0) {
- mul_v3_v3fl(r_area_co, area_cos[n], 1.0f / count[n]);
- break;
- }
- }
- if (n == 2) {
- zero_v3(r_area_co);
- }
+ Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, float r_area_co[3])
+{
+ const Brush *brush = BKE_paint_brush(&sd->paint);
+ SculptSession *ss = ob->sculpt;
+ const bool has_bm_orco = ss->bm && sculpt_stroke_is_dynamic_topology(ss, brush);
+ int n;
+
+ /* 0=towards view, 1=flipped */
+ float area_cos[2][3] = {{0.0f}};
+
+ int count[2] = {0};
+
+ /* Intentionally set 'sd' to NULL since we share logic with vertex paint. */
+ SculptThreadedTaskData data = {
+ .sd = NULL,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ .totnode = totnode,
+ .has_bm_orco = has_bm_orco,
+ .area_cos = area_cos,
+ .area_nos = NULL,
+ .count = count,
+ };
+ BLI_mutex_init(&data.mutex);
+
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
+ BLI_task_parallel_range(0, totnode, &data, calc_area_normal_and_center_task_cb, &settings);
+
+ BLI_mutex_end(&data.mutex);
+
+ /* for flatten center */
+ for (n = 0; n < ARRAY_SIZE(area_cos); n++) {
+ if (count[n] != 0) {
+ mul_v3_v3fl(r_area_co, area_cos[n], 1.0f / count[n]);
+ break;
+ }
+ }
+ if (n == 2) {
+ zero_v3(r_area_co);
+ }
}
static void calc_area_normal(
- Sculpt *sd, Object *ob,
- PBVHNode **nodes, int totnode,
- float r_area_no[3])
+ Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, float r_area_no[3])
{
- const Brush *brush = BKE_paint_brush(&sd->paint);
- bool use_threading = (sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT;
- sculpt_pbvh_calc_area_normal(brush, ob, nodes, totnode, use_threading, r_area_no);
+ const Brush *brush = BKE_paint_brush(&sd->paint);
+ bool use_threading = (sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT;
+ sculpt_pbvh_calc_area_normal(brush, ob, nodes, totnode, use_threading, r_area_no);
}
/* expose 'calc_area_normal' externally. */
-void sculpt_pbvh_calc_area_normal(
- const Brush *brush, Object *ob,
- PBVHNode **nodes, int totnode,
- bool use_threading,
- float r_area_no[3])
-{
- SculptSession *ss = ob->sculpt;
- const bool has_bm_orco = ss->bm && sculpt_stroke_is_dynamic_topology(ss, brush);
-
- /* 0=towards view, 1=flipped */
- float area_nos[2][3] = {{0.0f}};
-
- int count[2] = {0};
-
- /* Intentionally set 'sd' to NULL since this is used for vertex paint too. */
- SculptThreadedTaskData data = {
- .sd = NULL, .ob = ob, .brush = brush, .nodes = nodes, .totnode = totnode,
- .has_bm_orco = has_bm_orco, .area_cos = NULL, .area_nos = area_nos, .count = count,
- };
- BLI_mutex_init(&data.mutex);
-
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = use_threading;
- BLI_task_parallel_range(
- 0, totnode,
- &data,
- calc_area_normal_and_center_task_cb,
- &settings);
-
- BLI_mutex_end(&data.mutex);
-
- /* for area normal */
- for (int i = 0; i < ARRAY_SIZE(area_nos); i++) {
- if (normalize_v3_v3(r_area_no, area_nos[i]) != 0.0f) {
- break;
- }
- }
+void sculpt_pbvh_calc_area_normal(const Brush *brush,
+ Object *ob,
+ PBVHNode **nodes,
+ int totnode,
+ bool use_threading,
+ float r_area_no[3])
+{
+ SculptSession *ss = ob->sculpt;
+ const bool has_bm_orco = ss->bm && sculpt_stroke_is_dynamic_topology(ss, brush);
+
+ /* 0=towards view, 1=flipped */
+ float area_nos[2][3] = {{0.0f}};
+
+ int count[2] = {0};
+
+ /* Intentionally set 'sd' to NULL since this is used for vertex paint too. */
+ SculptThreadedTaskData data = {
+ .sd = NULL,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ .totnode = totnode,
+ .has_bm_orco = has_bm_orco,
+ .area_cos = NULL,
+ .area_nos = area_nos,
+ .count = count,
+ };
+ BLI_mutex_init(&data.mutex);
+
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = use_threading;
+ BLI_task_parallel_range(0, totnode, &data, calc_area_normal_and_center_task_cb, &settings);
+
+ BLI_mutex_end(&data.mutex);
+
+ /* for area normal */
+ for (int i = 0; i < ARRAY_SIZE(area_nos); i++) {
+ if (normalize_v3_v3(r_area_no, area_nos[i]) != 0.0f) {
+ break;
+ }
+ }
}
-
/* this calculates flatten center and area normal together,
* amortizing the memory bandwidth and loop overhead to calculate both at the same time */
static void calc_area_normal_and_center(
- Sculpt *sd, Object *ob,
- PBVHNode **nodes, int totnode,
- float r_area_no[3], float r_area_co[3])
-{
- const Brush *brush = BKE_paint_brush(&sd->paint);
- SculptSession *ss = ob->sculpt;
- const bool has_bm_orco = ss->bm && sculpt_stroke_is_dynamic_topology(ss, brush);
- int n;
-
- /* 0=towards view, 1=flipped */
- float area_cos[2][3] = {{0.0f}};
- float area_nos[2][3] = {{0.0f}};
-
- int count[2] = {0};
-
- /* Intentionally set 'sd' to NULL since this is used for vertex paint too. */
- SculptThreadedTaskData data = {
- .sd = NULL, .ob = ob, .brush = brush, .nodes = nodes, .totnode = totnode,
- .has_bm_orco = has_bm_orco, .area_cos = area_cos, .area_nos = area_nos, .count = count,
- };
- BLI_mutex_init(&data.mutex);
-
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
- BLI_task_parallel_range(
- 0, totnode,
- &data,
- calc_area_normal_and_center_task_cb,
- &settings);
-
- BLI_mutex_end(&data.mutex);
-
- /* for flatten center */
- for (n = 0; n < ARRAY_SIZE(area_cos); n++) {
- if (count[n] != 0) {
- mul_v3_v3fl(r_area_co, area_cos[n], 1.0f / count[n]);
- break;
- }
- }
- if (n == 2) {
- zero_v3(r_area_co);
- }
-
- /* for area normal */
- for (n = 0; n < ARRAY_SIZE(area_nos); n++) {
- if (normalize_v3_v3(r_area_no, area_nos[n]) != 0.0f) {
- break;
- }
- }
+ Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, float r_area_no[3], float r_area_co[3])
+{
+ const Brush *brush = BKE_paint_brush(&sd->paint);
+ SculptSession *ss = ob->sculpt;
+ const bool has_bm_orco = ss->bm && sculpt_stroke_is_dynamic_topology(ss, brush);
+ int n;
+
+ /* 0=towards view, 1=flipped */
+ float area_cos[2][3] = {{0.0f}};
+ float area_nos[2][3] = {{0.0f}};
+
+ int count[2] = {0};
+
+ /* Intentionally set 'sd' to NULL since this is used for vertex paint too. */
+ SculptThreadedTaskData data = {
+ .sd = NULL,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ .totnode = totnode,
+ .has_bm_orco = has_bm_orco,
+ .area_cos = area_cos,
+ .area_nos = area_nos,
+ .count = count,
+ };
+ BLI_mutex_init(&data.mutex);
+
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
+ BLI_task_parallel_range(0, totnode, &data, calc_area_normal_and_center_task_cb, &settings);
+
+ BLI_mutex_end(&data.mutex);
+
+ /* for flatten center */
+ for (n = 0; n < ARRAY_SIZE(area_cos); n++) {
+ if (count[n] != 0) {
+ mul_v3_v3fl(r_area_co, area_cos[n], 1.0f / count[n]);
+ break;
+ }
+ }
+ if (n == 2) {
+ zero_v3(r_area_co);
+ }
+
+ /* for area normal */
+ for (n = 0; n < ARRAY_SIZE(area_nos); n++) {
+ if (normalize_v3_v3(r_area_no, area_nos[n]) != 0.0f) {
+ break;
+ }
+ }
}
/** \} */
-
/* Return modified brush strength. Includes the direction of the brush, positive
* values pull vertices, negative values push. Uses tablet pressure and a
* special multiplier found experimentally to scale the strength factor. */
-static float brush_strength(
- const Sculpt *sd, const StrokeCache *cache,
- const float feather, const UnifiedPaintSettings *ups)
-{
- const Scene *scene = cache->vc->scene;
- const Brush *brush = BKE_paint_brush((Paint *)&sd->paint);
-
- /* Primary strength input; square it to make lower values more sensitive */
- const float root_alpha = BKE_brush_alpha_get(scene, brush);
- float alpha = root_alpha * root_alpha;
- float dir = (brush->flag & BRUSH_DIR_IN) ? -1 : 1;
- float pressure = BKE_brush_use_alpha_pressure(scene, brush) ? cache->pressure : 1;
- float pen_flip = cache->pen_flip ? -1 : 1;
- float invert = cache->invert ? -1 : 1;
- float overlap = ups->overlap_factor;
- /* spacing is integer percentage of radius, divide by 50 to get
- * normalized diameter */
-
- float flip = dir * invert * pen_flip;
-
- switch (brush->sculpt_tool) {
- case SCULPT_TOOL_CLAY:
- case SCULPT_TOOL_CLAY_STRIPS:
- case SCULPT_TOOL_DRAW:
- case SCULPT_TOOL_LAYER:
- return alpha * flip * pressure * overlap * feather;
-
- case SCULPT_TOOL_MASK:
- overlap = (1 + overlap) / 2;
- switch ((BrushMaskTool)brush->mask_tool) {
- case BRUSH_MASK_DRAW:
- return alpha * flip * pressure * overlap * feather;
- case BRUSH_MASK_SMOOTH:
- return alpha * pressure * feather;
- }
- BLI_assert(!"Not supposed to happen");
- return 0.0f;
-
- case SCULPT_TOOL_CREASE:
- case SCULPT_TOOL_BLOB:
- return alpha * flip * pressure * overlap * feather;
-
- case SCULPT_TOOL_INFLATE:
- if (flip > 0) {
- return 0.250f * alpha * flip * pressure * overlap * feather;
- }
- else {
- return 0.125f * alpha * flip * pressure * overlap * feather;
- }
-
- case SCULPT_TOOL_FILL:
- case SCULPT_TOOL_SCRAPE:
- case SCULPT_TOOL_FLATTEN:
- if (flip > 0) {
- overlap = (1 + overlap) / 2;
- return alpha * flip * pressure * overlap * feather;
- }
- else {
- /* reduce strength for DEEPEN, PEAKS, and CONTRAST */
- return 0.5f * alpha * flip * pressure * overlap * feather;
- }
-
- case SCULPT_TOOL_SMOOTH:
- return alpha * pressure * feather;
-
- case SCULPT_TOOL_PINCH:
- if (flip > 0) {
- return alpha * flip * pressure * overlap * feather;
- }
- else {
- return 0.25f * alpha * flip * pressure * overlap * feather;
- }
-
- case SCULPT_TOOL_NUDGE:
- overlap = (1 + overlap) / 2;
- return alpha * pressure * overlap * feather;
-
- case SCULPT_TOOL_THUMB:
- return alpha * pressure * feather;
-
- case SCULPT_TOOL_SNAKE_HOOK:
- return root_alpha * feather;
-
- case SCULPT_TOOL_GRAB:
- return root_alpha * feather;
-
- case SCULPT_TOOL_ROTATE:
- return alpha * pressure * feather;
-
- default:
- return 0;
- }
+static float brush_strength(const Sculpt *sd,
+ const StrokeCache *cache,
+ const float feather,
+ const UnifiedPaintSettings *ups)
+{
+ const Scene *scene = cache->vc->scene;
+ const Brush *brush = BKE_paint_brush((Paint *)&sd->paint);
+
+ /* Primary strength input; square it to make lower values more sensitive */
+ const float root_alpha = BKE_brush_alpha_get(scene, brush);
+ float alpha = root_alpha * root_alpha;
+ float dir = (brush->flag & BRUSH_DIR_IN) ? -1 : 1;
+ float pressure = BKE_brush_use_alpha_pressure(scene, brush) ? cache->pressure : 1;
+ float pen_flip = cache->pen_flip ? -1 : 1;
+ float invert = cache->invert ? -1 : 1;
+ float overlap = ups->overlap_factor;
+ /* spacing is integer percentage of radius, divide by 50 to get
+ * normalized diameter */
+
+ float flip = dir * invert * pen_flip;
+
+ switch (brush->sculpt_tool) {
+ case SCULPT_TOOL_CLAY:
+ case SCULPT_TOOL_CLAY_STRIPS:
+ case SCULPT_TOOL_DRAW:
+ case SCULPT_TOOL_LAYER:
+ return alpha * flip * pressure * overlap * feather;
+
+ case SCULPT_TOOL_MASK:
+ overlap = (1 + overlap) / 2;
+ switch ((BrushMaskTool)brush->mask_tool) {
+ case BRUSH_MASK_DRAW:
+ return alpha * flip * pressure * overlap * feather;
+ case BRUSH_MASK_SMOOTH:
+ return alpha * pressure * feather;
+ }
+ BLI_assert(!"Not supposed to happen");
+ return 0.0f;
+
+ case SCULPT_TOOL_CREASE:
+ case SCULPT_TOOL_BLOB:
+ return alpha * flip * pressure * overlap * feather;
+
+ case SCULPT_TOOL_INFLATE:
+ if (flip > 0) {
+ return 0.250f * alpha * flip * pressure * overlap * feather;
+ }
+ else {
+ return 0.125f * alpha * flip * pressure * overlap * feather;
+ }
+
+ case SCULPT_TOOL_FILL:
+ case SCULPT_TOOL_SCRAPE:
+ case SCULPT_TOOL_FLATTEN:
+ if (flip > 0) {
+ overlap = (1 + overlap) / 2;
+ return alpha * flip * pressure * overlap * feather;
+ }
+ else {
+ /* reduce strength for DEEPEN, PEAKS, and CONTRAST */
+ return 0.5f * alpha * flip * pressure * overlap * feather;
+ }
+
+ case SCULPT_TOOL_SMOOTH:
+ return alpha * pressure * feather;
+
+ case SCULPT_TOOL_PINCH:
+ if (flip > 0) {
+ return alpha * flip * pressure * overlap * feather;
+ }
+ else {
+ return 0.25f * alpha * flip * pressure * overlap * feather;
+ }
+
+ case SCULPT_TOOL_NUDGE:
+ overlap = (1 + overlap) / 2;
+ return alpha * pressure * overlap * feather;
+
+ case SCULPT_TOOL_THUMB:
+ return alpha * pressure * feather;
+
+ case SCULPT_TOOL_SNAKE_HOOK:
+ return root_alpha * feather;
+
+ case SCULPT_TOOL_GRAB:
+ return root_alpha * feather;
+
+ case SCULPT_TOOL_ROTATE:
+ return alpha * pressure * feather;
+
+ default:
+ return 0;
+ }
}
/* Return a multiplier for brush strength on a particular vertex. */
-float tex_strength(SculptSession *ss, const Brush *br,
+float tex_strength(SculptSession *ss,
+ const Brush *br,
const float brush_point[3],
const float len,
const short vno[3],
@@ -1199,299 +1180,295 @@ float tex_strength(SculptSession *ss, const Brush *br,
const float mask,
const int thread_id)
{
- StrokeCache *cache = ss->cache;
- const Scene *scene = cache->vc->scene;
- const MTex *mtex = &br->mtex;
- float avg = 1;
- float rgba[4];
- float point[3];
+ StrokeCache *cache = ss->cache;
+ const Scene *scene = cache->vc->scene;
+ const MTex *mtex = &br->mtex;
+ float avg = 1;
+ float rgba[4];
+ float point[3];
- sub_v3_v3v3(point, brush_point, cache->plane_offset);
+ sub_v3_v3v3(point, brush_point, cache->plane_offset);
- if (!mtex->tex) {
- avg = 1;
- }
- else if (mtex->brush_map_mode == MTEX_MAP_MODE_3D) {
- /* Get strength by feeding the vertex
- * location directly into a texture */
- avg = BKE_brush_sample_tex_3d(scene, br, point, rgba, 0, ss->tex_pool);
- }
- else if (ss->texcache) {
- float symm_point[3], point_2d[2];
- float x = 0.0f, y = 0.0f; /* Quite warnings */
+ if (!mtex->tex) {
+ avg = 1;
+ }
+ else if (mtex->brush_map_mode == MTEX_MAP_MODE_3D) {
+ /* Get strength by feeding the vertex
+ * location directly into a texture */
+ avg = BKE_brush_sample_tex_3d(scene, br, point, rgba, 0, ss->tex_pool);
+ }
+ else if (ss->texcache) {
+ float symm_point[3], point_2d[2];
+ float x = 0.0f, y = 0.0f; /* Quite warnings */
- /* if the active area is being applied for symmetry, flip it
- * across the symmetry axis and rotate it back to the original
- * position in order to project it. This insures that the
- * brush texture will be oriented correctly. */
+ /* if the active area is being applied for symmetry, flip it
+ * across the symmetry axis and rotate it back to the original
+ * position in order to project it. This insures that the
+ * brush texture will be oriented correctly. */
- flip_v3_v3(symm_point, point, cache->mirror_symmetry_pass);
+ flip_v3_v3(symm_point, point, cache->mirror_symmetry_pass);
- if (cache->radial_symmetry_pass)
- mul_m4_v3(cache->symm_rot_mat_inv, symm_point);
+ if (cache->radial_symmetry_pass)
+ mul_m4_v3(cache->symm_rot_mat_inv, symm_point);
- ED_view3d_project_float_v2_m4(cache->vc->ar, symm_point, point_2d, cache->projection_mat);
+ ED_view3d_project_float_v2_m4(cache->vc->ar, symm_point, point_2d, cache->projection_mat);
- /* still no symmetry supported for other paint modes.
- * Sculpt does it DIY */
- if (mtex->brush_map_mode == MTEX_MAP_MODE_AREA) {
- /* Similar to fixed mode, but projects from brush angle
- * rather than view direction */
+ /* still no symmetry supported for other paint modes.
+ * Sculpt does it DIY */
+ if (mtex->brush_map_mode == MTEX_MAP_MODE_AREA) {
+ /* Similar to fixed mode, but projects from brush angle
+ * rather than view direction */
- mul_m4_v3(cache->brush_local_mat, symm_point);
+ mul_m4_v3(cache->brush_local_mat, symm_point);
- x = symm_point[0];
- y = symm_point[1];
+ x = symm_point[0];
+ y = symm_point[1];
- x *= br->mtex.size[0];
- y *= br->mtex.size[1];
+ x *= br->mtex.size[0];
+ y *= br->mtex.size[1];
- x += br->mtex.ofs[0];
- y += br->mtex.ofs[1];
+ x += br->mtex.ofs[0];
+ y += br->mtex.ofs[1];
- avg = paint_get_tex_pixel(&br->mtex, x, y, ss->tex_pool, thread_id);
+ avg = paint_get_tex_pixel(&br->mtex, x, y, ss->tex_pool, thread_id);
- avg += br->texture_sample_bias;
- }
- 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 += br->texture_sample_bias;
+ }
+ 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);
+ }
+ }
- /* Falloff curve */
- avg *= BKE_brush_curve_strength(br, len, cache->radius);
+ /* Falloff curve */
+ avg *= BKE_brush_curve_strength(br, len, cache->radius);
- avg *= frontface(br, cache->view_normal, vno, fno);
+ avg *= frontface(br, cache->view_normal, vno, fno);
- /* Paint mask */
- avg *= 1.0f - mask;
+ /* Paint mask */
+ avg *= 1.0f - mask;
- return avg;
+ return avg;
}
/* Test AABB against sphere */
bool sculpt_search_sphere_cb(PBVHNode *node, void *data_v)
{
- SculptSearchSphereData *data = data_v;
- float *center = data->ss->cache->location, nearest[3];
- float t[3], bb_min[3], bb_max[3];
- int i;
+ SculptSearchSphereData *data = data_v;
+ float *center = data->ss->cache->location, nearest[3];
+ float t[3], bb_min[3], bb_max[3];
+ int i;
- if (data->original)
- BKE_pbvh_node_get_original_BB(node, bb_min, bb_max);
- else
- BKE_pbvh_node_get_BB(node, bb_min, bb_max);
+ if (data->original)
+ BKE_pbvh_node_get_original_BB(node, bb_min, bb_max);
+ else
+ BKE_pbvh_node_get_BB(node, bb_min, bb_max);
- for (i = 0; i < 3; ++i) {
- if (bb_min[i] > center[i])
- nearest[i] = bb_min[i];
- else if (bb_max[i] < center[i])
- nearest[i] = bb_max[i];
- else
- nearest[i] = center[i];
- }
+ for (i = 0; i < 3; ++i) {
+ if (bb_min[i] > center[i])
+ nearest[i] = bb_min[i];
+ else if (bb_max[i] < center[i])
+ nearest[i] = bb_max[i];
+ else
+ nearest[i] = center[i];
+ }
- sub_v3_v3v3(t, center, nearest);
+ sub_v3_v3v3(t, center, nearest);
- return len_squared_v3(t) < data->radius_squared;
+ return len_squared_v3(t) < data->radius_squared;
}
/* 2D projection (distance to line). */
bool sculpt_search_circle_cb(PBVHNode *node, void *data_v)
{
- SculptSearchCircleData *data = data_v;
- float bb_min[3], bb_max[3];
+ SculptSearchCircleData *data = data_v;
+ float bb_min[3], bb_max[3];
- if (data->original)
- BKE_pbvh_node_get_original_BB(node, bb_min, bb_max);
- else
- BKE_pbvh_node_get_BB(node, bb_min, bb_min);
+ if (data->original)
+ BKE_pbvh_node_get_original_BB(node, bb_min, bb_max);
+ else
+ BKE_pbvh_node_get_BB(node, bb_min, bb_min);
- float dummy_co[3], dummy_depth;
- const float dist_sq = dist_squared_ray_to_aabb_v3(
- data->dist_ray_to_aabb_precalc, bb_min, bb_max, dummy_co, &dummy_depth);
+ float dummy_co[3], dummy_depth;
+ const float dist_sq = dist_squared_ray_to_aabb_v3(
+ data->dist_ray_to_aabb_precalc, bb_min, bb_max, dummy_co, &dummy_depth);
- return dist_sq < data->radius_squared || 1;
+ return dist_sq < data->radius_squared || 1;
}
/* Handles clipping against a mirror modifier and SCULPT_LOCK axis flags */
static void sculpt_clip(Sculpt *sd, SculptSession *ss, float co[3], const float val[3])
{
- int i;
-
- for (i = 0; i < 3; ++i) {
- if (sd->flags & (SCULPT_LOCK_X << i))
- continue;
-
- if ((ss->cache->flag & (CLIP_X << i)) && (fabsf(co[i]) <= ss->cache->clip_tolerance[i]))
- co[i] = 0.0f;
- else
- co[i] = val[i];
- }
-}
-
-static PBVHNode **sculpt_pbvh_gather_generic(
- Object *ob, Sculpt *sd, const Brush *brush, bool use_original, float radius_scale, int *r_totnode)
-{
- SculptSession *ss = ob->sculpt;
- PBVHNode **nodes = NULL;
-
- /* Build a list of all nodes that are potentially within the brush's area of influence */
- if (brush->falloff_shape == PAINT_FALLOFF_SHAPE_SPHERE) {
- SculptSearchSphereData data = {
- .ss = ss,
- .sd = sd,
- .radius_squared = SQUARE(ss->cache->radius * radius_scale),
- .original = use_original,
- };
- BKE_pbvh_search_gather(ss->pbvh, sculpt_search_sphere_cb, &data, &nodes, r_totnode);
- }
- else {
- struct DistRayAABB_Precalc dist_ray_to_aabb_precalc;
- dist_squared_ray_to_aabb_v3_precalc(&dist_ray_to_aabb_precalc, ss->cache->location, ss->cache->view_normal);
- SculptSearchCircleData data = {
- .ss = ss,
- .sd = sd,
- .radius_squared = SQUARE(ss->cache->radius * radius_scale),
- .original = use_original,
- .dist_ray_to_aabb_precalc = &dist_ray_to_aabb_precalc,
- };
- BKE_pbvh_search_gather(ss->pbvh, sculpt_search_circle_cb, &data, &nodes, r_totnode);
- }
- return nodes;
+ int i;
+
+ for (i = 0; i < 3; ++i) {
+ if (sd->flags & (SCULPT_LOCK_X << i))
+ continue;
+
+ if ((ss->cache->flag & (CLIP_X << i)) && (fabsf(co[i]) <= ss->cache->clip_tolerance[i]))
+ co[i] = 0.0f;
+ else
+ co[i] = val[i];
+ }
+}
+
+static PBVHNode **sculpt_pbvh_gather_generic(Object *ob,
+ Sculpt *sd,
+ const Brush *brush,
+ bool use_original,
+ float radius_scale,
+ int *r_totnode)
+{
+ SculptSession *ss = ob->sculpt;
+ PBVHNode **nodes = NULL;
+
+ /* Build a list of all nodes that are potentially within the brush's area of influence */
+ if (brush->falloff_shape == PAINT_FALLOFF_SHAPE_SPHERE) {
+ SculptSearchSphereData data = {
+ .ss = ss,
+ .sd = sd,
+ .radius_squared = SQUARE(ss->cache->radius * radius_scale),
+ .original = use_original,
+ };
+ BKE_pbvh_search_gather(ss->pbvh, sculpt_search_sphere_cb, &data, &nodes, r_totnode);
+ }
+ else {
+ struct DistRayAABB_Precalc dist_ray_to_aabb_precalc;
+ dist_squared_ray_to_aabb_v3_precalc(
+ &dist_ray_to_aabb_precalc, ss->cache->location, ss->cache->view_normal);
+ SculptSearchCircleData data = {
+ .ss = ss,
+ .sd = sd,
+ .radius_squared = SQUARE(ss->cache->radius * radius_scale),
+ .original = use_original,
+ .dist_ray_to_aabb_precalc = &dist_ray_to_aabb_precalc,
+ };
+ BKE_pbvh_search_gather(ss->pbvh, sculpt_search_circle_cb, &data, &nodes, r_totnode);
+ }
+ return nodes;
}
/* Calculate primary direction of movement for many brushes */
static void calc_sculpt_normal(
- Sculpt *sd, Object *ob,
- PBVHNode **nodes, int totnode,
- float r_area_no[3])
-{
- const Brush *brush = BKE_paint_brush(&sd->paint);
- const SculptSession *ss = ob->sculpt;
-
- switch (brush->sculpt_plane) {
- case SCULPT_DISP_DIR_VIEW:
- copy_v3_v3(r_area_no, ss->cache->true_view_normal);
- break;
-
- case SCULPT_DISP_DIR_X:
- ARRAY_SET_ITEMS(r_area_no, 1, 0, 0);
- break;
-
- case SCULPT_DISP_DIR_Y:
- ARRAY_SET_ITEMS(r_area_no, 0, 1, 0);
- break;
-
- case SCULPT_DISP_DIR_Z:
- ARRAY_SET_ITEMS(r_area_no, 0, 0, 1);
- break;
-
- case SCULPT_DISP_DIR_AREA:
- calc_area_normal(sd, ob, nodes, totnode, r_area_no);
- break;
-
- default:
- break;
- }
-}
-
-static void update_sculpt_normal(Sculpt *sd, Object *ob,
- PBVHNode **nodes, int totnode)
-{
- const Brush *brush = BKE_paint_brush(&sd->paint);
- StrokeCache *cache = ob->sculpt->cache;
-
- if (cache->mirror_symmetry_pass == 0 &&
- cache->radial_symmetry_pass == 0 &&
- (cache->first_time || !(brush->flag & BRUSH_ORIGINAL_NORMAL)))
- {
- calc_sculpt_normal(sd, ob, nodes, totnode, cache->sculpt_normal);
- if (brush->falloff_shape == PAINT_FALLOFF_SHAPE_TUBE) {
- project_plane_v3_v3v3(cache->sculpt_normal, cache->sculpt_normal, cache->view_normal);
- normalize_v3(cache->sculpt_normal);
- }
- copy_v3_v3(cache->sculpt_normal_symm, cache->sculpt_normal);
- }
- else {
- copy_v3_v3(cache->sculpt_normal_symm, cache->sculpt_normal);
- flip_v3(cache->sculpt_normal_symm, cache->mirror_symmetry_pass);
- mul_m4_v3(cache->symm_rot_mat, cache->sculpt_normal_symm);
- }
+ Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, float r_area_no[3])
+{
+ const Brush *brush = BKE_paint_brush(&sd->paint);
+ const SculptSession *ss = ob->sculpt;
+
+ switch (brush->sculpt_plane) {
+ case SCULPT_DISP_DIR_VIEW:
+ copy_v3_v3(r_area_no, ss->cache->true_view_normal);
+ break;
+
+ case SCULPT_DISP_DIR_X:
+ ARRAY_SET_ITEMS(r_area_no, 1, 0, 0);
+ break;
+
+ case SCULPT_DISP_DIR_Y:
+ ARRAY_SET_ITEMS(r_area_no, 0, 1, 0);
+ break;
+
+ case SCULPT_DISP_DIR_Z:
+ ARRAY_SET_ITEMS(r_area_no, 0, 0, 1);
+ break;
+
+ case SCULPT_DISP_DIR_AREA:
+ calc_area_normal(sd, ob, nodes, totnode, r_area_no);
+ break;
+
+ default:
+ break;
+ }
+}
+
+static void update_sculpt_normal(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
+{
+ const Brush *brush = BKE_paint_brush(&sd->paint);
+ StrokeCache *cache = ob->sculpt->cache;
+
+ if (cache->mirror_symmetry_pass == 0 && cache->radial_symmetry_pass == 0 &&
+ (cache->first_time || !(brush->flag & BRUSH_ORIGINAL_NORMAL))) {
+ calc_sculpt_normal(sd, ob, nodes, totnode, cache->sculpt_normal);
+ if (brush->falloff_shape == PAINT_FALLOFF_SHAPE_TUBE) {
+ project_plane_v3_v3v3(cache->sculpt_normal, cache->sculpt_normal, cache->view_normal);
+ normalize_v3(cache->sculpt_normal);
+ }
+ copy_v3_v3(cache->sculpt_normal_symm, cache->sculpt_normal);
+ }
+ else {
+ copy_v3_v3(cache->sculpt_normal_symm, cache->sculpt_normal);
+ flip_v3(cache->sculpt_normal_symm, cache->mirror_symmetry_pass);
+ mul_m4_v3(cache->symm_rot_mat, cache->sculpt_normal_symm);
+ }
}
static void calc_local_y(ViewContext *vc, const float center[3], float y[3])
{
- Object *ob = vc->obact;
- float loc[3], mval_f[2] = {0.0f, 1.0f};
- float zfac;
+ Object *ob = vc->obact;
+ float loc[3], mval_f[2] = {0.0f, 1.0f};
+ float zfac;
- mul_v3_m4v3(loc, ob->imat, center);
- zfac = ED_view3d_calc_zfac(vc->rv3d, loc, NULL);
+ mul_v3_m4v3(loc, ob->imat, center);
+ zfac = ED_view3d_calc_zfac(vc->rv3d, loc, NULL);
- ED_view3d_win_to_delta(vc->ar, mval_f, y, zfac);
- normalize_v3(y);
+ ED_view3d_win_to_delta(vc->ar, mval_f, y, zfac);
+ normalize_v3(y);
- add_v3_v3(y, ob->loc);
- mul_m4_v3(ob->imat, y);
+ add_v3_v3(y, ob->loc);
+ mul_m4_v3(ob->imat, y);
}
-static void calc_brush_local_mat(const Brush *brush, Object *ob,
- float local_mat[4][4])
+static void calc_brush_local_mat(const Brush *brush, Object *ob, float local_mat[4][4])
{
- const StrokeCache *cache = ob->sculpt->cache;
- float tmat[4][4];
- float mat[4][4];
- float scale[4][4];
- float angle, v[3];
- float up[3];
+ const StrokeCache *cache = ob->sculpt->cache;
+ float tmat[4][4];
+ float mat[4][4];
+ float scale[4][4];
+ float angle, v[3];
+ float up[3];
- /* Ensure ob->imat is up to date */
- invert_m4_m4(ob->imat, ob->obmat);
+ /* Ensure ob->imat is up to date */
+ invert_m4_m4(ob->imat, ob->obmat);
- /* Initialize last column of matrix */
- mat[0][3] = 0;
- mat[1][3] = 0;
- mat[2][3] = 0;
- mat[3][3] = 1;
+ /* Initialize last column of matrix */
+ mat[0][3] = 0;
+ mat[1][3] = 0;
+ mat[2][3] = 0;
+ mat[3][3] = 1;
- /* Get view's up vector in object-space */
- calc_local_y(cache->vc, cache->location, up);
+ /* Get view's up vector in object-space */
+ calc_local_y(cache->vc, cache->location, up);
- /* Calculate the X axis of the local matrix */
- cross_v3_v3v3(v, up, cache->sculpt_normal);
- /* Apply rotation (user angle, rake, etc.) to X axis */
- angle = brush->mtex.rot - cache->special_rotation;
- rotate_v3_v3v3fl(mat[0], v, cache->sculpt_normal, angle);
+ /* Calculate the X axis of the local matrix */
+ cross_v3_v3v3(v, up, cache->sculpt_normal);
+ /* Apply rotation (user angle, rake, etc.) to X axis */
+ angle = brush->mtex.rot - cache->special_rotation;
+ rotate_v3_v3v3fl(mat[0], v, cache->sculpt_normal, angle);
- /* Get other axes */
- cross_v3_v3v3(mat[1], cache->sculpt_normal, mat[0]);
- copy_v3_v3(mat[2], cache->sculpt_normal);
+ /* Get other axes */
+ cross_v3_v3v3(mat[1], cache->sculpt_normal, mat[0]);
+ copy_v3_v3(mat[2], cache->sculpt_normal);
- /* Set location */
- copy_v3_v3(mat[3], cache->location);
+ /* Set location */
+ copy_v3_v3(mat[3], cache->location);
- /* Scale by brush radius */
- normalize_m4(mat);
- scale_m4_fl(scale, cache->radius);
- mul_m4_m4m4(tmat, mat, scale);
+ /* Scale by brush radius */
+ normalize_m4(mat);
+ scale_m4_fl(scale, cache->radius);
+ mul_m4_m4m4(tmat, mat, scale);
- /* Return inverse (for converting from modelspace coords to local
- * area coords) */
- invert_m4_m4(local_mat, tmat);
+ /* Return inverse (for converting from modelspace coords to local
+ * area coords) */
+ invert_m4_m4(local_mat, tmat);
}
static void update_brush_local_mat(Sculpt *sd, Object *ob)
{
- StrokeCache *cache = ob->sculpt->cache;
+ StrokeCache *cache = ob->sculpt->cache;
- if (cache->mirror_symmetry_pass == 0 &&
- cache->radial_symmetry_pass == 0)
- {
- calc_brush_local_mat(BKE_paint_brush(&sd->paint), ob,
- cache->brush_local_mat);
- }
+ if (cache->mirror_symmetry_pass == 0 && cache->radial_symmetry_pass == 0) {
+ calc_brush_local_mat(BKE_paint_brush(&sd->paint), ob, cache->brush_local_mat);
+ }
}
/* For the smooth brush, uses the neighboring vertices around vert to calculate
@@ -1499,40 +1476,39 @@ static void update_brush_local_mat(Sculpt *sd, Object *ob)
* polygon.) */
static void neighbor_average(SculptSession *ss, float avg[3], unsigned vert)
{
- const MeshElemMap *vert_map = &ss->pmap[vert];
- const MVert *mvert = ss->mvert;
- float (*deform_co)[3] = ss->deform_cos;
+ const MeshElemMap *vert_map = &ss->pmap[vert];
+ const MVert *mvert = ss->mvert;
+ float(*deform_co)[3] = ss->deform_cos;
- /* Don't modify corner vertices */
- if (vert_map->count > 1) {
- int i, total = 0;
+ /* Don't modify corner vertices */
+ if (vert_map->count > 1) {
+ int i, total = 0;
- zero_v3(avg);
+ zero_v3(avg);
- for (i = 0; i < vert_map->count; i++) {
- const MPoly *p = &ss->mpoly[vert_map->indices[i]];
- unsigned f_adj_v[2];
+ for (i = 0; i < vert_map->count; i++) {
+ const MPoly *p = &ss->mpoly[vert_map->indices[i]];
+ unsigned f_adj_v[2];
- if (poly_get_adj_loops_from_vert(p, ss->mloop, vert, f_adj_v) != -1) {
- int j;
- for (j = 0; j < ARRAY_SIZE(f_adj_v); j += 1) {
- if (vert_map->count != 2 || ss->pmap[f_adj_v[j]].count <= 2) {
- add_v3_v3(avg, deform_co ? deform_co[f_adj_v[j]] :
- mvert[f_adj_v[j]].co);
+ if (poly_get_adj_loops_from_vert(p, ss->mloop, vert, f_adj_v) != -1) {
+ int j;
+ for (j = 0; j < ARRAY_SIZE(f_adj_v); j += 1) {
+ if (vert_map->count != 2 || ss->pmap[f_adj_v[j]].count <= 2) {
+ add_v3_v3(avg, deform_co ? deform_co[f_adj_v[j]] : mvert[f_adj_v[j]].co);
- total++;
- }
- }
- }
- }
+ total++;
+ }
+ }
+ }
+ }
- if (total > 0) {
- mul_v3_fl(avg, 1.0f / total);
- return;
- }
- }
+ if (total > 0) {
+ mul_v3_fl(avg, 1.0f / total);
+ return;
+ }
+ }
- copy_v3_v3(avg, deform_co ? deform_co[vert] : mvert[vert].co);
+ copy_v3_v3(avg, deform_co ? deform_co[vert] : mvert[vert].co);
}
/* Similar to neighbor_average(), but returns an averaged mask value
@@ -1540,2664 +1516,2727 @@ static void neighbor_average(SculptSession *ss, float avg[3], unsigned vert)
* corner vertices. */
static float neighbor_average_mask(SculptSession *ss, unsigned vert)
{
- const float *vmask = ss->vmask;
- float avg = 0;
- int i, total = 0;
+ const float *vmask = ss->vmask;
+ float avg = 0;
+ int i, total = 0;
- for (i = 0; i < ss->pmap[vert].count; i++) {
- const MPoly *p = &ss->mpoly[ss->pmap[vert].indices[i]];
- unsigned f_adj_v[2];
+ for (i = 0; i < ss->pmap[vert].count; i++) {
+ const MPoly *p = &ss->mpoly[ss->pmap[vert].indices[i]];
+ unsigned f_adj_v[2];
- if (poly_get_adj_loops_from_vert(p, ss->mloop, vert, f_adj_v) != -1) {
- int j;
- for (j = 0; j < ARRAY_SIZE(f_adj_v); j += 1) {
- avg += vmask[f_adj_v[j]];
- total++;
- }
- }
- }
+ if (poly_get_adj_loops_from_vert(p, ss->mloop, vert, f_adj_v) != -1) {
+ int j;
+ for (j = 0; j < ARRAY_SIZE(f_adj_v); j += 1) {
+ avg += vmask[f_adj_v[j]];
+ total++;
+ }
+ }
+ }
- if (total > 0)
- return avg / (float)total;
- else
- return vmask[vert];
+ if (total > 0)
+ return avg / (float)total;
+ else
+ return vmask[vert];
}
/* Same logic as neighbor_average(), but for bmesh rather than mesh */
static void bmesh_neighbor_average(float avg[3], BMVert *v)
{
- /* logic for 3 or more is identical */
- const int vfcount = BM_vert_face_count_at_most(v, 3);
+ /* logic for 3 or more is identical */
+ const int vfcount = BM_vert_face_count_at_most(v, 3);
- /* Don't modify corner vertices */
- if (vfcount > 1) {
- BMIter liter;
- BMLoop *l;
- int i, total = 0;
+ /* Don't modify corner vertices */
+ if (vfcount > 1) {
+ BMIter liter;
+ BMLoop *l;
+ int i, total = 0;
- zero_v3(avg);
+ zero_v3(avg);
- BM_ITER_ELEM (l, &liter, v, BM_LOOPS_OF_VERT) {
- const BMVert *adj_v[2] = {l->prev->v, l->next->v};
+ BM_ITER_ELEM (l, &liter, v, BM_LOOPS_OF_VERT) {
+ const BMVert *adj_v[2] = {l->prev->v, l->next->v};
- for (i = 0; i < ARRAY_SIZE(adj_v); i++) {
- const BMVert *v_other = adj_v[i];
- if (vfcount != 2 || BM_vert_face_count_at_most(v_other, 2) <= 2) {
- add_v3_v3(avg, v_other->co);
- total++;
- }
- }
- }
+ for (i = 0; i < ARRAY_SIZE(adj_v); i++) {
+ const BMVert *v_other = adj_v[i];
+ if (vfcount != 2 || BM_vert_face_count_at_most(v_other, 2) <= 2) {
+ add_v3_v3(avg, v_other->co);
+ total++;
+ }
+ }
+ }
- if (total > 0) {
- mul_v3_fl(avg, 1.0f / total);
- return;
- }
- }
+ if (total > 0) {
+ mul_v3_fl(avg, 1.0f / total);
+ return;
+ }
+ }
- copy_v3_v3(avg, v->co);
+ copy_v3_v3(avg, v->co);
}
/* For bmesh: average only the four most aligned (parallel and perpendicular) edges
* relative to a direction. Naturally converges to a quad-like tessellation. */
static void bmesh_four_neighbor_average(float avg[3], float direction[3], BMVert *v)
{
- /* Logic for 3 or more is identical. */
- const int vfcount = BM_vert_face_count_at_most(v, 3);
-
- /* Don't modify corner vertices. */
- if (vfcount < 2) {
- copy_v3_v3(avg, v->co);
- return;
- }
-
- /* Project the direction to the vertex normal and create an additional
- * parallel vector. */
- float dir_a[3], dir_b[3];
- cross_v3_v3v3(dir_a, direction, v->no);
- cross_v3_v3v3(dir_b, dir_a, v->no);
-
- /* The four vectors which will be used for smoothing.
- * Occasionally less than 4 verts match the requirements in that case
- * use 'v' as fallback. */
- BMVert *pos_a = v;
- BMVert *neg_a = v;
- BMVert *pos_b = v;
- BMVert *neg_b = v;
-
- float pos_score_a = 0.0f;
- float neg_score_a = 0.0f;
- float pos_score_b = 0.0f;
- float neg_score_b = 0.0f;
-
- BMIter liter;
- BMLoop *l;
-
- BM_ITER_ELEM(l, &liter, v, BM_LOOPS_OF_VERT) {
- BMVert *adj_v[2] = { l->prev->v, l->next->v };
-
- for (int i = 0; i < ARRAY_SIZE(adj_v); i++) {
- BMVert *v_other = adj_v[i];
-
- if (vfcount != 2 || BM_vert_face_count_at_most(v_other, 2) <= 2) {
- float vec[3];
- sub_v3_v3v3(vec, v_other->co, v->co);
- normalize_v3(vec);
-
- /* The score is a measure of how orthogonal the edge is. */
- float score = dot_v3v3(vec, dir_a);
-
- if (score >= pos_score_a) {
- pos_a = v_other;
- pos_score_a = score;
- }
- else if (score < neg_score_a) {
- neg_a = v_other;
- neg_score_a = score;
- }
- /* The same scoring but for the perpendicular direction. */
- score = dot_v3v3(vec, dir_b);
-
- if (score >= pos_score_b) {
- pos_b = v_other;
- pos_score_b = score;
- }
- else if (score < neg_score_b) {
- neg_b = v_other;
- neg_score_b = score;
- }
- }
- }
- }
-
- /* Average everything together. */
- zero_v3(avg);
- add_v3_v3(avg, pos_a->co);
- add_v3_v3(avg, neg_a->co);
- add_v3_v3(avg, pos_b->co);
- add_v3_v3(avg, neg_b->co);
- mul_v3_fl(avg, 0.25f);
-
- /* Preserve volume. */
- float vec[3];
- sub_v3_v3(avg, v->co);
- mul_v3_v3fl(vec, v->no, dot_v3v3(avg, v->no));
- sub_v3_v3(avg, vec);
- add_v3_v3(avg, v->co);
+ /* Logic for 3 or more is identical. */
+ const int vfcount = BM_vert_face_count_at_most(v, 3);
+
+ /* Don't modify corner vertices. */
+ if (vfcount < 2) {
+ copy_v3_v3(avg, v->co);
+ return;
+ }
+
+ /* Project the direction to the vertex normal and create an additional
+ * parallel vector. */
+ float dir_a[3], dir_b[3];
+ cross_v3_v3v3(dir_a, direction, v->no);
+ cross_v3_v3v3(dir_b, dir_a, v->no);
+
+ /* The four vectors which will be used for smoothing.
+ * Occasionally less than 4 verts match the requirements in that case
+ * use 'v' as fallback. */
+ BMVert *pos_a = v;
+ BMVert *neg_a = v;
+ BMVert *pos_b = v;
+ BMVert *neg_b = v;
+
+ float pos_score_a = 0.0f;
+ float neg_score_a = 0.0f;
+ float pos_score_b = 0.0f;
+ float neg_score_b = 0.0f;
+
+ BMIter liter;
+ BMLoop *l;
+
+ BM_ITER_ELEM (l, &liter, v, BM_LOOPS_OF_VERT) {
+ BMVert *adj_v[2] = {l->prev->v, l->next->v};
+
+ for (int i = 0; i < ARRAY_SIZE(adj_v); i++) {
+ BMVert *v_other = adj_v[i];
+
+ if (vfcount != 2 || BM_vert_face_count_at_most(v_other, 2) <= 2) {
+ float vec[3];
+ sub_v3_v3v3(vec, v_other->co, v->co);
+ normalize_v3(vec);
+
+ /* The score is a measure of how orthogonal the edge is. */
+ float score = dot_v3v3(vec, dir_a);
+
+ if (score >= pos_score_a) {
+ pos_a = v_other;
+ pos_score_a = score;
+ }
+ else if (score < neg_score_a) {
+ neg_a = v_other;
+ neg_score_a = score;
+ }
+ /* The same scoring but for the perpendicular direction. */
+ score = dot_v3v3(vec, dir_b);
+
+ if (score >= pos_score_b) {
+ pos_b = v_other;
+ pos_score_b = score;
+ }
+ else if (score < neg_score_b) {
+ neg_b = v_other;
+ neg_score_b = score;
+ }
+ }
+ }
+ }
+
+ /* Average everything together. */
+ zero_v3(avg);
+ add_v3_v3(avg, pos_a->co);
+ add_v3_v3(avg, neg_a->co);
+ add_v3_v3(avg, pos_b->co);
+ add_v3_v3(avg, neg_b->co);
+ mul_v3_fl(avg, 0.25f);
+
+ /* Preserve volume. */
+ float vec[3];
+ sub_v3_v3(avg, v->co);
+ mul_v3_v3fl(vec, v->no, dot_v3v3(avg, v->no));
+ sub_v3_v3(avg, vec);
+ add_v3_v3(avg, v->co);
}
/* Same logic as neighbor_average_mask(), but for bmesh rather than mesh */
static float bmesh_neighbor_average_mask(BMVert *v, const int cd_vert_mask_offset)
{
- BMIter liter;
- BMLoop *l;
- float avg = 0;
- int i, total = 0;
+ BMIter liter;
+ BMLoop *l;
+ float avg = 0;
+ int i, total = 0;
- BM_ITER_ELEM (l, &liter, v, BM_LOOPS_OF_VERT) {
- /* skip this vertex */
- const BMVert *adj_v[2] = {l->prev->v, l->next->v};
+ BM_ITER_ELEM (l, &liter, v, BM_LOOPS_OF_VERT) {
+ /* skip this vertex */
+ const BMVert *adj_v[2] = {l->prev->v, l->next->v};
- for (i = 0; i < ARRAY_SIZE(adj_v); i++) {
- const BMVert *v_other = adj_v[i];
- const float *vmask = BM_ELEM_CD_GET_VOID_P(v_other, cd_vert_mask_offset);
- avg += (*vmask);
- total++;
- }
- }
+ for (i = 0; i < ARRAY_SIZE(adj_v); i++) {
+ const BMVert *v_other = adj_v[i];
+ const float *vmask = BM_ELEM_CD_GET_VOID_P(v_other, cd_vert_mask_offset);
+ avg += (*vmask);
+ total++;
+ }
+ }
- if (total > 0) {
- return avg / (float)total;
- }
- else {
- const float *vmask = BM_ELEM_CD_GET_VOID_P(v, cd_vert_mask_offset);
- return (*vmask);
- }
+ if (total > 0) {
+ return avg / (float)total;
+ }
+ else {
+ const float *vmask = BM_ELEM_CD_GET_VOID_P(v, cd_vert_mask_offset);
+ return (*vmask);
+ }
}
/* Note: uses after-struct allocated mem to store actual cache... */
typedef struct SculptDoBrushSmoothGridDataChunk {
- size_t tmpgrid_size;
+ size_t tmpgrid_size;
} SculptDoBrushSmoothGridDataChunk;
typedef struct {
- SculptSession *ss;
- const float *ray_start, *ray_normal;
- bool hit;
- float depth;
- bool original;
+ SculptSession *ss;
+ const float *ray_start, *ray_normal;
+ bool hit;
+ float depth;
+ bool original;
} SculptRaycastData;
typedef struct {
- const float *ray_start, *ray_normal;
- bool hit;
- float depth;
- float edge_length;
+ const float *ray_start, *ray_normal;
+ bool hit;
+ float depth;
+ float edge_length;
} SculptDetailRaycastData;
typedef struct {
- SculptSession *ss;
- const float *ray_start, *ray_normal;
- bool hit;
- float depth;
- float dist_sq_to_ray;
- bool original;
+ SculptSession *ss;
+ const float *ray_start, *ray_normal;
+ bool hit;
+ float depth;
+ float dist_sq_to_ray;
+ bool original;
} SculptFindNearestToRayData;
-static void do_smooth_brush_mesh_task_cb_ex(
- void *__restrict userdata,
- const int n,
- const ParallelRangeTLS *__restrict tls)
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- Sculpt *sd = data->sd;
- const Brush *brush = data->brush;
- const bool smooth_mask = data->smooth_mask;
- float bstrength = data->strength;
-
- PBVHVertexIter vd;
-
- CLAMP(bstrength, 0.0f, 1.0f);
-
- SculptBrushTest test;
- SculptBrushTestFn sculpt_brush_test_sq_fn =
- sculpt_brush_test_init_with_falloff_shape(ss, &test, data->brush->falloff_shape);
-
- BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
- {
- if (sculpt_brush_test_sq_fn(&test, vd.co)) {
- const float fade = bstrength * tex_strength(
- ss, brush, vd.co, sqrtf(test.dist),
- vd.no, vd.fno, smooth_mask ? 0.0f : (vd.mask ? *vd.mask : 0.0f), tls->thread_id);
- if (smooth_mask) {
- float val = neighbor_average_mask(ss, vd.vert_indices[vd.i]) - *vd.mask;
- val *= fade * bstrength;
- *vd.mask += val;
- CLAMP(*vd.mask, 0.0f, 1.0f);
- }
- else {
- float avg[3], val[3];
-
- neighbor_average(ss, avg, vd.vert_indices[vd.i]);
- sub_v3_v3v3(val, avg, vd.co);
-
- madd_v3_v3v3fl(val, vd.co, val, fade);
-
- sculpt_clip(sd, ss, vd.co, val);
- }
-
- if (vd.mvert)
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- BKE_pbvh_vertex_iter_end;
-}
-
-static void do_smooth_brush_bmesh_task_cb_ex(
- void *__restrict userdata,
- const int n,
- const ParallelRangeTLS *__restrict tls)
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- Sculpt *sd = data->sd;
- const Brush *brush = data->brush;
- const bool smooth_mask = data->smooth_mask;
- float bstrength = data->strength;
-
- PBVHVertexIter vd;
-
- CLAMP(bstrength, 0.0f, 1.0f);
-
- SculptBrushTest test;
- SculptBrushTestFn sculpt_brush_test_sq_fn =
- sculpt_brush_test_init_with_falloff_shape(ss, &test, data->brush->falloff_shape);
-
- BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
- {
- if (sculpt_brush_test_sq_fn(&test, vd.co)) {
- const float fade = bstrength * tex_strength(
- ss, brush, vd.co, sqrtf(test.dist),
- vd.no, vd.fno, smooth_mask ? 0.0f : *vd.mask, tls->thread_id);
- if (smooth_mask) {
- float val = bmesh_neighbor_average_mask(vd.bm_vert, vd.cd_vert_mask_offset) - *vd.mask;
- val *= fade * bstrength;
- *vd.mask += val;
- CLAMP(*vd.mask, 0.0f, 1.0f);
- }
- else {
- float avg[3], val[3];
-
- bmesh_neighbor_average(avg, vd.bm_vert);
- sub_v3_v3v3(val, avg, vd.co);
-
- madd_v3_v3v3fl(val, vd.co, val, fade);
-
- sculpt_clip(sd, ss, vd.co, val);
- }
-
- if (vd.mvert)
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- BKE_pbvh_vertex_iter_end;
-}
-
-static void do_topology_rake_bmesh_task_cb_ex(
- void *__restrict userdata,
- const int n,
- const ParallelRangeTLS *__restrict tls)
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- Sculpt *sd = data->sd;
- const Brush *brush = data->brush;
-
- float direction[3];
- copy_v3_v3(direction, ss->cache->grab_delta_symmetry);
-
- float tmp[3];
- mul_v3_v3fl(
- tmp, ss->cache->sculpt_normal_symm,
- dot_v3v3(ss->cache->sculpt_normal_symm, direction));
- sub_v3_v3(direction, tmp);
-
- /* Cancel if there's no grab data. */
- if (is_zero_v3(direction)) {
- return;
- }
-
- float bstrength = data->strength;
- CLAMP(bstrength, 0.0f, 1.0f);
-
- SculptBrushTest test;
- SculptBrushTestFn sculpt_brush_test_sq_fn =
- sculpt_brush_test_init_with_falloff_shape(ss, &test, data->brush->falloff_shape);
-
- PBVHVertexIter vd;
- BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
- {
- if (sculpt_brush_test_sq_fn(&test, vd.co)) {
- const float fade = bstrength * tex_strength(
- ss, brush, vd.co, sqrtf(test.dist),
- vd.no, vd.fno, *vd.mask, tls->thread_id) * ss->cache->pressure;
-
- float avg[3], val[3];
-
- bmesh_four_neighbor_average(avg, direction, vd.bm_vert);
-
- sub_v3_v3v3(val, avg, vd.co);
-
- madd_v3_v3v3fl(val, vd.co, val, fade);
-
- sculpt_clip(sd, ss, vd.co, val);
-
- if (vd.mvert)
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- BKE_pbvh_vertex_iter_end;
-}
-
-static void do_smooth_brush_multires_task_cb_ex(
- void *__restrict userdata,
- const int n,
- const ParallelRangeTLS *__restrict tls)
-{
- SculptThreadedTaskData *data = userdata;
- SculptDoBrushSmoothGridDataChunk *data_chunk = tls->userdata_chunk;
- SculptSession *ss = data->ob->sculpt;
- Sculpt *sd = data->sd;
- const Brush *brush = data->brush;
- const bool smooth_mask = data->smooth_mask;
- float bstrength = data->strength;
-
- CCGElem **griddata, *gddata;
- CCGKey key;
-
- float (*tmpgrid_co)[3] = NULL;
- float tmprow_co[2][3];
- float *tmpgrid_mask = NULL;
- float tmprow_mask[2];
-
- BLI_bitmap * const *grid_hidden;
- int *grid_indices, totgrid, gridsize;
- int i, x, y;
-
- SculptBrushTest test;
- SculptBrushTestFn sculpt_brush_test_sq_fn =
- sculpt_brush_test_init_with_falloff_shape(ss, &test, data->brush->falloff_shape);
-
- CLAMP(bstrength, 0.0f, 1.0f);
-
- BKE_pbvh_node_get_grids(ss->pbvh, data->nodes[n], &grid_indices, &totgrid, NULL, &gridsize, &griddata);
- BKE_pbvh_get_grid_key(ss->pbvh, &key);
-
- grid_hidden = BKE_pbvh_grid_hidden(ss->pbvh);
-
- if (smooth_mask)
- tmpgrid_mask = (void *)(data_chunk + 1);
- else
- tmpgrid_co = (void *)(data_chunk + 1);
-
- for (i = 0; i < totgrid; i++) {
- int gi = grid_indices[i];
- const BLI_bitmap *gh = grid_hidden[gi];
- gddata = griddata[gi];
-
- if (smooth_mask)
- memset(tmpgrid_mask, 0, data_chunk->tmpgrid_size);
- else
- memset(tmpgrid_co, 0, data_chunk->tmpgrid_size);
-
- for (y = 0; y < gridsize - 1; y++) {
- const int v = y * gridsize;
- if (smooth_mask) {
- tmprow_mask[0] = (*CCG_elem_offset_mask(&key, gddata, v) +
- *CCG_elem_offset_mask(&key, gddata, v + gridsize));
- }
- else {
- add_v3_v3v3(tmprow_co[0],
- CCG_elem_offset_co(&key, gddata, v),
- CCG_elem_offset_co(&key, gddata, v + gridsize));
- }
-
- for (x = 0; x < gridsize - 1; x++) {
- const int v1 = x + y * gridsize;
- const int v2 = v1 + 1;
- const int v3 = v1 + gridsize;
- const int v4 = v3 + 1;
-
- if (smooth_mask) {
- float tmp;
-
- tmprow_mask[(x + 1) % 2] = (*CCG_elem_offset_mask(&key, gddata, v2) +
- *CCG_elem_offset_mask(&key, gddata, v4));
- tmp = tmprow_mask[(x + 1) % 2] + tmprow_mask[x % 2];
-
- tmpgrid_mask[v1] += tmp;
- tmpgrid_mask[v2] += tmp;
- tmpgrid_mask[v3] += tmp;
- tmpgrid_mask[v4] += tmp;
- }
- else {
- float tmp[3];
-
- add_v3_v3v3(tmprow_co[(x + 1) % 2],
- CCG_elem_offset_co(&key, gddata, v2),
- CCG_elem_offset_co(&key, gddata, v4));
- add_v3_v3v3(tmp, tmprow_co[(x + 1) % 2], tmprow_co[x % 2]);
-
- add_v3_v3(tmpgrid_co[v1], tmp);
- add_v3_v3(tmpgrid_co[v2], tmp);
- add_v3_v3(tmpgrid_co[v3], tmp);
- add_v3_v3(tmpgrid_co[v4], tmp);
- }
- }
- }
-
- /* blend with existing coordinates */
- for (y = 0; y < gridsize; y++) {
- for (x = 0; x < gridsize; x++) {
- float *co;
- const float *fno;
- float *mask;
- const int index = y * gridsize + x;
-
- if (gh) {
- if (BLI_BITMAP_TEST(gh, index))
- continue;
- }
-
- co = CCG_elem_offset_co(&key, gddata, index);
- fno = CCG_elem_offset_no(&key, gddata, index);
- mask = CCG_elem_offset_mask(&key, gddata, index);
-
- if (sculpt_brush_test_sq_fn(&test, co)) {
- const float strength_mask = (smooth_mask ? 0.0f : *mask);
- const float fade = bstrength * tex_strength(
- ss, brush, co, sqrtf(test.dist),
- NULL, fno, strength_mask, tls->thread_id);
- float f = 1.0f / 16.0f;
-
- if (x == 0 || x == gridsize - 1)
- f *= 2.0f;
-
- if (y == 0 || y == gridsize - 1)
- f *= 2.0f;
-
- if (smooth_mask) {
- *mask += ((tmpgrid_mask[index] * f) - *mask) * fade;
- }
- else {
- float *avg = tmpgrid_co[index];
- float val[3];
-
- mul_v3_fl(avg, f);
- sub_v3_v3v3(val, avg, co);
- madd_v3_v3v3fl(val, co, val, fade);
-
- sculpt_clip(sd, ss, co, val);
- }
- }
- }
- }
- }
-}
-
-static void smooth(
- Sculpt *sd, Object *ob, PBVHNode **nodes, const int totnode, float bstrength, const bool smooth_mask)
-{
- SculptSession *ss = ob->sculpt;
- Brush *brush = BKE_paint_brush(&sd->paint);
-
- const int max_iterations = 4;
- const float fract = 1.0f / max_iterations;
- PBVHType type = BKE_pbvh_type(ss->pbvh);
- int iteration, count;
- float last;
-
- CLAMP(bstrength, 0.0f, 1.0f);
-
- count = (int)(bstrength * max_iterations);
- last = max_iterations * (bstrength - count * fract);
-
- if (type == PBVH_FACES && !ss->pmap) {
- BLI_assert(!"sculpt smooth: pmap missing");
- return;
- }
-
- for (iteration = 0; iteration <= count; ++iteration) {
- const float strength = (iteration != count) ? 1.0f : last;
-
- SculptThreadedTaskData data = {
- .sd = sd, .ob = ob, .brush = brush, .nodes = nodes,
- .smooth_mask = smooth_mask, .strength = strength,
- };
-
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
-
- switch (type) {
- case PBVH_GRIDS:
- {
- int gridsize;
- size_t size;
- SculptDoBrushSmoothGridDataChunk *data_chunk;
-
- BKE_pbvh_node_get_grids(ss->pbvh, NULL, NULL, NULL, NULL, &gridsize, NULL);
- size = (size_t)gridsize;
- size = sizeof(float) * size * size * (smooth_mask ? 1 : 3);
- data_chunk = MEM_mallocN(sizeof(*data_chunk) + size, __func__);
- data_chunk->tmpgrid_size = size;
- size += sizeof(*data_chunk);
-
- settings.userdata_chunk = data_chunk;
- settings.userdata_chunk_size = size;
- BLI_task_parallel_range(
- 0, totnode,
- &data,
- do_smooth_brush_multires_task_cb_ex,
- &settings);
-
- MEM_freeN(data_chunk);
- break;
- }
- case PBVH_FACES:
- BLI_task_parallel_range(
- 0, totnode,
- &data,
- do_smooth_brush_mesh_task_cb_ex,
- &settings);
- break;
- case PBVH_BMESH:
- BLI_task_parallel_range(
- 0, totnode,
- &data,
- do_smooth_brush_bmesh_task_cb_ex,
- &settings);
- break;
- }
-
- if (ss->multires)
- multires_stitch_grids(ob);
- }
+static void do_smooth_brush_mesh_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const ParallelRangeTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ Sculpt *sd = data->sd;
+ const Brush *brush = data->brush;
+ const bool smooth_mask = data->smooth_mask;
+ float bstrength = data->strength;
+
+ PBVHVertexIter vd;
+
+ CLAMP(bstrength, 0.0f, 1.0f);
+
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = sculpt_brush_test_init_with_falloff_shape(
+ ss, &test, data->brush->falloff_shape);
+
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
+ {
+ if (sculpt_brush_test_sq_fn(&test, vd.co)) {
+ const float fade = bstrength * tex_strength(ss,
+ brush,
+ vd.co,
+ sqrtf(test.dist),
+ vd.no,
+ vd.fno,
+ smooth_mask ? 0.0f : (vd.mask ? *vd.mask : 0.0f),
+ tls->thread_id);
+ if (smooth_mask) {
+ float val = neighbor_average_mask(ss, vd.vert_indices[vd.i]) - *vd.mask;
+ val *= fade * bstrength;
+ *vd.mask += val;
+ CLAMP(*vd.mask, 0.0f, 1.0f);
+ }
+ else {
+ float avg[3], val[3];
+
+ neighbor_average(ss, avg, vd.vert_indices[vd.i]);
+ sub_v3_v3v3(val, avg, vd.co);
+
+ madd_v3_v3v3fl(val, vd.co, val, fade);
+
+ sculpt_clip(sd, ss, vd.co, val);
+ }
+
+ if (vd.mvert)
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+static void do_smooth_brush_bmesh_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const ParallelRangeTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ Sculpt *sd = data->sd;
+ const Brush *brush = data->brush;
+ const bool smooth_mask = data->smooth_mask;
+ float bstrength = data->strength;
+
+ PBVHVertexIter vd;
+
+ CLAMP(bstrength, 0.0f, 1.0f);
+
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = sculpt_brush_test_init_with_falloff_shape(
+ ss, &test, data->brush->falloff_shape);
+
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
+ {
+ if (sculpt_brush_test_sq_fn(&test, vd.co)) {
+ const float fade = bstrength * tex_strength(ss,
+ brush,
+ vd.co,
+ sqrtf(test.dist),
+ vd.no,
+ vd.fno,
+ smooth_mask ? 0.0f : *vd.mask,
+ tls->thread_id);
+ if (smooth_mask) {
+ float val = bmesh_neighbor_average_mask(vd.bm_vert, vd.cd_vert_mask_offset) - *vd.mask;
+ val *= fade * bstrength;
+ *vd.mask += val;
+ CLAMP(*vd.mask, 0.0f, 1.0f);
+ }
+ else {
+ float avg[3], val[3];
+
+ bmesh_neighbor_average(avg, vd.bm_vert);
+ sub_v3_v3v3(val, avg, vd.co);
+
+ madd_v3_v3v3fl(val, vd.co, val, fade);
+
+ sculpt_clip(sd, ss, vd.co, val);
+ }
+
+ if (vd.mvert)
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+static void do_topology_rake_bmesh_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const ParallelRangeTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ Sculpt *sd = data->sd;
+ const Brush *brush = data->brush;
+
+ float direction[3];
+ copy_v3_v3(direction, ss->cache->grab_delta_symmetry);
+
+ float tmp[3];
+ mul_v3_v3fl(
+ tmp, ss->cache->sculpt_normal_symm, dot_v3v3(ss->cache->sculpt_normal_symm, direction));
+ sub_v3_v3(direction, tmp);
+
+ /* Cancel if there's no grab data. */
+ if (is_zero_v3(direction)) {
+ return;
+ }
+
+ float bstrength = data->strength;
+ CLAMP(bstrength, 0.0f, 1.0f);
+
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = sculpt_brush_test_init_with_falloff_shape(
+ ss, &test, data->brush->falloff_shape);
+
+ PBVHVertexIter vd;
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
+ {
+ if (sculpt_brush_test_sq_fn(&test, vd.co)) {
+ const float fade =
+ bstrength *
+ tex_strength(
+ ss, brush, vd.co, sqrtf(test.dist), vd.no, vd.fno, *vd.mask, tls->thread_id) *
+ ss->cache->pressure;
+
+ float avg[3], val[3];
+
+ bmesh_four_neighbor_average(avg, direction, vd.bm_vert);
+
+ sub_v3_v3v3(val, avg, vd.co);
+
+ madd_v3_v3v3fl(val, vd.co, val, fade);
+
+ sculpt_clip(sd, ss, vd.co, val);
+
+ if (vd.mvert)
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+static void do_smooth_brush_multires_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const ParallelRangeTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptDoBrushSmoothGridDataChunk *data_chunk = tls->userdata_chunk;
+ SculptSession *ss = data->ob->sculpt;
+ Sculpt *sd = data->sd;
+ const Brush *brush = data->brush;
+ const bool smooth_mask = data->smooth_mask;
+ float bstrength = data->strength;
+
+ CCGElem **griddata, *gddata;
+ CCGKey key;
+
+ float(*tmpgrid_co)[3] = NULL;
+ float tmprow_co[2][3];
+ float *tmpgrid_mask = NULL;
+ float tmprow_mask[2];
+
+ BLI_bitmap *const *grid_hidden;
+ int *grid_indices, totgrid, gridsize;
+ int i, x, y;
+
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = sculpt_brush_test_init_with_falloff_shape(
+ ss, &test, data->brush->falloff_shape);
+
+ CLAMP(bstrength, 0.0f, 1.0f);
+
+ BKE_pbvh_node_get_grids(
+ ss->pbvh, data->nodes[n], &grid_indices, &totgrid, NULL, &gridsize, &griddata);
+ BKE_pbvh_get_grid_key(ss->pbvh, &key);
+
+ grid_hidden = BKE_pbvh_grid_hidden(ss->pbvh);
+
+ if (smooth_mask)
+ tmpgrid_mask = (void *)(data_chunk + 1);
+ else
+ tmpgrid_co = (void *)(data_chunk + 1);
+
+ for (i = 0; i < totgrid; i++) {
+ int gi = grid_indices[i];
+ const BLI_bitmap *gh = grid_hidden[gi];
+ gddata = griddata[gi];
+
+ if (smooth_mask)
+ memset(tmpgrid_mask, 0, data_chunk->tmpgrid_size);
+ else
+ memset(tmpgrid_co, 0, data_chunk->tmpgrid_size);
+
+ for (y = 0; y < gridsize - 1; y++) {
+ const int v = y * gridsize;
+ if (smooth_mask) {
+ tmprow_mask[0] = (*CCG_elem_offset_mask(&key, gddata, v) +
+ *CCG_elem_offset_mask(&key, gddata, v + gridsize));
+ }
+ else {
+ add_v3_v3v3(tmprow_co[0],
+ CCG_elem_offset_co(&key, gddata, v),
+ CCG_elem_offset_co(&key, gddata, v + gridsize));
+ }
+
+ for (x = 0; x < gridsize - 1; x++) {
+ const int v1 = x + y * gridsize;
+ const int v2 = v1 + 1;
+ const int v3 = v1 + gridsize;
+ const int v4 = v3 + 1;
+
+ if (smooth_mask) {
+ float tmp;
+
+ tmprow_mask[(x + 1) % 2] = (*CCG_elem_offset_mask(&key, gddata, v2) +
+ *CCG_elem_offset_mask(&key, gddata, v4));
+ tmp = tmprow_mask[(x + 1) % 2] + tmprow_mask[x % 2];
+
+ tmpgrid_mask[v1] += tmp;
+ tmpgrid_mask[v2] += tmp;
+ tmpgrid_mask[v3] += tmp;
+ tmpgrid_mask[v4] += tmp;
+ }
+ else {
+ float tmp[3];
+
+ add_v3_v3v3(tmprow_co[(x + 1) % 2],
+ CCG_elem_offset_co(&key, gddata, v2),
+ CCG_elem_offset_co(&key, gddata, v4));
+ add_v3_v3v3(tmp, tmprow_co[(x + 1) % 2], tmprow_co[x % 2]);
+
+ add_v3_v3(tmpgrid_co[v1], tmp);
+ add_v3_v3(tmpgrid_co[v2], tmp);
+ add_v3_v3(tmpgrid_co[v3], tmp);
+ add_v3_v3(tmpgrid_co[v4], tmp);
+ }
+ }
+ }
+
+ /* blend with existing coordinates */
+ for (y = 0; y < gridsize; y++) {
+ for (x = 0; x < gridsize; x++) {
+ float *co;
+ const float *fno;
+ float *mask;
+ const int index = y * gridsize + x;
+
+ if (gh) {
+ if (BLI_BITMAP_TEST(gh, index))
+ continue;
+ }
+
+ co = CCG_elem_offset_co(&key, gddata, index);
+ fno = CCG_elem_offset_no(&key, gddata, index);
+ mask = CCG_elem_offset_mask(&key, gddata, index);
+
+ if (sculpt_brush_test_sq_fn(&test, co)) {
+ const float strength_mask = (smooth_mask ? 0.0f : *mask);
+ const float fade =
+ bstrength *
+ tex_strength(
+ ss, brush, co, sqrtf(test.dist), NULL, fno, strength_mask, tls->thread_id);
+ float f = 1.0f / 16.0f;
+
+ if (x == 0 || x == gridsize - 1)
+ f *= 2.0f;
+
+ if (y == 0 || y == gridsize - 1)
+ f *= 2.0f;
+
+ if (smooth_mask) {
+ *mask += ((tmpgrid_mask[index] * f) - *mask) * fade;
+ }
+ else {
+ float *avg = tmpgrid_co[index];
+ float val[3];
+
+ mul_v3_fl(avg, f);
+ sub_v3_v3v3(val, avg, co);
+ madd_v3_v3v3fl(val, co, val, fade);
+
+ sculpt_clip(sd, ss, co, val);
+ }
+ }
+ }
+ }
+ }
+}
+
+static void smooth(Sculpt *sd,
+ Object *ob,
+ PBVHNode **nodes,
+ const int totnode,
+ float bstrength,
+ const bool smooth_mask)
+{
+ SculptSession *ss = ob->sculpt;
+ Brush *brush = BKE_paint_brush(&sd->paint);
+
+ const int max_iterations = 4;
+ const float fract = 1.0f / max_iterations;
+ PBVHType type = BKE_pbvh_type(ss->pbvh);
+ int iteration, count;
+ float last;
+
+ CLAMP(bstrength, 0.0f, 1.0f);
+
+ count = (int)(bstrength * max_iterations);
+ last = max_iterations * (bstrength - count * fract);
+
+ if (type == PBVH_FACES && !ss->pmap) {
+ BLI_assert(!"sculpt smooth: pmap missing");
+ return;
+ }
+
+ for (iteration = 0; iteration <= count; ++iteration) {
+ const float strength = (iteration != count) ? 1.0f : last;
+
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ .smooth_mask = smooth_mask,
+ .strength = strength,
+ };
+
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
+
+ switch (type) {
+ case PBVH_GRIDS: {
+ int gridsize;
+ size_t size;
+ SculptDoBrushSmoothGridDataChunk *data_chunk;
+
+ BKE_pbvh_node_get_grids(ss->pbvh, NULL, NULL, NULL, NULL, &gridsize, NULL);
+ size = (size_t)gridsize;
+ size = sizeof(float) * size * size * (smooth_mask ? 1 : 3);
+ data_chunk = MEM_mallocN(sizeof(*data_chunk) + size, __func__);
+ data_chunk->tmpgrid_size = size;
+ size += sizeof(*data_chunk);
+
+ settings.userdata_chunk = data_chunk;
+ settings.userdata_chunk_size = size;
+ BLI_task_parallel_range(0, totnode, &data, do_smooth_brush_multires_task_cb_ex, &settings);
+
+ MEM_freeN(data_chunk);
+ break;
+ }
+ case PBVH_FACES:
+ BLI_task_parallel_range(0, totnode, &data, do_smooth_brush_mesh_task_cb_ex, &settings);
+ break;
+ case PBVH_BMESH:
+ BLI_task_parallel_range(0, totnode, &data, do_smooth_brush_bmesh_task_cb_ex, &settings);
+ break;
+ }
+
+ if (ss->multires)
+ multires_stitch_grids(ob);
+ }
}
static void bmesh_topology_rake(
- Sculpt *sd, Object *ob, PBVHNode **nodes, const int totnode, float bstrength)
+ Sculpt *sd, Object *ob, PBVHNode **nodes, const int totnode, float bstrength)
{
- Brush *brush = BKE_paint_brush(&sd->paint);
- CLAMP(bstrength, 0.0f, 1.0f);
+ Brush *brush = BKE_paint_brush(&sd->paint);
+ CLAMP(bstrength, 0.0f, 1.0f);
- /* Interactions increase both strength and quality. */
- const int iterations = 3;
+ /* Interactions increase both strength and quality. */
+ const int iterations = 3;
- int iteration;
- const int count = iterations * bstrength + 1;
- const float factor = iterations * bstrength / count;
+ int iteration;
+ const int count = iterations * bstrength + 1;
+ const float factor = iterations * bstrength / count;
- for (iteration = 0; iteration <= count; ++iteration) {
+ for (iteration = 0; iteration <= count; ++iteration) {
- SculptThreadedTaskData data = {
- .sd = sd, .ob = ob, .brush = brush, .nodes = nodes,
- .strength = factor,
- };
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ .strength = factor,
+ };
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
- BLI_task_parallel_range(
- 0, totnode,
- &data,
- do_topology_rake_bmesh_task_cb_ex,
- &settings);
- }
+ BLI_task_parallel_range(0, totnode, &data, do_topology_rake_bmesh_task_cb_ex, &settings);
+ }
}
static void do_smooth_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
{
- SculptSession *ss = ob->sculpt;
- smooth(sd, ob, nodes, totnode, ss->cache->bstrength, false);
+ SculptSession *ss = ob->sculpt;
+ smooth(sd, ob, nodes, totnode, ss->cache->bstrength, false);
}
-static void do_mask_brush_draw_task_cb_ex(
- void *__restrict userdata,
- const int n,
- const ParallelRangeTLS *__restrict tls)
+static void do_mask_brush_draw_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const ParallelRangeTLS *__restrict tls)
{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- const Brush *brush = data->brush;
- const float bstrength = ss->cache->bstrength;
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ const Brush *brush = data->brush;
+ const float bstrength = ss->cache->bstrength;
- PBVHVertexIter vd;
+ PBVHVertexIter vd;
- SculptBrushTest test;
- SculptBrushTestFn sculpt_brush_test_sq_fn =
- sculpt_brush_test_init_with_falloff_shape(ss, &test, data->brush->falloff_shape);
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = sculpt_brush_test_init_with_falloff_shape(
+ ss, &test, data->brush->falloff_shape);
- BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
- {
- if (sculpt_brush_test_sq_fn(&test, vd.co)) {
- const float fade = tex_strength(
- ss, brush, vd.co, sqrtf(test.dist),
- vd.no, vd.fno, 0.0f, tls->thread_id);
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
+ {
+ if (sculpt_brush_test_sq_fn(&test, vd.co)) {
+ const float fade = tex_strength(
+ ss, brush, vd.co, sqrtf(test.dist), vd.no, vd.fno, 0.0f, tls->thread_id);
- (*vd.mask) += fade * bstrength;
- CLAMP(*vd.mask, 0, 1);
+ (*vd.mask) += fade * bstrength;
+ CLAMP(*vd.mask, 0, 1);
- if (vd.mvert)
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- BKE_pbvh_vertex_iter_end;
- }
+ if (vd.mvert)
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ BKE_pbvh_vertex_iter_end;
+ }
}
static void do_mask_brush_draw(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
{
- Brush *brush = BKE_paint_brush(&sd->paint);
+ Brush *brush = BKE_paint_brush(&sd->paint);
- /* threaded loop over nodes */
- SculptThreadedTaskData data = {
- .sd = sd, .ob = ob, .brush = brush, .nodes = nodes,
- };
+ /* threaded loop over nodes */
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ };
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
- BLI_task_parallel_range(
- 0, totnode,
- &data,
- do_mask_brush_draw_task_cb_ex,
- &settings);
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
+ BLI_task_parallel_range(0, totnode, &data, do_mask_brush_draw_task_cb_ex, &settings);
}
static void do_mask_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
{
- SculptSession *ss = ob->sculpt;
- Brush *brush = BKE_paint_brush(&sd->paint);
+ SculptSession *ss = ob->sculpt;
+ Brush *brush = BKE_paint_brush(&sd->paint);
- switch ((BrushMaskTool)brush->mask_tool) {
- case BRUSH_MASK_DRAW:
- do_mask_brush_draw(sd, ob, nodes, totnode);
- break;
- case BRUSH_MASK_SMOOTH:
- smooth(sd, ob, nodes, totnode, ss->cache->bstrength, true);
- break;
- }
+ switch ((BrushMaskTool)brush->mask_tool) {
+ case BRUSH_MASK_DRAW:
+ do_mask_brush_draw(sd, ob, nodes, totnode);
+ break;
+ case BRUSH_MASK_SMOOTH:
+ smooth(sd, ob, nodes, totnode, ss->cache->bstrength, true);
+ break;
+ }
}
-static void do_draw_brush_task_cb_ex(
- void *__restrict userdata,
- const int n,
- const ParallelRangeTLS *__restrict tls)
+static void do_draw_brush_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const ParallelRangeTLS *__restrict tls)
{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- const Brush *brush = data->brush;
- const float *offset = data->offset;
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ const Brush *brush = data->brush;
+ const float *offset = data->offset;
- PBVHVertexIter vd;
- float (*proxy)[3];
+ PBVHVertexIter vd;
+ float(*proxy)[3];
- proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
+ 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(ss, &test, data->brush->falloff_shape);
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = sculpt_brush_test_init_with_falloff_shape(
+ ss, &test, data->brush->falloff_shape);
- BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
- {
- if (sculpt_brush_test_sq_fn(&test, vd.co)) {
- /* offset vertex */
- const float fade = tex_strength(
- ss, brush, vd.co, sqrtf(test.dist),
- vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, tls->thread_id);
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
+ {
+ if (sculpt_brush_test_sq_fn(&test, vd.co)) {
+ /* offset vertex */
+ const float fade = tex_strength(ss,
+ brush,
+ vd.co,
+ sqrtf(test.dist),
+ vd.no,
+ vd.fno,
+ vd.mask ? *vd.mask : 0.0f,
+ tls->thread_id);
- mul_v3_v3fl(proxy[vd.i], offset, fade);
+ mul_v3_v3fl(proxy[vd.i], offset, fade);
- if (vd.mvert)
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- BKE_pbvh_vertex_iter_end;
+ if (vd.mvert)
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
}
static void do_draw_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
{
- SculptSession *ss = ob->sculpt;
- Brush *brush = BKE_paint_brush(&sd->paint);
- float offset[3];
- const float bstrength = ss->cache->bstrength;
+ SculptSession *ss = ob->sculpt;
+ Brush *brush = BKE_paint_brush(&sd->paint);
+ float offset[3];
+ const float bstrength = ss->cache->bstrength;
- /* offset with as much as possible factored in already */
- mul_v3_v3fl(offset, ss->cache->sculpt_normal_symm, ss->cache->radius);
- mul_v3_v3(offset, ss->cache->scale);
- mul_v3_fl(offset, bstrength);
+ /* offset with as much as possible factored in already */
+ mul_v3_v3fl(offset, ss->cache->sculpt_normal_symm, ss->cache->radius);
+ mul_v3_v3(offset, ss->cache->scale);
+ mul_v3_fl(offset, bstrength);
- /* XXX - this shouldn't be necessary, but sculpting crashes in blender2.8 otherwise
- * initialize before threads so they can do curve mapping */
- curvemapping_initialize(brush->curve);
+ /* XXX - this shouldn't be necessary, but sculpting crashes in blender2.8 otherwise
+ * initialize before threads so they can do curve mapping */
+ curvemapping_initialize(brush->curve);
- /* threaded loop over nodes */
- SculptThreadedTaskData data = {
- .sd = sd, .ob = ob, .brush = brush, .nodes = nodes,
- .offset = offset,
- };
+ /* threaded loop over nodes */
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ .offset = offset,
+ };
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
- BLI_task_parallel_range(
- 0, totnode,
- &data,
- do_draw_brush_task_cb_ex,
- &settings);
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
+ BLI_task_parallel_range(0, totnode, &data, do_draw_brush_task_cb_ex, &settings);
}
/**
* Used for 'SCULPT_TOOL_CREASE' and 'SCULPT_TOOL_BLOB'
*/
-static void do_crease_brush_task_cb_ex(
- void *__restrict userdata,
- const int n,
- const ParallelRangeTLS *__restrict tls)
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- const Brush *brush = data->brush;
- SculptProjectVector *spvc = data->spvc;
- const float flippedbstrength = data->flippedbstrength;
- const float *offset = data->offset;
-
- PBVHVertexIter vd;
- float (*proxy)[3];
-
- 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(ss, &test, data->brush->falloff_shape);
-
- BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
- {
- if (sculpt_brush_test_sq_fn(&test, vd.co)) {
- /* offset vertex */
- const float fade = tex_strength(
- ss, brush, vd.co, sqrtf(test.dist),
- vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, tls->thread_id);
- float val1[3];
- float val2[3];
-
- /* first we pinch */
- sub_v3_v3v3(val1, test.location, vd.co);
- if (brush->falloff_shape == PAINT_FALLOFF_SHAPE_TUBE) {
- project_plane_v3_v3v3(val1, val1, ss->cache->view_normal);
- }
-
- mul_v3_fl(val1, fade * flippedbstrength);
-
- sculpt_project_v3(spvc, val1, val1);
-
- /* then we draw */
- mul_v3_v3fl(val2, offset, fade);
-
- add_v3_v3v3(proxy[vd.i], val1, val2);
-
- if (vd.mvert)
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- BKE_pbvh_vertex_iter_end;
+static void do_crease_brush_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const ParallelRangeTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ const Brush *brush = data->brush;
+ SculptProjectVector *spvc = data->spvc;
+ const float flippedbstrength = data->flippedbstrength;
+ const float *offset = data->offset;
+
+ PBVHVertexIter vd;
+ float(*proxy)[3];
+
+ 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(
+ ss, &test, data->brush->falloff_shape);
+
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
+ {
+ if (sculpt_brush_test_sq_fn(&test, vd.co)) {
+ /* offset vertex */
+ const float fade = tex_strength(ss,
+ brush,
+ vd.co,
+ sqrtf(test.dist),
+ vd.no,
+ vd.fno,
+ vd.mask ? *vd.mask : 0.0f,
+ tls->thread_id);
+ float val1[3];
+ float val2[3];
+
+ /* first we pinch */
+ sub_v3_v3v3(val1, test.location, vd.co);
+ if (brush->falloff_shape == PAINT_FALLOFF_SHAPE_TUBE) {
+ project_plane_v3_v3v3(val1, val1, ss->cache->view_normal);
+ }
+
+ mul_v3_fl(val1, fade * flippedbstrength);
+
+ sculpt_project_v3(spvc, val1, val1);
+
+ /* then we draw */
+ mul_v3_v3fl(val2, offset, fade);
+
+ add_v3_v3v3(proxy[vd.i], val1, val2);
+
+ if (vd.mvert)
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
}
static void do_crease_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
{
- SculptSession *ss = ob->sculpt;
- const Scene *scene = ss->cache->vc->scene;
- Brush *brush = BKE_paint_brush(&sd->paint);
- float offset[3];
- float bstrength = ss->cache->bstrength;
- float flippedbstrength, crease_correction;
- float brush_alpha;
-
- SculptProjectVector spvc;
-
- /* offset with as much as possible factored in already */
- mul_v3_v3fl(offset, ss->cache->sculpt_normal_symm, ss->cache->radius);
- mul_v3_v3(offset, ss->cache->scale);
- mul_v3_fl(offset, bstrength);
-
- /* we divide out the squared alpha and multiply by the squared crease to give us the pinch strength */
- crease_correction = brush->crease_pinch_factor * brush->crease_pinch_factor;
- brush_alpha = BKE_brush_alpha_get(scene, brush);
- if (brush_alpha > 0.0f)
- crease_correction /= brush_alpha * brush_alpha;
-
- /* we always want crease to pinch or blob to relax even when draw is negative */
- flippedbstrength = (bstrength < 0) ? -crease_correction * bstrength : crease_correction * bstrength;
-
- if (brush->sculpt_tool == SCULPT_TOOL_BLOB) flippedbstrength *= -1.0f;
-
- /* Use surface normal for 'spvc', so the vertices are pinched towards a line instead of a single point.
- * Without this we get a 'flat' surface surrounding the pinch */
- sculpt_project_v3_cache_init(&spvc, ss->cache->sculpt_normal_symm);
-
- /* threaded loop over nodes */
- SculptThreadedTaskData data = {
- .sd = sd, .ob = ob, .brush = brush, .nodes = nodes,
- .spvc = &spvc, .offset = offset, .flippedbstrength = flippedbstrength,
- };
-
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
- BLI_task_parallel_range(
- 0, totnode,
- &data,
- do_crease_brush_task_cb_ex,
- &settings);
-}
-
-static void do_pinch_brush_task_cb_ex(
- void *__restrict userdata,
- const int n,
- const ParallelRangeTLS *__restrict tls)
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- const Brush *brush = data->brush;
-
- PBVHVertexIter vd;
- float (*proxy)[3];
- const float bstrength = ss->cache->bstrength;
-
- 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(ss, &test, data->brush->falloff_shape);
-
- BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
- {
- if (sculpt_brush_test_sq_fn(&test, vd.co)) {
- const float fade = bstrength * tex_strength(
- ss, brush, vd.co, sqrtf(test.dist),
- vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, tls->thread_id);
- float val[3];
-
- sub_v3_v3v3(val, test.location, vd.co);
- if (brush->falloff_shape == PAINT_FALLOFF_SHAPE_TUBE) {
- project_plane_v3_v3v3(val, val, ss->cache->view_normal);
- }
- mul_v3_v3fl(proxy[vd.i], val, fade);
-
- if (vd.mvert)
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- BKE_pbvh_vertex_iter_end;
+ SculptSession *ss = ob->sculpt;
+ const Scene *scene = ss->cache->vc->scene;
+ Brush *brush = BKE_paint_brush(&sd->paint);
+ float offset[3];
+ float bstrength = ss->cache->bstrength;
+ float flippedbstrength, crease_correction;
+ float brush_alpha;
+
+ SculptProjectVector spvc;
+
+ /* offset with as much as possible factored in already */
+ mul_v3_v3fl(offset, ss->cache->sculpt_normal_symm, ss->cache->radius);
+ mul_v3_v3(offset, ss->cache->scale);
+ mul_v3_fl(offset, bstrength);
+
+ /* we divide out the squared alpha and multiply by the squared crease to give us the pinch strength */
+ crease_correction = brush->crease_pinch_factor * brush->crease_pinch_factor;
+ brush_alpha = BKE_brush_alpha_get(scene, brush);
+ if (brush_alpha > 0.0f)
+ crease_correction /= brush_alpha * brush_alpha;
+
+ /* we always want crease to pinch or blob to relax even when draw is negative */
+ flippedbstrength = (bstrength < 0) ? -crease_correction * bstrength :
+ crease_correction * bstrength;
+
+ if (brush->sculpt_tool == SCULPT_TOOL_BLOB)
+ flippedbstrength *= -1.0f;
+
+ /* Use surface normal for 'spvc', so the vertices are pinched towards a line instead of a single point.
+ * Without this we get a 'flat' surface surrounding the pinch */
+ sculpt_project_v3_cache_init(&spvc, ss->cache->sculpt_normal_symm);
+
+ /* threaded loop over nodes */
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ .spvc = &spvc,
+ .offset = offset,
+ .flippedbstrength = flippedbstrength,
+ };
+
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
+ BLI_task_parallel_range(0, totnode, &data, do_crease_brush_task_cb_ex, &settings);
+}
+
+static void do_pinch_brush_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const ParallelRangeTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ const Brush *brush = data->brush;
+
+ PBVHVertexIter vd;
+ float(*proxy)[3];
+ const float bstrength = ss->cache->bstrength;
+
+ 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(
+ ss, &test, data->brush->falloff_shape);
+
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
+ {
+ if (sculpt_brush_test_sq_fn(&test, vd.co)) {
+ const float fade = bstrength * tex_strength(ss,
+ brush,
+ vd.co,
+ sqrtf(test.dist),
+ vd.no,
+ vd.fno,
+ vd.mask ? *vd.mask : 0.0f,
+ tls->thread_id);
+ float val[3];
+
+ sub_v3_v3v3(val, test.location, vd.co);
+ if (brush->falloff_shape == PAINT_FALLOFF_SHAPE_TUBE) {
+ project_plane_v3_v3v3(val, val, ss->cache->view_normal);
+ }
+ mul_v3_v3fl(proxy[vd.i], val, fade);
+
+ if (vd.mvert)
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
}
static void do_pinch_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
{
- Brush *brush = BKE_paint_brush(&sd->paint);
+ Brush *brush = BKE_paint_brush(&sd->paint);
- SculptThreadedTaskData data = {
- .sd = sd, .ob = ob, .brush = brush, .nodes = nodes,
- };
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ };
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
- BLI_task_parallel_range(
- 0, totnode,
- &data,
- do_pinch_brush_task_cb_ex,
- &settings);
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
+ BLI_task_parallel_range(0, totnode, &data, do_pinch_brush_task_cb_ex, &settings);
}
-static void do_grab_brush_task_cb_ex(
- void *__restrict userdata,
- const int n,
- const ParallelRangeTLS *__restrict tls)
+static void do_grab_brush_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const ParallelRangeTLS *__restrict tls)
{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- const Brush *brush = data->brush;
- const float *grab_delta = data->grab_delta;
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ const Brush *brush = data->brush;
+ const float *grab_delta = data->grab_delta;
- PBVHVertexIter vd;
- SculptOrigVertData orig_data;
- float (*proxy)[3];
- const float bstrength = ss->cache->bstrength;
+ PBVHVertexIter vd;
+ SculptOrigVertData orig_data;
+ float(*proxy)[3];
+ const float bstrength = ss->cache->bstrength;
- sculpt_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
+ sculpt_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
- proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
+ 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(ss, &test, data->brush->falloff_shape);
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = sculpt_brush_test_init_with_falloff_shape(
+ ss, &test, data->brush->falloff_shape);
- BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
- {
- sculpt_orig_vert_data_update(&orig_data, &vd);
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
+ {
+ sculpt_orig_vert_data_update(&orig_data, &vd);
- if (sculpt_brush_test_sq_fn(&test, orig_data.co)) {
- const float fade = bstrength * tex_strength(
- ss, brush, orig_data.co, sqrtf(test.dist),
- orig_data.no, NULL, vd.mask ? *vd.mask : 0.0f, tls->thread_id);
+ if (sculpt_brush_test_sq_fn(&test, orig_data.co)) {
+ const float fade = bstrength * tex_strength(ss,
+ brush,
+ orig_data.co,
+ sqrtf(test.dist),
+ orig_data.no,
+ NULL,
+ vd.mask ? *vd.mask : 0.0f,
+ tls->thread_id);
- mul_v3_v3fl(proxy[vd.i], grab_delta, fade);
+ mul_v3_v3fl(proxy[vd.i], grab_delta, fade);
- if (vd.mvert)
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- BKE_pbvh_vertex_iter_end;
+ if (vd.mvert)
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
}
static void do_grab_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
{
- SculptSession *ss = ob->sculpt;
- Brush *brush = BKE_paint_brush(&sd->paint);
- float grab_delta[3];
+ SculptSession *ss = ob->sculpt;
+ Brush *brush = BKE_paint_brush(&sd->paint);
+ float grab_delta[3];
- copy_v3_v3(grab_delta, ss->cache->grab_delta_symmetry);
+ copy_v3_v3(grab_delta, ss->cache->grab_delta_symmetry);
- if (ss->cache->normal_weight > 0.0f) {
- sculpt_project_v3_normal_align(ss, ss->cache->normal_weight, grab_delta);
- }
+ if (ss->cache->normal_weight > 0.0f) {
+ sculpt_project_v3_normal_align(ss, ss->cache->normal_weight, grab_delta);
+ }
- SculptThreadedTaskData data = {
- .sd = sd, .ob = ob, .brush = brush, .nodes = nodes,
- .grab_delta = grab_delta,
- };
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ .grab_delta = grab_delta,
+ };
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
- BLI_task_parallel_range(
- 0, totnode,
- &data,
- do_grab_brush_task_cb_ex,
- &settings);
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
+ BLI_task_parallel_range(0, totnode, &data, do_grab_brush_task_cb_ex, &settings);
}
-static void do_nudge_brush_task_cb_ex(
- void *__restrict userdata,
- const int n,
- const ParallelRangeTLS *__restrict tls)
+static void do_nudge_brush_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const ParallelRangeTLS *__restrict tls)
{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- const Brush *brush = data->brush;
- const float *cono = data->cono;
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ const Brush *brush = data->brush;
+ const float *cono = data->cono;
- PBVHVertexIter vd;
- float (*proxy)[3];
- const float bstrength = ss->cache->bstrength;
+ PBVHVertexIter vd;
+ float(*proxy)[3];
+ const float bstrength = ss->cache->bstrength;
- proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
+ 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(ss, &test, data->brush->falloff_shape);
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = sculpt_brush_test_init_with_falloff_shape(
+ ss, &test, data->brush->falloff_shape);
- BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
- {
- if (sculpt_brush_test_sq_fn(&test, vd.co)) {
- const float fade = bstrength * tex_strength(
- ss, brush, vd.co, sqrtf(test.dist),
- vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, tls->thread_id);
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
+ {
+ if (sculpt_brush_test_sq_fn(&test, vd.co)) {
+ const float fade = bstrength * tex_strength(ss,
+ brush,
+ vd.co,
+ sqrtf(test.dist),
+ vd.no,
+ vd.fno,
+ vd.mask ? *vd.mask : 0.0f,
+ tls->thread_id);
- mul_v3_v3fl(proxy[vd.i], cono, fade);
+ mul_v3_v3fl(proxy[vd.i], cono, fade);
- if (vd.mvert)
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- BKE_pbvh_vertex_iter_end;
+ if (vd.mvert)
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
}
static void do_nudge_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
{
- SculptSession *ss = ob->sculpt;
- Brush *brush = BKE_paint_brush(&sd->paint);
- float grab_delta[3];
- float tmp[3], cono[3];
-
- copy_v3_v3(grab_delta, ss->cache->grab_delta_symmetry);
-
- cross_v3_v3v3(tmp, ss->cache->sculpt_normal_symm, grab_delta);
- cross_v3_v3v3(cono, tmp, ss->cache->sculpt_normal_symm);
-
- SculptThreadedTaskData data = {
- .sd = sd, .ob = ob, .brush = brush, .nodes = nodes,
- .cono = cono,
- };
-
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
- BLI_task_parallel_range(
- 0, totnode,
- &data,
- do_nudge_brush_task_cb_ex,
- &settings);
-}
-
-static void do_snake_hook_brush_task_cb_ex(
- void *__restrict userdata,
- const int n,
- const ParallelRangeTLS *__restrict tls)
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- const Brush *brush = data->brush;
- SculptProjectVector *spvc = data->spvc;
- const float *grab_delta = data->grab_delta;
-
- PBVHVertexIter vd;
- float (*proxy)[3];
- const float bstrength = ss->cache->bstrength;
- const bool do_rake_rotation = ss->cache->is_rake_rotation_valid;
- const bool do_pinch = (brush->crease_pinch_factor != 0.5f);
- const float pinch = do_pinch ?
- (2.0f * (0.5f - brush->crease_pinch_factor) * (len_v3(grab_delta) / ss->cache->radius)) : 0.0f;
-
- 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(ss, &test, data->brush->falloff_shape);
-
- BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
- {
- if (sculpt_brush_test_sq_fn(&test, vd.co)) {
- const float fade = bstrength * tex_strength(
- ss, brush, vd.co, sqrtf(test.dist),
- vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, tls->thread_id);
-
- mul_v3_v3fl(proxy[vd.i], grab_delta, fade);
-
- /* negative pinch will inflate, helps maintain volume */
- if (do_pinch) {
- float delta_pinch_init[3], delta_pinch[3];
-
- sub_v3_v3v3(delta_pinch, vd.co, test.location);
- if (brush->falloff_shape == PAINT_FALLOFF_SHAPE_TUBE) {
- project_plane_v3_v3v3(delta_pinch, delta_pinch, ss->cache->true_view_normal);
- }
-
- /* important to calculate based on the grabbed location
- * (intentionally ignore fade here). */
- add_v3_v3(delta_pinch, grab_delta);
-
- sculpt_project_v3(spvc, delta_pinch, delta_pinch);
-
- copy_v3_v3(delta_pinch_init, delta_pinch);
-
- float pinch_fade = pinch * fade;
- /* when reducing, scale reduction back by how close to the center we are,
- * so we don't pinch into nothingness */
- if (pinch > 0.0f) {
- /* square to have even less impact for close vertices */
- pinch_fade *= pow2f(min_ff(1.0f, len_v3(delta_pinch) / ss->cache->radius));
- }
- mul_v3_fl(delta_pinch, 1.0f + pinch_fade);
- sub_v3_v3v3(delta_pinch, delta_pinch_init, delta_pinch);
- add_v3_v3(proxy[vd.i], delta_pinch);
- }
-
- if (do_rake_rotation) {
- float delta_rotate[3];
- sculpt_rake_rotate(ss, test.location, vd.co, fade, delta_rotate);
- add_v3_v3(proxy[vd.i], delta_rotate);
- }
-
- if (vd.mvert)
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- BKE_pbvh_vertex_iter_end;
+ SculptSession *ss = ob->sculpt;
+ Brush *brush = BKE_paint_brush(&sd->paint);
+ float grab_delta[3];
+ float tmp[3], cono[3];
+
+ copy_v3_v3(grab_delta, ss->cache->grab_delta_symmetry);
+
+ cross_v3_v3v3(tmp, ss->cache->sculpt_normal_symm, grab_delta);
+ cross_v3_v3v3(cono, tmp, ss->cache->sculpt_normal_symm);
+
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ .cono = cono,
+ };
+
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
+ BLI_task_parallel_range(0, totnode, &data, do_nudge_brush_task_cb_ex, &settings);
+}
+
+static void do_snake_hook_brush_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const ParallelRangeTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ const Brush *brush = data->brush;
+ SculptProjectVector *spvc = data->spvc;
+ const float *grab_delta = data->grab_delta;
+
+ PBVHVertexIter vd;
+ float(*proxy)[3];
+ const float bstrength = ss->cache->bstrength;
+ const bool do_rake_rotation = ss->cache->is_rake_rotation_valid;
+ const bool do_pinch = (brush->crease_pinch_factor != 0.5f);
+ const float pinch = do_pinch ? (2.0f * (0.5f - brush->crease_pinch_factor) *
+ (len_v3(grab_delta) / ss->cache->radius)) :
+ 0.0f;
+
+ 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(
+ ss, &test, data->brush->falloff_shape);
+
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
+ {
+ if (sculpt_brush_test_sq_fn(&test, vd.co)) {
+ const float fade = bstrength * tex_strength(ss,
+ brush,
+ vd.co,
+ sqrtf(test.dist),
+ vd.no,
+ vd.fno,
+ vd.mask ? *vd.mask : 0.0f,
+ tls->thread_id);
+
+ mul_v3_v3fl(proxy[vd.i], grab_delta, fade);
+
+ /* negative pinch will inflate, helps maintain volume */
+ if (do_pinch) {
+ float delta_pinch_init[3], delta_pinch[3];
+
+ sub_v3_v3v3(delta_pinch, vd.co, test.location);
+ if (brush->falloff_shape == PAINT_FALLOFF_SHAPE_TUBE) {
+ project_plane_v3_v3v3(delta_pinch, delta_pinch, ss->cache->true_view_normal);
+ }
+
+ /* important to calculate based on the grabbed location
+ * (intentionally ignore fade here). */
+ add_v3_v3(delta_pinch, grab_delta);
+
+ sculpt_project_v3(spvc, delta_pinch, delta_pinch);
+
+ copy_v3_v3(delta_pinch_init, delta_pinch);
+
+ float pinch_fade = pinch * fade;
+ /* when reducing, scale reduction back by how close to the center we are,
+ * so we don't pinch into nothingness */
+ if (pinch > 0.0f) {
+ /* square to have even less impact for close vertices */
+ pinch_fade *= pow2f(min_ff(1.0f, len_v3(delta_pinch) / ss->cache->radius));
+ }
+ mul_v3_fl(delta_pinch, 1.0f + pinch_fade);
+ sub_v3_v3v3(delta_pinch, delta_pinch_init, delta_pinch);
+ add_v3_v3(proxy[vd.i], delta_pinch);
+ }
+
+ if (do_rake_rotation) {
+ float delta_rotate[3];
+ sculpt_rake_rotate(ss, test.location, vd.co, fade, delta_rotate);
+ add_v3_v3(proxy[vd.i], delta_rotate);
+ }
+
+ if (vd.mvert)
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
}
static void do_snake_hook_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
{
- SculptSession *ss = ob->sculpt;
- Brush *brush = BKE_paint_brush(&sd->paint);
- const float bstrength = ss->cache->bstrength;
- float grab_delta[3];
+ SculptSession *ss = ob->sculpt;
+ Brush *brush = BKE_paint_brush(&sd->paint);
+ const float bstrength = ss->cache->bstrength;
+ float grab_delta[3];
- SculptProjectVector spvc;
+ SculptProjectVector spvc;
- copy_v3_v3(grab_delta, ss->cache->grab_delta_symmetry);
+ copy_v3_v3(grab_delta, ss->cache->grab_delta_symmetry);
- if (bstrength < 0)
- negate_v3(grab_delta);
+ if (bstrength < 0)
+ negate_v3(grab_delta);
- if (ss->cache->normal_weight > 0.0f) {
- sculpt_project_v3_normal_align(ss, ss->cache->normal_weight, grab_delta);
- }
+ if (ss->cache->normal_weight > 0.0f) {
+ sculpt_project_v3_normal_align(ss, ss->cache->normal_weight, grab_delta);
+ }
- /* optionally pinch while painting */
- if (brush->crease_pinch_factor != 0.5f) {
- sculpt_project_v3_cache_init(&spvc, grab_delta);
- }
+ /* optionally pinch while painting */
+ if (brush->crease_pinch_factor != 0.5f) {
+ sculpt_project_v3_cache_init(&spvc, grab_delta);
+ }
- SculptThreadedTaskData data = {
- .sd = sd, .ob = ob, .brush = brush, .nodes = nodes,
- .spvc = &spvc, .grab_delta = grab_delta,
- };
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ .spvc = &spvc,
+ .grab_delta = grab_delta,
+ };
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
- BLI_task_parallel_range(
- 0, totnode,
- &data,
- do_snake_hook_brush_task_cb_ex,
- &settings);
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
+ BLI_task_parallel_range(0, totnode, &data, do_snake_hook_brush_task_cb_ex, &settings);
}
-static void do_thumb_brush_task_cb_ex(
- void *__restrict userdata,
- const int n,
- const ParallelRangeTLS *__restrict tls)
+static void do_thumb_brush_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const ParallelRangeTLS *__restrict tls)
{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- const Brush *brush = data->brush;
- const float *cono = data->cono;
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ const Brush *brush = data->brush;
+ const float *cono = data->cono;
- PBVHVertexIter vd;
- SculptOrigVertData orig_data;
- float (*proxy)[3];
- const float bstrength = ss->cache->bstrength;
+ PBVHVertexIter vd;
+ SculptOrigVertData orig_data;
+ float(*proxy)[3];
+ const float bstrength = ss->cache->bstrength;
- sculpt_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
+ sculpt_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
- proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
+ 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(ss, &test, data->brush->falloff_shape);
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = sculpt_brush_test_init_with_falloff_shape(
+ ss, &test, data->brush->falloff_shape);
- BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
- {
- sculpt_orig_vert_data_update(&orig_data, &vd);
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
+ {
+ sculpt_orig_vert_data_update(&orig_data, &vd);
- if (sculpt_brush_test_sq_fn(&test, orig_data.co)) {
- const float fade = bstrength * tex_strength(
- ss, brush, orig_data.co, sqrtf(test.dist),
- orig_data.no, NULL, vd.mask ? *vd.mask : 0.0f, tls->thread_id);
+ if (sculpt_brush_test_sq_fn(&test, orig_data.co)) {
+ const float fade = bstrength * tex_strength(ss,
+ brush,
+ orig_data.co,
+ sqrtf(test.dist),
+ orig_data.no,
+ NULL,
+ vd.mask ? *vd.mask : 0.0f,
+ tls->thread_id);
- mul_v3_v3fl(proxy[vd.i], cono, fade);
+ mul_v3_v3fl(proxy[vd.i], cono, fade);
- if (vd.mvert)
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- BKE_pbvh_vertex_iter_end;
+ if (vd.mvert)
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
}
static void do_thumb_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
{
- SculptSession *ss = ob->sculpt;
- Brush *brush = BKE_paint_brush(&sd->paint);
- float grab_delta[3];
- float tmp[3], cono[3];
+ SculptSession *ss = ob->sculpt;
+ Brush *brush = BKE_paint_brush(&sd->paint);
+ float grab_delta[3];
+ float tmp[3], cono[3];
- copy_v3_v3(grab_delta, ss->cache->grab_delta_symmetry);
+ copy_v3_v3(grab_delta, ss->cache->grab_delta_symmetry);
- cross_v3_v3v3(tmp, ss->cache->sculpt_normal_symm, grab_delta);
- cross_v3_v3v3(cono, tmp, ss->cache->sculpt_normal_symm);
+ cross_v3_v3v3(tmp, ss->cache->sculpt_normal_symm, grab_delta);
+ cross_v3_v3v3(cono, tmp, ss->cache->sculpt_normal_symm);
- SculptThreadedTaskData data = {
- .sd = sd, .ob = ob, .brush = brush, .nodes = nodes,
- .cono = cono,
- };
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ .cono = cono,
+ };
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
- BLI_task_parallel_range(
- 0, totnode,
- &data,
- do_thumb_brush_task_cb_ex,
- &settings);
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
+ BLI_task_parallel_range(0, totnode, &data, do_thumb_brush_task_cb_ex, &settings);
}
-static void do_rotate_brush_task_cb_ex(
- void *__restrict userdata,
- const int n,
- const ParallelRangeTLS *__restrict tls)
+static void do_rotate_brush_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const ParallelRangeTLS *__restrict tls)
{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- const Brush *brush = data->brush;
- const float angle = data->angle;
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ const Brush *brush = data->brush;
+ const float angle = data->angle;
- PBVHVertexIter vd;
- SculptOrigVertData orig_data;
- float (*proxy)[3];
- const float bstrength = ss->cache->bstrength;
+ PBVHVertexIter vd;
+ SculptOrigVertData orig_data;
+ float(*proxy)[3];
+ const float bstrength = ss->cache->bstrength;
- sculpt_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
+ sculpt_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
- proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
+ 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(ss, &test, data->brush->falloff_shape);
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = sculpt_brush_test_init_with_falloff_shape(
+ ss, &test, data->brush->falloff_shape);
- BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
- {
- sculpt_orig_vert_data_update(&orig_data, &vd);
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
+ {
+ sculpt_orig_vert_data_update(&orig_data, &vd);
- if (sculpt_brush_test_sq_fn(&test, orig_data.co)) {
- float vec[3], rot[3][3];
- const float fade = bstrength * tex_strength(
- ss, brush, orig_data.co, sqrtf(test.dist),
- orig_data.no, NULL, vd.mask ? *vd.mask : 0.0f, tls->thread_id);
+ if (sculpt_brush_test_sq_fn(&test, orig_data.co)) {
+ float vec[3], rot[3][3];
+ const float fade = bstrength * tex_strength(ss,
+ brush,
+ orig_data.co,
+ sqrtf(test.dist),
+ orig_data.no,
+ NULL,
+ vd.mask ? *vd.mask : 0.0f,
+ tls->thread_id);
- sub_v3_v3v3(vec, orig_data.co, ss->cache->location);
- axis_angle_normalized_to_mat3(rot, ss->cache->sculpt_normal_symm, angle * fade);
- mul_v3_m3v3(proxy[vd.i], rot, vec);
- add_v3_v3(proxy[vd.i], ss->cache->location);
- sub_v3_v3(proxy[vd.i], orig_data.co);
+ sub_v3_v3v3(vec, orig_data.co, ss->cache->location);
+ axis_angle_normalized_to_mat3(rot, ss->cache->sculpt_normal_symm, angle * fade);
+ mul_v3_m3v3(proxy[vd.i], rot, vec);
+ add_v3_v3(proxy[vd.i], ss->cache->location);
+ sub_v3_v3(proxy[vd.i], orig_data.co);
- if (vd.mvert)
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- BKE_pbvh_vertex_iter_end;
+ if (vd.mvert)
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
}
static void do_rotate_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
{
- SculptSession *ss = ob->sculpt;
- Brush *brush = BKE_paint_brush(&sd->paint);
-
- static const int flip[8] = { 1, -1, -1, 1, -1, 1, 1, -1 };
- const float angle = ss->cache->vertex_rotation * flip[ss->cache->mirror_symmetry_pass];
-
- SculptThreadedTaskData data = {
- .sd = sd, .ob = ob, .brush = brush, .nodes = nodes,
- .angle = angle,
- };
-
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
- BLI_task_parallel_range(
- 0, totnode,
- &data,
- do_rotate_brush_task_cb_ex,
- &settings);
+ SculptSession *ss = ob->sculpt;
+ Brush *brush = BKE_paint_brush(&sd->paint);
+
+ static const int flip[8] = {1, -1, -1, 1, -1, 1, 1, -1};
+ const float angle = ss->cache->vertex_rotation * flip[ss->cache->mirror_symmetry_pass];
+
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ .angle = angle,
+ };
+
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
+ BLI_task_parallel_range(0, totnode, &data, do_rotate_brush_task_cb_ex, &settings);
+}
+
+static void do_layer_brush_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const ParallelRangeTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ Sculpt *sd = data->sd;
+ const Brush *brush = data->brush;
+ const float *offset = data->offset;
+
+ PBVHVertexIter vd;
+ SculptOrigVertData orig_data;
+ float *layer_disp;
+ const float bstrength = ss->cache->bstrength;
+ const float lim = (bstrength < 0) ? -data->brush->height : data->brush->height;
+ /* XXX: layer brush needs conversion to proxy but its more complicated */
+ /* proxy = BKE_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co; */
+
+ sculpt_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
+
+ /* Why does this have to be thread-protected? */
+ BLI_mutex_lock(&data->mutex);
+ layer_disp = BKE_pbvh_node_layer_disp_get(ss->pbvh, data->nodes[n]);
+ BLI_mutex_unlock(&data->mutex);
+
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = sculpt_brush_test_init_with_falloff_shape(
+ ss, &test, data->brush->falloff_shape);
+
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
+ {
+ sculpt_orig_vert_data_update(&orig_data, &vd);
+
+ if (sculpt_brush_test_sq_fn(&test, orig_data.co)) {
+ const float fade = bstrength * tex_strength(ss,
+ brush,
+ vd.co,
+ sqrtf(test.dist),
+ vd.no,
+ vd.fno,
+ vd.mask ? *vd.mask : 0.0f,
+ tls->thread_id);
+ float *disp = &layer_disp[vd.i];
+ float val[3];
+
+ *disp += fade;
+
+ /* Don't let the displacement go past the limit */
+ if ((lim < 0.0f && *disp < lim) || (lim >= 0.0f && *disp > lim))
+ *disp = lim;
+
+ mul_v3_v3fl(val, offset, *disp);
+
+ if (!ss->multires && !ss->bm && ss->layer_co && (brush->flag & BRUSH_PERSISTENT)) {
+ int index = vd.vert_indices[vd.i];
+
+ /* persistent base */
+ add_v3_v3(val, ss->layer_co[index]);
+ }
+ else {
+ add_v3_v3(val, orig_data.co);
+ }
+
+ sculpt_clip(sd, ss, vd.co, val);
+
+ if (vd.mvert)
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
}
-static void do_layer_brush_task_cb_ex(
- void *__restrict userdata,
- const int n,
- const ParallelRangeTLS *__restrict tls)
+static void do_layer_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- Sculpt *sd = data->sd;
- const Brush *brush = data->brush;
- const float *offset = data->offset;
-
- PBVHVertexIter vd;
- SculptOrigVertData orig_data;
- float *layer_disp;
- const float bstrength = ss->cache->bstrength;
- const float lim = (bstrength < 0) ? -data->brush->height : data->brush->height;
- /* XXX: layer brush needs conversion to proxy but its more complicated */
- /* proxy = BKE_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co; */
+ SculptSession *ss = ob->sculpt;
+ Brush *brush = BKE_paint_brush(&sd->paint);
+ float offset[3];
- sculpt_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
+ mul_v3_v3v3(offset, ss->cache->scale, ss->cache->sculpt_normal_symm);
- /* Why does this have to be thread-protected? */
- BLI_mutex_lock(&data->mutex);
- layer_disp = BKE_pbvh_node_layer_disp_get(ss->pbvh, data->nodes[n]);
- BLI_mutex_unlock(&data->mutex);
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ .offset = offset,
+ };
+ BLI_mutex_init(&data.mutex);
- SculptBrushTest test;
- SculptBrushTestFn sculpt_brush_test_sq_fn =
- sculpt_brush_test_init_with_falloff_shape(ss, &test, data->brush->falloff_shape);
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
+ BLI_task_parallel_range(0, totnode, &data, do_layer_brush_task_cb_ex, &settings);
- BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
- {
- sculpt_orig_vert_data_update(&orig_data, &vd);
+ BLI_mutex_end(&data.mutex);
+}
- if (sculpt_brush_test_sq_fn(&test, orig_data.co)) {
- const float fade = bstrength * tex_strength(
- ss, brush, vd.co, sqrtf(test.dist),
- vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, tls->thread_id);
- float *disp = &layer_disp[vd.i];
- float val[3];
+static void do_inflate_brush_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const ParallelRangeTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ const Brush *brush = data->brush;
- *disp += fade;
+ PBVHVertexIter vd;
+ float(*proxy)[3];
+ const float bstrength = ss->cache->bstrength;
- /* Don't let the displacement go past the limit */
- if ((lim < 0.0f && *disp < lim) || (lim >= 0.0f && *disp > lim))
- *disp = lim;
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
- mul_v3_v3fl(val, offset, *disp);
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = sculpt_brush_test_init_with_falloff_shape(
+ ss, &test, data->brush->falloff_shape);
- if (!ss->multires && !ss->bm && ss->layer_co && (brush->flag & BRUSH_PERSISTENT)) {
- int index = vd.vert_indices[vd.i];
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
+ {
+ if (sculpt_brush_test_sq_fn(&test, vd.co)) {
+ const float fade = bstrength * tex_strength(ss,
+ brush,
+ vd.co,
+ sqrtf(test.dist),
+ vd.no,
+ vd.fno,
+ vd.mask ? *vd.mask : 0.0f,
+ tls->thread_id);
+ float val[3];
- /* persistent base */
- add_v3_v3(val, ss->layer_co[index]);
- }
- else {
- add_v3_v3(val, orig_data.co);
- }
+ if (vd.fno)
+ copy_v3_v3(val, vd.fno);
+ else
+ normal_short_to_float_v3(val, vd.no);
- sculpt_clip(sd, ss, vd.co, val);
+ mul_v3_fl(val, fade * ss->cache->radius);
+ mul_v3_v3v3(proxy[vd.i], val, ss->cache->scale);
- if (vd.mvert)
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- BKE_pbvh_vertex_iter_end;
+ if (vd.mvert)
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
}
-static void do_layer_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
+static void do_inflate_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
{
- SculptSession *ss = ob->sculpt;
- Brush *brush = BKE_paint_brush(&sd->paint);
- float offset[3];
-
- mul_v3_v3v3(offset, ss->cache->scale, ss->cache->sculpt_normal_symm);
-
- SculptThreadedTaskData data = {
- .sd = sd, .ob = ob, .brush = brush, .nodes = nodes,
- .offset = offset,
- };
- BLI_mutex_init(&data.mutex);
+ Brush *brush = BKE_paint_brush(&sd->paint);
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
- BLI_task_parallel_range(
- 0, totnode,
- &data,
- do_layer_brush_task_cb_ex,
- &settings);
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ };
- BLI_mutex_end(&data.mutex);
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
+ BLI_task_parallel_range(0, totnode, &data, do_inflate_brush_task_cb_ex, &settings);
}
-static void do_inflate_brush_task_cb_ex(
- void *__restrict userdata,
- const int n,
- const ParallelRangeTLS *__restrict tls)
+static void calc_sculpt_plane(
+ Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, float r_area_no[3], float r_area_co[3])
{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- const Brush *brush = data->brush;
+ SculptSession *ss = ob->sculpt;
+ Brush *brush = BKE_paint_brush(&sd->paint);
- PBVHVertexIter vd;
- float (*proxy)[3];
- const float bstrength = ss->cache->bstrength;
+ if (ss->cache->mirror_symmetry_pass == 0 && ss->cache->radial_symmetry_pass == 0 &&
+ ss->cache->tile_pass == 0 &&
+ (ss->cache->first_time || !(brush->flag & BRUSH_ORIGINAL_NORMAL))) {
+ switch (brush->sculpt_plane) {
+ case SCULPT_DISP_DIR_VIEW:
+ copy_v3_v3(r_area_no, ss->cache->true_view_normal);
+ break;
- proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
+ case SCULPT_DISP_DIR_X:
+ ARRAY_SET_ITEMS(r_area_no, 1, 0, 0);
+ break;
- SculptBrushTest test;
- SculptBrushTestFn sculpt_brush_test_sq_fn =
- sculpt_brush_test_init_with_falloff_shape(ss, &test, data->brush->falloff_shape);
+ case SCULPT_DISP_DIR_Y:
+ ARRAY_SET_ITEMS(r_area_no, 0, 1, 0);
+ break;
- BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
- {
- if (sculpt_brush_test_sq_fn(&test, vd.co)) {
- const float fade = bstrength * tex_strength(
- ss, brush, vd.co, sqrtf(test.dist),
- vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, tls->thread_id);
- float val[3];
+ case SCULPT_DISP_DIR_Z:
+ ARRAY_SET_ITEMS(r_area_no, 0, 0, 1);
+ break;
- if (vd.fno)
- copy_v3_v3(val, vd.fno);
- else
- normal_short_to_float_v3(val, vd.no);
+ case SCULPT_DISP_DIR_AREA:
+ calc_area_normal_and_center(sd, ob, nodes, totnode, r_area_no, r_area_co);
+ if (brush->falloff_shape == PAINT_FALLOFF_SHAPE_TUBE) {
+ project_plane_v3_v3v3(r_area_no, r_area_no, ss->cache->view_normal);
+ normalize_v3(r_area_no);
+ }
+ break;
- mul_v3_fl(val, fade * ss->cache->radius);
- mul_v3_v3v3(proxy[vd.i], val, ss->cache->scale);
+ default:
+ break;
+ }
- if (vd.mvert)
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- BKE_pbvh_vertex_iter_end;
-}
+ /* for flatten center */
+ /* flatten center has not been calculated yet if we are not using the area normal */
+ if (brush->sculpt_plane != SCULPT_DISP_DIR_AREA)
+ calc_area_center(sd, ob, nodes, totnode, r_area_co);
-static void do_inflate_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
-{
- Brush *brush = BKE_paint_brush(&sd->paint);
+ /* for area normal */
+ copy_v3_v3(ss->cache->sculpt_normal, r_area_no);
- SculptThreadedTaskData data = {
- .sd = sd, .ob = ob, .brush = brush, .nodes = nodes,
- };
+ /* for flatten center */
+ copy_v3_v3(ss->cache->last_center, r_area_co);
+ }
+ else {
+ /* for area normal */
+ copy_v3_v3(r_area_no, ss->cache->sculpt_normal);
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
- BLI_task_parallel_range(
- 0, totnode,
- &data,
- do_inflate_brush_task_cb_ex,
- &settings);
-}
+ /* for flatten center */
+ copy_v3_v3(r_area_co, ss->cache->last_center);
-static void calc_sculpt_plane(
- Sculpt *sd, Object *ob,
- PBVHNode **nodes, int totnode,
- float r_area_no[3], float r_area_co[3])
-{
- SculptSession *ss = ob->sculpt;
- Brush *brush = BKE_paint_brush(&sd->paint);
-
- if (ss->cache->mirror_symmetry_pass == 0 &&
- ss->cache->radial_symmetry_pass == 0 &&
- ss->cache->tile_pass == 0 &&
- (ss->cache->first_time || !(brush->flag & BRUSH_ORIGINAL_NORMAL)))
- {
- switch (brush->sculpt_plane) {
- case SCULPT_DISP_DIR_VIEW:
- copy_v3_v3(r_area_no, ss->cache->true_view_normal);
- break;
-
- case SCULPT_DISP_DIR_X:
- ARRAY_SET_ITEMS(r_area_no, 1, 0, 0);
- break;
-
- case SCULPT_DISP_DIR_Y:
- ARRAY_SET_ITEMS(r_area_no, 0, 1, 0);
- break;
-
- case SCULPT_DISP_DIR_Z:
- ARRAY_SET_ITEMS(r_area_no, 0, 0, 1);
- break;
-
- case SCULPT_DISP_DIR_AREA:
- calc_area_normal_and_center(sd, ob, nodes, totnode, r_area_no, r_area_co);
- if (brush->falloff_shape == PAINT_FALLOFF_SHAPE_TUBE) {
- project_plane_v3_v3v3(r_area_no, r_area_no, ss->cache->view_normal);
- normalize_v3(r_area_no);
- }
- break;
-
- default:
- break;
- }
-
- /* for flatten center */
- /* flatten center has not been calculated yet if we are not using the area normal */
- if (brush->sculpt_plane != SCULPT_DISP_DIR_AREA)
- calc_area_center(sd, ob, nodes, totnode, r_area_co);
-
- /* for area normal */
- copy_v3_v3(ss->cache->sculpt_normal, r_area_no);
-
- /* for flatten center */
- copy_v3_v3(ss->cache->last_center, r_area_co);
- }
- else {
- /* for area normal */
- copy_v3_v3(r_area_no, ss->cache->sculpt_normal);
-
- /* for flatten center */
- copy_v3_v3(r_area_co, ss->cache->last_center);
-
- /* for area normal */
- flip_v3(r_area_no, ss->cache->mirror_symmetry_pass);
-
- /* for flatten center */
- flip_v3(r_area_co, ss->cache->mirror_symmetry_pass);
-
- /* for area normal */
- mul_m4_v3(ss->cache->symm_rot_mat, r_area_no);
-
- /* for flatten center */
- mul_m4_v3(ss->cache->symm_rot_mat, r_area_co);
-
- /* shift the plane for the current tile */
- add_v3_v3(r_area_co, ss->cache->plane_offset);
- }
+ /* for area normal */
+ flip_v3(r_area_no, ss->cache->mirror_symmetry_pass);
+
+ /* for flatten center */
+ flip_v3(r_area_co, ss->cache->mirror_symmetry_pass);
+
+ /* for area normal */
+ mul_m4_v3(ss->cache->symm_rot_mat, r_area_no);
+
+ /* for flatten center */
+ mul_m4_v3(ss->cache->symm_rot_mat, r_area_co);
+
+ /* shift the plane for the current tile */
+ add_v3_v3(r_area_co, ss->cache->plane_offset);
+ }
}
static int plane_trim(const StrokeCache *cache, const Brush *brush, const float val[3])
{
- return (!(brush->flag & BRUSH_PLANE_TRIM) ||
- ((dot_v3v3(val, val) <= cache->radius_squared * cache->plane_trim_squared)));
+ return (!(brush->flag & BRUSH_PLANE_TRIM) ||
+ ((dot_v3v3(val, val) <= cache->radius_squared * cache->plane_trim_squared)));
}
-static bool plane_point_side_flip(
- const float co[3], const float plane[4],
- const bool flip)
+static bool plane_point_side_flip(const float co[3], const float plane[4], const bool flip)
{
- float d = plane_point_side_v3(plane, co);
- if (flip) d = -d;
- return d <= 0.0f;
+ float d = plane_point_side_v3(plane, co);
+ if (flip)
+ d = -d;
+ return d <= 0.0f;
}
static int plane_point_side(const float co[3], const float plane[4])
{
- float d = plane_point_side_v3(plane, co);
- return d <= 0.0f;
+ float d = plane_point_side_v3(plane, co);
+ return d <= 0.0f;
}
static float get_offset(Sculpt *sd, SculptSession *ss)
{
- Brush *brush = BKE_paint_brush(&sd->paint);
+ Brush *brush = BKE_paint_brush(&sd->paint);
- float rv = brush->plane_offset;
+ float rv = brush->plane_offset;
- if (brush->flag & BRUSH_OFFSET_PRESSURE) {
- rv *= ss->cache->pressure;
- }
+ if (brush->flag & BRUSH_OFFSET_PRESSURE) {
+ rv *= ss->cache->pressure;
+ }
- return rv;
+ return rv;
}
-static void do_flatten_brush_task_cb_ex(
- void *__restrict userdata,
- const int n,
- const ParallelRangeTLS *__restrict tls)
+static void do_flatten_brush_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const ParallelRangeTLS *__restrict tls)
{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- const Brush *brush = data->brush;
- const float *area_no = data->area_no;
- const float *area_co = data->area_co;
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ const Brush *brush = data->brush;
+ const float *area_no = data->area_no;
+ const float *area_co = data->area_co;
- PBVHVertexIter vd;
- float (*proxy)[3];
- const float bstrength = ss->cache->bstrength;
+ PBVHVertexIter vd;
+ float(*proxy)[3];
+ const float bstrength = ss->cache->bstrength;
- proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
+ 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(ss, &test, data->brush->falloff_shape);
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = sculpt_brush_test_init_with_falloff_shape(
+ ss, &test, data->brush->falloff_shape);
- plane_from_point_normal_v3(test.plane_tool, area_co, area_no);
+ plane_from_point_normal_v3(test.plane_tool, area_co, area_no);
- BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
- {
- if (sculpt_brush_test_sq_fn(&test, vd.co)) {
- float intr[3];
- float val[3];
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
+ {
+ if (sculpt_brush_test_sq_fn(&test, vd.co)) {
+ float intr[3];
+ float val[3];
- closest_to_plane_normalized_v3(intr, test.plane_tool, vd.co);
+ closest_to_plane_normalized_v3(intr, test.plane_tool, vd.co);
- sub_v3_v3v3(val, intr, vd.co);
+ sub_v3_v3v3(val, intr, vd.co);
- if (plane_trim(ss->cache, brush, val)) {
- const float fade = bstrength * tex_strength(
- ss, brush, vd.co, sqrtf(test.dist),
- vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, tls->thread_id);
+ if (plane_trim(ss->cache, brush, val)) {
+ const float fade = bstrength * tex_strength(ss,
+ brush,
+ vd.co,
+ sqrtf(test.dist),
+ vd.no,
+ vd.fno,
+ vd.mask ? *vd.mask : 0.0f,
+ tls->thread_id);
- mul_v3_v3fl(proxy[vd.i], val, fade);
+ mul_v3_v3fl(proxy[vd.i], val, fade);
- if (vd.mvert)
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- }
- BKE_pbvh_vertex_iter_end;
+ if (vd.mvert)
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
}
static void do_flatten_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
{
- SculptSession *ss = ob->sculpt;
- Brush *brush = BKE_paint_brush(&sd->paint);
+ SculptSession *ss = ob->sculpt;
+ Brush *brush = BKE_paint_brush(&sd->paint);
- const float radius = ss->cache->radius;
+ const float radius = ss->cache->radius;
- float area_no[3];
- float area_co[3];
+ float area_no[3];
+ float area_co[3];
- float offset = get_offset(sd, ss);
- float displace;
- float temp[3];
+ float offset = get_offset(sd, ss);
+ float displace;
+ float temp[3];
- calc_sculpt_plane(sd, ob, nodes, totnode, area_no, area_co);
+ calc_sculpt_plane(sd, ob, nodes, totnode, area_no, area_co);
- displace = radius * offset;
+ displace = radius * offset;
- mul_v3_v3v3(temp, area_no, ss->cache->scale);
- mul_v3_fl(temp, displace);
- add_v3_v3(area_co, temp);
+ mul_v3_v3v3(temp, area_no, ss->cache->scale);
+ mul_v3_fl(temp, displace);
+ add_v3_v3(area_co, temp);
- SculptThreadedTaskData data = {
- .sd = sd, .ob = ob, .brush = brush, .nodes = nodes,
- .area_no = area_no, .area_co = area_co,
- };
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ .area_no = area_no,
+ .area_co = area_co,
+ };
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
- BLI_task_parallel_range(
- 0, totnode,
- &data,
- do_flatten_brush_task_cb_ex,
- &settings);
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
+ BLI_task_parallel_range(0, totnode, &data, do_flatten_brush_task_cb_ex, &settings);
}
-static void do_clay_brush_task_cb_ex(
- void *__restrict userdata,
- const int n,
- const ParallelRangeTLS *__restrict tls)
+static void do_clay_brush_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const ParallelRangeTLS *__restrict tls)
{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- const Brush *brush = data->brush;
- const float *area_no = data->area_no;
- const float *area_co = data->area_co;
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ const Brush *brush = data->brush;
+ const float *area_no = data->area_no;
+ const float *area_co = data->area_co;
- PBVHVertexIter vd;
- float (*proxy)[3];
- const bool flip = (ss->cache->bstrength < 0);
- const float bstrength = flip ? -ss->cache->bstrength : ss->cache->bstrength;
+ PBVHVertexIter vd;
+ float(*proxy)[3];
+ const bool flip = (ss->cache->bstrength < 0);
+ const float bstrength = flip ? -ss->cache->bstrength : ss->cache->bstrength;
- proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
+ 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(ss, &test, data->brush->falloff_shape);
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = sculpt_brush_test_init_with_falloff_shape(
+ ss, &test, data->brush->falloff_shape);
- plane_from_point_normal_v3(test.plane_tool, area_co, area_no);
+ plane_from_point_normal_v3(test.plane_tool, area_co, area_no);
- BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
- {
- if (sculpt_brush_test_sq_fn(&test, vd.co)) {
- if (plane_point_side_flip(vd.co, test.plane_tool, flip)) {
- float intr[3];
- float val[3];
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
+ {
+ if (sculpt_brush_test_sq_fn(&test, vd.co)) {
+ if (plane_point_side_flip(vd.co, test.plane_tool, flip)) {
+ float intr[3];
+ float val[3];
- closest_to_plane_normalized_v3(intr, test.plane_tool, vd.co);
+ closest_to_plane_normalized_v3(intr, test.plane_tool, vd.co);
- sub_v3_v3v3(val, intr, vd.co);
+ sub_v3_v3v3(val, intr, vd.co);
- if (plane_trim(ss->cache, brush, val)) {
- /* note, the normal from the vertices is ignored,
- * causes glitch with planes, see: T44390 */
- const float fade = bstrength * tex_strength(
- ss, brush, vd.co, sqrtf(test.dist),
- vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, tls->thread_id);
+ if (plane_trim(ss->cache, brush, val)) {
+ /* note, the normal from the vertices is ignored,
+ * causes glitch with planes, see: T44390 */
+ const float fade = bstrength * tex_strength(ss,
+ brush,
+ vd.co,
+ sqrtf(test.dist),
+ vd.no,
+ vd.fno,
+ vd.mask ? *vd.mask : 0.0f,
+ tls->thread_id);
- mul_v3_v3fl(proxy[vd.i], val, fade);
+ mul_v3_v3fl(proxy[vd.i], val, fade);
- if (vd.mvert)
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- }
- }
- BKE_pbvh_vertex_iter_end;
+ if (vd.mvert)
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
}
static void do_clay_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
{
- SculptSession *ss = ob->sculpt;
- Brush *brush = BKE_paint_brush(&sd->paint);
+ SculptSession *ss = ob->sculpt;
+ Brush *brush = BKE_paint_brush(&sd->paint);
- const bool flip = (ss->cache->bstrength < 0);
- const float radius = flip ? -ss->cache->radius : ss->cache->radius;
+ const bool flip = (ss->cache->bstrength < 0);
+ const float radius = flip ? -ss->cache->radius : ss->cache->radius;
- float offset = get_offset(sd, ss);
- float displace;
+ float offset = get_offset(sd, ss);
+ float displace;
- float area_no[3];
- float area_co[3];
- float temp[3];
+ float area_no[3];
+ float area_co[3];
+ float temp[3];
- calc_sculpt_plane(sd, ob, nodes, totnode, area_no, area_co);
+ calc_sculpt_plane(sd, ob, nodes, totnode, area_no, area_co);
- displace = radius * (0.25f + offset);
+ displace = radius * (0.25f + offset);
- mul_v3_v3v3(temp, area_no, ss->cache->scale);
- mul_v3_fl(temp, displace);
- add_v3_v3(area_co, temp);
+ mul_v3_v3v3(temp, area_no, ss->cache->scale);
+ mul_v3_fl(temp, displace);
+ add_v3_v3(area_co, temp);
- /* add_v3_v3v3(p, ss->cache->location, area_no); */
+ /* add_v3_v3v3(p, ss->cache->location, area_no); */
- SculptThreadedTaskData data = {
- .sd = sd, .ob = ob, .brush = brush, .nodes = nodes,
- .area_no = area_no, .area_co = area_co,
- };
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ .area_no = area_no,
+ .area_co = area_co,
+ };
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
- BLI_task_parallel_range(
- 0, totnode,
- &data,
- do_clay_brush_task_cb_ex,
- &settings);
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
+ BLI_task_parallel_range(0, totnode, &data, do_clay_brush_task_cb_ex, &settings);
}
-static void do_clay_strips_brush_task_cb_ex(
- void *__restrict userdata,
- const int n,
- const ParallelRangeTLS *__restrict tls)
+static void do_clay_strips_brush_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const ParallelRangeTLS *__restrict tls)
{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- const Brush *brush = data->brush;
- float (*mat)[4] = data->mat;
- const float *area_no_sp = data->area_no_sp;
- const float *area_co = data->area_co;
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ const Brush *brush = data->brush;
+ float(*mat)[4] = data->mat;
+ const float *area_no_sp = data->area_no_sp;
+ const float *area_co = data->area_co;
- PBVHVertexIter vd;
- SculptBrushTest test;
- float (*proxy)[3];
- const bool flip = (ss->cache->bstrength < 0);
- const float bstrength = flip ? -ss->cache->bstrength : ss->cache->bstrength;
+ PBVHVertexIter vd;
+ SculptBrushTest test;
+ float(*proxy)[3];
+ const bool flip = (ss->cache->bstrength < 0);
+ const float bstrength = flip ? -ss->cache->bstrength : ss->cache->bstrength;
- proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
- sculpt_brush_test_init(ss, &test);
- plane_from_point_normal_v3(test.plane_tool, area_co, area_no_sp);
+ sculpt_brush_test_init(ss, &test);
+ plane_from_point_normal_v3(test.plane_tool, area_co, area_no_sp);
- BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
- {
- if (sculpt_brush_test_cube(&test, vd.co, mat)) {
- if (plane_point_side_flip(vd.co, test.plane_tool, flip)) {
- float intr[3];
- float val[3];
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
+ {
+ if (sculpt_brush_test_cube(&test, vd.co, mat)) {
+ if (plane_point_side_flip(vd.co, test.plane_tool, flip)) {
+ float intr[3];
+ float val[3];
- closest_to_plane_normalized_v3(intr, test.plane_tool, vd.co);
+ closest_to_plane_normalized_v3(intr, test.plane_tool, vd.co);
- sub_v3_v3v3(val, intr, vd.co);
+ sub_v3_v3v3(val, intr, vd.co);
- if (plane_trim(ss->cache, brush, val)) {
- /* note, the normal from the vertices is ignored,
- * causes glitch with planes, see: T44390 */
- const float fade = bstrength * tex_strength(
- ss, brush, vd.co, ss->cache->radius * test.dist,
- vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, tls->thread_id);
+ if (plane_trim(ss->cache, brush, val)) {
+ /* note, the normal from the vertices is ignored,
+ * causes glitch with planes, see: T44390 */
+ const float fade = bstrength * tex_strength(ss,
+ brush,
+ vd.co,
+ ss->cache->radius * test.dist,
+ vd.no,
+ vd.fno,
+ vd.mask ? *vd.mask : 0.0f,
+ tls->thread_id);
- mul_v3_v3fl(proxy[vd.i], val, fade);
+ mul_v3_v3fl(proxy[vd.i], val, fade);
- if (vd.mvert)
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- }
- }
- BKE_pbvh_vertex_iter_end;
+ if (vd.mvert)
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
}
static void do_clay_strips_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
{
- SculptSession *ss = ob->sculpt;
- Brush *brush = BKE_paint_brush(&sd->paint);
-
- const bool flip = (ss->cache->bstrength < 0);
- const float radius = flip ? -ss->cache->radius : ss->cache->radius;
- const float offset = get_offset(sd, ss);
- const float displace = radius * (0.25f + offset);
-
- float area_no_sp[3]; /* the sculpt-plane normal (whatever its set to) */
- float area_no[3]; /* geometry normal */
- float area_co[3];
-
- float temp[3];
- float mat[4][4];
- float scale[4][4];
- float tmat[4][4];
-
- calc_sculpt_plane(sd, ob, nodes, totnode, area_no_sp, area_co);
-
- if (brush->sculpt_plane != SCULPT_DISP_DIR_AREA || (brush->flag & BRUSH_ORIGINAL_NORMAL))
- calc_area_normal(sd, ob, nodes, totnode, area_no);
- else
- copy_v3_v3(area_no, area_no_sp);
-
- /* delay the first daub because grab delta is not setup */
- if (ss->cache->first_time)
- return;
-
- mul_v3_v3v3(temp, area_no_sp, ss->cache->scale);
- mul_v3_fl(temp, displace);
- add_v3_v3(area_co, temp);
-
- /* init mat */
- cross_v3_v3v3(mat[0], area_no, ss->cache->grab_delta_symmetry);
- mat[0][3] = 0;
- cross_v3_v3v3(mat[1], area_no, mat[0]);
- mat[1][3] = 0;
- copy_v3_v3(mat[2], area_no);
- mat[2][3] = 0;
- copy_v3_v3(mat[3], ss->cache->location);
- mat[3][3] = 1;
- normalize_m4(mat);
-
- /* scale mat */
- scale_m4_fl(scale, ss->cache->radius);
- mul_m4_m4m4(tmat, mat, scale);
- invert_m4_m4(mat, tmat);
-
- SculptThreadedTaskData data = {
- .sd = sd, .ob = ob, .brush = brush, .nodes = nodes,
- .area_no_sp = area_no_sp, .area_co = area_co, .mat = mat,
- };
-
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
- BLI_task_parallel_range(
- 0, totnode,
- &data,
- do_clay_strips_brush_task_cb_ex,
- &settings);
-}
-
-static void do_fill_brush_task_cb_ex(
- void *__restrict userdata,
- const int n,
- const ParallelRangeTLS *__restrict tls)
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- const Brush *brush = data->brush;
- const float *area_no = data->area_no;
- const float *area_co = data->area_co;
-
- PBVHVertexIter vd;
- float (*proxy)[3];
- const float bstrength = ss->cache->bstrength;
-
- 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(ss, &test, data->brush->falloff_shape);
-
- plane_from_point_normal_v3(test.plane_tool, area_co, area_no);
-
- BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
- {
- if (sculpt_brush_test_sq_fn(&test, vd.co)) {
- if (plane_point_side(vd.co, test.plane_tool)) {
- float intr[3];
- float val[3];
-
- closest_to_plane_normalized_v3(intr, test.plane_tool, vd.co);
-
- sub_v3_v3v3(val, intr, vd.co);
-
- if (plane_trim(ss->cache, brush, val)) {
- const float fade = bstrength * tex_strength(
- ss, brush, vd.co, sqrtf(test.dist),
- vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, tls->thread_id);
-
- mul_v3_v3fl(proxy[vd.i], val, fade);
-
- if (vd.mvert)
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- }
- }
- BKE_pbvh_vertex_iter_end;
+ SculptSession *ss = ob->sculpt;
+ Brush *brush = BKE_paint_brush(&sd->paint);
+
+ const bool flip = (ss->cache->bstrength < 0);
+ const float radius = flip ? -ss->cache->radius : ss->cache->radius;
+ const float offset = get_offset(sd, ss);
+ const float displace = radius * (0.25f + offset);
+
+ float area_no_sp[3]; /* the sculpt-plane normal (whatever its set to) */
+ float area_no[3]; /* geometry normal */
+ float area_co[3];
+
+ float temp[3];
+ float mat[4][4];
+ float scale[4][4];
+ float tmat[4][4];
+
+ calc_sculpt_plane(sd, ob, nodes, totnode, area_no_sp, area_co);
+
+ if (brush->sculpt_plane != SCULPT_DISP_DIR_AREA || (brush->flag & BRUSH_ORIGINAL_NORMAL))
+ calc_area_normal(sd, ob, nodes, totnode, area_no);
+ else
+ copy_v3_v3(area_no, area_no_sp);
+
+ /* delay the first daub because grab delta is not setup */
+ if (ss->cache->first_time)
+ return;
+
+ mul_v3_v3v3(temp, area_no_sp, ss->cache->scale);
+ mul_v3_fl(temp, displace);
+ add_v3_v3(area_co, temp);
+
+ /* init mat */
+ cross_v3_v3v3(mat[0], area_no, ss->cache->grab_delta_symmetry);
+ mat[0][3] = 0;
+ cross_v3_v3v3(mat[1], area_no, mat[0]);
+ mat[1][3] = 0;
+ copy_v3_v3(mat[2], area_no);
+ mat[2][3] = 0;
+ copy_v3_v3(mat[3], ss->cache->location);
+ mat[3][3] = 1;
+ normalize_m4(mat);
+
+ /* scale mat */
+ scale_m4_fl(scale, ss->cache->radius);
+ mul_m4_m4m4(tmat, mat, scale);
+ invert_m4_m4(mat, tmat);
+
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ .area_no_sp = area_no_sp,
+ .area_co = area_co,
+ .mat = mat,
+ };
+
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
+ BLI_task_parallel_range(0, totnode, &data, do_clay_strips_brush_task_cb_ex, &settings);
+}
+
+static void do_fill_brush_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const ParallelRangeTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ const Brush *brush = data->brush;
+ const float *area_no = data->area_no;
+ const float *area_co = data->area_co;
+
+ PBVHVertexIter vd;
+ float(*proxy)[3];
+ const float bstrength = ss->cache->bstrength;
+
+ 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(
+ ss, &test, data->brush->falloff_shape);
+
+ plane_from_point_normal_v3(test.plane_tool, area_co, area_no);
+
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
+ {
+ if (sculpt_brush_test_sq_fn(&test, vd.co)) {
+ if (plane_point_side(vd.co, test.plane_tool)) {
+ float intr[3];
+ float val[3];
+
+ closest_to_plane_normalized_v3(intr, test.plane_tool, vd.co);
+
+ sub_v3_v3v3(val, intr, vd.co);
+
+ if (plane_trim(ss->cache, brush, val)) {
+ const float fade = bstrength * tex_strength(ss,
+ brush,
+ vd.co,
+ sqrtf(test.dist),
+ vd.no,
+ vd.fno,
+ vd.mask ? *vd.mask : 0.0f,
+ tls->thread_id);
+
+ mul_v3_v3fl(proxy[vd.i], val, fade);
+
+ if (vd.mvert)
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
}
static void do_fill_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
{
- SculptSession *ss = ob->sculpt;
- Brush *brush = BKE_paint_brush(&sd->paint);
+ SculptSession *ss = ob->sculpt;
+ Brush *brush = BKE_paint_brush(&sd->paint);
- const float radius = ss->cache->radius;
+ const float radius = ss->cache->radius;
- float area_no[3];
- float area_co[3];
- float offset = get_offset(sd, ss);
+ float area_no[3];
+ float area_co[3];
+ float offset = get_offset(sd, ss);
- float displace;
+ float displace;
- float temp[3];
+ float temp[3];
- calc_sculpt_plane(sd, ob, nodes, totnode, area_no, area_co);
+ calc_sculpt_plane(sd, ob, nodes, totnode, area_no, area_co);
- displace = radius * offset;
+ displace = radius * offset;
- mul_v3_v3v3(temp, area_no, ss->cache->scale);
- mul_v3_fl(temp, displace);
- add_v3_v3(area_co, temp);
+ mul_v3_v3v3(temp, area_no, ss->cache->scale);
+ mul_v3_fl(temp, displace);
+ add_v3_v3(area_co, temp);
- SculptThreadedTaskData data = {
- .sd = sd, .ob = ob, .brush = brush, .nodes = nodes,
- .area_no = area_no, .area_co = area_co,
- };
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ .area_no = area_no,
+ .area_co = area_co,
+ };
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
- BLI_task_parallel_range(
- 0, totnode,
- &data,
- do_fill_brush_task_cb_ex,
- &settings);
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
+ BLI_task_parallel_range(0, totnode, &data, do_fill_brush_task_cb_ex, &settings);
}
-static void do_scrape_brush_task_cb_ex(
- void *__restrict userdata,
- const int n,
- const ParallelRangeTLS *__restrict tls)
+static void do_scrape_brush_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const ParallelRangeTLS *__restrict tls)
{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- const Brush *brush = data->brush;
- const float *area_no = data->area_no;
- const float *area_co = data->area_co;
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ const Brush *brush = data->brush;
+ const float *area_no = data->area_no;
+ const float *area_co = data->area_co;
- PBVHVertexIter vd;
- float (*proxy)[3];
- const float bstrength = ss->cache->bstrength;
+ PBVHVertexIter vd;
+ float(*proxy)[3];
+ const float bstrength = ss->cache->bstrength;
- proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
+ 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(ss, &test, data->brush->falloff_shape);
- plane_from_point_normal_v3(test.plane_tool, area_co, area_no);
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = sculpt_brush_test_init_with_falloff_shape(
+ ss, &test, data->brush->falloff_shape);
+ plane_from_point_normal_v3(test.plane_tool, area_co, area_no);
- BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
- {
- if (sculpt_brush_test_sq_fn(&test, vd.co)) {
- if (!plane_point_side(vd.co, test.plane_tool)) {
- float intr[3];
- float val[3];
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
+ {
+ if (sculpt_brush_test_sq_fn(&test, vd.co)) {
+ if (!plane_point_side(vd.co, test.plane_tool)) {
+ float intr[3];
+ float val[3];
- closest_to_plane_normalized_v3(intr, test.plane_tool, vd.co);
+ closest_to_plane_normalized_v3(intr, test.plane_tool, vd.co);
- sub_v3_v3v3(val, intr, vd.co);
+ sub_v3_v3v3(val, intr, vd.co);
- if (plane_trim(ss->cache, brush, val)) {
- const float fade = bstrength * tex_strength(
- ss, brush, vd.co, sqrtf(test.dist),
- vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, tls->thread_id);
+ if (plane_trim(ss->cache, brush, val)) {
+ const float fade = bstrength * tex_strength(ss,
+ brush,
+ vd.co,
+ sqrtf(test.dist),
+ vd.no,
+ vd.fno,
+ vd.mask ? *vd.mask : 0.0f,
+ tls->thread_id);
- mul_v3_v3fl(proxy[vd.i], val, fade);
+ mul_v3_v3fl(proxy[vd.i], val, fade);
- if (vd.mvert)
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- }
- }
- BKE_pbvh_vertex_iter_end;
+ if (vd.mvert)
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
}
static void do_scrape_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
{
- SculptSession *ss = ob->sculpt;
- Brush *brush = BKE_paint_brush(&sd->paint);
+ SculptSession *ss = ob->sculpt;
+ Brush *brush = BKE_paint_brush(&sd->paint);
- const float radius = ss->cache->radius;
+ const float radius = ss->cache->radius;
- float area_no[3];
- float area_co[3];
- float offset = get_offset(sd, ss);
+ float area_no[3];
+ float area_co[3];
+ float offset = get_offset(sd, ss);
- float displace;
+ float displace;
- float temp[3];
+ float temp[3];
- calc_sculpt_plane(sd, ob, nodes, totnode, area_no, area_co);
+ calc_sculpt_plane(sd, ob, nodes, totnode, area_no, area_co);
- displace = -radius * offset;
+ displace = -radius * offset;
- mul_v3_v3v3(temp, area_no, ss->cache->scale);
- mul_v3_fl(temp, displace);
- add_v3_v3(area_co, temp);
+ mul_v3_v3v3(temp, area_no, ss->cache->scale);
+ mul_v3_fl(temp, displace);
+ add_v3_v3(area_co, temp);
- SculptThreadedTaskData data = {
- .sd = sd, .ob = ob, .brush = brush, .nodes = nodes,
- .area_no = area_no, .area_co = area_co,
- };
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ .area_no = area_no,
+ .area_co = area_co,
+ };
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
- BLI_task_parallel_range(
- 0, totnode,
- &data,
- do_scrape_brush_task_cb_ex,
- &settings);
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
+ BLI_task_parallel_range(0, totnode, &data, do_scrape_brush_task_cb_ex, &settings);
}
-static void do_gravity_task_cb_ex(
- void *__restrict userdata,
- const int n,
- const ParallelRangeTLS *__restrict tls)
+static void do_gravity_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const ParallelRangeTLS *__restrict tls)
{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- const Brush *brush = data->brush;
- float *offset = data->offset;
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ const Brush *brush = data->brush;
+ float *offset = data->offset;
- PBVHVertexIter vd;
- float (*proxy)[3];
+ PBVHVertexIter vd;
+ float(*proxy)[3];
- proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
+ 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(ss, &test, data->brush->falloff_shape);
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = sculpt_brush_test_init_with_falloff_shape(
+ ss, &test, data->brush->falloff_shape);
- BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
- if (sculpt_brush_test_sq_fn(&test, vd.co)) {
- const float fade = tex_strength(
- ss, brush, vd.co, sqrtf(test.dist),
- vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, tls->thread_id);
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
+ {
+ if (sculpt_brush_test_sq_fn(&test, vd.co)) {
+ const float fade = tex_strength(ss,
+ brush,
+ vd.co,
+ sqrtf(test.dist),
+ vd.no,
+ vd.fno,
+ vd.mask ? *vd.mask : 0.0f,
+ tls->thread_id);
- mul_v3_v3fl(proxy[vd.i], offset, fade);
+ mul_v3_v3fl(proxy[vd.i], offset, fade);
- if (vd.mvert)
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- BKE_pbvh_vertex_iter_end;
+ if (vd.mvert)
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
}
static void do_gravity(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, float bstrength)
{
- SculptSession *ss = ob->sculpt;
- Brush *brush = BKE_paint_brush(&sd->paint);
+ SculptSession *ss = ob->sculpt;
+ Brush *brush = BKE_paint_brush(&sd->paint);
- float offset[3]/*, area_no[3]*/;
- float gravity_vector[3];
+ float offset[3] /*, area_no[3]*/;
+ float gravity_vector[3];
- mul_v3_v3fl(gravity_vector, ss->cache->gravity_direction, -ss->cache->radius_squared);
+ mul_v3_v3fl(gravity_vector, ss->cache->gravity_direction, -ss->cache->radius_squared);
- /* offset with as much as possible factored in already */
- mul_v3_v3v3(offset, gravity_vector, ss->cache->scale);
- mul_v3_fl(offset, bstrength);
+ /* offset with as much as possible factored in already */
+ mul_v3_v3v3(offset, gravity_vector, ss->cache->scale);
+ mul_v3_fl(offset, bstrength);
- /* threaded loop over nodes */
- SculptThreadedTaskData data = {
- .sd = sd, .ob = ob, .brush = brush, .nodes = nodes,
- .offset = offset,
- };
+ /* threaded loop over nodes */
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ .offset = offset,
+ };
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
- BLI_task_parallel_range(
- 0, totnode,
- &data,
- do_gravity_task_cb_ex,
- &settings);
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
+ BLI_task_parallel_range(0, totnode, &data, do_gravity_task_cb_ex, &settings);
}
-
void sculpt_vertcos_to_key(Object *ob, KeyBlock *kb, float (*vertCos)[3])
{
- Mesh *me = (Mesh *)ob->data;
- float (*ofs)[3] = NULL;
- int a;
- const int kb_act_idx = ob->shapenr - 1;
- KeyBlock *currkey;
+ Mesh *me = (Mesh *)ob->data;
+ float(*ofs)[3] = NULL;
+ int a;
+ const int kb_act_idx = ob->shapenr - 1;
+ KeyBlock *currkey;
- /* for relative keys editing of base should update other keys */
- if (BKE_keyblock_is_basis(me->key, kb_act_idx)) {
- ofs = BKE_keyblock_convert_to_vertcos(ob, kb);
+ /* for relative keys editing of base should update other keys */
+ if (BKE_keyblock_is_basis(me->key, kb_act_idx)) {
+ ofs = BKE_keyblock_convert_to_vertcos(ob, kb);
- /* calculate key coord offsets (from previous location) */
- for (a = 0; a < me->totvert; a++) {
- sub_v3_v3v3(ofs[a], vertCos[a], ofs[a]);
- }
+ /* calculate key coord offsets (from previous location) */
+ for (a = 0; a < me->totvert; a++) {
+ sub_v3_v3v3(ofs[a], vertCos[a], ofs[a]);
+ }
- /* apply offsets on other keys */
- for (currkey = me->key->block.first; currkey; currkey = currkey->next) {
- if ((currkey != kb) && (currkey->relative == kb_act_idx)) {
- BKE_keyblock_update_from_offset(ob, currkey, ofs);
- }
- }
+ /* apply offsets on other keys */
+ for (currkey = me->key->block.first; currkey; currkey = currkey->next) {
+ if ((currkey != kb) && (currkey->relative == kb_act_idx)) {
+ BKE_keyblock_update_from_offset(ob, currkey, ofs);
+ }
+ }
- MEM_freeN(ofs);
- }
+ MEM_freeN(ofs);
+ }
- /* modifying of basis key should update mesh */
- if (kb == me->key->refkey) {
- MVert *mvert = me->mvert;
+ /* modifying of basis key should update mesh */
+ if (kb == me->key->refkey) {
+ MVert *mvert = me->mvert;
- for (a = 0; a < me->totvert; a++, mvert++)
- copy_v3_v3(mvert->co, vertCos[a]);
+ for (a = 0; a < me->totvert; a++, mvert++)
+ copy_v3_v3(mvert->co, vertCos[a]);
- BKE_mesh_calc_normals(me);
- }
+ BKE_mesh_calc_normals(me);
+ }
- /* apply new coords on active key block, no need to re-allocate kb->data here! */
- BKE_keyblock_update_from_vertcos(ob, kb, vertCos);
+ /* apply new coords on active key block, no need to re-allocate kb->data here! */
+ BKE_keyblock_update_from_vertcos(ob, kb, vertCos);
}
/* Note: we do the topology update before any brush actions to avoid
* issues with the proxies. The size of the proxy can't change, so
* topology must be updated first. */
-static void sculpt_topology_update(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSettings *UNUSED(ups))
-{
- SculptSession *ss = ob->sculpt;
-
- int n, totnode;
- /* Build a list of all nodes that are potentially within the brush's area of influence */
- const bool use_original = sculpt_tool_needs_original(brush->sculpt_tool) ? true : ss->cache->original;
- const float radius_scale = 1.25f;
- PBVHNode **nodes = sculpt_pbvh_gather_generic(ob, sd, brush, use_original, radius_scale, &totnode);
-
- /* Only act if some verts are inside the brush area */
- if (totnode) {
- PBVHTopologyUpdateMode mode = 0;
- float location[3];
-
- if (!(sd->flags & SCULPT_DYNTOPO_DETAIL_MANUAL)) {
- if (sd->flags & SCULPT_DYNTOPO_SUBDIVIDE) {
- mode |= PBVH_Subdivide;
- }
-
- if ((sd->flags & SCULPT_DYNTOPO_COLLAPSE) ||
- (brush->sculpt_tool == SCULPT_TOOL_SIMPLIFY))
- {
- mode |= PBVH_Collapse;
- }
- }
-
- for (n = 0; n < totnode; n++) {
- sculpt_undo_push_node(ob, nodes[n],
- brush->sculpt_tool == SCULPT_TOOL_MASK ?
- SCULPT_UNDO_MASK : SCULPT_UNDO_COORDS);
- BKE_pbvh_node_mark_update(nodes[n]);
-
- if (BKE_pbvh_type(ss->pbvh) == PBVH_BMESH) {
- BKE_pbvh_node_mark_topology_update(nodes[n]);
- BKE_pbvh_bmesh_node_save_orig(nodes[n]);
- }
- }
-
- if (BKE_pbvh_type(ss->pbvh) == PBVH_BMESH) {
- BKE_pbvh_bmesh_update_topology(
- ss->pbvh, mode,
- ss->cache->location,
- ss->cache->view_normal,
- ss->cache->radius,
- (brush->flag & BRUSH_FRONTFACE) != 0,
- (brush->falloff_shape != PAINT_FALLOFF_SHAPE_SPHERE));
- }
-
- MEM_freeN(nodes);
-
- /* update average stroke position */
- copy_v3_v3(location, ss->cache->true_location);
- mul_m4_v3(ob->obmat, location);
- }
-}
-
-static void do_brush_action_task_cb(
- void *__restrict userdata,
- const int n,
- const ParallelRangeTLS *__restrict UNUSED(tls))
-{
- SculptThreadedTaskData *data = userdata;
-
- sculpt_undo_push_node(data->ob, data->nodes[n],
- data->brush->sculpt_tool == SCULPT_TOOL_MASK ? SCULPT_UNDO_MASK : SCULPT_UNDO_COORDS);
- BKE_pbvh_node_mark_update(data->nodes[n]);
+static void sculpt_topology_update(Sculpt *sd,
+ Object *ob,
+ Brush *brush,
+ UnifiedPaintSettings *UNUSED(ups))
+{
+ SculptSession *ss = ob->sculpt;
+
+ int n, totnode;
+ /* Build a list of all nodes that are potentially within the brush's area of influence */
+ const bool use_original = sculpt_tool_needs_original(brush->sculpt_tool) ? true :
+ ss->cache->original;
+ const float radius_scale = 1.25f;
+ PBVHNode **nodes = sculpt_pbvh_gather_generic(
+ ob, sd, brush, use_original, radius_scale, &totnode);
+
+ /* Only act if some verts are inside the brush area */
+ if (totnode) {
+ PBVHTopologyUpdateMode mode = 0;
+ float location[3];
+
+ if (!(sd->flags & SCULPT_DYNTOPO_DETAIL_MANUAL)) {
+ if (sd->flags & SCULPT_DYNTOPO_SUBDIVIDE) {
+ mode |= PBVH_Subdivide;
+ }
+
+ if ((sd->flags & SCULPT_DYNTOPO_COLLAPSE) || (brush->sculpt_tool == SCULPT_TOOL_SIMPLIFY)) {
+ mode |= PBVH_Collapse;
+ }
+ }
+
+ for (n = 0; n < totnode; n++) {
+ sculpt_undo_push_node(ob,
+ nodes[n],
+ brush->sculpt_tool == SCULPT_TOOL_MASK ? SCULPT_UNDO_MASK :
+ SCULPT_UNDO_COORDS);
+ BKE_pbvh_node_mark_update(nodes[n]);
+
+ if (BKE_pbvh_type(ss->pbvh) == PBVH_BMESH) {
+ BKE_pbvh_node_mark_topology_update(nodes[n]);
+ BKE_pbvh_bmesh_node_save_orig(nodes[n]);
+ }
+ }
+
+ if (BKE_pbvh_type(ss->pbvh) == PBVH_BMESH) {
+ BKE_pbvh_bmesh_update_topology(ss->pbvh,
+ mode,
+ ss->cache->location,
+ ss->cache->view_normal,
+ ss->cache->radius,
+ (brush->flag & BRUSH_FRONTFACE) != 0,
+ (brush->falloff_shape != PAINT_FALLOFF_SHAPE_SPHERE));
+ }
+
+ MEM_freeN(nodes);
+
+ /* update average stroke position */
+ copy_v3_v3(location, ss->cache->true_location);
+ mul_m4_v3(ob->obmat, location);
+ }
+}
+
+static void do_brush_action_task_cb(void *__restrict userdata,
+ const int n,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
+{
+ SculptThreadedTaskData *data = userdata;
+
+ sculpt_undo_push_node(data->ob,
+ data->nodes[n],
+ data->brush->sculpt_tool == SCULPT_TOOL_MASK ? SCULPT_UNDO_MASK :
+ SCULPT_UNDO_COORDS);
+ BKE_pbvh_node_mark_update(data->nodes[n]);
}
static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSettings *ups)
{
- SculptSession *ss = ob->sculpt;
- int totnode;
-
- /* Build a list of all nodes that are potentially within the brush's area of influence */
- const bool use_original = sculpt_tool_needs_original(brush->sculpt_tool) ? true : ss->cache->original;
- const float radius_scale = 1.0f;
- PBVHNode **nodes = sculpt_pbvh_gather_generic(ob, sd, brush, use_original, radius_scale, &totnode);
-
- /* Only act if some verts are inside the brush area */
- if (totnode) {
- float location[3];
-
- SculptThreadedTaskData task_data = {
- .sd = sd, .ob = ob, .brush = brush, .nodes = nodes,
- };
-
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
- BLI_task_parallel_range(
- 0, totnode,
- &task_data,
- do_brush_action_task_cb,
- &settings);
-
- if (sculpt_brush_needs_normal(ss, brush))
- update_sculpt_normal(sd, ob, nodes, totnode);
-
- if (brush->mtex.brush_map_mode == MTEX_MAP_MODE_AREA)
- update_brush_local_mat(sd, ob);
-
- /* Apply one type of brush action */
- switch (brush->sculpt_tool) {
- case SCULPT_TOOL_DRAW:
- do_draw_brush(sd, ob, nodes, totnode);
- break;
- case SCULPT_TOOL_SMOOTH:
- do_smooth_brush(sd, ob, nodes, totnode);
- break;
- case SCULPT_TOOL_CREASE:
- do_crease_brush(sd, ob, nodes, totnode);
- break;
- case SCULPT_TOOL_BLOB:
- do_crease_brush(sd, ob, nodes, totnode);
- break;
- case SCULPT_TOOL_PINCH:
- do_pinch_brush(sd, ob, nodes, totnode);
- break;
- case SCULPT_TOOL_INFLATE:
- do_inflate_brush(sd, ob, nodes, totnode);
- break;
- case SCULPT_TOOL_GRAB:
- do_grab_brush(sd, ob, nodes, totnode);
- break;
- case SCULPT_TOOL_ROTATE:
- do_rotate_brush(sd, ob, nodes, totnode);
- break;
- case SCULPT_TOOL_SNAKE_HOOK:
- do_snake_hook_brush(sd, ob, nodes, totnode);
- break;
- case SCULPT_TOOL_NUDGE:
- do_nudge_brush(sd, ob, nodes, totnode);
- break;
- case SCULPT_TOOL_THUMB:
- do_thumb_brush(sd, ob, nodes, totnode);
- break;
- case SCULPT_TOOL_LAYER:
- do_layer_brush(sd, ob, nodes, totnode);
- break;
- case SCULPT_TOOL_FLATTEN:
- do_flatten_brush(sd, ob, nodes, totnode);
- break;
- case SCULPT_TOOL_CLAY:
- do_clay_brush(sd, ob, nodes, totnode);
- break;
- case SCULPT_TOOL_CLAY_STRIPS:
- do_clay_strips_brush(sd, ob, nodes, totnode);
- break;
- case SCULPT_TOOL_FILL:
- do_fill_brush(sd, ob, nodes, totnode);
- break;
- case SCULPT_TOOL_SCRAPE:
- do_scrape_brush(sd, ob, nodes, totnode);
- break;
- case SCULPT_TOOL_MASK:
- do_mask_brush(sd, ob, nodes, totnode);
- break;
- }
-
- if (!ELEM(brush->sculpt_tool, SCULPT_TOOL_SMOOTH, SCULPT_TOOL_MASK) &&
- brush->autosmooth_factor > 0)
- {
- if (brush->flag & BRUSH_INVERSE_SMOOTH_PRESSURE) {
- smooth(sd, ob, nodes, totnode, brush->autosmooth_factor * (1 - ss->cache->pressure), false);
- }
- else {
- smooth(sd, ob, nodes, totnode, brush->autosmooth_factor, false);
- }
- }
-
- if (sculpt_brush_use_topology_rake(ss, brush)) {
- bmesh_topology_rake(sd, ob, nodes, totnode, brush->topology_rake_factor);
- }
-
- if (ss->cache->supports_gravity)
- do_gravity(sd, ob, nodes, totnode, sd->gravity_factor);
-
- MEM_freeN(nodes);
-
- /* update average stroke position */
- copy_v3_v3(location, ss->cache->true_location);
- mul_m4_v3(ob->obmat, location);
-
- add_v3_v3(ups->average_stroke_accum, location);
- ups->average_stroke_counter++;
- /* update last stroke position */
- ups->last_stroke_valid = true;
- }
+ SculptSession *ss = ob->sculpt;
+ int totnode;
+
+ /* Build a list of all nodes that are potentially within the brush's area of influence */
+ const bool use_original = sculpt_tool_needs_original(brush->sculpt_tool) ? true :
+ ss->cache->original;
+ const float radius_scale = 1.0f;
+ PBVHNode **nodes = sculpt_pbvh_gather_generic(
+ ob, sd, brush, use_original, radius_scale, &totnode);
+
+ /* Only act if some verts are inside the brush area */
+ if (totnode) {
+ float location[3];
+
+ SculptThreadedTaskData task_data = {
+ .sd = sd,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ };
+
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
+ BLI_task_parallel_range(0, totnode, &task_data, do_brush_action_task_cb, &settings);
+
+ if (sculpt_brush_needs_normal(ss, brush))
+ update_sculpt_normal(sd, ob, nodes, totnode);
+
+ if (brush->mtex.brush_map_mode == MTEX_MAP_MODE_AREA)
+ update_brush_local_mat(sd, ob);
+
+ /* Apply one type of brush action */
+ switch (brush->sculpt_tool) {
+ case SCULPT_TOOL_DRAW:
+ do_draw_brush(sd, ob, nodes, totnode);
+ break;
+ case SCULPT_TOOL_SMOOTH:
+ do_smooth_brush(sd, ob, nodes, totnode);
+ break;
+ case SCULPT_TOOL_CREASE:
+ do_crease_brush(sd, ob, nodes, totnode);
+ break;
+ case SCULPT_TOOL_BLOB:
+ do_crease_brush(sd, ob, nodes, totnode);
+ break;
+ case SCULPT_TOOL_PINCH:
+ do_pinch_brush(sd, ob, nodes, totnode);
+ break;
+ case SCULPT_TOOL_INFLATE:
+ do_inflate_brush(sd, ob, nodes, totnode);
+ break;
+ case SCULPT_TOOL_GRAB:
+ do_grab_brush(sd, ob, nodes, totnode);
+ break;
+ case SCULPT_TOOL_ROTATE:
+ do_rotate_brush(sd, ob, nodes, totnode);
+ break;
+ case SCULPT_TOOL_SNAKE_HOOK:
+ do_snake_hook_brush(sd, ob, nodes, totnode);
+ break;
+ case SCULPT_TOOL_NUDGE:
+ do_nudge_brush(sd, ob, nodes, totnode);
+ break;
+ case SCULPT_TOOL_THUMB:
+ do_thumb_brush(sd, ob, nodes, totnode);
+ break;
+ case SCULPT_TOOL_LAYER:
+ do_layer_brush(sd, ob, nodes, totnode);
+ break;
+ case SCULPT_TOOL_FLATTEN:
+ do_flatten_brush(sd, ob, nodes, totnode);
+ break;
+ case SCULPT_TOOL_CLAY:
+ do_clay_brush(sd, ob, nodes, totnode);
+ break;
+ case SCULPT_TOOL_CLAY_STRIPS:
+ do_clay_strips_brush(sd, ob, nodes, totnode);
+ break;
+ case SCULPT_TOOL_FILL:
+ do_fill_brush(sd, ob, nodes, totnode);
+ break;
+ case SCULPT_TOOL_SCRAPE:
+ do_scrape_brush(sd, ob, nodes, totnode);
+ break;
+ case SCULPT_TOOL_MASK:
+ do_mask_brush(sd, ob, nodes, totnode);
+ break;
+ }
+
+ if (!ELEM(brush->sculpt_tool, SCULPT_TOOL_SMOOTH, SCULPT_TOOL_MASK) &&
+ brush->autosmooth_factor > 0) {
+ if (brush->flag & BRUSH_INVERSE_SMOOTH_PRESSURE) {
+ smooth(
+ sd, ob, nodes, totnode, brush->autosmooth_factor * (1 - ss->cache->pressure), false);
+ }
+ else {
+ smooth(sd, ob, nodes, totnode, brush->autosmooth_factor, false);
+ }
+ }
+
+ if (sculpt_brush_use_topology_rake(ss, brush)) {
+ bmesh_topology_rake(sd, ob, nodes, totnode, brush->topology_rake_factor);
+ }
+
+ if (ss->cache->supports_gravity)
+ do_gravity(sd, ob, nodes, totnode, sd->gravity_factor);
+
+ MEM_freeN(nodes);
+
+ /* update average stroke position */
+ copy_v3_v3(location, ss->cache->true_location);
+ mul_m4_v3(ob->obmat, location);
+
+ add_v3_v3(ups->average_stroke_accum, location);
+ ups->average_stroke_counter++;
+ /* update last stroke position */
+ ups->last_stroke_valid = true;
+ }
}
/* flush displacement from deformed PBVH vertex to original mesh */
static void sculpt_flush_pbvhvert_deform(Object *ob, PBVHVertexIter *vd)
{
- SculptSession *ss = ob->sculpt;
- Mesh *me = ob->data;
- float disp[3], newco[3];
- int index = vd->vert_indices[vd->i];
+ SculptSession *ss = ob->sculpt;
+ Mesh *me = ob->data;
+ float disp[3], newco[3];
+ int index = vd->vert_indices[vd->i];
- sub_v3_v3v3(disp, vd->co, ss->deform_cos[index]);
- mul_m3_v3(ss->deform_imats[index], disp);
- add_v3_v3v3(newco, disp, ss->orig_cos[index]);
+ sub_v3_v3v3(disp, vd->co, ss->deform_cos[index]);
+ mul_m3_v3(ss->deform_imats[index], disp);
+ add_v3_v3v3(newco, disp, ss->orig_cos[index]);
- copy_v3_v3(ss->deform_cos[index], vd->co);
- copy_v3_v3(ss->orig_cos[index], newco);
+ copy_v3_v3(ss->deform_cos[index], vd->co);
+ copy_v3_v3(ss->orig_cos[index], newco);
- if (!ss->kb)
- copy_v3_v3(me->mvert[index].co, newco);
+ if (!ss->kb)
+ copy_v3_v3(me->mvert[index].co, newco);
}
-static void sculpt_combine_proxies_task_cb(
- void *__restrict userdata,
- const int n,
- const ParallelRangeTLS *__restrict UNUSED(tls))
+static void sculpt_combine_proxies_task_cb(void *__restrict userdata,
+ const int n,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- Sculpt *sd = data->sd;
- Object *ob = data->ob;
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ Sculpt *sd = data->sd;
+ Object *ob = data->ob;
- /* these brushes start from original coordinates */
- const bool use_orco = ELEM(data->brush->sculpt_tool, SCULPT_TOOL_GRAB, SCULPT_TOOL_ROTATE, SCULPT_TOOL_THUMB);
+ /* these brushes start from original coordinates */
+ const bool use_orco = ELEM(
+ data->brush->sculpt_tool, SCULPT_TOOL_GRAB, SCULPT_TOOL_ROTATE, SCULPT_TOOL_THUMB);
- PBVHVertexIter vd;
- PBVHProxyNode *proxies;
- int proxy_count;
- float (*orco)[3] = NULL;
+ PBVHVertexIter vd;
+ PBVHProxyNode *proxies;
+ int proxy_count;
+ float(*orco)[3] = NULL;
- if (use_orco && !ss->bm)
- orco = sculpt_undo_push_node(data->ob, data->nodes[n], SCULPT_UNDO_COORDS)->co;
+ if (use_orco && !ss->bm)
+ orco = sculpt_undo_push_node(data->ob, data->nodes[n], SCULPT_UNDO_COORDS)->co;
- BKE_pbvh_node_get_proxies(data->nodes[n], &proxies, &proxy_count);
+ BKE_pbvh_node_get_proxies(data->nodes[n], &proxies, &proxy_count);
- BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
- {
- float val[3];
- int p;
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
+ {
+ float val[3];
+ int p;
- if (use_orco) {
- if (ss->bm) {
- copy_v3_v3(val, BM_log_original_vert_co(ss->bm_log, vd.bm_vert));
- }
- else {
- copy_v3_v3(val, orco[vd.i]);
- }
- }
- else {
- copy_v3_v3(val, vd.co);
- }
+ if (use_orco) {
+ if (ss->bm) {
+ copy_v3_v3(val, BM_log_original_vert_co(ss->bm_log, vd.bm_vert));
+ }
+ else {
+ copy_v3_v3(val, orco[vd.i]);
+ }
+ }
+ else {
+ copy_v3_v3(val, vd.co);
+ }
- for (p = 0; p < proxy_count; p++)
- add_v3_v3(val, proxies[p].co[vd.i]);
+ for (p = 0; p < proxy_count; p++)
+ add_v3_v3(val, proxies[p].co[vd.i]);
- sculpt_clip(sd, ss, vd.co, val);
+ sculpt_clip(sd, ss, vd.co, val);
- if (ss->modifiers_active)
- sculpt_flush_pbvhvert_deform(ob, &vd);
- }
- BKE_pbvh_vertex_iter_end;
+ if (ss->modifiers_active)
+ sculpt_flush_pbvhvert_deform(ob, &vd);
+ }
+ BKE_pbvh_vertex_iter_end;
- BKE_pbvh_node_free_proxies(data->nodes[n]);
+ BKE_pbvh_node_free_proxies(data->nodes[n]);
}
static void sculpt_combine_proxies(Sculpt *sd, Object *ob)
{
- SculptSession *ss = ob->sculpt;
- Brush *brush = BKE_paint_brush(&sd->paint);
- PBVHNode **nodes;
- int totnode;
+ SculptSession *ss = ob->sculpt;
+ Brush *brush = BKE_paint_brush(&sd->paint);
+ PBVHNode **nodes;
+ int totnode;
- BKE_pbvh_gather_proxies(ss->pbvh, &nodes, &totnode);
+ BKE_pbvh_gather_proxies(ss->pbvh, &nodes, &totnode);
- /* first line is tools that don't support proxies */
- if (ss->cache->supports_gravity ||
- (sculpt_tool_is_proxy_used(brush->sculpt_tool) == false))
- {
- SculptThreadedTaskData data = {
- .sd = sd, .ob = ob, .brush = brush, .nodes = nodes,
- };
+ /* first line is tools that don't support proxies */
+ if (ss->cache->supports_gravity || (sculpt_tool_is_proxy_used(brush->sculpt_tool) == false)) {
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ };
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
- BLI_task_parallel_range(
- 0, totnode,
- &data,
- sculpt_combine_proxies_task_cb,
- &settings);
- }
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
+ BLI_task_parallel_range(0, totnode, &data, sculpt_combine_proxies_task_cb, &settings);
+ }
- if (nodes)
- MEM_freeN(nodes);
+ if (nodes)
+ MEM_freeN(nodes);
}
/* copy the modified vertices from bvh to the active key */
static void sculpt_update_keyblock(Object *ob)
{
- SculptSession *ss = ob->sculpt;
- float (*vertCos)[3];
+ SculptSession *ss = ob->sculpt;
+ float(*vertCos)[3];
- /* Keyblock update happens after handling deformation caused by modifiers,
- * so ss->orig_cos would be updated with new stroke */
- if (ss->orig_cos) vertCos = ss->orig_cos;
- else vertCos = BKE_pbvh_get_vertCos(ss->pbvh);
+ /* Keyblock update happens after handling deformation caused by modifiers,
+ * so ss->orig_cos would be updated with new stroke */
+ if (ss->orig_cos)
+ vertCos = ss->orig_cos;
+ else
+ vertCos = BKE_pbvh_get_vertCos(ss->pbvh);
- if (vertCos) {
- sculpt_vertcos_to_key(ob, ss->kb, vertCos);
+ if (vertCos) {
+ sculpt_vertcos_to_key(ob, ss->kb, vertCos);
- if (vertCos != ss->orig_cos)
- MEM_freeN(vertCos);
- }
+ if (vertCos != ss->orig_cos)
+ MEM_freeN(vertCos);
+ }
}
-static void sculpt_flush_stroke_deform_task_cb(
- void *__restrict userdata,
- const int n,
- const ParallelRangeTLS *__restrict UNUSED(tls))
+static void sculpt_flush_stroke_deform_task_cb(void *__restrict userdata,
+ const int n,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- Object *ob = data->ob;
- float (*vertCos)[3] = data->vertCos;
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ Object *ob = data->ob;
+ float(*vertCos)[3] = data->vertCos;
- PBVHVertexIter vd;
+ PBVHVertexIter vd;
- BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
- {
- sculpt_flush_pbvhvert_deform(ob, &vd);
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
+ {
+ sculpt_flush_pbvhvert_deform(ob, &vd);
- if (vertCos) {
- int index = vd.vert_indices[vd.i];
- copy_v3_v3(vertCos[index], ss->orig_cos[index]);
- }
- }
- BKE_pbvh_vertex_iter_end;
+ if (vertCos) {
+ int index = vd.vert_indices[vd.i];
+ copy_v3_v3(vertCos[index], ss->orig_cos[index]);
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
}
/* flush displacement from deformed PBVH to original layer */
static void sculpt_flush_stroke_deform(Sculpt *sd, Object *ob)
{
- SculptSession *ss = ob->sculpt;
- Brush *brush = BKE_paint_brush(&sd->paint);
-
- if (sculpt_tool_is_proxy_used(brush->sculpt_tool)) {
- /* this brushes aren't using proxies, so sculpt_combine_proxies() wouldn't
- * propagate needed deformation to original base */
-
- int totnode;
- Mesh *me = (Mesh *)ob->data;
- PBVHNode **nodes;
- float (*vertCos)[3] = NULL;
-
- if (ss->kb) {
- vertCos = MEM_mallocN(sizeof(*vertCos) * me->totvert, "flushStrokeDeofrm keyVerts");
-
- /* mesh could have isolated verts which wouldn't be in BVH,
- * to deal with this we copy old coordinates over new ones
- * and then update coordinates for all vertices from BVH
- */
- memcpy(vertCos, ss->orig_cos, sizeof(*vertCos) * me->totvert);
- }
-
- BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode);
-
- SculptThreadedTaskData data = {
- .sd = sd, .ob = ob, .brush = brush, .nodes = nodes,
- .vertCos = vertCos,
- };
-
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
- BLI_task_parallel_range(
- 0, totnode,
- &data,
- sculpt_flush_stroke_deform_task_cb,
- &settings);
-
- if (vertCos) {
- sculpt_vertcos_to_key(ob, ss->kb, vertCos);
- MEM_freeN(vertCos);
- }
-
- MEM_freeN(nodes);
-
- /* Modifiers could depend on mesh normals, so we should update them/
- * Note, then if sculpting happens on locked key, normals should be re-calculated
- * after applying coords from keyblock on base mesh */
- BKE_mesh_calc_normals(me);
- }
- else if (ss->kb) {
- sculpt_update_keyblock(ob);
- }
+ SculptSession *ss = ob->sculpt;
+ Brush *brush = BKE_paint_brush(&sd->paint);
+
+ if (sculpt_tool_is_proxy_used(brush->sculpt_tool)) {
+ /* this brushes aren't using proxies, so sculpt_combine_proxies() wouldn't
+ * propagate needed deformation to original base */
+
+ int totnode;
+ Mesh *me = (Mesh *)ob->data;
+ PBVHNode **nodes;
+ float(*vertCos)[3] = NULL;
+
+ if (ss->kb) {
+ vertCos = MEM_mallocN(sizeof(*vertCos) * me->totvert, "flushStrokeDeofrm keyVerts");
+
+ /* mesh could have isolated verts which wouldn't be in BVH,
+ * to deal with this we copy old coordinates over new ones
+ * and then update coordinates for all vertices from BVH
+ */
+ memcpy(vertCos, ss->orig_cos, sizeof(*vertCos) * me->totvert);
+ }
+
+ BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode);
+
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ .vertCos = vertCos,
+ };
+
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
+ BLI_task_parallel_range(0, totnode, &data, sculpt_flush_stroke_deform_task_cb, &settings);
+
+ if (vertCos) {
+ sculpt_vertcos_to_key(ob, ss->kb, vertCos);
+ MEM_freeN(vertCos);
+ }
+
+ MEM_freeN(nodes);
+
+ /* Modifiers could depend on mesh normals, so we should update them/
+ * Note, then if sculpting happens on locked key, normals should be re-calculated
+ * after applying coords from keyblock on base mesh */
+ BKE_mesh_calc_normals(me);
+ }
+ else if (ss->kb) {
+ sculpt_update_keyblock(ob);
+ }
}
/* Flip all the editdata across the axis/axes specified by symm. Used to
* calculate multiple modifications to the mesh when symmetry is enabled. */
-void sculpt_cache_calc_brushdata_symm(
- StrokeCache *cache, const char symm,
- const char axis, const float angle)
-{
- flip_v3_v3(cache->location, cache->true_location, symm);
- flip_v3_v3(cache->last_location, cache->true_last_location, symm);
- flip_v3_v3(cache->grab_delta_symmetry, cache->grab_delta, symm);
- flip_v3_v3(cache->view_normal, cache->true_view_normal, symm);
-
- /* XXX This reduces the length of the grab delta if it approaches the line of symmetry
- * XXX However, a different approach appears to be needed */
+void sculpt_cache_calc_brushdata_symm(StrokeCache *cache,
+ const char symm,
+ const char axis,
+ const float angle)
+{
+ flip_v3_v3(cache->location, cache->true_location, symm);
+ flip_v3_v3(cache->last_location, cache->true_last_location, symm);
+ flip_v3_v3(cache->grab_delta_symmetry, cache->grab_delta, symm);
+ flip_v3_v3(cache->view_normal, cache->true_view_normal, symm);
+
+ /* XXX This reduces the length of the grab delta if it approaches the line of symmetry
+ * XXX However, a different approach appears to be needed */
#if 0
- if (sd->paint.symmetry_flags & PAINT_SYMMETRY_FEATHER) {
- float frac = 1.0f / max_overlap_count(sd);
- float reduce = (feather - frac) / (1 - frac);
+ if (sd->paint.symmetry_flags & PAINT_SYMMETRY_FEATHER) {
+ float frac = 1.0f / max_overlap_count(sd);
+ float reduce = (feather - frac) / (1 - frac);
- printf("feather: %f frac: %f reduce: %f\n", feather, frac, reduce);
+ printf("feather: %f frac: %f reduce: %f\n", feather, frac, reduce);
- if (frac < 1)
- mul_v3_fl(cache->grab_delta_symmetry, reduce);
- }
+ if (frac < 1)
+ mul_v3_fl(cache->grab_delta_symmetry, reduce);
+ }
#endif
- unit_m4(cache->symm_rot_mat);
- unit_m4(cache->symm_rot_mat_inv);
- zero_v3(cache->plane_offset);
+ unit_m4(cache->symm_rot_mat);
+ unit_m4(cache->symm_rot_mat_inv);
+ zero_v3(cache->plane_offset);
- if (axis) { /* expects XYZ */
- rotate_m4(cache->symm_rot_mat, axis, angle);
- rotate_m4(cache->symm_rot_mat_inv, axis, -angle);
- }
+ if (axis) { /* expects XYZ */
+ rotate_m4(cache->symm_rot_mat, axis, angle);
+ rotate_m4(cache->symm_rot_mat_inv, axis, -angle);
+ }
- mul_m4_v3(cache->symm_rot_mat, cache->location);
- mul_m4_v3(cache->symm_rot_mat, cache->grab_delta_symmetry);
+ mul_m4_v3(cache->symm_rot_mat, cache->location);
+ mul_m4_v3(cache->symm_rot_mat, cache->grab_delta_symmetry);
- if (cache->supports_gravity) {
- flip_v3_v3(cache->gravity_direction, cache->true_gravity_direction, symm);
- mul_m4_v3(cache->symm_rot_mat, cache->gravity_direction);
- }
+ if (cache->supports_gravity) {
+ flip_v3_v3(cache->gravity_direction, cache->true_gravity_direction, symm);
+ mul_m4_v3(cache->symm_rot_mat, cache->gravity_direction);
+ }
- if (cache->is_rake_rotation_valid) {
- flip_qt_qt(cache->rake_rotation_symmetry, cache->rake_rotation, symm);
- }
+ if (cache->is_rake_rotation_valid) {
+ flip_qt_qt(cache->rake_rotation_symmetry, cache->rake_rotation, symm);
+ }
}
typedef void (*BrushActionFunc)(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSettings *ups);
-static void do_tiled(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSettings *ups, BrushActionFunc action)
-{
- SculptSession *ss = ob->sculpt;
- StrokeCache *cache = ss->cache;
- const float radius = cache->radius;
- BoundBox *bb = BKE_object_boundbox_get(ob);
- const float *bbMin = bb->vec[0];
- const float *bbMax = bb->vec[6];
- const float *step = sd->paint.tile_offset;
- int dim;
-
- /* These are integer locations, for real location: multiply with step and add orgLoc.
- * So 0,0,0 is at orgLoc. */
- int start[3];
- int end[3];
- int cur[3];
-
- float orgLoc[3]; /* position of the "prototype" stroke for tiling */
- copy_v3_v3(orgLoc, cache->location);
-
- for (dim = 0; dim < 3; ++dim) {
- if ((sd->paint.symmetry_flags & (PAINT_TILE_X << dim)) && step[dim] > 0) {
- start[dim] = (bbMin[dim] - orgLoc[dim] - radius) / step[dim];
- end[dim] = (bbMax[dim] - orgLoc[dim] + radius) / step[dim];
- }
- else
- start[dim] = end[dim] = 0;
- }
-
- /* first do the "untiled" position to initialize the stroke for this location */
- cache->tile_pass = 0;
- action(sd, ob, brush, ups);
-
- /* now do it for all the tiles */
- copy_v3_v3_int(cur, start);
- for (cur[0] = start[0]; cur[0] <= end[0]; ++cur[0]) {
- for (cur[1] = start[1]; cur[1] <= end[1]; ++cur[1]) {
- for (cur[2] = start[2]; cur[2] <= end[2]; ++cur[2]) {
- if (!cur[0] && !cur[1] && !cur[2])
- continue; /* skip tile at orgLoc, this was already handled before all others */
-
- ++cache->tile_pass;
-
- for (dim = 0; dim < 3; ++dim) {
- cache->location[dim] = cur[dim] * step[dim] + orgLoc[dim];
- cache->plane_offset[dim] = cur[dim] * step[dim];
- }
- action(sd, ob, brush, ups);
- }
- }
- }
-}
-
-
-static void do_radial_symmetry(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSettings *ups,
+static void do_tiled(
+ Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSettings *ups, BrushActionFunc action)
+{
+ SculptSession *ss = ob->sculpt;
+ StrokeCache *cache = ss->cache;
+ const float radius = cache->radius;
+ BoundBox *bb = BKE_object_boundbox_get(ob);
+ const float *bbMin = bb->vec[0];
+ const float *bbMax = bb->vec[6];
+ const float *step = sd->paint.tile_offset;
+ int dim;
+
+ /* These are integer locations, for real location: multiply with step and add orgLoc.
+ * So 0,0,0 is at orgLoc. */
+ int start[3];
+ int end[3];
+ int cur[3];
+
+ float orgLoc[3]; /* position of the "prototype" stroke for tiling */
+ copy_v3_v3(orgLoc, cache->location);
+
+ for (dim = 0; dim < 3; ++dim) {
+ if ((sd->paint.symmetry_flags & (PAINT_TILE_X << dim)) && step[dim] > 0) {
+ start[dim] = (bbMin[dim] - orgLoc[dim] - radius) / step[dim];
+ end[dim] = (bbMax[dim] - orgLoc[dim] + radius) / step[dim];
+ }
+ else
+ start[dim] = end[dim] = 0;
+ }
+
+ /* first do the "untiled" position to initialize the stroke for this location */
+ cache->tile_pass = 0;
+ action(sd, ob, brush, ups);
+
+ /* now do it for all the tiles */
+ copy_v3_v3_int(cur, start);
+ for (cur[0] = start[0]; cur[0] <= end[0]; ++cur[0]) {
+ for (cur[1] = start[1]; cur[1] <= end[1]; ++cur[1]) {
+ for (cur[2] = start[2]; cur[2] <= end[2]; ++cur[2]) {
+ if (!cur[0] && !cur[1] && !cur[2])
+ continue; /* skip tile at orgLoc, this was already handled before all others */
+
+ ++cache->tile_pass;
+
+ for (dim = 0; dim < 3; ++dim) {
+ cache->location[dim] = cur[dim] * step[dim] + orgLoc[dim];
+ cache->plane_offset[dim] = cur[dim] * step[dim];
+ }
+ action(sd, ob, brush, ups);
+ }
+ }
+ }
+}
+
+static void do_radial_symmetry(Sculpt *sd,
+ Object *ob,
+ Brush *brush,
+ UnifiedPaintSettings *ups,
BrushActionFunc action,
- const char symm, const int axis,
+ const char symm,
+ const int axis,
const float UNUSED(feather))
{
- SculptSession *ss = ob->sculpt;
- int i;
+ SculptSession *ss = ob->sculpt;
+ int i;
- for (i = 1; i < sd->radial_symm[axis - 'X']; ++i) {
- const float angle = 2 * M_PI * i / sd->radial_symm[axis - 'X'];
- ss->cache->radial_symmetry_pass = i;
- sculpt_cache_calc_brushdata_symm(ss->cache, symm, axis, angle);
- do_tiled(sd, ob, brush, ups, action);
- }
+ for (i = 1; i < sd->radial_symm[axis - 'X']; ++i) {
+ const float angle = 2 * M_PI * i / sd->radial_symm[axis - 'X'];
+ ss->cache->radial_symmetry_pass = i;
+ sculpt_cache_calc_brushdata_symm(ss->cache, symm, axis, angle);
+ do_tiled(sd, ob, brush, ups, action);
+ }
}
/* noise texture gives different values for the same input coord; this
@@ -4205,140 +4244,137 @@ static void do_radial_symmetry(Sculpt *sd, Object *ob, Brush *brush, UnifiedPain
* case */
static void sculpt_fix_noise_tear(Sculpt *sd, Object *ob)
{
- SculptSession *ss = ob->sculpt;
- Brush *brush = BKE_paint_brush(&sd->paint);
- MTex *mtex = &brush->mtex;
+ SculptSession *ss = ob->sculpt;
+ Brush *brush = BKE_paint_brush(&sd->paint);
+ MTex *mtex = &brush->mtex;
- if (ss->multires && mtex->tex && mtex->tex->type == TEX_NOISE)
- multires_stitch_grids(ob);
+ if (ss->multires && mtex->tex && mtex->tex->type == TEX_NOISE)
+ multires_stitch_grids(ob);
}
-static void do_symmetrical_brush_actions(
- Sculpt *sd, Object *ob,
- BrushActionFunc action, UnifiedPaintSettings *ups)
+static void do_symmetrical_brush_actions(Sculpt *sd,
+ Object *ob,
+ BrushActionFunc action,
+ UnifiedPaintSettings *ups)
{
- Brush *brush = BKE_paint_brush(&sd->paint);
- SculptSession *ss = ob->sculpt;
- StrokeCache *cache = ss->cache;
- const char symm = sd->paint.symmetry_flags & PAINT_SYMM_AXIS_ALL;
- int i;
+ Brush *brush = BKE_paint_brush(&sd->paint);
+ SculptSession *ss = ob->sculpt;
+ StrokeCache *cache = ss->cache;
+ const char symm = sd->paint.symmetry_flags & PAINT_SYMM_AXIS_ALL;
+ int i;
- float feather = calc_symmetry_feather(sd, ss->cache);
+ float feather = calc_symmetry_feather(sd, ss->cache);
- cache->bstrength = brush_strength(sd, cache, feather, ups);
- cache->symmetry = symm;
+ cache->bstrength = brush_strength(sd, cache, feather, ups);
+ cache->symmetry = symm;
- /* symm is a bit combination of XYZ - 1 is mirror X; 2 is Y; 3 is XY; 4 is Z; 5 is XZ; 6 is YZ; 7 is XYZ */
- for (i = 0; i <= symm; ++i) {
- if (i == 0 || (symm & i && (symm != 5 || i != 3) && (symm != 6 || (i != 3 && i != 5)))) {
- cache->mirror_symmetry_pass = i;
- cache->radial_symmetry_pass = 0;
+ /* symm is a bit combination of XYZ - 1 is mirror X; 2 is Y; 3 is XY; 4 is Z; 5 is XZ; 6 is YZ; 7 is XYZ */
+ for (i = 0; i <= symm; ++i) {
+ if (i == 0 || (symm & i && (symm != 5 || i != 3) && (symm != 6 || (i != 3 && i != 5)))) {
+ cache->mirror_symmetry_pass = i;
+ cache->radial_symmetry_pass = 0;
- sculpt_cache_calc_brushdata_symm(cache, i, 0, 0);
- do_tiled(sd, ob, brush, ups, action);
+ sculpt_cache_calc_brushdata_symm(cache, i, 0, 0);
+ do_tiled(sd, ob, brush, ups, action);
- do_radial_symmetry(sd, ob, brush, ups, action, i, 'X', feather);
- do_radial_symmetry(sd, ob, brush, ups, action, i, 'Y', feather);
- do_radial_symmetry(sd, ob, brush, ups, action, i, 'Z', feather);
- }
- }
+ do_radial_symmetry(sd, ob, brush, ups, action, i, 'X', feather);
+ do_radial_symmetry(sd, ob, brush, ups, action, i, 'Y', feather);
+ do_radial_symmetry(sd, ob, brush, ups, action, i, 'Z', feather);
+ }
+ }
}
static void sculpt_update_tex(const Scene *scene, Sculpt *sd, SculptSession *ss)
{
- Brush *brush = BKE_paint_brush(&sd->paint);
- const int radius = BKE_brush_size_get(scene, brush);
+ Brush *brush = BKE_paint_brush(&sd->paint);
+ const int radius = BKE_brush_size_get(scene, brush);
- if (ss->texcache) {
- MEM_freeN(ss->texcache);
- ss->texcache = NULL;
- }
+ if (ss->texcache) {
+ MEM_freeN(ss->texcache);
+ ss->texcache = NULL;
+ }
- if (ss->tex_pool) {
- BKE_image_pool_free(ss->tex_pool);
- ss->tex_pool = NULL;
- }
+ if (ss->tex_pool) {
+ BKE_image_pool_free(ss->tex_pool);
+ ss->tex_pool = NULL;
+ }
- /* Need to allocate a bigger buffer for bigger brush size */
- ss->texcache_side = 2 * radius;
- if (!ss->texcache || ss->texcache_side > ss->texcache_actual) {
- ss->texcache = BKE_brush_gen_texture_cache(brush, radius, false);
- ss->texcache_actual = ss->texcache_side;
- ss->tex_pool = BKE_image_pool_new();
- }
+ /* Need to allocate a bigger buffer for bigger brush size */
+ ss->texcache_side = 2 * radius;
+ if (!ss->texcache || ss->texcache_side > ss->texcache_actual) {
+ ss->texcache = BKE_brush_gen_texture_cache(brush, radius, false);
+ ss->texcache_actual = ss->texcache_side;
+ ss->tex_pool = BKE_image_pool_new();
+ }
}
-
-
bool sculpt_mode_poll(bContext *C)
{
- Object *ob = CTX_data_active_object(C);
- return ob && ob->mode & OB_MODE_SCULPT;
+ Object *ob = CTX_data_active_object(C);
+ return ob && ob->mode & OB_MODE_SCULPT;
}
bool sculpt_mode_poll_view3d(bContext *C)
{
- return (sculpt_mode_poll(C) &&
- CTX_wm_region_view3d(C));
+ return (sculpt_mode_poll(C) && CTX_wm_region_view3d(C));
}
bool sculpt_poll_view3d(bContext *C)
{
- return (sculpt_poll(C) &&
- CTX_wm_region_view3d(C));
+ return (sculpt_poll(C) && CTX_wm_region_view3d(C));
}
bool sculpt_poll(bContext *C)
{
- return sculpt_mode_poll(C) && paint_poll(C);
+ return sculpt_mode_poll(C) && paint_poll(C);
}
static const char *sculpt_tool_name(Sculpt *sd)
{
- Brush *brush = BKE_paint_brush(&sd->paint);
-
- switch ((eBrushSculptTool)brush->sculpt_tool) {
- case SCULPT_TOOL_DRAW:
- return "Draw Brush";
- case SCULPT_TOOL_SMOOTH:
- return "Smooth Brush";
- case SCULPT_TOOL_CREASE:
- return "Crease Brush";
- case SCULPT_TOOL_BLOB:
- return "Blob Brush";
- case SCULPT_TOOL_PINCH:
- return "Pinch Brush";
- case SCULPT_TOOL_INFLATE:
- return "Inflate Brush";
- case SCULPT_TOOL_GRAB:
- return "Grab Brush";
- case SCULPT_TOOL_NUDGE:
- return "Nudge Brush";
- case SCULPT_TOOL_THUMB:
- return "Thumb Brush";
- case SCULPT_TOOL_LAYER:
- return "Layer Brush";
- case SCULPT_TOOL_FLATTEN:
- return "Flatten Brush";
- case SCULPT_TOOL_CLAY:
- return "Clay Brush";
- case SCULPT_TOOL_CLAY_STRIPS:
- return "Clay Strips Brush";
- case SCULPT_TOOL_FILL:
- return "Fill Brush";
- case SCULPT_TOOL_SCRAPE:
- return "Scrape Brush";
- case SCULPT_TOOL_SNAKE_HOOK:
- return "Snake Hook Brush";
- case SCULPT_TOOL_ROTATE:
- return "Rotate Brush";
- case SCULPT_TOOL_MASK:
- return "Mask Brush";
- case SCULPT_TOOL_SIMPLIFY:
- return "Simplify Brush";
- }
-
- return "Sculpting";
+ Brush *brush = BKE_paint_brush(&sd->paint);
+
+ switch ((eBrushSculptTool)brush->sculpt_tool) {
+ case SCULPT_TOOL_DRAW:
+ return "Draw Brush";
+ case SCULPT_TOOL_SMOOTH:
+ return "Smooth Brush";
+ case SCULPT_TOOL_CREASE:
+ return "Crease Brush";
+ case SCULPT_TOOL_BLOB:
+ return "Blob Brush";
+ case SCULPT_TOOL_PINCH:
+ return "Pinch Brush";
+ case SCULPT_TOOL_INFLATE:
+ return "Inflate Brush";
+ case SCULPT_TOOL_GRAB:
+ return "Grab Brush";
+ case SCULPT_TOOL_NUDGE:
+ return "Nudge Brush";
+ case SCULPT_TOOL_THUMB:
+ return "Thumb Brush";
+ case SCULPT_TOOL_LAYER:
+ return "Layer Brush";
+ case SCULPT_TOOL_FLATTEN:
+ return "Flatten Brush";
+ case SCULPT_TOOL_CLAY:
+ return "Clay Brush";
+ case SCULPT_TOOL_CLAY_STRIPS:
+ return "Clay Strips Brush";
+ case SCULPT_TOOL_FILL:
+ return "Fill Brush";
+ case SCULPT_TOOL_SCRAPE:
+ return "Scrape Brush";
+ case SCULPT_TOOL_SNAKE_HOOK:
+ return "Snake Hook Brush";
+ case SCULPT_TOOL_ROTATE:
+ return "Rotate Brush";
+ case SCULPT_TOOL_MASK:
+ return "Mask Brush";
+ case SCULPT_TOOL_SIMPLIFY:
+ return "Simplify Brush";
+ }
+
+ return "Sculpting";
}
/**
@@ -4347,567 +4383,557 @@ static const char *sculpt_tool_name(Sculpt *sd)
void sculpt_cache_free(StrokeCache *cache)
{
- if (cache->dial)
- MEM_freeN(cache->dial);
- MEM_freeN(cache);
+ if (cache->dial)
+ MEM_freeN(cache->dial);
+ MEM_freeN(cache);
}
/* Initialize mirror modifier clipping */
static void sculpt_init_mirror_clipping(Object *ob, SculptSession *ss)
{
- ModifierData *md;
- int i;
-
- for (md = ob->modifiers.first; md; md = md->next) {
- if (md->type == eModifierType_Mirror &&
- (md->mode & eModifierMode_Realtime))
- {
- MirrorModifierData *mmd = (MirrorModifierData *)md;
-
- if (mmd->flag & MOD_MIR_CLIPPING) {
- /* check each axis for mirroring */
- for (i = 0; i < 3; ++i) {
- if (mmd->flag & (MOD_MIR_AXIS_X << i)) {
- /* enable sculpt clipping */
- ss->cache->flag |= CLIP_X << i;
-
- /* update the clip tolerance */
- if (mmd->tolerance >
- ss->cache->clip_tolerance[i])
- {
- ss->cache->clip_tolerance[i] =
- mmd->tolerance;
- }
- }
- }
- }
- }
- }
+ ModifierData *md;
+ int i;
+
+ for (md = ob->modifiers.first; md; md = md->next) {
+ if (md->type == eModifierType_Mirror && (md->mode & eModifierMode_Realtime)) {
+ MirrorModifierData *mmd = (MirrorModifierData *)md;
+
+ if (mmd->flag & MOD_MIR_CLIPPING) {
+ /* check each axis for mirroring */
+ for (i = 0; i < 3; ++i) {
+ if (mmd->flag & (MOD_MIR_AXIS_X << i)) {
+ /* enable sculpt clipping */
+ ss->cache->flag |= CLIP_X << i;
+
+ /* update the clip tolerance */
+ if (mmd->tolerance > ss->cache->clip_tolerance[i]) {
+ ss->cache->clip_tolerance[i] = mmd->tolerance;
+ }
+ }
+ }
+ }
+ }
+ }
}
/* Initialize the stroke cache invariants from operator properties */
static void sculpt_update_cache_invariants(
- bContext *C, Sculpt *sd, SculptSession *ss,
- wmOperator *op, const float mouse[2])
-{
- StrokeCache *cache = MEM_callocN(sizeof(StrokeCache), "stroke cache");
- Main *bmain = CTX_data_main(C);
- Scene *scene = CTX_data_scene(C);
- UnifiedPaintSettings *ups = &CTX_data_tool_settings(C)->unified_paint_settings;
- Brush *brush = BKE_paint_brush(&sd->paint);
- ViewContext *vc = paint_stroke_view_context(op->customdata);
- Object *ob = CTX_data_active_object(C);
- float mat[3][3];
- float viewDir[3] = {0.0f, 0.0f, 1.0f};
- float max_scale;
- int i;
- int mode;
-
- ss->cache = cache;
-
- /* Set scaling adjustment */
- if (brush->sculpt_tool == SCULPT_TOOL_LAYER) {
- max_scale = 1.0f;
- }
- else {
- max_scale = 0.0f;
- for (i = 0; i < 3; i ++) {
- max_scale = max_ff(max_scale, fabsf(ob->scale[i]));
- }
- }
- cache->scale[0] = max_scale / ob->scale[0];
- cache->scale[1] = max_scale / ob->scale[1];
- cache->scale[2] = max_scale / ob->scale[2];
-
- cache->plane_trim_squared = brush->plane_trim * brush->plane_trim;
-
- cache->flag = 0;
-
- sculpt_init_mirror_clipping(ob, ss);
-
- /* Initial mouse location */
- if (mouse)
- copy_v2_v2(cache->initial_mouse, mouse);
- else
- zero_v2(cache->initial_mouse);
-
- mode = RNA_enum_get(op->ptr, "mode");
- cache->invert = mode == BRUSH_STROKE_INVERT;
- cache->alt_smooth = mode == BRUSH_STROKE_SMOOTH;
- cache->normal_weight = brush->normal_weight;
-
- /* interpret invert as following normal, for grab brushes */
- if (SCULPT_TOOL_HAS_NORMAL_WEIGHT(brush->sculpt_tool)) {
- if (cache->invert) {
- cache->invert = false;
- cache->normal_weight = (cache->normal_weight == 0.0f);
- }
- }
-
- /* not very nice, but with current events system implementation
- * we can't handle brush appearance inversion hotkey separately (sergey) */
- if (cache->invert) ups->draw_inverted = true;
- else ups->draw_inverted = false;
-
- /* Alt-Smooth */
- if (cache->alt_smooth) {
- if (brush->sculpt_tool == SCULPT_TOOL_MASK) {
- cache->saved_mask_brush_tool = brush->mask_tool;
- brush->mask_tool = BRUSH_MASK_SMOOTH;
- }
- else {
- Paint *p = &sd->paint;
- Brush *br;
- int size = BKE_brush_size_get(scene, brush);
-
- BLI_strncpy(cache->saved_active_brush_name, brush->id.name + 2,
- sizeof(cache->saved_active_brush_name));
-
- br = (Brush *)BKE_libblock_find_name(bmain, ID_BR, "Smooth");
- if (br) {
- BKE_paint_brush_set(p, br);
- brush = br;
- cache->saved_smooth_size = BKE_brush_size_get(scene, brush);
- BKE_brush_size_set(scene, brush, size);
- curvemapping_initialize(brush->curve);
- }
- }
- }
-
- copy_v2_v2(cache->mouse, cache->initial_mouse);
- copy_v2_v2(ups->tex_mouse, cache->initial_mouse);
-
- /* Truly temporary data that isn't stored in properties */
-
- cache->vc = vc;
-
- cache->brush = brush;
-
- /* cache projection matrix */
- ED_view3d_ob_project_mat_get(cache->vc->rv3d, ob, cache->projection_mat);
-
- invert_m4_m4(ob->imat, ob->obmat);
- copy_m3_m4(mat, cache->vc->rv3d->viewinv);
- mul_m3_v3(mat, viewDir);
- copy_m3_m4(mat, ob->imat);
- mul_m3_v3(mat, viewDir);
- normalize_v3_v3(cache->true_view_normal, viewDir);
-
- cache->supports_gravity = (!ELEM(brush->sculpt_tool, SCULPT_TOOL_MASK, SCULPT_TOOL_SMOOTH, SCULPT_TOOL_SIMPLIFY) &&
- (sd->gravity_factor > 0.0f));
- /* get gravity vector in world space */
- if (cache->supports_gravity) {
- if (sd->gravity_object) {
- Object *gravity_object = sd->gravity_object;
-
- copy_v3_v3(cache->true_gravity_direction, gravity_object->obmat[2]);
- }
- else {
- cache->true_gravity_direction[0] = cache->true_gravity_direction[1] = 0.0;
- cache->true_gravity_direction[2] = 1.0;
- }
-
- /* transform to sculpted object space */
- mul_m3_v3(mat, cache->true_gravity_direction);
- normalize_v3(cache->true_gravity_direction);
- }
-
- /* Initialize layer brush displacements and persistent coords */
- if (brush->sculpt_tool == SCULPT_TOOL_LAYER) {
- /* not supported yet for multires or dynamic topology */
- if (!ss->multires && !ss->bm && !ss->layer_co &&
- (brush->flag & BRUSH_PERSISTENT))
- {
- if (!ss->layer_co)
- ss->layer_co = MEM_mallocN(sizeof(float) * 3 * ss->totvert,
- "sculpt mesh vertices copy");
-
- if (ss->deform_cos) {
- memcpy(ss->layer_co, ss->deform_cos, ss->totvert);
- }
- else {
- for (i = 0; i < ss->totvert; ++i) {
- copy_v3_v3(ss->layer_co[i], ss->mvert[i].co);
- }
- }
- }
-
- if (ss->bm) {
- /* Free any remaining layer displacements from nodes. If not and topology changes
- * from using another tool, then next layer toolstroke
- * can access past disp array bounds */
- BKE_pbvh_free_layer_disp(ss->pbvh);
- }
- }
-
- /* Make copies of the mesh vertex locations and normals for some tools */
- if (brush->flag & BRUSH_ANCHORED) {
- cache->original = 1;
- }
-
- if (SCULPT_TOOL_HAS_ACCUMULATE(brush->sculpt_tool)) {
- if (!(brush->flag & BRUSH_ACCUMULATE)) {
- cache->original = 1;
- }
- }
-
- cache->first_time = 1;
+ bContext *C, Sculpt *sd, SculptSession *ss, wmOperator *op, const float mouse[2])
+{
+ StrokeCache *cache = MEM_callocN(sizeof(StrokeCache), "stroke cache");
+ Main *bmain = CTX_data_main(C);
+ Scene *scene = CTX_data_scene(C);
+ UnifiedPaintSettings *ups = &CTX_data_tool_settings(C)->unified_paint_settings;
+ Brush *brush = BKE_paint_brush(&sd->paint);
+ ViewContext *vc = paint_stroke_view_context(op->customdata);
+ Object *ob = CTX_data_active_object(C);
+ float mat[3][3];
+ float viewDir[3] = {0.0f, 0.0f, 1.0f};
+ float max_scale;
+ int i;
+ int mode;
+
+ ss->cache = cache;
+
+ /* Set scaling adjustment */
+ if (brush->sculpt_tool == SCULPT_TOOL_LAYER) {
+ max_scale = 1.0f;
+ }
+ else {
+ max_scale = 0.0f;
+ for (i = 0; i < 3; i++) {
+ max_scale = max_ff(max_scale, fabsf(ob->scale[i]));
+ }
+ }
+ cache->scale[0] = max_scale / ob->scale[0];
+ cache->scale[1] = max_scale / ob->scale[1];
+ cache->scale[2] = max_scale / ob->scale[2];
+
+ cache->plane_trim_squared = brush->plane_trim * brush->plane_trim;
+
+ cache->flag = 0;
+
+ sculpt_init_mirror_clipping(ob, ss);
+
+ /* Initial mouse location */
+ if (mouse)
+ copy_v2_v2(cache->initial_mouse, mouse);
+ else
+ zero_v2(cache->initial_mouse);
+
+ mode = RNA_enum_get(op->ptr, "mode");
+ cache->invert = mode == BRUSH_STROKE_INVERT;
+ cache->alt_smooth = mode == BRUSH_STROKE_SMOOTH;
+ cache->normal_weight = brush->normal_weight;
+
+ /* interpret invert as following normal, for grab brushes */
+ if (SCULPT_TOOL_HAS_NORMAL_WEIGHT(brush->sculpt_tool)) {
+ if (cache->invert) {
+ cache->invert = false;
+ cache->normal_weight = (cache->normal_weight == 0.0f);
+ }
+ }
+
+ /* not very nice, but with current events system implementation
+ * we can't handle brush appearance inversion hotkey separately (sergey) */
+ if (cache->invert)
+ ups->draw_inverted = true;
+ else
+ ups->draw_inverted = false;
+
+ /* Alt-Smooth */
+ if (cache->alt_smooth) {
+ if (brush->sculpt_tool == SCULPT_TOOL_MASK) {
+ cache->saved_mask_brush_tool = brush->mask_tool;
+ brush->mask_tool = BRUSH_MASK_SMOOTH;
+ }
+ else {
+ Paint *p = &sd->paint;
+ Brush *br;
+ int size = BKE_brush_size_get(scene, brush);
+
+ BLI_strncpy(cache->saved_active_brush_name,
+ brush->id.name + 2,
+ sizeof(cache->saved_active_brush_name));
+
+ br = (Brush *)BKE_libblock_find_name(bmain, ID_BR, "Smooth");
+ if (br) {
+ BKE_paint_brush_set(p, br);
+ brush = br;
+ cache->saved_smooth_size = BKE_brush_size_get(scene, brush);
+ BKE_brush_size_set(scene, brush, size);
+ curvemapping_initialize(brush->curve);
+ }
+ }
+ }
+
+ copy_v2_v2(cache->mouse, cache->initial_mouse);
+ copy_v2_v2(ups->tex_mouse, cache->initial_mouse);
+
+ /* Truly temporary data that isn't stored in properties */
+
+ cache->vc = vc;
+
+ cache->brush = brush;
+
+ /* cache projection matrix */
+ ED_view3d_ob_project_mat_get(cache->vc->rv3d, ob, cache->projection_mat);
+
+ invert_m4_m4(ob->imat, ob->obmat);
+ copy_m3_m4(mat, cache->vc->rv3d->viewinv);
+ mul_m3_v3(mat, viewDir);
+ copy_m3_m4(mat, ob->imat);
+ mul_m3_v3(mat, viewDir);
+ normalize_v3_v3(cache->true_view_normal, viewDir);
+
+ cache->supports_gravity =
+ (!ELEM(brush->sculpt_tool, SCULPT_TOOL_MASK, SCULPT_TOOL_SMOOTH, SCULPT_TOOL_SIMPLIFY) &&
+ (sd->gravity_factor > 0.0f));
+ /* get gravity vector in world space */
+ if (cache->supports_gravity) {
+ if (sd->gravity_object) {
+ Object *gravity_object = sd->gravity_object;
+
+ copy_v3_v3(cache->true_gravity_direction, gravity_object->obmat[2]);
+ }
+ else {
+ cache->true_gravity_direction[0] = cache->true_gravity_direction[1] = 0.0;
+ cache->true_gravity_direction[2] = 1.0;
+ }
+
+ /* transform to sculpted object space */
+ mul_m3_v3(mat, cache->true_gravity_direction);
+ normalize_v3(cache->true_gravity_direction);
+ }
+
+ /* Initialize layer brush displacements and persistent coords */
+ if (brush->sculpt_tool == SCULPT_TOOL_LAYER) {
+ /* not supported yet for multires or dynamic topology */
+ if (!ss->multires && !ss->bm && !ss->layer_co && (brush->flag & BRUSH_PERSISTENT)) {
+ if (!ss->layer_co)
+ ss->layer_co = MEM_mallocN(sizeof(float) * 3 * ss->totvert, "sculpt mesh vertices copy");
+
+ if (ss->deform_cos) {
+ memcpy(ss->layer_co, ss->deform_cos, ss->totvert);
+ }
+ else {
+ for (i = 0; i < ss->totvert; ++i) {
+ copy_v3_v3(ss->layer_co[i], ss->mvert[i].co);
+ }
+ }
+ }
+
+ if (ss->bm) {
+ /* Free any remaining layer displacements from nodes. If not and topology changes
+ * from using another tool, then next layer toolstroke
+ * can access past disp array bounds */
+ BKE_pbvh_free_layer_disp(ss->pbvh);
+ }
+ }
+
+ /* Make copies of the mesh vertex locations and normals for some tools */
+ if (brush->flag & BRUSH_ANCHORED) {
+ cache->original = 1;
+ }
+
+ if (SCULPT_TOOL_HAS_ACCUMULATE(brush->sculpt_tool)) {
+ if (!(brush->flag & BRUSH_ACCUMULATE)) {
+ cache->original = 1;
+ }
+ }
+
+ cache->first_time = 1;
#define PIXEL_INPUT_THRESHHOLD 5
- if (brush->sculpt_tool == SCULPT_TOOL_ROTATE)
- cache->dial = BLI_dial_initialize(cache->initial_mouse, PIXEL_INPUT_THRESHHOLD);
+ if (brush->sculpt_tool == SCULPT_TOOL_ROTATE)
+ cache->dial = BLI_dial_initialize(cache->initial_mouse, PIXEL_INPUT_THRESHHOLD);
#undef PIXEL_INPUT_THRESHHOLD
}
static void sculpt_update_brush_delta(UnifiedPaintSettings *ups, Object *ob, Brush *brush)
{
- SculptSession *ss = ob->sculpt;
- StrokeCache *cache = ss->cache;
- const float mouse[2] = {
- cache->mouse[0],
- cache->mouse[1],
- };
- int tool = brush->sculpt_tool;
-
- if (ELEM(tool,
- SCULPT_TOOL_GRAB, SCULPT_TOOL_NUDGE,
- SCULPT_TOOL_CLAY_STRIPS, SCULPT_TOOL_SNAKE_HOOK,
- SCULPT_TOOL_THUMB) ||
- sculpt_brush_use_topology_rake(ss, brush))
- {
- float grab_location[3], imat[4][4], delta[3], loc[3];
-
- if (cache->first_time) {
- copy_v3_v3(cache->orig_grab_location,
- cache->true_location);
- }
- else if (tool == SCULPT_TOOL_SNAKE_HOOK)
- add_v3_v3(cache->true_location, cache->grab_delta);
-
- /* compute 3d coordinate at same z from original location + mouse */
- mul_v3_m4v3(loc, ob->obmat, cache->orig_grab_location);
- ED_view3d_win_to_3d(cache->vc->v3d, cache->vc->ar, loc, mouse, grab_location);
-
- /* compute delta to move verts by */
- if (!cache->first_time) {
- switch (tool) {
- case SCULPT_TOOL_GRAB:
- case SCULPT_TOOL_THUMB:
- sub_v3_v3v3(delta, grab_location, cache->old_grab_location);
- invert_m4_m4(imat, ob->obmat);
- mul_mat3_m4_v3(imat, delta);
- add_v3_v3(cache->grab_delta, delta);
- break;
- case SCULPT_TOOL_CLAY_STRIPS:
- case SCULPT_TOOL_NUDGE:
- case SCULPT_TOOL_SNAKE_HOOK:
- if (brush->flag & BRUSH_ANCHORED) {
- float orig[3];
- mul_v3_m4v3(orig, ob->obmat, cache->orig_grab_location);
- sub_v3_v3v3(cache->grab_delta, grab_location, orig);
- }
- else {
- sub_v3_v3v3(cache->grab_delta, grab_location,
- cache->old_grab_location);
- }
- invert_m4_m4(imat, ob->obmat);
- mul_mat3_m4_v3(imat, cache->grab_delta);
- break;
- default:
- /* Use for 'Brush.topology_rake_factor'. */
- sub_v3_v3v3(cache->grab_delta, grab_location, cache->old_grab_location);
- break;
-
- }
- }
- else {
- zero_v3(cache->grab_delta);
- }
-
- if (brush->falloff_shape == PAINT_FALLOFF_SHAPE_TUBE) {
- project_plane_v3_v3v3(cache->grab_delta, cache->grab_delta, ss->cache->true_view_normal);
- }
-
- copy_v3_v3(cache->old_grab_location, grab_location);
-
- if (tool == SCULPT_TOOL_GRAB)
- copy_v3_v3(cache->anchored_location, cache->true_location);
- else if (tool == SCULPT_TOOL_THUMB)
- copy_v3_v3(cache->anchored_location, cache->orig_grab_location);
-
- if (ELEM(tool, SCULPT_TOOL_GRAB, SCULPT_TOOL_THUMB)) {
- /* location stays the same for finding vertices in brush radius */
- copy_v3_v3(cache->true_location, cache->orig_grab_location);
-
- ups->draw_anchored = true;
- copy_v2_v2(ups->anchored_initial_mouse, cache->initial_mouse);
- ups->anchored_size = ups->pixel_radius;
- }
-
-
- /* handle 'rake' */
- cache->is_rake_rotation_valid = false;
-
- if (cache->first_time) {
- copy_v3_v3(cache->rake_data.follow_co, grab_location);
- }
-
- if (sculpt_brush_needs_rake_rotation(brush)) {
- cache->rake_data.follow_dist = cache->radius * SCULPT_RAKE_BRUSH_FACTOR;
-
- if (!is_zero_v3(cache->grab_delta)) {
- const float eps = 0.00001f;
-
- float v1[3], v2[3];
-
- copy_v3_v3(v1, cache->rake_data.follow_co);
- copy_v3_v3(v2, cache->rake_data.follow_co);
- sub_v3_v3(v2, cache->grab_delta);
-
- sub_v3_v3(v1, grab_location);
- sub_v3_v3(v2, grab_location);
-
- if ((normalize_v3(v2) > eps) &&
- (normalize_v3(v1) > eps) &&
- (len_squared_v3v3(v1, v2) > eps))
- {
- const float rake_dist_sq = len_squared_v3v3(cache->rake_data.follow_co, grab_location);
- const float rake_fade = (rake_dist_sq > SQUARE(cache->rake_data.follow_dist)) ?
- 1.0f : sqrtf(rake_dist_sq) / cache->rake_data.follow_dist;
-
- float axis[3], angle;
- float tquat[4];
-
- rotation_between_vecs_to_quat(tquat, v1, v2);
-
- /* use axis-angle to scale rotation since the factor may be above 1 */
- quat_to_axis_angle(axis, &angle, tquat);
- normalize_v3(axis);
-
- angle *= brush->rake_factor * rake_fade;
- axis_angle_normalized_to_quat(cache->rake_rotation, axis, angle);
- cache->is_rake_rotation_valid = true;
- }
- }
- sculpt_rake_data_update(&cache->rake_data, grab_location);
- }
- }
+ SculptSession *ss = ob->sculpt;
+ StrokeCache *cache = ss->cache;
+ const float mouse[2] = {
+ cache->mouse[0],
+ cache->mouse[1],
+ };
+ int tool = brush->sculpt_tool;
+
+ if (ELEM(tool,
+ SCULPT_TOOL_GRAB,
+ SCULPT_TOOL_NUDGE,
+ SCULPT_TOOL_CLAY_STRIPS,
+ SCULPT_TOOL_SNAKE_HOOK,
+ SCULPT_TOOL_THUMB) ||
+ sculpt_brush_use_topology_rake(ss, brush)) {
+ float grab_location[3], imat[4][4], delta[3], loc[3];
+
+ if (cache->first_time) {
+ copy_v3_v3(cache->orig_grab_location, cache->true_location);
+ }
+ else if (tool == SCULPT_TOOL_SNAKE_HOOK)
+ add_v3_v3(cache->true_location, cache->grab_delta);
+
+ /* compute 3d coordinate at same z from original location + mouse */
+ mul_v3_m4v3(loc, ob->obmat, cache->orig_grab_location);
+ ED_view3d_win_to_3d(cache->vc->v3d, cache->vc->ar, loc, mouse, grab_location);
+
+ /* compute delta to move verts by */
+ if (!cache->first_time) {
+ switch (tool) {
+ case SCULPT_TOOL_GRAB:
+ case SCULPT_TOOL_THUMB:
+ sub_v3_v3v3(delta, grab_location, cache->old_grab_location);
+ invert_m4_m4(imat, ob->obmat);
+ mul_mat3_m4_v3(imat, delta);
+ add_v3_v3(cache->grab_delta, delta);
+ break;
+ case SCULPT_TOOL_CLAY_STRIPS:
+ case SCULPT_TOOL_NUDGE:
+ case SCULPT_TOOL_SNAKE_HOOK:
+ if (brush->flag & BRUSH_ANCHORED) {
+ float orig[3];
+ mul_v3_m4v3(orig, ob->obmat, cache->orig_grab_location);
+ sub_v3_v3v3(cache->grab_delta, grab_location, orig);
+ }
+ else {
+ sub_v3_v3v3(cache->grab_delta, grab_location, cache->old_grab_location);
+ }
+ invert_m4_m4(imat, ob->obmat);
+ mul_mat3_m4_v3(imat, cache->grab_delta);
+ break;
+ default:
+ /* Use for 'Brush.topology_rake_factor'. */
+ sub_v3_v3v3(cache->grab_delta, grab_location, cache->old_grab_location);
+ break;
+ }
+ }
+ else {
+ zero_v3(cache->grab_delta);
+ }
+
+ if (brush->falloff_shape == PAINT_FALLOFF_SHAPE_TUBE) {
+ project_plane_v3_v3v3(cache->grab_delta, cache->grab_delta, ss->cache->true_view_normal);
+ }
+
+ copy_v3_v3(cache->old_grab_location, grab_location);
+
+ if (tool == SCULPT_TOOL_GRAB)
+ copy_v3_v3(cache->anchored_location, cache->true_location);
+ else if (tool == SCULPT_TOOL_THUMB)
+ copy_v3_v3(cache->anchored_location, cache->orig_grab_location);
+
+ if (ELEM(tool, SCULPT_TOOL_GRAB, SCULPT_TOOL_THUMB)) {
+ /* location stays the same for finding vertices in brush radius */
+ copy_v3_v3(cache->true_location, cache->orig_grab_location);
+
+ ups->draw_anchored = true;
+ copy_v2_v2(ups->anchored_initial_mouse, cache->initial_mouse);
+ ups->anchored_size = ups->pixel_radius;
+ }
+
+ /* handle 'rake' */
+ cache->is_rake_rotation_valid = false;
+
+ if (cache->first_time) {
+ copy_v3_v3(cache->rake_data.follow_co, grab_location);
+ }
+
+ if (sculpt_brush_needs_rake_rotation(brush)) {
+ cache->rake_data.follow_dist = cache->radius * SCULPT_RAKE_BRUSH_FACTOR;
+
+ if (!is_zero_v3(cache->grab_delta)) {
+ const float eps = 0.00001f;
+
+ float v1[3], v2[3];
+
+ copy_v3_v3(v1, cache->rake_data.follow_co);
+ copy_v3_v3(v2, cache->rake_data.follow_co);
+ sub_v3_v3(v2, cache->grab_delta);
+
+ sub_v3_v3(v1, grab_location);
+ sub_v3_v3(v2, grab_location);
+
+ if ((normalize_v3(v2) > eps) && (normalize_v3(v1) > eps) &&
+ (len_squared_v3v3(v1, v2) > eps)) {
+ const float rake_dist_sq = len_squared_v3v3(cache->rake_data.follow_co, grab_location);
+ const float rake_fade = (rake_dist_sq > SQUARE(cache->rake_data.follow_dist)) ?
+ 1.0f :
+ sqrtf(rake_dist_sq) / cache->rake_data.follow_dist;
+
+ float axis[3], angle;
+ float tquat[4];
+
+ rotation_between_vecs_to_quat(tquat, v1, v2);
+
+ /* use axis-angle to scale rotation since the factor may be above 1 */
+ quat_to_axis_angle(axis, &angle, tquat);
+ normalize_v3(axis);
+
+ angle *= brush->rake_factor * rake_fade;
+ axis_angle_normalized_to_quat(cache->rake_rotation, axis, angle);
+ cache->is_rake_rotation_valid = true;
+ }
+ }
+ sculpt_rake_data_update(&cache->rake_data, grab_location);
+ }
+ }
}
/* Initialize the stroke cache variants from operator properties */
-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;
- SculptSession *ss = ob->sculpt;
- StrokeCache *cache = ss->cache;
- Brush *brush = BKE_paint_brush(&sd->paint);
-
- /* RNA_float_get_array(ptr, "location", cache->traced_location); */
-
- if (cache->first_time ||
- !((brush->flag & BRUSH_ANCHORED) ||
- (brush->sculpt_tool == SCULPT_TOOL_SNAKE_HOOK) ||
- (brush->sculpt_tool == SCULPT_TOOL_ROTATE))
- )
- {
- RNA_float_get_array(ptr, "location", cache->true_location);
- }
-
- cache->pen_flip = RNA_boolean_get(ptr, "pen_flip");
- RNA_float_get_array(ptr, "mouse", cache->mouse);
-
- /* XXX: Use pressure value from first brush step for brushes which don't
- * support strokes (grab, thumb). They depends on initial state and
- * brush coord/pressure/etc.
- * It's more an events design issue, which doesn't split coordinate/pressure/angle
- * changing events. We should avoid this after events system re-design */
- if (paint_supports_dynamic_size(brush, PAINT_MODE_SCULPT) || cache->first_time) {
- cache->pressure = RNA_float_get(ptr, "pressure");
- }
-
- /* Truly temporary data that isn't stored in properties */
- if (cache->first_time) {
- if (!BKE_brush_use_locked_size(scene, brush)) {
- cache->initial_radius = paint_calc_object_space_radius(cache->vc,
- cache->true_location,
- BKE_brush_size_get(scene, brush));
- BKE_brush_unprojected_radius_set(scene, brush, cache->initial_radius);
- }
- else {
- cache->initial_radius = BKE_brush_unprojected_radius_get(scene, brush);
- }
- }
-
- if (BKE_brush_use_size_pressure(scene, brush) && paint_supports_dynamic_size(brush, PAINT_MODE_SCULPT)) {
- cache->radius = cache->initial_radius * cache->pressure;
- }
- else {
- cache->radius = cache->initial_radius;
- }
-
- cache->radius_squared = cache->radius * cache->radius;
-
- if (brush->flag & BRUSH_ANCHORED) {
- /* true location has been calculated as part of the stroke system already here */
- if (brush->flag & BRUSH_EDGE_TO_EDGE) {
- RNA_float_get_array(ptr, "location", cache->true_location);
- }
-
- cache->radius = paint_calc_object_space_radius(cache->vc,
- cache->true_location,
- ups->pixel_radius);
- cache->radius_squared = cache->radius * cache->radius;
-
- copy_v3_v3(cache->anchored_location, cache->true_location);
- }
-
- sculpt_update_brush_delta(ups, ob, brush);
-
- if (brush->sculpt_tool == SCULPT_TOOL_ROTATE) {
- cache->vertex_rotation = -BLI_dial_angle(cache->dial, cache->mouse) * cache->bstrength;
-
- ups->draw_anchored = true;
- copy_v2_v2(ups->anchored_initial_mouse, cache->initial_mouse);
- copy_v3_v3(cache->anchored_location, cache->true_location);
- ups->anchored_size = ups->pixel_radius;
- }
-
- cache->special_rotation = ups->brush_rotation;
+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;
+ SculptSession *ss = ob->sculpt;
+ StrokeCache *cache = ss->cache;
+ Brush *brush = BKE_paint_brush(&sd->paint);
+
+ /* RNA_float_get_array(ptr, "location", cache->traced_location); */
+
+ if (cache->first_time ||
+ !((brush->flag & BRUSH_ANCHORED) || (brush->sculpt_tool == SCULPT_TOOL_SNAKE_HOOK) ||
+ (brush->sculpt_tool == SCULPT_TOOL_ROTATE))) {
+ RNA_float_get_array(ptr, "location", cache->true_location);
+ }
+
+ cache->pen_flip = RNA_boolean_get(ptr, "pen_flip");
+ RNA_float_get_array(ptr, "mouse", cache->mouse);
+
+ /* XXX: Use pressure value from first brush step for brushes which don't
+ * support strokes (grab, thumb). They depends on initial state and
+ * brush coord/pressure/etc.
+ * It's more an events design issue, which doesn't split coordinate/pressure/angle
+ * changing events. We should avoid this after events system re-design */
+ if (paint_supports_dynamic_size(brush, PAINT_MODE_SCULPT) || cache->first_time) {
+ cache->pressure = RNA_float_get(ptr, "pressure");
+ }
+
+ /* Truly temporary data that isn't stored in properties */
+ if (cache->first_time) {
+ if (!BKE_brush_use_locked_size(scene, brush)) {
+ cache->initial_radius = paint_calc_object_space_radius(
+ cache->vc, cache->true_location, BKE_brush_size_get(scene, brush));
+ BKE_brush_unprojected_radius_set(scene, brush, cache->initial_radius);
+ }
+ else {
+ cache->initial_radius = BKE_brush_unprojected_radius_get(scene, brush);
+ }
+ }
+
+ if (BKE_brush_use_size_pressure(scene, brush) &&
+ paint_supports_dynamic_size(brush, PAINT_MODE_SCULPT)) {
+ cache->radius = cache->initial_radius * cache->pressure;
+ }
+ else {
+ cache->radius = cache->initial_radius;
+ }
+
+ cache->radius_squared = cache->radius * cache->radius;
+
+ if (brush->flag & BRUSH_ANCHORED) {
+ /* true location has been calculated as part of the stroke system already here */
+ if (brush->flag & BRUSH_EDGE_TO_EDGE) {
+ RNA_float_get_array(ptr, "location", cache->true_location);
+ }
+
+ cache->radius = paint_calc_object_space_radius(
+ cache->vc, cache->true_location, ups->pixel_radius);
+ cache->radius_squared = cache->radius * cache->radius;
+
+ copy_v3_v3(cache->anchored_location, cache->true_location);
+ }
+
+ sculpt_update_brush_delta(ups, ob, brush);
+
+ if (brush->sculpt_tool == SCULPT_TOOL_ROTATE) {
+ cache->vertex_rotation = -BLI_dial_angle(cache->dial, cache->mouse) * cache->bstrength;
+
+ ups->draw_anchored = true;
+ copy_v2_v2(ups->anchored_initial_mouse, cache->initial_mouse);
+ copy_v3_v3(cache->anchored_location, cache->true_location);
+ ups->anchored_size = ups->pixel_radius;
+ }
+
+ cache->special_rotation = ups->brush_rotation;
}
/* Returns true if any of the smoothing modes are active (currently
* one of smooth brush, autosmooth, mask smooth, or shift-key
* smooth) */
-static bool sculpt_any_smooth_mode(const Brush *brush,
- StrokeCache *cache,
- int stroke_mode)
+static bool sculpt_any_smooth_mode(const Brush *brush, StrokeCache *cache, int stroke_mode)
{
- return ((stroke_mode == BRUSH_STROKE_SMOOTH) ||
- (cache && cache->alt_smooth) ||
- (brush->sculpt_tool == SCULPT_TOOL_SMOOTH) ||
- (brush->autosmooth_factor > 0) ||
- ((brush->sculpt_tool == SCULPT_TOOL_MASK) &&
- (brush->mask_tool == BRUSH_MASK_SMOOTH)));
+ return ((stroke_mode == BRUSH_STROKE_SMOOTH) || (cache && cache->alt_smooth) ||
+ (brush->sculpt_tool == SCULPT_TOOL_SMOOTH) || (brush->autosmooth_factor > 0) ||
+ ((brush->sculpt_tool == SCULPT_TOOL_MASK) && (brush->mask_tool == BRUSH_MASK_SMOOTH)));
}
static void sculpt_stroke_modifiers_check(const bContext *C, Object *ob, const Brush *brush)
{
- SculptSession *ss = ob->sculpt;
+ SculptSession *ss = ob->sculpt;
- if (ss->kb || ss->modifiers_active) {
- Depsgraph *depsgraph = CTX_data_depsgraph(C);
- Scene *scene = CTX_data_scene(C);
- Sculpt *sd = scene->toolsettings->sculpt;
- bool need_pmap = sculpt_any_smooth_mode(brush, ss->cache, 0);
- BKE_sculpt_update_mesh_elements(depsgraph, scene, sd, ob, need_pmap, false);
- }
+ if (ss->kb || ss->modifiers_active) {
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ Scene *scene = CTX_data_scene(C);
+ Sculpt *sd = scene->toolsettings->sculpt;
+ bool need_pmap = sculpt_any_smooth_mode(brush, ss->cache, 0);
+ BKE_sculpt_update_mesh_elements(depsgraph, scene, sd, ob, need_pmap, false);
+ }
}
static void sculpt_raycast_cb(PBVHNode *node, void *data_v, float *tmin)
{
- if (BKE_pbvh_node_get_tmin(node) < *tmin) {
- SculptRaycastData *srd = data_v;
- float (*origco)[3] = NULL;
- bool use_origco = false;
-
- if (srd->original && srd->ss->cache) {
- if (BKE_pbvh_type(srd->ss->pbvh) == PBVH_BMESH) {
- use_origco = true;
- }
- else {
- /* intersect with coordinates from before we started stroke */
- SculptUndoNode *unode = sculpt_undo_get_node(node);
- origco = (unode) ? unode->co : NULL;
- use_origco = origco ? true : false;
- }
- }
-
- if (BKE_pbvh_node_raycast(srd->ss->pbvh, node, origco, use_origco,
- srd->ray_start, srd->ray_normal, &srd->depth))
- {
- srd->hit = 1;
- *tmin = srd->depth;
- }
- }
+ if (BKE_pbvh_node_get_tmin(node) < *tmin) {
+ SculptRaycastData *srd = data_v;
+ float(*origco)[3] = NULL;
+ bool use_origco = false;
+
+ if (srd->original && srd->ss->cache) {
+ if (BKE_pbvh_type(srd->ss->pbvh) == PBVH_BMESH) {
+ use_origco = true;
+ }
+ else {
+ /* intersect with coordinates from before we started stroke */
+ SculptUndoNode *unode = sculpt_undo_get_node(node);
+ origco = (unode) ? unode->co : NULL;
+ use_origco = origco ? true : false;
+ }
+ }
+
+ if (BKE_pbvh_node_raycast(srd->ss->pbvh,
+ node,
+ origco,
+ use_origco,
+ srd->ray_start,
+ srd->ray_normal,
+ &srd->depth)) {
+ srd->hit = 1;
+ *tmin = srd->depth;
+ }
+ }
}
static void sculpt_find_nearest_to_ray_cb(PBVHNode *node, void *data_v, float *tmin)
{
- if (BKE_pbvh_node_get_tmin(node) < *tmin) {
- SculptFindNearestToRayData *srd = data_v;
- float (*origco)[3] = NULL;
- bool use_origco = false;
-
- if (srd->original && srd->ss->cache) {
- if (BKE_pbvh_type(srd->ss->pbvh) == PBVH_BMESH) {
- use_origco = true;
- }
- else {
- /* intersect with coordinates from before we started stroke */
- SculptUndoNode *unode = sculpt_undo_get_node(node);
- origco = (unode) ? unode->co : NULL;
- use_origco = origco ? true : false;
- }
- }
-
- if (BKE_pbvh_node_find_nearest_to_ray(
- srd->ss->pbvh, node, origco, use_origco,
- srd->ray_start, srd->ray_normal,
- &srd->depth, &srd->dist_sq_to_ray))
- {
- srd->hit = 1;
- *tmin = srd->dist_sq_to_ray;
- }
- }
+ if (BKE_pbvh_node_get_tmin(node) < *tmin) {
+ SculptFindNearestToRayData *srd = data_v;
+ float(*origco)[3] = NULL;
+ bool use_origco = false;
+
+ if (srd->original && srd->ss->cache) {
+ if (BKE_pbvh_type(srd->ss->pbvh) == PBVH_BMESH) {
+ use_origco = true;
+ }
+ else {
+ /* intersect with coordinates from before we started stroke */
+ SculptUndoNode *unode = sculpt_undo_get_node(node);
+ origco = (unode) ? unode->co : NULL;
+ use_origco = origco ? true : false;
+ }
+ }
+
+ if (BKE_pbvh_node_find_nearest_to_ray(srd->ss->pbvh,
+ node,
+ origco,
+ use_origco,
+ srd->ray_start,
+ srd->ray_normal,
+ &srd->depth,
+ &srd->dist_sq_to_ray)) {
+ srd->hit = 1;
+ *tmin = srd->dist_sq_to_ray;
+ }
+ }
}
static void sculpt_raycast_detail_cb(PBVHNode *node, void *data_v, float *tmin)
{
- if (BKE_pbvh_node_get_tmin(node) < *tmin) {
- SculptDetailRaycastData *srd = data_v;
- if (BKE_pbvh_bmesh_node_raycast_detail(node, srd->ray_start, srd->ray_normal,
- &srd->depth, &srd->edge_length))
- {
- srd->hit = 1;
- *tmin = srd->depth;
- }
- }
+ if (BKE_pbvh_node_get_tmin(node) < *tmin) {
+ SculptDetailRaycastData *srd = data_v;
+ if (BKE_pbvh_bmesh_node_raycast_detail(
+ node, srd->ray_start, srd->ray_normal, &srd->depth, &srd->edge_length)) {
+ srd->hit = 1;
+ *tmin = srd->depth;
+ }
+ }
}
-static float sculpt_raycast_init(
- ViewContext *vc, const float mouse[2],
- float ray_start[3], float ray_end[3], float ray_normal[3], bool original)
+static float sculpt_raycast_init(ViewContext *vc,
+ const float mouse[2],
+ float ray_start[3],
+ float ray_end[3],
+ float ray_normal[3],
+ bool original)
{
- float obimat[4][4];
- float dist;
- Object *ob = vc->obact;
- RegionView3D *rv3d = vc->ar->regiondata;
+ float obimat[4][4];
+ float dist;
+ Object *ob = vc->obact;
+ RegionView3D *rv3d = vc->ar->regiondata;
- /* TODO: what if the segment is totally clipped? (return == 0) */
- ED_view3d_win_to_segment_clipped(vc->depsgraph, vc->ar, vc->v3d, mouse, ray_start, ray_end, true);
+ /* TODO: what if the segment is totally clipped? (return == 0) */
+ ED_view3d_win_to_segment_clipped(
+ vc->depsgraph, vc->ar, vc->v3d, mouse, ray_start, ray_end, true);
- invert_m4_m4(obimat, ob->obmat);
- mul_m4_v3(obimat, ray_start);
- mul_m4_v3(obimat, ray_end);
+ invert_m4_m4(obimat, ob->obmat);
+ mul_m4_v3(obimat, ray_start);
+ mul_m4_v3(obimat, ray_end);
- sub_v3_v3v3(ray_normal, ray_end, ray_start);
- dist = normalize_v3(ray_normal);
+ sub_v3_v3v3(ray_normal, ray_end, ray_start);
+ dist = normalize_v3(ray_normal);
- if ((rv3d->is_persp == false) &&
- /* if the ray is clipped, don't adjust its start/end */
- ((rv3d->rflag & RV3D_CLIPPING) == 0))
- {
- BKE_pbvh_raycast_project_ray_root(ob->sculpt->pbvh, original, ray_start, ray_end, ray_normal);
+ if ((rv3d->is_persp == false) &&
+ /* if the ray is clipped, don't adjust its start/end */
+ ((rv3d->rflag & RV3D_CLIPPING) == 0)) {
+ BKE_pbvh_raycast_project_ray_root(ob->sculpt->pbvh, original, ray_start, ray_end, ray_normal);
- /* recalculate the normal */
- sub_v3_v3v3(ray_normal, ray_end, ray_start);
- dist = normalize_v3(ray_normal);
- }
+ /* recalculate the normal */
+ sub_v3_v3v3(ray_normal, ray_end, ray_start);
+ dist = normalize_v3(ray_normal);
+ }
- return dist;
+ return dist;
}
/* Do a raycast in the tree to find the 3d brush location
@@ -4916,859 +4942,887 @@ static float sculpt_raycast_init(
*/
bool sculpt_stroke_get_location(bContext *C, float out[3], const float mouse[2])
{
- Object *ob;
- SculptSession *ss;
- StrokeCache *cache;
- float ray_start[3], ray_end[3], ray_normal[3], depth;
- bool original;
- ViewContext vc;
-
- ED_view3d_viewcontext_init(C, &vc);
-
- ob = vc.obact;
-
- ss = ob->sculpt;
- cache = ss->cache;
- original = (cache) ? cache->original : 0;
-
- const Brush *brush = BKE_paint_brush(BKE_paint_get_active_from_context(C));
-
- sculpt_stroke_modifiers_check(C, ob, brush);
-
- depth = sculpt_raycast_init(&vc, mouse, ray_start, ray_end, ray_normal, original);
-
- bool hit = false;
- {
- SculptRaycastData srd = {
- .original = original,
- .ss = ob->sculpt,
- .hit = 0,
- .ray_start = ray_start,
- .ray_normal = ray_normal,
- .depth = depth,
- };
- BKE_pbvh_raycast(
- ss->pbvh, sculpt_raycast_cb, &srd,
- ray_start, ray_normal, srd.original);
- if (srd.hit) {
- hit = true;
- copy_v3_v3(out, ray_normal);
- mul_v3_fl(out, srd.depth);
- add_v3_v3(out, ray_start);
- }
- }
-
- if (hit == false) {
- if (ELEM(brush->falloff_shape, PAINT_FALLOFF_SHAPE_TUBE)) {
- SculptFindNearestToRayData srd = {
- .original = original,
- .ss = ob->sculpt,
- .hit = 0,
- .ray_start = ray_start,
- .ray_normal = ray_normal,
- .depth = FLT_MAX,
- .dist_sq_to_ray = FLT_MAX,
- };
- BKE_pbvh_find_nearest_to_ray(
- ss->pbvh, sculpt_find_nearest_to_ray_cb, &srd,
- ray_start, ray_normal, srd.original);
- if (srd.hit) {
- hit = true;
- copy_v3_v3(out, ray_normal);
- mul_v3_fl(out, srd.depth);
- add_v3_v3(out, ray_start);
- }
- }
- }
-
- if (cache && hit) {
- copy_v3_v3(cache->true_location, out);
- }
-
- return hit;
+ Object *ob;
+ SculptSession *ss;
+ StrokeCache *cache;
+ float ray_start[3], ray_end[3], ray_normal[3], depth;
+ bool original;
+ ViewContext vc;
+
+ ED_view3d_viewcontext_init(C, &vc);
+
+ ob = vc.obact;
+
+ ss = ob->sculpt;
+ cache = ss->cache;
+ original = (cache) ? cache->original : 0;
+
+ const Brush *brush = BKE_paint_brush(BKE_paint_get_active_from_context(C));
+
+ sculpt_stroke_modifiers_check(C, ob, brush);
+
+ depth = sculpt_raycast_init(&vc, mouse, ray_start, ray_end, ray_normal, original);
+
+ bool hit = false;
+ {
+ SculptRaycastData srd = {
+ .original = original,
+ .ss = ob->sculpt,
+ .hit = 0,
+ .ray_start = ray_start,
+ .ray_normal = ray_normal,
+ .depth = depth,
+ };
+ BKE_pbvh_raycast(ss->pbvh, sculpt_raycast_cb, &srd, ray_start, ray_normal, srd.original);
+ if (srd.hit) {
+ hit = true;
+ copy_v3_v3(out, ray_normal);
+ mul_v3_fl(out, srd.depth);
+ add_v3_v3(out, ray_start);
+ }
+ }
+
+ if (hit == false) {
+ if (ELEM(brush->falloff_shape, PAINT_FALLOFF_SHAPE_TUBE)) {
+ SculptFindNearestToRayData srd = {
+ .original = original,
+ .ss = ob->sculpt,
+ .hit = 0,
+ .ray_start = ray_start,
+ .ray_normal = ray_normal,
+ .depth = FLT_MAX,
+ .dist_sq_to_ray = FLT_MAX,
+ };
+ BKE_pbvh_find_nearest_to_ray(
+ ss->pbvh, sculpt_find_nearest_to_ray_cb, &srd, ray_start, ray_normal, srd.original);
+ if (srd.hit) {
+ hit = true;
+ copy_v3_v3(out, ray_normal);
+ mul_v3_fl(out, srd.depth);
+ add_v3_v3(out, ray_start);
+ }
+ }
+ }
+
+ if (cache && hit) {
+ copy_v3_v3(cache->true_location, out);
+ }
+
+ return hit;
}
static void sculpt_brush_init_tex(const Scene *scene, Sculpt *sd, SculptSession *ss)
{
- Brush *brush = BKE_paint_brush(&sd->paint);
- MTex *mtex = &brush->mtex;
+ Brush *brush = BKE_paint_brush(&sd->paint);
+ MTex *mtex = &brush->mtex;
- /* init mtex nodes */
- if (mtex->tex && mtex->tex->nodetree) {
- /* has internal flag to detect it only does it once */
- ntreeTexBeginExecTree(mtex->tex->nodetree);
- }
+ /* init mtex nodes */
+ if (mtex->tex && mtex->tex->nodetree) {
+ /* has internal flag to detect it only does it once */
+ ntreeTexBeginExecTree(mtex->tex->nodetree);
+ }
- /* TODO: Shouldn't really have to do this at the start of every
- * stroke, but sculpt would need some sort of notification when
- * changes are made to the texture. */
- sculpt_update_tex(scene, sd, ss);
+ /* TODO: Shouldn't really have to do this at the start of every
+ * stroke, but sculpt would need some sort of notification when
+ * changes are made to the texture. */
+ sculpt_update_tex(scene, sd, ss);
}
static void sculpt_brush_stroke_init(bContext *C, wmOperator *op)
{
- Depsgraph *depsgraph = CTX_data_depsgraph(C);
- Scene *scene = CTX_data_scene(C);
- Object *ob = CTX_data_active_object(C);
- Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
- SculptSession *ss = CTX_data_active_object(C)->sculpt;
- Brush *brush = BKE_paint_brush(&sd->paint);
- int mode = RNA_enum_get(op->ptr, "mode");
- bool is_smooth;
- bool need_mask = false;
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ Scene *scene = CTX_data_scene(C);
+ Object *ob = CTX_data_active_object(C);
+ Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
+ SculptSession *ss = CTX_data_active_object(C)->sculpt;
+ Brush *brush = BKE_paint_brush(&sd->paint);
+ int mode = RNA_enum_get(op->ptr, "mode");
+ bool is_smooth;
+ bool need_mask = false;
- if (brush->sculpt_tool == SCULPT_TOOL_MASK) {
- need_mask = true;
- }
+ if (brush->sculpt_tool == SCULPT_TOOL_MASK) {
+ need_mask = true;
+ }
- view3d_operator_needs_opengl(C);
- sculpt_brush_init_tex(scene, sd, ss);
+ view3d_operator_needs_opengl(C);
+ sculpt_brush_init_tex(scene, sd, ss);
- is_smooth = sculpt_any_smooth_mode(brush, NULL, mode);
- BKE_sculpt_update_mesh_elements(depsgraph, scene, sd, ob, is_smooth, need_mask);
+ is_smooth = sculpt_any_smooth_mode(brush, NULL, mode);
+ BKE_sculpt_update_mesh_elements(depsgraph, scene, sd, ob, is_smooth, need_mask);
}
static void sculpt_restore_mesh(Sculpt *sd, Object *ob)
{
- SculptSession *ss = ob->sculpt;
- Brush *brush = BKE_paint_brush(&sd->paint);
+ SculptSession *ss = ob->sculpt;
+ Brush *brush = BKE_paint_brush(&sd->paint);
- /* Restore the mesh before continuing with anchored stroke */
- if ((brush->flag & BRUSH_ANCHORED) ||
- (brush->sculpt_tool == SCULPT_TOOL_GRAB &&
- BKE_brush_use_size_pressure(ss->cache->vc->scene, brush)) ||
- (brush->flag & BRUSH_DRAG_DOT))
- {
- paint_mesh_restore_co(sd, ob);
- }
+ /* Restore the mesh before continuing with anchored stroke */
+ if ((brush->flag & BRUSH_ANCHORED) ||
+ (brush->sculpt_tool == SCULPT_TOOL_GRAB &&
+ BKE_brush_use_size_pressure(ss->cache->vc->scene, brush)) ||
+ (brush->flag & BRUSH_DRAG_DOT)) {
+ paint_mesh_restore_co(sd, ob);
+ }
}
/* Copy the PBVH bounding box into the object's bounding box */
void sculpt_update_object_bounding_box(Object *ob)
{
- if (ob->runtime.bb) {
- float bb_min[3], bb_max[3];
+ if (ob->runtime.bb) {
+ float bb_min[3], bb_max[3];
- BKE_pbvh_bounding_box(ob->sculpt->pbvh, bb_min, bb_max);
- BKE_boundbox_init_from_minmax(ob->runtime.bb, bb_min, bb_max);
- }
+ BKE_pbvh_bounding_box(ob->sculpt->pbvh, bb_min, bb_max);
+ BKE_boundbox_init_from_minmax(ob->runtime.bb, bb_min, bb_max);
+ }
}
static void sculpt_flush_update(bContext *C)
{
- Depsgraph *depsgraph = CTX_data_depsgraph(C);
- Object *ob = CTX_data_active_object(C);
- Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
- SculptSession *ss = ob->sculpt;
- ARegion *ar = CTX_wm_region(C);
- bScreen *screen = CTX_wm_screen(C);
- MultiresModifierData *mmd = ss->multires;
-
- if (mmd != NULL) {
- /* NOTE: SubdivCCG is living in the evaluated object. */
- multires_mark_as_modified(ob_eval, MULTIRES_COORDS_MODIFIED);
- }
-
- DEG_id_tag_update(&ob->id, ID_RECALC_SHADING);
-
- bool use_shaded_mode = false;
- if (mmd || (BKE_pbvh_type(ss->pbvh) == PBVH_BMESH)) {
- /* Multres or dyntopo are drawn directly by EEVEE,
- * no need for hacks in this case. */
- }
- else {
- /* We search if an area of the current window is in lookdev/rendered
- * display mode. In this case, for changes to show up, we need to
- * tag for ID_RECALC_GEOMETRY. */
- for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
- for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
- if (sl->spacetype == SPACE_VIEW3D) {
- View3D *v3d = (View3D *)sl;
- if (v3d->shading.type > OB_SOLID) {
- use_shaded_mode = true;
- }
- }
- }
- }
- }
-
- if (ss->kb || ss->modifiers_active || use_shaded_mode) {
- DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
- ED_region_tag_redraw(ar);
- }
- else {
- rcti r;
-
- BKE_pbvh_update(ss->pbvh, PBVH_UpdateBB, NULL);
- /* Update the object's bounding box too so that the object
- * doesn't get incorrectly clipped during drawing in
- * draw_mesh_object(). [#33790] */
- sculpt_update_object_bounding_box(ob);
-
- if (sculpt_get_redraw_rect(ar, CTX_wm_region_view3d(C), ob, &r)) {
- if (ss->cache) {
- ss->cache->current_r = r;
- }
-
- /* previous is not set in the current cache else
- * the partial rect will always grow */
- sculpt_extend_redraw_rect_previous(ob, &r);
-
- r.xmin += ar->winrct.xmin - 2;
- r.xmax += ar->winrct.xmin + 2;
- r.ymin += ar->winrct.ymin - 2;
- r.ymax += ar->winrct.ymin + 2;
-
- ss->partial_redraw = 1;
- ED_region_tag_redraw_partial(ar, &r);
- }
- }
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ Object *ob = CTX_data_active_object(C);
+ Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
+ SculptSession *ss = ob->sculpt;
+ ARegion *ar = CTX_wm_region(C);
+ bScreen *screen = CTX_wm_screen(C);
+ MultiresModifierData *mmd = ss->multires;
+
+ if (mmd != NULL) {
+ /* NOTE: SubdivCCG is living in the evaluated object. */
+ multires_mark_as_modified(ob_eval, MULTIRES_COORDS_MODIFIED);
+ }
+
+ DEG_id_tag_update(&ob->id, ID_RECALC_SHADING);
+
+ bool use_shaded_mode = false;
+ if (mmd || (BKE_pbvh_type(ss->pbvh) == PBVH_BMESH)) {
+ /* Multres or dyntopo are drawn directly by EEVEE,
+ * no need for hacks in this case. */
+ }
+ else {
+ /* We search if an area of the current window is in lookdev/rendered
+ * display mode. In this case, for changes to show up, we need to
+ * tag for ID_RECALC_GEOMETRY. */
+ for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
+ for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
+ if (sl->spacetype == SPACE_VIEW3D) {
+ View3D *v3d = (View3D *)sl;
+ if (v3d->shading.type > OB_SOLID) {
+ use_shaded_mode = true;
+ }
+ }
+ }
+ }
+ }
+
+ if (ss->kb || ss->modifiers_active || use_shaded_mode) {
+ DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
+ ED_region_tag_redraw(ar);
+ }
+ else {
+ rcti r;
+
+ BKE_pbvh_update(ss->pbvh, PBVH_UpdateBB, NULL);
+ /* Update the object's bounding box too so that the object
+ * doesn't get incorrectly clipped during drawing in
+ * draw_mesh_object(). [#33790] */
+ sculpt_update_object_bounding_box(ob);
+
+ if (sculpt_get_redraw_rect(ar, CTX_wm_region_view3d(C), ob, &r)) {
+ if (ss->cache) {
+ ss->cache->current_r = r;
+ }
+
+ /* previous is not set in the current cache else
+ * the partial rect will always grow */
+ sculpt_extend_redraw_rect_previous(ob, &r);
+
+ r.xmin += ar->winrct.xmin - 2;
+ r.xmax += ar->winrct.xmin + 2;
+ r.ymin += ar->winrct.ymin - 2;
+ r.ymax += ar->winrct.ymin + 2;
+
+ ss->partial_redraw = 1;
+ ED_region_tag_redraw_partial(ar, &r);
+ }
+ }
}
/* Returns whether the mouse/stylus is over the mesh (1)
* or over the background (0) */
static bool over_mesh(bContext *C, struct wmOperator *UNUSED(op), float x, float y)
{
- float mouse[2], co[3];
+ float mouse[2], co[3];
- mouse[0] = x;
- mouse[1] = y;
+ mouse[0] = x;
+ mouse[1] = y;
- return sculpt_stroke_get_location(C, co, mouse);
+ return sculpt_stroke_get_location(C, co, mouse);
}
-static bool sculpt_stroke_test_start(bContext *C, struct wmOperator *op,
- const float mouse[2])
+static bool sculpt_stroke_test_start(bContext *C, struct wmOperator *op, const float mouse[2])
{
- /* Don't start the stroke until mouse goes over the mesh.
- * note: mouse will only be null when re-executing the saved stroke.
- * We have exception for 'exec' strokes since they may not set 'mouse',
- * only 'location', see: T52195. */
- if (((op->flag & OP_IS_INVOKE) == 0) ||
- (mouse == NULL) || over_mesh(C, op, mouse[0], mouse[1]))
- {
- Object *ob = CTX_data_active_object(C);
- SculptSession *ss = ob->sculpt;
- Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
+ /* Don't start the stroke until mouse goes over the mesh.
+ * note: mouse will only be null when re-executing the saved stroke.
+ * We have exception for 'exec' strokes since they may not set 'mouse',
+ * only 'location', see: T52195. */
+ if (((op->flag & OP_IS_INVOKE) == 0) || (mouse == NULL) ||
+ over_mesh(C, op, mouse[0], mouse[1])) {
+ Object *ob = CTX_data_active_object(C);
+ SculptSession *ss = ob->sculpt;
+ Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
- ED_view3d_init_mats_rv3d(ob, CTX_wm_region_view3d(C));
+ ED_view3d_init_mats_rv3d(ob, CTX_wm_region_view3d(C));
- sculpt_update_cache_invariants(C, sd, ss, op, mouse);
+ sculpt_update_cache_invariants(C, sd, ss, op, mouse);
- sculpt_undo_push_begin(sculpt_tool_name(sd));
+ sculpt_undo_push_begin(sculpt_tool_name(sd));
- return 1;
- }
- else
- return 0;
+ return 1;
+ }
+ else
+ return 0;
}
-static void sculpt_stroke_update_step(bContext *C, struct PaintStroke *UNUSED(stroke), PointerRNA *itemptr)
+static void sculpt_stroke_update_step(bContext *C,
+ struct PaintStroke *UNUSED(stroke),
+ PointerRNA *itemptr)
{
- UnifiedPaintSettings *ups = &CTX_data_tool_settings(C)->unified_paint_settings;
- Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
- Object *ob = CTX_data_active_object(C);
- SculptSession *ss = ob->sculpt;
- const Brush *brush = BKE_paint_brush(&sd->paint);
+ UnifiedPaintSettings *ups = &CTX_data_tool_settings(C)->unified_paint_settings;
+ Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
+ Object *ob = CTX_data_active_object(C);
+ SculptSession *ss = ob->sculpt;
+ const Brush *brush = BKE_paint_brush(&sd->paint);
- sculpt_stroke_modifiers_check(C, ob, brush);
- sculpt_update_cache_variants(C, sd, ob, itemptr);
- sculpt_restore_mesh(sd, ob);
+ sculpt_stroke_modifiers_check(C, ob, brush);
+ sculpt_update_cache_variants(C, sd, ob, itemptr);
+ sculpt_restore_mesh(sd, ob);
- if (sd->flags & (SCULPT_DYNTOPO_DETAIL_CONSTANT | SCULPT_DYNTOPO_DETAIL_MANUAL)) {
- float object_space_constant_detail = 1.0f / (sd->constant_detail * mat4_to_scale(ob->obmat));
- BKE_pbvh_bmesh_detail_size_set(ss->pbvh, object_space_constant_detail);
- }
- else if (sd->flags & SCULPT_DYNTOPO_DETAIL_BRUSH) {
- BKE_pbvh_bmesh_detail_size_set(ss->pbvh, ss->cache->radius * sd->detail_percent / 100.0f);
- }
- else {
- BKE_pbvh_bmesh_detail_size_set(
- ss->pbvh,
- (ss->cache->radius /
- (float)ups->pixel_radius) *
- (float)(sd->detail_size * U.pixelsize) / 0.4f);
- }
+ if (sd->flags & (SCULPT_DYNTOPO_DETAIL_CONSTANT | SCULPT_DYNTOPO_DETAIL_MANUAL)) {
+ float object_space_constant_detail = 1.0f / (sd->constant_detail * mat4_to_scale(ob->obmat));
+ BKE_pbvh_bmesh_detail_size_set(ss->pbvh, object_space_constant_detail);
+ }
+ else if (sd->flags & SCULPT_DYNTOPO_DETAIL_BRUSH) {
+ BKE_pbvh_bmesh_detail_size_set(ss->pbvh, ss->cache->radius * sd->detail_percent / 100.0f);
+ }
+ else {
+ BKE_pbvh_bmesh_detail_size_set(ss->pbvh,
+ (ss->cache->radius / (float)ups->pixel_radius) *
+ (float)(sd->detail_size * U.pixelsize) / 0.4f);
+ }
- if (sculpt_stroke_is_dynamic_topology(ss, brush)) {
- do_symmetrical_brush_actions(sd, ob, sculpt_topology_update, ups);
- }
+ if (sculpt_stroke_is_dynamic_topology(ss, brush)) {
+ do_symmetrical_brush_actions(sd, ob, sculpt_topology_update, ups);
+ }
- do_symmetrical_brush_actions(sd, ob, do_brush_action, ups);
+ do_symmetrical_brush_actions(sd, ob, do_brush_action, ups);
- sculpt_combine_proxies(sd, ob);
+ sculpt_combine_proxies(sd, ob);
- /* hack to fix noise texture tearing mesh */
- sculpt_fix_noise_tear(sd, ob);
+ /* hack to fix noise texture tearing mesh */
+ sculpt_fix_noise_tear(sd, ob);
- /* TODO(sergey): This is not really needed for the solid shading,
- * which does use pBVH drawing anyway, but texture and wireframe
- * requires this.
- *
- * Could be optimized later, but currently don't think it's so
- * much common scenario.
- *
- * Same applies to the DEG_id_tag_update() invoked from
- * sculpt_flush_update().
- */
- if (ss->modifiers_active) {
- sculpt_flush_stroke_deform(sd, ob);
- }
- else if (ss->kb) {
- sculpt_update_keyblock(ob);
- }
+ /* TODO(sergey): This is not really needed for the solid shading,
+ * which does use pBVH drawing anyway, but texture and wireframe
+ * requires this.
+ *
+ * Could be optimized later, but currently don't think it's so
+ * much common scenario.
+ *
+ * Same applies to the DEG_id_tag_update() invoked from
+ * sculpt_flush_update().
+ */
+ if (ss->modifiers_active) {
+ sculpt_flush_stroke_deform(sd, ob);
+ }
+ else if (ss->kb) {
+ sculpt_update_keyblock(ob);
+ }
- ss->cache->first_time = false;
+ ss->cache->first_time = false;
- /* Cleanup */
- sculpt_flush_update(C);
+ /* Cleanup */
+ sculpt_flush_update(C);
}
static void sculpt_brush_exit_tex(Sculpt *sd)
{
- Brush *brush = BKE_paint_brush(&sd->paint);
- MTex *mtex = &brush->mtex;
+ Brush *brush = BKE_paint_brush(&sd->paint);
+ MTex *mtex = &brush->mtex;
- if (mtex->tex && mtex->tex->nodetree)
- ntreeTexEndExecTree(mtex->tex->nodetree->execdata);
+ if (mtex->tex && mtex->tex->nodetree)
+ ntreeTexEndExecTree(mtex->tex->nodetree->execdata);
}
static void sculpt_stroke_done(const bContext *C, struct PaintStroke *UNUSED(stroke))
{
- Main *bmain = CTX_data_main(C);
- Object *ob = CTX_data_active_object(C);
- Scene *scene = CTX_data_scene(C);
- SculptSession *ss = ob->sculpt;
- Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
+ Main *bmain = CTX_data_main(C);
+ Object *ob = CTX_data_active_object(C);
+ Scene *scene = CTX_data_scene(C);
+ SculptSession *ss = ob->sculpt;
+ Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
- /* Finished */
- if (ss->cache) {
- UnifiedPaintSettings *ups = &CTX_data_tool_settings(C)->unified_paint_settings;
- Brush *brush = BKE_paint_brush(&sd->paint);
- BLI_assert(brush == ss->cache->brush); /* const, so we shouldn't change. */
- ups->draw_inverted = false;
+ /* Finished */
+ if (ss->cache) {
+ UnifiedPaintSettings *ups = &CTX_data_tool_settings(C)->unified_paint_settings;
+ Brush *brush = BKE_paint_brush(&sd->paint);
+ BLI_assert(brush == ss->cache->brush); /* const, so we shouldn't change. */
+ ups->draw_inverted = false;
- sculpt_stroke_modifiers_check(C, ob, brush);
+ sculpt_stroke_modifiers_check(C, ob, brush);
- /* Alt-Smooth */
- if (ss->cache->alt_smooth) {
- if (brush->sculpt_tool == SCULPT_TOOL_MASK) {
- brush->mask_tool = ss->cache->saved_mask_brush_tool;
- }
- else {
- BKE_brush_size_set(scene, brush, ss->cache->saved_smooth_size);
- brush = (Brush *)BKE_libblock_find_name(bmain, ID_BR, ss->cache->saved_active_brush_name);
- if (brush) {
- BKE_paint_brush_set(&sd->paint, brush);
- }
- }
- }
+ /* Alt-Smooth */
+ if (ss->cache->alt_smooth) {
+ if (brush->sculpt_tool == SCULPT_TOOL_MASK) {
+ brush->mask_tool = ss->cache->saved_mask_brush_tool;
+ }
+ else {
+ BKE_brush_size_set(scene, brush, ss->cache->saved_smooth_size);
+ brush = (Brush *)BKE_libblock_find_name(bmain, ID_BR, ss->cache->saved_active_brush_name);
+ if (brush) {
+ BKE_paint_brush_set(&sd->paint, brush);
+ }
+ }
+ }
- sculpt_cache_free(ss->cache);
- ss->cache = NULL;
+ sculpt_cache_free(ss->cache);
+ ss->cache = NULL;
- sculpt_undo_push_end();
+ sculpt_undo_push_end();
- BKE_pbvh_update(ss->pbvh, PBVH_UpdateOriginalBB, NULL);
+ BKE_pbvh_update(ss->pbvh, PBVH_UpdateOriginalBB, NULL);
- if (BKE_pbvh_type(ss->pbvh) == PBVH_BMESH)
- BKE_pbvh_bmesh_after_stroke(ss->pbvh);
+ if (BKE_pbvh_type(ss->pbvh) == PBVH_BMESH)
+ BKE_pbvh_bmesh_after_stroke(ss->pbvh);
- /* optimization: if there is locked key and active modifiers present in */
- /* the stack, keyblock is updating at each step. otherwise we could update */
- /* keyblock only when stroke is finished */
- if (ss->kb && !ss->modifiers_active) sculpt_update_keyblock(ob);
+ /* optimization: if there is locked key and active modifiers present in */
+ /* the stack, keyblock is updating at each step. otherwise we could update */
+ /* keyblock only when stroke is finished */
+ if (ss->kb && !ss->modifiers_active)
+ sculpt_update_keyblock(ob);
- ss->partial_redraw = 0;
+ ss->partial_redraw = 0;
- /* try to avoid calling this, only for e.g. linked duplicates now */
- if (((Mesh *)ob->data)->id.us > 1)
- DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
+ /* try to avoid calling this, only for e.g. linked duplicates now */
+ if (((Mesh *)ob->data)->id.us > 1)
+ DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
- WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
- }
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
+ }
- sculpt_brush_exit_tex(sd);
+ sculpt_brush_exit_tex(sd);
}
static int sculpt_brush_stroke_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
- struct PaintStroke *stroke;
- int ignore_background_click;
- int retval;
+ struct PaintStroke *stroke;
+ int ignore_background_click;
+ int retval;
- sculpt_brush_stroke_init(C, op);
+ sculpt_brush_stroke_init(C, op);
- stroke = paint_stroke_new(C, op, sculpt_stroke_get_location,
- sculpt_stroke_test_start,
- sculpt_stroke_update_step, NULL,
- sculpt_stroke_done, event->type);
+ stroke = paint_stroke_new(C,
+ op,
+ sculpt_stroke_get_location,
+ sculpt_stroke_test_start,
+ sculpt_stroke_update_step,
+ NULL,
+ sculpt_stroke_done,
+ event->type);
- op->customdata = stroke;
+ op->customdata = stroke;
- /* For tablet rotation */
- ignore_background_click = RNA_boolean_get(op->ptr, "ignore_background_click");
+ /* For tablet rotation */
+ ignore_background_click = RNA_boolean_get(op->ptr, "ignore_background_click");
- if (ignore_background_click && !over_mesh(C, op, event->x, event->y)) {
- paint_stroke_data_free(op);
- return OPERATOR_PASS_THROUGH;
- }
+ if (ignore_background_click && !over_mesh(C, op, event->x, event->y)) {
+ paint_stroke_data_free(op);
+ return OPERATOR_PASS_THROUGH;
+ }
- if ((retval = op->type->modal(C, op, event)) == OPERATOR_FINISHED) {
- paint_stroke_data_free(op);
- return OPERATOR_FINISHED;
- }
- /* add modal handler */
- WM_event_add_modal_handler(C, op);
+ if ((retval = op->type->modal(C, op, event)) == OPERATOR_FINISHED) {
+ paint_stroke_data_free(op);
+ return OPERATOR_FINISHED;
+ }
+ /* add modal handler */
+ WM_event_add_modal_handler(C, op);
- OPERATOR_RETVAL_CHECK(retval);
- BLI_assert(retval == OPERATOR_RUNNING_MODAL);
+ OPERATOR_RETVAL_CHECK(retval);
+ BLI_assert(retval == OPERATOR_RUNNING_MODAL);
- return OPERATOR_RUNNING_MODAL;
+ return OPERATOR_RUNNING_MODAL;
}
static int sculpt_brush_stroke_exec(bContext *C, wmOperator *op)
{
- sculpt_brush_stroke_init(C, op);
+ sculpt_brush_stroke_init(C, op);
- op->customdata = paint_stroke_new(C, op, sculpt_stroke_get_location, sculpt_stroke_test_start,
- sculpt_stroke_update_step, NULL, sculpt_stroke_done, 0);
+ op->customdata = paint_stroke_new(C,
+ op,
+ sculpt_stroke_get_location,
+ sculpt_stroke_test_start,
+ sculpt_stroke_update_step,
+ NULL,
+ sculpt_stroke_done,
+ 0);
- /* frees op->customdata */
- paint_stroke_exec(C, op);
+ /* frees op->customdata */
+ paint_stroke_exec(C, op);
- return OPERATOR_FINISHED;
+ return OPERATOR_FINISHED;
}
static void sculpt_brush_stroke_cancel(bContext *C, wmOperator *op)
{
- Object *ob = CTX_data_active_object(C);
- SculptSession *ss = ob->sculpt;
- Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
- const Brush *brush = BKE_paint_brush(&sd->paint);
+ Object *ob = CTX_data_active_object(C);
+ SculptSession *ss = ob->sculpt;
+ Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
+ const Brush *brush = BKE_paint_brush(&sd->paint);
- /* XXX Canceling strokes that way does not work with dynamic topology, user will have to do real undo for now.
- * See T46456. */
- if (ss->cache && !sculpt_stroke_is_dynamic_topology(ss, brush)) {
- paint_mesh_restore_co(sd, ob);
- }
+ /* XXX Canceling strokes that way does not work with dynamic topology, user will have to do real undo for now.
+ * See T46456. */
+ if (ss->cache && !sculpt_stroke_is_dynamic_topology(ss, brush)) {
+ paint_mesh_restore_co(sd, ob);
+ }
- paint_stroke_cancel(C, op);
+ paint_stroke_cancel(C, op);
- if (ss->cache) {
- sculpt_cache_free(ss->cache);
- ss->cache = NULL;
- }
+ if (ss->cache) {
+ sculpt_cache_free(ss->cache);
+ ss->cache = NULL;
+ }
- sculpt_brush_exit_tex(sd);
+ sculpt_brush_exit_tex(sd);
}
static void SCULPT_OT_brush_stroke(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Sculpt";
- ot->idname = "SCULPT_OT_brush_stroke";
- ot->description = "Sculpt a stroke into the geometry";
+ /* identifiers */
+ ot->name = "Sculpt";
+ ot->idname = "SCULPT_OT_brush_stroke";
+ ot->description = "Sculpt a stroke into the geometry";
- /* api callbacks */
- ot->invoke = sculpt_brush_stroke_invoke;
- ot->modal = paint_stroke_modal;
- ot->exec = sculpt_brush_stroke_exec;
- ot->poll = sculpt_poll;
- ot->cancel = sculpt_brush_stroke_cancel;
+ /* api callbacks */
+ ot->invoke = sculpt_brush_stroke_invoke;
+ ot->modal = paint_stroke_modal;
+ ot->exec = sculpt_brush_stroke_exec;
+ ot->poll = sculpt_poll;
+ ot->cancel = sculpt_brush_stroke_cancel;
- /* flags (sculpt does own undo? (ton) */
- ot->flag = OPTYPE_BLOCKING;
+ /* flags (sculpt does own undo? (ton) */
+ ot->flag = OPTYPE_BLOCKING;
- /* properties */
+ /* properties */
- paint_stroke_operator_properties(ot);
+ paint_stroke_operator_properties(ot);
- RNA_def_boolean(ot->srna, "ignore_background_click", 0,
- "Ignore Background Click",
- "Clicks on the background do not start the stroke");
+ RNA_def_boolean(ot->srna,
+ "ignore_background_click",
+ 0,
+ "Ignore Background Click",
+ "Clicks on the background do not start the stroke");
}
/* Reset the copy of the mesh that is being sculpted on (currently just for the layer brush) */
static int sculpt_set_persistent_base_exec(bContext *C, wmOperator *UNUSED(op))
{
- SculptSession *ss = CTX_data_active_object(C)->sculpt;
+ SculptSession *ss = CTX_data_active_object(C)->sculpt;
- if (ss) {
- if (ss->layer_co)
- MEM_freeN(ss->layer_co);
- ss->layer_co = NULL;
- }
+ if (ss) {
+ if (ss->layer_co)
+ MEM_freeN(ss->layer_co);
+ ss->layer_co = NULL;
+ }
- return OPERATOR_FINISHED;
+ return OPERATOR_FINISHED;
}
static void SCULPT_OT_set_persistent_base(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Set Persistent Base";
- ot->idname = "SCULPT_OT_set_persistent_base";
- ot->description = "Reset the copy of the mesh that is being sculpted on";
+ /* identifiers */
+ ot->name = "Set Persistent Base";
+ ot->idname = "SCULPT_OT_set_persistent_base";
+ ot->description = "Reset the copy of the mesh that is being sculpted on";
- /* api callbacks */
- ot->exec = sculpt_set_persistent_base_exec;
- ot->poll = sculpt_mode_poll;
+ /* api callbacks */
+ ot->exec = sculpt_set_persistent_base_exec;
+ ot->poll = sculpt_mode_poll;
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
/************************** Dynamic Topology **************************/
static void sculpt_dynamic_topology_triangulate(BMesh *bm)
{
- if (bm->totloop != bm->totface * 3) {
- BM_mesh_triangulate(bm, MOD_TRIANGULATE_QUAD_BEAUTY, MOD_TRIANGULATE_NGON_EARCLIP, 4, false, NULL, NULL, NULL);
- }
+ if (bm->totloop != bm->totface * 3) {
+ BM_mesh_triangulate(
+ bm, MOD_TRIANGULATE_QUAD_BEAUTY, MOD_TRIANGULATE_NGON_EARCLIP, 4, false, NULL, NULL, NULL);
+ }
}
void sculpt_pbvh_clear(Object *ob)
{
- SculptSession *ss = ob->sculpt;
+ SculptSession *ss = ob->sculpt;
- /* Clear out any existing DM and PBVH */
- if (ss->pbvh) {
- BKE_pbvh_free(ss->pbvh);
- }
- ss->pbvh = NULL;
- BKE_object_free_derived_caches(ob);
+ /* Clear out any existing DM and PBVH */
+ if (ss->pbvh) {
+ BKE_pbvh_free(ss->pbvh);
+ }
+ ss->pbvh = NULL;
+ BKE_object_free_derived_caches(ob);
}
void sculpt_dyntopo_node_layers_add(SculptSession *ss)
{
- int cd_node_layer_index;
+ int cd_node_layer_index;
- char layer_id[] = "_dyntopo_node_id";
+ char layer_id[] = "_dyntopo_node_id";
- cd_node_layer_index = CustomData_get_named_layer_index(&ss->bm->vdata, CD_PROP_INT, layer_id);
- if (cd_node_layer_index == -1) {
- BM_data_layer_add_named(ss->bm, &ss->bm->vdata, CD_PROP_INT, layer_id);
- cd_node_layer_index = CustomData_get_named_layer_index(&ss->bm->vdata, CD_PROP_INT, layer_id);
- }
+ cd_node_layer_index = CustomData_get_named_layer_index(&ss->bm->vdata, CD_PROP_INT, layer_id);
+ if (cd_node_layer_index == -1) {
+ BM_data_layer_add_named(ss->bm, &ss->bm->vdata, CD_PROP_INT, layer_id);
+ cd_node_layer_index = CustomData_get_named_layer_index(&ss->bm->vdata, CD_PROP_INT, layer_id);
+ }
- ss->cd_vert_node_offset = CustomData_get_n_offset(
- &ss->bm->vdata, CD_PROP_INT,
- cd_node_layer_index - CustomData_get_layer_index(&ss->bm->vdata, CD_PROP_INT));
+ ss->cd_vert_node_offset = CustomData_get_n_offset(
+ &ss->bm->vdata,
+ CD_PROP_INT,
+ cd_node_layer_index - CustomData_get_layer_index(&ss->bm->vdata, CD_PROP_INT));
- ss->bm->vdata.layers[cd_node_layer_index].flag |= CD_FLAG_TEMPORARY;
+ ss->bm->vdata.layers[cd_node_layer_index].flag |= CD_FLAG_TEMPORARY;
- cd_node_layer_index = CustomData_get_named_layer_index(&ss->bm->pdata, CD_PROP_INT, layer_id);
- if (cd_node_layer_index == -1) {
- BM_data_layer_add_named(ss->bm, &ss->bm->pdata, CD_PROP_INT, layer_id);
- cd_node_layer_index = CustomData_get_named_layer_index(&ss->bm->pdata, CD_PROP_INT, layer_id);
- }
+ cd_node_layer_index = CustomData_get_named_layer_index(&ss->bm->pdata, CD_PROP_INT, layer_id);
+ if (cd_node_layer_index == -1) {
+ BM_data_layer_add_named(ss->bm, &ss->bm->pdata, CD_PROP_INT, layer_id);
+ cd_node_layer_index = CustomData_get_named_layer_index(&ss->bm->pdata, CD_PROP_INT, layer_id);
+ }
- ss->cd_face_node_offset = CustomData_get_n_offset(
- &ss->bm->pdata, CD_PROP_INT,
- cd_node_layer_index - CustomData_get_layer_index(&ss->bm->pdata, CD_PROP_INT));
+ ss->cd_face_node_offset = CustomData_get_n_offset(
+ &ss->bm->pdata,
+ CD_PROP_INT,
+ cd_node_layer_index - CustomData_get_layer_index(&ss->bm->pdata, CD_PROP_INT));
- ss->bm->pdata.layers[cd_node_layer_index].flag |= CD_FLAG_TEMPORARY;
+ ss->bm->pdata.layers[cd_node_layer_index].flag |= CD_FLAG_TEMPORARY;
}
-
-void sculpt_update_after_dynamic_topology_toggle(
- Depsgraph *depsgraph,
- Scene *scene, Object *ob)
+void sculpt_update_after_dynamic_topology_toggle(Depsgraph *depsgraph, Scene *scene, Object *ob)
{
- Sculpt *sd = scene->toolsettings->sculpt;
+ Sculpt *sd = scene->toolsettings->sculpt;
- /* Create the PBVH */
- BKE_sculpt_update_mesh_elements(depsgraph, scene, sd, ob, false, false);
- WM_main_add_notifier(NC_OBJECT | ND_DRAW, ob);
+ /* Create the PBVH */
+ BKE_sculpt_update_mesh_elements(depsgraph, scene, sd, ob, false, false);
+ WM_main_add_notifier(NC_OBJECT | ND_DRAW, ob);
}
-void sculpt_dynamic_topology_enable_ex(
- Depsgraph *depsgraph,
- Scene *scene, Object *ob)
+void sculpt_dynamic_topology_enable_ex(Depsgraph *depsgraph, Scene *scene, Object *ob)
{
- SculptSession *ss = ob->sculpt;
- Mesh *me = ob->data;
- const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_ME(me);
+ SculptSession *ss = ob->sculpt;
+ Mesh *me = ob->data;
+ const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_ME(me);
- sculpt_pbvh_clear(ob);
+ sculpt_pbvh_clear(ob);
- ss->bm_smooth_shading = (scene->toolsettings->sculpt->flags & SCULPT_DYNTOPO_SMOOTH_SHADING) != 0;
+ ss->bm_smooth_shading = (scene->toolsettings->sculpt->flags & SCULPT_DYNTOPO_SMOOTH_SHADING) !=
+ 0;
- /* Dynamic topology doesn't ensure selection state is valid, so remove [#36280] */
- BKE_mesh_mselect_clear(me);
+ /* Dynamic topology doesn't ensure selection state is valid, so remove [#36280] */
+ BKE_mesh_mselect_clear(me);
- /* Create triangles-only BMesh */
- ss->bm = BM_mesh_create(
- &allocsize,
- &((struct BMeshCreateParams){.use_toolflags = false,}));
+ /* Create triangles-only BMesh */
+ ss->bm = BM_mesh_create(&allocsize,
+ &((struct BMeshCreateParams){
+ .use_toolflags = false,
+ }));
- BM_mesh_bm_from_me(
- ss->bm, me, (&(struct BMeshFromMeshParams){
- .calc_face_normal = true, .use_shapekey = true, .active_shapekey = ob->shapenr,
- }));
- sculpt_dynamic_topology_triangulate(ss->bm);
- BM_data_layer_add(ss->bm, &ss->bm->vdata, CD_PAINT_MASK);
- sculpt_dyntopo_node_layers_add(ss);
- /* make sure the data for existing faces are initialized */
- if (me->totpoly != ss->bm->totface) {
- BM_mesh_normals_update(ss->bm);
- }
+ BM_mesh_bm_from_me(ss->bm,
+ me,
+ (&(struct BMeshFromMeshParams){
+ .calc_face_normal = true,
+ .use_shapekey = true,
+ .active_shapekey = ob->shapenr,
+ }));
+ sculpt_dynamic_topology_triangulate(ss->bm);
+ BM_data_layer_add(ss->bm, &ss->bm->vdata, CD_PAINT_MASK);
+ sculpt_dyntopo_node_layers_add(ss);
+ /* make sure the data for existing faces are initialized */
+ if (me->totpoly != ss->bm->totface) {
+ BM_mesh_normals_update(ss->bm);
+ }
- /* Enable dynamic topology */
- me->flag |= ME_SCULPT_DYNAMIC_TOPOLOGY;
+ /* Enable dynamic topology */
+ me->flag |= ME_SCULPT_DYNAMIC_TOPOLOGY;
- /* Enable logging for undo/redo */
- ss->bm_log = BM_log_create(ss->bm);
+ /* Enable logging for undo/redo */
+ ss->bm_log = BM_log_create(ss->bm);
- /* Refresh */
- sculpt_update_after_dynamic_topology_toggle(depsgraph, scene, ob);
+ /* Refresh */
+ sculpt_update_after_dynamic_topology_toggle(depsgraph, scene, ob);
}
/* Free the sculpt BMesh and BMLog
*
* If 'unode' is given, the BMesh's data is copied out to the unode
* before the BMesh is deleted so that it can be restored from */
-void sculpt_dynamic_topology_disable_ex(
- Depsgraph *depsgraph,
- Scene *scene, Object *ob, SculptUndoNode *unode)
-{
- SculptSession *ss = ob->sculpt;
- Mesh *me = ob->data;
-
- sculpt_pbvh_clear(ob);
-
- if (unode) {
- /* Free all existing custom data */
- CustomData_free(&me->vdata, me->totvert);
- CustomData_free(&me->edata, me->totedge);
- CustomData_free(&me->fdata, me->totface);
- CustomData_free(&me->ldata, me->totloop);
- CustomData_free(&me->pdata, me->totpoly);
-
- /* Copy over stored custom data */
- me->totvert = unode->bm_enter_totvert;
- me->totloop = unode->bm_enter_totloop;
- me->totpoly = unode->bm_enter_totpoly;
- me->totedge = unode->bm_enter_totedge;
- me->totface = 0;
- CustomData_copy(&unode->bm_enter_vdata, &me->vdata, CD_MASK_MESH.vmask,
- CD_DUPLICATE, unode->bm_enter_totvert);
- CustomData_copy(&unode->bm_enter_edata, &me->edata, CD_MASK_MESH.emask,
- CD_DUPLICATE, unode->bm_enter_totedge);
- CustomData_copy(&unode->bm_enter_ldata, &me->ldata, CD_MASK_MESH.lmask,
- CD_DUPLICATE, unode->bm_enter_totloop);
- CustomData_copy(&unode->bm_enter_pdata, &me->pdata, CD_MASK_MESH.pmask,
- CD_DUPLICATE, unode->bm_enter_totpoly);
-
- BKE_mesh_update_customdata_pointers(me, false);
- }
- else {
- BKE_sculptsession_bm_to_me(ob, true);
- }
-
- /* Clear data */
- me->flag &= ~ME_SCULPT_DYNAMIC_TOPOLOGY;
-
- /* typically valid but with global-undo they can be NULL, [#36234] */
- if (ss->bm) {
- BM_mesh_free(ss->bm);
- ss->bm = NULL;
- }
- if (ss->bm_log) {
- BM_log_free(ss->bm_log);
- ss->bm_log = NULL;
- }
-
- BKE_particlesystem_reset_all(ob);
- BKE_ptcache_object_reset(scene, ob, PTCACHE_RESET_OUTDATED);
-
- /* Refresh */
- sculpt_update_after_dynamic_topology_toggle(depsgraph, scene, ob);
+void sculpt_dynamic_topology_disable_ex(Depsgraph *depsgraph,
+ Scene *scene,
+ Object *ob,
+ SculptUndoNode *unode)
+{
+ SculptSession *ss = ob->sculpt;
+ Mesh *me = ob->data;
+
+ sculpt_pbvh_clear(ob);
+
+ if (unode) {
+ /* Free all existing custom data */
+ CustomData_free(&me->vdata, me->totvert);
+ CustomData_free(&me->edata, me->totedge);
+ CustomData_free(&me->fdata, me->totface);
+ CustomData_free(&me->ldata, me->totloop);
+ CustomData_free(&me->pdata, me->totpoly);
+
+ /* Copy over stored custom data */
+ me->totvert = unode->bm_enter_totvert;
+ me->totloop = unode->bm_enter_totloop;
+ me->totpoly = unode->bm_enter_totpoly;
+ me->totedge = unode->bm_enter_totedge;
+ me->totface = 0;
+ CustomData_copy(&unode->bm_enter_vdata,
+ &me->vdata,
+ CD_MASK_MESH.vmask,
+ CD_DUPLICATE,
+ unode->bm_enter_totvert);
+ CustomData_copy(&unode->bm_enter_edata,
+ &me->edata,
+ CD_MASK_MESH.emask,
+ CD_DUPLICATE,
+ unode->bm_enter_totedge);
+ CustomData_copy(&unode->bm_enter_ldata,
+ &me->ldata,
+ CD_MASK_MESH.lmask,
+ CD_DUPLICATE,
+ unode->bm_enter_totloop);
+ CustomData_copy(&unode->bm_enter_pdata,
+ &me->pdata,
+ CD_MASK_MESH.pmask,
+ CD_DUPLICATE,
+ unode->bm_enter_totpoly);
+
+ BKE_mesh_update_customdata_pointers(me, false);
+ }
+ else {
+ BKE_sculptsession_bm_to_me(ob, true);
+ }
+
+ /* Clear data */
+ me->flag &= ~ME_SCULPT_DYNAMIC_TOPOLOGY;
+
+ /* typically valid but with global-undo they can be NULL, [#36234] */
+ if (ss->bm) {
+ BM_mesh_free(ss->bm);
+ ss->bm = NULL;
+ }
+ if (ss->bm_log) {
+ BM_log_free(ss->bm_log);
+ ss->bm_log = NULL;
+ }
+
+ BKE_particlesystem_reset_all(ob);
+ BKE_ptcache_object_reset(scene, ob, PTCACHE_RESET_OUTDATED);
+
+ /* Refresh */
+ sculpt_update_after_dynamic_topology_toggle(depsgraph, scene, ob);
}
void sculpt_dynamic_topology_disable(bContext *C, SculptUndoNode *unode)
{
- Depsgraph *depsgraph = CTX_data_depsgraph(C);
- Scene *scene = CTX_data_scene(C);
- Object *ob = CTX_data_active_object(C);
- sculpt_dynamic_topology_disable_ex(depsgraph, scene, ob, unode);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ Scene *scene = CTX_data_scene(C);
+ Object *ob = CTX_data_active_object(C);
+ sculpt_dynamic_topology_disable_ex(depsgraph, scene, ob, unode);
}
-static void sculpt_dynamic_topology_disable_with_undo(
- Depsgraph *depsgraph, Scene *scene, Object *ob)
+static void sculpt_dynamic_topology_disable_with_undo(Depsgraph *depsgraph,
+ Scene *scene,
+ Object *ob)
{
- SculptSession *ss = ob->sculpt;
- if (ss->bm) {
- sculpt_undo_push_begin("Dynamic topology disable");
- sculpt_undo_push_node(ob, NULL, SCULPT_UNDO_DYNTOPO_END);
- sculpt_dynamic_topology_disable_ex(depsgraph, scene, ob, NULL);
- sculpt_undo_push_end();
- }
+ SculptSession *ss = ob->sculpt;
+ if (ss->bm) {
+ sculpt_undo_push_begin("Dynamic topology disable");
+ sculpt_undo_push_node(ob, NULL, SCULPT_UNDO_DYNTOPO_END);
+ sculpt_dynamic_topology_disable_ex(depsgraph, scene, ob, NULL);
+ sculpt_undo_push_end();
+ }
}
-static void sculpt_dynamic_topology_enable_with_undo(
- Depsgraph *depsgraph,
- Scene *scene, Object *ob)
+static void sculpt_dynamic_topology_enable_with_undo(Depsgraph *depsgraph,
+ Scene *scene,
+ Object *ob)
{
- SculptSession *ss = ob->sculpt;
- if (ss->bm == NULL) {
- sculpt_undo_push_begin("Dynamic topology enable");
- sculpt_dynamic_topology_enable_ex(depsgraph, scene, ob);
- sculpt_undo_push_node(ob, NULL, SCULPT_UNDO_DYNTOPO_BEGIN);
- sculpt_undo_push_end();
- }
+ SculptSession *ss = ob->sculpt;
+ if (ss->bm == NULL) {
+ sculpt_undo_push_begin("Dynamic topology enable");
+ sculpt_dynamic_topology_enable_ex(depsgraph, scene, ob);
+ sculpt_undo_push_node(ob, NULL, SCULPT_UNDO_DYNTOPO_BEGIN);
+ sculpt_undo_push_end();
+ }
}
static int sculpt_dynamic_topology_toggle_exec(bContext *C, wmOperator *UNUSED(op))
{
- Depsgraph *depsgraph = CTX_data_depsgraph(C);
- Scene *scene = CTX_data_scene(C);
- Object *ob = CTX_data_active_object(C);
- SculptSession *ss = ob->sculpt;
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ Scene *scene = CTX_data_scene(C);
+ Object *ob = CTX_data_active_object(C);
+ SculptSession *ss = ob->sculpt;
- WM_cursor_wait(1);
+ WM_cursor_wait(1);
- if (ss->bm) {
- sculpt_dynamic_topology_disable_with_undo(depsgraph, scene, ob);
- }
- else {
- sculpt_dynamic_topology_enable_with_undo(depsgraph, scene, ob);
- }
+ if (ss->bm) {
+ sculpt_dynamic_topology_disable_with_undo(depsgraph, scene, ob);
+ }
+ else {
+ sculpt_dynamic_topology_enable_with_undo(depsgraph, scene, ob);
+ }
- WM_cursor_wait(0);
+ WM_cursor_wait(0);
- return OPERATOR_FINISHED;
+ return OPERATOR_FINISHED;
}
enum eDynTopoWarnFlag {
- DYNTOPO_WARN_VDATA = (1 << 0),
- DYNTOPO_WARN_EDATA = (1 << 1),
- DYNTOPO_WARN_LDATA = (1 << 2),
- DYNTOPO_WARN_MODIFIER = (1 << 3),
+ DYNTOPO_WARN_VDATA = (1 << 0),
+ DYNTOPO_WARN_EDATA = (1 << 1),
+ DYNTOPO_WARN_LDATA = (1 << 2),
+ DYNTOPO_WARN_MODIFIER = (1 << 3),
};
static int dyntopo_warning_popup(bContext *C, wmOperatorType *ot, enum eDynTopoWarnFlag flag)
{
- uiPopupMenu *pup = UI_popup_menu_begin(C, IFACE_("Warning!"), ICON_ERROR);
- uiLayout *layout = UI_popup_menu_layout(pup);
+ uiPopupMenu *pup = UI_popup_menu_begin(C, IFACE_("Warning!"), ICON_ERROR);
+ uiLayout *layout = UI_popup_menu_layout(pup);
- if (flag & (DYNTOPO_WARN_VDATA | DYNTOPO_WARN_EDATA | DYNTOPO_WARN_LDATA)) {
- const char *msg_error = TIP_("Vertex Data Detected!");
- const char *msg = TIP_("Dyntopo will not preserve vertex colors, UVs, or other customdata");
- uiItemL(layout, msg_error, ICON_INFO);
- uiItemL(layout, msg, ICON_NONE);
- uiItemS(layout);
- }
+ if (flag & (DYNTOPO_WARN_VDATA | DYNTOPO_WARN_EDATA | DYNTOPO_WARN_LDATA)) {
+ const char *msg_error = TIP_("Vertex Data Detected!");
+ const char *msg = TIP_("Dyntopo will not preserve vertex colors, UVs, or other customdata");
+ uiItemL(layout, msg_error, ICON_INFO);
+ uiItemL(layout, msg, ICON_NONE);
+ uiItemS(layout);
+ }
- if (flag & DYNTOPO_WARN_MODIFIER) {
- const char *msg_error = TIP_("Generative Modifiers Detected!");
- const char *msg = TIP_("Keeping the modifiers will increase polycount when returning to object mode");
+ if (flag & DYNTOPO_WARN_MODIFIER) {
+ const char *msg_error = TIP_("Generative Modifiers Detected!");
+ const char *msg = TIP_(
+ "Keeping the modifiers will increase polycount when returning to object mode");
- uiItemL(layout, msg_error, ICON_INFO);
- uiItemL(layout, msg, ICON_NONE);
- uiItemS(layout);
- }
+ uiItemL(layout, msg_error, ICON_INFO);
+ uiItemL(layout, msg, ICON_NONE);
+ uiItemS(layout);
+ }
- uiItemFullO_ptr(layout, ot, IFACE_("OK"), ICON_NONE, NULL, WM_OP_EXEC_DEFAULT, 0, NULL);
+ uiItemFullO_ptr(layout, ot, IFACE_("OK"), ICON_NONE, NULL, WM_OP_EXEC_DEFAULT, 0, NULL);
- UI_popup_menu_end(C, pup);
+ UI_popup_menu_end(C, pup);
- return OPERATOR_INTERFACE;
+ return OPERATOR_INTERFACE;
}
static enum eDynTopoWarnFlag sculpt_dynamic_topology_check(Scene *scene, Object *ob)
{
- Mesh *me = ob->data;
- SculptSession *ss = ob->sculpt;
+ Mesh *me = ob->data;
+ SculptSession *ss = ob->sculpt;
- enum eDynTopoWarnFlag flag = 0;
+ enum eDynTopoWarnFlag flag = 0;
- BLI_assert(ss->bm == NULL);
- UNUSED_VARS_NDEBUG(ss);
+ BLI_assert(ss->bm == NULL);
+ UNUSED_VARS_NDEBUG(ss);
- for (int i = 0; i < CD_NUMTYPES; i++) {
- if (!ELEM(i, CD_MVERT, CD_MEDGE, CD_MFACE, CD_MLOOP, CD_MPOLY, CD_PAINT_MASK, CD_ORIGINDEX)) {
- if (CustomData_has_layer(&me->vdata, i)) {
- flag |= DYNTOPO_WARN_VDATA;
- }
- if (CustomData_has_layer(&me->edata, i)) {
- flag |= DYNTOPO_WARN_EDATA;
- }
- if (CustomData_has_layer(&me->ldata, i)) {
- flag |= DYNTOPO_WARN_LDATA;
- }
- }
- }
+ for (int i = 0; i < CD_NUMTYPES; i++) {
+ if (!ELEM(i, CD_MVERT, CD_MEDGE, CD_MFACE, CD_MLOOP, CD_MPOLY, CD_PAINT_MASK, CD_ORIGINDEX)) {
+ if (CustomData_has_layer(&me->vdata, i)) {
+ flag |= DYNTOPO_WARN_VDATA;
+ }
+ if (CustomData_has_layer(&me->edata, i)) {
+ flag |= DYNTOPO_WARN_EDATA;
+ }
+ if (CustomData_has_layer(&me->ldata, i)) {
+ flag |= DYNTOPO_WARN_LDATA;
+ }
+ }
+ }
- {
- VirtualModifierData virtualModifierData;
- ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
+ {
+ VirtualModifierData virtualModifierData;
+ ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
- /* exception for shape keys because we can edit those */
- for (; md; md = md->next) {
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
- if (!modifier_isEnabled(scene, md, eModifierMode_Realtime)) continue;
+ /* exception for shape keys because we can edit those */
+ for (; md; md = md->next) {
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ if (!modifier_isEnabled(scene, md, eModifierMode_Realtime))
+ continue;
- if (mti->type == eModifierTypeType_Constructive) {
- flag |= DYNTOPO_WARN_MODIFIER;
- break;
- }
- }
- }
+ if (mti->type == eModifierTypeType_Constructive) {
+ flag |= DYNTOPO_WARN_MODIFIER;
+ break;
+ }
+ }
+ }
- return flag;
+ return flag;
}
-static int sculpt_dynamic_topology_toggle_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+static int sculpt_dynamic_topology_toggle_invoke(bContext *C,
+ wmOperator *op,
+ const wmEvent *UNUSED(event))
{
- Object *ob = CTX_data_active_object(C);
- SculptSession *ss = ob->sculpt;
+ Object *ob = CTX_data_active_object(C);
+ SculptSession *ss = ob->sculpt;
- if (!ss->bm) {
- Scene *scene = CTX_data_scene(C);
- enum eDynTopoWarnFlag flag = sculpt_dynamic_topology_check(scene, ob);
+ if (!ss->bm) {
+ Scene *scene = CTX_data_scene(C);
+ enum eDynTopoWarnFlag flag = sculpt_dynamic_topology_check(scene, ob);
- if (flag) {
- /* The mesh has customdata that will be lost, let the user confirm this is OK */
- return dyntopo_warning_popup(C, op->type, flag);
- }
- }
+ if (flag) {
+ /* The mesh has customdata that will be lost, let the user confirm this is OK */
+ return dyntopo_warning_popup(C, op->type, flag);
+ }
+ }
- return sculpt_dynamic_topology_toggle_exec(C, op);
+ return sculpt_dynamic_topology_toggle_exec(C, op);
}
static void SCULPT_OT_dynamic_topology_toggle(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Dynamic Topology Toggle";
- ot->idname = "SCULPT_OT_dynamic_topology_toggle";
- ot->description = "Dynamic topology alters the mesh topology while sculpting";
+ /* identifiers */
+ ot->name = "Dynamic Topology Toggle";
+ ot->idname = "SCULPT_OT_dynamic_topology_toggle";
+ ot->description = "Dynamic topology alters the mesh topology while sculpting";
- /* api callbacks */
- ot->invoke = sculpt_dynamic_topology_toggle_invoke;
- ot->exec = sculpt_dynamic_topology_toggle_exec;
- ot->poll = sculpt_mode_poll;
+ /* api callbacks */
+ ot->invoke = sculpt_dynamic_topology_toggle_invoke;
+ ot->exec = sculpt_dynamic_topology_toggle_exec;
+ ot->poll = sculpt_mode_poll;
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
/************************* SCULPT_OT_optimize *************************/
static int sculpt_optimize_exec(bContext *C, wmOperator *UNUSED(op))
{
- Object *ob = CTX_data_active_object(C);
+ Object *ob = CTX_data_active_object(C);
- sculpt_pbvh_clear(ob);
- WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
+ sculpt_pbvh_clear(ob);
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
- return OPERATOR_FINISHED;
+ return OPERATOR_FINISHED;
}
static bool sculpt_and_dynamic_topology_poll(bContext *C)
{
- Object *ob = CTX_data_active_object(C);
+ Object *ob = CTX_data_active_object(C);
- return sculpt_mode_poll(C) && ob->sculpt->bm;
+ return sculpt_mode_poll(C) && ob->sculpt->bm;
}
/* The BVH gets less optimal more quickly with dynamic topology than
@@ -5777,572 +5831,578 @@ static bool sculpt_and_dynamic_topology_poll(bContext *C)
* to recalculate it than toggling modes. */
static void SCULPT_OT_optimize(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Optimize";
- ot->idname = "SCULPT_OT_optimize";
- ot->description = "Recalculate the sculpt BVH to improve performance";
+ /* identifiers */
+ ot->name = "Optimize";
+ ot->idname = "SCULPT_OT_optimize";
+ ot->description = "Recalculate the sculpt BVH to improve performance";
- /* api callbacks */
- ot->exec = sculpt_optimize_exec;
- ot->poll = sculpt_and_dynamic_topology_poll;
+ /* api callbacks */
+ ot->exec = sculpt_optimize_exec;
+ ot->poll = sculpt_and_dynamic_topology_poll;
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
/********************* Dynamic topology symmetrize ********************/
static int sculpt_symmetrize_exec(bContext *C, wmOperator *UNUSED(op))
{
- Object *ob = CTX_data_active_object(C);
- const Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
- SculptSession *ss = ob->sculpt;
+ Object *ob = CTX_data_active_object(C);
+ const Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
+ SculptSession *ss = ob->sculpt;
- /* To simplify undo for symmetrize, all BMesh elements are logged
- * as deleted, then after symmetrize operation all BMesh elements
- * are logged as added (as opposed to attempting to store just the
- * parts that symmetrize modifies) */
- sculpt_undo_push_begin("Dynamic topology symmetrize");
- sculpt_undo_push_node(ob, NULL, SCULPT_UNDO_DYNTOPO_SYMMETRIZE);
- BM_log_before_all_removed(ss->bm, ss->bm_log);
+ /* To simplify undo for symmetrize, all BMesh elements are logged
+ * as deleted, then after symmetrize operation all BMesh elements
+ * are logged as added (as opposed to attempting to store just the
+ * parts that symmetrize modifies) */
+ sculpt_undo_push_begin("Dynamic topology symmetrize");
+ sculpt_undo_push_node(ob, NULL, SCULPT_UNDO_DYNTOPO_SYMMETRIZE);
+ BM_log_before_all_removed(ss->bm, ss->bm_log);
- BM_mesh_toolflags_set(ss->bm, true);
+ BM_mesh_toolflags_set(ss->bm, true);
- /* Symmetrize and re-triangulate */
- BMO_op_callf(ss->bm, (BMO_FLAG_DEFAULTS & ~BMO_FLAG_RESPECT_HIDE),
- "symmetrize input=%avef direction=%i dist=%f",
- sd->symmetrize_direction, 0.00001f);
- sculpt_dynamic_topology_triangulate(ss->bm);
+ /* Symmetrize and re-triangulate */
+ BMO_op_callf(ss->bm,
+ (BMO_FLAG_DEFAULTS & ~BMO_FLAG_RESPECT_HIDE),
+ "symmetrize input=%avef direction=%i dist=%f",
+ sd->symmetrize_direction,
+ 0.00001f);
+ sculpt_dynamic_topology_triangulate(ss->bm);
- /* bisect operator flags edges (keep tags clean for edge queue) */
- BM_mesh_elem_hflag_disable_all(ss->bm, BM_EDGE, BM_ELEM_TAG, false);
+ /* bisect operator flags edges (keep tags clean for edge queue) */
+ BM_mesh_elem_hflag_disable_all(ss->bm, BM_EDGE, BM_ELEM_TAG, false);
- BM_mesh_toolflags_set(ss->bm, false);
+ BM_mesh_toolflags_set(ss->bm, false);
- /* Finish undo */
- BM_log_all_added(ss->bm, ss->bm_log);
- sculpt_undo_push_end();
+ /* Finish undo */
+ BM_log_all_added(ss->bm, ss->bm_log);
+ sculpt_undo_push_end();
- /* Redraw */
- sculpt_pbvh_clear(ob);
- WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
+ /* Redraw */
+ sculpt_pbvh_clear(ob);
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
- return OPERATOR_FINISHED;
+ return OPERATOR_FINISHED;
}
static void SCULPT_OT_symmetrize(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Symmetrize";
- ot->idname = "SCULPT_OT_symmetrize";
- ot->description = "Symmetrize the topology modifications";
+ /* identifiers */
+ ot->name = "Symmetrize";
+ ot->idname = "SCULPT_OT_symmetrize";
+ ot->description = "Symmetrize the topology modifications";
- /* api callbacks */
- ot->exec = sculpt_symmetrize_exec;
- ot->poll = sculpt_and_dynamic_topology_poll;
+ /* api callbacks */
+ ot->exec = sculpt_symmetrize_exec;
+ ot->poll = sculpt_and_dynamic_topology_poll;
}
/**** Toggle operator for turning sculpt mode on or off ****/
static void sculpt_init_session(Depsgraph *depsgraph, Scene *scene, Object *ob)
{
- /* Create persistent sculpt mode data */
- BKE_sculpt_toolsettings_data_ensure(scene);
-
- ob->sculpt = MEM_callocN(sizeof(SculptSession), "sculpt session");
- ob->sculpt->mode_type = OB_MODE_SCULPT;
- BKE_sculpt_update_mesh_elements(depsgraph, scene, scene->toolsettings->sculpt, ob, false, false);
-}
-
-static int ed_object_sculptmode_flush_recalc_flag(Scene *scene, Object *ob, MultiresModifierData *mmd)
-{
- int flush_recalc = 0;
- /* multires in sculpt mode could have different from object mode subdivision level */
- flush_recalc |= mmd && mmd->sculptlvl != mmd->lvl;
- /* if object has got active modifiers, it's dm could be different in sculpt mode */
- flush_recalc |= sculpt_has_active_modifiers(scene, ob);
- return flush_recalc;
-}
-
-void ED_object_sculptmode_enter_ex(
- Main *bmain, Depsgraph *depsgraph,
- Scene *scene, Object *ob, const bool force_dyntopo,
- ReportList *reports)
-{
- const int mode_flag = OB_MODE_SCULPT;
- Mesh *me = BKE_mesh_from_object(ob);
-
- /* Enter sculptmode */
- ob->mode |= mode_flag;
-
- MultiresModifierData *mmd = BKE_sculpt_multires_active(scene, ob);
-
- const int flush_recalc = ed_object_sculptmode_flush_recalc_flag(scene, ob, mmd);
-
- if (flush_recalc)
- DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
-
- /* Create sculpt mode session data */
- if (ob->sculpt) {
- BKE_sculptsession_free(ob);
- }
-
- /* Make sure derived final from original object does not reference possibly
- * freed memory.
- */
- BKE_object_free_derived_caches(ob);
-
- sculpt_init_session(depsgraph, scene, ob);
-
- /* Mask layer is required */
- if (mmd) {
- /* XXX, we could attempt to support adding mask data mid-sculpt mode (with multi-res)
- * but this ends up being quite tricky (and slow) */
- BKE_sculpt_mask_layers_ensure(ob, mmd);
- }
-
- if (!(fabsf(ob->scale[0] - ob->scale[1]) < 1e-4f && fabsf(ob->scale[1] - ob->scale[2]) < 1e-4f)) {
- BKE_report(reports, RPT_WARNING,
- "Object has non-uniform scale, sculpting may be unpredictable");
- }
- else if (is_negative_m4(ob->obmat)) {
- BKE_report(reports, RPT_WARNING,
- "Object has negative scale, sculpting may be unpredictable");
- }
-
- Paint *paint = BKE_paint_get_active_from_paintmode(scene, PAINT_MODE_SCULPT);
- BKE_paint_init(bmain, scene, PAINT_MODE_SCULPT, PAINT_CURSOR_SCULPT);
-
- paint_cursor_start_explicit(paint, bmain->wm.first, sculpt_poll_view3d);
-
- /* Check dynamic-topology flag; re-enter dynamic-topology mode when changing modes,
- * As long as no data was added that is not supported. */
- if (me->flag & ME_SCULPT_DYNAMIC_TOPOLOGY) {
- const char *message_unsupported = NULL;
- if (me->totloop != me->totpoly * 3) {
- message_unsupported = TIP_("non-triangle face");
- }
- else if (mmd != NULL) {
- message_unsupported = TIP_("multi-res modifier");
- }
- else {
- enum eDynTopoWarnFlag flag = sculpt_dynamic_topology_check(scene, ob);
- if (flag == 0) {
- /* pass */
- }
- else if (flag & DYNTOPO_WARN_VDATA) {
- message_unsupported = TIP_("vertex data");
- }
- else if (flag & DYNTOPO_WARN_EDATA) {
- message_unsupported = TIP_("edge data");
- }
- else if (flag & DYNTOPO_WARN_LDATA) {
- message_unsupported = TIP_("face data");
- }
- else if (flag & DYNTOPO_WARN_MODIFIER) {
- message_unsupported = TIP_("constructive modifier");
- }
- else {
- BLI_assert(0);
- }
- }
-
- if ((message_unsupported == NULL) || force_dyntopo) {
- /* Needed because we may be entering this mode before the undo system loads. */
- wmWindowManager *wm = bmain->wm.first;
- bool has_undo = wm->undo_stack != NULL;
- /* undo push is needed to prevent memory leak */
- if (has_undo) {
- sculpt_undo_push_begin("Dynamic topology enable");
- }
- sculpt_dynamic_topology_enable_ex(depsgraph, scene, ob);
- if (has_undo) {
- sculpt_undo_push_node(ob, NULL, SCULPT_UNDO_DYNTOPO_BEGIN);
- sculpt_undo_push_end();
- }
- }
- else {
- BKE_reportf(reports, RPT_WARNING,
- "Dynamic Topology found: %s, disabled",
- message_unsupported);
- me->flag &= ~ME_SCULPT_DYNAMIC_TOPOLOGY;
- }
- }
-
- /* Flush object mode. */
- DEG_id_tag_update(&ob->id, ID_RECALC_COPY_ON_WRITE);
+ /* Create persistent sculpt mode data */
+ BKE_sculpt_toolsettings_data_ensure(scene);
+
+ ob->sculpt = MEM_callocN(sizeof(SculptSession), "sculpt session");
+ ob->sculpt->mode_type = OB_MODE_SCULPT;
+ BKE_sculpt_update_mesh_elements(depsgraph, scene, scene->toolsettings->sculpt, ob, false, false);
+}
+
+static int ed_object_sculptmode_flush_recalc_flag(Scene *scene,
+ Object *ob,
+ MultiresModifierData *mmd)
+{
+ int flush_recalc = 0;
+ /* multires in sculpt mode could have different from object mode subdivision level */
+ flush_recalc |= mmd && mmd->sculptlvl != mmd->lvl;
+ /* if object has got active modifiers, it's dm could be different in sculpt mode */
+ flush_recalc |= sculpt_has_active_modifiers(scene, ob);
+ return flush_recalc;
+}
+
+void ED_object_sculptmode_enter_ex(Main *bmain,
+ Depsgraph *depsgraph,
+ Scene *scene,
+ Object *ob,
+ const bool force_dyntopo,
+ ReportList *reports)
+{
+ const int mode_flag = OB_MODE_SCULPT;
+ Mesh *me = BKE_mesh_from_object(ob);
+
+ /* Enter sculptmode */
+ ob->mode |= mode_flag;
+
+ MultiresModifierData *mmd = BKE_sculpt_multires_active(scene, ob);
+
+ const int flush_recalc = ed_object_sculptmode_flush_recalc_flag(scene, ob, mmd);
+
+ if (flush_recalc)
+ DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
+
+ /* Create sculpt mode session data */
+ if (ob->sculpt) {
+ BKE_sculptsession_free(ob);
+ }
+
+ /* Make sure derived final from original object does not reference possibly
+ * freed memory.
+ */
+ BKE_object_free_derived_caches(ob);
+
+ sculpt_init_session(depsgraph, scene, ob);
+
+ /* Mask layer is required */
+ if (mmd) {
+ /* XXX, we could attempt to support adding mask data mid-sculpt mode (with multi-res)
+ * but this ends up being quite tricky (and slow) */
+ BKE_sculpt_mask_layers_ensure(ob, mmd);
+ }
+
+ if (!(fabsf(ob->scale[0] - ob->scale[1]) < 1e-4f &&
+ fabsf(ob->scale[1] - ob->scale[2]) < 1e-4f)) {
+ BKE_report(
+ reports, RPT_WARNING, "Object has non-uniform scale, sculpting may be unpredictable");
+ }
+ else if (is_negative_m4(ob->obmat)) {
+ BKE_report(reports, RPT_WARNING, "Object has negative scale, sculpting may be unpredictable");
+ }
+
+ Paint *paint = BKE_paint_get_active_from_paintmode(scene, PAINT_MODE_SCULPT);
+ BKE_paint_init(bmain, scene, PAINT_MODE_SCULPT, PAINT_CURSOR_SCULPT);
+
+ paint_cursor_start_explicit(paint, bmain->wm.first, sculpt_poll_view3d);
+
+ /* Check dynamic-topology flag; re-enter dynamic-topology mode when changing modes,
+ * As long as no data was added that is not supported. */
+ if (me->flag & ME_SCULPT_DYNAMIC_TOPOLOGY) {
+ const char *message_unsupported = NULL;
+ if (me->totloop != me->totpoly * 3) {
+ message_unsupported = TIP_("non-triangle face");
+ }
+ else if (mmd != NULL) {
+ message_unsupported = TIP_("multi-res modifier");
+ }
+ else {
+ enum eDynTopoWarnFlag flag = sculpt_dynamic_topology_check(scene, ob);
+ if (flag == 0) {
+ /* pass */
+ }
+ else if (flag & DYNTOPO_WARN_VDATA) {
+ message_unsupported = TIP_("vertex data");
+ }
+ else if (flag & DYNTOPO_WARN_EDATA) {
+ message_unsupported = TIP_("edge data");
+ }
+ else if (flag & DYNTOPO_WARN_LDATA) {
+ message_unsupported = TIP_("face data");
+ }
+ else if (flag & DYNTOPO_WARN_MODIFIER) {
+ message_unsupported = TIP_("constructive modifier");
+ }
+ else {
+ BLI_assert(0);
+ }
+ }
+
+ if ((message_unsupported == NULL) || force_dyntopo) {
+ /* Needed because we may be entering this mode before the undo system loads. */
+ wmWindowManager *wm = bmain->wm.first;
+ bool has_undo = wm->undo_stack != NULL;
+ /* undo push is needed to prevent memory leak */
+ if (has_undo) {
+ sculpt_undo_push_begin("Dynamic topology enable");
+ }
+ sculpt_dynamic_topology_enable_ex(depsgraph, scene, ob);
+ if (has_undo) {
+ sculpt_undo_push_node(ob, NULL, SCULPT_UNDO_DYNTOPO_BEGIN);
+ sculpt_undo_push_end();
+ }
+ }
+ else {
+ BKE_reportf(
+ reports, RPT_WARNING, "Dynamic Topology found: %s, disabled", message_unsupported);
+ me->flag &= ~ME_SCULPT_DYNAMIC_TOPOLOGY;
+ }
+ }
+
+ /* Flush object mode. */
+ DEG_id_tag_update(&ob->id, ID_RECALC_COPY_ON_WRITE);
}
void ED_object_sculptmode_enter(struct bContext *C, ReportList *reports)
{
- Main *bmain = CTX_data_main(C);
- Scene *scene = CTX_data_scene(C);
- ViewLayer *view_layer = CTX_data_view_layer(C);
- Object *ob = OBACT(view_layer);
- Depsgraph *depsgraph = CTX_data_depsgraph(C);
- ED_object_sculptmode_enter_ex(bmain, depsgraph, scene, ob, false, reports);
+ Main *bmain = CTX_data_main(C);
+ Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Object *ob = OBACT(view_layer);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ ED_object_sculptmode_enter_ex(bmain, depsgraph, scene, ob, false, reports);
}
-void ED_object_sculptmode_exit_ex(
- Depsgraph *depsgraph,
- Scene *scene, Object *ob)
+void ED_object_sculptmode_exit_ex(Depsgraph *depsgraph, Scene *scene, Object *ob)
{
- const int mode_flag = OB_MODE_SCULPT;
- Mesh *me = BKE_mesh_from_object(ob);
+ const int mode_flag = OB_MODE_SCULPT;
+ Mesh *me = BKE_mesh_from_object(ob);
- MultiresModifierData *mmd = BKE_sculpt_multires_active(scene, ob);
- if (mmd) {
- multires_force_update(ob);
- }
+ MultiresModifierData *mmd = BKE_sculpt_multires_active(scene, ob);
+ if (mmd) {
+ multires_force_update(ob);
+ }
- /* Not needed for now. */
+ /* Not needed for now. */
#if 0
- const int flush_recalc = ed_object_sculptmode_flush_recalc_flag(scene, ob, mmd);
+ const int flush_recalc = ed_object_sculptmode_flush_recalc_flag(scene, ob, mmd);
#endif
- /* Always for now, so leaving sculpt mode always ensures scene is in
- * a consistent state.
- */
- if (true || /* flush_recalc || */ (ob->sculpt && ob->sculpt->bm)) {
- DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
- }
+ /* Always for now, so leaving sculpt mode always ensures scene is in
+ * a consistent state.
+ */
+ if (true || /* flush_recalc || */ (ob->sculpt && ob->sculpt->bm)) {
+ DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
+ }
- if (me->flag & ME_SCULPT_DYNAMIC_TOPOLOGY) {
- /* Dynamic topology must be disabled before exiting sculpt
- * mode to ensure the undo stack stays in a consistent
- * state */
- sculpt_dynamic_topology_disable_with_undo(depsgraph, scene, ob);
+ if (me->flag & ME_SCULPT_DYNAMIC_TOPOLOGY) {
+ /* Dynamic topology must be disabled before exiting sculpt
+ * mode to ensure the undo stack stays in a consistent
+ * state */
+ sculpt_dynamic_topology_disable_with_undo(depsgraph, scene, ob);
- /* store so we know to re-enable when entering sculpt mode */
- me->flag |= ME_SCULPT_DYNAMIC_TOPOLOGY;
- }
+ /* store so we know to re-enable when entering sculpt mode */
+ me->flag |= ME_SCULPT_DYNAMIC_TOPOLOGY;
+ }
- /* Leave sculptmode */
- ob->mode &= ~mode_flag;
+ /* Leave sculptmode */
+ ob->mode &= ~mode_flag;
- BKE_sculptsession_free(ob);
+ BKE_sculptsession_free(ob);
- paint_cursor_delete_textures();
+ paint_cursor_delete_textures();
- /* Never leave derived meshes behind. */
- BKE_object_free_derived_caches(ob);
+ /* Never leave derived meshes behind. */
+ BKE_object_free_derived_caches(ob);
- /* Flush object mode. */
- DEG_id_tag_update(&ob->id, ID_RECALC_COPY_ON_WRITE);
+ /* Flush object mode. */
+ DEG_id_tag_update(&ob->id, ID_RECALC_COPY_ON_WRITE);
}
void ED_object_sculptmode_exit(bContext *C)
{
- Depsgraph *depsgraph = CTX_data_depsgraph(C);
- Scene *scene = CTX_data_scene(C);
- ViewLayer *view_layer = CTX_data_view_layer(C);
- Object *ob = OBACT(view_layer);
- ED_object_sculptmode_exit_ex(depsgraph, scene, ob);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Object *ob = OBACT(view_layer);
+ ED_object_sculptmode_exit_ex(depsgraph, scene, ob);
}
static int sculpt_mode_toggle_exec(bContext *C, wmOperator *op)
{
- struct wmMsgBus *mbus = CTX_wm_message_bus(C);
- Main *bmain = CTX_data_main(C);
- Depsgraph *depsgraph = CTX_data_depsgraph_on_load(C);
- Scene *scene = CTX_data_scene(C);
- ToolSettings *ts = scene->toolsettings;
- ViewLayer *view_layer = CTX_data_view_layer(C);
- Object *ob = OBACT(view_layer);
- const int mode_flag = OB_MODE_SCULPT;
- const bool is_mode_set = (ob->mode & mode_flag) != 0;
+ struct wmMsgBus *mbus = CTX_wm_message_bus(C);
+ Main *bmain = CTX_data_main(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph_on_load(C);
+ Scene *scene = CTX_data_scene(C);
+ ToolSettings *ts = scene->toolsettings;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Object *ob = OBACT(view_layer);
+ const int mode_flag = OB_MODE_SCULPT;
+ const bool is_mode_set = (ob->mode & mode_flag) != 0;
- if (!is_mode_set) {
- if (!ED_object_mode_compat_set(C, ob, mode_flag, op->reports)) {
- return OPERATOR_CANCELLED;
- }
- }
+ if (!is_mode_set) {
+ if (!ED_object_mode_compat_set(C, ob, mode_flag, op->reports)) {
+ return OPERATOR_CANCELLED;
+ }
+ }
- if (is_mode_set) {
- ED_object_sculptmode_exit_ex(depsgraph, scene, ob);
- }
- else {
- ED_object_sculptmode_enter_ex(bmain, depsgraph, scene, ob, false, op->reports);
- BKE_paint_toolslots_brush_validate(bmain, &ts->sculpt->paint);
- }
+ if (is_mode_set) {
+ ED_object_sculptmode_exit_ex(depsgraph, scene, ob);
+ }
+ else {
+ ED_object_sculptmode_enter_ex(bmain, depsgraph, scene, ob, false, op->reports);
+ BKE_paint_toolslots_brush_validate(bmain, &ts->sculpt->paint);
+ }
- WM_event_add_notifier(C, NC_SCENE | ND_MODE, scene);
+ WM_event_add_notifier(C, NC_SCENE | ND_MODE, scene);
- WM_msg_publish_rna_prop(mbus, &ob->id, ob, Object, mode);
+ WM_msg_publish_rna_prop(mbus, &ob->id, ob, Object, mode);
- WM_toolsystem_update_from_context_view3d(C);
+ WM_toolsystem_update_from_context_view3d(C);
- return OPERATOR_FINISHED;
+ return OPERATOR_FINISHED;
}
static void SCULPT_OT_sculptmode_toggle(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Sculpt Mode";
- ot->idname = "SCULPT_OT_sculptmode_toggle";
- ot->description = "Toggle sculpt mode in 3D view";
+ /* identifiers */
+ ot->name = "Sculpt Mode";
+ ot->idname = "SCULPT_OT_sculptmode_toggle";
+ ot->description = "Toggle sculpt mode in 3D view";
- /* api callbacks */
- ot->exec = sculpt_mode_toggle_exec;
- ot->poll = ED_operator_object_active_editable_mesh;
+ /* api callbacks */
+ ot->exec = sculpt_mode_toggle_exec;
+ ot->poll = ED_operator_object_active_editable_mesh;
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_USE_EVAL_DATA;
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_USE_EVAL_DATA;
}
static bool sculpt_and_constant_or_manual_detail_poll(bContext *C)
{
- Object *ob = CTX_data_active_object(C);
- Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
+ Object *ob = CTX_data_active_object(C);
+ Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
- return sculpt_mode_poll(C) && ob->sculpt->bm &&
- (sd->flags & (SCULPT_DYNTOPO_DETAIL_CONSTANT | SCULPT_DYNTOPO_DETAIL_MANUAL));
+ return sculpt_mode_poll(C) && ob->sculpt->bm &&
+ (sd->flags & (SCULPT_DYNTOPO_DETAIL_CONSTANT | SCULPT_DYNTOPO_DETAIL_MANUAL));
}
static int sculpt_detail_flood_fill_exec(bContext *C, wmOperator *UNUSED(op))
{
- Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
- Object *ob = CTX_data_active_object(C);
- SculptSession *ss = ob->sculpt;
- float size;
- float bb_min[3], bb_max[3], center[3], dim[3];
- int i, totnodes;
- PBVHNode **nodes;
+ Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
+ Object *ob = CTX_data_active_object(C);
+ SculptSession *ss = ob->sculpt;
+ float size;
+ float bb_min[3], bb_max[3], center[3], dim[3];
+ int i, totnodes;
+ PBVHNode **nodes;
- BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnodes);
+ BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnodes);
- if (!totnodes)
- return OPERATOR_CANCELLED;
+ if (!totnodes)
+ return OPERATOR_CANCELLED;
- for (i = 0; i < totnodes; i++) {
- BKE_pbvh_node_mark_topology_update(nodes[i]);
- }
- /* get the bounding box, it's center and size */
- BKE_pbvh_bounding_box(ob->sculpt->pbvh, bb_min, bb_max);
- add_v3_v3v3(center, bb_min, bb_max);
- mul_v3_fl(center, 0.5f);
- sub_v3_v3v3(dim, bb_max, bb_min);
- size = max_fff(dim[0], dim[1], dim[2]);
+ for (i = 0; i < totnodes; i++) {
+ BKE_pbvh_node_mark_topology_update(nodes[i]);
+ }
+ /* get the bounding box, it's center and size */
+ BKE_pbvh_bounding_box(ob->sculpt->pbvh, bb_min, bb_max);
+ add_v3_v3v3(center, bb_min, bb_max);
+ mul_v3_fl(center, 0.5f);
+ sub_v3_v3v3(dim, bb_max, bb_min);
+ size = max_fff(dim[0], dim[1], dim[2]);
- /* update topology size */
- float object_space_constant_detail = 1.0f / (sd->constant_detail * mat4_to_scale(ob->obmat));
- BKE_pbvh_bmesh_detail_size_set(ss->pbvh, object_space_constant_detail);
+ /* update topology size */
+ float object_space_constant_detail = 1.0f / (sd->constant_detail * mat4_to_scale(ob->obmat));
+ BKE_pbvh_bmesh_detail_size_set(ss->pbvh, object_space_constant_detail);
- sculpt_undo_push_begin("Dynamic topology flood fill");
- sculpt_undo_push_node(ob, NULL, SCULPT_UNDO_COORDS);
+ sculpt_undo_push_begin("Dynamic topology flood fill");
+ sculpt_undo_push_node(ob, NULL, SCULPT_UNDO_COORDS);
- while (BKE_pbvh_bmesh_update_topology(
- ss->pbvh, PBVH_Collapse | PBVH_Subdivide,
- center, NULL, size, false, false))
- {
- for (i = 0; i < totnodes; i++)
- BKE_pbvh_node_mark_topology_update(nodes[i]);
- }
+ while (BKE_pbvh_bmesh_update_topology(
+ ss->pbvh, PBVH_Collapse | PBVH_Subdivide, center, NULL, size, false, false)) {
+ for (i = 0; i < totnodes; i++)
+ BKE_pbvh_node_mark_topology_update(nodes[i]);
+ }
- MEM_freeN(nodes);
- sculpt_undo_push_end();
+ MEM_freeN(nodes);
+ sculpt_undo_push_end();
- /* force rebuild of pbvh for better BB placement */
- sculpt_pbvh_clear(ob);
- /* Redraw */
- WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
+ /* force rebuild of pbvh for better BB placement */
+ sculpt_pbvh_clear(ob);
+ /* Redraw */
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
- return OPERATOR_FINISHED;
+ return OPERATOR_FINISHED;
}
static void SCULPT_OT_detail_flood_fill(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Detail Flood Fill";
- ot->idname = "SCULPT_OT_detail_flood_fill";
- ot->description = "Flood fill the mesh with the selected detail setting";
+ /* identifiers */
+ ot->name = "Detail Flood Fill";
+ ot->idname = "SCULPT_OT_detail_flood_fill";
+ ot->description = "Flood fill the mesh with the selected detail setting";
- /* api callbacks */
- ot->exec = sculpt_detail_flood_fill_exec;
- ot->poll = sculpt_and_constant_or_manual_detail_poll;
+ /* api callbacks */
+ ot->exec = sculpt_detail_flood_fill_exec;
+ ot->poll = sculpt_and_constant_or_manual_detail_poll;
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
static void sample_detail(bContext *C, int mx, int my)
{
- /* Find 3D view to pick from. */
- bScreen *screen = CTX_wm_screen(C);
- ScrArea *sa = BKE_screen_find_area_xy(screen, SPACE_VIEW3D, mx, my);
- ARegion *ar = (sa) ? BKE_area_find_region_xy(sa, RGN_TYPE_WINDOW, mx, my) : NULL;
- if (ar == NULL) {
- return;
- }
+ /* Find 3D view to pick from. */
+ bScreen *screen = CTX_wm_screen(C);
+ ScrArea *sa = BKE_screen_find_area_xy(screen, SPACE_VIEW3D, mx, my);
+ ARegion *ar = (sa) ? BKE_area_find_region_xy(sa, RGN_TYPE_WINDOW, mx, my) : NULL;
+ if (ar == NULL) {
+ return;
+ }
- /* Set context to 3D view. */
- ScrArea *prev_sa = CTX_wm_area(C);
- ARegion *prev_ar = CTX_wm_region(C);
- CTX_wm_area_set(C, sa);
- CTX_wm_region_set(C, ar);
+ /* Set context to 3D view. */
+ ScrArea *prev_sa = CTX_wm_area(C);
+ ARegion *prev_ar = CTX_wm_region(C);
+ CTX_wm_area_set(C, sa);
+ CTX_wm_region_set(C, ar);
- ViewContext vc;
- ED_view3d_viewcontext_init(C, &vc);
+ ViewContext vc;
+ ED_view3d_viewcontext_init(C, &vc);
- /* Pick sample detail. */
- Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
- Object *ob = vc.obact;
- Brush *brush = BKE_paint_brush(&sd->paint);
+ /* Pick sample detail. */
+ Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
+ Object *ob = vc.obact;
+ Brush *brush = BKE_paint_brush(&sd->paint);
- sculpt_stroke_modifiers_check(C, ob, brush);
+ sculpt_stroke_modifiers_check(C, ob, brush);
- float mouse[2] = {mx - ar->winrct.xmin, my - ar->winrct.ymin};
- float ray_start[3], ray_end[3], ray_normal[3];
- float depth = sculpt_raycast_init(&vc, mouse, ray_start, ray_end, ray_normal, false);
+ float mouse[2] = {mx - ar->winrct.xmin, my - ar->winrct.ymin};
+ float ray_start[3], ray_end[3], ray_normal[3];
+ float depth = sculpt_raycast_init(&vc, mouse, ray_start, ray_end, ray_normal, false);
- SculptDetailRaycastData srd;
- srd.hit = 0;
- srd.ray_start = ray_start;
- srd.ray_normal = ray_normal;
- srd.depth = depth;
- srd.edge_length = 0.0f;
+ SculptDetailRaycastData srd;
+ srd.hit = 0;
+ srd.ray_start = ray_start;
+ srd.ray_normal = ray_normal;
+ srd.depth = depth;
+ srd.edge_length = 0.0f;
- BKE_pbvh_raycast(ob->sculpt->pbvh, sculpt_raycast_detail_cb, &srd,
- ray_start, ray_normal, false);
+ BKE_pbvh_raycast(ob->sculpt->pbvh, sculpt_raycast_detail_cb, &srd, ray_start, ray_normal, false);
- if (srd.hit && srd.edge_length > 0.0f) {
- /* Convert edge length to world space detail resolution. */
- sd->constant_detail = 1 / (srd.edge_length * mat4_to_scale(ob->obmat));
- }
+ if (srd.hit && srd.edge_length > 0.0f) {
+ /* Convert edge length to world space detail resolution. */
+ sd->constant_detail = 1 / (srd.edge_length * mat4_to_scale(ob->obmat));
+ }
- /* Restore context. */
- CTX_wm_area_set(C, prev_sa);
- CTX_wm_region_set(C, prev_ar);
+ /* Restore context. */
+ CTX_wm_area_set(C, prev_sa);
+ CTX_wm_region_set(C, prev_ar);
}
static int sculpt_sample_detail_size_exec(bContext *C, wmOperator *op)
{
- int ss_co[2];
- RNA_int_get_array(op->ptr, "location", ss_co);
- sample_detail(C, ss_co[0], ss_co[1]);
- return OPERATOR_FINISHED;
+ int ss_co[2];
+ RNA_int_get_array(op->ptr, "location", ss_co);
+ sample_detail(C, ss_co[0], ss_co[1]);
+ return OPERATOR_FINISHED;
}
-
static int sculpt_sample_detail_size_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(e))
{
- ED_workspace_status_text(C, "Click on the mesh to set the detail");
- WM_cursor_modal_set(CTX_wm_window(C), BC_EYEDROPPER_CURSOR);
- WM_event_add_modal_handler(C, op);
- return OPERATOR_RUNNING_MODAL;
+ ED_workspace_status_text(C, "Click on the mesh to set the detail");
+ WM_cursor_modal_set(CTX_wm_window(C), BC_EYEDROPPER_CURSOR);
+ WM_event_add_modal_handler(C, op);
+ return OPERATOR_RUNNING_MODAL;
}
static int sculpt_sample_detail_size_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
- switch (event->type) {
- case LEFTMOUSE:
- if (event->val == KM_PRESS) {
- int ss_co[2] = {event->x, event->y};
+ switch (event->type) {
+ case LEFTMOUSE:
+ if (event->val == KM_PRESS) {
+ int ss_co[2] = {event->x, event->y};
- sample_detail(C, ss_co[0], ss_co[1]);
+ sample_detail(C, ss_co[0], ss_co[1]);
- RNA_int_set_array(op->ptr, "location", ss_co);
- WM_cursor_modal_restore(CTX_wm_window(C));
- ED_workspace_status_text(C, NULL);
- WM_main_add_notifier(NC_SCENE | ND_TOOLSETTINGS, NULL);
+ RNA_int_set_array(op->ptr, "location", ss_co);
+ WM_cursor_modal_restore(CTX_wm_window(C));
+ ED_workspace_status_text(C, NULL);
+ WM_main_add_notifier(NC_SCENE | ND_TOOLSETTINGS, NULL);
- return OPERATOR_FINISHED;
- }
- break;
+ return OPERATOR_FINISHED;
+ }
+ break;
- case RIGHTMOUSE:
- {
- WM_cursor_modal_restore(CTX_wm_window(C));
- ED_workspace_status_text(C, NULL);
+ case RIGHTMOUSE: {
+ WM_cursor_modal_restore(CTX_wm_window(C));
+ ED_workspace_status_text(C, NULL);
- return OPERATOR_CANCELLED;
- }
- }
+ return OPERATOR_CANCELLED;
+ }
+ }
- return OPERATOR_RUNNING_MODAL;
+ return OPERATOR_RUNNING_MODAL;
}
-
static void SCULPT_OT_sample_detail_size(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Sample Detail Size";
- ot->idname = "SCULPT_OT_sample_detail_size";
- ot->description = "Sample the mesh detail on clicked point";
+ /* identifiers */
+ ot->name = "Sample Detail Size";
+ ot->idname = "SCULPT_OT_sample_detail_size";
+ ot->description = "Sample the mesh detail on clicked point";
- /* api callbacks */
- ot->invoke = sculpt_sample_detail_size_invoke;
- ot->exec = sculpt_sample_detail_size_exec;
- ot->modal = sculpt_sample_detail_size_modal;
- ot->poll = sculpt_and_constant_or_manual_detail_poll;
+ /* api callbacks */
+ ot->invoke = sculpt_sample_detail_size_invoke;
+ ot->exec = sculpt_sample_detail_size_exec;
+ ot->modal = sculpt_sample_detail_size_modal;
+ ot->poll = sculpt_and_constant_or_manual_detail_poll;
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- RNA_def_int_array(ot->srna, "location", 2, NULL, 0, SHRT_MAX,
- "Location", "Screen Coordinates of sampling", 0, SHRT_MAX);
+ RNA_def_int_array(ot->srna,
+ "location",
+ 2,
+ NULL,
+ 0,
+ SHRT_MAX,
+ "Location",
+ "Screen Coordinates of sampling",
+ 0,
+ SHRT_MAX);
}
-
/* Dynamic-topology detail size
*
* This should be improved further, perhaps by showing a triangle
* grid rather than brush alpha */
static void set_brush_rc_props(PointerRNA *ptr, const char *prop)
{
- char *path = BLI_sprintfN("tool_settings.sculpt.brush.%s", prop);
- RNA_string_set(ptr, "data_path_primary", path);
- MEM_freeN(path);
+ char *path = BLI_sprintfN("tool_settings.sculpt.brush.%s", prop);
+ RNA_string_set(ptr, "data_path_primary", path);
+ MEM_freeN(path);
}
static int sculpt_set_detail_size_exec(bContext *C, wmOperator *UNUSED(op))
{
- Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
+ Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
- PointerRNA props_ptr;
- wmOperatorType *ot = WM_operatortype_find("WM_OT_radial_control", true);
+ PointerRNA props_ptr;
+ wmOperatorType *ot = WM_operatortype_find("WM_OT_radial_control", true);
- WM_operator_properties_create_ptr(&props_ptr, ot);
+ WM_operator_properties_create_ptr(&props_ptr, ot);
- if (sd->flags & (SCULPT_DYNTOPO_DETAIL_CONSTANT | SCULPT_DYNTOPO_DETAIL_MANUAL)) {
- set_brush_rc_props(&props_ptr, "constant_detail_resolution");
- RNA_string_set(&props_ptr, "data_path_primary", "tool_settings.sculpt.constant_detail_resolution");
- }
- else if (sd->flags & SCULPT_DYNTOPO_DETAIL_BRUSH) {
- set_brush_rc_props(&props_ptr, "constant_detail_resolution");
- RNA_string_set(&props_ptr, "data_path_primary", "tool_settings.sculpt.detail_percent");
- }
- else {
- set_brush_rc_props(&props_ptr, "detail_size");
- RNA_string_set(&props_ptr, "data_path_primary", "tool_settings.sculpt.detail_size");
- }
+ if (sd->flags & (SCULPT_DYNTOPO_DETAIL_CONSTANT | SCULPT_DYNTOPO_DETAIL_MANUAL)) {
+ set_brush_rc_props(&props_ptr, "constant_detail_resolution");
+ RNA_string_set(
+ &props_ptr, "data_path_primary", "tool_settings.sculpt.constant_detail_resolution");
+ }
+ else if (sd->flags & SCULPT_DYNTOPO_DETAIL_BRUSH) {
+ set_brush_rc_props(&props_ptr, "constant_detail_resolution");
+ RNA_string_set(&props_ptr, "data_path_primary", "tool_settings.sculpt.detail_percent");
+ }
+ else {
+ set_brush_rc_props(&props_ptr, "detail_size");
+ RNA_string_set(&props_ptr, "data_path_primary", "tool_settings.sculpt.detail_size");
+ }
- WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &props_ptr);
+ WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &props_ptr);
- WM_operator_properties_free(&props_ptr);
+ WM_operator_properties_free(&props_ptr);
- return OPERATOR_FINISHED;
+ return OPERATOR_FINISHED;
}
static void SCULPT_OT_set_detail_size(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Set Detail Size";
- ot->idname = "SCULPT_OT_set_detail_size";
- ot->description = "Set the mesh detail (either relative or constant one, depending on current dyntopo mode)";
+ /* identifiers */
+ ot->name = "Set Detail Size";
+ ot->idname = "SCULPT_OT_set_detail_size";
+ ot->description =
+ "Set the mesh detail (either relative or constant one, depending on current dyntopo mode)";
- /* api callbacks */
- ot->exec = sculpt_set_detail_size_exec;
- ot->poll = sculpt_and_dynamic_topology_poll;
+ /* api callbacks */
+ ot->exec = sculpt_set_detail_size_exec;
+ ot->poll = sculpt_and_dynamic_topology_poll;
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
void ED_operatortypes_sculpt(void)
{
- WM_operatortype_append(SCULPT_OT_brush_stroke);
- WM_operatortype_append(SCULPT_OT_sculptmode_toggle);
- WM_operatortype_append(SCULPT_OT_set_persistent_base);
- WM_operatortype_append(SCULPT_OT_dynamic_topology_toggle);
- WM_operatortype_append(SCULPT_OT_optimize);
- WM_operatortype_append(SCULPT_OT_symmetrize);
- WM_operatortype_append(SCULPT_OT_detail_flood_fill);
- WM_operatortype_append(SCULPT_OT_sample_detail_size);
- WM_operatortype_append(SCULPT_OT_set_detail_size);
+ WM_operatortype_append(SCULPT_OT_brush_stroke);
+ WM_operatortype_append(SCULPT_OT_sculptmode_toggle);
+ WM_operatortype_append(SCULPT_OT_set_persistent_base);
+ WM_operatortype_append(SCULPT_OT_dynamic_topology_toggle);
+ WM_operatortype_append(SCULPT_OT_optimize);
+ WM_operatortype_append(SCULPT_OT_symmetrize);
+ WM_operatortype_append(SCULPT_OT_detail_flood_fill);
+ WM_operatortype_append(SCULPT_OT_sample_detail_size);
+ WM_operatortype_append(SCULPT_OT_set_detail_size);
}
diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h
index 44ed680a916..97f2ca1a143 100644
--- a/source/blender/editors/sculpt_paint/sculpt_intern.h
+++ b/source/blender/editors/sculpt_paint/sculpt_intern.h
@@ -21,7 +21,6 @@
* \ingroup edsculpt
*/
-
#ifndef __SCULPT_INTERN_H__
#define __SCULPT_INTERN_H__
@@ -52,72 +51,72 @@ bool sculpt_stroke_get_location(struct bContext *C, float out[3], const float mo
/* Dynamic topology */
void sculpt_pbvh_clear(Object *ob);
void sculpt_dyntopo_node_layers_add(struct SculptSession *ss);
-void sculpt_update_after_dynamic_topology_toggle(
- struct Depsgraph *depsgraph,
- struct Scene *scene, struct Object *ob);
-void sculpt_dynamic_topology_enable_ex(
- struct Depsgraph *depsgraph,
- struct Scene *scene, struct Object *ob);
-
-void sculpt_dynamic_topology_disable_ex(
- struct Depsgraph *depsgraph,
- struct Scene *scene, struct Object *ob,
- struct SculptUndoNode *unode);
+void sculpt_update_after_dynamic_topology_toggle(struct Depsgraph *depsgraph,
+ struct Scene *scene,
+ struct Object *ob);
+void sculpt_dynamic_topology_enable_ex(struct Depsgraph *depsgraph,
+ struct Scene *scene,
+ struct Object *ob);
+
+void sculpt_dynamic_topology_disable_ex(struct Depsgraph *depsgraph,
+ struct Scene *scene,
+ struct Object *ob,
+ struct SculptUndoNode *unode);
void sculpt_dynamic_topology_disable(bContext *C, struct SculptUndoNode *unode);
/* Undo */
typedef enum {
- SCULPT_UNDO_COORDS,
- SCULPT_UNDO_HIDDEN,
- SCULPT_UNDO_MASK,
- SCULPT_UNDO_DYNTOPO_BEGIN,
- SCULPT_UNDO_DYNTOPO_END,
- SCULPT_UNDO_DYNTOPO_SYMMETRIZE,
+ SCULPT_UNDO_COORDS,
+ SCULPT_UNDO_HIDDEN,
+ SCULPT_UNDO_MASK,
+ SCULPT_UNDO_DYNTOPO_BEGIN,
+ SCULPT_UNDO_DYNTOPO_END,
+ SCULPT_UNDO_DYNTOPO_SYMMETRIZE,
} SculptUndoType;
typedef struct SculptUndoNode {
- struct SculptUndoNode *next, *prev;
-
- SculptUndoType type;
-
- char idname[MAX_ID_NAME]; /* name instead of pointer*/
- void *node; /* only during push, not valid afterwards! */
-
- float (*co)[3];
- float (*orig_co)[3];
- short (*no)[3];
- float *mask;
- int totvert;
-
- /* non-multires */
- int maxvert; /* to verify if totvert it still the same */
- int *index; /* to restore into right location */
- BLI_bitmap *vert_hidden;
-
- /* multires */
- int maxgrid; /* same for grid */
- int gridsize; /* same for grid */
- int totgrid; /* to restore into right location */
- int *grids; /* to restore into right location */
- BLI_bitmap **grid_hidden;
-
- /* bmesh */
- struct BMLogEntry *bm_entry;
- bool applied;
- CustomData bm_enter_vdata;
- CustomData bm_enter_edata;
- CustomData bm_enter_ldata;
- CustomData bm_enter_pdata;
- int bm_enter_totvert;
- int bm_enter_totedge;
- int bm_enter_totloop;
- int bm_enter_totpoly;
-
- /* shape keys */
- char shapeName[sizeof(((KeyBlock *)0))->name];
-
- size_t undo_size;
+ struct SculptUndoNode *next, *prev;
+
+ SculptUndoType type;
+
+ char idname[MAX_ID_NAME]; /* name instead of pointer*/
+ void *node; /* only during push, not valid afterwards! */
+
+ float (*co)[3];
+ float (*orig_co)[3];
+ short (*no)[3];
+ float *mask;
+ int totvert;
+
+ /* non-multires */
+ int maxvert; /* to verify if totvert it still the same */
+ int *index; /* to restore into right location */
+ BLI_bitmap *vert_hidden;
+
+ /* multires */
+ int maxgrid; /* same for grid */
+ int gridsize; /* same for grid */
+ int totgrid; /* to restore into right location */
+ int *grids; /* to restore into right location */
+ BLI_bitmap **grid_hidden;
+
+ /* bmesh */
+ struct BMLogEntry *bm_entry;
+ bool applied;
+ CustomData bm_enter_vdata;
+ CustomData bm_enter_edata;
+ CustomData bm_enter_ldata;
+ CustomData bm_enter_pdata;
+ int bm_enter_totvert;
+ int bm_enter_totedge;
+ int bm_enter_totloop;
+ int bm_enter_totpoly;
+
+ /* shape keys */
+ char shapeName[sizeof(((KeyBlock *)0))->name];
+
+ size_t undo_size;
} SculptUndoNode;
/* Factor of brush to have rake point following behind
@@ -125,89 +124,88 @@ typedef struct SculptUndoNode {
#define SCULPT_RAKE_BRUSH_FACTOR 0.25f
struct SculptRakeData {
- float follow_dist;
- float follow_co[3];
+ float follow_dist;
+ float follow_co[3];
};
/* Single struct used by all BLI_task threaded callbacks, let's avoid adding 10's of those... */
typedef struct SculptThreadedTaskData {
- struct bContext *C;
- struct Sculpt *sd;
- struct Object *ob;
- const struct Brush *brush;
- struct PBVHNode **nodes;
- int totnode;
-
- struct VPaint *vp;
- struct VPaintData *vpd;
- struct WPaintData *wpd;
- struct WeightPaintInfo *wpi;
- unsigned int *lcol;
- struct Mesh *me;
- /* For passing generic params. */
- void *custom_data;
-
-
- /* Data specific to some callbacks. */
- /* Note: even if only one or two of those are used at a time, keeping them separated, names help figuring out
- * what it is, and memory overhead is ridiculous anyway... */
- float flippedbstrength;
- float angle;
- float strength;
- bool smooth_mask;
- bool has_bm_orco;
-
- struct SculptProjectVector *spvc;
- float *offset;
- float *grab_delta;
- float *cono;
- float *area_no;
- float *area_no_sp;
- float *area_co;
- float(*mat)[4];
- float(*vertCos)[3];
-
- /* 0=towards view, 1=flipped */
- float(*area_cos)[3];
- float(*area_nos)[3];
- int *count;
-
- ThreadMutex mutex;
+ struct bContext *C;
+ struct Sculpt *sd;
+ struct Object *ob;
+ const struct Brush *brush;
+ struct PBVHNode **nodes;
+ int totnode;
+
+ struct VPaint *vp;
+ struct VPaintData *vpd;
+ struct WPaintData *wpd;
+ struct WeightPaintInfo *wpi;
+ unsigned int *lcol;
+ struct Mesh *me;
+ /* For passing generic params. */
+ void *custom_data;
+
+ /* Data specific to some callbacks. */
+ /* Note: even if only one or two of those are used at a time, keeping them separated, names help figuring out
+ * what it is, and memory overhead is ridiculous anyway... */
+ float flippedbstrength;
+ float angle;
+ float strength;
+ bool smooth_mask;
+ bool has_bm_orco;
+
+ struct SculptProjectVector *spvc;
+ float *offset;
+ float *grab_delta;
+ float *cono;
+ float *area_no;
+ float *area_no_sp;
+ float *area_co;
+ float (*mat)[4];
+ float (*vertCos)[3];
+
+ /* 0=towards view, 1=flipped */
+ float (*area_cos)[3];
+ float (*area_nos)[3];
+ int *count;
+
+ ThreadMutex mutex;
} SculptThreadedTaskData;
/*************** Brush testing declarations ****************/
typedef struct SculptBrushTest {
- float radius_squared;
- float location[3];
- float dist;
- int mirror_symmetry_pass;
+ float radius_squared;
+ float location[3];
+ float dist;
+ int mirror_symmetry_pass;
- /* For circle (not sphere) projection. */
- float plane_view[4];
+ /* For circle (not sphere) projection. */
+ float plane_view[4];
- /* Some tool code uses a plane for it's calculateions. */
- float plane_tool[4];
+ /* Some tool code uses a plane for it's calculateions. */
+ float plane_tool[4];
- /* View3d clipping - only set rv3d for clipping */
- struct RegionView3D *clip_rv3d;
+ /* View3d clipping - only set rv3d for clipping */
+ struct RegionView3D *clip_rv3d;
} SculptBrushTest;
typedef bool (*SculptBrushTestFn)(SculptBrushTest *test, const float co[3]);
typedef struct {
- struct Sculpt *sd;
- struct SculptSession *ss;
- float radius_squared;
- bool original;
+ struct Sculpt *sd;
+ struct SculptSession *ss;
+ float radius_squared;
+ bool original;
} SculptSearchSphereData;
typedef struct {
- struct Sculpt *sd;
- struct SculptSession *ss;
- float radius_squared;
- bool original;
- struct DistRayAABB_Precalc *dist_ray_to_aabb_precalc;
+ struct Sculpt *sd;
+ struct SculptSession *ss;
+ float radius_squared;
+ bool original;
+ struct DistRayAABB_Precalc *dist_ray_to_aabb_precalc;
} SculptSearchCircleData;
void sculpt_brush_test_init(struct SculptSession *ss, SculptBrushTest *test);
@@ -219,26 +217,28 @@ bool sculpt_brush_test_circle_sq(SculptBrushTest *test, const float co[3]);
bool sculpt_search_sphere_cb(PBVHNode *node, void *data_v);
bool sculpt_search_circle_cb(PBVHNode *node, void *data_v);
-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);
-
-float tex_strength(
- struct SculptSession *ss, const struct Brush *br,
- const float point[3],
- const float len,
- const short vno[3],
- const float fno[3],
- const float mask,
- const int thread_id);
+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);
+
+float tex_strength(struct SculptSession *ss,
+ const struct Brush *br,
+ const float point[3],
+ const float len,
+ const short vno[3],
+ const float fno[3],
+ const float mask,
+ const int thread_id);
/* just for vertex paint. */
-void sculpt_pbvh_calc_area_normal(
- const struct Brush *brush, Object *ob,
- PBVHNode **nodes, int totnode,
- bool use_threading,
- float r_area_no[3]);
+void sculpt_pbvh_calc_area_normal(const struct Brush *brush,
+ Object *ob,
+ PBVHNode **nodes,
+ int totnode,
+ bool use_threading,
+ float r_area_no[3]);
/* Cache stroke properties. Used because
* RNA property lookup isn't particularly fast.
@@ -247,98 +247,99 @@ void sculpt_pbvh_calc_area_normal(
*/
typedef struct StrokeCache {
- /* Invariants */
- float initial_radius;
- float scale[3];
- int flag;
- float clip_tolerance[3];
- float initial_mouse[2];
-
- /* Variants */
- float radius;
- float radius_squared;
- float true_location[3];
- float true_last_location[3];
- float location[3];
- float last_location[3];
- bool is_last_valid;
-
- bool pen_flip;
- bool invert;
- float pressure;
- float mouse[2];
- float bstrength;
- float normal_weight; /* from brush (with optional override) */
-
- /* The rest is temporary storage that isn't saved as a property */
-
- bool first_time; /* Beginning of stroke may do some things special */
-
- /* from ED_view3d_ob_project_mat_get() */
- float projection_mat[4][4];
-
- /* Clean this up! */
- struct ViewContext *vc;
- const struct Brush *brush;
-
- float special_rotation;
- float grab_delta[3], grab_delta_symmetry[3];
- float old_grab_location[3], orig_grab_location[3];
-
- /* screen-space rotation defined by mouse motion */
- float rake_rotation[4], rake_rotation_symmetry[4];
- bool is_rake_rotation_valid;
- struct SculptRakeData rake_data;
-
- /* Symmetry index between 0 and 7 bit combo 0 is Brush only;
- * 1 is X mirror; 2 is Y mirror; 3 is XY; 4 is Z; 5 is XZ; 6 is YZ; 7 is XYZ */
- int symmetry;
- int mirror_symmetry_pass; /* the symmetry pass we are currently on between 0 and 7*/
- float true_view_normal[3];
- float view_normal[3];
-
- /* sculpt_normal gets calculated by calc_sculpt_normal(), then the
- * sculpt_normal_symm gets updated quickly with the usual symmetry
- * transforms */
- float sculpt_normal[3];
- float sculpt_normal_symm[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];
-
- float plane_offset[3]; /* used to shift the plane around when doing tiled strokes */
- int tile_pass;
-
- float last_center[3];
- int radial_symmetry_pass;
- float symm_rot_mat[4][4];
- float symm_rot_mat_inv[4][4];
- bool original;
- float anchored_location[3];
-
- float vertex_rotation; /* amount to rotate the vertices when using rotate brush */
- struct Dial *dial;
-
- char saved_active_brush_name[MAX_ID_NAME];
- char saved_mask_brush_tool;
- int saved_smooth_size; /* smooth tool copies the size of the current tool */
- bool alt_smooth;
-
- float plane_trim_squared;
-
- bool supports_gravity;
- float true_gravity_direction[3];
- float gravity_direction[3];
-
- rcti previous_r; /* previous redraw rectangle */
- rcti current_r; /* current redraw rectangle */
+ /* Invariants */
+ float initial_radius;
+ float scale[3];
+ int flag;
+ float clip_tolerance[3];
+ float initial_mouse[2];
+
+ /* Variants */
+ float radius;
+ float radius_squared;
+ float true_location[3];
+ float true_last_location[3];
+ float location[3];
+ float last_location[3];
+ bool is_last_valid;
+
+ bool pen_flip;
+ bool invert;
+ float pressure;
+ float mouse[2];
+ float bstrength;
+ float normal_weight; /* from brush (with optional override) */
+
+ /* The rest is temporary storage that isn't saved as a property */
+
+ bool first_time; /* Beginning of stroke may do some things special */
+
+ /* from ED_view3d_ob_project_mat_get() */
+ float projection_mat[4][4];
+
+ /* Clean this up! */
+ struct ViewContext *vc;
+ const struct Brush *brush;
+
+ float special_rotation;
+ float grab_delta[3], grab_delta_symmetry[3];
+ float old_grab_location[3], orig_grab_location[3];
+
+ /* screen-space rotation defined by mouse motion */
+ float rake_rotation[4], rake_rotation_symmetry[4];
+ bool is_rake_rotation_valid;
+ struct SculptRakeData rake_data;
+
+ /* Symmetry index between 0 and 7 bit combo 0 is Brush only;
+ * 1 is X mirror; 2 is Y mirror; 3 is XY; 4 is Z; 5 is XZ; 6 is YZ; 7 is XYZ */
+ int symmetry;
+ int mirror_symmetry_pass; /* the symmetry pass we are currently on between 0 and 7*/
+ float true_view_normal[3];
+ float view_normal[3];
+
+ /* sculpt_normal gets calculated by calc_sculpt_normal(), then the
+ * sculpt_normal_symm gets updated quickly with the usual symmetry
+ * transforms */
+ float sculpt_normal[3];
+ float sculpt_normal_symm[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];
+
+ float plane_offset[3]; /* used to shift the plane around when doing tiled strokes */
+ int tile_pass;
+
+ float last_center[3];
+ int radial_symmetry_pass;
+ float symm_rot_mat[4][4];
+ float symm_rot_mat_inv[4][4];
+ bool original;
+ float anchored_location[3];
+
+ float vertex_rotation; /* amount to rotate the vertices when using rotate brush */
+ struct Dial *dial;
+
+ char saved_active_brush_name[MAX_ID_NAME];
+ char saved_mask_brush_tool;
+ int saved_smooth_size; /* smooth tool copies the size of the current tool */
+ bool alt_smooth;
+
+ float plane_trim_squared;
+
+ bool supports_gravity;
+ float true_gravity_direction[3];
+ float gravity_direction[3];
+
+ rcti previous_r; /* previous redraw rectangle */
+ rcti current_r; /* current redraw rectangle */
} StrokeCache;
-void sculpt_cache_calc_brushdata_symm(
- StrokeCache *cache, const char symm,
- const char axis, const float angle);
+void sculpt_cache_calc_brushdata_symm(StrokeCache *cache,
+ const char symm,
+ const char axis,
+ const float angle);
void sculpt_cache_free(StrokeCache *cache);
SculptUndoNode *sculpt_undo_push_node(Object *ob, PBVHNode *node, SculptUndoType type);
diff --git a/source/blender/editors/sculpt_paint/sculpt_undo.c b/source/blender/editors/sculpt_paint/sculpt_undo.c
index 9c76292aaa7..0b995860feb 100644
--- a/source/blender/editors/sculpt_paint/sculpt_undo.c
+++ b/source/blender/editors/sculpt_paint/sculpt_undo.c
@@ -70,26 +70,25 @@
#include "paint_intern.h"
#include "sculpt_intern.h"
-
typedef struct UndoSculpt {
- ListBase nodes;
+ ListBase nodes;
- size_t undo_size;
+ size_t undo_size;
} UndoSculpt;
static UndoSculpt *sculpt_undo_get_nodes(void);
static void update_cb(PBVHNode *node, void *rebuild)
{
- BKE_pbvh_node_mark_update(node);
- if (*((bool *)rebuild))
- BKE_pbvh_node_mark_rebuild_draw(node);
- BKE_pbvh_node_fully_hidden_set(node, 0);
+ BKE_pbvh_node_mark_update(node);
+ if (*((bool *)rebuild))
+ BKE_pbvh_node_mark_rebuild_draw(node);
+ BKE_pbvh_node_fully_hidden_set(node, 0);
}
struct PartialUpdateData {
- PBVH *pbvh;
- bool rebuild;
+ PBVH *pbvh;
+ bool rebuild;
};
/**
@@ -97,248 +96,238 @@ struct PartialUpdateData {
*/
static void update_cb_partial(PBVHNode *node, void *userdata)
{
- struct PartialUpdateData *data = userdata;
- if (BKE_pbvh_node_vert_update_check_any(data->pbvh, node)) {
- update_cb(node, &(data->rebuild));
- }
+ struct PartialUpdateData *data = userdata;
+ if (BKE_pbvh_node_vert_update_check_any(data->pbvh, node)) {
+ update_cb(node, &(data->rebuild));
+ }
}
static bool test_swap_v3_v3(float a[3], float b[3])
{
- /* no need for float comparison here (memory is exactly equal or not) */
- if (memcmp(a, b, sizeof(float[3])) != 0) {
- swap_v3_v3(a, b);
- return true;
- }
- else {
- return false;
- }
+ /* no need for float comparison here (memory is exactly equal or not) */
+ if (memcmp(a, b, sizeof(float[3])) != 0) {
+ swap_v3_v3(a, b);
+ return true;
+ }
+ else {
+ return false;
+ }
}
static bool sculpt_undo_restore_deformed(
- const SculptSession *ss,
- SculptUndoNode *unode,
- int uindex, int oindex,
- float coord[3])
+ const SculptSession *ss, SculptUndoNode *unode, int uindex, int oindex, float coord[3])
{
- if (test_swap_v3_v3(coord, unode->orig_co[uindex])) {
- copy_v3_v3(unode->co[uindex], ss->deform_cos[oindex]);
- return true;
- }
- else {
- return false;
- }
+ if (test_swap_v3_v3(coord, unode->orig_co[uindex])) {
+ copy_v3_v3(unode->co[uindex], ss->deform_cos[oindex]);
+ return true;
+ }
+ else {
+ return false;
+ }
}
static bool sculpt_undo_restore_coords(bContext *C, SculptUndoNode *unode)
{
- Scene *scene = CTX_data_scene(C);
- Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
- ViewLayer *view_layer = CTX_data_view_layer(C);
- Object *ob = OBACT(view_layer);
- Depsgraph *depsgraph = CTX_data_depsgraph(C);
- SculptSession *ss = ob->sculpt;
- SubdivCCG *subdiv_ccg = ss->subdiv_ccg;
- MVert *mvert;
- int *index;
-
- if (unode->maxvert) {
- /* regular mesh restore */
-
- if (ss->kb && !STREQ(ss->kb->name, unode->shapeName)) {
- /* shape key has been changed before calling undo operator */
-
- Key *key = BKE_key_from_object(ob);
- KeyBlock *kb = key ? BKE_keyblock_find_name(key, unode->shapeName) : NULL;
-
- if (kb) {
- ob->shapenr = BLI_findindex(&key->block, kb) + 1;
-
- BKE_sculpt_update_mesh_elements(depsgraph, scene, sd, ob, false, false);
- WM_event_add_notifier(C, NC_OBJECT | ND_DATA, ob);
- }
- else {
- /* key has been removed -- skip this undo node */
- return 0;
- }
- }
-
- /* no need for float comparison here (memory is exactly equal or not) */
- index = unode->index;
- mvert = ss->mvert;
-
- if (ss->kb) {
- float (*vertCos)[3];
- vertCos = BKE_keyblock_convert_to_vertcos(ob, ss->kb);
-
- if (unode->orig_co) {
- if (ss->modifiers_active) {
- for (int i = 0; i < unode->totvert; i++) {
- sculpt_undo_restore_deformed(ss, unode, i, index[i], vertCos[index[i]]);
- }
- }
- else {
- for (int i = 0; i < unode->totvert; i++) {
- swap_v3_v3(vertCos[index[i]], unode->orig_co[i]);
- }
- }
- }
- else {
- for (int i = 0; i < unode->totvert; i++) {
- swap_v3_v3(vertCos[index[i]], unode->co[i]);
- }
- }
-
- /* propagate new coords to keyblock */
- sculpt_vertcos_to_key(ob, ss->kb, vertCos);
-
- /* pbvh uses it's own mvert array, so coords should be */
- /* propagated to pbvh here */
- BKE_pbvh_apply_vertCos(ss->pbvh, vertCos, ss->kb->totelem);
-
- MEM_freeN(vertCos);
- }
- else {
- if (unode->orig_co) {
- if (ss->modifiers_active) {
- for (int i = 0; i < unode->totvert; i++) {
- if (sculpt_undo_restore_deformed(ss, unode, i, index[i], mvert[index[i]].co)) {
- mvert[index[i]].flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- }
- else {
- for (int i = 0; i < unode->totvert; i++) {
- if (test_swap_v3_v3(mvert[index[i]].co, unode->orig_co[i])) {
- mvert[index[i]].flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- }
- }
- else {
- for (int i = 0; i < unode->totvert; i++) {
- if (test_swap_v3_v3(mvert[index[i]].co, unode->co[i])) {
- mvert[index[i]].flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- }
- }
- }
- else if (unode->maxgrid && subdiv_ccg != NULL) {
- /* multires restore */
- CCGElem **grids, *grid;
- CCGKey key;
- float (*co)[3];
- int gridsize;
-
- grids = subdiv_ccg->grids;
- gridsize = subdiv_ccg->grid_size;
- BKE_subdiv_ccg_key_top_level(&key, subdiv_ccg);
-
- co = unode->co;
- for (int j = 0; j < unode->totgrid; j++) {
- grid = grids[unode->grids[j]];
-
- for (int i = 0; i < gridsize * gridsize; i++, co++) {
- swap_v3_v3(CCG_elem_offset_co(&key, grid, i), co[0]);
- }
- }
- }
-
- return 1;
+ Scene *scene = CTX_data_scene(C);
+ Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Object *ob = OBACT(view_layer);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ SculptSession *ss = ob->sculpt;
+ SubdivCCG *subdiv_ccg = ss->subdiv_ccg;
+ MVert *mvert;
+ int *index;
+
+ if (unode->maxvert) {
+ /* regular mesh restore */
+
+ if (ss->kb && !STREQ(ss->kb->name, unode->shapeName)) {
+ /* shape key has been changed before calling undo operator */
+
+ Key *key = BKE_key_from_object(ob);
+ KeyBlock *kb = key ? BKE_keyblock_find_name(key, unode->shapeName) : NULL;
+
+ if (kb) {
+ ob->shapenr = BLI_findindex(&key->block, kb) + 1;
+
+ BKE_sculpt_update_mesh_elements(depsgraph, scene, sd, ob, false, false);
+ WM_event_add_notifier(C, NC_OBJECT | ND_DATA, ob);
+ }
+ else {
+ /* key has been removed -- skip this undo node */
+ return 0;
+ }
+ }
+
+ /* no need for float comparison here (memory is exactly equal or not) */
+ index = unode->index;
+ mvert = ss->mvert;
+
+ if (ss->kb) {
+ float(*vertCos)[3];
+ vertCos = BKE_keyblock_convert_to_vertcos(ob, ss->kb);
+
+ if (unode->orig_co) {
+ if (ss->modifiers_active) {
+ for (int i = 0; i < unode->totvert; i++) {
+ sculpt_undo_restore_deformed(ss, unode, i, index[i], vertCos[index[i]]);
+ }
+ }
+ else {
+ for (int i = 0; i < unode->totvert; i++) {
+ swap_v3_v3(vertCos[index[i]], unode->orig_co[i]);
+ }
+ }
+ }
+ else {
+ for (int i = 0; i < unode->totvert; i++) {
+ swap_v3_v3(vertCos[index[i]], unode->co[i]);
+ }
+ }
+
+ /* propagate new coords to keyblock */
+ sculpt_vertcos_to_key(ob, ss->kb, vertCos);
+
+ /* pbvh uses it's own mvert array, so coords should be */
+ /* propagated to pbvh here */
+ BKE_pbvh_apply_vertCos(ss->pbvh, vertCos, ss->kb->totelem);
+
+ MEM_freeN(vertCos);
+ }
+ else {
+ if (unode->orig_co) {
+ if (ss->modifiers_active) {
+ for (int i = 0; i < unode->totvert; i++) {
+ if (sculpt_undo_restore_deformed(ss, unode, i, index[i], mvert[index[i]].co)) {
+ mvert[index[i]].flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ }
+ else {
+ for (int i = 0; i < unode->totvert; i++) {
+ if (test_swap_v3_v3(mvert[index[i]].co, unode->orig_co[i])) {
+ mvert[index[i]].flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ }
+ }
+ else {
+ for (int i = 0; i < unode->totvert; i++) {
+ if (test_swap_v3_v3(mvert[index[i]].co, unode->co[i])) {
+ mvert[index[i]].flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ }
+ }
+ }
+ else if (unode->maxgrid && subdiv_ccg != NULL) {
+ /* multires restore */
+ CCGElem **grids, *grid;
+ CCGKey key;
+ float(*co)[3];
+ int gridsize;
+
+ grids = subdiv_ccg->grids;
+ gridsize = subdiv_ccg->grid_size;
+ BKE_subdiv_ccg_key_top_level(&key, subdiv_ccg);
+
+ co = unode->co;
+ for (int j = 0; j < unode->totgrid; j++) {
+ grid = grids[unode->grids[j]];
+
+ for (int i = 0; i < gridsize * gridsize; i++, co++) {
+ swap_v3_v3(CCG_elem_offset_co(&key, grid, i), co[0]);
+ }
+ }
+ }
+
+ return 1;
}
-static bool sculpt_undo_restore_hidden(
- bContext *C,
- SculptUndoNode *unode)
+static bool sculpt_undo_restore_hidden(bContext *C, SculptUndoNode *unode)
{
- ViewLayer *view_layer = CTX_data_view_layer(C);
- Object *ob = OBACT(view_layer);
- SculptSession *ss = ob->sculpt;
- SubdivCCG *subdiv_ccg = ss->subdiv_ccg;
- int i;
-
- if (unode->maxvert) {
- MVert *mvert = ss->mvert;
-
- for (i = 0; i < unode->totvert; i++) {
- MVert *v = &mvert[unode->index[i]];
- if ((BLI_BITMAP_TEST(unode->vert_hidden, i) != 0) != ((v->flag & ME_HIDE) != 0)) {
- BLI_BITMAP_FLIP(unode->vert_hidden, i);
- v->flag ^= ME_HIDE;
- v->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- }
- else if (unode->maxgrid && subdiv_ccg != NULL) {
- BLI_bitmap **grid_hidden = subdiv_ccg->grid_hidden;
-
- for (i = 0; i < unode->totgrid; i++) {
- SWAP(BLI_bitmap *,
- unode->grid_hidden[i],
- grid_hidden[unode->grids[i]]);
-
- }
- }
-
- return 1;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Object *ob = OBACT(view_layer);
+ SculptSession *ss = ob->sculpt;
+ SubdivCCG *subdiv_ccg = ss->subdiv_ccg;
+ int i;
+
+ if (unode->maxvert) {
+ MVert *mvert = ss->mvert;
+
+ for (i = 0; i < unode->totvert; i++) {
+ MVert *v = &mvert[unode->index[i]];
+ if ((BLI_BITMAP_TEST(unode->vert_hidden, i) != 0) != ((v->flag & ME_HIDE) != 0)) {
+ BLI_BITMAP_FLIP(unode->vert_hidden, i);
+ v->flag ^= ME_HIDE;
+ v->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ }
+ else if (unode->maxgrid && subdiv_ccg != NULL) {
+ BLI_bitmap **grid_hidden = subdiv_ccg->grid_hidden;
+
+ for (i = 0; i < unode->totgrid; i++) {
+ SWAP(BLI_bitmap *, unode->grid_hidden[i], grid_hidden[unode->grids[i]]);
+ }
+ }
+
+ return 1;
}
static bool sculpt_undo_restore_mask(bContext *C, SculptUndoNode *unode)
{
- ViewLayer *view_layer = CTX_data_view_layer(C);
- Object *ob = OBACT(view_layer);
- SculptSession *ss = ob->sculpt;
- SubdivCCG *subdiv_ccg = ss->subdiv_ccg;
- MVert *mvert;
- float *vmask;
- int *index, i, j;
-
- if (unode->maxvert) {
- /* regular mesh restore */
-
- index = unode->index;
- mvert = ss->mvert;
- vmask = ss->vmask;
-
- for (i = 0; i < unode->totvert; i++) {
- if (vmask[index[i]] != unode->mask[i]) {
- SWAP(float, vmask[index[i]], unode->mask[i]);
- mvert[index[i]].flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- }
- else if (unode->maxgrid && subdiv_ccg != NULL) {
- /* multires restore */
- CCGElem **grids, *grid;
- CCGKey key;
- float *mask;
- int gridsize;
-
- grids = subdiv_ccg->grids;
- gridsize = subdiv_ccg->grid_size;
- BKE_subdiv_ccg_key_top_level(&key, subdiv_ccg);
-
- mask = unode->mask;
- for (j = 0; j < unode->totgrid; j++) {
- grid = grids[unode->grids[j]];
-
- for (i = 0; i < gridsize * gridsize; i++, mask++)
- SWAP(float, *CCG_elem_offset_mask(&key, grid, i), *mask);
- }
- }
-
- return 1;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Object *ob = OBACT(view_layer);
+ SculptSession *ss = ob->sculpt;
+ SubdivCCG *subdiv_ccg = ss->subdiv_ccg;
+ MVert *mvert;
+ float *vmask;
+ int *index, i, j;
+
+ if (unode->maxvert) {
+ /* regular mesh restore */
+
+ index = unode->index;
+ mvert = ss->mvert;
+ vmask = ss->vmask;
+
+ for (i = 0; i < unode->totvert; i++) {
+ if (vmask[index[i]] != unode->mask[i]) {
+ SWAP(float, vmask[index[i]], unode->mask[i]);
+ mvert[index[i]].flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ }
+ else if (unode->maxgrid && subdiv_ccg != NULL) {
+ /* multires restore */
+ CCGElem **grids, *grid;
+ CCGKey key;
+ float *mask;
+ int gridsize;
+
+ grids = subdiv_ccg->grids;
+ gridsize = subdiv_ccg->grid_size;
+ BKE_subdiv_ccg_key_top_level(&key, subdiv_ccg);
+
+ mask = unode->mask;
+ for (j = 0; j < unode->totgrid; j++) {
+ grid = grids[unode->grids[j]];
+
+ for (i = 0; i < gridsize * gridsize; i++, mask++)
+ SWAP(float, *CCG_elem_offset_mask(&key, grid, i), *mask);
+ }
+ }
+
+ return 1;
}
static void sculpt_undo_bmesh_restore_generic_task_cb(
- void *__restrict userdata,
- const int n,
- const ParallelRangeTLS *__restrict UNUSED(tls))
+ void *__restrict userdata, const int n, const ParallelRangeTLS *__restrict UNUSED(tls))
{
- PBVHNode **nodes = userdata;
+ PBVHNode **nodes = userdata;
- BKE_pbvh_node_mark_redraw(nodes[n]);
+ BKE_pbvh_node_mark_redraw(nodes[n]);
}
static void sculpt_undo_bmesh_restore_generic(bContext *C,
@@ -346,59 +335,55 @@ static void sculpt_undo_bmesh_restore_generic(bContext *C,
Object *ob,
SculptSession *ss)
{
- if (unode->applied) {
- BM_log_undo(ss->bm, ss->bm_log);
- unode->applied = false;
- }
- else {
- BM_log_redo(ss->bm, ss->bm_log);
- unode->applied = true;
- }
-
- if (unode->type == SCULPT_UNDO_MASK) {
- int totnode;
- PBVHNode **nodes;
- Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
-
- BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode);
-
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
- BLI_task_parallel_range(
- 0, totnode,
- nodes,
- sculpt_undo_bmesh_restore_generic_task_cb,
- &settings);
-
- if (nodes)
- MEM_freeN(nodes);
- }
- else {
- sculpt_pbvh_clear(ob);
- }
+ if (unode->applied) {
+ BM_log_undo(ss->bm, ss->bm_log);
+ unode->applied = false;
+ }
+ else {
+ BM_log_redo(ss->bm, ss->bm_log);
+ unode->applied = true;
+ }
+
+ if (unode->type == SCULPT_UNDO_MASK) {
+ int totnode;
+ PBVHNode **nodes;
+ Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
+
+ BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode);
+
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
+ BLI_task_parallel_range(
+ 0, totnode, nodes, sculpt_undo_bmesh_restore_generic_task_cb, &settings);
+
+ if (nodes)
+ MEM_freeN(nodes);
+ }
+ else {
+ sculpt_pbvh_clear(ob);
+ }
}
/* Create empty sculpt BMesh and enable logging */
-static void sculpt_undo_bmesh_enable(
- Object *ob, SculptUndoNode *unode)
+static void sculpt_undo_bmesh_enable(Object *ob, SculptUndoNode *unode)
{
- SculptSession *ss = ob->sculpt;
- Mesh *me = ob->data;
-
- sculpt_pbvh_clear(ob);
-
- /* Create empty BMesh and enable logging */
- ss->bm = BM_mesh_create(
- &bm_mesh_allocsize_default,
- &((struct BMeshCreateParams){.use_toolflags = false,}));
- BM_data_layer_add(ss->bm, &ss->bm->vdata, CD_PAINT_MASK);
- sculpt_dyntopo_node_layers_add(ss);
- me->flag |= ME_SCULPT_DYNAMIC_TOPOLOGY;
-
- /* Restore the BMLog using saved entries */
- ss->bm_log = BM_log_from_existing_entries_create(ss->bm,
- unode->bm_entry);
+ SculptSession *ss = ob->sculpt;
+ Mesh *me = ob->data;
+
+ sculpt_pbvh_clear(ob);
+
+ /* Create empty BMesh and enable logging */
+ ss->bm = BM_mesh_create(&bm_mesh_allocsize_default,
+ &((struct BMeshCreateParams){
+ .use_toolflags = false,
+ }));
+ BM_data_layer_add(ss->bm, &ss->bm->vdata, CD_PAINT_MASK);
+ sculpt_dyntopo_node_layers_add(ss);
+ me->flag |= ME_SCULPT_DYNAMIC_TOPOLOGY;
+
+ /* Restore the BMLog using saved entries */
+ ss->bm_log = BM_log_from_existing_entries_create(ss->bm, unode->bm_entry);
}
static void sculpt_undo_bmesh_restore_begin(bContext *C,
@@ -406,18 +391,18 @@ static void sculpt_undo_bmesh_restore_begin(bContext *C,
Object *ob,
SculptSession *ss)
{
- if (unode->applied) {
- sculpt_dynamic_topology_disable(C, unode);
- unode->applied = false;
- }
- else {
- sculpt_undo_bmesh_enable(ob, unode);
-
- /* Restore the mesh from the first log entry */
- BM_log_redo(ss->bm, ss->bm_log);
-
- unode->applied = true;
- }
+ if (unode->applied) {
+ sculpt_dynamic_topology_disable(C, unode);
+ unode->applied = false;
+ }
+ else {
+ sculpt_undo_bmesh_enable(ob, unode);
+
+ /* Restore the mesh from the first log entry */
+ BM_log_redo(ss->bm, ss->bm_log);
+
+ unode->applied = true;
+ }
}
static void sculpt_undo_bmesh_restore_end(bContext *C,
@@ -425,19 +410,19 @@ static void sculpt_undo_bmesh_restore_end(bContext *C,
Object *ob,
SculptSession *ss)
{
- if (unode->applied) {
- sculpt_undo_bmesh_enable(ob, unode);
-
- /* Restore the mesh from the last log entry */
- BM_log_undo(ss->bm, ss->bm_log);
-
- unode->applied = false;
- }
- else {
- /* Disable dynamic topology sculpting */
- sculpt_dynamic_topology_disable(C, NULL);
- unode->applied = true;
- }
+ if (unode->applied) {
+ sculpt_undo_bmesh_enable(ob, unode);
+
+ /* Restore the mesh from the last log entry */
+ BM_log_undo(ss->bm, ss->bm_log);
+
+ unode->applied = false;
+ }
+ else {
+ /* Disable dynamic topology sculpting */
+ sculpt_dynamic_topology_disable(C, NULL);
+ unode->applied = true;
+ }
}
/* Handle all dynamic-topology updates
@@ -449,565 +434,555 @@ static int sculpt_undo_bmesh_restore(bContext *C,
Object *ob,
SculptSession *ss)
{
- switch (unode->type) {
- case SCULPT_UNDO_DYNTOPO_BEGIN:
- sculpt_undo_bmesh_restore_begin(C, unode, ob, ss);
- return true;
-
- case SCULPT_UNDO_DYNTOPO_END:
- sculpt_undo_bmesh_restore_end(C, unode, ob, ss);
- return true;
-
- default:
- if (ss->bm_log) {
- sculpt_undo_bmesh_restore_generic(C, unode, ob, ss);
- return true;
- }
- break;
- }
-
- return false;
+ switch (unode->type) {
+ case SCULPT_UNDO_DYNTOPO_BEGIN:
+ sculpt_undo_bmesh_restore_begin(C, unode, ob, ss);
+ return true;
+
+ case SCULPT_UNDO_DYNTOPO_END:
+ sculpt_undo_bmesh_restore_end(C, unode, ob, ss);
+ return true;
+
+ default:
+ if (ss->bm_log) {
+ sculpt_undo_bmesh_restore_generic(C, unode, ob, ss);
+ return true;
+ }
+ break;
+ }
+
+ return false;
}
static void sculpt_undo_restore_list(bContext *C, ListBase *lb)
{
- Scene *scene = CTX_data_scene(C);
- Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
- ViewLayer *view_layer = CTX_data_view_layer(C);
- Object *ob = OBACT(view_layer);
- Depsgraph *depsgraph = CTX_data_depsgraph(C);
- SculptSession *ss = ob->sculpt;
- SubdivCCG *subdiv_ccg = ss->subdiv_ccg;
- SculptUndoNode *unode;
- bool update = false, rebuild = false;
- bool need_mask = false;
- bool partial_update = true;
-
- for (unode = lb->first; unode; unode = unode->next) {
- if (STREQ(unode->idname, ob->id.name)) {
- if (unode->type == SCULPT_UNDO_MASK) {
- /* is possible that we can't do the mask undo (below)
- * because of the vertex count */
- need_mask = true;
- break;
- }
- }
- }
-
- DEG_id_tag_update(&ob->id, ID_RECALC_SHADING);
-
- BKE_sculpt_update_mesh_elements(depsgraph, scene, sd, ob, false, need_mask);
-
- if (lb->first && sculpt_undo_bmesh_restore(C, lb->first, ob, ss))
- return;
-
- for (unode = lb->first; unode; unode = unode->next) {
- if (!STREQ(unode->idname, ob->id.name))
- continue;
-
- /* check if undo data matches current data well enough to
- * continue */
- if (unode->maxvert) {
- if (ss->totvert != unode->maxvert)
- continue;
- }
- else if (unode->maxgrid && subdiv_ccg != NULL) {
- if ((subdiv_ccg->num_grids != unode->maxgrid) ||
- (subdiv_ccg->grid_size != unode->gridsize))
- {
- continue;
- }
-
- /* multi-res can't do partial updates since it doesn't flag edited vertices */
- partial_update = false;
- }
-
- switch (unode->type) {
- case SCULPT_UNDO_COORDS:
- if (sculpt_undo_restore_coords(C, unode))
- update = true;
- break;
- case SCULPT_UNDO_HIDDEN:
- if (sculpt_undo_restore_hidden(C, unode))
- rebuild = true;
- break;
- case SCULPT_UNDO_MASK:
- if (sculpt_undo_restore_mask(C, unode))
- update = true;
- break;
-
- case SCULPT_UNDO_DYNTOPO_BEGIN:
- case SCULPT_UNDO_DYNTOPO_END:
- case SCULPT_UNDO_DYNTOPO_SYMMETRIZE:
- BLI_assert(!"Dynamic topology should've already been handled");
- break;
- }
- }
-
- if (update || rebuild) {
- bool tag_update = false;
- /* we update all nodes still, should be more clever, but also
- * needs to work correct when exiting/entering sculpt mode and
- * the nodes get recreated, though in that case it could do all */
- if (partial_update) {
- struct PartialUpdateData data = {
- .rebuild = rebuild,
- .pbvh = ss->pbvh,
- };
- BKE_pbvh_search_callback(ss->pbvh, NULL, NULL, update_cb_partial, &data);
- }
- else {
- BKE_pbvh_search_callback(ss->pbvh, NULL, NULL, update_cb, &rebuild);
- }
- BKE_pbvh_update(ss->pbvh, PBVH_UpdateBB | PBVH_UpdateOriginalBB | PBVH_UpdateRedraw | PBVH_UpdateNormals, NULL);
-
- if (BKE_sculpt_multires_active(scene, ob)) {
- if (rebuild)
- multires_mark_as_modified(ob, MULTIRES_HIDDEN_MODIFIED);
- else
- multires_mark_as_modified(ob, MULTIRES_COORDS_MODIFIED);
- }
-
- tag_update |= ((Mesh *)ob->data)->id.us > 1;
-
- if (ss->kb || ss->modifiers_active) {
- Mesh *mesh = ob->data;
- BKE_mesh_calc_normals(mesh);
-
- BKE_sculptsession_free_deformMats(ss);
- tag_update |= true;
- }
-
- if (tag_update) {
- DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
- }
- else {
- sculpt_update_object_bounding_box(ob);
- }
- }
+ Scene *scene = CTX_data_scene(C);
+ Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Object *ob = OBACT(view_layer);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ SculptSession *ss = ob->sculpt;
+ SubdivCCG *subdiv_ccg = ss->subdiv_ccg;
+ SculptUndoNode *unode;
+ bool update = false, rebuild = false;
+ bool need_mask = false;
+ bool partial_update = true;
+
+ for (unode = lb->first; unode; unode = unode->next) {
+ if (STREQ(unode->idname, ob->id.name)) {
+ if (unode->type == SCULPT_UNDO_MASK) {
+ /* is possible that we can't do the mask undo (below)
+ * because of the vertex count */
+ need_mask = true;
+ break;
+ }
+ }
+ }
+
+ DEG_id_tag_update(&ob->id, ID_RECALC_SHADING);
+
+ BKE_sculpt_update_mesh_elements(depsgraph, scene, sd, ob, false, need_mask);
+
+ if (lb->first && sculpt_undo_bmesh_restore(C, lb->first, ob, ss))
+ return;
+
+ for (unode = lb->first; unode; unode = unode->next) {
+ if (!STREQ(unode->idname, ob->id.name))
+ continue;
+
+ /* check if undo data matches current data well enough to
+ * continue */
+ if (unode->maxvert) {
+ if (ss->totvert != unode->maxvert)
+ continue;
+ }
+ else if (unode->maxgrid && subdiv_ccg != NULL) {
+ if ((subdiv_ccg->num_grids != unode->maxgrid) ||
+ (subdiv_ccg->grid_size != unode->gridsize)) {
+ continue;
+ }
+
+ /* multi-res can't do partial updates since it doesn't flag edited vertices */
+ partial_update = false;
+ }
+
+ switch (unode->type) {
+ case SCULPT_UNDO_COORDS:
+ if (sculpt_undo_restore_coords(C, unode))
+ update = true;
+ break;
+ case SCULPT_UNDO_HIDDEN:
+ if (sculpt_undo_restore_hidden(C, unode))
+ rebuild = true;
+ break;
+ case SCULPT_UNDO_MASK:
+ if (sculpt_undo_restore_mask(C, unode))
+ update = true;
+ break;
+
+ case SCULPT_UNDO_DYNTOPO_BEGIN:
+ case SCULPT_UNDO_DYNTOPO_END:
+ case SCULPT_UNDO_DYNTOPO_SYMMETRIZE:
+ BLI_assert(!"Dynamic topology should've already been handled");
+ break;
+ }
+ }
+
+ if (update || rebuild) {
+ bool tag_update = false;
+ /* we update all nodes still, should be more clever, but also
+ * needs to work correct when exiting/entering sculpt mode and
+ * the nodes get recreated, though in that case it could do all */
+ if (partial_update) {
+ struct PartialUpdateData data = {
+ .rebuild = rebuild,
+ .pbvh = ss->pbvh,
+ };
+ BKE_pbvh_search_callback(ss->pbvh, NULL, NULL, update_cb_partial, &data);
+ }
+ else {
+ BKE_pbvh_search_callback(ss->pbvh, NULL, NULL, update_cb, &rebuild);
+ }
+ BKE_pbvh_update(ss->pbvh,
+ PBVH_UpdateBB | PBVH_UpdateOriginalBB | PBVH_UpdateRedraw | PBVH_UpdateNormals,
+ NULL);
+
+ if (BKE_sculpt_multires_active(scene, ob)) {
+ if (rebuild)
+ multires_mark_as_modified(ob, MULTIRES_HIDDEN_MODIFIED);
+ else
+ multires_mark_as_modified(ob, MULTIRES_COORDS_MODIFIED);
+ }
+
+ tag_update |= ((Mesh *)ob->data)->id.us > 1;
+
+ if (ss->kb || ss->modifiers_active) {
+ Mesh *mesh = ob->data;
+ BKE_mesh_calc_normals(mesh);
+
+ BKE_sculptsession_free_deformMats(ss);
+ tag_update |= true;
+ }
+
+ if (tag_update) {
+ DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
+ }
+ else {
+ sculpt_update_object_bounding_box(ob);
+ }
+ }
}
static void sculpt_undo_free_list(ListBase *lb)
{
- SculptUndoNode *unode = lb->first;
- while (unode != NULL) {
- SculptUndoNode *unode_next = unode->next;
- if (unode->co)
- MEM_freeN(unode->co);
- if (unode->no)
- MEM_freeN(unode->no);
- if (unode->index)
- MEM_freeN(unode->index);
- if (unode->grids)
- MEM_freeN(unode->grids);
- if (unode->orig_co)
- MEM_freeN(unode->orig_co);
- if (unode->vert_hidden)
- MEM_freeN(unode->vert_hidden);
- if (unode->grid_hidden) {
- for (int i = 0; i < unode->totgrid; i++) {
- if (unode->grid_hidden[i])
- MEM_freeN(unode->grid_hidden[i]);
- }
- MEM_freeN(unode->grid_hidden);
- }
- if (unode->mask)
- MEM_freeN(unode->mask);
-
- if (unode->bm_entry) {
- BM_log_entry_drop(unode->bm_entry);
- }
-
- if (unode->bm_enter_totvert)
- CustomData_free(&unode->bm_enter_vdata, unode->bm_enter_totvert);
- if (unode->bm_enter_totedge)
- CustomData_free(&unode->bm_enter_edata, unode->bm_enter_totedge);
- if (unode->bm_enter_totloop)
- CustomData_free(&unode->bm_enter_ldata, unode->bm_enter_totloop);
- if (unode->bm_enter_totpoly)
- CustomData_free(&unode->bm_enter_pdata, unode->bm_enter_totpoly);
-
- MEM_freeN(unode);
-
- unode = unode_next;
- }
+ SculptUndoNode *unode = lb->first;
+ while (unode != NULL) {
+ SculptUndoNode *unode_next = unode->next;
+ if (unode->co)
+ MEM_freeN(unode->co);
+ if (unode->no)
+ MEM_freeN(unode->no);
+ if (unode->index)
+ MEM_freeN(unode->index);
+ if (unode->grids)
+ MEM_freeN(unode->grids);
+ if (unode->orig_co)
+ MEM_freeN(unode->orig_co);
+ if (unode->vert_hidden)
+ MEM_freeN(unode->vert_hidden);
+ if (unode->grid_hidden) {
+ for (int i = 0; i < unode->totgrid; i++) {
+ if (unode->grid_hidden[i])
+ MEM_freeN(unode->grid_hidden[i]);
+ }
+ MEM_freeN(unode->grid_hidden);
+ }
+ if (unode->mask)
+ MEM_freeN(unode->mask);
+
+ if (unode->bm_entry) {
+ BM_log_entry_drop(unode->bm_entry);
+ }
+
+ if (unode->bm_enter_totvert)
+ CustomData_free(&unode->bm_enter_vdata, unode->bm_enter_totvert);
+ if (unode->bm_enter_totedge)
+ CustomData_free(&unode->bm_enter_edata, unode->bm_enter_totedge);
+ if (unode->bm_enter_totloop)
+ CustomData_free(&unode->bm_enter_ldata, unode->bm_enter_totloop);
+ if (unode->bm_enter_totpoly)
+ CustomData_free(&unode->bm_enter_pdata, unode->bm_enter_totpoly);
+
+ MEM_freeN(unode);
+
+ unode = unode_next;
+ }
}
/* Most likely we don't need this. */
#if 0
static bool sculpt_undo_cleanup(bContext *C, ListBase *lb)
{
- Scene *scene = CTX_data_scene(C);
- ViewLayer *view_layer = CTX_data_view_layer(C);
- Object *ob = OBACT(view_layer);
- SculptUndoNode *unode;
+ Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Object *ob = OBACT(view_layer);
+ SculptUndoNode *unode;
- unode = lb->first;
+ unode = lb->first;
- if (unode && !STREQ(unode->idname, ob->id.name)) {
- if (unode->bm_entry)
- BM_log_cleanup_entry(unode->bm_entry);
+ if (unode && !STREQ(unode->idname, ob->id.name)) {
+ if (unode->bm_entry)
+ BM_log_cleanup_entry(unode->bm_entry);
- return true;
- }
+ return true;
+ }
- return false;
+ return false;
}
#endif
SculptUndoNode *sculpt_undo_get_node(PBVHNode *node)
{
- UndoSculpt *usculpt = sculpt_undo_get_nodes();
+ UndoSculpt *usculpt = sculpt_undo_get_nodes();
- if (usculpt == NULL) {
- return NULL;
- }
+ if (usculpt == NULL) {
+ return NULL;
+ }
- return BLI_findptr(&usculpt->nodes, node, offsetof(SculptUndoNode, node));
+ return BLI_findptr(&usculpt->nodes, node, offsetof(SculptUndoNode, node));
}
-static void sculpt_undo_alloc_and_store_hidden(PBVH *pbvh,
- SculptUndoNode *unode)
+static void sculpt_undo_alloc_and_store_hidden(PBVH *pbvh, SculptUndoNode *unode)
{
- PBVHNode *node = unode->node;
- BLI_bitmap **grid_hidden;
- int i, *grid_indices, totgrid;
+ PBVHNode *node = unode->node;
+ BLI_bitmap **grid_hidden;
+ int i, *grid_indices, totgrid;
- grid_hidden = BKE_pbvh_grid_hidden(pbvh);
+ grid_hidden = BKE_pbvh_grid_hidden(pbvh);
- BKE_pbvh_node_get_grids(pbvh, node, &grid_indices, &totgrid,
- NULL, NULL, NULL);
+ BKE_pbvh_node_get_grids(pbvh, node, &grid_indices, &totgrid, NULL, NULL, NULL);
- unode->grid_hidden = MEM_mapallocN(sizeof(*unode->grid_hidden) * totgrid,
- "unode->grid_hidden");
+ unode->grid_hidden = MEM_mapallocN(sizeof(*unode->grid_hidden) * totgrid, "unode->grid_hidden");
- for (i = 0; i < totgrid; i++) {
- if (grid_hidden[grid_indices[i]])
- unode->grid_hidden[i] = MEM_dupallocN(grid_hidden[grid_indices[i]]);
- else
- unode->grid_hidden[i] = NULL;
- }
+ for (i = 0; i < totgrid; i++) {
+ if (grid_hidden[grid_indices[i]])
+ unode->grid_hidden[i] = MEM_dupallocN(grid_hidden[grid_indices[i]]);
+ else
+ unode->grid_hidden[i] = NULL;
+ }
}
-static SculptUndoNode *sculpt_undo_alloc_node(
- Object *ob, PBVHNode *node,
- SculptUndoType type)
+static SculptUndoNode *sculpt_undo_alloc_node(Object *ob, PBVHNode *node, SculptUndoType type)
{
- UndoSculpt *usculpt = sculpt_undo_get_nodes();
- SculptUndoNode *unode;
- SculptSession *ss = ob->sculpt;
- int totvert, allvert, totgrid, maxgrid, gridsize, *grids;
-
- unode = MEM_callocN(sizeof(SculptUndoNode), "SculptUndoNode");
- BLI_strncpy(unode->idname, ob->id.name, sizeof(unode->idname));
- unode->type = type;
- unode->node = node;
-
- if (node) {
- BKE_pbvh_node_num_verts(ss->pbvh, node, &totvert, &allvert);
- BKE_pbvh_node_get_grids(ss->pbvh, node, &grids, &totgrid,
- &maxgrid, &gridsize, NULL);
-
- unode->totvert = totvert;
- }
- else
- maxgrid = 0;
-
- /* we will use this while sculpting, is mapalloc slow to access then? */
-
- /* general TODO, fix count_alloc */
- switch (type) {
- case SCULPT_UNDO_COORDS:
- unode->co = MEM_mapallocN(sizeof(float[3]) * allvert, "SculptUndoNode.co");
- unode->no = MEM_mapallocN(sizeof(short[3]) * allvert, "SculptUndoNode.no");
-
- usculpt->undo_size = (sizeof(float[3]) + sizeof(short[3]) + sizeof(int)) * allvert;
- break;
- case SCULPT_UNDO_HIDDEN:
- if (maxgrid)
- sculpt_undo_alloc_and_store_hidden(ss->pbvh, unode);
- else
- unode->vert_hidden = BLI_BITMAP_NEW(allvert, "SculptUndoNode.vert_hidden");
-
- break;
- case SCULPT_UNDO_MASK:
- unode->mask = MEM_mapallocN(sizeof(float) * allvert, "SculptUndoNode.mask");
-
- usculpt->undo_size += (sizeof(float) * sizeof(int)) * allvert;
-
- break;
- case SCULPT_UNDO_DYNTOPO_BEGIN:
- case SCULPT_UNDO_DYNTOPO_END:
- case SCULPT_UNDO_DYNTOPO_SYMMETRIZE:
- BLI_assert(!"Dynamic topology should've already been handled");
- break;
- }
-
- BLI_addtail(&usculpt->nodes, unode);
-
- if (maxgrid) {
- /* multires */
- unode->maxgrid = maxgrid;
- unode->totgrid = totgrid;
- unode->gridsize = gridsize;
- unode->grids = MEM_mapallocN(sizeof(int) * totgrid, "SculptUndoNode.grids");
- }
- else {
- /* regular mesh */
- unode->maxvert = ss->totvert;
- unode->index = MEM_mapallocN(sizeof(int) * allvert, "SculptUndoNode.index");
- }
-
- if (ss->modifiers_active)
- unode->orig_co = MEM_callocN(allvert * sizeof(*unode->orig_co), "undoSculpt orig_cos");
-
- return unode;
+ UndoSculpt *usculpt = sculpt_undo_get_nodes();
+ SculptUndoNode *unode;
+ SculptSession *ss = ob->sculpt;
+ int totvert, allvert, totgrid, maxgrid, gridsize, *grids;
+
+ unode = MEM_callocN(sizeof(SculptUndoNode), "SculptUndoNode");
+ BLI_strncpy(unode->idname, ob->id.name, sizeof(unode->idname));
+ unode->type = type;
+ unode->node = node;
+
+ if (node) {
+ BKE_pbvh_node_num_verts(ss->pbvh, node, &totvert, &allvert);
+ BKE_pbvh_node_get_grids(ss->pbvh, node, &grids, &totgrid, &maxgrid, &gridsize, NULL);
+
+ unode->totvert = totvert;
+ }
+ else
+ maxgrid = 0;
+
+ /* we will use this while sculpting, is mapalloc slow to access then? */
+
+ /* general TODO, fix count_alloc */
+ switch (type) {
+ case SCULPT_UNDO_COORDS:
+ unode->co = MEM_mapallocN(sizeof(float[3]) * allvert, "SculptUndoNode.co");
+ unode->no = MEM_mapallocN(sizeof(short[3]) * allvert, "SculptUndoNode.no");
+
+ usculpt->undo_size = (sizeof(float[3]) + sizeof(short[3]) + sizeof(int)) * allvert;
+ break;
+ case SCULPT_UNDO_HIDDEN:
+ if (maxgrid)
+ sculpt_undo_alloc_and_store_hidden(ss->pbvh, unode);
+ else
+ unode->vert_hidden = BLI_BITMAP_NEW(allvert, "SculptUndoNode.vert_hidden");
+
+ break;
+ case SCULPT_UNDO_MASK:
+ unode->mask = MEM_mapallocN(sizeof(float) * allvert, "SculptUndoNode.mask");
+
+ usculpt->undo_size += (sizeof(float) * sizeof(int)) * allvert;
+
+ break;
+ case SCULPT_UNDO_DYNTOPO_BEGIN:
+ case SCULPT_UNDO_DYNTOPO_END:
+ case SCULPT_UNDO_DYNTOPO_SYMMETRIZE:
+ BLI_assert(!"Dynamic topology should've already been handled");
+ break;
+ }
+
+ BLI_addtail(&usculpt->nodes, unode);
+
+ if (maxgrid) {
+ /* multires */
+ unode->maxgrid = maxgrid;
+ unode->totgrid = totgrid;
+ unode->gridsize = gridsize;
+ unode->grids = MEM_mapallocN(sizeof(int) * totgrid, "SculptUndoNode.grids");
+ }
+ else {
+ /* regular mesh */
+ unode->maxvert = ss->totvert;
+ unode->index = MEM_mapallocN(sizeof(int) * allvert, "SculptUndoNode.index");
+ }
+
+ if (ss->modifiers_active)
+ unode->orig_co = MEM_callocN(allvert * sizeof(*unode->orig_co), "undoSculpt orig_cos");
+
+ return unode;
}
static void sculpt_undo_store_coords(Object *ob, SculptUndoNode *unode)
{
- SculptSession *ss = ob->sculpt;
- PBVHVertexIter vd;
-
- BKE_pbvh_vertex_iter_begin(ss->pbvh, unode->node, vd, PBVH_ITER_ALL)
- {
- copy_v3_v3(unode->co[vd.i], vd.co);
- if (vd.no) copy_v3_v3_short(unode->no[vd.i], vd.no);
- else normal_float_to_short_v3(unode->no[vd.i], vd.fno);
-
- if (ss->modifiers_active)
- copy_v3_v3(unode->orig_co[vd.i], ss->orig_cos[unode->index[vd.i]]);
- }
- BKE_pbvh_vertex_iter_end;
+ SculptSession *ss = ob->sculpt;
+ PBVHVertexIter vd;
+
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, unode->node, vd, PBVH_ITER_ALL)
+ {
+ copy_v3_v3(unode->co[vd.i], vd.co);
+ if (vd.no)
+ copy_v3_v3_short(unode->no[vd.i], vd.no);
+ else
+ normal_float_to_short_v3(unode->no[vd.i], vd.fno);
+
+ if (ss->modifiers_active)
+ copy_v3_v3(unode->orig_co[vd.i], ss->orig_cos[unode->index[vd.i]]);
+ }
+ BKE_pbvh_vertex_iter_end;
}
static void sculpt_undo_store_hidden(Object *ob, SculptUndoNode *unode)
{
- PBVH *pbvh = ob->sculpt->pbvh;
- PBVHNode *node = unode->node;
-
- if (unode->grids) {
- /* already stored during allocation */
- }
- else {
- MVert *mvert;
- const int *vert_indices;
- int allvert;
- int i;
-
- BKE_pbvh_node_num_verts(pbvh, node, NULL, &allvert);
- BKE_pbvh_node_get_verts(pbvh, node, &vert_indices, &mvert);
- for (i = 0; i < allvert; i++) {
- BLI_BITMAP_SET(unode->vert_hidden, i,
- mvert[vert_indices[i]].flag & ME_HIDE);
- }
- }
+ PBVH *pbvh = ob->sculpt->pbvh;
+ PBVHNode *node = unode->node;
+
+ if (unode->grids) {
+ /* already stored during allocation */
+ }
+ else {
+ MVert *mvert;
+ const int *vert_indices;
+ int allvert;
+ int i;
+
+ BKE_pbvh_node_num_verts(pbvh, node, NULL, &allvert);
+ BKE_pbvh_node_get_verts(pbvh, node, &vert_indices, &mvert);
+ for (i = 0; i < allvert; i++) {
+ BLI_BITMAP_SET(unode->vert_hidden, i, mvert[vert_indices[i]].flag & ME_HIDE);
+ }
+ }
}
static void sculpt_undo_store_mask(Object *ob, SculptUndoNode *unode)
{
- SculptSession *ss = ob->sculpt;
- PBVHVertexIter vd;
-
- BKE_pbvh_vertex_iter_begin(ss->pbvh, unode->node, vd, PBVH_ITER_ALL)
- {
- unode->mask[vd.i] = *vd.mask;
- }
- BKE_pbvh_vertex_iter_end;
+ SculptSession *ss = ob->sculpt;
+ PBVHVertexIter vd;
+
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, unode->node, vd, PBVH_ITER_ALL)
+ {
+ unode->mask[vd.i] = *vd.mask;
+ }
+ BKE_pbvh_vertex_iter_end;
}
-static SculptUndoNode *sculpt_undo_bmesh_push(Object *ob,
- PBVHNode *node,
- SculptUndoType type)
+static SculptUndoNode *sculpt_undo_bmesh_push(Object *ob, PBVHNode *node, SculptUndoType type)
{
- UndoSculpt *usculpt = sculpt_undo_get_nodes();
- SculptSession *ss = ob->sculpt;
- PBVHVertexIter vd;
-
- SculptUndoNode *unode = usculpt->nodes.first;
-
- if (unode == NULL) {
- unode = MEM_callocN(sizeof(*unode), __func__);
-
- BLI_strncpy(unode->idname, ob->id.name, sizeof(unode->idname));
- unode->type = type;
- unode->applied = true;
-
- if (type == SCULPT_UNDO_DYNTOPO_END) {
- unode->bm_entry = BM_log_entry_add(ss->bm_log);
- BM_log_before_all_removed(ss->bm, ss->bm_log);
- }
- else if (type == SCULPT_UNDO_DYNTOPO_BEGIN) {
- Mesh *me = ob->data;
-
- /* Store a copy of the mesh's current vertices, loops, and
- * polys. A full copy like this is needed because entering
- * dynamic-topology immediately does topological edits
- * (converting polys to triangles) that the BMLog can't
- * fully restore from */
- CustomData_copy(&me->vdata, &unode->bm_enter_vdata, CD_MASK_MESH.vmask,
- CD_DUPLICATE, me->totvert);
- CustomData_copy(&me->edata, &unode->bm_enter_edata, CD_MASK_MESH.emask,
- CD_DUPLICATE, me->totedge);
- CustomData_copy(&me->ldata, &unode->bm_enter_ldata, CD_MASK_MESH.lmask,
- CD_DUPLICATE, me->totloop);
- CustomData_copy(&me->pdata, &unode->bm_enter_pdata, CD_MASK_MESH.pmask,
- CD_DUPLICATE, me->totpoly);
- unode->bm_enter_totvert = me->totvert;
- unode->bm_enter_totedge = me->totedge;
- unode->bm_enter_totloop = me->totloop;
- unode->bm_enter_totpoly = me->totpoly;
-
- unode->bm_entry = BM_log_entry_add(ss->bm_log);
- BM_log_all_added(ss->bm, ss->bm_log);
- }
- else {
- unode->bm_entry = BM_log_entry_add(ss->bm_log);
- }
-
- BLI_addtail(&usculpt->nodes, unode);
- }
-
- if (node) {
- switch (type) {
- case SCULPT_UNDO_COORDS:
- case SCULPT_UNDO_MASK:
- /* Before any vertex values get modified, ensure their
- * original positions are logged */
- BKE_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_ALL) {
- BM_log_vert_before_modified(ss->bm_log, vd.bm_vert, vd.cd_vert_mask_offset);
- }
- BKE_pbvh_vertex_iter_end;
- break;
-
- case SCULPT_UNDO_HIDDEN:
- {
- GSetIterator gs_iter;
- GSet *faces = BKE_pbvh_bmesh_node_faces(node);
- BKE_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_ALL) {
- BM_log_vert_before_modified(ss->bm_log, vd.bm_vert, vd.cd_vert_mask_offset);
- }
- BKE_pbvh_vertex_iter_end;
-
- GSET_ITER (gs_iter, faces) {
- BMFace *f = BLI_gsetIterator_getKey(&gs_iter);
- BM_log_face_modified(ss->bm_log, f);
- }
- break;
- }
-
- case SCULPT_UNDO_DYNTOPO_BEGIN:
- case SCULPT_UNDO_DYNTOPO_END:
- case SCULPT_UNDO_DYNTOPO_SYMMETRIZE:
- break;
- }
- }
-
- return unode;
+ UndoSculpt *usculpt = sculpt_undo_get_nodes();
+ SculptSession *ss = ob->sculpt;
+ PBVHVertexIter vd;
+
+ SculptUndoNode *unode = usculpt->nodes.first;
+
+ if (unode == NULL) {
+ unode = MEM_callocN(sizeof(*unode), __func__);
+
+ BLI_strncpy(unode->idname, ob->id.name, sizeof(unode->idname));
+ unode->type = type;
+ unode->applied = true;
+
+ if (type == SCULPT_UNDO_DYNTOPO_END) {
+ unode->bm_entry = BM_log_entry_add(ss->bm_log);
+ BM_log_before_all_removed(ss->bm, ss->bm_log);
+ }
+ else if (type == SCULPT_UNDO_DYNTOPO_BEGIN) {
+ Mesh *me = ob->data;
+
+ /* Store a copy of the mesh's current vertices, loops, and
+ * polys. A full copy like this is needed because entering
+ * dynamic-topology immediately does topological edits
+ * (converting polys to triangles) that the BMLog can't
+ * fully restore from */
+ CustomData_copy(
+ &me->vdata, &unode->bm_enter_vdata, CD_MASK_MESH.vmask, CD_DUPLICATE, me->totvert);
+ CustomData_copy(
+ &me->edata, &unode->bm_enter_edata, CD_MASK_MESH.emask, CD_DUPLICATE, me->totedge);
+ CustomData_copy(
+ &me->ldata, &unode->bm_enter_ldata, CD_MASK_MESH.lmask, CD_DUPLICATE, me->totloop);
+ CustomData_copy(
+ &me->pdata, &unode->bm_enter_pdata, CD_MASK_MESH.pmask, CD_DUPLICATE, me->totpoly);
+ unode->bm_enter_totvert = me->totvert;
+ unode->bm_enter_totedge = me->totedge;
+ unode->bm_enter_totloop = me->totloop;
+ unode->bm_enter_totpoly = me->totpoly;
+
+ unode->bm_entry = BM_log_entry_add(ss->bm_log);
+ BM_log_all_added(ss->bm, ss->bm_log);
+ }
+ else {
+ unode->bm_entry = BM_log_entry_add(ss->bm_log);
+ }
+
+ BLI_addtail(&usculpt->nodes, unode);
+ }
+
+ if (node) {
+ switch (type) {
+ case SCULPT_UNDO_COORDS:
+ case SCULPT_UNDO_MASK:
+ /* Before any vertex values get modified, ensure their
+ * original positions are logged */
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_ALL)
+ {
+ BM_log_vert_before_modified(ss->bm_log, vd.bm_vert, vd.cd_vert_mask_offset);
+ }
+ BKE_pbvh_vertex_iter_end;
+ break;
+
+ case SCULPT_UNDO_HIDDEN: {
+ GSetIterator gs_iter;
+ GSet *faces = BKE_pbvh_bmesh_node_faces(node);
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_ALL)
+ {
+ BM_log_vert_before_modified(ss->bm_log, vd.bm_vert, vd.cd_vert_mask_offset);
+ }
+ BKE_pbvh_vertex_iter_end;
+
+ GSET_ITER (gs_iter, faces) {
+ BMFace *f = BLI_gsetIterator_getKey(&gs_iter);
+ BM_log_face_modified(ss->bm_log, f);
+ }
+ break;
+ }
+
+ case SCULPT_UNDO_DYNTOPO_BEGIN:
+ case SCULPT_UNDO_DYNTOPO_END:
+ case SCULPT_UNDO_DYNTOPO_SYMMETRIZE:
+ break;
+ }
+ }
+
+ return unode;
}
-SculptUndoNode *sculpt_undo_push_node(
- Object *ob, PBVHNode *node,
- SculptUndoType type)
+SculptUndoNode *sculpt_undo_push_node(Object *ob, PBVHNode *node, SculptUndoType type)
{
- SculptSession *ss = ob->sculpt;
- SculptUndoNode *unode;
-
- /* list is manipulated by multiple threads, so we lock */
- BLI_thread_lock(LOCK_CUSTOM1);
-
- if (ss->bm ||
- ELEM(type,
- SCULPT_UNDO_DYNTOPO_BEGIN,
- SCULPT_UNDO_DYNTOPO_END))
- {
- /* Dynamic topology stores only one undo node per stroke,
- * regardless of the number of PBVH nodes modified */
- unode = sculpt_undo_bmesh_push(ob, node, type);
- BLI_thread_unlock(LOCK_CUSTOM1);
- return unode;
- }
- else if ((unode = sculpt_undo_get_node(node))) {
- BLI_thread_unlock(LOCK_CUSTOM1);
- return unode;
- }
-
- unode = sculpt_undo_alloc_node(ob, node, type);
-
- /* NOTE: If this ever becomes a bottleneck, make a lock inside of the node.
- * so we release global lock sooner, but keep data locked for until it is
- * fully initialized.
- */
-
- if (unode->grids) {
- int totgrid, *grids;
- BKE_pbvh_node_get_grids(ss->pbvh, node, &grids, &totgrid,
- NULL, NULL, NULL);
- memcpy(unode->grids, grids, sizeof(int) * totgrid);
- }
- else {
- const int *vert_indices;
- int allvert;
- BKE_pbvh_node_num_verts(ss->pbvh, node, NULL, &allvert);
- BKE_pbvh_node_get_verts(ss->pbvh, node, &vert_indices, NULL);
- memcpy(unode->index, vert_indices, sizeof(int) * unode->totvert);
- }
-
- switch (type) {
- case SCULPT_UNDO_COORDS:
- sculpt_undo_store_coords(ob, unode);
- break;
- case SCULPT_UNDO_HIDDEN:
- sculpt_undo_store_hidden(ob, unode);
- break;
- case SCULPT_UNDO_MASK:
- sculpt_undo_store_mask(ob, unode);
- break;
- case SCULPT_UNDO_DYNTOPO_BEGIN:
- case SCULPT_UNDO_DYNTOPO_END:
- case SCULPT_UNDO_DYNTOPO_SYMMETRIZE:
- BLI_assert(!"Dynamic topology should've already been handled");
- break;
- }
-
- /* store active shape key */
- if (ss->kb) BLI_strncpy(unode->shapeName, ss->kb->name, sizeof(ss->kb->name));
- else unode->shapeName[0] = '\0';
-
- BLI_thread_unlock(LOCK_CUSTOM1);
-
- return unode;
+ SculptSession *ss = ob->sculpt;
+ SculptUndoNode *unode;
+
+ /* list is manipulated by multiple threads, so we lock */
+ BLI_thread_lock(LOCK_CUSTOM1);
+
+ if (ss->bm || ELEM(type, SCULPT_UNDO_DYNTOPO_BEGIN, SCULPT_UNDO_DYNTOPO_END)) {
+ /* Dynamic topology stores only one undo node per stroke,
+ * regardless of the number of PBVH nodes modified */
+ unode = sculpt_undo_bmesh_push(ob, node, type);
+ BLI_thread_unlock(LOCK_CUSTOM1);
+ return unode;
+ }
+ else if ((unode = sculpt_undo_get_node(node))) {
+ BLI_thread_unlock(LOCK_CUSTOM1);
+ return unode;
+ }
+
+ unode = sculpt_undo_alloc_node(ob, node, type);
+
+ /* NOTE: If this ever becomes a bottleneck, make a lock inside of the node.
+ * so we release global lock sooner, but keep data locked for until it is
+ * fully initialized.
+ */
+
+ if (unode->grids) {
+ int totgrid, *grids;
+ BKE_pbvh_node_get_grids(ss->pbvh, node, &grids, &totgrid, NULL, NULL, NULL);
+ memcpy(unode->grids, grids, sizeof(int) * totgrid);
+ }
+ else {
+ const int *vert_indices;
+ int allvert;
+ BKE_pbvh_node_num_verts(ss->pbvh, node, NULL, &allvert);
+ BKE_pbvh_node_get_verts(ss->pbvh, node, &vert_indices, NULL);
+ memcpy(unode->index, vert_indices, sizeof(int) * unode->totvert);
+ }
+
+ switch (type) {
+ case SCULPT_UNDO_COORDS:
+ sculpt_undo_store_coords(ob, unode);
+ break;
+ case SCULPT_UNDO_HIDDEN:
+ sculpt_undo_store_hidden(ob, unode);
+ break;
+ case SCULPT_UNDO_MASK:
+ sculpt_undo_store_mask(ob, unode);
+ break;
+ case SCULPT_UNDO_DYNTOPO_BEGIN:
+ case SCULPT_UNDO_DYNTOPO_END:
+ case SCULPT_UNDO_DYNTOPO_SYMMETRIZE:
+ BLI_assert(!"Dynamic topology should've already been handled");
+ break;
+ }
+
+ /* store active shape key */
+ if (ss->kb)
+ BLI_strncpy(unode->shapeName, ss->kb->name, sizeof(ss->kb->name));
+ else
+ unode->shapeName[0] = '\0';
+
+ BLI_thread_unlock(LOCK_CUSTOM1);
+
+ return unode;
}
void sculpt_undo_push_begin(const char *name)
{
- UndoStack *ustack = ED_undo_stack_get();
- bContext *C = NULL; /* special case, we never read from this. */
- BKE_undosys_step_push_init_with_type(ustack, C, name, BKE_UNDOSYS_TYPE_SCULPT);
+ UndoStack *ustack = ED_undo_stack_get();
+ bContext *C = NULL; /* special case, we never read from this. */
+ BKE_undosys_step_push_init_with_type(ustack, C, name, BKE_UNDOSYS_TYPE_SCULPT);
}
void sculpt_undo_push_end(void)
{
- UndoSculpt *usculpt = sculpt_undo_get_nodes();
- SculptUndoNode *unode;
-
- /* we don't need normals in the undo stack */
- for (unode = usculpt->nodes.first; unode; unode = unode->next) {
- if (unode->no) {
- MEM_freeN(unode->no);
- unode->no = NULL;
- }
-
- if (unode->node)
- BKE_pbvh_node_layer_disp_free(unode->node);
- }
-
- /* We could remove this and enforce all callers run in an operator using 'OPTYPE_UNDO'. */
- wmWindowManager *wm = G_MAIN->wm.first;
- if (wm->op_undo_depth == 0) {
- UndoStack *ustack = ED_undo_stack_get();
- BKE_undosys_step_push(ustack, NULL, NULL);
- }
+ UndoSculpt *usculpt = sculpt_undo_get_nodes();
+ SculptUndoNode *unode;
+
+ /* we don't need normals in the undo stack */
+ for (unode = usculpt->nodes.first; unode; unode = unode->next) {
+ if (unode->no) {
+ MEM_freeN(unode->no);
+ unode->no = NULL;
+ }
+
+ if (unode->node)
+ BKE_pbvh_node_layer_disp_free(unode->node);
+ }
+
+ /* We could remove this and enforce all callers run in an operator using 'OPTYPE_UNDO'. */
+ wmWindowManager *wm = G_MAIN->wm.first;
+ if (wm->op_undo_depth == 0) {
+ UndoStack *ustack = ED_undo_stack_get();
+ BKE_undosys_step_push(ustack, NULL, NULL);
+ }
}
/* -------------------------------------------------------------------- */
@@ -1015,149 +990,154 @@ void sculpt_undo_push_end(void)
* \{ */
typedef struct SculptUndoStep {
- UndoStep step;
- /* note: will split out into list for multi-object-sculpt-mode. */
- UndoSculpt data;
+ UndoStep step;
+ /* note: will split out into list for multi-object-sculpt-mode. */
+ UndoSculpt data;
} SculptUndoStep;
static bool sculpt_undosys_poll(bContext *C)
{
- Object *obact = CTX_data_active_object(C);
- if (obact && obact->type == OB_MESH) {
- if (obact && (obact->mode & OB_MODE_SCULPT)) {
- return true;
- }
- }
- return false;
+ Object *obact = CTX_data_active_object(C);
+ if (obact && obact->type == OB_MESH) {
+ if (obact && (obact->mode & OB_MODE_SCULPT)) {
+ return true;
+ }
+ }
+ return false;
}
static void sculpt_undosys_step_encode_init(struct bContext *UNUSED(C), UndoStep *us_p)
{
- SculptUndoStep *us = (SculptUndoStep *)us_p;
- /* dummy, memory is cleared anyway. */
- BLI_listbase_clear(&us->data.nodes);
+ SculptUndoStep *us = (SculptUndoStep *)us_p;
+ /* dummy, memory is cleared anyway. */
+ BLI_listbase_clear(&us->data.nodes);
}
-static bool sculpt_undosys_step_encode(struct bContext *UNUSED(C), struct Main *UNUSED(bmain), UndoStep *us_p)
+static bool sculpt_undosys_step_encode(struct bContext *UNUSED(C),
+ struct Main *UNUSED(bmain),
+ UndoStep *us_p)
{
- /* dummy, encoding is done along the way by adding tiles
- * to the current 'SculptUndoStep' added by encode_init. */
- SculptUndoStep *us = (SculptUndoStep *)us_p;
- us->step.data_size = us->data.undo_size;
-
- SculptUndoNode *unode = us->data.nodes.last;
- if (unode && unode->type == SCULPT_UNDO_DYNTOPO_END) {
- us->step.use_memfile_step = true;
- }
- us->step.is_applied = true;
- return true;
+ /* dummy, encoding is done along the way by adding tiles
+ * to the current 'SculptUndoStep' added by encode_init. */
+ SculptUndoStep *us = (SculptUndoStep *)us_p;
+ us->step.data_size = us->data.undo_size;
+
+ SculptUndoNode *unode = us->data.nodes.last;
+ if (unode && unode->type == SCULPT_UNDO_DYNTOPO_END) {
+ us->step.use_memfile_step = true;
+ }
+ us->step.is_applied = true;
+ return true;
}
static void sculpt_undosys_step_decode_undo_impl(struct bContext *C, SculptUndoStep *us)
{
- BLI_assert(us->step.is_applied == true);
- sculpt_undo_restore_list(C, &us->data.nodes);
- us->step.is_applied = false;
+ BLI_assert(us->step.is_applied == true);
+ sculpt_undo_restore_list(C, &us->data.nodes);
+ us->step.is_applied = false;
}
static void sculpt_undosys_step_decode_redo_impl(struct bContext *C, SculptUndoStep *us)
{
- BLI_assert(us->step.is_applied == false);
- sculpt_undo_restore_list(C, &us->data.nodes);
- us->step.is_applied = true;
+ BLI_assert(us->step.is_applied == false);
+ sculpt_undo_restore_list(C, &us->data.nodes);
+ us->step.is_applied = true;
}
static void sculpt_undosys_step_decode_undo(struct bContext *C, SculptUndoStep *us)
{
- SculptUndoStep *us_iter = us;
- while (us_iter->step.next && (us_iter->step.next->type == us_iter->step.type)) {
- if (us_iter->step.next->is_applied == false) {
- break;
- }
- us_iter = (SculptUndoStep *)us_iter->step.next;
- }
- while (us_iter != us) {
- sculpt_undosys_step_decode_undo_impl(C, us_iter);
- us_iter = (SculptUndoStep *)us_iter->step.prev;
- }
+ SculptUndoStep *us_iter = us;
+ while (us_iter->step.next && (us_iter->step.next->type == us_iter->step.type)) {
+ if (us_iter->step.next->is_applied == false) {
+ break;
+ }
+ us_iter = (SculptUndoStep *)us_iter->step.next;
+ }
+ while (us_iter != us) {
+ sculpt_undosys_step_decode_undo_impl(C, us_iter);
+ us_iter = (SculptUndoStep *)us_iter->step.prev;
+ }
}
static void sculpt_undosys_step_decode_redo(struct bContext *C, SculptUndoStep *us)
{
- SculptUndoStep *us_iter = us;
- while (us_iter->step.prev && (us_iter->step.prev->type == us_iter->step.type)) {
- if (us_iter->step.prev->is_applied == true) {
- break;
- }
- us_iter = (SculptUndoStep *)us_iter->step.prev;
- }
- while (us_iter && (us_iter->step.is_applied == false)) {
- sculpt_undosys_step_decode_redo_impl(C, us_iter);
- if (us_iter == us) {
- break;
- }
- us_iter = (SculptUndoStep *)us_iter->step.next;
- }
+ SculptUndoStep *us_iter = us;
+ while (us_iter->step.prev && (us_iter->step.prev->type == us_iter->step.type)) {
+ if (us_iter->step.prev->is_applied == true) {
+ break;
+ }
+ us_iter = (SculptUndoStep *)us_iter->step.prev;
+ }
+ while (us_iter && (us_iter->step.is_applied == false)) {
+ sculpt_undosys_step_decode_redo_impl(C, us_iter);
+ if (us_iter == us) {
+ break;
+ }
+ us_iter = (SculptUndoStep *)us_iter->step.next;
+ }
}
-static void sculpt_undosys_step_decode(struct bContext *C, struct Main *bmain, UndoStep *us_p, int dir)
+static void sculpt_undosys_step_decode(struct bContext *C,
+ struct Main *bmain,
+ UndoStep *us_p,
+ int dir)
{
- /* Ensure sculpt mode. */
- {
- Scene *scene = CTX_data_scene(C);
- ViewLayer *view_layer = CTX_data_view_layer(C);
- /* Sculpt needs evaluated state. */
- BKE_scene_view_layer_graph_evaluated_ensure(bmain, scene, view_layer);
- Object *ob = OBACT(view_layer);
- if (ob && (ob->type == OB_MESH)) {
- Depsgraph *depsgraph = CTX_data_depsgraph(C);
- if (ob->mode & OB_MODE_SCULPT) {
- /* pass */
- }
- else {
- ED_object_mode_generic_exit(bmain, depsgraph, scene, ob);
- Mesh *me = ob->data;
- /* Don't add sculpt topology undo steps when reading back undo state.
- * The undo steps must enter/exit for us. */
- me->flag &= ~ME_SCULPT_DYNAMIC_TOPOLOGY;
- ED_object_sculptmode_enter_ex(bmain, depsgraph, scene, ob, true, NULL);
- }
- BLI_assert(sculpt_undosys_poll(C));
- }
- else {
- BLI_assert(0);
- return;
- }
- }
-
- SculptUndoStep *us = (SculptUndoStep *)us_p;
- if (dir < 0) {
- sculpt_undosys_step_decode_undo(C, us);
- }
- else {
- sculpt_undosys_step_decode_redo(C, us);
- }
+ /* Ensure sculpt mode. */
+ {
+ Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ /* Sculpt needs evaluated state. */
+ BKE_scene_view_layer_graph_evaluated_ensure(bmain, scene, view_layer);
+ Object *ob = OBACT(view_layer);
+ if (ob && (ob->type == OB_MESH)) {
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ if (ob->mode & OB_MODE_SCULPT) {
+ /* pass */
+ }
+ else {
+ ED_object_mode_generic_exit(bmain, depsgraph, scene, ob);
+ Mesh *me = ob->data;
+ /* Don't add sculpt topology undo steps when reading back undo state.
+ * The undo steps must enter/exit for us. */
+ me->flag &= ~ME_SCULPT_DYNAMIC_TOPOLOGY;
+ ED_object_sculptmode_enter_ex(bmain, depsgraph, scene, ob, true, NULL);
+ }
+ BLI_assert(sculpt_undosys_poll(C));
+ }
+ else {
+ BLI_assert(0);
+ return;
+ }
+ }
+
+ SculptUndoStep *us = (SculptUndoStep *)us_p;
+ if (dir < 0) {
+ sculpt_undosys_step_decode_undo(C, us);
+ }
+ else {
+ sculpt_undosys_step_decode_redo(C, us);
+ }
}
static void sculpt_undosys_step_free(UndoStep *us_p)
{
- SculptUndoStep *us = (SculptUndoStep *)us_p;
- sculpt_undo_free_list(&us->data.nodes);
+ SculptUndoStep *us = (SculptUndoStep *)us_p;
+ sculpt_undo_free_list(&us->data.nodes);
}
/* Export for ED_undo_sys. */
void ED_sculpt_undosys_type(UndoType *ut)
{
- ut->name = "Sculpt";
- ut->poll = sculpt_undosys_poll;
- ut->step_encode_init = sculpt_undosys_step_encode_init;
- ut->step_encode = sculpt_undosys_step_encode;
- ut->step_decode = sculpt_undosys_step_decode;
- ut->step_free = sculpt_undosys_step_free;
+ ut->name = "Sculpt";
+ ut->poll = sculpt_undosys_poll;
+ ut->step_encode_init = sculpt_undosys_step_encode_init;
+ ut->step_encode = sculpt_undosys_step_encode;
+ ut->step_decode = sculpt_undosys_step_decode;
+ ut->step_free = sculpt_undosys_step_free;
- ut->use_context = true;
+ ut->use_context = true;
- ut->step_size = sizeof(SculptUndoStep);
+ ut->step_size = sizeof(SculptUndoStep);
}
/** \} */
@@ -1168,15 +1148,15 @@ void ED_sculpt_undosys_type(UndoType *ut)
static UndoSculpt *sculpt_undosys_step_get_nodes(UndoStep *us_p)
{
- SculptUndoStep *us = (SculptUndoStep *)us_p;
- return &us->data;
+ SculptUndoStep *us = (SculptUndoStep *)us_p;
+ return &us->data;
}
static UndoSculpt *sculpt_undo_get_nodes(void)
{
- UndoStack *ustack = ED_undo_stack_get();
- UndoStep *us = BKE_undosys_stack_init_or_active_with_type(ustack, BKE_UNDOSYS_TYPE_SCULPT);
- return sculpt_undosys_step_get_nodes(us);
+ UndoStack *ustack = ED_undo_stack_get();
+ UndoStep *us = BKE_undosys_stack_init_or_active_with_type(ustack, BKE_UNDOSYS_TYPE_SCULPT);
+ return sculpt_undosys_step_get_nodes(us);
}
/** \} */
diff --git a/source/blender/editors/sculpt_paint/sculpt_uv.c b/source/blender/editors/sculpt_paint/sculpt_uv.c
index dde09bb0f45..39ada703b9b 100644
--- a/source/blender/editors/sculpt_paint/sculpt_uv.c
+++ b/source/blender/editors/sculpt_paint/sculpt_uv.c
@@ -22,7 +22,6 @@
* \ingroup edsculpt
*/
-
#include "MEM_guardedalloc.h"
#include "BLI_utildefines.h"
@@ -64,126 +63,123 @@
#include "UI_view2d.h"
-#define MARK_BOUNDARY 1
+#define MARK_BOUNDARY 1
typedef struct UvAdjacencyElement {
- /* pointer to original uvelement */
- UvElement *element;
- /* uv pointer for convenience. Caution, this points to the original UVs! */
- float *uv;
- /* general use flag (Used to check if Element is boundary here) */
- char flag;
+ /* pointer to original uvelement */
+ UvElement *element;
+ /* uv pointer for convenience. Caution, this points to the original UVs! */
+ float *uv;
+ /* general use flag (Used to check if Element is boundary here) */
+ char flag;
} UvAdjacencyElement;
typedef struct UvEdge {
- unsigned int uv1;
- unsigned int uv2;
- /* general use flag
- * (Used to check if edge is boundary here, and propagates to adjacency elements) */
- char flag;
+ unsigned int uv1;
+ unsigned int uv2;
+ /* general use flag
+ * (Used to check if edge is boundary here, and propagates to adjacency elements) */
+ char flag;
} UvEdge;
typedef struct UVInitialStrokeElement {
- /* index to unique uv */
- int uv;
+ /* index to unique uv */
+ int uv;
- /* strength of brush on initial position */
- float strength;
+ /* strength of brush on initial position */
+ float strength;
- /* initial uv position */
- float initial_uv[2];
+ /* initial uv position */
+ float initial_uv[2];
} UVInitialStrokeElement;
typedef struct UVInitialStroke {
- /* Initial Selection,for grab brushes for instance */
- UVInitialStrokeElement *initialSelection;
+ /* Initial Selection,for grab brushes for instance */
+ UVInitialStrokeElement *initialSelection;
- /* total initially selected UVs*/
- int totalInitialSelected;
+ /* total initially selected UVs*/
+ int totalInitialSelected;
- /* initial mouse coordinates */
- float init_coord[2];
+ /* initial mouse coordinates */
+ float init_coord[2];
} UVInitialStroke;
-
/* custom data for uv smoothing brush */
typedef struct UvSculptData {
- /* Contains the first of each set of coincident uvs.
- * These will be used to perform smoothing on and propagate the changes
- * to their coincident uvs */
- UvAdjacencyElement *uv;
+ /* Contains the first of each set of coincident uvs.
+ * These will be used to perform smoothing on and propagate the changes
+ * to their coincident uvs */
+ UvAdjacencyElement *uv;
- /* ...Is what it says */
- int totalUniqueUvs;
+ /* ...Is what it says */
+ int totalUniqueUvs;
- /* Edges used for adjacency info, used with laplacian smoothing */
- UvEdge *uvedges;
+ /* Edges used for adjacency info, used with laplacian smoothing */
+ UvEdge *uvedges;
- /* need I say more? */
- int totalUvEdges;
+ /* need I say more? */
+ int totalUvEdges;
- /* data for initial stroke, used by tools like grab */
- UVInitialStroke *initial_stroke;
+ /* data for initial stroke, used by tools like grab */
+ UVInitialStroke *initial_stroke;
- /* timer to be used for airbrush-type brush */
- wmTimer *timer;
+ /* timer to be used for airbrush-type brush */
+ wmTimer *timer;
- /* to determine quickly adjacent uvs */
- UvElementMap *elementMap;
+ /* to determine quickly adjacent uvs */
+ UvElementMap *elementMap;
- /* uvsmooth Paint for fast reference */
- Paint *uvsculpt;
+ /* uvsmooth Paint for fast reference */
+ Paint *uvsculpt;
- /* tool to use. duplicating here to change if modifier keys are pressed */
- char tool;
+ /* tool to use. duplicating here to change if modifier keys are pressed */
+ char tool;
- /* store invert flag here */
- char invert;
+ /* store invert flag here */
+ char invert;
} UvSculptData;
-
static Brush *uv_sculpt_brush(bContext *C)
{
- Scene *scene = CTX_data_scene(C);
- ToolSettings *settings = scene->toolsettings;
+ Scene *scene = CTX_data_scene(C);
+ ToolSettings *settings = scene->toolsettings;
- if (!settings->uvsculpt)
- return NULL;
- return BKE_paint_brush(&settings->uvsculpt->paint);
+ if (!settings->uvsculpt)
+ return NULL;
+ return BKE_paint_brush(&settings->uvsculpt->paint);
}
-
static bool uv_sculpt_brush_poll_do(bContext *C, const bool check_region)
{
- BMEditMesh *em;
- int ret;
- Object *obedit = CTX_data_edit_object(C);
- SpaceImage *sima = CTX_wm_space_image(C);
- Scene *scene = CTX_data_scene(C);
- ToolSettings *toolsettings = scene->toolsettings;
-
- if (!uv_sculpt_brush(C) || !obedit || obedit->type != OB_MESH ||
- !sima || ED_space_image_show_render(sima) || (sima->mode == SI_MODE_PAINT))
- {
- return 0;
- }
-
- em = BKE_editmesh_from_object(obedit);
- ret = EDBM_uv_check(em);
-
- if (ret) {
- ARegion *ar = CTX_wm_region(C);
- if ((!toolsettings->use_uv_sculpt) || (check_region && ar && (ar->regiontype != RGN_TYPE_WINDOW))) {
- ret = 0;
- }
- }
-
- return ret;
+ BMEditMesh *em;
+ int ret;
+ Object *obedit = CTX_data_edit_object(C);
+ SpaceImage *sima = CTX_wm_space_image(C);
+ Scene *scene = CTX_data_scene(C);
+ ToolSettings *toolsettings = scene->toolsettings;
+
+ if (!uv_sculpt_brush(C) || !obedit || obedit->type != OB_MESH || !sima ||
+ ED_space_image_show_render(sima) || (sima->mode == SI_MODE_PAINT)) {
+ return 0;
+ }
+
+ em = BKE_editmesh_from_object(obedit);
+ ret = EDBM_uv_check(em);
+
+ if (ret) {
+ ARegion *ar = CTX_wm_region(C);
+ if ((!toolsettings->use_uv_sculpt) ||
+ (check_region && ar && (ar->regiontype != RGN_TYPE_WINDOW))) {
+ ret = 0;
+ }
+ }
+
+ return ret;
}
static bool uv_sculpt_brush_poll(bContext *C)
{
- return uv_sculpt_brush_poll_do(C, true);
+ return uv_sculpt_brush_poll_do(C, true);
}
static void brush_drawcursor_uvsculpt(bContext *C, int x, int y, void *UNUSED(customdata))
@@ -191,74 +187,70 @@ static void brush_drawcursor_uvsculpt(bContext *C, int x, int y, void *UNUSED(cu
#define PX_SIZE_FADE_MAX 12.0f
#define PX_SIZE_FADE_MIN 4.0f
- Scene *scene = CTX_data_scene(C);
- //Brush *brush = image_paint_brush(C);
- Paint *paint = BKE_paint_get_active_from_context(C);
- Brush *brush = BKE_paint_brush(paint);
-
- if (paint && brush && paint->flags & PAINT_SHOW_BRUSH) {
- const float size = (float)BKE_brush_size_get(scene, brush);
- float alpha = 0.5f;
-
- /* fade out the brush (cheap trick to work around brush interfering with sampling [#])*/
- if (size < PX_SIZE_FADE_MIN) {
- return;
- }
- else if (size < PX_SIZE_FADE_MAX) {
- alpha *= (size - PX_SIZE_FADE_MIN) / (PX_SIZE_FADE_MAX - PX_SIZE_FADE_MIN);
- }
-
- uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
- immUniformColor3fvAlpha(brush->add_col, alpha);
-
- GPU_line_smooth(true);
- GPU_blend(true);
- imm_draw_circle_wire_2d(pos, (float)x, (float)y, size, 40);
- GPU_blend(false);
- GPU_line_smooth(false);
-
- immUnbindProgram();
- }
+ Scene *scene = CTX_data_scene(C);
+ //Brush *brush = image_paint_brush(C);
+ Paint *paint = BKE_paint_get_active_from_context(C);
+ Brush *brush = BKE_paint_brush(paint);
+
+ if (paint && brush && paint->flags & PAINT_SHOW_BRUSH) {
+ const float size = (float)BKE_brush_size_get(scene, brush);
+ float alpha = 0.5f;
+
+ /* fade out the brush (cheap trick to work around brush interfering with sampling [#])*/
+ if (size < PX_SIZE_FADE_MIN) {
+ return;
+ }
+ else if (size < PX_SIZE_FADE_MAX) {
+ alpha *= (size - PX_SIZE_FADE_MIN) / (PX_SIZE_FADE_MAX - PX_SIZE_FADE_MIN);
+ }
+
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immUniformColor3fvAlpha(brush->add_col, alpha);
+
+ GPU_line_smooth(true);
+ GPU_blend(true);
+ imm_draw_circle_wire_2d(pos, (float)x, (float)y, size, 40);
+ GPU_blend(false);
+ GPU_line_smooth(false);
+
+ immUnbindProgram();
+ }
#undef PX_SIZE_FADE_MAX
#undef PX_SIZE_FADE_MIN
}
-
void ED_space_image_uv_sculpt_update(Main *bmain, wmWindowManager *wm, Scene *scene)
{
- ToolSettings *settings = scene->toolsettings;
- if (settings->use_uv_sculpt) {
- if (settings->uvsculpt == NULL) {
- settings->uv_sculpt_tool = UV_SCULPT_TOOL_GRAB;
- settings->uv_sculpt_settings = UV_SCULPT_LOCK_BORDERS | UV_SCULPT_ALL_ISLANDS;
- settings->uv_relax_method = UV_SCULPT_TOOL_RELAX_LAPLACIAN;
- }
- BKE_paint_ensure(settings, (Paint **)&settings->uvsculpt);
- BKE_paint_init(bmain, scene, PAINT_MODE_SCULPT_UV, PAINT_CURSOR_SCULPT);
-
- settings->uvsculpt->paint.paint_cursor = WM_paint_cursor_activate(
- wm,
- SPACE_IMAGE, RGN_TYPE_WINDOW,
- uv_sculpt_brush_poll,
- brush_drawcursor_uvsculpt, NULL);
- }
- else {
- if (settings->uvsculpt) {
- WM_paint_cursor_end(wm, settings->uvsculpt->paint.paint_cursor);
- settings->uvsculpt->paint.paint_cursor = NULL;
- }
- }
+ ToolSettings *settings = scene->toolsettings;
+ if (settings->use_uv_sculpt) {
+ if (settings->uvsculpt == NULL) {
+ settings->uv_sculpt_tool = UV_SCULPT_TOOL_GRAB;
+ settings->uv_sculpt_settings = UV_SCULPT_LOCK_BORDERS | UV_SCULPT_ALL_ISLANDS;
+ settings->uv_relax_method = UV_SCULPT_TOOL_RELAX_LAPLACIAN;
+ }
+ BKE_paint_ensure(settings, (Paint **)&settings->uvsculpt);
+ BKE_paint_init(bmain, scene, PAINT_MODE_SCULPT_UV, PAINT_CURSOR_SCULPT);
+
+ settings->uvsculpt->paint.paint_cursor = WM_paint_cursor_activate(
+ wm, SPACE_IMAGE, RGN_TYPE_WINDOW, uv_sculpt_brush_poll, brush_drawcursor_uvsculpt, NULL);
+ }
+ else {
+ if (settings->uvsculpt) {
+ WM_paint_cursor_end(wm, settings->uvsculpt->paint.paint_cursor);
+ settings->uvsculpt->paint.paint_cursor = NULL;
+ }
+ }
}
bool uv_sculpt_poll(bContext *C)
{
- return uv_sculpt_brush_poll_do(C, true);
+ return uv_sculpt_brush_poll_do(C, true);
}
bool uv_sculpt_keymap_poll(bContext *C)
{
- return uv_sculpt_brush_poll_do(C, false);
+ return uv_sculpt_brush_poll_do(C, false);
}
/*********** Improved Laplacian Relaxation Operator ************************/
@@ -267,660 +259,692 @@ bool uv_sculpt_keymap_poll(bContext *C)
***************************************************************************/
typedef struct Temp_UvData {
- float sum_co[2], p[2], b[2], sum_b[2];
- int ncounter;
+ float sum_co[2], p[2], b[2], sum_b[2];
+ int ncounter;
} Temp_UVData;
-
-
-static void HC_relaxation_iteration_uv(BMEditMesh *em, UvSculptData *sculptdata, float mouse_coord[2],
- float alpha, float radius, float aspectRatio)
+static void HC_relaxation_iteration_uv(BMEditMesh *em,
+ UvSculptData *sculptdata,
+ float mouse_coord[2],
+ float alpha,
+ float radius,
+ float aspectRatio)
{
- Temp_UVData *tmp_uvdata;
- float diff[2];
- int i;
- float radius_root = sqrtf(radius);
- Brush *brush = BKE_paint_brush(sculptdata->uvsculpt);
-
- tmp_uvdata = (Temp_UVData *)MEM_callocN(sculptdata->totalUniqueUvs * sizeof(Temp_UVData), "Temporal data");
-
- /* counting neighbors */
- for (i = 0; i < sculptdata->totalUvEdges; i++) {
- UvEdge *tmpedge = sculptdata->uvedges + i;
- tmp_uvdata[tmpedge->uv1].ncounter++;
- tmp_uvdata[tmpedge->uv2].ncounter++;
-
- add_v2_v2(tmp_uvdata[tmpedge->uv2].sum_co, sculptdata->uv[tmpedge->uv1].uv);
- add_v2_v2(tmp_uvdata[tmpedge->uv1].sum_co, sculptdata->uv[tmpedge->uv2].uv);
- }
-
- for (i = 0; i < sculptdata->totalUniqueUvs; i++) {
- copy_v2_v2(diff, tmp_uvdata[i].sum_co);
- mul_v2_fl(diff, 1.f / tmp_uvdata[i].ncounter);
- copy_v2_v2(tmp_uvdata[i].p, diff);
-
- tmp_uvdata[i].b[0] = diff[0] - sculptdata->uv[i].uv[0];
- tmp_uvdata[i].b[1] = diff[1] - sculptdata->uv[i].uv[1];
- }
-
- for (i = 0; i < sculptdata->totalUvEdges; i++) {
- UvEdge *tmpedge = sculptdata->uvedges + i;
- add_v2_v2(tmp_uvdata[tmpedge->uv1].sum_b, tmp_uvdata[tmpedge->uv2].b);
- add_v2_v2(tmp_uvdata[tmpedge->uv2].sum_b, tmp_uvdata[tmpedge->uv1].b);
- }
-
- for (i = 0; i < sculptdata->totalUniqueUvs; i++) {
- float dist;
- /* This is supposed to happen only if "Pin Edges" is on, since we have initialization on stroke start
- * If ever uv brushes get their own mode we should check for toolsettings option too */
- if ((sculptdata->uv[i].flag & MARK_BOUNDARY)) {
- continue;
- }
-
- sub_v2_v2v2(diff, sculptdata->uv[i].uv, mouse_coord);
- diff[1] /= aspectRatio;
- if ((dist = dot_v2v2(diff, diff)) <= radius) {
- UvElement *element;
- float strength;
- strength = alpha * BKE_brush_curve_strength_clamped(brush, sqrtf(dist), radius_root);
-
- sculptdata->uv[i].uv[0] = (1.0f - strength) * sculptdata->uv[i].uv[0] + strength * (tmp_uvdata[i].p[0] - 0.5f * (tmp_uvdata[i].b[0] + tmp_uvdata[i].sum_b[0] / tmp_uvdata[i].ncounter));
- sculptdata->uv[i].uv[1] = (1.0f - strength) * sculptdata->uv[i].uv[1] + strength * (tmp_uvdata[i].p[1] - 0.5f * (tmp_uvdata[i].b[1] + tmp_uvdata[i].sum_b[1] / tmp_uvdata[i].ncounter));
-
- for (element = sculptdata->uv[i].element; element; element = element->next) {
- MLoopUV *luv;
- BMLoop *l;
-
- if (element->separate && element != sculptdata->uv[i].element)
- break;
-
- l = element->l;
- luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
- copy_v2_v2(luv->uv, sculptdata->uv[i].uv);
- }
- }
- }
-
- MEM_freeN(tmp_uvdata);
-
- return;
+ Temp_UVData *tmp_uvdata;
+ float diff[2];
+ int i;
+ float radius_root = sqrtf(radius);
+ Brush *brush = BKE_paint_brush(sculptdata->uvsculpt);
+
+ tmp_uvdata = (Temp_UVData *)MEM_callocN(sculptdata->totalUniqueUvs * sizeof(Temp_UVData),
+ "Temporal data");
+
+ /* counting neighbors */
+ for (i = 0; i < sculptdata->totalUvEdges; i++) {
+ UvEdge *tmpedge = sculptdata->uvedges + i;
+ tmp_uvdata[tmpedge->uv1].ncounter++;
+ tmp_uvdata[tmpedge->uv2].ncounter++;
+
+ add_v2_v2(tmp_uvdata[tmpedge->uv2].sum_co, sculptdata->uv[tmpedge->uv1].uv);
+ add_v2_v2(tmp_uvdata[tmpedge->uv1].sum_co, sculptdata->uv[tmpedge->uv2].uv);
+ }
+
+ for (i = 0; i < sculptdata->totalUniqueUvs; i++) {
+ copy_v2_v2(diff, tmp_uvdata[i].sum_co);
+ mul_v2_fl(diff, 1.f / tmp_uvdata[i].ncounter);
+ copy_v2_v2(tmp_uvdata[i].p, diff);
+
+ tmp_uvdata[i].b[0] = diff[0] - sculptdata->uv[i].uv[0];
+ tmp_uvdata[i].b[1] = diff[1] - sculptdata->uv[i].uv[1];
+ }
+
+ for (i = 0; i < sculptdata->totalUvEdges; i++) {
+ UvEdge *tmpedge = sculptdata->uvedges + i;
+ add_v2_v2(tmp_uvdata[tmpedge->uv1].sum_b, tmp_uvdata[tmpedge->uv2].b);
+ add_v2_v2(tmp_uvdata[tmpedge->uv2].sum_b, tmp_uvdata[tmpedge->uv1].b);
+ }
+
+ for (i = 0; i < sculptdata->totalUniqueUvs; i++) {
+ float dist;
+ /* This is supposed to happen only if "Pin Edges" is on, since we have initialization on stroke start
+ * If ever uv brushes get their own mode we should check for toolsettings option too */
+ if ((sculptdata->uv[i].flag & MARK_BOUNDARY)) {
+ continue;
+ }
+
+ sub_v2_v2v2(diff, sculptdata->uv[i].uv, mouse_coord);
+ diff[1] /= aspectRatio;
+ if ((dist = dot_v2v2(diff, diff)) <= radius) {
+ UvElement *element;
+ float strength;
+ strength = alpha * BKE_brush_curve_strength_clamped(brush, sqrtf(dist), radius_root);
+
+ sculptdata->uv[i].uv[0] = (1.0f - strength) * sculptdata->uv[i].uv[0] +
+ strength *
+ (tmp_uvdata[i].p[0] -
+ 0.5f * (tmp_uvdata[i].b[0] +
+ tmp_uvdata[i].sum_b[0] / tmp_uvdata[i].ncounter));
+ sculptdata->uv[i].uv[1] = (1.0f - strength) * sculptdata->uv[i].uv[1] +
+ strength *
+ (tmp_uvdata[i].p[1] -
+ 0.5f * (tmp_uvdata[i].b[1] +
+ tmp_uvdata[i].sum_b[1] / tmp_uvdata[i].ncounter));
+
+ for (element = sculptdata->uv[i].element; element; element = element->next) {
+ MLoopUV *luv;
+ BMLoop *l;
+
+ if (element->separate && element != sculptdata->uv[i].element)
+ break;
+
+ l = element->l;
+ luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
+ copy_v2_v2(luv->uv, sculptdata->uv[i].uv);
+ }
+ }
+ }
+
+ MEM_freeN(tmp_uvdata);
+
+ return;
}
-static void laplacian_relaxation_iteration_uv(BMEditMesh *em, UvSculptData *sculptdata, float mouse_coord[2], float alpha, float radius, float aspectRatio)
+static void laplacian_relaxation_iteration_uv(BMEditMesh *em,
+ UvSculptData *sculptdata,
+ float mouse_coord[2],
+ float alpha,
+ float radius,
+ float aspectRatio)
{
- Temp_UVData *tmp_uvdata;
- float diff[2];
- int i;
- float radius_root = sqrtf(radius);
- Brush *brush = BKE_paint_brush(sculptdata->uvsculpt);
-
- tmp_uvdata = (Temp_UVData *)MEM_callocN(sculptdata->totalUniqueUvs * sizeof(Temp_UVData), "Temporal data");
-
- /* counting neighbors */
- for (i = 0; i < sculptdata->totalUvEdges; i++) {
- UvEdge *tmpedge = sculptdata->uvedges + i;
- tmp_uvdata[tmpedge->uv1].ncounter++;
- tmp_uvdata[tmpedge->uv2].ncounter++;
-
- add_v2_v2(tmp_uvdata[tmpedge->uv2].sum_co, sculptdata->uv[tmpedge->uv1].uv);
- add_v2_v2(tmp_uvdata[tmpedge->uv1].sum_co, sculptdata->uv[tmpedge->uv2].uv);
- }
-
- /* Original Lacplacian algorithm included removal of normal component of translation. here it is not
- * needed since we translate along the UV plane always.*/
- for (i = 0; i < sculptdata->totalUniqueUvs; i++) {
- copy_v2_v2(tmp_uvdata[i].p, tmp_uvdata[i].sum_co);
- mul_v2_fl(tmp_uvdata[i].p, 1.f / tmp_uvdata[i].ncounter);
- }
-
- for (i = 0; i < sculptdata->totalUniqueUvs; i++) {
- float dist;
- /* This is supposed to happen only if "Pin Edges" is on, since we have initialization on stroke start
- * If ever uv brushes get their own mode we should check for toolsettings option too */
- if ((sculptdata->uv[i].flag & MARK_BOUNDARY)) {
- continue;
- }
-
- sub_v2_v2v2(diff, sculptdata->uv[i].uv, mouse_coord);
- diff[1] /= aspectRatio;
- if ((dist = dot_v2v2(diff, diff)) <= radius) {
- UvElement *element;
- float strength;
- strength = alpha * BKE_brush_curve_strength_clamped(brush, sqrtf(dist), radius_root);
-
- sculptdata->uv[i].uv[0] = (1.0f - strength) * sculptdata->uv[i].uv[0] + strength * tmp_uvdata[i].p[0];
- sculptdata->uv[i].uv[1] = (1.0f - strength) * sculptdata->uv[i].uv[1] + strength * tmp_uvdata[i].p[1];
-
- for (element = sculptdata->uv[i].element; element; element = element->next) {
- MLoopUV *luv;
- BMLoop *l;
-
- if (element->separate && element != sculptdata->uv[i].element)
- break;
-
- l = element->l;
- luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
- copy_v2_v2(luv->uv, sculptdata->uv[i].uv);
- }
- }
- }
-
- MEM_freeN(tmp_uvdata);
-
- return;
+ Temp_UVData *tmp_uvdata;
+ float diff[2];
+ int i;
+ float radius_root = sqrtf(radius);
+ Brush *brush = BKE_paint_brush(sculptdata->uvsculpt);
+
+ tmp_uvdata = (Temp_UVData *)MEM_callocN(sculptdata->totalUniqueUvs * sizeof(Temp_UVData),
+ "Temporal data");
+
+ /* counting neighbors */
+ for (i = 0; i < sculptdata->totalUvEdges; i++) {
+ UvEdge *tmpedge = sculptdata->uvedges + i;
+ tmp_uvdata[tmpedge->uv1].ncounter++;
+ tmp_uvdata[tmpedge->uv2].ncounter++;
+
+ add_v2_v2(tmp_uvdata[tmpedge->uv2].sum_co, sculptdata->uv[tmpedge->uv1].uv);
+ add_v2_v2(tmp_uvdata[tmpedge->uv1].sum_co, sculptdata->uv[tmpedge->uv2].uv);
+ }
+
+ /* Original Lacplacian algorithm included removal of normal component of translation. here it is not
+ * needed since we translate along the UV plane always.*/
+ for (i = 0; i < sculptdata->totalUniqueUvs; i++) {
+ copy_v2_v2(tmp_uvdata[i].p, tmp_uvdata[i].sum_co);
+ mul_v2_fl(tmp_uvdata[i].p, 1.f / tmp_uvdata[i].ncounter);
+ }
+
+ for (i = 0; i < sculptdata->totalUniqueUvs; i++) {
+ float dist;
+ /* This is supposed to happen only if "Pin Edges" is on, since we have initialization on stroke start
+ * If ever uv brushes get their own mode we should check for toolsettings option too */
+ if ((sculptdata->uv[i].flag & MARK_BOUNDARY)) {
+ continue;
+ }
+
+ sub_v2_v2v2(diff, sculptdata->uv[i].uv, mouse_coord);
+ diff[1] /= aspectRatio;
+ if ((dist = dot_v2v2(diff, diff)) <= radius) {
+ UvElement *element;
+ float strength;
+ strength = alpha * BKE_brush_curve_strength_clamped(brush, sqrtf(dist), radius_root);
+
+ sculptdata->uv[i].uv[0] = (1.0f - strength) * sculptdata->uv[i].uv[0] +
+ strength * tmp_uvdata[i].p[0];
+ sculptdata->uv[i].uv[1] = (1.0f - strength) * sculptdata->uv[i].uv[1] +
+ strength * tmp_uvdata[i].p[1];
+
+ for (element = sculptdata->uv[i].element; element; element = element->next) {
+ MLoopUV *luv;
+ BMLoop *l;
+
+ if (element->separate && element != sculptdata->uv[i].element)
+ break;
+
+ l = element->l;
+ luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
+ copy_v2_v2(luv->uv, sculptdata->uv[i].uv);
+ }
+ }
+ }
+
+ MEM_freeN(tmp_uvdata);
+
+ return;
}
-
-static void uv_sculpt_stroke_apply(bContext *C, wmOperator *op, const wmEvent *event, Object *obedit)
+static void uv_sculpt_stroke_apply(bContext *C,
+ wmOperator *op,
+ const wmEvent *event,
+ Object *obedit)
{
- float co[2], radius, radius_root;
- Scene *scene = CTX_data_scene(C);
- ARegion *ar = CTX_wm_region(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- unsigned int tool;
- UvSculptData *sculptdata = (UvSculptData *)op->customdata;
- SpaceImage *sima;
- int invert;
- int width, height;
- float aspectRatio;
- float alpha, zoomx, zoomy;
- Brush *brush = BKE_paint_brush(sculptdata->uvsculpt);
- ToolSettings *toolsettings = CTX_data_tool_settings(C);
- tool = sculptdata->tool;
- invert = sculptdata->invert ? -1 : 1;
- alpha = BKE_brush_alpha_get(scene, brush);
- UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &co[0], &co[1]);
-
- sima = CTX_wm_space_image(C);
- ED_space_image_get_size(sima, &width, &height);
- ED_space_image_get_zoom(sima, ar, &zoomx, &zoomy);
-
- radius = BKE_brush_size_get(scene, brush) / (width * zoomx);
- aspectRatio = width / (float)height;
-
- /* We will compare squares to save some computation */
- radius = radius * radius;
- radius_root = sqrtf(radius);
-
- /*
- * Pinch Tool
- */
- if (tool == UV_SCULPT_TOOL_PINCH) {
- int i;
- alpha *= invert;
- for (i = 0; i < sculptdata->totalUniqueUvs; i++) {
- float dist, diff[2];
- /* This is supposed to happen only if "Lock Borders" is on, since we have initialization on stroke start
- * If ever uv brushes get their own mode we should check for toolsettings option too */
- if (sculptdata->uv[i].flag & MARK_BOUNDARY) {
- continue;
- }
-
- sub_v2_v2v2(diff, sculptdata->uv[i].uv, co);
- diff[1] /= aspectRatio;
- if ((dist = dot_v2v2(diff, diff)) <= radius) {
- UvElement *element;
- float strength;
- strength = alpha * BKE_brush_curve_strength_clamped(brush, sqrtf(dist), radius_root);
- normalize_v2(diff);
-
- sculptdata->uv[i].uv[0] -= strength * diff[0] * 0.001f;
- sculptdata->uv[i].uv[1] -= strength * diff[1] * 0.001f;
-
- for (element = sculptdata->uv[i].element; element; element = element->next) {
- MLoopUV *luv;
- BMLoop *l;
-
- if (element->separate && element != sculptdata->uv[i].element)
- break;
-
- l = element->l;
- luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
- copy_v2_v2(luv->uv, sculptdata->uv[i].uv);
- }
- }
- }
- }
-
- /*
- * Smooth Tool
- */
- else if (tool == UV_SCULPT_TOOL_RELAX) {
- unsigned int method = toolsettings->uv_relax_method;
- if (method == UV_SCULPT_TOOL_RELAX_HC) {
- HC_relaxation_iteration_uv(em, sculptdata, co, alpha, radius, aspectRatio);
- }
- else {
- laplacian_relaxation_iteration_uv(em, sculptdata, co, alpha, radius, aspectRatio);
- }
- }
-
- /*
- * Grab Tool
- */
- else if (tool == UV_SCULPT_TOOL_GRAB) {
- int i;
- float diff[2];
- sub_v2_v2v2(diff, co, sculptdata->initial_stroke->init_coord);
-
- for (i = 0; i < sculptdata->initial_stroke->totalInitialSelected; i++) {
- UvElement *element;
- int uvindex = sculptdata->initial_stroke->initialSelection[i].uv;
- float strength = sculptdata->initial_stroke->initialSelection[i].strength;
- sculptdata->uv[uvindex].uv[0] = sculptdata->initial_stroke->initialSelection[i].initial_uv[0] + strength * diff[0];
- sculptdata->uv[uvindex].uv[1] = sculptdata->initial_stroke->initialSelection[i].initial_uv[1] + strength * diff[1];
-
- for (element = sculptdata->uv[uvindex].element; element; element = element->next) {
- MLoopUV *luv;
- BMLoop *l;
-
- if (element->separate && element != sculptdata->uv[uvindex].element)
- break;
-
- l = element->l;
- luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
- copy_v2_v2(luv->uv, sculptdata->uv[uvindex].uv);
- }
- }
- }
+ float co[2], radius, radius_root;
+ Scene *scene = CTX_data_scene(C);
+ ARegion *ar = CTX_wm_region(C);
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ unsigned int tool;
+ UvSculptData *sculptdata = (UvSculptData *)op->customdata;
+ SpaceImage *sima;
+ int invert;
+ int width, height;
+ float aspectRatio;
+ float alpha, zoomx, zoomy;
+ Brush *brush = BKE_paint_brush(sculptdata->uvsculpt);
+ ToolSettings *toolsettings = CTX_data_tool_settings(C);
+ tool = sculptdata->tool;
+ invert = sculptdata->invert ? -1 : 1;
+ alpha = BKE_brush_alpha_get(scene, brush);
+ UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &co[0], &co[1]);
+
+ sima = CTX_wm_space_image(C);
+ ED_space_image_get_size(sima, &width, &height);
+ ED_space_image_get_zoom(sima, ar, &zoomx, &zoomy);
+
+ radius = BKE_brush_size_get(scene, brush) / (width * zoomx);
+ aspectRatio = width / (float)height;
+
+ /* We will compare squares to save some computation */
+ radius = radius * radius;
+ radius_root = sqrtf(radius);
+
+ /*
+ * Pinch Tool
+ */
+ if (tool == UV_SCULPT_TOOL_PINCH) {
+ int i;
+ alpha *= invert;
+ for (i = 0; i < sculptdata->totalUniqueUvs; i++) {
+ float dist, diff[2];
+ /* This is supposed to happen only if "Lock Borders" is on, since we have initialization on stroke start
+ * If ever uv brushes get their own mode we should check for toolsettings option too */
+ if (sculptdata->uv[i].flag & MARK_BOUNDARY) {
+ continue;
+ }
+
+ sub_v2_v2v2(diff, sculptdata->uv[i].uv, co);
+ diff[1] /= aspectRatio;
+ if ((dist = dot_v2v2(diff, diff)) <= radius) {
+ UvElement *element;
+ float strength;
+ strength = alpha * BKE_brush_curve_strength_clamped(brush, sqrtf(dist), radius_root);
+ normalize_v2(diff);
+
+ sculptdata->uv[i].uv[0] -= strength * diff[0] * 0.001f;
+ sculptdata->uv[i].uv[1] -= strength * diff[1] * 0.001f;
+
+ for (element = sculptdata->uv[i].element; element; element = element->next) {
+ MLoopUV *luv;
+ BMLoop *l;
+
+ if (element->separate && element != sculptdata->uv[i].element)
+ break;
+
+ l = element->l;
+ luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
+ copy_v2_v2(luv->uv, sculptdata->uv[i].uv);
+ }
+ }
+ }
+ }
+
+ /*
+ * Smooth Tool
+ */
+ else if (tool == UV_SCULPT_TOOL_RELAX) {
+ unsigned int method = toolsettings->uv_relax_method;
+ if (method == UV_SCULPT_TOOL_RELAX_HC) {
+ HC_relaxation_iteration_uv(em, sculptdata, co, alpha, radius, aspectRatio);
+ }
+ else {
+ laplacian_relaxation_iteration_uv(em, sculptdata, co, alpha, radius, aspectRatio);
+ }
+ }
+
+ /*
+ * Grab Tool
+ */
+ else if (tool == UV_SCULPT_TOOL_GRAB) {
+ int i;
+ float diff[2];
+ sub_v2_v2v2(diff, co, sculptdata->initial_stroke->init_coord);
+
+ for (i = 0; i < sculptdata->initial_stroke->totalInitialSelected; i++) {
+ UvElement *element;
+ int uvindex = sculptdata->initial_stroke->initialSelection[i].uv;
+ float strength = sculptdata->initial_stroke->initialSelection[i].strength;
+ sculptdata->uv[uvindex].uv[0] =
+ sculptdata->initial_stroke->initialSelection[i].initial_uv[0] + strength * diff[0];
+ sculptdata->uv[uvindex].uv[1] =
+ sculptdata->initial_stroke->initialSelection[i].initial_uv[1] + strength * diff[1];
+
+ for (element = sculptdata->uv[uvindex].element; element; element = element->next) {
+ MLoopUV *luv;
+ BMLoop *l;
+
+ if (element->separate && element != sculptdata->uv[uvindex].element)
+ break;
+
+ l = element->l;
+ luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
+ copy_v2_v2(luv->uv, sculptdata->uv[uvindex].uv);
+ }
+ }
+ }
}
-
static void uv_sculpt_stroke_exit(bContext *C, wmOperator *op)
{
- UvSculptData *data = op->customdata;
- if (data->timer) {
- WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), data->timer);
- }
- if (data->elementMap) {
- BM_uv_element_map_free(data->elementMap);
- }
- if (data->uv) {
- MEM_freeN(data->uv);
- }
- if (data->uvedges) {
- MEM_freeN(data->uvedges);
- }
- if (data->initial_stroke) {
- if (data->initial_stroke->initialSelection) {
- MEM_freeN(data->initial_stroke->initialSelection);
- }
- MEM_freeN(data->initial_stroke);
- }
-
- MEM_freeN(data);
- op->customdata = NULL;
+ UvSculptData *data = op->customdata;
+ if (data->timer) {
+ WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), data->timer);
+ }
+ if (data->elementMap) {
+ BM_uv_element_map_free(data->elementMap);
+ }
+ if (data->uv) {
+ MEM_freeN(data->uv);
+ }
+ if (data->uvedges) {
+ MEM_freeN(data->uvedges);
+ }
+ if (data->initial_stroke) {
+ if (data->initial_stroke->initialSelection) {
+ MEM_freeN(data->initial_stroke->initialSelection);
+ }
+ MEM_freeN(data->initial_stroke);
+ }
+
+ MEM_freeN(data);
+ op->customdata = NULL;
}
-static int uv_element_offset_from_face_get(UvElementMap *map, BMFace *efa, BMLoop *l, int island_index, const bool doIslands)
+static int uv_element_offset_from_face_get(
+ UvElementMap *map, BMFace *efa, BMLoop *l, int island_index, const bool doIslands)
{
- UvElement *element = BM_uv_element_get(map, efa, l);
- if (!element || (doIslands && element->island != island_index)) {
- return -1;
- }
- return element - map->buf;
+ UvElement *element = BM_uv_element_get(map, efa, l);
+ if (!element || (doIslands && element->island != island_index)) {
+ return -1;
+ }
+ return element - map->buf;
}
-
static unsigned int uv_edge_hash(const void *key)
{
- const UvEdge *edge = key;
- return (BLI_ghashutil_uinthash(edge->uv2) +
- BLI_ghashutil_uinthash(edge->uv1));
+ const UvEdge *edge = key;
+ return (BLI_ghashutil_uinthash(edge->uv2) + BLI_ghashutil_uinthash(edge->uv1));
}
static bool uv_edge_compare(const void *a, const void *b)
{
- const UvEdge *edge1 = a;
- const UvEdge *edge2 = b;
+ const UvEdge *edge1 = a;
+ const UvEdge *edge2 = b;
- if ((edge1->uv1 == edge2->uv1) && (edge1->uv2 == edge2->uv2)) {
- return 0;
- }
- return 1;
+ if ((edge1->uv1 == edge2->uv1) && (edge1->uv2 == edge2->uv2)) {
+ return 0;
+ }
+ return 1;
}
-
static UvSculptData *uv_sculpt_stroke_init(bContext *C, wmOperator *op, const wmEvent *event)
{
- Scene *scene = CTX_data_scene(C);
- Object *obedit = CTX_data_edit_object(C);
- ToolSettings *ts = scene->toolsettings;
- UvSculptData *data = MEM_callocN(sizeof(*data), "UV Smooth Brush Data");
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- BMesh *bm = em->bm;
-
- op->customdata = data;
-
- curvemapping_initialize(ts->uvsculpt->paint.brush->curve);
-
- if (data) {
- int counter = 0, i;
- ARegion *ar = CTX_wm_region(C);
- float co[2];
- BMFace *efa;
- MLoopUV *luv;
- BMLoop *l;
- BMIter iter, liter;
-
- UvEdge *edges;
- GHash *edgeHash;
- GHashIterator gh_iter;
-
- bool do_island_optimization = !(ts->uv_sculpt_settings & UV_SCULPT_ALL_ISLANDS);
- int island_index = 0;
- /* Holds, for each UvElement in elementMap, a pointer to its unique uv.*/
- int *uniqueUv;
- data->tool = (RNA_enum_get(op->ptr, "mode") == BRUSH_STROKE_SMOOTH) ? UV_SCULPT_TOOL_RELAX : ts->uv_sculpt_tool;
- data->invert = (RNA_enum_get(op->ptr, "mode") == BRUSH_STROKE_INVERT) ? 1 : 0;
-
- data->uvsculpt = &ts->uvsculpt->paint;
-
- if (do_island_optimization) {
- /* We will need island information */
- if (ts->uv_flag & UV_SYNC_SELECTION) {
- data->elementMap = BM_uv_element_map_create(bm, false, true, true);
- }
- else {
- data->elementMap = BM_uv_element_map_create(bm, true, true, true);
- }
- }
- else {
- if (ts->uv_flag & UV_SYNC_SELECTION) {
- data->elementMap = BM_uv_element_map_create(bm, false, true, false);
- }
- else {
- data->elementMap = BM_uv_element_map_create(bm, true, true, false);
- }
- }
-
- if (!data->elementMap) {
- uv_sculpt_stroke_exit(C, op);
- return NULL;
- }
-
- /* Mouse coordinates, useful for some functions like grab and sculpt all islands */
- UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &co[0], &co[1]);
-
- /* we need to find the active island here */
- if (do_island_optimization) {
- UvElement *element;
- UvNearestHit hit = UV_NEAREST_HIT_INIT;
- Image *ima = CTX_data_edit_image(C);
- uv_find_nearest_vert(scene, ima, obedit, co, 0.0f, &hit);
-
- element = BM_uv_element_get(data->elementMap, hit.efa, hit.l);
- island_index = element->island;
- }
-
-
- /* Count 'unique' uvs */
- for (i = 0; i < data->elementMap->totalUVs; i++) {
- if (data->elementMap->buf[i].separate &&
- (!do_island_optimization || data->elementMap->buf[i].island == island_index))
- {
- counter++;
- }
- }
-
- /* Allocate the unique uv buffers */
- data->uv = MEM_mallocN(sizeof(*data->uv) * counter, "uv_brush_unique_uvs");
- uniqueUv = MEM_mallocN(sizeof(*uniqueUv) * data->elementMap->totalUVs, "uv_brush_unique_uv_map");
- edgeHash = BLI_ghash_new(uv_edge_hash, uv_edge_compare, "uv_brush_edge_hash");
- /* we have at most totalUVs edges */
- edges = MEM_mallocN(sizeof(*edges) * data->elementMap->totalUVs, "uv_brush_all_edges");
- if (!data->uv || !uniqueUv || !edgeHash || !edges) {
- if (edges) {
- MEM_freeN(edges);
- }
- if (uniqueUv) {
- MEM_freeN(uniqueUv);
- }
- if (edgeHash) {
- BLI_ghash_free(edgeHash, NULL, NULL);
- }
- uv_sculpt_stroke_exit(C, op);
- return NULL;
- }
-
- data->totalUniqueUvs = counter;
- /* So that we can use this as index for the UvElements */
- counter = -1;
- /* initialize the unique UVs */
- for (i = 0; i < bm->totvert; i++) {
- UvElement *element = data->elementMap->vert[i];
- for (; element; element = element->next) {
- if (element->separate) {
- if (do_island_optimization && (element->island != island_index)) {
- /* skip this uv if not on the active island */
- for (; element->next && !(element->next->separate); element = element->next)
- ;
- continue;
- }
-
- l = element->l;
- luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
-
- counter++;
- data->uv[counter].element = element;
- data->uv[counter].flag = 0;
- data->uv[counter].uv = luv->uv;
- }
- /* pointer arithmetic to the rescue, as always :)*/
- uniqueUv[element - data->elementMap->buf] = counter;
- }
- }
-
-
- /* Now, on to generate our uv connectivity data */
- counter = 0;
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- int offset1, itmp1 = uv_element_offset_from_face_get(data->elementMap, efa, l, island_index, do_island_optimization);
- int offset2, itmp2 = uv_element_offset_from_face_get(data->elementMap, efa, l->next, island_index, do_island_optimization);
- char *flag;
-
- /* Skip edge if not found(unlikely) or not on valid island */
- if (itmp1 == -1 || itmp2 == -1)
- continue;
-
- offset1 = uniqueUv[itmp1];
- offset2 = uniqueUv[itmp2];
-
- edges[counter].flag = 0;
- /* using an order policy, sort uvs according to address space. This avoids
- * Having two different UvEdges with the same uvs on different positions */
- if (offset1 < offset2) {
- edges[counter].uv1 = offset1;
- edges[counter].uv2 = offset2;
- }
- else {
- edges[counter].uv1 = offset2;
- edges[counter].uv2 = offset1;
- }
- /* Hack! Set the value of the key to its flag.
- * Now we can set the flag when an edge exists twice :) */
- flag = BLI_ghash_lookup(edgeHash, &edges[counter]);
- if (flag) {
- *flag = 1;
- }
- else {
- /* Hack mentioned */
- BLI_ghash_insert(edgeHash, &edges[counter], &edges[counter].flag);
- }
- counter++;
- }
- }
-
- MEM_freeN(uniqueUv);
-
- /* Allocate connectivity data, we allocate edges once */
- data->uvedges = MEM_mallocN(sizeof(*data->uvedges) * BLI_ghash_len(edgeHash), "uv_brush_edge_connectivity_data");
- if (!data->uvedges) {
- BLI_ghash_free(edgeHash, NULL, NULL);
- MEM_freeN(edges);
- uv_sculpt_stroke_exit(C, op);
- return NULL;
- }
-
- /* fill the edges with data */
- i = 0;
- GHASH_ITER (gh_iter, edgeHash) {
- data->uvedges[i++] = *((UvEdge *)BLI_ghashIterator_getKey(&gh_iter));
- }
- data->totalUvEdges = BLI_ghash_len(edgeHash);
-
- /* cleanup temporary stuff */
- BLI_ghash_free(edgeHash, NULL, NULL);
- MEM_freeN(edges);
-
- /* transfer boundary edge property to uvs */
- if (ts->uv_sculpt_settings & UV_SCULPT_LOCK_BORDERS) {
- for (i = 0; i < data->totalUvEdges; i++) {
- if (!data->uvedges[i].flag) {
- data->uv[data->uvedges[i].uv1].flag |= MARK_BOUNDARY;
- data->uv[data->uvedges[i].uv2].flag |= MARK_BOUNDARY;
- }
- }
- }
-
- /* Allocate initial selection for grab tool */
- if (data->tool == UV_SCULPT_TOOL_GRAB) {
- float radius, radius_root;
- UvSculptData *sculptdata = (UvSculptData *)op->customdata;
- SpaceImage *sima;
- int width, height;
- float aspectRatio;
- float alpha, zoomx, zoomy;
- Brush *brush = BKE_paint_brush(sculptdata->uvsculpt);
-
- alpha = BKE_brush_alpha_get(scene, brush);
-
- radius = BKE_brush_size_get(scene, brush);
- sima = CTX_wm_space_image(C);
- ED_space_image_get_size(sima, &width, &height);
- ED_space_image_get_zoom(sima, ar, &zoomx, &zoomy);
-
- aspectRatio = width / (float)height;
- radius /= (width * zoomx);
- radius = radius * radius;
- radius_root = sqrtf(radius);
-
- /* Allocate selection stack */
- data->initial_stroke = MEM_mallocN(sizeof(*data->initial_stroke), "uv_sculpt_initial_stroke");
- if (!data->initial_stroke) {
- uv_sculpt_stroke_exit(C, op);
- }
- data->initial_stroke->initialSelection = MEM_mallocN(sizeof(*data->initial_stroke->initialSelection) * data->totalUniqueUvs, "uv_sculpt_initial_selection");
- if (!data->initial_stroke->initialSelection) {
- uv_sculpt_stroke_exit(C, op);
- }
-
- copy_v2_v2(data->initial_stroke->init_coord, co);
-
- counter = 0;
-
- for (i = 0; i < data->totalUniqueUvs; i++) {
- float dist, diff[2];
- if (data->uv[i].flag & MARK_BOUNDARY) {
- continue;
- }
-
- sub_v2_v2v2(diff, data->uv[i].uv, co);
- diff[1] /= aspectRatio;
- if ((dist = dot_v2v2(diff, diff)) <= radius) {
- float strength;
- strength = alpha * BKE_brush_curve_strength_clamped(brush, sqrtf(dist), radius_root);
-
- data->initial_stroke->initialSelection[counter].uv = i;
- data->initial_stroke->initialSelection[counter].strength = strength;
- copy_v2_v2(data->initial_stroke->initialSelection[counter].initial_uv, data->uv[i].uv);
- counter++;
- }
- }
-
- data->initial_stroke->totalInitialSelected = counter;
- }
- }
-
- return op->customdata;
+ Scene *scene = CTX_data_scene(C);
+ Object *obedit = CTX_data_edit_object(C);
+ ToolSettings *ts = scene->toolsettings;
+ UvSculptData *data = MEM_callocN(sizeof(*data), "UV Smooth Brush Data");
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMesh *bm = em->bm;
+
+ op->customdata = data;
+
+ curvemapping_initialize(ts->uvsculpt->paint.brush->curve);
+
+ if (data) {
+ int counter = 0, i;
+ ARegion *ar = CTX_wm_region(C);
+ float co[2];
+ BMFace *efa;
+ MLoopUV *luv;
+ BMLoop *l;
+ BMIter iter, liter;
+
+ UvEdge *edges;
+ GHash *edgeHash;
+ GHashIterator gh_iter;
+
+ bool do_island_optimization = !(ts->uv_sculpt_settings & UV_SCULPT_ALL_ISLANDS);
+ int island_index = 0;
+ /* Holds, for each UvElement in elementMap, a pointer to its unique uv.*/
+ int *uniqueUv;
+ data->tool = (RNA_enum_get(op->ptr, "mode") == BRUSH_STROKE_SMOOTH) ? UV_SCULPT_TOOL_RELAX :
+ ts->uv_sculpt_tool;
+ data->invert = (RNA_enum_get(op->ptr, "mode") == BRUSH_STROKE_INVERT) ? 1 : 0;
+
+ data->uvsculpt = &ts->uvsculpt->paint;
+
+ if (do_island_optimization) {
+ /* We will need island information */
+ if (ts->uv_flag & UV_SYNC_SELECTION) {
+ data->elementMap = BM_uv_element_map_create(bm, false, true, true);
+ }
+ else {
+ data->elementMap = BM_uv_element_map_create(bm, true, true, true);
+ }
+ }
+ else {
+ if (ts->uv_flag & UV_SYNC_SELECTION) {
+ data->elementMap = BM_uv_element_map_create(bm, false, true, false);
+ }
+ else {
+ data->elementMap = BM_uv_element_map_create(bm, true, true, false);
+ }
+ }
+
+ if (!data->elementMap) {
+ uv_sculpt_stroke_exit(C, op);
+ return NULL;
+ }
+
+ /* Mouse coordinates, useful for some functions like grab and sculpt all islands */
+ UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &co[0], &co[1]);
+
+ /* we need to find the active island here */
+ if (do_island_optimization) {
+ UvElement *element;
+ UvNearestHit hit = UV_NEAREST_HIT_INIT;
+ Image *ima = CTX_data_edit_image(C);
+ uv_find_nearest_vert(scene, ima, obedit, co, 0.0f, &hit);
+
+ element = BM_uv_element_get(data->elementMap, hit.efa, hit.l);
+ island_index = element->island;
+ }
+
+ /* Count 'unique' uvs */
+ for (i = 0; i < data->elementMap->totalUVs; i++) {
+ if (data->elementMap->buf[i].separate &&
+ (!do_island_optimization || data->elementMap->buf[i].island == island_index)) {
+ counter++;
+ }
+ }
+
+ /* Allocate the unique uv buffers */
+ data->uv = MEM_mallocN(sizeof(*data->uv) * counter, "uv_brush_unique_uvs");
+ uniqueUv = MEM_mallocN(sizeof(*uniqueUv) * data->elementMap->totalUVs,
+ "uv_brush_unique_uv_map");
+ edgeHash = BLI_ghash_new(uv_edge_hash, uv_edge_compare, "uv_brush_edge_hash");
+ /* we have at most totalUVs edges */
+ edges = MEM_mallocN(sizeof(*edges) * data->elementMap->totalUVs, "uv_brush_all_edges");
+ if (!data->uv || !uniqueUv || !edgeHash || !edges) {
+ if (edges) {
+ MEM_freeN(edges);
+ }
+ if (uniqueUv) {
+ MEM_freeN(uniqueUv);
+ }
+ if (edgeHash) {
+ BLI_ghash_free(edgeHash, NULL, NULL);
+ }
+ uv_sculpt_stroke_exit(C, op);
+ return NULL;
+ }
+
+ data->totalUniqueUvs = counter;
+ /* So that we can use this as index for the UvElements */
+ counter = -1;
+ /* initialize the unique UVs */
+ for (i = 0; i < bm->totvert; i++) {
+ UvElement *element = data->elementMap->vert[i];
+ for (; element; element = element->next) {
+ if (element->separate) {
+ if (do_island_optimization && (element->island != island_index)) {
+ /* skip this uv if not on the active island */
+ for (; element->next && !(element->next->separate); element = element->next)
+ ;
+ continue;
+ }
+
+ l = element->l;
+ luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
+
+ counter++;
+ data->uv[counter].element = element;
+ data->uv[counter].flag = 0;
+ data->uv[counter].uv = luv->uv;
+ }
+ /* pointer arithmetic to the rescue, as always :)*/
+ uniqueUv[element - data->elementMap->buf] = counter;
+ }
+ }
+
+ /* Now, on to generate our uv connectivity data */
+ counter = 0;
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ int offset1, itmp1 = uv_element_offset_from_face_get(
+ data->elementMap, efa, l, island_index, do_island_optimization);
+ int offset2, itmp2 = uv_element_offset_from_face_get(
+ data->elementMap, efa, l->next, island_index, do_island_optimization);
+ char *flag;
+
+ /* Skip edge if not found(unlikely) or not on valid island */
+ if (itmp1 == -1 || itmp2 == -1)
+ continue;
+
+ offset1 = uniqueUv[itmp1];
+ offset2 = uniqueUv[itmp2];
+
+ edges[counter].flag = 0;
+ /* using an order policy, sort uvs according to address space. This avoids
+ * Having two different UvEdges with the same uvs on different positions */
+ if (offset1 < offset2) {
+ edges[counter].uv1 = offset1;
+ edges[counter].uv2 = offset2;
+ }
+ else {
+ edges[counter].uv1 = offset2;
+ edges[counter].uv2 = offset1;
+ }
+ /* Hack! Set the value of the key to its flag.
+ * Now we can set the flag when an edge exists twice :) */
+ flag = BLI_ghash_lookup(edgeHash, &edges[counter]);
+ if (flag) {
+ *flag = 1;
+ }
+ else {
+ /* Hack mentioned */
+ BLI_ghash_insert(edgeHash, &edges[counter], &edges[counter].flag);
+ }
+ counter++;
+ }
+ }
+
+ MEM_freeN(uniqueUv);
+
+ /* Allocate connectivity data, we allocate edges once */
+ data->uvedges = MEM_mallocN(sizeof(*data->uvedges) * BLI_ghash_len(edgeHash),
+ "uv_brush_edge_connectivity_data");
+ if (!data->uvedges) {
+ BLI_ghash_free(edgeHash, NULL, NULL);
+ MEM_freeN(edges);
+ uv_sculpt_stroke_exit(C, op);
+ return NULL;
+ }
+
+ /* fill the edges with data */
+ i = 0;
+ GHASH_ITER (gh_iter, edgeHash) {
+ data->uvedges[i++] = *((UvEdge *)BLI_ghashIterator_getKey(&gh_iter));
+ }
+ data->totalUvEdges = BLI_ghash_len(edgeHash);
+
+ /* cleanup temporary stuff */
+ BLI_ghash_free(edgeHash, NULL, NULL);
+ MEM_freeN(edges);
+
+ /* transfer boundary edge property to uvs */
+ if (ts->uv_sculpt_settings & UV_SCULPT_LOCK_BORDERS) {
+ for (i = 0; i < data->totalUvEdges; i++) {
+ if (!data->uvedges[i].flag) {
+ data->uv[data->uvedges[i].uv1].flag |= MARK_BOUNDARY;
+ data->uv[data->uvedges[i].uv2].flag |= MARK_BOUNDARY;
+ }
+ }
+ }
+
+ /* Allocate initial selection for grab tool */
+ if (data->tool == UV_SCULPT_TOOL_GRAB) {
+ float radius, radius_root;
+ UvSculptData *sculptdata = (UvSculptData *)op->customdata;
+ SpaceImage *sima;
+ int width, height;
+ float aspectRatio;
+ float alpha, zoomx, zoomy;
+ Brush *brush = BKE_paint_brush(sculptdata->uvsculpt);
+
+ alpha = BKE_brush_alpha_get(scene, brush);
+
+ radius = BKE_brush_size_get(scene, brush);
+ sima = CTX_wm_space_image(C);
+ ED_space_image_get_size(sima, &width, &height);
+ ED_space_image_get_zoom(sima, ar, &zoomx, &zoomy);
+
+ aspectRatio = width / (float)height;
+ radius /= (width * zoomx);
+ radius = radius * radius;
+ radius_root = sqrtf(radius);
+
+ /* Allocate selection stack */
+ data->initial_stroke = MEM_mallocN(sizeof(*data->initial_stroke),
+ "uv_sculpt_initial_stroke");
+ if (!data->initial_stroke) {
+ uv_sculpt_stroke_exit(C, op);
+ }
+ data->initial_stroke->initialSelection = MEM_mallocN(
+ sizeof(*data->initial_stroke->initialSelection) * data->totalUniqueUvs,
+ "uv_sculpt_initial_selection");
+ if (!data->initial_stroke->initialSelection) {
+ uv_sculpt_stroke_exit(C, op);
+ }
+
+ copy_v2_v2(data->initial_stroke->init_coord, co);
+
+ counter = 0;
+
+ for (i = 0; i < data->totalUniqueUvs; i++) {
+ float dist, diff[2];
+ if (data->uv[i].flag & MARK_BOUNDARY) {
+ continue;
+ }
+
+ sub_v2_v2v2(diff, data->uv[i].uv, co);
+ diff[1] /= aspectRatio;
+ if ((dist = dot_v2v2(diff, diff)) <= radius) {
+ float strength;
+ strength = alpha * BKE_brush_curve_strength_clamped(brush, sqrtf(dist), radius_root);
+
+ data->initial_stroke->initialSelection[counter].uv = i;
+ data->initial_stroke->initialSelection[counter].strength = strength;
+ copy_v2_v2(data->initial_stroke->initialSelection[counter].initial_uv, data->uv[i].uv);
+ counter++;
+ }
+ }
+
+ data->initial_stroke->totalInitialSelected = counter;
+ }
+ }
+
+ return op->customdata;
}
static int uv_sculpt_stroke_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
- UvSculptData *data;
- Object *obedit = CTX_data_edit_object(C);
+ UvSculptData *data;
+ Object *obedit = CTX_data_edit_object(C);
- if (!(data = uv_sculpt_stroke_init(C, op, event))) {
- return OPERATOR_CANCELLED;
- }
+ if (!(data = uv_sculpt_stroke_init(C, op, event))) {
+ return OPERATOR_CANCELLED;
+ }
- uv_sculpt_stroke_apply(C, op, event, obedit);
+ uv_sculpt_stroke_apply(C, op, event, obedit);
- data->timer = WM_event_add_timer(CTX_wm_manager(C), CTX_wm_window(C), TIMER, 0.001f);
+ data->timer = WM_event_add_timer(CTX_wm_manager(C), CTX_wm_window(C), TIMER, 0.001f);
- if (!data->timer) {
- uv_sculpt_stroke_exit(C, op);
- return OPERATOR_CANCELLED;
- }
- WM_event_add_modal_handler(C, op);
+ if (!data->timer) {
+ uv_sculpt_stroke_exit(C, op);
+ return OPERATOR_CANCELLED;
+ }
+ WM_event_add_modal_handler(C, op);
- return OPERATOR_RUNNING_MODAL;
+ return OPERATOR_RUNNING_MODAL;
}
-
static int uv_sculpt_stroke_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
- UvSculptData *data = (UvSculptData *)op->customdata;
- Object *obedit = CTX_data_edit_object(C);
-
- switch (event->type) {
- case LEFTMOUSE:
- case MIDDLEMOUSE:
- case RIGHTMOUSE:
- uv_sculpt_stroke_exit(C, op);
- return OPERATOR_FINISHED;
-
- case MOUSEMOVE:
- case INBETWEEN_MOUSEMOVE:
- uv_sculpt_stroke_apply(C, op, event, obedit);
- break;
- case TIMER:
- if (event->customdata == data->timer)
- uv_sculpt_stroke_apply(C, op, event, obedit);
- break;
- default:
- return OPERATOR_RUNNING_MODAL;
- }
-
- ED_region_tag_redraw(CTX_wm_region(C));
- WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
- DEG_id_tag_update(obedit->data, 0);
- return OPERATOR_RUNNING_MODAL;
+ UvSculptData *data = (UvSculptData *)op->customdata;
+ Object *obedit = CTX_data_edit_object(C);
+
+ switch (event->type) {
+ case LEFTMOUSE:
+ case MIDDLEMOUSE:
+ case RIGHTMOUSE:
+ uv_sculpt_stroke_exit(C, op);
+ return OPERATOR_FINISHED;
+
+ case MOUSEMOVE:
+ case INBETWEEN_MOUSEMOVE:
+ uv_sculpt_stroke_apply(C, op, event, obedit);
+ break;
+ case TIMER:
+ if (event->customdata == data->timer)
+ uv_sculpt_stroke_apply(C, op, event, obedit);
+ break;
+ default:
+ return OPERATOR_RUNNING_MODAL;
+ }
+
+ ED_region_tag_redraw(CTX_wm_region(C));
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
+ DEG_id_tag_update(obedit->data, 0);
+ return OPERATOR_RUNNING_MODAL;
}
void SCULPT_OT_uv_sculpt_stroke(wmOperatorType *ot)
{
- static const EnumPropertyItem stroke_mode_items[] = {
- {BRUSH_STROKE_NORMAL, "NORMAL", 0, "Regular", "Apply brush normally"},
- {BRUSH_STROKE_INVERT, "INVERT", 0, "Invert", "Invert action of brush for duration of stroke"},
- {BRUSH_STROKE_SMOOTH, "RELAX", 0, "Relax", "Switch brush to relax mode for duration of stroke"},
- {0},
- };
-
- /* identifiers */
- ot->name = "Sculpt UVs";
- ot->description = "Sculpt UVs using a brush";
- ot->idname = "SCULPT_OT_uv_sculpt_stroke";
-
- /* api callbacks */
- ot->invoke = uv_sculpt_stroke_invoke;
- ot->modal = uv_sculpt_stroke_modal;
- ot->poll = uv_sculpt_poll;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* props */
- RNA_def_enum(ot->srna, "mode", stroke_mode_items, BRUSH_STROKE_NORMAL, "Mode", "Stroke Mode");
+ static const EnumPropertyItem stroke_mode_items[] = {
+ {BRUSH_STROKE_NORMAL, "NORMAL", 0, "Regular", "Apply brush normally"},
+ {BRUSH_STROKE_INVERT,
+ "INVERT",
+ 0,
+ "Invert",
+ "Invert action of brush for duration of stroke"},
+ {BRUSH_STROKE_SMOOTH,
+ "RELAX",
+ 0,
+ "Relax",
+ "Switch brush to relax mode for duration of stroke"},
+ {0},
+ };
+
+ /* identifiers */
+ ot->name = "Sculpt UVs";
+ ot->description = "Sculpt UVs using a brush";
+ ot->idname = "SCULPT_OT_uv_sculpt_stroke";
+
+ /* api callbacks */
+ ot->invoke = uv_sculpt_stroke_invoke;
+ ot->modal = uv_sculpt_stroke_modal;
+ ot->poll = uv_sculpt_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* props */
+ RNA_def_enum(ot->srna, "mode", stroke_mode_items, BRUSH_STROKE_NORMAL, "Mode", "Stroke Mode");
}