442 lines
11 KiB
C++
442 lines
11 KiB
C++
#include "Renderer.h"
|
|
#include "structs.h"
|
|
#include "utils.h"
|
|
#include "cwrappers.h"
|
|
#include "Input.h"
|
|
|
|
#include <GL/glut.h>
|
|
|
|
//Initialize static member
|
|
Renderer Renderer::m_instance;
|
|
|
|
void Renderer::init(int* argc, char** argv) {
|
|
this->windowID = init_glut(argc,argv);
|
|
this->init_opengl();
|
|
|
|
//Generate Subdivision
|
|
clock_t start = clock();
|
|
for (int i = 0; i < atoi(argv[1]); i++) {
|
|
Subdivision::getInstance()->performSubdivision(*(argv[2]));
|
|
}
|
|
std::cout << "Subdivision time: "
|
|
<< (clock()-start)/(float)CLOCKS_PER_SEC << " seconds.\n";
|
|
|
|
std::cout << "Generating Normals..";
|
|
this->generateNormals();
|
|
std::cout << "Done.\nGenerating Scene..";
|
|
this->create_scene();
|
|
std::cout << "Done.\n";
|
|
|
|
glMatrixMode(GL_MODELVIEW);
|
|
glPushMatrix();
|
|
glLoadIdentity();
|
|
glGetFloatv(GL_MODELVIEW_MATRIX,currModelTransform);
|
|
glPopMatrix();
|
|
|
|
std::cout << "Total time: "
|
|
<< (clock()-start)/(float)CLOCKS_PER_SEC << " seconds.\n";
|
|
std::cout << "Final number of vertices : " << (int) points->size() << std::endl;
|
|
std::cout << "Final number of triangles : " << (int) triangles->size() << std::endl;
|
|
}
|
|
|
|
//Calculate the normals for each triangle
|
|
void Renderer::generateNormals() {
|
|
|
|
/* Generate normals for triangles and Vertices */
|
|
Vector tempNormal;
|
|
|
|
Point a1a2, a1a3;
|
|
Point a1, a2, a3;
|
|
|
|
std::vector<Triangle>::iterator t_iter;
|
|
|
|
for (t_iter = triangles->begin(); t_iter != triangles->end(); t_iter++) {
|
|
|
|
a1 = points->at(t_iter->a1);
|
|
a2 = points->at(t_iter->a2);
|
|
a3 = points->at(t_iter->a3);
|
|
|
|
a1a2 = a2 - a1;
|
|
a1a3 = a3 - a1;
|
|
|
|
cross(tempNormal,a1a2,a1a3);
|
|
|
|
tempNormal.i *= -1;
|
|
tempNormal.j *= -1;
|
|
tempNormal.k *= -1;
|
|
|
|
/* Store the normal for the triangle */
|
|
t_iter->normal = tempNormal;
|
|
|
|
}
|
|
}
|
|
|
|
void Renderer::init_opengl()
|
|
{
|
|
// back-face culling on
|
|
glEnable(GL_CULL_FACE);
|
|
glCullFace(GL_BACK); // We want to cull the back
|
|
glFrontFace(GL_CW); // The vertices we get are clockwise
|
|
|
|
// automatically scale normals to unit length after transformation
|
|
glEnable(GL_NORMALIZE);
|
|
|
|
//Flat shading
|
|
glShadeModel(GL_FLAT);
|
|
|
|
// clear to BLACK
|
|
glClearColor(0.0, 0.0, 0.0, 1.0);
|
|
|
|
// Enable depth test
|
|
glEnable(GL_DEPTH_TEST);
|
|
}
|
|
|
|
GLint Renderer::init_glut(int* argc, char** argv)
|
|
{
|
|
int 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 5: Subdivision fancyness!");
|
|
|
|
/* register callbacks */
|
|
|
|
/* window size changes */
|
|
glutReshapeFunc(reshape);
|
|
|
|
/* 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 */
|
|
|
|
//Create the Zoom Menu
|
|
GLint menuID = glutCreateMenu(menu);
|
|
glutAddMenuEntry("Zoom in (w)",Input::ZOOM_IN_EVENT);
|
|
glutAddMenuEntry("Zoom out (s)",Input::ZOOM_OUT_EVENT);
|
|
glutAddMenuEntry("Animate (a)",Input::ANIMATE_EVENT);
|
|
glutAddMenuEntry("Lines Only (l)",Input::LINES_EVENT);
|
|
glutAddMenuEntry("Full Model (f)",Input::FULL_EVENT);
|
|
|
|
glutSetMenu(menuID);
|
|
|
|
glutAttachMenu(GLUT_RIGHT_BUTTON);
|
|
|
|
return id;
|
|
}
|
|
|
|
void Renderer::render() {
|
|
//Initialize
|
|
glutSetWindow(windowID);
|
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
|
|
|
/* set the projection matrix */
|
|
glMatrixMode(GL_PROJECTION);
|
|
glLoadIdentity();
|
|
gluPerspective(viewDist,1.0,15.0,25.0);
|
|
|
|
glMatrixMode(GL_MODELVIEW);
|
|
glLoadIdentity();
|
|
|
|
init_lightsource();
|
|
|
|
glTranslatef(0,0,-20);
|
|
if (!animate) {
|
|
glMultMatrixf(currModelTransform);
|
|
} else {
|
|
glMultMatrixf(currModelTransform);
|
|
this->rotAngle1 += this->dAngle1;
|
|
this->rotAngle2 += this->dAngle2;
|
|
glRotatef(this->rotAngle1,1,2,3);
|
|
glRotatef(this->rotAngle2,-2,-1,0);
|
|
}
|
|
#ifdef SCENELIST
|
|
glCallList(this->sceneID);
|
|
#else
|
|
this->create_scene();
|
|
#endif
|
|
|
|
//Draw
|
|
glFlush();
|
|
glutSwapBuffers();
|
|
|
|
if (animate) { glutPostRedisplay(); }
|
|
}
|
|
|
|
void Renderer::window_resize(GLint vpw, GLint vph) {
|
|
glutSetWindow(this->windowID);
|
|
|
|
/* 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();
|
|
}
|
|
|
|
void Renderer::set_material_properties(GLfloat r, GLfloat g, GLfloat b) {
|
|
GLfloat mat_specular[4] = { 0.0, 0.0, 0.0, 1.0 };
|
|
GLfloat mat_ambient_and_diffuse[4] = { 0.5, 0.5, 0.5, 1.0 };
|
|
GLfloat mat_shininess[1] = { 0.0 };
|
|
|
|
mat_specular[0] = mat_ambient_and_diffuse[0] = r;
|
|
mat_specular[1] = mat_ambient_and_diffuse[1] = g;
|
|
mat_specular[2] = mat_ambient_and_diffuse[2] = b;
|
|
|
|
glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
|
|
glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess);
|
|
glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, mat_ambient_and_diffuse);
|
|
}
|
|
|
|
void Renderer::init_lightsource()
|
|
{
|
|
GLfloat light_ambient[] = { .1, .1, .1, 1.0 };
|
|
GLfloat light_diffuse[] = { .7, .7, .7, 1.0 };
|
|
GLfloat light_specular[] = { 0, 0, 0, 1.0 };
|
|
GLfloat light_position[] = { 2, 2, 2, 0.0 };
|
|
|
|
glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient);
|
|
glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse);
|
|
glLightfv(GL_LIGHT0, GL_SPECULAR, light_specular);
|
|
glLightfv(GL_LIGHT0, GL_POSITION, light_position);
|
|
glLightf(GL_LIGHT0,GL_CONSTANT_ATTENUATION,1.0);
|
|
glLightf(GL_LIGHT0,GL_LINEAR_ATTENUATION,0.0);
|
|
glLightf(GL_LIGHT0,GL_QUADRATIC_ATTENUATION,0.0);
|
|
|
|
glEnable(GL_LIGHTING);
|
|
glEnable(GL_LIGHT0);
|
|
}
|
|
|
|
#ifdef SCENELIST
|
|
|
|
GLuint Renderer::init_sceneList() {
|
|
GLuint sceneList = glGenLists(1);
|
|
|
|
Point a1, a2, a3;
|
|
Vector tempNormal;
|
|
std::vector<Triangle>::iterator t_iter;
|
|
|
|
glNewList(sceneList,GL_COMPILE);
|
|
glBegin(GL_TRIANGLES);
|
|
|
|
for (t_iter = triangles->begin();
|
|
t_iter != triangles->end();
|
|
t_iter++)
|
|
{
|
|
a1 = points->at(t_iter->a1);
|
|
a2 = points->at(t_iter->a2);
|
|
a3 = points->at(t_iter->a3);
|
|
|
|
tempNormal = t_iter->normal;
|
|
|
|
glNormal3f(tempNormal.i, tempNormal.j, tempNormal.k);
|
|
|
|
glVertex3f(a1.x, a1.y, a1.z);
|
|
glVertex3f(a2.x, a2.y, a2.z);
|
|
glVertex3f(a3.x, a3.y, a3.z);
|
|
}
|
|
|
|
glEnd();
|
|
|
|
glEndList();
|
|
|
|
return sceneList;
|
|
}
|
|
|
|
GLvoid Renderer::create_scene() {
|
|
|
|
GLuint scene = this->init_sceneList();
|
|
|
|
GLuint sceneList = glGenLists(1);
|
|
|
|
glNewList(sceneList,GL_COMPILE);
|
|
|
|
set_material_properties(1.0,1.0,1.0);
|
|
|
|
Point Max;
|
|
Point Min;
|
|
Point Center;
|
|
std::vector<Point>::iterator p_iter;
|
|
p_iter = points->begin();
|
|
|
|
|
|
Max.x = Min.x = p_iter->x;
|
|
Max.y = Min.y = p_iter->y;
|
|
Max.z = Min.z = p_iter->z;
|
|
|
|
p_iter++;
|
|
|
|
for(; p_iter != points->end(); p_iter++)
|
|
{
|
|
|
|
if (p_iter->x > Max.x) {
|
|
Max.x = p_iter->x;
|
|
} else if (p_iter->x < Min.x) {
|
|
Min.x = p_iter->x;
|
|
}
|
|
|
|
if (p_iter->y > Max.y) {
|
|
Max.y = p_iter->y;
|
|
} else if (p_iter->y < Min.y) {
|
|
Min.y = p_iter->y;
|
|
}
|
|
|
|
if (p_iter->z > Max.z) {
|
|
Max.z = p_iter->z;
|
|
} else if (p_iter->z < Min.z) {
|
|
Min.z = p_iter->z;
|
|
}
|
|
}
|
|
|
|
Center.x = (Max.x + Min.x) / 2.;
|
|
Center.y = (Max.y + Min.y) / 2.;
|
|
Center.z = (Max.z + Min.z) / 2.;
|
|
|
|
float scaleX, scaleY, scaleZ;
|
|
scaleX = (Max.x - Min.x) / 2.;
|
|
scaleY = (Max.y - Min.y) / 2.;
|
|
scaleZ = (Max.z - Min.z) / 2.;
|
|
|
|
float scaleFactor;
|
|
|
|
scaleFactor = scaleX > scaleY ? scaleX : scaleY;
|
|
scaleFactor = scaleZ > scaleFactor ? scaleZ : scaleFactor;
|
|
scaleFactor = 1. / scaleFactor;
|
|
|
|
glPushMatrix();
|
|
glTranslatef(0.-(Center.x*scaleFactor),0.-(Center.y*scaleFactor),0.-(Center.z*scaleFactor));
|
|
glScalef(scaleFactor,scaleFactor,scaleFactor);
|
|
glCallList(scene);
|
|
glPopMatrix();
|
|
|
|
glEndList();
|
|
|
|
this->sceneID = sceneList;
|
|
}
|
|
|
|
#else
|
|
|
|
GLuint Renderer::init_sceneList() {
|
|
Point a1, a2, a3;
|
|
Vector tempNormal;
|
|
std::vector<Triangle>::iterator t_iter;
|
|
|
|
glBegin(GL_TRIANGLES);
|
|
|
|
for (t_iter = triangles->begin();
|
|
t_iter != triangles->end();
|
|
t_iter++)
|
|
{
|
|
a1 = points->at(t_iter->a1);
|
|
a2 = points->at(t_iter->a2);
|
|
a3 = points->at(t_iter->a3);
|
|
|
|
tempNormal = t_iter->normal;
|
|
|
|
glNormal3f(tempNormal.i, tempNormal.j, tempNormal.k);
|
|
|
|
glVertex3f(a1.x, a1.y, a1.z);
|
|
glVertex3f(a2.x, a2.y, a2.z);
|
|
glVertex3f(a3.x, a3.y, a3.z);
|
|
}
|
|
|
|
glEnd();
|
|
|
|
|
|
return 0;
|
|
}
|
|
|
|
GLvoid Renderer::create_scene() {
|
|
|
|
set_material_properties(1.0,1.0,1.0);
|
|
|
|
Point Max;
|
|
Point Min;
|
|
Point Center;
|
|
std::vector<Point>::iterator p_iter;
|
|
p_iter = points->begin();
|
|
|
|
|
|
Max.x = Min.x = p_iter->x;
|
|
Max.y = Min.y = p_iter->y;
|
|
Max.z = Min.z = p_iter->z;
|
|
|
|
p_iter++;
|
|
|
|
for(; p_iter != points->end(); p_iter++)
|
|
{
|
|
|
|
if (p_iter->x > Max.x) {
|
|
Max.x = p_iter->x;
|
|
} else if (p_iter->x < Min.x) {
|
|
Min.x = p_iter->x;
|
|
}
|
|
|
|
if (p_iter->y > Max.y) {
|
|
Max.y = p_iter->y;
|
|
} else if (p_iter->y < Min.y) {
|
|
Min.y = p_iter->y;
|
|
}
|
|
|
|
if (p_iter->z > Max.z) {
|
|
Max.z = p_iter->z;
|
|
} else if (p_iter->z < Min.z) {
|
|
Min.z = p_iter->z;
|
|
}
|
|
}
|
|
|
|
Center.x = (Max.x + Min.x) / 2.;
|
|
Center.y = (Max.y + Min.y) / 2.;
|
|
Center.z = (Max.z + Min.z) / 2.;
|
|
|
|
float scaleX, scaleY, scaleZ;
|
|
scaleX = (Max.x - Min.x) / 2.;
|
|
scaleY = (Max.y - Min.y) / 2.;
|
|
scaleZ = (Max.z - Min.z) / 2.;
|
|
|
|
float scaleFactor;
|
|
|
|
scaleFactor = scaleX > scaleY ? scaleX : scaleY;
|
|
scaleFactor = scaleZ > scaleFactor ? scaleZ : scaleFactor;
|
|
scaleFactor = 1. / scaleFactor;
|
|
|
|
glPushMatrix();
|
|
glTranslatef(0.-(Center.x*scaleFactor),0.-(Center.y*scaleFactor),0.-(Center.z*scaleFactor));
|
|
glScalef(scaleFactor,scaleFactor,scaleFactor);
|
|
this->init_sceneList();
|
|
glPopMatrix();
|
|
}
|
|
|
|
#endif
|
|
|
|
|