~ubuntu-branches/ubuntu/jaunty/gtkgl2/jaunty

« back to all changes in this revision

Viewing changes to examples/zktor.c

  • Committer: Bazaar Package Importer
  • Author(s): Marcelo E. Magallon
  • Date: 2003-05-11 19:47:24 UTC
  • Revision ID: james.westby@ubuntu.com-20030511194724-8ps3cvawx0n99kl8
Tags: upstream-1.99.0
Import upstream version 1.99.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* 
 
2
 * Copyright (C) 1998 Janne L�f <jlof@mail.student.oulu.fi>
 
3
 *
 
4
 * This library is free software; you can redistribute it and/or
 
5
 * modify it under the terms of the GNU Library General Public
 
6
 * License as published by the Free Software Foundation; either
 
7
 * version 2 of the License, or (at your option) any later version.
 
8
 *
 
9
 * This library is distributed in the hope that it will be useful,
 
10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
12
 * Library General Public License for more details.
 
13
 *
 
14
 * You should have received a copy of the GNU Library General Public
 
15
 * License along with this library; if not, write to the Free
 
16
 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
17
 */
 
18
 
 
19
 
 
20
/* Zktor is a word that does not mean anything and is difficult to pronounce. */
 
21
/* I apologize for horrible coding. */
 
22
 
 
23
 
 
24
#include <math.h>
 
25
#include <stdlib.h>
 
26
#include <glib.h>
 
27
#include <gtk/gtk.h>
 
28
#include <gdk/gdk.h>
 
29
#include <gdk/gdkkeysyms.h>
 
30
#include <gtkgl/gtkglarea.h>
 
31
#include <GL/gl.h>
 
32
#include <GL/glu.h>
 
33
 
 
34
#ifndef M_PI
 
35
#define M_PI 3.14
 
36
#endif
 
37
 
 
38
 
 
39
/* #define FULLSCREEN_MESA_3DFX    /* uncomment this to get 3DFX acceleration */
 
40
 
 
41
#ifdef FULLSCREEN_MESA_3DFX
 
42
#include <GL/xmesa.h>
 
43
#endif 
 
44
 
 
45
 
 
46
 
 
47
typedef struct {
 
48
  int   state; /* zero state means dead */
 
49
  float timer;
 
50
  float pos_x,pos_y;
 
51
  float vel_x,vel_y;
 
52
  float dir;
 
53
  float radius;
 
54
} Entity;
 
55
 
 
56
/* game state */
 
57
 
 
58
GTimer *gtimer = NULL;
 
59
 
 
60
double game_time;
 
61
double game_tick;
 
62
int draw_fast = 0;
 
63
 
 
64
int wave_cnt;
 
65
double wave_time;
 
66
double vortex_time;
 
67
 
 
68
int control_speed;
 
69
int control_spin;
 
70
int control_fire;
 
71
 
 
72
int score = 0;
 
73
int highscore = 0;
 
74
 
 
75
Entity player;
 
76
Entity enemy[10];
 
77
Entity vortex[10];
 
78
Entity p_bullet[20];
 
79
Entity e_bullet[20];
 
80
Entity particle[60];
 
81
 
 
82
GLuint fontbase = 0;
 
83
 
 
84
 
 
85
float rnd()
 
86
{
 
87
  return (1.0*rand()/(RAND_MAX+1.0));
 
88
}
 
89
int collision(const Entity *a, const Entity *b)
 
90
{
 
91
  if (a->state && b->state) { 
 
92
    float dx = a->pos_x  - b->pos_x;
 
93
    float dy = a->pos_y  - b->pos_y;
 
94
    float r  = a->radius + b->radius;
 
95
    if (dx*dx+dy*dy < r*r)
 
96
      return TRUE;
 
97
  }
 
98
  return FALSE;
 
99
}
 
100
 
 
101
void gCircle(float radius, int points)
 
102
{
 
103
  float a,step = 360.0/points;
 
104
  for (a = 0; a < 360.0; a += step) {
 
105
    float dx = -sin(a*M_PI/180);
 
106
    float dy =  cos(a*M_PI/180);
 
107
    glVertex2f(dx*radius,dy*radius);
 
108
  }
 
109
}
 
110
 
 
111
 
 
112
void game_init()
 
113
{
 
114
  int i;
 
115
 
 
116
  if (!gtimer)
 
117
    gtimer = g_timer_new();
 
118
  g_timer_reset(gtimer);
 
119
 
 
120
  game_time = g_timer_elapsed(gtimer, NULL);
 
121
  game_tick  = 1.0 / 60;
 
122
 
 
123
  wave_cnt = 0;
 
124
  wave_time = game_time + 5; /* give 5 secs before start of waves */
 
125
  vortex_time = game_time + 3; /* give 3 secs before 1st vortex */
 
126
 
 
127
 
 
128
  control_speed = 0;
 
129
  control_spin  = 0;
 
130
  control_fire  = 0;
 
131
 
 
132
  score = 0;
 
133
 
 
134
  player.state = 1;
 
135
  player.timer = game_time;
 
136
  player.pos_x = 0;
 
137
  player.pos_y = 0;
 
138
  player.vel_x = 0;
 
139
  player.vel_y = 0;
 
140
  player.dir   = 0;
 
141
  player.radius= 5;
 
142
 
 
143
 
 
144
  for (i=0; i<sizeof(enemy)/sizeof(Entity); i++)
 
145
    enemy[i].state = 0;
 
146
 
 
147
  for (i=0; i<sizeof(vortex)/sizeof(Entity); i++)
 
148
    vortex[i].state = 0;
 
149
 
 
150
  for (i=0; i<sizeof(p_bullet)/sizeof(Entity); i++)
 
151
    p_bullet[i].state = 0;
 
152
 
 
153
  for (i=0; i<sizeof(e_bullet)/sizeof(Entity); i++)
 
154
    e_bullet[i].state = 0;
 
155
}
 
