Java-Gaming.org    
Featured games (79)
games approved by the League of Dukes
Games in Showcase (477)
Games in Android Showcase (107)
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]
  ignore  |  Print  
  [SOLVED] sharing a GLContext across several GLCanvas and JPanel instances  (Read 3102 times)
0 Members and 1 Guest are viewing this topic.
Offline voodoogiant

Senior Newbie





« Posted 2010-08-08 02:45:59 »

I have small app that have a tab widget holding several JPanels, each holding a GLCanvas.  After getting a VBO setup and working in one, I found my app would crash (SIGSEGV) if I moved from tab to another. I figured this had something to do with trying to share the VBO and/or shaders across contexts.  To solve the problem, I figured I would change the way I create the GLCanvas, by sending it a context from a previous GLCanvas if it already exists. 

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
    capabilities = new GLCapabilities(profile)

    //initialize a GLDrawable of your choice
    if (PanelGL.context == null) {
      canvas = new GLCanvas(capabilities)
      PanelGL.context = canvas.getContext()
    }
    else {
      new GLCanvas(capabilities,
                   new DefaultGLCapabilitiesChooser(),
                   PanelGL.context,
                   null)
    }


This fixed the error, but now on the second and third GLCanvases their screens are completely green.  The green makes sense as right now I just have it hard-coded into the fragment shader, but on the first screen while I see the bunny model, on the second and third it's just green.  I don't know if it's a bug in my setup or if the camera is just too close to the model (although I'm guessing it's more my setup). 

As I am running Linux, I have tried adding the "-Djogl.GLContext.optimize" as recommended in the JOGL User Guide, but that just made my program exit instead of getting the green screen. 

Is this the correct way to share a context across multiple CLCanvas instances?  Do I need to do anything different with the VBO and shaders to share them as well? 
Offline lhkbob

JGO Knight


Medals: 32



« Reply #1 - Posted 2010-08-09 17:09:17 »

That should be the proper way to share an OpenGL canvas, at least in the way you're calling the constructor.  The code itself doesn't make sense because in one condition you're assigning the first GLCanvas to a canvas variable, and in the other you're just doing new GLCanvas().  Maybe that was just for the purposes of the post?

Here are some things to try:
1. Make sure your first GLCanvas is visible before you use it to create the other GLCanvas's, because it might not have set its GLContext up correctly until it is added to a visible component (that's a maybe, most times GLCanvas is pretty good about having a context right away).

2. Check the behavior of the tab widget to see if switching tabs indirectly calls addNotify() and removeNotify() on the GLCanvas's.  You can do this by extending the GLCanvas class, overriding those two methods to print out statements and then call super.XNotify().

3. Use a GLPBuffer as the shared context. You create a 1x1 context in the beginning of your code and all GLCanvases share with it.

Offline voodoogiant

Senior Newbie





« Reply #2 - Posted 2010-08-10 15:20:02 »

1. Make sure your first GLCanvas is visible before you use it to create the other GLCanvas's, because it might not have set its GLContext up correctly until it is added to a visible component (that's a maybe, most times GLCanvas is pretty good about having a context right away).

I tried that with limited success.  I overrode the setVisible function and added the GLCanvas then.  I store it's context and try using it when the other two pop up.  I get an image on the first panel but nothing at all on the second two panels.  Would I have more success using GLJPanel? 

2. Check the behavior of the tab widget to see if switching tabs indirectly calls addNotify() and removeNotify() on the GLCanvas's.  You can do this by extending the GLCanvas class, overriding those two methods to print out statements and then call super.XNotify().

What exactly am I checking for? 

3. Use a GLPBuffer as the shared context. You create a 1x1 context in the beginning of your code and all GLCanvases share with it.

