package org.loon.framework.game.simple;
import java.awt.AWTEvent;
import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Composite;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.event.InputMethodEvent;
import java.awt.event.InputMethodListener;
import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
import java.awt.font.TextAttribute;
import java.awt.font.TextHitInfo;
import java.awt.font.TextLayout;
import java.awt.im.InputMethodRequests;
import java.awt.image.BufferedImage;
import java.text.AttributedCharacterIterator;
import java.text.AttributedString;
import java.text.AttributedCharacterIterator.Attribute;
import org.loon.framework.game.simple.core.EmulatorButtons;
import org.loon.framework.game.simple.core.EmulatorListener;
import org.loon.framework.game.simple.core.IHandler;
import org.loon.framework.game.simple.core.LSystem;
import org.loon.framework.game.simple.core.graphics.IScreen;
import org.loon.framework.game.simple.core.graphics.device.LGraphics;
import org.loon.framework.game.simple.core.graphics.device.LGraphicsJava2D;
import org.loon.framework.game.simple.core.timer.LTimerContext;
import org.loon.framework.game.simple.core.timer.SystemTimer;
import org.loon.framework.game.simple.utils.GraphicsUtils;
/**
* Copyright 2008 - 2009
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*
* @project loonframework
* @author chenpeng
* @emailceponline ceponline@yahoo.com.cn
* @version 0.1.2
*/
public class Java2DView extends Java2DCanvas implements IView, Runnable,
InputMethodListener, InputMethodRequests {
private static final long serialVersionUID = 1982278682597393958L;
final static private Toolkit systemToolKit = GraphicsUtils.toolKit;
private final static long MAX_INTERVAL = 1000L;
private boolean start, isFPS;
private String actionName;
private AttributedString composedTextString;
private AttributedCharacterIterator composedText;
private TextHitInfo caret;
final static private Attribute[] IM_ATTRIBUTES = { TextAttribute.INPUT_METHOD_HIGHLIGHT };
final static private AttributedCharacterIterator EMPTY_TEXT = (new AttributedString(
"")).getIterator();
final static private Font fpsFont = GraphicsUtils.getFont("Dialog", 0, 20);
final static private int fpsX = 5;
final static private int fpsY = 20;
private transient boolean running = true, showLogo = true;
private transient int shake_tmp, num_tmp;
private transient long maxFrames, before, curTime, startTime, offsetTime,
curFPS, calcInterval;
private transient double frameCount;
private Dimension dimension;
private IHandler handler;
private LGraphics gl;
private IScreen screen;
private BufferedImage awtImage;
private Thread mainLoop;
private GameContext context;
private EmulatorListener emulatorListener;
private EmulatorButtons emulatorButtons;
public Java2DView(IHandler handler) {
format(handler);
}
/**
* GameView
*
* @param handler
*/
public void format(IHandler handler) {
this.handler = handler;
this.context = GameManager.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);
this.addInputMethodListener(this);
}
/**
* GameView
*
* @return
*/
private long innerClock() {
long now = System.currentTimeMillis();
long ret = now - before;
before = now;
return ret;
}
/**
* Graphics
*/
public void createScreen() {
int pixelSize = getWidth() * getHeight();
int[] pixels = new int[pixelSize];
this.awtImage = GraphicsUtils.newAwtRGBImage(pixels, getWidth(),
getHeight(), pixelSize);
this.gl = new LGraphicsJava2D(awtImage);
}
/**
*
*
*/
public void destroy() {
synchronized (this) {
handler.destroy();
GameManager.getInstance().unregisterApp(this);
context = null;
if (gl != null) {
gl.dispose();
gl = null;
}
LSystem.destroy();
LSystem.gc();
notifyAll();
}
}
/**
*
*
* @param emulatorListener
*/
public void setEmulatorListener(EmulatorListener emulator) {
this.emulatorListener = emulator;
if (emulatorListener != null) {
if (emulatorButtons == null) {
emulatorButtons = new EmulatorButtons(emulatorListener, handler
.getWidth(), handler.getHeight());
} else {
emulatorButtons.setEmulatorListener(emulator);
}
} else {
emulatorButtons = null;
}
}
/**
*
*
* @return
*/
public EmulatorListener getEmulatorListener() {
return emulatorListener;
}
/**
*
*
* @return
*/
public EmulatorButtons getEmulatorButtons() {
return emulatorButtons;
}
/**
*
*
* @return
*/
final public BufferedImage getAwtImage() {
return awtImage;
}
/**
*
*
* @param g
*/
private void clearDraw(LGraphics g) {
g.setColor(Color.BLACK);
g.fillRect(0, 0, this.getWidth(), this.getHeight());
}
/**
*
*
*/
public synchronized void update() {
if (running) {
Graphics screen = this.getGraphics();
if (screen != null) {
screen.drawImage(awtImage, 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 screen = this.getGraphics();
if (screen != null) {
if (emulatorButtons != null) {
gl.drawImage(img, x, y);
emulatorButtons.draw(gl);
screen.drawImage(awtImage, 0, 0, null);
} else {
screen.drawImage(img, x, y, null);
}
systemToolKit.sync();
}
}
}
/**
*
*/
public synchronized void update(BufferedImage img, int w, int h) {
if (running) {
Graphics screen = this.getGraphics();
if (screen != null) {
if (emulatorButtons != null) {
gl.drawImage(img, getWidth() / 2 - w / 2, getHeight() / 2
- h / 2);
emulatorButtons.draw(gl);
screen.drawImage(awtImage, 0, 0, null);
} else {
screen.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 screen = this.getGraphics();
if (screen != null) {
if (emulatorButtons != null) {
gl.drawImage(img, getWidth() / 2 - w / 2, getHeight() / 2
- h / 2, w, h);
emulatorButtons.draw(gl);
screen.drawImage(awtImage, 0, 0, null);
} else {
screen.drawImage(img, getWidth() / 2 - w / 2, getHeight()
/ 2 - h / 2, w, h, null);
}
systemToolKit.sync();
}
}
}
/**
*
*/
public synchronized void update(BufferedImage img) {
if (running) {
Graphics screen = this.getGraphics();
if (screen != null) {
if (emulatorButtons != null) {
gl.drawImage(img, 0, 0);
emulatorButtons.draw(gl);
screen.drawImage(awtImage, 0, 0, null);
} else {
screen.drawImage(img, 0, 0, null);
}
systemToolKit.sync();
}
}
}
/**
* GameView
*
*/
public void run() {
if (showLogo) {
showLogo();
}
final LTimerContext timerContext = new LTimerContext();
final SystemTimer timer = context.getTimer();
timerContext.setTimeMillis(startTime = timer.getTimeMillis());
boolean reapint;
do {
if (!start) {
Thread.yield();
continue;
}
reapint = LSystem.AUTO_REPAINT;
screen = handler.getScreen();
if (!screen.next()) {
if (reapint) {
this.update();
}
continue;
}
if (reapint) {
shake_tmp = screen.getShakeNumber();
if (shake_tmp > 0) {
gl.drawImage(screen.getBackground(), shake_tmp / 2
- LSystem.random.nextInt(shake_tmp), shake_tmp / 2
- LSystem.random.nextInt(shake_tmp));
} else if (shake_tmp == -1) {
gl.drawImage(screen.getBackground(), 0, 0);
}
}
curTime = timer.getTimeMillis();
timerContext.setTimeSinceLastUpdate(curTime
- timerContext.getTimeMillis());
timerContext.setSleepTimeMillis((offsetTime - timerContext
.getTimeSinceLastUpdate())
- timerContext.getOverSleepTimeMillis());
if (timerContext.getSleepTimeMillis() > 0) {
try {
Thread.sleep(timerContext.getSleepTimeMillis());
} catch (InterruptedException e) {
}
timerContext
.setOverSleepTimeMillis((timer.getTimeMillis() - curTime)
- timerContext.getSleepTimeMillis());
} else {
timerContext.setOverSleepTimeMillis(0L);
}
timerContext.setTimeMillis(timer.getTimeMillis());
screen.callEvents();
screen.runTimer(timerContext);
if (reapint) {
screen.createUI(gl);
if (isFPS) {
tickFrames();
gl.setFont(fpsFont);
gl.setColor(Color.white);
gl.setAntialias(true);
gl.drawString("FPS:" + curFPS, fpsX, fpsY);
}
if (emulatorButtons != null) {
emulatorButtons.draw(gl);
}
this.update();
}
if (isFocusOwner()) {
Thread.yield();
continue;
}
GraphicsUtils.wait(30);
LSystem.gc(1000, 1);
} while (running);
this.destroy();
}
/**
* FPS
*
*/
private void tickFrames() {
frameCount++;
calcInterval += offsetTime;
if (calcInterval >= MAX_INTERVAL) {
long timeNow = System.currentTimeMillis();
long realElapsedTime = timeNow - startTime;
curFPS = (long) ((frameCount / realElapsedTime) * MAX_INTERVAL);
frameCount = 0L;
calcInterval = 0L;
startTime = timeNow;
}
}
/**
* Logo
*
*/
public void showLogo() {
try {
Image logo = null;
long elapsedTime;
int cx = 0, cy = 0;
double delay;
try {
logo = GraphicsUtils.loadImage("system/image/logo.png");
cx = this.getWidth() / 2 - logo.getWidth(null) / 2;
cy = this.getHeight() / 2 - logo.getHeight(null) / 2;
} catch (Exception e) {
}
float alpha = 0.0f;
boolean firstTime = true;
elapsedTime = innerClock();
while (alpha < 1.0f) {
clearDraw(gl);
Composite old = gl.getComposite();
gl.setComposite(AlphaComposite.getInstance(
AlphaComposite.SRC_OVER, alpha));
gl.drawImage(logo, cx, cy);
gl.setComposite(old);
if (firstTime) {
firstTime = false;
}
elapsedTime = innerClock();
delay = 0.00065 * elapsedTime;
if (delay > 0.22) {
delay = 0.22 + (delay / 6);
}
alpha += delay;
update();
}
while (num_tmp < 3000) {
num_tmp += innerClock();
update();
}
alpha = 1.0f;
while (alpha > 0.0f) {
clearDraw(gl);
Composite old = gl.getComposite();
gl.setComposite(AlphaComposite.getInstance(
AlphaComposite.SRC_OVER, alpha));
gl.drawImage(logo, cx, cy);
gl.setComposite(old);
elapsedTime = innerClock();
delay = 0.00055 * elapsedTime;
if (delay > 0.15) {
delay = 0.15 + ((delay - 0.04) / 2);
}
alpha -= delay;
update();
}
gl.restore();
showLogo = false;
} catch (Throwable e) {
}
}
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 + 1);
} catch (SecurityException ex) {
}
context.setAnimationThread(mainLoop);
mainLoop.start();
}
public void mainStop() {
this.mainLoop = null;
}
public void startPaint() {
this.start = true;
}
public void endPaint() {
this.start = 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 isShowLogo() {
return showLogo;
}
public void setShowLogo(boolean showLogo) {
this.showLogo = showLogo;
}
public boolean isRunning() {
return running;
}
public void setRunning(boolean running) {
this.running = running;
}
/**
*
*/
public InputMethodRequests getInputMethodRequests() {
return this;
}
/**
*
*/
public AttributedCharacterIterator getDisplayText() {
if (composedText == null) {
return super.getDisplayText();
} else {
return EMPTY_TEXT;
}
}
/**
*
*/
public TextHitInfo getCaret() {
if (composedText == null) {
return super.getCaret();
} else if (caret == null) {
return null;
} else {
return caret.getOffsetHit(getCommittedTextLength());
}
}
/**
*
*/
public void inputMethodTextChanged(InputMethodEvent e) {
int committedCharacterCount = e.getCommittedCharacterCount();
AttributedCharacterIterator text = e.getText();
composedText = null;
char c;
if (text != null) {
int toCopy = committedCharacterCount;
c = text.first();
while (toCopy-- > 0) {
insertCharacter(c);
c = text.next();
}
handler.changeText(getCommittedString());
if (text.getEndIndex()
- (text.getBeginIndex() + committedCharacterCount) > 0) {
composedTextString = new AttributedString(text, text
.getBeginIndex()
+ committedCharacterCount, text.getEndIndex(),
IM_ATTRIBUTES);
composedTextString.addAttribute(TextAttribute.FONT, getFont());
composedText = composedTextString.getIterator();
}
}
e.consume();
invalidateTextLayout();
caret = e.getCaret();
clear();
}
/**
*
*/
public void caretPositionChanged(InputMethodEvent e) {
caret = e.getCaret();
e.consume();
}
/**
*
*/
public Rectangle getTextLocation(TextHitInfo offset) {
Rectangle rectangle;
if (offset == null) {
rectangle = getCaretRectangle();
} else {
TextHitInfo globalOffset = offset
.getOffsetHit(getCommittedTextLength());
rectangle = getCaretRectangle(globalOffset);
}
Point location = getLocationOnScreen();
rectangle.translate(location.x, location.y);
return rectangle;
}
/**
* x,y
*/
public TextHitInfo getLocationOffset(int x, int y) {
Point location = getLocationOnScreen();
Point textOrigin = getTextOrigin();
x -= location.x + textOrigin.x;
y -= location.y + textOrigin.y;
TextLayout textLayout = getTextLayout();
if (textLayout != null && textLayout.getBounds().contains(x, y)) {
return textLayout.hitTestChar(x, y).getOffsetHit(
-getCommittedTextLength());
} else {
return null;
}
}
public int getInsertPositionOffset() {
return getCommittedTextLength();
}
public AttributedCharacterIterator getCommittedText(int beginIndex,
int endIndex, Attribute[] attributes) {
return getCommittedText(beginIndex, endIndex);
}
public AttributedCharacterIterator cancelLatestCommittedText(
Attribute[] attributes) {
return null;
}
public AttributedCharacterIterator getSelectedText(Attribute[] attributes) {
return EMPTY_TEXT;
}
public IHandler getHandler() {
return handler;
}
}
|