B4A Library [Lib] Accelerated surface

This library provides a dedicated drawing surface embedded inside a view, which benefits from the hardware acceleration. With it, you get the speed of OpenGL for 2D without the complexity.
It includes many Canvas methods (with anti-aliasing, matrix and camera) and a few useful methods for Bitmaps and Drawables (AlterColors, Crop, LoadNinePatch, ReduceColors, SetDensity, etc.). You can import the Matrix, Camera, Paint and Path objects from another library (if they are not wrapped).

surface.png

imageviews.jpg


You can use it to make games:

princess_tiles.png

space_enemies.png


It includes a tool (TextFactory) to do nice titles (that you can export to a bitmap):

textfactory.jpg


It supports Porter-Duff modes, color filters and texture blending (the processing time is very fast):

pdmodes.jpg


The archive includes four benchmarks:

Perf.png


Because of my lack of (free) time, don't expect answers from me about this library if you're not one of my donors.

Download the latest version (1.12)
To convert a project from v0.9x to v1.x, read this.

Hints & Tips

This library does not work with Android versions < 2 (Eclair and Froyo may exhibit performance problems, so I recommend only Gingerbread or a newer version for animations with a high FPS).
The hardware acceleration is not enabled with Android versions < 3.
 

Attachments

  • Java source - AcceleratedSurface.zip
    21.3 KB · Views: 375
Last edited:

sterlingy

Active Member
Licensed User
Longtime User
Does ClipRect clip what has been drawn, or is it something that is set and then anything that is drawn to a canvas is automatically clipped, thereby saving CPU time.

-Sterling
 

Informatix

Expert
Licensed User
Longtime User
Does ClipRect clip what has been drawn, or is it something that is set and then anything that is drawn to a canvas is automatically clipped, thereby saving CPU time.

The second assumption is the right one. You can see an example in AcceleratedSurface.b4a.
 

sterlingy

Active Member
Licensed User
Longtime User
Is it possible to flip a bitmap in either the horizontal, vertical or both directions? I wrongly assumed there was a matrixFlip method.

-Sterling
 

Informatix

Expert
Licensed User
Longtime User
New version 0.962

New version 0.962:
I added two examples:
- Fireworks: it shows a basic particle system with three different particle emitters (circle-shaped, spiral-shaped, fountain-shaped);
- PrincessTiles: this demonstrates a few professional techniques used in 2D games with a tiled map. The same techniques can be used in a platform game. The hero is moved with the accelerometer.
 
Last edited:

Informatix

Expert
Licensed User
Longtime User
New version !

The version 1.0 has undergone significant changes and does not offer backward compatibility with version 0.9x.

The changelog is too important to be listed here. Many functions have been removed because their usefulness was not obvious or they were not efficient. There are new classes (AS_Object, AS_Path, AS_Text) and new functions (DrawObjectAt, SaveState, RotateCanvas, CreateLayer, Merge, SetDensity, ...). There's a help file with the complete list.

All examples have been updated, and I added three examples (one of them is a tool to create nice titles).

Download this version
 

NFOBoy

Active Member
Licensed User
Longtime User
Frederic,

another donation on the way for this one. Couple questions.

When I run accelerated mode on my S3 running JB, I max out at 40fps on the flakes demo, but it doesn't significantly slow down until 180 flakes. No acceleration, it slows down a lot more.

My Galaxy SL running GB easily goes over 40 fps under accelerated mode up until about 140-160 flakes (which I know it has a smaller screen, but I would think the S3 should easily get over 40fps as well)

Do you know what would be holding back the s3?


Also, not seeing any difference between the lighten/darken selection, what should I be looking for there?

(so many demos, so many ideas... combined with JBox2D and Gestures... awesome libraries all)

Ross
 

Informatix

Expert
Licensed User
Longtime User
Frederic,

another donation on the way for this one. Couple questions.

When I run accelerated mode on my S3 running JB, I max out at 40fps on the flakes demo, but it doesn't significantly slow down until 180 flakes. No acceleration, it slows down a lot more.

My Galaxy SL running GB easily goes over 40 fps under accelerated mode up until about 140-160 flakes (which I know it has a smaller screen, but I would think the S3 should easily get over 40fps as well)

Do you know what would be holding back the s3?


