Java-Gaming.org Hi !
Featured games (83)
games approved by the League of Dukes
Games in Showcase (523)
Games in Android Showcase (127)
games submitted by our members
Games in WIP (592)
games currently in development
News: Read the Java Gaming Resources, or peek at the official Java tutorials
 
    Home     Help   Search   Login   Register   
Pages: [1]
  ignore  |  Print  
  Am I calculating the FPS right?  (Read 2480 times)
0 Members and 1 Guest are viewing this topic.
Offline gcsaba2

Junior Devvie




Hello world


« Posted 2006-09-10 20:39:31 »

This is my main loop:

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
   public void loop() {
      while (gameRunning) {
         fpsCounter++;
         
         if (isFocusOwner()) {
            long now = System.currentTimeMillis();
// --------------- I calculate the FPS here -----------------------
            if (now - oneSecond >= 1000) {
               oneSecond = now;
               fps = fpsCounter;
               fpsCounter = 0;
            }
// -------------- I sync the game speed here -------------------------
            if (now - Globals.timer >= Globals.frameDiff) {
               Globals.timer = now;
               doAction();
            }

            doDraw();
         } else
            try { Thread.sleep(100); } catch (Exception ex) {}
      }
   }


OK, so what I do here is this:
  • during each loop I increase fpsCounter
  • I check if 1 second has passed since I last updated oneSecond
  • if one second has passed, I pass the value of fpsCounter to fps (to be printed out on the screen) and I reset fpsCounter to zero; also, I update oneSecond to the current time

With this I get that my game is running at 13 FPS! That si incredibly slow, I was expecting something around 70, not less than 60 in any case. Am I calculating the FPS right?

If not, then is 13 FPS normal for Java games? I remember a year ago when I worked with C++ it was always around 70 FPS... Huh
Offline oNyx

JGO Coder


Medals: 2


pixels! :x


« Reply #1 - Posted 2006-09-10 23:11:39 »

Yea the fps counter is alright.

>If not, then is 13 FPS normal for Java games?

No.

You kick your main thread into zzz land for ~100msec each frame. Remove that line and the fps will go up.

See here how to do throttling with a crap timer (such as currentTimeMillis):
http://www.java-gaming.org/forums/index.php?topic=11640.msg93602#msg93602

edit: on a second thought... that sleep stuff is in the else branch... no idea what you're doing thats so slow. Fullalpha with java2d perhaps?

弾幕 ☆ @mahonnaiseblog
Offline gcsaba2

Junior Devvie




Hello world


« Reply #2 - Posted 2006-09-11 09:37:40 »

Yeah I send it to sleep when the window is not focused, so it would not use 100% of the CPU.
I am using Java2D and I use translucent images. I load each image, create a translucent counterpart and make all the pink pixels transparent.

Here's some of the stuff I do, if anyone notices what I should change just let me know.

JFrame initialization:
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
   public Game() {
      super(Settings.getProperty("game.title"));
      setResizable(false);
      setBounds(0,0,Globals.RESOLUTION_X,Globals.RESOLUTION_Y);
      setSize(Globals.RESOLUTION_X, Globals.RESOLUTION_Y);
      setDefaultCloseOperation(EXIT_ON_CLOSE);
      setIgnoreRepaint(true);
      gc.setLayout(null);
      setUndecorated(true);
      gc.setBackground(Color.BLACK);
}


Graphics mode initialization. First I check whether it should be fullscreen or not, then I set the display mode to 800x600x32

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
   /** Initialize buffers and fullscreen */
   private void initGraphics() {
      if (Settings.getPropertyBool("display.fullscreen")) {
         if (Globals.GRAPHICS_DEVICE.isFullScreenSupported())
            Globals.GRAPHICS_DEVICE.setFullScreenWindow(this);
         DisplayMode[] displayModes = Globals.GRAPHICS_DEVICE.getDisplayModes();
         int selected = 0;
         for (int i=0; i<displayModes.length; i++) {
            if (displayModes[i].getWidth() == Globals.RESOLUTION_X &&
                  displayModes[i].getHeight() == Globals.RESOLUTION_Y &&
                  displayModes[i].getBitDepth() == Globals.BPS)
               selected = i;
         }
         Globals.GRAPHICS_DEVICE.setDisplayMode(displayModes[selected]);
      }
     
      createBufferStrategy(2);
   }