Doing this, I got a ton of stuff dumped to the screen, but didn't get an image in any of the GLCanvas's that tried to use the context. 

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
    [java] Desired: GLCapabilities[Capabilities[Onscreen: false, Red: 8, Green: 8, Blue: 8, Alpha: 0, Opaque: true], GL profile: GLProfile[GL3/GL3], PBuffer: true, DoubleBuffered: false, Stereo: false, HardwareAccelerated: true, DepthBits: 24, StencilBits: 0, Red Accum: 0, Green Accum: 0, Blue Accum: 0, Alpha Accum: 0, Multisample: false, Num samples: 0, PBuffer-FloatingPointBuffers: false, PBuffer-RenderToTexture: false, PBuffer-RenderToTextureRectangle: false]
     [java] Available 0: GLCapabilities[Capabilities[Onscreen: false, Red: 8, Green: 8, Blue: 8, Alpha: 0, Opaque: true], GL profile: GLProfile[GL3/GL3], PBuffer: true, DoubleBuffered: false, Stereo: false, HardwareAccelerated: true, DepthBits: 24, StencilBits: 0, Red Accum: 16, Green Accum: 16, Blue Accum: 16, Alpha Accum: 16, Multisample: false, Num samples: 0, PBuffer-FloatingPointBuffers: false, PBuffer-RenderToTexture: false, PBuffer-RenderToTextureRectangle: false]
     [java] Available 1: GLCapabilities[Capabilities[Onscreen: false, Red: 8, Green: 8, Blue: 8, Alpha: 8, Opaque: true], GL profile: GLProfile[GL3/GL3], PBuffer: true, DoubleBuffered: false, Stereo: false, HardwareAccelerated: true, DepthBits: 24, StencilBits: 0, Red Accum: 16, Green Accum: 16, Blue Accum: 16, Alpha Accum: 16, Multisample: false, Num samples: 0, PBuffer-FloatingPointBuffers: false, PBuffer-RenderToTexture: false, PBuffer-RenderToTextureRectangle: false]
     [java] Available 2: GLCapabilities[Capabilities[Onscreen: false, Red: 8, Green: 8, Blue: 8, Alpha: 0, Opaque: true], GL profile: GLProfile[GL3/GL3], PBuffer: true, DoubleBuffered: false, Stereo: false, HardwareAccelerated: true, DepthBits: 24, StencilBits: 0, Red Accum: 16, Green Accum: 16, Blue Accum: 16, Alpha Accum: 16, Multisample: false, Num samples: 0, PBuffer-FloatingPointBuffers: false, PBuffer-RenderToTexture: false, PBuffer-RenderToTextureRectangle: false]
     [java] Available 3: GLCapabilities[Capabilities[Onscreen: false, Red: 8, Green: 8, Blue: 8, Alpha: 8, Opaque: true], GL profile: GLProfile[GL3/GL3], PBuffer: true, DoubleBuffered: false, Stereo: false, HardwareAccelerated: true, DepthBits: 24, StencilBits: 0, Red Accum: 16, Green Accum: 16, Blue Accum: 16, Alpha Accum: 16, Multisample: false, Num samples: 0, PBuffer-FloatingPointBuffers: false, PBuffer-RenderToTexture: false, PBuffer-RenderToTextureRectangle: false]
     [java] Available 4: GLCapabilities[Capabilities[Onscreen: false, Red: 8, Green: 8, Blue: 8, Alpha: 0, Opaque: true], GL profile: GLProfile[GL3/GL3], PBuffer: true, DoubleBuffered: false, Stereo: false, HardwareAccelerated: true, DepthBits: 24, StencilBits: 0, Red Accum: 16, Green Accum: 16, Blue Accum: 16, Alpha Accum: 16, Multisample: false, Num samples: 0, PBuffer-FloatingPointBuffers: false, PBuffer-RenderToTexture: false, PBuffer-RenderToTextureRectangle: false]
     [java] Available 5: GLCapabilities[Capabilities[Onscreen: false, Red: 8, Green: 8, Blue: 8, Alpha: 8, Opaque: true], GL profile: GLProfile[GL3/GL3], PBuffer: true, DoubleBuffered: false, Stereo: false, HardwareAccelerated: true, DepthBits: 24, StencilBits: 0, Red Accum: 16, Green Accum: 16, Blue Accum: 16, Alpha Accum: 16, Multisample: false, Num samples: 0, PBuffer-FloatingPointBuffers: false, PBuffer-RenderToTexture: false, PBuffer-RenderToTextureRectangle: false]
     [java] Available 6: GLCapabilities[Capabilities[Onscreen: false, Red: 8, Green: 8, Blue: 8, Alpha: 0, Opaque: true], GL profile: GLProfile[GL3/GL3], PBuffer: true, DoubleBuffered: false, Stereo: false, HardwareAccelerated: true, DepthBits: 24, StencilBits: 8, Red Accum: 16, Green Accum: 16, Blue Accum: 16, Alpha Accum: 16, Multisample: false, Num samples: 0, PBuffer-FloatingPointBuffers: false, PBuffer-RenderToTexture: false, PBuffer-RenderToTextureRectangle: false]
     [java] Available 7: GLCapabilities[Capabilities[Onscreen: false, Red: 8, Green: 8, Blue: 8, Alpha: 8, Opaque: true], GL profile: GLProfile[GL3/GL3], PBuffer: true, DoubleBuffered: false, Stereo: false, HardwareAccelerated: true, DepthBits: 24, StencilBits: 8, Red Accum: 16, Green Accum: 16, Blue Accum: 16, Alpha Accum: 16, Multisample: false, Num samples: 0, PBuffer-FloatingPointBuffers: false, PBuffer-RenderToTexture: false, PBuffer-RenderToTextureRectangle: false]
     [java] Available 8: GLCapabilities[Capabi ...

etc.

Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline lhkbob

JGO Knight


Medals: 32



« Reply #3 - Posted 2010-08-10 16:58:52 »

What exactly am I checking for? 
Look for removeNotify() being called on the GLCanvas's when they are hidden by another tab, and addNotify() being called when a GLCanvas should be made visible. This might suggest that the contexts are being destroyed and remade each time a tab is switched. Alternatively, it could appear to be multiple addNotify() in the beginning without any removeNotify() which would suggest that the GLCanvas's are initialized once internally and aren't destroyed by tabbing.

Quote
Doing this, I got a ton of stuff dumped to the screen, but didn't get an image in any of the GLCanvas's that tried to use the context. 
This looks like you have some debugging enabled in JOGL and these look like the capability options for the pbuffer.

If you could send me some code, here or by PM, I could take a more thorough look through it.

Offline voodoogiant

Senior Newbie





« Reply #4 - Posted 2010-08-11 03:27:57 »

Between creating a pBuffer and sharing the first context created, are there advantages and disadvantages to each one? 

Here's my code in scala.  I'm probably doing something naive.  removeNotify never seems to be called switching panels. 

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  
  object PanelGL {
    var context = null : GLContext
    var capabilities = null : GLCapabilities
    var profile = null : GLProfile
    def getContext():GLContext = {
      if (context == null) {
        //create a profile, in this case OpenGL 3.1 or later
       val capabilities = getCapabilities()
        capabilities.setDepthBits(24)
        val pBuffer = GLDrawableFactory.getFactory(profile).createGLPbuffer(capabilities, new DefaultGLCapabilitiesChooser, 1, 1, null)
        context = pBuffer.getContext()
      }
      context
    }
    def getCapabilities():GLCapabilities = {
      if (profile == null)
        profile = GLProfile.get(GLProfile.GL3);
      if (capabilities == null)
        capabilities = new GLCapabilities(profile)
      capabilities
    }
   
    def instance:PanelGL = {
      val singlePanel = new PanelGL()
      Copper.glPanels += singlePanel
       
      singlePanel
    }
  }
  class PanelGL extends JPanel with GLEventListener with MouseListener with MouseMotionListener {
    setLayout(new BorderLayout())
    setMinimumSize(new Dimension(200,200))
    setPreferredSize(new Dimension(800,600))

    var canvas = null : GLCanvas // initialized when the panel is set to visible

    override def setVisible(aFlag:boolean) {
      super.setVisible(aFlag)

      if (canvas == null) {
        canvas = new GLCanvas(PanelGL.getCapabilities(),
                              new DefaultGLCapabilitiesChooser,
                              PanelGL.getContext(),
                              null)
        add(BorderLayout.CENTER, canvas)
      }

      //register GLEventListener
     canvas.addGLEventListener(this)
    }

    override def addNotify() {
      super.addNotify()
      println("addNotify")
    }

    override def removeNotify() {
      super.removeNotify()
      println("removeNotify")
    }


I just barely found this and was going to start scanning through it to see how it implements the context sharing. 
http://www.koders.com/java/fidDAD2B2DC72C134C327CCD667898FC9BE0F185930.aspx
Offline lhkbob

JGO Knight


Medals: 32



« Reply #5 - Posted 2010-08-11 17:19:06 »

A pbuffer's context is theoretically more stable for use with context sharing (it won't go away due to the window system or anything like that).

Looking at your code, nothing jumped out at me, but I also don't experience with scala so I can't be certain.  Do you continue to get the odd rendering behavior with using the pbuffer? It could be that there is a bug in your rendering code. When contexts are shared, the objects like vbos and textures and shaders are shared, but the opengl state is not, so you might have to make sure you're properly setting up the camera and matrices for each context when you render.

Offline voodoogiant

Senior Newbie





« Reply #6 - Posted 2010-08-13 06:26:58 »

Maybe if I made a simpler example.  If the JPanel below were to be a GLEventListener with a GLCanas inside it, how would one set it up so all instances shared the same context as a pbuffer? 

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
import javax.swing.*;
import java.awt.*;

public class Test extends JPanel
{
    public static void main(String[] args) {
   Test test = new Test();

   JFrame frame = new JFrame("test");
   JTabbedPane pane = new JTabbedPane();
   pane.addTab("Tab 1", new Test());
   pane.addTab("Tab 2", new Test());
   pane.addTab("Tab 3", new Test());
   frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
   frame.setContentPane(pane);
   frame.setSize(800,600);
   frame.setVisible(true);
    }

    JTabbedPane tabbedPane;

    Test() {
    }
}
Offline lhkbob

JGO Knight


Medals: 32



« Reply #7 - Posted 2010-08-14 00:59:25 »

So I took your shell and filled in the details and on my computer everything gets shared correctly when USE_SHARING is true. Just paste it into a file named Test.java and it should compile and run if jogl is setup.

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  
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;

import javax.media.opengl.DefaultGLCapabilitiesChooser;
import javax.media.opengl.GL;
import javax.media.opengl.GL2;
import javax.media.opengl.GLAutoDrawable;
import javax.media.opengl.GLCapabilities;
import javax.media.opengl.GLDrawableFactory;
import javax.media.opengl.GLEventListener;
import javax.media.opengl.GLPbuffer;
import javax.media.opengl.GLProfile;
import javax.media.opengl.awt.GLCanvas;
import javax.swing.JFrame;
import javax.swing.JTabbedPane;

import com.jogamp.opengl.util.FPSAnimator;

public class Test {
    public static boolean USE_SHARING = true;
   
    public static void main(String[] args) {
        // make pbuffer
       GLProfile profile = GLProfile.get(GLProfile.GL2);
        GLCapabilities glCaps = new GLCapabilities(profile);
        glCaps.setPBuffer(true);
        GLPbuffer pbuffer = GLDrawableFactory.getFactory(profile).createGLPbuffer(glCaps,
                                                                                  new DefaultGLCapabilitiesChooser(),
                                                                                  1, 1, null);
       
        // make 3 canvases
       glCaps = new GLCapabilities(profile);
        GLCanvas canvas1, canvas2, canvas3;
       
        if (USE_SHARING) {
            canvas1 = new GLCanvas(glCaps, new DefaultGLCapabilitiesChooser(), pbuffer.getContext(), null);
            canvas2 = new GLCanvas(glCaps, new DefaultGLCapabilitiesChooser(), pbuffer.getContext(), null);
            canvas3 = new GLCanvas(glCaps, new DefaultGLCapabilitiesChooser(), pbuffer.getContext(), null);
        } else {
            canvas1 = new GLCanvas(glCaps);
            canvas2 = new GLCanvas(glCaps);
            canvas3 = new GLCanvas(glCaps);
        }
       

        canvas1.addGLEventListener(new TestRenderer(new float[] { 1f, 0f, 0f }));
        canvas2.addGLEventListener(new TestRenderer(new float[] { 0f, 1f, 0f }));
        canvas3.addGLEventListener(new TestRenderer(new float[] { 0f, 0f, 1f }));
       
       
        // set up frame and tabs
       JFrame frame = new JFrame();
        JTabbedPane pane = new JTabbedPane();
        pane.addTab("Red Canvas", canvas1);
        pane.addTab("Green Canvas", canvas2);
        pane.addTab("Blue Canvas", canvas3);
       
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setContentPane(pane);
        frame.setSize(800, 600);
        frame.setVisible(true);
       
        new FPSAnimator(canvas1, 10).start();
        new FPSAnimator(canvas2, 10).start();
        new FPSAnimator(canvas3, 10).start();
    }
   
    private static class TestRenderer implements GLEventListener {
        private static int textureId = -1;
       
        private float[] color;
       
        public TestRenderer(float[] color) {
            this.color = color;
        }
       
        @Override
        public void display(GLAutoDrawable drawable) {
            GL2 gl = drawable.getGL().getGL2();
           
            // set custom background color to distinguish tabs
           gl.glClearColor(color[0], color[1], color[2], 1f);
            gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
           
            gl.glEnable(GL.GL_TEXTURE_2D);
            gl.glBindTexture(GL.GL_TEXTURE_2D, textureId);
           
            // make this white so the texture appears correctly
           // if the texture wasn't shared properly, the quad will be all white
           gl.glColor4f(1f, 1f, 1f, 1f);
           
            gl.glBegin(GL2.GL_QUADS);
                gl.glVertex3f(-1f, 1f, 0f); gl.glTexCoord2f(0f, 1f);
                gl.glVertex3f(-1f, -1f, 0f); gl.glTexCoord2f(0f, 0f);
                gl.glVertex3f(1f, -1f, 0f); gl.glTexCoord2f(1f, 0f);
                gl.glVertex3f(1f, 1f, 0f); gl.glTexCoord2f(1f, 1f);
            gl.glEnd();
           
            gl.glDisable(GL.GL_TEXTURE_2D);
            gl.glBindTexture(GL.GL_TEXTURE_2D, 0);
        }

        @Override
        public void dispose(GLAutoDrawable drawable) {
            // do nothing
       }

        @Override
        public void init(GLAutoDrawable drawable) {
            GL2 gl = drawable.getGL().getGL2();
            System.out.println("Initializing GLCanvas@" + Integer.toHexString(drawable.hashCode()));
            if (textureId < 0) {
                int[] id = new int[1];
                gl.glGenTextures(1, id, 0);
                textureId = id[0];
               
                System.out.println("Creating texture on GLCanvas@" + Integer.toHexString(drawable.hashCode()) + " with ID=" + textureId);

                // fill up pixel image with a gradient pattern
               gl.glBindTexture(GL.GL_TEXTURE_2D, textureId);
                int width = 16;
                int height = 16;
               
                FloatBuffer data = ByteBuffer.allocateDirect(4 * 3 * width * height).order(ByteOrder.nativeOrder()).asFloatBuffer();
                for (int y = 0; y < height; y++) {
                    for (int x = 0; x < width; x++) {
                        data.put(3 * (y * width + x) + 0, x / (float) width);
                        data.put(3 * (y * width + x) + 1, y / (float) height);
                        data.put(3 * (y * width + x) + 2, 0f);
                    }
                }
               
                gl.glTexImage2D(GL.GL_TEXTURE_2D, 0, GL.GL_RGB, width, height, 0, GL.GL_RGB, GL.GL_FLOAT, data.rewind());
                gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, GL.GL_NEAREST);
                gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, GL.GL_NEAREST);
               
                gl.glBindTexture(GL.GL_TEXTURE_2D, 0);
            }
        }

        @Override
        public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) {
            GL2 gl = drawable.getGL().getGL2();
            gl.glMatrixMode(GL2.GL_PROJECTION);
            gl.glLoadIdentity();
            gl.glOrtho(-2, 2, -2, 2, -1, 1);
           
            gl.glMatrixMode(GL2.GL_MODELVIEW);
            gl.glLoadIdentity();
        }
    }
}