156
void game_play()
 
157
{
 
158
  int i;
 
159
  double time_now,tick_now;
 
160
 
 
161
  /* timing */
 
162
  time_now = g_timer_elapsed(gtimer, NULL);
 
163
  tick_now = time_now - game_time;
 
164
  if (tick_now < 0.001) tick_now = 0.001;
 
165
  if (tick_now > 0.2  ) tick_now = 0.2;
 
166
  game_tick = (tick_now + 4*game_tick)/5; /* average */
 
167
  game_time = time_now;
 
168
  
 
169
 
 
170
  /* is it time for next wave? */
 
171
  if (player.state && wave_time <= game_time) {
 
172
    wave_time = game_time + 20; /* 20 second waves */
 
173
    wave_cnt++;
 
174
    for (i=0; i<wave_cnt; i++) {
 
175
      int j;
 
176
      for (j=0; j<sizeof(enemy)/sizeof(Entity); j++) {
 
177
        if (!enemy[j].state) {
 
178
          enemy[j].radius = 50;
 
179
          do {
 
180
            enemy[j].pos_x = rnd()*200 - 100;
 
181
            enemy[j].pos_y = rnd()*200 - 100;
 
182
          } while (collision(&enemy[j], &player));
 
183
          enemy[j].state = 1;
 
184
          enemy[j].timer = game_time;
 
185
          enemy[j].vel_x = 0;
 
186
          enemy[j].vel_y = 0;
 
187
          enemy[j].dir = 360*rnd()-180;
 
188
          enemy[j].radius = 5;
 
189
          break;
 
190
        }
 
191
      }
 
192
    }
 
193
  }
 
194
 
 
195
 
 
196
 
 
197
  /* player */
 
198
  if (player.state) {
 
199
    float dx,dy;
 
200
 
 
201
    /* turn to direction given by spin control */
 
202
    player.dir   += 180 * control_spin  * game_tick;
 
203
    while (player.dir > 180) player.dir -= 360;
 
204
    while (player.dir <-180) player.dir += 360;
 
205
    /* unit direction vector */
 
206
    dx = -sin(player.dir*(M_PI/180));
 
207
    dy =  cos(player.dir*(M_PI/180));
 
208
    /* accelerate if speed control is pressed */
 
209
    player.vel_x += 50 * control_speed * dx * game_tick;
 
210
    player.vel_y += 50 * control_speed * dy * game_tick;
 
211
    /* move */
 
212
    player.pos_x += player.vel_x * game_tick;
 
213
    player.pos_y += player.vel_y * game_tick;
 
214
    /* collision to border */
 
215
    if (player.pos_x < -100) {
 
216
      player.pos_x = -100;
 
217
      player.vel_x = 0;
 
218
    }
 
219
    if (player.pos_x > 100) {
 
220
      player.pos_x = 100;
 
221
      player.vel_x = 0;
 
222
    }
 
223
    if (player.pos_y < -100) {
 
224
      player.pos_y = -100;
 
225
      player.vel_y = 0;
 
226
    }
 
227
    if (player.pos_y > 100) {
 
228
      player.pos_y = 100;
 
229
      player.vel_y = 0;
 
230
    }
 
231
    /* if fire is pressed and 0.2 secs has elapsed since last bullet fired */
 
232
    if (control_fire && (game_time - player.timer) > 0.2  ) {
 
233
      for (i=0; i<sizeof(p_bullet)/sizeof(Entity); i++) {
 
234
        if (!p_bullet[i].state) {
 
235
          player.timer = game_time;
 
236
          p_bullet[i].state = 1;
 
237
          p_bullet[i].timer = game_time;
 
238
          p_bullet[i].pos_x = player.pos_x + player.radius*dx;
 
239
          p_bullet[i].pos_y = player.pos_y + player.radius*dy;
 
240
          p_bullet[i].vel_x = player.vel_x + dx*100;
 
241
          p_bullet[i].vel_y = player.vel_y + dy*100;
 
242
          p_bullet[i].dir   = player.dir;
 
243
          p_bullet[i].radius= .5;
 
244
          break;
 
245
        }
 
246
      }
 
247
    }
 
248
 
 
249
    /* if speed control is pressed create more particles */
 
250
    if (control_speed) {
 
251
      for (i=0; i<sizeof(particle)/sizeof(Entity); i++) {
 
252
        if (!particle[i].state) {
 
253
          float spread = rnd()*15 - 7.5;
 
254
          particle[i].state = 1;
 
255
          particle[i].timer = game_time + rnd()*.8 + .2;
 
256
          particle[i].pos_x = player.pos_x - player.radius*dx;
 
257
          particle[i].pos_y = player.pos_y - player.radius*dy;
 
258
          particle[i].vel_x = player.vel_x - dx*25 - dy * spread;
 
259
          particle[i].vel_y = player.vel_y - dy*25 + dx * spread;
 
260
          particle[i].dir   = player.dir;
 
261
          particle[i].radius= .1;
 
262
          break;
 
263
        }
 
264
      }
 
265
    }
 
266
 
 
267
 
 
268
  } else {
 
269
    /* enemies continue to chase player position even if player is dead
 
270
       - make it center of screen if player is dead */
 
271
    player.pos_x = 0;
 
272
    player.pos_y = 0;
 
273
  }
 
274
 
 
275
 
 
276
  /* enemy */
 
277
  for (i=0; i<sizeof(enemy)/sizeof(Entity); i++) {
 
278
    if (enemy[i].state) {
 
279
      float x,y,dx,dy,a;
 
280
      int j;
 
281
 
 
282
      /* distance to player */
 
283
      x = player.pos_x - enemy[i].pos_x;
 
284
      y = player.pos_y - enemy[i].pos_y;
 
285
      /* calculate signed angle to player */
 
286
      a = enemy[i].dir + atan2(x,y) * 180/M_PI;
 
287
      while (a > 180) a-=360;
 
288
      while (a <-180) a+=360;
 
289
      /* turn towards player */
 
290
      if (a < -3) {
 
291
        enemy[i].dir += 90 * game_tick;
 
292
        while (enemy[i].dir > 180) enemy[i].dir -= 360;
 
293
      }
 
294
      if (a > 3) {
 
295
        enemy[i].dir -= 90 * game_tick;
 
296
        while (enemy[i].dir <-180) enemy[i].dir += 360;
 
297
      }
 
298
      /* unit direction vector */
 
299
      dx = -sin(enemy[i].dir*(M_PI/180));
 
300
      dy =  cos(enemy[i].dir*(M_PI/180));
 
301
      /* accelerate if player is ahead */
 
302
      if (fabs(a) < 10) {
 
303
        enemy[i].vel_x += 20*dx * game_tick;
 
304
        enemy[i].vel_y += 20*dy * game_tick;
 
305
      }
 
306
      /* move */
 
307
      enemy[i].pos_x += enemy[i].vel_x * game_tick;
 
308
      enemy[i].pos_y += enemy[i].vel_y * game_tick;
 
309
      /* collision to border */
 
310
      if (enemy[i].pos_x < -100) {
 
311
        enemy[i].pos_x = -100;
 
312
        enemy[i].vel_x = 0;
 
313
      }
 
314
      if (enemy[i].pos_x > 100) {
 
315
        enemy[i].pos_x = 100;
 
316
        enemy[i].vel_x = 0;
 
317
      }
 
318
      if (enemy[i].pos_y < -100) {
 
319
        enemy[i].pos_y = -100;
 
320
        enemy[i].vel_y = 0;
 
321
      }
 
322
      if (enemy[i].pos_y > 100) {
 
323
        enemy[i].pos_y = 100;
 
324
        enemy[i].vel_y = 0;
 
325
      }
 
326
      /* fire if player is alive and ahead */
 
327
      if (player.state && (fabs(a) < 20) && (game_time - enemy[i].timer) > .6) {
 
328
        for (j=0; j<sizeof(e_bullet)/sizeof(Entity); j++) {
 
329
          if (!e_bullet[j].state) {
 
330
            enemy[i].timer = game_time;
 
331
            e_bullet[j].state = 1;
 
332
            e_bullet[j].timer = game_time;
 
333
            e_bullet[j].pos_x = enemy[i].pos_x + enemy[i].radius*dx;
 
334
            e_bullet[j].pos_y = enemy[i].pos_y + enemy[i].radius*dy;
 
335
            e_bullet[j].vel_x = enemy[i].vel_x + dx*60;
 
336
            e_bullet[j].vel_y = enemy[i].vel_y + dy*60;
 
337
            e_bullet[j].dir   = enemy[i].dir;
 
338
            e_bullet[j].radius= .5;
 
339
            break;
 
340
          }
 
341
        }
 
342
      }
 
343
    }
 
344
  }
 
345
 
 
346
 
 
347
  /* vortex */
 
348
  for (i=0; i<sizeof(vortex)/sizeof(Entity); i++) {
 
349
    if (vortex[i].state) {
 
350
      int j;
 
351
      /* kill this vortex, time is up */
 
352
      if (vortex[i].timer < game_time) {
 
353
        vortex[i].state = 0;
 
354
        continue;
 
355
      }
 
356
      /* move */
 
357
      vortex[i].dir   += 60  * game_tick;
 
358
      vortex[i].pos_x += vortex[i].vel_x * game_tick;
 
359
      vortex[i].pos_y += vortex[i].vel_y * game_tick;
 
360
      /* collision to border */
 
361
      if (vortex[i].pos_x < -100) {
 
362
        vortex[i].pos_x = -200 - vortex[i].pos_x;
 
363
        vortex[i].vel_x = -vortex[i].vel_x;
 
364
      }
 
365
      if (vortex[i].pos_x > 100) {
 
366
        vortex[i].pos_x = 200 - vortex[i].pos_x;
 
367
        vortex[i].vel_x = -vortex[i].vel_x;
 
368
      }
 
369
      if (vortex[i].pos_y < -100) {
 
370
        vortex[i].pos_y = -200 - vortex[i].pos_y;
 
371
        vortex[i].vel_y = -vortex[i].vel_y;
 
372
      }
 
373
      if (vortex[i].pos_y > 100) {
 
374
        vortex[i].pos_y =  200 - vortex[i].pos_y;
 
375
        vortex[i].vel_y = -vortex[i].vel_y;
 
376
      }
 
377
 
 
378
      /* shake player */
 
379
      if (collision(&vortex[i], &player)) {
 
380
        player.vel_x += (rnd()*500 - 250) * game_tick;
 
381
        player.vel_y += (rnd()*500 - 250) * game_tick;
 
382
        player.dir   += (rnd()*180 -  90) * game_tick;
 
383
      }
 
384
      /* shake enemy */
 
385
      for (j=0; j<sizeof(enemy)/sizeof(Entity); j++) {
 
386
        if (collision(&vortex[i], &enemy[j])) {
 
387
          enemy[j].vel_x += (rnd()*500 - 250) * game_tick;
 
388
          enemy[j].vel_y += (rnd()*500 - 250) * game_tick;
 
389
          enemy[i].dir   += (rnd()*180 -  90) * game_tick;
 
390
        }
 
391
      }
 
392
 
 
393
    } else if (vortex_time < game_time) {
 
394
      vortex_time = game_time + rnd()*10 + 5;
 
395
      do {
 
396
        vortex[i].pos_x  = 200*rnd()-100;
 
397
        vortex[i].pos_y  = 200*rnd()-100;
 
398
        vortex[i].radius = rnd()*10 + 10;
 
399
      } while (collision(&vortex[i], &player));
 
400
      vortex[i].state = 1;
 
401
      vortex[i].timer = game_time + rnd()*15 + 5;
 
402
      do vortex[i].vel_x = rnd()*30 - 15; while (fabs(vortex[i].vel_x) < 10);
 
403
      do vortex[i].vel_y = rnd()*30 - 15; while (fabs(vortex[i].vel_y) < 10);
 
404
      vortex[i].dir = 0;      
 
405
    }
 
406
  }
 
407
 
 
408
 
 
409
  /* p_bullet */
 
410
  for (i=0; i<sizeof(p_bullet)/sizeof(Entity); i++) {
 
411
    if (p_bullet[i].state) {
 
412
      int j;
 
413
      /* move */
 
414
      p_bullet[i].pos_x += p_bullet[i].vel_x * game_tick;
 
415
      p_bullet[i].pos_y += p_bullet[i].vel_y * game_tick;
 
416
      /* collision to border kills bullet */
 
417
      if (p_bullet[i].pos_x < -115 ||
 
418
          p_bullet[i].pos_x >  115 ||
 
419
          p_bullet[i].pos_y < -115 ||
 
420
          p_bullet[i].pos_y >  115) {
 
421
        p_bullet[i].state = 0;
 
422
      }
 
423
      /* collision to enemy. kills bullet and kills enemy */
 
424
      /* and adds 100 to score */
 
425
      for (j=0; j<sizeof(enemy)/sizeof(Entity); j++) {
 
426
        if (collision(&p_bullet[i],&enemy[j])) {
 
427
          score += 100;
 
428
          if (score > highscore) highscore = score;
 
429
          p_bullet[i].state = 0;
 
430
          enemy[j].state = 0;
 
431
        }
 
432
      }
 
433
      /* collision to vortex shakes bullet */
 
434
      for (j=0; j<sizeof(vortex)/sizeof(Entity); j++) {
 
435
        if (collision(&p_bullet[i], &vortex[j])) {
 
436
          p_bullet[i].vel_x += (rnd()*600 - 300) * game_tick;
 
437
          p_bullet[i].vel_y += (rnd()*600 - 300) * game_tick;
 
438
          p_bullet[i].dir = rnd()*360-180;
 
439
        }
 
440
      }
 
441
    }
 
442
  }
 
443
 
 
444
  /* e_bullet */
 
445
  for (i=0; i<sizeof(e_bullet)/sizeof(Entity); i++) {
 
446
    if (e_bullet[i].state) {
 
447
      int j;
 
448
      /* move */
 
449
      e_bullet[i].pos_x += e_bullet[i].vel_x * game_tick;
 
450
      e_bullet[i].pos_y += e_bullet[i].vel_y * game_tick;
 
451
      /* collision to border kills bullet */
 
452
      if (e_bullet[i].pos_x < -115 ||
 
453
          e_bullet[i].pos_x >  115 ||
 
454
          e_bullet[i].pos_y < -115 ||
 
455
          e_bullet[i].pos_y >  115)
 
456
        e_bullet[i].state = 0;
 
457
      /* collision to player kills bullet and kills player */
 
458
      if (collision(&e_bullet[i], &player)) {
 
459
        e_bullet[i].state = 0;
 
460
        player.state = 0;
 
461
      }
 
462
      /* collision to vortex shakes bullet */
 
463
      for (j=0; j<sizeof(vortex)/sizeof(Entity); j++) {
 
464
        if (collision(&p_bullet[i], &vortex[j])) {
 
465
          e_bullet[i].vel_x += (rnd()*600 - 300) * game_tick;
 
466
          e_bullet[i].vel_y += (rnd()*600 - 300) * game_tick;
 
467
          e_bullet[i].dir = rnd()*360-180;
 
468
        }
 
469
      }
 
470
    }
 
471
  }
 
472
 
 
473
  /* particle */
 
474
  for (i=0; i<sizeof(particle)/sizeof(Entity); i++) {
 
475
    if (particle[i].state) {
 
476
      /* time elapsed, kill particle */
 
477
      if (particle[i].timer < game_time) {
 
478
        particle[i].state = 0;
 
479
        continue;
 
480
      }
 
481
      /* move */
 
482
      particle[i].pos_x += particle[i].vel_x * game_tick;
 
483
      particle[i].pos_y += particle[i].vel_y * game_tick;
 
484
    }
 
485
  }
 
486
 
 
487
}
 
