Java graphics are flashing - java

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.

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);
.....
}

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.

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.

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

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

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.

Related

Enabling OpenGL in Java makes edges of JPanel with graphics get cut off

I'm making a game using Java Graphics2D for a school assignment. When I add the following line to the beginning of my main method to improve performance,
System.setProperty("sun.java2d.opengl", "true");
the edges of the graphics panel get cut off.
I made a small program to show the effect:
import java.awt.*;
import java.awt.geom.*;
import javax.swing.*;
public class Main extends JPanel {
public Main() {
JFrame frame = new JFrame("OpenGL off");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setPreferredSize(new Dimension(800, 600));
frame.add(this);
frame.pack();
frame.setVisible(true);
}
public void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
g2.setPaint(Color.RED);
g2.setStroke(new BasicStroke(5.0f));
g2.draw(new Ellipse2D.Double(0, 0, 800, 600));
}
public static void main(String[] args) {
// Enables hardware acceleration
System.setProperty("sun.java2d.opengl", "true");
new Main();
}
}
No OpenGL:
OpenGL enabled:
The problem shows up on Windows but not Mac.
Java Version: Java 11, OS: Windows 10
EDIT: The problem also occurs with Java 14
I found some documentation by Oracle saying that this command may not work with some hardware configurations or versions of java. It's more of a convenience thing, as you said and you may just be using it with the wrong version of Java or one that does not support this command. I suggest that you look at this documentation: https://docs.oracle.com/javase/7/docs/technotes/guides/2d/flags.html
You may need to upgrade your Java version or just use your MAC OS since that seems to be working well. I recommend reading the documentation as that has some solid information. Long story short, it's probably a problem on your end and you should either research in order to find an alternative or just settle. I am also a student who is in the beginning of my programming career and I just decided to try and solve a problem, I hope I helped?

TrueTypeFont.drawString() not supported

I'm trying to implement 2D text rendering into my LWJGL game and have searched everywhere for a working solution, but keep getting the same error. I am currently trying to follow this tutorial. Here is the error:
Exception in thread "main" java.lang.IllegalStateException: Function is not supported
at org.lwjgl.BufferChecks.checkFunctionAddress(BufferChecks.java:58)
at org.lwjgl.opengl.GL11.glColor4f(GL11.java:893)
at org.newdawn.slick.opengl.renderer.ImmediateModeOGLRenderer.glColor4f(ImmediateModeOGLRenderer.java:124)
at org.newdawn.slick.Color.bind(Color.java:182)
at org.newdawn.slick.TrueTypeFont.drawString(TrueTypeFont.java:363)
at org.newdawn.slick.TrueTypeFont.drawString(TrueTypeFont.java:355)
at guis.Gui.drawString(Gui.java:23)
at engineTester.MainGameLoop.main(MainGameLoop.java:110)
and here is my Gui class:
package guis;
import java.awt.Font;
import org.newdawn.slick.TrueTypeFont;
public class Gui {
private TrueTypeFont font;
private Font awtFont;
public Gui() {
this.awtFont = new Font("Times New Roman", Font.BOLD, 24);
this.font = new TrueTypeFont(awtFont, false);
}
public void drawString(int x, int y, String text) {
font.drawString(x, y, text);
}
}
Why is this error caused?
EDIT: Regarding this answer to another question: https://stackoverflow.com/a/26319508/5838494 I already did this and it does not work.
You need to set up your opengl version lower than 3.0, because functions used by TrueTypeFont have been removed in 3.x.
Or you can take a look into opengl 3.x / 4.x
Opengl3.3
if you do not have to support older opengl versions.
The problem here is probably that you do something like
public Gui theGui = new Gui();
in your main class I guess. Now, when you do this, the constructor is called and when you create your TrueTypeFont there, there is no OpenGL context yet, because the main class is also just being initialized, and hence the drawing fails because it has no OpenGL context.
You can try and change that to just a declaration like public Gui gui; and then, when you load your application, after you created the GL context, you assign the field with this.gui = new Gui();.
But I can only guess here because you do not have much code in your question. There might be other problems with this code, like incompatibility of the Slick library (Do you have the latest version, or better the version that's known to be compatible with your OpenGL version?), or similar.

How am I supposed to draw an image from my Java Applet?

I am not sure how to fully express this but, I have probably gone through 10 pages of Google links on this topic and not one of them has helped me solve my issue.
I thought it would be simple enough, I was just trying to add an image to the paint function of my java applet, like any other shape, but this has turned out to be a nightmare for me.
The problem is that every time I try to run the drawImage function it keeps saying Access Denied ("java.io.FilePermission" "Image.jpg" "read"). Yet, none of the tutorials mention this at all, all they ever say is that I should do the following:
import java.applet.*;
import java.awt.*;
Image img;
//These would go in the paint function
img=getImage(getDocumentBase(),"/Image.jpg"); //I have tried without the slash too
g.drawImage(img,20,20,this);
This is all they do and it works for them, but it just won't work for me. Other methods are far too complex for the sake of just adding an image, and even when I go through the toil of doing those it keeps giving me the "Access Denied" message. There's also the method of "signing" it, but I really don't think that's going to help given all that I have tried, so I am afraid it might just be another wasted endeavor. None of the tutorials even tell you to have your applet signed.
I have the image in the "build" (also called bin) folder together with the classes.
The program seemed to run when I included the entire file path, but even then the image did not display. That is not to mention I can't really include the complete path from my own computer because then it wouldn't work when I actually send it to another person.
Please, I just want to know why it doesn't work for me yet seems to work perfectly for others. That, and if there's a way around this.
This is an example of what I am doing:
import java.applet.*;
import java.awt.*;
public class JavaProject extends JApplet
{
Image img;
public void init()
{
img=getImage(getDocumentBase(),"/Image.jpg");
}
public void paint(Graphics g)
{
super.paint(g);
g.drawImage(img,20,20,this);
}
}
This is my HTML file:
<html>
<head>
<title> My First Web Page </title>
</head>
<body>
<applet code="JavaProject.class" width="400" height="500">
</applet>
</body>
</html>
According JApplet java docs method getImage(URL url, String name) should have two parameter: URL-link to picture and String name.
Is method getDocumentBase() returnig an URL-link?
You must start by understanding that an Applet, unless signed, may not read from the file system. It must use either classpath resources or things fetched from the same place it was fetched from. You have to decide which of these applies to you. If the image is a fixed image, you can put it in your classpath as a resource, and use Class.getResourceAsStream. If it's a different image every time, you'll have to use HTTP.
Try this one if the image in the "build" (also called bin) folder together with the classes.
import java.awt.Graphics;
import java.awt.Image;
import java.net.URL;
import javax.swing.JApplet;
public class JavaProject extends JApplet {
Image img;
public void init() {
img = getImage(getDocumentBase(), "images/222.png");
// Please ensure that 222.png is placed under bin/images folder directly
}
#Override
public void paint(Graphics g) {
update(g);
}
#Override
public void update(Graphics g) {
g.drawImage(img, 20, 20, this);
}
}
Try with HTTP URL first
URL myURL = new URL("https://www.gravatar.com/avatar/a94613cea642e6e9e2105867bc2e103e?s=32&d=identicon&r=PG&f=1");
img = getImage(myURL);
If you are using Eclipse under Windows then have a look at below screenshot:
Please have a look at below post to get some understanding about it.
java.io.FilePermission exception - Read from jar file?

How can I inherit the system's anti-alias setting for painting text to off-screen images like swing does?

When I run my swing GUI applications under Java 6, they automatically use my configured sub-pixel anti-alias settings for all fonts. The result is much improved over standard AA options.
But when I paint to an image I can find no way to initialize the graphics context to use the system's AA configuration. Trying to play around with Java's different AA hints is a lost cause because no sub-pixel method will work for all users.
Is there any way to inherit system AA settings for a given graphics context instead of having to pick one and explicitly set the hint? At the moment I have to use GASP AA to avoid the horrible results that standard AA gives with small fonts. I have tried not setting anything for text AA, and not setting any AA hints at all.
Update 2010-01-05
I think I have pinned this down; the subpixel AA hints appear to only be respected when painting directly to the AWT graphics context; when I paint to a double-buffer image it just does standard AA; but when I bypass the double-buffer image the subpixel AA is done.
Otherwise The_Fire's answer would work in JVMs which have Swing available (but not J2ME JVMs); Note that The_Fire's answer does not work using an AWT component (using new Label() instead of new JLabel() fails), presumably because the FontRenderContext cannot be extracted until the component is realized to the display.
My current code to get the graphics context for my target image currently looks like this:
try {
if((dbImage=dctRoot.createImage(wid,hgt,1))!=null) { // if createImage returns null or throws an exception the component is not yet displayable
dbGraphics=(Graphics2D)dbImage.getGraphics();
if(dctRoot.properties.getBoolean("Antialias",true)) {
try {
// set AA on overall
dbGraphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING ,RenderingHints.VALUE_ANTIALIAS_ON);
// set text AA to platform/impl default
dbGraphics.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,RenderingHints.VALUE_TEXT_ANTIALIAS_DEFAULT);
// try to override platform/impl AA with font-specified AA (Java 6+)
try { dbGraphics.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,RenderingHints.class.getField("VALUE_TEXT_ANTIALIAS_GASP").get(null)); } catch(Throwable thr) {;} // yes, ignore exception
}
catch(Throwable thr) {
dctRoot.log.println("Antialiasing not supported on this JVM ("+thr+").");
dctRoot.setProperty("Antialias","False"); // turn off AA for subsequent painting
}
}
}
}
catch(Throwable thr) {
dbImage=null;
dbGraphics=null;
}
The code to create the image uses an underlying AWT component, which forms the backdrop on which I do all my painting - the component is a Panel, because I need to be able to do a setFocusCycleRoot so it plays well with other AWT components. The create image code follows:
public DctImage createImage(int wid, int hgt, float accpty) {
GraphicsConfiguration cfg=awtComponent.getGraphicsConfiguration();
Image img=null;
if(transparentImages) {
//y { img=new BufferedImage(wid,hgt,BufferedImage.TYPE_INT_ARGB); } // NB: J2ME CDC/PP 1.1 does not have the BufferedImage constructors (one day I may discover a way to create a BufferedImage via another API!!)
try { img=cfg.createCompatibleImage(wid,hgt,Transparency.TRANSLUCENT); }// NB: J2ME CDC/PP 1.1 does not have this API, but prefer to use GraphicsConfiguration over new BufferImage(...)
catch(NoClassDefFoundError thr) { transparentImages=false; createImage(wid,hgt,accpty); } // try again with transparency disabled
catch(NoSuchMethodError thr) { transparentImages=false; createImage(wid,hgt,accpty); } // try again with transparency disabled
catch(NoSuchFieldError thr) { transparentImages=false; createImage(wid,hgt,accpty); } // try again with transparency disabled
}
else {
img=cfg.createCompatibleImage(wid,hgt);
}
if(accpty>0 && SET_ACCELERATION_PRIORITY!=null) {
try { SET_ACCELERATION_PRIORITY.invoke(img,new Object[]{new Float(accpty)}); } catch(Throwable thr) {;}
}
return (img==null ? null : new DctImage(img));
}
I found there were a few factors going on here.
First, the image needs to be created from the underlying AWT component, and it must be created without transparency:
cfg.createCompatibleImage(wid,hgt);
instead of
cfg.createCompatibleImage(wid,hgt,Transparency.TRANSLUCENT);
Second, for some inexplicable reason, the primary AA setting, KEY_ANTIALIASING, must be off to use LCD subpixel AA.
Lastly, and most importantly, the desktop font rendering hints are easily retrieved using:
java.awt.Toolkit.getDesktopProperty("awt.font.desktophints")
Update 2010-01-05
Retesting in Java 6.26, it seems like the problem with needing to set general AA off to render text AA has finally been resolved (way to go Oracle... after Sun was just a few years decade too late).
Using Swing, I'm able to get the right text anti-aliasing hint like this:
JLabel label = new JLabel();
FontMetrics fm = label.getFontMetrics( label.getFont() );
Object aaHintValue = fm.getFontRenderContext().getAntiAliasingHint();
On my system this returns RenderingHits.VALUE_TEXT_ANTIALIAS_LCD_HRGB.
java.awt.Toolkit.getDesktopProperty("awt.font.desktophints") appears to be null on linux, at least without any special vm command line options, presumably because it's unable to figure out what the platform defaults are.. adding e.g "-Dawt.useSystemAAFontSettings=lcd" seems to cure it and enables subpixel rendering if you set the hints on your Graphics2D instance.
Wait, are you running this code on a Windows JVM? I thought ClearType was a Microsoft technology that Swing inherits through some native code (ie, not available on Linux or other non Microsoft platforms).
I once wrote a servlet that generated JPGs with anti aliased fonts that ran on Debian, and this was the code I used
Font font = new Font("Komix", Font.PLAIN, 8);
Graphics2D g2;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
FontRenderContext frc = g2.getFontRenderContext();
g2.setFont(font);
g2.setPaint(Color.black);
g2.drawString(sMessage, xOffset, yOffset);
Offhand I can't recall if any of this code relies on Swing (I imported javax.swing and the servlet is about 300 lines long, so I may have thought I needed it for something else), a quick check on Google looks like this is squarely in the AWT space. Hope that helps.

