package jadex.application.space.envsupport.observer.graphics.java2d;
import jadex.application.space.envsupport.math.IVector2;
import jadex.application.space.envsupport.observer.graphics.AbstractViewport;
import jadex.application.space.envsupport.observer.graphics.drawable.DrawableCombiner;
import jadex.application.space.envsupport.observer.graphics.drawable.Primitive;
import jadex.application.space.envsupport.observer.graphics.layer.Layer;
import jadex.application.space.envsupport.observer.perspective.IPerspective;
import jadex.commons.service.library.ILibraryService;
import java.awt.Canvas;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.awt.geom.AffineTransform;
import java.awt.image.AffineTransformOp;
import java.awt.image.BufferedImage;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import javax.imageio.ImageIO;
/**
* This class manages the GUI and all user interaction.
*/
public class ViewportJ2D extends AbstractViewport implements ComponentListener
{
private Map imageCache_;
/** Action that renders the frame. */
private Runnable renderFrameAction_;
/** The current draw context */
private Graphics2D context_;
/** The default transform */
private AffineTransform defaultTransform_;
/** The renderers. */
private static final IJ2DRenderer[] RENDERERS = new IJ2DRenderer[6];
static
{
RENDERERS[0] = new EllipseJ2DRenderer();
RENDERERS[1] = new RectangleJ2DRenderer();
RENDERERS[2] = new RegularPolygonJ2DRenderer();
RENDERERS[3] = new TextJ2DRenderer();
RENDERERS[4] = new TexturedRectangleJ2DRenderer();
RENDERERS[5] = new TriangleJ2DRenderer();
}
/** The layer renderers. */
private static final ILayerJ2DRenderer[] LAYER_RENDERERS = new ILayerJ2DRenderer[3];
static
{
LAYER_RENDERERS[0] = new ColorLayerJ2DRenderer();
LAYER_RENDERERS[1] = new GridLayerJ2DRenderer();
LAYER_RENDERERS[2] = new TiledLayerJ2DRenderer();
}
/**
* Creates a new Viewport.
*
* @param layerObject object holding properties for pre/postlayers
* @param libService the library service
*/
public ViewportJ2D(IPerspective persp, ILibraryService libService)
{
super(persp);
libService_ = libService;
imageCache_ = Collections.synchronizedMap(new HashMap());
canvas_ = new ViewportCanvas();
canvas_.addComponentListener(this);
MouseController mc = new MouseController();
canvas_.addMouseListener(mc);
canvas_.addMouseWheelListener(mc);
canvas_.addMouseMotionListener(mc);
renderFrameAction_ = new Runnable()
{
public void run()
{
rendering = false;
canvas_.repaint();
};
};
}
/**
* Returns an image for texturing
*
* @param path resource path of the image
*/
public BufferedImage getImage(String path)
{
BufferedImage image = (BufferedImage)imageCache_.get(path);
if(image == null)
{
image = loadImage(path);
imageCache_.put(path, image);
}
return image;
}
public void refresh()
{
if(!rendering)
{
rendering = true;
EventQueue.invokeLater(renderFrameAction_);
}
}
public Graphics2D getContext()
{
return context_;
}
/**
* Returns the default transform.
* @return the default transform
*/
public AffineTransform getDefaultTransform()
{
return defaultTransform_;
}
/**
* Sets up the image transform.
*
* @param sizeX image x-size
* @param sizeY image y-size
* @return the transform
*/
public AffineTransform getImageTransform(int sizeX, int sizeY)
{
AffineTransform imageTransform = new AffineTransform();
imageTransform.translate(1.0 * inversionFlag_.getXAsInteger(),
1.0 * inversionFlag_.getYAsInteger());
imageTransform.scale(-((inversionFlag_.getXAsInteger() << 1) - 1)
/ (double)sizeX, -((inversionFlag_.getYAsInteger() << 1) - 1)
/ (double)sizeY);
return imageTransform;
}
/**
* Draws a primitive
* @param dc The combiner.
* @param primitive The primitive.
* @param obj The object being drawn.
*/
public void drawPrimitive(DrawableCombiner dc, Primitive primitive, Object obj)
{
RENDERERS[primitive.getType()].prepareAndExecuteDraw(dc, primitive, obj, this);
}
/**
* Disposes the Viewport.
*/
public void dispose()
{
}
// Component events
public void componentHidden(ComponentEvent e)
{
}
public void componentMoved(ComponentEvent e)
{
}
public void componentResized(ComponentEvent e)
{
if ((canvas_.getWidth() == 0) || (canvas_.getHeight() == 0))
return;
IVector2 oldPaddedSize = paddedSize_.copy();
setSize(size_);
setPosition(paddedSize_.copy().subtract(oldPaddedSize).multiply(0.5).negate().add(position_));
}
public void componentShown(ComponentEvent e)
{
}
/**
* Loads an image.
*
* @param path resource path of the image
*/
private BufferedImage loadImage(String path)
{
ClassLoader cl = libService_.getClassLoader();
BufferedImage image = null;
try
{
image = ImageIO.read(cl.getResource(path));
AffineTransform tf = AffineTransform.getScaleInstance(1, -1);
tf.translate(0, -image.getHeight());
AffineTransformOp op = new AffineTransformOp(tf,
AffineTransformOp.TYPE_NEAREST_NEIGHBOR);
image = op.filter(image, null);
}
catch(Exception e)
{
}
return image;
}
private class ViewportCanvas extends Canvas
{
private BufferedImage backBuffer_;
private Rectangle.Double clearRectangle_;
public ViewportCanvas()
{
backBuffer_ = new BufferedImage(1, 1,
BufferedImage.TYPE_4BYTE_ABGR_PRE);
clearRectangle_ = new Rectangle.Double();
clearRectangle_.x = 0.0;
clearRectangle_.y = 0.0;
clearRectangle_.width = size_.getXAsDouble();
clearRectangle_.height = size_.getYAsDouble();
}
public Dimension minimumSize()
{
return new Dimension(1, 1);
}
public Dimension getMinimumSize()
{
return new Dimension(1, 1);
}
public void paint(Graphics gfx)
{
try
{
if ((getWidth() == 0) || (getHeight() == 0))
return;
if((backBuffer_.getWidth() != getWidth())
|| (backBuffer_.getHeight() != getHeight()))
{
backBuffer_ = new BufferedImage(getWidth(), getHeight(),
BufferedImage.TYPE_4BYTE_ABGR_PRE);
ViewportJ2D.this.setSize(size_);
}
Graphics2D g = (Graphics2D)backBuffer_.getGraphics();
defaultTransform_ = g.getTransform();
g.setColor(bgColor_);
g.fillRect(0, 0, getWidth(), getHeight());
Rectangle clipRect = getClippingBox();
if (getInvertX())
clipRect.x = canvas_.getWidth() - clipRect.x - clipRect.width;
if (!getInvertY())
clipRect.y = canvas_.getHeight() - clipRect.y - clipRect.height;
g.setClip(clipRect.x, clipRect.y, clipRect.width, clipRect.height);
setupTransform(g);
context_ = g;
synchronized(preLayers_)
{
for (int i = 0; i < preLayers_.length; ++i)
{
Layer l = preLayers_[i];
LAYER_RENDERERS[l.getType()].draw(getPerspective(), l, areaSize_, ViewportJ2D.this);
}
}
synchronized(objectList_)
{
synchronized(objectLayers_)
{
objectLayers_.clear();
for (Iterator it = objectList_.iterator(); it.hasNext(); )
{
Object[] o = (Object[]) it.next();
DrawableCombiner d = (DrawableCombiner) o[1];
if (!drawObjects_.contains(d))
{
//d.init(ViewportJ2D.this);
drawObjects_.add(d);
}
objectLayers_.addAll(d.getLayers());
}
AffineTransform tf = g.getTransform();
g.translate(objShiftX_, objShiftY_);
// TODO: Hack!, get Monitor to ensure object draw synchronization
Object monitor = getPerspective().getObserverCenter().getSpace().getMonitor();
for(Iterator it = objectLayers_.iterator(); it
.hasNext();)
{
Integer layer = (Integer)it.next();
Iterator it2 = objectList_.iterator();
while(it2.hasNext())
{
Object[] o = (Object[])it2.next();
Object obj = o[0];
DrawableCombiner d = (DrawableCombiner)o[1];
// TODO: Hack!, ensure object draw synchronization
synchronized (monitor)
{
d.draw(obj, layer, ViewportJ2D.this);
}
}
}
g.setTransform(tf);
}
}
synchronized(postLayers_)
{
for (int i = 0; i < postLayers_.length; ++i)
{
Layer l = postLayers_[i];
LAYER_RENDERERS[l.getType()].draw(getPerspective(), l, areaSize_, ViewportJ2D.this);
}
}
context_ = null;
g.setTransform(defaultTransform_);
g.dispose();
gfx.drawImage(backBuffer_, 0, 0, null);
gfx.dispose();
}
catch(IllegalStateException e)
{
}
}
public void update(Graphics g)
{
paint(g);
}
private void setupTransform(Graphics2D g)
{
g.translate(
backBuffer_.getWidth() * inversionFlag_.getXAsInteger(),
backBuffer_.getHeight()
* (inversionFlag_.getYAsInteger() ^ 1));
g.scale((backBuffer_.getWidth() / paddedSize_.getXAsDouble())
* -((inversionFlag_.getXAsInteger() << 1) - 1),
(backBuffer_.getHeight() / paddedSize_.getYAsDouble())
* ((inversionFlag_.getYAsInteger() << 1) - 1));
g.translate(-pixPosition_.getXAsDouble(), -pixPosition_.getYAsDouble());
}
}
}