android OpenGL ES simple Tile generator performance problem - android

following this question : Best approach for oldschool 2D zelda-like game
Thank to previous replies, and with a major inspiration from http://insanitydesign.com/wp/projects/nehe-android-ports/ , i started to build a simple Tile Generator for my simple 2D zelda-like game project.
I can now generate a map with the same textured tile, using 2 for(..) imbricated iterations to draw horizontal and vertical tiles, and got some basic DPAD key input listeners to scroll over the x and y axis.
but now im running into my first performance problems, just with one texture and one model.
When trying to build a 10x10 map, scrolling is fine and smooth.
When trying with 50x50, things get worse, and with a 100x100, its way unacceptable.
Is there a way only to tell OpenGL to render the 'visible' part of my mapset and ignore the hidden tiles? im a totally new to this.
im using
GLU.gluLookAt(gl, cameraPosX, cameraPosY, 10.0f,cameraPosX, cameraPosY, 0.0f, 0.0f, 1.0f, 0.0f);
to set the camera and point of view for a 2D-style feeling.
Any help ? :)
for (int j = 0; j < 10; j++) {
for (int i = 0; i < 10; i++) {
gl.glPushMatrix(); // Sauvegarde la matrice sur le stack
//Bind the texture according to the set texture filter
gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[filter]);
//Set the face rotation
gl.glFrontFace(GL10.GL_CW);
//Enable texture state
gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
//Enable vertex state
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
//Point to our vertex buffer
gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuffer);
//point to our texture buff
gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, textureBuffer);
//Draw the vertices as triangle strip
gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, vertices.length / 3);
//Disable the client state before leaving
gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
gl.glTranslatef(1.0f, 0.0f, 0.0f); // on avance d'une tile
}
// on va commencer a dessiner la 2e ligne
gl.glPopMatrix(); // Rappelle la matrice sur le stack
gl.glTranslatef(0.0f, -1.0f, 0.0f);
}

The reason why the loop gets slow is that it makes OpenGL to do lots of unnecessary work. This is because there are lots of redundant state changes.
That means that you are calling gl functions with parameters that doesn't have any effect. Calling these functions eat up a lot of CPU time and might cause the whole OpenGL pipeline to stall as it cannot work very effectively.
For example you should call glBindTexture only if you want to change the texture used. The above code binds the same texture over and over again in the inner loop which is very expensive. Similarly you don't need to enable and disable texture coordinate and vertex arrays in the inner loop. Even setting texture coordinate pointer and vertex pointer in the inner loop is unnecessary as they don't change between subsequent loops.
The bottom line is, that in the inner loop you should only change translation and call glDrawArrays. Everything else just eats up resources for nothing.
There are more advanced things you can do to speed this up even more. Tile background can be drawn so that it causes only one call to glDrawArrays (or glDrawElements). If you are interested in, you should Google topics like batching and texture atlases.

You can easily make your loop to draw only the visible aria.
Here is some example how it needs to be done. I don't know the android API so thread my example as metacode.
int cols = SCREEN_WIDTH / TILE_SIZE + 1; // how many columns can fit on the screen
int rows = SCREEN_HEIGHT / TILE_SIZE + 1; // haw many rows can fit on the screen
int firstVisibleCol = cameraPosX / TILE_SIZE; // first column we need to draw
int firstVisibleRow = cameraPosY / TILE_SIZE; // first row we need to draw
// and now the loop becomes
for (int j = firstVisibleRow; j < rows; j++) {
for (int i = firstVisibleCol ; i < cols; i++) {
...
}
}

Related

How to make a cylinder in renderscript

