Skip to content

Instantly share code, notes, and snippets.

@chandujr
Created August 2, 2016 10:21
Show Gist options
  • Star 6 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save chandujr/5d79f3603efadb566d0a8f7edb5ba0ad to your computer and use it in GitHub Desktop.
Save chandujr/5d79f3603efadb566d0a8f7edb5ba0ad to your computer and use it in GitHub Desktop.
This class helps to create a circular progress indicator. This is an updated version of the code by forum user Xoppa. You can see the original code here: https://github.com/xoppa/world/blob/master/src/com/xoppa/android/misc/RadialSprite.java
/**
* An updated version of the code by forum user Xoppa.
* You can see the original code here: https://github.com/xoppa/world/blob/master/src/com/xoppa/android/misc/RadialSprite.java
**/
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.Batch;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.math.MathUtils;
import com.badlogic.gdx.scenes.scene2d.utils.Drawable;
/** @author Xoppa */
class RadialSprite implements Drawable {
private final static int TOPRIGHT1 = 0;
private final static int BOTTOMRIGHT1 = 5;
private final static int BOTTOMLEFT1 = 10;
private final static int TOPLEFT1 = 15;
private final static int TOPRIGHT2 = 20;
private final static int BOTTOMRIGHT2 = 25;
private final static int BOTTOMLEFT2 = 30;
private final static int TOPLEFT2 = 35;
private final static int TOPRIGHT3 = 40;
private final static int BOTTOMRIGHT3 = 45;
private final static int BOTTOMLEFT3 = 50;
private final static int TOPLEFT3 = 55;
private Texture texture;
private final float[] verts = new float[60];
private float x, y, angle, width, height, u1, u2, v1, v2, du, dv;
private boolean dirty = true;
private int draw = 0;
private float angleOffset = 270f;
private float originX, originY;
private float scaleX = 1f, scaleY = 1f;
RadialSprite(final TextureRegion textureRegion) {
this.texture = textureRegion.getTexture();
this.u1 = textureRegion.getU();
this.v1 = textureRegion.getV();
this.u2 = textureRegion.getU2();
this.v2 = textureRegion.getV2();
this.du = u2 - u1;
this.dv = v2 - v1;
this.width = textureRegion.getRegionWidth();
this.height = textureRegion.getRegionHeight();
setColor(Color.WHITE);
}
public void setColor(float packedColor) {
for (int i = 0; i < 12; i++)
verts[i*5+2] = packedColor;
}
public void setColor(final Color color) {
setColor(color.toFloatBits());
}
private final void vert(final float[] verts, final int offset, final float x, final float y) {
final float u = u1 + du * ((x - this.x) / this.width);
final float v = v1 + dv * (1f - ((y - this.y) / this.height));
vert(verts, offset, x, y, u, v);
}
private final void vert(final float[] verts, final int offset, final float x, final float y, final float u, final float v) {
verts[offset] = this.x + originX + (x - this.x - originX) * scaleX;
verts[offset+1] = this.y + originY + (y - this.y - originY) * scaleY;
verts[offset+3] = u;
verts[offset+4] = v;
}
private void calculate(float x, float y, float width, float height, float angle, float u0, float v0, float u1, float v1) {
if (!this.dirty && this.x == x && this.y == y && this.angle == angle && this.width == width && this.height == height
&& this.u1 == u0 && this.v2 == v1 && this.u2 == u1 && this.v2 == v1)
return;
this.x = x;
this.y = y;
this.width = width;
this.height = height;
this.angle = angle;
this.u1 = u0;
this.v1 = v0;
this.u2 = u1;
this.v2 = v1;
final float centerX = width * 0.5f;
final float centerY = height * 0.5f;
final float x2 = x + width;
final float y2 = y + height;
final float xc = x + centerX;
final float yc = y + centerY;
final float ax = MathUtils.cosDeg(angle+angleOffset); // positive right, negative left
final float ay = MathUtils.sinDeg(angle+angleOffset); // positive top, negative bottom
final float txa = ax != 0f ? Math.abs(centerX / ax) : 99999999f; // intersection on left or right "wall"
final float tya = ay != 0f ? Math.abs(centerY / ay) : 99999999f; // intersection on top or bottom "wall"
final float t = Math.min(txa, tya);
// tx and ty are the intersection points relative to centerX and centerY.
final float tx = t*ax;
final float ty = t*ay;
vert(verts, BOTTOMRIGHT1, x+centerX, y);
if (ax >= 0f) { // rotation on the rights half
vert(verts, TOPLEFT1, x, y2);
vert(verts, TOPRIGHT1, xc, y2);
vert(verts, BOTTOMLEFT1, x, y);
vert(verts, BOTTOMLEFT2, xc, yc);
vert(verts, TOPLEFT2, xc, y2);
if (txa < tya) { // rotation on the right side
vert(verts, TOPRIGHT2, x2, y2);
vert(verts, BOTTOMRIGHT2, x2, yc + ty);
draw = 2;
} else if (ay > 0f) { // rotation on the top side
vert(verts, BOTTOMRIGHT2, xc + tx, y2);
vert(verts, TOPRIGHT2, xc + tx*0.5f, y2);
draw = 2;
} else { // rotation on the bottom side
vert(verts, TOPRIGHT2, x2, y2);
vert(verts, BOTTOMRIGHT2, x2, y);
vert(verts, TOPLEFT3, xc, yc);
vert(verts, TOPRIGHT3, x2, y);
vert(verts, BOTTOMLEFT3, xc + tx, y);
vert(verts, BOTTOMRIGHT3, xc + tx * 0.5f, y);
draw = 3;
}
} else { // rotation on the left half
vert(verts, TOPRIGHT1, x+centerX, y+centerY);
if (txa < tya) { // rotation on the left side
vert(verts, BOTTOMLEFT1, x, y);
vert(verts, TOPLEFT1, x, yc+ty);
draw = 1;
} else if (ay < 0f) { // rotation on the bottom side
vert(verts, TOPLEFT1, xc+tx, y);
vert(verts, BOTTOMLEFT1, xc+tx*0.5f, y);
draw = 1;
} else { // rotation on the top side
vert(verts, TOPLEFT1, x, y2);
vert(verts, BOTTOMLEFT1, x, y);
vert(verts, BOTTOMRIGHT2, xc, yc);
vert(verts, BOTTOMLEFT2, x, y2);
vert(verts, TOPLEFT2, xc+tx*0.5f, y2);
vert(verts, TOPRIGHT2, xc+tx, y2);
draw = 2;
}
}
this.dirty = false;
}
private void draw(final SpriteBatch batch, final float x, final float y, float width, float height, final float angle) {
if (width < 0) { scaleX = -1f; width = -width; }
if (height < 0) { scaleY = -1f; height = -height; }
calculate(x, y, width, height, angle, u1, v1, u2, v2);
batch.draw(texture, verts, 0, 20*draw);
}
private void draw(final SpriteBatch batch, final float x, final float y, final float angle) {
draw(batch, x, y, width, height, angle);
}
public void setOrigin(float x, float y) {
if (originX == x && originY == y)
return;
originX = x;
originY = y;
dirty = true;
}
public void setScale(float x, float y) {
if (scaleX == x && scaleY == y)
return;
scaleX = x;
scaleY = y;
dirty = true;
}
public float getAngle() {
return this.angle;
}
void setAngle(final float angle) {
if (this.angle == angle)
return;
this.angle = angle;
dirty = true;
}
private float leftWidth = 0;
private float rightWidth = 0;
private float topHeight = 0;
private float bottomHeight = 0;
private float minWidth = 0;
private float minHeight = 0;
@Override
public void draw(Batch batch, float x, float y, float width, float height) {
draw((SpriteBatch) batch, x, y, angle);
}
@Override
public float getLeftWidth() {
return leftWidth;
}
@Override
public void setLeftWidth(float leftWidth) {
this.leftWidth = leftWidth;
}
@Override
public float getRightWidth() {
return rightWidth;
}
@Override
public void setRightWidth(float rightWidth) {
this.rightWidth = rightWidth;
}
@Override
public float getTopHeight() {
return topHeight;
}
@Override
public void setTopHeight(float topHeight) {
this.topHeight = topHeight;
}
@Override
public float getBottomHeight() {
return bottomHeight;
}
@Override
public void setBottomHeight(float bottomHeight) {
this.bottomHeight = bottomHeight;
}
@Override
public float getMinWidth() {
return minWidth;
}
@Override
public void setMinWidth(float minWidth) {
this.minWidth = minWidth;
}
@Override
public float getMinHeight() {
return minHeight;
}
@Override
public void setMinHeight(float minHeight) {
this.minHeight = minHeight;
}
public Texture getTexture() {
return texture;
}
public void setTextureRegion(final TextureRegion textureRegion) {
this.texture = textureRegion.getTexture();
this.u1 = textureRegion.getU();
this.v1 = textureRegion.getV();
this.u2 = textureRegion.getU2();
this.v2 = textureRegion.getV2();
this.dirty = true;
}
}
@tlehloba
Copy link

how do you call this method ?

@chandujr
Copy link
Author

chandujr commented Nov 3, 2016

@hlobaz I'm sorry, I didn't see your comment. I didn't get any notification!

Anyway, if it's still useful to you and you haven't figured out, you can call the class constructor RadialSprite() and pass a TextureRegion object to it.

@PROSKEY
Copy link

PROSKEY commented Aug 12, 2020

@chandujr I couldn't figure out how to start progress from top middle point. what do i need to change to make it start from there. Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment