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. :)
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 need to capture more pixels than the width of the screen contains to save a higher res image. I figure the only two options are to pack more pixels into the screen with some Matrix command, or to make the actual view larger than the screen (which I don't think is possible.) I should probably make it known that I'm using OpenGL ES 2. Any help?
The technique you're looking for is called Render to Texture. Essentially you create an offscreen framebuffer, and redirect your draw calls to this framebuffer instead of the default.
You can make your framebuffer as big as you want (within hardware limitations).
This looks like a reasonable example:
http://blog.shayanjaved.com/2011/05/13/android-opengl-es-2-0-render-to-texture/
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 want to create a number of straight lines connecting small circle shapes. then I want to change the color and width of the lines from within my program. I was thinking of using Canvas to do this but there does not seem to be a way to access individual shapes drawn on canvas to change their attributes after they are drawn. What would be an easy way to implement this?
First of all, what version of Java and which UI toolkit? AWT's Canvas is very dumb, it will not even "remember" what you have painted; when you minimize and restore the window, it will send a paint() event because it wants to be repainted.
The easiest way (if you are using AWT and stuck to Canvas) is to have a List of your shapes (either one list for all or one for circles and one for lines, or whatever you like) and make your paint method draw all of them. Then update the objects in your list. When you are done updating, call repaint() on your canvas and it will call paint() for you again.
You don't paint shapes onto a Canvas if you're using Graphics and Graphics2D functions like drawRect, drawPolygon, drawOval, etc. Once they're drawn, they don't exist as shapes anymore. You just have an image with filled-in pixels.
As mihi said, you may have to keep track of the shapes you're trying to draw, then regenerate your image if it changes. Perhaps you could also "unpaint" a shape you're trying to change by painting over it in the background color and repainting the changed shape.
I have to create a special TextFieldUI that draws an image as the background. That image contains some alpha components. However, whenever a character is written in that text field, first it redraws the background and then draws the character. This is fine when the background contains no alpha components, but after a few characters have been typed, the alpha areas sum up to become black.
The only way I can see around this is in the paintBackground method of TextfieldUI (which I'm overriding), I have to first sample the color of the background at that location, paint the entire graphics component that color, and then paint my background.
Does anyone know how to sample the color of a pixel when all I have access to is the Graphics object?
Is there a better way to draw a custom image as the textfield background other than overriding paintBackground in TextfieldUI?
Thanks
I haven't tried it before, but Swing is built on top of AWT, and the Robot class had a way of sampling specific pixels in the AWT
Well, I don't know what your custom code looks like in the paintBackground method, but I would make sure you fill in the text field background before you draw the image.
I'll let you decide if its "better" or not, but you can use the Background Panel which allows you to add an image to a panel. Then you add the text field to the panel (the text field is automatically made non-opaque so the image shows through). Then you add the panel to the GUI.
If that doesn't work then it would be nice to have a demo of your code so we can see whats actually happening.
When you override paintBackground, you're calling the superclass version first, right? It already lays down a background-color rectangle that would give your image a fresh-start.
Rather than 'sampling' the background color, it's probably already correct (the superclass paintBackground code gets it from the parent component if not locally set). If that default is not correct, set it in initial interface construction. (Your field isn't being overlaid on other complicated arbitrary interface of unknown solid colors, is it?)