Digest caching, oh boy! Such commit! Wow!

v5stable
Ondřej Hruška 10 years ago
parent de34b66fde
commit 85859995c4
  1. 40
      src/mightypork/gamecore/control/bus/EventBus.java
  2. 13
      src/mightypork/gamecore/gui/Action.java
  3. 8
      src/mightypork/gamecore/gui/components/BusEnabledPainter.java
  4. 7
      src/mightypork/gamecore/gui/components/Component.java
  5. 5
      src/mightypork/gamecore/gui/components/painters/TextPainter.java
  6. 12
      src/mightypork/gamecore/render/Render.java
  7. 10
      src/mightypork/gamecore/render/fonts/FontRenderer.java
  8. 14
      src/mightypork/rogue/App.java
  9. 16
      src/mightypork/rogue/Main.java
  10. 16
      src/mightypork/rogue/screens/test_bouncyboxes/BouncyBox.java
  11. 10
      src/mightypork/rogue/screens/test_bouncyboxes/LayerBouncyBoxes.java
  12. 6
      src/mightypork/utils/math/animation/AnimDouble.java
  13. 35
      src/mightypork/utils/math/constraints/num/Num.java
  14. 10
      src/mightypork/utils/math/constraints/num/NumDigest.java
  15. 38
      src/mightypork/utils/math/constraints/rect/Rect.java
  16. 28
      src/mightypork/utils/math/constraints/rect/RectDigest.java
  17. 61
      src/mightypork/utils/math/constraints/vect/Digestable.java
  18. 35
      src/mightypork/utils/math/constraints/vect/Vect.java
  19. 11
      src/mightypork/utils/math/constraints/vect/VectDigest.java

