Accueil > > > CAMÉRA OPENGL UTILISANT LES QUATERNIONS
CAMÉRA OPENGL UTILISANT LES QUATERNIONS
Information sur la source
Description
Tout d'abord, j'utilise openGL, la GLU et la GLUT. Ca marche sous windows et linux. J'ai un doute pour unix. Mon code est composé de 3 classes : - UnitQuaternion : permet d'utiliser des quaternions unitaires pour représenter des rotations - MovingObject : permet de faire bouger un objet (translation et rotation) en déplaçant soit le repère local autour du repère global, soit l'inverse. - Camera : hérite de MovingObject, permet d'enrichir le comportement d'un objet mobile en lui permettant de modifier la matrice modèle-vue - FlatSurface : permet de définir une surface planaire - Collidable : permet de gérer les collsions ellipsoïdes/ellipsoïdes (pas encore au point) et ellipsoïdes/surfaces planaires Sachez que je fais de l'openGL depuis à peine 4 mois et du C++ depuis 3 mois et demi. Je sais que ce n'est pas très propre, toutes vos critiques seront les bienvenues. Les commentaires sont en anglais car j'ai demandé de l'aide à des gens ne pratiquant pas la langue de Molière, merci de votre compréhension. J'utilise des tableaux de float au même format qu'openGL. Ma classe UnitQuaternion sert à utiliser des quaternions unitaires; les quaternions unitaires forment un sous-espace vectoriel des quaternions, appartenant eux-mêmes aux nombres dits "hypercomplexes". Ma classe MovingObject comprend une matrice appelée "Transform" dont les lignes contiennent les vecteurs suivants: Up, Right, Forward et LA COLONNE Position (Haut, Droite, Devant et Position). Je pars du principe que j'avance dans les Z négatifs. Les quaternions unitaires me servent à stocker et combiner des informations sur les rotations. 3 variables de type flottant me permettent de stocker les angles à la façon de Cardan. J'arrive à modifier la matrice modèle-vue mais sans gimbal lock, en chargeant la matrice identité (ici, c'est peut-être facultatif) et en recalculant la matrice de rotation à partir de mes angles de Cardan en passant par les quaternions puis en replaçant l'objet ou la caméra à sa position initiale. J'essaie d'éviter à tout prix la multiplication de matrice et de garder des informations sur mes vecteurs.
Source
- #include <GL/glut.h>
- #include <GL/glext.h>
- #include <string.h>
- #include <stdlib.h>
- #include <iostream.h>
- #include <math.h>
- #include <vector>
- #ifdef WIN32_API
- #define glutWarpPointer SetCursorPos
- #include <windows.h>
- #endif
- #ifndef M_PI
- #define M_PI 3.14159265359
- #endif
- /*#if !defined(GLUT_WHEEL_UP)
- # define GLUT_WHEEL_UP 4
- # define GLUT_WHEEL_DOWN 5
- #endif
- */
- using namespace std;
-
- //GLUT_MIDDLE_BUTTON
-
- //http://users.ox.ac.uk/~orie1330/bmploader.html
-
- #define BMPError char
- #define BMPNOTABITMAP 'b' //Possible error flags
- #define BMPNOOPEN 'o'
- #define BMPFILEERROR 'f'
- #define BMPBADINT 'i'
- #define BMPNOERROR '\0'
- #define BMPUNKNOWNFORMAT 'u'
- #include <string.h>
-
- typedef unsigned char BYTE;
-
- class BMPClass{
-
- //private: int width;
- public: int width;
- //private: int height;
- public: int height;
- //private: BYTE* bytes;//OpenGL formatted pixels
- public: BYTE* bytes;
-
- public: BMPClass(){
- bytes=NULL;
- }
-
- public: ~BMPClass(){
- if(bytes!=NULL)
- delete[](bytes);
- }
-
- public: BYTE& pixel(int x,int y,int c){
- return(bytes[(y*width+x)*3+c]);
- }
- public: void allocateMem(){
- if(bytes!=NULL)
- delete[](bytes);
- bytes=new BYTE[width*height*3];
- }
-
- //Loads the bmp in fname, and puts the data in the current object
- public: BMPError LoadBMPFromFile(char* fname){
- if(sizeof(int)!=4)
- return(BMPBADINT);
- FILE* f=fopen(fname,"rb"); //open for reading in binary mode
- if(!f)
- return(BMPNOOPEN);
- char header[54];
- fread(header,54,1,f); //read the 54bit main header
- if(header[0]!='B' || header[1]!='M')
- {fclose(f);
- return(BMPNOTABITMAP); //all bitmaps should start "BM"
- }
- //it seems gimp sometimes makes its headers small, so we have to do hence all the fseeks
- int offset=*(unsigned int*)(header+10);
- width=*(int*)(header+18);
- height=*(int*)(header+22);
- //now the bitmap knows how big it is it can allocate its memory
- allocateMem();
- int bits=int(header[28]); //colourdepth
- int x,y,c;
- BYTE cols[256*4]; //colourtable
- switch(bits){
- case(24):
- {fseek(f,offset,SEEK_SET);
- fread(bytes,width*height*3,1,f); //24bit is easy
- for(x=0;x<width*height*3;x+=3) //except the format is BGR, grr
- {BYTE temp=bytes[x];
- bytes[x]=bytes[x+2];
- bytes[x+2]=temp;
- }
- break;
- }
- case(8):
- {fread(cols,256*4,1,f); //read colortable
- fseek(f,offset,SEEK_SET);
- for(y=0;y<height;++y) //(Notice 4bytes/col for some reason)
- for(x=0;x<width;++x)
- {BYTE byte;
- fread(&byte,1,1,f); //just read byte
- for(int c=0;c<3;++c)
- pixel(x,y,c)=cols[byte*4+2-c]; //and look up in the table
- }
- break;
- }
- case(4):
- {fread(cols,16*4,1,f);
- fseek(f,offset,SEEK_SET);
- for(y=0;y<256;++y)
- for(x=0;x<256;x+=2)
- {BYTE byte;
- fread(&byte,1,1,f); //as above, but need to exract two
- for(c=0;c<3;++c) //pixels from each byte
- pixel(x,y,c)=cols[byte/16*4+2-c];
- for(c=0;c<3;++c)
- pixel(x+1,y,c)=cols[byte%16*4+2-c];
- }
- break;
- }
- case(1):
- {fread(cols,8,1,f);
- fseek(f,offset,SEEK_SET);
- for(y=0;y<height;++y)
- for(x=0;x<width;x+=8)
- {BYTE byte;
- fread(&byte,1,1,f);
- //Every byte is eight pixels
- //so I'm shifting the byte to the relevant position, then masking out
- //all but the lowest bit in order to get the index into the colourtable.
- for(int x2=0;x2<8;++x2)
- for(int c=0;c<3;++c)
- pixel(x+x2,y,c)=cols[((byte>>(7-x2))&1)*4+2-c];
- }
- break;
- }
- default:
- {fclose(f);
- return(BMPUNKNOWNFORMAT);
- }
- }
- if(ferror(f))
- {fclose(f);
- return(BMPFILEERROR);
- }
- fclose(f);
- return(BMPNOERROR);
- }
-
- //Translates my error codes into English
- public: static char* TranslateBMPError(BMPError err){
- switch(err)
- {case(BMPNOTABITMAP):
- return "This file is not a bitmap, specifically it doesn't start 'BM'";
- case(BMPNOOPEN):
- return "Failed to open the file, suspect it doesn't exist";
- case(BMPFILEERROR):
- return "ferror said we had an error. This error seems to not always mean anything, try ignoring it";
- case(BMPBADINT):
- return "sizeof(int)!=4 quite a lot of rewriting probably needs to be done on the code";
- case(BMPNOERROR):
- return "No errors detected";
- case(BMPUNKNOWNFORMAT):
- return "Unknown bmp format, ie not 24bit, 256,16 or 2 colour";
- default:
- return "Not a valid error code";
- }
- }
-
- public: GLuint loadBMPTexture(char *filename){
- GLuint TID=0;
- if(LoadBMPFromFile(filename)!=BMPNOERROR)
- return(TID);
- //generate texture
- glPushAttrib(GL_ENABLE_BIT);
- glEnable(GL_TEXTURE_2D);
- glGenTextures(1,&TID);
- glBindTexture(GL_TEXTURE_2D,TID);
- //setup some parameters for texture filters
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- glTexImage2D(GL_TEXTURE_2D,0,3,width,height,0,GL_RGB,GL_UNSIGNED_BYTE,bytes);
- glDisable(GL_TEXTURE_2D);
- glPopAttrib();
- return(TID);
- }
- };
-
-
- //#define JPEG_LIB_VERSION 62
- #ifdef __cplusplus
- extern "C" {
- #endif
- #include <jpeglib.h>
- #include <jconfig.h>
- #include <jerror.h>
- #include <jmorecfg.h>
- //OpenGL texture info
- typedef struct{
- GLsizei width;
- GLsizei height;
-
- GLenum format;
- GLint internalFormat;
- GLuint id;
-
- GLubyte *texels;
- } gl_texture_t;
-
- gl_texture_t* ReadJPEGFromFile(const char *filename){
- gl_texture_t *texinfo = NULL;
- FILE *fp = NULL;
- struct jpeg_decompress_struct cinfo;
- struct jpeg_error_mgr jerr;
- JSAMPROW j;
- int i;
-
- //open image file
- fp = fopen (filename, "rb");
- if (!fp)
- {
- fprintf (stderr, "error: couldn't open \"%s\"!\n", filename);
- return NULL;
- }
-
- //create and configure decompressor
- jpeg_create_decompress (&cinfo);
- cinfo.err = jpeg_std_error (&jerr);
- jpeg_stdio_src (&cinfo, fp);
-
- //read header and prepare for decompression
- jpeg_read_header (&cinfo, TRUE);
- jpeg_start_decompress (&cinfo);
-
- //initialize image's member variables
- texinfo = (gl_texture_t *)malloc (sizeof (gl_texture_t));
- texinfo->width = cinfo.image_width;
- texinfo->height = cinfo.image_height;
- texinfo->internalFormat = cinfo.num_components;
-
- if (cinfo.num_components == 1)
- texinfo->format = GL_LUMINANCE;
- else
- texinfo->format = GL_RGB;
-
- texinfo->texels = (GLubyte *)malloc (sizeof (GLubyte) * texinfo->width
- * texinfo->height * texinfo->internalFormat);
-
- //extract each scanline of the image
- for (i = 0; i < texinfo->height; ++i)
- {
- j = (texinfo->texels +
- ((texinfo->height - (i + 1)) * texinfo->width * texinfo->internalFormat));
- jpeg_read_scanlines (&cinfo, &j, 1);
- }
-
- //finish decompression and release memory
- jpeg_finish_decompress (&cinfo);
- jpeg_destroy_decompress (&cinfo);
-
- fclose (fp);
- return texinfo;
- }
-
- GLuint loadJPEGTexture (const char *filename){
- gl_texture_t *jpeg_tex = NULL;
- GLuint tex_id = 0;
-
- jpeg_tex = ReadJPEGFromFile (filename);
-
- if (jpeg_tex && jpeg_tex->texels)
- {
- //generate texture
- glGenTextures (1, &jpeg_tex->id);
- glBindTexture (GL_TEXTURE_2D, jpeg_tex->id);
-
- //setup some parameters for texture filters and mipmapping
- glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
- glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-
- gluBuild2DMipmaps (GL_TEXTURE_2D, jpeg_tex->internalFormat,
- jpeg_tex->width, jpeg_tex->height,
- jpeg_tex->format, GL_UNSIGNED_BYTE, jpeg_tex->texels);
-
- tex_id = jpeg_tex->id;
-
- //OpenGL has its own copy of texture data
- free (jpeg_tex->texels);
- free (jpeg_tex);
- }
-
- return tex_id;
- }
-
- #ifdef __cplusplus
- }
- #endif
-
- void crossProduct(float *x,float *y,float *z,float x1,float y1,float z1,float x2,float y2,float z2){
- (*x)=y1*z2-z1*y2;
- (*y)=z1*x2-x1*z2;
- (*z)=x1*y2-y1*x2;
- }
-
- void crossProduct(float* vector,float* vector1,float* vector2){
- vector[0]=vector1[1]*vector2[2]-vector1[2]*vector2[1];
- vector[1]=vector1[2]*vector2[0]-vector1[0]*vector2[2];
- vector[2]=vector1[0]*vector2[1]-vector1[1]*vector2[0];
- }
-
- float dot(float x1,float y1,float z1,float x2,float y2,float z2){
- return((x1*x2)+(y1*y2)+(z1*z2));
- }
-
- float dot(float* vector1,float* vector2){
- return((vector1[0]*vector2[0])+
- (vector1[1]*vector2[1])+
- (vector1[2]*vector2[2]));
- }
-
- float norm(float x,float y,float z){
- return(sqrt(x*x+y*y+z*z));
- }
-
- float norm(float* vector){
- return(sqrt(vector[0]*vector[0]+vector[1]*vector[1]+vector[2]*vector[2]));
- }
-
- bool equals(float* vector1,float* vector2){
- return(vector1[0]==vector2[0]&&vector1[1]==vector2[1]&&vector1[2]==vector2[2]);
- }
-
- void vectorFromBipoint(float* vector,float* point1,float* point2){
- vector[0]=point2[0]-point1[0];
- vector[1]=point2[1]-point1[1];
- vector[2]=point2[2]-point1[2];
- }
-
-
- void normalize(float *vector){
- float n;
- if((n=norm(vector))==0)
- return;//avoids a division by zero
- vector[0]/=n;
- vector[1]/=n;
- vector[2]/=n;
- }
-
- void normalize(float *x,float *y,float *z){
- float n;
- if((n=norm((*x),(*y),(*z)))==0)
- return;//avoids a division by zero
- (*x)/=n;
- (*y)/=n;
- (*z)/=n;
- }
-
- class UnitQuaternion{
-
- private: float m_w;
- private: float m_x;
- private: float m_y;
- private: float m_z;
-
- public: inline void setW(float w){
- m_w=w;
- }
-
- public: inline void setX(float x){
- m_x=x;
- }
-
- public: inline void setY(float y){
- m_y=y;
- }
-
- public: inline void setZ(float z){
- m_z=z;
- }
-
- public: inline void createNeutralUnitQuaternion(){
- m_w=1;
- m_x=0;
- m_y=0;
- m_z=0;
- }
-
- //warning!! angle in radians!
- public: void createFromAxisAngle(float angle,float x,float y,float z){
- float r=(float)sin(angle/2.0f);
- m_w=(float)cos(angle/2.0f);
- m_x=x*r;
- m_y=y*r;
- m_z=z*r;
- }
-
- public: float norm(){
- return(sqrt(m_w*m_w+m_x*m_x+m_y*m_y+m_z*m_z));
- }
-
- public: void normalize(){
- float n;
- if((n=norm())==0.0f)
- return;
- m_w/=n;
- m_x/=n;
- m_y/=n;
- m_z/=n;
- }
-
- public: void createMatrix(float* matrix){
- /*float mxXmx=m_x*m_x,myXmy=m_y*m_y,mzXmz=m_z*m_z;
- float mxXmy=m_x*m_y,mzXmw=m_z*m_w,mxXmz=m_x*m_z,myXmw=m_y*m_w,mxXmw=m_x*m_w,myXmz=m_y*m_z;
- matrix[0]=1.0f-2.0f*(myXmy+mzXmz);
- matrix[1]=2.0f*(mxXmy+mzXmw);
- matrix[2]=2.0f*(mxXmz-myXmw);
- matrix[3]=0.0f;
- matrix[4]=2.0f*(mxXmy-mzXmw);
- matrix[5]=1.0f-2.0f*(mxXmx+mzXmz);
- matrix[6]=2.0f*(myXmz+mxXmw);
- matrix[7]=0.0f;
- matrix[8]=2.0f*(mxXmz+myXmw);
- matrix[9]=2.0f*(myXmz-mxXmw);
- matrix[10]=1.0f-2.0f*(mxXmx+myXmy);
- matrix[11]=0.0f;
- matrix[12]=0.0f;
- matrix[13]=0.0f;
- matrix[14]=0.0f;
- matrix[15]=1.0f;*/
- float myXmyX2=m_y*m_y*2.0f,mzXmzX2=m_z*m_z*2.0f,mzXmw=m_z*m_w,
- myXmw=m_y*m_w,mxXmw=m_x*m_w;
- matrix[0]=1.0f-(myXmyX2+mzXmzX2);
- matrix[1]=2.0f*(m_x*m_y+mzXmw);
- matrix[2]=2.0f*(m_x*m_z-myXmw);
- matrix[3]=0.0f;
- matrix[4]=matrix[1]-4.0f*mzXmw;
- matrix[5]=matrix[0]-2.0f*m_x*m_x+myXmyX2;
- matrix[6]=2.0f*(m_y*m_z+mxXmw);
- matrix[7]=0.0f;
- matrix[8]=matrix[2]+4.0f*myXmw;
- matrix[9]=matrix[6]-4.0f*mxXmw;
- matrix[10]=matrix[5]+mzXmzX2-myXmyX2;
- matrix[11]=0.0f;
- matrix[12]=0.0f;
- matrix[13]=0.0f;
- matrix[14]=0.0f;
- matrix[15]=1.0f;
- }
-
- public: void createInvertedMatrix(float* matrix){
- float myXmyX2=m_y*m_y*2.0f,mzXmzX2=m_z*m_z*2.0f,mzXmw=m_z*m_w,
- myXmw=m_y*m_w,mxXmw=m_x*m_w;
- matrix[0]=1.0f-(myXmyX2+mzXmzX2);
- matrix[4]=2.0f*(m_x*m_y+mzXmw);
- matrix[8]=2.0f*(m_x*m_z-myXmw);
- matrix[3]=0.0f;
- matrix[1]=matrix[4]-4.0f*mzXmw;
- matrix[5]=matrix[0]-2.0f*m_x*m_x+myXmyX2;
- matrix[9]=2.0f*(m_y*m_z+mxXmw);
- matrix[7]=0.0f;
- matrix[2]=matrix[8]+4.0f*myXmw;
- matrix[6]=matrix[9]-4.0f*mxXmw;
- matrix[10]=matrix[5]+mzXmzX2-myXmyX2;
- matrix[11]=0.0f;
- matrix[12]=0.0f;
- matrix[13]=0.0f;
- matrix[14]=0.0f;
- matrix[15]=1.0f;
- }
-
- public: UnitQuaternion operator *(UnitQuaternion q){
- UnitQuaternion r;
- r.m_w=m_w*q.m_w-m_x*q.m_x-m_y*q.m_y-m_z*q.m_z;
- r.m_x=m_w*q.m_x+m_x*q.m_w+m_y*q.m_z-m_z*q.m_y;
- r.m_y=m_w*q.m_y+m_y*q.m_w+m_z*q.m_x-m_x*q.m_z;
- r.m_z=m_w*q.m_z+m_z*q.m_w+m_x*q.m_y-m_y*q.m_x;
- return(r);
- }
-
- };
-
-
- class MovingObject{
- protected: float Transform[16];
- protected: float old_position[16];
- protected: UnitQuaternion m_qPitch;
- protected: UnitQuaternion m_qYaw;
- protected: UnitQuaternion m_qRoll;
- //angles of the movement from the initial position
- protected: float m_PitchRadians;
- protected: float m_YawRadians;
- protected: float m_RollRadians;
- //angles of the bounding ellipsoide with the axes at the beginning
- protected: float initial_m_PitchRadians;
- protected: float initial_m_YawRadians;
- protected: float initial_m_RollRadians;
-
- protected: float* vertexArray;
- protected: float* textureCoordinateArray;
- protected: float* normalArray;
- protected: unsigned int* vertexPerTextureArray;
- protected: unsigned int* textureArray;
- protected: unsigned int vertexCount;
- protected: unsigned int textureCount;
-
- public: MovingObject(float x=0.0f,float y=0.0f,float z=0.0f,
- float initial_m_PitchRadians=0.0f,float initial_m_YawRadians=0.0f,
- float initial_m_RollRadians=0.0f,
- float* vertexArray=NULL,unsigned int vertexCount=0,
- float* textureCoordinateArray=NULL,float* normalArray=NULL,
- unsigned int* vertexPerTextureArray=NULL,
- unsigned int* textureArray=NULL,unsigned int textureCount=0){
- this->vertexArray=vertexArray;
- this->textureCoordinateArray=textureCoordinateArray;
- this->normalArray=normalArray;
- this->textureArray=textureArray;
- this->vertexPerTextureArray=vertexPerTextureArray;
- //declare them here
- //use sizeof to get their sizes like this:
- //vertexCount=sizeof(vertexArray)/sizeof(float);
- //textureCount=sizeof(textureArray)/sizeof(float);
- //warning!! vertexPerTextureArray's size must be equals to
- //textureCount!!
- //use glGenTextures to initialize textureArray
- // glBindTexture to select the texture
- // glTexImage2D or GluBuild2DMipmaps to load the image data in the texture
- this->textureCount=textureCount;
- this->vertexCount=vertexCount;
- //4x4 matrix filled with 0
- Transform[0]=1.0f;
- Transform[1]=0.0f;
- Transform[2]=0.0f;
- Transform[3]=0.0f;
- Transform[4]=0.0f;
- Transform[5]=1.0f;
- Transform[6]=0.0f;
- Transform[7]=0.0f;
- Transform[8]=0.0f;
- Transform[9]=0.0f;
- Transform[10]=-1.0f;
- Transform[11]=0.0f;
- Transform[12]=x;//translation matrix
- Transform[13]=y;
- Transform[14]=z;
- Transform[15]=1.0f;
- old_position[0]=x;
- old_position[1]=y;
- old_position[2]=z;
- m_PitchRadians=0.0f;
- m_YawRadians=0.0f;
- m_RollRadians=0.0f;
- this->initial_m_PitchRadians=initial_m_PitchRadians;
- this->initial_m_YawRadians=initial_m_YawRadians;
- this->initial_m_RollRadians=initial_m_RollRadians;
- m_qPitch.createNeutralUnitQuaternion();
- m_qYaw.createNeutralUnitQuaternion();
- m_qRoll.createNeutralUnitQuaternion();
- }
-
- public: virtual ~MovingObject(){
- if(vertexArray!=NULL)
- delete[](vertexArray);
- if(textureCoordinateArray!=NULL)
- delete[](textureCoordinateArray);
- if(normalArray!=NULL)
- delete[](normalArray);
- if(textureArray!=NULL)
- delete[](textureArray);
- }
-
- public: virtual void undoPositionChanges(){
- float tmp[3];
- int i;
- for(i=0;i<16;i++)
- tmp[i]=old_position[i];
- for(i=0;i<16;i++)
- old_position[i]=Transform[i];
- for(i=0;i<16;i++)
- Transform[i]=tmp[i];
- }
-
- public: virtual void updateOldPosition(){
- for(int i=0;i<16;i++)
- old_position[i]=Transform[i];
- }
-
- public: virtual void moveLocal(float x,float y,float z,float distance=1){
- float dx=x*Transform[0]+y*Transform[4]+z*Transform[8];
- float dy=x*Transform[1]+y*Transform[5]+z*Transform[9];
- float dz=x*Transform[2]+y*Transform[6]+z*Transform[10];
- updateOldPosition();
- Transform[12]+=dx*distance;
- Transform[13]+=dy*distance;
- Transform[14]+=dz*distance;
- }
-
- public: virtual void moveGlobal(float x,float y,float z,float distance=1){
- updateOldPosition();
- Transform[12]+=x*distance;
- Transform[13]+=y*distance;
- Transform[14]+=z*distance;
- }
-
- public: virtual void rotateLocal(float angle,float x,float y,float z){
- //rotation at the point (0,0,0)
- //around the vector (x,y,z) by deg degrees
- //glPushMatrix();
- //glLoadMatrixf(Transform);
- //glRotatef(deg,x,y,z);
- //glGetFloatv(GL_MODELVIEW_MATRIX,Transform);
- //glPopMatrix();
- if(x!=0)
- m_PitchRadians=0;
- if(y!=0)
- m_YawRadians=0;
- if(z!=0)
- m_RollRadians=0;
- rotateGlobal(angle,x,y,z);
- }
-
- public: virtual void rotateGlobal(float angle,float x,float y,float z){
- //we have to invert the rotations to get global axes
- //in local coordinates. That's just the transposed matrix
- //here
- /*
- float dx=x*Transform[0]+y*Transform[1]+z*Transform[2];
- float dy=x*Transform[4]+y*Transform[5]+z*Transform[6];
- float dz=x*Transform[8]+y*Transform[9]+z*Transform[10];
- */
- // Right Up Forward
- // FIRST TRY WITH UVN
- /*
- glMatrixMode(GL_MODELVIEW);
- glPushMatrix();
- glLoadMatrixf(Transform);
- glRotatef(angle,dx,dy,dz);
- glGetFloatv(GL_MODELVIEW_MATRIX,Transform);
- glPopMatrix();*/
- //SECOND TRY WITH QUATERNIONS BUT NOT WORKING
- //STILL GIMBAL LOCK
- /*
- if(dx==0)
- m_qPitch.createNeutralUnitQuaternion();
- else
- m_qPitch.createFromAxisAngle(angle,dx,0.0f,0.0f);
- if(dy==0)
- m_qYaw.createNeutralUnitQuaternion();
- else
- m_qYaw.createFromAxisAngle(angle,0.0f,dy,0.0f);
- if(dz==0)
- m_qRoll.createNeutralUnitQuaternion();
- else
- m_qRoll.createFromAxisAngle(angle,0.0f,0.0f,dz);
- UnitQuaternion q=m_qPitch*m_qYaw*m_qRoll;
- float matrix[16];
- q.createInvertedMatrix(matrix);
- glPushMatrix();
- glLoadMatrixf(matrix);
- glMultMatrixf(Transform);
- float tmp[3]={Transform[12],Transform[13],Transform[14]};
- glGetFloatv(GL_MODELVIEW_MATRIX,Transform);
- Transform[12]=tmp[0];
- Transform[13]=tmp[1];
- Transform[14]=tmp[2];
- glPopMatrix();
- */
- // NEW NEW NEW
- if(x!=0.0f)
- {m_PitchRadians+=angle;
- if(m_PitchRadians<-M_PI)
- m_PitchRadians+=2*M_PI;
- else
- if(m_PitchRadians>M_PI)
- m_PitchRadians-=2*M_PI;
- m_qPitch.createFromAxisAngle(m_PitchRadians,1.0f,0.0f,0.0f);
- m_qPitch.normalize();
- }
- if(y!=0.0f)
- {m_YawRadians+=angle;
- if(m_YawRadians<-M_PI)
- m_YawRadians+=2*M_PI;
- else
- if(m_YawRadians>M_PI)
- m_YawRadians-=2*M_PI;
- m_qYaw.createFromAxisAngle(m_YawRadians,0.0f,1.0f,0.0f);
- m_qYaw.normalize();
- }
- if(z!=0.0f)
- {m_RollRadians+=angle;
- if(m_RollRadians<-M_PI)
- m_RollRadians+=2*M_PI;
- else
- if(m_RollRadians>M_PI)
- m_RollRadians-=2*M_PI;
- m_qRoll.createFromAxisAngle(m_RollRadians,0.0f,0.0f,1.0f);
- m_qRoll.normalize();
- }
- UnitQuaternion q=m_qPitch*m_qYaw*m_qRoll;
- q.normalize();
- updateOldPosition();
- float position[3]={Transform[12],Transform[13],Transform[14]};
- q.createMatrix(Transform);
- Transform[12]=position[0];
- Transform[13]=position[1];
- Transform[14]=position[2];
- /*
- cout <<"\n[[";
- for(int i=0,j=0;i<16;i++)
- {if(matrix[(i*4)%16+j]==-0)
- matrix[(i*4)%16+j]=0;
- cout <<matrix[(i*4)%16+j]<<" ";
- if(i%4==3)
- {j++;
- if(i!=15)
- cout <<"]\n [";
- else cout <<"]]";
- }
- }
- cout <<"\n"; */
- /*
- cout <<"\n[[";
- for(int i=0,j=0;i<16;i++)
- {if(Transform[(i*4)%16+j]==-0)
- Transform[(i*4)%16+j]=0;
- cout <<Transform[(i*4)%16+j]<<" ";
- if(i%4==3)
- {j++;
- if(i!=15)
- cout <<"]\n [";
- else cout <<"]]";
- }
- }
- cout <<"\n";*/
- }
-
- public: void toString(){
- cout <<"\n[[";
- for(int i=0,j=0;i<16;i++)
- {if(Transform[(i*4)%16+j]==-0)
- Transform[(i*4)%16+j]=0;
- cout <<Transform[(i*4)%16+j]<<" ";
- if(i%4==3)
- {j++;
- if(i!=15)
- cout <<"]\n [";
- else cout <<"]]";
- }
- }
- cout <<"\n";
- }
-
- public: virtual void draw(){
- //we need to know:
- // the number of vertices (= the number of normals)
- // ? (= the number of texture coordinates)
- // the number of textures
- // the numbers of vertices to use before changing
- // the current texture that has to be used
- // OR
- // the number of texture=the number of vertices/4
- glPushMatrix();
- glEnableClientState(GL_VERTEX_ARRAY);
- glEnableClientState(GL_TEXTURE_COORD_ARRAY);
- glEnableClientState(GL_NORMAL_ARRAY);
- glEnableClientState(GL_TEXTURE_2D);
- //glLockArrays();
- glVertexPointer(3,GL_FLOAT,0,vertexArray);
- glTexCoordPointer(3,GL_FLOAT,0,textureCoordinateArray);
- glNormalPointer(GL_FLOAT,0,normalArray);
- glLoadMatrixf(Transform);
- for(unsigned int i=0,j=0;i<textureCount&&j<vertexCount;i++)
- {glBindTexture(GL_TEXTURE_2D,textureArray[i]);
- glDrawArrays(GL_POLYGON,j,vertexPerTextureArray[i]);
- j+=vertexPerTextureArray[i];
- }
- //glUnlockArrays();
- glDisableClientState(GL_VERTEX_ARRAY);
- glDisableClientState(GL_TEXTURE_COORD_ARRAY);
- glDisableClientState(GL_NORMAL_ARRAY);
- glDisableClientState(GL_TEXTURE_2D);
- glPopMatrix();
- }
- };
-
- class Camera :public MovingObject{
- private: float min_m_PitchRadians;
- private: float min_m_YawRadians;
- private: float min_m_RollRadians;
- private: float max_m_PitchRadians;
- private: float max_m_YawRadians;
- private: float max_m_RollRadians;
-
- public: Camera(float x=0.0f,float y=0.0f,float z=0.0f,
- float min_m_PitchRadians=-2*M_PI,
- float min_m_YawRadians=-2*M_PI,
- float min_m_RollRadians=-2*M_PI,
- float max_m_PitchRadians=2*M_PI,
- float max_m_YawRadians=2*M_PI,
- float max_m_RollRadians=2*M_PI){
- MovingObject::MovingObject(x,y,z);
- //default behaviour :
- //doesn't clamp any angle while rotating
- this->min_m_PitchRadians=min_m_PitchRadians;
- this->min_m_YawRadians=min_m_YawRadians;
- this->min_m_RollRadians=min_m_RollRadians;
- this->max_m_PitchRadians=max_m_PitchRadians;
- this->max_m_YawRadians=max_m_YawRadians;
- this->max_m_RollRadians=max_m_RollRadians;
- }
-
- //protected: virtual void collide(){}
-
- public: virtual void moveLocal(float x,float y,float z,float distance=1){
- MovingObject::moveLocal(x,y,z,distance);
- setView();
- }
-
- public: virtual void moveGlobal(float x,float y,float z,float distance=1){
- MovingObject::moveGlobal(x,y,z,distance);
- setView();
- }
-
- public: virtual void rotateLocal(float angle,float x,float y,float z){
- if(x!=0)
- m_PitchRadians=0;
- if(y!=0)
- m_YawRadians=0;
- if(z!=0)
- m_RollRadians=0;
- rotateGlobal(angle,x,y,z);
- setView();
- }
-
- public: virtual void rotateGlobal(float angle,float x,float y,float z){
- if(x!=0.0f)
- {m_PitchRadians+=angle;
- if(m_PitchRadians<-M_PI)
- m_PitchRadians+=2*M_PI;
- else
- if(m_PitchRadians>M_PI)
- m_PitchRadians-=2*M_PI;
- if(m_PitchRadians<min_m_PitchRadians)
- m_PitchRadians=min_m_PitchRadians;
- else
- if(m_PitchRadians>max_m_PitchRadians)
- m_PitchRadians=max_m_PitchRadians;
- m_qPitch.createFromAxisAngle(m_PitchRadians,1.0f,0.0f,0.0f);
- m_qPitch.normalize();
- }
- if(y!=0.0f)
- {m_YawRadians+=angle;
- if(m_YawRadians<-M_PI)
- m_YawRadians+=2*M_PI;
- else
- if(m_YawRadians>M_PI)
- m_YawRadians-=2*M_PI;
- if(m_YawRadians<min_m_YawRadians)
- m_YawRadians=min_m_YawRadians;
- else
- if(m_YawRadians>max_m_YawRadians)
- m_YawRadians=max_m_YawRadians;
- m_qYaw.createFromAxisAngle(m_YawRadians,0.0f,1.0f,0.0f);
- m_qYaw.normalize();
- }
- if(z!=0.0f)
- {m_RollRadians+=angle;
- if(m_RollRadians<-M_PI)
- m_RollRadians+=2*M_PI;
- else
- if(m_RollRadians>M_PI)
- m_RollRadians-=2*M_PI;
- if(m_RollRadians<min_m_RollRadians)
- m_RollRadians=min_m_RollRadians;
- else
- if(m_RollRadians>max_m_RollRadians)
- m_RollRadians=max_m_RollRadians;
- m_qRoll.createFromAxisAngle(m_RollRadians,0.0f,0.0f,1.0f);
- m_qRoll.normalize();
- }
- UnitQuaternion q=m_qPitch*m_qYaw*m_qRoll;
- q.normalize();
- updateOldPosition();
- float position[3]={Transform[12],Transform[13],Transform[14]};
- q.createMatrix(Transform);
- Transform[12]=position[0];
- Transform[13]=position[1];
- Transform[14]=position[2];
- setView();
- }
-
- protected: virtual void setView(){
- float viewmatrix[16]={Transform[0],Transform[4],-Transform[8],0
- ,Transform[1],Transform[5],-Transform[9],0
- ,Transform[2],Transform[6],-Transform[10],0
- ,-(Transform[0]*Transform[12]
- +Transform[1]*Transform[13]
- +Transform[2]*Transform[14])
- ,-(Transform[4]*Transform[12]
- +Transform[5]*Transform[13]
- +Transform[6]*Transform[14])
- ,(Transform[8]*Transform[12]
- +Transform[9]*Transform[13]
- +Transform[10]*Transform[14])
- ,1};
- glLoadMatrixf(viewmatrix);/*
- cout <<"\n[[";
- for(int i=0,j=0;i<16;i++)
- {if(viewmatrix[(i*4)%16+j]==-0)
- viewmatrix[(i*4)%16+j]=0;
- cout <<viewmatrix[(i*4)%16+j]<<" ";
- if(i%4==3)
- {j++;
- if(i!=15)
- cout <<"]\n [";
- else cout <<"]]";
- }
- }
- cout <<"\n";
- gluLookAt(Position[0],Position[1],Position[2]
- ,Forward[0]+Position[0],Forward[1]+Position[1],Forward[2]+Position[2]
- ,Up[0],Up[1],Up[2]);*/
- }
-
- };
-
- class FlatSurface{
- private: float center[3];
- private: float bound[12];
- private: float normal[3];
-
- public: FlatSurface(float bound1x,float bound1y,float bound1z,
- float bound2x,float bound2y,float bound2z,
- float bound3x,float bound3y,float bound3z,
- float bound4x,float bound4y,float bound4z){
- this->bound[0]=bound1x;
- this->bound[1]=bound1y;
- this->bound[2]=bound1z;
- this->bound[3]=bound2x;
- this->bound[4]=bound2y;
- this->bound[5]=bound2z;
- this->bound[6]=bound3x;
- this->bound[7]=bound3y;
- this->bound[8]=bound3z;
- this->bound[9]=bound4x;
- this->bound[10]=bound4y;
- this->bound[11]=bound4z;
- this->center[0]=(bound1x+bound3x)/2;
- this->center[1]=(bound1y+bound3y)/2;
- this->center[2]=(bound1z+bound3z)/2;
- crossProduct(&normal[0],&normal[1],&normal[2],
- (bound2x-bound1x),(bound2y-bound1y),(bound2z-bound1z),
- (bound4x-bound1x),(bound4y-bound1y),(bound4z-bound1z));
- normalize(normal);
- }
-
- private: void updateNormal(){
- crossProduct(&normal[0],&normal[1],&normal[2],
- (bound[3]-bound[0]),(bound[4]-bound[1]),(bound[5]-bound[2]),
- (bound[9]-bound[0]),(bound[10]-bound[1]),(bound[11]-bound[2]));
- normalize(normal);
- }
-
- public: float* getCenter(){
- return(center);
- }
-
- public: float* getBounds(){
- return(bound);
- }
-
- public: float* getNormal(){
- return(normal);
- }
-
- public: bool contains(float* point){
- //b1, b2, b3 and b4 are the rectangle's bounds
- //a is the point supposed to be a collision point
- float b1b3[3];
- vectorFromBipoint(b1b3,&bound[0],&bound[6]);
- float b1a[3];
- vectorFromBipoint(b1a,&bound[0],point);
- float n;
- if((n=norm(b1a))>norm(b1b3))
- return(false);
- if(n==0)
- return(true);
- float cosb1b2b1a,n2,b1b2[3];
- vectorFromBipoint(b1b2,&bound[0],&bound[3]);
- n2=norm(b1b2);
- if((cosb1b2b1a=dot(b1b2,b1a)/(n2*n))<0)
- return(false);
- float k1;
- if(cosb1b2b1a==1)
- {if(b1b2[0]!=0)
- k1=b1a[0]/b1b2[0];
- else
- if(b1b2[1]!=0)
- k1=b1a[1]/b1b2[1];
- else
- k1=b1a[2]/b1b2[2];
- return(k1>0&&k1<=1);
- }
- float b1b4[3],k2;
- vectorFromBipoint(b1b4,&bound[0],&bound[9]);
- if(cosb1b2b1a==0)
- {if(b1b4[0]!=0)
- k2=b1a[0]/b1b4[0];
- else
- if(b1b4[1]!=0)
- k2=b1a[1]/b1b4[1];
- else
- k2=b1a[2]/b1b4[2];
- return(k2>0&&k2<=1);
- }
- if((k1=(cosb1b2b1a*n)/n2)<=0||k1>1)
- return(false);
- float cosb1b4b1a,n4=norm(b1b4);
- if((cosb1b4b1a=dot(b1b4,b1a)/(n4*n))<0)
- return(false);
- return((k2=(cosb1b4b1a*n)/n4)>0&&k2<=1);
- }
-
- public: void draw(){}
-
- };
-
- class WallSet{
- private: vector<FlatSurface> wallsVector;
- //I need to modify FlatSurface to allow it to
- //be able to contain information about the way
- //to draw it
- public: WallSet(FlatSurface walls[]=NULL,unsigned int count=0){
- for(unsigned int i=0;i<count;i++)
- wallsVector.push_back(walls[i]);
- }
-
- public: void addWall(FlatSurface wall){
- wallsVector.push_back(wall);
- }
-
- public: FlatSurface getWall(int index){
- return(wallsVector[index]);
- }
-
- public: unsigned int size(){
- return(wallsVector.size());
- }
-
- public: void draw(){
- for(unsigned int i=0;i<size();i++)
- wallsVector[i].draw();
- }
-
- /*public: void collideAndCorrect(){
-
- }*/
-
- };
-
- class Collidable :public MovingObject{
- //collidable objects considered as spheres
- //protected: unsigned int radius;
- protected: float xradius;
- protected: float yradius;
- protected: float zradius;
-
- public: Collidable(float x=0.0f,float y=0.0f,float z=0.0f,
- float xradius=0.0f,float yradius=0.0f,float zradius=0.0f,
- float initial_m_PitchRadians=0.0f,float initial_m_YawRadians=0.0f,
- float initial_m_RollRadians=0.0f){
- MovingObject::MovingObject(x,y,z,initial_m_PitchRadians,
- initial_m_YawRadians,initial_m_RollRadians);
- //this->radius=radius;
- this->xradius=xradius;
- this->yradius=yradius;
- this->zradius=zradius;
- }
- /*
- public: virtual void moveLocal(float x,float y,float z,float distance=1){
- MovingObject::moveLocal(x,y,z,distance);
-
- }
-
- public: virtual void moveGlobal(float x,float y,float z,float distance=1){
- MovingObject::moveGlobal(x,y,z,distance);
-
- }
-
- public: virtual void rotateLocal(float angle,float x,float y,float z){
- MovingObject::rotateLocal(angle,x,y,z);
-
- }
-
- public: virtual void rotateGlobal(float angle,float x,float y,float z){
- MovingObject::rotateGlobal(angle,x,y,z);
-
- }
- */
- //I can use this collision point and the farthest collision point
- //to compute a distance between them
- //to know how to correct the position of the object
-
- public: virtual void draw(){
- MovingObject::draw();
- }
-
- public: virtual bool collide(FlatSurface surface,float* collision_point,
- float* farthest_collision_point){
- //warning!! the distance between old and new positions must be
- //equal or shorter than the shortest DIAMETER!!
- //Otherwise, the whole movement must be treated as
- //a sum of smaller movements equal or shorter than
- //the shortest DIAMETER
- //handles intersections and check if there is a true collision
- //does NOT handle case of piercing objects provoking multiple
- //collisions per movement
- float d,raydirection[3];
- vectorFromBipoint(raydirection,&old_position[12],&Transform[12]);
- //cout<<"\n"<<Transform[2]<<" "<<Transform[6]<<" "<<Transform[10]<<"\n";
- if(norm(raydirection)!=1)
- normalize(raydirection);
- if((d=dot(surface.getNormal(),raydirection))==0)
- return(false);
- //checks if the surface is parallel to the ray direction
- //why do I take the center of the surface???
- float tmp[3];
- vectorFromBipoint(tmp,&Transform[12],surface.getCenter());
- d=dot(surface.getNormal(),tmp)/d;
- collision_point[0]=Transform[12]+raydirection[0]*d;
- collision_point[1]=Transform[13]+raydirection[1]*d;
- collision_point[2]=Transform[14]+raydirection[2]*d;
- if(isIn(collision_point,farthest_collision_point,raydirection))
- return(surface.contains(collision_point));
- //If d is negative, the collision takes place behind the
- //starting point of the ray along the opposite direction
- //and again there is no intersection.
- //warning!! I'm going to assume that I'm doing a rectilinear
- //movement!!
- //I check if the new position is behind the plane
- if(d<0)
- {float dprime;
- vectorFromBipoint(tmp,&old_position[12],surface.getCenter());
- dprime=dot(surface.getNormal(),tmp)/dot(surface.getNormal(),raydirection);
- //I check if the old position is not behind the plane
- if(dprime<=0)
- return(false);/*
- collision_point[0]=old_position[12]+raydirection[0]*dprime;
- collision_point[1]=old_position[13]+raydirection[1]*dprime;
- collision_point[2]=old_position[14]+raydirection[2]*dprime;*/
- //I check if the direction line goes through the surface
- return(surface.contains(collision_point));
- }
- //else
- // if(d<0)
- // then (the object has gone through the wall)
- // length_of_movement=2*shortest_radius+1
- // length_of_movements=norm(unnormalized_raydirection);
- // remaining_distance=length_of_movements
- // (subdivisions_count=ceil(length_of_movement/length_of_movements);)
- // test a sum of smaller movements equal or shorter than
- // the shortest DIAMETER
- // old_position constant, Transform[12..14] variable
- // while(true)
- // {if(remaining_distance>=length_of_movement)
- // {warning!! this is a rectilinear approximation!!
- // Transform[12]=old_position[12]+length_of_movement*raydirection[0];
- // Transform[13]=old_position[13]+length_of_movement*raydirection[1];
- // Transform[14]=old_position[14]+length_of_movement*raydirection[2];
- // if(collide(surface,collision_point))
- // return(true);
- // remaining_distance-=length_of_movement;
- // }
- // else
- // {warning!! this is a rectilinear approximation!!
- // Transform[12]=old_position[12]+remaining_distance*raydirection[0];
- // Transform[13]=old_position[13]+remaining_distance*raydirection[1];
- // Transform[14]=old_position[14]+remaining_distance*raydirection[2];
- // if(collide(surface,collision_point))
- // return(true);
- // remaining_distance=0; useless
- // break;
- // }
- // }
- return(false);
- }
-
- public: virtual bool isIn(float* collision_point,float* farthest_collision_point,
- float* raydirection){
- bool result=true;
- float collision_vector[3];
- vectorFromBipoint(collision_vector,&Transform[12],collision_point);
- float norm_col=norm(collision_vector);
- /*
- if(xradius==0)
- if(yradius==0)
- if(zradius==0)
- {farthest_collision_point[0]=Transform[12];
- farthest_collision_point[1]=Transform[13];
- farthest_collision_point[2]=Transform[14];
- return(norm_col<=0);
- }
- else
- //line
- else
- if(zradius==0)
- //line
- else
- //ellipse
- else
- if(yradius==0)
- if(zradius==0)
- //line
- else
- //ellipse
- else
- if(zradius==0)
- //ellipse
- else
- //ellipsoide
- */
- //angles of the movement from the axes
- //=angles of the movement from the initial position
- //+angles of the initial position
- float real_m_RollRadians=m_RollRadians+initial_m_RollRadians;
- float real_m_YawRadians=m_YawRadians+initial_m_YawRadians;
- float cosroll=cos(real_m_RollRadians);
- float sinroll=sin(real_m_RollRadians);
- float cosyaw=cos(real_m_YawRadians);
- float sinyaw=sin(real_m_YawRadians);
- if(norm_col==0)
- {//phi==0&&theta==0
- farthest_collision_point[0]=Transform[12]+xradius*cosyaw*cosroll;
- farthest_collision_point[1]=Transform[13]+yradius*cosyaw*sinroll;
- farthest_collision_point[2]=Transform[14]+zradius*sinyaw;
- return(true);
- }
- if(xradius==yradius&&xradius==zradius)
- result=(norm_col<=xradius);
- else
- if(norm_col>xradius&&norm_col>yradius&&norm_col>zradius)
- result=false;
- else
- if(norm_col<=xradius&&norm_col<=yradius&&norm_col<=zradius)
- result=true;
- float a[3];
- a[0]=xradius*cosroll+Transform[12];
- a[1]=xradius*sinroll+Transform[13];
- if(collision_point[0]!=Transform[12])
- a[2]=((xradius*cosroll/(collision_point[0]-Transform[12]))*
- (collision_point[2]-Transform[14]))+Transform[14];
- else
- if(collision_point[1]!=Transform[13])
- a[2]=((xradius*sinroll/(collision_point[1]-Transform[13]))*
- (collision_point[2]-Transform[14]))+Transform[14];
- else
- a[2]=Transform[14];
- float oprimea[3];
- vectorFromBipoint(oprimea,&Transform[12],a);
- float norm_oprimea_norm_col=norm(oprimea)*norm_col;
- //warning!! risk of division by zero
- float cosphi=dot(oprimea,collision_vector)/norm_oprimea_norm_col;
- float oprimen[3];
- crossProduct(oprimen,oprimea,collision_vector);
- float sinphi=norm(oprimen)/norm_oprimea_norm_col;
- float c[3];
- c[0]=zradius*cos(real_m_YawRadians)+Transform[12];
- c[2]=zradius*sin(real_m_YawRadians)+Transform[14];
- if(collision_point[0]!=Transform[12])
- c[1]=((zradius*cosyaw/(collision_point[0]-Transform[12]))*
- (collision_point[1]-Transform[13]))+Transform[13];
- else
- if(collision_point[2]!=Transform[14])
- c[1]=((zradius*sinyaw/(collision_point[2]-Transform[14]))*
- (collision_point[1]-Transform[13]))+Transform[13];
- else
- c[1]=Transform[13];
- float oprimec[3];
- vectorFromBipoint(oprimec,&Transform[12],c);
- float norm_oprimec_norm_col=norm(oprimec)*norm_col;
- //warning!! risk of division by zero
- float costheta=dot(oprimec,collision_vector)/norm_oprimec_norm_col;
- float oprimenprime[3];
- crossProduct(oprimenprime,oprimec,collision_vector);
- float sintheta=norm(oprimenprime)/norm_oprimec_norm_col;
- //farthest collision point from the center of the ellipsoid
- float costheta_cosyaw=costheta*cosyaw;
- float cosphi_cosroll=cosphi*cosroll;
- float sintheta_sinyaw=sintheta*sinyaw;
- float sinphi_sinroll=sinphi*sinroll;
- float costheta_cosyaw___sintheta_sinyaw=
- costheta_cosyaw-sintheta_sinyaw;
- farthest_collision_point[0]=Transform[12]+xradius*
- costheta_cosyaw___sintheta_sinyaw*(cosphi_cosroll-sinphi_sinroll);
- farthest_collision_point[1]=Transform[13]+yradius*
- costheta_cosyaw___sintheta_sinyaw*(sinphi_sinroll+cosphi_cosroll);
- farthest_collision_point[2]=Transform[14]+zradius*
- (sintheta_sinyaw+costheta*cosyaw);
- float farthest_collision_vector[3];
- vectorFromBipoint(farthest_collision_vector,&Transform[12],farthest_collision_point);
- if(norm(collision_vector)>norm(farthest_collision_vector))
- return(false);
- return(result);
- }
-
- //I can use this distance between farthest collision points
- //to know how to correct the position of the object
- public: virtual bool collide(Collidable object,
- float* vector_between_farthest_collision_points,float* first_farthest_collision_point){
- //warning!! the distance between old and new positions must be
- //equal or shorter than the sum of the shortest DIAMETERS!!
- //Otherwise, the whole movement must be treated as
- //a sum of smaller movements equal or shorter than
- //the shortest DIAMETER
- float second_farthest_collision_point[3];
- bool result=false;
- float raydirection[3];
- vectorFromBipoint(raydirection,&old_position[12],&Transform[12]);
- if(norm(raydirection)!=1)
- normalize(raydirection);
- if(isIn(&(object.Transform[12]),first_farthest_collision_point,raydirection))
- result=true;
- //this excludes the case O==F'
- //this excludes the case O' in this
- vectorFromBipoint(raydirection,&Transform[12],&old_position[12]);
- if(norm(raydirection)!=1)
- normalize(raydirection);
- if(object.isIn(&Transform[12],second_farthest_collision_point,raydirection))
- result=true;
- //this excludes the case O in object
- float ffprime[3];
- vectorFromBipoint(ffprime,first_farthest_collision_point,second_farthest_collision_point);
- vectorFromBipoint(vector_between_farthest_collision_points
- ,first_farthest_collision_point,second_farthest_collision_point);
- if(result==true||equals(first_farthest_collision_point,second_farthest_collision_point))
- return(true);
- //this excludes the case F==F'
- if(equals(&Transform[12],first_farthest_collision_point))
- {float oprimefprime[3];
- vectorFromBipoint(oprimefprime,&(object.Transform[12]),second_farthest_collision_point);
- float oprimef[3];
- vectorFromBipoint(oprimef,&(object.Transform[12]),first_farthest_collision_point);
- if(norm(oprimefprime)>=norm(oprimef))
- return(true);
- //this excludes the case O==F
- }
- else
- {float of[3];
- vectorFromBipoint(of,&Transform[12],first_farthest_collision_point);
- float ofprime[3];
- vectorFromBipoint(ofprime,&Transform[12],second_farthest_collision_point);
- float k;
- if(ofprime[0]!=0)
- k=of[0]/ofprime[0];
- else
- if(ofprime[1]!=0)
- k=of[1]/ofprime[1];
- else
- k=of[2]/ofprime[2];
- if(k>=1)
- return(true);
- //no need to check when k<0 because it is treated
- //above, when O is in object
- }
- return(false);
- //comment the line above and uncomment the lines below if
- //you have objects doing movements greater than their own
- //shortest diameter
- //at last, we must check if this has not gone through the object
- //we build the plane which is orthogonal to (OO') in 3 steps
- // we use the dot product to get a vector which is
- // orthogonal to (OO')
- // we use the cross product to get a vector which is
- // orthogonal to the both vectors
- // we sum O'F'' and O'F'' to get the last point
- //we use the class 'FlatSurface' to build a surface
- //we throw a ray and check if this was behind the plane
- //we build an other plane which is orthogonal to
- //the greatest radius and contains O
- //we check if rays from the
- //following points go through this new plane
- //we check if they go through the ellipse which
- //comes from the object's ellipsoide :
- // the former origin
- // its projection at the top of this ellipsoide
- // its projection at the bottom of this ellipsoide
- }
-
- public: virtual void collideAndCorrect(WallSet walls){
- for(unsigned int i=0;i<walls.size();i++)
- collideAndCorrect(walls.getWall(i));
- }
-
- public: virtual bool collideAndCorrect(FlatSurface surface){
- float collision_point[3];
- float farthest_collision_point[3];
- if(collide(surface,collision_point,farthest_collision_point))
- {reactDuringCollisionWith(surface,collision_point,farthest_collision_point);
- float tmp[3];
- vectorFromBipoint(tmp,&Transform[12],&old_position[12]);
- float farthest_collision_vector[3];
- vectorFromBipoint(farthest_collision_vector,collision_point
- ,farthest_collision_point);
- float n=norm(farthest_collision_vector);
- tmp[0]*=n+0.0001f;
- tmp[1]*=n+0.0001f;
- tmp[2]*=n+0.0001f;
- correct(tmp);
- return(true);
- }
- return(false);
- }
-
- public: virtual bool collideAndCorrect(Collidable object){
- float vector_between_farthest_collision_points[3];
- float first_farthest_collision_point[3];
- if(collide(object,vector_between_farthest_collision_points,
- first_farthest_collision_point))
- {reactDuringCollisionWith(object,vector_between_farthest_collision_points
- ,first_farthest_collision_point);
- float tmp[3];
- vectorFromBipoint(tmp,&Transform[12],&old_position[12]);
- float n=dot(vector_between_farthest_collision_points,tmp);
- tmp[0]*=n+0.0001f;
- tmp[1]*=n+0.0001f;
- tmp[2]*=n+0.0001f;
- correct(tmp);
- return(true);
- }
- return(false);
- }
-
- protected: virtual void correct(float* correction_vector){
- Transform[12]+=correction_vector[0];
- Transform[13]+=correction_vector[1];
- Transform[14]+=correction_vector[2];
- }
-
- public: virtual float getCollisionDamage(){
- return(0.0f);
- }
-
- protected: virtual void reactDuringCollisionWith(FlatSurface surface
- ,float* collision_point,float* farthest_collision_point){
- //will be mainly used for damages and explosions
- }
-
- protected: virtual void reactDuringCollisionWith(Collidable object
- ,float* vector_between_farthest_collision_points
- ,float* first_farthest_collision_point){
- //will be mainly used for damages and explosions
- }
-
- /*
- public: virtual bool collide(FlatSurface surface){
- float collision_point[3];
- return(collide(surface,collision_point));
- }
- */
- };
-
-
-
- class Fallable:public Collidable{
-
- public: void fall(){}
-
- };
-
- class Player:public Fallable,Camera{
- //handle ammo
- //handle life
- };
-
- class Bot:public Fallable,Camera{
- //redefine getCollisionDamage
- //handle other kinds of damage
- };
-
- class Projectile:public Collidable{
- //redefine getCollisionDamage
- };
-
- //I may need an Explosion class
-
- #define STARTING_MODE 0 //display a few images
- #define INTRO_MODE 1 //display a few images
- #define PLAYING_MODE 5 //display the game, movements allowed
- #define PAUSING_MODE 2 //display a few images
- #define DYING_MODE 4 //display the game, movements not allowed, no gun
- #define GAME_OVER_MODE 3 //display a few images
-
- //I can simulate the death by reducing the yradius of the player
-
- static short alpha=0,beta=0,Gamma=0,delta=0;
- static int pointerx,pointery;
- static Camera cam(0,0,0,-M_PI/2.0f,-2*M_PI,-2*M_PI,M_PI/2.0f,2*M_PI,2*M_PI);
- static Collidable object(0,0,0,10,5,10);
- static FlatSurface wall(20,20,2000,20,-20,2000,20,-20,-2000,20,20,-2000);
- static unsigned short WINDOW_WIDTH,WINDOW_HEIGHT;
- static unsigned char GAME_CURRENT_DISPLAY_MODE;
- static unsigned int menu_textures_ID[16];
- static int current_menu_texture_index;
-
- void warpPointerAtCenter(){
- pointerx=WINDOW_WIDTH/2;
- pointery=WINDOW_HEIGHT/2;
- glutWarpPointer((int)pointerx,(int)pointery);
- }
-
- bool pointerAtEdge(){
- return(pointerx<=0||pointerx>=WINDOW_WIDTH-1||
- pointery<=0||pointerx>=WINDOW_HEIGHT-1);
- }
-
- void drawWalls(){
- glBegin(GL_QUADS);
- glNormal3f(-1,0,0);
- glVertex3f(-20,20,-2000);
- glVertex3f(-20,-20,-2000);
- glVertex3f(-20,-20,2000);
- glVertex3f(-20,20,2000);
-
- glNormal3f(1,0,0);
- glVertex3f(20,20,2000);
- glVertex3f(20,-20,2000);
- glVertex3f(20,-20,-2000);
- glVertex3f(20,20,-2000);
-
- glEnd();
- }
-
- void drawParallelipipede(float x,float y,float z){
- glBegin(GL_QUADS);
-
- glNormal3f(0,0,1);
- glVertex3f(-x/2,y/2,z/2);
- glVertex3f(-x/2,-y/2,z/2);
- glVertex3f(x/2,-y/2,z/2);
- glVertex3f(x/2,y/2,z/2);
-
- glNormal3f(1,0,0);
- glVertex3f(x/2,y/2,z/2);
- glVertex3f(x/2,-y/2,z/2);
- glVertex3f(x/2,-y/2,-z/2);
- glVertex3f(x/2,y/2,-z/2);
-
- glNormal3f(0,0,-1);
- glVertex3f(x/2,y/2,-z/2);
- glVertex3f(x/2,-y/2,-z/2);
- glVertex3f(-x/2,-y/2,-z/2);
- glVertex3f(-x/2,y/2,-z/2);
-
- glNormal3f(-1,0,0);
- glVertex3f(-x/2,y/2,-z/2);
- glVertex3f(-x/2,-y/2,-z/2);
- glVertex3f(-x/2,-y/2,z/2);
- glVertex3f(-x/2,y/2,z/2);
-
- glNormal3f(0,1,0);
- glVertex3f(-x/2,y/2,z/2);
- glVertex3f(x/2,y/2,z/2);
- glVertex3f(x/2,y/2,-z/2);
- glVertex3f(-x/2,y/2,-z/2);
-
- glNormal3f(0,-1,0);
- glVertex3f(-x/2,-y/2,-z/2);
- glVertex3f(x/2,y/2,-z/2);
- glVertex3f(x/2,-y/2,z/2);
- glVertex3f(-x/2,-y/2,z/2);
- glEnd();
- }
-
- void drawArm(int a,int b,int c,int d){
- glRotatef(a,0,0,1);
- glPushMatrix();
- glTranslatef(5.,0.,0.);
- //glScalef(10.,1.,1.);
- glColor3f(1.,0.,0.0);
- drawParallelipipede(10,1,1);
- glPopMatrix();
-
- glTranslatef(10.,0.,0.);
- glRotatef(b,0,0,1);
- glPushMatrix();
- glTranslatef(4.5,0.,0.);
- //glScalef(9.,1.,1.);
- glColor3f(0.,1.,0.0);
- drawParallelipipede(9,1,1);
- glPopMatrix();
-
- glTranslatef(9.,0,0);
- glPushMatrix();
- glRotatef(c,0,0,1);
- glTranslatef(2.,0.,0.);
- //glScalef(4.,1.,1.);
- glColor3f(0.,0.,1.0);
- drawParallelipipede(4,1,1);
- glPopMatrix();
-
- glRotatef(d,0,0,1);
- glTranslatef(2.,0.,0.);
- //glScalef(4.,1.,1.);
- glColor3f(1.,1.,0.0);
- drawParallelipipede(4,1,1);
- }
-
- void init(){
- GAME_CURRENT_DISPLAY_MODE=STARTING_MODE;
- current_menu_texture_index=GAME_CURRENT_DISPLAY_MODE*4;
- char filename[30],tmp[3];
- glEnable(GL_TEXTURE_2D);
- for(int i=0;i<16;i++)
- {strcpy(filename,"menu_texture");
- sprintf(tmp,"%d",i);
- strcat(filename,tmp);
- strcat(filename,".jpg");
- menu_textures_ID[i]=loadJPEGTexture(filename);
- }
- glDisable(GL_TEXTURE_2D);
- WINDOW_WIDTH=glutGet(GLUT_WINDOW_WIDTH);
- WINDOW_HEIGHT=glutGet(GLUT_WINDOW_HEIGHT);
- glClearColor(1.0,1.0,1.0,0.0);
- glClearDepth(1.0);
- glEnable(GL_DEPTH_TEST);
- glDepthFunc(GL_LESS);/*
- glEnable(GL_CULL_FACE);
- glCullFace(GL_BACK);*/
- /*glViewport(-50,-50,100,100);*/
- glMatrixMode(GL_PROJECTION);
- glLoadIdentity();
- /*glFrustum(-50,50,-50,50,20,100);*//*ca marche quand meme*/
- gluPerspective(65.0,((float)WINDOW_WIDTH)/
- ((float)WINDOW_HEIGHT),1,1000);
- glHint(GL_PERSPECTIVE_CORRECTION_HINT,GL_NICEST);
- glMatrixMode(GL_MODELVIEW);
- glutSetCursor(GLUT_CURSOR_NONE);
- warpPointerAtCenter();
- //object.rotateLocal(M_PI/2,0,1,0);
- }
-
- void display(){
- glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
- if(GAME_CURRENT_DISPLAY_MODE==PLAYING_MODE||
- GAME_CURRENT_DISPLAY_MODE==DYING_MODE)
- {glPushAttrib(GL_COLOR_BUFFER_BIT);
- glPushMatrix();
- drawArm(alpha,beta,Gamma,delta);
- glPopMatrix();
- glPopAttrib();
- glPushAttrib(GL_COLOR_BUFFER_BIT);
- glPushMatrix();
- glColor3f(0.3,0.3,0.3);
- drawWalls();
- glPopMatrix();
- glPopAttrib();
- }
- else
- {glPushMatrix();
- glLoadIdentity();
- glEnable(GL_TEXTURE_2D);
- glColor3f(1,1,1);
- glBindTexture(GL_TEXTURE_2D,menu_textures_ID[current_menu_texture_index]);
- glBegin(GL_QUADS);
- glVertex3f(-WINDOW_WIDTH/2,-WINDOW_HEIGHT/2,-250);
- glTexCoord3f(0,1,-250);
- glVertex3f(-WINDOW_WIDTH/2,WINDOW_HEIGHT/2,-250);
- glTexCoord3f(1,1,-250);
- glVertex3f(WINDOW_WIDTH/2,WINDOW_HEIGHT/2,-250);
- glTexCoord3f(1,0,-250);
- glVertex3f(WINDOW_WIDTH/2,-WINDOW_HEIGHT/2,-250);
- glTexCoord3f(0,0,-250);
- glEnd();
- glPopMatrix();/*
- unsigned char bitmap[512*512*3];
- glGetTexImage(GL_TEXTURE_2D,0,GL_RGB,GL_UNSIGNED_BYTE,bitmap);
- glBitmap(512,512,0,0,0,0,bitmap); */
- glDisable(GL_TEXTURE_2D);
- }
- glFlush();
- glutSwapBuffers();/*
- if(object.collide(wall))
- {cout<<"collision\n";
- object.toString();
- } */
- if(pointerAtEdge())
- warpPointerAtCenter();
- }
-
- void special(int key,int x,int y){
- if(GAME_CURRENT_DISPLAY_MODE==PLAYING_MODE)
- {switch(key)
- {case GLUT_KEY_UP :{alpha=(alpha+10)%360;
- glutPostRedisplay();
- break;
- }
- case GLUT_KEY_DOWN :{alpha=(alpha-10)%360;
- glutPostRedisplay();
- break;
- }
- case GLUT_KEY_LEFT :{beta=(beta+10)%360;
- glutPostRedisplay();
- break;
- }
- case GLUT_KEY_RIGHT :{beta=(beta-10)%360;
- glutPostRedisplay();
- break;
- }
- case GLUT_KEY_PAGE_UP :{Gamma=(Gamma+10)%360;
- glutPostRedisplay();
- break;
- }
- case GLUT_KEY_PAGE_DOWN :{Gamma=(Gamma-10)%360;
- glutPostRedisplay();
- break;
- }
- case GLUT_KEY_F1 :{delta=(delta+10)%360;
- glutPostRedisplay();
- break;
- }
- case GLUT_KEY_F2 :{delta=(delta-10)%360;
- glutPostRedisplay();
- break;
- }
- case GLUT_KEY_F3 :{GAME_CURRENT_DISPLAY_MODE=PAUSING_MODE;
- current_menu_texture_index=GAME_CURRENT_DISPLAY_MODE*4;
- glutPostRedisplay();
- break;
- }
- default :{exit(EXIT_SUCCESS);
- break;
- }
- }
- }
- else
- {switch(key)
- {case GLUT_KEY_F4 :{exit(EXIT_SUCCESS);
- break;
- }
- case GLUT_KEY_F3 :{switch(GAME_CURRENT_DISPLAY_MODE)
- {case STARTING_MODE :{GAME_CURRENT_DISPLAY_MODE=INTRO_MODE;
- current_menu_texture_index=GAME_CURRENT_DISPLAY_MODE*4;
- break;
- }
- case INTRO_MODE :{GAME_CURRENT_DISPLAY_MODE=PLAYING_MODE;
- current_menu_texture_index=GAME_CURRENT_DISPLAY_MODE*4;
- break;
- }
- case PAUSING_MODE :{GAME_CURRENT_DISPLAY_MODE=PLAYING_MODE;
- //glPopMatrix();
- current_menu_texture_index=GAME_CURRENT_DISPLAY_MODE*4;
- break;
- }
- case DYING_MODE :{GAME_CURRENT_DISPLAY_MODE=GAME_OVER_MODE;
- current_menu_texture_index=GAME_CURRENT_DISPLAY_MODE*4;
- break;
- }
- case GAME_OVER_MODE :{GAME_CURRENT_DISPLAY_MODE=PLAYING_MODE;
- current_menu_texture_index=GAME_CURRENT_DISPLAY_MODE*4;
- break;
- }
- }
- glutPostRedisplay();
- break;
- }
- }
- }
- }
-
- void keyboard(unsigned char key,int x,int y){
- if(GAME_CURRENT_DISPLAY_MODE==PLAYING_MODE)
- {switch(key)
- {case 'z':{cam.moveLocal(0,0,1,5);
- /*
- cam.move(5);
- cam.move(0);*/
- break;
- }
- case 'q':{cam.moveLocal(1,0,0,-5);/*
- cam.move(-5);
- cam.move(0); */
- break;
- }
- case 's':{cam.moveLocal(1,0,0,5);/*
- cam.move(5);
- cam.move(0); */
- break;
- }
- case 'w':{cam.moveLocal(0,0,1,-5);
- /*cam.move(-5);
- cam.move(0);*/
- break;
- }
- case 't':{object.moveLocal(0,0,1,5);
- break;
- }
- case 'v':{object.moveLocal(0,0,1,-5);
- break;
- }
- case 'f':{object.moveLocal(1,0,0,-5);
- break;
- }
- case 'g':{object.moveLocal(1,0,0,5);
- break;
- }
-
- }
- //cam.setView();
- glutPostRedisplay();
- }
- }
-
- void passiveMotion(int x,int y){
- /*if(GAME_CURRENT_DISPLAY_MODE==PLAYING_MODE)
- {*/
- float shiftx=0,shifty=0;
- if(pointerx-x<0)
- shiftx=-5.0f/60.0f;
- else if(pointerx-x>0)
- shiftx=5.0f/60.0f;
- pointerx=x;
- cam.rotateGlobal(shiftx,0,1,0);
- if(y-pointery<0)
- shifty=-5.0f/60.0f;
- else if(y-pointery>0)
- shifty=5.0f/60.0f;
- pointery=y;
- cam.rotateGlobal(shifty,1,0,0);
- glutPostRedisplay();
- /* }
- else
- {pointerx=x;
- pointery=y;
- }*/
- }
-
- void idle(){
- if(GAME_CURRENT_DISPLAY_MODE==PLAYING_MODE||
- GAME_CURRENT_DISPLAY_MODE==DYING_MODE)
- {
- /*glutPostRedisplay();*/
- }
- else
- {if(current_menu_texture_index!=(GAME_CURRENT_DISPLAY_MODE*4)+3)
- current_menu_texture_index++;
- else
- current_menu_texture_index=GAME_CURRENT_DISPLAY_MODE*4;
- //cout<<current_menu_texture_index<<" "<<menu_textures_ID[current_menu_texture_index]<<" \n";
- //I should use a timer here
- glutPostRedisplay();
- }
- }
-
- int main(int argc,char* argv[]){
- GAME_CURRENT_DISPLAY_MODE=0;
- glutInit(&argc,argv);
- glutInitDisplayMode(GLUT_RGBA|GLUT_DOUBLE|GLUT_DEPTH);
- glutCreateWindow("");
- glutFullScreen();
- init();
- glutIdleFunc(idle);
- glutPassiveMotionFunc(passiveMotion);
- glutDisplayFunc(display);
- glutSpecialFunc(special);
- glutKeyboardFunc(keyboard);
- glutMainLoop();
- exit(EXIT_SUCCESS);
- }
#include <GL/glut.h>
#include <GL/glext.h>
#include <string.h>
#include <stdlib.h>
#include <iostream.h>
#include <math.h>
#include <vector>
#ifdef WIN32_API
#define glutWarpPointer SetCursorPos
#include <windows.h>
#endif
#ifndef M_PI
#define M_PI 3.14159265359
#endif
/*#if !defined(GLUT_WHEEL_UP)
# define GLUT_WHEEL_UP 4
# define GLUT_WHEEL_DOWN 5
#endif
*/
using namespace std;
//GLUT_MIDDLE_BUTTON
//http://users.ox.ac.uk/~orie1330/bmploader.html
#define BMPError char
#define BMPNOTABITMAP 'b' //Possible error flags
#define BMPNOOPEN 'o'
#define BMPFILEERROR 'f'
#define BMPBADINT 'i'
#define BMPNOERROR '\0'
#define BMPUNKNOWNFORMAT 'u'
#include <string.h>
typedef unsigned char BYTE;
class BMPClass{
//private: int width;
public: int width;
//private: int height;
public: int height;
//private: BYTE* bytes;//OpenGL formatted pixels
public: BYTE* bytes;
public: BMPClass(){
bytes=NULL;
}
public: ~BMPClass(){
if(bytes!=NULL)
delete[](bytes);
}
public: BYTE& pixel(int x,int y,int c){
return(bytes[(y*width+x)*3+c]);
}
public: void allocateMem(){
if(bytes!=NULL)
delete[](bytes);
bytes=new BYTE[width*height*3];
}
//Loads the bmp in fname, and puts the data in the current object
public: BMPError LoadBMPFromFile(char* fname){
if(sizeof(int)!=4)
return(BMPBADINT);
FILE* f=fopen(fname,"rb"); //open for reading in binary mode
if(!f)
return(BMPNOOPEN);
char header[54];
fread(header,54,1,f); //read the 54bit main header
if(header[0]!='B' || header[1]!='M')
{fclose(f);
return(BMPNOTABITMAP); //all bitmaps should start "BM"
}
//it seems gimp sometimes makes its headers small, so we have to do hence all the fseeks
int offset=*(unsigned int*)(header+10);
width=*(int*)(header+18);
height=*(int*)(header+22);
//now the bitmap knows how big it is it can allocate its memory
allocateMem();
int bits=int(header[28]); //colourdepth
int x,y,c;
BYTE cols[256*4]; //colourtable
switch(bits){
case(24):
{fseek(f,offset,SEEK_SET);
fread(bytes,width*height*3,1,f); //24bit is easy
for(x=0;x<width*height*3;x+=3) //except the format is BGR, grr
{BYTE temp=bytes[x];
bytes[x]=bytes[x+2];
bytes[x+2]=temp;
}
break;
}
case(8):
{fread(cols,256*4,1,f); //read colortable
fseek(f,offset,SEEK_SET);
for(y=0;y<height;++y) //(Notice 4bytes/col for some reason)
for(x=0;x<width;++x)
{BYTE byte;
fread(&byte,1,1,f); //just read byte
for(int c=0;c<3;++c)
pixel(x,y,c)=cols[byte*4+2-c]; //and look up in the table
}
break;
}
case(4):
{fread(cols,16*4,1,f);
fseek(f,offset,SEEK_SET);
for(y=0;y<256;++y)
for(x=0;x<256;x+=2)
{BYTE byte;
fread(&byte,1,1,f); //as above, but need to exract two
for(c=0;c<3;++c) //pixels from each byte
pixel(x,y,c)=cols[byte/16*4+2-c];
for(c=0;c<3;++c)
pixel(x+1,y,c)=cols[byte%16*4+2-c];
}
break;
}
case(1):
{fread(cols,8,1,f);
fseek(f,offset,SEEK_SET);
for(y=0;y<height;++y)
for(x=0;x<width;x+=8)
{BYTE byte;
fread(&byte,1,1,f);
//Every byte is eight pixels
//so I'm shifting the byte to the relevant position, then masking out
//all but the lowest bit in order to get the index into the colourtable.
for(int x2=0;x2<8;++x2)
for(int c=0;c<3;++c)
pixel(x+x2,y,c)=cols[((byte>>(7-x2))&1)*4+2-c];
}
break;
}
default:
{fclose(f);
return(BMPUNKNOWNFORMAT);
}
}
if(ferror(f))
{fclose(f);
return(BMPFILEERROR);
}
fclose(f);
return(BMPNOERROR);
}
//Translates my error codes into English
public: static char* TranslateBMPError(BMPError err){
switch(err)
{case(BMPNOTABITMAP):
return "This file is not a bitmap, specifically it doesn't start 'BM'";
case(BMPNOOPEN):
return "Failed to open the file, suspect it doesn't exist";
case(BMPFILEERROR):
return "ferror said we had an error. This error seems to not always mean anything, try ignoring it";
case(BMPBADINT):
return "sizeof(int)!=4 quite a lot of rewriting probably needs to be done on the code";
case(BMPNOERROR):
return "No errors detected";
case(BMPUNKNOWNFORMAT):
return "Unknown bmp format, ie not 24bit, 256,16 or 2 colour";
default:
return "Not a valid error code";
}
}
public: GLuint loadBMPTexture(char *filename){
GLuint TID=0;
if(LoadBMPFromFile(filename)!=BMPNOERROR)
return(TID);
//generate texture
glPushAttrib(GL_ENABLE_BIT);
glEnable(GL_TEXTURE_2D);
glGenTextures(1,&TID);
glBindTexture(GL_TEXTURE_2D,TID);
//setup some parameters for texture filters
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D,0,3,width,height,0,GL_RGB,GL_UNSIGNED_BYTE,bytes);
glDisable(GL_TEXTURE_2D);
glPopAttrib();
return(TID);
}
};
//#define JPEG_LIB_VERSION 62
#ifdef __cplusplus
extern "C" {
#endif
#include <jpeglib.h>
#include <jconfig.h>
#include <jerror.h>
#include <jmorecfg.h>
//OpenGL texture info
typedef struct{
GLsizei width;
GLsizei height;
GLenum format;
GLint internalFormat;
GLuint id;
GLubyte *texels;
} gl_texture_t;
gl_texture_t* ReadJPEGFromFile(const char *filename){
gl_texture_t *texinfo = NULL;
FILE *fp = NULL;
struct jpeg_decompress_struct cinfo;
struct jpeg_error_mgr jerr;
JSAMPROW j;
int i;
//open image file
fp = fopen (filename, "rb");
if (!fp)
{
fprintf (stderr, "error: couldn't open \"%s\"!\n", filename);
return NULL;
}
//create and configure decompressor
jpeg_create_decompress (&cinfo);
cinfo.err = jpeg_std_error (&jerr);
jpeg_stdio_src (&cinfo, fp);
//read header and prepare for decompression
jpeg_read_header (&cinfo, TRUE);
jpeg_start_decompress (&cinfo);
//initialize image's member variables
texinfo = (gl_texture_t *)malloc (sizeof (gl_texture_t));
texinfo->width = cinfo.image_width;
texinfo->height = cinfo.image_height;
texinfo->internalFormat = cinfo.num_components;
if (cinfo.num_components == 1)
texinfo->format = GL_LUMINANCE;
else
texinfo->format = GL_RGB;
texinfo->texels = (GLubyte *)malloc (sizeof (GLubyte) * texinfo->width
* texinfo->height * texinfo->internalFormat);
//extract each scanline of the image
for (i = 0; i < texinfo->height; ++i)
{
j = (texinfo->texels +
((texinfo->height - (i + 1)) * texinfo->width * texinfo->internalFormat));
jpeg_read_scanlines (&cinfo, &j, 1);
}
//finish decompression and release memory
jpeg_finish_decompress (&cinfo);
jpeg_destroy_decompress (&cinfo);
fclose (fp);
return texinfo;
}
GLuint loadJPEGTexture (const char *filename){
gl_texture_t *jpeg_tex = NULL;
GLuint tex_id = 0;
jpeg_tex = ReadJPEGFromFile (filename);
if (jpeg_tex && jpeg_tex->texels)
{
//generate texture
glGenTextures (1, &jpeg_tex->id);
glBindTexture (GL_TEXTURE_2D, jpeg_tex->id);
//setup some parameters for texture filters and mipmapping
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
gluBuild2DMipmaps (GL_TEXTURE_2D, jpeg_tex->internalFormat,
jpeg_tex->width, jpeg_tex->height,
jpeg_tex->format, GL_UNSIGNED_BYTE, jpeg_tex->texels);
tex_id = jpeg_tex->id;
//OpenGL has its own copy of texture data
free (jpeg_tex->texels);
free (jpeg_tex);
}
return tex_id;
}
#ifdef __cplusplus
}
#endif
void crossProduct(float *x,float *y,float *z,float x1,float y1,float z1,float x2,float y2,float z2){
(*x)=y1*z2-z1*y2;
(*y)=z1*x2-x1*z2;
(*z)=x1*y2-y1*x2;
}
void crossProduct(float* vector,float* vector1,float* vector2){
vector[0]=vector1[1]*vector2[2]-vector1[2]*vector2[1];
vector[1]=vector1[2]*vector2[0]-vector1[0]*vector2[2];
vector[2]=vector1[0]*vector2[1]-vector1[1]*vector2[0];
}
float dot(float x1,float y1,float z1,float x2,float y2,float z2){
return((x1*x2)+(y1*y2)+(z1*z2));
}
float dot(float* vector1,float* vector2){
return((vector1[0]*vector2[0])+
(vector1[1]*vector2[1])+
(vector1[2]*vector2[2]));
}
float norm(float x,float y,float z){
return(sqrt(x*x+y*y+z*z));
}
float norm(float* vector){
return(sqrt(vector[0]*vector[0]+vector[1]*vector[1]+vector[2]*vector[2]));
}
bool equals(float* vector1,float* vector2){
return(vector1[0]==vector2[0]&&vector1[1]==vector2[1]&&vector1[2]==vector2[2]);
}
void vectorFromBipoint(float* vector,float* point1,float* point2){
vector[0]=point2[0]-point1[0];
vector[1]=point2[1]-point1[1];
vector[2]=point2[2]-point1[2];
}
void normalize(float *vector){
float n;
if((n=norm(vector))==0)
return;//avoids a division by zero
vector[0]/=n;
vector[1]/=n;
vector[2]/=n;
}
void normalize(float *x,float *y,float *z){
float n;
if((n=norm((*x),(*y),(*z)))==0)
return;//avoids a division by zero
(*x)/=n;
(*y)/=n;
(*z)/=n;
}
class UnitQuaternion{
private: float m_w;
private: float m_x;
private: float m_y;
private: float m_z;
public: inline void setW(float w){
m_w=w;
}
public: inline void setX(float x){
m_x=x;
}
public: inline void setY(float y){
m_y=y;
}
public: inline void setZ(float z){
m_z=z;
}
public: inline void createNeutralUnitQuaternion(){
m_w=1;
m_x=0;
m_y=0;
m_z=0;
}
//warning!! angle in radians!
public: void createFromAxisAngle(float angle,float x,float y,float z){
float r=(float)sin(angle/2.0f);
m_w=(float)cos(angle/2.0f);
m_x=x*r;
m_y=y*r;
m_z=z*r;
}
public: float norm(){
return(sqrt(m_w*m_w+m_x*m_x+m_y*m_y+m_z*m_z));
}
public: void normalize(){
float n;
if((n=norm())==0.0f)
return;
m_w/=n;
m_x/=n;
m_y/=n;
m_z/=n;
}
public: void createMatrix(float* matrix){
/*float mxXmx=m_x*m_x,myXmy=m_y*m_y,mzXmz=m_z*m_z;
float mxXmy=m_x*m_y,mzXmw=m_z*m_w,mxXmz=m_x*m_z,myXmw=m_y*m_w,mxXmw=m_x*m_w,myXmz=m_y*m_z;
matrix[0]=1.0f-2.0f*(myXmy+mzXmz);
matrix[1]=2.0f*(mxXmy+mzXmw);
matrix[2]=2.0f*(mxXmz-myXmw);
matrix[3]=0.0f;
matrix[4]=2.0f*(mxXmy-mzXmw);
matrix[5]=1.0f-2.0f*(mxXmx+mzXmz);
matrix[6]=2.0f*(myXmz+mxXmw);
matrix[7]=0.0f;
matrix[8]=2.0f*(mxXmz+myXmw);
matrix[9]=2.0f*(myXmz-mxXmw);
matrix[10]=1.0f-2.0f*(mxXmx+myXmy);
matrix[11]=0.0f;
matrix[12]=0.0f;
matrix[13]=0.0f;
matrix[14]=0.0f;
matrix[15]=1.0f;*/
float myXmyX2=m_y*m_y*2.0f,mzXmzX2=m_z*m_z*2.0f,mzXmw=m_z*m_w,
myXmw=m_y*m_w,mxXmw=m_x*m_w;
matrix[0]=1.0f-(myXmyX2+mzXmzX2);
matrix[1]=2.0f*(m_x*m_y+mzXmw);
matrix[2]=2.0f*(m_x*m_z-myXmw);
matrix[3]=0.0f;
matrix[4]=matrix[1]-4.0f*mzXmw;
matrix[5]=matrix[0]-2.0f*m_x*m_x+myXmyX2;
matrix[6]=2.0f*(m_y*m_z+mxXmw);
matrix[7]=0.0f;
matrix[8]=matrix[2]+4.0f*myXmw;
matrix[9]=matrix[6]-4.0f*mxXmw;
matrix[10]=matrix[5]+mzXmzX2-myXmyX2;
matrix[11]=0.0f;
matrix[12]=0.0f;
matrix[13]=0.0f;
matrix[14]=0.0f;
matrix[15]=1.0f;
}
public: void createInvertedMatrix(float* matrix){
float myXmyX2=m_y*m_y*2.0f,mzXmzX2=m_z*m_z*2.0f,mzXmw=m_z*m_w,
myXmw=m_y*m_w,mxXmw=m_x*m_w;
matrix[0]=1.0f-(myXmyX2+mzXmzX2);
matrix[4]=2.0f*(m_x*m_y+mzXmw);
matrix[8]=2.0f*(m_x*m_z-myXmw);
matrix[3]=0.0f;
matrix[1]=matrix[4]-4.0f*mzXmw;
matrix[5]=matrix[0]-2.0f*m_x*m_x+myXmyX2;
matrix[9]=2.0f*(m_y*m_z+mxXmw);
matrix[7]=0.0f;
matrix[2]=matrix[8]+4.0f*myXmw;
matrix[6]=matrix[9]-4.0f*mxXmw;
matrix[10]=matrix[5]+mzXmzX2-myXmyX2;
matrix[11]=0.0f;
matrix[12]=0.0f;
matrix[13]=0.0f;
matrix[14]=0.0f;
matrix[15]=1.0f;
}
public: UnitQuaternion operator *(UnitQuaternion q){
UnitQuaternion r;
r.m_w=m_w*q.m_w-m_x*q.m_x-m_y*q.m_y-m_z*q.m_z;
r.m_x=m_w*q.m_x+m_x*q.m_w+m_y*q.m_z-m_z*q.m_y;
r.m_y=m_w*q.m_y+m_y*q.m_w+m_z*q.m_x-m_x*q.m_z;
r.m_z=m_w*q.m_z+m_z*q.m_w+m_x*q.m_y-m_y*q.m_x;
return(r);
}
};
class MovingObject{
protected: float Transform[16];
protected: float old_position[16];
protected: UnitQuaternion m_qPitch;
protected: UnitQuaternion m_qYaw;
protected: UnitQuaternion m_qRoll;
//angles of the movement from the initial position
protected: float m_PitchRadians;
protected: float m_YawRadians;
protected: float m_RollRadians;
//angles of the bounding ellipsoide with the axes at the beginning
protected: float initial_m_PitchRadians;
protected: float initial_m_YawRadians;
protected: float initial_m_RollRadians;
protected: float* vertexArray;
protected: float* textureCoordinateArray;
protected: float* normalArray;
protected: unsigned int* vertexPerTextureArray;
protected: unsigned int* textureArray;
protected: unsigned int vertexCount;
protected: unsigned int textureCount;
public: MovingObject(float x=0.0f,float y=0.0f,float z=0.0f,
float initial_m_PitchRadians=0.0f,float initial_m_YawRadians=0.0f,
float initial_m_RollRadians=0.0f,
float* vertexArray=NULL,unsigned int vertexCount=0,
float* textureCoordinateArray=NULL,float* normalArray=NULL,
unsigned int* vertexPerTextureArray=NULL,
unsigned int* textureArray=NULL,unsigned int textureCount=0){
this->vertexArray=vertexArray;
this->textureCoordinateArray=textureCoordinateArray;
this->normalArray=normalArray;
this->textureArray=textureArray;
this->vertexPerTextureArray=vertexPerTextureArray;
//declare them here
//use sizeof to get their sizes like this:
//vertexCount=sizeof(vertexArray)/sizeof(float);
//textureCount=sizeof(textureArray)/sizeof(float);
//warning!! vertexPerTextureArray's size must be equals to
//textureCount!!
//use glGenTextures to initialize textureArray
// glBindTexture to select the texture
// glTexImage2D or GluBuild2DMipmaps to load the image data in the texture
this->textureCount=textureCount;
this->vertexCount=vertexCount;
//4x4 matrix filled with 0
Transform[0]=1.0f;
Transform[1]=0.0f;
Transform[2]=0.0f;
Transform[3]=0.0f;
Transform[4]=0.0f;
Transform[5]=1.0f;
Transform[6]=0.0f;
Transform[7]=0.0f;
Transform[8]=0.0f;
Transform[9]=0.0f;
Transform[10]=-1.0f;
Transform[11]=0.0f;
Transform[12]=x;//translation matrix
Transform[13]=y;
Transform[14]=z;
Transform[15]=1.0f;
old_position[0]=x;
old_position[1]=y;
old_position[2]=z;
m_PitchRadians=0.0f;
m_YawRadians=0.0f;
m_RollRadians=0.0f;
this->initial_m_PitchRadians=initial_m_PitchRadians;
this->initial_m_YawRadians=initial_m_YawRadians;
this->initial_m_RollRadians=initial_m_RollRadians;
m_qPitch.createNeutralUnitQuaternion();
m_qYaw.createNeutralUnitQuaternion();
m_qRoll.createNeutralUnitQuaternion();
}
public: virtual ~MovingObject(){
if(vertexArray!=NULL)
delete[](vertexArray);
if(textureCoordinateArray!=NULL)
delete[](textureCoordinateArray);
if(normalArray!=NULL)
delete[](normalArray);
if(textureArray!=NULL)
delete[](textureArray);
}
public: virtual void undoPositionChanges(){
float tmp[3];
int i;
for(i=0;i<16;i++)
tmp[i]=old_position[i];
for(i=0;i<16;i++)
old_position[i]=Transform[i];
for(i=0;i<16;i++)
Transform[i]=tmp[i];
}
public: virtual void updateOldPosition(){
for(int i=0;i<16;i++)
old_position[i]=Transform[i];
}
public: virtual void moveLocal(float x,float y,float z,float distance=1){
float dx=x*Transform[0]+y*Transform[4]+z*Transform[8];
float dy=x*Transform[1]+y*Transform[5]+z*Transform[9];
float dz=x*Transform[2]+y*Transform[6]+z*Transform[10];
updateOldPosition();
Transform[12]+=dx*distance;
Transform[13]+=dy*distance;
Transform[14]+=dz*distance;
}
public: virtual void moveGlobal(float x,float y,float z,float distance=1){
updateOldPosition();
Transform[12]+=x*distance;
Transform[13]+=y*distance;
Transform[14]+=z*distance;
}
public: virtual void rotateLocal(float angle,float x,float y,float z){
//rotation at the point (0,0,0)
//around the vector (x,y,z) by deg degrees
//glPushMatrix();
//glLoadMatrixf(Transform);
//glRotatef(deg,x,y,z);
//glGetFloatv(GL_MODELVIEW_MATRIX,Transform);
//glPopMatrix();
if(x!=0)
m_PitchRadians=0;
if(y!=0)
m_YawRadians=0;
if(z!=0)
m_RollRadians=0;
rotateGlobal(angle,x,y,z);
}
public: virtual void rotateGlobal(float angle,float x,float y,float z){
//we have to invert the rotations to get global axes
//in local coordinates. That's just the transposed matrix
//here
/*
float dx=x*Transform[0]+y*Transform[1]+z*Transform[2];
float dy=x*Transform[4]+y*Transform[5]+z*Transform[6];
float dz=x*Transform[8]+y*Transform[9]+z*Transform[10];
*/
// Right Up Forward
// FIRST TRY WITH UVN
/*
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadMatrixf(Transform);
glRotatef(angle,dx,dy,dz);
glGetFloatv(GL_MODELVIEW_MATRIX,Transform);
glPopMatrix();*/
//SECOND TRY WITH QUATERNIONS BUT NOT WORKING
//STILL GIMBAL LOCK
/*
if(dx==0)
m_qPitch.createNeutralUnitQuaternion();
else
m_qPitch.createFromAxisAngle(angle,dx,0.0f,0.0f);
if(dy==0)
m_qYaw.createNeutralUnitQuaternion();
else
m_qYaw.createFromAxisAngle(angle,0.0f,dy,0.0f);
if(dz==0)
m_qRoll.createNeutralUnitQuaternion();
else
m_qRoll.createFromAxisAngle(angle,0.0f,0.0f,dz);
UnitQuaternion q=m_qPitch*m_qYaw*m_qRoll;
float matrix[16];
q.createInvertedMatrix(matrix);
glPushMatrix();
glLoadMatrixf(matrix);
glMultMatrixf(Transform);
float tmp[3]={Transform[12],Transform[13],Transform[14]};
glGetFloatv(GL_MODELVIEW_MATRIX,Transform);
Transform[12]=tmp[0];
Transform[13]=tmp[1];
Transform[14]=tmp[2];
glPopMatrix();
*/
// NEW NEW NEW
if(x!=0.0f)
{m_PitchRadians+=angle;
if(m_PitchRadians<-M_PI)
m_PitchRadians+=2*M_PI;
else
if(m_PitchRadians>M_PI)
m_PitchRadians-=2*M_PI;
m_qPitch.createFromAxisAngle(m_PitchRadians,1.0f,0.0f,0.0f);
m_qPitch.normalize();
}
if(y!=0.0f)
{m_YawRadians+=angle;
if(m_YawRadians<-M_PI)
m_YawRadians+=2*M_PI;
else
if(m_YawRadians>M_PI)
m_YawRadians-=2*M_PI;
m_qYaw.createFromAxisAngle(m_YawRadians,0.0f,1.0f,0.0f);
m_qYaw.normalize();
}
if(z!=0.0f)
{m_RollRadians+=angle;
if(m_RollRadians<-M_PI)
m_RollRadians+=2*M_PI;
else
if(m_RollRadians>M_PI)
m_RollRadians-=2*M_PI;
m_qRoll.createFromAxisAngle(m_RollRadians,0.0f,0.0f,1.0f);
m_qRoll.normalize();
}
UnitQuaternion q=m_qPitch*m_qYaw*m_qRoll;
q.normalize();
updateOldPosition();
float position[3]={Transform[12],Transform[13],Transform[14]};
q.createMatrix(Transform);
Transform[12]=position[0];
Transform[13]=position[1];
Transform[14]=position[2];
/*
cout <<"\n[[";
for(int i=0,j=0;i<16;i++)
{if(matrix[(i*4)%16+j]==-0)
matrix[(i*4)%16+j]=0;
cout <<matrix[(i*4)%16+j]<<" ";
if(i%4==3)
{j++;
if(i!=15)
cout <<"]\n [";
else cout <<"]]";
}
}
cout <<"\n"; */
/*
cout <<"\n[[";
for(int i=0,j=0;i<16;i++)
{if(Transform[(i*4)%16+j]==-0)
Transform[(i*4)%16+j]=0;
cout <<Transform[(i*4)%16+j]<<" ";
if(i%4==3)
{j++;
if(i!=15)
cout <<"]\n [";
else cout <<"]]";
}
}
cout <<"\n";*/
}
public: void toString(){
cout <<"\n[[";
for(int i=0,j=0;i<16;i++)
{if(Transform[(i*4)%16+j]==-0)
Transform[(i*4)%16+j]=0;
cout <<Transform[(i*4)%16+j]<<" ";
if(i%4==3)
{j++;
if(i!=15)
cout <<"]\n [";
else cout <<"]]";
}
}
cout <<"\n";
}
public: virtual void draw(){
//we need to know:
// the number of vertices (= the number of normals)
// ? (= the number of texture coordinates)
// the number of textures
// the numbers of vertices to use before changing
// the current texture that has to be used
// OR
// the number of texture=the number of vertices/4
glPushMatrix();
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);
glEnableClientState(GL_TEXTURE_2D);
//glLockArrays();
glVertexPointer(3,GL_FLOAT,0,vertexArray);
glTexCoordPointer(3,GL_FLOAT,0,textureCoordinateArray);
glNormalPointer(GL_FLOAT,0,normalArray);
glLoadMatrixf(Transform);
for(unsigned int i=0,j=0;i<textureCount&&j<vertexCount;i++)
{glBindTexture(GL_TEXTURE_2D,textureArray[i]);
glDrawArrays(GL_POLYGON,j,vertexPerTextureArray[i]);
j+=vertexPerTextureArray[i];
}
//glUnlockArrays();
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisableClientState(GL_NORMAL_ARRAY);
glDisableClientState(GL_TEXTURE_2D);
glPopMatrix();
}
};
class Camera :public MovingObject{
private: float min_m_PitchRadians;
private: float min_m_YawRadians;
private: float min_m_RollRadians;
private: float max_m_PitchRadians;
private: float max_m_YawRadians;
private: float max_m_RollRadians;
public: Camera(float x=0.0f,float y=0.0f,float z=0.0f,
float min_m_PitchRadians=-2*M_PI,
float min_m_YawRadians=-2*M_PI,
float min_m_RollRadians=-2*M_PI,
float max_m_PitchRadians=2*M_PI,
float max_m_YawRadians=2*M_PI,
float max_m_RollRadians=2*M_PI){
MovingObject::MovingObject(x,y,z);
//default behaviour :
//doesn't clamp any angle while rotating
this->min_m_PitchRadians=min_m_PitchRadians;
this->min_m_YawRadians=min_m_YawRadians;
this->min_m_RollRadians=min_m_RollRadians;
this->max_m_PitchRadians=max_m_PitchRadians;
this->max_m_YawRadians=max_m_YawRadians;
this->max_m_RollRadians=max_m_RollRadians;
}
//protected: virtual void collide(){}
public: virtual void moveLocal(float x,float y,float z,float distance=1){
MovingObject::moveLocal(x,y,z,distance);
setView();
}
public: virtual void moveGlobal(float x,float y,float z,float distance=1){
MovingObject::moveGlobal(x,y,z,distance);
setView();
}
public: virtual void rotateLocal(float angle,float x,float y,float z){
if(x!=0)
m_PitchRadians=0;
if(y!=0)
m_YawRadians=0;
if(z!=0)
m_RollRadians=0;
rotateGlobal(angle,x,y,z);
setView();
}
public: virtual void rotateGlobal(float angle,float x,float y,float z){
if(x!=0.0f)
{m_PitchRadians+=angle;
if(m_PitchRadians<-M_PI)
m_PitchRadians+=2*M_PI;
else
if(m_PitchRadians>M_PI)
m_PitchRadians-=2*M_PI;
if(m_PitchRadians<min_m_PitchRadians)
m_PitchRadians=min_m_PitchRadians;
else
if(m_PitchRadians>max_m_PitchRadians)
m_PitchRadians=max_m_PitchRadians;
m_qPitch.createFromAxisAngle(m_PitchRadians,1.0f,0.0f,0.0f);
m_qPitch.normalize();
}
if(y!=0.0f)
{m_YawRadians+=angle;
if(m_YawRadians<-M_PI)
m_YawRadians+=2*M_PI;
else
if(m_YawRadians>M_PI)
m_YawRadians-=2*M_PI;
if(m_YawRadians<min_m_YawRadians)
m_YawRadians=min_m_YawRadians;
else
if(m_YawRadians>max_m_YawRadians)
m_YawRadians=max_m_YawRadians;
m_qYaw.createFromAxisAngle(m_YawRadians,0.0f,1.0f,0.0f);
m_qYaw.normalize();
}
if(z!=0.0f)
{m_RollRadians+=angle;
if(m_RollRadians<-M_PI)
m_RollRadians+=2*M_PI;
else
if(m_RollRadians>M_PI)
m_RollRadians-=2*M_PI;
if(m_RollRadians<min_m_RollRadians)
m_RollRadians=min_m_RollRadians;
else
if(m_RollRadians>max_m_RollRadians)
m_RollRadians=max_m_RollRadians;
m_qRoll.createFromAxisAngle(m_RollRadians,0.0f,0.0f,1.0f);
m_qRoll.normalize();
}
UnitQuaternion q=m_qPitch*m_qYaw*m_qRoll;
q.normalize();
updateOldPosition();
float position[3]={Transform[12],Transform[13],Transform[14]};
q.createMatrix(Transform);
Transform[12]=position[0];
Transform[13]=position[1];
Transform[14]=position[2];
setView();
}
protected: virtual void setView(){
float viewmatrix[16]={Transform[0],Transform[4],-Transform[8],0
,Transform[1],Transform[5],-Transform[9],0
,Transform[2],Transform[6],-Transform[10],0
,-(Transform[0]*Transform[12]
+Transform[1]*Transform[13]
+Transform[2]*Transform[14])
,-(Transform[4]*Transform[12]
+Transform[5]*Transform[13]
+Transform[6]*Transform[14])
,(Transform[8]*Transform[12]
+Transform[9]*Transform[13]
+Transform[10]*Transform[14])
,1};
glLoadMatrixf(viewmatrix);/*
cout <<"\n[[";
for(int i=0,j=0;i<16;i++)
{if(viewmatrix[(i*4)%16+j]==-0)
viewmatrix[(i*4)%16+j]=0;
cout <<viewmatrix[(i*4)%16+j]<<" ";
if(i%4==3)
{j++;
if(i!=15)
cout <<"]\n [";
else cout <<"]]";
}
}
cout <<"\n";
gluLookAt(Position[0],Position[1],Position[2]
,Forward[0]+Position[0],Forward[1]+Position[1],Forward[2]+Position[2]
,Up[0],Up[1],Up[2]);*/
}
};
class FlatSurface{
private: float center[3];
private: float bound[12];
private: float normal[3];
public: FlatSurface(float bound1x,float bound1y,float bound1z,
float bound2x,float bound2y,float bound2z,
float bound3x,float bound3y,float bound3z,
float bound4x,float bound4y,float bound4z){
this->bound[0]=bound1x;
this->bound[1]=bound1y;
this->bound[2]=bound1z;
this->bound[3]=bound2x;
this->bound[4]=bound2y;
this->bound[5]=bound2z;
this->bound[6]=bound3x;
this->bound[7]=bound3y;
this->bound[8]=bound3z;
this->bound[9]=bound4x;
this->bound[10]=bound4y;
this->bound[11]=bound4z;
this->center[0]=(bound1x+bound3x)/2;
this->center[1]=(bound1y+bound3y)/2;
this->center[2]=(bound1z+bound3z)/2;
crossProduct(&normal[0],&normal[1],&normal[2],
(bound2x-bound1x),(bound2y-bound1y),(bound2z-bound1z),
(bound4x-bound1x),(bound4y-bound1y),(bound4z-bound1z));
normalize(normal);
}
private: void updateNormal(){
crossProduct(&normal[0],&normal[1],&normal[2],
(bound[3]-bound[0]),(bound[4]-bound[1]),(bound[5]-bound[2]),
(bound[9]-bound[0]),(bound[10]-bound[1]),(bound[11]-bound[2]));
normalize(normal);
}
public: float* getCenter(){
return(center);
}
public: float* getBounds(){
return(bound);
}
public: float* getNormal(){
return(normal);
}
public: bool contains(float* point){
//b1, b2, b3 and b4 are the rectangle's bounds
//a is the point supposed to be a collision point
float b1b3[3];
vectorFromBipoint(b1b3,&bound[0],&bound[6]);
float b1a[3];
vectorFromBipoint(b1a,&bound[0],point);
float n;
if((n=norm(b1a))>norm(b1b3))
return(false);
if(n==0)
return(true);
float cosb1b2b1a,n2,b1b2[3];
vectorFromBipoint(b1b2,&bound[0],&bound[3]);
n2=norm(b1b2);
if((cosb1b2b1a=dot(b1b2,b1a)/(n2*n))<0)
return(false);
float k1;
if(cosb1b2b1a==1)
{if(b1b2[0]!=0)
k1=b1a[0]/b1b2[0];
else
if(b1b2[1]!=0)
k1=b1a[1]/b1b2[1];
else
k1=b1a[2]/b1b2[2];
return(k1>0&&k1<=1);
}
float b1b4[3],k2;
vectorFromBipoint(b1b4,&bound[0],&bound[9]);
if(cosb1b2b1a==0)
{if(b1b4[0]!=0)
k2=b1a[0]/b1b4[0];
else
if(b1b4[1]!=0)
k2=b1a[1]/b1b4[1];
else
k2=b1a[2]/b1b4[2];
return(k2>0&&k2<=1);
}
if((k1=(cosb1b2b1a*n)/n2)<=0||k1>1)
return(false);
float cosb1b4b1a,n4=norm(b1b4);
if((cosb1b4b1a=dot(b1b4,b1a)/(n4*n))<0)
return(false);
return((k2=(cosb1b4b1a*n)/n4)>0&&k2<=1);
}
public: void draw(){}
};
class WallSet{
private: vector<FlatSurface> wallsVector;
//I need to modify FlatSurface to allow it to
//be able to contain information about the way
//to draw it
public: WallSet(FlatSurface walls[]=NULL,unsigned int count=0){
for(unsigned int i=0;i<count;i++)
wallsVector.push_back(walls[i]);
}
public: void addWall(FlatSurface wall){
wallsVector.push_back(wall);
}
public: FlatSurface getWall(int index){
return(wallsVector[index]);
}
public: unsigned int size(){
return(wallsVector.size());
}
public: void draw(){
for(unsigned int i=0;i<size();i++)
wallsVector[i].draw();
}
/*public: void collideAndCorrect(){
}*/
};
class Collidable :public MovingObject{
//collidable objects considered as spheres
//protected: unsigned int radius;
protected: float xradius;
protected: float yradius;
protected: float zradius;
public: Collidable(float x=0.0f,float y=0.0f,float z=0.0f,
float xradius=0.0f,float yradius=0.0f,float zradius=0.0f,
float initial_m_PitchRadians=0.0f,float initial_m_YawRadians=0.0f,
float initial_m_RollRadians=0.0f){
MovingObject::MovingObject(x,y,z,initial_m_PitchRadians,
initial_m_YawRadians,initial_m_RollRadians);
//this->radius=radius;
this->xradius=xradius;
this->yradius=yradius;
this->zradius=zradius;
}
/*
public: virtual void moveLocal(float x,float y,float z,float distance=1){
MovingObject::moveLocal(x,y,z,distance);
}
public: virtual void moveGlobal(float x,float y,float z,float distance=1){
MovingObject::moveGlobal(x,y,z,distance);
}
public: virtual void rotateLocal(float angle,float x,float y,float z){
MovingObject::rotateLocal(angle,x,y,z);
}
public: virtual void rotateGlobal(float angle,float x,float y,float z){
MovingObject::rotateGlobal(angle,x,y,z);
}
*/
//I can use this collision point and the farthest collision point
//to compute a distance between them
//to know how to correct the position of the object
public: virtual void draw(){
MovingObject::draw();
}
public: virtual bool collide(FlatSurface surface,float* collision_point,
float* farthest_collision_point){
//warning!! the distance between old and new positions must be
//equal or shorter than the shortest DIAMETER!!
//Otherwise, the whole movement must be treated as
//a sum of smaller movements equal or shorter than
//the shortest DIAMETER
//handles intersections and check if there is a true collision
//does NOT handle case of piercing objects provoking multiple
//collisions per movement
float d,raydirection[3];
vectorFromBipoint(raydirection,&old_position[12],&Transform[12]);
//cout<<"\n"<<Transform[2]<<" "<<Transform[6]<<" "<<Transform[10]<<"\n";
if(norm(raydirection)!=1)
normalize(raydirection);
if((d=dot(surface.getNormal(),raydirection))==0)
return(false);
//checks if the surface is parallel to the ray direction
//why do I take the center of the surface???
float tmp[3];
vectorFromBipoint(tmp,&Transform[12],surface.getCenter());
d=dot(surface.getNormal(),tmp)/d;
collision_point[0]=Transform[12]+raydirection[0]*d;
collision_point[1]=Transform[13]+raydirection[1]*d;
collision_point[2]=Transform[14]+raydirection[2]*d;
if(isIn(collision_point,farthest_collision_point,raydirection))
return(surface.contains(collision_point));
//If d is negative, the collision takes place behind the
//starting point of the ray along the opposite direction
//and again there is no intersection.
//warning!! I'm going to assume that I'm doing a rectilinear
//movement!!
//I check if the new position is behind the plane
if(d<0)
{float dprime;
vectorFromBipoint(tmp,&old_position[12],surface.getCenter());
dprime=dot(surface.getNormal(),tmp)/dot(surface.getNormal(),raydirection);
//I check if the old position is not behind the plane
if(dprime<=0)
return(false);/*
collision_point[0]=old_position[12]+raydirection[0]*dprime;
collision_point[1]=old_position[13]+raydirection[1]*dprime;
collision_point[2]=old_position[14]+raydirection[2]*dprime;*/
//I check if the direction line goes through the surface
return(surface.contains(collision_point));
}
//else
// if(d<0)
// then (the object has gone through the wall)
// length_of_movement=2*shortest_radius+1
// length_of_movements=norm(unnormalized_raydirection);
// remaining_distance=length_of_movements
// (subdivisions_count=ceil(length_of_movement/length_of_movements);)
// test a sum of smaller movements equal or shorter than
// the shortest DIAMETER
// old_position constant, Transform[12..14] variable
// while(true)
// {if(remaining_distance>=length_of_movement)
// {warning!! this is a rectilinear approximation!!
// Transform[12]=old_position[12]+length_of_movement*raydirection[0];
// Transform[13]=old_position[13]+length_of_movement*raydirection[1];
// Transform[14]=old_position[14]+length_of_movement*raydirection[2];
// if(collide(surface,collision_point))
// return(true);
// remaining_distance-=length_of_movement;
// }
// else
// {warning!! this is a rectilinear approximation!!
// Transform[12]=old_position[12]+remaining_distance*raydirection[0];
// Transform[13]=old_position[13]+remaining_distance*raydirection[1];
// Transform[14]=old_position[14]+remaining_distance*raydirection[2];
// if(collide(surface,collision_point))
// return(true);
// remaining_distance=0; useless
// break;
// }
// }
return(false);
}
public: virtual bool isIn(float* collision_point,float* farthest_collision_point,
float* raydirection){
bool result=true;
float collision_vector[3];
vectorFromBipoint(collision_vector,&Transform[12],collision_point);
float norm_col=norm(collision_vector);
/*
if(xradius==0)
if(yradius==0)
if(zradius==0)
{farthest_collision_point[0]=Transform[12];
farthest_collision_point[1]=Transform[13];
farthest_collision_point[2]=Transform[14];
return(norm_col<=0);
}
else
//line
else
if(zradius==0)
//line
else
//ellipse
else
if(yradius==0)
if(zradius==0)
//line
else
//ellipse
else
if(zradius==0)
//ellipse
else
//ellipsoide
*/
//angles of the movement from the axes
//=angles of the movement from the initial position
//+angles of the initial position
float real_m_RollRadians=m_RollRadians+initial_m_RollRadians;
float real_m_YawRadians=m_YawRadians+initial_m_YawRadians;
float cosroll=cos(real_m_RollRadians);
float sinroll=sin(real_m_RollRadians);
float cosyaw=cos(real_m_YawRadians);
float sinyaw=sin(real_m_YawRadians);
if(norm_col==0)
{//phi==0&&theta==0
farthest_collision_point[0]=Transform[12]+xradius*cosyaw*cosroll;
farthest_collision_point[1]=Transform[13]+yradius*cosyaw*sinroll;
farthest_collision_point[2]=Transform[14]+zradius*sinyaw;
return(true);
}
if(xradius==yradius&&xradius==zradius)
result=(norm_col<=xradius);
else
if(norm_col>xradius&&norm_col>yradius&&norm_col>zradius)
result=false;
else
if(norm_col<=xradius&&norm_col<=yradius&&norm_col<=zradius)
result=true;
float a[3];
a[0]=xradius*cosroll+Transform[12];
a[1]=xradius*sinroll+Transform[13];
if(collision_point[0]!=Transform[12])
a[2]=((xradius*cosroll/(collision_point[0]-Transform[12]))*
(collision_point[2]-Transform[14]))+Transform[14];
else
if(collision_point[1]!=Transform[13])
a[2]=((xradius*sinroll/(collision_point[1]-Transform[13]))*
(collision_point[2]-Transform[14]))+Transform[14];
else
a[2]=Transform[14];
float oprimea[3];
vectorFromBipoint(oprimea,&Transform[12],a);
float norm_oprimea_norm_col=norm(oprimea)*norm_col;
//warning!! risk of division by zero
float cosphi=dot(oprimea,collision_vector)/norm_oprimea_norm_col;
float oprimen[3];
crossProduct(oprimen,oprimea,collision_vector);
float sinphi=norm(oprimen)/norm_oprimea_norm_col;
float c[3];
c[0]=zradius*cos(real_m_YawRadians)+Transform[12];
c[2]=zradius*sin(real_m_YawRadians)+Transform[14];
if(collision_point[0]!=Transform[12])
c[1]=((zradius*cosyaw/(collision_point[0]-Transform[12]))*
(collision_point[1]-Transform[13]))+Transform[13];
else
if(collision_point[2]!=Transform[14])
c[1]=((zradius*sinyaw/(collision_point[2]-Transform[14]))*
(collision_point[1]-Transform[13]))+Transform[13];
else
c[1]=Transform[13];
float oprimec[3];
vectorFromBipoint(oprimec,&Transform[12],c);
float norm_oprimec_norm_col=norm(oprimec)*norm_col;
//warning!! risk of division by zero
float costheta=dot(oprimec,collision_vector)/norm_oprimec_norm_col;
float oprimenprime[3];
crossProduct(oprimenprime,oprimec,collision_vector);
float sintheta=norm(oprimenprime)/norm_oprimec_norm_col;
//farthest collision point from the center of the ellipsoid
float costheta_cosyaw=costheta*cosyaw;
float cosphi_cosroll=cosphi*cosroll;
float sintheta_sinyaw=sintheta*sinyaw;
float sinphi_sinroll=sinphi*sinroll;
float costheta_cosyaw___sintheta_sinyaw=
costheta_cosyaw-sintheta_sinyaw;
farthest_collision_point[0]=Transform[12]+xradius*
costheta_cosyaw___sintheta_sinyaw*(cosphi_cosroll-sinphi_sinroll);
farthest_collision_point[1]=Transform[13]+yradius*
costheta_cosyaw___sintheta_sinyaw*(sinphi_sinroll+cosphi_cosroll);
farthest_collision_point[2]=Transform[14]+zradius*
(sintheta_sinyaw+costheta*cosyaw);
float farthest_collision_vector[3];
vectorFromBipoint(farthest_collision_vector,&Transform[12],farthest_collision_point);
if(norm(collision_vector)>norm(farthest_collision_vector))
return(false);
return(result);
}
//I can use this distance between farthest collision points
//to know how to correct the position of the object
public: virtual bool collide(Collidable object,
float* vector_between_farthest_collision_points,float* first_farthest_collision_point){
//warning!! the distance between old and new positions must be
//equal or shorter than the sum of the shortest DIAMETERS!!
//Otherwise, the whole movement must be treated as
//a sum of smaller movements equal or shorter than
//the shortest DIAMETER
float second_farthest_collision_point[3];
bool result=false;
float raydirection[3];
vectorFromBipoint(raydirection,&old_position[12],&Transform[12]);
if(norm(raydirection)!=1)
normalize(raydirection);
if(isIn(&(object.Transform[12]),first_farthest_collision_point,raydirection))
result=true;
//this excludes the case O==F'
//this excludes the case O' in this
vectorFromBipoint(raydirection,&Transform[12],&old_position[12]);
if(norm(raydirection)!=1)
normalize(raydirection);
if(object.isIn(&Transform[12],second_farthest_collision_point,raydirection))
result=true;
//this excludes the case O in object
float ffprime[3];
vectorFromBipoint(ffprime,first_farthest_collision_point,second_farthest_collision_point);
vectorFromBipoint(vector_between_farthest_collision_points
,first_farthest_collision_point,second_farthest_collision_point);
if(result==true||equals(first_farthest_collision_point,second_farthest_collision_point))
return(true);
//this excludes the case F==F'
if(equals(&Transform[12],first_farthest_collision_point))
{float oprimefprime[3];
vectorFromBipoint(oprimefprime,&(object.Transform[12]),second_farthest_collision_point);
float oprimef[3];
vectorFromBipoint(oprimef,&(object.Transform[12]),first_farthest_collision_point);
if(norm(oprimefprime)>=norm(oprimef))
return(true);
//this excludes the case O==F
}
else
{float of[3];
vectorFromBipoint(of,&Transform[12],first_farthest_collision_point);
float ofprime[3];
vectorFromBipoint(ofprime,&Transform[12],second_farthest_collision_point);
float k;
if(ofprime[0]!=0)
k=of[0]/ofprime[0];
else
if(ofprime[1]!=0)
k=of[1]/ofprime[1];
else
k=of[2]/ofprime[2];
if(k>=1)
return(true);
//no need to check when k<0 because it is treated
//above, when O is in object
}
return(false);
//comment the line above and uncomment the lines below if
//you have objects doing movements greater than their own
//shortest diameter
//at last, we must check if this has not gone through the object
//we build the plane which is orthogonal to (OO') in 3 steps
// we use the dot product to get a vector which is
// orthogonal to (OO')
// we use the cross product to get a vector which is
// orthogonal to the both vectors
// we sum O'F'' and O'F'' to get the last point
//we use the class 'FlatSurface' to build a surface
//we throw a ray and check if this was behind the plane
//we build an other plane which is orthogonal to
//the greatest radius and contains O
//we check if rays from the
//following points go through this new plane
//we check if they go through the ellipse which
//comes from the object's ellipsoide :
// the former origin
// its projection at the top of this ellipsoide
// its projection at the bottom of this ellipsoide
}
public: virtual void collideAndCorrect(WallSet walls){
for(unsigned int i=0;i<walls.size();i++)
collideAndCorrect(walls.getWall(i));
}
public: virtual bool collideAndCorrect(FlatSurface surface){
float collision_point[3];
float farthest_collision_point[3];
if(collide(surface,collision_point,farthest_collision_point))
{reactDuringCollisionWith(surface,collision_point,farthest_collision_point);
float tmp[3];
vectorFromBipoint(tmp,&Transform[12],&old_position[12]);
float farthest_collision_vector[3];
vectorFromBipoint(farthest_collision_vector,collision_point
,farthest_collision_point);
float n=norm(farthest_collision_vector);
tmp[0]*=n+0.0001f;
tmp[1]*=n+0.0001f;
tmp[2]*=n+0.0001f;
correct(tmp);
return(true);
}
return(false);
}
public: virtual bool collideAndCorrect(Collidable object){
float vector_between_farthest_collision_points[3];
float first_farthest_collision_point[3];
if(collide(object,vector_between_farthest_collision_points,
first_farthest_collision_point))
{reactDuringCollisionWith(object,vector_between_farthest_collision_points
,first_farthest_collision_point);
float tmp[3];
vectorFromBipoint(tmp,&Transform[12],&old_position[12]);
float n=dot(vector_between_farthest_collision_points,tmp);
tmp[0]*=n+0.0001f;
tmp[1]*=n+0.0001f;
tmp[2]*=n+0.0001f;
correct(tmp);
return(true);
}
return(false);
}
protected: virtual void correct(float* correction_vector){
Transform[12]+=correction_vector[0];
Transform[13]+=correction_vector[1];
Transform[14]+=correction_vector[2];
}
public: virtual float getCollisionDamage(){
return(0.0f);
}
protected: virtual void reactDuringCollisionWith(FlatSurface surface
,float* collision_point,float* farthest_collision_point){
//will be mainly used for damages and explosions
}
protected: virtual void reactDuringCollisionWith(Collidable object
,float* vector_between_farthest_collision_points
,float* first_farthest_collision_point){
//will be mainly used for damages and explosions
}
/*
public: virtual bool collide(FlatSurface surface){
float collision_point[3];
return(collide(surface,collision_point));
}
*/
};
class Fallable:public Collidable{
public: void fall(){}
};
class Player:public Fallable,Camera{
//handle ammo
//handle life
};
class Bot:public Fallable,Camera{
//redefine getCollisionDamage
//handle other kinds of damage
};
class Projectile:public Collidable{
//redefine getCollisionDamage
};
//I may need an Explosion class
#define STARTING_MODE 0 //display a few images
#define INTRO_MODE 1 //display a few images
#define PLAYING_MODE 5 //display the game, movements allowed
#define PAUSING_MODE 2 //display a few images
#define DYING_MODE 4 //display the game, movements not allowed, no gun
#define GAME_OVER_MODE 3 //display a few images
//I can simulate the death by reducing the yradius of the player
static short alpha=0,beta=0,Gamma=0,delta=0;
static int pointerx,pointery;
static Camera cam(0,0,0,-M_PI/2.0f,-2*M_PI,-2*M_PI,M_PI/2.0f,2*M_PI,2*M_PI);
static Collidable object(0,0,0,10,5,10);
static FlatSurface wall(20,20,2000,20,-20,2000,20,-20,-2000,20,20,-2000);
static unsigned short WINDOW_WIDTH,WINDOW_HEIGHT;
static unsigned char GAME_CURRENT_DISPLAY_MODE;
static unsigned int menu_textures_ID[16];
static int current_menu_texture_index;
void warpPointerAtCenter(){
pointerx=WINDOW_WIDTH/2;
pointery=WINDOW_HEIGHT/2;
glutWarpPointer((int)pointerx,(int)pointery);
}
bool pointerAtEdge(){
return(pointerx<=0||pointerx>=WINDOW_WIDTH-1||
pointery<=0||pointerx>=WINDOW_HEIGHT-1);
}
void drawWalls(){
glBegin(GL_QUADS);
glNormal3f(-1,0,0);
glVertex3f(-20,20,-2000);
glVertex3f(-20,-20,-2000);
glVertex3f(-20,-20,2000);
glVertex3f(-20,20,2000);
glNormal3f(1,0,0);
glVertex3f(20,20,2000);
glVertex3f(20,-20,2000);
glVertex3f(20,-20,-2000);
glVertex3f(20,20,-2000);
glEnd();
}
void drawParallelipipede(float x,float y,float z){
glBegin(GL_QUADS);
glNormal3f(0,0,1);
glVertex3f(-x/2,y/2,z/2);
glVertex3f(-x/2,-y/2,z/2);
glVertex3f(x/2,-y/2,z/2);
glVertex3f(x/2,y/2,z/2);
glNormal3f(1,0,0);
glVertex3f(x/2,y/2,z/2);
glVertex3f(x/2,-y/2,z/2);
glVertex3f(x/2,-y/2,-z/2);
glVertex3f(x/2,y/2,-z/2);
glNormal3f(0,0,-1);
glVertex3f(x/2,y/2,-z/2);
glVertex3f(x/2,-y/2,-z/2);
glVertex3f(-x/2,-y/2,-z/2);
glVertex3f(-x/2,y/2,-z/2);
glNormal3f(-1,0,0);
glVertex3f(-x/2,y/2,-z/2);
glVertex3f(-x/2,-y/2,-z/2);
glVertex3f(-x/2,-y/2,z/2);
glVertex3f(-x/2,y/2,z/2);
glNormal3f(0,1,0);
glVertex3f(-x/2,y/2,z/2);
glVertex3f(x/2,y/2,z/2);
glVertex3f(x/2,y/2,-z/2);
glVertex3f(-x/2,y/2,-z/2);
glNormal3f(0,-1,0);
glVertex3f(-x/2,-y/2,-z/2);
glVertex3f(x/2,y/2,-z/2);
glVertex3f(x/2,-y/2,z/2);
glVertex3f(-x/2,-y/2,z/2);
glEnd();
}
void drawArm(int a,int b,int c,int d){
glRotatef(a,0,0,1);
glPushMatrix();
glTranslatef(5.,0.,0.);
//glScalef(10.,1.,1.);
glColor3f(1.,0.,0.0);
drawParallelipipede(10,1,1);
glPopMatrix();
glTranslatef(10.,0.,0.);
glRotatef(b,0,0,1);
glPushMatrix();
glTranslatef(4.5,0.,0.);
//glScalef(9.,1.,1.);
glColor3f(0.,1.,0.0);
drawParallelipipede(9,1,1);
glPopMatrix();
glTranslatef(9.,0,0);
glPushMatrix();
glRotatef(c,0,0,1);
glTranslatef(2.,0.,0.);
//glScalef(4.,1.,1.);
glColor3f(0.,0.,1.0);
drawParallelipipede(4,1,1);
glPopMatrix();
glRotatef(d,0,0,1);
glTranslatef(2.,0.,0.);
//glScalef(4.,1.,1.);
glColor3f(1.,1.,0.0);
drawParallelipipede(4,1,1);
}
void init(){
GAME_CURRENT_DISPLAY_MODE=STARTING_MODE;
current_menu_texture_index=GAME_CURRENT_DISPLAY_MODE*4;
char filename[30],tmp[3];
glEnable(GL_TEXTURE_2D);
for(int i=0;i<16;i++)
{strcpy(filename,"menu_texture");
sprintf(tmp,"%d",i);
strcat(filename,tmp);
strcat(filename,".jpg");
menu_textures_ID[i]=loadJPEGTexture(filename);
}
glDisable(GL_TEXTURE_2D);
WINDOW_WIDTH=glutGet(GLUT_WINDOW_WIDTH);
WINDOW_HEIGHT=glutGet(GLUT_WINDOW_HEIGHT);
glClearColor(1.0,1.0,1.0,0.0);
glClearDepth(1.0);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);/*
glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);*/
/*glViewport(-50,-50,100,100);*/
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
/*glFrustum(-50,50,-50,50,20,100);*//*ca marche quand meme*/
gluPerspective(65.0,((float)WINDOW_WIDTH)/
((float)WINDOW_HEIGHT),1,1000);
glHint(GL_PERSPECTIVE_CORRECTION_HINT,GL_NICEST);
glMatrixMode(GL_MODELVIEW);
glutSetCursor(GLUT_CURSOR_NONE);
warpPointerAtCenter();
//object.rotateLocal(M_PI/2,0,1,0);
}
void display(){
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
if(GAME_CURRENT_DISPLAY_MODE==PLAYING_MODE||
GAME_CURRENT_DISPLAY_MODE==DYING_MODE)
{glPushAttrib(GL_COLOR_BUFFER_BIT);
glPushMatrix();
drawArm(alpha,beta,Gamma,delta);
glPopMatrix();
glPopAttrib();
glPushAttrib(GL_COLOR_BUFFER_BIT);
glPushMatrix();
glColor3f(0.3,0.3,0.3);
drawWalls();
glPopMatrix();
glPopAttrib();
}
else
{glPushMatrix();
glLoadIdentity();
glEnable(GL_TEXTURE_2D);
glColor3f(1,1,1);
glBindTexture(GL_TEXTURE_2D,menu_textures_ID[current_menu_texture_index]);
glBegin(GL_QUADS);
glVertex3f(-WINDOW_WIDTH/2,-WINDOW_HEIGHT/2,-250);
glTexCoord3f(0,1,-250);
glVertex3f(-WINDOW_WIDTH/2,WINDOW_HEIGHT/2,-250);
glTexCoord3f(1,1,-250);
glVertex3f(WINDOW_WIDTH/2,WINDOW_HEIGHT/2,-250);
glTexCoord3f(1,0,-250);
glVertex3f(WINDOW_WIDTH/2,-WINDOW_HEIGHT/2,-250);
glTexCoord3f(0,0,-250);
glEnd();
glPopMatrix();/*
unsigned char bitmap[512*512*3];
glGetTexImage(GL_TEXTURE_2D,0,GL_RGB,GL_UNSIGNED_BYTE,bitmap);
glBitmap(512,512,0,0,0,0,bitmap); */
glDisable(GL_TEXTURE_2D);
}
glFlush();
glutSwapBuffers();/*
if(object.collide(wall))
{cout<<"collision\n";
object.toString();
} */
if(pointerAtEdge())
warpPointerAtCenter();
}
void special(int key,int x,int y){
if(GAME_CURRENT_DISPLAY_MODE==PLAYING_MODE)
{switch(key)
{case GLUT_KEY_UP :{alpha=(alpha+10)%360;
glutPostRedisplay();
break;
}
case GLUT_KEY_DOWN :{alpha=(alpha-10)%360;
glutPostRedisplay();
break;
}
case GLUT_KEY_LEFT :{beta=(beta+10)%360;
glutPostRedisplay();
break;
}
case GLUT_KEY_RIGHT :{beta=(beta-10)%360;
glutPostRedisplay();
break;
}
case GLUT_KEY_PAGE_UP :{Gamma=(Gamma+10)%360;
glutPostRedisplay();
break;
}
case GLUT_KEY_PAGE_DOWN :{Gamma=(Gamma-10)%360;
glutPostRedisplay();
break;
}
case GLUT_KEY_F1 :{delta=(delta+10)%360;
glutPostRedisplay();
break;
}
case GLUT_KEY_F2 :{delta=(delta-10)%360;
glutPostRedisplay();
break;
}
case GLUT_KEY_F3 :{GAME_CURRENT_DISPLAY_MODE=PAUSING_MODE;
current_menu_texture_index=GAME_CURRENT_DISPLAY_MODE*4;
glutPostRedisplay();
break;
}
default :{exit(EXIT_SUCCESS);
break;
}
}
}
else
{switch(key)
{case GLUT_KEY_F4 :{exit(EXIT_SUCCESS);
break;
}
case GLUT_KEY_F3 :{switch(GAME_CURRENT_DISPLAY_MODE)
{case STARTING_MODE :{GAME_CURRENT_DISPLAY_MODE=INTRO_MODE;
current_menu_texture_index=GAME_CURRENT_DISPLAY_MODE*4;
break;
}
case INTRO_MODE :{GAME_CURRENT_DISPLAY_MODE=PLAYING_MODE;
current_menu_texture_index=GAME_CURRENT_DISPLAY_MODE*4;
break;
}
case PAUSING_MODE :{GAME_CURRENT_DISPLAY_MODE=PLAYING_MODE;
//glPopMatrix();
current_menu_texture_index=GAME_CURRENT_DISPLAY_MODE*4;
break;
}
case DYING_MODE :{GAME_CURRENT_DISPLAY_MODE=GAME_OVER_MODE;
current_menu_texture_index=GAME_CURRENT_DISPLAY_MODE*4;
break;
}
case GAME_OVER_MODE :{GAME_CURRENT_DISPLAY_MODE=PLAYING_MODE;
current_menu_texture_index=GAME_CURRENT_DISPLAY_MODE*4;
break;
}
}
glutPostRedisplay();
break;
}
}
}
}
void keyboard(unsigned char key,int x,int y){
if(GAME_CURRENT_DISPLAY_MODE==PLAYING_MODE)
{switch(key)
{case 'z':{cam.moveLocal(0,0,1,5);
/*
cam.move(5);
cam.move(0);*/
break;
}
case 'q':{cam.moveLocal(1,0,0,-5);/*
cam.move(-5);
cam.move(0); */
break;
}
case 's':{cam.moveLocal(1,0,0,5);/*
cam.move(5);
cam.move(0); */
break;
}
case 'w':{cam.moveLocal(0,0,1,-5);
/*cam.move(-5);
cam.move(0);*/
break;
}
case 't':{object.moveLocal(0,0,1,5);
break;
}
case 'v':{object.moveLocal(0,0,1,-5);
break;
}
case 'f':{object.moveLocal(1,0,0,-5);
break;
}
case 'g':{object.moveLocal(1,0,0,5);
break;
}
}
//cam.setView();
glutPostRedisplay();
}
}
void passiveMotion(int x,int y){
/*if(GAME_CURRENT_DISPLAY_MODE==PLAYING_MODE)
{*/
float shiftx=0,shifty=0;
if(pointerx-x<0)
shiftx=-5.0f/60.0f;
else if(pointerx-x>0)
shiftx=5.0f/60.0f;
pointerx=x;
cam.rotateGlobal(shiftx,0,1,0);
if(y-pointery<0)
shifty=-5.0f/60.0f;
else if(y-pointery>0)
shifty=5.0f/60.0f;
pointery=y;
cam.rotateGlobal(shifty,1,0,0);
glutPostRedisplay();
/* }
else
{pointerx=x;
pointery=y;
}*/
}
void idle(){
if(GAME_CURRENT_DISPLAY_MODE==PLAYING_MODE||
GAME_CURRENT_DISPLAY_MODE==DYING_MODE)
{
/*glutPostRedisplay();*/
}
else
{if(current_menu_texture_index!=(GAME_CURRENT_DISPLAY_MODE*4)+3)
current_menu_texture_index++;
else
current_menu_texture_index=GAME_CURRENT_DISPLAY_MODE*4;
//cout<<current_menu_texture_index<<" "<<menu_textures_ID[current_menu_texture_index]<<" \n";
//I should use a timer here
glutPostRedisplay();
}
}
int main(int argc,char* argv[]){
GAME_CURRENT_DISPLAY_MODE=0;
glutInit(&argc,argv);
glutInitDisplayMode(GLUT_RGBA|GLUT_DOUBLE|GLUT_DEPTH);
glutCreateWindow("");
glutFullScreen();
init();
glutIdleFunc(idle);
glutPassiveMotionFunc(passiveMotion);
glutDisplayFunc(display);
glutSpecialFunc(special);
glutKeyboardFunc(keyboard);
glutMainLoop();
exit(EXIT_SUCCESS);
}
Conclusion
D'autre part, ce code permet de faire bouger un petit bras robot avec les touches Haut, Bas, Gauche, Droite, F1 et F2. F3 permet de quitter l'application. Vous pouvez essayer de bouger avec la souris, avancer et reculer avec Z et W, faire des pas de côté avec Q et S.
Je remercie Alexander Festini pour ses conseils et sa caméra UVN, mais également Ben Kenwright, Ashley James, Vic Hollis et M. Karlsson pour leur aide.
N.B: j'essayerai de mettre mon code à jour tous les jours saufs le weekend.
Merci d'avance pour votre aide.
Fichier Zip
Historique
- 06 avril 2006 18:49:01 :
- J'ajoute un zip à la demande de LE_DUCHE
- 07 avril 2006 12:53:03 :
- J'ai réussi à me débarasser du gimbal lock. Cependant, au bout d'un moment, au lieu de tourner sur moi-même, je me mets à tourner autour d'un point fixe. Le problème vient de la fonction rotateGlobal.
- 11 avril 2006 17:37:59 :
- ça marche beaucoup mieux, on peut même limiter l'angle de vue pour un FPS par exemple
- 14 avril 2006 17:06:25 :
- Le code marche pleinement sous windows et linux. Seule la fonction rotateLocal n'a pas été testé. L'angle autour de x est limité pour un FPS mais vous pouvez le changer.
- 10 mai 2006 10:35:37 :
- Ajout de plusieurs classes : FlatSurface (surfaces planaires) et Collidable (gestion des collisions). Vous pouvez ainsi faire une caméra qui ne passe pas à travers les murs!!!
- 15 mai 2006 16:53:18 :
- Le système de collision est presque fini. J'ai corrigé quelques erreurs dans le calcul du point le plus loin du centre de l'ellipsoïde et alligné avec le point de collision éventuel.
- 24 mai 2006 16:55:49 :
- J'ai corrigé un bug persistant dans la caméra. Par moment, les mouvements restaient bloqués dans une seule position. J'ai presque fini la gestion des collisions. Je commence à gérer l'affichage de murs, décors etc au niveau purement logiciel en utilisant entre autres des vertex arrays. Si vous avez des suggestions à faire, je suis tout ouï.
Sources du même auteur
Sources de la même categorie
Commentaires et avis
Discussions en rapport avec ce code source dans le forum
Quaternions et opengl [ par acropole ]
Bonjour,Je cherche de l'aide pour programmer en C++ les mouvement d'objets dans un environnement openGl. J'ai commencé à programmer l'a
Tutoriaux Complet SDL OpenGL C++ [ par Fireflect ]
Bonjours, Je recherche des bons tutoriaux sur le mélange OpenGL SDL C++ sans glut ou quoi que ce soit d'autre avec des sources bien optimisé
Problème OpenGL (GL_POINT) [ par olivier_job ]
Bonjour, J'utilise VC++ 7.0, avec wxWindows. Le problème est le suivant. Sur mon ordinateur, les GL_POINTS apparaissent comme des cercle
Transparence avec glBlend [ par smoove5198 ]
Bonjour, A l'aide d'un tutorial j'ai crée une classe qui affiche du texte sous opengl a partir d'une texture bmp listant tous les caracteres. D
GRAPHISME....OPENGL,WIN32 [ par kenza_sana ]
HELOOO.. je voudrai 'minitaliser avec le mode graphique mais je n'ay arrive pas car je en comprend pas deja j'entned tj parler de WIN32 et OPENGL..jhe
Plusieurs View dans une MFC et affichage opengl [ par Fipovi3 ]
Bonjour,Je suis en train de créer une application mfc en sdi. J'ai créé des splitters pour diviser ma fenêtre principale en 4 vues
de Blender, en passant par OpenGL, jusqua mon programme win32 [ par Muner ]
Bonjour,existe t'il un programme qui convertisse les projets Blender en fichiers OpenGL (ou 3ds (si c'est les mêmes ou pas (je n'en sais rien)))
transparences en openGL [ par vangeurmasker ]
J'ai un probleme dans un projet en OpenGL. J'utilise le canal alpha de mes textures pour gérér les transparences. Mais le probleme est qu'au
Tutz texture opengl??? [ par Slown ]
Salut a tous. Voila, j'suis a la recherche d'un tutorial COMPLET sur la pose de texture en opengl. Pour l'instant j'utilise le code: http://www.linuxg
opengl : lumière, fog pose problème quand picking [ par kortin ]
Bonjour,j'aimerais ajouté le fog et la lumière dynamique dans mon projet openGL.Tout fonctionne bien, mais lors de la s
|
Derniers Blogs
IMAGINE CUP 2012, MAKE A SIGN EN FINALEIMAGINE CUP 2012, MAKE A SIGN EN FINALE par junarnoalg
Voilà qui est fait, la nouvelle est officielle ! L'équipe belge "Make a Sign" va au pays des kangourous défendre son projet dans la catégorie Software Design. http://www.imaginecup.com/CompetitionsContent/Competition/WorldwideFinalists.aspx V...
Cliquez pour lire la suite de l'article par junarnoalg KINECT 1.5 IS OUT !KINECT 1.5 IS OUT ! par Vko
La version 1.5 du Kinect For Microsoft vient tout juste de sortir ! Plein de nouveautés: Tracking de squelette en Near Mode Détection en position assise Détection faciale avec un SDK dédié Documentation et des guideline (enfin) Un out...
Cliquez pour lire la suite de l'article par Vko LES ACTUALITéS DE LA SEMAINE SUR C2I.FR (14 MAI - 20 MAI) LES ACTUALITéS DE LA SEMAINE SUR C2I.FR (14 MAI - 20 MAI) par richardc
Mise à jour des Web API du 14 Mai
Réservez dès maintenant votre journée du 20 juin pour le Windows Azure Dev Camp 2012 à Paris
Mise à jour de Team Foundation Service
MechCommander 2 sur Windows 8
Entity Framework 5 Release Candidate e...
Cliquez pour lire la suite de l'article par richardc REACTIVE EXTENSIONS : CONSOMMER DES SERVICES AVEC RX PARTIE 3, LES PIèGES à éVITERREACTIVE EXTENSIONS : CONSOMMER DES SERVICES AVEC RX PARTIE 3, LES PIèGES à éVITER par Groc
Une mauvaise utilisation de rx lors de l'écriture d'une couche d'accès à des services peut conduire à des cas embarassants avec des erreurs mal gérées, des appels qui ne partent lorsqu'ils le devraient, et même des résultats incorrects . le tout nuis...
Cliquez pour lire la suite de l'article par Groc SHAREPOINT BLOG SITE, PROBLèME D'ARCHIVESSHAREPOINT BLOG SITE, PROBLèME D'ARCHIVES par junarnoalg
Dernièrement, nous avons migré le site
myTIC
vers un nouveau serveur SharePoint 2010. Dans les contenus que nous vouloins récupérer, nous avions un certain nombre de blogs.
Nous avons utilisé les commandes Power...
Cliquez pour lire la suite de l'article par junarnoalg
Forum
MATRICE TEMPLATEMATRICE TEMPLATE par hjr2610
Cliquez pour lire la suite par hjr2610 RE : SAC A DOS RE : SAC A DOS par hadjkaddour
Cliquez pour lire la suite par hadjkaddour
Logiciels
sDEVIS-FACTURES vlPRO (8.1.0.3)SDEVIS-FACTURES VLPRO (8.1.0.3)sDEVIS-FACTURES vlPRO a été mis au point pour les particuliers, créateurs, entrepreneurs, artisa... Cliquez pour télécharger sDEVIS-FACTURES vlPRO 974 Application Server (12.2.4.6)974 APPLICATION SERVER (12.2.4.6)Développez de puissantes applications dans un environnement de 'cloud computing', clusterisé, séc... Cliquez pour télécharger 974 Application Server vPicture (1.4.2.1)VPICTURE (1.4.2.1)Avec vPicture, hébergez vos images facilement et rapidement.
vPicture est un utilitaire simple, ... Cliquez pour télécharger vPicture Easy-Planning (2.2.1.6)EASY-PLANNING (2.2.1.6)Easy-Planning permet de créer des plannings sous la représentation de diagrammes et est adapté au... Cliquez pour télécharger Easy-Planning COM-BACKUP (2.0)COM-BACKUP (2.0)
COM-BACKUP est un logiciel de sauvegarde qui permet de planifier les sauvegardes de vos dossiers ...
Cliquez pour télécharger COM-BACKUP
|