How to draw images fast in OGLES2.0 with android? - java

I have a little bit knowledge of android and OGLES2.0 but when i am drawing a picture it takes approximately 0.4ms. So I can draw only 40 pictures in 16ms in order to get 60fps for my game.
Here is my GLRenderer code:
The important parts are the Render-method and the Sprite Class.
public class GLRenderer implements Renderer {
// Our matrices
private final float[] mtrxProjection = new float[16];
private final float[] mtrxView = new float[16];
private final float[] mtrxProjectionAndView = new float[16];
// Geometric variables
public static int[] vertices;
public static short[] indices;
public static int[] uvs;
public IntBuffer vertexBuffer;
public ShortBuffer drawListBuffer;
public IntBuffer uvBuffer;
public List<Sprite> sprites;
public int[] texturenames;
public MainActivity mainActivity;
// Our screenresolution
float mScreenWidth = 1280;
float mScreenHeight = 720;
float ssu = 1.0f;
float ssx = 1.0f;
float ssy = 1.0f;
float swp = 1280.0f;
float shp = 720.0f;
Update update;
Images images;
// Misc
Context mContext;
long mLastTime;
int mProgram;
public GLRenderer (MainActivity mainActivity) {
this.mContext = mainActivity;
this.mainActivity = mainActivity;
this.mLastTime = System.currentTimeMillis() + 100;
this.sprites = new ArrayList<Sprite>();
}
public void onPause () {
/* Do stuff to pause the renderer */
}
public void onResume () {
/* Do stuff to resume the renderer */
this.mLastTime = System.currentTimeMillis();
}
#Override
public void onDrawFrame (GL10 unused) {
// Get the current time
long now = System.currentTimeMillis();
// We should make sure we are valid and sane
if (this.mLastTime > now) return;
// Get the amount of time the last frame took.
long elapsed = now - this.mLastTime;
System.out.println(elapsed);
// clear Screen and Depth Buffer, we have set the clear color as black.
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
// Drawing all static things like the background
drawStatics();
for (Opponent opponent: this.update.opponents) {
int position = this.sprites.indexOf(opponent.getSprite());
// Rotate the sprite
this.sprites.get(position).rotate((float) Math.toRadians(opponent.getAngle()));
// Create the image information
SetupImage(opponent.getPicture(), 0);
// Update our example
UpdateSprite(position);
// Render our example
Render(this.mtrxProjectionAndView, 0);
}
for (Tower tower: this.update.towers) {
long a = System.nanoTime();
int position = this.sprites.indexOf(tower.getSprite());
// Rotate the sprite
this.sprites.get(position).rotate((float) Math.toRadians(tower.getAngle()));
// Create the image information
SetupImage(tower.getPicture(), 0);
// Update our example
UpdateSprite(position);
// Render our example
Render(this.mtrxProjectionAndView, 0);
System.out.println("time: " + (System.nanoTime() - a));
}
for (Bullet bullet: this.update.bullets) {
int position = this.sprites.indexOf(bullet.getSprite());
// Rotate the sprite
this.sprites.get(position).rotate((float) Math.toRadians(bullet.getAngle()));
// Create the image information
SetupImage(bullet.getPicture(), 0);
// Update our example
UpdateSprite(position);
// Render our example
Render(this.mtrxProjectionAndView, 0);
}
for (SuperExplosion explosion: this.update.explosions) {
int position = this.sprites.indexOf(explosion.getSprite());
// Rotate the sprite
// sprites.get(position).rotate((float)Math.toRadians(explosion.getAngle()));
// Create the image information
SetupImage(explosion.getPicture(), 0);
// Update our example
UpdateSprite(position);
// Render our example
Render(this.mtrxProjectionAndView, 0);
}
drawStatics2();
// Save the current time to see how long it took :).
this.mLastTime = now;
// System.out.println("höhe "+mScreenHeight+" breite "+ mScreenWidth);
}
private void drawStatics () {
// Ground
// Update our example
long h = System.nanoTime();
UpdateSprite(0);
// for (int i = 0; i < vertices.length; i++) {
// System.out.println("vertices [" + i + "]: " + vertices[i]);
// }
// Render our example
Render(this.mtrxProjectionAndView, 1);
System.out.println("time: " + (System.nanoTime() - h));
// Bar
// Update our example
UpdateSprite(1);
// Render our example
Render(this.mtrxProjectionAndView, 2);
if (!this.update.upgrade) {
if (this.update.normalSpeed) {
// Update our example
UpdateSprite(2);
// Render our example
Render(this.mtrxProjectionAndView, 3);
} else {
// Update our example
UpdateSprite(3);
// Render our example
Render(this.mtrxProjectionAndView, 4);
}
if (!this.update.start) {
// Update our example
UpdateSprite(4);
// Render our example
Render(this.mtrxProjectionAndView, 5);
}
}
// UpgradeBar
if (this.update.upgrade) {
// Update our example
UpdateSprite(6);
// Render our example
Render(this.mtrxProjectionAndView, 7);
}
h = System.nanoTime();
// Bunny1
// Update our example
UpdateSprite(7);
// Render our example
Render(this.mtrxProjectionAndView, 8);
System.out.println("time bunny1 " + (System.nanoTime() - h));
// CarrotTower
// Update our example
UpdateSprite(8);
// Render our example
Render(this.mtrxProjectionAndView, 9);
// MineThrower
// Update our example
UpdateSprite(9);
// Render our example
Render(this.mtrxProjectionAndView, 10);
// BunnyKing
// Update our example
UpdateSprite(10);
// Render our example
Render(this.mtrxProjectionAndView, 11);
}
private void drawStatics2 () {
// Life
// Update our example
UpdateSprite(5);
// Render our example
Render(this.mtrxProjectionAndView, 6);
}
private void Render (float[] m, int index) {
// get handle to vertex shader's vPosition member
int mPositionHandle = GLES20.glGetAttribLocation(riGraphicTools.sp_Image, "vPosition");
// Enable generic vertex attribute array
GLES20.glEnableVertexAttribArray(mPositionHandle);
// Prepare the triangle coordinate data
GLES20.glVertexAttribPointer(mPositionHandle, 3, GLES20.GL_INT, false, 0, this.vertexBuffer);
// Get handle to texture coordinates location
int mTexCoordLoc = GLES20.glGetAttribLocation(riGraphicTools.sp_Image, "a_texCoord");
// Enable generic vertex attribute array
GLES20.glEnableVertexAttribArray(mTexCoordLoc);
// Prepare the texturecoordinates
GLES20.glVertexAttribPointer(mTexCoordLoc, 2, GLES20.GL_INT, false, 0, this.uvBuffer);
// Get handle to shape's transformation matrix
int mtrxhandle = GLES20.glGetUniformLocation(riGraphicTools.sp_Image, "uMVPMatrix");
// Apply the projection and view transformation
GLES20.glUniformMatrix4fv(mtrxhandle, 1, false, m, 0);
// Get handle to textures locations
int mSamplerLoc = GLES20.glGetUniformLocation(riGraphicTools.sp_Image, "s_texture");
// Set the sampler texture unit to 0, where we have saved the texture.
GLES20.glUniform1i(mSamplerLoc, index);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, this.texturenames[index]);
// Set filtering
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
// Draw the triangle
GLES20.glDrawElements(GLES20.GL_TRIANGLES, indices.length, GLES20.GL_UNSIGNED_SHORT, this.drawListBuffer);
// Disable vertex array
GLES20.glDisableVertexAttribArray(mPositionHandle);
GLES20.glDisableVertexAttribArray(mTexCoordLoc);
}
#Override
public void onSurfaceChanged (GL10 gl, int width, int height) {
// We need to know the current width and height.
this.mScreenWidth = width;
this.mScreenHeight = height;
// Redo the Viewport, making it fullscreen.
GLES20.glViewport(0, 0, (int) this.mScreenWidth, (int) this.mScreenHeight);
// Clear our matrices
for (int i = 0; i < 16; i++) {
this.mtrxProjection[i] = 0.0f;
this.mtrxView[i] = 0.0f;
this.mtrxProjectionAndView[i] = 0.0f;
}
// Setup our screen width and height for normal sprite translation.
Matrix.orthoM(this.mtrxProjection, 0, 0f, this.mScreenWidth, 0.0f, this.mScreenHeight, 0, 50);
// Set the camera position (View matrix)
Matrix.setLookAtM(this.mtrxView, 0, 0f, 0f, 1f, 0f, 0f, 0f, 0f, 1.0f, 0.0f);
// Calculate the projection and view transformation
Matrix.multiplyMM(this.mtrxProjectionAndView, 0, this.mtrxProjection, 0, this.mtrxView, 0);
// Setup our scaling system
SetupScaling();
// Create the GroundSprite
SetupTriangle(this.images.ground_1.getWidth(), this.images.ground_1.getHeight(), 0, 0);
SetupTriangle(this.images.bar1.getWidth(), this.images.bar1.getHeight(), 0, 0);
SetupTriangle(this.images.speed1.getWidth(), this.images.speed1.getHeight(), 0, 0);
SetupTriangle(this.images.speed2.getWidth(), this.images.speed2.getHeight(), 0, 0);
SetupTriangle(this.images.start.getWidth(), this.images.start.getHeight(), 0, 0);
SetupTriangle(this.images.life.getWidth(), this.images.life.getHeight(), 0, 0);
SetupTriangle(this.images.upgradeBar.getWidth(), this.images.upgradeBar.getHeight(), 0, 0);
SetupTriangle(this.images.bunny1.getWidth(), this.images.bunny1.getHeight(), 0, 0);
SetupTriangle(this.images.carrotTower.getWidth(), this.images.carrotTower.getHeight(), 0, 0);
SetupTriangle(this.images.mineThrower.getWidth(), this.images.mineThrower.getHeight(), 0, 0);
SetupTriangle(this.images.bunnyKing1.getWidth(), this.images.bunnyKing1.getHeight(), 0, 0);
this.sprites.get(0).translate(this.ssx * this.images.ground_1.getWidth() / 2, this.ssy * this.images.ground_1.getHeight() / 2);
this.sprites.get(1).translate(this.ssx * (this.images.bar1.getWidth() / 2) + this.ssx * 1084.0f, this.ssy * this.images.bar1.getHeight() / 2.0f);
this.sprites.get(2).translate(this.ssx * this.images.speed1.getWidth() / 2 + this.ssx * 20, this.mScreenHeight - (this.ssy * this.images.speed1.getHeight() / 2) - this.ssy * 5);
this.sprites.get(3).translate(this.ssx * this.images.speed2.getWidth() / 2 + this.ssx * 20, this.mScreenHeight - (this.ssy * this.images.speed2.getHeight() / 2) - this.ssy * 5);
this.sprites.get(4).translate(this.ssx * this.images.start.getWidth() / 2 + this.ssx * 120, this.mScreenHeight - (this.ssy * this.images.start.getHeight() / 2) - this.ssy * 5);
this.sprites.get(5).translate(this.ssx * this.images.life.getWidth() / 2 + this.ssx * 5, this.ssy * this.images.life.getHeight() / 2 + this.ssy * (20));
this.sprites.get(6).translate(this.ssx * this.images.upgradeBar.getWidth() / 2, this.ssy * this.images.upgradeBar.getHeight() / 2);
this.sprites.get(7).translate(this.ssx * (this.images.bunny1.getWidth()) + this.ssx * (1280 - 143 - (this.images.bunny1.getWidth() / 2)), this.mScreenHeight - (this.ssy * this.images.bunny1.getHeight() / 2) - (this.ssy * (235 + (this.images.bunny1.getHeight() / 2))));
this.sprites.get(8).translate(this.ssx * (this.images.carrotTower.getWidth()) + this.ssx * (1280 - 53 - (this.images.carrotTower.getWidth() / 2)), this.mScreenHeight - (this.ssy * this.images.carrotTower.getHeight() / 2) - (this.ssy * (235 + (this.images.carrotTower.getHeight() / 2))));
this.sprites.get(9).translate(this.ssx * (this.images.mineThrower.getWidth()) + this.ssx * (1280 - 143 - (this.images.mineThrower.getWidth() / 2)), this.mScreenHeight - (this.ssy * this.images.mineThrower.getHeight() / 2) - (this.ssy * (325 + (this.images.mineThrower.getHeight() / 2))));
this.sprites.get(10).translate(this.ssx * (this.images.bunnyKing1.getWidth()) + this.ssx * (1280 - 53 - (this.images.bunnyKing1.getWidth() / 2)), this.mScreenHeight - (this.ssy * this.images.bunnyKing1.getHeight() / 2) - (this.ssy * (325 + (this.images.bunnyKing1.getHeight() / 2))));
}
#Override
public void onSurfaceCreated (GL10 gl, EGLConfig config) {
// Setup our scaling system
SetupScaling();
// Set the clear color to black
GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1);
// Blending
GLES20.glEnable(GLES20.GL_BLEND);
// How should opengl blend it
GLES20.glBlendFunc(GLES20.GL_ONE, GLES20.GL_ONE_MINUS_SRC_ALPHA);
// Create the shaders, solid color
int vertexShader = riGraphicTools.loadShader(GLES20.GL_VERTEX_SHADER, riGraphicTools.vs_SolidColor);
int fragmentShader = riGraphicTools.loadShader(GLES20.GL_FRAGMENT_SHADER, riGraphicTools.fs_SolidColor);
riGraphicTools.sp_SolidColor = GLES20.glCreateProgram(); // create empty
// OpenGL ES
// Program
GLES20.glAttachShader(riGraphicTools.sp_SolidColor, vertexShader); // add
// the
// vertex
// shader
// to
// program
GLES20.glAttachShader(riGraphicTools.sp_SolidColor, fragmentShader); // add
// the
// fragment
// shader
// to
// program
GLES20.glLinkProgram(riGraphicTools.sp_SolidColor); // creates OpenGL ES
// program
// executables
// Create the shaders, images
vertexShader = riGraphicTools.loadShader(GLES20.GL_VERTEX_SHADER, riGraphicTools.vs_Image);
fragmentShader = riGraphicTools.loadShader(GLES20.GL_FRAGMENT_SHADER, riGraphicTools.fs_Image);
riGraphicTools.sp_Image = GLES20.glCreateProgram(); // create empty
// OpenGL ES Program
GLES20.glAttachShader(riGraphicTools.sp_Image, vertexShader); // add the
// vertex
// shader
// to
// program
GLES20.glAttachShader(riGraphicTools.sp_Image, fragmentShader); // add
// the
// fragment
// shader
// to
// program
GLES20.glLinkProgram(riGraphicTools.sp_Image); // creates OpenGL ES
// program executables
// Set our shader programm
GLES20.glUseProgram(riGraphicTools.sp_Image);
// Creating a Images Object
this.images = new Images(this.mainActivity.getResources());
// Loading the Bitmaps
this.images.load();
Timer t = new Timer();
t.schedule(this.update = new Update(this.mainActivity, this, this.images), 16);
// Generate Textures, if more needed, alter these numbers.
this.texturenames = new int[24];
GLES20.glGenTextures(24, this.texturenames, 0);
SetupImageStatics();
}
private void SetupImageStatics () {
SetupImage(this.images.ground_1, 1);
SetupImage(this.images.bar1, 2);
SetupImage(this.images.speed1, 3);
SetupImage(this.images.speed2, 4);
SetupImage(this.images.start, 5);
SetupImage(this.images.life, 6);
SetupImage(this.images.upgradeBar, 7);
SetupImage(this.images.bunny1, 8);
SetupImage(this.images.carrotTower, 9);
SetupImage(this.images.mineThrower, 10);
SetupImage(this.images.bunnyKing1, 11);
}
public void SetupScaling () {
// The screen resolutions
this.swp = (this.mContext.getResources().getDisplayMetrics().widthPixels);
this.shp = (this.mContext.getResources().getDisplayMetrics().heightPixels);
// Orientation is assumed portrait
this.ssx = this.swp / 1280.0f;
this.ssy = this.shp / 720.0f;
// Get our uniform scaler
if (this.ssx > this.ssy) this.ssu = this.ssy;
else this.ssu = this.ssx;
}
public void processTouchEvent (MotionEvent me) {
switch (me.getAction()) {
case MotionEvent.ACTION_DOWN:
this.update.x = (int) me.getX();
this.update.y = (int) me.getY();
this.update.getItemOrUpgrade(this.update.x, this.update.y);
this.update.fastForward(this.update.x, this.update.y);
this.update.start(this.update.x, this.update.y);
this.update.nextUpgrade(this.update.x, this.update.y);
break;
case MotionEvent.ACTION_MOVE:
if (this.update.tower != 0) {
this.update.x = (int) me.getX();
this.update.y = (int) me.getY();
this.update.pathPlace(this.update.x, this.update.y);
}
break;
case MotionEvent.ACTION_UP:
this.update.x = (int) me.getX();
this.update.y = (int) me.getY();
this.update.placeOrReleaseItem = true;
break;
}
}
public void UpdateSprite (int location) {
// Get new transformed vertices
vertices = this.sprites.get(location).getTransformedVertices();
// The vertex buffer.
ByteBuffer bb = ByteBuffer.allocateDirect(vertices.length * 4);
bb.order(ByteOrder.nativeOrder());
this.vertexBuffer = bb.asIntBuffer();
this.vertexBuffer.put(vertices);
this.vertexBuffer.position(0);
}
public void SetupImage (Bitmap bmp, int index) {
// Create our UV coordinates.
uvs = new int[] { 0, 0, 0, 1, 1, 1, 1, 0 };
// The texture buffer
ByteBuffer bb = ByteBuffer.allocateDirect(uvs.length * 4);
bb.order(ByteOrder.nativeOrder());
this.uvBuffer = bb.asIntBuffer();
this.uvBuffer.put(uvs);
this.uvBuffer.position(0);
// // Retrieve our image from resources.
// int id =
// mContext.getResources().getIdentifier("drawable/ic_launcher", null,
// mContext.getPackageName());
//
// // Temporary create a bitmap
// Bitmap bmp = BitmapFactory.decodeResource(mContext.getResources(),
// id);
// Bind texture to texturename
GLES20.glActiveTexture(GLES20.GL_TEXTURE0 + index);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, this.texturenames[index]);
// Set filtering
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
// Load the bitmap into the bound texture.
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bmp, 0);
// // We are done using the bitmap so we should recycle it.
// bmp.recycle();
}
public void SetupTriangle (float width, float height, float x, float y) {
// Get information of sprite.
this.sprites.add(new Sprite(width, height, x, y));
vertices = this.sprites.get(this.sprites.size() - 1).getTransformedVertices();
// The order of vertexrendering for a quad
indices = new short[] { 0, 1, 2, 0, 2, 3 };
// The vertex buffer.
ByteBuffer bb = ByteBuffer.allocateDirect(vertices.length * 4);
bb.order(ByteOrder.nativeOrder());
this.vertexBuffer = bb.asIntBuffer();
this.vertexBuffer.put(vertices);
this.vertexBuffer.position(0);
// initialize byte buffer for the draw list
ByteBuffer dlb = ByteBuffer.allocateDirect(indices.length * 2);
dlb.order(ByteOrder.nativeOrder());
this.drawListBuffer = dlb.asShortBuffer();
this.drawListBuffer.put(indices);
this.drawListBuffer.position(0);
}
class Sprite {
float angle;
float scale;
RectF base;
Point translation;
public Sprite (float width, float height, float x, float y) {
// Initialise our intital size around the 0,0 point
this.base = new RectF(-(width / 2f) * GLRenderer.this.ssu, (height / 2f) * GLRenderer.this.ssu, (width / 2f) * GLRenderer.this.ssu, -(height / 2f) * GLRenderer.this.ssu);
// Initial translation
this.translation = new Point(Math.round(x * GLRenderer.this.ssu), Math.round(y * GLRenderer.this.ssu));
// We start with our inital size
this.scale = 1f;
// We start in our inital angle
this.angle = 0.0f;
}
public void translate (float deltax, float deltay) {
// Update our location.
this.translation.x += Math.round(deltax);
this.translation.y += Math.round(deltay);
}
public void scale (float deltas) {
this.scale += deltas;
}
public void rotate (float deltaa) {
this.angle += deltaa;
}
public int[] getTransformedVertices () {
// Start with scaling
int x1 = Math.round(this.base.left * this.scale);
int x2 = Math.round(this.base.right * this.scale);
int y1 = Math.round(this.base.bottom * this.scale);
int y2 = Math.round(this.base.top * this.scale);
// We now detach from our Rect because when rotating,
// we need the seperate points, so we do so in opengl order
Point one = new Point(x1, y2);
Point two = new Point(x1, y1);
Point three = new Point(x2, y1);
Point four = new Point(x2, y2);
// We create the sin and cos function once,
// so we do not have calculate them each time.
float s = (float) Math.sin(this.angle);
float c = (float) Math.cos(this.angle);
// Then we rotate each point
one.x = Math.round(x1 * c - y2 * s);
one.y = Math.round(x1 * s + y2 * c);
two.x = Math.round(x1 * c - y1 * s);
two.y = Math.round(x1 * s + y1 * c);
three.x = Math.round(x2 * c - y1 * s);
three.y = Math.round(x2 * s + y1 * c);
four.x = Math.round(x2 * c - y2 * s);
four.y = Math.round(x2 * s + y2 * c);
// Finally we translate the sprite to its correct position.
one.x += this.translation.x;
one.y += this.translation.y;
two.x += this.translation.x;
two.y += this.translation.y;
three.x += this.translation.x;
three.y += this.translation.y;
four.x += this.translation.x;
four.y += this.translation.y;
// We now return our float array of vertices.
return new int[] { Math.round(one.x), Math.round(one.y), 0, Math.round(two.x), Math.round(two.y), 0, Math.round(three.x), Math.round(three.y), 0, Math.round(four.x), Math.round(four.y), 0, };
}
}
public class Update extends TimerTask {
Bitmap ball;
int x, y;
int mapStage = StaticVariables.getMap();
int towerCost = 200;
boolean start = false;
int x2 = 0;
int y2 = 0;
public int points = 50000;
public boolean stageClear = false;
boolean everythingSpawned = false;
public int life = 200;
private int space = 40;
public boolean stageLose = false;
public boolean upgrade = false;
List<Opponent> opponents = new ArrayList<Opponent>();
List<Tower> towers = new ArrayList<Tower>();
List<Bullet> bullets = new ArrayList<Bullet>();
List<SuperExplosion> explosions = new ArrayList<SuperExplosion>();
List<Path> paths = new ArrayList<Path>();
List<int[]> stages = new ArrayList<int[]>();
private List<Integer> minesPassive = new ArrayList<Integer>();
private List<Integer> removeBulletsIndex = new ArrayList<Integer>();
List<Integer> removeMinesPassive = new ArrayList<Integer>();
public int time = 16;
public int speed = 1;
public int stageLevel = 1;
public boolean placePossible = true;
private int timeTimes = 0;
private int bubble = 0;
public boolean wait = false;
public int mapLength;
boolean change = false, change1 = false, change2 = false, change3 = false;
double maxX, maxY, minX, minY, abstandX2, abstandX, abstandY2, abstandY, shortestSpacing, shortest, angleMaxX, angleMaxY, angleMinX, angleMinY, angleAbstandX, angleAbstandY;
int shortestIndex, index, spawnCounter = 0;
private MediaPlayer bubblePopSound;
private int tower = 0;
int nextImage = 0;
private boolean normalSpeed = true;
float invisability = 1;
private int upgradeBarDiff = 0;
private boolean hideUpgradeBar = false;
public int iceBallRotation;
private int explosionTime;
private List<MinePlace> minesPlaced = new ArrayList<MinePlace>();
private int gameLocation = 0;
Localizer localizer;
int testCounter;
boolean load = true;
private boolean placeOrReleaseItem = false;
double viewWidth, viewHeight;
MergeSort mergeSort = new MergeSort();
GLRenderer glRenderer2;
public List<Integer> getMinesPassive () {
return this.minesPassive;
}
public void setMinesPassive (int index2, int minesPassive) {
this.minesPassive.set(index2, minesPassive);
}
public void addMinesPassive (int minesPassive) {
this.minesPassive.add(minesPassive);
}
public void addMinesPassive (int i, Integer minesPassive) {
this.minesPassive.add(i, minesPassive);
}
}
I hope you know a method to improve the drawing speed.
Thank you in advance!

