Refactored subsystems for cleaner modularity.

v5stable
Ondřej Hruška 10 years ago
parent e2e5576664
commit 6013a105ad
  1. 89
      src/mightypork/rogue/App.java
  2. 40
      src/mightypork/rogue/AppAccess.java
  3. 209
      src/mightypork/rogue/AppSubsystem.java
  4. 47
      src/mightypork/rogue/display/DisplaySystem.java
  5. 119
      src/mightypork/rogue/display/Screen.java
  6. 91
      src/mightypork/rogue/display/ScreenTestAnimations.java
  7. 8
      src/mightypork/rogue/display/constraints/ConstraintContext.java
  8. 33
      src/mightypork/rogue/display/events/UpdateEvent.java
  9. 1
      src/mightypork/rogue/fonts/Align.java
  10. 1
      src/mightypork/rogue/fonts/Fonts.java
  11. 81
      src/mightypork/rogue/input/InputSystem.java
  12. 2
      src/mightypork/rogue/sounds/BaseAudioPlayer.java
  13. 17
      src/mightypork/rogue/sounds/NullAudio.java
  14. 88
      src/mightypork/rogue/sounds/SoundSystem.java
  15. 6
      src/mightypork/rogue/tasks/TaskTakeScreenshot.java
  16. 2
      src/mightypork/rogue/textures/Textures.java
  17. 1
      src/mightypork/rogue/textures/Tx.java
  18. 2
      src/mightypork/utils/objects/VarargsParser.java
  19. 15
      src/mightypork/utils/patterns/Initializable.java
  20. 20
      src/mightypork/utils/patterns/subscription/MessageBus.java

