Android OpenGL Circle Texture Doubled - android

I am trying to draw Circle with texture on it which should be stretched on all vertices.
The problem is that the result i get looks like this:
http://s14.postimg.org/3wyb74469/image.png
I have tried to draw triangle fan as it need to be , first coordinates at 0,0,0
And rest as needed:
http://escience.anu.edu.au/lecture/cg/surfaceModeling/image/surfaceModeling015.png
Also here is the same question and I couldn't get answer for my problem from it :
OpenGL ES, add texture to circle
Loading circle vertices coordinates function:
private final int mVerticesDataSize = 3;
private final int mNumberOfVertices = 180;
private final int mBytesPerFloat = 4;
private float[] vertices;
private FloatBuffer mVerticesBuff;
public void loadCircleVerticesBuff(Context mActivityContext){
mVerticesBuff = ByteBuffer.allocateDirect(mNumberOfVertices * mVerticesDataSize * mBytesPerFloat).order(ByteOrder.nativeOrder()).asFloatBuffer();
vertices = new float[mNumberOfVertices * mVerticesDataSize];
float theta = 0;
for (int i = 0; i < (mNumberOfVertices * mVerticesDataSize); i += 3) {
vertices[i] = (float) (((float) 5*Math.cos(theta)));
vertices[i + 1] = (float) ((float) 5*Math.sin(theta));
vertices[i + 2] = 0;
theta += Math.PI / 90;
}
mVerticesBuff.put(vertices);
mVerticesBuff.position(0);
}
Loading circle texture coordinates function:
private final int mTextureCoordinateDataSize = 3;
public void loadCircleTextureBuff(){
mCircleTextureCoordinatesBuff = ByteBuffer.allocateDirect(mNumberOfVertices * mTextureCoordinateDataSize * mBytesPerFloat).order(ByteOrder.nativeOrder()).asFloatBuffer();
mCircleTextureCoordinatesBuff.put(vertices);
mCircleTextureCoordinatesBuff.position(0);
}
The opengl function used to draw is :
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_FAN, 0, mNumberOfVertices);

