Java-Gaming.org    
Featured games (81)
games approved by the League of Dukes
Games in Showcase (494)
Games in Android Showcase (114)
games submitted by our members
Games in WIP (563)
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  
  Java2D Optimization  (Read 4596 times)
0 Members and 1 Guest are viewing this topic.
Offline Eli Delventhal

JGO Kernel


Medals: 42
Projects: 11
Exp: 10 years


Game Engineer


« Posted 2008-11-06 06:49:16 »

I'm trying to get decent speed out of Java2D and it just isn't happening. I don't know if I'm doing it some dumb way or not, but I usually use OpenGL so I haven't worried about it. This time, though I want to stick with Java2D if possible.

Here is a simple test app I made that creates a bunch of images and draws them while spinning them around and moving them. Basically it's meant to be a simple stress test. But I find that even with very simple images and not very many of them I'm having really bad luck in terms of speed. If I increase window size to fill my screen, almost no matter what I end up getting only around 20 fps, which is just crazy.

I've got to be doing something wrong.

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  
43  
44  
45  
46  
47  
48  
49  
50  
51  
52  
53  
54  
55  
56  
57  
58  
59  
60  
61  
62  
63  
64  
65  
66  
67  
68  
69  
70  
71  
72  
73  
74  
75  
76  
77  
78  
79  
80  
81  
82  
83  
84  
85  
86  
87  
88  
89  
90  
91  
92  
93  
94  
95  
96  
97  
98  
99  
100  
101  
102  
103  
104  
105  
106  
107  
108  
109  
110  
111  
112  
113  
114  
115  
116  
117  
118  
119  
120  
121  
122  
123  
124  
125  
126  
127  
128  
129  
130  
131  
132  
133  
134  
135  
136  
137  
138  
139  
140  
141  
142  
143  
144  
145  
146  
147  
148  
149  
150  
151  
152  
153  
154  
155  
156  
157  
158  
159  
160  
161  
162  
163  
164  
165  
166  
167  
168  
169  
170  
171  
172  
173  
174  
175  
176  
177  
178  
179  
180  
181  
182  
183  
184  
185  
186  
187  
188  
189  
190  
191  
192  
193  
194  
195  
196  
197  
import javax.swing.*;
import java.awt.*;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.io.File;
import javax.imageio.ImageIO;
import java.util.ArrayList;

public class Test2 extends JFrame
{
   private TestCanvas canvas;
   
   public static final int NES_WIDTH = 256;
   public static final int NES_HEIGHT = 224;
   
   public Test2()
   {
      canvas = new TestCanvas();
      getContentPane().add(canvas);
      setSize(500,500);
      setVisible(true);
   }
   
   public void run()
   {
      canvas.run();
   }
   
   public static void main(String[] args)
   {
      new Test2().run();
   }
   
   private class TestCanvas extends Canvas
   {
      private AffineTransform affine;
      private BufferedImage image;
     
      private int lastWidth;
      private int lastHeight;
     
      private ArrayList<Sprite> sprites;
     
      private float fps;
      private int draws;
     
      public TestCanvas()
      {
         
         affine = new AffineTransform();
         sprites = new ArrayList<Sprite>();
         for (int i = 0; i < 20; i++)
         {
            sprites.add(new Sprite((float)(Math.random() * NES_WIDTH), (float)(Math.random() * NES_HEIGHT), (int)(Math.random() * 30+1), (int)(Math.random() * 30+1), (float)(Math.random()*5.0f+0.1f), (float)(Math.random() * Math.PI / 50.0f +0.1f)));
            sprites.get(sprites.size()-1).setTarget((float)(Math.random() * NES_WIDTH), (float)(Math.random() * NES_HEIGHT));
         }
         
         try
         {
            image = ImageIO.read(new File(System.getProperty("user.dir") + "/RCR.jpg"));
         }
         catch (Exception e)
         {
            e.printStackTrace();
         }
      }
     
