Canvas manipulation vs element manipulation
-
13-07-2021 - |
Question
I am developing a small library as a basis for some applications. As I am about to create a scenegraph (2D) I am wondering which of the following approaches looks more promising under the view of performance, maintainability, easy to use etc.
- I could give each drawable element a matrix where I perform translation, rotation and more.
- I could do everything on the canvas instead of the elements.
The first solution has a disadvantages: For primitive elements like circles, where I can't pass a matrix in the draw call, I must access the translated values from the matrix like this:
private float get(int index) {
final float[] values = new float[9];
getValues(values);
return values[index];
}
public float getX() {
return get(Matrix.MTRANS_X);
}
public float getY() {
return get(Matrix.MTRANS_Y);
}
So on every draw call I create a float array for each getter call (one for getX(), one for getY()). Assuming that I have plenty of elements on the screen, this could lead to a memory and performance impact.
The second approach has the disadvantage of "negative" thinking. If I want an element be drawn at point 100/100 I must translate the canvas to -100/-100 as I would draw on 0/0. If I restore the canvas after that, the result would be the element be drawn on the wanted 100/100. I am not sure if this negative thinking would result in a heavy impact on code maintainability and decreased understanding (never even started to think about introducing bugs by simply forgetting to negate something...).
Does someone have a tip which way should be preferred?
Solution
It seems that indeed both solutions must be combined.
My assumption on the second approach is totally wrong. If I translate an element to 100/100, the point of origin will be changed to 100/100. The same applies, of course, to the canvas. The negative thinking was total nonsense of me.
The combined result will be the following:
- Each element that will be drawn, has his own Matrix which contains rotation, translation and scale.
- The canvas will be saved via
save()
, with the provided methodconcat(Matrix matrix)
the matrix of the element can be applied. The drawing will be done and the canvas will be restored withrestore()
. - Each drawable Element which is the parent of other drawables will loop over the children and save, concat and restore in the same way.
This enables the implementation of a 2D scene graph without any big implementation work.
OTHER TIPS
For performance reasons, using the internal matrices method is probably faster since it allows libraries to be hardware-accelerated automatically, if that's what you are doing. Then again, I'm not entirely sure if it would be hardware accelerated.
#2 is the fun way. It definitely would give you more power and flexibility in the long-run. Also, you might be able to combine the two.
There's also #3: when you say drawable element, and if you are using Android Drawables, you can create a custom Drawable class.
I don't think there's a perfect way to do this