#include "../csc321.h" #include "Shape.h" #include Shape::~Shape() { // destroy your data here } void Shape::draw() { // render the shape using OpenGL glBegin(GL_TRIANGLES); if (vertices.size() == normals.size()) { // one normal per vertex for (unsigned int i = 0; i < vertices.size(); i += 3) { glNormal3dv(&normals[i][0]); glVertex3dv(&vertices[i][0]); glNormal3dv(&normals[i+1][0]); glVertex3dv(&vertices[i+1][0]); glNormal3dv(&normals[i+2][0]); glVertex3dv(&vertices[i+2][0]); } } else { // one normal per face for (unsigned int i = 0; i < vertices.size(); i += 3) { glNormal3dv(&normals[i/3][0]); glVertex3dv(&vertices[i][0]); glVertex3dv(&vertices[i+1][0]); glVertex3dv(&vertices[i+2][0]); } } glEnd(); } Shape::Shape() : vertices(), normals() { } void Shape::addTriangle(const Point3& p1, const Point3& p2, const Point3& p3) { vertices.push_back(p1); vertices.push_back(p2); vertices.push_back(p3); } void Shape::addTriangle(const Point3& p1, const Point3& p2, const Point3& p3, const Vector3& n) { vertices.push_back(p1); vertices.push_back(p2); vertices.push_back(p3); normals.push_back(n); } void Shape::addTriangle(const Point3& p1, const Point3& p2, const Point3& p3, const Vector3& n1, const Vector3& n2, const Vector3& n3) { vertices.push_back(p1); vertices.push_back(p2); vertices.push_back(p3); normals.push_back(n1); normals.push_back(n2); normals.push_back(n3); } void Shape::addSquare(const Point3& p1, const Point3& p2, const Point3& p3, const Point3& p4) { addTriangle(p1, p2, p4); addTriangle(p2, p3, p4); } void Shape::addSquare(const Point3& p1, const Point3& p2, const Point3& p3, const Point3& p4, const Vector3& n) { addTriangle(p1, p2, p4, n); addTriangle(p2, p3, p4, n); } void Shape::addSquare(const Point3& p1, const Point3& p2, const Point3& p3, const Point3& p4, const Vector3& n1, const Vector3& n2, const Vector3& n3, const Vector3& n4) { addTriangle(p1, p2, p4, n1, n2, n4); addTriangle(p2, p3, p4, n2, n3, n4); } Cube::Cube(int n) : Shape() { for (int u = 0; u < n; u++) { for (int v = 0; v < n; v++) { double s0 = -0.5 + (1.0 * u) / n; double t0 = 0.5 - (1.0 * v) / n; double s1 = -0.5 + (1.0 * (u + 1)) / n; double t1 = 0.5 - (1.0 * (v + 1)) / n; // z = 0.5 addSquare(Point3(s0, t0, 0.5), Point3(s0, t1, 0.5), Point3(s1, t1, 0.5), Point3(s1, t0, 0.5), Vector3(0, 0, 1)); // z = -0.5 addSquare(Point3(s1, t0, -0.5), Point3(s1, t1, -0.5), Point3(s0, t1, -0.5), Point3(s0, t0, -0.5), Vector3(0, 0, -1)); // x = 0.5 addSquare(Point3(0.5, t0, s0), Point3(0.5, t0, s1), Point3(0.5, t1, s1), Point3(0.5, t1, s0), Vector3(1, 0, 0)); // x = -0.5 addSquare(Point3(-0.5, t0, s1), Point3(-0.5, t0, s0), Point3(-0.5, t1, s0), Point3(-0.5, t1, s1), Vector3(-1, 0, 0)); // y = 0.5 addSquare(Point3(s0, 0.5, t0), Point3(s1, 0.5, t0), Point3(s1, 0.5, t1), Point3(s0, 0.5, t1), Vector3(0, 1, 0)); // y = -0.5 addSquare(Point3(s1, -0.5, t0), Point3(s0, -0.5, t0), Point3(s0, -0.5, t1), Point3(s1, -0.5, t1), Vector3(0, -1, 0)); } } } Cone::Cone(int n, int m) : Shape() { if (n < 3) n = 3; double ca = 0.5, sa = 0.0; for (int i = 1; i <= n; i++) { double a = (2 * M_PI * i) / n; double ca1 = 0.5 * cos(a); double sa1 = 0.5 * sin(a); addTriangle(Point3(0, -0.5, 0), Point3(ca, -0.5, sa), Point3(ca1, -0.5, sa1), Vector3(0, -1, 0), Vector3(0, -1, 0), Vector3(0, -1, 0)); float y = 0.5f - 1.0f / m; double r = 1.0 / m; addTriangle(Point3(0, 0.5, 0), Point3(r * ca1, y, r * sa1), Point3(r * ca, y, r * sa), Vector3(0, 1, 0), Vector3(ca1 * 2, 0.5, sa1 * 2), Vector3(ca * 2, 0.5, sa * 2)); for (int j = 1; j < m; j++) { float y1 = 0.5f - (float) j / m; float y2 = 0.5f - (float) (j + 1) / m; r = (double) j / m; double r2 = (double) (j + 1) / m; addSquare(Point3(r * ca, y1, r * sa), Point3(r * ca1, y1,r * sa1), Point3(r2 * ca1, y2, r2 * sa1), Point3(r2 * ca, y2, r2 * sa), Vector3(ca * 2, 0.5, sa * 2), Vector3(ca1 * 2, 0.5, sa1 * 2), Vector3(ca1 * 2, 0.5, sa1 * 2), Vector3(ca * 2, 0.5, sa * 2)); } ca = ca1; sa = sa1; } } Cylinder::Cylinder(int n, int m) : Shape() { if (n < 3) n = 3; double ca = 0.5, sa = 0.0; for (int i = 1; i <= n; i++) { double a = (2 * M_PI * i) / n; double ca1 = 0.5 * cos(a); double sa1 = 0.5 * sin(a); addTriangle(Point3(0, 0.5, 0), Point3(ca1, 0.5, sa1), Point3(ca, 0.5, sa), Vector3(0, 1, 0), Vector3(0, 1, 0), Vector3(0, 1, 0)); addTriangle(Point3(0, -0.5, 0), Point3(ca, -0.5, sa), Point3(ca1, -0.5, sa1), Vector3(0, -1, 0), Vector3(0, -1, 0), Vector3(0, -1, 0)); for (int j = 0; j < m; j++) { float y1 = 0.5f - (float) j / m; float y2 = 0.5f - (float) (j + 1) / m; addSquare(Point3(ca, y1, sa), Point3(ca1, y1, sa1), Point3(ca1, y2, sa1), Point3(ca, y2, sa), Vector3(ca * 2, 0, sa * 2), Vector3(ca1 * 2, 0, sa1 * 2), Vector3(ca1 * 2, 0, sa1 * 2), Vector3(ca * 2, 0, sa * 2)); } ca = ca1; sa = sa1; } } Sphere::Sphere(int n) : Shape() { unsigned int i; int j; if (n > 5) n = 5; double a = 2.0 / (1.0 + sqrt(5.0)); addTriangle(Point3( 0, a, -1), Point3(-a, 1, 0), Point3( a, 1, 0)); addTriangle(Point3( 0, a, 1), Point3( a, 1, 0), Point3(-a, 1, 0)); addTriangle(Point3( 0, a, 1), Point3(-1, 0, a), Point3( 0, -a, 1)); addTriangle(Point3( 0, a, 1), Point3( 0, -a, 1), Point3( 1, 0, a)); addTriangle(Point3( 0, a, -1), Point3( 1, 0, -a), Point3( 0, -a, -1)); addTriangle(Point3( 0, a, -1), Point3( 0, -a, -1), Point3(-1, 0, -a)); addTriangle(Point3( 0, -a, 1), Point3(-a, -1, 0), Point3( a, -1, 0)); addTriangle(Point3( 0, -a, -1), Point3( a, -1, 0), Point3(-a, -1, 0)); addTriangle(Point3(-a, 1, 0), Point3(-1, 0, -a), Point3(-1, 0, a)); addTriangle(Point3(-a, -1, 0), Point3(-1, 0, a), Point3(-1, 0, -a)); addTriangle(Point3( a, 1, 0), Point3( 1, 0, a), Point3( 1, 0, -a)); addTriangle(Point3( a, -1, 0), Point3( 1, 0, -a), Point3( 1, 0, a)); addTriangle(Point3( 0, a, 1), Point3(-a, 1, 0), Point3(-1, 0, a)); addTriangle(Point3( 0, a, 1), Point3( 1, 0, a), Point3( a, 1, 0)); addTriangle(Point3( 0, a, -1), Point3(-1, 0, -a), Point3(-a, 1, 0)); addTriangle(Point3( 0, a, -1), Point3( a, 1, 0), Point3( 1, 0, -a)); addTriangle(Point3( 0, -a, -1), Point3(-a, -1, 0), Point3(-1, 0, -a)); addTriangle(Point3( 0, -a, -1), Point3( 1, 0, -a), Point3( a, -1, 0)); addTriangle(Point3( 0, -a, 1), Point3(-1, 0, a), Point3(-a, -1, 0)); addTriangle(Point3( 0, -a, 1), Point3( a, -1, 0), Point3( 1, 0, a)); std::vector vOld; for (j = 1; j < n; j++) { // normalize to sphere Point3 origin; for (i = 0; i < vertices.size(); i++) { Vector3 v = unit( vertices[i] - origin ); vertices[i] = origin + v; } vOld = vertices; vertices.clear(); for (i = 0; i < vOld.size(); i += 3) { Point3 v1 = vOld[i]; double x1 = v1[0], y1 = v1[1], z1 = v1[2]; Point3 v2 = vOld[i + 1]; double x2 = v2[0], y2 = v2[1], z2 = v2[2]; Point3 v3 = vOld[i + 2]; double x3 = v3[0], y3 = v3[1], z3 = v3[2]; addTriangle(v1, Point3((x1 + x2) * 0.5, (y1 + y2) * 0.5, (z1 + z2) * 0.5), Point3((x1 + x3) * 0.5, (y1 + y3) * 0.5, (z1 + z3) * 0.5)); addTriangle(Point3((x1 + x2) * 0.5, (y1 + y2) * 0.5, (z1 + z2) * 0.5), v2, Point3((x3 + x2) * 0.5, (y3 + y2) * 0.5, (z3 + z2) * 0.5)); addTriangle(Point3((x1 + x3) * 0.5, (y1 + y3) * 0.5, (z1 + z3) * 0.5), Point3((x3 + x2) * 0.5, (y3 + y2) * 0.5, (z3 + z2) * 0.5), v3); addTriangle(Point3((x1 + x3) * 0.5, (y1 + y3) * 0.5, (z1 + z3) * 0.5), Point3((x1 + x2) * 0.5, (y1 + y2) * 0.5, (z1 + z2) * 0.5), Point3((x3 + x2) * 0.5, (y3 + y2) * 0.5, (z3 + z2) * 0.5)); } } // compute normals and scale to 0.5 radius Point3 origin; for (i = 0; i < vertices.size(); i++) { Vector3 n = unit( vertices[i] - origin ); normals.push_back(n); vertices[i] = origin + n * 0.5; } } MoebiusStrip::MoebiusStrip(int n, int m) : Shape() { unsigned int k; int i, j; if (n < 3) n = 3; for (i = 0; i < n; i++) { for (j = 0; j < m; j++) { double s0 = 2 * M_PI * i / n; double t0 = -0.4 + 0.8 * j / m; double s1 = 2 * M_PI * (i + 1) / n; double t1 = -0.4 + 0.8 * (j + 1) / m; double x1 = cos(s0) + t0 * cos(s0 * 0.5) * cos(s0); double y1 = sin(s0) + t0 * cos(s0 * 0.5) * sin(s0); double z1 = t0 * sin(s0 * 0.5); double x2 = cos(s1) + t0 * cos(s1 * 0.5) * cos(s1); double y2 = sin(s1) + t0 * cos(s1 * 0.5) * sin(s1); double z2 = t0 * sin(s1 * 0.5); double x3 = cos(s1) + t1 * cos(s1 * 0.5) * cos(s1); double y3 = sin(s1) + t1 * cos(s1 * 0.5) * sin(s1); double z3 = t1 * sin(s1 * 0.5); double x4 = cos(s0) + t1 * cos(s0 * 0.5) * cos(s0); double y4 = sin(s0) + t1 * cos(s0 * 0.5) * sin(s0); double z4 = t1 * sin(s0 * 0.5); // add the square both ways (because surface is two sided) addSquare(Point3(x1, y1, z1), Point3(x2, y2, z2), Point3(x3, y3, z3), Point3(x4, y4, z4)); addSquare(Point3(x2, y2, z2), Point3(x1, y1, z1), Point3(x4, y4, z4), Point3(x3, y3, z3)); } } // calculate only one normal per face, the explicit expression for the surface normal is // a little too messy for (k = 0; k < vertices.size(); k += 3) { vertices[k ] *= 0.70; vertices[k + 1] *= 0.70; vertices[k + 2] *= 0.70; Vector3 a = vertices[k + 1] - vertices[k]; Vector3 b = vertices[k + 2] - vertices[k]; Vector3 n = a ^ b; n.normalize(); normals.push_back(n); } } Cow::Cow() : Shape() { std::ifstream cowFile("../data/cow.raw"); if ( !cowFile.good() ) return; bool done = !cowFile; while (!done) { Point3 p1, p2, p3; cowFile >> p1[0]; cowFile >> p1[1]; cowFile >> p1[2]; cowFile >> p2[0]; cowFile >> p2[1]; cowFile >> p2[2]; cowFile >> p3[0]; cowFile >> p3[1]; done = !(cowFile >> p3[2]); addTriangle(p1, p2, p3); } for (unsigned int i = 0; i < vertices.size(); i += 3) { vertices[i ] *= 0.20; vertices[i + 1] *= 0.20; vertices[i + 2] *= 0.20; Vector3 a = vertices[i + 1] - vertices[i]; Vector3 b = vertices[i + 2] - vertices[i]; Vector3 n = a ^ b; n.normalize(); normals.push_back(n); } }