//------------------------------------------------------------------------------
// Includes
//------------------------------------------------------------------------------
#ifdef __WIN32__
#include <windows.h>
#endif
#include <GL/glut.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#ifndef bool
typedef int bool;
#define false (1==2)
#define true (1==1)
#endif
//------------------------------------------------------------------------------
// Constantes & Variables
//------------------------------------------------------------------------------
#define EXIT {fclose(fichier); return -1;}
#define CTOI(C) (*(int*)&C)
#define WIDTH 640 // largeur
#define HEIGHT 480 // hauteur
GLuint Name[50]; // nombre de textures
int Size=16; // taille des boules
int CurrentW; // largeur actuelle de la fenêtre
int CurrentH; // hauteur actuelle de la fenêtre
struct struct_jeu
{
float pourc; // pourcentage rempli
long int score; // score du joueur
int boules; // boules durant la partie
int zones; // nombre de zones créées
float load; // chargement du niveau (> 0 : gagné | < 0 : perdu )
} jeu;
struct struct_boule
{
float posX; // positon X de la boule
float posY; // positon Y de la boule
float movX; // déplacement X de la boule
float movY; // déplacement Y de la boule
int zone; // zone où est la boule
} boules[100]; // nombre maximal de boule
struct struct_zone
{
int debX; // origine X d'une zone
int debY; // origine Y d'une zone
int finX; // longeur X d'une zone
int finY; // hauteur Y d'une zone
} zones[100]; // nombre maximal de zone (autant que de boules)
// Gestion du temps
struct TEMPS
{
int tps; // temps depuis le début
int non_ecoule; // temps non ecoulé pendant la pause
float ecart; // ecart de temps entre deux frames
long int frame; // nombre de frames depuis le début
int frame_fps; // nombre réinitialisé pour les FPS
int base; // temps réinitialisé pour les FPS
int pause; // pause du temps
float fps; // nombre de FPS
};
struct TEMPS temps;
//------------------------------------------------------------------------------
// Affiche la chaine à l'écran
//------------------------------------------------------------------------------
void render_string(void* font, const char* string)
{
char* p = (char*) string;
while (*p != '\0') glutBitmapCharacter(font, *p++);
}
//------------------------------------------------------------------------------
// Initialisation du jeu
//------------------------------------------------------------------------------
void Init_Game ( )
{
int x;
jeu.zones = 1;
jeu.pourc = 0;
jeu.load = 0;
zones[0].debX = 0;
zones[0].debY = 0;
zones[0].finX = WIDTH;
zones[0].finY = HEIGHT;
for ( x = 0; x < jeu.boules; x++)
{
boules[x].posX = (int)(rand( )%(WIDTH - Size));
boules[x].posY = (int)(rand( )%(HEIGHT - Size));
boules[x].movX = (int)(rand( )%10-5);
boules[x].movY = (int)(rand( )%10-5);
boules[x].zone = 0;
}
char msg[255];
sprintf (msg, "Game Balls | %02.2f%% | %ld points | %d %s | %d %s | by BeLZeL", jeu.pourc, jeu.score, jeu.boules, (jeu.boules<=1)?"balle":"balles", jeu.zones, (jeu.zones<=1)?"zone":"zones" );
glutSetWindowTitle(msg);
}
//------------------------------------------------------------------------------
// Gestion des boutons de la souris
//------------------------------------------------------------------------------
void SourisClic ( int button, int state, int MouseX, int MouseY )
{
int Czone=-1; // quelle zone cliquée, si Czone = -1, alors la zone n'est pas valide
int Count=jeu.zones; // combien de zones affichées
int x, y; // pour les boucles
MouseX = (int) ( MouseX * WIDTH / (float) ( CurrentW ) );
MouseY = (int) ( MouseY * HEIGHT / (float) ( CurrentH ) );
bool gauche, droite, haut, bas, milieu;
// true : balle
// false : pas de balle
gauche = droite = haut = bas = milieu = false;
if ( jeu.load == 0 )
{
// on détecte la zone cliquée
for ( x = 0; x < jeu.zones; x++ )
{
// par rapport à la souris
if ( ( (MouseX > zones[x].debX) && (MouseX < zones[x].finX) ) && ( (MouseY > zones[x].debY) && (MouseY < zones[x].finY) ) )
Czone = x;
// par rapport aux boules
for ( y = 0; y < jeu.boules; y++ )
if ( ( (boules[y].posX > zones[x].debX) && (boules[y].posX < zones[x].finX) ) && ( (boules[y].posY > zones[x].debY) && (boules[y].posY < zones[x].finY) ) )
boules[y].zone = x;
}
// clic gauche - trait vertical
if ( (button==GLUT_LEFT_BUTTON) && (state==GLUT_DOWN) && (Czone != -1) )
{
// recherche les positions des balles par rapport au clic
for ( x = 0; x < jeu.boules; x++ )
{
if (boules[x].zone == Czone)
{
if ((MouseX > boules[x].posX + Size) && (zones[Czone].debX < boules[x].posX + Size) && (zones[Czone].finX > boules[x].posX + Size) && (!gauche)) gauche = true;
if ((MouseX < boules[x].posX) && (zones[Czone].debX < boules[x].posX) && (zones[Czone].finX > boules[x].posX) && (!droite)) droite = true;
if ((MouseX > boules[x].posX) && (MouseX <= boules[x].posX + Size) && (!milieu)) milieu = true;
}
}
// définition de la nouvelle zone
if ((gauche) && (droite))
{
zones[Count].debY = zones[Czone].debY;
zones[Count].finX = zones[Czone].finX;
zones[Count].finY = zones[Czone].finY;
zones[Count].debX = MouseX+1;
zones[Czone].finX = MouseX-1;
jeu.zones++;
}
else
{
if (gauche) zones[Czone].finX = MouseX;
if (droite) zones[Czone].debX = MouseX;
}
if (milieu) jeu.load=-1;
}
// clic droit - trait horizontal
if ( (button==GLUT_RIGHT_BUTTON) && (state==GLUT_DOWN) && (Czone != -1) )
{
// recherche des positions des balles par rapport au clic
for ( x = 0; x < jeu.boules; x++ )
{
if (boules[x].zone == Czone)
{
if ((MouseY > boules[x].posY + Size) && (zones[Czone].debY < boules[x].posY + Size) && (zones[Czone].finY > boules[x].posY + Size) && (!haut)) haut = true;
if ((MouseY < boules[x].posY) && (zones[Czone].debY < boules[x].posY) && (zones[Czone].finY > boules[x].posY) && (!bas)) bas = true;
if ((MouseY > boules[x].posY) && (MouseY <= boules[x].posY + Size) && (!milieu)) milieu = true;
}
}
// définition de la nouvelle zone
if ((haut) && (bas))
{
zones[Count].debX = zones[Czone].debX;
zones[Count].finX = zones[Czone].finX;
zones[Count].finY = zones[Czone].finY;
zones[Count].debY = MouseY+1;
zones[Czone].finY = MouseY-1;
jeu.zones++;
}
else
{
if (haut) zones[Czone].finY = MouseY;
if (bas) zones[Czone].debY = MouseY;
}
if (milieu) jeu.load=-1;
}
if (Czone != -1)
{
char msg[255];
long int SurfZone = 0;
long int old_pourc = jeu.pourc;
for ( x = 0; x < jeu.zones; x++)
SurfZone += (zones[x].finX - zones[x].debX) * (zones[x].finY - zones[x].debY);
jeu.pourc = 100-SurfZone/(float)(640*480*0.01);
jeu.score += (int)(jeu.pourc - old_pourc);
sprintf (msg, "Game Balls | %02.2f%% | %ld points | %d %s | %d %s | by BeLZeL", jeu.pourc, jeu.score, jeu.boules, (jeu.boules<=1)?"balle":"balles", jeu.zones, (jeu.zones<=1)?"zone":"zones" );
glutSetWindowTitle(msg);
}
// partie finie, on recommence en plus dur ;)
if ((jeu.pourc > 75) && (jeu.load==0))
{
jeu.boules+=2;
jeu.load=1;
}
}
}
//------------------------------------------------------------------------------
// Dessine les boules
//------------------------------------------------------------------------------
void Draw_Boules ( )
{
int x, y;
glBindTexture(GL_TEXTURE_2D, Name[0] );
for ( x = 0; x < jeu.boules; x++)
{
// affichage la boule à l'écran
glBegin(GL_QUADS);
glTexCoord2d ( 0, 1 ); glVertex2d( boules[x].posX, boules[x].posY );
glTexCoord2d ( 0, 0 ); glVertex2d( boules[x].posX, boules[x].posY+Size );
glTexCoord2d ( 1, 0 ); glVertex2d( boules[x].posX+Size, boules[x].posY+Size );
glTexCoord2d ( 1, 1 ); glVertex2d( boules[x].posX+Size, boules[x].posY );
glEnd();
// Collisions entre les boules
for ( y = 0; y < jeu.boules; y++)
if ( pow(boules[x].posX+boules[x].movX*temps.ecart*100-boules[y].posX-boules[y].movX*temps.ecart*100,2) + pow(boules[x].posY+boules[x].movY*temps.ecart*100-boules[y].posY-boules[y].movY*temps.ecart*100,2) <= pow(Size, 2) )
{
int t;
t = boules[x].movX;
boules[x].movX = boules[y].movX;
boules[y].movX = t;
t = boules[x].movY;
boules[x].movY = boules[y].movY;
boules[y].movY = t;
}
// Collisions entre les zones
// gauche et droite
if (( boules[x].posX + boules[x].movX*temps.ecart*100 <= zones[boules[x].zone].debX ) || ( boules[x].posX + boules[x].movX*temps.ecart*100 >= zones[boules[x].zone].finX - Size ))
boules[x].movX = -boules[x].movX;
boules[x].posX += boules[x].movX*temps.ecart*100;
// haut et bas
if (( boules[x].posY + boules[x].movY*temps.ecart*100 <= zones[boules[x].zone].debY ) || ( boules[x].posY + boules[x].movY*temps.ecart*100 >= zones[boules[x].zone].finY - Size ))
boules[x].movY = -boules[x].movY;
boules[x].posY += boules[x].movY*temps.ecart*100;
}
}
//------------------------------------------------------------------------------
// Charge une image TGA 32 bits non compressée
//------------------------------------------------------------------------------
int LoadTGA(char *filename, int nb) // Loads A TGA File Into Memory
{
GLubyte TGAheader[12]={0,0,2,0,0,0,0,0,0,0,0,0};// Uncompressed TGA Header
GLubyte TGAcompare[12]; // Used To Compare TGA Header
GLubyte header[6]; // First 6 Useful Bytes From The Header
int imageSize; // Used To Store The Image Size When Setting Aside Ram
int type; // Set The Default GL Mode To RBGA (32 BPP)
GLubyte *imageData; // Données de l'image, jusqu'à 32 bits
int bpp; // Bits Par Pixel de l'image
int Width, Height; // Taille de l'image
int i;
// Lit le fichier et son header
FILE *fichier = fopen(filename, "rb"); // Open The TGA File
if (fread(TGAcompare,1,sizeof(TGAcompare),fichier)!=sizeof(TGAcompare)) EXIT; // Are There 12 Bytes To Read?
if (memcmp(TGAheader,TGAcompare,sizeof(TGAheader))!=0) EXIT; // Does The Header Match What We Want?
if (fread(header,1,sizeof(header),fichier)!=sizeof(header)) EXIT; // If So Read Next 6 Header Bytes
// Récupère les infos de l'image
Width = header[1] * 256 + header[0]; // Determine The TGA Width (highbyte*256+lowbyte)
Height = header[3] * 256 + header[2]; // Determine The TGA Height (highbyte*256+lowbyte)
bpp = header[4]; // Grab The TGA's Bits Per Pixel (24 or 32)
if (bpp==24) type=GL_RGB; // If So Set The 'type' To GL_RGB
else type=GL_RGBA; // If So Set The 'type' To GL_RGBA
imageSize = Width*Height*bpp/8; // Calculate The Memory Required For The TGA Data
// Charge l'image
imageData=(GLubyte *)malloc(imageSize); // Reserve Memory To Hold The TGA Data
if (fread(imageData, 1, imageSize, fichier)!=imageSize) // Does The Image Size Match The Memory Reserved?
{
free ( imageData );
EXIT;
}
fclose (fichier); // Close The File
// Inverse R et B
for(i=0; i<imageSize;i+=bpp/8) // Loop Through The Image Data
{ // Swaps The 1st And 3rd Bytes ('R'ed and 'B'lue)
int t=imageData[i]; // Temporarily Store The Value At Image Data 'i'
imageData[i]=imageData[i+2]; // Set The 1st Byte To The Value Of The 3rd Byte
imageData[i+2]=t; // Set The 3rd Byte To The Value In 'temp' (1st Byte Value)
}
// Build A Texture From The Data
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glGenTextures(nb, &Name[nb]); // Generate OpenGL texture IDs
glBindTexture(GL_TEXTURE_2D, Name[nb]); // Bind Our Texture
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); // Linear Filtered (ca lisser les textures mais moins ien que le TriLinear Filtering)
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); // Linear Filtered
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT);
glTexImage2D(GL_TEXTURE_2D, 0, type, Width, Height, 0, type, GL_UNSIGNED_BYTE, imageData);
return Name[nb]; // Texture Building Went Ok, Return True
}
//------------------------------------------------------------------------------
// ReSize Function
//------------------------------------------------------------------------------
void ReshapeGL ( int Width, int Height )
{
if (Height==0) Height=1;
CurrentW = Width;
CurrentH = Height;
glViewport ( 0, 0, Width, Height );
glMatrixMode ( GL_PROJECTION );
glLoadIdentity ( );
glOrtho ( 0, WIDTH, HEIGHT, 0, 0, 0.2 ); // Fait un écran Ortho
}
//------------------------------------------------------------------------------
// Initialisation Function
//------------------------------------------------------------------------------
void InitGL ( )
{
glClearColor ( 0.0f, 0.0f, 0.0f, 0.0f ); // Black Background
glClearDepth(1.0f); // Configuration de la profondeur du buffer
glDepthFunc ( GL_LEQUAL );
glEnable ( GL_DEPTH_TEST );
glAlphaFunc ( GL_GREATER, 0.5f );
glEnable ( GL_ALPHA_TEST );
glEnable ( GL_TEXTURE_2D );
glEnable ( GL_COLOR ); // Colors Enabled
}
//------------------------------------------------------------------------------
// Draw Function
//------------------------------------------------------------------------------
void DrawGL ( )
{
int x;
// Mise à jour du temps
temps.frame++;
temps.frame_fps++;
temps.ecart = (double)(( glutGet ( GLUT_ELAPSED_TIME ) - temps.tps - 0.0001) / 1000);
temps.tps = glutGet ( GLUT_ELAPSED_TIME );
glDisable ( GL_COLOR );
glEnable ( GL_TEXTURE_2D );
if (jeu.load != 0)
{
glMatrixMode ( GL_MODELVIEW );
glLoadIdentity ( );
glPushMatrix ( );
// gagné sinon perdu
if (jeu.load > 0)
{
glColor3f ( 1,1,1 );
// BACKGROUND
glBindTexture ( GL_TEXTURE_2D, Name[1] );
glBegin ( GL_QUADS );
glTexCoord2d ( 0, 1 ); glVertex2d( 0, 0 );
glTexCoord2d ( 0, 0 ); glVertex2d( 0, HEIGHT );
glTexCoord2d ( 1, 0 ); glVertex2d( WIDTH, HEIGHT );
glTexCoord2d ( 1, 1 ); glVertex2d( WIDTH, 0 );
glEnd ( );
glDisable ( GL_TEXTURE_2D );
glEnable ( GL_COLOR );
}
else
{
glDisable ( GL_TEXTURE_2D );
glEnable ( GL_COLOR );
// LE FOND NOIR
glColor3d ( 0, 0, 0 );
glBegin ( GL_QUADS );
glVertex2d( 0, 0 );
glVertex2d( WIDTH, 0 );
glVertex2d( WIDTH, HEIGHT );
glVertex2d( 0, HEIGHT );
glEnd ( );
// LA BORDURE
glLineWidth(10);
glColor3f ( 0.9, 0.2, 0.3 );
glBegin ( GL_LINE_LOOP );
glVertex2d( 0, 0 );
glVertex2d( 0, HEIGHT );
glVertex2d( WIDTH, HEIGHT );
glVertex2d( WIDTH, 0 );
glEnd ( );
}
// 2D - OBLIGATOIRE
glPopMatrix ( );
glMatrixMode ( GL_PROJECTION );
glLoadIdentity ( );
glOrtho ( 0, WIDTH, HEIGHT, 0, 0, 0.2 ); // Fait un écran Ortho
char str[255];
// gagné sinon perdu
if (jeu.load > 0)
{
glColor3f ( 0, 0, 0 );
sprintf ( str, "Niveau fini ... passage au niveau suivant !" );
glRasterPos2f ( 10, 100 );
render_string ( GLUT_BITMAP_HELVETICA_18, str );
sprintf ( str, "Pourcentage : %2.2f/100!", jeu.pourc);
glRasterPos2f ( 10, 130 );
render_string ( GLUT_BITMAP_HELVETICA_18, str );
sprintf ( str, "Score : %ld", jeu.score);
glRasterPos2f ( 10, 160 );
render_string ( GLUT_BITMAP_HELVETICA_18, str );
sprintf ( str, "Niveau suivant -> %d balles", jeu.boules);
glRasterPos2f ( 10, 190 );
render_string ( GLUT_BITMAP_HELVETICA_18, str );
}
else
{
glColor3f ( 0.9, 0.2, 0.1 );
sprintf ( str, "Jeu fini (Gaimauveur) !!! Booooouuuuuuuh que c'est dommage !" );
glRasterPos2f ( 10, 100 );
render_string ( GLUT_BITMAP_HELVETICA_18, str );
if (jeu.boules <= 100) sprintf ( str, "Exceptionnel ! %d balles, tu peux maintenant te reposer !", jeu.boules);
if (jeu.boules <= 30) sprintf ( str, "T'es un dieu, c'est clair ! %d balles quand meme !", jeu.boules);
if (jeu.boules <= 15) sprintf ( str, "Waou, pas facile d'arriver à %d balles !", jeu.boules);
if (jeu.boules <= 9) sprintf ( str, "Et %d balles, c'est bien !", jeu.boules);
if (jeu.boules <= 5) sprintf ( str, "Mais %d balles, c'est po mal !", jeu.boules);
if (jeu.boules <= 3) sprintf ( str, "Pis %d balles, c'est po terrible !", jeu.boules);
glRasterPos2f ( 10, 130 );
render_string ( GLUT_BITMAP_HELVETICA_18, str );
sprintf ( str, "Score : %ld", jeu.score);
glRasterPos2f ( 10, 160 );
render_string ( GLUT_BITMAP_HELVETICA_18, str );
}
(jeu.load > 0)?(jeu.load+=temps.ecart*1000):(jeu.load-=temps.ecart*1000);
// chargement du nouveau niveau
if (jeu.load >= 3000)
{
Init_Game ( );
jeu.load=0;
}
// chargement du nouveau niveau
if (jeu.load <= -4000)
{
jeu.boules=1;
jeu.score = 0;
Init_Game ( );
jeu.load=0;
}
glDisable ( GL_COLOR );
glEnable ( GL_TEXTURE_2D );
glutSwapBuffers ( ); // Draw The Frame
glutPostRedisplay ( ); // Restart DrawGL
}
else
{
// BACKGROUND
glBindTexture ( GL_TEXTURE_2D, Name[1] );
glBegin ( GL_QUADS );
glTexCoord2d ( 0, 1 ); glVertex2d( 0, 0 );
glTexCoord2d ( 0, 0 ); glVertex2d( 0, HEIGHT );
glTexCoord2d ( 1, 0 ); glVertex2d( WIDTH, HEIGHT );
glTexCoord2d ( 1, 1 ); glVertex2d( WIDTH, 0 );
glEnd ( );
glDisable ( GL_TEXTURE_2D );
glEnable ( GL_COLOR );
for ( x = 0; x < jeu.zones; x++ )
{
// LES ZONES
glColor3d ( 0, 0, 0 );
glBegin ( GL_QUADS );
glVertex2d( zones[x].debX, zones[x].debY );
glVertex2d( zones[x].finX, zones[x].debY );
glVertex2d( zones[x].finX, zones[x].finY );
glVertex2d( zones[x].debX, zones[x].finY );
glEnd ( );
}
// LA BORDURE
glLineWidth(10);
glColor3f ( 0.9, 0.2, 0.3 );
glBegin ( GL_LINE_LOOP );
glVertex2d( 0, 0 );
glVertex2d( 0, HEIGHT );
glVertex2d( WIDTH, HEIGHT );
glVertex2d( WIDTH, 0 );
glEnd ( );
glColor3d ( 1, 1, 1 );
glDisable ( GL_COLOR );
glEnable ( GL_TEXTURE_2D );
// BOULE
Draw_Boules ( );
glutSwapBuffers ( ); // Draw The Frame
glutPostRedisplay ( ); // Restart DrawGL
}
}
//------------------------------------------------------------------------------
// Main Function
//------------------------------------------------------------------------------
int main( int argc, char *argv[ ], char *envp[ ] )
{
srand ( time ( NULL ) );
// Create The Window
glutInit ( &argc, argv );
glutInitDisplayMode ( GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH );
glutInitWindowSize ( WIDTH, HEIGHT );
glutInitWindowPosition ( 50, 50 );
glutCreateWindow ( "" );
jeu.boules = 1; // nombre de boule au départ
InitGL ( );
Init_Game ( );
glutSetCursor(GLUT_CURSOR_FULL_CROSSHAIR);
LoadTGA ( "ball.tga", 0 );
LoadTGA ( "wall.tga", 1 );
glutReshapeFunc ( ReshapeGL );
glutDisplayFunc ( DrawGL );
glutMouseFunc ( SourisClic );
glutMainLoop ( );
return 0;
}
//------------------------------------------------------------------------------
// THE END
//------------------------------------------------------------------------------