Graphics2D wrapper for Texture

I made an wrapper for drawing on texture using Graphics2D functionality.

It supports only RGB image (without alpha) and don’t support sub image update.

Feel free to use this. :slight_smile:

I wish someone helps me about the sub-texture update and alpha/gray image support.





[java]

package jme3test.texture;



import java.awt.Color;

import java.awt.image.BufferedImage;

import java.io.IOException;



import javax.imageio.ImageIO;



import com.jme3.app.SimpleApplication;

import com.jme3.asset.TextureKey;

import com.jme3.input.KeyInput;

import com.jme3.input.controls.ActionListener;

import com.jme3.input.controls.KeyTrigger;

import com.jme3.material.Material;

import com.jme3.math.FastMath;

import com.jme3.math.Vector3f;

import com.jme3.scene.Geometry;

import com.jme3.scene.shape.Box;

import com.jme3.texture.Texture;



public class TestTextureGraphics extends SimpleApplication {



private TextureGraphics g;

private Color[] COLORS = new Color[] { Color.black, Color.black, Color.green, Color.blue, Color.gray };



private void drawColor() {

for (int i = 0; i < 10; i++) {

int x = FastMath.nextRandomInt(0, settings.getWidth());

int y = FastMath.nextRandomInt(0, settings.getHeight());

g.setColor(COLORS[(int)(FastMath.nextRandomFloat()COLORS.length)]);

g.fillOval(x, y, settings.getWidth()/10, settings.getWidth()/10);

}

g.update();

}



private void drawImage() throws IOException {

BufferedImage img = ImageIO.read(getClass().getResourceAsStream("/Interface/Logo/Monkey.jpg"));

g.drawImage(img, 0, 0, null);

g.update();

}



@Override

public void simpleInitApp() {

Box mesh = new Box(Vector3f.ZERO, 1, 1, 1);

Geometry geom = new Geometry(“Box”, mesh);

Material mat = new Material(assetManager, “Common/MatDefs/Misc/SimpleTextured.j3md”);

TextureKey key = new TextureKey(“Interface/Logo/Monkey.jpg”, false);

Texture t = assetManager.loadTexture(key);

mat.setTexture(“ColorMap”, t);

g = new TextureGraphics(t);

geom.setMaterial(mat);

rootNode.attachChild(geom);



inputManager.addMapping(“color”, new KeyTrigger(KeyInput.KEY_1));

inputManager.addMapping(“image”, new KeyTrigger(KeyInput.KEY_2));

inputManager.addListener(new ActionListener() {

@Override

public void onAction(String name, boolean isPressed, float tpf) {

if (name.equals(“color”)) {

drawColor();

} else if (name.equals(“image”)) {

try {

drawImage();

} catch (IOException e) {

e.printStackTrace();

}

}

} }, “color”, “image”);

}



public static void main(String[] args) {

TestTextureGraphics test = new TestTextureGraphics();

test.start();

}

}

[/java]



[java]

package com.rontab.bim.render;



import java.awt.
;

import java.awt.RenderingHints.Key;

import java.awt.font.FontRenderContext;

import java.awt.font.GlyphVector;

import java.awt.geom.AffineTransform;

import java.awt.image.BufferedImage;

import java.awt.image.BufferedImageOp;

import java.awt.image.DataBuffer;

import java.awt.image.DataBufferByte;

import java.awt.image.ImageObserver;

import java.awt.image.RenderedImage;

import java.awt.image.renderable.RenderableImage;

import java.lang.ref.WeakReference;

import java.nio.ByteBuffer;

import java.text.AttributedCharacterIterator;

import java.util.Map;



import com.jme3.texture.Image;

import com.jme3.texture.Image.Format;

import com.jme3.texture.Texture;



