Asg 7: Read in (parse) and display a simple A|W object

Objectives

Following Assignment 06, where the camera_t object is used to look at a simple plane, now replace the simple plane (list of point_t pointers) by an Alias|Wavefront object, e.g., a simple cube.

Assignment

  1. Use the C++ code from Assignment 06 to set up a 3D perspective projection and to manipulate the camera's viewpoint.
  2. Create an aw_t object that will be used to store the so-called B-REP (boundary representation) of a (hollow) 3D object. The aw_t object contains the following data objects: The interface and implementation for this object should be provided in separate header aw.h and implementation aw.cpp files.
  3. Create a vertex_t object that will be used to store the 3D coordinates of a vertex. This object is very similar to the point_t object used previously. The vertex_t object contains the following data objects: The interface and implementation for this object should be provided in separate header vertex.h and implementation vertex.cpp files.
  4. Create a face_t object that will be used to store the integer vertex indeces that index into the object's vertex list, basically a list of integers. The face_t object contains the following data objects: The interface and implementation for this object should be provided in separate header face.h and implementation face.cpp files.

Details

  1. Camera and OpenGL perspective details are the same as in Assignment 06.

Hints

  1. Notice that the indices stored in the data file number from 1..n whereas C/C++ lists, including the std::vector, are indexed 0..n-1.
  2. One of two trickiest parts of this assignment is the file parsing. You should look over previous code for reading the point_t object and follow that pattern. This time, when looping through the input, you will have to decide what is being read in: a vertex_t object, a face_t object, or the std::string object. Each of these is identified by the leading character, i.e., v, g, or f, respectively. Therefore, your parsing loop should read in a single character and then switch on that character to decide what to read in, e.g., with std::istream& s,
      while( s.get(c) && !s.eof() ) {
        switch(c) {
          case 'v':
            // read in vertex_t object
          break;
          case 'g':
            // read in group string
          break;
          case 'f':
            // read in face_t object
          break;
      }
    	
    For convenience, you should have each object read itself so that you are calling each object's operator>>.
  3. Another of the trickier parts of this assignment is rendering (drawing) of the object. Each face of the object is just a polygon, so that is drawn just like the plane of Assignment 06, with glBegin(GL_QUADS);. The tricky part is getting at the three x-, y-, and z-coordinates of each vertex for the call to glVertex3f.

    To do the above, you will need to

    Hint: see Assignment 02 and specifically how those coordinates were printed out (recall the (*the_points[i])[0] syntax).

Requirements

  1. Make sure to create a new vertex_t* each time a new vertex is read in (this gets added to the object's vertex list).
  2. Make sure to create a new face_t* each time a new face is read in (this gets added to the object's face list).
  3. Make sure that you properly delete the list of points by deleteing each point pointer as you erase each one from the list (i.e., when the program exits).

Input

  1. The cube-ccw.obj file used to test the above program is:
    v 1.0 1.0 1.0
    v 1.0 1.0 -1.0
    v 1.0 -1.0 1.0
    v 1.0 -1.0 -1.0
    v -1.0 1.0 1.0
    v -1.0 1.0 -1.0
    v -1.0 -1.0 1.0
    v -1.0 -1.0 -1.0
    g cube
    f 1 5 7 3
    f 2 1 3 4
    f 5 6 8 7
    f 6 2 4 8
    f 2 6 5 1
    f 8 4 3 7
    	
  2. An object is represented by a list of vertices, basically a list of 3D points similar to what was used previously to display a plane.
  3. Each vertex is now used in a list of faces (polygons) that define the spatial boundary of the object. For a cube, there are 6 quadrilaterals.
  4. Note that, in general, you cannot assume that all objects are composed of quads; they could be composed on n-sided faces, or polygons. You cannot therefore assume that each face will have 4 indices into the vertex list. There will be at least 3 and at most n where n is unknown. For this reason we use the STL std::vector containers, which keep track of the size of the list.

Output

  1. Expected output with the above input file is whatever you need to help you diagnose and debug the program, e.g.,:
    GL: 2.1 NVIDIA-10.2.1 310.41.15f01 NVIDIA Corporation
    number of verts read in: 8
    number of faces read in: 5
    *** printing object list
    v 1.0 1.0 1.0
    v 1.0 1.0 -1.0
    v 1.0 -1.0 1.0
    v 1.0 -1.0 -1.0
    v -1.0 1.0 1.0
    v -1.0 1.0 -1.0
    v -1.0 -1.0 1.0
    v -1.0 -1.0 -1.0
    g cube
    f 1 5 7 3
    f 2 1 3 4
    f 5 6 8 7
    f 6 2 4 8
    f 2 6 5 1
    	
    it is a good idea to print out the object parsed in, to make sure you can read the object data and then reproduce it by iterating through the vertex and face lists.

  2. When you have the object read in and stored properly, it should show up as below:

  3. See also:

Supplemental

  1. Here is a Makefile that you can use to compile the project:
    .SUFFIXES: .c .o .cpp .cc .cxx .C
    
    UNAME = $(shell uname)
    PLATFORM = $(shell uname -p)
    
    CC = g++
    COPTS = -g -Wall
    
    INCDIR =
    LIBDIR =
    
    ifeq ("$(shell uname)", "Linux")
    INC = \
      -I/usr/lib/glut-3.7/include
    LIBDIR = \
      -L/usr/lib -L/usr/X11R6/lib -L/usr/lib/glut-3.7/lib/glut
    LIBS = \
      -lglut -lGLU -lGL -lXmu -lXi -lXext -lX11 -lm
    else
    ifeq ("$(shell uname)", "Darwin")
    LIBS = \
      -framework OpenGL -framework GLUT -framework Foundation -lstdc++
    endif
    endif
    
    .c.o:
    	$(CC) -c $(INCDIR) $(COPTS) -o $@ $<
    
    .cpp.o:
    	$(CC) -c $(INCDIR) $(COPTS) -o $@ $<
    
    all : main
    
    OBJECTS = \
    point.o \
    face.o \
    vertex.o \
    aw.o \
    camera.o
    
    main : $(OBJECTS) main.o
    	$(CC) -o $@ $(INCDIR) $(COPTS) $(OBJECTS) $@.o $(LIBDIR) $(LIBS)
    
    point.o: point.h point.cpp
    
    clean :
    	rm -f *.o
    	rm -rf main
    	

Turn in

Turn in all of your code, in one tar.gz archive of your asg##/ directory, including:
  1. A README file containing
    1. Course id--section no
    2. Name
    3. Brief solution description (e.g., program design, description of algorithm, etc., however appropriate).
    4. Lessons learned, identified interesting features of your program
    5. Any special usage instructions
  2. Makefile
  3. source code (.h headers and .cpp source)
  4. object code (do a make clean before tar)

How to hand in

See handin notes

Grading scheme