Attempt to separate framework from game impl.
This commit is contained in:
@@ -9,21 +9,24 @@ import java.util.logging.Level;
|
||||
|
||||
import javax.swing.JOptionPane;
|
||||
|
||||
import mightypork.rogue.bus.events.*;
|
||||
import mightypork.rogue.bus.events.ActionRequest.RequestType;
|
||||
import mightypork.rogue.gui.screens.ScreenRegistry;
|
||||
import mightypork.rogue.gui.screens.test_bouncyboxes.ScreenTestBouncy;
|
||||
import mightypork.rogue.gui.screens.test_cat_sound.ScreenTestCat;
|
||||
import mightypork.rogue.gui.screens.test_font.ScreenTestFont;
|
||||
import mightypork.rogue.input.InputSystem;
|
||||
import mightypork.rogue.input.KeyStroke;
|
||||
import mightypork.rogue.input.Keys;
|
||||
import mightypork.rogue.render.DisplaySystem;
|
||||
import mightypork.rogue.sounds.SoundSystem;
|
||||
import mightypork.rogue.util.SlickLogRedirector;
|
||||
import mightypork.utils.control.bus.EventBus;
|
||||
import mightypork.utils.control.interf.Destroyable;
|
||||
import mightypork.utils.control.interf.Updateable;
|
||||
import mightypork.gamecore.AppAccess;
|
||||
import mightypork.gamecore.GameLoop;
|
||||
import mightypork.gamecore.SlickLogRedirector;
|
||||
import mightypork.gamecore.control.bus.EventBus;
|
||||
import mightypork.gamecore.control.bus.events.*;
|
||||
import mightypork.gamecore.control.interf.Destroyable;
|
||||
import mightypork.gamecore.control.interf.Updateable;
|
||||
import mightypork.gamecore.gui.screens.ScreenRegistry;
|
||||
import mightypork.gamecore.input.InputSystem;
|
||||
import mightypork.gamecore.input.KeyStroke;
|
||||
import mightypork.gamecore.input.Keys;
|
||||
import mightypork.gamecore.render.DisplaySystem;
|
||||
import mightypork.gamecore.resources.sounds.SoundSystem;
|
||||
import mightypork.rogue.events.ActionRequest;
|
||||
import mightypork.rogue.events.ActionRequest.RequestType;
|
||||
import mightypork.rogue.screens.test_bouncyboxes.ScreenTestBouncy;
|
||||
import mightypork.rogue.screens.test_cat_sound.ScreenTestCat;
|
||||
import mightypork.rogue.screens.test_font.ScreenTestFont;
|
||||
import mightypork.utils.logging.Log;
|
||||
import mightypork.utils.logging.LogInstance;
|
||||
|
||||
@@ -43,7 +46,7 @@ public class App implements AppAccess {
|
||||
private DisplaySystem displaySystem;
|
||||
private static SoundSystem soundSystem;
|
||||
private EventBus eventBus;
|
||||
private MainLoop mainLoop;
|
||||
private GameLoop mainLoop;
|
||||
private ScreenRegistry screens;
|
||||
|
||||
|
||||
|
||||
@@ -1,47 +0,0 @@
|
||||
package mightypork.rogue;
|
||||
|
||||
|
||||
import mightypork.rogue.input.InputSystem;
|
||||
import mightypork.rogue.render.DisplaySystem;
|
||||
import mightypork.rogue.sounds.SoundSystem;
|
||||
import mightypork.utils.control.bus.EventBus;
|
||||
|
||||
|
||||
/**
|
||||
* App interface visible to subsystems
|
||||
*
|
||||
* @author MightyPork
|
||||
*/
|
||||
public interface AppAccess {
|
||||
|
||||
/**
|
||||
* @return sound system
|
||||
*/
|
||||
abstract SoundSystem snd();
|
||||
|
||||
|
||||
/**
|
||||
* @return input system
|
||||
*/
|
||||
abstract InputSystem input();
|
||||
|
||||
|
||||
/**
|
||||
* @return display system
|
||||
*/
|
||||
abstract DisplaySystem disp();
|
||||
|
||||
|
||||
/**
|
||||
* @return event bus
|
||||
*/
|
||||
abstract EventBus bus();
|
||||
|
||||
|
||||
/**
|
||||
* Quit to OS<br>
|
||||
* Destroy app & exit VM
|
||||
*/
|
||||
abstract void shutdown();
|
||||
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
package mightypork.rogue;
|
||||
|
||||
|
||||
import mightypork.rogue.input.InputSystem;
|
||||
import mightypork.rogue.render.DisplaySystem;
|
||||
import mightypork.rogue.sounds.SoundSystem;
|
||||
import mightypork.utils.control.bus.EventBus;
|
||||
|
||||
|
||||
/**
|
||||
* App access adapter
|
||||
*
|
||||
* @author MightyPork
|
||||
*/
|
||||
public class AppAdapter implements AppAccess {
|
||||
|
||||
private final AppAccess app;
|
||||
|
||||
|
||||
public AppAdapter(AppAccess app) {
|
||||
if (app == null) throw new NullPointerException("AppAccess instance cannot be null.");
|
||||
|
||||
this.app = app;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public final SoundSystem snd()
|
||||
{
|
||||
return app.snd();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public final InputSystem input()
|
||||
{
|
||||
return app.input();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public final DisplaySystem disp()
|
||||
{
|
||||
return app.disp();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public final EventBus bus()
|
||||
{
|
||||
return app.bus();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void shutdown()
|
||||
{
|
||||
app.shutdown();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,24 +1,17 @@
|
||||
package mightypork.rogue;
|
||||
|
||||
|
||||
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.ActionRequest.RequestType;
|
||||
import mightypork.rogue.bus.events.MainLoopTaskRequest;
|
||||
import mightypork.rogue.bus.events.UpdateEvent;
|
||||
import mightypork.rogue.render.Renderable;
|
||||
import mightypork.rogue.tasks.TaskTakeScreenshot;
|
||||
import mightypork.gamecore.GameLoop;
|
||||
import mightypork.gamecore.input.Action;
|
||||
import mightypork.gamecore.render.Renderable;
|
||||
import mightypork.rogue.events.ActionRequest;
|
||||
import mightypork.rogue.events.ActionRequest.RequestType;
|
||||
import mightypork.rogue.util.Utils;
|
||||
import mightypork.utils.control.timing.TimerDelta;
|
||||
|
||||
|
||||
public class MainLoop extends Subsystem implements ActionRequest.Listener, MainLoopTaskRequest.Listener {
|
||||
public class MainLoop extends GameLoop implements ActionRequest.Listener {
|
||||
|
||||
private final Queue<Runnable> taskQueue = new ConcurrentLinkedQueue<Runnable>();
|
||||
private final Renderable renderable;
|
||||
final Renderable renderable;
|
||||
|
||||
|
||||
public MainLoop(App app, Renderable masterRenderable) {
|
||||
@@ -31,36 +24,11 @@ public class MainLoop extends Subsystem implements ActionRequest.Listener, MainL
|
||||
this.renderable = masterRenderable;
|
||||
}
|
||||
|
||||
/** timer */
|
||||
private TimerDelta timer;
|
||||
private boolean running = true;
|
||||
|
||||
|
||||
public void start()
|
||||
{
|
||||
timer = new TimerDelta();
|
||||
|
||||
while (running) {
|
||||
disp().beginFrame();
|
||||
|
||||
bus().send(new UpdateEvent(timer.getDelta()));
|
||||
|
||||
Runnable r;
|
||||
while ((r = taskQueue.poll()) != null) {
|
||||
r.run();
|
||||
}
|
||||
|
||||
renderable.render();
|
||||
|
||||
disp().endFrame();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void deinit()
|
||||
protected void tick()
|
||||
{
|
||||
running = false;
|
||||
renderable.render();
|
||||
}
|
||||
|
||||
|
||||
@@ -82,10 +50,10 @@ public class MainLoop extends Subsystem implements ActionRequest.Listener, MainL
|
||||
}
|
||||
|
||||
/** Take a screenshot */
|
||||
private final Runnable taskScreenshot = new Runnable() {
|
||||
private final Action taskScreenshot = new Action() {
|
||||
|
||||
@Override
|
||||
public void run()
|
||||
public void execute()
|
||||
{
|
||||
Res.getEffect("gui.shutter").play(1);
|
||||
Utils.runAsThread(new TaskTakeScreenshot(disp()));
|
||||
@@ -93,29 +61,22 @@ public class MainLoop extends Subsystem implements ActionRequest.Listener, MainL
|
||||
};
|
||||
|
||||
/** Shutdown the application */
|
||||
private final Runnable taskShutdown = new Runnable() {
|
||||
private final Action taskShutdown = new Action() {
|
||||
|
||||
@Override
|
||||
public void run()
|
||||
public void execute()
|
||||
{
|
||||
shutdown();
|
||||
}
|
||||
};
|
||||
|
||||
/** Toggle fullscreen */
|
||||
private final Runnable taskFullscreen = new Runnable() {
|
||||
private final Action taskFullscreen = new Action() {
|
||||
|
||||
@Override
|
||||
public void run()
|
||||
public void execute()
|
||||
{
|
||||
disp().switchFullscreen();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@Override
|
||||
public synchronized void queueTask(Runnable request)
|
||||
{
|
||||
taskQueue.add(request);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,18 +1,19 @@
|
||||
package mightypork.rogue;
|
||||
|
||||
|
||||
import mightypork.rogue.fonts.DeferredFont;
|
||||
import mightypork.rogue.fonts.DeferredFont.FontStyle;
|
||||
import mightypork.rogue.fonts.FontBank;
|
||||
import mightypork.rogue.fonts.GLFont;
|
||||
import mightypork.rogue.loading.AsyncResourceLoader;
|
||||
import mightypork.rogue.sounds.SoundBank;
|
||||
import mightypork.rogue.sounds.players.EffectPlayer;
|
||||
import mightypork.rogue.sounds.players.LoopPlayer;
|
||||
import mightypork.rogue.textures.FilteredTexture.Filter;
|
||||
import mightypork.rogue.textures.FilteredTexture.Wrap;
|
||||
import mightypork.rogue.textures.TextureBank;
|
||||
import mightypork.rogue.textures.TxQuad;
|
||||
import mightypork.gamecore.AppAccess;
|
||||
import mightypork.gamecore.loading.AsyncResourceLoader;
|
||||
import mightypork.gamecore.resources.fonts.DeferredFont;
|
||||
import mightypork.gamecore.resources.fonts.DeferredFont.FontStyle;
|
||||
import mightypork.gamecore.resources.fonts.FontBank;
|
||||
import mightypork.gamecore.resources.fonts.GLFont;
|
||||
import mightypork.gamecore.resources.sounds.SoundBank;
|
||||
import mightypork.gamecore.resources.sounds.players.EffectPlayer;
|
||||
import mightypork.gamecore.resources.sounds.players.LoopPlayer;
|
||||
import mightypork.gamecore.resources.textures.FilteredTexture.Filter;
|
||||
import mightypork.gamecore.resources.textures.FilteredTexture.Wrap;
|
||||
import mightypork.gamecore.resources.textures.TextureBank;
|
||||
import mightypork.gamecore.resources.textures.TxQuad;
|
||||
|
||||
import org.newdawn.slick.opengl.Texture;
|
||||
|
||||
|
||||
+4
-24
@@ -1,18 +1,14 @@
|
||||
package mightypork.rogue.tasks;
|
||||
package mightypork.rogue;
|
||||
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
|
||||
import mightypork.rogue.Paths;
|
||||
import mightypork.rogue.render.DisplaySystem;
|
||||
import mightypork.rogue.render.DisplaySystem.Screenshot;
|
||||
import mightypork.gamecore.render.DisplaySystem;
|
||||
import mightypork.gamecore.render.DisplaySystem.Screenshot;
|
||||
import mightypork.utils.logging.Log;
|
||||
|
||||
|
||||
@@ -29,20 +25,6 @@ public class TaskTakeScreenshot implements Runnable {
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
|
||||
final BufferedImage image = new BufferedImage(scr.width, scr.height, BufferedImage.TYPE_INT_RGB);
|
||||
|
||||
// convert to a buffered image
|
||||
for (int x = 0; x < scr.width; x++) {
|
||||
for (int y = 0; y < scr.height; y++) {
|
||||
final int i = (x + (scr.width * y)) * scr.bpp;
|
||||
final int r = scr.bytes.get(i) & 0xFF;
|
||||
final int g = scr.bytes.get(i + 1) & 0xFF;
|
||||
final int b = scr.bytes.get(i + 2) & 0xFF;
|
||||
image.setRGB(x, scr.height - (y + 1), (0xFF << 24) | (r << 16) | (g << 8) | b);
|
||||
}
|
||||
}
|
||||
|
||||
final String fname = getUniqueScreenshotName();
|
||||
|
||||
// generate unique filename
|
||||
@@ -56,11 +38,9 @@ public class TaskTakeScreenshot implements Runnable {
|
||||
|
||||
Log.f3("Saving screenshot to file: " + file);
|
||||
|
||||
final String format = "PNG";
|
||||
|
||||
// save to disk
|
||||
try {
|
||||
ImageIO.write(image, format, file);
|
||||
scr.save(file);
|
||||
} catch (final IOException e) {
|
||||
Log.e("Failed to save screenshot.", e);
|
||||
}
|
||||
@@ -1,100 +0,0 @@
|
||||
package mightypork.rogue.bus;
|
||||
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import mightypork.rogue.AppAccess;
|
||||
import mightypork.rogue.AppAdapter;
|
||||
import mightypork.utils.control.bus.EventBus;
|
||||
import mightypork.utils.control.bus.clients.DelegatingClient;
|
||||
import mightypork.utils.control.bus.clients.ToggleableClient;
|
||||
|
||||
|
||||
/**
|
||||
* Client that can be attached to the {@link EventBus}, or added as a child
|
||||
* client to another {@link DelegatingClient}
|
||||
*
|
||||
* @author MightyPork
|
||||
*/
|
||||
public class ChildClient extends AppAdapter implements DelegatingClient, ToggleableClient {
|
||||
|
||||
public ChildClient(AppAccess app) {
|
||||
super(app);
|
||||
}
|
||||
|
||||
private final Set<Object> clients = new LinkedHashSet<Object>();
|
||||
private boolean listening = true;
|
||||
private boolean delegating = true;
|
||||
|
||||
|
||||
@Override
|
||||
public final Collection<Object> getChildClients()
|
||||
{
|
||||
return clients;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public final boolean doesDelegate()
|
||||
{
|
||||
return delegating;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean isListening()
|
||||
{
|
||||
return listening;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Add a child subscriber to the {@link EventBus}.<br>
|
||||
*
|
||||
* @param client
|
||||
*/
|
||||
public final void addChildClient(Object client)
|
||||
{
|
||||
if (bus().isClientValid(client)) {
|
||||
clients.add(client);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Remove a child subscriber
|
||||
*
|
||||
* @param client subscriber to remove
|
||||
*/
|
||||
public final void removeChildClient(Object client)
|
||||
{
|
||||
if (client != null) {
|
||||
clients.remove(client);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set whether events should be received.
|
||||
*
|
||||
* @param listening receive events
|
||||
*/
|
||||
public final void setListening(boolean listening)
|
||||
{
|
||||
this.listening = listening;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set whether events should be passed on to child nodes
|
||||
*
|
||||
* @param delegating
|
||||
*/
|
||||
public final void setDelegating(boolean delegating)
|
||||
{
|
||||
this.delegating = delegating;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
package mightypork.rogue.bus;
|
||||
|
||||
|
||||
import mightypork.rogue.AppAccess;
|
||||
import mightypork.utils.control.interf.Destroyable;
|
||||
|
||||
|
||||
/**
|
||||
* App event bus client, to be used for subsystems, screens and anything that
|
||||
* needs access to the eventbus
|
||||
*
|
||||
* @author MightyPork
|
||||
*/
|
||||
public abstract class Subsystem extends ChildClient implements Destroyable {
|
||||
|
||||
public Subsystem(AppAccess app) {
|
||||
super(app);
|
||||
|
||||
bus().subscribe(this);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public final void destroy()
|
||||
{
|
||||
deinit();
|
||||
|
||||
bus().unsubscribe(this);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Deinitialize the subsystem<br>
|
||||
* (called during destruction)
|
||||
*/
|
||||
protected abstract void deinit();
|
||||
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
package mightypork.rogue.bus.events;
|
||||
|
||||
|
||||
import mightypork.utils.control.bus.events.Event;
|
||||
import mightypork.utils.control.bus.events.types.ImmediateEvent;
|
||||
import mightypork.utils.control.interf.Destroyable;
|
||||
|
||||
|
||||
/**
|
||||
* Invoke destroy() method of all subscribers. Used to deinit a system.
|
||||
*
|
||||
* @author MightyPork
|
||||
*/
|
||||
@ImmediateEvent
|
||||
public class DestroyEvent implements Event<Destroyable> {
|
||||
|
||||
@Override
|
||||
public void handleBy(Destroyable handler)
|
||||
{
|
||||
handler.destroy();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,87 +0,0 @@
|
||||
package mightypork.rogue.bus.events;
|
||||
|
||||
|
||||
import mightypork.utils.control.bus.events.Event;
|
||||
|
||||
import org.lwjgl.input.Keyboard;
|
||||
|
||||
|
||||
/**
|
||||
* A keyboard event
|
||||
*
|
||||
* @author MightyPork
|
||||
*/
|
||||
public class KeyboardEvent implements Event<KeyboardEvent.Listener> {
|
||||
|
||||
private final int key;
|
||||
private final boolean down;
|
||||
private final char c;
|
||||
|
||||
|
||||
public KeyboardEvent(int key, char c, boolean down) {
|
||||
this.key = key;
|
||||
this.c = c;
|
||||
this.down = down;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return key code (see {@link org.lwjgl.input.Keyboard})
|
||||
*/
|
||||
public int getKey()
|
||||
{
|
||||
return key;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return true if key was just pressed
|
||||
*/
|
||||
public boolean isDown()
|
||||
{
|
||||
return down;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return true if key was just released
|
||||
*/
|
||||
public boolean isUp()
|
||||
{
|
||||
return !down;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return event character (if any)
|
||||
*/
|
||||
public char getChar()
|
||||
{
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void handleBy(Listener keh)
|
||||
{
|
||||
keh.receive(this);
|
||||
}
|
||||
|
||||
public interface Listener {
|
||||
|
||||
/**
|
||||
* Handle an event
|
||||
*
|
||||
* @param event event
|
||||
*/
|
||||
void receive(KeyboardEvent event);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return Keyboard.getKeyName(key) + ":" + (down ? "DOWN" : "UP");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
package mightypork.rogue.bus.events;
|
||||
|
||||
|
||||
import mightypork.utils.control.bus.events.Event;
|
||||
import mightypork.utils.control.bus.events.types.SingleReceiverEvent;
|
||||
|
||||
|
||||
/**
|
||||
* Request to execute given {@link Runnable} in main loop.
|
||||
*
|
||||
* @author MightyPork
|
||||
*/
|
||||
@SingleReceiverEvent
|
||||
public class MainLoopTaskRequest implements Event<MainLoopTaskRequest.Listener> {
|
||||
|
||||
private final Runnable task;
|
||||
|
||||
|
||||
public MainLoopTaskRequest(Runnable task) {
|
||||
this.task = task;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void handleBy(Listener handler)
|
||||
{
|
||||
handler.queueTask(task);
|
||||
}
|
||||
|
||||
public interface Listener {
|
||||
|
||||
/**
|
||||
* Perform the requested action
|
||||
*
|
||||
* @param request
|
||||
*/
|
||||
void queueTask(Runnable request);
|
||||
}
|
||||
}
|
||||
@@ -1,119 +0,0 @@
|
||||
package mightypork.rogue.bus.events;
|
||||
|
||||
|
||||
import mightypork.utils.control.bus.events.Event;
|
||||
import mightypork.utils.math.coord.Coord;
|
||||
|
||||
|
||||
/**
|
||||
* Mouse button / wheel event triggered
|
||||
*
|
||||
* @author MightyPork
|
||||
*/
|
||||
public class MouseButtonEvent implements Event<MouseButtonEvent.Listener> {
|
||||
|
||||
public static final int BUTTON_LEFT = 0;
|
||||
public static final int BUTTON_MIDDLE = 1;
|
||||
public static final int BUTTON_RIGHT = 2;
|
||||
|
||||
private final int button;
|
||||
private final int wheeld;
|
||||
private final Coord pos;
|
||||
private final boolean down;
|
||||
|
||||
|
||||
/**
|
||||
* Mouse button event
|
||||
*
|
||||
* @param pos event position
|
||||
* @param button button id
|
||||
* @param down button pressed
|
||||
* @param wheeld wheel change
|
||||
*/
|
||||
public MouseButtonEvent(Coord pos, int button, boolean down, int wheeld) {
|
||||
this.button = button;
|
||||
this.down = down;
|
||||
this.pos = pos;
|
||||
this.wheeld = wheeld;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return true if the event was caused by a button state change
|
||||
*/
|
||||
public boolean isButtonEvent()
|
||||
{
|
||||
return button != -1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return true if the event was caused by a wheel change
|
||||
*/
|
||||
public boolean isWheelEvent()
|
||||
{
|
||||
return wheeld != 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return button id or -1 if none was pressed
|
||||
*/
|
||||
public int getButton()
|
||||
{
|
||||
return button;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return number of steps the wheel changed since last event
|
||||
*/
|
||||
public int getWheelDelta()
|
||||
{
|
||||
return wheeld;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return mouse position when the event occurred
|
||||
*/
|
||||
public Coord getPos()
|
||||
{
|
||||
return pos;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return true if button was just pressed
|
||||
*/
|
||||
public boolean isDown()
|
||||
{
|
||||
return button != -1 && down;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return true if button was just released
|
||||
*/
|
||||
public boolean isUp()
|
||||
{
|
||||
return button != -1 && !down;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void handleBy(Listener handler)
|
||||
{
|
||||
handler.receive(this);
|
||||
}
|
||||
|
||||
public interface Listener {
|
||||
|
||||
/**
|
||||
* Handle an event
|
||||
*
|
||||
* @param event event
|
||||
*/
|
||||
void receive(MouseButtonEvent event);
|
||||
}
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
package mightypork.rogue.bus.events;
|
||||
|
||||
|
||||
import mightypork.utils.control.bus.events.Event;
|
||||
import mightypork.utils.control.bus.events.types.UnloggedEvent;
|
||||
import mightypork.utils.math.coord.Coord;
|
||||
|
||||
|
||||
/**
|
||||
* Mouse moved
|
||||
*
|
||||
* @author MightyPork
|
||||
*/
|
||||
@UnloggedEvent
|
||||
public class MouseMotionEvent implements Event<MouseMotionEvent.Listener> {
|
||||
|
||||
private final Coord move;
|
||||
private final Coord pos;
|
||||
|
||||
|
||||
public MouseMotionEvent(Coord pos, Coord move) {
|
||||
this.move = move;
|
||||
this.pos = pos;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return movement since last {@link MouseMotionEvent}
|
||||
*/
|
||||
public Coord getMove()
|
||||
{
|
||||
return move;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return current mouse position
|
||||
*/
|
||||
public Coord getPos()
|
||||
{
|
||||
return pos;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void handleBy(Listener keh)
|
||||
{
|
||||
keh.receive(this);
|
||||
}
|
||||
|
||||
public interface Listener {
|
||||
|
||||
/**
|
||||
* Handle an event
|
||||
*
|
||||
* @param event event
|
||||
*/
|
||||
void receive(MouseMotionEvent event);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
package mightypork.rogue.bus.events;
|
||||
|
||||
|
||||
import mightypork.rogue.loading.DeferredResource;
|
||||
import mightypork.utils.control.bus.events.Event;
|
||||
import mightypork.utils.control.bus.events.types.SingleReceiverEvent;
|
||||
|
||||
|
||||
/**
|
||||
* Request to schedule loading a deferred resource.
|
||||
*
|
||||
* @author MightyPork
|
||||
*/
|
||||
@SingleReceiverEvent
|
||||
public class ResourceLoadRequest implements Event<ResourceLoadRequest.Listener> {
|
||||
|
||||
private final DeferredResource resource;
|
||||
|
||||
|
||||
public ResourceLoadRequest(DeferredResource resource) {
|
||||
this.resource = resource;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void handleBy(Listener handler)
|
||||
{
|
||||
handler.loadResource(resource);
|
||||
}
|
||||
|
||||
public interface Listener {
|
||||
|
||||
/**
|
||||
* Load a resource
|
||||
*
|
||||
* @param resource
|
||||
*/
|
||||
void loadResource(DeferredResource resource);
|
||||
}
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
package mightypork.rogue.bus.events;
|
||||
|
||||
|
||||
import mightypork.utils.control.bus.events.Event;
|
||||
import mightypork.utils.math.coord.Coord;
|
||||
|
||||
|
||||
/**
|
||||
* Screen resolution or mode was changed
|
||||
*
|
||||
* @author MightyPork
|
||||
*/
|
||||
public class ScreenChangeEvent implements Event<ScreenChangeEvent.Listener> {
|
||||
|
||||
private final boolean fullscreen;
|
||||
private final Coord screenSize;
|
||||
private final boolean fsChanged;
|
||||
|
||||
|
||||
public ScreenChangeEvent(boolean fsChanged, boolean fullscreen, Coord size) {
|
||||
this.fullscreen = fullscreen;
|
||||
this.screenSize = size;
|
||||
this.fsChanged = fsChanged;
|
||||
}
|
||||
|
||||
|
||||
public boolean isFullscreen()
|
||||
{
|
||||
return fullscreen;
|
||||
}
|
||||
|
||||
|
||||
public boolean fullscreenChanged()
|
||||
{
|
||||
return fsChanged;
|
||||
}
|
||||
|
||||
|
||||
public Coord getScreenSize()
|
||||
{
|
||||
return screenSize;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void handleBy(Listener handler)
|
||||
{
|
||||
handler.receive(this);
|
||||
}
|
||||
|
||||
public interface Listener {
|
||||
|
||||
void receive(ScreenChangeEvent event);
|
||||
}
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
package mightypork.rogue.bus.events;
|
||||
|
||||
|
||||
import mightypork.utils.control.bus.events.Event;
|
||||
import mightypork.utils.control.bus.events.types.SingleReceiverEvent;
|
||||
|
||||
|
||||
/**
|
||||
* Request to change screen
|
||||
*
|
||||
* @author MightyPork
|
||||
*/
|
||||
@SingleReceiverEvent
|
||||
public class ScreenRequestEvent implements Event<ScreenRequestEvent.Listener> {
|
||||
|
||||
private final String scrName;
|
||||
|
||||
|
||||
public ScreenRequestEvent(String screenKey) {
|
||||
scrName = screenKey;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void handleBy(Listener handler)
|
||||
{
|
||||
handler.showScreen(scrName);
|
||||
}
|
||||
|
||||
public interface Listener {
|
||||
|
||||
void showScreen(String key);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
package mightypork.rogue.bus.events;
|
||||
|
||||
|
||||
import mightypork.utils.control.bus.events.Event;
|
||||
import mightypork.utils.control.bus.events.types.ImmediateEvent;
|
||||
import mightypork.utils.control.bus.events.types.UnloggedEvent;
|
||||
import mightypork.utils.control.interf.Updateable;
|
||||
|
||||
|
||||
/**
|
||||
* Delta timing update event
|
||||
*
|
||||
* @author MightyPork
|
||||
*/
|
||||
// sending via queue would hog the bus
|
||||
@ImmediateEvent
|
||||
@UnloggedEvent
|
||||
public class UpdateEvent implements Event<Updateable> {
|
||||
|
||||
private final double deltaTime;
|
||||
|
||||
|
||||
/**
|
||||
* @param deltaTime time since last update (sec)
|
||||
*/
|
||||
public UpdateEvent(double deltaTime) {
|
||||
this.deltaTime = deltaTime;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void handleBy(Updateable handler)
|
||||
{
|
||||
handler.update(deltaTime);
|
||||
}
|
||||
}
|
||||
+3
-3
@@ -1,8 +1,8 @@
|
||||
package mightypork.rogue.bus.events;
|
||||
package mightypork.rogue.events;
|
||||
|
||||
|
||||
import mightypork.utils.control.bus.events.Event;
|
||||
import mightypork.utils.control.bus.events.types.SingleReceiverEvent;
|
||||
import mightypork.gamecore.control.bus.events.Event;
|
||||
import mightypork.gamecore.control.bus.events.types.SingleReceiverEvent;
|
||||
|
||||
|
||||
/**
|
||||
@@ -1,188 +0,0 @@
|
||||
package mightypork.rogue.fonts;
|
||||
|
||||
|
||||
import java.awt.Font;
|
||||
import java.awt.FontFormatException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
import mightypork.rogue.loading.BaseDeferredResource;
|
||||
import mightypork.rogue.loading.MustLoadInMainThread;
|
||||
import mightypork.utils.files.FileUtils;
|
||||
import mightypork.utils.logging.LoggedName;
|
||||
import mightypork.utils.math.color.RGB;
|
||||
import mightypork.utils.math.coord.Coord;
|
||||
|
||||
|
||||
/**
|
||||
* Font obtained from a resource file (TTF).
|
||||
*
|
||||
* @author MightyPork
|
||||
*/
|
||||
@MustLoadInMainThread
|
||||
@LoggedName(name = "Font")
|
||||
public class DeferredFont extends BaseDeferredResource implements GLFont {
|
||||
|
||||
public static enum FontStyle
|
||||
{
|
||||
PLAIN(Font.PLAIN), BOLD(Font.BOLD), ITALIC(Font.ITALIC), BOLD_ITALIC(Font.BOLD + Font.ITALIC);
|
||||
|
||||
int numeric;
|
||||
|
||||
|
||||
private FontStyle(int style) {
|
||||
this.numeric = style;
|
||||
}
|
||||
}
|
||||
|
||||
private SlickFont font = null;
|
||||
private final double size;
|
||||
private final FontStyle style;
|
||||
private final boolean antiAlias;
|
||||
private final String extraChars;
|
||||
|
||||
|
||||
/**
|
||||
* A font from resource
|
||||
*
|
||||
* @param resourcePath resource to load
|
||||
* @param extraChars extra chars (0-255 loaded by default)
|
||||
* @param size size (px)
|
||||
*/
|
||||
public DeferredFont(String resourcePath, String extraChars, double size) {
|
||||
this(resourcePath, extraChars, size, FontStyle.PLAIN, true);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A font from resource
|
||||
*
|
||||
* @param resourcePath resource to load
|
||||
* @param extraChars extra chars (0-255 loaded by default)
|
||||
* @param size size (pt)
|
||||
* @param style font style
|
||||
*/
|
||||
public DeferredFont(String resourcePath, String extraChars, double size, FontStyle style) {
|
||||
this(resourcePath, extraChars, size, style, true);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A font from resource
|
||||
*
|
||||
* @param resourcePath resource to load
|
||||
* @param extraChars extra chars (0-255 loaded by default)
|
||||
* @param size size (pt)
|
||||
* @param style font style
|
||||
* @param antialias use antialiasing
|
||||
*/
|
||||
public DeferredFont(String resourcePath, String extraChars, double size, FontStyle style, boolean antialias) {
|
||||
super(resourcePath);
|
||||
this.size = size;
|
||||
this.style = style;
|
||||
this.antiAlias = antialias;
|
||||
this.extraChars = extraChars;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected final void loadResource(String path) throws FontFormatException, IOException
|
||||
{
|
||||
final Font awtFont = getAwtFont(path, (float) size, style.numeric);
|
||||
|
||||
font = new SlickFont(awtFont, antiAlias, extraChars);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get a font for a resource path / name
|
||||
*
|
||||
* @param resource resource to load
|
||||
* @param size font size (pt)
|
||||
* @param style font style
|
||||
* @return the {@link Font}
|
||||
* @throws FontFormatException
|
||||
* @throws IOException
|
||||
*/
|
||||
protected Font getAwtFont(String resource, float size, int style) throws FontFormatException, IOException
|
||||
{
|
||||
InputStream in = null;
|
||||
|
||||
try {
|
||||
|
||||
in = FileUtils.getResource(resource);
|
||||
|
||||
Font awtFont = Font.createFont(Font.TRUETYPE_FONT, in);
|
||||
|
||||
awtFont = awtFont.deriveFont(size);
|
||||
awtFont = awtFont.deriveFont(style);
|
||||
|
||||
return awtFont;
|
||||
|
||||
} finally {
|
||||
try {
|
||||
if (in != null) in.close();
|
||||
} catch (final IOException e) {
|
||||
//pass
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Draw string
|
||||
*
|
||||
* @param str string to draw
|
||||
* @param color draw color
|
||||
*/
|
||||
@Override
|
||||
public void draw(String str, RGB color)
|
||||
{
|
||||
if (!ensureLoaded()) return;
|
||||
|
||||
font.draw(str, color);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get size needed to render give string
|
||||
*
|
||||
* @param text string to check
|
||||
* @return coord (width, height)
|
||||
*/
|
||||
@Override
|
||||
public Coord getNeededSpace(String text)
|
||||
{
|
||||
if (!ensureLoaded()) return Coord.zero();
|
||||
|
||||
return font.getNeededSpace(text);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return font height
|
||||
*/
|
||||
@Override
|
||||
public int getHeight()
|
||||
{
|
||||
if (!ensureLoaded()) return 0;
|
||||
|
||||
return font.getHeight();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int getWidth(String text)
|
||||
{
|
||||
return font.getWidth(text);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void destroy()
|
||||
{
|
||||
// this will have to suffice
|
||||
font = null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,64 +0,0 @@
|
||||
package mightypork.rogue.fonts;
|
||||
|
||||
|
||||
import java.awt.Font;
|
||||
import java.awt.FontFormatException;
|
||||
import java.io.IOException;
|
||||
|
||||
import mightypork.utils.logging.LoggedName;
|
||||
|
||||
|
||||
/**
|
||||
* Font obtained from the OS
|
||||
*
|
||||
* @author MightyPork
|
||||
*/
|
||||
@LoggedName(name = "FontNative")
|
||||
public class DeferredFontNative extends DeferredFont {
|
||||
|
||||
/**
|
||||
* A font from OS, found by name
|
||||
*
|
||||
* @param fontName font family name
|
||||
* @param extraChars extra chars (0-255 loaded by default)
|
||||
* @param size size (pt)
|
||||
*/
|
||||
public DeferredFontNative(String fontName, String extraChars, double size) {
|
||||
super(fontName, extraChars, size);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A font from OS, found by name
|
||||
*
|
||||
* @param fontName font family name
|
||||
* @param extraChars extra chars (0-255 loaded by default)
|
||||
* @param size size (pt)
|
||||
* @param style font style
|
||||
*/
|
||||
public DeferredFontNative(String fontName, String extraChars, double size, FontStyle style) {
|
||||
super(fontName, extraChars, size, style);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A font from OS, found by name
|
||||
*
|
||||
* @param fontName font family name
|
||||
* @param extraChars extra chars (0-255 loaded by default)
|
||||
* @param size size (pt)
|
||||
* @param style font style
|
||||
* @param antialias use antialiasing
|
||||
*/
|
||||
public DeferredFontNative(String fontName, String extraChars, double size, FontStyle style, boolean antialias) {
|
||||
super(fontName, extraChars, size, style, antialias);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected Font getAwtFont(String resource, float size, int style) throws FontFormatException, IOException
|
||||
{
|
||||
return new Font(resource, style, (int) size);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
package mightypork.rogue.fonts;
|
||||
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
import mightypork.rogue.AppAccess;
|
||||
import mightypork.rogue.AppAdapter;
|
||||
import mightypork.rogue.bus.events.ResourceLoadRequest;
|
||||
import mightypork.utils.logging.Log;
|
||||
|
||||
import org.newdawn.slick.opengl.Texture;
|
||||
|
||||
|
||||
/**
|
||||
* Font loader and registry
|
||||
*
|
||||
* @author MightyPork
|
||||
*/
|
||||
public class FontBank extends AppAdapter {
|
||||
|
||||
private static final GLFont NULL_FONT = new NullFont();
|
||||
|
||||
|
||||
public FontBank(AppAccess app) {
|
||||
super(app);
|
||||
}
|
||||
|
||||
private final HashMap<String, GLFont> fonts = new HashMap<String, GLFont>();
|
||||
|
||||
|
||||
/**
|
||||
* Load a {@link DeferredFont}
|
||||
*
|
||||
* @param key font key
|
||||
* @param font font instance
|
||||
*/
|
||||
public void loadFont(String key, DeferredFont font)
|
||||
{
|
||||
bus().send(new ResourceLoadRequest(font));
|
||||
|
||||
fonts.put(key, font);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Add a {@link GLFont} to the bank.
|
||||
*
|
||||
* @param key font key
|
||||
* @param font font instance
|
||||
*/
|
||||
public void addFont(String key, GLFont font)
|
||||
{
|
||||
fonts.put(key, font);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get a loaded {@link Texture}
|
||||
*
|
||||
* @param key texture key
|
||||
* @return the texture
|
||||
*/
|
||||
public GLFont getFont(String key)
|
||||
{
|
||||
final GLFont f = fonts.get(key);
|
||||
|
||||
if (f == null) {
|
||||
Log.w("There's no font called " + key + "!");
|
||||
return NULL_FONT;
|
||||
}
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,58 +0,0 @@
|
||||
package mightypork.rogue.fonts;
|
||||
|
||||
|
||||
import mightypork.rogue.render.Render;
|
||||
import mightypork.utils.math.color.RGB;
|
||||
import mightypork.utils.math.coord.Coord;
|
||||
import mightypork.utils.math.coord.Rect;
|
||||
|
||||
|
||||
public class FontRenderer {
|
||||
|
||||
private final GLFont font;
|
||||
|
||||
|
||||
public FontRenderer(GLFont font) {
|
||||
|
||||
if (font == null) throw new NullPointerException("Font cannot be null.");
|
||||
|
||||
this.font = font;
|
||||
}
|
||||
|
||||
|
||||
public void draw(String text, Coord pos, double height, RGB color)
|
||||
{
|
||||
Render.pushState();
|
||||
|
||||
Render.translate(pos.round());
|
||||
Render.scaleXY(getScale(height));
|
||||
|
||||
font.draw(text, color);
|
||||
|
||||
Render.popState();
|
||||
}
|
||||
|
||||
|
||||
public Coord getNeededSpace(String text, double height)
|
||||
{
|
||||
return font.getNeededSpace(text).mul(getScale(height));
|
||||
}
|
||||
|
||||
|
||||
public double getWidth(String text, double height)
|
||||
{
|
||||
return getNeededSpace(text, height).x;
|
||||
}
|
||||
|
||||
|
||||
public Rect getBounds(String text, Coord pos, double height)
|
||||
{
|
||||
return Rect.fromSize(getNeededSpace(text, height)).add(pos);
|
||||
}
|
||||
|
||||
|
||||
private double getScale(double height)
|
||||
{
|
||||
return height / font.getHeight();
|
||||
}
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
package mightypork.rogue.fonts;
|
||||
|
||||
|
||||
import mightypork.utils.math.color.RGB;
|
||||
import mightypork.utils.math.coord.Coord;
|
||||
|
||||
|
||||
public interface GLFont {
|
||||
|
||||
/**
|
||||
* Draw string at position
|
||||
*
|
||||
* @param text string to draw
|
||||
* @param color draw color
|
||||
*/
|
||||
void draw(String text, RGB color);
|
||||
|
||||
|
||||
/**
|
||||
* Get suize needed to render give string
|
||||
*
|
||||
* @param text string to check
|
||||
* @return coord (width, height)
|
||||
*/
|
||||
Coord getNeededSpace(String text);
|
||||
|
||||
|
||||
/**
|
||||
* @return font height
|
||||
*/
|
||||
int getHeight();
|
||||
|
||||
|
||||
/**
|
||||
* @param text texted text
|
||||
* @return space needed
|
||||
*/
|
||||
int getWidth(String text);
|
||||
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
package mightypork.rogue.fonts;
|
||||
|
||||
|
||||
/**
|
||||
* Glyph tables.
|
||||
*
|
||||
* @author MightyPork
|
||||
*/
|
||||
public class Glyphs {
|
||||
|
||||
public static final String space = " ";
|
||||
public static final String latin = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
|
||||
public static final String latin_extra = "ŒÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜŸÝßàáâãäåæçèéêëìíîïðñòóôõöøùúûüýþÿĚŠČŘŽŤŇĎŮěščřžťňďůŁłđ";
|
||||
public static final String numbers = "0123456789";
|
||||
public static final String punctuation = ".-,.?!:;\"'";
|
||||
public static final String punctuation_extra = "()¿¡»«›‹“”‘’„…";
|
||||
public static final String symbols = "[]{}#$%&§*+/<=>@\\^_|~°";
|
||||
public static final String symbols_extra = "¥€£¢`ƒ†‡ˆ‰•¤¦¨ªº¹²³¬¯±´µ¶·¸¼½¾×÷™©®→↓←↑";
|
||||
|
||||
public static final String basic = space + latin + numbers + punctuation + symbols;
|
||||
public static final String extra = latin_extra + punctuation_extra + symbols_extra;
|
||||
public static final String all = basic + extra;
|
||||
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
package mightypork.rogue.fonts;
|
||||
|
||||
|
||||
import mightypork.utils.math.color.RGB;
|
||||
import mightypork.utils.math.coord.Coord;
|
||||
|
||||
|
||||
/**
|
||||
* Null font used where real resource could not be loaded.
|
||||
*
|
||||
* @author MightyPork
|
||||
*/
|
||||
public class NullFont implements GLFont {
|
||||
|
||||
@Override
|
||||
public void draw(String str, RGB color)
|
||||
{
|
||||
// nope
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Coord getNeededSpace(String str)
|
||||
{
|
||||
return Coord.zero();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int getHeight()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int getWidth(String text)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,106 +0,0 @@
|
||||
package mightypork.rogue.fonts;
|
||||
|
||||
|
||||
import static org.lwjgl.opengl.GL11.*;
|
||||
|
||||
import java.awt.Font;
|
||||
|
||||
import mightypork.rogue.render.Render;
|
||||
import mightypork.utils.math.color.RGB;
|
||||
import mightypork.utils.math.coord.Coord;
|
||||
|
||||
import org.newdawn.slick.Color;
|
||||
import org.newdawn.slick.TrueTypeFont;
|
||||
|
||||
|
||||
/**
|
||||
* Wrapper for slick font
|
||||
*
|
||||
* @author MightyPork
|
||||
*/
|
||||
public class SlickFont implements GLFont {
|
||||
|
||||
private final TrueTypeFont ttf;
|
||||
|
||||
|
||||
/**
|
||||
* A font with ASCII and extra chars
|
||||
*
|
||||
* @param font font to load
|
||||
* @param antiAlias antialiasing
|
||||
* @param extraChars extra chars to load
|
||||
*/
|
||||
public SlickFont(Font font, boolean antiAlias, String extraChars) {
|
||||
|
||||
ttf = new TrueTypeFont(font, antiAlias, stripASCII(extraChars));
|
||||
}
|
||||
|
||||
|
||||
private static char[] stripASCII(String chars)
|
||||
{
|
||||
if (chars == null) return null;
|
||||
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
for (final char c : chars.toCharArray()) {
|
||||
if (c <= 255) continue; // already included in default set
|
||||
sb.append(c);
|
||||
}
|
||||
|
||||
return sb.toString().toCharArray();
|
||||
}
|
||||
|
||||
|
||||
private static void prepareForRender()
|
||||
{
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Draw in color
|
||||
*
|
||||
* @param str string to draw
|
||||
* @param color text color
|
||||
*/
|
||||
@Override
|
||||
public void draw(String str, RGB color)
|
||||
{
|
||||
Render.pushState();
|
||||
|
||||
prepareForRender();
|
||||
ttf.drawString(0, 0, str, rgbToSlickColor(color));
|
||||
|
||||
Render.popState();
|
||||
}
|
||||
|
||||
|
||||
private static Color rgbToSlickColor(RGB rgb)
|
||||
{
|
||||
return new Color((float) rgb.r, (float) rgb.g, (float) rgb.b, (float) rgb.a);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Coord getNeededSpace(String text)
|
||||
{
|
||||
return new Coord(getWidth(text), getHeight());
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int getHeight()
|
||||
{
|
||||
return ttf.getHeight();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int getWidth(String text)
|
||||
{
|
||||
return ttf.getWidth(text);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
package mightypork.rogue.gui.renderers;
|
||||
|
||||
|
||||
import static mightypork.utils.math.constraints.ConstraintFactory.*;
|
||||
import mightypork.rogue.AppAccess;
|
||||
import mightypork.utils.math.constraints.RectEvaluable;
|
||||
|
||||
|
||||
public class ColumnHolder extends ElementHolder {
|
||||
|
||||
private final int cols;
|
||||
private int col = 0;
|
||||
|
||||
|
||||
public ColumnHolder(AppAccess app, RectEvaluable context, int rows) {
|
||||
super(app, context);
|
||||
this.cols = rows;
|
||||
}
|
||||
|
||||
|
||||
public ColumnHolder(AppAccess app, int rows) {
|
||||
super(app);
|
||||
this.cols = rows;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Add a row to the holder.
|
||||
*
|
||||
* @param elem
|
||||
*/
|
||||
@Override
|
||||
public void add(final PluggableRenderable elem)
|
||||
{
|
||||
if (elem == null) return;
|
||||
|
||||
elem.setContext(c_column(this, cols, col++));
|
||||
|
||||
attach(elem);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,82 +0,0 @@
|
||||
package mightypork.rogue.gui.renderers;
|
||||
|
||||
|
||||
import java.util.LinkedList;
|
||||
|
||||
import mightypork.rogue.AppAccess;
|
||||
import mightypork.rogue.bus.ChildClient;
|
||||
import mightypork.rogue.render.Renderable;
|
||||
import mightypork.utils.control.bus.EventBus;
|
||||
import mightypork.utils.math.constraints.RectEvaluable;
|
||||
import mightypork.utils.math.coord.Rect;
|
||||
|
||||
|
||||
/**
|
||||
* Bag for {@link PluggableRenderer} elements with constraints.<br>
|
||||
* Elements are exposed to {@link EventBus}.
|
||||
*
|
||||
* @author MightyPork
|
||||
*/
|
||||
public abstract class ElementHolder extends ChildClient implements PluggableRenderable {
|
||||
|
||||
private final LinkedList<PluggableRenderable> elements = new LinkedList<PluggableRenderable>();
|
||||
private RectEvaluable context;
|
||||
|
||||
|
||||
public ElementHolder(AppAccess app) {
|
||||
super(app);
|
||||
}
|
||||
|
||||
|
||||
public ElementHolder(AppAccess app, RectEvaluable context) {
|
||||
super(app);
|
||||
setContext(context);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public final void setContext(RectEvaluable context)
|
||||
{
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public final void render()
|
||||
{
|
||||
for (final Renderable element : elements) {
|
||||
element.render();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public final Rect getRect()
|
||||
{
|
||||
return context.getRect();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Add element to the holder, setting it's context.<br>
|
||||
* Element must then be attached using the <code>attach</code> method.
|
||||
*
|
||||
* @param elem element
|
||||
*/
|
||||
public abstract void add(PluggableRenderable elem);
|
||||
|
||||
|
||||
/**
|
||||
* Connect to bus and add to element list
|
||||
*
|
||||
* @param elem element; it's context will be set to the constraint.
|
||||
*/
|
||||
public final void attach(PluggableRenderable elem)
|
||||
{
|
||||
if (elem == null) return;
|
||||
|
||||
elements.add(elem);
|
||||
addChildClient(elem);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
package mightypork.rogue.gui.renderers;
|
||||
|
||||
|
||||
import mightypork.rogue.render.Render;
|
||||
import mightypork.rogue.textures.TxQuad;
|
||||
|
||||
|
||||
public class ImageRenderer extends PluggableRenderer {
|
||||
|
||||
private TxQuad texture;
|
||||
|
||||
|
||||
public ImageRenderer(TxQuad texture) {
|
||||
this.texture = texture;
|
||||
}
|
||||
|
||||
|
||||
public void setTexture(TxQuad texture)
|
||||
{
|
||||
this.texture = texture;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void render()
|
||||
{
|
||||
Render.quadTextured(getRect(), texture);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
package mightypork.rogue.gui.renderers;
|
||||
|
||||
|
||||
import mightypork.rogue.render.Renderable;
|
||||
import mightypork.utils.math.constraints.PluggableContext;
|
||||
import mightypork.utils.math.constraints.RectEvaluable;
|
||||
import mightypork.utils.math.coord.Rect;
|
||||
|
||||
|
||||
public interface PluggableRenderable extends Renderable, PluggableContext {
|
||||
|
||||
@Override
|
||||
void render();
|
||||
|
||||
|
||||
@Override
|
||||
Rect getRect();
|
||||
|
||||
|
||||
@Override
|
||||
void setContext(RectEvaluable rect);
|
||||
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
package mightypork.rogue.gui.renderers;
|
||||
|
||||
|
||||
import mightypork.rogue.render.Renderable;
|
||||
import mightypork.utils.math.constraints.ContextAdapter;
|
||||
import mightypork.utils.math.constraints.RectEvaluable;
|
||||
import mightypork.utils.math.coord.Rect;
|
||||
|
||||
|
||||
/**
|
||||
* {@link Renderable} with pluggable context
|
||||
*
|
||||
* @author MightyPork
|
||||
*/
|
||||
public abstract class PluggableRenderer extends ContextAdapter implements PluggableRenderable {
|
||||
|
||||
@Override
|
||||
public abstract void render();
|
||||
|
||||
|
||||
@Override
|
||||
public Rect getRect()
|
||||
{
|
||||
return super.getRect();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void setContext(RectEvaluable rect)
|
||||
{
|
||||
super.setContext(rect);
|
||||
}
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
package mightypork.rogue.gui.renderers;
|
||||
|
||||
|
||||
import static mightypork.utils.math.constraints.ConstraintFactory.*;
|
||||
import mightypork.rogue.AppAccess;
|
||||
import mightypork.utils.math.constraints.RectEvaluable;
|
||||
|
||||
|
||||
public class RowHolder extends ElementHolder {
|
||||
|
||||
private final int rows;
|
||||
private int row = 0;
|
||||
|
||||
|
||||
public RowHolder(AppAccess app, RectEvaluable context, int rows) {
|
||||
super(app, context);
|
||||
this.rows = rows;
|
||||
}
|
||||
|
||||
|
||||
public RowHolder(AppAccess app, int rows) {
|
||||
super(app);
|
||||
this.rows = rows;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Add a row to the holder.
|
||||
*
|
||||
* @param elem
|
||||
*/
|
||||
@Override
|
||||
public void add(final PluggableRenderable elem)
|
||||
{
|
||||
if (elem == null) return;
|
||||
|
||||
elem.setContext(c_row(this, rows, row++));
|
||||
|
||||
attach(elem);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,82 +0,0 @@
|
||||
package mightypork.rogue.gui.renderers;
|
||||
|
||||
|
||||
import mightypork.rogue.fonts.FontRenderer;
|
||||
import mightypork.rogue.fonts.GLFont;
|
||||
import mightypork.utils.math.color.RGB;
|
||||
import mightypork.utils.math.coord.Coord;
|
||||
|
||||
|
||||
public class TextRenderer extends PluggableRenderer {
|
||||
|
||||
public static enum Align
|
||||
{
|
||||
LEFT, CENTER, RIGHT;
|
||||
}
|
||||
|
||||
private FontRenderer font;
|
||||
private String text;
|
||||
private RGB color;
|
||||
private Align align;
|
||||
|
||||
|
||||
public TextRenderer(GLFont font, String text, RGB color, Align align) {
|
||||
this.font = new FontRenderer(font);
|
||||
this.text = text;
|
||||
this.color = color;
|
||||
this.align = align;
|
||||
}
|
||||
|
||||
|
||||
public void setFont(FontRenderer font)
|
||||
{
|
||||
this.font = font;
|
||||
}
|
||||
|
||||
|
||||
public void setText(String text)
|
||||
{
|
||||
this.text = text;
|
||||
}
|
||||
|
||||
|
||||
public void setColor(RGB color)
|
||||
{
|
||||
this.color = color;
|
||||
}
|
||||
|
||||
|
||||
public void setAlign(Align align)
|
||||
{
|
||||
this.align = align;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void render()
|
||||
{
|
||||
final double h = getRect().getHeight();
|
||||
|
||||
final double w = font.getWidth(text, h);
|
||||
|
||||
final Coord start;
|
||||
|
||||
switch (align) {
|
||||
case LEFT:
|
||||
start = getRect().getMin();
|
||||
break;
|
||||
|
||||
case CENTER:
|
||||
start = getRect().getCenterV1().sub_ip(w / 2D, 0);
|
||||
break;
|
||||
|
||||
case RIGHT:
|
||||
default:
|
||||
start = getRect().getX2Y1().sub_ip(w, 0);
|
||||
break;
|
||||
}
|
||||
|
||||
font.draw(text, start, h, color);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
package mightypork.rogue.gui.screens;
|
||||
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedList;
|
||||
|
||||
import mightypork.rogue.AppAccess;
|
||||
|
||||
|
||||
public abstract class LayeredScreen extends Screen {
|
||||
|
||||
private final Collection<ScreenLayer> layers = new LinkedList<ScreenLayer>();
|
||||
|
||||
|
||||
public LayeredScreen(AppAccess app) {
|
||||
super(app);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected final void renderScreen()
|
||||
{
|
||||
for (final ScreenLayer layer : layers) {
|
||||
layer.render();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Add a layer to the screen.
|
||||
*
|
||||
* @param layer
|
||||
*/
|
||||
protected final void addLayer(ScreenLayer layer)
|
||||
{
|
||||
this.layers.add(layer); // will be rendered from last to first
|
||||
addChildClient(layer); // connect to bus
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Remove a layer
|
||||
*
|
||||
* @param layer
|
||||
*/
|
||||
protected final void removeLayer(ScreenLayer layer)
|
||||
{
|
||||
this.layers.remove(layer);
|
||||
removeChildClient(layer);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,180 +0,0 @@
|
||||
package mightypork.rogue.gui.screens;
|
||||
|
||||
|
||||
import static org.lwjgl.opengl.GL11.*;
|
||||
import mightypork.rogue.AppAccess;
|
||||
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.Renderable;
|
||||
import mightypork.utils.control.interf.Destroyable;
|
||||
import mightypork.utils.math.constraints.RectEvaluable;
|
||||
import mightypork.utils.math.coord.Coord;
|
||||
import mightypork.utils.math.coord.Rect;
|
||||
|
||||
|
||||
/**
|
||||
* Screen class.
|
||||
*
|
||||
* @author MightyPork
|
||||
*/
|
||||
public abstract class Screen extends ChildClient implements Renderable, Destroyable, KeyBinder, RectEvaluable, ScreenChangeEvent.Listener {
|
||||
|
||||
private final KeyBindingPool keybindings = new KeyBindingPool();
|
||||
|
||||
private boolean active;
|
||||
private boolean needSetupViewport = false;
|
||||
|
||||
|
||||
public Screen(AppAccess app) {
|
||||
super(app);
|
||||
|
||||
// disable events initially
|
||||
setListening(false);
|
||||
|
||||
addChildClient(keybindings);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public final void bindKeyStroke(KeyStroke stroke, Runnable task)
|
||||
{
|
||||
keybindings.bindKeyStroke(stroke, task);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public final void unbindKeyStroke(KeyStroke stroke)
|
||||
{
|
||||
keybindings.unbindKeyStroke(stroke);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public final void destroy()
|
||||
{
|
||||
deinitScreen();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Prepare for being shown
|
||||
*
|
||||
* @param shown true to show, false to hide
|
||||
*/
|
||||
public final void setActive(boolean shown)
|
||||
{
|
||||
if (shown) {
|
||||
active = true;
|
||||
needSetupViewport = true;
|
||||
|
||||
onSizeChanged(getRect().getSize());
|
||||
onScreenEnter();
|
||||
|
||||
// enable events
|
||||
setListening(true);
|
||||
|
||||
} else {
|
||||
onScreenLeave();
|
||||
|
||||
active = false;
|
||||
|
||||
// disable events
|
||||
setListening(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Clean up before screen is destroyed.
|
||||
*/
|
||||
protected abstract void deinitScreen();
|
||||
|
||||
|
||||
/**
|
||||
* Called when the screen becomes active
|
||||
*/
|
||||
protected abstract void onScreenEnter();
|
||||
|
||||
|
||||
/**
|
||||
* Called when the screen is no longer active
|
||||
*/
|
||||
protected abstract void onScreenLeave();
|
||||
|
||||
|
||||
/**
|
||||
* Update GUI for new screen size
|
||||
*
|
||||
* @param size screen size
|
||||
*/
|
||||
protected void onSizeChanged(Coord size)
|
||||
{
|
||||
// no impl
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Render screen contents (context is ready for 2D rendering)
|
||||
*/
|
||||
protected abstract void renderScreen();
|
||||
|
||||
|
||||
/**
|
||||
* @return true if screen is the curretn screen
|
||||
*/
|
||||
public final boolean isActive()
|
||||
{
|
||||
return active;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public final void receive(ScreenChangeEvent event)
|
||||
{
|
||||
if (!isActive()) return;
|
||||
|
||||
onSizeChanged(event.getScreenSize());
|
||||
|
||||
needSetupViewport = true;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public final Rect getRect()
|
||||
{
|
||||
return disp().getRect();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public final void render()
|
||||
{
|
||||
if (!isActive()) return;
|
||||
|
||||
if (needSetupViewport) {
|
||||
setupViewport();
|
||||
}
|
||||
|
||||
renderScreen();
|
||||
}
|
||||
|
||||
|
||||
protected void setupViewport()
|
||||
{
|
||||
// fix projection for changed size
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
final 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);
|
||||
}
|
||||
|
||||
|
||||
public abstract String getId();
|
||||
}
|
||||
@@ -1,59 +0,0 @@
|
||||
package mightypork.rogue.gui.screens;
|
||||
|
||||
|
||||
import mightypork.rogue.bus.ChildClient;
|
||||
import mightypork.rogue.input.KeyBinder;
|
||||
import mightypork.rogue.input.KeyBindingPool;
|
||||
import mightypork.rogue.input.KeyStroke;
|
||||
import mightypork.rogue.render.Renderable;
|
||||
import mightypork.utils.math.constraints.RectEvaluable;
|
||||
import mightypork.utils.math.coord.Rect;
|
||||
|
||||
|
||||
/**
|
||||
* Screen display layer
|
||||
*
|
||||
* @author MightyPork
|
||||
*/
|
||||
public abstract class ScreenLayer extends ChildClient implements Renderable, RectEvaluable, KeyBinder {
|
||||
|
||||
private final Screen screen;
|
||||
|
||||
private final KeyBindingPool keybindings = new KeyBindingPool();
|
||||
|
||||
|
||||
public ScreenLayer(Screen screen) {
|
||||
super(screen); // screen as AppAccess
|
||||
|
||||
this.screen = screen;
|
||||
addChildClient(keybindings);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public final void bindKeyStroke(KeyStroke stroke, Runnable task)
|
||||
{
|
||||
keybindings.bindKeyStroke(stroke, task);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public final void unbindKeyStroke(KeyStroke stroke)
|
||||
{
|
||||
keybindings.unbindKeyStroke(stroke);
|
||||
}
|
||||
|
||||
|
||||
protected Screen screen()
|
||||
{
|
||||
return screen;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Rect getRect()
|
||||
{
|
||||
return screen.getRect();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,60 +0,0 @@
|
||||
package mightypork.rogue.gui.screens;
|
||||
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
import mightypork.rogue.AppAccess;
|
||||
import mightypork.rogue.bus.Subsystem;
|
||||
import mightypork.rogue.bus.events.ScreenRequestEvent;
|
||||
import mightypork.rogue.render.Renderable;
|
||||
import mightypork.utils.logging.Log;
|
||||
|
||||
|
||||
public class ScreenRegistry extends Subsystem implements ScreenRequestEvent.Listener, Renderable {
|
||||
|
||||
private final HashMap<String, Screen> screens = new HashMap<String, Screen>();
|
||||
private Screen active = null;
|
||||
|
||||
|
||||
public ScreenRegistry(AppAccess app) {
|
||||
super(app);
|
||||
}
|
||||
|
||||
|
||||
public void add(Screen screen)
|
||||
{
|
||||
screens.put(screen.getId(), screen);
|
||||
addChildClient(screen);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void showScreen(String key)
|
||||
{
|
||||
Log.f3("Request to show screen \"" + key + "\"");
|
||||
|
||||
final 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;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void render()
|
||||
{
|
||||
if (active != null) active.render();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void deinit()
|
||||
{
|
||||
// no impl
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,207 +0,0 @@
|
||||
package mightypork.rogue.input;
|
||||
|
||||
|
||||
import mightypork.rogue.AppAccess;
|
||||
import mightypork.rogue.bus.Subsystem;
|
||||
import mightypork.rogue.bus.events.ActionRequest;
|
||||
import mightypork.rogue.bus.events.ActionRequest.RequestType;
|
||||
import mightypork.rogue.bus.events.KeyboardEvent;
|
||||
import mightypork.rogue.bus.events.MouseButtonEvent;
|
||||
import mightypork.rogue.bus.events.MouseMotionEvent;
|
||||
import mightypork.utils.control.interf.Updateable;
|
||||
import mightypork.utils.math.constraints.NumEvaluable;
|
||||
import mightypork.utils.math.coord.Coord;
|
||||
|
||||
import org.lwjgl.LWJGLException;
|
||||
import org.lwjgl.input.Keyboard;
|
||||
import org.lwjgl.input.Mouse;
|
||||
import org.lwjgl.opengl.Display;
|
||||
|
||||
|
||||
public class InputSystem extends Subsystem implements Updateable, KeyBinder {
|
||||
|
||||
// listeners
|
||||
private final KeyBindingPool keybindings;
|
||||
private boolean yAxisDown = true;
|
||||
private static boolean inited = false;
|
||||
|
||||
|
||||
public InputSystem(AppAccess app) {
|
||||
super(app);
|
||||
|
||||
initDevices();
|
||||
|
||||
// global keybindings
|
||||
keybindings = new KeyBindingPool();
|
||||
addChildClient(keybindings);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public final void deinit()
|
||||
{
|
||||
Mouse.destroy();
|
||||
Keyboard.destroy();
|
||||
}
|
||||
|
||||
|
||||
private static void initDevices()
|
||||
{
|
||||
if (inited) return;
|
||||
inited = true;
|
||||
|
||||
try {
|
||||
Mouse.create();
|
||||
Keyboard.create();
|
||||
Keyboard.enableRepeatEvents(false);
|
||||
} catch (final LWJGLException e) {
|
||||
throw new RuntimeException("Failed to initialize input devices.", e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public final void bindKeyStroke(KeyStroke stroke, Runnable task)
|
||||
{
|
||||
keybindings.bindKeyStroke(stroke, task);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void unbindKeyStroke(KeyStroke stroke)
|
||||
{
|
||||
keybindings.unbindKeyStroke(stroke);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void update(double delta)
|
||||
{
|
||||
// was destroyed
|
||||
if (!Display.isCreated()) return;
|
||||
if (!Mouse.isCreated()) return;
|
||||
if (!Keyboard.isCreated()) return;
|
||||
|
||||
Display.processMessages();
|
||||
|
||||
final Coord moveSum = Coord.zero();
|
||||
final Coord lastPos = Coord.zero();
|
||||
boolean wasMouse = false;
|
||||
|
||||
while (Mouse.next()) {
|
||||
onMouseEvent(moveSum, lastPos);
|
||||
wasMouse = true;
|
||||
}
|
||||
|
||||
if (wasMouse && !moveSum.isZero()) bus().send(new MouseMotionEvent(lastPos, moveSum));
|
||||
|
||||
while (Keyboard.next()) {
|
||||
onKeyEvent();
|
||||
}
|
||||
|
||||
if (Display.isCloseRequested()) {
|
||||
bus().send(new ActionRequest(RequestType.SHUTDOWN));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void onMouseEvent(Coord moveSum, Coord lastPos)
|
||||
{
|
||||
final int button = Mouse.getEventButton();
|
||||
final boolean down = Mouse.getEventButtonState();
|
||||
final Coord pos = new Coord(Mouse.getEventX(), Mouse.getEventY());
|
||||
final Coord move = new Coord(Mouse.getEventDX(), Mouse.getEventDY());
|
||||
final int wheeld = Mouse.getEventDWheel();
|
||||
|
||||
if (yAxisDown) {
|
||||
flipScrY(pos);
|
||||
move.mul_ip(1, -1, 1);
|
||||
}
|
||||
|
||||
if (button != -1 || wheeld != 0) {
|
||||
bus().send(new MouseButtonEvent(pos, button, down, wheeld));
|
||||
}
|
||||
|
||||
moveSum.add_ip(move);
|
||||
lastPos.setTo(pos);
|
||||
}
|
||||
|
||||
|
||||
private void onKeyEvent()
|
||||
{
|
||||
final int key = Keyboard.getEventKey();
|
||||
final boolean down = Keyboard.getEventKeyState();
|
||||
final char c = Keyboard.getEventCharacter();
|
||||
|
||||
bus().send(new KeyboardEvent(key, c, down));
|
||||
}
|
||||
|
||||
|
||||
private void flipScrY(Coord c)
|
||||
{
|
||||
if (disp() != null) {
|
||||
c.setY_ip(disp().getSize().y - c.y);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set whether Y axis should go top-down instead of LWJGL default bottom-up.<br>
|
||||
* Default = true.
|
||||
*
|
||||
* @param yAxisDown
|
||||
*/
|
||||
public void setYDown(boolean yAxisDown)
|
||||
{
|
||||
this.yAxisDown = yAxisDown;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get absolute mouse position
|
||||
*
|
||||
* @return mouse position
|
||||
*/
|
||||
public Coord getMousePos()
|
||||
{
|
||||
final Coord pos = new Coord(Mouse.getX(), Mouse.getY());
|
||||
flipScrY(pos);
|
||||
return pos;
|
||||
}
|
||||
|
||||
|
||||
public void grabMouse(boolean grab)
|
||||
{
|
||||
Mouse.setGrabbed(grab);
|
||||
}
|
||||
|
||||
private final NumEvaluable cmousex = new NumEvaluable() {
|
||||
|
||||
@Override
|
||||
public double getValue()
|
||||
{
|
||||
return getMousePos().x;
|
||||
}
|
||||
};
|
||||
|
||||
private final NumEvaluable cmousey = new NumEvaluable() {
|
||||
|
||||
@Override
|
||||
public double getValue()
|
||||
{
|
||||
return getMousePos().y;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
public NumEvaluable c_mouse_x()
|
||||
{
|
||||
return cmousex;
|
||||
}
|
||||
|
||||
|
||||
public NumEvaluable c_mouse_y()
|
||||
{
|
||||
return cmousey;
|
||||
}
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
package mightypork.rogue.input;
|
||||
|
||||
|
||||
public interface KeyBinder {
|
||||
|
||||
/**
|
||||
* Bind handler to a keystroke, replace current handler if any
|
||||
*
|
||||
* @param stroke trigger keystroke
|
||||
* @param task handler
|
||||
*/
|
||||
void bindKeyStroke(KeyStroke stroke, Runnable task);
|
||||
|
||||
|
||||
/**
|
||||
* Remove handler from a keystroke (id any)
|
||||
*
|
||||
* @param stroke stroke
|
||||
*/
|
||||
void unbindKeyStroke(KeyStroke stroke);
|
||||
|
||||
}
|
||||
@@ -1,66 +0,0 @@
|
||||
package mightypork.rogue.input;
|
||||
|
||||
|
||||
import mightypork.rogue.bus.events.KeyboardEvent;
|
||||
|
||||
|
||||
/**
|
||||
* Key binding, trigger activated by a keystroke event
|
||||
*
|
||||
* @author MightyPork
|
||||
*/
|
||||
public class KeyBinding implements KeyboardEvent.Listener {
|
||||
|
||||
private final KeyStroke keystroke;
|
||||
private Runnable handler;
|
||||
private boolean wasActive = false;
|
||||
|
||||
|
||||
/**
|
||||
* @param stroke trigger keystroke
|
||||
* @param handler action
|
||||
*/
|
||||
public KeyBinding(KeyStroke stroke, Runnable handler) {
|
||||
this.keystroke = stroke;
|
||||
this.handler = handler;
|
||||
|
||||
wasActive = keystroke.isActive();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Check for equality of keystroke
|
||||
*
|
||||
* @param stroke other keystroke
|
||||
* @return true if keystrokes are equal (cannot co-exist)
|
||||
*/
|
||||
public boolean matches(KeyStroke stroke)
|
||||
{
|
||||
return this.keystroke.equals(stroke);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param handler event handler
|
||||
*/
|
||||
public void setHandler(Runnable handler)
|
||||
{
|
||||
this.handler = handler;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void receive(KeyboardEvent event)
|
||||
{
|
||||
// ignore unrelated events
|
||||
if (!keystroke.getKeys().contains(event.getKey())) return;
|
||||
|
||||
// run handler when event was met
|
||||
if (keystroke.isActive() && !wasActive) {
|
||||
handler.run();
|
||||
}
|
||||
|
||||
wasActive = keystroke.isActive();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,70 +0,0 @@
|
||||
package mightypork.rogue.input;
|
||||
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.Set;
|
||||
|
||||
import mightypork.rogue.bus.events.KeyboardEvent;
|
||||
import mightypork.utils.logging.Log;
|
||||
|
||||
|
||||
/**
|
||||
* Key binding pool
|
||||
*
|
||||
* @author MightyPork
|
||||
*/
|
||||
public class KeyBindingPool implements KeyBinder, KeyboardEvent.Listener {
|
||||
|
||||
private final Set<KeyBinding> bindings = new HashSet<KeyBinding>();
|
||||
|
||||
|
||||
/**
|
||||
* Bind handler to a keystroke, replace current handler if any
|
||||
*
|
||||
* @param stroke trigger keystroke
|
||||
* @param task handler
|
||||
*/
|
||||
@Override
|
||||
public void bindKeyStroke(KeyStroke stroke, Runnable task)
|
||||
{
|
||||
for (final KeyBinding kb : bindings) {
|
||||
if (kb.matches(stroke)) {
|
||||
Log.w("Duplicate KeyBinding (" + stroke + "), using newest handler.");
|
||||
kb.setHandler(task);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
bindings.add(new KeyBinding(stroke, task));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Remove handler from keystroke (id any)
|
||||
*
|
||||
* @param stroke stroke
|
||||
*/
|
||||
@Override
|
||||
public void unbindKeyStroke(KeyStroke stroke)
|
||||
{
|
||||
final Iterator<KeyBinding> iter = bindings.iterator();
|
||||
|
||||
while (iter.hasNext()) {
|
||||
final KeyBinding kb = iter.next();
|
||||
if (kb.matches(stroke)) {
|
||||
iter.remove();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void receive(KeyboardEvent event)
|
||||
{
|
||||
for (final KeyBinding kb : bindings) {
|
||||
kb.receive(event);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,120 +0,0 @@
|
||||
package mightypork.rogue.input;
|
||||
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.lwjgl.input.Keyboard;
|
||||
|
||||
|
||||
/**
|
||||
* Key stroke trigger
|
||||
*
|
||||
* @author MightyPork
|
||||
*/
|
||||
public class KeyStroke {
|
||||
|
||||
private final Set<Integer> keys = new LinkedHashSet<Integer>();
|
||||
private final boolean fallingEdge;
|
||||
|
||||
|
||||
/**
|
||||
* KeyStroke
|
||||
*
|
||||
* @param fallingEdge true for falling edge, up for rising edge
|
||||
* @param keys keys that must be pressed
|
||||
*/
|
||||
public KeyStroke(boolean fallingEdge, int... keys) {
|
||||
this.fallingEdge = fallingEdge;
|
||||
for (final int k : keys) {
|
||||
this.keys.add(k);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Rising edge keystroke
|
||||
*
|
||||
* @param keys
|
||||
*/
|
||||
public KeyStroke(int... keys) {
|
||||
fallingEdge = false;
|
||||
for (final int k : keys) {
|
||||
this.keys.add(k);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return true if the keystroke is currently satisfied (keys pressed)
|
||||
*/
|
||||
public boolean isActive()
|
||||
{
|
||||
boolean st = true;
|
||||
for (final int k : keys) {
|
||||
st &= Keyboard.isKeyDown(k);
|
||||
}
|
||||
|
||||
return fallingEdge ? st : !st;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int hashCode()
|
||||
{
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((keys == null) ? 0 : keys.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj)
|
||||
{
|
||||
if (this == obj) return true;
|
||||
if (obj == null) return false;
|
||||
if (!(obj instanceof KeyStroke)) return false;
|
||||
final KeyStroke other = (KeyStroke) obj;
|
||||
|
||||
if (keys == null) {
|
||||
if (other.keys != null) return false;
|
||||
} else if (!keys.equals(other.keys)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (fallingEdge != other.fallingEdge) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
String s = "(";
|
||||
|
||||
int cnt = 0;
|
||||
final Iterator<Integer> i = keys.iterator();
|
||||
for (; i.hasNext(); cnt++) {
|
||||
if (cnt > 0) s += "+";
|
||||
s += Keyboard.getKeyName(i.next());
|
||||
}
|
||||
|
||||
s += fallingEdge ? ",DOWN" : ",UP";
|
||||
|
||||
s += ")";
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return the key set
|
||||
*/
|
||||
public Set<Integer> getKeys()
|
||||
{
|
||||
return keys;
|
||||
}
|
||||
}
|
||||
@@ -1,140 +0,0 @@
|
||||
package mightypork.rogue.input;
|
||||
|
||||
|
||||
import org.lwjgl.input.Keyboard;
|
||||
|
||||
|
||||
/**
|
||||
* Key constants, from LWJGL {@link Keyboard}
|
||||
*
|
||||
* @author MightyPork
|
||||
*/
|
||||
public interface Keys {
|
||||
|
||||
//@formatter:off
|
||||
|
||||
public static final int CHAR_NONE = '\0';
|
||||
|
||||
public static final int KEY_NONE = 0x00;
|
||||
|
||||
public static final int KEY_ESCAPE = 0x01;
|
||||
|
||||
public static final int KEY_1 = 0x02;
|
||||
public static final int KEY_2 = 0x03;
|
||||
public static final int KEY_3 = 0x04;
|
||||
public static final int KEY_4 = 0x05;
|
||||
public static final int KEY_5 = 0x06;
|
||||
public static final int KEY_6 = 0x07;
|
||||
public static final int KEY_7 = 0x08;
|
||||
public static final int KEY_8 = 0x09;
|
||||
public static final int KEY_9 = 0x0A;
|
||||
public static final int KEY_0 = 0x0B;
|
||||
|
||||
public static final int KEY_Q = 0x10;
|
||||
public static final int KEY_W = 0x11;
|
||||
public static final int KEY_E = 0x12;
|
||||
public static final int KEY_R = 0x13;
|
||||
public static final int KEY_T = 0x14;
|
||||
public static final int KEY_Y = 0x15;
|
||||
public static final int KEY_U = 0x16;
|
||||
public static final int KEY_I = 0x17;
|
||||
public static final int KEY_O = 0x18;
|
||||
public static final int KEY_P = 0x19;
|
||||
public static final int KEY_A = 0x1E;
|
||||
public static final int KEY_S = 0x1F;
|
||||
public static final int KEY_D = 0x20;
|
||||
public static final int KEY_F = 0x21;
|
||||
public static final int KEY_G = 0x22;
|
||||
public static final int KEY_H = 0x23;
|
||||
public static final int KEY_J = 0x24;
|
||||
public static final int KEY_K = 0x25;
|
||||
public static final int KEY_L = 0x26;
|
||||
public static final int KEY_Z = 0x2C;
|
||||
public static final int KEY_X = 0x2D;
|
||||
public static final int KEY_C = 0x2E;
|
||||
public static final int KEY_V = 0x2F;
|
||||
public static final int KEY_B = 0x30;
|
||||
public static final int KEY_N = 0x31;
|
||||
public static final int KEY_M = 0x32;
|
||||
|
||||
public static final int KEY_MINUS = 0x0C;
|
||||
public static final int KEY_EQUALS = 0x0D;
|
||||
public static final int KEY_SLASH = 0x35;
|
||||
public static final int KEY_BACKSLASH = 0x2B;
|
||||
public static final int KEY_LBRACKET = 0x1A;
|
||||
public static final int KEY_RBRACKET = 0x1B;
|
||||
public static final int KEY_SEMICOLON = 0x27;
|
||||
public static final int KEY_APOSTROPHE = 0x28;
|
||||
public static final int KEY_GRAVE = 0x29;
|
||||
public static final int KEY_COMMA = 0x33;
|
||||
public static final int KEY_PERIOD = 0x34;
|
||||
|
||||
public static final int KEY_SPACE = 0x39;
|
||||
public static final int KEY_BACKSPACE = 0x0E;
|
||||
public static final int KEY_TAB = 0x0F;
|
||||
|
||||
public static final int KEY_F1 = 0x3B;
|
||||
public static final int KEY_F2 = 0x3C;
|
||||
public static final int KEY_F3 = 0x3D;
|
||||
public static final int KEY_F4 = 0x3E;
|
||||
public static final int KEY_F5 = 0x3F;
|
||||
public static final int KEY_F6 = 0x40;
|
||||
public static final int KEY_F7 = 0x41;
|
||||
public static final int KEY_F8 = 0x42;
|
||||
public static final int KEY_F9 = 0x43;
|
||||
public static final int KEY_F10 = 0x44;
|
||||
public static final int KEY_F11 = 0x57;
|
||||
public static final int KEY_F12 = 0x58;
|
||||
public static final int KEY_F13 = 0x64;
|
||||
public static final int KEY_F14 = 0x65;
|
||||
public static final int KEY_F15 = 0x66;
|
||||
|
||||
public static final int KEY_CAPSLOCK = 0x3A;
|
||||
public static final int KEY_SCROLLLOCK = 0x46;
|
||||
public static final int KEY_NUMLOCK = 0x45;
|
||||
|
||||
public static final int KEY_SUBTRACT = 0x4A; /* - on numeric keypad */
|
||||
public static final int KEY_ADD = 0x4E; /* + on numeric keypad */
|
||||
public static final int KEY_NUMPAD0 = 0x52;
|
||||
public static final int KEY_NUMPAD1 = 0x4F;
|
||||
public static final int KEY_NUMPAD2 = 0x50;
|
||||
public static final int KEY_NUMPAD3 = 0x51;
|
||||
public static final int KEY_NUMPAD4 = 0x4B;
|
||||
public static final int KEY_NUMPAD5 = 0x4C;
|
||||
public static final int KEY_NUMPAD6 = 0x4D;
|
||||
public static final int KEY_NUMPAD7 = 0x47;
|
||||
public static final int KEY_NUMPAD8 = 0x48;
|
||||
public static final int KEY_NUMPAD9 = 0x49;
|
||||
public static final int KEY_DECIMAL = 0x53; /* . on numeric keypad */
|
||||
public static final int KEY_NUMPADENTER = 0x9C; /* Enter on numeric keypad */
|
||||
public static final int KEY_DIVIDE = 0xB5; /* / on numeric keypad */
|
||||
public static final int KEY_MULTIPLY = 0x37; /* * on numeric keypad */
|
||||
|
||||
public static final int KEY_LCONTROL = 0x1D;
|
||||
public static final int KEY_RCONTROL = 0x9D;
|
||||
public static final int KEY_LALT = 0x38;
|
||||
public static final int KEY_RALT = 0xB8;
|
||||
public static final int KEY_LSHIFT = 0x2A;
|
||||
public static final int KEY_RSHIFT = 0x36;
|
||||
public static final int KEY_LMETA = 0xDB;
|
||||
public static final int KEY_RMETA = 0xDC;
|
||||
|
||||
|
||||
public static final int KEY_UP = 0xC8; /* UpArrow on arrow keypad */
|
||||
public static final int KEY_DOWN = 0xD0; /* DownArrow on arrow keypad */
|
||||
public static final int KEY_LEFT = 0xCB; /* LeftArrow on arrow keypad */
|
||||
public static final int KEY_RIGHT = 0xCD; /* RightArrow on arrow keypad */
|
||||
|
||||
public static final int KEY_HOME = 0xC7; /* Home on arrow keypad */
|
||||
public static final int KEY_END = 0xCF; /* End on arrow keypad */
|
||||
|
||||
public static final int KEY_PAGEUP = 0xC9; /* PgUp on arrow keypad */
|
||||
public static final int KEY_PAGEDOWN = 0xD1; /* PgDn on arrow keypad */
|
||||
|
||||
public static final int KEY_RETURN = 0x1C;
|
||||
public static final int KEY_PAUSE = 0xC5; /* Pause */
|
||||
public static final int KEY_INSERT = 0xD2; /* Insert on arrow keypad */
|
||||
public static final int KEY_DELETE = 0xD3; /* Delete on arrow keypad */
|
||||
|
||||
//@formatter:on
|
||||
}
|
||||
@@ -1,108 +0,0 @@
|
||||
package mightypork.rogue.loading;
|
||||
|
||||
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
|
||||
import mightypork.rogue.AppAccess;
|
||||
import mightypork.rogue.bus.events.MainLoopTaskRequest;
|
||||
import mightypork.rogue.bus.events.ResourceLoadRequest;
|
||||
import mightypork.utils.control.interf.Destroyable;
|
||||
import mightypork.utils.logging.Log;
|
||||
|
||||
|
||||
/**
|
||||
* Asynchronous resource loading thread.
|
||||
*
|
||||
* @author MightyPork
|
||||
*/
|
||||
public class AsyncResourceLoader extends Thread implements ResourceLoadRequest.Listener, Destroyable {
|
||||
|
||||
public static void launch(AppAccess app)
|
||||
{
|
||||
(new AsyncResourceLoader(app)).start();
|
||||
}
|
||||
|
||||
private final ExecutorService exs = Executors.newCachedThreadPool();
|
||||
|
||||
private final LinkedBlockingQueue<DeferredResource> toLoad = new LinkedBlockingQueue<DeferredResource>();
|
||||
private boolean stopped;
|
||||
private final AppAccess app;
|
||||
|
||||
|
||||
public AsyncResourceLoader(AppAccess app) {
|
||||
super("Deferred loader");
|
||||
this.app = app;
|
||||
app.bus().subscribe(this);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void loadResource(DeferredResource resource)
|
||||
{
|
||||
toLoad.add(resource);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
Log.f3("Asynchronous resource loader started.");
|
||||
|
||||
while (!stopped) {
|
||||
|
||||
try {
|
||||
final DeferredResource def = toLoad.take();
|
||||
if (def == null) continue;
|
||||
|
||||
if (!def.isLoaded()) {
|
||||
|
||||
// skip nulls
|
||||
if (def instanceof NullResource) continue;
|
||||
|
||||
// textures & fonts needs to be loaded in main thread
|
||||
if (def.getClass().isAnnotationPresent(MustLoadInMainThread.class)) {
|
||||
|
||||
Log.f3("<LOADER> Delegating to main thread:\n " + Log.str(def));
|
||||
|
||||
app.bus().send(new MainLoopTaskRequest(new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
def.load();
|
||||
}
|
||||
}));
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
Log.f3("<LOADER> Loading async:\n " + Log.str(def));
|
||||
|
||||
exs.submit(new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
def.load();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
} catch (final InterruptedException ignored) {
|
||||
//
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void destroy()
|
||||
{
|
||||
stopped = true;
|
||||
exs.shutdownNow();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,135 +0,0 @@
|
||||
package mightypork.rogue.loading;
|
||||
|
||||
|
||||
import mightypork.utils.control.interf.Destroyable;
|
||||
import mightypork.utils.logging.Log;
|
||||
import mightypork.utils.logging.LoggedName;
|
||||
|
||||
|
||||
/**
|
||||
* Deferred resource abstraction.<br>
|
||||
* Resources implementing {@link NullResource} will be treated as fake and not
|
||||
* attempted to load.
|
||||
*
|
||||
* @author MightyPork
|
||||
*/
|
||||
@LoggedName(name = "Resource")
|
||||
public abstract class BaseDeferredResource implements DeferredResource, Destroyable {
|
||||
|
||||
private final String resource;
|
||||
private boolean loadFailed = false;
|
||||
private boolean loadAttempted = false;
|
||||
|
||||
|
||||
public BaseDeferredResource(String resource) {
|
||||
this.resource = resource;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public synchronized final void load()
|
||||
{
|
||||
if (loadAttempted) {
|
||||
Log.w("<RES> Already loaded @ load():\n " + this);
|
||||
return;
|
||||
}
|
||||
|
||||
loadAttempted = true;
|
||||
|
||||
loadFailed = false;
|
||||
|
||||
if (isNull()) return;
|
||||
try {
|
||||
if (resource == null) {
|
||||
throw new NullPointerException("Resource string cannot be null for non-null resource.");
|
||||
}
|
||||
|
||||
Log.f3("<RES> Loading:\n " + this);
|
||||
loadResource(resource);
|
||||
Log.f3("<RES> Loaded:\n " + this);
|
||||
} catch (final Exception e) {
|
||||
loadFailed = true;
|
||||
Log.e("<RES> Failed to load:\n " + this, e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public final boolean isLoaded()
|
||||
{
|
||||
if (isNull()) return false;
|
||||
|
||||
return loadAttempted && !loadFailed;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Check if the resource is loaded; if not, try to do so.
|
||||
*
|
||||
* @return true if it's loaded now.
|
||||
*/
|
||||
public synchronized final boolean ensureLoaded()
|
||||
{
|
||||
if (isNull()) return false;
|
||||
|
||||
if (isLoaded()) {
|
||||
return true;
|
||||
} else {
|
||||
Log.w("<RES> First use, not loaded yet - loading directly\n " + this);
|
||||
load();
|
||||
}
|
||||
|
||||
return isLoaded();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Load the resource. Called from load() - once only.
|
||||
*
|
||||
* @param resource the path / name of a resource
|
||||
* @throws Exception when some problem prevented the resource from being
|
||||
* loaded.
|
||||
*/
|
||||
protected abstract void loadResource(String resource) throws Exception;
|
||||
|
||||
|
||||
@Override
|
||||
public abstract void destroy();
|
||||
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return Log.str(getClass()) + "(\"" + resource + "\")";
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int hashCode()
|
||||
{
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((resource == null) ? 0 : resource.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj)
|
||||
{
|
||||
if (this == obj) return true;
|
||||
if (obj == null) return false;
|
||||
if (!(obj instanceof BaseDeferredResource)) return false;
|
||||
final BaseDeferredResource other = (BaseDeferredResource) obj;
|
||||
if (resource == null) {
|
||||
if (other.resource != null) return false;
|
||||
} else if (!resource.equals(other.resource)) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
private boolean isNull()
|
||||
{
|
||||
return this instanceof NullResource;
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
package mightypork.rogue.loading;
|
||||
|
||||
|
||||
/**
|
||||
* Deferred resource
|
||||
*
|
||||
* @author MightyPork
|
||||
*/
|
||||
public interface DeferredResource {
|
||||
|
||||
/**
|
||||
* Load the actual resource, if not loaded yet.
|
||||
*/
|
||||
void load();
|
||||
|
||||
|
||||
/**
|
||||
* Check if resource was successfully loaded.
|
||||
*
|
||||
* @return true if already loaded
|
||||
*/
|
||||
boolean isLoaded();
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
package mightypork.rogue.loading;
|
||||
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
|
||||
/**
|
||||
* Resource that is texture-based and therefore needs to be loaded in the main
|
||||
* thread (ie. main loop).
|
||||
*
|
||||
* @author MightyPork
|
||||
*/
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE)
|
||||
@Inherited
|
||||
@Documented
|
||||
public @interface MustLoadInMainThread {}
|
||||
@@ -1,12 +0,0 @@
|
||||
package mightypork.rogue.loading;
|
||||
|
||||
|
||||
/**
|
||||
* Resource that is used as a placeholder instead of an actual resource; this
|
||||
* resource should not be attempted to be loaded.
|
||||
*
|
||||
* @author MightyPork
|
||||
*/
|
||||
public interface NullResource {
|
||||
|
||||
}
|
||||
@@ -1,208 +0,0 @@
|
||||
package mightypork.rogue.render;
|
||||
|
||||
|
||||
import static org.lwjgl.opengl.GL11.*;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import mightypork.rogue.AppAccess;
|
||||
import mightypork.rogue.bus.Subsystem;
|
||||
import mightypork.rogue.bus.events.ScreenChangeEvent;
|
||||
import mightypork.utils.logging.Log;
|
||||
import mightypork.utils.math.constraints.RectEvaluable;
|
||||
import mightypork.utils.math.coord.Coord;
|
||||
import mightypork.utils.math.coord.Rect;
|
||||
|
||||
import org.lwjgl.BufferUtils;
|
||||
import org.lwjgl.LWJGLException;
|
||||
import org.lwjgl.opengl.Display;
|
||||
import org.lwjgl.opengl.DisplayMode;
|
||||
|
||||
|
||||
public class DisplaySystem extends Subsystem implements RectEvaluable {
|
||||
|
||||
private DisplayMode windowDisplayMode;
|
||||
private int targetFps;
|
||||
|
||||
|
||||
public DisplaySystem(AppAccess app) {
|
||||
super(app);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void deinit()
|
||||
{
|
||||
Display.destroy();
|
||||
}
|
||||
|
||||
|
||||
public void setTargetFps(int fps)
|
||||
{
|
||||
this.targetFps = fps;
|
||||
}
|
||||
|
||||
|
||||
public void createMainWindow(int width, int height, boolean resizable, boolean fullscreen, String title)
|
||||
{
|
||||
try {
|
||||
Display.setDisplayMode(windowDisplayMode = new DisplayMode(width, height));
|
||||
Display.setResizable(resizable);
|
||||
Display.setVSyncEnabled(true);
|
||||
Display.setTitle(title);
|
||||
Display.create();
|
||||
|
||||
if (fullscreen) {
|
||||
switchFullscreen();
|
||||
Display.update();
|
||||
}
|
||||
|
||||
Render.init();
|
||||
|
||||
} catch (final LWJGLException e) {
|
||||
throw new RuntimeException("Could not initialize screen", e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Toggle FS if possible
|
||||
*/
|
||||
public void switchFullscreen()
|
||||
{
|
||||
try {
|
||||
|
||||
if (!Display.isFullscreen()) {
|
||||
Log.f3("Entering fullscreen.");
|
||||
// save window resize
|
||||
windowDisplayMode = new DisplayMode(Display.getWidth(), Display.getHeight());
|
||||
|
||||
Display.setDisplayMode(Display.getDesktopDisplayMode());
|
||||
Display.setFullscreen(true);
|
||||
Display.update();
|
||||
} else {
|
||||
Log.f3("Leaving fullscreen.");
|
||||
Display.setDisplayMode(windowDisplayMode);
|
||||
Display.update();
|
||||
}
|
||||
|
||||
bus().send(new ScreenChangeEvent(true, Display.isFullscreen(), getSize()));
|
||||
|
||||
} catch (final Throwable t) {
|
||||
Log.e("Failed to toggle fullscreen mode.", t);
|
||||
try {
|
||||
Display.setDisplayMode(windowDisplayMode);
|
||||
Display.update();
|
||||
} catch (final Throwable t1) {
|
||||
throw new RuntimeException("Failed to revert failed fullscreen toggle.", t1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public Screenshot takeScreenshot()
|
||||
{
|
||||
glReadBuffer(GL_FRONT);
|
||||
final int width = Display.getDisplayMode().getWidth();
|
||||
final int height = Display.getDisplayMode().getHeight();
|
||||
final int bpp = 4; // Assuming a 32-bit display with a byte each for red,
|
||||
// green, blue, and alpha.
|
||||
final ByteBuffer buffer = BufferUtils.createByteBuffer(width * height * bpp);
|
||||
glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
|
||||
|
||||
final Screenshot sc = new Screenshot(width, height, bpp, buffer);
|
||||
|
||||
return sc;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return true if close was requested (i.e. click on cross)
|
||||
*/
|
||||
public boolean isCloseRequested()
|
||||
{
|
||||
return Display.isCloseRequested();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get fullscreen state
|
||||
*
|
||||
* @return is fullscreen
|
||||
*/
|
||||
public boolean isFullscreen()
|
||||
{
|
||||
return Display.isFullscreen();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get screen size
|
||||
*
|
||||
* @return size
|
||||
*/
|
||||
public Coord getSize()
|
||||
{
|
||||
return new Coord(getWidth(), getHeight());
|
||||
}
|
||||
|
||||
|
||||
public int getWidth()
|
||||
{
|
||||
return Display.getWidth();
|
||||
}
|
||||
|
||||
|
||||
public int getHeight()
|
||||
{
|
||||
return Display.getHeight();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Start a OpenGL frame
|
||||
*/
|
||||
public void beginFrame()
|
||||
{
|
||||
// handle resize
|
||||
if (Display.wasResized()) {
|
||||
bus().send(new ScreenChangeEvent(false, Display.isFullscreen(), getSize()));
|
||||
}
|
||||
|
||||
glLoadIdentity();
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* End an OpenGL frame, flip buffers, sync to fps.
|
||||
*/
|
||||
public void endFrame()
|
||||
{
|
||||
Display.update(false); // don't poll input devices
|
||||
Display.sync(targetFps);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Rect getRect()
|
||||
{
|
||||
return new Rect(getSize());
|
||||
}
|
||||
|
||||
public static class Screenshot {
|
||||
|
||||
public int width;
|
||||
public int height;
|
||||
public int bpp;
|
||||
public ByteBuffer bytes;
|
||||
|
||||
|
||||
public Screenshot(int width, int height, int bpp, ByteBuffer buffer) {
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
this.bpp = bpp;
|
||||
this.bytes = buffer;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,494 +0,0 @@
|
||||
package mightypork.rogue.render;
|
||||
|
||||
|
||||
import static org.lwjgl.opengl.GL11.*;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import mightypork.rogue.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.lwjgl.opengl.GL11;
|
||||
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);
|
||||
|
||||
|
||||
public static void init()
|
||||
{
|
||||
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);
|
||||
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Scale
|
||||
*
|
||||
* @param factor vector of scaling factors
|
||||
*/
|
||||
public static void scale(Coord factor)
|
||||
{
|
||||
glScaled(factor.x, factor.y, factor.z);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Scale by X factor
|
||||
*
|
||||
* @param factor scaling factor
|
||||
*/
|
||||
public static void scaleXY(double factor)
|
||||
{
|
||||
glScaled(factor, factor, 1);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Scale by X factor
|
||||
*
|
||||
* @param factor scaling factor
|
||||
*/
|
||||
public static void scaleX(double factor)
|
||||
{
|
||||
glScaled(factor, 1, 1);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Scale by Y factor
|
||||
*
|
||||
* @param factor scaling factor
|
||||
*/
|
||||
public static void scaleY(double factor)
|
||||
{
|
||||
glScaled(1, factor, 1);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Scale by Z factor
|
||||
*
|
||||
* @param factor scaling factor
|
||||
*/
|
||||
public static void scaleZ(double factor)
|
||||
{
|
||||
glScaled(1, 1, factor);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Rotate around X axis
|
||||
*
|
||||
* @param angle deg
|
||||
*/
|
||||
public static void rotateX(double angle)
|
||||
{
|
||||
rotate(angle, AXIS_X);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Rotate around Y axis
|
||||
*
|
||||
* @param angle deg
|
||||
*/
|
||||
public static void rotateY(double angle)
|
||||
{
|
||||
rotate(angle, AXIS_Y);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Rotate around Z axis
|
||||
*
|
||||
* @param angle deg
|
||||
*/
|
||||
public static void rotateZ(double angle)
|
||||
{
|
||||
rotate(angle, AXIS_Z);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Rotate
|
||||
*
|
||||
* @param angle rotate angle
|
||||
* @param axis rotation axis
|
||||
*/
|
||||
public static void rotate(double angle, Coord axis)
|
||||
{
|
||||
final Coord vec = axis.norm(1);
|
||||
glRotated(angle, vec.x, vec.y, vec.z);
|
||||
}
|
||||
|
||||
private static int pushed = 0;
|
||||
|
||||
|
||||
/**
|
||||
* Store GL state
|
||||
*/
|
||||
public static void pushState()
|
||||
{
|
||||
pushed++;
|
||||
|
||||
if (pushed >= 3) {
|
||||
Log.w("Suspicious amount of state pushes: " + pushed);
|
||||
}
|
||||
|
||||
// Log.f3("push : "+pushed);
|
||||
|
||||
GL11.glPushAttrib(GL11.GL_ALL_ATTRIB_BITS);
|
||||
GL11.glPushClientAttrib(GL11.GL_ALL_CLIENT_ATTRIB_BITS);
|
||||
GL11.glPushMatrix();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Restore Gl state
|
||||
*/
|
||||
public static void popState()
|
||||
{
|
||||
if (pushed == 0) {
|
||||
Log.w("Pop without push.");
|
||||
}
|
||||
|
||||
pushed--;
|
||||
|
||||
// Log.f3("pop : "+pushed);
|
||||
|
||||
GL11.glPopMatrix();
|
||||
GL11.glPopClientAttrib();
|
||||
GL11.glPopAttrib();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Load texture
|
||||
*
|
||||
* @param resourcePath
|
||||
* @return the loaded texture
|
||||
*/
|
||||
public synchronized static Texture loadTexture(String resourcePath)
|
||||
{
|
||||
|
||||
try {
|
||||
|
||||
final String ext = FileUtils.getExtension(resourcePath).toUpperCase();
|
||||
|
||||
final Texture texture = TextureLoader.getTexture(ext, ResourceLoader.getResourceAsStream(resourcePath));
|
||||
|
||||
if (texture == null) {
|
||||
Log.w("Texture " + resourcePath + " could not be loaded.");
|
||||
}
|
||||
|
||||
return texture;
|
||||
|
||||
} catch (final 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
|
||||
* @param linear use linear interpolation for scaling
|
||||
* @throws RuntimeException if not loaded yet
|
||||
*/
|
||||
private static void bindTexture(Texture texture, boolean linear) throws RuntimeException
|
||||
{
|
||||
texture.bind();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Bind texture with linear interpolation
|
||||
*
|
||||
* @param texture the texture
|
||||
* @throws RuntimeException if not loaded yet
|
||||
*/
|
||||
private static void bindTexture(Texture texture) throws RuntimeException
|
||||
{
|
||||
bindTexture(texture, false);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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)
|
||||
{
|
||||
final double left = quad.x1();
|
||||
final double bottom = quad.y1();
|
||||
final double right = quad.x2();
|
||||
final double top = quad.y2();
|
||||
|
||||
// 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)
|
||||
*/
|
||||
public static void quadUV(Rect quad, Rect uvs)
|
||||
{
|
||||
glBegin(GL_QUADS);
|
||||
quadUV_nobound(quad, uvs);
|
||||
glEnd();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Draw quad without glBegin and glEnd.
|
||||
*
|
||||
* @param quad rectangle (px)
|
||||
* @param uvs texture coords (0-1)
|
||||
*/
|
||||
public static void quadUV_nobound(Rect quad, Rect uvs)
|
||||
{
|
||||
final double left = quad.x1();
|
||||
final double bottom = quad.y1();
|
||||
final double right = quad.x2();
|
||||
final double top = quad.y2();
|
||||
|
||||
final double tleft = uvs.x1();
|
||||
final double tbottom = uvs.y1();
|
||||
final double tright = uvs.x2();
|
||||
final double ttop = uvs.y2();
|
||||
|
||||
// quad with texture
|
||||
glTexCoord2d(tleft, ttop);
|
||||
glVertex2d(left, top);
|
||||
glTexCoord2d(tright, ttop);
|
||||
glVertex2d(right, top);
|
||||
glTexCoord2d(tright, tbottom);
|
||||
glVertex2d(right, bottom);
|
||||
glTexCoord2d(tleft, tbottom);
|
||||
glVertex2d(left, bottom);
|
||||
}
|
||||
|
||||
|
||||
public static void quadGradH(Rect quad, RGB colorLeft, RGB colorRight)
|
||||
{
|
||||
final double left = quad.x1();
|
||||
final double bottom = quad.y1();
|
||||
final double right = quad.y2();
|
||||
final double top = quad.y2();
|
||||
|
||||
// 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)
|
||||
{
|
||||
final double left = quad.x1();
|
||||
final double bottom = quad.y1();
|
||||
final double right = quad.y2();
|
||||
final double top = quad.y2();
|
||||
|
||||
// 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)
|
||||
{
|
||||
pushState();
|
||||
bindTexture(texture);
|
||||
setColor(tint);
|
||||
quadUV(quad, uvs);
|
||||
popState();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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,16 +0,0 @@
|
||||
package mightypork.rogue.render;
|
||||
|
||||
|
||||
/**
|
||||
* Can be rendered
|
||||
*
|
||||
* @author MightyPork
|
||||
*/
|
||||
public interface Renderable {
|
||||
|
||||
/**
|
||||
* Render on screen
|
||||
*/
|
||||
void render();
|
||||
|
||||
}
|
||||
+11
-11
@@ -1,37 +1,37 @@
|
||||
package mightypork.rogue.gui.screens.test_bouncyboxes;
|
||||
package mightypork.rogue.screens.test_bouncyboxes;
|
||||
|
||||
|
||||
import static mightypork.utils.math.constraints.ConstraintFactory.*;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
import mightypork.rogue.gui.renderers.PluggableRenderer;
|
||||
import mightypork.rogue.render.Render;
|
||||
import mightypork.utils.control.interf.Updateable;
|
||||
import mightypork.gamecore.control.interf.Updateable;
|
||||
import mightypork.gamecore.gui.renderers.PluggableRenderer;
|
||||
import mightypork.gamecore.render.Render;
|
||||
import mightypork.utils.math.animation.AnimDouble;
|
||||
import mightypork.utils.math.animation.Easing;
|
||||
import mightypork.utils.math.color.RGB;
|
||||
import mightypork.utils.math.constraints.NumEvaluable;
|
||||
import mightypork.utils.math.constraints.RectEvaluable;
|
||||
import mightypork.utils.math.constraints.NumberConstraint;
|
||||
import mightypork.utils.math.constraints.RectConstraint;
|
||||
|
||||
|
||||
public class BouncyBox extends PluggableRenderer implements Updateable {
|
||||
|
||||
private final Random rand = new Random();
|
||||
|
||||
private final RectEvaluable box;
|
||||
private final RectConstraint box;
|
||||
|
||||
private final AnimDouble pos = new AnimDouble(0, Easing.BOUNCE_OUT);
|
||||
|
||||
|
||||
public BouncyBox() {
|
||||
// create box
|
||||
final NumEvaluable side = c_height(this);
|
||||
RectEvaluable abox = c_box(this, side, side);
|
||||
final NumberConstraint side = c_height(this);
|
||||
RectConstraint abox = c_box(this, side, side);
|
||||
|
||||
// move
|
||||
final NumEvaluable move_length = c_sub(c_width(this), side);
|
||||
final NumEvaluable offset = c_mul(move_length, c_n(pos));
|
||||
final NumberConstraint move_length = c_sub(c_width(this), side);
|
||||
final NumberConstraint offset = c_mul(move_length, c_n(pos));
|
||||
abox = c_move(abox, offset, c_n(0));
|
||||
|
||||
// add padding
|
||||
+10
-10
@@ -1,4 +1,4 @@
|
||||
package mightypork.rogue.gui.screens.test_bouncyboxes;
|
||||
package mightypork.rogue.screens.test_bouncyboxes;
|
||||
|
||||
|
||||
import static mightypork.utils.math.constraints.ConstraintFactory.*;
|
||||
@@ -6,16 +6,16 @@ import static mightypork.utils.math.constraints.ConstraintFactory.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import mightypork.gamecore.gui.renderers.RowHolder;
|
||||
import mightypork.gamecore.gui.renderers.TextRenderer;
|
||||
import mightypork.gamecore.gui.renderers.TextRenderer.Align;
|
||||
import mightypork.gamecore.gui.screens.Screen;
|
||||
import mightypork.gamecore.gui.screens.ScreenLayer;
|
||||
import mightypork.gamecore.input.KeyStroke;
|
||||
import mightypork.gamecore.input.Keys;
|
||||
import mightypork.rogue.Res;
|
||||
import mightypork.rogue.gui.renderers.RowHolder;
|
||||
import mightypork.rogue.gui.renderers.TextRenderer;
|
||||
import mightypork.rogue.gui.renderers.TextRenderer.Align;
|
||||
import mightypork.rogue.gui.screens.Screen;
|
||||
import mightypork.rogue.gui.screens.ScreenLayer;
|
||||
import mightypork.rogue.input.KeyStroke;
|
||||
import mightypork.rogue.input.Keys;
|
||||
import mightypork.utils.math.color.RGB;
|
||||
import mightypork.utils.math.constraints.RectEvaluable;
|
||||
import mightypork.utils.math.constraints.RectConstraint;
|
||||
|
||||
|
||||
public class LayerBouncyBoxes extends ScreenLayer {
|
||||
@@ -46,7 +46,7 @@ public class LayerBouncyBoxes extends ScreenLayer {
|
||||
});
|
||||
|
||||
// shrink screen rect by 8% on all sides
|
||||
final RectEvaluable holder_rect = c_shrink(this, c_percent(c_height(this), c_n(8)));
|
||||
final RectConstraint holder_rect = c_shrink(this, c_percent(c_height(this), c_n(8)));
|
||||
|
||||
addChildClient(layout = new RowHolder(screen, holder_rect, 8));
|
||||
|
||||
+6
-6
@@ -1,11 +1,11 @@
|
||||
package mightypork.rogue.gui.screens.test_bouncyboxes;
|
||||
package mightypork.rogue.screens.test_bouncyboxes;
|
||||
|
||||
|
||||
import mightypork.rogue.AppAccess;
|
||||
import mightypork.rogue.bus.events.ScreenRequestEvent;
|
||||
import mightypork.rogue.gui.screens.LayeredScreen;
|
||||
import mightypork.rogue.input.KeyStroke;
|
||||
import mightypork.rogue.input.Keys;
|
||||
import mightypork.gamecore.AppAccess;
|
||||
import mightypork.gamecore.control.bus.events.ScreenRequestEvent;
|
||||
import mightypork.gamecore.gui.screens.LayeredScreen;
|
||||
import mightypork.gamecore.input.KeyStroke;
|
||||
import mightypork.gamecore.input.Keys;
|
||||
|
||||
|
||||
public class ScreenTestBouncy extends LayeredScreen {
|
||||
+12
-12
@@ -1,24 +1,24 @@
|
||||
package mightypork.rogue.gui.screens.test_cat_sound;
|
||||
package mightypork.rogue.screens.test_cat_sound;
|
||||
|
||||
|
||||
import static mightypork.utils.math.constraints.ConstraintFactory.*;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
import mightypork.gamecore.control.bus.events.MouseButtonEvent;
|
||||
import mightypork.gamecore.control.interf.Updateable;
|
||||
import mightypork.gamecore.gui.renderers.ImageRenderer;
|
||||
import mightypork.gamecore.gui.renderers.TextRenderer;
|
||||
import mightypork.gamecore.gui.renderers.TextRenderer.Align;
|
||||
import mightypork.gamecore.gui.screens.Screen;
|
||||
import mightypork.gamecore.gui.screens.ScreenLayer;
|
||||
import mightypork.gamecore.input.KeyStroke;
|
||||
import mightypork.gamecore.input.Keys;
|
||||
import mightypork.rogue.Res;
|
||||
import mightypork.rogue.bus.events.MouseButtonEvent;
|
||||
import mightypork.rogue.gui.renderers.ImageRenderer;
|
||||
import mightypork.rogue.gui.renderers.TextRenderer;
|
||||
import mightypork.rogue.gui.renderers.TextRenderer.Align;
|
||||
import mightypork.rogue.gui.screens.Screen;
|
||||
import mightypork.rogue.gui.screens.ScreenLayer;
|
||||
import mightypork.rogue.input.KeyStroke;
|
||||
import mightypork.rogue.input.Keys;
|
||||
import mightypork.utils.control.interf.Updateable;
|
||||
import mightypork.utils.math.animation.AnimDouble;
|
||||
import mightypork.utils.math.animation.Easing;
|
||||
import mightypork.utils.math.color.RGB;
|
||||
import mightypork.utils.math.constraints.RectEvaluable;
|
||||
import mightypork.utils.math.constraints.RectConstraint;
|
||||
import mightypork.utils.math.coord.Coord;
|
||||
|
||||
|
||||
@@ -44,7 +44,7 @@ public class LayerFlyingCat extends ScreenLayer implements Updateable, MouseButt
|
||||
cat.setContext(c_centered(c_box(this, c_n(size), c_n(size)), c_n(xPos), c_n(yPos)));
|
||||
|
||||
//@formatter:off
|
||||
final RectEvaluable flyingFontBox = c_centered(
|
||||
final RectConstraint flyingFontBox = c_centered(
|
||||
c_box(this, c_n(0), c_n(64)),
|
||||
input().c_mouse_x(),
|
||||
input().c_mouse_y()
|
||||
+8
-8
@@ -1,14 +1,14 @@
|
||||
package mightypork.rogue.gui.screens.test_cat_sound;
|
||||
package mightypork.rogue.screens.test_cat_sound;
|
||||
|
||||
|
||||
import mightypork.rogue.AppAccess;
|
||||
import mightypork.gamecore.AppAccess;
|
||||
import mightypork.gamecore.control.bus.events.ScreenRequestEvent;
|
||||
import mightypork.gamecore.gui.screens.LayeredScreen;
|
||||
import mightypork.gamecore.input.KeyStroke;
|
||||
import mightypork.gamecore.input.Keys;
|
||||
import mightypork.rogue.Res;
|
||||
import mightypork.rogue.bus.events.ActionRequest;
|
||||
import mightypork.rogue.bus.events.ActionRequest.RequestType;
|
||||
import mightypork.rogue.bus.events.ScreenRequestEvent;
|
||||
import mightypork.rogue.gui.screens.LayeredScreen;
|
||||
import mightypork.rogue.input.KeyStroke;
|
||||
import mightypork.rogue.input.Keys;
|
||||
import mightypork.rogue.events.ActionRequest;
|
||||
import mightypork.rogue.events.ActionRequest.RequestType;
|
||||
|
||||
|
||||
public class ScreenTestCat extends LayeredScreen {
|
||||
+4
-4
@@ -1,10 +1,10 @@
|
||||
package mightypork.rogue.gui.screens.test_font;
|
||||
package mightypork.rogue.screens.test_font;
|
||||
|
||||
|
||||
import mightypork.rogue.AppAccess;
|
||||
import mightypork.gamecore.AppAccess;
|
||||
import mightypork.gamecore.gui.screens.Screen;
|
||||
import mightypork.gamecore.resources.fonts.FontRenderer;
|
||||
import mightypork.rogue.Res;
|
||||
import mightypork.rogue.fonts.FontRenderer;
|
||||
import mightypork.rogue.gui.screens.Screen;
|
||||
import mightypork.utils.math.color.RGB;
|
||||
import mightypork.utils.math.coord.Coord;
|
||||
|
||||
@@ -1,236 +0,0 @@
|
||||
package mightypork.rogue.sounds;
|
||||
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import mightypork.rogue.loading.BaseDeferredResource;
|
||||
import mightypork.utils.files.FileUtils;
|
||||
import mightypork.utils.logging.LoggedName;
|
||||
import mightypork.utils.math.coord.Coord;
|
||||
|
||||
import org.newdawn.slick.openal.Audio;
|
||||
import org.newdawn.slick.openal.SoundStore;
|
||||
|
||||
|
||||
/**
|
||||
* Wrapper class for slick audio
|
||||
*
|
||||
* @author MightyPork
|
||||
*/
|
||||
@LoggedName(name = "Audio")
|
||||
public class DeferredAudio extends BaseDeferredResource {
|
||||
|
||||
private enum PlayMode
|
||||
{
|
||||
EFFECT, MUSIC;
|
||||
}
|
||||
|
||||
/** Audio resource */
|
||||
private Audio backingAudio = null;
|
||||
|
||||
// last play options
|
||||
private PlayMode mode = PlayMode.EFFECT;
|
||||
private double pauseLoopPosition = 0;
|
||||
private boolean looping = false;
|
||||
private boolean paused = false;
|
||||
private double lastPlayPitch = 1;
|
||||
private double lastPlayGain = 1;
|
||||
|
||||
|
||||
/**
|
||||
* Create deferred primitive audio player
|
||||
*
|
||||
* @param resourceName resource to load when needed
|
||||
*/
|
||||
public DeferredAudio(String resourceName) {
|
||||
super(resourceName);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Pause loop (remember position and stop playing) - if was looping
|
||||
*/
|
||||
public void pauseLoop()
|
||||
{
|
||||
if (!ensureLoaded()) return;
|
||||
|
||||
if (isPlaying() && looping) {
|
||||
pauseLoopPosition = backingAudio.getPosition();
|
||||
stop();
|
||||
paused = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Resume loop (if was paused)
|
||||
*
|
||||
* @return source ID
|
||||
*/
|
||||
public int resumeLoop()
|
||||
{
|
||||
if (!ensureLoaded()) return -1;
|
||||
|
||||
int source = -1;
|
||||
if (looping && paused) {
|
||||
if (mode == PlayMode.MUSIC) {
|
||||
source = backingAudio.playAsMusic((float) lastPlayPitch, (float) lastPlayGain, true);
|
||||
} else {
|
||||
source = backingAudio.playAsSoundEffect((float) lastPlayPitch, (float) lastPlayGain, true);
|
||||
}
|
||||
backingAudio.setPosition((float) pauseLoopPosition);
|
||||
paused = false;
|
||||
}
|
||||
return source;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void loadResource(String resource) throws IOException
|
||||
{
|
||||
final String ext = FileUtils.getExtension(resource);
|
||||
|
||||
if (ext.equalsIgnoreCase("ogg")) {
|
||||
backingAudio = SoundStore.get().getOgg(resource);
|
||||
|
||||
} else if (ext.equalsIgnoreCase("wav")) {
|
||||
backingAudio = SoundStore.get().getWAV(resource);
|
||||
|
||||
} else if (ext.equalsIgnoreCase("aif")) {
|
||||
backingAudio = SoundStore.get().getAIF(resource);
|
||||
|
||||
} else if (ext.equalsIgnoreCase("mod")) {
|
||||
backingAudio = SoundStore.get().getMOD(resource);
|
||||
|
||||
} else {
|
||||
throw new RuntimeException("Invalid audio file extension.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void stop()
|
||||
{
|
||||
if (!isLoaded()) return;
|
||||
|
||||
backingAudio.stop();
|
||||
paused = false;
|
||||
}
|
||||
|
||||
|
||||
public boolean isPlaying()
|
||||
{
|
||||
if (!isLoaded()) return false;
|
||||
|
||||
return backingAudio.isPlaying();
|
||||
}
|
||||
|
||||
|
||||
public boolean isPaused()
|
||||
{
|
||||
if (!isLoaded()) return false;
|
||||
|
||||
return backingAudio.isPaused();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Play as sound effect at listener position
|
||||
*
|
||||
* @param pitch pitch (1 = default)
|
||||
* @param gain gain (0-1)
|
||||
* @param loop looping
|
||||
* @return source id
|
||||
*/
|
||||
public int playAsEffect(double pitch, double gain, boolean loop)
|
||||
{
|
||||
return playAsEffect(pitch, gain, loop, SoundSystem.getListener());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Play as sound effect at given X-Y position
|
||||
*
|
||||
* @param pitch pitch (1 = default)
|
||||
* @param gain gain (0-1)
|
||||
* @param loop looping
|
||||
* @param x
|
||||
* @param y
|
||||
* @return source id
|
||||
*/
|
||||
public int playAsEffect(double pitch, double gain, boolean loop, double x, double y)
|
||||
{
|
||||
return playAsEffect(pitch, gain, loop, x, y, SoundSystem.getListener().z);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Play as sound effect at given position
|
||||
*
|
||||
* @param pitch pitch (1 = default)
|
||||
* @param gain gain (0-1)
|
||||
* @param loop looping
|
||||
* @param x
|
||||
* @param y
|
||||
* @param z
|
||||
* @return source id
|
||||
*/
|
||||
public int playAsEffect(double pitch, double gain, boolean loop, double x, double y, double z)
|
||||
{
|
||||
if (!ensureLoaded()) return -1;
|
||||
|
||||
this.lastPlayPitch = pitch;
|
||||
this.lastPlayGain = gain;
|
||||
looping = loop;
|
||||
mode = PlayMode.EFFECT;
|
||||
return backingAudio.playAsSoundEffect((float) pitch, (float) gain, loop, (float) x, (float) y, (float) z);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Play as sound effect at given position
|
||||
*
|
||||
* @param pitch pitch (1 = default)
|
||||
* @param gain gain (0-1)
|
||||
* @param loop looping
|
||||
* @param pos coord
|
||||
* @return source id
|
||||
*/
|
||||
public int playAsEffect(double pitch, double gain, boolean loop, Coord pos)
|
||||
{
|
||||
if (!ensureLoaded()) return -1;
|
||||
|
||||
return playAsEffect(pitch, gain, loop, pos.x, pos.y, pos.z);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Play as music using source 0.<br>
|
||||
* Discouraged, since this does not allow cross-fading.
|
||||
*
|
||||
* @param pitch play pitch
|
||||
* @param gain play gain
|
||||
* @param loop looping
|
||||
* @return source
|
||||
*/
|
||||
public int playAsMusic(double pitch, double gain, boolean loop)
|
||||
{
|
||||
if (!ensureLoaded()) return -1;
|
||||
|
||||
this.lastPlayPitch = (float) pitch;
|
||||
this.lastPlayGain = (float) gain;
|
||||
looping = loop;
|
||||
mode = PlayMode.MUSIC;
|
||||
return backingAudio.playAsMusic((float) pitch, (float) gain, loop);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void destroy()
|
||||
{
|
||||
if (!isLoaded() || backingAudio == null) return;
|
||||
|
||||
backingAudio.release();
|
||||
backingAudio = null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
package mightypork.rogue.sounds;
|
||||
|
||||
|
||||
import mightypork.utils.math.Calc;
|
||||
import mightypork.utils.objects.Mutable;
|
||||
|
||||
|
||||
/**
|
||||
* Volume combined of multiple volumes, combining them (multiplication).
|
||||
*
|
||||
* @author MightyPork
|
||||
*/
|
||||
public class JointVolume extends Mutable<Double> {
|
||||
|
||||
private final Mutable<Double>[] volumes;
|
||||
|
||||
|
||||
/**
|
||||
* Create joint volume with master gain of 1
|
||||
*
|
||||
* @param volumes individual volumes to join
|
||||
*/
|
||||
public JointVolume(Mutable<Double>... volumes) {
|
||||
super(1D);
|
||||
this.volumes = volumes;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get combined gain (multiplied)
|
||||
*/
|
||||
@Override
|
||||
public Double get()
|
||||
{
|
||||
double d = super.get();
|
||||
for (final Mutable<Double> v : volumes)
|
||||
d *= v.get();
|
||||
|
||||
return Calc.clampd(d, 0, 1);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set master gain
|
||||
*/
|
||||
@Override
|
||||
public void set(Double o)
|
||||
{
|
||||
super.set(o);
|
||||
}
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
package mightypork.rogue.sounds;
|
||||
|
||||
|
||||
import mightypork.rogue.loading.NullResource;
|
||||
import mightypork.utils.logging.LoggedName;
|
||||
|
||||
|
||||
/**
|
||||
* Placeholder for cases where no matching audio is found and
|
||||
* {@link NullPointerException} has to be avoided.
|
||||
*
|
||||
* @author MightyPork
|
||||
*/
|
||||
@LoggedName(name = "NullAudio")
|
||||
public class NullAudio extends DeferredAudio implements NullResource {
|
||||
|
||||
public NullAudio() {
|
||||
super(null);
|
||||
}
|
||||
}
|
||||
@@ -1,92 +0,0 @@
|
||||
package mightypork.rogue.sounds;
|
||||
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import mightypork.rogue.AppAccess;
|
||||
import mightypork.rogue.AppAdapter;
|
||||
import mightypork.rogue.sounds.players.EffectPlayer;
|
||||
import mightypork.rogue.sounds.players.LoopPlayer;
|
||||
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 final Map<String, EffectPlayer> effects = new HashMap<String, EffectPlayer>();
|
||||
private final 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)
|
||||
{
|
||||
final 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)
|
||||
{
|
||||
final EffectPlayer p = effects.get(key);
|
||||
if (p == null) {
|
||||
Log.w("Requesting unknown sound effect \"" + key + "\".");
|
||||
return NULL_EFFECT;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
}
|
||||
@@ -1,213 +0,0 @@
|
||||
package mightypork.rogue.sounds;
|
||||
|
||||
|
||||
import java.nio.FloatBuffer;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import mightypork.rogue.AppAccess;
|
||||
import mightypork.rogue.bus.Subsystem;
|
||||
import mightypork.rogue.bus.events.ResourceLoadRequest;
|
||||
import mightypork.rogue.sounds.players.EffectPlayer;
|
||||
import mightypork.rogue.sounds.players.LoopPlayer;
|
||||
import mightypork.utils.control.interf.Updateable;
|
||||
import mightypork.utils.math.Calc.Buffers;
|
||||
import mightypork.utils.math.coord.Coord;
|
||||
import mightypork.utils.objects.Mutable;
|
||||
|
||||
import org.lwjgl.openal.AL;
|
||||
import org.lwjgl.openal.AL10;
|
||||
import org.newdawn.slick.openal.SoundStore;
|
||||
|
||||
|
||||
/**
|
||||
* Sound system class (only one instance should be made per application)
|
||||
*
|
||||
* @author MightyPork
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
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 Coord listener = new Coord();
|
||||
|
||||
static {
|
||||
// initialize sound system
|
||||
SoundStore.get().setMaxSources(MAX_SOURCES);
|
||||
SoundStore.get().init();
|
||||
|
||||
setListener(INITIAL_LISTENER_POS);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set listener pos
|
||||
*
|
||||
* @param pos
|
||||
*/
|
||||
public static void setListener(Coord pos)
|
||||
{
|
||||
listener.setTo(pos);
|
||||
FloatBuffer buf3 = Buffers.alloc(3);
|
||||
FloatBuffer buf6 = Buffers.alloc(6);
|
||||
buf3.clear();
|
||||
Buffers.fill(buf3, (float) pos.x, (float) pos.y, (float) pos.z);
|
||||
AL10.alListener(AL10.AL_POSITION, buf3);
|
||||
buf3.clear();
|
||||
Buffers.fill(buf3, 0, 0, 0);
|
||||
AL10.alListener(AL10.AL_VELOCITY, buf3);
|
||||
buf6.clear();
|
||||
Buffers.fill(buf6, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f);
|
||||
AL10.alListener(AL10.AL_ORIENTATION, buf6);
|
||||
buf3 = buf6 = null;
|
||||
}
|
||||
|
||||
|
||||
public static Coord getListener()
|
||||
{
|
||||
return listener;
|
||||
}
|
||||
|
||||
// -- instance --
|
||||
|
||||
public final Mutable<Double> masterVolume = new Mutable<Double>(1D);
|
||||
public final Mutable<Double> effectsVolume = new JointVolume(masterVolume);
|
||||
public final Mutable<Double> loopsVolume = new JointVolume(masterVolume);
|
||||
|
||||
private final Set<LoopPlayer> loopPlayers = new HashSet<LoopPlayer>();
|
||||
private final Set<DeferredAudio> resources = new HashSet<DeferredAudio>();
|
||||
|
||||
|
||||
public SoundSystem(AppAccess app) {
|
||||
super(app);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public final void deinit()
|
||||
{
|
||||
for (final DeferredAudio r : resources) {
|
||||
r.destroy();
|
||||
}
|
||||
|
||||
SoundStore.get().clear();
|
||||
AL.destroy();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void update(double delta)
|
||||
{
|
||||
for (final Updateable lp : loopPlayers) {
|
||||
lp.update(delta);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create effect resource
|
||||
*
|
||||
* @param resource resource path
|
||||
* @param pitch default pitch (1 = unchanged)
|
||||
* @param gain default gain (0-1)
|
||||
* @return player
|
||||
*/
|
||||
public EffectPlayer createEffect(String resource, double pitch, double gain)
|
||||
{
|
||||
return new EffectPlayer(getResource(resource), pitch, gain, effectsVolume);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Register loop resource (music / effect loop)
|
||||
*
|
||||
* @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 LoopPlayer createLoop(String resource, double pitch, double gain, double fadeIn, double fadeOut)
|
||||
{
|
||||
final LoopPlayer p = new LoopPlayer(getResource(resource), pitch, gain, loopsVolume);
|
||||
p.setFadeTimes(fadeIn, fadeOut);
|
||||
loopPlayers.add(p);
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create {@link DeferredAudio} for a resource
|
||||
*
|
||||
* @param res a resource name
|
||||
* @return the resource
|
||||
* @throws IllegalArgumentException if resource is already registered
|
||||
*/
|
||||
private DeferredAudio getResource(String res)
|
||||
{
|
||||
final DeferredAudio a = new DeferredAudio(res);
|
||||
bus().send(new ResourceLoadRequest(a));
|
||||
|
||||
if (resources.contains(a)) throw new IllegalArgumentException("Sound resource " + res + " is already registered.");
|
||||
resources.add(a);
|
||||
return a;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Fade out all loops (ie. for screen transitions)
|
||||
*/
|
||||
public void fadeOutAllLoops()
|
||||
{
|
||||
for (final LoopPlayer p : loopPlayers) {
|
||||
p.fadeOut();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Pause all loops (leave volume unchanged)
|
||||
*/
|
||||
public void pauseAllLoops()
|
||||
{
|
||||
for (final LoopPlayer p : loopPlayers) {
|
||||
p.pause();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set level of master volume
|
||||
*
|
||||
* @param d level
|
||||
*/
|
||||
public void setMasterVolume(double d)
|
||||
{
|
||||
masterVolume.set(d);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set level of effects volume
|
||||
*
|
||||
* @param d level
|
||||
*/
|
||||
public void setEffectsVolume(double d)
|
||||
{
|
||||
effectsVolume.set(d);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set level of music volume
|
||||
*
|
||||
* @param d level
|
||||
*/
|
||||
public void setMusicVolume(double d)
|
||||
{
|
||||
loopsVolume.set(d);
|
||||
}
|
||||
}
|
||||
@@ -1,81 +0,0 @@
|
||||
package mightypork.rogue.sounds.players;
|
||||
|
||||
|
||||
import mightypork.rogue.sounds.DeferredAudio;
|
||||
import mightypork.utils.control.interf.Destroyable;
|
||||
import mightypork.utils.objects.Mutable;
|
||||
|
||||
|
||||
public abstract class BaseAudioPlayer implements Destroyable {
|
||||
|
||||
/** the track */
|
||||
private final DeferredAudio audio;
|
||||
|
||||
/** base gain for sfx */
|
||||
private final double baseGain;
|
||||
|
||||
/** base pitch for sfx */
|
||||
private final double basePitch;
|
||||
|
||||
/** dedicated volume control */
|
||||
private final Mutable<Double> gainMultiplier;
|
||||
|
||||
|
||||
public BaseAudioPlayer(DeferredAudio track, double baseGain, Mutable<Double> gainMultiplier) {
|
||||
this(track, 1, baseGain, gainMultiplier);
|
||||
}
|
||||
|
||||
|
||||
public BaseAudioPlayer(DeferredAudio track, double basePitch, double baseGain, Mutable<Double> gainMultiplier) {
|
||||
this.audio = track;
|
||||
|
||||
this.baseGain = baseGain;
|
||||
this.basePitch = basePitch;
|
||||
|
||||
if (gainMultiplier == null) gainMultiplier = new Mutable<Double>(1D);
|
||||
|
||||
this.gainMultiplier = gainMultiplier;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void destroy()
|
||||
{
|
||||
audio.destroy();
|
||||
}
|
||||
|
||||
|
||||
protected DeferredAudio getAudio()
|
||||
{
|
||||
return audio;
|
||||
}
|
||||
|
||||
|
||||
protected double getGain(double multiplier)
|
||||
{
|
||||
return baseGain * gainMultiplier.get() * multiplier;
|
||||
}
|
||||
|
||||
|
||||
protected double getPitch(double multiplier)
|
||||
{
|
||||
return basePitch * multiplier;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get if audio is valid
|
||||
*
|
||||
* @return is valid
|
||||
*/
|
||||
protected boolean hasAudio()
|
||||
{
|
||||
return (audio != null);
|
||||
}
|
||||
|
||||
|
||||
public void load()
|
||||
{
|
||||
if (hasAudio()) audio.load();
|
||||
}
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
package mightypork.rogue.sounds.players;
|
||||
|
||||
|
||||
import mightypork.rogue.sounds.DeferredAudio;
|
||||
import mightypork.utils.math.coord.Coord;
|
||||
import mightypork.utils.objects.Mutable;
|
||||
|
||||
|
||||
public class EffectPlayer extends BaseAudioPlayer {
|
||||
|
||||
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 (!hasAudio()) return -1;
|
||||
|
||||
return getAudio().playAsEffect(getPitch(pitch), getGain(gain), false);
|
||||
}
|
||||
|
||||
|
||||
public int play(double gain)
|
||||
{
|
||||
return play(1, gain);
|
||||
}
|
||||
|
||||
|
||||
public int play(double pitch, double gain, Coord pos)
|
||||
{
|
||||
if (!hasAudio()) return -1;
|
||||
|
||||
return getAudio().playAsEffect(getPitch(pitch), getGain(gain), false, pos);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,133 +0,0 @@
|
||||
package mightypork.rogue.sounds.players;
|
||||
|
||||
|
||||
import mightypork.rogue.sounds.DeferredAudio;
|
||||
import mightypork.utils.control.interf.Updateable;
|
||||
import mightypork.utils.control.timing.Pauseable;
|
||||
import mightypork.utils.math.animation.AnimDouble;
|
||||
import mightypork.utils.objects.Mutable;
|
||||
|
||||
import org.lwjgl.openal.AL10;
|
||||
|
||||
|
||||
public class LoopPlayer extends BaseAudioPlayer implements Updateable, Pauseable {
|
||||
|
||||
private int sourceID = -1;
|
||||
|
||||
/** animator for fade in and fade out */
|
||||
private final AnimDouble fadeAnim = new AnimDouble(0);
|
||||
|
||||
private double lastUpdateGain = 0;
|
||||
|
||||
/** flag that track is paused */
|
||||
private boolean paused = true;
|
||||
|
||||
/** Default fadeIn time */
|
||||
private double inTime = 1;
|
||||
|
||||
/** Default fadeOut time */
|
||||
private double outTime = 1;
|
||||
|
||||
|
||||
public LoopPlayer(DeferredAudio track, double pitch, double baseGain, Mutable<Double> gainMultiplier) {
|
||||
super(track, (float) pitch, (float) baseGain, gainMultiplier);
|
||||
|
||||
paused = true;
|
||||
}
|
||||
|
||||
|
||||
public void setFadeTimes(double in, double out)
|
||||
{
|
||||
inTime = in;
|
||||
outTime = out;
|
||||
}
|
||||
|
||||
|
||||
private void initLoop()
|
||||
{
|
||||
if (hasAudio() && sourceID == -1) {
|
||||
sourceID = getAudio().playAsEffect(getPitch(1), getGain(1), true);
|
||||
getAudio().pauseLoop();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void pause()
|
||||
{
|
||||
if (!hasAudio() || paused) return;
|
||||
|
||||
initLoop();
|
||||
|
||||
getAudio().pauseLoop();
|
||||
paused = true;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean isPaused()
|
||||
{
|
||||
return paused;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void resume()
|
||||
{
|
||||
if (!hasAudio() || !paused) return;
|
||||
|
||||
initLoop();
|
||||
|
||||
sourceID = getAudio().resumeLoop();
|
||||
paused = false;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void update(double delta)
|
||||
{
|
||||
if (!hasAudio() || paused) return;
|
||||
|
||||
initLoop();
|
||||
|
||||
fadeAnim.update(delta);
|
||||
|
||||
final double gain = getGain(fadeAnim.now());
|
||||
if (!paused && gain != lastUpdateGain) {
|
||||
AL10.alSourcef(sourceID, AL10.AL_GAIN, (float) gain);
|
||||
lastUpdateGain = gain;
|
||||
}
|
||||
|
||||
if (gain == 0 && !paused) pause(); // pause on zero volume
|
||||
}
|
||||
|
||||
|
||||
public void fadeIn(double secs)
|
||||
{
|
||||
if (!hasAudio()) return;
|
||||
|
||||
resume();
|
||||
fadeAnim.fadeIn(secs);
|
||||
}
|
||||
|
||||
|
||||
public void fadeOut(double secs)
|
||||
{
|
||||
if (!hasAudio()) return;
|
||||
|
||||
fadeAnim.fadeOut(secs);
|
||||
}
|
||||
|
||||
|
||||
public void fadeIn()
|
||||
{
|
||||
fadeIn(inTime);
|
||||
}
|
||||
|
||||
|
||||
public void fadeOut()
|
||||
{
|
||||
fadeOut(outTime);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,209 +0,0 @@
|
||||
package mightypork.rogue.textures;
|
||||
|
||||
|
||||
import mightypork.rogue.loading.BaseDeferredResource;
|
||||
import mightypork.rogue.loading.MustLoadInMainThread;
|
||||
import mightypork.rogue.render.Render;
|
||||
import mightypork.utils.logging.LoggedName;
|
||||
import mightypork.utils.math.coord.Rect;
|
||||
|
||||
import org.lwjgl.opengl.GL11;
|
||||
import org.newdawn.slick.opengl.Texture;
|
||||
|
||||
|
||||
/**
|
||||
* Deferred texture
|
||||
*
|
||||
* @author MightyPork
|
||||
*/
|
||||
@MustLoadInMainThread
|
||||
@LoggedName(name = "Texture")
|
||||
public class DeferredTexture extends BaseDeferredResource implements FilteredTexture {
|
||||
|
||||
private Texture backingTexture;
|
||||
private Filter filter_min = Filter.LINEAR;
|
||||
private Filter filter_mag = Filter.LINEAR;
|
||||
private Wrap wrap = Wrap.CLAMP;
|
||||
|
||||
|
||||
public DeferredTexture(String resourcePath) {
|
||||
super(resourcePath);
|
||||
}
|
||||
|
||||
|
||||
public TxQuad getQuad(Rect rect)
|
||||
{
|
||||
return new TxQuad(this, rect);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void loadResource(String path)
|
||||
{
|
||||
backingTexture = Render.loadTexture(path);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean hasAlpha()
|
||||
{
|
||||
if (!ensureLoaded()) return false;
|
||||
|
||||
return backingTexture.hasAlpha();
|
||||
}
|
||||
|
||||
|
||||
public void bindRaw()
|
||||
{
|
||||
if (!ensureLoaded()) return;
|
||||
|
||||
backingTexture.bind();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void bind()
|
||||
{
|
||||
if (!ensureLoaded()) return;
|
||||
|
||||
backingTexture.bind();
|
||||
|
||||
GL11.glTexEnvf(GL11.GL_TEXTURE_ENV, GL11.GL_TEXTURE_ENV_MODE, GL11.GL_MODULATE);
|
||||
|
||||
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, wrap.num);
|
||||
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, wrap.num);
|
||||
|
||||
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, filter_min.num);
|
||||
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, filter_mag.num);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int getImageHeight()
|
||||
{
|
||||
if (!ensureLoaded()) return 0;
|
||||
|
||||
return backingTexture.getImageHeight();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int getImageWidth()
|
||||
{
|
||||
if (!ensureLoaded()) return 0;
|
||||
|
||||
return backingTexture.getImageWidth();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getTextureRef()
|
||||
{
|
||||
if (!ensureLoaded()) return null;
|
||||
|
||||
return backingTexture.getTextureRef();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public float getHeight()
|
||||
{
|
||||
if (!ensureLoaded()) return 0;
|
||||
|
||||
return backingTexture.getHeight();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public float getWidth()
|
||||
{
|
||||
if (!ensureLoaded()) return 0;
|
||||
|
||||
return backingTexture.getWidth();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int getTextureHeight()
|
||||
{
|
||||
if (!ensureLoaded()) return 0;
|
||||
|
||||
return backingTexture.getTextureHeight();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int getTextureWidth()
|
||||
{
|
||||
if (!ensureLoaded()) return 0;
|
||||
|
||||
return backingTexture.getTextureWidth();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void release()
|
||||
{
|
||||
if (!isLoaded()) return;
|
||||
|
||||
backingTexture.release();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int getTextureID()
|
||||
{
|
||||
if (!ensureLoaded()) return -1;
|
||||
|
||||
return backingTexture.getTextureID();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public byte[] getTextureData()
|
||||
{
|
||||
if (!ensureLoaded()) return null;
|
||||
|
||||
return backingTexture.getTextureData();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void setTextureFilter(int textureFilter)
|
||||
{
|
||||
if (!ensureLoaded()) return;
|
||||
|
||||
backingTexture.setTextureFilter(textureFilter);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void destroy()
|
||||
{
|
||||
release();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void setFilter(Filter filterMin, Filter filterMag)
|
||||
{
|
||||
this.filter_min = filterMin;
|
||||
this.filter_mag = filterMag;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void setWrap(Wrap wrapping)
|
||||
{
|
||||
this.wrap = wrapping;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void setFilter(Filter filter)
|
||||
{
|
||||
setFilter(filter, filter);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
package mightypork.rogue.textures;
|
||||
|
||||
|
||||
import org.lwjgl.opengl.GL11;
|
||||
import org.newdawn.slick.opengl.Texture;
|
||||
|
||||
|
||||
public interface FilteredTexture extends Texture {
|
||||
|
||||
public static enum Filter
|
||||
{
|
||||
LINEAR(GL11.GL_LINEAR), NEAREST(GL11.GL_NEAREST);
|
||||
|
||||
public final int num;
|
||||
|
||||
|
||||
private Filter(int gl) {
|
||||
this.num = gl;
|
||||
}
|
||||
}
|
||||
|
||||
public static enum Wrap
|
||||
{
|
||||
CLAMP(GL11.GL_CLAMP), REPEAT(GL11.GL_REPEAT);
|
||||
|
||||
public final int num;
|
||||
|
||||
|
||||
private Wrap(int gl) {
|
||||
this.num = gl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set filter for scaling
|
||||
*
|
||||
* @param filterMin downscale filter
|
||||
* @param filterMag upscale filter
|
||||
*/
|
||||
void setFilter(Filter filterMin, Filter filterMag);
|
||||
|
||||
|
||||
/**
|
||||
* Set filter for scaling (both up and down)
|
||||
*
|
||||
* @param filter filter
|
||||
*/
|
||||
void setFilter(Filter filter);
|
||||
|
||||
|
||||
/**
|
||||
* @param wrapping wrap mode
|
||||
*/
|
||||
void setWrap(Wrap wrapping);
|
||||
}
|
||||
@@ -1,136 +0,0 @@
|
||||
package mightypork.rogue.textures;
|
||||
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
import mightypork.rogue.AppAccess;
|
||||
import mightypork.rogue.AppAdapter;
|
||||
import mightypork.rogue.bus.events.ResourceLoadRequest;
|
||||
import mightypork.rogue.textures.FilteredTexture.Filter;
|
||||
import mightypork.rogue.textures.FilteredTexture.Wrap;
|
||||
import mightypork.utils.math.coord.Rect;
|
||||
|
||||
import org.newdawn.slick.opengl.Texture;
|
||||
|
||||
|
||||
/**
|
||||
* Texture loader and quad registry
|
||||
*
|
||||
* @author MightyPork
|
||||
*/
|
||||
public class TextureBank extends AppAdapter {
|
||||
|
||||
public TextureBank(AppAccess app) {
|
||||
super(app);
|
||||
}
|
||||
|
||||
private final HashMap<String, DeferredTexture> textures = new HashMap<String, DeferredTexture>();
|
||||
|
||||
private final HashMap<String, TxQuad> quads = new HashMap<String, TxQuad>();
|
||||
|
||||
private DeferredTexture lastTx;
|
||||
|
||||
|
||||
/**
|
||||
* Load a {@link Texture} from resource, with filters LINEAR and wrap CLAMP
|
||||
*
|
||||
* @param key texture key
|
||||
* @param resourcePath texture resource path
|
||||
*/
|
||||
public void loadTexture(String key, String resourcePath)
|
||||
{
|
||||
loadTexture(key, resourcePath, Filter.LINEAR, Filter.NEAREST, Wrap.CLAMP);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Load a {@link Texture} from resource
|
||||
*
|
||||
* @param key texture key
|
||||
* @param resourcePath texture resource path
|
||||
* @param filter_min min filter (when rendered smaller)
|
||||
* @param filter_mag mag filter (when rendered larger)
|
||||
* @param wrap texture wrapping
|
||||
*/
|
||||
public void loadTexture(String key, String resourcePath, Filter filter_min, Filter filter_mag, Wrap wrap)
|
||||
{
|
||||
final DeferredTexture tx = new DeferredTexture(resourcePath);
|
||||
tx.setFilter(filter_min, filter_mag);
|
||||
tx.setWrap(wrap);
|
||||
|
||||
bus().send(new ResourceLoadRequest(tx));
|
||||
|
||||
textures.put(key, tx);
|
||||
lastTx = tx;
|
||||
|
||||
makeQuad(key, Rect.one());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create a {@link TxQuad} in a texture
|
||||
*
|
||||
* @param quadKey quad key
|
||||
* @param textureKey texture key
|
||||
* @param quad quad rectangle (absolute pixel coordinates) *
|
||||
*/
|
||||
public void makeQuad(String quadKey, String textureKey, Rect quad)
|
||||
{
|
||||
final DeferredTexture tx = textures.get(textureKey);
|
||||
if (tx == null) throw new RuntimeException("Texture with key " + textureKey + " not defined!");
|
||||
|
||||
final TxQuad txquad = tx.getQuad(quad);
|
||||
|
||||
quads.put(quadKey, txquad);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create a {@link TxQuad} in the last loaded texture
|
||||
*
|
||||
* @param quadKey quad key
|
||||
* @param quad quad rectangle (absolute pixel coordinates)
|
||||
*/
|
||||
public void makeQuad(String quadKey, Rect quad)
|
||||
{
|
||||
final DeferredTexture tx = lastTx;
|
||||
if (tx == null) throw new RuntimeException("There's no texture loaded yet, can't define quads!");
|
||||
|
||||
final TxQuad txquad = tx.getQuad(quad);
|
||||
|
||||
quads.put(quadKey, txquad);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get a {@link TxQuad} for key
|
||||
*
|
||||
* @param key quad key
|
||||
* @return the quad
|
||||
*/
|
||||
public TxQuad getTxQuad(String key)
|
||||
{
|
||||
final TxQuad q = quads.get(key);
|
||||
|
||||
if (q == null) throw new RuntimeException("There's no quad called " + key + "!");
|
||||
|
||||
return q;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get a loaded {@link Texture}
|
||||
*
|
||||
* @param key texture key
|
||||
* @return the texture
|
||||
*/
|
||||
public Texture getTexture(String key)
|
||||
{
|
||||
final Texture t = textures.get(key);
|
||||
|
||||
if (t == null) throw new RuntimeException("There's no texture called " + key + "!");
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,91 +0,0 @@
|
||||
package mightypork.rogue.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 final Texture tx;
|
||||
/** Coords in texture (0-1) */
|
||||
public final 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)
|
||||
{
|
||||
final double w = tx.getImageWidth();
|
||||
final 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 texture UVs (0-1)
|
||||
*/
|
||||
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,67 +0,0 @@
|
||||
package mightypork.rogue.util;
|
||||
|
||||
|
||||
import mightypork.utils.logging.LogInstance;
|
||||
|
||||
import org.newdawn.slick.util.LogSystem;
|
||||
|
||||
|
||||
public class SlickLogRedirector implements LogSystem {
|
||||
|
||||
LogInstance l;
|
||||
|
||||
|
||||
public SlickLogRedirector(LogInstance log) {
|
||||
this.l = log;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void error(String msg, Throwable e)
|
||||
{
|
||||
l.e(msg, e);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void error(Throwable e)
|
||||
{
|
||||
l.e(e);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void error(String msg)
|
||||
{
|
||||
l.e(msg);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void warn(String msg)
|
||||
{
|
||||
l.w(msg);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void warn(String msg, Throwable e)
|
||||
{
|
||||
l.e(msg, e);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void info(String msg)
|
||||
{
|
||||
l.i(msg);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void debug(String msg)
|
||||
{
|
||||
l.f3(msg);
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user