Java-Gaming.org    
Featured games (79)
games approved by the League of Dukes
Games in Showcase (477)
Games in Android Showcase (108)
games submitted by our members
Games in WIP (536)
games currently in development
News: Read the Java Gaming Resources, or peek at the official Java tutorials
 
    Home     Help   Search   Login   Register   
Pages: [1] 2
  ignore  |  Print  
  Realtime raytracing experiments in pure Java  (Read 5734 times)
0 Members and 1 Guest are viewing this topic.
Offline Varkas
« Posted 2013-01-09 12:44:49 »

The insanity! But I dared and wanted to see what can be achieved with a simple raytracing engine and a Java2D rendering backend (Java2D isnt't the bottleneck here, as it turned out).

Edit start

Latest demo without shadows:
http://www.java-gaming.org/user-generated-content/members/132627/simpleray-r5.jar

Latest demo with shadows:
http://www.java-gaming.org/user-generated-content/members/132627/simpleray-r6.jar

Edit end

The results are surprising - realtime raytracing of simple scenes might be possible with Java on current computers. The preview doesn't look like much, but textures won't cause a big slowdown, and the two spheres have mirror surfaces, so the core features of raytracing, reflection and refraction seem to be doable. Lightsources and shadows will cause a slowdown though. For this scene, I'd estimate 30% slowdown for each additional light source. I'll find that out soon. In the demo the balls circle around the center of the checkerboard plane, so there shouldn't be any caching messing with my timings since each frame is different from the former.

Using one thread on a 2.5 GHz core i5 I get about 30FPS with my current code and three scene elements (two reflective) and 800x600 pixels.



I hope I can optimize the tracer itself some more, and when using all (virtual) cores of the CPU there might be a speedup of 3 or more in reach, which is looking promising.

I hope to get a little graphics demo out of this, wanted to do something like that since a while Smiley


if (error) throw new Brick(); // Blog (german): http://gedankenweber.wordpress.com
Offline alesky

Junior Member


Medals: 3
Exp: 15 years


mmm....


« Reply #1 - Posted 2013-01-09 14:38:09 »

wow, go haead and let us to know how i going!!!!!   Wink
Offline Varkas
« Reply #2 - Posted 2013-01-09 16:02:13 »

Going well so far Cheesy

Textures took a while, but I now have textures and two worker threads in place to parallelize the rendering process. Didn't result in such a big speedup, and the thread synchronisation was quite tricky, but it works.



I've put a demo up - I'm curious to hear if and how well this works on other systems. It does a few ugly hacks in the graphics code, and I feel uncertain if this will work well on other systems ...

http://www.java-gaming.org/user-generated-content/members/132627/simpleray.jar

It's an executable jar file, a double click should run it if you have Java 7 installed.

Also I'm curious how high/low the FPS will go on other PCs. I'm getting something like 30 FPS in average, but the movement isn't all smooth because some frames take notably longer to render than others. I have not yet found out why. Initially I thought it would skip frames or double-show buffered frames, but the double buffering seems to be alright. It's indeed the calculation time itself that can go up by 30% for some frames.

Anyways, looks promising and I want to add some light and color effects now to work into the direction of a graphics demo.

Edit: Resizing the window can annoy the rendering code to the point when it stops rendering. If you want to reproduce the bug, you have a 99% chance that resizing will work Grin

if (error) throw new Brick(); // Blog (german): http://gedankenweber.wordpress.com
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline theagentd
« Reply #3 - Posted 2013-01-09 16:51:13 »

62 FPS on an i7 860 @ 3.52GHz.

Why did you need any synchronization? It should be possible to do the ray tracing for each pixel in parallel without any synchronization at all. Shouldn't each pixel only depend on its own ray?

Myomyomyo.
Offline davedes
« Reply #4 - Posted 2013-01-09 17:03:27 »

Would love to try it on Mac 10.6.8, but alas, Java 7 requirement. Sad

Offline theagentd
« Reply #5 - Posted 2013-01-09 17:11:19 »

Would love to try it on Mac 10.6.8, but alas, Java 7 requirement. Sad
Oh! That's solvable! It's actually possible to download it! FOR FREE!  Wink

Myomyomyo.
Offline davedes
« Reply #6 - Posted 2013-01-09 17:44:27 »

Would love to try it on Mac 10.6.8, but alas, Java 7 requirement. Sad
Oh! That's solvable! It's actually possible to download it! FOR FREE!  Wink
Java 7 is not available for 10.6.8. Keep in mind roughly ~40-50% of Macs are still on 10.6.8, and are unable to run Java 7 apps.

Further, Java 7 will not work on OSX Chrome.

Nor will it work with LWJGL, until the devs fix it. So even if I did purchase Mountain Lion, I would need to switch back and forth between JREs in order to run Java 7 apps, Chrome applets and any LWJGL apps.

So basically Java 7 will cost me $30, a long download on my slow wifi, a lot of trouble, and of course all the little problems that tend to come with upgrading your operating system. Not worth it to run a Java 2D application which has no real reason to target JRE7 in the first place.

The whole thing is a pain in the ass. And all of this for string switch? Roll Eyes

Offline Danny02
« Reply #7 - Posted 2013-01-09 19:52:36 »

so very do I see the framerate?
Offline Varkas
« Reply #8 - Posted 2013-01-09 22:55:57 »

Why did you need any synchronization? It should be possible to do the ray tracing for each pixel in parallel without any synchronization at all. Shouldn't each pixel only depend on its own ray?

Synchronization was maybe a bit misleading. The problem is that the display thread needs to wait till all rendering threads have finished, and then switch the buffer and display the frame while the rendering threads work on the next frame.

Each pixel is independent. Just the threads must keep some order so that the parts come together in the right frame.

I'm not sure if I did it right, but I tried to compile it with "Java 6 binary level", and I hope this will execute with Java 6, too:

http://www.java-gaming.org/user-generated-content/members/132627/simpleray-r2.jar

It's also got a bugfix for the mentioned thread synchronization. It might be a tad faster than before. Tomorrow I'll try to work some more on it. Do the current AMD and Intel CPUs have two real FPUs, or even more?

@Danny02: The FPS are in the window title, updated every second.

if (error) throw new Brick(); // Blog (german): http://gedankenweber.wordpress.com
Offline davedes
« Reply #9 - Posted 2013-01-09 23:37:39 »

35 FPS here. Impressive!

The movement stutters a little. And on some runs the balls simply stop moving, and FPS is no longer updated. No error in the console.

Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline EgonOlsen
« Reply #10 - Posted 2013-01-09 23:55:27 »

Do the current AMD and Intel CPUs have two real FPUs, or even more?
Intel has one per physical core, older AMDs had that too. Newer AMDs (Bulldozer) have one per module (which includes 2 integer clusters), but that one can be used by both clusters and switches pretty fast. On my Core i7 (4 cores, 8 threads), i get 57fps with a cpu load of 25% (i.e. 2 of the 8 possible threads are at 100%).

Offline Varkas
« Reply #11 - Posted 2013-01-10 00:22:23 »

35 FPS here. Impressive!

Thanks! And thanks again for testing on a Mac. It's good to know that it works there, too.

The stuttering will stay until I try to smooth out the display of frames. At the moment each frame is displayed once it it is ready, and the rendering code for some reason has a notable jitter in the rendering times.

With some luck I could solve the deadlock though. it seems all three threads could run into a "wait()" call, and waited for a notify to continue, which never came because all threads were waiting ... I need a clear head and some sleep to look into this again.

A more bouncy version, hopefully with less deadlock:

http://www.java-gaming.org/user-generated-content/members/132627/simpleray-r3.jar

Thanks for all the feedback Smiley

if (error) throw new Brick(); // Blog (german): http://gedankenweber.wordpress.com
Offline Varkas
« Reply #12 - Posted 2013-01-10 00:25:34 »

On my Core i7 (4 cores, 8 threads), i get 57fps with a cpu load of 25% (i.e. 2 of the 8 possible threads are at 100%).

That looks reasonable. The third thread most likely vanishes in the backgground noise because it only does the display and buffer switching. Thanks also for the details on the CPUs!

Next will be to see how much slowdown shadows will cause. And glass bodies.

if (error) throw new Brick(); // Blog (german): http://gedankenweber.wordpress.com
Offline gouessej
« Reply #13 - Posted 2013-01-10 00:31:34 »

Sorry I just get a black window. OpenJDK 1.7 update 6

Offline Varkas
« Reply #14 - Posted 2013-01-10 00:34:14 »

OpenJDK 1.7 update 6

I guess my graphics tricks don't like that. Can you run it from a console window, and see if there is a ClassCastException or ArrayIndexOutOfBounds exception thrown? I had to reach deep into the raster classes to get Java2D working as a framebuffer for me.

if (error) throw new Brick(); // Blog (german): http://gedankenweber.wordpress.com
Offline alesky

Junior Member


Medals: 3
Exp: 15 years


mmm....


« Reply #15 - Posted 2013-01-10 00:36:25 »

for my works

fantastic!!!!

congratulation good job
Offline ra4king

JGO Kernel


Medals: 341
Projects: 2
Exp: 5 years


I'm the King!


« Reply #16 - Posted 2013-01-10 03:25:28 »

Steady 80FPS on my i7 2600K with GTX 580. I really need to learn how ray tracing works :S

Offline Best Username Ever

Junior Member





« Reply #17 - Posted 2013-01-10 04:37:10 »

The insanity! But I dared and wanted to see what can be achieved with a simple raytracing engine and a Java2D rendering backend (Java2D isnt't the bottleneck here, as it turned out).

Ha, I would not have thought of anything like that. It makes sense though.

Can triple buffering help synchronization? (I haven't read this myself... Cheesy)
Online Roquen
« Reply #18 - Posted 2013-01-10 10:30:17 »

If you haven't happened to think about this...don't forget cache coherency for your worker threads.
Offline Longor1996
« Reply #19 - Posted 2013-01-10 14:09:54 »

Um, the Raytracer crashes after 2-5 Minutes.
It just stops rendering and shows the last frame.
Is this intentional?

- Longor1996

Sorry for my bad English! That's because i am from Germany.
Offline Varkas
« Reply #20 - Posted 2013-01-10 15:21:21 »

Um, the Raytracer crashes after 2-5 Minutes.

I assume it ran into a deadlock. Till today I didn't know that multiple notify() calls can cause only one wait() to wake up if they happen at exactly the same time (and it happened ...)

I once more changed the threading concept. I hope it now works without deadlocks. It starts 8 rendering worker threads and one program thread, and is capped at 60 FPS for those with real powerful machines. I can't test the capping though, I don't reach that much FPS with my hardware Wink

I want to call this the "Turn up your fans, maximum core!" edition Grin
http://www.java-gaming.org/user-generated-content/members/132627/simpleray-r4.jar

3 mirror balls, one infinite plane and a sky sphere, give me ~30 FPS. I'm somewhat certain that I can't achieve big speedups anymore, but I'll see what I can do with it. It's a nice toy for sure Smiley

@Roquen: I've got one volatile variable which is increased by the worker threads to count how many workers are done yet. Now that you mention it, I must say that I'm not quite sure what happens with the frame buffer, which is written to by all worker threads.

@alesky: Thanks Cheesy

@ra4king: Wow, that is some gaming equipment you have there! Raytracing is a simple concept, but vector math ... well you know how to use OpenGL, so I assume have already learned most it Smiley

if (error) throw new Brick(); // Blog (german): http://gedankenweber.wordpress.com
Offline nsigma
« Reply #21 - Posted 2013-01-10 15:36:50 »

I assume it ran into a deadlock. Till today I didn't know that multiple notify() calls can cause only one wait() to wake up if they happen at exactly the same time (and it happened ...)
...
@Roquen: I've got one volatile variable which is increased by the worker threads to count how many workers are done yet. Now that you mention it, I must say that I'm not quite sure what happens with the frame buffer, which is written to by all worker threads.

A volatile variable is probably not a good idea.  Increment is a get and set operation which is not thread safe.  How about AtomicInteger?

Given that threading is hard, and prone to issues, how about using some of the concurrency utils built in to the JDK?  You could use an ExecutorService to manage the worker threads, and have your render thread wait on each Future.get() in turn.

I guess my graphics tricks don't like that. Can you run it from a console window, and see if there is a ClassCastException or ArrayIndexOutOfBounds exception thrown? I had to reach deep into the raster classes to get Java2D working as a framebuffer for me.

What does that mean exactly?  Are you working directly with an int[] of pixels?  Where are you getting them from - a BufferedImage?  If so, you could also build an image from your array rather than trying to get the array from the image - this code might help (PixelData is just a wrapper to an int[] and dimensions, etc.)

Praxis LIVE - open-source intermedia toolkit and live interactive visual editor
Digital Prisoners - interactive spaces and projections
Offline Varkas
« Reply #22 - Posted 2013-01-10 16:04:02 »

A volatile variable is probably not a good idea.  Increment is a get and set operation which is not thread safe.  How about AtomicInteger?

Maybe I was wrong again. I thought an x++ is an atomic operation in Java. I didn't look into the new concurrency classes yet (I've been working with Java 1.4 tooo long ...), but I heard they are useful. AtomicInteger is new to me, but seems to be what I should have used there.

Given that threading is hard, and prone to issues, how about using some of the concurrency utils built in to the JDK?

I guess it would be a good idea Grin

What does that mean exactly?  Are you working directly with an int[] of pixels?  Where are you getting them from - a BufferedImage?

BufferedImage -> WriteableRaster -> DataBuffer -> int []

I've been surprised that it was actually accessible. But I must admit my last try to dig into the graphics internals was done with Java 1.2, and my memory says that the structures were not so easily accessible back then.

If so, you could also build an image from your array rather than trying to get the array from the image - this code might help)

That's about what I have been doing, just that they build an BufferedImage from the data, while I wanted to write into the buffer of an already existing BufferedImage. But thanks, it's good to know that the method is used, and that it's not as hacky as I had assumed Smiley

At least it opened a lot of options for me, since I was/am used to working with frame buffer devices and I can now use a lot of tricks that I was used from my older projects. Writing all pixels in a loop gave me 144 FPS on my PC, using one thread. That seemed to have plenty of reserves for application code, and was much faster than my former tries to display graphics with Java2D, which were more like giving 15-20 FPS. My bigger game projects don't need it right now, but it's good to know that once can use Java this way nowadays Smiley

The only question that really puzzles me is why drawing operations including alpha blending are so slow for volatile images on some graphics adapters. On my PC drawing semi-transparent buffered images to a volatile image resulted in like 400 FPS and on my laptop about 20 FPS. This is too much difference to be easily understood by my poor brain  persecutioncomplex

Thanks for the hints with the new concurrency classes!

if (error) throw new Brick(); // Blog (german): http://gedankenweber.wordpress.com
Offline nsigma
« Reply #23 - Posted 2013-01-10 16:28:05 »

Maybe I was wrong again. I thought an x++ is an atomic operation in Java.

No, it isn't.  See eg. http://jeremymanson.blogspot.co.uk/2007/08/volatile-does-not-mean-atomic.html

BufferedImage -> WriteableRaster -> DataBuffer -> int []

I've been surprised that it was actually accessible. But I must admit my last try to dig into the graphics internals was done with Java 1.2, and my memory says that the structures were not so easily accessible back then.

Nothing (relevant) has changed as far as I can see.  You just need to be careful where you're getting the BufferedImage from and what format it's in.  Any TYPE_INT_* should give you an int[] though, so might not be the cause of Julien's issue.  It's not hacky either - it's what BufferedImages were designed for!  The code I pointed to is mine btw - feel free to use anything from that class without worrying about the license.

Slight bit of pedantry, but I'd say the title of this thread isn't entirely accurate - if you're doing all the raytracing through direct array manipulation it's not really in Java2D.

Praxis LIVE - open-source intermedia toolkit and live interactive visual editor
Digital Prisoners - interactive spaces and projections
Offline Varkas
« Reply #24 - Posted 2013-01-10 16:42:15 »

The deadlock in r3 was caused by something else. I don't think someone has given feedback to the r4 yet (the one with the volatile int for the workers done count). But just to be safe, I've changed that to an AtomicInteger:

http://www.java-gaming.org/user-generated-content/members/132627/simpleray-r5.jar

There was also a bug in r4 that disabled the 60FPS cap. I still couldn't test it, but in r5 it's at least enabled.

Regarding the buffered images, maybe I just didn't know the right was when I tried it first. Well, at least I know it now and I'm happy that it works Smiley

And yes, I've taken care to create a BufferedImage of TYPE_INT_RGB, in the hope that those will always get an IntDataBuffer. Maybe Julien just ran into an immediate deadlock, I dunno. If the r5 works, I'll blame my buggy threading.

I'll adjust the thread title.

if (error) throw new Brick(); // Blog (german): http://gedankenweber.wordpress.com
Offline theagentd
« Reply #25 - Posted 2013-01-10 16:49:58 »

Shameless plug: http://code.google.com/p/small-java-threading-library/.

I'd say do it like this:
1. Start X threads when the program starts.
2. When you want to render, signal the threads to start in some way.
3. Then each thread gets and increases an AtomicInteger to get a pixel index. Each thread then processes for example 1000 pixels or so, basically something like this in a loop:
1  
2  
3  
4  
5  
6  
7  
8  
9  
int pixelIndex = atomicInteger.getAndIncrement();
//Add code to terminate if done.
int start = pixelIndex * PIXELS_PER_BATCH;
int end = Math.min((pixelIndex + 1) * PIXELS_PER_BATCH, width*height);
for(int i = start; i < end; i++){
    int pixelX = i % screenWidth;
    int pixelY = i / screenHeight;
    processPixel(pixelX, pixelY);
}


The point of using the PIXEL_PER_BATCH variable is to reduce the amount of synchronization so that you don't have to synchronize per pixel. However, we still want to have a pretty big number of subtasks since each subtask can take a very different amount of time depending on what geometry it hits.

If you were to use my threading library, here's the code 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  
//Constant:
private static final int PIXELS_PER_BATCH = 1000;


//Setup code:
TaskTreeBuilder builder = new TaskTreeBuilder();
SplitTask task = new SplitTask(0, 0, 1) {
   
   @Override
   protected void runSubtask(int subtask) {
      int start = subtask * PIXELS_PER_BATCH;
      int end = Math.max((subtask + 1) * PIXELS_PER_BATCH, width*height);
      for(int i = start; i < end; i++){
          int pixelX = i % screenWidth;
          int pixelY = i / screenHeight;
          processPixel(pixelX, pixelY);
      }
   }
   
   @Override
   public void finish() {}
};

builder.addTask(task);

TaskTree tree = builder.build();
GameExecutor executor = new MultithreadedExecutor(Runtime.getRuntime().availableProcessors());


//Game loop code:
task.setSubtasks((width * height + PIXELS_PER_BATCH - 1) / PIXELS_PER_BATCH); //Round up division
executor.run(tree);

Myomyomyo.
Offline Danny02
« Reply #26 - Posted 2013-01-10 16:52:41 »

Hey you could try Aparapi for this. Would give it a try if wouldn't be that tired atm
Offline Riven
« League of Dukes »

JGO Overlord


Medals: 749
Projects: 4
Exp: 16 years


Hand over your head.


« Reply #27 - Posted 2013-01-10 16:53:28 »

The deadlock in r3 was caused by something else. I don't think someone has given feedback to the r4 yet (the one with the volatile int for the workers done count). But just to be safe, I've changed that to an AtomicInteger

When using volatile variables, you have a guarantee that the value you read is from the main memory, instead of from the processor cache. This does not mean you can increment it reliably from more than one thread, as an increment is basically:
1  
2  
3  
4  
5  
6  
volatile int counter;

{
    int n = counter;
    counter = n + 1;
}

You can see how the read and the write are two instructions, so multiple threads can and up interleaving these instructions, causing lost increments.

Just using AtomicInteger doesn't solve it, as it's just a volatile integer underneath. You must use
counter.incrementAndGet()
or
counter.getAndIncrement()
as they have the required functionality (compare-and-swap) to guarantee increments from multiple threads.

Hi, appreciate more people! Σ ♥ = ¾
Learn how to award medals... and work your way up the social rankings
Offline Varkas
« Reply #28 - Posted 2013-01-10 16:59:29 »

I'll try to post the relevant code parts to give an idea what I'm doing. The code is from r5.

Tracer setup and thread management:
    
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
    public Tracer(DisplayPanel panel)
    {
        this.displayPanel = panel;
        this.objects = new ArrayList<SceneObject>();
        this.workers = new ArrayList<WorkerThread>();
        this.doneCount = new AtomicInteger(0);
       
        int count = 8;
       
        for(int i=0; i<count; i++)
        {
            workers.add(new WorkerThread(this, i));
        }


1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
    private void setup()
    {
        camera = new V3(2, -10, 7);
        lookAt = new V3(0, 1, 0);

[snipsnip]
       
        for(WorkerThread worker : workers)
        {
            worker.start();
        }


Tracer doing thread workload distribution:

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
    void calculateScene()
    {
        final int height = displayPanel.getHeight();
        final int width = displayPanel.getWidth();
        final int hh = height >> 1;
       
        final int stripe = height / workers.size() + 1;
       
        for(int i=0; i<workers.size(); i++)
        {
            final int yStart = -hh + i * stripe;
            final int yEnd = Math.min(hh, yStart + stripe);
           
            WorkerThread worker = workers.get(i);
            worker.startRendering(yStart, yEnd, width);

            synchronized(worker)
            {
                worker.notify();
            }
        }
    }


Worker callback when done:

1  
2  
3  
4  
5  
6  
7  
8  
9  
    public synchronized void workerDone()
    {
        int count = doneCount.incrementAndGet();
       
        if(count == workers.size())
        {
            notify();
        }
    }

    
Tracer sync'ing on all workers done:

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
    private synchronized void waitForSceneFinish()
    {
        try
        {
            // System.err.println("waiting for workers on frame=" + frame);
           
            wait();
           
            doneCount.set(0);
        }
        catch (InterruptedException ex)
        {
            Logger.getLogger(Tracer.class.getName()).log(Level.SEVERE, null, ex);
        }
    }



Worker thread core method:

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
    private synchronized void calculate()
    {
        while(true)
        {
            try
            {
                wait();
                tracer.calculateScene(yStart, yEnd, v, p, lineV, linepix);            
                tracer.workerDone();
            }
            catch (InterruptedException ex)
            {
                Logger.getLogger(WorkerThread.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }


Tracer scene building:

1  
2  
3  
4  
5  
6  
    synchronized void nextFrame(Graphics gr)
    {
        calculateScene();
        displayPanel.paint(gr);
        waitForSceneFinish();
    }

if (error) throw new Brick(); // Blog (german): http://gedankenweber.wordpress.com
Offline nsigma
« Reply #29 - Posted 2013-01-10 17:12:41 »

Just to say, since posting earlier I've given this a go (r5).  Good work!  I get a steady 30fps with OpenJDK 1.6 on Ubuntu 12.04 - Intel® Core™ i5 CPU M 430 @ 2.27GHz × 4  Top gives me this running at ~300% CPU (100% per virtual core).


Praxis LIVE - open-source intermedia toolkit and live interactive visual editor
Digital Prisoners - interactive spaces and projections
Pages: [1] 2
  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.

CogWheelz (16 views)
2014-07-30 21:08:39

Riven (22 views)
2014-07-29 18:09:19

Riven (14 views)
2014-07-29 18:08:52

Dwinin (12 views)
2014-07-29 10:59:34

E.R. Fleming (32 views)
2014-07-29 03:07:13

E.R. Fleming (12 views)
2014-07-29 03:06:25

pw (43 views)
2014-07-24 01:59:36

Riven (42 views)
2014-07-23 21:16:32

Riven (30 views)
2014-07-23 21:07:15

Riven (31 views)
2014-07-23 20:56:16
HotSpot Options
by dleskov
2014-07-08 03:59:08

Java and Game Development Tutorials
by SwordsMiner
2014-06-14 00:58:24

Java and Game Development Tutorials
by SwordsMiner
2014-06-14 00:47:22

How do I start Java Game Development?
by ra4king
2014-05-17 11:13:37

HotSpot Options
by Roquen
2014-05-15 09:59:54

HotSpot Options
by Roquen
2014-05-06 15:03:10

Escape Analysis
by Roquen
2014-04-29 22:16:43

Experimental Toys
by Roquen
2014-04-28 13:24:22
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!