I have been trying to make a cylinder in renderscript. This is the code I've tried:
public Mesh cylinder(){
float radius=1.25f, halfLength=5;
int slices=16;
Mesh.TriangleMeshBuilder mbo= new TriangleMeshBuilder(mRSGL,3, Mesh.TriangleMeshBuilder.TEXTURE_0);
for(int i=0; i<slices; i++) {
float theta = (float) (((float)i)*2.0*Math.PI);
float nextTheta = (float) (((float)i+1)*2.0*Math.PI);
/*vertex at middle of end*/
mbo.addVertex(0.0f, halfLength, 0.0f);
/*vertices at edges of circle*/
mbo.addVertex((float)(radius*Math.cos(theta)), halfLength, (float)(radius*Math.sin(theta)));
mbo.addVertex((float)(radius*Math.cos(nextTheta)), halfLength, (float)(radius*Math.sin(nextTheta)));
/* the same vertices at the bottom of the cylinder*/
mbo.addVertex((float)(radius*Math.cos(nextTheta)), -halfLength, (float)(radius*Math.sin(nextTheta)));
mbo.addVertex((float)(radius*Math.cos(theta)), halfLength, (float)(radius*Math.sin(theta)));
mbo.addVertex(0.0f, -halfLength, 0.0f);
mbo.addTriangle(0, 1, 2);
mbo.addTriangle(3, 4, 5);
}
return mbo.create(true);
}
But this code gives me a rectangle of length 5. Any ideas where I'm going wrong?
You actually have a few problems here. First, your angles are always equal to multiples of 2pi. You need to divide by the number of sectors when you calculate your angles. Additionally in this step you have an unnecessary explicit type conversion, java will handle the conversion of integer to double for you.
Second, you are constantly adding the same two triangles to the mesh and not adding any triangles for the side of the cylinder, just the two end faces. In your loop when calling addTriangle() you should use indices, for example addTriangle(n, n+1, n+2).
Finally, you were missing a negative sign when you created your 4th vertex, so it was actually at halfLength, not -halfLength.
Try this:
public Mesh cylinder(){
float radius=1.25f, halfLength=5;
int slices=16;
Mesh.TriangleMeshBuilder mbo= new TriangleMeshBuilder(mRSGL,3, Mesh.TriangleMeshBuilder.TEXTURE_0);
/*vertex at middle of end*/
mbo.addVertex(0.0f, halfLength, 0.0f);
mbo.addVertex(0.0f, -halfLength, 0.0f);
for(int i=0; i<slices; i++) {
float theta = (float) (i*2.0*Math.PI / slices);
float nextTheta = (float) ((i+1)*2.0*Math.PI / slices);
/*vertices at edges of circle*/
mbo.addVertex((float)(radius*Math.cos(theta)), halfLength, (float)(radius*Math.sin(theta)));
mbo.addVertex((float)(radius*Math.cos(nextTheta)), halfLength, (float)(radius*Math.sin(nextTheta)));
/* the same vertices at the bottom of the cylinder*/
mbo.addVertex((float)(radius*Math.cos(nextTheta)), -halfLength, (float)(radius*Math.sin(nextTheta)));
mbo.addVertex((float)(radius*Math.cos(theta)), -halfLength, (float)(radius*Math.sin(theta)));
/*Add the faces for the ends, ordered for back face culling*/
mbo.addTriangle(4*i+3, 4*i+2, 0);
//The offsets here are to adjust for the first two indices being the center points. The sector number (i) is multiplied by 4 because the way you are building this mesh, there are 4 vertices added with each sector
mbo.addTriangle(4*i+5, 4*i+4, 1);
/*Add the faces for the side*/
mbo.addTriangle(4*i+2, 4*i+4, 4*i+5);
mbo.addTriangle(4*i+4, 4*i+2, 4*i+3);
}
return mbo.create(true);
}
I have also added a slight optimization where the vertices for the centers of the circles are created only once, thus saving memory. The order of indices here is for back face culling. Reverse it if you want front face. Should your needs require a more efficient method eventually, allocation builders allow for using trifans and tristrips, but for a mesh of this complexity the ease of triangle meshes is merited. I have run this code on my own system to verify that it works.

Android 3D Surface Plot

