/***********************
 * assignment1.c shell *
 ****************************************************************
 * written 12/16/95                                             *
 * by Andy Johnson                                              *
 ****************************************************************
 * this is the shell for the first EECS 488 Spring 96 assignment*
 * written in Mesa (OpenGL.)                                    *
 *                                                              *
 * this program has a VERY primitive window interface to try    *
 * and keep things as simple as possible, so while you can move *
 * the window, trying to resize it will not do you much good    *
 ****************************************************************/
 
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "glaux.h"


/****************************************************************/

#define WIDTH  400 /* width of the window and user's frame buffer */
#define HEIGHT 300 /* height of the window and user's frame buffer */

#define OUTLINE 0 /* outline drawing mode */
#define FILLED  1 /* filled drawing mode */


/****************************************************************/

static void initializeGraphics(char *);
static void initializeBuffer(void);
static void outlineIntoBuffer(void);
static void fillIntoBuffer(void);
static void displayBuffer(void);
static void changeView(void);
static void key_esc(void);
static void Reshape(int width, int height);
static void display(void);


/****************************************************************/
/* Global Variables
 * 
 * YES,  THESE ARE BAD, SHOULDN'T USE THEM, BAD FOR ALL KINDS OF
 * REASONS,  BUT THIS PROGRAM IS NASTY ENOUGH WITHOUT PASSING
 * ARRAYS AROUND,  AND HEY I HAVE A PHD SO I'M ALLOWED TO USE THEM.
 */

int outlineOrFilled = OUTLINE;	/* current drawing mode */

float myFrameBuffer[HEIGHT][WIDTH];  /* user's frame buffer */


/****************************************************************
 * INITIALIZEGRAPHICS
 * 
 * function to initialize the graphics
 * 
 * input: windowName - name of window to be opened
 * no outputs
 ****************************************************************/

static void initializeGraphics(char * windowName)
    {
    /* create a single-buffered RGBA window of size WIDTH by HEIGHT
     * located at 0, 0. If this window can not be created then exit
     * the program
     */

    auxInitDisplayMode(AUX_SINGLE | AUX_RGBA);
    auxInitPosition( 0,0, WIDTH, HEIGHT);
    if (auxInitWindow(windowName) == GL_FALSE)
	{
	fprintf(stderr, "could not open a window\n");
	auxQuit();
	}


    /* clear the background of the window to black and set up
     * the window for orthographics viewing. 
     */

    glClearColor( 0.0, 0.0, 0.0, 0.0);
    glClear( GL_COLOR_BUFFER_BIT );
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho( -1.0, 1.0, -1.0, 1.0, -1.0, 1.0 );
    }

/****************************************************************
 * INITIALIZEBUFFER
 * 
 * function to initialize the user's frame buffer
 * 
 * no inputs
 * no outputs
 ****************************************************************/

static void initializeBuffer()
    {
    int columnCounter;
    int rowCounter;

    /* set the user's frame buffer to be all 0s - black
     */

    for(columnCounter=0;columnCounter<WIDTH;columnCounter++)   
	for(rowCounter=0;rowCounter<HEIGHT;rowCounter++)   
	    myFrameBuffer[rowCounter][columnCounter] = 0;
    }
    
/****************************************************************
 * OUTLINEINTOBUFFER
 * 
 * function to draw the outline of the polygon in the user's frame buffer
 * 
 * no inputs
 * no outputs
 ****************************************************************/

static void outlineIntoBuffer()
    {
    int columnCounter;
    int rowCounter;

    /* MUCH OF YOUR WORK WILL BE DONE HERE, IN THIS FUNCTION
     * AND IN OTHER FUNCTIONS CALLED BY THIS FUNCTION
     */

    /* AS AN EXAMPLE, THE FOLLOWING CODE DRAWS A SMALL BORDER WITHIN
     * THE USER'S FRAME BUFFER. YOU WILL WANT TO REPLACE THIS CODE WITH
     * CODE TO DRAW THE OUTLINE OF THE POLYGON YOU READ IN.
     * 
     * REMEMBER THAT THE FRAMEBUFFER HAS 0, 0 IN THE LOWER LEFT HAND
     * CORNER
     */
  	    
    /* draw the top border */
    for(columnCounter=10;columnCounter<=WIDTH-10;columnCounter++)
	myFrameBuffer[HEIGHT-10][columnCounter] = 1;

    /* draw the bottom border */
    for(columnCounter=10;columnCounter<=WIDTH-10;columnCounter++)
	myFrameBuffer[10][columnCounter] = 1;

    /* draw the left border */
    for(rowCounter=10;rowCounter<=HEIGHT-10;rowCounter++)
	myFrameBuffer[rowCounter][10] = 1;
	
    /* draw the right border */
    for(rowCounter=10;rowCounter<=HEIGHT-10;rowCounter++)
	myFrameBuffer[rowCounter][WIDTH-10] = 1;

    }