      public void paint(Graphics g)
      {
         if (lastWidth != getWidth() || lastHeight != getHeight())
         {
            affine.setToScale(getWidth() / (NES_WIDTH+0.0), getHeight() / (NES_HEIGHT+0.0));
            lastWidth = getWidth();
            lastHeight = getHeight();
         }
         
         Graphics2D g2 = (Graphics2D) g;
         g2.setTransform(affine);
         
         g2.drawImage(image,0,0,null);
         
         for (int i = 0; i < sprites.size(); i++)
            sprites.get(i).draw(g2);
         
         g.setColor(Color.WHITE);
         g.drawString("FPS: " + fps,150,15);
         
         draws++;
      }
     
      public void run()
      {
         boolean running = true;
         float target = 1000 / 60.0f;
         float frameAverage = target;
         long lastFrame = System.currentTimeMillis();
         float yield = 10000f;
         float damping = 0.1f;

         long lastSecond = lastFrame;

         while (running)
         {
            long timeNow = System.currentTimeMillis();
            frameAverage = (frameAverage * 10 + (timeNow - lastFrame)) / 11;
            lastFrame = timeNow;

            yield += yield*((target/frameAverage)-1)*damping+0.05f;

            for(int i = 0; i < yield; i++)
               Thread.yield();
           
            if (timeNow - lastSecond >= 1000)
            {
               fps = draws;
               draws = 0;
               lastSecond = timeNow;
            }
           
            repaint();
         }
      }
   }
   
   private class Sprite
   {
      private BufferedImage image;
      private float x, y;
      private int width, height;
      private float rotation, rotationSpeed;
      private float targetX, targetY, speed;
     
      public Sprite(float newX, float newY, int wid, int hi, float shpeed, float rotSpeed)
      {
         x = newX;
         y = newY;
         width = wid;
         height = hi;
         speed = shpeed;
         rotationSpeed = rotSpeed;
         
         GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
         GraphicsDevice gd = ge.getDefaultScreenDevice();
         image = gd.getDefaultConfiguration().createCompatibleImage(width,height,Transparency.TRANSLUCENT);
         
         for (int i = 0; i < image.getWidth(); i++)
            for (int j = 0; j < image.getHeight(); j++)
               image.getRaster().setPixel(i,j,new int[]{(int)(Math.random()*256),(int)(Math.random()*256),(int)(Math.random()*256),(int)(Math.random()*256)});
      }
     
      public void draw(Graphics2D g)
      {
         //Move to the target.
        moveTarget();
         
         //Adjust the rotation.
        rotation += rotationSpeed;
         
         g.rotate(rotation, x+width/2, y+height/2);
         g.drawImage(image,(int)x,(int)y,null);
         g.rotate(-rotation, x+width/2, y+height/2);
      }
     
      private void moveTarget()
      {
         if (x != targetX && y != targetY)
         {
            float xDist = targetX - x;
            float yDist = targetY - y;
            float dist = (float) Math.sqrt(xDist * xDist + yDist * yDist);
            float newX = x + (xDist / dist) * speed;
            float newY = y + (yDist / dist) * speed;
           
            if ((x < targetX && newX > targetX) || (x > targetX && newX < targetX))
               x = targetX;
            else
               x = newX;
               
            if ((y < targetY && newY > targetY) || (y > targetY && newY < targetY))
               y = targetY;
            else
               y = newY;
         }
         else
         {
            //Set a new target.
           setTarget((float)(Math.random() * NES_WIDTH), (float)(Math.random() * NES_HEIGHT));
         }
      }
     
      public void setTarget(float targX, float targY)
      {
         targetX = targX;
         targetY = targY;
      }
   }
}


Also, I've tried with VolatileImages, just using fillRect to draw pixels, having a JPanel instead of a Canvas, and more, but no luck.

See my work:
OTC Software
Offline Riven
« League of Dukes »

JGO Overlord


Medals: 793
Projects: 4
Exp: 16 years


Hand over your head.


« Reply #1 - Posted 2008-11-06 07:13:14 »

What happens if you switch from currentTimeMillis to nanoTime ?

Hi, appreciate more people! Σ ♥ = ¾
Learn how to award medals... and work your way up the social rankings
Offline Eli Delventhal

