translate high level VRML97/X3D models into ANSI C source code for fast performing, lightweight, "library
free" OpenGL applications.
The x3dSnap Compiler offers a fast, lightweight
solution to quickly integrating 3D content into you applications,
without the added overhead of using a large 3D scene graph library. Here are a few of
the benefits at a glance:
-
High-level language productivity.
Jump-Start your graphics development by utilizing VRML/X3D's
high-level modeling semantics to easily build complex 3D worlds.
The compiler translates the defined geometry into its equivalent
implementation in ANSI C/OpenGL automatically.
-
"Runtime free" execution. ANSI C source code
compiles into independently executing OpenGL code and does not require any runtime
libraries or plug-in software on the host platform.
All geometry and texture information is collapsed into GL/GLU API
calls and static data declarations, respectively. The
x3dSnap compiler optionally produces a GLUT main routine and basic
user-input callbacks to enable a "quick view" of the
model once it's compiled.
-
Faster performance, smaller memory footprint.The
target ANSI C source is comparable to inline expanded code: loops are
unrolled, redundant calls are filtered, vertex data are consolidated
and interleaved to provide maximum performance on most
hardware architectures. The generated code also forgoes any
direct heap
allocations, reducing its memory requirements to its own code and data
segments (plus any allocations necessary for the GL/GLU library).
-
Preprocessing enables quicker loading & execution.
Texture and vertex data is preprocessed by the compiler,
dramatically reducing application load time and increasing rendering
performance. Texture URLs are decoded, and compiled into OpenGL's
internal format for immediate loading. Vertex, normal and
color data are sorted and consolidated into one global array for faster lookup
and reduced data segment sizes.
-
WYSIAYG 'What you see is all you get'.
The compiler translates VRML nodes as they are encountered in the
scene graph. Every line of code generated is used, and reused
during rendering. There is no danger of your application being
forced to link with unused code, which is often difficult to avoid
when linking with a C++ library. This can be crucial for
platforms hosting applications requiring extremely small memory
footprints.
Sample Compile
The goal of the x3dSnap project is to combine the productivity
of VRML/X3D's high-level modeling semantics with the efficiency and
control of the C/C++ programming language to reduce development efforts,
without sacrificing rendering performance or image quality.
Let's look at an example to illustrate this. The ISO VRML97 Standard defines 52 built-in nodes or
command objects, ten of which (Box, Cone, Cylinder, ElevationGrid, Extrusion,
IndexedFaceSet, IndexedLineSet, PointSet, Sphere & Text) describe
high-level geometry. In addition, VRML provides a flexible
prototyping mechanism to define new aggregate types from given 52 built-in
types. To keep the first example simple, consider the following
short VRML97 world definition, which defines a blue sphere hovering over a yellow platform.
|
|
|
|
#VRML V2.0 utf8
DEF platform Transform {
children [ Shape {
appearance Appearance { material Material { diffuseColor 1 1
0.5 } }
geometry Box { size 3 0.2 3 }
} ]
}
DEF blue_sphere Transform {
children [ Shape {
appearance Appearance { material Material { diffuseColor
0.5 0.5 1 } }
geometry Sphere { }
} ]
translation 0 3 0
}
|
|
|
figure 1.0 - Sample
VRML Definition (Source) |
|
|
|
|
|
|
|
|
figure 1.1 - OpenGL
rendering of VRML source |
|
The x3dSnap Compiler translates the above model into the
following OpenGL API invocations in ANSI C:
|
/*
* draw_model
*/
void draw_model(void)
{
/* Transform */
glPushMatrix();
/* Shape */
/* Appearance */
/* Material */
glMaterialfv(GL_FRONT_AND_BACK,
GL_AMBIENT, v4f_table[3]);     /*
<0.2, 0.2, 0.1, 1> */
glMaterialfv(GL_FRONT_AND_BACK,
GL_DIFFUSE, v4f_table[4]);     /*
<1, 1, 0.5, 1> */
glMaterialf(GL_FRONT_AND_BACK,
GL_SHININESS, 25.600000);
glMaterialfv(GL_FRONT_AND_BACK,
GL_SPECULAR, v4f_table[0]);     /*
<0, 0, 0, 1> */
glMaterialfv(GL_FRONT_AND_BACK,
GL_EMISSION, v4f_table[0]);     /*
<0, 0, 0, 1> */
glColor4fv(v4f_table[4]);     /*
<1, 1, 0.5, 1> */
glEnable(GL_LIGHTING);
/* Box */
glEnable(GL_CULL_FACE);
glPushClientAttrib(GL_CLIENT_VERTEX_ARRAY_BIT);
glInterleavedArrays(GL_N3F_V3F, 0, v6f_table);
glDrawElements(GL_QUADS, 24,
GL_UNSIGNED_BYTE, indices_table);
glPopClientAttrib();
glDisable(GL_CULL_FACE);
glDisable(GL_LIGHTING);
glPopMatrix();
/* Transform */
glPushMatrix();
glTranslatef(0, 3, 0);
/* Shape */
/* Appearance */
/* Material */
glMaterialfv(GL_FRONT_AND_BACK,
GL_AMBIENT, v4f_table[5]);     /*
<0.1, 0.1, 0.2, 1> */
glMaterialfv(GL_FRONT_AND_BACK,
GL_DIFFUSE, v4f_table[6]);     /*
<0.5, 0.5, 1, 1> */
glMaterialf(GL_FRONT_AND_BACK,
GL_SHININESS, 25.600000);
glMaterialfv(GL_FRONT_AND_BACK,
GL_SPECULAR, v4f_table[0]);     /*
<0, 0, 0, 1> */
glMaterialfv(GL_FRONT_AND_BACK,
GL_EMISSION, v4f_table[0]);     /*
<0, 0, 0, 1> */
glColor4fv(v4f_table[6]);     /*
<0.5, 0.5, 1, 1> */
glEnable(GL_LIGHTING);
/* Sphere */
gluQuadricTexture(qobj,
GL_FALSE);
gluQuadricNormals(qobj,
GL_SMOOTH);
glPushMatrix();
glRotatef(-90, 1, 0, 0);
glEnable(GL_CULL_FACE);
gluSphere(qobj, 1, 20, 20);
glDisable(GL_CULL_FACE);
glPopMatrix();
glDisable(GL_LIGHTING);
glPopMatrix();
glDisable(GL_LIGHT0);
glFlush();
}
/*
* Globals
*/
GLUquadricObj * qobj = 0;
GLfloat v3f_table[][3] = {
{1, 1, 1}, {-1.5, -2.05, -1.5}, {-1.5, -2.05, 1.5}, {-1.5, 2.05, 1.5}, {-1.5, 2.05,
-1.5}, {1.5, -2.05, 1.5}, {1.5, 2.05, 1.5}, {1.5, -2.05, -1.5}, {1.5, 2.05, -1.5}
};
GLfloat v4f_table[][4] = {
{0, 0, 0, 1}, {1, 1, 1, 1}, {0, 0, 1, 0}, {0.2, 0.2, 0.1, 1}, {1, 1, 0.5, 1}, {0.1,
0.1, 0.2, 1}, {0.5, 0.5, 1, 1}
};
GLfloat v6f_table[][6] = {
{-1, 0, 0, -1.5, -0.1, -1.5}, {-1, 0, 0, -1.5, -0.1, 1.5}, {-1, 0, 0, -1.5, 0.1,
1.5}, {-1, 0, 0, -1.5, 0.1, -1.5}, {0, 0, 1, -1.5, -0.1, 1.5}, {0, 0, 1, 1.5, -0.1,
1.5}, {0, 0, 1, 1.5, 0.1, 1.5}, {0, 0, 1, -1.5, 0.1, 1.5}, {1, 0, 0, 1.5, -0.1,
1.5}, {1, 0, 0, 1.5, -0.1, -1.5}, {1, 0, 0, 1.5, 0.1, -1.5}, {1, 0, 0, 1.5, 0.1,
1.5}, {0, 0, -1, 1.5, -0.1, -1.5}, {0, 0, -1, -1.5, -0.1, -1.5}, {0, 0, -1, -1.5,
0.1, -1.5}, {0, 0, -1, 1.5, 0.1, -1.5}, {0, 1, 0, -1.5, 0.1, 1.5}, {0, 1, 0, 1.5,
0.1, 1.5}, {0, 1, 0, 1.5, 0.1, -1.5}, {0, 1, 0, -1.5, 0.1, -1.5}, {0, -1, 0, -1.5,
-0.1, -1.5}, {0, -1, 0, 1.5, -0.1, -1.5}, {0, -1, 0, 1.5, -0.1, 1.5}, {0, -1, 0,
-1.5, -0.1, 1.5}
};
GLubyte indices_table[24] = {
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
23
};
GLfloat viewpoints[][16] = {
/* [0] Entry Viewpoint */
{0.715674, 0.696888, -0.0464674, 0,
-0.0157274, 0.0825936, 0.996459, 0,
0.698258, -0.712409, 0.0700703, 0,
-5.3823e-05, 2.5183e-05, -9.99988, 1}
};
|
|
Currently, thex3dSnap Compiler will generate
code for all VRML97 geometry nodes but two (Extrusion and Text will
be added shortly).
Example 2. Adding a Texture
To expand on the above example, let's "wrap" the blue sphere
in a two dimensional texture defined in a JPEG
image. We can use the VRML97 ImageTexture node to accomplish this:
|
DEF blue_sphere Transform {
children [ Shape {
appearance Appearance {
material Material { }
texture ImageTexture { url [
"images/earth.jpg" ] }
}
geometry Sphere { }
} ]
translation 0 3 0
}
| |
compiling the changes results in in the following code (some lines have been omitted):
|
/* Transform "blue_sphere"
*/
glPushMatrix();
glTranslatef(0, 3, 0);
/* Shape */
/* Appearance */
/* Material */
glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, v4f_table[5]);
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, v4f_table[6]);
glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 25.600000);
glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, v4f_table[0]);
glEnable(GL_LIGHTING);
glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, v4f_table[0]);
glColor4fv(v4f_table[6]);
|
|
|
/* ImageTexture */
glBindTexture(GL_TEXTURE_2D, texture2d_names[0]);/* images/earth.jpg */
glTexEnvf(GL_TEXTURE_ENV,
GL_TEXTURE_ENV_MODE, GL_MODULATE);
glEnable(GL_TEXTURE_2D);
|
|
|
/* Sphere */
gluQuadricTexture(qobj,
GL_TRUE);
gluQuadricNormals(qobj,
GL_SMOOTH);
glPushMatrix();
glRotatef(-90, 1, 0, 0);
glEnable(GL_CULL_FACE);
gluSphere(qobj, 1, 20, 20);
glDisable(GL_CULL_FACE);
glPopMatrix();
glDisable(GL_TEXTURE_2D);
glDisable(GL_LIGHTING);
glPopMatrix();
/* * Globals */
GLuint texture2d_names[1];
/* texture source: images/earth.jpg dimensions: 256 x 128 x 3 */
GLubyte
texture2d_images_earth_jpg[] = {
0xCC, 0xCC, 0x69, 0xCC, 0xCC, 0x69, 0xCC, 0xCC, 0x69, 0xCC, 0xCC, 0x69, 0xCC, 0xCC,....};
|
|
The init routine creates and initializes the texture object as follows:
|
/* * init */
glGenTextures(1, texture2d_names);
glBindTexture(GL_TEXTURE_2D, texture2d_names[0]);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 256, 128, 0, GL_RGB, GL_UNSIGNED_BYTE, texture2d_images_earth_jpg);
|
|
|