/*
* Copyright (c) 2013 by Gerrit Grunwald
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package eu.hansolo.enzo.common;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.image.PixelWriter;
import javafx.scene.image.WritableImage;
import javafx.scene.paint.Color;
import javafx.scene.paint.ImagePattern;
import javafx.scene.shape.Shape;
import java.util.Random;
/**
* Created by
* User: hansolo
* Date: 01.03.13
* Time: 11:16
*/
public class BrushedMetalPaint {
private int radius;
private double amount;
private int color;
private double shine;
private boolean monochrome;
private Random randomNumbers;
// ******************** Constructors **************************************
public BrushedMetalPaint() {
this(Color.rgb(136, 136, 136), 5, 0.1, true, 0.3);
}
public BrushedMetalPaint(final Color COLOR) {
this(COLOR, 5, 0.1, true, 0.3);
}
public BrushedMetalPaint(final Color COLOR, final int RADIUS, final double AMOUNT, final boolean MONOCHROME, final double SHINE) {
color = getIntFromColor(COLOR);
radius = RADIUS;
amount = AMOUNT;
monochrome = MONOCHROME;
shine = SHINE;
}
// ******************** Methods *******************************************
public Image getImage(final double W, final double H) {
final int WIDTH = (int) W;
final int HEIGHT = (int) H;
WritableImage DESTINATION = new WritableImage(WIDTH, HEIGHT);
final int[] IN_PIXELS = new int[WIDTH];
final int[] OUT_PIXELS = new int[WIDTH];
randomNumbers = new Random(0);
final int ALPHA = color & 0xff000000;
final int RED = (color >> 16) & 0xff;
final int GREEN = (color >> 8) & 0xff;
final int BLUE = color & 0xff;
for (int y = 0; y < HEIGHT; y++) {
for (int x = 0; x < WIDTH; x++) {
int tr = RED;
int tg = GREEN;
int tb = BLUE;
if (shine != 0) {
int f = (int) (255 * shine * Math.sin((double) x / WIDTH * Math.PI));
tr += f;
tg += f;
tb += f;
}
if (monochrome) {
int n = (int) (255 * (2 * randomNumbers.nextFloat() - 1) * amount);
IN_PIXELS[x] = ALPHA | (clamp(tr + n) << 16) | (clamp(tg + n) << 8) | clamp(tb + n);
} else {
IN_PIXELS[x] = ALPHA | (random(tr) << 16) | (random(tg) << 8) | random(tb);
}
}
if (radius != 0) {
blur(IN_PIXELS, OUT_PIXELS, WIDTH, radius);
setRGB(DESTINATION, 0, y, OUT_PIXELS);
} else {
setRGB(DESTINATION, 0, y, IN_PIXELS);
}
}
return DESTINATION;
}
public ImageView getImageView(final double W, final double H, final Shape CLIP) {
final Image IMAGE = getImage(W, H);
final ImageView IMAGE_VIEW = new ImageView(IMAGE);
IMAGE_VIEW.setClip(CLIP);
return IMAGE_VIEW;
}
public ImagePattern apply(final Shape SHAPE) {
double x = SHAPE.getLayoutBounds().getMinX();
double y = SHAPE.getLayoutBounds().getMinY();
double width = SHAPE.getLayoutBounds().getWidth();
double height = SHAPE.getLayoutBounds().getHeight();
return new ImagePattern(getImage(width, height), x, y, width, height, false);
}
public void blur(final int[] IN, final int[] OUT, final int WIDTH, final int RADIUS) {
final int WIDTH_MINUS_1 = WIDTH - 1;
final int R2 = 2 * RADIUS + 1;
int tr = 0, tg = 0, tb = 0;
for (int i = -RADIUS; i <= RADIUS; i++) {
int rgb = IN[mod(i, WIDTH)];
tr += (rgb >> 16) & 0xff;
tg += (rgb >> 8) & 0xff;
tb += rgb & 0xff;
}
for (int x = 0; x < WIDTH; x++) {
OUT[x] = 0xff000000 | ((tr / R2) << 16) | ((tg / R2) << 8) | (tb / R2);
int i1 = x + RADIUS + 1;
if (i1 > WIDTH_MINUS_1) {
i1 = mod(i1, WIDTH);
}
int i2 = x - RADIUS;
if (i2 < 0) {
i2 = mod(i2, WIDTH);
}
int rgb1 = IN[i1];
int rgb2 = IN[i2];
tr += ((rgb1 & 0xff0000) - (rgb2 & 0xff0000)) >> 16;
tg += ((rgb1 & 0xff00) - (rgb2 & 0xff00)) >> 8;
tb += (rgb1 & 0xff) - (rgb2 & 0xff);
}
}
public void setRadius(final int RADIUS) {
radius = RADIUS;
}
public int getRadius() {
return radius;
}
public void setAmount(final double AMOUNT) {
amount = AMOUNT;
}
public double getAmount() {
return amount;
}
public void setColor(final int COLOR) {
color = COLOR;
}
public int getColor() {
return color;
}
public void setMonochrome(final boolean MONOCHROME) {
monochrome = MONOCHROME;
}
public boolean isMonochrome() {
return monochrome;
}
public void setShine(final double SHINE) {
shine = SHINE;
}
public double getShine() {
return shine;
}
private int random(int x) {
x += (int) (255 * (2 * randomNumbers.nextFloat() - 1) * amount);
if (x < 0) {
x = 0;
} else if (x > 0xff) {
x = 0xff;
}
return x;
}
private int clamp(final int C) {
int ret = C;
if (C < 0) {
ret = 0;
}
if (C > 255) {
ret = 255;
}
return ret;
}
private int mod(int a, final int B) {
final int N = a / B;
a -= N * B;
if (a < 0) {
return a + B;
}
return a;
}
private void setRGB(final WritableImage IMAGE, final int X, final int Y, final int[] PIXELS) {
final PixelWriter RASTER = IMAGE.getPixelWriter();
for (int x = 0 ; x < PIXELS.length ; x++) {
RASTER.setColor(X + x, Y, Color.rgb((PIXELS[x] >> 16) & 0xFF, (PIXELS[x] >> 8) & 0xFF, (PIXELS[x] &0xFF)));
}
}
private int getIntFromColor(final Color COLOR) {
String hex = COLOR.toString();
StringBuilder intValue = new StringBuilder(10);
intValue.append(hex.substring(8, 10));
intValue.append(hex.substring(2, 8));
return (int) Long.parseLong(intValue.toString(), 16);
}
}