Using glOrtho with 2d sprite animation

Problems with Canvas, OpenGL, etc...

Using glOrtho with 2d sprite animation

Postby p4r4digm » Thu Apr 14, 2011 7:58 pm

Greetings. I've dabbled in OpenGL in the past and as far as I understood it the best way to do 2d games with sprite-based animation was eliminate the z plane and set up an orthographic projection so you can just use Cartesian coordinates for textures and drawing positions.

So I've been trying to implement this in android. I was just using all the build in draw functions but rendering a few hundred images separately with the vanilla drawbitmap functions was killing my framerate.

A rect shows up on the screen all right but the texture refuses to show. if you could take a look and let me know where I'm going wrong here I'd really appreciate it. Be warned I don;t have nearly as comprehensive understanding of opengl as I would like. I respect anyone that can wrap their heads around this stuff.

This is the sprite class which draws the rect with the bound texture:
Code: Select all
public class Sprite {
   
   private FloatBuffer vertexBuffer;   // buffer holding the vertices
   private FloatBuffer textureBuffer;
   private int[] textures = new int[1];
   
   
   private float vertices[] = {
          0.0f,  0.0f,
          0.0f, 32.0f,
          32.0f,  0.0f,
          32.0f, 32.0f
         
   };
   
   private float texture[] = {
         0.0f,  0.0f,
          0.0f, 16.0f,
          16.0f,  0.0f,
          16.0f, 16.0f
         
   };
   
   public Sprite() {
      ByteBuffer byteBuffer = ByteBuffer.allocateDirect(vertices.length * 4);
      byteBuffer.order(ByteOrder.nativeOrder());
      vertexBuffer = byteBuffer.asFloatBuffer();
      vertexBuffer.put(vertices);
      vertexBuffer.position(0);
      
      byteBuffer = ByteBuffer.allocateDirect(texture.length * 4);
      byteBuffer.order(ByteOrder.nativeOrder());
      textureBuffer = byteBuffer.asFloatBuffer();
      textureBuffer.put(texture);
      textureBuffer.position(0);
      
   }
   
   public void loadGLTexture(GL10 gl, Context context)
   {
      Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(),
            R.drawable.charactersprites);
      
      gl.glGenTextures(1, textures, 0);
      gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[0]);

      //Not sure if I need these...
      //gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_NEAREST);
      //gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);
      
      GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap, 0);
      bitmap.recycle();

   }
   
   /** The draw method for the triangle with the GL context */
   public void draw(GL10 gl) {
      gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[0]);

      
      gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
      gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);

      //gl.glFrontFace(GL10.GL_CW);//is this necessary?
      
      // set the colour for the triangle
      //gl.glColor4f(0.0f, 1.0f, 0.0f, 0.5f);
      
      // Point to our vertex buffer
      gl.glVertexPointer(2, GL10.GL_FLOAT, 0, vertexBuffer);
      gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, textureBuffer);


      // Draw the vertices as triangle strip
      gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, vertices.length / 2);
      
      //Disable the client state before leaving
      gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
      gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);

   }
}



And this is the renderer...i pass in the srfaceview to hold onto so i can get the height and width for the projection
Code: Select all
public class GlRenderer implements Renderer {

   private Sprite sprite;
   private GLSurfaceView surfaceView;
   private Context context;
   
   /** Constructor to set the handed over context */
   public GlRenderer(GLSurfaceView surfaceView, Context context) {
      this.sprite = new Sprite();
      this.surfaceView = surfaceView;
      this.context = context;
   }

   @Override
   public void onDrawFrame(GL10 gl) {
      // clear Screen and Depth Buffer
      gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
      gl.glMatrixMode(GL10.GL_PROJECTION);
      
      // Reset the Modelview Matrix
      gl.glLoadIdentity();
      gl.glOrthof(0.0f, surfaceView.getWidth(), surfaceView.getHeight(), 0.0f, -1.0f, 1.0f);

      sprite.draw(gl);   

   }

   @Override
   public void onSurfaceCreated(GL10 gl, EGLConfig config) {
      sprite.loadGLTexture(gl, this.context);
      
      gl.glEnable(GL10.GL_TEXTURE_2D);
      gl.glShadeModel(GL10.GL_SMOOTH);
      gl.glClearColor(0.0f, 0.0f, 0.0f, 0.5f);
      gl.glClearDepthf(1.0f);
      gl.glEnable(GL10.GL_DEPTH_TEST);
      gl.glDepthFunc(GL10.GL_LEQUAL);
      
      gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_NICEST);

      
   }

}
p4r4digm
Freshman
Freshman
 
Posts: 4
Joined: Thu Apr 14, 2011 7:50 pm

Top

