We closed this forum 18 June 2010. It has served us well since 2005 as the ALPHA forum did before it from 2002 to 2005. New discussions are ongoing at the new URL http://forum.processing.org. You'll need to sign up and get a new user account. We're sorry about that inconvenience, but we think it's better in the long run. The content on this forum will remain online.
Page Index Toggle Pages: 1
Preloading (sort of) (Read 1333 times)
Preloading (sort of)
Apr 8th, 2009, 2:07pm
 
Hi all, I'm writing a 3D pure OpenGL collada viewer that does a bunch of slow initialization routines (like generating texture mipmaps and building / uploading vertex buffer object arrays).

The problem is not 3D-related, so I'm not sure if I'm posting in the right forum section, this is my first post here.

Here is a short simplified sketch to reproduce the problem I'm trying to solve.

Basically after the applet starts, I'd love to be able to draw a looping preloading animation (in the applet window) while the slow generation function is running, just so that the user knows that the app isn't frozen or hasn't crashed.

I've also tried moving the slow routine inside a separate thread, but in order to upload vbo data or generate mipmaps, I need to be able to access the pgl and gl objects, and it seems I can't do that from within the thread. (when trying to upload vbos, it throws this error, which makes sense: no OpenGL buffer object appears to be bound to target 0x8892)

Thanks for your suggestions in advance!
Michele

Code:

import processing.opengl.*;
boolean generated = false;

void setup()
{
 size( 200, 200, OPENGL );
 background( 0 );
}

void draw()
{
 if ( !generated )
 {
   generate_mipmaps();
   generated = true;
 }

 rect( 50, 50, 100, 100 );
}

// some really slow initialization stuff in here
void generate_mipmaps()
{
 for ( int i = 0; i < 300000; i++ )
 {
   PImage img = new PImage( 100, 100 );
 }
}

Re: Preloading (sort of)
Reply #1 - Apr 8th, 2009, 2:34pm
 