Also, not seeing any difference between the lighten/darken selection, what should I be looking for there?

(so many demos, so many ideas... combined with JBox2D and Gestures... awesome libraries all)

One of my chinese tablets can't display more than 40 FPS, like your S3, despite a good GPU. I think it's related to the vertical sync. Anyway it doesn't seem to be a real problem (we give too much importance to numbers sometimes ;)).

Porter-Duff modes, IMHO, should be used only with the HwAcc disabled because the result varies too much between devices and OS when HwAcc is enabled.
 

Informatix

Expert
Licensed User
Longtime User
How to convert a project created with v0.9x to the new v1.0:

- Rename AcceleratedCanvas to AS_Canvas;

- Rename ImageUtils to AS_ImageUtils;

- Rename Texture to AS_Texture;

- Replace all CreateScaledBitmap(LoadBitmap...) and CreateScaledBitmap(LoadBitmapSample...) by LoadScaledBitmap;

- Replace all ...Rotated functions by:
B4X:
AC.SaveState
AC.RotateCanvasAround(...)
AC.Draw...
AC.RestoreState

- Replace Create by CreateWithBitmap (for textures);

- The ...WithPaint and ...WithTexture have been removed. To use a custom Paint or to apply a texture, use the new AS_Object class. Example:
B4X:
 Dim O As AS_Object
O.CreateOval(140dip, 110dip, True).SetTexture(texWater)
AC.DrawObjectAt(O, 0, 0)

- The MatrixReset and MatrixPre... functions have been removed, so you have to compute your matrix only with the MatrixSet... and MatrixPost... functions.
 

NFOBoy

Active Member
Licensed User
Longtime User
Passing the AC

Frederic, if I want to design classes that draw themselves, would there be any problem having a Draw Event that accepts the AC object from the draw event, does its magic to the AC and then returns back to the Draw Object? (it appears that should be no problem)

The only issue I see is from a de-bugging perspective, is that the update and draw events can't be stopped while in debug mode at the same time, do you concur?

Ross
 

kostas3001

Member
Licensed User
Longtime User
Hi Informatix

Great job!

In the old version v: 0.962 if I put to the background a JPG or PNG image and use the following code:

Dim R As Rect
R.Initialize (0, 0, AcSf.Width, AcSf.Height)
AC.DrawRectWithTexture (R, FondoTexture)

works very well, but I can not use

For i = 0 To LaserShots.size - 1
LaserShot = LaserShots.Get (i)
R.Initialize (LaserShot.X, LaserShot.Y, LaserShot.X + LaserShotSize, LaserShot.Y + 1.5%)
AC.DrawRect (R, Colors.Yellow, False, 10)
Next

AC.DrawText ("Start", 0, 100, Typeface.DEFAULT, 30, Colors.White, AC.ALIGN_LEFT)

because laser and text not look at the screen.

With the new version of the library will be able to see the laser drawing and text?
 

Informatix

Expert
Licensed User
Longtime User
Frederic, if I want to design classes that draw themselves, would there be any problem having a Draw Event that accepts the AC object from the draw event, does its magic to the AC and then returns back to the Draw Object? (it appears that should be no problem)

The only issue I see is from a de-bugging perspective, is that the update and draw events can't be stopped while in debug mode at the same time, do you concur?

Ross

You can pass the AS_Canvas object to any sub or class, and this sub or class can use it to draw onto the surface at any time. In v1.0, the AS_Canvas reference changes only when the surface is resized (a new Canvas has to be created).

I have no idea about the possible debugging issues. I never use the B4A debugger. It is of no use with libraries.
 

Informatix

Expert
Licensed User
Longtime User
Hi Informatix

Great job!

In the old version v: 0.962 if I put to the background a JPG or PNG image and use the following code:

Dim R As Rect
R.Initialize (0, 0, AcSf.Width, AcSf.Height)
AC.DrawRectWithTexture (R, FondoTexture)

works very well, but I can not use

For i = 0 To LaserShots.size - 1
LaserShot = LaserShots.Get (i)
R.Initialize (LaserShot.X, LaserShot.Y, LaserShot.X + LaserShotSize, LaserShot.Y + 1.5%)
AC.DrawRect (R, Colors.Yellow, False, 10)
Next

