Skip to content

Commit

Permalink
SmudgeTweaks: Many tweaks for smudge settings
Browse files Browse the repository at this point in the history
Smudge Length Multiplier (smear longer)
Smudge Buckets (256 smudge states)
Smudge Transparency (similar to lock alpha but for smudge)
Paint mode (Spectral upsampling)
Posterize mode
  • Loading branch information
briend committed Jan 26, 2019
1 parent a2b3f56 commit 096acda
Show file tree
Hide file tree
Showing 24 changed files with 4,209 additions and 148 deletions.
5 changes: 5 additions & 0 deletions Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@ MyPaint_introspectable_headers = \
mypaint-rectangle.h \
mypaint-surface.h \
mypaint-tiled-surface.h \
fastapprox/fastpow.h \
fastapprox/sse.h \
fastapprox/fastexp.h \
fastapprox/cast.h \
fastapprox/fastlog.h \
$(libmypaint_glib)

if HAVE_INTROSPECTION
Expand Down
193 changes: 190 additions & 3 deletions brushmodes.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@

#include <stdint.h>
#include <assert.h>
#include <math.h>
#include "fastapprox/fastpow.h"

#include "helpers.h"

Expand All @@ -43,6 +45,7 @@
// resultAlpha = topAlpha + (1.0 - topAlpha) * bottomAlpha
// resultColor = topColor + (1.0 - topAlpha) * bottomColor
//

void draw_dab_pixels_BlendMode_Normal (uint16_t * mask,
uint16_t * rgba,
uint16_t color_r,
Expand All @@ -66,7 +69,89 @@ void draw_dab_pixels_BlendMode_Normal (uint16_t * mask,
}
};

void draw_dab_pixels_BlendMode_Normal_Paint (uint16_t * mask,
uint16_t * rgba,
uint16_t color_r,
uint16_t color_g,
uint16_t color_b,
uint16_t opacity) {

while (1) {
for (; mask[0]; mask++, rgba+=4) {
uint32_t opa_a = mask[0]*(uint32_t)opacity/(1<<15); // topAlpha
uint32_t opa_b = (1<<15)-opa_a; // bottomAlpha

//alpha-weighted ratio for WGM (sums to 1.0)
float fac_a = (float)opa_a / (opa_a + opa_b * rgba[3] / (1<<15));
//fac_a *= fac_a;
float fac_b = 1.0 - fac_a;

//convert bottom to spectral. Un-premult alpha to obtain reflectance
//color noise is not a problem since low alpha also implies low weight
float spectral_b[10] = {0};
if (rgba[3] > 0) {
rgb_to_spectral((float)rgba[0] / rgba[3], (float)rgba[1] / rgba[3], (float)rgba[2] / rgba[3], spectral_b);
} else {
rgb_to_spectral((float)rgba[0]/ (1<<15), (float)rgba[1]/ (1<<15), (float)rgba[2]/ (1<<15), spectral_b);
}
// convert top to spectral. Already straight color
float spectral_a[10] = {0};
rgb_to_spectral((float)color_r / (1<<15), (float)color_g / (1<<15), (float)color_b / (1<<15), spectral_a);

// mix to the two spectral reflectances using WGM
float spectral_result[10] = {0};
for (int i=0; i<10; i++) {
spectral_result[i] = fastpow(spectral_a[i], fac_a) * fastpow(spectral_b[i], fac_b);
}

// convert back to RGB and premultiply alpha
float rgb_result[3] = {0};
spectral_to_rgb(spectral_result, rgb_result);
rgba[3] = opa_a + opa_b * rgba[3] / (1<<15);

for (int i=0; i<3; i++) {
rgba[i] =(rgb_result[i] * rgba[3]);
}
}
if (!mask[1]) break;
rgba += mask[1];
mask += 2;
}
};

//Posterize. Basically exactly like GIMP's posterize
//reduces colors by adjustable amount (posterize_num).
//posterize the canvas, then blend that via opacity
//does not affect alpha

