Commit D14179: Revamp Vertex Paint With C++

- Verrtex paint mode has been refactored into C++ templates.
  It now works with both byte and float colors and point
  & corner attribute domains.
- There is a new API for mixing colors (also based
  on C++ templates).  Unlike the existing APIs byte
  and float colors are interpolated identically.
  Interpolation does happen in a squared rgb space,
  this may be changed in the future.
- Vertex paint now uses the sculpt undo system.

Reviewed By: Brecht Van Lommel.

Differential Revision: https://developer.blender.org/D14179
Ref D14179
This commit is contained in:
Joseph Eagar 2022-04-20 22:03:45 -07:00
parent c6ed879f9a
commit 575ade22d4
Notes: blender-bot 2023-07-12 09:46:06 +02:00
Referenced by issue #98884, Regression: Crash when switched to vertex paint mode
Referenced by issue #97597, Regression: Crash in weight painting
Referenced by issue #97489, Unify Interpolation In Vertex Paint And Sculpt Mode
Referenced by issue #97183, Regression: Vertex paint mode (old style) work only with 1st attribute layer, no matter what selected is
Referenced by issue #69760, Undo/Adjust Last Operation: vertex and weightpaint operators/strokes undo more then they should (change back any setting changed prior to execution)
Referenced by issue #107845, Vertex paint mode breaks permanently under certain conditions (Global undo involved)
Referenced by pull request #109971, Fix #109822: Average Brush in Vertex Paint Mode is broken
Referenced by commit ac3f4e959f, Fix #109822: Average Brush in Vertex Paint Mode is broken
18 changed files with 2428 additions and 1330 deletions

@ -1 +1 @@
Subproject commit 63699f968344db7dc853d2c5972325beea44900c
Subproject commit 716dc02ec30c0810513f7b4adc4ae865ae50c4e6

@ -1 +1 @@
Subproject commit baa581415c7ed23d7c45ef873631748135672683
Subproject commit 787ea78f7fa6f0373d80ba1247768402df93f8ad

View File

