Newer
Older
cg / sources / main.cpp
@glproj03 glproj03 on 16 Dec 2005 16 KB passed by reference
//////////////////////////////////////////////////////////////
//                                                          //
// Project: SDL/OpenGL template                             //
// Goal   : just open a window with a valid OpenGL context  //
// Author : Achille Peternier, VRLab - EPFL, 2005           //
//                                                          //
//////////////////////////////////////////////////////////////

//////////////
// #INCLUDE //
//////////////
#include <windows.h>    // Only required under Windows :-D
#include <SDL.h>        // This file import the SDL inteface
#include <GL/gl.h>      // This file import the OpenGL interface
#include <GL/glu.h>     // This file offers some OpenGL-related utilities 

#include <stdio.h>

#include <math.h>

/////////////
// #PRAGMA //
///////////// 
// Visual Studio specific: you can import libraries directly by
// specifing them through a #pragma. On other compilters/platforms add
// the required .lib to the makefile or project proprieties
#pragma comment(lib, "opengl32.lib")
#pragma comment(lib, "glu32.lib")
#pragma comment(lib, "sdl.lib")
#pragma comment(lib, "sdlmain.lib")

/////////////
// #DEFINE //
/////////////
// Constants hardcoded during compilation
#define WINDOW_TITLE       "the cube"
#define WINDOW_X           800   // Window width
#define WINDOW_Y           600   // Window height
#define WINDOW_COLORDEPTH  32    // Color depth (in bits)
#define WINDOW_ZETADEPTH   24    // z-buffer depth (in bits)

#define SURFACE_COUNT      6                              
#define PI                 3.14159265f


///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
// CLASSES 


class Color {
 public:
  float r;
  float g;
  float b;
  Color(float _r, float _g, float _b) {
    r = _r;
    g = _g;
    b = _b;
  }  

  void drawColor() {
    glColor4f(r, g, b, 1.0f);
  }

  Color* clone() {
	return new Color(r,g,b);
  }
};


class Vec {
 public:
  float c[3];

  Vec(float vx, float vy, float vz) {
    c[0] = vx;
    c[1] = vy;
    c[2] = vz;
  }

  Vec(Vec* v) {
	Vec(v->x(), v->y(), v->z());
  }

  float x() {
	return c[0];
  }

  float y() {
	return c[1];
  }

  float z() {
	return c[2];
  }

  float* getCoords() {
	return c;
  }

  Vec operator+(Vec& v) {
    return Vec(x() + v.x(), y() + v.y(), z() + v.z());
  }

  void add(Vec& a) {
	c[0] += a.x();
	c[1] += a.y();
	c[2] += a.z();
  }

  Vec operator-(Vec& v) {
    return Vec(x() - v.x(), y() - v.y(), z() - v.z());
  }

  Vec operator*(float s) {
    Vec r = Vec(x()*s, y()*s, z()*s);
    return r;
  }

  Vec operator*(Vec& s) {
	Vec r = Vec(x()*s.x(), y()*s.y(), z()*s.z());
  }

  Vec operator/(float s) {
	Vec r = Vec(x()/s, y()/s, z()/s);
	return r;
  }

  Vec cross(Vec& v) {
	return Vec(y() * v.z() - z() * v.y(), 
			   z() * v.x() - x() * v.z(), 
			   x() * v.y() - y() * v.x());
  }

  Vec normalize() {
    return *this * (1 / length());
  }

  float length() {
    return sqrt(x()*x()+y()*y()+z()*z());
  }

  void print() {
    printf (" vektor: %f, %f, %f\n", x(), y(), z());
  }

  Vec* clone() {
    return new Vec(x(), y(), z());
  }
};


class Poly {
 private:
  Vec** initpoints;
  int size;

  Vec* position;
  Vec* rotation;
  Color* color;

 public:
  Poly(Vec** _points, int _size) {
	//TODO constructor almost same as below
	size = _size;
	initpoints = _points;	

	color = new Color (1,1,1);

	Vec c = calcCenter();
	setCenter(c);	

	rotation = new Vec(0,0,0);		
  }

  Poly(Vec** _points, int _size, Color _color) {
	size = _size;
	initpoints = _points;	

	color = _color.clone();

	Vec c = calcCenter();
	setCenter(c);	

	rotation = new Vec(0,0,0);		
  }

