package com.gebauz.bauzoid.graphics.sprite;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.Texture;
import com.gebauz.bauzoid.graphics.Graphics;
import com.gebauz.bauzoid.graphics.GraphicsObject;
import com.gebauz.bauzoid.graphics.model.SimpleGeometry;
import com.gebauz.bauzoid.graphics.model.Geometry.PrimitiveType;
import com.gebauz.bauzoid.graphics.renderstates.RenderStates;
import com.gebauz.bauzoid.graphics.sprite.SpriteRegion;
import com.gebauz.bauzoid.graphics.sprite.SpriteShader;
import com.gebauz.bauzoid.math.Vector4;
/** Sprite class that loads a texture and allows definition of regions (for atlasing, or multi-framing). */
public class Sprite
extends GraphicsObject
{
// Constants========================================================================================
public static int NUM_INDICES_PER_REGION =
6;
public static int NUM_ATTRIBUTES_PER_REGION =
4;
// Embedded Types===================================================================================
// Fields===========================================================================================
/** The texture this sprite is based on. */
protected Texture mTexture =
null;
/** Stores the separate regions of the sprite that were defined. */
private SpriteRegion
[] mRegions =
null;
/** Stores all Geometry of all SpriteRegions. */
private SimpleGeometry mMesh =
null;
/** Store the texture filename so it can be loaded asynchronously later. */
protected String mTextureFilename =
null;
/** Store the atlas region definition filename so it can be loaded asynchronously later. */
protected String mRegionDefFilename =
null;
/** Flag to check if asynchronous or synchronous loading was requested. */
protected boolean mIsAsync =
false;
// Methods==========================================================================================
public Sprite
(Graphics graphics,
String textureFile
)
{
super(graphics
);
mTextureFilename = textureFile
;
}
public Sprite
(Graphics graphics,
String textureFile,
String atlasFile
)
{
this(graphics, textureFile
);
mRegionDefFilename = atlasFile
;
}
/** Called during asynchronous loading to initiate AssetManager's loading mechanism. */
public void initAsync
()
{
if (mTextureFilename ==
null)
return; // maybe ASSERT?
mIsAsync =
true;
getAssetManager
().
load(mTextureFilename, Texture.
class);
if (mRegionDefFilename
!=
null)
{
getAssetManager
().
load(mRegionDefFilename, SpriteRegionDefinition.
class);
}
}
/** Called synchronously (or after initAsync() for asynchronous loading). */
public void init
()
{
if (mTextureFilename ==
null)
return;
if (!mIsAsync
)
{
// load texture synchronously
mTexture =
new Texture
(Gdx.
files.
internal(mTextureFilename
));
}
else
{
// grab texture that should be loaded asynchronously already
mTexture = getAssetManager
().
get(mTextureFilename, Texture.
class);
}
if (mRegionDefFilename
!=
null)
{
SpriteRegionDefinition atlas =
null;
if (!mIsAsync
)
{
// load synchronously
atlas = SpriteUtil.
readSpriteRegionInfo(Gdx.
files.
internal(mRegionDefFilename
));
}
else
{
atlas = getAssetManager
().
get(mRegionDefFilename, SpriteRegionDefinition.
class);
}
SpriteRegion regions
[] =
new SpriteRegion
[atlas.
frames.
size()];
for (int i =
0; i
< atlas.
frames.
size(); i++
)
{
SpriteRegionDefinition.
FrameInfo info = atlas.
frames.
get(i
);
regions
[i
] =
new SpriteRegion
(this, i, info.
x, info.
y, info.
w, info.
h,
true);
}
setRegions
(regions
);
}
else
{
// create default geometry for entire sprite (make 1 region)
SpriteRegion regions
[] =
new SpriteRegion
[1];
regions
[0] =
new SpriteRegion
(this,
0,
0,
0, getTextureWidth
(), getTextureHeight
(),
true);
setRegions
(regions
);
}
}
/** Destroy sprite. */
public void dispose
()
{
if (mRegions
!=
null)
mRegions =
null;
if (mTexture
!=
null)
{
if (mIsAsync
)
{
getAssetManager
().
unload(mTextureFilename
);
}
else
{
mTexture.
dispose();
}
mTexture =
null;
}
if (mRegionDefFilename
!=
null)
{
if (mIsAsync
)
{
getAssetManager
().
unload(mRegionDefFilename
);
}
}
}
public void setRegions
(SpriteRegion
[] regions
)
{
if (mMesh
!=
null)
{
mMesh.
dispose();
mMesh =
null;
}
mRegions = regions
;
mMesh = createGeometry
();
}
public SimpleGeometry createGeometry
()
{
float[] vertices =
new float[NUM_ATTRIBUTES_PER_REGION
* SimpleGeometry.
POSITION_COORD_PER_ELEMENT * mRegions.
length];
float[] texCoords =
new float[NUM_ATTRIBUTES_PER_REGION
* SimpleGeometry.
TEXCOORD_COORD_PER_ELEMENT * mRegions.
length];
float[] colors =
new float[NUM_ATTRIBUTES_PER_REGION
* SimpleGeometry.
COLOR_COORD_PER_ELEMENT * mRegions.
length];
// two triangles per region
short[] indices =
new short[NUM_INDICES_PER_REGION
* mRegions.
length];
for (int i =
0; i
< mRegions.
length; i++
)
{
SpriteRegion r = getRegion
(i
);
float[] v =
{
-1.0f, -1.0f, 0.0f,
1.0f, -1.0f, 0.0f,
1.0f, 1.0f, 0.0f,
-1.0f, 1.0f, 0.0f
};
float[] t =
{
r.
left, r.
top,
r.
right, r.
top,
r.
right, r.
bottom,
r.
left, r.
bottom
};
float[] c =
{
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1
};
System.
arraycopy(v,
0, vertices, NUM_ATTRIBUTES_PER_REGION
* SimpleGeometry.
POSITION_COORD_PER_ELEMENT * i, v.
length);
System.
arraycopy(t,
0, texCoords, NUM_ATTRIBUTES_PER_REGION
* SimpleGeometry.
TEXCOORD_COORD_PER_ELEMENT * i, t.
length);
System.
arraycopy(c,
0, colors, NUM_ATTRIBUTES_PER_REGION
* SimpleGeometry.
COLOR_COORD_PER_ELEMENT * i, c.
length);
int n = i
*NUM_INDICES_PER_REGION
;
short base =
(short)(i
* NUM_ATTRIBUTES_PER_REGION
);
indices
[n++
] = base
; indices
[n++
] =
(short)(base+
1); indices
[n++
] =
(short)(base+
2);
indices
[n++
] = base
; indices
[n++
] =
(short)(base+
2); indices
[n++
] =
(short)(base+
3);
}
SimpleGeometry mesh =
new SimpleGeometry
(getGraphics
(), PrimitiveType.
TRIANGLES);
mesh.
setPositions(vertices
);
mesh.
setTexCoords(texCoords
);
mesh.
setColors(colors
);
mesh.
setIndices(indices
);
return mesh
;
}
/** Create a single SpriteInstance for a single region. */
public final SpriteInstance createSpriteInstance
(int regionIndex
)
{
return new SpriteInstance
(getRegion
(regionIndex
));
}
/** Create a multiple SpriteInstances, each for a single region. */
public void createSpriteInstances
(SpriteInstance
[] instances
)
{
if (instances.
length < mRegions.
length)
return;
for (int i =
0; i
< instances.
length; i++
)
{
instances
[i
] = createSpriteInstance
(i
);
}
}
/** Create a multiple SpriteInstances, each for a single region. */
public SpriteInstance
[] createSpriteInstances
()
{
SpriteInstance frames
[] =
new SpriteInstance
[mRegions.
length];
createSpriteInstances
(frames
);
return frames
;
}
/** Create a single SpriteInstance for all regions. */
public SpriteInstance createSpriteInstanceForAll
()
{
SpriteInstance instance =
new SpriteInstance
(mRegions
);
return instance
;
}
/** Peforms the actual render without any model matrix handling. */
public void performRender
(int region,
float alpha, Vector4 color
)
{
RenderStates rs = getRenderStates
();
SpriteShader shader = getGraphics
().
getSpriteShader();
// draw sprite
shader.
activate(getTexture
(), alpha, color
);
{
rs.
blending.
setEnabled(true);
rs.
culling.
setEnabled(false);
rs.
activate();
rs.
blending.
activate(true);
{
mMesh.
render(getMeshStartIndex
(region
), NUM_INDICES_PER_REGION
);
}
rs.
deactivate();
}
shader.
deactivate();
}
// Getters/Setters==================================================================================
/** Get a reference to the texture. */
public final Texture getTexture
()
{
return mTexture
;
}
/** Get the sprite texture's total width. */
public final int getTextureWidth
()
{
if (mTexture ==
null)
return 0;
return mTexture.
getWidth();
}
/** Get the sprite texture's total height. */
public final int getTextureHeight
()
{
if (mTexture ==
null)
return 0;
return mTexture.
getHeight();
}
/** Get number of defined regions. */
public final int getRegionCount
()
{
if (mRegions ==
null)
return 0;
return mRegions.
length;
}
/** Get region. */
public final SpriteRegion getRegion
(int i
)
{
if (mRegions ==
null)
return null;
return mRegions
[i
];
}
/** Get regions array.*/
public final SpriteRegion
[] getRegions
()
{
return mRegions
;
}
/** Get starting index for region mesh rendering. */
private final int getMeshStartIndex
(int regionIndex
)
{
return (regionIndex
* NUM_INDICES_PER_REGION
);
}
}