mirror of
https://github.com/jneug/zeichenmaschine.git
synced 2026-04-14 14:43:33 +02:00
Merge branch 'concurrent-frames'
This commit is contained in:
@@ -1,7 +1,9 @@
|
|||||||
package schule.ngb.zm;
|
package schule.ngb.zm;
|
||||||
|
|
||||||
|
import java.awt.AlphaComposite;
|
||||||
import java.awt.Color;
|
import java.awt.Color;
|
||||||
import java.awt.*;
|
import java.awt.Graphics2D;
|
||||||
|
import java.awt.RenderingHints;
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
|
|
||||||
public abstract class Layer extends Constants implements Drawable, Updatable {
|
public abstract class Layer extends Constants implements Drawable, Updatable {
|
||||||
@@ -73,8 +75,8 @@ public abstract class Layer extends Constants implements Drawable, Updatable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Erstellt einen neuen Puffer für die Ebene mit der angegebenen Größe
|
* Erstellt einen neuen Puffer für die Ebene mit der angegebenen Größe und
|
||||||
* und kopiert den Inhalt des alten Puffers in den Neuen.
|
* kopiert den Inhalt des alten Puffers in den Neuen.
|
||||||
*
|
*
|
||||||
* @param width Width des neuen Puffers.
|
* @param width Width des neuen Puffers.
|
||||||
* @param height Höhe des neuen Puffers.
|
* @param height Höhe des neuen Puffers.
|
||||||
@@ -86,8 +88,8 @@ public abstract class Layer extends Constants implements Drawable, Updatable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Leert die Ebene und löscht alles bisher gezeichnete. Alle Pixel der
|
* Leert die Ebene und löscht alles bisher gezeichnete. Alle Pixel der Ebene
|
||||||
* Ebene werden transparent, damit unterliegende Ebenen durchscheinen können.
|
* werden transparent, damit unterliegende Ebenen durchscheinen können.
|
||||||
*/
|
*/
|
||||||
public void clear() {
|
public void clear() {
|
||||||
// https://stackoverflow.com/questions/31149206/set-pixels-of-bufferedimage-as-transparent
|
// https://stackoverflow.com/questions/31149206/set-pixels-of-bufferedimage-as-transparent
|
||||||
|
|||||||
@@ -29,6 +29,9 @@ public final class Options {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Zustände in denen sich die Zeichenmaschine befinden kann.
|
||||||
|
*/
|
||||||
public enum AppState {
|
public enum AppState {
|
||||||
INITIALIZING,
|
INITIALIZING,
|
||||||
INITIALIZED,
|
INITIALIZED,
|
||||||
@@ -37,9 +40,16 @@ public final class Options {
|
|||||||
DRAWING,
|
DRAWING,
|
||||||
PAUSED,
|
PAUSED,
|
||||||
STOPPED,
|
STOPPED,
|
||||||
TERMINATED
|
TERMINATED,
|
||||||
|
IDLE
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Richtungen für die Ausrichtung von Formen. Richtungen sind durch
|
||||||
|
* Einheitsvektoren bzw. deren Kombination repräsentiert, wodurch mit ihnen
|
||||||
|
* gerechnet werden kann. Jede Richtung ist zusätzlich als Himmelsrichtung
|
||||||
|
* definiert.
|
||||||
|
*/
|
||||||
public enum Direction {
|
public enum Direction {
|
||||||
CENTER(0, 0),
|
CENTER(0, 0),
|
||||||
|
|
||||||
@@ -90,6 +100,7 @@ public final class Options {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Gibt die entgegengesetzte Richtung zu dieser zurück.
|
* Gibt die entgegengesetzte Richtung zu dieser zurück.
|
||||||
|
*
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public Direction inverse() {
|
public Direction inverse() {
|
||||||
|
|||||||
@@ -174,18 +174,32 @@ public class Zeichenleinwand extends Canvas {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public boolean removeLayer( Layer pLayer ) {
|
public boolean removeLayer( Layer pLayer ) {
|
||||||
|
synchronized( layers ) {
|
||||||
return layers.remove(pLayer);
|
return layers.remove(pLayer);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void removeLayers( Layer... pLayers ) {
|
public void removeLayers( Layer... pLayers ) {
|
||||||
|
synchronized( layers ) {
|
||||||
for( Layer layer : pLayers ) {
|
for( Layer layer : pLayers ) {
|
||||||
layers.remove(layer);
|
layers.remove(layer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void clearLayers() {
|
public void clearLayers() {
|
||||||
|
synchronized( layers ) {
|
||||||
layers.clear();
|
layers.clear();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateLayers( double delta ) {
|
||||||
|
synchronized( layers ) {
|
||||||
|
for( Layer layer : layers ) {
|
||||||
|
layer.update(delta);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Erstellt eine passende {@link BufferStrategy} für diese Ebene.
|
* Erstellt eine passende {@link BufferStrategy} für diese Ebene.
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package schule.ngb.zm;
|
package schule.ngb.zm;
|
||||||
|
|
||||||
|
import schule.ngb.zm.anim.Animation;
|
||||||
import schule.ngb.zm.shapes.ShapesLayer;
|
import schule.ngb.zm.shapes.ShapesLayer;
|
||||||
import schule.ngb.zm.tasks.TaskRunner;
|
import schule.ngb.zm.tasks.TaskRunner;
|
||||||
import schule.ngb.zm.util.ImageLoader;
|
import schule.ngb.zm.util.ImageLoader;
|
||||||
@@ -23,6 +24,7 @@ import java.util.logging.Level;
|
|||||||
* Die Klasse übernimmt die Initialisierung eines Programmfensters und der
|
* Die Klasse übernimmt die Initialisierung eines Programmfensters und der
|
||||||
* nötigen Komponenten.
|
* nötigen Komponenten.
|
||||||
*/
|
*/
|
||||||
|
// TODO: Refactorings (besonders in Bezug auf Nebenläufigkeit)
|
||||||
public class Zeichenmaschine extends Constants {
|
public class Zeichenmaschine extends Constants {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -34,10 +36,19 @@ public class Zeichenmaschine extends Constants {
|
|||||||
IN_BLUEJ = System.getProperty("java.class.path").contains("bluej");
|
IN_BLUEJ = System.getProperty("java.class.path").contains("bluej");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gibt an, ob die Zeichenmaschine unter macOS gestartet wurde.
|
||||||
|
*/
|
||||||
public static final boolean MACOS;
|
public static final boolean MACOS;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gibt an, ob die Zeichenmaschine unter Windows gestartet wurde.
|
||||||
|
*/
|
||||||
public static final boolean WINDOWS;
|
public static final boolean WINDOWS;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gibt an, ob die Zeichenmaschine unter Linux gestartet wurde.
|
||||||
|
*/
|
||||||
public static final boolean LINUX;
|
public static final boolean LINUX;
|
||||||
|
|
||||||
static {
|
static {
|
||||||
@@ -95,10 +106,21 @@ public class Zeichenmaschine extends Constants {
|
|||||||
* Interne Attribute zur Steuerung der Zeichenmaschine.
|
* Interne Attribute zur Steuerung der Zeichenmaschine.
|
||||||
*/
|
*/
|
||||||
//@formatter:off
|
//@formatter:off
|
||||||
// Das Zeichenfenster der Zeichenmaschine
|
|
||||||
|
/**
|
||||||
|
* Das Zeichenfenster der Zeichenmaschine
|
||||||
|
*/
|
||||||
private JFrame frame;
|
private JFrame frame;
|
||||||
// Die Graphics-Objekte für das aktuelle Fenster.
|
|
||||||
|
/**
|
||||||
|
* Die Graphics-Umgebung für das aktuelle Fenster.
|
||||||
|
*/
|
||||||
private GraphicsEnvironment environment;
|
private GraphicsEnvironment environment;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Das Anzeigefenster, auf dem die ZM gestartet wurde (muss nicht gleich
|
||||||
|
* dem Aktuellen sein, wenn das Fenster verschoben wurde).
|
||||||
|
*/
|
||||||
private GraphicsDevice displayDevice;
|
private GraphicsDevice displayDevice;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -116,11 +138,11 @@ public class Zeichenmaschine extends Constants {
|
|||||||
private int initialWidth, initialHeight;
|
private int initialWidth, initialHeight;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* KeyListener, um den Vollbild-Modus mit der Escape-Taste zu verlassen.
|
* {@code KeyListener}, um den Vollbild-Modus mit der Escape-Taste zu
|
||||||
* Wird von {@link #setFullscreen(boolean)} automatisch einzugefügt und
|
* verlassen. Wird von {@link #setFullscreen(boolean)} automatisch
|
||||||
* entfernt.
|
* hinzugefügt und entfernt.
|
||||||
*/
|
*/
|
||||||
KeyListener fullscreenExitListener = new KeyAdapter() {
|
private KeyListener fullscreenExitListener = new KeyAdapter() {
|
||||||
@Override
|
@Override
|
||||||
public void keyPressed( KeyEvent e ) {
|
public void keyPressed( KeyEvent e ) {
|
||||||
if( e.getKeyCode() == KeyEvent.VK_ESCAPE ) {
|
if( e.getKeyCode() == KeyEvent.VK_ESCAPE ) {
|
||||||
@@ -131,30 +153,69 @@ public class Zeichenmaschine extends Constants {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Aktueller Zustand der Zeichenmaschine.
|
// Aktueller Zustand der Zeichenmaschine.
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Zustand der Zeichenmaschine insgesamt
|
||||||
|
*/
|
||||||
private Options.AppState state = Options.AppState.INITIALIZING;
|
private Options.AppState state = Options.AppState.INITIALIZING;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Zustand des update/draw Threads
|
||||||
|
*/
|
||||||
|
private Options.AppState updateState = Options.AppState.STOPPED;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ob der Zeichenthread noch laufen soll, oder beendet.
|
||||||
|
*/
|
||||||
private boolean running = false;
|
private boolean running = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ob die ZM nach dem nächsten Frame pausiert werden soll.
|
||||||
|
*/
|
||||||
private boolean pause_pending = false;
|
private boolean pause_pending = false;
|
||||||
|
|
||||||
private boolean stop_after_update = false, run_once = true;
|
/**
|
||||||
|
* Ob die ZM bei nicht überschriebener update() Methode stoppen soll,
|
||||||
|
* oder trotzdem weiterläuft.
|
||||||
|
*/
|
||||||
|
private boolean run_once = true;
|
||||||
|
|
||||||
// Aktuelle Frames pro Sekunde der Zeichenmaschine.
|
/**
|
||||||
|
* Aktuelle Frames pro Sekunde der Zeichenmaschine.
|
||||||
|
*/
|
||||||
private int framesPerSecondInternal;
|
private int framesPerSecondInternal;
|
||||||
|
|
||||||
// Hauptthread der Zeichenmaschine.
|
/**
|
||||||
|
* Hauptthread der Zeichenmaschine.
|
||||||
|
*/
|
||||||
private Thread mainThread;
|
private Thread mainThread;
|
||||||
|
|
||||||
// Queue für geplante Aufgaben
|
/**
|
||||||
|
* Queue für geplante Aufgaben
|
||||||
|
*/
|
||||||
private DelayQueue<DelayedTask> taskQueue = new DelayQueue<>();
|
private DelayQueue<DelayedTask> taskQueue = new DelayQueue<>();
|
||||||
|
|
||||||
// Queue für abgefangene InputEvents
|
/**
|
||||||
|
* Queue für abgefangene InputEvents
|
||||||
|
*/
|
||||||
private BlockingQueue<InputEvent> eventQueue = new LinkedBlockingQueue<>();
|
private BlockingQueue<InputEvent> eventQueue = new LinkedBlockingQueue<>();
|
||||||
|
|
||||||
// Gibt an, ob nach Ende des Hauptthreads das Programm beendet werden soll,
|
/**
|
||||||
// oder das Zeichenfenster weiter geöffnet bleibt.
|
* Gibt an, ob nach Ende des Hauptthreads das Programm beendet werden soll,
|
||||||
|
* oder das Zeichenfenster weiter geöffnet bleibt.
|
||||||
|
*/
|
||||||
private boolean quitAfterTeardown = false;
|
private boolean quitAfterTeardown = false;
|
||||||
|
|
||||||
// Mauscursor
|
// Mauszeiger
|
||||||
|
/**
|
||||||
|
* Cache für den unsichtbaren Mauszeiger, wenn {@link #hideCursor()}
|
||||||
|
* aufgerufen wurde.
|
||||||
|
*/
|
||||||
private Cursor invisibleCursor = null;
|
private Cursor invisibleCursor = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ob der Mauszeiger derzeit sichtbar ist (bzw. sein sollte).
|
||||||
|
*/
|
||||||
protected boolean cursorVisible = true;
|
protected boolean cursorVisible = true;
|
||||||
//@formatter:on
|
//@formatter:on
|
||||||
|
|
||||||
@@ -335,11 +396,20 @@ public class Zeichenmaschine extends Constants {
|
|||||||
frame.addWindowListener(new WindowAdapter() {
|
frame.addWindowListener(new WindowAdapter() {
|
||||||
@Override
|
@Override
|
||||||
public void windowClosing( WindowEvent e ) {
|
public void windowClosing( WindowEvent e ) {
|
||||||
//exit();
|
if( running ) {
|
||||||
|
running = false;
|
||||||
teardown();
|
teardown();
|
||||||
cleanup();
|
cleanup();
|
||||||
|
}
|
||||||
|
// Give the app a minimum amount of time to shut down
|
||||||
|
// then kill it.
|
||||||
|
try {
|
||||||
|
Thread.sleep(5);
|
||||||
|
} catch( InterruptedException ex ) {
|
||||||
|
} finally {
|
||||||
quit(true);
|
quit(true);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Fenster zusammenbauen, auf dem Bildschirm zentrieren ...
|
// Fenster zusammenbauen, auf dem Bildschirm zentrieren ...
|
||||||
@@ -882,8 +952,13 @@ public class Zeichenmaschine extends Constants {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if( state != Options.AppState.RUNNING ) {
|
||||||
|
LOG.warn("Don't use delay(int) from within settings() or setup().");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
long timer = 0L;
|
long timer = 0L;
|
||||||
if( state == Options.AppState.DRAWING ) {
|
if( updateState == Options.AppState.DRAWING ) {
|
||||||
// Falls gerade draw() ausgeführt wird, zeigen wir den aktuellen
|
// Falls gerade draw() ausgeführt wird, zeigen wir den aktuellen
|
||||||
// Stand der Zeichnung auf der Leinwand an. Die Zeit für das
|
// Stand der Zeichnung auf der Leinwand an. Die Zeit für das
|
||||||
// Rendern wird gemessen und von der Wartezeit abgezogen.
|
// Rendern wird gemessen und von der Wartezeit abgezogen.
|
||||||
@@ -1038,7 +1113,6 @@ public class Zeichenmaschine extends Constants {
|
|||||||
*/
|
*/
|
||||||
public void update( double delta ) {
|
public void update( double delta ) {
|
||||||
running = !run_once;
|
running = !run_once;
|
||||||
stop_after_update = run_once;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1052,7 +1126,7 @@ public class Zeichenmaschine extends Constants {
|
|||||||
* dar, da hier die Zeichnung des Programms erstellt wird.
|
* dar, da hier die Zeichnung des Programms erstellt wird.
|
||||||
*/
|
*/
|
||||||
public void draw() {
|
public void draw() {
|
||||||
//running = !stop_after_update;
|
// Intentionally left blank
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1322,10 +1396,14 @@ public class Zeichenmaschine extends Constants {
|
|||||||
delay(1);
|
delay(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ThreadExecutor for the update/draw Thread
|
||||||
|
final UpdateThreadExecutor updateThreadExecutor = new UpdateThreadExecutor();
|
||||||
|
|
||||||
// start of thread in ms
|
// start of thread in ms
|
||||||
final long start = System.currentTimeMillis();
|
final long start = System.currentTimeMillis();
|
||||||
// current time in ns
|
// current time in ns
|
||||||
long beforeTime = System.nanoTime();
|
long beforeTime = System.nanoTime();
|
||||||
|
long updateBeforeTime = System.nanoTime();
|
||||||
// store for deltas
|
// store for deltas
|
||||||
long overslept = 0L;
|
long overslept = 0L;
|
||||||
// internal counters for tick and runtime
|
// internal counters for tick and runtime
|
||||||
@@ -1341,24 +1419,61 @@ public class Zeichenmaschine extends Constants {
|
|||||||
state = Options.AppState.RUNNING;
|
state = Options.AppState.RUNNING;
|
||||||
while( running ) {
|
while( running ) {
|
||||||
// delta in seconds
|
// delta in seconds
|
||||||
delta = (System.nanoTime() - beforeTime) / 1000000000.0;
|
|
||||||
beforeTime = System.nanoTime();
|
beforeTime = System.nanoTime();
|
||||||
|
|
||||||
saveMousePosition(mouseEvent);
|
saveMousePosition(mouseEvent);
|
||||||
|
|
||||||
if( state != Options.AppState.PAUSED ) {
|
if( state != Options.AppState.PAUSED ) {
|
||||||
handleUpdate(delta);
|
//handleUpdate(delta);
|
||||||
handleDraw();
|
//handleDraw();
|
||||||
|
|
||||||
|
// Update and draw are executed in a new thread,
|
||||||
|
// but we wait for them to finish unless the user
|
||||||
|
// did call any blocking method, that would also block
|
||||||
|
// rendering of new frames.
|
||||||
|
if( !updateThreadExecutor.isRunning() ) {
|
||||||
|
delta = (System.nanoTime() - updateBeforeTime) / 1000000000.0;
|
||||||
|
updateBeforeTime = System.nanoTime();
|
||||||
|
|
||||||
|
updateThreadExecutor.execute(() -> {
|
||||||
|
if( state == Options.AppState.RUNNING
|
||||||
|
&& updateState == Options.AppState.IDLE ) {
|
||||||
|
// Call to update()
|
||||||
|
updateState = Options.AppState.UPDATING;
|
||||||
|
Zeichenmaschine.this.update(delta);
|
||||||
|
// Update Layers
|
||||||
|
canvas.updateLayers(delta);
|
||||||
|
// Call to draw()
|
||||||
|
updateState = Options.AppState.DRAWING;
|
||||||
|
Zeichenmaschine.this.draw();
|
||||||
|
updateState = Options.AppState.IDLE;
|
||||||
|
// Send latest input events after finishing draw
|
||||||
|
// since these may also block
|
||||||
|
dispatchEvents();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait for the update/draw Thread to finish
|
||||||
|
while( updateThreadExecutor.isRunning()
|
||||||
|
&& !updateThreadExecutor.isWaiting() ) {
|
||||||
|
Thread.yield();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Display the current buffer content
|
||||||
if( canvas != null ) {
|
if( canvas != null ) {
|
||||||
canvas.render();
|
canvas.render();
|
||||||
// canvas.invalidate();
|
// canvas.invalidate();
|
||||||
// frame.repaint();
|
// frame.repaint();
|
||||||
}
|
}
|
||||||
|
|
||||||
dispatchEvents();
|
|
||||||
|
// dispatchEvents();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Running pending tasks and notify any
|
||||||
|
// waiting FrameSynchonizedTasks
|
||||||
|
// TODO: should this this also happen in the updateThread?
|
||||||
runTasks();
|
runTasks();
|
||||||
synchronized( globalSyncLock ) {
|
synchronized( globalSyncLock ) {
|
||||||
globalSyncLock.notifyAll();
|
globalSyncLock.notifyAll();
|
||||||
@@ -1369,7 +1484,7 @@ public class Zeichenmaschine extends Constants {
|
|||||||
long dt = afterTime - beforeTime;
|
long dt = afterTime - beforeTime;
|
||||||
long sleep = ((1000000000L / framesPerSecondInternal) - dt) - overslept;
|
long sleep = ((1000000000L / framesPerSecondInternal) - dt) - overslept;
|
||||||
|
|
||||||
|
// Sleep before next frame
|
||||||
if( sleep > 0 ) {
|
if( sleep > 0 ) {
|
||||||
try {
|
try {
|
||||||
Thread.sleep(sleep / 1000000L, (int) (sleep % 1000000L));
|
Thread.sleep(sleep / 1000000L, (int) (sleep % 1000000L));
|
||||||
@@ -1382,19 +1497,24 @@ public class Zeichenmaschine extends Constants {
|
|||||||
overslept = 0L;
|
overslept = 0L;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Update stats
|
||||||
_tick += 1;
|
_tick += 1;
|
||||||
_runtime = System.currentTimeMillis() - start;
|
_runtime = System.currentTimeMillis() - start;
|
||||||
tick = _tick;
|
tick = _tick;
|
||||||
runtime = _runtime;
|
runtime = _runtime;
|
||||||
framesPerSecond = framesPerSecondInternal;
|
framesPerSecond = framesPerSecondInternal;
|
||||||
|
|
||||||
|
// If pause requested, we pause now
|
||||||
if( pause_pending ) {
|
if( pause_pending ) {
|
||||||
state = Options.AppState.PAUSED;
|
state = Options.AppState.PAUSED;
|
||||||
pause_pending = false;
|
pause_pending = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Shutdown the updateThreads
|
||||||
|
updateThreadExecutor.shutdownNow();
|
||||||
state = Options.AppState.STOPPED;
|
state = Options.AppState.STOPPED;
|
||||||
|
|
||||||
|
// Cleanup
|
||||||
teardown();
|
teardown();
|
||||||
cleanup();
|
cleanup();
|
||||||
state = Options.AppState.TERMINATED;
|
state = Options.AppState.TERMINATED;
|
||||||
@@ -1408,10 +1528,7 @@ public class Zeichenmaschine extends Constants {
|
|||||||
if( state == Options.AppState.RUNNING ) {
|
if( state == Options.AppState.RUNNING ) {
|
||||||
state = Options.AppState.UPDATING;
|
state = Options.AppState.UPDATING;
|
||||||
update(delta);
|
update(delta);
|
||||||
|
canvas.updateLayers(delta);
|
||||||
for( Layer l: canvas.getLayers() ) {
|
|
||||||
l.update(delta);
|
|
||||||
}
|
|
||||||
state = Options.AppState.RUNNING;
|
state = Options.AppState.RUNNING;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1426,6 +1543,7 @@ public class Zeichenmaschine extends Constants {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Remove
|
||||||
class DelayedTask implements Delayed {
|
class DelayedTask implements Delayed {
|
||||||
|
|
||||||
long startTime; // in ms
|
long startTime; // in ms
|
||||||
@@ -1515,6 +1633,60 @@ public class Zeichenmaschine extends Constants {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class UpdateThreadExecutor extends ThreadPoolExecutor {
|
||||||
|
|
||||||
|
private Thread updateThread;
|
||||||
|
|
||||||
|
private boolean running = false, waiting = false;
|
||||||
|
|
||||||
|
public UpdateThreadExecutor() {
|
||||||
|
super(1, 1, 0L,
|
||||||
|
TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>());
|
||||||
|
updateState = Options.AppState.IDLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void beforeExecute( Thread t, Runnable r ) {
|
||||||
|
// We store the one Thread this Executor holds
|
||||||
|
// but it might change if a new Thread needed to be spawned
|
||||||
|
// due to en error.
|
||||||
|
updateThread = t;
|
||||||
|
running = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void afterExecute( Runnable r, Throwable t ) {
|
||||||
|
running = false;
|
||||||
|
updateState = Options.AppState.IDLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ermittelt, ob der interne Thread gerade eine update/draw Task
|
||||||
|
* ausführt.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public boolean isRunning() {
|
||||||
|
return running;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ermittelt, ob der interne Thread gerade eine update/draw Task
|
||||||
|
* ausführt und dabei in einen Wartezustand versetzt wurde. Das bedeutet
|
||||||
|
* in der Regel, dass innerhalb von {@link #update(double)} oder
|
||||||
|
* {@link #draw()} ein {@link #delay(int)} ausgeführt wurde, oder aus
|
||||||
|
* einem anderen Grund beispielsweise {@link Thread#sleep(long)}
|
||||||
|
* aufgerufen wurde. (Dies kann zum Beispiel beim
|
||||||
|
* {@link Animation#await() Warten auf Animationen} der Fall sein.)
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public boolean isWaiting() {
|
||||||
|
return running && updateThread.getState() == Thread.State.TIMED_WAITING;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
private static final Log LOG = Log.getLogger(Zeichenmaschine.class);
|
private static final Log LOG = Log.getLogger(Zeichenmaschine.class);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user