Kinesia Online Course
Computer Graphics
Kinesia LLC, 2003

    1. Introduction
    2. Line Drawing
    3. Drawing Objects
    4. More Drawing Tools
    5. Normal Vectors and Polygonal Models of Surfaces
    6. Viewing I -- Affine Transformations
    7. Viewing II -- Projections
    8. Color
    9. Lighting
    10. Blending, antialiasing, fog ..
    11. Display Lists, Bitmaps and Images
    12. Texture Mapping
    13. Curves and Surfaces
    14. Games and SDL

    Line Drawing

    1. Bresenham's Line Algorithm

    2. Assume: y = mx + b
       

    3. Given two endpoints ( x0, y0 ), ( xn, yn ) we can choose the start point ( xk, yk )
    4. We want to decide what's the next pixel to draw; we have eight choices. ( Why? )
    5. Assume 0 ≤ m ≤ 1 and x0 < xn
      • Our choices are either ( xk + 1, yk ) or ( xk + 1, yk + 1 )
      • Let
        dlower = y - yk
          = m ( xk + 1 ) + b - yk
        and
        dupper = ( yk + 1 ) - y
          = yk + 1 - m ( xk + 1 ) - b
      • To determine which one is closer to the line path:
        dupper - dlower = 2m ( xk + 1 ) - 2 yk + 2b - 1

        Let m = ( yn - y0 ) / ( xn - x0 ) = Δy / Δx

        Define the decision parameter as

        pk = Δx ( dlower - dupper )
          = 2Δy.xk - 2Δx.yk + c     ----- ( 1 )
        where c = 2Δy + Δx ( 2b - 1 ) is a constant ( independent of pixel position )

        Therefore,

        pk+1 - pk = 2Δy ( xk+1 - xk ) 2Δx ( yk+1 - yk ) But, xk+1 = xk + 1 So, pk+1 = pk + 2Δy - 2Δx ( yk+1 - yk )     ---- ( 2 ) with p0 = 2Δy - Δx

        In ( 2 ) , yk+1 - yk is either 0 or 1, depending on the sign of pk. From ( 1 ), as Δx >0, if the pixel at yk is closer to the line path than at yk + 1 (i.e. dlower < dupper ), pk is negative and we choose the next pixel to be the lower pixel; otherwise we choose the upper pixel.

      Brensenham's Line Drawing algorithm for |m| < 1

      1. Input two endpoints ( x0, y0 ), ( xn, yn ) where ( x0, y0 ) is the left endpoint.
      2. Plot ( x0, y0 ) as first point.
      3. Calculate Δx, Δy and p0 = 2Δy - Δx
      4. Start with k = 0, perform the test:
        If pk < 0, the next point to plot is ( xk +1, yk ) and pk+1 = pk + 2 Δy
        otherwise, the next point to plot is ( xk +1, yk + 1) and pk+1 = pk + 2 Δy - 2 Δx
      5. Perform step 4 Δx - 1 times.
    6. SDL Library
      /*
        draws a line from current point to new point using Bresenham algorithm
        surf is the SDL_Surface of the class
      */
      void Surface:: lineTo( int x1, int y1 )
      {
          Uint16 *buffer;
          int drawpos;
          int xspan, yspan;
          int xinc, yinc, x0, y0;
          int sum;
          int i;
      
          /* If we need to lock this surface before drawing pixels, do so. */
          if (SDL_MUSTLOCK( surf )) {
      	if (SDL_LockSurface(surf) < 0) {
      	    printf("Error locking surface: %s\n", SDL_GetError());
      	    abort();
      	}
          }
      
          /* Get the surface's data pointer. */
          buffer = (Uint16 *)surf->pixels;
      	
          x0 = CP.x;	y0 = CP.y;
         //here's the Brensenham's algorithm, it draws from ( x0, y0 ) to ( x1, y1 )
      
          /* Calculate the x and y spans of the line. */
          xspan = x1-x0+1;
          yspan = y1-y0+1;
      	
          /* Figure out the correct increment for the major axis.
             Account for negative spans (x1 < x0, for instance). */
          if (xspan < 0) {
      	xinc = -1;
      	xspan = -xspan;
          } else xinc = 1;
      
          if (yspan < 0) {
      	yinc = -surf->pitch/2;
      	yspan = -yspan;
          } else yinc = surf->pitch/2;
      	
          i = 0;
          sum = 0;
      	
          /* This is our current offset into the buffer. We use this
             variable so that we don't have to calculate the offset at
             each step; we simply increment this by the correct amount.
      
             Instead of adding 1 to the x coordinate, we add one to drawpos.
             Instead of adding 1 to the y coordinate, we add the surface's
             pitch (scanline width) to drawpos. */
          drawpos = surf->pitch/2 * y0 + x0;
      	
          /* Our loop will be different depending on the
             major axis. */
          if (xspan < yspan) {
      
      	/* Loop through each pixel along the major axis. */
      	for (i = 0; i < yspan; i++) {
      
      	    /* Draw the pixel. */
      	    buffer[drawpos] = color;
      
      	    /* Update the incremental division. */
      	    sum += xspan;
      
      	    /* If we've reached the dividend, advance
      	       and reset. */
      	    if (sum >= yspan) {
      		drawpos += xinc;
      		sum -= yspan;
      	    }
      
      	    /* Increment the drawing position. */
      	    drawpos += yinc;
      	}
          } else {
      	/* See comments above. This code is equivalent. */
      	for (i = 0; i < xspan; i++) {
      
      	    buffer[drawpos] = color;
      			
      	    sum += yspan;
      
      	    if (sum >= xspan) {
      		drawpos += yinc;
      		sum -= xspan;
      	    }
      
      	    drawpos += xinc;
      	}
          }
          CP.set ( x1, y1 );		//set new CP position
          /* Unlock the surface. */
          SDL_UnlockSurface(surf);
      }
      

    7. Turtle Graphics

      Turtle graphics is a style of computer drawing based on preserved state (position and orientation) and a small number of operations against that state (forward, turn, pen up & down).
      The state was called the turtle and programs taught the turtle how to draw.
      Easy for kids to pick up.

      You can apply turtle graphics to draw fractals

        to draw-a-box 
      	forward 10
      	turn 90
      	forward 10
      	turn 90
      	forward 10
      	turn 90
      	forward 10
      	turn 90
      
        to draw-a-window
      	draw-a-box
      	turn 90
      	draw-a-box
      	turn 90
      	draw-a-box
      	turn 90
      	draw-a-box
        	turn 90
        
       

      A coding example: drawing a hook

      void Canvas::forward ( float dist, int isVisible )
      {
        const float RadPerDeg = 0.017453393;          //radians per degree
        float x = CP.getX() + dist * cos ( RadPerDeg * CD );
        float y = CP.getY() + dist * sin ( RadPerDeg * CD );
        if ( isVisible )
          lineTo( x, y );
        else
          moveTo ( x, y );
      }//forward
        
      //L is length of short side
      void draw_hook( float L )
      {
        cvs.forward( 3*L, 1 );
        cvs.turn( 90 );
        cvs.forward( L, 1 );
        cvs.turn( 90 );
        cvs.forward( L, 1 );
        cvs.turn( 90 );
      }
       
      void display(void)
      {
        cvs.clearScreen();
       
        cvs.moveTo(0.0, 0.0); //starts at center
        cvs.turnTo ( 0.0 );   //points horizontally
        draw_hook ( 0.5 );
      }
        

      Some Programming Examples

      Class exercise:

      Use turtle graphics to draw a star pattern.