/****************************************************************
 * FILLINTOBUFFER
 * 
 * function to fill the polygon in the user's frame buffer
 * 
 * no inputs
 * no outputs
 ****************************************************************/

static void fillIntoBuffer()
    {
    int columnCounter;
    int rowCounter;

    /* MUCH OF YOUR WORK WILL BE DONE HERE, IN THIS FUNCTION
     * AND IN OTHER FUNCTIONS CALLED BY THIS FUNCTION
     */

    /* AS AN EXAMPLE, THE FOLLOWING CODE FILLS THE SMALL BORDER WITHIN
     * THE USER'S FRAME BUFFER. YOU WILL WANT TO REPLACE THIS CODE WITH
     * CODE TO FILL THE POLYGON DRAWN PREVIOUSLY.
     * 
     * REMEMBER THAT THE FRAMEBUFFER HAS 0, 0 IN THE LOWER LEFT HAND
     * CORNER
     */
  	    
    /* fill in the border with a nice gradient fill
     * you can fill with a solid white (1.0)
     */
     
    for(rowCounter=10;rowCounter<=HEIGHT-10;rowCounter++)
	for(columnCounter=10;columnCounter<=WIDTH-10;columnCounter++)
	    myFrameBuffer[rowCounter][columnCounter] =
		(float) (rowCounter+columnCounter)/(WIDTH+HEIGHT);
    }
    
/****************************************************************
 * DISPLAYBUFFER
 * 
 * function to copy the array into the frame buffer
 * 
 * no inputs
 * no outputs
 ****************************************************************/

static void displayBuffer()
    {
    /* set the current raster position to the lower left hand corner
     * of the window
     */
     
    glRasterPos2i(-1, -1);
    
    
    /* copy the user's framebuffer array into the actual frame buffer
     * treating each value in the array as a luminance (greyscale) value
     * with 0.0 = black and 1.0 = white
     */
    
    glDrawPixels(WIDTH, HEIGHT, GL_LUMINANCE, GL_FLOAT, myFrameBuffer);


    /* force all unfinished graphics commands to execute */

    glFlush();
    }


/****************************************************************
 * CHANGEVIEW
 * 
 * the space bar is used to switch mdoes in this program. The
 * program initially shows the outline of the polygons. When the
 * user presses the space bar the polygon should be filled. When
 * the user presses the space bar again the program halts.
 * 
 * no inputs
 * no outputs
 ****************************************************************/

static void changeView()
    {
    switch(outlineOrFilled){
	case OUTLINE:	outlineOrFilled = FILLED;
			fillIntoBuffer();
			break;
			
	case FILLED:	auxQuit();
			break;
	}
    }

/****************************************************************
 * KEY_ESC
 * 
 * whenever the escape key is pressed while focus is on this
 * process' window the program will halt
 * 
 * no inputs
 * no outputs
 ****************************************************************/

/*
static void key_esc()
    {
    auxQuit();
    }
*/

/****************************************************************
 * RESHAPE
 * 
 * whenever the window is shrunk or expanded this function is
 * called to update the contents of the window. In this case this
 * function does nothing when the window is reshaped
 * 
 * inputs: new width and height of the window
 * no outputs
 ****************************************************************/

static void reshape( int width, int height )
    {
    /* not doing anything when the window is reshaped */
    }
    
/****************************************************************
 * DISPLAY
 * 
 * the function call within is called to update the 
 * contents of the window. In this case it calls the
 * function which copies the user's frame buffer into the
 * actual frame buffer
 * 
 * no inputs
 * no outputs
 ****************************************************************/

static void display( void )
    {	
    displayBuffer();
    }

/****************************************************************
 * MAIN
 * 
 * function to copy the array into the frame buffer
 * 
 * inputs: command line arguments
 * outputs: 0 if program exited properly
 ****************************************************************/

int main( int argc, char **argv )
    {
    /* YOU WILL PROBABLY ALSO NEED TO MODIFY MAIN SOMEWHAT TO DEAL
     * WITH THE DATA FILE YOU WILL BE READING IN
     */

    initializeGraphics(argv[0]);
    
    /* YOU WILL PROBABLY WANT SOME FUNCTION CALL HERE TO READ
     * IN THE VERTICES FROM THE DATA FILE
     */
   
    initializeBuffer();
    outlineIntoBuffer();
  

    /* display the window until the user kills it
     * 
     * THIS CODE ALLOWS INTERATION WITH THE WINDOWING SYSTEM
     * DECLARING WHICH FUNCTIONS SHOULD BE CALLED WHEN THE WINDOW
     * MUST BE UPDATED OR THERE IS INPUT FROM THE KEYBOARD OR MOUSE
     */
    
    auxExposeFunc(reshape);
    auxReshapeFunc(reshape);
    auxKeyFunc( AUX_SPACE, changeView );
    auxMainLoop( display );

 
    return 0;
}