It is a bit hard to say how to increase performance in your case. Too much noise in code from my perspective. But generally speaking there are some basic tips on how to increase performance during rendering:
- avoid unnecessary OpenGl state machine changes
- avoid unnecessary OpenGl state querying (e.g. GLES20.glGetAttribLocation())
- avoid memory allocations during rendering
- use simplest shaders possible
- use texture atlases to avoid necessary texture binds
- use VBOs whenever possible
For more information on subject try to read https://www.opengl.org/wiki/Performance. Or see this talk https://www.youtube.com/watch?v=YLVbLVtjDDw.
You may also consider using libGDX http://libgdx.badlogicgames.com/ it will handle drawing sprites efficient way for you.

Related

Failing to use VBOs in OpenGl/Android

Greetings my fellow programmers,
I've searched the WEB, checked examples online but still can't figure it out. I'm sorry if this was asked previously, I'm tired after a week-long debug of this. I hope you can help me.
Basically the problem is that I try to draw some quads (with triangles) but nothing is drawn. Previously I was drawing without VBOs the way described in 'Triangle example' on official Android website. Everything worked fine, but I decided that updating vertices/indices buffers in Renderer.OnDrawFrame() is not efficient :)
So here is my code:
public class FloorPlanRenderer implements GLSurfaceView.Renderer {
public volatile float mAngle;
// mMVPMatrix is an abbreviation for "Model View Projection Matrix"
private final float[] mMVPMatrix = new float[16];
private final float[] mProjectionMatrix = new float[16];
private final float[] mViewMatrix = new float[16];
private final float[] mRotationMatrix = new float[16];
private GLSurfaceView mGlView;
private GlEngine mGlEngine;
private boolean dataSet = false;
#Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
// Set the background frame color
GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
// Initialize the accumulated rotation matrix
Matrix.setIdentityM(mRotationMatrix, 0);
// Position the eye in front of the origin.
final float eyeX = 0.0f;
final float eyeY = 0.0f;
final float eyeZ = -3.0f;
// We are looking toward the distance
final float lookX = 0.0f;
final float lookY = 0.0f;
final float lookZ = 0.0f; //-5.0f;
// Set our up vector. This is where our head would be pointing were we holding the camera.
final float upX = 0.0f;
final float upY = 1.0f;
final float upZ = 0.0f;
// Set the view matrix. This matrix can be said to represent the camera position.
Matrix.setLookAtM(mViewMatrix, 0, eyeX, eyeY, eyeZ, lookX, lookY, lookZ, upX, upY, upZ);
mGlEngine = new GlEngine(10);
mGlEngine.registerQuad(new Wall(-0.5f, 0.4f, -0.2f, 0.4f));
mGlEngine.registerQuad(new Wall(0.5f, 0.4f, 0.2f, 0.4f));
mGlEngine.registerQuad(new Wall(0.0f, 0.0f, 0.0f, 0.3f, 0.02f));
}
#Override
public void onSurfaceChanged(GL10 unused, int width, int height) {
GLES20.glViewport(0, 0, width, height);
// Create a new perspective projection matrix. The height will stay the same
// while the width will vary as per aspect ratio.
final float ratio = (float) width / height;
final float left = -ratio;
final float right = ratio;
final float bottom = -1.0f;
final float top = 1.0f;
final float near = 3.0f;
final float far = 7.0f;
// this projection matrix is applied to object coordinates
// in the onDrawFrame() method
Matrix.frustumM(mProjectionMatrix, 0, left, right, bottom, top, near, far);
}
#Override
public void onDrawFrame(GL10 gl) {
float[] scratch = new float[16];
// Calculate the projection and view transformation
Matrix.multiplyMM(mMVPMatrix, 0, mProjectionMatrix, 0, mViewMatrix, 0);
Matrix.setRotateM(mRotationMatrix, 0, mAngle, 0, 0, 1.0f);
// Combine the rotation matrix with the projection and camera view
// Note that the mMVPMatrix factor *must be first* in order
// for the matrix multiplication product to be correct.
Matrix.multiplyMM(scratch, 0, mMVPMatrix, 0, mRotationMatrix, 0);
mGlEngine.render(scratch);
}
}
GlEngine class:
public class GlEngine {
public static final int COORDS_PER_VERTEX = 3;
public static final int ORDER_INDICES_PER_QUAD = 6;
public static final int VERTICES_PER_QUAD = 4;
public static final int SIZE_OF_FLOAT = Float.SIZE/Byte.SIZE;
public static final int SIZE_OF_SHORT = Short.SIZE/Byte.SIZE;
private int mQuadsNum = 0;
private int mLastCoordsIndex = 0;
private int mLastOrderIndex = 0;
private final FloatBuffer vertexBuffer;
private final ShortBuffer indexBuffer;
private final String vertexShaderCode =
// This matrix member variable provides a hook to manipulate
// the coordinates of the objects that use this vertex shader
"uniform mat4 uMVPMatrix;" +
"attribute vec4 vPosition;" +
"void main() {" +
// the matrix must be included as a modifier of gl_Position
// Note that the uMVPMatrix factor *must be first* in order
// for the matrix multiplication product to be correct.
" gl_Position = uMVPMatrix * vPosition;" +
"}";
// Use to access and set the view transformation
private int mMVPMatrixHandle;
private final String fragmentShaderCode =
"precision mediump float;" +
"uniform vec4 vColor;" +
"void main() {" +
" gl_FragColor = vColor;" +
"}";
private final int mProgram;
private int mPositionHandle;
private int mColorHandle;
private final int vertexStride = COORDS_PER_VERTEX * 4; // 4 bytes per vertex
float color[] = { 0.63671875f, 0.76953125f, 0.22265625f, 0.0f };
private boolean mDataInitNeeded = true;
public GlEngine(int quadsNum) {
ByteBuffer bb = ByteBuffer.allocateDirect(quadsNum * VERTICES_PER_QUAD *
COORDS_PER_VERTEX * SIZE_OF_FLOAT);
bb.order(ByteOrder.nativeOrder()); // device hardware's native byte order
vertexBuffer = bb.asFloatBuffer();
ByteBuffer bb2 = ByteBuffer.allocateDirect(quadsNum *
ORDER_INDICES_PER_QUAD * SIZE_OF_SHORT);
bb2.order(ByteOrder.nativeOrder());
indexBuffer = bb2.asShortBuffer();
int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER,
vertexShaderCode);
int fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER,
fragmentShaderCode);
mProgram = GLES20.glCreateProgram();
GLES20.glAttachShader(mProgram, vertexShader);
GLES20.glAttachShader(mProgram, fragmentShader);
GLES20.glLinkProgram(mProgram);
}
public static int loadShader(int type, String shaderCode){
// create a vertex shader type (GLES20.GL_VERTEX_SHADER)
// or a fragment shader type (GLES20.GL_FRAGMENT_SHADER)
int shader = GLES20.glCreateShader(type);
// add the source code to the shader and compile it
GLES20.glShaderSource(shader, shaderCode);
GLES20.glCompileShader(shader);
return shader;
}
public void registerQuad(Wall quad) {
quad.putCoords(vertexBuffer);
quad.putIndices(indexBuffer);
mQuadsNum++;
}
// This code is dealing with VBO side of things
private final int[] mVerticesBufferId = new int[BUFFERS_COUNT];
private final int[] mIndicesBufferId = new int[BUFFERS_COUNT];
private static final int BUFFERS_COUNT = 1;
public void copyToGpu(FloatBuffer vertices) {
GLES20.glGenBuffers(BUFFERS_COUNT, mVerticesBufferId, 0);
// Copy vertices data into GPU memory
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, mVerticesBufferId[0]);
GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, vertices.capacity() * SIZE_OF_FLOAT, vertices, GLES20.GL_STATIC_DRAW);
// Cleanup buffer
vertices.limit(0);
vertices = null;
}
public void copyToGpu(ShortBuffer indices) {
GLES20.glGenBuffers(BUFFERS_COUNT, mIndicesBufferId, 0);
// Copy vertices data into GPU memory
GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, mIndicesBufferId[0]);
GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, indices.capacity() * SIZE_OF_SHORT, indices, GLES20.GL_STATIC_DRAW);
// Cleanup buffer
indices.limit(0);
indices = null;
}
public void render(float[] mvpMatrix) {
setData();
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, mVerticesBufferId[0]);
GLES20.glUseProgram(mProgram);
mPositionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition");
GLES20.glEnableVertexAttribArray(mPositionHandle);
GLES20.glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX, GLES20.GL_FLOAT, false, vertexStride, 0);
mColorHandle = GLES20.glGetUniformLocation(mProgram, "vColor");
GLES20.glUniform4fv(mColorHandle, 1, color, 0);
// get handle to shape's transformation matrix
mMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix");
// Pass the projection and view transformation to the shader
GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mvpMatrix, 0);
GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, mIndicesBufferId[0]);
// Draw quads
GLES20.glDrawElements(
GLES20.GL_TRIANGLES, mQuadsNum * ORDER_INDICES_PER_QUAD,
GLES20.GL_UNSIGNED_SHORT, 0);
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, 0);
}
// This method is called on gl thread GlSurfaceView.queueEvent(...)
public void setData() {
if (mDataInitNeeded) {
// Reset positions of buffers for consuming in GL
vertexBuffer.position(0);
indexBuffer.position(0);
copyToGpu(vertexBuffer);
copyToGpu(indexBuffer);
mDataInitNeeded = false;
}
}
public void deallocateGlBuffers() {
if (mVerticesBufferId[0] > 0) {
GLES20.glDeleteBuffers(mVerticesBufferId.length, mVerticesBufferId, 0);
mVerticesBufferId[0] = 0;
}
if (mIndicesBufferId[0] > 0) {
GLES20.glDeleteBuffers(mIndicesBufferId.length, mIndicesBufferId, 0);
mIndicesBufferId[0] = 0;
}
}
}
The Wall class which represents rectangle:
public class Wall {
// number of coordinates per vertex in this array
private static final int COORDS_PER_VERTEX = 3;
private static final int VERTICES_NUM = 4; // it's a rect after all
private static final float DEFAULT_WIDTH = 0.05f;
private static final float DEFAULT_COORDS_SOURCE = 0.5f;
private final float mCoords[] = new float[COORDS_PER_VERTEX * VERTICES_NUM];
private final short mDrawOrder[] = { 0, 1, 2, // first triangle
1, 2, 3 }; // second triangle
private int mVertexBufferPosition;
private int mIndexBufferPosition;
private final PointF mA = new PointF(0, 0);
private final PointF mB = new PointF(0, 0);
private float mWidth;
public Wall() {
init(-DEFAULT_COORDS_SOURCE, DEFAULT_COORDS_SOURCE, DEFAULT_COORDS_SOURCE,
-DEFAULT_COORDS_SOURCE, DEFAULT_WIDTH);
}
public Wall(float x1, float y1, float x2, float y2)
{
init(x1, y1, x2, y2, DEFAULT_WIDTH);
}
public Wall(float x1, float y1, float x2, float y2, float width) {
init(x1, y1, x2, y2, width);
}
private void init(float x1, float y1, float x2, float y2, float width) {
mA.x = x1;
mA.y = y1;
mB.x = x2;
mB.y = y2;
mWidth = width;
calcCoords();
}
private void calcCoords() {
float[] vector = {mA.x - mB.x, mA.y - mB.y};
float magnitude = (float) Math.sqrt(vector[0]*vector[0] + vector[1]*vector[1]);
float[] identityVector = {vector[0]/magnitude, vector[1]/magnitude};
float[] orthogonalIdentityVector = {identityVector[1], -identityVector[0]};
mCoords[0] = mA.x + mWidth * orthogonalIdentityVector[0];
mCoords[1] = mA.y + mWidth * orthogonalIdentityVector[1];
mCoords[3] = mA.x - mWidth * orthogonalIdentityVector[0];
mCoords[4] = mA.y - mWidth * orthogonalIdentityVector[1];
mCoords[6] = mB.x + mWidth * orthogonalIdentityVector[0];
mCoords[7] = mB.y + mWidth * orthogonalIdentityVector[1];
mCoords[9] = mB.x - mWidth * orthogonalIdentityVector[0];
mCoords[10] = mB.y - mWidth * orthogonalIdentityVector[1];
}
public void putCoords(FloatBuffer vertexBuffer) {
mVertexBufferPosition = vertexBuffer.position();
for (int i = 0; i < mDrawOrder.length; i++) {
mDrawOrder[i] += mVertexBufferPosition/GlEngine.COORDS_PER_VERTEX;
}
vertexBuffer.put(mCoords);
}
public void putIndices(ShortBuffer indexBuffer) {
mIndexBufferPosition = indexBuffer.position();
indexBuffer.put(mDrawOrder);
}
public float getWidth() {
return mWidth;
}
public void setWidth(float mWidth) {
this.mWidth = mWidth;
}
public PointF getA() {
return mA;
}
public void setA(float x, float y) {
this.mA.x = x;
this.mA.y = y;
}
public PointF getB() {
return mB;
}
public void setB(float x, float y) {
this.mB.x = x;
this.mB.y = y;
}
}
In Wall class I save offset where it places its vertices and indices because this class will be changing in the future and it intended to update its vertices in the main buffer (the buffer will not be recompiled for each OnDrawFrame).
Thank you. I hope with your help I will somehow overcome this (another) obstacle on my way to OpenGl ES.
Shame on me! I incidentally put indices into wrong array. Instead of this:
// Copy vertices data into GPU memory
GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, mIndicesBufferId[0]);
GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, indices.capacity() * SIZE_OF_SHORT, indices, GLES20.GL_STATIC_DRAW);
There should be:
// Copy vertices data into GPU memory
GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, mIndicesBufferId[0]);
GLES20.glBufferData(GLES20.GL_ELEMENT_ARRAY_BUFFER, indices.capacity() * SIZE_OF_SHORT, indices, GLES20.GL_STATIC_DRAW);
Why shame? because in the log I saw:
07-23 16:20:05.442 5170-5264/com.example.neutrino.maze W/Adreno-ES20: : GL_INVALID_OPERATION
Just after the second call to glBufferData where I put GL_ARRAY_BUFFER instead of GL_ELEMENT_ARRAY_BUFFER. This was for sure caused by copy-paste as in many cases.

