B4A Library [Class] - OpenGL ES - 2D Image library

V1.5
Added: SetSkew() - To skew to image
Added: Reset() - Resets general image parameters (skew, position, rotation, handle, animation, flipped state)


I have put together a library designed for the purpose of displaying 2D images using OpenGL ES. The library needs Andrew Graham's libraries:

OpenGL ES library.
Reflection Library

Also, if you want to employ error checking you will also need Andrew's Threading library.

OpenGLES_2DLib.png
OpenGLLib_4.png


VIDEO: Jelly Beans


Key Features for the 2D Images
=======================================
* Pixel-Perfect image drawing (with unfiltered or filtered render options)
* Resize, rotate, flip, skew, change colour, alpha, blending modes, cropped areas - All faster than stock bitmap/canvas drawing
* Collision checks (only basic box-box checks)
* Anchor points - Each image has its own anchor hotspot (called handle in the library) so that the image can be rotated/flipped around a particular point
* An image can share the texture from an existing image (to save space and improve memory performance)
* Images don't need to be a power of 2 since the library will re-size them if required.
* Animation - Images can be animated easily by setting 'frames'. Image strips as well as image grids are supported
* Set specific areas of the image to draw

Key Features for the Display
=======================================
* Virtual display setup makes it easy to create a common display which scales to the devices physical screen size
* Global positioning (anchor/handle), scaling, and rotation which impacts all images.
* GL surface view can be made transparent so that GL images appear on top of regular views.

Have a play with the examples to see how the basic implementation works.
Hopefully the commands make sense.

OpenGL ES 2D Image Library v1.5 - Download link -- Select File then Download
NOTE: Demos should be run in Release Mode

V1.1
Added: Transparency for GL surface view. New subs = SetClsAlpha(), SetClsColor()
Changed: ClearScreen() to Cls()
V1.2
Added: Virtual display commands/functions
Added: SetRect() for images
V1.3
Added: GetLeft(), GetRight(), GetTop(), GetBottom(), AtPoint()
Added: More demos
V1.4a Minor change: Removed glBlendEquation
V1.4
Added: SetBlend - To change the rendering appearance of images (Alpha, Light,Dark,Mask)
Added: Jelly Beans demo
Changed: The way images are loaded. Instead of checking for surface changes every time Draw() is called, a dedicated (one-shot) LoadImages() sub is called instead.
 
Last edited:

Jim Brown

Active Member
Licensed User
Longtime User
Thanks for the information Andrew.

@Informatix,
I am pretty stumped as to why performance is slower. Could it be because I am using OpenGL ES rather than OpenGL 2?
My Draw method per image boils down to:
B4X:
   gl.glEnableClientState(gl.GL_VERTEX_ARRAY)
   gl.glEnableClientState(gl.GL_COLOR_ARRAY)
   gl.glVertexPointerf(2,verts)
   gl.glColorPointerf(4,0,cols)
   If tex(0)>0 Then
      gl.glEnable(gl.GL_TEXTURE_2D) : gl.glEnable(gl.GL_BLEND)
      gl.glBlendFunc(BlendSRC,BlendDST)
      gl.glEnableClientState(gl.GL_TEXTURE_COORD_ARRAY)
      gl.glBindTexture(gl.GL_TEXTURE_2D,tex(0))
      gl.glTexCoordPointerf(2,0,uvs)
   End If
   gl.glPushMatrix
     gl.glTranslatef(X+0.375,Y+0.375,0) ' trick for exact pixelization
     gl.glRotatef(Angle,0,0,1)
     gl.glScalef(FlippedX,FlippedY,1)
     gl.glDrawArrays(gl.GL_TRIANGLE_STRIP,0,4)
   gl.glPopMatrix
   gl.glDisableClientState(gl.GL_VERTEX_ARRAY)
   gl.glDisableClientState(gl.GL_TEXTURE_COORD_ARRAY)
   gl.glDisableClientState(gl.GL_COLOR_ARRAY)
 

Informatix

Expert
Licensed User
Longtime User
With the VBO extension, OpenGL 1.1 gets very good results in (Java) tests. So it's not tied to the version. (And OpenGL 2 is also OpenGL ES; ES means "for embedded system")

Next week, I'll convert a Java program to B4A. I'll compare the performance at each step. We'll see if the problem comes from the OpenGL library or from the class.
 

Informatix

Expert
Licensed User
Longtime User
With the VBO extension, OpenGL 1.1 gets very good results in (Java) tests. So it's not tied to the version. (And OpenGL 2 is also OpenGL ES; ES means "for embedded system")

Next week, I'll convert a Java program to B4A. I'll compare the performance at each step. We'll see if the problem comes from the OpenGL library or from the class.

