Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added a Scene2DDebugRenderer #2011

Merged
merged 11 commits into from Jul 23, 2014
1 change: 1 addition & 0 deletions CHANGES
@@ -1,4 +1,5 @@
[1.2.1]
- API change: Added a new Scene2DDebugRenderer and removed the old Table debug rendering, see https://github.com/libgdx/libgdx/pull/2011
- Files#getLocalStoragePath now returns the actual path instead of the empty string synonym on desktop (LWJGL and JGLFW).
- Fixed and improved xorshift128+ PRNG implementation.
- Added support for Tiled's animated tiles, and varying frame duration tile animations.
Expand Down
3 changes: 2 additions & 1 deletion CONTRIBUTORS
Expand Up @@ -169,4 +169,5 @@ mbforbes https://github.com/mbforbes
Unkn0wn0ne https://github.com/Unkn0wn0ne
davebaol https://github.com/davebaol
CodePoKE https://github.com/codepoke
Konijnendijk https://github.com/Konijnendijk
Konijnendijk https://github.com/Konijnendijk
nooone https://github.com/nooone
36 changes: 31 additions & 5 deletions gdx/src/com/badlogic/gdx/scenes/scene2d/Actor.java
Expand Up @@ -24,6 +24,8 @@
import com.badlogic.gdx.scenes.scene2d.InputEvent.Type;
import com.badlogic.gdx.scenes.scene2d.utils.ActorGestureListener;
import com.badlogic.gdx.scenes.scene2d.utils.ClickListener;
import com.badlogic.gdx.scenes.scene2d.utils.Scene2DDebugRenderer;
import com.badlogic.gdx.scenes.scene2d.utils.Scene2DDebugRenderer.DebugRect;
import com.badlogic.gdx.scenes.scene2d.utils.ScissorStack;
import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.DelayedRemovalArray;
Expand Down Expand Up @@ -65,6 +67,9 @@ public class Actor {
final Color color = new Color(1, 1, 1, 1);
private Object userObject;

private boolean debuggingEnabled = true;
public static Color debugColor = new Color(0, 1, 0, 1);

/** Draws the actor. The Batch is configured to draw in the parent's coordinate system.
* {@link Batch#draw(com.badlogic.gdx.graphics.g2d.TextureRegion, float, float, float, float, float, float, float, float, float)
* This draw method} is convenient to draw a rotated and scaled TextureRegion. {@link Batch#begin()} has already been called on
Expand Down Expand Up @@ -379,16 +384,16 @@ public void setPosition (float x, float y) {
}

/** Set position of Actor centered on x, y */
public void setCenterPosition(float x, float y) {
public void setCenterPosition (float x, float y) {
this.x = x - width / 2;
this.y = y - height / 2;
}

public float getCenterX() {
public float getCenterX () {
return this.x + width / 2;
}

public float getCenterY() {
public float getCenterY () {
return this.y + height / 2;
}

Expand Down Expand Up @@ -554,8 +559,7 @@ public Color getColor () {
return color;
}

/** Retrieve custom actor name set with {@link Actor#setName(String)},
* used for easier identification */
/** Retrieve custom actor name set with {@link Actor#setName(String)}, used for easier identification */
public String getName () {
return name;
}
Expand All @@ -566,6 +570,28 @@ public void setName (String name) {
this.name = name;
}

/** The {@link Scene2DDebugRenderer} will ask every actor of a stage for their debugging rectangles. To fill the given array you
* can obtain fresh {@link DebugRect}s via the {@link Scene2DDebugRenderer#debugRectPool}. To avoid the garbage collection you
* should make sure to free them later, but it's not a strict requirement. */
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Who should free them and when? If they are from Scene2DDebugRenderer.debugRectPool can't they be freed automatically?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm shuffling things around slightly, please hold. :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't have a look at the refactored code yet, but the custom Actor should free them, whenever they want to. I wasn't able to free them automatically (for example after rendering them in Scene2DDebugRenderer, because Table keeps them for a longer time.

public void getDebugRects (Array<DebugRect> debugRects) {
DebugRect debugRect = Scene2DDebugRenderer.debugRectPool.obtain();
debugRect.bottomLeft.set(0, 0);
debugRect.topRight.set(width, height);
debugRect.color.set(Actor.debugColor);
debugRects.add(debugRect);
}

/** Used only in combination with a {@link Scene2DDebugRenderer}. It does only influence this particular actor, not its
* children, in case we have a {@link Group}. */
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note the first sentence is used for the summary in javadocs, so should describe the method succinctly. Subsequent sentences can give more details. /pedantic :)

public void setDebuggingEnabled (boolean enabled) {
debuggingEnabled = enabled;
}

/** Used only in combination with a {@link Scene2DDebugRenderer}. */
public boolean isDebuggingEnabled () {
return debuggingEnabled;
}

/** Changes the z-order for this actor so it is in front of all siblings. */
public void toFront () {
setZIndex(Integer.MAX_VALUE);
Expand Down
20 changes: 18 additions & 2 deletions gdx/src/com/badlogic/gdx/scenes/scene2d/Group.java
Expand Up @@ -22,6 +22,7 @@
import com.badlogic.gdx.math.Rectangle;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.scenes.scene2d.utils.Cullable;
import com.badlogic.gdx.scenes.scene2d.utils.Scene2DDebugRenderer;
import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.SnapshotArray;

Expand Down Expand Up @@ -289,12 +290,12 @@ public void clear () {
public <T extends Actor> T findActor (String name) {
Array<Actor> children = this.children;
for (int i = 0, n = children.size; i < n; i++)
if (name.equals(children.get(i).getName())) return (T) children.get(i);
if (name.equals(children.get(i).getName())) return (T)children.get(i);
for (int i = 0, n = children.size; i < n; i++) {
Actor child = children.get(i);
if (child instanceof Group) {
Actor actor = ((Group)child).findActor(name);
if (actor != null) return (T) actor;
if (actor != null) return (T)actor;
}
}
return null;
Expand Down Expand Up @@ -364,6 +365,21 @@ public void print () {
print("");
}

/** Used only in combination with a {@link Scene2DDebugRenderer}.
* @param recursively If {@code true} it will also recursively disable all children of this group. */
public void setDebuggingEnabled (boolean enabled, boolean recursively) {
setDebuggingEnabled(enabled);
if (recursively) {
for (Actor child : children) {
if (child instanceof Group) {
((Group)child).setDebuggingEnabled(enabled, recursively);
} else {
child.setDebuggingEnabled(enabled);
}
}
}
}

private void print (String indent) {
Actor[] actors = children.begin();
for (int i = 0, n = children.size; i < n; i++) {
Expand Down
153 changes: 37 additions & 116 deletions gdx/src/com/badlogic/gdx/scenes/scene2d/ui/Table.java
Expand Up @@ -16,23 +16,17 @@

package com.badlogic.gdx.scenes.scene2d.ui;

import com.badlogic.gdx.Application;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.g2d.Batch;
import com.badlogic.gdx.graphics.glutils.ImmediateModeRenderer;
import com.badlogic.gdx.graphics.glutils.ImmediateModeRenderer20;
import com.badlogic.gdx.math.Rectangle;
import com.badlogic.gdx.scenes.scene2d.Actor;
import com.badlogic.gdx.scenes.scene2d.Group;
import com.badlogic.gdx.scenes.scene2d.Stage;
import com.badlogic.gdx.scenes.scene2d.Touchable;
import com.badlogic.gdx.scenes.scene2d.ui.Label.LabelStyle;
import com.badlogic.gdx.scenes.scene2d.ui.Value.Fixed;
import com.badlogic.gdx.scenes.scene2d.utils.Align;
import com.badlogic.gdx.scenes.scene2d.utils.Drawable;
import com.badlogic.gdx.scenes.scene2d.utils.Layout;
import com.badlogic.gdx.scenes.scene2d.utils.Scene2DDebugRenderer;
import com.badlogic.gdx.scenes.scene2d.utils.Scene2DDebugRenderer.DebugRect;
import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.Pool;

Expand All @@ -42,6 +36,10 @@
* The preferred and minimum sizes are that of the children when laid out in columns and rows.
* @author Nathan Sweet */
public class Table extends WidgetGroup {

public static Color debugColor = new Color(0, 0, 1, 1);
public static Color debugCellColor = new Color(1, 0, 0, 1);

static Pool<Cell> cellPool = new Pool<Cell>() {
protected Cell newObject () {
return new Cell();
Expand All @@ -68,7 +66,7 @@ protected Cell newObject () {
int align = Align.center;

Debug debug = Debug.none;
Array<DebugRect> debugRects;
Array<DebugRect> debugRects = new Array<DebugRect>();

private Drawable background;
private boolean clip;
Expand Down Expand Up @@ -281,7 +279,7 @@ public Cell<Label> add (String text, String fontName, String colorName) {

/** Adds a cell without an actor. */
public Cell add () {
return add((Actor) null);
return add((Actor)null);
}

/** Adds a new cell to the table with the specified actors in a {@link Stack}.
Expand Down Expand Up @@ -329,7 +327,10 @@ public void reset () {
padBottom = Value.zero;
padRight = Value.zero;
align = Align.center;
if (debug != Debug.none) debugRects.clear();
if (debug != Debug.none) {
Scene2DDebugRenderer.debugRectPool.freeAll(debugRects);
debugRects.clear();
}
debug = Debug.none;
cellDefaults.defaults();
for (int i = 0, n = columnDefaults.size; i < n; i++) {
Expand Down Expand Up @@ -598,7 +599,10 @@ public Table debugActor () {
public Table debug (Debug debug) {
this.debug = debug;
if (debug == Debug.none) {
if (debugRects != null) debugRects.clear();
if (debugRects != null) {
Scene2DDebugRenderer.debugRectPool.freeAll(debugRects);
debugRects.clear();
}
} else
invalidate();
return this;
Expand Down Expand Up @@ -1099,19 +1103,22 @@ else if ((c.align & Align.bottom) != 0)

// Store debug rectangles.
if (debug == Debug.none) return;
if (debugRects != null) debugRects.clear();
if (debugRects != null) {
Scene2DDebugRenderer.debugRectPool.freeAll(debugRects);
debugRects.clear();
}
currentX = x;
currentY = y;
if (debug == Debug.table || debug == Debug.all) {
TableDebug.addRectangle(this, Debug.table, layoutX, layoutY, layoutWidth, layoutHeight);
TableDebug.addRectangle(this, Debug.table, x, y, tableWidth - hpadding, tableHeight - vpadding);
addDebugRect(layoutX, layoutY, layoutWidth, layoutHeight, debugColor);
addDebugRect(x, y, tableWidth - hpadding, tableHeight - vpadding, debugColor);
}
for (int i = 0; i < cellCount; i++) {
Cell c = cells.get(i);

// Actor bounds.
if (debug == Debug.actor || debug == Debug.all)
TableDebug.addRectangle(this, Debug.actor, c.actorX, c.actorY, c.actorWidth, c.actorHeight);
addDebugRect(c.actorX, c.actorY, c.actorWidth, c.actorHeight, Actor.debugColor);

// Cell bounds.
float spannedCellWidth = 0;
Expand All @@ -1120,8 +1127,8 @@ else if ((c.align & Align.bottom) != 0)
spannedCellWidth -= c.computedPadLeft + c.computedPadRight;
currentX += c.computedPadLeft;
if (debug == Debug.cell || debug == Debug.all) {
TableDebug.addRectangle(this, Debug.cell, currentX, currentY + c.computedPadTop, spannedCellWidth, rowHeight[c.row]
- c.computedPadTop - c.computedPadBottom);
addDebugRect(currentX, currentY + c.computedPadTop, spannedCellWidth, rowHeight[c.row] - c.computedPadTop
- c.computedPadBottom, debugCellColor);
}

if (c.endRow) {
Expand All @@ -1132,109 +1139,23 @@ else if ((c.align & Align.bottom) != 0)
}
}

/** Draws the debug lines for all tables in the stage. If this method is not called each frame, no debug lines will be drawn. If
* debug is never turned on for any table in the application, calling this method will have no effect. If a table has ever had
* debug set, calling this method causes an expensive traversal of all actors in the stage. */
static public void drawDebug (Stage stage) {
if (TableDebug.draw) TableDebug.draw(stage);
@Override
public void getDebugRects (Array<DebugRect> debugRects) {
debugRects.addAll(this.debugRects);
}

/** @author Nathan Sweet */
static public enum Debug {
none, all, table, cell, actor
private void addDebugRect (float x, float y, float width, float height, Color color) {
DebugRect debugRect = Scene2DDebugRenderer.debugRectPool.obtain();
float yCorrected = getHeight() - y - height;
debugRect.bottomLeft.set(x, yCorrected);
debugRect.topRight.set(x + width, yCorrected + height);
debugRect.color.set(color);
debugRects.add(debugRect);
}

/** @author Nathan Sweet */
static class DebugRect extends Rectangle {
final Debug type;

public DebugRect (Debug type, float x, float y, float width, float height) {
super(x, y, width, height);
this.type = type;
}
static public enum Debug {
none, all, table, cell, actor
}

/** @author Nathan Sweet */
static class TableDebug {
static boolean draw;

static private Application app;
static private ImmediateModeRenderer debugRenderer;

static public void addRectangle (Table table, Debug type, float x, float y, float w, float h) {
draw = true;
if (table.debugRects == null) table.debugRects = new Array();
table.debugRects.add(new DebugRect(type, x, table.getHeight() - y, w, h));
}

static void draw (Stage stage) {
// Handle cases where Android holds on to static objects
if (app != Gdx.app || debugRenderer == null) {
debugRenderer = new ImmediateModeRenderer20(128, false, true, 0);
app = Gdx.app;
}

debugRenderer.begin(stage.getBatch().getProjectionMatrix(), GL20.GL_LINES);
draw(stage.getActors());
debugRenderer.end();
}

static void draw (Array<Actor> actors) {
for (int i = 0, n = actors.size; i < n; i++) {
Actor actor = actors.get(i);
if (!actor.isVisible()) continue;
if (actor instanceof Table) draw((Table)actor);
if (actor instanceof Group) draw(((Group)actor).getChildren());
}
}

static public void draw (Table table) {
if (table.debug == Debug.none) return;
Array<DebugRect> debugRects = table.debugRects;
if (debugRects == null) return;

float x = 0, y = 0;
Actor parent = table;
while (parent != null) {
if (parent instanceof Group) {
x += parent.getX();
y += parent.getY();
}
parent = parent.getParent();
}

for (int i = 0, n = debugRects.size; i < n; i++) {
DebugRect rect = debugRects.get(i);
float x1 = x + rect.x;
float y1 = y + rect.y - rect.height;
float x2 = x1 + rect.width;
float y2 = y1 + rect.height;
float r = rect.type == Debug.cell ? 1 : 0;
float g = rect.type == Debug.actor ? 1 : 0;
float b = rect.type == Debug.table ? 1 : 0;

debugRenderer.color(r, g, b, 1);
debugRenderer.vertex(x1, y1, 0);
debugRenderer.color(r, g, b, 1);
debugRenderer.vertex(x1, y2, 0);

debugRenderer.color(r, g, b, 1);
debugRenderer.vertex(x1, y2, 0);
debugRenderer.color(r, g, b, 1);
debugRenderer.vertex(x2, y2, 0);

debugRenderer.color(r, g, b, 1);
debugRenderer.vertex(x2, y2, 0);
debugRenderer.color(r, g, b, 1);
debugRenderer.vertex(x2, y1, 0);

debugRenderer.color(r, g, b, 1);
debugRenderer.vertex(x2, y1, 0);
debugRenderer.color(r, g, b, 1);
debugRenderer.vertex(x1, y1, 0);

if (debugRenderer.getNumVertices() == 128) debugRenderer.flush();
}
}
}
}