Getting Started


To get going, you need to clone the repository we have set up for you on Gitlab that has been pre-populated with starter code. We will be using Git for source control. For more detailed information, refer to the git tutorial. In order to get the source code, follow the directions below:

Note: If git ever asks you for a username and password when you access the repo, that's because your ssh key is not loaded into the system. From git bash (windows) or the terminal (linux), type pwd. Then navigate to that directory and there should be a .ssh file. Copy your OpenSSH public key into that folder with the name id_rsa (windows) or id_rsa.pub (linux). To generate an ssh key on Windows, use puttygen (hit generate with default settings) and export as OpenSSH under Conversions. The git server also needs to know about your public key in order to allow you access. Go to gitlab, profile settings, SSH Keys and add yours in. See the link below for information on ssh keys for linux.

  1. Log on to Gitlab, and if you haven't already done so, add an ssh key
  2. Open 'Git Bash' on Windows (Search for it in the start menu if you are having trouble finding it)
  3. Navigate to the parent directory of where you would like your repository to live. We recommend putting it somewhere in your Z: drive
  4. Run the following command to make a local copy of your repository named 'impressionist'. You can find your repository on GitLab under the projects tab on the right side of your dashboard.

    $ git clone git@gitlab.cs.washington.edu:cse457-15au-impressionist/YOUR_REPO.git impressionist

  5. Open the project in Visual Studio. Build and run it. You should see a graphical interface with a lot of missing functionality. It will be your job to implement these features.
  6. After you've made some changes to the skeleton (perhaps you added a triangle brush), commit your files and push them so they are accessible to your partner or from a different machine.

    $ git add --all

    $ git commit -m "added a triangle brush"

    $ git push origin master

  7. If your partner has made changes, run

    $ git pull

    to update your copy of the repository with their changes before you start working to avoid merge conflicts.

Note: If you are having errors in the #include lines of any of your header files, copy over the fltk1.3.3 folder from C:\Program Files (x86)\ into C:\Program Files. This is an issue where the build is looking in the wrong folder.

Project Turn-in


Code Turn-in:

One partner needs to submit your binary and source code by the due date to the Catalyst Dropbox. You do not need to submit a detailed description of everything you did for the project, however we do ask that you include a readme that describes anything "out of the ordinary" you did for your project. This means anything that lies outside of the range of options on the project webpage and which you think merits consideration for extra credit. This does not include requirements or standard bells and whistles. If you did your development under Linux, please note that as well.

Your turnin should be a zip file containing two folders that looks like this:

binary/ [program].exe - Executable file compiled in release mode
Files needed by the executable - this includes textures, images, shaders, and other files
README.txt - only if you did anything out of ordinary
source/ Everything needed to compile and run your project
Please do not include the "debug/" and "release/" folders

The grading will consist of a staff member running your project right out of the binary directory and stepping through the features. We will verify the timestamp of the executable and consult source code as needed.

Note: Be sure to compile your executable in Release Mode

Important: Please download your uploaded .zip file and test running the program from the binary directory after turning it in.

Artifact Turn-in:

When you are done with a project, you and your partner will create a project "artifact" to show off the features of your program. For the Animator and Modeler projects, you and your partner will work together to submit one artifact for the group. For the Impressionist and Trace projects, you and your partner will work separately to submit one artifact each.

This is required. You will lose points if you do not submit at least something. We will not grade on artistic merit. However, after everyone submits their artifacts, we will create a gallery on the course website where you will vote on your favorite artifacts! The winner and runners-up will receive a small amount of extra credit. So be sure to try your best!

Instructional Lab


The main instructional lab for our course is CSE 022, in the basement of the Allen Center. As a registered student in the class, you should have access to this lab. Contact cardkey@cs if you are not able to enter the lab with your cardkey.

The computers are Windows 10 workstations. Applications are built using Visual C++, the FLTK UI toolkit, and OpenGL.

Rules for CSE 022:

In addition to the above rules, the Lab Community Committee has created a set of guidelines about general lab use. The main points are:

