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.
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. <br><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]