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