B4A Library OpenGL library

Here is a first stab at implementing an OpenGL library. The implementation is a subset of the full Android API but the actual functionality is pretty complete (I think!) as the omitted functions are mainly those that used scaled integer working, I have only implemented the equivalents that use floats.

However it is almost totally untested. I have got it to the point where it can draw a triangle on the screen but my total ignorance of OpenGL makes further progress challenging and I'm not really interested in doing graphics. As it can now draw on-screen most of the further functionality should be OK as it is a very thin wrapper of the OpenGL API. The hard part of integrating the GLSurfaceView with Basic4android and drawing on it is done.

The reason for posting it therefore is to see if there is any interest in it before I waste more time on it, and to see if there is an OpenGL expert out there who would collaborate on testing and debugging it - assuming anyone wants to use it at all!

As an aside I believe that the GLSurfaceView, being based on a standard View, can also be drawn on using the same methods as other Views as well as by the OpenGL renderer but I haven't tried that.

Note that the "demo" needs my Threading library.

EDIT :- Version 1.1 posted. See post #5 for details.

EDIT :- Version 1.2 posted. See post #10 for details.

EDIT :- Version 1.3 posted. See post #16 for details.

EDIT :- Version 1.4 posted. See post #21 for details.

EDIT :- Version 1.5 posted. See post #25 for details.

EDIT :- Version 1.6 posted. See post #35 for details.
EDIT :- Version 1.6 reposted with correct version number. See post #38 for details.

EDIT :- Version 1.7 posted. See post #39 for details.
 

Attachments

  • OpenGL1.7.zip
    51.3 KB · Views: 2,508
Last edited:

Steven Sparrow

Member
Licensed User
Longtime User
OpenGL Testing

We use openGL extensively in a number of projects and as we are migrating code to the Android and iPhone platforms, one of the biggest stumbling blocks was the lack of a 3D engine in basic4android.

We had already starting an openGL implementation of our own, but after seeing your past contributions to basic4andoid I'm sure your implementaiton is likely to be cleaner and more functional.

Will give it a try and get back to you with our findings.

Keep up the great work !
Steve
 

JogiDroid

Member
Licensed User
Longtime User
Wow, that's nice, one big feature/lib I have been missing in B4A... I have some experience with OpenGL and lot of intrest for 3d gfx so I'm going to test this feature soon... (week or so..)
Thanks!!!
 

agraham

Expert
Licensed User
Longtime User
Version 1.1 now posted has support for all the Android OpenGL Interfaces, namely GL10, GL10Ext, GL11, GL11Ext and GL11ExtensionPack. The constants and functions supported may be found in the Android documentation GL10 - Android SDK | Android Developers. Note the clickable list of Interfaces in the lower left panel.

Many functions have equivalents taking either an array or an Android native Buffer. As Basic4android doesn handle Buffers I have omitted those functions using them. However there are a few functions that exist that only accept a Buffer parameter, for example GL10.glVertexPointer. For those functions I have synthesised an alternative using a float array. Alternatives using int or other types of array are possible if required.

Some functions exist in two forms using the same name but different parameter lists. Basic4android does not suppport this so the figure "2" has been appended to the later version name to allow Basic4android to distinguish them. I think I've found them all but if a particular expected version is not visible that is probably the reason for it.

There may be stupid mistakes and typos but I am pretty sure we can overcome those as they arise and hopefully end up with a working OpenGL implementation for Basic4android.
 
Last edited:

gorelshv

Member
Licensed User
Longtime User
hey Andrew, could you post a sample code? just something basic like making a cube and putting a texture on it. thanks.
 

agraham

Expert
Licensed User
Longtime User
could you post a sample code?
No. I'm a Systems Engineer, not a graphics programmer and I know nothing about actually using OpenGL for graphics work. That is why I asked for collaboration to test the library. I knew some people wanted OpenGL so I have done the work to expose it to Basic4android. I now need feedback and examples of failure from people who know what they are doing so that we can debug the library.
 

geocomputing

Member
Licensed User
Longtime User
Andrew,

In answer to your question of whether anyone wants a gl library I can personally say that I definitely do and I've got lots of uses for it. Having gl is something I've been hoping for and makes b4a an amazing product. Thank you very much for providing it, I'll post any bugs I find.

Many thanks,

Andrew.

:sign0060: :sign0098: :sign0060:
 

agraham

Expert
Licensed User
Longtime User
Hmm! I didn't think this library would grow like this :(

Version 1.2 now posted.

GL10 Object name changed to GL1 to reflect that it might support either OpenGL ES 1.0 or 1.1.

Various GL1.xxxPointer functions refined as I now better appreciate what they do.

Added Int as well as Float versions of many functions to improve the orthogonality of what's available. This may need revisiting when someone who really knows what they are doing plays with this library.

