Fixed some javadoc

master
Ondřej Hruška 10 years ago
parent 6208a0c2eb
commit abd5bec682
  1. 68
      src/junk/AppInitOptions.java
  2. 86
      src/junk/BaseApp.java
  3. 124
      src/junk/DisplaySystem.java
  4. 266
      src/junk/Render.java
  5. 104
      src/junk/SoundSystem.java
  6. 106
      src/mightypork/gamecore/audio/AudioModule.java
  7. 18
      src/mightypork/gamecore/audio/DeferredAudio.java
  8. 52
      src/mightypork/gamecore/audio/IAudio.java
  9. 20
      src/mightypork/gamecore/audio/JointVolume.java
  10. 28
      src/mightypork/gamecore/audio/SoundRegistry.java
  11. 10
      src/mightypork/gamecore/audio/Volume.java
  12. 50
      src/mightypork/gamecore/audio/players/BaseAudioPlayer.java
  13. 28
      src/mightypork/gamecore/audio/players/EffectPlayer.java
  14. 100
      src/mightypork/gamecore/audio/players/LoopPlayer.java
  15. 52
      src/mightypork/gamecore/core/App.java
  16. 13
      src/mightypork/gamecore/core/AppBackend.java
  17. 18
      src/mightypork/gamecore/core/AppPlugin.java
  18. 14
      src/mightypork/gamecore/core/BackendModule.java
  19. 98
      src/mightypork/gamecore/core/InitTask.java
  20. 87
      src/mightypork/gamecore/core/MainLoop.java
  21. 4
      src/mightypork/gamecore/core/OptionalInitTask.java
  22. 91
      src/mightypork/gamecore/core/WorkDir.java
  23. 129
      src/mightypork/gamecore/core/config/Config.java
  24. 34
      src/mightypork/gamecore/core/config/InitTaskConfig.java
  25. 27
      src/mightypork/gamecore/core/config/KeyStrokeProperty.java
  26. 16
      src/mightypork/gamecore/core/events/MainLoopRequest.java
  27. 11
      src/mightypork/gamecore/core/events/ShutdownEvent.java
  28. 6
      src/mightypork/gamecore/core/events/ShutdownListener.java
  29. 12
      src/mightypork/gamecore/core/init/InitTaskCrashHandler.java
  30. 48
      src/mightypork/gamecore/core/init/InitTaskDisplay.java
  31. 28
      src/mightypork/gamecore/core/init/InitTaskIonizables.java
  32. 46
      src/mightypork/gamecore/core/init/InitTaskLog.java
  33. 22
      src/mightypork/gamecore/core/init/InitTaskLogHeader.java
  34. 62
      src/mightypork/gamecore/core/init/InitTaskWorkdir.java
  35. 36
      src/mightypork/gamecore/core/plugins/screenshot/InitTaskPluginScreenshot.java
  36. 6
      src/mightypork/gamecore/core/plugins/screenshot/ScreenshotPlugin.java
  37. 6
      src/mightypork/gamecore/core/plugins/screenshot/ScreenshotRequest.java
  38. 40
      src/mightypork/gamecore/core/plugins/screenshot/TaskTakeScreenshot.java
  39. 6
      src/mightypork/gamecore/graphics/FullscreenToggleRequest.java
  40. 287
      src/mightypork/gamecore/graphics/GraphicsModule.java
  41. 6
      src/mightypork/gamecore/graphics/Renderable.java
  42. 6
      src/mightypork/gamecore/graphics/Screenshot.java
  43. 93
      src/mightypork/gamecore/graphics/fonts/DeferredFont.java
  44. 42
      src/mightypork/gamecore/graphics/fonts/FontRegistry.java
  45. 102
      src/mightypork/gamecore/graphics/fonts/FontRenderer.java
  46. 29
      src/mightypork/gamecore/graphics/fonts/Glyphs.java
  47. 42
      src/mightypork/gamecore/graphics/fonts/IFont.java
  48. 4
      src/mightypork/gamecore/graphics/textures/DeferredTexture.java
  49. 7
      src/mightypork/gamecore/graphics/textures/FilterMode.java
  50. 34
      src/mightypork/gamecore/graphics/textures/ITexture.java
  51. 16
      src/mightypork/gamecore/graphics/textures/QuadGrid.java
  52. 78
      src/mightypork/gamecore/graphics/textures/TextureRegistry.java
  53. 24
      src/mightypork/gamecore/graphics/textures/TxQuad.java
  54. 22
      src/mightypork/gamecore/graphics/textures/TxSheet.java
  55. 10
      src/mightypork/gamecore/graphics/textures/WrapMode.java
  56. 6
      src/mightypork/gamecore/gui/Action.java
  57. 26
      src/mightypork/gamecore/gui/ActionGroup.java
  58. 8
      src/mightypork/gamecore/gui/HasAction.java
  59. 88
      src/mightypork/gamecore/gui/components/BaseComponent.java
  60. 52
      src/mightypork/gamecore/gui/components/Component.java
  61. 14
      src/mightypork/gamecore/gui/components/DynamicWidthComponent.java
  62. 10
      src/mightypork/gamecore/gui/components/InputComponent.java
  63. 72
      src/mightypork/gamecore/gui/components/LayoutComponent.java
  64. 55
      src/mightypork/gamecore/gui/components/LinearComponent.java
  65. 14
      src/mightypork/gamecore/gui/components/PluggableRenderable.java
  66. 26
      src/mightypork/gamecore/gui/components/input/ClickableComponent.java
  67. 30
      src/mightypork/gamecore/gui/components/input/ClickableWrapper.java
  68. 34
      src/mightypork/gamecore/gui/components/input/TextButton.java
  69. 24
      src/mightypork/gamecore/gui/components/layout/ColumnLayout.java
  70. 16
      src/mightypork/gamecore/gui/components/layout/ConstraintLayout.java
  71. 36
      src/mightypork/gamecore/gui/components/layout/FlowColumnLayout.java
  72. 34
      src/mightypork/gamecore/gui/components/layout/FlowRowLayout.java
  73. 36
      src/mightypork/gamecore/gui/components/layout/GridLayout.java
  74. 4
      src/mightypork/gamecore/gui/components/layout/NullComponent.java
  75. 24
      src/mightypork/gamecore/gui/components/layout/RowLayout.java
  76. 30
      src/mightypork/gamecore/gui/components/layout/linear/AbstractLinearWrapper.java
  77. 8
      src/mightypork/gamecore/gui/components/layout/linear/LinearGap.java
  78. 38
      src/mightypork/gamecore/gui/components/layout/linear/LinearLayout.java
  79. 16
      src/mightypork/gamecore/gui/components/layout/linear/LinearRectangle.java
  80. 8
      src/mightypork/gamecore/gui/components/layout/linear/LinearSquare.java
  81. 8
      src/mightypork/gamecore/gui/components/layout/linear/LinearWrapper.java
  82. 7
      src/mightypork/gamecore/gui/components/painters/ImagePainter.java
  83. 26
      src/mightypork/gamecore/gui/components/painters/QuadPainter.java
  84. 92
      src/mightypork/gamecore/gui/components/painters/TextPainter.java
  85. 13
      src/mightypork/gamecore/gui/events/LayoutChangeEvent.java
  86. 8
      src/mightypork/gamecore/gui/events/LayoutChangeListener.java
  87. 7
      src/mightypork/gamecore/gui/events/ScreenRequest.java
  88. 4
      src/mightypork/gamecore/gui/events/ScreenRequestListener.java
  89. 16
      src/mightypork/gamecore/gui/events/ViewportChangeEvent.java
  90. 6
      src/mightypork/gamecore/gui/events/ViewportChangeListener.java
  91. 62
      src/mightypork/gamecore/gui/screens/LayeredScreen.java
  92. 126
      src/mightypork/gamecore/gui/screens/Overlay.java
  93. 11
      src/mightypork/gamecore/gui/screens/Screen.java
  94. 20
      src/mightypork/gamecore/gui/screens/ScreenLayer.java
  95. 46
      src/mightypork/gamecore/gui/screens/ScreenRegistry.java
  96. 47
      src/mightypork/gamecore/gui/screens/impl/CrossfadeOverlay.java
  97. 16
      src/mightypork/gamecore/gui/screens/impl/CrossfadeRequest.java
  98. 10
      src/mightypork/gamecore/gui/screens/impl/FadingLayer.java
  99. 12
      src/mightypork/gamecore/gui/screens/impl/LayerColor.java
  100. 56
      src/mightypork/gamecore/input/InputModule.java
  101. Some files were not shown because too many files have changed in this diff Show More

