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,377
Last edited:

agraham

Expert
Licensed User
Longtime User
It's taken over four hours :sign0137: but I fixed it :sign0060:
After checking every constant allocation and call in the library I googled for Android depth problems and found that the example code I copied to initialise the GLSurfaceView was not specifying the allocation of a depth buffer!:sign0161:

Version 1.4 properly initialises the GLSurfaceView and fixes a couple of typos that turned up in my fine toothcomb trawl through the library code.

I have replaced the original demo OpenGL code with geocomputings rotating cube. :icon_clap:

EDIT :- I fixed it using the Xoom and just tried it on the ZTE Blade where it threw an array index exception. Commenting out the assignment to glsv.DebugFlags in Activity_Resume fixed it, and speeded it up a lot too. Looks like there's a bug in the OpenGL debug wrapper on the Blade. :(
 
Last edited:

geocomputing

Member
Licensed User
Longtime User
Hi Andrew,

Sorry not to have stopped by sooner, otherwise I would have uploaded the project zip for you. However, it looks like you've done some amazing work. I've tried v1.4 of the library and it works perfectly on my Wildfire and Galaxy Tab. :sign0060:

I noticed in your initial post that you haven't implemented buffer objects. If I had a wish it would be that they be added some day as they can make a big difference to 3D performance. However, I'm happy to be content at the moment just to have OpenGL to use on B4A. :)

Many thanks and congratulations on such a useful and important library.

:wav:

Best wishes,

Andrew.
 

agraham

Expert
Licensed User
Longtime User
I noticed in your initial post that you haven't implemented buffer objects. If I had a wish it would be that they be added some day as they can make a big difference to 3D performance.
I'm not sure we are talking about the same Buffer objects. In Android a Buffer is a Java object based on a linear area of memory, like an array, which is available to native code (assembler and C/C++) routines as it is located in non-managed memory. Basic4android can only handle Java arrays which are much the same as Buffers but are located on the managed heap.

The Android OpenGL implementation often has two versions of the same function, one taking a Buffer parameter, the other taking an array parameter. I've only exposed the variants accepting arrays.

In a few cases, mainly the xxxPointer functions, only a variant accepting a Buffer exists so in those cases I have implemented the method as accepting an array and copied the array into a Buffer that I have created in unmanaged memory to pass to the API.

B4X:
   public void glVertexPointerf(int size, float[] points)
   {
      ByteBuffer pbb = ByteBuffer.allocateDirect(points.length * 4);
      pbb.order(ByteOrder.nativeOrder());
      FloatBuffer pfb = pbb.asFloatBuffer();
      pfb.put(points);
      pfb.position(0);
      gl.glVertexPointer(size, GL_FLOAT, 0, pfb);
   }
The line pfb.put(points); copies the points array to the new Buffer and as it is a single call I suspect it translates to a CPU block move instruction so I can't see that there is going to be a significant performance hit bearing in mind all the subsequent processing that is going to be carried out on that data.

Other than the above Buffer consideration I can see nothing else that would impact 3D performance.
 

geocomputing

Member
Licensed User
Longtime User
Hi,

My misunderstanding I think. I assumed you were meaning that the library wouldn't be able to take full advantage of vertex buffers to reduce memory transfer overheads in drawing 3d objects. I'll be trying to implement a model with a few thousand triangles soon, so I'll report back any performance info I get. I'm sure your library will perform very well :)

Anyway, thanks again :)

Best wishes,

Andrew.
 

agraham

Expert
Licensed User
Longtime User
Version 1.5 now posted just about wraps up the OpenGL functionality.

As the GLSurfaceView events run on a separate thread to the main GUI thread I previously provided the RunOnGuiThread method for rendering code to run on the main thread. Version 1.5 now includes a QueueEvent method that provides the complementary ability for main thread code to run on the rendering thread. As uncaught exceptions occurring on the rendering thread would halt the application any such exceptions in a Sub run using QueueEvent are caught and saved in a new QueuedEventException property and can be examined to establish the cause using an ExceptionEx object from my Threading library.
 

derez

