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:

wimpie3

Well-Known Member
Licensed User
Longtime User
Is it possible to copy a part of the accelerated surface and paste it somewhere (in the same surface or a second one)?
 

wimpie3

Well-Known Member
Licensed User
Longtime User
So when I want to animate something on the surface, like sliding the contents away, I have to draw the animation step-by-step in the draw function myself? :-(
 

wimpie3

Well-Known Member
Licensed User
Longtime User
What I'm trying to do is rather simple. I have created a drawing on the accelerated surface and I want to cut the drawing in two and slide one part to the left and one part to the right of the screen. I was trying to do that by copying a part of the surface to the same surface again, but each time shifted to the left of right with one pixel to create the sliding effect. But that doesn't seem to be possible...?
 

Informatix

Expert
Licensed User
Longtime User
What I'm trying to do is rather simple. I have created a drawing on the accelerated surface and I want to cut the drawing in two and slide one part to the left and one part to the right of the screen. I was trying to do that by copying a part of the surface to the same surface again, but each time shifted to the left of right with one pixel to create the sliding effect. But that doesn't seem to be possible...?
Your best option is to render the surface to a bitmap (with the Bitmap property) and crop the resulting bitmap (with the ImageUtils.Crop function).
 

wimpie3

Well-Known Member
Licensed User
Longtime User
As soon as I try to do this:

B4X:
myBitmap=utils.Crop(AcSf.Bitmap,1,1,100,100)

I get an error:

B4X:
java.lang.IllegalArgumentException: width and height must be > 0

How on earth is that possible?
 

wimpie3

Well-Known Member
Licensed User
Longtime User
B4X:
    Dim bm As Bitmap
    bm=AcSF.Bitmap
    Log("bm width=" & bm.Width & " bm height=" & bm.Height)

The log-line is never reached. Android crashes on "AcSF.Bitmap". It seems that as soon as you generate the bitmap in the accelerated surface, something goes wrong.

B4X:
main_vvv7 (java line: 524)
java.lang.IllegalArgumentException: width and height must be > 0
    at android.graphics.Bitmap.nativeCreate(Native Method)
    at android.graphics.Bitmap.createBitmap(Bitmap.java:695)
    at flm.b4a.accelerview.AcceleratedSurface.getBitmap(AcceleratedSurface.java:172)
    at b4a.example.main._vvv7(main.java:524)
    at b4a.example.main._vv1(main.java:782)
    at b4a.example.main._acsf1_touch(main.java:371)
    at java.lang.reflect.Method.invokeNative(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:507)
    at anywheresoftware.b4a.BA.raiseEvent2(BA.java:187)
    at anywheresoftware.b4a.BA.raiseEvent2(BA.java:175)
    at anywheresoftware.b4a.BA.raiseEvent(BA.java:171)
    at flm.b4a.accelerview.AcceleratedSurface$1.onTouch(AcceleratedSurface.java:57)
    at android.view.View.dispatchTouchEvent(View.java:3928)
    at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1015)
    at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1015)
    at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1015)
    at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1015)
    at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1015)
    at com.android.internal.policy.impl.PhoneWindow$DecorView.superDispatchTouchEvent(PhoneWindow.java:1784)
    at com.android.internal.policy.impl.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1157)
    at android.app.Activity.dispatchTouchEvent(Activity.java:2181)
    at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchTouchEvent(PhoneWindow.java:1759)
    at android.view.ViewRoot.deliverPointerEvent(ViewRoot.java:2336)
    at android.view.ViewRoot.handleMessage(ViewRoot.java:1976)
    at android.os.Handler.dispatchMessage(Handler.java:99)
    at android.os.Looper.loop(Looper.java:143)
    at android.app.ActivityThread.main(ActivityThread.java:4263)
    at java.lang.reflect.Method.invokeNative(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:507)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597)
    at dalvik.system.NativeStart.main(Native Method)
java.lang.IllegalArgumentException: width and height must be > 0
 

Informatix

