Java graphics are flashing
Asked Answered
C

6

10

Okay, I understand your need for an SSCCE, so I created (my first) one.

I managed to replicate the problem with under 200 lines of code. On my system this demo compiled and ran perfectly (only the flickering was still there of course). I stripped everything that had nothing to do with it. So basically we have two source files now: the screen manager and the game manager.

The screen manager: http://pastebin.com/WeKpxEXW

The game manager: http://pastebin.com/p3C5m8UN

You can compile this code with this make file (I use a ported version of Linux' make for Windows): CC = javac BASE = nl/jorikoolstra/jLevel CLASS_FILES = classes/$(BASE)/Game/GameMain.class classes/$(BASE)/Graphics/ScreenManager.class

jLevel: $(CLASS_FILES)
    @echo Done.

classes/%.class : src/%.java
    @echo Compiling src/$*.java to $@ [command: $(CC) src/$*.java ] ...
    @$(CC) -Xlint:unchecked -d classes -classpath src src/$*.java

Where the source files are placed in the /src directory and the classes in the /classes directory.

After compilation to byte-code the game can be started using the following .bat file:

@set STARUP_CLASS=nl.jorikoolstra.jLevel.Game.GameMain
@set ARGUMENTS=1280 1024 32
@java -cp classes;resources %STARUP_CLASS% %ARGUMENTS%

Note that the ARGUMENT variable depends on your own screen settings and that you have to change it so that the game is displayed in the right resolution for your screen.

Coimbatore answered 25/1, 2013 at 10:5 Comment(15)
I haven't read through the code, but have you tried restarting your computer? It often fixes flashing issues for me.Crush
Yes I did, did not help.Coimbatore
Do you still have the problem if you take it out of Fullscreen mode? Are you using hardware acceleration the same on Linux and Windows? You can try this: frame.getGraphicsConfiguration().getBufferCapabilities().isPageFlipping() to see if its hardware accelerated. Make sure its the same on both platforms before ruling it out.Cephalic
Do you hace current drivers installed on the Windows machine?Freighter
Will check this today and post back.Coimbatore
frame.getGraphicsConfiguration().getBufferCapabilities().isPageFlipping() returned true, also when I try to vut out the full screen mode the buffering strategy fails with: Exception in thread "main" java.lang.IllegalStateException: Component must have a valid peer. I'm pretty sure my drivers are up to date though.Coimbatore
I didn't see any draw stuffs with the BufferStrategy?Bourque
No that is somewhere else in the code, I placed that in a rendering method that is called in the game loop. But the execution time of the drawing is small as I already mentioned. Do you want me to post that too?Coimbatore
We can help you if you provide a Short, Self Contained, Correct (Compilable), ExampleSandi
Does the original code from chapter 18 (linked above) run as expected on Windows?Impellent
it really would be useful to see where you actually paint/use your bufferstrategy. also, are you using awt or swing components?Hildagarde
You've a typo here: if (hwnd == null) hwnd.dispose();, although that could not cause the flickering. My advice is to go back to basics with a trivial application that creates a window with a buffer strategy and draws something simple to it. Make sure that works, then keep incorporating parts of the full game until it goes wrong.Impignorate
Have you tried it on another Windows 7 based machine? If so, and it still happens, did they both use the same vendor graphics card? AMD (I don't know about nVidia) can restart the driver and that causes a kind of flash, but I'm not sure if it would be the same as you are describing. Other than that, are you sharing data between the rendering thread and the update thread, and if so, where are you locking in contrast to when you clear and flush the buffer?Roan
Please see the new example all!Coimbatore
Please try my solution, tell me if it is not what you want.Bourque
B
8

I see why it is flickering ----

BufferStrategy is doing a separate painting job from the Component's paint() method and they seem to use different Graphics objects and they are refreshing at a different rate --

when paint() is invoked before show(), it's fine. But

when paint() is invoked after show(), it will repaint the component to its initial blank look -- so flashing happens.


It's very easy to eliminate the flickering: override paint() method of your JFrame (GameMain) as you don't need it to do anything (BufferStrategy can give you more precise control on painting stuffs):

@Override
public void paint (Graphics g) {}

That's all. (I have tested it and it works fine, hope this may help :))


===== Update =====

Instead of overriding paint() method, a better way is to call setIgnoreRepaint(true) for your JFrame (GameMain) -- this method is just designed for such purposes! USE IT!

private GameMain(String ... args)
{
    setIgnoreRepaint(true);
    .....
}
Bourque answered 3/2, 2013 at 14:15 Comment(5)
@Coimbatore I think it will. It is Java's painting scheme, platform-independent. Have you tried it out?Bourque
Right. This is exactly what the code link I posted shows. You call bufferStrategy.show(), not any other.Autogiro
Yes, it did the job :). Thanks.Coimbatore
Apparently this is platform-dependent, why else could this run on Linux without the setIgnoreRepaint(true); line?Coimbatore
Ubuntu running with Gnome desktop yes, with the default JDK installed.Coimbatore
B
1

It may work for you, when you set your hwnd.createBufferStrategy(2) in its own method.

Betthel answered 1/2, 2013 at 10:7 Comment(3)
You mean in the initializeGameEnvironment() method?Coimbatore
should work, but better sth like this: public void createStrategy() { createBufferStrategy(2); strategy = getBufferStrategy(); } and call this, after your first screen is visibleBetthel
Unfortunately it does not work :(, I pasted the createBufferStrategy(2) after screenManager.setFullScreen(displayMode, this); and it still flickers very rapidly. Also I can't why this would work, after all hwnd is a reference to the JFrame and methods called on that reference are exactly the same as calling it from the inner class, right? Thanks for your help anyway, maybe you can find the real error.Coimbatore
B
1

This is how i implement double buffering, might help you get the concept. Note it's implemented in a JPanel, but i think it can be implemented in other containers:

TheJApplet.java:

import java.awt.*;
import javax.swing.*;

public class TheJApplet extends JApplet
{
    private Image myImage;

    java.net.URL GameURL = CheckerGameJApplet.class.getResource("GameIMG");

    String GamePath = GameURL.getPath();

    @Override
    public void init()
    {
        String GraphPath = GamePath+"/";

        File myImage_File = new File(GraphPath+"myImage.jpg");

        try
        {
            myImage = ImageIO.read(myImage_File);
        }
        catch (IOException ex)
        {
            // Add how you like to catch the IOExeption
        }

        final TheJPanel myJPanel = new TheJPanel(myImage);

        add(myJPanel);
    }
}

TheJPanel.java:

import java.awt.*;
import javax.swing.*;

public class TheJPanel extends JPanel
{
    private int screenWidth  = 500;
    private int screenHeight = 500;

    private BufferedImage BuffImg = new BufferedImage
                                         (screenWidth, 
                                          screenHeight,
                                          BufferedImage.TYPE_INT_RGB);

    private Graphics2D Graph = BuffImg.createGraphics();

    private Image myImage;

    public TheJPanel(Image myImage)
    {
        this.myImage = myImage;

        repaint();
    }

    @Override
    public void paintComponent(Graphics G)
    {
        Graphics2D Graph2D = (Graphics2D)G;

        super.paintComponent(Graph2D);

        if(BuffImg == null)
        {
            System.err.println("BuffImg is null");
        }

        Graph.drawImage(myImage, 0, 0, this);

        Graph2D.drawImage(BuffImg, 0, 0, this);
    }
}

Hope this helps, good luck.

Barcroft answered 2/2, 2013 at 18:37 Comment(3)
Calling super.paintComponent() in your JPanel might trigger a repaint of the background - I would skip that line. Also, double-buffering is supported natively in JComponent through setDoubleBuffered(true)Ilise
I made a board game this way and works perfectly, what do you mean by "might trigger a repaint of the background", didn't made much sense to me, can you explain further?. I'll take a look at setDoubleBuffered(true) and check if it will reduce the number of lines in my code, though i kinda remember that i had tried it on my board game and didn't work, no harm in double checking, thanks for the tip and the remark.Barcroft
When you call the super method it will draw the default component look which you don't need if you draw the component's entire content yourself. This can also cause flickering.Ilise
A
1

I have a cross-platform Java AWT-based program with animation. It had flashing problems until I strictly followed the example code at in the Java BufferStrategy documentation. However I'm using an AWT Canvas embedded in a Swing hierarchy, not full screen as you. You can see the code here if interested.

Another thing to note is that the AWT pipeline uses OpenGL primitives for good performance, and OpenGL support is buggy in many video drivers. Try installing latest versions of drivers for your platform.

Autogiro answered 2/2, 2013 at 19:27 Comment(0)
B
1

There was a problem with Java rendering transparent background GIF images. That could be the problem.

Bantu answered 3/2, 2013 at 2:15 Comment(2)
I only use .png images in the rendering loop for sprites.Coimbatore
Also in the new example no images are used at all, just text, and it still flickers.Coimbatore
I
0

I find it rather difficult to answer your question without an SCCSE. I also wonder what the RepaintManagerResetter does.

You might want to set your background color to some fancy colors like 0xFF00FF to find out if someone "clears" the background before the drawing happens. If the flicker image is purple, it's that - if it contains garbage or old images, it's probably the double-buffering.

In any case I would try to ensure that noone draws expect yourself. First, try to prevent native Windows code from drawing the window background. Set this once:

/*
 * Set a Windows specific AWT property that prevents heavyweight components 
 * from erasing their background. 
 */
System.setProperty("sun.awt.noerasebackground", "true");

Also, make sure that you override this in your JFrame(if you are using Swing components)

@Override
public void paintComponent(Graphics G)
{
  // do not call super.pC() here
  ...
}

If that doesn't help, please provide a working example of your code, so people can reproduce the problem.

Ilise answered 2/2, 2013 at 19:13 Comment(1)
System.setProperty("sun.awt.noerasebackground", "true"); did not do the job, also in the new example I do not use any JComponents.Coimbatore

© 2022 - 2024 — McMap. All rights reserved.