package de.lessvoid.nifty.processing.renderer;
import java.io.File;
import java.net.URISyntaxException;
import de.lessvoid.nifty.render.BlendMode;
import de.lessvoid.nifty.spi.render.*;
import de.lessvoid.nifty.tools.Color;
import de.lessvoid.nifty.tools.resourceloader.NiftyResourceLoader;
import de.lessvoid.nifty.tools.resourceloader.FileSystemLocation;
import processing.core.*;
/**
* Implementation of Nifty's RenderDevice for Processing.
* @author Xuanming
*/
public class RenderDeviceProcessing implements RenderDevice {
private final PGraphics graphics;
private final PApplet app;
private NiftyResourceLoader resourceLoader;
private MouseCursor mouseCursor;
/**
* Instantiate RenderDeviceProcessing.
* @param app PApplet instance that Processing is currently running in.
*/
public RenderDeviceProcessing(PApplet app) {
this(app, app.width, app.height, true);
}
/**
* Instantiate RenderDeviceProcessing (verbose version)
* @param app PApplet instance that Processing is currently running in.
* @param width Desired width of Nifty instance.
* @param height Desired height of Nifty instance.
*/
public RenderDeviceProcessing(PApplet app, int width, int height, boolean render) {
this.graphics = app.createGraphics(width, height);
this.app = app;
// If self render is turned on, register this object with Processing draw method.
if (render) {
app.registerMethod("draw", this);
}
/*
* All classes in Processing are inner classes of the Processing PApplet instance.
* Creating a helper property to assist in finding inner ScreenController classes from XML.
* Using this property, users just need to specify 'controller="${PROP.APP}ControllerName"' in
* their XML layouts, where ControllerName is the name of the actual ScreenController impl.
*/
System.setProperty("APP", app.getClass().getName() + "$");
}
/**
* Draw method called from Processing if self render is turned on.
* Draw canvas onto Processing window.
*/
public void draw() {
app.image(graphics, 0, 0);
}
@Override
public void setResourceLoader(NiftyResourceLoader niftyResourceLoader) {
this.resourceLoader = niftyResourceLoader;
resourceLoader.addResourceLocation(new FileSystemLocation(new File(app.dataPath(""))));
}
@Override
public RenderImage createImage(String filename, boolean filterLinear) {
return new RenderImageProcessing(app.dataPath(filename), app);
}
@Override
public RenderFont createFont(String filename) {
try {
return new RenderFontProcessing(app, graphics, resourceLoader.getResource(filename).toURI().getPath());
} catch (URISyntaxException e) {
return new RenderFontProcessing(app, graphics, resourceLoader.getResource(filename).getPath());
}
}
@Override
public int getWidth() {
return graphics.width;
}
@Override
public int getHeight() {
return graphics.height;
}
@Override
public void beginFrame() {
graphics.beginDraw();
clear();
}
@Override
public void endFrame() {
graphics.endDraw();
}
@Override
public void clear() {
graphics.clear();
}
@Override
public void setBlendMode(BlendMode renderMode) {
switch (renderMode) {
case BLEND:
graphics.blendMode(PConstants.BLEND);
break;
case MULIPLY:
graphics.blendMode(PConstants.MULTIPLY);
break;
}
}
@Override
public void renderQuad(int x, int y, int width, int height, Color color) {
// Draw rectangle.
graphics.noStroke();
graphics.fill(convertColor(color));
graphics.rect(x, y, width, height);
}
@Override
public void renderQuad(int x, int y, int width, int height, Color topLeft,
Color topRight, Color bottomRight, Color bottomLeft) {
// Convert colors.
int topLeftC = convertColor(topLeft);
int topRightC = convertColor(topRight);
int bottomLeftC = convertColor(bottomLeft);
int bottomRightC = convertColor(bottomRight);
// Draw rectangle using pixels[] array.
graphics.loadPixels();
for (int k = y; k < y + height; k++) {
for (int i = x; i < x + width; i++) {
float xRange = PApplet.map(i, x, x + width, 0, 1);
float yRange = PApplet.map(k, y, y + height, 0, 1);
graphics.pixels[(k * graphics.width) + i] =
app.lerpColor(
app.lerpColor(bottomLeftC, bottomRightC, xRange),
app.lerpColor(topLeftC, topRightC, xRange),
yRange
)
;
}
}
graphics.updatePixels();
}
@Override
public void renderImage(RenderImage image, int x, int y, int width,
int height, Color color, float imageScale) {
PImage img;
if (width > 0 && height > 0 && imageScale > 0.0) {
if (image instanceof RenderImageProcessing){
img = ((RenderImageProcessing) image).resize(width, height, imageScale);
graphics.tint(convertColor(color));
graphics.image(img, x, y);
graphics.noTint();
}
}
}
@Override
public void renderImage(RenderImage image, int x, int y, int w, int h,
int srcX, int srcY, int srcW, int srcH, Color color, float scale,
int centerX, int centerY) {
PImage img;
if (w > 0 && h > 0 && scale > 0.0) {
if (image instanceof RenderImageProcessing) {
img = ((RenderImageProcessing) image).crop(srcX, srcY, srcW, srcH);
img.resize(w, h);
img.resize(Math.round(img.width * scale), Math.round(img.height * scale));
graphics.tint(convertColor(color));
graphics.image(img, x, y);
graphics.noTint();
}
}
}
@Override
public void renderFont(RenderFont font, String text, int x, int y,
Color fontColor, float sizeX, float sizeY) {
if (font instanceof RenderFontProcessing){
graphics.textFont(((RenderFontProcessing) font).getFont());
graphics.textSize(((RenderFontProcessing) font).getSize() * sizeX);
graphics.fill(convertColor(fontColor));
graphics.text(text, x, y + (int)((graphics.textDescent() + graphics.textAscent()) * 1.21));
}
}
@Override
public void enableClip(int x0, int y0, int x1, int y1) {
graphics.clip(x0, y0, x1 - x0, y1 - y0);
}
@Override
public void disableClip() {
graphics.noClip();
}
@Override
public MouseCursor createMouseCursor(String filename, int hotspotX, int hotspotY) {
return new MouseCursorProcessing(app, app.dataPath(filename), hotspotX, hotspotY);
}
@Override
public void enableMouseCursor(MouseCursor mouseCursor) {
this.mouseCursor = mouseCursor;
mouseCursor.enable();
}
@Override
public void disableMouseCursor() {
if (mouseCursor != null) {
mouseCursor.disable();
}
}
/**
* Get the Processing PGraphics object for external uses.
* @return PGraphics object that Nifty draws on.
*/
public PGraphics getCanvas() {
return graphics;
}
/**
* Convert the Nifty Color data type to the Processing one.
* @param c
* @return
*/
private int convertColor(Color c) {
return
app.color(
c.getRed() * 255,
c.getGreen() * 255,
c.getBlue() * 255,
c.getAlpha() * 255
)
;
}
}