Assignment 3: Green eggs and Bresenham

Due in two parts on Thursday, Feb 16th and Thursday, 23rd, before midnight

The goals for this assignment are:

  • Implement an canvas class capable of drawing lines and simple shapes

  • Implement a procedural artwork using your canvas class

1. Getting started

Clone your copy of the repository to your own computer. To build,

Don’t forget to do an "out of source" build and run cmake .. from the /build directory!
$ git clone git@github.com:<username>/canvas-drawer.git
$ cd canvas-drawer
$ mkdir build
$ cd build
$ cmake ..
$ make (or start canvas-drawer.sln)
$ ../bin/draw_test (or ../bin/Debug/draw_test from the developer console in Visual Studio)
$ ../bin/draw_art (or ../bin/Debug/draw_art from the developer console in Visual Studio)

2. Canvas class

Implement a class canvas, which can draw lines and triangles on a raster image. This class mirrors the APIs found in OpenGL 1.0 and Processing See the beginShape for an example that is similar to what you are building for this assignment.

The canvas class implements a state machine based API for drawing lines and triangles of different colors. For example, the following code creates a canvas with size (100,100) and draws a red line followed by a green line.

Canvas drawer(100, 100);
drawer.background(0,0,0);

drawer.begin(LINES);

drawer.color(255,0,0);
drawer.vertex(0,0);
drawer.vertex(100,0);

drawer.color(0,255,0);
drawer.vertex(0, 0);
drawer.vertex(0,100);

drawer.end();

You are given basecode in canvas.h and canvas.cpp to use as a starting point. You are also given a raster image class, Image defined in image.h and image.cpp. You should replace this class with your implementation from last week.

You may add any supporting methods and member variables to implement your class. For example, you might want to add member variables to store the current primitive or color. Or you might want to add functions to draw lines and triangles.

3. draw_test (Due 2/16)

Due Feb 16th, by midnight

In canvas.h and canvas.cpp, implement the following methods in Canvas.

  • begin(PrimitiveType type) indicates that the following vertices correspond to a shape

  • end() indicates that all vertices have been specified and we should draw the primitive

  • vertex(int x, int y) specifies a vertex. Vertex positions should be clipped to the size of the raster image.

  • color(unsigned char r, unsigned char g, unsigned char b) specifies a color. All vertices specified after this call should have the given color.

  • background(unsigned char r, unsigned char g, unsigned char b) fills the canvas with a given color

3.1. Walkthrough and tips

Use draw_test.cpp to test the core functionality of your canvas

3.1.1. Line drawing

The following code should produce the images below.

drawer.color(255, 255, 255);
test_line(drawer, 0, 50, 100, 50, "horizontal-line.png");
test_line(drawer, 50, 0, 50, 100, "vertical-line.png");
test_line(drawer, 0, 0, 100, 100, "diagonal-line-1.png");
test_line(drawer, 25, 10, 75, 25,  "h-lessthan-w-line-1.png");
test_line(drawer, 25, 25, 75, 75,  "w-lessthan-h-line-1.png");
test_line(drawer, 0, 100, 100, 0, "diagonal-line-2.png");
test_line(drawer, 25, 90, 75, 75,  "h-lessthan-w-line-2.png");
test_line(drawer, 25, 90, 75, 25,  "w-lessthan-h-line-2.png");
horizontal line
vertical line
diagonal line 1
h lessthan w line 1
w lessthan h line 1
diagonal line 2
h lessthan w line 2
w lessthan h line 2

3.1.2. Interpolated line colors

The following code should produce the image below.

// test line interpolation
drawer.background(0, 0, 0);
drawer.begin(LINES);
drawer.color(255, 0, 255);
drawer.vertex(0, 0);
drawer.color(0, 255, 255);
drawer.vertex(100, 100);
drawer.end();
drawer.save("line-color-interpolation.png");
line color interpolation

3.1.3. Triangles

The following code should produce the image below.

// test triangle with interpolation
drawer.background(0, 0, 0);
drawer.begin(TRIANGLES);
drawer.color(255, 0, 255);
drawer.vertex(10, 0);
drawer.color(0, 255, 255);
drawer.vertex(90, 50);
drawer.color(255, 255, 0);
drawer.vertex(10, 90);
drawer.end();
drawer.save("triangle.png");
triangle

3.1.4. Composite shapes

The following code should produce the image below.

// test quad with interpolation
drawer.background(0, 0, 0);
drawer.begin(TRIANGLES);
drawer.color(255, 0, 255);
drawer.vertex(10, 10);
drawer.vertex(10, 90);
drawer.vertex(90, 90);

drawer.color(255, 255, 0);
drawer.vertex(90, 90);
drawer.vertex(90, 10);
drawer.vertex(10, 10);
drawer.end();
drawer.save("quad.png");
quad

4. draw_art (Due 2/23)

Due Feb 23rd

Implement at least 4 additional canvas features. Feel free to come up with your own ideas. Here are suggestions:

  • Make it easy for the user to draw different shapes

    • Circle: draw a circle with given position and radius

    • Rectangle: draw a rectangle with given center, width, and height

    • Star: draw a star shape

    • Flower, or other shapes using rose curves

  • Let the user set line widths

  • Add a point primitive

  • Support both filled shapes and outlined shapes

  • Support different blend modes, such as add, difference, and multiply

  • make it easy for users to specify gradients

  • Support alpha blending

4.1. Create a unique image

In the program, draw_art.cpp, use multiple effects to create one or more unique images. Feel free to be creative and use operations from the previous assignment. For example, additive blending can be used to create glowing objects.

Make sure to use your custom operations from the previous question in your artworks!! You will not get credit for operators which you don’t test and show work correctly!

Ideas for procedural patterns might be based on spirograph, random numbers and noise, gradients, or color palettes.

Below we create random circles and use the y position to determine its color using a gradient from yellow to cyan. This image also implements both a circle and circle outline.

RandomCircles

The image below creates random stars and colors the background with a gradient using triangles.

Sky

We can also use curves and flow fields to generate patterns. The following image draws line between two points which trace out a rose curve. We use additive blending with the current pixel color to do the coloring.

Rose7

We add noise to the points to get other, more organic, shapes. For this type of effect, a semi-random number which varies smoother often gives better results. Below I use

float noise(float t)
{
   float v = sin(t) * 1175.5453123;
   return v - int(v);
}
Rose8

5. Update Readme.md

Update Readme.md to include documentation on your unique features and art created with your class.

6. What to hand in

  1. Your code. Make sure your code is checked into github

  2. One or more images created using your software

  3. Update Readme.md so it includes a writeup of the features your application supports

7. Grading rubric

Grades each week are out of 4 points.

  • (4 points) Milestone #1

    • (1 points) Correct implementation of the interface

    • (2 points) Drawing lines (all cases correct)

    • (1 points) Rasterizing triangles with edge case handling

  • (4 points) Milestone #2

    • (2.0 points) no memory errors

    • (1.0 points) readme and unique images/demos

    • (0.2 points) style and header comment

    • (0.8 points) unique features

Code rubrics

For full credit, your C++ programs must be feature-complete, robust (e.g. run without memory errors or crashing) and have good style. Some credit lost for missing features or bugs, depending on severity of error

-5% for style errors. See the class coding style here. -50% for memory errors -100% for failure to checkin work to Github -100% for failure to compile on linux using make