AC.DrawText ("Start", 0, 100, Typeface.DEFAULT, 30, Colors.White, AC.ALIGN_LEFT)

because laser and text not look at the screen.

With the new version of the library will be able to see the laser drawing and text?

I forgot to mention that I solved the problem with texts and textures in the same canvas. You can see in the Perf_Water demo that the FPS string at the top is white now.
The problem was due to a bug in the API function "Paint.reset()".
 

kostas3001

Member
Licensed User
Longtime User
Thanks Informatix

With the new library everything works perfectly, I've tested it.

Great job! I hope to see more features and more examples with your library.
 

Informatix

Expert
Licensed User
Longtime User
New version

Hello,

In this new version:
- I added the PathEffects (SetPathEffect, SetPathEffect2, AddToPathEffect);
- I added DrawBitmapMesh (the bitmap is drawn through a mesh made of numerous nodes; it's useful to distort a bitmap or apply it on a 3D object);
- I added two examples to illustrate the PathEffects functions and DrawBitmapMesh;
- I added the Get/SetAlpha functions for AS_Object and AS_Text;
- I added the GetWidth and GetHeight functions for AS_Object;
- I improved the error checking;
- I fixed a minor bug in the TextFactory example.

That's probably the last version because this library is rich enough, and the number of functions that benefit from the hardware acceleration is limited.

Download the new version (1.1)
 

Informatix

Expert
Licensed User
Longtime User
HINTS & TIPS


Things to avoid

Allocating memory/creating objects in the Draw/Update events

As much as possible, avoid allocating memory/creating objects with Dim, Initialize, LoadBitmap, CreateScaledBitmap, etc., in the Update and Draw events because that lowers the performance. All objects (bitmaps, arrays, etc.) should be initialized and ready to use when these events are fired.

Modifying views in the Draw event

Never change a view property (text of label, width of imageview, ...) in the Draw event because that lowers a lot the performance. Do these changes in the Update event.


What's the fastest method to...?

Draw a bitmap:

Average FPS for the Perf_Smileys example on a Nexus 7 with JB 4.2.2 (settings 15/500 with hardware acceleration):
DrawBitmapAt: 42
DrawObjectAt with a bitmap object: 41
DrawBitmapWithMatrixAt with Filter=False: 37
DrawBitmap: 34
DrawBitmapWithMatrixAt with Filter=True: 30

Average FPS on a Huawei Honor with Gingerbread 2.3.6 (settings 15/150 without hardware acceleration):
DrawBitmapAt: 41
DrawObjectAt with a bitmap object: 41
DrawBitmapWithMatrixAt with Filter=False: 41
DrawBitmapWithMatrixAt with Filter=True: 40
DrawBitmap: 39

Rotate a bitmap:

I modified the Perf_Smileys example with the following code:
Code 1:
B4X:
AC.MatrixSetRotate2(45, 32dip, 32dip)
AC.DrawBitmapWithMatrixAt(bmpSmiley, Smiley.x, Smiley.y, Filter)
Code 2:
B4X:
AC.SaveState
AC.RotateCanvasAround(45, Smiley.x + 32dip, Smiley.y + 32dip)
AC.DrawBitmapAt(bmpSmiley, Smiley.x, Smiley.y)
AC.RestoreState
Average FPS on a Nexus 7 with JB 4.2.2 (settings 15/500 with hardware acceleration):
Code 1 with Filter=False: 33
Code 1 with Filter=True: 30
Code 2: 30

Scale a bitmap:

I modified the Perf_Smileys example with the following code:
Code 1:
B4X:
AC.MatrixSetScale(2, 2)
AC.DrawBitmapWithMatrixAt(bmpSmiley, Smiley.x, Smiley.y, Filter)
Code 2:
B4X:
AC.SaveState
AC.ScaleCanvas(2, 2)
AC.DrawBitmapAt(bmpSmiley, Smiley.x / 2, Smiley.y / 2)
AC.RestoreState
Code 3:
B4X:
R.Initialize(Smiley.x, Smiley.y, Smiley.x + 128dip, Smiley.y + 128dip)
AC.DrawBitmap(bmpSmiley, Null, R)
Average FPS on a Nexus 7 with JB 4.2.2 (settings 15/500 with hardware acceleration):
Code 2: 22
Code 1 with Filter=False: 22
Code 1 with Filter=True: 22
Code 3: 21


SetXferMode and Porter-Duff modes

The result of SetXferMode may vary from one OS to another when the hardware acceleration is enabled. That's why it is advised to use this function with the acceleration disabled. However, some modes are fully supported by all OS and should benefit from the hardware acceleration without issue:
Clear: Not OK
Darken: Not OK
Dst_ATop: Not OK
Dst_In: Not OK
Dst_Out: OK
Dst_Over: OK
Lighten: Not OK
Multiply: Not OK
Screen: OK
Src_ATop: OK
Src_In: Not OK
Src_Out: Not OK
Src_Over: OK
XOR: OK

The source object (Src) is the object with the XferMode set. The destination object (Dst) is everything that intersects or is overlapped by the source object, including the background of your surface. If you want the destination to be a specific object (or group of objects), you have to draw the Src and Dst objects in a separate layer with CreateLayer, then tranfer the result to the canvas with TransferLayer (cf. example Objects'n'Modes).


Using a bitmap instead of drawing the background

If you draw repeatedly the background of your surface with the same scene, you may save the result as a bitmap (cf. the Bitmap property) and set this bitmap as the background of the surface. That will increase the performance. But beware: you cannot get the Bitmap property in the Draw event and you should set the background outside of it.


Saving memory

Two effective ways of reducing the memory consumption are the use of LoadScaledBitmap to load your bitmaps with their exact size on screen (you should prefer this function to LoadBitmapSample in all cases) and ReduceColors to reduce their color range (the differences for the eye are subtle and should be unnoticed in most cases). ReduceColors removes also the alpha channel, so it is not suited for images with transparent parts.
 

Informatix

Expert
Licensed User
Longtime User
New version - Bugs fixed

Version v1.11

I fixed three bugs/issues in this version:
- AS_Canvas: DrawObjectAt used a slow and faulty method to translate a path object to the given coordinates;
- AS_Canvas: DrawPath didn't accept an AS_Path as parameter;
- AS_Path: ImportPath didn't check if the path was initialized.

Download the latest version (1.11)
 

kostas3001

Member
Licensed User
Longtime User
Hi Informatix

In release 1.0 of the library, if I put sound play in AcSf_Touch, I experience small "cuts" in the drawing...:

Sub AcSf_Touch(Action As Int, X As Int, Y As Int, Event As Object)
If Action = Activity.ACTION_DOWN Then
If FireWait <= 0 Then
Dim LaserShot As typLaser
'MP_laser.Stop
'MP_laser.Initialize2("MP")
'MP_laser.Load(File.DirAssets, "laser1.mp3")
'MP_laser.SetVolume(0.99, 0.99)

LaserShot.Y = PositionY + Bit.ShiftRight(Nave.Height, 1) - 0.25%y
LaserShot.X = PositionX + Nave.Width ' - 1.5%x - LaserShotSize
LaserShots.Add(LaserShot)
FireWait = WaitBeforeNextShot
'MP_laser.Play
End If
End If
End Sub

Can you put your example SpaceEnemies.b4a with sound, please?
 

Informatix

Expert
Licensed User
Longtime User
Hi Informatix

In release 1.0 of the library, if I put sound play in AcSf_Touch, I experience small "cuts" in the drawing...:

Sub AcSf_Touch(Action As Int, X As Int, Y As Int, Event As Object)
If Action = Activity.ACTION_DOWN Then
If FireWait <= 0 Then
Dim LaserShot As typLaser
'MP_laser.Stop
'MP_laser.Initialize2("MP")
'MP_laser.Load(File.DirAssets, "laser1.mp3")
'MP_laser.SetVolume(0.99, 0.99)

LaserShot.Y = PositionY + Bit.ShiftRight(Nave.Height, 1) - 0.25%y
LaserShot.X = PositionX + Nave.Width ' - 1.5%x - LaserShotSize
LaserShots.Add(LaserShot)
FireWait = WaitBeforeNextShot
'MP_laser.Play
End If
End If
End Sub

Can you put your example SpaceEnemies.b4a with sound, please?

Sounds must be played with SoundPool, not the media player. The media player is for music only.
 
Top