Added Matrix and Visibility support objects.

Added GLSurfaceView.RunOnGuiThread so that rendering code can run stuff on the GUI thread.

Improved the demo, not in the graphics but in the structure to show error handling on the rendering thread which would otherwise force close the application as exceptions not on the main thread are not trapped and reported by Basic4android.
 
Last edited:

geocomputing

Member
Licensed User
Longtime User
Andrew,

I think I've found a little bug. I adapted your demo to make a rotating 3d cube. On a wildfire it works properly, but on a galaxy tab it doesn't clear the view each time it redraws (i.e. each update it doesn't remove the previous triangle drawings). Also, it doesn't seem to properly sort triangles by depth, but that may just need me to add another flag. I've put my code below in case it helps.

Best wishes,

Andrew.

'Activity module
Sub Process_Globals
'These global variables will be declared once when the application starts.
'These variables can be accessed from all modules.
Dim Timer1 As Timer
End Sub

Sub Globals
'These global variables will be redeclared each time the activity is created.
'These variables can only be accessed from this module.
Dim glsv As GLSurfaceView
Dim eyex,eyey,eyez,eyeradius,eyeangle As Float
eyex=0
eyey=0
eyez=0
eyeradius=5
eyeangle=3.14159
End Sub

Sub Timer1_Tick
eyeangle=eyeangle+0.1
If eyeangle>(2*3.14159) Then eyeangle=eyeangle-(2*3.14159)
glsv.RequestRender
End Sub

Sub Activity_Create(FirstTime As Boolean)
glsv.Initialize(glsv.RENDERMODE_WHEN_DIRTY, "glsv")
Activity.AddView(glsv,0,0,Activity.Width,Activity.Height)
End Sub

Sub Activity_Resume
'glsv.DebugFlags = glsv.DEBUG_CHECK_GL_ERROR + glsv.DEBUG_LOG_GL_CALLS ' Can set debug flags here if required
glsv.Resume ' Must call GLSurfaceView.Resume to restart the rendering thread
Timer1.Initialize("Timer1", 100)
Timer1.Enabled = True
End Sub

Sub Activity_Pause (UserClosed As Boolean)
glsv.Pause ' Must call GLSurfaceView.Pause to halt the rendering thread
Timer1.Enabled = False
End Sub



' The GLSurfaceView events run on a separate thread to the main thread.
' They therefore must not try to manipulate GUI elements.
' The OpenGL library does not allow the debugger to halt at code within these event Subs.

Sub glsv_Draw(gl As GL10)
'The view wants to be drawn using the suppllied GL10
gl.glDisable(gl.GL_DITHER)
gl.glClear(gl.GL_COLOR_BUFFER_BIT + gl.GL_DEPTH_BITS)
gl.glMatrixMode(gl.GL_MODELVIEW)
gl.glLoadIdentity
eyex=eyeradius*Sin(eyeangle)
eyez=eyeradius*Cos(eyeangle)
gl.gluLookAt(eyex,eyey,eyez, 0,0,0, 0,1,0)
gl.glEnableClientState(gl.GL_VERTEX_ARRAY)
Dim coords(0) As Float
coords = Array As Float(-0.5,1,-1, 0.5,1,-1, 0.5,-1,-1, -0.5,-1,-1, -0.5,1,1, 0.5,1,1, 0.5,-1,1, -0.5,-1,1)
Dim indeces(0) As Short
indeces = Array As Short(0,1,2, 2,3,0, 4,5,6, 6,7,4, 4,5,1, 1,0,4, 7,6,2, 2,3,7)
gl.glColor4f(1, 0, 0, 1)
gl.glVertexPointer(3, coords)
gl.glDrawElements(gl.GL_TRIANGLES, 24, indeces)
indeces = Array As Short(5,1,6, 1,2,6)
gl.glColor4f(0, 0, 1, 1)
' gl.glVertexPointer(3, coords)
gl.glDrawElements(gl.GL_TRIANGLES, 6, indeces)
End Sub

Sub glsv_SurfaceChanged(gl As GL10, width As Int, height As Int)
'Called when the surface has changed size.
gl.glViewport(0, 0, width, height)
gl.glMatrixMode(gl.GL_PROJECTION)
Dim ratio As Float
ratio = width/height
gl.glFrustumf(-ratio, ratio, -1, 1, 3, 7)
End Sub

Sub glsv_SurfaceCreated(gl As GL10)
'Called when the surface is created or recreated.
gl.glDisable(gl.GL_DITHER)
gl.glHint(gl.GL_PERSPECTIVE_CORRECTION_HINT, gl.GL_FASTEST)
gl.glShadeModel(gl.GL_SMOOTH)
gl.glEnable(gl.GL_DEPTH_TEST)
gl.glClearColor(0.5, 0.5, 0.5, 1)
End Sub
 

agraham

Expert
Licensed User
Longtime User
On my ZTE Blade it works fine except that two of the faces seem transparent which I presume is the depth problem you allude to.

However my Motorola Xoom also does not clear the old view each time. Checking gl.gluErrorString(gl.glGetError) there is an "invalid value" error on the Xoom after

gl.glClear(gl.GL_COLOR_BUFFER_BIT + gl.GL_DEPTH_BITS)

replacing it with

gl.glClear(gl.GL_COLOR_BUFFER_BIT)

and it works fine - except for the depth problem which I don't think can be down to the library as most of the method calls are a direct exposure of the API call with no intermediate processing.

Note that calling GL1.glGetError resets the error value to "no error" so the call return may need to be assigned immediately if wanted for further use.
 

geocomputing

Member
Licensed User
Longtime User
Hi Andrew,

Many thanks for that, it now works on my galaxy tab properly. Not clearing the depth buffer can lead to some strange antics so I did it this way instead:

gl.glClear(gl.GL_COLOR_BUFFER_BIT)
gl.glClear(gl.GL_DEPTH_BUFFER_BIT)

I'm a bit worried by what you say, as I made four red sides so the 3D effect was more obvious with simple lighting. However, I also added a blue back face and from what you say you didn't see it on your device. In fact it's the back face which shows the depth sorting problem, and I think it may be due to the two calls to glDrawElements.

I had a look and I couldn't see any immediately obvious reasons why the depth order is wrong. I even set the depth mode to GL_LEQUAL just in case, which didn't help. I'll try to find time to play/read a bit more to find out what's the matter.

By the way, this is a brilliant B4A library, so thank you very much indeed :)