  ~Poly() {
	delete position;
	delete rotation;
	delete color;
  }

  /* 
   * set the position where the (rotation-)center of 
   * the polygon is located
   */
  void setCenter(Vec& c) {
	delete position;
	position = c.clone();
  }

  /*
   * initial rotation relative to rotation center
   */
  Vec getInitRotation(Vec& v) {
	return Vec(atan2(v.y(), v.z()),
			   atan2(v.x(), v.z()),
			   atan2(v.y(), v.x()));
  }

  /*
   * calculate the center relative to all vertices.
   */
  Vec calcCenter() {
	Vec s (0,0,0);
	for (int i = 0; i < size; i++) {
	  s = s+*initpoints[i];
	}
	return s / ((float)size);
  }

  /*
   * reset the position of all vertices (ie. translate your
   * polygon to an absolute position)
   */
  void setPosition(Vec newcenter) {
	Vec diff = newcenter - (*position);
	delete position;
	position = newcenter.clone();
	for (int i = 0; i < size; i++) {
	  initpoints[i]->add(diff);
	}	
  }

  //additional rotation in arcs
  void rotate(Vec rot) {
	rotation->add(rot);
  }

  Vec rotate_x(Vec& c) {
	  Vec initrot = getInitRotation(c);
	  Vec rot = initrot + *rotation;
	  float r = Vec(0, c.y(), c.z()).length();	  
	  return Vec (c.x(), r*cos(rot.x()), r*sin(rot.x()));
  }

  Vec rotate_y(Vec& c) {
	  Vec initrot = getInitRotation(c);
	  Vec rot = initrot + *rotation;
	  float r = Vec(c.x(), 0, c.z()).length();	  
	  return Vec (r*sin(rot.y()), c.y(), r*cos(rot.y()));
  }

  Vec rotate_z(Vec& c) {
	  Vec initrot = getInitRotation(c);
	  Vec rot = initrot + *rotation;
	  float r = Vec(c.x(), c.y(), 0).length();	  
	  return Vec (r*cos(rot.z()), r*sin(rot.z()), c.z());
  }

  void draw() {	
	glBegin (GL_POLYGON);    
	
	Vec v1 = *initpoints[2] - *initpoints[0];
	Vec v2 = *initpoints[1] - *initpoints[0];
	glNormal3fv(  (v1.cross(v2)+ *initpoints[0]).c  );
	
    for (int v = 0; v < size; v++) {	  

	  color->drawColor();
	  Vec out = (*initpoints[v] - *position);
	  out = rotate_x(out);
	  out = rotate_y(out);
	  out = rotate_z(out);
	  glVertex3fv((*position + out).c);
    }
	glEnd();
  }  
};


/*
 * lightsource
 */
class Light {
 public:
  Vec* pos;
  Vec* dir;
  Light(Vec* _pos, Vec* _dir) {
	pos = _pos;
	dir = _dir;
  }

  void trace() {
	  glBegin (GL_LINES);
	    glVertex3fv(pos->getCoords());
		glVertex3fv(dir->getCoords());
	  glEnd();	
  }

  void draw() {
	//printf(GL_LIGHT0);
	glLightf(GL_LIGHT0, GL_SPOT_CUTOFF, 180.0f);
	float p [4] = {pos->x(), pos->y(), pos->z(), 1.0f};
	float d [4] = {dir->x(), dir->y(), dir->z(), 1.0f};
	glLightfv(GL_LIGHT0, GL_POSITION, p);
	glLightfv(GL_LIGHT0, GL_SPOT_DIRECTION, d);
  }
};

class Model {
	private:
		Poly** faces;
		int size;

		Vec* position;
		Vec* rotation;

	public:
		Model(Poly** _faces, int _size) {
			size = _size;
			faces = _faces;
			Vec c = calcCenter();
			setCenter(c);
			rotation = new Vec(0,0,0);
		}

		~Model() {
			delete position;
			delete rotation;
		}

		void setCenter(Vec& c) {
			delete position;
			position = c.clone();
		}

		Vec calcCenter() {
			Vec s(0,0,0);
			for ( int i = 0; i < size; i++ ) {
			  Vec c = faces[i]->calcCenter();
			  s = s + c;
			}			
			return s/((float)size);
		}

		void rotate(Vec rot) {
			rotation->add(rot);
			for ( int i = 0; i < size; i++ ) {
				faces[i]->rotate(rot);
			}
		}

