Can not make a bitmap from a complicated view with state machine.
I have a RelativeLayout in which a dynamic tree of views handles touchevents to draw graphics. It uses a state machine to keep track of events like down, move and up and perform various drawing activities.
Now I want to make a copy (bitmap) of this RelativeLayout every time the view changes and display on the second screen. I have tried both methods I found online:
draw(theSecondCanvas);
Bitmap cache = getDrawingCache();
Both work most of time except occasional failure. The problem is both methods will eventually call every child views' draw() one more time to draw on the second canvas. But the state machine has changed to the different state based on the last touch event. It gives different drawing result or sometime error with null object reference because the additional drawing request has no touch event associated with it.
One option is for me to fix the complicated logic of state machine in the tree of views so it can handle an additional stateless drawing on the second canvas.
But I would think it has to be a simpler way to capture a bitmap from a view without drawing everything again. The view has done all the drawing inside already. It doesn't make sense to repeat the same work on the second canvas just to get a copy of bitmap.
Any suggestions? Thanks in advance!
I realized that off-screen rendering is not necessary in my case. I can intercept default canvas and draw on my own canvas with a bitmap. Then copy the bitmap to the default canvas. This solves the problem.
Related
I don't think I understand how the render method works.
From what I read online / saw on youtube tutorials, I gathered that the render method is a looping function that you can use to keep your game updated and read users' inputs. When you want to draw something in the screen you do so in this method, and before drawing anything you clear the screen.
But if I want to draw something stationary, wouldn't it be better to draw it outside the render method (so the computer doesn't have to clear the screen and redraw everything many times)?
What am I missing?
You can't draw outside the render method, because it's the method called on the OpenGL thread. You can't draw to OpenGL from other threads.
If your entire screen is frequently static for more than a few ms, which might be the case in something like a card game, you can disable the continuous refreshing of the screen using Gdx.graphics.setContinuousRendering(false). This will save energy because the GPU and CPU won't have to work as hard. See here for instructions on using it.
As for why this typically isn't done:
Think of a "frame buffer" as a bitmap image in memory that can be drawn to and then shown on screen. Most mobile rendering is done with double-buffering. This means while one buffer is being drawn to (the back buffer), the front buffer that was drawn to on the previous frame is being rendered directly to the screen. They swap back and forth each frame for faster rendering.
The way graphics work is that each item that's drawn modifies the color of pixels in the frame buffer where the item is drawn. Items may be masked or be translucent, and these will alter the color of pixels behind them. The original color of those pixels are lost once something is drawn in front and modifies them
So, even if some item on your screen is static, if there are other items on the screen that move or change color, and they overlap the static item (either in front of or behind), you still have to redraw the whole screen every time anything changes.
If one area of the screen is static and never overlapped by dynamic objects, and the dynamic objects are contained entirely within a rectangle, you could potentially set a viewport that limits drawing to the dynamic area and avoid clearing the whole screen. However, GPUs are designed specifically to be efficient at clearing the whole screen. Because of double-buffering, if you don't clear the whole screen, it's actually likely to harm performance because if you don't clear it, the contents of the screen have to be copied between the front and back buffers before you can start drawing the next frame.
Another strategy is if you have a static object that is very complicated and taxing for the GPU to draw because it has lots of layers or a complicated shader, you could draw it to an off-screen frame buffer object (FrameBuffer class in libGDX) one time, and then render that FrameBuffer's texture to the screen on each frame like a sprite.
I'm making a UI application in java and I was trying to draw some graphics to represent a compass in a window. I'm handling the rotation with the mouse dragged event on my canvas but the problem is that everything in my canvas is rotating. I'd like to know if I can handle every elements I draw in my canvas separately so only my arrow will move and not the whole canvas.
Thanks
Presumably you've got a draw loop that draws a bunch of things. Background, compass, arrow for the compass. Maybe some other things.
When you draw with a canvas you issue commands to the context that are akin to loading up a paintbrush with paint.
If you want to paint a red line and then a blue line you pick up some red paint, paint one line, then clean your brush and pick up some blue paint and paint that line.
The canvas context is exactly the same. What you want to do here is paint a bunch of things on a normal canvas context. Then you want to save the context with ctx.save() and do your rotations.
When you translate or rotate or even just set a fill on the context you aren't changing things that were already done, you're just saying "for everything after this point, apply these operations."
So then you paint the compass arrow/needle.
Then call ctx.restore() and continue on your merry way. This will stop the rotation from happening to things drawn after the arrow.
the save and restore functions of the context keep track of the old state so that you aren't drawing everything after the needle with a rotated context. It's kind of like washing a paintbrush, only better, because you can remember that it used to have blue on it instead of having to wash it clean every time.
By the way, if you do want to reset your canvas context to its default state completely (black brushes, default transform, no shadows, etc), you can simply do canvas.width = canvas.width and it will give the context a full reset.
I asked a question about this earlier but received no responses, so I'm trying again.
I need to do a rendered 2D picture with some accompanying labels and graphics on a Motorola Xoom, Android 3.0. Although what I need can be done with just a SurfaceView (Canvas) or just a GLSurfaceView, I would really like to use both because the rendering is faster with the GLSurfaceView, and the labeling and graphics are easier with the SurfaceView. The visual layout is as shown below.
I tried to put the SurfaceView on top by declaring it in the layout XML after the GLSurfaceView. The SurfaceView is transparent (except for where I explicitly draw stuff) so that the GLSurfaceView can still be seen.
This approach has worked pretty well with one huge exception. Anything that I draw on the SurfaceView that is in the GLSurfaceView region does not show up at all. To verify this I drew some text that was right on the boundary (some in the shared region, some just in the SurfaceView region), and it was chopped off at the GLSurfaceView boundary. I have tried using the "bringToFront" method to fix this, but it hasn't worked.
Can anyone give me some ideas on why this isn't working or what I can do about it? Is it that the GLSurfaceView is in front, or is that the GLSurfaceView writes directly to the video memory, so it doesn't matter if something is in front of it?
The way SurfaceViews work will make it impossible to do what you want. You will have to render your text inside the GLSurfaceView.
Never try to overlap a GLSurfaceView with anything (above or below). At best it breaks on your device and you catch it early, at worst it works on one device and not others. Bite the bullet and do everything in a GL view or none of it. If you need the speed then GL is the way to go.
we should set setZOrderMediaOverlay and setZOrderOnTop to true value
setZOrderMediaOverlay
Added in API level 5
void setZOrderMediaOverlay (boolean isMediaOverlay)
Control whether the surface view's surface is placed on top of another regular surface view in the window (but still behind the window itself). This is typically used to place overlays on top of an underlying media surface view.
Note that this must be set before the surface view's containing window is attached to the window manager.
Calling this overrides any previous call to setZOrderOnTop(boolean).
setZOrderOnTop
Added in API level 5
void setZOrderOnTop (boolean onTop)
Control whether the surface view's surface is placed on top of its window. Normally it is placed behind the window, to allow it to (for the most part) appear to composite with the views in the hierarchy. By setting this, you cause it to be placed above the window. This means that none of the contents of the window this SurfaceView is in will be visible on top of its surface.
Note that this must be set before the surface view's containing window is attached to the window manager.
Calling this overrides any previous call to setZOrderMediaOverlay(boolean).
Please refer to this link :
http://developer.android.com/reference/android/view/SurfaceView.html#setZOrderMediaOverlay(boolean)
You gyus have seen those flash based flip books. I want to create the same in Java. I am using JTextArea for leaf of the book. What I want to know is how can I go about implementing the page flip effect, by overriding the componentPaint method combined with Mouse/KeyListener perhaps?
You would need to render the existing page into an off-screen buffer, then transform the buffer to render the page flip.
So,
create an off-screen image buffer of the size of the screen.
Get the graphics context of the buffer and call super.componentPaint with that context
You've now got your page rendered 'flat' into your off screen buffer
With your on-screen context,
clear the area,
copy the offscreen page scaled to show the flip
draw an alpha gradient over the top to 'shade' the page so it looks 3D
You'd need to drive this in a thread to repeatedly invoke the re-draw whilst the animation plays out. So Set a 'pageIsTurning' flag, and 'percentageTurned' that will indicate to the paint method that it needs to do the special drawing and where it is in the animation. Update the percentageTurned flag as you repeatedly call the paint method, then once things are complete, reset the flag and allow the componentPaint method to default to super.componentPaint.
Instead of reinventing the wheel, try this awesome source code for this custom JComponent that does exactly what you are asking:
http://lmireport.googlecode.com/svn/trunk/ireport/src/be/savat/components/JBookPanel.java
Enjoy. :)
I am working on an app that will show reverse view from camera. For example, if current view from camera is like:
,
the app should reverse view like:
so user will see constantly reverse view from camera through this app.
I am not very sure how to achieve this. Any help or idea would be highly appreciated. Thanks!
I understand from your answer that you want to display the reversed view in real-time.
I would create a custom SurfaceView and override the onDraw method to split the image in two and reverse the two slices.
Then I would pass the holder of your surface to the camera object like this:
camera.setPreviewDisplay(myCustomSurfaceView.getHolder());
What about simply drawing only half your image at a time?
Create a custom component and override the onDraw. When you draw your bitmap, simply adjust the location and width values so you are only drawing half of the image at a time... of course you will need to draw twice.
You could also do the same thing with a second bitmap.. apply only part of your original bitmap to the second bitmap and do that twice, adjusting the location and width as needed.
Other options are to do some sort of transform, but my guess in the end is that your going to be doing something similar.