core/vgui/vrml/vgui_vrml_draw_visitor.cxx
Go to the documentation of this file.
00001 // This is core/vgui/vrml/vgui_vrml_draw_visitor.cxx
00002 #ifdef VCL_NEEDS_PRAGMA_INTERFACE
00003 #pragma implementation
00004 #endif
00005 //:
00006 // \file
00007 // \author Andrew W. Fitzgibbon, Oxford RRG
00008 // \date   9 Jan 1999
00009 //-----------------------------------------------------------------------------
00010 
00011 #include "vgui_vrml_draw_visitor.h"
00012 
00013 #include <vcl_functional.h>
00014 #include <vcl_string.h>
00015 
00016 #include <vgui/vgui_gl.h>
00017 #include <vgui/vgui_glu.h>
00018 
00019 #include <vcl_iostream.h>
00020 #include <vcl_vector.h>
00021 #include <vcl_map.h>
00022 
00023 #include <vnl/vnl_float_3.h>
00024 #include <vnl/vnl_cross.h>
00025 #include <vnl/vnl_math.h>
00026 
00027 #include <Qv/QvString.h>
00028 #include <Qv/QvInput.h>
00029 #include <Qv/QvState.h>
00030 #include <Qv/QvNode.h>
00031 
00032 #include <Qv/QvGroup.h>
00033 #include <Qv/QvCoordinate3.h>
00034 #include <Qv/QvIndexedLineSet.h>
00035 #include <Qv/QvIndexedFaceSet.h>
00036 #include <Qv/QvPointSet.h>
00037 #include <Qv/QvSphere.h>
00038 #include <Qv/QvCone.h>
00039 #include <Qv/QvCylinder.h>
00040 #include <Qv/QvCube.h>
00041 
00042 #include <Qv/QvTransform.h>
00043 #include <Qv/QvTranslation.h>
00044 #include <Qv/QvRotation.h>
00045 #include <Qv/QvScale.h>
00046 
00047 #include <Qv/QvMaterial.h>
00048 #include <Qv/QvTexture2.h>
00049 
00050 #include "vgui_vrml_texture_map.h"
00051 
00052 
00053 static inline void GlVertex(const point3D& p)
00054 {
00055   glVertex3f(p.x, p.y, p.z);
00056 }
00057 
00058 
00059 // FIXME : see Templates/map+string.vgui_vrml_texture_map~-.C for explanation.
00060 #if 0
00061 typedef vcl_map<vcl_string, vgui_vrml_texture_map*, vcl_less<vcl_string> > vgui_vrml_texture_mapMap;
00062 static vgui_vrml_texture_map* current_texmap = 0;
00063 static vgui_vrml_texture_mapMap texturemaps; // Images
00064 
00065 static vgui_vrml_texture_map* gettexture(char const* filename)
00066 {
00067   vgui_vrml_texture_mapMap::iterator p = texturemaps.find(filename);
00068   if (p != texturemaps.end())
00069     return (*p).second;
00070 
00071   vgui_vrml_texture_map* newmap = vgui_vrml_texture_map::create(filename);
00072 
00073   return texturemaps[filename] = newmap;
00074 }
00075 #else // 0
00076 
00077 static vgui_vrml_texture_map *current_texmap = 0;
00078 static vgui_vrml_texture_map* gettexture(char const* filename)
00079 {
00080   static vcl_vector<vcl_string> names;
00081   static vcl_vector<vgui_vrml_texture_map*> tmaps;
00082 
00083   unsigned N=names.size();
00084   for (unsigned i=0; i<N; ++i)
00085     if (names[i] == vcl_string(filename))
00086       return tmaps[i];
00087 
00088   vgui_vrml_texture_map *newmap = vgui_vrml_texture_map::create(filename);
00089   names.push_back(filename);
00090   tmaps.push_back(newmap);
00091 
00092   return newmap;
00093 }
00094 #endif // 0
00095 
00096 
00097 vgui_vrml_draw_visitor::vgui_vrml_draw_visitor()
00098 {
00099   gl_mode = textured;
00100   quadric = gluNewQuadric();
00101   twosided = true;
00102   remake_texture = true;
00103 }
00104 
00105 vgui_vrml_draw_visitor::~vgui_vrml_draw_visitor()
00106 {
00107   gluDeleteQuadric(quadric);
00108 }
00109 
00110 // GROUPS
00111 
00112 bool vgui_vrml_draw_visitor::Visit(QvSeparator* node)
00113 {
00114   // Mask Bit                 Attribute Group
00115   // GL_ACCUM_BUFFER_BIT      accum-buffer
00116   // GL_ALL_ATTRIB_BITS       ---
00117   // GL_COLOR_BUFFER_BIT      color-buffer
00118   // GL_CURRENT_BIT           current
00119   // GL_DEPTH_BUFFER_BIT      depth-buffer
00120   // GL_ENABLE_BIT            enable
00121   // GL_EVAL_BIT              eval
00122   // GL_FOG_BIT               fog
00123   // GL_HINT_BIT              hint
00124   // GL_LIGHTING_BIT          lighting
00125   // GL_LINE_BIT              line
00126   // GL_LIST_BIT              list
00127   // GL_PIXEL_MODE_BIT        pixel
00128   // GL_POINT_BIT             point
00129   // GL_POLYGON_BIT           polygon
00130   // GL_POLYGON_STIPPLE_BIT   polygon-stipple
00131   // GL_SCISSOR_BIT           scissor
00132   // GL_STENCIL_BUFFER_BIT    stencil-buffer
00133   // GL_TEXTURE_BIT           texture
00134   // GL_TRANSFORM_BIT         transform
00135   // GL_VIEWPORT_BIT          viewport
00136   glPushAttrib(GL_CURRENT_BIT | GL_LIGHTING_BIT | GL_TEXTURE_BIT);
00137   glPushMatrix();
00138   QvVisitor::Visit(node);
00139   glPopMatrix();
00140   glPopAttrib();
00141   return true;
00142 }
00143 
00144 bool vgui_vrml_draw_visitor::Visit(QvTransformSeparator* node)
00145 {
00146   glPushMatrix();
00147   QvVisitor::Visit(node);
00148   glPopMatrix();
00149   return true;
00150 }
00151 
00152 #define QUADRIC_COMPLEXITY 24
00153 
00154 bool vgui_vrml_draw_visitor::Visit(QvShapeHints* /*node*/)
00155 {
00156   return gl_mode != wireframe;
00157 }
00158 
00159 
00160 // GEOMETRY
00161 bool vgui_vrml_draw_visitor::Visit(QvCube* node)
00162 {
00163   // cube has width height depth
00164 
00165   static GLfloat normals[6][3] = {
00166     {-1.0, 0.0, 0.0},
00167     {0.0, 1.0, 0.0},
00168     {1.0, 0.0, 0.0},
00169     {0.0, -1.0, 0.0},
00170     {0.0, 0.0, 1.0},
00171     {0.0, 0.0, -1.0}
00172   };
00173   static GLint faces[6][4] = {
00174     {0, 1, 2, 3},
00175     {3, 2, 6, 7},
00176     {7, 6, 5, 4},
00177     {4, 5, 1, 0},
00178     {5, 6, 2, 1},
00179     {7, 4, 0, 3}
00180   };
00181 
00182   GLfloat vertices[8][3];
00183   GLint i;
00184   float width = node->width.value;
00185   float height = node->height.value;
00186   float depth = node->depth.value;
00187 
00188   vertices[0][0] = vertices[1][0] = vertices[2][0] = vertices[3][0] = -width/2;
00189   vertices[4][0] = vertices[5][0] = vertices[6][0] = vertices[7][0] = width/2;
00190   vertices[0][1] = vertices[1][1] = vertices[4][1] = vertices[5][1] = -height/2;
00191   vertices[2][1] = vertices[3][1] = vertices[6][1] = vertices[7][1] = height/2;
00192   vertices[0][2] = vertices[3][2] = vertices[4][2] = vertices[7][2] = -depth/2;
00193   vertices[1][2] = vertices[2][2] = vertices[5][2] = vertices[6][2] = depth/2;
00194 
00195   for (i = 5; i >= 0; i--) {
00196     if (gl_mode != wireframe)
00197       glBegin(GL_QUADS);
00198     else
00199       glBegin(GL_LINE_LOOP);
00200     glNormal3fv(&normals[i][0]);
00201     glVertex3fv(&vertices[faces[i][0]][0]);
00202     glVertex3fv(&vertices[faces[i][1]][0]);
00203     glVertex3fv(&vertices[faces[i][2]][0]);
00204     glVertex3fv(&vertices[faces[i][3]][0]);
00205     glEnd();
00206   }
00207   return true;
00208 }
00209 
00210 
00211 bool vgui_vrml_draw_visitor::Visit(QvSphere* node)
00212 {
00213   float r = node->radius.value;
00214 
00215   // gluQuadricDrawStyle GLU_LINE GLU_FILL GLU_POINT GLU_SILHOUETTE
00216   if (gl_mode == wireframe)
00217     gluQuadricDrawStyle(quadric, GLenum(GLU_LINE));
00218   else
00219     gluQuadricDrawStyle(quadric, GLenum(GLU_FILL));
00220 
00221   gluSphere(quadric, r, QUADRIC_COMPLEXITY, QUADRIC_COMPLEXITY);
00222   return true;
00223 }
00224 
00225 bool vgui_vrml_draw_visitor::Visit(QvCylinder* node)
00226 {
00227   float r = node->radius.value;
00228   float h = node->height.value;
00229   bool parts = (int)node->parts.value != 0;
00230 
00231   glRotated(-90, 1, 0, 0);
00232 
00233   glTranslatef(0,0,-h/2);
00234 
00235   if (gl_mode == wireframe)
00236     gluQuadricDrawStyle(quadric, GLenum(GLU_LINE));
00237   else
00238     gluQuadricDrawStyle(quadric, GLenum(GLU_FILL));
00239 
00240 
00241   // fsm : GLU_OUTSIDE/GLU_INSIDE are not GLenums. cast avoids warning (egcs).
00242   gluQuadricOrientation(quadric, GLenum(GLU_OUTSIDE) );
00243   if (parts && (QvCylinder::SIDES | QvCylinder::ALL)!=0)
00244     gluCylinder(quadric, r,r, h, QUADRIC_COMPLEXITY, 2);
00245 
00246   if (parts && (QvCylinder::BOTTOM | QvCylinder::ALL)!=0) {
00247     gluQuadricOrientation(quadric, GLenum(GLU_INSIDE) );
00248     gluDisk(quadric, 0, r, QUADRIC_COMPLEXITY, 3);
00249     gluQuadricOrientation(quadric, GLenum(GLU_OUTSIDE) );
00250   }
00251 
00252   glTranslatef(0,0,h);
00253 
00254   if (parts && (QvCylinder::TOP | QvCylinder::ALL)!=0)
00255     gluDisk(quadric, 0, r, QUADRIC_COMPLEXITY, 3); // z = h
00256 
00257   glTranslatef(0,0,-h/2);
00258 
00259   glRotated(90, 1, 0, 0);
00260   return true;
00261 }
00262 
00263 bool vgui_vrml_draw_visitor::Visit(QvCone* node)
00264 {
00265   float r = node->bottomRadius.value;
00266   float h = node->height.value;
00267   bool parts = (int)node->parts.value != 0;
00268   float tz = h/2;
00269 
00270   glRotated(90, 1, 0, 0);
00271   glTranslatef(0,0, -tz);
00272 
00273   if (gl_mode == wireframe)
00274     gluQuadricDrawStyle(quadric, GLenum(GLU_LINE));
00275   else
00276     gluQuadricDrawStyle(quadric, GLenum(GLU_FILL));
00277 
00278   if (parts && (QvCone::SIDES | QvCone::ALL)!=0)
00279     gluCylinder(quadric, 0, r, h, QUADRIC_COMPLEXITY, 2);
00280 
00281   glTranslatef(0,0, 2 * tz);
00282 
00283   if (parts && (QvCone::BOTTOM | QvCone::ALL)!=0)
00284     gluDisk(quadric, 0, r, QUADRIC_COMPLEXITY, 3);
00285 
00286   glTranslatef(0,0, -tz);
00287   glRotated(-90, 1, 0, 0);
00288   return true;
00289 }
00290 
00291 bool vgui_vrml_draw_visitor::Visit(QvPointSet* ps)
00292 {
00293   glPushAttrib(GL_CURRENT_BIT);
00294   glDisable(GL_TEXTURE_2D);
00295   glBegin(GL_POINTS);
00296 
00297   int n = (ps->numPoints.value == -1) ? ps->num_ : ps->numPoints.value;
00298   n += ps->startIndex.value;
00299   for (int i = ps->startIndex.value; i < n; ++i)
00300     GlVertex(ps->points_[i]);
00301   glEnd();
00302   glPopAttrib();
00303 
00304   return true;
00305 }
00306 
00307 bool vgui_vrml_draw_visitor::Visit(QvIndexedLineSet* node)
00308 {
00309   glPushAttrib(GL_CURRENT_BIT);
00310   glDisable(GL_TEXTURE_2D);
00311 
00312   const point3D* vertexlist = node->vertexlist_;   // vertex data
00313   int numvertinds = node->numvertinds_;            // no. of vertex indices
00314   const int* vertindices = node->vertindices_;     // vertex index list
00315 
00316   glBegin(GL_LINES);
00317   for (int j = 0; j < numvertinds-1; ++j) {
00318     int i1 = vertindices[j];
00319     int i2 = vertindices[j+1];
00320 
00321     if (i1 != -1 && i2 != -1) {
00322       GlVertex(vertexlist[i1]);
00323       GlVertex(vertexlist[i2]);
00324     }
00325   }
00326   glEnd();
00327   glPopAttrib();
00328   return true;
00329 }
00330 
00331 bool vgui_vrml_draw_visitor::Visit(QvIndexedFaceSet* node)
00332 {
00333   // members of QvIndexedFaceSet
00334   //const point3D* vertexlist_;         // vertex data
00335   //int numvertinds_;                   // no. of vertex indices
00336   //const int* vertindices_;            // vertex index list
00337   // Fields:
00338   //     QvMFLong               coordIndex;             // Coordinate indices
00339   //     QvMFLong               materialIndex;          // Material indices
00340   //     QvMFLong               normalIndex;            // Surface normal indices
00341   //     QvMFLong               textureCoordIndex;      // Texture Coordinate indices
00342 
00343   const point3D* vertexlist = node->vertexlist_;   // vertex data
00344   int numvertinds = node->numvertinds_;            // no. of vertex indices
00345   const int* vertindices = node->vertindices_;     // vertex index list
00346 
00347   const point2D* texvertlist = node->texvertlist_;        // texture vertices
00348   int numtextureinds = node->numtextureinds_;                // no. of texture indices
00349   const int* textureindices = node->textureindices_;         // texture index list
00350 
00351   vcl_vector<point3D const*> polyverts;
00352   vcl_vector<point2D const*> polytexcoords;
00353   //int i = 0;
00354   for (int i = 0; i < numvertinds; ++i)
00355   {
00356     // Collect verts
00357     polyverts.clear();
00358     polytexcoords.clear();
00359     while (i < numvertinds && vertindices[i] != -1) {
00360       polyverts.push_back(&vertexlist[vertindices[i]]);
00361       if (i < numtextureinds && gl_mode == textured)
00362         polytexcoords.push_back(&texvertlist[textureindices[i]]);
00363       ++i;
00364     }
00365     unsigned n = polyverts.size();
00366     if (n < 3) {
00367       vcl_cerr << "Bad poly, n = " << n << '\n';
00368       continue;
00369     }
00370 
00371     // Begin poly or wireframe
00372     vnl_float_3 normal;
00373     if (gl_mode == wireframe) {
00374       glBegin(GL_LINE_LOOP);
00375     }
00376     else {
00377       // Compute normal if shaded
00378       vnl_float_3 a(polyverts[0]->x, polyverts[0]->y, polyverts[0]->z);
00379       vnl_float_3 b(polyverts[1]->x, polyverts[1]->y, polyverts[1]->z);
00380       vnl_float_3 c(polyverts[2]->x, polyverts[2]->y, polyverts[2]->z);
00381       normal = vnl_cross_3d(b - a, c - b);
00382       normal *= -1.0f / normal.magnitude();
00383 
00384       glBegin(GL_POLYGON);
00385 
00386       glNormal3f(normal[0], normal[1], normal[2]);
00387     }
00388 
00389     for (unsigned v = 0; v < n; ++v) {
00390       if (gl_mode == textured && v < polytexcoords.size())
00391         glTexCoord2f(polytexcoords[v]->x, polytexcoords[v]->y);
00392 
00393       GlVertex(*polyverts[v]);
00394     }
00395     glEnd();
00396 
00397     // If twosided, do reverse also
00398     if (twosided && gl_mode != wireframe) {
00399       glBegin(GL_POLYGON);
00400       glNormal3f(-normal[0], -normal[1], -normal[2]);
00401       for (unsigned v = n; v > 0;) {
00402         --v;
00403         if (v < polytexcoords.size())
00404           glTexCoord2f(polytexcoords[v]->x, polytexcoords[v]->y);
00405         GlVertex(*polyverts[v]);
00406       }
00407       glEnd();
00408     }
00409   }
00410   return true;
00411 }
00412 
00413 bool vgui_vrml_draw_visitor::Visit(QvAsciiText* /*node*/)
00414 {
00415   return true;
00416 }
00417 
00418 static void GlRotate(double angle_rad, const float* axis)
00419 {
00420   static const float RAD2DEG = float(vnl_math::deg_per_rad);
00421   glRotatef(static_cast<float>(angle_rad) * RAD2DEG, axis[0], axis[1], axis[2]);
00422 }
00423 
00424 static void GlRotate(const QvSFRotation& r)
00425 {
00426   GlRotate(r.angle, r.axis);
00427 }
00428 
00429 // TRANSFORMS
00430 bool vgui_vrml_draw_visitor::Visit(QvTransform* node)
00431 {
00432   const vector3D* tran1 = (const vector3D*) node->translation.value;
00433   const vector3D* tran2 = (const vector3D*) node->center.value;
00434   const float* scale = node->scaleFactor.value;
00435 
00436   glTranslatef (tran1->x + tran2->x, tran1->y + tran2->y, tran1->z + tran2->z);
00437   GlRotate(node->rotation);
00438 
00439   // just rotates the scaling vector
00440   GlRotate(node->scaleOrientation.angle, node->scaleOrientation.axis);
00441   glScalef (scale[0], scale[1], scale[2]);
00442 
00443   // just rotates the scaling vector
00444   GlRotate(-node->scaleOrientation.angle, node->scaleOrientation.axis);
00445   glTranslatef (-tran2->x, -tran2->y, -tran2->z);  // - tran2
00446   return true;
00447 }
00448 
00449 bool vgui_vrml_draw_visitor::Visit(QvScale* node)
00450 {
00451   const float* scale = node->scaleFactor.value;
00452   if (!scale[0] || !scale[1] || !scale[2])
00453     vcl_cerr << "Scale: scaling factors must all be non-zero\n";
00454   glScalef (scale[0], scale[1], scale[2]);
00455   return true;
00456 }
00457 
00458 bool vgui_vrml_draw_visitor::Visit(QvRotation* node)
00459 {
00460   GlRotate(node->rotation);
00461   return true;
00462 }
00463 
00464 bool vgui_vrml_draw_visitor::Visit(QvTranslation* node)
00465 {
00466   float* t = node->translation.value;
00467   glTranslatef(t[0], t[1], t[2]);
00468   return true;
00469 }
00470 
00471 // APPEARANCE
00472 
00473 bool vgui_vrml_draw_visitor::Visit(QvMaterial* node)
00474 {
00475   //// Fields
00476   //QvMFColor           ambientColor;   // Ambient color
00477   //QvMFColor           diffuseColor;   // Diffuse color
00478   //QvMFColor           specularColor;  // Specular color
00479   //QvMFColor           emissiveColor;  // Emissive color
00480   //QvMFFloat           shininess;      // Shininess
00481   //QvMFFloat           transparency;   // Transparency
00482 
00483   glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, node->ambientColor.values);
00484   glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, node->diffuseColor.values);
00485   glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, node->specularColor.values);
00486   glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, node->emissiveColor.values);
00487   glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, node->shininess.values[0]);
00488   float* c = node->emissiveColor.values;
00489 #ifdef DEBUG
00490   vcl_cerr << "rgba " << c[0] <<' '<< c[1] <<' '<< c[2] <<' '<< node->transparency.values[0] << '\n';
00491 #endif
00492   glColor4f(c[0], c[1], c[2], node->transparency.values[0]);
00493   return true;
00494 }
00495 
00496 bool vgui_vrml_draw_visitor::Visit(QvTexture2* node)
00497 {
00498   //    enum Wrap {                     // Texture wrap type
00499   //      REPEAT,                       // Repeats texture outside 0-1
00500   //                                    //  texture coordinate range
00501   //      CLAMP                         // Clamps texture coordinates
00502   //                                    //  to lie within 0-1 range
00503   //    };
00504   //
00505   //    // Fields.
00506   //    QvSFString              filename;       // file to read texture from
00507   //    QvSFImage               image;          // The texture
00508   //    QvSFEnum                wrapS;
00509   //    QvSFEnum                wrapT;
00510   //
00511   //    virtual QvBool  readInstance(QvInput *in);
00512   //    QvBool          readImage();
00513   //
00514   //    void setHandle (int handle, int alpha);  // mpichler, 1996-05-06
00515   //
00516   if (gl_mode == textured) {
00517     char const* filename = node->filename.value.getString();
00518 
00519     vgui_vrml_texture_map* tm = gettexture(filename);
00520     if (tm == current_texmap && !remake_texture) {
00521       return true;
00522     }
00523     current_texmap = tm;
00524     if (tm) {
00525       glEnable(GL_TEXTURE_2D);
00526       glTexImage2D(GL_TEXTURE_2D, 0, 3,
00527                    tm->rgb.width(), tm->rgb.height(),
00528                    0,
00529                    GL_RGB, GL_UNSIGNED_BYTE, tm->rgb.get_buffer());
00530       remake_texture = false;
00531     }
00532     else {
00533       glDisable(GL_TEXTURE_2D);
00534     }
00535   }
00536   return true;
00537 }