JOGL Issue with Vertex Buffers

I`m using Vertex Buffers in JOGL. I have a few hundred thousand triangles. Each triangle contains :
9 floats for the vertices - 3 for each edge
3 floats for the surface normal
3 floats for the colors.
I can`t seem to display the triangles or the colors. I know the normals are being calculated correctly.
This doesn`t work.
gl.glDrawArrays(GL2.GL_TRIANGLES, 0, vertxcnt);
But, the below snippet works - however I don`t see the colors. So, I know the points that are making up the triangles are correct.
gl.glDrawArrays(GL2.GL_POINTS, 0, vertxcnt);
So, if the points and the normals are correctly being calculated, I thinking is I`m going wrong in the render(gl) function. The code for that is below. What am I doing wrong? I cant post SSCCE now due to the complexity, but would like to know if anything is glaringly wrong.
private void render(GL2 gl) {
// VBO
// Enable Pointers
gl.glBindBuffer(GL2.GL_ARRAY_BUFFER, VBOVertices[0]); // Set Pointers To Our Data
gl.glEnableClientState(GL2.GL_VERTEX_ARRAY); // Enable Vertex Arrays
gl.glVertexPointer(3, GL.GL_FLOAT, BufferUtil.SIZEOF_FLOAT * 15, 0); //15 = 9 vertices of triangles + 3 normal + 3 colors
gl.glEnableClientState(GL2.GL_NORMAL_ARRAY);
gl.glNormalPointer(GL.GL_FLOAT, BufferUtil.SIZEOF_FLOAT * 15, BufferUtil.SIZEOF_FLOAT * 9);
gl.glEnableClientState(GL2.GL_COLOR_ARRAY);
gl.glColorPointer(3, GL.GL_FLOAT, BufferUtil.SIZEOF_FLOAT * 15, BufferUtil.SIZEOF_FLOAT * 12);
// Render
// Draw All Of The Triangles At Once
gl.glPointSize(4);
gl.glDrawArrays(GL2.GL_POINTS, 0, vertxcnt);
// Disable Pointers
// Disable Vertex, Normals and Color Arrays
gl.glDisableClientState(GL2.GL_VERTEX_ARRAY);
gl.glDisableClientState(GL2.GL_NORMAL_ARRAY);
gl.glDisableClientState(GL2.GL_COLOR_ARRAY);
}
Here is the init and display functions.
#Override
public void init(GLAutoDrawable drawable) {
GL2 gl = drawable.getGL().getGL2();
gl.glClearColor(0.0f, 0.0f, 6.0f, 0.5f);
gl.glClearDepth(1.0f); // Depth Buffer Setup
gl.glDepthFunc(GL.GL_LEQUAL); // The Type Of Depth Testing (Less Or
// Equal)
gl.glEnable(GL.GL_DEPTH_TEST); // Enable Depth Testing
gl.glDepthFunc(GL2.GL_LESS);
gl.glEnable(GL2.GL_LIGHTING);
gl.glEnable(GL2.GL_LIGHT0);
gl.glEnable(GL2.GL_AUTO_NORMAL);
gl.glEnable(GL2.GL_NORMALIZE);
gl.glEnable(GL2.GL_CULL_FACE);
gl.glFrontFace(GL2.GL_CCW);
gl.glCullFace(GL2.GL_BACK);
gl.glHint(GL2.GL_PERSPECTIVE_CORRECTION_HINT, GL2.GL_NICEST);
gl.glShadeModel(GL2.GL_SMOOTH);
buildVBOs(gl);
}
#Override
public void display(GLAutoDrawable drawable) {
GL2 gl = drawable.getGL().getGL2();
gl.glClearColor(.0f, .0f, .2f, 0.9f);
gl.glClear(GL2.GL_COLOR_BUFFER_BIT | GL2.GL_DEPTH_BUFFER_BIT);
gl.glLoadIdentity();
glu.gluLookAt(45, 0, 0, 0, 0, 0, 0.0, 1.0, 0.0);
float ma_x = (float) getMax(fx0);
float mi_x = (float) getMin(fx0);
float tr_x = (ma_x + mi_x) / 2;
float ma_y = (float) getMax(fy0);
float mi_y = (float) getMin(fy0);
float tr_y = (ma_y + mi_y) / 2;
float ma_z = (float) getMax(fz0);
float mi_z = (float) getMin(fz0);
float tr_z = (ma_z + mi_z) / 2;
gl.glScalef(scaleFac, scaleFac, scaleFac);
gl.glRotatef(rotFac, 0, 1, 0);
gl.glTranslatef(-tr_x, -tr_y, -tr_z);
for (int i = 0; i < 30; i++) {
render(gl);
gl.glRotatef(12, 0, 0, 1);
}
}
*/
private void createVects(double ang) {
int cnt = fx0.size();
for (int i = 0; i < cnt - 1; i++) {
// Triangle 1 and 2 [Top]
float x0 = (float) (fx0.get(i) * Math.cos(ang) - fy0.get(i) * Math.sin(ang));
float y0 = (float) (fx0.get(i) * Math.sin(ang) + fy0.get(i) * Math.cos(ang));
float z0 = fz0.get(i).floatValue();
Vect3D v0 = new Vect3D(x0, y0, z0);
fvert.add(v0); // 0
float x1 = (float) (fx0.get(i + 1) * Math.cos(ang) - fy0.get(i + 1) * Math.sin(ang));
float y1 = (float) (fx0.get(i + 1) * Math.sin(ang) + fy0.get(i + 1) * Math.cos(ang));
float z1 = fz0.get(i + 1).floatValue();
Vect3D v1 = new Vect3D(x1, y1, z1);
fvert.add(v1);// 1
float x2 = (float) (fx1.get(i + 1) * Math.cos(ang) - fy1.get(i + 1) * Math.sin(ang));
float y2 = (float) (fx1.get(i + 1) * Math.sin(ang) + fy1.get(i + 1) * Math.cos(ang));
float z2 = fz1.get(i + 1).floatValue();
Vect3D v2 = new Vect3D(x2, y2, z2);
fvert.add(v2);// 2
Vect3D n0 = calcNormal(v0, v1, v2);
fnorm.add(n0);
// VBO
vertices.put(x0); //vertices of the triangle
vertices.put(y0);
vertices.put(z0);
vertices.put(x1);
vertices.put(y1);
vertices.put(z1);
vertices.put(x2);
vertices.put(y2);
vertices.put(z2);
vertices.put(n0.x); // normals
vertices.put(n0.y);
vertices.put(n0.z);
vertices.put(0.5f); // colors // for now
vertices.put(0.0f);
vertices.put(0.0f);
}
}

LWJGL Circle program create's an oval-like shape

I'm trying to draw a circle in LWJGL, but when I draw I try to draw it, it makes a shape that's more like an oval rather than a circle. Also, when I change my circleVertexCount 350+, the shape like flips out. I'm really not sure how the code works that creates the vertices(I have taken Geometry and I know the basic trig ratios). I haven't really found that good of tutorials on creating circles. Here's my code:
public class Circles {
// Setup variables
private int WIDTH = 800;
private int HEIGHT = 600;
private String title = "Circle";
private float fXOffset;
private int vbo = 0;
private int vao = 0;
int circleVertexCount = 300;
float[] vertexData = new float[(circleVertexCount + 1) * 4];
public Circles() {
setupOpenGL();
setupQuad();
while (!Display.isCloseRequested()) {
loop();
adjustVertexData();
Display.update();
Display.sync(60);
}
Display.destroy();
}
public void setupOpenGL() {
try {
Display.setDisplayMode(new DisplayMode(WIDTH, HEIGHT));
Display.setTitle(title);
Display.create();
} catch (LWJGLException e) {
e.printStackTrace();
System.exit(-1);
}
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
}
public void setupQuad() {
float r = 0.1f;
float x;
float y;
float offSetX = 0f;
float offSetY = 0f;
double theta = 2.0 * Math.PI;
vertexData[0] = (float) Math.sin(theta / circleVertexCount) * r + offSetX;
vertexData[1] = (float) Math.cos(theta / circleVertexCount) * r + offSetY;
for (int i = 2; i < 400; i += 2) {
double angle = theta * i / circleVertexCount;
x = (float) Math.cos(angle) * r;
vertexData[i] = x + offSetX;
}
for (int i = 3; i < 404; i += 2) {
double angle = Math.PI * 2 * i / circleVertexCount;
y = (float) Math.sin(angle) * r;
vertexData[i] = y + offSetY;
}
FloatBuffer vertexBuffer = BufferUtils.createFloatBuffer(vertexData.length);
vertexBuffer.put(vertexData);
vertexBuffer.flip();
vao = glGenVertexArrays();
glBindVertexArray(vao);
vbo = glGenBuffers();
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER,vertexBuffer, GL_STATIC_DRAW);
glVertexAttribPointer(0, 2, GL_FLOAT, false, 0, 0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
}
public void loop() {
glClear(GL_COLOR_BUFFER_BIT);
glBindVertexArray(vao);
glEnableVertexAttribArray(0);
glDrawArrays(GL_TRIANGLE_FAN, 0, vertexData.length / 2);
glDisableVertexAttribArray(0);
glBindVertexArray(0);
}
public static void main(String[] args) {
new Circles();
}
private void adjustVertexData() {
float newData[] = new float[vertexData.length];
System.arraycopy(vertexData, 0, newData, 0, vertexData.length);
if(Keyboard.isKeyDown(Keyboard.KEY_W)) {
fXOffset += 0.05f;
} else if(Keyboard.isKeyDown(Keyboard.KEY_S)) {
fXOffset -= 0.05f;
}
for(int i = 0; i < vertexData.length; i += 2) {
newData[i] += fXOffset;
}
FloatBuffer newDataBuffer = BufferUtils.createFloatBuffer(newData.length);
newDataBuffer.put(newData);
newDataBuffer.flip();
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferSubData(GL_ARRAY_BUFFER, 0, newDataBuffer);
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
}
300 Vertex Count(This is my main problem)
400 Vertex Count - I removed this image, it's bugged out, should be a tiny sliver cut out from the right, like a secant
500 Vertex Count
Each 100, it removes more and more of the circle, and so on.
One of your problems is this:
for (int i = 2; i < 400; i += 2) {
double angle = theta * i / circleVertexCount;
x = (float) Math.cos(angle) * r;
vertexData[i] = x + offSetX;
}
for (int i = 3; i < 404; i += 2) {
double angle = Math.PI * 2 * i / circleVertexCount;
y = (float) Math.sin(angle) * r;
vertexData[i] = y + offSetY;
}
You are using a different value for angle for the x and y position of each vertex.
You could try this instead:
for (int i = 0; i <= circleVertexCount; i++) {
double angle = i * theta / circleVertexCount;
x = (float) Math.cos(angle) * r;
y = (float) Math.sin(angle) * r;
vertexData[i * 2] = x + offSetX;
vertexData[i * 2 + 1] = y + offSetY;
}
The reason part of your circle was being cut out at higher vertex counts was the i < 400 in your for loops, so I have changed it to i <= circleVertexCount.
Another problem is that your window is not square, and you are not using a shader (or the deprecated built in matrices) to correct this. This means that one unit up looks a different length than one unit right, resulting in an oval instead of a circle. To fix this you could multiply your vertex x position by your display height divided by your display width, preferably in a shader.

Draw an Arc and gradient it

I would like to know if its possible to draw a Arc on a graphics Panel using a gradient and how I would go about it.
My end goal would be to rotate the arc in a full circle so it would be similar to a rotating loading circle. However it is not a loading bar. It would be a background of a custom JButton.
Any suggestions to alternatives that would create a similar effect would be appreciated.
This is similar to what oi want to draw. Keep in mind that it will be "rotating"
public class TestArc {
public static void main(String[] args) {
new TestArc();
}
public TestArc() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
public TestPane() {
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
int radius = Math.min(getWidth(), getHeight());
int x = (getWidth() - radius) / 2;
int y = (getHeight() - radius) / 2;
RadialGradientPaint rgp = new RadialGradientPaint(
new Point(getWidth() / 2, getHeight() / 2),
radius,
new float[]{0f, 1f},
new Color[]{Color.RED, Color.YELLOW}
);
g2d.setPaint(rgp);
g2d.fill(new Arc2D.Float(x, y, radius, radius, 0, 45, Arc2D.PIE));
g2d.dispose();
}
}
}
You might like to have a look at 2D Graphics for more info
Updated after additional input
So you want a conical fill effect then...
The implementation I have comes from Harmonic Code, but I can't find a direct reference to it (I think it's part of his (excellent) series), but you can see the source code here
Now. I had issues with the angles as it appears that 0 starts at the top point (not the left) and it doesn't like negative angles...you might have better luck, but what I did was create a basic buffer at a position I could easily get working and then rotate the graphics context using an AffineTransformation...
public class TestArc {
public static void main(String[] args) {
new TestArc();
}
public TestArc() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private float angle = 0;
private float extent = 270;
private BufferedImage buffer;
public TestPane() {
Timer timer = new Timer(125, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
angle -= 5;
if (angle > 360) {
angle = 0;
}
repaint();
}
});
timer.setRepeats(true);
timer.setCoalesce(false);
timer.start();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
protected BufferedImage getBuffer() {
if (buffer == null) {
int radius = Math.min(getWidth(), getHeight());
int x = (getWidth() - radius) / 2;
int y = (getHeight() - radius) / 2;
buffer = new BufferedImage(radius, radius, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = buffer.createGraphics();
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
float startAngle = 0;
Color start = new Color(0, 128, 0, 128);
Color end = new Color(0, 128, 0, 0);
ConicalGradientPaint rgp = new ConicalGradientPaint(
true,
new Point(getWidth() / 2, getHeight() / 2),
0.5f,
new float[]{startAngle, extent},
new Color[]{start, end});
g2d.setPaint(rgp);
g2d.fill(new Arc2D.Float(x, y, radius, radius, startAngle + 90, -extent, Arc2D.PIE));
// g2d.fill(new Ellipse2D.Float(0, 0, radius, radius));
g2d.dispose();
g2d.dispose();
}
return buffer;
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
int radius = Math.min(getWidth(), getHeight());
int x = (getWidth()) / 2;
int y = (getHeight()) / 2;
BufferedImage buffer = getBuffer();
g2d.setTransform(AffineTransform.getRotateInstance(Math.toRadians(angle), x, y));
x = (getWidth() - buffer.getWidth()) / 2;
y = (getHeight() - buffer.getHeight()) / 2;
g2d.drawImage(buffer, x, y, this);
g2d.dispose();
}
}
public final class ConicalGradientPaint implements java.awt.Paint {
private final java.awt.geom.Point2D CENTER;
private final double[] FRACTION_ANGLES;
private final double[] RED_STEP_LOOKUP;
private final double[] GREEN_STEP_LOOKUP;
private final double[] BLUE_STEP_LOOKUP;
private final double[] ALPHA_STEP_LOOKUP;
private final java.awt.Color[] COLORS;
private static final float INT_TO_FLOAT_CONST = 1f / 255f;
/**
* Standard constructor which takes the FRACTIONS in values from 0.0f to
* 1.0f
*
* #param CENTER
* #param GIVEN_FRACTIONS
* #param GIVEN_COLORS
* #throws IllegalArgumentException
*/
public ConicalGradientPaint(final java.awt.geom.Point2D CENTER, final float[] GIVEN_FRACTIONS, final java.awt.Color[] GIVEN_COLORS) throws IllegalArgumentException {
this(false, CENTER, 0.0f, GIVEN_FRACTIONS, GIVEN_COLORS);
}
/**
* Enhanced constructor which takes the FRACTIONS in degress from 0.0f to
* 360.0f and also an GIVEN_OFFSET in degrees around the rotation CENTER
*
* #param USE_DEGREES
* #param CENTER
* #param GIVEN_OFFSET
* #param GIVEN_FRACTIONS
* #param GIVEN_COLORS
* #throws IllegalArgumentException
*/
public ConicalGradientPaint(final boolean USE_DEGREES, final java.awt.geom.Point2D CENTER, final float GIVEN_OFFSET, final float[] GIVEN_FRACTIONS, final java.awt.Color[] GIVEN_COLORS) throws IllegalArgumentException {
// Check that fractions and colors are of the same size
if (GIVEN_FRACTIONS.length != GIVEN_COLORS.length) {
throw new IllegalArgumentException("Fractions and colors must be equal in size");
}
final java.util.ArrayList<Float> FRACTION_LIST = new java.util.ArrayList<Float>(GIVEN_FRACTIONS.length);
final float OFFSET;
if (USE_DEGREES) {
final double DEG_FRACTION = 1f / 360f;
if (Double.compare((GIVEN_OFFSET * DEG_FRACTION), -0.5) == 0) {
OFFSET = -0.5f;
} else if (Double.compare((GIVEN_OFFSET * DEG_FRACTION), 0.5) == 0) {
OFFSET = 0.5f;
} else {
OFFSET = (float) (GIVEN_OFFSET * DEG_FRACTION);
}
for (float fraction : GIVEN_FRACTIONS) {
FRACTION_LIST.add((float) (fraction * DEG_FRACTION));
}
} else {
// Now it seems to work with rotation of 0.5f, below is the old code to correct the problem
// if (GIVEN_OFFSET == -0.5)
// {
// // This is needed because of problems in the creation of the Raster
// // with a angle offset of exactly -0.5
// OFFSET = -0.49999f;
// }
// else if (GIVEN_OFFSET == 0.5)
// {
// // This is needed because of problems in the creation of the Raster
// // with a angle offset of exactly +0.5
// OFFSET = 0.499999f;
// }
// else
{
OFFSET = GIVEN_OFFSET;
}
for (float fraction : GIVEN_FRACTIONS) {
FRACTION_LIST.add(fraction);
}
}
// Check for valid offset
if (OFFSET > 0.5f || OFFSET < -0.5f) {
throw new IllegalArgumentException("Offset has to be in the range of -0.5 to 0.5");
}
// Adjust fractions and colors array in the case where startvalue != 0.0f and/or endvalue != 1.0f
final java.util.List<java.awt.Color> COLOR_LIST = new java.util.ArrayList<java.awt.Color>(GIVEN_COLORS.length);
COLOR_LIST.addAll(java.util.Arrays.asList(GIVEN_COLORS));
// Assure that fractions start with 0.0f
if (FRACTION_LIST.get(0) != 0.0f) {
FRACTION_LIST.add(0, 0.0f);
final java.awt.Color TMP_COLOR = COLOR_LIST.get(0);
COLOR_LIST.add(0, TMP_COLOR);
}
// Assure that fractions end with 1.0f
if (FRACTION_LIST.get(FRACTION_LIST.size() - 1) != 1.0f) {
FRACTION_LIST.add(1.0f);
COLOR_LIST.add(GIVEN_COLORS[0]);
}
// Recalculate the fractions and colors with the given offset
final java.util.Map<Float, java.awt.Color> FRACTION_COLORS = recalculate(FRACTION_LIST, COLOR_LIST, OFFSET);
// Clear the original FRACTION_LIST and COLOR_LIST
FRACTION_LIST.clear();
COLOR_LIST.clear();
// Sort the hashmap by fraction and add the values to the FRACION_LIST and COLOR_LIST
final java.util.SortedSet<Float> SORTED_FRACTIONS = new java.util.TreeSet<Float>(FRACTION_COLORS.keySet());
final java.util.Iterator<Float> ITERATOR = SORTED_FRACTIONS.iterator();
while (ITERATOR.hasNext()) {
final float CURRENT_FRACTION = ITERATOR.next();
FRACTION_LIST.add(CURRENT_FRACTION);
COLOR_LIST.add(FRACTION_COLORS.get(CURRENT_FRACTION));
}
// Set the values
this.CENTER = CENTER;
COLORS = COLOR_LIST.toArray(new java.awt.Color[]{});
// Prepare lookup table for the angles of each fraction
final int MAX_FRACTIONS = FRACTION_LIST.size();
this.FRACTION_ANGLES = new double[MAX_FRACTIONS];
for (int i = 0; i < MAX_FRACTIONS; i++) {
FRACTION_ANGLES[i] = FRACTION_LIST.get(i) * 360;
}
// Prepare lookup tables for the color stepsize of each color
RED_STEP_LOOKUP = new double[COLORS.length];
GREEN_STEP_LOOKUP = new double[COLORS.length];
BLUE_STEP_LOOKUP = new double[COLORS.length];
ALPHA_STEP_LOOKUP = new double[COLORS.length];
for (int i = 0; i < (COLORS.length - 1); i++) {
RED_STEP_LOOKUP[i] = ((COLORS[i + 1].getRed() - COLORS[i].getRed()) * INT_TO_FLOAT_CONST) / (FRACTION_ANGLES[i + 1] - FRACTION_ANGLES[i]);
GREEN_STEP_LOOKUP[i] = ((COLORS[i + 1].getGreen() - COLORS[i].getGreen()) * INT_TO_FLOAT_CONST) / (FRACTION_ANGLES[i + 1] - FRACTION_ANGLES[i]);
BLUE_STEP_LOOKUP[i] = ((COLORS[i + 1].getBlue() - COLORS[i].getBlue()) * INT_TO_FLOAT_CONST) / (FRACTION_ANGLES[i + 1] - FRACTION_ANGLES[i]);
ALPHA_STEP_LOOKUP[i] = ((COLORS[i + 1].getAlpha() - COLORS[i].getAlpha()) * INT_TO_FLOAT_CONST) / (FRACTION_ANGLES[i + 1] - FRACTION_ANGLES[i]);
}
}
/**
* Recalculates the fractions in the FRACTION_LIST and their associated
* colors in the COLOR_LIST with a given OFFSET. Because the conical
* gradients always starts with 0 at the top and clockwise direction you
* could rotate the defined conical gradient from -180 to 180 degrees which
* equals values from -0.5 to +0.5
*
* #param FRACTION_LIST
* #param COLOR_LIST
* #param OFFSET
* #return Hashmap that contains the recalculated fractions and colors after
* a given rotation
*/
private java.util.HashMap<Float, java.awt.Color> recalculate(final java.util.List<Float> FRACTION_LIST, final java.util.List<java.awt.Color> COLOR_LIST, final float OFFSET) {
// Recalculate the fractions and colors with the given offset
final int MAX_FRACTIONS = FRACTION_LIST.size();
final java.util.HashMap<Float, java.awt.Color> FRACTION_COLORS = new java.util.HashMap<Float, java.awt.Color>(MAX_FRACTIONS);
for (int i = 0; i < MAX_FRACTIONS; i++) {
// Add offset to fraction
final float TMP_FRACTION = FRACTION_LIST.get(i) + OFFSET;
// Color related to current fraction
final java.awt.Color TMP_COLOR = COLOR_LIST.get(i);
// Check each fraction for limits (0...1)
if (TMP_FRACTION <= 0) {
FRACTION_COLORS.put(1.0f + TMP_FRACTION + 0.0001f, TMP_COLOR);
final float NEXT_FRACTION;
final java.awt.Color NEXT_COLOR;
if (i < MAX_FRACTIONS - 1) {
NEXT_FRACTION = FRACTION_LIST.get(i + 1) + OFFSET;
NEXT_COLOR = COLOR_LIST.get(i + 1);
} else {
NEXT_FRACTION = 1 - FRACTION_LIST.get(0) + OFFSET;
NEXT_COLOR = COLOR_LIST.get(0);
}
if (NEXT_FRACTION > 0) {
final java.awt.Color NEW_FRACTION_COLOR = getColorFromFraction(TMP_COLOR, NEXT_COLOR, (int) ((NEXT_FRACTION - TMP_FRACTION) * 10000), (int) ((-TMP_FRACTION) * 10000));
FRACTION_COLORS.put(0.0f, NEW_FRACTION_COLOR);
FRACTION_COLORS.put(1.0f, NEW_FRACTION_COLOR);
}
} else if (TMP_FRACTION >= 1) {
FRACTION_COLORS.put(TMP_FRACTION - 1.0f - 0.0001f, TMP_COLOR);
final float PREVIOUS_FRACTION;
final java.awt.Color PREVIOUS_COLOR;
if (i > 0) {
PREVIOUS_FRACTION = FRACTION_LIST.get(i - 1) + OFFSET;
PREVIOUS_COLOR = COLOR_LIST.get(i - 1);
} else {
PREVIOUS_FRACTION = FRACTION_LIST.get(MAX_FRACTIONS - 1) + OFFSET;
PREVIOUS_COLOR = COLOR_LIST.get(MAX_FRACTIONS - 1);
}
if (PREVIOUS_FRACTION < 1) {
final java.awt.Color NEW_FRACTION_COLOR = getColorFromFraction(TMP_COLOR, PREVIOUS_COLOR, (int) ((TMP_FRACTION - PREVIOUS_FRACTION) * 10000), (int) (TMP_FRACTION - 1.0f) * 10000);
FRACTION_COLORS.put(1.0f, NEW_FRACTION_COLOR);
FRACTION_COLORS.put(0.0f, NEW_FRACTION_COLOR);
}
} else {
FRACTION_COLORS.put(TMP_FRACTION, TMP_COLOR);
}
}
// Clear the original FRACTION_LIST and COLOR_LIST
FRACTION_LIST.clear();
COLOR_LIST.clear();
return FRACTION_COLORS;
}
/**
* With the START_COLOR at the beginning and the DESTINATION_COLOR at the
* end of the given RANGE the method will calculate and return the color
* that equals the given VALUE. e.g. a START_COLOR of BLACK (R:0, G:0, B:0,
* A:255) and a DESTINATION_COLOR of WHITE(R:255, G:255, B:255, A:255) with
* a given RANGE of 100 and a given VALUE of 50 will return the color that
* is exactly in the middle of the gradient between black and white which is
* gray(R:128, G:128, B:128, A:255) So this method is really useful to
* calculate colors in gradients between two given colors.
*
* #param START_COLOR
* #param DESTINATION_COLOR
* #param RANGE
* #param VALUE
* #return Color calculated from a range of values by given value
*/
public java.awt.Color getColorFromFraction(final java.awt.Color START_COLOR, final java.awt.Color DESTINATION_COLOR, final int RANGE, final int VALUE) {
final float SOURCE_RED = START_COLOR.getRed() * INT_TO_FLOAT_CONST;
final float SOURCE_GREEN = START_COLOR.getGreen() * INT_TO_FLOAT_CONST;
final float SOURCE_BLUE = START_COLOR.getBlue() * INT_TO_FLOAT_CONST;
final float SOURCE_ALPHA = START_COLOR.getAlpha() * INT_TO_FLOAT_CONST;
final float DESTINATION_RED = DESTINATION_COLOR.getRed() * INT_TO_FLOAT_CONST;
final float DESTINATION_GREEN = DESTINATION_COLOR.getGreen() * INT_TO_FLOAT_CONST;
final float DESTINATION_BLUE = DESTINATION_COLOR.getBlue() * INT_TO_FLOAT_CONST;
final float DESTINATION_ALPHA = DESTINATION_COLOR.getAlpha() * INT_TO_FLOAT_CONST;
final float RED_DELTA = DESTINATION_RED - SOURCE_RED;
final float GREEN_DELTA = DESTINATION_GREEN - SOURCE_GREEN;
final float BLUE_DELTA = DESTINATION_BLUE - SOURCE_BLUE;
final float ALPHA_DELTA = DESTINATION_ALPHA - SOURCE_ALPHA;
final float RED_FRACTION = RED_DELTA / RANGE;
final float GREEN_FRACTION = GREEN_DELTA / RANGE;
final float BLUE_FRACTION = BLUE_DELTA / RANGE;
final float ALPHA_FRACTION = ALPHA_DELTA / RANGE;
//System.out.println(DISTANCE + " " + CURRENT_FRACTION);
return new java.awt.Color(SOURCE_RED + RED_FRACTION * VALUE, SOURCE_GREEN + GREEN_FRACTION * VALUE, SOURCE_BLUE + BLUE_FRACTION * VALUE, SOURCE_ALPHA + ALPHA_FRACTION * VALUE);
}
#Override
public java.awt.PaintContext createContext(final java.awt.image.ColorModel COLOR_MODEL, final java.awt.Rectangle DEVICE_BOUNDS, final java.awt.geom.Rectangle2D USER_BOUNDS, final java.awt.geom.AffineTransform TRANSFORM, final java.awt.RenderingHints HINTS) {
final java.awt.geom.Point2D TRANSFORMED_CENTER = TRANSFORM.transform(CENTER, null);
return new ConicalGradientPaintContext(TRANSFORMED_CENTER);
}
#Override
public int getTransparency() {
return java.awt.Transparency.TRANSLUCENT;
}
private final class ConicalGradientPaintContext implements java.awt.PaintContext {
final private java.awt.geom.Point2D CENTER;
public ConicalGradientPaintContext(final java.awt.geom.Point2D CENTER) {
this.CENTER = new java.awt.geom.Point2D.Double(CENTER.getX(), CENTER.getY());
}
#Override
public void dispose() {
}
#Override
public java.awt.image.ColorModel getColorModel() {
return java.awt.image.ColorModel.getRGBdefault();
}
#Override
public java.awt.image.Raster getRaster(final int X, final int Y, final int TILE_WIDTH, final int TILE_HEIGHT) {
final double ROTATION_CENTER_X = -X + CENTER.getX();
final double ROTATION_CENTER_Y = -Y + CENTER.getY();
final int MAX = FRACTION_ANGLES.length;
// Create raster for given colormodel
final java.awt.image.WritableRaster RASTER = getColorModel().createCompatibleWritableRaster(TILE_WIDTH, TILE_HEIGHT);
// Create data array with place for red, green, blue and alpha values
int[] data = new int[(TILE_WIDTH * TILE_HEIGHT * 4)];
double dx;
double dy;
double distance;
double angle;
double currentRed = 0;
double currentGreen = 0;
double currentBlue = 0;
double currentAlpha = 0;
for (int py = 0; py < TILE_HEIGHT; py++) {
for (int px = 0; px < TILE_WIDTH; px++) {
// Calculate the distance between the current position and the rotation angle
dx = px - ROTATION_CENTER_X;
dy = py - ROTATION_CENTER_Y;
distance = Math.sqrt(dx * dx + dy * dy);
// Avoid division by zero
if (distance == 0) {
distance = 1;
}
// 0 degree on top
angle = Math.abs(Math.toDegrees(Math.acos(dx / distance)));
if (dx >= 0 && dy <= 0) {
angle = 90.0 - angle;
} else if (dx >= 0 && dy >= 0) {
angle += 90.0;
} else if (dx <= 0 && dy >= 0) {
angle += 90.0;
} else if (dx <= 0 && dy <= 0) {
angle = 450.0 - angle;
}
// Check for each angle in fractionAngles array
for (int i = 0; i < (MAX - 1); i++) {
if ((angle >= FRACTION_ANGLES[i])) {
currentRed = COLORS[i].getRed() * INT_TO_FLOAT_CONST + (angle - FRACTION_ANGLES[i]) * RED_STEP_LOOKUP[i];
currentGreen = COLORS[i].getGreen() * INT_TO_FLOAT_CONST + (angle - FRACTION_ANGLES[i]) * GREEN_STEP_LOOKUP[i];
currentBlue = COLORS[i].getBlue() * INT_TO_FLOAT_CONST + (angle - FRACTION_ANGLES[i]) * BLUE_STEP_LOOKUP[i];
currentAlpha = COLORS[i].getAlpha() * INT_TO_FLOAT_CONST + (angle - FRACTION_ANGLES[i]) * ALPHA_STEP_LOOKUP[i];
continue;
}
}
// Fill data array with calculated color values
final int BASE = (py * TILE_WIDTH + px) * 4;
data[BASE + 0] = (int) (currentRed * 255);
data[BASE + 1] = (int) (currentGreen * 255);
data[BASE + 2] = (int) (currentBlue * 255);
data[BASE + 3] = (int) (currentAlpha * 255);
}
}
// Fill the raster with the data
RASTER.setPixels(0, 0, TILE_WIDTH, TILE_HEIGHT, data);
return RASTER;
}
}
}
}

OpenGL render grid and rotate script not working?

I created a simple script that creates a perlin noise array and renders it on-screen. The perlin code is sound, but the render code is not. The screen only renders white with absolutely nothing on-screen.
public class MainClass {
double lastFPS = 0;
double fps = 0;
int seed = 0;
float rotation = 0;
float[][]noise = new float[0][0];
float[]cameraPos = {0f,0f,0f};
public static void main(String[] args)
{
MainClass mainClass = new MainClass();
Random r = new Random();
mainClass.seed = r.nextInt();
mainClass.launchScreen();
}
float lerp(float x0, float x1, float alpha)
{
return x0 * (1 - alpha) + alpha * x1;
}
/**
* Calculate the FPS and set it in the title bar
*/
public void updateFPS() {
if (getTime() - lastFPS > 1000) {
Display.setTitle("FPS: " + fps + "; Seed: " + seed);
fps = 0; //reset the FPS counter
lastFPS += 1000; //add one second
}
fps++;
}
public void launchScreen()
{
try {
Display.setDisplayMode(new DisplayMode(800,600));
Display.create();
} catch (LWJGLException e) {
e.printStackTrace();
System.exit(0);
}
lastFPS = getTime();
float rot = 0.0f;
PerlinGen pg = new PerlinGen();
noise = pg.GeneratePerlinNoise(pg.GenerateWhiteNoise(100, 100, seed), 5); //Get perlin noise array, returns float values from 0.0 to 1.0.
System.out.println("Noise length is: (" + noise.length + "," + noise[0].length + ")");
// init OpenGL here
GL11.glMatrixMode(GL11.GL_PROJECTION);
GL11.glLoadIdentity();
GL11.glOrtho(0, 800, 0, 600, 1, -1);
GL11.glMatrixMode(GL11.GL_MODELVIEW);
GL11.glPolygonMode( GL11.GL_FRONT_AND_BACK, GL11.GL_LINE ); //Wireframe
//GL11.glPolygonMode( GL11.GL_FRONT_AND_BACK, GL11.GL_FILL ); //Normal
while (!Display.isCloseRequested()) {
updateFPS();
// render OpenGL here
GL11.glClearColor(1,1,1,1);
GL11.glClear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT);
// draw quad
int centerX = noise.length*5;
int centerY = 5;
int centerZ = noise[0].length*-5;
GLU.gluLookAt(centerX*2,500, centerZ*2, /* look from camera XYZ */
centerX, centerY, centerZ, /* look at the origin */
0, 1, 0); /* positive Y up vector */
drawNoiseGrid(rot);
rot += 0.05f;
Display.update();
}
Display.destroy();
}
public void drawNoiseGrid(float r)
{
rotation = r;
GL11.glColor3f(0f,0f,0.0f);
for(int x=0;x<noise.length-1;x++)
{
for(int y=0;y<noise[x].length-1;y++)
{
GL11.glBegin(GL11.GL_QUADS);
GL11.glVertex3f(10*x,noise[x][y]*10,-10*y);//topleft
GL11.glVertex3f(10*(x+1),noise[x+1][y]*10,-10*y);//topright
GL11.glVertex3f(10*x,noise[x][y+1]*10,-10*(y+1));//bottomleft
GL11.glVertex3f(10*(x+1),noise[x+1][y+1]*10,-10*(y+1));//bottomright
GL11.glEnd();
}
}
}
/**
* Get the time in milliseconds
*
* #return The system time in milliseconds
*/
public long getTime() {
return (Sys.getTime() * 1000) / Sys.getTimerResolution();
}
}
You have each quad structured like this:
//topleft
//topright
//bottomleft
//bottomright
If that sequence is accurate you're trying to submit some sort of goofy "Z"-shaped polygon to GL_QUADS.
Try this order instead:
//bottomleft
//bottomright
//topright
//topleft
Also, you don't need a glBegin()/glEnd() per quad so move those to the outside of the loop for a little performance boost:
GL11.glBegin(GL11.GL_QUADS);
for(int x=0;x<noise.length-1;x++)
{
for(int y=0;y<noise[x].length-1;y++)
{
GL11.glVertex3f(10*x,noise[x][y+1]*10,-10*(y+1));//bottomleft
GL11.glVertex3f(10*(x+1),noise[x+1][y+1]*10,-10*(y+1));//bottomright
GL11.glVertex3f(10*(x+1),noise[x+1][y]*10,-10*y);//topright
GL11.glVertex3f(10*x,noise[x][y]*10,-10*y);//topleft
}
}
GL11.glEnd();

Categories

Resources