My requirement is to create a 3d surface plot(should also display the x y z axis) from a list of data points (x y z) values.The 3d visualization should be done on ANDROID.
My Inputs : Currently planning on using open gl 1.0 and java. I m also considering Adore3d , min3d and rgl package which uses open gl 1.0. Good at java ,but a novice at 3d programming.
Time Frame : 2 months
I would like to know the best way to go about it? Is opengl 1.0 good for 3d surface plotting?Any other packages/libraries that can be used with Android?
Well, you can plot the surface using OpenGL 1.0 or OpenGL 2.0. All you need to do is to draw the axes as lines and draw the surface as triangles. If you have your heightfield data, you would do:
float[][] surface;
int width, height; // 2D surface data and it's dimensions
GL.glBegin(GL.GL_LINES);
GL.glVertex3f(0, 0, 0); // line starting at 0, 0, 0
GL.glVertex3f(width, 0, 0); // line ending at width, 0, 0
GL.glVertex3f(0, 0, 0); // line starting at 0, 0, 0
GL.glVertex3f(0, 0, height); // line ending at 0, 0, height
GL.glVertex3f(0, 0, 0); // line starting at 0, 0, 0
GL.glVertex3f(0, 50, 0); // line ending at 0, 50, 0 (50 is maximal value in surface[])
GL.glEnd();
// display the axes
GL.glBegin(GL.GL_TRIANGLES);
for(int x = 1; x < width; ++ x) {
for(int y = 1; y < height; ++ y) {
float a = surface[x - 1][y - 1];
float b = surface[x][y - 1];
float c = surface[x][y];
float d = surface[x - 1][y];
// get four points on the surface (they form a quad)
GL.glVertex3f(x - 1, a, y - 1);
GL.glVertex3f(x, b, y - 1);
GL.glVertex3f(x, c, y);
// draw triangle abc
GL.glVertex3f(x - 1, a, y - 1);
GL.glVertex3f(x, c, y);
GL.glVertex3f(x - 1, d, y);
// draw triangle acd
}
}
GL.glEnd();
// display the data
This draws simple axes and heightfield, all in white color. It should be pretty straight forward to extend it from here.
Re the second part of your question:
Any other packages/libraries that can be used with Android?
Yes, it's now possible to draw an Android 3D Surface Plot with SciChart.
Link to Android Chart features page
Link to Android 3D Surface Plot example
Lots of configurations are possible including drawing wireframe, gradient colour maps, contours and real-time updates.
Disclosure, I'm the tech lead on the scichart team

Problems Using Wavefront .obj's texture coordinates in Android OpenGL ES

