Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
ultraq committed Dec 28, 2024
1 parent 33771b6 commit 3c8fc40
Show file tree
Hide file tree
Showing 5 changed files with 213 additions and 186 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ package nz.net.ultraq.redhorizon.engine
import nz.net.ultraq.redhorizon.engine.scenegraph.Scene
import nz.net.ultraq.redhorizon.events.EventTarget

import org.slf4j.Logger
import org.slf4j.LoggerFactory

import groovy.transform.PackageScope

/**
Expand All @@ -33,6 +36,8 @@ import groovy.transform.PackageScope
*/
abstract class EngineSystem implements Runnable, EventTarget {

private static final Logger logger = LoggerFactory.getLogger(EngineSystem)

private Engine engine
protected Scene scene

Expand All @@ -49,6 +54,25 @@ abstract class EngineSystem implements Runnable, EventTarget {
return engine
}

/**
* Return the name of the system, for logging purposes.
*/
protected String getSystemName() {

return this.class.simpleName
}

/**
* Initialize any resources for the running of the system here.
*/
protected void init() {
}

/**
* Enter the loop for the system to continually work on the scene.
*/
protected abstract void processLoop()

/**
* Execute an action and optionally wait such that, if repeated, it would run
* no faster than the given frequency.
Expand All @@ -68,6 +92,26 @@ abstract class EngineSystem implements Runnable, EventTarget {
}
}

/**
* Controlled initialization, execution loop, and shutdown or an engine
* system.
*/
@Override
final void run() {

logger.debug('{}: starting', systemName)
init()
trigger(new EngineSystemReadyEvent())

logger.debug('{}: in loop', systemName)
processLoop()

logger.debug('{}: shutting down', systemName)
trigger(new EngineSystemStoppedEvent())
shutdown()
logger.debug('{}: stopped', systemName)
}

/**
* Set the engine this system is a part of.
*/
Expand All @@ -86,4 +130,10 @@ abstract class EngineSystem implements Runnable, EventTarget {
this.scene = scene
configureScene()
}

/**
* Cleanup/free any resources created by the system here.
*/
protected void shutdown() {
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,6 @@ package nz.net.ultraq.redhorizon.engine.audio

import nz.net.ultraq.redhorizon.engine.EngineStats
import nz.net.ultraq.redhorizon.engine.EngineSystem
import nz.net.ultraq.redhorizon.engine.EngineSystemReadyEvent
import nz.net.ultraq.redhorizon.engine.EngineSystemStoppedEvent
import nz.net.ultraq.redhorizon.engine.audio.openal.OpenALContext
import nz.net.ultraq.redhorizon.engine.audio.openal.OpenALRenderer
import nz.net.ultraq.redhorizon.engine.scenegraph.AudioElement
Expand All @@ -34,7 +32,7 @@ import java.util.concurrent.LinkedBlockingQueue

/**
* Audio system, manages the connection to the audio hardware and playback of
* audio objects.
* audio objects in the scene.
*
* @author Emanuel Rabina
*/
Expand All @@ -47,6 +45,9 @@ class AudioSystem extends EngineSystem implements AudioRequests {
private final BlockingQueue<Tuple2<AudioResource, CompletableFuture<Void>>> deletionRequests = new LinkedBlockingQueue<>()
private final List<Node> queryResults = []

private OpenALContext context
private OpenALRenderer renderer

/**
* Constructor, build a new engine for rendering audio.
*/
Expand All @@ -61,6 +62,48 @@ class AudioSystem extends EngineSystem implements AudioRequests {
scene.audioRequestsHandler = this
}

@Override
protected void init() {

context = new OpenALContext()
context.withCurrent { ->
renderer = new OpenALRenderer(config)
logger.debug(renderer.toString())
EngineStats.instance.attachAudioRenderer(renderer)
}
}

@Override
protected void processLoop() {

context.withCurrent { ->
while (!Thread.interrupted()) {
try {
rateLimit(100) { ->
processRequests(renderer)

// Run the audio elements
// TODO: Split this out like the graphics system where we wait to
// be told to process audio objects instead of looping
// through the scene ourselves
if (scene?.listener) {
scene.listener.render(renderer)
queryResults.clear()
scene.query(scene.listener.range, queryResults).each { node ->
if (node instanceof AudioElement) {
node.render(renderer)
}
}
}
}
}
catch (InterruptedException ignored) {
break
}
}
}
}

/**
* Run through all of the queued requests for the creation and deletion of
* graphics resources.
Expand Down Expand Up @@ -106,59 +149,12 @@ class AudioSystem extends EngineSystem implements AudioRequests {
})
}

/**
* Starts the audio engine loop: builds a connection to the OpenAL device,
* renders audio items found within the current scene, cleaning it all up when
* made to shut down.
*/
@Override
void run() {

logger.debug('Starting audio system')

// Initialization
new OpenALContext().withCloseable { context ->
context.withCurrent { ->
new OpenALRenderer(config).withCloseable { renderer ->
logger.debug(renderer.toString())
EngineStats.instance.attachAudioRenderer(renderer)

trigger(new EngineSystemReadyEvent())

// Rendering loop
logger.debug('Audio system in render loop...')
while (!Thread.interrupted()) {
try {
rateLimit(100) { ->

processRequests(renderer)

// Run the audio elements
// TODO: Split this out like the graphics system where we wait to
// be told to process audio objects instead of looping
// through the scene ourselves
if (scene?.listener) {
scene.listener.render(renderer)
queryResults.clear()
scene.query(scene.listener.range, queryResults).each { node ->
if (node instanceof AudioElement) {
node.render(renderer)
}
}
}
}
}
catch (InterruptedException ignored) {
break
}
}
}
protected void shutdown() {

// Shutdown
logger.debug('Shutting down audio system')
}
context.withCurrent { ->
renderer.close()
}
trigger(new EngineSystemStoppedEvent())
logger.debug('Audio system stopped')
context.close()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,6 @@ package nz.net.ultraq.redhorizon.engine.game

import nz.net.ultraq.redhorizon.engine.EngineStats
import nz.net.ultraq.redhorizon.engine.EngineSystem
import nz.net.ultraq.redhorizon.engine.EngineSystemReadyEvent
import nz.net.ultraq.redhorizon.engine.EngineSystemStoppedEvent
import nz.net.ultraq.redhorizon.engine.graphics.GraphicsSystem

import org.slf4j.Logger
Expand All @@ -35,6 +33,7 @@ class GameLogicSystem extends EngineSystem {

private static final Logger logger = LoggerFactory.getLogger(GameLogicSystem)

private GraphicsSystem graphicsSystem
private long lastUpdateTimeMs

@Override
Expand All @@ -44,17 +43,14 @@ class GameLogicSystem extends EngineSystem {
}

@Override
void run() {
protected void init() {

logger.debug('Starting game logic system')
graphicsSystem = (GraphicsSystem)engine.systems.find { system -> system instanceof GraphicsSystem }
}

// Initialization
// TODO: These phases could probably live in the parent EngineSystem class
var graphicsSystem = (GraphicsSystem)engine.systems.find { system -> system instanceof GraphicsSystem }
trigger(new EngineSystemReadyEvent())
@Override
void processLoop() {

// Game loop
logger.debug('Game logic system in loop...')
while (!Thread.interrupted()) {
try {
var currentTimeMs = System.currentTimeMillis()
Expand All @@ -71,11 +67,5 @@ class GameLogicSystem extends EngineSystem {
break
}
}

// Shutdown
logger.debug('Shutting down game logic system')

trigger(new EngineSystemStoppedEvent())
logger.debug('Game logic system stopped')
}
}
Loading

0 comments on commit 3c8fc40

Please sign in to comment.