I load images and make them transparent like this:
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
36  
37  
38  
39  
40  
41  
42  
   public static Color TRANSPARENT_COLOR = new Color(255,0,255);
   private static HashMap pictures = new HashMap();
   
   public static Image createTransparentImage(String path) throws IOException {
      // no need to load the image twice
      if (pictures.containsKey(path))
         return (Image)pictures.get(path);
     
      File file = new File(path);
      if (!file.exists())
         throw new IOException("File not found: " + path);
     
      BufferedImage image = ImageIO.read(file);
     
      BufferedImage result = Globals.GRAPHICS_CONFIG.createCompatibleImage(image.getWidth(),image.getHeight(),Transparency.TRANSLUCENT);
      Graphics g2 = result.getGraphics();
      // draw image on the transparent image
      g2.drawImage(image,0,0,null);
      g2.dispose();
      // make the pixels transparent
      DataBuffer dbuffer = result.getRaster().getDataBuffer();
      // get array of pixels
      int[] imageData = ((DataBufferInt)dbuffer).getData();
           
      int r,g,b;
      int red = TRANSPARENT_COLOR.getRed();
      int blue = TRANSPARENT_COLOR.getBlue();
      int green = TRANSPARENT_COLOR.getGreen();
      for (int i=0; i<imageData.length; i++) {
         r = getR(imageData[i]);
         g = getG(imageData[i]);
         b = getB(imageData[i]);

         if ( (r == red) && (b == blue) && (g == green) ) {
            imageData[i] = 0;  // set pixel to 0 (also sets its alpha to 0)            
         }
      }      
     
      pictures.put(path, result);
     
      return result;
   }


I tried changing the Transparency.TRANSLUCENT to Transparency.BITMASK but this only made the game improve to 16 fps
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline gcsaba2

Junior Devvie




Hello world


« Reply #3 - Posted 2006-09-11 09:46:08 »

Oh yeah, and all the images are 64x64 pixels. Now I remember there was a limit in Java that if an image is too large it won't be accelerated. What was this limit?
Offline gcsaba2

Junior Devvie




Hello world


« Reply #4 - Posted 2006-09-11 09:48:44 »

I'm drawing out a map, so far only the walls and corridors. On top of the map I draw a cursor. I've just checked, and if I comment out the line which draws the map, the FPS goes up to 370. So obviously it is the map images that cause the problem...  Undecided
Offline gcsaba2

Junior Devvie




Hello world


« Reply #5 - Posted 2006-09-11 10:17:58 »

If I get the image with createCompatibleVolatileImage() then the FPS goes up to 70-90, but then it isn't transparent. Even if I save a GIF image with a transparent background, it will make the background white.

I also tried resizing the images to 32x32 but the FPS remained the same...

I also tried using the -Dsun.java2d.ddforcevram=true arguement, but it didn't do a thing...
Offline gcsaba2

Junior Devvie




Hello world


« Reply #6 - Posted 2006-09-11 10:46:20 »

With rendering hints set for speed I can get no more than 16 FPS...

Graphics2D g = (Graphics2D)Globals.CANVAS;
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF);
g.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_SPEED);
g.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_SPEED);
g.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_DISABLE);
g.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_OFF);
g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_SPEED);
g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_OFF);


Obviously I need to do something with those images...
Offline gcsaba2

Junior Devvie




Hello world


« Reply #7 - Posted 2006-09-11 11:21:37 »

OK now I've tried loading the image not as a BufferedImage but as a simple Image:

Image img = Toolkit.getDefaultToolkit().getImage(path);

Interesting that this way I get 70 FPS. Still, this way I have to make the images transparent in a drawing program, and can't do it myself inside the application... but if I can't find any other way then this will be good as well...
Offline Kova

Senior Devvie





« Reply #8 - Posted 2006-09-11 11:55:27 »

Dude, use edit on your post to add new comments... this is ugly and unreadable what you do.

In windows under DirectX (default) alpha images aren't accelarated. Try to use OpenGL pipeline and see how it works, search forums to see how to enable it, it's a command at startup or a line of code of system proparty. Buffered images try their best to be accelerated, I think you should use them. If you load the image and then work anything on it, it loses accelerration. When you're done with your work, create a new BufferedImage with that data.
Offline gcsaba2

Junior Devvie




Hello world


« Reply #9 - Posted 2006-09-11 12:17:34 »

That's it, that actually made it work!!! Grin

I create a compatible BufferedImage, pass through its data array and turn all the pink pixels into transparent. Then finally I create a new compatible image, and paint the modified BufferedImage on it.
Looks like the problem all along was that I modified the compatible image's data array, so it stopped being accelerated.

Thanks for the help, sorry for spamming Grin
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline Markus_Persson

JGO Wizard


Medals: 16
Projects: 19


Mojang Specifications


« Reply #10 - Posted 2006-09-11 12:45:29 »

This is my main loop:

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
   public void loop() {
      while (gameRunning) {
         fpsCounter++;
         
         if (isFocusOwner()) {
            long now = System.currentTimeMillis();
// --------------- I calculate the FPS here -----------------------
            if (now - oneSecond >= 1000) {
               oneSecond = now;
               fps = fpsCounter;
               fpsCounter = 0;
            }
// -------------- I sync the game speed here -------------------------
            if (now - Globals.timer >= Globals.frameDiff) {
               Globals.timer = now;
               doAction();
            }

            doDraw();
         } else
            try { Thread.sleep(100); } catch (Exception ex) {}
      }
   }


Extremely minor nit-pick, but you're leaking a little bit of time once every second
If you change "oneSecond = now;" into "oneSecond += 1000;", you stop the leaking. It probably won't affect the reported fps, though. Wink

Play Minecraft!
Offline gcsaba2

Junior Devvie




Hello world


« Reply #11 - Posted 2006-09-11 12:59:57 »

I made the changes and it dropped from 70 to 69 FPS!
Click to Play
  Grin
