I started working on the sample Finger Paint app in the Android SDK to get more familiar with graphics. Lately I've been trying to implement undo/redo, and I've ran into road blocks every way I've tried. I've found a few threads about this, but none have gotten me past these issues. Here are my main 2 trials:
Strategy 1:
Save a stack of the paths (or canvases) and on undo clear the screen and redraw each path except the last one (or reinstate the most recent canvas).
The problem here is likely simple, but I just can't get the view to redraw anything. How do I draw saved paths (or restore a saved canvas)?
Strategy 2:
Save a stack of Bitmaps using getDrawingCache() after each touch. On undo, put the last bitmap back.
The saving has to be ran via post() from a runnable so it executes after onDraw() finishes (post adds it to the system message line after invalidate()). The issue is that when ran from the runnable getDrawingCache() always returns the initial version of the painting, like it can't see any changes after the first.
Why does getDrawingCache(), when called from a runnable, not see the current state of the view?
I've been fighting with this a while. Thanks.
case MotionEvent.ACTION_UP:
touch_up();
invalidate();
Runnable r = new Runnable(){
#Override
public void run() {
myView.storeView();
}
};
myView.post(r);
}
public void storeView(){
historyCount++;
if(historyCount > historySize) historyCount = 6; //We don't want more than 6
history.add(Bitmap.createBitmap(myView.getDrawingCache()),historyCount);
}
For strategy 1, you need to define a data structure that represents all the information needed to render a part of the drawing. So, for instance, if you draw a segment of the drawing by tracking the user's touch position, define a data structure that consists of the current color, drawing shape, and an ArrayList of coordinates used generated by one user gesture. As you follow the user's touch, drawing to the screen, also append the touch coordinates to the ArrayList for the current gesture. When the touch ends, push the data structure onto the undo stack and wait for the next user gesture to create the next structure instance and start populating it.
If you have various gestures (fill, freehand trace, straight line, etc.), you can have a separate structure for each. They can all inherit from an abstract class so they can all go on the stack.
The second strategy strikes me as a horrible memory hog. I think we'd have to see your code to understand why it isn't working as intended.
Related
The way I understand the HERE Android SDK is that there's a MapView that has a backing Map object. Adding objects, setting the center, zooming etc should be performed on the Map object and this eventually reflects on the MapView.
Question:
Are there any restrictions on what thread the operations on the Map object must be performed? For example, must they all be called on the UI thread? Also, should multiple subsequent calls be synchronized?
I ask this because I want to make multiple changes in a Map (resize the map view, change some visible layers, change the scheme, add a MapRoute and zoom out to the bounding box of the route). When I try this, it sometimes works but sometimes doesn't. Sometimes, only some of the operations are applied. For example, everything works except the zoom is not applied.
I know there are some listeners that can help me:
Map.OnTransformListener - this I can use to let me know when a zooming operation has ended
Map.OnSchemeChangedListener - this I can use to know when a scheme change event has ended
What is not clear to me from the documentation is what other operations constitute a "transform"? Which of these operations must be performed in a synchronized fashion?
For example, is the following code expected to behave correctly?
map.setCenter(coordinate, Animation.BOW, 18, 0f, 60f);
map.addMapObject(routeObject);
map.setVisibleLayers(layersToShow, true);
map.setScheme(Map.Scheme.NORMAL_DAY)
Note that in the above example, I'm proceeding to make changes immediately after setCenter even before the animation is complete. Is this the expected way to use the API?
There is no restriction on what thread you call the API from. Internally, all calls are synchronized and thread safe.
What you are looking for is the MapView#executeSynchronized API. [link] This will batch up a few operations into one screen redraw. [At least when I wrote that API a few years ago]
What you are experiencing happens because the underlying rendering thread started drawing some of the commands from the calling thread. This caused subsequent calls to lose effect.
Talking in context of a game based on openGL renderer :
Lets assume there are two threads :
that updates the gameLogic and physics etc. for the in game objects
that makes openGL draw calls for each game object based on data in the game objects (that thread 1 keeps updating)
Unless you have two copies of each game object in the current state of the game you'll have to pause Thread 1 while Thread 2 makes the draw calls otherwise the game objects will get updated in the middle of a draw call for that object ! which is undesirable!
but stopping thread 1 to safely make draw calls from thread 2 kills the whole purpose of multithreading/cocurrency
Is there a better approach for this other than using hundreds or thousands or sync objects/fences so that the multicore architecture can be exploited for performance?
I know I can still use multiThreading for loading texture and compiling shaders for the objects which are yet to be the part of the current game state but how do I do it for the active/visible objects without causing conflict with draw and update?
The usual approach is that the simulation thread after completing a game step commits the state into an intermediary buffer and then signals the renderer thread. Since OpenGL executes asynchronously the render thread should complete rather quickly, thereby releasing the intermediary buffer for the next state.
You shouldn't render directly from the game state anyway, since what the renderer needs to do its works and what the simulation produces not always are the same things. So some mapping may be necessary anyway.
This is quite a general question you're asking. If you ask 10 different people, you'll probably get 10 different answers. In the past I implemented something similar, and here's what I did (after a long series of optimisation cycles).
Your model-update loop which runs on a background thread should look something like this:
while(true)
{
updateAllModels()
}
As you said, this will cause an issue when the GL thread kicks in, since it may very well render a view based on a model which is half way through being rendered, which can cause UI glitches at the best case.
The straight-forward way for dealing with this would be synchronising the update:
while (true)
{
synchronized(...)
{
updateAllModels();
}
}
Where the object you synchronize with here is the same object you'll use to synchronize the drawing method.
Now we have an improved method which won't cause glitches in the UI, but the overall rendering will probably take a very severe performance hit, since all rendering needs to wait until all model updates are finished, or vise versa - the models update will need to wait until all drawing is finished.
Now, lets think for a moment - what do we really need to be synchronizing?
In my app (a space game), when updating the models, I needed to calculate vectors, check for collisions and update all the object's positions, rotations, scale, etc.
Out of all these things, the only things the view cares about is the position, rotation, scale and a few other small considerations which the UI needs to know in order to correctly render the game world. The rendering process doesn't care about a game object's vector, the AI code, collision tests, etc. Considering this, I altered my update code to look something like this:
while (true)
{
synchronized(...)
{
updateVisibleChanges(); // sets all visible changes - positions, rotations, etc
}
updateInvisibleChanges(); // alters vectors, AI calculations, collision tests, etc
}
Same as before, we're synchronising the update and the draw methods, but this time, the critical section is much smaller than before. Essentially, the only things which should be set in the updateVisibleChanges method are things which pertain to the position, rotation, scale, etc of the objects which should be rendered. All other calculations (which are usually the most exhaustive ones) are performed afterwards, and do not stop the rendering from occurring.
An added bonus from this method - when you're performing your invisible changes, you can be sure that all objects are in the position they need to be (which is very useful for accurate collision tests). For example, in the method before the last one, object A moves, then object A tests a collision against object B which hasn't moved yet. It is possible that had object B moved before object A tested a collision, there would be a different result.
Of course, the last example I showed isn't perfect - you will still need to hang the rendering method and/or the updateVisible method to avoid clashes, but I fear that this will always be a problem, and the key is minimizing the amount of work you're doing in either thread sensitive method.
Hope this helps :)
So, I'm developing a game and I'm using Canvas with SurfaceHolder to update the screen every time an object is supposed to move. That much is working fine so far. Now, the problem happens when I want to stop drawing to the Canvas and just leave it as it is based on the last drawing commands.
So one way that I tried was to simply return from the function that I call when drawing when the end condition is met. However, when I do this, the canvas starts rapidly alternating between the commands sent right when the condition was met and the commands sent one iteration before. I have no idea how or why this is happening since the drawing function is not executing any of its draw commands after the condition is met. Can anyone explain how the canvas can keep refreshing itself when it doesn't get any draw commands?
The code in the thread for locking and unlocking is pretty simple:
public void run() {
Canvas c = null;
try {
c = sh.lockCanvas(null);
synchronized(sh) {
drawCan(c);
}
}
finally {
if(c!=null) {
sh.unlockCanvasAndPost(c);
}
}
}
and the drawCan function is structured like this:
public void drawCan(Canvas c) {
/* Check if user's health is greater than 0. Don't draw anything if it is less */
if(userHealth<=0) {
return;
}
/* Drawing commands - drawRect(), drawBitmap(), etc are run here */
}
Now normally, this runs fine. But when the userHealth condition is met, the Canvas constantly alternates between the last commands sent and the commands right before that. I know that the draw functions are not being called because I used Log.d() in that area of the code and no messages appeared on LogCat after the condition was met. Can someone explain why this is happening and what the solution would be?
The Canvas is double- or triple- buffered and not erased between frames. When you call lock/unlock, you're switching between previously-rendered buffers.
If you move your if(userHealth<=0) test into run() and use it to avoid calling lock/unlock, you should get the desired effect.
For a much longer explanation about what's going on, see this post.
Update: I realized today that I'd omitted a detail (from the answer and ensuing comments). It doesn't change the answer but it may be useful to know.
The lockCanvas() method takes an optional "dirty" rect that allows you to do partial updates. If you use this, and Surface is able to keep track of the "front" buffer you just rendered, the system will copy the non-dirty contents of the front buffer to the back buffer as part of locking the Surface (see copyBlt() in Surface.cpp).
The system doesn't guarantee that this will work, which is why the "dirty" rect is an in-out parameter. If the front buffer isn't available to copy from, the lock method will just expand the dirty rect to cover the entire screen. In either case, your app is responsible for updating every pixel in the "dirty" rect; if you don't, you get the effects you observed.
This does mean that the Surface is explicitly trying to be double-buffered when used with a Canvas, which would explain why you're seeing two frames alternating rather than three even though SurfaceView is generally triple-buffered. (Which is the thing that has been nagging at me since I wrote this up.) It's also possible to be double-buffered if you're just not generating frames fast enough to require triple-buffering.
I am using GLSurfaceView for my application's core drawing process.
I do my drawing onDrawFrame ( a function that gets called as often as possible, like thread loop ).
However when touch event occurs I use different class that manages all the user input.
Problem rises when the this "input manager" tried to talk to "draw manager".
my input manager tells draw manager a new set of coordinates (distorted shape, modified by the user) that draw manager should draw.
However since input manager passes this new drawing items very frequently I think this unexpected behavior occurs :
The shape that's being rendered flickers (disappears for a sec) or at some point, when "drawing manager" receives and tried to set a new buffer data, it throws out of index error(since I need to move buffer index as I read the buffer; if I try to set a new buffer data while I am reading also as well, it results in an unexpected behavior).
I lack experience to deal with this situation that I am facing. What will be a way to make sure "storing" and"reading" do not occur at the same time?
I wanted to write some simple game in android using opengl es but immediately ran into trouble with the main game loop. As I read here: http://developer.android.com/resources/tutorials/opengl/opengl-es10.html the app calls public void onDrawFrame(GL10 gl) every time it needs to redraw the surface. Or smth like that. My problem was - how to create an update loop that is independent of draw calls. I mean - it can't work like that, I can't update the game logic only when the device (app?) wants to redraw the surface (or am I wrong?).
After some googling I came to a conclusion that I have to create another thread for update loop. But then I had another problem - with one thread taking care of drawing and another one taking care of updating the game logic I didn't know how to make them cooperate. First, they were two separate classes (at least in my implementation) so they couldn't use the same game variables and objects (sprites, timers, different variables, counters and so on... pretty much everything these two classes needed to do their jobs). Now I think I could somehow pack them both into one class. But - second, I needed to synchronize the two threads somehow.
Finally, I came out with this general idea:
3 classes:
public class MyRenderer implements GLSurfaceView.Renderer with onSurfaceCreated() method taking care of drawing
public class UpdateThread implements Runnable with run() and update() methods. run() was calling update() method exactly 60 times a second (I wanted a fixed step loop)
public class SpritesHolder used as a container for all the game objects/variables/stuff (like sprites, timers, state variables and so on...) with all the fields public.
So basically the SpritesHolder class was a box holding all the needed variables in one place, so MyRenderer and UpdateThread classes could access it and use it.
As for synchronization - I just did smth like this:
public void update(float delta)
{
synchronized (spritesHolder)
{
// whole method code...
}
}
and:
public void onDrawFrame(GL10 gl)
{
synchronized (spritesHolder)
{
// whole method code...
}
}
so that both threads didn't use the spritesHolder at the same time. So updates were done 60 times per second and drawing took place whenever app (device?) needed.
A lot of talking, sorry, I've almost finished writing this post. ;) So anyway - this (described above) works and I even did write some game based on this 'template' but I think my ideas might be crazy and one can desing it all a whole lot better. I'd be very grateful for all comments and advices.
Your solution probably will work, though it might be suboptimal for performance. If you think about it the render thread and the update thread don't really need to be 100% exclusive.
I recently spent a while thinking about this for my game, and this is what I ended up coming up with (not necessarily better, but just something to think about):
For every renderable object, I have an object owned by the update thread, and another object owned by the rendering thread that is just a plain container that contains instructions for how to draw an object (model matrix, uniform values, meshID, etc). I run through the update thread computing all the final positions and values for my renderable objects, and then I synchronize for a small window where I pass any values that changed during that frame to the objects in the renderable thread. Then as soon as the new information has passed, the frame rendering begins while the next update frame runs simultaneously. Because there's only a small exclusion window it allows the update and draw threads to run simultaneously most of the time.
I didn't use this with OpenGL yet, but UpdateThread should be a TimerTask.
In you activity launch it with
new Timer().schedule(new UpdateThread(view), 0, 15); //where view is your view, and 15 is the wait time
in your TimerTask call the view with a Handler. e.g (in your view class)
Handler refreshHandler = new Handler() {
public void handleMessage(Message msg) {
//Handle it; e.g. for canvas invalidate()
}};
In your UpdateThread run method do this:
view.refreshHandler.sendMessage(new Message());
Now it is independent of your gameloop. Furthermore your gameloop should not be in the MainActivity but in a Thread (unidirectional OO).