ce Canvas étendu propose l'implémentation du rendu graphique 2D pour un jeu animé avec option plein écran en rendu passif ou actif (a.k.a "Swing passive or active Rendering"). Il utilise les librairies Java Advanced Imaging pour accélérer le rendu "off" et "on-screen". Toute plateforme Java devrait être supportée, pour autant que les librairies soient disponibles.
Les classes importées du package installer.* et sf3.* sont disponibles en fichier zip à compiler.
Note: Le support d'accélération graphique d'OpenGL s'active avec Java2D AU LANCEMENT DE LA JVM par les options (respecter la casse svp !) :
-J-Dsun.java2d.opengl=True -J-Dsun.java2d.translaccel=true
:::... :.... ::::: ;;;::: b23:production 2007 GNU/GPL
(ajout: sept 2007 - les deux Timer buffer et render sont maintenant mieux géré grâce à la mise en place d'un moniteur de synchronisation sur l'offscreen-sprite et de l'amélioration du "coalesceing" (regroupement des Threads en un seul). Le full-screen est possible en affichage actif uniquement. )
Source / Exemple :
/*
*
- Created on 28 avril 2007, 02:13
*
- To change this template, choose Tools | Template Manager
- and open the template in the editor.
- /
package sf3;
import installer.UIMessage;
import java.awt.AWTException;
import java.awt.BufferCapabilities;
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.DisplayMode;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.Insets;
import java.awt.KeyEventDispatcher;
import java.awt.KeyEventPostProcessor;
import java.awt.KeyboardFocusManager;
import java.awt.MediaTracker;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferStrategy;
import java.net.URISyntaxException;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
import java.util.Vector;
import javax.media.jai.GraphicsJAI;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import sf3.system.CoalescedThreadsMonitor;
import sf3.system.Console;
import sf3.system.Resource;
import sf3.system.SpritesCacheManager;
import sf3.system.Threaded;
/**
- This class extends a CanvasJAI to bring the faster rendering to Sprites as a lightweight component. It refreshes itself at the current refresh rate taken from the running DisplayMode.
- It has an internal double-buffer and can show the console log beyond screen. Type "f4" function key to switch to fullscreen mode.
- NOTICE: when it is taken off from the fullscreen-mode RenderingSceneListener had to be initaliazed to interceipt the reset message and reinit the scene, otherwise you won't get it bakc on the frame.
- @see RenderingSceneListener#reset()
- @author www.b23prodtm.com
- /
public class RenderingScene extends Canvas implements KeyEventPostProcessor, Runnable, Resource, Threaded {
/** the console switch
boolean consoleEnabled = false;
/** the buffer */
SortedMap<String, Sprite> buffer;
/** the back-buffer */
SpritesCacheManager<String, Sprite> backBuffer;
/***/
MediaTracker mt = new MediaTracker(this);
/** the fullscreen-mode switch*/
boolean fullscreen = false;
/** the default size of this scene*/
static Dimension defaultSize = new Dimension(150, 150);
/** default refresh rate [Hz]
int defaultRefreshRate = 60;
/** the screen refresh Timer */
javax.swing.Timer refresh;
/** the offscreen refresh Timer */
javax.swing.Timer refresh_off;
/** the graphics device*/
static GraphicsDevice device;
/** refresh rate in Hz given by the current display Mode*/
int refreshRate;
/** the containing frame for the scene */
JFrame frame;
/** the current display mode*/
private DisplayMode displayMode;
/** the initial display mode*/
private DisplayMode initialDisplayMode;
/** windowed mode */
static final int WINDOWED_MODE = 0;
/** fullscreen-mode*/
static final int FULLSCREEN_MODE = 1;
/** offscreen mode */
static final int OFFSCREEN_MODE = 2;
/** the actions before drawing */
private Set<Action> before_action_list = Collections.synchronizedSet(new HashSet<Action>());
/** the actions after drawn*/
private Set<Action> after_action_list = Collections.synchronizedSet(new HashSet<Action>());
/** offscreen action list*/
final Set<Action> offscreen_action_list = Collections.synchronizedSet(new HashSet<Action>());
/** this rendering scene listeners*/
private Set<RenderingSceneListener> listeners = Collections.synchronizedSet(new HashSet<RenderingSceneListener>());
/** current state of the rendering scene
- @see #STOPPED
- @see #RUNNING
- @see #SUSPENDED
- @default STOPPED*/
private int state = STOPPED;
/** running state*/
public static final int RUNNING = 0;
/** suspended state*/
public static final int SUSPENDED = 1;
/** stopped state*/
public static final int STOPPED = 2;
/***/
public static boolean _innerRsrcMode = true;
/***/
private transient boolean rendering = false;
/***/
private transient CoalescedThreadsMonitor vSynch;
/***/
private transient boolean buffering = false;
/***/
private transient CoalescedThreadsMonitor bufferSynch;
/***/
public static boolean _multiThreading = false;
/** set the frame where to add the scene canvas and to use as owner (MUST set to some existing and visible frame)
- @param frame the frame that contains this RenderingScene Canvas*/
/***/
public void setToDevice(JFrame frame) {
this.frame = frame;
}
/***/
public void addNotify() {
super.addNotify();
BufferCapabilities c = getGraphicsConfiguration().getBufferCapabilities();
try {
if (c.isMultiBufferAvailable()) {
createBufferStrategy(3, c);
} else if (c.isPageFlipping()) {
createBufferStrategy(2, c);
} else {
createBufferStrategy(1, c);
}
} catch (AWTException ex) {
ex.printStackTrace();
try {
createBufferStrategy(1, c);
} catch (AWTException ex2) {
ex.printStackTrace();
activeRendering = false;
}
}
}
/** contructs a new RenderingScene instance that can be added to a frame with a default size
- @see #defaultSize
- NOTICE: don't forget to call getToDevice(Frame), and to launch the timer to with resume()
- @see #resume()
- @see #getToDevice(Frame)*/
public RenderingScene() {
this(defaultSize);
}
/** Creates a new instance of RenderingScene *
- @param size the size of this scene*/
public RenderingScene(Dimension size) {
super((device = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice()).getDefaultConfiguration());
backBuffer = new SpritesCacheManager<String, Sprite>(5);
backBuffer.setSwapDiskEnabled(false);
buffer = Collections.synchronizedSortedMap(backBuffer);
addKeyboardEvents();
displayMode = initialDisplayMode = device.getDisplayMode();
refreshRate = device.getDisplayMode().getRefreshRate();
if (refreshRate <= 0) {
refreshRate = defaultRefreshRate;
}
defaultSize = size;
setSize(size);
setPreferredSize(size);
setBackground(Color.BLACK);
setForeground(Color.GREEN);
addActionBefore(getRefreshAction(-1));
addActionAfter(getRefreshAction(WINDOWED_MODE));
setVisible(true);
setThreadGroup(new CoalescedThreadsMonitor("RenderingScene-TG"));
loadResource();
}
/** notifies the RenderingListener for a reset (usually after coming off fullscreen-mode). A new instance of RenderingScene must be reinitialized again.*/
private void notifyReset() {
synchronized (listeners) {
for (Iterator<RenderingSceneListener> i = listeners.iterator(); i.hasNext();) {
i.next().reset();
}
}
System.out.println("-RenderingScene reset-");
}
/** Synchronizes the display device. (on Linux, this fixes event queue problems)*/
private void sync() {
getToolkit().sync();
}
/***/
Thread offscreen = null;
/** returns the refreshing task for the offscreen
- @return offscreen refreshing task*/
protected ActionListener getOffscreenTask() {
return new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (offscreen instanceof Thread) {
if (offscreen.isAlive()) {
return;
}
}
Thread t = offscreen = new Thread(bufferSynch, RenderingScene.this, "T-offscreen-refresh");
t.setDaemon(false);
t.setPriority(Thread.MAX_PRIORITY);
t.start();
}
};
}
/***/
public void run() {
int pty = Thread.currentThread().getPriority();
Thread.currentThread().setPriority(bufferSynch.getMaxPriority());
if (vSynch == null) {
return;
}
backBuffer.ensureListCapacity(backBuffer.getInitialListCapacity());
boolean interrupt_ = false;
final CoalescedThreadsMonitor monitor0 = vSynch;
synchronized (monitor0.getMonitor(true)) {
monitor0.notifyOnMonitor();
if (rendering) {
System.err.println("RenderingScene offscreen task is waitin' for rendering...");
}
while (rendering) {
System.err.print(".");
try {
monitor0.waitOnMonitor();
} catch (InterruptedException e) {
e.printStackTrace();
Thread.currentThread().interrupt();
}
}
try {
System.err.print("OK\n\r");
buffering = true;
final CoalescedThreadsMonitor monitor = offscreenSynch;
synchronized(monitor.getMonitor(false)) {
monitor.notifyOnMonitor();
Graphics offG = getOffscreen().getImage((Component) this).getGraphics();
offG.setClip(0, 0, getWidth(), getHeight());
GraphicsJAI g = (GraphicsJAI) Sprite.createGraphicsJAI(offG, RenderingScene.this);
System.out.println("////////////////////////////////////////////offscreen initied - " + System.currentTimeMillis());
g.clearRect(0, 0, getWidth(), getHeight());
g.setBackground(Color.BLACK);
g.setColor(Color.YELLOW);
doOffscreenTasks(new ActionEvent(this, hashCode(), "refreshing-offscreen"));
if (consoleEnabled) {
GUIConsoleOutput console = getGCO();
if (console != null) {
console.setAlpha(0.5f);
System.out.println("CONSOLE GUI ");
console.validate();
//console.pack();
console.draw(this, g);
}
}
String logo_file = "intel_logo.png";
Dimension logo_size = new Dimension(64, 26);
drawLogo(g, logo_file, logo_size, GUIConsoleOutput.RIGHT, GUIConsoleOutput.BOTTOM);
String logo_java_file = "logo_java_grey.png";
Dimension logo_java_size = new Dimension(53, 53);
drawLogo(g, logo_java_file, logo_java_size, GUIConsoleOutput.LEFT, GUIConsoleOutput.BOTTOM);
}
} catch (InterruptedException e) {
e.printStackTrace();
interrupt_ = true;
} finally {
buffering = false;
System.out.println("//////////////////////////////////////////offscreen flushed - " + System.currentTimeMillis());
}
}
final CoalescedThreadsMonitor monitor1 = bufferSynch;
synchronized (monitor1.getMonitor(false)) {
monitor1.notifyAllOnMonitor();
}
backBuffer.ensureListCapacity(backBuffer.getInitialListCapacity());
if (interrupt_) {
Thread.currentThread().interrupt();
}
Thread.currentThread().setPriority(pty);
}
/***/
public Sprite getLogo(String logo, Dimension size) {
Sprite sp;
if (!buffer.containsKey(logo)) {
try {
buffer.put(logo, sp = new Sprite(logo, _innerRsrcMode, "image/png", size, true));
/*if (sp.getThreadGroup() != getThreadGroup()) {
sp.setThreadGroup(getThreadGroup());
}*/
sp.setMt(mt);
} catch (URISyntaxException ex) {
ex.printStackTrace();
}
}
sp = buffer.get(logo);
sp.validate();
return sp;
}
/***/
Double[] scale = new Double[]{1.0, 1.0};
double scale_step = 0.1;
/***/
public void drawLogo(Graphics2D g2, String logo, Dimension size, int hpos, int vpos) throws InterruptedException {
Sprite logo_sp = getLogo(logo, size);
GraphicsJAI g = Sprite.createGraphicsJAI(g2, this);
AffineTransform tx = AffineTransform.getScaleInstance(1, 1);
if (scale[0] <= -1 || scale[0] >= 1) {
scale_step *= -1;
}
scale[0] += scale_step;
if (scale[0] == 0.0) {
return;
}
tx.scale(scale[0], scale[1]);
tx.translate((int) (-0.5f * (float)logo_sp.getWidth() * (float)tx.getScaleX() - (float)((scale[0] <= 0)?logo_sp.getWidth():0)), 0);
Point translate = new Point(0, 0);
Insets insets = new Insets(10, 10, 10, 10);
switch (hpos) {
case GUIConsoleOutput.LEFT:
translate.x = insets.left;
break;
case GUIConsoleOutput.CENTER:
translate.x = (int) ((float)getWidth() / 2.0f - (float)logo_sp.getWidth() / 2.0f);
break;
case GUIConsoleOutput.RIGHT:
translate.x = -insets.right + (int) (getWidth() - logo_sp.getWidth());
break;
default:
break;
}
switch (vpos) {
case GUIConsoleOutput.TOP:
translate.y = insets.top;
break;
case GUIConsoleOutput.CENTER:
translate.y = (int) ((float)getHeight() / 2.0f - (float)logo_sp.getHeight() / 2.0f);
break;
case GUIConsoleOutput.BOTTOM:
translate.y = -insets.bottom + (int) (getHeight() - logo_sp.getHeight());
break;
default:
break;
}
g.translate(translate.x, translate.y);
logo_sp.validate();//logo_sp.pack();
logo_sp.draw(this, g, tx);
g.translate(-translate.x, -translate.y);
}
/***/
Thread screen = null;
/** returns screen refreshing task
- @return screen refreshing task*/
protected ActionListener getScreenTask() {
return new ActionListener() {
public void actionPerformed(ActionEvent pe) {
final ActionEvent e = pe;
if (screen instanceof Thread) {
if (screen.isAlive()) {
return;
}
}
Thread t = screen = new Thread(vSynch, new Runnable() {
public void run() {
if (!isDisplayable()) {
return;
}
if (bufferSynch == null) {
return;
}
boolean interrupt_ = false;
setIgnoreRepaint(activeRendering);
if (activeRendering) {
final CoalescedThreadsMonitor monitor0 = bufferSynch;
synchronized (monitor0.getMonitor(true)) {
monitor0.notifyOnMonitor();
if (buffering) {
System.err.println("RenderingScene screen task is waitin' for buffering...");
}
while (buffering) {
System.err.print(".");
try {
monitor0.waitOnMonitor();
} catch (InterruptedException ex) {
ex.printStackTrace();
Thread.currentThread().interrupt();
}
}
try {
rendering = true;
doBeforeScreenTasks(e);
System.out.println(((activeRendering) ? "-HARD RENDERING-" : "-SOFT RENDERING-") + "\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\screen initied - " + System.currentTimeMillis());
BufferStrategy strategy = RenderingScene.this.getBufferStrategy();
Graphics g = null;
do {
do {
g = strategy.getDrawGraphics();
if (g != null) {
Rectangle box = new Rectangle(0, 0, getWidth(), getWidth());
g.setClip(box);
g.clearRect(box.x, box.y, box.width, box.height);
draw(g, RenderingScene.this);
g.dispose();
}
} while (strategy.contentsRestored());
if (isDisplayable()) {
strategy.show();
}
} while (strategy.contentsLost());
doAfterScreenTasks(e);
} catch (InterruptedException e) {
e.printStackTrace();
interrupt_ = true;
} finally {
rendering = false;
}
}
final CoalescedThreadsMonitor monitor1 = vSynch;
synchronized (monitor1.getMonitor(false)) {
monitor1.notifyAllOnMonitor();
}
if (interrupt_) {
Thread.currentThread().interrupt();
}
} else {
repaint();
}
}
}, "T-screen-refresh");
t.setPriority(Thread.MAX_PRIORITY);
t.setDaemon(false);
t.start();
}
};
}
/** returns the refreshing action associated to the given mode
- @param mode the mode to get the action from
- @see #FULLSCREEN_MODE
- @see #WINDOWED_MODE
- @return the action object */
private Action getRefreshAction(int mode) {
switch (mode) {
case WINDOWED_MODE:
return new AbstractAction() {
public void actionPerformed(ActionEvent e) {
int pty = Thread.currentThread().getPriority();
Thread.currentThread().setPriority(Thread.MAX_PRIORITY);
Thread.currentThread().setPriority(pty);
}
};
case FULLSCREEN_MODE:
return new AbstractAction() {
public void actionPerformed(ActionEvent e) {
int pty = Thread.currentThread().getPriority();
Thread.currentThread().setPriority(Thread.MAX_PRIORITY);
sync();
Thread.currentThread().setPriority(pty);
}
};
default:
return new AbstractAction() {
public void actionPerformed(ActionEvent e) {
}
};
}
}
/***/
private void doBeforeScreenTasks(ActionEvent pe) throws InterruptedException {
final ActionEvent e = pe;
synchronized (before_action_list) {
Vector<Thread> vT = new Vector<Thread>();
for (Iterator<Action> i = before_action_list.iterator(); i.hasNext();) {
final Action a = i.next();
if (a instanceof Action) {
Thread t = new Thread(new Runnable() {
public void run() {
a.actionPerformed(e);
}
}, "T-Screen-Task");
t.setPriority(Thread.MAX_PRIORITY);
t.start();
if (!_multiThreading) {
t.join();
} else {
vT.add(t);
}
}
}
if (_multiThreading) {
for (Iterator<Thread> i = vT.iterator(); i.hasNext();) {
i.next().join();
}
}
}
}
/***/
private void doAfterScreenTasks(ActionEvent pe) throws InterruptedException {
final ActionEvent e = pe;
synchronized (after_action_list) {
Vector<Thread> vT = new Vector<Thread>();
for (Iterator<Action> i = after_action_list.iterator(); i.hasNext();) {
final Action a = i.next();
if (a instanceof Action) {
Thread t = new Thread(new Runnable() {
public void run() {
a.actionPerformed(e);
}
}, "T-Screen-Task");
t.setPriority(Thread.MAX_PRIORITY);
t.start();
if (!_multiThreading) {
t.join();
} else {
vT.add(t);
}
}
}
if (_multiThreading) {
for (Iterator<Thread> i = vT.iterator(); i.hasNext();) {
i.next().join();
}
}
}
}
/***/
private void doOffscreenTasks(ActionEvent pe) throws InterruptedException {
final ActionEvent e = pe;
synchronized (offscreen_action_list) {
Vector<Thread> vT = new Vector<Thread>();
for (Iterator<Action> i = offscreen_action_list.iterator(); i.hasNext();) {
final Action a = i.next();
if (a instanceof Action) {
Thread t = new Thread(bufferSynch, new Runnable() {
public void run() {
a.actionPerformed(e);
}
}, "T-Offscreen-Task");
t.setPriority(Thread.MAX_PRIORITY);
t.start();
if (!_multiThreading) {
t.join();
} else {
vT.add(t);
}
}
}
if (_multiThreading) {
for (Iterator<Thread> i = vT.iterator(); i.hasNext();) {
i.next().join();
}
}
}
}
/** adds a new listener to the RenderingSceneListners
- @param l the listener to add
- /
public void addListener(RenderingSceneListener l) {
listeners.add(l);
}
/** removes the given listener from the RenderingSceneListeners
- @param l the listener to remove*/
public void removeListener(RenderingSceneListener l) {
listeners.remove(l);
}
/** adds a new double-buffered drawing
- @param a the action to add to offscreen rendering, which assumes that the action solely uses the offscreen to draw on the scene
- @see #getOffscreen()*/
public void addActionOffscreen(Action a) {
offscreen_action_list.add(a);
}
/** puts a new action before the screen-refresh-drawing action tick
- @param a the action to add*/
public void addActionBefore(Action a) {
before_action_list.add(a);
}
/** puts a new action after the screen-refresh-drawing action tick
- @param a the action to add*/
public void addActionAfter(Action a) {
after_action_list.add(a);
}
/** removes an action in the offscreen-rendering action list
- @param a the action to remove from offscreen-rendering list
- @return whether it has found the action or not*/
public boolean removeActionOffscreen(Action a) {
return offscreen_action_list.remove(a);
}
/** removes an action set before the screen-refresh-drawing aciton tick
- @param a the action to remove
- @return whether it has found the action or not */
public boolean removeActionBefore(Action a) {
return before_action_list.remove(a);
}
/** removes an action set before the screen-refresh-drawing action tick
- @param a the action to remove
- @return whether it has found the action or not */
public boolean removeActionAfter(Action a) {
return after_action_list.remove(a);
}
/** returns the current state of the rendering scene
- @return the current state
- @see #STOPPED
- @see #RUNNING
- @see #SUSPENDED*/
public int getState() {
return state;
}
/** suspends the rendering timer */
public void suspend() {
if (state == RUNNING) {
stop();
System.out.println(" rendering's suspended");
state = SUSPENDED;
}
}
/** resumes the rendering timer*/
public void resume() {
if (state == RUNNING) {
if (vSynch instanceof CoalescedThreadsMonitor) {
if (vSynch.isDestroyed()) {
System.err.println(vSynch.getName() + " TG is destroyed!");
}
}
if (bufferSynch instanceof CoalescedThreadsMonitor) {
if (bufferSynch.isDestroyed()) {
System.err.println(bufferSynch.getName() + " TG is destroyed!");
}
}
refresh_off.setInitialDelay((int) (1000f/(float)refreshRate));
refresh.setInitialDelay((int) (1000f/(float)refreshRate));
removeKeyboardEvents();
addKeyboardEvents();
refresh_off.restart();
refresh.restart();
System.out.println(" rendering's restarted");
} else if (state == STOPPED || state == SUSPENDED) {
start();
}
state = RUNNING;
}
/** starts the rendering timer */
private void start() {
assert frame != null : "you must set a device frame to this canvas before to use it!";
if (vSynch instanceof CoalescedThreadsMonitor) {
if (vSynch.isDestroyed()) {
System.err.println(vSynch.getName() + " TG is destroyed!");
}
}
if (bufferSynch instanceof CoalescedThreadsMonitor) {
if (bufferSynch.isDestroyed()) {
System.err.println(bufferSynch.getName() + " TG is destroyed!");
}
}
removeKeyboardEvents();
addKeyboardEvents();
refresh_off = new javax.swing.Timer((int) (1000.0f / (float)refreshRate), getOffscreenTask());
backBuffer.buffer(refresh_off);
refresh = new javax.swing.Timer((int) (1000.0f / (float)refreshRate), getScreenTask());
backBuffer.buffer(refresh);
refresh_off.start();
refresh.start();
System.out.println(" rendering's started");
state = RUNNING;
}
/** stops the rendering timer */
private void stop() {
refresh_off.stop();
refresh.stop();
bufferSynch.cancelAll(true);
vSynch.cancelAll(true);
System.out.println(" rendering's stopped");
state = STOPPED;
}
/** overriden to stop the rendering timer before loosing the scene */
protected void finalize() throws Throwable {
removeKeyboardEvents();
stop();
clearResource();
super.finalize();
}
/** sets refreshRate to given Hz, limited to current display resfresh rate
- @param hz the new refresh rate to be used by the offscreen rendering timer*/
public void setRefreshRate(int hz) {
suspend();
refreshRate = Math.max(1, Math.min(displayMode.getRefreshRate(), hz));
resume();
}
/** returns the current refresh rate
- @return the current resfresh rate [Hz]*/
public int getRefreshRate() {
return refreshRate;
}
/** modifies the offscreen sprite in buffer with a new one
- @param offscreen the new Sprite to use as offscreen*/
public void setOffscreen(Sprite offscreen) {
buffer.put("offscreen", offscreen);
}
/***/
public String getFPS() {
return getOffscreen().getFPS();
}
/** returns the current offscreen sprite
- @return the current offscreen*/
public Sprite getOffscreen() {
Sprite sp;
if (!buffer.containsKey("offscreen")) {
buffer.put("offscreen", sp = (!getGraphicsConfiguration().getBufferCapabilities().getBackBufferCapabilities().isTrueVolatile()) ? new Sprite(Sprite.createBufferedImage(new Dimension(getWidth(), getHeight()), Sprite.DEFAULT_TYPE), "image/x-png", new Dimension(getWidth(), getHeight())) : new Sprite(Sprite.createVolatileImage(new Dimension(getWidth(), getHeight())), "image/x-png", new Dimension(getWidth(), getHeight())));
/*if (sp.getThreadGroup() != getThreadGroup()) {
sp.setThreadGroup(getThreadGroup());
}*/
sp.setMt(mt);
}
sp = buffer.get("offscreen");
sp.setPreferredSize(new Dimension(getWidth(), getHeight()));
sp.setSize(getWidth(), getHeight());
sp.validate();
return sp;
}
/***/
private transient Thread T_switchFullScreen;
/** swichtes to fullscreen-mode */
private void switchFullScreen(boolean init) {
if (!activeRendering) {
new UIMessage(true, "full-screen not allowed w/ soft rendering, switch to hardware accelerated [F12] !", frame, UIMessage.ERROR_TYPE);
return;
}
if (fullscreen) {
try {
if (device.isFullScreenSupported()) {
device.setDisplayMode(initialDisplayMode);
}
} catch (IllegalArgumentException ex) {
ex.printStackTrace();
String msg = "";
for (StackTraceElement se : ex.getStackTrace()) {
msg += se.toString() + "\n";
}
new UIMessage(false, ex.getMessage() + "\r\n" + msg, frame, UIMessage.ERROR_TYPE);
} finally {
stop();
device.setFullScreenWindow(null);
frame.setResizable(true);
setPreferredSize(defaultSize);
frame.setSize(defaultSize);
frame.pack();
removeActionAfter(getRefreshAction(FULLSCREEN_MODE));
addActionAfter(getRefreshAction(WINDOWED_MODE));
fullscreen = false;
start();
}
} else {
stop();
if (init) {
DisplayModeWrapper[] dms = new DisplayModeWrapper[device.getDisplayModes().length];
int i = 0;
for (DisplayMode dm : device.getDisplayModes()) {
dms[i++] = new DisplayModeWrapper(dm);
}
displayMode = ((DisplayModeWrapper) JOptionPane.showInputDialog(this, "What display mode should I use?", "Fullscreen mode", JOptionPane.QUESTION_MESSAGE, null, dms, new DisplayModeWrapper(displayMode))).getDM();
}
removeActionAfter(getRefreshAction(WINDOWED_MODE));
addActionAfter(getRefreshAction(FULLSCREEN_MODE));
if (frame instanceof JFrame) {
if (!frame.isDisplayable()) {
frame = new JFrame();
}
} else {
frame = new JFrame();
}
if (!frame.isDisplayable()) {
frame.setUndecorated(true);
}
fullscreen = true;
defaultSize = new Dimension(getWidth(), getHeight());
frame.getContentPane().removeAll();
frame.getContentPane().add(this);
device.setFullScreenWindow(frame);
try {
device.setDisplayMode(displayMode);
} catch (IllegalArgumentException ex) {
ex.printStackTrace();
new UIMessage(true, ex, null);
} finally {
// fix for mac os x
setPreferredSize(new Dimension(displayMode.getWidth(), displayMode.getHeight()));
frame.setSize(displayMode.getWidth(), displayMode.getHeight());
frame.setResizable(false);
frame.pack();
start();
if (init) {
if (T_switchFullScreen instanceof Thread) {
if (T_switchFullScreen.isAlive()) {
return;
}
}
Thread t = T_switchFullScreen = new Thread(new Runnable() {
public void run() {
JFrame wait = UIMessage.displayWaiting("switching to full-screen " + new DisplayModeWrapper(displayMode).toString(), RenderingScene.this);
try {
Thread.currentThread().sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
switchFullScreen(false);
try {
Thread.currentThread().sleep(3000);
} catch (InterruptedException ex) {
ex.printStackTrace();
} finally {
switchFullScreen(false);
wait.dispose();
}
}
}
}, "T-switchFullScreen-initloop");
t.start();
}
}
}
}
/** sets the size of the rendering scene to the given size
- @param size the size to resize to
- @see #setSize(int, int)*/
public void setSize(Dimension size) {
setSize(size.width, size.height);
}
/** sets the size of the rendering scene to the given values
- @param width new width
- @param height new height
- @see #setSize(Dimension)*/
public void setSize(int width, int height) {
super.setSize(width, height);
//getOffscreen().setSize(width, height);
}
/** sets the preferred size of the rendering scene to given size
- @param size the new preferred size
- /
public void setPreferredSize(Dimension size) {
super.setPreferredSize(size);
//getOffscreen().setPreferredSize(size);
defaultSize = size;
}
/***/
private boolean ticker = false;
/***/
private boolean keyPressed = false;
/***/
private boolean keyEvent = false;
/***/
private CoalescedThreadsMonitor offscreenSynch;
/** draws the offscreen to the graphics on given component
- @param g the Graphics instance
- @param c the component to draw on (Graphics g should be those from that component)*/
protected void draw(Graphics g, Component c) throws InterruptedException {
int pty = Thread.currentThread().getPriority();
Thread.currentThread().setPriority(vSynch.getMaxPriority());
backBuffer.ensureListCapacity(backBuffer.getInitialListCapacity());
GraphicsJAI graphics = Sprite.createGraphicsJAI(g, c);
//graphics.setClip(0, 0, getWidth(), getHeight());
System.err.print("OK\n\r");
rendering = true;
final CoalescedThreadsMonitor monitor = offscreenSynch;
synchronized(monitor.getMonitor(false)) {
monitor.notifyOnMonitor();
Sprite off = getOffscreen();
off.validate();//off.pack();
off.draw(c, graphics);
Color clr = graphics.getColor();
graphics.setColor(Color.GREEN);
if (keyEvent) {
graphics.drawOval(10, 10, 30, 30);
if (keyPressed) {
graphics.fillOval(10, 10, 30, 30);
}
}
graphics.setColor(clr);
ticker = !ticker;
helpConsoleArgs.put("lastOutputPX", new Point(0, 0));
if (_paintCommandsEnabled) {
drawString(graphics, "[F1] this help", GUIConsoleOutput.CENTER, GUIConsoleOutput.TOP);
drawString(graphics, ((ticker) ? "-" : " ") + ((activeRendering) ? "HARD" : "SOFT") + ((ticker) ? "-" : " ") + " [F12] graphics accel. ", GUIConsoleOutput.RIGHT, GUIConsoleOutput.TOP);
drawString(graphics, "[F11] on/off, [F4] full-screen, [F9] multi-threading : " + ((!_multiThreading) ? "off" : "on"), GUIConsoleOutput.LEFT, GUIConsoleOutput.BOTTOM);
drawString(graphics, device.getDisplayMode().getWidth() + "x" + device.getDisplayMode().getHeight() + "@ " + refreshRate + " Hz " + device.getDisplayMode().getBitDepth() + " bits", GUIConsoleOutput.RIGHT, GUIConsoleOutput.BOTTOM);
drawString(graphics, "[PGUp/PGDown] refresh +/- (" + refreshRate + "Hz)", GUIConsoleOutput.LEFT, -1);
}
drawString(graphics, "FPS = " + String.valueOf(off.getFPS()), GUIConsoleOutput.LEFT, GUIConsoleOutput.TOP);
}
System.out.println("\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\screen flushed - " + System.currentTimeMillis());
Thread.currentThread().setPriority(pty);
backBuffer.ensureListCapacity(backBuffer.getInitialListCapacity());
}
/***/
Map<String, Object> helpConsoleArgs = new HashMap<String, Object>();
/** draw one string at desired position
- @param str string to draw
- @param int horizontal position
- @param int vertical position
- @param g2 the graphics instance to draw on
- @see GUIConsoleOutput#BOTTOM
- @see GUIConsoleOutput#TOP
- @see GUIConsoleOutput#RIGHT
- @see GUIConsoleOutput#LEFT*/
public void drawString(Graphics2D g2, String str, int hpos, int vpos) {
GraphicsJAI graphics = Sprite.createGraphicsJAI(g2, this);
Color c = graphics.getColor();
graphics.setColor(Color.GREEN);
/*Insets insets = new Insets(10, 10, 10, 10);
Point pos = new Point(insets.left, insets.top);
switch(hpos) {
case GUIConsoleOutput.RIGHT:
pos.x = getWidth() - toGraphicalMetrics(str, graphics).width - insets.right;
break;
case GUIConsoleOutput.LEFT:
pos.x = insets.left;
break;
default:
pos.x = (int)((float)getWidth() / 2.0f - (float)toGraphicalMetrics(str, graphics).width / 2.0f);
break;
}
switch(vpos) {
case GUIConsoleOutput.TOP:
pos.y = insets.top;
break;
case GUIConsoleOutput.BOTTOM:
pos.y = getHeight() - toGraphicalMetrics(str, graphics).height - insets.bottom;
break;
default:
pos.y = (int)((float)getHeight() / 2.0f - (float)toGraphicalMetrics(str, graphics).height / 2.0f);
break;
}*/
helpConsoleArgs.put("valign", vpos);
helpConsoleArgs.put("align", hpos);
helpConsoleArgs.put("outputRowPX_pad", 3);
helpConsoleArgs.put("outputColPX_pad", 10);
helpConsoleArgs.put("size", graphics.getClipBounds().getSize());
GUIConsoleOutput.drawNewLine(helpConsoleArgs, graphics, new StringBuffer(str));
//graphics.drawString(str, pos.x, pos.y);
graphics.setColor(c);
}
/***
public Graphics getGraphics() {
return super.getGraphics();
}
/** overriden to draw the contents
- @param g Graphics instance */
public void paint(Graphics g) {
try {
draw(g, this);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
/***/
Thread update = null;
/***/
public void update(Graphics pg) {
final Graphics g = pg;
if (update instanceof Thread) {
if (update.isAlive()) {
return;
}
}
Thread t = update = new Thread(vSynch, new Runnable() {
public void run() {
if (bufferSynch == null) {
return;
}
boolean interrupt_ = false;
final CoalescedThreadsMonitor monitor0 = bufferSynch;
synchronized (monitor0.getMonitor(true)) {
monitor0.notifyOnMonitor();
if (buffering) {
System.err.println("RenderingScene screen task is waitin' for buffering...");
}
while (buffering) {
System.err.print(".");
try {
monitor0.waitOnMonitor();
} catch (InterruptedException ex) {
ex.printStackTrace();
Thread.currentThread().interrupt();
}
}
rendering = true;
try {
doBeforeScreenTasks(new ActionEvent("T-before-screen-task", hashCode(), "do"));
Rectangle box = new Rectangle(0, 0, getWidth(), getWidth());
g.setClip(box);
g.clearRect(box.x, box.y, box.width, box.height);
paint(g);
g.dispose();
doAfterScreenTasks(new ActionEvent("T-after-screen-task", hashCode(), "do"));
} catch (InterruptedException e) {
e.printStackTrace();
interrupt_ = true;
} finally {
rendering = false;
}
}
final CoalescedThreadsMonitor monitor1 = vSynch;
synchronized (monitor1.getMonitor(false)) {
monitor1.notifyAllOnMonitor();
}
if (interrupt_) {
Thread.currentThread().interrupt();
}
}
});
t.setPriority(Thread.MAX_PRIORITY);
t.setDaemon(false);
t.start();
}
/***/
public boolean isOpaque() {
return true;
}
/** returns graphical metrics of the given string for the given graphics.
- @param str the string to get graphical metrics from
- @param g the graphics to get to font metrics from
- @return the dimension of the string as if it were drawn on the graphics instance */
public static Dimension toGraphicalMetrics(String str, Graphics g) {
return new Dimension(g.getFontMetrics().stringWidth(str), g.getFontMetrics().getHeight());
}
/** returns the default graphical metrics for one character on the given graphics
- @return the dimension of the character as if it were drawn on the graphics instance
- @param g hte graphics to get the font metrics from*/
public static Dimension toGraphicalMetrics(Graphics g) {
return new Dimension(g.getFontMetrics().getMaxAdvance(), g.getFontMetrics().getHeight());
}
/** returns the max characters that can be drawn each-nearby on the given graphics. graphics clip size is the available space.
- @param clipWidth available clip width on the graphics
- @param inset the insets you may want to apply
- @param g the graphics to take mesurement on */
public static int toMaxCharsCOLS(int clipWidth, int inset, Graphics g) {
return (int) Math.floor((float)(clipWidth - inset * 2) / (float)RenderingScene.toGraphicalMetrics(g).width);
}
/***/
public void setMt(MediaTracker mt) {
this.mt = mt;
}
/***/
public MediaTracker getMt() {
return mt;
}
/** returns the current GUICOnsoleOutput component
- @return the current console sprite component
- @see #getConsole()*/
private GUIConsoleOutput getGCO() {
GUIConsoleOutput sp;
if (!buffer.containsKey("GCO")) {
buffer.put("GCO", sp = new GUIConsoleOutput(isInnerResourceModeEnabled(), 50, new Dimension(getWidth(), getHeight()), consoleEnabled));
/*if (sp.getThreadGroup() != getThreadGroup()) {
sp.setThreadGroup(getThreadGroup());
}*/
sp.setMt(mt);
}
sp = (GUIConsoleOutput) buffer.get("GCO");
sp.setPreferredSize(new Dimension(getWidth(), getHeight()));
sp.setSize(new Dimension(getWidth(), getHeight()));
sp.setValign(GUIConsoleOutput.TOP);
sp.setAlign(GUIConsoleOutput.LEFT);
sp.validate();
return sp;
}
/** dis/enables the console
public void setConsoleEnabled(boolean b) {
//suspend();
getGCO().setEnabled(b);
consoleEnabled = b;
resume();
}
/** checks whether the console is painted or not
public boolean isConsoleEnabled() {
return consoleEnabled;
}
/** returns the current console Console instance
- @return current console instance
- @see #getGCO()*/
public Console getConsole() {
return getGCO().getConsole();
}
/** buffers the given Object, used when an object uses quite more than usual memory. Hence it can be cleared off faster the main-memory. */
public void buffer(Object sp) {
backBuffer.buffer(sp);
}
/***/
static boolean activeRendering = true;
/***/
Vector<KeyEventDispatcher> keds = new Vector<KeyEventDispatcher>();
/***/
public void addKeyboardEventsDispatcher(KeyEventDispatcher ked) {
keds.add(ked);
}
/***/
public void removeKeyboardEventsDispatcher(KeyEventDispatcher ked) {
while (keds.remove(ked)) {
;
}
}
/***/
public void removeKeyboardEvents() {
for (Iterator<KeyEventDispatcher> i = keds.iterator(); i.hasNext();) {
KeyboardFocusManager.getCurrentKeyboardFocusManager().removeKeyEventDispatcher(i.next());
}
KeyboardFocusManager.getCurrentKeyboardFocusManager().removeKeyEventPostProcessor(this);
keyEvent = false;
}
/***/
public void addKeyboardEvents() {
for (Iterator<KeyEventDispatcher> i = keds.iterator(); i.hasNext();) {
KeyboardFocusManager.getCurrentKeyboardFocusManager().addKeyEventDispatcher(i.next());
}
KeyboardFocusManager.getCurrentKeyboardFocusManager().addKeyEventPostProcessor(this);
}
/***/
public static boolean _paintCommandsEnabled = false;
/***/
public boolean isInnerResourceModeEnabled() {
return _innerRsrcMode;
}
/***/
public void setInnerResourceModeEnabled(boolean b) {
_innerRsrcMode = b;
}
public boolean isMultiThreadingEnabled() {
return _multiThreading;
}
public void setMultiThreadingEnabled(boolean b) {
_multiThreading = b;
}
public void switchFullScreen() {
switchFullScreen(true);
}
private boolean resourceLoaded = false;
public Object loadResource() {
getOffscreen();
getGCO();
resourceLoaded = true;
return null;
}
public Object clearResource() {
backBuffer.clear();
resourceLoaded = false;
return null;
}
public boolean isResourceLoaded() {
return resourceLoaded;
}
public ThreadGroup getThreadGroup() {
return vSynch.getParent();
}
public void setThreadGroup(ThreadGroup tg) {
if(vSynch instanceof ThreadGroup)
vSynch.interrupt();
if(bufferSynch instanceof ThreadGroup)
bufferSynch.interrupt();
if (tg instanceof ThreadGroup) {
offscreenSynch = new CoalescedThreadsMonitor(tg, "TG-" + getClass().getName() + "-offscreen");
vSynch = new CoalescedThreadsMonitor(tg, "TG-" + getClass().getName() + "-vSynch");
bufferSynch = new CoalescedThreadsMonitor(tg, "TG-" + getClass().getName() + "-bufferSynch");
} else {
offscreenSynch = new CoalescedThreadsMonitor("TG-" + getClass().getName() + "-offscreen");
vSynch = new CoalescedThreadsMonitor("TG-" + getClass().getName() + "-vSynch");
bufferSynch = new CoalescedThreadsMonitor("TG-" + getClass().getName() + "-bufferSynch");
}
vSynch.setMaxPriority(Thread.MAX_PRIORITY);
bufferSynch.setMaxPriority(Thread.MAX_PRIORITY);
}
public boolean postProcessKeyEvent(KeyEvent event) {
System.out.println(event.paramString());
keyEvent = true;
switch (event.getID()) {
case KeyEvent.KEY_PRESSED:
keyPressed = true;
switch (event.getKeyCode()) {
case KeyEvent.VK_F1:
_paintCommandsEnabled = !_paintCommandsEnabled;
break;
case KeyEvent.VK_F11:
switch (state) {
case RUNNING:
suspend();
break;
default:
resume();
break;
}
break;
case KeyEvent.VK_F4:
switchFullScreen();
return true;
case KeyEvent.VK_PAGE_UP:
setRefreshRate(getRefreshRate() + 1);
return true;
case KeyEvent.VK_PAGE_DOWN:
setRefreshRate(getRefreshRate() - 1);
return true;
case KeyEvent.VK_F12:
if (fullscreen) {
switchFullScreen();
}
activeRendering = !activeRendering;
notifyReset();
return true;
case KeyEvent.VK_F9:
_multiThreading = !_multiThreading;
return true;
default:
return false;
}
default:
keyPressed = false;
break;
}
return false;
}
/** this is the display mode wrapper to make checks on*/
class DisplayModeWrapper {
/** the wrapped display mode instance*/
DisplayMode dm;
/** contructs a new wrapper for the given display mode
- @param mode the display mode to wrap*/
public DisplayModeWrapper(DisplayMode mode) {
dm = mode;
}
/** retunrs the wrapped display mode instance
- @return wrapped display mode*/
public DisplayMode getDM() {
return dm;
}
/** returns the string normalization of the wrapped display mode
- @return string normalization of the wrapped display mode*/
public String toString() {
String str = dm.getWidth() + "x" + dm.getHeight() + "@ " + dm.getRefreshRate() + " Hz " + dm.getBitDepth() + " bits";
return str;
}
/** override equals(Object) to make correct checks against another DisplayMode*/
public boolean equals(Object object) {
if (object instanceof DisplayMode) {
object = new DisplayModeWrapper((DisplayMode) object);
}
if (object instanceof DisplayModeWrapper) {
DisplayMode dm2 = ((DisplayModeWrapper) object).getDM();
if (dm2.getWidth() == dm.getWidth() && dm2.getHeight() == dm.getHeight() && dm2.getBitDepth() == dm.getBitDepth() && dm2.getRefreshRate() == dm.getRefreshRate()) {
return true;
}
}
return false;
}
}
}
Conclusion :
l'API sf3jswing utilise ces packages et est actuellement en cours de développement. Les phases de beta-test commencent. Disponible à l'adresse sourceforge.net
http://sf.net/projects/sf3jswing
Vous n'êtes pas encore membre ?
inscrivez-vous, c'est gratuit et ça prend moins d'une minute !
Les membres obtiennent plus de réponses que les utilisateurs anonymes.
Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.
Le fait d'être membre vous permet d'avoir des options supplémentaires.