@ -615,9 +615,6 @@ typedef struct SculptSession {
union {
struct {
struct SculptVertexPaintGeomMap gmap;
/* For non-airbrush painting to re-apply from the original (MLoop aligned). */
unsigned int *previous_color;
} vpaint;
struct {

View File

@ -1341,8 +1341,6 @@ void BKE_sculptsession_free_vwpaint_data(struct SculptSession *ss)
struct SculptVertexPaintGeomMap *gmap = NULL;
if (ss->mode_type == OB_MODE_VERTEX_PAINT) {
gmap = &ss->mode.vpaint.gmap;
MEM_SAFE_FREE(ss->mode.vpaint.previous_color);
}
else if (ss->mode_type == OB_MODE_WEIGHT_PAINT) {
gmap = &ss->mode.wpaint.gmap;

View File

@ -345,5 +345,7 @@ BLI_color_convert_to_theme4b(const ColorSceneLinear4f<eAlpha::Straight> &scene_l
using ColorGeometry4f = ColorSceneLinear4f<eAlpha::Premultiplied>;
using ColorGeometry4b = ColorSceneLinearByteEncoded4b<eAlpha::Premultiplied>;
using ColorPaint4f = ColorSceneLinear4f<eAlpha::Straight>;
using ColorPaint4b = ColorSceneLinearByteEncoded4b<eAlpha::Straight>;
} // namespace blender

File diff suppressed because it is too large Load Diff

View File

@ -171,6 +171,7 @@ set(SRC
BLI_boxpack_2d.h
BLI_buffer.h
BLI_color.hh
BLI_color_mix.hh
BLI_compiler_attrs.h
BLI_compiler_compat.h
BLI_compiler_typecheck.h

View File

@ -2448,6 +2448,54 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
}
/* Rebuild active/render color attribute references. */
if (!MAIN_VERSION_ATLEAST(bmain, 302, 6)) {
LISTBASE_FOREACH (Brush *, br, &bmain->brushes) {
/* buggy code in wm_toolsystem broke smear in old files,
reset to defaults */
if (br->sculpt_tool == SCULPT_TOOL_SMEAR) {
br->alpha = 1.0f;
br->spacing = 5;
br->flag &= ~BRUSH_ALPHA_PRESSURE;
br->flag &= ~BRUSH_SPACE_ATTEN;
br->curve_preset = BRUSH_CURVE_SPHERE;
}
}
LISTBASE_FOREACH (Mesh *, me, &bmain->meshes) {
for (int step = 0; step < 2; step++) {
CustomDataLayer *actlayer = NULL;
int vact1, vact2;
if (step) {
vact1 = CustomData_get_render_layer_index(&me->vdata, CD_PROP_COLOR);
vact2 = CustomData_get_render_layer_index(&me->ldata, CD_PROP_BYTE_COLOR);
}
else {
vact1 = CustomData_get_active_layer_index(&me->vdata, CD_PROP_COLOR);
vact2 = CustomData_get_active_layer_index(&me->ldata, CD_PROP_BYTE_COLOR);
}
if (vact1 != -1) {
actlayer = me->vdata.layers + vact1;
}
else if (vact2 != -1) {
actlayer = me->ldata.layers + vact2;
}
if (actlayer) {
if (step) {
BKE_id_attributes_render_color_set(&me->id, actlayer);
}
else {
BKE_id_attributes_active_color_set(&me->id, actlayer);
}
}
}
}
}
if (!MAIN_VERSION_ATLEAST(bmain, 302, 7)) {
/* Generate 'system' liboverrides IDs.
* NOTE: This is a fairly rough process, based on very basic heuristics. Should be enough for a

View File

@ -271,6 +271,14 @@ static eV3DShadingColorType workbench_color_type_get(WORKBENCH_PrivateData *wpd,
BKE_pbvh_is_drawing_set(ob->sculpt->pbvh, is_sculpt_pbvh);
}
const CustomData *cd_vdata = workbench_mesh_get_vert_custom_data(me);
const CustomData *cd_ldata = workbench_mesh_get_loop_custom_data(me);
bool has_color = (CustomData_has_layer(cd_vdata, CD_PROP_COLOR) ||
CustomData_has_layer(cd_vdata, CD_PROP_BYTE_COLOR) ||
CustomData_has_layer(cd_ldata, CD_PROP_COLOR) ||
CustomData_has_layer(cd_ldata, CD_PROP_BYTE_COLOR));
if (color_type == V3D_SHADING_TEXTURE_COLOR) {
if (ob->dt < OB_TEXTURE) {
color_type = V3D_SHADING_MATERIAL_COLOR;
@ -285,14 +293,6 @@ static eV3DShadingColorType workbench_color_type_get(WORKBENCH_PrivateData *wpd,
color_type = V3D_SHADING_OBJECT_COLOR;
}
else {
const CustomData *cd_vdata = workbench_mesh_get_vert_custom_data(me);
const CustomData *cd_ldata = workbench_mesh_get_loop_custom_data(me);
bool has_color = (CustomData_has_layer(cd_vdata, CD_PROP_COLOR) ||
CustomData_has_layer(cd_vdata, CD_PROP_BYTE_COLOR) ||
CustomData_has_layer(cd_ldata, CD_PROP_COLOR) ||
CustomData_has_layer(cd_ldata, CD_PROP_BYTE_COLOR));
if (!has_color) {
color_type = V3D_SHADING_OBJECT_COLOR;
}
@ -314,7 +314,7 @@ static eV3DShadingColorType workbench_color_type_get(WORKBENCH_PrivateData *wpd,
*r_texpaint_mode = true;
}
}
else if (is_vertpaint_mode && me && CustomData_has_layer(ldata, CD_PROP_BYTE_COLOR)) {
else if (is_vertpaint_mode && me && has_color) {
color_type = V3D_SHADING_VERTEX_COLOR;
}
}

View File

@ -428,19 +428,19 @@ int ED_mesh_color_add(
bool ED_mesh_color_ensure(struct Mesh *me, const char *name)
{
BLI_assert(me->edit_mesh == NULL);
CustomDataLayer *layer = BKE_id_attributes_active_color_get(&me->id);
if (!me->mloopcol && me->totloop) {
CustomData_add_layer_named(
&me->ldata, CD_PROP_BYTE_COLOR, CD_DEFAULT, NULL, me->totloop, name);
int layer_i = CustomData_get_layer_index(&me->ldata, CD_PROP_BYTE_COLOR);
if (!layer) {
CustomData_add_layer_named(&me->ldata, CD_PROP_BYTE_COLOR, CD_DEFAULT, NULL, me->totloop, name);
layer = me->ldata.layers + CustomData_get_layer_index(&me->ldata, CD_PROP_BYTE_COLOR);
BKE_id_attributes_active_color_set(&me->id, me->ldata.layers + layer_i);
BKE_id_attributes_active_color_set(&me->id, layer);
BKE_mesh_update_customdata_pointers(me, true);
}
DEG_id_tag_update(&me->id, 0);
return (me->mloopcol != NULL);
return (layer != NULL);
}
bool ED_mesh_color_remove_index(Mesh *me, const int n)

View File

@ -48,7 +48,7 @@ set(SRC
paint_ops.c
paint_stroke.c
paint_utils.c
paint_vertex.c
paint_vertex.cc
paint_vertex_color_ops.c
paint_vertex_color_utils.c
paint_vertex_proj.c

View File

@ -133,7 +133,9 @@ void PAINT_OT_weight_gradient(struct wmOperatorType *ot);
void PAINT_OT_vertex_paint_toggle(struct wmOperatorType *ot);
void PAINT_OT_vertex_paint(struct wmOperatorType *ot);
unsigned int vpaint_get_current_col(struct Scene *scene, struct VPaint *vp, bool secondary);
unsigned int vpaint_get_current_color(struct Scene *scene,
struct VPaint *vp,
bool secondary);
/* paint_vertex_color_utils.c */

View File

@ -47,75 +47,6 @@ static void tag_object_after_update(Object *object)
BKE_mesh_batch_cache_dirty_tag(mesh, BKE_MESH_BATCH_DIRTY_ALL);
}
/* -------------------------------------------------------------------- */
/** \name Set Vertex Colors Operator
* \{ */
static bool vertex_color_set(Object *ob, uint paintcol)
{
Mesh *me;
if (((me = BKE_mesh_from_object(ob)) == NULL) || (ED_mesh_color_ensure(me, NULL) == false)) {
return false;
}
const bool use_face_sel = (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
const bool use_vert_sel = (me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0;
const MPoly *mp = me->mpoly;
for (int i = 0; i < me->totpoly; i++, mp++) {
MLoopCol *lcol = me->mloopcol + mp->loopstart;
if (use_face_sel && !(mp->flag & ME_FACE_SEL)) {
continue;
}
int j = 0;
do {
uint vidx = me->mloop[mp->loopstart + j].v;
if (!(use_vert_sel && !(me->mvert[vidx].flag & SELECT))) {
*(int *)lcol = paintcol;
}
lcol++;
j++;
} while (j < mp->totloop);
}
/* remove stale me->mcol, will be added later */
BKE_mesh_tessface_clear(me);
tag_object_after_update(ob);
return true;
}
static int vertex_color_set_exec(bContext *C, wmOperator *UNUSED(op))
{
Scene *scene = CTX_data_scene(C);
Object *obact = CTX_data_active_object(C);
uint paintcol = vpaint_get_current_col(scene, scene->toolsettings->vpaint, false);
if (vertex_color_set(obact, paintcol)) {
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, obact);
return OPERATOR_FINISHED;
}
return OPERATOR_CANCELLED;
}
void PAINT_OT_vertex_color_set(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Set Vertex Colors";
ot->idname = "PAINT_OT_vertex_color_set";
ot->description = "Fill the active vertex color layer with the current paint color";
/* api callbacks */
ot->exec = vertex_color_set_exec;
ot->poll = vertex_paint_mode_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
/** \} */
/* -------------------------------------------------------------------- */

View File

@ -73,570 +73,3 @@ bool ED_vpaint_color_transform(struct Object *ob,
return true;
}
/* -------------------------------------------------------------------- */
/** \name Color Blending Modes
* \{ */
BLI_INLINE uint mcol_blend(uint col_src, uint col_dst, int fac)
{
uchar *cp_src, *cp_dst, *cp_mix;
int mfac;
uint col_mix = 0;
if (fac == 0) {
return col_src;
}
if (fac >= 255) {
return col_dst;
}
mfac = 255 - fac;
cp_src = (uchar *)&col_src;
cp_dst = (uchar *)&col_dst;
cp_mix = (uchar *)&col_mix;
/* Updated to use the rgb squared color model which blends nicer. */
int r1 = cp_src[0] * cp_src[0];
int g1 = cp_src[1] * cp_src[1];
int b1 = cp_src[2] * cp_src[2];
int a1 = cp_src[3] * cp_src[3];
int r2 = cp_dst[0] * cp_dst[0];
int g2 = cp_dst[1] * cp_dst[1];
int b2 = cp_dst[2] * cp_dst[2];
int a2 = cp_dst[3] * cp_dst[3];
cp_mix[0] = round_fl_to_uchar(sqrtf(divide_round_i((mfac * r1 + fac * r2), 255)));
cp_mix[1] = round_fl_to_uchar(sqrtf(divide_round_i((mfac * g1 + fac * g2), 255)));
cp_mix[2] = round_fl_to_uchar(sqrtf(divide_round_i((mfac * b1 + fac * b2), 255)));
cp_mix[3] = round_fl_to_uchar(sqrtf(divide_round_i((mfac * a1 + fac * a2), 255)));
return col_mix;
}
BLI_INLINE uint mcol_add(uint col_src, uint col_dst, int fac)
{
uchar *cp_src, *cp_dst, *cp_mix;
int temp;
uint col_mix = 0;
if (fac == 0) {
return col_src;
}
cp_src = (uchar *)&col_src;
cp_dst = (uchar *)&col_dst;
cp_mix = (uchar *)&col_mix;
temp = cp_src[0] + divide_round_i((fac * cp_dst[0]), 255);
cp_mix[0] = (temp > 254) ? 255 : temp;
temp = cp_src[1] + divide_round_i((fac * cp_dst[1]), 255);
cp_mix[1] = (temp > 254) ? 255 : temp;
temp = cp_src[2] + divide_round_i((fac * cp_dst[2]), 255);
cp_mix[2] = (temp > 254) ? 255 : temp;
temp = cp_src[3] + divide_round_i((fac * cp_dst[3]), 255);
cp_mix[3] = (temp > 254) ? 255 : temp;
return col_mix;
}
BLI_INLINE uint mcol_sub(uint col_src, uint col_dst, int fac)
{
uchar *cp_src, *cp_dst, *cp_mix;
int temp;
uint col_mix = 0;
if (fac == 0) {
return col_src;
}
cp_src = (uchar *)&col_src;
cp_dst = (uchar *)&col_dst;
cp_mix = (uchar *)&col_mix;
temp = cp_src[0] - divide_round_i((fac * cp_dst[0]), 255);
cp_mix[0] = (temp < 0) ? 0 : temp;
temp = cp_src[1] - divide_round_i((fac * cp_dst[1]), 255);
cp_mix[1] = (temp < 0) ? 0 : temp;
temp = cp_src[2] - divide_round_i((fac * cp_dst[2]), 255);
cp_mix[2] = (temp < 0) ? 0 : temp;
temp = cp_src[3] - divide_round_i((fac * cp_dst[3]), 255);
cp_mix[3] = (temp < 0) ? 0 : temp;
return col_mix;
}
BLI_INLINE uint mcol_mul(uint col_src, uint col_dst, int fac)
{
uchar *cp_src, *cp_dst, *cp_mix;
int mfac;
uint col_mix = 0;
if (fac == 0) {
return col_src;
}
mfac = 255 - fac;
cp_src = (uchar *)&col_src;
cp_dst = (uchar *)&col_dst;
cp_mix = (uchar *)&col_mix;
/* first mul, then blend the fac */
cp_mix[0] = divide_round_i(mfac * cp_src[0] * 255 + fac * cp_dst[0] * cp_src[0], 255 * 255);
cp_mix[1] = divide_round_i(mfac * cp_src[1] * 255 + fac * cp_dst[1] * cp_src[1], 255 * 255);
cp_mix[2] = divide_round_i(mfac * cp_src[2] * 255 + fac * cp_dst[2] * cp_src[2], 255 * 255);
cp_mix[3] = divide_round_i(mfac * cp_src[3] * 255 + fac * cp_dst[3] * cp_src[3], 255 * 255);
return col_mix;
}
BLI_INLINE uint mcol_lighten(uint col_src, uint col_dst, int fac)
{
uchar *cp_src, *cp_dst, *cp_mix;
int mfac;
uint col_mix = 0;
if (fac == 0) {
return col_src;
}
if (fac >= 255) {
return col_dst;
}
mfac = 255 - fac;
cp_src = (uchar *)&col_src;
cp_dst = (uchar *)&col_dst;
cp_mix = (uchar *)&col_mix;
/* See if we're lighter, if so mix, else don't do anything.
* if the paint color is darker then the original, then ignore */
if (IMB_colormanagement_get_luminance_byte(cp_src) >
IMB_colormanagement_get_luminance_byte(cp_dst)) {
return col_src;
}
cp_mix[0] = divide_round_i(mfac * cp_src[0] + fac * cp_dst[0], 255);
cp_mix[1] = divide_round_i(mfac * cp_src[1] + fac * cp_dst[1], 255);
cp_mix[2] = divide_round_i(mfac * cp_src[2] + fac * cp_dst[2], 255);
cp_mix[3] = divide_round_i(mfac * cp_src[3] + fac * cp_dst[3], 255);
return col_mix;
}
BLI_INLINE uint mcol_darken(uint col_src, uint col_dst, int fac)
{
uchar *cp_src, *cp_dst, *cp_mix;
int mfac;
uint col_mix = 0;
if (fac == 0) {
return col_src;
}
if (fac >= 255) {
return col_dst;
}
mfac = 255 - fac;
cp_src = (uchar *)&col_src;
cp_dst = (uchar *)&col_dst;
cp_mix = (uchar *)&col_mix;
/* See if we're darker, if so mix, else don't do anything.
* if the paint color is brighter then the original, then ignore */
if (IMB_colormanagement_get_luminance_byte(cp_src) <
IMB_colormanagement_get_luminance_byte(cp_dst)) {
return col_src;
}
cp_mix[0] = divide_round_i((mfac * cp_src[0] + fac * cp_dst[0]), 255);
cp_mix[1] = divide_round_i((mfac * cp_src[1] + fac * cp_dst[1]), 255);
cp_mix[2] = divide_round_i((mfac * cp_src[2] + fac * cp_dst[2]), 255);
cp_mix[3] = divide_round_i((mfac * cp_src[3] + fac * cp_dst[3]), 255);
return col_mix;
}
BLI_INLINE uint mcol_colordodge(uint col_src, uint col_dst, int fac)
{
uchar *cp_src, *cp_dst, *cp_mix;
int mfac, temp;
uint col_mix = 0;
if (fac == 0) {
return col_src;
}
mfac = 255 - fac;
cp_src = (uchar *)&col_src;
cp_dst = (uchar *)&col_dst;
cp_mix = (uchar *)&col_mix;
temp = (cp_dst[0] == 255) ? 255 : min_ii((cp_src[0] * 225) / (255 - cp_dst[0]), 255);
cp_mix[0] = (mfac * cp_src[0] + temp * fac) / 255;
temp = (cp_dst[1] == 255) ? 255 : min_ii((cp_src[1] * 225) / (255 - cp_dst[1]), 255);
cp_mix[1] = (mfac * cp_src[1] + temp * fac) / 255;
temp = (cp_dst[2] == 255) ? 255 : min_ii((cp_src[2] * 225) / (255 - cp_dst[2]), 255);
cp_mix[2] = (mfac * cp_src[2] + temp * fac) / 255;
temp = (cp_dst[3] == 255) ? 255 : min_ii((cp_src[3] * 225) / (255 - cp_dst[3]), 255);
cp_mix[3] = (mfac * cp_src[3] + temp * fac) / 255;
return col_mix;
}
BLI_INLINE uint mcol_difference(uint col_src, uint col_dst, int fac)
{
uchar *cp_src, *cp_dst, *cp_mix;
int mfac, temp;
uint col_mix = 0;
if (fac == 0) {
return col_src;
}
mfac = 255 - fac;
cp_src = (uchar *)&col_src;
cp_dst = (uchar *)&col_dst;
cp_mix = (uchar *)&col_mix;
temp = abs(cp_src[0] - cp_dst[0]);
cp_mix[0] = (mfac * cp_src[0] + temp * fac) / 255;
temp = abs(cp_src[1] - cp_dst[1]);
cp_mix[1] = (mfac * cp_src[1] + temp * fac) / 255;
temp = abs(cp_src[2] - cp_dst[2]);
cp_mix[2] = (mfac * cp_src[2] + temp * fac) / 255;
temp = abs(cp_src[3] - cp_dst[3]);
cp_mix[3] = (mfac * cp_src[3] + temp * fac) / 255;
return col_mix;
}
BLI_INLINE uint mcol_screen(uint col_src, uint col_dst, int fac)
{
uchar *cp_src, *cp_dst, *cp_mix;
int mfac, temp;
uint col_mix = 0;
if (fac == 0) {
return col_src;
}
mfac = 255 - fac;
cp_src = (uchar *)&col_src;
cp_dst = (uchar *)&col_dst;
cp_mix = (uchar *)&col_mix;
temp = max_ii(255 - (((255 - cp_src[0]) * (255 - cp_dst[0])) / 255), 0);
cp_mix[0] = (mfac * cp_src[0] + temp * fac) / 255;
temp = max_ii(255 - (((255 - cp_src[1]) * (255 - cp_dst[1])) / 255), 0);
cp_mix[1] = (mfac * cp_src[1] + temp * fac) / 255;
temp = max_ii(255 - (((255 - cp_src[2]) * (255 - cp_dst[2])) / 255), 0);
cp_mix[2] = (mfac * cp_src[2] + temp * fac) / 255;
temp = max_ii(255 - (((255 - cp_src[3]) * (255 - cp_dst[3])) / 255), 0);
cp_mix[3] = (mfac * cp_src[3] + temp * fac) / 255;
return col_mix;
}
BLI_INLINE uint mcol_hardlight(uint col_src, uint col_dst, int fac)
{
uchar *cp_src, *cp_dst, *cp_mix;
int mfac, temp;
uint col_mix = 0;
if (fac == 0) {
return col_src;
}
mfac = 255 - fac;
cp_src = (uchar *)&col_src;
cp_dst = (uchar *)&col_dst;
cp_mix = (uchar *)&col_mix;
int i = 0;
for (i = 0; i < 4; i++) {
if (cp_dst[i] > 127) {
temp = 255 - ((255 - 2 * (cp_dst[i] - 127)) * (255 - cp_src[i]) / 255);
}
else {
temp = (2 * cp_dst[i] * cp_src[i]) >> 8;
}
cp_mix[i] = min_ii((mfac * cp_src[i] + temp * fac) / 255, 255);
}
return col_mix;
}
BLI_INLINE uint mcol_overlay(uint col_src, uint col_dst, int fac)
{
uchar *cp_src, *cp_dst, *cp_mix;
int mfac, temp;
uint col_mix = 0;
if (fac == 0) {
return col_src;
}
mfac = 255 - fac;
cp_src = (uchar *)&col_src;
cp_dst = (uchar *)&col_dst;
cp_mix = (uchar *)&col_mix;
int i = 0;
for (i = 0; i < 4; i++) {
if (cp_src[i] > 127) {
temp = 255 - ((255 - 2 * (cp_src[i] - 127)) * (255 - cp_dst[i]) / 255);
}
else {
temp = (2 * cp_dst[i] * cp_src[i]) >> 8;
}
cp_mix[i] = min_ii((mfac * cp_src[i] + temp * fac) / 255, 255);
}
return col_mix;
}
BLI_INLINE uint mcol_softlight(uint col_src, uint col_dst, int fac)
{
uchar *cp_src, *cp_dst, *cp_mix;
int mfac, temp;
uint col_mix = 0;
if (fac == 0) {
return col_src;
}
mfac = 255 - fac;
cp_src = (uchar *)&col_src;
cp_dst = (uchar *)&col_dst;
cp_mix = (uchar *)&col_mix;
for (int i = 0; i < 4; i++) {
if (cp_src[i] < 127) {
temp = ((2 * ((cp_dst[i] / 2) + 64)) * cp_src[i]) / 255;
}
else {
temp = 255 - (2 * (255 - ((cp_dst[i] / 2) + 64)) * (255 - cp_src[i]) / 255);
}
cp_mix[i] = (temp * fac + cp_src[i] * mfac) / 255;
}
return col_mix;
}
BLI_INLINE uint mcol_exclusion(uint col_src, uint col_dst, int fac)
{
uchar *cp_src, *cp_dst, *cp_mix;
int mfac, temp;
uint col_mix = 0;
if (fac == 0) {
return col_src;
}
mfac = 255 - fac;
cp_src = (uchar *)&col_src;
cp_dst = (uchar *)&col_dst;
cp_mix = (uchar *)&col_mix;
int i = 0;
for (i = 0; i < 4; i++) {
temp = 127 - ((2 * (cp_src[i] - 127) * (cp_dst[i] - 127)) / 255);
cp_mix[i] = (temp * fac + cp_src[i] * mfac) / 255;
}
return col_mix;
}
BLI_INLINE uint mcol_luminosity(uint col_src, uint col_dst, int fac)
{
uchar *cp_src, *cp_dst, *cp_mix;
int mfac;
uint col_mix = 0;
if (fac == 0) {
return col_src;
}
mfac = 255 - fac;
cp_src = (uchar *)&col_src;
cp_dst = (uchar *)&col_dst;
cp_mix = (uchar *)&col_mix;
float h1, s1, v1;
float h2, s2, v2;
float r, g, b;
rgb_to_hsv(cp_src[0] / 255.0f, cp_src[1] / 255.0f, cp_src[2] / 255.0f, &h1, &s1, &v1);
rgb_to_hsv(cp_dst[0] / 255.0f, cp_dst[1] / 255.0f, cp_dst[2] / 255.0f, &h2, &s2, &v2);
v1 = v2;
hsv_to_rgb(h1, s1, v1, &r, &g, &b);
cp_mix[0] = ((int)(r * 255.0f) * fac + mfac * cp_src[0]) / 255;
cp_mix[1] = ((int)(g * 255.0f) * fac + mfac * cp_src[1]) / 255;
cp_mix[2] = ((int)(b * 255.0f) * fac + mfac * cp_src[2]) / 255;
cp_mix[3] = ((int)(cp_dst[3]) * fac + mfac * cp_src[3]) / 255;
return col_mix;
}
BLI_INLINE uint mcol_saturation(uint col_src, uint col_dst, int fac)
{
uchar *cp_src, *cp_dst, *cp_mix;
int mfac;
uint col_mix = 0;
if (fac == 0) {
return col_src;
}
mfac = 255 - fac;
cp_src = (uchar *)&col_src;
cp_dst = (uchar *)&col_dst;
cp_mix = (uchar *)&col_mix;
float h1, s1, v1;
float h2, s2, v2;
float r, g, b;
rgb_to_hsv(cp_src[0] / 255.0f, cp_src[1] / 255.0f, cp_src[2] / 255.0f, &h1, &s1, &v1);
rgb_to_hsv(cp_dst[0] / 255.0f, cp_dst[1] / 255.0f, cp_dst[2] / 255.0f, &h2, &s2, &v2);
if (s1 > EPS_SATURATION) {
s1 = s2;
}
hsv_to_rgb(h1, s1, v1, &r, &g, &b);
cp_mix[0] = ((int)(r * 255.0f) * fac + mfac * cp_src[0]) / 255;
cp_mix[1] = ((int)(g * 255.0f) * fac + mfac * cp_src[1]) / 255;
cp_mix[2] = ((int)(b * 255.0f) * fac + mfac * cp_src[2]) / 255;
return col_mix;
}
BLI_INLINE uint mcol_hue(uint col_src, uint col_dst, int fac)
{
uchar *cp_src, *cp_dst, *cp_mix;
int mfac;
uint col_mix = 0;
if (fac == 0) {
return col_src;
}
mfac = 255 - fac;
cp_src = (uchar *)&col_src;
cp_dst = (uchar *)&col_dst;
cp_mix = (uchar *)&col_mix;
float h1, s1, v1;
float h2, s2, v2;
float r, g, b;
rgb_to_hsv(cp_src[0] / 255.0f, cp_src[1] / 255.0f, cp_src[2] / 255.0f, &h1, &s1, &v1);
rgb_to_hsv(cp_dst[0] / 255.0f, cp_dst[1] / 255.0f, cp_dst[2] / 255.0f, &h2, &s2, &v2);
h1 = h2;
hsv_to_rgb(h1, s1, v1, &r, &g, &b);
cp_mix[0] = ((int)(r * 255.0f) * fac + mfac * cp_src[0]) / 255;
cp_mix[1] = ((int)(g * 255.0f) * fac + mfac * cp_src[1]) / 255;
cp_mix[2] = ((int)(b * 255.0f) * fac + mfac * cp_src[2]) / 255;
cp_mix[3] = ((int)(cp_dst[3]) * fac + mfac * cp_src[3]) / 255;
return col_mix;
}
BLI_INLINE uint mcol_alpha_add(uint col_src, int fac)
{
uchar *cp_src, *cp_mix;
int temp;
uint col_mix = col_src;
if (fac == 0) {
return col_src;
}
cp_src = (uchar *)&col_src;
cp_mix = (uchar *)&col_mix;
temp = cp_src[3] + fac;
cp_mix[3] = (temp > 254) ? 255 : temp;
return col_mix;
}
BLI_INLINE uint mcol_alpha_sub(uint col_src, int fac)
{
uchar *cp_src, *cp_mix;
int temp;
uint col_mix = col_src;
if (fac == 0) {
return col_src;
}
cp_src = (uchar *)&col_src;
cp_mix = (uchar *)&col_mix;
temp = cp_src[3] - fac;
cp_mix[3] = temp < 0 ? 0 : temp;
return col_mix;
}
uint ED_vpaint_blend_tool(const int tool, const uint col, const uint paintcol, const int alpha_i)
{
switch ((IMB_BlendMode)tool) {
case IMB_BLEND_MIX:
return mcol_blend(col, paintcol, alpha_i);
case IMB_BLEND_ADD:
return mcol_add(col, paintcol, alpha_i);
case IMB_BLEND_SUB:
return mcol_sub(col, paintcol, alpha_i);
case IMB_BLEND_MUL:
return mcol_mul(col, paintcol, alpha_i);
case IMB_BLEND_LIGHTEN:
return mcol_lighten(col, paintcol, alpha_i);
case IMB_BLEND_DARKEN:
return mcol_darken(col, paintcol, alpha_i);
case IMB_BLEND_COLORDODGE:
return mcol_colordodge(col, paintcol, alpha_i);
case IMB_BLEND_DIFFERENCE:
return mcol_difference(col, paintcol, alpha_i);
case IMB_BLEND_SCREEN:
return mcol_screen(col, paintcol, alpha_i);
case IMB_BLEND_HARDLIGHT:
return mcol_hardlight(col, paintcol, alpha_i);
case IMB_BLEND_OVERLAY:
return mcol_overlay(col, paintcol, alpha_i);
case IMB_BLEND_SOFTLIGHT:
return mcol_softlight(col, paintcol, alpha_i);
case IMB_BLEND_EXCLUSION:
return mcol_exclusion(col, paintcol, alpha_i);
case IMB_BLEND_LUMINOSITY:
return mcol_luminosity(col, paintcol, alpha_i);
case IMB_BLEND_SATURATION:
return mcol_saturation(col, paintcol, alpha_i);
case IMB_BLEND_HUE:
return mcol_hue(col, paintcol, alpha_i);
/* non-color */
case IMB_BLEND_ERASE_ALPHA:
return mcol_alpha_sub(col, alpha_i);
case IMB_BLEND_ADD_ALPHA:
return mcol_alpha_add(col, alpha_i);
default:
BLI_assert(0);
return 0;
}
}
/** \} */

View File

@ -4025,6 +4025,7 @@ void SCULPT_cache_free(StrokeCache *cache)
MEM_SAFE_FREE(cache->detail_directions);
MEM_SAFE_FREE(cache->prev_displacement);
MEM_SAFE_FREE(cache->limit_surface_co);
MEM_SAFE_FREE(cache->prev_colors_vpaint);
if (cache->pose_ik_chain) {
SCULPT_pose_ik_chain_free(cache->pose_ik_chain);

View File

@ -219,7 +219,6 @@ typedef struct SculptThreadedTaskData {
int totnode;
struct VPaint *vp;
struct VPaintData *vpd;
struct WPaintData *wpd;
struct WeightPaintInfo *wpi;
unsigned int *lcol;
@ -493,6 +492,7 @@ typedef struct StrokeCache {
float mouse_event[2];
float (*prev_colors)[4];
void *prev_colors_vpaint;
/* Multires Displacement Smear. */
float (*prev_displacement)[3];

@ -1 +1 @@
Subproject commit 4c1e01e3e309282beb1af3b1eddb2c7f9a666b5d
Subproject commit 1e658ca996f11e5ff3398d89bd81f5b719304a57