Offline erikd

JGO Ninja


Medals: 16
Projects: 4
Exp: 14 years


Maximumisness


« Reply #12 - Posted 2006-09-11 13:42:28 »

Just change it back for better performance  Wink Grin

Offline JAW

Senior Devvie


Medals: 2



« Reply #13 - Posted 2006-09-13 17:52:29 »

As far as I know, currentTimeMillis() is inaccurate, at least with windows. Try nanoTime() instead and remember to divide by 1.000.000 to convert nano to milli.

I cant exactly tell what you do with your transpant image, but there might be better ways. CreateCompatibleImage has the transparency options opaque, bitmask and translucent. If you just want masked images (pixel is visible or not, but no alpha), use bitmask transparency.
You can read transparent GIFs (use bitmask transparency) and PNGs (support full alpha information) and draw them on a BufferedImage. So you dont need all this per pixel computation.

-JAW
Offline ravenger

Senior Newbie





« Reply #14 - Posted 2006-09-18 18:15:50 »

As far as I know, currentTimeMillis() is inaccurate, at least with windows. Try nanoTime() instead and remember to divide by 1.000.000 to convert nano to milli.

You can actually use Thread.sleep(long milis, int nanos), which means you can do this; Thread.sleep(nanoTime/1000000,(int)nanoTime%1000000); also note that the sleep  is also inaccurate in itself, there is a couple ms delay in the call and the shorter you get it to sleep the more it will be inaccurate. You basicly have to compensate that aswell if you really wanna get accurate;

This is an example of a piece of code out of the book "Killer Game Programming in Java" which covers for it;
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
// Number of frames with a delay of 0 ms before the animation thread yields to other running threads.
private static final int NO_DELAYS_PER_YIELD = 16;
private long period = 10000000; // 10000000ns (10ms) giving 100 FPS
....
// Time handling code in mainloop;
beforeTime = System.nanoTime();
...
doGameLogic(); // movement, collision, drawing etc.
...
afterTime = System.nanoTime();
timeDiff = afterTime - beforeTime;
sleepTime = ( period - timeDiff ) - overSleepTime;   // time left in this loop

if ( sleepTime > 0 ) {
          try {
           /* Sleeptime is in nanosecs, and there is currently no Thread.sleep(nanosecs)
                * only Thread.sleep(long ms, int nanosecs)
                * since theres 1000000ns to 1ms divide by 1000000 and ns is mod 1000000;
              */

             Thread.sleep ( sleepTime / 1000000, (int) sleepTime % 1000000 );
                 
          } catch ( Exception e ) {}
          // Since there is a slight inaccuracy in the sleep, we need to cover for it
          overSleepTime = ( System.nanoTime() - afterTime ) - sleepTime;
} else {
          overSleepTime = 0;

        if ( ++noDelays >= NO_DELAYS_PER_YIELD ) {
                Thread.yield( );   // give another thread a chance to run
           noDelays = 0;
   }
}

If the sleep( ) call sleeps for 12 ms instead of the desired 10 ms, then overSleepTime will be assigned 2 ms. On the next iteration of the loop, this value will be deducted from the sleep time, reducing it by 2 ms. In this way, sleep inaccuracies are corrected.
Pages: [1]
  ignore  |  Print  
 
 
You cannot reply to this message, because it is very, very old.

 

Add your game by posting it in the WIP section,
or publish it in Showcase.

The first screenshot will be displayed as a thumbnail.

SHC (24 views)
2014-11-25 12:00:59

SHC (22 views)
2014-11-25 11:53:45

Norakomi (19 views)
2014-11-25 11:26:43

Gibbo3771 (22 views)
2014-11-24 19:59:16

trollwarrior1 (36 views)
2014-11-22 12:13:56

xFryIx (74 views)
2014-11-13 12:34:49

digdugdiggy (52 views)
2014-11-12 21:11:50

digdugdiggy (46 views)
2014-11-12 21:10:15

digdugdiggy (41 views)
2014-11-12 21:09:33

kovacsa (67 views)
2014-11-07 19:57:14
Understanding relations between setOrigin, setScale and setPosition in libGdx
by mbabuskov
2014-10-09 22:35:00

Definite guide to supporting multiple device resolutions on Android (2014)
by mbabuskov
2014-10-02 22:36:02

List of Learning Resources
by Longor1996
2014-08-16 10:40:00

List of Learning Resources
by SilverTiger
2014-08-05 19:33:27

Resources for WIP games
by CogWheelz
2014-08-01 16:20:17

Resources for WIP games
by CogWheelz
2014-08-01 16:19:50

List of Learning Resources
by SilverTiger
2014-07-31 16:29:50

List of Learning Resources
by SilverTiger
2014-07-31 16:26:06
java-gaming.org is not responsible for the content posted by its members, including references to external websites, and other references that may or may not have a relation with our primarily gaming and game production oriented community. inquiries and complaints can be sent via email to the info‑account of the company managing the website of java‑gaming.org
Powered by MySQL Powered by PHP Powered by SMF 1.1.18 | SMF © 2013, Simple Machines | Managed by Enhanced Four Valid XHTML 1.0! Valid CSS!