Renderer full life cycle;
This commit is contained in:
@@ -11,6 +11,8 @@ public interface Renderer {
|
|||||||
void run(List<RenderingBo> renderingBOs) throws InterruptedException;
|
void run(List<RenderingBo> renderingBOs) throws InterruptedException;
|
||||||
|
|
||||||
void reset();
|
void reset();
|
||||||
|
|
||||||
|
void shutdown();
|
||||||
|
|
||||||
void takeScreenshot();
|
void takeScreenshot();
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import java.util.function.Consumer;
|
|||||||
import org.springframework.beans.factory.annotation.Qualifier;
|
import org.springframework.beans.factory.annotation.Qualifier;
|
||||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||||
|
import org.springframework.context.ApplicationContext;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
|
|
||||||
import de.extio.game_engine.renderer.model.RenderingBo;
|
import de.extio.game_engine.renderer.model.RenderingBo;
|
||||||
@@ -32,8 +33,8 @@ public class RendererConfiguration {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public RendererData rendererData(final Renderer renderer, final RendererControl rendererControl, final RenderingBoPool renderingBoPool, @Qualifier("gameEngineEventConsumer") final Consumer<Object> eventConsumer) {
|
public RendererData rendererData(final ApplicationContext applicationContext, final Renderer renderer, final RendererControl rendererControl, final RenderingBoPool renderingBoPool, @Qualifier("gameEngineEventConsumer") final Consumer<Object> eventConsumer) {
|
||||||
final var rendererData = new RendererData(renderer, rendererControl, renderingBoPool, eventConsumer);
|
final var rendererData = new RendererData(applicationContext, renderer, rendererControl, renderingBoPool, eventConsumer);
|
||||||
renderer.setRendererData(rendererData);
|
renderer.setRendererData(rendererData);
|
||||||
rendererControl.setRendererData(rendererData);
|
rendererControl.setRendererData(rendererData);
|
||||||
renderingBoPool.setRendererData(rendererData);
|
renderingBoPool.setRendererData(rendererData);
|
||||||
@@ -41,11 +42,8 @@ public class RendererConfiguration {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public RendererLoop rendererLoop(final RendererData rendererData) {
|
public RendererLauncher rendererLauncher(final ApplicationContext applicationContext, final RendererData rendererData) {
|
||||||
final var rendererLoop = new RendererLoop(rendererData);
|
return new RendererLauncher(applicationContext, rendererData);
|
||||||
rendererData.setRendererLoop(rendererLoop);
|
|
||||||
rendererLoop.start();
|
|
||||||
return rendererLoop;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,10 +3,14 @@ package de.extio.game_engine.renderer;
|
|||||||
import java.util.concurrent.atomic.AtomicLong;
|
import java.util.concurrent.atomic.AtomicLong;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
import org.springframework.context.ApplicationContext;
|
||||||
|
|
||||||
import de.extio.game_engine.renderer.model.options.UiOptions;
|
import de.extio.game_engine.renderer.model.options.UiOptions;
|
||||||
import de.extio.game_engine.renderer.model.options.VideoOptions;
|
import de.extio.game_engine.renderer.model.options.VideoOptions;
|
||||||
|
|
||||||
public class RendererData {
|
public class RendererData {
|
||||||
|
|
||||||
|
private final ApplicationContext applicationContext;
|
||||||
|
|
||||||
private final Renderer renderer;
|
private final Renderer renderer;
|
||||||
|
|
||||||
@@ -24,12 +28,17 @@ public class RendererData {
|
|||||||
|
|
||||||
private RendererLoop rendererLoop;
|
private RendererLoop rendererLoop;
|
||||||
|
|
||||||
public RendererData(final Renderer renderer, final RendererControl rendererControl, final RenderingBoPool renderingBoPool, final Consumer<Object> eventConsumer) {
|
public RendererData(final ApplicationContext applicationContext, final Renderer renderer, final RendererControl rendererControl, final RenderingBoPool renderingBoPool, final Consumer<Object> eventConsumer) {
|
||||||
|
this.applicationContext = applicationContext;
|
||||||
this.renderer = renderer;
|
this.renderer = renderer;
|
||||||
this.rendererControl = rendererControl;
|
this.rendererControl = rendererControl;
|
||||||
this.renderingBoPool = renderingBoPool;
|
this.renderingBoPool = renderingBoPool;
|
||||||
this.eventConsumer = eventConsumer;
|
this.eventConsumer = eventConsumer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ApplicationContext getApplicationContext() {
|
||||||
|
return applicationContext;
|
||||||
|
}
|
||||||
|
|
||||||
public RendererControl getRendererControl() {
|
public RendererControl getRendererControl() {
|
||||||
return this.rendererControl;
|
return this.rendererControl;
|
||||||
|
|||||||
@@ -0,0 +1,113 @@
|
|||||||
|
package de.extio.game_engine.renderer;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.factory.DisposableBean;
|
||||||
|
import org.springframework.beans.factory.InitializingBean;
|
||||||
|
import org.springframework.boot.SpringApplication;
|
||||||
|
import org.springframework.context.ApplicationContext;
|
||||||
|
|
||||||
|
public class RendererLauncher implements InitializingBean, DisposableBean {
|
||||||
|
|
||||||
|
private static final Logger LOGGER = LoggerFactory.getLogger(RendererLauncher.class);
|
||||||
|
|
||||||
|
private final ApplicationContext applicationContext;
|
||||||
|
|
||||||
|
private final RendererData rendererData;
|
||||||
|
|
||||||
|
private RendererLoop rendererLoop;
|
||||||
|
|
||||||
|
private Thread rendererLoopThread;
|
||||||
|
|
||||||
|
private Thread watchDogThread;
|
||||||
|
|
||||||
|
public RendererLauncher(final ApplicationContext applicationContext, final RendererData rendererData) {
|
||||||
|
this.applicationContext = applicationContext;
|
||||||
|
this.rendererData = rendererData;
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Override
|
||||||
|
// public void start() {
|
||||||
|
// this.launch();
|
||||||
|
// }
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void afterPropertiesSet() throws Exception {
|
||||||
|
this.launch();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void destroy() throws Exception {
|
||||||
|
this.shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Override
|
||||||
|
// public void stop() {
|
||||||
|
// this.shutdown();
|
||||||
|
// }
|
||||||
|
|
||||||
|
// @Override
|
||||||
|
// public boolean isRunning() {
|
||||||
|
// return this.rendererLoopThread != null && this.rendererLoopThread.isAlive();
|
||||||
|
// }
|
||||||
|
|
||||||
|
private void launch() {
|
||||||
|
if (this.rendererLoopThread != null && this.rendererLoopThread.isAlive()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOGGER.info("Launching RendererLoop");
|
||||||
|
this.rendererLoop = new RendererLoop(this.rendererData);
|
||||||
|
rendererData.setRendererLoop(rendererLoop);
|
||||||
|
this.rendererLoopThread = Thread.ofPlatform()
|
||||||
|
.name("RendererLoop")
|
||||||
|
.daemon(false)
|
||||||
|
.start(this.rendererLoop);
|
||||||
|
|
||||||
|
LOGGER.info("Launching RendererWatchDog");
|
||||||
|
this.watchDogThread = Thread.ofPlatform()
|
||||||
|
.name("RendererWatchDog")
|
||||||
|
.daemon(true)
|
||||||
|
.start(() -> {
|
||||||
|
try {
|
||||||
|
this.rendererLoopThread.join();
|
||||||
|
LOGGER.error("RendererLoop thread has exited unexpectedly, shutting down application");
|
||||||
|
SpringApplication.exit(this.applicationContext, () -> 1);
|
||||||
|
}
|
||||||
|
catch (final InterruptedException e) {
|
||||||
|
Thread.currentThread().interrupt();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void shutdown() {
|
||||||
|
if (this.watchDogThread != null && this.watchDogThread.isAlive()) {
|
||||||
|
LOGGER.info("Shutting down RendererWatchDog");
|
||||||
|
this.watchDogThread.interrupt();
|
||||||
|
try {
|
||||||
|
this.watchDogThread.join(5000);
|
||||||
|
}
|
||||||
|
catch (final InterruptedException e) {
|
||||||
|
Thread.currentThread().interrupt();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.watchDogThread = null;
|
||||||
|
|
||||||
|
if (this.rendererLoopThread != null && this.rendererLoopThread.isAlive() && this.rendererLoop != null) {
|
||||||
|
LOGGER.info("Shutting down RendererLoop");
|
||||||
|
this.rendererLoop.shutdown();
|
||||||
|
try {
|
||||||
|
this.rendererLoopThread.join(5000);
|
||||||
|
}
|
||||||
|
catch (final InterruptedException e) {
|
||||||
|
Thread.currentThread().interrupt();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.rendererLoopThread = null;
|
||||||
|
this.rendererLoop = null;
|
||||||
|
this.rendererData.setRendererLoop(null);
|
||||||
|
|
||||||
|
this.rendererData.getRenderer().shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -5,28 +5,28 @@ import java.util.ArrayList;
|
|||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
public class RendererLoop extends Thread {
|
public class RendererLoop implements Runnable {
|
||||||
|
|
||||||
private static final Logger LOGGER = LoggerFactory.getLogger(RendererLoop.class);
|
private static final Logger LOGGER = LoggerFactory.getLogger(RendererLoop.class);
|
||||||
|
|
||||||
private final RendererData rendererData;
|
private volatile boolean shutdown;
|
||||||
|
|
||||||
private volatile boolean running = true;
|
private final RendererData rendererData;
|
||||||
|
|
||||||
public RendererLoop(final RendererData rendererData) {
|
public RendererLoop(final RendererData rendererData) {
|
||||||
this.rendererData = rendererData;
|
this.rendererData = rendererData;
|
||||||
this.setName("Renderer-Loop");
|
|
||||||
this.setDaemon(false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
|
this.shutdown = false;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
this.rendererData.getRenderer().show();
|
this.rendererData.getRenderer().show();
|
||||||
|
|
||||||
LOGGER.info("Renderer loop started");
|
LOGGER.info("Renderer loop started");
|
||||||
int exceptionCount = 0;
|
int exceptionCount = 0;
|
||||||
while (this.running) {
|
while (!this.shutdown) {
|
||||||
try {
|
try {
|
||||||
this.rendererData.nextFrame();
|
this.rendererData.nextFrame();
|
||||||
this.rendererData.getRenderer().run(new ArrayList<>()); // TODO: Pass actual renderables
|
this.rendererData.getRenderer().run(new ArrayList<>()); // TODO: Pass actual renderables
|
||||||
@@ -45,7 +45,7 @@ public class RendererLoop extends Thread {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
LOGGER.info("Renderer loop exited");
|
LOGGER.info("Renderer loop exited");
|
||||||
}
|
}
|
||||||
catch (final Throwable t) {
|
catch (final Throwable t) {
|
||||||
@@ -54,7 +54,8 @@ public class RendererLoop extends Thread {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void shutdown() {
|
public void shutdown() {
|
||||||
this.running = false;
|
LOGGER.info("RendererLoop shutdown requested");
|
||||||
|
this.shutdown = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ import javax.imageio.ImageIO;
|
|||||||
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.boot.SpringApplication;
|
||||||
|
|
||||||
import de.extio.game_engine.keyboard.KeyModifiers;
|
import de.extio.game_engine.keyboard.KeyModifiers;
|
||||||
import de.extio.game_engine.renderer.RendererControl;
|
import de.extio.game_engine.renderer.RendererControl;
|
||||||
@@ -93,7 +94,8 @@ public class G2DMainFrame extends Frame {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void windowClosing(final WindowEvent e) {
|
public void windowClosing(final WindowEvent e) {
|
||||||
G2DMainFrame.this.rendererData.getRendererLoop().shutdown();
|
LOGGER.info("Window closing requested");
|
||||||
|
SpringApplication.exit(G2DMainFrame.this.rendererData.getApplicationContext(), () -> 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -98,6 +98,25 @@ public class G2DRenderer implements Renderer {
|
|||||||
public void reset() {
|
public void reset() {
|
||||||
G2DDrawControl.reset();
|
G2DDrawControl.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void shutdown() {
|
||||||
|
LOGGER.info("shutdown()");
|
||||||
|
|
||||||
|
this.rwLock.writeLock().lock();
|
||||||
|
try {
|
||||||
|
if (this.mainFrame != null) {
|
||||||
|
this.mainFrame.unregisterFullScreenWindow();
|
||||||
|
this.reset();
|
||||||
|
this.mainFrame.setVisible(false);
|
||||||
|
this.mainFrame.dispose();
|
||||||
|
this.mainFrame = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
this.rwLock.writeLock().unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run(final List<RenderingBo> renderingBOs) throws InterruptedException {
|
public void run(final List<RenderingBo> renderingBOs) throws InterruptedException {
|
||||||
|
|||||||
@@ -163,8 +163,11 @@ public class G2DRendererControl implements RendererControl {
|
|||||||
if (this.updateAbsoluteViewportPortDimension()) {
|
if (this.updateAbsoluteViewportPortDimension()) {
|
||||||
this.recalculate();
|
this.recalculate();
|
||||||
}
|
}
|
||||||
this.renderer.getMainFrame().createBufferStrategy();
|
final var mainFrame = this.renderer.getMainFrame();
|
||||||
this.renderer.getMainFrame().resizeListenerEnabled = true;
|
if (mainFrame != null) {
|
||||||
|
mainFrame.createBufferStrategy();
|
||||||
|
mainFrame.resizeListenerEnabled = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
if (lockRenderer) {
|
if (lockRenderer) {
|
||||||
@@ -174,7 +177,10 @@ public class G2DRendererControl implements RendererControl {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (async) {
|
if (async) {
|
||||||
EventQueue.invokeLater(run);
|
// EventQueue.invokeLater(run); // Using EventQueue here can clutter the AWT event queue with too many events when resizing on a system with high event rate
|
||||||
|
Thread.ofVirtual()
|
||||||
|
.name("G2DRendererControl-ViewportUpdater", 0)
|
||||||
|
.start(run);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
run.run();
|
run.run();
|
||||||
@@ -189,7 +195,7 @@ public class G2DRendererControl implements RendererControl {
|
|||||||
private boolean updateAbsoluteViewportPortDimension() {
|
private boolean updateAbsoluteViewportPortDimension() {
|
||||||
boolean changed = false;
|
boolean changed = false;
|
||||||
final var absoluteDim = this.absoluteViewportDimension;
|
final var absoluteDim = this.absoluteViewportDimension;
|
||||||
if (absoluteDim == null || absoluteDim.getX() != this.renderer.getMainFrame().getWidth() || absoluteDim.getY() != this.renderer.getMainFrame().getHeight()) {
|
if (absoluteDim == null || (this.renderer.getMainFrame() != null && (absoluteDim.getX() != this.renderer.getMainFrame().getWidth() || absoluteDim.getY() != this.renderer.getMainFrame().getHeight()))) {
|
||||||
this.absoluteViewportDimension = ImmutableCoordI2.create(this.renderer.getMainFrame().getWidth(), this.renderer.getMainFrame().getHeight());
|
this.absoluteViewportDimension = ImmutableCoordI2.create(this.renderer.getMainFrame().getWidth(), this.renderer.getMainFrame().getHeight());
|
||||||
changed = true;
|
changed = true;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user