@ -16,88 +16,88 @@ import mightypork.gamecore.resources.loading.ResourceLoader;
* Init options holder class * Init options holder class
*/ */
public class AppInitOptions { public class AppInitOptions {
String logDir = "log"; String logDir = "log";
String logFilePrefix = "runtime"; String logFilePrefix = "runtime";
String screenshotDir = "screenshots"; String screenshotDir = "screenshots";
boolean busLogging = false; boolean busLogging = false;
String configFile = "settings.cfg"; String configFile = "settings.cfg";
String configComment = "Main config file"; String configComment = "Main config file";
final List<ResourceSetup> resourceLists = new ArrayList<>(); final List<ResourceSetup> resourceLists = new ArrayList<>();
final List<KeySetup> keyLists = new ArrayList<>(); final List<KeySetup> keyLists = new ArrayList<>();
final List<ConfigSetup> configLists = new ArrayList<>(); final List<ConfigSetup> configLists = new ArrayList<>();
ResourceLoader resourceLoader = new AsyncResourceLoader(); ResourceLoader resourceLoader = new AsyncResourceLoader();
Level logLevel = Level.ALL; Level logLevel = Level.ALL;
public boolean sigleInstance = true; public boolean sigleInstance = true;
Level logSoutLevel = Level.ALL; Level logSoutLevel = Level.ALL;
public void setConfigFile(String filename, String comment) public void setConfigFile(String filename, String comment)
{ {
configFile = filename; configFile = filename;
configComment = comment; configComment = comment;
} }
public void addConfig(ConfigSetup cfg) public void addConfig(ConfigSetup cfg)
{ {
configLists.add(cfg); configLists.add(cfg);
} }
public void addKeys(KeySetup keys) public void addKeys(KeySetup keys)
{ {
keyLists.add(keys); keyLists.add(keys);
} }
public void addResources(ResourceSetup res) public void addResources(ResourceSetup res)
{ {
resourceLists.add(res); resourceLists.add(res);
} }
public void setBackend(AppBackend backend) public void setBackend(AppBackend backend)
{ {
this.backend = backend; this.backend = backend;
} }
/** /**
* Set whether to run in single instance mode, or allow multiple instances.<br> * Set whether to run in single instance mode, or allow multiple instances.<br>
* Multiple instances running can cause various collisions (eg. when writing * Multiple instances running can cause various collisions (eg. when writing
* config file or logging). * config file or logging).
* *
* @param sigleInstance true to allow only one instance * @param sigleInstance true to allow only one instance
*/ */
public void setSigleInstance(boolean sigleInstance) public void setSigleInstance(boolean sigleInstance)
{ {
this.sigleInstance = sigleInstance; this.sigleInstance = sigleInstance;
} }
/** /**
* Set working directory path. If not exists, it will be created. * Set working directory path. If not exists, it will be created.
* *
* @param workdir work dir path * @param workdir work dir path
*/ */
public void setWorkdir(File workdir) public void setWorkdir(File workdir)
{ {
this.workdir = workdir; this.workdir = workdir;
} }
public void setBusLogging(boolean yes) public void setBusLogging(boolean yes)
{ {
busLogging = yes; busLogging = yes;
} }
public void setLogOptions(String logDir, String filePrefix, int archivedCount, Level logLevel) public void setLogOptions(String logDir, String filePrefix, int archivedCount, Level logLevel)
{ {
this.logDir = logDir; this.logDir = logDir;
@ -105,26 +105,26 @@ public class AppInitOptions {
this.logArchiveCount = archivedCount; this.logArchiveCount = archivedCount;
this.logLevel = logLevel; this.logLevel = logLevel;
} }
public void setResourceLoader(ResourceLoader resLoader) public void setResourceLoader(ResourceLoader resLoader)
{ {
resourceLoader = resLoader; resourceLoader = resLoader;
} }
public void setScreenshotDir(String path) public void setScreenshotDir(String path)
{ {
this.screenshotDir = path; this.screenshotDir = path;
} }
public void setLockFile(String lockFile) public void setLockFile(String lockFile)
{ {
this.lockFile = lockFile; this.lockFile = lockFile;
} }
public void setLogLevel(Level logLevel, Level soutLevel) public void setLogLevel(Level logLevel, Level soutLevel)
{ {
this.logLevel = logLevel; this.logLevel = logLevel;

@ -6,37 +6,37 @@ import java.lang.Thread.UncaughtExceptionHandler;
import mightypork.gamecore.core.App; import mightypork.gamecore.core.App;
import mightypork.gamecore.core.AppBackend; import mightypork.gamecore.core.AppBackend;
import mightypork.gamecore.core.MainLoop; import mightypork.gamecore.core.MainLoop;
import mightypork.gamecore.core.WorkDir;
import mightypork.gamecore.core.config.Config; import mightypork.gamecore.core.config.Config;
import mightypork.gamecore.gui.screens.ScreenRegistry; import mightypork.gamecore.gui.screens.ScreenRegistry;
import mightypork.gamecore.gui.screens.impl.CrossfadeOverlay; import mightypork.gamecore.gui.screens.impl.CrossfadeOverlay;
import mightypork.gamecore.resources.Res; import mightypork.gamecore.resources.Res;
import mightypork.gamecore.resources.ResourceSetup; import mightypork.gamecore.resources.ResourceSetup;
import mightypork.utils.files.WorkDir;
import mightypork.utils.logging.Log; import mightypork.utils.logging.Log;
/** /**
* Basic screen-based game with subsystems.<br> * Basic screen-based game with subsystems.<br>
* This class takes care of the initialization sequence. * This class takes care of the initialization sequence.
* *
* @author Ondřej Hruška (MightyPork) * @author Ondřej Hruška (MightyPork)
*/ */
public abstract class BaseApp extends App implements UncaughtExceptionHandler { public abstract class BaseApp extends App implements UncaughtExceptionHandler {
// modules // modules
private MainLoop gameLoop; private MainLoop gameLoop;
private ScreenRegistry screenRegistry; private ScreenRegistry screenRegistry;
private boolean started = false; private boolean started = false;
private boolean lockObtained = false; private boolean lockObtained = false;
// init opt holder // init opt holder
private final AppInitOptions opt = new AppInitOptions(); private final AppInitOptions opt = new AppInitOptions();
/** /**
* Get init options * Get init options
* *
* @return opt holder * @return opt holder
*/ */
public AppInitOptions getInitOptions() public AppInitOptions getInitOptions()
@ -44,17 +44,17 @@ public abstract class BaseApp extends App implements UncaughtExceptionHandler {
if (started) { if (started) {
throw new IllegalStateException("Cannot alter init options after starting the App."); throw new IllegalStateException("Cannot alter init options after starting the App.");
} }
return opt; return opt;
} }
public BaseApp(AppBackend backend) public BaseApp(AppBackend backend)
{ {
super(backend); super(backend);
} }
/** /**
* Start the application * Start the application
*/ */
@ -62,64 +62,64 @@ public abstract class BaseApp extends App implements UncaughtExceptionHandler {
public final void start() public final void start()
{ {
initialize(); initialize();
Log.i("Starting main loop..."); Log.i("Starting main loop...");
// open first screen !!! // open first screen !!!
started = true; started = true;
gameLoop.start(); gameLoop.start();
} }
/** /**
* Init the app * Init the app
*/ */
protected void initialize() protected void initialize()
{ {
WorkDir.init(opt.workdir); WorkDir.setBaseDir(opt.workdir);
if (opt.sigleInstance) initLock(); if (opt.sigleInstance) initLock();
lockObtained = true; lockObtained = true;
for (final RouteSetup rs : opt.routeLists) { for (final RouteSetup rs : opt.routeLists) {
WorkDir.registerRoutes(rs); WorkDir.registerRoutes(rs);
} }
WorkDir.addPath("_screenshot_dir", opt.screenshotDir); WorkDir.addPath("_screenshot_dir", opt.screenshotDir);
// apply configurations // apply configurations
Config.init(WorkDir.getFile(opt.configFile), opt.configComment); Config.init(WorkDir.getFile(opt.configFile), opt.configComment);
// add keys to config // add keys to config
for (final KeySetup l : opt.keyLists) { for (final KeySetup l : opt.keyLists) {
Config.registerKeys(l); Config.registerKeys(l);
} }
// add options to config // add options to config
for (final ConfigSetup c : opt.configLists) { for (final ConfigSetup c : opt.configLists) {
Config.registerOptions(c); Config.registerOptions(c);
} }
Config.load(); Config.load();
/* /*
* Display * Display
*/ */
Log.f2("Initializing Display System..."); Log.f2("Initializing Display System...");
initDisplay(gfx()); initDisplay(gfx());
/* /*
* Audio * Audio
*/ */
Log.f2("Initializing Sound System..."); Log.f2("Initializing Sound System...");
soundSystem = new SoundSystem(this); soundSystem = new SoundSystem(this);
initSoundSystem(soundSystem); initSoundSystem(soundSystem);
/* /*
* Input * Input
*/ */
Log.f2("Initializing Input System..."); Log.f2("Initializing Input System...");
inputSystem = new LwjglInputModule(this); inputSystem = new LwjglInputModule(this);
initInputSystem(inputSystem); initInputSystem(inputSystem);
/* /*
* Prepare main loop * Prepare main loop
*/ */
@ -127,55 +127,55 @@ public abstract class BaseApp extends App implements UncaughtExceptionHandler {
screenRegistry = new ScreenRegistry(this); screenRegistry = new ScreenRegistry(this);
gameLoop = createMainLoop(); gameLoop = createMainLoop();
gameLoop.setRootRenderable(screenRegistry); gameLoop.setRootRenderable(screenRegistry);
/* /*
* Load resources * Load resources
* *
* Resources should be registered to registries, and AsyncResourceLoader will load them. * Resources should be registered to registries, and AsyncResourceLoader will load them.
*/ */
Log.f1("Loading resources..."); Log.f1("Loading resources...");
if (opt.resourceLoader != null) { if (opt.resourceLoader != null) {
opt.resourceLoader.init(this); opt.resourceLoader.setBaseDir(this);
} }
Res.init(this); Res.setBaseDir(this);
for (final ResourceSetup rl : opt.resourceLists) { for (final ResourceSetup rl : opt.resourceLists) {
Res.load(rl); Res.load(rl);
} }
/* /*
* Screen registry * Screen registry
* *
* Must be after resources, because screens can request them during instantiation. * Must be after resources, because screens can request them during instantiation.
*/ */
Log.f2("Registering screens..."); Log.f2("Registering screens...");
initScreens(screenRegistry); initScreens(screenRegistry);
} }
/** /**
* Register game screens to the registry. * Register game screens to the registry.
* *
* @param screens * @param screens
*/ */
protected void initScreens(ScreenRegistry screens) protected void initScreens(ScreenRegistry screens)
{ {
screens.addOverlay(new CrossfadeOverlay(this)); screens.addOverlay(new CrossfadeOverlay(this));
} }
/** /**
* Create game loop instance * Create game loop instance
* *
* @return the game loop. * @return the game loop.
*/ */
protected MainLoop createMainLoop() protected MainLoop createMainLoop()
{ {
return new MainLoop(this); return new MainLoop(this);
} }
protected void beforeShutdown() protected void beforeShutdown()
{ {
// ??? // ???

@ -24,67 +24,67 @@
// //
///** ///**
// * Display system // * Display system
// * // *
// * @author Ondřej Hruška (MightyPork) // * @author Ondřej Hruška (MightyPork)
// */ // */
//@Deprecated //@Deprecated
//public class DisplaySystem extends AppModule implements RectBound { //public class DisplaySystem extends AppModule implements RectBound {
// //
// private DisplayMode windowDisplayMode; // private DisplayMode windowDisplayMode;
// private int targetFps; // private int targetFps;
// private FpsMeter fpsMeter; // private FpsMeter fpsMeter;
// private boolean fullscreenSwitchRequested; // private boolean fullscreenSwitchRequested;
// //
// /** Current screen size */ // /** Current screen size */
// private static final Vect screenSize = new Vect() { // private static final Vect screenSize = new Vect() {
// //
// @Override // @Override
// public double y() // public double y()
// { // {
// return Display.getHeight(); // return Display.getHeight();
// } // }
// //
// //
// @Override // @Override
// public double x() // public double x()
// { // {
// return Display.getWidth(); // return Display.getWidth();
// } // }
// }; // };
// //
// private static final Rect rect = Rect.make(screenSize); // private static final Rect rect = Rect.make(screenSize);
// //
// //
// /** // /**
// * @param app app access // * @param app app access
// */ // */
// public DisplaySystem(AppAccess app) { // public DisplaySystem(AppAccess app) {
// super(app); // super(app);
// } // }
// //
// //
// @Override // @Override
// protected void deinit() // protected void deinit()
// { // {
// Display.destroy(); // Display.destroy();
// } // }
// //
// //
// /** // /**
// * Set target fps (for syncing in endFrame() call).<br> // * Set target fps (for syncing in endFrame() call).<br>
// * With vsync enabled, the target fps may not be met. // * With vsync enabled, the target fps may not be met.
// * // *
// * @param fps requested fps // * @param fps requested fps
// */ // */
// public void setTargetFps(int fps) // public void setTargetFps(int fps)
// { // {
// this.targetFps = fps; // this.targetFps = fps;
// } // }
// //
// //
// /** // /**
// * Create a main window // * Create a main window
// * // *
// * @param width requested width // * @param width requested width
// * @param height requested height // * @param height requested height
// * @param resizable is resizable by the user // * @param resizable is resizable by the user
@ -99,22 +99,22 @@
// Display.setVSyncEnabled(true); // Display.setVSyncEnabled(true);
// Display.setTitle(title); // Display.setTitle(title);
// Display.create(); // Display.create();
// //
// fpsMeter = new FpsMeter(); // fpsMeter = new FpsMeter();
// //
// if (fullscreen) { // if (fullscreen) {
// switchFullscreen(); // switchFullscreen();
// Display.update(); // Display.update();
// } // }
// //
// getEventBus().send(new DisplayReadyEvent()); // getEventBus().send(new DisplayReadyEvent());
// //
// } catch (final LWJGLException e) { // } catch (final LWJGLException e) {
// throw new RuntimeException("Could not initialize screen", e); // throw new RuntimeException("Could not initialize screen", e);
// } // }
// } // }
// //
// //
// /** // /**
// * Toggle FS if possible // * Toggle FS if possible
// */ // */
@ -122,17 +122,17 @@
// { // {
// fullscreenSwitchRequested = true; // fullscreenSwitchRequested = true;
// } // }
// //
// //
// private void doSwitchFullscreen() // private void doSwitchFullscreen()
// { // {
// try { // try {
// //
// if (!Display.isFullscreen()) { // if (!Display.isFullscreen()) {
// Log.f3("Entering fullscreen."); // Log.f3("Entering fullscreen.");
// // save window resize // // save window resize
// windowDisplayMode = new DisplayMode(Display.getWidth(), Display.getHeight()); // windowDisplayMode = new DisplayMode(Display.getWidth(), Display.getHeight());
// //
// Display.setDisplayMode(Display.getDesktopDisplayMode()); // Display.setDisplayMode(Display.getDesktopDisplayMode());
// Display.setFullscreen(true); // Display.setFullscreen(true);
// Display.update(); // Display.update();
@ -141,9 +141,9 @@
// Display.setDisplayMode(windowDisplayMode); // Display.setDisplayMode(windowDisplayMode);
// Display.update(); // Display.update();
// } // }
// //
// getEventBus().send(new ViewportChangeEvent(getSize())); // getEventBus().send(new ViewportChangeEvent(getSize()));
// //
// } catch (final Throwable t) { // } catch (final Throwable t) {
// Log.e("Failed to toggle fullscreen mode.", t); // Log.e("Failed to toggle fullscreen mode.", t);
// try { // try {
@ -154,12 +154,12 @@
// } // }
// } // }
// } // }
// //
// //
// /** // /**
// * Take screenshot (expensive processing is done on-demand when screenshot // * Take screenshot (expensive processing is done on-demand when screenshot
// * is processed). // * is processed).
// * // *
// * @return screenshot object // * @return screenshot object
// */ // */
// public static AwtScreenshot prepareScreenshot() // public static AwtScreenshot prepareScreenshot()
@ -170,13 +170,13 @@
// final int bpp = 4; // final int bpp = 4;
// final ByteBuffer buffer = BufferUtils.createByteBuffer(width * height * bpp); // final ByteBuffer buffer = BufferUtils.createByteBuffer(width * height * bpp);
// glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, buffer); // glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
// //
// final AwtScreenshot sc = new AwtScreenshot(width, height, bpp, buffer); // final AwtScreenshot sc = new AwtScreenshot(width, height, bpp, buffer);
// //
// return sc; // return sc;
// } // }
// //
// //
// /** // /**
// * @return true if close was requested (i.e. click on cross) // * @return true if close was requested (i.e. click on cross)
// */ // */
@ -184,41 +184,41 @@
// { // {
// return Display.isCloseRequested(); // return Display.isCloseRequested();
// } // }
// //
// //
// /** // /**
// * Get fullscreen state // * Get fullscreen state
// * // *
// * @return is fullscreen // * @return is fullscreen
// */ // */
// public static boolean isFullscreen() // public static boolean isFullscreen()
// { // {
// return Display.isFullscreen(); // return Display.isFullscreen();
// } // }
// //
// //
// /** // /**
// * Get screen size. This Vect is final and views at it can safely be made. // * Get screen size. This Vect is final and views at it can safely be made.
// * // *
// * @return size // * @return size
// */ // */
// public static Vect getSize() // public static Vect getSize()
// { // {
// return screenSize; // return screenSize;
// } // }
// //
// //
// /** // /**
// * Get screen rect. Static version of getRect(). // * Get screen rect. Static version of getRect().
// * // *
// * @return size // * @return size
// */ // */
// public static Rect getBounds() // public static Rect getBounds()
// { // {
// return rect; // return rect;
// } // }
// //
// //
// /** // /**
// * @return screen width // * @return screen width
// */ // */
@ -226,8 +226,8 @@
// { // {
// return screenSize.xi(); // return screenSize.xi();
// } // }
// //
// //
// /** // /**
// * @return screen height // * @return screen height
// */ // */
@ -235,8 +235,8 @@
// { // {
// return screenSize.yi(); // return screenSize.yi();
// } // }
// //
// //
// /** // /**
// * Start a OpenGL frame // * Start a OpenGL frame
// */ // */
@ -246,18 +246,18 @@
// if (Display.wasResized()) { // if (Display.wasResized()) {
// getEventBus().send(new ViewportChangeEvent(getSize())); // getEventBus().send(new ViewportChangeEvent(getSize()));
// } // }
// //
// if (fullscreenSwitchRequested) { // if (fullscreenSwitchRequested) {
// fullscreenSwitchRequested = false; // fullscreenSwitchRequested = false;
// doSwitchFullscreen(); // doSwitchFullscreen();
// } // }
// //
// glLoadIdentity(); // glLoadIdentity();
// glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// fpsMeter.frame(); // fpsMeter.frame();
// } // }
// //
// //
// /** // /**
// * End an OpenGL frame, flip buffers, sync to fps. // * End an OpenGL frame, flip buffers, sync to fps.
// */ // */
@ -266,8 +266,8 @@
// Display.update(false); // don't poll input devices // Display.update(false); // don't poll input devices
// Display.sync(targetFps); // Display.sync(targetFps);
// } // }
// //
// //
// /** // /**
// * Get screen rect. This Rect is final and views at it can safely be made. // * Get screen rect. This Rect is final and views at it can safely be made.
// */ // */
@ -276,8 +276,8 @@
// { // {
// return getBounds(); // return getBounds();
// } // }
// //
// //
// /** // /**
// * @return current FPS // * @return current FPS
// */ // */
@ -285,11 +285,11 @@
// { // {
// return fpsMeter.getFPS(); // return fpsMeter.getFPS();
// } // }
// //
// //
// /** // /**
// * Get screen center. This vect is final and views at it can safely be made. // * Get screen center. This vect is final and views at it can safely be made.
// * // *
// * @return screen center. // * @return screen center.
// */ // */
// public static Vect getCenter() // public static Vect getCenter()

@ -24,31 +24,31 @@
// //
///** ///**
// * Render utilities // * Render utilities
// * // *
// * @author Ondřej Hruška (MightyPork) // * @author Ondřej Hruška (MightyPork)
// */ // */
//@Deprecated //@Deprecated
//public class Render { //public class Render {
// //
// public static final VectConst AXIS_X = Vect.make(1, 0, 0); // public static final VectConst AXIS_X = Vect.make(1, 0, 0);
// public static final VectConst AXIS_Y = Vect.make(0, 1, 0); // public static final VectConst AXIS_Y = Vect.make(0, 1, 0);
// public static final VectConst AXIS_Z = Vect.make(0, 0, 1); // public static final VectConst AXIS_Z = Vect.make(0, 0, 1);
// //
// //
// /** // /**
// * Bind GL color // * Bind GL color
// * // *
// * @param color Color color // * @param color Color color
// */ // */
// public static void setColor(Color color) // public static void setColor(Color color)
// { // {
// if (color != null) glColor4d(color.r(), color.g(), color.b(), color.a()); // if (color != null) glColor4d(color.r(), color.g(), color.b(), color.a());
// } // }
// //
// //
// /** // /**
// * Bind GL color // * Bind GL color
// * // *
// * @param color Color color // * @param color Color color
// * @param alpha alpha multiplier // * @param alpha alpha multiplier
// */ // */
@ -56,11 +56,11 @@
// { // {
// if (color != null) glColor4d(color.r(), color.g(), color.b(), color.a() * alpha); // if (color != null) glColor4d(color.r(), color.g(), color.b(), color.a() * alpha);
// } // }
// //
// //
// /** // /**
// * Translate // * Translate
// * // *
// * @param x // * @param x
// * @param y // * @param y
// */ // */
@ -68,11 +68,11 @@
// { // {
// glTranslated(x, y, 0); // glTranslated(x, y, 0);
// } // }
// //
// //
// /** // /**
// * Translate // * Translate
// * // *
// * @param x // * @param x
// * @param y // * @param y
// * @param z // * @param z
@ -81,33 +81,33 @@
// { // {
// glTranslated(x, y, z); // glTranslated(x, y, z);
// } // }
// //
// //
// /** // /**
// * Translate with coord // * Translate with coord
// * // *
// * @param coord coord // * @param coord coord
// */ // */
// public static void translate(Vect coord) // public static void translate(Vect coord)
// { // {
// glTranslated(coord.x(), coord.y(), coord.z()); // glTranslated(coord.x(), coord.y(), coord.z());
// } // }
// //
// //
// /** // /**
// * Translate with coord, discard Z // * Translate with coord, discard Z
// * // *
// * @param coord coord // * @param coord coord
// */ // */
// public static void translateXY(Vect coord) // public static void translateXY(Vect coord)
// { // {
// glTranslated(coord.x(), coord.y(), 0); // glTranslated(coord.x(), coord.y(), 0);
// } // }
// //
// //
// /** // /**
// * Scale // * Scale
// * // *
// * @param x // * @param x
// * @param y // * @param y
// */ // */
@ -115,11 +115,11 @@
// { // {
// glScaled(x, y, 0); // glScaled(x, y, 0);
// } // }
// //
// //
// /** // /**
// * Scale // * Scale
// * // *
// * @param x // * @param x
// * @param y // * @param y
// * @param z // * @param z
@ -128,99 +128,99 @@
// { // {
// glScaled(x, y, z); // glScaled(x, y, z);
// } // }
// //
// //
// /** // /**
// * Scale // * Scale
// * // *
// * @param factor vector of scaling factors // * @param factor vector of scaling factors
// */ // */
// public static void scale(Vect factor) // public static void scale(Vect factor)
// { // {
// glScaled(factor.x(), factor.y(), factor.z()); // glScaled(factor.x(), factor.y(), factor.z());
// } // }
// //
// //
// /** // /**
// * Scale by X factor // * Scale by X factor
// * // *
// * @param factor scaling factor // * @param factor scaling factor
// */ // */
// public static void scaleXY(double factor) // public static void scaleXY(double factor)
// { // {
// glScaled(factor, factor, 1); // glScaled(factor, factor, 1);
// } // }
// //
// //
// /** // /**
// * Scale by X factor // * Scale by X factor
// * // *
// * @param factor scaling factor // * @param factor scaling factor
// */ // */
// public static void scaleX(double factor) // public static void scaleX(double factor)
// { // {
// glScaled(factor, 1, 1); // glScaled(factor, 1, 1);
// } // }
// //
// //
// /** // /**
// * Scale by Y factor // * Scale by Y factor
// * // *
// * @param factor scaling factor // * @param factor scaling factor
// */ // */
// public static void scaleY(double factor) // public static void scaleY(double factor)
// { // {
// glScaled(1, factor, 1); // glScaled(1, factor, 1);
// } // }
// //
// //
// /** // /**
// * Scale by Z factor // * Scale by Z factor
// * // *
// * @param factor scaling factor // * @param factor scaling factor
// */ // */
// public static void scaleZ(double factor) // public static void scaleZ(double factor)
// { // {
// glScaled(1, 1, factor); // glScaled(1, 1, factor);
// } // }
// //
// //
// /** // /**
// * Rotate around X axis // * Rotate around X axis
// * // *
// * @param angle deg // * @param angle deg
// */ // */
// public static void rotateX(double angle) // public static void rotateX(double angle)
// { // {
// rotate(angle, AXIS_X); // rotate(angle, AXIS_X);
// } // }
// //
// //
// /** // /**
// * Rotate around Y axis // * Rotate around Y axis
// * // *
// * @param angle deg // * @param angle deg
// */ // */
// public static void rotateY(double angle) // public static void rotateY(double angle)
// { // {
// rotate(angle, AXIS_Y); // rotate(angle, AXIS_Y);
// } // }
// //
// //
// /** // /**
// * Rotate around Z axis // * Rotate around Z axis
// * // *
// * @param angle deg // * @param angle deg
// */ // */
// public static void rotateZ(double angle) // public static void rotateZ(double angle)
// { // {
// rotate(angle, AXIS_Z); // rotate(angle, AXIS_Z);
// } // }
// //
// //
// /** // /**
// * Rotate // * Rotate
// * // *
// * @param angle rotate angle // * @param angle rotate angle
// * @param axis rotation axis // * @param axis rotation axis
// */ // */
@ -229,23 +229,23 @@
// final Vect vec = axis.norm(1); // final Vect vec = axis.norm(1);
// glRotated(angle, vec.x(), vec.y(), vec.z()); // glRotated(angle, vec.x(), vec.y(), vec.z());
// } // }
// //
// private static int pushed = 0; // private static int pushed = 0;
// /** Can be used to avoid texture binding and glBegin/glEnd in textured quads */ // /** Can be used to avoid texture binding and glBegin/glEnd in textured quads */
// public static boolean batchTexturedQuadMode; // public static boolean batchTexturedQuadMode;
// //
// //
// /** // /**
// * Store GL state // * Store GL state
// */ // */
// public static void pushState() // public static void pushState()
// { // {
// pushed++; // pushed++;
// //
// if (pushed >= 100) { // if (pushed >= 100) {
// Log.w("Suspicious number of state pushes: " + pushed); // Log.w("Suspicious number of state pushes: " + pushed);
// } // }
// //
// GL11.glPushAttrib(GL11.GL_ALL_ATTRIB_BITS); // GL11.glPushAttrib(GL11.GL_ALL_ATTRIB_BITS);
// GL11.glPushClientAttrib(GL11.GL_ALL_CLIENT_ATTRIB_BITS); // GL11.glPushClientAttrib(GL11.GL_ALL_CLIENT_ATTRIB_BITS);
// GL11.glMatrixMode(GL11.GL_MODELVIEW); // GL11.glMatrixMode(GL11.GL_MODELVIEW);
@ -254,8 +254,8 @@
// GL11.glPushMatrix(); // GL11.glPushMatrix();
// GL11.glMatrixMode(GL11.GL_MODELVIEW); // GL11.glMatrixMode(GL11.GL_MODELVIEW);
// } // }
// //
// //
// /** // /**
// * Restore Gl state // * Restore Gl state
// */ // */
@ -264,9 +264,9 @@
// if (pushed == 0) { // if (pushed == 0) {
// Log.w("Pop without push."); // Log.w("Pop without push.");
// } // }
// //
// pushed--; // pushed--;
// //
// GL11.glMatrixMode(GL11.GL_PROJECTION); // GL11.glMatrixMode(GL11.GL_PROJECTION);
// GL11.glPopMatrix(); // GL11.glPopMatrix();
// GL11.glMatrixMode(GL11.GL_MODELVIEW); // GL11.glMatrixMode(GL11.GL_MODELVIEW);
@ -274,8 +274,8 @@
// GL11.glPopClientAttrib(); // GL11.glPopClientAttrib();
// GL11.glPopAttrib(); // GL11.glPopAttrib();
// } // }
// //
// //
// /** // /**
// * Store matrix // * Store matrix
// */ // */
@ -283,8 +283,8 @@
// { // {
// GL11.glPushMatrix(); // GL11.glPushMatrix();
// } // }
// //
// //
// /** // /**
// * Restore Gl state // * Restore Gl state
// */ // */
@ -292,41 +292,41 @@
// { // {
// GL11.glPopMatrix(); // GL11.glPopMatrix();
// } // }
// //
// //
// /** // /**
// * Load texture // * Load texture
// * // *
// * @param resourcePath // * @param resourcePath
// * @param filtering filtering mode to use while loading. // * @param filtering filtering mode to use while loading.
// * @return the loaded texture // * @return the loaded texture
// */ // */
// public synchronized static Texture loadSlickTexture(String resourcePath, FilterMode filtering) // public synchronized static Texture loadSlickTexture(String resourcePath, FilterMode filtering)
// { // {
// //
// try { // try {
// //
// final String ext = FileUtils.getExtension(resourcePath).toUpperCase(); // final String ext = FileUtils.getExtension(resourcePath).toUpperCase();
// //
// final Texture texture = TextureLoader.getTexture(ext, FileUtils.getResource(resourcePath), false, filtering.num); // final Texture texture = TextureLoader.getTexture(ext, FileUtils.getResource(resourcePath), false, filtering.num);
// //
// if (texture == null) { // if (texture == null) {
// Log.w("Texture " + resourcePath + " could not be loaded."); // Log.w("Texture " + resourcePath + " could not be loaded.");
// } // }
// //
// return texture; // return texture;
// //
// } catch (final IOException e) { // } catch (final IOException e) {
// Log.e("Loading of texture " + resourcePath + " failed.", e); // Log.e("Loading of texture " + resourcePath + " failed.", e);
// throw new RuntimeException("Could not load texture " + resourcePath + ".", e); // throw new RuntimeException("Could not load texture " + resourcePath + ".", e);
// } // }
// //
// } // }
// //
// //
// /** // /**
// * Render quad 2D // * Render quad 2D
// * // *
// * @param rect rectangle // * @param rect rectangle
// * @param color draw color // * @param color draw color
// */ // */
@ -335,21 +335,21 @@
// setColor(color); // setColor(color);
// quad(rect); // quad(rect);
// } // }
// //
// //
// /** // /**
// * Render quad // * Render quad
// * // *
// * @param quad the quad to draw (px) // * @param quad the quad to draw (px)
// */ // */
// public static void quad(Rect quad) // public static void quad(Rect quad)
// { // {
// final RectDigest q = quad.digest(); // final RectDigest q = quad.digest();
// //
// // draw with color // // draw with color
// //
// glDisable(GL_TEXTURE_2D); // glDisable(GL_TEXTURE_2D);
// //
// // quad // // quad
// glBegin(GL_QUADS); // glBegin(GL_QUADS);
// glVertex2d(q.left, q.bottom); // glVertex2d(q.left, q.bottom);
@ -358,11 +358,11 @@
// glVertex2d(q.left, q.top); // glVertex2d(q.left, q.top);
// glEnd(); // glEnd();
// } // }
// //
// //
// /** // /**
// * Draw quad with horizontal gradient // * Draw quad with horizontal gradient
// * // *
// * @param quad drawn quad bounds // * @param quad drawn quad bounds
// * @param color1 left color // * @param color1 left color
// * @param color2 right color // * @param color2 right color
@ -371,17 +371,17 @@
// { // {
// quadColor(quad, color1, color2, color2, color1); // quadColor(quad, color1, color2, color2, color1);
// } // }
// //
// //
// public static void quadColor(Rect quad, Color color) // public static void quadColor(Rect quad, Color color)
// { // {
// quadColor(quad, color, color, color, color); // quadColor(quad, color, color, color, color);
// } // }
// //
// //
// /** // /**
// * Draw quad with coloured vertices. // * Draw quad with coloured vertices.
// * // *
// * @param quad drawn quad bounds // * @param quad drawn quad bounds
// * @param colorHMinVMin // * @param colorHMinVMin
// * @param colorHMaxVMin // * @param colorHMaxVMin
@ -391,30 +391,30 @@
// public static void quadColor(Rect quad, Color colorHMinVMin, Color colorHMaxVMin, Color colorHMaxVMax, Color colorHMinVMax) // public static void quadColor(Rect quad, Color colorHMinVMin, Color colorHMaxVMin, Color colorHMaxVMax, Color colorHMinVMax)
// { // {
// final RectDigest r = quad.digest(); // final RectDigest r = quad.digest();
// //
// // draw with color // // draw with color
// //
// glDisable(GL_TEXTURE_2D); // glDisable(GL_TEXTURE_2D);
// //
// glBegin(GL_QUADS); // glBegin(GL_QUADS);
// setColor(colorHMinVMax); // setColor(colorHMinVMax);
// glVertex2d(r.left, r.bottom); // glVertex2d(r.left, r.bottom);
// //
// setColor(colorHMaxVMax); // setColor(colorHMaxVMax);
// glVertex2d(r.right, r.bottom); // glVertex2d(r.right, r.bottom);
// //
// setColor(colorHMaxVMin); // setColor(colorHMaxVMin);
// glVertex2d(r.right, r.top); // glVertex2d(r.right, r.top);
// //
// setColor(colorHMinVMin); // setColor(colorHMinVMin);
// glVertex2d(r.left, r.top); // glVertex2d(r.left, r.top);
// glEnd(); // glEnd();
// } // }
// //
// //
// /** // /**
// * Draw quad with vertical gradient // * Draw quad with vertical gradient
// * // *
// * @param quad drawn quad bounds // * @param quad drawn quad bounds
// * @param color1 top color // * @param color1 top color
// * @param color2 bottom color // * @param color2 bottom color
@ -423,11 +423,11 @@
// { // {
// quadColor(quad, color1, color1, color2, color2); // quadColor(quad, color1, color1, color2, color2);
// } // }
// //
// //
// /** // /**
// * Render textured rect // * Render textured rect
// * // *
// * @param quad rectangle (px) // * @param quad rectangle (px)
// * @param txquad texture quad // * @param txquad texture quad
// */ // */
@ -435,11 +435,11 @@
// { // {
// quadTextured(quad, txquad, RGB.WHITE); // quadTextured(quad, txquad, RGB.WHITE);
// } // }
// //
// //
// /** // /**
// * Render textured rect // * Render textured rect
// * // *
// * @param quad rectangle (px) // * @param quad rectangle (px)
// * @param txquad texture instance // * @param txquad texture instance
// * @param tint color tint // * @param tint color tint
@ -452,50 +452,50 @@
// glBegin(GL_QUADS); // glBegin(GL_QUADS);
// setColor(tint); // setColor(tint);
// } // }
// //
// final RectDigest q = quad.digest(); // final RectDigest q = quad.digest();
// final RectDigest u = txquad.uvs.digest(); // final RectDigest u = txquad.uvs.digest();
// //
// final double offs = 0.0001;// hack to avoid white stitching // final double offs = 0.0001;// hack to avoid white stitching
// //
// double tL = u.left + offs, tR = u.right - offs, tT = u.top + offs, tB = u.bottom - offs; // double tL = u.left + offs, tR = u.right - offs, tT = u.top + offs, tB = u.bottom - offs;
// //
// // handle flip // // handle flip
// if (txquad.isFlippedY()) { // if (txquad.isFlippedY()) {
// final double swap = tT; // final double swap = tT;
// tT = tB; // tT = tB;
// tB = swap; // tB = swap;
// } // }
// //
// if (txquad.isFlippedX()) { // if (txquad.isFlippedX()) {
// final double swap = tL; // final double swap = tL;
// tL = tR; // tL = tR;
// tR = swap; // tR = swap;
// } // }
// //
// final double w = txquad.tx.getWidth01(); // final double w = txquad.tx.getWidth01();
// final double h = txquad.tx.getHeight01(); // final double h = txquad.tx.getHeight01();
// //
// // quad with texture // // quad with texture
// glTexCoord2d(tL * w, tB * h); // glTexCoord2d(tL * w, tB * h);
// glVertex2d(q.left, q.bottom); // glVertex2d(q.left, q.bottom);
// //
// glTexCoord2d(tR * w, tB * h); // glTexCoord2d(tR * w, tB * h);
// glVertex2d(q.right, q.bottom); // glVertex2d(q.right, q.bottom);
// //
// glTexCoord2d(tR * w, tT * h); // glTexCoord2d(tR * w, tT * h);
// glVertex2d(q.right, q.top); // glVertex2d(q.right, q.top);
// //
// glTexCoord2d(tL * w, tT * h); // glTexCoord2d(tL * w, tT * h);
// glVertex2d(q.left, q.top); // glVertex2d(q.left, q.top);
// //
// if (!batchTexturedQuadMode) glEnd(); // if (!batchTexturedQuadMode) glEnd();
// } // }
// //
// //
// /** // /**
// * Setup Ortho projection for 2D graphics // * Setup Ortho projection for 2D graphics
// * // *
// * @param size viewport size (screen size) // * @param size viewport size (screen size)
// */ // */
// public static void setupOrtho(Vect size) // public static void setupOrtho(Vect size)
@ -505,35 +505,35 @@
// glLoadIdentity(); // glLoadIdentity();
// glViewport(0, 0, size.xi(), size.yi()); // glViewport(0, 0, size.xi(), size.yi());
// glOrtho(0, size.xi(), size.yi(), 0, -1000, 1000); // glOrtho(0, size.xi(), size.yi(), 0, -1000, 1000);
// //
// // back to modelview // // back to modelview
// glMatrixMode(GL_MODELVIEW); // glMatrixMode(GL_MODELVIEW);
// //
// glLoadIdentity(); // glLoadIdentity();
// //
// glDisable(GL_LIGHTING); // glDisable(GL_LIGHTING);
// //
// glClearDepth(1f); // glClearDepth(1f);
// glEnable(GL_DEPTH_TEST); // glEnable(GL_DEPTH_TEST);
// glDepthFunc(GL_LEQUAL); // glDepthFunc(GL_LEQUAL);
// //
// glEnable(GL_NORMALIZE); // glEnable(GL_NORMALIZE);
// //
// glShadeModel(GL_SMOOTH); // glShadeModel(GL_SMOOTH);
// //
// glEnable(GL_BLEND); // glEnable(GL_BLEND);
// glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
// } // }
// //
// //
// public static void enterBatchTexturedQuadMode(ITexture texture) // public static void enterBatchTexturedQuadMode(ITexture texture)
// { // {
// texture.bind(); // texture.bind();
// glBegin(GL11.GL_QUADS); // glBegin(GL11.GL_QUADS);
// batchTexturedQuadMode = true; // batchTexturedQuadMode = true;
// } // }
// //
// //
// public static void leaveBatchTexturedQuadMode() // public static void leaveBatchTexturedQuadMode()
// { // {
// glEnd(); // glEnd();

@ -28,22 +28,22 @@ package junk;
// //
///** ///**
// * Sound system class (only one instance should be made per application) // * Sound system class (only one instance should be made per application)
// * // *
// * @author Ondřej Hruška (MightyPork) // * @author Ondřej Hruška (MightyPork)
// */ // */
//@Deprecated //@Deprecated
//public class SoundSystem extends BusNode implements Updateable, Destroyable { //public class SoundSystem extends BusNode implements Updateable, Destroyable {
// //
// private static final Vect INITIAL_LISTENER_POS = Vect.ZERO; // private static final Vect INITIAL_LISTENER_POS = Vect.ZERO;
// private static final int MAX_SOURCES = 256; // private static final int MAX_SOURCES = 256;
// //
// private static VectVar listener = Vect.makeVar(); // private static VectVar listener = Vect.makeVar();
// private static boolean soundSystemInited = false; // private static boolean soundSystemInited = false;
// //
// //
// /** // /**
// * Set listener pos // * Set listener pos
// * // *
// * @param pos // * @param pos
// */ // */
// public static void setListener(Vect pos) // public static void setListener(Vect pos)
@ -61,8 +61,8 @@ package junk;
// BufferHelper.fill(buf6, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f); // BufferHelper.fill(buf6, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f);
// AL10.alListener(AL10.AL_ORIENTATION, buf6); // AL10.alListener(AL10.AL_ORIENTATION, buf6);
// } // }
// //
// //
// /** // /**
// * @return listener coordinate // * @return listener coordinate
// */ // */
@ -70,50 +70,50 @@ package junk;
// { // {
// return listener; // return listener;
// } // }
// //
// // -- instance -- // // -- instance --
// //
// private final Volume masterVolume = new Volume(1D); // private final Volume masterVolume = new Volume(1D);
// private final Volume effectsVolume = new JointVolume(masterVolume); // private final Volume effectsVolume = new JointVolume(masterVolume);
// private final Volume loopsVolume = new JointVolume(masterVolume); // private final Volume loopsVolume = new JointVolume(masterVolume);
// //
// private final List<LoopPlayer> loopPlayers = new ArrayList<>(); // private final List<LoopPlayer> loopPlayers = new ArrayList<>();
// private final List<DeferredAudio> resources = new ArrayList<>(); // private final List<DeferredAudio> resources = new ArrayList<>();
// //
// //
// /** // /**
// * @param busAccess app access // * @param busAccess app access
// */ // */
// public SoundSystem() { // public SoundSystem() {
// //
// if (!soundSystemInited) { // if (!soundSystemInited) {
// soundSystemInited = true; // soundSystemInited = true;
// //
// try { // try {
// SoundStore.get().setMaxSources(MAX_SOURCES); // SoundStore.get().setMaxSources(MAX_SOURCES);
// SoundStore.get().init(); // SoundStore.get().init();
// setListener(INITIAL_LISTENER_POS); // setListener(INITIAL_LISTENER_POS);
// //
// App.bus().send(new AudioReadyEvent()); // App.bus().send(new AudioReadyEvent());
// } catch (final Throwable t) { // } catch (final Throwable t) {
// Log.e("Error initializing sound system.", t); // Log.e("Error initializing sound system.", t);
// } // }
// } // }
// } // }
// //
// //
// @Override // @Override
// public void destroy() // public void destroy()
// { // {
// for (final DeferredAudio r : resources) { // for (final DeferredAudio r : resources) {
// r.destroy(); // r.destroy();
// } // }
// //
// SoundStore.get().clear(); // SoundStore.get().clear();
// AL.destroy(); // AL.destroy();
// } // }
// //
// //
// @Override // @Override
// public void update(double delta) // public void update(double delta)
// { // {
@ -121,11 +121,11 @@ package junk;
// lp.update(delta); // lp.update(delta);
// } // }
// } // }
// //
// //
// /** // /**
// * Create effect resource // * Create effect resource
// * // *
// * @param resource resource path // * @param resource resource path
// * @param pitch default pitch (1 = unchanged) // * @param pitch default pitch (1 = unchanged)
// * @param gain default gain (0-1) // * @param gain default gain (0-1)
@ -135,11 +135,11 @@ package junk;
// { // {
// return new EffectPlayer(createResource(resource), pitch, gain, effectsVolume); // return new EffectPlayer(createResource(resource), pitch, gain, effectsVolume);
// } // }
// //
// //
// /** // /**
// * Register loop resource (music / effect loop) // * Register loop resource (music / effect loop)
// * // *
// * @param resource resource path // * @param resource resource path
// * @param pitch default pitch (1 = unchanged) // * @param pitch default pitch (1 = unchanged)
// * @param gain default gain (0-1) // * @param gain default gain (0-1)
@ -154,11 +154,11 @@ package junk;
// loopPlayers.add(p); // loopPlayers.add(p);
// return p; // return p;
// } // }
// //
// //
// /** // /**
// * Create {@link DeferredAudio} for a resource // * Create {@link DeferredAudio} for a resource
// * // *
// * @param res a resource name // * @param res a resource name
// * @return the resource // * @return the resource
// * @throws IllegalArgumentException if resource is already registered // * @throws IllegalArgumentException if resource is already registered
@ -170,8 +170,8 @@ package junk;
// resources.add(a); // resources.add(a);
// return a; // return a;
// } // }
// //
// //
// /** // /**
// * Fade out all loops (ie. for screen transitions) // * Fade out all loops (ie. for screen transitions)
// */ // */
@ -181,8 +181,8 @@ package junk;
// p.fadeOut(); // p.fadeOut();
// } // }
// } // }
// //
// //
// /** // /**
// * Pause all loops (leave volume unchanged) // * Pause all loops (leave volume unchanged)
// */ // */
@ -192,66 +192,66 @@ package junk;
// p.pause(); // p.pause();
// } // }
// } // }
// //
// //
// /** // /**
// * Set level of master volume // * Set level of master volume
// * // *
// * @param d level // * @param d level
// */ // */
// public void setMasterVolume(double d) // public void setMasterVolume(double d)
// { // {
// masterVolume.set(d); // masterVolume.set(d);
// } // }
// //
// //
// /** // /**
// * Set level of effects volume // * Set level of effects volume
// * // *
// * @param d level // * @param d level
// */ // */
// public void setEffectsVolume(double d) // public void setEffectsVolume(double d)
// { // {
// effectsVolume.set(d); // effectsVolume.set(d);
// } // }
// //
// //
// /** // /**
// * Set level of music volume // * Set level of music volume
// * // *
// * @param d level // * @param d level
// */ // */
// public void setMusicVolume(double d) // public void setMusicVolume(double d)
// { // {
// loopsVolume.set(d); // loopsVolume.set(d);
// } // }
// //
// //
// /** // /**
// * Get level of master volume // * Get level of master volume
// * // *
// * @return level // * @return level
// */ // */
// public double getMasterVolume() // public double getMasterVolume()
// { // {
// return masterVolume.get(); // return masterVolume.get();
// } // }
// //
// //
// /** // /**
// * Get level of effects volume // * Get level of effects volume
// * // *
// * @return level // * @return level
// */ // */
// public double getEffectsVolume() // public double getEffectsVolume()
// { // {
// return effectsVolume.get(); // return effectsVolume.get();
// } // }
// //
// //
// /** // /**
// * Get level of music volume // * Get level of music volume
// * // *
// * @return level // * @return level
// */ // */
// public double getMusicVolume() // public double getMusicVolume()

@ -15,54 +15,54 @@ import mightypork.utils.math.constraints.vect.Vect;
/** /**
* Abstract audio module. * Abstract audio module.
* *
* @author Ondřej Hruška (MightyPork) * @author Ondřej Hruška (MightyPork)
*/ */
public abstract class AudioModule extends BackendModule implements Updateable { public abstract class AudioModule extends BackendModule implements Updateable {
/** /**
* Set listener position * Set listener position
* *
* @param pos listener position * @param pos listener position
*/ */
public abstract void setListenerPos(Vect pos); public abstract void setListenerPos(Vect pos);
/** /**
* Get current listener position * Get current listener position
* *
* @return listener position * @return listener position
*/ */
public abstract Vect getListenerPos(); public abstract Vect getListenerPos();
// -- instance -- // -- instance --
private final Volume masterVolume = new Volume(1D); private final Volume masterVolume = new Volume(1D);
private final Volume effectsVolume = new JointVolume(masterVolume); private final Volume effectsVolume = new JointVolume(masterVolume);
private final Volume loopsVolume = new JointVolume(masterVolume); private final Volume loopsVolume = new JointVolume(masterVolume);
private final List<LoopPlayer> loopPlayers = new ArrayList<>(); private final List<LoopPlayer> loopPlayers = new ArrayList<>();
private final List<DeferredAudio> resources = new ArrayList<>(); private final List<DeferredAudio> resources = new ArrayList<>();
@Override @Override
public void destroy() public void destroy()
{ {
for (final DeferredAudio r : resources) { for (final DeferredAudio r : resources) {
r.destroy(); r.destroy();
} }
deinitSoundSystem(); deinitSoundSystem();
} }
/** /**
* Deinitialize the soud system, release resources etc.<br> * Deinitialize the soud system, release resources etc.<br>
* Audio resources are already destroyed. * Audio resources are already destroyed.
*/ */
protected abstract void deinitSoundSystem(); protected abstract void deinitSoundSystem();
@Override @Override
public void update(double delta) public void update(double delta)
{ {
@ -70,11 +70,11 @@ public abstract class AudioModule extends BackendModule implements Updateable {
lp.update(delta); lp.update(delta);
} }
} }
/** /**
* Create effect resource * Create effect resource
* *
* @param resource resource path * @param resource resource path
* @param pitch default pitch (1 = unchanged) * @param pitch default pitch (1 = unchanged)
* @param gain default gain (0-1) * @param gain default gain (0-1)
@ -82,13 +82,13 @@ public abstract class AudioModule extends BackendModule implements Updateable {
*/ */
public EffectPlayer createEffect(String resource, double pitch, double gain) public EffectPlayer createEffect(String resource, double pitch, double gain)
{ {
return new EffectPlayer(createResource(resource), pitch, gain, effectsVolume); return new EffectPlayer(createAudio(resource), pitch, gain, effectsVolume);
} }
/** /**
* Register loop resource (music / effect loop) * Register loop resource (music / effect loop)
* *
* @param resource resource path * @param resource resource path
* @param pitch default pitch (1 = unchanged) * @param pitch default pitch (1 = unchanged)
* @param gain default gain (0-1) * @param gain default gain (0-1)
@ -98,39 +98,39 @@ public abstract class AudioModule extends BackendModule implements Updateable {
*/ */
public LoopPlayer createLoop(String resource, double pitch, double gain, double fadeIn, double fadeOut) public LoopPlayer createLoop(String resource, double pitch, double gain, double fadeIn, double fadeOut)
{ {
final LoopPlayer p = new LoopPlayer(createResource(resource), pitch, gain, loopsVolume); final LoopPlayer p = new LoopPlayer(createAudio(resource), pitch, gain, loopsVolume);
p.setFadeTimes(fadeIn, fadeOut); p.setFadeTimes(fadeIn, fadeOut);
loopPlayers.add(p); loopPlayers.add(p);
return p; return p;
} }
/** /**
* Create {@link DeferredAudio} for a resource, request deferred load and * Create {@link DeferredAudio} for a resource, request deferred load and
* add to the resources list. * add to the resources list.
* *
* @param res a resource name * @param res a resource name
* @return the resource * @return the resource
* @throws IllegalArgumentException if resource is already registered * @throws IllegalArgumentException if resource is already registered
*/ */
protected DeferredAudio createResource(String res) protected DeferredAudio createAudio(String res)
{ {
final DeferredAudio a = doCreateResource(res); final DeferredAudio a = doCreateResource(res);
App.bus().send(new ResourceLoadRequest(a)); App.bus().send(new ResourceLoadRequest(a));
resources.add(a); resources.add(a);
return a; return a;
} }
/** /**
* Create a backend-specific deferred audio resource * Create a backend-specific deferred audio resource
* *
* @param res resource path * @param res resource path
* @return Deferred Audio * @return Deferred Audio
*/ */
protected abstract DeferredAudio doCreateResource(String res); protected abstract DeferredAudio doCreateResource(String res);
/** /**
* Fade out all loops (= fade out the currently playing loops) * Fade out all loops (= fade out the currently playing loops)
*/ */
@ -140,8 +140,8 @@ public abstract class AudioModule extends BackendModule implements Updateable {
p.fadeOut(); p.fadeOut();
} }
} }
/** /**
* Pause all loops (leave volume unchanged) * Pause all loops (leave volume unchanged)
*/ */
@ -151,66 +151,66 @@ public abstract class AudioModule extends BackendModule implements Updateable {
p.pause(); p.pause();
} }
} }
/** /**
* Set level of master volume (volume multiplier) * Set level of master volume (volume multiplier)
* *
* @param volume level (0..1) * @param volume level (0..1)
*/ */
public void setMasterVolume(double volume) public void setMasterVolume(double volume)
{ {
masterVolume.set(volume); masterVolume.set(volume);
} }
/** /**
* Set level of effects volume (volume multiplier) * Set level of effects volume (volume multiplier)
* *
* @param volume level (0..1) * @param volume level (0..1)
*/ */
public void setEffectsVolume(double volume) public void setEffectsVolume(double volume)
{ {
effectsVolume.set(volume); effectsVolume.set(volume);
} }
/** /**
* Set level of loops volume (volume multiplier) * Set level of loops volume (volume multiplier)
* *
* @param volume level (0..1) * @param volume level (0..1)
*/ */
public void setLoopsVolume(double volume) public void setLoopsVolume(double volume)
{ {
loopsVolume.set(volume); loopsVolume.set(volume);
} }
/** /**
* Get level of master volume (volume multiplier) * Get level of master volume (volume multiplier)
* *
* @return level (0..1) * @return level (0..1)
*/ */
public double getMasterVolume() public double getMasterVolume()
{ {
return masterVolume.get(); return masterVolume.get();
} }
/** /**
* Get level of effects volume (volume multiplier) * Get level of effects volume (volume multiplier)
* *
* @return level (0..1) * @return level (0..1)
*/ */
public double getEffectsVolume() public double getEffectsVolume()
{ {
return effectsVolume.get(); return effectsVolume.get();
} }
/** /**
* Get level of loops volume (volume multiplier) * Get level of loops volume (volume multiplier)
* *
* @return level (0..1) * @return level (0..1)
*/ */
public double getLoopsVolume() public double getLoopsVolume()

@ -9,37 +9,37 @@ import mightypork.utils.math.constraints.vect.Vect;
/** /**
* Abstract deferred audio, to be extended in backend. * Abstract deferred audio, to be extended in backend.
* *
* @author Ondřej Hruška (MightyPork) * @author Ondřej Hruška (MightyPork)
*/ */
@Alias(name = "Audio") @Alias(name = "Audio")
public abstract class DeferredAudio extends BaseDeferredResource implements IAudio { public abstract class DeferredAudio extends BaseDeferredResource implements IAudio {
/** /**
* Create audio * Create audio
* *
* @param resourceName resource to load (when needed) * @param resourceName resource to load (when needed)
*/ */
public DeferredAudio(String resourceName) public DeferredAudio(String resourceName)
{ {
super(resourceName); super(resourceName);
} }
@Override @Override
public void play(double pitch, double gain, boolean loop) public void play(double pitch, double gain, boolean loop)
{ {
play(pitch, gain, loop, App.audio().getListenerPos()); play(pitch, gain, loop, App.audio().getListenerPos());
} }
@Override @Override
public void play(double pitch, double gain, boolean loop, double x, double y) public void play(double pitch, double gain, boolean loop, double x, double y)
{ {
play(pitch, gain, loop, x, y, App.audio().getListenerPos().z()); play(pitch, gain, loop, x, y, App.audio().getListenerPos().z());
} }
@Override @Override
public void play(double pitch, double gain, boolean loop, Vect pos) public void play(double pitch, double gain, boolean loop, Vect pos)
{ {

@ -7,63 +7,63 @@ import mightypork.utils.math.constraints.vect.Vect;
/** /**
* Audio resource interface (backend independent) * Audio resource interface (backend independent)
* *
* @author Ondřej Hruška (MightyPork) * @author Ondřej Hruška (MightyPork)
*/ */
public interface IAudio extends Destroyable { public interface IAudio extends Destroyable {
/** /**
* Pause loop (remember position and stop playing) - if was looping * Pause loop (remember position and stop playing) - if was looping
*/ */
void pauseLoop(); void pauseLoop();
/** /**
* Resume loop (if was paused) * Resume loop (if was paused)
*/ */
void resumeLoop(); void resumeLoop();
/** /**
* Adjust gain for the currently playing effect (can be used for fading * Adjust gain for the currently playing effect (can be used for fading
* music) * music)
* *
* @param gain gain to set 0..1 * @param gain gain to set 0..1
*/ */
void adjustGain(double gain); void adjustGain(double gain);
/** /**
* Stop audio playback * Stop audio playback
*/ */
void stop(); void stop();
/** /**
* @return true if the audio is playing * @return true if the audio is playing
*/ */
boolean isPlaying(); boolean isPlaying();
/** /**
* @return trie if the audio is paused * @return trie if the audio is paused
*/ */
boolean isPaused(); boolean isPaused();
/** /**
* Play as sound effect at listener position * Play as sound effect at listener position
* *
* @param pitch pitch (1 = default) * @param pitch pitch (1 = default)
* @param gain gain (0-1) * @param gain gain (0-1)
* @param loop looping * @param loop looping
*/ */
void play(double pitch, double gain, boolean loop); void play(double pitch, double gain, boolean loop);
/** /**
* Play as sound effect at given X-Y position * Play as sound effect at given X-Y position
* *
* @param pitch pitch (1 = default) * @param pitch pitch (1 = default)
* @param gain gain (0-1) * @param gain gain (0-1)
* @param loop looping * @param loop looping
@ -71,11 +71,11 @@ public interface IAudio extends Destroyable {
* @param y * @param y
*/ */
void play(double pitch, double gain, boolean loop, double x, double y); void play(double pitch, double gain, boolean loop, double x, double y);
/** /**
* Play as sound effect at given position * Play as sound effect at given position
* *
* @param pitch pitch (1 = default) * @param pitch pitch (1 = default)
* @param gain gain (0-1) * @param gain gain (0-1)
* @param loop looping * @param loop looping
@ -84,16 +84,16 @@ public interface IAudio extends Destroyable {
* @param z * @param z
*/ */
void play(double pitch, double gain, boolean loop, double x, double y, double z); void play(double pitch, double gain, boolean loop, double x, double y, double z);
/** /**
* Play as sound effect at given position * Play as sound effect at given position
* *
* @param pitch pitch (1 = default) * @param pitch pitch (1 = default)
* @param gain gain (0-1) * @param gain gain (0-1)
* @param loop looping * @param loop looping
* @param pos coord * @param pos coord
*/ */
void play(double pitch, double gain, boolean loop, Vect pos); void play(double pitch, double gain, boolean loop, Vect pos);
} }

@ -6,17 +6,17 @@ import mightypork.utils.math.Calc;
/** /**
* Volume combined of multiple volumes, combining them (multiplication). * Volume combined of multiple volumes, combining them (multiplication).
* *
* @author Ondřej Hruška (MightyPork) * @author Ondřej Hruška (MightyPork)
*/ */
public class JointVolume extends Volume { public class JointVolume extends Volume {
private final Volume[] volumes; private final Volume[] volumes;
/** /**
* Create joint volume with master gain of 1 * Create joint volume with master gain of 1
* *
* @param volumes individual volumes to join * @param volumes individual volumes to join
*/ */
@SafeVarargs @SafeVarargs
@ -25,8 +25,8 @@ public class JointVolume extends Volume {
super(1D); super(1D);
this.volumes = volumes; this.volumes = volumes;
} }
/** /**
* Get combined gain (multiplied) * Get combined gain (multiplied)
*/ */
@ -36,11 +36,11 @@ public class JointVolume extends Volume {
double d = super.get(); double d = super.get();
for (final Volume v : volumes) for (final Volume v : volumes)
d *= v.get(); d *= v.get();
return Calc.clamp(d, 0, 1); return Calc.clamp(d, 0, 1);
} }
/** /**
* Set master gain * Set master gain
*/ */

@ -11,18 +11,18 @@ import mightypork.gamecore.core.App;
/** /**
* Audio resource storage * Audio resource storage
* *
* @author Ondřej Hruška (MightyPork) * @author Ondřej Hruška (MightyPork)
*/ */
public class SoundRegistry { public class SoundRegistry {
private final Map<String, EffectPlayer> effects = new HashMap<>(); private final Map<String, EffectPlayer> effects = new HashMap<>();
private final Map<String, LoopPlayer> loops = new HashMap<>(); private final Map<String, LoopPlayer> loops = new HashMap<>();
/** /**
* Register effect resource * Register effect resource
* *
* @param key sound key * @param key sound key
* @param resource resource path * @param resource resource path
* @param pitch default pitch (1 = unchanged) * @param pitch default pitch (1 = unchanged)
@ -32,11 +32,11 @@ public class SoundRegistry {
{ {
effects.put(key, App.audio().createEffect(resource, pitch, gain)); effects.put(key, App.audio().createEffect(resource, pitch, gain));
} }
/** /**
* Register loop resource (music / effect loop) * Register loop resource (music / effect loop)
* *
* @param key sound key * @param key sound key
* @param resource resource path * @param resource resource path
* @param pitch default pitch (1 = unchanged) * @param pitch default pitch (1 = unchanged)
@ -48,11 +48,11 @@ public class SoundRegistry {
{ {
loops.put(key, App.audio().createLoop(resource, pitch, gain, fadeIn, fadeOut)); loops.put(key, App.audio().createLoop(resource, pitch, gain, fadeIn, fadeOut));
} }
/** /**
* Get a loop player for key * Get a loop player for key
* *
* @param key sound key * @param key sound key
* @return loop player * @return loop player
*/ */
@ -64,11 +64,11 @@ public class SoundRegistry {
} }
return p; return p;
} }
/** /**
* Get a effect player for key * Get a effect player for key
* *
* @param key sound key * @param key sound key
* @return effect player * @return effect player
*/ */

@ -7,11 +7,11 @@ import mightypork.utils.struct.Mutable;
/** /**
* Mutable volume 0-1 * Mutable volume 0-1
* *
* @author Ondřej Hruška (MightyPork) * @author Ondřej Hruška (MightyPork)
*/ */
public class Volume extends Mutable<Double> { public class Volume extends Mutable<Double> {
/** /**
* @param d initial value * @param d initial value
*/ */
@ -19,12 +19,12 @@ public class Volume extends Mutable<Double> {
{ {
super(d); super(d);
} }
@Override @Override
public void set(Double d) public void set(Double d)
{ {
super.set(Calc.clamp(d, 0, 1)); super.set(Calc.clamp(d, 0, 1));
} }
} }

@ -8,24 +8,24 @@ import mightypork.utils.interfaces.Destroyable;
/** /**
* Basic abstract player * Basic abstract player
* *
* @author Ondřej Hruška (MightyPork) * @author Ondřej Hruška (MightyPork)
*/ */
public abstract class BaseAudioPlayer implements Destroyable { public abstract class BaseAudioPlayer implements Destroyable {
/** the track */ /** the track */
private final DeferredAudio audio; private final DeferredAudio audio;
/** base gain for sfx */ /** base gain for sfx */
private final double baseGain; private final double baseGain;
/** base pitch for sfx */ /** base pitch for sfx */
private final double basePitch; private final double basePitch;
/** dedicated volume control */ /** dedicated volume control */
private final Volume gainMultiplier; private final Volume gainMultiplier;
/** /**
* @param track audio resource * @param track audio resource
* @param basePitch base pitch (pitch multiplier) * @param basePitch base pitch (pitch multiplier)
@ -35,23 +35,23 @@ public abstract class BaseAudioPlayer implements Destroyable {
public BaseAudioPlayer(DeferredAudio track, double basePitch, double baseGain, Volume volume) public BaseAudioPlayer(DeferredAudio track, double basePitch, double baseGain, Volume volume)
{ {
this.audio = track; this.audio = track;
this.baseGain = baseGain; this.baseGain = baseGain;
this.basePitch = basePitch; this.basePitch = basePitch;
if (volume == null) volume = new Volume(1D); if (volume == null) volume = new Volume(1D);
this.gainMultiplier = volume; this.gainMultiplier = volume;
} }
@Override @Override
public void destroy() public void destroy()
{ {
audio.destroy(); audio.destroy();
} }
/** /**
* @return audio resource * @return audio resource
*/ */
@ -59,11 +59,11 @@ public abstract class BaseAudioPlayer implements Destroyable {
{ {
return audio; return audio;
} }
/** /**
* Get play gain, computed based on volume and given multiplier * Get play gain, computed based on volume and given multiplier
* *
* @param multiplier extra volume adjustment * @param multiplier extra volume adjustment
* @return computed gain * @return computed gain
*/ */
@ -71,11 +71,11 @@ public abstract class BaseAudioPlayer implements Destroyable {
{ {
return baseGain * gainMultiplier.get() * multiplier; return baseGain * gainMultiplier.get() * multiplier;
} }
/** /**
* Get pitch * Get pitch
* *
* @param multiplier pitch adjustment * @param multiplier pitch adjustment
* @return computed pitch * @return computed pitch
*/ */
@ -83,19 +83,19 @@ public abstract class BaseAudioPlayer implements Destroyable {
{ {
return basePitch * multiplier; return basePitch * multiplier;
} }
/** /**
* Get if audio is valid * Get if audio is valid
* *
* @return is valid * @return is valid
*/ */
protected boolean hasAudio() protected boolean hasAudio()
{ {
return (audio != null); return (audio != null);
} }
/** /**
* force load the resource * force load the resource
*/ */

@ -8,11 +8,11 @@ import mightypork.utils.math.constraints.vect.Vect;
/** /**
* Player for one-off effects * Player for one-off effects
* *
* @author Ondřej Hruška (MightyPork) * @author Ondřej Hruška (MightyPork)
*/ */
public class EffectPlayer extends BaseAudioPlayer { public class EffectPlayer extends BaseAudioPlayer {
/** /**
* @param track audio resource * @param track audio resource
* @param basePitch base pitch (pitch multiplier) * @param basePitch base pitch (pitch multiplier)
@ -23,36 +23,36 @@ public class EffectPlayer extends BaseAudioPlayer {
{ {
super(track, (float) basePitch, (float) baseGain, volume); super(track, (float) basePitch, (float) baseGain, volume);
} }
/** /**
* Play at listener * Play at listener
* *
* @param pitch play pitch * @param pitch play pitch
* @param gain play gain * @param gain play gain
*/ */
public void play(double pitch, double gain) public void play(double pitch, double gain)
{ {
if (!hasAudio()) return; if (!hasAudio()) return;
getAudio().play(computePitch(pitch), computeGain(gain), false); getAudio().play(computePitch(pitch), computeGain(gain), false);
} }
/** /**
* Play at listener * Play at listener
* *
* @param gain play gain * @param gain play gain
*/ */
public void play(double gain) public void play(double gain)
{ {
play(1, gain); play(1, gain);
} }
/** /**
* Play at given position * Play at given position
* *
* @param pitch play pitch * @param pitch play pitch
* @param gain play gain * @param gain play gain
* @param pos play position * @param pos play position
@ -60,8 +60,8 @@ public class EffectPlayer extends BaseAudioPlayer {
public void play(double pitch, double gain, Vect pos) public void play(double pitch, double gain, Vect pos)
{ {
if (!hasAudio()) return; if (!hasAudio()) return;
getAudio().play(computePitch(pitch), computeGain(gain), false, pos); getAudio().play(computePitch(pitch), computeGain(gain), false, pos);
} }
} }

@ -10,28 +10,26 @@ import mightypork.utils.math.animation.NumAnimated;
/** /**
* Audio loop player (with fading, good for music) * Audio loop player (with fading, good for music)
* *
* @author Ondřej Hruška (MightyPork) * @author Ondřej Hruška (MightyPork)
*/ */
public class LoopPlayer extends BaseAudioPlayer implements Updateable, Pauseable { public class LoopPlayer extends BaseAudioPlayer implements Updateable, Pauseable {
private final int sourceID = -1;
/** animator for fade in and fade out */ /** animator for fade in and fade out */
private final NumAnimated fadeAnim = new NumAnimated(0); private final NumAnimated fadeAnim = new NumAnimated(0);
private double lastUpdateGain = 0; private double lastUpdateGain = 0;
/** flag that track is paused */ /** flag that track is paused */
private boolean paused = true; private boolean paused = true;
/** Default fadeIn time */ /** Default fadeIn time */
private double inTime = 1; private double inTime = 1;
/** Default fadeOut time */ /** Default fadeOut time */
private double outTime = 1; private double outTime = 1;
/** /**
* @param track audio resource * @param track audio resource
* @param basePitch base pitch (pitch multiplier) * @param basePitch base pitch (pitch multiplier)
@ -41,14 +39,14 @@ public class LoopPlayer extends BaseAudioPlayer implements Updateable, Pauseable
public LoopPlayer(DeferredAudio track, double basePitch, double baseGain, Volume volume) public LoopPlayer(DeferredAudio track, double basePitch, double baseGain, Volume volume)
{ {
super(track, (float) basePitch, (float) baseGain, volume); super(track, (float) basePitch, (float) baseGain, volume);
paused = true; paused = true;
} }
/** /**
* Set fading duration (seconds) * Set fading duration (seconds)
* *
* @param in duration of fade-in * @param in duration of fade-in
* @param out duration of fade-out * @param out duration of fade-out
*/ */
@ -57,96 +55,96 @@ public class LoopPlayer extends BaseAudioPlayer implements Updateable, Pauseable
inTime = in; inTime = in;
outTime = out; outTime = out;
} }
private void initLoop() private void initLoop()
{ {
if (hasAudio() && sourceID == -1) { if (hasAudio()) {
getAudio().play(computePitch(1), computeGain(1), true); getAudio().play(computePitch(1), computeGain(1), true);
getAudio().pauseLoop(); getAudio().pauseLoop();
} }
} }
@Override @Override
public void pause() public void pause()
{ {
if (!hasAudio() || paused) return; if (!hasAudio() || paused) return;
initLoop(); initLoop();
getAudio().pauseLoop(); getAudio().pauseLoop();
paused = true; paused = true;
} }
@Override @Override
public boolean isPaused() public boolean isPaused()
{ {
return paused; return paused;
} }
@Override @Override
public void resume() public void resume()
{ {
if (!hasAudio() || !paused) return; if (!hasAudio() || !paused) return;
initLoop(); initLoop();
paused = false; paused = false;
getAudio().adjustGain(computeGain(fadeAnim.value())); getAudio().adjustGain(computeGain(fadeAnim.value()));
} }
@Override @Override
public void update(double delta) public void update(double delta)
{ {
if (!hasAudio() || paused) return; if (!hasAudio() || paused) return;
initLoop(); initLoop();
fadeAnim.update(delta); fadeAnim.update(delta);
final double gain = computeGain(fadeAnim.value()); final double gain = computeGain(fadeAnim.value());
if (!paused && gain != lastUpdateGain) { if (!paused && gain != lastUpdateGain) {
getAudio().adjustGain(gain); getAudio().adjustGain(gain);
lastUpdateGain = gain; lastUpdateGain = gain;
} }
if (gain == 0 && !paused) pause(); // pause on zero volume if (gain == 0 && !paused) pause(); // pause on zero volume
} }
/** /**
* Resume if paused, and fade in (pick up from current volume). * Resume if paused, and fade in (pick up from current volume).
* *
* @param secs * @param fadeTime fade time (s)
*/ */
public void fadeIn(double secs) public void fadeIn(double fadeTime)
{ {
if (!hasAudio()) return; if (!hasAudio()) return;
if (isPaused()) fadeAnim.setTo(0); if (isPaused()) fadeAnim.setTo(0);
resume(); resume();
fadeAnim.fadeIn(secs); fadeAnim.fadeIn(fadeTime);
} }
/** /**
* Fade out and pause when reached zero volume * Fade out and pause when reached zero volume
* *
* @param secs fade duration * @param fadeTime fade time (s)
*/ */
public void fadeOut(double secs) public void fadeOut(double fadeTime)
{ {
if (!hasAudio()) return; if (!hasAudio()) return;
if (isPaused()) return; if (isPaused()) return;
fadeAnim.fadeOut(secs); fadeAnim.fadeOut(fadeTime);
} }
/** /**
* Fade in with default duration * Fade in with default duration
*/ */
@ -154,8 +152,8 @@ public class LoopPlayer extends BaseAudioPlayer implements Updateable, Pauseable
{ {
fadeIn(inTime); fadeIn(inTime);
} }
/** /**
* Fade out with default duration * Fade out with default duration
*/ */
@ -163,5 +161,5 @@ public class LoopPlayer extends BaseAudioPlayer implements Updateable, Pauseable
{ {
fadeOut(outTime); fadeOut(outTime);
} }
} }

@ -19,7 +19,7 @@ import mightypork.utils.logging.Log;
/** /**
* Game base class & static subsystem access * Game base class & static subsystem access
* *
* @author MightyPork * @author MightyPork
*/ */
public class App extends BusNode { public class App extends BusNode {
@ -30,14 +30,16 @@ public class App extends BusNode {
private final EventBus eventBus = new EventBus(); private final EventBus eventBus = new EventBus();
private boolean started = false; private boolean started = false;
/** List of installed App plugins */
protected final DelegatingList plugins = new DelegatingList(); protected final DelegatingList plugins = new DelegatingList();
/** List of initializers */
protected final List<InitTask> initializers = new ArrayList<>(); protected final List<InitTask> initializers = new ArrayList<>();
/** /**
* Create an app with given backend. * Create an app with given backend.
* *
* @param backend * @param backend the backend to use
*/ */
public App(AppBackend backend) public App(AppBackend backend)
{ {
@ -56,8 +58,8 @@ public class App extends BusNode {
// initialize and use backend // initialize and use backend
this.backend = backend; this.backend = backend;
this.eventBus.subscribe(backend);
this.backend.bind(this); this.backend.bind(this);
this.eventBus.subscribe(backend);
this.backend.initialize(); this.backend.initialize();
} }
@ -65,7 +67,7 @@ public class App extends BusNode {
/** /**
* Add a plugin to the app. Plugins can eg. listen to bus events and react * Add a plugin to the app. Plugins can eg. listen to bus events and react
* to them. * to them.
* *
* @param plugin the added plugin. * @param plugin the added plugin.
*/ */
public void addPlugin(AppPlugin plugin) public void addPlugin(AppPlugin plugin)
@ -83,8 +85,8 @@ public class App extends BusNode {
/** /**
* Add an initializer to the app. * Add an initializer to the app.
* *
* @param initializer * @param initializer the added init task
*/ */
public void addInitTask(InitTask initializer) public void addInitTask(InitTask initializer)
{ {
@ -98,7 +100,7 @@ public class App extends BusNode {
/** /**
* Get current backend * Get current backend
* *
* @return the backend * @return the backend
*/ */
public AppBackend getBackend() public AppBackend getBackend()
@ -128,11 +130,21 @@ public class App extends BusNode {
// sort initializers by order. // sort initializers by order.
final List<InitTask> orderedInitializers = InitTask.inOrder(initializers); final List<InitTask> orderedInitializers = InitTask.inOrder(initializers);
for (final InitTask initializer : orderedInitializers) { for (final InitTask initTask : orderedInitializers) {
Log.f1("Running init task \"" + initializer.getName() + "\"..."); Log.f1("Running init task \"" + initTask.getName() + "\"...");
initializer.bind(this);
initializer.init(); initTask.bind(this);
initializer.run();
// set the task options
initTask.init();
initTask.before();
// main task action
initTask.run();
// after hook for extra actions immeditaely after the task completes
initTask.after();
} }
Log.i("=== Initialization sequence completed ==="); Log.i("=== Initialization sequence completed ===");
@ -199,7 +211,7 @@ public class App extends BusNode {
/** /**
* Get the currently running App instance. * Get the currently running App instance.
* *
* @return app instance * @return app instance
*/ */
public static App instance() public static App instance()
@ -210,7 +222,7 @@ public class App extends BusNode {
/** /**
* Get graphics module from the running app's backend * Get graphics module from the running app's backend
* *
* @return graphics module * @return graphics module
*/ */
public static GraphicsModule gfx() public static GraphicsModule gfx()
@ -221,7 +233,7 @@ public class App extends BusNode {
/** /**
* Get audio module from the running app's backend * Get audio module from the running app's backend
* *
* @return audio module * @return audio module
*/ */
public static AudioModule audio() public static AudioModule audio()
@ -232,7 +244,7 @@ public class App extends BusNode {
/** /**
* Get input module from the running app's backend * Get input module from the running app's backend
* *
* @return input module * @return input module
*/ */
public static InputModule input() public static InputModule input()
@ -243,7 +255,7 @@ public class App extends BusNode {
/** /**
* Get event bus instance. * Get event bus instance.
* *
* @return event bus * @return event bus
*/ */
public static EventBus bus() public static EventBus bus()
@ -254,7 +266,7 @@ public class App extends BusNode {
/** /**
* Get the main config, if initialized. * Get the main config, if initialized.
* *
* @return main config * @return main config
* @throws IllegalArgumentException if there is no such config. * @throws IllegalArgumentException if there is no such config.
*/ */
@ -266,7 +278,7 @@ public class App extends BusNode {
/** /**
* Get a config by alias. * Get a config by alias.
* *
* @param alias config alias * @param alias config alias
* @return the config * @return the config
* @throws IllegalArgumentException if there is no such config. * @throws IllegalArgumentException if there is no such config.

@ -12,17 +12,18 @@ import mightypork.utils.eventbus.clients.BusNode;
* The goal of this abstraction is to allow easy migration to different * The goal of this abstraction is to allow easy migration to different
* environment with different libraries etc. It should be as simple as using * environment with different libraries etc. It should be as simple as using
* different backend. * different backend.
* *
* @author MightyPork * @author MightyPork
*/ */
public abstract class AppBackend extends BusNode { public abstract class AppBackend extends BusNode {
/** App instance assigned using <code>bind()</code> */
protected App app; protected App app;
/** /**
* Assign an app instance. * Assign the initialized app instance to an "app" field.
* *
* @param app app * @param app app
*/ */
public void bind(App app) public void bind(App app)
@ -42,7 +43,7 @@ public abstract class AppBackend extends BusNode {
/** /**
* Get graphics module (screen manager, texture and font loader, renderer) * Get graphics module (screen manager, texture and font loader, renderer)
* *
* @return graphics module * @return graphics module
*/ */
public abstract GraphicsModule getGraphics(); public abstract GraphicsModule getGraphics();
@ -50,7 +51,7 @@ public abstract class AppBackend extends BusNode {
/** /**
* Get audio module ( * Get audio module (
* *
* @return audio module * @return audio module
*/ */
public abstract AudioModule getAudio(); public abstract AudioModule getAudio();
@ -58,7 +59,7 @@ public abstract class AppBackend extends BusNode {
/** /**
* Get input module * Get input module
* *
* @return input module * @return input module
*/ */
public abstract InputModule getInput(); public abstract InputModule getInput();

@ -9,20 +9,26 @@ import mightypork.utils.eventbus.clients.BusNode;
* App plugin. Plugins are an easy way to extend app functionality.<br> * App plugin. Plugins are an easy way to extend app functionality.<br>
* Typically, a plugin waits for trigger event(s) and performs some action upon * Typically, a plugin waits for trigger event(s) and performs some action upon
* receiving them. * receiving them.
* *
* @author Ondřej Hruška (MightyPork) * @author Ondřej Hruška (MightyPork)
*/ */
public class AppPlugin extends BusNode { public class AppPlugin extends BusNode {
/** App instance assigned using <code>bind()</code> */
protected App app; protected App app;
/**
* Assign the initialized app instance to an "app" field.
*
* @param app app
*/
void bind(App app) void bind(App app)
{ {
this.app = app; this.app = app;
} }
/** /**
* Initialize the plugin for the given App.<br> * Initialize the plugin for the given App.<br>
* The plugin is already attached to the event bus. * The plugin is already attached to the event bus.

@ -8,14 +8,20 @@ import mightypork.utils.interfaces.Destroyable;
/** /**
* Abstract application backend module. * Abstract application backend module.
* *
* @author MightyPork * @author MightyPork
*/ */
public abstract class BackendModule extends BusNode implements Destroyable { public abstract class BackendModule extends BusNode implements Destroyable {
/**
* Initialize the backend module.<br>
* Any initialization that would normally be done in constructor shall be
* done here, to avoid pitfalls with
* "call to overridable method from constructor"
*/
public abstract void init(); public abstract void init();
@Override @Override
@Stub @Stub
public void destroy() public void destroy()

@ -16,57 +16,81 @@ import mightypork.utils.logging.Log;
* App initializer. A sequence of initializers is executed once the start() * App initializer. A sequence of initializers is executed once the start()
* method on App is called. Adding initializers is one way to customize the App * method on App is called. Adding initializers is one way to customize the App
* behavior and features. * behavior and features.
* *
* @author Ondřej Hruška (MightyPork) * @author Ondřej Hruška (MightyPork)
*/ */
public abstract class InitTask { public abstract class InitTask {
/** App instance assigned using <code>bind()</code> */
protected App app; protected App app;
/** /**
* Assign the initialized app instance to a protected "app" field. * Assign the initialized app instance to an "app" field.
* *
* @param app app * @param app app
*/ */
void bind(App app) final void bind(App app)
{ {
this.app = app; this.app = app;
} }
/** /**
* An intialization method that is called before the run() method.<br> * An init method that is called before the <code>run()</code> method.<br>
* This method should be left unimplemented in the task, and can be used to * This method should be left unimplemented in the task, and can be used to
* configure the init task when using it as anonymous inner type. * configure the init task when using it as anonymous inner type.
*/ */
@Stub @Stub
public void init() public void init()
{ {
//
} }
/** /**
* Run the initalizer on app. * Hook for extra action before the main task action.<br>
* Can be overridden during app configuration to "bake-in" extra actions.
*/
@Stub
public void before()
{
//
}
/**
* Run the initializer on app.
*/ */
public abstract void run(); public abstract void run();
/**
* Hook executed after the "run()" method.<br>
* Can be overridden during app configuration to "bake-in" extra actions.
*/
@Stub
public void after()
{
//
}
/** /**
* Get name of this initializer (for dependency resolver).<br> * Get name of this initializer (for dependency resolver).<br>
* The name should be short, snake_case and precise. * The name should be short, snake_case and precise.
* *
* @return name * @return name
*/ */
public abstract String getName(); public abstract String getName();
/** /**
* Get what other initializers must be already loaded before this can load.<br> * Get what other initializers must be already loaded before this can load.<br>
* Depending on itself or creating a circular dependency will cause error.<br> * Depending on itself or creating a circular dependency will cause error.<br>
* If the dependencies cannot be satisfied, the initialization sequence will * If the dependencies cannot be satisfied, the initialization sequence will
* be aborted. * be aborted.
* *
* @return array of names of required initializers. * @return array of names of required initializers.
*/ */
@Stub @Stub
@ -74,37 +98,37 @@ public abstract class InitTask {
{ {
return new String[] {}; return new String[] {};
} }
/** /**
* Order init tasks so that all dependencies are loaded before thye are * Order init tasks so that all dependencies are loaded before thye are
* needed by the tasks. * needed by the tasks.
* *
* @param tasks task list * @param tasks task list
* @return task list ordered * @return task list ordered
*/ */
public static List<InitTask> inOrder(List<InitTask> tasks) public static List<InitTask> inOrder(List<InitTask> tasks)
{ {
final List<InitTask> remaining = new ArrayList<>(tasks); final List<InitTask> remaining = new ArrayList<>(tasks);
final List<InitTask> ordered = new ArrayList<>(); final List<InitTask> ordered = new ArrayList<>();
final Set<String> loaded = new HashSet<>(); final Set<String> loaded = new HashSet<>();
// resolve task order // resolve task order
int addedThisIteration = 0; int addedThisIteration = 0;
do { do {
for (final Iterator<InitTask> i = remaining.iterator(); i.hasNext();) { for (final Iterator<InitTask> i = remaining.iterator(); i.hasNext();) {
final InitTask task = i.next(); final InitTask task = i.next();
String[] deps = task.getDependencies(); String[] deps = task.getDependencies();
if (deps == null) deps = new String[] {}; if (deps == null) deps = new String[] {};
int unmetDepsCount = deps.length; int unmetDepsCount = deps.length;
for (final String d : deps) { for (final String d : deps) {
if (loaded.contains(d)) unmetDepsCount--; if (loaded.contains(d)) unmetDepsCount--;
} }
if (unmetDepsCount == 0) { if (unmetDepsCount == 0) {
ordered.add(task); ordered.add(task);
loaded.add(task.getName()); loaded.add(task.getName());
@ -113,38 +137,38 @@ public abstract class InitTask {
} }
} }
} while (addedThisIteration > 0); } while (addedThisIteration > 0);
// check if any tasks are left out // check if any tasks are left out
if (remaining.size() > 0) { if (remaining.size() > 0) {
// build error message for each bad task // build error message for each bad task
int badInitializers = 0; int badInitializers = 0;
for (final InitTask task : remaining) { for (final InitTask task : remaining) {
if (Reflect.hasAnnotation(task.getClass(), OptionalInitTask.class)) { if (Reflect.hasAnnotation(task.getClass(), OptionalInitTask.class)) {
continue; continue;
} }
badInitializers++; badInitializers++;
String notSatisfied = ""; String notSatisfied = "";
for (final String d : task.getDependencies()) { for (final String d : task.getDependencies()) {
if (!loaded.contains(d)) { if (!loaded.contains(d)) {
if (!notSatisfied.isEmpty()) { if (!notSatisfied.isEmpty()) {
notSatisfied += ", "; notSatisfied += ", ";
} }
notSatisfied += d; notSatisfied += d;
} }
} }
Log.w("InitTask \"" + task.getName() + "\" - missing dependencies: " + notSatisfied); Log.w("InitTask \"" + task.getName() + "\" - missing dependencies: " + notSatisfied);
} }
if (badInitializers > 0) throw new RuntimeException("Some InitTask dependencies could not be satisfied."); if (badInitializers > 0) throw new RuntimeException("Some InitTask dependencies could not be satisfied.");
} }
return ordered; return ordered;
} }
} }

@ -17,23 +17,31 @@ import mightypork.utils.math.timing.TimerDelta;
/** /**
* Delta-timed game loop with task queue etc. * Delta-timed game loop with task queue etc.
* *
* @author Ondřej Hruška (MightyPork) * @author Ondřej Hruška (MightyPork)
*/ */
public class MainLoop extends BusNode implements Destroyable { public class MainLoop extends BusNode implements Destroyable {
private static final double MAX_TIME_TASKS = 1 / 30D; // (avoid queue from hogging timing) /**
private static final double MAX_DELTA = 1 / 20D; // (skip huge gaps caused by loading resources etc) * Max time spent on main loop tasks per cycle (s)
*/
protected double MAX_TIME_TASKS = 1 / 30D;
/**
* Max delta time (s) per frame.<br>
* If delta is larger than this, it's clamped to it.
*/
protected double MAX_DELTA = 1 / 20D;
private final Deque<Runnable> tasks = new ConcurrentLinkedDeque<>(); private final Deque<Runnable> tasks = new ConcurrentLinkedDeque<>();
private TimerDelta timer; private TimerDelta timer;
private Renderable rootRenderable; private Renderable rootRenderable;
private volatile boolean running = true; private volatile boolean running = true;
/** /**
* Set primary renderable * Set primary renderable
* *
* @param rootRenderable main {@link Renderable}, typically a * @param rootRenderable main {@link Renderable}, typically a
* {@link ScreenRegistry} * {@link ScreenRegistry}
*/ */
@ -41,50 +49,54 @@ public class MainLoop extends BusNode implements Destroyable {
{ {
this.rootRenderable = rootRenderable; this.rootRenderable = rootRenderable;
} }
/** /**
* Start the loop * Start the loop
*/ */
public void start() public void start()
{ {
timer = new TimerDelta(); timer = new TimerDelta();
while (running) { while (running) {
App.gfx().beginFrame(); App.gfx().beginFrame();
double delta = timer.getDelta(); double delta = timer.getDelta();
if (delta > MAX_DELTA) { if (delta > MAX_DELTA) {
Log.f3("(timing) Cropping delta: was " + delta + " , limit " + MAX_DELTA); Log.f3("(timing) Clamping delta: was " + delta + " s, MAX_DELTA = " + MAX_DELTA + " s");
delta = MAX_DELTA; delta = MAX_DELTA;
} }
// dispatch update event
App.bus().sendDirect(new UpdateEvent(delta)); App.bus().sendDirect(new UpdateEvent(delta));
// run main loop tasks
Runnable r; Runnable r;
final long t = Profiler.begin(); final long t = Profiler.begin();
while ((r = tasks.poll()) != null) { while ((r = tasks.poll()) != null) {
Log.f3(" * Main loop task."); Log.f3(" * Main loop task.");
r.run(); r.run();
if (Profiler.end(t) > MAX_TIME_TASKS) { if (Profiler.end(t) > MAX_TIME_TASKS) {
Log.f3("! Postponing main loop tasks to next cycle."); Log.f3("! Time's up, postponing task to next cycle.");
break; break;
} }
} }
beforeRender(); beforeRender();
if (rootRenderable != null) { if (rootRenderable != null) {
rootRenderable.render(); rootRenderable.render();
} }
afterRender(); afterRender();
App.gfx().endFrame(); App.gfx().endFrame();
} }
} }
/** /**
* Called before render * Called before render
*/ */
@ -93,8 +105,8 @@ public class MainLoop extends BusNode implements Destroyable {
{ {
// //
} }
/** /**
* Called after render * Called after render
*/ */
@ -103,28 +115,29 @@ public class MainLoop extends BusNode implements Destroyable {
{ {
// //
} }
@Override @Override
public void destroy() public void destroy()
{ {
running = false; running = false;
} }
/** /**
* Add a task to queue to be executed in the main loop (OpenGL thread) * Add a task to queue to be executed in the main loop (in rendering
* * context)
* @param request task *
* @param priority if true, skip other tasks * @param task task
* @param skipQueue true to skip the queue
*/ */
public synchronized void queueTask(Runnable request, boolean priority) public synchronized void queueTask(Runnable task, boolean skipQueue)
{ {
if (priority) { if (skipQueue) {
tasks.addFirst(request); tasks.addFirst(task);
} else { } else {
tasks.addLast(request); tasks.addLast(task);
} }
} }
} }

@ -12,7 +12,7 @@ import java.lang.annotation.Target;
/** /**
* Indicates that an {@link InitTask} can safely be ignored if it's dependencies * Indicates that an {@link InitTask} can safely be ignored if it's dependencies
* are not satisfied. * are not satisfied.
* *
* @author Ondřej Hruška (MightyPork) * @author Ondřej Hruška (MightyPork)
*/ */
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
@ -20,5 +20,5 @@ import java.lang.annotation.Target;
@Documented @Documented
@Inherited @Inherited
public @interface OptionalInitTask { public @interface OptionalInitTask {
} }

@ -1,91 +0,0 @@
package mightypork.gamecore.core;
import java.io.File;
import java.util.HashMap;
import java.util.Map;
import mightypork.utils.logging.Log;
/**
* Static application workdir accessor.
*
* @author Ondřej Hruška (MightyPork)
*/
public class WorkDir {
private static File workdir;
private static Map<String, String> namedPaths = new HashMap<>();
public static void init(File workdir)
{
WorkDir.workdir = workdir;
}
/**
* Add a path alias (dir or file), relative to the workdir.
*
* @param alias path alias
* @param path path relative to workdir
*/
public static void addPath(String alias, String path)
{
namedPaths.put(alias, path);
}
/**
* Get workdir folder, create if not exists.
*
* @param path dir path relative to workdir
* @return dir file
*/
public static File getDir(String path)
{
if (namedPaths.containsKey(path)) path = namedPaths.get(path);
final File f = new File(workdir, path);
if (!f.exists()) {
if (!f.mkdirs()) {
Log.w("Could not create a directory: " + f + " (path: " + path + ")");
}
}
return f;
}
/**
* Get workdir file, create parent if not exists.
*
* @param path dir path relative to workdir
* @return dir file
*/
public static File getFile(String path)
{
if (namedPaths.containsKey(path)) path = namedPaths.get(path);
final File f = new File(workdir, path);
// create the parent dir
if (!f.getParent().equals(workdir)) {
f.getParentFile().mkdirs();
}
return f;
}
/**
* @return the workdir File
*/
public static File getWorkDir()
{
return workdir;
}
}

@ -4,51 +4,52 @@ package mightypork.gamecore.core.config;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import mightypork.gamecore.core.WorkDir;
import mightypork.gamecore.input.Key; import mightypork.gamecore.input.Key;
import mightypork.gamecore.input.KeyStroke; import mightypork.gamecore.input.KeyStroke;
import mightypork.utils.config.propmgr.Property; import mightypork.utils.config.propmgr.Property;
import mightypork.utils.config.propmgr.PropertyManager; import mightypork.utils.config.propmgr.PropertyManager;
import mightypork.utils.config.propmgr.PropertyStore; import mightypork.utils.config.propmgr.PropertyStore;
import mightypork.utils.config.propmgr.store.PropertyFile; import mightypork.utils.config.propmgr.store.PropertyFile;
import mightypork.utils.files.WorkDir;
import mightypork.utils.logging.Log; import mightypork.utils.logging.Log;
/** /**
* Settings repository. * Settings repository.
* *
* @author Ondřej Hruška (MightyPork) * @author Ondřej Hruška (MightyPork)
*/ */
public class Config { public class Config {
/** Array of configs registered for the app */
protected static Map<String, Config> configs = new HashMap<>(); protected static Map<String, Config> configs = new HashMap<>();
private final Map<String, KeyStrokeProperty> strokes = new HashMap<>(); private final Map<String, KeyStrokeProperty> strokes = new HashMap<>();
private final PropertyManager propertyManager; private final PropertyManager propertyManager;
/** /**
* Get a config from the static map, by given alias * Get a config from the static map, by given alias
* *
* @param alias alias * @param alias alias
* @return the config * @return the config
*/ */
public static Config forAlias(String alias) public static Config forAlias(String alias)
{ {
final Config c = configs.get(alias); final Config c = configs.get(alias);
if (c == null) { if (c == null) {
throw new IllegalArgumentException("There is no config with alias \"" + alias + "\""); throw new IllegalArgumentException("There is no config with alias \"" + alias + "\"");
} }
return c; return c;
} }
/** /**
* Register a config by alias. * Register a config by alias.
* *
* @param alias config alias * @param alias config alias
* @param config the config * @param config the config
*/ */
@ -57,14 +58,14 @@ public class Config {
if (configs.get(alias) != null) { if (configs.get(alias) != null) {
throw new IllegalArgumentException("The alias \"" + alias + "\" is already used."); throw new IllegalArgumentException("The alias \"" + alias + "\" is already used.");
} }
configs.put(alias, config); configs.put(alias, config);
} }
/** /**
* Initialize property manager for a file * Initialize property manager for a file
* *
* @param file config file, relative to workdir * @param file config file, relative to workdir
* @param headComment file comment * @param headComment file comment
*/ */
@ -72,22 +73,22 @@ public class Config {
{ {
this(new PropertyFile(WorkDir.getFile(file), headComment)); this(new PropertyFile(WorkDir.getFile(file), headComment));
} }
/** /**
* Initialize property manager for a given store * Initialize property manager for a given store
* *
* @param store property store backing the property manager * @param store property store backing the property manager
*/ */
public Config(PropertyStore store) public Config(PropertyStore store)
{ {
propertyManager = new PropertyManager(store); propertyManager = new PropertyManager(store);
} }
/** /**
* Add a keystroke property * Add a keystroke property
* *
* @param key key in config file * @param key key in config file
* @param defval default value (keystroke datastring) * @param defval default value (keystroke datastring)
* @param comment optional comment, can be null * @param comment optional comment, can be null
@ -98,11 +99,11 @@ public class Config {
strokes.put(prefixKeyStroke(key), kprop); strokes.put(prefixKeyStroke(key), kprop);
propertyManager.addProperty(kprop); propertyManager.addProperty(kprop);
} }
/** /**
* Add a boolean property (flag) * Add a boolean property (flag)
* *
* @param key key in config file * @param key key in config file
* @param defval default value * @param defval default value
* @param comment optional comment, can be null * @param comment optional comment, can be null
@ -111,11 +112,11 @@ public class Config {
{ {
propertyManager.addBoolean(key, defval, comment); propertyManager.addBoolean(key, defval, comment);
} }
/** /**
* Add an integer property * Add an integer property
* *
* @param key key in config file * @param key key in config file
* @param defval default value * @param defval default value
* @param comment optional comment, can be null * @param comment optional comment, can be null
@ -124,11 +125,11 @@ public class Config {
{ {
propertyManager.addInteger(key, defval, comment); propertyManager.addInteger(key, defval, comment);
} }
/** /**
* Add a double property * Add a double property
* *
* @param key key in config file * @param key key in config file
* @param defval default value * @param defval default value
* @param comment optional comment, can be null * @param comment optional comment, can be null
@ -137,11 +138,11 @@ public class Config {
{ {
propertyManager.addDouble(key, defval, comment); propertyManager.addDouble(key, defval, comment);
} }
/** /**
* Add a string property * Add a string property
* *
* @param key key in config file * @param key key in config file
* @param defval default value * @param defval default value
* @param comment optional comment, can be null * @param comment optional comment, can be null
@ -150,19 +151,19 @@ public class Config {
{ {
propertyManager.addString(key, defval, comment); propertyManager.addString(key, defval, comment);
} }
/** /**
* Add an arbitrary property (can be custom type) * Add an arbitrary property (can be custom type)
* *
* @param prop the property to add * @param prop the property to add
*/ */
public <T> void addProperty(Property<T> prop) public <T> void addProperty(Property<T> prop)
{ {
propertyManager.addProperty(prop); propertyManager.addProperty(prop);
} }
/** /**
* Load config from file * Load config from file
*/ */
@ -170,8 +171,8 @@ public class Config {
{ {
propertyManager.load(); propertyManager.load();
} }
/** /**
* Save config to file * Save config to file
*/ */
@ -180,13 +181,13 @@ public class Config {
Log.f3("Saving config."); Log.f3("Saving config.");
propertyManager.save(); propertyManager.save();
} }
/** /**
* Get an option for key * Get an option for key
* *
* @param key * @param key config key
* @return option value * @return option values
*/ */
public <T> T getValue(String key) public <T> T getValue(String key)
{ {
@ -194,18 +195,18 @@ public class Config {
if (propertyManager.getProperty(key) == null) { if (propertyManager.getProperty(key) == null) {
throw new IllegalArgumentException("No such property: " + key); throw new IllegalArgumentException("No such property: " + key);
} }
return propertyManager.getValue(key); return propertyManager.getValue(key);
} catch (final ClassCastException cce) { } catch (final ClassCastException cce) {
throw new RuntimeException("Property of incompatible type: " + key); throw new RuntimeException("Property of incompatible type: " + key);
} }
} }
/** /**
* Set option to a value. Call the save() method to make the change * Set option to a value. Call the save() method to make the change
* permanent. * permanent.
* *
* @param key option key * @param key option key
* @param value value to set * @param value value to set
*/ */
@ -214,14 +215,14 @@ public class Config {
if (propertyManager.getProperty(key) == null) { if (propertyManager.getProperty(key) == null) {
throw new IllegalArgumentException("No such property: " + key); throw new IllegalArgumentException("No such property: " + key);
} }
propertyManager.setValue(key, value); propertyManager.setValue(key, value);
} }
/** /**
* Add "key." before the given config file key * Add "key." before the given config file key
* *
* @param cfgKey config key * @param cfgKey config key
* @return key. + cfgKey * @return key. + cfgKey
*/ */
@ -229,11 +230,11 @@ public class Config {
{ {
return "key." + cfgKey; return "key." + cfgKey;
} }
/** /**
* Get keystroke for name * Get keystroke for name
* *
* @param cfgKey stroke identifier in config file * @param cfgKey stroke identifier in config file
* @return the stroke * @return the stroke
*/ */
@ -243,14 +244,14 @@ public class Config {
if (kp == null) { if (kp == null) {
throw new IllegalArgumentException("No such stroke: " + cfgKey); throw new IllegalArgumentException("No such stroke: " + cfgKey);
} }
return kp.getValue(); return kp.getValue();
} }
/** /**
* Set a keystroke for name * Set a keystroke for name
* *
* @param cfgKey stroke identifier in config file * @param cfgKey stroke identifier in config file
* @param key stroke key * @param key stroke key
* @param mod stroke modifiers * @param mod stroke modifiers
@ -261,7 +262,7 @@ public class Config {
if (kp == null) { if (kp == null) {
throw new IllegalArgumentException("No such stroke: " + cfgKey); throw new IllegalArgumentException("No such stroke: " + cfgKey);
} }
kp.getValue().setTo(key, mod); kp.getValue().setTo(key, mod);
} }
} }

@ -9,14 +9,14 @@ import mightypork.utils.annotations.Stub;
* Initialize config. To apply this initializer, you must extend it. That * Initialize config. To apply this initializer, you must extend it. That
* ensures that the workdir initializer has already finished when the code is * ensures that the workdir initializer has already finished when the code is
* executed (such as resolving a file path for the config file). * executed (such as resolving a file path for the config file).
* *
* @author Ondřej Hruška (MightyPork) * @author Ondřej Hruška (MightyPork)
*/ */
public abstract class InitTaskConfig extends InitTask { public abstract class InitTaskConfig extends InitTask {
/** /**
* Add a config with given alias * Add a config with given alias
* *
* @param alias config alias * @param alias config alias
* @param config config to add * @param config config to add
*/ */
@ -24,16 +24,16 @@ public abstract class InitTaskConfig extends InitTask {
{ {
Config.register(alias, config); Config.register(alias, config);
} }
/** /**
* Initialize the main config. * Initialize the main config.
* *
* @return the main config. * @return the main config.
*/ */
protected abstract Config buildConfig(); protected abstract Config buildConfig();
/** /**
* Initialize extra configs.<br> * Initialize extra configs.<br>
* the addConfig() method can be used to register configs. * the addConfig() method can be used to register configs.
@ -42,34 +42,34 @@ public abstract class InitTaskConfig extends InitTask {
protected void buildExtraConfigs() protected void buildExtraConfigs()
{ {
} }
// locked to encourage the use of the build* methods. // locked to encourage the use of the build* methods.
@Override @Override
public final void init() public final void init()
{ {
} }
@Override @Override
public final void run() public final void run()
{ {
addConfig("main", buildConfig()); addConfig("main", buildConfig());
buildExtraConfigs(); buildExtraConfigs();
} }
@Override @Override
public String getName() public String getName()
{ {
return "config"; return "config";
} }
@Override @Override
public String[] getDependencies() public String[] getDependencies()
{ {
return new String[] { "workdir" }; return new String[] { "workdir" };
} }
} }

@ -12,41 +12,48 @@ import mightypork.utils.config.propmgr.Property;
* The stored value must stay the same instance ({@link KeyStroke} is mutable).<br> * The stored value must stay the same instance ({@link KeyStroke} is mutable).<br>
* That ensures that bindings based on this keystroke are automatically updated * That ensures that bindings based on this keystroke are automatically updated
* when the settings change. * when the settings change.
* *
* @author Ondřej Hruška (MightyPork) * @author Ondřej Hruška (MightyPork)
*/ */
public class KeyStrokeProperty extends Property<KeyStroke> { public class KeyStrokeProperty extends Property<KeyStroke> {
/**
* Make a keystroke property
*
* @param key config key
* @param defaultValue default keystroke value
* @param comment property comment
*/
public KeyStrokeProperty(String key, KeyStroke defaultValue, String comment) public KeyStrokeProperty(String key, KeyStroke defaultValue, String comment)
{ {
super(key, defaultValue, comment); super(key, defaultValue, comment);
} }
@Override @Override
public void fromString(String string) public void fromString(String string)
{ {
if (string != null) { if (string != null) {
// keep the same instance // keep the same instance
final Key backup_key = value.getKey(); final Key backup_key = value.getKey();
final int backup_mod = value.getMod(); final int backup_mod = value.getMod();
value.loadFromString(string); value.loadFromString(string);
if (value.getKey() == Keys.NONE) { if (value.getKey() == Keys.NONE) {
value.setTo(backup_key, backup_mod); value.setTo(backup_key, backup_mod);
} }
} }
} }
@Override @Override
public String toString() public String toString()
{ {
return value.saveToString(); return value.saveToString();
} }
@Override @Override
public void setValue(Object value) public void setValue(Object value)
{ {

@ -8,16 +8,16 @@ import mightypork.utils.eventbus.events.flags.SingleReceiverEvent;
/** /**
* Request to execute given {@link Runnable} in main loop. * Request to execute given {@link Runnable} in main loop.
* *
* @author Ondřej Hruška (MightyPork) * @author Ondřej Hruška (MightyPork)
*/ */
@SingleReceiverEvent @SingleReceiverEvent
public class MainLoopRequest extends BusEvent<MainLoop> { public class MainLoopRequest extends BusEvent<MainLoop> {
private final Runnable task; private final Runnable task;
private final boolean priority; private final boolean priority;
/** /**
* @param task task to run on main thread in rendering context * @param task task to run on main thread in rendering context
*/ */
@ -25,8 +25,8 @@ public class MainLoopRequest extends BusEvent<MainLoop> {
{ {
this(task, false); this(task, false);
} }
/** /**
* @param task task to run on main thread in rendering context * @param task task to run on main thread in rendering context
* @param priority if true, skip other tasks in queue * @param priority if true, skip other tasks in queue
@ -36,8 +36,8 @@ public class MainLoopRequest extends BusEvent<MainLoop> {
this.task = task; this.task = task;
this.priority = priority; this.priority = priority;
} }
@Override @Override
public void handleBy(MainLoop handler) public void handleBy(MainLoop handler)
{ {

@ -10,10 +10,8 @@ import mightypork.utils.logging.Log;
* Shutdown event.<br> * Shutdown event.<br>
* This event is dispatched when the <code>App.shutdown()</code> method is * This event is dispatched when the <code>App.shutdown()</code> method is
* called. If no client consumes it, the shutdown will immediately follow.<br> * called. If no client consumes it, the shutdown will immediately follow.<br>
* This is a way to allow clients to abort the shutdown (ie. ask user to save * This is a way to allow clients to abort the shutdown (ie. ask to save game).
* game). After the game is saved, the <code>App.shutdown()</code> method can be *
* called again.
*
* @author Ondřej Hruška (MightyPork) * @author Ondřej Hruška (MightyPork)
*/ */
public class ShutdownEvent extends BusEvent<ShutdownListener> { public class ShutdownEvent extends BusEvent<ShutdownListener> {
@ -21,6 +19,11 @@ public class ShutdownEvent extends BusEvent<ShutdownListener> {
private final Runnable shutdownTask; private final Runnable shutdownTask;
/**
* Make a shutdown event
*
* @param doShutdown Task that does the actual shutdown
*/
public ShutdownEvent(Runnable doShutdown) public ShutdownEvent(Runnable doShutdown)
{ {
this.shutdownTask = doShutdown; this.shutdownTask = doShutdown;

@ -3,15 +3,15 @@ package mightypork.gamecore.core.events;
/** /**
* Quit request listener; implementing client can abort shutdown. * Quit request listener; implementing client can abort shutdown.
* *
* @author Ondřej Hruška (MightyPork) * @author Ondřej Hruška (MightyPork)
*/ */
public interface ShutdownListener { public interface ShutdownListener {
/** /**
* Intercept quit request.<br> * Intercept quit request.<br>
* Consume the event to abort shutdown (ie. ask user to save) * Consume the event to abort shutdown (ie. ask user to save)
* *
* @param event quit request event. * @param event quit request event.
*/ */
void onShutdown(ShutdownEvent event); void onShutdown(ShutdownEvent event);

@ -13,18 +13,18 @@ import mightypork.utils.logging.Log;
* Add a crash handler to the app.<br> * Add a crash handler to the app.<br>
* For customized crash message / crash dialog etc, override the * For customized crash message / crash dialog etc, override the
* uncaughtException() method. * uncaughtException() method.
* *
* @author Ondřej Hruška (MightyPork) * @author Ondřej Hruška (MightyPork)
*/ */
public class InitTaskCrashHandler extends InitTask implements UncaughtExceptionHandler { public class InitTaskCrashHandler extends InitTask implements UncaughtExceptionHandler {
@Override @Override
public void run() public void run()
{ {
Thread.setDefaultUncaughtExceptionHandler(this); Thread.setDefaultUncaughtExceptionHandler(this);
} }
@Override @Override
@Stub @Stub
public void uncaughtException(Thread thread, Throwable throwable) public void uncaughtException(Thread thread, Throwable throwable)
@ -32,8 +32,8 @@ public class InitTaskCrashHandler extends InitTask implements UncaughtExceptionH
Log.e("The game has crashed.", throwable); Log.e("The game has crashed.", throwable);
App.shutdown(); App.shutdown();
} }
@Override @Override
public String getName() public String getName()
{ {

@ -7,19 +7,19 @@ import mightypork.gamecore.graphics.GraphicsModule;
/** /**
* Setup main window. * Setup main window.
* *
* @author Ondřej Hruška (MightyPork) * @author Ondřej Hruška (MightyPork)
*/ */
public class InitTaskDisplay extends InitTask { public class InitTaskDisplay extends InitTask {
private int width = 800, height = 600, fps = 60; private int width = 800, height = 600, fps = 60;
private boolean resizable, fullscreen; private boolean resizable, fullscreen;
private String title = "Game"; private String title = "Game";
/** /**
* Set initial window size * Set initial window size
* *
* @param width width (px) * @param width width (px)
* @param height height (px) * @param height height (px)
*/ */
@ -28,70 +28,70 @@ public class InitTaskDisplay extends InitTask {
this.width = width; this.width = width;
this.height = height; this.height = height;
} }
/** /**
* Set whether the window should be resizable * Set whether the window should be resizable
* *
* @param resizable true for resizable * @param resizable true for resizable
*/ */
public void setResizable(boolean resizable) public void setResizable(boolean resizable)
{ {
this.resizable = resizable; this.resizable = resizable;
} }
/** /**
* Set window title * Set window title
* *
* @param title title text * @param title title text
*/ */
public void setTitle(String title) public void setTitle(String title)
{ {
this.title = title; this.title = title;
} }
/** /**
* Set desired framerate. * Set desired framerate.
* *
* @param fps FPS * @param fps FPS
*/ */
public void setTargetFps(int fps) public void setTargetFps(int fps)
{ {
this.fps = fps; this.fps = fps;
} }
/** /**
* Set whether the window should start in fullscreen * Set whether the window should start in fullscreen
* *
* @param fullscreen true for fullscreen * @param fullscreen true for fullscreen
*/ */
public void setFullscreen(boolean fullscreen) public void setFullscreen(boolean fullscreen)
{ {
this.fullscreen = fullscreen; this.fullscreen = fullscreen;
} }
@Override @Override
public void run() public void run()
{ {
final GraphicsModule gfx = app.getBackend().getGraphics(); final GraphicsModule gfx = app.getBackend().getGraphics();
gfx.setSize(width, height); gfx.setSize(width, height);
gfx.setResizable(resizable); gfx.setResizable(resizable);
gfx.setTitle(title); gfx.setTitle(title);
gfx.setTargetFps(fps); gfx.setTargetFps(fps);
if (fullscreen) gfx.setFullscreen(true); if (fullscreen) gfx.setFullscreen(true);
} }
@Override @Override
public String getName() public String getName()
{ {
return "display"; return "display";
} }
} }

@ -15,24 +15,24 @@ import mightypork.utils.math.algo.Move;
/** /**
* Register extra ionizables added by the game library (non-native ION types).<br> * Register extra ionizables added by the game library (non-native ION types).<br>
* This initializer can be called anywhere in the initialization sequence. * This initializer can be called anywhere in the initialization sequence.
* *
* @author Ondřej Hruška (MightyPork) * @author Ondřej Hruška (MightyPork)
*/ */
public class InitTaskIonizables extends InitTask { public class InitTaskIonizables extends InitTask {
@Override @Override
public void run() public void run()
{ {
Ion.registerIndirect(255, new IonizerBinary<Coord>() { Ion.registerIndirect(255, new IonizerBinary<Coord>() {
@Override @Override
public void save(Coord object, IonOutput out) throws IOException public void save(Coord object, IonOutput out) throws IOException
{ {
out.writeInt(object.x); out.writeInt(object.x);
out.writeInt(object.y); out.writeInt(object.y);
} }
@Override @Override
public Coord load(IonInput in) throws IOException public Coord load(IonInput in) throws IOException
{ {
@ -40,19 +40,19 @@ public class InitTaskIonizables extends InitTask {
final int y = in.readInt(); final int y = in.readInt();
return new Coord(x, y); return new Coord(x, y);
} }
}); });
Ion.registerIndirect(254, new IonizerBinary<Move>() { Ion.registerIndirect(254, new IonizerBinary<Move>() {
@Override @Override
public void save(Move object, IonOutput out) throws IOException public void save(Move object, IonOutput out) throws IOException
{ {
out.writeInt(object.x()); out.writeInt(object.x());
out.writeInt(object.y()); out.writeInt(object.y());
} }
@Override @Override
public Move load(IonInput in) throws IOException public Move load(IonInput in) throws IOException
{ {
@ -60,15 +60,15 @@ public class InitTaskIonizables extends InitTask {
final int y = in.readInt(); final int y = in.readInt();
return new Move(x, y); return new Move(x, y);
} }
}); });
} }
@Override @Override
public String getName() public String getName()
{ {
return "ion"; return "ion";
} }
} }

@ -5,7 +5,7 @@ import java.io.File;
import java.util.logging.Level; import java.util.logging.Level;
import mightypork.gamecore.core.InitTask; import mightypork.gamecore.core.InitTask;
import mightypork.gamecore.core.WorkDir; import mightypork.utils.files.WorkDir;
import mightypork.utils.logging.Log; import mightypork.utils.logging.Log;
import mightypork.utils.logging.writers.LogWriter; import mightypork.utils.logging.writers.LogWriter;
import mightypork.utils.string.StringUtil; import mightypork.utils.string.StringUtil;
@ -14,36 +14,36 @@ import mightypork.utils.string.StringUtil;
/** /**
* Init main logger and console log printing.<br> * Init main logger and console log printing.<br>
* Must be called after workdir is initialized. * Must be called after workdir is initialized.
* *
* @author Ondřej Hruška (MightyPork) * @author Ondřej Hruška (MightyPork)
*/ */
public class InitTaskLog extends InitTask { public class InitTaskLog extends InitTask {
private String logDir = "log"; private String logDir = "log";
private String logName = "runtime"; private String logName = "runtime";
private int archiveCount = 5; private int archiveCount = 5;
private Level levelWrite = Level.ALL; private Level levelWrite = Level.ALL;
private Level levelPrint = Level.ALL; private Level levelPrint = Level.ALL;
/** /**
* Set log directory (relative to workdir).<br> * Set log directory (relative to workdir).<br>
* Defaults to "log". * Defaults to "log".
* *
* @param logDir log directory. * @param logDir log directory.
*/ */
public void setLogDir(String logDir) public void setLogDir(String logDir)
{ {
this.logDir = logDir; this.logDir = logDir;
} }
/** /**
* Set log name. This name is used as a prefix for archived log files.<br> * Set log name. This name is used as a prefix for archived log files.<br>
* Should contain only valid filename characters.<br> * Should contain only valid filename characters.<br>
* Defaults to "runtime". * Defaults to "runtime".
* *
* @param logName log name * @param logName log name
*/ */
public void setLogName(String logName) public void setLogName(String logName)
@ -51,28 +51,28 @@ public class InitTaskLog extends InitTask {
if (!StringUtil.isValidFilenameString(logName)) { if (!StringUtil.isValidFilenameString(logName)) {
throw new IllegalArgumentException("Invalid log name."); throw new IllegalArgumentException("Invalid log name.");
} }
this.logName = logName; this.logName = logName;
} }
/** /**
* Set number of logs to keep in the logs directory.<br> * Set number of logs to keep in the logs directory.<br>
* Set to 0 to keep just the last log, -1 to keep unlimited number of logs.<br> * Set to 0 to keep just the last log, -1 to keep unlimited number of logs.<br>
* Defaults to 5. * Defaults to 5.
* *
* @param archiveCount logs to keep * @param archiveCount logs to keep
*/ */
public void setArchiveCount(int archiveCount) public void setArchiveCount(int archiveCount)
{ {
this.archiveCount = archiveCount; this.archiveCount = archiveCount;
} }
/** /**
* Set logging levels (minimal level of message to be accepted)<br> * Set logging levels (minimal level of message to be accepted)<br>
* Defaults to ALL, ALL. * Defaults to ALL, ALL.
* *
* @param levelWrite level for writing to file * @param levelWrite level for writing to file
* @param levelPrint level for writing to stdout / stderr * @param levelPrint level for writing to stdout / stderr
*/ */
@ -81,8 +81,8 @@ public class InitTaskLog extends InitTask {
this.levelWrite = levelWrite; this.levelWrite = levelWrite;
this.levelPrint = levelPrint; this.levelPrint = levelPrint;
} }
@Override @Override
public void run() public void run()
{ {
@ -91,15 +91,15 @@ public class InitTaskLog extends InitTask {
Log.setLevel(levelWrite); Log.setLevel(levelWrite);
Log.setSysoutLevel(levelPrint); Log.setSysoutLevel(levelPrint);
} }
@Override @Override
public String getName() public String getName()
{ {
return "log"; return "log";
} }
@Override @Override
public String[] getDependencies() public String[] getDependencies()
{ {

@ -5,47 +5,47 @@ import java.io.IOException;
import mightypork.gamecore.core.InitTask; import mightypork.gamecore.core.InitTask;
import mightypork.gamecore.core.OptionalInitTask; import mightypork.gamecore.core.OptionalInitTask;
import mightypork.gamecore.core.WorkDir; import mightypork.utils.files.WorkDir;
import mightypork.utils.logging.Log; import mightypork.utils.logging.Log;
/** /**
* initializer task that writes a system info header to the log file.<br> * initializer task that writes a system info header to the log file.<br>
* Must be called after log is initialized. * Must be called after log is initialized.
* *
* @author Ondřej Hruška (MightyPork) * @author Ondřej Hruška (MightyPork)
*/ */
@OptionalInitTask @OptionalInitTask
public class InitTaskLogHeader extends InitTask { public class InitTaskLogHeader extends InitTask {
@Override @Override
public void run() public void run()
{ {
String txt = ""; String txt = "";
txt += "\n### SYSTEM INFO ###\n\n"; txt += "\n### SYSTEM INFO ###\n\n";
txt += " Platform ...... " + System.getProperty("os.name") + "\n"; txt += " Platform ...... " + System.getProperty("os.name") + "\n";
txt += " Runtime ....... " + System.getProperty("java.runtime.name") + "\n"; txt += " Runtime ....... " + System.getProperty("java.runtime.name") + "\n";
txt += " Java .......... " + System.getProperty("java.version") + "\n"; txt += " Java .......... " + System.getProperty("java.version") + "\n";
txt += " Launch path ... " + System.getProperty("user.dir") + "\n"; txt += " Launch path ... " + System.getProperty("user.dir") + "\n";
try { try {
txt += " Workdir ....... " + WorkDir.getWorkDir().getCanonicalPath() + "\n"; txt += " Workdir ....... " + WorkDir.getBaseDir().getCanonicalPath() + "\n";
} catch (final IOException e) { } catch (final IOException e) {
Log.e(e); Log.e(e);
} }
Log.i(txt); Log.i(txt);
} }
@Override @Override
public String getName() public String getName()
{ {
return "log_header"; return "log_header";
} }
@Override @Override
public String[] getDependencies() public String[] getDependencies()
{ {

@ -10,25 +10,25 @@ import javax.swing.JOptionPane;
import mightypork.gamecore.core.App; import mightypork.gamecore.core.App;
import mightypork.gamecore.core.InitTask; import mightypork.gamecore.core.InitTask;
import mightypork.gamecore.core.WorkDir;
import mightypork.utils.annotations.Stub; import mightypork.utils.annotations.Stub;
import mightypork.utils.files.InstanceLock; import mightypork.utils.files.InstanceLock;
import mightypork.utils.files.WorkDir;
import mightypork.utils.logging.Log; import mightypork.utils.logging.Log;
/** /**
* Initializer that takes care of setting up the proper workdir. * Initializer that takes care of setting up the proper workdir.
* *
* @author Ondřej Hruška (MightyPork) * @author Ondřej Hruška (MightyPork)
*/ */
public class InitTaskWorkdir extends InitTask { public class InitTaskWorkdir extends InitTask {
private File workdirPath; private File workdirPath;
private boolean doLock; private boolean doLock;
private String lockFile = ".lock"; private String lockFile = ".lock";
private final Map<String, String> namedPaths = new HashMap<>(); private final Map<String, String> namedPaths = new HashMap<>();
/** /**
* @param workdir path to the working directory * @param workdir path to the working directory
* @param lock whether to lock the directory (single instance mode) * @param lock whether to lock the directory (single instance mode)
@ -38,45 +38,45 @@ public class InitTaskWorkdir extends InitTask {
this.workdirPath = workdir; this.workdirPath = workdir;
this.doLock = lock; this.doLock = lock;
} }
/** /**
* Set workdir root path * Set workdir root path
* *
* @param path workdir path * @param path workdir path
*/ */
public void setWorkdirPath(File path) public void setWorkdirPath(File path)
{ {
this.workdirPath = path; this.workdirPath = path;
} }
/** /**
* Set whether the workdir should be locked when the app is running, to * Set whether the workdir should be locked when the app is running, to
* prevent other instances from running simultaneously. * prevent other instances from running simultaneously.
* *
* @param lock * @param lock true to use lock
*/ */
public void setInstanceLock(boolean lock) public void setInstanceLock(boolean lock)
{ {
this.doLock = lock; this.doLock = lock;
} }
/** /**
* Set name of the lock file. * Set name of the lock file.
* *
* @param lockFile * @param lockFile lock file name
*/ */
public void setLockFileName(String lockFile) public void setLockFileName(String lockFile)
{ {
this.lockFile = lockFile; this.lockFile = lockFile;
} }
/** /**
* Add a named path * Add a named path
* *
* @param alias path alias (snake_case) * @param alias path alias (snake_case)
* @param path path (relative to the workdir) * @param path path (relative to the workdir)
*/ */
@ -84,13 +84,13 @@ public class InitTaskWorkdir extends InitTask {
{ {
namedPaths.put(alias, path); namedPaths.put(alias, path);
} }
@Override @Override
public void run() public void run()
{ {
WorkDir.init(workdirPath); WorkDir.setBaseDir(workdirPath);
// lock working directory // lock working directory
if (doLock) { if (doLock) {
final File lock = WorkDir.getFile(lockFile); final File lock = WorkDir.getFile(lockFile);
@ -99,13 +99,13 @@ public class InitTaskWorkdir extends InitTask {
return; return;
} }
} }
for (final Entry<String, String> e : namedPaths.entrySet()) { for (final Entry<String, String> e : namedPaths.entrySet()) {
WorkDir.addPath(e.getKey(), e.getValue()); WorkDir.addPath(e.getKey(), e.getValue());
} }
} }
/** /**
* Called when the lock file could not be obtained (cannot write or already * Called when the lock file could not be obtained (cannot write or already
* exists).<br> * exists).<br>
@ -115,20 +115,20 @@ public class InitTaskWorkdir extends InitTask {
protected void onLockError() protected void onLockError()
{ {
Log.e("Could not obtain lock file.\nOnly one instance can run at a time."); Log.e("Could not obtain lock file.\nOnly one instance can run at a time.");
//@formatter:off //@formatter:off
JOptionPane.showMessageDialog( JOptionPane.showMessageDialog(
null, null,
"Another instance is already running.\n(Delete the "+lockFile +" file in the working directory to override)", "Another instance is already running.\n(Delete the "+lockFile +" file in the working directory to override)",
"Lock Error", "Lock Error",
JOptionPane.ERROR_MESSAGE JOptionPane.ERROR_MESSAGE
); );
//@formatter:on //@formatter:on
App.shutdown(); App.shutdown();
} }
@Override @Override
public String getName() public String getName()
{ {

@ -2,19 +2,19 @@ package mightypork.gamecore.core.plugins.screenshot;
import mightypork.gamecore.core.InitTask; import mightypork.gamecore.core.InitTask;
import mightypork.gamecore.core.WorkDir; import mightypork.utils.files.WorkDir;
/** /**
* Register screenshot plugin to the App. * Register screenshot plugin to the App.
* *
* @author Ondřej Hruška (MightyPork) * @author Ondřej Hruška (MightyPork)
*/ */
public class InitTaskPluginScreenshot extends InitTask { public class InitTaskPluginScreenshot extends InitTask {
private String screenshotDir; private String screenshotDir;
/** /**
* Initialize to use the "screenshots" directory * Initialize to use the "screenshots" directory
*/ */
@ -22,49 +22,49 @@ public class InitTaskPluginScreenshot extends InitTask {
{ {
this("screenshots"); this("screenshots");
} }
/** /**
* Initialize to use the given directory for saving. * Initialize to use the given directory for saving.
* *
* @param dir screenshot dir (relative to workdir) * @param dir screenshot dir (relative to workdir)
*/ */
public InitTaskPluginScreenshot(String dir) public InitTaskPluginScreenshot(String dir)
{ {
this.screenshotDir = dir; this.screenshotDir = dir;
} }
/** /**
* Set screenshot directory * Set screenshot directory
* *
* @param dir screenshot dir (relative to workdir) * @param dir screenshot dir (relative to workdir)
*/ */
public void setScreenshotDir(String dir) public void setScreenshotDir(String dir)
{ {
this.screenshotDir = dir; this.screenshotDir = dir;
} }
@Override @Override
public void run() public void run()
{ {
WorkDir.addPath("_screenshot_dir", screenshotDir); WorkDir.addPath("_screenshot_dir", screenshotDir);
app.addPlugin(new ScreenshotPlugin()); app.addPlugin(new ScreenshotPlugin());
} }
@Override @Override
public String getName() public String getName()
{ {
return "plugin_screenshot"; return "plugin_screenshot";
} }
@Override @Override
public String[] getDependencies() public String[] getDependencies()
{ {
return new String[] { "workdir" }; return new String[] { "workdir" };
} }
} }

@ -11,18 +11,18 @@ import mightypork.utils.Support;
* This plugin waits for a {@link ScreenshotRequest} event.<br> * This plugin waits for a {@link ScreenshotRequest} event.<br>
* Upon receiving it, a screenshot is captured and written to file * Upon receiving it, a screenshot is captured and written to file
* asynchronously. * asynchronously.
* *
* @author Ondřej Hruška (MightyPork) * @author Ondřej Hruška (MightyPork)
*/ */
public class ScreenshotPlugin extends AppPlugin { public class ScreenshotPlugin extends AppPlugin {
/** /**
* Take screenshot. Called by the trigger event. * Take screenshot. Called by the trigger event.
*/ */
void takeScreenshot() void takeScreenshot()
{ {
App.bus().send(new MainLoopRequest(new Runnable() { App.bus().send(new MainLoopRequest(new Runnable() {
@Override @Override
public void run() public void run()
{ {

@ -7,16 +7,16 @@ import mightypork.utils.eventbus.events.flags.SingleReceiverEvent;
/** /**
* Event used to request screenshot capture. * Event used to request screenshot capture.
* *
* @author MightyPork * @author MightyPork
*/ */
@SingleReceiverEvent @SingleReceiverEvent
public class ScreenshotRequest extends BusEvent<ScreenshotPlugin> { public class ScreenshotRequest extends BusEvent<ScreenshotPlugin> {
@Override @Override
protected void handleBy(ScreenshotPlugin handler) protected void handleBy(ScreenshotPlugin handler)
{ {
handler.takeScreenshot(); handler.takeScreenshot();
} }
} }

@ -5,9 +5,9 @@ import java.io.File;
import java.io.IOException; import java.io.IOException;
import mightypork.gamecore.core.App; import mightypork.gamecore.core.App;
import mightypork.gamecore.core.WorkDir;
import mightypork.gamecore.graphics.Screenshot; import mightypork.gamecore.graphics.Screenshot;
import mightypork.utils.Support; import mightypork.utils.Support;
import mightypork.utils.files.WorkDir;
import mightypork.utils.logging.Log; import mightypork.utils.logging.Log;
@ -15,14 +15,14 @@ import mightypork.utils.logging.Log;
* Task that takes screenshot and asynchronously saves it to a file.<br> * Task that takes screenshot and asynchronously saves it to a file.<br>
* Can be run in a separate thread, but must be instantiated in the render * Can be run in a separate thread, but must be instantiated in the render
* thread. * thread.
* *
* @author MightyPork * @author MightyPork
*/ */
public class TaskTakeScreenshot implements Runnable { public class TaskTakeScreenshot implements Runnable {
private final Screenshot scr; private final Screenshot scr;
/** /**
* Take screenshot. Must be called in render thread. * Take screenshot. Must be called in render thread.
*/ */
@ -30,16 +30,16 @@ public class TaskTakeScreenshot implements Runnable {
{ {
scr = App.gfx().takeScreenshot(); scr = App.gfx().takeScreenshot();
} }
@Override @Override
public void run() public void run()
{ {
// generate unique filename // generate unique filename
final File file = getScreenshotFile(); final File file = getScreenshotFile();
Log.f3("Saving screenshot to file: " + file); Log.f3("Saving screenshot to file: " + file);
// save to disk // save to disk
try { try {
scr.save(file); scr.save(file);
@ -47,8 +47,8 @@ public class TaskTakeScreenshot implements Runnable {
Log.e("Failed to save screenshot.", e); Log.e("Failed to save screenshot.", e);
} }
} }
/** /**
* @return File to save the screenshot to. * @return File to save the screenshot to.
*/ */
@ -57,8 +57,8 @@ public class TaskTakeScreenshot implements Runnable {
final String fname = getBaseFilename(); final String fname = getBaseFilename();
return findFreeFile(fname); return findFreeFile(fname);
} }
/** /**
* @return directory for screenshots * @return directory for screenshots
*/ */
@ -66,23 +66,23 @@ public class TaskTakeScreenshot implements Runnable {
{ {
return WorkDir.getDir("_screenshot_dir"); return WorkDir.getDir("_screenshot_dir");
} }
/** /**
* Get base filename for the screenshot, without extension. * Get base filename for the screenshot, without extension.
* *
* @return filename * @return filename
*/ */
protected String getBaseFilename() protected String getBaseFilename()
{ {
return Support.getTime("yyyy-MM-dd_HH-mm-ss"); return Support.getTime("yyyy-MM-dd_HH-mm-ss");
} }
/** /**
* Find first free filename for the screenshot, by adding -NUMBER after the * Find first free filename for the screenshot, by adding -NUMBER after the
* base filename and before extension. * base filename and before extension.
* *
* @param base_name base filename * @param base_name base filename
* @return full path to screenshot file * @return full path to screenshot file
*/ */
@ -97,5 +97,5 @@ public class TaskTakeScreenshot implements Runnable {
} }
return file; return file;
} }
} }

@ -5,6 +5,12 @@ import mightypork.utils.eventbus.BusEvent;
import mightypork.utils.eventbus.events.flags.SingleReceiverEvent; import mightypork.utils.eventbus.events.flags.SingleReceiverEvent;
/**
* Event that will request fullscreen toggle in the graphics module.<br>
* FIXME the usefullness of this event is dubious.
*
* @author Ondřej Hruška (MightyPork)
*/
@SingleReceiverEvent @SingleReceiverEvent
public class FullscreenToggleRequest extends BusEvent<GraphicsModule> { public class FullscreenToggleRequest extends BusEvent<GraphicsModule> {

@ -2,6 +2,7 @@ package mightypork.gamecore.graphics;
import mightypork.gamecore.core.BackendModule; import mightypork.gamecore.core.BackendModule;
import mightypork.gamecore.graphics.fonts.DeferredFont;
import mightypork.gamecore.graphics.textures.DeferredTexture; import mightypork.gamecore.graphics.textures.DeferredTexture;
import mightypork.gamecore.graphics.textures.TxQuad; import mightypork.gamecore.graphics.textures.TxQuad;
import mightypork.gamecore.gui.events.ViewportChangeEvent; import mightypork.gamecore.gui.events.ViewportChangeEvent;
@ -17,388 +18,400 @@ import mightypork.utils.math.timing.FpsMeter;
* Render and display backend module.<br> * Render and display backend module.<br>
* This module takes care of setting and getting screen size and parameters, * This module takes care of setting and getting screen size and parameters,
* drawing on screen and timing render frames. * drawing on screen and timing render frames.
* *
* @author MightyPork * @author MightyPork
*/ */
public abstract class GraphicsModule extends BackendModule { public abstract class GraphicsModule extends BackendModule {
/** X axis vector */
protected static final VectConst AXIS_X = Vect.make(1, 0, 0); protected static final VectConst AXIS_X = Vect.make(1, 0, 0);
/** Y axis vector */
protected static final VectConst AXIS_Y = Vect.make(0, 1, 0); protected static final VectConst AXIS_Y = Vect.make(0, 1, 0);
/** Z axis vector */
protected static final VectConst AXIS_Z = Vect.make(0, 0, 1); protected static final VectConst AXIS_Z = Vect.make(0, 0, 1);
/** /**
* Set drawing color * Set drawing color
* *
* @param color color * @param color color
*/ */
public abstract void setColor(Color color); public abstract void setColor(Color color);
/** /**
* Set drawing color, adjust alpha * Set drawing color, adjust alpha
* *
* @param color color * @param color color
* @param alpha alpha multiplier * @param alpha alpha multiplier
*/ */
public abstract void setColor(Color color, double alpha); public abstract void setColor(Color color, double alpha);
/** /**
* Translate by x, y * Translate by x, y
* *
* @param x x offset * @param x x offset
* @param y y offset * @param y y offset
*/ */
public abstract void translate(double x, double y); public abstract void translate(double x, double y);
/** /**
* Translate by x, y, z * Translate by x, y, z
* *
* @param x x offset * @param x x offset
* @param y y offset * @param y y offset
* @param z z offset * @param z z offset
*/ */
public abstract void translate(double x, double y, double z); public abstract void translate(double x, double y, double z);
/** /**
* Translate by offset vector * Translate by offset vector
* *
* @param offset offset coordinate * @param offset offset coordinate
*/ */
public abstract void translate(Vect offset); public abstract void translate(Vect offset);
/** /**
* Translate by offset vector, ignore Z * Translate by offset vector, ignore Z
* *
* @param offset offset coordinate * @param offset offset coordinate
*/ */
public abstract void translateXY(Vect offset); public abstract void translateXY(Vect offset);
/** /**
* Set scale for translations and coordinates * Set scale for translations and coordinates
* *
* @param x x scale * @param x x scale
* @param y y scale * @param y y scale
*/ */
public abstract void scale(double x, double y); public abstract void scale(double x, double y);
/** /**
* Set scale for translations and coordinates * Set scale for translations and coordinates
* *
* @param x x scale * @param x x scale
* @param y y scale * @param y y scale
* @param z z scale * @param z z scale
*/ */
public abstract void scale(double x, double y, double z); public abstract void scale(double x, double y, double z);
/** /**
* Set scale for translations and coordinates * Set scale for translations and coordinates
* *
* @param scale vector * @param scale vector
*/ */
public abstract void scale(Vect scale); public abstract void scale(Vect scale);
/** /**
* Set scale for translations and coordinates (same value for X and Y scale) * Set scale for translations and coordinates (same value for X and Y scale)
* *
* @param scale scaling factor * @param scale scaling factor
*/ */
public abstract void scaleXY(double scale); public abstract void scaleXY(double scale);
/** /**
* Set X scale for translations and coordinates * Set X scale for translations and coordinates
* *
* @param scale scaling factor * @param scale scaling factor
*/ */
public abstract void scaleX(double scale); public abstract void scaleX(double scale);
/** /**
* Set Y scale for translations and coordinates * Set Y scale for translations and coordinates
* *
* @param scale scaling factor * @param scale scaling factor
*/ */
public abstract void scaleY(double scale); public abstract void scaleY(double scale);
/** /**
* Set Z scale for translations and coordinates * Set Z scale for translations and coordinates
* *
* @param scale scaling factor * @param scale scaling factor
*/ */
public abstract void scaleZ(double scale); public abstract void scaleZ(double scale);
/** /**
* Rotate coordinate system around X axis * Rotate coordinate system around X axis
* *
* @param angle rotation (in degrees) * @param angle rotation (in degrees)
*/ */
public abstract void rotateX(double angle); public abstract void rotateX(double angle);
/** /**
* Rotate coordinate system around Y axis * Rotate coordinate system around Y axis
* *
* @param angle rotation (in degrees) * @param angle rotation (in degrees)
*/ */
public abstract void rotateY(double angle); public abstract void rotateY(double angle);
/** /**
* Rotate coordinate system around Z axis * Rotate coordinate system around Z axis
* *
* @param angle rotation (in degrees) * @param angle rotation (in degrees)
*/ */
public abstract void rotateZ(double angle); public abstract void rotateZ(double angle);
/** /**
* Rotate coordinate system around given axis * Rotate coordinate system around given axis
* *
* @param angle rotation angle * @param angle rotation angle
* @param axis rotation axis (unit vector) * @param axis rotation axis (unit vector)
*/ */
public abstract void rotate(double angle, Vect axis); public abstract void rotate(double angle, Vect axis);
/** /**
* Store render state on stack<br> * Store render state on stack<br>
* This includes pushGeometry and pushColor. * This includes pushGeometry and pushColor.
*/ */
public abstract void pushState(); public abstract void pushState();
/** /**
* Restore state from stack (must be pushed first)<br> * Restore state from stack (must be pushed first)<br>
* This includes popColor and popGeometry. * This includes popColor and popGeometry.
*/ */
public abstract void popState(); public abstract void popState();
/** /**
* Store current rotation and translation on stack * Store current rotation and translation on stack
*/ */
public abstract void pushGeometry(); public abstract void pushGeometry();
/** /**
* Restore rotation and translation from stack * Restore rotation and translation from stack
*/ */
public abstract void popGeometry(); public abstract void popGeometry();
/** /**
* Store color on stack (so it can later be restored) * Store color on stack (so it can later be restored)
*/ */
public abstract void pushColor(); public abstract void pushColor();
/** /**
* Restore color from stack (must be pushed first) * Restore color from stack (must be pushed first)
*/ */
public abstract void popColor(); public abstract void popColor();
/** /**
* Render 2D quad with currently set color * Render 2D quad with currently set color
* *
* @param rect drawn rect * @param rect drawn rect
*/ */
public abstract void quad(Rect rect); public abstract void quad(Rect rect);
/** /**
* Render 2D quad with given color.<br> * Render 2D quad with given color.<br>
* This may change current drawing color. * This may change current drawing color.
* *
* @param rect rectangle * @param rect rectangle
* @param color draw color * @param color draw color
*/ */
public abstract void quad(Rect rect, Color color); public abstract void quad(Rect rect, Color color);
/** /**
* Render 2D quad with gradient.<br> * Render 2D quad with gradient.<br>
* This may change current drawing color. * This may change current drawing color.
* *
* @param rect rectangle * @param rect rectangle
* @param grad gradient * @param grad gradient
*/ */
public abstract void quad(Rect rect, Grad grad); public abstract void quad(Rect rect, Grad grad);
/** /**
* Render textured quad with current color * Render textured quad with current color
* *
* @param rect rectangle to draw * @param rect rectangle to draw
* @param txquad texture quad * @param txquad texture quad
*/ */
public abstract void quad(Rect rect, TxQuad txquad); public abstract void quad(Rect rect, TxQuad txquad);
/** /**
* Render textured quad with given color * Render textured quad with given color
* *
* @param rect rectangle to draw * @param rect rectangle to draw
* @param txquad texture instance * @param txquad texture instance
* @param color color tint * @param color color tint
*/ */
public abstract void quad(Rect rect, TxQuad txquad, Color color); public abstract void quad(Rect rect, TxQuad txquad, Color color);
/** /**
* Setup projection for 2D graphics, using current scren size * Setup projection for 2D graphics, using current screen size
*/ */
public abstract void setupProjection(); public abstract void setupProjection();
/** /**
* Get backend-flavoured lazy texture * Get backend-flavoured deferred texture. This should support PNG images.
* *
* @param path path to texture * @param path path to texture
* @return the lazy texture * @return the deferred font
*/ */
public abstract DeferredTexture getLazyTexture(String path); public abstract DeferredTexture createDeferredTexture(String path);
/**
* Get backend-flavoured deferred font. This should support TTF fonts.
*
* @param path path to font, or font name in the system
* @return the deferred font
*/
public abstract DeferredFont createDeferredFont(String path);
/** /**
* Set target fps (for syncing in endFrame() call).<br> * Set target fps (for syncing in endFrame() call).<br>
* With vsync enabled, the target fps may not be met. * With vsync enabled, the target fps may not be met.
* *
* @param fps requested fps * @param fps requested fps
*/ */
public abstract void setTargetFps(int fps); public abstract void setTargetFps(int fps);
/** /**
* Set fullscreen. The fullscreen state will be changed when possible (eg. * Set fullscreen. The fullscreen state will be changed when possible (eg.
* at the end of the current frame) and a {@link ViewportChangeEvent} will * at the end of the current frame) and a {@link ViewportChangeEvent} will
* be fired. * be fired.
* *
* @param fs true for fullscreen * @param fs true for fullscreen
*/ */
public abstract void setFullscreen(boolean fs); public abstract void setFullscreen(boolean fs);
/** /**
* Request fullscreen toggle. See setFullscreen() for more info) * Request fullscreen toggle. See setFullscreen() for more info)
*/ */
public abstract void switchFullscreen(); public abstract void switchFullscreen();
/** /**
* Get fullscreen state (note that methods changing fullscreen may not have * Get fullscreen state (note that methods changing fullscreen may not have
* immediate effect, so this method may report the old state if the * immediate effect, so this method may report the old state if the
* fullscreen state has not yet been changed). * fullscreen state has not yet been changed).
* *
* @return is fullscreen * @return is fullscreen
*/ */
public abstract boolean isFullscreen(); public abstract boolean isFullscreen();
/** /**
* Take screenshot (expensive processing should be done in separate thread * Take screenshot (expensive processing should be done in separate thread
* when screenshot is saved).<br> * when screenshot is saved).<br>
* This method is utilized by the Screenshot plugin. * This method is utilized by the Screenshot plugin.
* *
* @return screenshot object * @return screenshot object
*/ */
public abstract Screenshot takeScreenshot(); public abstract Screenshot takeScreenshot();
/** /**
* Start a render frame - clear buffers, prepare rendering context etc. * Start a render frame - clear buffers, prepare rendering context etc.
*/ */
public abstract void beginFrame(); public abstract void beginFrame();
/** /**
* End a render frame: flip buffers, sync to fps... * End a render frame: flip buffers, sync to fps...
*/ */
public abstract void endFrame(); public abstract void endFrame();
/** /**
* Set display dimensions * Set display dimensions
* *
* @param width display width (pixels) * @param width display width (pixels)
* @param height display height (pixels) * @param height display height (pixels)
*/ */
public abstract void setSize(int width, int height); public abstract void setSize(int width, int height);
/** /**
* Set window titlebar text * Set window titlebar text
* *
* @param title titlebar text * @param title titlebar text
*/ */
public abstract void setTitle(String title); public abstract void setTitle(String title);
/** /**
* Enable or disable VSync * Enable or disable VSync
* *
* @param vsync true for vsync enabled * @param vsync true for vsync enabled
*/ */
public abstract void setVSync(boolean vsync); public abstract void setVSync(boolean vsync);
/** /**
* Set window resizable / fixed * Set window resizable / fixed
* *
* @param resizable true for resizable * @param resizable true for resizable
*/ */
public abstract void setResizable(boolean resizable); public abstract void setResizable(boolean resizable);
/** /**
* Get screen rect. Should always return the same Rect instance. * Get screen rect. Should always return the same Rect instance.
* *
* @return the rect * @return the rect
*/ */
public abstract Rect getRect(); public abstract Rect getRect();
/** /**
* Get current FPS (eg. measured by a {@link FpsMeter}) * Get current FPS (eg. measured by a {@link FpsMeter})
* *
* @return current FPS * @return current FPS
*/ */
public abstract long getFps(); public abstract long getFps();
/** /**
* Get screen center. Should always return the same Vect instance. * Get screen center. Should always return the same {@link Vect} instance.
* *
* @return screen center. * @return screen center.
*/ */
public abstract Vect getCenter(); public abstract Vect getCenter();
/** /**
* Get screen size. Should always return the same Vect instance. * Get screen size. Should always return the same {@link Vect} instance.
* *
* @return size * @return size
*/ */
public abstract Vect getSize(); public abstract Vect getSize();
/** /**
* @return screen width * @return screen width
*/ */
public abstract int getWidth(); public abstract int getWidth();
/** /**
* @return screen height * @return screen height
*/ */

@ -3,14 +3,14 @@ package mightypork.gamecore.graphics;
/** /**
* Can be rendered * Can be rendered
* *
* @author Ondřej Hruška (MightyPork) * @author Ondřej Hruška (MightyPork)
*/ */
public interface Renderable { public interface Renderable {
/** /**
* Render on screen. * Render on screen.
*/ */
void render(); void render();
} }

@ -18,15 +18,15 @@ import java.io.IOException;
* Once created (passing byte buffer in constructor), the Screenshot should be * Once created (passing byte buffer in constructor), the Screenshot should be
* safe to process (call the save() method) in separate thread. * safe to process (call the save() method) in separate thread.
* </p> * </p>
* *
* @author MightyPork * @author MightyPork
*/ */
public interface Screenshot { public interface Screenshot {
/** /**
* Process byte buffer and write image to a file.<br> * Process byte buffer and write image to a file.<br>
* Image can be cached for future save. * Image can be cached for future save.
* *
* @param file target file * @param file target file
* @throws IOException on error writing to file * @throws IOException on error writing to file
*/ */

@ -6,22 +6,33 @@ import mightypork.gamecore.resources.BaseDeferredResource;
/** /**
* Abstract deferred font stub. * Deferred font stub.
* *
* @author Ondřej Hruška (MightyPork) * @author Ondřej Hruška (MightyPork)
*/ */
public abstract class DeferredFont extends BaseDeferredResource implements IFont { public abstract class DeferredFont extends BaseDeferredResource implements IFont {
/**
* Font style enum
*/
public static enum FontStyle public static enum FontStyle
{ {
PLAIN(0), BOLD(1), ITALIC(2), BOLD_ITALIC(3); /** Plan style */
PLAIN(0),
/** Bold style */
BOLD(1),
/** Italic style */
ITALIC(2),
/** Bond and italic together */
BOLD_ITALIC(1 + 2);
/** Number associated with the style */
public int numval; public int numval;
/** /**
* Font style * Font style
* *
* @param style style index as in awt Font. Not using constants to be * @param style style index as in awt Font. Not using constants to be
* independent on awt. * independent on awt.
*/ */
@ -31,53 +42,111 @@ public abstract class DeferredFont extends BaseDeferredResource implements IFont
} }
} }
/**
* Requested font size. For bitmap fonts, this should match the actual font
* size (in pixels). The font can be scaled after loaded, but it may be
* cached with this size.
*/
protected double size = 12; protected double size = 12;
/** Requested font style. If not applicable, fall back to PLAIN */
protected FontStyle style = FontStyle.PLAIN; protected FontStyle style = FontStyle.PLAIN;
/**
* Chars that are required to be loaded in the font. A space glyph must be
* also added when loading.
*/
protected String chars = Glyphs.basic; protected String chars = Glyphs.basic;
/** Requested filtering mode */
protected FilterMode filter = FilterMode.NEAREST; protected FilterMode filter = FilterMode.NEAREST;
/** Whether to use anti-aliasing for the font. */
protected boolean antialias = false; protected boolean antialias = false;
/**
* Ratio of the font to discard at the top (how much of the glyphs height is
* blank from top)
*/
protected double discardTop = 0; protected double discardTop = 0;
/**
* Ratio of the font to discard at the bottom (how much of the glyphs height
* is blank from bottom)
*/
protected double discardBottom = 0; protected double discardBottom = 0;
/**
* Make a font from resource
*
* @param resource the font resource
*/
public DeferredFont(String resource) public DeferredFont(String resource)
{ {
super(resource); super(resource);
} }
public void setSize(double size) /**
* Set font size. If the font is backed by a texture, this is the size at
* which the font is rendered to the texture. For bitmap fonts, this should
* match the font height in px.
*
* @param size font size
*/
public final void setSize(double size)
{ {
this.size = size; this.size = size;
} }
public void setStyle(FontStyle style) /**
* Set desired font style
*
* @param style style
*/
public final void setStyle(FontStyle style)
{ {
this.style = style; this.style = style;
} }
public void setChars(String chars) /**
* Set what chars are to be loaded. The space glyph will be loaded always.
*
* @param chars String containing chars to load (duplicates are ignored)
*/
public final void setChars(String chars)
{ {
this.chars = chars; this.chars = chars;
} }
public void setFilter(FilterMode filter) /**
* Set texture filtering mode. For bitmap fonts, set to NEAREST.
*
* @param filter filter mode.
*/
public final void setFilter(FilterMode filter)
{ {
this.filter = filter; this.filter = filter;
} }
public void setAntialias(boolean antialias) /**
* Set whether to use antialiasing.
*
* @param antialias antialias
*/
public final void setAntialias(boolean antialias)
{ {
this.antialias = antialias; this.antialias = antialias;
} }
@Override @Override
public void setDiscardRatio(double top, double bottom) public final void setDiscardRatio(double top, double bottom)
{ {
discardTop = top; discardTop = top;
discardBottom = bottom; discardBottom = bottom;
@ -85,14 +154,14 @@ public abstract class DeferredFont extends BaseDeferredResource implements IFont
@Override @Override
public double getTopDiscardRatio() public final double getTopDiscardRatio()
{ {
return discardTop; return discardTop;
} }
@Override @Override
public double getBottomDiscardRatio() public final double getBottomDiscardRatio()
{ {
return discardBottom; return discardBottom;
} }

@ -10,32 +10,32 @@ import mightypork.utils.eventbus.clients.BusNode;
/** /**
* Font loader and registry * Font loader and registry
* *
* @author Ondřej Hruška (MightyPork) * @author Ondřej Hruška (MightyPork)
*/ */
public class FontRegistry extends BusNode { public class FontRegistry extends BusNode {
private final HashMap<String, IFont> fonts = new HashMap<>(); private final HashMap<String, IFont> fonts = new HashMap<>();
private final HashMap<String, String> aliases = new HashMap<>(); private final HashMap<String, String> aliases = new HashMap<>();
/** /**
* Load a {@link DeferredLwjglFont} * Load a {@link DeferredFont}
* *
* @param key font key * @param key font key
* @param font font instance * @param font font instance
*/ */
public void addFont(String key, DeferredFont font) public void addFont(String key, DeferredFont font)
{ {
App.bus().send(new ResourceLoadRequest(font)); App.bus().send(new ResourceLoadRequest(font));
fonts.put(key, font); fonts.put(key, font);
} }
/** /**
* Add a {@link IFont} to the bank. * Add a {@link IFont} to the bank.
* *
* @param key font key * @param key font key
* @param font font instance * @param font font instance
*/ */
@ -43,11 +43,11 @@ public class FontRegistry extends BusNode {
{ {
fonts.put(key, font); fonts.put(key, font);
} }
/** /**
* Add a font alias. * Add a font alias.
* *
* @param alias_key alias key * @param alias_key alias key
* @param font_key font key * @param font_key font key
*/ */
@ -55,25 +55,25 @@ public class FontRegistry extends BusNode {
{ {
aliases.put(alias_key, font_key); aliases.put(alias_key, font_key);
} }
/** /**
* Get a loaded {@link Texture} * Get a loaded {@link IFont}
* *
* @param key texture key * @param key texture key
* @return the texture * @return the texture
*/ */
public IFont getFont(String key) public IFont getFont(String key)
{ {
IFont f = fonts.get(key); IFont f = fonts.get(key);
if (f == null) f = fonts.get(aliases.get(key)); if (f == null) f = fonts.get(aliases.get(key));
if (f == null) { if (f == null) {
throw new RuntimeException("There's no font called " + key + "!"); throw new RuntimeException("There's no font called " + key + "!");
} }
return f; return f;
} }
} }

@ -11,16 +11,16 @@ import mightypork.utils.math.constraints.vect.Vect;
/** /**
* Font renderer * Font renderer
* *
* @author Ondřej Hruška (MightyPork) * @author Ondřej Hruška (MightyPork)
*/ */
public class FontRenderer { public class FontRenderer {
private IFont font; private IFont font;
private Color color; private Color color;
/** /**
* @param font used font * @param font used font
*/ */
@ -28,8 +28,8 @@ public class FontRenderer {
{ {
this(font, RGB.WHITE); this(font, RGB.WHITE);
} }
/** /**
* @param font used font * @param font used font
* @param color drawing color * @param color drawing color
@ -39,11 +39,11 @@ public class FontRenderer {
this.font = font; this.font = font;
this.color = color; this.color = color;
} }
/** /**
* Get region needed to draw text at size * Get region needed to draw text at size
* *
* @param text text to draw * @param text text to draw
* @param height drawing height * @param height drawing height
* @return taken space (width, height) * @return taken space (width, height)
@ -52,11 +52,11 @@ public class FontRenderer {
{ {
return font.getNeededSpace(text).mul(getScale(height)); return font.getNeededSpace(text).mul(getScale(height));
} }
/** /**
* Get width needed to draw text at size * Get width needed to draw text at size
* *
* @param text text to draw * @param text text to draw
* @param height drawing height * @param height drawing height
* @return needed width * @return needed width
@ -65,39 +65,39 @@ public class FontRenderer {
{ {
return getNeededSpace(text, height).x(); return getNeededSpace(text, height).x();
} }
private double getScale(double height) private double getScale(double height)
{ {
return height / font.getLineHeight(); return height / font.getLineHeight();
} }
/** /**
* Change drawing font * Change drawing font
* *
* @param font font to use for drawing * @param font font to use for drawing
*/ */
public void setFont(IFont font) public void setFont(IFont font)
{ {
this.font = font; this.font = font;
} }
/** /**
* Set drawing color * Set drawing color
* *
* @param color color * @param color color
*/ */
public void setColor(Color color) public void setColor(Color color)
{ {
this.color = color; this.color = color;
} }
/** /**
* Draw on screen * Draw on screen
* *
* @param text text to draw * @param text text to draw
* @param pos origin (min coord) * @param pos origin (min coord)
* @param height drawing height * @param height drawing height
@ -106,21 +106,21 @@ public class FontRenderer {
public void draw(String text, Vect pos, double height, Color color) public void draw(String text, Vect pos, double height, Color color)
{ {
App.gfx().pushGeometry(); App.gfx().pushGeometry();
final double sc = getScale(height); final double sc = getScale(height);
App.gfx().translate(pos.x(), pos.y()); App.gfx().translate(pos.x(), pos.y());
App.gfx().scaleXY(sc); App.gfx().scaleXY(sc);
font.draw(text, color); font.draw(text, color);
App.gfx().popGeometry(); App.gfx().popGeometry();
} }
/** /**
* Draw on screen * Draw on screen
* *
* @param text text to draw * @param text text to draw
* @param bounds drawing bounds (height for font height, horizontal bounds * @param bounds drawing bounds (height for font height, horizontal bounds
* for align) * for align)
@ -130,11 +130,11 @@ public class FontRenderer {
{ {
this.draw(text, bounds, align, this.color); this.draw(text, bounds, align, this.color);
} }
/** /**
* Draw on screen * Draw on screen
* *
* @param text text to draw * @param text text to draw
* @param bounds drawing bounds (height for font height, horizontal bounds * @param bounds drawing bounds (height for font height, horizontal bounds
* for align) * for align)
@ -144,29 +144,29 @@ public class FontRenderer {
public void draw(String text, Rect bounds, AlignX align, Color color) public void draw(String text, Rect bounds, AlignX align, Color color)
{ {
Vect start; Vect start;
switch (align) { switch (align) {
case LEFT: case LEFT:
start = bounds.topLeft(); start = bounds.topLeft();
break; break;
case CENTER: case CENTER:
start = bounds.topCenter(); start = bounds.topCenter();
break; break;
case RIGHT: case RIGHT:
default: default:
start = bounds.topRight(); start = bounds.topRight();
break; break;
} }
draw(text, start, bounds.height().value(), align, color); draw(text, start, bounds.height().value(), align, color);
} }
/** /**
* Draw on screen * Draw on screen
* *
* @param text text to draw * @param text text to draw
* @param pos origin (min coord) * @param pos origin (min coord)
* @param height drawing height * @param height drawing height
@ -176,11 +176,11 @@ public class FontRenderer {
{ {
draw(text, pos, height, align, this.color); draw(text, pos, height, align, this.color);
} }
/** /**
* Draw on screen * Draw on screen
* *
* @param text text to draw * @param text text to draw
* @param pos origin (min coord) * @param pos origin (min coord)
* @param height drawing height * @param height drawing height
@ -189,27 +189,27 @@ public class FontRenderer {
*/ */
public void draw(String text, Vect pos, double height, AlignX align, Color color) public void draw(String text, Vect pos, double height, AlignX align, Color color)
{ {
final double w = getWidth(text, height); final double w = getWidth(text, height);
Vect start; Vect start;
switch (align) { switch (align) {
case LEFT: case LEFT:
start = pos; start = pos;
break; break;
case CENTER: case CENTER:
start = pos.sub(w / 2D, 0); start = pos.sub(w / 2D, 0);
break; break;
case RIGHT: case RIGHT:
default: default:
start = pos.sub(w, 0); start = pos.sub(w, 0);
break; break;
} }
draw(text, start, height, color); draw(text, start, height, color);
} }
} }

@ -2,22 +2,41 @@ package mightypork.gamecore.graphics.fonts;
/** /**
* Glyph tables, can be used for font loading. * Glyph tables, can be used for font loading.<br>
* * The font should also always add a space glyph.
*
* @author Ondřej Hruška (MightyPork) * @author Ondřej Hruška (MightyPork)
*/ */
public class Glyphs { public class Glyphs {
/** A-Z a-z */
public static final String latin = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; public static final String latin = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
/** Extra variants of latin glyphs */
public static final String latin_extra = "ŒÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜŸÝßàáâãäåæçèéêëìíîïðñòóôõöøùúûüýþÿĚŠČŘŽŤŇĎŮěščřžťňďůŁłđ"; public static final String latin_extra = "ŒÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜŸÝßàáâãäåæçèéêëìíîïðñòóôõöøùúûüýþÿĚŠČŘŽŤŇĎŮěščřžťňďůŁłđ";
/** 0-9 */
public static final String numbers = "0123456789"; public static final String numbers = "0123456789";
/** Commonly used punctuation symbols */
public static final String punctuation = ".-,.?!:;\"'"; public static final String punctuation = ".-,.?!:;\"'";
/** Less common punctuation symbols */
public static final String punctuation_extra = "()¿¡»«›‹“”‘’„…"; public static final String punctuation_extra = "()¿¡»«›‹“”‘’„…";
/** Commonly used symbols (that are not included in punctuation) */
public static final String symbols = "[]{}#$%&§*+/<=>@\\^_|~°"; public static final String symbols = "[]{}#$%&§*+/<=>@\\^_|~°";
/** Less common symbols */
public static final String symbols_extra = "¥€£¢`ƒ†‡ˆ‰•¤¦¨ªº¹²³¬­¯±´µ¶·¸¼½¾×÷™©­®→↓←↑"; public static final String symbols_extra = "¥€£¢`ƒ†‡ˆ‰•¤¦¨ªº¹²³¬­¯±´µ¶·¸¼½¾×÷™©­®→↓←↑";
/** Latin, numbers, punctuation and symbols */
public static final String basic = latin + numbers + punctuation + symbols; public static final String basic = latin + numbers + punctuation + symbols;
/** Extra glyphs to accompany "basic" */
public static final String extra = latin_extra + punctuation_extra + symbols_extra; public static final String extra = latin_extra + punctuation_extra + symbols_extra;
/** Basic + Extra */
public static final String all = basic + extra; public static final String all = basic + extra;
} }

@ -7,69 +7,69 @@ import mightypork.utils.math.constraints.vect.Vect;
/** /**
* Interface bor drawable font. * Interface bor drawable font.
* *
* @author Ondřej Hruška (MightyPork) * @author Ondřej Hruška (MightyPork)
*/ */
public interface IFont { public interface IFont {
/** /**
* Draw without scaling at (0, 0) in given color. * Draw without scaling at (0, 0) in given color.
* *
* @param text text to draw * @param text text to draw
* @param color draw color * @param color draw color
*/ */
void draw(String text, Color color); void draw(String text, Color color);
/** /**
* Get suize needed to render give string * Get suize needed to render give string
* *
* @param text string to check * @param text string to check
* @return coord (width, height) * @return coord (width, height)
*/ */
Vect getNeededSpace(String text); Vect getNeededSpace(String text);
/** /**
* @return font height * @return font height
*/ */
int getLineHeight(); int getLineHeight();
/** /**
* @param text texted text * @param text texted text
* @return space needed * @return space needed
*/ */
int getWidth(String text); int getWidth(String text);
/** /**
* @return specified font size * @return specified font size
*/ */
int getFontSize(); int getFontSize();
/** /**
* Set what vertical ratio of the font size is blank and should be cut off * Set what vertical ratio of the font size is blank and should be cut off
* when rendering * when rendering
* *
* @param top top ratio (0-1) * @param top top ratio (0-1)
* @param bottom bottom ratio (0-1) * @param bottom bottom ratio (0-1)
*/ */
void setDiscardRatio(double top, double bottom); void setDiscardRatio(double top, double bottom);
/** /**
* Get top discard ratio (blank unused space) * Get top discard ratio (blank unused space)
* *
* @return ratio * @return ratio
*/ */
double getTopDiscardRatio(); double getTopDiscardRatio();
/** /**
* Get bottom discard ratio (blank unused space) * Get bottom discard ratio (blank unused space)
* *
* @return ratio * @return ratio
*/ */
double getBottomDiscardRatio(); double getBottomDiscardRatio();

@ -9,14 +9,16 @@ import mightypork.utils.math.constraints.rect.Rect;
/** /**
* Deferred texture (to be extended by backend texture) * Deferred texture (to be extended by backend texture)
* *
* @author Ondřej Hruška (MightyPork) * @author Ondřej Hruška (MightyPork)
*/ */
@Alias(name = "Texture") @Alias(name = "Texture")
@MustLoadInRenderingContext @MustLoadInRenderingContext
public abstract class DeferredTexture extends BaseDeferredResource implements ITexture { public abstract class DeferredTexture extends BaseDeferredResource implements ITexture {
/** Used filtering mode */
protected FilterMode filter = FilterMode.NEAREST; protected FilterMode filter = FilterMode.NEAREST;
/** Used wrapping mode */
protected WrapMode wrap = WrapMode.CLAMP; protected WrapMode wrap = WrapMode.CLAMP;

@ -3,10 +3,13 @@ package mightypork.gamecore.graphics.textures;
/** /**
* Texture filtering mode * Texture filtering mode
* *
* @author Ondřej Hruška (MightyPork) * @author Ondřej Hruška (MightyPork)
*/ */
public enum FilterMode public enum FilterMode
{ {
LINEAR, NEAREST; /** Smoothing, useful for photos */
LINEAR,
/** Sharp, useful for pixel art graphics */
NEAREST;
} }

@ -7,56 +7,56 @@ import mightypork.utils.math.constraints.rect.Rect;
/** /**
* Texture interface, backend independent * Texture interface, backend independent
* *
* @author Ondřej Hruška (MightyPork) * @author Ondřej Hruška (MightyPork)
*/ */
public interface ITexture extends Destroyable { public interface ITexture extends Destroyable {
/** /**
* Set filter for scaling * Set filter for scaling
* *
* @param filter filter * @param filter filter
*/ */
void setFilter(FilterMode filter); void setFilter(FilterMode filter);
/** /**
* @param wrapping wrap mode * @param wrapping wrap mode
*/ */
void setWrap(WrapMode wrapping); void setWrap(WrapMode wrapping);
/** /**
* Get a quad from this texture of given position/size * Get a quad from this texture of given position/size
* *
* @param uvs quad rect * @param uvs quad rect
* @return the quad * @return the quad
*/ */
TxQuad makeQuad(Rect uvs); TxQuad makeQuad(Rect uvs);
/** /**
* Get a grid for given number of tiles * Get a grid for given number of tiles
* *
* @param x horizontal tile count * @param x horizontal tile count
* @param y vertical tile count * @param y vertical tile count
* @return grid * @return grid
*/ */
QuadGrid grid(int x, int y); QuadGrid grid(int x, int y);
/** /**
* @return source image width (corresponding to width01) * @return source image width (corresponding to width01)
*/ */
int getImageWidth(); int getImageWidth();
/** /**
* @return source image height (corresponding to height01) * @return source image height (corresponding to height01)
*/ */
int getImageHeight(); int getImageHeight();
/** /**
* @return true if the image is RGBA * @return true if the image is RGBA
*/ */

@ -5,8 +5,9 @@ import mightypork.utils.math.constraints.rect.Rect;
/** /**
* {@link TxQuad} and {@link TxSheet} building utility * {@link TxQuad} and {@link TxSheet} building utility, that cuts a texture into
* * equally sized quads.
*
* @author Ondřej Hruška (MightyPork) * @author Ondřej Hruška (MightyPork)
*/ */
public class QuadGrid { public class QuadGrid {
@ -18,6 +19,11 @@ public class QuadGrid {
private final double tileH; private final double tileH;
/**
* @param tx backing texture
* @param tilesX number of tile columns
* @param tilesY number of tile rows
*/
public QuadGrid(ITexture tx, int tilesX, int tilesY) public QuadGrid(ITexture tx, int tilesX, int tilesY)
{ {
this.tx = tx; this.tx = tx;
@ -30,7 +36,7 @@ public class QuadGrid {
/** /**
* Make square quad at given coords (one grid cell) * Make square quad at given coords (one grid cell)
* *
* @param x x coordinate (cells) * @param x x coordinate (cells)
* @param y y coordinate (cells) * @param y y coordinate (cells)
* @return the quad * @return the quad
@ -48,7 +54,7 @@ public class QuadGrid {
/** /**
* Make square quad at given coords, with arbitrary size. Coordinates are * Make square quad at given coords, with arbitrary size. Coordinates are
* multiples of cell size. * multiples of cell size.
* *
* @param x x coordinate (cells) * @param x x coordinate (cells)
* @param y y coordinate (cells) * @param y y coordinate (cells)
* @param width width (cells) * @param width width (cells)
@ -71,7 +77,7 @@ public class QuadGrid {
/** /**
* Make a sheet. * Make a sheet.
* *
* @param x x origin coordinate (cells) * @param x x origin coordinate (cells)
* @param y y origin coordinate (cells) * @param y y origin coordinate (cells)
* @param width width (cells) * @param width width (cells)

@ -13,91 +13,91 @@ import mightypork.utils.math.constraints.rect.Rect;
/** /**
* Texture storage and quad/sheet registry. Quads and Sheets are interchangeable * Texture storage and quad/sheet registry. Quads and Sheets are interchangeable
* once registered. * once registered.
* *
* @author Ondřej Hruška (MightyPork) * @author Ondřej Hruška (MightyPork)
*/ */
public class TextureRegistry { public class TextureRegistry {
private final Map<String, ITexture> textures = new HashMap<>(); private final Map<String, ITexture> textures = new HashMap<>();
private final Map<String, TxSheet> sheets = new HashMap<>(); private final Map<String, TxSheet> sheets = new HashMap<>();
/** /**
* Load a texture from resource, without a key. This texture will not be * Load a texture from resource, without a key. This texture will not be
* added to the bank. * added to the bank.
* *
* @param resourcePath resource path of the texture * @param resourcePath resource path of the texture
* @param filter * @param filter filtering mode
* @param wrap * @param wrap wrapping mode
* @return texture reference * @return texture reference
*/ */
public ITexture addTexture(String resourcePath, FilterMode filter, WrapMode wrap) public ITexture addTexture(String resourcePath, FilterMode filter, WrapMode wrap)
{ {
return addTexture(resourcePath, resourcePath, filter, wrap); return addTexture(resourcePath, resourcePath, filter, wrap);
} }
/** /**
* Load a texture from resource; if key is not null, the texture will be * Load a texture from resource; if key is not null, the texture will be
* added to the bank. * added to the bank.
* *
* @param key texture key, can be null. * @param key texture key, can be null.
* @param resourcePath resource path of the texture * @param resourcePath resource path of the texture
* @param filter * @param filter filtering mode
* @param wrap * @param wrap wrapping mode
* @return texture reference * @return texture reference
*/ */
public ITexture addTexture(String key, String resourcePath, FilterMode filter, WrapMode wrap) public ITexture addTexture(String key, String resourcePath, FilterMode filter, WrapMode wrap)
{ {
if (key != null) if (textures.containsKey(key)) throw new KeyAlreadyExistsException(); if (key != null) if (textures.containsKey(key)) throw new KeyAlreadyExistsException();
final DeferredTexture texture = App.gfx().getLazyTexture(resourcePath); final DeferredTexture texture = App.gfx().createDeferredTexture(resourcePath);
texture.setFilter(filter); texture.setFilter(filter);
texture.setWrap(wrap); texture.setWrap(wrap);
App.bus().send(new ResourceLoadRequest(texture)); App.bus().send(new ResourceLoadRequest(texture));
if (key != null) { if (key != null) {
textures.put(key, texture); textures.put(key, texture);
add(key, texture.makeQuad(Rect.ONE)); add(key, texture.makeQuad(Rect.ONE));
} }
return texture; return texture;
} }
/** /**
* Add already created quad to the quad registry * Add already created quad to the quad registry
* *
* @param quadKey key * @param quadKey key
* @param quad quad to add * @param quad quad to add
*/ */
public void add(String quadKey, TxQuad quad) public void add(String quadKey, TxQuad quad)
{ {
if (sheets.containsKey(quadKey)) throw new KeyAlreadyExistsException(); if (sheets.containsKey(quadKey)) throw new KeyAlreadyExistsException();
sheets.put(quadKey, quad.makeSheet(1, 1)); sheets.put(quadKey, quad.makeSheet(1, 1));
} }
/** /**
* Add an already created sheet * Add an already created sheet
* *
* @param sheetKey key * @param sheetKey key
* @param sheet sheet to add * @param sheet sheet to add
*/ */
public void add(String sheetKey, TxSheet sheet) public void add(String sheetKey, TxSheet sheet)
{ {
if (sheets.containsKey(sheetKey)) throw new KeyAlreadyExistsException(); if (sheets.containsKey(sheetKey)) throw new KeyAlreadyExistsException();
sheets.put(sheetKey, sheet); sheets.put(sheetKey, sheet);
} }
/** /**
* Get a {@link TxQuad} for key; if it was added as sheet, the first quad * Get a {@link TxQuad} for key; if it was added as sheet, the first quad
* ofthe sheet is returned. * ofthe sheet is returned.
* *
* @param key quad key * @param key quad key
* @return the quad * @return the quad
*/ */
@ -105,39 +105,39 @@ public class TextureRegistry {
{ {
return getSheet(key).getQuad(0); // get the first return getSheet(key).getQuad(0); // get the first
} }
/** /**
* Get a loaded {@link ITexture} * Get a loaded {@link ITexture}
* *
* @param key texture key * @param key texture key
* @return the texture * @return the texture
*/ */
public ITexture getTexture(String key) public ITexture getTexture(String key)
{ {
final ITexture tx = textures.get(key); final ITexture tx = textures.get(key);
if (tx == null) throw new RuntimeException("There's no texture called \"" + key + "\"!"); if (tx == null) throw new RuntimeException("There's no texture called \"" + key + "\"!");
return tx; return tx;
} }
/** /**
* Get a {@link TxSheet} for key * Get a {@link TxSheet} for key
* *
* @param key sheet key * @param key sheet key
* @return the sheet * @return the sheet
*/ */
public TxSheet getSheet(String key) public TxSheet getSheet(String key)
{ {
final TxSheet sh = sheets.get(key); final TxSheet sh = sheets.get(key);
if (sh == null) { if (sh == null) {
throw new RuntimeException("There's no sheet called \"" + key + "\"!"); throw new RuntimeException("There's no sheet called \"" + key + "\"!");
} }
return sh; return sh;
} }
} }

@ -7,7 +7,7 @@ import mightypork.utils.math.constraints.rect.RectConst;
/** /**
* Texture Quad (describing a part of a texture) * Texture Quad (describing a part of a texture)
* *
* @author Ondřej Hruška (MightyPork) * @author Ondřej Hruška (MightyPork)
*/ */
public class TxQuad { public class TxQuad {
@ -23,7 +23,7 @@ public class TxQuad {
/** /**
* TxQuad from origin and size in pixels * TxQuad from origin and size in pixels
* *
* @param tx texture * @param tx texture
* @param xPx left top X (0-1) * @param xPx left top X (0-1)
* @param yPx left top Y (0-1) * @param yPx left top Y (0-1)
@ -42,7 +42,7 @@ public class TxQuad {
/** /**
* TxQuad from origin and size 0-1 * TxQuad from origin and size 0-1
* *
* @param tx texture * @param tx texture
* @param x1 left top X (0-1) * @param x1 left top X (0-1)
* @param y1 left top Y (0-1) * @param y1 left top Y (0-1)
@ -58,7 +58,7 @@ public class TxQuad {
/** /**
* Make of coords * Make of coords
* *
* @param tx texture * @param tx texture
* @param x1 left top X (0-1) * @param x1 left top X (0-1)
* @param y1 left top Y (0-1) * @param y1 left top Y (0-1)
@ -84,7 +84,7 @@ public class TxQuad {
/** /**
* Clone another * Clone another
* *
* @param txQuad a copied quad * @param txQuad a copied quad
*/ */
public TxQuad(TxQuad txQuad) public TxQuad(TxQuad txQuad)
@ -98,7 +98,7 @@ public class TxQuad {
/** /**
* Get copy * Get copy
* *
* @return copy of this * @return copy of this
*/ */
public TxQuad copy() public TxQuad copy()
@ -109,7 +109,7 @@ public class TxQuad {
/** /**
* Make a sheet starting with this quad, spannign to right and down. * Make a sheet starting with this quad, spannign to right and down.
* *
* @param width sheet width * @param width sheet width
* @param height sheet height * @param height sheet height
* @return sheet * @return sheet
@ -142,12 +142,18 @@ public class TxQuad {
} }
/**
* @return true if the quad is to be rendered flipped vertically
*/
public boolean isFlippedY() public boolean isFlippedY()
{ {
return flipY; return flipY;
} }
/**
* @return true if the quad is to be rendered flipped horizontally
*/
public boolean isFlippedX() public boolean isFlippedX()
{ {
return flipX; return flipX;
@ -156,8 +162,8 @@ public class TxQuad {
/** /**
* Use the same flit/other attributes as the original txQuad * Use the same flit/other attributes as the original txQuad
* *
* @param original * @param original quad to copy attributes from
*/ */
public void dupeAttrs(TxQuad original) public void dupeAttrs(TxQuad original)
{ {

@ -7,8 +7,9 @@ import mightypork.utils.logging.Log;
/** /**
* Basic sprite sheet * Basic sprite sheet (cuts a {@link TxQuad} to a number of same-sized
* * sub-quads)
*
* @author Ondřej Hruška (MightyPork) * @author Ondřej Hruška (MightyPork)
*/ */
public class TxSheet { public class TxSheet {
@ -22,6 +23,13 @@ public class TxSheet {
private final int count; private final int count;
/**
* Make a sprite sheet
*
* @param tx backing texture quad
* @param width number of tiles horizontally
* @param height number of tiles vertically
*/
public TxSheet(TxQuad tx, int width, int height) public TxSheet(TxQuad tx, int width, int height)
{ {
this.original = tx; this.original = tx;
@ -43,7 +51,7 @@ public class TxSheet {
/** /**
* Get a quad based on ratio 0-1 (0: first, 1: last) * Get a quad based on ratio 0-1 (0: first, 1: last)
* *
* @param ratio ratio * @param ratio ratio
* @return quad * @return quad
*/ */
@ -55,7 +63,7 @@ public class TxSheet {
/** /**
* Get quad of index * Get quad of index
* *
* @param index index * @param index index
* @return the quad * @return the quad
*/ */
@ -86,7 +94,7 @@ public class TxSheet {
/** /**
* Get entirely random TxQuad from this sheet * Get entirely random TxQuad from this sheet
* *
* @return the picked quad * @return the picked quad
*/ */
public TxQuad getRandomQuad() public TxQuad getRandomQuad()
@ -97,7 +105,7 @@ public class TxSheet {
/** /**
* Get random TxQuad from this sheet * Get random TxQuad from this sheet
* *
* @param seed random number generator seed * @param seed random number generator seed
* @return the picked quad * @return the picked quad
*/ */
@ -110,7 +118,7 @@ public class TxSheet {
/** /**
* Get random TxQuad from this sheet * Get random TxQuad from this sheet
* *
* @param seed random number generator seed (double will be converted to * @param seed random number generator seed (double will be converted to
* long) * long)
* @return the picked quad * @return the picked quad

@ -2,11 +2,15 @@ package mightypork.gamecore.graphics.textures;
/** /**
* Texture wrap mode * Texture wrap mode (policy when rendered on larger area than can be covered by
* * the texture)
*
* @author Ondřej Hruška (MightyPork) * @author Ondřej Hruška (MightyPork)
*/ */
public enum WrapMode public enum WrapMode
{ {
CLAMP, REPEAT; /** transparent in the overlap area */
CLAMP,
/** repeat the texture (tiling) */
REPEAT;
} }

@ -5,8 +5,8 @@ import mightypork.utils.interfaces.Enableable;
/** /**
* Triggered action * An {@link Enableable} runnable.
* *
* @author Ondřej Hruška (MightyPork) * @author Ondřej Hruška (MightyPork)
*/ */
public abstract class Action implements Runnable, Enableable { public abstract class Action implements Runnable, Enableable {
@ -16,7 +16,7 @@ public abstract class Action implements Runnable, Enableable {
/** /**
* Enable the action * Enable the action
* *
* @param enable true to enable * @param enable true to enable
*/ */
@Override @Override

@ -7,6 +7,12 @@ import java.util.Set;
import mightypork.utils.interfaces.Enableable; import mightypork.utils.interfaces.Enableable;
/**
* A group of enableable objects that propagates it's "enable" state to them
* all.
*
* @author Ondřej Hruška (MightyPork)
*/
public class ActionGroup implements Enableable { public class ActionGroup implements Enableable {
private boolean enabled = true; private boolean enabled = true;
@ -30,9 +36,25 @@ public class ActionGroup implements Enableable {
} }
public void add(Enableable action) /**
* Add an {@link Enableable} to the group
*
* @param member the object to add
*/
public void add(Enableable member)
{ {
groupMembers.add(action); groupMembers.add(member);
}
/**
* Remove a group member
*
* @param member the object to remove
*/
public void remove(Enableable member)
{
groupMembers.remove(member);
} }
} }

@ -3,14 +3,14 @@ package mightypork.gamecore.gui;
/** /**
* Element that can be assigned an action (ie. button); * Element that can be assigned an action (ie. button);
* *
* @author Ondřej Hruška (MightyPork) * @author Ondřej Hruška (MightyPork)
*/ */
public interface ActionTrigger { public interface HasAction {
/** /**
* Assign an action * Assign an action
* *
* @param action action * @param action action
*/ */
void setAction(Action action); void setAction(Action action);

@ -7,7 +7,6 @@ import mightypork.gamecore.gui.events.LayoutChangeEvent;
import mightypork.gamecore.gui.events.LayoutChangeListener; import mightypork.gamecore.gui.events.LayoutChangeListener;
import mightypork.utils.Support; import mightypork.utils.Support;
import mightypork.utils.annotations.Stub; import mightypork.utils.annotations.Stub;
import mightypork.utils.interfaces.Enableable;
import mightypork.utils.logging.Log; import mightypork.utils.logging.Log;
import mightypork.utils.math.color.Color; import mightypork.utils.math.color.Color;
import mightypork.utils.math.constraints.num.Num; import mightypork.utils.math.constraints.num.Num;
@ -20,64 +19,69 @@ import mightypork.utils.math.constraints.rect.proxy.RectProxy;
/** /**
* {@link Renderable} with pluggable context. When caching is enabled, the * {@link Renderable} with pluggable context. When caching is enabled, the
* layout update can be triggered by firing the {@link LayoutChangeEvent}. * layout update can be triggered by firing the {@link LayoutChangeEvent}.
* *
* @author Ondřej Hruška (MightyPork) * @author Ondřej Hruška (MightyPork)
*/ */
public abstract class BaseComponent extends AbstractRectCache implements Component, LayoutChangeListener, Enableable { public abstract class BaseComponent extends AbstractRectCache implements Component, LayoutChangeListener {
private Rect source; private Rect source;
private boolean visible = true; private boolean visible = true;
private boolean enabled = true; private boolean enabled = true;
private int indirectDisableLevel = 0; private int indirectDisableLevel = 0;
private Num alphaMul = Num.ONE; private Num alphaMul = Num.ONE;
/**
* Create a base component.<br>
* By default, disable caching to avoid problems with updating. Caching can
* be enabled by individual components.
*/
public BaseComponent() public BaseComponent()
{ {
enableCaching(false); enableCaching(false);
} }
@Override @Override
public void setRect(RectBound rect) public void setRect(RectBound rect)
{ {
this.source = new RectProxy(rect); this.source = new RectProxy(rect);
} }
@Override @Override
public final boolean isVisible() public final boolean isVisible()
{ {
return visible; return visible;
} }
@Override @Override
public final void setVisible(boolean visible) public final void setVisible(boolean visible)
{ {
this.visible = visible; this.visible = visible;
} }
@Override @Override
public final Rect getCacheSource() public final Rect getCacheSource()
{ {
return source.round(); // round to avoid visual artifacts in fonts and such return source.round(); // round to avoid visual artifacts in fonts and such
} }
@Override @Override
public final void render() public final void render()
{ {
if (!isVisible()) return; if (!isVisible()) return;
Color.pushAlpha(alphaMul); Color.pushAlpha(alphaMul);
renderComponent(); renderComponent();
Color.popAlpha(); Color.popAlpha();
} }
@Override @Override
public final void onLayoutChanged() public final void onLayoutChanged()
{ {
@ -87,63 +91,63 @@ public abstract class BaseComponent extends AbstractRectCache implements Compone
Log.e("Component is missing a bounding rect, at: " + Support.str(getClass())); Log.e("Component is missing a bounding rect, at: " + Support.str(getClass()));
} }
} }
@Override @Override
public final void onConstraintChanged() public final void onConstraintChanged()
{ {
updateLayout(); updateLayout();
} }
@Override @Override
public final boolean isMouseOver() public final boolean isMouseOver()
{ {
return App.input().getMousePos().isInside(this); return App.input().getMousePos().isInside(this);
} }
/** /**
* Draw the component (it's visible) * Draw the component (it's visible)
*/ */
protected abstract void renderComponent(); protected abstract void renderComponent();
@Override @Override
@Stub @Stub
public void updateLayout() public void updateLayout()
{ {
} }
@Override @Override
public void setEnabled(boolean yes) public void setEnabled(boolean yes)
{ {
enabled = yes; enabled = yes;
} }
@Override @Override
public boolean isEnabled() public boolean isEnabled()
{ {
return enabled && isIndirectlyEnabled(); return enabled && isIndirectlyEnabled();
} }
@Override @Override
public final void setAlpha(Num alpha) public final void setAlpha(Num alpha)
{ {
this.alphaMul = alpha; this.alphaMul = alpha;
} }
@Override @Override
public final void setAlpha(double alpha) public final void setAlpha(double alpha)
{ {
this.alphaMul = Num.make(alpha); this.alphaMul = Num.make(alpha);
} }
@Override @Override
public void setIndirectlyEnabled(boolean yes) public void setIndirectlyEnabled(boolean yes)
{ {
@ -153,15 +157,15 @@ public abstract class BaseComponent extends AbstractRectCache implements Compone
if (indirectDisableLevel > 0) indirectDisableLevel--; if (indirectDisableLevel > 0) indirectDisableLevel--;
} }
} }
@Override @Override
public boolean isIndirectlyEnabled() public boolean isIndirectlyEnabled()
{ {
return indirectDisableLevel == 0; return indirectDisableLevel == 0;
} }
@Override @Override
public boolean isDirectlyEnabled() public boolean isDirectlyEnabled()
{ {

@ -8,86 +8,86 @@ import mightypork.utils.math.constraints.num.Num;
/** /**
* Basic UI component interface * Basic UI component interface
* *
* @author Ondřej Hruška (MightyPork) * @author Ondřej Hruška (MightyPork)
*/ */
public interface Component extends Enableable, Hideable, PluggableRenderable { public interface Component extends Enableable, Hideable, PluggableRenderable {
/** /**
* Render the component, if it is visible. * Render the component, if it is visible.
*/ */
@Override @Override
void render(); void render();
/** /**
* The bounding rect was changed. The component should now update any cached * The bounding rect was changed. The component should now update any cached
* constraints derived from it. * constraints derived from it.
*/ */
void updateLayout(); void updateLayout();
/** /**
* @return true if mouse is currently over the component * @return true if mouse is currently over the component
*/ */
boolean isMouseOver(); boolean isMouseOver();
/** /**
* Set alpha multiplier for this and nested components * Set alpha multiplier for this and nested components
* *
* @param alpha alpha multiplier (dynamic value) * @param alpha alpha multiplier (dynamic value)
*/ */
void setAlpha(Num alpha); void setAlpha(Num alpha);
/** /**
* Set alpha multiplier for this and nested components * Set alpha multiplier for this and nested components
* *
* @param alpha alpha multiplier (constant value) * @param alpha alpha multiplier (constant value)
*/ */
void setAlpha(double alpha); void setAlpha(double alpha);
/** /**
* Indirectly enable / disable, used for nested hierarchies.<br> * Indirectly enable / disable, used for nested hierarchies.<br>
* When component is twice indirectly disabled, it needs to be twice * When component is twice indirectly disabled, it needs to be twice
* indirectly enabled to be enabled again. * indirectly enabled to be enabled again.
* *
* @param yes * @param yes
*/ */
void setIndirectlyEnabled(boolean yes); void setIndirectlyEnabled(boolean yes);
/** /**
* Check if the compionent is not indirectly disabled. May still be directly * Check if the compionent is not indirectly disabled. May still be directly
* disabled. * disabled.
* *
* @return indirectly enabled * @return indirectly enabled
*/ */
boolean isIndirectlyEnabled(); boolean isIndirectlyEnabled();
/** /**
* Check if the component is directly enabled (set by setEnabled()). May * Check if the component is directly enabled (set by setEnabled()). May
* still be indirectly disabled. * still be indirectly disabled.
* *
* @return directly enabled * @return directly enabled
*/ */
boolean isDirectlyEnabled(); boolean isDirectlyEnabled();
/** /**
* Set directly enabled (must be both directly and indirectly enabled to be * Set directly enabled (must be both directly and indirectly enabled to be
* enabled completely) * enabled completely)
*/ */
@Override @Override
public void setEnabled(boolean yes); public void setEnabled(boolean yes);
/** /**
* Check if the component is both directly and indirectly enabled * Check if the component is both directly and indirectly enabled
* *
* @return enabled * @return enabled
*/ */
@Override @Override

@ -1,7 +1,19 @@
package mightypork.gamecore.gui.components; package mightypork.gamecore.gui.components;
/**
* Component whose width is derived from content.<br>
* Used for Linear components.
*
* @author Ondřej Hruška (MightyPork)
*/
public interface DynamicWidthComponent extends Component { public interface DynamicWidthComponent extends Component {
/**
* Get current width, if the element has specified height
*
* @param height current height
* @return current width
*/
double computeWidth(double height); double computeWidth(double height);
} }

@ -2,11 +2,15 @@ package mightypork.gamecore.gui.components;
import mightypork.utils.eventbus.clients.ToggleableClient; import mightypork.utils.eventbus.clients.ToggleableClient;
import mightypork.utils.interfaces.Enableable;
public abstract class InputComponent extends BaseComponent implements Enableable, ToggleableClient { /**
* Component used for user input, such as buttons.
*
* @author Ondřej Hruška (MightyPork)
*/
public abstract class InputComponent extends BaseComponent implements ToggleableClient {
@Override @Override
public boolean isListening() public boolean isListening()
{ {

@ -9,77 +9,91 @@ import mightypork.utils.eventbus.clients.DelegatingList;
import mightypork.utils.math.constraints.rect.RectBound; import mightypork.utils.math.constraints.rect.RectBound;
/**
* Component that provides positioning to member components
*
* @author Ondřej Hruška (MightyPork)
*/
public abstract class LayoutComponent extends BaseComponent implements ClientHub { public abstract class LayoutComponent extends BaseComponent implements ClientHub {
private final DelegatingList clientList; private final DelegatingList clientList;
final LinkedList<Component> components = new LinkedList<>(); final LinkedList<Component> components = new LinkedList<>();
/**
* Layout component with the given context (container)
*
* @param context context
*/
public LayoutComponent(RectBound context) public LayoutComponent(RectBound context)
{ {
this.clientList = new DelegatingList(); this.clientList = new DelegatingList();
setRect(context); setRect(context);
enableCaching(true); // layout is typically updated only when screen resizes. enableCaching(true); // layout is typically updated only when screen resizes.
} }
/**
* Component without context (can be assigned a context using
* <code>setRect()</code>)
*/
public LayoutComponent() public LayoutComponent()
{ {
this(null); this(null);
} }
@Override @Override
public Collection<Object> getChildClients() public Collection<Object> getChildClients()
{ {
return clientList; return clientList;
} }
@Override @Override
public boolean doesDelegate() public boolean doesDelegate()
{ {
return clientList.doesDelegate(); return clientList.doesDelegate();
} }
@Override @Override
public boolean isListening() public boolean isListening()
{ {
return clientList.isListening(); return clientList.isListening();
} }
@Override @Override
public void addChildClient(Object client) public void addChildClient(Object client)
{ {
clientList.add(client); clientList.add(client);
} }
@Override @Override
public void removeChildClient(Object client) public void removeChildClient(Object client)
{ {
clientList.remove(client); clientList.remove(client);
} }
@Override @Override
public void setEnabled(boolean yes) public void setEnabled(boolean yes)
{ {
if (isDirectlyEnabled() != yes) { if (isDirectlyEnabled() != yes) {
super.setEnabled(yes); super.setEnabled(yes);
for (final Component c : components) { for (final Component c : components) {
c.setIndirectlyEnabled(yes); c.setIndirectlyEnabled(yes);
} }
} }
} }
/** /**
* Connect to bus and add to element list * Connect to bus and add to element list
* *
* @param component added component, whose context has already been set. * @param component added component, whose context has already been set.
*/ */
protected final void attach(Component component) protected final void attach(Component component)
@ -88,12 +102,12 @@ public abstract class LayoutComponent extends BaseComponent implements ClientHub
if (component == this) { if (component == this) {
throw new IllegalArgumentException("Uruboros. (infinite recursion evaded)"); throw new IllegalArgumentException("Uruboros. (infinite recursion evaded)");
} }
components.add(component); components.add(component);
addChildClient(component); addChildClient(component);
} }
@Override @Override
public void renderComponent() public void renderComponent()
{ {
@ -101,8 +115,8 @@ public abstract class LayoutComponent extends BaseComponent implements ClientHub
cmp.render(); cmp.render();
} }
} }
@Override @Override
public void updateLayout() public void updateLayout()
{ {
@ -110,13 +124,13 @@ public abstract class LayoutComponent extends BaseComponent implements ClientHub
cmp.updateLayout(); cmp.updateLayout();
} }
} }
@Override @Override
public void setIndirectlyEnabled(boolean yes) public void setIndirectlyEnabled(boolean yes)
{ {
super.setIndirectlyEnabled(yes); super.setIndirectlyEnabled(yes);
for (final Component cmp : components) { for (final Component cmp : components) {
cmp.setIndirectlyEnabled(yes); cmp.setIndirectlyEnabled(yes);
} }

@ -8,37 +8,43 @@ import mightypork.utils.math.constraints.vect.Vect;
import mightypork.utils.math.constraints.vect.proxy.VectAdapter; import mightypork.utils.math.constraints.vect.proxy.VectAdapter;
/**
* A linear component, one whose height and origin can be set and it's width is
* adjusted accordingly.
*
* @author Ondřej Hruška (MightyPork)
*/
public abstract class LinearComponent extends BaseComponent implements DynamicWidthComponent { public abstract class LinearComponent extends BaseComponent implements DynamicWidthComponent {
private final Rect rect = new Rect() { private final Rect rect = new Rect() {
@Override @Override
public Vect size() public Vect size()
{ {
return new Vect() { return new Vect() {
@Override @Override
public double x() public double x()
{ {
return computeWidth(y()); return computeWidth(y());
} }
@Override @Override
public double y() public double y()
{ {
return height.value(); return height.value();
} }
}; };
} }
@Override @Override
public Vect origin() public Vect origin()
{ {
return new VectAdapter() { return new VectAdapter() {
@Override @Override
protected Vect getSource() protected Vect getSource()
{ {
@ -47,30 +53,43 @@ public abstract class LinearComponent extends BaseComponent implements DynamicWi
}; };
} }
}; };
private Vect origin; private Vect origin;
private Num height; private Num height;
/**
* Create a linear component
*/
public LinearComponent() public LinearComponent()
{ {
super.setRect(rect); super.setRect(rect);
} }
@Override @Override
public void setRect(RectBound rect) public void setRect(RectBound rect)
{ {
throw new RuntimeException("Cannot assign a rect to a linear component. Set origin and height instead."); throw new RuntimeException("Cannot assign a rect to a linear component. Set origin and height instead.");
} }
/**
* Set component's height
*
* @param height the height
*/
public void setHeight(Num height) public void setHeight(Num height)
{ {
this.height = height; this.height = height;
} }
/**
* Set component's origin
*
* @param origin origin
*/
public void setOrigin(Vect origin) public void setOrigin(Vect origin)
{ {
this.origin = origin; this.origin = origin;

@ -9,20 +9,20 @@ import mightypork.utils.math.constraints.rect.RectBound;
/** /**
* Renderable that can be assigned different context * Renderable that can be assigned different context
* *
* @author Ondřej Hruška (MightyPork) * @author Ondřej Hruška (MightyPork)
*/ */
public interface PluggableRenderable extends Renderable, PluggableRectBound { public interface PluggableRenderable extends Renderable, PluggableRectBound {
@Override @Override
void render(); void render();
@Override @Override
Rect getRect(); Rect getRect();
@Override @Override
void setRect(RectBound rect); void setRect(RectBound rect);
} }

@ -2,47 +2,47 @@ package mightypork.gamecore.gui.components.input;
import mightypork.gamecore.gui.Action; import mightypork.gamecore.gui.Action;
import mightypork.gamecore.gui.ActionTrigger; import mightypork.gamecore.gui.HasAction;
import mightypork.gamecore.gui.components.InputComponent; import mightypork.gamecore.gui.components.InputComponent;
import mightypork.gamecore.input.events.MouseButtonEvent; import mightypork.gamecore.input.events.MouseButtonEvent;
import mightypork.gamecore.input.events.MouseButtonHandler; import mightypork.gamecore.input.events.MouseButtonHandler;
public abstract class ClickableComponent extends InputComponent implements ActionTrigger, MouseButtonHandler { public abstract class ClickableComponent extends InputComponent implements HasAction, MouseButtonHandler {
protected boolean btnDownOver; protected boolean btnDownOver;
private Action action; private Action action;
@Override @Override
public void setAction(Action action) public void setAction(Action action)
{ {
this.action = action; this.action = action;
} }
protected void triggerAction() protected void triggerAction()
{ {
if (action != null && isEnabled()) action.run(); if (action != null && isEnabled()) action.run();
} }
@Override @Override
public void receive(MouseButtonEvent event) public void receive(MouseButtonEvent event)
{ {
if (!event.isButtonEvent()) return; if (!event.isButtonEvent()) return;
if (event.isDown()) { if (event.isDown()) {
btnDownOver = event.isOver(this); btnDownOver = event.isOver(this);
} }
if (event.isUp()) { if (event.isUp()) {
if (btnDownOver && event.isOver(this)) { if (btnDownOver && event.isOver(this)) {
triggerAction(); triggerAction();
event.consume(); event.consume();
} }
btnDownOver = false; btnDownOver = false;
} }
} }

@ -9,41 +9,41 @@ import mightypork.utils.eventbus.clients.DelegatingClient;
public class ClickableWrapper extends ClickableComponent implements DelegatingClient { public class ClickableWrapper extends ClickableComponent implements DelegatingClient {
private final Component wrapped; private final Component wrapped;
private final ClientList list; private final ClientList list;
public ClickableWrapper(Component wrapped) public ClickableWrapper(Component wrapped)
{ {
this.wrapped = wrapped; this.wrapped = wrapped;
wrapped.setRect(this); wrapped.setRect(this);
list = new ClientList(wrapped); list = new ClientList(wrapped);
} }
@Override @Override
public Collection<?> getChildClients() public Collection<?> getChildClients()
{ {
return list; return list;
} }
@Override @Override
public boolean doesDelegate() public boolean doesDelegate()
{ {
return true; return true;
} }
@Override @Override
protected void renderComponent() protected void renderComponent()
{ {
wrapped.render(); wrapped.render();
} }
@Override @Override
public void setEnabled(boolean yes) public void setEnabled(boolean yes)
{ {
@ -52,13 +52,13 @@ public class ClickableWrapper extends ClickableComponent implements DelegatingCl
wrapped.setIndirectlyEnabled(yes); wrapped.setIndirectlyEnabled(yes);
} }
} }
@Override @Override
public void setIndirectlyEnabled(boolean yes) public void setIndirectlyEnabled(boolean yes)
{ {
super.setIndirectlyEnabled(yes); super.setIndirectlyEnabled(yes);
wrapped.setIndirectlyEnabled(yes); wrapped.setIndirectlyEnabled(yes);
} }
} }

@ -14,35 +14,35 @@ import mightypork.utils.math.constraints.vect.var.VectVar;
/** /**
* Menu-like button with shadow and push state * Menu-like button with shadow and push state
* *
* @author Ondřej Hruška (MightyPork) * @author Ondřej Hruška (MightyPork)
*/ */
public class TextButton extends ClickableComponent implements DynamicWidthComponent { public class TextButton extends ClickableComponent implements DynamicWidthComponent {
public final TextPainter textPainter; public final TextPainter textPainter;
private final VectVar offset = Vect.makeVar(); private final VectVar offset = Vect.makeVar();
public Vect offsetPassive = height().div(16).toVectXY(); public Vect offsetPassive = height().div(16).toVectXY();
public Vect offsetOver = height().div(20).toVectXY(); public Vect offsetOver = height().div(20).toVectXY();
public Vect offsetUnder = height().div(32).toVectXY(); public Vect offsetUnder = height().div(32).toVectXY();
private final Color color; private final Color color;
private boolean hoverMove = true; private boolean hoverMove = true;
public TextButton(IFont font, String text, Color color) public TextButton(IFont font, String text, Color color)
{ {
this.color = color; this.color = color;
this.textPainter = new TextPainter(font, AlignX.CENTER, this.color, text); this.textPainter = new TextPainter(font, AlignX.CENTER, this.color, text);
this.textPainter.setRect(this); this.textPainter.setRect(this);
this.textPainter.setShadow(RGB.BLACK_30, offset); this.textPainter.setShadow(RGB.BLACK_30, offset);
textPainter.setVPaddingPercent(5); textPainter.setVPaddingPercent(5);
} }
@Override @Override
protected void renderComponent() protected void renderComponent()
{ {
@ -55,11 +55,11 @@ public class TextButton extends ClickableComponent implements DynamicWidthCompon
} else { } else {
offset.setTo(offsetPassive); offset.setTo(offsetPassive);
} }
textPainter.render(); textPainter.render();
} }
/** /**
* Disable offset change on hover * Disable offset change on hover
*/ */
@ -67,12 +67,12 @@ public class TextButton extends ClickableComponent implements DynamicWidthCompon
{ {
hoverMove = false; hoverMove = false;
} }
@Override @Override
public double computeWidth(double height) public double computeWidth(double height)
{ {
return textPainter.computeWidth(height); return textPainter.computeWidth(height);
} }
} }

@ -6,37 +6,37 @@ import mightypork.utils.math.constraints.rect.RectBound;
public class ColumnLayout extends GridLayout { public class ColumnLayout extends GridLayout {
private int col = 0; private int col = 0;
public ColumnLayout(int rows) public ColumnLayout(int rows)
{ {
this(null, rows); this(null, rows);
} }
public ColumnLayout(RectBound context, int cols) public ColumnLayout(RectBound context, int cols)
{ {
super(context, 1, cols); super(context, 1, cols);
} }
public void add(final Component elem) public void add(final Component elem)
{ {
add(elem, 1); add(elem, 1);
} }
public void add(final Component elem, int colSpan) public void add(final Component elem, int colSpan)
{ {
if (elem == null) return; if (elem == null) return;
put(elem, 0, col, 1, colSpan); put(elem, 0, col, 1, colSpan);
col += colSpan; col += colSpan;
} }
public void skip(int cols) public void skip(int cols)
{ {
col += cols; col += cols;

@ -8,31 +8,31 @@ import mightypork.utils.math.constraints.rect.RectBound;
/** /**
* Layout for components with arbitrary constraints. * Layout for components with arbitrary constraints.
* *
* @author Ondřej Hruška (MightyPork) * @author Ondřej Hruška (MightyPork)
*/ */
public class ConstraintLayout extends LayoutComponent { public class ConstraintLayout extends LayoutComponent {
public ConstraintLayout() public ConstraintLayout()
{ {
} }
public ConstraintLayout(RectBound context) public ConstraintLayout(RectBound context)
{ {
super(context); super(context);
} }
/** /**
* Add a component to the layout.<br> * Add a component to the layout.<br>
* The component's rect must be set up manually. * The component's rect must be set up manually.
* *
* @param component * @param component
*/ */
public void add(Component component) public void add(Component component)
{ {
attach(component); attach(component);
} }
} }

@ -11,16 +11,16 @@ import mightypork.utils.math.constraints.rect.RectBound;
/** /**
* Holder with same-sized columns, aligned to left or right * Holder with same-sized columns, aligned to left or right
* *
* @author Ondřej Hruška (MightyPork) * @author Ondřej Hruška (MightyPork)
*/ */
public class FlowColumnLayout extends LayoutComponent { public class FlowColumnLayout extends LayoutComponent {
private int col = 0; private int col = 0;
private Num elementWidth; private Num elementWidth;
private final AlignX align; private final AlignX align;
/** /**
* @param context context * @param context context
* @param elementWidth width of all elements * @param elementWidth width of all elements
@ -31,17 +31,17 @@ public class FlowColumnLayout extends LayoutComponent {
super(context); super(context);
this.elementWidth = elementWidth; this.elementWidth = elementWidth;
this.align = align; this.align = align;
if (align != AlignX.LEFT && align != AlignX.RIGHT) { if (align != AlignX.LEFT && align != AlignX.RIGHT) {
throw new IllegalArgumentException("Can align only left or right."); throw new IllegalArgumentException("Can align only left or right.");
} }
} }
/** /**
* make a new holder.<br> * make a new holder.<br>
* Context must be assigned before rendering. * Context must be assigned before rendering.
* *
* @param elementWidth width of all elements * @param elementWidth width of all elements
* @param align component align. Legal values are LEFT and RIGHT. * @param align component align. Legal values are LEFT and RIGHT.
*/ */
@ -49,19 +49,19 @@ public class FlowColumnLayout extends LayoutComponent {
{ {
this(null, elementWidth, align); this(null, elementWidth, align);
} }
/** /**
* Add an item * Add an item
* *
* @param elem * @param elem
*/ */
public void add(final Component elem) public void add(final Component elem)
{ {
if (elem == null) return; if (elem == null) return;
final Rect r; final Rect r;
switch (align) { switch (align) {
case LEFT: case LEFT:
r = leftEdge().growRight(elementWidth).moveX(elementWidth.mul(col++)); r = leftEdge().growRight(elementWidth).moveX(elementWidth.mul(col++));
@ -72,16 +72,16 @@ public class FlowColumnLayout extends LayoutComponent {
default: default:
throw new IllegalArgumentException("Bad align."); throw new IllegalArgumentException("Bad align.");
} }
elem.setRect(r); elem.setRect(r);
attach(elem); attach(elem);
} }
public void setElementWidth(Num elementWidth) public void setElementWidth(Num elementWidth)
{ {
this.elementWidth = elementWidth; this.elementWidth = elementWidth;
} }
} }

@ -11,16 +11,16 @@ import mightypork.utils.math.constraints.rect.RectBound;
/** /**
* Holder with same-sized rows, aligned to top or bottom * Holder with same-sized rows, aligned to top or bottom
* *
* @author Ondřej Hruška (MightyPork) * @author Ondřej Hruška (MightyPork)
*/ */
public class FlowRowLayout extends LayoutComponent { public class FlowRowLayout extends LayoutComponent {
private int row = 0; private int row = 0;
private Num elementHeight; private Num elementHeight;
private final AlignY align; private final AlignY align;
/** /**
* @param context context * @param context context
* @param elementHeight height of all elements * @param elementHeight height of all elements
@ -31,17 +31,17 @@ public class FlowRowLayout extends LayoutComponent {
super(context); super(context);
this.elementHeight = elementHeight; this.elementHeight = elementHeight;
this.align = align; this.align = align;
if (align != AlignY.TOP && align != AlignY.BOTTOM) { if (align != AlignY.TOP && align != AlignY.BOTTOM) {
throw new IllegalArgumentException("Can align only to top or bottom."); throw new IllegalArgumentException("Can align only to top or bottom.");
} }
} }
/** /**
* make a new holder.<br> * make a new holder.<br>
* Context must be assigned before rendering. * Context must be assigned before rendering.
* *
* @param elementHeight height of all elements * @param elementHeight height of all elements
* @param align component align. Legal values are TOP and BOTTOM. * @param align component align. Legal values are TOP and BOTTOM.
*/ */
@ -49,19 +49,19 @@ public class FlowRowLayout extends LayoutComponent {
{ {
this(null, elementHeight, align); this(null, elementHeight, align);
} }
/** /**
* Add an item * Add an item
* *
* @param elem * @param elem
*/ */
public void add(final Component elem) public void add(final Component elem)
{ {
if (elem == null) return; if (elem == null) return;
final Rect r; final Rect r;
switch (align) { switch (align) {
case TOP: case TOP:
r = topEdge().growDown(elementHeight).moveY(elementHeight.mul(row++)); r = topEdge().growDown(elementHeight).moveY(elementHeight.mul(row++));
@ -72,13 +72,13 @@ public class FlowRowLayout extends LayoutComponent {
default: default:
throw new IllegalArgumentException("Bad align."); throw new IllegalArgumentException("Bad align.");
} }
elem.setRect(r); elem.setRect(r);
attach(elem); attach(elem);
} }
public void setElementHeight(Num elementHeight) public void setElementHeight(Num elementHeight)
{ {
this.elementHeight = elementHeight; this.elementHeight = elementHeight;

@ -9,14 +9,14 @@ import mightypork.utils.math.constraints.rect.builders.TiledRect;
/** /**
* Holder with table cells * Holder with table cells
* *
* @author Ondřej Hruška (MightyPork) * @author Ondřej Hruška (MightyPork)
*/ */
public class GridLayout extends LayoutComponent { public class GridLayout extends LayoutComponent {
private final TiledRect tiler; private final TiledRect tiler;
/** /**
* @param context context * @param context context
* @param rows number of rows * @param rows number of rows
@ -27,12 +27,12 @@ public class GridLayout extends LayoutComponent {
super(context); super(context);
this.tiler = tiles(cols, rows); this.tiler = tiles(cols, rows);
} }
/** /**
* make a new holder.<br> * make a new holder.<br>
* Context must be assigned before rendering. * Context must be assigned before rendering.
* *
* @param rows number of rows * @param rows number of rows
* @param cols number of columns * @param cols number of columns
*/ */
@ -40,11 +40,11 @@ public class GridLayout extends LayoutComponent {
{ {
this(null, rows, cols); this(null, rows, cols);
} }
/** /**
* Add a row to the holder. * Add a row to the holder.
* *
* @param row row (one-based) * @param row row (one-based)
* @param column column (one-based) * @param column column (one-based)
* @param elem added component * @param elem added component
@ -52,16 +52,16 @@ public class GridLayout extends LayoutComponent {
public void put(Component elem, int row, int column) public void put(Component elem, int row, int column)
{ {
if (elem == null) return; if (elem == null) return;
elem.setRect(tiler.tile(column, row)); elem.setRect(tiler.tile(column, row));
attach(elem); attach(elem);
} }
/** /**
* Put with span * Put with span
* *
* @param elem * @param elem
* @param row * @param row
* @param column * @param column
@ -71,10 +71,10 @@ public class GridLayout extends LayoutComponent {
public void put(Component elem, int row, int column, int rowspan, int colspan) public void put(Component elem, int row, int column, int rowspan, int colspan)
{ {
if (elem == null) return; if (elem == null) return;
elem.setRect(tiler.span(column, row, colspan, rowspan)); elem.setRect(tiler.span(column, row, colspan, rowspan));
attach(elem); attach(elem);
} }
} }

@ -6,11 +6,11 @@ import mightypork.gamecore.gui.components.BaseComponent;
/** /**
* Invisible component that does nothing at all; Null object pattern * Invisible component that does nothing at all; Null object pattern
* *
* @author Ondřej Hruška (MightyPork) * @author Ondřej Hruška (MightyPork)
*/ */
public class NullComponent extends BaseComponent { public class NullComponent extends BaseComponent {
@Override @Override
protected void renderComponent() protected void renderComponent()
{ {

@ -6,37 +6,37 @@ import mightypork.utils.math.constraints.rect.RectBound;
public class RowLayout extends GridLayout { public class RowLayout extends GridLayout {
private int row = 0; private int row = 0;
public RowLayout(int rows) public RowLayout(int rows)
{ {
this(null, rows); this(null, rows);
} }
public RowLayout(RectBound context, int rows) public RowLayout(RectBound context, int rows)
{ {
super(context, rows, 1); super(context, rows, 1);
} }
public void add(final Component elem) public void add(final Component elem)
{ {
add(elem, 1); add(elem, 1);
} }
public void add(final Component elem, int rowSpan) public void add(final Component elem, int rowSpan)
{ {
if (elem == null) return; if (elem == null) return;
put(elem, row, 0, rowSpan, 1); put(elem, row, 0, rowSpan, 1);
row += rowSpan; row += rowSpan;
} }
public void skip(int rows) public void skip(int rows)
{ {
row += rows; row += rows;

@ -11,15 +11,15 @@ import mightypork.utils.eventbus.clients.DelegatingClient;
/** /**
* Converts a component into a linear component * Converts a component into a linear component
* *
* @author Ondřej Hruška (MightyPork) * @author Ondřej Hruška (MightyPork)
*/ */
public abstract class AbstractLinearWrapper extends LinearComponent implements DelegatingClient { public abstract class AbstractLinearWrapper extends LinearComponent implements DelegatingClient {
protected final Component wrapped; protected final Component wrapped;
private final ClientList list; private final ClientList list;
/** /**
* @param wrapped wrapped component. Can be null. * @param wrapped wrapped component. Can be null.
*/ */
@ -34,32 +34,32 @@ public abstract class AbstractLinearWrapper extends LinearComponent implements D
wrapped.setRect(this); wrapped.setRect(this);
} }
} }
list = new ClientList(wrapped); list = new ClientList(wrapped);
} }
@Override @Override
protected void renderComponent() protected void renderComponent()
{ {
if (wrapped != null) wrapped.render(); if (wrapped != null) wrapped.render();
} }
@Override @Override
public Collection<?> getChildClients() public Collection<?> getChildClients()
{ {
return list; return list;
} }
@Override @Override
public boolean doesDelegate() public boolean doesDelegate()
{ {
return true; return true;
} }
@Override @Override
public void setEnabled(boolean yes) public void setEnabled(boolean yes)
{ {
@ -68,8 +68,8 @@ public abstract class AbstractLinearWrapper extends LinearComponent implements D
wrapped.setIndirectlyEnabled(yes); wrapped.setIndirectlyEnabled(yes);
} }
} }
@Override @Override
public void setIndirectlyEnabled(boolean yes) public void setIndirectlyEnabled(boolean yes)
{ {

@ -7,17 +7,17 @@ import mightypork.utils.math.constraints.num.Num;
/** /**
* Gap in linear layout * Gap in linear layout
* *
* @author Ondřej Hruška (MightyPork) * @author Ondřej Hruška (MightyPork)
*/ */
public class LinearGap extends LinearRectangle { public class LinearGap extends LinearRectangle {
public LinearGap(Num width) public LinearGap(Num width)
{ {
super(new NullComponent(), width); super(new NullComponent(), width);
} }
public LinearGap(double heightPercent) public LinearGap(double heightPercent)
{ {
this(Num.ZERO); this(Num.ZERO);

@ -16,31 +16,31 @@ import mightypork.utils.math.constraints.vect.proxy.VectAdapter;
* Layout that aligns elements while taking into account their actual * Layout that aligns elements while taking into account their actual
* dimensions.<br> * dimensions.<br>
* Useful eg. for buttons that stretch based on text length. * Useful eg. for buttons that stretch based on text length.
* *
* @author Ondřej Hruška (MightyPork) * @author Ondřej Hruška (MightyPork)
*/ */
public class LinearLayout extends LayoutComponent { public class LinearLayout extends LayoutComponent {
public LinearLayout(AlignX align) public LinearLayout(AlignX align)
{ {
this.align = align; this.align = align;
} }
public LinearLayout(RectBound context, AlignX align) public LinearLayout(RectBound context, AlignX align)
{ {
super(context); super(context);
this.align = align; this.align = align;
} }
private final NumSum totalWidth = new NumSum(); private final NumSum totalWidth = new NumSum();
private final Vect leftAlignOrigin = LinearLayout.this.origin(); private final Vect leftAlignOrigin = LinearLayout.this.origin();
private final Vect centerAlignOrigin = LinearLayout.this.topCenter().sub(totalWidth.half(), Num.ZERO); private final Vect centerAlignOrigin = LinearLayout.this.topCenter().sub(totalWidth.half(), Num.ZERO);
private final Vect rightAlignOrigin = LinearLayout.this.topRight().sub(totalWidth, Num.ZERO); private final Vect rightAlignOrigin = LinearLayout.this.topRight().sub(totalWidth, Num.ZERO);
private final Vect leftMostOrigin = new VectAdapter() { private final Vect leftMostOrigin = new VectAdapter() {
@Override @Override
protected Vect getSource() protected Vect getSource()
{ {
@ -55,18 +55,18 @@ public class LinearLayout extends LayoutComponent {
} }
} }
}; };
private Vect nextOrigin = leftMostOrigin; private Vect nextOrigin = leftMostOrigin;
private AlignX align = AlignX.LEFT; private AlignX align = AlignX.LEFT;
public void add(DynamicWidthComponent dwcomp) public void add(DynamicWidthComponent dwcomp)
{ {
add(new LinearWrapper(dwcomp)); add(new LinearWrapper(dwcomp));
} }
public void add(LinearComponent lincomp) public void add(LinearComponent lincomp)
{ {
lincomp.setHeight(height()); lincomp.setHeight(height());
@ -75,17 +75,17 @@ public class LinearLayout extends LayoutComponent {
totalWidth.addSummand(lincomp.width()); totalWidth.addSummand(lincomp.width());
attach(lincomp); attach(lincomp);
} }
public void setAlign(AlignX align) public void setAlign(AlignX align)
{ {
this.align = align; this.align = align;
} }
/** /**
* Add a gap. * Add a gap.
* *
* @param heightPercent percent of height for gap width * @param heightPercent percent of height for gap width
*/ */
public void gap(double heightPercent) public void gap(double heightPercent)

@ -6,27 +6,27 @@ import mightypork.utils.math.constraints.num.Num;
public class LinearRectangle extends AbstractLinearWrapper { public class LinearRectangle extends AbstractLinearWrapper {
private Num width; private Num width;
public LinearRectangle(Component wrapped, Num width) public LinearRectangle(Component wrapped, Num width)
{ {
super(wrapped); super(wrapped);
this.width = width; this.width = width;
} }
public void setWidth(Num width) public void setWidth(Num width)
{ {
this.width = width; this.width = width;
} }
@Override @Override
public double computeWidth(double height) public double computeWidth(double height)
{ {
return this.width.value(); return this.width.value();
} }
} }

@ -5,17 +5,17 @@ import mightypork.gamecore.gui.components.Component;
public class LinearSquare extends AbstractLinearWrapper { public class LinearSquare extends AbstractLinearWrapper {
public LinearSquare(Component wrapped) public LinearSquare(Component wrapped)
{ {
super(wrapped); super(wrapped);
} }
@Override @Override
public double computeWidth(double height) public double computeWidth(double height)
{ {
return height; return height;
} }
} }

@ -5,17 +5,17 @@ import mightypork.gamecore.gui.components.DynamicWidthComponent;
public class LinearWrapper extends AbstractLinearWrapper { public class LinearWrapper extends AbstractLinearWrapper {
public LinearWrapper(DynamicWidthComponent wrapped) public LinearWrapper(DynamicWidthComponent wrapped)
{ {
super(wrapped); super(wrapped);
} }
@Override @Override
public double computeWidth(double height) public double computeWidth(double height)
{ {
return ((DynamicWidthComponent) wrapped).computeWidth(height); return ((DynamicWidthComponent) wrapped).computeWidth(height);
} }
} }

@ -9,7 +9,7 @@ import mightypork.gamecore.gui.components.DynamicWidthComponent;
/** /**
* Draws image in given rect * Draws image in given rect
* *
* @author Ondřej Hruška (MightyPork) * @author Ondřej Hruška (MightyPork)
*/ */
public class ImagePainter extends BaseComponent implements DynamicWidthComponent { public class ImagePainter extends BaseComponent implements DynamicWidthComponent {
@ -40,6 +40,11 @@ public class ImagePainter extends BaseComponent implements DynamicWidthComponent
} }
/**
* Set drawn {@link TxQuad}
*
* @param txQuad the drawn quad
*/
public void setTxQuad(TxQuad txQuad) public void setTxQuad(TxQuad txQuad)
{ {
this.txQuad = txQuad; this.txQuad = txQuad;

@ -10,41 +10,41 @@ import mightypork.utils.math.color.Grad;
/** /**
* Draws image in given rect * Draws image in given rect
* *
* @author Ondřej Hruška (MightyPork) * @author Ondřej Hruška (MightyPork)
*/ */
public class QuadPainter extends BaseComponent { public class QuadPainter extends BaseComponent {
@FactoryMethod @FactoryMethod
public static QuadPainter gradH(Color colorLeft, Color colorRight) public static QuadPainter gradH(Color colorLeft, Color colorRight)
{ {
return new QuadPainter(colorLeft, colorRight, colorRight, colorLeft); return new QuadPainter(colorLeft, colorRight, colorRight, colorLeft);
} }
@FactoryMethod @FactoryMethod
public static QuadPainter gradV(Color colorTop, Color colorBottom) public static QuadPainter gradV(Color colorTop, Color colorBottom)
{ {
return new QuadPainter(colorTop, colorTop, colorBottom, colorBottom); return new QuadPainter(colorTop, colorTop, colorBottom, colorBottom);
} }
private final Grad grad; private final Grad grad;
/** /**
* Painter with solid color * Painter with solid color
* *
* @param color * @param color
*/ */
public QuadPainter(Color color) public QuadPainter(Color color)
{ {
this.grad = new Grad(color, color, color, color); this.grad = new Grad(color, color, color, color);
} }
/** /**
* Painter with coloured vertices. * Painter with coloured vertices.
* *
* @param leftTop * @param leftTop
* @param rightTop * @param rightTop
* @param leftBottom * @param leftBottom
@ -54,8 +54,8 @@ public class QuadPainter extends BaseComponent {
{ {
this.grad = new Grad(leftTop, rightTop, rightBottom, leftBottom); this.grad = new Grad(leftTop, rightTop, rightBottom, leftBottom);
} }
@Override @Override
public void renderComponent() public void renderComponent()
{ {

@ -18,24 +18,24 @@ import mightypork.utils.string.StringWrapper;
/** /**
* Text painting component. * Text painting component.
* *
* @author Ondřej Hruška (MightyPork) * @author Ondřej Hruška (MightyPork)
*/ */
public class TextPainter extends BaseComponent implements DynamicWidthComponent { public class TextPainter extends BaseComponent implements DynamicWidthComponent {
private static final boolean DEBUG_FONT_RENDER = false; private static final boolean DEBUG_FONT_RENDER = false;
private final FontRenderer font; private final FontRenderer font;
private Color color; private Color color;
private AlignX align; private AlignX align;
private StringProvider text; private StringProvider text;
private boolean shadow; private boolean shadow;
private double yPaddingPerc = 0; private double yPaddingPerc = 0;
private Color shadowColor = RGB.BLACK; private Color shadowColor = RGB.BLACK;
private Vect shadowOffset = Vect.make(2, 2); private Vect shadowOffset = Vect.make(2, 2);
/** /**
* @param font font to use * @param font font to use
*/ */
@ -43,32 +43,32 @@ public class TextPainter extends BaseComponent implements DynamicWidthComponent
{ {
this(font, AlignX.LEFT, RGB.WHITE); this(font, AlignX.LEFT, RGB.WHITE);
} }
public TextPainter(IFont font, Color color, String text) public TextPainter(IFont font, Color color, String text)
{ {
this(font, AlignX.LEFT, color, new StringWrapper(text)); this(font, AlignX.LEFT, color, new StringWrapper(text));
} }
public TextPainter(IFont font, Color color, StringProvider text) public TextPainter(IFont font, Color color, StringProvider text)
{ {
this(font, AlignX.LEFT, color, text); this(font, AlignX.LEFT, color, text);
} }
public TextPainter(IFont font, Color color) public TextPainter(IFont font, Color color)
{ {
this(font, AlignX.LEFT, color, (StringProvider) null); this(font, AlignX.LEFT, color, (StringProvider) null);
} }
public TextPainter(IFont font, AlignX align, Color color, String text) public TextPainter(IFont font, AlignX align, Color color, String text)
{ {
this(font, align, color, new StringWrapper(text)); this(font, align, color, new StringWrapper(text));
} }
public TextPainter(IFont font, AlignX align, Color color, StringProvider text) public TextPainter(IFont font, AlignX align, Color color, StringProvider text)
{ {
this.font = new FontRenderer(font); this.font = new FontRenderer(font);
@ -76,92 +76,92 @@ public class TextPainter extends BaseComponent implements DynamicWidthComponent
this.align = align; this.align = align;
this.text = text; this.text = text;
} }
public TextPainter(IFont font, AlignX align, Color color) public TextPainter(IFont font, AlignX align, Color color)
{ {
this(font, align, color, (StringProvider) null); this(font, align, color, (StringProvider) null);
} }
@Override @Override
public void renderComponent() public void renderComponent()
{ {
if (text == null) return; if (text == null) return;
final String str = text.getString(); final String str = text.getString();
final Num shrY = height().perc(yPaddingPerc); final Num shrY = height().perc(yPaddingPerc);
final Rect rect = getRect().shrink(Num.ZERO, shrY); final Rect rect = getRect().shrink(Num.ZERO, shrY);
if (shadow) { if (shadow) {
font.draw(str, rect.round(), align, shadowColor); font.draw(str, rect.round(), align, shadowColor);
} }
final Rect r = (shadow ? rect.move(shadowOffset.neg()) : rect).round(); final Rect r = (shadow ? rect.move(shadowOffset.neg()) : rect).round();
font.draw(str, r, align, color); font.draw(str, r, align, color);
if (DEBUG_FONT_RENDER) App.gfx().quad(r, RGB.PINK.withAlpha(0.4)); if (DEBUG_FONT_RENDER) App.gfx().quad(r, RGB.PINK.withAlpha(0.4));
} }
public void setShadow(Color color, Vect offset) public void setShadow(Color color, Vect offset)
{ {
setShadow(true); setShadow(true);
setShadowColor(color); setShadowColor(color);
setShadowOffset(offset); setShadowOffset(offset);
} }
public void setShadow(boolean shadow) public void setShadow(boolean shadow)
{ {
this.shadow = shadow; this.shadow = shadow;
} }
public void setShadowColor(Color shadowColor) public void setShadowColor(Color shadowColor)
{ {
this.shadowColor = shadowColor; this.shadowColor = shadowColor;
} }
public void setShadowOffset(Vect shadowOffset) public void setShadowOffset(Vect shadowOffset)
{ {
this.shadowOffset = shadowOffset; this.shadowOffset = shadowOffset;
} }
public void setColor(Color color) public void setColor(Color color)
{ {
this.color = color; this.color = color;
} }
public void setAlign(AlignX align) public void setAlign(AlignX align)
{ {
this.align = align; this.align = align;
} }
public void setText(String text) public void setText(String text)
{ {
this.text = new StringWrapper(text); this.text = new StringWrapper(text);
} }
public void setText(StringProvider text) public void setText(StringProvider text)
{ {
this.text = text; this.text = text;
} }
public void setVPaddingPercent(double percY) public void setVPaddingPercent(double percY)
{ {
yPaddingPerc = percY; yPaddingPerc = percY;
} }
@Override @Override
public double computeWidth(double height) public double computeWidth(double height)
{ {

@ -9,20 +9,17 @@ import mightypork.utils.eventbus.events.flags.NonRejectableEvent;
/** /**
* Intended use is to notify UI component sub-clients that they should poll * Intended use is to notify UI component sub-clients that they should poll
* their cached constraints. * their cached constraints.<br>
* * Is {@link NonRejectableEvent} to force update even of hidden screens and
* layers.
*
* @author Ondřej Hruška (MightyPork) * @author Ondřej Hruška (MightyPork)
*/ */
@DirectEvent @DirectEvent
@NonConsumableEvent @NonConsumableEvent
@NonRejectableEvent @NonRejectableEvent
public class LayoutChangeEvent extends BusEvent<LayoutChangeListener> { public class LayoutChangeEvent extends BusEvent<LayoutChangeListener> {
public LayoutChangeEvent()
{
}
@Override @Override
public void handleBy(LayoutChangeListener handler) public void handleBy(LayoutChangeListener handler)
{ {

@ -1,7 +1,15 @@
package mightypork.gamecore.gui.events; package mightypork.gamecore.gui.events;
/**
* Receives notifications about layout change
*
* @author Ondřej Hruška (MightyPork)
*/
public interface LayoutChangeListener { public interface LayoutChangeListener {
/**
* Triggered when display size changed and GUI should be recalculated.
*/
public void onLayoutChanged(); public void onLayoutChanged();
} }

@ -1,13 +1,14 @@
package mightypork.gamecore.gui.events; package mightypork.gamecore.gui.events;
import mightypork.gamecore.gui.screens.ScreenRegistry;
import mightypork.utils.eventbus.BusEvent; import mightypork.utils.eventbus.BusEvent;
import mightypork.utils.eventbus.events.flags.SingleReceiverEvent; import mightypork.utils.eventbus.events.flags.SingleReceiverEvent;
/** /**
* Request to change screen * Request to change screen in {@link ScreenRegistry}
* *
* @author Ondřej Hruška (MightyPork) * @author Ondřej Hruška (MightyPork)
*/ */
@SingleReceiverEvent @SingleReceiverEvent
@ -17,6 +18,8 @@ public class ScreenRequest extends BusEvent<ScreenRequestListener> {
/** /**
* Create a request to change screen
*
* @param screenKey screen name * @param screenKey screen name
*/ */
public ScreenRequest(String screenKey) public ScreenRequest(String screenKey)

@ -3,11 +3,11 @@ package mightypork.gamecore.gui.events;
/** /**
* {@link ScreenRequest} listener * {@link ScreenRequest} listener
* *
* @author Ondřej Hruška (MightyPork) * @author Ondřej Hruška (MightyPork)
*/ */
public interface ScreenRequestListener { public interface ScreenRequestListener {
/** /**
* @param key screen to show * @param key screen to show
*/ */

@ -9,16 +9,16 @@ import mightypork.utils.math.constraints.vect.Vect;
/** /**
* Screen resolution or mode was changed * Screen resolution or mode was changed
* *
* @author Ondřej Hruška (MightyPork) * @author Ondřej Hruška (MightyPork)
*/ */
@NonConsumableEvent @NonConsumableEvent
@NotLoggedEvent @NotLoggedEvent
public class ViewportChangeEvent extends BusEvent<ViewportChangeListener> { public class ViewportChangeEvent extends BusEvent<ViewportChangeListener> {
private final Vect screenSize; private final Vect screenSize;
/** /**
* @param size new screen size * @param size new screen size
*/ */
@ -26,8 +26,8 @@ public class ViewportChangeEvent extends BusEvent<ViewportChangeListener> {
{ {
this.screenSize = size; this.screenSize = size;
} }
/** /**
* @return new screen size * @return new screen size
*/ */
@ -35,8 +35,8 @@ public class ViewportChangeEvent extends BusEvent<ViewportChangeListener> {
{ {
return screenSize; return screenSize;
} }
@Override @Override
public void handleBy(ViewportChangeListener handler) public void handleBy(ViewportChangeListener handler)
{ {

@ -3,14 +3,14 @@ package mightypork.gamecore.gui.events;
/** /**
* {@link ViewportChangeEvent} listener * {@link ViewportChangeEvent} listener
* *
* @author Ondřej Hruška (MightyPork) * @author Ondřej Hruška (MightyPork)
*/ */
public interface ViewportChangeListener { public interface ViewportChangeListener {
/** /**
* Handle event * Handle event
* *
* @param event * @param event
*/ */
void onViewportChanged(ViewportChangeEvent event); void onViewportChanged(ViewportChangeEvent event);

@ -11,47 +11,51 @@ import mightypork.utils.eventbus.clients.DelegatingClient;
/** /**
* Screen with multiple instances of {@link ScreenLayer} * Screen with multiple instances of {@link ScreenLayer}. Layers specify their
* * rendering and event priority.
*
* @author Ondřej Hruška (MightyPork) * @author Ondřej Hruška (MightyPork)
*/ */
public abstract class LayeredScreen extends Screen { public abstract class LayeredScreen extends Screen {
/** /**
* Wrapper for delegating client, to use custom client ordering. * Wrapper for delegating client, to use custom client ordering.
* *
* @author Ondřej Hruška (MightyPork) * @author Ondřej Hruška (MightyPork)
*/ */
private class LayersClient implements DelegatingClient { private class LayersClient implements DelegatingClient {
@SuppressWarnings({ "unchecked", "rawtypes" }) @SuppressWarnings({ "unchecked", "rawtypes" })
@Override @Override
public Collection getChildClients() public Collection getChildClients()
{ {
return layersByEventPriority; return layersByEventPriority;
} }
@Override @Override
public boolean doesDelegate() public boolean doesDelegate()
{ {
return true; return true;
} }
} }
private final List<ScreenLayer> layersByZIndex = new ArrayList<>(); private final List<ScreenLayer> layersByZIndex = new ArrayList<>();
private final List<ScreenLayer> layersByEventPriority = new ArrayList<>(); private final List<ScreenLayer> layersByEventPriority = new ArrayList<>();
private final LayersClient layersClient = new LayersClient(); private final LayersClient layersClient = new LayersClient();
/**
* Create a layered screen
*/
public LayeredScreen() public LayeredScreen()
{ {
addChildClient(layersClient); addChildClient(layersClient);
} }
@Override @Override
protected void renderScreen() protected void renderScreen()
{ {
@ -59,40 +63,40 @@ public abstract class LayeredScreen extends Screen {
if (layer.isVisible()) layer.render(); if (layer.isVisible()) layer.render();
} }
} }
/** /**
* Add a layer to the screen. * Add a layer to the screen.
* *
* @param layer * @param layer the layer to add
*/ */
protected void addLayer(ScreenLayer layer) protected void addLayer(ScreenLayer layer)
{ {
this.layersByZIndex.add(layer); this.layersByZIndex.add(layer);
this.layersByEventPriority.add(layer); this.layersByEventPriority.add(layer);
Collections.sort(layersByEventPriority, new Comparator<Overlay>() { Collections.sort(layersByEventPriority, new Comparator<Overlay>() {
@Override @Override
public int compare(Overlay o1, Overlay o2) public int compare(Overlay o1, Overlay o2)
{ {
return o2.getEventPriority() - o1.getEventPriority(); return o2.getEventPriority() - o1.getEventPriority();
} }
}); });
Collections.sort(layersByZIndex, new Comparator<Overlay>() { Collections.sort(layersByZIndex, new Comparator<Overlay>() {
@Override @Override
public int compare(Overlay o1, Overlay o2) public int compare(Overlay o1, Overlay o2)
{ {
return o1.getZIndex() - o2.getZIndex(); return o1.getZIndex() - o2.getZIndex();
} }
}); });
} }
@Override @Override
protected void onScreenEnter() protected void onScreenEnter()
{ {
@ -100,8 +104,8 @@ public abstract class LayeredScreen extends Screen {
layer.onScreenEnter(); layer.onScreenEnter();
} }
} }
@Override @Override
protected void onScreenLeave() protected void onScreenLeave()
{ {
@ -109,5 +113,5 @@ public abstract class LayeredScreen extends Screen {
layer.onScreenLeave(); layer.onScreenLeave();
} }
} }
} }

@ -25,64 +25,66 @@ import mightypork.utils.math.constraints.vect.Vect;
/** /**
* Abstract overlay.<br> * Abstract overlay.<br>
* Overlay is connected to event bus and is renderable. * Overlay is connected to event bus and is renderable.
* *
* @author Ondřej Hruška (MightyPork) * @author Ondřej Hruška (MightyPork)
*/ */
public abstract class Overlay extends BusNode implements Comparable<Overlay>, Updateable, Renderable, KeyBinder, Hideable, Enableable, LayoutChangeListener { public abstract class Overlay extends BusNode implements Comparable<Overlay>, Updateable, Renderable, KeyBinder, Hideable, Enableable, LayoutChangeListener {
private boolean visible = true; private boolean visible = true;
private boolean enabled = true; private boolean enabled = true;
private final KeyBindingPool keybindings = new KeyBindingPool(); private final KeyBindingPool keybindings = new KeyBindingPool();
/** Root layout, rendered and attached to the event bus. */ /** Root layout, rendered and attached to the event bus. */
protected final ConstraintLayout root; protected final ConstraintLayout root;
/** Constraint: Mouse position. */ /** Constraint: Mouse position. */
protected final Vect mouse; protected final Vect mouse;
/** Extra rendered items (outside root) */ /** Extra rendered items (outside root) */
protected final Collection<Renderable> rendered = new ArrayList<>(); protected final Collection<Renderable> rendered = new ArrayList<>();
/** Extra updated items (outside root - those can just implement Updateable) */ /** Extra updated items (not members of the component tree) */
protected final Collection<Updateable> updated = new ArrayList<>(); protected final Collection<Updateable> updated = new ArrayList<>();
private Num alphaMul = Num.ONE; private Num alphaMul = Num.ONE;
/**
* Create an overlay over the screen
*/
public Overlay() public Overlay()
{ {
this.mouse = App.input().getMousePos(); this.mouse = App.input().getMousePos();
this.root = new ConstraintLayout(App.gfx().getRect()); this.root = new ConstraintLayout(App.gfx().getRect());
addChildClient(root); addChildClient(root);
addChildClient(keybindings); addChildClient(keybindings);
rendered.add(root); rendered.add(root);
} }
@Override @Override
public final void bindKey(KeyStroke stroke, Trigger edge, Runnable task) public final void bindKey(KeyStroke stroke, Trigger edge, Runnable task)
{ {
keybindings.bindKey(stroke, edge, task); keybindings.bindKey(stroke, edge, task);
} }
@Override @Override
public final void unbindKey(KeyStroke stroke) public final void unbindKey(KeyStroke stroke)
{ {
keybindings.unbindKey(stroke); keybindings.unbindKey(stroke);
} }
@Override @Override
public final boolean isVisible() public final boolean isVisible()
{ {
return visible; return visible;
} }
@Override @Override
public void setVisible(boolean visible) public void setVisible(boolean visible)
{ {
@ -91,8 +93,8 @@ public abstract class Overlay extends BusNode implements Comparable<Overlay>, Up
root.setVisible(visible); root.setVisible(visible);
} }
} }
@Override @Override
public void setEnabled(boolean yes) public void setEnabled(boolean yes)
{ {
@ -101,35 +103,35 @@ public abstract class Overlay extends BusNode implements Comparable<Overlay>, Up
root.setEnabled(yes); root.setEnabled(yes);
} }
} }
@Override @Override
public boolean isEnabled() public boolean isEnabled()
{ {
return enabled; return enabled;
} }
/** /**
* Get rendering layer * Get rendering layer
* *
* @return higher = on top. * @return higher = on top.
*/ */
@Stub @Stub
public abstract int getZIndex(); public abstract int getZIndex();
/** /**
* Get event bus listening priority - useful to block incoming events. * Get event bus listening priority - useful to block incoming events.
* *
* @return higher = first. * @return higher = first.
*/ */
public int getEventPriority() public int getEventPriority()
{ {
return getZIndex(); return getZIndex();
} }
/** /**
* Render the overlay. The caller MUST check for visibility himself. * Render the overlay. The caller MUST check for visibility himself.
*/ */
@ -137,34 +139,34 @@ public abstract class Overlay extends BusNode implements Comparable<Overlay>, Up
public void render() public void render()
{ {
if (!isVisible()) return; if (!isVisible()) return;
Color.pushAlpha(alphaMul); Color.pushAlpha(alphaMul);
for (final Renderable r : rendered) { for (final Renderable r : rendered) {
r.render(); r.render();
} }
Color.popAlpha(); Color.popAlpha();
} }
@Override @Override
public void update(double delta) public void update(double delta)
{ {
if (!isEnabled()) return; if (!isEnabled()) return;
for (final Updateable u : updated) { for (final Updateable u : updated) {
u.update(delta); u.update(delta);
} }
} }
@Override @Override
public int compareTo(Overlay o) public int compareTo(Overlay o)
{ {
return o.getEventPriority() - getEventPriority(); return o.getEventPriority() - getEventPriority();
} }
/** /**
* <p> * <p>
* Screen size changed. * Screen size changed.
@ -180,41 +182,57 @@ public abstract class Overlay extends BusNode implements Comparable<Overlay>, Up
public void onLayoutChanged() public void onLayoutChanged()
{ {
} }
/**
* Set overlay's alpha multiplier
*
* @param alpha alpha multiplier
*/
public void setAlpha(Num alpha) public void setAlpha(Num alpha)
{ {
this.alphaMul = alpha; this.alphaMul = alpha;
} }
/**
* Set overlay's alpha multiplier
*
* @param alpha alpha multiplier
*/
public void setAlpha(double alpha) public void setAlpha(double alpha)
{ {
this.alphaMul = Num.make(alpha); this.alphaMul = Num.make(alpha);
} }
/**
* Show and set enabled
*/
public void show() public void show()
{ {
setVisible(true); setVisible(true);
setEnabled(true); setEnabled(true);
} }
/**
* Hide and set disabled
*/
public void hide() public void hide()
{ {
setVisible(false); setVisible(false);
setEnabled(false); setEnabled(false);
} }
@Override @Override
public boolean isListening() public boolean isListening()
{ {
return (isVisible() || isEnabled()); return (isVisible() || isEnabled());
} }
@Override @Override
public boolean doesDelegate() public boolean doesDelegate()
{ {

@ -17,7 +17,7 @@ import mightypork.utils.math.constraints.rect.RectBound;
/** /**
* Screen class. * Screen class.
* *
* @author Ondřej Hruška (MightyPork) * @author Ondřej Hruška (MightyPork)
*/ */
public abstract class Screen extends BusNode implements Renderable, RectBound, KeyBinder, LayoutChangeListener { public abstract class Screen extends BusNode implements Renderable, RectBound, KeyBinder, LayoutChangeListener {
@ -28,9 +28,12 @@ public abstract class Screen extends BusNode implements Renderable, RectBound, K
private volatile boolean needSetupViewport = false; private volatile boolean needSetupViewport = false;
/**
* Make a screen. The screen will initially not listen to the bus, which is
* changed once the setActive method is set to true.
*/
public Screen() public Screen()
{ {
// disable events initially // disable events initially
setListening(false); setListening(false);
@ -60,7 +63,7 @@ public abstract class Screen extends BusNode implements Renderable, RectBound, K
/** /**
* Prepare for being shown * Prepare for being shown
* *
* @param shown true to show, false to hide * @param shown true to show, false to hide
*/ */
public final void setActive(boolean shown) public final void setActive(boolean shown)
@ -134,6 +137,7 @@ public abstract class Screen extends BusNode implements Renderable, RectBound, K
@Stub @Stub
protected void onScreenEnter() protected void onScreenEnter()
{ {
//
} }
@ -143,6 +147,7 @@ public abstract class Screen extends BusNode implements Renderable, RectBound, K
@Stub @Stub
protected void onScreenLeave() protected void onScreenLeave()
{ {
//
} }

@ -6,14 +6,14 @@ import mightypork.utils.annotations.Stub;
/** /**
* Screen display layer * Screen display layer
* *
* @author Ondřej Hruška (MightyPork) * @author Ondřej Hruška (MightyPork)
*/ */
public abstract class ScreenLayer extends Overlay { public abstract class ScreenLayer extends Overlay {
private final Screen screen; private final Screen screen;
/** /**
* @param screen parent screen * @param screen parent screen
*/ */
@ -21,8 +21,8 @@ public abstract class ScreenLayer extends Overlay {
{ {
this.screen = screen; this.screen = screen;
} }
/** /**
* @return parent screen instance * @return parent screen instance
*/ */
@ -30,8 +30,8 @@ public abstract class ScreenLayer extends Overlay {
{ {
return screen; return screen;
} }
/** /**
* Called when the screen becomes active * Called when the screen becomes active
*/ */
@ -39,8 +39,8 @@ public abstract class ScreenLayer extends Overlay {
protected void onScreenEnter() protected void onScreenEnter()
{ {
} }
/** /**
* Called when the screen is no longer active * Called when the screen is no longer active
*/ */

@ -18,19 +18,19 @@ import mightypork.utils.logging.Log;
/** /**
* Game screens holder; Takes care of rendering and screen requests. * Game screens holder; Takes care of rendering and screen requests.
* *
* @author Ondřej Hruška (MightyPork) * @author Ondřej Hruška (MightyPork)
*/ */
public class ScreenRegistry extends BusNode implements ScreenRequestListener, ViewportChangeListener, Renderable { public class ScreenRegistry extends BusNode implements ScreenRequestListener, ViewportChangeListener, Renderable {
private final Map<String, Screen> screens = new HashMap<>(); private final Map<String, Screen> screens = new HashMap<>();
private final Collection<Overlay> overlays = new TreeSet<>(); private final Collection<Overlay> overlays = new TreeSet<>();
private volatile Screen active = null; private volatile Screen active = null;
/** /**
* Add a screen * Add a screen
* *
* @param name screen key for calling * @param name screen key for calling
* @param screen added screen * @param screen added screen
*/ */
@ -39,11 +39,11 @@ public class ScreenRegistry extends BusNode implements ScreenRequestListener, Vi
screens.put(name, screen); screens.put(name, screen);
addChildClient(screen); addChildClient(screen);
} }
/** /**
* Add an overlay * Add an overlay
* *
* @param overlay added overlay * @param overlay added overlay
*/ */
public void addOverlay(Overlay overlay) public void addOverlay(Overlay overlay)
@ -51,56 +51,56 @@ public class ScreenRegistry extends BusNode implements ScreenRequestListener, Vi
overlays.add(overlay); overlays.add(overlay);
addChildClient(overlay); addChildClient(overlay);
} }
@Override @Override
public void showScreen(String key) public void showScreen(String key)
{ {
Log.f3("Request to show screen \"" + key + "\""); Log.f3("Request to show screen \"" + key + "\"");
// find screen to show // find screen to show
final Screen toShow = screens.get(key); final Screen toShow = screens.get(key);
if (toShow == null) { if (toShow == null) {
throw new RuntimeException("Screen " + key + " not defined."); throw new RuntimeException("Screen " + key + " not defined.");
} }
// deactivate last screen // deactivate last screen
if (active != null) { if (active != null) {
active.setActive(false); active.setActive(false);
} }
// activate new screen // activate new screen
toShow.setActive(true); toShow.setActive(true);
active = toShow; active = toShow;
fireLayoutUpdateEvent(); fireLayoutUpdateEvent();
} }
@Override @Override
public void render() public void render()
{ {
if (active != null) { if (active != null) {
active.render(); active.render();
for (final Overlay overlay : overlays) { for (final Overlay overlay : overlays) {
if (overlay.isVisible()) overlay.render(); if (overlay.isVisible()) overlay.render();
} }
} }
} }
@Override @Override
public void onViewportChanged(ViewportChangeEvent event) public void onViewportChanged(ViewportChangeEvent event)
{ {
if (active != null) fireLayoutUpdateEvent(); if (active != null) fireLayoutUpdateEvent();
} }
private void fireLayoutUpdateEvent() private void fireLayoutUpdateEvent()
{ {
App.bus().sendDirectToChildren(this, new LayoutChangeEvent()); App.bus().sendDirectToChildren(this, new LayoutChangeEvent());
} }
} }

@ -5,6 +5,7 @@ import mightypork.gamecore.core.App;
import mightypork.gamecore.gui.components.painters.QuadPainter; import mightypork.gamecore.gui.components.painters.QuadPainter;
import mightypork.gamecore.gui.events.ScreenRequest; import mightypork.gamecore.gui.events.ScreenRequest;
import mightypork.gamecore.gui.screens.Overlay; import mightypork.gamecore.gui.screens.Overlay;
import mightypork.gamecore.gui.screens.ScreenRegistry;
import mightypork.utils.math.animation.Easing; import mightypork.utils.math.animation.Easing;
import mightypork.utils.math.animation.NumAnimated; import mightypork.utils.math.animation.NumAnimated;
import mightypork.utils.math.color.pal.RGB; import mightypork.utils.math.color.pal.RGB;
@ -12,20 +13,20 @@ import mightypork.utils.math.timing.TimedTask;
/** /**
* Overlay used for cross-fading between screens * Overlay used for cross-fading between screens in {@link ScreenRegistry}
* *
* @author Ondřej Hruška (MightyPork) * @author Ondřej Hruška (MightyPork)
*/ */
public class CrossfadeOverlay extends Overlay { public class CrossfadeOverlay extends Overlay {
private static final double T_IN = 0.4; private static final double T_IN = 0.4;
private static final double T_OUT = 0.6; private static final double T_OUT = 0.6;
NumAnimated alpha = new NumAnimated(0); NumAnimated alpha = new NumAnimated(0);
String requestedScreenName; String requestedScreenName;
TimedTask revealTask = new TimedTask() { TimedTask revealTask = new TimedTask() {
@Override @Override
public void run() public void run()
{ {
@ -38,47 +39,55 @@ public class CrossfadeOverlay extends Overlay {
alpha.fadeOut(T_OUT); alpha.fadeOut(T_OUT);
} }
}; };
/**
* Create new crossfade overlay
*/
public CrossfadeOverlay() public CrossfadeOverlay()
{ {
final QuadPainter qp = new QuadPainter(RGB.BLACK); // TODO allow custom colors final QuadPainter qp = new QuadPainter(RGB.BLACK); // TODO allow custom colors
qp.setRect(root); qp.setRect(root);
root.add(qp); root.add(qp);
updated.add(alpha); updated.add(alpha);
updated.add(revealTask); updated.add(revealTask);
setAlpha(alpha); setAlpha(alpha);
} }
@Override @Override
public int getZIndex() public int getZIndex()
{ {
return 10000; // not too high, so app can put something on top return 10000; // not too high, so app can put something on top
} }
/**
* Go to specified screen
*
* @param screen screen alias
* @param fromDark true to fade from dark (ie. first screen in application)
*/
public void goToScreen(String screen, boolean fromDark) public void goToScreen(String screen, boolean fromDark)
{ {
requestedScreenName = screen; requestedScreenName = screen;
if (screen == null) { if (screen == null) {
// going for halt // going for halt
App.audio().fadeOutAllLoops(); App.audio().fadeOutAllLoops();
} }
if (fromDark) { if (fromDark) {
alpha.setTo(1); alpha.setTo(1);
revealTask.run(); revealTask.run();
} else { } else {
revealTask.start(T_IN); revealTask.start(T_IN);
alpha.setEasing(Easing.SINE_IN); alpha.setEasing(Easing.SINE_IN);
alpha.fadeIn(T_IN); alpha.fadeIn(T_IN);
} }
} }
} }

@ -10,11 +10,11 @@ import mightypork.utils.eventbus.events.flags.SingleReceiverEvent;
*/ */
@SingleReceiverEvent @SingleReceiverEvent
public class CrossfadeRequest extends BusEvent<CrossfadeOverlay> { public class CrossfadeRequest extends BusEvent<CrossfadeOverlay> {
private final String screen; private final String screen;
private final boolean fromDark; private final boolean fromDark;
/** /**
* @param screen screen key to show. Null = exit the app. * @param screen screen key to show. Null = exit the app.
* @param fromDark true to fade from full black (ie. start of the game) * @param fromDark true to fade from full black (ie. start of the game)
@ -25,8 +25,8 @@ public class CrossfadeRequest extends BusEvent<CrossfadeOverlay> {
this.screen = screen; this.screen = screen;
this.fromDark = fromDark; this.fromDark = fromDark;
} }
/** /**
* @param screen screen key to show. Null = exit the app. * @param screen screen key to show. Null = exit the app.
*/ */
@ -36,12 +36,12 @@ public class CrossfadeRequest extends BusEvent<CrossfadeOverlay> {
this.screen = screen; this.screen = screen;
this.fromDark = false; this.fromDark = false;
} }
@Override @Override
public void handleBy(CrossfadeOverlay handler) public void handleBy(CrossfadeOverlay handler)
{ {
handler.goToScreen(screen, fromDark); handler.goToScreen(screen, fromDark);
} }
} }

@ -11,7 +11,7 @@ import mightypork.utils.math.timing.TimedTask;
/** /**
* Layer that smoothly appears/disappears when shown/hidden * Layer that smoothly appears/disappears when shown/hidden
* *
* @author Ondřej Hruška (MightyPork) * @author Ondřej Hruška (MightyPork)
*/ */
public abstract class FadingLayer extends ScreenLayer { public abstract class FadingLayer extends ScreenLayer {
@ -44,8 +44,8 @@ public abstract class FadingLayer extends ScreenLayer {
/** /**
* Create with default fading time and effect * Create with default fading time and effect
* *
* @param screen * @param screen the parent screen
*/ */
public FadingLayer(Screen screen) public FadingLayer(Screen screen)
{ {
@ -54,7 +54,9 @@ public abstract class FadingLayer extends ScreenLayer {
/** /**
* @param screen * Create with custom animator
*
* @param screen the parent screen
* @param easingAnim the animation num * @param easingAnim the animation num
*/ */
public FadingLayer(Screen screen, NumAnimated easingAnim) public FadingLayer(Screen screen, NumAnimated easingAnim)

@ -7,11 +7,23 @@ import mightypork.gamecore.gui.screens.ScreenLayer;
import mightypork.utils.math.color.Color; import mightypork.utils.math.color.Color;
/**
* Screen overlay with a given color.
*
* @author Ondřej Hruška (MightyPork)
*/
public class LayerColor extends ScreenLayer { public class LayerColor extends ScreenLayer {
private final int zIndex; private final int zIndex;
/**
* Overlay with color
*
* @param screen the parent screen
* @param color the used color
* @param zIndex z-index in the screen
*/
public LayerColor(Screen screen, Color color, int zIndex) public LayerColor(Screen screen, Color color, int zIndex)
{ {
super(screen); super(screen);

@ -11,89 +11,89 @@ import mightypork.utils.math.constraints.vect.Vect;
* access to mouse position, key states etc.<br> * access to mouse position, key states etc.<br>
* The input module also takes care of calling App.shutdown() when the user * The input module also takes care of calling App.shutdown() when the user
* requests exit (eg. clicks the titlebar close button) * requests exit (eg. clicks the titlebar close button)
* *
* @author Ondřej Hruška (MightyPork) * @author Ondřej Hruška (MightyPork)
*/ */
public abstract class InputModule extends BackendModule implements KeyBinder { public abstract class InputModule extends BackendModule implements KeyBinder {
protected KeyBindingPool keybindings; protected KeyBindingPool keybindings;
@Override @Override
public final void init() public final void init()
{ {
initKeyCodes(); initKeyCodes();
initDevices(); initDevices();
keybindings = new KeyBindingPool(); keybindings = new KeyBindingPool();
addChildClient(keybindings); addChildClient(keybindings);
} }
/** /**
* Initialize key codes for keys in {@link Keys} * Initialize key codes for keys in {@link Keys}
*/ */
protected abstract void initKeyCodes(); protected abstract void initKeyCodes();
/** /**
* Initialize input devices (set up infrastructure for getting the input) * Initialize input devices (set up infrastructure for getting the input)
*/ */
protected abstract void initDevices(); protected abstract void initDevices();
@Override @Override
public void bindKey(KeyStroke stroke, Trigger edge, Runnable task) public void bindKey(KeyStroke stroke, Trigger edge, Runnable task)
{ {
keybindings.bindKey(stroke, edge, task); keybindings.bindKey(stroke, edge, task);
} }
@Override @Override
public void unbindKey(KeyStroke stroke) public void unbindKey(KeyStroke stroke)
{ {
keybindings.unbindKey(stroke); keybindings.unbindKey(stroke);
} }
/** /**
* Get absolute mouse position. Should always return the same Vect instance * Get absolute mouse position. Should always return the same Vect instance
* (use a VectVar or similar). * (use a VectVar or similar).
* *
* @return mouse position * @return mouse position
*/ */
public abstract Vect getMousePos(); public abstract Vect getMousePos();
/** /**
* Check if mouse is inside window * Check if mouse is inside window
* *
* @return true if mouse is inside window. * @return true if mouse is inside window.
*/ */
public abstract boolean isMouseInside(); public abstract boolean isMouseInside();
/** /**
* Trap mouse cursor in the window / release it * Trap mouse cursor in the window / release it
* *
* @param grab true to grab, false to release * @param grab true to grab, false to release
*/ */
public abstract void grabMouse(boolean grab); public abstract void grabMouse(boolean grab);
/** /**
* Check if key is down. The key comes from the Keys class, so the code is * Check if key is down. The key comes from the Keys class, so the code is
* the one assigned in initKeyCodes() * the one assigned in initKeyCodes()
* *
* @param key key to check * @param key key to check
* @return is down * @return is down
*/ */
public abstract boolean isKeyDown(Key key); public abstract boolean isKeyDown(Key key);
/** /**
* Check mouse button state * Check mouse button state
* *
* @param button button to test (0 left, 1 right, 2 middle, 3,4,5... extra) * @param button button to test (0 left, 1 right, 2 middle, 3,4,5... extra)
* @return true if the button exists and is down * @return true if the button exists and is down
*/ */

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save