drawImage() for .png files doesn't work in Java applet?

I made this pacman game using an applet. When the applet finishes loading, it is meant to display a 'start menu' graphic i made which says 'Double click to start the game', etc. The graphic would take up the whole 400x400 applet. Here's the code:
public void paint(Graphics g)
{
if (! isRunning)
{
switch (result)
{
case 0:
showStartScreen(g);
break;
case 1:
showWonScreen(g);
break;
case -1:
showLostScreen(g);
break;
}
return;
}
//Code for rendering other stuff if game is here
}
showStartScreen:
public void showStartScreen(Graphics g)
{
Image intro=img.getImg("pacman-intro.png");
g.drawImage(intro, 0, 0, this);
}
This works fine when I run this locally on Eclipse, but in the web browser, when the applet is loaded I just see a blank box where the java's loading animation previously was. Surprisingly, if I double click randomly where the applet is meant to be, the game starts and works as normal. So this makes me think that the problem is just with drawing .png files using drawImage.
The same thing occurs when you win or lose the game,it just hangs instead of drawing the graphic it needs to.
You can see this here (you can use arrow keys to control)
P.S I am using double buffering here.
Any thoughts..?
EDIT: Code for ImgHelper class which is used to load the img:
import java.awt.Image;
import java.net.URL;
import javax.swing.ImageIcon;
public class ImgHelper
{
public Image getImg(String file)
{
//Engine is the name of the base applet class
URL url=Engine.class.getClassLoader().getResource("assets/" + file);
return new ImageIcon(url).getImage();
}
}
Ah, I checked the contents of your jar file.
Replace "pacman-intro.png" with "pacman-intro.PNG". It's case-sensitive.
Are the pngs in the right directory? Is "." in the path env-variable on the server?
Try "./pacman-intro.png" i.e.

Categories