package com.gebauz.pingk.entities;
import java.util.Vector;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.Texture;
import com.gebauz.Bauzoid.graphics.model.AttributeArray;
import com.gebauz.Bauzoid.graphics.model.SimpleGeometry;
import com.gebauz.Bauzoid.graphics.model.Geometry;
import com.gebauz.Bauzoid.graphics.renderstates.RenderStates;
import com.gebauz.Bauzoid.graphics.renderstates.BlendingStates.BlendingMode;
import com.gebauz.Bauzoid.graphics.shader.ShaderProgram;
import com.gebauz.Bauzoid.graphics.shader.ShaderUniform;
import com.gebauz.Bauzoid.graphics.shader.ShaderUtil;
import com.gebauz.Bauzoid.graphics.sprite.SpriteShader;
import com.gebauz.Bauzoid.math.MathUtil;
import com.gebauz.Bauzoid.math.Matrix4;
import com.gebauz.Bauzoid.math.Vector2;
import com.gebauz.pingk.game.GameConsts;
import com.gebauz.pingk.game.GameLogic;
public class BallTrail
extends Entity
{
private class TrailElement
{
private Vector2 mPosition
;
private Vector2 mNormal
;
private Vector2 mDirection
;
private Vector2 mPoint1
;
private Vector2 mPoint2
;
private float mLifeTime = 0.0f
;
public TrailElement
(Vector2 pos, Vector2 prevPos,
float angleNormal
)
{
mPosition =
new Vector2
(pos.
x, pos.
y);
mDirection =
new Vector2
(pos.
x - prevPos.
x, pos.
y - prevPos.
y);
if (angleNormal
< 0.0f
)
{
mNormal =
new Vector2
(mDirection.
y, -mDirection.
x);
}
else
{
// 0
mNormal =
new Vector2
((float)Math.
cos(MathUtil.
degToRad(angleNormal
)),
(float)Math.
sin(MathUtil.
degToRad(angleNormal
)));
}
mNormal.
setLength(GameConsts.
BALL_TRAIL_WIDTH);
mPoint1 =
new Vector2
(mPosition.
x + mNormal.
x, mPosition.
y + mNormal.
y);
mPoint2 =
new Vector2
(mPosition.
x - mNormal.
x, mPosition.
y - mNormal.
y);
mLifeTime = 0.0f
;
}
public Vector2 getPosition
()
{
return mPosition
;
}
public Vector2 getDirection
()
{
return mDirection
;
}
public Vector2 getNormal
()
{
return mNormal
;
}
public Vector2 getPoint1
()
{
return mPoint1
;
}
public Vector2 getPoint2
()
{
return mPoint2
;
}
public void update
(float deltaTime
)
{
mLifeTime += deltaTime
;
}
public float getAlpha
()
{
return (1.0f-MathUtil.
clamp(mLifeTime / GameConsts.
BALL_TRAIL_ELEMENT_LIFETIME, 0.0f, 1.0f
));
}
}
private Ball mBall
;
// private Mesh mTrailMesh = new Mesh();
private SimpleGeometry mTrailMesh =
null;
private ShaderProgram mShaderProgram =
null;
private ShaderUniform mTextureHandle =
null;
private Texture mTexture =
null;
private Vector<TrailElement
> mElements =
new Vector<TrailElement
>();
private int mNumPrimitives =
0;
private float mTrailTimer = 0.0f
;
public BallTrail
(GameLogic gameLogic, Ball ball
)
{
super(gameLogic
);
mBall = ball
;
}
@
Override
public void init
()
{
mTexture =
new Texture
(Gdx.
files.
internal("data/textures/trail.png"));
mTrailMesh =
new SimpleGeometry
(getGraphics
(), Geometry.
PrimitiveType.
TRIANGLE_STRIP);
mShaderProgram = ShaderUtil.
createShaderFromFile(getGraphics
(), Gdx.
files.
internal("data/shaders/trailshader.vert"),
Gdx.
files.
internal("data/shaders/trailshader.frag"));
if (mShaderProgram
!=
null)
{
mTextureHandle = mShaderProgram.
getUniform("uDiffuse");
}
}
@
Override
public void exit
()
{
if (mShaderProgram
!=
null)
{
mTextureHandle =
null;
mShaderProgram.
dispose();
mShaderProgram =
null;
}
if (mTrailMesh
!=
null)
{
mTrailMesh.
dispose();
mTrailMesh =
null;
}
if (mTexture
!=
null)
{
mTexture.
dispose();
mTexture =
null;
}
mBall =
null;
}
public void reset
()
{
mElements.
clear();
//mTrailMesh.setVertices(null);
mNumPrimitives =
0;
}
/**
* Add new trail point
* @param x X-axis coordinate
* @param y Y-axis coordinate
* @param angleNormal if >= 0.0f, specifies the angle of the normal to be used
*/
public void addTrailPoint
(float x,
float y,
float angleNormal
)
{
mTrailTimer -= GameConsts.
BALL_TRAIL_INTERVAL;
Vector2 lastPos =
new Vector2
(x, y
);
if (mElements.
size() > 0)
{
lastPos = mElements.
get(mElements.
size()-
1).
getPosition();
// do not add point if positions are the same
if (Vector2.
distance(lastPos,
new Vector2
(x, y
)) < MathUtil.
EPSILON)
{
return;
}
}
mElements.
add(new TrailElement
(new Vector2
(x, y
), lastPos, angleNormal
));
// trim if larger than wanted
while (mElements.
size() > GameConsts.
BALL_TRAIL_LENGTH)
{
mElements.
remove(0);
}
//mTrailFadeTimer = 0.0f;
buildGeometry
();
}
public void buildGeometry
()
{
// prepare geometry
if (mElements.
size() >=
2)
{
//float life = 1.0f - MathUtil.clamp(mTrailFadeTimer / 2.0f, 0.0f, 1.0f);
// two vertices per trail element
AttributeArray vertices =
new AttributeArray
(mElements.
size() * SimpleGeometry.
POSITION_COORD_PER_ELEMENT * 2 * 2);
AttributeArray texCoords =
new AttributeArray
(mElements.
size() * SimpleGeometry.
TEXCOORD_COORD_PER_ELEMENT * 2 * 2);
AttributeArray colors =
new AttributeArray
(mElements.
size() * SimpleGeometry.
COLOR_COORD_PER_ELEMENT * 2 * 2);
int index =
0;
for (int i = mElements.
size() -
1; i
>=
0; i--
)
{
TrailElement element1 = mElements.
get(i
);
vertices.
fill(element1.
getPoint1().
x, element1.
getPoint1().
y, 0.0f
);
vertices.
fill(element1.
getPoint2().
x, element1.
getPoint2().
y, 0.0f
);
texCoords.
fill(0.0f, 1.0f
);
texCoords.
fill(0.0f, 0.0f
);
float lifeTime = element1.
getAlpha();
if (i ==
0)
lifeTime = 0.0f
;
colors.
fill(GameConsts.
PINGK_COLOR.
x, GameConsts.
PINGK_COLOR.
y, GameConsts.
PINGK_COLOR.
z, lifeTime
);
colors.
fill(GameConsts.
PINGK_COLOR.
x, GameConsts.
PINGK_COLOR.
y, GameConsts.
PINGK_COLOR.
z, lifeTime
);
if (i
> 0)
{
TrailElement element2 = mElements.
get(i-
1);
if (Vector2.
dotProduct(element1.
getNormal(), element2.
getNormal()) < 0.0f
)
{
// facing away -> twist
vertices.
fill(element1.
getPoint2().
x, element1.
getPoint2().
y, 0.0f
);
vertices.
fill(element1.
getPoint1().
x, element1.
getPoint1().
y, 0.0f
);
texCoords.
fill(0.0f, 1.0f
);
texCoords.
fill(0.0f, 0.0f
);
colors.
fill(GameConsts.
PINGK_COLOR.
x, GameConsts.
PINGK_COLOR.
y, GameConsts.
PINGK_COLOR.
z, lifeTime
);
colors.
fill(GameConsts.
PINGK_COLOR.
x, GameConsts.
PINGK_COLOR.
y, GameConsts.
PINGK_COLOR.
z, lifeTime
);
}
}
}
mNumPrimitives = vertices.
getUsedCount() / SimpleGeometry.
POSITION_COORD_PER_ELEMENT;
mTrailMesh.
setPositions(vertices.
getAttributeArray());
mTrailMesh.
setTexCoords(texCoords.
getAttributeArray());
mTrailMesh.
setColors(colors.
getAttributeArray());
/*mTrailMesh.setPrimitiveType(GL10.GL_TRIANGLE_STRIP);
mTrailMesh.setVertices(vertices.getAttributeArray());
mTrailMesh.setTexCoords(texCoords.getAttributeArray());
mTrailMesh.setColors(colors.getAttributeArray());*/
}
}
@
Override
public void update
(float deltaTime
)
{
mTrailTimer += deltaTime
;
//mTrailFadeTimer += deltaTime;
if (mTrailTimer
> GameConsts.
BALL_TRAIL_INTERVAL)
{
addTrailPoint
(mBall.
getX(), mBall.
getY(), -1.0f
);
}
for (int i =
0; i
< mElements.
size(); i++
)
{
mElements.
get(i
).
update(deltaTime
);
}
}
public void updateFade
(float deltaTime
)
{
//mTrailFadeTimer += deltaTime;
for (int i =
0; i
< mElements.
size(); i++
)
{
mElements.
get(i
).
update(deltaTime
);
}
// rebuild geometry for color fading...
buildGeometry
();
}
@
Override
public void render
()
{
RenderStates rs = getGraphics
().
renderStates;
Matrix4 modelMatrix = Matrix4.
createIdentity();
rs.
pushModelMatrix();
{
rs.
model = modelMatrix
;
mShaderProgram.
activate();
{
mTextureHandle.
set(0);
rs.
getTextureStage(0).
bindTexture(mTexture
);
rs.
blending.
setEnabled(true);
rs.
blending.
setBlendingMode(BlendingMode.
ALPHABLEND);
rs.
culling.
setEnabled(false);
rs.
depthTest.
setEnabled(false);
rs.
activate();
{
mTrailMesh.
render();
}
rs.
deactivate();
}
mShaderProgram.
deactivate();
}
rs.
popModelMatrix();
/* GL10 gl = GLUtil.getGL();
// transform
gl.glMatrixMode(GL10.GL_MODELVIEW);
gl.glPushMatrix();
{
gl.glLoadIdentity();
RenderStates renderStates = GLUtil.getRenderStates();
renderStates.depthTest.setEnabled(false);
renderStates.culling.setEnabled(false);
renderStates.blending.setEnabled(true);
renderStates.blending.setBlendingMode(BlendingMode.ALPHABLEND);
renderStates.getTextureStage(0).bindTexture(mTexture);
renderStates.activate();
mTrailMesh.render(mNumPrimitives);
//mTrailMesh.render();
renderStates.deactivate();
renderStates.getTextureStage(0).bindTexture(null);
}
gl.glPopMatrix();*/
}
}