/**

  • Apply Graphics2D operation on Texture image
  • @author Lim, YongHoon(mulova)

    */

    public class TextureGraphics extends Graphics2D {

    private BufferedImage canvasImage;

    private WeakReference<Texture> texture;

    private Graphics2D g;

    private boolean frequentUpdate = true;



    public TextureGraphics(Texture tex) {

    super();

    this.texture = new WeakReference<Texture>(tex);

    canvasImage = new BufferedImage(tex.getImage().getWidth(), tex.getImage().getHeight(),

    BufferedImage.TYPE_3BYTE_BGR);

    }



    /**
  • @param update
  •        set true if image is updated frequently. &lt;br&gt;<br />
    
  •        if true, keep graphics instance but use more resource.<br />
    

*/

public void setFrequentUpdate(boolean update) {

this.frequentUpdate = update;

}



public Graphics2D getGraphics() {

if (g == null) {

g = canvasImage.createGraphics();

}

return g;

}



public int getWidth() {

return canvasImage.getWidth();

}



public int getHeight() {

return canvasImage.getHeight();

}



/**

  • TODO performance issue. find a way not to pick a pixel one by one TODO
  • performance issue. copy image data only selected bound

    *
  • @param bound
  •        if null, the whole image bound is updated<br />
    

*/

public boolean update() {

if (g == null)

return false;

Texture tex = texture.get();

if (tex == null)

return false;

// final byte data[] = toByteArray(canvasImage, bound);

final byte data[] = extractImageData(canvasImage);

Image image = tex.getImage();

image.setFormat(Format.BGR8);

ByteBuffer imageBuffer = image.getData(0);

imageBuffer.rewind();

imageBuffer.put(data);

imageBuffer.flip();

image.setUpdateNeeded();



if (!frequentUpdate) {

g.dispose();

g = null;

}



return true;

}



private byte[] extractImageData(BufferedImage img){

DataBuffer buf = img.getRaster().getDataBuffer();

switch (buf.getDataType()){

case DataBuffer.TYPE_BYTE:

DataBufferByte byteBuf = (DataBufferByte) buf;

return byteBuf.getData();

}

return null;

}



byte[] arr;

private byte[] toByteArray(final BufferedImage image, Rectangle bound) {

final int width = image.getWidth(null);

final int height = image.getHeight(null);

final boolean hasAlpha = image.getColorModel().hasAlpha();

final boolean grayscale = image.getColorModel().getNumComponents() == 1;



if (image.getRaster().getTransferType() == DataBuffer.TYPE_BYTE) {

return (byte[]) image.getRaster().getDataElements(0, 0, width, height, null);

}



if (arr == null) {

arr = new byte[width * height * (grayscale ? 1 : (hasAlpha ? 4 : 3))];

}

final int[] tmpData = new int[width];

int index = 0;

for (int y = height-1; y >= 0; y–) {

image.getRGB(0, y, width, 1, tmpData, 0, width);

for (int i = 0; i < width; i++) {

final int argb = tmpData;

if (grayscale) {

arr[index++] = (byte) (argb & 0xFF);

} else {

if (hasAlpha) {

arr[index++] = (byte) (argb & 0xFF);

}

arr[index++] = (byte) ((argb >> 8) & 0xFF);

arr[index++] = (byte) ((argb >> 16) & 0xFF);

arr[index++] = (byte) ((argb >> 24) & 0xFF);

}

}

}

return arr;

}



@Override

public void dispose() {

if (g != null) {

g.dispose();

}

}



@Override

public void draw(Shape s) {

getGraphics().draw(s);

}



@Override

public boolean drawImage(java.awt.Image img, AffineTransform xform, ImageObserver obs) {

return getGraphics().drawImage(img, xform, obs);

}



@Override

public void drawImage(BufferedImage img, BufferedImageOp op, int x, int y) {

getGraphics().drawImage(img, op, x, y);

}



@Override

public void drawRenderedImage(RenderedImage img, AffineTransform xform) {

getGraphics().drawRenderedImage(img, xform);

}



@Override

public void drawRenderableImage(RenderableImage img, AffineTransform xform) {

getGraphics().drawRenderableImage(img, xform);

}



@Override

public void drawString(String str, int x, int y) {

getGraphics().drawString(str, x, y);

}



@Override

public void drawString(String str, float x, float y) {

getGraphics().drawString(str, x, y);

}



@Override

public void drawString(AttributedCharacterIterator iterator, int x, int y) {

getGraphics().drawString(iterator, x, y);

}



@Override

public void drawString(AttributedCharacterIterator iterator, float x, float y) {

getGraphics().drawString(iterator, x, y);

}



@Override

public void drawGlyphVector(GlyphVector g, float x, float y) {

this.getGraphics().drawGlyphVector(g, x, y);

}



@Override

public void fill(Shape s) {

getGraphics().fill(s);

}



@Override

public boolean hit(java.awt.Rectangle rect, Shape s, boolean onStroke) {

return getGraphics().hit(rect, s, onStroke);

}



@Override

public GraphicsConfiguration getDeviceConfiguration() {

return getGraphics().getDeviceConfiguration();

}



@Override

public void setComposite(Composite comp) {

getGraphics().setComposite(comp);

}



@Override

public void setPaint(Paint paint) {

getGraphics().setPaint(paint);

}



@Override

public void setStroke(Stroke s) {

getGraphics().setStroke(s);

}



@Override

public void setRenderingHint(Key hintKey, Object hintValue) {

getGraphics().setRenderingHint(hintKey, hintValue);

}



@Override

public Object getRenderingHint(Key hintKey) {

return getGraphics().getRenderingHint(hintKey);

}



@Override

public void setRenderingHints(Map<?, ?> hints) {

getGraphics().setRenderingHints(hints);

}



@Override

public void addRenderingHints(Map<?, ?> hints) {

getGraphics().addRenderingHints(hints);

}



@Override

public RenderingHints getRenderingHints() {

return getGraphics().getRenderingHints();

}



@Override

public void translate(int x, int y) {

getGraphics().translate(x, y);

}



@Override

public void translate(double tx, double ty) {

getGraphics().translate(tx, ty);

}



@Override

public void rotate(double theta) {

getGraphics().rotate(theta);

}



@Override

public void rotate(double theta, double x, double y) {

getGraphics().rotate(theta, x, y);

}



@Override

public void scale(double sx, double sy) {

getGraphics().scale(sx, sy);

}



@Override

public void shear(double shx, double shy) {

getGraphics().shear(shx, shy);

}



@Override

public void transform(AffineTransform Tx) {

getGraphics().transform(Tx);

}



@Override

public void setTransform(AffineTransform Tx) {

getGraphics().setTransform(Tx);

}



@Override

public AffineTransform getTransform() {

return getGraphics().getTransform();

}



@Override

public Paint getPaint() {

return getGraphics().getPaint();

}



@Override

public Composite getComposite() {

return getGraphics().getComposite();

}



@Override

public void setBackground(Color color) {

getGraphics().setBackground(color);

}



@Override

public Color getBackground() {

return getGraphics().getBackground();

}



@Override

public Stroke getStroke() {

return getGraphics().getStroke();

}



@Override

public void clip(Shape s) {

getGraphics().clip(s);

}



@Override

public FontRenderContext getFontRenderContext() {

return getGraphics().getFontRenderContext();

}



@Override

public Graphics create() {

return getGraphics().create();

}



@Override

public Color getColor() {

return getGraphics().getColor();

}



@Override

public void setColor(Color c) {

getGraphics().setColor©;

}



@Override

public void setPaintMode() {

getGraphics().setPaintMode();

}



@Override

public void setXORMode(Color c1) {

getGraphics().setXORMode(c1);

}



@Override

public Font getFont() {

return getGraphics().getFont();

}



@Override

public void setFont(Font font) {

getGraphics().setFont(font);

}



@Override

public FontMetrics getFontMetrics(Font f) {

return getGraphics().getFontMetrics(f);

}



@Override

public java.awt.Rectangle getClipBounds() {

return getGraphics().getClipBounds();

}



@Override

public void clipRect(int x, int y, int width, int height) {

getGraphics().clipRect(x, y, width, height);

}



@Override

public void setClip(int x, int y, int width, int height) {

getGraphics().setClip(x, y, width, height);

}



@Override

public Shape getClip() {

return getGraphics().getClip();

}



@Override

public void setClip(Shape clip) {

getGraphics().setClip(clip);

}



@Override

public void copyArea(int x, int y, int width, int height, int dx, int dy) {

getGraphics().copyArea(x, y, width, height, dx, dy);

}



@Override

public void drawLine(int x1, int y1, int x2, int y2) {

getGraphics().drawLine(x1, y1, x2, y2);

}



@Override

public void fillRect(int x, int y, int width, int height) {

getGraphics().fillRect(x, y, width, height);

}



@Override

public void clearRect(int x, int y, int width, int height) {

getGraphics().clearRect(x, y, width, height);

}



@Override

public void drawRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight) {

getGraphics().drawRoundRect(x, y, width, height, arcWidth, arcHeight);

}



