1 /* ************************************************************************* *
2     Simplevaders space-invaders like game that is not like space-invaders
3     Copyright (C) 2007  DusteD
4 
5     This program is free software: you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation, either version 3 of the License, or
8     (at your option) any later version.
9 
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14 
15     You should have received a copy of the GNU General Public License
16     along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  * ************************************************************************* */
18 
19 /* Disclamer (2): This was my first computergame, my first experience with opengl,
20    sdl and my first C++ program. I learned a lot from all the mistakes and
21    design-flaws I made here. So, go easy on me, I know there are lots of errors in
22    here, but I only learn by doing, and by making mistakes. */
23 
24 //FIXME: needz moar bullutz
25 
26 #include <iostream>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <GL/gl.h>
30 #include <GL/glu.h>
31 #include <SDL/SDL.h>
32 #include <SDL/SDL_ttf.h>
33 #include <SDL/SDL_mixer.h>
34 #include <SDL/SDL_image.h>
35 #include <math.h>
36 #include <string.h>
37 #include <unistd.h>
38 
39 #define ALIEN_SHOOT_DELAY rand() % 5000/(level/5.0f);
40 #define NUM_PSYS 20
41 #define NUM_PARTICLES 50
42 #define NUM_BULLETS 200
43 
44 using namespace std;
45 SDL_Surface *screen = NULL;
46 SDL_Surface *texture = NULL;
47 
48 TTF_Font *font = NULL;
49 SDL_Surface *textureb = NULL;
50 SDL_Surface *welcomeimg = NULL;
51 
52 SDL_Event event;
53 
54 //sounds
55 bool sound=1;
56 Mix_Chunk *SND_playerbullet = NULL;
57 Mix_Chunk *SND_nmedie = NULL;
58 Mix_Chunk *SND_gameover = NULL;
59 Mix_Chunk *SND_playerhit = NULL;
60 
61 int bestScore=0;
62 
63 int level=1;
64 int playerbullets=0;
65 int nextlevblocks=0;
66 
67 int alienrows = 3;
68 #define aliensInrow 15
69 #define MAX_ALIEN_ROWS 5
70 
71 void spawnbullet(GLfloat x, GLfloat y,bool dir);
72 float rndflt(float total, float negative);
73 void initGameObjects(bool ng);
74 void txt();
75 void exitgame(bool status);
76 void game_over();
77 void newgame();
78 void spawnPsystem(GLfloat x, GLfloat y, GLfloat scale, int life, GLfloat maxvel);
79 void renderParticlesystems();
80 void renderAlienRows();
81 
82 long aRowLastTick=0;
83 int aRowTicks=0;
84 
85 long drawLastTick;
86 bool glBlink=0;
87 bool glBlinkOff=0;
88 bool enablePs=1;
89 
90 float scale = 0.4f;
91 
92 bool starfield=1;
93 GLuint glTexture[5]; // 0 = score 1 = welcome 2 = gameover 3 = flare 4=credits
94 GLint glAlienMesh = 0;
95 
96 //closeness = sqrt(pow(pos[0] - aliens[alienr].pos[0],2) + pow(pos[1] - aliens[alienr].pos[1],2));
97 class particleSystem {
98 public:
99   int numparticles, liveparticles, life[NUM_PARTICLES];
100   bool initialized,l[NUM_PARTICLES];
101   GLfloat x[NUM_PARTICLES], y[NUM_PARTICLES], vel[NUM_PARTICLES], rot[NUM_PARTICLES], col[NUM_PARTICLES][3], scale,ox,oy,maxvel;
102   uint32_t lastTick;
103   uint32_t lifeTicks;
104   int syslife;
105 
init()106   void init()
107   {
108     int p=0;
109     if(liveparticles != 0)
110     {
111       cout << "trying to init live ps\n";
112       exitgame(1);
113     }
114     while(p<numparticles)
115     {
116       x[p]=0.0f;
117       y[p]=0.0f;
118       rot[p]=rndflt(360,0);
119       vel[p]=rndflt(maxvel,0)+0.1;
120       l[p]=1;
121       life[p]=rand() % syslife;
122       col[p][0]=rndflt(1,0);
123       col[p][1]=rndflt(1,0);
124       col[p][2]=rndflt(1,0);
125       p++;
126     }
127     liveparticles=p;
128     lastTick=SDL_GetTicks();
129     lifeTicks=lastTick;
130     initialized=1;
131   }
132 
update()133   void update()
134   {
135     int p=0;
136     int ticks = SDL_GetTicks() - lastTick;
137     GLfloat d;
138     while(p<numparticles)
139     {
140       if(l[p])
141       {
142         d = vel[p] * (ticks / 1000.0f);
143 
144         x[p] = x[p]+d;
145         //Nulstil cursor
146         glLoadIdentity();
147         //Roter
148         GLfloat g = (1.f/rndflt(life[p],0))*(SDL_GetTicks() - lifeTicks);
149 
150         glTranslatef( ox, oy, -5.0 );
151         glRotatef( rot[p],0.0,0.0,1.0 );
152         glTranslatef( x[p],0.0,0.0);
153         //Placer
154 
155         //Farv
156         glColor4f( 1.0, 1.0-(g/2), 1.0f-g, 1.0f-g );
157         //Tegn
158         glEnable(GL_TEXTURE_2D);
159         glBindTexture(GL_TEXTURE_2D, glTexture[3]);
160         glEnable(GL_BLEND);
161         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
162         glBegin ( GL_QUADS );
163           glTexCoord2f(0.0f,-1.0f);glVertex3f(-0.1f*scale,  0.1f*scale, 0.0f);
164           glTexCoord2f(1.0f,-1.0f);glVertex3f( 0.1f*scale,  0.1f*scale, 0.0f);
165           glTexCoord2f(1.0f,0.0f); glVertex3f( 0.1f*scale, -0.1f*scale, 0.0f);
166           glTexCoord2f(0.0f,0.0f); glVertex3f(-0.1f*scale, -0.1f*scale, 0.0f);
167         glEnd();
168         glDisable(GL_TEXTURE_2D);
169         glDisable(GL_BLEND);
170         glPopMatrix();
171         //Hvis den er død?
172         if(x[p] > 3.0 || x[p] < -3.0 || y[p] > 3.0 || y[p] < -3.0 || (lifeTicks+life[p]) < SDL_GetTicks())
173         {
174           liveparticles--;
175           l[p]=0;
176         }
177       }
178       p++;
179     }
180 
181     lastTick = SDL_GetTicks();
182   }
183 };
184 
185 
186 particleSystem psys[NUM_PSYS];
187 
188 /* function to reset our viewport after a window resize */
resizeWindow(int width,int height)189 void resizeWindow( int width, int height )
190 {
191     /* Height / width ration */
192     GLfloat ratio;
193 
194     /* Protect against a divide by zero */
195     if ( height == 0 )
196       height = 1;
197 
198     ratio = ( GLfloat )width / ( GLfloat )height;
199 
200     /* Setup our viewport. */
201     glViewport( 0, 0, ( GLsizei )width, ( GLsizei )height );
202 
203     /* change to the projection matrix and set our viewing volume. */
204     glMatrixMode( GL_PROJECTION );
205     glLoadIdentity( );
206 
207     /* Set our perspective */
208     gluPerspective( 45.0f, ratio, 0.1f, 100.0f );
209 
210     /* Make sure we're chaning the model view and not the projection */
211     glMatrixMode( GL_MODELVIEW );
212 
213     /* Reset The View */
214     glLoadIdentity();
215 }
216 
217 class player {
218   public:
219   int lives;
220   int health;
221   GLfloat pos[3];
222   long lastTick;
223   long lastShotTick;
224   GLfloat xvel;
225   GLfloat yvel;
226   bool shooting;
227   int score;
228 
stats()229   void stats()
230   {
231     txt();
232   }
233 
move()234   void move()
235   {
236     int ticks;
237     GLfloat xdistance,ydistance;
238 
239     ticks = SDL_GetTicks() - lastTick;
240     lastTick = SDL_GetTicks();
241 
242     xdistance = xvel * (ticks / 1000.0f);
243     pos[0] = pos[0] + xdistance;
244 
245 
246     ydistance = yvel * (ticks / 1000.0f);
247     pos[1] = pos[1] + ydistance;
248 
249     xvel=0.0f;
250     yvel=0.0f;
251 
252     //keep player on screen
253     if(pos[0] > 3.1 || pos[0] < -3.1)
254       pos[0] = pos[0] - xdistance;
255     if(pos[1] > 2.5 || pos[1] < -2.5)
256       pos[1]=pos[1]-ydistance;
257 
258     glTranslatef( pos[0], pos[1], pos[2] );
259 
260     if(shooting)
261     {
262       if(SDL_GetTicks() - lastShotTick > 100)
263       {
264       if(playerbullets<6)
265       {
266         spawnbullet(pos[0],pos[1],1);
267         lastShotTick=SDL_GetTicks();
268         if(sound)
269           Mix_PlayChannel( -1, SND_playerbullet, 0 );
270         playerbullets++;
271       }
272       }
273     }
274   }
275 
gethit()276   void gethit()
277   {
278     lives--;
279     glBlink=1;
280     drawLastTick=SDL_GetTicks();
281     stats();
282     if(sound)
283       Mix_PlayChannel(-1, SND_playerhit, 0);
284 
285     if(lives == 0)
286     {
287       game_over();
288     }
289   }
290 };
291 
292 player playerobj;
293 
294 class alienrow {
295   private:
296   float shootDelay[15];
297   long lastShotTick[15];
298   bool dir; //0 = <-- 1= -->
299   public:
300   bool nextrow;
301   bool active;
302   GLfloat x[15],y,xvel;
303   bool live[15];
304 
hit(int a)305   void hit(int a)
306   {
307     live[a]=0;
308     spawnPsystem(x[a],y-0.25,0.3,1000,1.0);
309     playerbullets--;
310     playerobj.score=playerobj.score+(3*level*level);
311     playerobj.stats();
312     if(playerobj.score > bestScore)
313       bestScore = playerobj.score;
314     if(sound)
315       Mix_PlayChannel( -1, SND_nmedie, 0 );
316   }
317 
init(GLfloat starty,bool startdir)318   void init(GLfloat starty, bool startdir)
319   {
320     GLfloat width = 0.5*scale;
321     if(active != 1)
322     {
323       int a=0;
324       GLfloat offset=0.0f;
325       GLfloat startx = -2.0f;
326       active=1;
327       dir = startdir;
328       xvel = 10.2f*(level/50.0f);
329       y = starty;
330       nextrow=0;
331 
332       while(a < 15)
333       {
334         live[a] = 1;
335         x[a] = startx + offset;
336         shootDelay[a] = ALIEN_SHOOT_DELAY;
337         lastShotTick[a] = SDL_GetTicks()-rand() % 250;
338         offset = offset + width + 0.1;
339         a++;
340       }
341     } else {
342       cout << "Tried to initialize active row.\n";
343       exitgame(1);
344     }
345   }
346 
update()347   void update()
348   {
349     int a=0;
350     int tempdir=3;
351     int livealiens=0;
352     GLfloat d = xvel*((aRowTicks - aRowLastTick)/1000.0f);
353 
354     if(active==0)
355       return;
356 
357     while(a<15)
358     {
359       if(live[a])
360       {
361         livealiens++;
362 
363         if(dir)
364           x[a] = x[a] + d;
365         else
366           x[a] = x[a] - d;
367 
368         if(x[a] > 3.0f)
369           tempdir=0;
370         else if(x[a] < -3.0f)
371           tempdir=1;
372 
373         glPushMatrix();
374         glLoadIdentity();
375         glTranslatef( x[a], y, -6.0f );
376         glCallList(glAlienMesh);
377         glPopMatrix();
378 
379         //Skyd
380         if((SDL_GetTicks()-lastShotTick[a]) > shootDelay[a])
381         {
382           spawnbullet(x[a],y,0);
383           lastShotTick[a] = SDL_GetTicks();
384           shootDelay[a]=ALIEN_SHOOT_DELAY;
385         }
386 
387         //Coldetc player
388         GLfloat closeness = sqrt(pow(x[a] - playerobj.pos[0],2) + pow(y - playerobj.pos[1],2));
389         if(closeness < 0.26)
390         {
391           hit(a);
392           playerobj.score--;
393           playerobj.gethit();
394           playerobj.stats();
395         }
396 
397       }
398       a++;
399     }
400 
401     if(tempdir<3)
402     {
403       dir=tempdir;
404       nextrow=1;
405     }
406     if(livealiens==0)
407     {
408       active=0;
409       nextrow=0;
410     }
411     //Game over?
412     if(y < -2.2)
413       game_over();
414   }
415 };
416 
417 alienrow arows[MAX_ALIEN_ROWS];
418 
419 class bullet  {
420   public:
421   bool active;
422   bool dir;
423   float yvel;
424   GLfloat pos[3];
425   long lastTick;
426 
move()427   void move()
428   {
429 
430       int ticks;
431       GLfloat distance;
432 
433       ticks = SDL_GetTicks() - lastTick;
434       distance = yvel * (ticks / 1000.0f);
435       lastTick = SDL_GetTicks();
436 
437       if(dir == 0)
438         pos[1] = pos[1] - distance; //0.001f;//distance;
439         else
440         pos[1] = pos[1] + distance; //0.001f;//distance;
441 
442       glTranslatef( pos[0], pos[1], pos[2] );
443 
444       if(dir == 0)
445       {
446         if(pos[1] < -2.5f)
447         {
448           active=0;
449         }
450       } else {
451         if(pos[1] > 2.5f)
452         {
453           active=0;
454           playerbullets--;
455         }
456       }
457 
458     //Collision detection med player
459     if(pos[0] > playerobj.pos[0]-0.15f && pos[0] < playerobj.pos[0]+0.15f && pos[1] < playerobj.pos[1]+0.25f  && pos[1] > playerobj.pos[1]-0.25f && dir==0)
460     {
461       playerobj.gethit();
462       active=0;
463     } else if(dir==1) {
464 
465       //Gå alle aliens igennem
466       int ar=0;
467       while(ar < alienrows)
468       {
469         if(arows[ar].active == 1)
470         {
471           int a=0;
472           while(a < aliensInrow)
473           {
474             if(arows[ar].live[a] == 1)
475             {
476               if(pos[0] > arows[ar].x[a]-0.18 && pos[0] < arows[ar].x[a]+0.18 && pos[1] > arows[ar].y-0.18 && pos[1] < arows[ar].y+0.18 ) //HACK virker ikke med scale
477               {
478                 arows[ar].hit(a);
479                 active=0;
480               }
481             }
482             a++;
483           }
484         }
485         ar++;
486       }
487     }
488   }
489 };
490 
491 
492 bullet bullets[NUM_BULLETS];
493 
spawnbullet(GLfloat x,GLfloat y,bool dir)494 void spawnbullet(GLfloat x, GLfloat y,bool dir)
495 {
496   int thisbullet=0;
497   //Loop gennem vores bullets til vi finder en der ikke er aktiv
498   while(thisbullet != NUM_BULLETS)
499   {
500     if(bullets[thisbullet].active != 1)
501     {
502       bullets[thisbullet].active = 1;
503       bullets[thisbullet].pos[0] = x;
504       bullets[thisbullet].dir=dir;
505       if(dir==1)
506       {
507         bullets[thisbullet].yvel=3.5f;
508         bullets[thisbullet].pos[1] = y +0.25f;
509        } else {
510         bullets[thisbullet].yvel=1.5f;
511         bullets[thisbullet].pos[1] = y-0.1f;
512       }
513       bullets[thisbullet].lastTick = SDL_GetTicks();
514       break;
515     }
516     thisbullet++;
517   }
518 
519 }
520 
521 //lists
522 
523 GLint glAlienBulletMesh = 1;
524 //GLint glPlayerMesh = 2 ;
525 GLint glPlayerBullet = 3;
526 //GLint glScores = 4;
527 
528 
529 
530 
initGLobjects()531 void initGLobjects()
532 {
533 
534 
535   glAlienMesh = glGenLists(1);
536   glNewList(glAlienMesh, GL_COMPILE);
537     glColor3f(1.0f,0.0f,0.0f);
538     glBegin( GL_TRIANGLES );
539 
540       glVertex3f( -0.25f*scale,0.25f*scale,0.0f*scale );
541       glVertex3f( 0.25f*scale,0.25f*scale,0.0f*scale );
542       glColor3f(1.0f,1.0f,0.0f);
543       glVertex3f( 0.0*scale, -0.25*scale,0.0f*scale );
544 
545       glColor3f(1.0f,0.0f,0.0f);
546 
547       glVertex3f( -0.30f*scale,0.35f*scale,0.0f*scale );
548       glVertex3f( -0.25f*scale,0.25f*scale,0.0f*scale );
549       glVertex3f( 0.0f*scale,0.25f*scale,0.0f*scale );
550 
551 
552       glVertex3f( 0.30f*scale,0.35f*scale,0.0f*scale );
553       glVertex3f( 0.25f*scale,0.25f*scale,0.0f*scale );
554       glVertex3f( 0.0f*scale,0.25f*scale,0.0f*scale );
555     glEnd( );
556   glEndList();
557 
558   glAlienBulletMesh = glGenLists(1);
559   glNewList(glAlienBulletMesh, GL_COMPILE);
560     glBegin( GL_TRIANGLES );
561       glColor3f(1.0f,1.0f,1.0f);
562       glVertex3f( -0.015f, 0.015f,0.0f );
563       glVertex3f( 0.015f, 0.015f,0.0f);
564       glVertex3f( 0.0f, -0.030f, 0.0f);
565     glEnd( );
566   glEndList();
567 
568   //Player bullet mesh (glPlayerBullet)
569   glPlayerBullet = glGenLists(1);
570   glNewList(glPlayerBullet, GL_COMPILE);
571     glBegin( GL_TRIANGLES );
572       glColor3f(0.0f,1.0f,0.0f);
573       glVertex3f( 0.0f, 0.03f, 0.0f );
574       glColor3f(1.0f,1.0f,1.0f);
575       glVertex3f( -0.02f, -0.025f, 0.0f);
576       glVertex3f(  0.02f, -0.025f, 0.0f);
577     glEnd( );
578   glEndList();
579 
580   //Texturer
581   welcomeimg = IMG_Load("/usr/local/share/simplevaders/intro.png");
582 
583   if(welcomeimg == NULL)
584     exitgame(1);
585 
586   glGenTextures(1, &glTexture[1]);
587   glBindTexture(GL_TEXTURE_2D, glTexture[1]);
588     gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGBA, welcomeimg->w, welcomeimg->h, GL_RGBA, GL_UNSIGNED_BYTE, welcomeimg->pixels);
589   glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
590 
591   //Texturer
592   welcomeimg = IMG_Load("/usr/local/share/simplevaders/gameover.png");
593 
594   if(welcomeimg == NULL)
595     exitgame(1);
596 
597   glGenTextures(1, &glTexture[2]);
598   glBindTexture(GL_TEXTURE_2D, glTexture[2]);
599     gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGBA, welcomeimg->w, welcomeimg->h, GL_RGBA, GL_UNSIGNED_BYTE, welcomeimg->pixels);
600   glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
601 
602   //Texturer
603   welcomeimg = IMG_Load("/usr/local/share/simplevaders/flare.png");
604 
605   if(welcomeimg == NULL)
606     exitgame(1);
607 
608   glGenTextures(1, &glTexture[3]);
609   glBindTexture(GL_TEXTURE_2D, glTexture[3]);
610     gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGBA, welcomeimg->w, welcomeimg->h, GL_RGBA, GL_UNSIGNED_BYTE, welcomeimg->pixels);
611   glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
612 
613   //Texturer
614   welcomeimg = IMG_Load("/usr/local/share/simplevaders/cred.png");
615 
616   if(welcomeimg == NULL)
617     exitgame(1);
618 
619   glGenTextures(1, &glTexture[4]);
620   glBindTexture(GL_TEXTURE_2D, glTexture[4]);
621     gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGBA, welcomeimg->w, welcomeimg->h, GL_RGBA, GL_UNSIGNED_BYTE, welcomeimg->pixels);
622   glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
623 
624   SDL_FreeSurface( welcomeimg );
625 
626 }
627 
initGameObjects(bool ng)628 void initGameObjects(bool ng)
629 {
630 // Player
631   playerobj.pos[0] = 0.0;
632   playerobj.pos[1] = -2.20;
633 
634   playerobj.lastTick = SDL_GetTicks();
635   if(ng)
636   {
637     playerobj.score = 0;
638     playerobj.lives = 3;
639   }
640   playerobj.stats();
641 
642 //Bullets
643   int thisbullet = 0;
644   while(thisbullet != NUM_BULLETS)
645   {
646     bullets[thisbullet].lastTick = SDL_GetTicks();
647     bullets[thisbullet].active = 0;
648     thisbullet++;
649   }
650 
651   int ar=0;
652   GLfloat yofs=2.2;
653 
654   while(ar < alienrows)
655   {
656     arows[ar].active=0;
657     arows[ar].init(yofs, 1);
658     yofs=yofs-0.25f;
659     ar++;
660   }
661   aRowLastTick=SDL_GetTicks(); //HACK
662 
663 }
664 
initTxt()665 void initTxt()
666 {
667   if(!font)
668   {
669     font = TTF_OpenFont( "/usr/local/share/simplevaders/font.ttf", 24 );
670     if(!font)
671     {
672       cout << "Font not loaded!\n";
673       exitgame(1);
674     }
675   }
676 }
677 
txt()678 void txt()
679 {
680   SDL_Color textColor = { 255, 255, 255 };
681 
682   char msg[25];
683   sprintf(msg,"%i|%i|%i",playerobj.lives,level,playerobj.score);
684 
685   texture = TTF_RenderText_Blended( font, msg, textColor );
686   textureb = SDL_CreateRGBSurface(0, 256, 256, 32, 0xff000000, 0x0000ff00, 0x00ff0000, 0x00000000); //FIXME: i cant get
687 
688 
689   SDL_BlitSurface(texture, 0, textureb, 0);
690 
691   if(!texture)
692   {
693     cout << "\nTexture error\n";
694     exitgame(1);
695   }
696 
697   if(!texture->pixels)
698   {
699     cout << "\nNo pixulZ! :(\n";
700     exitgame(1);
701   }
702 
703   if(!glTexture[0])
704   {
705     glGenTextures(1, &glTexture[0]);
706   }
707   glBindTexture(GL_TEXTURE_2D, glTexture[0]);
708   gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGBA, textureb->w, textureb->h, GL_RGBA, GL_UNSIGNED_BYTE, textureb->pixels);
709   glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
710   SDL_FreeSurface( texture );
711   SDL_FreeSurface( textureb );
712 }
713 
714 
initGL()715 void initGL() {
716 
717     printf("GL_RENDERER   = %s\n", (char *) glGetString(GL_RENDERER));
718    // printf("GL_VERSION    = %s\n", (char *) glGetString(GL_VERSION));
719     printf("GL_VENDOR     = %s\n", (char *) glGetString(GL_VENDOR));
720   //  printf("GL_EXTENSIONS = %s\n", (char *) glGetString(GL_EXTENSIONS));
721 
722     /* Enable smooth shading */
723     glShadeModel( GL_SMOOTH );
724 
725     /* Set the background black */
726     glClearColor( 0.0f, 0.0f, 0.0f, 0.0f );
727 
728     /* Depth buffer setup */
729     glClearDepth( 1.0f );
730 
731     /* Enables Depth Testing */
732     glEnable( GL_DEPTH_TEST );
733 
734     /* The Type Of Depth Test To Do */
735     glDepthFunc( GL_LEQUAL );
736 
737     /* Really Nice Perspective Calculations */
738     glHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST );
739 
740   initGLobjects();
741 
742 }
743 #define NUMSTARS 1000
744 #define STARSTART 3.0f
745 
746 GLfloat starsy[NUMSTARS];
747 GLfloat starsx[NUMSTARS];
748 GLfloat starspeed[NUMSTARS];
749 GLfloat starh[NUMSTARS];
750 
751 long lastStarTick=0;
752 
rndflt(float total,float negative)753 float rndflt(float total, float negative)
754 {
755 
756   return (rand()/(float(RAND_MAX)+1)*total)-negative;
757 }
758 
initStarField()759 void initStarField()
760 {
761   int star=0;
762   while(star < NUMSTARS)
763   {
764     starsy[star]=rndflt(6.0f,3.0f);
765     starsx[star]=rndflt(6.6f,3.3f); //Random float kthx
766     starspeed[star]=rndflt(2.5f,0.0f)+0.1;//rndflt(2,0); //random speed kthx
767     starh[star] = rndflt(1.0f,0.0f);
768 
769     star++;
770   }
771 }
772 
glStarfield()773 void glStarfield()
774 {
775   glLoadIdentity();
776   glTranslatef( 0.0f, 0.0f, -6.0f );
777 
778   int star=0;
779   GLfloat distance;
780   int ticks = SDL_GetTicks() - lastStarTick;
781 
782   glPushMatrix();
783   glBegin( GL_POINTS );
784   while(star<NUMSTARS)
785   {
786     //Uden for skærmen
787     if(starsy[star] <= -3.0f)
788     {
789       starsy[star]=STARSTART;
790       starsx[star]=rndflt(6.6f,3.3f); //Random float kthx
791       starspeed[star]=rndflt(2.5f,0.0f)+0.1; //random speed kthx
792     }
793     else
794     {
795       //Inden for skærmen
796 
797 
798 
799   //  cout << "Star"<< star<< " ("<<starsx[star] << ","<<starsy[star]<<") \n";
800     distance = starspeed[star]*(level/2.0f) * (ticks/1000.0f);
801     lastStarTick = SDL_GetTicks();
802     starsy[star]=starsy[star] - distance;
803     }
804     glColor3f(starh[star],starh[star],starh[star]);
805     glVertex3f( starsx[star], starsy[star], 0.0f );
806 
807     star++;
808   }
809   glEnd();
810   glPopMatrix();
811 }
812 
813 
814 
815 
glScoreboard()816 void glScoreboard()
817 {
818   glPushMatrix();
819   glLoadIdentity();
820   glTranslatef( 2.34f, 2.35f, -6.0f );
821 
822   glEnable(GL_TEXTURE_2D);
823   glBindTexture(GL_TEXTURE_2D, glTexture[0]);
824   glEnable(GL_BLEND);
825   glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
826   glBegin( GL_QUADS );
827 
828     glColor3f(1.0f,1.0f,1.0f);
829 
830     glTexCoord2f(0.0f, 0.1125f);
831     glVertex3f( 0.0f, 0.0f, 0.0f );
832 
833     glTexCoord2f(1.0f, 0.1125f);
834     glVertex3f( 1.0f, 0.0f, 0.0f );
835 
836     glTexCoord2f(1.0f, 0.0f);
837     glVertex3f( 1.0f, 0.1125f, 0.0f );
838 
839     glTexCoord2f(0.0f, 0.0f);
840     glVertex3f( 0.0f, 0.1125f, 0.0f );
841   glEnd();
842   glDisable(GL_TEXTURE_2D);
843   glDisable(GL_BLEND);
844   glPopMatrix();
845 }
846 
renderAlienRows()847 void renderAlienRows()
848 {
849   int ar=0;
850   nextlevblocks=0;
851   aRowTicks = SDL_GetTicks();
852   while(ar < alienrows)
853   {
854     if(arows[ar].active==1)
855     {
856 //      cout << ar << "\n";
857 
858       if(arows[ar].nextrow==1)
859       {
860         if(ar < alienrows+1)
861         {
862           if(arows[ar].nextrow==1)
863           {
864             if(arows[ar+1].active==0)
865             {
866               arows[ar].nextrow=0;
867               arows[ar].y =arows[ar].y - 0.25f;
868             }
869           }
870 
871         }
872       }
873       arows[ar].update();
874       nextlevblocks = 1;
875     }
876     ar++;
877   }
878   aRowLastTick = SDL_GetTicks();
879 }
880 
draw()881 void draw()
882 {
883 
884   if(glBlink && !glBlinkOff)
885   {
886     int ticks = SDL_GetTicks() - drawLastTick;
887 
888     glClearColor( 1.0f, 0.0f, 0.0f, 0.0f );
889     if(ticks > 50)
890     {
891       glBlink=0;
892       glClearColor( 0.0f, 0.0f, 0.0f, 0.0f );
893     }
894   }
895 
896   glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
897 
898   if(starfield)
899   {
900     glStarfield();
901     lastStarTick = SDL_GetTicks();
902   }
903 
904   //Reset position
905   glLoadIdentity();
906   glTranslatef( 0.0f, 0.0f, -6.0f );
907 
908 
909   renderAlienRows();
910 
911 
912   int thisbullet=0;
913   //Vis bullets...
914   while(thisbullet != NUM_BULLETS)
915   {
916     if(bullets[thisbullet].active == 1)
917     {
918       glPushMatrix();
919       glLoadIdentity();
920       glTranslatef( 0.0f, 0.0f, -6.0f );
921       bullets[thisbullet].move();
922       if(bullets[thisbullet].dir==0)
923         glCallList(glAlienBulletMesh);
924       else
925         glCallList(glPlayerBullet);
926       glPopMatrix();
927     }
928     thisbullet++;
929   }
930 
931   //Player FIXME: Som det er nu varer det en frame før skibet skyder!
932   glPushMatrix();
933   glLoadIdentity();
934   glTranslatef( 0.0f, 0.0f, -6.0f );
935   playerobj.move();
936   if(playerobj.lives > 0)
937   {
938     glBegin( GL_TRIANGLES );
939       if(playerobj.shooting)
940         glColor3f(1.0f,0.0f,0.0f);
941       else
942         glColor3f(0.0f,1.0f,1.0f);
943       playerobj.shooting=0;
944       glVertex3f( 0.0f, 0.15f,0.0f );
945       glColor3f(0.0f,0.0f,1.0f);
946       glVertex3f( -0.15f, -0.15f,0.0f);
947       glVertex3f(  0.15f, -0.15f,0.0f);
948 
949       glVertex3f( 0.15f, -0.15f, 0.0f);
950       glVertex3f( 0.0f,  -0.15f, 0.0f);
951       glVertex3f( 0.20f, -0.25f, 0.f);
952 
953       glVertex3f( -0.15f, -0.15f, 0.0f);
954       glVertex3f( 0.0f,  -0.15f, 0.0f);
955       glVertex3f( -0.20f, -0.25f, 0.f);
956 
957     glEnd( );
958   }
959   glPopMatrix();
960 
961 
962   //Scoreboard
963   glScoreboard();
964 
965   renderParticlesystems();
966 
967     glPopMatrix();
968     /* Draw it to the screen */
969     SDL_GL_SwapBuffers( );
970 }
971 
initSound()972 void initSound()
973 {
974   if(Mix_OpenAudio( 22050, MIX_DEFAULT_FORMAT, 2, 1024 ) == -1)
975   {
976     cout << "\nUnable to initializing sound\n";
977     exitgame(1);
978   }
979   SND_playerbullet = Mix_LoadWAV( "/usr/local/share/simplevaders/playerbullet.wav" );
980   SND_playerhit = Mix_LoadWAV("/usr/local/share/simplevaders/playerhit.wav");
981   SND_nmedie = Mix_LoadWAV( "/usr/local/share/simplevaders/nmedie.wav" );
982   SND_gameover = Mix_LoadWAV("/usr/local/share/simplevaders/gameover.wav");
983 
984   if(SND_playerbullet == NULL)
985   {
986     cout << "\nCouldn't load /usr/local/share/simplevaders/playerbullet.wav\n";
987     exitgame(1);
988   }
989 
990   if(SND_playerhit == NULL)
991   {
992     cout << "\nCouldn't load /usr/local/share/simplevaders/playerhit.wav\n";
993     exitgame(1);
994   }
995 
996   if(SND_nmedie == NULL)
997   {
998     cout << "\nCouldn't load /usr/local/share/simplevaders/nmedie.wav\n";
999     exitgame(1);
1000   }
1001 
1002   if(SND_gameover == NULL)
1003   {
1004     cout << "\nCouldn't load /usr/local/share/simplevaders/gameover.wav\n";
1005     exitgame(1);
1006   }
1007 }
1008 
1009 
spawnPsystem(GLfloat x,GLfloat y,GLfloat scale,int life,GLfloat maxvel)1010 void spawnPsystem(GLfloat x, GLfloat y, GLfloat scale, int life, GLfloat maxvel) {
1011 int ps=0;
1012   if(enablePs)
1013   {
1014     //Find et system der er ledigt
1015     while(ps < NUM_PSYS)
1016     {
1017       if(psys[ps].liveparticles==0)
1018       {
1019         psys[ps].numparticles = NUM_PARTICLES;
1020         psys[ps].scale = scale;
1021         psys[ps].ox = x;
1022         psys[ps].oy = y;
1023         psys[ps].syslife = life;
1024         psys[ps].maxvel = maxvel;
1025         psys[ps].init();
1026         break;
1027       }
1028       ps++;
1029     }
1030   }
1031 }
1032 
renderParticlesystems()1033 void renderParticlesystems()
1034 {
1035   int ps=0;
1036   if(enablePs)
1037   {
1038     while(ps < NUM_PSYS)
1039     {
1040     // cout << "\n Rendering particles..\n";
1041       if(psys[ps].liveparticles > 0)
1042       {
1043         psys[ps].update();
1044     //   cout << "rendering live particle..\n";
1045       }
1046       ps++;
1047     }
1048   }
1049 }
1050 
intro(int playstate)1051 void intro(int playstate)
1052 {
1053   glClearColor( 0.0f, 0.0f, 0.0f, 0.0f );
1054   glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
1055 
1056   if(starfield)
1057   {
1058     glStarfield();
1059     lastStarTick = SDL_GetTicks();
1060   }
1061 
1062 
1063 
1064   glPushMatrix();
1065   glLoadIdentity();
1066   glTranslatef( 0.0f, 0.0f, -6.0f );
1067 
1068   glEnable(GL_TEXTURE_2D);
1069   if(playstate==1)
1070     glBindTexture(GL_TEXTURE_2D, glTexture[1]);
1071   else if(playstate==2)
1072     glBindTexture(GL_TEXTURE_2D, glTexture[2]);
1073   else
1074     glBindTexture(GL_TEXTURE_2D, glTexture[4]);
1075 
1076   glEnable(GL_BLEND);
1077   glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1078   glBegin( GL_QUADS );
1079 
1080     glColor3f(1.0f,1.0f,1.0f);
1081 
1082     glTexCoord2f( 0.0f, -1.0f );
1083     glVertex3f( -1.0f, 1.0f, 0.0f );
1084 
1085     glTexCoord2f( 1.0f, -1.0f );
1086     glVertex3f( 1.0f, 1.0f, 0.0f );
1087 
1088     glTexCoord2f( 1.0f, 0.0f );
1089     glVertex3f( 1.0f, -1.0f, 0.0f );
1090 
1091     glTexCoord2f( 0.0f, 0.0f );
1092     glVertex3f( -1.0f, -1.0f, 0.0f );
1093   glEnd();
1094   glDisable(GL_TEXTURE_2D);
1095 
1096   glDisable(GL_BLEND);
1097   glPopMatrix();
1098 
1099   glScoreboard();
1100 
1101   renderParticlesystems();
1102 
1103   SDL_GL_SwapBuffers( );
1104 
1105 }
1106 
1107 SDL_Joystick *joyA = NULL;
1108 int joysticknr=0;
1109 int playstate = 1;
1110 Sint16 x_move=0, y_move=0;
1111 Uint8 btnA=0;
1112 
handleInputPlaying()1113 void handleInputPlaying()
1114 {
1115   //Ikke flere aliens? Næste bane
1116   if(nextlevblocks==0)
1117   {
1118     level++;;
1119     playerobj.lives++;
1120     initGameObjects(0);
1121     playerbullets=0;
1122   }
1123 
1124   Uint8 *keyStates = SDL_GetKeyState( NULL );
1125   if(keyStates[SDLK_LEFT])
1126     playerobj.xvel=-2.5f;
1127   if(keyStates[SDLK_RIGHT])
1128     playerobj.xvel=2.5f;
1129   if(keyStates[SDLK_UP])
1130     playerobj.yvel=2.5f;
1131   if(keyStates[SDLK_DOWN])
1132     playerobj.yvel=-2.5f;
1133   if(keyStates[SDLK_LCTRL])
1134     playerobj.shooting=1;
1135 
1136 
1137   if(SDL_JoystickOpened(joysticknr))
1138   {
1139     x_move=SDL_JoystickGetAxis(joyA, 0);
1140     y_move=SDL_JoystickGetAxis(joyA, 1);
1141     btnA = SDL_JoystickGetButton(joyA,0);
1142 
1143     if(x_move < -200)
1144       playerobj.xvel=-2.5f;
1145     if(x_move > 200)
1146       playerobj.xvel=2.5f;
1147     if(y_move < -200)
1148       playerobj.yvel=2.5f;
1149     if(y_move > 200)
1150       playerobj.yvel=-2.5f;
1151     if(btnA)
1152       playerobj.shooting=1;
1153   }
1154 }
1155 
1156 
1157 
1158 
main(int argc,char * argv[])1159 int main (int argc, char *argv[]) {
1160 bool fullscreen=0;
1161 int resx=1600;
1162 int resy=1200;
1163 int sleepdelay = 10000;
1164 
1165 drawLastTick=0;
1166 
1167 int arg=0;
1168 while(arg != argc)
1169 {
1170   if(strcmp(argv[arg],"--nosound") == 0)
1171   {
1172     sound=0;
1173     cout << "\nSound disabled.\n";
1174   } else if(strcmp(argv[arg],"--fullscreen") == 0)
1175   {
1176     fullscreen=1;
1177   } else if(strcmp(argv[arg],"--noblink") == 0)
1178   {
1179     glBlinkOff=1;
1180     cout << "\nBlinking disabled.\n";
1181   } else if(strcmp(argv[arg], "--x") == 0)
1182   {
1183     arg++; //det er det næste der er spændende
1184     resx = atoi(argv[arg]);
1185   } else if(strcmp(argv[arg], "--y") == 0)
1186   {
1187     arg++;
1188     resy = atoi(argv[arg]);
1189   } else if(strcmp(argv[arg],"--nostars") == 0) {
1190     starfield=0;
1191   } else if(strcmp(argv[arg],"--noparticles") == 0) {
1192     enablePs=0;
1193   } else if(strcmp(argv[arg],"--sleep") == 0) {
1194     arg++;
1195     sleepdelay = atoi(argv[arg]);
1196     if(sleepdelay < 10)
1197       sleepdelay = 1000;
1198   } else if(strcmp(argv[arg],"--help") == 0 || strcmp(argv[arg],"-help") == 0 || strcmp(argv[arg],"-h") == 0)
1199   {
1200     cout << "\nsimplevaders - a space-invaders like game that is nothing like space-invaders.\nUsage:\n  simplevaders [--nosound] [--fullscreen] [--noblink] [--x pixels] [--y pixels] [--nostars] [--noparticles] [--sleep USeconds]\n\nControls:\n s = toggle sound (if enabled)\n f = toggle fullscreen\n a = toggle starfield\n arrows = move ship\n lctrl = shoot\n\nJoystick 0:\n btn0 = shoot\n xy aix.. go figure.\n";
1201     return(0);
1202   }
1203   arg++;
1204 }
1205 
1206 if(resx < 1 || resy < 1 || resx > 12000 || resy > 12000)
1207 {
1208   cout << "\nInvalid resolution:" << resx <<"x" << resy << "\n";
1209   exitgame(1);
1210 }
1211 
1212 
1213   //Initialize SDL
1214   if(SDL_Init(SDL_INIT_VIDEO|SDL_INIT_TIMER|SDL_INIT_JOYSTICK) <0 )
1215   {
1216     printf("\nError: Unable to initialize SDL:%s\n", SDL_GetError());
1217     exitgame(1);
1218   }
1219 
1220  SDL_ShowCursor(SDL_DISABLE);
1221 
1222   //joysticks?
1223   if(SDL_NumJoysticks() > 0)
1224   {
1225     joyA = SDL_JoystickOpen(joysticknr);
1226     cout << "\n" << SDL_NumJoysticks() << " joysticks found, using '" << SDL_JoystickName(joysticknr) << "' with "<<SDL_JoystickNumButtons(joyA)<<" buttons.\n";
1227     if(!SDL_JoystickOpened(joysticknr))
1228       cout << " error opening joystick, no joystick.\n";
1229 
1230     SDL_JoystickEventState (SDL_ENABLE);
1231   }
1232 
1233   if(fullscreen)
1234     screen = SDL_SetVideoMode(resx,resy,32,SDL_OPENGL|SDL_RESIZABLE|SDL_DOUBLEBUF|SDL_FULLSCREEN );
1235   else
1236     screen = SDL_SetVideoMode(resx,resy,32,SDL_OPENGL|SDL_RESIZABLE|SDL_DOUBLEBUF );
1237 
1238   if( screen == NULL )
1239   {
1240     printf("\nError: Unable to set screen to %ix%i: %s\n",resx,resy,SDL_GetError());
1241     exitgame(1);
1242   }
1243 
1244   if(TTF_Init() == -1)
1245   {
1246     cout << "\nError: could not init SDL_ttf: "<< TTF_GetError() <<"\n";
1247     exitgame(1);
1248   }
1249 
1250   SDL_WM_SetCaption("simplevaders", "simplevaders");
1251 
1252   initGL();
1253   initTxt();
1254   initGameObjects(1);
1255   initStarField();
1256 
1257   if(sound)
1258     initSound();
1259 
1260       /* resize the initial window */
1261   resizeWindow(resx,resy);
1262   int done=0;
1263 
1264   while(done == 0)
1265   {
1266 
1267     nextlevblocks=0;
1268     if(playstate==0)
1269       draw();
1270     else if(playstate>0)
1271       intro(playstate);
1272 
1273     if(playstate==0)
1274       handleInputPlaying();
1275 
1276     while (SDL_PollEvent(&event) )
1277     {
1278 
1279       if( event.type == SDL_QUIT ) {
1280         done = 1;
1281       }
1282 
1283       if( event.type == SDL_KEYDOWN ) {
1284         if(event.key.keysym.sym==SDLK_f)
1285         {
1286           if(!fullscreen)
1287           {
1288             fullscreen=1;
1289             screen = SDL_SetVideoMode(resx,resy,32,SDL_OPENGL|SDL_RESIZABLE|SDL_DOUBLEBUF|SDL_FULLSCREEN );
1290           } else {
1291             fullscreen=0;
1292             screen = SDL_SetVideoMode(resx,resy,32,SDL_OPENGL|SDL_RESIZABLE|SDL_DOUBLEBUF );
1293           }
1294           resizeWindow(resx,resy);
1295           if( screen == NULL )
1296           {
1297             printf("\nError: Unable to set screen to %ix%i: %s\n",resx,resy,SDL_GetError());
1298             exitgame(1);
1299           }
1300         }
1301 
1302         if(event.key.keysym.sym==SDLK_LCTRL && playstate > 0)
1303         {
1304           playstate--;
1305           if(playstate==0)
1306             newgame();
1307         }
1308 
1309         if( event.key.keysym.sym==SDLK_s)
1310           sound=!sound;
1311 
1312         if( event.key.keysym.sym==SDLK_a)
1313           starfield=!starfield;
1314 
1315         if( event.key.keysym.sym==SDLK_ESCAPE)
1316         {
1317           if(playstate==3)
1318           {
1319             playstate=4;
1320           }
1321           else
1322           {
1323             playstate=3;
1324             spawnPsystem(-2.0, 1.8,1.5, 6000, 2.5);
1325             spawnPsystem( 2.0, 1.8,1.5, 6000, 2.5);
1326             spawnPsystem( 2.0,-1.8,1.5, 6000, 2.5);
1327             spawnPsystem(-2.0,-1.8,1.5, 6000, 2.5);
1328             spawnPsystem(0.0,0.0,1.5, 6000, 2.5);
1329           }
1330         }
1331 
1332       }
1333 
1334       if( event.type == SDL_VIDEORESIZE ) {
1335         screen = SDL_SetVideoMode(event.resize.w, event.resize.h,32,SDL_OPENGL|SDL_RESIZABLE|SDL_DOUBLEBUF );
1336         if( screen == NULL )
1337         {
1338           printf("\nError: Unable to set screen to %ix%i: %s\n",resx,resy,SDL_GetError());
1339           exitgame(1);
1340         }
1341         resizeWindow(event.resize.w, event.resize.h);
1342       }
1343 
1344       if(event.type == SDL_JOYBUTTONDOWN)
1345       {
1346         if(event.jbutton.button==0 && playstate > 0)
1347         {
1348           playstate--;
1349           if(playstate==0)
1350             newgame();
1351         }
1352       }
1353     }
1354 
1355     if(playstate==4)
1356       done=1;
1357 
1358     usleep(sleepdelay);
1359 //    SDL_Delay(10);
1360   }
1361 
1362   exitgame(0);
1363 }
1364 
game_over()1365 void game_over()
1366 {
1367   if(sound)
1368     Mix_PlayChannel(-1, SND_gameover, 0);
1369 
1370   spawnPsystem(playerobj.pos[0],playerobj.pos[1]-0.25,3.4f,5000,1.5);
1371   playstate=2;
1372 }
1373 
newgame()1374 void newgame()
1375 {
1376   level=1;
1377   playerbullets=0;
1378   initGameObjects(1);
1379 }
1380 
exitgame(bool status)1381 void exitgame(bool status) {
1382 
1383   //Free SDL surfaces
1384   SDL_FreeSurface( screen );
1385 
1386   //Free font
1387   TTF_CloseFont( font );
1388 
1389   //Shutdown sdl_ttf
1390   TTF_Quit();
1391 
1392   //Sound
1393   if(sound) {
1394     Mix_FreeChunk( SND_playerbullet );
1395     Mix_FreeChunk( SND_nmedie );
1396     Mix_FreeChunk( SND_gameover );
1397     Mix_FreeChunk ( SND_playerhit );
1398     Mix_CloseAudio();
1399   }
1400 
1401   //Close joysticks
1402   if(SDL_JoystickOpened(joysticknr))
1403   {
1404     SDL_JoystickClose(joyA);
1405   }
1406 
1407   //Shutdown sdl
1408   SDL_ShowCursor(SDL_ENABLE);
1409   SDL_Quit();
1410 
1411 
1412   if(status)
1413   {
1414     cout << "\nExited with errors.\n";
1415     exit(1);
1416   } else {
1417     cout << "\nThanks for playing, come back soon! ;)\nBest score this game was "<< bestScore << " points.\n";
1418     exit(0);
1419   }
1420 }
1421