		void draw() {
			for ( int i = 0; i <size; i++ ) {
				faces[i]->draw();
			}
		}

		void addFace(Poly* face) {
			Poly** t = faces;
			size++;
			for ( int i = 0; i < size-1; i++ ) {
				faces[i] = t[i];
			}
			faces[size-1] = face;
		}
};


///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
// GLOBAL VARS 

int MouseX, MouseY, OldMouseX, OldMouseY;
bool MouseButtonRight, MouseButtonLeft;
bool done = false;   // Quit application when true

Model* importModel(char* fname) {

	FILE *fp;
	char lbuf[200];
	char* buf2;
	int numpoints = 0;
	float tpf[3] = {0.0f, 0.0f, 0.0f};
	int* tp = NULL;
	int tps = 0;
	int cp = 0;
	Vec** points;
	Vec** tpoints;
	Model* mm = new Model(NULL, 0);
	Poly* tpp;


	fp = fopen(fname, "r");

	if ( fp == NULL ) {
		printf("Error reading file %s\n", fname);
		return NULL;
	}

	while( fgets(lbuf, sizeof(lbuf), fp) != NULL ) {
		buf2 = strtok(lbuf, " ");
		if ( buf2 == "v" ) {
			numpoints++;
			tpf[0] = (float)atof(strtok(lbuf, NULL));
			tpf[1] = (float)atof(strtok(lbuf, NULL));
			tpf[2] = (float)atof(strtok(lbuf, NULL));
			points[numpoints-1] = new Vec(tpf[0], tpf[1], tpf[2]);
		}
		if ( buf2 == "f" ) {
			tps = 0;
			while ( (buf2 = strtok(lbuf, NULL)) != NULL ) {
				cp = atoi(buf2);
				tpoints[tps] = points[cp]->clone();
				tps++;
			}
			tpp = new Poly(tpoints, tps);
			mm->addFace(tpp);
		}
	}


	fclose(fp);
	return mm;
}


///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
// MAIN //

