How does double buffering in applets work? - java

I'm writing this Java code from a video tutorial in youtube on making Java game applets. However, the instructor didn't really explain how an applet's update method does double-buffering as he calls it.
import java.awt.*;
import java.applet.Applet;
public class Game extends Applet implements Runnable {
private Image i;
private Graphics g2;
private int x, y, dx = 1, dy = 1, radius = 10;
...
public void update(Graphics g) {
if ( i == null ) {
i = createImage(getHeight(), getHeight());
}
g2 = i.getGraphics();
g2.setColor(getBackground());
g2.fillRect(0, 0, getWidth(), getHeight());
g2.setColor(getForeground());
paint(g2);
g.drawImage(i, 0, 0, null);
}
public void paint(Graphics g)
{
x+= dx;
y+= dy;
g.setColor(Color.RED);
g.fillOval( x, getHeight() - y, radius * 4, radius * 4);
g.setColor(Color.BLUE);
g.fillOval( getWidth() - x - radius, y, radius * 4, radius * 4);
g.setColor(Color.GREEN);
g.fillOval( x, y, radius * 4, radius * 4);
g.setColor(Color.YELLOW);
g.fillOval( getWidth() - x , getHeight() - y , radius * 4, radius * 4);
}
How is flickering being removed here? What is the use of having an Image object? What is the use of having another Graphics object, why not use the parameter Graphics?

The general idea of double buffering is that drawing is slow, and if you have a lot to draw the user will notice this in the form of flickering. Instead, you do all your drawing to an off screen image (a buffer). Then when you are ready, you swap the offscreen buffer so it is now drawing on screen. This swap happens very quickly, since it's usually just updating a pointer.
The user no longer sees the flickering because all the drawing work is done off screen.
The code you posted is a variant of double buffering. All the drawing work is done off screen to the Image object i. Once the drawing is complete, the image object is then copied to the component, in the last line of the update method.
I say variant because the code above does not swap the buffers. Instead, you are copying the off screen buffer i to the on screen one. It still eliminates flicker because all the rendering work is done off screen. Copying the image is still quite fast.
The second Graphics object is there because you should always use the one provided by the component when drawing. So, the code above asks the Image object for its Graphics object. However, there is no real reason to store g2 as a member variable, you can just request it each time in update.

Related

Quickly rotate image section in Java

I would like to rotate, scale, and translate a section of an image. For example, I have a sprite-sheet with columns and rows of sprites. I can draw the section I want onto a temporary BufferedImage, then transform that temporary image onto the main graphics, but this is a very slow operation.
How can I make this much much faster? It needs to occur more than 100 * 60 times per second.
public void Draw_WorldSpace(Graphics2D g, double x, double y, double angle, double deltaTime) {
// setup portion of image to transform
BufferedImage tempImage = new BufferedImage(sourceRectangle.width, sourceRectangle.height, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2 = tempImage.createGraphics();
g2.drawImage(image, 0, 0, sourceRectangle.width, sourceRectangle.height, sourceRectangle.x, sourceRectangle.y, sourceRectangle.width, sourceRectangle.height, null);
g2.dispose();
// setup a transformation object
AffineTransform transform = new AffineTransform();
// match view rotation
transform.translate(GameLogic.viewPort.GetCanvasCenter().x, GameLogic.viewPort.GetCanvasCenter().y);
transform.rotate(Math.toRadians(GameLogic.viewPort.GetAngle()));
transform.translate(-GameLogic.viewPort.GetCanvasCenter().x, -GameLogic.viewPort.GetCanvasCenter().y);
// set to position
transform.translate(x - GameLogic.viewPort.GetViewPortCenter().x + GameLogic.viewPort.GetCanvasCenter().x, y - GameLogic.viewPort.GetViewPortCenter().y + GameLogic.viewPort.GetCanvasCenter().y);
// rotate
transform.rotate(Math.toRadians(angle));
// center on sprite
transform.translate(-sourceRectangle.width / 2, -sourceRectangle.height() / 2);
// draw the sprite
g.drawImage(tempImage, transform, null);
}
Ultimately I did what Hovercraft Full Of Eels suggested. I wasn't the biggest fan of the solution simply because it requires a lot of memory overhead. But ultimately, it worked like a charm and even game me more streamlined control over the graphics, so that's really cool.

Image/Texture scroll/shift (wrap)

Does anyone know whether libGDX has a method for scrolling/shifting an image/texture within itself?
To explain; I would like to be able to scroll the contents (pixels) of an image, either vertically or horizontally within its own region. For example, if an image is shifted 1 pixel to the right, all pixels move 1 to the right and those on the right-most-edge are wrapped to the left-most-edge. The image size does not change, only the positioning of the pixels within it change.
I have mainly been working with the Sprite class, it can do a lot (scale, rotate, etc) but shift/scroll as I need it, isn't there.
Before writting the method myself, I thought I'd ask here...
The following worked for me, this was provided by Kush:
float delta = 0f;
// In the Actors act method
delta += Gdx.graphics.getDeltaTime();
// Horizontal
batch.draw(texture, 0, 0, width, height, 0 + delta * 10, 1, 1 + delta * 10, 0);
// Vertical
batch.draw(texture, 0, 0, width, height, 1, 0 + delta * 10, 0, 1 + delta * 10);
You won't need Sprite for this, draw directly Texture using batch. For wrapping first set
Texture texture = new Texture("example.png");
texture.setWrap(TextureWrap.Repeat, TextureWrap.Repeat);
then draw using uv
batch.draw(texture, x, y, width, height, u, v, u2, v2);
or any other method that suits you in SpriteBatch.

How to add an image to an already drawn box using LWJGL & Slick2D

I am creating a simple 2D game for my computer class. I already have a box that moves around through a level. But, i want to change this box to instead display a stickman standing that I drew. Then, more specifically, i would like in my MovementInput class (where i assign movements to the buttons), I want when neither A(my moving left button) or D(my moving right button) OR when both A and D are held down to display this standing.png image. How would i go about doing this?!
This is my code for drawing the box
public class Man extends AbstractMoveableEntity {
public Man(double x, double y, double width, double height) {
super(x, y, width, height);
}
#Override
public void draw() {
glColor3d(0, 0, 255);
glRectd(x - width / 2, y, x + width / 2, y + height);
}
}
And in my MovementInput class, this is my code for the A&D thing
if ((Keyboard.isKeyDown(Keyboard.KEY_D) &&Keyboard.isKeyDown(Keyboard.KEY_A))||(!Keyboard.isKeyDown(Keyboard.KEY_D) && !Keyboard.isKeyDown(Keyboard.KEY_A))) {
man.setDX(0);
}
Use something called Texture Atlases for multiple frames of animation and a simple timer to loop through the frames. ThinMatrix on YouTube has a really good tutorial for this here as well as many other concepts.

Inaccurate Graphics2D.draw(Shape) method

I make a game and when I animate entity with low velocity I use g.FILL(new Ellipse2D.Float(x, y, r, r)); because it renders smooth and fluent motion.
It work fine (in Example blue left circle). But when I needed just an outline of circle I used g.DRAW(new Ellipse2D.Float(x, y, w, h)); and it didn't work and I absolutely don't know what's wrong. No fluent motion, circle jumps pixel over pixel and it looks ugly (in Example red right circle). Graphics2D.draw(Shape) count float values like int values.
This Example code demonstrate it, don't study it a lot, just import, run and watch.
public class Example extends JFrame {
public static void main(String[] args) { new Example(); }
public Example() {
setBounds(50, 50, 400, 400);
setVisible(true);
while(true) {
x1 += 0.01;
y1 += 0.01;
x2 -= 0.01;
y2 += 0.01;
try {
Thread.sleep(16);
} catch (InterruptedException e) {
e.printStackTrace();
}
repaint();
}
}
double x1 = 50 , y1 = 50;
double x2 = 250, y2 = 50;
#Override
public void paint(Graphics gg) {
Graphics2D g = (Graphics2D) gg;
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g.setColor(Color.BLUE);
g.fill(new Ellipse2D.Double(x1, y1, 100, 100));
g.setColor(Color.RED);
g.draw(new Ellipse2D.Double(x2, y2, 100, 100));
}
}
So how can I fix it without tricks like filling two cirle or moving image of circle? Thanks for every answer.
I would guess the problem is that you didn't invoke super.paint(...) as the first statement in the method which means you lose some of the default painting functionality.
However, that is NOT the proper solution as you should NOT be overriding the paint() method of a JFrame at all. Custom painting is done by overriding the `paintComponent(...) method of a JPanel and then you add the panel to the frame. Read the section from the Swing tutorial on Custom Painting for more information and working examples.
Also, don't use a while true loop for animation. Instead you should be using a Swing Timer to schedule the animation (the tutorial has a section on Swing Timers). Your code only works because you are NOT creating the GUI correctly. The GUI should be created on the Event Dispatch Thread. The Custom Painting tutorial shows you how to use the invokeLater(...) method to do this. The tutorial also has a section on Concurrency in Swing which explains this concept in more detail.
With drawing circles/ovals/ellipses in Java, the "pure" mode often helps drawing it with subpixel accuracy:
g.setRenderingHint( RenderingHints. KEY_STROKE_CONTROL,
RenderingHints.VALUE_STROKE_PURE)
My other answer has more details: https://stackoverflow.com/a/31221395/1143274

Why gif animation doesn't animate when using it in paintComponent()?

I'm using paintComponent() to paint a gif animated image at the backgound of JPanel.
It shows up the gif but doesn't animate.
I use java 1.5 and i know that i can use label with icon.
Does any body know why and how to fix it?
private static class CirclePanel extends JPanel {
ImageIcon imageIcon = new ImageIcon(BarcodeModel.class.getResource("verify.gif"));
Point point = f.getLocation();
protected void paintComponent(Graphics g) {
Graphics gc = g.create();
Graphics2D g2d = (Graphics2D) g.create();
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.3f));
g2d.setColor(Color.BLUE);
g2d.drawImage(imageIcon.getImage(), getWidth() / 2, getHeight() / 2, null);
g2d.drawRect(0, 0, getWidth(), getHeight());
g2d.setStroke(new BasicStroke(10f,BasicStroke.CAP_ROUND,BasicStroke.JOIN_MITER));
g2d.setFont(g.getFont().deriveFont(Font.BOLD | Font.ITALIC,15f));
g2d.drawString("Wait Please ...",getWidth()/2-imageIcon.getIconHeight()/3,getHeight()/2+imageIcon.getIconHeight()+15);
g2d.dispose();
}
This is the gif image.
Edited: just add image observer to the g2d.drawImage() method.
g2d.drawImage(imageIcon.getImage(), getWidth() / 2, getHeight() / 2, this);
The reason is that the standard Java ImageIO API only loads the first image of the gif.
How to fix? Google for a Gif Loader for Java, which loads every image of the gif. Then you have to paint the right image at the right time. An alternative way would be to have different png files representing each time one frame of the animation.
Update: Well... Actually, after doing some research, it looks like the way you did it actually loads all the frames of the animated gif. The reason for it is that the ImageIcon's method getImage() always returns the first image.
To fix it, you can try this (I'm not sure if it will work...)
Instead of using Grahpics.drawImage(), use ImageIcon.paintIcon(). Like this:
imageIcon.paintIcon(this, g2d, getWidth() / 2 - imageIcon.getIconWidth() / 2, getHeight() / 2);
Image observer will take care of it.
You should just pas the observer to the g2d.drawImage(); as below.
g2d.drawImage(imageIcon.getImage(), getWidth() / 2, getHeight() / 2, this);
In my case 'this' refer to CirclePanel which extends JPanel, it can be any thing for example if you are using gif as a icon for a button, you should use button as image observer.

Categories