488
 
 
489
void game_render()
 
490
{
 
491
  int i;
 
492
 
 
493
  /* drawmode */
 
494
  if (draw_fast) {
 
495
    glDisable(GL_LINE_SMOOTH);
 
496
    glDisable(GL_POINT_SMOOTH);
 
497
    glDisable(GL_BLEND);
 
498
  } else {
 
499
    glEnable(GL_LINE_SMOOTH);
 
500
    glEnable(GL_POINT_SMOOTH);
 
501
    glEnable(GL_BLEND);
 
502
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
 
503
  }
 
504
 
 
505
 
 
506
  /* view */
 
507
  glMatrixMode(GL_PROJECTION);
 
508
  glLoadIdentity();
 
509
  gluOrtho2D(-115,115,-115,115);
 
510
  glMatrixMode(GL_MODELVIEW);
 
511
  glLoadIdentity();
 
512
 
 
513
  /* clear background */
 
514
  glClearColor(0,0,0,1);
 
515
  glClear(GL_COLOR_BUFFER_BIT);
 
516
 
 
517
  /* frame around image */
 
518
  glColor3f(1,1,0);
 
519
  glBegin(GL_LINE_LOOP);
 
520
  glVertex2f(-110, 110);
 
521
  glVertex2f( 110, 110);
 
522
  glVertex2f( 110,-110);
 
523
  glVertex2f(-110,-110);
 
524
  glEnd();
 
525
 
 
526
  glColor3f(1,0,0);
 
527
  glBegin(GL_LINE_LOOP);
 
528
  glVertex2f(-105, 105);
 
529
  glVertex2f( 105, 105);
 
530
  glVertex2f( 105,-105);
 
531
  glVertex2f(-105,-105);
 
532
  glEnd();
 
533
 
 
534
  glColor3f(0,0,1);
 
535
  glBegin(GL_LINE_LOOP);
 
536
  glVertex2f(-100, 100);
 
537
  glVertex2f( 100, 100);
 
538
  glVertex2f( 100,-100);
 
539
  glVertex2f(-100,-100);
 
540
  glEnd();
 
541
 
 
542
 
 
543
  /* player */
 
544
  if (player.state) {
 
545
    glPushMatrix();
 
546
    glTranslatef(player.pos_x, player.pos_y, 0);
 
547
    glRotatef(player.dir, 0,0,1);
 
548
 
 
549
    glColor3f(.5,.5,1);
 
550
    glBegin(GL_LINE_LOOP);
 
551
    glVertex2f(-4,-4);
 
552
    glVertex2f( 0, 5);
 
553
    glVertex2f( 4,-4);
 
554
    glEnd();
 
555
 
 
556
    glColor3f(1,1,1);
 
557
    glBegin(GL_LINE_STRIP);
 
558
    glVertex2f(-2,-5);
 
559
    glVertex2f(-4,-2);
 
560
    glVertex2f(-2, 2);
 
561
    glVertex2f( 2, 2);
 
562
    glVertex2f( 4,-2);
 
563
    glVertex2f( 2,-5);
 
564
    glEnd();
 
565
 
 
566
    glPopMatrix();
 
567
  }
 
568
 
 
569
  /* enemy */
 
570
  for (i=0; i<sizeof(enemy)/sizeof(Entity); i++) {
 
571
    if (enemy[i].state) {
 
572
      glPushMatrix();
 
573
      glTranslatef(enemy[i].pos_x, enemy[i].pos_y, 0);
 
574
 
 
575
      glRotatef(enemy[i].dir, 0,0,1);
 
576
 
 
577
      glColor3f(1,0,0);
 
578
      glBegin(GL_LINE_STRIP);
 
579
      glVertex2f(-3,-4);
 
580
      glVertex2f(-5, 0);
 
581
      glVertex2f( 0, 5);
 
582
      glVertex2f( 5, 0);
 
583
      glVertex2f( 3,-4);
 
584
      glEnd();
 
585
      glColor3f(1,1,0);
 
586
      glBegin(GL_LINE_LOOP);
 
587
      glVertex2f( 0, 5);
 
588
      glVertex2f( 3,-4);
 
589
      glVertex2f(-3,-4);
 
590
      glEnd();
 
591
 
 
592
      glPopMatrix();
 
593
    }
 
594
  }
 
595
 
 
596
  /* vortex */
 
597
  for (i=0; i<sizeof(vortex)/sizeof(Entity); i++) {
 
598
    if (vortex[i].state) {
 
599
      
 
600
      glPushMatrix();
 
601
      glTranslatef(vortex[i].pos_x, vortex[i].pos_y, 0);
 
602
      glRotatef(vortex[i].dir, 0,0,1);
 
603
 
 
604
      glColor3f(0,.5,1);
 
605
      glBegin(GL_LINE_LOOP);
 
606
      gCircle(vortex[i].radius,6);
 
607
      glEnd();
 
608
 
 
609
      glColor3f(0,0,1);
 
610
      glBegin(GL_LINE_LOOP);
 
611
      gCircle(vortex[i].radius*.7, 6);
 
612
      glEnd();
 
613
 
 
614
      glColor3f(0,0,.5);
 
615
      glBegin(GL_LINE_LOOP);
 
616
      gCircle(vortex[i].radius*.4, 6);
 
617
      glEnd();
 
618
 
 
619
      glPopMatrix();
 
620
    }
 
621
  }
 
622
 
 
623
  /* p_bullet */
 
624
  for (i=0; i<sizeof(p_bullet)/sizeof(Entity); i++) {
 
625
    if (p_bullet[i].state) {
 
626
      glPushMatrix();
 
627
      glTranslatef(p_bullet[i].pos_x, p_bullet[i].pos_y, 0);
 
628
      glRotatef(p_bullet[i].dir, 0,0,1);
 
629
 
 
630
      glColor3f(1,1,1);
 
631
      glBegin(GL_LINES);
 
632
      glVertex2f(0, 1);
 
633
      glVertex2f(0,-1);
 
634
      glEnd();
 
635
 
 
636
      glPopMatrix();
 
637
    }
 
638
  }
 
639
 
 
640
  /* e_bullet */
 
641
  for (i=0; i<sizeof(e_bullet)/sizeof(Entity); i++) {
 
642
    if (e_bullet[i].state) {
 
643
      glPushMatrix();
 
644
      glTranslatef(e_bullet[i].pos_x, e_bullet[i].pos_y, 0);
 
645
      glRotatef(e_bullet[i].dir, 0,0,1);
 
646
 
 
647
      glColor3f(1,1,0);
 
648
      glBegin(GL_LINES);
 
649
      glVertex2f(0, 1);
 
650
      glVertex2f(0,-1);
 
651
      glEnd();
 
652
 
 
653
      glPopMatrix();
 
654
    }
 
655
  }
 
656
 
 
657
  /* particles */
 
658
  glColor3f(.5,.7,1);
 
659
  glBegin(GL_POINTS);
 
660
  for (i=0; i<sizeof(particle)/sizeof(Entity); i++) {
 
661
    if (particle[i].state)
 
662
      glVertex2f(particle[i].pos_x, particle[i].pos_y);
 
663
  }
 
664
  glEnd();
 
665
 
 
666
  /* textual info */
 
667
  if (fontbase) {
 
668
    char s[200];
 
669
    g_snprintf(s, sizeof(s), "wave %d score %d highscore %d", wave_cnt, score, highscore);
 
670
    
 
671
    glColor3f(.8,.8,.8);
 
672
    glRasterPos2f(-90, 90);
 
673
    glListBase(fontbase);
 
674
    glCallLists(strlen(s), GL_UNSIGNED_BYTE, s);
 
675
 
 
676
  }
 
677
}
 
