ccFactory        

the component class Factory

       
Introducing the x3dSnap Compiler for

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);
 
 
       

mailto:info@ccfactory.com

Productivity through component-oriented software development