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: 784
Last edited:

sterlingy

Active Member
Licensed User
Longtime User
Copying the sprite from the sheet is a bit slow, whatever method you use. It's better to separate the individual images before animating them. As you can see in my benchmark, one of the slowest method to draw a bitmap is to use the DrawBitmap function, which is the one used to retrieve a sprite from a sheet (and the one used by GameView).
This helps, so do you suggest that I load individual bitmaps (i.e. not use a sprite sheet) into an array or should I use Crop to point to the current image in the sprite sheet?
 

Informatix

Expert
Licensed User
Longtime User
This helps, so do you suggest that I load individual bitmaps (i.e. not use a sprite sheet) into an array or should I use Crop to point to the current image in the sprite sheet?

If you load your sprite sheet as a single file, crop each bitmap, then start the animation, what you gain by loading only one file is lost by the time past to crop and you use twice the memory you would use by loading each image individually. So my suggestion is to keep each image in a separate file. And if you want to animate them in sequence, an array is, of course, very convenient.
 

kanaida

Active Member
Licensed User
Longtime User
Pretty Awesome

I was looking for something like this to try to learn how to make games and have fast enough graphics. I have an LG Connect 4G and I get 60fps @ 120 Objects. It only decreases slightly as I add more as well. Ironically on my nexus 10, with the same amount of objects gives me about 58 fps. It would mean that the amount of pixels offsets all the increased gfx power quite a bit. Luckily though, they seem to be on par.

Although OpenGL seems not very debug friendly in b4a so this will make a great alternative. OpenGL seemed to crash all the time on my nexus 10 as well when the same code would work on my phone.

Thanks for your effort, i'll try to see what i pick up and maybe learn a thing or two.
 

NFOBoy

Active Member
Licensed User
Longtime User
Acceleration in Manifest?

Frédéric,

in looking at the Android Developer site, came across this:
public static final int FLAG_HARDWARE_ACCELERATED
Added in API level 11

Indicates whether this window should be hardware accelerated. Requesting hardware acceleration does not guarantee it will happen.

This flag can be controlled programmatically only to enable hardware acceleration. To enable hardware acceleration for a given window programmatically, do the following:

Window w = activity.getWindow(); // in Activity's onCreate() for instance
w.setFlags(WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED,
WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED);


It is important to remember that this flag must be set before setting the content view of your activity or dialog.

This flag cannot be used to disable hardware acceleration after it was enabled in your manifest using hardwareAccelerated. If you need to selectively and programmatically disable hardware acceleration (for automated testing for instance), make sure it is turned off in your manifest and enable it on your activity or dialog when you need it instead, using the method described above.

This flag is automatically set by the system if the android:hardwareAccelerated XML attribute is set to true on an activity or on the application.

Constant Value: 16777216 (0x01000000)

In the wiki it mentions :
Warning: some modes may have a different result depending on whether the hardware acceleration is enabled or not.

In all your samples , the AndroidManifest has the hardware enabled=True, so just wondering if that means that it shouldn't have that in the Manifest, if you want the Porter-Duff to behave properly?

Ross
 

NFOBoy

Active Member
Licensed User
Longtime User
AS Surfaces

Frédéric,

Thanks to your AnimationPlus(AP) library, and the NOA library, I have just completed a nice little educational game app, that (to me) looks very nice.

It does have a few slowdown hiccups, (on my S3!!) that I don't see on my other devices, so while I am sure it is something in my phone (time to wipe and start fresh), I also think it is partly because I am using all Custom Views, so that I can take advantage of the calls to NOA and AP to add the effects.

One of the reasons I use Custom Views, is to take advantage of very quickly determining which View is selected by the user, and then tying all those update events to that Custom View for moving the view around on the screen.

Thanks to your AS Samples, I "think" I might have a handle of using NOA or AP with AS.. so my next project is to try to make a game with multiple moving elements (like WhackAMole)..

My thoughts for implementation are to design a custom View with a transparent View over the AS, so I can get the user info again, and then have the AS do whatever Animation is appropriate. Theoretically, I could see getting up to 60 Cutom Views instantiated at the same time.

I think this will free the animations from the "stutter" effect I see at times, and should allow for a smoother experience, but I am just wondering if there is a performance hit by having so many AS instantiated at the same time? (As I know there would be some with them being instantiated as normal Views.. i.e. 60 imageViews with 60 clearPanels, each one potentially doing there own animation effects using NOA or AP).

