diff options
author | Sergey Sharybin <sergey.vfx@gmail.com> | 2017-10-03 10:59:06 +0300 |
---|---|---|
committer | Sergey Sharybin <sergey.vfx@gmail.com> | 2017-10-03 10:59:06 +0300 |
commit | 2bfa061a15762e93f0391e3348f58bcfa512d8fc (patch) | |
tree | b3d51e85572e3272c1e0a4c1817d011f61f81386 /source/blender | |
parent | 21369429168c5799125a63ef728947f4fd6668e9 (diff) | |
parent | 2b3ff61d805ccbb219e773e1a5c69e02b0c90109 (diff) |
Merge branch 'master' into blender2.8
Notes:
- Changes in paint_vertex.c were simple to merge, mainly related on passing
evaluation context.
- Conflicts in EditDM and drawmesh.c are solved using code from blender2.8
branch. Those areas are deprecated and not to be used in final release.
However, it's possible that some reference code from master is lost, so
keep attention when adding alpha support for vertex painting.
Diffstat (limited to 'source/blender')
25 files changed, 1000 insertions, 420 deletions
diff --git a/source/blender/blenkernel/BKE_brush.h b/source/blender/blenkernel/BKE_brush.h index dedb75a080a..c1e107e101a 100644 --- a/source/blender/blenkernel/BKE_brush.h +++ b/source/blender/blenkernel/BKE_brush.h @@ -70,7 +70,7 @@ void BKE_brush_randomize_texture_coords(struct UnifiedPaintSettings *ups, bool m /* brush curve */ void BKE_brush_curve_preset(struct Brush *b, int preset); float BKE_brush_curve_strength_clamped(struct Brush *br, float p, const float len); -float BKE_brush_curve_strength(struct Brush *br, float p, const float len); +float BKE_brush_curve_strength(const struct Brush *br, float p, const float len); /* sampling */ float BKE_brush_sample_tex_3D( diff --git a/source/blender/blenkernel/BKE_paint.h b/source/blender/blenkernel/BKE_paint.h index 5c7684f9fe1..527c0aeb609 100644 --- a/source/blender/blenkernel/BKE_paint.h +++ b/source/blender/blenkernel/BKE_paint.h @@ -230,9 +230,12 @@ typedef struct SculptSession { /* Vertex aligned arrays of weights. */ float *previous_accum; - float *previous_weight; /* Keep track of how much each vertex has been painted (non-airbrush only). */ float *alpha_weight; + + /* Needed to continuously re-apply over the same weights (VP_FLAG_SPRAY disabled). + * Lazy initialize as needed (flag is set to 1 to tag it as uninitialized). */ + struct MDeformVert *dvert_prev; } wpaint; //struct { diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c index 03b0710c8fc..0300dfe5891 100644 --- a/source/blender/blenkernel/intern/brush.c +++ b/source/blender/blenkernel/intern/brush.c @@ -966,7 +966,7 @@ void BKE_brush_randomize_texture_coords(UnifiedPaintSettings *ups, bool mask) } /* Uses the brush curve control to find a strength value */ -float BKE_brush_curve_strength(Brush *br, float p, const float len) +float BKE_brush_curve_strength(const Brush *br, float p, const float len) { float strength; diff --git a/source/blender/blenkernel/intern/cdderivedmesh.c b/source/blender/blenkernel/intern/cdderivedmesh.c index dd43bf8b9d8..d1282c1a0fe 100644 --- a/source/blender/blenkernel/intern/cdderivedmesh.c +++ b/source/blender/blenkernel/intern/cdderivedmesh.c @@ -641,18 +641,8 @@ static void cdDM_drawMappedFaces( /* avoid buffer problems in following code */ } else if (setDrawOptions == NULL) { - const bool show_alpha = true; - if (show_alpha) { - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - } - /* just draw the entire face array */ GPU_buffer_draw_elements(dm->drawObject->triangles, GL_TRIANGLES, 0, tot_tri_elem); - - if (show_alpha) { - glDisable(GL_BLEND); - } } else { for (mat_index = 0; mat_index < dm->drawObject->totmaterial; mat_index++) { diff --git a/source/blender/blenkernel/intern/paint.c b/source/blender/blenkernel/intern/paint.c index 8c336002ba3..40d02acab1c 100644 --- a/source/blender/blenkernel/intern/paint.c +++ b/source/blender/blenkernel/intern/paint.c @@ -49,6 +49,7 @@ #include "BKE_brush.h" #include "BKE_colortools.h" +#include "BKE_deform.h" #include "BKE_main.h" #include "BKE_context.h" #include "BKE_crazyspace.h" @@ -689,8 +690,12 @@ void BKE_sculptsession_free_vwpaint_data(struct SculptSession *ss) gmap = &ss->mode.wpaint.gmap; MEM_SAFE_FREE(ss->mode.wpaint.alpha_weight); - MEM_SAFE_FREE(ss->mode.wpaint.previous_weight); MEM_SAFE_FREE(ss->mode.wpaint.previous_accum); + if (ss->mode.wpaint.dvert_prev) { + BKE_defvert_array_free_elems(ss->mode.wpaint.dvert_prev, ss->totvert); + MEM_freeN(ss->mode.wpaint.dvert_prev); + ss->mode.wpaint.dvert_prev = NULL; + } } else { return; diff --git a/source/blender/blenkernel/intern/subsurf_ccg.c b/source/blender/blenkernel/intern/subsurf_ccg.c index 764df797ef6..d461e03fcda 100644 --- a/source/blender/blenkernel/intern/subsurf_ccg.c +++ b/source/blender/blenkernel/intern/subsurf_ccg.c @@ -2199,12 +2199,12 @@ static void ccgDM_buffer_copy_color( for (S = 0; S < numVerts; S++) { for (y = 0; y < gridFaces; y++) { for (x = 0; x < gridFaces; x++) { - copy_v3_v3_uchar(&varray[start + 0], &mloopcol[iface * 16 + 0]); - copy_v3_v3_uchar(&varray[start + 3], &mloopcol[iface * 16 + 12]); - copy_v3_v3_uchar(&varray[start + 6], &mloopcol[iface * 16 + 8]); - copy_v3_v3_uchar(&varray[start + 9], &mloopcol[iface * 16 + 4]); + copy_v4_v4_uchar(&varray[start + 0], &mloopcol[iface * 16 + 0]); + copy_v4_v4_uchar(&varray[start + 4], &mloopcol[iface * 16 + 12]); + copy_v4_v4_uchar(&varray[start + 8], &mloopcol[iface * 16 + 8]); + copy_v4_v4_uchar(&varray[start + 12], &mloopcol[iface * 16 + 4]); - start += 12; + start += 16; iface++; } } @@ -3544,16 +3544,16 @@ static void ccgDM_drawMappedFaces(DerivedMesh *dm, float *c = CCG_grid_elem_co(&key, faceGridData, x + 1, y + 1); float *d = CCG_grid_elem_co(&key, faceGridData, x, y + 1); - if (cp) glColor3ubv(&cp[4]); + if (cp) glColor4ubv(&cp[4]); glNormal3fv(ln[1]); glVertex3fv(d); - if (cp) glColor3ubv(&cp[8]); + if (cp) glColor4ubv(&cp[8]); glNormal3fv(ln[2]); glVertex3fv(c); - if (cp) glColor3ubv(&cp[12]); + if (cp) glColor4ubv(&cp[12]); glNormal3fv(ln[3]); glVertex3fv(b); - if (cp) glColor3ubv(&cp[0]); + if (cp) glColor4ubv(&cp[0]); glNormal3fv(ln[0]); glVertex3fv(a); @@ -3571,10 +3571,10 @@ static void ccgDM_drawMappedFaces(DerivedMesh *dm, a = CCG_grid_elem(&key, faceGridData, x, y + 0); b = CCG_grid_elem(&key, faceGridData, x, y + 1); - if (cp) glColor3ubv(&cp[0]); + if (cp) glColor4ubv(&cp[0]); glNormal3fv(CCG_elem_no(&key, a)); glVertex3fv(CCG_elem_co(&key, a)); - if (cp) glColor3ubv(&cp[4]); + if (cp) glColor4ubv(&cp[4]); glNormal3fv(CCG_elem_no(&key, b)); glVertex3fv(CCG_elem_co(&key, b)); @@ -3586,10 +3586,10 @@ static void ccgDM_drawMappedFaces(DerivedMesh *dm, a = CCG_grid_elem(&key, faceGridData, x, y + 0); b = CCG_grid_elem(&key, faceGridData, x, y + 1); - if (cp) glColor3ubv(&cp[12]); + if (cp) glColor4ubv(&cp[12]); glNormal3fv(CCG_elem_no(&key, a)); glVertex3fv(CCG_elem_co(&key, a)); - if (cp) glColor3ubv(&cp[8]); + if (cp) glColor4ubv(&cp[8]); glNormal3fv(CCG_elem_no(&key, b)); glVertex3fv(CCG_elem_co(&key, b)); @@ -3609,13 +3609,13 @@ static void ccgDM_drawMappedFaces(DerivedMesh *dm, ccgDM_glNormalFast(a, b, c, d); - if (cp) glColor3ubv(&cp[4]); + if (cp) glColor4ubv(&cp[4]); glVertex3fv(d); - if (cp) glColor3ubv(&cp[8]); + if (cp) glColor4ubv(&cp[8]); glVertex3fv(c); - if (cp) glColor3ubv(&cp[12]); + if (cp) glColor4ubv(&cp[12]); glVertex3fv(b); - if (cp) glColor3ubv(&cp[0]); + if (cp) glColor4ubv(&cp[0]); glVertex3fv(a); if (cp) cp += 16; diff --git a/source/blender/blenlib/BLI_math_geom.h b/source/blender/blenlib/BLI_math_geom.h index 0fef849c8fa..d0b59244384 100644 --- a/source/blender/blenlib/BLI_math_geom.h +++ b/source/blender/blenlib/BLI_math_geom.h @@ -119,6 +119,26 @@ float dist_squared_ray_to_seg_v3( const float ray_origin[3], const float ray_direction[3], const float v0[3], const float v1[3], float r_point[3], float *r_depth); + +struct DistRayAABB_Precalc { + float ray_origin[3]; + float ray_direction[3]; + float ray_inv_dir[3]; + bool sign[3]; +}; +void dist_squared_ray_to_aabb_precalc( + struct DistRayAABB_Precalc *neasrest_precalc, + const float ray_origin[3], const float ray_direction[3]); +float dist_squared_ray_to_aabb( + const struct DistRayAABB_Precalc *data, + const float bb_min[3], const float bb_max[3], + float r_point[3], float *r_depth); +/* when there is no advantage to precalc. */ +float dist_squared_to_ray_to_aabb_simple( + const float ray_origin[3], const float ray_direction[3], + const float bb_min[3], const float bb_max[3], + float r_point[3], float *r_depth); + float closest_to_line_v2(float r_close[2], const float p[2], const float l1[2], const float l2[2]); float closest_to_line_v3(float r_close[3], const float p[3], const float l1[3], const float l2[3]); void closest_to_line_segment_v2(float r_close[2], const float p[2], const float l1[2], const float l2[2]); diff --git a/source/blender/blenlib/intern/math_geom.c b/source/blender/blenlib/intern/math_geom.c index 53fcf9c745c..dbbc1adb534 100644 --- a/source/blender/blenlib/intern/math_geom.c +++ b/source/blender/blenlib/intern/math_geom.c @@ -619,6 +619,152 @@ float dist_squared_ray_to_seg_v3( return len_squared_v3(t) - SQUARE(*r_depth); } +/* -------------------------------------------------------------------- */ +/** \name dist_squared_to_ray_to_aabb and helpers + * \{ */ + +void dist_squared_ray_to_aabb_precalc( + struct DistRayAABB_Precalc *neasrest_precalc, + const float ray_origin[3], const float ray_direction[3]) +{ + copy_v3_v3(neasrest_precalc->ray_origin, ray_origin); + copy_v3_v3(neasrest_precalc->ray_direction, ray_direction); + + for (int i = 0; i < 3; i++) { + neasrest_precalc->ray_inv_dir[i] = + (neasrest_precalc->ray_direction[i] != 0.0f) ? + (1.0f / neasrest_precalc->ray_direction[i]) : FLT_MAX; + neasrest_precalc->sign[i] = (neasrest_precalc->ray_inv_dir[i] < 0.0f); + } +} + +/** + * Returns the distance from a ray to a bound-box (projected on ray) + */ +float dist_squared_ray_to_aabb( + const struct DistRayAABB_Precalc *data, + const float bb_min[3], const float bb_max[3], + float r_point[3], float *r_depth) +{ + // bool r_axis_closest[3]; + float local_bvmin[3], local_bvmax[3]; + if (data->sign[0]) { + local_bvmin[0] = bb_max[0]; + local_bvmax[0] = bb_min[0]; + } + else { + local_bvmin[0] = bb_min[0]; + local_bvmax[0] = bb_max[0]; + } + if (data->sign[1]) { + local_bvmin[1] = bb_max[1]; + local_bvmax[1] = bb_min[1]; + } + else { + local_bvmin[1] = bb_min[1]; + local_bvmax[1] = bb_max[1]; + } + if (data->sign[2]) { + local_bvmin[2] = bb_max[2]; + local_bvmax[2] = bb_min[2]; + } + else { + local_bvmin[2] = bb_min[2]; + local_bvmax[2] = bb_max[2]; + } + + const float tmin[3] = { + (local_bvmin[0] - data->ray_origin[0]) * data->ray_inv_dir[0], + (local_bvmin[1] - data->ray_origin[1]) * data->ray_inv_dir[1], + (local_bvmin[2] - data->ray_origin[2]) * data->ray_inv_dir[2], + }; + const float tmax[3] = { + (local_bvmax[0] - data->ray_origin[0]) * data->ray_inv_dir[0], + (local_bvmax[1] - data->ray_origin[1]) * data->ray_inv_dir[1], + (local_bvmax[2] - data->ray_origin[2]) * data->ray_inv_dir[2], + }; + /* `va` and `vb` are the coordinates of the AABB edge closest to the ray */ + float va[3], vb[3]; + /* `rtmin` and `rtmax` are the minimum and maximum distances of the ray hits on the AABB */ + float rtmin, rtmax; + int main_axis; + + if ((tmax[0] <= tmax[1]) && (tmax[0] <= tmax[2])) { + rtmax = tmax[0]; + va[0] = vb[0] = local_bvmax[0]; + main_axis = 3; + // r_axis_closest[0] = data->sign[0]; + } + else if ((tmax[1] <= tmax[0]) && (tmax[1] <= tmax[2])) { + rtmax = tmax[1]; + va[1] = vb[1] = local_bvmax[1]; + main_axis = 2; + // r_axis_closest[1] = data->sign[1]; + } + else { + rtmax = tmax[2]; + va[2] = vb[2] = local_bvmax[2]; + main_axis = 1; + // r_axis_closest[2] = data->sign[2]; + } + + if ((tmin[0] >= tmin[1]) && (tmin[0] >= tmin[2])) { + rtmin = tmin[0]; + va[0] = vb[0] = local_bvmin[0]; + main_axis -= 3; + // r_axis_closest[0] = !data->sign[0]; + } + else if ((tmin[1] >= tmin[0]) && (tmin[1] >= tmin[2])) { + rtmin = tmin[1]; + va[1] = vb[1] = local_bvmin[1]; + main_axis -= 1; + // r_axis_closest[1] = !data->sign[1]; + } + else { + rtmin = tmin[2]; + va[2] = vb[2] = local_bvmin[2]; + main_axis -= 2; + // r_axis_closest[2] = !data->sign[2]; + } + if (main_axis < 0) { + main_axis += 3; + } + + /* if rtmin <= rtmax, ray intersect `AABB` */ + if (rtmin <= rtmax) { + float dvec[3]; + copy_v3_v3(r_point, local_bvmax); + sub_v3_v3v3(dvec, local_bvmax, data->ray_origin); + *r_depth = dot_v3v3(dvec, data->ray_direction); + return 0.0f; + } + + if (data->sign[main_axis]) { + va[main_axis] = local_bvmax[main_axis]; + vb[main_axis] = local_bvmin[main_axis]; + } + else { + va[main_axis] = local_bvmin[main_axis]; + vb[main_axis] = local_bvmax[main_axis]; + } + + return dist_squared_ray_to_seg_v3( + data->ray_origin, data->ray_direction, va, vb, + r_point, r_depth); +} + +float dist_squared_to_ray_to_aabb_simple( + const float ray_origin[3], const float ray_direction[3], + const float bbmin[3], const float bbmax[3], + float r_point[3], float *r_depth) +{ + struct DistRayAABB_Precalc data; + dist_squared_ray_to_aabb_precalc(&data, ray_origin, ray_direction); + return dist_squared_ray_to_aabb(&data, bbmin, bbmax, r_point, r_depth); +} +/** \} */ + + /* Adapted from "Real-Time Collision Detection" by Christer Ericson, * published by Morgan Kaufmann Publishers, copyright 2005 Elsevier Inc. * diff --git a/source/blender/blenloader/intern/versioning_270.c b/source/blender/blenloader/intern/versioning_270.c index afbd84bdb91..bab1a45796d 100644 --- a/source/blender/blenloader/intern/versioning_270.c +++ b/source/blender/blenloader/intern/versioning_270.c @@ -1653,23 +1653,6 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main) } } - { - Brush *br; - br = (Brush *)BKE_libblock_find_name_ex(main, ID_BR, "Average"); - if (!br) { - br = BKE_brush_add(main, "Average", OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT); - br->vertexpaint_tool = PAINT_BLEND_AVERAGE; - br->ob_mode = OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT; - } - - br = (Brush *)BKE_libblock_find_name_ex(main, ID_BR, "Smear"); - if (!br) { - br = BKE_brush_add(main, "Smear", OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT); - br->vertexpaint_tool = PAINT_BLEND_SMEAR; - br->ob_mode = OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT; - } - } - FOREACH_NODETREE(main, ntree, id) { if (ntree->type == NTREE_COMPOSIT) { do_versions_compositor_render_passes(ntree); @@ -1720,6 +1703,20 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main) } } } + + if (!DNA_struct_elem_find(fd->filesdna, "VPaint", "char", "falloff_shape")) { + for (Scene *scene = main->scene.first; scene; scene = scene->id.next) { + ToolSettings *ts = scene->toolsettings; + for (int i = 0; i < 2; i++) { + VPaint *vp = i ? ts->vpaint : ts->wpaint; + if (vp != NULL) { + /* remove all other flags */ + vp->flag &= (VP_FLAG_SPRAY | VP_FLAG_VGROUP_RESTRICT); + vp->normal_angle = 80; + } + } + } + } } } diff --git a/source/blender/compositor/intern/COM_Debug.cpp b/source/blender/compositor/intern/COM_Debug.cpp index a7b464cde29..68439ff8469 100644 --- a/source/blender/compositor/intern/COM_Debug.cpp +++ b/source/blender/compositor/intern/COM_Debug.cpp @@ -28,9 +28,11 @@ #include <vector> extern "C" { +#include "BLI_sys_types.h" #include "BLI_fileops.h" #include "BLI_path_util.h" #include "BLI_string.h" + #include "DNA_node_types.h" #include "BKE_appdir.h" #include "BKE_node.h" @@ -174,7 +176,7 @@ int DebugInfo::graphviz_operation(const ExecutionSystem *system, const NodeOpera len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "%s\\n(%s)", m_op_names[operation].c_str(), typeid(*operation).name()); - len += snprintf(str + len, maxlen > len ? maxlen - len : 0, " (%d,%d)", operation->getWidth(), operation->getHeight()); + len += snprintf(str + len, maxlen > len ? maxlen - len : 0, " (%u,%u)", operation->getWidth(), operation->getHeight()); int totoutputs = operation->getNumberOfOutputSockets(); if (totoutputs != 0) { diff --git a/source/blender/compositor/nodes/COM_ScaleNode.cpp b/source/blender/compositor/nodes/COM_ScaleNode.cpp index 61eea9227dc..ef4128a78b4 100644 --- a/source/blender/compositor/nodes/COM_ScaleNode.cpp +++ b/source/blender/compositor/nodes/COM_ScaleNode.cpp @@ -52,6 +52,9 @@ void ScaleNode::convertToOperations(NodeConverter &converter, const CompositorCo converter.mapInputSocket(inputXSocket, operation->getInputSocket(1)); converter.mapInputSocket(inputYSocket, operation->getInputSocket(2)); converter.mapOutputSocket(outputSocket, operation->getOutputSocket(0)); + + operation->setVariableSize(inputXSocket->isLinked() || + inputYSocket->isLinked()); break; } case CMP_SCALE_SCENEPERCENT: @@ -67,6 +70,10 @@ void ScaleNode::convertToOperations(NodeConverter &converter, const CompositorCo converter.addLink(scaleFactorOperation->getOutputSocket(), operation->getInputSocket(1)); converter.addLink(scaleFactorOperation->getOutputSocket(), operation->getInputSocket(2)); converter.mapOutputSocket(outputSocket, operation->getOutputSocket(0)); + + operation->setVariableSize(inputXSocket->isLinked() || + inputYSocket->isLinked()); + break; } case CMP_SCALE_RENDERPERCENT: @@ -81,9 +88,13 @@ void ScaleNode::convertToOperations(NodeConverter &converter, const CompositorCo operation->setNewHeight(rd->ysch * rd->size / 100.0f); operation->getInputSocket(0)->setResizeMode(COM_SC_NO_RESIZE); converter.addOperation(operation); - + converter.mapInputSocket(inputSocket, operation->getInputSocket(0)); converter.mapOutputSocket(outputSocket, operation->getOutputSocket(0)); + + operation->setVariableSize(inputXSocket->isLinked() || + inputYSocket->isLinked()); + break; } case CMP_SCALE_ABSOLUTE: @@ -91,11 +102,15 @@ void ScaleNode::convertToOperations(NodeConverter &converter, const CompositorCo /* TODO: what is the use of this one.... perhaps some issues when the ui was updated... */ ScaleAbsoluteOperation *operation = new ScaleAbsoluteOperation(); converter.addOperation(operation); - + converter.mapInputSocket(inputSocket, operation->getInputSocket(0)); converter.mapInputSocket(inputXSocket, operation->getInputSocket(1)); converter.mapInputSocket(inputYSocket, operation->getInputSocket(2)); converter.mapOutputSocket(outputSocket, operation->getOutputSocket(0)); + + operation->setVariableSize(inputXSocket->isLinked() || + inputYSocket->isLinked()); + break; } } diff --git a/source/blender/compositor/operations/COM_ScaleOperation.cpp b/source/blender/compositor/operations/COM_ScaleOperation.cpp index 46e155e43b5..b498b359144 100644 --- a/source/blender/compositor/operations/COM_ScaleOperation.cpp +++ b/source/blender/compositor/operations/COM_ScaleOperation.cpp @@ -36,6 +36,7 @@ BaseScaleOperation::BaseScaleOperation() #else m_sampler = -1; #endif + m_variable_size = false; } ScaleOperation::ScaleOperation() : BaseScaleOperation() @@ -87,20 +88,27 @@ void ScaleOperation::executePixelSampled(float output[4], float x, float y, Pixe bool ScaleOperation::determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output) { rcti newInput; - float scaleX[4]; - float scaleY[4]; - - this->m_inputXOperation->readSampled(scaleX, 0, 0, COM_PS_NEAREST); - this->m_inputYOperation->readSampled(scaleY, 0, 0, COM_PS_NEAREST); + if (!m_variable_size) { + float scaleX[4]; + float scaleY[4]; - const float scx = scaleX[0]; - const float scy = scaleY[0]; + this->m_inputXOperation->readSampled(scaleX, 0, 0, COM_PS_NEAREST); + this->m_inputYOperation->readSampled(scaleY, 0, 0, COM_PS_NEAREST); - newInput.xmax = this->m_centerX + (input->xmax - this->m_centerX) / scx; - newInput.xmin = this->m_centerX + (input->xmin - this->m_centerX) / scx; - newInput.ymax = this->m_centerY + (input->ymax - this->m_centerY) / scy; - newInput.ymin = this->m_centerY + (input->ymin - this->m_centerY) / scy; + const float scx = scaleX[0]; + const float scy = scaleY[0]; + newInput.xmax = this->m_centerX + (input->xmax - this->m_centerX) / scx; + newInput.xmin = this->m_centerX + (input->xmin - this->m_centerX) / scx; + newInput.ymax = this->m_centerY + (input->ymax - this->m_centerY) / scy; + newInput.ymin = this->m_centerY + (input->ymin - this->m_centerY) / scy; + } + else { + newInput.xmax = this->getWidth(); + newInput.xmin = 0; + newInput.ymax = this->getHeight(); + newInput.ymin = 0; + } return BaseScaleOperation::determineDependingAreaOfInterest(&newInput, readOperation, output); } @@ -162,24 +170,32 @@ void ScaleAbsoluteOperation::executePixelSampled(float output[4], float x, float bool ScaleAbsoluteOperation::determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output) { rcti newInput; - float scaleX[4]; - float scaleY[4]; - - this->m_inputXOperation->readSampled(scaleX, 0, 0, COM_PS_NEAREST); - this->m_inputYOperation->readSampled(scaleY, 0, 0, COM_PS_NEAREST); - - const float scx = scaleX[0]; - const float scy = scaleY[0]; - const float width = this->getWidth(); - const float height = this->getHeight(); - //div - float relateveXScale = scx / width; - float relateveYScale = scy / height; - - newInput.xmax = this->m_centerX + (input->xmax - this->m_centerX) / relateveXScale; - newInput.xmin = this->m_centerX + (input->xmin - this->m_centerX) / relateveXScale; - newInput.ymax = this->m_centerY + (input->ymax - this->m_centerY) / relateveYScale; - newInput.ymin = this->m_centerY + (input->ymin - this->m_centerY) / relateveYScale; + if (!m_variable_size) { + float scaleX[4]; + float scaleY[4]; + + this->m_inputXOperation->readSampled(scaleX, 0, 0, COM_PS_NEAREST); + this->m_inputYOperation->readSampled(scaleY, 0, 0, COM_PS_NEAREST); + + const float scx = scaleX[0]; + const float scy = scaleY[0]; + const float width = this->getWidth(); + const float height = this->getHeight(); + //div + float relateveXScale = scx / width; + float relateveYScale = scy / height; + + newInput.xmax = this->m_centerX + (input->xmax - this->m_centerX) / relateveXScale; + newInput.xmin = this->m_centerX + (input->xmin - this->m_centerX) / relateveXScale; + newInput.ymax = this->m_centerY + (input->ymax - this->m_centerY) / relateveYScale; + newInput.ymin = this->m_centerY + (input->ymin - this->m_centerY) / relateveYScale; + } + else { + newInput.xmax = this->getWidth(); + newInput.xmin = 0; + newInput.ymax = this->getHeight(); + newInput.ymin = 0; + } return BaseScaleOperation::determineDependingAreaOfInterest(&newInput, readOperation, output); } diff --git a/source/blender/compositor/operations/COM_ScaleOperation.h b/source/blender/compositor/operations/COM_ScaleOperation.h index 706a5898027..17cd31f9710 100644 --- a/source/blender/compositor/operations/COM_ScaleOperation.h +++ b/source/blender/compositor/operations/COM_ScaleOperation.h @@ -28,6 +28,7 @@ class BaseScaleOperation : public NodeOperation { public: void setSampler(PixelSampler sampler) { this->m_sampler = (int) sampler; } + void setVariableSize(bool variable_size) { m_variable_size = variable_size; }; protected: BaseScaleOperation(); @@ -35,6 +36,7 @@ protected: PixelSampler getEffectiveSampler(PixelSampler sampler) { return (m_sampler == -1) ? sampler : (PixelSampler) m_sampler; } int m_sampler; + bool m_variable_size; }; class ScaleOperation : public BaseScaleOperation { diff --git a/source/blender/editors/mesh/meshtools.c b/source/blender/editors/mesh/meshtools.c index 8fddf2551b8..5261baeab57 100644 --- a/source/blender/editors/mesh/meshtools.c +++ b/source/blender/editors/mesh/meshtools.c @@ -454,15 +454,6 @@ int join_mesh_exec(bContext *C, wmOperator *op) /* adjust settings to fit (allocate a new data-array) */ kbn->data = MEM_callocN(sizeof(float) * 3 * totvert, "joined_shapekey"); kbn->totelem = totvert; - - /* XXX 2.5 Animato */ -#if 0 - /* also, copy corresponding ipo-curve to ipo-block if applicable */ - if (me->key->ipo && key->ipo) { - /* FIXME... this is a luxury item! */ - puts("FIXME: ignoring IPO's when joining shapekeys on Meshes for now..."); - } -#endif } kb_map[i] = kbn; diff --git a/source/blender/editors/sculpt_paint/paint_vertex.c b/source/blender/editors/sculpt_paint/paint_vertex.c index 9775c136586..1df6030bb10 100644 --- a/source/blender/editors/sculpt_paint/paint_vertex.c +++ b/source/blender/editors/sculpt_paint/paint_vertex.c @@ -89,10 +89,76 @@ struct WPaintAverageAccum { double value; }; -static void defweight_prev_init(const MDeformWeight *dw, float *weight_prev) +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; +}; + + +static void view_angle_limits_init( + struct NormalAnglePrecalc *a, float angle, bool do_mask_normal) +{ + 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; + + 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); +} + +static float view_angle_limits_apply_falloff( + const struct NormalAnglePrecalc *a, float angle_cos, float *mask_p) { - if (UNLIKELY(*weight_prev == -1.0f)) { - *weight_prev = dw ? dw->weight : 0.0f; + 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->flag & VP_FLAG_PROJECT_BACKFACE) == 0) || + ((vp->flag & VP_FLAG_PROJECT_FLAT) == 0); +} + + +static void defweight_prev_restore_or_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); + } + else { + defvert_copy(dv_curr, dv_prev); } } @@ -137,7 +203,7 @@ int vertex_paint_mode_poll(bContext *C) int vertex_paint_poll(bContext *C) { - if (vertex_paint_mode_poll(C) && + if (vertex_paint_mode_poll(C) && BKE_paint_brush(&CTX_data_tool_settings(C)->vpaint->paint)) { ScrArea *sa = CTX_wm_area(C); @@ -179,8 +245,8 @@ int weight_paint_poll(bContext *C) static VPaint *new_vpaint(int wpaint) { VPaint *vp = MEM_callocN(sizeof(VPaint), "VPaint"); - - vp->flag = (wpaint) ? 0 : VP_SPRAY; + + vp->flag = (wpaint) ? 0 : VP_FLAG_SPRAY; vp->paint.flags |= PAINT_SHOW_BRUSH; return vp; @@ -208,7 +274,7 @@ static uint vpaint_blend( uint color_blend = ED_vpaint_blend_tool(tool, color_curr, color_paint, alpha_i); /* if no spray, clip color adding with colorig & orig alpha */ - if ((vp->flag & VP_SPRAY) == 0) { + if ((vp->flag & VP_FLAG_SPRAY) == 0) { uint color_test, a; char *cp, *ct, *co; @@ -250,9 +316,10 @@ static float calc_vp_strength_col_dl( { 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) + 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 dist_sq = len_squared_v2v2(mval, co_ss); @@ -293,7 +360,7 @@ static float calc_vp_alpha_col_dl( if (strength > 0.0f) { float alpha = brush_alpha_pressure * strength; - if (vp->flag & VP_NORMALS) { + if ((vp->flag & VP_FLAG_PROJECT_FLAT) == 0) { float dvec[3]; /* transpose ! */ @@ -316,10 +383,11 @@ static float calc_vp_alpha_col_dl( } /* vpaint has 'vpaint_blend' */ -static float wpaint_blend(VPaint *wp, float weight, - const float alpha, float paintval, - const float UNUSED(brush_alpha_value), - const short do_flip) +static float wpaint_blend( + VPaint *wp, float weight, + const float alpha, float paintval, + const float UNUSED(brush_alpha_value), + const short do_flip) { Brush *brush = BKE_paint_brush(&wp->paint); int tool = brush->vertexpaint_tool; @@ -338,11 +406,11 @@ static float wpaint_blend(VPaint *wp, float weight, tool = PAINT_BLEND_LIGHTEN; break; } } - + weight = ED_wpaint_blend_tool(tool, weight, paintval, alpha); CLAMP(weight, 0.0f, 1.0f); - + return weight; } @@ -497,8 +565,9 @@ static void do_weight_paint_normalize_all_locked_try_active( } #if 0 /* UNUSED */ -static bool has_unselected_unlocked_bone_group(int defbase_tot, bool *defbase_sel, int selected, - const bool *lock_flags, const bool *vgroup_validmap) +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) { @@ -611,13 +680,15 @@ typedef struct WeightPaintInfo { struct WeightPaintGroupData active, mirror; - const bool *lock_flags; /* boolean array for locked bones, - * length of defbase_tot */ - const bool *defbase_sel; /* boolean array for selected bones, - * length of defbase_tot, cant be const because of how its passed */ - - const bool *vgroup_validmap; /* same as WeightPaintData.vgroup_validmap, - * only added here for convenience */ + /* 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; @@ -630,8 +701,7 @@ static void do_weight_paint_vertex_single( /* vars which remain the same for every vert */ VPaint *wp, Object *ob, const WeightPaintInfo *wpi, /* vars which change on each stroke */ - const uint index, float alpha, float paintweight - ) + const uint index, float alpha, float paintweight) { Mesh *me = ob->data; MDeformVert *dv = &me->dvert[index]; @@ -646,18 +716,6 @@ static void do_weight_paint_vertex_single( MDeformVert *dv_mirr; MDeformWeight *dw_mirr; - if (wp->flag & VP_ONLYVGROUP) { - dw = defvert_find_index(dv, wpi->active.index); - } - else { - dw = defvert_verify_index(dv, wpi->active.index); - } - - if (dw == NULL) { - return; - } - - /* 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); @@ -673,11 +731,29 @@ static void do_weight_paint_vertex_single( index_mirr = vgroup_mirr = -1; } + if ((wp->flag & VP_FLAG_SPRAY) == 0) { + struct MDeformVert *dvert_prev = ob->sculpt->mode.wpaint.dvert_prev; + defweight_prev_restore_or_init(dvert_prev, me->dvert, index); + if (index_mirr != -1) { + defweight_prev_restore_or_init(dvert_prev, me->dvert, index_mirr); + } + } + + 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_ONLYVGROUP) { + if (wp->flag & VP_FLAG_VGROUP_RESTRICT) { dw_mirr = defvert_find_index(dv_mirr, vgroup_mirr); if (dw_mirr == NULL) { @@ -711,8 +787,9 @@ static void do_weight_paint_vertex_single( * then there is no need to run the more complicated checks */ { - dw->weight = wpaint_blend(wp, dw->weight, alpha, paintweight, - wpi->brush_alpha_value, wpi->do_flip); + dw->weight = wpaint_blend( + wp, dw->weight, alpha, paintweight, + wpi->brush_alpha_value, wpi->do_flip); /* WATCH IT: take care of the ordering of applying mirror -> normalize, * can give wrong results [#26193], least confusing if normalize is done last */ @@ -793,6 +870,17 @@ static void do_weight_paint_vertex_multi( if (index_mirr != -1 && index_mirr != index) { dv_mirr = &me->dvert[index_mirr]; } + else { + index_mirr = -1; + } + } + + if ((wp->flag & VP_FLAG_SPRAY) == 0) { + struct MDeformVert *dvert_prev = ob->sculpt->mode.wpaint.dvert_prev; + defweight_prev_restore_or_init(dvert_prev, me->dvert, index); + if (index_mirr != -1) { + defweight_prev_restore_or_init(dvert_prev, me->dvert, index_mirr); + } } /* compute weight change by applying the brush to average or sum of group weights */ @@ -920,7 +1008,7 @@ static void vertex_paint_init_session_data(const ToolSettings *ts, Object *ob) /* Create average brush arrays */ if (ob->mode == OB_MODE_VERTEX_PAINT) { - if ((ts->vpaint->flag & VP_SPRAY) == 0) { + if ((ts->vpaint->flag & VP_FLAG_SPRAY) == 0) { if (ob->sculpt->mode.vpaint.previous_color == NULL) { ob->sculpt->mode.vpaint.previous_color = MEM_callocN(me->totloop * sizeof(uint), __func__); @@ -941,18 +1029,28 @@ static void vertex_paint_init_session_data(const ToolSettings *ts, Object *ob) } } else if (ob->mode == OB_MODE_WEIGHT_PAINT) { - if ((ts->wpaint->flag & VP_SPRAY) == 0) { + if ((ts->wpaint->flag & VP_FLAG_SPRAY) == 0) { 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.previous_weight == NULL) { - ob->sculpt->mode.wpaint.previous_weight = - MEM_mallocN(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; + } } if (brush && brush->flag & BRUSH_ACCUMULATE) { if (ob->sculpt->mode.wpaint.previous_accum == NULL) { @@ -973,7 +1071,7 @@ static void vertex_paint_init_session_data(const ToolSettings *ts, Object *ob) * \note Keep in sync with #vpaint_mode_toggle_exec */ static int wpaint_mode_toggle_exec(bContext *C, wmOperator *op) -{ +{ 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; @@ -1039,7 +1137,7 @@ static int wpaint_mode_toggle_exec(bContext *C, wmOperator *op) } BKE_mesh_batch_cache_dirty(ob->data, BKE_MESH_BATCH_DIRTY_ALL); - + /* Weightpaint works by overriding colors in mesh, * so need to make sure we recalc on enter and * exit (exit needs doing regardless because we @@ -1067,25 +1165,25 @@ static int paint_poll_test(bContext *C) 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"; - + /* api callbacks */ ot->exec = wpaint_mode_toggle_exec; ot->poll = paint_poll_test; - + /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - } /* ************ weight paint operator ********** */ struct WPaintData { ViewContext vc; + struct NormalAnglePrecalc normal_angle_precalc; struct WeightPaintGroupData active, mirror; @@ -1108,12 +1206,12 @@ struct WPaintData { /* Initialize the stroke cache invariants from operator properties */ static void vwpaint_update_cache_invariants( - bContext *C, VPaint *vd, SculptSession *ss, wmOperator *op, const float mouse[2]) + bContext *C, 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; - Brush *brush = BKE_paint_brush(&vd->paint); + Brush *brush = BKE_paint_brush(&vp->paint); ViewContext *vc = paint_stroke_view_context(op->customdata); Object *ob = CTX_data_active_object(C); float mat[3][3]; @@ -1165,12 +1263,12 @@ static void vwpaint_update_cache_invariants( } /* Initialize the stroke cache variants from operator properties */ -static void vwpaint_update_cache_variants(bContext *C, VPaint *vd, Object *ob, PointerRNA *ptr) +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(&vd->paint); + Brush *brush = BKE_paint_brush(&vp->paint); /* This effects the actual brush radius, so things farther away * are compared with a larger radius and vise versa. */ @@ -1228,7 +1326,7 @@ static bool wpaint_stroke_test_start(bContext *C, wmOperator *op, const float mo int defbase_tot, defbase_tot_sel; bool *defbase_sel; SculptSession *ss = ob->sculpt; - VPaint *vd = CTX_data_tool_settings(C)->wpaint; + VPaint *vp = CTX_data_tool_settings(C)->wpaint; EvaluationContext eval_ctx; float mat[4][4], imat[4][4]; @@ -1286,6 +1384,7 @@ static bool wpaint_stroke_test_start(bContext *C, wmOperator *op, const float mo wpd = MEM_callocN(sizeof(struct WPaintData), "WPaintData"); paint_stroke_set_mode_data(stroke, wpd); view3d_set_viewcontext(C, &wpd->vc); + view_angle_limits_init(&wpd->normal_angle_precalc, vp->normal_angle, (vp->flag & VP_FLAG_PROJECT_FLAT) == 0); wpd->active.index = vgroup_index.active; wpd->mirror.index = vgroup_index.mirror; @@ -1342,11 +1441,15 @@ static bool wpaint_stroke_test_start(bContext *C, wmOperator *op, const float mo /* If not previously created, create vertex/weight paint mode session data */ vertex_paint_init_session(&eval_ctx, scene, ob); - vwpaint_update_cache_invariants(C, vd, ss, op, mouse); + vwpaint_update_cache_invariants(C, vp, ss, op, mouse); vertex_paint_init_session_data(ts, ob); - if (ss->mode.wpaint.previous_weight != NULL) { - copy_vn_fl(ss->mode.wpaint.previous_weight, me->totvert, -1.0f); + 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; @@ -1360,7 +1463,7 @@ static float dot_vf3vs3(const float brushNormal[3], const short vertexNormal[3]) } static void get_brush_alpha_data( - Scene *scene, SculptSession *ss, Brush *brush, + 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 = @@ -1372,6 +1475,36 @@ static void get_brush_alpha_data( (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); + + CLAMP(weight, 0.0f, 1.0f); + return weight; + } + else { + return defvert_find_weight(dv, wpi->active.index); + } +} + +static 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 == VP_FALLOFF_SHAPE_SPHERE) { + sculpt_brush_test_sq_fn = sculpt_brush_test_sphere_sq; + } + else { + /* VP_FALLOFF_SHAPE_TUBE */ + plane_from_point_normal_v3(test->plane, test->location, ss->cache->view_normal); + sculpt_brush_test_sq_fn = sculpt_brush_test_circle_sq; + } + return sculpt_brush_test_sq_fn; +} + static void do_wpaint_brush_blur_task_cb_ex( void *userdata, void *UNUSED(userdata_chunk), const int n, const int UNUSED(thread_id)) { @@ -1380,25 +1513,26 @@ static void do_wpaint_brush_blur_task_cb_ex( CCGDerivedMesh *ccgdm = BKE_pbvh_get_ccgdm(ss->pbvh); const struct SculptVertexPaintGeomMap *gmap = &ss->mode.wpaint.gmap; - Brush *brush = data->brush; - StrokeCache *cache = ss->cache; + const Brush *brush = data->brush; + const StrokeCache *cache = ss->cache; Scene *scene = CTX_data_scene(data->C); - const float brush_strength = cache->bstrength; 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; - sculpt_brush_test_init(ss, &test); + SculptBrushTestFn sculpt_brush_test_sq_fn = + sculpt_brush_test_init_with_falloff_shape(ss, &test, data->vp->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(&test, vd.co)) { + if (sculpt_brush_test_sq_fn(&test, vd.co)) { /* For grid based pbvh, take the vert whose loop coopresponds to the current grid. * Otherwise, take the current vert. */ const int v_index = ccgdm ? data->me->mloop[vd.grid_indices[vd.g]].v : vd.vert_indices[vd.i]; @@ -1418,17 +1552,23 @@ static void do_wpaint_brush_blur_task_cb_ex( const int l_index = mp->loopstart + k; const MLoop *ml = &data->me->mloop[l_index]; const MDeformVert *dv = &data->me->dvert[ml->v]; - weight_final += defvert_find_weight(dv, data->wpi->active.index); + weight_final += wpaint_get_active_weight(dv, data->wpi); } } /* Apply the weight to the vertex. */ if (total_hit_loops != 0) { - const float view_dot = (vd.no) ? dot_vf3vs3(cache->sculpt_normal_symm, vd.no) : 1.0; - if (view_dot > 0.0f) { + float brush_strength = cache->bstrength; + const float angle_cos = (use_normal && vd.no) ? + dot_vf3vs3(ss->cache->sculpt_normal_symm, vd.no) : 1.0f; + if (((data->vp->flag & VP_FLAG_PROJECT_BACKFACE) || + (angle_cos > 0.0f)) && + ((data->vp->flag & VP_FLAG_PROJECT_FLAT) || + 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); float final_alpha = - view_dot * brush_fade * brush_strength * + brush_fade * brush_strength * grid_alpha * brush_alpha_pressure; if (brush->flag & BRUSH_ACCUMULATE) { @@ -1458,12 +1598,12 @@ static void do_wpaint_brush_smear_task_cb_ex( CCGDerivedMesh *ccgdm = BKE_pbvh_get_ccgdm(ss->pbvh); const struct SculptVertexPaintGeomMap *gmap = &ss->mode.wpaint.gmap; - Brush *brush = data->brush; - Scene *scene = CTX_data_scene(data->C); - StrokeCache *cache = ss->cache; - const float brush_strength = cache->bstrength; + 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]; @@ -1474,26 +1614,32 @@ static void do_wpaint_brush_smear_task_cb_ex( if (normalize_v3(brush_dir) != 0.0f) { SculptBrushTest test; - sculpt_brush_test_init(ss, &test); + SculptBrushTestFn sculpt_brush_test_sq_fn = + sculpt_brush_test_init_with_falloff_shape(ss, &test, data->vp->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_fast(&test, vd.co)) { - const float view_dot = (vd.no) ? dot_vf3vs3(cache->sculpt_normal_symm, vd.no) : 1.0; - if (view_dot > 0.0f) { - bool do_color = false; - - /* For grid based pbvh, take the vert whose loop cooresponds to the current grid. - * Otherwise, take the current vert. */ - const int v_index = ccgdm ? data->me->mloop[vd.grid_indices[vd.g]].v : vd.vert_indices[vd.i]; - const float grid_alpha = ccgdm ? 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) { + if (sculpt_brush_test_sq_fn(&test, vd.co)) { + /* For grid based pbvh, take the vert whose loop cooresponds to the current grid. + * Otherwise, take the current vert. */ + const int v_index = ccgdm ? data->me->mloop[vd.grid_indices[vd.g]].v : vd.vert_indices[vd.i]; + const float grid_alpha = ccgdm ? 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(ss->cache->sculpt_normal_symm, vd.no) : 1.0f; + if (((data->vp->flag & VP_FLAG_PROJECT_BACKFACE) || + (angle_cos > 0.0f)) && + ((data->vp->flag & VP_FLAG_PROJECT_FLAT) || + 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; @@ -1522,7 +1668,7 @@ static void do_wpaint_brush_smear_task_cb_ex( if (stroke_dot > stroke_dot_max) { stroke_dot_max = stroke_dot; MDeformVert *dv = &data->me->dvert[v_other_index]; - weight_final = defvert_find_weight(dv, data->wpi->active.index); + weight_final = wpaint_get_active_weight(dv, data->wpi); do_color = true; } } @@ -1530,9 +1676,9 @@ static void do_wpaint_brush_smear_task_cb_ex( } /* Apply weight to vertex */ if (do_color) { - const float brush_fade = BKE_brush_curve_strength(brush, test.dist, cache->radius); - const float final_alpha = - view_dot * brush_fade * brush_strength * + const float brush_fade = BKE_brush_curve_strength(brush, 0.0f, cache->radius); + float final_alpha = + brush_fade * brush_strength * grid_alpha * brush_alpha_pressure; do_weight_paint_vertex( data->vp, data->ob, data->wpi, @@ -1552,26 +1698,27 @@ static void do_wpaint_brush_draw_task_cb_ex( SculptThreadedTaskData *data = userdata; SculptSession *ss = data->ob->sculpt; CCGDerivedMesh *ccgdm = BKE_pbvh_get_ccgdm(ss->pbvh); - Scene *scene = CTX_data_scene(data->C); + const Scene *scene = CTX_data_scene(data->C); - Brush *brush = data->brush; - StrokeCache *cache = ss->cache; - const float brush_strength = cache->bstrength; + const Brush *brush = data->brush; + const StrokeCache *cache = ss->cache; const float paintweight = BKE_brush_weight_get(scene, brush); 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; - sculpt_brush_test_init(ss, &test); + SculptBrushTestFn sculpt_brush_test_sq_fn = + sculpt_brush_test_init_with_falloff_shape(ss, &test, data->vp->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(&test, vd.co)) { + 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 cooresponds to the current grid. * Otherwise, take the current vert. */ @@ -1581,11 +1728,16 @@ static void do_wpaint_brush_draw_task_cb_ex( 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 float view_dot = (vd.no) ? dot_vf3vs3(cache->sculpt_normal_symm, vd.no) : 1.0; - if (view_dot > 0.0f) { + float brush_strength = cache->bstrength; + const float angle_cos = (use_normal && vd.no) ? + dot_vf3vs3(ss->cache->sculpt_normal_symm, vd.no) : 1.0f; + if (((data->vp->flag & VP_FLAG_PROJECT_BACKFACE) || + (angle_cos > 0.0f)) && + ((data->vp->flag & VP_FLAG_PROJECT_FLAT) || + 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); - float final_alpha = view_dot * brush_fade * brush_strength * grid_alpha * brush_alpha_pressure; - + float final_alpha = brush_fade * brush_strength * grid_alpha * brush_alpha_pressure; if (brush->flag & BRUSH_ACCUMULATE) { float mask_accum = ss->mode.wpaint.previous_accum[v_index]; final_alpha = min_ff(final_alpha + mask_accum, brush_strength); @@ -1593,7 +1745,7 @@ static void do_wpaint_brush_draw_task_cb_ex( } /* Non-spray logic. */ - if ((data->vp->flag & VP_SPRAY) == 0) { + if ((data->vp->flag & VP_FLAG_SPRAY) == 0) { /* Only paint if we have greater alpha. */ if (ss->mode.wpaint.alpha_weight[v_index] < final_alpha) { ss->mode.wpaint.alpha_weight[v_index] = final_alpha; @@ -1601,14 +1753,6 @@ static void do_wpaint_brush_draw_task_cb_ex( else { continue; } - - MDeformVert *dv = &data->me->dvert[v_index]; - MDeformWeight *dw = defvert_find_index(dv, data->wpi->active.index); - float *weight_prev = &ss->mode.wpaint.previous_weight[v_index]; - defweight_prev_init(dw, weight_prev); - if (dw) { - dw->weight = *weight_prev; - } } do_weight_paint_vertex( @@ -1629,6 +1773,7 @@ static void do_wpaint_brush_calc_average_weight_cb_ex( StrokeCache *cache = ss->cache; CCGDerivedMesh *ccgdm = BKE_pbvh_get_ccgdm(ss->pbvh); + 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; @@ -1637,16 +1782,18 @@ static void do_wpaint_brush_calc_average_weight_cb_ex( accum->value = 0.0; SculptBrushTest test; - sculpt_brush_test_init(ss, &test); + SculptBrushTestFn sculpt_brush_test_sq_fn = + sculpt_brush_test_init_with_falloff_shape(ss, &test, data->vp->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(&test, vd.co)) { - const float view_dot = (vd.no) ? dot_vf3vs3(cache->sculpt_normal_symm, vd.no) : 1.0; - if (view_dot > 0.0 && BKE_brush_curve_strength(data->brush, sqrtf(test.dist), cache->radius) > 0.0) { + if (sculpt_brush_test_sq_fn(&test, vd.co)) { + const float angle_cos = (use_normal && vd.no) ? + dot_vf3vs3(ss->cache->sculpt_normal_symm, 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 = ccgdm ? data->me->mloop[vd.grid_indices[vd.g]].v : vd.vert_indices[vd.i]; // const float grid_alpha = ccgdm ? 1.0f / vd.gridsize : 1.0f; const char v_flag = data->me->mvert[v_index].flag; @@ -1655,7 +1802,7 @@ static void do_wpaint_brush_calc_average_weight_cb_ex( if (!(use_face_sel || use_vert_sel) || v_flag & SELECT) { const MDeformVert *dv = &data->me->dvert[v_index]; accum->len += 1; - accum->value += defvert_find_weight(dv, data->wpi->active.index); + accum->value += wpaint_get_active_weight(dv, data->wpi); } } } @@ -1704,31 +1851,78 @@ static void wpaint_paint_leaves( .sd = sd, .ob = ob, .brush = brush, .nodes = nodes, .vp = vp, .wpd = wpd, .wpi = wpi, .me = me, .C = C, }; + /* current mirroring code cannot be run in parallel */ + bool use_threading = !(me->editflag & ME_EDIT_MIRROR_X); + switch (brush->vertexpaint_tool) { case PAINT_BLEND_AVERAGE: calculate_average_weight(&data, nodes, totnode); BLI_task_parallel_range_ex( 0, totnode, &data, NULL, 0, - do_wpaint_brush_draw_task_cb_ex, true, false); + do_wpaint_brush_draw_task_cb_ex, use_threading, false); break; case PAINT_BLEND_SMEAR: BLI_task_parallel_range_ex( 0, totnode, &data, NULL, 0, - do_wpaint_brush_smear_task_cb_ex, true, false); + do_wpaint_brush_smear_task_cb_ex, use_threading, false); break; case PAINT_BLEND_BLUR: BLI_task_parallel_range_ex( 0, totnode, &data, NULL, 0, - do_wpaint_brush_blur_task_cb_ex, true, false); + do_wpaint_brush_blur_task_cb_ex, use_threading, false); break; default: BLI_task_parallel_range_ex( 0, totnode, &data, NULL, 0, - do_wpaint_brush_draw_task_cb_ex, true, false); + do_wpaint_brush_draw_task_cb_ex, use_threading, false); 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 (wp->falloff_shape == VP_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_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) @@ -1737,19 +1931,9 @@ static void wpaint_do_paint( ss->cache->radial_symmetry_pass = i; sculpt_cache_calc_brushdata_symm(ss->cache, symm, axis, angle); - SculptSearchSphereData data; - PBVHNode **nodes = NULL; int totnode; + PBVHNode **nodes = vwpaint_pbvh_gather_generic(ob, wp, sd, brush, &totnode); - - /* Build a list of all nodes that are potentially within the brush's area of influence */ - data.ss = ss; - data.sd = sd; - data.radius_squared = ss->cache->radius_squared; - data.original = true; - BKE_pbvh_search_gather(ss->pbvh, sculpt_search_sphere_cb, &data, &nodes, &totnode); - - sculpt_pbvh_calc_area_normal(brush, ob, nodes, totnode, true, ss->cache->sculpt_normal_symm); wpaint_paint_leaves(C, ob, sd, wp, wpd, wpi, me, nodes, totnode); if (nodes) @@ -1843,7 +2027,7 @@ static void wpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P vc = &wpd->vc; ob = vc->obact; - + view3d_operator_needs_opengl(C); ED_view3d_init_mats_rv3d(ob, vc->rv3d); @@ -1908,7 +2092,7 @@ 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) { ED_vpaint_proj_handle_free(wpd->vp_handle); @@ -1925,12 +2109,12 @@ static void wpaint_stroke_done(const bContext *C, struct PaintStroke *stroke) 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) { @@ -1958,7 +2142,7 @@ static int wpaint_invoke(bContext *C, wmOperator *op, const wmEvent *event) 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; @@ -1968,7 +2152,7 @@ static int wpaint_invoke(bContext *C, wmOperator *op, const wmEvent *event) OPERATOR_RETVAL_CHECK(retval); BLI_assert(retval == OPERATOR_RUNNING_MODAL); - + return OPERATOR_RUNNING_MODAL; } @@ -1998,22 +2182,21 @@ static void wpaint_cancel(bContext *C, wmOperator *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"; - + /* 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; - + paint_stroke_operator_properties(ot); } @@ -2023,7 +2206,7 @@ void PAINT_OT_weight_paint(wmOperatorType *ot) * \note Keep in sync with #wpaint_mode_toggle_exec */ static int vpaint_mode_toggle_exec(bContext *C, wmOperator *op) -{ +{ 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; @@ -2038,7 +2221,7 @@ static int vpaint_mode_toggle_exec(bContext *C, wmOperator *op) } me = BKE_mesh_from_object(ob); - + /* toggle: end vpaint */ if (is_mode_set) { ob->mode &= ~mode_flag; @@ -2071,7 +2254,7 @@ static int vpaint_mode_toggle_exec(bContext *C, wmOperator *op) if (vp == NULL) vp = scene->toolsettings->vpaint = new_vpaint(0); - + paint_cursor_start(C, vertex_paint_poll); BKE_paint_init(scene, ePaintVertex, PAINT_CURSOR_VERTEX_PAINT); @@ -2091,24 +2274,23 @@ static int vpaint_mode_toggle_exec(bContext *C, wmOperator *op) /* update modifier stack for mapping requirements */ DEG_id_tag_update(&me->id, 0); - + WM_event_add_notifier(C, NC_SCENE | ND_MODE, scene); - + 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"; - + /* api callbacks */ ot->exec = vpaint_mode_toggle_exec; ot->poll = paint_poll_test; - + /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } @@ -2123,7 +2305,7 @@ void PAINT_OT_vertex_paint_toggle(wmOperatorType *ot) * - validate context (add mcol) * - create customdata storage * - call paint once (mouse click) - * - add modal handler + * - add modal handler * * Operator->modal() * - for every mousemove, apply vertex paint @@ -2142,6 +2324,8 @@ typedef struct PolyFaceMap { struct VPaintData { ViewContext vc; + struct NormalAnglePrecalc normal_angle_precalc; + uint paintcol; struct VertProjHandle *vp_handle; @@ -2180,7 +2364,7 @@ static bool vpaint_stroke_test_start(bContext *C, struct wmOperator *op, const f 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; @@ -2189,7 +2373,8 @@ static bool vpaint_stroke_test_start(bContext *C, struct wmOperator *op, const f vpd = MEM_callocN(sizeof(*vpd), "VPaintData"); paint_stroke_set_mode_data(stroke, vpd); view3d_set_viewcontext(C, &vpd->vc); - + view_angle_limits_init(&vpd->normal_angle_precalc, vp->normal_angle, (vp->flag & VP_FLAG_PROJECT_FLAT) == 0); + vpd->paintcol = vpaint_get_current_col(scene, vp); vpd->is_texbrush = !(brush->vertexpaint_tool == PAINT_BLEND_BLUR) && @@ -2253,16 +2438,17 @@ static void do_vpaint_brush_calc_average_color_cb_ex( memset(accum->value, 0, sizeof(accum->value)); SculptBrushTest test; - sculpt_brush_test_init(ss, &test); + SculptBrushTestFn sculpt_brush_test_sq_fn = + sculpt_brush_test_init_with_falloff_shape(ss, &test, data->vp->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_fast(&test, vd.co)) { + if (sculpt_brush_test_sq_fn(&test, vd.co)) { const int v_index = ccgdm ? data->me->mloop[vd.grid_indices[vd.g]].v : vd.vert_indices[vd.i]; - if (BKE_brush_curve_strength(data->brush, test.dist, cache->radius) > 0.0) { + 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) { @@ -2310,25 +2496,26 @@ static void do_vpaint_brush_draw_task_cb_ex( CCGDerivedMesh *ccgdm = BKE_pbvh_get_ccgdm(ss->pbvh); const struct SculptVertexPaintGeomMap *gmap = &ss->mode.vpaint.gmap; - Brush *brush = data->brush; - StrokeCache *cache = ss->cache; - const float brush_strength = cache->bstrength; + const Brush *brush = data->brush; + const StrokeCache *cache = ss->cache; uint *lcol = data->lcol; - Scene *scene = CTX_data_scene(data->C); + 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; - sculpt_brush_test_init(ss, &test); + SculptBrushTestFn sculpt_brush_test_sq_fn = + sculpt_brush_test_init_with_falloff_shape(ss, &test, data->vp->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(&test, vd.co)) { + 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 cooresponds to the current grid. * Otherwise, take the current vert. */ @@ -2340,9 +2527,15 @@ static void do_vpaint_brush_draw_task_cb_ex( 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. */ - const float view_dot = (vd.no) ? dot_vf3vs3(cache->sculpt_normal_symm, vd.no) : 1.0; - if (view_dot > 0.0f) { - const float brush_fade = BKE_brush_curve_strength(brush, test.dist, cache->radius); + float brush_strength = cache->bstrength; + const float angle_cos = (use_normal && vd.no) ? + dot_vf3vs3(ss->cache->sculpt_normal_symm, vd.no) : 1.0f; + if (((data->vp->flag & VP_FLAG_PROJECT_BACKFACE) || + (angle_cos > 0.0f)) && + ((data->vp->flag & VP_FLAG_PROJECT_FLAT) || + 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. */ @@ -2368,9 +2561,8 @@ static void do_vpaint_brush_draw_task_cb_ex( color_orig = ss->mode.vpaint.previous_color[l_index]; } float final_alpha = - 255 * brush_fade * brush_strength * view_dot * + 255 * brush_fade * brush_strength * tex_alpha * brush_alpha_pressure * grid_alpha; - if (brush->flag & BRUSH_ACCUMULATE) { float mask_accum = ss->mode.vpaint.previous_accum[l_index]; final_alpha = min_ff(final_alpha + mask_accum, 255.0f * brush_strength); @@ -2399,36 +2591,43 @@ static void do_vpaint_brush_blur_task_cb_ex( Scene *scene = CTX_data_scene(data->C); const struct SculptVertexPaintGeomMap *gmap = &ss->mode.vpaint.gmap; - Brush *brush = data->brush; - StrokeCache *cache = ss->cache; - const float brush_strength = cache->bstrength; + 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; - sculpt_brush_test_init(ss, &test); + SculptBrushTestFn sculpt_brush_test_sq_fn = + sculpt_brush_test_init_with_falloff_shape(ss, &test, data->vp->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(&test, vd.co)) { - /* For grid based pbvh, take the vert whose loop cooresponds to the current grid. + if (sculpt_brush_test_sq_fn(&test, vd.co)) { + /* For grid based pbvh, take the vert whose loop cooresponds to the current grid. * Otherwise, take the current vert. */ const int v_index = ccgdm ? data->me->mloop[vd.grid_indices[vd.g]].v : vd.vert_indices[vd.i]; const float grid_alpha = ccgdm ? 1.0f / vd.gridsize : 1.0f; const MVert *mv = &data->me->mvert[v_index]; - const float view_dot = (vd.no) ? dot_vf3vs3(cache->sculpt_normal_symm, vd.no) : 1.0; - if (view_dot > 0.0f) { - const float brush_fade = BKE_brush_curve_strength(brush, test.dist, cache->radius); + /* 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(ss->cache->sculpt_normal_symm, vd.no) : 1.0f; + if (((data->vp->flag & VP_FLAG_PROJECT_BACKFACE) || + (angle_cos > 0.0f)) && + ((data->vp->flag & VP_FLAG_PROJECT_FLAT) || + 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); - /* If the vertex is selected for painting. */ - if (!use_vert_sel || mv->flag & SELECT) { /* Get the average poly color */ uint color_final = 0; int total_hit_loops = 0; @@ -2472,8 +2671,8 @@ static void do_vpaint_brush_blur_task_cb_ex( } color_orig = ss->mode.vpaint.previous_color[l_index]; } - const float final_alpha = - 255 * brush_fade * brush_strength * view_dot * + 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. */ @@ -2499,13 +2698,13 @@ static void do_vpaint_brush_smear_task_cb_ex( Scene *scene = CTX_data_scene(data->C); const struct SculptVertexPaintGeomMap *gmap = &ss->mode.vpaint.gmap; - Brush *brush = data->brush; - StrokeCache *cache = ss->cache; - const float brush_strength = cache->bstrength; + 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; @@ -2515,14 +2714,15 @@ static void do_vpaint_brush_smear_task_cb_ex( if (normalize_v3(brush_dir) != 0.0f) { SculptBrushTest test; - sculpt_brush_test_init(ss, &test); + SculptBrushTestFn sculpt_brush_test_sq_fn = + sculpt_brush_test_init_with_falloff_shape(ss, &test, data->vp->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(&test, vd.co)) { + if (sculpt_brush_test_sq_fn(&test, vd.co)) { /* For grid based pbvh, take the vert whose loop cooresponds to the current grid. * Otherwise, take the current vert. */ const int v_index = ccgdm ? data->me->mloop[vd.grid_indices[vd.g]].v : vd.vert_indices[vd.i]; @@ -2533,9 +2733,15 @@ static void do_vpaint_brush_smear_task_cb_ex( 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. */ - const float view_dot = (vd.no) ? dot_vf3vs3(cache->sculpt_normal_symm, vd.no) : 1.0; - if (view_dot > 0.0f) { - const float brush_fade = BKE_brush_curve_strength(brush, test.dist, cache->radius); + float brush_strength = cache->bstrength; + const float angle_cos = (use_normal && vd.no) ? + dot_vf3vs3(ss->cache->sculpt_normal_symm, vd.no) : 1.0f; + if (((data->vp->flag & VP_FLAG_PROJECT_BACKFACE) || + (angle_cos > 0.0f)) && + ((data->vp->flag & VP_FLAG_PROJECT_FLAT) || + 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 @@ -2592,9 +2798,9 @@ static void do_vpaint_brush_smear_task_cb_ex( } color_orig = ss->mode.vpaint.previous_color[l_index]; } - const float final_alpha = + float final_alpha = 255 * brush_fade * brush_strength * - view_dot * brush_alpha_pressure * grid_alpha; + 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( @@ -2676,27 +2882,18 @@ static void vpaint_paint_leaves( } static void vpaint_do_paint( - bContext *C, Sculpt *sd, VPaint *vd, struct VPaintData *vpd, + 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); - SculptSearchSphereData data; - PBVHNode **nodes = NULL; - int totnode; - /* Build a list of all nodes that are potentially within the brush's area of influence */ - data.ss = ss; - data.sd = sd; - data.radius_squared = ss->cache->radius_squared; - data.original = true; - BKE_pbvh_search_gather(ss->pbvh, sculpt_search_sphere_cb, &data, &nodes, &totnode); - - sculpt_pbvh_calc_area_normal(brush, ob, nodes, totnode, true, ss->cache->sculpt_normal_symm); + int totnode; + PBVHNode **nodes = vwpaint_pbvh_gather_generic(ob, vp, sd, brush, &totnode); /* Paint those leaves. */ - vpaint_paint_leaves(C, sd, vd, vpd, ob, me, nodes, totnode); + vpaint_paint_leaves(C, sd, vp, vpd, ob, me, nodes, totnode); if (nodes) { MEM_freeN(nodes); @@ -2704,31 +2901,31 @@ static void vpaint_do_paint( } static void vpaint_do_radial_symmetry( - bContext *C, Sculpt *sd, VPaint *vd, struct VPaintData *vpd, Object *ob, Mesh *me, + 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 < vd->radial_symm[axis - 'X']; i++) { - const float angle = (2.0 * M_PI) * i / vd->radial_symm[axis - 'X']; - vpaint_do_paint(C, sd, vd, vpd, ob, me, brush, symm, axis, i, angle); + 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 *vd, struct VPaintData *vpd, Object *ob) + bContext *C, Sculpt *sd, VPaint *vp, struct VPaintData *vpd, Object *ob) { - Brush *brush = BKE_paint_brush(&vd->paint); + Brush *brush = BKE_paint_brush(&vp->paint); Mesh *me = ob->data; SculptSession *ss = ob->sculpt; StrokeCache *cache = ss->cache; - const char symm = vd->paint.symmetry_flags & PAINT_SYMM_AXIS_ALL; + const char symm = vp->paint.symmetry_flags & PAINT_SYMM_AXIS_ALL; int i = 0; /* initial stroke */ - vpaint_do_paint(C, sd, vd, vpd, ob, me, brush, i, 'X', 0, 0); - vpaint_do_radial_symmetry(C, sd, vd, vpd, ob, me, brush, i, 'X'); - vpaint_do_radial_symmetry(C, sd, vd, vpd, ob, me, brush, i, 'Y'); - vpaint_do_radial_symmetry(C, sd, vd, vpd, ob, me, brush, i, 'Z'); + 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; @@ -2740,16 +2937,16 @@ static void vpaint_do_symmetrical_brush_actions( sculpt_cache_calc_brushdata_symm(cache, i, 0, 0); if (i & (1 << 0)) { - vpaint_do_paint(C, sd, vd, vpd, ob, me, brush, i, 'X', 0, 0); - vpaint_do_radial_symmetry(C, sd, vd, vpd, ob, me, brush, i, 'X'); + 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, vd, vpd, ob, me, brush, i, 'Y', 0, 0); - vpaint_do_radial_symmetry(C, sd, vd, vpd, ob, me, brush, i, 'Y'); + 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, vd, vpd, ob, me, brush, i, 'Z', 0, 0); - vpaint_do_radial_symmetry(C, sd, vd, vpd, ob, me, brush, i, 'Z'); + 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'); } } } @@ -2824,10 +3021,11 @@ static int vpaint_invoke(bContext *C, wmOperator *op, const wmEvent *event) { 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; @@ -2838,15 +3036,16 @@ static int vpaint_invoke(bContext *C, wmOperator *op, const wmEvent *event) OPERATOR_RETVAL_CHECK(retval); BLI_assert(retval == 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); @@ -2871,14 +3070,14 @@ void PAINT_OT_vertex_paint(wmOperatorType *ot) 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; - + /* flags */ ot->flag = OPTYPE_UNDO | OPTYPE_BLOCKING; 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 a3da5a76dec..3b3e7297aec 100644 --- a/source/blender/editors/sculpt_paint/paint_vertex_color_utils.c +++ b/source/blender/editors/sculpt_paint/paint_vertex_color_utils.c @@ -281,7 +281,7 @@ BLI_INLINE uint mcol_darken(uint col1, uint col2, int fac) BLI_INLINE uint mcol_colordodge(uint col1, uint col2, int fac) { uchar *cp1, *cp2, *cp; - int mfac,temp; + int mfac, temp; uint col = 0; if (fac == 0) { 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 30d62d5a64e..ef86f3c773d 100644 --- a/source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c +++ b/source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c @@ -676,15 +676,14 @@ static void gradientVertInit__mapFunc( static int paint_weight_gradient_modal(bContext *C, wmOperator *op, const wmEvent *event) { - int ret = WM_gesture_straightline_modal(C, op, event); wmGesture *gesture = op->customdata; DMGradient_vertStoreBase *vert_cache = gesture->userdata; - bool do_gesture_free = false; + 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! */ - do_gesture_free = true; + WM_gesture_straightline_cancel(C, op); ret &= ~OPERATOR_RUNNING_MODAL; ret |= OPERATOR_FINISHED; } @@ -698,16 +697,14 @@ static int paint_weight_gradient_modal(bContext *C, wmOperator *op, const wmEven 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, OB_RECALC_DATA); WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); } else if (ret & OPERATOR_FINISHED) { wpaint_prev_destroy(&vert_cache->wpp); - } - - if (do_gesture_free) { - WM_gesture_straightline_cancel(C, op); + MEM_freeN(vert_cache); } return ret; @@ -743,6 +740,7 @@ static int paint_weight_gradient_exec(bContext *C, wmOperator *op) sizeof(DMGradient_vertStoreBase) + (sizeof(DMGradient_vertStore) * me->totvert), __func__); + gesture->userdata_free = false; data.is_init = true; wpaint_prev_create(&((DMGradient_vertStoreBase *)gesture->userdata)->wpp, me->dvert, me->totvert); 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 c05b0ba89cf..4d70d82d5c6 100644 --- a/source/blender/editors/sculpt_paint/paint_vertex_weight_utils.c +++ b/source/blender/editors/sculpt_paint/paint_vertex_weight_utils.c @@ -185,6 +185,93 @@ BLI_INLINE float wval_darken(const float weight, const float paintval, const flo 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; +} +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; +} +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; +} +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; +} +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; +} +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; +} +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; +} + /* vpaint has 'vpaint_blend_tool' */ /* result is not clamped from [0-1] */ float ED_wpaint_blend_tool( @@ -197,15 +284,27 @@ float ED_wpaint_blend_tool( case PAINT_BLEND_MIX: case PAINT_BLEND_AVERAGE: case PAINT_BLEND_SMEAR: - case PAINT_BLEND_BLUR: return wval_blend(weight, paintval, alpha); - case PAINT_BLEND_ADD: return wval_add(weight, paintval, alpha); - case PAINT_BLEND_SUB: return wval_sub(weight, paintval, alpha); - case PAINT_BLEND_MUL: return wval_mul(weight, paintval, alpha); - case PAINT_BLEND_LIGHTEN: return wval_lighten(weight, paintval, alpha); - case PAINT_BLEND_DARKEN: return wval_darken(weight, paintval, alpha); - default: - BLI_assert(0); - return 0.0f; + case PAINT_BLEND_BLUR: return wval_blend(weight, paintval, alpha); + case PAINT_BLEND_ADD: return wval_add(weight, paintval, alpha); + case PAINT_BLEND_SUB: return wval_sub(weight, paintval, alpha); + case PAINT_BLEND_MUL: return wval_mul(weight, paintval, alpha); + case PAINT_BLEND_LIGHTEN: return wval_lighten(weight, paintval, alpha); + case PAINT_BLEND_DARKEN: return wval_darken(weight, paintval, alpha); + /* Mostly make sense for color: support anyway. */ + case PAINT_BLEND_COLORDODGE: return wval_colordodge(weight, paintval, alpha); + case PAINT_BLEND_DIFFERENCE: return wval_difference(weight, paintval, alpha); + case PAINT_BLEND_SCREEN: return wval_screen(weight, paintval, alpha); + case PAINT_BLEND_HARDLIGHT: return wval_hardlight(weight, paintval, alpha); + case PAINT_BLEND_OVERLAY: return wval_overlay(weight, paintval, alpha); + case PAINT_BLEND_SOFTLIGHT: return wval_softlight(weight, paintval, alpha); + case PAINT_BLEND_EXCLUSION: return wval_exclusion(weight, paintval, alpha); + /* Only for color: just use blend. */ + case PAINT_BLEND_LUMINOCITY: + case PAINT_BLEND_SATURATION: + case PAINT_BLEND_HUE: + case PAINT_BLEND_ALPHA_SUB: + case PAINT_BLEND_ALPHA_ADD: + 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 d32db8973a0..ac5138deec7 100644 --- a/source/blender/editors/sculpt_paint/sculpt.c +++ b/source/blender/editors/sculpt_paint/sculpt.c @@ -523,6 +523,9 @@ void sculpt_brush_test_init(SculptSession *ss, SculptBrushTest *test) copy_v3_v3(test->location, ss->cache->location); test->dist = 0.0f; /* just for initialize */ + /* Only for 2D projection. */ + zero_v4(test->plane); + test->mirror_symmetry_pass = ss->cache->mirror_symmetry_pass; if (rv3d->rflag & RV3D_CLIPPING) { @@ -544,7 +547,7 @@ BLI_INLINE bool sculpt_brush_test_clipping(const SculptBrushTest *test, const fl return ED_view3d_clipping_test(rv3d, symm_co, true); } -bool sculpt_brush_test(SculptBrushTest *test, const float co[3]) +bool sculpt_brush_test_sphere(SculptBrushTest *test, const float co[3]) { float distsq = len_squared_v3v3(co, test->location); @@ -560,7 +563,7 @@ bool sculpt_brush_test(SculptBrushTest *test, const float co[3]) } } -bool sculpt_brush_test_sq(SculptBrushTest *test, const float co[3]) +bool sculpt_brush_test_sphere_sq(SculptBrushTest *test, const float co[3]) { float distsq = len_squared_v3v3(co, test->location); @@ -576,7 +579,7 @@ bool sculpt_brush_test_sq(SculptBrushTest *test, const float co[3]) } } -bool sculpt_brush_test_fast(const SculptBrushTest *test, const float co[3]) +bool sculpt_brush_test_sphere_fast(const SculptBrushTest *test, const float co[3]) { if (sculpt_brush_test_clipping(test, co)) { return 0; @@ -584,6 +587,24 @@ bool sculpt_brush_test_fast(const SculptBrushTest *test, const float co[3]) 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, 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; + } +} + bool sculpt_brush_test_cube(SculptBrushTest *test, const float co[3], float local[4][4]) { float side = M_SQRT1_2; @@ -639,7 +660,7 @@ static float frontface(Brush *br, const float sculpt_normal[3], static bool sculpt_brush_test_cyl(SculptBrushTest *test, float co[3], float location[3], const float area_no[3]) { - if (sculpt_brush_test_fast(test, co)) { + if (sculpt_brush_test_sphere_fast(test, co)) { float t1[3], t2[3], t3[3], dist; sub_v3_v3v3(t1, location, co); @@ -786,7 +807,7 @@ static void calc_area_normal_and_center_task_cb(void *userdata, const int n) closest_on_tri_to_point_v3(co, test.location, UNPACK3(co_tri)); - if (sculpt_brush_test_fast(&test, co)) { + if (sculpt_brush_test_sphere_fast(&test, co)) { float no[3]; int flip_index; @@ -820,7 +841,7 @@ static void calc_area_normal_and_center_task_cb(void *userdata, const int n) co = vd.co; } - if (sculpt_brush_test_fast(&test, co)) { + if (sculpt_brush_test_sphere_fast(&test, co)) { float no_buf[3]; const float *no; int flip_index; @@ -1213,6 +1234,24 @@ bool sculpt_search_sphere_cb(PBVHNode *node, void *data_v) 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]; + + 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( + data->dist_ray_to_aabb_precalc, bb_min, bb_max, dummy_co, &dummy_depth); + + return dist_sq < data->radius_squared; +} + /* 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]) { @@ -1530,7 +1569,7 @@ static void do_smooth_brush_mesh_task_cb_ex( BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { - if (sculpt_brush_test(&test, vd.co)) { + if (sculpt_brush_test_sphere(&test, vd.co)) { const float fade = bstrength * tex_strength( ss, brush, vd.co, test.dist, vd.no, vd.fno, smooth_mask ? 0.0f : (vd.mask ? *vd.mask : 0.0f), @@ -1578,7 +1617,7 @@ static void do_smooth_brush_bmesh_task_cb_ex( BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { - if (sculpt_brush_test(&test, vd.co)) { + if (sculpt_brush_test_sphere(&test, vd.co)) { const float fade = bstrength * tex_strength( ss, brush, vd.co, test.dist, vd.no, vd.fno, smooth_mask ? 0.0f : *vd.mask, thread_id); @@ -1717,7 +1756,7 @@ static void do_smooth_brush_multires_task_cb_ex( fno = CCG_elem_offset_no(&key, gddata, index); mask = CCG_elem_offset_mask(&key, gddata, index); - if (sculpt_brush_test(&test, co)) { + if (sculpt_brush_test_sphere(&test, co)) { const float strength_mask = (smooth_mask ? 0.0f : *mask); const float fade = bstrength * tex_strength( ss, brush, co, test.dist, NULL, fno, strength_mask, thread_id); @@ -1837,7 +1876,7 @@ static void do_mask_brush_draw_task_cb_ex( BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { - if (sculpt_brush_test(&test, vd.co)) { + if (sculpt_brush_test_sphere(&test, vd.co)) { const float fade = tex_strength(ss, brush, vd.co, test.dist, vd.no, vd.fno, 0.0f, thread_id); (*vd.mask) += fade * bstrength; @@ -1897,7 +1936,7 @@ static void do_draw_brush_task_cb_ex( BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { - if (sculpt_brush_test(&test, vd.co)) { + if (sculpt_brush_test_sphere(&test, vd.co)) { /* offset vertex */ const float fade = tex_strength( ss, brush, vd.co, test.dist, vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, thread_id); @@ -1958,7 +1997,7 @@ static void do_crease_brush_task_cb_ex( BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { - if (sculpt_brush_test(&test, vd.co)) { + if (sculpt_brush_test_sphere(&test, vd.co)) { /* offset vertex */ const float fade = tex_strength( ss, brush, vd.co, test.dist, vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, thread_id); @@ -2044,7 +2083,7 @@ static void do_pinch_brush_task_cb_ex( BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { - if (sculpt_brush_test(&test, vd.co)) { + if (sculpt_brush_test_sphere(&test, vd.co)) { const float fade = bstrength * tex_strength( ss, brush, vd.co, test.dist, vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, thread_id); float val[3]; @@ -2096,7 +2135,7 @@ static void do_grab_brush_task_cb_ex( { sculpt_orig_vert_data_update(&orig_data, &vd); - if (sculpt_brush_test(&test, orig_data.co)) { + if (sculpt_brush_test_sphere(&test, orig_data.co)) { const float fade = bstrength * tex_strength( ss, brush, orig_data.co, test.dist, orig_data.no, NULL, vd.mask ? *vd.mask : 0.0f, thread_id); @@ -2151,7 +2190,7 @@ static void do_nudge_brush_task_cb_ex( BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { - if (sculpt_brush_test(&test, vd.co)) { + if (sculpt_brush_test_sphere(&test, vd.co)) { const float fade = bstrength * tex_strength( ss, brush, vd.co, test.dist, vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, thread_id); @@ -2210,7 +2249,7 @@ static void do_snake_hook_brush_task_cb_ex( BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { - if (sculpt_brush_test(&test, vd.co)) { + if (sculpt_brush_test_sphere(&test, vd.co)) { const float fade = bstrength * tex_strength( ss, brush, vd.co, test.dist, vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, thread_id); @@ -2311,7 +2350,7 @@ static void do_thumb_brush_task_cb_ex( { sculpt_orig_vert_data_update(&orig_data, &vd); - if (sculpt_brush_test(&test, orig_data.co)) { + if (sculpt_brush_test_sphere(&test, orig_data.co)) { const float fade = bstrength * tex_strength( ss, brush, orig_data.co, test.dist, orig_data.no, NULL, vd.mask ? *vd.mask : 0.0f, thread_id); @@ -2371,7 +2410,7 @@ static void do_rotate_brush_task_cb_ex( { sculpt_orig_vert_data_update(&orig_data, &vd); - if (sculpt_brush_test(&test, orig_data.co)) { + if (sculpt_brush_test_sphere(&test, orig_data.co)) { float vec[3], rot[3][3]; const float fade = bstrength * tex_strength( ss, brush, orig_data.co, test.dist, orig_data.no, NULL, vd.mask ? *vd.mask : 0.0f, @@ -2439,7 +2478,7 @@ static void do_layer_brush_task_cb_ex( { sculpt_orig_vert_data_update(&orig_data, &vd); - if (sculpt_brush_test(&test, orig_data.co)) { + if (sculpt_brush_test_sphere(&test, orig_data.co)) { const float fade = bstrength * tex_strength( ss, brush, vd.co, test.dist, vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, thread_id); float *disp = &layer_disp[vd.i]; @@ -2511,7 +2550,7 @@ static void do_inflate_brush_task_cb_ex( BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { - if (sculpt_brush_test(&test, vd.co)) { + if (sculpt_brush_test_sphere(&test, vd.co)) { const float fade = bstrength * tex_strength( ss, brush, vd.co, test.dist, vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, thread_id); float val[3]; @@ -2617,16 +2656,6 @@ static void calc_sculpt_plane( } } -/* Projects a point onto a plane along the plane's normal */ -static void point_plane_project( - float intr[3], - const float co[3], const float plane_normal[3], const float plane_center[3]) -{ - sub_v3_v3v3(intr, co, plane_center); - mul_v3_v3fl(intr, plane_normal, dot_v3v3(plane_normal, intr)); - sub_v3_v3v3(intr, co, intr); -} - static int plane_trim(const StrokeCache *cache, const Brush *brush, const float val[3]) { return (!(brush->flag & BRUSH_PLANE_TRIM) || @@ -2634,26 +2663,18 @@ static int plane_trim(const StrokeCache *cache, const Brush *brush, const float } static bool plane_point_side_flip( - const float co[3], const float plane_normal[3], const float plane_center[3], + const float co[3], const float plane[4], const bool flip) { - float delta[3]; - float d; - - sub_v3_v3v3(delta, co, plane_center); - d = dot_v3v3(plane_normal, delta); - + 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_normal[3], const float plane_center[3]) +static int plane_point_side(const float co[3], const float plane[4]) { - float delta[3]; - - sub_v3_v3v3(delta, co, plane_center); - return dot_v3v3(plane_normal, delta) <= 0.0f; + float d = plane_point_side_v3(plane, co); + return d <= 0.0f; } static float get_offset(Sculpt *sd, SculptSession *ss) @@ -2686,14 +2707,15 @@ static void do_flatten_brush_task_cb_ex( 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, area_co, area_no); BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { - if (sculpt_brush_test_sq(&test, vd.co)) { + if (sculpt_brush_test_sphere_sq(&test, vd.co)) { float intr[3]; float val[3]; - point_plane_project(intr, vd.co, area_no, area_co); + closest_to_plane_normalized_v3(intr, test.plane, vd.co); sub_v3_v3v3(val, intr, vd.co); @@ -2762,15 +2784,16 @@ static void do_clay_brush_task_cb_ex( 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, area_co, area_no); BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { - if (sculpt_brush_test_sq(&test, vd.co)) { - if (plane_point_side_flip(vd.co, area_no, area_co, flip)) { + if (sculpt_brush_test_sphere_sq(&test, vd.co)) { + if (plane_point_side_flip(vd.co, test.plane, flip)) { float intr[3]; float val[3]; - point_plane_project(intr, vd.co, area_no, area_co); + closest_to_plane_normalized_v3(intr, test.plane, vd.co); sub_v3_v3v3(val, intr, vd.co); @@ -2846,15 +2869,16 @@ static void do_clay_strips_brush_task_cb_ex( 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, 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, area_no_sp, area_co, flip)) { + if (plane_point_side_flip(vd.co, test.plane, flip)) { float intr[3]; float val[3]; - point_plane_project(intr, vd.co, area_no_sp, area_co); + closest_to_plane_normalized_v3(intr, test.plane, vd.co); sub_v3_v3v3(val, intr, vd.co); @@ -2953,15 +2977,16 @@ static void do_fill_brush_task_cb_ex( 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, area_co, area_no); BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { - if (sculpt_brush_test_sq(&test, vd.co)) { - if (plane_point_side(vd.co, area_no, area_co)) { + if (sculpt_brush_test_sphere_sq(&test, vd.co)) { + if (plane_point_side(vd.co, test.plane)) { float intr[3]; float val[3]; - point_plane_project(intr, vd.co, area_no, area_co); + closest_to_plane_normalized_v3(intr, test.plane, vd.co); sub_v3_v3v3(val, intr, vd.co); @@ -3031,15 +3056,16 @@ static void do_scrape_brush_task_cb_ex( 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, area_co, area_no); BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { - if (sculpt_brush_test_sq(&test, vd.co)) { - if (!plane_point_side(vd.co, area_no, area_co)) { + if (sculpt_brush_test_sphere_sq(&test, vd.co)) { + if (!plane_point_side(vd.co, test.plane)) { float intr[3]; float val[3]; - point_plane_project(intr, vd.co, area_no, area_co); + closest_to_plane_normalized_v3(intr, test.plane, vd.co); sub_v3_v3v3(val, intr, vd.co); @@ -3109,7 +3135,7 @@ static void do_gravity_task_cb_ex( sculpt_brush_test_init(ss, &test); BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { - if (sculpt_brush_test_sq(&test, vd.co)) { + if (sculpt_brush_test_sphere_sq(&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, thread_id); diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h index 27d8fbaa340..425cecb0010 100644 --- a/source/blender/editors/sculpt_paint/sculpt_intern.h +++ b/source/blender/editors/sculpt_paint/sculpt_intern.h @@ -181,10 +181,15 @@ typedef struct SculptBrushTest { float dist; int mirror_symmetry_pass; + /* For circle (not sphere) projection. */ + float plane[4]; + /* 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; @@ -192,12 +197,22 @@ typedef struct { bool original; } SculptSearchSphereData; +typedef struct { + 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); -bool sculpt_brush_test(SculptBrushTest *test, const float co[3]); -bool sculpt_brush_test_sq(SculptBrushTest *test, const float co[3]); -bool sculpt_brush_test_fast(const SculptBrushTest *test, const float co[3]); +bool sculpt_brush_test_sphere(SculptBrushTest *test, const float co[3]); +bool sculpt_brush_test_sphere_sq(SculptBrushTest *test, const float co[3]); +bool sculpt_brush_test_sphere_fast(const SculptBrushTest *test, const float co[3]); bool sculpt_brush_test_cube(SculptBrushTest *test, const float co[3], float local[4][4]); +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); float tex_strength( struct SculptSession *ss, struct Brush *br, const float point[3], diff --git a/source/blender/imbuf/intern/tiff.c b/source/blender/imbuf/intern/tiff.c index 8e5cf80e013..98aa7c5353b 100644 --- a/source/blender/imbuf/intern/tiff.c +++ b/source/blender/imbuf/intern/tiff.c @@ -813,26 +813,51 @@ int imb_savetiff(ImBuf *ibuf, const char *name, int flags) } /* copy pixel data. While copying, we flip the image vertically. */ + const int channels_in_float = ibuf->channels ? ibuf->channels : 4; for (x = 0; x < ibuf->x; x++) { for (y = 0; y < ibuf->y; y++) { - from_i = 4 * (y * ibuf->x + x); + from_i = ((size_t)channels_in_float) * (y * ibuf->x + x); to_i = samplesperpixel * ((ibuf->y - y - 1) * ibuf->x + x); if (pixels16) { /* convert from float source */ float rgb[4]; - - if (ibuf->float_colorspace || (ibuf->colormanage_flag & IMB_COLORMANAGE_IS_DATA)) { - /* float buffer was managed already, no need in color space conversion */ - copy_v3_v3(rgb, &fromf[from_i]); + + if (channels_in_float == 3 || channels_in_float == 4) { + if (ibuf->float_colorspace || + (ibuf->colormanage_flag & IMB_COLORMANAGE_IS_DATA)) + { + /* Float buffer was managed already, no need in color + * space conversion. + */ + copy_v3_v3(rgb, &fromf[from_i]); + } + else { + /* Standard linear-to-srgb conversion if float buffer + * wasn't managed. + */ + linearrgb_to_srgb_v3_v3(rgb, &fromf[from_i]); + } + if (channels_in_float == 4) { + rgb[3] = fromf[from_i + 3]; + } + else { + rgb[3] = 1.0f; + } } else { - /* standard linear-to-srgb conversion if float buffer wasn't managed */ - linearrgb_to_srgb_v3_v3(rgb, &fromf[from_i]); + if (ibuf->float_colorspace || + (ibuf->colormanage_flag & IMB_COLORMANAGE_IS_DATA)) + { + rgb[0] = fromf[from_i]; + } + else { + rgb[0] = linearrgb_to_srgb(fromf[from_i]); + } + rgb[1] = rgb[2] = rgb[0]; + rgb[3] = 1.0f; } - rgb[3] = fromf[from_i + 3]; - for (i = 0; i < samplesperpixel; i++, to_i++) to16[to_i] = FTOUSHORT(rgb[i]); } diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h index e073c6a9f13..4c1accdcdf1 100644 --- a/source/blender/makesdna/DNA_scene_types.h +++ b/source/blender/makesdna/DNA_scene_types.h @@ -1121,18 +1121,26 @@ typedef struct UvSculpt { /* Vertex Paint */ typedef struct VPaint { Paint paint; - short flag, pad; + short flag; + char falloff_shape, normal_angle; int radial_symm[3]; /* For mirrored painting */ } VPaint; /* VPaint.flag */ enum { - // VP_COLINDEX = (1 << 0), /* only paint onto active material*/ /* deprecated since before 2.49 */ - // VP_AREA = (1 << 1), /* deprecated since 2.70 */ - VP_NORMALS = (1 << 3), - VP_SPRAY = (1 << 4), - // VP_MIRROR_X = (1 << 5), /* deprecated in 2.5x use (me->editflag & ME_EDIT_MIRROR_X) */ - VP_ONLYVGROUP = (1 << 7) /* weight paint only */ + VP_FLAG_PROJECT_BACKFACE = (1 << 0), + /* TODO */ + // VP_FLAG_PROJECT_XRAY = (1 << 1), + VP_FLAG_PROJECT_FLAT = (1 << 3), + VP_FLAG_SPRAY = (1 << 4), + /* weight paint only */ + VP_FLAG_VGROUP_RESTRICT = (1 << 7) +}; + +/* VPaint.falloff_shape */ +enum { + VP_FALLOFF_SHAPE_SPHERE = 0, + VP_FALLOFF_SHAPE_TUBE = 1, }; /* ------------------------------------------- */ diff --git a/source/blender/makesrna/intern/rna_sculpt_paint.c b/source/blender/makesrna/intern/rna_sculpt_paint.c index 106098d22d6..adf647d2dd6 100644 --- a/source/blender/makesrna/intern/rna_sculpt_paint.c +++ b/source/blender/makesrna/intern/rna_sculpt_paint.c @@ -690,23 +690,44 @@ static void rna_def_vertex_paint(BlenderRNA *brna) RNA_def_struct_path_func(srna, "rna_VertexPaint_path"); RNA_def_struct_ui_text(srna, "Vertex Paint", "Properties of vertex and weight paint mode"); - /* vertex paint only */ - prop = RNA_def_property(srna, "use_normal", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "flag", VP_NORMALS); - RNA_def_property_ui_text(prop, "Normals", "Apply the vertex normal before painting"); + static EnumPropertyItem prop_falloff_items[] = { + {VP_FALLOFF_SHAPE_SPHERE, "SPHERE", 0, "Sphere", "Spherical falloff from the brush"}, + {VP_FALLOFF_SHAPE_TUBE, "TUBE", 0, "Circle", "Circular falloff from the brush along the view"}, + {0, NULL, 0, NULL, NULL} + }; + + prop = RNA_def_property(srna, "falloff_shape", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "falloff_shape"); + RNA_def_property_enum_items(prop, prop_falloff_items); + RNA_def_property_ui_text(prop, "Falloff", ""); + RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); + + prop = RNA_def_property(srna, "use_backface_culling", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", VP_FLAG_PROJECT_BACKFACE); + RNA_def_property_ui_text(prop, "Cull", "Ignore vertices pointing away from the view (faster)"); + RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); + + prop = RNA_def_property(srna, "use_normal_falloff", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", VP_FLAG_PROJECT_FLAT); + RNA_def_property_ui_text(prop, "Normals", "Paint most on faces pointing towards the view"); RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); + prop = RNA_def_property(srna, "use_spray", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "flag", VP_SPRAY); + RNA_def_property_boolean_sdna(prop, NULL, "flag", VP_FLAG_SPRAY); RNA_def_property_ui_text(prop, "Spray", "Keep applying paint effect while holding mouse"); RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); /* weight paint only */ prop = RNA_def_property(srna, "use_group_restrict", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "flag", VP_ONLYVGROUP); + RNA_def_property_boolean_sdna(prop, NULL, "flag", VP_FLAG_VGROUP_RESTRICT); RNA_def_property_ui_text(prop, "Restrict", "Restrict painting to vertices in the group"); RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); + prop = RNA_def_property(srna, "normal_angle", PROP_INT, PROP_UNSIGNED); + RNA_def_property_range(prop, 0, 90); + RNA_def_property_ui_text(prop, "Angle", "Paint most on faces pointing towards the view according to this angle"); + /* Mirroring */ prop = RNA_def_property(srna, "radial_symmetry", PROP_INT, PROP_XYZ); RNA_def_property_int_sdna(prop, NULL, "radial_symm"); diff --git a/source/blender/windowmanager/WM_types.h b/source/blender/windowmanager/WM_types.h index 7fe9f3a8ab4..9df9afcb064 100644 --- a/source/blender/windowmanager/WM_types.h +++ b/source/blender/windowmanager/WM_types.h @@ -428,6 +428,7 @@ typedef struct wmGesture { /* free pointer to use for operator allocs (if set, its freed on exit)*/ void *userdata; + bool userdata_free; } wmGesture; /* ************** wmEvent ************************ */ diff --git a/source/blender/windowmanager/intern/wm_gesture.c b/source/blender/windowmanager/intern/wm_gesture.c index 30d1fa9d5ca..77030fac5ea 100644 --- a/source/blender/windowmanager/intern/wm_gesture.c +++ b/source/blender/windowmanager/intern/wm_gesture.c @@ -71,6 +71,7 @@ wmGesture *WM_gesture_new(bContext *C, const wmEvent *event, int type) gesture->type = type; gesture->event_type = event->type; gesture->swinid = ar->swinid; /* means only in area-region context! */ + gesture->userdata_free = true; /* Free if userdata is set. */ wm_subwindow_origin_get(window, gesture->swinid, &sx, &sy); @@ -114,7 +115,7 @@ void WM_gesture_end(bContext *C, wmGesture *gesture) win->tweak = NULL; BLI_remlink(&win->gesture, gesture); MEM_freeN(gesture->customdata); - if (gesture->userdata) { + if (gesture->userdata && gesture->userdata_free) { MEM_freeN(gesture->userdata); } MEM_freeN(gesture); |