parent
6b8891666a
commit
1af5f01520
@ -1,200 +0,0 @@ |
|||||||
package mightypork.rogue; |
|
||||||
|
|
||||||
|
|
||||||
import static org.lwjgl.opengl.GL11.*; |
|
||||||
|
|
||||||
import java.util.Random; |
|
||||||
|
|
||||||
import mightypork.rogue.animations.GUIRenderer; |
|
||||||
import mightypork.rogue.input.InputHandler; |
|
||||||
import mightypork.rogue.input.Keys; |
|
||||||
import mightypork.utils.math.coord.Coord; |
|
||||||
import mightypork.utils.math.coord.Vec; |
|
||||||
|
|
||||||
import org.lwjgl.input.Keyboard; |
|
||||||
import org.lwjgl.input.Mouse; |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Screen class.<br> |
|
||||||
* Screen animates 3D world, while contained panels render 2D overlays, process |
|
||||||
* inputs and run the game logic. |
|
||||||
* |
|
||||||
* @author MightyPork |
|
||||||
*/ |
|
||||||
public abstract class Screen implements GUIRenderer, InputHandler { |
|
||||||
|
|
||||||
/** RNG */ |
|
||||||
protected static Random rand = new Random(); |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* handle fullscreen change |
|
||||||
*/ |
|
||||||
@Override |
|
||||||
public final void onFullscreenChange() |
|
||||||
{ |
|
||||||
onWindowResize(); |
|
||||||
onViewportChanged(); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
protected abstract void onViewportChanged(); |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* handle window resize. |
|
||||||
*/ |
|
||||||
public final void onWindowResize() |
|
||||||
{ |
|
||||||
glMatrixMode(GL_PROJECTION); |
|
||||||
glLoadIdentity(); |
|
||||||
|
|
||||||
Coord s = App.inst.getSize(); |
|
||||||
|
|
||||||
glViewport(0, 0, s.xi(), s.yi()); |
|
||||||
|
|
||||||
glOrtho(0, s.x, 0, s.y, -1000, 1000); |
|
||||||
|
|
||||||
glMatrixMode(GL_MODELVIEW); |
|
||||||
|
|
||||||
glLoadIdentity(); |
|
||||||
|
|
||||||
glEnable(GL_BLEND); |
|
||||||
//glDisable(GL_DEPTH_TEST);
|
|
||||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); |
|
||||||
glDisable(GL_TEXTURE_2D); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Initialize screen |
|
||||||
*/ |
|
||||||
public void init() |
|
||||||
{ |
|
||||||
onWindowResize(); |
|
||||||
|
|
||||||
initScreen(); |
|
||||||
|
|
||||||
// SETUP LIGHTS
|
|
||||||
glDisable(GL_LIGHTING); |
|
||||||
|
|
||||||
// OTHER SETTINGS
|
|
||||||
glMatrixMode(GL_MODELVIEW); |
|
||||||
glLoadIdentity(); |
|
||||||
|
|
||||||
glClearDepth(1f); |
|
||||||
glEnable(GL_DEPTH_TEST); |
|
||||||
glDepthFunc(GL_LEQUAL); |
|
||||||
|
|
||||||
glEnable(GL_NORMALIZE); |
|
||||||
|
|
||||||
glShadeModel(GL_SMOOTH); |
|
||||||
glDisable(GL_TEXTURE_2D); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Here you can initialize the screen. |
|
||||||
*/ |
|
||||||
public abstract void initScreen(); |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Update tick |
|
||||||
*/ |
|
||||||
@Override |
|
||||||
public final void updateGui() |
|
||||||
{ |
|
||||||
Mouse.poll(); |
|
||||||
Keyboard.poll(); |
|
||||||
checkInputEvents(); |
|
||||||
|
|
||||||
onGuiUpdate(); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
protected abstract void onGuiUpdate(); |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Render screen |
|
||||||
* |
|
||||||
* @param delta delta time (position between two update ticks, to allow |
|
||||||
* super-smooth animations) |
|
||||||
*/ |
|
||||||
@Override |
|
||||||
public final void render(double delta) |
|
||||||
{ |
|
||||||
glPushAttrib(GL_ENABLE_BIT); |
|
||||||
|
|
||||||
// draw the directly rendered 3D stuff
|
|
||||||
render3D(); |
|
||||||
|
|
||||||
glPopAttrib(); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
protected abstract void render3D(); |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Check input events and process them. |
|
||||||
*/ |
|
||||||
private final void checkInputEvents() |
|
||||||
{ |
|
||||||
while (Keyboard.next()) { |
|
||||||
int key = Keyboard.getEventKey(); |
|
||||||
boolean down = Keyboard.getEventKeyState(); |
|
||||||
char c = Keyboard.getEventCharacter(); |
|
||||||
Keys.onKey(key, down); |
|
||||||
onKey(key, c, down); |
|
||||||
} |
|
||||||
while (Mouse.next()) { |
|
||||||
int button = Mouse.getEventButton(); |
|
||||||
boolean down = Mouse.getEventButtonState(); |
|
||||||
Coord delta = new Coord(Mouse.getEventDX(), Mouse.getEventDY()); |
|
||||||
Coord pos = new Coord(Mouse.getEventX(), Mouse.getEventY()); |
|
||||||
int wheeld = Mouse.getEventDWheel(); |
|
||||||
|
|
||||||
onMouseButton(button, down, wheeld, pos, delta); |
|
||||||
} |
|
||||||
|
|
||||||
int xc = Mouse.getX(); |
|
||||||
int yc = Mouse.getY(); |
|
||||||
int xd = Mouse.getDX(); |
|
||||||
int yd = Mouse.getDY(); |
|
||||||
int wd = Mouse.getDWheel(); |
|
||||||
|
|
||||||
if (Math.abs(xd) > 0 || Math.abs(yd) > 0 || Math.abs(wd) > 0) { |
|
||||||
onMouseMove(new Coord(xc, yc), new Vec(xd, yd), wd); |
|
||||||
} |
|
||||||
|
|
||||||
handleKeyStates(); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
@Override |
|
||||||
public abstract void onKey(int key, char c, boolean down); |
|
||||||
|
|
||||||
|
|
||||||
@Override |
|
||||||
public abstract void onMouseButton(int button, boolean down, int wheeld, Coord pos, Coord delta); |
|
||||||
|
|
||||||
|
|
||||||
@Override |
|
||||||
public abstract void handleKeyStates(); |
|
||||||
|
|
||||||
|
|
||||||
@Override |
|
||||||
public abstract void onMouseMove(Coord coord, Vec vec, int wd); |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Render background 2D (all is ready for rendering) |
|
||||||
* |
|
||||||
* @param delta delta time |
|
||||||
*/ |
|
||||||
protected abstract void render2D(double delta); |
|
||||||
|
|
||||||
} |
|
@ -1,30 +0,0 @@ |
|||||||
package mightypork.rogue.animations; |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Empty animation (no effect) |
|
||||||
* |
|
||||||
* @author MightyPork |
|
||||||
*/ |
|
||||||
public class EmptyAnimator implements GUIRenderer { |
|
||||||
|
|
||||||
/** |
|
||||||
* New empty animation |
|
||||||
*/ |
|
||||||
public EmptyAnimator() {} |
|
||||||
|
|
||||||
|
|
||||||
@Override |
|
||||||
public void updateGui() |
|
||||||
{} |
|
||||||
|
|
||||||
|
|
||||||
@Override |
|
||||||
public void render(double delta) |
|
||||||
{} |
|
||||||
|
|
||||||
|
|
||||||
@Override |
|
||||||
public void onFullscreenChange() |
|
||||||
{} |
|
||||||
} |
|
@ -1,13 +0,0 @@ |
|||||||
package mightypork.rogue.animations; |
|
||||||
|
|
||||||
|
|
||||||
public interface GUIRenderer { |
|
||||||
|
|
||||||
public void updateGui(); |
|
||||||
|
|
||||||
|
|
||||||
public void render(double delta); |
|
||||||
|
|
||||||
|
|
||||||
public void onFullscreenChange(); |
|
||||||
} |
|
@ -0,0 +1,200 @@ |
|||||||
|
package mightypork.rogue.display; |
||||||
|
|
||||||
|
|
||||||
|
import static org.lwjgl.opengl.GL11.*; |
||||||
|
|
||||||
|
import java.awt.image.BufferedImage; |
||||||
|
import java.nio.ByteBuffer; |
||||||
|
|
||||||
|
import org.lwjgl.BufferUtils; |
||||||
|
import org.lwjgl.LWJGLException; |
||||||
|
import org.lwjgl.opengl.Display; |
||||||
|
import org.lwjgl.opengl.DisplayMode; |
||||||
|
|
||||||
|
import mightypork.rogue.App; |
||||||
|
import mightypork.rogue.Const; |
||||||
|
import mightypork.rogue.display.events.ScreenChangeEvent; |
||||||
|
import mightypork.utils.logging.Log; |
||||||
|
import mightypork.utils.math.coord.Coord; |
||||||
|
import mightypork.utils.patterns.Destroyable; |
||||||
|
import mightypork.utils.patterns.Initializable; |
||||||
|
import mightypork.utils.time.Updateable; |
||||||
|
|
||||||
|
|
||||||
|
public class DisplaySystem implements Initializable, Destroyable { |
||||||
|
|
||||||
|
private boolean initialized; |
||||||
|
|
||||||
|
private DisplayMode windowDisplayMode; |
||||||
|
private int targetFps; |
||||||
|
|
||||||
|
|
||||||
|
public DisplaySystem() { |
||||||
|
initialize(); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void initialize() |
||||||
|
{ |
||||||
|
if(initialized) return; |
||||||
|
|
||||||
|
initChannels(); |
||||||
|
|
||||||
|
initialized = true; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Initialize event channels |
||||||
|
*/ |
||||||
|
private void initChannels() |
||||||
|
{ |
||||||
|
App.msgbus().registerMessageType(ScreenChangeEvent.class, ScreenChangeEvent.Listener.class); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void destroy() |
||||||
|
{ |
||||||
|
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(); |
||||||
|
} |
||||||
|
} catch (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(); |
||||||
|
} |
||||||
|
|
||||||
|
App.broadcast(new ScreenChangeEvent(true, Display.isFullscreen(), getSize())); |
||||||
|
|
||||||
|
} catch (Throwable t) { |
||||||
|
Log.e("Failed to toggle fullscreen mode.", t); |
||||||
|
try { |
||||||
|
Display.setDisplayMode(windowDisplayMode); |
||||||
|
Display.update(); |
||||||
|
} catch (Throwable t1) { |
||||||
|
throw new RuntimeException("Failed to revert failed fullscreen toggle.", t1); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
public BufferedImage takeScreenshot() |
||||||
|
{ |
||||||
|
glReadBuffer(GL_FRONT); |
||||||
|
int width = Display.getDisplayMode().getWidth(); |
||||||
|
int height = Display.getDisplayMode().getHeight(); |
||||||
|
int bpp = 4; // Assuming a 32-bit display with a byte each for red, green, blue, and alpha.
|
||||||
|
ByteBuffer buffer = BufferUtils.createByteBuffer(width * height * bpp); |
||||||
|
glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, buffer); |
||||||
|
|
||||||
|
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); |
||||||
|
|
||||||
|
// convert to a buffered image
|
||||||
|
for (int x = 0; x < width; x++) { |
||||||
|
for (int y = 0; y < height; y++) { |
||||||
|
int i = (x + (width * y)) * bpp; |
||||||
|
int r = buffer.get(i) & 0xFF; |
||||||
|
int g = buffer.get(i + 1) & 0xFF; |
||||||
|
int b = buffer.get(i + 2) & 0xFF; |
||||||
|
image.setRGB(x, height - (y + 1), (0xFF << 24) | (r << 16) | (g << 8) | b); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return image; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* @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(Display.getWidth(), Display.getHeight()); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Start a OpenGL frame |
||||||
|
*/ |
||||||
|
public void beginFrame() |
||||||
|
{ |
||||||
|
if(Display.wasResized()) { |
||||||
|
App.broadcast(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); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,214 @@ |
|||||||
|
package mightypork.rogue.display; |
||||||
|
|
||||||
|
|
||||||
|
import static org.lwjgl.opengl.GL11.*; |
||||||
|
|
||||||
|
import java.util.Random; |
||||||
|
|
||||||
|
import mightypork.rogue.App; |
||||||
|
import mightypork.rogue.display.events.ScreenChangeEvent; |
||||||
|
import mightypork.rogue.input.KeyBinder; |
||||||
|
import mightypork.rogue.input.KeyBindingPool; |
||||||
|
import mightypork.rogue.input.KeyStroke; |
||||||
|
import mightypork.rogue.input.events.KeyboardEvent; |
||||||
|
import mightypork.rogue.input.events.MouseMotionEvent; |
||||||
|
import mightypork.rogue.input.events.MouseButtonEvent; |
||||||
|
import mightypork.utils.math.coord.Coord; |
||||||
|
import mightypork.utils.patterns.Destroyable; |
||||||
|
import mightypork.utils.patterns.Initializable; |
||||||
|
import mightypork.utils.time.Updateable; |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Screen class.<br> |
||||||
|
* Screen animates 3D world, while contained panels render 2D overlays, process |
||||||
|
* inputs and run the game logic. |
||||||
|
* |
||||||
|
* @author MightyPork |
||||||
|
*/ |
||||||
|
public abstract class Screen implements KeyBinder, Updateable, Initializable, KeyboardEvent.Listener, MouseMotionEvent.Listener, MouseButtonEvent.Listener, ScreenChangeEvent.Listener { |
||||||
|
|
||||||
|
private KeyBindingPool keybindings = new KeyBindingPool(); |
||||||
|
|
||||||
|
private boolean active; |
||||||
|
|
||||||
|
|
||||||
|
public Screen() { |
||||||
|
initialize(); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
@Override |
||||||
|
public void bindKeyStroke(KeyStroke stroke, Runnable task) |
||||||
|
{ |
||||||
|
keybindings.bindKeyStroke(stroke, task); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
@Override |
||||||
|
public void unbindKeyStroke(KeyStroke stroke) |
||||||
|
{ |
||||||
|
keybindings.unbindKeyStroke(stroke); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Prepare for being shown |
||||||
|
* @param shown true to show, false to hide |
||||||
|
*/ |
||||||
|
public final void setActive(boolean shown) |
||||||
|
{ |
||||||
|
if (shown) { |
||||||
|
active = true; |
||||||
|
setupGraphics(); |
||||||
|
setupViewport(); |
||||||
|
onSizeChanged(App.disp().getSize()); |
||||||
|
onEnter(); |
||||||
|
App.msgbus().addSubscriber(this); |
||||||
|
} else { |
||||||
|
active = false; |
||||||
|
onLeave(); |
||||||
|
App.msgbus().removeSubscriber(this); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
private void setupGraphics() |
||||||
|
{ |
||||||
|
glMatrixMode(GL_MODELVIEW); |
||||||
|
glLoadIdentity(); |
||||||
|
|
||||||
|
glDisable(GL_LIGHTING); |
||||||
|
|
||||||
|
glClearDepth(1f); |
||||||
|
glEnable(GL_DEPTH_TEST); |
||||||
|
glDepthFunc(GL_LEQUAL); |
||||||
|
|
||||||
|
glEnable(GL_NORMALIZE); |
||||||
|
|
||||||
|
glShadeModel(GL_SMOOTH); |
||||||
|
|
||||||
|
glEnable(GL_BLEND); |
||||||
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); |
||||||
|
|
||||||
|
glDisable(GL_TEXTURE_2D); |
||||||
|
|
||||||
|
setupViewport(); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
private void setupViewport() |
||||||
|
{ |
||||||
|
// fix projection for changed size
|
||||||
|
glMatrixMode(GL_PROJECTION); |
||||||
|
glLoadIdentity(); |
||||||
|
Coord s = App.disp().getSize(); |
||||||
|
glViewport(0, 0, s.xi(), s.yi()); |
||||||
|
glOrtho(0, s.x, 0, s.y, -1000, 1000); |
||||||
|
|
||||||
|
// back to modelview
|
||||||
|
glMatrixMode(GL_MODELVIEW); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Initialize screen layout and key bindings.<br> |
||||||
|
* Called when the screen is created, not when it comes to front. For that, use onEnter(). |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public abstract void initialize(); |
||||||
|
|
||||||
|
/** |
||||||
|
* Called when the screen becomes active |
||||||
|
*/ |
||||||
|
protected abstract void onEnter(); |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Called when the screen is no longer active |
||||||
|
*/ |
||||||
|
protected abstract void onLeave(); |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Update GUI for new screen size |
||||||
|
* |
||||||
|
* @param size screen size |
||||||
|
*/ |
||||||
|
protected abstract void onSizeChanged(Coord size); |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Render screen contents (context is ready for 2D rendering) |
||||||
|
*/ |
||||||
|
protected abstract void renderScreen(); |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Update animations and timing |
||||||
|
* |
||||||
|
* @param delta time elapsed |
||||||
|
*/ |
||||||
|
protected abstract void updateScreen(double delta); |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Render screen |
||||||
|
*/ |
||||||
|
private final void renderBegin() |
||||||
|
{ |
||||||
|
glPushAttrib(GL_ENABLE_BIT); |
||||||
|
glPushMatrix(); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Render screen |
||||||
|
*/ |
||||||
|
private final void renderEnd() |
||||||
|
{ |
||||||
|
glPopAttrib(); |
||||||
|
glPopMatrix(); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
@Override |
||||||
|
public final void update(double delta) |
||||||
|
{ |
||||||
|
if (!isActive()) return; |
||||||
|
|
||||||
|
updateScreen(delta); |
||||||
|
renderBegin(); |
||||||
|
renderScreen(); |
||||||
|
renderEnd(); |
||||||
|
}; |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* @return true if screen is the curretn screen |
||||||
|
*/ |
||||||
|
protected final boolean isActive() |
||||||
|
{ |
||||||
|
return active; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
@Override |
||||||
|
public final void receive(ScreenChangeEvent event) |
||||||
|
{ |
||||||
|
if (!isActive()) return; |
||||||
|
|
||||||
|
setupViewport(); |
||||||
|
|
||||||
|
onSizeChanged(event.getScreenSize()); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
@Override |
||||||
|
public final void receive(KeyboardEvent event) |
||||||
|
{ |
||||||
|
if (!isActive()) return; |
||||||
|
keybindings.receive(event); |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,168 @@ |
|||||||
|
package mightypork.rogue.display; |
||||||
|
|
||||||
|
|
||||||
|
import org.lwjgl.input.Keyboard; |
||||||
|
import org.lwjgl.input.Mouse; |
||||||
|
import org.lwjgl.opengl.Display; |
||||||
|
|
||||||
|
import mightypork.rogue.App; |
||||||
|
import mightypork.rogue.input.KeyStroke; |
||||||
|
import mightypork.rogue.input.events.MouseButtonEvent; |
||||||
|
import mightypork.rogue.input.events.MouseMotionEvent; |
||||||
|
import mightypork.rogue.util.RenderUtils; |
||||||
|
import mightypork.utils.math.Polar; |
||||||
|
import mightypork.utils.math.color.RGB; |
||||||
|
import mightypork.utils.math.coord.Coord; |
||||||
|
import mightypork.utils.math.easing.Easing; |
||||||
|
import mightypork.utils.time.AnimDouble; |
||||||
|
import mightypork.utils.time.AnimDoubleDeg; |
||||||
|
|
||||||
|
|
||||||
|
public class ScreenSplash extends Screen { |
||||||
|
|
||||||
|
private AnimDoubleDeg degAnim = new AnimDoubleDeg(0, Easing.SINE); |
||||||
|
|
||||||
|
//@formatter:off
|
||||||
|
private AnimDouble[] anims = new AnimDouble[] { |
||||||
|
new AnimDouble(0, Easing.NONE), |
||||||
|
new AnimDouble(0, Easing.LINEAR), |
||||||
|
|
||||||
|
new AnimDouble(0, Easing.QUADRATIC_IN), |
||||||
|
new AnimDouble(0, Easing.QUADRATIC_OUT), |
||||||
|
new AnimDouble(0, Easing.QUADRATIC), |
||||||
|
|
||||||
|
new AnimDouble(0, Easing.CUBIC_IN), |
||||||
|
new AnimDouble(0, Easing.CUBIC_OUT), |
||||||
|
new AnimDouble(0, Easing.CUBIC), |
||||||
|
|
||||||
|
new AnimDouble(0, Easing.QUADRATIC_IN), |
||||||
|
new AnimDouble(0, Easing.QUADRATIC_OUT), |
||||||
|
new AnimDouble(0, Easing.QUADRATIC), |
||||||
|
|
||||||
|
new AnimDouble(0, Easing.QUINTIC_IN), |
||||||
|
new AnimDouble(0, Easing.QUINTIC_OUT), |
||||||
|
new AnimDouble(0, Easing.QUINTIC_IN_OUT), |
||||||
|
|
||||||
|
new AnimDouble(0, Easing.EXPO_IN), |
||||||
|
new AnimDouble(0, Easing.EXPO_OUT), |
||||||
|
new AnimDouble(0, Easing.EXPO), |
||||||
|
|
||||||
|
new AnimDouble(0, Easing.SINE_IN), |
||||||
|
new AnimDouble(0, Easing.SINE_OUT), |
||||||
|
new AnimDouble(0, Easing.SINE), |
||||||
|
|
||||||
|
new AnimDouble(0, Easing.CIRC_IN), |
||||||
|
new AnimDouble(0, Easing.CIRC_OUT), |
||||||
|
new AnimDouble(0, Easing.CIRC), |
||||||
|
}; |
||||||
|
//@formatter:on
|
||||||
|
|
||||||
|
@Override |
||||||
|
public void initialize() |
||||||
|
{ |
||||||
|
bindKeyStroke(new KeyStroke(Keyboard.KEY_RIGHT), new Runnable() { |
||||||
|
|
||||||
|
@Override |
||||||
|
public void run() |
||||||
|
{ |
||||||
|
for (AnimDouble a : anims) { |
||||||
|
a.animate(0, 1, 3); |
||||||
|
} |
||||||
|
} |
||||||
|
}); |
||||||
|
|
||||||
|
bindKeyStroke(new KeyStroke(Keyboard.KEY_LEFT), new Runnable() { |
||||||
|
|
||||||
|
@Override |
||||||
|
public void run() |
||||||
|
{ |
||||||
|
for (AnimDouble a : anims) { |
||||||
|
a.animate(1, 0, 3); |
||||||
|
} |
||||||
|
} |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
@Override |
||||||
|
protected void renderScreen() |
||||||
|
{ |
||||||
|
double screenH = Display.getHeight(); |
||||||
|
double screenW = Display.getWidth(); |
||||||
|
double perBoxH = screenH / anims.length; |
||||||
|
double padding = perBoxH*0.1; |
||||||
|
double boxSide = perBoxH-padding*2; |
||||||
|
|
||||||
|
for (int i = 0; i < anims.length; i++) { |
||||||
|
AnimDouble a = anims[i]; |
||||||
|
|
||||||
|
RenderUtils.setColor(i%3==0?RGB.GREEN:RGB.BLUE); |
||||||
|
RenderUtils.quadSize( |
||||||
|
padding + a.getCurrentValue() * (screenW - perBoxH - padding*2), |
||||||
|
screenH - perBoxH * i - perBoxH + padding, |
||||||
|
boxSide, |
||||||
|
boxSide |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
RenderUtils.setColor(RGB.YELLOW); |
||||||
|
RenderUtils.translate(new Coord(Display.getWidth() / 2, Display.getHeight() / 2)); |
||||||
|
RenderUtils.rotateZ(degAnim.getCurrentValue()); |
||||||
|
RenderUtils.quadSize(-10, -10, 20, 200); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
@Override |
||||||
|
public void receive(MouseMotionEvent event) |
||||||
|
{ |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
@Override |
||||||
|
public void receive(MouseButtonEvent event) |
||||||
|
{ |
||||||
|
if(event.isDown()) { |
||||||
|
Coord vec = App.disp().getSize().half().vecTo(event.getPos()); |
||||||
|
|
||||||
|
Polar p = Polar.fromCoord(vec); |
||||||
|
|
||||||
|
degAnim.fadeTo(p.getAngleDeg() - 90, 0.2); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
@Override |
||||||
|
protected void onEnter() |
||||||
|
{ |
||||||
|
// TODO Auto-generated method stub
|
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
@Override |
||||||
|
protected void onLeave() |
||||||
|
{ |
||||||
|
// TODO Auto-generated method stub
|
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
@Override |
||||||
|
protected void onSizeChanged(Coord size) |
||||||
|
{ |
||||||
|
// TODO Auto-generated method stub
|
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
@Override |
||||||
|
protected void updateScreen(double delta) |
||||||
|
{ |
||||||
|
degAnim.update(delta); |
||||||
|
|
||||||
|
for (AnimDouble a : anims) { |
||||||
|
a.update(delta); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,50 @@ |
|||||||
|
package mightypork.rogue.display.events; |
||||||
|
|
||||||
|
|
||||||
|
import mightypork.utils.math.coord.Coord; |
||||||
|
import mightypork.utils.patterns.subscription.Handleable; |
||||||
|
|
||||||
|
|
||||||
|
public class ScreenChangeEvent implements Handleable<ScreenChangeEvent.Listener> { |
||||||
|
|
||||||
|
private boolean fullscreen; |
||||||
|
private Coord screenSize; |
||||||
|
private 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 { |
||||||
|
|
||||||
|
public void receive(ScreenChangeEvent event); |
||||||
|
} |
||||||
|
} |
@ -1,52 +0,0 @@ |
|||||||
package mightypork.rogue.input; |
|
||||||
|
|
||||||
|
|
||||||
import mightypork.utils.math.coord.Coord; |
|
||||||
import mightypork.utils.math.coord.Vec; |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Input event handler |
|
||||||
* |
|
||||||
* @author MightyPork |
|
||||||
*/ |
|
||||||
public interface InputHandler { |
|
||||||
|
|
||||||
/** |
|
||||||
* Called each update tick, if the mouse position was changed. |
|
||||||
* |
|
||||||
* @param pos mouse position |
|
||||||
* @param move mouse motion |
|
||||||
* @param wheelDelta mouse wheel delta |
|
||||||
*/ |
|
||||||
public void onMouseMove(Coord pos, Vec move, int wheelDelta); |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Mouse event handler. |
|
||||||
* |
|
||||||
* @param button button which caused this event |
|
||||||
* @param down true = down, false = up |
|
||||||
* @param wheelDelta number of steps the wheel turned since last event |
|
||||||
* @param pos mouse position |
|
||||||
* @param deltaPos delta mouse position |
|
||||||
*/ |
|
||||||
public void onMouseButton(int button, boolean down, int wheelDelta, Coord pos, Coord deltaPos); |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Key event handler. |
|
||||||
* |
|
||||||
* @param key key index, constant Keyboard.KEY_??? |
|
||||||
* @param c character typed, if any |
|
||||||
* @param down true = down, false = up |
|
||||||
*/ |
|
||||||
public void onKey(int key, char c, boolean down); |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* In this method screen can handle static inputs, that is: |
|
||||||
* Keyboard.isKeyDown, Mouse.isButtonDown etc. |
|
||||||
*/ |
|
||||||
public void handleKeyStates(); |
|
||||||
} |
|
@ -0,0 +1,126 @@ |
|||||||
|
package mightypork.rogue.input; |
||||||
|
|
||||||
|
|
||||||
|
import mightypork.rogue.App; |
||||||
|
import mightypork.rogue.input.events.KeyboardEvent; |
||||||
|
import mightypork.rogue.input.events.MouseButtonEvent; |
||||||
|
import mightypork.rogue.input.events.MouseMotionEvent; |
||||||
|
import mightypork.utils.math.coord.Coord; |
||||||
|
import mightypork.utils.patterns.Destroyable; |
||||||
|
import mightypork.utils.patterns.Initializable; |
||||||
|
import org.lwjgl.LWJGLException; |
||||||
|
import org.lwjgl.input.Keyboard; |
||||||
|
import org.lwjgl.input.Mouse; |
||||||
|
import org.lwjgl.opengl.Display; |
||||||
|
|
||||||
|
|
||||||
|
public class InputSystem implements KeyBinder, Destroyable, Initializable { |
||||||
|
|
||||||
|
private boolean initialized; |
||||||
|
|
||||||
|
// listeners
|
||||||
|
private KeyBindingPool keybindings; |
||||||
|
|
||||||
|
|
||||||
|
public InputSystem() { |
||||||
|
initialize(); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
@Override |
||||||
|
public void initialize() |
||||||
|
{ |
||||||
|
if (initialized) return; |
||||||
|
|
||||||
|
initDevices(); |
||||||
|
|
||||||
|
initChannels(); |
||||||
|
|
||||||
|
keybindings = new KeyBindingPool(); |
||||||
|
|
||||||
|
App.msgbus().addSubscriber(keybindings); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
private void initDevices() |
||||||
|
{ |
||||||
|
try { |
||||||
|
Mouse.create(); |
||||||
|
Keyboard.create(); |
||||||
|
Keyboard.enableRepeatEvents(false); |
||||||
|
} catch (LWJGLException e) { |
||||||
|
throw new RuntimeException("Failed to initialize input devices.", e); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
private void initChannels() |
||||||
|
{ |
||||||
|
App.msgbus().registerMessageType(KeyboardEvent.class, KeyboardEvent.Listener.class); |
||||||
|
App.msgbus().registerMessageType(MouseMotionEvent.class, MouseMotionEvent.Listener.class); |
||||||
|
App.msgbus().registerMessageType(MouseButtonEvent.class, MouseButtonEvent.Listener.class); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
@Override |
||||||
|
public void destroy() |
||||||
|
{ |
||||||
|
Mouse.destroy(); |
||||||
|
Keyboard.destroy(); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
@Override |
||||||
|
public void bindKeyStroke(KeyStroke stroke, Runnable task) |
||||||
|
{ |
||||||
|
keybindings.bindKeyStroke(stroke, task); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
@Override |
||||||
|
public void unbindKeyStroke(KeyStroke stroke) |
||||||
|
{ |
||||||
|
keybindings.unbindKeyStroke(stroke); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Update inputs |
||||||
|
*/ |
||||||
|
public final void poll() |
||||||
|
{ |
||||||
|
Display.processMessages(); // redundant if Display.update() is called in main loop
|
||||||
|
Mouse.poll(); |
||||||
|
Keyboard.poll(); |
||||||
|
|
||||||
|
while (Mouse.next()) { |
||||||
|
onMouseEvent(); |
||||||
|
} |
||||||
|
|
||||||
|
while (Keyboard.next()) { |
||||||
|
onKeyEvent(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
private void onMouseEvent() |
||||||
|
{ |
||||||
|
int button = Mouse.getEventButton(); |
||||||
|
boolean down = Mouse.getEventButtonState(); |
||||||
|
Coord pos = new Coord(Mouse.getEventX(), Mouse.getEventY()); |
||||||
|
Coord move = new Coord(Mouse.getEventDX(), Mouse.getEventDY()); |
||||||
|
int wheeld = Mouse.getEventDWheel(); |
||||||
|
|
||||||
|
if (button != -1 || wheeld != 0) App.broadcast(new MouseButtonEvent(pos, button, down, wheeld)); |
||||||
|
if(!move.isZero()) App.broadcast(new MouseMotionEvent(pos, move)); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
private void onKeyEvent() |
||||||
|
{ |
||||||
|
int key = Keyboard.getEventKey(); |
||||||
|
boolean down = Keyboard.getEventKeyState(); |
||||||
|
char c = Keyboard.getEventCharacter(); |
||||||
|
App.broadcast(new KeyboardEvent(key, c, down)); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,21 @@ |
|||||||
|
package mightypork.rogue.input; |
||||||
|
|
||||||
|
|
||||||
|
public interface KeyBinder { |
||||||
|
|
||||||
|
/** |
||||||
|
* Bind handler to a keystroke, replace current handler if any |
||||||
|
* |
||||||
|
* @param stroke trigger keystroke |
||||||
|
* @param task handler |
||||||
|
*/ |
||||||
|
abstract void bindKeyStroke(KeyStroke stroke, Runnable task); |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Remove handler from a keystroke (id any) |
||||||
|
* @param stroke stroke |
||||||
|
*/ |
||||||
|
abstract void unbindKeyStroke(KeyStroke stroke); |
||||||
|
|
||||||
|
} |
@ -0,0 +1,48 @@ |
|||||||
|
package mightypork.rogue.input; |
||||||
|
|
||||||
|
|
||||||
|
import mightypork.rogue.input.events.KeyboardEvent; |
||||||
|
|
||||||
|
|
||||||
|
public class KeyBinding implements KeyboardEvent.Listener { |
||||||
|
|
||||||
|
private KeyStroke keystroke; |
||||||
|
private Runnable handler; |
||||||
|
private boolean wasActive = false; |
||||||
|
|
||||||
|
|
||||||
|
public KeyBinding(KeyStroke stroke, Runnable handler) { |
||||||
|
this.keystroke = stroke; |
||||||
|
this.handler = handler; |
||||||
|
|
||||||
|
wasActive = keystroke.isActive(); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
public boolean matches(KeyStroke stroke) |
||||||
|
{ |
||||||
|
return this.keystroke.equals(stroke); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
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(); |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,68 @@ |
|||||||
|
package mightypork.rogue.input; |
||||||
|
|
||||||
|
|
||||||
|
import java.util.HashSet; |
||||||
|
import java.util.Iterator; |
||||||
|
import java.util.Set; |
||||||
|
|
||||||
|
import mightypork.rogue.input.events.KeyboardEvent; |
||||||
|
import mightypork.utils.logging.Log; |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Key binding pool |
||||||
|
* |
||||||
|
* @author MightyPork |
||||||
|
*/ |
||||||
|
public class KeyBindingPool implements KeyBinder, KeyboardEvent.Listener { |
||||||
|
|
||||||
|
private 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 (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) |
||||||
|
{ |
||||||
|
Iterator<KeyBinding> iter = bindings.iterator(); |
||||||
|
|
||||||
|
while (iter.hasNext()) { |
||||||
|
KeyBinding kb = iter.next(); |
||||||
|
if (kb.matches(stroke)) { |
||||||
|
iter.remove(); |
||||||
|
return; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void receive(KeyboardEvent event) |
||||||
|
{ |
||||||
|
for(KeyBinding kb: bindings) { |
||||||
|
kb.receive(event); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,114 @@ |
|||||||
|
package mightypork.rogue.input; |
||||||
|
|
||||||
|
|
||||||
|
import java.util.Iterator; |
||||||
|
import java.util.LinkedHashSet; |
||||||
|
import java.util.Set; |
||||||
|
|
||||||
|
import org.lwjgl.input.Keyboard; |
||||||
|
|
||||||
|
|
||||||
|
public class KeyStroke { |
||||||
|
|
||||||
|
private Set<Integer> keys = new LinkedHashSet<Integer>(); |
||||||
|
private boolean down = true; |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* KeyStroke |
||||||
|
* |
||||||
|
* @param down true for falling edge, up for rising edge |
||||||
|
* @param keys keys that must be pressed |
||||||
|
*/ |
||||||
|
public KeyStroke(boolean down, int... keys) { |
||||||
|
this.down = down; |
||||||
|
for (int k : keys) { |
||||||
|
this.keys.add(k); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Falling edge keystroke |
||||||
|
* |
||||||
|
* @param keys |
||||||
|
*/ |
||||||
|
public KeyStroke(int... keys) { |
||||||
|
for (int k : keys) { |
||||||
|
this.keys.add(k); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
public boolean isActive() |
||||||
|
{ |
||||||
|
boolean st = true; |
||||||
|
for (int k : keys) { |
||||||
|
st &= Keyboard.isKeyDown(k); |
||||||
|
} |
||||||
|
|
||||||
|
return down ? st : !st; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
public void setKeys(Set<Integer> keys) |
||||||
|
{ |
||||||
|
this.keys = keys; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
@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; |
||||||
|
KeyStroke other = (KeyStroke) obj; |
||||||
|
|
||||||
|
if (keys == null) { |
||||||
|
if (other.keys != null) return false; |
||||||
|
} else if (!keys.equals(other.keys)) { |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
if (down != other.down) return false; |
||||||
|
|
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
@Override |
||||||
|
public String toString() |
||||||
|
{ |
||||||
|
String s = "("; |
||||||
|
|
||||||
|
int cnt = 0; |
||||||
|
Iterator<Integer> i = keys.iterator(); |
||||||
|
for (; i.hasNext(); cnt++) { |
||||||
|
if (cnt > 0) s += "+"; |
||||||
|
s += Keyboard.getKeyName(i.next()); |
||||||
|
} |
||||||
|
|
||||||
|
s += down ? ",DOWN" : "UP"; |
||||||
|
|
||||||
|
s += ")"; |
||||||
|
|
||||||
|
return s; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
public Set<Integer> getKeys() |
||||||
|
{ |
||||||
|
return keys; |
||||||
|
} |
||||||
|
} |
@ -1,122 +0,0 @@ |
|||||||
package mightypork.rogue.input; |
|
||||||
|
|
||||||
|
|
||||||
import org.lwjgl.input.Keyboard; |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Key state handler |
|
||||||
*/ |
|
||||||
public class Keys { |
|
||||||
|
|
||||||
private static boolean[] prevKeys; |
|
||||||
private static boolean[] keys; |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* initialize key state handler |
|
||||||
*/ |
|
||||||
private static void init() |
|
||||||
{ |
|
||||||
|
|
||||||
if (keys == null) { |
|
||||||
keys = new boolean[Keyboard.KEYBOARD_SIZE]; |
|
||||||
} |
|
||||||
|
|
||||||
if (prevKeys == null) { |
|
||||||
prevKeys = new boolean[Keyboard.KEYBOARD_SIZE]; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* method called when key event was detected in Screen class. |
|
||||||
* |
|
||||||
* @param key |
|
||||||
* @param down |
|
||||||
*/ |
|
||||||
public static void onKey(int key, boolean down) |
|
||||||
{ |
|
||||||
|
|
||||||
init(); |
|
||||||
|
|
||||||
prevKeys[key] = keys[key]; |
|
||||||
keys[key] = down; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Check if key is down |
|
||||||
* |
|
||||||
* @param key key index |
|
||||||
* @return is down |
|
||||||
*/ |
|
||||||
public static boolean isDown(int key) |
|
||||||
{ |
|
||||||
|
|
||||||
init(); |
|
||||||
|
|
||||||
return keys[key]; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Check if key is up |
|
||||||
* |
|
||||||
* @param key key index |
|
||||||
* @return is up |
|
||||||
*/ |
|
||||||
public static boolean isUp(int key) |
|
||||||
{ |
|
||||||
|
|
||||||
init(); |
|
||||||
|
|
||||||
return !keys[key]; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Check if key was just pressed (changed state since last event on this |
|
||||||
* key) |
|
||||||
* |
|
||||||
* @param key key index |
|
||||||
* @return true if changed state to DOWN |
|
||||||
*/ |
|
||||||
public static boolean justPressed(int key) |
|
||||||
{ |
|
||||||
|
|
||||||
init(); |
|
||||||
|
|
||||||
return !prevKeys[key] && keys[key]; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Check if key was just released (changed state since last event on this |
|
||||||
* key) |
|
||||||
* |
|
||||||
* @param key key index |
|
||||||
* @return true if changed state to UP |
|
||||||
*/ |
|
||||||
public static boolean justReleased(int key) |
|
||||||
{ |
|
||||||
|
|
||||||
init(); |
|
||||||
|
|
||||||
return prevKeys[key] && !keys[key]; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Destroy "just" flag for a key. |
|
||||||
* |
|
||||||
* @param key key index |
|
||||||
*/ |
|
||||||
public static void destroyChangeState(int key) |
|
||||||
{ |
|
||||||
|
|
||||||
init(); |
|
||||||
|
|
||||||
prevKeys[key] = keys[key]; |
|
||||||
} |
|
||||||
} |
|
@ -0,0 +1,85 @@ |
|||||||
|
package mightypork.rogue.input.events; |
||||||
|
|
||||||
|
|
||||||
|
import org.lwjgl.input.Keyboard; |
||||||
|
|
||||||
|
import mightypork.utils.patterns.subscription.Handleable; |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* A keyboard event |
||||||
|
* |
||||||
|
* @author MightyPork |
||||||
|
*/ |
||||||
|
public class KeyboardEvent implements Handleable<KeyboardEvent.Listener> { |
||||||
|
|
||||||
|
private int key; |
||||||
|
private boolean down; |
||||||
|
private 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 |
||||||
|
*/ |
||||||
|
public void receive(KeyboardEvent event); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public String toString() |
||||||
|
{ |
||||||
|
return Keyboard.getKeyName(key)+":"+(down?"DOWN":"UP"); |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,119 @@ |
|||||||
|
package mightypork.rogue.input.events; |
||||||
|
|
||||||
|
|
||||||
|
import mightypork.utils.math.coord.Coord; |
||||||
|
import mightypork.utils.patterns.subscription.Handleable; |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Mouse button / wheel event |
||||||
|
* |
||||||
|
* @author MightyPork |
||||||
|
*/ |
||||||
|
public class MouseButtonEvent implements Handleable<MouseButtonEvent.Listener> { |
||||||
|
|
||||||
|
public static final int BUTTON_LEFT = 0; |
||||||
|
public static final int BUTTON_MIDDLE = 1; |
||||||
|
public static final int BUTTON_RIGHT = 2; |
||||||
|
|
||||||
|
private int button; |
||||||
|
private int wheeld; |
||||||
|
private Coord pos; |
||||||
|
private 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 |
||||||
|
*/ |
||||||
|
public void receive(MouseButtonEvent event); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,54 @@ |
|||||||
|
package mightypork.rogue.input.events; |
||||||
|
|
||||||
|
|
||||||
|
import mightypork.utils.math.coord.Coord; |
||||||
|
import mightypork.utils.patterns.subscription.Handleable; |
||||||
|
|
||||||
|
|
||||||
|
public class MouseMotionEvent implements Handleable<MouseMotionEvent.Listener> { |
||||||
|
|
||||||
|
private Coord move; |
||||||
|
private Coord pos; |
||||||
|
|
||||||
|
|
||||||
|
public MouseMotionEvent(Coord pos, Coord move) { |
||||||
|
this.move = move; |
||||||
|
this.pos = pos; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* @return movement since last {@link MouseMotionEvent} |
||||||
|
*/ |
||||||
|
public Coord getPosDelta() |
||||||
|
{ |
||||||
|
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 |
||||||
|
*/ |
||||||
|
public void receive(MouseMotionEvent event); |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -1,82 +0,0 @@ |
|||||||
package mightypork.rogue.screens; |
|
||||||
|
|
||||||
|
|
||||||
import mightypork.rogue.Screen; |
|
||||||
import mightypork.utils.math.coord.Coord; |
|
||||||
import mightypork.utils.math.coord.Vec; |
|
||||||
|
|
||||||
|
|
||||||
public class ScreenSplash extends Screen { |
|
||||||
|
|
||||||
@Override |
|
||||||
protected void onViewportChanged() |
|
||||||
{ |
|
||||||
// TODO Auto-generated method stub
|
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
@Override |
|
||||||
public void initScreen() |
|
||||||
{ |
|
||||||
// TODO Auto-generated method stub
|
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
@Override |
|
||||||
protected void onGuiUpdate() |
|
||||||
{ |
|
||||||
// TODO Auto-generated method stub
|
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
@Override |
|
||||||
protected void render3D() |
|
||||||
{ |
|
||||||
// TODO Auto-generated method stub
|
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
@Override |
|
||||||
public void onKey(int key, char c, boolean down) |
|
||||||
{ |
|
||||||
// TODO Auto-generated method stub
|
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
@Override |
|
||||||
public void onMouseButton(int button, boolean down, int wheeld, Coord pos, Coord delta) |
|
||||||
{ |
|
||||||
// TODO Auto-generated method stub
|
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
@Override |
|
||||||
public void handleKeyStates() |
|
||||||
{ |
|
||||||
// TODO Auto-generated method stub
|
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
@Override |
|
||||||
public void onMouseMove(Coord coord, Vec vec, int wd) |
|
||||||
{ |
|
||||||
// TODO Auto-generated method stub
|
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
@Override |
|
||||||
protected void render2D(double delta) |
|
||||||
{ |
|
||||||
// TODO Auto-generated method stub
|
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
} |
|
@ -1,77 +0,0 @@ |
|||||||
package mightypork.rogue.sounds; |
|
||||||
|
|
||||||
|
|
||||||
import mightypork.utils.objects.Mutable; |
|
||||||
|
|
||||||
|
|
||||||
public abstract class AudioPlayer { |
|
||||||
|
|
||||||
/** base gain for sfx */ |
|
||||||
private double baseGain = 1; |
|
||||||
|
|
||||||
/** the track */ |
|
||||||
private AudioX track; |
|
||||||
|
|
||||||
/** base pitch for sfx */ |
|
||||||
private double basePitch = 1; |
|
||||||
|
|
||||||
/** dedicated volume control */ |
|
||||||
private Mutable<Float> gainMultiplier = null; |
|
||||||
|
|
||||||
|
|
||||||
public AudioPlayer(AudioX track, double baseGain, Mutable<Float> gainMultiplier) { |
|
||||||
this(track, 1, baseGain, gainMultiplier); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
public AudioPlayer(AudioX track, double basePitch, double baseGain, Mutable<Float> gainMultiplier) { |
|
||||||
this.track = track; |
|
||||||
|
|
||||||
this.baseGain = baseGain; |
|
||||||
this.basePitch = basePitch; |
|
||||||
|
|
||||||
this.gainMultiplier = gainMultiplier; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
public void destroy() |
|
||||||
{ |
|
||||||
track.release(); |
|
||||||
track = null; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
protected AudioX getAudio() |
|
||||||
{ |
|
||||||
return track; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
protected float getGain(double multiplier) |
|
||||||
{ |
|
||||||
return (float) (baseGain * gainMultiplier.get() * multiplier); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
protected float getPitch(double multiplier) |
|
||||||
{ |
|
||||||
return (float) (basePitch * multiplier); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Get if audio is valid |
|
||||||
* |
|
||||||
* @return is valid |
|
||||||
*/ |
|
||||||
protected boolean canPlay() |
|
||||||
{ |
|
||||||
return (track != null); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
public void load() |
|
||||||
{ |
|
||||||
if (canPlay()) track.load(); |
|
||||||
} |
|
||||||
} |
|
@ -0,0 +1,77 @@ |
|||||||
|
package mightypork.rogue.sounds; |
||||||
|
|
||||||
|
|
||||||
|
import mightypork.utils.objects.Mutable; |
||||||
|
|
||||||
|
|
||||||
|
public abstract class BaseAudioPlayer { |
||||||
|
|
||||||
|
/** the track */ |
||||||
|
private AudioX audio; |
||||||
|
|
||||||
|
/** base gain for sfx */ |
||||||
|
private double baseGain = 1; |
||||||
|
|
||||||
|
/** base pitch for sfx */ |
||||||
|
private double basePitch = 1; |
||||||
|
|
||||||
|
/** dedicated volume control */ |
||||||
|
private Mutable<Double> gainMultiplier = null; |
||||||
|
|
||||||
|
|
||||||
|
public BaseAudioPlayer(AudioX track, double baseGain, Mutable<Double> gainMultiplier) { |
||||||
|
this(track, 1, baseGain, gainMultiplier); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
public BaseAudioPlayer(AudioX track, double basePitch, double baseGain, Mutable<Double> gainMultiplier) { |
||||||
|
this.audio = track; |
||||||
|
|
||||||
|
this.baseGain = baseGain; |
||||||
|
this.basePitch = basePitch; |
||||||
|
|
||||||
|
this.gainMultiplier = gainMultiplier; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
public void destroy() |
||||||
|
{ |
||||||
|
audio.destroy(); |
||||||
|
audio = null; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
protected AudioX 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 canPlay() |
||||||
|
{ |
||||||
|
return (audio != null); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
public void load() |
||||||
|
{ |
||||||
|
if (canPlay()) audio.load(); |
||||||
|
} |
||||||
|
} |
@ -1,179 +0,0 @@ |
|||||||
package mightypork.rogue.sounds; |
|
||||||
|
|
||||||
|
|
||||||
import java.nio.FloatBuffer; |
|
||||||
import java.util.HashMap; |
|
||||||
import java.util.Map; |
|
||||||
|
|
||||||
import mightypork.utils.math.Calc.Buffers; |
|
||||||
import mightypork.utils.math.coord.Coord; |
|
||||||
import mightypork.utils.objects.Mutable; |
|
||||||
import mightypork.utils.time.Updateable; |
|
||||||
|
|
||||||
import org.lwjgl.openal.AL10; |
|
||||||
import org.newdawn.slick.openal.SoundStore; |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Preloaded sounds. |
|
||||||
* |
|
||||||
* @author MightyPork |
|
||||||
*/ |
|
||||||
public class SoundManager implements Updateable { |
|
||||||
|
|
||||||
private static SoundManager inst = new SoundManager(); |
|
||||||
public Mutable<Float> masterVolume = new Mutable<Float>(1F); |
|
||||||
@SuppressWarnings("unchecked") |
|
||||||
public Mutable<Float> effectsVolume = new JointVolume(masterVolume); |
|
||||||
@SuppressWarnings("unchecked") |
|
||||||
public Mutable<Float> loopsVolume = new JointVolume(masterVolume); |
|
||||||
public Coord listener = new Coord(Coord.ZERO); |
|
||||||
private Map<String, EffectPlayer> effects = new HashMap<String, EffectPlayer>(); |
|
||||||
private Map<String, LoopPlayer> loops = new HashMap<String, LoopPlayer>(); |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Singleton constructor |
|
||||||
*/ |
|
||||||
private SoundManager() { |
|
||||||
SoundStore.get().setMaxSources(256); |
|
||||||
SoundStore.get().init(); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
public static SoundManager get() |
|
||||||
{ |
|
||||||
return inst; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
public void addEffect(String key, String resource, float pitch, float gain) |
|
||||||
{ |
|
||||||
EffectPlayer p = new EffectPlayer(new AudioX(resource), pitch, gain, effectsVolume); |
|
||||||
effects.put(key, p); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
public void addLoop(String key, String resource, float pitch, float gain, double fadeIn, double fadeOut) |
|
||||||
{ |
|
||||||
LoopPlayer p = new LoopPlayer(new AudioX(resource), pitch, gain, loopsVolume); |
|
||||||
p.setFadeTimes(fadeIn, fadeOut); |
|
||||||
loops.put(key, p); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
public LoopPlayer getLoop(String key) |
|
||||||
{ |
|
||||||
LoopPlayer p = loops.get(key); |
|
||||||
if (p == null) { |
|
||||||
throw new IllegalArgumentException("Requesting unknown sound loop \"" + key + "\"."); |
|
||||||
} |
|
||||||
return p; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
public EffectPlayer getEffect(String key) |
|
||||||
{ |
|
||||||
EffectPlayer p = effects.get(key); |
|
||||||
if (p == null) { |
|
||||||
throw new IllegalArgumentException("Requesting unknown sound effect \"" + key + "\"."); |
|
||||||
} |
|
||||||
return p; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
public void fadeOutAllLoops() |
|
||||||
{ |
|
||||||
for (LoopPlayer p : loops.values()) { |
|
||||||
p.fadeOut(); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
public void fadeInLoop(String key) |
|
||||||
{ |
|
||||||
getLoop(key).fadeIn(); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
public void fadeInLoop(String key, double seconds) |
|
||||||
{ |
|
||||||
getLoop(key).fadeIn(seconds); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
public void pauseLoop(String key) |
|
||||||
{ |
|
||||||
getLoop(key).pause(); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
public void pauseAllLoops() |
|
||||||
{ |
|
||||||
for (LoopPlayer p : loops.values()) { |
|
||||||
p.pause(); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
public void resumeLoop(String key) |
|
||||||
{ |
|
||||||
getLoop(key).resume(); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Set listener pos |
|
||||||
* |
|
||||||
* @param pos |
|
||||||
*/ |
|
||||||
public 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; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
@Override |
|
||||||
public void update(double delta) |
|
||||||
{ |
|
||||||
for (LoopPlayer lp : loops.values()) { |
|
||||||
lp.update(delta); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
public void setMasterVolume(float f) |
|
||||||
{ |
|
||||||
masterVolume.set(f); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
public void setEffectsVolume(float f) |
|
||||||
{ |
|
||||||
effectsVolume.set(f); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
public void setMusicVolume(float f) |
|
||||||
{ |
|
||||||
loopsVolume.set(f); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
public void destroy() |
|
||||||
{ |
|
||||||
SoundStore.get().clear(); |
|
||||||
} |
|
||||||
} |
|
@ -0,0 +1,309 @@ |
|||||||
|
package mightypork.rogue.sounds; |
||||||
|
|
||||||
|
|
||||||
|
import java.nio.FloatBuffer; |
||||||
|
import java.util.HashMap; |
||||||
|
import java.util.HashSet; |
||||||
|
import java.util.Map; |
||||||
|
import java.util.Set; |
||||||
|
|
||||||
|
import mightypork.utils.math.Calc.Buffers; |
||||||
|
import mightypork.utils.math.coord.Coord; |
||||||
|
import mightypork.utils.objects.Mutable; |
||||||
|
import mightypork.utils.patterns.Destroyable; |
||||||
|
import mightypork.utils.time.Updateable; |
||||||
|
|
||||||
|
import org.lwjgl.openal.AL; |
||||||
|
import org.lwjgl.openal.AL10; |
||||||
|
import org.newdawn.slick.openal.SoundStore; |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Sound system class (only one instance should be made per application) |
||||||
|
* |
||||||
|
* @author MightyPork |
||||||
|
*/ |
||||||
|
@SuppressWarnings("unchecked") |
||||||
|
// needed for JointVolume
|
||||||
|
public class SoundSystem implements Updateable, Destroyable { |
||||||
|
|
||||||
|
// static
|
||||||
|
|
||||||
|
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 Mutable<Double> masterVolume = new Mutable<Double>(1D); |
||||||
|
public Mutable<Double> effectsVolume = new JointVolume(masterVolume); |
||||||
|
public Mutable<Double> loopsVolume = new JointVolume(masterVolume); |
||||||
|
|
||||||
|
private Map<String, EffectPlayer> effects = new HashMap<String, EffectPlayer>(); |
||||||
|
private Map<String, LoopPlayer> loops = new HashMap<String, LoopPlayer>(); |
||||||
|
private Set<AudioX> resources = new HashSet<AudioX>(); |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* 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) |
||||||
|
{ |
||||||
|
EffectPlayer p = new EffectPlayer(getResource(resource), pitch, gain, effectsVolume); |
||||||
|
effects.put(key, p); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* 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) |
||||||
|
{ |
||||||
|
LoopPlayer p = new LoopPlayer(getResource(resource), pitch, gain, loopsVolume); |
||||||
|
p.setFadeTimes(fadeIn, fadeOut); |
||||||
|
loops.put(key, p); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Create {@link AudioX} for a resource |
||||||
|
* @param res a resource name |
||||||
|
* @return the resource |
||||||
|
* |
||||||
|
* @throws IllegalArgumentException if resource is already registered |
||||||
|
*/ |
||||||
|
private AudioX getResource(String res) { |
||||||
|
AudioX a = new AudioX(res); |
||||||
|
if(resources.contains(a)) throw new IllegalArgumentException("Sound resource "+res+" is already registered."); |
||||||
|
resources.add(a); |
||||||
|
return a; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Get a loop player for key |
||||||
|
* |
||||||
|
* @param key sound key |
||||||
|
* @return loop player |
||||||
|
*/ |
||||||
|
public LoopPlayer getLoop(String key) |
||||||
|
{ |
||||||
|
LoopPlayer p = loops.get(key); |
||||||
|
if (p == null) { |
||||||
|
throw new IllegalArgumentException("Requesting unknown sound loop \"" + key + "\"."); |
||||||
|
} |
||||||
|
return p; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Get a effect player for key |
||||||
|
* |
||||||
|
* @param key sound key |
||||||
|
* @return effect player |
||||||
|
*/ |
||||||
|
public EffectPlayer getEffect(String key) |
||||||
|
{ |
||||||
|
EffectPlayer p = effects.get(key); |
||||||
|
if (p == null) { |
||||||
|
throw new IllegalArgumentException("Requesting unknown sound effect \"" + key + "\"."); |
||||||
|
} |
||||||
|
return p; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Fade out all loops (ie. for screen transitions) |
||||||
|
*/ |
||||||
|
public void fadeOutAllLoops() |
||||||
|
{ |
||||||
|
for (LoopPlayer p : loops.values()) { |
||||||
|
p.fadeOut(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Fade in a loop (with default time) |
||||||
|
* |
||||||
|
* @param key sound key |
||||||
|
*/ |
||||||
|
public void fadeInLoop(String key) |
||||||
|
{ |
||||||
|
getLoop(key).fadeIn(); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Fade in a loop |
||||||
|
* |
||||||
|
* @param key sound key |
||||||
|
* @param seconds fade-in duration |
||||||
|
*/ |
||||||
|
public void fadeInLoop(String key, double seconds) |
||||||
|
{ |
||||||
|
getLoop(key).fadeIn(seconds); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Fade out a loop (with default time) |
||||||
|
* |
||||||
|
* @param key sound key |
||||||
|
*/ |
||||||
|
public void fadeOutLoop(String key) |
||||||
|
{ |
||||||
|
getLoop(key).fadeOut(); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Fade out a loop |
||||||
|
* |
||||||
|
* @param key sound key |
||||||
|
* @param seconds fade-out duration |
||||||
|
*/ |
||||||
|
public void fadeOutLoop(String key, double seconds) |
||||||
|
{ |
||||||
|
getLoop(key).fadeOut(seconds); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Pause a loop |
||||||
|
* |
||||||
|
* @param key sound key |
||||||
|
*/ |
||||||
|
public void pauseLoop(String key) |
||||||
|
{ |
||||||
|
getLoop(key).pause(); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Pause all loops (leave volume unchanged) |
||||||
|
*/ |
||||||
|
public void pauseAllLoops() |
||||||
|
{ |
||||||
|
for (LoopPlayer p : loops.values()) { |
||||||
|
p.pause(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Resume a loop |
||||||
|
* |
||||||
|
* @param key sound key |
||||||
|
*/ |
||||||
|
public void resumeLoop(String key) |
||||||
|
{ |
||||||
|
getLoop(key).resume(); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
@Override |
||||||
|
public void update(double delta) |
||||||
|
{ |
||||||
|
for (LoopPlayer lp : loops.values()) { |
||||||
|
lp.update(delta); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* 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); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
@Override |
||||||
|
public void destroy() |
||||||
|
{ |
||||||
|
for(AudioX r: resources) { |
||||||
|
r.destroy(); |
||||||
|
} |
||||||
|
|
||||||
|
SoundStore.get().clear(); |
||||||
|
AL.destroy(); |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,61 @@ |
|||||||
|
package mightypork.rogue.tasks; |
||||||
|
|
||||||
|
|
||||||
|
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.App; |
||||||
|
import mightypork.rogue.Paths; |
||||||
|
import mightypork.utils.logging.Log; |
||||||
|
|
||||||
|
|
||||||
|
public class TaskTakeScreenshot implements Runnable { |
||||||
|
|
||||||
|
private BufferedImage image; |
||||||
|
|
||||||
|
|
||||||
|
public TaskTakeScreenshot() { |
||||||
|
this.image = App.disp().takeScreenshot(); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
@Override |
||||||
|
public void run() |
||||||
|
{ |
||||||
|
String fname = getUniqueScreenshotName(); |
||||||
|
|
||||||
|
// generate unique filename
|
||||||
|
File file; |
||||||
|
int index = 0; |
||||||
|
while (true) { |
||||||
|
file = new File(Paths.SCREENSHOTS, fname + (index > 0 ? "-" + index : "") + ".png"); |
||||||
|
if (!file.exists()) break; |
||||||
|
index++; |
||||||
|
} |
||||||
|
|
||||||
|
Log.f3("Saving screenshot to file: " + file); |
||||||
|
|
||||||
|
String format = "PNG"; |
||||||
|
|
||||||
|
// save to disk
|
||||||
|
try { |
||||||
|
ImageIO.write(image, format, file); |
||||||
|
} catch (IOException e) { |
||||||
|
Log.e("Failed to save screenshot.", e); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
private String getUniqueScreenshotName() |
||||||
|
{ |
||||||
|
DateFormat df = new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss"); |
||||||
|
return df.format(new Date()); |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -1,91 +0,0 @@ |
|||||||
package mightypork.rogue.threads; |
|
||||||
|
|
||||||
|
|
||||||
import java.awt.image.BufferedImage; |
|
||||||
import java.io.File; |
|
||||||
import java.io.IOException; |
|
||||||
import java.nio.ByteBuffer; |
|
||||||
import java.text.DateFormat; |
|
||||||
import java.text.SimpleDateFormat; |
|
||||||
import java.util.Date; |
|
||||||
|
|
||||||
import javax.imageio.ImageIO; |
|
||||||
|
|
||||||
import mightypork.rogue.Paths; |
|
||||||
import mightypork.utils.logging.Log; |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Thread for saving screenshot |
|
||||||
* |
|
||||||
* @author MightyPork |
|
||||||
*/ |
|
||||||
public class ThreadSaveScreenshot extends Thread { |
|
||||||
|
|
||||||
private ByteBuffer buffer; |
|
||||||
private int width; |
|
||||||
private int height; |
|
||||||
private int bpp; |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Save screenshot thread |
|
||||||
* |
|
||||||
* @param buffer byte buffer with image data |
|
||||||
* @param width screen width |
|
||||||
* @param height screen height |
|
||||||
* @param bpp bits per pixel |
|
||||||
*/ |
|
||||||
public ThreadSaveScreenshot(ByteBuffer buffer, int width, int height, int bpp) { |
|
||||||
this.buffer = buffer; |
|
||||||
this.width = width; |
|
||||||
this.height = height; |
|
||||||
this.bpp = bpp; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
private String getUniqueScreenshotName() |
|
||||||
{ |
|
||||||
DateFormat df = new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss"); |
|
||||||
return df.format(new Date()); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
@Override |
|
||||||
public void run() |
|
||||||
{ |
|
||||||
String fname = getUniqueScreenshotName(); |
|
||||||
|
|
||||||
// generate unique filename
|
|
||||||
File file; |
|
||||||
int index = 0; |
|
||||||
while (true) { |
|
||||||
file = new File(Paths.SCREENSHOTS, fname + (index > 0 ? "-" + index : "") + ".png"); |
|
||||||
if (!file.exists()) break; |
|
||||||
index++; |
|
||||||
} |
|
||||||
|
|
||||||
Log.f3("Saving screenshot to file: " + file); |
|
||||||
|
|
||||||
String format = "PNG"; |
|
||||||
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); |
|
||||||
|
|
||||||
// convert to a buffered image
|
|
||||||
for (int x = 0; x < width; x++) { |
|
||||||
for (int y = 0; y < height; y++) { |
|
||||||
int i = (x + (width * y)) * bpp; |
|
||||||
int r = buffer.get(i) & 0xFF; |
|
||||||
int g = buffer.get(i + 1) & 0xFF; |
|
||||||
int b = buffer.get(i + 2) & 0xFF; |
|
||||||
image.setRGB(x, height - (y + 1), (0xFF << 24) | (r << 16) | (g << 8) | b); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
// save to disk
|
|
||||||
try { |
|
||||||
ImageIO.write(image, format, file); |
|
||||||
} catch (IOException e) { |
|
||||||
Log.e("Failed to save screenshot.", e); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
@ -1,32 +0,0 @@ |
|||||||
package mightypork.rogue.threads; |
|
||||||
|
|
||||||
|
|
||||||
import mightypork.rogue.App; |
|
||||||
import mightypork.rogue.input.Keys; |
|
||||||
import mightypork.utils.logging.Log; |
|
||||||
|
|
||||||
import org.lwjgl.input.Keyboard; |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* @author MightyPork |
|
||||||
*/ |
|
||||||
public class ThreadScreenshotTrigger extends Thread { |
|
||||||
|
|
||||||
@Override |
|
||||||
public void run() |
|
||||||
{ |
|
||||||
while (true) { |
|
||||||
if (Keys.justPressed(Keyboard.KEY_F2)) { |
|
||||||
Log.f2("F2, taking screenshot."); |
|
||||||
App.scheduledScreenshot = true; |
|
||||||
Keys.destroyChangeState(Keyboard.KEY_F2); |
|
||||||
} |
|
||||||
try { |
|
||||||
sleep(2); |
|
||||||
} catch (InterruptedException e) { |
|
||||||
e.printStackTrace(); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
@ -1,111 +0,0 @@ |
|||||||
package mightypork.utils.math; |
|
||||||
|
|
||||||
|
|
||||||
import mightypork.utils.math.Calc.Deg; |
|
||||||
import mightypork.utils.math.Calc.Rad; |
|
||||||
import mightypork.utils.math.coord.Coord; |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Polar coordinate in degrees |
|
||||||
* |
|
||||||
* @author MightyPork |
|
||||||
*/ |
|
||||||
public class PolarDeg { |
|
||||||
|
|
||||||
/** angle in degrees */ |
|
||||||
public double angle = 0; |
|
||||||
/** distance in units */ |
|
||||||
public double distance = 0; |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Polar coordinate in degrees |
|
||||||
* |
|
||||||
* @param angle angle in degrees |
|
||||||
* @param distance distance from origin |
|
||||||
*/ |
|
||||||
public PolarDeg(double angle, double distance) { |
|
||||||
this.angle = angle; |
|
||||||
this.distance = distance; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Make polar from coord |
|
||||||
* |
|
||||||
* @param coord coord |
|
||||||
* @return polar |
|
||||||
*/ |
|
||||||
public static PolarDeg fromCoord(Coord coord) |
|
||||||
{ |
|
||||||
return new PolarDeg(Rad.toDeg(Math.atan2(coord.y, coord.x)), Math.sqrt(Calc.square(coord.x) + Calc.square(coord.y))); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Make polar from coords |
|
||||||
* |
|
||||||
* @param x x coord |
|
||||||
* @param y y coord |
|
||||||
* @return polar |
|
||||||
*/ |
|
||||||
public static PolarDeg fromCoord(double x, double y) |
|
||||||
{ |
|
||||||
return PolarDeg.fromCoord(new Coord(x, y)); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Make polar from coords |
|
||||||
* |
|
||||||
* @param x x coord |
|
||||||
* @param z y coord |
|
||||||
* @return polar |
|
||||||
*/ |
|
||||||
public static PolarDeg fromCoordXZ(double x, double z) |
|
||||||
{ |
|
||||||
return PolarDeg.fromCoordXZ(new Coord(x, 0, z)); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Get coord from polar |
|
||||||
* |
|
||||||
* @return coord |
|
||||||
*/ |
|
||||||
public Coord toCoord() |
|
||||||
{ |
|
||||||
return new Coord(distance * Math.cos(Deg.toRad(angle)), distance * Math.sin(Deg.toRad(angle))); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Get X,0,Y coord from polar |
|
||||||
* |
|
||||||
* @return coord |
|
||||||
*/ |
|
||||||
public Coord toCoordXZ() |
|
||||||
{ |
|
||||||
return new Coord(distance * Math.cos(Deg.toRad(angle)), 0, distance * Math.sin(Deg.toRad(angle))); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
@Override |
|
||||||
public String toString() |
|
||||||
{ |
|
||||||
return "Polar(theta=" + angle + ", r=" + distance + ")"; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Build polar from X,Z instead of X,Y |
|
||||||
* |
|
||||||
* @param coord cpprd with X,Z |
|
||||||
* @return polar |
|
||||||
*/ |
|
||||||
public static PolarDeg fromCoordXZ(Coord coord) |
|
||||||
{ |
|
||||||
return fromCoord(coord.x, coord.z); |
|
||||||
} |
|
||||||
} |
|
@ -0,0 +1,94 @@ |
|||||||
|
package mightypork.utils.math.coord; |
||||||
|
|
||||||
|
import mightypork.utils.math.Calc; |
||||||
|
import mightypork.utils.time.Updateable; |
||||||
|
|
||||||
|
|
||||||
|
public class CoordAnimated extends Coord implements Updateable { |
||||||
|
|
||||||
|
private double animTime = 0; |
||||||
|
private Coord offs; |
||||||
|
private Coord start; |
||||||
|
private double time = 0; |
||||||
|
|
||||||
|
/** |
||||||
|
* Update delta timing |
||||||
|
* |
||||||
|
* @param delta delta time to add |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public void update(double delta) |
||||||
|
{ |
||||||
|
if (start == null) start = new Coord(); |
||||||
|
if (offs == null) offs = new Coord(); |
||||||
|
animTime = Calc.clampd(animTime + delta, 0, time); |
||||||
|
if (animIsFinished()) { |
||||||
|
time = 0; |
||||||
|
animTime = 0; |
||||||
|
start.setTo(this); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Remember position (other changes will be for animation) |
||||||
|
*/ |
||||||
|
public void animRemember() |
||||||
|
{ |
||||||
|
if (start == null) start = new Coord(); |
||||||
|
if (offs == null) offs = new Coord(); |
||||||
|
start.setTo(this); |
||||||
|
offs = Coord.zero(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Start animation |
||||||
|
* |
||||||
|
* @param time anim length |
||||||
|
*/ |
||||||
|
public void animStart(double time) |
||||||
|
{ |
||||||
|
if (start == null) start = new Coord(); |
||||||
|
if (offs == null) offs = new Coord(); |
||||||
|
this.time = time; |
||||||
|
animTime = 0; |
||||||
|
offs = start.vecTo(this); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Stop animation, assign to current value |
||||||
|
*/ |
||||||
|
public void animStop() |
||||||
|
{ |
||||||
|
setTo(animGetCurrent()); |
||||||
|
animRemember(); |
||||||
|
animTime = 0; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Get if animation is finished |
||||||
|
* |
||||||
|
* @return is finished |
||||||
|
*/ |
||||||
|
public boolean animIsFinished() |
||||||
|
{ |
||||||
|
return animTime >= time; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Get current value (animated) |
||||||
|
* |
||||||
|
* @return curent value |
||||||
|
*/ |
||||||
|
public Coord animGetCurrent() |
||||||
|
{ |
||||||
|
if (time == 0) return getCopy(); // avoid zero division
|
||||||
|
|
||||||
|
if (start == null) start = new Coord(); |
||||||
|
if (offs == null) offs = new Coord(); |
||||||
|
|
||||||
|
if (animIsFinished()) return this; |
||||||
|
|
||||||
|
return start.add(offs.mul(animTime / time)); |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -1,398 +0,0 @@ |
|||||||
package mightypork.utils.math.coord; |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Simple integer coordinate class<br> |
|
||||||
* Unlike Coord, this is suitable for using in array indices etc. |
|
||||||
* |
|
||||||
* @author MightyPork |
|
||||||
*/ |
|
||||||
public class CoordI { |
|
||||||
|
|
||||||
/** X coordinate */ |
|
||||||
public int x = 0; |
|
||||||
/** Y coordinate */ |
|
||||||
public int y = 0; |
|
||||||
/** Z coordinate */ |
|
||||||
public int z = 0; |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Create CoordI as copy of other |
|
||||||
* |
|
||||||
* @param other coord to copy |
|
||||||
*/ |
|
||||||
public CoordI(CoordI other) { |
|
||||||
setTo(other); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Integer 2D Coord |
|
||||||
* |
|
||||||
* @param x x coord |
|
||||||
* @param y y coord |
|
||||||
*/ |
|
||||||
public CoordI(int x, int y) { |
|
||||||
this.x = x; |
|
||||||
this.y = y; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Integer 3D Coord |
|
||||||
* |
|
||||||
* @param x x coord |
|
||||||
* @param y y coord |
|
||||||
* @param z z coord |
|
||||||
*/ |
|
||||||
public CoordI(int x, int y, int z) { |
|
||||||
this.x = x; |
|
||||||
this.y = y; |
|
||||||
this.z = z; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Empty cobnstructor 0,0,0 |
|
||||||
*/ |
|
||||||
public CoordI() { |
|
||||||
x = 0; |
|
||||||
y = 0; |
|
||||||
z = 0; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Add other coordI coordinates in a copy |
|
||||||
* |
|
||||||
* @param other coordI to add |
|
||||||
* @return copy modified |
|
||||||
*/ |
|
||||||
public CoordI add(CoordI other) |
|
||||||
{ |
|
||||||
return copy().add_ip(other); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Add coords in copy |
|
||||||
* |
|
||||||
* @param x x coord |
|
||||||
* @param y y coord |
|
||||||
* @return the copy |
|
||||||
*/ |
|
||||||
public CoordI add(int x, int y) |
|
||||||
{ |
|
||||||
return copy().add_ip(x, y, 0); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Add coords in copy |
|
||||||
* |
|
||||||
* @param x x coord |
|
||||||
* @param y y coord |
|
||||||
* @param z z coord |
|
||||||
* @return the copy |
|
||||||
*/ |
|
||||||
public CoordI add(int x, int y, int z) |
|
||||||
{ |
|
||||||
return copy().add_ip(x, y, z); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Add other coordI coordinates in place |
|
||||||
* |
|
||||||
* @param move coordI to add |
|
||||||
* @return this |
|
||||||
*/ |
|
||||||
public CoordI add_ip(CoordI move) |
|
||||||
{ |
|
||||||
x += move.x; |
|
||||||
y += move.y; |
|
||||||
z += move.z; |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Add coords in place |
|
||||||
* |
|
||||||
* @param x x coord |
|
||||||
* @param y y coord |
|
||||||
* @return this |
|
||||||
*/ |
|
||||||
public CoordI add_ip(int x, int y) |
|
||||||
{ |
|
||||||
this.x += x; |
|
||||||
this.y += y; |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Add coords in place |
|
||||||
* |
|
||||||
* @param x x coord |
|
||||||
* @param y y coord |
|
||||||
* @param z z coord |
|
||||||
* @return this |
|
||||||
*/ |
|
||||||
public CoordI add_ip(int x, int y, int z) |
|
||||||
{ |
|
||||||
this.x += x; |
|
||||||
this.y += y; |
|
||||||
this.z += z; |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Get copy |
|
||||||
* |
|
||||||
* @return copy |
|
||||||
*/ |
|
||||||
public CoordI copy() |
|
||||||
{ |
|
||||||
return new CoordI(x, y, z); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
@Override |
|
||||||
public boolean equals(Object obj) |
|
||||||
{ |
|
||||||
if (obj == null) return false; |
|
||||||
if (obj instanceof CoordI) return ((CoordI) obj).x == x && ((CoordI) obj).y == y && ((CoordI) obj).z == z; |
|
||||||
return false; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
@Override |
|
||||||
public int hashCode() |
|
||||||
{ |
|
||||||
return x ^ y ^ z; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Middle of this and other coordinate, rounded to CoordI - integers |
|
||||||
* |
|
||||||
* @param other other coordI |
|
||||||
* @return middle CoordI |
|
||||||
*/ |
|
||||||
public CoordI midTo(CoordI other) |
|
||||||
{ |
|
||||||
return new CoordI((x + other.x) / 2, (y + other.y) / 2, (z + other.z) / 2); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Multiply in copy 2D |
|
||||||
* |
|
||||||
* @param x x coord |
|
||||||
* @param y y coord |
|
||||||
* @return the copy |
|
||||||
*/ |
|
||||||
public CoordI mul(double x, double y) |
|
||||||
{ |
|
||||||
return copy().mul_ip(x, y); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Multiply in copy |
|
||||||
* |
|
||||||
* @param x x coord |
|
||||||
* @param y y coord |
|
||||||
* @param z z coord |
|
||||||
* @return the copy |
|
||||||
*/ |
|
||||||
public CoordI mul(double x, double y, double z) |
|
||||||
{ |
|
||||||
return copy().mul_ip(x, y, z); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Multiply in place 2D |
|
||||||
* |
|
||||||
* @param x x coord |
|
||||||
* @param y y coord |
|
||||||
* @return this |
|
||||||
*/ |
|
||||||
public CoordI mul_ip(double x, double y) |
|
||||||
{ |
|
||||||
this.x *= x; |
|
||||||
this.y *= y; |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Multiply in place |
|
||||||
* |
|
||||||
* @param x x coord |
|
||||||
* @param y y coord |
|
||||||
* @param z z coord |
|
||||||
* @return this |
|
||||||
*/ |
|
||||||
public CoordI mul_ip(double x, double y, double z) |
|
||||||
{ |
|
||||||
this.x *= x; |
|
||||||
this.y *= y; |
|
||||||
this.z *= z; |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Set to coords from other coord |
|
||||||
* |
|
||||||
* @param other source coord |
|
||||||
*/ |
|
||||||
public void setTo(CoordI other) |
|
||||||
{ |
|
||||||
if (other == null) { |
|
||||||
setTo(0, 0, 0); |
|
||||||
return; |
|
||||||
} |
|
||||||
this.x = other.x; |
|
||||||
this.y = other.y; |
|
||||||
this.z = other.z; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Set coords to |
|
||||||
* |
|
||||||
* @param x x coord to set |
|
||||||
* @param y y coord to set |
|
||||||
*/ |
|
||||||
public void setTo(int x, int y) |
|
||||||
{ |
|
||||||
this.x = x; |
|
||||||
this.y = y; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Set coords to |
|
||||||
* |
|
||||||
* @param x x coord to set |
|
||||||
* @param y y coord to set |
|
||||||
* @param z z coord to set |
|
||||||
*/ |
|
||||||
public void setTo(int x, int y, int z) |
|
||||||
{ |
|
||||||
this.x = x; |
|
||||||
this.y = y; |
|
||||||
this.z = z; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Subtract other coordI coordinates in a copy |
|
||||||
* |
|
||||||
* @param other coordI to subtract |
|
||||||
* @return copy subtracted |
|
||||||
*/ |
|
||||||
public CoordI sub(CoordI other) |
|
||||||
{ |
|
||||||
return copy().sub_ip(other); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Subtract x,y in a copy |
|
||||||
* |
|
||||||
* @param x x to subtract |
|
||||||
* @param y y to subtract |
|
||||||
* @return copy subtracted |
|
||||||
*/ |
|
||||||
public CoordI sub(int x, int y) |
|
||||||
{ |
|
||||||
return copy().sub_ip(new CoordI(x, y)); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Subtract x,y,z in a copy |
|
||||||
* |
|
||||||
* @param x x to subtract |
|
||||||
* @param y y to subtract |
|
||||||
* @param z z to subtract |
|
||||||
* @return copy subtracted |
|
||||||
*/ |
|
||||||
public CoordI sub(int x, int y, int z) |
|
||||||
{ |
|
||||||
return copy().sub_ip(new CoordI(x, y, z)); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Subtract other coordI coordinates in place |
|
||||||
* |
|
||||||
* @param move coordI to subtract |
|
||||||
* @return this |
|
||||||
*/ |
|
||||||
public CoordI sub_ip(CoordI move) |
|
||||||
{ |
|
||||||
x -= move.x; |
|
||||||
y -= move.y; |
|
||||||
z -= move.z; |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Sub coords in place |
|
||||||
* |
|
||||||
* @param x x coord |
|
||||||
* @param y y coord |
|
||||||
* @return this |
|
||||||
*/ |
|
||||||
public CoordI sub_ip(int x, int y) |
|
||||||
{ |
|
||||||
this.x -= x; |
|
||||||
this.y -= y; |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Sub coords in place |
|
||||||
* |
|
||||||
* @param x x coord |
|
||||||
* @param y y coord |
|
||||||
* @param z z coord |
|
||||||
* @return this |
|
||||||
*/ |
|
||||||
public CoordI sub_ip(int x, int y, int z) |
|
||||||
{ |
|
||||||
this.x -= x; |
|
||||||
this.y -= y; |
|
||||||
this.z -= z; |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Convert to double Coord |
|
||||||
* |
|
||||||
* @return coord with X and y from this CoordI |
|
||||||
*/ |
|
||||||
public Coord toCoord() |
|
||||||
{ |
|
||||||
return new Coord(x, y); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
@Override |
|
||||||
public String toString() |
|
||||||
{ |
|
||||||
return "[ " + x + " ; " + y + " ; " + z + " ]"; |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
@ -1,326 +0,0 @@ |
|||||||
package mightypork.utils.math.coord; |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Vector in 2D/3D space. |
|
||||||
* |
|
||||||
* @author MightyPork |
|
||||||
*/ |
|
||||||
public class Vec extends Coord { |
|
||||||
|
|
||||||
/** Vec [1;1;1] */ |
|
||||||
@SuppressWarnings("hiding") |
|
||||||
public static final Vec ONE = new Vec(1, 1, 1); |
|
||||||
/** Zero vector */ |
|
||||||
@SuppressWarnings("hiding") |
|
||||||
public static final Vec ZERO = new Vec(0, 0, 0); |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Get cross product of two vectors |
|
||||||
* |
|
||||||
* @param a 1st vector |
|
||||||
* @param b 2nd vector |
|
||||||
* @return cross product |
|
||||||
*/ |
|
||||||
public static Vec cross(Vec a, Vec b) |
|
||||||
{ |
|
||||||
return a.cross(b); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Get dot product of two vectors |
|
||||||
* |
|
||||||
* @param a 1st vector |
|
||||||
* @param b 2nd vector |
|
||||||
* @return dot product |
|
||||||
*/ |
|
||||||
public static double dot(Vec a, Vec b) |
|
||||||
{ |
|
||||||
return a.dot(b); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Generate random coord (gaussian) |
|
||||||
* |
|
||||||
* @param max max distance from 0 |
|
||||||
* @return new coord |
|
||||||
*/ |
|
||||||
public static Vec random(double max) |
|
||||||
{ |
|
||||||
return new Vec(Coord.random(max)); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Generate random coord (min-max) |
|
||||||
* |
|
||||||
* @param max max distance from 0 |
|
||||||
* @return new coord |
|
||||||
*/ |
|
||||||
public static Vec random(double min, double max) |
|
||||||
{ |
|
||||||
return new Vec(Coord.random(min, max)); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Scale vector |
|
||||||
* |
|
||||||
* @param a vector |
|
||||||
* @param scale |
|
||||||
* @return scaled copy |
|
||||||
*/ |
|
||||||
public static Vec scale(Vec a, double scale) |
|
||||||
{ |
|
||||||
return a.scale(scale); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Get vector size |
|
||||||
* |
|
||||||
* @param vec vector to get size of |
|
||||||
* @return size in units |
|
||||||
*/ |
|
||||||
public static double size(Vec vec) |
|
||||||
{ |
|
||||||
return vec.size(); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Create zero vector |
|
||||||
*/ |
|
||||||
public Vec() { |
|
||||||
super(); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Create vector as a copy of another |
|
||||||
* |
|
||||||
* @param copied copied vector |
|
||||||
*/ |
|
||||||
public Vec(Coord copied) { |
|
||||||
super(copied); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Create 2D vector |
|
||||||
* |
|
||||||
* @param x x coordinate |
|
||||||
* @param y y coordinate |
|
||||||
*/ |
|
||||||
public Vec(Number x, Number y) { |
|
||||||
super(x, y); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Create 3D vector |
|
||||||
* |
|
||||||
* @param x x coordinate |
|
||||||
* @param y y coordinate |
|
||||||
* @param z z coordinate |
|
||||||
*/ |
|
||||||
public Vec(Number x, Number y, Number z) { |
|
||||||
super(x, y, z); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
@Override |
|
||||||
public Vec copy() |
|
||||||
{ |
|
||||||
return new Vec(this); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Multiply by other vector, vector multiplication |
|
||||||
* |
|
||||||
* @param vec other vector |
|
||||||
* @return copy multiplied |
|
||||||
*/ |
|
||||||
public Vec cross(Vec vec) |
|
||||||
{ |
|
||||||
return copy().cross_ip(vec); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Multiply by other vector, vector multiplication; in place |
|
||||||
* |
|
||||||
* @param vec other vector |
|
||||||
* @return this |
|
||||||
*/ |
|
||||||
public Vec cross_ip(Vec vec) |
|
||||||
{ |
|
||||||
setTo(y * vec.z - z * vec.y, z * vec.x - x * vec.z, x * vec.y - y * vec.x); |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Get dot product |
|
||||||
* |
|
||||||
* @param vec other vector |
|
||||||
* @return dot product |
|
||||||
*/ |
|
||||||
public double dot(Vec vec) |
|
||||||
{ |
|
||||||
return x * vec.x + y * vec.y + z * vec.z; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
// STATIC
|
|
||||||
|
|
||||||
/** |
|
||||||
* Negate all coordinates (* -1) |
|
||||||
* |
|
||||||
* @return negated coordinate |
|
||||||
*/ |
|
||||||
public Vec neg() |
|
||||||
{ |
|
||||||
return copy().neg_ip(); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Negate all coordinates (* -1), in place |
|
||||||
* |
|
||||||
* @return this |
|
||||||
*/ |
|
||||||
public Vec neg_ip() |
|
||||||
{ |
|
||||||
scale_ip(-1); |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Scale vector to given size |
|
||||||
* |
|
||||||
* @param size size we need |
|
||||||
* @return scaled vector |
|
||||||
*/ |
|
||||||
public Vec norm(double size) |
|
||||||
{ |
|
||||||
return copy().norm_ip(size); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Scale vector to given size, in place |
|
||||||
* |
|
||||||
* @param size size we need |
|
||||||
* @return scaled vector |
|
||||||
*/ |
|
||||||
public Vec norm_ip(double size) |
|
||||||
{ |
|
||||||
if (size() == 0) { |
|
||||||
z = -1; |
|
||||||
} |
|
||||||
if (size == 0) { |
|
||||||
setTo(0, 0, 0); |
|
||||||
return this; |
|
||||||
} |
|
||||||
double k = size / size(); |
|
||||||
scale_ip(k); |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* offset randomly |
|
||||||
* |
|
||||||
* @param max max +- offset |
|
||||||
* @return offset coord |
|
||||||
*/ |
|
||||||
@Override |
|
||||||
public Vec random_offset(double max) |
|
||||||
{ |
|
||||||
return (Vec) super.random_offset(max); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* offset randomly |
|
||||||
* |
|
||||||
* @param min min offset |
|
||||||
* @param max max offset |
|
||||||
* @return offset coord |
|
||||||
*/ |
|
||||||
@Override |
|
||||||
public Vec random_offset(double min, double max) |
|
||||||
{ |
|
||||||
return (Vec) super.random_offset(min, max); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* offset randomly in place |
|
||||||
* |
|
||||||
* @param max max +- offset |
|
||||||
* @return this |
|
||||||
*/ |
|
||||||
@Override |
|
||||||
public Vec random_offset_ip(double max) |
|
||||||
{ |
|
||||||
return (Vec) super.random_offset_ip(max); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* offset randomly in place |
|
||||||
* |
|
||||||
* @param min min offset |
|
||||||
* @param max max offset |
|
||||||
* @return this |
|
||||||
*/ |
|
||||||
@Override |
|
||||||
public Vec random_offset_ip(double min, double max) |
|
||||||
{ |
|
||||||
return (Vec) super.random_offset_ip(min, max); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Multiply all coordinates by factor; scalar multiplication |
|
||||||
* |
|
||||||
* @param factor multiplier |
|
||||||
* @return copy multiplied |
|
||||||
*/ |
|
||||||
public Vec scale(double factor) |
|
||||||
{ |
|
||||||
return copy().scale_ip(factor); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Multiply all coordinates by factor, in place |
|
||||||
* |
|
||||||
* @param factor multiplier |
|
||||||
* @return this |
|
||||||
*/ |
|
||||||
public Vec scale_ip(double factor) |
|
||||||
{ |
|
||||||
return (Vec) mul_ip(factor); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Get vector size |
|
||||||
* |
|
||||||
* @return vector size in units |
|
||||||
*/ |
|
||||||
@Override |
|
||||||
public double size() |
|
||||||
{ |
|
||||||
return Math.sqrt(x * x + y * y + z * z); |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
@ -0,0 +1,322 @@ |
|||||||
|
package mightypork.utils.math.easing; |
||||||
|
|
||||||
|
|
||||||
|
import mightypork.utils.math.Calc; |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Easing function.<br> |
||||||
|
* The easing function must be time-invariant and it's domain is [0-1]. |
||||||
|
* |
||||||
|
* @author MightyPork |
||||||
|
*/ |
||||||
|
public interface Easing { |
||||||
|
|
||||||
|
/** |
||||||
|
* Get value of the easing function at given time. |
||||||
|
* |
||||||
|
* @param time number in range 0..1 |
||||||
|
* @return value at given time |
||||||
|
*/ |
||||||
|
public double get(double time); |
||||||
|
|
||||||
|
public static final Easing NONE = new Easing() { |
||||||
|
|
||||||
|
@Override |
||||||
|
public double get(double time) |
||||||
|
{ |
||||||
|
double t = Calc.clampd(time, 0, 1); |
||||||
|
|
||||||
|
return (t < 0.5 ? 0 : 1); |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
public static final Easing LINEAR = new Easing() { |
||||||
|
|
||||||
|
@Override |
||||||
|
public double get(double time) |
||||||
|
{ |
||||||
|
double t = Calc.clampd(time, 0, 1); |
||||||
|
|
||||||
|
return t; |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
public static final Easing QUADRATIC_IN = new Easing() { |
||||||
|
|
||||||
|
@Override |
||||||
|
public double get(double time) |
||||||
|
{ |
||||||
|
double t = Calc.clampd(time, 0, 1); |
||||||
|
|
||||||
|
return t * t; |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
public static final Easing QUADRATIC_OUT = new Easing() { |
||||||
|
|
||||||
|
@Override |
||||||
|
public double get(double time) |
||||||
|
{ |
||||||
|
double t = Calc.clampd(time, 0, 1); |
||||||
|
|
||||||
|
return 1 - (t - 1) * (t - 1); |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
public static final Easing QUADRATIC = new Easing() { |
||||||
|
|
||||||
|
@Override |
||||||
|
public double get(double time) |
||||||
|
{ |
||||||
|
double t = Calc.clampd(time, 0, 1); |
||||||
|
|
||||||
|
if (t < 0.5) return QUADRATIC_IN.get(2 * t) * 0.5; |
||||||
|
return 0.5 + QUADRATIC_OUT.get(2 * t - 1) * 0.5; |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
public static final Easing CUBIC_IN = new Easing() { |
||||||
|
|
||||||
|
@Override |
||||||
|
public double get(double time) |
||||||
|
{ |
||||||
|
double t = Calc.clampd(time, 0, 1); |
||||||
|
|
||||||
|
return t * t * t; |
||||||
|
} |
||||||
|
}; |
||||||
|
public static final Easing CUBIC_OUT = new Easing() { |
||||||
|
|
||||||
|
@Override |
||||||
|
public double get(double time) |
||||||
|
{ |
||||||
|
double t = Calc.clampd(time, 0, 1); |
||||||
|
|
||||||
|
return (t - 1) * (t - 1) * (t - 1) + 1; |
||||||
|
} |
||||||
|
}; |
||||||
|
public static final Easing CUBIC = new Easing() { |
||||||
|
|
||||||
|
@Override |
||||||
|
public double get(double time) |
||||||
|
{ |
||||||
|
double d = 1; |
||||||
|
double t = time; |
||||||
|
double b = 0; |
||||||
|
double c = (1 - 0); |
||||||
|
t /= d / 2; |
||||||
|
if (t < 1) return c / 2 * t * t * t + b; |
||||||
|
t -= 2; |
||||||
|
return c / 2 * (t * t * t + 2) + b; |
||||||
|
} |
||||||
|
}; |
||||||
|
public static final Easing QUARTIC_IN = new Easing() { |
||||||
|
|
||||||
|
@Override |
||||||
|
public double get(double time) |
||||||
|
{ |
||||||
|
double d = 1; |
||||||
|
double t = time; |
||||||
|
double b = 0; |
||||||
|
double c = (1 - 0); |
||||||
|
t /= d; |
||||||
|
return c * t * t * t * t + b; |
||||||
|
} |
||||||
|
}; |
||||||
|
public static final Easing QUARTIC_OUT = new Easing() { |
||||||
|
|
||||||
|
@Override |
||||||
|
public double get(double time) |
||||||
|
{ |
||||||
|
double d = 1; |
||||||
|
double t = time; |
||||||
|
double b = 0; |
||||||
|
double c = (1 - 0); |
||||||
|
|
||||||
|
t /= d; |
||||||
|
t--; |
||||||
|
return -c * (t * t * t * t - 1) + b; |
||||||
|
} |
||||||
|
}; |
||||||
|
public static final Easing QUARTIC = new Easing() { |
||||||
|
|
||||||
|
@Override |
||||||
|
public double get(double time) |
||||||
|
{ |
||||||
|
double d = 1; |
||||||
|
double t = time; |
||||||
|
double b = 0; |
||||||
|
double c = (1 - 0); |
||||||
|
|
||||||
|
t /= d / 2; |
||||||
|
if (t < 1) return c / 2 * t * t * t * t + b; |
||||||
|
t -= 2; |
||||||
|
return -c / 2 * (t * t * t * t - 2) + b; |
||||||
|
} |
||||||
|
}; |
||||||
|
public static final Easing QUINTIC_IN = new Easing() { |
||||||
|
|
||||||
|
@Override |
||||||
|
public double get(double time) |
||||||
|
{ |
||||||
|
double d = 1; |
||||||
|
double t = time; |
||||||
|
double b = 0; |
||||||
|
double c = (1 - 0); |
||||||
|
t /= d; |
||||||
|
return c * t * t * t * t * t + b; |
||||||
|
} |
||||||
|
}; |
||||||
|
public static final Easing QUINTIC_OUT = new Easing() { |
||||||
|
|
||||||
|
@Override |
||||||
|
public double get(double time) |
||||||
|
{ |
||||||
|
double d = 1; |
||||||
|
double t = time; |
||||||
|
double b = 0; |
||||||
|
double c = (1 - 0); |
||||||
|
t /= d; |
||||||
|
t--; |
||||||
|
return c * (t * t * t * t * t + 1) + b; |
||||||
|
} |
||||||
|
}; |
||||||
|
public static final Easing QUINTIC_IN_OUT = new Easing() { |
||||||
|
|
||||||
|
@Override |
||||||
|
public double get(double time) |
||||||
|
{ |
||||||
|
double d = 1; |
||||||
|
double t = time; |
||||||
|
double b = 0; |
||||||
|
double c = (1 - 0); |
||||||
|
t /= d / 2; |
||||||
|
if (t < 1) return c / 2 * t * t * t * t * t + b; |
||||||
|
t -= 2; |
||||||
|
return c / 2 * (t * t * t * t * t + 2) + b; |
||||||
|
} |
||||||
|
}; |
||||||
|
public static final Easing SINE_IN = new Easing() { |
||||||
|
|
||||||
|
@Override |
||||||
|
public double get(double time) |
||||||
|
{ |
||||||
|
double d = 1; |
||||||
|
double t = time; |
||||||
|
double b = 0; |
||||||
|
double c = (1 - 0); |
||||||
|
return -c * Math.cos(t / d * (Math.PI / 2)) + c + b; |
||||||
|
} |
||||||
|
}; |
||||||
|
public static final Easing SINE_OUT = new Easing() { |
||||||
|
|
||||||
|
@Override |
||||||
|
public double get(double time) |
||||||
|
{ |
||||||
|
double d = 1; |
||||||
|
double t = time; |
||||||
|
double b = 0; |
||||||
|
double c = (1 - 0); |
||||||
|
|
||||||
|
return c * Math.sin(t / d * (Math.PI / 2)) + b; |
||||||
|
} |
||||||
|
}; |
||||||
|
public static final Easing SINE = new Easing() { |
||||||
|
|
||||||
|
@Override |
||||||
|
public double get(double time) |
||||||
|
{ |
||||||
|
double d = 1; |
||||||
|
double t = time; |
||||||
|
double b = 0; |
||||||
|
double c = (1 - 0); |
||||||
|
return -c / 2 * (Math.cos(Math.PI * t / d) - 1) + b; |
||||||
|
} |
||||||
|
}; |
||||||
|
public static final Easing EXPO_IN = new Easing() { |
||||||
|
|
||||||
|
@Override |
||||||
|
public double get(double time) |
||||||
|
{ |
||||||
|
double d = 1; |
||||||
|
double t = time; |
||||||
|
double b = 0; |
||||||
|
double c = (1 - 0); |
||||||
|
|
||||||
|
return c * Math.pow(2, 10 * (t / d - 1)) + b; |
||||||
|
} |
||||||
|
}; |
||||||
|
public static final Easing EXPO_OUT = new Easing() { |
||||||
|
|
||||||
|
@Override |
||||||
|
public double get(double time) |
||||||
|
{ |
||||||
|
double d = 1; |
||||||
|
double t = time; |
||||||
|
double b = 0; |
||||||
|
double c = (1 - 0); |
||||||
|
|
||||||
|
return c * (-Math.pow(2, -10 * t / d) + 1) + b; |
||||||
|
} |
||||||
|
}; |
||||||
|
public static final Easing EXPO = new Easing() { |
||||||
|
|
||||||
|
@Override |
||||||
|
public double get(double time) |
||||||
|
{ |
||||||
|
double d = 1; |
||||||
|
double t = time; |
||||||
|
double b = 0; |
||||||
|
double c = (1 - 0); |
||||||
|
|
||||||
|
t /= d / 2; |
||||||
|
if (t < 1) return c / 2 * Math.pow(2, 10 * (t - 1)) + b; |
||||||
|
t--; |
||||||
|
return c / 2 * (-Math.pow(2, -10 * t) + 2) + b; |
||||||
|
} |
||||||
|
}; |
||||||
|
public static final Easing CIRC_IN = new Easing() { |
||||||
|
|
||||||
|
@Override |
||||||
|
public double get(double time) |
||||||
|
{ |
||||||
|
double d = 1; |
||||||
|
double t = time; |
||||||
|
double b = 0; |
||||||
|
double c = (1 - 0); |
||||||
|
t /= d; |
||||||
|
return -c * (Math.sqrt(1 - t * t) - 1) + b; |
||||||
|
} |
||||||
|
}; |
||||||
|
public static final Easing CIRC_OUT = new Easing() { |
||||||
|
|
||||||
|
@Override |
||||||
|
public double get(double time) |
||||||
|
{ |
||||||
|
double d = 1; |
||||||
|
double t = time; |
||||||
|
double b = 0; |
||||||
|
double c = (1 - 0); |
||||||
|
|
||||||
|
t--; |
||||||
|
return c * Math.sqrt(1 - t * t) + b; |
||||||
|
} |
||||||
|
}; |
||||||
|
public static final Easing CIRC = new Easing() { |
||||||
|
|
||||||
|
@Override |
||||||
|
public double get(double time) |
||||||
|
{ |
||||||
|
double d = 1; |
||||||
|
double t = time; |
||||||
|
double b = 0; |
||||||
|
double c = (1 - 0); |
||||||
|
|
||||||
|
t /= d / 2; |
||||||
|
if (t < 1) return -c / 2 * (Math.sqrt(1 - t * t) - 1) + b; |
||||||
|
t -= 2; |
||||||
|
return c / 2 * (Math.sqrt(1 - t * t) + 1) + b; |
||||||
|
} |
||||||
|
}; |
||||||
|
} |
@ -0,0 +1,14 @@ |
|||||||
|
package mightypork.utils.patterns; |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Object that can be destroyed (free resources etc) |
||||||
|
* |
||||||
|
* @author MightyPork |
||||||
|
*/ |
||||||
|
public interface Destroyable { |
||||||
|
/** |
||||||
|
* Destroy this object |
||||||
|
*/ |
||||||
|
public void destroy(); |
||||||
|
} |
@ -0,0 +1,14 @@ |
|||||||
|
package mightypork.utils.patterns; |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Object that can be initialized |
||||||
|
* |
||||||
|
* @author MightyPork |
||||||
|
*/ |
||||||
|
public interface Initializable { |
||||||
|
/** |
||||||
|
* Initialize if not initialized yet |
||||||
|
*/ |
||||||
|
public void initialize(); |
||||||
|
} |
@ -0,0 +1,18 @@ |
|||||||
|
package mightypork.utils.patterns.subscription; |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Something that can be handled by HANDLER. |
||||||
|
* |
||||||
|
* @author MightyPork |
||||||
|
* @param <HANDLER> handler type |
||||||
|
*/ |
||||||
|
public interface Handleable<HANDLER> { |
||||||
|
|
||||||
|
/** |
||||||
|
* Ask handler to handle this message. |
||||||
|
* |
||||||
|
* @param handler handler instance |
||||||
|
*/ |
||||||
|
public void handleBy(HANDLER handler); |
||||||
|
} |
@ -0,0 +1,121 @@ |
|||||||
|
package mightypork.utils.patterns.subscription; |
||||||
|
|
||||||
|
import java.util.LinkedHashSet; |
||||||
|
import java.util.Set; |
||||||
|
|
||||||
|
import mightypork.utils.logging.Log; |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* An event bus, accommodating multiple {@link MessageChannel}s. |
||||||
|
* |
||||||
|
* @author MightyPork |
||||||
|
*/ |
||||||
|
public class MessageBus implements Subscribable { |
||||||
|
|
||||||
|
private Set<MessageChannel<?, ?>> channels = new LinkedHashSet<MessageChannel<?, ?>>(); |
||||||
|
private Set<Object> clients = new LinkedHashSet<Object>(); |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Add a {@link MessageChannel} to this bus.<br> |
||||||
|
* If a channel of matching types is already added, it is returned instead. |
||||||
|
* |
||||||
|
* @param channel channel to be added |
||||||
|
* @return the channel that's now in the bus |
||||||
|
*/ |
||||||
|
public MessageChannel<?, ?> addChannel(MessageChannel<?, ?> channel) |
||||||
|
{ |
||||||
|
// if the channel already exists, return this instance instead.
|
||||||
|
for (MessageChannel<?, ?> ch : channels) { |
||||||
|
if (ch.equals(channel)) { |
||||||
|
Log.w("Channel of type "+channel+" already registered."); |
||||||
|
return ch; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
channels.add(channel); |
||||||
|
|
||||||
|
for (Object c : clients) { |
||||||
|
channel.addSubscriber(c); |
||||||
|
} |
||||||
|
|
||||||
|
return channel; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Remove a {@link MessageChannel} from this bus |
||||||
|
* |
||||||
|
* @param channel true if channel was removed |
||||||
|
*/ |
||||||
|
public void removeChannel(MessageChannel<?, ?> channel) |
||||||
|
{ |
||||||
|
channels.remove(channel); |
||||||
|
|
||||||
|
for (Object c : clients) { |
||||||
|
channel.removeSubscriber(c); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Broadcast a message |
||||||
|
* |
||||||
|
* @param message message |
||||||
|
* @return true if message was accepted by at least one channel |
||||||
|
*/ |
||||||
|
public boolean broadcast(Object message) |
||||||
|
{ |
||||||
|
boolean sent = false; |
||||||
|
for (MessageChannel<?, ?> b : channels) { |
||||||
|
sent |= b.broadcast(message); |
||||||
|
} |
||||||
|
return sent; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Subscribe a client to the bus. The client will be connected to all |
||||||
|
* current and future channels, until removed from the bus. |
||||||
|
* |
||||||
|
* @return <code>true</code> |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public boolean addSubscriber(Object client) |
||||||
|
{ |
||||||
|
for (MessageChannel<?, ?> b : channels) { |
||||||
|
b.addSubscriber(client); |
||||||
|
} |
||||||
|
|
||||||
|
clients.add(client); |
||||||
|
|
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
@Override |
||||||
|
public void removeSubscriber(Object client) |
||||||
|
{ |
||||||
|
for (MessageChannel<?, ?> b : channels) { |
||||||
|
b.removeSubscriber(client); |
||||||
|
} |
||||||
|
|
||||||
|
clients.remove(client); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Add a channel for given message and client type. |
||||||
|
* |
||||||
|
* @param messageClass message type |
||||||
|
* @param clientClass client type |
||||||
|
* @return the created channel instance |
||||||
|
*/ |
||||||
|
public <F_MESSAGE extends Handleable<F_CLIENT>, F_CLIENT> MessageChannel<?, ?> registerMessageType(Class<F_MESSAGE> messageClass, Class<F_CLIENT> clientClass) |
||||||
|
{ |
||||||
|
MessageChannel<F_MESSAGE, F_CLIENT> bc = new MessageChannel<F_MESSAGE, F_CLIENT>(messageClass, clientClass); |
||||||
|
return addChannel(bc); |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,156 @@ |
|||||||
|
package mightypork.utils.patterns.subscription; |
||||||
|
|
||||||
|
|
||||||
|
import java.util.HashSet; |
||||||
|
import java.util.Set; |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Message subsystem (broadcaster with clients) to which clients can subscribe.<br> |
||||||
|
* If more than one type of message is needed, {@link MessageBus} is a better |
||||||
|
* choice. |
||||||
|
* |
||||||
|
* @author MightyPork |
||||||
|
* @param <MESSAGE> message type |
||||||
|
* @param <CLIENT> client (subscriber) type |
||||||
|
*/ |
||||||
|
public final class MessageChannel<MESSAGE extends Handleable<CLIENT>, CLIENT> implements Subscribable { |
||||||
|
|
||||||
|
private Set<CLIENT> clients = new HashSet<CLIENT>(); |
||||||
|
|
||||||
|
private Class<CLIENT> clientClass; |
||||||
|
private Class<MESSAGE> messageClass; |
||||||
|
|
||||||
|
|
||||||
|
public MessageChannel(Class<MESSAGE> messageClass, Class<CLIENT> clientClass) { |
||||||
|
|
||||||
|
if(messageClass == null || clientClass == null) throw new IllegalArgumentException("Null Message or Client class."); |
||||||
|
|
||||||
|
this.clientClass = clientClass; |
||||||
|
this.messageClass = messageClass; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean addSubscriber(Object client) |
||||||
|
{ |
||||||
|
if (!canSubscribe(client)) return false; |
||||||
|
|
||||||
|
clients.add(clientClass.cast(client)); |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
@Override |
||||||
|
public void removeSubscriber(Object client) |
||||||
|
{ |
||||||
|
clients.remove(client); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Try to broadcast a message.<br> |
||||||
|
* If message is of wrong type, <code>false</code> is returned. |
||||||
|
* |
||||||
|
* @param message a message to send |
||||||
|
* @return true if message was sent |
||||||
|
*/ |
||||||
|
public boolean broadcast(Object message) |
||||||
|
{ |
||||||
|
|
||||||
|
if (!canBroadcast(message)) return false; |
||||||
|
|
||||||
|
MESSAGE evt = messageClass.cast(message); |
||||||
|
|
||||||
|
for (CLIENT client : clients) { |
||||||
|
sendTo(client, evt); |
||||||
|
} |
||||||
|
|
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Send a message to a client |
||||||
|
* |
||||||
|
* @param client target client |
||||||
|
* @param message message to send |
||||||
|
*/ |
||||||
|
private void sendTo(CLIENT client, MESSAGE message) |
||||||
|
{ |
||||||
|
((Handleable<CLIENT>) message).handleBy(client); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Check if the given message can be broadcasted by this |
||||||
|
* {@link MessageChannel} |
||||||
|
* |
||||||
|
* @param maybeMessage event object |
||||||
|
* @return can be broadcasted |
||||||
|
*/ |
||||||
|
private boolean canBroadcast(Object maybeMessage) |
||||||
|
{ |
||||||
|
return messageClass.isInstance(maybeMessage); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Check if a client can subscribe to this {@link MessageChannel} |
||||||
|
* |
||||||
|
* @param maybeClient client asking for subscription |
||||||
|
* @return can subscribe |
||||||
|
*/ |
||||||
|
public boolean canSubscribe(Object maybeClient) |
||||||
|
{ |
||||||
|
return clientClass.isInstance(maybeClient); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
@Override |
||||||
|
public int hashCode() |
||||||
|
{ |
||||||
|
final int prime = 31; |
||||||
|
int result = 1; |
||||||
|
result = prime * result + clientClass.getName().hashCode(); |
||||||
|
result = prime * result + messageClass.getName().hashCode(); |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean equals(Object obj) |
||||||
|
{ |
||||||
|
if (this == obj) return true; |
||||||
|
if (obj == null) return false; |
||||||
|
if (!(obj instanceof MessageChannel)) return false; |
||||||
|
|
||||||
|
MessageChannel<?, ?> other = (MessageChannel<?, ?>) obj; |
||||||
|
|
||||||
|
if (!clientClass.getName().equals(other.clientClass.getName())) return false; |
||||||
|
|
||||||
|
if (!messageClass.getName().equals(other.messageClass.getName())) return false; |
||||||
|
|
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public String toString() |
||||||
|
{ |
||||||
|
return "CHANNEL( "+messageClass.getSimpleName()+" -> "+clientClass.getSimpleName()+" )"; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Create an instance for given types |
||||||
|
* |
||||||
|
* @param messageClass event class
|
||||||
|
* @param clientClass client class
|
||||||
|
* @return the broadcaster |
||||||
|
*/ |
||||||
|
public static <F_MESSAGE extends Handleable<F_CLIENT>, F_CLIENT> MessageChannel<F_MESSAGE, F_CLIENT> create(Class<F_MESSAGE> messageClass, Class<F_CLIENT> clientClass) |
||||||
|
{ |
||||||
|
return new MessageChannel<F_MESSAGE, F_CLIENT>(messageClass, clientClass); |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,26 @@ |
|||||||
|
package mightypork.utils.patterns.subscription; |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Subscribable object |
||||||
|
* |
||||||
|
* @author MightyPork |
||||||
|
*/ |
||||||
|
public interface Subscribable { |
||||||
|
|
||||||
|
/** |
||||||
|
* Subscribe a client to messages from this object |
||||||
|
* |
||||||
|
* @param client a subscribing client |
||||||
|
* @return true if client is now subscribed |
||||||
|
*/ |
||||||
|
public boolean addSubscriber(Object client); |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Unsubscribe a client from from this object |
||||||
|
* |
||||||
|
* @param client a clientto unsubscribe |
||||||
|
*/ |
||||||
|
public void removeSubscriber(Object client); |
||||||
|
} |
@ -0,0 +1,50 @@ |
|||||||
|
package mightypork.utils.time; |
||||||
|
|
||||||
|
|
||||||
|
import mightypork.utils.math.Calc; |
||||||
|
import mightypork.utils.math.Calc.Rad; |
||||||
|
import mightypork.utils.math.easing.Easing; |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Radians animator |
||||||
|
* |
||||||
|
* @author MightyPork |
||||||
|
*/ |
||||||
|
public class AnimDoubleRad extends AnimDouble { |
||||||
|
|
||||||
|
public AnimDoubleRad(AnimDouble other) { |
||||||
|
super(other); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
public AnimDoubleRad(double value) { |
||||||
|
super(value); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
public AnimDoubleRad(double value, Easing easing) { |
||||||
|
super(value, easing); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
@Override |
||||||
|
public double getCurrentValue() |
||||||
|
{ |
||||||
|
if (duration == 0) return Rad.norm(to); |
||||||
|
return Calc.interpolateRad(from, to, (elapsedTime / duration), easing); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
@Override |
||||||
|
protected double getProgressFromValue(double value) |
||||||
|
{ |
||||||
|
double whole = Rad.diff(from, to); |
||||||
|
if (Rad.diff(value, from) < whole && Rad.diff(value, to) < whole) { |
||||||
|
double partial = Rad.diff(from, value); |
||||||
|
return partial / whole; |
||||||
|
} |
||||||
|
|
||||||
|
return 0; |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue