#include "Geometry.h" #include "glInterface.h" #include "stdio.h" #include "teapot.h" #include #define NO_LIST -1 #define STRIP_END -1 int Geometry::num_torus_indices; int Geometry::num_torus_vertices; int Geometry::num_torus_normals; const int Geometry::torus_precision = 24; const int Geometry::sphere_precision = 24; float *Geometry::torus_vertices; float *Geometry::torus_normals; int *Geometry::torus_indices; // choose size so the glut-rendered sphere is approximately // as big as the other objects const float Geometry::sphere_radius = 1.0 / 9.0f; const float Geometry::torus_inner_radius = 0.05; const float Geometry::torus_outer_radius = 0.07; int Geometry::sDisplayList[NUM_OBJECTS]; bool Geometry::sIsInitialised = Init(); Geometry::Geometry(): mXRotation(0), mYRotation(0), mZRotation(0), mScale(1.0), mObjectType(TEAPOT) { copyVector3Values(mTranslation, 0, 0, 0); SetAmbientColor(0.1745, 0.01175, 0.01175); SetDiffuseColor(0.61424, 0.04136, 0.04136); SetSpecularColor(0.727811, 0.626959, 0.626959); CalcBoundingVolume(); CalcTransform(); GenerateList(); } Geometry::Geometry(Vector3 translation, float xRot, float yRot, float zRot, float scale, int objectType): mXRotation(xRot), mYRotation(yRot), mZRotation(zRot), mScale(scale), mObjectType(objectType) { copyVector3(mTranslation, translation); SetAmbientColor(0.1745, 0.01175, 0.01175); SetDiffuseColor(0.61424, 0.04136, 0.04136); SetSpecularColor(0.727811, 0.626959, 0.626959); CalcBoundingVolume(); CalcTransform(); GenerateList(); } void Geometry::ResetLists() { for(int i = 0; i < NUM_OBJECTS; i++) { if(sDisplayList[i] == NO_LIST) glDeleteLists(sDisplayList[i], 1); sDisplayList[i] = NO_LIST; } } void Geometry::CleanUp() { ResetLists(); delete [] torus_vertices; delete [] torus_normals; delete [] torus_indices; } bool Geometry::Init() { for(int i=0; i < NUM_OBJECTS; i++) sDisplayList[i] = NO_LIST; // parameters chosen so torus is approximately as big as teapot CreateTorus(torus_inner_radius, torus_outer_radius, torus_precision); return true; } void Geometry::GenerateList() { if(sDisplayList[mObjectType] == NO_LIST) { sDisplayList[mObjectType] = glGenLists(1); glNewList(sDisplayList[mObjectType], GL_COMPILE); switch(mObjectType) { case TEAPOT: RenderTeapot(); break; case TORUS: RenderTorus(); break; case SPHERE: RenderSphere(); break; default: break; } glEndList(); } } void Geometry::Render() { glMaterialfv(GL_FRONT, GL_AMBIENT, mAmbientColor); glMaterialfv(GL_FRONT, GL_DIFFUSE, mDiffuseColor); glMaterialfv(GL_FRONT, GL_SPECULAR, mSpecularColor); glPushMatrix(); Transform(); glCallList(sDisplayList[mObjectType]); glPopMatrix(); } //! sets rotations around the three axis: executed in the order specified here void Geometry::SetRotations(float xRot, float yRot, float zRot) { mXRotation = xRot; mYRotation = yRot; mZRotation = zRot; CalcBoundingVolume(); CalcTransform(); } void Geometry::SetTranslation(Vector3 translation) { copyVector3(mTranslation, translation); CalcBoundingVolume(); CalcTransform(); } void Geometry::SetScale(float scale) { mScale = scale; CalcTransform(); CalcBoundingVolume(); } void Geometry::SetAmbientColor(float ambientR, float ambientG, float ambientB) { mAmbientColor[0] = ambientR; mAmbientColor[1] = ambientG; mAmbientColor[2] = ambientB; } void Geometry::SetDiffuseColor(float diffuseR, float diffuseG, float diffuseB) { mDiffuseColor[0] = diffuseR; mDiffuseColor[1] = diffuseG; mDiffuseColor[2] = diffuseB; } void Geometry::SetSpecularColor(float specularR, float specularG, float specularB) { mSpecularColor[0] = specularR; mSpecularColor[1] = specularG; mSpecularColor[2] = specularB; } float Geometry::GetScale() { return mScale; } void Geometry::GetTranslation(Vector3 translation) { copyVector3(translation, mTranslation); } void Geometry::GetRotations(float &xRot, float &yRot, float &zRot) { xRot = mXRotation; yRot = mYRotation; zRot = mZRotation; } const AABox &Geometry::GetBoundingVolume() { return mBoundingBox; } void Geometry::SetLastVisited(int lastVisited) { mLastVisited = lastVisited; } int Geometry::GetLastVisited() { return mLastVisited; } void Geometry::SetObjectType(int type) { mObjectType = type; GenerateList(); } void Geometry::RenderTeapot() { int i = 0; while(i < num_teapot_indices) { glBegin(GL_TRIANGLE_STRIP); while(teapot_indices[i] != STRIP_END) { int index = teapot_indices[i] * 3; glNormal3fv(teapot_normals + index); glVertex3fv(teapot_vertices + index); i++; } glEnd(); i++; // skip strip end flag } } void Geometry::CalcBoundingVolume() { switch(mObjectType) { case TORUS: CalcBoundingVolume(torus_vertices, num_torus_vertices); break; case SPHERE: CalcSphereBoundingVolume(); break; case TEAPOT: CalcBoundingVolume(teapot_vertices, num_teapot_vertices); break; default: break; } } void Geometry::CalcBoundingVolume(float *vertices, const int num_vertices) { Vector3 *rotatedPoints = new Vector3[num_vertices]; for(int i = 0; i < num_vertices; i++) { copyVector3Values(rotatedPoints[i], vertices[i * 3], vertices[i * 3 + 1], vertices[i * 3 + 2]); rotateVectorZ(rotatedPoints[i], mZRotation * PI_180); rotateVectorY(rotatedPoints[i], mYRotation * PI_180); rotateVectorX(rotatedPoints[i], mXRotation * PI_180); } calcCubicHull(mBoundingBox.min, mBoundingBox.max, rotatedPoints, num_vertices); for(int i=0; i< 3; i++) { mBoundingBox.min[i] *= mScale; mBoundingBox.max[i] *= mScale; } addVector3(mBoundingBox.min, mTranslation, mBoundingBox.min); addVector3(mBoundingBox.max, mTranslation, mBoundingBox.max); delete [] rotatedPoints; } void Geometry::CalcSphereBoundingVolume() { float len = mScale * sphere_radius; Vector3 size = {len, len, len}; diffVector3(mBoundingBox.min, mTranslation, size); addVector3(mBoundingBox.max, mTranslation, size); } void Geometry::RenderTorus() { glVertexPointer(3, GL_FLOAT, sizeof(float), torus_vertices); glEnableClientState(GL_VERTEX_ARRAY); glNormalPointer(GL_FLOAT, sizeof(float), torus_normals); glEnableClientState(GL_NORMAL_ARRAY); glDrawElements(GL_TRIANGLES, num_torus_indices, GL_UNSIGNED_INT, torus_indices); glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_NORMAL_ARRAY); } /* creates a torus with specified radii, with number of rings and ring subdivision = precision. */ void Geometry::CreateTorus(float innerRadius, float outerRadius, int precision) { num_torus_vertices = num_torus_normals = (precision + 1) * (precision + 1); num_torus_indices = 2 * precision * precision * 3; torus_vertices = new float[num_torus_vertices * 3]; torus_normals = new float[num_torus_normals * 3]; torus_indices = new int[num_torus_indices]; for(int i=0; i