Coord and rect views and freezing; Fixed font glitches.

v5stable
Ondřej Hruška 10 years ago
parent ebac276ed2
commit e940c53dd6
  1. 8
      src/mightypork/gamecore/audio/DeferredAudio.java
  2. 4
      src/mightypork/gamecore/audio/SoundSystem.java
  3. 4
      src/mightypork/gamecore/control/GameLoop.java
  4. 8
      src/mightypork/gamecore/control/bus/events/ResourceLoadRequest.java
  5. 110
      src/mightypork/gamecore/gui/components/painters/TextPainter.java
  6. 28
      src/mightypork/gamecore/gui/constraints/Constraints.java
  7. 3
      src/mightypork/gamecore/gui/screens/LayeredScreen.java
  8. 8
      src/mightypork/gamecore/input/InputSystem.java
  9. 12
      src/mightypork/gamecore/loading/AsyncResourceLoader.java
  10. 144
      src/mightypork/gamecore/loading/BaseDeferredResource.java
  11. 23
      src/mightypork/gamecore/loading/Deferred.java
  12. 131
      src/mightypork/gamecore/loading/DeferredResource.java
  13. 11
      src/mightypork/gamecore/render/DisplaySystem.java
  14. 122
      src/mightypork/gamecore/render/Render.java
  15. 2
      src/mightypork/gamecore/render/fonts/FontBank.java
  16. 26
      src/mightypork/gamecore/render/fonts/FontRenderer.java
  17. 23
      src/mightypork/gamecore/render/fonts/GLFont.java
  18. 134
      src/mightypork/gamecore/render/fonts/SlickFont.java
  19. 430
      src/mightypork/gamecore/render/fonts/impl/CachedFont.java
  20. 107
      src/mightypork/gamecore/render/fonts/impl/DeferredFont.java
  21. 32
      src/mightypork/gamecore/render/fonts/impl/DeferredFontNative.java
  22. 20
      src/mightypork/gamecore/render/fonts/impl/NullFont.java
  23. 7
      src/mightypork/gamecore/render/textures/DeferredTexture.java
  24. 26
      src/mightypork/gamecore/render/textures/TextureBank.java
  25. 6
      src/mightypork/gamecore/render/textures/TxQuad.java
  26. 2
      src/mightypork/rogue/App.java
  27. 31
      src/mightypork/rogue/Res.java
  28. 6
      src/mightypork/rogue/screens/LayerFps.java
  29. 24
      src/mightypork/rogue/screens/test_cat_sound/LayerFlyingCat.java
  30. 7
      src/mightypork/rogue/screens/test_cat_sound/ScreenTestCat.java
  31. 25
      src/mightypork/utils/logging/Log.java
  32. 26
      src/mightypork/utils/math/Calc.java
  33. 8
      src/mightypork/utils/math/Polar.java
  34. 11
      src/mightypork/utils/math/color/RGB.java
  35. 42
      src/mightypork/utils/math/coord/ConstraintCoordView.java
  36. 402
      src/mightypork/utils/math/coord/Coord.java
  37. 31
      src/mightypork/utils/math/coord/CoordValue.java
  38. 62
      src/mightypork/utils/math/coord/CoordView.java
  39. 251
      src/mightypork/utils/math/coord/Rect.java
  40. 37
      src/mightypork/utils/math/coord/RectView.java
  41. 2
      src/mightypork/utils/objects/Convert.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());
}

@ -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);

@ -64,7 +64,9 @@ public abstract class GameLoop extends AppModule implements MainLoopTaskRequest.
beforeRender();
if (rootRenderable != null) rootRenderable.render();
if (rootRenderable != null) {
rootRenderable.render();
}
afterRender();

@ -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<ResourceLoadRequest.Listener> {
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<ResourceLoadRequest.Listener>
*
* @param resource
*/
void loadResource(DeferredResource resource);
void loadResource(Deferred resource);
}
}