Expert
Licensed User
Longtime User
B4X:
    Dim bm As Bitmap
    bm=AcSF.Bitmap
    Log("bm width=" & bm.Width & " bm height=" & bm.Height)

The log-line is never reached. Android crashes on "AcSF.Bitmap". It seems that as soon as you generate the bitmap in the accelerated surface, something goes wrong.

B4X:
main_vvv7 (java line: 524)
java.lang.IllegalArgumentException: width and height must be > 0
    at android.graphics.Bitmap.nativeCreate(Native Method)
    at android.graphics.Bitmap.createBitmap(Bitmap.java:695)
    at flm.b4a.accelerview.AcceleratedSurface.getBitmap(AcceleratedSurface.java:172)
    at b4a.example.main._vvv7(main.java:524)
    at b4a.example.main._vv1(main.java:782)
    at b4a.example.main._acsf1_touch(main.java:371)
    at java.lang.reflect.Method.invokeNative(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:507)
    at anywheresoftware.b4a.BA.raiseEvent2(BA.java:187)
    at anywheresoftware.b4a.BA.raiseEvent2(BA.java:175)
    at anywheresoftware.b4a.BA.raiseEvent(BA.java:171)
    at flm.b4a.accelerview.AcceleratedSurface$1.onTouch(AcceleratedSurface.java:57)
    at android.view.View.dispatchTouchEvent(View.java:3928)
    at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1015)
    at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1015)
    at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1015)
    at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1015)
    at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1015)
    at com.android.internal.policy.impl.PhoneWindow$DecorView.superDispatchTouchEvent(PhoneWindow.java:1784)
    at com.android.internal.policy.impl.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1157)
    at android.app.Activity.dispatchTouchEvent(Activity.java:2181)
    at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchTouchEvent(PhoneWindow.java:1759)
    at android.view.ViewRoot.deliverPointerEvent(ViewRoot.java:2336)
    at android.view.ViewRoot.handleMessage(ViewRoot.java:1976)
    at android.os.Handler.dispatchMessage(Handler.java:99)
    at android.os.Looper.loop(Looper.java:143)
    at android.app.ActivityThread.main(ActivityThread.java:4263)
    at java.lang.reflect.Method.invokeNative(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:507)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597)
    at dalvik.system.NativeStart.main(Native Method)
java.lang.IllegalArgumentException: width and height must be > 0
The bitmap cannot be rendered from inside the rendering (_Draw) event. You have to create it from another event (the Update event, any touch event, etc.).
 

wimpie3

Well-Known Member
Licensed User
Longtime User
That's exactly what I'm doing... I'm getting the bitmap in a sub fired by the TOUCH event. NOT in the draw event.
 

wimpie3

Well-Known Member
Licensed User
Longtime User
After pulling my hair out for a few hours, I have found the solution. I had this in my code:

B4X:
panel.AddView(AcSf, 0, 0, -1, -1)

Turns out the accelerated surface does indeed take the entire space as you would imagine (with the -1,-1 parameter). HOWEVER, something goes wrong inside the library if you do this.

Changing the code to

B4X:
panel.AddView(AcSf, 0, 0, 500dip, 500dip)

did the trick: -1 is not supported...
 

wimpie3

Well-Known Member
Licensed User
Longtime User
I see your library supports a function called LoadNinePatchDrawable, but I cannot figure out how to draw the loaded ninepatch to the accelerated canvas... there is no example for this available.
 

wimpie3

Well-Known Member
Licensed User
Longtime User
Thanks.

Is it possible to draw on the accelerated canvas without the canvas being visible to the user? You can create a canvas and set it invisible, but the draw event is never fired when you do that.
 

wimpie3

Well-Known Member
Licensed User
Longtime User
You've said so yourself:

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

I have about fifty things I want to draw in the background each time at every draw event. So at the start of my program, I create a temporary accelerated surface, draw the fifty bitmaps on that surface, take a "picture" of that surface with the bitmap method and use that bitmap as the background on a second accelerated surface.

The problem is that the initial draw of the bitmap at the start of my program is visible, and I wanted to avoid that.
 
Top