geometry.C

Go to the documentation of this file.
00001 /*
00002  * This file is part of the "Archon" framework.
00003  * (http://files3d.sourceforge.net)
00004  *
00005  * Copyright  2002 by Kristian Spangsege and Brian Kristiansen.
00006  *
00007  * Permission to use, copy, modify, and distribute this software and
00008  * its documentation under the terms of the GNU General Public License is
00009  * hereby granted. No representations are made about the suitability of
00010  * this software for any purpose. It is provided "as is" without express
00011  * or implied warranty. See the GNU General Public License
00012  * (http://www.gnu.org/copyleft/gpl.html) for more details.
00013  *
00014  * The characters in this file are ISO8859-1 encoded.
00015  *
00016  * The documentation in this file is in "Doxygen" style
00017  * (http://www.doxygen.org).
00018  */
00019 
00026 #include <GL/gl.h>
00027 
00028 #include <archon/x3d/server/field_type.H>
00029 #include <archon/x3d/server/field.H>
00030 #include <archon/x3d/server/geometry.H>
00031 
00032 namespace Archon
00033 {
00034   namespace X3D
00035   {
00036     const NodeType *GeometryNode::type = 0;
00037     const NodeType *Geometry3DNode::type = 0;
00038 
00039     const NodeType *Box::type = 0;
00040     const NodeType *Cone::type = 0;
00041     const NodeType *Cylinder::type = 0;
00042     const NodeType *IndexedLineSet::type = 0;
00043     const NodeType *PointSet::type = 0;
00044     const NodeType *Sphere::type = 0;
00045 
00046     const NodeType *ComposedGeometryNode::type = 0;
00047     const NodeType *ElevationGrid::type = 0;
00048     const NodeType *IndexedFaceSet::type = 0;
00049 
00050     const NodeType *ShapeNode::type = 0;
00051     const NodeType *Shape::type = 0;
00052 
00053     void initializeGeometryComponent()
00054     {
00055       vector<const FieldBase *> fields;
00056 
00057 
00058       // GeometryNode
00059 
00060       GeometryNode::type =
00061         NodeType::newAbstract("GeometryNode", false, 0,
00062                               Node::type);
00063 
00064 
00065       // Geometry3DNode
00066 
00067       Geometry3DNode::type =
00068         NodeType::newAbstract("Geometry3DNode", false, 0,
00069                               GeometryNode::type);
00070 
00071 
00072       // Box
00073 
00074       fields.push_back(newPrivateField("size", SFVec3f::type,
00075                                        &Box::size));
00076       Box::type =
00077         NodeType::newConcrete("Box", "geometry",
00078                               Box::instantiate, &fields,
00079                               Geometry3DNode::type);
00080       fields.clear();
00081 
00082 
00083       // Cone
00084 
00085       fields.push_back(newPrivateField("bottomRadius", SFFloat::type,
00086                                        &Cone::bottomRadius));
00087       fields.push_back(newPrivateField("height", SFFloat::type,
00088                                        &Cone::height));
00089       fields.push_back(newPrivateField("side", SFBool::type,
00090                                        &Cone::side));
00091       fields.push_back(newPrivateField("bottom", SFBool::type,
00092                                        &Cone::bottom));
00093       Cone::type =
00094         NodeType::newConcrete("Cone", "geometry",
00095                               Cone::instantiate, &fields,
00096                               Geometry3DNode::type);
00097       fields.clear();
00098 
00099 
00100       // Cylinder
00101 
00102       fields.push_back(newPrivateField("bottom", SFBool::type,
00103                                        &Cylinder::bottom));
00104       fields.push_back(newPrivateField("radius", SFFloat::type,
00105                                        &Cylinder::radius));
00106       fields.push_back(newPrivateField("height", SFFloat::type,
00107                                        &Cylinder::height));
00108       fields.push_back(newPrivateField("side", SFBool::type,
00109                                        &Cylinder::side));
00110       fields.push_back(newPrivateField("top", SFBool::type,
00111                                        &Cylinder::top));
00112       Cylinder::type =
00113         NodeType::newConcrete("Cylinder", "geometry",
00114                               Cylinder::instantiate, &fields,
00115                               Geometry3DNode::type);
00116       fields.clear();
00117 
00118 
00119       // IndexedLineSet
00120 
00121       fields.push_back(newExposedField("color",
00122                                        &IndexedLineSet::color,
00123                                        &IndexedLineSet::colorChanged,
00124                                        &IndexedLineSet::colorStamp));
00125       fields.push_back(newExposedField("coord",
00126                                        &IndexedLineSet::coord,
00127                                        &IndexedLineSet::coordChanged,
00128                                        &IndexedLineSet::coordStamp));
00129       fields.push_back(newPrivateField("colorIndex", MFInt32::type,
00130                                        &IndexedLineSet::colorIndex));
00131       fields.push_back(newEventIn("set_colorIndex", MFInt32::type,
00132                                   &IndexedLineSet::colorIndex,
00133                                   &IndexedLineSet::colorIndexStamp));
00134       fields.push_back(newPrivateField("colorPerVertex", SFBool::type,
00135                                        &IndexedLineSet::colorPerVertex));
00136       fields.push_back(newPrivateField("coordIndex", MFInt32::type,
00137                                        &IndexedLineSet::coordIndex));
00138       fields.push_back(newEventIn("set_coordIndex", MFInt32::type,
00139                                   &IndexedLineSet::coordIndex,
00140                                   &IndexedLineSet::coordIndexStamp));
00141       fields.push_back(newPrivateField("lineWidth", SFFloat::type,
00142                                        &IndexedLineSet::lineWidth));
00143       IndexedLineSet::type =
00144         NodeType::newConcrete("IndexedLineSet", "geometry",
00145                               IndexedLineSet::instantiate, &fields,
00146                               Geometry3DNode::type);
00147       fields.clear();
00148 
00149 
00150 
00151       // PointSet
00152 
00153       fields.push_back(newExposedField("color",
00154                                        &PointSet::color,
00155                                        &PointSet::colorChanged,
00156                                        &PointSet::colorStamp));
00157       fields.push_back(newExposedField("coord",
00158                                        &PointSet::coord,
00159                                        &PointSet::coordChanged,
00160                                        &PointSet::coordStamp));
00161       PointSet::type =
00162         NodeType::newConcrete("PointSet", "geometry",
00163                               PointSet::instantiate, &fields,
00164                               Geometry3DNode::type);
00165       fields.clear();
00166 
00167 
00168       // Sphere
00169 
00170       fields.push_back(newPrivateField("radius", SFFloat::type,
00171                                        &Sphere::radius));
00172       Sphere::type =
00173         NodeType::newConcrete("Sphere", "geometry",
00174                               Sphere::instantiate, &fields,
00175                               Geometry3DNode::type);
00176       fields.clear();
00177 
00178 
00179       // ComposedGeometryNode
00180 
00181       fields.push_back(newExposedField("color",
00182                                        &ComposedGeometryNode::color,
00183                                        &ComposedGeometryNode::colorAssign,
00184                                        &ComposedGeometryNode::colorChanged,
00185                                        &ComposedGeometryNode::colorStamp));
00186       fields.push_back(newExposedField("coord",
00187                                        &ComposedGeometryNode::coord,
00188                                        &ComposedGeometryNode::coordAssign,
00189                                        &ComposedGeometryNode::coordChanged,
00190                                        &ComposedGeometryNode::coordStamp));
00191       fields.push_back(newExposedField("normal",
00192                                        &ComposedGeometryNode::normal,
00193                                        &ComposedGeometryNode::normalAssign,
00194                                        &ComposedGeometryNode::normalChanged,
00195                                        &ComposedGeometryNode::normalStamp));
00196       fields.push_back(newExposedField("texCoord",
00197                                        &ComposedGeometryNode::texCoord,
00198                                        &ComposedGeometryNode::texCoordAssign,
00199                                        &ComposedGeometryNode::texCoordChanged,
00200                                        &ComposedGeometryNode::texCoordStamp));
00201       fields.push_back(newPrivateField("ccw", SFBool::type,
00202                                        &ComposedGeometryNode::ccw));
00203       fields.push_back(newPrivateField("colorPerVertex", SFBool::type,
00204                                        &ComposedGeometryNode::colorPerVertex));
00205       fields.push_back(newPrivateField("normalPerVertex", SFBool::type,
00206                                        &ComposedGeometryNode::normalPerVertex));
00207       fields.push_back(newPrivateField("solid", SFBool::type,
00208                                        &ComposedGeometryNode::solid));
00209       ComposedGeometryNode::type =
00210         NodeType::newAbstract("ComposedGeometryNode", false, &fields,
00211                               Geometry3DNode::type);
00212       fields.clear();
00213 
00214 
00215       // IndexedFaceSet
00216 
00217       fields.push_back(newPrivateField("convex", SFBool::type,
00218                                        &IndexedFaceSet::convex));
00219       fields.push_back(newPrivateField("colorIndex", MFInt32::type,
00220                                        &IndexedFaceSet::colorIndex));
00221       fields.push_back(newEventIn("set_colorIndex", MFInt32::type,
00222                                   &IndexedFaceSet::colorIndexAssign,
00223                                   &IndexedFaceSet::colorIndexStamp));
00224       fields.push_back(newPrivateField("coordIndex", MFInt32::type,
00225                                        &IndexedFaceSet::coordIndex));
00226       fields.push_back(newEventIn("set_coordIndex", MFInt32::type,
00227                                   &IndexedFaceSet::coordIndexAssign,
00228                                   &IndexedFaceSet::coordIndexStamp));
00229       fields.push_back(newPrivateField("creaseAngle", SFFloat::type,
00230                                        &IndexedFaceSet::creaseAngle));
00231       fields.push_back(newPrivateField("normalIndex", MFInt32::type,
00232                                        &IndexedFaceSet::normalIndex));
00233       fields.push_back(newEventIn("set_normalIndex", MFInt32::type,
00234                                   &IndexedFaceSet::normalIndexAssign,
00235                                   &IndexedFaceSet::normalIndexStamp));
00236       fields.push_back(newPrivateField("texCoordIndex", MFInt32::type,
00237                                        &IndexedFaceSet::texCoordIndex));
00238       fields.push_back(newEventIn("set_texCoordIndex", MFInt32::type,
00239                                   &IndexedFaceSet::texCoordIndexAssign,
00240                                   &IndexedFaceSet::texCoordIndexStamp));
00241       IndexedFaceSet::type =
00242         NodeType::newConcrete("IndexedFaceSet", "geometry",
00243                               IndexedFaceSet::instantiate, &fields,
00244                               ComposedGeometryNode::type);
00245       fields.clear();
00246 
00247 
00248       // ElevationGrid
00249 
00250       fields.push_back(newPrivateField("creaseAngle", SFFloat::type,
00251                                        &ElevationGrid::creaseAngle));
00252       fields.push_back(newPrivateField("height", MFFloat::type,
00253                                        &ElevationGrid::height));
00254       fields.push_back(newEventIn("set_height", MFFloat::type,
00255                                   &ElevationGrid::height,
00256                                   &ElevationGrid::heightStamp));
00257       fields.push_back(newPrivateField("xDimension", SFInt32::type,
00258                                        &ElevationGrid::xDimension));
00259       fields.push_back(newPrivateField("xSpacing", SFFloat::type,
00260                                        &ElevationGrid::xSpacing));
00261       fields.push_back(newPrivateField("zDimension", SFInt32::type,
00262                                        &ElevationGrid::zDimension));
00263       fields.push_back(newPrivateField("zSpacing", SFFloat::type,
00264                                        &ElevationGrid::zSpacing));
00265       ElevationGrid::type =
00266         NodeType::newConcrete("ElevationGrid", "geometry",
00267                               ElevationGrid::instantiate, &fields,
00268                               ComposedGeometryNode::type);
00269       fields.clear();
00270 
00271 
00272       // ShapeNode
00273 
00274       ShapeNode::type =
00275         NodeType::newAbstract("ShapeNode", false, 0,
00276                               ChildNode::type);
00277 
00278 
00279       // Shape
00280 
00281       fields.push_back(newExposedField("appearance",
00282                                        &Shape::appearance,
00283                                        &Shape::appearanceChanged,
00284                                        &Shape::appearanceStamp));
00285       fields.push_back(newExposedField("geometry",
00286                                        &Shape::geometry,
00287                                        &Shape::geometryChanged,
00288                                        &Shape::geometryStamp));
00289       Shape::type =
00290         NodeType::newConcrete("Shape", "children",
00291                               Shape::instantiate, &fields,
00292                               ShapeNode::type, BoundedObject::type);
00293       fields.clear();
00294     }
00295 
00296 
00297     bool ComposedGeometryNode::coordAssign(const Ref<CoordinateNode> &v, const Time &t)
00298     {
00299       coord = v;
00300       coordStamp = t;
00301       reprocess();
00302       return true;
00303     }
00304 
00305     bool ComposedGeometryNode::colorAssign(const Ref<ColorNode> &v, const Time &t)
00306     {
00307       color = v;
00308       colorStamp = t;
00309       reprocess();
00310       return true;
00311     }
00312 
00313     bool ComposedGeometryNode::normalAssign(const Ref<NormalNode> &v, const Time &t)
00314     {
00315       normal = v;
00316       normalStamp = t;
00317       reprocess();
00318       return true;
00319     }
00320 
00321     bool ComposedGeometryNode::texCoordAssign(const Ref<TextureCoordinateNode> &v, const Time &t)
00322     {
00323       texCoord = v;
00324       texCoordStamp = t;
00325       reprocess();
00326       return true;
00327     }
00328 
00329     bool IndexedFaceSet::coordIndexAssign(const vector<int> &v, const Time &t)
00330     {
00331       coordIndex = v;
00332       coordIndexStamp = t;
00333       reprocess();
00334       return true;
00335     }
00336 
00337     bool IndexedFaceSet::colorIndexAssign(const vector<int> &v, const Time &t)
00338     {
00339       colorIndex = v;
00340       colorIndexStamp = t;
00341       reprocess();
00342       return true;
00343     }
00344 
00345     bool IndexedFaceSet::normalIndexAssign(const vector<int> &v, const Time &t)
00346     {
00347       normalIndex = v;
00348       normalIndexStamp = t;
00349       reprocess();
00350       return true;
00351     }
00352 
00353     bool IndexedFaceSet::texCoordIndexAssign(const vector<int> &v, const Time &t)
00354     {
00355       texCoordIndex = v;
00356       texCoordIndexStamp = t;
00357       reprocess();
00358       return true;
00359     }
00360 
00361 
00362     void renderNormals(const vector<Vector3> &n, const RenderConfig *c)
00363     {
00364       glDisable(GL_LIGHTING);
00365       glDisable(GL_TEXTURE_2D);
00366       glLineWidth(1);
00367       glColor3f(c->normalColor[0], c->normalColor[1], c->normalColor[2]);
00368       glBegin(GL_LINES);
00369       unsigned i = 0;
00370       while(i<n.size())
00371       {
00372         Vector3 v = n[i++];
00373         glVertex3d(v[0], v[1], v[2]);
00374         v += n[i++] * c->normalLength;
00375         glVertex3d(v[0], v[1], v[2]);
00376       }
00377       glEnd();
00378     }
00379 
00380 
00381     // Box
00382 
00383     int Box::intersect(const Math::Ray3 &ray, double &dist) const
00384     {
00385       Math::Box3 box(size);
00386       return Math::intersect(ray, box, dist);
00387     }
00388 
00389     void Box::getNormalAndTexCoord(Vector3 hitPoint, int where,
00390                                    const Shape *,
00391                                    Vector3 *hitNormal,
00392                                    Vector2 *hitTexCoord) const
00393     {
00394       switch(where)
00395       {
00396       case 1: //left face
00397         if(hitNormal) hitNormal->set(-1, 0, 0);
00398         if(hitTexCoord) hitTexCoord->set(0.5+hitPoint[2]/size[2], 0.5+hitPoint[1]/size[1]);
00399         break;
00400       case 2: //right face
00401         if(hitNormal) hitNormal->set(1, 0, 0);
00402         if(hitTexCoord) hitTexCoord->set(0.5-hitPoint[2]/size[2], 0.5+hitPoint[1]/size[1]);
00403         break;
00404       case 3: //bottom face
00405         if(hitNormal) hitNormal->set(0, -1, 0);
00406         if(hitTexCoord) hitTexCoord->set(0.5+hitPoint[0]/size[0], 0.5+hitPoint[2]/size[2]);
00407         break;
00408       case 4: //top face
00409         if(hitNormal) hitNormal->set(0, 1, 0);
00410         if(hitTexCoord) hitTexCoord->set(0.5+hitPoint[0]/size[0], 0.5-hitPoint[2]/size[2]);
00411         break;
00412       case 5: //back face
00413         if(hitNormal) hitNormal->set(0, 0, -1);
00414         if(hitTexCoord) hitTexCoord->set(0.5-hitPoint[0]/size[0], 0.5+hitPoint[1]/size[1]);
00415         break;
00416       case 6: //front face
00417         if(hitNormal) hitNormal->set(0, 0, 1);
00418         if(hitTexCoord) hitTexCoord->set(0.5+hitPoint[0]/size[0], 0.5+hitPoint[1]/size[1]);
00419         break;
00420       }
00421     }
00422 
00423 
00424     // Cone
00425 
00426     int Cone::intersect(const Math::Ray3 &ray, double &dist) const
00427     {
00428       bool enterOnly = side & bottom;
00429       return Math::intersectCone(ray, height, bottomRadius, dist, side,
00430                                  bottom, enterOnly);
00431     }
00432 
00433     void Cone::getNormalAndTexCoord(Vector3 hitPoint, int where,
00434                                     const Shape *,
00435                                     Vector3 *hitNormal,
00436                                     Vector2 *hitTexCoord) const
00437     {
00438       switch(where)
00439       {
00440       case 1: // side
00441         if(hitNormal)
00442         {
00443           double h = bottomRadius/height;
00444           double f = bottomRadius * (0.5 - hitPoint[1]/height);
00445           if(f==0) hitNormal->set(0, h, 1);
00446           else hitNormal->set(hitPoint[0]/f, h, hitPoint[2]/f);
00447         }
00448 
00449         if(hitTexCoord)
00450         {
00451           (*hitTexCoord)[0] = hitPoint[0] == 0 ? hitPoint[2] < 0 ? 0 : 0.5 :
00452             (hitPoint[0] < 0 ? 0.25 : 0.75) - atan(hitPoint[2]/hitPoint[0]) / (2 * M_PI);
00453 
00454           (*hitTexCoord)[1] = 0.5 + hitPoint[1]/height;
00455         }
00456         break;
00457 
00458       case 2: // bottom cap
00459         if(hitNormal) hitNormal->set(0, -1, 0);
00460         if(hitTexCoord) hitTexCoord->set(0.5+hitPoint[0]/bottomRadius/2, 0.5+hitPoint[2]/bottomRadius/2);
00461         break;
00462       }
00463     }
00464 
00465 
00466     // Cylinder
00467 
00474     int Cylinder::intersect(const Math::Ray3 &ray, double &dist) const
00475     {
00476       bool enterOnly = side & top & bottom;
00477       return Math::intersectCylinder(ray, height, radius, dist, side,
00478                                      top, bottom, enterOnly);
00479     }
00480 
00481     void Cylinder::getNormalAndTexCoord(Vector3 hitPoint, int where,
00482                                         const Shape *,
00483                                         Vector3 *hitNormal,
00484                                         Vector2 *hitTexCoord) const
00485     {
00486       switch(where)
00487       {
00488       case 1: // side
00489         if(hitNormal)
00490         {
00491           hitNormal->set(hitPoint[0], 0, hitPoint[2]);
00492         }
00493 
00494         if(hitTexCoord)
00495         {
00496           (*hitTexCoord)[0] = hitPoint[0] == 0 ? hitPoint[2] < 0 ? 0 : 0.5 :
00497             (hitPoint[0] < 0 ? 0.25 : 0.75) - atan(hitPoint[2]/hitPoint[0]) / (2 * M_PI);
00498 
00499           (*hitTexCoord)[1] = 0.5 + hitPoint[1]/height;
00500         }
00501         break;
00502 
00503       case 2: // bottom cap
00504         if(hitNormal) hitNormal->set(0, -1, 0);
00505         if(hitTexCoord) hitTexCoord->set(0.5+hitPoint[0]/radius/2, 0.5+hitPoint[2]/radius/2);
00506         break;
00507 
00508       case 3: // top cap
00509         if(hitNormal) hitNormal->set(0, 1, 0);
00510         if(hitTexCoord) hitTexCoord->set(0.5+hitPoint[0]/radius/2, 0.5-hitPoint[2]/radius/2);
00511         break;
00512       }
00513     }
00514 
00515 
00516     // Sphere
00517 
00518     int Sphere::intersect(const Math::Ray3 &ray, double &dist) const
00519     {
00520       Math::Sphere3 sphere(radius);
00521       return Math::intersect(ray, sphere, dist) ? 1 : 0;
00522     }
00523 
00524     void Sphere::getNormalAndTexCoord(Vector3 hitPoint, int where,
00525                                       const Shape *,
00526                                       Vector3 *hitNormal,
00527                                       Vector2 *hitTexCoord) const
00528     {
00529       if(hitNormal) *hitNormal = hitPoint;
00530 
00531       if(!hitTexCoord) return;
00532 
00533       /*
00534        * Determine the longitude angle of the point as a value between 0
00535        * and 1 (starting and ending at the prime meridian and rising to
00536        * the east.)
00537        * Note that the longitude is actually the shortest angle between the
00538        * prime meridian and the meridian of the point.
00539        */
00540       (*hitTexCoord)[0] = hitPoint[0] == 0 ? hitPoint[2] < 0 ? 0 : 0.5 :
00541         (hitPoint[0] < 0 ? 0.25 : 0.75) - atan(hitPoint[2]/hitPoint[0]) / (2 * M_PI);
00542 
00543       /*
00544        * Determine the latitude angle of the point as a value between 0
00545        * and 1 (0 beeing at the south pole and 1 beeing at the north
00546        * pole.)
00547        * Note that the latitude is actually the shortest angle between the
00548        * intersection direction and the equator plane.
00549        */
00550       (*hitTexCoord)[1] = acos(-hitPoint[1]/radius) / M_PI;
00551     }
00552 
00553 
00554     // ElevationGrid
00555 
00559     int ElevationGrid::intersect(const Math::Ray3 &, double &dist) const
00560     {
00561       return false;
00562     }
00563 
00567     void ElevationGrid::getNormalAndTexCoord(Vector3 hitPoint, int where,
00568                                              const Shape *,
00569                                              Vector3 *hitNormal,
00570                                              Vector2 *hitTexCoord) const
00571     {
00572       if(hitNormal) *hitNormal = Vector3::zero();
00573       if(hitTexCoord) *hitTexCoord = Vector2::zero();
00574     }
00575 
00576 
00577     // IndexedFaceSet
00578 
00587     int IndexedFaceSet::intersect(const Math::Ray3 &ray, double &dist) const
00588     {
00589       if(!coords) return 0;
00590 
00591       int f = 0; // Face index
00592       for(unsigned i=0; i<preprocessedCoordIndex.size(); ++i, ++f)
00593       {
00594         Vector3 n = preprocessedNormal[f];
00595         double c = dot(n, ray.direction);
00596         if(c >= 0) // backface culling!!
00597         {
00598           // Seek to next polygon
00599           while(preprocessedCoordIndex[++i] >= 0);
00600           continue;
00601         }
00602 
00603         int i0, i1, i2;
00604         Math::sort3(abs(n[0]), abs(n[1]), abs(n[2]), i2, i0, i1);
00605 
00606         Vector3 p0 = (*coords)[preprocessedCoordIndex[i]];
00607         Vector3 p1 = (*coords)[preprocessedCoordIndex[++i]];
00608         Vector3 p2 = (*coords)[preprocessedCoordIndex[++i]];
00609 
00610         double d = dot(n, p0-ray.origin) / c;
00611       
00612         double v00 = ray.origin[i0] + d*ray.direction[i0] - p0[i0];
00613         double v01 = ray.origin[i1] + d*ray.direction[i1] - p0[i1];
00614 
00615         double v10 = p1[i0] - p0[i0];
00616         double v11 = p1[i1] - p0[i1];
00617 
00618         double v20, v21;
00619         for(;;)
00620         {
00621           v20 = p2[i0] - p0[i0];
00622           v21 = p2[i1] - p0[i1];
00623 
00624           double a, b;
00625           bool hit = false;
00626           if(v10)
00627           {
00628             b = (v01*v10 - v00*v11)/(v21*v10 - v20*v11);
00629             if(b >= 0 && b <= 1)
00630             {
00631               a = (v00 - b*v20)/v10;
00632               if(a >= 0 && a+b <= 1) hit = true;
00633             }
00634           }
00635           else
00636           {
00637             b = v00/v20;
00638             if(b >= 0 && b <= 1)
00639             {
00640               a = (v01 - b*v21)/v11;
00641               if(a >= 0 && a+b <= 1) hit = true;
00642             }
00643           }
00644 
00645           if(hit)
00646           {
00647             // At this point a and b could be used to interpolate colors, normals and texture coordinates
00648             // For example: N = (1-(a+b)) N[0] + a N[i-1] + b N[i];
00649 
00650             dist = d;
00651             return i-1;
00652           }
00653 
00654           int j = preprocessedCoordIndex[++i];
00655           if(j<0) break; // Next polygon
00656 
00657           p2 = (*coords)[j];
00658           v10=v20;
00659           v11=v21;
00660         }
00661       }
00662 
00663       return 0;
00664     }
00665 
00666     void IndexedFaceSet::getNormalAndTexCoord(Vector3 hitPoint, int where,
00667                                               const Shape *shape,
00668                                               Vector3 *hitNormal,
00669                                               Vector2 *hitTexCoord) const
00670     {
00671       if(!coords) return;
00672 
00673       // Backtrack to the beginning of the polygon
00674       int i = where-1;
00675       while(i>0)
00676       {
00677         int j = preprocessedCoordIndex[--i];
00678         if(j<0)
00679         {
00680           ++i;
00681           break;
00682         }
00683       }
00684 
00685       int j0 = preprocessedCoordIndex[i];
00686       int j1 = preprocessedCoordIndex[where];
00687       int j2 = preprocessedCoordIndex[where+1];
00688 
00689       // Count the number of previous faces to determine face index
00690       // (too damned painfull - we need another solution)
00691       int f=0;
00692       {
00693         int j=i;
00694         while(j>0) if(preprocessedCoordIndex[--j]<0) ++f;
00695       }
00696       
00697       Vector3 n = preprocessedNormal[f];
00698 
00699       int i0, i1, i2;
00700       Math::sort3(abs(n[0]), abs(n[1]), abs(n[2]), i2, i0, i1);
00701 
00702       Vector3 p0 = (*coords)[j0];
00703       Vector3 p1 = (*coords)[j1];
00704       Vector3 p2 = (*coords)[j2];
00705 
00706       double v00 = hitPoint[i0] - p0[i0];
00707       double v01 = hitPoint[i1] - p0[i1];
00708 
00709       double v10 = p1[i0] - p0[i0];
00710       double v11 = p1[i1] - p0[i1];
00711 
00712       double v20 = p2[i0] - p0[i0];
00713       double v21 = p2[i1] - p0[i1];
00714 
00715       double a, b;
00716       if(v10)
00717       {
00718         b = (v01*v10 - v00*v11)/(v21*v10 - v20*v11);
00719         a = (v00 - b*v20)/v10;
00720       }
00721       else
00722       {
00723         b = v00/v20;
00724         a = (v01 - b*v21)/v11;
00725       }
00726 
00727       // Normal
00728       if(hitNormal)
00729       {
00730         Vector3 n0, n1, n2;
00731         if(preprocessedNormalIndex.empty())
00732         {
00733           n0 = (*normals)[j0];
00734           n1 = (*normals)[j1];
00735           n2 = (*normals)[j2];
00736         }
00737         else
00738         {
00739           n0 = (*normals)[preprocessedNormalIndex[i]];
00740           n1 = (*normals)[preprocessedNormalIndex[where]];
00741           n2 = (*normals)[preprocessedNormalIndex[where+1]];
00742         }
00743 
00744         n0 *= 1-(a+b);
00745         n1 *= a;
00746         n2 *= b;
00747         n0 += n1;
00748         n0 += n2;
00749         *hitNormal = n0;
00750       }
00751 
00752       // Texture coordinate
00753       if(hitTexCoord)
00754       {
00755         if(texCoords)
00756         {
00757           Vector2 t0, t1, t2;
00758           if(preprocessedTexCoordIndex.empty())
00759           {
00760             t0 = (*texCoords)[j0];
00761             t1 = (*texCoords)[j1];
00762             t2 = (*texCoords)[j2];
00763           }
00764           else
00765           {
00766             t0 = (*texCoords)[preprocessedTexCoordIndex[i]];
00767             t1 = (*texCoords)[preprocessedTexCoordIndex[where]];
00768             t2 = (*texCoords)[preprocessedTexCoordIndex[where+1]];
00769           }
00770 
00771           t0 *= 1-(a+b);
00772           t1 *= a;
00773           t2 *= b;
00774           t0 += t1;
00775           t0 += t2;
00776           *hitTexCoord = t0;
00777         }
00778         else
00779         {
00780           Vector3 bboxCenter;
00781           Vector3 bboxSize = shape->getBboxSize();
00782           if(bboxSize[0] == -1)
00783           {
00784             bboxCenter = preprocessedBboxCenter;
00785             bboxSize   = preprocessedBboxSize;
00786           }
00787           else bboxCenter = shape->getBboxCenter();
00788 
00789           // Find out which spatial coordinates map to which
00790           // texture coordinates
00791           int i0, i1, i2;
00792           Math::sort3(bboxSize[0], bboxSize[1], bboxSize[2], i0, i1, i2);
00793 
00794           hitTexCoord->set(0.5 + (hitPoint[i0] - bboxCenter[i0]) / bboxSize[i0],
00795                            (bboxSize[i1]/2 + hitPoint[i1] - bboxCenter[i1]) / bboxSize[i0]);
00796         }
00797       }
00798     }
00799 
00800     void Box::render(bool texture,
00801                      const Shape *shape,
00802                      const RenderConfig *config)
00803     {
00804       glFrontFace(GL_CCW);
00805       glDisable(GL_COLOR_MATERIAL);
00806       glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, 0);
00807       glEnable(GL_CULL_FACE);
00808 
00809       const double x = size[0]/2;
00810       const double y = size[1]/2;
00811       const double z = size[2]/2;
00812 
00813       glBegin(GL_QUADS);
00814 
00815       // Left
00816       glNormal3d(-1,  0,  0);
00817       if(texture) glTexCoord2d(0, 0);
00818       glVertex3d(-x, -y, -z);
00819       if(texture) glTexCoord2d(1, 0);
00820       glVertex3d(-x, -y,  z);
00821       if(texture) glTexCoord2d(1, 1);
00822       glVertex3d(-x,  y,  z);
00823       if(texture) glTexCoord2d(0, 1);
00824       glVertex3d(-x,  y, -z);
00825 
00826       // Right
00827       glNormal3d( 1,  0,  0);
00828       if(texture) glTexCoord2d(0, 0);
00829       glVertex3d( x, -y,  z);
00830       if(texture) glTexCoord2d(1, 0);
00831       glVertex3d( x, -y, -z);
00832       if(texture) glTexCoord2d(1, 1);
00833       glVertex3d( x,  y, -z);
00834       if(texture) glTexCoord2d(0, 1);
00835       glVertex3d( x,  y,  z);
00836 
00837       // Bottom
00838       glNormal3d( 0, -1,  0);
00839       if(texture) glTexCoord2d(0, 0);
00840       glVertex3d(-x, -y, -z);
00841       if(texture) glTexCoord2d(1, 0);
00842       glVertex3d( x, -y, -z);
00843       if(texture) glTexCoord2d(1, 1);
00844       glVertex3d( x, -y,  z);
00845       if(texture) glTexCoord2d(0, 1);
00846       glVertex3d(-x, -y,  z);
00847 
00848       // Top
00849       glNormal3d( 0,  1,  0);
00850       if(texture) glTexCoord2d(0, 0);
00851       glVertex3d(-x,  y,  z);
00852       if(texture) glTexCoord2d(1, 0);
00853       glVertex3d( x,  y,  z);
00854       if(texture) glTexCoord2d(1, 1);
00855       glVertex3d( x,  y, -z);
00856       if(texture) glTexCoord2d(0, 1);
00857       glVertex3d(-x,  y, -z);
00858 
00859       // Back
00860       glNormal3d( 0,  0, -1);
00861       if(texture) glTexCoord2d(0, 0);
00862       glVertex3d( x, -y, -z);
00863       if(texture) glTexCoord2d(1, 0);
00864       glVertex3d(-x, -y, -z);
00865       if(texture) glTexCoord2d(1, 1);
00866       glVertex3d(-x,  y, -z);
00867       if(texture) glTexCoord2d(0, 1);
00868       glVertex3d( x,  y, -z);
00869 
00870       // Front
00871       glNormal3d( 0,  0,  1);
00872       if(texture) glTexCoord2d(0, 0);
00873       glVertex3d(-x, -y,  z);
00874       if(texture) glTexCoord2d(1, 0);
00875       glVertex3d( x, -y,  z);
00876       if(texture) glTexCoord2d(1, 1);
00877       glVertex3d( x,  y,  z);
00878       if(texture) glTexCoord2d(0, 1);
00879       glVertex3d(-x,  y,  z);
00880 
00881       glEnd();
00882 
00883       if(config->showNormals)
00884       {
00885         vector<Vector3> normals;
00886 
00887         // Left
00888         normals.push_back(Vector3(-x, -y, -z));
00889         normals.push_back(Vector3(-1,  0,  0));
00890         normals.push_back(Vector3(-x, -y,  z));
00891         normals.push_back(Vector3(-1,  0,  0));
00892         normals.push_back(Vector3(-x,  y,  z));
00893         normals.push_back(Vector3(-1,  0,  0));
00894         normals.push_back(Vector3(-x,  y, -z));
00895         normals.push_back(Vector3(-1,  0,  0));
00896 
00897         // Right
00898         normals.push_back(Vector3( x, -y,  z));
00899         normals.push_back(Vector3( 1,  0,  0));
00900         normals.push_back(Vector3( x, -y, -z));
00901         normals.push_back(Vector3( 1,  0,  0));
00902         normals.push_back(Vector3( x,  y, -z));
00903         normals.push_back(Vector3( 1,  0,  0));
00904         normals.push_back(Vector3( x,  y,  z));
00905         normals.push_back(Vector3( 1,  0,  0));
00906 
00907         // Bottom
00908         normals.push_back(Vector3(-x, -y, -z));
00909         normals.push_back(Vector3( 0, -1,  0));
00910         normals.push_back(Vector3( x, -y, -z));
00911         normals.push_back(Vector3( 0, -1,  0));
00912         normals.push_back(Vector3( x, -y,  z));
00913         normals.push_back(Vector3( 0, -1,  0));
00914         normals.push_back(Vector3(-x, -y,  z));
00915         normals.push_back(Vector3( 0, -1,  0));
00916 
00917         // Top
00918         normals.push_back(Vector3(-x,  y,  z));
00919         normals.push_back(Vector3( 0,  1,  0));
00920         normals.push_back(Vector3( x,  y,  z));
00921         normals.push_back(Vector3( 0,  1,  0));
00922         normals.push_back(Vector3( x,  y, -z));
00923         normals.push_back(Vector3( 0,  1,  0));
00924         normals.push_back(Vector3(-x,  y, -z));
00925         normals.push_back(Vector3( 0,  1,  0));
00926 
00927         // Back
00928         normals.push_back(Vector3( x, -y, -z));
00929         normals.push_back(Vector3( 0,  0, -1));
00930         normals.push_back(Vector3(-x, -y, -z));
00931         normals.push_back(Vector3( 0,  0, -1));
00932         normals.push_back(Vector3(-x,  y, -z));
00933         normals.push_back(Vector3( 0,  0, -1));
00934         normals.push_back(Vector3( x,  y, -z));
00935         normals.push_back(Vector3( 0,  0, -1));
00936 
00937         // Front
00938         normals.push_back(Vector3(-x, -y,  z));
00939         normals.push_back(Vector3( 0,  0,  1));
00940         normals.push_back(Vector3( x, -y,  z));
00941         normals.push_back(Vector3( 0,  0,  1));
00942         normals.push_back(Vector3( x,  y,  z));
00943         normals.push_back(Vector3( 0,  0,  1));
00944         normals.push_back(Vector3(-x,  y,  z));
00945         normals.push_back(Vector3( 0,  0,  1));
00946 
00947         renderNormals(normals, config);
00948       }
00949     }
00950 
00951     void Cone::render(bool texture,
00952                       const Shape *shape,
00953                       const RenderConfig *config)
00954     {
00955       glFrontFace(GL_CW);
00956       glDisable(GL_COLOR_MATERIAL);
00957       if(side&bottom)
00958       {
00959         glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, 0);
00960         glEnable(GL_CULL_FACE);
00961       }
00962       else
00963       {
00964         glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, 1);
00965         glDisable(GL_CULL_FACE);
00966       }
00967 
00968       const int heightSteps = config->subdivision2;  // Eleveation / lattitude
00969       const int thetaSteps = config->subdivision1; // Azimuth / longitude
00970 
00971       const double r = bottomRadius;
00972       const double h = height;
00973 
00974       vector<Vector2> vl(thetaSteps);
00975 
00976       vector<Vector3> normals;
00977       const bool showNormals = config->showNormals;
00978 
00979       // Bottom
00980       if(bottom)
00981       {
00982         glBegin(GL_POLYGON);
00983         glNormal3d(0, -1, 0);
00984         const double y = h/-2;
00985         for(int i=0; i<thetaSteps; ++i)
00986         {
00987           const double theta = 2 * M_PI / thetaSteps * i;
00988 
00989           Vector2 v(-sin(theta), -cos(theta));
00990           if(texture) glTexCoord2d(v[0]/2+0.5, v[1]/2+0.5);
00991           vl[i] = v *= r;
00992           glVertex3d(v[0], y, v[1]);
00993         }
00994         glEnd();
00995         if(showNormals) for(int i=0; i<thetaSteps; ++i)
00996         {
00997           normals.push_back(Vector3(vl[i][0], y, vl[i][1]));
00998           normals.push_back(Vector3(0, -1, 0));
00999         }
01000       }
01001       else
01002       {
01003         for(int i=0; i<thetaSteps; ++i)
01004         {
01005           const double theta = 2 * M_PI / thetaSteps * i;
01006           vl[i] = Vector2(-sin(theta)*r, -cos(theta)*r);
01007         }
01008       }
01009 
01010       if(side)
01011       {
01012         Vector2 n(h, r);
01013         n.normalize();
01014 
01015         double prevTexT = 0;
01016         double prevY = h/-2;
01017 
01018         Vector2 v;
01019 
01020         // Middle quad strips
01021         for(int i=1; i<=heightSteps; ++i)
01022         {
01023           glBegin(GL_QUAD_STRIP);
01024 
01025           const Vector2 w = vl[0];
01026 
01027           const double texT = 1.0 / heightSteps * i;
01028           const double y = h * (texT - 0.5);
01029 
01030           for(int j=0; j<thetaSteps; ++j)
01031           {
01032             const double texS = 1.0 / thetaSteps * j;
01033             const double theta = 2 * M_PI * texS;
01034 
01035             double x = -sin(theta);
01036             double z = -cos(theta);
01037 
01038             glNormal3d(x*n[0], n[1], z*n[0]);
01039 
01040             if(texture) glTexCoord2d(texS, prevTexT);
01041             v = vl[j];
01042             glVertex3d(v[0], prevY, v[1]);
01043             if(showNormals)
01044             {
01045               normals.push_back(Vector3(v[0], prevY, v[1]));
01046               normals.push_back(Vector3(x*n[0], n[1], z*n[0]));
01047             }
01048 
01049             if(texture) glTexCoord2d(texS, texT);
01050             v = Vector2(x, z);
01051             v *= r * (1 - texT);
01052             glVertex3d(v[0], y, v[1]);
01053             vl[j] = v;
01054           }
01055 
01056           glNormal3d(0, n[1], -n[0]);
01057 
01058           if(texture) glTexCoord2d(1, prevTexT);
01059           glVertex3d(w[0], prevY, w[1]);
01060 
01061           if(texture) glTexCoord2d(1, texT);
01062           v = vl[0];
01063           glVertex3d(v[0], y, v[1]);
01064 
01065           prevTexT = texT;
01066           prevY = y;
01067 
01068           glEnd();
01069         }
01070 
01071         if(showNormals) for(int i=0; i<thetaSteps; ++i)
01072         {
01073           const double texS = 1.0 / thetaSteps * i;
01074           const double theta = 2 * M_PI * texS;
01075 
01076           double x = -sin(theta);
01077           double z = -cos(theta);
01078 
01079           normals.push_back(Vector3(vl[i][0], prevY, vl[i][1]));
01080           normals.push_back(Vector3(x*n[0], n[1], z*n[0]));
01081         }
01082       }
01083  
01084       if(showNormals) renderNormals(normals, config);
01085    }
01086 
01087     void Cylinder::render(bool texture,
01088                           const Shape *shape,
01089                           const RenderConfig *config)
01090     {
01091       glFrontFace(GL_CCW);
01092       glDisable(GL_COLOR_MATERIAL);
01093       if(side&top&bottom)
01094       {
01095         glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, 0);
01096         glEnable(GL_CULL_FACE);
01097       }
01098       else
01099       {
01100         glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, 1);
01101         glDisable(GL_CULL_FACE);
01102       }
01103 
01104       const int thetaSteps = config->subdivision1; // Azimuth / longitude
01105 
01106       const double r = radius;
01107       const double y = height / 2;
01108 
01109       vector<Vector2> vl(thetaSteps);
01110       vector<Vector2> tl(texture ? thetaSteps : 0);
01111 
01112       vector<Vector3> normals;
01113       const bool showNormals = config->showNormals;
01114 
01115       // Side
01116       if(side)
01117       {
01118         glBegin(GL_QUAD_STRIP);
01119 
01120         for(int i=0; i<thetaSteps; ++i)
01121         {
01122           const double texS = 1.0 / thetaSteps * i;
01123           const double theta = 2 * M_PI * texS;
01124 
01125           double x = -sin(theta);
01126           double z = -cos(theta);
01127 
01128           if(texture) tl[i] = Vector2(x/2+0.5, z/-2+0.5);
01129 
01130           glNormal3d(x, 0, z);
01131           if(showNormals)
01132           {
01133             normals.push_back(Vector3(x*r, y, z*r));
01134             normals.push_back(Vector3(x, 0, z));
01135             normals.push_back(Vector3(x*r, -y, z*r));
01136             normals.push_back(Vector3(x, 0, z));
01137           }
01138           x *= r;
01139           z *= r;
01140           if(texture) glTexCoord2d(texS, 1);
01141           glVertex3d(x, y, z);
01142           if(texture) glTexCoord2d(texS, 0);
01143           glVertex3d(x, -y, z);
01144 
01145           vl[i] = Vector2(x, z);
01146         }
01147 
01148         glNormal3d(0, 0, -1);
01149         if(texture) glTexCoord2d(1, 1);
01150         glVertex3d(0, y, -r);
01151         if(texture) glTexCoord2d(1, 0);
01152         glVertex3d(0, -y, -r);
01153 
01154         glEnd();
01155       }
01156       else
01157       {
01158         for(int i=0; i<thetaSteps; ++i)
01159         {
01160           const double theta = 2 * M_PI / thetaSteps * i;
01161 
01162           double x = -sin(theta);
01163           double z = -cos(theta);
01164           if(texture) tl[i] = Vector2(x/2+0.5, z/-2+0.5);
01165           vl[i] = Vector2(x*r, z*r);
01166         }
01167       }
01168 
01169       // Top
01170       if(top)
01171       {
01172         glNormal3d(0, 1, 0);
01173         glBegin(GL_POLYGON);
01174         for(int i=0; i<thetaSteps; ++i)
01175         {
01176           if(texture) glTexCoord2d(tl[i][0], tl[i][1]);
01177           glVertex3d(vl[i][0], y, vl[i][1]);
01178         }
01179         glEnd();
01180         if(showNormals) for(int i=0; i<thetaSteps; ++i)
01181         {
01182           normals.push_back(Vector3(vl[i][0], y, vl[i][1]));
01183           normals.push_back(Vector3(0, 1, 0));
01184         }
01185       }
01186 
01187       // Bottom
01188       if(bottom)
01189       {
01190         glNormal3d(0, -1, 0);
01191         glBegin(GL_POLYGON);
01192         for(int i=thetaSteps-1; i>=0; --i)
01193         {
01194           if(texture) glTexCoord2d(tl[i][0], -tl[i][1]);
01195           glVertex3d(vl[i][0], -y, vl[i][1]);
01196         }
01197         glEnd();
01198         if(showNormals) for(int i=0; i<thetaSteps; ++i)
01199         {
01200           normals.push_back(Vector3(vl[i][0], -y, vl[i][1]));
01201           normals.push_back(Vector3(0, -1, 0));
01202         }
01203       }
01204 
01205       if(showNormals) renderNormals(normals, config);
01206     }
01207 
01208 
01209     void IndexedLineSet::render(bool texture,
01210                                 const Shape *shape,
01211                                 const RenderConfig *config)
01212     {
01213       if(!coord) return;
01214 
01215       const Coordinate *_coord =
01216         dynamic_cast<const Coordinate *>(coord.get());
01217       const Color *rgb =
01218         dynamic_cast<const Color *>(color.get());
01219       const ColorRGBA *rgba =
01220         dynamic_cast<const ColorRGBA *>(color.get());
01221 
01222       if(!_coord)
01223         ARCHON_THROW1(InternalException,
01224                       "'" + coord->getType()->getName() +
01225                       "' is not supported yet");
01226       if(!rgb && !rgba && color)
01227         ARCHON_THROW1(InternalException,
01228                       "'" + color->getType()->getName() +
01229                       "' is not supported yet");
01230 
01231       const vector<Vector3> &v = _coord->getPoint();
01232       const vector<Vector3> *rgb_v  = rgb  ? &rgb->getColor()  : 0;
01233       const vector<Vector4> *rgba_v = rgba ? &rgba->getColor() : 0;
01234 
01235       bool hasColorIndex = !colorIndex.empty();
01236       bool rgbPerVertex  = rgb  && colorPerVertex;
01237       bool rgbPerFace    = rgb  && !rgbPerVertex;
01238       bool rgbaPerVertex = rgba && colorPerVertex;
01239       bool rgbaPerFace   = rgba && !rgbaPerVertex;
01240 
01241       vector<int>::const_iterator ci = colorIndex.begin();
01242       vector<int>::const_iterator vi = coordIndex.begin();
01243 
01244       glLineWidth(lineWidth);
01245       //glEnable(GL_LINE_SMOOTH);
01246       glDisable(GL_LIGHTING);
01247       glDisable(GL_TEXTURE_2D);
01248 
01249       if(!rgb && !rgba)
01250       {
01251         const Appearance *a =
01252           dynamic_cast<const Appearance *>(shape->getAppearance().get());
01253         if(a)
01254         {
01255           const Material *m =
01256             dynamic_cast<const Material *>(a->getMaterial().get());
01257           if(m)
01258           {
01259             Vector3 c = m->getEmissiveColor();
01260             glColor3d(c[0], c[1], c[2]);
01261           }
01262         }
01263       }
01264 
01265       int i = 0; // Face index
01266       while(vi != coordIndex.end())
01267       {
01268         if(rgbPerFace)
01269         {
01270           const Vector3 &c = (*rgb_v)[hasColorIndex ? *(ci++) : i];
01271           glColor3d(c[0], c[1], c[2]);
01272         }
01273 
01274         if(rgbaPerFace)
01275         {
01276           const Vector4 &c = (*rgba_v)[hasColorIndex ? *(ci++) : i];
01277           glColor4d(c[0], c[1], c[2], c[3]);
01278         }
01279 
01280         glBegin(GL_LINE_STRIP);
01281         for(;;)
01282         {
01283           if(rgbPerVertex)
01284           {
01285             const Vector3 &c = (*rgb_v)[hasColorIndex ? *(ci++) : *vi];
01286             glColor3d(c[0], c[1], c[2]);
01287           }
01288 
01289           if(rgbaPerVertex)
01290           {
01291             const Vector4 &c = (*rgba_v)[hasColorIndex ? *(ci++) : *vi];
01292             glColor4d(c[0], c[1], c[2], c[3]);
01293           }
01294 
01295           const Vector3 &w = v[*(vi++)];
01296           glVertex3d(w[0], w[1], w[2]);
01297 
01298           if(vi == coordIndex.end()) break;
01299           if(*vi == -1)
01300           {
01301             ++vi;
01302             if(rgbPerVertex || rgbaPerVertex) ++ci;
01303             break;
01304           }
01305         }
01306         glEnd();
01307 
01308         ++i;
01309       }
01310     }
01311 
01312 
01313     void PointSet::render(bool texture,
01314                           const Shape *shape,
01315                           const RenderConfig *config)
01316     {
01317       if(!coord) return;
01318 
01319       const Coordinate *_coord =
01320         dynamic_cast<const Coordinate *>(coord.get());
01321       const Color *rgb =
01322         dynamic_cast<const Color *>(color.get());
01323       const ColorRGBA *rgba =
01324         dynamic_cast<const ColorRGBA *>(color.get());
01325 
01326       if(!_coord)
01327         ARCHON_THROW1(InternalException,
01328                       "'" + coord->getType()->getName() +
01329                       "' is not supported yet");
01330       if(!rgb && !rgba && color)
01331         ARCHON_THROW1(InternalException,
01332                       "'" + color->getType()->getName() +
01333                       "' is not supported yet");
01334 
01335       const vector<Vector3> &v = _coord->getPoint();
01336       const unsigned n = v.size();
01337       if(!n) return;
01338 
01339       if(rgb  && rgb->getColor().size()  < n ||
01340          rgba && rgba->getColor().size() < n)
01341       {
01342         rgb = 0;
01343         rgba = 0;
01344       }
01345 
01346       glPointSize(2);
01347       //glEnable(GL_POINT_SMOOTH);
01348       glDisable(GL_LIGHTING);
01349       glDisable(GL_TEXTURE_2D);
01350 
01351       if(!rgb && !rgba)
01352       {
01353         const Appearance *a =
01354           dynamic_cast<const Appearance *>(shape->getAppearance().get());
01355         if(a)
01356         {
01357           const Material *m =
01358             dynamic_cast<const Material *>(a->getMaterial().get());
01359           if(m)
01360           {
01361             Vector3 c = m->getEmissiveColor();
01362             glColor3d(c[0], c[1], c[2]);
01363           }
01364         }
01365       }
01366 
01367       glBegin(GL_POINTS);
01368       for(unsigned i=0; i<n; ++i)
01369       {
01370         if(rgb)
01371         {
01372           Vector3 c = rgb->getColor()[i];
01373           glColor3d(c[0], c[1], c[2]);
01374         }
01375         else if(rgba)
01376         {
01377           Vector4 c = rgba->getColor()[i];
01378           glColor4d(c[0], c[1], c[2], c[3]);
01379         }
01380         Vector3 w = v[i];
01381         glVertex3d(w[0], w[1], w[2]);
01382       }
01383       glEnd();
01384     }
01385 
01386 
01387     void Sphere::render(bool texture,
01388                         const Shape *shape,
01389                         const RenderConfig *config)
01390     {
01391       glFrontFace(GL_CW);
01392       glDisable(GL_COLOR_MATERIAL);
01393       glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, 0);
01394       glEnable(GL_CULL_FACE);
01395 
01396       const int phiSteps = config->subdivision2;  // Eleveation / lattitude
01397       const int thetaSteps = config->subdivision1; // Azimuth / longitude
01398 
01399       vector<Vector3> normals;
01400       const bool showNormals = config->showNormals;
01401 
01402       vector<Vector3> vl(thetaSteps);
01403 
01404       glBegin(GL_QUAD_STRIP);
01405 
01406       Vector3 v;
01407 
01408       // Southern pole
01409       if(showNormals)
01410       {
01411         normals.push_back(Vector3(0, -radius, 0));
01412         normals.push_back(Vector3(0, -1, 0));
01413       }
01414       double texT = 1.0 / phiSteps;
01415       double phi = M_PI * (texT - 0.5);
01416       double sin_phi = sin(phi);
01417       double cos_phi = cos(phi);
01418       for(int i=0; i<thetaSteps; ++i)
01419       {
01420         double texS = 1.0 / thetaSteps * i;
01421         double theta = 2 * M_PI * texS;
01422 
01423         if(texture) glTexCoord2d(texS, 0);
01424         glNormal3d(0, -1, 0);
01425         glVertex3d(0, -radius, 0);
01426 
01427         if(texture) glTexCoord2d(texS, texT);
01428         v = vl[i] = Vector3(cos_phi*-sin(theta), sin_phi, cos_phi*-cos(theta));
01429         glNormal3d(v[0], v[1], v[2]);
01430         v *= radius;
01431         glVertex3d(v[0], v[1], v[2]);
01432         if(showNormals)
01433         {
01434           normals.push_back(v);
01435           normals.push_back(vl[i]);
01436         }
01437       }
01438 
01439       if(texture) glTexCoord2d(1, 0);
01440       glNormal3d(0, -1, 0);
01441       glVertex3d(0, -radius, 0);
01442 
01443       if(texture) glTexCoord2d(1, texT);
01444       v = vl[0];
01445       glNormal3d(v[0], v[1], v[2]);
01446       v *= radius;
01447       glVertex3d(v[0], v[1], v[2]);
01448 
01449       double prevTexT = texT;
01450 
01451       glEnd();
01452 
01453       // Middle quad strips
01454       for(int i=2; i<phiSteps; ++i)
01455       {
01456         glBegin(GL_QUAD_STRIP);
01457 
01458         Vector3 w = vl[0];
01459 
01460         texT = 1.0 / phiSteps * i;
01461         phi = M_PI * (texT - 0.5);
01462         sin_phi = sin(phi);
01463         cos_phi = cos(phi);
01464         for(int j=0; j<thetaSteps; ++j)
01465         {
01466           double texS = 1.0 / thetaSteps * j;
01467           double theta = 2 * M_PI * texS;
01468 
01469           if(texture) glTexCoord2d(texS, prevTexT);
01470           v = vl[j];
01471           glNormal3d(v[0], v[1], v[2]);
01472           v *= radius;
01473           glVertex3d(v[0], v[1], v[2]);
01474 
01475           if(texture) glTexCoord2d(texS, texT);
01476           v = vl[j] = Vector3(cos_phi*-sin(theta), sin_phi, cos_phi*-cos(theta));
01477           glNormal3d(v[0], v[1], v[2]);
01478           v *= radius;
01479           glVertex3d(v[0], v[1], v[2]);
01480           if(showNormals)
01481           {
01482             normals.push_back(v);
01483             normals.push_back(vl[j]);
01484           }
01485         }
01486 
01487         if(texture) glTexCoord2d(1, prevTexT);
01488         glNormal3d(w[0], w[1], w[2]);
01489         w *= radius;
01490         glVertex3d(w[0], w[1], w[2]);
01491 
01492         if(texture) glTexCoord2d(1, texT);
01493         v = vl[0];
01494         glNormal3d(v[0], v[1], v[2]);
01495         v *= radius;
01496         glVertex3d(v[0], v[1], v[2]);
01497 
01498         prevTexT = texT;
01499 
01500         glEnd();
01501       }
01502 
01503       // Northern pole
01504       glBegin(GL_QUAD_STRIP);
01505 
01506       for(int i=0; i<thetaSteps; ++i)
01507       {
01508         double texS = 1.0 / thetaSteps * i;
01509 
01510         if(texture) glTexCoord2d(texS, prevTexT);
01511         v = vl[i];
01512         glNormal3d(v[0], v[1], v[2]);
01513         v *= radius;
01514         glVertex3d(v[0], v[1], v[2]);
01515 
01516         if(texture) glTexCoord2d(texS, 1);
01517         glNormal3d(0, 1, 0);
01518         glVertex3d(0, radius, 0);
01519       }
01520 
01521       if(texture) glTexCoord2d(1, prevTexT);
01522       v = vl[0];
01523       glNormal3d(v[0], v[1], v[2]);
01524       v *= radius;
01525       glVertex3d(v[0], v[1], v[2]);
01526 
01527       if(texture) glTexCoord2d(1, 1);
01528       glNormal3d(0, 1, 0);
01529       glVertex3d(0, radius, 0);
01530 
01531       if(showNormals)
01532       {
01533         normals.push_back(Vector3(0, radius, 0));
01534         normals.push_back(Vector3(0, 1, 0));
01535       }
01536 
01537       glEnd();
01538 
01539       if(showNormals) renderNormals(normals, config);
01540     }
01541 
01542     void IndexedFaceSet::reprocess()
01543     {
01544       preprocessed = false;
01545     }
01546 
01626     void IndexedFaceSet::preprocess()
01627     {
01628       Logger *logger = Logger::get();
01629 
01630       coords     = 0;
01631       rgbColors  = 0;
01632       rgbaColors = 0;
01633       normals    = 0;
01634       texCoords  = 0;
01635 
01636       preprocessedCoordIndex.clear();
01637       preprocessedColorIndex.clear();
01638       preprocessedNormalIndex.clear();
01639       preprocessedTexCoordIndex.clear();
01640       preprocessedNormal.clear();
01641 
01642       // Coordinate
01643       if(coordIndex.empty())
01644       {
01645         preprocessed = true;
01646         return;
01647       }
01648       if(!coord)
01649       {
01650         logger->log("IndexedFaceSet::preprocess: Lacking CoordinateNode");
01651         preprocessed = true;
01652         return;
01653       }
01654       const Coordinate *_coord =
01655         dynamic_cast<const Coordinate *>(coord.get());
01656       if(!_coord)
01657         ARCHON_THROW1(InternalException,
01658                       "'" + coord->getType()->getName() +
01659                       "' is not supported yet");
01660       coords = &_coord->getPoint();
01661       int nv = coords->size();
01662       if(!nv)
01663       {
01664         logger->log("IndexedFaceSet::preprocess: Empty CoordinateNode");
01665         preprocessed = true;
01666         return;
01667       }
01668 
01669       // Color
01670       const Color     *_rgbColor  = 0;
01671       const ColorRGBA *_rgbaColor = 0;
01672       int nc = 0;
01673       if(color)
01674       {
01675         if((_rgbColor = dynamic_cast<const Color *>(color.get())))
01676           nc = _rgbColor->getColor().size();
01677         else if((_rgbaColor = dynamic_cast<const ColorRGBA *>(color.get())))
01678           nc = _rgbaColor->getColor().size();
01679         else ARCHON_THROW1(InternalException,
01680                            "'" + color->getType()->getName() +
01681                            "' is not supported yet");
01682         if(!nc) logger->log("IndexedFaceSet::preprocess: Empty ColorNode");
01683       }
01684       else if(!colorIndex.empty()) logger->log("IndexedFaceSet::preprocess: Lacking ColorNode");
01685 
01686       // Normal
01687       const Normal *_normal = 0;
01688       int nn = 0;
01689       if(normal)
01690       {
01691         if((_normal = dynamic_cast<const Normal *>(normal.get())))
01692           nn = _normal->getNormal().size();
01693         else ARCHON_THROW1(InternalException,
01694                            "'" + normal->getType()->getName() +
01695                            "' is not supported yet");
01696         if(!nn) logger->log("IndexedFaceSet::preprocess: Empty NormalNode");
01697       }
01698       else if(!normalIndex.empty()) logger->log("IndexedFaceSet::preprocess: WARN: Lacking NormalNode");
01699 
01700       // TextureCoordinate
01701       const TextureCoordinate *_texCoord = 0;
01702       int nt = 0;
01703       if(texCoord)
01704       {
01705         if((_texCoord = dynamic_cast<const TextureCoordinate *>(texCoord.get())))
01706           nt = _texCoord->getPoint().size();
01707         else ARCHON_THROW1(InternalException,
01708                            "'" + texCoord->getType()->getName() +
01709                            "' is not supported yet");
01710         if(!nt) logger->log("IndexedFaceSet::preprocess: Empty TextureCoordinateNode");
01711       }
01712       else if(!texCoordIndex.empty()) logger->log("IndexedFaceSet::preprocess: Lacking TextureCoordinateNode");
01713 
01714       // If coordIndex is used to index into texCoord
01715       if(nc &&    colorIndex.empty() && colorPerVertex &&  nc<nv) nv = nc;
01716       if(nn &&   normalIndex.empty() && normalPerVertex && nn<nv) nv = nn;
01717       if(nt && texCoordIndex.empty() &&                    nt<nv) nv = nt;
01718 
01719       // Make room for new indices to boost performance
01720       int n = coordIndex.size()+1;
01721       preprocessedCoordIndex.reserve(n);
01722       if(nc && (!colorPerVertex || !colorIndex.empty()))
01723         preprocessedColorIndex.reserve(n);
01724       if(nn && (!normalPerVertex || !normalIndex.empty()))
01725         preprocessedNormalIndex.reserve(n);
01726       if(nt && !texCoordIndex.empty())
01727         preprocessedTexCoordIndex.reserve(n);
01728 
01729       bool wc = false; // Gate for warning about too short colorIndex
01730       bool wn = false; // Gate for warning about too short normalIndex
01731       bool wt = false; // Gate for warning about too short texCoordIndex
01732 
01733       int jv = 0; // previous valid vertex index
01734       int jc = 0; // previous valid color index
01735       int jn = 0; // previous valid normal index
01736       int jt = 0; // previous valid texture coordinate index
01737 
01738       int f=0; // Fase index
01739       int i0=0; // Start of polygon
01740       for(int i=0; static_cast<unsigned>(i0)<coordIndex.size(); ++i)
01741       {
01742         int j = static_cast<unsigned>(i)<coordIndex.size() ? coordIndex[i] : -1;
01743         if(j < 0)
01744         {
01745           if(j != -1) logger->log("IndexedFaceSet::preprocess: Bad end-of-face marker (coordIndex[i]=j)");
01746           if(i-i0 < 3)
01747           {
01748             logger->log("IndexedFaceSet::preprocess: Too few vertices in polygon (i-i0)");
01749             i0 = i+1;
01750             ++f;
01751             continue;
01752           }
01753 
01754           // Coordinate
01755           vector<int> poly;
01756           poly.reserve(i-i0);
01757           if(ccw) for(int k=i0; k<i; ++k)
01758           {
01759             j = coordIndex[k];
01760             if(j<nv) jv = j;
01761             else logger->log("IndexedFaceSet::preprocess: Index out of range (coordIndex[k]==j)");
01762             poly.push_back(jv);
01763           }
01764           else for(int k=i-1; k>=i0; --k)
01765           {
01766             j = coordIndex[k];
01767             if(j<nv) jv = j;
01768             else logger->log("IndexedFaceSet::preprocess: Index out of range (coordIndex[k]==j)");
01769             poly.push_back(jv);
01770           }
01771 
01772           // Compute normal - almost forgetting about degenrate and non-convex polygons
01773           {
01774             int j0 = poly[0];
01775             int j1 = poly[1];
01776             int j2 = poly[2];
01777             Vector3 normal = (*coords)[j1];
01778             normal -= (*coords)[j0];
01779             Vector3 v = (*coords)[j2];
01780             v -= (*coords)[j0];
01781             normal *= v;
01782             if(normal == Vector3::zero())
01783             {
01784               logger->log("IndexedFaceSet::preprocess: Polygon was not both simple and convex");
01785               i0 = i+1;
01786               ++f;
01787               continue;
01788             }
01789             normal.normalize();
01790             preprocessedNormal.push_back(normal); // We should start by counting the number of polygons, then reserve the necessary space
01791           }
01792 
01793           // DETECT AND DISCARD INVALID POLYGONS HERE
01794 
01795           // CONSIDER DECOMPOSITION OF NON-CONVEX POLYGONS HERE
01796           // Must result in 1 or more convex polygons that use the
01797           // original vertices and when combined they must correspond
01798           // with the original posibly non-convex polygon. Because the
01799           // vertices generally cannot be perfectly planar, we should
01800           // considder the decomposition with respect to the plane
01801           // spanned by the first 3 non-coincident vertices of the
01802           // original polygon (or something similar).
01803 
01804 
01805           preprocessedCoordIndex.insert(preprocessedCoordIndex.end(), poly.begin(), poly.end());
01806           preprocessedCoordIndex.push_back(-1);
01807 
01808           // Color
01809           if(nc)
01810           {
01811             if(!colorPerVertex)
01812             {
01813               if(colorIndex.empty())
01814               {
01815                 if(f<nc) jc = f;
01816                 else logger->log("IndexedFaceSet::preprocess: Too few elements in ColorNode");
01817               }
01818               else if(static_cast<unsigned>(f)<colorIndex.size())
01819               {
01820                 j = colorIndex[f];
01821                 if(j>=0 && j<nc) jc = j;
01822                 else logger->log("IndexedFaceSet::preprocess: Index out of range (colorIndex[f]==j)");
01823               }
01824               else logger->log("IndexedFaceSet::preprocess: Too few indices in colorIndex");
01825               for(int k=i0; k<i; ++k) preprocessedColorIndex.push_back(jc);
01826               preprocessedColorIndex.push_back(-1);
01827             }
01828             else if(!colorIndex.empty())
01829             {
01830               j = static_cast<unsigned>(i)<colorIndex.size() ? colorIndex[i] : -1;
01831               if(j != -1) logger->log("IndexedFaceSet::preprocess: Bad end-of-face marker (colorIndex[i]==j)");
01832               if(ccw) for(int k=i0; k<i; ++k)
01833               {
01834                 if(static_cast<unsigned>(k)<colorIndex.size())
01835                 {
01836                   j = colorIndex[k];
01837                   if(j>=0 && j<nc) jc = j;
01838                   else logger->log("IndexedFaceSet::preprocess: Index out of range (colorIndex[k]==j)");
01839                 }
01840                 else if(!wc)
01841                 {
01842                   logger->log("IndexedFaceSet::preprocess: Too few indices in colorIndex");
01843                   wc = true;
01844                 }
01845                 preprocessedColorIndex.push_back(jc);
01846               }
01847               else for(int k=i-1; k>=i0; --k)
01848               {
01849                 if(static_cast<unsigned>(k)<colorIndex.size())
01850                 {
01851                   j = colorIndex[k];
01852                   if(j>=0 && j<nc) jc = j;
01853                   else logger->log("IndexedFaceSet::preprocess: Index out of range (colorIndex[k]==j)");
01854                 }
01855                 else if(!wc)
01856                 {
01857                   logger->log("IndexedFaceSet::preprocess: Too few indices in colorIndex");
01858                   wc = true;
01859                 }
01860                 preprocessedColorIndex.push_back(jc);
01861               }
01862               preprocessedColorIndex.push_back(-1);
01863             }
01864           }
01865 
01866           // Normal
01867           if(nn)
01868           {
01869             if(!normalPerVertex)
01870             {
01871               if(normalIndex.empty())
01872               {
01873                 if(f<nn) jn = f;
01874                 else logger->log("IndexedFaceSet::preprocess: Too few elements in NormalNode");
01875               }
01876               else if(static_cast<unsigned>(f)<normalIndex.size())
01877               {
01878                 j = normalIndex[f];
01879                 if(j>=0 && j<nn) jn = j;
01880                 else logger->log("IndexedFaceSet::preprocess: Index out of range (normalIndex[f]==j)");
01881               }
01882               else logger->log("IndexedFaceSet::preprocess: Too few indices in normalIndex");
01883               for(int k=i0; k<i; ++k) preprocessedNormalIndex.push_back(jn);
01884               preprocessedNormalIndex.push_back(-1);
01885             }
01886             else if(!normalIndex.empty())
01887             {
01888               j = static_cast<unsigned>(i)<normalIndex.size() ? normalIndex[i] : -1;
01889               if(j != -1) logger->log("IndexedFaceSet::preprocess: Bad end-of-face marker (normalIndex[i]==j)");
01890               if(ccw) for(int k=i0; k<i; ++k)
01891               {
01892                 if(static_cast<unsigned>(k)<normalIndex.size())
01893                 {
01894                   j = normalIndex[k];
01895                   if(j>=0 && j<nn) jn = j;
01896                   else logger->log("IndexedFaceSet::preprocess: Index out of range (normalIndex[k]==j)");
01897                 }
01898                 else if(!wn)
01899                 {
01900                   logger->log("IndexedFaceSet::preprocess: Too few indices in normalIndex");
01901                   wn = true;
01902                 }
01903                 preprocessedNormalIndex.push_back(jn);
01904               }
01905               else for(int k=i-1; k>=i0; --k)
01906               {
01907                 if(static_cast<unsigned>(k)<normalIndex.size())
01908                 {
01909                   j = normalIndex[k];
01910                   if(j>=0 && j<nn) jn = j;
01911                   else logger->log("IndexedFaceSet::preprocess: Index out of range (normalIndex[k]==j)");
01912                 }
01913                 else if(!wn)
01914                 {
01915                   logger->log("IndexedFaceSet::preprocess: Too few indices in normalIndex");
01916                   wn = true;
01917                 }
01918                 preprocessedNormalIndex.push_back(jn);
01919               }
01920               preprocessedNormalIndex.push_back(-1);
01921             }
01922           }
01923 
01924           // TextureCoordinate
01925           if(nt && !texCoordIndex.empty())
01926           {
01927             j = static_cast<unsigned>(i)<texCoordIndex.size() ? texCoordIndex[i] : -1;
01928             if(j != -1) logger->log("IndexedFaceSet::preprocess: Bad end-of-face marker (texCoordIndex[i]==j)");
01929             if(ccw) for(int k=i0; k<i; ++k)
01930             {
01931               if(static_cast<unsigned>(k)<texCoordIndex.size())
01932               {
01933                 j = texCoordIndex[k];
01934                 if(j>=0 && j<nt) jt = j;
01935                 else logger->log("IndexedFaceSet::preprocess: Index out of range (texCoordIndex[k]==j)");
01936               }
01937               else if(!wt)
01938               {
01939                 logger->log("IndexedFaceSet::preprocess: Too few indices in texCoordIndex");
01940                 wt = true;
01941               }
01942               preprocessedTexCoordIndex.push_back(jt);
01943             }
01944             else for(int k=i-1; k>=i0; --k)
01945             {
01946               if(static_cast<unsigned>(k)<texCoordIndex.size())
01947               {
01948                 j = texCoordIndex[k];
01949                 if(j>=0 && j<nt) jt = j;
01950                 else logger->log("IndexedFaceSet::preprocess: Index out of range (texCoordIndex[k]==j)");
01951               }
01952               else if(!wt)
01953               {
01954                 logger->log("IndexedFaceSet::preprocess: Too few indices in texCoordIndex");
01955                 wt = true;
01956               }
01957               preprocessedTexCoordIndex.push_back(jt);
01958             }
01959             preprocessedTexCoordIndex.push_back(-1);
01960           }
01961 
01962           i0 = i+1;
01963           ++f;
01964         }
01965       }
01966 
01967       // Was it a total failure
01968       if(preprocessedCoordIndex.empty())
01969       {
01970         coords = 0;
01971         preprocessed = true;
01972         return;
01973       }
01974 
01975       if(nc)
01976         if(_rgbColor) rgbColors = &_rgbColor->getColor();
01977         else rgbaColors = &_rgbaColor->getColor();
01978       if(nn) normals    = &_normal->getNormal();
01979       if(nt) texCoords  = &_texCoord->getPoint();
01980 
01981       // Generate vertex normals based on crease angle
01982       if(!nn)
01983       {
01984         // Compute a map from vertex index to list of face indices
01985         vector<vector<int> > vertexFaces;
01986         vertexFaces.resize(coords->size());
01987         int f=0; // Fase index
01988         for(unsigned i=0; i<preprocessedCoordIndex.size(); ++i)
01989         {
01990           int j = preprocessedCoordIndex[i];
01991           if(j < 0) { ++f; continue; }
01992           vertexFaces[j].push_back(f);
01993         }
01994 
01995         double creaseDotLimit = creaseAngle >= M_PI ? -1 : cos(creaseAngle);
01996 
01997         f=0; // Fase index
01998         for(unsigned i=0; i<preprocessedCoordIndex.size(); ++i)
01999         {
02000           int j = preprocessedCoordIndex[i];
02001           if(j < 0)
02002           {
02003             preprocessedNormalIndex.push_back(-1);
02004             ++f;
02005             continue;
02006           }
02007 
02008           vector<int> &fv = vertexFaces[j];
02009           vector<int>::iterator fi = fv.begin();
02010           Vector3 n0 = preprocessedNormal[f];
02011           Vector3 n = n0; // Sum of normals
02012           bool c = false;
02013           while(fi != fv.end())
02014           {
02015             if(*fi != f)
02016             {
02017               Vector3 n1 = preprocessedNormal[*fi];
02018               if(dot(n0, n1) > creaseDotLimit)
02019               {
02020                 n += n1;
02021                 c = true;
02022               }
02023             }
02024 
02025             ++fi;
02026           }
02027 
02028           int k = f;
02029           if(c)
02030           {
02031             // TRY TO REUSE PREVIOUS IDENTICAL NORMALS HERE TO PREVENT UNNECCESSARILY HUGE LIST OF NORMALS
02032 
02033             n.normalize();
02034             k = preprocessedNormal.size();
02035             preprocessedNormal.push_back(n);
02036           }
02037           preprocessedNormalIndex.push_back(k);
02038         }
02039 
02040         normals = &preprocessedNormal;
02041       }
02042 
02043       // Compute the minimal AABB in case it is needed for atomatic
02044       // texture coordinate generation. It is needed if this
02045       // IndexedFaceSet is used in a context where the shape does not
02046       // specify the AABB. Whether it is, or not, cannot neccessarily
02047       // be determined at the time op preprocessing, so the only way
02048       // we can prevent processing of the AABB when it is not needed,
02049       // is by splitting it out into a seperate preprocesing step and
02050       // running it when the AABB is needed first time.
02051       if(!nt)
02052       {
02053         Box3 b(Vector3::zero());
02054         for(unsigned i=0; i<coords->size(); ++i)
02055         {
02056           Vector3 v = (*coords)[i];
02057           if(v[0] < b.lowerCorner[0]) b.lowerCorner[0] = v[0];
02058           if(v[0] > b.upperCorner[0]) b.upperCorner[0] = v[0];
02059           if(v[1] < b.lowerCorner[1]) b.lowerCorner[1] = v[1];
02060           if(v[1] > b.upperCorner[1]) b.upperCorner[1] = v[1];
02061           if(v[2] < b.lowerCorner[2]) b.lowerCorner[2] = v[2];
02062           if(v[2] > b.upperCorner[2]) b.upperCorner[2] = v[2];
02063         }
02064         preprocessedBboxCenter = b.getCenter();
02065         preprocessedBboxSize   = b.getSize();
02066       }
02067 
02068       preprocessed = true;
02069     }
02070 
02071     void IndexedFaceSet::render(bool texture,
02072                                 const Shape *shape,
02073                                 const RenderConfig *config)
02074     {
02075       if(!preprocessed) preprocess();
02076       if(!coords) return;
02077 
02078       glFrontFace(GL_CCW);
02079 
02080       if(solid)
02081       {
02082         glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, 0);
02083         glEnable(GL_CULL_FACE);
02084       }
02085       else
02086       {
02087         glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, 1);
02088         glDisable(GL_CULL_FACE);
02089       }
02090 
02091       if(rgbColors || rgbaColors) glEnable(GL_COLOR_MATERIAL);
02092       else glDisable(GL_COLOR_MATERIAL);
02093 
02094       // Setup projective texture
02095       if(texture && !texCoords)
02096       {
02097         Vector3 bboxCenter;
02098         Vector3 bboxSize = shape->getBboxSize();
02099         if(bboxSize[0] == -1)
02100         {
02101           bboxCenter = preprocessedBboxCenter;
02102           bboxSize   = preprocessedBboxSize;
02103         }
02104         else bboxCenter = shape->getBboxCenter();
02105 
02106         // Find out which spatial coordinates map to which
02107         // texture coordinates
02108         int i0, i1, i2;
02109         Math::sort3(bboxSize[0], bboxSize[1], bboxSize[2], i0, i1, i2);
02110 
02111         // First texture coordinate S
02112         {
02113           double c = 1/bboxSize[i0];
02114           GLdouble v[4] = { 0, 0, 0, (bboxSize[i0]/2-bboxCenter[i0])*c };
02115           v[i0] = c;
02116           glTexGendv(GL_S, GL_OBJECT_PLANE, v);
02117         }
02118 
02119         // Second texture coordinate T
02120         {
02121           double c = 1/bboxSize[i0];
02122           GLdouble v[4] = { 0, 0, 0, (bboxSize[i1]/2-bboxCenter[i1])*c };
02123           v[i1] = c;
02124           glTexGendv(GL_T, GL_OBJECT_PLANE, v);
02125         }
02126 
02127         glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
02128         glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
02129 
02130         glEnable(GL_TEXTURE_GEN_S);
02131         glEnable(GL_TEXTURE_GEN_T);
02132       }
02133 
02134       bool emptyColorIndex    = preprocessedColorIndex.empty();
02135       bool emptyNormalIndex   = preprocessedNormalIndex.empty();
02136       bool emptyTexCoordIndex = preprocessedTexCoordIndex.empty();
02137 
02138       for(unsigned i=0; i<preprocessedCoordIndex.size(); ++i)
02139       {
02140         glBegin(GL_POLYGON);
02141 
02142         for(;; ++i)
02143         {
02144           int j = preprocessedCoordIndex[i];
02145           if(j<0) break;
02146 
02147           // Color
02148           if(rgbColors)
02149           {
02150             Vector3 c = (*rgbColors)[emptyColorIndex ? j : preprocessedColorIndex[i]];
02151             glColor3d(c[0], c[1], c[2]);
02152           }
02153           else if(rgbaColors)
02154           {
02155             Vector4 c = (*rgbaColors)[emptyColorIndex ? j : preprocessedColorIndex[i]];
02156             glColor4d(c[0], c[1], c[2], c[3]);
02157           }
02158 
02159           // Normal
02160           {
02161             Vector3 n = (*normals)[emptyNormalIndex ? j : preprocessedNormalIndex[i]];
02162             glNormal3d(n[0], n[1], n[2]);
02163           }
02164 
02165           // Texture
02166           if(texCoords)
02167           {
02168             Vector2 t = (*texCoords)[emptyTexCoordIndex ? j : preprocessedTexCoordIndex[i]];
02169             glTexCoord2d(t[0], t[1]);
02170           }
02171 
02172           // Coordinate
02173           {
02174             Vector3 v = (*coords)[j];
02175             glVertex3d(v[0], v[1], v[2]);
02176           }
02177         }
02178 
02179         glEnd();
02180       }
02181 
02182       // Disable projective texture
02183       if(texture && !texCoords)
02184       {
02185         glDisable(GL_TEXTURE_GEN_S);
02186         glDisable(GL_TEXTURE_GEN_T);
02187       }
02188 
02189       if(config->showNormals)
02190       {
02191         vector<Vector3> n;
02192         for(unsigned i=0; i<preprocessedCoordIndex.size(); ++i)
02193         {
02194           int j = preprocessedCoordIndex[i];
02195           if(j<0) continue;
02196           n.push_back((*coords)[j]);
02197           n.push_back((*normals)[emptyNormalIndex ? j : preprocessedNormalIndex[i]]);
02198         }
02199         renderNormals(n, config);
02200       }
02201     }
02202 
02207     void ElevationGrid::render(bool texture,
02208                                const Shape *shape,
02209                                const RenderConfig *config)
02210     {
02211       const unsigned n = xDimension * zDimension;
02212       if(height.size() < n) return;
02213 
02214       const int iMax = xDimension - 1;
02215       const int jMax = zDimension - 1;
02216       const unsigned m = iMax * jMax;
02217 
02218       const Color *rgb =
02219         dynamic_cast<const Color *>(color.get());
02220       const ColorRGBA *rgba =
02221         dynamic_cast<const ColorRGBA *>(color.get());
02222       const TextureCoordinate *_texCoord = 
02223         dynamic_cast<const TextureCoordinate *>(texCoord.get());
02224       const Normal *_normal =
02225         dynamic_cast<const Normal *>(normal.get());
02226 
02227       if(!rgb && !rgba && color)
02228         ARCHON_THROW1(InternalException,
02229                       "'" + color->getType()->getName() +
02230                       "' is not supported yet");
02231       if(!_texCoord && texCoord)
02232         ARCHON_THROW1(InternalException,
02233                       "'" + texCoord->getType()->getName() +
02234                       "' is not supported yet");
02235       if(!_normal && normal)
02236         ARCHON_THROW1(InternalException,
02237                       "'" + normal->getType()->getName() +
02238                       "' is not supported yet");
02239 
02240       if(rgb  && rgb->getColor().size()  < (colorPerVertex ? n : m) ||
02241          rgba && rgba->getColor().size() < (colorPerVertex ? n : m))
02242       {
02243         rgb = 0;
02244         rgba = 0;
02245       }
02246 
02247       if(_texCoord && _texCoord->getPoint().size() < n) _texCoord = 0;
02248       if(_normal && _normal->getNormal().size() < (normalPerVertex ? n : m)) _normal = 0;
02249 
02250       glFrontFace(ccw ? GL_CCW : GL_CW);
02251 
02252       if(solid)
02253       {
02254         glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, 0);
02255         glEnable(GL_CULL_FACE);
02256       }
02257       else
02258       {
02259         glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, 1);
02260         glDisable(GL_CULL_FACE);
02261       }
02262 
02263       if(rgb || rgba) glEnable(GL_COLOR_MATERIAL);
02264       else glDisable(GL_COLOR_MATERIAL);
02265 
02266 
02267       /*
02268        * Preperation for automatic normal computation
02269        */
02270       double creaseDotLimit; // Limit on normal dot-product alt. to limit on angle
02271       vector<Vector3> autoNormals(m);
02272       double prevZ = 0;
02273       if(!_normal)
02274       {
02275         creaseDotLimit = creaseAngle >= M_PI ? -1 : cos(creaseAngle);
02276         const bool cw = !ccw;
02277         for(int j=1; j<zDimension; ++j)
02278         {
02279           const double z = zSpacing * j;
02280 
02281           double prevX = 0;
02282           for(int i=1; i<xDimension; ++i)
02283           {
02284             const double x = xSpacing * i;
02285 
02286             Vector3 n(prevX, height[(i-1) + (j-1) * xDimension], prevZ);
02287             n -= Vector3(x, height[i + j * xDimension], z);
02288             Vector3 v(prevX, height[(i-1) + j * xDimension], z);
02289             v -= Vector3(x, height[i + (j-1) * xDimension], prevZ);
02290             n *= v;
02291             if(cw) n.negate();
02292             n.normalize();
02293             autoNormals[(i-1) + (j-1) * iMax] = n;
02294 
02295             prevX = x;
02296           }
02297 
02298           prevZ = z;
02299         }
02300 
02301         prevZ = 0;
02302       }
02303 
02304       double prevT = 0;
02305 
02306       vector<Vector3> normals;
02307       const bool showNormals = config->showNormals;
02308 
02309       glBegin(GL_QUADS);
02310 
02311       for(int j=1; j<zDimension; ++j)
02312       {
02313         const double z = zSpacing * j;
02314         const double t = j/double(jMax);
02315 
02316         double prevX = 0;
02317         double prevS = 0;
02318 
02319         for(int i=1; i<xDimension; ++i)
02320         {
02321           const double x = xSpacing * i;
02322           const double s = i/double(iMax);
02323 
02324           int faseIndex = (i-1) + (j-1) * iMax;
02325 
02326           Vector3 n;
02327 
02328           if(rgb && !colorPerVertex)
02329           {
02330             const Vector3 &c = rgb->getColor()[faseIndex];
02331             glColor3d(c[0], c[1], c[2]);
02332           }
02333           if(rgba && !colorPerVertex)
02334           {
02335             const Vector4 &c = rgba->getColor()[faseIndex];
02336             glColor4d(c[0], c[1], c[2], c[3]);
02337           }
02338           if(_normal && !normalPerVertex)
02339           {
02340             n = _normal->getNormal()[faseIndex];
02341             glNormal3d(n[0], n[1], n[2]);
02342           }
02343 
02344 
02345           // First vertex (NE)
02346           {
02347             int vertexIndex = i + (j-1) * xDimension;
02348 
02349             if(rgb && colorPerVertex)
02350             {
02351               const Vector3 &c = rgb->getColor()[vertexIndex];
02352               glColor3d(c[0], c[1], c[2]);
02353             }
02354             if(rgba && colorPerVertex)
02355             {
02356               const Vector4 &c = rgba->getColor()[vertexIndex];
02357               glColor4d(c[0], c[1], c[2], c[3]);
02358             }
02359             if(_normal && normalPerVertex)
02360             {
02361               n = _normal->getNormal()[vertexIndex];
02362               glNormal3d(n[0], n[1], n[2]);
02363             }
02364             else if(!_normal)
02365             {
02366               // Auto generate normal
02367 
02368               Vector3 n0 = autoNormals[faseIndex];
02369               n = n0;
02370               int m = 1;
02371               if(i<iMax)
02372               {
02373                 Vector3 n1 = autoNormals[faseIndex + 1];
02374                 if(dot(n0, n1) > creaseDotLimit) { n += n1; ++m; }
02375               }
02376               if(j>1)
02377               {
02378                 Vector3 n1 = autoNormals[faseIndex - iMax];
02379                 if(dot(n0, n1) > creaseDotLimit) { n += n1; ++m; }
02380               }
02381               if(i<iMax && j>1)
02382               {
02383                 Vector3 n1 = autoNormals[faseIndex - iMax + 1];
02384                 if(dot(n0, n1) > creaseDotLimit) { n += n1; ++m; }
02385               }
02386               n /= m;
02387 
02388               glNormal3d(n[0], n[1], n[2]);
02389             }
02390 
02391             if(texture)
02392             {
02393               if(texCoord)
02394               {
02395                 const Vector2 &v = _texCoord->getPoint()[vertexIndex];
02396                 glTexCoord2d(v[0], v[1]);
02397               }
02398               else glTexCoord2d(s, prevT);
02399             }
02400 
02401             glVertex3d(x, height[vertexIndex], prevZ);
02402             if(showNormals)
02403             {
02404               normals.push_back(Vector3(x, height[vertexIndex], prevZ));
02405               normals.push_back(n);
02406             }
02407           }
02408 
02409           // Second vertex (NW)
02410           {
02411             int vertexIndex = (i-1) + (j-1) * xDimension;
02412 
02413             if(rgb && colorPerVertex)
02414             {
02415               const Vector3 &c = rgb->getColor()[vertexIndex];
02416               glColor3d(c[0], c[1], c[2]);
02417             }
02418             if(rgba && colorPerVertex)
02419             {
02420               const Vector4 &c = rgba->getColor()[vertexIndex];
02421               glColor4d(c[0], c[1], c[2], c[3]);
02422             }
02423             if(_normal && normalPerVertex)
02424             {
02425               n = _normal->getNormal()[vertexIndex];
02426               glNormal3d(n[0], n[1], n[2]);
02427             }
02428             else if(!_normal)
02429             {
02430               // Auto generate normal
02431 
02432               Vector3 n0 = autoNormals[faseIndex];
02433               n = n0;
02434               int m = 1;
02435               if(i>1)
02436               {
02437                 Vector3 n1 = autoNormals[faseIndex - 1];
02438                 if(dot(n0, n1) > creaseDotLimit) { n += n1; ++m; }
02439               }
02440               if(j>1)
02441               {
02442                 Vector3 n1 = autoNormals[faseIndex - iMax];
02443                 if(dot(n0, n1) > creaseDotLimit) { n += n1; ++m; }
02444               }
02445               if(i>1 && j>1)
02446               {
02447                 Vector3 n1 = autoNormals[faseIndex - iMax - 1];
02448                 if(dot(n0, n1) > creaseDotLimit) { n += n1; ++m; }
02449               }
02450               n /= m;
02451 
02452               glNormal3d(n[0], n[1], n[2]);
02453             }
02454 
02455             if(texture)
02456             {
02457               if(texCoord)
02458               {
02459                 const Vector2 &v = _texCoord->getPoint()[vertexIndex];
02460                 glTexCoord2d(v[0], v[1]);
02461               }
02462               else glTexCoord2d(prevS, prevT);
02463             }
02464 
02465             glVertex3d(prevX, height[vertexIndex], prevZ);
02466             if(showNormals)
02467             {
02468               normals.push_back(Vector3(prevX, height[vertexIndex], prevZ));
02469               normals.push_back(n);
02470             }
02471           }
02472 
02473           // Third vertex (SW)
02474           {
02475             int vertexIndex = (i-1) + j * xDimension;
02476 
02477             if(rgb && colorPerVertex)
02478             {
02479               const Vector3 &c = rgb->getColor()[vertexIndex];
02480               glColor3d(c[0], c[1], c[2]);
02481             }
02482             if(rgba && colorPerVertex)
02483             {
02484               const Vector4 &c = rgba->getColor()[vertexIndex];
02485               glColor4d(c[0], c[1], c[2], c[3]);
02486             }
02487             if(_normal && normalPerVertex)
02488             {
02489               n = _normal->getNormal()[vertexIndex];
02490               glNormal3d(n[0], n[1], n[2]);
02491             }
02492             else if(!_normal)
02493             {
02494               // Auto generate normal
02495 
02496               Vector3 n0 = autoNormals[faseIndex];
02497               n = n0;
02498               int m = 1;
02499               if(i>1)
02500               {
02501                 Vector3 n1 = autoNormals[faseIndex - 1];
02502                 if(dot(n0, n1) > creaseDotLimit) { n += n1; ++m; }
02503               }
02504               if(j<jMax)
02505               {
02506                 Vector3 n1 = autoNormals[faseIndex + iMax];
02507                 if(dot(n0, n1) > creaseDotLimit) { n += n1; ++m; }
02508               }
02509               if(i>1 && j<jMax)
02510               {
02511                 Vector3 n1 = autoNormals[faseIndex + iMax - 1];
02512                 if(dot(n0, n1) > creaseDotLimit) { n += n1; ++m; }
02513               }
02514               n /= m;
02515 
02516               glNormal3d(n[0], n[1], n[2]);
02517             }
02518 
02519             if(texture)
02520             {
02521               if(texCoord)
02522               {
02523                 const Vector2 &v = _texCoord->getPoint()[vertexIndex];
02524                 glTexCoord2d(v[0], v[1]);
02525               }
02526               else glTexCoord2d(prevS, t);
02527             }
02528 
02529             glVertex3d(prevX, height[vertexIndex], z);
02530             if(showNormals)
02531             {
02532               normals.push_back(Vector3(prevX, height[vertexIndex], z));
02533               normals.push_back(n);
02534             }
02535           }
02536 
02537           // Fourth vertex (SE)
02538           {
02539             int vertexIndex = i + j * xDimension;
02540 
02541             if(rgb && colorPerVertex)
02542             {
02543               const Vector3 &c = rgb->getColor()[vertexIndex];
02544               glColor3d(c[0], c[1], c[2]);
02545             }
02546             if(rgba && colorPerVertex)
02547             {
02548               const Vector4 &c = rgba->getColor()[vertexIndex];
02549               glColor4d(c[0], c[1], c[2], c[3]);
02550             }
02551             if(_normal && normalPerVertex)
02552             {
02553               n = _normal->getNormal()[vertexIndex];
02554               glNormal3d(n[0], n[1], n[2]);
02555             }
02556             else if(!_normal)
02557             {
02558               // Auto generate normal
02559 
02560               Vector3 n0 = autoNormals[faseIndex];
02561               n = n0;
02562               int m = 1;
02563               if(i<iMax)
02564               {
02565                 Vector3 n1 = autoNormals[faseIndex + 1];
02566                 if(dot(n0, n1) > creaseDotLimit) { n += n1; ++m; }
02567               }
02568               if(j<jMax)
02569               {
02570                 Vector3 n1 = autoNormals[faseIndex + iMax];
02571                 if(dot(n0, n1) > creaseDotLimit) { n += n1; ++m; }
02572               }
02573               if(i<iMax && j<jMax)
02574               {
02575                 Vector3 n1 = autoNormals[faseIndex + iMax + 1];
02576                 if(dot(n0, n1) > creaseDotLimit) { n += n1; ++m; }
02577               }
02578               n /= m;
02579 
02580               glNormal3d(n[0], n[1], n[2]);
02581             }
02582 
02583             if(texture)
02584             {
02585               if(texCoord)
02586               {
02587                 const Vector2 &v = _texCoord->getPoint()[vertexIndex];
02588                 glTexCoord2d(v[0], v[1]);
02589               }
02590               else glTexCoord2d(s, t);
02591             }
02592 
02593             glVertex3d(x, height[vertexIndex], z);
02594             if(showNormals)
02595             {
02596               normals.push_back(Vector3(x, height[vertexIndex], z));
02597               normals.push_back(n);
02598             }
02599           }
02600 
02601           prevX = x;
02602           prevS = s;
02603         }
02604 
02605         prevZ = z;
02606         prevT = t;
02607       }
02608 
02609       glEnd();
02610 
02611       if(showNormals) renderNormals(normals, config);
02612     }
02613   }
02614 }

Generated on Sun Jul 30 22:55:43 2006 for Archon by  doxygen 1.4.4