Files
GTSchoolShit/CS4451/proj3/main.cpp
2025-06-07 01:59:34 -04:00

663 lines
16 KiB
C++

//C Stuff
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <math.h>
#include <time.h>
//OpenGL Stuff
#include <GL/glut.h>
#define VPD_MIN 200
#define VPD_DEFAULT 800
#define VPD_MAX 1024
#define ORTHO_SIZE 1.0
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif
#define TWOPI (2.0 * M_PI)
/*
* For some godforsaken reason, rand() is returning negative numbers in
* FreeBSD and Linux.
*
* Hence this.
*/
inline float RANDNUM() {
float f = (float)( (float)rand() / (float)(RAND_MAX+1) );
if (f < 0) {
return -1.*f;
}
return f;
}
enum MENU { MENU_LINES=0,
MENU_TRIANGLES,
MENU_SPRAY_MORE_POINTS,
MENU_RESET,
MENU_RANDOMIZE,
MENU_ANIMATE,
MENU_DRAWSITES,
MENU_SITECOLORBLACK,
MENU_INCREASE_SITE_SIZE,
MENU_DECREASE_SITE_SIZE,
MENU_DRAWING,
MENU_UNCAP_FPS,
MENU_RESET_FPS,
MENU_DECREASE_MAX_FPS
};
typedef struct SRGB {
float r;
float g;
float b;
} RGB;
typedef struct SSite {
RGB color;
float x;
float y;
float angle;
float angularVelocity;
float radius;
} Site;
typedef struct _rgb {
unsigned char r,g,b;
} ppm_rgb;
typedef struct _ppmimage {
int sizex,sizey;
ppm_rgb *color;
} ppmimage;
//////////////////
// Global STUFF //
//////////////////
#define DEFAULT_NUMPOINTS 64
#define DEFAULT_RANDSITES 32
#define DEFAULT_SITEWIDTH ORTHO_SIZE*.0025
#define DEFAULT_FPS .00825;
GLint wid; // GLUT window id
GLint vpd = VPD_DEFAULT; // (square) viewport dimensions
GLuint cone; //Cone display list
GLuint numPoints = DEFAULT_NUMPOINTS; //number of points for the cone fan
GLuint randSites = DEFAULT_RANDSITES; //The number of random points to draw from
bool animate = false; //whether the world is animated or not
bool drawSites = true; //whether or not to draw sites
bool siteColorBlack = true; //defines whether sites will be drawn as black or not
float siteWidth = DEFAULT_SITEWIDTH; //siteWidth for the rectangle
bool useFile = false; //Use the ppm file or not
ppmimage* pImage = NULL;
bool capFPS = true;
float ONE_OVER_FPS = DEFAULT_FPS; //fps cap
Site* sites = NULL;
/************************************************************/
ppmimage read_ppmimage ( const char *name )
{
ppmimage result;
int range;
FILE *fp = fopen(name,"rb");
if (!fp)
{
fprintf(stderr,"No file\n");
exit(1);
}
if (getc(fp)!='P' || getc(fp)!='6') {
fprintf(stderr,"Invalid File\n");
exit(1);
}
fscanf(fp,"%d%d%d\n",&result.sizex,&result.sizey,&range);
assert(range==255); // we'll use only rgb range 0...255 here
result.color = (ppm_rgb*)malloc(result.sizex*result.sizey*sizeof(ppm_rgb));
fread(result.color,sizeof(ppm_rgb),result.sizex*result.sizey,fp);
return result;
}
ppm_rgb getRGB(float x, float y) {
int newX, newY;
x+=ORTHO_SIZE;
y+=ORTHO_SIZE;
x /= ORTHO_SIZE*2.;
y /= ORTHO_SIZE*2.;
y = 1.-y;
//printf("x= %f y= %f\n",x,y);
newX = (int)((x*pImage->sizex)-1.);
newY = (int)((y*pImage->sizey)-1.);
if (newX > pImage->sizex-1) {
newX = pImage->sizex-1;
} else if (newX < 0) {
newX = 0;
}
if (newY > pImage->sizey-1) {
newY = pImage->sizey-1;
} else if (newY < 0) {
newY = 0;
}
//printf("X= %d Y= %d sizex=%d\n",newX,newY,pImage->sizex);
ppm_rgb p = pImage->color[(newY*pImage->sizex) + newX];
//printf("%d\n",(newY*pImage->sizex) + newX);
return pImage->color[(newY*pImage->sizex) + newX];
}
/*************************************************************/
/*
* Sites will never be NULL when this is called
*/
inline void reinit_sites() {
free(sites);
sites = (Site*)malloc(sizeof(Site)*randSites);
}
/*
*
*/
GLvoid set_random_color(Site* s) {
s->color.r = RANDNUM();
s->color.g = RANDNUM();
s->color.b = RANDNUM();
}
/*
*
*/
GLvoid set_all_random_color() {
for (GLuint i = 0; i < randSites; i++) {
set_random_color(sites+i);
}
}
/*
*
*/
GLvoid init_random_sites(int start) {
float x, y;
for (GLuint i = start; i < randSites; i++) {
x = RANDNUM() * ORTHO_SIZE * 2.;
y = RANDNUM() * ORTHO_SIZE * 2.;
x -= ORTHO_SIZE;
y -= ORTHO_SIZE;
sites[i].x = x;
sites[i].y = y;
sites[i].radius = sqrt(pow(x,2)+pow(y,2));
/* Add by quadrant for ease */
if ( x >= 0. && y >= 0.) {
//Quadrant 1
sites[i].angle = atan(y/x);
} else if ( x < 0. && y >= 0. ) {
//Quad 2
sites[i].angle = atan(y/-x) + (M_PI/2.);
} else if ( x < 0. && y < 0. ) {
//Quad 3
sites[i].angle = atan(-y/-x) + M_PI;
} else {
//Quad 4
sites[i].angle = atan(-y/x) + (M_PI) + (M_PI/2.);
}
set_random_color(sites+i);
sites[i].angularVelocity = RANDNUM() * (4.) * ((rand() % 2) ? -1. : 1.);
//convert to radians
sites[i].angularVelocity /= (180./M_PI);
}
}
GLvoid init_random_sites() {
init_random_sites(0);
}
/**
* This performs window resizing, like project 2
*/
GLvoid window_resize(GLint vpw, GLint vph)
{
glutSetWindow(wid);
/* maintain a square viewport, not too small, not too big */
if( vpw < vph ) vpd = vph;
else vpd = vpw;
if( vpd < VPD_MIN ) vpd = VPD_MIN;
if( vpd > VPD_MAX ) vpd = VPD_MAX;
glViewport(0, 0, vpd, vpd);
glutReshapeWindow(vpd, vpd);
glutPostRedisplay();
}
/**
* Window menu
*/
GLvoid menu ( int value ) {
switch (value) {
case MENU_LINES:
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
glutPostRedisplay();
break;
case MENU_TRIANGLES:
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glutPostRedisplay();
break;
case MENU_SPRAY_MORE_POINTS:
randSites *= 2;
sites = (Site*)realloc(sites,sizeof(Site)*randSites);
init_random_sites(randSites/2);
glutPostRedisplay();
break;
case MENU_RESET:
animate = false;
siteColorBlack = true;
drawSites = true;
useFile = false;
siteWidth = DEFAULT_SITEWIDTH;
//Avoid constantly rerandomizing
if (randSites == DEFAULT_RANDSITES) {
glutPostRedisplay();
break;
}
case MENU_RANDOMIZE:
useFile = false;
animate = false;
siteColorBlack = true;
drawSites = true;
randSites = DEFAULT_RANDSITES;
reinit_sites();
init_random_sites();
glutPostRedisplay();
break;
case MENU_ANIMATE:
animate ? animate = false : animate = true;
glutPostRedisplay();
break;
case MENU_DRAWSITES:
drawSites ? drawSites = false : drawSites = true;
glutPostRedisplay();
break;
case MENU_SITECOLORBLACK:
siteColorBlack ? siteColorBlack = false : siteColorBlack = true;
glutPostRedisplay();
break;
case MENU_INCREASE_SITE_SIZE:
siteWidth *= 2;
glutPostRedisplay();
break;
case MENU_DECREASE_SITE_SIZE:
siteWidth /= 2;
glutPostRedisplay();
break;
case MENU_DRAWING:
useFile ? useFile = false : useFile = true;
glutPostRedisplay();
break;
case MENU_UNCAP_FPS:
capFPS ? capFPS = false : capFPS = true;
break;
case MENU_RESET_FPS:
ONE_OVER_FPS = DEFAULT_FPS;
break;
case MENU_DECREASE_MAX_FPS:
ONE_OVER_FPS *= 2.;
break;
default: break;
}
}
/**
* Keyboard input callback
*/
GLvoid keyboard_event(GLubyte key, GLint x, GLint y)
{
switch(key) {
case 27: /* ESC */
exit(0);
case 'l':
menu(MENU_LINES);
break;
case 'f':
menu(MENU_TRIANGLES);
break;
case 's':
menu(MENU_SPRAY_MORE_POINTS);
break;
case 'r':
menu(MENU_RESET);
break;
case 'e':
menu(MENU_RANDOMIZE);
break;
case 'a':
menu(MENU_ANIMATE);
break;
case 'd':
menu(MENU_DRAWSITES);
break;
case 'i':
menu(MENU_SITECOLORBLACK);
break;
case '+':
menu(MENU_INCREASE_SITE_SIZE);
break;
case '-':
menu(MENU_DECREASE_SITE_SIZE);
break;
case 't':
menu(MENU_DRAWING);
break;
case 'u':
menu(MENU_UNCAP_FPS);
break;
case 'j':
menu(MENU_RESET_FPS);
break;
case 'k':
menu(MENU_DECREASE_MAX_FPS);
break;
default: break;
}
}
/**
* Handle mouse drag motion
*/
GLvoid button_motion(GLint mx, GLint my) {
//printf("Dragging %d %d\n",mx,my);
return;
}
/**
* Handle mouse movement
*/
GLvoid passive_motion(GLint mx, GLint my) {
//printf("Someone is moving above me %d %d\n",mx,my);
return;
}
/**
* Redraw the view
*/
GLvoid redraw(GLvoid) {
clock_t frame = clock();
/* set the projection matrix */
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-ORTHO_SIZE,ORTHO_SIZE,-ORTHO_SIZE,ORTHO_SIZE,15.0,25.0);
//gluPerspective(20.0,1.0,15.0,25.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(0,0,-20.0);
/* ensure we're drawing to the correct GLUT window */
glutSetWindow(wid);
/* clear the color buffers */
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
ppm_rgb temp;
/* Draw random points */
for (GLuint i = 0; i < randSites; i++) {
glPushMatrix();
if (animate) {
sites[i].angle += sites[i].angularVelocity;
}
if (sites[i].angle >= 2.*M_PI) {
sites[i].angle -= 2.*M_PI;
}
//glRotatef(sites[i].angle,0,0,1);
/*
* x = r*cos(angle)
* y = r*sin(angle)
*/
sites[i].x = sites[i].radius * cos(sites[i].angle);
sites[i].y = sites[i].radius * sin(sites[i].angle);
glTranslatef(sites[i].x,
sites[i].y,
0);
if (useFile && pImage) {
temp = getRGB(sites[i].x,sites[i].y);
glColor3f(temp.r / 255., temp.g / 255., temp.b / 255.);
} else {
glColor3f(sites[i].color.r,
sites[i].color.g,
sites[i].color.b);
}
glCallList(cone);
if (drawSites) {
if (siteColorBlack) {
glColor3f(0,0,0);
} else {
glColor3f(1-sites[i].color.r,
1-sites[i].color.g,
1-sites[i].color.b);
}
glRectf(-siteWidth,-siteWidth,siteWidth,siteWidth);
}
glPopMatrix();
}
/* flush the pipeline */
glFlush();
/* look at our handiwork */
glutSwapBuffers();
if (animate && !capFPS) {
glutPostRedisplay();
}else if (animate) {
float temp = CLOCKS_PER_SEC*ONE_OVER_FPS;
while (clock() - frame < temp);
glutPostRedisplay();
}
}
/**
* Mouse button pressed
*/
GLvoid mouse_button(GLint btn, GLint state, GLint mx, GLint my)
{
return;
}
/**
* This handles the glut initialization
*/
GLint init_glut(GLint *argc, char **argv)
{
GLint id;
glutInit(argc,argv);
/* size and placement hints to the window system */
glutInitWindowSize(vpd, vpd);
glutInitWindowPosition(10,10);
/* double buffered, RGB color mode */
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
/* create a GLUT window (not drawn until glutMainLoop() is entered) */
id = glutCreateWindow("cs4451 project 3: Voronoi Diagram");
/* register callbacks */
/* window size changes */
glutReshapeFunc(window_resize);
/* keypress handling when the current window has input focus */
glutKeyboardFunc(keyboard_event);
/* mouse event handling */
glutMouseFunc(mouse_button); /* button press/release */
glutMotionFunc(button_motion); /* mouse motion w/ button down */
glutPassiveMotionFunc(passive_motion); /* mouse motion with button up */
/* window obscured/revealed event handler */
glutVisibilityFunc(NULL);
/* handling of keyboard SHIFT, ALT, CTRL keys */
glutSpecialFunc(NULL);
/* what to do when mouse cursor enters/exits the current window */
glutEntryFunc(NULL);
/* what to do on each display loop iteration */
glutDisplayFunc(redraw);
/* Create the menu */
GLint viewMenu = glutCreateMenu(menu);
glutAddMenuEntry("Lines Only (l)",MENU_LINES);
glutAddMenuEntry("Full View (f)",MENU_TRIANGLES);
GLint siteMenu = glutCreateMenu(menu);
glutAddMenuEntry("Show/Hide Sites (d)",MENU_DRAWSITES);
glutAddMenuEntry("Toggle inverse site coloring (i)",MENU_SITECOLORBLACK);
glutAddMenuEntry("Increase site size (+)",MENU_INCREASE_SITE_SIZE);
glutAddMenuEntry("Decrease site size (-)",MENU_DECREASE_SITE_SIZE);
GLint fpsMenu = glutCreateMenu(menu);
glutAddMenuEntry("Increase Max FPS (j)",MENU_RESET_FPS);
glutAddMenuEntry("Decrease Max FPS (k)",MENU_DECREASE_MAX_FPS);
glutAddMenuEntry("Uncap FPS (u)",MENU_UNCAP_FPS);
/*GLint menuID = */
glutCreateMenu(menu);
glutAddSubMenu("View Options",viewMenu);
glutAddSubMenu("Site Options",siteMenu);
glutAddSubMenu("Framerate Options",fpsMenu);
glutAddMenuEntry("Spray More Points (s)",MENU_SPRAY_MORE_POINTS);
glutAddMenuEntry("Move Points (a)",MENU_ANIMATE);
glutAddMenuEntry("Toggle Coloring Method (t)",MENU_DRAWING);
glutAddMenuEntry("Reset (r)",MENU_RESET);
glutAddMenuEntry("Reset-Randomize (e)",MENU_RANDOMIZE);
glutAttachMenu(GLUT_RIGHT_BUTTON);
return id;
}
/**
* OpenGL initializations
*/
GLvoid init_opengl(GLvoid)
{
/* clear to BLACK */
glClearColor(0.0, 0.0, 0.0, 1.0);
/* Enable depth test */
glEnable(GL_DEPTH_TEST);
}
///////////////////////////
// Voronoi Diagram stuff //
///////////////////////////
GLuint init_cone ( )
{
GLuint sceneList = glGenLists(1);
float temp;
glNewList(sceneList,GL_COMPILE);
glBegin(GL_TRIANGLE_FAN);
//Initialize the first vertex
glVertex3f(0,0,0);
for (GLuint k = 0; k < numPoints; k++) {
temp = (TWOPI*k) / (float)numPoints;
glVertex4f(cos(temp),sin(temp),-1,0);
}
glVertex4f(cos(0.),sin(0.),-1,0);
glEnd();
glEndList();
return sceneList;
}
int main(int argc, char* argv[]) {
ppmimage image;
srand(time(NULL));
if (argc >= 2) {
image = read_ppmimage(argv[1]);
pImage = &image;
}
wid = init_glut(&argc,argv);
init_opengl();
cone = init_cone();
sites = (Site*)malloc(sizeof(Site)*randSites);
init_random_sites();
glutMainLoop();
return 0;
}