I'm writing an android app using openGL ES. I followed some online tutorials and managed to load up a textured cube using hard-coded vertices/indices/texture coordinates
As a next step I wrote a parser for wavefront .obj files. I made a mock file using the vertices etc from the tutorial, which loads fine.
However, when I use a file made using a 3d modelling package, all the textures get messed up
Below is how I'm currently getting the texture coordinates:
First I load all the texture coordinates, the vt's into a big vector
Next I find the first two texture coordinates for each f triangle (so f 1/2/3 2/5/2 3/4/1 means I take the 2nd and 5th texture coordinates. Since .obj starts counting from 1 not 0, I have to -1 from the position and then multiply the position by 2 for the x coord position and do the same but +1 for the y coord position in my vt array)
I take those texture coordinates that I just found and add them to another vector.
Once I've gone through all the vertices. I turn the vector into a FloatBuffer, passing that to glTexCoordPointer in my draw method
Here is the code for parsing the file:
private void openObjFile(String filename, Context context, GL10 gl){
Vector<String> lines = openFile(filename, context); // opens the file
Vector<String[]> tokens = new Vector<String[]>();
Vector<Float> vertices = new Vector<Float>();
Vector<Float> textureCoordinates = new Vector<Float>();
Vector<Float> vertexNormals = new Vector<Float>();
// tokenise
for(int i = 0;i<lines.size();i++){
String line = lines.get(i);
tokens.add(line.split(" "));
}
for(int j = 0;j<tokens.size();j++){
String[] linetokens = tokens.get(j);
// get rid of comments
//if(linetokens[0].equalsIgnoreCase("#")){
//tokens.remove(j);
//}
// get texture from .mtl file
if(linetokens[0].equalsIgnoreCase("mtllib")){
parseMaterials(linetokens[1],context, gl);
}
// vertices
if(linetokens[0].equalsIgnoreCase("v")){
vertices.add(Float.valueOf(linetokens[1]));
vertices.add(Float.valueOf(linetokens[2]));
vertices.add(Float.valueOf(linetokens[3]));
}
// texture coordinates
if(linetokens[0].equalsIgnoreCase("vt")){
textureCoordinates.add(Float.valueOf(linetokens[1]));
textureCoordinates.add(Float.valueOf(linetokens[2]));
}
// vertex normals
if(linetokens[0].equalsIgnoreCase("vn")){
vertexNormals.add(Float.valueOf(linetokens[1]));
vertexNormals.add(Float.valueOf(linetokens[2]));
vertexNormals.add(Float.valueOf(linetokens[3]));
}
}
// vertices
this.vertices = GraphicsUtil.getFloatBuffer(vertices);
Mesh mesh = null;
Vector<Short> indices = null;
Vector<Float> textureCoordinatesMesh = null;
Vector<Float> vertexNormalsMesh = null;
for(int j = 0;j<tokens.size();j++){
String[] linetokens = tokens.get(j);
if(linetokens[0].equalsIgnoreCase("g")){
if(mesh!=null){
mesh.setIndices(GraphicsUtil.getShortBuffer(indices));
mesh.setNumindices(indices.size());
mesh.setNormals(GraphicsUtil.getFloatBuffer(vertexNormalsMesh));
mesh.setTextureCoordinates(GraphicsUtil.getFloatBuffer(textureCoordinatesMesh));
meshes.add(mesh);
}
mesh = new Mesh();
indices = new Vector<Short>();
textureCoordinatesMesh = new Vector<Float>();
vertexNormalsMesh = new Vector<Float>();
} else if(linetokens[0].equalsIgnoreCase("usemtl")){
String material_name = linetokens[1];
for(int mn = 0;mn<materials.size();mn++){
if(materials.get(mn).getName().equalsIgnoreCase(material_name)){
mesh.setTextureID(materials.get(mn).getTextureID());
mn = materials.size();
}
}
} else if(linetokens[0].equalsIgnoreCase("f")){
for(int v = 1;v<linetokens.length;v++){
String[] vvtvn = linetokens[v].split("/");
short index = Short.parseShort(vvtvn[0]);
index -= 1;
indices.add(index);
if(v!=3){
int texturePosition = (Integer.parseInt(vvtvn[1]) - 1) * 2;
float xcoord = (textureCoordinates.get(texturePosition));
float ycoord = (textureCoordinates.get(texturePosition+1));
// normalise
if(xcoord>1 || ycoord>1){
xcoord = xcoord / Math.max(xcoord, ycoord);
ycoord = ycoord / Math.max(xcoord, ycoord);
}
textureCoordinatesMesh.add(xcoord);
textureCoordinatesMesh.add(ycoord);
}
int normalPosition = (Integer.parseInt(vvtvn[2]) - 1) *3;
vertexNormalsMesh.add(vertexNormals.get(normalPosition));
vertexNormalsMesh.add(vertexNormals.get(normalPosition)+1);
vertexNormalsMesh.add(vertexNormals.get(normalPosition)+2);
}
}
}
if(mesh!=null){
mesh.setIndices(GraphicsUtil.getShortBuffer(indices));
mesh.setNumindices(indices.size());
mesh.setNormals(GraphicsUtil.getFloatBuffer(vertexNormalsMesh));
mesh.setTextureCoordinates(GraphicsUtil.getFloatBuffer(textureCoordinatesMesh));
meshes.add(mesh);
}// Adding the final mesh
}
And here is the code for drawing:
public void draw(GL10 gl){
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
// Counter-clockwise winding.
gl.glFrontFace(GL10.GL_CCW);
gl.glEnable(GL10.GL_CULL_FACE);
gl.glCullFace(GL10.GL_BACK);
// Pass the vertex buffer in
gl.glVertexPointer(3, GL10.GL_FLOAT, 0,
vertices);
for(int i=0;i<meshes.size();i++){
meshes.get(i).draw(gl);
}
// Disable the buffers
gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
}
public void draw(GL10 gl){
if(textureID>=0){
// Enable Textures
gl.glEnable(GL10.GL_TEXTURE_2D);
// Get specific texture.
gl.glBindTexture(GL10.GL_TEXTURE_2D, textureID);
// Use UV coordinates.
gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
// Pass in texture coordinates
gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, textureCoordinates);
}
// Pass in texture normals
gl.glNormalPointer(GL10.GL_FLOAT, 0, normals);
gl.glEnableClientState(GL10.GL_NORMAL_ARRAY);
gl.glDrawElements(GL10.GL_TRIANGLES, numindices,GL10.GL_UNSIGNED_SHORT, indices);
if(textureID>=0){
// Disable buffers
gl.glDisableClientState(GL10.GL_NORMAL_ARRAY);
gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
}
}
I'd really appreciate any help with this. It is frustrating to be not-quite able to load up the model from file and I'm really not sure what I'm doing wrong or missing here
I have to admit to being a little confused by the framing of your code. Specific things I would expect to be an issue:
you decline to copy a texture coordinate to the final mesh list for the third vertex associated with any face; this should put all of your coordinates out of sync after the first two
your texture coordinate normalisation step is unnecessary — to the extent that I'm not sure why it's in there — and probably broken (what if xcoord is larger than ycoord on the first line, then smaller on the second?)
OBJ considers (0, 0) to be the top left of a texture, OpenGL considers it to be the bottom left, so unless you've set the texture matrix stack to invert texture coordinates in code not shown, you need to invert them yourself, e.g. textureCoordinatesMesh.add(1.0 - ycoord);
Besides that, generic OBJ comments that I'm sure you're already well aware of and don't relate to the problem here are that you should expect to handle files that don't supply normals and files that don't supply either normals or texture coordinates (you currently assume both are present), and OBJ can hold faces with an arbitrary number of vertices, not just triangles. But they're always planar and convex, so you can just draw them as a fan or break them into triangles as though they were a fan.

