Coord and rect views and freezing; Fixed font glitches.
This commit is contained in:
@@ -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)
|
||||
{
|
||||
font.usePtSize(enable);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void render()
|
||||
{
|
||||
if (getText() == null) return;
|
||||
if (text == null) return;
|
||||
|
||||
font.draw(getText(), getRect(), getAlign(), getColor());
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
public void setShadow(RGB color, Coord offset)
|
||||
{
|
||||
setShadow(true);
|
||||
setShadowColor(color);
|
||||
setShadowOffset(offset);
|
||||
}
|
||||
|
||||
|
||||
public void setShadow(boolean shadow)
|
||||
{
|
||||
this.shadow = shadow;
|
||||
}
|
||||
|
||||
|
||||
public void setShadowColor(RGB shadowColor)
|
||||
{
|
||||
this.shadowColor = shadowColor;
|
||||
}
|
||||
|
||||
|
||||
public void setShadowOffset(Coord shadowOffset)
|
||||
{
|
||||
this.shadowOffset = shadowOffset;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Assign paint color
|
||||
*
|
||||
* @param color paint color
|
||||
*/
|
||||
public void setColor(RGB color)
|
||||
{
|
||||
this.color = color;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set text align
|
||||
*
|
||||
* @param align text align
|
||||
*/
|
||||
public void setAlign(Align align)
|
||||
{
|
||||
this.align = align;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set drawn text
|
||||
*
|
||||
* @param text text
|
||||
*/
|
||||
public void setText(String text)
|
||||
{
|
||||
this.text = new StringWrapper(text);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set drawn text provider
|
||||
*
|
||||
* @param text text provider
|
||||
*/
|
||||
public void setText(StringProvider text)
|
||||
{
|
||||
this.text = text;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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()
|
||||
{
|
||||
return color;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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()
|
||||
{
|
||||
return align;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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()
|
||||
{
|
||||
return text.getString();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
}
|
||||
+62
-47
@@ -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,30 +62,55 @@ 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 style font style
|
||||
*/
|
||||
public DeferredFont(String resourcePath, String extraChars, double size, FontStyle style) {
|
||||
this(resourcePath, extraChars, size, style, FilterMode.NEAREST);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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, FilterMode filter) {
|
||||
public DeferredFont(String resourcePath, String chars, double size, FontStyle style, boolean antialias, FilterMode filter) {
|
||||
super(resourcePath);
|
||||
this.size = size;
|
||||
this.style = style;
|
||||
this.extraChars = extraChars;
|
||||
this.chars = chars;
|
||||
this.filter = filter;
|
||||
this.antialias = antialias;
|
||||
}
|
||||
|
||||
|
||||
public void setFont(GLFont font)
|
||||
{
|
||||
this.font = font;
|
||||
}
|
||||
|
||||
|
||||
public void setSize(double size)
|
||||
{
|
||||
this.size = size;
|
||||
}
|
||||
|
||||
|
||||
public void setStyle(FontStyle style)
|
||||
{
|
||||
this.style = style;
|
||||
}
|
||||
|
||||
|
||||
public void setChars(String chars)
|
||||
{
|
||||
this.chars = chars;
|
||||
}
|
||||
|
||||
|
||||
public void setFilter(FilterMode filter)
|
||||
{
|
||||
this.filter = filter;
|
||||
}
|
||||
|
||||
|
||||
public void setAntialias(boolean antialias)
|
||||
{
|
||||
this.antialias = antialias;
|
||||
}
|
||||
|
||||
|
||||
@@ -92,8 +118,8 @@ public class DeferredFont extends BaseDeferredResource implements GLFont {
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
+4
-28
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
+3
-17
@@ -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);
|
||||
final DeferredTexture texture = new DeferredTexture(resourcePath);
|
||||
texture.setFilter(filter_min, filter_mag);
|
||||
texture.setWrap(wrap);
|
||||
|
||||
getEventBus().send(new ResourceLoadRequest(tx));
|
||||
|
||||
textures.put(key, tx);
|
||||
lastTx = tx;
|
||||
|
||||
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;
|
||||
@@ -369,18 +453,6 @@ public class Coord {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* offset randomly in place
|
||||
*
|
||||
* @param max max +- offset
|
||||
* @return this
|
||||
*/
|
||||
public Coord random_offset_ip(double max)
|
||||
{
|
||||
return add(random(1).norm_ip(rand.nextDouble() * max));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* offset randomly
|
||||
*
|
||||
@@ -394,6 +466,18 @@ public class Coord {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* offset randomly in place
|
||||
*
|
||||
* @param max max +- offset
|
||||
* @return this
|
||||
*/
|
||||
public Coord random_offset_ip(double max)
|
||||
{
|
||||
return add_ip(random(1).norm_ip(rand.nextDouble() * max));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* offset randomly in place
|
||||
*
|
||||
@@ -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,71 +595,74 @@ 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
|
||||
*
|
||||
* @param x x coordinate
|
||||
* @return this
|
||||
*/
|
||||
public Coord setX_ip(Number x)
|
||||
{
|
||||
this.x = x.doubleValue();
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set Y coordinate in a copy
|
||||
*
|
||||
* @param y y coordinate
|
||||
* @return copy with set coordinate
|
||||
*/
|
||||
public Coord setY(Number y)
|
||||
public Coord setY(double y)
|
||||
{
|
||||
return copy().setY_ip(y);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set Y coordinate in place
|
||||
*
|
||||
* @param y y coordinate
|
||||
* @return this
|
||||
*/
|
||||
public Coord setY_ip(Number y)
|
||||
{
|
||||
this.y = y.doubleValue();
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set Z coordinate in a copy
|
||||
*
|
||||
* @param z z coordinate
|
||||
* @return copy with set coordinate
|
||||
*/
|
||||
public Coord setZ(Number z)
|
||||
public Coord setZ(double z)
|
||||
{
|
||||
return copy().setZ_ip(z);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set X coordinate in place
|
||||
*
|
||||
* @param x x coordinate
|
||||
* @return this
|
||||
*/
|
||||
public Coord setX_ip(double x)
|
||||
{
|
||||
assertWritable();
|
||||
this.x = x;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set Y coordinate in place
|
||||
*
|
||||
* @param y y coordinate
|
||||
* @return this
|
||||
*/
|
||||
public Coord setY_ip(double y)
|
||||
{
|
||||
assertWritable();
|
||||
this.y = y;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set Z coordinate in place
|
||||
*
|
||||
* @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,81 +764,135 @@ public class Coord {
|
||||
/**
|
||||
* @return X as double
|
||||
*/
|
||||
@Override
|
||||
public double x()
|
||||
{
|
||||
return x;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return X as float
|
||||
*/
|
||||
public float xf()
|
||||
{
|
||||
return (float) x;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return X as int
|
||||
*/
|
||||
public int xi()
|
||||
{
|
||||
return (int) Math.round(x);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return Y as double
|
||||
*/
|
||||
@Override
|
||||
public double y()
|
||||
{
|
||||
return y;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return Y as float
|
||||
*/
|
||||
public float yf()
|
||||
{
|
||||
return (float) y;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return Y as int
|
||||
*/
|
||||
public int yi()
|
||||
{
|
||||
return (int) Math.round(y);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return Z as double
|
||||
*/
|
||||
@Override
|
||||
public double z()
|
||||
{
|
||||
return z;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return X as constraint view
|
||||
*/
|
||||
@Override
|
||||
public final NumberConstraint xc()
|
||||
{
|
||||
return xc != null ? xc : new NumberConstraint() {
|
||||
|
||||
@Override
|
||||
public double getValue()
|
||||
{
|
||||
return x();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return Y as constraint view
|
||||
*/
|
||||
@Override
|
||||
public final NumberConstraint yc()
|
||||
{
|
||||
return yc != null ? yc : new NumberConstraint() {
|
||||
|
||||
@Override
|
||||
public double getValue()
|
||||
{
|
||||
return y();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return Z as constraint view
|
||||
*/
|
||||
@Override
|
||||
public final NumberConstraint zc()
|
||||
{
|
||||
return zc != null ? zc : new NumberConstraint() {
|
||||
|
||||
@Override
|
||||
public double getValue()
|
||||
{
|
||||
return z();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return X as float
|
||||
*/
|
||||
public final float xf()
|
||||
{
|
||||
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 (float) z();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return X as int
|
||||
*/
|
||||
public final int xi()
|
||||
{
|
||||
return (int) Math.round(x());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return Y as int
|
||||
*/
|
||||
public final int yi()
|
||||
{
|
||||
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,7 +374,29 @@ public class Rect implements RectConstraint {
|
||||
*/
|
||||
public Coord getHMinVMax()
|
||||
{
|
||||
return new Coord(min.x, max.y);
|
||||
return HMinVMax;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get right bottom
|
||||
*
|
||||
* @return center
|
||||
*/
|
||||
public Coord getHMaxVMin()
|
||||
{
|
||||
return HMaxVMin;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get right top
|
||||
*
|
||||
* @return center
|
||||
*/
|
||||
public Coord getHMaxVMax()
|
||||
{
|
||||
return max.view();
|
||||
}
|
||||
|
||||
|
||||
@@ -317,29 +429,7 @@ public class Rect implements RectConstraint {
|
||||
*/
|
||||
public Coord getOrigin()
|
||||
{
|
||||
return getMin();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get right bottom
|
||||
*
|
||||
* @return center
|
||||
*/
|
||||
public Coord getHMaxVMin()
|
||||
{
|
||||
return new Coord(max.x, min.y);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get right top
|
||||
*
|
||||
* @return center
|
||||
*/
|
||||
public Coord getHMaxVMax()
|
||||
{
|
||||
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) {
|
||||
|
||||
Reference in New Issue
Block a user