If so, I can go down the path of creating a Custom Object, that would just be the bitmap, and then I do a search in GestureDetector to see which object is being touched or moved, and pass appropriate information to the Object, and during Update get everything ready, and have the AS passed to each object during the Draw event, it just doesn't feel as encapsulated that way, but if necessary... :)

Ross
 

Informatix

Expert
Licensed User
Longtime User
In all your samples , the AndroidManifest has the hardware enabled=True, so just wondering if that means that it shouldn't have that in the Manifest, if you want the Porter-Duff to behave properly?

Ross

To disable the HA for an AS, the easiest way is to set the HA parameter to False when you initialize the AS. So you can have AS without HA and AS with HA in the same activity (it's the case in the Space Enemies example). The setting in the manifest should be left to True.
 

Informatix

Expert
Licensed User
Longtime User
Thanks to your AnimationPlus(AP) library, and the NOA library, I have just completed a nice little educational game app, that (to me) looks very nice.

Glad to hear it.

It does have a few slowdown hiccups, (on my S3!!) that I don't see on my other devices, so while I am sure it is something in my phone (time to wipe and start fresh), I also think it is partly because I am using all Custom Views, so that I can take advantage of the calls to NOA and AP to add the effects.

Let me know if you solved the problem with the S3 because you're the second to report slowdowns (the first case was with GameView, but it is based on the same principles).

One of the reasons I use Custom Views, is to take advantage of very quickly determining which View is selected by the user, and then tying all those update events to that Custom View for moving the view around on the screen.

Not very good for performance, but very convenient when you have rectangular objects. In real games, things on screen are not always rectangular, so the method is (when a touch action occurs):
- in that part of the screen, who is concerned?
- I sort the concerned elements by Z-order;
- I check if the touch action is in the AABB of the topmost element;
- if yes, I check if the touch point is transparent (if not, I take the element behind).
You could think that's slow. In fact, it's fast when well implemented. Usually, you have only a few elements to test under your finger and the last check (transparency) can be skipped if not really required (that's the slowest part because you have to read a pixel when Action=0).

My thoughts for implementation are to design a custom View with a transparent View over the AS, so I can get the user info again, and then have the AS do whatever Animation is appropriate. Theoretically, I could see getting up to 60 Cutom Views instantiated at the same time.
I think this will free the animations from the "stutter" effect I see at times, and should allow for a smoother experience, but I am just wondering if there is a performance hit by having so many AS instantiated at the same time?

I don't understand what you're really trying to do (what's the purpose of the transparent view?) and why that would "free the animations from the stutter effect". So I cannot give an answer.
 

NFOBoy

Active Member
Licensed User
Longtime User
Ah, the purpose of the transparent view is to capture the touch events, and then translating/moving/animating the actual visible portion, since it is not possible to actually move the object capturing the motion events.

When the user lifts their finger (or something happens to remove the visible portion) I then update the final position of the view and transparent top so that they then again match (to start the loop over again).

Here is my "ugly" class definition for a Custom View in my game. Using the ClearTop I don't have to search to see what View got picked, so animation/translation code is very encapsulated within the class. When I do animations, I have to do it to each layer (3: Characters which contain s transparency; the background color-which is randomly chosen at runtime; the white frame behind the color and character) (animations for coming into play, being taken out of play) Only a few on at one time, so no performance issues (except as I mentioned on my top-tier device, which I don't see in other games I play, so think it is because of the animations being tied to the GUI thread, instead of an AS)

B4X:
Sub Class_Globals
   

   
   Public asView As Button 'the visibile portion
   Private bmpFrontSide As Bitmap 'the picture for this view
   
   Private holdingView As Panel 'parent for this view
   Private myImage As String 'where the image file is stored
   Private vModule As Object 'for callbacks
   Private myCharacter As CharacterInfo 'information about the character attached to this view
   

   Private myClearTop As Button 'to put over the top of the asView and capture Motion Events
   Private btnBackGroundColor As Button 'the view for showing the chosen color behind picture 
   Private myBackGroundColor As Int 'for the background color behind each button
   Private myWhiteBack As Button 'to put behind the background color as a buffer to see it better (sticks out from behind the view to frame it in white)
   
   Private listOfBarrels As List 'barrels to be used to see if collision occurs 
   Private listOfButtons As List 'to store instance of each View of this type to be instantiated

   Private Gesture As Gestures 'to capture the Input on each clear Top
   Private originalX, originalY As Int 'to remember where the view started when move operation begins

   Private bCanMove As Boolean 'sometimes the view shouldn't be moving
   
   Private timesWrong As Int 'for use in determining when to animate the correct Barrel that user should be aiming for
   
   Private MP As MediaPlayer 'to play the character name
   Private MPuhuh As MediaPlayer 'to play the "nope" sound when user picks the wrong barrel
End Sub

I DO think in terms of rectangular views, as my thought process is definitely aligned to the things available in NOA for feedback (e.g. how far along the animation is to vary the pitch/volume of the sounds, based on the chosen interpolator), but also realize I need to think about doing animations directly on the bitmap... I'm just not there yet. :)
 

Informatix

Expert
Licensed User
Longtime User
but also realize I need to think about doing animations directly on the bitmap... I'm just not there yet. :)

I'm not sure I will try some day to place and move a transparent panel in front on any touchable element because I'm quite sure it's one of the worst solution in terms of performance, but if that runs fine on any device as you implemented it, why not?
If you read the Romain Guy's posts on internet (he's a Google engineer working on the graphics part of Android), you'll see that the worst thing is to stack transparent panels on transparent panels on transparent panels on...

NOA is not limited to views. I use it in one of my projects to shrink gradually a bitmap and move another one.

And you should avoid the MediaPlayer to play sounds. It is not designed for that (only music). Use Soundpool instead.
 

latch

Active Member
Licensed User
Longtime User
Would it be logical to assume that one would use..

Crop (src As Bitmap, x As Int, y As Int, width As Int, height As Int)

..in the surface draw function to draw sprites extracted from a sprite sheet? Or do I have have to declare a bitmap object for everything I want to draw with..

ac.DrawBitmapWithMatrixAt(super, super.width/2 +ex(n)-mx, super.height/2 + ey(n)-my, True)

What I am asking is, is this going to cause problems?

ac.DrawBitmapWithMatrixAt(Crop (spritesheet,0, 0, 128, 128),width,height, True)
 

Informatix

Expert
Licensed User
Longtime User
Would it be logical to assume that one would use..
..in the surface draw function to draw sprites extracted from a sprite sheet? Or do I have have to declare a bitmap object for everything I want to draw with..

I can't see any advantage at using a sprite sheet with AS or GameView. You use more memory (you have to load the full sheet in memory and create a bitmap to hold the current bitmap to display; in the worst case, you don't have this extra bitmap with individual images) and it is less effective (because of the functions involved, e.g. DrawBitmap instead of DrawBitmapAt).