Do OpenGL Point Sprites work in Android?

I'm developing on a Droid, version 2.1-update1. My supported GL extensions include GL_OES_point_sprite and GL_OES_point_size_array.
I am unable to get point sprites to render. The code below throws UnsupportedOperationException from GLWrapperBase at the glTexEnvi call. If I disable textures and comment out the glTexEnvi all, it throws the same exception further down, at glPointSizePointerOES().
Are point sprites properly supported in Android? Has anyone gotten them working? Or is there an issue with my code below?
// Note that gl is cast to GL11
gl.glEnable(GL11.GL_TEXTURE_2D);
gl.glEnable(GL11.GL_BLEND);
gl.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
gl.glDepthMask(false);
gl.glEnable(GL11.GL_POINT_SPRITE_OES);
gl.glTexEnvi( GL11.GL_POINT_SPRITE_OES, GL11.GL_COORD_REPLACE_OES, GL11.GL_TRUE );
gl.glEnableClientState(GL11.GL_VERTEX_ARRAY);
gl.glVertexPointer(2, GL11.GL_SHORT, 0, .vertBuffer);
gl.glEnableClientState(GL11.GL_POINT_SIZE_ARRAY_OES);
gl.glPointSizePointerOES(GL11.GL_FLOAT, 0, pointSizeBuffer);
Thanks
I got this working, here is my draw function
Initialize everything
gl.glEnable(GL10.GL_TEXTURE);
TextureManager.activateTexture(gl, R.drawable.water1); //Don't look for this, it's not public api, just looks upd texture id for android resource if loaded, and then activates it. it's the gl.glBindTexture() call replacement
gl.glEnable(GL11.GL_POINT_SPRITE_OES);
gl.glEnableClientState(GL11.GL_POINT_SIZE_ARRAY_BUFFER_BINDING_OES);
gl.glEnableClientState(GL11.GL_POINT_SIZE_ARRAY_OES);
gl.glEnableClientState(GL11.GL_POINT_SPRITE_OES);
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
Set the texture environment up to use point sprites
gl.glTexEnvf(GL11.GL_POINT_SPRITE_OES, GL11.GL_COORD_REPLACE_OES, GL11.GL_TRUE);
Set up pointers to the data (First array is 2d laid out [x,y,x2,y2,...] second is 1d [s1,s2,..])
gl.glVertexPointer(2,GL11.GL_FLOAT,0,PosData);
((GL11)(gl)).glPointSizePointerOES(GL10.GL_FLOAT, 0, SizeData);
Draw
gl.glDrawArrays(GL10.GL_POINTS,0,MAX);
Disable stuff
gl.glDisableClientState(GL11.GL_VERTEX_ARRAY);
gl.glDisableClientState(GL11.GL_POINT_SIZE_ARRAY_OES);
gl.glDisableClientState(GL11.GL_POINT_SIZE_ARRAY_BUFFER_BINDING_OES);
gl.glDisableClientState(GL11.GL_POINT_SIZE_ARRAY_OES);
gl.glDisable(GL10.GL_TEXTURE);
In my initializer I only have my projection setup and GL_BLEND enabled for blending. I think you would need GL_COLOR_MATERIAL if you wanted to color your sprite.
I got the point sprites working with ES 1.1 & 2 on a nexus one. I use a fixed point size so I didn´t have to use a size buffer but you can use my code to first get it working and then add the size buffer.
In my draw method:
gl.glEnable(GL11.GL_POINT_SPRITE_OES);
gl.glTexEnvf(GL11.GL_POINT_SPRITE_OES, GL11.GL_COORD_REPLACE_OES, GL11.GL_TRUE);
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
// 2 dimensional array, (x1,y1, x2, y2, ...).
gl.glVertexPointer(2, GL10.GL_FLOAT, 0, mVerticesBuffer);
gl.glEnable(GL10.GL_TEXTURE_2D);
gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
gl.glBindTexture(GL10.GL_TEXTURE_2D, mTextureId);
gl.glPointSize(32); // Fixed point size for all points
// This only worked with GLES11 & GLES20.
GLES11.glDrawArrays(GLES11.GL_POINTS, 0, vertices.length);
gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
gl.glDisable(GL10.GL_TEXTURE_2D);
gl.glDisable(GL11.GL_POINT_SPRITE_OES);
if like me you're using MatrixTrackingGL you need to use glTexEnvf rather than glTexEnvi (f not i at the end) and you need to go into MatrixTrackingGL and change glPointSizePointerOES:
public void glPointSizePointerOES(int type, int stride, Buffer pointer) {
mgl11.glPointSizePointerOES(type, stride, pointer);
//throw new UnsupportedOperationException();
}
I'm sure there is a good reason why it is unsupported in the first place but I don't know it and it works for me on a ZTE Blade running android 2.1
For anyone wondering, MatrixTrackerGL comes from C:\Program Files\android-sdk-windows\samples\android-7\ApiDemos\src\com\example\android\apis\graphics\spritetext
It is used when setting up your GLSurface View:
// GraphicsRenderer is my implementation of Renderer
Graphics Renderer graphicsRenderer = new GraphicsRenderer(this);
GLSurfaceView mGLView = (GLSurfaceView) findViewById(R.id.graphics_glsurfaceview1);
mGLView.setGLWrapper(new GLSurfaceView.GLWrapper() {
public GL wrap(GL gl) {
return new MatrixTrackingGL(gl);
}});
mGLView.setEGLConfigChooser(true);
mGLView.setRenderer(graphicsRenderer);
and means you can use GLU.gluUnProject to do picking!:
MatrixGrabber matrixGrabber = new MatrixGrabber();
matrixGrabber.getCurrentModelView(gl);
matrixGrabber.getCurrentProjection(gl);
float[] vector = new float[4];
GLU.gluUnProject(x, y, 0f, matrixGrabber.mModelView, 0, matrixGrabber.mProjection, 0, new int[]{mGLView .getTop(),mGLView .getLeft(),mGLView .getWidth(),mGLView .getHeight()}, 0, vector, 0);

