package org.ripple.power.ui.projector;
import java.awt.AWTEvent;
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.ImageCapabilities;
import java.awt.Toolkit;
import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.awt.image.VolatileImage;
import org.ripple.power.config.LSystem;
import org.ripple.power.timer.LTimerContext;
import org.ripple.power.timer.SystemTimer;
import org.ripple.power.ui.graphics.LColor;
import org.ripple.power.ui.graphics.LGraphics;
import org.ripple.power.ui.graphics.geom.RectBox;
import org.ripple.power.ui.projector.core.LHandler;
import org.ripple.power.ui.projector.core.graphics.Screen;
import org.ripple.power.utils.GraphicsUtils;
public class UIView extends Canvas implements Runnable {
private static final long serialVersionUID = 1982278682597393958L;
final static private Toolkit systemToolKit = GraphicsUtils.toolKit;
private final static long MAX_INTERVAL = 1000L;
private boolean isStart, isFPS, isMemory;
private Image logo;
private String actionName;
final static private Font fpsFont = GraphicsUtils.getFont(Font.SANS_SERIF,
0, 20);
private transient long remainderMicros;
private transient boolean running = true;
private transient int repaintMode;
private long maxFrames, startTime, offsetTime, curFPS, calcInterval,
lastTimeMicros, elapsedTime;
private transient double frameCount;
private boolean isSupportHardware;
private Dimension dimension;
private LHandler handler;
private LGraphics gl;
private VolatileImage hardwareImage;
private BufferedImage awtImage;
private Thread mainLoop;
private UIContext context;
public UIView(LHandler handler) {
format(handler);
}
/**
* 创建GameView初始设置
*
* @param handler
*/
public void format(LHandler handler) {
this.handler = handler;
if (handler != null) {
handler.setView(this);
}
this.context = LSystem.getInstance().registerApp(this);
this.setFPS(LSystem.DEFAULT_MAX_FPS);
this.setBackground(Color.BLACK);
this.dimension = new Dimension(handler.getWidth(), handler.getHeight());
this.setSize(dimension);
this.setIgnoreRepaint(true);
this.addFocusListener(handler);
this.addKeyListener(handler);
this.addMouseListener(handler);
this.addMouseMotionListener(handler);
this.setIgnoreRepaint(true);
this.enableInputMethods(true);
}
/**
* 返回当前正在使用的游戏画布
*
* @return
*/
public LGraphics getLGraphics() {
return gl;
}
/**
* 创建初始的Graphics
*/
public void createScreen() {
int width = getWidth();
int height = getHeight();
try {
hardwareImage = createVolatileImage(width, height,
new ImageCapabilities(true));
} catch (Exception e) {
hardwareImage = null;
int pixelSize = width * height;
int[] pixels = new int[pixelSize];
this.awtImage = GraphicsUtils.newAwtRGBImage(pixels, width, height,
pixelSize);
}
if (hardwareImage == null) {
this.isSupportHardware = false;
this.gl = new LGraphics(awtImage);
} else {
this.isSupportHardware = true;
this.gl = new LGraphics(hardwareImage);
}
LSystem.screenRect = new RectBox(0, 0, width, height);
}
/**
* 销毁图形资源
*
*/
public void destroy() {
synchronized (this) {
handler.destroy();
LSystem.getInstance().unregisterApp(this);
context = null;
if (gl != null) {
gl.dispose();
gl = null;
}
LSystem.destroy();
notifyAll();
}
}
/**
* 获得窗体图像
*
* @return
*/
final public Image getAwtImage() {
if (isSupportHardware) {
return hardwareImage;
} else {
return awtImage;
}
}
/**
* 刷新绘图
*
*/
public synchronized void update() {
if (running) {
Graphics currentControl = this.getGraphics();
if (currentControl != null) {
currentControl.drawImage(getAwtImage(), 0, 0, null);
systemToolKit.sync();
gl.restore();
}
}
}
/**
* 刷新图像到指定位置
*
* @param img
* @param x
* @param y
*/
public synchronized void updateLocation(BufferedImage img, int x, int y) {
if (running) {
Graphics currentControl = this.getGraphics();
if (currentControl != null) {
currentControl.drawImage(img, x, y, null);
systemToolKit.sync();
}
}
}
/**
* 刷新绘图,成比例调整显示位置(居中)
*/
public synchronized void update(BufferedImage img, int w, int h) {
if (running) {
Graphics currentControl = this.getGraphics();
if (currentControl != null) {
currentControl.drawImage(img, getWidth() / 2 - w / 2,
getHeight() / 2 - h / 2, null);
systemToolKit.sync();
}
}
}
/**
* 刷新绘图,成比例调整显示位置(画面变更为指定大小)
*
* @param img
* @param w
* @param h
*/
public synchronized void updateFull(BufferedImage img, int w, int h) {
if (running) {
Graphics currentControl = this.getGraphics();
if (currentControl != null) {
currentControl.drawImage(img, getWidth() / 2 - w / 2,
getHeight() / 2 - h / 2, w, h, null);
systemToolKit.sync();
}
}
}
/**
* 刷新绘图
*/
public synchronized void update(BufferedImage img) {
if (running) {
Graphics currentControl = this.getGraphics();
if (currentControl != null) {
currentControl.drawImage(img, 0, 0, null);
systemToolKit.sync();
}
}
}
/**
* GameView内部线程
*
*/
public void run() {
final LTimerContext timerContext = new LTimerContext();
final SystemTimer timer = LSystem.getSystemTimer();
long currTimeMicros, goalTimeMicros, elapsedTimeMicros;
Thread currentThread = Thread.currentThread();
do {
if (LSystem.isPaused) {
GraphicsUtils.wait(300);
lastTimeMicros = timer.getTimeMicros();
elapsedTime = 0;
remainderMicros = 0;
}
if (!isStart) {
Thread.yield();
continue;
}
if (!handler.next()) {
if (LSystem.AUTO_REPAINT) {
this.update();
}
continue;
}
handler.calls();
goalTimeMicros = lastTimeMicros + 1000000L / maxFrames;
currTimeMicros = timer.sleepTimeMicros(goalTimeMicros);
elapsedTimeMicros = currTimeMicros - lastTimeMicros
+ remainderMicros;
elapsedTime = Math.max(0, (int) (elapsedTimeMicros / 1000));
remainderMicros = elapsedTimeMicros - elapsedTime * 1000;
lastTimeMicros = currTimeMicros;
timerContext.millisSleepTime = remainderMicros;
timerContext.timeSinceLastUpdate = elapsedTime;
handler.runTimer(timerContext);
if (LSystem.AUTO_REPAINT) {
repaintMode = handler.getRepaintMode();
switch (repaintMode) {
case Screen.SCREEN_BITMAP_REPAINT:
if (handler.getX() == 0 && handler.getY() == 0) {
gl.drawImage(handler.getBackground(), 0, 0);
} else {
gl.drawClear();
gl.drawImage(handler.getBackground(), handler.getX(),
handler.getY());
}
break;
case Screen.SCREEN_CANVAS_REPAINT:
gl.drawClear();
break;
case Screen.SCREEN_NOT_REPAINT:
break;
default:
if (handler.getX() == 0 && handler.getY() == 0) {
gl.drawImage(
handler.getBackground(),
repaintMode / 2
- LSystem.random.nextInt(repaintMode),
repaintMode / 2
- LSystem.random.nextInt(repaintMode));
} else {
gl.drawClear();
gl.drawImage(handler.getBackground(),
handler.getX() + repaintMode / 2
- LSystem.random.nextInt(repaintMode),
handler.getY() + repaintMode / 2
- LSystem.random.nextInt(repaintMode));
}
break;
}
handler.draw(gl);
if (isFPS) {
tickFrames();
gl.setAntiAlias(true);
gl.setFont(fpsFont);
gl.setColor(LColor.white);
gl.drawString("FPS:" + curFPS, 10, 25);
gl.setAntiAlias(false);
}
if (isMemory) {
Runtime runtime = Runtime.getRuntime();
long totalMemory = runtime.totalMemory();
long currentMemory = totalMemory - runtime.freeMemory();
String memoryUsage = ((float) ((currentMemory * 10) >> 20) / 10)
+ " of "
+ ((float) ((totalMemory * 10) >> 20) / 10) + " MB";
gl.setAntiAlias(true);
gl.setFont(fpsFont);
gl.setColor(LColor.white);
gl.drawString("MEMORY:" + memoryUsage, 5, 45);
gl.setAntiAlias(false);
}
this.update();
}
if (isFocusOwner()) {
Thread.yield();
LSystem.isPaused = false;
continue;
} else {
LSystem.isPaused = true;
}
} while (running && mainLoop == currentThread);
this.destroy();
}
/**
* 生成FPS数值
*
*/
private void tickFrames() {
frameCount++;
calcInterval += offsetTime;
if (calcInterval >= MAX_INTERVAL) {
long timeNow = System.currentTimeMillis();
long realElapsedTime = timeNow - startTime;
curFPS = Math.min(maxFrames,
(long) ((frameCount / realElapsedTime) * MAX_INTERVAL));
frameCount = 0L;
calcInterval = 0L;
startTime = timeNow;
}
}
protected void processEvent(AWTEvent e) {
super.processEvent(e);
if (e instanceof MouseEvent) {
if (!isFocusOwner()) {
requestFocus();
}
} else if (e instanceof KeyEvent) {
if (!isFocusOwner()) {
requestFocus();
}
}
}
public String getActionCommand() {
return actionName;
}
public void setActionCommand(String name) {
this.actionName = name;
}
public Thread getMainLoop() {
return mainLoop;
}
public void mainLoop() {
mainLoop = context.createThread(this);
try {
mainLoop.setPriority(Thread.NORM_PRIORITY);
} catch (SecurityException ex) {
}
context.setAnimationThread(mainLoop);
mainLoop.start();
}
public void mainStop() {
this.mainLoop = null;
}
public void startPaint() {
this.isStart = true;
}
public void endPaint() {
this.isStart = false;
}
public void setFPS(long frames) {
this.maxFrames = frames;
this.offsetTime = (long) (1.0 / maxFrames * MAX_INTERVAL);
}
public long getMaxFPS() {
return this.maxFrames;
}
public long getCurrentFPS() {
return this.curFPS;
}
public void setShowFPS(boolean isFPS) {
this.isFPS = isFPS;
}
public boolean isShowMemory() {
return isMemory;
}
public void setShowMemory(boolean showMemory) {
this.isMemory = showMemory;
}
public Image getLogo() {
return logo;
}
public void setLogo(Image logo) {
this.logo = logo;
}
public void setLogo(String fileName) {
this.setLogo(GraphicsUtils.loadNotCacheImage(fileName));
}
public boolean isRunning() {
return running;
}
public void setRunning(boolean running) {
this.running = running;
}
public boolean isSupportHardware() {
return isSupportHardware;
}
public LHandler getHandler() {
return handler;
}
}