Expert
Licensed User
Longtime User
I want to use a transparent color as the gl.glclearcolor in order to draw the moving body over a bitmap (the bitmap is the activity's background and the drawing is done on a panel).
But, the use of alfa = 0 or any other value does not affect the clearing color.
what is missing ?
 

agraham

Expert
Licensed User
Longtime User
what is missing ?
Alpha in backgrounds is not supported at present. There are complications in implementing this whose ramifications I do not presently understand so I am not at present prepared to promise that this will be possible.
 
Last edited:

derez

Expert
Licensed User
Longtime User
:(

Alternatively - how can I draw the body over a bitmap ?
(sequence of operations: clear the window, draw an image, draw body)
 

derez

Expert
Licensed User
Longtime User
Started already, but not yet at textures...
In the meantime my UAV is flying quite well at night also.
 

Attachments

  • uav5.jpg
    uav5.jpg
    35.6 KB · Views: 297
Last edited:

derez

Expert
Licensed User
Longtime User
I looked at the bitmaps, images and textures... it is too low level for me.
The GL wants to read the image from a memory buffer, and this is the missing link for what I understand - how to get it in the correct format from the B4A bitmap structure.
 

derez

Expert
Licensed User
Longtime User
I think this is more suitable for images:
(taken from this http://www.loria.fr/~roegel/cours/iut/opengl/addison.pdf)

Reading, Writing, and Copying Pixel Data
OpenGL provides three basic commands that manipulate image data:
glReadPixels() - Reads a rectangular array of pixels from the framebuffer and stores the data
in processor memory.
glDrawPixels() - Writes a rectangular array of pixels from data kept in processor memory
into the framebuffer at the current raster position specified by glRasterPos*().
glCopyPixels() - Copies a rectangular array of pixels from one part of the framebuffer to
another. This command behaves similarly to a call to glReadPixels() followed by a call to
glDrawPixels(), but the data is never written into processor memory.
For the aforementioned commands, the order of pixel data processing operations is shown in Figure
8-3:
Figure 8-3 : Simplistic Diagram of Pixel Data Flow
The basic ideas in Figure 8-3 are correct. The coordinates of glRasterPos*(), which specify the
current raster position used by glDrawPixels() and glCopyPixels(), are transformed by the
geometric processing pipeline. Both glDrawPixels() and glCopyPixels() are affected by
rasterization and per-fragment operations. (But when drawing or copying a pixel rectangle, there’s
almost never a reason to have fog or texture enabled.)
However, additional steps arise because there are many kinds of framebuffer data, many ways to
store pixel information in computer memory, and various data conversions that can be performed
during the reading, writing, and copying operations. These possibilities translate to many different
modes of operation. If all your program does is copy images on the screen or read them into
memory temporarily so that they can be copied out later, you can ignore most of these modes.
However, if you want your program to modify the data while it’s in memory - for example, if you
have an image stored in one format but the window requires a different format - or if you want to
save image data to a file for future restoration in another session or on another kind of machine with
significantly different graphical capabilities, you have to understand the various modes.
The rest of this section describes the basic commands in detail. The following sections discuss the
details of the series of imaging operations that comprise the Imaging Pipeline: pixel-storage modes,
pixel-transfer operations, and pixel-mapping operations.

Reading Pixel Data from Frame Buffer to Processor Memory

void glReadPixels(GLint x, GLint y, GLsizei width, GLsizei height,
GLenum format, GLenum type, GLvoid *pixels);
Reads pixel data from the framebuffer rectangle whose lower-left corner is at (x, y) and
whose dimensions are width and height and stores it in the array pointed to by pixels. format
indicates the kind of pixel data elements that are read (an index value or an R, G, B, or A
component value, as listed in Table 8-1), and type indicates the data type of each element (see
Table 8-2).

If you are using glReadPixels() to obtain RGBA or color-index information, you may need to
clarify which buffer you are trying to access. For example, if you have a double-buffered window,
you need to specify whether you are reading data from the front buffer or back buffer. To control
the current read source buffer, call glReadBuffer().
Table 8-1 : Pixel Formats for glReadPixels() or glDrawPixels()
format Constant Pixel Format
GL_COLOR_INDEX A single color index
GL_RGB A red color component, followed by a green color component,
followed by a blue color component
GL_RGBA A red color component, followed by a green color component,
followed by a blue color component, followed by an alpha
color component
GL_RED A single red color component
GL_GREEN A single green color component
GL_BLUE A single blue color component
GL_ALPHA A single alpha color component
GL_LUMINANCE A single luminance component
GL_LUMINANCE_ALPHA A luminance component followed by an alpha color
component
GL_STENCIL_INDEX A single stencil index
GL_DEPTH_COMPONENT A single depth component
Table 8-2 : Data Types for
 

agraham

Expert
Licensed User
Longtime User
Sorry, but that document doesn't describe the variant of OpenGL used by Android and other mobile devices. Android implements OpenGL ES 1.0 with some capabilities from OpenGL ES 1.1. OpenGL ES is a simplified version of OpenGL for embedded systems. In fact glDrawPixels doesn't exist, and it looks like I might have got glReadPixels implementation wrong but it doesn't seem of much use anyway without the complementary function to return them.

It needs someone who knows more than I, but I think textures is the only way to get images into OpenGL ES.
 

agraham

Expert
Licensed User
Longtime User
Version 1.6 now posted.

The xml help now makes plain that the renderer runs on a different thread to the main thread.

Rewritten GL1.glreadPixels to return an array of Ints representing the ARGB pixel values of a specified area of the GLSurfaceView image.

Added GL1.glReadPixelBitmap that returns a Bitmap containing a specified area of the GLSurfaceView image.
 

derez

Expert
Licensed User
Longtime User
Thank you for improving !

I need help with drawing an image as background.
I followed this Texture Mapping – OpenGL Android (Displaying Images using OpenGL and Squares) | Against the Grain – Game Development and prepared a simplified version of UAV, without the flight simulator.
It draws a rectangular background built of two triangles and the UAV body is "flying" in front of it. It looks nice as long as the texture is not enabled. When I enable the texture (line 133) there is still no texture, and the whole display becomes darker.

I'm sure there is something wrong but can't point it.
I'll appreciate if someone is willing to look at it. I believe every application using opengl needs a background. The best way would be to have a background image on a view or on the activity, and the graphics on top with transparent color, but that is not available (yet ...?)

Thanks


edit - the new version is loading as 1.5
 

Attachments

  • uav7.zip
    69.9 KB · Views: 300
Last edited:

agraham

Expert
Licensed User
Longtime User
Version 1.7 now posted has a new Initialize2 method that initialises the drawing format to 32 bit RGBA thus supporting transparency. The original Initialize sets it to R5G6B5 16 bit colour with no alpha.

Initialize2 also accepts specified sizes for the depth and stencil buffers, use 16 and 0 resppectively if in doubt as to what they do.
 

derez

Expert
Licensed User
Longtime User
Agraham - Thank you but I don't see any difference in the result.
I put a picture on the activity and init2 the glsv on a panel, clearing the color every cycle with alfa = 0, but the color is solid, not transparent.

Anything else to do to have it transparent ?
 

Attachments

  • u7.jpg
    u7.jpg
    50.9 KB · Views: 280
Top