JGO Kernel


Medals: 42
Projects: 11
Exp: 10 years


Game Engineer


« Reply #2 - Posted 2008-11-06 08:30:34 »

Same results. I changed the target and the fps counter to match that as well obviously (using 1,000,000,000 instead of 1,000). So it ended up giving the exact same fps.

[EDIT] As a note, I just did the same test on OpenGL and when I have 2000 entities on screen at a bigger resolution I still get 50 fps, which is obviously better than Java2D's 20 fps with 20 entities. The OpenGL test was using currentTimeMillis.

[EDIT2] It takes 5,000 entities on OpenGL to match the fps obtained with 20 entities on Java2D. That's 250:1. There's no way that can be right.

See my work:
OTC Software
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline Abuse

JGO Knight


Medals: 12


falling into the abyss of reality


« Reply #3 - Posted 2008-11-06 11:01:00 »

Are you using the java 6u10 runtime?
If not, the AffineTransform(s) will be relegating all of your rendering to software.

Other than that, you arn't using BufferStrategy so the target surface of all your rendering may not be in graphics memory - again potencially causing all of the rendering to occur through software.
Ofcourse this again depends on Java version - i'm not sure if under-the-hood Canvas has been altered in the most recent JRE releases so that it always uses an accelerated surface for rendering.

3rdly, because the "RCR" image is obtained directly from ImageIO it will not be accelerated in older JRE's (releases prior to 1.5, or maybe 1.4.2, I forget when that flaw was fixed).
In these JRE's you need to copy it onto a compatible image for it to be eligable for acceleration.

