I'm writing a simple OpenGL application in Java that implements the Monte Carlo method for estimating the value of PI. The method is pretty easy. Simply, you draw a circle inside a unit square and then plot random points over the scene. Now, for each point that is inside the circle you increment the counter for in points. After determining for all the random points wither they are inside the circle or not you divide the number of in points over the total number of points you have plotted all multiplied by 4 to get an estimation of PI. It goes something like this PI = (inPoints / totalPoints) * 4. This is because mathematically the ratio of a circle's area to a square's area is PI/4, so when we multiply it by 4 we get PI.
My problem doesn't lie in the algorithm itself; however, I'm having problems trying to plot the points as they are being generated instead of just plotting everything at once when the program finishes executing. I want to give the application a sense of real-time display where the user would see the points as they are being plotted. I'm a beginner at OpenGL and I'm pretty sure there is a multi-threading feature built into it. Non the less, I tried to manually create my own thread. Each worker thread plots one point at a time. Following is the psudo-code:
/* this part of the code exists in display() method in MyCanvas.java
which extends GLCanvas and implements GLEventListener */
// main loop
for(int i = 0; i < number_of_points; i++){
RandomGenerator random = new RandomGenerator();
float x = random.nextFloat();
float y = random.nextFloat();
Thread pointThread = new Thread(new PointThread(x, y));
}
gl.glFlush();
/* this part of the code exists in run() method in
PointThread.java which implements Runnable */
void run(){
try{
gl.glPushMatrix();
gl.glBegin(GL2.GL_POINTS);
if(pointIsIn)
gl.glColor3f(1.0f, 0.0f, 0.0f); // red point
else
gl.glColor3f(0.0f, 0.0f, 1.0f); // blue point
gl.glVertex3f(x, y, 0.0f); // coordinates
gl.glEnd();
gl.glPopMatrix();
}catch(Exception e){
}
}
I'm not sure if my approach to solving this issue is correct. I hope you guys can help me out. Thanks.
EDIT:
OK! So I have followed what you have suggested Sven, and instead of using AWT components that would restrict multi-threading, I went on and used GLWindow which is a NEWT context component that wouldn't restrict me from doing so; however, I'm still facing the same issue while dispatching threads. The program seems to wait until all points are determined and then draws everything all at once. Please look into my real code below which is one class called "MonteCarlo" the issue is specifically in the display() method. Put in mind that I'm not really plotting the points right now I'm just printing out hello to the standard output just to test the program.
import javax.media.opengl.GL2;
import javax.media.opengl.glu.gl2.GLUgl2;
import javax.media.opengl.GLAutoDrawable;
import javax.media.opengl.GLProfile;
import javax.media.opengl.GLCapabilities;
import javax.media.opengl.GLEventListener;
import com.jogamp.newt.event.WindowAdapter;
import com.jogamp.newt.event.WindowEvent;
import com.jogamp.newt.opengl.GLWindow;
import com.jogamp.opengl.util.FPSAnimator;
import java.util.Random;
public class MonteCarlo implements GLEventListener{
private static final String TITLE = "Monte Carlo Method";
private static final int WINDOW_WIDTH = 400;
private static final int WINDOW_HEIGHT = 400;
private static final int FPS = 60;
private static final float RADIUS = 0.5f;
public MonteCarlo(){
}
@Override
public void init(GLAutoDrawable drawable){
GL2 gl = drawable.getGL().getGL2();
gl.glClearColor(1.0f, 1.0f, 1.0f, 0.0f);
gl.glClearDepth(1.0f);
}
@Override
public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height){
GL2 gl = drawable.getGL().getGL2();
GLUgl2 glu = new GLUgl2();
gl.glViewport(0, 0, width, height);
gl.glMatrixMode(GL2.GL_PROJECTION);
gl.glLoadIdentity();
glu.gluPerspective(53.14f, 1.0f, 1.0f, 100.0f);
gl.glMatrixMode(GL2.GL_MODELVIEW);
}
@Override
public void display(GLAutoDrawable drawable){
GL2 gl = drawable.getGL().getGL2();
GLUgl2 glu = new GLUgl2();
gl.glClear(GL2.GL_COLOR_BUFFER_BIT | GL2.GL_DEPTH_BUFFER_BIT);
gl.glLoadIdentity();
glu.gluLookAt(0.5f, 0.5f, 1.0f, 0.5f, 0.5f, -1.0f, 0.0f, 1.0f, 0.0f);
gl.glPushMatrix();
gl.glBegin(GL2.GL_LINES);
gl.glColor3f(0.0f, 0.0f, 0.0f);
gl.glVertex3f(0.0f, 0.5f, 0.0f);
gl.glVertex3f(1.0f, 0.5f, 0.0f);
gl.glVertex3f(0.5f, 0.0f, 0.0f);
gl.glVertex3f(0.5f, 1.0f, 0.0f);
gl.glEnd();
gl.glPopMatrix();
int in = 0;
int total = 1000000;
Random floatRandomGenerator = new Random();
for(int i = 0; i < total; i++){
float x = floatRandomGenerator.nextFloat();
float y = floatRandomGenerator.nextFloat();
if((Math.pow(x - 0.5, 2) + Math.pow(y - 0.5, 2)) <= Math.pow(RADIUS, 2)){
in++;
new Thread(){
@Override
public void run(){
System.out.println("hello");
}
}.start();
}
}
gl.glPushMatrix();
gl.glPointSize(10.0f);
gl.glBegin(GL2.GL_POINTS);
gl.glColor3f(1.0f, 0.0f, 0.0f);
gl.glVertex3f(0.5f, 0.5f, 0.0f);
gl.glVertex3f(0.75f, 0.5f, 0.0f);
gl.glVertex3f(1.0f, 0.5f, 0.0f);
gl.glEnd();
gl.glPopMatrix();
gl.glFlush();
}
@Override
public void dispose(GLAutoDrawable drawable){
}
public static void main(String[] args){
GLProfile glProfile = GLProfile.getDefault();
GLCapabilities glCapabilities = new GLCapabilities(glProfile);
GLWindow glWindow = GLWindow.create(glCapabilities);
final FPSAnimator fpsAnimator = new FPSAnimator(glWindow, FPS, true);
glWindow.addWindowListener(new WindowAdapter(){
@Override
public void windowDestroyNotify(WindowEvent e){
new Thread(){
@Override
public void run(){
fpsAnimator.stop();
System.exit(0);
}
}.start();
};
});
glWindow.addGLEventListener(new MonteCarlo());
glWindow.setTitle(TITLE);
glWindow.setSize(WINDOW_WIDTH, WINDOW_HEIGHT);
glWindow.setVisible(true);
fpsAnimator.start();
}
}
Thank you :)