Please read the complete Lab Usage Guidelines.

Working from Home


  1. Make sure you have FLTK 1.3.3 installed on your computer. If you're running Windows and using Microsoft Visual Studio 2015, then you can download and run the FLTK Installer. Otherwise, you'll need to download and compile the FLTK source code.

  2. Download git on your machine.

  3. Follow the Getting Started steps above.

  4. You may need to point Visual Studio to the correct include and library directories for the FLTK that came in your repository (since normally it points to the local one on each lab machine).

  5. Open the .vcxproj file to load the project into Visual Studio.

Note: If you are having errors in the #include lines of any of your header files, copy over the fltk1.3.3 folder from C:\Program Files (x86)\ into C:\Program Files. This is an issue where the build is looking in the wrong folder.

Visual Studio 2015

Visual Studio is the Microsoft IDE for windows based development. We will use Visual Studio 2015 in the labs. You can find the community edition for free here.

Do you have the windows SDK too? If the Visual Studio install did not install the SDK, then you might run into errors of the sort gl.h ot glut.h not found. Installing the Windows SDK will help.

Fastlight Toolkit (FLTK)

FLTK is a C++ graphical user interface tookit for X(Unix), OpenGL and Microsoft Windows(Nt 4.0, 95, 98).

We won't cover much about FLTK in here, since we will be using FLUID to generate the FLTK source code. But it is good to learn the basic of FLTK so that you can be more familiar with Fluid later on. For this, refer to the to see the complete FLTK Programming Manual.

Installation on Windows

These directions are intended for advanced users. The course staff supports the graphics lab development environment, but if you would like to work elsewhere these directions may help. Your mileage may vary.

1. Install FLTK files

Note: You should not have to complete Steps 2 or 3 to get the project to work. They are here to try only if Step 1 fails.

2. Configure Visual Studio (MSVC)

3. Verify that your project is linking with the correct library

Installation on Linux

FLTK is already installed on instructional Linux systems (attu and the workstations in the Allen Center labs) in /usr, and on your own Linux system, before attempting to follow these instructions you should look for prepackaged binaries for your own distribution.

1. Install Mesa

As the first step, you must install MesaGL. To install it:

> gunzip MesaLib-3_0_tar.gz
> tar -xvf MesaLib-3_0_tar
> cd Mesa-3.0
> make linux-386
.....

Several minutes later, you will have libMesaGL.a and LibMesaGLU.a in Mesa-3.0/lib and a directory called GL in Mesa-3.0/include. I usually prefer to copy all these files into ~/local/lib and ~/local/include such that I can access all the libraries without remembering tons of paths.

2. Install Fltk

Now, we try to make fltk. You can get the source from here.

> gunzip fltk-1.3.3-source.tar.gz
> tar -xvf fltk-1.3.3-source.tar
> ./configure 
> make

Create a local directory in you home dir
Open makeinclude file and change the prefix variable to the your local
directory

> make install
> cp fltk-1.3.3/fluid/fluid ~/local/bin
> cp fltk-1.3.3/

You will have 'fluid' in ~/local/bin, 
two directories, FL and Fl, in include 
and libfltk.a in lib.

Now everyting is in ~/local, you need to change the value of the variable, $(LOCAL), in Makefile to ~/local.

Git Tutorial


Git is a modern version control system for managing the sharing and versioning of your source code. Git is a "distributed" version control system, as opposed to classical systems such as CVS and Subversion which are based on a single central repository. While distributed version control is very powerful, this tutorial will teach you to use git in a "client-server" fashion that mimics the classical version control systems that you may already be used to.

Git has many, many more advanced features than are presented in this tutorial. If you'd like to learn about them, git has a comprehensive set of man pages (man 1 git or git --help ), as well as the online Git Community Book. Try these references first if you get unexpected output or error messages from git commands.

Cloning the Repository

Log on to Gitlab, add an ssh key, and then find your group's repository under the Projects tab.

Click your repository's name, and at the top of the page there should be a string you can copy of the form git@gitlab.cs.washington.edu:cse457-15sp/YOUR_REPO.git, where YOUR_REPO is your group identifier.

Copy that string, and in a shell (such as Git Bash or Git Shell), run:

$ git clone copied_string

This will create a directory named YOUR_REPO in the current directory

We recommend renaming the local copy of the repository to something more descriptive, by running:

$ git clone copied_string descriptive_name

This will create a directory named descriptive_name in the current directory

If you are prompted to enter your password that means you haven't set up your ssh keys in gitlab properly. Do that now to avoid repeated password prompts as you push and pull things from gitlab.

Committing other changes to the repository

The commit and update process in git differs slightly from that of other version control systems that you may have used. To illustrate how it works, we'll make a minor change to one file and create a new file.

Copy the contents of pointBrush.h and paste into a new file called lineBrush.h. Replace all occurrences of 'point' with 'line'. In impressionistDoc.cpp, add lineBrush.h to the brush includes. (search for pointBrush.h if you're having trouble finding this)

Now run the git status command and observe its output:

$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)

    modified:   impressionistDoc.cpp

Untracked files:
(use "git add <file>..." to include in what will be committed)

    lineBrush.h

no changes added to commit (use "git add" and/or "git commit -a")

This output shows two things: first, you must explicitly add new ("untracked") files to the repository before they can be committed (as is true in other version control systems), and second, you must explicitly stage your changes before they will be committed (unlike subversion, which will automatically commit all of your changes if you just run svn commit). To further illustrate this, run the git commit command:

$ git commit -m "Adding the line brush header file."

This command will be a no-op: you should see the same output as from the git status command, ending in the same message: 'no changes added to commit (use "git add" and/or "git commit -a")'. To add your changes to the commit set, you must use the git add command on the changed files (whether they are new files or files already in the repository!):

$ git add impressionistDoc.cpp
$ git add lineBrush.h
$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes to be committed:
(use "git reset HEAD ..." to unstage)

    modified:   impressionistDoc.cpp
    new file:   lineBrush.h

You can see that the change to the impressionistDoc.cpp file and the addition of lineBrush.h have now been staged for the commit. To commit all of the changes that you have staged, run git commit:

$ git commit -m "Adding the line brush header file."
[master 41a5c0d] Adding the line brush header file.
2 files changed, 2 insertions(+), 0 deletions(-)
create mode 100644 lineBrush.h

Details

The -m argument to git commit is used to provide a commit message; if you forget to use it, then git will open a text editor for you to enter a commit message.

To make git behave more like subversion and automatically commit all of the changes you have made to files already in the repository (automatically commit all unstaged changes), use the -a flag with git commit. You may find, however, that the process of staging / unstaging changes is one of the most useful features of git: it allows you to make lots of changes to lots of files, but only commit the changes you want while leaving other files with in-progress changes uncommitted.

If you get a message like "file.c: needs merge" when you try to commit, then you have a conflict from a previous git pull that has not been resolved. See the Updating your local repository section below for more information about resolving conflicts.

However, at this point you have committed some changes, but your commit is not yet visible to the other users of the repository. git separates the notion of committing changes from the notion of "pushing" your update to the central repository. This can be useful for an individual developer that wants to make many changes to the code in many small logical commits before pushing all of them to the central repository, but for your CSE 457 projects you will probably just want to push after every commit.

To push your commits to the central repository, simply run git push:

$ git push
Counting objects: 4, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (4/4), 312 bytes | 0 bytes/s, done.
Total 4 (delta 0), reused 0 (delta 0)
To git@gitlab.cs.washington.edu:cse457-15sp-impressionist/YOUR_REPO.git
eb27358..c3615e1  master -> master
Notes:

Updating your local repository

To update your local copy of the repository with commits that other members of your group have made, simply use the git pull command. It will either show:

$ git pull

Already up-to-date.

or something like:

$ git pull
...
impressionistDoc.cpp                |    1 +
lineBrush.h                     |    1 +
2 files changed, 2 insertions(+), 0 deletions(-)
create mode 100644 lineBrush.h