Launch it with the java2d trace options enabled, to see which pipeline your rendering is going through.
( http://java.sun.com/j2se/1.5.0/docs/guide/2d/flags.html )

Make Elite IV:Dangerous happen! Pledge your backing at KICKSTARTER here! https://dl.dropbox.com/u/54785909/EliteIVsmaller.png
Offline Daniel_F

Junior Member


Projects: 2


Java games rock!


« Reply #4 - Posted 2008-11-06 11:08:15 »

I'm trying to get decent speed out of Java2D and it just isn't happening. ...

What if you change the run method to 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 void run()
        {
            boolean running = true;
            float target = 1000 / 60.0f;
            float frameAverage = target;
            long lastFrame = System.currentTimeMillis();
            float yield = 10000f;
            float damping = 0.1f;

            long lastSecond = lastFrame;
           
            setIgnoreRepaint(true);
            createBufferStrategy(3);
            BufferStrategy b = getBufferStrategy();

            while (running)
            {
               
                long timeNow = System.currentTimeMillis();
                frameAverage = (frameAverage * 10 + (timeNow - lastFrame)) / 11;
                lastFrame = timeNow;

                yield += yield*((target/frameAverage)-1)*damping+0.05f;

                for(int i = 0; i < yield; i++)
                    Thread.yield();
               
                if (timeNow - lastSecond >= 1000)
                {
                    fps = draws;
                    draws = 0;
                    lastSecond = timeNow;
                }
               
                //repaint();
               Graphics g = b.getDrawGraphics();
                g.clearRect(0, 0, getWidth(), getHeight());
                paint(g);
                g.dispose();
                if (!b.contentsLost()) b.show();
            }
        }
Offline CommanderKeith
« Reply #5 - Posted 2008-11-06 13:07:28 »

You need to use VolatileImages instead of BufferedImages in your sprite class, that's your problem. For some reason BufferedImages just don't cut it any more, they're usually un-accelerated for some reason.

Like Abuse said, if you run your program with the trace options (use this as an option: -Dsun.java2d.trace=,count) then you'll see lots of non d3d calls which means it's using software loops instead of hardware.

VolatileImages are a pain to use though, here's some code I use:

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
public static VolatileImage createVolatileImage(int width, int height, int transparency) {   
      GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
      GraphicsConfiguration gc = ge.getDefaultScreenDevice().getDefaultConfiguration();
      VolatileImage image = null;

      image = gc.createCompatibleVolatileImage(width, height, transparency);

      int valid = image.validate(gc);

      if (valid == VolatileImage.IMAGE_INCOMPATIBLE) {
         image = createVolatileImage(width, height, transparency);
      }
      System.out.println("created new VolatileImage");
      return image;
   }


1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
public void render(JComponent component){
      GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
      GraphicsConfiguration gc = ge.getDefaultScreenDevice().getDefaultConfiguration();
      if (vImage == null || getW() != vImage.getWidth() || getH() != vImage.getHeight() || vImage.validate(gc) != VolatileImage.IMAGE_OK) {
         vImage = createVolatileImage(getW(), getH(), Transparency.OPAQUE);
         drawOntoImage();
      }
      do {
         int valid = vImage.validate(gc);
         if (valid == VolatileImage.IMAGE_INCOMPATIBLE) {
            vImage = createVolatileImage();
            drawOntoImage();
         }
      } while (vImage.contentsLost());
      Graphics2D g2D = (Graphics2D)component.getGraphics();
      g2D.drawImage(vImage, x, y, null);
   }

Offline princec

JGO Kernel


Medals: 378
Projects: 3
Exp: 16 years


Eh? Who? What? ... Me?


« Reply #6 - Posted 2008-11-06 14:04:02 »

And the trouble is this is all entirely random advice when applied to any particular combination of OS and VM :/ It's no wonder we made LWJGL.

Cas Smiley

Offline erikd

JGO Ninja


Medals: 16
Projects: 4
Exp: 14 years


Maximumisness


« Reply #7 - Posted 2008-11-06 15:00:31 »

When I use Java2D to do something fast, I just limit myself to just doing simple things.

I think your main problem is using AffineTransform to scale (scaling using drawImage usually works quite fast), and Graphics.rotate is also slowing you down.
Without those things I still got a steady 60fps instead of a slideshow when rendering 2000 sprites (I also changed your run() method as Daniel_F suggested).
For rotation I myself use a class that pre-rotates an image.

Offline Abuse

JGO Knight


Medals: 12


falling into the abyss of reality


« Reply #8 - Posted 2008-11-06 16:34:51 »

And the trouble is this is all entirely random advice when applied to any particular combination of OS and VM :/ It's no wonder we made LWJGL.

Cas Smiley

Indeed, IMO Java2D was a poorly thought out API from the beginning.
The numerous attempts (between 1.3 & 1.6) to graft it ontop of different h/w accelerated native libraries across multiple platforms has left much of it's functionality unreliable due to this fragmentation.

While each release has for the most part conformed to the formal specifications set down by the API, the most important aspect of a graphics rendering API - Performance - has no formal specification, and consequently has not been correctly managed.

I wonder - do any common development languages impose performance specifications upon formal design interfaces?
I presume this is a far greater consideration for real-time systems?

Make Elite IV:Dangerous happen! Pledge your backing at KICKSTARTER here! https://dl.dropbox.com/u/54785909/EliteIVsmaller.png
Offline Orangy Tang

JGO Kernel


Medals: 56
Projects: 11


Monkey for a head


« Reply #9 - Posted 2008-11-06 16:48:22 »

I wonder - do any common development languages impose performance specifications upon formal design interfaces?
I presume this is a far greater consideration for real-time systems?

The only one that springs to mind is the specification for the C++ standard library. The containers and algorithms all have minimum big-O performance specified (eg. random access to a vector is guranteed to be O(1) ). This leads to the interesting side effect that while it's possible to implement a (say) std::map with whatever data structure / algorithm the implementator chooses, the performance restrictions usually mean there's a canonical data structure that everyone uses (like a red-black tree).

I'm not sure how well big-O notation would work for a graphics api though.

[ TriangularPixels.com - Play Growth Spurt, Rescue Squad and Snowman Village ] [ Rebirth - game resource library ]
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline princec

JGO Kernel


Medals: 378
Projects: 3
Exp: 16 years


Eh? Who? What? ... Me?


« Reply #10 - Posted 2008-11-06 19:53:55 »

Even OpenGL has no actual requirement for performance. It just so happens you can more or less rely on most of this basic stuff without worrying about it.

Cas Smiley

Offline Orangy Tang

JGO Kernel


Medals: 56
Projects: 11


Monkey for a head


« Reply #11 - Posted 2008-11-06 21:33:25 »

Even OpenGL has no actual requirement for performance. It just so happens you can more or less rely on most of this basic stuff without worrying about it.

Cas Smiley
It's been one of the major gripes (especially amongst the opengl.org community) recently though. It might be nice and whizzy for basic stuff but when you start getting into some of the more advanced extensions it can still be something of a performance lottery it seems.

[ TriangularPixels.com - Play Growth Spurt, Rescue Squad and Snowman Village ] [ Rebirth - game resource library ]
Offline Eli Delventhal

JGO Kernel


Medals: 42
Projects: 11
Exp: 10 years


Game Engineer


« Reply #12 - Posted 2008-11-06 22:22:59 »

Thanks for all the great responses, guys.

Looks like putting in a buffer strategy is what's really going to make the big difference (I can't actually test that at the moment), because all of the other suggestions I tried at one iteration or another, including volatile images, turning off rotation, turing off the affine transform, etc.

