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

//////////////
// #INCLUDE //
//////////////

#ifdef WIN32
#include <windows.h>    // Only required under Windows :-D
#endif

#include <SDL.h>        // This file import the SDL inteface
#include <SDL/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 <string.h>
#include <stdlib.h>
#include <unistd.h>

#include <string>
#include <iostream>
#include <fstream>

#include <math.h>

#ifdef WIN32
/////////////
// #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")
#endif

#include "array.cpp"

using namespace std;

/////////////
// #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

#define DEBUG

int debugct = 0;
int firstprint = 1;

#define DD() do { printf("DD:%d\n", debugct); debugct++;} while(0);
#define DD1(x) while(firstprint) { printf("DD1: %d\n", x); firstprint = 0;};

///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
// 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());
  }

  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) {
	return Vec(x()*s.x(), y()*s.y(), z()*s.z());
  }

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

  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:
  Array* initpoints;
  int size;

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

 public:
  Poly(Array* _points) {
	Poly(_points, Color(1,1,1));
  }

  Poly(Array* _points, Color _color) {
	size = _points->length();
	position = new Vec(0,0,0);
	rotation = new Vec(0,0,0);
	color = _color.clone();

#ifdef DEBUG
	  printf("new Poly(%d)\n", size);
#endif
	initpoints = new Array(_points);

	setCenter(calcCenter());
  }

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

  /*
   * 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);
	Vec* t;
	initpoints->reset();
	while ( t = (Vec*)initpoints->next() ) {
		s = s+*t;
	}
	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();
	Vec* t;
	initpoints->reset();
	while ( t = (Vec*)initpoints->next() ) {
		t->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 = *((Vec*)initpoints->get(2)) - *((Vec*)initpoints->get(0));
	//Vec v2 = *((Vec*)initpoints->get(1)) - *((Vec*)initpoints->get(0));
	//glNormal3fv(  v1.cross(v2)+ *(Vec*)((*initpoints)[0]).c  );
	//glNormal3fv(  v1.cross(v2) + ((Vec*)initpoints->get(0))->c  );

	Vec* t;
	Vec* mv;
	initpoints->reset();
	while ( (t = (Vec*)initpoints->next()) ) {
	  color->drawColor();
	  Vec out = (*t - *position);
	  out = rotate_x(out);
	  out = rotate_y(out);
	  out = rotate_z(out);
	  mv = (*position + out).clone();
	  glVertex3fv(mv->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:
		Array* faces;

		Vec* position;
		Vec* rotation;

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

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

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

		Vec calcCenter() {
			Vec s(0,0,0);
			Poly* t;
			faces->reset();
			while ( t = (Poly*)faces->next() ) {
				s = s + t->calcCenter();
			}
			return s/((float)faces->length());
		}

		void rotate(Vec rot) {
			rotation->add(rot);
			faces->reset();
			Poly* t;
			while ( t = (Poly*)faces->next() ) {
				t->rotate(rot);
			}
		}

		void draw() {
			faces->reset();
			Poly* t;
			while ( t = (Poly*)faces->next() ) {
				t->draw();
			}
		}

		void addFace(Poly* face) {
			faces->push(face);
		}

		int numberOfFaces() {
			return faces->length();
		}
};


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

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

const char* getNextToken(string& line) {
	if ( line.length() < 1 ) {
		return NULL;
	}

	string mp;

	while ( line[0] == ' ' ) {
		line.erase(0, 1);
	}

	int np = line.find(" ", 0);

	if ( (unsigned int)np == string::npos ) {
		np = line.length();
	}

	mp = line.substr(0, np);
	line.erase(0, np);

	return mp.c_str();
}

int getNextPoint(string& line) {
	const char* tch;
	tch = getNextToken(line);
	if ( tch == NULL ) {
		return -1;
	}
	return (int)atoi(tch);
}

float getNextCoord(string& line) {
	const char* tch;
	tch = getNextToken(line);
	if ( tch == NULL ) {
		return -1;
	}
	return (float)atof(tch);
}

Model* importModel(char* fname) {

	string line;
	ifstream fp;

	Array* points = new Array();
	Array* tpoints = new Array();
	Model* mm = new Model(new Array());

	int tp = -1;

	
	fp.open(fname);

	if ( ! fp.is_open()) {
		printf("Error reading file %s\n", fname);
		return mm;
	}

	while ( !fp.eof() ) {
		getline(fp, line);

		if ( line[0] == 'v' ) {
			line.erase(0,1);
			points->push(new Vec(getNextCoord(line), getNextCoord(line), getNextCoord(line)));
		}

		if ( line[0] == 'f' ) {
			line.erase(0,1);

			tpoints->clear();
			while ( (tp = getNextPoint(line)) > -1 ) {
				tpoints->push(points->get(tp-1));
			}
			mm->addFace(new Poly(tpoints));
		}
	}

	fp.close();

	delete points;
	delete tpoints;

	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 black  (0,0,0);
   Color blue   (0,0,1);
   Color red    (1,0,0);
   Color violet (1,0,1);
   Color yellow (1,1,0);
   Color white  (1,1,1);
   Color green  (0,1,0);
   Color cyan   (0,1,1);

   Vec* p0  = new Vec(0 ,0 ,0 );
   Vec* p1  = new Vec(10,0 ,0 );
   Vec* p2  = new Vec(10,10,0 );
   Vec* p3  = new Vec(0 ,10,0 );

   Vec* p4  = new Vec(0 ,0 ,10);
   Vec* p5  = new Vec(10,0 ,10);
   Vec* p6  = new Vec(10,10,10);
   Vec* p7  = new Vec(0 ,10,10);

   Vec cen (5,5,5);

   /*

          4---7
          |pp5|
      4---0---3---7---4
      |pp2|pp0|pp3|pp1|
      5---1---2---6---5
          |pp4|
	  5---6

    */

   Array* pp0 = new Array();
   pp0->push(p0);
   pp0->push(p3);
   pp0->push(p2);
   pp0->push(p1);

   Array* pp1 = new Array();
   pp1->push(p4);
   pp1->push(p5);
   pp1->push(p6);
   pp1->push(p7);

   Array* pp2 = new Array();
   pp2->push(p4);
   pp2->push(p0);
   pp2->push(p1);
   pp2->push(p5);

   Array* pp3 = new Array();
   pp3->push(p2);
   pp3->push(p3);
   pp3->push(p7);
   pp3->push(p6);

   Array* pp4 = new Array();
   pp4->push(p1);
   pp4->push(p2);
   pp4->push(p6);
   pp4->push(p5);

   Array* pp5 = new Array();
   pp5->push(p3);
   pp5->push(p0);
   pp5->push(p4);
   pp5->push(p7);
  
	Array* polys = new Array();
	polys->push(new Poly(pp0, red));
	polys->push(new Poly(pp1, green));
	polys->push(new Poly(pp2, cyan));
	polys->push(new Poly(pp3, blue));
	polys->push(new Poly(pp4, yellow));
	polys->push(new Poly(pp5, violet));

   //Model* myModel = importModel("teapot.obj");
	//	printf("imported teapot.obj : %d faces\n", myModel->numberOfFaces());

  Poly* t;
  polys->reset();
  while ( t = (Poly*)polys->next() ) {
	  //printf("polys %d setCenter\n", polys->pos()-1);
	  t->setCenter(cen);
  }

   //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);

	    polys->reset();
	    while ( t = (Poly*)polys->next() ) {
		   t->draw();
		  t->rotate(Vec(0.0f, 0.01f, 0.01f));
	    }

		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:
      usleep(2000); // 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;
}