Compare commits
25
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4faabc203d | ||
|
|
cf096bcce5 | ||
|
|
e368877b6e | ||
|
|
60e76ecfcc | ||
|
|
f0401d0184 | ||
|
|
137dbc21da | ||
|
|
84789ccf47 | ||
|
|
23fe35db4a | ||
|
|
da0737a4c6 | ||
|
|
dda4aa171e | ||
|
|
ae57315df9 | ||
|
|
3987b234bb | ||
|
|
a9b38b9417 | ||
|
|
a4108f2caf | ||
|
|
50cbc9479b | ||
|
|
cafcf78cd2 | ||
|
|
87d0c9d500 | ||
|
|
c5fa77d395 | ||
|
|
d3f392d689 | ||
|
|
3c0763a4c8 | ||
|
|
eee9ed14dc | ||
|
|
ec64ad21fc | ||
|
|
7024fb4402 | ||
|
|
4bc4af553e | ||
|
|
f48797feb5 |
+2
-30
@@ -2,36 +2,8 @@
|
|||||||
<classpath>
|
<classpath>
|
||||||
<classpathentry kind="src" path="src"/>
|
<classpathentry kind="src" path="src"/>
|
||||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.7"/>
|
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.7"/>
|
||||||
<classpathentry kind="lib" path="lib/jinput.jar" sourcepath="lib/lwjgl-source-2.8.4.zip">
|
|
||||||
<attributes>
|
|
||||||
<attribute name="org.eclipse.jdt.launching.CLASSPATH_ATTR_LIBRARY_PATH_ENTRY" value="Rogue/lib"/>
|
|
||||||
</attributes>
|
|
||||||
</classpathentry>
|
|
||||||
<classpathentry kind="lib" path="lib/jogg-0.0.7.jar">
|
|
||||||
<attributes>
|
|
||||||
<attribute name="org.eclipse.jdt.launching.CLASSPATH_ATTR_LIBRARY_PATH_ENTRY" value="Rogue/lib"/>
|
|
||||||
</attributes>
|
|
||||||
</classpathentry>
|
|
||||||
<classpathentry kind="lib" path="lib/jorbis-0.0.15.jar">
|
|
||||||
<attributes>
|
|
||||||
<attribute name="org.eclipse.jdt.launching.CLASSPATH_ATTR_LIBRARY_PATH_ENTRY" value="Rogue/lib"/>
|
|
||||||
</attributes>
|
|
||||||
</classpathentry>
|
|
||||||
<classpathentry kind="lib" path="lib/lwjgl_util.jar" sourcepath="lib/lwjgl-source-2.8.4.zip">
|
|
||||||
<attributes>
|
|
||||||
<attribute name="org.eclipse.jdt.launching.CLASSPATH_ATTR_LIBRARY_PATH_ENTRY" value="Rogue/lib"/>
|
|
||||||
</attributes>
|
|
||||||
</classpathentry>
|
|
||||||
<classpathentry kind="lib" path="lib/lwjgl.jar" sourcepath="lib/lwjgl-source-2.8.4.zip">
|
|
||||||
<attributes>
|
|
||||||
<attribute name="org.eclipse.jdt.launching.CLASSPATH_ATTR_LIBRARY_PATH_ENTRY" value="Rogue/lib"/>
|
|
||||||
</attributes>
|
|
||||||
</classpathentry>
|
|
||||||
<classpathentry kind="lib" path="lib/slick-util.jar" sourcepath="lib/slick-util-src.zip">
|
|
||||||
<attributes>
|
|
||||||
<attribute name="org.eclipse.jdt.launching.CLASSPATH_ATTR_LIBRARY_PATH_ENTRY" value="Rogue/lib"/>
|
|
||||||
</attributes>
|
|
||||||
</classpathentry>
|
|
||||||
<classpathentry combineaccessrules="false" kind="src" path="/MightyUtils"/>
|
<classpathentry combineaccessrules="false" kind="src" path="/MightyUtils"/>
|
||||||
|
<classpathentry combineaccessrules="false" kind="src" path="/GameCore"/>
|
||||||
|
<classpathentry combineaccessrules="false" kind="src" path="/GameCore-LWJGL"/>
|
||||||
<classpathentry kind="output" path="bin"/>
|
<classpathentry kind="output" path="bin"/>
|
||||||
</classpath>
|
</classpath>
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
/target/
|
/target/
|
||||||
/~local/
|
/~local/
|
||||||
/.rogue-save/
|
/.rogue-save/
|
||||||
|
/rogue-workdir/
|
||||||
/build/out/*.jar
|
/build/out/*.jar
|
||||||
/build/in/*.jar
|
/build/in/*.jar
|
||||||
*.log
|
*.log
|
||||||
|
|||||||
@@ -2,24 +2,30 @@
|
|||||||
|
|
||||||
**Read the [MANUAL](http://goo.gl/AU0IdI) if you want to play the game.**
|
**Read the [MANUAL](http://goo.gl/AU0IdI) if you want to play the game.**
|
||||||
|
|
||||||
It explains it way better than this text file.
|
|
||||||
|
NOTE: Master has experimental code
|
||||||
|
----------------------------------
|
||||||
|
|
||||||
|
The Master branch holds Rogue based on the new GameCore implementation (see "dependencies" below for link).
|
||||||
|
|
||||||
|
The latest **stable** version is in the branch `v5stable`. That branch is stable, debugged and has no dependencies. It's a standalone Eclipse project.
|
||||||
|
|
||||||
|
You can use `v5stable` to see the original source and try to build it, but further development of that branch is stopped. The master means the future.
|
||||||
|
|
||||||
|
|
||||||
DEPENDENCIES:
|
DEPENDENCIES
|
||||||
-------------
|
------------
|
||||||
|
|
||||||
- [MightyPork/ion](https://github.com/MightyPork/ion)
|
If you intend to **build it from source**, you will need those Eclipse projects in your workspace:
|
||||||
- [MightyPork/dynmath](https://github.com/MightyPork/dynmath)
|
|
||||||
|
- [MightyPork/gamecore](https://github.com/MightyPork/gamecore) - The "GameCore" game engine
|
||||||
|
- [MightyPork/gamecore-lwjgl](https://github.com/MightyPork/gamecore-lwjgl) - LWJGL backend for GameCore
|
||||||
|
- [MightyPork/mightyutils](https://github.com/MightyPork/mightyutils) - Game utils
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
The package `mightypork.gamecore` contains the framework part of the project.
|
The following is the original readme, applicable to `v5stable` version.
|
||||||
|
|
||||||
It is not yet ready to be published on it's own, but you can have a look at the
|
|
||||||
source if you're interested. The actual library repo will be set up later, with
|
|
||||||
more polished code, better docs, and cleaner hierarchy.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Description
|
## Description
|
||||||
|
|
||||||
@@ -55,13 +61,7 @@ more polished code, better docs, and cleaner hierarchy.
|
|||||||
|
|
||||||
## BUILDING FROM SOURCE
|
## BUILDING FROM SOURCE
|
||||||
|
|
||||||
1. Export a jar with the following (all compiled sources and res) into `build/in/build.jar`:
|
1. Export a jar with the compiled sources and /res into `build/in/build.jar`
|
||||||
- `mightypork.gamecore.*`
|
|
||||||
- `mightypork.rogue.*`
|
|
||||||
- `mightypork.ion.*`
|
|
||||||
- `mightypork.dynmath.*`
|
|
||||||
- `res` folder with Rogue resources
|
|
||||||
|
|
||||||
2. Run `make` to create a stand-alone executable jar in `build/out/release.jar`
|
2. Run `make` to create a stand-alone executable jar in `build/out/release.jar`
|
||||||
3. Use `make run` to execute it
|
3. Use `make run` to execute it
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,246 +0,0 @@
|
|||||||
package mightypork.gamecore.core;
|
|
||||||
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import mightypork.gamecore.input.KeyStroke;
|
|
||||||
import mightypork.gamecore.input.Keys;
|
|
||||||
import mightypork.utils.files.config.Property;
|
|
||||||
import mightypork.utils.files.config.PropertyManager;
|
|
||||||
import mightypork.utils.logging.Log;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Static application configuration
|
|
||||||
*
|
|
||||||
* @author Ondřej Hruška (MightyPork)
|
|
||||||
*/
|
|
||||||
public class Config {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Config setup. Used to populate the config file.
|
|
||||||
*/
|
|
||||||
public static interface ConfigSetup {
|
|
||||||
|
|
||||||
void addOptions(PropertyManager prop);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Key configurator access
|
|
||||||
*/
|
|
||||||
public static class KeyOpts {
|
|
||||||
|
|
||||||
private KeyOpts()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void add(String cfgKey, String dataString)
|
|
||||||
{
|
|
||||||
add(cfgKey, dataString, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void add(String cfgKey, String dataString, String comment)
|
|
||||||
{
|
|
||||||
final KeyProperty kprop = new KeyProperty(prefixKey(cfgKey), KeyStroke.createFromDataString(dataString), comment);
|
|
||||||
strokes.put(prefixKey(cfgKey), kprop);
|
|
||||||
cfg.putProperty(kprop);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Key configurator
|
|
||||||
*/
|
|
||||||
public static interface KeySetup {
|
|
||||||
|
|
||||||
public void addKeys(KeyOpts keys);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Key property.<br>
|
|
||||||
* The stored value must be invariant ({@link KeyStroke} is mutable).
|
|
||||||
*
|
|
||||||
* @author Ondřej Hruška (MightyPork)
|
|
||||||
*/
|
|
||||||
public static class KeyProperty extends Property<KeyStroke> {
|
|
||||||
|
|
||||||
public KeyProperty(String key, KeyStroke defaultValue, String comment)
|
|
||||||
{
|
|
||||||
super(key, defaultValue, comment);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public KeyStroke decode(String string, KeyStroke defval)
|
|
||||||
{
|
|
||||||
if (string != null) {
|
|
||||||
// keep it invariant
|
|
||||||
|
|
||||||
final int backup_key = getValue().getKey();
|
|
||||||
final int backup_mod = getValue().getMod();
|
|
||||||
|
|
||||||
getValue().fromDataString(string);
|
|
||||||
if (getValue().getKey() == Keys.NONE) {
|
|
||||||
getValue().setTo(backup_key, backup_mod);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return getValue();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String encode(KeyStroke value)
|
|
||||||
{
|
|
||||||
return value.toDataString();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setValue(Object value)
|
|
||||||
{
|
|
||||||
// keep it invariant
|
|
||||||
getValue().setTo(((KeyStroke) value).getKey(), ((KeyStroke) value).getMod());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Config.KeyOpts keyOpts = new Config.KeyOpts();
|
|
||||||
public static Map<String, KeyProperty> strokes = new HashMap<>();
|
|
||||||
|
|
||||||
private static PropertyManager cfg;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize property manger for a file
|
|
||||||
*
|
|
||||||
* @param file config file
|
|
||||||
* @param comment file comment
|
|
||||||
*/
|
|
||||||
public static void init(File file, String comment)
|
|
||||||
{
|
|
||||||
cfg = new PropertyManager(file, comment);
|
|
||||||
cfg.cfgNewlineBeforeComments(true);
|
|
||||||
cfg.cfgSeparateSections(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* populate config with keys from a key setup
|
|
||||||
*
|
|
||||||
* @param keys key setup to add
|
|
||||||
*/
|
|
||||||
public static void registerKeys(KeySetup keys)
|
|
||||||
{
|
|
||||||
keys.addKeys(Config.keyOpts);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Populate config with options from a config setup
|
|
||||||
*
|
|
||||||
* @param conf config setup to add
|
|
||||||
*/
|
|
||||||
public static void registerOptions(ConfigSetup conf)
|
|
||||||
{
|
|
||||||
conf.addOptions(Config.cfg);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Load config from file
|
|
||||||
*/
|
|
||||||
public static void load()
|
|
||||||
{
|
|
||||||
cfg.load();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Save config to file
|
|
||||||
*/
|
|
||||||
public static void save()
|
|
||||||
{
|
|
||||||
Log.f3("Saving config.");
|
|
||||||
cfg.save();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get an option for key
|
|
||||||
*
|
|
||||||
* @param key
|
|
||||||
* @return option value
|
|
||||||
*/
|
|
||||||
public static <T> T getValue(String key)
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
if (cfg.getProperty(key) == null) {
|
|
||||||
throw new IllegalArgumentException("No such property: " + key);
|
|
||||||
}
|
|
||||||
|
|
||||||
return cfg.getValue(key);
|
|
||||||
} catch (final ClassCastException cce) {
|
|
||||||
throw new RuntimeException("Property of incompatible type: " + key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set option to a value
|
|
||||||
*
|
|
||||||
* @param key option key
|
|
||||||
* @param value value to set
|
|
||||||
*/
|
|
||||||
public static <T> void setValue(String key, T value)
|
|
||||||
{
|
|
||||||
if (cfg.getProperty(key) == null) {
|
|
||||||
throw new IllegalArgumentException("No such property: " + key);
|
|
||||||
}
|
|
||||||
|
|
||||||
cfg.setValue(key, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private static String prefixKey(String cfgKey)
|
|
||||||
{
|
|
||||||
return "key." + cfgKey;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get keystroke for name
|
|
||||||
*
|
|
||||||
* @param cfgKey stroke identifier in config file
|
|
||||||
* @return the stroke
|
|
||||||
*/
|
|
||||||
public static KeyStroke getKey(String cfgKey)
|
|
||||||
{
|
|
||||||
final KeyProperty kp = strokes.get(prefixKey(cfgKey));
|
|
||||||
if (kp == null) {
|
|
||||||
throw new IllegalArgumentException("No such stroke: " + cfgKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
return kp.getValue();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set a keystroke for name
|
|
||||||
*
|
|
||||||
* @param cfgKey stroke identifier in config file
|
|
||||||
* @param key stroke key
|
|
||||||
* @param mod stroke modifiers
|
|
||||||
*/
|
|
||||||
public static void setKey(String cfgKey, int key, int mod)
|
|
||||||
{
|
|
||||||
final Config.KeyProperty kp = strokes.get(prefixKey(cfgKey));
|
|
||||||
if (kp == null) {
|
|
||||||
throw new IllegalArgumentException("No such stroke: " + cfgKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
kp.getValue().setTo(key, mod);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,117 +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 {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Route configurator.
|
|
||||||
*/
|
|
||||||
public static interface RouteSetup {
|
|
||||||
|
|
||||||
public void addRoutes(RouteOpts routeOpts);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Route configurator access
|
|
||||||
*/
|
|
||||||
public static class RouteOpts {
|
|
||||||
|
|
||||||
public void addPath(String alias, String path)
|
|
||||||
{
|
|
||||||
WorkDir.addPath(alias, path);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static RouteOpts routeOpts = new RouteOpts();
|
|
||||||
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)
|
|
||||||
*
|
|
||||||
* @param alias path alias
|
|
||||||
* @param path path relative to workdir
|
|
||||||
*/
|
|
||||||
public static void addPath(String alias, String path)
|
|
||||||
{
|
|
||||||
namedPaths.put(alias, path);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static void registerRoutes(RouteSetup rs)
|
|
||||||
{
|
|
||||||
rs.addRoutes(routeOpts);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
package mightypork.gamecore.core.events;
|
|
||||||
|
|
||||||
|
|
||||||
import mightypork.gamecore.core.modules.MainLoop;
|
|
||||||
import mightypork.utils.eventbus.BusEvent;
|
|
||||||
import mightypork.utils.eventbus.events.flags.SingleReceiverEvent;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Request to execute given {@link Runnable} in main loop.
|
|
||||||
*
|
|
||||||
* @author Ondřej Hruška (MightyPork)
|
|
||||||
*/
|
|
||||||
@SingleReceiverEvent
|
|
||||||
public class MainLoopRequest extends BusEvent<MainLoop> {
|
|
||||||
|
|
||||||
private final Runnable task;
|
|
||||||
private final boolean priority;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param task task to run on main thread in rendering context
|
|
||||||
* @param priority if true, skip other tasks in queue
|
|
||||||
*/
|
|
||||||
public MainLoopRequest(Runnable task, boolean priority)
|
|
||||||
{
|
|
||||||
this.task = task;
|
|
||||||
this.priority = priority;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void handleBy(MainLoop handler)
|
|
||||||
{
|
|
||||||
handler.queueTask(task, priority);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
package mightypork.gamecore.core.events;
|
|
||||||
|
|
||||||
|
|
||||||
import mightypork.gamecore.core.modules.MainLoop;
|
|
||||||
import mightypork.utils.eventbus.BusEvent;
|
|
||||||
import mightypork.utils.eventbus.events.flags.NonConsumableEvent;
|
|
||||||
import mightypork.utils.eventbus.events.flags.SingleReceiverEvent;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Shutdown request, non-interactive. Shutdown needs to execute on GL thread for
|
|
||||||
* display to deinit properly.
|
|
||||||
*
|
|
||||||
* @author Ondřej Hruška (MightyPork)
|
|
||||||
*/
|
|
||||||
@SingleReceiverEvent
|
|
||||||
@NonConsumableEvent
|
|
||||||
public class ShudownRequest extends BusEvent<MainLoop> {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void handleBy(final MainLoop handler)
|
|
||||||
{
|
|
||||||
handler.queueTask(new Runnable() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void run()
|
|
||||||
{
|
|
||||||
handler.shutdown();
|
|
||||||
}
|
|
||||||
}, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
package mightypork.gamecore.core.events;
|
|
||||||
|
|
||||||
|
|
||||||
import mightypork.utils.eventbus.BusEvent;
|
|
||||||
import mightypork.utils.eventbus.EventBus;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* User quit request. This event is triggered when user clicks the "close"
|
|
||||||
* titlebar button, and if no client consumes it, the application will be shut
|
|
||||||
* down.
|
|
||||||
*
|
|
||||||
* @author Ondřej Hruška (MightyPork)
|
|
||||||
*/
|
|
||||||
public class UserQuitRequest extends BusEvent<UserQuitRequestListener> {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void handleBy(UserQuitRequestListener handler)
|
|
||||||
{
|
|
||||||
handler.onQuitRequest(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onDispatchComplete(EventBus bus)
|
|
||||||
{
|
|
||||||
if (!isConsumed()) {
|
|
||||||
bus.send(new ShudownRequest());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
package mightypork.gamecore.core.events;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Quit request listener; implementing client can abort shutdown.
|
|
||||||
*
|
|
||||||
* @author Ondřej Hruška (MightyPork)
|
|
||||||
*/
|
|
||||||
public interface UserQuitRequestListener {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Intercept quit request.<br>
|
|
||||||
* Consume the event to abort shutdown (ie. ask user to save)
|
|
||||||
*
|
|
||||||
* @param event quit request event.
|
|
||||||
*/
|
|
||||||
void onQuitRequest(UserQuitRequest event);
|
|
||||||
}
|
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
package mightypork.gamecore.core.modules;
|
|
||||||
|
|
||||||
|
|
||||||
import mightypork.gamecore.input.InputSystem;
|
|
||||||
import mightypork.gamecore.render.DisplaySystem;
|
|
||||||
import mightypork.gamecore.resources.audio.SoundSystem;
|
|
||||||
import mightypork.utils.eventbus.BusAccess;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* App interface visible to subsystems
|
|
||||||
*
|
|
||||||
* @author Ondřej Hruška (MightyPork)
|
|
||||||
*/
|
|
||||||
public interface AppAccess extends BusAccess {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return sound system
|
|
||||||
*/
|
|
||||||
abstract SoundSystem getSoundSystem();
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return input system
|
|
||||||
*/
|
|
||||||
abstract InputSystem getInput();
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return display system
|
|
||||||
*/
|
|
||||||
abstract DisplaySystem getDisplay();
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Quit to OS<br>
|
|
||||||
* Destroy app & exit VM
|
|
||||||
*/
|
|
||||||
abstract void shutdown();
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,65 +0,0 @@
|
|||||||
package mightypork.gamecore.core.modules;
|
|
||||||
|
|
||||||
|
|
||||||
import mightypork.gamecore.input.InputSystem;
|
|
||||||
import mightypork.gamecore.render.DisplaySystem;
|
|
||||||
import mightypork.gamecore.resources.audio.SoundSystem;
|
|
||||||
import mightypork.utils.eventbus.EventBus;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* App access adapter (defualt {@link AppAccess} implementation)
|
|
||||||
*
|
|
||||||
* @author Ondřej Hruška (MightyPork)
|
|
||||||
*/
|
|
||||||
public class AppAccessAdapter implements AppAccess {
|
|
||||||
|
|
||||||
private final AppAccess app;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param app app access
|
|
||||||
*/
|
|
||||||
public AppAccessAdapter(AppAccess app)
|
|
||||||
{
|
|
||||||
if (app == null) throw new NullPointerException("AppAccess instance cannot be null.");
|
|
||||||
|
|
||||||
this.app = app;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public final SoundSystem getSoundSystem()
|
|
||||||
{
|
|
||||||
return app.getSoundSystem();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public final InputSystem getInput()
|
|
||||||
{
|
|
||||||
return app.getInput();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public final DisplaySystem getDisplay()
|
|
||||||
{
|
|
||||||
return app.getDisplay();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public final EventBus getEventBus()
|
|
||||||
{
|
|
||||||
return app.getEventBus();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public final void shutdown()
|
|
||||||
{
|
|
||||||
app.shutdown();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,61 +0,0 @@
|
|||||||
package mightypork.gamecore.core.modules;
|
|
||||||
|
|
||||||
|
|
||||||
import mightypork.gamecore.input.InputSystem;
|
|
||||||
import mightypork.gamecore.render.DisplaySystem;
|
|
||||||
import mightypork.gamecore.resources.audio.SoundSystem;
|
|
||||||
import mightypork.utils.eventbus.clients.RootBusNode;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* App event bus client, to be used for subsystems, screens and anything that
|
|
||||||
* needs access to the eventbus and other systems; Attached directly to bus.
|
|
||||||
*
|
|
||||||
* @author Ondřej Hruška (MightyPork)
|
|
||||||
*/
|
|
||||||
public abstract class AppModule extends RootBusNode implements AppAccess {
|
|
||||||
|
|
||||||
private final AppAccess app;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a module
|
|
||||||
*
|
|
||||||
* @param app access to app systems
|
|
||||||
*/
|
|
||||||
public AppModule(AppAccess app)
|
|
||||||
{
|
|
||||||
super(app);
|
|
||||||
|
|
||||||
this.app = app;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public final SoundSystem getSoundSystem()
|
|
||||||
{
|
|
||||||
return app.getSoundSystem();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public final InputSystem getInput()
|
|
||||||
{
|
|
||||||
return app.getInput();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public final DisplaySystem getDisplay()
|
|
||||||
{
|
|
||||||
return app.getDisplay();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public final void shutdown()
|
|
||||||
{
|
|
||||||
app.shutdown();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,63 +0,0 @@
|
|||||||
package mightypork.gamecore.core.modules;
|
|
||||||
|
|
||||||
|
|
||||||
import mightypork.gamecore.input.InputSystem;
|
|
||||||
import mightypork.gamecore.render.DisplaySystem;
|
|
||||||
import mightypork.gamecore.resources.audio.SoundSystem;
|
|
||||||
import mightypork.utils.eventbus.clients.BusNode;
|
|
||||||
import mightypork.utils.eventbus.clients.DelegatingClient;
|
|
||||||
import mightypork.utils.eventbus.clients.RootBusNode;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Delegating bus client, to be attached to any {@link DelegatingClient}, such
|
|
||||||
* as a {@link RootBusNode}.
|
|
||||||
*
|
|
||||||
* @author Ondřej Hruška (MightyPork)
|
|
||||||
*/
|
|
||||||
public class AppSubModule extends BusNode implements AppAccess {
|
|
||||||
|
|
||||||
private final AppAccess app;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create submodule
|
|
||||||
*
|
|
||||||
* @param app access to app systems
|
|
||||||
*/
|
|
||||||
public AppSubModule(AppAccess app)
|
|
||||||
{
|
|
||||||
super(app);
|
|
||||||
|
|
||||||
this.app = app;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public final SoundSystem getSoundSystem()
|
|
||||||
{
|
|
||||||
return app.getSoundSystem();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public final InputSystem getInput()
|
|
||||||
{
|
|
||||||
return app.getInput();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public final DisplaySystem getDisplay()
|
|
||||||
{
|
|
||||||
return app.getDisplay();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public final void shutdown()
|
|
||||||
{
|
|
||||||
app.shutdown();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,566 +0,0 @@
|
|||||||
package mightypork.gamecore.core.modules;
|
|
||||||
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.lang.Thread.UncaughtExceptionHandler;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.logging.Level;
|
|
||||||
|
|
||||||
import javax.swing.JOptionPane;
|
|
||||||
|
|
||||||
import mightypork.gamecore.core.Config;
|
|
||||||
import mightypork.gamecore.core.Config.ConfigSetup;
|
|
||||||
import mightypork.gamecore.core.Config.KeySetup;
|
|
||||||
import mightypork.gamecore.core.WorkDir;
|
|
||||||
import mightypork.gamecore.core.WorkDir.RouteSetup;
|
|
||||||
import mightypork.gamecore.gui.screens.ScreenRegistry;
|
|
||||||
import mightypork.gamecore.gui.screens.impl.CrossfadeOverlay;
|
|
||||||
import mightypork.gamecore.input.InputSystem;
|
|
||||||
import mightypork.gamecore.render.DisplaySystem;
|
|
||||||
import mightypork.gamecore.resources.AsyncResourceLoader;
|
|
||||||
import mightypork.gamecore.resources.Res;
|
|
||||||
import mightypork.gamecore.resources.ResourceLoader;
|
|
||||||
import mightypork.gamecore.resources.ResourceSetup;
|
|
||||||
import mightypork.gamecore.resources.audio.SoundSystem;
|
|
||||||
import mightypork.gamecore.util.SlickLogRedirector;
|
|
||||||
import mightypork.utils.annotations.DefaultImpl;
|
|
||||||
import mightypork.utils.eventbus.EventBus;
|
|
||||||
import mightypork.utils.eventbus.events.DestroyEvent;
|
|
||||||
import mightypork.utils.files.InstanceLock;
|
|
||||||
import mightypork.utils.ion.Ion;
|
|
||||||
import mightypork.utils.ion.IonInput;
|
|
||||||
import mightypork.utils.ion.IonOutput;
|
|
||||||
import mightypork.utils.ion.IonizerBinary;
|
|
||||||
import mightypork.utils.logging.Log;
|
|
||||||
import mightypork.utils.logging.writers.LogWriter;
|
|
||||||
import mightypork.utils.math.algo.Coord;
|
|
||||||
import mightypork.utils.math.algo.Move;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Basic screen-based game with subsystems.<br>
|
|
||||||
* This class takes care of the initialization sequence.
|
|
||||||
*
|
|
||||||
* @author Ondřej Hruška (MightyPork)
|
|
||||||
*/
|
|
||||||
public abstract class BaseApp implements AppAccess, UncaughtExceptionHandler {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Init options holder class
|
|
||||||
*/
|
|
||||||
public class AppInitOptions {
|
|
||||||
|
|
||||||
private String logDir = "log";
|
|
||||||
private String logFilePrefix = "runtime";
|
|
||||||
|
|
||||||
private String screenshotDir = "screenshots";
|
|
||||||
|
|
||||||
private int logArchiveCount = 0;
|
|
||||||
private boolean busLogging = false;
|
|
||||||
|
|
||||||
private String configFile = "settings.cfg";
|
|
||||||
private String configComment = "Main config file";
|
|
||||||
|
|
||||||
public String lockFile = ".lock";
|
|
||||||
|
|
||||||
private final List<ResourceSetup> resourceLists = new ArrayList<>();
|
|
||||||
private final List<Config.KeySetup> keyLists = new ArrayList<>();
|
|
||||||
private final List<ConfigSetup> configLists = new ArrayList<>();
|
|
||||||
private final List<RouteSetup> routeLists = new ArrayList<>();
|
|
||||||
|
|
||||||
private ResourceLoader resourceLoader = new AsyncResourceLoader();
|
|
||||||
private Level logLevel = Level.ALL;
|
|
||||||
public boolean sigleInstance;
|
|
||||||
private Level logSoutLevel;
|
|
||||||
|
|
||||||
|
|
||||||
public void setConfigFile(String filename, String comment)
|
|
||||||
{
|
|
||||||
configFile = filename;
|
|
||||||
configComment = comment;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void addConfig(ConfigSetup cfg)
|
|
||||||
{
|
|
||||||
configLists.add(cfg);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void addKeys(Config.KeySetup keys)
|
|
||||||
{
|
|
||||||
keyLists.add(keys);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void addRoutes(RouteSetup keys)
|
|
||||||
{
|
|
||||||
routeLists.add(keys);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void addResources(ResourceSetup res)
|
|
||||||
{
|
|
||||||
resourceLists.add(res);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void setBusLogging(boolean yes)
|
|
||||||
{
|
|
||||||
busLogging = yes;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void setLogOptions(String logDir, String filePrefix, int archivedCount, Level logLevel)
|
|
||||||
{
|
|
||||||
this.logDir = logDir;
|
|
||||||
this.logFilePrefix = filePrefix;
|
|
||||||
this.logArchiveCount = archivedCount;
|
|
||||||
this.logLevel = logLevel;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void setResourceLoader(ResourceLoader resLoader)
|
|
||||||
{
|
|
||||||
resourceLoader = resLoader;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void setScreenshotDir(String path)
|
|
||||||
{
|
|
||||||
this.screenshotDir = path;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void setLockFile(String lockFile)
|
|
||||||
{
|
|
||||||
this.lockFile = lockFile;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void setLogLevel(Level logLevel, Level soutLevel)
|
|
||||||
{
|
|
||||||
this.logLevel = logLevel;
|
|
||||||
this.logSoutLevel = soutLevel;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// modules
|
|
||||||
private InputSystem inputSystem;
|
|
||||||
private DisplaySystem displaySystem;
|
|
||||||
private SoundSystem soundSystem;
|
|
||||||
private EventBus eventBus;
|
|
||||||
private MainLoop gameLoop;
|
|
||||||
private ScreenRegistry screenRegistry;
|
|
||||||
private boolean started = false;
|
|
||||||
private boolean lockObtained = false;
|
|
||||||
|
|
||||||
// init opt holder
|
|
||||||
private final AppInitOptions opt = new AppInitOptions();
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get init options
|
|
||||||
*
|
|
||||||
* @return opt holder
|
|
||||||
*/
|
|
||||||
public AppInitOptions opt()
|
|
||||||
{
|
|
||||||
if (started) {
|
|
||||||
throw new IllegalStateException("Cannot alter init options after starting the App.");
|
|
||||||
}
|
|
||||||
|
|
||||||
return opt;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public BaseApp(File workdir, boolean singleInstance)
|
|
||||||
{
|
|
||||||
WorkDir.init(workdir);
|
|
||||||
|
|
||||||
opt.sigleInstance = singleInstance;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Start the application
|
|
||||||
*/
|
|
||||||
public final void start()
|
|
||||||
{
|
|
||||||
Thread.setDefaultUncaughtExceptionHandler(this);
|
|
||||||
|
|
||||||
initialize();
|
|
||||||
|
|
||||||
Log.i("Starting main loop...");
|
|
||||||
|
|
||||||
// open first screen
|
|
||||||
started = true;
|
|
||||||
gameLoop.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Init the app
|
|
||||||
*/
|
|
||||||
protected void initialize()
|
|
||||||
{
|
|
||||||
if (opt.sigleInstance) initLock();
|
|
||||||
lockObtained = true;
|
|
||||||
|
|
||||||
for (final RouteSetup rs : opt.routeLists) {
|
|
||||||
WorkDir.registerRoutes(rs);
|
|
||||||
}
|
|
||||||
WorkDir.addPath("_screenshot_dir", opt.screenshotDir);
|
|
||||||
|
|
||||||
// apply configurations
|
|
||||||
Config.init(WorkDir.getFile(opt.configFile), opt.configComment);
|
|
||||||
|
|
||||||
// add keys to config
|
|
||||||
for (final KeySetup l : opt.keyLists) {
|
|
||||||
Config.registerKeys(l);
|
|
||||||
}
|
|
||||||
|
|
||||||
// add options to config
|
|
||||||
for (final ConfigSetup c : opt.configLists) {
|
|
||||||
Config.registerOptions(c);
|
|
||||||
}
|
|
||||||
Config.load();
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Setup logging
|
|
||||||
*/
|
|
||||||
final LogWriter log = Log.create(opt.logFilePrefix, new File(WorkDir.getDir(opt.logDir), opt.logFilePrefix + ".log"), opt.logArchiveCount);
|
|
||||||
Log.setMainLogger(log);
|
|
||||||
Log.setLevel(opt.logLevel);
|
|
||||||
Log.setSysoutLevel(opt.logSoutLevel);
|
|
||||||
|
|
||||||
// connect slickutil to the logger
|
|
||||||
org.newdawn.slick.util.Log.setLogSystem(new SlickLogRedirector(log));
|
|
||||||
writeLogHeader();
|
|
||||||
|
|
||||||
|
|
||||||
Log.i("=== Starting initialization sequence ===");
|
|
||||||
|
|
||||||
// pre-init hook
|
|
||||||
Log.f2("Calling pre-init hook...");
|
|
||||||
preInit();
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Event bus
|
|
||||||
*/
|
|
||||||
Log.f2("Starting Event Bus...");
|
|
||||||
eventBus = new EventBus();
|
|
||||||
eventBus.subscribe(this);
|
|
||||||
eventBus.detailedLogging = opt.busLogging;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Ionizables
|
|
||||||
*/
|
|
||||||
Log.f3("Initializing ION save system...");
|
|
||||||
registerIonizables();
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Display
|
|
||||||
*/
|
|
||||||
Log.f2("Initializing Display System...");
|
|
||||||
displaySystem = new DisplaySystem(this);
|
|
||||||
initDisplay(displaySystem);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Audio
|
|
||||||
*/
|
|
||||||
Log.f2("Initializing Sound System...");
|
|
||||||
soundSystem = new SoundSystem(this);
|
|
||||||
initSoundSystem(soundSystem);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Input
|
|
||||||
*/
|
|
||||||
Log.f2("Initializing Input System...");
|
|
||||||
inputSystem = new InputSystem(this);
|
|
||||||
initInputSystem(inputSystem);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Prepare main loop
|
|
||||||
*/
|
|
||||||
Log.f1("Creating Screen Registry and Game Loop...");
|
|
||||||
screenRegistry = new ScreenRegistry(this);
|
|
||||||
gameLoop = createMainLoop();
|
|
||||||
gameLoop.setRootRenderable(screenRegistry);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Load resources
|
|
||||||
*
|
|
||||||
* Resources should be registered to registries, and AsyncResourceLoader will load them.
|
|
||||||
*/
|
|
||||||
Log.f1("Loading resources...");
|
|
||||||
if (opt.resourceLoader != null) {
|
|
||||||
opt.resourceLoader.init(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
Res.init(this);
|
|
||||||
|
|
||||||
for (final ResourceSetup rl : opt.resourceLists) {
|
|
||||||
Res.load(rl);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Screen registry
|
|
||||||
*
|
|
||||||
* Must be after resources, because screens can request them during instantiation.
|
|
||||||
*/
|
|
||||||
Log.f2("Registering screens...");
|
|
||||||
initScreens(screenRegistry);
|
|
||||||
|
|
||||||
postInit();
|
|
||||||
Log.i("=== Initialization sequence completed ===");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
protected void writeLogHeader()
|
|
||||||
{
|
|
||||||
logSystemInfo();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
protected void logSystemInfo()
|
|
||||||
{
|
|
||||||
String txt = "";
|
|
||||||
|
|
||||||
txt += "\n### SYSTEM INFO ###\n\n";
|
|
||||||
txt += " Platform ...... " + System.getProperty("os.name") + "\n";
|
|
||||||
txt += " Runtime ....... " + System.getProperty("java.runtime.name") + "\n";
|
|
||||||
txt += " Java .......... " + System.getProperty("java.version") + "\n";
|
|
||||||
txt += " Launch path ... " + System.getProperty("user.dir") + "\n";
|
|
||||||
|
|
||||||
try {
|
|
||||||
txt += " Workdir ....... " + WorkDir.getWorkDir().getCanonicalPath() + "\n";
|
|
||||||
} catch (final IOException e) {
|
|
||||||
Log.e(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
Log.i(txt);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
protected void registerIonizables()
|
|
||||||
{
|
|
||||||
Ion.registerIndirect(255, new IonizerBinary<Coord>() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void save(Coord object, IonOutput out) throws IOException
|
|
||||||
{
|
|
||||||
out.writeInt(object.x);
|
|
||||||
out.writeInt(object.y);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Coord load(IonInput in) throws IOException
|
|
||||||
{
|
|
||||||
final int x = in.readInt();
|
|
||||||
final int y = in.readInt();
|
|
||||||
return new Coord(x, y);
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
Ion.registerIndirect(254, new IonizerBinary<Move>() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void save(Move object, IonOutput out) throws IOException
|
|
||||||
{
|
|
||||||
out.writeInt(object.x());
|
|
||||||
out.writeInt(object.y());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Move load(IonInput in) throws IOException
|
|
||||||
{
|
|
||||||
final int x = in.readInt();
|
|
||||||
final int y = in.readInt();
|
|
||||||
return new Move(x, y);
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called at the beginning of the initialization sequence, right after lock
|
|
||||||
* was obtained.
|
|
||||||
*/
|
|
||||||
@DefaultImpl
|
|
||||||
protected void preInit()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called at the end of init sequence, before main loop starts.
|
|
||||||
*/
|
|
||||||
@DefaultImpl
|
|
||||||
protected void postInit()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create window and configure display system
|
|
||||||
*
|
|
||||||
* @param display
|
|
||||||
*/
|
|
||||||
@DefaultImpl
|
|
||||||
protected void initDisplay(DisplaySystem display)
|
|
||||||
{
|
|
||||||
display.createMainWindow(800, 600, true, false, "LWJGL game");
|
|
||||||
display.setTargetFps(60);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Configure sound system (ie. adjust volume)
|
|
||||||
*
|
|
||||||
* @param audio
|
|
||||||
*/
|
|
||||||
@DefaultImpl
|
|
||||||
protected void initSoundSystem(SoundSystem audio)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Register game screens to the registry.
|
|
||||||
*
|
|
||||||
* @param screens
|
|
||||||
*/
|
|
||||||
protected void initScreens(ScreenRegistry screens)
|
|
||||||
{
|
|
||||||
screens.addOverlay(new CrossfadeOverlay(this));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create game loop instance
|
|
||||||
*
|
|
||||||
* @return the game loop.
|
|
||||||
*/
|
|
||||||
protected MainLoop createMainLoop()
|
|
||||||
{
|
|
||||||
return new MainLoop(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Try to obtain lock.
|
|
||||||
*/
|
|
||||||
private void initLock()
|
|
||||||
{
|
|
||||||
final File lock = WorkDir.getFile(opt.lockFile);
|
|
||||||
if (!InstanceLock.onFile(lock)) {
|
|
||||||
onLockError();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@DefaultImpl
|
|
||||||
protected void initInputSystem(InputSystem input)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Triggered when lock cannot be obtained.<br>
|
|
||||||
* App should terminate gracefully.
|
|
||||||
*/
|
|
||||||
|
|
||||||
protected void onLockError()
|
|
||||||
{
|
|
||||||
Log.e("Could not obtain lock file.\nOnly one instance can run at a time.");
|
|
||||||
|
|
||||||
//@formatter:off
|
|
||||||
JOptionPane.showMessageDialog(
|
|
||||||
null,
|
|
||||||
"Another instance is already running.\n(Delete the "+opt.lockFile +" file in the working directory to override)",
|
|
||||||
"Lock Error",
|
|
||||||
JOptionPane.ERROR_MESSAGE
|
|
||||||
);
|
|
||||||
//@formatter:on
|
|
||||||
|
|
||||||
shutdown();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public final SoundSystem getSoundSystem()
|
|
||||||
{
|
|
||||||
return soundSystem;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public final InputSystem getInput()
|
|
||||||
{
|
|
||||||
return inputSystem;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public final DisplaySystem getDisplay()
|
|
||||||
{
|
|
||||||
return displaySystem;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public final EventBus getEventBus()
|
|
||||||
{
|
|
||||||
return eventBus;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
protected void beforeShutdown()
|
|
||||||
{
|
|
||||||
if (lockObtained) Config.save();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public final void uncaughtException(Thread t, Throwable e)
|
|
||||||
{
|
|
||||||
onCrash(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
protected void onCrash(Throwable e)
|
|
||||||
{
|
|
||||||
Log.e("The game has crashed.", e);
|
|
||||||
shutdown();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public final void shutdown()
|
|
||||||
{
|
|
||||||
beforeShutdown();
|
|
||||||
|
|
||||||
Log.i("Shutting down subsystems...");
|
|
||||||
|
|
||||||
try {
|
|
||||||
if (getEventBus() != null) {
|
|
||||||
getEventBus().send(new DestroyEvent());
|
|
||||||
getEventBus().destroy();
|
|
||||||
}
|
|
||||||
} catch (final Throwable e) {
|
|
||||||
Log.e(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
Log.i("Terminating...");
|
|
||||||
System.exit(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,155 +0,0 @@
|
|||||||
package mightypork.gamecore.core.modules;
|
|
||||||
|
|
||||||
|
|
||||||
import java.util.Deque;
|
|
||||||
import java.util.concurrent.ConcurrentLinkedDeque;
|
|
||||||
|
|
||||||
import mightypork.gamecore.gui.screens.ScreenRegistry;
|
|
||||||
import mightypork.gamecore.render.Renderable;
|
|
||||||
import mightypork.gamecore.render.TaskTakeScreenshot;
|
|
||||||
import mightypork.gamecore.render.events.ScreenshotRequestListener;
|
|
||||||
import mightypork.utils.Support;
|
|
||||||
import mightypork.utils.annotations.DefaultImpl;
|
|
||||||
import mightypork.utils.eventbus.events.UpdateEvent;
|
|
||||||
import mightypork.utils.logging.Log;
|
|
||||||
import mightypork.utils.math.timing.Profiler;
|
|
||||||
import mightypork.utils.math.timing.TimerDelta;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Delta-timed game loop with task queue etc.
|
|
||||||
*
|
|
||||||
* @author Ondřej Hruška (MightyPork)
|
|
||||||
*/
|
|
||||||
public class MainLoop extends AppModule implements ScreenshotRequestListener {
|
|
||||||
|
|
||||||
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)
|
|
||||||
|
|
||||||
private final Deque<Runnable> tasks = new ConcurrentLinkedDeque<>();
|
|
||||||
private TimerDelta timer;
|
|
||||||
private Renderable rootRenderable;
|
|
||||||
private volatile boolean running = true;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param app {@link AppAccess} instance
|
|
||||||
*/
|
|
||||||
public MainLoop(AppAccess app)
|
|
||||||
{
|
|
||||||
super(app);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set primary renderable
|
|
||||||
*
|
|
||||||
* @param rootRenderable main {@link Renderable}, typically a
|
|
||||||
* {@link ScreenRegistry}
|
|
||||||
*/
|
|
||||||
public void setRootRenderable(Renderable rootRenderable)
|
|
||||||
{
|
|
||||||
this.rootRenderable = rootRenderable;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Start the loop
|
|
||||||
*/
|
|
||||||
public void start()
|
|
||||||
{
|
|
||||||
timer = new TimerDelta();
|
|
||||||
|
|
||||||
while (running) {
|
|
||||||
getDisplay().beginFrame();
|
|
||||||
|
|
||||||
double delta = timer.getDelta();
|
|
||||||
if (delta > MAX_DELTA) {
|
|
||||||
Log.f3("(timing) Cropping delta: was " + delta + " , limit " + MAX_DELTA);
|
|
||||||
delta = MAX_DELTA;
|
|
||||||
}
|
|
||||||
|
|
||||||
getEventBus().sendDirect(new UpdateEvent(delta));
|
|
||||||
|
|
||||||
Runnable r;
|
|
||||||
final long t = Profiler.begin();
|
|
||||||
while ((r = tasks.poll()) != null) {
|
|
||||||
Log.f3(" * Main loop task.");
|
|
||||||
r.run();
|
|
||||||
if (Profiler.end(t) > MAX_TIME_TASKS) {
|
|
||||||
Log.f3("! Postponing main loop tasks to next cycle.");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
beforeRender();
|
|
||||||
|
|
||||||
if (rootRenderable != null) {
|
|
||||||
rootRenderable.render();
|
|
||||||
}
|
|
||||||
|
|
||||||
afterRender();
|
|
||||||
|
|
||||||
getDisplay().endFrame();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called before render
|
|
||||||
*/
|
|
||||||
@DefaultImpl
|
|
||||||
protected void beforeRender()
|
|
||||||
{
|
|
||||||
//
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called after render
|
|
||||||
*/
|
|
||||||
@DefaultImpl
|
|
||||||
protected void afterRender()
|
|
||||||
{
|
|
||||||
//
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void deinit()
|
|
||||||
{
|
|
||||||
running = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add a task to queue to be executed in the main loop (OpenGL thread)
|
|
||||||
*
|
|
||||||
* @param request task
|
|
||||||
* @param priority if true, skip other tasks
|
|
||||||
*/
|
|
||||||
public synchronized void queueTask(Runnable request, boolean priority)
|
|
||||||
{
|
|
||||||
if (priority) {
|
|
||||||
tasks.addFirst(request);
|
|
||||||
} else {
|
|
||||||
tasks.addLast(request);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onScreenshotRequest()
|
|
||||||
{
|
|
||||||
// ensure it's started in main thread
|
|
||||||
queueTask(new Runnable() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void run()
|
|
||||||
{
|
|
||||||
Support.runAsThread(new TaskTakeScreenshot());
|
|
||||||
}
|
|
||||||
}, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,54 +0,0 @@
|
|||||||
package mightypork.gamecore.gui;
|
|
||||||
|
|
||||||
|
|
||||||
import mightypork.utils.interfaces.Enableable;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Triggered action
|
|
||||||
*
|
|
||||||
* @author Ondřej Hruška (MightyPork)
|
|
||||||
*/
|
|
||||||
public abstract class Action implements Runnable, Enableable {
|
|
||||||
|
|
||||||
private boolean enabled = true;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Enable the action
|
|
||||||
*
|
|
||||||
* @param enable true to enable
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public final void setEnabled(boolean enable)
|
|
||||||
{
|
|
||||||
this.enabled = enable;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return true if this action is enabled.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public final boolean isEnabled()
|
|
||||||
{
|
|
||||||
return enabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Run the action, if it's enabled.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public final void run()
|
|
||||||
{
|
|
||||||
if (enabled) execute();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Do the work.
|
|
||||||
*/
|
|
||||||
protected abstract void execute();
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
package mightypork.gamecore.gui;
|
|
||||||
|
|
||||||
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
import mightypork.utils.interfaces.Enableable;
|
|
||||||
|
|
||||||
|
|
||||||
public class ActionGroup implements Enableable {
|
|
||||||
|
|
||||||
private boolean enabled = true;
|
|
||||||
|
|
||||||
private final Set<Enableable> groupMembers = new HashSet<>();
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setEnabled(boolean yes)
|
|
||||||
{
|
|
||||||
enabled = yes;
|
|
||||||
for (final Enableable e : groupMembers)
|
|
||||||
e.setEnabled(yes);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isEnabled()
|
|
||||||
{
|
|
||||||
return enabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void add(Enableable action)
|
|
||||||
{
|
|
||||||
groupMembers.add(action);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
package mightypork.gamecore.gui;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Element that can be assigned an action (ie. button);
|
|
||||||
*
|
|
||||||
* @author Ondřej Hruška (MightyPork)
|
|
||||||
*/
|
|
||||||
public interface ActionTrigger {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Assign an action
|
|
||||||
*
|
|
||||||
* @param action action
|
|
||||||
*/
|
|
||||||
void setAction(Action action);
|
|
||||||
}
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
package mightypork.gamecore.gui;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Horizontal align sides
|
|
||||||
*
|
|
||||||
* @author Ondřej Hruška (MightyPork)
|
|
||||||
*/
|
|
||||||
public enum AlignX
|
|
||||||
{
|
|
||||||
LEFT, CENTER, RIGHT;
|
|
||||||
}
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
package mightypork.gamecore.gui;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Vertical align sides
|
|
||||||
*
|
|
||||||
* @author Ondřej Hruška (MightyPork)
|
|
||||||
*/
|
|
||||||
public enum AlignY
|
|
||||||
{
|
|
||||||
TOP, CENTER, BOTTOM;
|
|
||||||
}
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
package mightypork.gamecore.gui;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Element that can be hidden or visible
|
|
||||||
*
|
|
||||||
* @author Ondřej Hruška (MightyPork)
|
|
||||||
*/
|
|
||||||
public interface Hideable {
|
|
||||||
|
|
||||||
void setVisible(boolean yes);
|
|
||||||
|
|
||||||
|
|
||||||
boolean isVisible();
|
|
||||||
}
|
|
||||||
@@ -1,170 +0,0 @@
|
|||||||
package mightypork.gamecore.gui.components;
|
|
||||||
|
|
||||||
|
|
||||||
import mightypork.gamecore.gui.events.LayoutChangeEvent;
|
|
||||||
import mightypork.gamecore.gui.events.LayoutChangeListener;
|
|
||||||
import mightypork.gamecore.input.InputSystem;
|
|
||||||
import mightypork.gamecore.render.Renderable;
|
|
||||||
import mightypork.utils.Support;
|
|
||||||
import mightypork.utils.annotations.DefaultImpl;
|
|
||||||
import mightypork.utils.interfaces.Enableable;
|
|
||||||
import mightypork.utils.logging.Log;
|
|
||||||
import mightypork.utils.math.color.Color;
|
|
||||||
import mightypork.utils.math.constraints.num.Num;
|
|
||||||
import mightypork.utils.math.constraints.rect.Rect;
|
|
||||||
import mightypork.utils.math.constraints.rect.RectBound;
|
|
||||||
import mightypork.utils.math.constraints.rect.caching.AbstractRectCache;
|
|
||||||
import mightypork.utils.math.constraints.rect.proxy.RectProxy;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@link Renderable} with pluggable context. When caching is enabled, the
|
|
||||||
* layout update can be triggered by firing the {@link LayoutChangeEvent}.
|
|
||||||
*
|
|
||||||
* @author Ondřej Hruška (MightyPork)
|
|
||||||
*/
|
|
||||||
public abstract class BaseComponent extends AbstractRectCache implements Component, LayoutChangeListener, Enableable {
|
|
||||||
|
|
||||||
private Rect source;
|
|
||||||
private boolean visible = true;
|
|
||||||
private boolean enabled = true;
|
|
||||||
private int indirectDisableLevel = 0;
|
|
||||||
|
|
||||||
private Num alphaMul = Num.ONE;
|
|
||||||
|
|
||||||
|
|
||||||
public BaseComponent()
|
|
||||||
{
|
|
||||||
enableCaching(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setRect(RectBound rect)
|
|
||||||
{
|
|
||||||
this.source = new RectProxy(rect);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public final boolean isVisible()
|
|
||||||
{
|
|
||||||
return visible;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public final void setVisible(boolean visible)
|
|
||||||
{
|
|
||||||
this.visible = visible;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public final Rect getCacheSource()
|
|
||||||
{
|
|
||||||
return source.round(); // round to avoid visual artifacts in fonts and such
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public final void render()
|
|
||||||
{
|
|
||||||
if (!isVisible()) return;
|
|
||||||
|
|
||||||
Color.pushAlpha(alphaMul);
|
|
||||||
renderComponent();
|
|
||||||
Color.popAlpha();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public final void onLayoutChanged()
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
poll();
|
|
||||||
} catch (final NullPointerException e) {
|
|
||||||
Log.e("Component is missing a bounding rect, at: " + Support.str(getClass()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public final void onConstraintChanged()
|
|
||||||
{
|
|
||||||
updateLayout();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public final boolean isMouseOver()
|
|
||||||
{
|
|
||||||
return InputSystem.getMousePos().isInside(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Draw the component (it's visible)
|
|
||||||
*/
|
|
||||||
protected abstract void renderComponent();
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@DefaultImpl
|
|
||||||
public void updateLayout()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setEnabled(boolean yes)
|
|
||||||
{
|
|
||||||
enabled = yes;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isEnabled()
|
|
||||||
{
|
|
||||||
return enabled && isIndirectlyEnabled();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public final void setAlpha(Num alpha)
|
|
||||||
{
|
|
||||||
this.alphaMul = alpha;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public final void setAlpha(double alpha)
|
|
||||||
{
|
|
||||||
this.alphaMul = Num.make(alpha);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setIndirectlyEnabled(boolean yes)
|
|
||||||
{
|
|
||||||
if (!yes) {
|
|
||||||
indirectDisableLevel++;
|
|
||||||
} else {
|
|
||||||
if (indirectDisableLevel > 0) indirectDisableLevel--;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isIndirectlyEnabled()
|
|
||||||
{
|
|
||||||
return indirectDisableLevel == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isDirectlyEnabled()
|
|
||||||
{
|
|
||||||
return enabled;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,95 +0,0 @@
|
|||||||
package mightypork.gamecore.gui.components;
|
|
||||||
|
|
||||||
|
|
||||||
import mightypork.gamecore.gui.Hideable;
|
|
||||||
import mightypork.utils.interfaces.Enableable;
|
|
||||||
import mightypork.utils.math.constraints.num.Num;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Basic UI component interface
|
|
||||||
*
|
|
||||||
* @author Ondřej Hruška (MightyPork)
|
|
||||||
*/
|
|
||||||
public interface Component extends Enableable, Hideable, PluggableRenderable {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Render the component, if it is visible.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
void render();
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The bounding rect was changed. The component should now update any cached
|
|
||||||
* constraints derived from it.
|
|
||||||
*/
|
|
||||||
void updateLayout();
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return true if mouse is currently over the component
|
|
||||||
*/
|
|
||||||
boolean isMouseOver();
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set alpha multiplier for this and nested components
|
|
||||||
*
|
|
||||||
* @param alpha alpha multiplier (dynamic value)
|
|
||||||
*/
|
|
||||||
void setAlpha(Num alpha);
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set alpha multiplier for this and nested components
|
|
||||||
*
|
|
||||||
* @param alpha alpha multiplier (constant value)
|
|
||||||
*/
|
|
||||||
void setAlpha(double alpha);
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Indirectly enable / disable, used for nested hierarchies.<br>
|
|
||||||
* When component is twice indirectly disabled, it needs to be twice
|
|
||||||
* indirectly enabled to be enabled again.
|
|
||||||
*
|
|
||||||
* @param yes
|
|
||||||
*/
|
|
||||||
void setIndirectlyEnabled(boolean yes);
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if the compionent is not indirectly disabled. May still be directly
|
|
||||||
* disabled.
|
|
||||||
*
|
|
||||||
* @return indirectly enabled
|
|
||||||
*/
|
|
||||||
boolean isIndirectlyEnabled();
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if the component is directly enabled (set by setEnabled()). May
|
|
||||||
* still be indirectly disabled.
|
|
||||||
*
|
|
||||||
* @return directly enabled
|
|
||||||
*/
|
|
||||||
boolean isDirectlyEnabled();
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set directly enabled (must be both directly and indirectly enabled to be
|
|
||||||
* enabled completely)
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void setEnabled(boolean yes);
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if the component is both directly and indirectly enabled
|
|
||||||
*
|
|
||||||
* @return enabled
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public boolean isEnabled();
|
|
||||||
}
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
package mightypork.gamecore.gui.components;
|
|
||||||
|
|
||||||
|
|
||||||
public interface DynamicWidthComponent extends Component {
|
|
||||||
|
|
||||||
double computeWidth(double height);
|
|
||||||
}
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
package mightypork.gamecore.gui.components;
|
|
||||||
|
|
||||||
|
|
||||||
import mightypork.utils.eventbus.clients.ToggleableClient;
|
|
||||||
import mightypork.utils.interfaces.Enableable;
|
|
||||||
|
|
||||||
|
|
||||||
public abstract class InputComponent extends BaseComponent implements Enableable, ToggleableClient {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isListening()
|
|
||||||
{
|
|
||||||
return isEnabled();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,162 +0,0 @@
|
|||||||
package mightypork.gamecore.gui.components;
|
|
||||||
|
|
||||||
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.LinkedList;
|
|
||||||
|
|
||||||
import mightypork.gamecore.core.modules.AppAccess;
|
|
||||||
import mightypork.gamecore.core.modules.AppSubModule;
|
|
||||||
import mightypork.gamecore.input.InputSystem;
|
|
||||||
import mightypork.gamecore.render.DisplaySystem;
|
|
||||||
import mightypork.gamecore.resources.audio.SoundSystem;
|
|
||||||
import mightypork.utils.eventbus.EventBus;
|
|
||||||
import mightypork.utils.eventbus.clients.ClientHub;
|
|
||||||
import mightypork.utils.math.constraints.rect.RectBound;
|
|
||||||
|
|
||||||
|
|
||||||
public abstract class LayoutComponent extends BaseComponent implements ClientHub, AppAccess {
|
|
||||||
|
|
||||||
private final AppSubModule subModule;
|
|
||||||
final LinkedList<Component> components = new LinkedList<>();
|
|
||||||
|
|
||||||
|
|
||||||
public LayoutComponent(AppAccess app, RectBound context)
|
|
||||||
{
|
|
||||||
this.subModule = new AppSubModule(app);
|
|
||||||
setRect(context);
|
|
||||||
enableCaching(true); // layout is typically updated only when screen resizes.
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public LayoutComponent(AppAccess app)
|
|
||||||
{
|
|
||||||
this(app, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public EventBus getEventBus()
|
|
||||||
{
|
|
||||||
return subModule.getEventBus();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Collection<Object> getChildClients()
|
|
||||||
{
|
|
||||||
return subModule.getChildClients();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean doesDelegate()
|
|
||||||
{
|
|
||||||
return subModule.doesDelegate();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isListening()
|
|
||||||
{
|
|
||||||
return subModule.isListening();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public SoundSystem getSoundSystem()
|
|
||||||
{
|
|
||||||
return subModule.getSoundSystem();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public InputSystem getInput()
|
|
||||||
{
|
|
||||||
return subModule.getInput();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public DisplaySystem getDisplay()
|
|
||||||
{
|
|
||||||
return subModule.getDisplay();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void shutdown()
|
|
||||||
{
|
|
||||||
subModule.shutdown();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void addChildClient(Object client)
|
|
||||||
{
|
|
||||||
subModule.addChildClient(client);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void removeChildClient(Object client)
|
|
||||||
{
|
|
||||||
subModule.removeChildClient(client);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setEnabled(boolean yes)
|
|
||||||
{
|
|
||||||
if (isDirectlyEnabled() != yes) {
|
|
||||||
super.setEnabled(yes);
|
|
||||||
|
|
||||||
for (final Component c : components) {
|
|
||||||
c.setIndirectlyEnabled(yes);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Connect to bus and add to element list
|
|
||||||
*
|
|
||||||
* @param component added component, whose context has already been set.
|
|
||||||
*/
|
|
||||||
protected final void attach(Component component)
|
|
||||||
{
|
|
||||||
if (component == null) return;
|
|
||||||
if (component == this) throw new IllegalArgumentException("Uruboros. (infinite recursion evaded)");
|
|
||||||
|
|
||||||
components.add(component);
|
|
||||||
addChildClient(component);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void renderComponent()
|
|
||||||
{
|
|
||||||
for (final Component cmp : components) {
|
|
||||||
cmp.render();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void updateLayout()
|
|
||||||
{
|
|
||||||
for (final Component cmp : components) {
|
|
||||||
cmp.updateLayout();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setIndirectlyEnabled(boolean yes)
|
|
||||||
{
|
|
||||||
super.setIndirectlyEnabled(yes);
|
|
||||||
|
|
||||||
for (final Component cmp : components) {
|
|
||||||
cmp.setIndirectlyEnabled(yes);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,78 +0,0 @@
|
|||||||
package mightypork.gamecore.gui.components;
|
|
||||||
|
|
||||||
|
|
||||||
import mightypork.utils.math.constraints.num.Num;
|
|
||||||
import mightypork.utils.math.constraints.rect.Rect;
|
|
||||||
import mightypork.utils.math.constraints.rect.RectBound;
|
|
||||||
import mightypork.utils.math.constraints.vect.Vect;
|
|
||||||
import mightypork.utils.math.constraints.vect.proxy.VectAdapter;
|
|
||||||
|
|
||||||
|
|
||||||
public abstract class LinearComponent extends BaseComponent implements DynamicWidthComponent {
|
|
||||||
|
|
||||||
private final Rect rect = new Rect() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Vect size()
|
|
||||||
{
|
|
||||||
return new Vect() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public double x()
|
|
||||||
{
|
|
||||||
return computeWidth(y());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public double y()
|
|
||||||
{
|
|
||||||
return height.value();
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Vect origin()
|
|
||||||
{
|
|
||||||
return new VectAdapter() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Vect getSource()
|
|
||||||
{
|
|
||||||
return origin;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
private Vect origin;
|
|
||||||
private Num height;
|
|
||||||
|
|
||||||
|
|
||||||
public LinearComponent()
|
|
||||||
{
|
|
||||||
super.setRect(rect);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setRect(RectBound rect)
|
|
||||||
{
|
|
||||||
throw new RuntimeException("Cannot assign a rect to a linear component. Set origin and height instead.");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void setHeight(Num height)
|
|
||||||
{
|
|
||||||
this.height = height;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void setOrigin(Vect origin)
|
|
||||||
{
|
|
||||||
this.origin = origin;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
package mightypork.gamecore.gui.components;
|
|
||||||
|
|
||||||
|
|
||||||
import mightypork.gamecore.render.Renderable;
|
|
||||||
import mightypork.utils.math.constraints.rect.PluggableRectBound;
|
|
||||||
import mightypork.utils.math.constraints.rect.Rect;
|
|
||||||
import mightypork.utils.math.constraints.rect.RectBound;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Renderable that can be assigned different context
|
|
||||||
*
|
|
||||||
* @author Ondřej Hruška (MightyPork)
|
|
||||||
*/
|
|
||||||
public interface PluggableRenderable extends Renderable, PluggableRectBound {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
void render();
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
Rect getRect();
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
void setRect(RectBound rect);
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
package mightypork.gamecore.gui.components.input;
|
|
||||||
|
|
||||||
|
|
||||||
import mightypork.gamecore.gui.Action;
|
|
||||||
import mightypork.gamecore.gui.ActionTrigger;
|
|
||||||
import mightypork.gamecore.gui.components.InputComponent;
|
|
||||||
import mightypork.gamecore.input.events.MouseButtonEvent;
|
|
||||||
import mightypork.gamecore.input.events.MouseButtonHandler;
|
|
||||||
|
|
||||||
|
|
||||||
public abstract class ClickableComponent extends InputComponent implements ActionTrigger, MouseButtonHandler {
|
|
||||||
|
|
||||||
protected boolean btnDownOver;
|
|
||||||
private Action action;
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setAction(Action action)
|
|
||||||
{
|
|
||||||
this.action = action;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
protected void triggerAction()
|
|
||||||
{
|
|
||||||
if (action != null && isEnabled()) action.run();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void receive(MouseButtonEvent event)
|
|
||||||
{
|
|
||||||
if (!event.isButtonEvent()) return;
|
|
||||||
|
|
||||||
if (event.isDown()) {
|
|
||||||
btnDownOver = event.isOver(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (event.isUp()) {
|
|
||||||
|
|
||||||
if (btnDownOver && event.isOver(this)) {
|
|
||||||
triggerAction();
|
|
||||||
event.consume();
|
|
||||||
}
|
|
||||||
|
|
||||||
btnDownOver = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,64 +0,0 @@
|
|||||||
package mightypork.gamecore.gui.components.input;
|
|
||||||
|
|
||||||
|
|
||||||
import java.util.Collection;
|
|
||||||
|
|
||||||
import mightypork.gamecore.gui.components.Component;
|
|
||||||
import mightypork.utils.eventbus.clients.ClientList;
|
|
||||||
import mightypork.utils.eventbus.clients.DelegatingClient;
|
|
||||||
|
|
||||||
|
|
||||||
public class ClickableWrapper extends ClickableComponent implements DelegatingClient {
|
|
||||||
|
|
||||||
private final Component wrapped;
|
|
||||||
private final ClientList list;
|
|
||||||
|
|
||||||
|
|
||||||
public ClickableWrapper(Component wrapped)
|
|
||||||
{
|
|
||||||
this.wrapped = wrapped;
|
|
||||||
wrapped.setRect(this);
|
|
||||||
|
|
||||||
list = new ClientList(wrapped);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Collection<?> getChildClients()
|
|
||||||
{
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean doesDelegate()
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void renderComponent()
|
|
||||||
{
|
|
||||||
wrapped.render();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setEnabled(boolean yes)
|
|
||||||
{
|
|
||||||
if (yes != super.isDirectlyEnabled()) {
|
|
||||||
super.setEnabled(yes);
|
|
||||||
wrapped.setIndirectlyEnabled(yes);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setIndirectlyEnabled(boolean yes)
|
|
||||||
{
|
|
||||||
super.setIndirectlyEnabled(yes);
|
|
||||||
wrapped.setIndirectlyEnabled(yes);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,78 +0,0 @@
|
|||||||
package mightypork.gamecore.gui.components.input;
|
|
||||||
|
|
||||||
|
|
||||||
import mightypork.gamecore.gui.AlignX;
|
|
||||||
import mightypork.gamecore.gui.components.DynamicWidthComponent;
|
|
||||||
import mightypork.gamecore.gui.components.painters.TextPainter;
|
|
||||||
import mightypork.gamecore.input.InputSystem;
|
|
||||||
import mightypork.gamecore.resources.fonts.GLFont;
|
|
||||||
import mightypork.utils.math.color.Color;
|
|
||||||
import mightypork.utils.math.color.pal.RGB;
|
|
||||||
import mightypork.utils.math.constraints.vect.Vect;
|
|
||||||
import mightypork.utils.math.constraints.vect.var.VectVar;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Menu-like button with shadow and push state
|
|
||||||
*
|
|
||||||
* @author Ondřej Hruška (MightyPork)
|
|
||||||
*/
|
|
||||||
public class TextButton extends ClickableComponent implements DynamicWidthComponent {
|
|
||||||
|
|
||||||
public final TextPainter textPainter;
|
|
||||||
|
|
||||||
private final VectVar offset = Vect.makeVar();
|
|
||||||
|
|
||||||
public Vect offsetPassive = height().div(16).toVectXY();
|
|
||||||
public Vect offsetOver = height().div(20).toVectXY();
|
|
||||||
public Vect offsetUnder = height().div(32).toVectXY();
|
|
||||||
|
|
||||||
private final Color color;
|
|
||||||
|
|
||||||
private boolean hoverMove = true;
|
|
||||||
|
|
||||||
|
|
||||||
public TextButton(GLFont font, String text, Color color)
|
|
||||||
{
|
|
||||||
this.color = color;
|
|
||||||
|
|
||||||
this.textPainter = new TextPainter(font, AlignX.CENTER, this.color, text);
|
|
||||||
this.textPainter.setRect(this);
|
|
||||||
this.textPainter.setShadow(RGB.BLACK_30, offset);
|
|
||||||
textPainter.setVPaddingPercent(5);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void renderComponent()
|
|
||||||
{
|
|
||||||
if (isMouseOver()) {
|
|
||||||
if (InputSystem.isMouseButtonDown(0)) {
|
|
||||||
offset.setTo(offsetUnder);
|
|
||||||
} else {
|
|
||||||
offset.setTo(hoverMove ? offsetOver : offsetPassive);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
offset.setTo(offsetPassive);
|
|
||||||
}
|
|
||||||
|
|
||||||
textPainter.render();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Disable offset change on hover
|
|
||||||
*/
|
|
||||||
public void disableHoverEffect()
|
|
||||||
{
|
|
||||||
hoverMove = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public double computeWidth(double height)
|
|
||||||
{
|
|
||||||
return textPainter.computeWidth(height);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,45 +0,0 @@
|
|||||||
package mightypork.gamecore.gui.components.layout;
|
|
||||||
|
|
||||||
|
|
||||||
import mightypork.gamecore.core.modules.AppAccess;
|
|
||||||
import mightypork.gamecore.gui.components.Component;
|
|
||||||
import mightypork.utils.math.constraints.rect.RectBound;
|
|
||||||
|
|
||||||
|
|
||||||
public class ColumnLayout extends GridLayout {
|
|
||||||
|
|
||||||
private int col = 0;
|
|
||||||
|
|
||||||
|
|
||||||
public ColumnLayout(AppAccess app, int rows)
|
|
||||||
{
|
|
||||||
this(app, null, rows);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public ColumnLayout(AppAccess app, RectBound context, int cols)
|
|
||||||
{
|
|
||||||
super(app, context, 1, cols);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void add(final Component elem)
|
|
||||||
{
|
|
||||||
add(elem, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void add(final Component elem, int colSpan)
|
|
||||||
{
|
|
||||||
if (elem == null) return;
|
|
||||||
|
|
||||||
put(elem, 0, col, 1, colSpan);
|
|
||||||
col += colSpan;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void skip(int cols)
|
|
||||||
{
|
|
||||||
col += cols;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
package mightypork.gamecore.gui.components.layout;
|
|
||||||
|
|
||||||
|
|
||||||
import mightypork.gamecore.core.modules.AppAccess;
|
|
||||||
import mightypork.gamecore.gui.components.Component;
|
|
||||||
import mightypork.gamecore.gui.components.LayoutComponent;
|
|
||||||
import mightypork.utils.math.constraints.rect.RectBound;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Layout for components with arbitrary constraints.
|
|
||||||
*
|
|
||||||
* @author Ondřej Hruška (MightyPork)
|
|
||||||
*/
|
|
||||||
public class ConstraintLayout extends LayoutComponent {
|
|
||||||
|
|
||||||
public ConstraintLayout(AppAccess app)
|
|
||||||
{
|
|
||||||
super(app);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public ConstraintLayout(AppAccess app, RectBound context)
|
|
||||||
{
|
|
||||||
super(app, context);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add a component to the layout.<br>
|
|
||||||
* The component's rect must be set up manually.
|
|
||||||
*
|
|
||||||
* @param component
|
|
||||||
*/
|
|
||||||
public void add(Component component)
|
|
||||||
{
|
|
||||||
attach(component);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,90 +0,0 @@
|
|||||||
package mightypork.gamecore.gui.components.layout;
|
|
||||||
|
|
||||||
|
|
||||||
import mightypork.gamecore.core.modules.AppAccess;
|
|
||||||
import mightypork.gamecore.gui.AlignX;
|
|
||||||
import mightypork.gamecore.gui.components.Component;
|
|
||||||
import mightypork.gamecore.gui.components.LayoutComponent;
|
|
||||||
import mightypork.utils.math.constraints.num.Num;
|
|
||||||
import mightypork.utils.math.constraints.rect.Rect;
|
|
||||||
import mightypork.utils.math.constraints.rect.RectBound;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holder with same-sized columns, aligned to left or right
|
|
||||||
*
|
|
||||||
* @author Ondřej Hruška (MightyPork)
|
|
||||||
*/
|
|
||||||
public class FlowColumnLayout extends LayoutComponent {
|
|
||||||
|
|
||||||
private int col = 0;
|
|
||||||
private Num elementWidth;
|
|
||||||
private final AlignX align;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param app app access
|
|
||||||
* @param context context
|
|
||||||
* @param elementWidth width of all elements
|
|
||||||
* @param align component align. Legal values are LEFT and RIGHT.
|
|
||||||
*/
|
|
||||||
public FlowColumnLayout(AppAccess app, RectBound context, Num elementWidth, AlignX align)
|
|
||||||
{
|
|
||||||
super(app, context);
|
|
||||||
this.elementWidth = elementWidth;
|
|
||||||
this.align = align;
|
|
||||||
|
|
||||||
if (align != AlignX.LEFT && align != AlignX.RIGHT) {
|
|
||||||
throw new IllegalArgumentException("Can align only left or right.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* make a new holder.<br>
|
|
||||||
* Context must be assigned before rendering.
|
|
||||||
*
|
|
||||||
* @param app app access
|
|
||||||
* @param elementWidth width of all elements
|
|
||||||
* @param align component align. Legal values are LEFT and RIGHT.
|
|
||||||
*/
|
|
||||||
public FlowColumnLayout(AppAccess app, Num elementWidth, AlignX align)
|
|
||||||
{
|
|
||||||
this(app, null, elementWidth, align);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add an item
|
|
||||||
*
|
|
||||||
* @param elem
|
|
||||||
*/
|
|
||||||
public void add(final Component elem)
|
|
||||||
{
|
|
||||||
if (elem == null) return;
|
|
||||||
|
|
||||||
final Rect r;
|
|
||||||
|
|
||||||
switch (align) {
|
|
||||||
case LEFT:
|
|
||||||
r = leftEdge().growRight(elementWidth).moveX(elementWidth.mul(col++));
|
|
||||||
break;
|
|
||||||
case RIGHT:
|
|
||||||
r = rightEdge().growLeft(elementWidth).moveX(elementWidth.mul(-(col++)));
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new IllegalArgumentException("Bad align.");
|
|
||||||
}
|
|
||||||
|
|
||||||
elem.setRect(r);
|
|
||||||
|
|
||||||
attach(elem);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void setElementWidth(Num elementWidth)
|
|
||||||
{
|
|
||||||
this.elementWidth = elementWidth;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,89 +0,0 @@
|
|||||||
package mightypork.gamecore.gui.components.layout;
|
|
||||||
|
|
||||||
|
|
||||||
import mightypork.gamecore.core.modules.AppAccess;
|
|
||||||
import mightypork.gamecore.gui.AlignY;
|
|
||||||
import mightypork.gamecore.gui.components.Component;
|
|
||||||
import mightypork.gamecore.gui.components.LayoutComponent;
|
|
||||||
import mightypork.utils.math.constraints.num.Num;
|
|
||||||
import mightypork.utils.math.constraints.rect.Rect;
|
|
||||||
import mightypork.utils.math.constraints.rect.RectBound;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holder with same-sized rows, aligned to top or bottom
|
|
||||||
*
|
|
||||||
* @author Ondřej Hruška (MightyPork)
|
|
||||||
*/
|
|
||||||
public class FlowRowLayout extends LayoutComponent {
|
|
||||||
|
|
||||||
private int row = 0;
|
|
||||||
private Num elementHeight;
|
|
||||||
private final AlignY align;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param app app access
|
|
||||||
* @param context context
|
|
||||||
* @param elementHeight height of all elements
|
|
||||||
* @param align component align. Legal values are TOP and BOTTOM.
|
|
||||||
*/
|
|
||||||
public FlowRowLayout(AppAccess app, RectBound context, Num elementHeight, AlignY align)
|
|
||||||
{
|
|
||||||
super(app, context);
|
|
||||||
this.elementHeight = elementHeight;
|
|
||||||
this.align = align;
|
|
||||||
|
|
||||||
if (align != AlignY.TOP && align != AlignY.BOTTOM) {
|
|
||||||
throw new IllegalArgumentException("Can align only to top or bottom.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* make a new holder.<br>
|
|
||||||
* Context must be assigned before rendering.
|
|
||||||
*
|
|
||||||
* @param app app access
|
|
||||||
* @param elementHeight height of all elements
|
|
||||||
* @param align component align. Legal values are TOP and BOTTOM.
|
|
||||||
*/
|
|
||||||
public FlowRowLayout(AppAccess app, Num elementHeight, AlignY align)
|
|
||||||
{
|
|
||||||
this(app, null, elementHeight, align);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add an item
|
|
||||||
*
|
|
||||||
* @param elem
|
|
||||||
*/
|
|
||||||
public void add(final Component elem)
|
|
||||||
{
|
|
||||||
if (elem == null) return;
|
|
||||||
|
|
||||||
final Rect r;
|
|
||||||
|
|
||||||
switch (align) {
|
|
||||||
case TOP:
|
|
||||||
r = topEdge().growDown(elementHeight).moveY(elementHeight.mul(row++));
|
|
||||||
break;
|
|
||||||
case BOTTOM:
|
|
||||||
r = bottomEdge().growUp(elementHeight).moveY(elementHeight.mul(-(row++)));
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new IllegalArgumentException("Bad align.");
|
|
||||||
}
|
|
||||||
|
|
||||||
elem.setRect(r);
|
|
||||||
|
|
||||||
attach(elem);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void setElementHeight(Num elementHeight)
|
|
||||||
{
|
|
||||||
this.elementHeight = elementHeight;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,83 +0,0 @@
|
|||||||
package mightypork.gamecore.gui.components.layout;
|
|
||||||
|
|
||||||
|
|
||||||
import mightypork.gamecore.core.modules.AppAccess;
|
|
||||||
import mightypork.gamecore.gui.components.Component;
|
|
||||||
import mightypork.gamecore.gui.components.LayoutComponent;
|
|
||||||
import mightypork.utils.math.constraints.rect.RectBound;
|
|
||||||
import mightypork.utils.math.constraints.rect.builders.TiledRect;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holder with table cells
|
|
||||||
*
|
|
||||||
* @author Ondřej Hruška (MightyPork)
|
|
||||||
*/
|
|
||||||
public class GridLayout extends LayoutComponent {
|
|
||||||
|
|
||||||
private final TiledRect tiler;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param app app access
|
|
||||||
* @param context context
|
|
||||||
* @param rows number of rows
|
|
||||||
* @param cols number of columns
|
|
||||||
*/
|
|
||||||
public GridLayout(AppAccess app, RectBound context, int rows, int cols)
|
|
||||||
{
|
|
||||||
super(app, context);
|
|
||||||
this.tiler = tiles(cols, rows);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* make a new holder.<br>
|
|
||||||
* Context must be assigned before rendering.
|
|
||||||
*
|
|
||||||
* @param app app access
|
|
||||||
* @param rows number of rows
|
|
||||||
* @param cols number of columns
|
|
||||||
*/
|
|
||||||
public GridLayout(AppAccess app, int rows, int cols)
|
|
||||||
{
|
|
||||||
this(app, null, rows, cols);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add a row to the holder.
|
|
||||||
*
|
|
||||||
* @param row row (one-based)
|
|
||||||
* @param column column (one-based)
|
|
||||||
* @param elem added component
|
|
||||||
*/
|
|
||||||
public void put(Component elem, int row, int column)
|
|
||||||
{
|
|
||||||
if (elem == null) return;
|
|
||||||
|
|
||||||
elem.setRect(tiler.tile(column, row));
|
|
||||||
|
|
||||||
attach(elem);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Put with span
|
|
||||||
*
|
|
||||||
* @param elem
|
|
||||||
* @param row
|
|
||||||
* @param column
|
|
||||||
* @param rowspan
|
|
||||||
* @param colspan
|
|
||||||
*/
|
|
||||||
public void put(Component elem, int row, int column, int rowspan, int colspan)
|
|
||||||
{
|
|
||||||
if (elem == null) return;
|
|
||||||
|
|
||||||
elem.setRect(tiler.span(column, row, colspan, rowspan));
|
|
||||||
|
|
||||||
attach(elem);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
package mightypork.gamecore.gui.components.layout;
|
|
||||||
|
|
||||||
|
|
||||||
import mightypork.gamecore.gui.components.BaseComponent;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Invisible component that does nothing at all; Null object pattern
|
|
||||||
*
|
|
||||||
* @author Ondřej Hruška (MightyPork)
|
|
||||||
*/
|
|
||||||
public class NullComponent extends BaseComponent {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void renderComponent()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,45 +0,0 @@
|
|||||||
package mightypork.gamecore.gui.components.layout;
|
|
||||||
|
|
||||||
|
|
||||||
import mightypork.gamecore.core.modules.AppAccess;
|
|
||||||
import mightypork.gamecore.gui.components.Component;
|
|
||||||
import mightypork.utils.math.constraints.rect.RectBound;
|
|
||||||
|
|
||||||
|
|
||||||
public class RowLayout extends GridLayout {
|
|
||||||
|
|
||||||
private int row = 0;
|
|
||||||
|
|
||||||
|
|
||||||
public RowLayout(AppAccess app, int rows)
|
|
||||||
{
|
|
||||||
this(app, null, rows);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public RowLayout(AppAccess app, RectBound context, int rows)
|
|
||||||
{
|
|
||||||
super(app, context, rows, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void add(final Component elem)
|
|
||||||
{
|
|
||||||
add(elem, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void add(final Component elem, int rowSpan)
|
|
||||||
{
|
|
||||||
if (elem == null) return;
|
|
||||||
|
|
||||||
put(elem, row, 0, rowSpan, 1);
|
|
||||||
row += rowSpan;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void skip(int rows)
|
|
||||||
{
|
|
||||||
row += rows;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,79 +0,0 @@
|
|||||||
package mightypork.gamecore.gui.components.layout.linear;
|
|
||||||
|
|
||||||
|
|
||||||
import java.util.Collection;
|
|
||||||
|
|
||||||
import mightypork.gamecore.gui.components.Component;
|
|
||||||
import mightypork.gamecore.gui.components.LinearComponent;
|
|
||||||
import mightypork.utils.eventbus.clients.ClientList;
|
|
||||||
import mightypork.utils.eventbus.clients.DelegatingClient;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts a component into a linear component
|
|
||||||
*
|
|
||||||
* @author Ondřej Hruška (MightyPork)
|
|
||||||
*/
|
|
||||||
public abstract class AbstractLinearWrapper extends LinearComponent implements DelegatingClient {
|
|
||||||
|
|
||||||
protected final Component wrapped;
|
|
||||||
private final ClientList list;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param wrapped wrapped component. Can be null.
|
|
||||||
*/
|
|
||||||
public AbstractLinearWrapper(Component wrapped)
|
|
||||||
{
|
|
||||||
this.wrapped = wrapped;
|
|
||||||
if (wrapped != null) {
|
|
||||||
if (wrapped instanceof LinearComponent) {
|
|
||||||
((LinearComponent) wrapped).setHeight(height());
|
|
||||||
((LinearComponent) wrapped).setOrigin(origin());
|
|
||||||
} else {
|
|
||||||
wrapped.setRect(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
list = new ClientList(wrapped);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void renderComponent()
|
|
||||||
{
|
|
||||||
if (wrapped != null) wrapped.render();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Collection<?> getChildClients()
|
|
||||||
{
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean doesDelegate()
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setEnabled(boolean yes)
|
|
||||||
{
|
|
||||||
if (yes != super.isDirectlyEnabled()) {
|
|
||||||
super.setEnabled(yes);
|
|
||||||
wrapped.setIndirectlyEnabled(yes);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setIndirectlyEnabled(boolean yes)
|
|
||||||
{
|
|
||||||
super.setIndirectlyEnabled(yes);
|
|
||||||
wrapped.setIndirectlyEnabled(yes);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
package mightypork.gamecore.gui.components.layout.linear;
|
|
||||||
|
|
||||||
|
|
||||||
import mightypork.gamecore.gui.components.layout.NullComponent;
|
|
||||||
import mightypork.utils.math.constraints.num.Num;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gap in linear layout
|
|
||||||
*
|
|
||||||
* @author Ondřej Hruška (MightyPork)
|
|
||||||
*/
|
|
||||||
public class LinearGap extends LinearRectangle {
|
|
||||||
|
|
||||||
public LinearGap(Num width)
|
|
||||||
{
|
|
||||||
super(new NullComponent(), width);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public LinearGap(double heightPercent)
|
|
||||||
{
|
|
||||||
this(Num.ZERO);
|
|
||||||
setWidth(height().perc(heightPercent));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,90 +0,0 @@
|
|||||||
package mightypork.gamecore.gui.components.layout.linear;
|
|
||||||
|
|
||||||
|
|
||||||
import mightypork.gamecore.core.modules.AppAccess;
|
|
||||||
import mightypork.gamecore.gui.AlignX;
|
|
||||||
import mightypork.gamecore.gui.components.DynamicWidthComponent;
|
|
||||||
import mightypork.gamecore.gui.components.LayoutComponent;
|
|
||||||
import mightypork.gamecore.gui.components.LinearComponent;
|
|
||||||
import mightypork.utils.math.constraints.num.Num;
|
|
||||||
import mightypork.utils.math.constraints.num.batch.NumSum;
|
|
||||||
import mightypork.utils.math.constraints.rect.RectBound;
|
|
||||||
import mightypork.utils.math.constraints.vect.Vect;
|
|
||||||
import mightypork.utils.math.constraints.vect.proxy.VectAdapter;
|
|
||||||
|
|
||||||
|
|
||||||
public class LinearLayout extends LayoutComponent {
|
|
||||||
|
|
||||||
public LinearLayout(AppAccess app, AlignX align)
|
|
||||||
{
|
|
||||||
super(app);
|
|
||||||
this.align = align;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public LinearLayout(AppAccess app, RectBound context, AlignX align)
|
|
||||||
{
|
|
||||||
super(app, context);
|
|
||||||
this.align = align;
|
|
||||||
}
|
|
||||||
|
|
||||||
private final NumSum totalWidth = new NumSum();
|
|
||||||
|
|
||||||
private final Vect leftAlignOrigin = LinearLayout.this.origin();
|
|
||||||
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 leftMostOrigin = new VectAdapter() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Vect getSource()
|
|
||||||
{
|
|
||||||
switch (align) {
|
|
||||||
default:
|
|
||||||
case LEFT:
|
|
||||||
return leftAlignOrigin;
|
|
||||||
case CENTER:
|
|
||||||
return centerAlignOrigin;
|
|
||||||
case RIGHT:
|
|
||||||
return rightAlignOrigin;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
private Vect nextOrigin = leftMostOrigin;
|
|
||||||
|
|
||||||
private AlignX align = AlignX.LEFT;
|
|
||||||
|
|
||||||
|
|
||||||
public void add(DynamicWidthComponent dwcomp)
|
|
||||||
{
|
|
||||||
add(new LinearWrapper(dwcomp));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void add(LinearComponent lincomp)
|
|
||||||
{
|
|
||||||
lincomp.setHeight(height());
|
|
||||||
lincomp.setOrigin(nextOrigin);
|
|
||||||
nextOrigin = nextOrigin.add(lincomp.width(), Num.ZERO);
|
|
||||||
totalWidth.addSummand(lincomp.width());
|
|
||||||
attach(lincomp);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void setAlign(AlignX align)
|
|
||||||
{
|
|
||||||
this.align = align;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add a gap.
|
|
||||||
*
|
|
||||||
* @param heightPercent percent of height for gap width
|
|
||||||
*/
|
|
||||||
public void gap(double heightPercent)
|
|
||||||
{
|
|
||||||
add(new LinearGap(heightPercent));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
package mightypork.gamecore.gui.components.layout.linear;
|
|
||||||
|
|
||||||
|
|
||||||
import mightypork.gamecore.gui.components.Component;
|
|
||||||
import mightypork.utils.math.constraints.num.Num;
|
|
||||||
|
|
||||||
|
|
||||||
public class LinearRectangle extends AbstractLinearWrapper {
|
|
||||||
|
|
||||||
private Num width;
|
|
||||||
|
|
||||||
|
|
||||||
public LinearRectangle(Component wrapped, Num width)
|
|
||||||
{
|
|
||||||
super(wrapped);
|
|
||||||
this.width = width;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void setWidth(Num width)
|
|
||||||
{
|
|
||||||
this.width = width;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public double computeWidth(double height)
|
|
||||||
{
|
|
||||||
return this.width.value();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
package mightypork.gamecore.gui.components.layout.linear;
|
|
||||||
|
|
||||||
|
|
||||||
import mightypork.gamecore.gui.components.Component;
|
|
||||||
|
|
||||||
|
|
||||||
public class LinearSquare extends AbstractLinearWrapper {
|
|
||||||
|
|
||||||
public LinearSquare(Component wrapped)
|
|
||||||
{
|
|
||||||
super(wrapped);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public double computeWidth(double height)
|
|
||||||
{
|
|
||||||
return height;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
package mightypork.gamecore.gui.components.layout.linear;
|
|
||||||
|
|
||||||
|
|
||||||
import mightypork.gamecore.gui.components.DynamicWidthComponent;
|
|
||||||
|
|
||||||
|
|
||||||
public class LinearWrapper extends AbstractLinearWrapper {
|
|
||||||
|
|
||||||
public LinearWrapper(DynamicWidthComponent wrapped)
|
|
||||||
{
|
|
||||||
super(wrapped);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public double computeWidth(double height)
|
|
||||||
{
|
|
||||||
return ((DynamicWidthComponent) wrapped).computeWidth(height);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
package mightypork.gamecore.gui.components.painters;
|
|
||||||
|
|
||||||
|
|
||||||
import mightypork.gamecore.gui.components.BaseComponent;
|
|
||||||
import mightypork.gamecore.gui.components.DynamicWidthComponent;
|
|
||||||
import mightypork.gamecore.render.Render;
|
|
||||||
import mightypork.gamecore.resources.textures.TxQuad;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Draws image in given rect
|
|
||||||
*
|
|
||||||
* @author Ondřej Hruška (MightyPork)
|
|
||||||
*/
|
|
||||||
public class ImagePainter extends BaseComponent implements DynamicWidthComponent {
|
|
||||||
|
|
||||||
private TxQuad txQuad;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param txQuad drawn image
|
|
||||||
*/
|
|
||||||
public ImagePainter(TxQuad txQuad)
|
|
||||||
{
|
|
||||||
this.txQuad = txQuad;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void renderComponent()
|
|
||||||
{
|
|
||||||
Render.quadTextured(this, txQuad);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public double computeWidth(double height)
|
|
||||||
{
|
|
||||||
return (height / txQuad.uvs.height().value()) * txQuad.uvs.width().value();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void setTxQuad(TxQuad txQuad)
|
|
||||||
{
|
|
||||||
this.txQuad = txQuad;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,72 +0,0 @@
|
|||||||
package mightypork.gamecore.gui.components.painters;
|
|
||||||
|
|
||||||
|
|
||||||
import mightypork.gamecore.gui.components.BaseComponent;
|
|
||||||
import mightypork.gamecore.render.Render;
|
|
||||||
import mightypork.utils.annotations.FactoryMethod;
|
|
||||||
import mightypork.utils.math.color.Color;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Draws image in given rect
|
|
||||||
*
|
|
||||||
* @author Ondřej Hruška (MightyPork)
|
|
||||||
*/
|
|
||||||
public class QuadPainter extends BaseComponent {
|
|
||||||
|
|
||||||
@FactoryMethod
|
|
||||||
public static QuadPainter gradH(Color colorLeft, Color colorRight)
|
|
||||||
{
|
|
||||||
return new QuadPainter(colorLeft, colorRight, colorRight, colorLeft);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@FactoryMethod
|
|
||||||
public static QuadPainter gradV(Color colorTop, Color colorBottom)
|
|
||||||
{
|
|
||||||
return new QuadPainter(colorTop, colorTop, colorBottom, colorBottom);
|
|
||||||
}
|
|
||||||
|
|
||||||
private final Color colorHMinVMin;
|
|
||||||
private final Color colorHMaxVMin;
|
|
||||||
private final Color colorHMaxVMax;
|
|
||||||
private final Color colorHMinVMax;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Painter with solid color
|
|
||||||
*
|
|
||||||
* @param color
|
|
||||||
*/
|
|
||||||
public QuadPainter(Color color)
|
|
||||||
{
|
|
||||||
this.colorHMinVMin = color;
|
|
||||||
this.colorHMaxVMin = color;
|
|
||||||
this.colorHMaxVMax = color;
|
|
||||||
this.colorHMinVMax = color;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Painter with coloured vertices.
|
|
||||||
*
|
|
||||||
* @param colorHMinVMin
|
|
||||||
* @param colorHMaxVMin
|
|
||||||
* @param colorHMaxVMax
|
|
||||||
* @param colorHMinVMax
|
|
||||||
*/
|
|
||||||
public QuadPainter(Color colorHMinVMin, Color colorHMaxVMin, Color colorHMaxVMax, Color colorHMinVMax)
|
|
||||||
{
|
|
||||||
this.colorHMinVMin = colorHMinVMin;
|
|
||||||
this.colorHMaxVMin = colorHMaxVMin;
|
|
||||||
this.colorHMaxVMax = colorHMaxVMax;
|
|
||||||
this.colorHMinVMax = colorHMinVMax;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void renderComponent()
|
|
||||||
{
|
|
||||||
Render.quadColor(getRect(), colorHMinVMin, colorHMaxVMin, colorHMaxVMax, colorHMinVMax);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,170 +0,0 @@
|
|||||||
package mightypork.gamecore.gui.components.painters;
|
|
||||||
|
|
||||||
|
|
||||||
import mightypork.gamecore.gui.AlignX;
|
|
||||||
import mightypork.gamecore.gui.components.BaseComponent;
|
|
||||||
import mightypork.gamecore.gui.components.DynamicWidthComponent;
|
|
||||||
import mightypork.gamecore.render.Render;
|
|
||||||
import mightypork.gamecore.resources.fonts.FontRenderer;
|
|
||||||
import mightypork.gamecore.resources.fonts.GLFont;
|
|
||||||
import mightypork.utils.math.color.Color;
|
|
||||||
import mightypork.utils.math.color.pal.RGB;
|
|
||||||
import mightypork.utils.math.constraints.num.Num;
|
|
||||||
import mightypork.utils.math.constraints.rect.Rect;
|
|
||||||
import mightypork.utils.math.constraints.vect.Vect;
|
|
||||||
import mightypork.utils.string.StringProvider;
|
|
||||||
import mightypork.utils.string.StringWrapper;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Text painting component.
|
|
||||||
*
|
|
||||||
* @author Ondřej Hruška (MightyPork)
|
|
||||||
*/
|
|
||||||
public class TextPainter extends BaseComponent implements DynamicWidthComponent {
|
|
||||||
|
|
||||||
private static final boolean DEBUG_FONT_RENDER = false;
|
|
||||||
private final FontRenderer font;
|
|
||||||
private Color color;
|
|
||||||
private AlignX align;
|
|
||||||
private StringProvider text;
|
|
||||||
private boolean shadow;
|
|
||||||
|
|
||||||
private double yPaddingPerc = 0;
|
|
||||||
|
|
||||||
private Color shadowColor = RGB.BLACK;
|
|
||||||
private Vect shadowOffset = Vect.make(2, 2);
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param font font to use
|
|
||||||
*/
|
|
||||||
public TextPainter(GLFont font)
|
|
||||||
{
|
|
||||||
this(font, AlignX.LEFT, RGB.WHITE);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public TextPainter(GLFont font, Color color, String text)
|
|
||||||
{
|
|
||||||
this(font, AlignX.LEFT, color, new StringWrapper(text));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public TextPainter(GLFont font, Color color, StringProvider text)
|
|
||||||
{
|
|
||||||
this(font, AlignX.LEFT, color, text);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public TextPainter(GLFont font, Color color)
|
|
||||||
{
|
|
||||||
this(font, AlignX.LEFT, color, (StringProvider) null);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public TextPainter(GLFont font, AlignX align, Color color, String text)
|
|
||||||
{
|
|
||||||
this(font, align, color, new StringWrapper(text));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public TextPainter(GLFont font, AlignX align, Color color, StringProvider text)
|
|
||||||
{
|
|
||||||
this.font = new FontRenderer(font);
|
|
||||||
this.color = color;
|
|
||||||
this.align = align;
|
|
||||||
this.text = text;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public TextPainter(GLFont font, AlignX align, Color color)
|
|
||||||
{
|
|
||||||
this(font, align, color, (StringProvider) null);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void renderComponent()
|
|
||||||
{
|
|
||||||
if (text == null) return;
|
|
||||||
|
|
||||||
final String str = text.getString();
|
|
||||||
|
|
||||||
final Num shrY = height().perc(yPaddingPerc);
|
|
||||||
|
|
||||||
final Rect rect = getRect().shrink(Num.ZERO, shrY);
|
|
||||||
|
|
||||||
if (shadow) {
|
|
||||||
font.draw(str, rect.round(), align, shadowColor);
|
|
||||||
}
|
|
||||||
|
|
||||||
final Rect r = (shadow ? rect.move(shadowOffset.neg()) : rect).round();
|
|
||||||
font.draw(str, r, align, color);
|
|
||||||
|
|
||||||
if (DEBUG_FONT_RENDER) Render.quadColor(r, RGB.PINK.withAlpha(0.4));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void setShadow(Color color, Vect offset)
|
|
||||||
{
|
|
||||||
setShadow(true);
|
|
||||||
setShadowColor(color);
|
|
||||||
setShadowOffset(offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void setShadow(boolean shadow)
|
|
||||||
{
|
|
||||||
this.shadow = shadow;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void setShadowColor(Color shadowColor)
|
|
||||||
{
|
|
||||||
this.shadowColor = shadowColor;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void setShadowOffset(Vect shadowOffset)
|
|
||||||
{
|
|
||||||
this.shadowOffset = shadowOffset;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void setColor(Color color)
|
|
||||||
{
|
|
||||||
this.color = color;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void setAlign(AlignX align)
|
|
||||||
{
|
|
||||||
this.align = align;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void setText(String text)
|
|
||||||
{
|
|
||||||
this.text = new StringWrapper(text);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void setText(StringProvider text)
|
|
||||||
{
|
|
||||||
this.text = text;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void setVPaddingPercent(double percY)
|
|
||||||
{
|
|
||||||
yPaddingPerc = percY;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public double computeWidth(double height)
|
|
||||||
{
|
|
||||||
return font.getWidth(this.text.getString(), height * ((100 - yPaddingPerc * 2) / 100D));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
package mightypork.gamecore.gui.events;
|
|
||||||
|
|
||||||
|
|
||||||
import mightypork.utils.eventbus.BusEvent;
|
|
||||||
import mightypork.utils.eventbus.events.flags.DirectEvent;
|
|
||||||
import mightypork.utils.eventbus.events.flags.NonConsumableEvent;
|
|
||||||
import mightypork.utils.eventbus.events.flags.NonRejectableEvent;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Intended use is to notify UI component sub-clients that they should poll
|
|
||||||
* their cached constraints.
|
|
||||||
*
|
|
||||||
* @author Ondřej Hruška (MightyPork)
|
|
||||||
*/
|
|
||||||
@DirectEvent
|
|
||||||
@NonConsumableEvent
|
|
||||||
@NonRejectableEvent
|
|
||||||
public class LayoutChangeEvent extends BusEvent<LayoutChangeListener> {
|
|
||||||
|
|
||||||
public LayoutChangeEvent()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void handleBy(LayoutChangeListener handler)
|
|
||||||
{
|
|
||||||
handler.onLayoutChanged();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
package mightypork.gamecore.gui.events;
|
|
||||||
|
|
||||||
|
|
||||||
public interface LayoutChangeListener {
|
|
||||||
|
|
||||||
public void onLayoutChanged();
|
|
||||||
}
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
package mightypork.gamecore.gui.events;
|
|
||||||
|
|
||||||
|
|
||||||
import mightypork.utils.eventbus.BusEvent;
|
|
||||||
import mightypork.utils.eventbus.events.flags.SingleReceiverEvent;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Request to change screen
|
|
||||||
*
|
|
||||||
* @author Ondřej Hruška (MightyPork)
|
|
||||||
*/
|
|
||||||
@SingleReceiverEvent
|
|
||||||
public class ScreenRequest extends BusEvent<ScreenRequestListener> {
|
|
||||||
|
|
||||||
private final String scrName;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param screenKey screen name
|
|
||||||
*/
|
|
||||||
public ScreenRequest(String screenKey)
|
|
||||||
{
|
|
||||||
scrName = screenKey;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void handleBy(ScreenRequestListener handler)
|
|
||||||
{
|
|
||||||
handler.showScreen(scrName);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
package mightypork.gamecore.gui.events;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@link ScreenRequest} listener
|
|
||||||
*
|
|
||||||
* @author Ondřej Hruška (MightyPork)
|
|
||||||
*/
|
|
||||||
public interface ScreenRequestListener {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param key screen to show
|
|
||||||
*/
|
|
||||||
void showScreen(String key);
|
|
||||||
}
|
|
||||||
@@ -1,118 +0,0 @@
|
|||||||
package mightypork.gamecore.gui.screens;
|
|
||||||
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Comparator;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import mightypork.gamecore.core.modules.AppAccess;
|
|
||||||
import mightypork.utils.eventbus.clients.DelegatingClient;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Screen with multiple instances of {@link ScreenLayer}
|
|
||||||
*
|
|
||||||
* @author Ondřej Hruška (MightyPork)
|
|
||||||
*/
|
|
||||||
public abstract class LayeredScreen extends Screen {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Wrapper for delegating client, to use custom client ordering.
|
|
||||||
*
|
|
||||||
* @author Ondřej Hruška (MightyPork)
|
|
||||||
*/
|
|
||||||
private class LayersClient implements DelegatingClient {
|
|
||||||
|
|
||||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
|
||||||
@Override
|
|
||||||
public Collection getChildClients()
|
|
||||||
{
|
|
||||||
return layersByEventPriority;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean doesDelegate()
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private final List<ScreenLayer> layersByZIndex = new ArrayList<>();
|
|
||||||
private final List<ScreenLayer> layersByEventPriority = new ArrayList<>();
|
|
||||||
|
|
||||||
private final LayersClient layersClient = new LayersClient();
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param app app access
|
|
||||||
*/
|
|
||||||
public LayeredScreen(AppAccess app)
|
|
||||||
{
|
|
||||||
super(app);
|
|
||||||
addChildClient(layersClient);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void renderScreen()
|
|
||||||
{
|
|
||||||
for (final ScreenLayer layer : layersByZIndex) {
|
|
||||||
if (layer.isVisible()) layer.render();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add a layer to the screen.
|
|
||||||
*
|
|
||||||
* @param layer
|
|
||||||
*/
|
|
||||||
protected void addLayer(ScreenLayer layer)
|
|
||||||
{
|
|
||||||
this.layersByZIndex.add(layer);
|
|
||||||
this.layersByEventPriority.add(layer);
|
|
||||||
|
|
||||||
Collections.sort(layersByEventPriority, new Comparator<Overlay>() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int compare(Overlay o1, Overlay o2)
|
|
||||||
{
|
|
||||||
return o2.getEventPriority() - o1.getEventPriority();
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
Collections.sort(layersByZIndex, new Comparator<Overlay>() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int compare(Overlay o1, Overlay o2)
|
|
||||||
{
|
|
||||||
return o1.getZIndex() - o2.getZIndex();
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onScreenEnter()
|
|
||||||
{
|
|
||||||
for (final ScreenLayer layer : layersByEventPriority) {
|
|
||||||
layer.onScreenEnter();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onScreenLeave()
|
|
||||||
{
|
|
||||||
for (final ScreenLayer layer : layersByEventPriority) {
|
|
||||||
layer.onScreenLeave();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,225 +0,0 @@
|
|||||||
package mightypork.gamecore.gui.screens;
|
|
||||||
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collection;
|
|
||||||
|
|
||||||
import mightypork.gamecore.core.modules.AppAccess;
|
|
||||||
import mightypork.gamecore.core.modules.AppSubModule;
|
|
||||||
import mightypork.gamecore.gui.Hideable;
|
|
||||||
import mightypork.gamecore.gui.components.layout.ConstraintLayout;
|
|
||||||
import mightypork.gamecore.gui.events.LayoutChangeListener;
|
|
||||||
import mightypork.gamecore.input.KeyBinder;
|
|
||||||
import mightypork.gamecore.input.KeyBindingPool;
|
|
||||||
import mightypork.gamecore.input.KeyStroke;
|
|
||||||
import mightypork.gamecore.input.KeyStroke.Edge;
|
|
||||||
import mightypork.gamecore.render.Renderable;
|
|
||||||
import mightypork.utils.annotations.DefaultImpl;
|
|
||||||
import mightypork.utils.interfaces.Enableable;
|
|
||||||
import mightypork.utils.interfaces.Updateable;
|
|
||||||
import mightypork.utils.math.color.Color;
|
|
||||||
import mightypork.utils.math.constraints.num.Num;
|
|
||||||
import mightypork.utils.math.constraints.vect.Vect;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Abstract overlay.<br>
|
|
||||||
* Overlay is connected to event bus and is renderable.
|
|
||||||
*
|
|
||||||
* @author Ondřej Hruška (MightyPork)
|
|
||||||
*/
|
|
||||||
public abstract class Overlay extends AppSubModule implements Comparable<Overlay>, Updateable, Renderable, KeyBinder, Hideable, Enableable,
|
|
||||||
LayoutChangeListener {
|
|
||||||
|
|
||||||
private boolean visible = true;
|
|
||||||
private boolean enabled = true;
|
|
||||||
|
|
||||||
private final KeyBindingPool keybindings = new KeyBindingPool();
|
|
||||||
|
|
||||||
/** Root layout, rendered and attached to the event bus. */
|
|
||||||
protected final ConstraintLayout root;
|
|
||||||
|
|
||||||
/** Constraint: Mouse position. */
|
|
||||||
protected final Vect mouse;
|
|
||||||
|
|
||||||
/** Extra rendered items (outside root) */
|
|
||||||
protected final Collection<Renderable> rendered = new ArrayList<>();
|
|
||||||
|
|
||||||
/** Extra updated items (outside root - those can just implement Updateable) */
|
|
||||||
protected final Collection<Updateable> updated = new ArrayList<>();
|
|
||||||
private Num alphaMul = Num.ONE;
|
|
||||||
|
|
||||||
|
|
||||||
public Overlay(AppAccess app)
|
|
||||||
{
|
|
||||||
super(app);
|
|
||||||
|
|
||||||
this.mouse = getInput().getMousePos();
|
|
||||||
|
|
||||||
this.root = new ConstraintLayout(app, getDisplay());
|
|
||||||
addChildClient(root);
|
|
||||||
addChildClient(keybindings);
|
|
||||||
|
|
||||||
rendered.add(root);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public final void bindKey(KeyStroke stroke, Edge edge, Runnable task)
|
|
||||||
{
|
|
||||||
keybindings.bindKey(stroke, edge, task);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public final void unbindKey(KeyStroke stroke)
|
|
||||||
{
|
|
||||||
keybindings.unbindKey(stroke);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public final boolean isVisible()
|
|
||||||
{
|
|
||||||
return visible;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setVisible(boolean visible)
|
|
||||||
{
|
|
||||||
if (visible != this.visible) {
|
|
||||||
this.visible = visible;
|
|
||||||
root.setVisible(visible);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setEnabled(boolean yes)
|
|
||||||
{
|
|
||||||
if (enabled != yes) {
|
|
||||||
this.enabled = yes;
|
|
||||||
root.setEnabled(yes);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isEnabled()
|
|
||||||
{
|
|
||||||
return enabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get rendering layer
|
|
||||||
*
|
|
||||||
* @return higher = on top.
|
|
||||||
*/
|
|
||||||
@DefaultImpl
|
|
||||||
public abstract int getZIndex();
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get event bus listening priority - useful to block incoming events.
|
|
||||||
*
|
|
||||||
* @return higher = first.
|
|
||||||
*/
|
|
||||||
public int getEventPriority()
|
|
||||||
{
|
|
||||||
return getZIndex();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Render the overlay. The caller MUST check for visibility himself.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void render()
|
|
||||||
{
|
|
||||||
if (!isVisible()) return;
|
|
||||||
|
|
||||||
Color.pushAlpha(alphaMul);
|
|
||||||
for (final Renderable r : rendered) {
|
|
||||||
r.render();
|
|
||||||
}
|
|
||||||
|
|
||||||
Color.popAlpha();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void update(double delta)
|
|
||||||
{
|
|
||||||
if (!isEnabled()) return;
|
|
||||||
|
|
||||||
for (final Updateable u : updated) {
|
|
||||||
u.update(delta);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int compareTo(Overlay o)
|
|
||||||
{
|
|
||||||
return o.getEventPriority() - getEventPriority();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>
|
|
||||||
* Screen size changed.
|
|
||||||
* </p>
|
|
||||||
* <p>
|
|
||||||
* Layouts / components should listen for this event and update their cached
|
|
||||||
* constraints; components added to root or directly to this overlay as
|
|
||||||
* child clients will receive the event.
|
|
||||||
* </p>
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
@DefaultImpl
|
|
||||||
public void onLayoutChanged()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void setAlpha(Num alpha)
|
|
||||||
{
|
|
||||||
this.alphaMul = alpha;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void setAlpha(double alpha)
|
|
||||||
{
|
|
||||||
this.alphaMul = Num.make(alpha);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void show()
|
|
||||||
{
|
|
||||||
setVisible(true);
|
|
||||||
setEnabled(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void hide()
|
|
||||||
{
|
|
||||||
setVisible(false);
|
|
||||||
setEnabled(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isListening()
|
|
||||||
{
|
|
||||||
return (isVisible() || isEnabled());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean doesDelegate()
|
|
||||||
{
|
|
||||||
return isListening();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,160 +0,0 @@
|
|||||||
package mightypork.gamecore.gui.screens;
|
|
||||||
|
|
||||||
|
|
||||||
import mightypork.gamecore.core.modules.AppAccess;
|
|
||||||
import mightypork.gamecore.core.modules.AppSubModule;
|
|
||||||
import mightypork.gamecore.gui.events.LayoutChangeEvent;
|
|
||||||
import mightypork.gamecore.gui.events.LayoutChangeListener;
|
|
||||||
import mightypork.gamecore.input.KeyBinder;
|
|
||||||
import mightypork.gamecore.input.KeyBindingPool;
|
|
||||||
import mightypork.gamecore.input.KeyStroke;
|
|
||||||
import mightypork.gamecore.input.KeyStroke.Edge;
|
|
||||||
import mightypork.gamecore.render.DisplaySystem;
|
|
||||||
import mightypork.gamecore.render.Render;
|
|
||||||
import mightypork.gamecore.render.Renderable;
|
|
||||||
import mightypork.utils.annotations.DefaultImpl;
|
|
||||||
import mightypork.utils.math.constraints.rect.Rect;
|
|
||||||
import mightypork.utils.math.constraints.rect.RectBound;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Screen class.
|
|
||||||
*
|
|
||||||
* @author Ondřej Hruška (MightyPork)
|
|
||||||
*/
|
|
||||||
public abstract class Screen extends AppSubModule implements Renderable, RectBound, KeyBinder, LayoutChangeListener {
|
|
||||||
|
|
||||||
private final KeyBindingPool keybindings = new KeyBindingPool();
|
|
||||||
|
|
||||||
private volatile boolean active;
|
|
||||||
private volatile boolean needSetupViewport = false;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param app app access
|
|
||||||
*/
|
|
||||||
public Screen(AppAccess app)
|
|
||||||
{
|
|
||||||
super(app);
|
|
||||||
|
|
||||||
// disable events initially
|
|
||||||
setListening(false);
|
|
||||||
|
|
||||||
addChildClient(keybindings);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private void fireLayoutChangeEvent()
|
|
||||||
{
|
|
||||||
getEventBus().sendDirectToChildren(this, new LayoutChangeEvent());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public final void bindKey(KeyStroke stroke, Edge edge, Runnable task)
|
|
||||||
{
|
|
||||||
keybindings.bindKey(stroke, edge, task);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public final void unbindKey(KeyStroke stroke)
|
|
||||||
{
|
|
||||||
keybindings.unbindKey(stroke);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Prepare for being shown
|
|
||||||
*
|
|
||||||
* @param shown true to show, false to hide
|
|
||||||
*/
|
|
||||||
public final void setActive(boolean shown)
|
|
||||||
{
|
|
||||||
if (shown) {
|
|
||||||
active = true;
|
|
||||||
needSetupViewport = true;
|
|
||||||
|
|
||||||
fireLayoutChangeEvent();
|
|
||||||
onScreenEnter();
|
|
||||||
|
|
||||||
// enable events
|
|
||||||
setListening(true);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
onScreenLeave();
|
|
||||||
|
|
||||||
active = false;
|
|
||||||
|
|
||||||
// disable events
|
|
||||||
setListening(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return true if screen is the current screen
|
|
||||||
*/
|
|
||||||
public final boolean isActive()
|
|
||||||
{
|
|
||||||
return active;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onLayoutChanged()
|
|
||||||
{
|
|
||||||
if (!isActive()) return;
|
|
||||||
|
|
||||||
needSetupViewport = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public final Rect getRect()
|
|
||||||
{
|
|
||||||
return getDisplay().getRect();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void render()
|
|
||||||
{
|
|
||||||
if (!isActive()) return;
|
|
||||||
|
|
||||||
if (needSetupViewport) {
|
|
||||||
Render.setupOrtho(DisplaySystem.getSize());
|
|
||||||
}
|
|
||||||
|
|
||||||
Render.pushState();
|
|
||||||
|
|
||||||
renderScreen();
|
|
||||||
|
|
||||||
Render.popState();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called when the screen becomes active
|
|
||||||
*/
|
|
||||||
@DefaultImpl
|
|
||||||
protected void onScreenEnter()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called when the screen is no longer active
|
|
||||||
*/
|
|
||||||
@DefaultImpl
|
|
||||||
protected void onScreenLeave()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Render screen contents (context is ready for 2D rendering)
|
|
||||||
*/
|
|
||||||
protected abstract void renderScreen();
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,53 +0,0 @@
|
|||||||
package mightypork.gamecore.gui.screens;
|
|
||||||
|
|
||||||
|
|
||||||
import mightypork.utils.annotations.DefaultImpl;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Screen display layer
|
|
||||||
*
|
|
||||||
* @author Ondřej Hruška (MightyPork)
|
|
||||||
*/
|
|
||||||
public abstract class ScreenLayer extends Overlay {
|
|
||||||
|
|
||||||
private final Screen screen;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param screen parent screen
|
|
||||||
*/
|
|
||||||
public ScreenLayer(Screen screen)
|
|
||||||
{
|
|
||||||
super(screen); // screen as AppAccess
|
|
||||||
|
|
||||||
this.screen = screen;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return parent screen instance
|
|
||||||
*/
|
|
||||||
protected final Screen getScreen()
|
|
||||||
{
|
|
||||||
return screen;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called when the screen becomes active
|
|
||||||
*/
|
|
||||||
@DefaultImpl
|
|
||||||
protected void onScreenEnter()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called when the screen is no longer active
|
|
||||||
*/
|
|
||||||
@DefaultImpl
|
|
||||||
protected void onScreenLeave()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,124 +0,0 @@
|
|||||||
package mightypork.gamecore.gui.screens;
|
|
||||||
|
|
||||||
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.TreeSet;
|
|
||||||
|
|
||||||
import mightypork.gamecore.core.modules.AppAccess;
|
|
||||||
import mightypork.gamecore.core.modules.AppModule;
|
|
||||||
import mightypork.gamecore.gui.events.LayoutChangeEvent;
|
|
||||||
import mightypork.gamecore.gui.events.ScreenRequestListener;
|
|
||||||
import mightypork.gamecore.render.Renderable;
|
|
||||||
import mightypork.gamecore.render.events.ViewportChangeEvent;
|
|
||||||
import mightypork.gamecore.render.events.ViewportChangeListener;
|
|
||||||
import mightypork.utils.annotations.DefaultImpl;
|
|
||||||
import mightypork.utils.logging.Log;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Game screens holder; Takes care of rendering and screen requests.
|
|
||||||
*
|
|
||||||
* @author Ondřej Hruška (MightyPork)
|
|
||||||
*/
|
|
||||||
public class ScreenRegistry extends AppModule implements ScreenRequestListener, ViewportChangeListener, Renderable {
|
|
||||||
|
|
||||||
private final Map<String, Screen> screens = new HashMap<>();
|
|
||||||
private final Collection<Overlay> overlays = new TreeSet<>();
|
|
||||||
private volatile Screen active = null;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param app app access
|
|
||||||
*/
|
|
||||||
public ScreenRegistry(AppAccess app)
|
|
||||||
{
|
|
||||||
super(app);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add a screen
|
|
||||||
*
|
|
||||||
* @param name screen key for calling
|
|
||||||
* @param screen added screen
|
|
||||||
*/
|
|
||||||
public void addScreen(String name, Screen screen)
|
|
||||||
{
|
|
||||||
screens.put(name, screen);
|
|
||||||
addChildClient(screen);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add an overlay
|
|
||||||
*
|
|
||||||
* @param overlay added overlay
|
|
||||||
*/
|
|
||||||
public void addOverlay(Overlay overlay)
|
|
||||||
{
|
|
||||||
overlays.add(overlay);
|
|
||||||
addChildClient(overlay);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void showScreen(String key)
|
|
||||||
{
|
|
||||||
Log.f3("Request to show screen \"" + key + "\"");
|
|
||||||
|
|
||||||
// find screen to show
|
|
||||||
final Screen toShow = screens.get(key);
|
|
||||||
if (toShow == null) {
|
|
||||||
throw new RuntimeException("Screen " + key + " not defined.");
|
|
||||||
}
|
|
||||||
|
|
||||||
// deactivate last screen
|
|
||||||
if (active != null) {
|
|
||||||
active.setActive(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
// activate new screen
|
|
||||||
toShow.setActive(true);
|
|
||||||
|
|
||||||
active = toShow;
|
|
||||||
|
|
||||||
fireLayoutUpdateEvent();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void render()
|
|
||||||
{
|
|
||||||
if (active != null) {
|
|
||||||
active.render();
|
|
||||||
|
|
||||||
for (final Overlay overlay : overlays) {
|
|
||||||
if (overlay.isVisible()) overlay.render();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@DefaultImpl
|
|
||||||
protected void deinit()
|
|
||||||
{
|
|
||||||
//
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onViewportChanged(ViewportChangeEvent event)
|
|
||||||
{
|
|
||||||
if (active != null) fireLayoutUpdateEvent();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private void fireLayoutUpdateEvent()
|
|
||||||
{
|
|
||||||
getEventBus().sendDirectToChildren(this, new LayoutChangeEvent());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,87 +0,0 @@
|
|||||||
package mightypork.gamecore.gui.screens.impl;
|
|
||||||
|
|
||||||
|
|
||||||
import mightypork.gamecore.core.events.ShudownRequest;
|
|
||||||
import mightypork.gamecore.core.modules.AppAccess;
|
|
||||||
import mightypork.gamecore.gui.components.painters.QuadPainter;
|
|
||||||
import mightypork.gamecore.gui.events.ScreenRequest;
|
|
||||||
import mightypork.gamecore.gui.screens.Overlay;
|
|
||||||
import mightypork.utils.math.animation.Easing;
|
|
||||||
import mightypork.utils.math.animation.NumAnimated;
|
|
||||||
import mightypork.utils.math.color.pal.RGB;
|
|
||||||
import mightypork.utils.math.timing.TimedTask;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Overlay used for cross-fading between screens
|
|
||||||
*
|
|
||||||
* @author Ondřej Hruška (MightyPork)
|
|
||||||
*/
|
|
||||||
public class CrossfadeOverlay extends Overlay {
|
|
||||||
|
|
||||||
private static final double T_IN = 0.4;
|
|
||||||
private static final double T_OUT = 0.6;
|
|
||||||
|
|
||||||
NumAnimated alpha = new NumAnimated(0);
|
|
||||||
String requestedScreenName;
|
|
||||||
|
|
||||||
TimedTask revealTask = new TimedTask() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void run()
|
|
||||||
{
|
|
||||||
if (requestedScreenName == null) {
|
|
||||||
getEventBus().send(new ShudownRequest());
|
|
||||||
} else {
|
|
||||||
getEventBus().send(new ScreenRequest(requestedScreenName));
|
|
||||||
}
|
|
||||||
alpha.setEasing(Easing.SINE_OUT);
|
|
||||||
alpha.fadeOut(T_OUT);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
public CrossfadeOverlay(AppAccess app)
|
|
||||||
{
|
|
||||||
super(app);
|
|
||||||
|
|
||||||
final QuadPainter qp = new QuadPainter(RGB.BLACK); // TODO allow custom colors
|
|
||||||
qp.setRect(root);
|
|
||||||
root.add(qp);
|
|
||||||
|
|
||||||
updated.add(alpha);
|
|
||||||
updated.add(revealTask);
|
|
||||||
|
|
||||||
setAlpha(alpha);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getZIndex()
|
|
||||||
{
|
|
||||||
return 10000; // not too high, so app can put something on top
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void goToScreen(String screen, boolean fromDark)
|
|
||||||
{
|
|
||||||
requestedScreenName = screen;
|
|
||||||
|
|
||||||
if (screen == null) {
|
|
||||||
// going for halt
|
|
||||||
getSoundSystem().fadeOutAllLoops();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fromDark) {
|
|
||||||
alpha.setTo(1);
|
|
||||||
revealTask.run();
|
|
||||||
} else {
|
|
||||||
revealTask.start(T_IN);
|
|
||||||
|
|
||||||
alpha.setEasing(Easing.SINE_IN);
|
|
||||||
alpha.fadeIn(T_IN);
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
package mightypork.gamecore.gui.screens.impl;
|
|
||||||
|
|
||||||
|
|
||||||
import mightypork.utils.eventbus.BusEvent;
|
|
||||||
import mightypork.utils.eventbus.events.flags.SingleReceiverEvent;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Ondřej Hruška (MightyPork)
|
|
||||||
*/
|
|
||||||
@SingleReceiverEvent
|
|
||||||
public class CrossfadeRequest extends BusEvent<CrossfadeOverlay> {
|
|
||||||
|
|
||||||
private final String screen;
|
|
||||||
private final boolean fromDark;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param screen screen key to show. Null = exit the app.
|
|
||||||
* @param fromDark true to fade from full black (ie. start of the game)
|
|
||||||
*/
|
|
||||||
public CrossfadeRequest(String screen, boolean fromDark)
|
|
||||||
{
|
|
||||||
super();
|
|
||||||
this.screen = screen;
|
|
||||||
this.fromDark = fromDark;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param screen screen key to show. Null = exit the app.
|
|
||||||
*/
|
|
||||||
public CrossfadeRequest(String screen)
|
|
||||||
{
|
|
||||||
super();
|
|
||||||
this.screen = screen;
|
|
||||||
this.fromDark = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void handleBy(CrossfadeOverlay handler)
|
|
||||||
{
|
|
||||||
handler.goToScreen(screen, fromDark);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,153 +0,0 @@
|
|||||||
package mightypork.gamecore.gui.screens.impl;
|
|
||||||
|
|
||||||
|
|
||||||
import mightypork.gamecore.gui.screens.Screen;
|
|
||||||
import mightypork.gamecore.gui.screens.ScreenLayer;
|
|
||||||
import mightypork.utils.annotations.DefaultImpl;
|
|
||||||
import mightypork.utils.math.animation.Easing;
|
|
||||||
import mightypork.utils.math.animation.NumAnimated;
|
|
||||||
import mightypork.utils.math.timing.TimedTask;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Layer that smoothly appears/disappears when shown/hidden
|
|
||||||
*
|
|
||||||
* @author Ondřej Hruška (MightyPork)
|
|
||||||
*/
|
|
||||||
public abstract class FadingLayer extends ScreenLayer {
|
|
||||||
|
|
||||||
private final NumAnimated numa;
|
|
||||||
private final TimedTask hideTimer = new TimedTask() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void run()
|
|
||||||
{
|
|
||||||
FadingLayer.super.hide();
|
|
||||||
fadingOut = false;
|
|
||||||
onHideFinished();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
private final TimedTask showTimer = new TimedTask() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void run()
|
|
||||||
{
|
|
||||||
fadingIn = false;
|
|
||||||
onShowFinished();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
private boolean fadingIn = false;
|
|
||||||
private boolean fadingOut = false;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create with default fading time and effect
|
|
||||||
*
|
|
||||||
* @param screen
|
|
||||||
*/
|
|
||||||
public FadingLayer(Screen screen)
|
|
||||||
{
|
|
||||||
this(screen, new NumAnimated(1, Easing.QUADRATIC_OUT, 0.3));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param screen
|
|
||||||
* @param easingAnim the animation num
|
|
||||||
*/
|
|
||||||
public FadingLayer(Screen screen, NumAnimated easingAnim)
|
|
||||||
{
|
|
||||||
super(screen);
|
|
||||||
|
|
||||||
numa = easingAnim;
|
|
||||||
|
|
||||||
updated.add(numa);
|
|
||||||
updated.add(hideTimer);
|
|
||||||
updated.add(showTimer);
|
|
||||||
|
|
||||||
setAlpha(numa);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called after the fade-out was completed
|
|
||||||
*/
|
|
||||||
@DefaultImpl
|
|
||||||
protected void onHideFinished()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called after the fade-in was completed
|
|
||||||
*/
|
|
||||||
@DefaultImpl
|
|
||||||
protected void onShowFinished()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Show with fading
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void show()
|
|
||||||
{
|
|
||||||
if (fadingIn) return;
|
|
||||||
|
|
||||||
if (!isVisible() || fadingOut) {
|
|
||||||
super.show();
|
|
||||||
numa.fadeIn();
|
|
||||||
hideTimer.stop();
|
|
||||||
showTimer.start(numa.getDefaultDuration());
|
|
||||||
|
|
||||||
fadingOut = false;
|
|
||||||
fadingIn = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Hide without fading
|
|
||||||
*/
|
|
||||||
public void hideImmediate()
|
|
||||||
{
|
|
||||||
hideTimer.stop();
|
|
||||||
numa.setTo(0);
|
|
||||||
super.hide();
|
|
||||||
onHideFinished();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Show without fading
|
|
||||||
*/
|
|
||||||
public void showImmediate()
|
|
||||||
{
|
|
||||||
hideTimer.stop();
|
|
||||||
numa.setTo(1);
|
|
||||||
super.show();
|
|
||||||
onShowFinished();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Hide with fading
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void hide()
|
|
||||||
{
|
|
||||||
if (fadingOut) return;
|
|
||||||
|
|
||||||
if (isVisible()) {
|
|
||||||
numa.fadeOut();
|
|
||||||
hideTimer.start(numa.getDefaultDuration());
|
|
||||||
|
|
||||||
fadingOut = true;
|
|
||||||
fadingIn = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
package mightypork.gamecore.gui.screens.impl;
|
|
||||||
|
|
||||||
|
|
||||||
import mightypork.gamecore.gui.components.painters.QuadPainter;
|
|
||||||
import mightypork.gamecore.gui.screens.Screen;
|
|
||||||
import mightypork.gamecore.gui.screens.ScreenLayer;
|
|
||||||
import mightypork.utils.math.color.Color;
|
|
||||||
|
|
||||||
|
|
||||||
public class LayerColor extends ScreenLayer {
|
|
||||||
|
|
||||||
private final int zIndex;
|
|
||||||
|
|
||||||
|
|
||||||
public LayerColor(Screen screen, Color color, int zIndex)
|
|
||||||
{
|
|
||||||
super(screen);
|
|
||||||
|
|
||||||
final QuadPainter qp = new QuadPainter(color);
|
|
||||||
qp.setRect(root);
|
|
||||||
root.add(qp);
|
|
||||||
this.zIndex = zIndex;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getZIndex()
|
|
||||||
{
|
|
||||||
return this.zIndex;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,267 +0,0 @@
|
|||||||
package mightypork.gamecore.input;
|
|
||||||
|
|
||||||
|
|
||||||
import mightypork.gamecore.core.events.UserQuitRequest;
|
|
||||||
import mightypork.gamecore.core.modules.AppAccess;
|
|
||||||
import mightypork.gamecore.input.KeyStroke.Edge;
|
|
||||||
import mightypork.gamecore.input.events.InputReadyEvent;
|
|
||||||
import mightypork.gamecore.input.events.KeyEvent;
|
|
||||||
import mightypork.gamecore.input.events.MouseButtonEvent;
|
|
||||||
import mightypork.gamecore.input.events.MouseMotionEvent;
|
|
||||||
import mightypork.utils.eventbus.clients.RootBusNode;
|
|
||||||
import mightypork.utils.interfaces.Updateable;
|
|
||||||
import mightypork.utils.math.constraints.vect.Vect;
|
|
||||||
import mightypork.utils.math.constraints.vect.var.VectVar;
|
|
||||||
|
|
||||||
import org.lwjgl.LWJGLException;
|
|
||||||
import org.lwjgl.input.Keyboard;
|
|
||||||
import org.lwjgl.input.Mouse;
|
|
||||||
import org.lwjgl.opengl.Display;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Input system
|
|
||||||
*
|
|
||||||
* @author Ondřej Hruška (MightyPork)
|
|
||||||
*/
|
|
||||||
public class InputSystem extends RootBusNode implements Updateable, KeyBinder {
|
|
||||||
|
|
||||||
private static boolean inited = false;
|
|
||||||
|
|
||||||
/** Current mouse position */
|
|
||||||
private static final Vect mousePos = new Vect() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public double x()
|
|
||||||
{
|
|
||||||
if (!Mouse.isInsideWindow()) return Integer.MIN_VALUE;
|
|
||||||
|
|
||||||
return Mouse.getX();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public double y()
|
|
||||||
{
|
|
||||||
if (!Mouse.isInsideWindow()) return Integer.MIN_VALUE;
|
|
||||||
// flip Y axis
|
|
||||||
return Display.getHeight() - Mouse.getY();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
private final KeyBindingPool keybindings;
|
|
||||||
|
|
||||||
private final VectVar mouseMove = Vect.makeVar();
|
|
||||||
private final VectVar mouseLastPos = Vect.makeVar();
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param app app access
|
|
||||||
*/
|
|
||||||
public InputSystem(AppAccess app)
|
|
||||||
{
|
|
||||||
super(app);
|
|
||||||
|
|
||||||
initDevices();
|
|
||||||
|
|
||||||
// global keybindings
|
|
||||||
keybindings = new KeyBindingPool();
|
|
||||||
addChildClient(keybindings);
|
|
||||||
|
|
||||||
getEventBus().send(new InputReadyEvent());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public final void deinit()
|
|
||||||
{
|
|
||||||
Mouse.destroy();
|
|
||||||
Keyboard.destroy();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private void initDevices()
|
|
||||||
{
|
|
||||||
if (inited) return;
|
|
||||||
inited = true;
|
|
||||||
|
|
||||||
try {
|
|
||||||
Mouse.create();
|
|
||||||
Keyboard.create();
|
|
||||||
Keyboard.enableRepeatEvents(false);
|
|
||||||
} catch (final LWJGLException e) {
|
|
||||||
throw new RuntimeException("Failed to initialize input devices.", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public final void bindKey(KeyStroke stroke, Edge edge, Runnable task)
|
|
||||||
{
|
|
||||||
keybindings.bindKey(stroke, edge, task);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void unbindKey(KeyStroke stroke)
|
|
||||||
{
|
|
||||||
keybindings.unbindKey(stroke);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public synchronized void update(double delta)
|
|
||||||
{
|
|
||||||
// was destroyed or not initialized
|
|
||||||
if (!Display.isCreated()) return;
|
|
||||||
if (!Mouse.isCreated()) return;
|
|
||||||
if (!Keyboard.isCreated()) return;
|
|
||||||
|
|
||||||
Display.processMessages();
|
|
||||||
|
|
||||||
// sum the moves
|
|
||||||
mouseMove.reset();
|
|
||||||
mouseLastPos.reset();
|
|
||||||
boolean wasMouse = false;
|
|
||||||
while (Mouse.next()) {
|
|
||||||
onMouseEvent(mouseMove, mouseLastPos);
|
|
||||||
wasMouse = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (wasMouse && !mouseMove.isZero()) {
|
|
||||||
getEventBus().send(new MouseMotionEvent(mouseLastPos, mouseMove));
|
|
||||||
}
|
|
||||||
|
|
||||||
while (Keyboard.next()) {
|
|
||||||
onKeyEvent();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Display.isCloseRequested()) {
|
|
||||||
getEventBus().send(new UserQuitRequest());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private void onMouseEvent(VectVar moveSum, VectVar lastPos)
|
|
||||||
{
|
|
||||||
final int button = Mouse.getEventButton();
|
|
||||||
final boolean down = Mouse.getEventButtonState();
|
|
||||||
|
|
||||||
final VectVar pos = Vect.makeVar(Mouse.getEventX(), Mouse.getEventY());
|
|
||||||
final VectVar move = Vect.makeVar(Mouse.getEventDX(), Mouse.getEventDY());
|
|
||||||
|
|
||||||
final int wheeld = Mouse.getEventDWheel();
|
|
||||||
|
|
||||||
// flip Y axis
|
|
||||||
pos.setY(Display.getHeight() - pos.y());
|
|
||||||
|
|
||||||
if (button != -1 || wheeld != 0) {
|
|
||||||
getEventBus().send(new MouseButtonEvent(pos.freeze(), button, down, wheeld));
|
|
||||||
}
|
|
||||||
|
|
||||||
moveSum.setTo(moveSum.add(move));
|
|
||||||
lastPos.setTo(pos);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private void onKeyEvent()
|
|
||||||
{
|
|
||||||
final int key = Keyboard.getEventKey();
|
|
||||||
final boolean down = Keyboard.getEventKeyState();
|
|
||||||
final char c = Keyboard.getEventCharacter();
|
|
||||||
|
|
||||||
getEventBus().send(new KeyEvent(key, c, down));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get absolute mouse position. This vect is final and views at it can
|
|
||||||
* safely be made.
|
|
||||||
*
|
|
||||||
* @return mouse position
|
|
||||||
*/
|
|
||||||
public static Vect getMousePos()
|
|
||||||
{
|
|
||||||
return mousePos;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return true if mouse is inside window.
|
|
||||||
*/
|
|
||||||
public static boolean isMouseInside()
|
|
||||||
{
|
|
||||||
return Mouse.isInsideWindow();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Trap mouse cursor in the window
|
|
||||||
*
|
|
||||||
* @param grab true to grab
|
|
||||||
*/
|
|
||||||
public static void grabMouse(boolean grab)
|
|
||||||
{
|
|
||||||
Mouse.setGrabbed(grab);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if key is down
|
|
||||||
*
|
|
||||||
* @param key key to check (constant from the {@link Keys} class)
|
|
||||||
* @return is down
|
|
||||||
*/
|
|
||||||
public static boolean isKeyDown(int key)
|
|
||||||
{
|
|
||||||
return Keyboard.isKeyDown(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check mouse button state
|
|
||||||
*
|
|
||||||
* @param button button to test (0 left, 1 right, 2 middle)
|
|
||||||
* @return button is down
|
|
||||||
*/
|
|
||||||
public static boolean isMouseButtonDown(int button)
|
|
||||||
{
|
|
||||||
return Mouse.isButtonDown(button);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return bit mask of active mod keys
|
|
||||||
*/
|
|
||||||
public static int getActiveModKeys()
|
|
||||||
{
|
|
||||||
int mods = 0;
|
|
||||||
|
|
||||||
if (Keyboard.isKeyDown(Keys.L_ALT) || Keyboard.isKeyDown(Keys.R_ALT)) {
|
|
||||||
mods |= Keys.MOD_ALT;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Keyboard.isKeyDown(Keys.L_SHIFT) || Keyboard.isKeyDown(Keys.R_SHIFT)) {
|
|
||||||
mods |= Keys.MOD_SHIFT;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Keyboard.isKeyDown(Keys.L_CONTROL) || Keyboard.isKeyDown(Keys.R_CONTROL)) {
|
|
||||||
mods |= Keys.MOD_CONTROL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Keyboard.isKeyDown(Keys.L_META) || Keyboard.isKeyDown(Keys.R_META)) {
|
|
||||||
mods |= Keys.MOD_META;
|
|
||||||
}
|
|
||||||
|
|
||||||
return mods;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return true if the system is initialized
|
|
||||||
*/
|
|
||||||
public static boolean isReady()
|
|
||||||
{
|
|
||||||
return inited;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
package mightypork.gamecore.input;
|
|
||||||
|
|
||||||
|
|
||||||
import mightypork.gamecore.gui.Action;
|
|
||||||
import mightypork.gamecore.input.KeyStroke.Edge;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Can bind events to keys.
|
|
||||||
*
|
|
||||||
* @author Ondřej Hruška (MightyPork)
|
|
||||||
*/
|
|
||||||
public interface KeyBinder {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Bind handler to a keystroke, replace current handler if any
|
|
||||||
*
|
|
||||||
* @param edge trigger edge
|
|
||||||
* @param stroke trigger keystroke
|
|
||||||
* @param task handler; can be {@link Runnable} or {@link Action}
|
|
||||||
*/
|
|
||||||
void bindKey(KeyStroke stroke, Edge edge, Runnable task);
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove handler from a keystroke (id any)
|
|
||||||
*
|
|
||||||
* @param stroke stroke
|
|
||||||
*/
|
|
||||||
void unbindKey(KeyStroke stroke);
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,82 +0,0 @@
|
|||||||
package mightypork.gamecore.input;
|
|
||||||
|
|
||||||
|
|
||||||
import mightypork.gamecore.input.KeyStroke.Edge;
|
|
||||||
import mightypork.gamecore.input.events.InputReadyListener;
|
|
||||||
import mightypork.gamecore.input.events.KeyEvent;
|
|
||||||
import mightypork.gamecore.input.events.KeyEventHandler;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Key binding, trigger activated by a keystroke event
|
|
||||||
*
|
|
||||||
* @author Ondřej Hruška (MightyPork)
|
|
||||||
*/
|
|
||||||
public class KeyBinding implements KeyEventHandler, InputReadyListener {
|
|
||||||
|
|
||||||
private final KeyStroke keystroke;
|
|
||||||
private Runnable handler;
|
|
||||||
private final Edge edge;
|
|
||||||
private boolean wasDown = false;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param edge trigger edge
|
|
||||||
* @param stroke trigger keystroke
|
|
||||||
* @param handler action
|
|
||||||
*/
|
|
||||||
public KeyBinding(KeyStroke stroke, Edge edge, Runnable handler)
|
|
||||||
{
|
|
||||||
this.keystroke = stroke;
|
|
||||||
this.handler = handler;
|
|
||||||
this.edge = edge;
|
|
||||||
|
|
||||||
if (InputSystem.isReady()) wasDown = stroke.isDown();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check for equality of keystroke
|
|
||||||
*
|
|
||||||
* @param stroke other keystroke
|
|
||||||
* @return true if keystrokes are equal (cannot co-exist)
|
|
||||||
*/
|
|
||||||
public boolean matches(KeyStroke stroke)
|
|
||||||
{
|
|
||||||
return this.keystroke.equals(stroke);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param handler event handler
|
|
||||||
*/
|
|
||||||
public void setHandler(Runnable handler)
|
|
||||||
{
|
|
||||||
this.handler = handler;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void receive(KeyEvent event)
|
|
||||||
{
|
|
||||||
final boolean nowDown = keystroke.isDown();
|
|
||||||
|
|
||||||
boolean trigger = false;
|
|
||||||
trigger |= (edge == Edge.FALLING && (!wasDown && nowDown));
|
|
||||||
trigger |= (edge == Edge.RISING && (wasDown && !nowDown));
|
|
||||||
wasDown = nowDown;
|
|
||||||
|
|
||||||
// run handler when event was met
|
|
||||||
if (trigger) {
|
|
||||||
handler.run();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onInputReady()
|
|
||||||
{
|
|
||||||
wasDown = keystroke.isDown();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,72 +0,0 @@
|
|||||||
package mightypork.gamecore.input;
|
|
||||||
|
|
||||||
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
import mightypork.gamecore.input.KeyStroke.Edge;
|
|
||||||
import mightypork.gamecore.input.events.KeyEvent;
|
|
||||||
import mightypork.gamecore.input.events.KeyEventHandler;
|
|
||||||
import mightypork.utils.logging.Log;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Key binding pool
|
|
||||||
*
|
|
||||||
* @author Ondřej Hruška (MightyPork)
|
|
||||||
*/
|
|
||||||
public class KeyBindingPool implements KeyBinder, KeyEventHandler {
|
|
||||||
|
|
||||||
private final Set<KeyBinding> bindings = new HashSet<>();
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Bind handler to a keystroke, replace current handler if any
|
|
||||||
*
|
|
||||||
* @param stroke trigger keystroke
|
|
||||||
* @param task handler
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void bindKey(KeyStroke stroke, Edge edge, Runnable task)
|
|
||||||
{
|
|
||||||
for (final KeyBinding kb : bindings) {
|
|
||||||
if (kb.matches(stroke)) {
|
|
||||||
Log.w("Duplicate KeyBinding (" + stroke + "), replacing handler.");
|
|
||||||
kb.setHandler(task);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bindings.add(new KeyBinding(stroke, edge, task));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove handler from keystroke (id any)
|
|
||||||
*
|
|
||||||
* @param stroke stroke
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void unbindKey(KeyStroke stroke)
|
|
||||||
{
|
|
||||||
final Iterator<KeyBinding> iter = bindings.iterator();
|
|
||||||
|
|
||||||
while (iter.hasNext()) {
|
|
||||||
final KeyBinding kb = iter.next();
|
|
||||||
if (kb.matches(stroke)) {
|
|
||||||
iter.remove();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void receive(KeyEvent event)
|
|
||||||
{
|
|
||||||
for (final KeyBinding kb : bindings) {
|
|
||||||
kb.receive(event);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,145 +0,0 @@
|
|||||||
package mightypork.gamecore.input;
|
|
||||||
|
|
||||||
|
|
||||||
import mightypork.utils.string.StringUtil;
|
|
||||||
|
|
||||||
import org.lwjgl.input.Keyboard;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Key stroke trigger
|
|
||||||
*
|
|
||||||
* @author Ondřej Hruška (MightyPork)
|
|
||||||
*/
|
|
||||||
public class KeyStroke { //implements Pollable
|
|
||||||
|
|
||||||
public static enum Edge
|
|
||||||
{
|
|
||||||
FALLING, RISING;
|
|
||||||
}
|
|
||||||
|
|
||||||
private int mod;
|
|
||||||
private int key;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* KeyStroke
|
|
||||||
*
|
|
||||||
* @param key key code
|
|
||||||
* @param mod_mask mods mask
|
|
||||||
*/
|
|
||||||
public KeyStroke(int key, int mod_mask)
|
|
||||||
{
|
|
||||||
setTo(key, mod_mask);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Rising edge keystroke
|
|
||||||
*
|
|
||||||
* @param key key code
|
|
||||||
*/
|
|
||||||
public KeyStroke(int key)
|
|
||||||
{
|
|
||||||
this(key, Keys.MOD_NONE);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return true if the keystroke is currently down & modifiers match.
|
|
||||||
*/
|
|
||||||
public boolean isDown()
|
|
||||||
{
|
|
||||||
boolean st = Keyboard.isKeyDown(key);
|
|
||||||
st &= (InputSystem.getActiveModKeys() == mod);
|
|
||||||
|
|
||||||
return st;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void setTo(int key, int mod_mask)
|
|
||||||
{
|
|
||||||
this.key = key;
|
|
||||||
this.mod = mod_mask | Keys.keyToMod(key); // for mods alone
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public String toDataString()
|
|
||||||
{
|
|
||||||
String s = "";
|
|
||||||
|
|
||||||
if (mod != Keys.MOD_NONE) s = Keys.modToString(mod);
|
|
||||||
|
|
||||||
s += Keys.keyToString(key);
|
|
||||||
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static KeyStroke createFromDataString(String dataString)
|
|
||||||
{
|
|
||||||
final KeyStroke ks = new KeyStroke(Keys.NONE, Keys.MOD_NONE);
|
|
||||||
ks.fromDataString(dataString);
|
|
||||||
return ks;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void fromDataString(String dataString)
|
|
||||||
{
|
|
||||||
final String dataString1 = dataString.toUpperCase().replace('-', '+').replaceAll("[^A-Z0-9_+]", "");
|
|
||||||
|
|
||||||
if (dataString1.contains("+")) {
|
|
||||||
|
|
||||||
final String keyStr = StringUtil.fromLastChar(dataString1, '+');
|
|
||||||
final String modStr = StringUtil.toLastChar(dataString1, '+');
|
|
||||||
|
|
||||||
setTo(Keys.keyFromString(keyStr), Keys.modFromString(modStr));
|
|
||||||
|
|
||||||
} else {
|
|
||||||
setTo(Keys.keyFromString(dataString1), Keys.MOD_NONE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public int getKey()
|
|
||||||
{
|
|
||||||
return key;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public int getMod()
|
|
||||||
{
|
|
||||||
return mod;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString()
|
|
||||||
{
|
|
||||||
return toDataString();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int hashCode()
|
|
||||||
{
|
|
||||||
final int prime = 31;
|
|
||||||
int result = 1;
|
|
||||||
result = prime * result + key;
|
|
||||||
result = prime * result + mod;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean equals(Object obj)
|
|
||||||
{
|
|
||||||
if (this == obj) return true;
|
|
||||||
if (obj == null) return false;
|
|
||||||
if (getClass() != obj.getClass()) return false;
|
|
||||||
final KeyStroke other = (KeyStroke) obj;
|
|
||||||
if (key != other.key) return false;
|
|
||||||
if (mod != other.mod) return false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,265 +0,0 @@
|
|||||||
package mightypork.gamecore.input;
|
|
||||||
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
|
|
||||||
import mightypork.utils.logging.Log;
|
|
||||||
|
|
||||||
import org.lwjgl.input.Keyboard;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Key constants, from LWJGL {@link Keyboard}
|
|
||||||
*
|
|
||||||
* @author Ondřej Hruška (MightyPork)
|
|
||||||
*/
|
|
||||||
public class Keys {
|
|
||||||
|
|
||||||
//@formatter:off
|
|
||||||
|
|
||||||
public static final int NONE = Keyboard.KEY_NONE;
|
|
||||||
|
|
||||||
public static final int ESCAPE = Keyboard.KEY_ESCAPE;
|
|
||||||
|
|
||||||
public static final int NUM_1 = Keyboard.KEY_1;
|
|
||||||
public static final int NUM_2 = Keyboard.KEY_2;
|
|
||||||
public static final int NUM_3 = Keyboard.KEY_3;
|
|
||||||
public static final int NUM_4 = Keyboard.KEY_4;
|
|
||||||
public static final int NUM_5 = Keyboard.KEY_5;
|
|
||||||
public static final int NUM_6 = Keyboard.KEY_6;
|
|
||||||
public static final int NUM_7 = Keyboard.KEY_7;
|
|
||||||
public static final int NUM_8 = Keyboard.KEY_8;
|
|
||||||
public static final int NUM_9 = Keyboard.KEY_9;
|
|
||||||
public static final int NUM_0 = Keyboard.KEY_0;
|
|
||||||
|
|
||||||
public static final int Q = Keyboard.KEY_Q;
|
|
||||||
public static final int W = Keyboard.KEY_W;
|
|
||||||
public static final int E = Keyboard.KEY_E;
|
|
||||||
public static final int R = Keyboard.KEY_R;
|
|
||||||
public static final int T = Keyboard.KEY_T;
|
|
||||||
public static final int Y = Keyboard.KEY_Y;
|
|
||||||
public static final int U = Keyboard.KEY_U;
|
|
||||||
public static final int I = Keyboard.KEY_I;
|
|
||||||
public static final int O = Keyboard.KEY_O;
|
|
||||||
public static final int P = Keyboard.KEY_P;
|
|
||||||
public static final int A = Keyboard.KEY_A;
|
|
||||||
public static final int S = Keyboard.KEY_S;
|
|
||||||
public static final int D = Keyboard.KEY_D;
|
|
||||||
public static final int F = Keyboard.KEY_F;
|
|
||||||
public static final int G = Keyboard.KEY_G;
|
|
||||||
public static final int H = Keyboard.KEY_H;
|
|
||||||
public static final int J = Keyboard.KEY_J;
|
|
||||||
public static final int K = Keyboard.KEY_K;
|
|
||||||
public static final int L = Keyboard.KEY_L;
|
|
||||||
public static final int Z = Keyboard.KEY_Z;
|
|
||||||
public static final int X = Keyboard.KEY_X;
|
|
||||||
public static final int C = Keyboard.KEY_C;
|
|
||||||
public static final int V = Keyboard.KEY_V;
|
|
||||||
public static final int B = Keyboard.KEY_B;
|
|
||||||
public static final int N = Keyboard.KEY_N;
|
|
||||||
public static final int M = Keyboard.KEY_M;
|
|
||||||
|
|
||||||
public static final int MINUS = Keyboard.KEY_MINUS;
|
|
||||||
public static final int EQUALS = Keyboard.KEY_EQUALS;
|
|
||||||
public static final int SLASH = Keyboard.KEY_SLASH;
|
|
||||||
public static final int BACKSLASH = Keyboard.KEY_BACKSLASH;
|
|
||||||
public static final int L_BRACKET = Keyboard.KEY_LBRACKET;
|
|
||||||
public static final int R_BRACKET = Keyboard.KEY_RBRACKET;
|
|
||||||
public static final int SEMICOLON = Keyboard.KEY_SEMICOLON;
|
|
||||||
public static final int APOSTROPHE = Keyboard.KEY_APOSTROPHE;
|
|
||||||
public static final int GRAVE = Keyboard.KEY_GRAVE;
|
|
||||||
public static final int COMMA = Keyboard.KEY_COMMA;
|
|
||||||
public static final int PERIOD = Keyboard.KEY_PERIOD;
|
|
||||||
|
|
||||||
public static final int SPACE = Keyboard.KEY_SPACE;
|
|
||||||
public static final int BACKSPACE = Keyboard.KEY_BACK;
|
|
||||||
public static final int TAB = Keyboard.KEY_TAB;
|
|
||||||
|
|
||||||
public static final int F1 = Keyboard.KEY_F1;
|
|
||||||
public static final int F2 = Keyboard.KEY_F2;
|
|
||||||
public static final int F3 = Keyboard.KEY_F3;
|
|
||||||
public static final int F4 = Keyboard.KEY_F4;
|
|
||||||
public static final int F5 = Keyboard.KEY_F5;
|
|
||||||
public static final int F6 = Keyboard.KEY_F6;
|
|
||||||
public static final int F7 = Keyboard.KEY_F7;
|
|
||||||
public static final int F8 = Keyboard.KEY_F8;
|
|
||||||
public static final int F9 = Keyboard.KEY_F9;
|
|
||||||
public static final int F10 = Keyboard.KEY_F10;
|
|
||||||
public static final int F11 = Keyboard.KEY_F11;
|
|
||||||
public static final int F12 = Keyboard.KEY_F12;
|
|
||||||
public static final int F13 = Keyboard.KEY_F13;
|
|
||||||
public static final int F14 = Keyboard.KEY_F14;
|
|
||||||
public static final int F15 = Keyboard.KEY_F15;
|
|
||||||
|
|
||||||
public static final int CAPS_LOCK = Keyboard.KEY_CAPITAL;
|
|
||||||
public static final int SCROLL_LOCK = Keyboard.KEY_SCROLL;
|
|
||||||
public static final int NUM_LOCK = Keyboard.KEY_NUMLOCK;
|
|
||||||
|
|
||||||
public static final int NUMPAD_MINUS = Keyboard.KEY_SUBTRACT;
|
|
||||||
public static final int NUMPAD_PLUSS = Keyboard.KEY_ADD;
|
|
||||||
public static final int NUMPAD_0 = Keyboard.KEY_NUMPAD0;
|
|
||||||
public static final int NUMPAD_1 = Keyboard.KEY_NUMPAD1;
|
|
||||||
public static final int NUMPAD_2 = Keyboard.KEY_NUMPAD2;
|
|
||||||
public static final int NUMPAD_3 = Keyboard.KEY_NUMPAD3;
|
|
||||||
public static final int NUMPAD_4 = Keyboard.KEY_NUMPAD4;
|
|
||||||
public static final int NUMPAD_5 = Keyboard.KEY_NUMPAD5;
|
|
||||||
public static final int NUMPAD_6 = Keyboard.KEY_NUMPAD6;
|
|
||||||
public static final int NUMPAD_7 = Keyboard.KEY_NUMPAD7;
|
|
||||||
public static final int NUMPAD_8 = Keyboard.KEY_NUMPAD8;
|
|
||||||
public static final int NUMPAD_9 = Keyboard.KEY_NUMPAD9;
|
|
||||||
public static final int NUMPAD_DECIMAL = Keyboard.KEY_DECIMAL;
|
|
||||||
public static final int NUMPAD_ENTER = Keyboard.KEY_NUMPADENTER;
|
|
||||||
public static final int NUMPAD_DIVIDE = Keyboard.KEY_DIVIDE;
|
|
||||||
public static final int NUMPAD_MULTIPLY = Keyboard.KEY_MULTIPLY;
|
|
||||||
|
|
||||||
public static final int L_CONTROL = Keyboard.KEY_LCONTROL;
|
|
||||||
public static final int R_CONTROL = Keyboard.KEY_RCONTROL;
|
|
||||||
public static final int L_ALT = Keyboard.KEY_LMENU;
|
|
||||||
public static final int R_ALT = Keyboard.KEY_RMENU;
|
|
||||||
public static final int L_SHIFT = Keyboard.KEY_LSHIFT;
|
|
||||||
public static final int R_SHIFT = Keyboard.KEY_RSHIFT;
|
|
||||||
public static final int L_META = Keyboard.KEY_LMETA;
|
|
||||||
public static final int R_META = Keyboard.KEY_RMETA;
|
|
||||||
|
|
||||||
public static final int UP = Keyboard.KEY_UP;
|
|
||||||
public static final int DOWN = Keyboard.KEY_DOWN;
|
|
||||||
public static final int LEFT = Keyboard.KEY_LEFT;
|
|
||||||
public static final int RIGHT = Keyboard.KEY_RIGHT;
|
|
||||||
|
|
||||||
public static final int HOME = Keyboard.KEY_HOME;
|
|
||||||
public static final int END = Keyboard.KEY_END;
|
|
||||||
|
|
||||||
public static final int PAGE_UP = Keyboard.KEY_PRIOR;
|
|
||||||
public static final int PAGE_DOWN = Keyboard.KEY_NEXT;
|
|
||||||
|
|
||||||
public static final int RETURN = Keyboard.KEY_RETURN;
|
|
||||||
public static final int PAUSE = Keyboard.KEY_PAUSE;
|
|
||||||
public static final int INSERT = Keyboard.KEY_INSERT;
|
|
||||||
public static final int DELETE = Keyboard.KEY_DELETE;
|
|
||||||
|
|
||||||
public static final byte MOD_NONE = 0;
|
|
||||||
public static final byte MOD_ALT = 1;
|
|
||||||
public static final byte MOD_CONTROL = 2;
|
|
||||||
public static final byte MOD_SHIFT = 4;
|
|
||||||
public static final byte MOD_META = 8;
|
|
||||||
//@formatter:on
|
|
||||||
|
|
||||||
private static HashMap<String, String> loadAliasMap = new HashMap<>();
|
|
||||||
private static HashMap<String, String> saveAliasMap = new HashMap<>();
|
|
||||||
|
|
||||||
static {
|
|
||||||
// init maps
|
|
||||||
loadAliasMap.put("ENTER", "RETURN");
|
|
||||||
loadAliasMap.put("PGDN", "NEXT");
|
|
||||||
loadAliasMap.put("PGUP", "PRIOR");
|
|
||||||
loadAliasMap.put("PAGE_DOWN", "NEXT");
|
|
||||||
loadAliasMap.put("PAGE_UP", "PRIOR");
|
|
||||||
loadAliasMap.put("SPACEBAR", "SPACE");
|
|
||||||
loadAliasMap.put("ESC", "ESCAPE");
|
|
||||||
loadAliasMap.put("NUMPAD_DIVIDE", "DIVIDE");
|
|
||||||
loadAliasMap.put("NUMPAD_MULTIPLY", "MULTIPLY");
|
|
||||||
loadAliasMap.put("NUMPAD_ADD", "ADD");
|
|
||||||
loadAliasMap.put("NUMPAD_SUBTRACT", "SUBTRACT");
|
|
||||||
loadAliasMap.put("CAPS_LOCK", "CAPITAL");
|
|
||||||
loadAliasMap.put("SCROLL_LOCK", "SROLL");
|
|
||||||
loadAliasMap.put("NUM_LOCK", "NUMLOCK");
|
|
||||||
loadAliasMap.put("BACKSPACE", "BACK");
|
|
||||||
|
|
||||||
saveAliasMap.put("RETURN", "ENTER");
|
|
||||||
saveAliasMap.put("ESCAPE", "ESC");
|
|
||||||
saveAliasMap.put("NEXT", "PGDN");
|
|
||||||
saveAliasMap.put("PRIOR", "PGUP");
|
|
||||||
saveAliasMap.put("DIVIDE", "NUMPAD_DIVIDE");
|
|
||||||
saveAliasMap.put("MULTIPLY", "NUMPAD_MULTIPLY");
|
|
||||||
saveAliasMap.put("ADD", "NUMPAD_ADD");
|
|
||||||
saveAliasMap.put("SUBTRACT", "NUMPAD_SUBTRACT");
|
|
||||||
saveAliasMap.put("CAPITAL", "CAPS_LOCK");
|
|
||||||
saveAliasMap.put("SROLL", "SCROLL_LOCK");
|
|
||||||
saveAliasMap.put("NUMLOCK", "NUM_LOCK");
|
|
||||||
saveAliasMap.put("BACK", "BACKSPACE");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static int keyFromString(String key)
|
|
||||||
{
|
|
||||||
String key1 = key;
|
|
||||||
if (loadAliasMap.containsKey(key1)) key1 = loadAliasMap.get(key1);
|
|
||||||
|
|
||||||
final int index = Keyboard.getKeyIndex(key1);
|
|
||||||
if (index == Keys.NONE && !key1.equals("NONE")) {
|
|
||||||
Log.w("Could not parse key: " + key + " (" + key1 + ")");
|
|
||||||
}
|
|
||||||
return index;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static int modFromString(String mod)
|
|
||||||
{
|
|
||||||
int mod_mask = Keys.MOD_NONE;
|
|
||||||
|
|
||||||
if (mod.contains("CTRL")) {
|
|
||||||
mod_mask |= Keys.MOD_CONTROL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mod.contains("ALT")) {
|
|
||||||
mod_mask |= Keys.MOD_ALT;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mod.contains("SHIFT")) {
|
|
||||||
mod_mask |= Keys.MOD_SHIFT;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mod.contains("META") || mod.contains("WIN")) {
|
|
||||||
mod_mask |= Keys.MOD_META;
|
|
||||||
}
|
|
||||||
|
|
||||||
return mod_mask;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static String modToString(int mod)
|
|
||||||
{
|
|
||||||
String s = "";
|
|
||||||
|
|
||||||
if ((mod & Keys.MOD_CONTROL) != 0) {
|
|
||||||
s += "CTRL+";
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((mod & Keys.MOD_ALT) != 0) {
|
|
||||||
s += "ALT+";
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((mod & Keys.MOD_SHIFT) != 0) {
|
|
||||||
s += "SHIFT+";
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((mod & Keys.MOD_META) != 0) {
|
|
||||||
s += "META+";
|
|
||||||
}
|
|
||||||
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static String keyToString(int key)
|
|
||||||
{
|
|
||||||
String s = Keyboard.getKeyName(key);
|
|
||||||
if (saveAliasMap.containsKey(s)) s = saveAliasMap.get(s);
|
|
||||||
if (s == null) {
|
|
||||||
Log.w("Could not stringify key: " + key);
|
|
||||||
s = "NONE";
|
|
||||||
}
|
|
||||||
return s.toUpperCase();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static int keyToMod(int key)
|
|
||||||
{
|
|
||||||
if (key == L_SHIFT || key == R_SHIFT) return MOD_SHIFT;
|
|
||||||
if (key == L_CONTROL || key == R_CONTROL) return MOD_CONTROL;
|
|
||||||
if (key == L_ALT || key == R_ALT) return MOD_ALT;
|
|
||||||
if (key == L_META || key == R_META) return MOD_META;
|
|
||||||
return MOD_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
package mightypork.gamecore.input.events;
|
|
||||||
|
|
||||||
|
|
||||||
import mightypork.utils.eventbus.BusEvent;
|
|
||||||
|
|
||||||
|
|
||||||
public class InputReadyEvent extends BusEvent<InputReadyListener> {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void handleBy(InputReadyListener handler)
|
|
||||||
{
|
|
||||||
handler.onInputReady();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
package mightypork.gamecore.input.events;
|
|
||||||
|
|
||||||
|
|
||||||
public interface InputReadyListener {
|
|
||||||
|
|
||||||
void onInputReady();
|
|
||||||
}
|
|
||||||
@@ -1,85 +0,0 @@
|
|||||||
package mightypork.gamecore.input.events;
|
|
||||||
|
|
||||||
|
|
||||||
import mightypork.utils.eventbus.BusEvent;
|
|
||||||
import mightypork.utils.eventbus.events.flags.NotLoggedEvent;
|
|
||||||
|
|
||||||
import org.lwjgl.input.Keyboard;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A keyboard event
|
|
||||||
*
|
|
||||||
* @author Ondřej Hruška (MightyPork)
|
|
||||||
*/
|
|
||||||
@NotLoggedEvent
|
|
||||||
public class KeyEvent extends BusEvent<KeyEventHandler> {
|
|
||||||
|
|
||||||
private final int key;
|
|
||||||
private final boolean down;
|
|
||||||
private final char c;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param key key that triggered the event. Can be KEY_NONE.
|
|
||||||
* @param c typed char (can be zero char)
|
|
||||||
* @param down true = pressed, false = released.
|
|
||||||
*/
|
|
||||||
public KeyEvent(int key, char c, boolean down)
|
|
||||||
{
|
|
||||||
this.key = key;
|
|
||||||
this.c = c;
|
|
||||||
this.down = down;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return key code (see {@link org.lwjgl.input.Keyboard})
|
|
||||||
*/
|
|
||||||
public int getKey()
|
|
||||||
{
|
|
||||||
return key;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return true if key was just pressed
|
|
||||||
*/
|
|
||||||
public boolean isDown()
|
|
||||||
{
|
|
||||||
return down;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return true if key was just released
|
|
||||||
*/
|
|
||||||
public boolean isUp()
|
|
||||||
{
|
|
||||||
return !down;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return event character (if any)
|
|
||||||
*/
|
|
||||||
public char getChar()
|
|
||||||
{
|
|
||||||
return c;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void handleBy(KeyEventHandler keh)
|
|
||||||
{
|
|
||||||
keh.receive(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString()
|
|
||||||
{
|
|
||||||
return Keyboard.getKeyName(key) + ":" + (down ? "DOWN" : "UP");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
package mightypork.gamecore.input.events;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@link KeyEvent} listener
|
|
||||||
*
|
|
||||||
* @author Ondřej Hruška (MightyPork)
|
|
||||||
*/
|
|
||||||
public interface KeyEventHandler {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handle an event
|
|
||||||
*
|
|
||||||
* @param event event
|
|
||||||
*/
|
|
||||||
void receive(KeyEvent event);
|
|
||||||
}
|
|
||||||
@@ -1,126 +0,0 @@
|
|||||||
package mightypork.gamecore.input.events;
|
|
||||||
|
|
||||||
|
|
||||||
import mightypork.utils.eventbus.BusEvent;
|
|
||||||
import mightypork.utils.eventbus.events.flags.NotLoggedEvent;
|
|
||||||
import mightypork.utils.math.constraints.rect.RectBound;
|
|
||||||
import mightypork.utils.math.constraints.vect.Vect;
|
|
||||||
import mightypork.utils.math.constraints.vect.VectConst;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Mouse button / wheel event triggered
|
|
||||||
*
|
|
||||||
* @author Ondřej Hruška (MightyPork)
|
|
||||||
*/
|
|
||||||
@NotLoggedEvent
|
|
||||||
public class MouseButtonEvent extends BusEvent<MouseButtonHandler> {
|
|
||||||
|
|
||||||
public static final int BUTTON_LEFT = 0;
|
|
||||||
public static final int BUTTON_MIDDLE = 1;
|
|
||||||
public static final int BUTTON_RIGHT = 2;
|
|
||||||
|
|
||||||
private final int button;
|
|
||||||
private final int wheeld;
|
|
||||||
private final VectConst pos;
|
|
||||||
private final boolean down;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Mouse button event
|
|
||||||
*
|
|
||||||
* @param pos event position
|
|
||||||
* @param button button id
|
|
||||||
* @param down button pressed
|
|
||||||
* @param wheeld wheel change
|
|
||||||
*/
|
|
||||||
public MouseButtonEvent(Vect pos, int button, boolean down, int wheeld)
|
|
||||||
{
|
|
||||||
this.button = button;
|
|
||||||
this.down = down;
|
|
||||||
this.pos = pos.freeze();
|
|
||||||
this.wheeld = wheeld;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return true if the event was caused by a button state change
|
|
||||||
*/
|
|
||||||
public boolean isButtonEvent()
|
|
||||||
{
|
|
||||||
return button != -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return true if the event was caused by a wheel change
|
|
||||||
*/
|
|
||||||
public boolean isWheelEvent()
|
|
||||||
{
|
|
||||||
return wheeld != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return button id or -1 if none was pressed
|
|
||||||
*/
|
|
||||||
public int getButton()
|
|
||||||
{
|
|
||||||
return button;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return number of steps the wheel changed since last event
|
|
||||||
*/
|
|
||||||
public int getWheelDelta()
|
|
||||||
{
|
|
||||||
return wheeld;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return mouse position when the event occurred
|
|
||||||
*/
|
|
||||||
public VectConst getPos()
|
|
||||||
{
|
|
||||||
return pos;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return true if button was just pressed
|
|
||||||
*/
|
|
||||||
public boolean isDown()
|
|
||||||
{
|
|
||||||
return button != -1 && down;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return true if button was just released
|
|
||||||
*/
|
|
||||||
public boolean isUp()
|
|
||||||
{
|
|
||||||
return button != -1 && !down;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get if event happened over a rect
|
|
||||||
*
|
|
||||||
* @param rect rect region
|
|
||||||
* @return was over
|
|
||||||
*/
|
|
||||||
public boolean isOver(RectBound rect)
|
|
||||||
{
|
|
||||||
return rect.getRect().contains(pos);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void handleBy(MouseButtonHandler handler)
|
|
||||||
{
|
|
||||||
handler.receive(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
package mightypork.gamecore.input.events;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@link MouseButtonEvent} listener
|
|
||||||
*
|
|
||||||
* @author Ondřej Hruška (MightyPork)
|
|
||||||
*/
|
|
||||||
public interface MouseButtonHandler {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handle an event
|
|
||||||
*
|
|
||||||
* @param event event
|
|
||||||
*/
|
|
||||||
void receive(MouseButtonEvent event);
|
|
||||||
}
|
|
||||||
@@ -1,57 +0,0 @@
|
|||||||
package mightypork.gamecore.input.events;
|
|
||||||
|
|
||||||
|
|
||||||
import mightypork.utils.eventbus.BusEvent;
|
|
||||||
import mightypork.utils.eventbus.events.flags.NotLoggedEvent;
|
|
||||||
import mightypork.utils.math.constraints.vect.Vect;
|
|
||||||
import mightypork.utils.math.constraints.vect.VectConst;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Mouse moved
|
|
||||||
*
|
|
||||||
* @author Ondřej Hruška (MightyPork)
|
|
||||||
*/
|
|
||||||
@NotLoggedEvent
|
|
||||||
public class MouseMotionEvent extends BusEvent<MouseMotionHandler> {
|
|
||||||
|
|
||||||
private final VectConst move;
|
|
||||||
private final VectConst pos;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param pos end pos
|
|
||||||
* @param move move vector
|
|
||||||
*/
|
|
||||||
public MouseMotionEvent(Vect pos, Vect move)
|
|
||||||
{
|
|
||||||
this.move = move.freeze();
|
|
||||||
this.pos = pos.freeze();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return movement since last {@link MouseMotionEvent}
|
|
||||||
*/
|
|
||||||
public VectConst getMove()
|
|
||||||
{
|
|
||||||
return move;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return current mouse position
|
|
||||||
*/
|
|
||||||
public VectConst getPos()
|
|
||||||
{
|
|
||||||
return pos;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void handleBy(MouseMotionHandler keh)
|
|
||||||
{
|
|
||||||
keh.receive(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
package mightypork.gamecore.input.events;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@link MouseMotionEvent} listener
|
|
||||||
*
|
|
||||||
* @author Ondřej Hruška (MightyPork)
|
|
||||||
*/
|
|
||||||
public interface MouseMotionHandler {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handle an event
|
|
||||||
*
|
|
||||||
* @param event event
|
|
||||||
*/
|
|
||||||
void receive(MouseMotionEvent event);
|
|
||||||
}
|
|
||||||
@@ -1,298 +0,0 @@
|
|||||||
package mightypork.gamecore.render;
|
|
||||||
|
|
||||||
|
|
||||||
import static org.lwjgl.opengl.GL11.*;
|
|
||||||
|
|
||||||
import java.nio.ByteBuffer;
|
|
||||||
|
|
||||||
import mightypork.gamecore.core.modules.AppAccess;
|
|
||||||
import mightypork.gamecore.core.modules.AppModule;
|
|
||||||
import mightypork.gamecore.render.events.DisplayReadyEvent;
|
|
||||||
import mightypork.gamecore.render.events.ViewportChangeEvent;
|
|
||||||
import mightypork.utils.logging.Log;
|
|
||||||
import mightypork.utils.math.constraints.rect.Rect;
|
|
||||||
import mightypork.utils.math.constraints.rect.RectBound;
|
|
||||||
import mightypork.utils.math.constraints.vect.Vect;
|
|
||||||
import mightypork.utils.math.timing.FpsMeter;
|
|
||||||
|
|
||||||
import org.lwjgl.BufferUtils;
|
|
||||||
import org.lwjgl.LWJGLException;
|
|
||||||
import org.lwjgl.opengl.Display;
|
|
||||||
import org.lwjgl.opengl.DisplayMode;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Display system
|
|
||||||
*
|
|
||||||
* @author Ondřej Hruška (MightyPork)
|
|
||||||
*/
|
|
||||||
public class DisplaySystem extends AppModule implements RectBound {
|
|
||||||
|
|
||||||
private DisplayMode windowDisplayMode;
|
|
||||||
private int targetFps;
|
|
||||||
private FpsMeter fpsMeter;
|
|
||||||
private boolean fullscreenSwitchRequested;
|
|
||||||
|
|
||||||
/** Current screen size */
|
|
||||||
private static final Vect screenSize = new Vect() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public double y()
|
|
||||||
{
|
|
||||||
return Display.getHeight();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public double x()
|
|
||||||
{
|
|
||||||
return Display.getWidth();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
private static final Rect rect = Rect.make(screenSize);
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param app app access
|
|
||||||
*/
|
|
||||||
public DisplaySystem(AppAccess app)
|
|
||||||
{
|
|
||||||
super(app);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void deinit()
|
|
||||||
{
|
|
||||||
Display.destroy();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set target fps (for syncing in endFrame() call).<br>
|
|
||||||
* With vsync enabled, the target fps may not be met.
|
|
||||||
*
|
|
||||||
* @param fps requested fps
|
|
||||||
*/
|
|
||||||
public void setTargetFps(int fps)
|
|
||||||
{
|
|
||||||
this.targetFps = fps;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a main window
|
|
||||||
*
|
|
||||||
* @param width requested width
|
|
||||||
* @param height requested height
|
|
||||||
* @param resizable is resizable by the user
|
|
||||||
* @param fullscreen is in fullscreen
|
|
||||||
* @param title window title
|
|
||||||
*/
|
|
||||||
public void createMainWindow(int width, int height, boolean resizable, boolean fullscreen, String title)
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
Display.setDisplayMode(windowDisplayMode = new DisplayMode(width, height));
|
|
||||||
Display.setResizable(resizable);
|
|
||||||
Display.setVSyncEnabled(true);
|
|
||||||
Display.setTitle(title);
|
|
||||||
Display.create();
|
|
||||||
|
|
||||||
fpsMeter = new FpsMeter();
|
|
||||||
|
|
||||||
if (fullscreen) {
|
|
||||||
switchFullscreen();
|
|
||||||
Display.update();
|
|
||||||
}
|
|
||||||
|
|
||||||
getEventBus().send(new DisplayReadyEvent());
|
|
||||||
|
|
||||||
} catch (final LWJGLException e) {
|
|
||||||
throw new RuntimeException("Could not initialize screen", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Toggle FS if possible
|
|
||||||
*/
|
|
||||||
public void switchFullscreen()
|
|
||||||
{
|
|
||||||
fullscreenSwitchRequested = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private void doSwitchFullscreen()
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
|
|
||||||
if (!Display.isFullscreen()) {
|
|
||||||
Log.f3("Entering fullscreen.");
|
|
||||||
// save window resize
|
|
||||||
windowDisplayMode = new DisplayMode(Display.getWidth(), Display.getHeight());
|
|
||||||
|
|
||||||
Display.setDisplayMode(Display.getDesktopDisplayMode());
|
|
||||||
Display.setFullscreen(true);
|
|
||||||
Display.update();
|
|
||||||
} else {
|
|
||||||
Log.f3("Leaving fullscreen.");
|
|
||||||
Display.setDisplayMode(windowDisplayMode);
|
|
||||||
Display.update();
|
|
||||||
}
|
|
||||||
|
|
||||||
getEventBus().send(new ViewportChangeEvent(getSize()));
|
|
||||||
|
|
||||||
} catch (final Throwable t) {
|
|
||||||
Log.e("Failed to toggle fullscreen mode.", t);
|
|
||||||
try {
|
|
||||||
Display.setDisplayMode(windowDisplayMode);
|
|
||||||
Display.update();
|
|
||||||
} catch (final Throwable t1) {
|
|
||||||
throw new RuntimeException("Failed to revert failed fullscreen toggle.", t1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Take screenshot (expensive processing is done on-demand when screenshot
|
|
||||||
* is processed).
|
|
||||||
*
|
|
||||||
* @return screenshot object
|
|
||||||
*/
|
|
||||||
public static Screenshot prepareScreenshot()
|
|
||||||
{
|
|
||||||
glReadBuffer(GL_FRONT);
|
|
||||||
final int width = Display.getWidth();
|
|
||||||
final int height = Display.getHeight();
|
|
||||||
final int bpp = 4;
|
|
||||||
final ByteBuffer buffer = BufferUtils.createByteBuffer(width * height * bpp);
|
|
||||||
glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
|
|
||||||
|
|
||||||
final Screenshot sc = new Screenshot(width, height, bpp, buffer);
|
|
||||||
|
|
||||||
return sc;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return true if close was requested (i.e. click on cross)
|
|
||||||
*/
|
|
||||||
public static boolean isCloseRequested()
|
|
||||||
{
|
|
||||||
return Display.isCloseRequested();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get fullscreen state
|
|
||||||
*
|
|
||||||
* @return is fullscreen
|
|
||||||
*/
|
|
||||||
public static boolean isFullscreen()
|
|
||||||
{
|
|
||||||
return Display.isFullscreen();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get screen size. This Vect is final and views at it can safely be made.
|
|
||||||
*
|
|
||||||
* @return size
|
|
||||||
*/
|
|
||||||
public static Vect getSize()
|
|
||||||
{
|
|
||||||
return screenSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get screen rect. Static version of getRect().
|
|
||||||
*
|
|
||||||
* @return size
|
|
||||||
*/
|
|
||||||
public static Rect getBounds()
|
|
||||||
{
|
|
||||||
return rect;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return screen width
|
|
||||||
*/
|
|
||||||
public static int getWidth()
|
|
||||||
{
|
|
||||||
return screenSize.xi();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return screen height
|
|
||||||
*/
|
|
||||||
public static int getHeight()
|
|
||||||
{
|
|
||||||
return screenSize.yi();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Start a OpenGL frame
|
|
||||||
*/
|
|
||||||
public void beginFrame()
|
|
||||||
{
|
|
||||||
// handle resize
|
|
||||||
if (Display.wasResized()) {
|
|
||||||
getEventBus().send(new ViewportChangeEvent(getSize()));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fullscreenSwitchRequested) {
|
|
||||||
fullscreenSwitchRequested = false;
|
|
||||||
doSwitchFullscreen();
|
|
||||||
}
|
|
||||||
|
|
||||||
glLoadIdentity();
|
|
||||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
|
||||||
fpsMeter.frame();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* End an OpenGL frame, flip buffers, sync to fps.
|
|
||||||
*/
|
|
||||||
public void endFrame()
|
|
||||||
{
|
|
||||||
Display.update(false); // don't poll input devices
|
|
||||||
Display.sync(targetFps);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get screen rect. This Rect is final and views at it can safely be made.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public Rect getRect()
|
|
||||||
{
|
|
||||||
return getBounds();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return current FPS
|
|
||||||
*/
|
|
||||||
public long getFps()
|
|
||||||
{
|
|
||||||
return fpsMeter.getFPS();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get screen center. This vect is final and views at it can safely be made.
|
|
||||||
*
|
|
||||||
* @return screen center.
|
|
||||||
*/
|
|
||||||
public static Vect getCenter()
|
|
||||||
{
|
|
||||||
return rect.center();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,541 +0,0 @@
|
|||||||
package mightypork.gamecore.render;
|
|
||||||
|
|
||||||
|
|
||||||
import static org.lwjgl.opengl.GL11.*;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
import mightypork.gamecore.resources.textures.FilterMode;
|
|
||||||
import mightypork.gamecore.resources.textures.GLTexture;
|
|
||||||
import mightypork.gamecore.resources.textures.TxQuad;
|
|
||||||
import mightypork.utils.files.FileUtils;
|
|
||||||
import mightypork.utils.logging.Log;
|
|
||||||
import mightypork.utils.math.color.Color;
|
|
||||||
import mightypork.utils.math.color.pal.RGB;
|
|
||||||
import mightypork.utils.math.constraints.rect.Rect;
|
|
||||||
import mightypork.utils.math.constraints.rect.caching.RectDigest;
|
|
||||||
import mightypork.utils.math.constraints.vect.Vect;
|
|
||||||
import mightypork.utils.math.constraints.vect.VectConst;
|
|
||||||
|
|
||||||
import org.lwjgl.opengl.GL11;
|
|
||||||
import org.newdawn.slick.opengl.Texture;
|
|
||||||
import org.newdawn.slick.opengl.TextureLoader;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Render utilities
|
|
||||||
*
|
|
||||||
* @author Ondřej Hruška (MightyPork)
|
|
||||||
*/
|
|
||||||
public class Render {
|
|
||||||
|
|
||||||
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_Z = Vect.make(0, 0, 1);
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Bind GL color
|
|
||||||
*
|
|
||||||
* @param color Color color
|
|
||||||
*/
|
|
||||||
public static void setColor(Color color)
|
|
||||||
{
|
|
||||||
if (color != null) glColor4d(color.r(), color.g(), color.b(), color.a());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Bind GL color
|
|
||||||
*
|
|
||||||
* @param color Color color
|
|
||||||
* @param alpha alpha multiplier
|
|
||||||
*/
|
|
||||||
public static void setColor(Color color, double alpha)
|
|
||||||
{
|
|
||||||
if (color != null) glColor4d(color.r(), color.g(), color.b(), color.a() * alpha);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Translate
|
|
||||||
*
|
|
||||||
* @param x
|
|
||||||
* @param y
|
|
||||||
*/
|
|
||||||
public static void translate(double x, double y)
|
|
||||||
{
|
|
||||||
glTranslated(x, y, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Translate
|
|
||||||
*
|
|
||||||
* @param x
|
|
||||||
* @param y
|
|
||||||
* @param z
|
|
||||||
*/
|
|
||||||
public static void translate(double x, double y, double z)
|
|
||||||
{
|
|
||||||
glTranslated(x, y, z);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Translate with coord
|
|
||||||
*
|
|
||||||
* @param coord coord
|
|
||||||
*/
|
|
||||||
public static void translate(Vect coord)
|
|
||||||
{
|
|
||||||
glTranslated(coord.x(), coord.y(), coord.z());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Translate with coord, discard Z
|
|
||||||
*
|
|
||||||
* @param coord coord
|
|
||||||
*/
|
|
||||||
public static void translateXY(Vect coord)
|
|
||||||
{
|
|
||||||
glTranslated(coord.x(), coord.y(), 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Scale
|
|
||||||
*
|
|
||||||
* @param x
|
|
||||||
* @param y
|
|
||||||
*/
|
|
||||||
public static void scale(double x, double y)
|
|
||||||
{
|
|
||||||
glScaled(x, y, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Scale
|
|
||||||
*
|
|
||||||
* @param x
|
|
||||||
* @param y
|
|
||||||
* @param z
|
|
||||||
*/
|
|
||||||
public static void scale(double x, double y, double z)
|
|
||||||
{
|
|
||||||
glScaled(x, y, z);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Scale
|
|
||||||
*
|
|
||||||
* @param factor vector of scaling factors
|
|
||||||
*/
|
|
||||||
public static void scale(Vect factor)
|
|
||||||
{
|
|
||||||
glScaled(factor.x(), factor.y(), factor.z());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Scale by X factor
|
|
||||||
*
|
|
||||||
* @param factor scaling factor
|
|
||||||
*/
|
|
||||||
public static void scaleXY(double factor)
|
|
||||||
{
|
|
||||||
glScaled(factor, factor, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Scale by X factor
|
|
||||||
*
|
|
||||||
* @param factor scaling factor
|
|
||||||
*/
|
|
||||||
public static void scaleX(double factor)
|
|
||||||
{
|
|
||||||
glScaled(factor, 1, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Scale by Y factor
|
|
||||||
*
|
|
||||||
* @param factor scaling factor
|
|
||||||
*/
|
|
||||||
public static void scaleY(double factor)
|
|
||||||
{
|
|
||||||
glScaled(1, factor, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Scale by Z factor
|
|
||||||
*
|
|
||||||
* @param factor scaling factor
|
|
||||||
*/
|
|
||||||
public static void scaleZ(double factor)
|
|
||||||
{
|
|
||||||
glScaled(1, 1, factor);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Rotate around X axis
|
|
||||||
*
|
|
||||||
* @param angle deg
|
|
||||||
*/
|
|
||||||
public static void rotateX(double angle)
|
|
||||||
{
|
|
||||||
rotate(angle, AXIS_X);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Rotate around Y axis
|
|
||||||
*
|
|
||||||
* @param angle deg
|
|
||||||
*/
|
|
||||||
public static void rotateY(double angle)
|
|
||||||
{
|
|
||||||
rotate(angle, AXIS_Y);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Rotate around Z axis
|
|
||||||
*
|
|
||||||
* @param angle deg
|
|
||||||
*/
|
|
||||||
public static void rotateZ(double angle)
|
|
||||||
{
|
|
||||||
rotate(angle, AXIS_Z);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Rotate
|
|
||||||
*
|
|
||||||
* @param angle rotate angle
|
|
||||||
* @param axis rotation axis
|
|
||||||
*/
|
|
||||||
public static void rotate(double angle, Vect axis)
|
|
||||||
{
|
|
||||||
final Vect vec = axis.norm(1);
|
|
||||||
glRotated(angle, vec.x(), vec.y(), vec.z());
|
|
||||||
}
|
|
||||||
|
|
||||||
private static int pushed = 0;
|
|
||||||
/** Can be used to avoid texture binding and glBegin/glEnd in textured quads */
|
|
||||||
public static boolean batchTexturedQuadMode;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Store GL state
|
|
||||||
*/
|
|
||||||
public static void pushState()
|
|
||||||
{
|
|
||||||
pushed++;
|
|
||||||
|
|
||||||
if (pushed >= 100) {
|
|
||||||
Log.w("Suspicious number of state pushes: " + pushed);
|
|
||||||
}
|
|
||||||
|
|
||||||
GL11.glPushAttrib(GL11.GL_ALL_ATTRIB_BITS);
|
|
||||||
GL11.glPushClientAttrib(GL11.GL_ALL_CLIENT_ATTRIB_BITS);
|
|
||||||
GL11.glMatrixMode(GL11.GL_MODELVIEW);
|
|
||||||
GL11.glPushMatrix();
|
|
||||||
GL11.glMatrixMode(GL11.GL_PROJECTION);
|
|
||||||
GL11.glPushMatrix();
|
|
||||||
GL11.glMatrixMode(GL11.GL_MODELVIEW);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Restore Gl state
|
|
||||||
*/
|
|
||||||
public static void popState()
|
|
||||||
{
|
|
||||||
if (pushed == 0) {
|
|
||||||
Log.w("Pop without push.");
|
|
||||||
}
|
|
||||||
|
|
||||||
pushed--;
|
|
||||||
|
|
||||||
GL11.glMatrixMode(GL11.GL_PROJECTION);
|
|
||||||
GL11.glPopMatrix();
|
|
||||||
GL11.glMatrixMode(GL11.GL_MODELVIEW);
|
|
||||||
GL11.glPopMatrix();
|
|
||||||
GL11.glPopClientAttrib();
|
|
||||||
GL11.glPopAttrib();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Store matrix
|
|
||||||
*/
|
|
||||||
public static void pushMatrix()
|
|
||||||
{
|
|
||||||
GL11.glPushMatrix();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Restore Gl state
|
|
||||||
*/
|
|
||||||
public static void popMatrix()
|
|
||||||
{
|
|
||||||
GL11.glPopMatrix();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Load texture
|
|
||||||
*
|
|
||||||
* @param resourcePath
|
|
||||||
* @param filtering filtering mode to use while loading.
|
|
||||||
* @return the loaded texture
|
|
||||||
*/
|
|
||||||
public synchronized static Texture loadSlickTexture(String resourcePath, FilterMode filtering)
|
|
||||||
{
|
|
||||||
|
|
||||||
try {
|
|
||||||
|
|
||||||
final String ext = FileUtils.getExtension(resourcePath).toUpperCase();
|
|
||||||
|
|
||||||
final Texture texture = TextureLoader.getTexture(ext, FileUtils.getResource(resourcePath), false, filtering.num);
|
|
||||||
|
|
||||||
if (texture == null) {
|
|
||||||
Log.w("Texture " + resourcePath + " could not be loaded.");
|
|
||||||
}
|
|
||||||
|
|
||||||
return texture;
|
|
||||||
|
|
||||||
} catch (final IOException e) {
|
|
||||||
Log.e("Loading of texture " + resourcePath + " failed.", e);
|
|
||||||
throw new RuntimeException("Could not load texture " + resourcePath + ".", e);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Render quad 2D
|
|
||||||
*
|
|
||||||
* @param rect rectangle
|
|
||||||
* @param color draw color
|
|
||||||
*/
|
|
||||||
public static void quad(Rect rect, Color color)
|
|
||||||
{
|
|
||||||
setColor(color);
|
|
||||||
quad(rect);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Render quad
|
|
||||||
*
|
|
||||||
* @param quad the quad to draw (px)
|
|
||||||
*/
|
|
||||||
public static void quad(Rect quad)
|
|
||||||
{
|
|
||||||
final RectDigest q = quad.digest();
|
|
||||||
|
|
||||||
// draw with color
|
|
||||||
|
|
||||||
glDisable(GL_TEXTURE_2D);
|
|
||||||
|
|
||||||
// quad
|
|
||||||
glBegin(GL_QUADS);
|
|
||||||
glVertex2d(q.left, q.bottom);
|
|
||||||
glVertex2d(q.right, q.bottom);
|
|
||||||
glVertex2d(q.right, q.top);
|
|
||||||
glVertex2d(q.left, q.top);
|
|
||||||
glEnd();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Draw quad with horizontal gradient
|
|
||||||
*
|
|
||||||
* @param quad drawn quad bounds
|
|
||||||
* @param color1 left color
|
|
||||||
* @param color2 right color
|
|
||||||
*/
|
|
||||||
public static void quadGradH(Rect quad, Color color1, Color color2)
|
|
||||||
{
|
|
||||||
quadColor(quad, color1, color2, color2, color1);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static void quadColor(Rect quad, Color color)
|
|
||||||
{
|
|
||||||
quadColor(quad, color, color, color, color);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Draw quad with coloured vertices.
|
|
||||||
*
|
|
||||||
* @param quad drawn quad bounds
|
|
||||||
* @param colorHMinVMin
|
|
||||||
* @param colorHMaxVMin
|
|
||||||
* @param colorHMaxVMax
|
|
||||||
* @param colorHMinVMax
|
|
||||||
*/
|
|
||||||
public static void quadColor(Rect quad, Color colorHMinVMin, Color colorHMaxVMin, Color colorHMaxVMax, Color colorHMinVMax)
|
|
||||||
{
|
|
||||||
final RectDigest r = quad.digest();
|
|
||||||
|
|
||||||
// draw with color
|
|
||||||
|
|
||||||
glDisable(GL_TEXTURE_2D);
|
|
||||||
|
|
||||||
glBegin(GL_QUADS);
|
|
||||||
setColor(colorHMinVMax);
|
|
||||||
glVertex2d(r.left, r.bottom);
|
|
||||||
|
|
||||||
setColor(colorHMaxVMax);
|
|
||||||
glVertex2d(r.right, r.bottom);
|
|
||||||
|
|
||||||
setColor(colorHMaxVMin);
|
|
||||||
glVertex2d(r.right, r.top);
|
|
||||||
|
|
||||||
setColor(colorHMinVMin);
|
|
||||||
glVertex2d(r.left, r.top);
|
|
||||||
glEnd();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Draw quad with vertical gradient
|
|
||||||
*
|
|
||||||
* @param quad drawn quad bounds
|
|
||||||
* @param color1 top color
|
|
||||||
* @param color2 bottom color
|
|
||||||
*/
|
|
||||||
public static void quadGradV(Rect quad, Color color1, Color color2)
|
|
||||||
{
|
|
||||||
quadColor(quad, color1, color1, color2, color2);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Render textured rect
|
|
||||||
*
|
|
||||||
* @param quad rectangle (px)
|
|
||||||
* @param txquad texture quad
|
|
||||||
*/
|
|
||||||
public static void quadTextured(Rect quad, TxQuad txquad)
|
|
||||||
{
|
|
||||||
quadTextured(quad, txquad, RGB.WHITE);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Render textured rect
|
|
||||||
*
|
|
||||||
* @param quad rectangle (px)
|
|
||||||
* @param txquad texture instance
|
|
||||||
* @param tint color tint
|
|
||||||
*/
|
|
||||||
public static void quadTextured(Rect quad, TxQuad txquad, Color tint)
|
|
||||||
{
|
|
||||||
if (!batchTexturedQuadMode) {
|
|
||||||
glEnable(GL_TEXTURE_2D);
|
|
||||||
txquad.tx.bind();
|
|
||||||
glBegin(GL_QUADS);
|
|
||||||
setColor(tint);
|
|
||||||
}
|
|
||||||
|
|
||||||
final RectDigest q = quad.digest();
|
|
||||||
final RectDigest u = txquad.uvs.digest();
|
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
// handle flip
|
|
||||||
if (txquad.isFlippedY()) {
|
|
||||||
final double swap = tT;
|
|
||||||
tT = tB;
|
|
||||||
tB = swap;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (txquad.isFlippedX()) {
|
|
||||||
final double swap = tL;
|
|
||||||
tL = tR;
|
|
||||||
tR = swap;
|
|
||||||
}
|
|
||||||
|
|
||||||
final double w = txquad.tx.getWidth01();
|
|
||||||
final double h = txquad.tx.getHeight01();
|
|
||||||
|
|
||||||
// quad with texture
|
|
||||||
glTexCoord2d(tL * w, tB * h);
|
|
||||||
glVertex2d(q.left, q.bottom);
|
|
||||||
|
|
||||||
glTexCoord2d(tR * w, tB * h);
|
|
||||||
glVertex2d(q.right, q.bottom);
|
|
||||||
|
|
||||||
glTexCoord2d(tR * w, tT * h);
|
|
||||||
glVertex2d(q.right, q.top);
|
|
||||||
|
|
||||||
glTexCoord2d(tL * w, tT * h);
|
|
||||||
glVertex2d(q.left, q.top);
|
|
||||||
|
|
||||||
if (!batchTexturedQuadMode) glEnd();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Setup Ortho projection for 2D graphics
|
|
||||||
*
|
|
||||||
* @param size viewport size (screen size)
|
|
||||||
*/
|
|
||||||
public static void setupOrtho(Vect size)
|
|
||||||
{
|
|
||||||
// fix projection for changed size
|
|
||||||
glMatrixMode(GL_PROJECTION);
|
|
||||||
glLoadIdentity();
|
|
||||||
glViewport(0, 0, size.xi(), size.yi());
|
|
||||||
glOrtho(0, size.xi(), size.yi(), 0, -1000, 1000);
|
|
||||||
|
|
||||||
// back to modelview
|
|
||||||
glMatrixMode(GL_MODELVIEW);
|
|
||||||
|
|
||||||
glLoadIdentity();
|
|
||||||
|
|
||||||
glDisable(GL_LIGHTING);
|
|
||||||
|
|
||||||
glClearDepth(1f);
|
|
||||||
glEnable(GL_DEPTH_TEST);
|
|
||||||
glDepthFunc(GL_LEQUAL);
|
|
||||||
|
|
||||||
glEnable(GL_NORMALIZE);
|
|
||||||
|
|
||||||
glShadeModel(GL_SMOOTH);
|
|
||||||
|
|
||||||
glEnable(GL_BLEND);
|
|
||||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static void enterBatchTexturedQuadMode(GLTexture texture)
|
|
||||||
{
|
|
||||||
texture.bind();
|
|
||||||
glBegin(GL11.GL_QUADS);
|
|
||||||
batchTexturedQuadMode = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static void leaveBatchTexturedQuadMode()
|
|
||||||
{
|
|
||||||
glEnd();
|
|
||||||
batchTexturedQuadMode = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user