Best wishes,

Andrew.
 

derez

Expert
Licensed User
Longtime User
Andrew, have mercy !
I have read already 40 pages of the 453 page openGL tutorial .....

Thank you for that library :sign0060:
 

agraham

Expert
Licensed User
Longtime User
However, I also added a blue back face and from what you say you didn't see it on your device.
Yes, I can see the blue back face, it looks the same on both the devices that I have tried it on. It is the red front face and the edge face coming towards you that seem invisible.

Tomorrow I'll look at improving the error handling. I've an idea that might make finding the line where an error occurs a bit easier.
 

agraham

Expert
Licensed User
Longtime User
Version 1.3 has a minor internal change to the library not visible externally. The demo has improved error reporting using the ExceptionEx object from my Threading library.

Placing glsv.DebugFlags = glsv.DEBUG_CHECK_GL_ERROR in Activity_Resume causes an exception as soon as an error occurs and the exception handler will show the line number in the Java source where the problem arose. You can then check the source in a line numbering editor, like Programmers Notepad or Notepad++, to find the actual method.

If you look carefully at posts 12 and 13 you will see that I had, due to the perils of Intellisense, used gl.GL_DEPTH_BITS instead of gl.GL_DEPTH_BUFFER_BIT which was the reason for the problem. You corrected it without noticing.

Both
gl.glClear(gl.GL_COLOR_BUFFER_BIT + gl.GL_DEPTH_BUFFER_BIT)
and
gl.glClear( Bit.Or(gl.GL_COLOR_BUFFER_BIT, gl.GL_DEPTH_BUFFER_BIT))
do in fact work OK
 

geocomputing

Member
Licensed User
Longtime User
Hi,

I've been playing more (now using v1.3 of your library). The triangles aren't disappearing, they're just being drawn over by triangles behind. I didn't want to make the mistake of thinking I knew what I was doing, especially as I wasn't setting specific surface normals, so I've taken an example from the Hello Android book by Ed Burnette, and translated it into B4A. It's a spinning cube and I know it should work as I've tried it in Eclipse and it worked perfectly. However, on B4A it doesn't seem to be correctly z-buffering.

I've put the code below in case it helps, and maybe it's useful for anyone who needs a GL example.

Thanks,

Andrew.


<textarea cols="80" rows="30">

'Activity module
Sub Process_Globals
'These global variables will be declared once when the application starts.
'These variables can be accessed from all modules.
Dim Timer1 As Timer
End Sub

Sub Globals
'These global variables will be redeclared each time the activity is created.
'These variables can only be accessed from this module.
Dim glsv As GLSurfaceView
Dim eyeangle As Float
Dim coords(0) As Float
eyeangle=0
End Sub

Sub Timer1_Tick
eyeangle=eyeangle+0.1
If eyeangle>(2*3.14159) Then eyeangle=eyeangle-(2*3.14159)
glsv.RequestRender
End Sub