@ -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.<br>
* 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.<br>
* 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.<br>
* <i>This getter is used for getting drawing color; so if it's overriden,
* the draw color can be adjusted in real time.</i>
*
* @return drawing color
*/
public RGB getColor()
public void setAlign(Align align)
{
return color;
this.align = align;
}
/**
* Get text align.<br>
* <i>This getter is used for getting align; so if it's overidden, the align
* can be adjusted in real time.</i>
*
* @return text align
*/
public Align getAlign()
public void setText(String text)
{
return align;
this.text = new StringWrapper(text);
}
/**
* Get text to draw.<br>
* <i>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)</i>
*
* @return text align
*/
public String getText()
public void setText(StringProvider text)
{
return text.getString();
this.text = text;
}
}

@ -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());
}
};
}

@ -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();
}
}

@ -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();
}

@ -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<DeferredResource> toLoad = new LinkedBlockingQueue<>();
private final LinkedBlockingQueue<Deferred> 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("<LOADER> Cannot load async: " + Log.str(resource));
// Log.f3("<LOADER> 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("<LOADER> Loading async:\n " + Log.str(def));
Log.f3("<LOADER> Loading: " + Log.str(def));
exs.submit(new Runnable() {

@ -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.<br>
* Resources implementing {@link NullResource} will be treated as fake and not
* attempted to load.
*
* @author MightyPork
*/
@LoggedName(name = "Resource")
public abstract class BaseDeferredResource implements DeferredResource, Destroyable {
private final String resource;
private 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("<RES> 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("<RES> Loading:\n " + this);
loadResource(resource);
Log.f3("<RES> Loaded:\n " + this);
} catch (final Exception e) {
loadFailed = true;
Log.e("<RES> Failed to load:\n " + this, e);
}
}
@Override
public 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("<RES> (!) First use, not loaded yet - loading directly\n " + this);
load();
}
return isLoaded();
}
/**
* Load the resource. Called from load() - once only.
*
* @param resource the path / name of a resource
* @throws Exception when some problem prevented the resource from being
* loaded.
*/
protected abstract void loadResource(String resource) throws Exception;
@Override
public abstract void destroy();
@Override
public String toString()
{
return Log.str(getClass()) + "(\"" + resource + "\")";
}
@Override
public int hashCode()
{
final int prime = 31;
int result = 1;
result = prime * result + ((resource == null) ? 0 : resource.hashCode());
return result;
}
@Override
public boolean equals(Object obj)
{
if (this == obj) return true;
if (obj == null) return false;
if (!(obj instanceof BaseDeferredResource)) return false;
final BaseDeferredResource other = (BaseDeferredResource) obj;
if (resource == null) {
if (other.resource != null) return false;
} else if (!resource.equals(other.resource)) return false;
return true;
}
private boolean isNull()
{
return this instanceof NullResource;
}
}

@ -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();
}

@ -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.<br>
* 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("<RES> Loading: " + this);
loadResource(resource);
Log.f3("<RES> Loaded: " + this);
} catch (final Exception e) {
loadFailed = true;
Log.e("<RES> 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("<RES> (!) 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;
}
}

@ -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);
}

@ -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);
}
}

@ -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;

@ -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.<br>
* 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();
}

@ -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();
}

@ -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;
}
}

@ -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<Character, CharTile> 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<LoadedGlyph> glyphs = new ArrayList<>();
final List<Character> 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());
}
}

@ -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;
}
}

@ -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);
}

@ -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;
}
}

@ -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();
}

@ -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);
}

@ -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();
}

@ -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");
}

@ -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);
}

@ -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));
}

@ -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);
}

@ -62,4 +62,11 @@ public class ScreenTestCat extends LayeredScreen {
return "test.cat";
}
@Override
protected void renderScreen()
{
super.renderScreen();
}
}

@ -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();
}
}

@ -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
*

@ -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);
}

@ -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);
}
}

@ -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();
}
}

@ -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.<br>
* 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.<br>
* 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();
}

@ -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();
}

@ -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();
}
}

@ -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();
}
}

@ -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;
}
}

@ -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) {

Loading…
Cancel
Save