678
 
 
679
 
 
680
 
 
681
/* --------------------------------------- */
 
682
 
 
683
 
 
684
#ifdef FULLSCREEN_MESA_3DFX
 
685
 
 
686
gint switch_fullscreen(GtkWidget *gl_area)
 
687
{
 
688
  static GtkWidget *fullscreenwidget = NULL;
 
689
 
 
690
  if (!fullscreenwidget)
 
691
    {
 
692
      /* Grab keyboard and pointer so that user does not wander off the game
 
693
         window while in fullscreen mode.
 
694
      */
 
695
      if (gdk_keyboard_grab(gl_area->window, FALSE, GDK_CURRENT_TIME) == 0)
 
696
        {
 
697
          if (gdk_pointer_grab(gl_area->window, FALSE, 0, NULL, NULL, GDK_CURRENT_TIME) == 0)
 
698
            {
 
699
              gtk_widget_grab_focus(gl_area);
 
700
              if (gtk_gl_area_make_current(GTK_GL_AREA(gl_area)))
 
701
                {
 
702
                  if (XMesaSetFXmode((XMESA_FX_FULLSCREEN)))
 
703
                    {
 
704
                      fullscreenwidget = gl_area;
 
705
                      return TRUE;
 
706
                    }
 
707
                }
 
708
              gdk_pointer_ungrab(GDK_CURRENT_TIME);
 
709
            }
 
710
          gdk_keyboard_ungrab(GDK_CURRENT_TIME);
 
711
        }
 
712
      return FALSE;
 
713
    }
 
714
 
 
715
  if (fullscreenwidget == gl_area)
 
716
    {
 
717
      if (gtk_gl_area_make_current(GTK_GL_AREA(gl_area)))
 
718
        XMesaSetFXmode(XMESA_FX_WINDOW);
 
719
      
 
720
      gdk_keyboard_ungrab(GDK_CURRENT_TIME);
 
721
      gdk_pointer_ungrab(GDK_CURRENT_TIME);
 
722
      fullscreenwidget = NULL;
 
723
      return TRUE;
 
724
    }
 
725
  
 
726
  return FALSE;
 
727
}
 
728
 
 
729
#endif
 
730
 
 
731
 
 
732
 
 
733
 
 
734
gint init(GtkWidget *widget)
 
735
{
 
736
  /* OpenGL functions can be called only if makecurrent returns true */
 
737
  if (gtk_gl_area_make_current(GTK_GL_AREA(widget))) {
 
738
#if !defined(WIN32)
 
739
    GdkFont *font;
 
740
#endif
 
741
 
 
742
    /* set viewport */
 
743
    glViewport(0,0, widget->allocation.width, widget->allocation.height);
 
744
 
 
745
#if !defined(WIN32)
 
746
    /* generate font display lists */
 
747
    font = gdk_font_load("-adobe-helvetica-medium-r-normal--*-120-*-*-*-*-*-*");
 
748
    if (font) {
 
749
      fontbase = glGenLists( 128 );
 
750
      gdk_gl_use_gdk_font(font, 0, 128, fontbase);
 
751
      gdk_font_unref(font);
 
752
    }
 
753
#endif
 
754
  }
 
755
  return TRUE;
 
756
}
 
757
 
 
758
 
 
759
/* When widget is exposed it's contents are redrawn. */
 
760
gint draw(GtkWidget *widget, GdkEventExpose *event)
 
761
{
 
762
  /* Draw only last expose. */
 
763
  if (event->count > 0)
 
764
    return TRUE;
 
765
 
 
766
  if (gtk_gl_area_make_current(GTK_GL_AREA(widget)))
 
767
    game_render();
 
768
 
 
769
  /* Swap backbuffer to front */
 
770
  gtk_gl_area_swapbuffers(GTK_GL_AREA(widget));
 
771
  
 
772
  return TRUE;
 
773
}
 
774
 
 
775
/* When glarea widget size changes, viewport size is set to match the new size */
 
776
gint reshape(GtkWidget *widget, GdkEventConfigure *event)
 
777
{
 
778
  /* OpenGL functions can be called only if make_current returns true */
 
779
  if (gtk_gl_area_make_current(GTK_GL_AREA(widget)))
 
780
    {
 
781
      glViewport(0,0, widget->allocation.width, widget->allocation.height);
 
782
    }
 
783
  return TRUE;
 
784
}
 
785
 
 
786
 
 
787
gint key_press_event(GtkWidget *widget, GdkEventKey *event)
 
788
{
 
789
  switch (event->keyval) {
 
790
  case GDK_Left:
 
791
    control_spin = 1;
 
792
    break;
 
793
  case GDK_Right:
 
794
    control_spin = -1;
 
795
    break;
 
796
  case GDK_Up:
 
797
  case GDK_space:
 
798
    control_fire = 1;
 
799
    break;
 
800
  case GDK_Down:
 
801
    control_speed = 1;
 
802
    break;
 
803
  case GDK_r:
 
804
    game_init();
 
805
    break;
 
806
  case GDK_q:
 
807
    gtk_main_quit();
 
808
    break;
 
809
 
 
810
#ifdef FULLSCREEN_MESA_3DFX
 
811
  case GDK_f:
 
812
    switch_fullscreen(widget);
 
813
    break;
 
814
#endif
 
815
 
 
816
  case GDK_d:
 
817
    draw_fast = (!draw_fast);
 
818
    break;
 
819
  }
 
820
  /* prevent the default handler from being run */
 
821
  gtk_signal_emit_stop_by_name(GTK_OBJECT(widget),"key_press_event");
 
822
  return TRUE;
 
823
}
 
