Fixed a build problem.
[gljewel.git] / gljewel.c
blob0c66d573aa8674e4f7bb36008e6a89d3bb77cc88
1 /**
2 * @file gljewel.c
3 * @brief The main source file for gljewel.
5 * Copyright 2001, 2008 David Ashley <dashxdr@gmail.com>
6 * Copyright 2008 Stephen M. Webb <stephen.webb@bregmasoft.ca>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of Version 2 of the GNU General Public License as
10 * published by the Free Software Foundation.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #if defined(_WIN32) && !defined(__CYGWIN__)
23 # define WIN32_LEAN_AND_MEAN 1
24 # include <windows.h>
25 #endif
26 #include <fcntl.h>
27 #include <stdlib.h>
29 #include <stdarg.h>
30 #include <GL/gl.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <math.h>
35 #include <signal.h>
36 #include <string.h>
37 #include <stdarg.h>
38 #include <time.h>
39 #include <SDL/SDL.h>
40 #include <SDL/SDL_main.h>
42 #include "bcube.h"
43 #include "bucky.h"
44 #include "cylinder.h"
45 #include "diamond.h"
46 #include "ico.h"
47 #include "misc.h"
48 #include "matrix.h"
49 #include "pyramid.h"
50 #include "shape.h"
51 #include "sphere.h"
52 #include "text.h"
54 typedef unsigned int uint32;
56 #define SWAPTIME 20
58 #define HIGHSCOREFILENAME ".gljewelscores"
60 enum sounds {
61 ROWSOUND,
62 DROPSOUND,
63 BIGDROPSOUND,
64 SWAPSOUND,
65 GAMEOVERSOUND,
66 ALERTSOUND,
67 ILLEGALSOUND,
70 #define BDIST 1000.0f
72 shape shapes[9];
73 static GLint objectlists;
75 char clearing=1,clearonce=0;
77 float life,decay;
78 int stage,score,level;
79 int nummoves;
80 int gamestate;
81 int cumulative;
82 int cumulativebuildup;
83 float cumulativefade;
84 int enteringline;
85 int baseshow;
87 #define STARTLIFE 1000.0f
88 #define ALARMLEVEL 10.0f // seconds before death
89 #define CREDIT 50.0f
90 #define INITIALDECAY 0.4f
91 #define DECAYADD 0.02f
92 #define NEXTLEVEL 10
94 #define LIFEVISIBLE (STARTLIFE*2.0f)
96 // position/scaling settings
97 #define SCALE 0.88f // size of each jewel
98 #define SPACING 1.76f // how much to move for each row/column
99 #define SHIFTX 3.0f // shift the jewels sideways so they're not centered
100 #define SHIFTY 0.0f
102 // text settings
103 #define SCOREX -8.0f // coords for upper left
104 #define SCOREY 5.0f
105 #define SCOREZ 8.0f
106 #define FONTSIZE 0.015f
107 #define LINESPACE (FONTSIZE*70)
108 #define SCORETAB 4.3f // move to right for even spacing
110 #define HIGHX -2.0f
111 #define HIGHY 4.2f
112 #define HIGHZ 8.0f
113 #define HIGHXNUMBER 0.0f
114 #define HIGHXNAME 1.3f
115 #define HIGHXSCORE 5.0f
116 #define HIGHXLEVEL 2.5f
117 #define HIGHYSPACE (-FONTSIZE*60)
119 #define HIGHLEFT -3.5f
120 #define HIGHRIGHT 8.2f
121 #define HIGHTOP 5.7f
122 #define HIGHBOTTOM (-HIGHTOP)
124 #define MAXHIGHSCORES 100
126 #define MAXNAMELENGTH 12
127 struct highscore {
128 char name[MAXNAMELENGTH];
129 int score;
130 int level;
131 } highscores[MAXHIGHSCORES];
133 char lastentered[MAXNAMELENGTH]={0};
135 enum gamestate {
136 GAMEOVER,
137 PLAYING,
138 ENTERHIGH,
141 static GLfloat lightpos[4] = {-2.0f, 4.0f, 4.0f, 0.0f};
142 static GLfloat light1pos[4] = {22.0f, 2.0f, 4.0f, 0.0f};
143 static GLfloat light2pos[4] = {0.0f, 0.0f, 4.0f, 0.0f};
144 static GLfloat red[4] = {0.8f, 0.1f, 0.0f, 1.0f};
145 static GLfloat green[4] = {0.0f, 0.8f, 0.2f, 1.0f};
146 static GLfloat yellow[4] = {1.0f, 1.0f, 0.0f, 1.0f};
147 static GLfloat blue[4] = {0.2f, 0.2f, 1.0f, 1.0f};
148 static GLfloat white[4] = {1.0f, 1.0f, 1.0f, 1.0f};
149 static GLfloat magenta[4] = {1.0f, 0.0f, 1.0f, 1.0f};
150 #define WH2 0.7f
151 static GLfloat white2[4] = {WH2, WH2, WH2, 1.0f};
152 static GLfloat orange[4] = {1.0f, 0.5f, 0.0f, 1.0f};
153 #define GV 0.75f
154 static GLfloat grey[4] = {GV,GV,GV,1.0f};
155 #define GV2 0.75f
156 static GLfloat grey2[4] = {GV2,GV2,GV2,1.0f};
158 static GLfloat *colormaps[]={blue,orange,yellow,magenta,green,red,white};
159 static GLfloat dimmer[4]={0.0f, 0.0f, 0.0f, 0.5f};
161 vector eye;
163 #define EX 8
164 #define EY 8
166 struct element {
167 int type;
168 float ax,ay,az;
169 float angle;
170 float fall,speed;
171 float vanish;
172 float dx,dy;
173 int swapping;
174 } elements[EY][EX];
176 #define MAXSCORESPRITES 12
177 struct scoresprite {
178 float x,y,z;
179 float fade;
180 int value;
181 } scoresprites[MAXSCORESPRITES];
183 int mousex,mousey,sizex,sizey;
186 uint32 *tpixels;
187 uint32 torgba(unsigned int r,unsigned int g,unsigned int b,unsigned int a)
189 r&=255;
190 g&=255;
191 b&=255;
192 a&=255;
193 return (a<<24) | (r<<0) | (g<<8) | (b<<16);
196 int fontloaded=0;
198 int fontheight;
200 matrix unprojectmatrix;
202 void initunproject(void)
204 matrix projection,model;
205 matrix temp;
207 glGetFloatv(GL_PROJECTION_MATRIX,(void *)projection);
208 glGetFloatv(GL_MODELVIEW_MATRIX,(void *)model);
209 matrixXmatrix(&temp,&projection,&model);
210 invertmatrix(&unprojectmatrix,&temp);
213 SDL_Surface *setvideomode(int w, int h)
215 SDL_Surface *screen;
216 screen = SDL_SetVideoMode(w, h, 24, SDL_OPENGL|SDL_RESIZABLE);
217 if(!screen)
219 fprintf(stderr, "Couldn't set %dx%d GL video mode: %s\n",
220 sizex, sizey, SDL_GetError());
221 SDL_Quit();
222 exit(2);
224 return screen;
227 static void resize( unsigned int width, unsigned int height )
229 float h;
231 sizex=width;
232 sizey=height;
234 setvideomode(width, height);
236 glViewport(0, 0, (GLint) width, (GLint) height);
237 glMatrixMode(GL_PROJECTION);
238 glLoadIdentity();
239 if(width<height)
241 h=(float)height/(float)width;
242 glFrustum(-1.0, 1.0, -h, h, 5.0, 60.0);
243 } else
245 h=(float)width/(float)height;
246 glFrustum(-h,h,-1.0,1.0,5.0,60.0);
248 glMatrixMode(GL_MODELVIEW);
249 glLoadIdentity();
250 glTranslatef(0.0, 0.0, -40.0);
251 initunproject();
256 #if 0
257 static Window make_rgb_db_window( Display *dpy,
258 unsigned int width, unsigned int height )
260 int attrib[] = { GLX_RGBA,
261 GLX_RED_SIZE, 1,
262 GLX_GREEN_SIZE, 1,
263 GLX_BLUE_SIZE, 1,
264 GLX_DOUBLEBUFFER,
265 GLX_DEPTH_SIZE, 1,
266 None };
267 int scrnum;
268 XSetWindowAttributes attr;
269 uint32 mask;
270 Window root;
271 Window win;
272 GLXContext ctx;
273 XVisualInfo *visinfo;
275 scrnum = DefaultScreen( dpy );
276 root = RootWindow( dpy, scrnum );
278 visinfo = glXChooseVisual( dpy, scrnum, attrib );
279 if (!visinfo) {
280 printf("Error: couldn't get an RGB, Double-buffered visual\n");
281 exit(1);
284 /* window attributes */
285 attr.background_pixel = 0;
286 attr.border_pixel = 0;
287 attr.colormap = XCreateColormap( dpy, root, visinfo->visual, AllocNone);
288 attr.event_mask = StructureNotifyMask | ExposureMask;
289 mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
291 win = XCreateWindow( dpy, root, 0, 0, width, height,
292 0, visinfo->depth, InputOutput,
293 visinfo->visual, mask, &attr );
295 ctx = glXCreateContext( dpy, visinfo, NULL, True );
297 glXMakeCurrent( dpy, win, ctx );
299 return win;
301 #endif
304 void setmaterial(GLfloat *color)
306 float shiny=25.0;
307 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, color);
308 glMaterialfv(GL_FRONT, GL_SPECULAR, white);
309 glMaterialfv(GL_FRONT, GL_SHININESS, &shiny);
312 void makedots(float size)
314 int i;
315 float a;
316 #define DOTS 12
317 glPointSize(3.0);
318 glDisable(GL_LIGHTING);
319 glBegin(GL_POINTS);
320 for(i=0;i<DOTS;++i)
322 float u,v;
323 a=i*PI*2.0f/DOTS;
324 u=cosf(a)*size;
325 v=sinf(a)*size;
326 glVertex3f(u,v,0.0);
327 glVertex3f(u,0.0,v);
329 glEnd();
330 glEnable(GL_LIGHTING);
334 void norm2(float *p1,float *p2,float *p3)
336 float nx,ny,nz;
337 float x1,y1,z1;
338 float x2,y2,z2;
340 x1=p2[0]-p1[0];
341 y1=p2[1]-p1[1];
342 z1=p2[2]-p1[2];
344 x2=p3[0]-p1[0];
345 y2=p3[1]-p1[1];
346 z2=p3[2]-p1[2];
348 nx=y1*z2-y2*z1;
349 ny=x2*z1-x1*z2;
350 nz=x1*y2-x2*y1;
351 glNormal3f(nx,ny,nz);
355 void makespiky(GLfloat *color,float scale)
357 #define SPIKES 12
358 #define SPIKEZ 0.5f
359 #define SPIKEIN 0.7f
360 float x1[SPIKES],y1[SPIKES];
361 float x2[SPIKES],y2[SPIKES];
362 float a,b,b2;
363 int i,j;
364 float p0[3],p1[3],p2[3];
366 b=PI*2.0f/SPIKES;
367 b2=b/2.0f;
368 for(i=0;i<SPIKES;++i)
370 a=i*b;
371 x1[i]=cosf(a)*scale*SPIKEIN;
372 y1[i]=sinf(a)*scale*SPIKEIN;
373 x2[i]=cosf(a+b2)*scale;
374 y2[i]=sinf(a+b2)*scale;
377 glDisable(GL_TEXTURE_2D);
378 glEnable(GL_NORMALIZE);
379 setmaterial(color);
381 glBegin(GL_TRIANGLE_FAN);
382 p0[0]=0.0;
383 p0[1]=0.0;
384 p0[2]=SPIKEZ*scale;
385 glVertex3fv(p0);
386 p1[0]=x1[0];
387 p1[1]=y1[0];
388 p1[2]=0.0;
389 glVertex3fv(p1);
390 for(i=0;i<SPIKES;++i)
392 j=i+1;
393 if(j>=SPIKES) j-=SPIKES;
395 p2[0]=x2[i];
396 p2[1]=y2[i];
397 p2[2]=0.0;
399 norm2(p0,p1,p2);
400 glVertex3fv(p2);
402 p1[0]=x1[j];
403 p1[1]=y1[j];
404 p1[2]=0.0;
406 norm2(p0,p2,p1);
407 glVertex3fv(p1);
410 glEnd();
414 float timeindicator;
416 void showlife(void)
418 float a,b;
419 int i;
421 #define SECTIONS 24
422 #define LIFEX -6.5f
423 #define LIFEY -1.0f
424 #define LIFEZ1 8.0f
425 #define LIFEZ2 5.0f
426 #define LIFESIZE 2.0f
427 #define LIFENORMAL 0.7f
429 #define SECTIONYELLOW 4
430 #define SECTIONRED 1
433 glPushMatrix();
434 glTranslatef(LIFEX,LIFEY,LIFEZ2);
435 glRotatef(11.0f, 0.0f, 1.0f, 0.0f);
436 b=PI*2.0f/SECTIONS;
438 a=0;
439 setmaterial(blue);
440 glNormal3f(0.0f, 0.0f, 1.0f);
441 glBegin(GL_LINE_LOOP);
442 for(i=0;i<SECTIONS;++i)
444 glVertex3f(sinf(a)*LIFESIZE,cosf(a)*LIFESIZE, 0.0);
445 a+=b;
447 glEnd();
449 glBegin(GL_TRIANGLE_FAN);
450 glEnable(GL_NORMALIZE);
451 glVertex3f(0.0, 0.0, LIFEZ1-LIFEZ2);
452 if(life<LIFEVISIBLE)
454 float x,y;
455 a=PI*2.0f*life/LIFEVISIBLE;
456 x=sinf(a)*LIFESIZE;
457 y=cosf(a)*LIFESIZE;
458 glNormal3f(x,y,LIFENORMAL);
459 glVertex3f(x,y,0.0f);
460 i=(int)(life*(float)SECTIONS/LIFEVISIBLE);
461 } else i=SECTIONS;
462 if(i>SECTIONYELLOW)
463 setmaterial(green);
464 else if(i>SECTIONRED)
465 setmaterial(yellow);
466 else setmaterial(red);
468 for(;i>=0;--i)
470 if(i==SECTIONYELLOW) setmaterial(yellow);
471 else if(i==SECTIONRED) setmaterial(red);
472 a=(i-0.5f)*b;
473 glNormal3f(sinf(a), cosf(a), LIFENORMAL);
475 a=i*b;
476 glVertex3f(sinf(a)*LIFESIZE,cosf(a)*LIFESIZE,0.0);
478 glEnd();
480 glTranslatef(0.0f, -3.0f, 0.0f);
481 glRotatef(timeindicator,0.0f, 0.0f, 1.0f);
482 glCallList(objectlists+8);
483 glPopMatrix();
487 void setgrey(float v)
489 float col[4]={v,v,v,v};
490 glMaterialfv(GL_FRONT,GL_AMBIENT_AND_DIFFUSE, col);
494 void f2(float angle, GLfloat *color, int orient)
496 float nx,xt;
497 float ny,yt;
498 float nz,zt;
499 int i,j,k;
500 float t1,t2;
502 xt=yt=zt=0.0f;
503 nx=ny=nz=0.0f;
505 // glDisable(GL_DEPTH_TEST);
506 glPushMatrix();
508 nz=10.0f;
510 glRotatef(angle, 0.1f, 1.0f, 0.0f);
512 for(k=0;k<15;++k)
514 i=k%3;
515 j=k/3;
516 if(i==1 && j>=1 && j<4) continue;
518 #define TSCALE 1.3f
521 nx=ny=nz=0.0;
522 t1=(i-1)*TSCALE;
523 t2=(j-2)*TSCALE;
524 switch(orient)
526 case 0:
527 nx += t1;
528 ny += t2;
529 break;
530 case 1:
531 nx += t2;
532 nz += t1;
533 break;
534 case 2:
535 ny += t1;
536 nz += t2;
537 break;
541 glTranslatef(nx-xt,ny-yt,nz-zt);
542 xt=nx;
543 yt=ny;
544 zt=nz;
545 glPushMatrix();
546 // glRotatef(e->angle,e->ax,e->ay,e->az);
547 setmaterial(color);
548 glCallList(objectlists+1);
549 glPopMatrix();
552 glPopMatrix();
555 #define FDOWN 0.5
556 void figure(void)
558 static float angle=0.0;
559 glPushMatrix();
560 glTranslatef(-5.5, -3.0, 10.0);
561 glScalef(FDOWN, FDOWN, FDOWN);
562 f2(angle, blue, 0);
563 f2(angle, red, 1);
564 f2(angle, green, 2);
565 angle+=1;
566 glPopMatrix();
570 float cursorrot;
571 int cposx=0,cposy=0;
573 static void draw(void)
575 int i,j,k;
576 struct element *e;
577 float xt,yt,zt,x,y,t;
578 int c=0;
579 float a;
580 float nx,ny,nz;
582 if(clearing || clearonce)
584 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
585 if(clearonce) clearonce=0;
588 glLightfv(GL_LIGHT0, GL_POSITION, lightpos);
589 glLightfv(GL_LIGHT1, GL_POSITION, light1pos);
590 glLightfv(GL_LIGHT2, GL_POSITION, light2pos);
593 if(gamestate==PLAYING) showlife();
595 glPushMatrix();
597 t=SPACING;
598 y=t*(EY/2.0f-0.5f);
599 xt=yt=zt=0.0;
601 e=elements[0];
602 k=EX*EY;
603 glDisable(GL_DEPTH_TEST);
604 glEnable(GL_BLEND);
605 for(j=0;j<EY;++j)
607 x=-t*(EX/2.0f-0.5f);
608 for(i=0;i<EX;++i)
611 nx=x+SHIFTX;
612 ny=y;
613 nz=0.0;
614 nz+=(1.0f-e->vanish)*50.0f;
615 if(e->swapping)
617 float s;
618 a=e->swapping*PI/2.0f/SWAPTIME;
619 s=t*cosf(a);
620 nx+=s*e->dx;
621 ny+=s*e->dy;
622 s=t*sinf(a*2.0);
623 if(c++ & 1) s=-s;
624 nz+=s;
626 ny+=e->fall*t;
627 glTranslatef(nx-xt,ny-yt,nz-zt);
628 xt=nx;
629 yt=ny;
630 zt=nz;
631 if(gamestate==PLAYING && cposx==i && cposy==j)
632 glEnable(GL_LIGHT2);
633 if(e->swapping) {glDisable(GL_BLEND);glEnable(GL_DEPTH_TEST);}
634 glPushMatrix();
635 glRotatef(e->angle,e->ax,e->ay,e->az);
636 // glScalef(e->vanish,e->vanish,e->vanish);
637 setmaterial(colormaps[e->type]);
638 if (e->type == 2)
639 shapes[2].draw();
640 else
641 glCallList(objectlists+e->type);
642 glPopMatrix();
643 if(e->swapping) {glEnable(GL_BLEND);glDisable(GL_DEPTH_TEST);}
644 if(gamestate==PLAYING && cposx==i && cposy==j)
645 glDisable(GL_LIGHT2);
646 x+=t;
647 ++e;
649 y-=t;
651 glEnable(GL_DEPTH_TEST);
652 if(0 && cposx>=0 && cposy>=0 && cposx<EX && cposy<EY)
654 nx=-SPACING*(-cposx+EY/2.0f-0.5f);
655 ny= SPACING*(-cposy+EY/2.0f-0.5f);
656 glTranslatef(nx-xt,ny-yt,nz-zt);
657 glPushMatrix();
658 // glRotatef(cursorrot,.70710,-.70710,0.0);
659 cursorrot+=5.0f;
660 // glCallList(objectlists+7);
661 glPopMatrix();
662 glPushMatrix();
663 glRotatef(cursorrot,1.0f,0.0f,0.0f);
664 glCallList(objectlists+7);
665 glPopMatrix();
668 glPopMatrix();
670 #define SCORESPRITEFADE 0.01f
672 for(i=0;i<MAXSCORESPRITES;++i)
674 GLfloat col[4];
675 struct scoresprite *ss=scoresprites+i;
676 if(ss->fade==0.0) continue;
677 col[0]=col[1]=col[2]=ss->fade;
678 col[3]=1.0f;
679 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
680 glPushMatrix();
681 glTranslatef(ss->x,ss->y-(1.0f-ss->fade),ss->z);
682 drawstring(1,"+%d",ss->value);
683 glPopMatrix();
686 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, red);
688 glPushMatrix();
689 glTranslatef(SCOREX+SCORETAB,SCOREY,SCOREZ);
690 drawstring(2,"%d",score);
691 glTranslatef(0.0, -LINESPACE, 0.0);
692 drawstring(2,"%d",level);
693 glTranslatef(0.0, -LINESPACE, 0.0);
694 drawstring(2,"%d",nummoves);
695 glTranslatef(0.0, -LINESPACE, 0.0);
696 glPopMatrix();
698 glPushMatrix();
699 glTranslatef(SCOREX,SCOREY,SCOREZ);
700 drawstring(0,"Score");
701 glTranslatef(0.0, -LINESPACE, 0.0);
702 drawstring(0,"Level");
703 glTranslatef(0.0, -LINESPACE, 0.0);
704 drawstring(0,"Moves");
705 if(gamestate!=PLAYING)
707 glTranslatef(0.0f, -3.5f*LINESPACE, 0.0f);
708 drawstring(0,"Game Over");
710 else if(cumulativefade>0.0)
712 setgrey(cumulativefade);
713 glEnable(GL_BLEND);
714 glTranslatef(SCORETAB/2.0, -LINESPACE, 0.0);
715 drawstring(1,"+%d",cumulative);
716 glDisable(GL_BLEND);
718 glPopMatrix();
720 if(gamestate!=PLAYING)
722 struct highscore *h=highscores+baseshow;
724 glEnable(GL_BLEND);
725 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, dimmer);
726 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
727 glDisable(GL_LIGHT0);
728 glDisable(GL_LIGHT1);
729 glBegin(GL_QUADS);
730 glVertex3f(HIGHLEFT,HIGHTOP,HIGHZ);
731 glVertex3f(HIGHLEFT,HIGHBOTTOM,HIGHZ);
732 glVertex3f(HIGHRIGHT,HIGHBOTTOM,HIGHZ);
733 glVertex3f(HIGHRIGHT,HIGHTOP,HIGHZ);
734 glEnd();
735 glEnable(GL_LIGHT0);
736 glEnable(GL_LIGHT1);
737 glBlendFunc(GL_ONE,GL_ONE);
740 glPushMatrix();
741 glTranslatef(HIGHX,HIGHY,HIGHZ);
742 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, grey);
744 glPushMatrix();
745 drawstring(1,"Rank");
746 glTranslatef(HIGHXNAME, 0.0, 0.0);
747 drawstring(0,"Name");
748 glTranslatef(HIGHXSCORE, 0.0, 0.0);
749 drawstring(1,"Score");
750 glTranslatef(HIGHXLEVEL, 0.0, 0.0);
751 drawstring(1,"Level");
752 glPopMatrix();
753 glTranslatef(0.0, HIGHYSPACE, 0.0);
755 for(i=0;i<10;++i,++h)
757 char nametemp[MAXNAMELENGTH];
758 strcpy(nametemp,h->name);
759 if(enteringline==i+baseshow)
761 glMaterialfv(GL_FRONT,GL_AMBIENT_AND_DIFFUSE, red);
762 if(gamestate==ENTERHIGH)
763 strcat(nametemp,">");
765 glPushMatrix();
766 drawstring(1,"%d.",i+baseshow+1);
767 glTranslatef(HIGHXNAME, 0.0, 0.0);
768 drawstring(0,"%s",nametemp);
769 glTranslatef(HIGHXSCORE, 0.0, 0.0);
770 drawstring(1,"%d",h->score);
771 glTranslatef(HIGHXLEVEL, 0.0, 0.0);
772 drawstring(1,"%d",h->level);
773 glPopMatrix();
774 glTranslatef(0.0, HIGHYSPACE, 0.0);
775 if(enteringline==i+baseshow)
776 glMaterialfv(GL_FRONT,GL_AMBIENT_AND_DIFFUSE, grey);
778 glPopMatrix();
779 figure();
782 SDL_GL_SwapBuffers();
787 void showmatrix(float *f)
789 printf("%f %f %f %f\n",f[0],f[4],f[8],f[12]);
790 printf("%f %f %f %f\n",f[1],f[5],f[9],f[13]);
791 printf("%f %f %f %f\n",f[2],f[6],f[10],f[14]);
792 printf("%f %f %f %f\n",f[3],f[7],f[11],f[15]);
795 void getpos(int *px,int *py,int mx,int my)
797 vector world,screen;
798 GLint viewport[4];
800 glGetIntegerv(GL_VIEWPORT,viewport);
801 screen[0]=(mx-viewport[0])*2.0f/viewport[2]-1.0f;
802 screen[1]=(my-viewport[1])*2.0f/viewport[3]-1.0f;
803 screen[2]=0.27272727f;
804 screen[3]=1.0f;
805 matrixXvector(&world,&unprojectmatrix,&screen);
806 if(world[3]!=0.0)
808 float x,y;
809 float z=world[2]/world[3];
810 x=(z*world[0]/world[3]-SHIFTX)/SPACING+EX/2;
811 y=(z*world[1]/world[3]-SHIFTY)/SPACING+EY/2;
812 *px=(int)(x+1000)-1000;
813 *py=(int)(y+1000)-1000;
814 } else *px=*py=-1;
818 int chainreaction;
820 int wins[16][4]={
821 {1,-1,0,1},
822 {-1,-1,-1,1},
823 {0,-1,1,1},
824 {0,-2,0,1},
826 {1,1,-1,0},
827 {1,-1,-1,-1},
828 {1,0,-1,1},
829 {2,0,-1,0},
831 {-1,1,0,-1},
832 {1,1,1,-1},
833 {0,1,-1,-1},
834 {0,2,0,-1},
836 {-1,-1,1,0},
837 {-1,1,1,1},
838 {-1,0,1,-1},
839 {-2,0,1,0},
841 int anymoves(void)
843 unsigned char temp[EY+4][EX+4];
844 struct element *e;
845 int i,j,k,t;
846 int moves;
847 memset(temp,0xff,sizeof(temp));
848 e=elements[0];
849 for(j=0;j<EY;++j)
850 for(i=0;i<EX;++i)
851 temp[j+2][i+2]=e++ -> type;
853 moves=0;
854 for(j=2;j<EY+2;++j)
855 for(i=2;i<EX+2;++i)
856 for(k=0;k<16;++k)
858 t=temp[j][i];
859 if(t!=temp[j+wins[k][1]][i+wins[k][0]]) continue;
860 if(t!=temp[j+wins[k][3]][i+wins[k][2]]) continue;
861 ++moves;
863 return nummoves=moves;
866 void tossall(void)
868 int j;
869 struct element *e;
870 e=elements[0];
871 j=EX*EY;
872 while(j--) e++ -> vanish=0.999f;
873 playsound(BIGDROPSOUND);
876 void randomvector(float *x,float *y,float *z)
878 int ix,iy,iz;
879 float d;
883 ix=(rand()&1023)-512;
884 iy=(rand()&1023)-512;
885 iz=(rand()&1023)-512;
886 } while(ix==0 && iy==0 && iz==0);
887 d=1.0f/sqrtf((float)(ix*ix+iy*iy+iz*iz));
888 *x=ix*d;
889 *y=iy*d;
890 *z=iz*d;
891 *x=*z=0;*y=1.0;
894 void initelement(struct element *e)
897 memset(e,0,sizeof(*e));
898 e->type=(rand()&0xffff)%7;
899 e->angle=(rand()&1023)*360.0f/1024.0f;
900 e->vanish=1.0;
901 e->fall=0.0;
902 randomvector(&e->ax,&e->ay,&e->az);
905 void initelements(void)
907 int i,j;
908 struct element *e;
909 e=elements[0];
910 j=EX*EY;
911 for(i=0;i<j;++i)
912 initelement(e++);
915 void replace(void)
917 int i,j,k;
918 struct element *e,*e2;
919 int falls[EX];
921 for(i=0;i<EX;++i)
922 falls[i]=1;
923 for(j=EY-1;j>=0;--j)
925 for(i=0;i<EX;++i)
927 e=elements[j]+i;
928 if(e->vanish!=0.0) continue;
929 k=j;
930 while(--k>=0)
932 e2=elements[k]+i;
933 if(e2->vanish!=0.0) break;
935 if(k>=0)
937 *e=*e2;
938 e2->vanish=0.0;
939 e->fall=j-k;
940 } else
942 initelement(e);
943 e->fall=j+falls[i]++;
949 void addlife(int chain,int len,float x,float y)
951 int value;
952 int i;
953 struct scoresprite *ss;
954 value=chain+len;
955 cumulative=cumulativebuildup+=value;
956 cumulativefade=1.0f;
957 for(ss=scoresprites,i=0;i<MAXSCORESPRITES;++i,++ss)
959 if(ss->fade!=0.0f) continue;
960 ss->x=(x-EX/2.0f+0.5f)*SPACING+SHIFTX;
961 ss->y=-(y-EY/2.0f)*SPACING+SHIFTY;
962 ss->z=0.0f;
963 ss->fade=1.0f;
964 ss->value=value;
965 break;
968 score+=value;
969 life+=(value)*CREDIT;
970 stage+=len;
971 if(stage>=NEXTLEVEL)
973 stage-=NEXTLEVEL;
974 decay+=DECAYADD;
975 ++level;
978 void endgame(void)
980 struct highscore *h;
982 gamestate=GAMEOVER;
983 h=highscores+MAXHIGHSCORES;
984 while(h>highscores && h[-1].score<score) --h;
985 enteringline=h-highscores;
986 baseshow=enteringline-5;
987 if(baseshow<0) baseshow=0;
988 if(baseshow>MAXHIGHSCORES-10) baseshow=MAXHIGHSCORES-10;
989 if(enteringline==MAXHIGHSCORES) return;
990 memmove(h+1,h,(MAXHIGHSCORES-enteringline)*sizeof(struct highscore));
991 strcpy(h->name,lastentered);
992 h->score=score;
993 h->level=level;
994 gamestate=ENTERHIGH;
996 void declife()
998 timeindicator-=decay*5.0f;
999 life-=decay;
1000 if(life<0.0)
1002 life=0.0;
1003 if(gamestate!=GAMEOVER)
1005 endgame();
1006 playsound(GAMEOVERSOUND);
1011 int findwins(int justchecking)
1013 int i,j,k;
1014 struct element *e;
1015 int hadsome=0;
1016 float x,y;
1018 for(j=0;j<EY;++j)
1020 k=0;
1021 for(i=1;i<EX+1;++i)
1023 e=elements[j]+i;
1024 if(i<EX && e->type==e[-1].type) ++k;
1025 else if(k>=2)
1027 hadsome=1;
1028 if(!justchecking)
1030 x=i-1-k/2.0f;
1031 y=j+0.5f;
1032 addlife(chainreaction,k-1,x,y);
1034 ++k;
1035 while(k) e[-k--].vanish=0.999f;
1036 k=0;
1037 } else k=0;
1041 for(j=0;j<EX;++j)
1043 k=0;
1044 for(i=1;i<EY+1;++i)
1046 e=elements[i]+j;
1047 if(i<EY && e->type==e[-EX].type) ++k;
1048 else if(k>=2)
1050 hadsome=1;
1051 if(!justchecking)
1053 x=j;
1054 y=i-0.5f-k/2.0f;
1055 addlife(chainreaction,k-1,x,y);
1057 ++k;
1058 while(k) e[-EX*k--].vanish=0.999f;
1059 k=0;
1060 } else k=0;
1063 if(!justchecking)
1065 if(hadsome)
1067 playsound(ROWSOUND);
1068 ++chainreaction;
1069 } else chainreaction=0,cumulativebuildup=0;
1071 return hadsome;
1074 #define SWAPMAX 4
1075 char swapfifo[SWAPMAX][4];
1076 int swapput=0,swaptake=0;
1077 void addswap(int px,int py,int dx,int dy)
1079 char *p;
1080 if(((swapput+1) & (SWAPMAX-1)) == swaptake) return;
1081 p=swapfifo[swapput++];
1082 swapput&=SWAPMAX-1;
1083 *p++=px;
1084 *p++=py;
1085 *p++=dx;
1086 *p=dy;
1089 int tryswap(void)
1091 struct element t;
1092 struct element *e1,*e2;
1093 char *p;
1094 int px,py,dx,dy;
1095 if(swapput==swaptake) return 0;
1097 playsound(SWAPSOUND);
1098 p=swapfifo[swaptake++];
1099 swaptake&=SWAPMAX-1;
1100 px=*p++;
1101 py=*p++;
1102 dx=*p++;
1103 dy=*p;
1104 e1=elements[py]+px;
1105 e2=elements[py+dy]+px+dx;
1106 t=*e1;
1107 *e1=*e2;
1108 *e2=t;
1109 e1->dx=dx;
1110 e1->dy=-dy;
1111 e1->swapping=1;
1112 e2->dx=-dx;
1113 e2->dy=dy;
1114 e2->swapping=1;
1115 return 1;
1119 #define FALLRATE 0.02f
1120 #define VANISHRATE 0.05f
1122 int dropsound;
1123 int waspicked;
1124 void illegal(struct element *e1,struct element *e2)
1126 struct element t;
1127 t=*e1;
1128 *e1=*e2;
1129 *e2=t;
1130 e1->dx=-e1->dx;
1131 e1->dy=-e1->dy;
1132 e1->swapping=1;
1133 e2->dx=-e2->dx;
1134 e2->dy=-e2->dy;
1135 e2->swapping=1;
1136 waspicked=0;
1139 int alertcounter;
1141 enum actionstates {
1142 ACTION_LOOKING,
1143 ACTION_WAITING,
1144 ACTION_SWAPPING,
1145 ACTION_UNSWAPPING,
1146 ACTION_REMOVING,
1147 ACTION_DROPPING,
1150 int actionmode;
1151 void action()
1153 struct element *e,*le,*e1=0,*e2=0;
1154 int i;
1155 int hadsome;
1156 struct scoresprite *ss;
1158 if(gamestate==PLAYING && life<ALARMLEVEL*50*decay)
1160 --alertcounter;
1161 if(alertcounter<=0)
1163 playsound(ALERTSOUND);
1164 alertcounter=50;
1168 for(i=0,ss=scoresprites;i<MAXSCORESPRITES;++i,++ss)
1170 ss->fade-=SCORESPRITEFADE;
1171 if(ss->fade<0.0) ss->fade=0.0;
1174 cumulativefade-=SCORESPRITEFADE;
1175 if(cumulativefade<0.0) cumulativefade=0.0;
1177 e=elements[0];
1178 le=e+EX*EY;
1179 while(e<le) e++ ->angle+=3.0;
1181 switch(actionmode)
1183 case ACTION_LOOKING:
1184 if(findwins(0))
1185 actionmode=ACTION_REMOVING;
1186 else
1187 if(anymoves())
1188 actionmode=ACTION_WAITING;
1189 else
1190 {tossall();actionmode=ACTION_REMOVING;}
1191 break;
1192 case ACTION_WAITING:
1193 if(gamestate!=PLAYING) break;
1194 declife();
1195 if(tryswap()) actionmode=ACTION_SWAPPING;
1196 break;
1197 case ACTION_UNSWAPPING:
1198 declife();
1199 case ACTION_SWAPPING:
1200 e=elements[0];
1201 hadsome=0;
1202 while(e<le)
1204 if(e->swapping)
1206 hadsome=1;
1207 ++e->swapping;
1208 if(e->swapping==SWAPTIME)
1210 e->swapping=0;
1211 e1=e2;
1212 e2=e;
1213 hadsome=2;
1216 ++e;
1218 if(hadsome==2)
1220 if(findwins(0))
1221 actionmode=ACTION_REMOVING;
1222 else if(actionmode==ACTION_SWAPPING)
1224 playsound(ILLEGALSOUND);
1225 illegal(e1,e2);
1226 actionmode=ACTION_UNSWAPPING;
1227 } else
1228 actionmode=ACTION_WAITING;
1230 break;
1231 case ACTION_REMOVING:
1232 hadsome=0;
1233 e=elements[0];
1234 while(e<le)
1236 if(e->vanish<1.0)
1238 e->vanish-=VANISHRATE;
1239 if(e->vanish<=0.0)
1241 e->vanish=0.0;
1242 ++hadsome;
1245 ++e;
1247 if(hadsome)
1249 replace();
1250 dropsound=1;
1251 actionmode=ACTION_DROPPING;
1253 break;
1254 case ACTION_DROPPING:
1255 e=elements[0];
1256 hadsome=0;
1257 while(e<le)
1259 if(e->fall>0.0)
1261 ++hadsome;
1262 e->fall-=e->speed;
1263 e->speed+=FALLRATE;
1264 if(e->fall<=0.0)
1266 e->fall=e->speed=0.0;
1267 if(dropsound)
1269 playsound(DROPSOUND);
1270 dropsound=0;
1274 ++e;
1276 if(!hadsome) actionmode=ACTION_LOOKING;
1277 break;
1281 #define MAXCODES 64
1282 static int downcodes[MAXCODES];
1283 static int pressedcodes[MAXCODES];
1284 static int numcodes=0,numpressed=0;
1286 void processkey(int key,int state)
1288 int i;
1289 if(state)
1291 if(numpressed<MAXCODES) pressedcodes[numpressed++]=key;
1292 for(i=0;i<numcodes;++i)
1293 if(downcodes[i]==key) return;
1294 if(numcodes<MAXCODES)
1295 downcodes[numcodes++]=key;
1296 } else
1298 for(i=0;i<numcodes;)
1300 if(downcodes[i]==key)
1301 downcodes[i]=downcodes[--numcodes];
1302 else
1303 ++i;
1308 int IsDown(int key)
1310 int i;
1311 for(i=0;i<numcodes;++i)
1312 if(downcodes[i]==key) return 1;
1313 return 0;
1316 int WasPressed(int key)
1318 int i;
1319 for(i=0;i<numpressed;++i)
1320 if(pressedcodes[i]==key) return 1;
1321 return 0;
1324 void writehighscores();
1326 void typedkey(int key)
1328 char *p;
1329 if(key<0 || key>0x7f) return;
1330 p=highscores[enteringline].name;
1331 if(key==10 || key==13)
1333 gamestate=GAMEOVER;
1334 writehighscores();
1336 else if(key==8)
1338 if(*p) p[strlen(p)-1]=0;
1339 } else
1340 if(strlen(p)<MAXNAMELENGTH-1)
1342 p+=strlen(p);
1343 *p++=key;
1344 *p=0;
1346 strcpy(lastentered,highscores[enteringline].name);
1350 int downx,downy;
1351 int isdown;
1352 void down(int x,int y)
1354 downx=x;
1355 downy=y;
1356 isdown=1;
1359 #define DIST 20
1360 #define ABS(x) (((x)<0) ? (-(x)) : (x))
1361 void moved(int x,int y)
1363 int dx,dy;
1364 int px,py;
1366 getpos(&cposx,&cposy,x,y);
1367 if(!isdown) return;
1368 dx=x-downx;
1369 dy=y-downy;
1370 if(dx*dx+dy*dy<DIST*DIST) return;
1371 isdown=0;
1372 if(ABS(dx)>ABS(dy))
1374 if(dx<0) dx=-1;
1375 else dx=1;
1376 dy=0;
1377 } else
1379 if(dy<0) dy=-1;
1380 else dy=1;
1381 dx=0;
1383 getpos(&px,&py,downx,downy);
1385 #define FIX 8.0
1386 px=(EX>>1)+((float)downx/sizex-0.5)*FIX;
1387 py=(EY>>1)+((float)downy/sizey-0.5)*FIX;
1390 if(px<0 || px>=EX || py<0 || py>=EY) return;
1391 if(px+dx<0 || px+dx>=EX || py+dy<0 || py+dy>=EY) return;
1392 addswap(px,py,dx,dy);
1396 void up(int x,int y)
1398 isdown=0;
1402 void initgame(void)
1404 int i;
1405 life=STARTLIFE;
1406 decay=INITIALDECAY;
1407 do initelements(); while(findwins(1));
1408 chainreaction=swapput=swaptake=0;
1409 stage=0;
1410 score=0;
1411 level=1;
1412 gamestate=PLAYING;
1413 cumulative=0;
1414 cumulativebuildup=0;
1415 cumulativefade=0.0;
1416 alertcounter=0;
1417 baseshow=0;
1418 enteringline=-1;
1419 for(i=0;i<MAXSCORESPRITES;++i) scoresprites[i].fade=0.0;
1420 actionmode=ACTION_LOOKING;
1423 #define INTERVAL 5
1425 int hc=0;
1426 #ifdef SMW_CHANGES
1427 void thandler(int val)
1429 signal(SIGALRM,thandler);
1430 ++hc;
1432 #endif
1434 static void event_loop( void )
1436 char exitflag=0;
1437 int nframes=0;
1438 int freeze=0;
1439 SDL_Event event;
1440 int code;
1443 Uint32 ticks = SDL_GetTicks();
1445 while(!exitflag)
1447 Uint32 new_ticks = SDL_GetTicks();
1448 Uint32 delta = new_ticks - ticks;
1449 if (delta > (1000/44))
1451 action();
1452 ticks = new_ticks;
1454 ++nframes;
1455 draw();
1456 #define DELTA 1.0
1458 if(WasPressed(SDLK_F1)) initgame();
1459 if(WasPressed(SDLK_F2)) playsound(BIGDROPSOUND);
1460 if(WasPressed(SDLK_F3)) playsound(GAMEOVERSOUND);
1461 if(WasPressed(SDLK_F4)) playsound(ROWSOUND);
1462 if(WasPressed(SDLK_F5)) playsound(ILLEGALSOUND);
1463 if(WasPressed(SDLK_F6)) playsound(ALERTSOUND);
1465 #if 0
1466 if(gamestate==PLAYING && WasPressed(XK_p)) freeze=!freeze;
1467 #endif
1468 if(gamestate==GAMEOVER && WasPressed(SDLK_SPACE)) initgame();
1469 // if(WasPressed(XK_p)) freeze=!freeze;
1471 numpressed=0;
1473 while(SDL_PollEvent(&event))
1475 switch(event.type)
1477 case SDL_MOUSEMOTION:
1478 mousex=event.motion.x;
1479 mousey=event.motion.y;
1480 moved(mousex, mousey);
1481 break;
1482 case SDL_MOUSEBUTTONDOWN:
1483 mousex=event.button.x;
1484 mousey=event.button.y;
1485 down(mousex, mousey);
1486 break;
1487 case SDL_MOUSEBUTTONUP:
1488 mousex=event.button.x;
1489 mousey=event.button.y;
1490 up(mousex, mousey);
1491 break;
1492 case SDL_KEYDOWN:
1493 code=event.key.keysym.sym;
1494 if(code==SDLK_ESCAPE) exitflag=1;
1495 processkey(code, 1);
1496 if(gamestate==ENTERHIGH) typedkey(code);
1497 break;
1498 case SDL_KEYUP:
1499 code=event.key.keysym.sym;
1500 processkey(code, 0);
1501 break;
1502 case SDL_VIDEORESIZE:
1503 resize(event.resize.w, event.resize.h);
1504 break;
1505 case SDL_QUIT:
1506 exitflag=1;
1507 break;
1508 // handle resize
1514 void makehighname(char *p)
1516 char *homedir = getenv("HOME");
1517 if (homedir)
1518 sprintf(p,"%s/%s",homedir,HIGHSCOREFILENAME);
1519 else
1520 sprintf(p,"%s",HIGHSCOREFILENAME);
1523 void readhighscores()
1525 FILE *f;
1526 int i,n;
1527 char tempname[256];
1528 int score,level;
1529 struct highscore *h;
1531 memset(highscores,0,sizeof(highscores));
1532 makehighname(tempname);
1533 f=fopen(tempname,"r");
1534 if(!f) return;
1535 for(h=highscores,i=0;i<MAXHIGHSCORES;++i,++h)
1537 n=fscanf(f,"%s %d %d",tempname,&score,&level);
1538 if(n==3)
1540 tempname[MAXNAMELENGTH-1]=0;
1541 if(*tempname=='.') *tempname=0;
1542 strcpy(h->name,tempname);
1543 h->score=score;
1544 h->level=level;
1548 void writehighscores()
1550 FILE *f;
1551 int i;
1552 char tempname[256];
1553 struct highscore *h;
1555 makehighname(tempname);
1556 f=fopen(tempname,"w");
1557 if(!f) return;
1558 h=highscores;
1559 for(h=highscores,i=0;i<MAXHIGHSCORES;++i,++h)
1561 fprintf(f,"%s %d %d\n",h->name[0] ? h->name : ".",h->score,h->level);
1563 fclose(f);
1567 int main( int argc, char *argv[] )
1569 SDL_Surface *screen;
1571 // if(fork()) return;
1572 readhighscores();
1574 srand(time(NULL));
1575 soundinit();
1576 initgame();
1577 gamestate=GAMEOVER;
1578 eye[0]=10.0;
1579 eye[1]=0.0;
1580 eye[2]=0.0;
1581 eye[3]=0.0;
1584 SDL_Init(SDL_INIT_VIDEO);
1585 sizex = 800;
1586 sizey = 600;
1588 screen = setvideomode(sizex, sizey);
1589 SDL_WM_SetCaption("glJewel", "gljewel");
1591 resize(sizex, sizey);
1593 // glLightfv(GL_LIGHT0, GL_POSITION, lightpos);
1594 glEnable(GL_CULL_FACE);
1595 glEnable(GL_LIGHTING);
1596 glEnable(GL_LIGHT0);
1597 glEnable(GL_LIGHT1);
1598 glLightfv(GL_LIGHT0,GL_SPECULAR,white);
1599 glLightfv(GL_LIGHT0,GL_DIFFUSE,grey);
1600 glLightfv(GL_LIGHT1,GL_SPECULAR,white2);
1601 glLightfv(GL_LIGHT1,GL_DIFFUSE,grey2);
1602 glLightfv(GL_LIGHT2,GL_SPECULAR,white);
1603 glLightfv(GL_LIGHT2,GL_DIFFUSE,grey);
1604 glEnable(GL_DEPTH_TEST);
1606 glShadeModel( GL_FLAT );
1607 glClearColor( 0.0, 0.0, 0.0, 1.0 );
1608 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1610 glDisable(GL_BLEND);
1611 // glBlendFunc(GL_SRC_ALPHA, GL_ONE);
1612 glBlendFunc(GL_ONE, GL_ONE);
1614 #ifndef HAVE_GL_VERTEX_BUFFERS
1615 initGlVboExtension();
1617 #endif
1618 glLineWidth(2.0);
1619 glDisable(GL_LINE_SMOOTH);
1621 initfont();
1623 objectlists = glGenLists(9);
1624 glNewList(objectlists+0, GL_COMPILE);
1625 makebucky(0.9*SCALE); // blue
1626 glEndList();
1628 glNewList(objectlists+1, GL_COMPILE);
1629 makebcube(SCALE); // orange
1630 glEndList();
1632 glNewList(objectlists+2, GL_COMPILE);
1633 makepyramid(0.7*SCALE); // yellow
1634 glEndList();
1635 create_pyramid(&shapes[2]);
1636 shapes[2].create(0.7f*SCALE);
1638 glNewList(objectlists+3, GL_COMPILE);
1639 makeicosahedron(0,SCALE); // magenta
1640 glEndList();
1642 glNewList(objectlists+4, GL_COMPILE);
1643 makecylinder(0.8f*SCALE); // green
1644 glEndList();
1646 glNewList(objectlists+5, GL_COMPILE);
1647 makediamond(0.9f*SCALE); // red
1648 glEndList();
1650 glNewList(objectlists+6, GL_COMPILE);
1651 makeuvsphere(0.9f*SCALE); // white
1652 glEndList();
1654 glNewList(objectlists+7, GL_COMPILE);
1655 makedots(0.95f*SCALE);
1656 glEndList();
1658 glNewList(objectlists+8, GL_COMPILE);
1659 makespiky(blue, 1.0);
1660 glEndList();
1662 event_loop();
1663 soundfree();
1664 writehighscores();
1665 SDL_Quit();
1666 return 0;