Re: Using glOrtho with 2d sprite animation

Postby ssj3gogeta » Fri Apr 15, 2011 6:43 am

Hi,
I took a quick look at your code and have a couple ideas:

-You have a comment in the loadGLTexture() function of your sprite class that says "Not sure if I need these..."
I think you do because the default parameter for GL_TEXTURE_MIN_FILTER is GL_NEAREST_MIPMAP_LINEAR which means you need to load all the texture mips to make it work. Try setting it to GL_NEAREST instead.

-The texture coordinates go from 0.0f to 16.0f
This is less important, but texture coordinates map from 0.0f to 1.0f. Depending on the wrapping mode and texture matrix, this can have undesired results.

Also as an extra...

-In the draw() function of the sprite class at glFrontFace "is this necessary?"
It's only useful if you want to cull backfaces using glEnable(GL_CULL_FACE)

Other than that, maybe you can post a screenshot, check the logcat to see if the texture was loaded correctly, or turn on glError checking. Hope this helps!
ssj3gogeta
Freshman
Freshman
 
Posts: 4
Joined: Tue Feb 01, 2011 4:49 am

Re: Using glOrtho with 2d sprite animation

Postby p4r4digm » Fri Apr 15, 2011 7:22 pm

Thank you for the advice!
After struggling with the damn thing all day yesterday I found a few problems:

First off, my damn textures were in the wrong resource folder since apparently froyo doesnt read textures from the mdpi folder (finding this out was pretty damn debilitating)

More importantly, as you stated, the texture coords were off because even using an ortho projection, the coords are still 0-1.0 (i figured if using ortho you could use normal cartesian coords like you do on the drawing matrix)

Also, I did end up needing those filter lines which determine how the texture is displayed, main thing there was switching from LINEAR to NEAREST (as you stated) which amde the textures not so blurry (im working with small spritebased textures)

So now I have everything displaying correctly. the huge problem im running into now is some optimization issues I need to deal with but then the fact that my update() function for game logic is in a seperate thread and so drawing sometimes takes place during the middle of an update and catches objects before they are finished moving resulting in a jumbled puzzle sort of effect.

My ideas for resolving this is setting the rendermode to "update on dirty" or whatever it is and then manually calling requestrender after update in the update thread to ensure it's only drawn after everything has been updated...I'm not very familiar with working with threads other than understanding the basics of how they work. Would you ahve any suggestions on how to resolve this?
p4r4digm
Freshman
Freshman
 
Posts: 4
Joined: Thu Apr 14, 2011 7:50 pm

Re: Using glOrtho with 2d sprite animation

Postby ssj3gogeta » Sat Apr 16, 2011 1:37 am

Ah I see. Setting the render mode to "update on dirty" sounds like it would work. If it's applicable, you could also try sticking the update() function as the first line of onDrawFrame() in your renderer class so that the update happens on the same thread before the draw calls happen.

Another (more difficult) way is to try and synchronize the update and draw calls so that they don't affect the sprites at the same time. You'll need to look into Thread synchronization to make this happen.
ssj3gogeta
Freshman
Freshman
 
Posts: 4
Joined: Tue Feb 01, 2011 4:49 am

Re: Using glOrtho with 2d sprite animation

Postby p4r4digm » Sat Apr 16, 2011 1:52 am

yeah the update on dirty plan didn't affect it as I had hoped. But you were right, moving update to the draw function did the trick, but then i imagine its going to be somewhat difficult to regulate the framerate. Ill look into synchronizing the threads.
p4r4digm
Freshman
Freshman
 
Posts: 4
Joined: Thu Apr 14, 2011 7:50 pm

Re: Using glOrtho with 2d sprite animation

Postby p4r4digm » Sat Apr 16, 2011 10:40 pm

After much frustration I finally got a system together that syncs up the frames nicely.

I created a drawlock class that both threads can lock, unlock, and check against so that they sync up.
Code: Select all
public class DrawLock
{
   private boolean locked;
   
   public synchronized void lock()
   {
      locked = true;
      notifyAll();
   }
   
   public synchronized void unlock()
   {
      locked = false;
      notifyAll();
   }
   
   public synchronized void checkLock()
   {
      while(locked)
      {
         try {
            wait();
         } catch (Exception e) {
            // TODO: handle exception
         }
      }
   }

}


Then basically in the render and update threads, you check the lock to wait until the other thread has unlocked it, then lock it, do your work, and unlock afterward.
p4r4digm
Freshman
Freshman
 
Posts: 4
Joined: Thu Apr 14, 2011 7:50 pm

Top

Return to Android 2D/3D Graphics - OpenGL Problems

Who is online

Users browsing this forum: No registered users and 2 guests