void draw_dab_pixels_BlendMode_Posterize (uint16_t * mask,
uint16_t * rgba,
uint16_t opacity,
uint16_t posterize_num) {

while (1) {
for (; mask[0]; mask++, rgba+=4) {

float r = (float)rgba[0] / (1<<15);
float g = (float)rgba[1] / (1<<15);
float b = (float)rgba[2] / (1<<15);

uint32_t post_r = (1<<15) * ROUND(r * posterize_num) / posterize_num;
uint32_t post_g = (1<<15) * ROUND(g * posterize_num) / posterize_num;
uint32_t post_b = (1<<15) * ROUND(b * posterize_num) / posterize_num;

uint32_t opa_a = mask[0]*(uint32_t)opacity/(1<<15); // topAlpha
uint32_t opa_b = (1<<15)-opa_a; // bottomAlpha
rgba[0] = (opa_a*post_r + opa_b*rgba[0])/(1<<15);
rgba[1] = (opa_a*post_g + opa_b*rgba[1])/(1<<15);
rgba[2] = (opa_a*post_b + opa_b*rgba[2])/(1<<15);

}
if (!mask[1]) break;
rgba += mask[1];
mask += 2;
}
};

// Colorize: apply the source hue and saturation, retaining the target
// brightness. Same thing as in the PDF spec addendum, and upcoming SVG
Expand All @@ -82,9 +167,9 @@ void draw_dab_pixels_BlendMode_Normal (uint16_t * mask,
// http://dvcs.w3.org/hg/FXTF/rawfile/tip/compositing/index.html.
// Same as ITU Rec. BT.601 (SDTV) rounded to 2 decimal places.

static const float LUMA_RED_COEFF = 0.3 * (1<<15);
static const float LUMA_GREEN_COEFF = 0.59 * (1<<15);
static const float LUMA_BLUE_COEFF = 0.11 * (1<<15);
static const float LUMA_RED_COEFF = 0.2126 * (1<<15);
static const float LUMA_GREEN_COEFF = 0.7152 * (1<<15);
static const float LUMA_BLUE_COEFF = 0.0722 * (1<<15);

// See also http://en.wikipedia.org/wiki/YCbCr

Expand Down Expand Up @@ -224,6 +309,59 @@ void draw_dab_pixels_BlendMode_Normal_and_Eraser (uint16_t * mask,
}
};

void draw_dab_pixels_BlendMode_Normal_and_Eraser_Paint (uint16_t * mask,
uint16_t * rgba,
uint16_t color_r,
uint16_t color_g,
uint16_t color_b,
uint16_t color_a,
uint16_t opacity) {

while (1) {
for (; mask[0]; mask++, rgba+=4) {
uint32_t opa_a = mask[0]*(uint32_t)opacity/(1<<15); // topAlpha
uint32_t opa_b = (1<<15)-opa_a; // bottomAlpha

float fac_a = (float)opa_a / (opa_a + opa_b * rgba[3] / (1<<15));
//fac_a *= fac_a;
float fac_b = 1.0 - fac_a;
//fac_a *= (float)color_a / (1<<15);
float spectral_b[10] = {0};
if (rgba[3] > 0) {
rgb_to_spectral((float)rgba[0] / rgba[3], (float)rgba[1] / rgba[3], (float)rgba[2] / rgba[3], spectral_b);
} else {
rgb_to_spectral((float)rgba[0]/ (1<<15), (float)rgba[1]/ (1<<15), (float)rgba[2]/ (1<<15), spectral_b);
}
// convert top to spectral. Already straight color
float spectral_a[10] = {0};
rgb_to_spectral((float)color_r / (1<<15), (float)color_g / (1<<15), (float)color_b / (1<<15), spectral_a);

// mix to the two spectral colors using WGM
float spectral_result[10] = {0};
for (int i=0; i<10; i++) {
spectral_result[i] = fastpow(spectral_a[i], fac_a) * fastpow(spectral_b[i], fac_b);
}
// convert back to RGB
float rgb_result[3] = {0};
spectral_to_rgb(spectral_result, rgb_result);

// apply eraser
opa_a = opa_a * color_a / (1<<15);

// calculate alpha normally
rgba[3] = opa_a + opa_b * rgba[3] / (1<<15);

for (int i=0; i<3; i++) {
rgba[i] =(rgb_result[i] * rgba[3]);
}

}
if (!mask[1]) break;
rgba += mask[1];
mask += 2;
}
};

// This is BlendMode_Normal with locked alpha channel.
//
void draw_dab_pixels_BlendMode_LockAlpha (uint16_t * mask,
Expand Down Expand Up @@ -251,6 +389,53 @@ void draw_dab_pixels_BlendMode_LockAlpha (uint16_t * mask,
}
};