I did the first test: calling an empty Renderer in B4A and in Java. I log the elapsed time between each call. Code in Java:
B4X:
final GLSurfaceView glsv = new GLSurfaceView(this);
glsv.setEGLConfigChooser(true);
glsv.setRenderer(new myRenderer());
glsv.setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
For the renderer:
B4X:
@Override
public void onDrawFrame(GL10 gl) {
   currTimeD = System.currentTimeMillis();
   if (prevTimeD == 0) {
      Log.d("B4A", "DRAW " + currTimeD);
   } else {
      Log.d("B4A", "DRAW " + currTimeD + " " + (currTimeD - prevTimeD));
   }
   prevTimeD = currTimeD;
}
For the timer:
B4X:
t = new Timer();
t.scheduleAtFixedRate(new TimerTask() {
   @Override
   public void run() {
      currTimeT = System.currentTimeMillis();
      if (prevTimeT == 0) {
         Log.d("B4A", "TICK " + currTimeT);
      } else {
         Log.d("B4A", "TICK " + currTimeT + " " + (currTimeT - prevTimeT));
      }
      prevTimeT = currTimeT;
      glsv.requestRender();
   }
}, 0, 16);

I get exactly the same result in Java and in B4A. With a timer set to 16ms, I get regular calls with GLSurfaceView.RENDERMODE_WHEN_DIRTY.
 

agraham

Expert
Licensed User
Longtime User
Good to know! Most methods in the library merely wrap the OpenGL function directly to expose it to B4A code so the overhead is just marshalling the arguments and doing a single additional function call. The only real overhead in the library is for those OpenGL calls that take a Buffer argument where the B4A exposure takes an array, for example glColorPointer.
B4X:
//public void glColorPointer(int size, int type, int stride, Buffer pointer) 
   public void glColorPointerf(int size, int stride, float[] colors)
   {
      ByteBuffer pbb = ByteBuffer.allocateDirect(colors.length * 4);
      pbb.order(ByteOrder.nativeOrder());
      FloatBuffer cfb = pbb.asFloatBuffer();
      cfb.put(colors);
      cfb.position(0);
      gl.glColorPointer(size, GL10.GL_FLOAT, stride, cfb);
   }
Perhaps your tests should try to check how much degradation the additional Buffer manipulation is causing.
 

Informatix

Expert
Licensed User
Longtime User
I stressed the above code with a stupid loop:
B4X:
int j = 0;
for(int i = 1; i <= 500000; i++)
   j = j + 1;
Log.d("B4A", "  LOOP " + (System.currentTimeMillis() - currTimeT) + " " + j);

Results: I have quite regular calls in Java and in B4A. But there's a big difference between the two results: the Java code is 3,5 times faster ! The conversion of the loop from B4A to Java seems to be the culprit.

Example of Log (Java):
TICK 1364128107252 16
LOOP 4 500000
DRAW 1364128107257 16
LOOP 5 500000
TICK 1364128107268 16
LOOP 4 500000
DRAW 1364128107272 15
LOOP 7 500000
TICK 1364128107284 16
LOOP 5 500000
DRAW 1364128107290 18
LOOP 5 500000
TICK 1364128107300 16
LOOP 4 500000
DRAW 1364128107304 14
LOOP 7 500000
TICK 1364128107317 17
LOOP 4 500000
DRAW 1364128107322 18
LOOP 6 500000
TICK 1364128107332 15
LOOP 4 500000
DRAW 1364128107336 14
LOOP 8 500000
TICK 1364128107348 16
LOOP 5 500000
DRAW 1364128107353 17
LOOP 7 500000
TICK 1364128107364 16
LOOP 5 500000
DRAW 1364128107370 17
LOOP 5 500000
Example of Log (B4A):
TICK 1364128277211 55
LOOP 48 500000
DRAW 1364128277224 49
LOOP 57 500000
TICK 1364128277269 58
LOOP 54 500000
DRAW 1364128277279 55
LOOP 37 500000
TICK 1364128277306 37
LOOP 56 500000
DRAW 1364128277335 56
LOOP 65 500000
TICK 1364128277371 65
LOOP 48 500000
DRAW 1364128277384 49
LOOP 58 500000
TICK 1364128277429 58
LOOP 55 500000
DRAW 1364128277439 55
LOOP 48 500000
TICK 1364128277477 48
LOOP 56 500000
DRAW 1364128277495 56
LOOP 48 500000
TICK 1364128277525 48
LOOP 56 500000
DRAW 1364128277552 57
LOOP 56 500000
TICK 1364128277581 56
LOOP 56 500000
DRAW 1364128277608 56
LOOP 57 500000
TICK 1364128277638 57
LOOP 46 500000
DRAW 1364128277654 46
LOOP 48 500000
TICK 1364128277686 48
LOOP 59 500000
DRAW 1364128277713 59
LOOP 56 500000
TICK 1364128277743 57
LOOP 56 500000
DRAW 1364128277770 57
LOOP 65 500000

EDIT: I copied the converted code in my Java test app and I have the same result as in B4A. This confirms that the loop conversion is inefficient and needs to be improved (the difference is too huge).

EDIT2: The loop in B4A uses double types and converts all results back to int. Simply horrible from a performance point of view. I don't understand why it is converted like this.
 
Last edited:

pons

New Member
Hi agraham, thank you for replying. Do you mean this link for the openg gl 2d library: that is in the 1st page of this thread? For me appears that the file have been moved to the recycle bin.
 
Last edited:
Top