// // Vrml 97 library // Copyright (C) 1998 Chris Morley // // %W% %G% // Viewer.cpp // Abstract base class for display of VRML models // #include "config.h" #include "Viewer.h" #include "MathUtils.h" #include "VrmlScene.h" // Empty destructor for derived classes to call. Viewer::~Viewer() {} // Build a cylinder object. It might be smarter to do just one, and reference // it with scaling (but the world creator could just as easily do that with // DEF/USE ...). void Viewer::computeCylinder(double height, double radius, int numFacets, float c[][3], float tc[][3], int faces[]) { double angle, x, y; int i, polyIndex; // Compute coordinates, texture coordinates: for (i = 0; i < numFacets; ++i) { angle = i * 2 * M_PI / numFacets; x = cos(angle); y = sin(angle); c[i][0] = (float)(radius * x); c[i][1] = (float)(0.5 * height); c[i][2] = (float)(radius * y); c[numFacets+i][0] = (float)(radius * x); c[numFacets+i][1] = (float)(-0.5 * height); c[numFacets+i][2] = (float)(radius * y); if (tc) { tc[i][0] = ((float) i) / numFacets; tc[i][1] = 0.0; tc[i][2] = 0.0; tc[numFacets+i][0] = ((float) i) / numFacets; tc[numFacets+i][1] = 1.0; tc[numFacets+i][2] = 0.0; } } // And compute indices: for (i = 0; i < numFacets; ++i) { polyIndex = 5*i; faces[polyIndex + 0] = i; faces[polyIndex + 1] = (i+1) % numFacets; faces[polyIndex + 2] = (i+1) % numFacets + numFacets; faces[polyIndex + 3] = i + numFacets; faces[polyIndex + 4] = -1; } } // Build an extrusion. void Viewer::computeExtrusion(int nOrientation, float *orientation, int nScale, float *scale, int nCrossSection, float *crossSection, int nSpine, float *spine, float *c, // OUT: coordinates float *tc, // OUT: texture coords int *faces) // OUT: face list { int i, j, ci; // Xscp, Yscp, Zscp- columns of xform matrix to align cross section // with spine segments. float Xscp[3] = { 1.0, 0.0, 0.0}; float Yscp[3] = { 0.0, 1.0, 0.0}; float Zscp[3] = { 0.0, 0.0, 1.0}; float lastZ[3]; // Is the spine a closed curve (last pt == first pt)? bool spineClosed = (FPZERO(spine[ 3*(nSpine-1)+0 ] - spine[0]) && FPZERO(spine[ 3*(nSpine-1)+1 ] - spine[1]) && FPZERO(spine[ 3*(nSpine-1)+2 ] - spine[2])); // Is the spine a straight line? bool spineStraight = true; for (i = 1; i < nSpine-1; ++i) { float v1[3], v2[3]; v1[0] = spine[3*(i-1)+0] - spine[3*(i)+0]; v1[1] = spine[3*(i-1)+1] - spine[3*(i)+1]; v1[2] = spine[3*(i-1)+2] - spine[3*(i)+2]; v2[0] = spine[3*(i+1)+0] - spine[3*(i)+0]; v2[1] = spine[3*(i+1)+1] - spine[3*(i)+1]; v2[2] = spine[3*(i+1)+2] - spine[3*(i)+2]; Vcross(v1, v2, v1); if (Vlength(v1) != 0.0) { spineStraight = false; Vnorm( v1 ); Vset( lastZ, v1 ); break; } } // If the spine is a straight line, compute a constant SCP xform if (spineStraight) { float V1[3] = { 0.0, 1.0, 0.0}, V2[3], V3[3]; V2[0] = spine[3*(nSpine-1)+0] - spine[0]; V2[1] = spine[3*(nSpine-1)+1] - spine[1]; V2[2] = spine[3*(nSpine-1)+2] - spine[2]; Vcross( V3, V2, V1 ); float len = (float)Vlength(V3); if (len != 0.0) // Not aligned with Y axis { Vscale(V3, 1.0f/len); float orient[4]; // Axis/angle Vset(orient, V3); orient[3] = acos(Vdot(V1,V2)); double scp[4][4]; // xform matrix Mrotation( scp, orient ); for (int k=0; k<3; ++k) { Xscp[k] = (float)scp[0][k]; Yscp[k] = (float)scp[1][k]; Zscp[k] = (float)scp[2][k]; } } } // Orientation matrix double om[4][4]; if (nOrientation == 1 && ! FPZERO(orientation[3]) ) Mrotation( om, orientation ); // Compute coordinates, texture coordinates: for (i = 0, ci = 0; i < nSpine; ++i, ci+=nCrossSection) { // Scale cross section for (j = 0; j < nCrossSection; ++j) { c[3*(ci+j)+0] = scale[0] * crossSection[ 2*j ]; c[3*(ci+j)+1] = 0.0; c[3*(ci+j)+2] = scale[1] * crossSection[ 2*j+1 ]; } // Compute Spine-aligned Cross-section Plane (SCP) if (! spineStraight) { float S1[3], S2[3]; // Spine vectors [i,i-1] and [i,i+1] int yi1, yi2, si1, s1i2, s2i2; if (spineClosed && (i == 0 || i == nSpine-1)) { yi1 = 3*(nSpine-2); yi2 = 3; si1 = 0; s1i2 = 3*(nSpine-2); s2i2 = 3; } else if (i == 0) { yi1 = 0; yi2 = 3; si1 = 3; s1i2 = 0; s2i2 = 6; } else if (i == nSpine-1) { yi1 = 3*(nSpine-2); yi2 = 3*(nSpine-1); si1 = 3*(nSpine-2); s1i2 = 3*(nSpine-3); s2i2 = 3*(nSpine-1); } else { yi1 = 3*(i-1); yi2 = 3*(i+1); si1 = 3*i; s1i2 = 3*(i-1); s2i2 = 3*(i+1); } Vdiff( Yscp, &spine[yi2], &spine[yi1] ); Vdiff( S1, &spine[s1i2], &spine[si1] ); Vdiff( S2, &spine[s2i2], &spine[si1] ); Vnorm( Yscp ); Vset(lastZ, Zscp); // Save last Zscp Vcross( Zscp, S2, S1 ); float VlenZ = (float)Vlength(Zscp); if ( VlenZ == 0.0 ) Vset(Zscp, lastZ); else Vscale( Zscp, 1.0f/VlenZ ); if ((i > 0) && (Vdot( Zscp, lastZ ) < 0.0)) Vscale( Zscp, -1.0 ); Vcross( Xscp, Yscp, Zscp ); } // Rotate cross section into SCP for (j = 0; j < nCrossSection; ++j) { float cx, cy, cz; cx = c[3*(ci+j)+0]*Xscp[0]+c[3*(ci+j)+1]*Yscp[0]+c[3*(ci+j)+2]*Zscp[0]; cy = c[3*(ci+j)+0]*Xscp[1]+c[3*(ci+j)+1]*Yscp[1]+c[3*(ci+j)+2]*Zscp[1]; cz = c[3*(ci+j)+0]*Xscp[2]+c[3*(ci+j)+1]*Yscp[2]+c[3*(ci+j)+2]*Zscp[2]; c[3*(ci+j)+0] = cx; c[3*(ci+j)+1] = cy; c[3*(ci+j)+2] = cz; } // Apply orientation if (! FPZERO(orientation[3]) ) { if (nOrientation > 1) Mrotation( om, orientation ); for (j = 0; j < nCrossSection; ++j) { float cx, cy, cz; cx = (float)(c[3*(ci+j)+0]*om[0][0]+c[3*(ci+j)+1]*om[1][0]+c[3*(ci+j)+2]*om[2][0]); cy = (float)(c[3*(ci+j)+0]*om[0][1]+c[3*(ci+j)+1]*om[1][1]+c[3*(ci+j)+2]*om[2][1]); cz = (float)(c[3*(ci+j)+0]*om[0][2]+c[3*(ci+j)+1]*om[1][2]+c[3*(ci+j)+2]*om[2][2]); c[3*(ci+j)+0] = cx; c[3*(ci+j)+1] = cy; c[3*(ci+j)+2] = cz; } } // Translate cross section for (j = 0; j < nCrossSection; ++j) { c[3*(ci+j)+0] += spine[3*i+0]; c[3*(ci+j)+1] += spine[3*i+1]; c[3*(ci+j)+2] += spine[3*i+2]; // Texture coords tc[3*(ci+j)+0] = ((float) j) / (nCrossSection-1); tc[3*(ci+j)+1] = 1.0f - ((float) i) / (nSpine-1); tc[3*(ci+j)+2] = 0.0f; } if (nScale > 1) scale += 2; if (nOrientation > 1) orientation += 4; } // And compute face indices: if (faces) { int polyIndex = 0; for (i = 0, ci = 0; i < nSpine-1; ++i, ci+=nCrossSection) { for (j = 0; j < nCrossSection-1; ++j) { faces[polyIndex + 0] = ci+j; faces[polyIndex + 1] = ci+j+1; faces[polyIndex + 2] = ci+j+1 + nCrossSection; faces[polyIndex + 3] = ci+j + nCrossSection; faces[polyIndex + 4] = -1; polyIndex += 5; } } } } void Viewer::computeSphere(double radius, int numLatLong, float c[][3], float tc[][3], int *faces) { double r, angle, x, y, z; int i, j, polyIndex; // Compute coordinates, texture coordinates: for (i = 0; i < numLatLong; ++i) { /*y = 2.0 * ( ((double)i) / (numLatLong-1) ) - 1.0;*/ angle = ( i * M_PI / (numLatLong-1) ) - M_PI_2; y = sin( angle ); r = sqrt( 1.0 - y*y ); for (j = 0; j < numLatLong; ++j) { angle = 2 * M_PI * ((double)j) / numLatLong; x = - sin(angle)*r; z = - cos(angle)*r; c[i*numLatLong+j][0] = (float)(radius * x); c[i*numLatLong+j][1] = (float)(radius * y); c[i*numLatLong+j][2] = (float)(radius * z); if (tc) { tc[i*numLatLong+j][0] = ((float) j)/numLatLong; tc[i*numLatLong+j][1] = ((float) i)/(numLatLong-1); tc[i*numLatLong+j][2] = 0.0; } } } // And compute indices: if (faces) for (i = 0; i < numLatLong-1; ++i) { for (j = 0; j < numLatLong; ++j) { polyIndex = 5*(i*numLatLong+j); faces[polyIndex + 0] = i*numLatLong+j; faces[polyIndex + 1] = i*numLatLong+(j+1)%numLatLong; faces[polyIndex + 2] = (i+1)*numLatLong+(j+1)%numLatLong; faces[polyIndex + 3] = (i+1)*numLatLong+j; faces[polyIndex + 4] = -1; // quad } } } // // Compute a target and up vector from position/orientation/distance. // void Viewer::computeView(float position[3], float orientation[3], float distance, float target[3], float up[3]) { // Graphics Gems, p 466. Convert between axis/angle and rotation matrix float len = (float)sqrt( orientation[0]*orientation[0] + orientation[1]*orientation[1] + orientation[2]*orientation[2] ); if (len > 0.0f) { orientation[0] /= len; orientation[1] /= len; orientation[2] /= len; } float s = (float)sin(orientation[3]); float c = (float)cos(orientation[3]); float t = 1.0f - c; // Transform [0,0,1] by the orientation to determine sight line target[0] = t * orientation[0] * orientation[2] + s * orientation[1]; target[1] = t * orientation[1] * orientation[2] - s * orientation[0]; target[2] = t * orientation[2] * orientation[2] + c; // Move along that vector the specified distance away from position[] target[0] = -distance*target[0] + position[0]; target[1] = -distance*target[1] + position[1]; target[2] = -distance*target[2] + position[2]; // Transform [0,1,0] by the orientation to determine up vector up[0] = t * orientation[0] * orientation[1] - s * orientation[2]; up[1] = t * orientation[1] * orientation[1] + c; up[2] = t * orientation[1] * orientation[2] + s * orientation[0]; } void Viewer::setColor(float , float , float , float ) {}