@ -198,30 +198,28 @@ final public class EventBus implements Destroyable {
{ {
assertLive(); assertLive();
synchronized (this) { channels.setBuffering(true);
channels.setBuffering(true); clients.setBuffering(true);
clients.setBuffering(true);
boolean sent = false;
boolean sent = false; boolean accepted = false;
boolean accepted = false;
final boolean singular = event.getClass().isAnnotationPresent(SingleReceiverEvent.class);
final boolean singular = event.getClass().isAnnotationPresent(SingleReceiverEvent.class);
for (final EventChannel<?, ?> b : channels) {
for (final EventChannel<?, ?> b : channels) { if (b.canBroadcast(event)) {
if (b.canBroadcast(event)) { accepted = true;
accepted = true; sent |= b.broadcast(event, clients);
sent |= b.broadcast(event, clients);
}
if (sent && singular) break;
} }
if (!accepted) Log.e("<bus> Not accepted by any channel: " + Log.str(event)); if (sent && singular) break;
if (!sent && shallLog(event)) Log.w("<bus> Not delivered: " + Log.str(event));
channels.setBuffering(false);
clients.setBuffering(false);
} }
if (!accepted) Log.e("<bus> Not accepted by any channel: " + Log.str(event));
if (!sent && shallLog(event)) Log.w("<bus> Not delivered: " + Log.str(event));
channels.setBuffering(false);
clients.setBuffering(false);
} }

@ -1,12 +1,15 @@
package mightypork.gamecore.gui; package mightypork.gamecore.gui;
import mightypork.gamecore.control.interf.Enableable;
/** /**
* Triggered action * Triggered action
* *
* @author MightyPork * @author MightyPork
*/ */
public abstract class Action implements Runnable { public abstract class Action implements Runnable, Enableable {
private boolean enabled = true; private boolean enabled = true;
@ -16,7 +19,8 @@ public abstract class Action implements Runnable {
* *
* @param enable true to enable * @param enable true to enable
*/ */
public void setEnabled(boolean enable) @Override
public final void enable(boolean enable)
{ {
this.enabled = enable; this.enabled = enable;
} }
@ -25,14 +29,15 @@ public abstract class Action implements Runnable {
/** /**
* @return true if this action is enabled. * @return true if this action is enabled.
*/ */
public boolean isEnabled() @Override
public final boolean isEnabled()
{ {
return enabled; return enabled;
} }
@Override @Override
public void run() public final void run()
{ {
if (enabled) execute(); if (enabled) execute();
} }

@ -10,7 +10,6 @@ import mightypork.gamecore.control.bus.EventBus;
import mightypork.gamecore.control.bus.clients.ClientHub; import mightypork.gamecore.control.bus.clients.ClientHub;
import mightypork.gamecore.input.InputSystem; import mightypork.gamecore.input.InputSystem;
import mightypork.gamecore.render.DisplaySystem; import mightypork.gamecore.render.DisplaySystem;
import mightypork.utils.annotations.DefaultImpl;
import mightypork.utils.math.constraints.RectBound; import mightypork.utils.math.constraints.RectBound;
import mightypork.utils.math.constraints.rect.Rect; import mightypork.utils.math.constraints.rect.Rect;
@ -153,11 +152,4 @@ public abstract class BusEnabledPainter extends SimplePainter implements ClientH
protected abstract void paint(); protected abstract void paint();
@Override
@DefaultImpl
public void update(double delta)
{
}
} }

@ -3,7 +3,6 @@ package mightypork.gamecore.gui.components;
import mightypork.gamecore.control.bus.clients.ToggleableClient; import mightypork.gamecore.control.bus.clients.ToggleableClient;
import mightypork.gamecore.control.interf.Enableable; import mightypork.gamecore.control.interf.Enableable;
import mightypork.gamecore.control.timing.Updateable;
import mightypork.gamecore.gui.Hideable; import mightypork.gamecore.gui.Hideable;
import mightypork.utils.math.constraints.RectBound; import mightypork.utils.math.constraints.RectBound;
import mightypork.utils.math.constraints.rect.Rect; import mightypork.utils.math.constraints.rect.Rect;
@ -14,7 +13,7 @@ import mightypork.utils.math.constraints.rect.Rect;
* *
* @author MightyPork * @author MightyPork
*/ */
public interface Component extends Hideable, PluggableRenderable, Updateable, Enableable, ToggleableClient { public interface Component extends Hideable, PluggableRenderable, Enableable, ToggleableClient {
/** /**
* Enable the component. This includes listening to event bus, and any * Enable the component. This includes listening to event bus, and any
@ -51,10 +50,6 @@ public interface Component extends Hideable, PluggableRenderable, Updateable, En
void render(); void render();
@Override
void update(double delta);
@Override @Override
public boolean isListening(); public boolean isListening();
} }

@ -8,7 +8,6 @@ import mightypork.gamecore.render.fonts.GLFont;
import mightypork.utils.math.color.RGB; import mightypork.utils.math.color.RGB;
import mightypork.utils.math.constraints.rect.Rect; import mightypork.utils.math.constraints.rect.Rect;
import mightypork.utils.math.constraints.vect.Vect; import mightypork.utils.math.constraints.vect.Vect;
import mightypork.utils.math.constraints.vect.VectVar;
import mightypork.utils.string.StringProvider; import mightypork.utils.string.StringProvider;
import mightypork.utils.string.StringProvider.StringWrapper; import mightypork.utils.string.StringProvider.StringWrapper;
@ -29,7 +28,7 @@ public class TextPainter extends SimplePainter {
private boolean shadow; private boolean shadow;
private RGB shadowColor = RGB.BLACK; private RGB shadowColor = RGB.BLACK;
private final VectVar shadowOffset = Vect.makeVar(1, 1); private Vect shadowOffset = Vect.make(1, 1);
/** /**
@ -116,7 +115,7 @@ public class TextPainter extends SimplePainter {
public void setShadowOffset(Vect shadowOffset) public void setShadowOffset(Vect shadowOffset)
{ {
this.shadowOffset.setTo(shadowOffset); this.shadowOffset = shadowOffset;
} }

@ -92,6 +92,17 @@ public class Render {
} }
/**
* Translate with coord, discard Z
*
* @param coord coord
*/
public static void translateXY(Vect coord)
{
glTranslated(coord.x(), coord.y(), 0);
}
/** /**
* Scale * Scale
* *
@ -352,7 +363,6 @@ public class Render {
public static void quad(Rect quad) public static void quad(Rect quad)
{ {
final RectDigest q = quad.digest(); final RectDigest q = quad.digest();
System.out.println(q);
// draw with color // draw with color
unbindTexture(); unbindTexture();

@ -5,7 +5,6 @@ import mightypork.gamecore.render.Render;
import mightypork.utils.math.color.RGB; import mightypork.utils.math.color.RGB;
import mightypork.utils.math.constraints.rect.Rect; import mightypork.utils.math.constraints.rect.Rect;
import mightypork.utils.math.constraints.vect.Vect; import mightypork.utils.math.constraints.vect.Vect;
import mightypork.utils.math.constraints.vect.VectVar;
/** /**
@ -109,7 +108,7 @@ public class FontRenderer {
{ {
Render.pushMatrix(); Render.pushMatrix();
Render.translate(pos.freeze().round()); Render.translateXY(pos.round());
Render.scaleXY(getScale(height)); Render.scaleXY(getScale(height));
font.draw(text, color); font.draw(text, color);
@ -192,19 +191,20 @@ public class FontRenderer {
final double w = getWidth(text, height); final double w = getWidth(text, height);
final VectVar start = Vect.makeVar(pos); Vect start;
switch (align) { switch (align) {
case LEFT: case LEFT:
start = pos;
break; break;
case CENTER: case CENTER:
start.sub(w / 2D, 0); start = pos.sub(w / 2D, 0);
break; break;
case RIGHT: case RIGHT:
default: default:
start.sub(w, 0); start = pos.sub(w, 0);
break; break;
} }

@ -29,6 +29,20 @@ import mightypork.utils.logging.LogWriter;
*/ */
public class App extends BaseApp { public class App extends BaseApp {
/**
* Launcher
*
* @param args
*/
public static void main(String[] args)
{
Config.init();
Config.save();
(new App()).start();
}
@Override @Override
protected LogWriter createLog() protected LogWriter createLog()
{ {

@ -1,16 +0,0 @@
package mightypork.rogue;
public class Main {
/**
* @param args
*/
public static void main(String[] args)
{
Config.init();
Config.save();
(new App()).start();
}
}

@ -3,6 +3,7 @@ package mightypork.rogue.screens.test_bouncyboxes;
import java.util.Random; import java.util.Random;
import mightypork.gamecore.control.bus.events.ScreenChangeEvent;
import mightypork.gamecore.control.timing.Updateable; import mightypork.gamecore.control.timing.Updateable;
import mightypork.gamecore.gui.components.SimplePainter; import mightypork.gamecore.gui.components.SimplePainter;
import mightypork.gamecore.render.Render; import mightypork.gamecore.render.Render;
@ -13,7 +14,7 @@ import mightypork.utils.math.constraints.num.Num;
import mightypork.utils.math.constraints.rect.Rect; import mightypork.utils.math.constraints.rect.Rect;
public class BouncyBox extends SimplePainter implements Updateable { public class BouncyBox extends SimplePainter implements Updateable, ScreenChangeEvent.Listener {
private final Random rand = new Random(); private final Random rand = new Random();
@ -30,6 +31,7 @@ public class BouncyBox extends SimplePainter implements Updateable {
abox = abox.shrink(height().perc(10)); abox = abox.shrink(height().perc(10));
box = abox; box = abox;
box.enableDigestCaching(true);
} }
@ -55,7 +57,17 @@ public class BouncyBox extends SimplePainter implements Updateable {
@Override @Override
public void update(double delta) public void update(double delta)
{ {
pos.update(delta); if (pos.isInProgress()) {
pos.update(delta);
box.poll();
}
}
@Override
public void receive(ScreenChangeEvent event)
{
box.poll();
} }
} }

@ -13,6 +13,7 @@ import mightypork.gamecore.input.Keys;
import mightypork.gamecore.render.fonts.FontRenderer.Align; import mightypork.gamecore.render.fonts.FontRenderer.Align;
import mightypork.rogue.Res; import mightypork.rogue.Res;
import mightypork.utils.math.color.RGB; import mightypork.utils.math.color.RGB;
import mightypork.utils.math.constraints.num.Num;
import mightypork.utils.math.constraints.rect.Rect; import mightypork.utils.math.constraints.rect.Rect;
import mightypork.utils.math.constraints.vect.Vect; import mightypork.utils.math.constraints.vect.Vect;
@ -50,9 +51,9 @@ public class LayerBouncyBoxes extends ScreenLayer {
final Rect holder_rect = b.shrink(b.height().perc(8)); final Rect holder_rect = b.shrink(b.height().perc(8));
addChildClient(layout = new RowHolder(screen, holder_rect, 2)); addChildClient(layout = new RowHolder(screen, holder_rect, 100));
for (int i = 0; i <= 0; i++) { for (int i = 0; i < 99; i++) {
final BouncyBox bbr = new BouncyBox(); final BouncyBox bbr = new BouncyBox();
layout.add(bbr); layout.add(bbr);
boxes.add(bbr); boxes.add(bbr);
@ -60,7 +61,10 @@ public class LayerBouncyBoxes extends ScreenLayer {
final TextPainter tp = new TextPainter(Res.getFont("default"), Align.LEFT, RGB.WHITE); final TextPainter tp = new TextPainter(Res.getFont("default"), Align.LEFT, RGB.WHITE);
tp.setText("Press \"C\" for \"Cat\" screen."); tp.setText("Press \"C\" for \"Cat\" screen.");
tp.setShadow(RGB.RED, Vect.make(2, 2));
final Num shadowOffset = tp.height().div(16 * 2); // half pixel if 16px font
tp.setShadow(RGB.RED, Vect.make(shadowOffset, shadowOffset));
layout.add(tp); layout.add(tp);
} }

@ -369,4 +369,10 @@ public class AnimDouble extends NumMutable implements Updateable, Pauseable {
{ {
return paused; return paused;
} }
public boolean isInProgress()
{
return !isFinished() && !isPaused();
}
} }

@ -3,9 +3,10 @@ package mightypork.utils.math.constraints.num;
import mightypork.utils.annotations.FactoryMethod; import mightypork.utils.annotations.FactoryMethod;
import mightypork.utils.math.Calc; import mightypork.utils.math.Calc;
import mightypork.utils.math.constraints.vect.Digestable;
public abstract class Num implements NumBound { public abstract class Num implements NumBound, Digestable<NumDigest> {
public static final NumConst ZERO = Num.make(0); public static final NumConst ZERO = Num.make(0);
public static final NumConst ONE = Num.make(1); public static final NumConst ONE = Num.make(1);
@ -61,6 +62,8 @@ public abstract class Num implements NumBound {
private Num p_square; private Num p_square;
private Num p_neg; private Num p_neg;
private Num p_abs; private Num p_abs;
private NumDigest lastDigest;
private boolean digestCachingEnabled;
public NumConst freeze() public NumConst freeze()
@ -74,9 +77,37 @@ public abstract class Num implements NumBound {
* *
* @return digest * @return digest
*/ */
@Override
public NumDigest digest() public NumDigest digest()
{ {
return new NumDigest(this); if (digestCachingEnabled && lastDigest != null) return lastDigest;
return lastDigest = new NumDigest(this);
}
@Override
public void enableDigestCaching(boolean yes)
{
digestCachingEnabled = yes;
}
/**
* @return true if digest caching is enabled.
*/
@Override
public boolean isDigestCachingEnabled()
{
return digestCachingEnabled;
}
@Override
public void poll()
{
if (digestCachingEnabled) lastDigest = new NumDigest(this);
} }

@ -3,13 +3,17 @@ package mightypork.utils.math.constraints.num;
public class NumDigest { public class NumDigest {
public final NumConst source;
public final double value; public final double value;
public NumDigest(Num num) { public NumDigest(Num num) {
this.value = num.value(); this.value = num.value();
this.source = num.freeze(); }
@Override
public String toString()
{
return String.format("Num(%.1f)", value);
} }
} }

@ -5,6 +5,7 @@ import mightypork.utils.annotations.FactoryMethod;
import mightypork.utils.math.constraints.RectBound; import mightypork.utils.math.constraints.RectBound;
import mightypork.utils.math.constraints.num.Num; import mightypork.utils.math.constraints.num.Num;
import mightypork.utils.math.constraints.num.NumConst; import mightypork.utils.math.constraints.num.NumConst;
import mightypork.utils.math.constraints.vect.Digestable;
import mightypork.utils.math.constraints.vect.Vect; import mightypork.utils.math.constraints.vect.Vect;
import mightypork.utils.math.constraints.vect.VectConst; import mightypork.utils.math.constraints.vect.VectConst;
@ -14,7 +15,7 @@ import mightypork.utils.math.constraints.vect.VectConst;
* *
* @author MightyPork * @author MightyPork
*/ */
public abstract class Rect implements RectBound { public abstract class Rect implements RectBound, Digestable<RectDigest> {
public static final RectConst ZERO = new RectConst(0, 0, 0, 0); public static final RectConst ZERO = new RectConst(0, 0, 0, 0);
public static final RectConst ONE = new RectConst(0, 0, 1, 1); public static final RectConst ONE = new RectConst(0, 0, 1, 1);
@ -159,6 +160,9 @@ public abstract class Rect implements RectBound {
private Rect p_edge_t; private Rect p_edge_t;
private Rect p_edge_b; private Rect p_edge_b;
private RectDigest lastDigest = null;
private boolean digestCachingEnabled = false;
/** /**
* Get a copy of current value * Get a copy of current value
@ -172,14 +176,36 @@ public abstract class Rect implements RectBound {
} }
@Override
public RectDigest digest()
{
if (digestCachingEnabled && lastDigest != null) return lastDigest;
return lastDigest = new RectDigest(this);
}
@Override
public void enableDigestCaching(boolean yes)
{
digestCachingEnabled = yes;
}
/** /**
* Get a snapshot of the current state, to be used for processing. * @return true if digest caching is enabled.
*
* @return digest
*/ */
public RectDigest digest() @Override
public boolean isDigestCachingEnabled()
{
return digestCachingEnabled;
}
@Override
public void poll()
{ {
return new RectDigest(this); if (digestCachingEnabled) lastDigest = new RectDigest(this);
} }

@ -1,15 +1,10 @@
package mightypork.utils.math.constraints.rect; package mightypork.utils.math.constraints.rect;
import mightypork.utils.math.constraints.vect.VectConst;
public class RectDigest { public class RectDigest {
public final RectConst source;
public final VectConst origin;
public final VectConst size;
public final double x; public final double x;
public final double y; public final double y;
public final double width; public final double width;
@ -22,27 +17,26 @@ public class RectDigest {
public RectDigest(Rect rect) { public RectDigest(Rect rect) {
this.source = rect.freeze();
this.origin = rect.origin().freeze(); final RectConst frozen = rect.freeze();
this.size = rect.size().freeze();
this.x = rect.x().value(); this.x = frozen.x().value();
this.y = rect.y().value(); this.y = frozen.y().value();
this.width = rect.width().value(); this.width = frozen.width().value();
this.height = rect.height().value(); this.height = frozen.height().value();
this.left = rect.left().value(); this.left = frozen.left().value();
this.right = rect.right().value(); this.right = frozen.right().value();
this.top = rect.top().value(); this.top = frozen.top().value();
this.bottom = rect.bottom().value(); this.bottom = frozen.bottom().value();
} }
@Override @Override
public String toString() public String toString()
{ {
return String.format("Rect at: (%.1f, %.1f), size: (%.1f, %.1f), bounds: L %.1f R %.1f T %.1f B %.1f", x, y, width, height, left, right, top, bottom); return String
.format("Rect{ at: (%.1f, %.1f), size: (%.1f, %.1f), bounds: L %.1f R %.1f T %.1f B %.1f }", x, y, width, height, left, right, top, bottom);
} }
} }

@ -0,0 +1,61 @@
package mightypork.utils.math.constraints.vect;
import mightypork.gamecore.control.timing.Pollable;
/**
* <p>
* Interface for constraints that support digests. Digest is a small data object
* with final fields, typically primitive, used for procesing (such as rendering
* or other very frequent operations).
* </p>
* <p>
* Taking a digest is expensive, so if it needs to be done often and the value
* changes are deterministic (such as, triggered by timing event or screen
* resize), it's useful to cache the last digest and reuse it until such an
* event occurs again.
* </p>
*
* @author MightyPork
* @param <D> digest class
*/
public interface Digestable<D> extends Pollable {
/**
* Take a digest. If digest caching is enabled and a digest is already
* cached, it should be reused instead of making a new one.
*
* @return digest
*/
public D digest();
/**
* <p>
* Toggle digest caching.
* </p>
* <p>
* To trigger update of the cache, call the <code>poll()</code> method.
* </p>
*
* @param yes
*/
void enableDigestCaching(boolean yes);
/**
* @return true if digest caching is enabled.
*/
boolean isDigestCachingEnabled();
/**
* If digest caching is enabled, query for a new digest and store it in a
* cache variable. This method shall only be called when the constraint is
* expected to have changed.
*/
@Override
void poll();
}

@ -14,7 +14,7 @@ import mightypork.utils.math.constraints.rect.Rect;
* *
* @author MightyPork * @author MightyPork
*/ */
public abstract class Vect implements VectBound { public abstract class Vect implements VectBound, Digestable<VectDigest> {
public static final VectConst ZERO = new VectConst(0, 0, 0); public static final VectConst ZERO = new VectConst(0, 0, 0);
public static final VectConst ONE = new VectConst(1, 1, 1); public static final VectConst ONE = new VectConst(1, 1, 1);
@ -104,6 +104,8 @@ public abstract class Vect implements VectBound {
private Num p_xc; private Num p_xc;
private Num p_yc; private Num p_yc;
private Num p_zc; private Num p_zc;
private boolean digestCachingEnabled;
private VectDigest lastDigest;
/** /**
@ -236,14 +238,33 @@ public abstract class Vect implements VectBound {
} }
/** @Override
* Get a snapshot of the current state, to be used for processing.
*
* @return digest
*/
public VectDigest digest() public VectDigest digest()
{ {
return new VectDigest(this); if (digestCachingEnabled && lastDigest != null) return lastDigest;
return lastDigest = new VectDigest(this);
}
@Override
public void enableDigestCaching(boolean yes)
{
digestCachingEnabled = yes;
}
@Override
public boolean isDigestCachingEnabled()
{
return digestCachingEnabled;
}
@Override
public void poll()
{
if (digestCachingEnabled) lastDigest = new VectDigest(this);
} }

@ -3,18 +3,21 @@ package mightypork.utils.math.constraints.vect;
public class VectDigest { public class VectDigest {
public final VectConst source;
public final double x; public final double x;
public final double y; public final double y;
public final double z; public final double z;
public VectDigest(Vect vect) { public VectDigest(Vect vect) {
this.source = vect.freeze();
this.x = vect.x(); this.x = vect.x();
this.y = vect.y(); this.y = vect.y();
this.z = vect.z(); this.z = vect.z();
} }
@Override
public String toString()
{
return String.format("Vect(%.1f, %.1f, %.1f)", x, y, z);
}
} }

Loading…
Cancel
Save