Android Opengl ES tiling engine, smooth scrolling

Following this : Best approach for oldschool 2D zelda-like game
I got a simple 2D tiles generator working, im reading an int map[100][100] filled with either 1's or 0's and draw tiles according to their tile id, 0 is water, 1 grass.
Im using some basic Numpad control handler, using a camIncr (32.0f), i set the camera position according to the movement :
case KeyEvent.KEYCODE_DPAD_RIGHT:
cameraPosX = (float)(cameraPosX + camIncr);
break;
In my draw loop, im just drawing enough tiles to fit on my screen, and track the top left tile using cameraOffsetX and cameraOffsetY (its the camera position / tile size )
Im using a GLU.gluOrtho2D for my projection.
Here is the draw loop inside my custom renderer :
gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
gl.glMatrixMode( GL10.GL_PROJECTION );
gl.glLoadIdentity( );
GLU.gluOrtho2D(gl, 0, scrWidth, scrHeight, 0);
repere.draw(gl, 100.0f); // this is just a helper, draw 2 lines at the origin
//Call the drawing methods
gl.glMatrixMode(GL10.GL_MODELVIEW);
gl.glLoadIdentity();
tiledBackground.draw(gl, filtering);
my tiledBackground draw function :
int cols = (569 / 32) + 2; // how many columns can fit on the screen
int rows = (320 / 32) + 1; // haw many rows can fit on the screen
int cameraPosX = (int) Open2DRenderer.getCameraPosX();
int cameraPosY = (int) Open2DRenderer.getCameraPosY();
tileOffsetX = (int) (cameraPosX / 32);
tileOffsetY = (int) (cameraPosY / -32);
gl.glPushMatrix();
for (int y = 0; y < rows; y++) {
for (int x = 0; x < cols; x++) {
try {
tile = map[y + tileOffsetY][x + tileOffsetX];
} catch (Exception e) {
e.printStackTrace(); //when out of array
tile = 0;
}
gl.glPushMatrix();
if (tile==0){
waterTile.draw(gl, filter);
}
if (tile==4) {
grassTile.draw(gl, filter);
}
gl.glTranslatef(32.0f, 0.0f, 0.0f);
}//
gl.glPopMatrix();
gl.glTranslatef(0.0f, 32.0f, 0.0f);
}
gl.glPopMatrix();
}
the waterTile and grassTile .draw function draw a 32x32 textured tile, might post the code if relevant.
Everything is fine, i can move using numpad arrows, and my map 'moves' with me, since im only drawing what i can see, its fast (see android OpenGL ES simple Tile generator performance problem where Aleks pointed me to a simple 'culling' idea)
I would like my engine to 'smooth scroll' now. I've tried tweaking the camIncr variable, the GLU.gluOrtho2D etc, nothing worked.
Any ideas ? :)
I finally found out.
i added a glTranslatef method right before entering the loop :
gl.glPushMatrix();
gl.glTranslatef(-cameraPosX%32, -cameraPosY%32, 0);
for (int y = 0; y < rows; y++) {
...
First, i was unsuccessfully trying to translate the scene using a brute cameraPosX / TILE_HEIGHT division, didn't work.
We have to translate the offset by which the tile extends beyond the screen, not the total cameraPosX offset, so we're using the Mod (%) operator instead of division.
Sorry for my bad english ^^

Categories

Resources