package framework.RWT;
import java.awt.AWTEvent;
import java.awt.Canvas;
import java.awt.Container;
import java.awt.Graphics;
import java.awt.GraphicsConfiguration;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import javax.media.j3d.Canvas3D;
import javax.media.j3d.ImageComponent2D;
import javax.media.j3d.View;
import javax.swing.event.MouseInputListener;
import com.sun.j3d.utils.universe.SimpleUniverse;
import framework.model3D.IViewer3D;
import framework.model3D.Universe;
import framework.schedule.ScheduleManager;
import framework.schedule.TaskController;
import framework.view3D.Camera3D;
import framework.view3D.Viewer3D;
/**
* GUI部品(RWTWidget)を配置可能なCanvas3D、親コンテナに対して相対座標で配置できる
* @author 新田直也
*
*/
@SuppressWarnings("serial")
public class RWTCanvas3D extends Canvas3D {
private ArrayList<RWTWidget> widgetList = new ArrayList<RWTWidget>();
private float relativeX = 0.0f;
private float relativeY = 0.0f;
private float relativeWidth = 0.0f;
private float relativeHeight = 0.0f;
private int x = 0;
private int y = 0;
private int width = 0;
private int height = 0;
private Camera3D camera = null;
private IViewer3D viewer = null;
private DisplayCanvas displayCanvas = null;
private BufferedImage image = null;
private static TaskController renderingController = ScheduleManager.getInstance().registerTask("rendering");
public RWTCanvas3D() {
this(SimpleUniverse.getPreferredConfiguration());
}
public RWTCanvas3D(GraphicsConfiguration gc) {
this(gc, false);
}
public RWTCanvas3D(boolean offScreen) {
this(SimpleUniverse.getPreferredConfiguration(), offScreen);
}
public RWTCanvas3D(GraphicsConfiguration gc, boolean offScreen) {
super(gc, offScreen);
setFocusable(false);
if (offScreen) {
displayCanvas = new DisplayCanvas();
} else {
enableEvents(AWTEvent.MOUSE_EVENT_MASK | AWTEvent.MOUSE_MOTION_EVENT_MASK);
}
renderingController.deactivate();
}
public Canvas getDisplayCanvas() {
if (isOffScreen()) {
return displayCanvas;
}
return this;
}
public void attachCamera(Camera3D camera) {
viewer = new Viewer3D(camera);
View oldView = this.getView();
if (oldView != null) oldView.removeCanvas3D(this);
camera.getView().addCanvas3D(this);
this.camera = camera;
}
/**
* Widgetを配置する。
* @param widget
*/
public void addWidget(RWTWidget widget) {
widgetList.add(widget);
}
/**
* RWTCanvas3Dの相対位置を決定する。
* @param x x座標値(0.0f〜1.0f)
* @param y y座標値(0.0f〜1.0f)
*/
public void setRelativePosition(float x, float y) {
relativeX = x;
relativeY = y;
}
/**
* RWTCanvas3Dの相対サイズを決定する。
* @param w 幅(0.0f〜1.0f)
* @param h 高さ(0.0f〜1.0f)
*/
public void setRelativeSize(float w, float h) {
relativeWidth = w;
relativeHeight = h;
}
/**
* 親のコンテナに応じて位置とサイズを合わせる。
* @param parent 親コンテナ
*/
public void adjust(Container parent) {
int sx = parent.getWidth();
int sy = parent.getHeight();
x = (int) (sx * relativeX);
y = (int) (sy * relativeY);
width = (int) (sx * relativeWidth);
height = (int) (sy * relativeHeight);
if (isOffScreen()) {
image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
ImageComponent2D ic = new ImageComponent2D(ImageComponent2D.FORMAT_RGBA, image, true, false);
ic.setCapability(ImageComponent2D.ALLOW_IMAGE_READ);
ic.setCapability(ImageComponent2D.ALLOW_IMAGE_WRITE);
setOffScreenBuffer(ic);
displayCanvas.setBounds(x, y, width, height);
getScreen3D().setSize(width, height);
getScreen3D().setPhysicalScreenWidth(0.0254/90.0 * (double)width);
getScreen3D().setPhysicalScreenHeight(0.0254/90.0 * (double)height);
} else {
setBounds(x, y, width, height);
}
}
@Override
public void preRender() {
if (viewer == null || camera == null) return;
viewer.setGraphicsContext3D(this.getGraphicsContext3D());
camera.getUniverse().preRender(viewer);
}
@Override
public void renderField(int fieldDesc) {
if (viewer == null || camera == null) return;
viewer.setGraphicsContext3D(this.getGraphicsContext3D());
camera.getUniverse().renderField(viewer);
}
@Override
public void postRender() {
if (viewer == null || camera == null) return;
viewer.setGraphicsContext3D(this.getGraphicsContext3D());
camera.getUniverse().postRender(viewer);
if (isOffScreen()) {
// オフスクリーンバッファ上の画像取得
ImageComponent2D ic = getOffScreenBuffer();
image = ic.getImage();
Graphics src = image.getGraphics();
// キャンバス上の Widget を合成
drawWidgets(src);
src.dispose();
// ディスプレイバッファに描画
Graphics dst = displayCanvas.getGraphics();
dst.drawImage(image, 0, 0, null);
dst.dispose();
}
}
@Override
public void postSwap() {
super.postSwap();
if (!isOffScreen()) {
// キャンバス上の Widget の描画
Graphics g = getGraphics();
drawWidgets(g);
g.dispose();
}
renderingController.deactivate();
}
/**
* オフスクリーンの場合のみ、レンダリングを明示的にスケジューリングする
*/
public void doRender() {
if (isOffScreen()) {
if (renderingController.activate()) {
// 前回のレンダリングが終了していた場合
renderOffScreenBuffer();
}
}
}
private void drawWidgets(Graphics g) {
for(int i = 0; i < widgetList.size(); i++) {
RWTWidget widget = widgetList.get(i);
if(widget.isVisible()) {
widget.adjust(this);
widget.paint(g);
}
}
}
public void processEvent(AWTEvent e) {
// イベントをコンテナ側に返す
Container c = this.getParent();
if (c != null) c.dispatchEvent(e);
}
private class DisplayCanvas extends Canvas {
public DisplayCanvas() {
setFocusable(false);
enableEvents(AWTEvent.MOUSE_EVENT_MASK | AWTEvent.MOUSE_MOTION_EVENT_MASK);
}
public void paint(Graphics g) {
super.paint(g);
if (image != null) {
synchronized (image) {
g.drawImage(image, 0, 0, null);
}
}
}
public void processEvent(AWTEvent e) {
// イベントをコンテナ側に返す
Container c = this.getParent();
if (c != null) c.dispatchEvent(e);
}
}
}