What I do is some switch/case syntax in the draw area.  Not sure if this is the best way or not.  (On a side note, please post your VBO code.  -  I'm trying to figure that out myself).

Code:

int loadcount = 0;
int loadfade = 255;

void draw(){
background(0);
switch(loadcount) {
case 0:
   loading animation...
   fill(0,loadfade);
   rect(0,0,width,height);  //fade in the loader
   loadfade = loadfade-5;
   if (loadfade < 1) {
loadcount = loadcount+1;
   }
   break;
case 1:
   delay(500);
   loading animation...
   do more stuff....
   loadcount = loadcount + 1
   break;
case 2:
   delay(500);
   loading animation...
   do more stuff....
   loadcount = loadcount + 1
   break;
case 3:
   put all your normal draw stuff...
   break;
}
Re: Preloading (sort of)
Reply #2 - Apr 8th, 2009, 11:56pm
 
Hi Jeff, thx for the quick answer.

Here's a sample that shows a simple VBO rotating cube.
Mousedrag rotates the cube in the y axis.

There's an initializer class that creates a thread (just started with threads yesterday, so there might be errors) where I want to place the VBO loading (and other slow operations like mipmapping).

If you uncomment line 72 and comment line 84, you'll see the thread starting but crashing (Illegally formatted version identifier: "null") when the first gl call is reached, I guess because the GL context can be accessed only when draw() is fired.

Any ideas?
Thanks a lot,
Michele
Re: Preloading (sort of)
Reply #3 - Apr 8th, 2009, 11:58pm
 
Code:

import processing.opengl.*;
import javax.media.opengl.*;
import javax.media.opengl.glu.*;
import com.sun.opengl.util.*;
import java.util.Vector;
import java.nio.*;

float roty = 0.0;

// GL stuff
GLU glu = new GLU();
PGraphicsOpenGL pgl;
GL gl;

String opengl_version_string = "";
float opengl_version = 0.0;
boolean GL_ARB_vertex_buffer_object_available = false;

// viewer, initializer
ms_viewer viewer;
ms_initializer initializer;

////////////////////////////////////////////////////////////////
// initializer
class ms_initializer extends Thread
{
ms_viewer viewer;
int i = 0;

// constructor
ms_initializer( ms_viewer _viewer )
{
viewer = _viewer;
}

// methods
void start()
{
super.start();
}

void run()
{
viewer.load();
}

void quit()
{
}
}

////////////////////////////////////////////////////////////////
// app constructor
void setup()
{
size( 640, 480, OPENGL );

// enable 2x (default) anti-aliasing if supported
hint( ENABLE_OPENGL_2X_SMOOTH );
// draws all geometry with smooth (anti-aliased) edges
smooth();

// viewer
viewer = new ms_viewer( this );

// black background
background( 000000 );

// load with initializer
initializer = new ms_initializer( viewer );
// UNCOMMENT NEXT LINE
// initializer.start();
}

////////////////////////////////////////////////////////////////
// app update
void draw()
{
if ( !viewer.loaded )
{
// load without initializer
// COMMENT NEXT LINE
viewer.load();

// preload animation
// ...
}
else
{
// ready to go
initializer.quit();
viewer.render();
}
}

////////////////////////////////////////////////////////////////
// app mouse dragged event
void mouseDragged()
{
roty += mouseX - pmouseX;
}

////////////////////////////////////////////////////////////////
// app destructor
void stop()
{
viewer.destructor();
}

////////////////////////////////////////////////////////////////
// viewer
class ms_viewer
{
PApplet parent;
boolean loaded = false;

Vector triangles = new Vector();
Vector positions = new Vector();
Vector normals = new Vector();

int[] elements_vbo = new int[1];
int[] positions_vbo = new int[1];
int[] normals_vbo = new int[1];

// constructor
ms_viewer( PApplet _parent )
{
this.parent = _parent;
}

// destructor
void destructor()
{
if ( GL_ARB_vertex_buffer_object_available )
{
gl.glDeleteBuffers( 1, positions_vbo, 0 );
gl.glDeleteBuffers( 1, normals_vbo, 0 );
gl.glDeleteBuffers( 1, elements_vbo, 0 );
}
}

// loader
void load()
{
// opengl - begin
pgl = (PGraphicsOpenGL) g; // g may change
gl = pgl.beginGL(); // always use the GL object returned by pgl

// setup vbo
GL_ARB_vertex_buffer_object_available = gl.isExtensionAvailable( "GL_ARB_vertex_buffer_object" );

if ( GL_ARB_vertex_buffer_object_available )
{
positions.addElement( new ms_vector3( -1.0f, -1.0f, 1.0f ) );
positions.addElement( new ms_vector3( 1.0f, -1.0f, 1.0f ) );
positions.addElement( new ms_vector3( 1.0f, 1.0f, 1.0f ) );
positions.addElement( new ms_vector3( -1.0f, 1.0f, 1.0f ) );
positions.addElement( new ms_vector3( -1.0f, -1.0f, -1.0f ) );
positions.addElement( new ms_vector3( 1.0f, -1.0f, -1.0f ) );
positions.addElement( new ms_vector3( 1.0f, 1.0f, -1.0f ) );
positions.addElement( new ms_vector3( -1.0f, 1.0f, -1.0f ) );
normals.addElement( new ms_vector3( 0.0, 1.0, 0.0 ) );
normals.addElement( new ms_vector3( 0.0, 1.0, 0.0 ) );
normals.addElement( new ms_vector3( 0.0, 1.0, 0.0 ) );
normals.addElement( new ms_vector3( 0.0, 1.0, 0.0 ) );
normals.addElement( new ms_vector3( 0.0, 1.0, 0.0 ) );
normals.addElement( new ms_vector3( 0.0, 1.0, 0.0 ) );
normals.addElement( new ms_vector3( 0.0, 1.0, 0.0 ) );
normals.addElement( new ms_vector3( 0.0, 1.0, 0.0 ) );
triangles.addElement( new ms_triangle( 0, 5, 1 ) );
triangles.addElement( new ms_triangle( 0, 4, 5 ) );
triangles.addElement( new ms_triangle( 1, 6, 2 ) );
triangles.addElement( new ms_triangle( 1, 5, 6 ) );
triangles.addElement( new ms_triangle( 2, 6, 7 ) );
triangles.addElement( new ms_triangle( 2, 7, 3 ) );
triangles.addElement( new ms_triangle( 0, 3, 7 ) );
triangles.addElement( new ms_triangle( 0, 7, 4 ) );
triangles.addElement( new ms_triangle( 0, 1, 2 ) );
triangles.addElement( new ms_triangle( 0, 2, 3 ) );
triangles.addElement( new ms_triangle( 4, 7, 6 ) );
triangles.addElement( new ms_triangle( 4, 6, 5 ) );

gl.glGenBuffers( 1, positions_vbo, 0 );
gl.glBindBuffer( GL.GL_ARRAY_BUFFER, positions_vbo[0] );
gl.glBufferData( GL.GL_ARRAY_BUFFER, positions.size() * 3 * BufferUtil.SIZEOF_FLOAT, ms_vector3s_to_float_buffer( positions ), GL.GL_STATIC_DRAW );

gl.glGenBuffers( 1, normals_vbo, 0 );
gl.glBindBuffer( GL.GL_ARRAY_BUFFER, normals_vbo[0] );
gl.glBufferData( GL.GL_ARRAY_BUFFER, normals.size() * 3 * BufferUtil.SIZEOF_FLOAT, ms_vector3s_to_float_buffer( normals ), GL.GL_STATIC_DRAW );

gl.glGenBuffers( 1, elements_vbo, 0 );
gl.glBindBuffer( GL.GL_ELEMENT_ARRAY_BUFFER, elements_vbo[0] );
gl.glBufferData( GL.GL_ELEMENT_ARRAY_BUFFER, triangles.size() * 3 * BufferUtil.SIZEOF_INT, ms_triangles_to_int_buffer( triangles ), GL.GL_STATIC_DRAW );
}

// opengl - end
pgl.endGL();

loaded = true;
}
Re: Preloading (sort of)
Reply #4 - Apr 8th, 2009, 11:58pm
 
Code:


// update
void render()
{
// opengl - begin
pgl = (PGraphicsOpenGL) g;
gl = pgl.beginGL();

// viewport
gl.glViewport ( 0, 0, width, height );

gl.glDisable( GL.GL_FOG );

gl.glEnable( GL.GL_DEPTH_TEST );
gl.glDepthFunc( GL.GL_LEQUAL );
gl.glDepthMask( true );

// GL_ZERO, GL_ONE, GL_SRC_COLOR, GL_ONE_MINUS_SRC_COLOR, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_DST_ALPHA, GL_ONE_MINUS_DST_ALPHA
gl.glBlendFunc( GL.GL_SRC_ALPHA, GL.GL_ONE_MINUS_SRC_ALPHA );

gl.glHint( GL.GL_PERSPECTIVE_CORRECTION_HINT, GL.GL_NICEST );

gl.glClearColor( 0.0, 0.0, 0.0, 1.0 );
gl.glClear( GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT );

gl.glMatrixMode( GL.GL_PROJECTION );
gl.glPushMatrix();
gl.glMatrixMode( GL.GL_MODELVIEW );
gl.glPushMatrix();

// camera
gl.glPushAttrib( GL.GL_ALL_ATTRIB_BITS );

gl.glMatrixMode( GL.GL_PROJECTION );
gl.glLoadIdentity();

glu.gluPerspective( 45.0, (float)width / (float)height, 1.0, 1000.0 );

gl.glMatrixMode( GL.GL_MODELVIEW );
gl.glLoadIdentity();

glu.gluLookAt( 0.0, 2.5, 5.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0 );

gl.glPopAttrib();

// translate
gl.glTranslatef( 0.0, 0.0, 0.0 );
// rotate along the y "up" axis
gl.glRotatef( roty, 0.0, 1.0, 0.0 );
// gl.glRotatef( frameCount * 0.5, 1.0, 1.0, 0.0 );

// render hidden line
gl.glDisable( GL.GL_BLEND );
gl.glDisable( GL.GL_LIGHTING );
gl.glShadeModel( GL.GL_FLAT );
gl.glPolygonMode( GL.GL_FRONT_AND_BACK,GL.GL_FILL );
gl.glColor4f( 0.5, 0.5, 0.5, 1.0 );
render_triangles();
gl.glPolygonMode( GL.GL_FRONT_AND_BACK, GL.GL_LINE );
gl.glColor4f( 0.75, 0.75, 0.75, 1.0 );
render_triangles( );

gl.glDisable( GL.GL_DEPTH_TEST );
gl.glMatrixMode( GL.GL_PROJECTION );
gl.glPopMatrix();
gl.glMatrixMode( GL.GL_MODELVIEW );
gl.glPopMatrix();

// opengl - end
pgl.endGL();
}

// render triangles (no failback, VBO only)
void render_triangles()
{
if ( GL_ARB_vertex_buffer_object_available )
{
gl.glEnableClientState( GL.GL_VERTEX_ARRAY );
gl.glBindBuffer( GL.GL_ARRAY_BUFFER, positions_vbo[0] );
gl.glVertexPointer( 3, GL.GL_FLOAT, 0, 0 );

gl.glEnableClientState( GL.GL_NORMAL_ARRAY );
gl.glBindBuffer( GL.GL_ARRAY_BUFFER, normals_vbo[0] );
gl.glNormalPointer( GL.GL_FLOAT, 0, 0 );

gl.glBindBuffer( GL.GL_ELEMENT_ARRAY_BUFFER, elements_vbo[0] );
gl.glDrawElements( GL.GL_TRIANGLES, triangles.size() * 3, GL.GL_UNSIGNED_INT, 0 );

gl.glDisableClientState( GL.GL_VERTEX_ARRAY );
gl.glDisableClientState( GL.GL_NORMAL_ARRAY );
}
}

// buffer converters
FloatBuffer ms_vector3s_to_float_buffer( Vector _vector )
{
FloatBuffer a = BufferUtil.newFloatBuffer( _vector.size() * 3 );
for( int i = 0; i < _vector.size(); i++ )
{
ms_vector3 v = (ms_vector3) _vector.elementAt( i );
a.put( v.x );
a.put( v.y );
a.put( v.z );
}
a.flip();
return a;
}

IntBuffer ms_triangles_to_int_buffer( Vector _vector )
{
IntBuffer a = BufferUtil.newIntBuffer( _vector.size() * 3 );
for( int i = 0; i < _vector.size(); i++ )
{
ms_triangle t = (ms_triangle) _vector.elementAt( i );
a.put( t.p[0] );
a.put( t.p[1] );
a.put( t.p[2] );
}
a.flip();
return a;
}
}

////////////////////////////////////////////////////////////////
// vector3
class ms_vector3
{
float x, y, z;

// constructor
ms_vector3()
{
this.x = 0;
this.y = 0;
this.z = 0;
}

ms_vector3( float _x, float _y, float _z )
{
this.x = _x;
this.y = _y;
this.z = _z;
}
}

////////////////////////////////////////////////////////////////
// triangle
class ms_triangle
{
int[] p = new int[3];

ms_triangle( int _a, int _b, int _c )
{
p[0] = _a;
p[1] = _b;
p[2] = _c;
}
}
Re: Preloading (sort of)
Reply #5 - Apr 9th, 2009, 7:54am
 
Nice!  I'm sure I'll learn a lot from this.  We need to get more pure OpenGL stuff into the hacks (hopefully when it goes wiki).  From what I'm reading, VBO is the way to go for high performance. I'm currently using a display list, which is pretty fast (and much simpler), but wanted to test out the VBO.  I'm loading a very large number of objects so I want to squeeze all the performance I can out of each call.  I'll try to take a look at the thread, but don't expect I'll be able to help on that one.  Post if you get it figured out. Smiley  I'm not sure if I can use multithreading, but it wouldn't hurt to have an example posted to learn from.
Page Index Toggle Pages: 1