In the past I've only used buffer strategies for full screen modes, I didn't even know that it was a logical thing to use it in Swing elements and Applets.

See my work:
OTC Software
Offline Eli Delventhal

JGO Kernel


Medals: 42
Projects: 11
Exp: 10 years


Game Engineer


« Reply #13 - Posted 2008-11-07 06:42:06 »

Okay doing all that seems to work okay, certainly to an acceptable level.

But then how do you guys suggest doing the things I now have to leave out (namely rotation and scaling)? I can scale the images with drawImage, but what about rotation?

See my work:
OTC Software
Offline CommanderKeith
« Reply #14 - Posted 2008-11-07 07:04:52 »

Did VolatileImages work out? 

BufferStrategies use VolatileImages under the hood, except that BufferStrategies can also do pointer-flipping (which is faster) if in full-screen. But you should still have to use VolatileImages for your sprites.

To rotate and scale and all that, just change the Graphics2D's AffineTransform then paint your VolatileImage. That way everything should be accelerated if you've got java6u10 and a non-intel video card.

See this super-useful thread for the latest tips on using java2D - Kirill G of substance fame talks to Dmitri Trembovetski, our hero who's making java2d better every day:

http://forums.java.net/jive/thread.jspa?threadID=39749&tstart=0

I suppose the thread kind of shows how hard java2D is to use - I mean kirill is a top java programmer whose libs are used by everyone, but he never even knew how to get hardware-acceleration.


Offline Eli Delventhal

JGO Kernel


Medals: 42
Projects: 11
Exp: 10 years


Game Engineer


« Reply #15 - Posted 2008-11-07 07:16:22 »

I had already tried VolatileImages and noticed no differences. I just tried again and the only difference I noticed was that transparency stopped working.

Also do you mean this for rotation:
1  
2  
3  
g.rotate(rotation, x+width/2, y+height/2);
g.drawImage(image,(int)x,(int)y,null);
g.rotate(-rotation, x+width/2, y+height/2);


Because that just rapes the performance.

See my work:
OTC Software
Offline Eli Delventhal

JGO Kernel


Medals: 42
Projects: 11
Exp: 10 years


Game Engineer


« Reply #16 - Posted 2008-11-07 07:22:37 »

Also does anyone know a way to just reduce the resolution in a window? Like I want the resolution to be say 300 x 300 but the window is 900 x 900, it should just draw all the pixels at 3x normal size. But I'm not talking a way of simulating this (drawing everything bigger) but actually doing it.

See my work:
OTC Software
Offline Abuse

JGO Knight


Medals: 12


falling into the abyss of reality


« Reply #17 - Posted 2008-11-07 12:36:48 »

Also does anyone know a way to just reduce the resolution in a window? Like I want the resolution to be say 300 x 300 but the window is 900 x 900, it should just draw all the pixels at 3x normal size. But I'm not talking a way of simulating this (drawing everything bigger) but actually doing it.

Scaling what you draw is the only way of achieving that.