@Override

public void fillRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight) {

getGraphics().fillRoundRect(x, y, width, height, arcWidth, arcHeight);

}



@Override

public void drawOval(int x, int y, int width, int height) {

getGraphics().drawOval(x, y, width, height);

}



@Override

public void fillOval(int x, int y, int width, int height) {

getGraphics().fillOval(x, y, width, height);

}



@Override

public void drawArc(int x, int y, int width, int height, int startAngle, int arcAngle) {

getGraphics().drawArc(x, y, width, height, startAngle, arcAngle);

}



@Override

public void fillArc(int x, int y, int width, int height, int startAngle, int arcAngle) {

getGraphics().fillArc(x, y, width, height, startAngle, arcAngle);

}



@Override

public void drawPolyline(int[] xPoints, int[] yPoints, int nPoints) {

getGraphics().drawPolyline(xPoints, yPoints, nPoints);

}



@Override

public void drawPolygon(int[] xPoints, int[] yPoints, int nPoints) {

getGraphics().drawPolygon(xPoints, yPoints, nPoints);

}



@Override

public void fillPolygon(int[] xPoints, int[] yPoints, int nPoints) {

getGraphics().fillPolygon(xPoints, yPoints, nPoints);

}



@Override

public boolean drawImage(java.awt.Image img, int x, int y, ImageObserver observer) {

return getGraphics().drawImage(img, x, y, observer);

}



@Override

public boolean drawImage(java.awt.Image img, int x, int y, int width, int height, ImageObserver observer) {

return getGraphics().drawImage(img, x, y, width, height, observer);

}



@Override

public boolean drawImage(java.awt.Image img, int x, int y, Color bgcolor, ImageObserver observer) {

return getGraphics().drawImage(img, x, y, bgcolor, observer);

}



@Override

public boolean drawImage(java.awt.Image img, int x, int y, int width, int height, Color bgcolor,

ImageObserver observer) {

return getGraphics().drawImage(img, x, y, width, height, bgcolor, observer);

}



@Override

public boolean drawImage(java.awt.Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2,

int sy2, ImageObserver observer) {

return getGraphics().drawImage(img, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, observer);

}



@Override

public boolean drawImage(java.awt.Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2,

int sy2, Color bgcolor, ImageObserver observer) {

return getGraphics().drawImage(img, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, bgcolor, observer);

}



}



[/java]

Wow great thats exactly what I need for my NH-Edit programm, perfect for a short preview of the textures :slight_smile:

I hope it helps!:smiley:

If you want to flip image, you can do it by AWTLoader.flipImage()

I didn’t include it for the performance reason.

Generally I don’t flip image but flip texture coordinates.