824
 
 
825
gint key_release_event(GtkWidget *widget, GdkEventKey *event)
 
826
{
 
827
  switch (event->keyval) {
 
828
  case GDK_Left:
 
829
    if (control_spin == 1) control_spin = 0;
 
830
    break;
 
831
  case GDK_Right:
 
832
    if (control_spin == -1) control_spin = 0;
 
833
    break;
 
834
  case GDK_Up:
 
835
  case GDK_space:
 
836
    control_fire = 0;
 
837
    break;
 
838
  case GDK_Down:
 
839
    control_speed = 0;
 
840
    break;
 
841
  }
 
842
  /* prevent the default handler from being run */
 
843
  gtk_signal_emit_stop_by_name(GTK_OBJECT(widget),"key_release_event");
 
844
  return TRUE;
 
845
}
 
846
 
 
847
gint animate(GtkWidget *glarea)
 
848
{
 
849
  game_play();
 
850
  gtk_widget_draw(GTK_WIDGET(glarea), NULL);
 
851
  return TRUE;
 
852
}
 
853
 
 
854
 
 
855
int main(int argc, char **argv)
 
856
{
 
857
  GtkWidget *window,*vbox,*logo,*glarea;
 
858
 
 
859
  /* Attribute list for gtkglarea widget. Specifies a
 
860
     list of Boolean attributes and enum/integer
 
861
     attribute/value pairs. The last attribute must be
 
862
     GDK_GL_NONE. See glXChooseVisual manpage for further
 
863
     explanation.
 
864
  */
 
865
  int attrlist[] = {
 
866
    GDK_GL_RGBA,
 
867
    GDK_GL_RED_SIZE,1,
 
868
    GDK_GL_GREEN_SIZE,1,
 
869
    GDK_GL_BLUE_SIZE,1,
 
870
    GDK_GL_DOUBLEBUFFER,
 
871
    GDK_GL_NONE
 
872
  };
 
873
 
 
874
#ifdef FULLSCREEN_MESA_3DFX
 
875
  setenv("MESA_GLX_FX", "", 1);
 
876
  setenv("FX_GLIDE_NO_SPLASH", "", 1);
 
877
#endif
 
878
 
 
879
  /* initialize gtk */
 
880
  gtk_init(&argc, &argv);
 
881
 
 
882
  /* Check if OpenGL (GLX extension) is supported. */
 
883
  if (gdk_gl_query() == FALSE) {
 
884
    g_print("OpenGL not supported\n");
 
885
    return 0;
 
886
  }
 
887
 
 
888
  /* Create new top level window. */
 
889
  window = gtk_window_new( GTK_WINDOW_TOPLEVEL);
 
890
  gtk_window_set_title(GTK_WINDOW(window), "Zktor");
 
891
 
 
892
  /* Quit form main if got delete event */
 
893
  gtk_signal_connect(GTK_OBJECT(window), "delete_event",
 
894
                     GTK_SIGNAL_FUNC(gtk_main_quit), NULL);
 
895
 
 
896
 
 
897
  /* You should always delete gtk_gl_area widgets before exit or else
 
898
     GLX contexts are left undeleted, this may cause problems (=core dump)
 
899
     in some systems.
 
900
     Destroy method of objects is not automatically called on exit.
 
901
     You need to manually enable this feature. Do gtk_quit_add_destroy()
 
902
     for all your top level windows unless you are certain that they get
 
903
     destroy signal by other means.
 
904
  */
 
905
  gtk_quit_add_destroy(1, GTK_OBJECT(window));
 
906
 
 
907
 
 
908
  vbox = GTK_WIDGET(gtk_vbox_new(FALSE, 0));
 
909
  gtk_container_set_border_width(GTK_CONTAINER(vbox), 10);
 
910
 
 
911
 
 
912
  logo = gtk_label_new("Zktor");
 
913
 
 
914
 
 
915
  /* Create new OpenGL widget. */
 
916
  glarea = GTK_WIDGET(gtk_gl_area_new(attrlist));
 
917
  /* Events for widget must be set before X Window is created */
 
918
  gtk_widget_set_events(GTK_WIDGET(glarea),
 
919
                        GDK_EXPOSURE_MASK|
 
920
                        GDK_KEY_PRESS_MASK|
 
921
                        GDK_KEY_RELEASE_MASK);
 
922
  /* set minimum size */
 
923
  /*  gtk_widget_set_usize(GTK_WIDGET(glarea), 200,200); */
 
924
  /* set default size */
 
925
  gtk_gl_area_size(GTK_GL_AREA(glarea), 640,400);
 
926
 
 
927
  
 
928
  /* Connect signal handlers */
 
929
  /* Redraw image when exposed. */
 
930
  gtk_signal_connect(GTK_OBJECT(glarea), "expose_event",
 
931
                     GTK_SIGNAL_FUNC(draw), NULL);
 
932
  /* When window is resized viewport needs to be resized also. */
 
933
  gtk_signal_connect(GTK_OBJECT(glarea), "configure_event",
 
934
                     GTK_SIGNAL_FUNC(reshape), NULL);
 
935
  /* Do initialization when widget has been realized. */
 
936
  gtk_signal_connect(GTK_OBJECT(glarea), "realize",
 
937
                     GTK_SIGNAL_FUNC(init), NULL);
 
938
  /* Capture keypress events */
 
939
  gtk_signal_connect(GTK_OBJECT(glarea), "key_press_event",
 
940
                     GTK_SIGNAL_FUNC(key_press_event), NULL);
 
941
  gtk_signal_connect(GTK_OBJECT(glarea), "key_release_event",
 
942
                     GTK_SIGNAL_FUNC(key_release_event), NULL);
 
943
 
 
944
  /* construct widget hierarchy  */
 
945
  gtk_container_add(GTK_CONTAINER(window),GTK_WIDGET(vbox));
 
946
  gtk_box_pack_start(GTK_BOX(vbox),   logo, FALSE, FALSE, 0);
 
947
  gtk_box_pack_start(GTK_BOX(vbox), glarea,  TRUE,  TRUE, 0);
 
948
 
 
949
 
 
950
 
 
951
  /* show all widgets */
 
952
  gtk_widget_show(GTK_WIDGET(glarea));
 
953
  gtk_widget_show(GTK_WIDGET(logo));
 
954
  gtk_widget_show(GTK_WIDGET(vbox));
 
955
  gtk_widget_show(window);
 
956
 
 
957
  /* set focus to glarea widget */
 
958
  GTK_WIDGET_SET_FLAGS(glarea, GTK_CAN_FOCUS);
 
959
  gtk_widget_grab_focus(GTK_WIDGET(glarea));
 
960
 
 
961
  /* animating */
 
962
  gtk_idle_add((GtkFunction)animate, glarea);
 
963
 
 
964
  game_init();
 
965
  gtk_main();
 
966
 
 
967
 
 
968
  return 0;
 
969
}