void draw_dab_pixels_BlendMode_LockAlpha_Paint (uint16_t * mask,
uint16_t * rgba,
uint16_t color_r,
uint16_t color_g,
uint16_t color_b,
uint16_t opacity) {

while (1) {
for (; mask[0]; mask++, rgba+=4) {

uint32_t opa_a = mask[0]*(uint32_t)opacity/(1<<15); // topAlpha
uint32_t opa_b = (1<<15)-opa_a; // bottomAlpha
opa_a *= rgba[3];
opa_a /= (1<<15);
float fac_a = (float)opa_a / (opa_a + opa_b * rgba[3] / (1<<15));
//fac_a *= fac_a;
float fac_b = 1.0 - fac_a;
float spectral_b[10] = {0};
if (rgba[3] > 0) {
rgb_to_spectral((float)rgba[0] / rgba[3], (float)rgba[1] / rgba[3], (float)rgba[2] / rgba[3], spectral_b);
} else {
rgb_to_spectral((float)rgba[0]/ (1<<15), (float)rgba[1]/ (1<<15), (float)rgba[2]/ (1<<15), spectral_b);
}
// convert top to spectral. Already straight color
float spectral_a[10] = {0};
rgb_to_spectral((float)color_r / (1<<15), (float)color_g / (1<<15), (float)color_b / (1<<15), spectral_a);

// mix to the two spectral colors using WGM
float spectral_result[10] = {0};
for (int i=0; i<10; i++) {
spectral_result[i] = fastpow(spectral_a[i], fac_a) * fastpow(spectral_b[i], fac_b);
}
// convert back to RGB
float rgb_result[3] = {0};
spectral_to_rgb(spectral_result, rgb_result);
rgba[3] = opa_a + opa_b * rgba[3] / (1<<15);

for (int i=0; i<3; i++) {
rgba[i] =(rgb_result[i] * rgba[3]);
}
}
if (!mask[1]) break;
rgba += mask[1];
mask += 2;
}
};


// Sum up the color/alpha components inside the masked region.
// Called by get_color().
Expand Down Expand Up @@ -299,3 +484,5 @@ void get_color_pixels_accumulate (uint16_t * mask,
*sum_a += a;
};



30 changes: 30 additions & 0 deletions brushmodes.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,26 +7,56 @@ void draw_dab_pixels_BlendMode_Normal (uint16_t * mask,
uint16_t color_g,
uint16_t color_b,
uint16_t opacity);

void draw_dab_pixels_BlendMode_Normal_Paint (uint16_t * mask,
uint16_t * rgba,
uint16_t color_r,
uint16_t color_g,
uint16_t color_b,
uint16_t opacity);
void
draw_dab_pixels_BlendMode_Color (uint16_t *mask,
uint16_t *rgba, // b=bottom, premult
uint16_t color_r, // }
uint16_t color_g, // }-- a=top, !premult
uint16_t color_b, // }
uint16_t opacity);
void
draw_dab_pixels_BlendMode_Posterize (uint16_t *mask,
uint16_t *rgba, // b=bottom, premult
uint16_t posterize,
uint16_t posterize_num);

void draw_dab_pixels_BlendMode_Normal_and_Eraser (uint16_t * mask,
uint16_t * rgba,
uint16_t color_r,
uint16_t color_g,
uint16_t color_b,
uint16_t color_a,
uint16_t opacity);

void draw_dab_pixels_BlendMode_Normal_and_Eraser_Paint (uint16_t * mask,
uint16_t * rgba,
uint16_t color_r,
uint16_t color_g,
uint16_t color_b,
uint16_t color_a,
uint16_t opacity);

void draw_dab_pixels_BlendMode_LockAlpha (uint16_t * mask,
uint16_t * rgba,
uint16_t color_r,
uint16_t color_g,
uint16_t color_b,
uint16_t opacity);

void draw_dab_pixels_BlendMode_LockAlpha_Paint (uint16_t * mask,
uint16_t * rgba,
uint16_t color_r,
uint16_t color_g,
uint16_t color_b,
uint16_t opacity);

void get_color_pixels_accumulate (uint16_t * mask,
uint16_t * rgba,
float * sum_weight,
Expand Down
Loading

0 comments on commit 096acda

Please sign in to comment.