#include #include #include "vectors.h" #include "matrix.h" #include "scene_parser.h" #include "camera.h" #include "light.h" #include "object3d.h" #include "group.h" #include "sphere.h" #include "plane.h" #include "triangle.h" #include "transform.h" //#include "box.h" #define DegreesToRadians(x) ((M_PI * x) / 180.0f) // ==================================================================== // ==================================================================== // CONSTRUCTORS, DESTRUCTOR & INITIALIZE SceneParser::SceneParser() { initialize(); } SceneParser::SceneParser(const char* filename) { initialize(); // open the file assert(filename != NULL); const char *ext = &filename[strlen(filename)-4]; assert(!strcmp(ext,".txt")); file = fopen(filename,"r"); assert (file != NULL); // parse the scene parseFile(); // close the file fclose(file); file = NULL; } SceneParser::~SceneParser() { if (group != NULL) delete group; if (camera != NULL) delete camera; } void SceneParser::initialize() { // initialize some reasonable default values group = NULL; camera = NULL; background_color = Vec3f(0.5,0.5,0.5); lights = NULL; num_lights = 0; current_object_color = Vec3f(1,1,1); file = NULL; } // ==================================================================== // ==================================================================== void SceneParser::parseFile() { // // at the top level, the scene can have a camera, // background color and a group of objects // (we will add lights and other things in future assignments) // char token[MAX_PARSER_TOKEN_LENGTH]; while (getToken(token)) { if (!strcmp(token, "OrthographicCamera")) { parseOrthographicCamera(); } else if (!strcmp(token, "PerspectiveCamera")) { parsePerspectiveCamera(); } else if (!strcmp(token, "Background")) { parseBackground(); } else if (!strcmp(token, "Lights")) { parseLights(); } else if (!strcmp(token, "Group")) { group = parseGroup(); } else { printf ("Unknown token in parseFile: '%s'\n", token); exit(0); } } } Group* SceneParser::parseGroup() { // // each group starts with an integer that specifies // the number of objects in the group // // the material node sets the color of all objects which // follow, until the next material node // char token[MAX_PARSER_TOKEN_LENGTH]; getToken(token); assert (!strcmp(token, "{")); // read in the number of objects getToken(token); assert (!strcmp(token, "numObjects")); int num_objects = readInt(); Group *answer = new Group(num_objects); // read in the objects int count = 0; while (num_objects > count) { getToken(token); if (!strcmp(token, "Material")) { // materials don't count parseMaterial(); } else { // everything else does count Object3D *object = parseObject(token); assert (object != NULL); answer->addObject(count,object); count++; } } getToken(token); assert (!strcmp(token, "}")); // return the group return answer; } Object3D* SceneParser::parseObject(char token[MAX_PARSER_TOKEN_LENGTH]) { //printf ("PARSE OBJECT %s\n", token); Object3D *answer = NULL; if (!strcmp(token, "Group")) { answer = (Object3D*)parseGroup(); } else if (!strcmp(token, "Sphere")) { answer = (Object3D*)parseSphere(); } else if (!strcmp(token, "Box")) { //answer = (Object3D*)parseBox(); } else if (!strcmp(token, "Plane")) { answer = (Object3D*)parsePlane(); } else if (!strcmp(token, "Triangle")) { answer = (Object3D*)parseTriangle(); } else if (!strcmp(token, "TriangleMesh")) { answer = (Object3D*)parseTriangleMesh(); } else if (!strcmp(token, "Transform")) { answer = (Object3D*)parseTransform(); } else { printf ("Unknown token in parseObject: '%s'\n", token); exit(0); } return answer; } // ==================================================================== // ==================================================================== void SceneParser::parseLights() { char token[MAX_PARSER_TOKEN_LENGTH]; getToken(token); assert (!strcmp(token, "{")); // read in the number of objects getToken(token); assert (!strcmp(token, "numLights")); num_lights = readInt(); lights = new (Light*)[num_lights]; // read in the objects int count = 0; while (num_lights > count) { getToken(token); if (!strcmp(token, "DirectionalLight")) { getToken(token); assert (!strcmp(token, "{")); getToken(token); assert (!strcmp(token, "direction")); Vec3f direction = readVec3f(); getToken(token); assert (!strcmp(token, "color")); Vec3f color = readVec3f(); getToken(token); assert (!strcmp(token, "}")); // ++++++++++++++++++++++++++++++++++++++++++++++++++++ // CALLING ASSIGNMENT 2 CODE lights[count] = new DirectionalLight(direction,color); // ++++++++++++++++++++++++++++++++++++++++++++++++++++ count++; } else { printf ("Unknown token in parseGroup: '%s'\n", token); exit(0); } } getToken(token); assert (!strcmp(token, "}")); } // ==================================================================== // ==================================================================== void SceneParser::parseOrthographicCamera() { char token[MAX_PARSER_TOKEN_LENGTH]; // read in the camera parameters getToken(token); assert (!strcmp(token, "{")); getToken(token); assert (!strcmp(token, "center")); Vec3f center = readVec3f(); getToken(token); assert (!strcmp(token, "direction")); Vec3f direction = readVec3f(); getToken(token); assert (!strcmp(token, "up")); Vec3f up = readVec3f(); getToken(token); assert (!strcmp(token, "size")); float size = readFloat(); getToken(token); assert (!strcmp(token, "}")); camera = new OrthographicCamera(center,direction,up,size); } void SceneParser::parsePerspectiveCamera() { char token[MAX_PARSER_TOKEN_LENGTH]; // read in the camera parameters getToken(token); assert (!strcmp(token, "{")); getToken(token); assert (!strcmp(token, "center")); Vec3f center = readVec3f(); getToken(token); assert (!strcmp(token, "direction")); Vec3f direction = readVec3f(); getToken(token); assert (!strcmp(token, "up")); Vec3f up = readVec3f(); getToken(token); assert (!strcmp(token, "angle")); float angle_degrees = readFloat(); float angle_radians = DegreesToRadians(angle_degrees); getToken(token); assert (!strcmp(token, "}")); // ++++++++++++++++++++++++++++++++++++++++++++++++++++ // CALLING ASSIGNMENT 2 CODE // create a new perspective camera and return it camera = new PerspectiveCamera(center,direction,up,angle_radians); // ++++++++++++++++++++++++++++++++++++++++++++++++++++ } void SceneParser::parseBackground() { char token[MAX_PARSER_TOKEN_LENGTH]; // read in the background color getToken(token); assert (!strcmp(token, "{")); while (1) { getToken(token); if (!strcmp(token, "}")) { break; } else if (!strcmp(token, "color")) { background_color = readVec3f(); } else if (!strcmp(token, "ambientLight")) { ambient_light = readVec3f(); } else { printf ("Unknown token in parseBackground: '%s'\n", token); assert(0); } } } // ==================================================================== // ==================================================================== void SceneParser::parseMaterial() { char token[MAX_PARSER_TOKEN_LENGTH]; // change the current object color // scoping for the materials is very simplistic, // and essentially ignores any tree hierarchy getToken(token); assert (!strcmp(token, "{")); getToken(token); assert (!strcmp(token, "diffuseColor")); current_object_color = readVec3f(); getToken(token); assert (!strcmp(token, "}")); } Sphere* SceneParser::parseSphere() { char token[MAX_PARSER_TOKEN_LENGTH]; // read in the sphere parameters getToken(token); assert (!strcmp(token, "{")); getToken(token); assert (!strcmp(token, "center")); Vec3f center = readVec3f(); getToken(token); assert (!strcmp(token, "radius")); float radius = readFloat(); getToken(token); assert (!strcmp(token, "}")); return new Sphere(center,radius,current_object_color); } /* // OPTIONAL, NOT REQUIRED TO HANDLE BOXES Box* SceneParser::parseBox() { char token[MAX_PARSER_TOKEN_LENGTH]; // read in the sphere parameters getToken(token); assert (!strcmp(token, "{")); getToken(token); assert (!strcmp(token, "min")); Vec3f min = readVec3f(); getToken(token); assert (!strcmp(token, "max")); Vec3f max = readVec3f(); getToken(token); assert (!strcmp(token, "}")); // create a new box object and return it return new Box(min,max,current_object_color); } */ Plane* SceneParser::parsePlane() { char token[MAX_PARSER_TOKEN_LENGTH]; // read in the sphere parameters getToken(token); assert (!strcmp(token, "{")); getToken(token); assert (!strcmp(token, "normal")); Vec3f normal = readVec3f(); getToken(token); assert (!strcmp(token, "offset")); float offset = readFloat(); getToken(token); assert (!strcmp(token, "}")); // ++++++++++++++++++++++++++++++++++++++++++++++++++++ // CALLING ASSIGNMENT 2 CODE // create a new plane object and return it return new Plane(normal,offset,current_object_color); // ++++++++++++++++++++++++++++++++++++++++++++++++++++ } Triangle* SceneParser::parseTriangle() { char token[MAX_PARSER_TOKEN_LENGTH]; // read in the sphere parameters getToken(token); assert (!strcmp(token, "{")); getToken(token); assert (!strcmp(token, "vertex0")); Vec3f v0 = readVec3f(); getToken(token); assert (!strcmp(token, "vertex1")); Vec3f v1 = readVec3f(); getToken(token); assert (!strcmp(token, "vertex2")); Vec3f v2 = readVec3f(); getToken(token); assert (!strcmp(token, "}")); // ++++++++++++++++++++++++++++++++++++++++++++++++++++ // CALLING ASSIGNMENT 2 CODE // create a new triangle object and return it return new Triangle(v0,v1,v2,current_object_color); // ++++++++++++++++++++++++++++++++++++++++++++++++++++ } Group* SceneParser::parseTriangleMesh() { char token[MAX_PARSER_TOKEN_LENGTH]; char filename[MAX_PARSER_TOKEN_LENGTH]; // get the filename getToken(token); assert (!strcmp(token, "{")); getToken(token); assert (!strcmp(token, "obj_file")); getToken(filename); getToken(token); assert (!strcmp(token, "}")); const char *ext = &filename[strlen(filename)-4]; assert(!strcmp(ext,".obj")); // read it once, get counts FILE *file = fopen(filename,"r"); assert (file != NULL); int vcount = 0; int fcount = 0; while (1) { int c = fgetc(file); if (c == EOF) { break; } else if (c == 'v') { assert(fcount == 0); float v0,v1,v2; fscanf (file,"%f %f %f",&v0,&v1,&v2); vcount++; } else if (c == 'f') { int f0,f1,f2; fscanf (file,"%d %d %d",&f0,&f1,&f2); fcount++; } // otherwise, must be whitespace } //printf ("verts %d faces %d\n", vcount,fcount); fclose(file); // make arrays Vec3f *verts = new Vec3f[vcount]; Group *answer = new Group(fcount); // read it again, save it file = fopen(filename,"r"); assert (file != NULL); int new_vcount = 0; int new_fcount = 0; while (1) { int c = fgetc(file); if (c == EOF) { break; } else if (c == 'v') { assert(new_fcount == 0); float v0,v1,v2; fscanf (file,"%f %f %f",&v0,&v1,&v2); verts[new_vcount] = Vec3f(v0,v1,v2); new_vcount++; } else if (c == 'f') { assert (vcount == new_vcount); int f0,f1,f2; fscanf (file,"%d %d %d",&f0,&f1,&f2); // indexed starting at 1... assert (f0 > 0 && f0 <= vcount); assert (f1 > 0 && f1 <= vcount); assert (f2 > 0 && f2 <= vcount); // ++++++++++++++++++++++++++++++++++++++++++++++++++++ // CALLING ASSIGNMENT 2 CODE // create a new triangle object and return it Triangle *t = new Triangle(verts[f0-1],verts[f1-1],verts[f2-1], current_object_color); // ++++++++++++++++++++++++++++++++++++++++++++++++++++ answer->addObject(new_fcount,t); new_fcount++; } // otherwise, must be whitespace } delete [] verts; assert (fcount == new_fcount); assert (vcount == new_vcount); fclose(file); return answer; } Transform* SceneParser::parseTransform() { char token[MAX_PARSER_TOKEN_LENGTH]; Matrix matrix; matrix.SetToIdentity(); Object3D *object = NULL; getToken(token); assert (!strcmp(token, "{")); // read in transformations: // apply to the LEFT side of the current matrix (so the first // transform in the list is the last applied to the object) getToken(token); while (1) { if (!strcmp(token,"Scale")) { getToken(token); assert (!strcmp(token, "{")); matrix *= Matrix::MakeScale(readVec3f()); getToken(token); assert (!strcmp(token, "}")); } else if (!strcmp(token,"XRotate")) { getToken(token); assert (!strcmp(token, "{")); matrix *= Matrix::MakeXRotation(DegreesToRadians(readFloat())); getToken(token); assert (!strcmp(token, "}")); } else if (!strcmp(token,"YRotate")) { getToken(token); assert (!strcmp(token, "{")); matrix *= Matrix::MakeYRotation(DegreesToRadians(readFloat())); getToken(token); assert (!strcmp(token, "}")); } else if (!strcmp(token,"ZRotate")) { getToken(token); assert (!strcmp(token, "{")); matrix *= Matrix::MakeZRotation(DegreesToRadians(readFloat())); getToken(token); assert (!strcmp(token, "}")); } else if (!strcmp(token,"Rotate")) { getToken(token); assert (!strcmp(token, "{")); Vec3f axis = readVec3f(); float degrees = readFloat(); matrix *= Matrix::MakeAxisRotation(axis,DegreesToRadians(degrees)); getToken(token); assert (!strcmp(token, "}")); } else if (!strcmp(token,"Translate")) { getToken(token); assert (!strcmp(token, "{")); matrix *= Matrix::MakeTranslation(readVec3f()); getToken(token); assert (!strcmp(token, "}")); } else if (!strcmp(token,"Matrix")) { Matrix matrix2; matrix2.SetToIdentity(); getToken(token); assert (!strcmp(token, "{")); for (int j = 0; j < 4; j++) { for (int i = 0; i < 4; i++) { float v = readFloat(); matrix2.Set(i,j,v); } } getToken(token); assert (!strcmp(token, "}")); matrix = matrix2 * matrix; } else { // otherwise this must be an object, // and there are no more transformations object = parseObject(token); break; } getToken(token); } assert(object != NULL); getToken(token); assert (!strcmp(token, "}")); // ++++++++++++++++++++++++++++++++++++++++++++++++++++ // CALLING ASSIGNMENT 2 CODE // create a new transform object and return it return new Transform(matrix, object); // ++++++++++++++++++++++++++++++++++++++++++++++++++++ } // ==================================================================== // ==================================================================== int SceneParser::getToken(char token[MAX_PARSER_TOKEN_LENGTH]) { // for simplicity, tokens must be separated by whitespace assert (file != NULL); int success = fscanf(file,"%s ",token); if (success == EOF) { token[0] = '\0'; return 0; } return 1; } Vec3f SceneParser::readVec3f() { float x,y,z; int count = fscanf(file,"%f %f %f",&x,&y,&z); if (count != 3) { printf ("Error trying to read 3 floats to make a Vec3f\n"); assert (0); } return Vec3f(x,y,z); } float SceneParser::readFloat() { float answer; int count = fscanf(file,"%f",&answer); if (count != 1) { printf ("Error trying to read 1 float\n"); assert (0); } return answer; } int SceneParser::readInt() { int answer; int count = fscanf(file,"%d",&answer); if (count != 1) { printf ("Error trying to read 1 int\n"); assert (0); } return answer; } // ==================================================================== // ====================================================================