Make Elite IV:Dangerous happen! Pledge your backing at KICKSTARTER here! https://dl.dropbox.com/u/54785909/EliteIVsmaller.png
Offline Addictman

Senior Member


Medals: 3
Projects: 1


Java games rock!


« Reply #18 - Posted 2008-11-07 13:12:21 »

Of course, if we're only talking images here, you can simply draw a 300*300 image into a 900*900 once, and draw the 900*900 image from there on. (Sort of like the intermediate image technique). However, if you want everything to scale "real-time", you'll just have to scale on the fly.
Offline CommanderKeith
« Reply #19 - Posted 2008-11-07 15:43:34 »

I had already tried VolatileImages and noticed no differences. I just tried again and the only difference I noticed was that transparency stopped working.

Also do you mean this for rotation:
1  
2  
3  
g.rotate(rotation, x+width/2, y+height/2);
g.drawImage(image,(int)x,(int)y,null);
g.rotate(-rotation, x+width/2, y+height/2);


Because that just rapes the performance.

Hmm, so are you using java 6 update 10 on a machine with a non-intel video card? For that setup, everything should be accelerated.

If you want to get to the bottom of the problem, post the print-out when you run with this VM option:
-Dsun.java2d.trace=,count

Offline Eli Delventhal

JGO Kernel


Medals: 42
Projects: 11
Exp: 10 years


Game Engineer


« Reply #20 - Posted 2008-11-08 03:02:49 »

I only have Java 5, unfortunately. That could potentially be the problem, but Sun is slow about releasing new VMs for Mac.

See my work:
OTC Software
Offline CommanderKeith
« Reply #21 - Posted 2008-11-08 05:35:00 »

Oh ok, well that explains things, I just assumed you were using windows. Well then I suppose using the ogl-pipeline should work ok, but it got a lot better in java 6 so that's a pity there's no java 6 for mac yet.

Offline gouessej
« Reply #22 - Posted 2008-11-08 10:40:40 »

I only have Java 5, unfortunately. That could potentially be the problem, but Sun is slow about releasing new VMs for Mac.
It is not Sun's problem and it is not Sun's JVM under Mac! It is Apple's JVM and there is already a JVM 1.6 for Mac but only for Mac OS X 10.5 (software update 1). It has nothing to do with Sun as Apple has always refused Sun to write a JVM for Mac!

http://developer.apple.com/java/
http://developer.apple.com/java/overview.html

Offline Eli Delventhal

JGO Kernel


Medals: 42
Projects: 11
Exp: 10 years


Game Engineer


« Reply #23 - Posted 2008-11-08 20:52:12 »

It is not Sun's problem and it is not Sun's JVM under Mac! It is Apple's JVM and there is already a JVM 1.6 for Mac but only for Mac OS X 10.5 (software update 1). It has nothing to do with Sun as Apple has always refused Sun to write a JVM for Mac!

http://developer.apple.com/java/
http://developer.apple.com/java/overview.html
That's incorrect, the JVM 1.6 is only for 10.5 Macs with 64-bit processors.

Quote
Java for Mac OS X 10.5, Update 1
57MB   2008-04-29
Java for Mac OS X 10.5, Update 1 adds Java SE 6 version 1.6.0_05 to 64-bit Intel Macs.

See my work:
OTC Software
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.

Dwinin (22 views)
2014-09-12 09:08:26

Norakomi (55 views)
2014-09-10 13:57:51

TehJavaDev (66 views)
2014-09-10 06:39:09

Tekkerue (33 views)
2014-09-09 02:24:56

mitcheeb (54 views)
2014-09-08 06:06:29

BurntPizza (38 views)
2014-09-07 01:13:42

Longarmx (24 views)
2014-09-07 01:12:14

Longarmx (30 views)
2014-09-07 01:11:22

Longarmx (28 views)
2014-09-07 01:10:19

mitcheeb (37 views)
2014-09-04 23:08:59
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

List of Learning Resources
by SilverTiger
2014-07-31 11:54:12

HotSpot Options
by dleskov
2014-07-08 01:59:08
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!