So solution found (: 1 very very importent thing i missed up / or openGL missed up.
Texture coordinates can be only in range of 0 to 1 .
So here is the trick/solution :
//Build vertices :
vertices[i] = (float) (((float) raduis*Math.cos(theta)))+raduis;
vertices[i + 1] = (float) ((float) raduis*Math.sin(theta))+raduis;
// Build texture :
for (int i = 0; i < (mNumberOfVertices * mVerticesDataSize); i += 3) {
vertices[i] = (vertices[i])/(raduis*2);
vertices[i + 1] = (vertices[i+1])/(raduis*2);
vertices[i + 2] = 0;
}
And here is the res :
http://s2.postimg.org/tno4jr4y1/image.png
Dont forget to flip texture vertices as i forgot (:

Related

Simple Music Visualisation with a Circle

Im trying to build a simple Music Visualisation App which just should resize a Circle. So if the Music Part which is currently playing is loud it should get bigger and if not it should get smaller.
To Visualize the Circle I just created a custom View Class which draws the circle in the onDraw Method.
To get the informations out of the current Audio, I found the Visualizer Class of Android and also used the setDataCaptureListener.
mVisualizer = new Visualizer(mMediaPlayer.getAudioSessionId());
mVisualizer.setCaptureSize(Visualizer.getCaptureSizeRange()[0]);
mVisualizer.setDataCaptureListener(
new Visualizer.OnDataCaptureListener() {
public void onWaveFormDataCapture(Visualizer visualizer,byte[] bytes, int samplingRate) {
mVisualizerView.updateVisualizer(bytes);
}
public void onFftDataCapture(Visualizer visualizer,byte[] bytes, int samplingRate) {
}
}, (int)(Visualizer.getMaxCaptureRate() / 1.5), true, false);
But my Problem is that I don't really know how I use the byte Array which is given back, to find out the music change in general (got louder or not ?).
I just tried to get the average of the array but this gives me completely bad results. The circle changed his size like it is on drugs. So I thought maybe the array has too many outlined/extreme values (which was true) so I calculated the median of the array. This gaved me better results but still isn't what I want. It's not very smooth and it's to complex. I always have to sort the array which is not really efficient. What am I thinking wrong ?
Im really a beginner in this AudioFX section and Im completely sorry If this is a dumb question and attempt of me.
Thank you for your help !
EDIT:
private float schwelle = 5000;
private float last = 0;
...
float summe = 0;
for (Byte currentByte: mBytes)
summe += currentByte;
if (summe > schwelle && summe > last)
{
last = summe; //make it bigger
}
else {
last -= 100; //make circle smaller
}
canvas.drawCircle(getWidth()/2,getHeight()/2,last / 100,mForePaint);
A really good git project is https://github.com/felixpalmer/android-visualizer.
I myself came up with this:(it's a lot simple than the git solution)
You can use the values of the array to draw the the waveform on the outline of a circle using trigonometry, and make the start radius of the circle bigger if the sum of the array is bigger than certain treshhold:
class StarWaveformRenderer implements Renderer {
private Paint p = new Paint();
private static final int BOOST_TRASH_HOLD = 10000;
private float stretchFade = 1; //circle fades after a prominent beat
#Override
public void render(Canvas canvas, byte[] data) {
if (data == null || data.length == 0)
return;
int centerX = canvas.getWidth() / 2;
int centerY = canvas.getHeight() / 2;
float stretch = stretchFade;
int sum = RenderUtils.sum(data);
p.setColor((p.getColor() + sum / 2)); //change color of circle
if (sum > BOOST_TRASH_HOLD) {//prominent beat
stretch = (float) Math.min(canvas.getWidth(), canvas.getHeight()) / Byte.MAX_VALUE / 3; //maximum
stretchFade = stretch;
}
double radDif = 2 * Math.PI / data.length; //the angle between each element of the array
double radPos = 0;
float lX = (float) Math.cos(radPos) * data[0] + centerX;
float lY = (float) Math.sin(radPos) * data[0] + centerY;
float cX;
float cY;
for (byte b : data) {
cX = (float) Math.cos(radPos) * b * stretch + centerX;
cY = (float) Math.sin(radPos) * b * stretch + centerY;//calculate position of outline, stretch indicates promince of the beat
canvas.drawLine(lX, lY, cX, cY, p);
lX = cX;
lY = cY;
radPos += radDif;
}
stretchFade = Math.max(1, stretchFade / 1.2f);//beat fades out
}
}
You can programm your own renderes and let the user select which one he wants to use. Just pass the array from onWaveformDataCapture to the onRender method.
Utils for analysing the waveform (the amplitude is stored kind of weird):
class RenderUtils {
private static final byte SHIFT = Byte.MAX_VALUE;
static int sum(byte[] data) {
int sum = 0;
for (byte b : data)
sum += b;
return sum;
}
static int toAmplitude(byte b) {
return b > 0 ? b + SHIFT : -b;//+127=high positive;+1=low positive;-127=low negative;-1=high negative
}
static float toAmplitude(float f) {
return f > 0 ? f + SHIFT : -f;//+127=high positive;+1=low positive;-127=low negative;-1=high negative
}
}

How tro draw fading path

How can I draw Path with fading (opacity or thicknes) line? Something like this.
I know there is LinearGradient shader for Paint, but it won't bend along the Path.
One possible solution might be to get points along the Path and just draw it by myself through the segments`. But I coouldn't find any method for that either.
I came up with the following code. The mos important thing is PathMeasure's getPosTan() method.
if (getGesturePath() != null) {
final short steps = 150;
final byte stepDistance = 5;
final byte maxTrailRadius = 15;
pathMeasure.setPath(getGesturePath(), false);
final float pathLength = pathMeasure.getLength();
for (short i = 1; i <= steps; i++) {
final float distance = pathLength - i * stepDistance;
if (distance >= 0) {
final float trailRadius = maxTrailRadius * (1 - (float) i / steps);
pathMeasure.getPosTan(distance, pathPos, null);
final float x = pathPos[0] + RandomUtils.nextFloat(0, 2 * trailRadius) - trailRadius;
final float y = pathPos[1] + RandomUtils.nextFloat(0, 2 * trailRadius) - trailRadius;
paint.setShader(new RadialGradient(
x,
y,
trailRadius > 0 ? trailRadius : Float.MIN_VALUE,
ColorUtils.setAlphaComponent(Color.GREEN, random.nextInt(0xff)),
Color.TRANSPARENT,
Shader.TileMode.CLAMP
));
canvas.drawCircle(x, y, trailRadius, paint);
}
}
}

LibGDX - Issue with FrameBuffer, Scene2D Table and clipping

I have a custom ImageTextButton in which I render the button to a FrameBuffer first and then draw with frameBuffer.getColorBufferTexture(). I don't really want to do this but I use a custom shader with this button that creates some visual effects and the only way I have been able to achieve it is with a FrameBuffer. I was surprised to find this actually works very smooth and fast though, the whole process takes 1-2ms on slow devices and having several instances doesn't cause any kind of framerate drop, so I am happy with this bit.
The issue I am having though is when I enable clipping on the ImageTextButton (with setClip(true)). The reason for this is the button can change in width, and I would like it to clip the text within the bounds of the button. If I disable the FrameBuffer and render normally, this part also works very well. If I combine the 2, it seems the clipping process gets confused and the result is either no text or very small parts of the text.
So here is the relevant code. I assumed it was because I set the FrameBuffer and SpriteBatch size/projection matrix just to deal with the active area (for efficiency) however if I don't modify any of this and use the same batch/projection matrix, so the FrameBuffer manages the whole screen, it is still the same result.
public void initFrameBuffer(){
xCache = (int) super.getX(); yCache = (int) super.getY();
widthCache = (int) super.getWidth(); heightCache = (int) super.getHeight();
frameBuffer = new FrameBuffer(Pixmap.Format.RGBA8888, widthCache, heightCache, false);
fboProjectionMatrix.setToOrtho2D(xCache, yCache+heightCache, widthCache, -heightCache);
this.fbBatch = new SpriteBatch();
this.fbBatch.setProjectionMatrix(fboProjectionMatrix);
this.frameBufferReady = true;
}
public void doFrameBuffer(Batch batch, float parentAlpha){
batch.end();
frameBuffer.begin();
fbBatch.begin();
Gdx.gl20.glClearColor(0f, 0.0f, 0.0f, 0.0f);
Gdx.gl20.glClear(GL20.GL_COLOR_BUFFER_BIT);
super.draw(fbBatch, parentAlpha);
fbBatch.end();
frameBuffer.end();
batch.begin();
}
public void drawFrameBufferObject(Batch batch, float parentAlpha){
batchColorCache = batch.getColor();
batch.setColor(1.0f, 1.0f, 1.0f, parentAlpha);
batch.draw(frameBuffer.getColorBufferTexture(), getX(), getY());
batch.setColor(batchColorCache);
}
#Override
public void draw(Batch batch, float parentAlpha) {
if (!this.frameBufferReady) initFrameBuffer();
doFrameBuffer(batch, parentAlpha);
drawFrameBufferObject(batch, parentAlpha);
}
Sorry for the long code, it's actually heavily trimmed down for the necessary parts..
Help hugely appreciated as always!
After much playing, the solution I have found is one that could probably be useful in other situations, and that is true clipping of the BitmapFontCache by vertex modification, no scissors involved! So if anyone would find this useful, the code is;
float xStart = ...start position of clip
float xEnd = ...end position of clip
//vertex offset numbers
int x_1 = 0, x_2 = 5, x2_1 = 10, x2_2 = 15;
int u_1 = 3, u_2 = 8, u2_1 = 13, u2_2 = 18;
for (int j = 0, n = pageCount; j < n; j++) {
int c = cache.getVertexCount(j);
int newIdx = 0;
if (c > 0) { // ignore if this texture has no glyphs
float[] vertices = cache.getVertices(j);
for(int i = 0; i < vertices.length; i+=20){
//if any of the vertices are outside the label, don't put them in the new cache
if(vertices[i+x2_1] > xStart && vertices[i+x_1] < xEnd){
for(int k = 0; k < 20; k++){
clippedVerts[j][newIdx+k] = vertices[i+k];
}
//case on major left glyph
if(vertices[i+x_1] < xStart){
float xDiff = vertices[i+x2_1]-xStart; //difference between right of glyph and clip
float xRatio = xDiff / (vertices[i+x2_1]-vertices[i+x_1]);
float uDiff = vertices[i+u2_1] - vertices[i+u_1];
float newU = vertices[i+u2_1] - uDiff*xRatio;
clippedVerts[j][newIdx+x_1] = xStart;
clippedVerts[j][newIdx+x_2] = xStart;
clippedVerts[j][newIdx+u_1] = newU;
clippedVerts[j][newIdx+u_2] = newU;
}
//case on major right glyph
if(vertices[i+x2_1] > xEnd){
float xDiff = xEnd-vertices[i+x_1]; //difference between left of glyph and clip
float xRatio = xDiff / (vertices[i+x2_1]-vertices[i+x_1]);
float uDiff = vertices[i+u2_1] - vertices[i+u_1];
float newU_2 = vertices[i+u_1] + uDiff*xRatio;
clippedVerts[j][newIdx+x2_1] = xEnd;
clippedVerts[j][newIdx+x2_2] = xEnd;
clippedVerts[j][newIdx+u2_1] = newU_2;
clippedVerts[j][newIdx+u2_2] = newU_2;
}
newIdx += 20;
}
}
}
clippedIdx[j] = newIdx;
}
for (int j = 0, n = pageCount; j < n; j++) {
int idx = clippedIdx[j];
if (idx > 0) { // ignore if this texture has no glyphs
float[] vertices = clippedVerts[j];
batch.draw(regions.get(j).getTexture(), vertices, 0, idx);
}
}

Showing trajectory indicator

From the image you can see that the ball fired on the left that fire behind it, does not match the calculated trajectory. Im drawing the ball trajectory using an equation from a SO question, this is modified to take into consideration the box2d steps of 30 frames per second. This does calculate a valid trajectory but it does not match the actual trajectory of the ball, the ball has a smaller trajectory. I am applying a box2d force to the ball, this also has a density set and a shape. The shape radius varies depending on the type of ball. Im setting the start velocity in the touchdown event.
public class ProjectileEquation {
public float gravity;
public Vector2 startVelocity = new Vector2();
public Vector2 startPoint = new Vector2();
public Vector2 gravityVec = new Vector2(0,-10f);
public float getX(float n) {
return startVelocity.x * (n * 1/30f) + startPoint.x;
}
public float getY(float n) {
float t = 1/30f * n;
return 0.5f * gravity * t * t + startVelocity.y * t + startPoint.y;
}
}
#Override
public void draw(SpriteBatch batch, float parentAlpha) {
float t = 0f;
float width = this.getWidth();
float height = this.getHeight();
float timeSeparation = this.timeSeparation;
for (int i = 0; i < trajectoryPointCount; i+=timeSeparation) {
//projectileEquation.getTrajectoryPoint(this.getX(), this.getY(), i);
float x = this.getX() + projectileEquation.getX(i);
float y = this.getY() + projectileEquation.getY(i);
batch.setColor(this.getColor());
if(trajectorySprite != null) batch.draw(trajectorySprite, x, y, width, height);
// t += timeSeparation;
}
}
public boolean touchDown (InputEvent event, float x, float y, int pointer, int button) {
if(button==1 || world.showingDialog)return false;
touchPos.set(x, y);
float angle = touchPos.sub(playerCannon.position).angle();
if(angle > 270 ) {
angle = 0;
}
else if(angle >70) {
angle = 70;
}
playerCannon.setAngle(angle);
world.trajPath.controller.angle = angle;
float radians = (float) angle * MathUtils.degreesToRadians;
float ballSpeed = touchPos.sub(playerCannon.position).len()*12;
world.trajPath.projectileEquation.startVelocity.x = (float) (Math.cos(radians) * ballSpeed);
world.trajPath.projectileEquation.startVelocity.y = (float) (Math.sin(radians) * ballSpeed);
return true;
}
public CannonBall(float x, float y, float width, float height, float damage, World world, Cannon cannonOwner) {
super(x, y, width, height, damage, world);
active = false;
shape = new CircleShape();
shape.setRadius(width/2);
FixtureDef fd = new FixtureDef();
fd.shape = shape;
fd.density = 4.5f;
if(cannonOwner.isEnemy) { //Enemy cannon balls cannot hit other enemy cannons just the player
fd.filter.groupIndex = -16;
}
bodyDef.type = BodyType.DynamicBody;
bodyDef.position.set(this.position);
body = world.createBody(bodyDef);
body.createFixture(fd);
body.setUserData(this);
body.setBullet(true);
this.cannonOwner = cannonOwner;
this.hitByBall = null;
this.particleEffect = null;
}
private CannonBall createCannonBall(float radians, float ballSpeed, float radius, float damage)
{
CannonBall cannonBall = new CannonBall(CannonEnd().x, CannonEnd().y, radius * ballSizeMultiplier, radius * ballSizeMultiplier, damage, this.world, this);
cannonBall.velocity.x = (float) (Math.cos(radians) * ballSpeed);
//cannonBall.velocity.x = (float) ((Math.sqrt(10) * Math.sqrt(29) *
// Math.sqrt((Math.tan(cannon.angle)*Math.tan(cannon.angle))+1)) / Math.sqrt(2 * Math.tan(cannon.angle) - (2 * 10 * 2)/29))* -1f;
cannonBall.velocity.y = (float) (Math.sin(radians) * ballSpeed);
cannonBall.active = true;
//cannonBall.body.applyLinearImpulse(cannonBall.velocity, cannonBall.position);
cannonBall.body.applyForce(cannonBall.velocity, cannonBall.position );
return cannonBall;
}
trajPath = new TrajectoryActor(-10f);
trajPath.setX(playerCannon.CannonEnd().x);
trajPath.setY(playerCannon.CannonEnd().y);
trajPath.setWidth(10f);
trajPath.setHeight(10f);
stage.addActor(trajPath);
Here is a code that I used for one of my other games, which proved to be very precise. The trick is to apply the impulse on the body and read the initial velocity. Having that I calculate 10 positions where the body will be within 0.5 seconds. The language is called Squirrel which is Lua based with C/C++ like syntax. You should be able to grasp what is going on there. What returns from the getTrajectoryPointsForObjectAtImpulse is an array of 10 positions through which the ball will pass within 0.5 seconds.
const TIMESTER_DIVIDOR = 60.0;
function getTrajectoryPoint( startingPosition, startingVelocity, n )
{
local gravity = box2DWorld.GetGravity();
local t = 1 / 60.0;
local stepVelocity = b2Vec2.Create( t * startingVelocity.x, t * startingVelocity.y );
local stepGravity = b2Vec2.Create( t * t * gravity.x, t * t * gravity.y );
local result = b2Vec2.Create( 0, 0 );
result.x = ( startingPosition.x + n * stepVelocity.x + 0.5 * ( n * n + n ) * stepGravity.x ) * MTP;
result.y = ( startingPosition.y + n * stepVelocity.y + 0.5 * ( n * n + n ) * stepGravity.y ) * -MTP;
return result;
}
function getTrajectoryPointsForObjectAtImpulse (object, impulse)
{
if( !object || !impulse ) return [];
local result = [];
object.bBody.ApplyLinearImpulse( impulse, object.bBody.GetWorldCenter() );
local initialVelocity = object.bBody.GetLinearVelocity();
object.bBody.SetLinearVelocity( b2Vec2.Create(0, 0) );
object.bBody.SetActive(false);
for ( local i = 0.0 ; i < ( 0.5 * TIMESTER_DIVIDOR ) ; )
{
result.append( getTrajectoryPoint(object.bBody.GetPosition(), initialVelocity, i.tointeger() ) );
i += ( (0.5 * TIMESTER_DIVIDOR) * 0.1 );
}
return result;
}
If you do not understand any part of the code, please let me know and I will try to explain.

onDraw() triggered but results don't show

I have the following routine in a subclass of view:
It calculates an array of points that make up a line, then erases the previous lines, then draws the new lines (impact refers to the width in pixels drawn with multiple lines). The line is your basic bell curve, squeezed or stretched by variance and x-factor.
Unfortunately, nothing shows on the screen. A previous version with drawPoint() and no array worked, and I've verified the array contents are being loaded correctly, and I can see that my onDraw() is being triggered.
Any ideas why it might not be drawn? Thanks in advance!
protected void drawNewLine( int maxx, int maxy, Canvas canvas, int impact, double variance, double xFactor, int color) {
// impact = 2 to 8; xFactor between 4 and 20; variance between 0.2 and 5
double x = 0;
double y = 0;
int cx = maxx / 2;
int cy = maxy / 2;
int mu = cx;
int index = 0;
points[maxx<<1][1] = points[maxx<<1][0];
for (x = 0; x < maxx; x++) {
points[index][1] = points[index][0];
points[index][0] = (float) x;
Log.i(DEBUG_TAG, "x: " + x);
index++;
double root = 1.0 / (Math.sqrt(2 * Math.PI * variance));
double exponent = -1.0 * (Math.pow(((x - mu)/maxx*xFactor), 2) / (2 * variance));
double ePow = Math.exp(exponent);
y = Math.round(cy * root * ePow);
points[index][1] = points[index][0];
points[index][0] = (float) (maxy - y - OFFSET);
index++;
}
points[maxx<<1][0] = (float) impact;
for (int line = 0; line < points[maxx<<1][1]; line++) {
for (int pt = 0; pt < (maxx<<1); pt++) {
pointsToPaint[pt] = points[pt][1];
}
for (int skip = 1; skip < (maxx<<1); skip = skip + 2)
pointsToPaint[skip] = pointsToPaint[skip] + line;
myLinePaint.setColor(Color.BLACK);
canvas.drawLines(pointsToPaint, bLinePaint); // draw over old lines w/blk
}
for (int line = 0; line < points[maxx<<1][0]; line++) {
for (int pt = 0; pt < maxx<<1; pt++) {
pointsToPaint[pt] = points[pt][0];
}
for (int skip = 1; skip < maxx<<1; skip = skip + 2)
pointsToPaint[skip] = pointsToPaint[skip] + line;
myLinePaint.setColor(color);
canvas.drawLines(pointsToPaint, myLinePaint); / new color
}
}
update: Replaced the drawLines() with drawPoint() in loop, still no joy
for (int p = 0; p<pointsToPaint.length; p = p + 2) {
Log.i(DEBUG_TAG, "x " + pointsToPaint[p] + " y " + pointsToPaint[p+1]);
canvas.drawPoint(pointsToPaint[p], pointsToPaint[p+1], myLinePaint);
}
/// canvas.drawLines(pointsToPaint, myLinePaint);
I was attempting to write from within onCreate() and onStart(). The View and its Canvas are never actually rendered for the first time until the end of onStart().
aren't you suppose to call invalidate (like a mapview) to force the view to reload?
YourView.invalidate() (or maybe postInvalidate(), depending where you are : main sthread or not)
here is the detail

Categories

Resources