int main( int argc, char **argv )
{
   // Initialize SDL:
   if (SDL_Init(SDL_INIT_VIDEO) == -1)	
   {
     printf("ERROR: unable to init SDL!\n");
     return 1;
   }		

   Color white (1,1,1);
   Color black (0,0,0);
   Color red (1,0,0);
   Color blue (0,0,1);
   Color green (0,1,0);
   Color yellow (1,1,0);
   
   Vec p0 (0 ,0 ,0 );
   Vec p1 (10,0 ,0 );
   Vec p2 (10,10,0 );
   Vec p3 (0 ,10,0 );

   Vec p4 (0 ,0 ,10);
   Vec p5 (10,0 ,10);
   Vec p6 (10,10,10);
   Vec p7 (0 ,10,10);

   Vec cen (5,5,5);

   /*Rect surf [SURFACE_COUNT] = {
     Rect (&p0, &p3, &p2, &p1, &red),
     Rect (&p4, &p5, &p6, &p7, &blue),
     Rect (&p4, &p0, &p1, &p5, &green),
     Rect (&p2, &p3, &p7, &p6, &yellow),
     Rect (&p1, &p2, &p6, &p5, &black),
     Rect (&p3, &p0, &p4, &p7, &white)
	 };*/

   Vec* pp0[4] = {&p0, &p3, &p2, &p1};
   Vec* pp1[4] = {&p4, &p5, &p6, &p7};
   Vec* pp2[4] = {&p4, &p0, &p1, &p5};
   Vec* pp3[4] = {&p2, &p3, &p7, &p6};
   Vec* pp4[4] = {&p1, &p2, &p6, &p5};
   Vec* pp5[4] = {&p3, &p0, &p4, &p7};

   Poly* polys [SURFACE_COUNT] = {
	 new Poly(pp0, 4, red),
	 new Poly(pp1, 4, green),
	 new Poly(pp2, 4, black),
	 new Poly(pp3, 4, blue),
	 new Poly(pp4, 4, yellow),
	 new Poly(pp5, 4),
   };

   Model* myModel = importModel("teapot.obj");
   
   for (int x = 0; x < SURFACE_COUNT; x++) {
	 polys[x]->setCenter(cen);
   }

   //Vec* pp [4] = {&p0, &p3, &p2, &p1};
   //Poly poly0 (pp,4);

   //light info
   Vec pos0(10.0f, 12.0f, 15.0f);
   Vec dir0(5.0f, 5.0f, 5.0f);

   Light light0(&pos0, &dir0);

   // Prepare configuration:   
   int bitsPerColor = 8;
   if (WINDOW_COLORDEPTH == 16) 
     bitsPerColor = 5;
   SDL_GL_SetAttribute(SDL_GL_RED_SIZE, bitsPerColor);
   SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, bitsPerColor);
   SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, bitsPerColor);	
   SDL_GL_SetAttribute(SDL_GL_ACCUM_RED_SIZE, 0);     
   SDL_GL_SetAttribute(SDL_GL_ACCUM_GREEN_SIZE, 0);   
   SDL_GL_SetAttribute(SDL_GL_ACCUM_BLUE_SIZE, 0);
   SDL_GL_SetAttribute(SDL_GL_ACCUM_ALPHA_SIZE, 0);   
   if (WINDOW_COLORDEPTH == 32) 
     SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8);
   else 
     SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 0);   
   SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, WINDOW_ZETADEPTH);	
   SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);	
	
   // Create surface:  
   unsigned flags = SDL_OPENGL;		
   SDL_WM_SetCaption(WINDOW_TITLE, NULL);   
   if (SDL_SetVideoMode(WINDOW_X, WINDOW_Y, WINDOW_COLORDEPTH, flags) == NULL) 
     {
       printf("ERROR: unsupported video configuration!\n");
       return 1;			
     }
   
   // Ok, SDL up with a valid OpenGL context!
   // Now setup some OpenGL parameter:
   // Clear background with a darkblue color
   glClearColor(0.0f, 0.0f, 0.5f, 1.0f); 
   
   // correct clipping
   glEnable (GL_DEPTH_TEST);
   
   //enable light
   glEnable(GL_LIGHTING);
   glEnable(GL_LIGHT0);
   
   glEnable(GL_COLOR_MATERIAL);
   
   ///////////////////////////////////////////////////////////////////////////
   ///////////////////////////////////////////////////////////////////////////
   ///////////////////////////////////////////////////////////////////////////
   ///////////////////////////////////////////////////////////////////////////
   // Mainloop: 
   
   float deltay = 0.0f;
   float deltaz = 0.0f;
   float deltacolor = 0.0f;
   
   while (!done)
	  {      
	    /////////////////////
	    // Do some rendering:
	    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	    
	    // Setup a perspective view:
	    glMatrixMode(GL_PROJECTION);
	    glLoadIdentity();
	    gluPerspective(45.0f,             // Field of view
			   WINDOW_X/WINDOW_Y,  // width/height ratio
			   1.0f,               // near clipping plane
			   1000.0f);           // far clipping plane
	    
	    // Place the viewer 50 units backward:
	    glMatrixMode(GL_MODELVIEW);
	    glLoadIdentity();
	    glTranslatef(0.0f, 0.0f, -50.0f);
	    
	    // Draw a rotating triangle:    
	    glRotatef(deltay, 0.0f, 1.0f, 0.0f); // Rotation around the Y axis
	    glRotatef(deltaz, 1.0f, 0.0f, 0.0f);  

		for (int i = 0; i < SURFACE_COUNT; i++) {		  
		  polys[i]->draw();
		  polys[i]->rotate(Vec(0.0f, 0.01f, 0.01f));
	    }

		//poly0.draw();
		//poly0.rotate(Vec(0.0, 0.01, 0.01));
		
		light0.draw();
		light0.trace();
		
		//myModel->draw();

	    ////////////////
	    // Check events:			
	    SDL_Event event;			
	    while (SDL_PollEvent(&event)) 
	      {
		// Quit by click on X:
		if (event.type == SDL_QUIT) 
		  done = true;			
	      }           
	    
	    // Update mouse:
	    OldMouseX = MouseX;
	    OldMouseY = MouseY;
	    unsigned buttons = SDL_GetMouseState(&MouseX, &MouseY);
	    if (buttons&SDL_BUTTON(1))
	      MouseButtonLeft = true;
	    else
	      MouseButtonLeft = false;
      if (buttons&SDL_BUTTON(3)) // <-- Beware: may be 2 on mouses 
	                         // without the middle button!
	MouseButtonRight = true;
      else
	MouseButtonRight = false;				
      
      //if (MouseButtonLeft)
      //      delta += 1.0f;            	
      
      // Update keyboard (used like a joypad):
      Uint8 *keystate = SDL_GetKeyState(NULL);
      if (keystate[SDLK_ESCAPE]) 
            done = true;	  

	  //background color
      if (keystate[SDLK_1])
            glClearColor(0.5f, 0.0f, 0.0f, 1.0f);
      if (keystate[SDLK_2])
            glClearColor(0.0f, 0.5f, 0.0f, 1.0f);            
      if (keystate[SDLK_3])
            glClearColor(0.0f, 0.0f, 0.5f, 1.0f);                        

	  //scene rotation
	  if (keystate[SDLK_LEFT])
			deltay -= 2.0f;
	  if (keystate[SDLK_RIGHT])
			deltay += 2.0f;
	  if (keystate[SDLK_UP])
			deltaz -= 2.0f;
	  if (keystate[SDLK_DOWN])
			deltaz += 2.0f;

	  //light rotation
	  /*	  if (keystate[SDLK_a])
			lightpos[0]+=lightdelta;
	  if (keystate[SDLK_d])			
		    lightpos[0]-=lightdelta;
	  if (keystate[SDLK_w])
			lightpos[1]+=lightdelta;
	  if (keystate[SDLK_s])			
		    lightpos[1]-=lightdelta;
	  if (keystate[SDLK_q])
			lightpos[2]+=lightdelta;
	  if (keystate[SDLK_e])			
		    lightpos[2]-=lightdelta;
	  */
	  if (keystate[SDLK_SPACE]) {
		    deltacolor += 0.01f;
			if (deltacolor > 1.0f) {
				deltacolor = 0.0f;
			}
	  }

		
   
      ////////////////
      // Swap buffers:
      _sleep(20); // Just don't kill computer resources ;)
      SDL_GL_SwapBuffers();	   
	   
      // Plain stupid log, just to show values:
      //printf("X: %d, Y: %d, but1: %d, but2: %d\n", 
      //     MouseX, MouseY, MouseButtonLeft, MouseButtonRight);
   }
	
   // Ok, release everything and byebye:
   SDL_Quit();
   return 0;
}
/*
//DEPRECATED
class Tri{
 public:
  Vec *p[3];
  Color *col;
  Vec *normal;

  Tri(Vec* p0, Vec* p1, Vec* p2, Color* c) {
    p[0] = p0;
    p[1] = p1;
    p[2] = p2;
    col = c;
    Vec v1 = (*p[1] - *p[0]);
    Vec v2 = (*p[2] - *p[0]);      
    normal = (v1).cross(v2);
  }

  ~Tri() {
    delete normal;
  }

  void draw() {
    glBegin (GL_TRIANGLES);    
      this->setNormal();
      col->setColor();
      for (int v = 0; v < 3; v++) {
		glVertex3f(p[v]->c[0], p[v]->c[1], p[v]->c[2]);
      }
	glEnd();
	this->drawNormals();
    this->print();
  }

  void drawNormals() {
	for (int v = 0; v < 3; v++) {
	  glBegin (GL_LINES);
	  glVertex3f(p[v]->x(), p[v]->y(), p[v]->z());
	  //glVertex3fv(((*p[v])*scale).getCoords());
	  glVertex3f(p[v]->x() + this->normal->x(),
	  			 p[v]->y() + this->normal->y(),
	  			 p[v]->z() + this->normal->z());
	  //glVertex3fv(((*p[v])*scale + this->normal).getCoords());
	  glEnd();
	}	  
  }

  void setNormal() {
    glNormal3fv(this->normal->getCoords());	
  }

  void print() {
    printf("triangle: \n");
    for (int v = 0; v < 3; v++) {
      p[v]->print();
    }		
    printf("normal: ");
    normal->print();
    printf("\n");
  }
};


//DEPRECATED
class Rect {
 public:
  Tri* t1;
  Tri* t2;
  Rect(Vec* p1, Vec* p2, Vec* p3, Vec* p4, Color* c) {
    t1 = new Tri (p1, p2, p3, c);
    t2 = new Tri (p1, p3, p4, c);
  }
  ~Rect() {
    delete t1;
    delete t2;
  }
  void draw() {
    t1->draw();
    t2->draw();
  }
};
*/