Refactored subsystems for cleaner modularity.

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

@ -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.awt.image.BufferedImage;
import java.nio.ByteBuffer; 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.rogue.display.events.ScreenChangeEvent;
import mightypork.utils.logging.Log; import mightypork.utils.logging.Log;
import mightypork.utils.math.coord.Coord; import mightypork.utils.math.coord.Coord;
import mightypork.utils.patterns.Destroyable; import mightypork.utils.math.coord.Rect;
import mightypork.utils.patterns.Initializable;
import org.lwjgl.BufferUtils; import org.lwjgl.BufferUtils;
import org.lwjgl.LWJGLException; import org.lwjgl.LWJGLException;
@ -19,27 +20,29 @@ import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.DisplayMode; import org.lwjgl.opengl.DisplayMode;
public class DisplaySystem implements Initializable, Destroyable { public class DisplaySystem extends AppSubsystem implements ConstraintContext {
private boolean initialized;
private DisplayMode windowDisplayMode; private DisplayMode windowDisplayMode;
private int targetFps; private int targetFps;
public DisplaySystem() { public DisplaySystem(AppAccess app) {
initialize(); super(app, true);
enableUpdates(false);
} }
@Override @Override
public void initialize() protected void init()
{ {
if (initialized) return;
initChannels(); initChannels();
}
initialized = true;
@Override
public void deinit()
{
Display.destroy();
} }
@ -48,14 +51,7 @@ public class DisplaySystem implements Initializable, Destroyable {
*/ */
private void initChannels() private void initChannels()
{ {
App.msgbus().registerMessageType(ScreenChangeEvent.class, ScreenChangeEvent.Listener.class); msgbus().createChannel(ScreenChangeEvent.class, ScreenChangeEvent.Listener.class);
}
@Override
public void destroy()
{
Display.destroy();
} }
@ -105,7 +101,7 @@ public class DisplaySystem implements Initializable, Destroyable {
Display.update(); Display.update();
} }
App.broadcast(new ScreenChangeEvent(true, Display.isFullscreen(), getSize())); msgbus().broadcast(new ScreenChangeEvent(true, Display.isFullscreen(), getSize()));
} catch (Throwable t) { } catch (Throwable t) {
Log.e("Failed to toggle fullscreen mode.", t); Log.e("Failed to toggle fullscreen mode.", t);
@ -182,7 +178,7 @@ public class DisplaySystem implements Initializable, Destroyable {
public void beginFrame() public void beginFrame()
{ {
if (Display.wasResized()) { if (Display.wasResized()) {
App.broadcast(new ScreenChangeEvent(false, Display.isFullscreen(), getSize())); msgbus().broadcast(new ScreenChangeEvent(false, Display.isFullscreen(), getSize()));
} }
glLoadIdentity(); glLoadIdentity();
@ -198,4 +194,11 @@ public class DisplaySystem implements Initializable, Destroyable {
Display.update(false); // don't poll input devices Display.update(false); // don't poll input devices
Display.sync(targetFps); 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 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.display.events.ScreenChangeEvent;
import mightypork.rogue.input.KeyBinder; import mightypork.rogue.input.KeyBinder;
import mightypork.rogue.input.KeyBindingPool; import mightypork.rogue.input.KeyBindingPool;
import mightypork.rogue.input.KeyStroke; 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.math.coord.Coord;
import mightypork.utils.patterns.Initializable; import mightypork.utils.math.coord.Rect;
import mightypork.utils.time.Updateable;
/** /**
@ -22,27 +20,27 @@ import mightypork.utils.time.Updateable;
* *
* @author MightyPork * @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; private boolean active;
public Screen() { public Screen(AppAccess app) {
initialize(); super(app, false);
} }
@Override @Override
public void bindKeyStroke(KeyStroke stroke, Runnable task) public final void bindKeyStroke(KeyStroke stroke, Runnable task)
{ {
keybindings.bindKeyStroke(stroke, task); keybindings.bindKeyStroke(stroke, task);
} }
@Override @Override
public void unbindKeyStroke(KeyStroke stroke) public final void unbindKeyStroke(KeyStroke stroke)
{ {
keybindings.unbindKeyStroke(stroke); keybindings.unbindKeyStroke(stroke);
} }
@ -59,13 +57,19 @@ public abstract class Screen implements KeyBinder, Updateable, Initializable, Ke
active = true; active = true;
setupGraphics(); setupGraphics();
setupViewport(); setupViewport();
onSizeChanged(App.disp().getSize()); onSizeChanged(getRect().getSize());
onEnter(); onScreenEnter();
App.msgbus().addSubscriber(this);
// subscribe to event bus
enableEvents(true);
} else { } else {
onScreenLeave();
active = false; 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 // fix projection for changed size
glMatrixMode(GL_PROJECTION); glMatrixMode(GL_PROJECTION);
glLoadIdentity(); glLoadIdentity();
Coord s = App.disp().getSize(); Coord s = disp().getSize();
glViewport(0, 0, s.xi(), s.yi()); glViewport(0, 0, s.xi(), s.yi());
glOrtho(0, s.x, 0, s.y, -1000, 1000); 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> * Initialize screen layout and key bindings.<br>
* Called when the screen is created, not when it comes to front. For that, * Called during screen construction.
* use onEnter().
*/ */
@Override protected abstract void initScreen();
public abstract void initialize();
/**
* Clean up before screen is destroyed.
*/
protected abstract void deinitScreen();
/** /**
* Called when the screen becomes active * Called when the screen becomes active
*/ */
protected abstract void onEnter(); protected abstract void onScreenEnter();
/** /**
* Called when the screen is no longer active * 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 * @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 * Render screen
*/ */
private final void renderBegin() private void renderBegin()
{ {
glPushAttrib(GL_ENABLE_BIT); glPushAttrib(GL_ENABLE_BIT);
glPushMatrix(); glPushMatrix();
@ -164,32 +193,17 @@ public abstract class Screen implements KeyBinder, Updateable, Initializable, Ke
/** /**
* Render screen * Render screen
*/ */
private final void renderEnd() private void renderEnd()
{ {
glPopAttrib(); glPopAttrib();
glPopMatrix(); 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 * @return true if screen is the curretn screen
*/ */
protected final boolean isActive() public final boolean isActive()
{ {
return active; 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 @Override
public final void receive(KeyboardEvent event) public final Rect getRect()
{ {
if (!isActive()) return; return disp().getRect();
keybindings.receive(event);
} }
} }

@ -3,10 +3,9 @@ package mightypork.rogue.display;
import java.util.Random; import java.util.Random;
import mightypork.rogue.App; import mightypork.rogue.AppAccess;
import mightypork.rogue.input.KeyStroke; import mightypork.rogue.input.KeyStroke;
import mightypork.rogue.input.events.MouseButtonEvent; import mightypork.rogue.input.events.MouseButtonEvent;
import mightypork.rogue.input.events.MouseMotionEvent;
import mightypork.rogue.util.RenderUtils; import mightypork.rogue.util.RenderUtils;
import mightypork.utils.math.Polar; import mightypork.utils.math.Polar;
import mightypork.utils.math.color.RGB; import mightypork.utils.math.color.RGB;
@ -19,7 +18,11 @@ import org.lwjgl.input.Keyboard;
import org.lwjgl.opengl.Display; 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 Random rand = new Random();
@ -94,7 +97,7 @@ public class ScreenTestAnimations extends Screen {
//@formatter:on //@formatter:on
@Override @Override
public void initialize() public void initScreen()
{ {
bindKeyStroke(new KeyStroke(Keyboard.KEY_RIGHT), new Runnable() { bindKeyStroke(new KeyStroke(Keyboard.KEY_RIGHT), new Runnable() {
@ -121,79 +124,69 @@ public class ScreenTestAnimations extends Screen {
@Override @Override
protected void renderScreen() protected void deinitScreen()
{ {
double screenH = Display.getHeight(); // no impl
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);
} }
@Override @Override
public void receive(MouseMotionEvent event) protected void onScreenEnter()
{ {
// // no impl
} }
@Override @Override
public void receive(MouseButtonEvent event) protected void onScreenLeave()
{ {
if (event.isDown()) { // no impl
Coord vec = App.disp().getSize().half().vecTo(event.getPos());
Polar p = Polar.fromCoord(vec);
degAnim.fadeTo(p.getAngleDeg() - 90, 1.5);
}
} }
@Override @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 @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 RenderUtils.setColor(RGB.GREEN);
protected void onSizeChanged(Coord size) RenderUtils.quadSize(padding + a.getCurrentValue() * (screenW - perBoxH), screenH - perBoxH * i - perBoxH + padding, boxSide, boxSide);
{ }
// TODO Auto-generated method stub
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 @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) { Polar p = Polar.fromCoord(vec);
a.update(delta);
degAnim.fadeTo(p.getAngleDeg() - 90, 1.5);
} }
} }

@ -4,7 +4,15 @@ package mightypork.rogue.display.constraints;
import mightypork.utils.math.coord.Rect; import mightypork.utils.math.coord.Rect;
/**
* Constraints can be based on this
*
* @author MightyPork
*/
public interface ConstraintContext { public interface ConstraintContext {
/**
* @return bounding rectangle
*/
public Rect getRect(); 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 * @author MightyPork
*/ */
@SuppressWarnings("javadoc")
public class Align { public class Align {
public static final int LEFT = -1; public static final int LEFT = -1;

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

@ -1,13 +1,12 @@
package mightypork.rogue.input; 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.KeyboardEvent;
import mightypork.rogue.input.events.MouseButtonEvent; import mightypork.rogue.input.events.MouseButtonEvent;
import mightypork.rogue.input.events.MouseMotionEvent; import mightypork.rogue.input.events.MouseMotionEvent;
import mightypork.utils.math.coord.Coord; import mightypork.utils.math.coord.Coord;
import mightypork.utils.patterns.Destroyable;
import mightypork.utils.patterns.Initializable;
import org.lwjgl.LWJGLException; import org.lwjgl.LWJGLException;
import org.lwjgl.input.Keyboard; import org.lwjgl.input.Keyboard;
@ -15,31 +14,35 @@ import org.lwjgl.input.Mouse;
import org.lwjgl.opengl.Display; import org.lwjgl.opengl.Display;
public class InputSystem implements KeyBinder, Destroyable, Initializable { public class InputSystem extends AppSubsystem implements KeyBinder {
private boolean initialized;
// listeners // listeners
private KeyBindingPool keybindings; private KeyBindingPool keybindings;
public InputSystem() { public InputSystem(AppAccess app) {
initialize(); super(app, true);
} }
@Override @Override
public void initialize() protected void init()
{ {
if (initialized) return;
initDevices(); initDevices();
initChannels(); initChannels();
// global keybindings
keybindings = new KeyBindingPool(); 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() private void initChannels()
{ {
App.msgbus().registerMessageType(KeyboardEvent.class, KeyboardEvent.Listener.class); msgbus().createChannel(KeyboardEvent.class, KeyboardEvent.Listener.class);
App.msgbus().registerMessageType(MouseMotionEvent.class, MouseMotionEvent.Listener.class); msgbus().createChannel(MouseMotionEvent.class, MouseMotionEvent.Listener.class);
App.msgbus().registerMessageType(MouseButtonEvent.class, MouseButtonEvent.Listener.class); msgbus().createChannel(MouseButtonEvent.class, MouseButtonEvent.Listener.class);
}
@Override
public void destroy()
{
Mouse.destroy();
Keyboard.destroy();
} }
@ -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() private void onMouseEvent()
{ {
int button = Mouse.getEventButton(); int button = Mouse.getEventButton();
@ -112,8 +88,8 @@ public class InputSystem implements KeyBinder, Destroyable, Initializable {
Coord move = new Coord(Mouse.getEventDX(), Mouse.getEventDY()); Coord move = new Coord(Mouse.getEventDX(), Mouse.getEventDY());
int wheeld = Mouse.getEventDWheel(); int wheeld = Mouse.getEventDWheel();
if (button != -1 || wheeld != 0) App.broadcast(new MouseButtonEvent(pos, button, down, wheeld)); if (button != -1 || wheeld != 0) msgbus().broadcast(new MouseButtonEvent(pos, button, down, wheeld));
if (!move.isZero()) App.broadcast(new MouseMotionEvent(pos, move)); if (!move.isZero()) msgbus().broadcast(new MouseMotionEvent(pos, move));
} }
@ -122,6 +98,21 @@ public class InputSystem implements KeyBinder, Destroyable, Initializable {
int key = Keyboard.getEventKey(); int key = Keyboard.getEventKey();
boolean down = Keyboard.getEventKeyState(); boolean down = Keyboard.getEventKeyState();
char c = Keyboard.getEventCharacter(); 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.baseGain = baseGain;
this.basePitch = basePitch; this.basePitch = basePitch;
if (gainMultiplier == null) gainMultiplier = new Mutable<Double>(1D);
this.gainMultiplier = gainMultiplier; 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.Map;
import java.util.Set; 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.Calc.Buffers;
import mightypork.utils.math.coord.Coord; import mightypork.utils.math.coord.Coord;
import mightypork.utils.objects.Mutable; import mightypork.utils.objects.Mutable;
import mightypork.utils.patterns.Destroyable;
import mightypork.utils.time.Updateable;
import org.lwjgl.openal.AL; import org.lwjgl.openal.AL;
import org.lwjgl.openal.AL10; import org.lwjgl.openal.AL10;
@ -24,13 +25,13 @@ import org.newdawn.slick.openal.SoundStore;
* @author MightyPork * @author MightyPork
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
// needed for JointVolume public class SoundSystem extends AppSubsystem {
public class SoundSystem implements Updateable, Destroyable {
// static
private static final Coord INITIAL_LISTENER_POS = new Coord(0, 0, 0); private static final Coord INITIAL_LISTENER_POS = new Coord(0, 0, 0);
private static final int MAX_SOURCES = 256; 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(); private static Coord listener = new Coord();
@ -65,13 +66,7 @@ public class SoundSystem implements Updateable, Destroyable {
buf3 = buf6 = null; buf3 = buf6 = null;
} }
// -- instance --
public static Coord getListener()
{
return listener;
}
// instance
public Mutable<Double> masterVolume = new Mutable<Double>(1D); public Mutable<Double> masterVolume = new Mutable<Double>(1D);
public Mutable<Double> effectsVolume = new JointVolume(masterVolume); public Mutable<Double> effectsVolume = new JointVolume(masterVolume);
@ -82,6 +77,45 @@ public class SoundSystem implements Updateable, Destroyable {
private Set<AudioX> resources = new HashSet<AudioX>(); 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 * Register effect resource
* *
@ -141,7 +175,8 @@ public class SoundSystem implements Updateable, Destroyable {
{ {
LoopPlayer p = loops.get(key); LoopPlayer p = loops.get(key);
if (p == null) { if (p == null) {
throw new IllegalArgumentException("Requesting unknown sound loop \"" + key + "\"."); Log.w("Requesting unknown sound loop \"" + key + "\".");
return NULL_LOOP;
} }
return p; return p;
} }
@ -157,7 +192,8 @@ public class SoundSystem implements Updateable, Destroyable {
{ {
EffectPlayer p = effects.get(key); EffectPlayer p = effects.get(key);
if (p == null) { if (p == null) {
throw new IllegalArgumentException("Requesting unknown sound effect \"" + key + "\"."); Log.w("Requesting unknown sound effect \"" + key + "\".");
return NULL_EFFECT;
} }
return p; 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 * Set level of master volume
* *
@ -293,17 +320,4 @@ public class SoundSystem implements Updateable, Destroyable {
{ {
loopsVolume.set(d); 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 javax.imageio.ImageIO;
import mightypork.rogue.App;
import mightypork.rogue.Paths; import mightypork.rogue.Paths;
import mightypork.rogue.display.DisplaySystem;
import mightypork.utils.logging.Log; import mightypork.utils.logging.Log;
@ -20,8 +20,8 @@ public class TaskTakeScreenshot implements Runnable {
private BufferedImage image; private BufferedImage image;
public TaskTakeScreenshot() { public TaskTakeScreenshot(DisplaySystem disp) {
this.image = App.disp().takeScreenshot(); this.image = disp.takeScreenshot();
} }

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

@ -6,7 +6,6 @@ package mightypork.rogue.textures;
* *
* @author MightyPork * @author MightyPork
*/ */
@SuppressWarnings("javadoc")
public class Tx { public class Tx {
// logo // 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 }; * 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); * Map&lt;String, Integer&gt; args = new VarargsParser&lt;String, Integer&gt;().parse(array);
* </pre> * </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<MessageChannel<?, ?>> channels = new LinkedHashSet<MessageChannel<?, ?>>();
private Set<Object> clients = new LinkedHashSet<Object>(); 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) { for (MessageChannel<?, ?> b : channels) {
sent |= b.broadcast(message); sent |= b.broadcast(message);
} }
if (!sent && warn_unsent) Log.w("Message not accepted by any channel: " + message);
return sent; return sent;
} }
@ -80,11 +83,13 @@ public class MessageBus implements Subscribable {
* Subscribe a client to the bus. The client will be connected to all * Subscribe a client to the bus. The client will be connected to all
* current and future channels, until removed from the bus. * current and future channels, until removed from the bus.
* *
* @return <code>true</code> * @return true on success
*/ */
@Override @Override
public boolean addSubscriber(Object client) public boolean addSubscriber(Object client)
{ {
if (client == null) return false;
for (MessageChannel<?, ?> b : channels) { for (MessageChannel<?, ?> b : channels) {
b.addSubscriber(client); 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. * Add a channel for given message and client type.
* *
@ -113,7 +129,7 @@ public class MessageBus implements Subscribable {
* @param clientClass client type * @param clientClass client type
* @return the created channel instance * @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); MessageChannel<F_MESSAGE, F_CLIENT> bc = new MessageChannel<F_MESSAGE, F_CLIENT>(messageClass, clientClass);
return addChannel(bc); return addChannel(bc);

Loading…
Cancel
Save