The function for sprite sheets is DrawBitmap (you select the right bitmap to display with the Src parameter) or DrawObject with a Bitmap type.

ac.DrawBitmapWithMatrixAt(Crop (spritesheet,0, 0, 128, 128) is just horrible ;) Forget it. That's slower and use more memory than the other solutions.
 
Last edited:

latch

Active Member
Licensed User
Longtime User
I need more than 80 bitmaps to animate my character. I'm doing a Sup*r M*troid ripoff with my own assets of course and not as many options(It IS and android game after all and doesn't have to be THAT epic) see here:
samusm.png


Anyways, I want responsiveness and don't want any out of memory for image errors - seems like I got a couple of those with Hail of Gunfire.

So lemme recap- you are saying I should just declare a bitmap array and display them like I was doing before like so:

dim duderunningleft(30) as bitmap
for n=0 to 29
duderunningleft(n)=ui.createscaledbitmap(all those parameters that go in here)
next

sub drawsurface
rotate and draw appropriate bitmap
end sub
 

Informatix

Expert
Licensed User
Longtime User
So lemme recap- you are saying I should just declare a bitmap array and display them like I was doing before like so:

Yes. It's the most efficient way. Note: the function to load bitmaps is LoadScaledBitmap. CreateScaledBitmap is just to resize them.

80 bitmaps: depending on their size, it's maybe too much for my library on some devices under Gingerbread.
 

padvou

Active Member
Licensed User
Longtime User
I took a look at one of the examples and I stumbled upon this piece of code:
B4X:
ObjPath.Initialize(4dip, 0)
    ObjPath.LineTo(0, -4dip).LineTo(8dip, -4dip).LineTo(12dip, 0).LineTo(8dip, 4dip).LineTo(0, 4dip)
What if I wanted to draw something like this, a closed path object like an ellipsis, when I know the radius of a series of points that form the path?
Of course the angle between them is known.
 

padvou

Active Member
Licensed User
Longtime User
Ok,
I 've made a function for this, so I 'm ready with this.
So now I have a table with x's and y's.
How do I draw a path?
 

padvou

Active Member
Licensed User
Longtime User
Sorry,
I meant my x's and y's are in mm.
Is there an efficient way to adjust them for the surface's dimensions proportionally?
 
Top