Skip to content

Commit

Permalink
Experiment with "Igneous dither."
Browse files Browse the repository at this point in the history
This is an error diffusion dither that uses IGN to introduce error.
  • Loading branch information
tommyettinger committed Nov 12, 2022
1 parent 22031a3 commit af3a0de
Show file tree
Hide file tree
Showing 2 changed files with 105 additions and 2 deletions.
105 changes: 104 additions & 1 deletion src/main/java/com/github/tommyettinger/anim8/PaletteReducer.java
Original file line number Diff line number Diff line change
Expand Up @@ -2670,6 +2670,110 @@ public Pixmap reduceJimenez(Pixmap pixmap) {
return pixmap;
}

public Pixmap reduceIgneous(Pixmap pixmap) {
boolean hasTransparent = (paletteArray[0] == 0);
final int lineLen = pixmap.getWidth(), h = pixmap.getHeight();
float[] curErrorRed, nextErrorRed, curErrorGreen, nextErrorGreen, curErrorBlue, nextErrorBlue;
if (curErrorRedFloats == null) {
curErrorRed = (curErrorRedFloats = new FloatArray(lineLen)).items;
nextErrorRed = (nextErrorRedFloats = new FloatArray(lineLen)).items;
curErrorGreen = (curErrorGreenFloats = new FloatArray(lineLen)).items;
nextErrorGreen = (nextErrorGreenFloats = new FloatArray(lineLen)).items;
curErrorBlue = (curErrorBlueFloats = new FloatArray(lineLen)).items;
nextErrorBlue = (nextErrorBlueFloats = new FloatArray(lineLen)).items;
} else {
curErrorRed = curErrorRedFloats.ensureCapacity(lineLen);
nextErrorRed = nextErrorRedFloats.ensureCapacity(lineLen);
curErrorGreen = curErrorGreenFloats.ensureCapacity(lineLen);
nextErrorGreen = nextErrorGreenFloats.ensureCapacity(lineLen);
curErrorBlue = curErrorBlueFloats.ensureCapacity(lineLen);
nextErrorBlue = nextErrorBlueFloats.ensureCapacity(lineLen);
for (int i = 0; i < lineLen; i++) {
nextErrorRed[i] = 0;
nextErrorGreen[i] = 0;
nextErrorBlue[i] = 0;
}
}
Pixmap.Blending blending = pixmap.getBlending();
pixmap.setBlending(Pixmap.Blending.None);
int color, used;
float rdiff, gdiff, bdiff;
float er, eg, eb;
byte paletteIndex;
float w1 = (6f * ditherStrength * populationBias * populationBias), w3 = w1 * 3f, w5 = w1 * 5f, w7 = w1 * 7f,
strength = 60f * ditherStrength / (populationBias * populationBias),
adj;

for (int y = 0; y < h; y++) {
int ny = y + 1;
for (int i = 0; i < lineLen; i++) {
curErrorRed[i] = nextErrorRed[i];
curErrorGreen[i] = nextErrorGreen[i];
curErrorBlue[i] = nextErrorBlue[i];
nextErrorRed[i] = 0;
nextErrorGreen[i] = 0;
nextErrorBlue[i] = 0;
}
for (int px = 0; px < lineLen; px++) {
color = pixmap.getPixel(px, y);
if ((color & 0x80) == 0 && hasTransparent)
pixmap.drawPixel(px, y, 0);
else {
adj = (px * 0.06711056f + y * 0.00583715f);
adj -= (int) adj;
adj *= 52.9829189f;
adj -= (int) adj;
adj -= 0.5f;
adj *= strength;

er = adj + (curErrorRed[px]);
eg = adj + (curErrorGreen[px]);
eb = adj + (curErrorBlue[px]);

int rr = MathUtils.clamp((int)(((color >>> 24) ) + er + 0.5f), 0, 0xFF);
int gg = MathUtils.clamp((int)(((color >>> 16) & 0xFF) + eg + 0.5f), 0, 0xFF);
int bb = MathUtils.clamp((int)(((color >>> 8) & 0xFF) + eb + 0.5f), 0, 0xFF);
paletteIndex =
paletteMapping[((rr << 7) & 0x7C00)
| ((gg << 2) & 0x3E0)
| ((bb >>> 3))];
used = paletteArray[paletteIndex & 0xFF];
pixmap.drawPixel(px, y, used);
rdiff = (0x3p-10f * ((color>>>24)- (used>>>24)) );
gdiff = (0x3p-10f * ((color>>>16&255)-(used>>>16&255)));
bdiff = (0x3p-10f * ((color>>>8&255)- (used>>>8&255)) );

if(px < lineLen - 1)
{
curErrorRed[px+1] += rdiff * w7;
curErrorGreen[px+1] += gdiff * w7;
curErrorBlue[px+1] += bdiff * w7;
}
if(ny < h)
{
if(px > 0)
{
nextErrorRed[px-1] += rdiff * w3;
nextErrorGreen[px-1] += gdiff * w3;
nextErrorBlue[px-1] += bdiff * w3;
}
if(px < lineLen - 1)
{
nextErrorRed[px+1] += rdiff * w1;
nextErrorGreen[px+1] += gdiff * w1;
nextErrorBlue[px+1] += bdiff * w1;
}
nextErrorRed[px] += rdiff * w5;
nextErrorGreen[px] += gdiff * w5;
nextErrorBlue[px] += bdiff * w5;
}
}
}
}
pixmap.setBlending(blending);
return pixmap;
}

/**
* An ordered dither that uses a sub-random sequence by Martin Roberts to disperse lightness adjustments across the
* image. This is very similar to {@link #reduceJimenez(Pixmap)}, but is milder by default, and has subtly different
Expand Down Expand Up @@ -2818,7 +2922,6 @@ public Pixmap reduceWoven(Pixmap pixmap) {
return pixmap;
}


/**
* A blue-noise-based dither; does not diffuse error, and uses a tiling blue noise pattern (which can be accessed
* with {@link #TRI_BLUE_NOISE}, but shouldn't usually be modified) as well as a 8x8 threshold matrix (the kind
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ public void refresh(){
reducer.reduceSolid(p);
break;
case 0:
reducer.reduceBlueNoiseSeparated(p);
reducer.reduceIgneous(p);
break;
case 1:
reducer.reduceBlueNoise(p);
Expand Down

0 comments on commit af3a0de

Please sign in to comment.