git will not allow you to pull updates into your repository while you have unstaged changes. Therefore, you must stage (git add) and commit all of your changes before pulling. If you have changes that you don't want to make visible to your group yet (because they cause the build to break, for instance) but you still want to update your local repository, you can just commit your changes, do not push them yet, and pull the updates. Then, when your changes are ready, you can commit again and then push to the central repository.

As with any version control system, pulling updates from the central repository may cause conflicts with changes that you have committed locally. Pay attention to the output from your pull command for instructions to resolve conflicts; generally, resolving a conflict entails opening up the conflicted file(s) in your editor, finding the conflicts (surrounded by the text markers <<<<<<<, =======, and >>>>>>>), fixing the conflicting code, staging the changes (git add) and committing and pushing again. For more information about resolving conflicts, the github user manual has a useful webpage.

C++ Resources


OpenGL


OpenGL is a 2D/3D graphics library. It is based on IRIS GL, developed at Silicon Graphics for their high-end workstations. You can find more information about the OpenGL standard at www.opengl.org. This document is not a tutorial, but introduces some of the basic concepts of OpenGL that will be used in our projects, and provides pointers into the documentation.

OpenGL Conventions

All the functions in the OpenGL library have names beginning with "gl". Defined constants have names beginning with "GL_".

It common for there to be a family of functions for performing the same operation, differing only in the number and/or types of arguments accepted by each. The names of these functions have tags at the end to indicate the type of argument. The whole family will be referred to with a star syntax. For instance, glColor*() refers to any of the 32 functions available within OpenGL for setting the current color, including:

glColor3f( GLfloat, GLfloat, GLfloat )
glColor4d( GLdouble, GLdouble, GLdouble, GLdouble )
glColor3ubv( GLubyte* )

There is also a library of utility functions whose names all begin with "glu". These are simply convenience functions for doing some common tasks that take a few OpenGL commands to perform.

OpenGL as a State Machine

OpenGL keeps a large amount of state. It has many modes which can be switched on and off with the glEnable and glDisable commands. You should think of each function call as manipulating this state, rather than performing a specific drawing operation. To enable high performance, implementations of OpenGL are allowed to buffer commands almost arbitrarily. When you have sent some commands to OpenGL and want to be sure that the results actually appear on screen, call glFlush to force OpenGL to complete.

The OpenGL state is kept in a data structure called a rendering context. We will typically create one rendering context for each OpenGL window. This keeps state changes for drawing in one window from interfering with drawing in the other windows. Switching to another context is done by calling wglCurrentContex.

Drawing Primitives

Drawing in OpenGL consists of calling glBegin to tell OpenGL what you want to draw, then a series of calls to glVertex* to specify the geometry, then a call the glEnd to finish up. The single argument to glBegin tells it how to interpret the series of vertices you are going to throw at it. Here are some of the valid things to send to glBegin:

GL_POINTS draws each vertex as a point
GL_LINES draws a segment connecting the vertices 1 and 2, a segment connecting vertices 3 and 4, 5 and 6, and so on
GL_TRIANGLES draws the first three vertices as a triangle, the second group of three as another triangle, and so on
GL_POLYGON takes the vertices as a single, simple, convex polygon

There are several other options, see the manual for more explanation. Note that whenever you tell OpenGL to draw a polygon, it must be flat and convex. Triangles are easy, because they are always flat and convex, but with higher-order polygons you must be careful or your results will look wrong. Each polygon has a front side and a back side, which can be rendered differently if you choose. The front side is defined (by default) as the side from which the vertices appear in counterclockwise order.

The vertices you specify are coordinates in 3D space. They are transformed by the current modelview matrix, then by the current projection matrix to determine where they map to on the screen.

Note: Many OpenGL operations are not allowed between a glBegin and a glEnd, including all those listed under Matrix Stacks below. Used inappropriately an OpenGL function will likely fail silently. For basic 2D programs such as Impressionist glVertex* and glColor* will probably be the only two gl* functions used between a glBegin and a glEnd. You can use as much non-OpenGL code as you like, though.

Matrix Stacks

For a more detailed and helpful explanation, visit here.

Contained in the OpenGL state are two matrices which affect how geometry appears on the screen. The projection matrix determines the position and orientation of the camera. The modelview matrix is used to transform geometry before rendering it. In our projects, the projection matrix will typically be set up by the skeleton code. You will change the modelview matrix to affect how primitives are drawn on the screen.

The state maintains a stack for each matrix, with the top matrix being the one that is in force. You can thus make temporary changes by pushing a copy, altering the matrix, using it, then throwing it away with a pop. Since a full stack is maintained, you can nest these temporary changes to (almost) arbitrary depth. The useful commands for manipulating these stacks are:

glMatrixMode Selects which matrix stack is being manipulated, GL_PROJECTION or GL_MODELVIEW. (Actually, there is a third one for controlling texture mapping, but you can read about that in the manual.) The remaining commands all affect the currently selected matrix stack.
glLoadIdentity Replaces the top element of the stack with an identity matrix.
glPushMatrix Duplicates the top element of the matrix stack.
glPopMatrix Pops and discards the top element of the stack.
glTranslate*
glRotate*
glScale*
Composes the top element of the stack with a transformation.

Manipulating the Frame Buffer

Frequently you will want to copy around blocks of pixels, rather than drawing individual primitives like lines and polygons. You could do this by drawing individual GL_POINT objects, but that would be horrendously slow and inefficient. Instead, there is a set of OpenGL functions for copying blocks of pixels to and from the framebuffer.

glReadPixels, glDrawPixels read/write a block of pixels from/to the frame buffer
glReadBuffer, glDrawBuffer select which buffer is read/written
glPixelStore* specify how pixels read/written are arranged
glRasterPos* set the starting point for pixel write operations

Keep in mind that we will frequently be using a double-buffered framebuffer to provide smooth animation. With double-buffering, objects are typically drawn into the "back" buffer, which is then swapped with the front buffer (with the SwapBuffers function) to provide the illusion of instantaneous redrawing. It is important to understand which buffer you are reading or writing when doing block pixel operations.

GLTemplate and Examples

Here is GLTemplate, a sample Windows application that opens an OpenGL window and draws a colored triangle. You can use it to experiment with OpenGL calls. The methods you'll want to look at are OnDraw(), SetupGLParameters(), and SetupProjection() within the CGLTemplateView class.

Here is the source for example programs found in the OpenGL Programming Guide (Addison-Wesley Publishing Company). The examples will probably not run unless you are on a Silicon Graphics workstation, but reading the code can still be useful (and you can copy the code into GLTemplate to try it out). These examples are from the first edition of the Guide, so they may not correspond exactly to the second edition.

Adobe Premiere


This is a very brief overview of the steps needed to create an AVI file from a sequence of still images using Adobe Premiere.

Important: your sequence of still images needs to have the frame number embedded in the filename:

final_0001.bmp
final_0002.bmp
final_0003.bmp

and so on. Adobe Premiere will recognize these named files as part of a sequence that way.

  1. Start Adobe Premiere and let it start a new project for you (the default action).

  2. Right-click in the "Project" window and select "Import" from the menu that appears.

  3. Select the first of your sequence of images, and check the "Numbered Stills" box.

  4. Premiere will open the entire sequence of images and store them in the Premiere project window as one animation.

  5. Drag the animation from the Project window to the Timeline window, into the "Video 1" track.

  6. Adjust the work area slider (at the top of the Timeline window) so that its length equals that of the animation you just dragged there.

  7. Select "Enter" to preview the project. You will be prompted to save the project before previewing.

  8. To create the AVI, select "File --> Export --> Movie" and make sure "Microsoft AVI" is the type of animation file that will be created. Select the "Cinepak" codec and adjust the "Quality" slider to your liking. Also, the frame size can be adjusted -- for smoother playback, a smaller frame size, such as 320x240, should be selected.