Sub Activity_Create(FirstTime As Boolean)
glsv.Initialize(glsv.RENDERMODE_WHEN_DIRTY, "glsv")
Activity.AddView(glsv,0,0,Activity.Width,Activity.Height)
End Sub

Sub Activity_Resume
glsv.Resume ' Must call GLSurfaceView.Resume to restart the rendering thread
Timer1.Initialize("Timer1", 100)
Timer1.Enabled = True
Dim half As Float
half=0.5
coords = Array As Float(-half,-half,half,half,-half,half,-half,half,half,half,half,half,-half,-half,-half,-half,half,-half,half,-half,-half,half,half,-half,-half,-half,half,-half,half,half,-half,-half,-half,-half,half,-half,half,-half,-half,half,half,-half,half,-half,half,half,half,half,-half,half,half,half,half,half,-half,half,-half,half,half,-half,-half,-half,half,-half,-half,-half,half,-half,half,half,-half,-half)
End Sub

Sub Activity_Pause (UserClosed As Boolean)
glsv.Pause ' Must call GLSurfaceView.Pause to halt the rendering thread
Timer1.Enabled = False
End Sub

Sub glsv_Draw(gl As GL1)
gl.glClear(Bit.Or(gl.GL_COLOR_BUFFER_BIT, gl.GL_DEPTH_BUFFER_BIT))
gl.glMatrixMode(gl.GL_MODELVIEW)
gl.glLoadIdentity
gl.gluLookAt(0,0,5, 0,0,0, 0,1,0)
gl.glRotatef((eyeangle/(2*3.14159))*360,0,1,0)
gl.glRotatef((eyeangle/(2*3.14159))*360,1,0,0)
gl.glVertexPointerf(3, coords)
gl.glColor4f(1,1,1,1)
gl.glNormal3f(0,0,1)
gl.glDrawArrays(gl.GL_TRIANGLE_STRIP,0,4)
gl.glNormal3f(0,0,-1)
gl.glDrawArrays(gl.GL_TRIANGLE_STRIP,4,4)
gl.glNormal3f(-1,0,0)
gl.glDrawArrays(gl.GL_TRIANGLE_STRIP,8,4)
gl.glNormal3f(1,0,0)
gl.glDrawArrays(gl.GL_TRIANGLE_STRIP,12,4)
gl.glNormal3f(0,1,0)
gl.glDrawArrays(gl.GL_TRIANGLE_STRIP,16,4)
gl.glNormal3f(0,-1,0)
gl.glDrawArrays(gl.GL_TRIANGLE_STRIP,20,4)
End Sub

Sub glsv_SurfaceChanged(gl As GL1, width As Int, height As Int)
gl.glViewport(0, 0, width, height)
gl.glMatrixMode(gl.GL_PROJECTION)
gl.glLoadIdentity
Dim ratio As Float
ratio = width/height
gl.gluPerspective(45,ratio,1,100)
End Sub

Sub glsv_SurfaceCreated(gl As GL1)
gl.glEnable(gl.GL_DEPTH_TEST)
gl.glDepthFunc(gl.GL_LESS)
gl.glEnableClientState(gl.GL_VERTEX_ARRAY)
Dim lightAmbient(0),lightDiffuse(0),lightPos(0) As Float
lightAmbient=Array As Float(0.2,0.2,0.2,1)
lightDiffuse=Array As Float(1,1,1,1)
lightPos=Array As Float(1,1,1,1)
gl.glEnable(gl.GL_LIGHTING)
gl.glEnable(gl.GL_LIGHT0)
gl.glLightfv(gl.GL_LIGHT0,gl.GL_AMBIENT,lightAmbient,0)
gl.glLightfv(gl.GL_LIGHT0,gl.GL_DIFFUSE,lightDiffuse,0)
gl.glLightfv(gl.GL_LIGHT0,gl.GL_POSITION,lightPos,0)
Dim matAmbient(0),matDiffuse(0) As Float
matAmbient=Array As Float(1,1,1,1)
matDiffuse=Array As Float(1,1,1,1)
gl.glMaterialfv(gl.GL_FRONT_AND_BACK,gl.GL_AMBIENT,matAmbient,0)
gl.glMaterialfv(gl.GL_FRONT_AND_BACK,gl.GL_DIFFUSE,matDiffuse,0)
End Sub

</textarea>
 

agraham

Expert
Licensed User
Longtime User
I enabled glsv.DebugFlags = glsv.DEBUG_CHECK_GL_ERROR and found that gl.glLightfv was erroring as it was calling the wrong method. Attached zip corrects that.

I've been through the OpenGL calls and they all seem to be be being passed through correctly so I can't at the moment see why the same code in Eclipse would be different. Can you post the Java from the Eclipse project for comparison?

EDIT :- Superseded attachment removed to avoid future confusion.
 
Last edited:
Top