Offline voodoogiant

Senior Newbie





« Reply #8 - Posted 2010-08-14 16:04:34 »

It worked!  You are all beautiful people. 

The main two differences I can see are calling setPBuffer(...) on the GLCapabilities I pass to the pbuffer, and making a separate GLCapabilities object for the GLCanvas's than I use for the pbuffer itself. 

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
  object PanelGL {
    val profile = GLProfile.get(GLProfile.GL3)
    val glCaps = new GLCapabilities(profile)
    glCaps.setPBuffer(true)
    val pbuffer = GLDrawableFactory.getFactory(profile).createGLPbuffer(glCaps,
                                                                    new DefaultGLCapabilitiesChooser(),
                                                                    1, 1, null)

  }
  class PanelGL extends JPanel with GLEventListener with MouseListener with MouseMotionListener {
    setLayout(new BorderLayout())
    setMinimumSize(new Dimension(200,200))
    setPreferredSize(new Dimension(800,600))

    var glCaps = new GLCapabilities(PanelGL.profile)
    val canvas = new GLCanvas(glCaps, new DefaultGLCapabilitiesChooser(), PanelGL.pbuffer.getContext(), null)
    add(BorderLayout.CENTER, canvas)
     
    canvas.addGLEventListener(this)
    canvas.addMouseListener(this)
    canvas.addMouseMotionListener(this)

Offline gouessej
« Reply #9 - Posted 2010-08-16 11:03:41 »

It worked!  You are all beautiful people. 
Thanks for sharing your findings Smiley

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.

Riven (12 views)
2014-07-29 09:09:19

Riven (8 views)
2014-07-29 09:08:52

Dwinin (9 views)
2014-07-29 01:59:34

E.R. Fleming (25 views)
2014-07-28 18:07:13

E.R. Fleming (10 views)
2014-07-28 18:06:25

pw (39 views)
2014-07-23 16:59:36

Riven (39 views)
2014-07-23 12:16:32

Riven (27 views)
2014-07-23 12:07:15

Riven (28 views)
2014-07-23 11:56:16

ctomni231 (59 views)
2014-07-17 21:55:21
HotSpot Options
by dleskov
2014-07-07 18:59:08

Java and Game Development Tutorials
by SwordsMiner
2014-06-13 15:58:24

Java and Game Development Tutorials
by SwordsMiner
2014-06-13 15:47:22

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

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

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

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

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