void Arcball::init() { center.set( 0.0, 0.0 ); radius = 1.0; q_now = quat_identity(); *rot_ptr = identity3D(); q_increment = quat_identity(); rot_increment = identity3D(); is_mouse_down = false; is_spinning = false; damp_factor = 0.0; zero_increment = true; }
mat4 mat4::inverse(void) // Gauss-Jordan elimination with partial pivoting { mat4 a(*this), // As a evolves from original mat into identity b(identity3D()); // b evolves from identity into inverse(a) int i, j, i1; // Loop over cols of a from left to right, eliminating above and below diag for (j=0; j<4; j++) { // Find largest pivot in column j among rows j..3 i1 = j; // Row with largest pivot candidate for (i=j+1; i<4; i++) if (fabs(a.v[i].n[j]) > fabs(a.v[i1].n[j])) i1 = i; // Swap rows i1 and j in a and b to put pivot on diagonal swap(a.v[i1], a.v[j]); swap(b.v[i1], b.v[j]); // Scale row j to have a unit diagonal if (a.v[j].n[j]==0.) VEC_ERROR("mat4::inverse: singular matrix; can't invert\n"); b.v[j] /= a.v[j].n[j]; a.v[j] /= a.v[j].n[j]; // Eliminate off-diagonal elems in col j of a, doing identical ops to b for (i=0; i<4; i++) if (i!=j) { b.v[i] -= a.v[i].n[j]*b.v[j]; a.v[i] -= a.v[i].n[j]*a.v[j]; } } return b; }
void c3arcball_init( c3arcballp a ) { a->center = c3vec2f( 0.0, 0.0 ); a->radius = 1.0; a->q_now = c3quat_identity(); a->rot_ptr = &a->rot; a->rot = identity3D(); a->q_increment = c3quat_identity(); a->rot_increment = identity3D(); a->is_mouse_down = false; a->is_spinning = false; a->damp_factor = 0.0; a->zero_increment = true; }
void static topBCall(Fl_Widget* w, void* v){ UI* j = ((UI*)v); j->control->win->c->rot = identity3D(); j->control->win->c->up = vec4(0, 1, 0, 1); j->control->win->c->eye = vec4(0, 0, 8, 1); glClearColor(0, 0, 0, 0); glClear(GL_COLOR_BUFFER_BIT); j->control->win->redraw(); }
void Arcball::mouse_down(int x, int y) { down_pt.set( (float)x, (float) y ); is_mouse_down = true; q_increment = quat_identity(); rot_increment = identity3D(); zero_increment = true; }
void ViewModel::reset() { up.set( 0.0, 1.0, 0.0 ); eye.set(0.0,0.0,10.0); lookat.set(0.0,0.0,0.0); mtx = identity3D(); update(); }
bool SceneInstance::computeTransform(mat4 &mat, int time) { mat = identity3D(); if (_transforms.empty()) return false; else { for (vector<Transform*>::reverse_iterator it = _transforms.rbegin(); it != _transforms.rend(); ++it) { mat = mat * (**it).getMatrix(time); } } return true; }
Viewport::Viewport(vec4 eye, int width, int height, Lens l) { _eye = eye; _UL = vec4(-0.18, 0.12, 1.02538, 0); _UR = vec4(0.18, 0.12, 1.02538, 0); _LL = vec4(-0.18, -0.12, 1.02538, 0); _LR = vec4(0.18, -0.12, 1.02538, 0); _pixelsWide = width; _pixelsHigh = height; _raysPerPixel = 1; _incPP = (int)sqrt((float)_raysPerPixel); _viewToWorld = identity3D(); _lens = l; }
void c3arcball_mouse_down( c3arcballp a, int x, int y) { a->down_pt = c3vec2f( (c3f)x, (c3f) y ); a->is_mouse_down = true; a->q_increment = c3quat_identity(); a->rot_increment = identity3D(); a->zero_increment = true; }
Scene::Scene(char* path) { shapes = new vector<Shape *>(); lights = new vector<Light *>(); outputPath = string("test.png"); maxDepth = 5; attenuation[0] = 1.0; attenuation[1] = 0.0; attenuation[2] = 0.0; transformations.push(identity3D()); ambient = Color(0.2, 0.2, 0.2); numSamples = 1; lensSize = 0; readScene(path); totalPix = width * height; }
void Scene::readfile(char* file){ string str, cmd; vec3 ambient; vec3 diffuse; vec3 specular; double shininess; vec3 emission; vec3 attenuation = vec3(1,0,0); vector<vec3> vertices; ifstream in; in.open(file); if (in.is_open()) { stack <mat4> transfstack; transfstack.push(mat4(identity3D())); getline (in, str); while (in) { if ((str.find_first_not_of(" \t\r\n") != string::npos) && (str[0] != '#')) { // Ruled out comment and blank lines stringstream s(str); s >> cmd; double values[10]; // Position and color for light, colors for others // Up to 10 params for cameras. bool validinput; // Validity of input if (cmd == "directional") { validinput = readvals(s, 6, values); // Position/color for lts. if (validinput) { vec3 posn = vec3(values[0],values[1],values[2]); vec3 col = vec3(values[3],values[4],values[5]); vec3 dir = vec3(transfstack.top() * vec4(posn, 0), 3); Light light = Light(dir,col,0); lights.push_back(light); } } else if (cmd == "point") { validinput = readvals(s, 6, values); // Position/color for lts. if (validinput) { vec3 posn = vec3(values[0],values[1],values[2]); vec3 col = vec3(values[3],values[4],values[5]); vec3 dir = vec3(transfstack.top() * vec4(posn, 1)); Light light = Light(dir,col,1,attenuation); lights.push_back(light); } } else if (cmd == "attenuation") { validinput = readvals(s, 3, values); // Position/color for lts. if (validinput) { attenuation = vec3(values[0],values[1],values[2]); } } else if (cmd == "maxdepth") { validinput = readvals(s,1,values); if (validinput) { maxdepth = values[0]; } } else if (cmd == "size") { validinput = readvals(s,2,values); if (validinput) { pixels = vec2(values[0],values[1]); film = new Film(pixels); } } else if (cmd == "output") { s>>name; } else if (cmd == "camera") {
mat4::mat4() { *this = identity3D(); }
void World::loadInstance(SceneInstance *si) { // Compute transform information. Should add a mat4 even if there is no transform. mat4 mTransform; if (!si->computeTransform(mTransform)) { mTransform = identity3D(); // if there is no transform, push an identity matrix. } if (!transformStack.empty() && transformStack.top() != identity3D()) { mat4 mPreviousTransform = transformStack.top(); mTransform = mPreviousTransform * mTransform; } transformStack.push(mTransform); SceneGroup *sg = si->getChild(); // Get camera info, if any. CameraInfo camInfo; if (sg->computeCamera(camInfo)) { vec4 eye(0.0, 0.0, 0.0, 1.0); double left = camInfo.sides[FRUS_LEFT]; double right = camInfo.sides[FRUS_RIGHT]; double top = camInfo.sides[FRUS_TOP]; double bottom = camInfo.sides[FRUS_BOTTOM]; double depth = -1*camInfo.sides[FRUS_NEAR]; vec4 LL(left, bottom, depth, 1.0); vec4 UL(left, top, depth, 1.0); vec4 LR(right, bottom, depth, 1.0); vec4 UR(right, top, depth, 1.0); eye = mTransform * eye; LL = mTransform * LL; UL = mTransform * UL; LR = mTransform * LR; UR = mTransform * UR; _view = Viewport(eye, LL, UL, LR, UR, IMAGE_WIDTH, IMAGE_HEIGHT, camInfo.perspective); } // Compute light info, if any. LightInfo li; if (sg->computeLight(li)) { vec3 direction, position; switch (li.type) { case LIGHT_DIRECTIONAL: case LIGHT_POINT: case LIGHT_SPOT: direction = vec3(-1*mTransform[0][2],-1*mTransform[1][2],-1*mTransform[2][2]); position = mTransform * vec3(0.0); _lights[li.type].push_back(Light(position, direction, li)); break; case LIGHT_AMBIENT: _ambientLight = li.color; break; } } // Computes sphere info, if any. double radius; MaterialInfo matInfo; if (sg->computeSphere(radius, matInfo, 0)) { _spheres.push_back(Sphere(vec4(0.0), radius, matInfo, mTransform)); } // Recursively parse scene. for (int i = 0; i < sg->getChildCount(); i++) { loadInstance(sg->getChild(i)); } // Pops the transformation matrix of this SceneGroup. This function should have added this matrix at the beginning. transformStack.pop(); }
mat4::mat4(void) { *this = identity3D();}
int main(int argc, char *argv[]) { // Start stopwatch double start = clock(); // Parsing command line for input file name: std::string file = std::string(argv[1]); // Initialize/Declare everything! float windowW = 0; float windowH = 0; unsigned int maxDepth = 0; Camera c; unsigned int shapeNum = 0; BRDF brdf; float a1 = 1.0f; float a2 = 0.0f; float a3 = 0.0f; // Initialize Containers std::vector< std::vector<float> > vertices; std::vector< std::vector<float> > trinormvertices; std::vector< std::vector<float> > trinormnormals; std::vector<Shape *> shapes0; std::vector<Shape> shapes1; std::vector<Sphere> spheres1; std::vector<Triangle> triangles1; std::vector<TriNormal> trinormals1; std::vector<DirectionalLight> DLs1; std::vector<PointLight> PLs1; std::vector<DirectionalLight *> DLs0; std::vector<PointLight *> PLs0; //stack of 4x4 matrix transformations std::stack<mat4> transforms; //transf //push the idendity 4x4 matrix transforms.push(identity3D()); //transf std::string fname = "output.bmp"; std::ifstream inpfile(file.c_str()); if(!inpfile.is_open()) { std::cout << "Unable to open file" << std::endl; } else { std::string line; // MatrixStack mst; while(inpfile.good()) { std::vector<std::string> splitline; std::string buf; std::getline(inpfile,line); std::stringstream ss(line); while (ss >> buf) { splitline.push_back(buf); } // Ignore blank lines if(splitline.size() == 0) { continue; } // Ignore comments if(splitline[0][0] == '#') { continue; } // Valid commands: // size width height // must be first command of file, controls image size else if(!splitline[0].compare("size")) { windowW = atoi(splitline[1].c_str()); c.w = windowW; c.h = windowH = atoi(splitline[2].c_str()); } // maxdepth depth // max # of bounces for ray (default 5) else if(!splitline[0].compare("maxdepth")) { maxDepth = atoi(splitline[1].c_str()); } // output filename // output file to write image to else if(!splitline[0].compare("output")) { fname = splitline[1]; } // camera lookfromx lookfromy lookfromz lookatx lookaty lookatz upx upy upz fov // specifies the camera in the standard way, as in homework 2. else if (!splitline[0].compare("camera")) { c.lookFrom.at(0) = atof(splitline[1].c_str()); c.lookFrom.at(1) = atof(splitline[2].c_str()); c.lookFrom.at(2) = atof(splitline[3].c_str()); c.lookAt.at(0) = atof(splitline[4].c_str()); c.lookAt.at(1) = atof(splitline[5].c_str()); c.lookAt.at(2) = atof(splitline[6].c_str()); c.upDir.at(0) = atof(splitline[7].c_str()); c.upDir.at(1) = atof(splitline[8].c_str()); c.upDir.at(2) = atof(splitline[9].c_str()); c.fov = atof(splitline[10].c_str()); } // sphere x y z radius // Defines a sphere with a given position and radius. else if(!splitline[0].compare("sphere")) { Shape shape(shapeNum); Sphere s(atof(splitline[1].c_str()), atof(splitline[2].c_str()), atof(splitline[3].c_str()), atof(splitline[4].c_str()), brdf, shapeNum++, transforms.top()); spheres1.push_back(s); shape.brdf = brdf; shapes1.push_back(shape); // STORE CURRENT TOP OF MATRIX STACK } // Ignore these, unused else if(!splitline[0].compare("maxverts")) { continue; } else if(!splitline[0].compare("maxvertsnorms")) { continue; } //vertex x y z // Defines a vertex at the given location. // The vertex is put into a pile, starting to be numbered at 0. else if(!splitline[0].compare("vertex")) { std::vector<float> p(3, 0.0f); p.at(0) = atof(splitline[1].c_str()); p.at(1) = atof(splitline[2].c_str()); p.at(2) = atof(splitline[3].c_str()); vertices.push_back(p); // Create a new vertex with these 3 values, store in some array } //vertexnormal x y z nx ny nz // Similar to the above, but define a surface normal with each vertex. // The vertex and vertexnormal set of vertices are completely independent // (as are maxverts and maxvertnorms). else if(!splitline[0].compare("vertexnormal")) { std::vector<float> p(6, 0.0f); std::vector<float> n(6, 0.0f); p.at(0) = atof(splitline[1].c_str()); p.at(1) = atof(splitline[2].c_str()); p.at(2) = atof(splitline[3].c_str()); n.at(3) = atof(splitline[4].c_str()); n.at(4) = atof(splitline[5].c_str()); n.at(5) = atof(splitline[6].c_str()); trinormvertices.push_back(p); trinormnormals.push_back(n); } //tri v1 v2 v3 // Create a triangle out of the vertices involved (which have previously // been specified with the vertex command). The vertices are assumed to // be specified in counter-clockwise order. Your code should internally // compute a face normal for this triangle. else if(!splitline[0].compare("tri")) { Shape shape(shapeNum); // std::vector<float> *v1 = &vertices.at(atoi(splitline[1].c_str())); // std::vector<float> *v2 = &vertices.at(atoi(splitline[2].c_str())); // std::vector<float> *v3 = &vertices.at(atoi(splitline[3].c_str())); //original code: //std::vector<float> *v1 = &vertices.at(atoi(splitline[1].c_str())); //std::vector<float> *v2 = &vertices.at(atoi(splitline[2].c_str())); //std::vector<float> *v3 = &vertices.at(atoi(splitline[3].c_str())); //casting each of the three 3D vertice vectors into 4D vectors: std::vector<float> *v1 = &vertices.at(atoi(splitline[1].c_str())); std::vector<float> *v2 = &vertices.at(atoi(splitline[2].c_str())); std::vector<float> *v3 = &vertices.at(atoi(splitline[3].c_str())); //new component is set by default to 1.0 //e.g., casted 4D vector of v1 looks like: v1(v1.x, v1.y, v1.z, 1.0) //vec4 v1_4D = vec4((*v1)[0], *&(v1->at(1)), v1->at(2)); vec3 v1_3d = vec3((float) v1->at(0), (float) v1->at(1), (float) v1->at(2)); vec3 v2_3d = vec3((float) v2->at(0), (float) v2->at(1), (float) v2->at(2)); vec3 v3_3d = vec3((float) v3->at(0), (float) v3->at(1), (float) v3->at(2)); vec4 v1_4D = vec4(v1_3d); vec4 v2_4D = vec4(v2_3d); vec4 v3_4D = vec4(v3_3d); //transforming the vertices by multiplying the transformation //matrix by the 4D vertex vector: //algebra3 notes about casting down from 4D to 3D: When casting to a lower dimension, //the vector is homogenized in the lower dimension. E.g., if a 4d {X,Y,Z,W} //is cast to 3d, the resulting vector is {X/W, Y/W, Z/W}. vec3 v1_3D = vec3(transforms.top() * v1_4D); vec3 v2_3D = vec3(transforms.top() * v2_4D); vec3 v3_3D = vec3(transforms.top() * v3_4D); //converting each vec3 into a vector<float>: std::vector<float> *vv1 = new std::vector<float>(3, 0.0f); std::vector<float> *vv2 = new std::vector<float>(3, 0.0f); std::vector<float> *vv3 = new std::vector<float>(3, 0.0f); vv1->at(0) = v1_3D[0]; vv1->at(1) = v1_3D[1]; vv1->at(2) = v1_3D[2]; vv2->at(0) = v2_3D[0]; vv2->at(1) = v2_3D[1]; vv2->at(2) = v2_3D[2]; vv3->at(0) = v3_3D[0]; vv3->at(1) = v3_3D[1]; vv3->at(2) = v3_3D[2]; //Finally, pushing the transformed vertices into the triangles container: Triangle t(vv1, vv2, vv3, brdf, shapeNum++); triangles1.push_back(t); shape.brdf = brdf; shapes1.push_back(shape); // STORE CURRENT TOP OF MATRIX } //trinormal v1 v2 v3 // Same as above but for vertices specified with normals. // In this case, each vertex has an associated normal, // and when doing shading, you should interpolate the normals // for intermediate points on the triangle. else if(!splitline[0].compare("trinormal")) { Shape shape(shapeNum); std::vector<float> *v1 = &trinormvertices.at(atoi(splitline[1].c_str())); std::vector<float> *v2 = &trinormvertices.at(atoi(splitline[2].c_str())); std::vector<float> *v3 = &trinormvertices.at(atoi(splitline[3].c_str())); std::vector<float> *n1 = &trinormnormals.at(atoi(splitline[1].c_str())); std::vector<float> *n2 = &trinormnormals.at(atoi(splitline[2].c_str())); std::vector<float> *n3 = &trinormnormals.at(atoi(splitline[3].c_str())); TriNormal t(v1, v2, v3, n1, n2, n3, brdf, shapeNum++); trinormals1.push_back(t); shape.brdf = brdf; shapes1.push_back(shape); // STORE CURRENT TOP OF MATRIX STACK } //Translate x y z // A translation 3-vector else if(!splitline[0].compare("translate")) { float x, y, z; x = atof(splitline[1].c_str()); y = atof(splitline[2].c_str()); z = atof(splitline[3].c_str()); //creating translation vector, v: vec3 v = vec3(x, y, z); //getting the top (i.e. latest) matrix on the stack, and doing a translation3D transform: mat4 vTranslated = translation3D(v); mat4 transMat = transforms.top() * vTranslated; //updating the top of the matrix stack: transforms.pop(); transforms.push(transMat); } //rotate x y z angle // Rotate by angle (in degrees) about the given axis as in OpenGL. else if(!splitline[0].compare("rotate")) { float x, y, z, angle; x = atof(splitline[1].c_str()); y = atof(splitline[2].c_str()); z = atof(splitline[3].c_str()); //angle of rotation IN DEGREES angle = atof(splitline[4].c_str()); //creating the axis of rotation vector, axis: vec3 axis = vec3(x, y, z); //getting the top (i.e.latest) matrix on the stack, and doing a rotation3D transform using DEGREES: mat4 rotatedV = rotation3D(axis, angle); mat4 rotMat = transforms.top() * rotatedV; //updating the top of the matrix stack: transforms.pop(); transforms.push(rotMat); } //scale x y z // Scale by the corresponding amount in each axis (a non-uniform scaling). else if(!splitline[0].compare("scale")) { float x, y, z; x = atof(splitline[1].c_str()); y = atof(splitline[2].c_str()); z = atof(splitline[3].c_str()); //creating the scaling vector, scaleV vec3 scaleV = vec3(x, y, z); //getting the top (i.e.latest) matrix on the stack, and doing a scaling3D transform mat4 scaledV = scaling3D(scaleV); mat4 scaleMat = transforms.top() * scaledV; //updating the top of the matrix stack: transforms.pop(); transforms.push(scaleMat); } //pushTransform // Push the current modeling transform on the stack as in OpenGL. // You might want to do pushTransform immediately after setting // the camera to preserve the “identity” transformation. else if(!splitline[0].compare("pushTransform")) { transforms.push(transforms.top()); } //popTransform // Pop the current transform from the stack as in OpenGL. // The sequence of popTransform and pushTransform can be used if // desired before every primitive to reset the transformation // (assuming the initial camera transformation is on the stack as // discussed above). else if(!splitline[0].compare("popTransform")) { if (transforms.size() == 1) { std::cout << "No more matrices." << std::endl; } else { transforms.pop(); } } //directional x y z r g b // The direction to the light source, and the color, as in OpenGL. else if(!splitline[0].compare("directional")) { //original DO NOT DELETE // DLs1.push_back(*new DirectionalLight (atof(splitline[1].c_str()), // atof(splitline[2].c_str()), // atof(splitline[3].c_str()), // atof(splitline[4].c_str()), // atof(splitline[5].c_str()), // atof(splitline[6].c_str()))); vec3 dir = vec3(atof(splitline[1].c_str()), atof(splitline[2].c_str()), atof(splitline[3].c_str())); vec3 rgb = vec3(atof(splitline[4].c_str()), atof(splitline[5].c_str()), atof(splitline[6].c_str())); //lizzie comment: vec3(const vec4& v, int dropAxis); <- casts v4 to v3 dir = vec3(transforms.top() * vec4(dir, 0), 3); DLs1.push_back(*new DirectionalLight(dir[0], dir[1], dir[2], rgb[0], rgb[1], rgb[2])); } //point x y z r g b // The location of a point source and the color, as in OpenGL. else if(!splitline[0].compare("point")) { //original code DO NOT DELETE // PLs1.push_back(*new PointLight (atof(splitline[1].c_str()), // atof(splitline[2].c_str()), // atof(splitline[3].c_str()), // atof(splitline[4].c_str()), // atof(splitline[5].c_str()), // atof(splitline[6].c_str()), a1, a2, a3)); vec3 loc = vec3(atof(splitline[1].c_str()), atof(splitline[2].c_str()), atof(splitline[3].c_str())); vec3 rgb = vec3(atof(splitline[4].c_str()), atof(splitline[5].c_str()), atof(splitline[6].c_str())); //lizzie comment: vec3(const vec4& v, int dropAxis); <- casts v4 to v3 loc = vec3(transforms.top() * vec4(loc, 1)); PLs1.push_back(*new PointLight(loc[0], loc[1], loc[2], rgb[0], rgb[1], rgb[2], a1, a2, a3)); } //attenuation const linear quadratic // Sets the constant, linear and quadratic attenuations // (default 1,0,0) as in OpenGL. else if(!splitline[0].compare("attenuation")) { a1 = atof(splitline[1].c_str()); a2 = atof(splitline[2].c_str()); a3 = atof(splitline[3].c_str()); } //ambient r g b // The global ambient color to be added for each object // (default is .2,.2,.2), set in BRDF constructor else if(!splitline[0].compare("ambient")) { brdf.ka.at(0) = atof(splitline[1].c_str()); brdf.ka.at(1) = atof(splitline[2].c_str()); brdf.ka.at(2) = atof(splitline[3].c_str()); } //diffuse r g b // specifies the diffuse color of the surface. else if(!splitline[0].compare("diffuse")) { brdf.kd.at(0) = atof(splitline[1].c_str()); brdf.kd.at(1) = atof(splitline[2].c_str()); brdf.kd.at(2) = atof(splitline[3].c_str()); } //specular r g b // specifies the specular color of the surface. else if(!splitline[0].compare("specular")) { brdf.ks.at(0) = atof(splitline[1].c_str()); brdf.ks.at(1) = atof(splitline[2].c_str()); brdf.ks.at(2) = atof(splitline[3].c_str()); } //shininess s // specifies the shininess of the surface. else if(!splitline[0].compare("shininess")) { brdf.s = atof(splitline[1].c_str()); } //emission r g b // gives the emissive color of the surface. else if(!splitline[0].compare("emission")) { brdf.ke.at(0) = atof(splitline[1].c_str()); brdf.ke.at(1) = atof(splitline[2].c_str()); brdf.ke.at(2) = atof(splitline[3].c_str()); } else { std::cerr << "Unknown command: " << splitline[0] << std::endl; } } inpfile.close(); } // BEGIN SHIT c.setD(); // set camera d c.setULRD(); // set camera ULRD Film f(windowW, windowH); RayTracer rt(&c); Sampler s(&c, &rt, &f); // Create iterators for containers unsigned int sphCount = 0; unsigned int triCount = 0; unsigned int tnCount = 0; // Set up shapes0, the finalized container for (unsigned int i = 0; i < shapes1.size(); i++) { if (sphCount < spheres1.size() && spheres1[sphCount].num == i) { shapes1[i].sph = &spheres1[sphCount++]; shapes0.push_back(&shapes1[i]); } else if (triCount < triangles1.size() && triangles1[triCount].num == i) { shapes1[i].tri = &triangles1[triCount++]; shapes0.push_back(&shapes1[i]); } else if (tnCount < trinormals1.size() && trinormals1[tnCount].num == i) { shapes1[i].tn = &trinormals1[tnCount++]; shapes0.push_back(&shapes1[i]); } else { printf("container maker not working"); std::exit(1); } } for (unsigned int i = 0; i < PLs1.size(); i++) { PLs0.push_back(&PLs1[i]); } for (unsigned int i = 0; i < DLs1.size(); i++) { DLs0.push_back(&DLs1[i]); } rt.shapes = &shapes0; rt.DLs = &DLs0; rt.PLs = &PLs0; // GOOOOOOOOOOOOOOO!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! render(windowW, windowH, maxDepth, fname, &s); double total = (clock() - start) / 1000000; if (total > 3599) { std::cout<<"Time taken: " << total / 3600 << " hours\n"; } else if (total > 59) { std::cout<<"Time taken: " << total/60 << " minutes\n"; } else { std::cout<<"Time taken: " << total << " seconds\n"; } }