@ -10,6 +10,7 @@ import javax.swing.JOptionPane;
import mightypork.rogue.display.DisplaySystem;
import mightypork.rogue.display.Screen;
import mightypork.rogue.display.ScreenTestAnimations;
import mightypork.rogue.display.events.UpdateEvent;
import mightypork.rogue.input.InputSystem;
import mightypork.rogue.input.KeyStroke;
import mightypork.rogue.sounds.SoundSystem;
@ -20,12 +21,11 @@ import mightypork.utils.logging.LogInstance;
import mightypork.utils.patterns.Destroyable;
import mightypork.utils.patterns.subscription.MessageBus;
import mightypork.utils.time.TimerDelta;
import mightypork.utils.time.TimerInterpolating;
import org.lwjgl.input.Keyboard;
public class App implements Destroyable {
public class App implements Destroyable, AppAccess {
/** instance pointer */
private static App inst;
@ -42,17 +42,6 @@ public class App implements Destroyable {
private boolean scheduledScreenshot = false;
/**
* Get the instance
*
* @return instance of App
*/
public static App inst()
{
return inst;
}
/**
* @param args
*/
@ -80,7 +69,7 @@ public class App implements Destroyable {
{
Log.e("The game has crashed.", error);
inst.exit();
if (inst != null) inst.exit();
}
@ -95,17 +84,6 @@ public class App implements Destroyable {
}
/**
* Get current screen
*
* @return screen
*/
public Screen getCurrentScreen()
{
return screen;
}
public void initialize()
{
Log.i("Initializing subsystems");
@ -188,6 +166,8 @@ public class App implements Destroyable {
{
events = new MessageBus();
events.addSubscriber(this);
events.createChannel(UpdateEvent.class, UpdateEvent.Listener.class);
}
@ -196,7 +176,7 @@ public class App implements Destroyable {
*/
private void initSound()
{
sounds = new SoundSystem();
sounds = new SoundSystem(this);
sounds.setMasterVolume(1);
}
@ -206,7 +186,7 @@ public class App implements Destroyable {
*/
private void initInput()
{
input = new InputSystem();
input = new InputSystem(this);
input.bindKeyStroke(new KeyStroke(Keyboard.KEY_F2), new Runnable() {
@ -245,7 +225,7 @@ public class App implements Destroyable {
*/
private void initDisplay()
{
display = new DisplaySystem();
display = new DisplaySystem(this);
display.createMainWindow(Const.WINDOW_W, Const.WINDOW_H, true, Config.START_IN_FS, Const.TITLEBAR);
display.setTargetFps(Const.FPS_RENDER);
}
@ -275,8 +255,7 @@ public class App implements Destroyable {
private void mainLoop()
{
screen = new ScreenTestAnimations();
screen = new ScreenTestAnimations(this);
screen.setActive(true);
timerRender = new TimerDelta();
@ -284,14 +263,7 @@ public class App implements Destroyable {
while (!display.isCloseRequested()) {
display.beginFrame();
input.poll();
double delta = timerRender.getDelta();
sounds.update(delta);
// Screen
screen.update(delta);
events.broadcast(new UpdateEvent(timerRender.getDelta()));
if (scheduledScreenshot) {
takeScreenshot();
@ -309,7 +281,7 @@ public class App implements Destroyable {
public void takeScreenshot()
{
sounds.getEffect("gui.shutter").play(1);
Utils.runAsThread(new TaskTakeScreenshot());
Utils.runAsThread(new TaskTakeScreenshot(display));
}
@ -320,53 +292,40 @@ public class App implements Destroyable {
/**
* @return sound system of the running instance
*/
public static SoundSystem soundsys()
@Override
public SoundSystem soundsys()
{
return inst.sounds;
return sounds;
}
/**
* @return input system of the running instance
*/
public static InputSystem input()
@Override
public InputSystem input()
{
return inst.input;
return input;
}
/**
* @return display system of the running instance
*/
public static DisplaySystem disp()
{
return inst.display;
}
/**
* @return event bus of the running instance
*/
public static MessageBus msgbus()
@Override
public DisplaySystem disp()
{
return inst.events;
return display;
}
/**
* @return screen of the running instance
* @return event bus
*/
public static Screen screen()
{
return inst.getCurrentScreen();
}
public static boolean broadcast(Object message)
@Override
public MessageBus msgbus()
{
boolean was = msgbus().broadcast(message);
if (!was) Log.w("Message not accepted by any channel: " + message);
return was;
return events;
}
}

@ -0,0 +1,40 @@
package mightypork.rogue;
import mightypork.rogue.display.DisplaySystem;
import mightypork.rogue.input.InputSystem;
import mightypork.rogue.sounds.SoundSystem;
import mightypork.utils.patterns.subscription.MessageBus;
/**
* App interface visible to subsystems
*
* @author MightyPork
*/
public interface AppAccess {
/**
* @return sound system
*/
abstract SoundSystem soundsys();
/**
* @return input system
*/
abstract InputSystem input();
/**
* @return display system
*/
abstract DisplaySystem disp();
/**
* @return event bus
*/
abstract MessageBus msgbus();
}

@ -0,0 +1,209 @@
package mightypork.rogue;
import java.util.HashSet;
import java.util.Set;
import mightypork.rogue.display.DisplaySystem;
import mightypork.rogue.display.events.UpdateEvent;
import mightypork.rogue.input.InputSystem;
import mightypork.rogue.sounds.SoundSystem;
import mightypork.utils.logging.Log;
import mightypork.utils.patterns.Destroyable;
import mightypork.utils.patterns.subscription.MessageBus;
import mightypork.utils.time.Updateable;
public abstract class AppSubsystem implements AppAccess, UpdateEvent.Listener, Updateable, Destroyable {
private AppAccess app;
private boolean wantUpdates;
private boolean destroyed = false;
/** Subsystem children subscribing to MessageBus */
private Set<Object> childSubscribers = new HashSet<Object>();
/**
* Create a subsystem
*
* @param app app instance access
* @param joinBus whether to initially join msgbus
*/
public AppSubsystem(AppAccess app, boolean joinBus) {
this.app = app;
// add to subscriber group
childSubscribers.add(this);
enableEvents(joinBus);
enableUpdates(true);
init();
}
/**
* Set whether events should be received.<br>
* This includes {@link UpdateEvent}, so disabling events also disables
* updates.
*
* @param enable
*/
protected final void enableEvents(boolean enable)
{
assertLive();
// this & child subscribers
for (Object o : childSubscribers) {
if (enable) {
app.msgbus().addSubscriber(o);
} else {
app.msgbus().removeSubscriber(o);
}
}
}
/**
* Set whether to receive {@link UpdateEvent}s (delta timing, one each
* frame).<br>
*
* @param enable
*/
protected final void enableUpdates(boolean enable)
{
assertLive();
wantUpdates = enable;
}
@Override
public final void receive(UpdateEvent event)
{
assertLive();
if (wantUpdates) update(event.getDeltaTime());
}
// /**
// * @return app instance
// */
// protected AppAccess app()
// {
// assertLive();
//
// return app;
// }
@Override
public void update(double delta)
{
Log.w("Subsystem " + getClass().getSimpleName() + " receives updates, but does not override the update() method.");
}
/**
* Initialize the subsystem<br>
* (called during construction)
*/
protected abstract void init();
/**
* Deinitialize the subsystem<br>
* (called during destruction)<br>
* <br>
* All child eventbus subscribers will be removed from the eventbus.
*/
protected abstract void deinit();
/**
* Add a child subscriber to the {@link MessageBus}.<br>
* Child subscribers are removed when subsystem is destroyed, and can be
* connected/disconnected using the <code>enableEvents()</code> method.
*
* @param client
* @return true on success
*/
public final boolean addChildSubscriber(Object client)
{
assertLive();
if (client == null) return false;
msgbus().addSubscriber(client);
childSubscribers.add(client);
return true;
}
public final void removeChildSubscriber(Object client)
{
assertLive();
childSubscribers.remove(client);
msgbus().removeSubscriber(client);
}
@Override
public final void destroy()
{
assertLive();
deinit();
enableEvents(false); // remove all subscribers from bus
app = null;
destroyed = true;
}
@Override
public MessageBus msgbus()
{
assertLive();
return app.msgbus();
}
@Override
public SoundSystem soundsys()
{
assertLive();
return app.soundsys();
}
@Override
public InputSystem input()
{
assertLive();
return app.input();
}
@Override
public DisplaySystem disp()
{
assertLive();
return app.disp();
}
private void assertLive()
{
if (destroyed) throw new IllegalStateException("Subsystem already destroyed.");
}
}

@ -6,12 +6,13 @@ import static org.lwjgl.opengl.GL11.*;
import java.awt.image.BufferedImage;
import java.nio.ByteBuffer;
import mightypork.rogue.App;
import mightypork.rogue.AppAccess;
import mightypork.rogue.AppSubsystem;
import mightypork.rogue.display.constraints.ConstraintContext;
import mightypork.rogue.display.events.ScreenChangeEvent;
import mightypork.utils.logging.Log;
import mightypork.utils.math.coord.Coord;
import mightypork.utils.patterns.Destroyable;
import mightypork.utils.patterns.Initializable;
import mightypork.utils.math.coord.Rect;
import org.lwjgl.BufferUtils;
import org.lwjgl.LWJGLException;
@ -19,27 +20,29 @@ import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.DisplayMode;
public class DisplaySystem implements Initializable, Destroyable {
private boolean initialized;
public class DisplaySystem extends AppSubsystem implements ConstraintContext {
private DisplayMode windowDisplayMode;
private int targetFps;
public DisplaySystem() {
initialize();
public DisplaySystem(AppAccess app) {
super(app, true);
enableUpdates(false);
}
@Override
public void initialize()
protected void init()
{
if (initialized) return;
initChannels();
}
initialized = true;
@Override
public void deinit()
{
Display.destroy();
}
@ -48,14 +51,7 @@ public class DisplaySystem implements Initializable, Destroyable {
*/
private void initChannels()
{
App.msgbus().registerMessageType(ScreenChangeEvent.class, ScreenChangeEvent.Listener.class);
}
@Override
public void destroy()
{
Display.destroy();
msgbus().createChannel(ScreenChangeEvent.class, ScreenChangeEvent.Listener.class);
}
@ -105,7 +101,7 @@ public class DisplaySystem implements Initializable, Destroyable {
Display.update();
}
App.broadcast(new ScreenChangeEvent(true, Display.isFullscreen(), getSize()));
msgbus().broadcast(new ScreenChangeEvent(true, Display.isFullscreen(), getSize()));
} catch (Throwable t) {
Log.e("Failed to toggle fullscreen mode.", t);
@ -182,7 +178,7 @@ public class DisplaySystem implements Initializable, Destroyable {
public void beginFrame()
{
if (Display.wasResized()) {
App.broadcast(new ScreenChangeEvent(false, Display.isFullscreen(), getSize()));
msgbus().broadcast(new ScreenChangeEvent(false, Display.isFullscreen(), getSize()));
}
glLoadIdentity();
@ -198,4 +194,11 @@ public class DisplaySystem implements Initializable, Destroyable {
Display.update(false); // don't poll input devices
Display.sync(targetFps);
}
@Override
public Rect getRect()
{
return new Rect(getSize());
}
}

@ -2,17 +2,15 @@ package mightypork.rogue.display;
import static org.lwjgl.opengl.GL11.*;
import mightypork.rogue.App;
import mightypork.rogue.AppAccess;
import mightypork.rogue.AppSubsystem;
import mightypork.rogue.display.constraints.ConstraintContext;
import mightypork.rogue.display.events.ScreenChangeEvent;
import mightypork.rogue.input.KeyBinder;
import mightypork.rogue.input.KeyBindingPool;
import mightypork.rogue.input.KeyStroke;
import mightypork.rogue.input.events.KeyboardEvent;
import mightypork.rogue.input.events.MouseButtonEvent;
import mightypork.rogue.input.events.MouseMotionEvent;
import mightypork.utils.math.coord.Coord;
import mightypork.utils.patterns.Initializable;
import mightypork.utils.time.Updateable;
import mightypork.utils.math.coord.Rect;
/**
@ -22,27 +20,27 @@ import mightypork.utils.time.Updateable;
*
* @author MightyPork
*/
public abstract class Screen implements KeyBinder, Updateable, Initializable, KeyboardEvent.Listener, MouseMotionEvent.Listener, MouseButtonEvent.Listener, ScreenChangeEvent.Listener {
public abstract class Screen extends AppSubsystem implements KeyBinder, ConstraintContext, ScreenChangeEvent.Listener {
private KeyBindingPool keybindings = new KeyBindingPool();
private KeyBindingPool keybindings;
private boolean active;
public Screen() {
initialize();
public Screen(AppAccess app) {
super(app, false);
}
@Override
public void bindKeyStroke(KeyStroke stroke, Runnable task)
public final void bindKeyStroke(KeyStroke stroke, Runnable task)
{
keybindings.bindKeyStroke(stroke, task);
}
@Override
public void unbindKeyStroke(KeyStroke stroke)
public final void unbindKeyStroke(KeyStroke stroke)
{
keybindings.unbindKeyStroke(stroke);
}
@ -59,13 +57,19 @@ public abstract class Screen implements KeyBinder, Updateable, Initializable, Ke
active = true;
setupGraphics();
setupViewport();
onSizeChanged(App.disp().getSize());
onEnter();
App.msgbus().addSubscriber(this);
onSizeChanged(getRect().getSize());
onScreenEnter();
// subscribe to event bus
enableEvents(true);
} else {
onScreenLeave();
active = false;
onLeave();
App.msgbus().removeSubscriber(this);
// unsusbcribe from event bus
enableEvents(false);
}
}
@ -99,7 +103,7 @@ public abstract class Screen implements KeyBinder, Updateable, Initializable, Ke
// fix projection for changed size
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
Coord s = App.disp().getSize();
Coord s = disp().getSize();
glViewport(0, 0, s.xi(), s.yi());
glOrtho(0, s.x, 0, s.y, -1000, 1000);
@ -108,25 +112,47 @@ public abstract class Screen implements KeyBinder, Updateable, Initializable, Ke
}
@Override
protected final void init()
{
keybindings = new KeyBindingPool();
addChildSubscriber(keybindings);
initScreen();
}
@Override
protected final void deinit()
{
deinitScreen();
}
/**
* Initialize screen layout and key bindings.<br>
* Called when the screen is created, not when it comes to front. For that,
* use onEnter().
* Called during screen construction.
*/
@Override
public abstract void initialize();
protected abstract void initScreen();
/**
* Clean up before screen is destroyed.
*/
protected abstract void deinitScreen();
/**
* Called when the screen becomes active
*/
protected abstract void onEnter();
protected abstract void onScreenEnter();
/**
* Called when the screen is no longer active
*/
protected abstract void onLeave();
protected abstract void onScreenLeave();
/**
@ -134,7 +160,10 @@ public abstract class Screen implements KeyBinder, Updateable, Initializable, Ke
*
* @param size screen size
*/
protected abstract void onSizeChanged(Coord size);
protected void onSizeChanged(Coord size)
{
// no impl
}
/**
@ -154,7 +183,7 @@ public abstract class Screen implements KeyBinder, Updateable, Initializable, Ke
/**
* Render screen
*/
private final void renderBegin()
private void renderBegin()
{
glPushAttrib(GL_ENABLE_BIT);
glPushMatrix();
@ -164,32 +193,17 @@ public abstract class Screen implements KeyBinder, Updateable, Initializable, Ke
/**
* Render screen
*/
private final void renderEnd()
private void renderEnd()
{
glPopAttrib();
glPopMatrix();
}
/**
* Update and render the screen
*/
@Override
public final void update(double delta)
{
if (!isActive()) return;
updateScreen(delta);
renderBegin();
renderScreen();
renderEnd();
};
/**
* @return true if screen is the curretn screen
*/
protected final boolean isActive()
public final boolean isActive()
{
return active;
}
@ -206,11 +220,24 @@ public abstract class Screen implements KeyBinder, Updateable, Initializable, Ke
}
/**
* Update and render the screen
*/
@Override
public final void update(double delta)
{
updateScreen(delta);
renderBegin();
renderScreen();
renderEnd();
}
@Override
public final void receive(KeyboardEvent event)
public final Rect getRect()
{
if (!isActive()) return;
keybindings.receive(event);
return disp().getRect();
}
}

@ -3,10 +3,9 @@ package mightypork.rogue.display;
import java.util.Random;
import mightypork.rogue.App;
import mightypork.rogue.AppAccess;
import mightypork.rogue.input.KeyStroke;
import mightypork.rogue.input.events.MouseButtonEvent;
import mightypork.rogue.input.events.MouseMotionEvent;
import mightypork.rogue.util.RenderUtils;
import mightypork.utils.math.Polar;
import mightypork.utils.math.color.RGB;
@ -19,8 +18,12 @@ import org.lwjgl.input.Keyboard;
import org.lwjgl.opengl.Display;
public class ScreenTestAnimations extends Screen {
public class ScreenTestAnimations extends Screen implements MouseButtonEvent.Listener {
public ScreenTestAnimations(AppAccess app) {
super(app);
}
private Random rand = new Random();
private AnimDoubleDeg degAnim = new AnimDoubleDeg(0, Easing.ELASTIC_OUT);
@ -94,7 +97,7 @@ public class ScreenTestAnimations extends Screen {
//@formatter:on
@Override
public void initialize()
public void initScreen()
{
bindKeyStroke(new KeyStroke(Keyboard.KEY_RIGHT), new Runnable() {
@ -102,7 +105,7 @@ public class ScreenTestAnimations extends Screen {
public void run()
{
for (AnimDouble a : anims) {
a.animate(0, 1, 1+rand.nextDouble()*1);
a.animate(0, 1, 1 + rand.nextDouble() * 1);
}
}
});
@ -113,7 +116,7 @@ public class ScreenTestAnimations extends Screen {
public void run()
{
for (AnimDouble a : anims) {
a.animate(1, 0, 1+rand.nextDouble()*1);
a.animate(1, 0, 1 + rand.nextDouble() * 1);
}
}
});
@ -121,79 +124,69 @@ public class ScreenTestAnimations extends Screen {
@Override
protected void renderScreen()
protected void deinitScreen()
{
double screenH = Display.getHeight();
double screenW = Display.getWidth();
double perBoxH = screenH / anims.length;
double padding = perBoxH * 0.1;
double boxSide = perBoxH - padding * 2;
for (int i = 0; i < anims.length; i++) {
AnimDouble a = anims[i];
RenderUtils.setColor(RGB.GREEN);
RenderUtils.quadSize(padding + a.getCurrentValue() * (screenW - perBoxH), screenH - perBoxH * i - perBoxH + padding, boxSide, boxSide);
}
RenderUtils.setColor(RGB.YELLOW);
RenderUtils.translate(new Coord(Display.getWidth() / 2, Display.getHeight() / 2));
RenderUtils.rotateZ(degAnim.getCurrentValue());
RenderUtils.quadSize(-10, -10, 20, 200);
// no impl
}
@Override
public void receive(MouseMotionEvent event)
protected void onScreenEnter()
{
//
// no impl
}
@Override
public void receive(MouseButtonEvent event)
protected void onScreenLeave()
{
if (event.isDown()) {
Coord vec = App.disp().getSize().half().vecTo(event.getPos());
Polar p = Polar.fromCoord(vec);
degAnim.fadeTo(p.getAngleDeg() - 90, 1.5);
}
// no impl
}
@Override
protected void onEnter()
protected void updateScreen(double delta)
{
// TODO Auto-generated method stub
degAnim.update(delta);
for (AnimDouble a : anims) {
a.update(delta);
}
}
@Override
protected void onLeave()
protected void renderScreen()
{
// TODO Auto-generated method stub
}
double screenH = Display.getHeight();
double screenW = Display.getWidth();
double perBoxH = screenH / anims.length;
double padding = perBoxH * 0.1;
double boxSide = perBoxH - padding * 2;
for (int i = 0; i < anims.length; i++) {
AnimDouble a = anims[i];
@Override
protected void onSizeChanged(Coord size)
{
// TODO Auto-generated method stub
RenderUtils.setColor(RGB.GREEN);
RenderUtils.quadSize(padding + a.getCurrentValue() * (screenW - perBoxH), screenH - perBoxH * i - perBoxH + padding, boxSide, boxSide);
}
RenderUtils.setColor(RGB.YELLOW);
RenderUtils.translate(new Coord(Display.getWidth() / 2, Display.getHeight() / 2));
RenderUtils.rotateZ(degAnim.getCurrentValue());
RenderUtils.quadSize(-10, -10, 20, 200);
}
@Override
protected void updateScreen(double delta)
public void receive(MouseButtonEvent event)
{
degAnim.update(delta);
if (event.isDown()) {
Coord vec = disp().getSize().half().vecTo(event.getPos());
for (AnimDouble a : anims) {
a.update(delta);
Polar p = Polar.fromCoord(vec);
degAnim.fadeTo(p.getAngleDeg() - 90, 1.5);
}
}

@ -4,7 +4,15 @@ package mightypork.rogue.display.constraints;
import mightypork.utils.math.coord.Rect;
/**
* Constraints can be based on this
*
* @author MightyPork
*/
public interface ConstraintContext {
/**
* @return bounding rectangle
*/
public Rect getRect();
}

@ -0,0 +1,33 @@
package mightypork.rogue.display.events;
import mightypork.utils.patterns.subscription.Handleable;
public class UpdateEvent implements Handleable<UpdateEvent.Listener> {
private final double deltaTime;
public UpdateEvent(double deltaTime) {
this.deltaTime = deltaTime;
}
public double getDeltaTime()
{
return deltaTime;
}
@Override
public void handleBy(Listener handler)
{
handler.receive(this);
}
public interface Listener {
public void receive(UpdateEvent event);
}
}

@ -6,7 +6,6 @@ package mightypork.rogue.fonts;
*
* @author MightyPork
*/
@SuppressWarnings("javadoc")
public class Align {
public static final int LEFT = -1;

@ -11,7 +11,6 @@ import mightypork.utils.logging.Log;
*
* @author Rapus
*/
@SuppressWarnings("javadoc")
public class Fonts {
public static LoadedFont splash_info;

@ -1,13 +1,12 @@
package mightypork.rogue.input;
import mightypork.rogue.App;
import mightypork.rogue.AppAccess;
import mightypork.rogue.AppSubsystem;
import mightypork.rogue.input.events.KeyboardEvent;
import mightypork.rogue.input.events.MouseButtonEvent;
import mightypork.rogue.input.events.MouseMotionEvent;
import mightypork.utils.math.coord.Coord;
import mightypork.utils.patterns.Destroyable;
import mightypork.utils.patterns.Initializable;
import org.lwjgl.LWJGLException;
import org.lwjgl.input.Keyboard;
@ -15,31 +14,35 @@ import org.lwjgl.input.Mouse;
import org.lwjgl.opengl.Display;
public class InputSystem implements KeyBinder, Destroyable, Initializable {
private boolean initialized;
public class InputSystem extends AppSubsystem implements KeyBinder {
// listeners
private KeyBindingPool keybindings;
public InputSystem() {
initialize();
public InputSystem(AppAccess app) {
super(app, true);
}
@Override
public void initialize()
protected void init()
{
if (initialized) return;
initDevices();
initChannels();
// global keybindings
keybindings = new KeyBindingPool();
addChildSubscriber(keybindings);
}
App.msgbus().addSubscriber(keybindings);
@Override
public void deinit()
{
Mouse.destroy();
Keyboard.destroy();
}
@ -57,17 +60,9 @@ public class InputSystem implements KeyBinder, Destroyable, Initializable {
private void initChannels()
{
App.msgbus().registerMessageType(KeyboardEvent.class, KeyboardEvent.Listener.class);
App.msgbus().registerMessageType(MouseMotionEvent.class, MouseMotionEvent.Listener.class);
App.msgbus().registerMessageType(MouseButtonEvent.class, MouseButtonEvent.Listener.class);
}
@Override
public void destroy()
{
Mouse.destroy();
Keyboard.destroy();
msgbus().createChannel(KeyboardEvent.class, KeyboardEvent.Listener.class);
msgbus().createChannel(MouseMotionEvent.class, MouseMotionEvent.Listener.class);
msgbus().createChannel(MouseButtonEvent.class, MouseButtonEvent.Listener.class);
}
@ -85,25 +80,6 @@ public class InputSystem implements KeyBinder, Destroyable, Initializable {
}
/**
* Update inputs
*/
public final void poll()
{
Display.processMessages(); // redundant if Display.update() is called in main loop
Mouse.poll();
Keyboard.poll();
while (Mouse.next()) {
onMouseEvent();
}
while (Keyboard.next()) {
onKeyEvent();
}
}
private void onMouseEvent()
{
int button = Mouse.getEventButton();
@ -112,8 +88,8 @@ public class InputSystem implements KeyBinder, Destroyable, Initializable {
Coord move = new Coord(Mouse.getEventDX(), Mouse.getEventDY());
int wheeld = Mouse.getEventDWheel();
if (button != -1 || wheeld != 0) App.broadcast(new MouseButtonEvent(pos, button, down, wheeld));
if (!move.isZero()) App.broadcast(new MouseMotionEvent(pos, move));
if (button != -1 || wheeld != 0) msgbus().broadcast(new MouseButtonEvent(pos, button, down, wheeld));
if (!move.isZero()) msgbus().broadcast(new MouseMotionEvent(pos, move));
}
@ -122,6 +98,21 @@ public class InputSystem implements KeyBinder, Destroyable, Initializable {
int key = Keyboard.getEventKey();
boolean down = Keyboard.getEventKeyState();
char c = Keyboard.getEventCharacter();
App.broadcast(new KeyboardEvent(key, c, down));
msgbus().broadcast(new KeyboardEvent(key, c, down));
}
@Override
public void update(double delta)
{
Display.processMessages(); // redundant if Display.update() is called in main loop
while (Mouse.next()) {
onMouseEvent();
}
while (Keyboard.next()) {
onKeyEvent();
}
}
}

@ -30,6 +30,8 @@ public abstract class BaseAudioPlayer {
this.baseGain = baseGain;
this.basePitch = basePitch;
if (gainMultiplier == null) gainMultiplier = new Mutable<Double>(1D);
this.gainMultiplier = gainMultiplier;
}

@ -0,0 +1,17 @@
package mightypork.rogue.sounds;
public class NullAudio extends AudioX {
public NullAudio() {
super("");
}
@Override
public boolean load()
{
return false;
}
}

@ -7,11 +7,12 @@ import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import mightypork.rogue.AppAccess;
import mightypork.rogue.AppSubsystem;
import mightypork.utils.logging.Log;
import mightypork.utils.math.Calc.Buffers;
import mightypork.utils.math.coord.Coord;
import mightypork.utils.objects.Mutable;
import mightypork.utils.patterns.Destroyable;
import mightypork.utils.time.Updateable;
import org.lwjgl.openal.AL;
import org.lwjgl.openal.AL10;
@ -24,13 +25,13 @@ import org.newdawn.slick.openal.SoundStore;
* @author MightyPork
*/
@SuppressWarnings("unchecked")
// needed for JointVolume
public class SoundSystem implements Updateable, Destroyable {
// static
public class SoundSystem extends AppSubsystem {
private static final Coord INITIAL_LISTENER_POS = new Coord(0, 0, 0);
private static final int MAX_SOURCES = 256;
private static final AudioX NO_SOUND = new NullAudio();
private static final LoopPlayer NULL_LOOP = new LoopPlayer(NO_SOUND, 0, 0, null);
private static final EffectPlayer NULL_EFFECT = new EffectPlayer(NO_SOUND, 0, 0, null);
private static Coord listener = new Coord();
@ -65,13 +66,7 @@ public class SoundSystem implements Updateable, Destroyable {
buf3 = buf6 = null;
}
public static Coord getListener()
{
return listener;
}
// instance
// -- instance --
public Mutable<Double> masterVolume = new Mutable<Double>(1D);
public Mutable<Double> effectsVolume = new JointVolume(masterVolume);
@ -82,6 +77,45 @@ public class SoundSystem implements Updateable, Destroyable {
private Set<AudioX> resources = new HashSet<AudioX>();
public SoundSystem(AppAccess app) {
super(app, true);
}
@Override
protected void init()
{
// empty
}
@Override
public void deinit()
{
for (AudioX r : resources) {
r.destroy();
}
SoundStore.get().clear();
AL.destroy();
}
@Override
public void update(double delta)
{
for (LoopPlayer lp : loops.values()) {
lp.update(delta);
}
}
public static Coord getListener()
{
return listener;
}
/**
* Register effect resource
*
@ -141,7 +175,8 @@ public class SoundSystem implements Updateable, Destroyable {
{
LoopPlayer p = loops.get(key);
if (p == null) {
throw new IllegalArgumentException("Requesting unknown sound loop \"" + key + "\".");
Log.w("Requesting unknown sound loop \"" + key + "\".");
return NULL_LOOP;
}
return p;
}
@ -157,7 +192,8 @@ public class SoundSystem implements Updateable, Destroyable {
{
EffectPlayer p = effects.get(key);
if (p == null) {
throw new IllegalArgumentException("Requesting unknown sound effect \"" + key + "\".");
Log.w("Requesting unknown sound effect \"" + key + "\".");
return NULL_EFFECT;
}
return p;
}
@ -253,15 +289,6 @@ public class SoundSystem implements Updateable, Destroyable {
}
@Override
public void update(double delta)
{
for (LoopPlayer lp : loops.values()) {
lp.update(delta);
}
}
/**
* Set level of master volume
*
@ -293,17 +320,4 @@ public class SoundSystem implements Updateable, Destroyable {
{
loopsVolume.set(d);
}
@Override
public void destroy()
{
for (AudioX r : resources) {
r.destroy();
}
SoundStore.get().clear();
AL.destroy();
}
}

@ -10,8 +10,8 @@ import java.util.Date;
import javax.imageio.ImageIO;
import mightypork.rogue.App;
import mightypork.rogue.Paths;
import mightypork.rogue.display.DisplaySystem;
import mightypork.utils.logging.Log;
@ -20,8 +20,8 @@ public class TaskTakeScreenshot implements Runnable {
private BufferedImage image;
public TaskTakeScreenshot() {
this.image = App.disp().takeScreenshot();
public TaskTakeScreenshot(DisplaySystem disp) {
this.image = disp.takeScreenshot();
}

@ -11,8 +11,6 @@ import org.newdawn.slick.opengl.Texture;
*
* @author MightyPork
*/
@SuppressWarnings("javadoc")
// unrelevant
public class Textures {
protected static Texture buttons_menu;

@ -6,7 +6,6 @@ package mightypork.rogue.textures;
*
* @author MightyPork
*/
@SuppressWarnings("javadoc")
public class Tx {
// logo

@ -16,6 +16,8 @@ import java.util.Map;
*
*
*
*
*
* Object[] array = { &quot;one&quot;, 1, &quot;two&quot;, 4, &quot;three&quot;, 9, &quot;four&quot;, 16 };
* Map&lt;String, Integer&gt; args = new VarargsParser&lt;String, Integer&gt;().parse(array);
* </pre>

@ -1,15 +0,0 @@
package mightypork.utils.patterns;
/**
* Object that can be initialized
*
* @author MightyPork
*/
public interface Initializable {
/**
* Initialize if not initialized yet
*/
public void initialize();
}

@ -16,6 +16,7 @@ public class MessageBus implements Subscribable {
private Set<MessageChannel<?, ?>> channels = new LinkedHashSet<MessageChannel<?, ?>>();
private Set<Object> clients = new LinkedHashSet<Object>();
private boolean warn_unsent = true;
/**
@ -72,6 +73,8 @@ public class MessageBus implements Subscribable {
for (MessageChannel<?, ?> b : channels) {
sent |= b.broadcast(message);
}
if (!sent && warn_unsent) Log.w("Message not accepted by any channel: " + message);
return sent;
}
@ -80,11 +83,13 @@ public class MessageBus implements Subscribable {
* Subscribe a client to the bus. The client will be connected to all
* current and future channels, until removed from the bus.
*
* @return <code>true</code>
* @return true on success
*/
@Override
public boolean addSubscriber(Object client)
{
if (client == null) return false;
for (MessageChannel<?, ?> b : channels) {
b.addSubscriber(client);
}
@ -106,6 +111,17 @@ public class MessageBus implements Subscribable {
}
/**
* Enable logging of unsent messages
*
* @param enable
*/
public void enableLoggingUnsent(boolean enable)
{
this.warn_unsent = enable;
}
/**
* Add a channel for given message and client type.
*
@ -113,7 +129,7 @@ public class MessageBus implements Subscribable {
* @param clientClass client type
* @return the created channel instance
*/
public <F_MESSAGE extends Handleable<F_CLIENT>, F_CLIENT> MessageChannel<?, ?> registerMessageType(Class<F_MESSAGE> messageClass, Class<F_CLIENT> clientClass)
public <F_MESSAGE extends Handleable<F_CLIENT>, F_CLIENT> MessageChannel<?, ?> createChannel(Class<F_MESSAGE> messageClass, Class<F_CLIENT> clientClass)
{
MessageChannel<F_MESSAGE, F_CLIENT> bc = new MessageChannel<F_MESSAGE, F_CLIENT>(messageClass, clientClass);
return addChannel(bc);

Loading…
Cancel
Save