|
|
|
@ -1,5 +1,7 @@
|
|
|
|
|
package com.fine.theme.utils; |
|
|
|
|
|
|
|
|
|
import org.jetbrains.annotations.NotNull; |
|
|
|
|
|
|
|
|
|
import java.awt.Color; |
|
|
|
|
import java.awt.Graphics2D; |
|
|
|
|
import java.awt.Rectangle; |
|
|
|
@ -77,86 +79,111 @@ public class ShadowRenderer {
|
|
|
|
|
int yStop = dstHeight - right; |
|
|
|
|
int shadowRgb = color.getRGB() & 0x00FFFFFF; |
|
|
|
|
int[] aHistory = new int[shadowSize]; |
|
|
|
|
int historyIdx; |
|
|
|
|
int aSum; |
|
|
|
|
BufferedImage dst = new BufferedImage(dstWidth, dstHeight, BufferedImage.TYPE_INT_ARGB); |
|
|
|
|
int[] dstBuffer = new int[dstWidth * dstHeight]; |
|
|
|
|
int[] srcBuffer = new int[srcWidth * srcHeight]; |
|
|
|
|
getPixels(image, 0, 0, srcWidth, srcHeight, srcBuffer); |
|
|
|
|
int lastPixelOffset = right * dstWidth; |
|
|
|
|
float hSumDivider = 1.0f / shadowSize; |
|
|
|
|
float vSumDivider = opacity / shadowSize; |
|
|
|
|
int[] hSumLookup = new int[256 * shadowSize]; |
|
|
|
|
for (int i = 0; i < hSumLookup.length; i++) { |
|
|
|
|
hSumLookup[i] = (int) (i * hSumDivider); |
|
|
|
|
} |
|
|
|
|
int[] vSumLookup = new int[256 * shadowSize]; |
|
|
|
|
for (int i = 0; i < vSumLookup.length; i++) { |
|
|
|
|
vSumLookup[i] = (int) (i * vSumDivider); |
|
|
|
|
|
|
|
|
|
int[] hSumLookup = initSumLookupArray(1.0f, shadowSize); |
|
|
|
|
int[] vSumLookup = initSumLookupArray(opacity, shadowSize); |
|
|
|
|
|
|
|
|
|
applyHorizontalShadowBlur(left, dstWidth, srcHeight, shadowSize, aHistory, srcWidth, hSumLookup, dstBuffer, srcBuffer); |
|
|
|
|
|
|
|
|
|
applyVerticalShadowBlur(dstWidth, left, aHistory, right, dstBuffer, yStop, vSumLookup, shadowRgb, |
|
|
|
|
lastPixelOffset, shadowSize, dstHeight); |
|
|
|
|
|
|
|
|
|
setPixels(dst, 0, 0, dstWidth, dstHeight, dstBuffer); |
|
|
|
|
return dst; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private static int @NotNull [] initSumLookupArray(float x, int shadowSize) { |
|
|
|
|
float sumDivider = x / shadowSize; |
|
|
|
|
int[] sumLookup = new int[256 * shadowSize]; |
|
|
|
|
for (int i = 0; i < sumLookup.length; i++) { |
|
|
|
|
sumLookup[i] = (int) (i * sumDivider); |
|
|
|
|
} |
|
|
|
|
int srcOffset; |
|
|
|
|
for (int srcY = 0, dstOffset = left * dstWidth; srcY < srcHeight; srcY++) { |
|
|
|
|
for (historyIdx = 0; historyIdx < shadowSize; ) { |
|
|
|
|
aHistory[historyIdx++] = 0; |
|
|
|
|
} |
|
|
|
|
aSum = 0; |
|
|
|
|
historyIdx = 0; |
|
|
|
|
srcOffset = srcY * srcWidth; |
|
|
|
|
for (int srcX = 0; srcX < srcWidth; srcX++) { |
|
|
|
|
int a = hSumLookup[aSum]; |
|
|
|
|
dstBuffer[dstOffset++] = a << 24; |
|
|
|
|
return sumLookup; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private static void applyVerticalShadowBlur(int dstWidth, int left, int[] aHistory, int right, int[] dstBuffer, |
|
|
|
|
int yStop, int[] vSumLookup, int shadowRgb, int lastPixelOffset, |
|
|
|
|
int shadowSize, int dstHeight) { |
|
|
|
|
for (int x = 0, bufferOffset = 0; x < dstWidth; x++, bufferOffset = x) { |
|
|
|
|
int aSum = initializeAlphaSum(dstWidth, left, aHistory, right, dstBuffer, bufferOffset, 0); |
|
|
|
|
bufferOffset = x; |
|
|
|
|
int historyIdx = 0; |
|
|
|
|
for (int y = 0; y < yStop; y++, bufferOffset += dstWidth) { |
|
|
|
|
int a = vSumLookup[aSum]; |
|
|
|
|
dstBuffer[bufferOffset] = a << 24 | shadowRgb; |
|
|
|
|
aSum -= aHistory[historyIdx]; |
|
|
|
|
a = srcBuffer[srcOffset + srcX] >>> 24; |
|
|
|
|
a = dstBuffer[bufferOffset + lastPixelOffset] >>> 24; |
|
|
|
|
aHistory[historyIdx] = a; |
|
|
|
|
aSum += a; |
|
|
|
|
if (++historyIdx >= shadowSize) { |
|
|
|
|
historyIdx -= shadowSize; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
for (int i = 0; i < shadowSize; i++) { |
|
|
|
|
int a = hSumLookup[aSum]; |
|
|
|
|
dstBuffer[dstOffset++] = a << 24; |
|
|
|
|
for (int y = yStop; y < dstHeight; y++, bufferOffset += dstWidth) { |
|
|
|
|
int a = vSumLookup[aSum]; |
|
|
|
|
dstBuffer[bufferOffset] = a << 24 | shadowRgb; |
|
|
|
|
aSum -= aHistory[historyIdx]; |
|
|
|
|
if (++historyIdx >= shadowSize) { |
|
|
|
|
historyIdx -= shadowSize; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private static int initializeAlphaSum(int dstWidth, int left, int[] aHistory, int right, int[] dstBuffer, int bufferOffset, int aSum) { |
|
|
|
|
int historyIdx; |
|
|
|
|
for (historyIdx = 0; historyIdx < left; ) { |
|
|
|
|
aHistory[historyIdx++] = 0; |
|
|
|
|
} |
|
|
|
|
for (int y = 0; y < right; y++, bufferOffset += dstWidth) { |
|
|
|
|
int a = dstBuffer[bufferOffset] >>> 24; |
|
|
|
|
aHistory[historyIdx++] = a; |
|
|
|
|
aSum += a; |
|
|
|
|
} |
|
|
|
|
return aSum; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
for (int x = 0, bufferOffset = 0; x < dstWidth; x++, bufferOffset = x) { |
|
|
|
|
aSum = 0; |
|
|
|
|
for (historyIdx = 0; historyIdx < left; ) { |
|
|
|
|
private static void applyHorizontalShadowBlur(int left, int dstWidth, int srcHeight, int shadowSize, |
|
|
|
|
int[] aHistory, int srcWidth, int[] hSumLookup, int[] dstBuffer, int[] srcBuffer) { |
|
|
|
|
int historyIdx; |
|
|
|
|
for (int srcY = 0, dstOffset = left * dstWidth; srcY < srcHeight; srcY++) { |
|
|
|
|
for (historyIdx = 0; historyIdx < shadowSize; ) { |
|
|
|
|
aHistory[historyIdx++] = 0; |
|
|
|
|
} |
|
|
|
|
for (int y = 0; y < right; y++, bufferOffset += dstWidth) { |
|
|
|
|
int a = dstBuffer[bufferOffset] >>> 24; |
|
|
|
|
aHistory[historyIdx++] = a; |
|
|
|
|
aSum += a; |
|
|
|
|
} |
|
|
|
|
bufferOffset = x; |
|
|
|
|
int aSum = 0; |
|
|
|
|
historyIdx = 0; |
|
|
|
|
for (int y = 0; y < yStop; y++, bufferOffset += dstWidth) { |
|
|
|
|
int a = vSumLookup[aSum]; |
|
|
|
|
dstBuffer[bufferOffset] = a << 24 | shadowRgb; |
|
|
|
|
int srcOffset = srcY * srcWidth; |
|
|
|
|
for (int srcX = 0; srcX < srcWidth; srcX++) { |
|
|
|
|
int a = hSumLookup[aSum]; |
|
|
|
|
dstBuffer[dstOffset++] = a << 24; |
|
|
|
|
aSum -= aHistory[historyIdx]; |
|
|
|
|
a = dstBuffer[bufferOffset + lastPixelOffset] >>> 24; |
|
|
|
|
a = srcBuffer[srcOffset + srcX] >>> 24; |
|
|
|
|
aHistory[historyIdx] = a; |
|
|
|
|
aSum += a; |
|
|
|
|
if (++historyIdx >= shadowSize) { |
|
|
|
|
historyIdx -= shadowSize; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
for (int y = yStop; y < dstHeight; y++, bufferOffset += dstWidth) { |
|
|
|
|
int a = vSumLookup[aSum]; |
|
|
|
|
dstBuffer[bufferOffset] = a << 24 | shadowRgb; |
|
|
|
|
aSum -= aHistory[historyIdx]; |
|
|
|
|
if (++historyIdx >= shadowSize) { |
|
|
|
|
historyIdx -= shadowSize; |
|
|
|
|
} |
|
|
|
|
dstOffset = updateDstBufferOffset(shadowSize, aHistory, hSumLookup, dstBuffer, aSum, dstOffset, historyIdx); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private static int updateDstBufferOffset(int shadowSize, int[] aHistory, int[] hSumLookup, int[] dstBuffer, |
|
|
|
|
int aSum, int dstOffset, int historyIdx) { |
|
|
|
|
for (int i = 0; i < shadowSize; i++) { |
|
|
|
|
int a = hSumLookup[aSum]; |
|
|
|
|
dstBuffer[dstOffset++] = a << 24; |
|
|
|
|
aSum -= aHistory[historyIdx]; |
|
|
|
|
if (++historyIdx >= shadowSize) { |
|
|
|
|
historyIdx -= shadowSize; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
setPixels(dst, 0, 0, dstWidth, dstHeight, dstBuffer); |
|
|
|
|
return dst; |
|
|
|
|
return dstOffset; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private int[] getPixels(BufferedImage img, int x, int y, int w, int h, int[] pixels) { |
|
|
|
|