#include "srgp.h"
#include <stdio.h>
#include <math.h>

/* This thing simply draws lines, doing the scan conversion itself
   rather than letting SRGP do it.
   When the left mouse button is depressed and released somewhere else,
   we use the algorithm of Program 3.1.
   When the middle mouse button is depressed and released somewhere
   else, we use the algorithm of Program 3.2.
   When the right mouse button is depressed and released somewhere
   else, we use my incremental Manhattan algorithm.
   To stop the program, press any key on the keyboard, or press two
   different mouse keys at once. */

#define LM   locator_measure

#define NORMALIZE \
   if (x0 > x1) {	\
      xt = x0;	\
      x0 = x1;	\
      x1 = xt;	\
      yt = y0;	\
      y0 = y1;	\
      y1 = yt;	\
      }

void Line1 (int x0, int y0, int x1, int y1) {
/* Should work for all nonvertical lines. */
   int xt, yt;
   int x, yi;
   double dx,dy,y,m;

   NORMALIZE

   dy = y1 - y0;
   dx = x1 - x0;
   m = dy / dx;
   y = y0;
   for (x = x0; x <= x1; x++) {
      yi = (int)(floor(y+0.5));
      SRGP_pointCoord (x,yi);
      y += m;
      }
   }

void Line2 (int x0, int y0, int x1, int y1) {
/* Works for slopes between 0 and 1. */
   int xt, yt;
   int dx, dy, incrE, incrNE, d, x, y;

   NORMALIZE

   dx = x1 - x0;
   dy = y1 - y0;
   d = dy * 2 - dx;
   incrE = dy * 2;
   incrNE = (dy - dx) *2;
   y = y0;
   for (x = x0; x <= x1; x++) {
      SRGP_pointCoord (x, y);
      if (d <= 0)
         d += incrE;
      else {
         d += incrNE;
         y++;
         }
      }
   }

void Line3 (int x0, int y0, int x1, int y1) {
/* Works for slopes between 0 and 1. */
   int xt, yt;
   int d, x, y, dx, dy;

   NORMALIZE

   dx = x1 - x0;
   dy = y1 - y0;
   d = dy * 2 - dx;
   y = y0;
   for (x = x0; x <= x1; x++) {
      SRGP_pointCoord (x, y);
      if (d <= 0)
         d++;
      else {
         y++; d--;
         }
      }
   }

void Line4 (int x0, int y0, int x1, int y1) {
/* Works for all positive slopes. */
   int xt, yt;
   int x,y;

   NORMALIZE

   x = x0;
   y = y0;

   while (x < x1 || y < y1) {
      SRGP_pointCoord (x,y);
      if ((x1-x) > 2*(y1-y))
         x++;
      else if ((y1-y) > 2*(x1-x))
         y++;
      else {
         x++;y++;
         }
      }
   }

main()
{
   LM oldmeasure, newmeasure;
   inputDevice theDevice;
   int which;

   SRGP_begin ("scan conversion demonstration", 800,800,3,FALSE);

   SRGP_useCanvas (SCREEN_CANVAS);
   SRGP_setLocatorEchoType (CURSOR);
   SRGP_setFillStyle(SOLID); 
   SRGP_setWriteMode (WRITE_REPLACE);
   SRGP_setLocatorButtonMask
      (LEFT_BUTTON_MASK | MIDDLE_BUTTON_MASK | RIGHT_BUTTON_MASK);
   SRGP_setInputMode(LOCATOR, EVENT);
   SRGP_setInputMode(KEYBOARD, EVENT);
   SRGP_setKeyboardProcessingMode (RAW);

   while (1) {
      theDevice = SRGP_waitEvent (INDEFINITE);
      if (theDevice == KEYBOARD) break;
      SRGP_getLocator (&oldmeasure);
      which = oldmeasure.button_of_last_transition;

      theDevice = SRGP_waitEvent (INDEFINITE);
      if (theDevice == KEYBOARD) break;
      SRGP_getLocator (&newmeasure);
      if (which != newmeasure.button_of_last_transition) break;

      switch (which) {
	case LEFT_BUTTON: {
	   Line1 (oldmeasure.position.x,
		  oldmeasure.position.y,
		  newmeasure.position.x,
		  newmeasure.position.y);
	   break;
	   }
	case MIDDLE_BUTTON: {
	   Line2 (oldmeasure.position.x,
		  oldmeasure.position.y,
		  newmeasure.position.x,
		  newmeasure.position.y);
	   break;
	   }
	case RIGHT_BUTTON: {
	   Line4 (oldmeasure.position.x,
		  oldmeasure.position.y,
		  newmeasure.position.x,
		  newmeasure.position.y);
	   break;
	   }
	}
      }
   }
