EventBus now using thread; +Textures; +Audio; Cleaner structure

This commit is contained in:
Ondřej Hruška
2014-04-04 23:06:56 +02:00
parent 7f35d1d316
commit 53b7b02609
68 changed files with 1887 additions and 1929 deletions
+120 -116
View File
@@ -4,22 +4,21 @@ package mightypork.rogue;
import java.io.File;
import java.io.RandomAccessFile;
import java.nio.channels.FileLock;
import java.util.ArrayList;
import javax.swing.JOptionPane;
import mightypork.rogue.display.DisplaySystem;
import mightypork.rogue.display.Screen;
import mightypork.rogue.display.screens.screenBouncy.TestLayeredScreen;
import mightypork.rogue.audio.SoundSystem;
import mightypork.rogue.bus.events.*;
import mightypork.rogue.gui.screens.ScreenRegistry;
import mightypork.rogue.input.InputSystem;
import mightypork.rogue.input.KeyStroke;
import mightypork.rogue.sounds.SoundSystem;
import mightypork.rogue.tasks.TaskTakeScreenshot;
import mightypork.rogue.textures.TextureRegistry;
import mightypork.rogue.util.Utils;
import mightypork.rogue.render.DisplaySystem;
import mightypork.utils.control.bus.EventBus;
import mightypork.utils.control.bus.events.DestroyEvent;
import mightypork.utils.control.bus.events.UpdateEvent;
import mightypork.utils.control.timing.TimerDelta;
import mightypork.utils.control.interf.Destroyable;
import mightypork.utils.control.interf.Updateable;
import mightypork.utils.logging.Log;
import mightypork.utils.logging.LogInstance;
@@ -38,22 +37,12 @@ public class App implements AppAccess {
// modules
private InputSystem inputSystem;
private SoundSystem soundSystem;
private DisplaySystem displaySystem;
private static SoundSystem soundSystem;
private EventBus eventBus;
private TextureRegistry textureRegistry;
private MainLoop mainLoop;
/** current screen */
private Screen screen;
/** Flag that screenshot is scheduled to be taken next loop */
private boolean scheduledScreenshot = false;
/** Log instance; accessible as static via Log. */
private LogInstance log;
/** timer */
private TimerDelta timerRender;
public ScreenRegistry screens;
/**
@@ -82,34 +71,9 @@ public class App implements AppAccess {
private void start()
{
initialize();
mainLoop();
shutdown();
}
/**
* App main loop
*/
private void mainLoop()
{
screen = new TestLayeredScreen(this);
screen.setActive(true);
timerRender = new TimerDelta();
while (!displaySystem.isCloseRequested()) {
displaySystem.beginFrame();
eventBus.broadcast(new UpdateEvent(timerRender.getDelta()));
if (scheduledScreenshot) {
takeScreenshot();
scheduledScreenshot = false;
}
displaySystem.endFrame();
}
Log.i("Starting main loop...");
mainLoop.start();
}
@@ -120,7 +84,7 @@ public class App implements AppAccess {
*/
public static void onCrash(Throwable error)
{
Log.e("The game has crashed.", error);
Log.e("The game has crashed!", error);
if (inst != null) inst.shutdown();
}
@@ -129,7 +93,11 @@ public class App implements AppAccess {
@Override
public void shutdown()
{
bus().broadcast(new DestroyEvent());
bus().send(new DestroyEvent());
bus().destroy();
Log.i("Shutting down...");
System.exit(0);
}
@@ -137,34 +105,124 @@ public class App implements AppAccess {
public void initialize()
{
Log.i("Initializing subsystems");
// lock working directory
/*
* Lock working directory
*/
initLock();
// setup logging
log = Log.create("runtime", Paths.LOGS, 10);
/*
* Setup logging
*/
LogInstance log = Log.create("runtime", Paths.LOGS, 10);
log.enable(Config.LOGGING_ENABLED);
log.enableSysout(Config.LOG_TO_STDOUT);
// event bus
Log.f1("Initializing subsystems...");
/*
* Event bus
*/
Log.f2("Initializing Event Bus...");
eventBus = new EventBus();
eventBus.enableLogging(Config.LOG_BUS);
initChannels();
// Subsystems
textureRegistry = new TextureRegistry(this);
/*
* Display
*/
Log.f2("Initializing Display System...");
displaySystem = new DisplaySystem(this);
displaySystem.createMainWindow(Const.WINDOW_W, Const.WINDOW_H, true, Config.START_IN_FS, Const.TITLEBAR);
displaySystem.setTargetFps(Const.FPS_RENDER);
/*
* Audio
*/
Log.f2("Initializing Sound System...");
soundSystem = new SoundSystem(this);
soundSystem.setMasterVolume(1);
/*
* Input
*/
Log.f2("Initializing Input System...");
inputSystem = new InputSystem(this);
setupGlobalKeystrokes();
// load resources
Resources.load(this);
/*
* Screen registry
*/
Log.f2("Initializing screen registry...");
screens = new ScreenRegistry(this);
/*
* Load resources
*/
Log.f1("Registering resources...");
Res.load(this);
/*
* Prepare main loop
*/
Log.f1("Preparing main loop...");
ArrayList<Runnable> loopTasks = new ArrayList<Runnable>();
loopTasks.add(new Runnable() {
@Override
public void run()
{
screens.render();
}
});
mainLoop = new MainLoop(this, loopTasks);
}
private void initChannels()
{
Log.f3("Registering channels...");
bus().addChannel(DestroyEvent.class, Destroyable.class);
bus().addChannel(UpdateEvent.class, Updateable.class);
bus().addChannel(ScreenChangeEvent.class, ScreenChangeEvent.Listener.class);
bus().addChannel(KeyboardEvent.class, KeyboardEvent.Listener.class);
bus().addChannel(MouseMotionEvent.class, MouseMotionEvent.Listener.class);
bus().addChannel(MouseButtonEvent.class, MouseButtonEvent.Listener.class);
bus().addChannel(ScreenRequestEvent.class, ScreenRequestEvent.Listener.class);
bus().addChannel(ActionRequest.class, ActionRequest.Listener.class);
}
private void setupGlobalKeystrokes()
{
input().bindKeyStroke(new KeyStroke(Keyboard.KEY_F11), new Runnable() {
@Override
public void run()
{
bus().queue(new ActionRequest(RequestType.FULLSCREEN));
}
});
input().bindKeyStroke(new KeyStroke(Keyboard.KEY_F2), new Runnable() {
@Override
public void run()
{
bus().queue(new ActionRequest(RequestType.SCREENSHOT));
}
});
input().bindKeyStroke(new KeyStroke(Keyboard.KEY_LCONTROL, Keyboard.KEY_Q), new Runnable() {
@Override
public void run()
{
bus().queue(new ActionRequest(RequestType.SHUTDOWN));
}
});
}
@@ -173,7 +231,7 @@ public class App implements AppAccess {
if (!Config.SINGLE_INSTANCE) return;
if (!lockInstance()) {
System.out.println("Working directory is locked.\nOnly one instance can run at a time.");
System.err.println("Working directory is locked.\nOnly one instance can run at a time.");
//@formatter:off
JOptionPane.showMessageDialog(
@@ -222,53 +280,6 @@ public class App implements AppAccess {
}
/**
* initialize inputs
*/
private void setupGlobalKeystrokes()
{
inputSystem.bindKeyStroke(new KeyStroke(Keyboard.KEY_F2), new Runnable() {
@Override
public void run()
{
Log.f3("F2, taking screenshot.");
scheduledScreenshot = true;
}
});
inputSystem.bindKeyStroke(new KeyStroke(false, Keyboard.KEY_F11), new Runnable() {
@Override
public void run()
{
Log.f3("F11, toggling fullscreen.");
displaySystem.switchFullscreen();
}
});
inputSystem.bindKeyStroke(new KeyStroke(Keyboard.KEY_LCONTROL, Keyboard.KEY_Q), new Runnable() {
@Override
public void run()
{
Log.f3("CTRL+Q, shutting down.");
shutdown();
}
});
}
/**
* Do take a screenshot
*/
private void takeScreenshot()
{
soundSystem.getEffect("gui.shutter").play(1);
Utils.runAsThread(new TaskTakeScreenshot(displaySystem));
}
/**
* @return sound system of the running instance
*/
@@ -308,11 +319,4 @@ public class App implements AppAccess {
return eventBus;
}
@Override
public TextureRegistry tx()
{
return textureRegistry;
}
}
+2 -9
View File
@@ -1,10 +1,9 @@
package mightypork.rogue;
import mightypork.rogue.display.DisplaySystem;
import mightypork.rogue.audio.SoundSystem;
import mightypork.rogue.input.InputSystem;
import mightypork.rogue.sounds.SoundSystem;
import mightypork.rogue.textures.TextureRegistry;
import mightypork.rogue.render.DisplaySystem;
import mightypork.utils.control.bus.EventBus;
@@ -39,12 +38,6 @@ public interface AppAccess {
abstract EventBus bus();
/**
* @return texture registry
*/
abstract TextureRegistry tx();
/**
* Quit to OS<br>
* Destroy app & exit VM
+2 -10
View File
@@ -1,10 +1,9 @@
package mightypork.rogue;
import mightypork.rogue.display.DisplaySystem;
import mightypork.rogue.audio.SoundSystem;
import mightypork.rogue.input.InputSystem;
import mightypork.rogue.sounds.SoundSystem;
import mightypork.rogue.textures.TextureRegistry;
import mightypork.rogue.render.DisplaySystem;
import mightypork.utils.control.bus.EventBus;
@@ -59,11 +58,4 @@ public class AppAdapter implements AppAccess {
app.shutdown();
}
@Override
public TextureRegistry tx()
{
return app.tx();
}
}
+1
View File
@@ -77,5 +77,6 @@ public class Config {
public static boolean SINGLE_INSTANCE = true;
public static boolean LOG_FONTS = false;
public static boolean LOG_BUS = false;
}
+1 -2
View File
@@ -15,8 +15,7 @@ public class Const {
public static final String TITLEBAR = APP_NAME + " v." + VERSION;
// AUDIO
public static final int FPS_RENDER = 200; // max
public static final long FPS_GUI_UPDATE = 60;
public static final int FPS_RENDER = 80; // max
// INITIAL WINDOW SIZE
public static final int WINDOW_W = 1024;
+21
View File
@@ -0,0 +1,21 @@
package mightypork.rogue;
/**
* Deferred resource
*
* @author MightyPork
*/
public interface Deferred {
/**
* Load the actual resource if not loaded yet
*/
public void load();
/**
* @return true if already loaded
*/
public boolean isLoaded();
}
+112
View File
@@ -0,0 +1,112 @@
package mightypork.rogue;
import java.util.ArrayList;
import java.util.List;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
import mightypork.rogue.bus.Subsystem;
import mightypork.rogue.bus.events.ActionRequest;
import mightypork.rogue.bus.events.RequestType;
import mightypork.rogue.bus.events.ScreenRequestEvent;
import mightypork.rogue.tasks.TaskTakeScreenshot;
import mightypork.rogue.util.Utils;
import mightypork.utils.control.bus.events.UpdateEvent;
import mightypork.utils.control.timing.TimerDelta;
public class MainLoop extends Subsystem implements ActionRequest.Listener {
private Queue<Runnable> taskQueue = new ConcurrentLinkedQueue<Runnable>();
private List<Runnable> regularTasks;
public MainLoop(App app, ArrayList<Runnable> loopTasks) {
super(app);
this.regularTasks = loopTasks;
}
/** timer */
private TimerDelta timer;
private boolean running = true;
public void start()
{
bus().queue(new ScreenRequestEvent("test.texture"));
timer = new TimerDelta();
while (running) {
disp().beginFrame();
bus().send(new UpdateEvent(timer.getDelta()));
for (Runnable r : regularTasks) {
r.run();
}
Runnable r;
while ((r = taskQueue.poll()) != null) {
r.run();
}
disp().endFrame();
}
}
@Override
protected void deinit()
{
running = false;
}
@Override
public void requestAction(RequestType request)
{
switch (request) {
case FULLSCREEN:
taskQueue.add(taskFullscreen);
break;
case SCREENSHOT:
taskQueue.add(taskScreenshot);
break;
case SHUTDOWN:
taskQueue.add(taskShutdown);
}
}
private final Runnable taskScreenshot = new Runnable() {
@Override
public void run()
{
Res.getEffect("gui.shutter").play(1);
Utils.runAsThread(new TaskTakeScreenshot(disp()));
}
};
private final Runnable taskShutdown = new Runnable() {
@Override
public void run()
{
shutdown();
}
};
private final Runnable taskFullscreen = new Runnable() {
@Override
public void run()
{
disp().switchFullscreen();
}
};
}
+87
View File
@@ -0,0 +1,87 @@
package mightypork.rogue;
import mightypork.rogue.audio.EffectPlayer;
import mightypork.rogue.audio.LoopPlayer;
import mightypork.rogue.audio.SoundBank;
import mightypork.rogue.gui.screens.screenBouncy.ScreenTestAnim;
import mightypork.rogue.gui.screens.screenTextures.ScreenTextureTest;
import mightypork.rogue.render.textures.TextureBank;
import mightypork.rogue.render.textures.TxQuad;
import org.newdawn.slick.opengl.Texture;
public class Res {
private static TextureBank textures;
private static SoundBank sounds;
private static boolean initialized = false;
public static void load(App app)
{
if (initialized) return;
initialized = true;
textures = new TextureBank(app);
sounds = new SoundBank(app);
loadSounds(app);
loadTextures(app);
loadFonts(app);
loadScreens(app);
}
private static void loadFonts(App app)
{
}
private static void loadTextures(App app)
{
textures.loadTexture("test.kitten", "/res/img/kitten.png");
}
private static void loadSounds(App app)
{
sounds.addEffect("gui.shutter", "/res/audio/shutter.ogg", 1, 1);
sounds.addLoop("test.wilderness", "/res/audio/wilderness.ogg", 1, 1, 3, 3);
}
private static void loadScreens(App app)
{
app.screens.add("test.anim", new ScreenTestAnim(app));
app.screens.add("test.texture", new ScreenTextureTest(app));
}
public static TxQuad getTxQuad(String key)
{
return textures.getTxQuad(key);
}
public static Texture getTexture(String key)
{
return textures.getTexture(key);
}
public static LoopPlayer getLoop(String key)
{
return sounds.getLoop(key);
}
public static EffectPlayer getEffect(String key)
{
return sounds.getEffect(key);
}
}
-33
View File
@@ -1,33 +0,0 @@
package mightypork.rogue;
public class Resources {
public static void load(AppAccess app)
{
loadSounds(app);
loadTextures(app);
loadFonts(app);
}
private static void loadFonts(AppAccess app)
{
}
private static void loadTextures(AppAccess app)
{
}
private static void loadSounds(AppAccess app)
{
}
}
@@ -1,4 +1,4 @@
package mightypork.rogue.sounds;
package mightypork.rogue.audio;
import mightypork.utils.objects.Mutable;
@@ -7,7 +7,7 @@ import mightypork.utils.objects.Mutable;
public abstract class BaseAudioPlayer {
/** the track */
private AudioX audio;
private DeferredAudio audio;
/** base gain for sfx */
private double baseGain = 1;
@@ -19,12 +19,12 @@ public abstract class BaseAudioPlayer {
private Mutable<Double> gainMultiplier = null;
public BaseAudioPlayer(AudioX track, double baseGain, Mutable<Double> gainMultiplier) {
public BaseAudioPlayer(DeferredAudio track, double baseGain, Mutable<Double> gainMultiplier) {
this(track, 1, baseGain, gainMultiplier);
}
public BaseAudioPlayer(AudioX track, double basePitch, double baseGain, Mutable<Double> gainMultiplier) {
public BaseAudioPlayer(DeferredAudio track, double basePitch, double baseGain, Mutable<Double> gainMultiplier) {
this.audio = track;
this.baseGain = baseGain;
@@ -43,7 +43,7 @@ public abstract class BaseAudioPlayer {
}
protected AudioX getAudio()
protected DeferredAudio getAudio()
{
return audio;
}
@@ -66,7 +66,7 @@ public abstract class BaseAudioPlayer {
*
* @return is valid
*/
protected boolean canPlay()
protected boolean hasAudio()
{
return (audio != null);
}
@@ -74,6 +74,6 @@ public abstract class BaseAudioPlayer {
public void load()
{
if (canPlay()) audio.load();
if (hasAudio()) audio.load();
}
}
@@ -1,6 +1,7 @@
package mightypork.rogue.sounds;
package mightypork.rogue.audio;
import mightypork.rogue.Deferred;
import mightypork.utils.control.interf.Destroyable;
import mightypork.utils.files.FileUtils;
import mightypork.utils.logging.Log;
@@ -15,7 +16,7 @@ import org.newdawn.slick.openal.SoundStore;
*
* @author MightyPork
*/
public class AudioX implements Destroyable {
public class DeferredAudio implements Destroyable, Deferred {
private enum PlayMode
{
@@ -39,7 +40,7 @@ public class AudioX implements Destroyable {
*
* @param resourceName resource to load when needed
*/
public AudioX(String resourceName) {
public DeferredAudio(String resourceName) {
this.audio = null;
this.resourcePath = resourceName;
}
@@ -50,7 +51,7 @@ public class AudioX implements Destroyable {
*/
public void pauseLoop()
{
if (!load()) return;
if (!ensureLoaded()) return;
if (isPlaying() && looping) {
pauseLoopPosition = audio.getPosition();
@@ -67,7 +68,7 @@ public class AudioX implements Destroyable {
*/
public int resumeLoop()
{
if (!load()) return -1;
if (!ensureLoaded()) return -1;
int source = -1;
if (looping && paused) {
@@ -88,24 +89,32 @@ public class AudioX implements Destroyable {
*
* @return resource is loaded
*/
private boolean isLoaded()
@Override
public boolean isLoaded()
{
return audio != null;
}
@Override
public void load()
{
ensureLoaded();
}
/**
* Try to load if not loaded already
*
* @return is loaded
*/
public boolean load()
protected boolean ensureLoaded()
{
if (isLoaded()) return true; // already loaded
if (loadFailed || resourcePath == null) return false; // not loaded, but
// can't load
// anyway
if (loadFailed || resourcePath == null) return false;
Log.f3("Trying to load: " + resourcePath);
loadFailed = false;
try {
String ext = FileUtils.getExtension(resourcePath);
@@ -124,6 +133,8 @@ public class AudioX implements Destroyable {
loadFailed = true; // don't try next time
}
if (!loadFailed) Log.f3("Audio loaded: " + resourcePath);
} catch (Exception e) {
Log.e("Could not load " + resourcePath, e);
loadFailed = true; // don't try next time
@@ -201,7 +212,7 @@ public class AudioX implements Destroyable {
*/
public int playAsEffect(double pitch, double gain, boolean loop, double x, double y, double z)
{
if (!load()) return -1;
if (!ensureLoaded()) return -1;
this.lastPlayPitch = pitch;
this.lastPlayGain = gain;
@@ -222,7 +233,7 @@ public class AudioX implements Destroyable {
*/
public int playAsEffect(double pitch, double gain, boolean loop, Coord pos)
{
if (!load()) return -1;
if (!ensureLoaded()) return -1;
return playAsEffect(pitch, gain, loop, pos.x, pos.y, pos.z);
}
@@ -239,7 +250,7 @@ public class AudioX implements Destroyable {
*/
public int playAsMusic(double pitch, double gain, boolean loop)
{
if (!load()) return -1;
if (!ensureLoaded()) return -1;
this.lastPlayPitch = (float) pitch;
this.lastPlayGain = (float) gain;
@@ -274,8 +285,8 @@ public class AudioX implements Destroyable {
{
if (this == obj) return true;
if (obj == null) return false;
if (!(obj instanceof AudioX)) return false;
AudioX other = (AudioX) obj;
if (!(obj instanceof DeferredAudio)) return false;
DeferredAudio other = (DeferredAudio) obj;
if (resourcePath == null) {
if (other.resourcePath != null) return false;
} else if (!resourcePath.equals(other.resourcePath)) {
@@ -1,4 +1,4 @@
package mightypork.rogue.sounds;
package mightypork.rogue.audio;
import mightypork.utils.math.coord.Coord;
@@ -7,14 +7,14 @@ import mightypork.utils.objects.Mutable;
public class EffectPlayer extends BaseAudioPlayer {
public EffectPlayer(AudioX track, double basePitch, double baseGain, Mutable<Double> gainMultiplier) {
public EffectPlayer(DeferredAudio track, double basePitch, double baseGain, Mutable<Double> gainMultiplier) {
super(track, (float) basePitch, (float) baseGain, gainMultiplier);
}
public int play(double pitch, double gain)
{
if (!canPlay()) return -1;
if (!hasAudio()) return -1;
return getAudio().playAsEffect(getPitch(pitch), getGain(gain), false);
}
@@ -28,7 +28,7 @@ public class EffectPlayer extends BaseAudioPlayer {
public int play(double pitch, double gain, Coord pos)
{
if (!canPlay()) return -1;
if (!hasAudio()) return -1;
return getAudio().playAsEffect(getPitch(pitch), getGain(gain), false, pos);
}
@@ -1,4 +1,4 @@
package mightypork.rogue.sounds;
package mightypork.rogue.audio;
import mightypork.utils.math.Calc;
@@ -1,4 +1,4 @@
package mightypork.rogue.sounds;
package mightypork.rogue.audio;
import mightypork.utils.control.interf.Updateable;
@@ -28,7 +28,7 @@ public class LoopPlayer extends BaseAudioPlayer implements Updateable, Pauseable
private double outTime = 1;
public LoopPlayer(AudioX track, double pitch, double baseGain, Mutable<Double> gainMultiplier) {
public LoopPlayer(DeferredAudio track, double pitch, double baseGain, Mutable<Double> gainMultiplier) {
super(track, (float) pitch, (float) baseGain, gainMultiplier);
paused = true;
@@ -44,7 +44,7 @@ public class LoopPlayer extends BaseAudioPlayer implements Updateable, Pauseable
private void initLoop()
{
if (!canPlay() && sourceID == -1) {
if (hasAudio() && sourceID == -1) {
sourceID = getAudio().playAsEffect(getPitch(1), getGain(1), true);
getAudio().pauseLoop();
}
@@ -54,7 +54,7 @@ public class LoopPlayer extends BaseAudioPlayer implements Updateable, Pauseable
@Override
public void pause()
{
if (!canPlay() || paused) return;
if (!hasAudio() || paused) return;
initLoop();
@@ -73,7 +73,7 @@ public class LoopPlayer extends BaseAudioPlayer implements Updateable, Pauseable
@Override
public void resume()
{
if (!canPlay() || paused) return;
if (!hasAudio() || !paused) return;
initLoop();
@@ -85,13 +85,13 @@ public class LoopPlayer extends BaseAudioPlayer implements Updateable, Pauseable
@Override
public void update(double delta)
{
if (!canPlay() || paused) return;
if (!hasAudio() || paused) return;
initLoop();
fadeAnim.update(delta);
double gain = getGain(fadeAnim.getCurrentValue());
double gain = getGain(fadeAnim.now());
if (!paused && gain != lastUpdateGain) {
AL10.alSourcef(sourceID, AL10.AL_GAIN, (float) gain);
lastUpdateGain = gain;
@@ -103,7 +103,7 @@ public class LoopPlayer extends BaseAudioPlayer implements Updateable, Pauseable
public void fadeIn(double secs)
{
if (!canPlay()) return;
if (!hasAudio()) return;
resume();
fadeAnim.fadeIn(secs);
@@ -112,7 +112,7 @@ public class LoopPlayer extends BaseAudioPlayer implements Updateable, Pauseable
public void fadeOut(double secs)
{
if (!canPlay()) return;
if (!hasAudio()) return;
fadeAnim.fadeOut(secs);
}
+30
View File
@@ -0,0 +1,30 @@
package mightypork.rogue.audio;
public class NullAudio extends DeferredAudio {
public NullAudio() {
super("");
}
@Override
public void load()
{
}
@Override
public boolean isLoaded()
{
return true;
}
@Override
protected boolean ensureLoaded()
{
return false;
}
}
+90
View File
@@ -0,0 +1,90 @@
package mightypork.rogue.audio;
import java.util.HashMap;
import java.util.Map;
import mightypork.rogue.AppAccess;
import mightypork.rogue.AppAdapter;
import mightypork.utils.logging.Log;
public class SoundBank extends AppAdapter {
private static final DeferredAudio 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 Map<String, EffectPlayer> effects = new HashMap<String, EffectPlayer>();
private Map<String, LoopPlayer> loops = new HashMap<String, LoopPlayer>();
public SoundBank(AppAccess app) {
super(app);
if (snd() == null) throw new NullPointerException("SoundSystem cannot be null.");
}
/**
* Register effect resource
*
* @param key sound key
* @param resource resource path
* @param pitch default pitch (1 = unchanged)
* @param gain default gain (0-1)
*/
public void addEffect(String key, String resource, double pitch, double gain)
{
effects.put(key, snd().createEffect(resource, pitch, gain));
}
/**
* Register loop resource (music / effect loop)
*
* @param key sound key
* @param resource resource path
* @param pitch default pitch (1 = unchanged)
* @param gain default gain (0-1)
* @param fadeIn default time for fadeIn
* @param fadeOut default time for fadeOut
*/
public void addLoop(String key, String resource, double pitch, double gain, double fadeIn, double fadeOut)
{
loops.put(key, snd().createLoop(resource, pitch, gain, fadeIn, fadeOut));
}
/**
* Get a loop player for key
*
* @param key sound key
* @return loop player
*/
public LoopPlayer getLoop(String key)
{
LoopPlayer p = loops.get(key);
if (p == null) {
Log.w("Requesting unknown sound loop \"" + key + "\".");
return NULL_LOOP;
}
return p;
}
/**
* Get a effect player for key
*
* @param key sound key
* @return effect player
*/
public EffectPlayer getEffect(String key)
{
EffectPlayer p = effects.get(key);
if (p == null) {
Log.w("Requesting unknown sound effect \"" + key + "\".");
return NULL_EFFECT;
}
return p;
}
}
@@ -1,16 +1,13 @@
package mightypork.rogue.sounds;
package mightypork.rogue.audio;
import java.nio.FloatBuffer;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import mightypork.rogue.AppAccess;
import mightypork.rogue.bus.Subsystem;
import mightypork.utils.control.interf.Updateable;
import mightypork.utils.logging.Log;
import mightypork.utils.math.Calc.Buffers;
import mightypork.utils.math.coord.Coord;
import mightypork.utils.objects.Mutable;
@@ -30,9 +27,6 @@ public class SoundSystem extends Subsystem implements Updateable {
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();
@@ -67,15 +61,20 @@ public class SoundSystem extends Subsystem implements Updateable {
buf3 = buf6 = null;
}
public static Coord getListener()
{
return listener;
}
// -- instance --
public Mutable<Double> masterVolume = new Mutable<Double>(1D);
public Mutable<Double> effectsVolume = new JointVolume(masterVolume);
public Mutable<Double> loopsVolume = new JointVolume(masterVolume);
private Map<String, EffectPlayer> effects = new HashMap<String, EffectPlayer>();
private Map<String, LoopPlayer> loops = new HashMap<String, LoopPlayer>();
private Set<AudioX> resources = new HashSet<AudioX>();
private Set<LoopPlayer> loopPlayers = new HashSet<LoopPlayer>();
private Set<DeferredAudio> resources = new HashSet<DeferredAudio>();
public SoundSystem(AppAccess app) {
@@ -86,7 +85,7 @@ public class SoundSystem extends Subsystem implements Updateable {
@Override
public final void deinit()
{
for (AudioX r : resources) {
for (DeferredAudio r : resources) {
r.destroy();
}
@@ -98,191 +97,83 @@ public class SoundSystem extends Subsystem implements Updateable {
@Override
public void update(double delta)
{
for (LoopPlayer lp : loops.values()) {
for (Updateable lp : loopPlayers) {
lp.update(delta);
}
}
public static Coord getListener()
{
return listener;
}
/**
* Register effect resource
* Create effect resource
*
* @param key sound key
* @param resource resource path
* @param pitch default pitch (1 = unchanged)
* @param gain default gain (0-1)
* @return player
*/
public void addEffect(String key, String resource, double pitch, double gain)
public EffectPlayer createEffect(String resource, double pitch, double gain)
{
EffectPlayer p = new EffectPlayer(getResource(resource), pitch, gain, effectsVolume);
effects.put(key, p);
return new EffectPlayer(getResource(resource), pitch, gain, effectsVolume);
}
/**
* Register loop resource (music / effect loop)
*
* @param key sound key
* @param resource resource path
* @param pitch default pitch (1 = unchanged)
* @param gain default gain (0-1)
* @param fadeIn default time for fadeIn
* @param fadeOut default time for fadeOut
* @return player
*/
public void addLoop(String key, String resource, double pitch, double gain, double fadeIn, double fadeOut)
public LoopPlayer createLoop(String resource, double pitch, double gain, double fadeIn, double fadeOut)
{
LoopPlayer p = new LoopPlayer(getResource(resource), pitch, gain, loopsVolume);
p.setFadeTimes(fadeIn, fadeOut);
loops.put(key, p);
loopPlayers.add(p);
return p;
}
/**
* Create {@link AudioX} for a resource
* Create {@link DeferredAudio} for a resource
*
* @param res a resource name
* @return the resource
* @throws IllegalArgumentException if resource is already registered
*/
private AudioX getResource(String res)
private DeferredAudio getResource(String res)
{
AudioX a = new AudioX(res);
DeferredAudio a = new DeferredAudio(res);
if (resources.contains(a)) throw new IllegalArgumentException("Sound resource " + res + " is already registered.");
resources.add(a);
return a;
}
/**
* Get a loop player for key
*
* @param key sound key
* @return loop player
*/
public LoopPlayer getLoop(String key)
{
LoopPlayer p = loops.get(key);
if (p == null) {
Log.w("Requesting unknown sound loop \"" + key + "\".");
return NULL_LOOP;
}
return p;
}
/**
* Get a effect player for key
*
* @param key sound key
* @return effect player
*/
public EffectPlayer getEffect(String key)
{
EffectPlayer p = effects.get(key);
if (p == null) {
Log.w("Requesting unknown sound effect \"" + key + "\".");
return NULL_EFFECT;
}
return p;
}
/**
* Fade out all loops (ie. for screen transitions)
*/
public void fadeOutAllLoops()
{
for (LoopPlayer p : loops.values()) {
for (LoopPlayer p : loopPlayers) {
p.fadeOut();
}
}
/**
* Fade in a loop (with default time)
*
* @param key sound key
*/
public void fadeInLoop(String key)
{
getLoop(key).fadeIn();
}
/**
* Fade in a loop
*
* @param key sound key
* @param seconds fade-in duration
*/
public void fadeInLoop(String key, double seconds)
{
getLoop(key).fadeIn(seconds);
}
/**
* Fade out a loop (with default time)
*
* @param key sound key
*/
public void fadeOutLoop(String key)
{
getLoop(key).fadeOut();
}
/**
* Fade out a loop
*
* @param key sound key
* @param seconds fade-out duration
*/
public void fadeOutLoop(String key, double seconds)
{
getLoop(key).fadeOut(seconds);
}
/**
* Pause a loop
*
* @param key sound key
*/
public void pauseLoop(String key)
{
getLoop(key).pause();
}
/**
* Pause all loops (leave volume unchanged)
*/
public void pauseAllLoops()
{
for (LoopPlayer p : loops.values()) {
for (LoopPlayer p : loopPlayers) {
p.pause();
}
}
/**
* Resume a loop
*
* @param key sound key
*/
public void resumeLoop(String key)
{
getLoop(key).resume();
}
/**
* Set level of master volume
*
+4 -1
View File
@@ -10,6 +10,7 @@ import mightypork.rogue.AppAdapter;
import mightypork.utils.control.bus.EventBus;
import mightypork.utils.control.bus.clients.DelegatingClient;
import mightypork.utils.control.bus.clients.ToggleableClient;
import mightypork.utils.logging.Log;
/**
@@ -57,8 +58,10 @@ public class ChildClient extends AppAdapter implements DelegatingClient, Togglea
*/
public final void addChildClient(Object client)
{
if (client != null) {
if (bus().isClientValid(client)) {
clients.add(client);
} else {
Log.w("Client rejected by bus: " + client.getClass().getSimpleName());
}
}
@@ -0,0 +1,33 @@
package mightypork.rogue.bus.events;
import mightypork.utils.control.bus.Event;
/**
* Request for action that should be performed in the main thread.
*
* @author MightyPork
*/
public class ActionRequest implements Event<ActionRequest.Listener> {
private RequestType type;
public ActionRequest(RequestType request) {
type = request;
}
@Override
public void handleBy(Listener handler)
{
handler.requestAction(type);
}
public interface Listener {
public void requestAction(RequestType request);
}
}
@@ -1,7 +1,7 @@
package mightypork.rogue.bus.events;
import mightypork.utils.control.bus.Handleable;
import mightypork.utils.control.bus.Event;
import org.lwjgl.input.Keyboard;
@@ -11,7 +11,7 @@ import org.lwjgl.input.Keyboard;
*
* @author MightyPork
*/
public class KeyboardEvent implements Handleable<KeyboardEvent.Listener> {
public class KeyboardEvent implements Event<KeyboardEvent.Listener> {
private int key;
private boolean down;
@@ -1,7 +1,7 @@
package mightypork.rogue.bus.events;
import mightypork.utils.control.bus.Handleable;
import mightypork.utils.control.bus.Event;
import mightypork.utils.math.coord.Coord;
@@ -10,7 +10,7 @@ import mightypork.utils.math.coord.Coord;
*
* @author MightyPork
*/
public class MouseButtonEvent implements Handleable<MouseButtonEvent.Listener> {
public class MouseButtonEvent implements Event<MouseButtonEvent.Listener> {
public static final int BUTTON_LEFT = 0;
public static final int BUTTON_MIDDLE = 1;
@@ -1,11 +1,11 @@
package mightypork.rogue.bus.events;
import mightypork.utils.control.bus.Handleable;
import mightypork.utils.control.bus.Event;
import mightypork.utils.math.coord.Coord;
public class MouseMotionEvent implements Handleable<MouseMotionEvent.Listener> {
public class MouseMotionEvent implements Event<MouseMotionEvent.Listener> {
private Coord move;
private Coord pos;
@@ -20,7 +20,7 @@ public class MouseMotionEvent implements Handleable<MouseMotionEvent.Listener> {
/**
* @return movement since last {@link MouseMotionEvent}
*/
public Coord getPosDelta()
public Coord getMove()
{
return move;
}
@@ -0,0 +1,7 @@
package mightypork.rogue.bus.events;
public enum RequestType
{
FULLSCREEN, SCREENSHOT, SHUTDOWN;
}
@@ -1,11 +1,11 @@
package mightypork.rogue.bus.events;
import mightypork.utils.control.bus.Handleable;
import mightypork.utils.control.bus.Event;
import mightypork.utils.math.coord.Coord;
public class ScreenChangeEvent implements Handleable<ScreenChangeEvent.Listener> {
public class ScreenChangeEvent implements Event<ScreenChangeEvent.Listener> {
private boolean fullscreen;
private Coord screenSize;
@@ -0,0 +1,28 @@
package mightypork.rogue.bus.events;
import mightypork.utils.control.bus.Event;
public class ScreenRequestEvent implements Event<ScreenRequestEvent.Listener> {
private String scrName;
public ScreenRequestEvent(String screenKey) {
scrName = screenKey;
}
@Override
public void handleBy(Listener handler)
{
handler.showScreen(scrName);
}
public interface Listener {
public void showScreen(String key);
}
}
@@ -1,22 +0,0 @@
package mightypork.rogue.display.screens;
import mightypork.rogue.AppAccess;
import mightypork.rogue.bus.Subsystem;
public class ScreenRegistry extends Subsystem {
public ScreenRegistry(AppAccess app) {
super(app);
}
@Override
protected void deinit()
{
// TODO Auto-generated method stub
}
}
@@ -1,6 +0,0 @@
package mightypork.rogue.display.screens.screenTextures;
public class ScreenTextureTest {
}
@@ -1,4 +1,4 @@
package mightypork.rogue.display.constraints;
package mightypork.rogue.gui.constraints;
import java.util.LinkedList;
@@ -1,4 +1,4 @@
package mightypork.rogue.display.constraints;
package mightypork.rogue.gui.constraints;
/**
@@ -1,4 +1,4 @@
package mightypork.rogue.display.constraints;
package mightypork.rogue.gui.constraints;
import mightypork.utils.math.constraints.ConstraintContext;
@@ -1,4 +1,4 @@
package mightypork.rogue.display;
package mightypork.rogue.gui.screens;
import java.util.LinkedList;
@@ -1,13 +1,15 @@
package mightypork.rogue.display;
package mightypork.rogue.gui.screens;
import static org.lwjgl.opengl.GL11.*;
import mightypork.rogue.AppAccess;
import mightypork.rogue.bus.Subsystem;
import mightypork.rogue.bus.ChildClient;
import mightypork.rogue.bus.events.ScreenChangeEvent;
import mightypork.rogue.input.KeyBinder;
import mightypork.rogue.input.KeyBindingPool;
import mightypork.rogue.input.KeyStroke;
import mightypork.rogue.render.Render;
import mightypork.utils.control.interf.Destroyable;
import mightypork.utils.control.interf.Updateable;
import mightypork.utils.math.constraints.ConstraintContext;
import mightypork.utils.math.coord.Coord;
@@ -21,11 +23,13 @@ import mightypork.utils.math.coord.Rect;
*
* @author MightyPork
*/
public abstract class Screen extends Subsystem implements Updateable, KeyBinder, ConstraintContext, ScreenChangeEvent.Listener {
public abstract class Screen extends ChildClient implements Destroyable, Updateable, KeyBinder, ConstraintContext, ScreenChangeEvent.Listener {
private final KeyBindingPool keybindings = new KeyBindingPool();
private boolean active;
private boolean needSetupGraphics = false;
private boolean needSetupViewport = false;
public Screen(AppAccess app) {
@@ -53,7 +57,7 @@ public abstract class Screen extends Subsystem implements Updateable, KeyBinder,
@Override
protected final void deinit()
public final void destroy()
{
deinitScreen();
}
@@ -68,8 +72,9 @@ public abstract class Screen extends Subsystem implements Updateable, KeyBinder,
{
if (shown) {
active = true;
setupGraphics();
setupViewport();
needSetupGraphics = true;
needSetupViewport = true;
onSizeChanged(getRect().getSize());
onScreenEnter();
@@ -130,51 +135,12 @@ public abstract class Screen extends Subsystem implements Updateable, KeyBinder,
protected abstract void updateScreen(double delta);
private void setupGraphics()
{
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glDisable(GL_LIGHTING);
glClearDepth(1f);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);
glEnable(GL_NORMALIZE);
glShadeModel(GL_SMOOTH);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDisable(GL_TEXTURE_2D);
setupViewport();
}
private void setupViewport()
{
// fix projection for changed size
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
Coord s = disp().getSize();
glViewport(0, 0, s.xi(), s.yi());
glOrtho(0, s.x, 0, s.y, -1000, 1000);
// back to modelview
glMatrixMode(GL_MODELVIEW);
}
/**
* Render screen
*/
private void renderBegin()
{
glPushAttrib(GL_ENABLE_BIT);
glPushMatrix();
Render.pushState();
}
@@ -183,8 +149,7 @@ public abstract class Screen extends Subsystem implements Updateable, KeyBinder,
*/
private void renderEnd()
{
glPopAttrib();
glPopMatrix();
Render.popState();
}
@@ -202,9 +167,9 @@ public abstract class Screen extends Subsystem implements Updateable, KeyBinder,
{
if (!isActive()) return;
setupViewport();
onSizeChanged(event.getScreenSize());
needSetupViewport = true;
}
@@ -215,10 +180,6 @@ public abstract class Screen extends Subsystem implements Updateable, KeyBinder,
public final void update(double delta)
{
updateScreen(delta);
renderBegin();
renderScreen();
renderEnd();
}
@@ -228,4 +189,56 @@ public abstract class Screen extends Subsystem implements Updateable, KeyBinder,
return disp().getRect();
}
public final void render()
{
if (!isActive()) return;
if (needSetupGraphics) {
setupGraphics();
}
if (needSetupViewport) {
setupViewport();
}
renderBegin();
renderScreen();
renderEnd();
}
private void setupGraphics()
{
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glDisable(GL_LIGHTING);
glClearDepth(1f);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);
glEnable(GL_NORMALIZE);
glShadeModel(GL_SMOOTH);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
}
private void setupViewport()
{
// fix projection for changed size
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
Coord s = disp().getSize();
glViewport(0, 0, s.xi(), s.yi());
glOrtho(0, s.x, s.y, 0, -1000, 1000);
// back to modelview
glMatrixMode(GL_MODELVIEW);
}
}
@@ -1,8 +1,8 @@
package mightypork.rogue.display;
package mightypork.rogue.gui.screens;
import mightypork.rogue.bus.ChildClient;
import mightypork.rogue.display.constraints.Renderable;
import mightypork.rogue.gui.constraints.Renderable;
import mightypork.utils.control.interf.Updateable;
import mightypork.utils.math.constraints.ConstraintContext;
import mightypork.utils.math.coord.Rect;
@@ -0,0 +1,55 @@
package mightypork.rogue.gui.screens;
import java.util.HashMap;
import mightypork.rogue.AppAccess;
import mightypork.rogue.bus.Subsystem;
import mightypork.rogue.bus.events.ScreenRequestEvent;
public class ScreenRegistry extends Subsystem implements ScreenRequestEvent.Listener {
private HashMap<String, Screen> screens = new HashMap<String, Screen>();
private Screen active = null;
public ScreenRegistry(AppAccess app) {
super(app);
}
public void add(String key, Screen screen)
{
screens.put(key, screen);
addChildClient(screen);
}
@Override
public void showScreen(String key)
{
Screen toshow = screens.get(key);
if (toshow == null) throw new RuntimeException("Screen " + key + " not defined.");
if (active != null) active.setActive(false);
toshow.setActive(true);
active = toshow;
}
public void render()
{
if (active != null) active.render();
}
@Override
protected void deinit()
{
// no impl
}
}
@@ -1,12 +1,12 @@
package mightypork.rogue.display.screens.screenBouncy;
package mightypork.rogue.gui.screens.screenBouncy;
import static mightypork.utils.math.constraints.ConstraintFactory.*;
import java.util.Random;
import mightypork.rogue.display.constraints.RenderableWithContext;
import mightypork.rogue.textures.Render;
import mightypork.rogue.gui.constraints.RenderableWithContext;
import mightypork.rogue.render.Render;
import mightypork.utils.control.interf.Updateable;
import mightypork.utils.math.animation.AnimDouble;
import mightypork.utils.math.animation.Easing;
@@ -55,7 +55,7 @@ public class BouncyBox implements RenderableWithContext, Updateable, ConstraintC
@Override
public void render()
{
Render.quadRect(box.getRect(), RGB.GREEN);
Render.quad(box.getRect(), RGB.GREEN);
}
@@ -1,4 +1,4 @@
package mightypork.rogue.display.screens.screenBouncy;
package mightypork.rogue.gui.screens.screenBouncy;
import static mightypork.utils.math.constraints.ConstraintFactory.*;
@@ -6,9 +6,9 @@ import static mightypork.utils.math.constraints.ConstraintFactory.*;
import java.util.ArrayList;
import java.util.List;
import mightypork.rogue.display.Screen;
import mightypork.rogue.display.ScreenLayer;
import mightypork.rogue.display.constraints.ElementHolder;
import mightypork.rogue.gui.constraints.ElementHolder;
import mightypork.rogue.gui.screens.Screen;
import mightypork.rogue.gui.screens.ScreenLayer;
import mightypork.utils.math.constraints.RectConstraint;
@@ -1,19 +1,19 @@
package mightypork.rogue.display.screens.screenBouncy;
package mightypork.rogue.gui.screens.screenBouncy;
import mightypork.rogue.AppAccess;
import mightypork.rogue.display.LayeredScreen;
import mightypork.rogue.gui.screens.LayeredScreen;
import mightypork.rogue.input.KeyStroke;
import org.lwjgl.input.Keyboard;
public class TestLayeredScreen extends LayeredScreen {
public class ScreenTestAnim extends LayeredScreen {
private LayerBouncyBoxes layer;
public TestLayeredScreen(AppAccess app) {
public ScreenTestAnim(AppAccess app) {
super(app);
layer = new LayerBouncyBoxes(this);
@@ -0,0 +1,104 @@
package mightypork.rogue.gui.screens.screenTextures;
import static mightypork.utils.math.constraints.ConstraintFactory.*;
import java.util.Random;
import mightypork.rogue.AppAccess;
import mightypork.rogue.Res;
import mightypork.rogue.bus.events.ActionRequest;
import mightypork.rogue.bus.events.MouseButtonEvent;
import mightypork.rogue.bus.events.RequestType;
import mightypork.rogue.gui.screens.Screen;
import mightypork.rogue.input.KeyStroke;
import mightypork.rogue.render.Render;
import mightypork.utils.math.animation.AnimDouble;
import mightypork.utils.math.animation.Easing;
import mightypork.utils.math.constraints.RectConstraint;
import mightypork.utils.math.coord.Coord;
import org.lwjgl.input.Keyboard;
public class ScreenTextureTest extends Screen implements MouseButtonEvent.Listener {
private RectConstraint kittenbox;
private AnimDouble s = new AnimDouble(400, Easing.SINE_BOTH);
private AnimDouble x = new AnimDouble(200, Easing.ELASTIC_OUT);
private AnimDouble y = new AnimDouble(200, Easing.ELASTIC_OUT);
private Random rand = new Random();
public ScreenTextureTest(AppAccess app) {
super(app);
kittenbox = c_move(c_box_sized(this, c_n(s), c_n(s)), c_n(x), c_n(y));
bindKeyStroke(new KeyStroke(Keyboard.KEY_ESCAPE), new Runnable() {
@Override
public void run()
{
snd().fadeOutAllLoops();
bus().schedule(new ActionRequest(RequestType.SHUTDOWN), 3);
}
});
}
@Override
protected void deinitScreen()
{
}
@Override
protected void onScreenEnter()
{
System.out.println("YOLO");
Res.getLoop("test.wilderness").fadeIn();
}
@Override
protected void onScreenLeave()
{
}
@Override
protected void renderScreen()
{
Render.quadTextured(kittenbox.getRect(), Res.getTexture("test.kitten"));
}
@Override
protected void updateScreen(double delta)
{
s.update(delta);
x.update(delta);
y.update(delta);
}
@Override
public void receive(MouseButtonEvent event)
{
if (!event.isDown()) return;
Coord pos = event.getPos();
double newSize = 200 + rand.nextInt(600);
double t = 2;
s.fadeTo(newSize, t / 2D);
x.fadeTo(pos.x - newSize / 2D, t);
y.fadeTo(pos.y - newSize / 2D, t);
}
}
+41 -15
View File
@@ -3,9 +3,11 @@ package mightypork.rogue.input;
import mightypork.rogue.AppAccess;
import mightypork.rogue.bus.Subsystem;
import mightypork.rogue.bus.events.ActionRequest;
import mightypork.rogue.bus.events.KeyboardEvent;
import mightypork.rogue.bus.events.MouseButtonEvent;
import mightypork.rogue.bus.events.MouseMotionEvent;
import mightypork.rogue.bus.events.RequestType;
import mightypork.utils.control.interf.Updateable;
import mightypork.utils.math.coord.Coord;
@@ -19,6 +21,7 @@ public class InputSystem extends Subsystem implements Updateable, KeyBinder {
// listeners
private KeyBindingPool keybindings;
private boolean yAxisDown = true;
public InputSystem(AppAccess app) {
@@ -26,8 +29,6 @@ public class InputSystem extends Subsystem implements Updateable, KeyBinder {
initDevices();
initChannels();
// global keybindings
keybindings = new KeyBindingPool();
addChildClient(keybindings);
@@ -54,14 +55,6 @@ public class InputSystem extends Subsystem implements Updateable, KeyBinder {
}
private void initChannels()
{
bus().createChannel(KeyboardEvent.class, KeyboardEvent.Listener.class);
bus().createChannel(MouseMotionEvent.class, MouseMotionEvent.Listener.class);
bus().createChannel(MouseButtonEvent.class, MouseButtonEvent.Listener.class);
}
@Override
public final void bindKeyStroke(KeyStroke stroke, Runnable task)
{
@@ -79,19 +72,35 @@ public class InputSystem extends Subsystem implements Updateable, KeyBinder {
@Override
public void update(double delta)
{
// was destroyed
if (!Display.isCreated()) return;
if (!Mouse.isCreated()) return;
if (!Keyboard.isCreated()) return;
Display.processMessages();
Coord moveSum = Coord.zero();
Coord lastPos = Coord.zero();
boolean wasMouse = false;
while (Mouse.next()) {
onMouseEvent();
onMouseEvent(moveSum, lastPos);
wasMouse = true;
}
if (wasMouse && !moveSum.isZero()) bus().queue(new MouseMotionEvent(lastPos, moveSum));
while (Keyboard.next()) {
onKeyEvent();
}
if (Display.isCloseRequested()) {
bus().queue(new ActionRequest(RequestType.SHUTDOWN));
}
}
private void onMouseEvent()
private void onMouseEvent(Coord moveSum, Coord lastPos)
{
int button = Mouse.getEventButton();
boolean down = Mouse.getEventButtonState();
@@ -99,8 +108,17 @@ public class InputSystem extends Subsystem implements Updateable, KeyBinder {
Coord move = new Coord(Mouse.getEventDX(), Mouse.getEventDY());
int wheeld = Mouse.getEventDWheel();
if (button != -1 || wheeld != 0) bus().broadcast(new MouseButtonEvent(pos, button, down, wheeld));
if (!move.isZero()) bus().broadcast(new MouseMotionEvent(pos, move));
if (yAxisDown) {
flipScrY(pos);
move.mul_ip(1, -1, 1);
}
if (button != -1 || wheeld != 0) {
bus().queue(new MouseButtonEvent(pos, button, down, wheeld));
}
moveSum.add_ip(move);
lastPos.setTo(pos);
}
@@ -109,6 +127,14 @@ public class InputSystem extends Subsystem implements Updateable, KeyBinder {
int key = Keyboard.getEventKey();
boolean down = Keyboard.getEventKeyState();
char c = Keyboard.getEventCharacter();
bus().broadcast(new KeyboardEvent(key, c, down));
bus().queue(new KeyboardEvent(key, c, down));
}
private void flipScrY(Coord c)
{
if (disp() != null) {
c.setY_ip(disp().getSize().y - c.y);
}
}
}
@@ -1,4 +1,4 @@
package mightypork.rogue.display;
package mightypork.rogue.render;
import static org.lwjgl.opengl.GL11.*;
@@ -27,8 +27,6 @@ public class DisplaySystem extends Subsystem implements ConstraintContext {
public DisplaySystem(AppAccess app) {
super(app);
initChannels();
}
@@ -39,15 +37,6 @@ public class DisplaySystem extends Subsystem implements ConstraintContext {
}
/**
* Initialize event channels
*/
private void initChannels()
{
bus().createChannel(ScreenChangeEvent.class, ScreenChangeEvent.Listener.class);
}
public void setTargetFps(int fps)
{
this.targetFps = fps;
@@ -94,7 +83,7 @@ public class DisplaySystem extends Subsystem implements ConstraintContext {
Display.update();
}
bus().broadcast(new ScreenChangeEvent(true, Display.isFullscreen(), getSize()));
bus().queue(new ScreenChangeEvent(true, Display.isFullscreen(), getSize()));
} catch (Throwable t) {
Log.e("Failed to toggle fullscreen mode.", t);
@@ -162,7 +151,7 @@ public class DisplaySystem extends Subsystem implements ConstraintContext {
{
// handle resize
if (Display.wasResized()) {
bus().broadcast(new ScreenChangeEvent(false, Display.isFullscreen(), getSize()));
bus().queue(new ScreenChangeEvent(false, Display.isFullscreen(), getSize()));
}
glLoadIdentity();
+349
View File
@@ -0,0 +1,349 @@
package mightypork.rogue.render;
import static org.lwjgl.opengl.GL11.*;
import java.io.IOException;
import mightypork.rogue.render.textures.TxQuad;
import mightypork.utils.files.FileUtils;
import mightypork.utils.logging.Log;
import mightypork.utils.math.color.RGB;
import mightypork.utils.math.coord.Coord;
import mightypork.utils.math.coord.Rect;
import org.newdawn.slick.opengl.SlickCallable;
import org.newdawn.slick.opengl.Texture;
import org.newdawn.slick.opengl.TextureImpl;
import org.newdawn.slick.opengl.TextureLoader;
import org.newdawn.slick.util.ResourceLoader;
/**
* Render utilities
*
* @author MightyPork
*/
public class Render {
private static final Coord AXIS_X = new Coord(1, 0, 0);
private static final Coord AXIS_Y = new Coord(0, 1, 0);
private static final Coord AXIS_Z = new Coord(0, 0, 1);
private static boolean inited = false;
/**
* Bind GL color
*
* @param color RGB color
*/
public static void setColor(RGB color)
{
if (color != null) glColor4d(color.r, color.g, color.b, color.a);
}
/**
* Bind GL color
*
* @param color RGB color
* @param alpha alpha multiplier
*/
public static void setColor(RGB color, double alpha)
{
if (color != null) glColor4d(color.r, color.g, color.b, color.a * alpha);
}
/**
* Translate with coord
*
* @param coord coord
*/
public static void translate(Coord coord)
{
glTranslated(coord.x, coord.y, coord.z);
}
public static void rotateX(double angle)
{
rotate(angle, AXIS_X);
}
public static void rotateY(double angle)
{
rotate(angle, AXIS_Y);
}
public static void rotateZ(double angle)
{
rotate(angle, AXIS_Z);
}
public static void rotate(double angle, Coord axis)
{
Coord vec = axis.norm(1);
glRotated(angle, vec.x, vec.y, vec.z);
}
public static void pushState()
{
SlickCallable.enterSafeBlock();
}
public static void popState()
{
SlickCallable.leaveSafeBlock();
}
/**
* Load texture
*
* @param resourcePath
* @return the loaded texture
*/
public static Texture loadTexture(String resourcePath)
{
if (!inited) {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
inited = true;
}
try {
String ext = FileUtils.getExtension(resourcePath).toUpperCase();
Log.f3("Loading texture " + ext + " at " + resourcePath);
Texture texture = TextureLoader.getTexture(ext, ResourceLoader.getResourceAsStream(resourcePath));
if (texture == null) {
Log.w("Texture " + resourcePath + " could not be loaded.");
}
return texture;
} catch (IOException e) {
Log.e("Loading of texture " + resourcePath + " failed.", e);
throw new RuntimeException("Could not load texture " + resourcePath + ".", e);
}
}
/**
* Bind texture
*
* @param texture the texture
* @throws RuntimeException if not loaded yet
*/
private static void bindTexture(Texture texture) throws RuntimeException
{
texture.bind();
}
/**
* Unbind all
*/
private static void unbindTexture()
{
if (TextureImpl.getLastBind() != null) {
TextureImpl.bindNone();
}
}
/**
* Render quad 2D
*
* @param rect rectangle
* @param color draw color
*/
public static void quad(Rect rect, RGB color)
{
setColor(color);
quad(rect);
}
/**
* Render quad
*
* @param quad the quad to draw (px)
*/
public static void quad(Rect quad)
{
double left = quad.xMin();
double bottom = quad.yMin();
double right = quad.yMax();
double top = quad.yMax();
// draw with color
unbindTexture();
// quad
glBegin(GL_QUADS);
glVertex2d(left, top);
glVertex2d(right, top);
glVertex2d(right, bottom);
glVertex2d(left, bottom);
glEnd();
}
/**
* Render textured rect (texture must be binded already)
*
* @param quad rectangle (px)
* @param uvs texture coords (0-1)
*/
private static void quadUV(Rect quad, Rect uvs)
{
double left = quad.xMin();
double bottom = quad.yMin();
double right = quad.xMax();
double top = quad.yMax();
double tleft = uvs.xMin();
double tbottom = uvs.yMin();
double tright = uvs.xMax();
double ttop = uvs.yMax();
// quad with texture
glBegin(GL_QUADS);
glTexCoord2d(tleft, ttop);
glVertex2d(left, top);
glTexCoord2d(tright, ttop);
glVertex2d(right, top);
glTexCoord2d(tright, tbottom);
glVertex2d(right, bottom);
glTexCoord2d(tleft, tbottom);
glVertex2d(left, bottom);
glEnd();
}
public static void quadGradH(Rect quad, RGB colorLeft, RGB colorRight)
{
double left = quad.xMin();
double bottom = quad.yMin();
double right = quad.yMax();
double top = quad.yMax();
// draw with color
unbindTexture();
glBegin(GL_QUADS);
setColor(colorLeft);
glVertex2d(left, top);
setColor(colorRight);
glVertex2d(right, top);
setColor(colorRight);
glVertex2d(right, bottom);
setColor(colorLeft);
glVertex2d(left, bottom);
glEnd();
}
public static void quadGradV(Rect quad, RGB colorTop, RGB colorBottom)
{
double left = quad.xMin();
double bottom = quad.yMin();
double right = quad.yMax();
double top = quad.yMax();
// draw with color
unbindTexture();
glBegin(GL_QUADS);
setColor(colorTop);
glVertex2d(left, top);
glVertex2d(right, top);
setColor(colorBottom);
glVertex2d(right, bottom);
glVertex2d(left, bottom);
glEnd();
}
/**
* Render textured rect
*
* @param quad rectangle (px)
* @param uvs texture coords rectangle (0-1)
* @param texture texture instance
* @param tint color tint
*/
public static void quadTextured(Rect quad, Rect uvs, Texture texture, RGB tint)
{
bindTexture(texture);
setColor(tint);
quadUV(quad, uvs);
}
/**
* Render textured rect
*
* @param quad rectangle (px)
* @param uvs texture coords rectangle (px)
* @param texture texture instance
*/
public static void quadTextured(Rect quad, Rect uvs, Texture texture)
{
quadTextured(quad, uvs, texture, RGB.WHITE);
}
/**
* Render textured rect
*
* @param quad rectangle (px)
* @param texture texture instance
*/
public static void quadTextured(Rect quad, Texture texture)
{
quadTextured(quad, Rect.one(), texture, RGB.WHITE);
}
/**
* Render textured rect
*
* @param quad rectangle (px)
* @param txquad texture quad
*/
public static void quadTextured(Rect quad, TxQuad txquad)
{
quadTextured(quad, txquad, RGB.WHITE);
}
/**
* Render textured rect
*
* @param quad rectangle (px)
* @param txquad texture instance
* @param tint color tint
*/
public static void quadTextured(Rect quad, TxQuad txquad, RGB tint)
{
quadTextured(quad, txquad.uvs, txquad.tx, tint);
}
}
@@ -1,12 +1,14 @@
package mightypork.rogue.textures;
package mightypork.rogue.render.textures;
import mightypork.rogue.Deferred;
import mightypork.rogue.render.Render;
import mightypork.utils.math.coord.Rect;
import org.newdawn.slick.opengl.Texture;
public class MultiTexture implements Texture {
public class MultiTexture implements Texture, Deferred {
private Texture backingTexture;
private String resourcePath;
@@ -23,17 +25,22 @@ public class MultiTexture implements Texture {
}
/**
* Attempt to load the texture.
*/
private void load()
@Override
public void load()
{
if (backingTexture == null) {
if (!isLoaded()) {
backingTexture = Render.loadTexture(resourcePath);
}
}
@Override
public boolean isLoaded()
{
return backingTexture != null;
}
@Override
public boolean hasAlpha()
{
@@ -1,11 +1,10 @@
package mightypork.rogue.textures;
package mightypork.rogue.render.textures;
import java.util.HashMap;
import mightypork.rogue.AppAccess;
import mightypork.rogue.bus.Subsystem;
import mightypork.utils.control.interf.Destroyable;
import mightypork.rogue.AppAdapter;
import mightypork.utils.math.coord.Rect;
import org.newdawn.slick.opengl.Texture;
@@ -16,9 +15,9 @@ import org.newdawn.slick.opengl.Texture;
*
* @author MightyPork
*/
public class TextureRegistry extends Subsystem implements Destroyable {
public class TextureBank extends AppAdapter {
public TextureRegistry(AppAccess app) {
public TextureBank(AppAccess app) {
super(app);
}
@@ -84,7 +83,7 @@ public class TextureRegistry extends Subsystem implements Destroyable {
* @param key quad key
* @return the quad
*/
public TxQuad getQuad(String key)
public TxQuad getTxQuad(String key)
{
TxQuad q = quads.get(key);
@@ -109,16 +108,4 @@ public class TextureRegistry extends Subsystem implements Destroyable {
return t;
}
@Override
protected void deinit()
{
for (Texture tx : textures.values()) {
tx.release();
}
textures.clear();
quads.clear();
}
}
@@ -0,0 +1,91 @@
package mightypork.rogue.render.textures;
import mightypork.utils.math.coord.Rect;
import org.newdawn.slick.opengl.Texture;
/**
* Texture Quad (describing a part of a texture)
*
* @author MightyPork
*/
public class TxQuad {
/** The texture */
public Texture tx;
/** Coords in texture (0-1) */
public Rect uvs;
/**
* TxQuad from origin and size in pixels
*
* @param tx texture
* @param xPx left top X (0-1)
* @param yPx left top Y (0-1)
* @param widthPx area width (0-1)
* @param heightPx area height (0-1)
* @return new TxQuad
*/
public static TxQuad fromSizePx(Texture tx, double xPx, double yPx, double widthPx, double heightPx)
{
double w = tx.getImageWidth();
double h = tx.getImageHeight();
return fromSize(tx, xPx / w, yPx / h, widthPx / w, heightPx / h);
}
/**
* TxQuad from origin and size 0-1
*
* @param tx texture
* @param x1 left top X (0-1)
* @param y1 left top Y (0-1)
* @param width area width (0-1)
* @param height area height (0-1)
* @return new TxQuad
*/
public static TxQuad fromSize(Texture tx, double x1, double y1, double width, double height)
{
return new TxQuad(tx, x1, y1, x1 + width, y1 + height);
}
/**
* Make of coords
*
* @param tx texture
* @param x1 left top X (0-1)
* @param y1 left top Y (0-1)
* @param x2 right bottom X (0-1)
* @param y2 right bottom Y (0-1)
*/
public TxQuad(Texture tx, double x1, double y1, double x2, double y2) {
this(tx, new Rect(x1, y1, x2, y2));
}
/**
* @param tx Texture
* @param uvs Rect of texturwe UVs (pixels - from left top)
*/
public TxQuad(Texture tx, Rect uvs) {
this.tx = tx;
this.uvs = uvs.copy();
}
public TxQuad(TxQuad txQuad) {
this.tx = txQuad.tx;
this.uvs = txQuad.uvs.copy();
}
public TxQuad copy()
{
return new TxQuad(this);
}
}
@@ -1,17 +0,0 @@
package mightypork.rogue.sounds;
public class NullAudio extends AudioX {
public NullAudio() {
super("");
}
@Override
public boolean load()
{
return false;
}
}
@@ -11,8 +11,8 @@ import java.util.Date;
import javax.imageio.ImageIO;
import mightypork.rogue.Paths;
import mightypork.rogue.display.DisplaySystem;
import mightypork.rogue.display.DisplaySystem.Screenshot;
import mightypork.rogue.render.DisplaySystem;
import mightypork.rogue.render.DisplaySystem.Screenshot;
import mightypork.utils.logging.Log;
File diff suppressed because it is too large Load Diff
-70
View File
@@ -1,70 +0,0 @@
package mightypork.rogue.textures;
import mightypork.utils.math.coord.Coord;
import mightypork.utils.math.coord.Rect;
import org.newdawn.slick.opengl.Texture;
/**
* Texture Quad (describing a part of a texture)
*
* @author MightyPork
*/
public class TxQuad {
/** The texture */
public Texture tx;
/** Coords in texture (pixels) */
public Rect uvs;
/** Quad size */
public Coord size;
/**
* Create TxQuad from left top coord and rect size
*
* @param tx texture
* @param x1 left top X
* @param y1 left top Y
* @param width area width
* @param height area height
* @return new TxQuad
*/
public static TxQuad fromSize(Texture tx, int x1, int y1, int width, int height)
{
return new TxQuad(tx, x1, y1, x1 + width, y1 + height);
}
/**
* Make of coords
*
* @param tx texture
* @param x1 x1
* @param y1 y1
* @param x2 x2
* @param y2 y2
*/
public TxQuad(Texture tx, int x1, int y1, int x2, int y2) {
this(tx, new Rect(x1, y1, x2, y2));
}
/**
* @param tx Texture
* @param uvs Rect of texturwe UVs (pixels - from left top)
*/
public TxQuad(Texture tx, Rect uvs) {
this.tx = tx;
this.uvs = uvs.copy();
this.size = uvs.getSize();
}
public TxQuad copy()
{
return new TxQuad(tx, uvs);
}
}