diff --git a/src/mightypork/gamecore/audio/DeferredAudio.java b/src/mightypork/gamecore/audio/DeferredAudio.java index 00650b2..b78eadc 100644 --- a/src/mightypork/gamecore/audio/DeferredAudio.java +++ b/src/mightypork/gamecore/audio/DeferredAudio.java @@ -3,7 +3,7 @@ package mightypork.gamecore.audio; import java.io.IOException; -import mightypork.gamecore.loading.BaseDeferredResource; +import mightypork.gamecore.loading.DeferredResource; import mightypork.utils.files.FileUtils; import mightypork.utils.logging.LoggedName; import mightypork.utils.math.coord.Coord; @@ -18,7 +18,7 @@ import org.newdawn.slick.openal.SoundStore; * @author MightyPork */ @LoggedName(name = "Audio") -public class DeferredAudio extends BaseDeferredResource { +public class DeferredAudio extends DeferredResource { private enum PlayMode { @@ -168,7 +168,7 @@ public class DeferredAudio extends BaseDeferredResource { */ public int playAsEffect(double pitch, double gain, boolean loop, double x, double y) { - return playAsEffect(pitch, gain, loop, x, y, SoundSystem.getListener().z); + return playAsEffect(pitch, gain, loop, x, y, SoundSystem.getListener().z()); } @@ -208,7 +208,7 @@ public class DeferredAudio extends BaseDeferredResource { { if (!ensureLoaded()) return -1; - return playAsEffect(pitch, gain, loop, pos.x, pos.y, pos.z); + return playAsEffect(pitch, gain, loop, pos.x(), pos.y(), pos.z()); } diff --git a/src/mightypork/gamecore/audio/SoundSystem.java b/src/mightypork/gamecore/audio/SoundSystem.java index a32e150..94ae6c6 100644 --- a/src/mightypork/gamecore/audio/SoundSystem.java +++ b/src/mightypork/gamecore/audio/SoundSystem.java @@ -26,7 +26,7 @@ import org.newdawn.slick.openal.SoundStore; */ public class SoundSystem extends RootBusNode implements Updateable { - private static final Coord INITIAL_LISTENER_POS = new Coord(0, 0, 0); + private static final Coord INITIAL_LISTENER_POS = Coord.ZERO; private static final int MAX_SOURCES = 256; private static Coord listener = new Coord(); @@ -45,7 +45,7 @@ public class SoundSystem extends RootBusNode implements Updateable { FloatBuffer buf3 = Buffers.alloc(3); FloatBuffer buf6 = Buffers.alloc(6); buf3.clear(); - Buffers.fill(buf3, (float) pos.x, (float) pos.y, (float) pos.z); + Buffers.fill(buf3, pos.xf(), pos.yf(), pos.zf()); AL10.alListener(AL10.AL_POSITION, buf3); buf3.clear(); Buffers.fill(buf3, 0, 0, 0); diff --git a/src/mightypork/gamecore/control/GameLoop.java b/src/mightypork/gamecore/control/GameLoop.java index 92d6acd..18bfa53 100644 --- a/src/mightypork/gamecore/control/GameLoop.java +++ b/src/mightypork/gamecore/control/GameLoop.java @@ -64,7 +64,9 @@ public abstract class GameLoop extends AppModule implements MainLoopTaskRequest. beforeRender(); - if (rootRenderable != null) rootRenderable.render(); + if (rootRenderable != null) { + rootRenderable.render(); + } afterRender(); diff --git a/src/mightypork/gamecore/control/bus/events/ResourceLoadRequest.java b/src/mightypork/gamecore/control/bus/events/ResourceLoadRequest.java index a2acad6..3497047 100644 --- a/src/mightypork/gamecore/control/bus/events/ResourceLoadRequest.java +++ b/src/mightypork/gamecore/control/bus/events/ResourceLoadRequest.java @@ -2,7 +2,7 @@ package mightypork.gamecore.control.bus.events; import mightypork.gamecore.control.bus.events.types.SingleReceiverEvent; -import mightypork.gamecore.loading.DeferredResource; +import mightypork.gamecore.loading.Deferred; /** @@ -13,13 +13,13 @@ import mightypork.gamecore.loading.DeferredResource; @SingleReceiverEvent public class ResourceLoadRequest implements Event { - private final DeferredResource resource; + private final Deferred resource; /** * @param resource resource to load */ - public ResourceLoadRequest(DeferredResource resource) { + public ResourceLoadRequest(Deferred resource) { this.resource = resource; } @@ -42,6 +42,6 @@ public class ResourceLoadRequest implements Event * * @param resource */ - void loadResource(DeferredResource resource); + void loadResource(Deferred resource); } } diff --git a/src/mightypork/gamecore/gui/components/painters/TextPainter.java b/src/mightypork/gamecore/gui/components/painters/TextPainter.java index 5bf39d3..26d4c24 100644 --- a/src/mightypork/gamecore/gui/components/painters/TextPainter.java +++ b/src/mightypork/gamecore/gui/components/painters/TextPainter.java @@ -6,12 +6,16 @@ import mightypork.gamecore.render.fonts.FontRenderer; import mightypork.gamecore.render.fonts.FontRenderer.Align; import mightypork.gamecore.render.fonts.GLFont; import mightypork.utils.math.color.RGB; +import mightypork.utils.math.coord.Coord; +import mightypork.utils.math.coord.Rect; import mightypork.utils.string.StringProvider; import mightypork.utils.string.StringProvider.StringWrapper; /** - * Text painting component + * Text painting component.
+ * Drawing values are obtained through getters, so overriding getters can be + * used to change parameters dynamically. * * @author MightyPork */ @@ -21,6 +25,10 @@ public class TextPainter extends PluggableRenderer { private RGB color; private Align align; private StringProvider text; + private boolean shadow; + + private RGB shadowColor = RGB.BLACK; + private Coord shadowOffset = Coord.one(); /** @@ -70,110 +78,68 @@ public class TextPainter extends PluggableRenderer { } - /** - * Use size specified during font init instead of size provided by - * {@link GLFont} instance (measured from tile heights.
- * This is better when the font is drawn in original size, but can cause - * weird artifacts if the font is scaled up. - * - * @param enable use it - */ - public void usePtSize(boolean enable) + @Override + public void render() { - font.usePtSize(enable); + if (text == null) return; + + final String str = text.getString(); + final Rect rect = getRect(); + + if (shadow) { + font.draw(str, rect.add(shadowOffset), align, shadowColor); + } + font.draw(str, rect, align, color); } - @Override - public void render() + public void setShadow(RGB color, Coord offset) { - if (getText() == null) return; - - font.draw(getText(), getRect(), getAlign(), getColor()); + setShadow(true); + setShadowColor(color); + setShadowOffset(offset); } - /** - * Assign paint color - * - * @param color paint color - */ - public void setColor(RGB color) + public void setShadow(boolean shadow) { - this.color = color; + this.shadow = shadow; } - /** - * Set text align - * - * @param align text align - */ - public void setAlign(Align align) + public void setShadowColor(RGB shadowColor) { - this.align = align; + this.shadowColor = shadowColor; } - /** - * Set drawn text - * - * @param text text - */ - public void setText(String text) + public void setShadowOffset(Coord shadowOffset) { - this.text = new StringWrapper(text); + this.shadowOffset = shadowOffset; } - /** - * Set drawn text provider - * - * @param text text provider - */ - public void setText(StringProvider text) + public void setColor(RGB color) { - this.text = text; + this.color = color; } - /** - * Get draw color.
- * This getter is used for getting drawing color; so if it's overriden, - * the draw color can be adjusted in real time. - * - * @return drawing color - */ - public RGB getColor() + public void setAlign(Align align) { - return color; + this.align = align; } - /** - * Get text align.
- * This getter is used for getting align; so if it's overidden, the align - * can be adjusted in real time. - * - * @return text align - */ - public Align getAlign() + public void setText(String text) { - return align; + this.text = new StringWrapper(text); } - /** - * Get text to draw.
- * This getter is used for getting text to draw; so if it's overidden, - * the text can be adjusted in real time. (alternative to using - * StringProvider) - * - * @return text align - */ - public String getText() + public void setText(StringProvider text) { - return text.getString(); + this.text = text; } } diff --git a/src/mightypork/gamecore/gui/constraints/Constraints.java b/src/mightypork/gamecore/gui/constraints/Constraints.java index 234fe5f..a12f201 100644 --- a/src/mightypork/gamecore/gui/constraints/Constraints.java +++ b/src/mightypork/gamecore/gui/constraints/Constraints.java @@ -23,7 +23,7 @@ public class Constraints { @Override public double getValue() { - return InputSystem.getMousePos().x; + return InputSystem.getMousePos().x(); } }; @@ -32,7 +32,7 @@ public class Constraints { @Override public double getValue() { - return InputSystem.getMousePos().y; + return InputSystem.getMousePos().y(); } }; @@ -246,7 +246,7 @@ public class Constraints { @Override public double getValue() { - return r.getRect().getSize().x; + return r.getRect().getSize().x(); } }; } @@ -259,7 +259,7 @@ public class Constraints { @Override public double getValue() { - return r.getRect().getSize().y; + return r.getRect().getSize().y(); } }; } @@ -274,7 +274,7 @@ public class Constraints { @Override public Rect getRect() { - final double height = r.getRect().getSize().y; + final double height = r.getRect().getSize().y(); final double perRow = height / rows; final Coord origin = r.getRect().getOrigin().add(0, perRow * index); @@ -293,7 +293,7 @@ public class Constraints { @Override public Rect getRect() { - final double width = r.getRect().getSize().x; + final double width = r.getRect().getSize().x(); final double perCol = width / columns; final Coord origin = r.getRect().getOrigin().add(perCol * index, 0); @@ -312,8 +312,8 @@ public class Constraints { @Override public Rect getRect() { - final double height = r.getRect().getSize().y; - final double width = r.getRect().getSize().y; + final double height = r.getRect().getSize().y(); + final double width = r.getRect().getSize().y(); final double perRow = height / rows; final double perCol = width / cols; @@ -522,8 +522,8 @@ public class Constraints { //@formatter:off return Rect.fromSize( - origin.x, - origin.y, + origin.x(), + origin.y(), _nv(width), _nv(height) ); @@ -544,8 +544,8 @@ public class Constraints { //@formatter:off return Rect.fromSize( - origin.x + _nv(x), - origin.y + _nv(y), + origin.x() + _nv(x), + origin.y() + _nv(y), _nv(width), _nv(height) ); @@ -582,7 +582,7 @@ public class Constraints { final Coord size = r.getRect().getSize(); final Coord center = centerTo.getRect().getCenter(); - return Rect.fromSize(center.x - size.x / 2D, center.y - size.y / 2D, size.x, size.y); + return Rect.fromSize(center.x() - size.x() / 2D, center.y() - size.y() / 2D, size.x(), size.y()); } }; } @@ -605,7 +605,7 @@ public class Constraints { { final Coord size = r.getRect().getSize(); - return Rect.fromSize(_nv(x) - size.x / 2D, _nv(y) - size.y / 2D, size.x, size.y); + return Rect.fromSize(_nv(x) - size.x() / 2D, _nv(y) - size.y() / 2D, size.x(), size.y()); } }; } diff --git a/src/mightypork/gamecore/gui/screens/LayeredScreen.java b/src/mightypork/gamecore/gui/screens/LayeredScreen.java index 36f414d..9b395ff 100644 --- a/src/mightypork/gamecore/gui/screens/LayeredScreen.java +++ b/src/mightypork/gamecore/gui/screens/LayeredScreen.java @@ -5,7 +5,6 @@ import java.util.Collection; import java.util.TreeSet; import mightypork.gamecore.control.AppAccess; -import mightypork.gamecore.render.Render; import mightypork.utils.math.coord.Coord; @@ -31,9 +30,7 @@ public abstract class LayeredScreen extends Screen { protected void renderScreen() { for (final ScreenLayer layer : layers) { - Render.pushState(); layer.render(); - Render.popState(); } } diff --git a/src/mightypork/gamecore/input/InputSystem.java b/src/mightypork/gamecore/input/InputSystem.java index 0b3ec44..3db1b98 100644 --- a/src/mightypork/gamecore/input/InputSystem.java +++ b/src/mightypork/gamecore/input/InputSystem.java @@ -129,10 +129,10 @@ public class InputSystem extends RootBusNode implements Updateable, KeyBinder { } if (button != -1 || wheeld != 0) { - getEventBus().send(new MouseButtonEvent(pos, button, down, wheeld)); + getEventBus().send(new MouseButtonEvent(pos.freeze(), button, down, wheeld)); } - moveSum.add_ip(move); + moveSum.add_ip(move.freeze()); lastPos.setTo(pos); } @@ -149,7 +149,7 @@ public class InputSystem extends RootBusNode implements Updateable, KeyBinder { private static void flipScrY(Coord c) { - if (DisplaySystem.yAxisDown) c.setY_ip(DisplaySystem.getSize().y - c.y); + if (DisplaySystem.yAxisDown) c.setY_ip(DisplaySystem.getSize().y() - c.y()); } @@ -162,7 +162,7 @@ public class InputSystem extends RootBusNode implements Updateable, KeyBinder { { final Coord pos = new Coord(Mouse.getX(), Mouse.getY()); flipScrY(pos); - return pos; + return pos.freeze(); } diff --git a/src/mightypork/gamecore/loading/AsyncResourceLoader.java b/src/mightypork/gamecore/loading/AsyncResourceLoader.java index 3054365..37dde05 100644 --- a/src/mightypork/gamecore/loading/AsyncResourceLoader.java +++ b/src/mightypork/gamecore/loading/AsyncResourceLoader.java @@ -6,7 +6,6 @@ import java.util.concurrent.Executors; import java.util.concurrent.LinkedBlockingQueue; import mightypork.gamecore.control.bus.BusAccess; -import mightypork.gamecore.control.bus.events.MainLoopTaskRequest; import mightypork.gamecore.control.bus.events.ResourceLoadRequest; import mightypork.gamecore.control.interf.Destroyable; import mightypork.utils.logging.Log; @@ -33,8 +32,9 @@ public class AsyncResourceLoader extends Thread implements ResourceLoadRequest.L private final ExecutorService exs = Executors.newCachedThreadPool(); - private final LinkedBlockingQueue toLoad = new LinkedBlockingQueue<>(); + private final LinkedBlockingQueue toLoad = new LinkedBlockingQueue<>(); private volatile boolean stopped; + @SuppressWarnings("unused") private final BusAccess app; @@ -49,7 +49,7 @@ public class AsyncResourceLoader extends Thread implements ResourceLoadRequest.L @Override - public void loadResource(final DeferredResource resource) + public void loadResource(final Deferred resource) { if (resource.isLoaded()) return; if (resource instanceof NullResource) return; @@ -57,7 +57,7 @@ public class AsyncResourceLoader extends Thread implements ResourceLoadRequest.L // textures & fonts needs to be loaded in main thread if (resource.getClass().isAnnotationPresent(MustLoadInMainThread.class)) { - // just ignore + Log.f3(" Cannot load async: " + Log.str(resource)); // Log.f3(" Delegating to main thread:\n " + Log.str(resource)); // @@ -85,12 +85,12 @@ public class AsyncResourceLoader extends Thread implements ResourceLoadRequest.L while (!stopped) { try { - final DeferredResource def = toLoad.take(); + final Deferred def = toLoad.take(); if (def == null) continue; if (!def.isLoaded()) { - Log.f3(" Loading async:\n " + Log.str(def)); + Log.f3(" Loading: " + Log.str(def)); exs.submit(new Runnable() { diff --git a/src/mightypork/gamecore/loading/BaseDeferredResource.java b/src/mightypork/gamecore/loading/BaseDeferredResource.java deleted file mode 100644 index 49319ab..0000000 --- a/src/mightypork/gamecore/loading/BaseDeferredResource.java +++ /dev/null @@ -1,144 +0,0 @@ -package mightypork.gamecore.loading; - - -import mightypork.gamecore.control.interf.Destroyable; -import mightypork.utils.logging.Log; -import mightypork.utils.logging.LoggedName; - - -/** - * Deferred resource abstraction.
- * Resources implementing {@link NullResource} will be treated as fake and not - * attempted to load. - * - * @author MightyPork - */ -@LoggedName(name = "Resource") -public abstract class BaseDeferredResource implements DeferredResource, Destroyable { - - private final String resource; - private volatile boolean loadFailed = false; - private volatile boolean loadAttempted = false; - - - /** - * @param resource resource path / name; this string is later used in - * loadResource() - */ - public BaseDeferredResource(String resource) { - this.resource = resource; - } - - - @Override - public synchronized final void load() - { - if(loadFailed) return; - - if (loadAttempted) { - Log.w(" Already loaded @ load():\n " + this); - (new IllegalStateException()).printStackTrace(); - return; - } - - loadAttempted = true; - - loadFailed = false; - - if (isNull()) return; - try { - if (resource == null) { - throw new NullPointerException("Resource string cannot be null for non-null resource."); - } - - Log.f3(" Loading:\n " + this); - loadResource(resource); - Log.f3(" Loaded:\n " + this); - } catch (final Exception e) { - loadFailed = true; - Log.e(" Failed to load:\n " + this, e); - } - } - - - @Override - public synchronized final boolean isLoaded() - { - if (isNull()) return false; - - return loadAttempted && !loadFailed; - } - - - /** - * Check if the resource is loaded; if not, try to do so. - * - * @return true if it's loaded now. - */ - public synchronized final boolean ensureLoaded() - { - if (isNull()) return false; - - if (isLoaded()) { - return true; - } else { - if(loadFailed) return false; - - Log.f3(" (!) First use, not loaded yet - loading directly\n " + this); - load(); - } - - return isLoaded(); - } - - - /** - * Load the resource. Called from load() - once only. - * - * @param resource the path / name of a resource - * @throws Exception when some problem prevented the resource from being - * loaded. - */ - protected abstract void loadResource(String resource) throws Exception; - - - @Override - public abstract void destroy(); - - - @Override - public String toString() - { - return Log.str(getClass()) + "(\"" + resource + "\")"; - } - - - @Override - public int hashCode() - { - final int prime = 31; - int result = 1; - result = prime * result + ((resource == null) ? 0 : resource.hashCode()); - return result; - } - - - @Override - public boolean equals(Object obj) - { - if (this == obj) return true; - if (obj == null) return false; - if (!(obj instanceof BaseDeferredResource)) return false; - final BaseDeferredResource other = (BaseDeferredResource) obj; - if (resource == null) { - if (other.resource != null) return false; - } else if (!resource.equals(other.resource)) return false; - return true; - } - - - private boolean isNull() - { - return this instanceof NullResource; - } -} diff --git a/src/mightypork/gamecore/loading/Deferred.java b/src/mightypork/gamecore/loading/Deferred.java new file mode 100644 index 0000000..28896da --- /dev/null +++ b/src/mightypork/gamecore/loading/Deferred.java @@ -0,0 +1,23 @@ +package mightypork.gamecore.loading; + + +/** + * Deferred resource + * + * @author MightyPork + */ +public interface Deferred { + + /** + * Load the actual resource, if not loaded yet. + */ + void load(); + + + /** + * Check if resource was successfully loaded. + * + * @return true if already loaded + */ + boolean isLoaded(); +} diff --git a/src/mightypork/gamecore/loading/DeferredResource.java b/src/mightypork/gamecore/loading/DeferredResource.java index a56654c..3ee162e 100644 --- a/src/mightypork/gamecore/loading/DeferredResource.java +++ b/src/mightypork/gamecore/loading/DeferredResource.java @@ -1,23 +1,140 @@ package mightypork.gamecore.loading; +import mightypork.gamecore.control.interf.Destroyable; +import mightypork.utils.logging.Log; +import mightypork.utils.logging.LoggedName; + + /** - * Deferred resource + * Deferred resource abstraction.
+ * Resources implementing {@link NullResource} will be treated as fake and not + * attempted to load. * * @author MightyPork */ -public interface DeferredResource { +@LoggedName(name = "Resource") +public abstract class DeferredResource implements Deferred, Destroyable { + + private final String resource; + private volatile boolean loadFailed = false; + private volatile boolean loadAttempted = false; + /** - * Load the actual resource, if not loaded yet. + * @param resource resource path / name; this string is later used in + * loadResource() */ - void load(); + public DeferredResource(String resource) { + this.resource = resource; + } + + + @Override + public synchronized final void load() + { + if (loadFailed) return; + + if (loadAttempted) return; + + loadAttempted = true; + + loadFailed = false; + + if (isNull()) return; + try { + if (resource == null) { + throw new NullPointerException("Resource string cannot be null for non-null resource."); + } + + Log.f3(" Loading: " + this); + loadResource(resource); + Log.f3(" Loaded: " + this); + } catch (final Exception e) { + loadFailed = true; + Log.e(" Failed to load: " + this, e); + } + } + + + @Override + public synchronized final boolean isLoaded() + { + if (isNull()) return false; + + return loadAttempted && !loadFailed; + } /** - * Check if resource was successfully loaded. + * Check if the resource is loaded; if not, try to do so. * - * @return true if already loaded + * @return true if it's loaded now. */ - boolean isLoaded(); + public synchronized final boolean ensureLoaded() + { + if (isNull()) return false; + + if (isLoaded()) { + return true; + } else { + if (loadFailed) return false; + + Log.f3(" (!) Loading on access: " + this); + load(); + } + + return isLoaded(); + } + + + /** + * Load the resource. Called from load() - once only. + * + * @param resource the path / name of a resource + * @throws Exception when some problem prevented the resource from being + * loaded. + */ + protected abstract void loadResource(String resource) throws Exception; + + + @Override + public abstract void destroy(); + + + @Override + public String toString() + { + return Log.str(getClass()) + "(\"" + resource + "\")"; + } + + + @Override + public int hashCode() + { + final int prime = 31; + int result = 1; + result = prime * result + ((resource == null) ? 0 : resource.hashCode()); + return result; + } + + + @Override + public boolean equals(Object obj) + { + if (this == obj) return true; + if (obj == null) return false; + if (!(obj instanceof DeferredResource)) return false; + final DeferredResource other = (DeferredResource) obj; + if (resource == null) { + if (other.resource != null) return false; + } else if (!resource.equals(other.resource)) return false; + return true; + } + + + private boolean isNull() + { + return this instanceof NullResource; + } } diff --git a/src/mightypork/gamecore/render/DisplaySystem.java b/src/mightypork/gamecore/render/DisplaySystem.java index e8b5eab..729c3fa 100644 --- a/src/mightypork/gamecore/render/DisplaySystem.java +++ b/src/mightypork/gamecore/render/DisplaySystem.java @@ -12,6 +12,7 @@ import mightypork.gamecore.control.timing.FpsMeter; import mightypork.gamecore.gui.constraints.NumberConstraint; import mightypork.gamecore.gui.constraints.RectConstraint; import mightypork.utils.logging.Log; +import mightypork.utils.math.coord.ConstraintCoordView; import mightypork.utils.math.coord.Coord; import mightypork.utils.math.coord.Rect; @@ -176,7 +177,7 @@ public class DisplaySystem extends AppModule implements RectConstraint { */ public static Coord getSize() { - return new Coord(getWidth(), getHeight()); + return size; } @@ -227,7 +228,7 @@ public class DisplaySystem extends AppModule implements RectConstraint { @Override public Rect getRect() { - return new Rect(getSize()); + return new Rect(Coord.ZERO, getSize()); } @@ -240,7 +241,7 @@ public class DisplaySystem extends AppModule implements RectConstraint { } /** Screen width constraint */ - public final NumberConstraint width = new NumberConstraint() { + public static final NumberConstraint width = new NumberConstraint() { @Override public double getValue() @@ -250,7 +251,7 @@ public class DisplaySystem extends AppModule implements RectConstraint { }; /** Screen height constaint */ - public final NumberConstraint height = new NumberConstraint() { + public static final NumberConstraint height = new NumberConstraint() { @Override public double getValue() @@ -258,4 +259,6 @@ public class DisplaySystem extends AppModule implements RectConstraint { return getHeight(); } }; + + public static final ConstraintCoordView size = new ConstraintCoordView(width, height, null); } diff --git a/src/mightypork/gamecore/render/Render.java b/src/mightypork/gamecore/render/Render.java index de5a733..cf8674f 100644 --- a/src/mightypork/gamecore/render/Render.java +++ b/src/mightypork/gamecore/render/Render.java @@ -26,9 +26,9 @@ import org.newdawn.slick.util.ResourceLoader; */ public class Render { - private static final Coord AXIS_X = new Coord(1, 0, 0); - private static final Coord AXIS_Y = new Coord(0, 1, 0); - private static final Coord AXIS_Z = new Coord(0, 0, 1); + public static final Coord AXIS_X = new Coord(1, 0, 0).freeze(); + public static final Coord AXIS_Y = new Coord(0, 1, 0).freeze(); + public static final Coord AXIS_Z = new Coord(0, 0, 1).freeze(); /** @@ -54,6 +54,31 @@ public class Render { } + /** + * 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 * @@ -61,7 +86,32 @@ public class Render { */ public static void translate(Coord coord) { - glTranslated(coord.x, coord.y, coord.z); + glTranslated(coord.x(), coord.y(), coord.z()); + } + + + /** + * 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); } @@ -72,7 +122,7 @@ public class Render { */ public static void scale(Coord factor) { - glScaled(factor.x, factor.y, factor.z); + glScaled(factor.x(), factor.y(), factor.z()); } @@ -162,7 +212,7 @@ public class Render { public static void rotate(double angle, Coord axis) { final Coord vec = axis.norm(1); - glRotated(angle, vec.x, vec.y, vec.z); + glRotated(angle, vec.x(), vec.y(), vec.z()); } private static int pushed = 0; @@ -179,8 +229,6 @@ public class Render { Log.w("Suspicious number of state pushes: " + pushed); } -// Log.f3("push : "+pushed); - GL11.glPushAttrib(GL11.GL_ALL_ATTRIB_BITS); GL11.glPushClientAttrib(GL11.GL_ALL_CLIENT_ATTRIB_BITS); GL11.glMatrixMode(GL11.GL_MODELVIEW); @@ -188,10 +236,6 @@ public class Render { GL11.glMatrixMode(GL11.GL_PROJECTION); GL11.glPushMatrix(); GL11.glMatrixMode(GL11.GL_MODELVIEW); - -// GL11.glPushAttrib(GL11.GL_ALL_ATTRIB_BITS); -// GL11.glPushClientAttrib(GL11.GL_ALL_CLIENT_ATTRIB_BITS); -// GL11.glPushMatrix(); } @@ -206,18 +250,30 @@ public class Render { pushed--; -// Log.f3("pop : "+pushed); - GL11.glMatrixMode(GL11.GL_PROJECTION); GL11.glPopMatrix(); GL11.glMatrixMode(GL11.GL_MODELVIEW); GL11.glPopMatrix(); GL11.glPopClientAttrib(); GL11.glPopAttrib(); - -// GL11.glPopMatrix(); -// GL11.glPopClientAttrib(); -// GL11.glPopAttrib(); + } + + + /** + * Store matrix + */ + public static void pushMatrix() + { + GL11.glPushMatrix(); + } + + + /** + * Restore Gl state + */ + public static void popMatrix() + { + GL11.glPopMatrix(); } @@ -254,24 +310,11 @@ public class Render { * Bind texture * * @param texture the texture - * @param linear use linear interpolation for scaling - * @throws RuntimeException if not loaded yet - */ - private static void bindTexture(Texture texture, boolean linear) throws RuntimeException - { - texture.bind(); - } - - - /** - * Bind texture with linear interpolation - * - * @param texture the texture * @throws RuntimeException if not loaded yet */ private static void bindTexture(Texture texture) throws RuntimeException { - bindTexture(texture, false); + texture.bind(); } @@ -280,9 +323,9 @@ public class Render { */ private static void unbindTexture() { - if (TextureImpl.getLastBind() != null) { - TextureImpl.bindNone(); - } + //if (TextureImpl.getLastBind() != null) { + TextureImpl.bindNone(); + //} } @@ -437,11 +480,10 @@ public class Render { */ public static void quadTextured(Rect quad, Rect uvs, Texture texture, RGB tint) { - pushState(); bindTexture(texture); setColor(tint); quadUV(quad, uvs); - popState(); + unbindTexture(); } @@ -466,7 +508,7 @@ public class Render { */ public static void quadTextured(Rect quad, Texture texture) { - quadTextured(quad, Rect.one(), texture, RGB.WHITE); + quadTextured(quad, Rect.ONE, texture, RGB.WHITE); } @@ -505,7 +547,7 @@ public class Render { glLoadIdentity(); final Coord s = DisplaySystem.getSize(); glViewport(0, 0, s.xi(), s.yi()); - glOrtho(0, s.x, (DisplaySystem.yAxisDown ? 1 : -1) * s.y, 0, -1000, 1000); + glOrtho(0, s.x(), (DisplaySystem.yAxisDown ? 1 : -1) * s.y(), 0, -1000, 1000); // back to modelview glMatrixMode(GL_MODELVIEW); @@ -523,7 +565,7 @@ public class Render { glShadeModel(GL_SMOOTH); glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); } } diff --git a/src/mightypork/gamecore/render/fonts/FontBank.java b/src/mightypork/gamecore/render/fonts/FontBank.java index 73094ae..c7b9cab 100644 --- a/src/mightypork/gamecore/render/fonts/FontBank.java +++ b/src/mightypork/gamecore/render/fonts/FontBank.java @@ -6,6 +6,8 @@ import java.util.HashMap; import mightypork.gamecore.control.AppAccess; import mightypork.gamecore.control.AppAdapter; import mightypork.gamecore.control.bus.events.ResourceLoadRequest; +import mightypork.gamecore.render.fonts.impl.DeferredFont; +import mightypork.gamecore.render.fonts.impl.NullFont; import mightypork.utils.logging.Log; import org.newdawn.slick.opengl.Texture; diff --git a/src/mightypork/gamecore/render/fonts/FontRenderer.java b/src/mightypork/gamecore/render/fonts/FontRenderer.java index f42753c..c592078 100644 --- a/src/mightypork/gamecore/render/fonts/FontRenderer.java +++ b/src/mightypork/gamecore/render/fonts/FontRenderer.java @@ -6,8 +6,6 @@ import mightypork.utils.math.color.RGB; import mightypork.utils.math.coord.Coord; import mightypork.utils.math.coord.Rect; -import org.lwjgl.opengl.GL11; - /** * Font renderer @@ -17,7 +15,6 @@ import org.lwjgl.opengl.GL11; public class FontRenderer { private GLFont font; - private boolean nativeRes = false; public static enum Align { @@ -45,20 +42,6 @@ public class FontRenderer { } - /** - * Use size specified during font init instead of size provided by - * {@link GLFont} instance (measured from tile heights.
- * This is better when the font is drawn in original size, but can cause - * weird artifacts if the font is scaled up. - * - * @param use use it - */ - public void usePtSize(boolean use) - { - nativeRes = use; - } - - /** * Get region needed to draw text at size * @@ -81,13 +64,13 @@ public class FontRenderer { */ public double getWidth(String text, double height) { - return getNeededSpace(text, height).x; + return getNeededSpace(text, height).x(); } private double getScale(double height) { - return height / (nativeRes ? font.getSize() : font.getGlyphHeight()); + return height / font.getHeight(); } @@ -123,15 +106,14 @@ public class FontRenderer { */ public void draw(String text, Coord pos, double height, RGB color) { - //Render.pushState(); + Render.pushMatrix(); - //GL11.glEnable(GL11.GL_TEXTURE_2D); Render.translate(pos.round()); Render.scaleXY(getScale(height)); font.draw(text, color); - //Render.popState(); + Render.popMatrix(); } diff --git a/src/mightypork/gamecore/render/fonts/GLFont.java b/src/mightypork/gamecore/render/fonts/GLFont.java index c2b824f..1836bc7 100644 --- a/src/mightypork/gamecore/render/fonts/GLFont.java +++ b/src/mightypork/gamecore/render/fonts/GLFont.java @@ -1,7 +1,6 @@ package mightypork.gamecore.render.fonts; -import mightypork.gamecore.render.textures.FilterMode; import mightypork.utils.math.color.RGB; import mightypork.utils.math.coord.Coord; @@ -14,9 +13,9 @@ import mightypork.utils.math.coord.Coord; public interface GLFont { /** - * Draw string at position + * Draw without scaling at (0, 0) in given color. * - * @param text string to draw + * @param text text to draw * @param color draw color */ void draw(String text, RGB color); @@ -34,7 +33,7 @@ public interface GLFont { /** * @return font height */ - int getGlyphHeight(); + int getHeight(); /** @@ -48,20 +47,4 @@ public interface GLFont { * @return specified font size */ int getSize(); - - /** - * Set used filtering - * - * @param filter font filtering mode - */ - void setFiltering(FilterMode filter); - - - /** - * Get used filter mode - * - * @return filter mode - */ - FilterMode getFiltering(); - } diff --git a/src/mightypork/gamecore/render/fonts/SlickFont.java b/src/mightypork/gamecore/render/fonts/SlickFont.java deleted file mode 100644 index 086fe9d..0000000 --- a/src/mightypork/gamecore/render/fonts/SlickFont.java +++ /dev/null @@ -1,134 +0,0 @@ -package mightypork.gamecore.render.fonts; - - -import static org.lwjgl.opengl.GL11.*; - -import java.awt.Font; - -import mightypork.gamecore.render.Render; -import mightypork.gamecore.render.textures.FilterMode; -import mightypork.utils.math.color.RGB; -import mightypork.utils.math.coord.Coord; - -import org.newdawn.slick.Color; -import org.newdawn.slick.TrueTypeFont; - - -/** - * Wrapper for slick font - * - * @author MightyPork - */ -public class SlickFont implements GLFont { - - private final TrueTypeFont ttf; - private FilterMode filter; - private final int fsize; - - - /** - * A font with ASCII and extra chars - * - * @param font font to load - * @param filtering filtering mode - * @param extraChars extra chars to load - */ - public SlickFont(Font font, FilterMode filtering, String extraChars) { - - this.filter = filtering; - this.fsize = font.getSize(); - ttf = new TrueTypeFont(font, true, stripASCII(extraChars)); - } - - - - @Override - public void setFiltering(FilterMode filter) - { - this.filter = filter; - } - - - private static char[] stripASCII(String chars) - { - if (chars == null) return null; - - final StringBuilder sb = new StringBuilder(); - for (final char c : chars.toCharArray()) { - if (c <= 255) continue; // already included in default set - sb.append(c); - } - - return sb.toString().toCharArray(); - } - - - private void prepareForRender() - { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter.num); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter.num); - } - - - /** - * Draw in color - * - * @param str string to draw - * @param color text color - */ - @Override - public void draw(String str, RGB color) - { - Render.pushState(); - - prepareForRender(); - ttf.drawString(0, 0, str, rgbToSlickColor(color)); - - Render.popState(); - } - - - private static Color rgbToSlickColor(RGB rgb) - { - return new Color((float) rgb.r, (float) rgb.g, (float) rgb.b, (float) rgb.a); - } - - - @Override - public Coord getNeededSpace(String text) - { - return new Coord(getWidth(text), getGlyphHeight()); - } - - - @Override - public int getGlyphHeight() - { - return ttf.getHeight(); - } - - - @Override - public int getWidth(String text) - { - return ttf.getWidth(text); - } - - - @Override - public int getSize() - { - return fsize; - } - - - - @Override - public FilterMode getFiltering() - { - return filter; - } - -} diff --git a/src/mightypork/gamecore/render/fonts/impl/CachedFont.java b/src/mightypork/gamecore/render/fonts/impl/CachedFont.java new file mode 100644 index 0000000..c9df7b2 --- /dev/null +++ b/src/mightypork/gamecore/render/fonts/impl/CachedFont.java @@ -0,0 +1,430 @@ +package mightypork.gamecore.render.fonts.impl; + + +import static org.lwjgl.opengl.GL11.*; + +import java.awt.Color; +import java.awt.FontMetrics; +import java.awt.Graphics2D; +import java.awt.RenderingHints; +import java.awt.image.BufferedImage; +import java.awt.image.DataBuffer; +import java.awt.image.DataBufferByte; +import java.awt.image.DataBufferInt; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.IntBuffer; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import mightypork.gamecore.render.fonts.GLFont; +import mightypork.gamecore.render.textures.FilterMode; +import mightypork.utils.logging.Log; +import mightypork.utils.math.color.RGB; +import mightypork.utils.math.coord.Coord; + +import org.lwjgl.BufferUtils; +import org.lwjgl.util.glu.GLU; +import org.newdawn.slick.opengl.GLUtils; + + +/** + * A TrueType font renderer with backing texture. + * + * @author James Chambers (Jimmy) + * @author Jeremy Adams (elias4444) + * @author Kevin Glass (kevglass) + * @author Peter Korzuszek (genail) + * @author David Aaron Muhar (bobjob) + * @author MightyPork + */ +public class CachedFont implements GLFont { + + private class CharTile { + + public int width; + public int height; + public int texPosX; + public int texPosY; + } + + /* char bank */ + private final Map chars = new HashMap<>(255); + + /* use antialiasing for rendering */ + private final boolean antiAlias; + + /* loaded font size (requested) */ + private final int fontSize; + + /* actual height of drawn glyphs */ + private int fontHeight; + + /* texture id */ + private int textureID; + + /* texture width */ + private int textureWidth; + + /* texture height */ + private int textureHeight; + + /* AWT font source */ + private final java.awt.Font font; + + private final FilterMode filter; + + + /** + * Make a font + * + * @param font original awt font to load + * @param antialias use antialiasing when rendering to cache texture + * @param filter used Gl filter + * @param chars chars to load + */ + public CachedFont(java.awt.Font font, boolean antialias, FilterMode filter, String chars) { + this(font, antialias, filter, chars.toCharArray()); + } + + + /** + * Make a font + * + * @param font original awt font to load + * @param antialias use antialiasing when rendering to cache texture + * @param filter used Gl filter + * @param chars chars to load + */ + public CachedFont(java.awt.Font font, boolean antialias, FilterMode filter, char[] chars) { + GLUtils.checkGLContext(); + + this.font = font; + this.filter = filter; + this.fontSize = font.getSize(); + this.antiAlias = antialias; + + createSet(chars); + } + + + /** + * Create a BufferedImage of the given character + * + * @param ch the character + * @return BufferedImage containing the drawn character + */ + private BufferedImage getFontImage(char ch) + { + FontMetrics metrics; + BufferedImage img; + Graphics2D g; + + // Create a temporary image to extract the character's size + img = new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB); + + g = (Graphics2D) img.getGraphics(); + if (antiAlias == true) g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + g.setFont(font); + + metrics = g.getFontMetrics(); + + final int charwidth = Math.max(1, metrics.charWidth(ch)); + final int charheight = Math.max(fontSize, metrics.getHeight()); + + // Create another image holding the character we are creating + final BufferedImage fontImage = new BufferedImage(charwidth, charheight, BufferedImage.TYPE_INT_ARGB); + + g = (Graphics2D) fontImage.getGraphics(); + if (antiAlias == true) g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + g.setFont(font); + g.setColor(Color.WHITE); + g.drawString(String.valueOf(ch), 0, metrics.getAscent()); + + return fontImage; + } + + + private void createSet(char[] charsToLoad) + { + try { + class LoadedGlyph { + + public char c; + public BufferedImage image; + public int width; + public int height; + + + public LoadedGlyph(char c, BufferedImage image) { + this.image = image; + this.c = c; + this.width = image.getWidth(); + this.height = image.getHeight(); + } + } + + final List glyphs = new ArrayList<>(); + final List loaded = new ArrayList<>(); + for (final char ch : charsToLoad) { + if (!loaded.contains(ch)) { + glyphs.add(new LoadedGlyph(ch, getFontImage(ch))); + loaded.add(ch); + } + } + + int lineHeight = 0; + + int beginX = 0, beginY = 0; + int canvasW = 128, canvasH = 128; + + boolean needsLarger = false; + + // find smallest 2^x size for texture + while (true) { + needsLarger = false; + + for (final LoadedGlyph glyph : glyphs) { + if (beginX + glyph.width > canvasW) { + beginY += lineHeight; + lineHeight = 0; + beginX = 0; + } + + if (lineHeight < glyph.height) { + lineHeight = glyph.height; + } + + if (beginY + lineHeight > canvasH) { + needsLarger = true; + break; + } + + // draw. + beginX += glyph.width; + } + + if (needsLarger) { + canvasW *= 2; + canvasH *= 2; + beginX = 0; + beginY = 0; + lineHeight = 0; + } else { + Log.f3(String.format("Generating font texture: %d×%d", canvasW, canvasH)); + break; + } + } + + textureWidth = canvasW; + textureHeight = canvasH; + + BufferedImage imag = new BufferedImage(textureWidth, textureHeight, BufferedImage.TYPE_INT_ARGB); + final Graphics2D g = (Graphics2D) imag.getGraphics(); + + g.setColor(new Color(0, 0, 0, 1)); + g.fillRect(0, 0, textureWidth, textureHeight); + + int rowHeight = 0, posX = 0, posY = 0; + + for (final LoadedGlyph glyph : glyphs) { + final CharTile cht = new CharTile(); + + cht.width = glyph.width; + cht.height = glyph.height; + + if (posX + cht.width >= textureWidth) { + posX = 0; + posY += rowHeight; + rowHeight = 0; + } + + cht.texPosX = posX; + cht.texPosY = posY; + + if (cht.height > fontHeight) { + fontHeight = cht.height; + } + + if (cht.height > rowHeight) { + rowHeight = cht.height; + } + + // Draw it here + g.drawImage(glyph.image, posX, posY, null); + + posX += cht.width; + + chars.put(glyph.c, cht); + } + + textureID = loadImage(imag); + + imag = null; + + } catch (final Exception e) { + Log.e("Failed to load font.", e); + } + } + + + private int loadImage(BufferedImage bufferedImage) + { + try { + final short width = (short) bufferedImage.getWidth(); + final short height = (short) bufferedImage.getHeight(); + final int bpp = (byte) bufferedImage.getColorModel().getPixelSize(); + + ByteBuffer byteBuffer; + final DataBuffer db = bufferedImage.getData().getDataBuffer(); + if (db instanceof DataBufferInt) { + final int intI[] = ((DataBufferInt) (bufferedImage.getData().getDataBuffer())).getData(); + final byte newI[] = new byte[intI.length * 4]; + for (int i = 0; i < intI.length; i++) { + final byte b[] = intToByteArray(intI[i]); + final int newIndex = i * 4; + + newI[newIndex] = b[1]; + newI[newIndex + 1] = b[2]; + newI[newIndex + 2] = b[3]; + newI[newIndex + 3] = b[0]; + } + + byteBuffer = ByteBuffer.allocateDirect(width * height * (bpp / 8)).order(ByteOrder.nativeOrder()).put(newI); + } else { + byteBuffer = ByteBuffer.allocateDirect(width * height * (bpp / 8)).order(ByteOrder.nativeOrder()).put(((DataBufferByte) (bufferedImage.getData().getDataBuffer())).getData()); + } + + byteBuffer.flip(); + + final int internalFormat = GL_RGBA8, format = GL_RGBA; + final IntBuffer textureId = BufferUtils.createIntBuffer(1); + + glGenTextures(textureId); + glBindTexture(GL_TEXTURE_2D, textureId.get(0)); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter.num); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + + GLU.gluBuild2DMipmaps(GL_TEXTURE_2D, internalFormat, width, height, format, GL_UNSIGNED_BYTE, byteBuffer); + return textureId.get(0); + + } catch (final Exception e) { + Log.e("Failed to load font.", e); + } + + return -1; + } + + + private static byte[] intToByteArray(int value) + { + return new byte[] { (byte) (value >>> 24), (byte) (value >>> 16), (byte) (value >>> 8), (byte) value }; + } + + + private void drawQuad(float xmin, float ymin, float xmax, float ymax, float txmin, float tymin, float txmax, float tymax) + { + final float draw_h = xmax - xmin; + final float draw_w = ymax - ymin; + final float txmin01 = txmin / textureWidth; + final float tymin01 = tymin / textureHeight; + final float twidth01 = ((txmax - txmin) / textureWidth); + final float theight01 = ((tymax - tymin) / textureHeight); + + glTexCoord2f(txmin01, tymin01); + glVertex2f(xmin, ymin); + + glTexCoord2f(txmin01, tymin01 + theight01); + glVertex2f(xmin, ymin + draw_w); + + glTexCoord2f(txmin01 + twidth01, tymin01 + theight01); + glVertex2f(xmin + draw_h, ymin + draw_w); + + glTexCoord2f(txmin01 + twidth01, tymin01); + glVertex2f(xmin + draw_h, ymin); + } + + + /** + * Get size needed to draw given string + * + * @param text drawn text + * @return needed width + */ + @Override + public int getWidth(String text) + { + int totalwidth = 0; + CharTile ch = null; + for (int i = 0; i < text.length(); i++) { + + ch = chars.get(text.charAt(i)); + + if (ch != null) totalwidth += ch.width; + } + return totalwidth; + } + + + @Override + public int getHeight() + { + return fontHeight; + } + + + @Override + public int getSize() + { + return fontSize; + } + + + @Override + public void draw(String text, RGB color) + { + GLUtils.checkGLContext(); + + glPushAttrib(GL_ENABLE_BIT); + glEnable(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, textureID); + glColor4d(color.r, color.g, color.b, color.a); + glBegin(GL_QUADS); + + CharTile chtx = null; + char charCurrent; + + glBegin(GL_QUADS); + + int totalwidth = 0; + for (int i = 0; i < text.length(); i++) { + charCurrent = text.charAt(i); + + chtx = chars.get(charCurrent); + + if (chtx != null) { + drawQuad((totalwidth), 0, (totalwidth + chtx.width), (chtx.height), chtx.texPosX, chtx.texPosY, chtx.texPosX + chtx.width, chtx.texPosY + chtx.height); + totalwidth += chtx.width; + } + } + + glEnd(); + glPopAttrib(); + } + + + @Override + public Coord getNeededSpace(String text) + { + return new Coord(getWidth(text), getHeight()); + } + +} diff --git a/src/mightypork/gamecore/render/fonts/DeferredFont.java b/src/mightypork/gamecore/render/fonts/impl/DeferredFont.java similarity index 65% rename from src/mightypork/gamecore/render/fonts/DeferredFont.java rename to src/mightypork/gamecore/render/fonts/impl/DeferredFont.java index 9cacac9..01252b2 100644 --- a/src/mightypork/gamecore/render/fonts/DeferredFont.java +++ b/src/mightypork/gamecore/render/fonts/impl/DeferredFont.java @@ -1,15 +1,14 @@ -package mightypork.gamecore.render.fonts; +package mightypork.gamecore.render.fonts.impl; -import static org.lwjgl.opengl.GL11.*; - import java.awt.Font; import java.awt.FontFormatException; import java.io.IOException; import java.io.InputStream; -import mightypork.gamecore.loading.BaseDeferredResource; +import mightypork.gamecore.loading.DeferredResource; import mightypork.gamecore.loading.MustLoadInMainThread; +import mightypork.gamecore.render.fonts.GLFont; import mightypork.gamecore.render.textures.FilterMode; import mightypork.utils.files.FileUtils; import mightypork.utils.logging.LoggedName; @@ -24,7 +23,7 @@ import mightypork.utils.math.coord.Coord; */ @MustLoadInMainThread @LoggedName(name = "Font") -public class DeferredFont extends BaseDeferredResource implements GLFont { +public class DeferredFont extends DeferredResource implements GLFont { public static enum FontStyle { @@ -38,22 +37,24 @@ public class DeferredFont extends BaseDeferredResource implements GLFont { } } - private SlickFont font = null; - private final double size; - private final FontStyle style; - private final String extraChars; + private GLFont font = null; + private double size; + private FontStyle style; + private String chars; private FilterMode filter; + private boolean antialias; /** - * A font from resource + * A font from resource; setters shall be used to specify parameters in + * greater detail. * * @param resourcePath resource to load - * @param extraChars extra chars (0-255 loaded by default) + * @param chars chars to load; null to load basic chars only * @param size size (px) */ - public DeferredFont(String resourcePath, String extraChars, double size) { - this(resourcePath, extraChars, size, FontStyle.PLAIN, FilterMode.NEAREST); + public DeferredFont(String resourcePath, String chars, double size) { + this(resourcePath, chars, size, FontStyle.PLAIN, true, FilterMode.LINEAR); } @@ -61,39 +62,64 @@ public class DeferredFont extends BaseDeferredResource implements GLFont { * A font from resource * * @param resourcePath resource to load - * @param extraChars extra chars (0-255 loaded by default) - * @param size size (pt) + * @param chars chars to load; null to load basic chars only + * @param size size (px) * @param style font style + * @param antialias use antialiasing for caching texture + * @param filter gl filtering mode */ - public DeferredFont(String resourcePath, String extraChars, double size, FontStyle style) { - this(resourcePath, extraChars, size, style, FilterMode.NEAREST); + public DeferredFont(String resourcePath, String chars, double size, FontStyle style, boolean antialias, FilterMode filter) { + super(resourcePath); + this.size = size; + this.style = style; + this.chars = chars; + this.filter = filter; + this.antialias = antialias; } - /** - * A font from resource - * - * @param resourcePath resource to load - * @param extraChars extra chars (0-255 loaded by default) - * @param size size (pt) - * @param style font style - * @param filter gl filtering mode - */ - public DeferredFont(String resourcePath, String extraChars, double size, FontStyle style, FilterMode filter) { - super(resourcePath); + public void setFont(GLFont font) + { + this.font = font; + } + + + public void setSize(double size) + { this.size = size; + } + + + public void setStyle(FontStyle style) + { this.style = style; - this.extraChars = extraChars; + } + + + public void setChars(String chars) + { + this.chars = chars; + } + + + public void setFilter(FilterMode filter) + { this.filter = filter; } + public void setAntialias(boolean antialias) + { + this.antialias = antialias; + } + + @Override protected synchronized final void loadResource(String path) throws FontFormatException, IOException { final Font awtFont = getAwtFont(path, (float) size, style.numval); - - font = new SlickFont(awtFont, filter, extraChars); + + font = new CachedFont(awtFont, antialias, filter, chars); } @@ -109,7 +135,6 @@ public class DeferredFont extends BaseDeferredResource implements GLFont { */ protected Font getAwtFont(String resource, float size, int style) throws FontFormatException, IOException { - try (InputStream in = FileUtils.getResource(resource)) { Font awtFont = Font.createFont(Font.TRUETYPE_FONT, in); @@ -119,7 +144,6 @@ public class DeferredFont extends BaseDeferredResource implements GLFont { return awtFont; } - } @@ -157,11 +181,11 @@ public class DeferredFont extends BaseDeferredResource implements GLFont { * @return font height */ @Override - public int getGlyphHeight() + public int getHeight() { if (!ensureLoaded()) return 0; - return font.getGlyphHeight(); + return font.getHeight(); } @@ -187,20 +211,11 @@ public class DeferredFont extends BaseDeferredResource implements GLFont { // this will have to suffice font = null; } - - - @Override + + public void setFiltering(FilterMode filter) { this.filter = filter; - - if(isLoaded()) font.setFiltering(filter); - } - - @Override - public FilterMode getFiltering() - { - return filter; } } diff --git a/src/mightypork/gamecore/render/fonts/DeferredFontNative.java b/src/mightypork/gamecore/render/fonts/impl/DeferredFontNative.java similarity index 51% rename from src/mightypork/gamecore/render/fonts/DeferredFontNative.java rename to src/mightypork/gamecore/render/fonts/impl/DeferredFontNative.java index 6be50d4..a8eb81a 100644 --- a/src/mightypork/gamecore/render/fonts/DeferredFontNative.java +++ b/src/mightypork/gamecore/render/fonts/impl/DeferredFontNative.java @@ -1,4 +1,4 @@ -package mightypork.gamecore.render.fonts; +package mightypork.gamecore.render.fonts.impl; import java.awt.Font; @@ -17,31 +17,6 @@ import mightypork.utils.logging.LoggedName; @LoggedName(name = "FontNative") public class DeferredFontNative extends DeferredFont { - /** - * A font from OS, found by name - * - * @param fontName font family name - * @param extraChars extra chars (0-255 loaded by default) - * @param size size (pt) - */ - public DeferredFontNative(String fontName, String extraChars, double size) { - super(fontName, extraChars, size); - } - - - /** - * A font from OS, found by name - * - * @param fontName font family name - * @param extraChars extra chars (0-255 loaded by default) - * @param size size (pt) - * @param style font style - */ - public DeferredFontNative(String fontName, String extraChars, double size, FontStyle style) { - super(fontName, extraChars, size, style); - } - - /** * A font from OS, found by name * @@ -49,10 +24,11 @@ public class DeferredFontNative extends DeferredFont { * @param extraChars extra chars (0-255 loaded by default) * @param size size (pt) * @param style font style + * @param antialias use antialiasing when drawn on the cache texture * @param filter GL filtering mode */ - public DeferredFontNative(String fontName, String extraChars, double size, FontStyle style, FilterMode filter) { - super(fontName, extraChars, size, style, filter); + public DeferredFontNative(String fontName, String extraChars, double size, FontStyle style, boolean antialias, FilterMode filter) { + super(fontName, extraChars, size, style, antialias, filter); } diff --git a/src/mightypork/gamecore/render/fonts/NullFont.java b/src/mightypork/gamecore/render/fonts/impl/NullFont.java similarity index 69% rename from src/mightypork/gamecore/render/fonts/NullFont.java rename to src/mightypork/gamecore/render/fonts/impl/NullFont.java index 4611f7a..392e575 100644 --- a/src/mightypork/gamecore/render/fonts/NullFont.java +++ b/src/mightypork/gamecore/render/fonts/impl/NullFont.java @@ -1,7 +1,7 @@ -package mightypork.gamecore.render.fonts; +package mightypork.gamecore.render.fonts.impl; -import mightypork.gamecore.render.textures.FilterMode; +import mightypork.gamecore.render.fonts.GLFont; import mightypork.utils.logging.Log; import mightypork.utils.math.color.RGB; import mightypork.utils.math.coord.Coord; @@ -29,7 +29,7 @@ public class NullFont implements GLFont { @Override - public int getGlyphHeight() + public int getHeight() { return 0; } @@ -47,19 +47,5 @@ public class NullFont implements GLFont { { return 0; } - - - @Override - public void setFiltering(FilterMode filter) - { - // nope - } - - - @Override - public FilterMode getFiltering() - { - return null; - } } diff --git a/src/mightypork/gamecore/render/textures/DeferredTexture.java b/src/mightypork/gamecore/render/textures/DeferredTexture.java index 3837060..1b31483 100644 --- a/src/mightypork/gamecore/render/textures/DeferredTexture.java +++ b/src/mightypork/gamecore/render/textures/DeferredTexture.java @@ -1,7 +1,7 @@ package mightypork.gamecore.render.textures; -import mightypork.gamecore.loading.BaseDeferredResource; +import mightypork.gamecore.loading.DeferredResource; import mightypork.gamecore.loading.MustLoadInMainThread; import mightypork.gamecore.render.Render; import mightypork.utils.logging.LoggedName; @@ -18,10 +18,10 @@ import org.newdawn.slick.opengl.Texture; */ @MustLoadInMainThread @LoggedName(name = "Texture") -public class DeferredTexture extends BaseDeferredResource implements FilteredTexture { +public class DeferredTexture extends DeferredResource implements FilteredTexture { private Texture backingTexture; - private FilterMode filter_min = FilterMode.NEAREST; + private FilterMode filter_min = FilterMode.LINEAR; private FilterMode filter_mag = FilterMode.NEAREST; private WrapMode wrap = WrapMode.CLAMP; @@ -90,7 +90,6 @@ public class DeferredTexture extends BaseDeferredResource implements FilteredTex GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, filter_mag.num); bindRaw(); - } diff --git a/src/mightypork/gamecore/render/textures/TextureBank.java b/src/mightypork/gamecore/render/textures/TextureBank.java index 0334f3d..a69d1ef 100644 --- a/src/mightypork/gamecore/render/textures/TextureBank.java +++ b/src/mightypork/gamecore/render/textures/TextureBank.java @@ -33,14 +33,19 @@ public class TextureBank extends AppAdapter { /** - * Load a {@link Texture} from resource, with filters LINEAR and wrap CLAMP + * Load a {@link Texture} * * @param key texture key - * @param resourcePath texture resource path + * @param texture texture to load */ - public void loadTexture(String key, String resourcePath) + public void loadTexture(String key, DeferredTexture texture) { - loadTexture(key, resourcePath, FilterMode.LINEAR, FilterMode.NEAREST, WrapMode.CLAMP); + getEventBus().send(new ResourceLoadRequest(texture)); + + textures.put(key, texture); + lastTx = texture; + + makeQuad(key, Rect.ONE); } @@ -55,16 +60,11 @@ public class TextureBank extends AppAdapter { */ public void loadTexture(String key, String resourcePath, FilterMode filter_min, FilterMode filter_mag, WrapMode wrap) { - final DeferredTexture tx = new DeferredTexture(resourcePath); - tx.setFilter(filter_min, filter_mag); - tx.setWrap(wrap); - - getEventBus().send(new ResourceLoadRequest(tx)); - - textures.put(key, tx); - lastTx = tx; + final DeferredTexture texture = new DeferredTexture(resourcePath); + texture.setFilter(filter_min, filter_mag); + texture.setWrap(wrap); - makeQuad(key, Rect.one()); + loadTexture(key, texture); } diff --git a/src/mightypork/gamecore/render/textures/TxQuad.java b/src/mightypork/gamecore/render/textures/TxQuad.java index b3ca54e..8024891 100644 --- a/src/mightypork/gamecore/render/textures/TxQuad.java +++ b/src/mightypork/gamecore/render/textures/TxQuad.java @@ -70,11 +70,11 @@ public class TxQuad { /** * @param tx Texture - * @param uvs Rect of texture UVs (0-1) + * @param uvs Rect of texture UVs (0-1); will be stored as is. */ public TxQuad(Texture tx, Rect uvs) { this.tx = tx; - this.uvs = uvs.copy(); + this.uvs = uvs.view(); } @@ -85,7 +85,7 @@ public class TxQuad { */ public TxQuad(TxQuad txQuad) { this.tx = txQuad.tx; - this.uvs = txQuad.uvs.copy(); + this.uvs = txQuad.uvs.view(); } diff --git a/src/mightypork/rogue/App.java b/src/mightypork/rogue/App.java index 2e2bd78..8687e49 100644 --- a/src/mightypork/rogue/App.java +++ b/src/mightypork/rogue/App.java @@ -64,7 +64,7 @@ public class App extends BaseApp { screens.add(new ScreenTestFont(this)); screens.add(new ScreenTestRender(this)); - screens.showScreen("test.render"); + screens.showScreen("test.cat"); } diff --git a/src/mightypork/rogue/Res.java b/src/mightypork/rogue/Res.java index 085f403..e4dd9b3 100644 --- a/src/mightypork/rogue/Res.java +++ b/src/mightypork/rogue/Res.java @@ -6,10 +6,11 @@ import mightypork.gamecore.audio.players.EffectPlayer; import mightypork.gamecore.audio.players.LoopPlayer; import mightypork.gamecore.control.AppAccess; import mightypork.gamecore.control.BaseApp; -import mightypork.gamecore.render.fonts.DeferredFont; -import mightypork.gamecore.render.fonts.DeferredFont.FontStyle; import mightypork.gamecore.render.fonts.FontBank; import mightypork.gamecore.render.fonts.GLFont; +import mightypork.gamecore.render.fonts.Glyphs; +import mightypork.gamecore.render.fonts.impl.DeferredFont; +import mightypork.gamecore.render.textures.DeferredTexture; import mightypork.gamecore.render.textures.FilterMode; import mightypork.gamecore.render.textures.TextureBank; import mightypork.gamecore.render.textures.TxQuad; @@ -54,23 +55,25 @@ public class Res { private static void loadFonts() { - //@formatter:off - fonts.loadFont( - "default", - new DeferredFont("/res/font/PolygonPixel5x7Standard.ttf", - null, - 16, - FontStyle.PLAIN, - FilterMode.NEAREST - ) - ); - //@formatter:on + DeferredFont font; + + font = new DeferredFont("/res/font/PolygonPixel5x7Standard.ttf", Glyphs.basic, 16); + font.setAntialias(true); + font.setFilter(FilterMode.NEAREST); + fonts.loadFont("default", font); + } private static void loadTextures() { - textures.loadTexture("test.kitten", "/res/img/kitten.png", FilterMode.LINEAR, FilterMode.NEAREST, WrapMode.CLAMP); + DeferredTexture texture; + + texture = new DeferredTexture("/res/img/kitten.png"); + texture.setFilter(FilterMode.LINEAR); + texture.setWrap(WrapMode.CLAMP); + textures.loadTexture("test.kitten", texture); + } diff --git a/src/mightypork/rogue/screens/LayerFps.java b/src/mightypork/rogue/screens/LayerFps.java index 0c4253e..92f15c8 100644 --- a/src/mightypork/rogue/screens/LayerFps.java +++ b/src/mightypork/rogue/screens/LayerFps.java @@ -2,7 +2,6 @@ package mightypork.rogue.screens; import static mightypork.gamecore.gui.constraints.Constraints.*; -import static org.lwjgl.opengl.GL11.*; import mightypork.gamecore.gui.components.painters.TextPainter; import mightypork.gamecore.gui.constraints.RectConstraint; import mightypork.gamecore.gui.screens.Screen; @@ -11,6 +10,7 @@ import mightypork.gamecore.render.fonts.FontRenderer.Align; import mightypork.gamecore.render.fonts.GLFont; import mightypork.rogue.Res; import mightypork.utils.math.color.RGB; +import mightypork.utils.math.coord.Coord; import mightypork.utils.string.StringProvider; @@ -32,11 +32,13 @@ public class LayerFps extends ScreenLayer { }; final GLFont font = Res.getFont("default"); - + final RectConstraint constraint = _round(_move(_grow_down(_right_top(this), 32), -8, 8)); tp = new TextPainter(font, Align.RIGHT, RGB.WHITE, text); tp.setContext(constraint); + + tp.setShadow(RGB.BLACK, Coord.at(1, 1)); } diff --git a/src/mightypork/rogue/screens/test_cat_sound/LayerFlyingCat.java b/src/mightypork/rogue/screens/test_cat_sound/LayerFlyingCat.java index 3d2557b..ae0bd82 100644 --- a/src/mightypork/rogue/screens/test_cat_sound/LayerFlyingCat.java +++ b/src/mightypork/rogue/screens/test_cat_sound/LayerFlyingCat.java @@ -9,7 +9,6 @@ import mightypork.gamecore.control.bus.events.MouseButtonEvent; import mightypork.gamecore.control.timing.Updateable; import mightypork.gamecore.gui.components.painters.ImagePainter; import mightypork.gamecore.gui.components.painters.TextPainter; -import mightypork.gamecore.gui.constraints.RectConstraint; import mightypork.gamecore.gui.screens.Screen; import mightypork.gamecore.gui.screens.ScreenLayer; import mightypork.gamecore.input.KeyStroke; @@ -40,17 +39,20 @@ public class LayerFlyingCat extends ScreenLayer implements Updateable, MouseButt xPos.setTo(DisplaySystem.getWidth() / 2); yPos.setTo(DisplaySystem.getHeight() / 2); - final RectConstraint catbox = _centered(_box(size, size), xPos, yPos); cat = new ImagePainter(Res.getTxQuad("test.kitten")); - cat.setContext(catbox); + cat.setContext(_centered(_box(size, size), xPos, yPos)); - final RectConstraint fpsbox = _centered(_box(64, 64), _mouseX, _mouseY); - - tp = new TextPainter(Res.getFont("default"), Align.CENTER, RGB.YELLOW, "Meow"); - - tp.setContext(fpsbox); + tp = new TextPainter(Res.getFont("default")); + tp.setAlign(Align.CENTER); + tp.setColor(RGB.YELLOW); + tp.setText("Meow!"); + tp.setShadow(RGB.dark(0.8), Coord.at(2, 2)); + tp.setContext(_centered(_box(64, 64), _mouseX, _mouseY)); + /* + * Register keys + */ bindKeyStroke(new KeyStroke(Keys.KEY_RETURN), new Runnable() { @Override @@ -69,6 +71,8 @@ public class LayerFlyingCat extends ScreenLayer implements Updateable, MouseButt size.update(delta); xPos.update(delta); yPos.update(delta); + + System.out.println(cat.getRect()); } @@ -81,8 +85,8 @@ public class LayerFlyingCat extends ScreenLayer implements Updateable, MouseButt final double t = 2; size.fadeTo(100 + rand.nextInt(700), t / 2D); - xPos.fadeTo(pos.x, t); - yPos.fadeTo(pos.y, t); + xPos.fadeTo(pos.x(), t); + yPos.fadeTo(pos.y(), t); } diff --git a/src/mightypork/rogue/screens/test_cat_sound/ScreenTestCat.java b/src/mightypork/rogue/screens/test_cat_sound/ScreenTestCat.java index 26bdb5b..7ac1947 100644 --- a/src/mightypork/rogue/screens/test_cat_sound/ScreenTestCat.java +++ b/src/mightypork/rogue/screens/test_cat_sound/ScreenTestCat.java @@ -62,4 +62,11 @@ public class ScreenTestCat extends LayeredScreen { return "test.cat"; } + + @Override + protected void renderScreen() + { + + super.renderScreen(); + } } diff --git a/src/mightypork/utils/logging/Log.java b/src/mightypork/utils/logging/Log.java index e3d29fe..948de66 100644 --- a/src/mightypork/utils/logging/Log.java +++ b/src/mightypork/utils/logging/Log.java @@ -62,7 +62,11 @@ public class Log { */ public static void w(String msg) { - if (staticLogging && ready()) main.w(msg); + if (staticLogging && ready()) { + main.w(msg); + } else { + System.err.println(msg); + } } @@ -73,7 +77,11 @@ public class Log { */ public static void e(String msg) { - if (staticLogging && ready()) main.e(msg); + if (staticLogging && ready()) { + main.e(msg); + } else { + System.err.println(msg); + } } @@ -85,7 +93,12 @@ public class Log { */ public static void e(String msg, Throwable thrown) { - if (staticLogging && ready()) main.e(msg, thrown); + if (staticLogging && ready()) { + main.e(msg, thrown); + } else { + System.err.println(msg); + thrown.printStackTrace(); + } } @@ -96,7 +109,11 @@ public class Log { */ public static void e(Throwable thrown) { - if (staticLogging && ready()) main.e(thrown); + if (staticLogging && ready()) { + main.e(thrown); + } else { + thrown.printStackTrace(); + } } diff --git a/src/mightypork/utils/math/Calc.java b/src/mightypork/utils/math/Calc.java index e931896..62f7d6f 100644 --- a/src/mightypork/utils/math/Calc.java +++ b/src/mightypork/utils/math/Calc.java @@ -34,37 +34,23 @@ public class Calc { public static double linePointDist(Coord lineDirVec, Coord linePoint, Coord point) { // line point L[lx,ly] - final double lx = linePoint.x; - final double ly = linePoint.y; + final double lx = linePoint.x(); + final double ly = linePoint.y(); // line equation ax+by+c=0 - final double a = -lineDirVec.y; - final double b = lineDirVec.x; + final double a = -lineDirVec.y(); + final double b = lineDirVec.x(); final double c = -a * lx - b * ly; // checked point P[x,y] - final double x = point.x; - final double y = point.y; + final double x = point.x(); + final double y = point.y(); // distance return Math.abs(a * x + b * y + c) / Math.sqrt(a * a + b * b); } - /** - * Get distance from 2D line to 2D point [X,Z] - * - * @param lineDirVec line directional vector - * @param linePoint point of line - * @param point point coordinate - * @return distance - */ - public static double linePointDistXZ(Coord lineDirVec, Coord linePoint, Coord point) - { - return linePointDist(new Coord(lineDirVec.x, lineDirVec.z), new Coord(linePoint.x, linePoint.z), new Coord(point.x, point.z)); - } - - /** * Get longest side of a right-angled triangle * diff --git a/src/mightypork/utils/math/Polar.java b/src/mightypork/utils/math/Polar.java index 0e2d405..2d8d70f 100644 --- a/src/mightypork/utils/math/Polar.java +++ b/src/mightypork/utils/math/Polar.java @@ -106,7 +106,8 @@ public class Polar { */ public static Polar fromCoord(Coord coord) { - return new Polar(Math.atan2(coord.y, coord.x), Math.sqrt(Calc.square(coord.x) + Calc.square(coord.y))); + return Polar.fromCoord(coord.x(), coord.y()); + } @@ -119,7 +120,10 @@ public class Polar { */ public static Polar fromCoord(double x, double y) { - return Polar.fromCoord(new Coord(x, y)); + final double a = Math.atan2(y, x); + final double r = Math.sqrt(x * x + y * y); + + return new Polar(a, r); } diff --git a/src/mightypork/utils/math/color/RGB.java b/src/mightypork/utils/math/color/RGB.java index f4ebedf..385261a 100644 --- a/src/mightypork/utils/math/color/RGB.java +++ b/src/mightypork/utils/math/color/RGB.java @@ -380,4 +380,15 @@ public class RGB { return Double.valueOf(r).hashCode() ^ Double.valueOf(g).hashCode() ^ Double.valueOf(b).hashCode() ^ Double.valueOf(a).hashCode(); } + + public static RGB dark(double d) + { + return new RGB(0, 0, 0, d); + } + + + public static RGB light(double d) + { + return new RGB(1, 1, 1, d); + } } diff --git a/src/mightypork/utils/math/coord/ConstraintCoordView.java b/src/mightypork/utils/math/coord/ConstraintCoordView.java new file mode 100644 index 0000000..75394c6 --- /dev/null +++ b/src/mightypork/utils/math/coord/ConstraintCoordView.java @@ -0,0 +1,42 @@ +package mightypork.utils.math.coord; + + +import mightypork.gamecore.gui.constraints.NumberConstraint; + + +public class ConstraintCoordView extends CoordView { + + private final NumberConstraint xc; + private final NumberConstraint yc; + private final NumberConstraint zc; + + + public ConstraintCoordView(NumberConstraint x, NumberConstraint y, NumberConstraint z) { + super(null); + this.xc = x; + this.yc = y; + this.zc = z; + } + + + @Override + public double x() + { + return xc == null ? 0 : xc.getValue(); + } + + + @Override + public double y() + { + return yc == null ? 0 : yc.getValue(); + } + + + @Override + public double z() + { + return zc == null ? 0 : zc.getValue(); + } + +} diff --git a/src/mightypork/utils/math/coord/Coord.java b/src/mightypork/utils/math/coord/Coord.java index 6e8dff9..bc06c29 100644 --- a/src/mightypork/utils/math/coord/Coord.java +++ b/src/mightypork/utils/math/coord/Coord.java @@ -3,6 +3,7 @@ package mightypork.utils.math.coord; import java.util.Random; +import mightypork.gamecore.gui.constraints.NumberConstraint; import mightypork.gamecore.gui.constraints.RectConstraint; import mightypork.utils.math.Calc; @@ -12,10 +13,13 @@ import mightypork.utils.math.Calc; * * @author MightyPork */ -public class Coord { +public class Coord implements CoordValue { protected static Random rand = new Random(); + public static final Coord ONE = new Coord(1).freeze(); + public static final Coord ZERO = new Coord(0).freeze(); + /** * Get distance to other point @@ -30,13 +34,31 @@ public class Coord { } /** X coordinate */ - public double x = 0; + private double x = 0; /** Y coordinate */ - public double y = 0; + private double y = 0; /** Z coordinate */ - public double z = 0; + private double z = 0; + + private Coord view = null; + + private boolean frozen = false; + + private NumberConstraint xc, yc, zc; + + + public static Coord at(double x, double y) + { + return new Coord(x, y); + } + + + public static Coord at(double x, double y, double z) + { + return new Coord(x, y, z); + } /** @@ -61,7 +83,7 @@ public class Coord { * * @param d coord value */ - public Coord(Number d) { + public Coord(double d) { setTo(d, d, d); } @@ -72,7 +94,7 @@ public class Coord { * @param x x coordinate * @param y y coordinate */ - public Coord(Number x, Number y) { + public Coord(double x, double y) { setTo(x, y); } @@ -84,11 +106,63 @@ public class Coord { * @param y y coordinate * @param z z coordinate */ - public Coord(Number x, Number y, Number z) { + public Coord(double x, double y, double z) { setTo(x, y, z); } + /** + * Freeze current coordinate values. + * + * @return this + */ + public Coord freeze() + { + frozen = true; + return this; + } + + + /** + * Get view at this coord + * + * @return the view + */ + public Coord view() + { + // cache last used view + if (view == null) view = new CoordView(this); + + return view; + } + + + /** + * @return true if this coord is writable + */ + public boolean isWritable() + { + return !frozen && !isView(); + } + + + /** + * @return true if this coord is a view at another + */ + public boolean isView() + { + return false; + } + + + protected void assertWritable() + { + if (!isWritable()) { + throw new UnsupportedOperationException("This Coord is not writable."); + } + } + + /** * Add a vector, in a copy * @@ -109,7 +183,7 @@ public class Coord { */ public Coord add_ip(Coord vec) { - return add_ip(vec.x, vec.y, vec.z); + return add_ip(vec.x(), vec.y(), vec.z()); } @@ -121,7 +195,7 @@ public class Coord { * @param y y offset * @return changed copy */ - public Coord add(Number x, Number y) + public Coord add(double x, double y) { return copy().add_ip(x, y); } @@ -135,7 +209,7 @@ public class Coord { * @param y y offset * @return this */ - public Coord add_ip(Number x, Number y) + public Coord add_ip(double x, double y) { return add_ip(x, y, 0); } @@ -149,7 +223,7 @@ public class Coord { * @param z z offset * @return changed copy */ - public Coord add(Number x, Number y, Number z) + public Coord add(double x, double y, double z) { return copy().add_ip(x, y, z); } @@ -163,11 +237,12 @@ public class Coord { * @param z z offset * @return this */ - public Coord add_ip(Number x, Number y, Number z) + public Coord add_ip(double x, double y, double z) { - this.x += x.doubleValue(); - this.y += y.doubleValue(); - this.z += z.doubleValue(); + assertWritable(); + this.x += x; + this.y += y; + this.z += z; return this; } @@ -179,7 +254,7 @@ public class Coord { */ public Coord copy() { - return new Coord(x, y, z); + return new Coord(this); } @@ -191,7 +266,11 @@ public class Coord { */ public double distTo(Coord point) { - return Math.sqrt((point.x - x) * (point.x - x) + (point.y - y) * (point.y - y) + (point.z - z) * (point.z - z)); + final double dx = (point.x() - this.x()); + final double dy = (point.y() - this.y()); + final double dz = (point.z() - this.z()); + + return Math.sqrt(dx * dx + dy * dy + dz * dz); } @@ -217,7 +296,11 @@ public class Coord { */ public boolean isInRect(Coord min, Coord max) { - return (x >= min.x && x <= max.x) && (y >= min.y && y <= max.y) && (z >= min.z && z <= max.z); + if (!Calc.inRange(x(), min.x(), max.x())) return false; + if (!Calc.inRange(y(), min.y(), max.y())) return false; + if (!Calc.inRange(z(), min.z(), max.z())) return false; + + return true; } @@ -268,18 +351,6 @@ public class Coord { } - /** - * Multiply each component, in place. - * - * @param d multiplier - * @return this - */ - public Coord mul_ip(double d) - { - return mul_ip(d, d, d); - } - - /** * Multiply each component, in a copy. * @@ -300,23 +371,21 @@ public class Coord { * @param y y multiplier * @return changed copy */ - public Coord mul(double x, int y) + public Coord mul(double x, double y) { return copy().mul_ip(x, y); } /** - * Multiply each component, in place.
- * Z is unchanged. + * Multiply each component, in place. * - * @param x x multiplier - * @param y y multiplier + * @param d multiplier * @return this */ - public Coord mul_ip(double x, double y) + public Coord mul_ip(double d) { - return mul_ip(x, y, 1); + return mul_ip(d, d, d); } @@ -334,6 +403,20 @@ public class Coord { } + /** + * Multiply each component, in place.
+ * Z is unchanged. + * + * @param x x multiplier + * @param y y multiplier + * @return this + */ + public Coord mul_ip(double x, double y) + { + return mul_ip(x, y, 1); + } + + /** * Multiply each component, in place. * @@ -342,7 +425,7 @@ public class Coord { */ public Coord mul_ip(Coord vec) { - return mul_ip(vec.x, vec.y, vec.z); + return mul_ip(vec.x(), vec.y(), vec.z()); } @@ -356,6 +439,7 @@ public class Coord { */ public Coord mul_ip(double x, double y, double z) { + assertWritable(); this.x *= x; this.y *= y; this.z *= z; @@ -370,27 +454,27 @@ public class Coord { /** - * offset randomly in place + * offset randomly * - * @param max max +- offset - * @return this + * @param min min offset + * @param max max offset + * @return offset coord */ - public Coord random_offset_ip(double max) + public Coord random_offset(double min, double max) { - return add(random(1).norm_ip(rand.nextDouble() * max)); + return copy().random_offset_ip(min, max); } /** - * offset randomly + * offset randomly in place * - * @param min min offset - * @param max max offset - * @return offset coord + * @param max max +- offset + * @return this */ - public Coord random_offset(double min, double max) + public Coord random_offset_ip(double max) { - return copy().random_offset_ip(min, max); + return add_ip(random(1).norm_ip(rand.nextDouble() * max)); } @@ -426,6 +510,7 @@ public class Coord { */ public Coord round_ip() { + assertWritable(); x = Math.round(x); y = Math.round(y); z = Math.round(z); @@ -440,9 +525,10 @@ public class Coord { */ public void setToMax(Coord other) { - x = Math.max(x, other.x); - y = Math.max(y, other.y); - z = Math.max(z, other.z); + assertWritable(); + x = Math.max(x, other.x()); + y = Math.max(y, other.y()); + z = Math.max(z, other.z()); } @@ -453,9 +539,10 @@ public class Coord { */ public void setToMin(Coord other) { - x = Math.min(x, other.x); - y = Math.min(y, other.y); - z = Math.min(z, other.z); + assertWritable(); + x = Math.min(x, other.x()); + y = Math.min(y, other.y()); + z = Math.min(z, other.z()); } @@ -467,7 +554,7 @@ public class Coord { */ public Coord setTo(Coord copied) { - return setTo(copied.x, copied.y, copied.z); + return setTo(copied.x(), copied.y(), copied.z()); } @@ -478,7 +565,7 @@ public class Coord { * @param y y coordinate * @return this */ - public Coord setTo(Number x, Number y) + public Coord setTo(double x, double y) { return setTo(x, y, 0); } @@ -492,11 +579,12 @@ public class Coord { * @param z z coordinate * @return this */ - public Coord setTo(Number x, Number y, Number z) + public Coord setTo(double x, double y, double z) { - this.x = x.doubleValue(); - this.y = y.doubleValue(); - this.z = z.doubleValue(); + assertWritable(); + this.x = x; + this.y = y; + this.z = z; return this; } @@ -507,59 +595,61 @@ public class Coord { * @param x x coordinate * @return copy with set coordinate */ - public Coord setX(Number x) + public Coord setX(double x) { return copy().setX_ip(x); } /** - * Set X coordinate in place + * Set Y coordinate in a copy * - * @param x x coordinate - * @return this + * @param y y coordinate + * @return copy with set coordinate */ - public Coord setX_ip(Number x) + public Coord setY(double y) { - this.x = x.doubleValue(); - return this; + return copy().setY_ip(y); } /** - * Set Y coordinate in a copy + * Set Z coordinate in a copy * - * @param y y coordinate + * @param z z coordinate * @return copy with set coordinate */ - public Coord setY(Number y) + public Coord setZ(double z) { - return copy().setY_ip(y); + return copy().setZ_ip(z); } /** - * Set Y coordinate in place + * Set X coordinate in place * - * @param y y coordinate + * @param x x coordinate * @return this */ - public Coord setY_ip(Number y) + public Coord setX_ip(double x) { - this.y = y.doubleValue(); + assertWritable(); + this.x = x; return this; } /** - * Set Z coordinate in a copy + * Set Y coordinate in place * - * @param z z coordinate - * @return copy with set coordinate + * @param y y coordinate + * @return this */ - public Coord setZ(Number z) + public Coord setY_ip(double y) { - return copy().setZ_ip(z); + assertWritable(); + this.y = y; + return this; } @@ -569,9 +659,10 @@ public class Coord { * @param z z coordinate * @return this */ - public Coord setZ_ip(Number z) + public Coord setZ_ip(double z) { - this.z = z.doubleValue(); + assertWritable(); + this.z = z; return this; } @@ -595,7 +686,7 @@ public class Coord { * @param y y offset * @return the offset copy */ - public Coord sub(Number x, Number y) + public Coord sub(double x, double y) { return copy().sub_ip(x, y); } @@ -609,7 +700,7 @@ public class Coord { * @param z z offset * @return the offset copy */ - public Coord sub(Number x, Number y, Number z) + public Coord sub(double x, double y, double z) { return copy().sub_ip(x, y, z); } @@ -623,7 +714,7 @@ public class Coord { */ public Coord sub_ip(Coord vec) { - return sub_ip(vec.x, vec.y, vec.z); + return sub_ip(vec.x(), vec.y(), vec.z()); } @@ -634,7 +725,7 @@ public class Coord { * @param y y offset * @return this */ - public Coord sub_ip(Number x, Number y) + public Coord sub_ip(double x, double y) { return sub_ip(x, y, 0); } @@ -648,11 +739,12 @@ public class Coord { * @param z z offset * @return this */ - public Coord sub_ip(Number x, Number y, Number z) + public Coord sub_ip(double x, double y, double z) { - this.x -= x.doubleValue(); - this.y -= y.doubleValue(); - this.z -= z.doubleValue(); + assertWritable(); + this.x -= x; + this.y -= y; + this.z -= z; return this; } @@ -672,6 +764,7 @@ public class Coord { /** * @return X as double */ + @Override public double x() { return x; @@ -679,74 +772,127 @@ public class Coord { /** - * @return X as float + * @return Y as double */ - public float xf() + @Override + public double y() { - return (float) x; + return y; } /** - * @return X as int + * @return Z as double */ - public int xi() + @Override + public double z() { - return (int) Math.round(x); + return z; } /** - * @return Y as double + * @return X as constraint view */ - public double y() + @Override + public final NumberConstraint xc() { - return y; + return xc != null ? xc : new NumberConstraint() { + + @Override + public double getValue() + { + return x(); + } + }; } /** - * @return Y as float + * @return Y as constraint view */ - public float yf() + @Override + public final NumberConstraint yc() { - return (float) y; + return yc != null ? yc : new NumberConstraint() { + + @Override + public double getValue() + { + return y(); + } + }; } /** - * @return Y as int + * @return Z as constraint view */ - public int yi() + @Override + public final NumberConstraint zc() { - return (int) Math.round(y); + return zc != null ? zc : new NumberConstraint() { + + @Override + public double getValue() + { + return z(); + } + }; } /** - * @return Z as double + * @return X as float */ - public double z() + public final float xf() { - return z; + return (float) x(); + } + + + /** + * @return Y as float + */ + public final float yf() + { + return (float) y(); } /** * @return Z as float */ - public float zf() + public final float zf() + { + return (float) z(); + } + + + /** + * @return X as int + */ + public final int xi() + { + return (int) Math.round(x()); + } + + + /** + * @return Y as int + */ + public final int yi() { - return (float) z; + return (int) Math.round(y()); } /** * @return Z as int */ - public int zi() + public final int zi() { - return (int) Math.round(z); + return (int) Math.round(z()); } @@ -798,9 +944,9 @@ public class Coord { { //@formatter:off setTo( - y * vec.z - z * vec.y, - z * vec.x - x * vec.z, - x * vec.y - y * vec.x + y * vec.z() - z * vec.y(), + z * vec.x() - x * vec.z(), + x * vec.y() - y * vec.x() ); //@formatter:on return this; @@ -815,7 +961,7 @@ public class Coord { */ public double dot(Coord vec) { - return x * vec.x + y * vec.y + z * vec.z; + return x() * vec.x() + y() * vec.y() + z() * vec.z(); } @@ -879,7 +1025,7 @@ public class Coord { { if (isZero()) return 0; - return Math.sqrt(x * x + y * y + z * z); + return Math.sqrt(x() * x() + y() * y() + z() * z()); } @@ -888,14 +1034,14 @@ public class Coord { */ public boolean isZero() { - return x == 0 && y == 0 && z == 0; + return x() == 0 && y() == 0 && z() == 0; } @Override public String toString() { - return "[" + x + ", " + y + ", " + z + "]"; + return String.format("( %.2f, %.2f, %.2f )", x(), y(), z()); } @@ -905,11 +1051,11 @@ public class Coord { final int prime = 31; int result = 1; long temp; - temp = Double.doubleToLongBits(x); + temp = Double.doubleToLongBits(x()); result = prime * result + (int) (temp ^ (temp >>> 32)); - temp = Double.doubleToLongBits(y); + temp = Double.doubleToLongBits(y()); result = prime * result + (int) (temp ^ (temp >>> 32)); - temp = Double.doubleToLongBits(z); + temp = Double.doubleToLongBits(z()); result = prime * result + (int) (temp ^ (temp >>> 32)); return result; } @@ -922,9 +1068,9 @@ public class Coord { if (obj == null) return false; if (!(obj instanceof Coord)) return false; final Coord other = (Coord) obj; - if (Double.doubleToLongBits(x) != Double.doubleToLongBits(other.x)) return false; - if (Double.doubleToLongBits(y) != Double.doubleToLongBits(other.y)) return false; - if (Double.doubleToLongBits(z) != Double.doubleToLongBits(other.z)) return false; + if (Double.doubleToLongBits(x()) != Double.doubleToLongBits(other.x())) return false; + if (Double.doubleToLongBits(y()) != Double.doubleToLongBits(other.y())) return false; + if (Double.doubleToLongBits(z()) != Double.doubleToLongBits(other.z())) return false; return true; } @@ -936,7 +1082,7 @@ public class Coord { */ public static Coord zero() { - return new Coord(0); + return ZERO.copy(); } @@ -947,7 +1093,7 @@ public class Coord { */ public static Coord one() { - return new Coord(1); + return ONE.copy(); } diff --git a/src/mightypork/utils/math/coord/CoordValue.java b/src/mightypork/utils/math/coord/CoordValue.java new file mode 100644 index 0000000..c77e613 --- /dev/null +++ b/src/mightypork/utils/math/coord/CoordValue.java @@ -0,0 +1,31 @@ +package mightypork.utils.math.coord; + + +import mightypork.gamecore.gui.constraints.NumberConstraint; + + +/** + * Coord values provider + * + * @author MightyPork + */ +public interface CoordValue { + + double x(); + + + double y(); + + + double z(); + + + NumberConstraint xc(); + + + NumberConstraint zc(); + + + NumberConstraint yc(); + +} diff --git a/src/mightypork/utils/math/coord/CoordView.java b/src/mightypork/utils/math/coord/CoordView.java new file mode 100644 index 0000000..d2348e9 --- /dev/null +++ b/src/mightypork/utils/math/coord/CoordView.java @@ -0,0 +1,62 @@ +package mightypork.utils.math.coord; + + +public class CoordView extends Coord { + + private CoordValue observed = null; + + + public CoordView(CoordValue coord) { + observed = coord; + } + + + @Override + public boolean isView() + { + return true; + } + + + @Override + public boolean isWritable() + { + return false; + } + + + @Override + public Coord view() + { + return this; + } + + + @Override + public Coord freeze() + { + return this; // no effect + } + + + @Override + public double x() + { + return observed.x(); + } + + + @Override + public double y() + { + return observed.y(); + } + + + @Override + public double z() + { + return observed.z(); + } + +} diff --git a/src/mightypork/utils/math/coord/Rect.java b/src/mightypork/utils/math/coord/Rect.java index 7093702..1e08669 100644 --- a/src/mightypork/utils/math/coord/Rect.java +++ b/src/mightypork/utils/math/coord/Rect.java @@ -1,6 +1,7 @@ package mightypork.utils.math.coord; +import mightypork.gamecore.gui.constraints.NumberConstraint; import mightypork.gamecore.gui.constraints.RectConstraint; import mightypork.utils.math.Calc; @@ -12,8 +13,12 @@ import mightypork.utils.math.Calc; */ public class Rect implements RectConstraint { + public static final Rect ZERO = new Rect(0, 0, 0, 0).freeze(); + public static final Rect ONE = new Rect(0, 0, 1, 1).freeze(); + + /** - * Rectangle from size + * Rectangle from size; coords are copied. * * @param min min coord * @param size rect size @@ -26,7 +31,7 @@ public class Rect implements RectConstraint { /** - * Make rect from min coord and size + * Make rect from min coord and size; coords are copied. * * @param min min coord * @param width size x @@ -35,7 +40,7 @@ public class Rect implements RectConstraint { */ public static Rect fromSize(Coord min, double width, double height) { - return new Rect(min, min.add(width, height)); + return new Rect(min.copy(), min.add(width, height)); } @@ -60,7 +65,7 @@ public class Rect implements RectConstraint { */ public static Rect fromSize(Coord size) { - return fromSize(0, 0, size.x, size.y); + return fromSize(0, 0, size.x(), size.y()); } @@ -79,10 +84,92 @@ public class Rect implements RectConstraint { } /** Lowest coordinates xy */ - private final Coord min = new Coord(); + protected final Coord min; /** Highest coordinates xy */ - private final Coord max = new Coord(); + protected final Coord max; + + // view of secondary corners. + + //@formatter:off + private final ConstraintCoordView HMinVMax = new ConstraintCoordView( + new NumberConstraint() { + @Override + public double getValue() + { + return min.x(); + } + }, + new NumberConstraint() { + @Override + public double getValue() + { + return max.y(); + } + }, + null + ); + + + private final ConstraintCoordView HMaxVMin = new ConstraintCoordView( + new NumberConstraint() { + @Override + public double getValue() { + return max.x(); + } + }, + new NumberConstraint() { + @Override + public double getValue() + { + return min.y(); + } + }, + null + ); + //@formatter:on + + private boolean frozen; + + + public boolean isWritable() + { + return !frozen && !isView(); + } + + + public boolean isView() + { + return false; + } + + + public Rect freeze() + { + min.freeze(); + max.freeze(); + frozen = true; + return this; + } + + + /** + * Get a readonly view + * + * @return view + */ + public RectView view() + { + return new RectView(this); + } + + + protected void assertWritable() + { + if (!isWritable()) { + throw new UnsupportedOperationException("This Rect is not writable."); + } + } /** @@ -99,18 +186,20 @@ public class Rect implements RectConstraint { * @param size size coord */ public Rect(Coord size) { - this(0, 0, size.x, size.y); + this(0, 0, size.x(), size.y()); } /** - * New rect of two coords + * New rect of two coords; Coords are plugged in directly (ie. views can be + * used for frozen rect representing another) * - * @param c1 coord 1 - * @param c2 coord 2 + * @param min coord 1 + * @param max coord 2 */ - public Rect(Coord c1, Coord c2) { - this(c1.x, c1.y, c2.x, c2.y); + public Rect(Coord min, Coord max) { + this.min = min; // must not copy + this.max = max; // must not copy } @@ -123,7 +212,8 @@ public class Rect implements RectConstraint { * @param ymax upper y */ public Rect(double xmin, double ymin, double xmax, double ymax) { - setTo(xmin, ymin, xmax, ymax); + min = new Coord(xmin, ymin); + max = new Coord(xmax, ymax); } @@ -144,7 +234,7 @@ public class Rect implements RectConstraint { * @param r other rect */ public Rect(Rect r) { - this(r.min.x, r.min.y, r.max.x, r.max.y); + this(r.min.copy(), r.max.copy()); } @@ -218,7 +308,7 @@ public class Rect implements RectConstraint { */ public Coord getCenter() { - return min.midTo(max); + return min.midTo(max).freeze(); } @@ -229,7 +319,7 @@ public class Rect implements RectConstraint { */ public Coord getCenterVMin() { - return new Coord((max.x + min.x) / 2D, min.y); + return new Coord((max.x() + min.x()) / 2D, min.y()).freeze(); } @@ -240,7 +330,7 @@ public class Rect implements RectConstraint { */ public Coord getCenterHMin() { - return new Coord(min.x, (max.y + min.y) / 2D); + return new Coord(min.x(), (max.y() + min.y()) / 2D).freeze(); } @@ -251,7 +341,7 @@ public class Rect implements RectConstraint { */ public Coord getCenterHMax() { - return new Coord(max.x, (max.y + min.y) / 2D); + return new Coord(max.x(), (max.y() + min.y()) / 2D).freeze(); } @@ -262,7 +352,7 @@ public class Rect implements RectConstraint { */ public Coord getCenterVMax() { - return new Coord((max.x + min.x) / 2D, max.y); + return new Coord((max.x() + min.x()) / 2D, max.y()).freeze(); } @@ -273,7 +363,7 @@ public class Rect implements RectConstraint { */ public Coord getHMinVMin() { - return new Coord(min.x, min.y); + return min.view(); } @@ -284,62 +374,62 @@ public class Rect implements RectConstraint { */ public Coord getHMinVMax() { - return new Coord(min.x, max.y); + return HMinVMax; } /** - * Alias for getX2Y2 + * Get right bottom * - * @return highest coordinates xy + * @return center */ - public Coord getMax() + public Coord getHMaxVMin() { - return getHMaxVMax(); + return HMaxVMin; } /** - * Alias for getX1Y1 + * Get right top * - * @return lowest coordinates xy + * @return center */ - public Coord getMin() + public Coord getHMaxVMax() { - return getHMinVMin(); + return max.view(); } /** - * Alias for getX1Y1 + * Alias for getX2Y2 * - * @return lowest coordinates xy + * @return highest coordinates xy */ - public Coord getOrigin() + public Coord getMax() { - return getMin(); + return getHMaxVMax(); } /** - * Get right bottom + * Alias for getX1Y1 * - * @return center + * @return lowest coordinates xy */ - public Coord getHMaxVMin() + public Coord getMin() { - return new Coord(max.x, min.y); + return getHMinVMin(); } /** - * Get right top + * Alias for getX1Y1 * - * @return center + * @return lowest coordinates xy */ - public Coord getHMaxVMax() + public Coord getOrigin() { - return new Coord(max.x, max.y); + return getHMinVMin(); } @@ -376,7 +466,7 @@ public class Rect implements RectConstraint { */ public Rect shrink_ip(Coord shrink) { - shrink_ip(shrink.x, shrink.y); + shrink_ip(shrink.x(), shrink.y()); return this; } @@ -461,7 +551,7 @@ public class Rect implements RectConstraint { */ public Rect grow_ip(Coord grow) { - grow_ip(grow.x, grow.y); + grow_ip(grow.x(), grow.y()); return this; } @@ -521,7 +611,7 @@ public class Rect implements RectConstraint { */ public boolean isInside(Coord point) { - return Calc.inRange(point.x, min.x, max.x) && Calc.inRange(point.y, min.y, max.y); + return Calc.inRange(point.x(), min.x(), max.x()) && Calc.inRange(point.y(), min.y(), max.y()); } @@ -603,17 +693,6 @@ public class Rect implements RectConstraint { } - /** - * Set to [0,0,coord.x,coord.y] - * - * @param coord size coord - */ - public void setTo(Coord coord) - { - setTo(0, 0, coord.x, coord.y); - } - - /** * Set to coordinates * @@ -624,10 +703,8 @@ public class Rect implements RectConstraint { */ public void setTo(double xmin, double ymin, double xmax, double ymax) { - min.x = Calc.min(xmin, xmax); - min.y = Calc.min(ymin, ymax); - max.x = Calc.max(xmin, xmax); - max.y = Calc.max(ymin, ymax); + min.setTo(Math.min(xmin, xmax), Math.min(ymin, ymax)); + max.setTo(Math.max(xmin, xmax), Math.max(ymin, ymax)); } @@ -695,28 +772,10 @@ public class Rect implements RectConstraint { } - /** - * @return rect [0,0-1,1] - */ - public static Rect one() - { - return new Rect(0, 0, 1, 1); - } - - - /** - * @return rect [0,0-0,0] - */ - public static Rect zero() - { - return new Rect(0, 0, 0, 0); - } - - @Override public String toString() { - return String.format("[( %4.1f; %4.1f )-( %4.1f; %4.1f )]", min.x, min.y, max.x, max.y); + return String.format("[%s-%s]", min.toString(), max.toString()); } @@ -725,7 +784,7 @@ public class Rect implements RectConstraint { */ public double xMin() { - return min.x; + return min.x(); } @@ -734,7 +793,7 @@ public class Rect implements RectConstraint { */ public double xMax() { - return max.x; + return max.x(); } @@ -743,7 +802,7 @@ public class Rect implements RectConstraint { */ public double yMin() { - return min.y; + return min.y(); } @@ -752,19 +811,19 @@ public class Rect implements RectConstraint { */ public double yMax() { - return max.y; + return max.y(); } public double getHeight() { - return max.y - min.y; + return max.y() - min.y(); } public double getWidth() { - return max.x - min.x; + return max.x() - min.x(); } @@ -775,7 +834,7 @@ public class Rect implements RectConstraint { */ public Coord getSize() { - return new Coord(max.x - min.x, max.y - min.y); + return new Coord(max.x() - min.x(), max.y() - min.y()); } @@ -784,4 +843,26 @@ public class Rect implements RectConstraint { { return this; } + + + /** + * Generate zero rect + * + * @return zero + */ + public static Rect zero() + { + return ZERO.copy(); + } + + + /** + * Generate 0,0-1,1 rect + * + * @return one + */ + public static Rect one() + { + return ZERO.copy(); + } } diff --git a/src/mightypork/utils/math/coord/RectView.java b/src/mightypork/utils/math/coord/RectView.java new file mode 100644 index 0000000..0fe70f8 --- /dev/null +++ b/src/mightypork/utils/math/coord/RectView.java @@ -0,0 +1,37 @@ +package mightypork.utils.math.coord; + + +/** + * Read only rect + * + * @author MightyPork + */ +public class RectView extends Rect { + + public RectView(Rect observed) { + super(observed.min.view(), observed.max.view()); + } + + + @Override + public boolean isWritable() + { + return false; + } + + + @Override + public boolean isView() + { + return true; + } + + + @Override + public Rect freeze() + { + // do nothing + return this; + } + +} diff --git a/src/mightypork/utils/objects/Convert.java b/src/mightypork/utils/objects/Convert.java index 8400bcb..2e04a02 100644 --- a/src/mightypork/utils/objects/Convert.java +++ b/src/mightypork/utils/objects/Convert.java @@ -126,7 +126,7 @@ public class Convert { if (o instanceof Coord) { final Coord c = (Coord) o; - return String.format("[%f:%f:%f]", c.x, c.y, c.z); + return String.format("[%f:%f:%f]", c.x(), c.y(), c.z()); } if (o instanceof Range) {