/* Parser.cpp * * Definition of the Parser class. */ #include "Parser.h" #include "Error.h" #include #include using namespace std; Parser::Parser(void) : loadMe_(NULL), verbose_(0) // default to quiet { // Nothing to do } Parser::~Parser(void) { // Nothing to do } void Parser::setVerbosity(int verbose) { verbose_ = verbose; if (verbose_ < 0) verbose_ = 0; if (verbose_ > MAX_VERBOSE) verbose_ = MAX_VERBOSE; reportVerbosity(); } void Parser::cycleVerbosity() { ++verbose_; if (verbose_ > MAX_VERBOSE) verbose_ = 0; reportVerbosity(); } void Parser::reportVerbosity() { cout << "Verbose = " << verbose_ << ": "; switch(verbose_) { case 0: cout << "No parsing output\n"; break; case 1: cout << "Only extra commands reported\n"; break; case 2: cout << "Everything reported\n"; break; default: cout << "***ERROR: Verbosity at " << verbose_ << endl; break; } } /* * loadFile() */ void Parser::loadFile(World* pWorld) { string cmd; bool notDone = true; // put world in its proper place loadMe_ = pWorld; assert(loadMe_ != NULL); // get filename while(notDone) { notDone = false; // only do one command unless otherwise specified cout << "Please enter filename of input file.\n" << "\tnone - Oops, I don't want to mess up my beautiful world!\n" << "\tcin - Accept input from console instead of file\n" << "\tformat - Display acceptable input file format\n" << "-> "; cin >> cmd; if(cmd == "none" || cmd == "n") { // do nothing } else if(cmd == "format" || cmd == "f") { cout << "The format of the input file is as follows:\n\n" << "\tN\n" << "\tx0 y0 z0 r0 g0 b0\n" << "\tx1 y1 z1 r1 g1 b1\n" << "\t...\n" << "\txN-1 yN-1 zN-1 rN-1 gN-1 bN-1\n" << "\tM\n" << "\tu0 v0 w0\n" << "\tu1 v1 w1\n" << "\t...\n" << "\tuM-1 vM-1 wM-1\n" << "\n" << "N is the number of vertices, M is the number of triangles, x_i, y_i,\n" << "z_i are floats representing the coordinates of vertex i, r_i, g_i, b_i\n" << "is the color of vertex i, and u_j, v_j, w_j are integers representing\n" << "indices in the vertex list of the vertices in triangle j as they\n" << "appear from the front of the triangle in counter-clockwise order.\n" << "\n" << "Additional cmds (must come after the normal format):\n" << "\tball x y z\t- moves the ball to (x,y,z)\n" << "\tvel x y z\t- sets ball's velocity to (x,y,z)\n" << "\tlight on/off\t- turns on or off shading\n" << "\n"; notDone = true; } else if(cmd == "help" || cmd == "h") { notDone = true; } else if(cmd == "cin") { // Make sure we start with an empty obstructions_ vector loadMe_->destroyWorld(); int error = parse(cin); if (error) { notDone = true; } meshCleanUp(); } else // interpret cmd as a filename { int error = getFile(cmd, NULL); if (error) { notDone = true; continue; } } } } int Parser::getFile(const string& filename, World* pWorld) { int error; // put world in its proper place if (loadMe_ == NULL) loadMe_ = pWorld; assert(loadMe_ != NULL); // get file fstream input(filename.c_str(), ios_base::in); // make sure input stream is good if (!(input)) { printf("***ERROR: Invalid filename: %s\n", filename.c_str()); return BADFILE; } // Make sure we start with an empty obstructions_ vector loadMe_->destroyWorld(); error = parse(input); meshCleanUp(); input.close(); return error; } /* * parse() * * This populates a world's obsructions_ vector based on an input stream. */ int Parser::parse(istream& input) { int nVert; // Number of vertices taken in int nTri; // Number of trianlges taken in double x,y,z; double r,g,b; int i1,i2,i3; vector vertices; // Take in vertices input >> nVert; for (int i = 0; i < nVert; ++i) { input >> x >> y >> z >> r >> g >> b; if (verbose_ > 1) printf("Vertex %d: (%.2f,%.2f,%.2f) r=%.2f g=%.2f b=%.2f\n", i,x,y,z,r,g,b); // Make sure the colors are valid if (r < 0 || r > 1 || g < 0 || r > 1 || b < 0 || b > 1) { printf("***ERROR: Only colors between 0 and 1 are allowed!\n\tOffending Vertex: \"%.2f %.2f %.2f r=%.2f g=%.2f b=%.2f\"\n", x,y,z,r,g,b); return BADCOLOR; } vertices.push_back(loadMe_->addVertex(Tuple(x,y,z), Tuple(r,g,b))); } // Take in Triangles and produce both Triangles and Edges. // i1,i2,i3 are the indices of the vertices that will make up // the given triangle. input >> nTri; for (int i = 0; i < nTri; ++i) { input >> i1 >> i2 >> i3; // Make sure that the indices given are valid // (We should probably do this differently than assert // statments - like return an error) if (i1 < 0 || i1 >= nVert || i1 >= (int)loadMe_->obstructions_.size() || i2 < 0 || i2 >= nVert || i2 >= (int)loadMe_->obstructions_.size() || i3 < 0 || i3 >= nVert || i3 >= (int)loadMe_->obstructions_.size()) { printf("***ERROR: Invalid Index in Triangle: \"%d %d %d\"", i1, i2, i3); return BADINDEX; } // Get the vertices that have been specified by index Vertex* v1 = vertices[i1]; Vertex* v2 = vertices[i2]; Vertex* v3 = vertices[i3]; // Make sure the Vertices are non-null if (v1 == NULL || v2 == NULL || v3 == NULL) { printf("***ERROR: Null pointer vertex in Triangle: \"%d %d %d\"", i1, i2, i3); return GENERROR; } // Report Triangle if (verbose_ > 1) { cout << "Triangle " << i << ": " << v1->v() << " " << v2->v() << " " << v3->v() << endl; } // Make the Triangle Triangle* temp = loadMe_->addTriangle(v1,v2,v3); curMesh_.push_back(temp); // Update the average normals of its verticies Tuple normal = temp->calcNormal(Tuple()); v1->addNormal(normal); v2->addNormal(normal); v3->addNormal(normal); // Make the 3 corresponding Edges loadMe_->addEdge(v1,v2); loadMe_->addEdge(v1,v3); loadMe_->addEdge(v2,v3); } // parse the rest return parseExtra(input); } /* * parseExtra() * * Parses anything left in the stream after parse is done */ int Parser::parseExtra(istream& input) { string extra; do { extra = ""; input >> extra; if (verbose_ > 0) printf("Additional Cmd: \"%s\"\n", extra.c_str()); // Insert new commands in here if (extra == "ball" || extra == "Ball" || extra == "BALL") { double x,y,z; input >> x >> y >> z; if (verbose_ > 0) printf("\tMove to (%.2f,%.2f,%.2f)\n",x,y,z); loadMe_->ball_.moveTo(Tuple(x,y,z)); } else if (extra == "vel" || extra == "Vel" || extra == "VEL") { double x,y,z; input >> x >> y >> z; if (verbose_ > 0) printf("\tAccel to (%.2f,%.2f,%.2f)\n",x,y,z); loadMe_->ball_.accelTo(Tuple(x,y,z)); } else if (extra == "newmesh" || extra == "newMesh" || extra == "NewMesh" || extra == "NEWMESH") { meshCleanUp(); parse(input); } else if (extra == "meshcolor" || extra == "meshColor" || extra == "MeshColor" || extra == "MESHCOLOR") { // Get colors: ambient, diffuse, specular, emissive (in order) vector colors; double r,g,b; for (int i = 0; i < NUM_OF_COLORS; ++i) { input >> r >> g >> b; colors.push_back(Tuple(r,g,b)); } if (verbose_ > 0) { cout << "\tMeshColor:"; for (int color = 0; color < (int)colors.size(); ++color) { cout << " " << colors[color]; } cout << endl; } // Apply colors to mesh for (int i = 0; i < (int)curMesh_.size(); ++i) { curMesh_[i]->setColors(colors); if (verbose_ > 1) { cout << "\tColorified triangle " << i << ": "; curMesh_[i]->print(); } } colors.clear(); ////// } else if (extra == "hole" || extra == "Hole" || extra == "HOLE") { // Make all of mesh into hole for (int i = 0; i < (int)curMesh_.size(); ++i) { curMesh_[i]->setIsHole(true); if (verbose_ > 1) { cout << "\tHoleified triangle " << i << ": "; curMesh_[i]->print(); } } } else if (extra == "light" || extra == "Light" || extra == "LIGHT") { string choice; input >> choice; if (choice == "off" || choice == "Off" || choice == "OFF" || choice == "0") { if (verbose_ > 0) printf("\tTurning OFF lights\n"); loadMe_->lightOff(); } else if (choice == "on" || choice == "On" || choice == "ON" || choice == "1") { if (verbose_ > 0) printf("\tTurning ON lights\n"); loadMe_->lightOn(); } else { printf("***WARNING: Bad value for light on/off: \"%s\"\n\tIgnoring light change request.\n", choice.c_str()); } } else if (extra == "worldbottom" || extra == "worldBottom" || extra == "WorldBottom" || extra == "WORLDBOTTOM") { double newBottom; input >> newBottom; if (verbose_ > 0) printf("New bottom of world = %f\n", newBottom); loadMe_->setBottom(newBottom); } else { if (extra != "") printf("***WARNING: Unknown command \"%s\"\n", extra.c_str()); } } while (extra != "" && input); return NOERROR; } void Parser::meshCleanUp() { curMesh_.clear(); }