1 /* This is "graphics.c", a part of the pool (billiards)-program
2 
3 "Another Pool GL".
4 
5 "graphics.c" uses the SDL graphics-library which is available at
6 
7 http://www.libsdl.org and
8 
9 Copyright (C) 1995,2002 by Gerrit Jahn (http://www.planetjahn.de)
10 
11 This file ist part of Another Pool / Another Pool GL (apool, apoolGL).
12 
13 "Another Pool" is free software; you can redistribute it
14 and/or modify it under the terms of the GNU General Public License
15 as published by the Free Software Foundation; either version 2 of
16 the License, or (at your option) any later version.
17 
18 This program is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
20 ME CHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21 GNU General Public License for more details.
22 
23 You should have received a copy of the GNU General Public License
24 along with GNU CC; see the file COPYING.  If not, write to
25 the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
26 
27 /* ------------------------------ graphics.c ----------------------------- */
28 
29 #include <math.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <time.h>
33 #include <sys/time.h>
34 #include <string.h>
35 #include <SDL.h>
36 #include <GL/gl.h>
37 #include <GL/glu.h>
38 #include "apool.h"
39 
40 #define GR_M_BUTTON_DOWN SDL_MOUSEBUTTONDOWN
41 #define GR_M_BUTTON_UP SDL_MOUSEBUTTONUP
42 #define GR_M_BUTTON_CHANGE SDL_MOUSEBUTTONDOWN|SDL_MOUSEBUTTONDOWN
43 #define GR_M_MOTION SDL_MOUSEMOTION
44 #define GR_M_KEYPRESS SDL_KEYDOWN
45 
46 #define PAINT_ALL \
47  gl_plotall(-1);\
48  paint_spin( 1.0/10.0, 0.45, 0.36 );\
49  speed(spd, 1.0/10.0, 0.09, 0.36);\
50  gl_plot_target();\
51  msg(current_message);\
52  msg2(current_message2);\
53  SDL_GL_SwapBuffers()
54 
55 int col[20][3] = {{0,0,0},{255,0,0},{255,255,0},{32,32,32},{0,127,0},
56                   {124,224,224},{55,0,0},{255,0,255},{32,32,222},{0,255,0},
57                   {255,255,255},{255,55,55},{0,0,0},{0,0,96},{0,0,255},
58 		  {0,0,127},{140,90,40},{0,0,196},{0,0,127},{0,0,127}};
59 #define TABLEGREEN 4
60 double oldalph=0.0, alph=0.0, spd=0.75, e_winkel, old_min;
61 int counter=0, oldx[BALLS], oldy[BALLS], olds[2];
62 int old_ball, old_hole, old_paint=5, mmouse = 0;
63 int SPINPOSX, SPINPOSY;
64 
65 struct hole posl[6]; /* 6 L�cher */
66 struct bande banpixel[18], ban[18];
67 
68 SDL_Event event;
69 SDL_Rect src_rect,dest_rect;
70 
init_graphics(void)71 void init_graphics( void )
72  {
73  InitGL(SCREENRESX, SCREENRESY);
74  }
75 
msg(char * out)76 void msg( char *out )
77  { /* Gibt einige Dinge unterhalb des Tisches aus */
78  glPrint(20,35,out,0,1.0,1.0,1.0,1.0,0.8);
79  }
80 
gl_print_foul(void)81 void gl_print_foul( void )
82  { /* Fouls anzeigen */
83  glPrintCentered(600,foul_msg,0,1.0,0.0,0.0,0.8,1.5);
84  }
85 
gl_print_err2(void)86 void gl_print_err2( void )
87  { /* freeball/extra shout anzeigen */
88  glPrintCentered(300,err2_msg1, 0, 1.0, 0.0, 0.0, 0.8,3.0);
89  glPrintCentered(220,err2_msg2, 0, 1.0, 0.0, 0.0, 0.8,3.0);
90  }
91 
msg2(char * out)92 void msg2( char *out )
93  { /* Gibt einige Dinge unterhalb des Tisches aus */
94  glPrint(20,15,out,0,1.0,1.0,1.0,1.0,0.8);
95  }
96 
plot_standings(void)97 void plot_standings( void )
98  {
99  char out[15];
100  sprintf(out,"%d : %d",(int)(ply[0].points)%10000+(int)(ply[1].points)/10000,
101 	 (int)(ply[1].points)%10000 + (int)(ply[0].points)/10000 );
102  /*   GrDrawString(out,strlen(out), display->w - (15+strlen(out))*8, 10, 10); */
103  }
104 
speed(double p,double scale,double posx,double posy)105 void speed( double p, double scale, double posx, double posy )
106  {
107  glDisable(GL_LIGHTING);
108  glEnable(GL_BLEND);
109  glDisable(GL_FOG);
110  glDisable(GL_DEPTH_TEST);             /* Disables Depth Testing */
111 
112  glMatrixMode(GL_PROJECTION);
113  glPushMatrix();
114  glLoadIdentity();
115  glOrtho(-0.5,0.5,-0.37,0.37,-0.5,1);
116  glMatrixMode(GL_MODELVIEW);
117  glPushMatrix();
118  glLoadIdentity();
119  glTranslated(posx, posy - 0.03 * (1.0 - scale), -0.0f);
120 
121  glColor4d(0.0f,0.0f,1.0f,0.3f);
122 
123  glBegin(GL_POLYGON);
124  glVertex3d( -0.2 - 0.2*scale, -(0.025 + 0.025*scale), 0.1);
125  glVertex3d(  0.2 + 0.2*scale, -(0.025 + 0.025*scale), 0.1);
126  glVertex3d(  0.2 + 0.2*scale,  (0.01 + 0.04*scale), 0.1);
127  glVertex3d( -0.2 - 0.2*scale,  (0.01 + 0.04*scale), 0.1);
128  glEnd();
129 
130  glColor4d(0.0f,0.0f,1.0f,0.2f);
131  glBegin(GL_POLYGON);
132  glVertex3d( -0.2 -0.2*scale, -(0.025 + 0.025*scale), 0.1);
133  glVertex3d( (-0.2+spd*0.4) + (-0.2+spd*0.4)*scale, -(0.025 + 0.025*scale), 0.1);
134  glVertex3d( (-0.2+spd*0.4) + (-0.2+spd*0.4)*scale,  (0.01 + 0.04*scale), 0.1);
135  glVertex3d( -0.2 -0.2*scale,  (0.01 + 0.04*scale), 0.1);
136  glEnd();
137 
138  glEnable(GL_DEPTH_TEST);
139  glDisable(GL_BLEND);
140  glEnable(GL_LIGHTING);
141  glEnable(GL_FOG);
142  glMatrixMode(GL_PROJECTION);
143  glPopMatrix();
144  glMatrixMode(GL_MODELVIEW);
145  glPopMatrix();
146  }
147 
paint_spin(double scale,double posx,double posy)148 void paint_spin( double scale, double posx, double posy )
149  {
150  float rad_outer=0.3;
151  double angle;
152  float MatDifWhite[] = {1.0,1.0,1.0,0.75};
153 
154  /* falls Textures ausgeschaltet muss die Spinkugel explizit
155     wei� sein, ansonsten hat sie die gleiche Farbe wie die
156     "next"-Kugel */
157  glMaterialfv(GL_FRONT, GL_DIFFUSE, MatDifWhite);
158 
159  glDisable(GL_FOG);
160  glEnable(GL_BLEND);
161  glDisable(GL_LIGHT1);
162  glDisable(GL_LIGHT2);
163  glEnable(GL_LIGHT3);
164 
165  glMatrixMode(GL_PROJECTION);
166  glPushMatrix();
167  glLoadIdentity();
168  glOrtho(-0.5,0.5,-0.4,0.4,1.0,0);
169 
170  glMatrixMode(GL_MODELVIEW);
171  glPushMatrix();
172  glLoadIdentity();
173  glTranslated(posx, posy - 0.03 * (1.0 - scale) + 0.012, -1.0) ;
174 
175  angle = sqrt( k[WHITE].e.x*90.0*k[WHITE].e.x*90.0 +
176 	       k[WHITE].e.y*90.0*k[WHITE].e.y*90.0 +
177 	       k[WHITE].e.z*90.0*k[WHITE].e.z*90.0 );
178  glRotated(angle, k[WHITE].e.y, k[WHITE].e.z, k[WHITE].e.x  );
179 
180  glMultMatrixd(k[WHITE].mrot);
181 
182  glEnable(GL_TEXTURE_2D);
183  glBindTexture(GL_TEXTURE_2D, texture[0]); /* Wei�e Kugel */
184  if( scale <= 0.1 ) icosphere(ico320, 320, rad_outer*scale);
185  else icosphere(ico5120, 5120, rad_outer*scale);
186 
187  glDisable(GL_TEXTURE_2D);
188 
189  glMatrixMode(GL_PROJECTION);
190  glPopMatrix();
191  glMatrixMode(GL_MODELVIEW);
192  glPopMatrix();
193 
194  glEnable(GL_DEPTH_TEST);
195  glDisable(GL_LIGHT3);
196  glEnable(GL_LIGHT1);
197  glEnable(GL_LIGHT2);
198  glDisable(GL_BLEND);
199  glEnable(GL_FOG);
200  }
201 
test_spin(void)202 void test_spin( void )
203  { /* Mouse-Abfrage f�r das Setzen des lokalen Spins... */
204  int oldx, oldy, i, ende=0;
205  Uint8 *keys;
206  double sz, sp, dummy;
207  struct timeval tp_start,tp_cur;
208  double time_cur, time_start;
209  SDL_GetMouseState(&oldx, &oldy);
210  for( i=10;i>=1;i-- )
211   {
212   gettimeofday(&tp_start,NULL);
213   time_start = tp_start.tv_sec * 1000000 + tp_start.tv_usec;
214   glFogf(GL_FOG_DENSITY, 1.0-i/(100.0/5.0));
215   gl_plotall(-1);
216   paint_spin( 1.0/(double)i, 0.5 - 0.5 / (double)i, 0.4 - 0.4/(double)i );
217   speed(spd, 1.0/10.0, 0.09, 0.36);
218   glPrintCentered(0.85*768,  "set spin", 0, 1.0, 1.0, 1.0, 1.0,4.0);
219   msg("move mouse to change spin. release middle button to leave...");
220   SDL_GL_SwapBuffers();
221   gettimeofday(&tp_cur,NULL);
222   time_cur = tp_cur.tv_sec * 1000000 + tp_cur.tv_usec;
223   if( time_cur - time_start < 10000 ) SDL_Delay(10+(time_cur - time_start)/1000);
224   }
225  keys=SDL_GetKeyState(NULL);
226  if( SDL_GetMouseState(&oldx, &oldy) & SDL_BUTTON(2) || keys[SDLK_e] )
227   {
228   do
229    {
230    do
231     {
232     while( SDL_PollEvent(&event) );
233     SDL_WaitEvent(&event);
234     }
235    while( event.type != SDL_MOUSEMOTION && event.type != SDL_KEYUP &&
236 	  (event.type != SDL_MOUSEBUTTONUP) &&
237 	  (event.type != SDL_MOUSEBUTTONDOWN) );
238    keys=SDL_GetKeyState(NULL);
239    if( event.type == SDL_MOUSEMOTION )
240     {
241     /* sollte vielleicht umgerechnet werden in einen Winkel !!! !!! !!! ??? */
242     sz = (event.motion.x - oldx)/50.0;
243     sp = (event.motion.y - oldy)/50.0;
244     SDL_WarpMouse( oldx, oldy );
245     dummy = sqrt( (k[WHITE].e.y+sp)*(k[WHITE].e.y+sp) + (k[WHITE].e.z+sz)*(k[WHITE].e.z+sz) );
246     if( dummy < 1.0 ) dummy = 1.0;
247     k[WHITE].e.x = 0.0;                        /* wird in translate_spin() entsprechend der Zielrichtung angepasst */
248     k[WHITE].e.y = (k[WHITE].e.y+sp) / dummy;
249     k[WHITE].e.z = (k[WHITE].e.z+sz) / dummy;
250     gl_plotall(-1);
251     paint_spin( 1.0, 0.0, 0.0 );
252     speed(spd, 1.0/10.0, 0.09, 0.36);
253     glPrintCentered(0.85*768,  "set spin", 0, 1.0, 1.0, 1.0, 1.0,4.0);
254     msg("move mouse to change spin. release middle button to leave...");
255     SDL_GL_SwapBuffers();
256     }
257    else {mmouse=1;}
258    if( !(SDL_GetMouseState(NULL,NULL) & SDL_BUTTON(2)) && !keys[SDLK_e] ) ende = 1;
259    }
260   while( !ende && !(event.type == SDL_KEYDOWN) &&
261 	 !((event.button.button == SDL_BUTTON_MIDDLE) &&
262 	   (event.type == SDL_MOUSEBUTTONUP)) &&
263 	 !(mmouse && ((event.type == SDL_MOUSEBUTTONDOWN) ||
264 		      (event.type == SDL_MOUSEBUTTONUP))) );
265   }
266  for( i=1;i<=10;i++ )
267   {
268   gettimeofday(&tp_start,NULL);
269   time_start = tp_start.tv_sec * 1000000 + tp_start.tv_usec;
270   gl_plotall(-1);
271   paint_spin( 1.0/(double)i, 0.5 - 0.5 / (double)i, 0.4 - 0.4/(double)i );
272   speed(spd, 1.0/10.0, 0.09, 0.36);
273   msg(current_message);
274   msg2(current_message2);
275   glFogf(GL_FOG_DENSITY, 1.0-i/20.0);
276   SDL_GL_SwapBuffers();
277   gettimeofday(&tp_cur,NULL);
278   time_cur = tp_cur.tv_sec * 1000000 + tp_cur.tv_usec;
279   if( time_cur - time_start < 10000 ) SDL_Delay(10+(time_cur - time_start)/1000);
280   }
281  glFogf(GL_FOG_DENSITY, 0.5);
282  PAINT_ALL;
283  mmouse = 0;
284  }
285 
wait_for_click(void)286 void wait_for_click( void )
287  /* wartet auf Mouse-Click oder Tasten-Druck */
288  {
289  SDL_Event event;
290  do
291   { SDL_WaitEvent(&event); }
292  while( ( event.type != SDL_KEYDOWN) && (event.type != SDL_MOUSEBUTTONUP) &&
293 	(event.type != SDL_QUIT) );
294  if( (event.type == SDL_KEYDOWN) || (event.type == SDL_QUIT) )
295   {
296   Uint8 *keystate = SDL_GetKeyState(NULL);
297   if( (keystate[SDLK_ESCAPE]) || (event.type == SDL_QUIT) ) stop_it();
298   }
299  }
300 
wait_for_click_up(void)301 void wait_for_click_up( void )
302  /* wartet auf Mouse-Click oder Tasten-Druck */
303  {
304  SDL_Event event;
305  do
306   { SDL_WaitEvent(&event); }
307  while( ( event.type != SDL_KEYUP) && (event.type != SDL_MOUSEBUTTONUP) &&
308 	(event.type != SDL_QUIT) );
309  if( (event.type == SDL_KEYUP) || (event.type == SDL_QUIT) )
310   {
311   Uint8 *keystate = SDL_GetKeyState(NULL);
312   if( (keystate[SDLK_ESCAPE]) || (event.type == SDL_QUIT) ) stop_it();
313   }
314  }
315 
wink(double a)316 void wink( double a ) /* Winkel zwischen Queue und Tisch darstellen */
317  {  /* K�nnte mal einen dickeren Queue bekommen !!! !!! !!!*/
318  /*  double b = a*M_PI/180.0; */
319  /*  int posx = 0.5, posy=0.3; */
320  /*  GrCircleArc(posx, posy, 6*PIXELRADIUS+1, 270, 362, GR_ARC_STYLE_OPEN, 9); */
321  /*  GrFilledCircleArc(posx, posy, 6*PIXELRADIUS, 270, 362,  */
322  /* 		   GR_ARC_STYLE_CLOSE2, COL_WHITE); */
323  /*  GrFilledCircle(posx+6.5*PIXELRADIUS*cos(oldalph), posy-6.5*PIXELRADIUS*sin(oldalph), */
324  /* 		PIXELRADIUS/2,0); */
325  /*  GrFilledCircle(posx+6.5*PIXELRADIUS*cos(b), posy-6.5*PIXELRADIUS*sin(oldalph=b), */
326  /* 		PIXELRADIUS/2,16); */
327  /*  SDL_UpdateRect(display,posx-1-PIXELRADIUS,posy-7.5*(PIXELRADIUS+1)-1, */
328  /* 		12*(PIXELRADIUS+2)+2,7.5*(PIXELRADIUS+2)+2); */
329  }
330 
err(char * out)331 void err( char *out )
332  { /* Ausgabe der normalen Texte w�hrend des Spiels */
333  glPrintCentered(768/2,out,0,1.0,0.5,0.5,1.0,1.45);
334  SDL_GL_SwapBuffers();
335  }
336 
err2(char * out,char * out2)337 void err2( char *out, char *out2 )
338  { /* Ausgabe von z.B. Free- oder Extra-Ball ... */
339  strcpy(err2_msg1, out);
340  strcpy(err2_msg2, out2);
341  err2_endtime = timer() + 3000; /* Nachricht wird 2 Sekunden lang angezeigt */
342  }
343 
foul(char * out,int time)344 void foul( char *out, int time )
345  { /* Ausgabe von z.B. Free- oder Extra-Ball ... */
346  strcpy(foul_msg, out);
347  foul_endtime = timer() + time; /* Nachricht wird time/1000 Sekunden lang angezeigt */
348  }
349 
debug(char * out)350 void debug( char *out )
351  { /* Ausgabe der Kommentare beim Computer-Spieler */
352  /*  char o[80]; */
353  /*  sprintf(o,"%s",out); */
354  /*  GrDrawString(out, strlen(out), 0, 35, TEXTCOL ); */
355  /*  SDL_Flip(display); */
356  }
357 
mouse_on(void)358 void mouse_on( void )
359  { SDL_ShowCursor(1); }
360 
mouse_off(void)361 void mouse_off( void )
362  { SDL_ShowCursor(0); }
363 
set_white_ball(void)364 void set_white_ball( void )
365  { /* Wei�e Kugel am Anfang oder nach Foul neu positionieren */
366  int i, j, okx,oky;
367  double old, old2, motionx,motiony, dummy;
368  int mousex, mousey;
369  struct vect v;
370  k[WHITE].p.z = RADIUS;
371  k[WHITE].v.z = 0.0;
372  k[WHITE].p.x = k[WHITE].p.y = 0.10;
373  k[WHITE].stat = (ONTABLE|MOVING);
374  if( (c_player == -1) || (cur != c_player ) )
375   {
376   k[WHITE].e.x = k[WHITE].e.y = k[WHITE].e.z = 0.0;
377   old2 = 0.25;
378   i = 225;
379   do
380    {
381    old = ((double)i) / 1000.0;
382    okx = 1;
383    for(j=0;j<BALLS;j++) /* Suche nach freiem Platz auf dem Tisch */
384     if( DIFF2( old-k[j].p.x, old2-k[j].p.y ) < 5.0*PIXELRADIUS*PIXELRADIUS )
385      {okx=0; break;}
386    }
387   while( !okx && (--i>50) );
388   k[WHITE].p.x = old; k[WHITE].p.y = old2;
389   gl_move_table(0.0f,0.0f,0.0f, 0.0f,0.0f,-0.985f, new_game ? 15.0 : 25.0f, 0, 0, 0);
390   do
391    {
392    gl_plotall(-1);
393    msg("move mouse to change the position of the cue-ball");
394    msg2("press left mouse button to set the position of the cue ball");
395    SDL_GL_SwapBuffers();
396    while( SDL_PollEvent(&event) );
397    SDL_WaitEvent( &event);
398    okx=oky=1;
399    if( event.type == SDL_MOUSEMOTION )
400     {
401     SDL_GetMouseState(&mousex, &mousey);
402     /*     SDL_WarpMouse(SCREENRESX/2, SCREENRESY/2 ); */
403     motionx = (double)(mousex-SCREENRESX/2) / (double)SCREENRESX;
404     motiony = (double)(mousey-SCREENRESY/2) / (double)SCREENRESX;
405     k[WHITE].p.x += motionx * cos(angz * M_PI/180.0) - motiony * sin(angz * M_PI/180.0);
406     k[WHITE].p.y -= motionx * sin(angz * M_PI/180.0) + motiony * cos(angz * M_PI/180.0);
407     for(i=0;i<BALLS-1;i++)
408      {
409      if( ABST(k[i].p,k[WHITE].p) < RADIUS*RADIUS*4.0 )
410       {
411       v.x = k[i].p.x - k[WHITE].p.x;
412       v.y = k[i].p.y - k[WHITE].p.y;
413       dummy = BETR(v);
414       v.x /= dummy;
415       v.y /= dummy;
416       k[WHITE].p.y = k[i].p.y - 2*RADIUS * v.y;
417       k[WHITE].p.y = k[i].p.y - 2*RADIUS * v.y;
418       }
419      }
420     if( k[WHITE].p.x > 0.25 ) k[WHITE].p.x = 0.25;
421     if( k[WHITE].p.y > 0.5 - RADIUS ) k[WHITE].p.y = 0.5-RADIUS;
422     if( k[WHITE].p.x < RADIUS ) k[WHITE].p.x = RADIUS;
423     if( k[WHITE].p.y < RADIUS ) k[WHITE].p.y = RADIUS;
424     SDL_WarpMouse(SCREENRESX/2, SCREENRESY/2 );
425     }
426    }
427   while( event.type != SDL_MOUSEBUTTONUP && event.type != SDL_KEYDOWN && event.type != SDL_QUIT );
428   if( (event.type == SDL_KEYDOWN) || (event.type == SDL_QUIT) )
429    {
430    Uint8 *keystate = SDL_GetKeyState(NULL);
431    if( (keystate[SDLK_ESCAPE]) || (event.type == SDL_QUIT) ) stop_it();
432    }
433   }
434  else /* !!! !!! !!! !!! !!! !!! VERBESSERN! */
435   {
436   /* Computer kann Wei�e legen ... */
437   k[WHITE].e.x = k[WHITE].e.y = k[WHITE].e.z = 0.0;
438   old2 = 0.25;
439   i = 250;
440   do
441    {
442    old = ((double)i) / 1000.0;
443    okx = 1;
444    for(j=0;j<WHITE;j++) /* Suche nach freiem Platz auf dem Tisch */
445     if( DIFF2( old-k[j].p.x, old2-k[j].p.y ) < 5.0*PIXELRADIUS*PIXELRADIUS )
446      {okx=0; break;}
447    }
448   while( !okx && (--i>50) );
449   k[WHITE].p.x = old; k[WHITE].p.y = old2;
450   gl_plotall(1);
451   }
452  new_game = 0;
453  }
454 
calc_player_v(void)455 void calc_player_v( void )
456  {
457  struct vect3 v;
458  double dummy;
459  v.x = target.x - k[WHITE].p.x;
460  v.y = target.y - k[WHITE].p.y;
461  if( fabs(v.x) > 1e-10 || fabs(v.y) > 1e-10 )
462   {
463   v.x /= (dummy = sqrt(v.x*v.x+v.y*v.y));
464   v.y /= dummy;
465   }
466  k[WHITE].e.x *= spd;
467  k[WHITE].e.y *= spd;
468  k[WHITE].e.z  *= 1.0; /* *spd!!! ??*/
469  k[WHITE].v.x = spd * SPEED_FACTOR * v.x / DIFFX;
470  k[WHITE].v.y = spd * SPEED_FACTOR * v.y / DIFFX;
471  }
472 
set_player_power(void)473 void set_player_power( void )
474  {
475  int oldx, oldy, i, ende = 0;
476  struct timeval tp_start,tp_cur;
477  double time_cur, time_start;
478  for( i=10;i>0;i-- )
479  {
480   gettimeofday(&tp_start,NULL);
481   time_start = tp_start.tv_sec * 1000000 + tp_start.tv_usec;
482   glFogf(GL_FOG_DENSITY, 1.0-i/(100.0/5.0));
483   gl_plotall(-1);
484   paint_spin( 1.0/10.0, 0.45, 0.36 );
485   speed(spd, 1.0/(double)i, 0.1 - 0.1/(double)i, 0.4 - 0.4/(double)i );
486   glPrintCentered(0.6*768,  "set speed", 0, 1.0, 1.0, 1.0, 1.0,4.0);
487   msg("move mouse to change initial speed, release button to leave...");
488   SDL_GL_SwapBuffers();
489   gettimeofday(&tp_cur,NULL);
490   time_cur = tp_cur.tv_sec * 1000000 + tp_cur.tv_usec;
491   if( time_cur - time_start < 10000 ) SDL_Delay(10+(time_cur - time_start)/1000);
492   }
493  if( SDL_GetMouseState(&oldx, &oldy) & SDL_BUTTON(3) )
494   {
495   do
496    {
497    while( SDL_PollEvent(&event) );
498    SDL_WaitEvent(&event);
499    if( (event.type == SDL_MOUSEMOTION ) )
500     {
501     if( (event.button.x != oldx) || (event.button.y != oldy) )
502      {
503      spd += 1.0/500.0 * (double)(event.button.x - oldx);
504      spd += 1.0/500.0 * (double)(-event.button.y + oldy);
505      SDL_WarpMouse(oldx, oldy);
506      if( spd > 1.0 ) spd = 1.0;
507      if( spd < 0.0 ) spd = 0.0;
508      gl_plotall(-1);
509      paint_spin( 1.0/10.0, 0.45, 0.36 );
510      speed(spd, 1.0, 0.0, 0.0 );
511      glPrintCentered(0.6*768,  "set speed", 0, 1.0, 1.0, 1.0, 1.0,4.0);
512      msg("move mouse to change initial speed, release button to leave...");
513      SDL_GL_SwapBuffers();
514      }
515     }
516    if( !(SDL_GetMouseState(NULL,NULL) & SDL_BUTTON(3)) ) ende = 1;
517    }
518   while( !ende && (event.type != SDL_MOUSEBUTTONUP) );
519   }
520  for( i=1;i<=10;i++ )
521   {
522   gettimeofday(&tp_start,NULL);
523   time_start = tp_start.tv_sec * 1000000 + tp_start.tv_usec;
524   glFogf(GL_FOG_DENSITY, 1.0-i/(100.0/5.0));
525   gl_plotall(-1);
526   paint_spin( 1.0/10.0, 0.45, 0.36 );
527   speed(spd, 1.0/(double)i, 0.1 - 0.1/(double)i, 0.4 - 0.4/(double)i );
528   msg(current_message);
529   msg2(current_message2);
530   SDL_GL_SwapBuffers();
531   gettimeofday(&tp_cur,NULL);
532   time_cur = tp_cur.tv_sec * 1000000 + tp_cur.tv_usec;
533   if( time_cur - time_start < 10000 ) SDL_Delay(10+(time_cur - time_start)/1000);
534   }
535  glFogf(GL_FOG_DENSITY, 0.5);
536  PAINT_ALL;
537  }
538 
set_player_spin(void)539 void set_player_spin( void )
540  {
541  int oldx, oldy;
542  double oldalph_local;
543  oldalph=alph;
544  msg("move mouse to change spin, press right button to change angle");
545  test_spin();
546  SDL_GetMouseState(&oldx, &oldy);
547  return;
548  if( (event.type == SDL_MOUSEBUTTONDOWN) &&
549      ((event.button.button == SDL_BUTTON_MIDDLE) ||
550       (event.button.button == SDL_BUTTON_RIGHT)))
551   {
552   msg("move mouse to change angle between queue an table");
553   do
554    {
555    oldalph_local = alph;
556    while( SDL_PollEvent(&event) );
557    SDL_WaitEvent( &event );
558    if( event.type == GR_M_MOTION )
559     {
560     if( (oldx-event.motion.x) || (oldy-event.motion.y) )
561      {
562      alph += 0.1 * (oldx - event.motion.x + oldy - event.motion.y);
563      SDL_WarpMouse( oldx, oldy );
564      if( alph > 90.0 ) alph = 90.0;
565      if( alph < 0.0 ) alph = 0.0;
566      wink( alph );
567      }
568     }
569    }
570   while( !(event.type == GR_M_KEYPRESS) &&
571 	 !( (event.type == SDL_MOUSEBUTTONUP) &&
572 	    ((event.button.button == SDL_BUTTON_MIDDLE) ||
573 	     (event.button.button == SDL_BUTTON_RIGHT))) );
574   }
575  MSG2;
576  }
577 
set_test_power(void)578 void set_test_power( void )
579  { /* Test-Prozedur, berechnet Geschw., die die Weisse haben mu�, um zur akt.
580       Maus-Position zu rollen */
581  struct vect3 v;
582  debug("press button, to play white to cur.pos. !");
583  do
584   { SDL_WaitEvent( &event ); }
585  while( !(event.type == GR_M_BUTTON_DOWN) );
586  v.x = (event.button.x-LEFT)/DIFFX - k[WHITE].p.x;
587  v.y = (event.button.y-UP)/DIFFX  - k[WHITE].p.y;
588  set_c_speed( SET_V(BETR( v ), 0), v );
589  }
590 
set_test_power2(void)591 int set_test_power2( void )
592  { /* Test-Prozedur, berechnet die Geschw., die die Weisse ben�tigt, um ein
593       best. Kugel in ein best. Loch zu schie�en; ohne jeden Test, ob andere
594       Kugeln im Weg liegen ... */
595  int i, puffer_ball;
596  struct vect3 v1, v2, v3, v4;
597  double dum1, dummy;
598  int dum2;
599  char outtext[80];
600  debug("ball ?");
601  do
602   { SDL_WaitEvent( &event ); }
603  while( !(event.type == GR_M_BUTTON_DOWN) );
604  v1.x = (event.button.x-LEFT) / DIFFX;
605  v1.y = (event.button.y-UP) / DIFFX;
606  dum1 = dum2 = 4;
607  for( i=0;i<WHITE;i++ )
608   if( DIFF( v1.x-k[i].p.x, v1.y-k[i].p.y ) < dum1 )
609    { dum1 = DIFF( v1.x-k[i].p.x, v1.y-k[i].p.y ); dum2 = i; }
610  v1.x = k[dum2].p.x; v1.y = k[dum2].p.y;
611  puffer_ball = dum2;
612  sprintf(outtext,"ball no: %d, hole ?", dum2 );
613  debug(outtext);
614  do
615   { SDL_WaitEvent( &event ); }
616  while( !(event.type == GR_M_BUTTON_DOWN) );
617  v2.x = (event.button.x-LEFT) / DIFFX;
618  v2.y = (event.button.y-UP) / DIFFX;
619  dum1 = 1000.0; dum2 = 0;
620  for( i=0;i<6;i++ )
621   if( DIFF( v2.x-posl[i].m.x, v2.y-posl[i].m.y ) < dum1 )
622    { dum1 = DIFF( v2.x-posl[i].m.x, v2.y-posl[i].m.y ); dum2 = i; }
623  sprintf(outtext,"hole: %d",dum2);
624  debug(outtext);
625  v2.x = posl[dum2].m.x; v2.y = posl[dum2].m.y;
626  v3 = calc_tp( v1, v2 );
627  dummy = sqrt( DIFF( k[WHITE].p.x-v3.x, k[WHITE].p.y-v3.y ));
628  /* geht so nat�rlich noch nicht wieder !!! */
629  v4.x = v2.x - v3.x; v4.y = v2.y - v3.y;
630  v1.x = v3.x - k[WHITE].p.x; v1.y = v3.y - k[WHITE].p.y;
631  if( COSV( v1, v4 ) > 0.0 )
632   {
633   v2.x = posl[dum2].p.x - posl[dum2].m.x;
634   v2.y = posl[dum2].p.y - posl[dum2].m.y;
635   v3.x = posl[dum2].m.x - k[puffer_ball].p.x;
636   v3.y = posl[dum2].m.y - k[puffer_ball].p.y;
637   if( ((dum2 == 2 || dum2 == 5) && COSV( v2, v3 ) > COS(e_winkel))
638       || (dum2 != 2 && dum2 != 5) )
639    {
640    if( (dum1=COSV( v1, v4 )) ) dummy += BETR(v4) / (dum1 * dum1);
641    else dummy = 1000000.0; /* =infinity */
642    set_c_speed( SET_V(dummy*sqrt(1.0/ROLL), 0), v1 );
643    return 1;
644    }
645   else
646    {
647    char out[80];
648    sprintf(out,"can't play this..(ew:%g/ pw:%g)", e_winkel,
649 	   180.0/M_PI * acos(COSV( v2, v3 )) );
650    debug(out);
651    return 0;
652    }
653   }
654  debug("can't play this...");
655  return 0;
656  }
657 
gl_plot_target(void)658 void gl_plot_target( void )
659  {
660  float MatDif[] = {0.5f, 0.5f, 1.0f, 0.3f};
661  float MatAmb[] = {0.1f, 0.1f, 0.4f, 0.1f};
662  float MatSpc[] = {0.0f, 0.0f, 0.5f, 1.0f};
663  float MatEm[] = {0.9f, 0.0f, 0.9f, 0.5f};
664  float MatZero[] = {0.0f, 0.0f, 0.0f, 0.0f};
665  GLfloat LightEmission[] = { 1.0f, 0.5f, 1.0f, 1.0f };
666 
667  glPushMatrix();
668  glLightfv(GL_LIGHT1, GL_EMISSION, LightEmission);
669  glMaterialfv(GL_FRONT, GL_DIFFUSE, MatDif);
670  glMaterialfv(GL_FRONT, GL_AMBIENT, MatAmb);
671  glMaterialfv(GL_FRONT, GL_SPECULAR, MatSpc);
672  glMaterialfv(GL_FRONT, GL_EMISSION, MatEm);
673 
674  glTranslatef((double)target.x-0.5f, (double)target.y-0.25f, RADIUS);
675 
676  glEnable(GL_BLEND);
677  glColor4d(0.2,0.2,1.0,0.3);
678 
679  icosphere(ico320, 320, RADIUS);
680  glDisable(GL_BLEND);
681 
682  glMaterialfv(GL_FRONT, GL_EMISSION, MatZero);
683  glLightfv(GL_LIGHT1, GL_EMISSION, MatZero);
684  glPopMatrix();
685  }
686 
newstartpos(double sx,double sy,double sz,int key,int invoke,int button)687 void newstartpos(  double sx, double sy , double sz, int key, int invoke, int button )
688  {
689  Uint8 *keys;
690  int ende=0;
691  do
692   {
693   startx += sx;
694   starty += sy;
695   startz += sz;
696   gl_plotall(-1);
697   gl_plot_target();
698   SDL_GL_SwapBuffers();
699   SDL_Delay(20);
700   SDL_PollEvent(NULL);
701   keys = SDL_GetKeyState(NULL);
702   if( keys[key] != SDL_PRESSED && invoke == 2 ) ende = 1;
703   if( !(SDL_GetMouseState(NULL,NULL) & SDL_BUTTON(button)) && invoke == 1 ) ende = 1;
704   }
705  while( !ende );
706  }
707 
newtranspos(double sx,double sy,double sz,int key,int invoke)708 void newtranspos(  double sx, double sy , double sz, int key, int invoke )
709  {
710  Uint8 *keys;
711  int ende=0;
712  do
713   {
714   transx += sx;
715   transy += sy;
716   transz += sz;
717   gl_plotall(1);
718   SDL_Delay(20);
719   SDL_PollEvent(NULL);
720   keys = SDL_GetKeyState(NULL);
721   if( keys[key] != SDL_PRESSED && invoke == 2 ) ende = 1;
722   if( !(SDL_GetMouseState(NULL,NULL) & SDL_BUTTON(1)) && invoke == 1 ) ende = 1;
723   }
724  while( !ende );
725  }
726 
special_target_mode(void)727 void special_target_mode(void)
728  {
729  struct vect v,p;
730  v.x = target.x - k[WHITE].p.x;
731  v.y = target.y - k[WHITE].p.y;
732  p.x = 1.0;
733  p.y = 0.0;
734  newstartx = 0.0;
735  newstarty = 0.0;
736  newstartz = -0.2;
737  newangz = 90.0 + (v.y < 0 ? 1 : -1) * 180.0/M_PI * acos(COSV(p,v));
738  newangx = -70.0;
739  newangy = 0.0;
740  newtransx = -(k[WHITE].p.x-0.5);
741  newtransy = -(k[WHITE].p.y-0.25);
742  newtransz = -6*RADIUS;
743  }
744 
745 /* berechnet den Schwerpunkt der Kugeln, die der aktuelle Spieler
746    zu spielen hat und setzt den Target-Ball dorthin, �berpr�ft
747    daraufhin, ob dort Platz ist und verschiebt den Target Ball
748    so lange bis es "passt" oder eine gewisse Anzahl vo
749    Verschiebungszyklen abgelaufen ist */
calc_target_pos(int cur)750 void calc_target_pos(int cur)
751  {
752  int i, count=0, ok;
753  double dummy;
754  struct vect a;
755  target.x = 0;
756  target.y = 0;
757 
758  switch( ply[cur].col )
759   {
760   case COL_BLACK:
761    target.x = k[BLACK].p.x;
762    target.y = k[BLACK].p.y;
763    break;
764   case COL_RED:
765    for(i=0;i<BALLS;i++)
766     {
767     if( (k[i].stat & ONTABLE) && (k[i].col == COL_RED) )
768      {
769      count ++;
770      target.x += k[i].p.x;
771      target.y += k[i].p.y;
772      }
773     }
774    target.x /= count;
775    target.y /= count;
776    break;
777   case COL_YELLOW:
778    for(i=0;i<BALLS;i++)
779     {
780     if( (k[i].stat & ONTABLE) && (k[i].col == COL_YELLOW) )
781      {
782      count ++;
783      target.x += k[i].p.x;
784      target.y += k[i].p.y;
785      }
786     }
787    target.x /= count;
788    target.y /= count;
789    break;
790   default:
791    for(i=0;i<BALLS;i++)
792     {
793     if( k[i].stat & ONTABLE )
794      {
795      count ++;
796      target.x += k[i].p.x;
797      target.y += k[i].p.y;
798      }
799     }
800    target.x /= (double)(count-1);
801    target.y /= (double)(count-1);
802    break;
803   }
804 
805  do
806   {
807   ok=1;
808   for(i=0;i<=BALLS;i++)
809    {
810    a.x = k[i].p.x - target.x;
811    a.y = k[i].p.y - target.y;
812    if( SKALP(a,a) < 4.0*RADIUS*RADIUS )
813     {
814     a.x = k[WHITE].p.x - target.x;
815     a.y = k[WHITE].p.y - target.y;
816     dummy = BETR(a);
817     a.x /= dummy;
818     a.y /= dummy;
819     target.x += a.x * 2.0*RADIUS;
820     target.y += a.y * 2.0*RADIUS;
821     ok=0; break;
822     }
823    }
824   }
825  while( !ok && ++counter < 30 );
826  }
827 
menu(void)828 int menu( void )
829  {
830  int i, ok=0, ret_wert=0;
831  double motionx, motiony, dummy;
832  int mousex, mousey;
833  char out[255], out2[128];
834  struct vect v;
835  gamemode &= (0xffff ^ PLAY_MODE); /* ungeschickt, eigentlich sowas wie MAXINT */
836  gamemode &= (0xffff ^ FREELOOK_MODE); /* ungeschickt, eigentlich sowas wie MAXINT */
837  wink( alph = 0.0 );
838  for( i=0;i<BALLS;i++) /* alle Kugeln neu initialisieren */
839   {
840   k[i].v.x = k[i].v.y = 0;
841   k[i].e.x = k[i].e.y = k[i].e.z = 0.0;
842   }
843  clear_rotation_matrix(WHITE); /* damit der SPIN-BALL rechts oben nicht verdreht ist... */
844 /*  k[WHITE].rot.x = 0 -0*angx; */
845 /*  k[WHITE].rot.y = -90.0+0*angy; */
846 /*  k[WHITE].rot.z = 0 +angz; */
847  k[WHITE].stat ^= GL_LISTED_NOT_MOVING; /* damit der Treffpunkt des Queues neu gemalt wird... */
848 /*  calc_rotation_inkl_z(WHITE); */
849 
850  if( new_game ) title_screen();
851  if( k[WHITE].stat & DELETED ) set_white_ball(); /* Wei�e neu setzen */
852  if( cur == c_player ) { computer_stoss(); return ret_wert; }
853  ok = 0;
854  MSG2;
855  if( simulation_flag ) {target.x = undo_target.x; target.y = undo_target.y;}
856  else calc_target_pos(cur);
857  simulation_flag=0;
858 
859  if( gamemode == TARGET_MODE )
860   gl_move_table(0.0f,0.0f,0.0f, 0.0f,0.0f,-0.985f, 10.0f, 0,0,0);
861  else if( gamemode == SPECIAL_TARGET_MODE )
862   {
863   special_target_mode();
864   gl_move_table(newangx,newangy,newangz,newstartx,newstarty,newstartz, 20.0f, newtransx, newtransy, newtransz);
865   }
866 
867  PAINT_ALL;
868  mouse_off();
869  SDL_WarpMouse(SCREENRESX/2, SCREENRESY/2 );
870  do
871   {
872   do
873    {
874    while( SDL_PollEvent(&event) ); /* versteht kein Mensch... */
875    SDL_WaitEvent(&event);
876    }
877   while( !( (event.type == SDL_KEYDOWN)       || (event.type == SDL_MOUSEBUTTONDOWN) ||
878 	    (event.type == SDL_MOUSEBUTTONUP) || (event.type == SDL_QUIT)          ||
879 	    (event.type == SDL_MOUSEMOTION)   || (event.type == SDL_SYSWMEVENT)  ||
880 	    (event.type == 1) || (event.type == 17) ) );
881   switch( event.type )
882    {
883    case 1: case 17: PAINT_ALL; break; /* Window-Refresh n�tig */
884    case SDL_MOUSEMOTION:
885     {
886     if( !(gamemode & FREELOOK_MODE) )
887      {
888      SDL_GetMouseState(&mousex, &mousey);
889      SDL_WarpMouse(SCREENRESX/2, SCREENRESY/2 );
890      motionx = (double)(mousex-SCREENRESX/2) / (double)SCREENRESX;
891      motiony = (double)(mousey-SCREENRESY/2) / (double)SCREENRESX;
892      target.x += motionx * cos(angz * M_PI/180.0) -motiony * sin(angz * M_PI/180.0);
893      target.y -= motionx * sin(angz * M_PI/180.0) + motiony * cos(angz * M_PI/180.0);
894      for(i=0;i<BALLS;i++)
895       {
896       if( ABST(k[i].p,target) < RADIUS*RADIUS*4.0 )  /* funktioniert meistens, sieht ganz lustig aus ;-) */
897        {
898        v.x = k[i].p.x - target.x;
899        v.y = k[i].p.y - target.y;
900        dummy = BETR(v);
901        v.x /= dummy;
902        v.y /= dummy;
903        target.x = k[i].p.x - 2*RADIUS * v.x;
904        target.y = k[i].p.y - 2*RADIUS * v.y;
905        }
906       }
907      if( target.x > 1.0 - RADIUS ) target.x = 1.0-RADIUS;
908      if( target.y > 0.5 - RADIUS ) target.y = 0.5-RADIUS;
909      if( target.x < RADIUS ) target.x = RADIUS;
910      if( target.y < RADIUS ) target.y = RADIUS;
911      /* Abfrage, ob target zu nahe an Kugel ist noch machen... */
912      SDL_WarpMouse(SCREENRESX/2, SCREENRESY/2 );
913      if( gamemode & SPECIAL_TARGET_MODE )
914       {
915       special_target_mode();
916       startx = newstartx;
917       starty = newstarty;
918       startz = newstartz;
919       angx = newangx;
920       angy = newangy;
921       angz = newangz;
922       transx = newtransx;
923       transy = newtransy;
924       transz = newtransz;
925       }
926      PAINT_ALL;
927      }
928     else if( gamemode & FREELOOK_MODE )
929      {
930      angz+=(double)event.motion.xrel;
931      angx+=(double)event.motion.yrel;
932      SDL_WarpMouse(SCREENRESX/2, SCREENRESY/2);
933      PAINT_ALL;
934      break;
935      }
936     }
937     break; /* �u�eres switch, Ende von event.type == MOUSE_MOTION */
938    case SDL_QUIT: ok = ret_wert = 1; stop_it(); break;
939    case SDL_MOUSEBUTTONDOWN: case SDL_MOUSEBUTTONUP:
940     {
941     switch(event.button.button)
942      {
943      case SDL_BUTTON_LEFT: /* Sto�: Geschw. berechnen */
944       switch(gamemode)
945        {
946        case FREELOOK_MODE: /* erstmal ;-) */
947        case SPECIAL_TARGET_MODE:
948        case TARGET_MODE:
949 	if( event.type == SDL_MOUSEBUTTONUP )   { calc_player_v(); ok = 1; gamemode |= PLAY_MODE; }
950 	else ok=0;
951 	break;
952        }
953       break;
954      case SDL_BUTTON_RIGHT:  /* Geschwindigkeits (Power)-Faktor verstellen */
955       if( event.type == SDL_MOUSEBUTTONDOWN ) set_player_power();
956       break;
957      case SDL_BUTTON_MIDDLE: /* Spin einstellen */
958       if( event.type == SDL_MOUSEBUTTONDOWN ) set_player_spin(); break;
959      case 4: alph = ((alph+=0.5) > 90 ? 90 : alph); wink( alph ); break;
960      case 5: alph = ((alph-=0.5) < 0 ? 0 : alph); wink( alph ); break;
961      }
962     }
963     break;
964    case SDL_KEYDOWN:
965     {
966     switch( event.key.keysym.sym )
967      {
968      case SDLK_SPACE:
969       gamemode ^= FREELOOK_MODE;
970       if( gamemode & FREELOOK_MODE )
971        {
972        sprintf(current_message, "free look mode - move mouse to change view, ...");
973        sprintf(current_message2,"F1: help; press SPACE to return to target mode, ...");
974        }
975       else if( gamemode & TARGET_MODE )
976        {
977        sprintf(current_message, "target mode - move mouse to change the position of the target ball");
978        sprintf(current_message2,"F1: help; left button: cue, right button speed, ...");
979        }
980       else if( gamemode & SPECIAL_TARGET_MODE )
981        {
982        sprintf(current_message, "special target mode; press w to toggle normal mode");
983        sprintf(current_message2,"F1: help; left button: cue, right button speed, ...");
984        }
985       PAINT_ALL;
986       break;
987      case SDLK_F9:
988       ball_env_map++;
989       if( ball_env_map > 2 ) ball_env_map = 0;
990       gl_init_lists();
991       PAINT_ALL;
992       switch(ball_env_map)
993        {
994        case 0:  sprintf(out2,"off"); break;
995        case 1:  sprintf(out2,"cube"); break;
996        case 2:  sprintf(out2,"sphere"); break;
997        }
998       sprintf(out,"ball environment mapping is set to %s\n",out2);
999       err(out);
1000       SDL_GL_SwapBuffers();
1001       break;
1002      case SDLK_F8:
1003       env_map = 1 - env_map;
1004       gl_init_lists();
1005       PAINT_ALL;
1006       sprintf(out,"environment mapping is set to %s\n",env_map == 0 ? "off" : "on");
1007       err(out);
1008       SDL_GL_SwapBuffers();
1009       break;
1010      case SDLK_F7:
1011       if( ++txt_detail > TEXTURE_HIGH ) txt_detail = TEXTURE_LOW;
1012       switch(txt_detail)
1013        {
1014        case TEXTURE_LOW:      sprintf(out2,"low"); break;
1015        case TEXTURE_HIGH:     sprintf(out2,"high"); break;
1016        }
1017       gl_init_lists();
1018       PAINT_ALL;
1019       sprintf(out,"texture detail level is set to %s\n",out2);
1020       err(out);
1021       SDL_GL_SwapBuffers();
1022       break;
1023      case SDLK_F6:
1024       if( (++shadows) > 3 ) shadows = 0;
1025       gl_init_lists();
1026       PAINT_ALL;
1027       switch(shadows)
1028        {
1029        case 0: sprintf(out2,"off"); break;
1030        case 1: sprintf(out2,"planar"); break;
1031        case 2: sprintf(out2,"stencil (alpha)"); break;
1032        case 3: sprintf(out2,"stencil (multi)"); break;
1033        }
1034       sprintf(out,"shadows set to %s\n",out2);
1035       err(out);
1036       SDL_GL_SwapBuffers();
1037       break;
1038      case SDLK_F5:
1039       if( ++geo_detail > DETAIL_VERYHIGH ) geo_detail = DETAIL_VERYLOW;
1040       switch(geo_detail)
1041        {
1042        case DETAIL_VERYLOW:  sprintf(out2,"very low");  txt_detail = TEXTURE_LOW;  break;
1043        case DETAIL_LOW:      sprintf(out2,"low");       txt_detail = TEXTURE_LOW;  break;
1044        case DETAIL_MED:      sprintf(out2,"medium");    txt_detail = TEXTURE_LOW;  break;
1045        case DETAIL_HIGH:     sprintf(out2,"high");      txt_detail = TEXTURE_HIGH; break;
1046        case DETAIL_VERYHIGH: sprintf(out2,"very high"); txt_detail = TEXTURE_HIGH; break;
1047        }
1048       gl_init_lists();
1049       PAINT_ALL;
1050       sprintf(out,"geometric detail level is set to %s\n",out2);
1051       err(out);
1052       SDL_GL_SwapBuffers();
1053       break;
1054      case SDLK_F3:
1055       display_floor_textures ^= 1;
1056       gl_init_lists();
1057       PAINT_ALL;
1058       sprintf(out,"display of floor texture is set to %s\n",display_floor_textures ? "on" : "off");
1059       err(out);
1060       SDL_GL_SwapBuffers();
1061       break;
1062      case SDLK_F4:
1063       display_textures ^= 1;
1064       gl_init_lists();
1065       PAINT_ALL;
1066       sprintf(out,"display textures is set to %s\n",display_textures ? "on" : "off");
1067       err(out);
1068       SDL_GL_SwapBuffers();
1069       break;
1070      case SDLK_h:
1071       calc_player_v();
1072       ok = 1;
1073       simulation_flag=1;
1074       gamemode |= (SIMULATION_MODE|PLAY_MODE);
1075       break;
1076      case SDLK_t:
1077       gl_move_table(0.0,0.0,0.0, 0.0,0.0,-0.985, 50.0, 0, 0, 0);
1078       break;
1079      case SDLK_s:
1080       gl_move_table(-55.0,0.0,-90.0, 0.0,0.1,-0.9, 50.0, 0, 0, 0);
1081       break;
1082      case SDLK_l:
1083       gl_move_table(oldang.x,oldang.y,oldang.z, oldstart.x,oldstart.y,oldstart.z, 50.0f,
1084 		    oldtrans.x, oldtrans.y, oldtrans.z);
1085       break;
1086      case SDLK_KP2:     newtranspos(  0.0,  0.003, 0.0, SDLK_KP2, 2); break;
1087      case SDLK_KP8:     newtranspos(  0.0, -0.003, 0.0, SDLK_KP8, 2); break;
1088      case SDLK_KP6:     newtranspos( -0.003,  0.0,  0.0, SDLK_KP6, 2); break;
1089      case SDLK_KP4:     newtranspos(  0.003,  0.0,  0.0, SDLK_KP4, 2); break;
1090      case SDLK_w:
1091       gamemode = (gamemode == TARGET_MODE) ? SPECIAL_TARGET_MODE : TARGET_MODE;
1092       if( gamemode == SPECIAL_TARGET_MODE )
1093        {
1094        sprintf(current_message, "special target mode; press w to toggle normal mode");
1095        special_target_mode();
1096        gl_move_table(newangx, newangy, newangz, newstartx, newstarty, newstartz, 50.0,
1097 		     newtransx, newtransy, newtransz);
1098        PAINT_ALL;
1099        }
1100       else if( gamemode == TARGET_MODE )
1101        {
1102        sprintf(current_message, "target mode - move mouse to change the position of the target ball");
1103        gl_move_table(0.0,0.0,0.0, 0.0,0.0,-0.985, 50.0, 0,0,0);
1104        PAINT_ALL;
1105        }
1106       break;
1107      case SDLK_DOWN:     newstartpos(  0.0,  0.003, 0.0, SDLK_DOWN, 2, -1); break;
1108      case SDLK_UP:       newstartpos(  0.0, -0.003, 0.0, SDLK_UP, 2, -1); break;
1109      case SDLK_RIGHT:    newstartpos( -0.003,  0.0,  0.0, SDLK_RIGHT, 2, -1); break;
1110      case SDLK_LEFT:     newstartpos(  0.003,  0.0,  0.0, SDLK_LEFT, 2, -1); break;
1111      case SDLK_PAGEUP:   newstartpos(  0.0,  0.0,  0.005, SDLK_PAGEUP, 2, -1); break;
1112      case SDLK_PAGEDOWN: newstartpos(  0.0,  0.0, -0.005, SDLK_PAGEDOWN, 2, -1); break;
1113      case SDLK_ESCAPE: ok = ret_wert = 1; break;
1114      case SDLK_n:		/* new game */
1115       mouse_off();
1116       ply[1-cur].points += 1;
1117       stats[cur].losses += 1;
1118       cur = 1 - cur;
1119       delete_ball(WHITE, -1);
1120       init_table();
1121       ok = 1;
1122       break;
1123      case SDLK_u:		/* undo last shot */
1124       undo();
1125       debug("undo...");
1126       PAINT_ALL;
1127       break;
1128      case SDLK_d:
1129       demo = 1;
1130       msg("press space or mouse button to stop demo");
1131       c_player = cur;
1132       last_gamemode = gamemode;
1133       gamemode = TARGET_MODE;
1134       gl_move_table(0.0,0.0,0.0, 0.0,0.0,-0.985, 50.0, 0,0,0);
1135       computer_stoss();
1136       ok = 1;
1137       break;
1138      case SDLK_y: gl_plotall(1); /* to make nicer screenshots ;-) */
1139       break;
1140      case SDLK_c:		/* computer plays every shot*/
1141       if( c_player == -1 )
1142        {
1143        c_player = cur;
1144        last_gamemode = gamemode;
1145        gamemode = TARGET_MODE;
1146        gl_move_table(0.0,0.0,0.0, 0.0,0.0,-0.985, 50.0, 0,0,0);
1147        }
1148       else { c_player = -1; break; }
1149      case SDLK_x:		/* let computer play one shot */
1150       computer_stoss();
1151       ok = 1;
1152       break;
1153      case SDLK_F11: if( ++table_color > 2 ) table_color = 0;
1154       gl_init_lists();
1155       PAINT_ALL;
1156       break;
1157      case SDLK_F12: plot_statistics( 0, 1 ); break;
1158      case SDLK_F1: help(); break;			/* F1 */
1159      case SDLK_F2: credits(); break;		/* F2 */
1160      case SDLK_f: showfps = 1-showfps; break;
1161      case SDLK_p: /* put away every ball except of white and eight ball ;-) */
1162       for( i=BLACK+1;i<WHITE;i++ ) delete_ball( i, -1 );
1163       for( i=0;i<BLACK;i++ ) delete_ball( i, -1 );
1164       break;
1165      case SDLK_e: mmouse = 1;
1166       test_spin();
1167       break;
1168      case SDLK_PLUS: alph = ((alph+=1) > 90 ? 90 : alph); wink( alph ); break;
1169      case SDLK_MINUS: alph = ((alph-=1) < 0 ? 0 : alph); wink( alph ); break;
1170      default: {}
1171      }
1172     }
1173    default:  break;
1174    }
1175   }
1176  while( !ok );
1177  if( !ret_wert && !(gamemode & SIMULATION_MODE) )
1178   {
1179   if( !( gamemode & SPECIAL_TARGET_MODE) ) gl_move_table(-55.0,0.0,-90.0, 0.0,0.1,-0.9, 10.0, 0, 0, 0);
1180   else gl_move_table(angx,angy,angz,startx,starty,startz*3.0,10.0,transx,transy,transz);
1181   }
1182  mouse_off();
1183  return ret_wert;
1184  }
1185 
delete_ball(int n,int pocket)1186 void delete_ball( int n, int pocket )
1187  /* Kugel "n" f�llt in Tasche und wird gel�scht; au�erdem wird gepr�ft, ob
1188     ein Foul durch das Versenken begangen wurde... Hatte der Spieler vor dem
1189     Versenken noch keine Farbe (Anfang des Spiels) so bekommt er hier diese */
1190  {
1191  k[n].stat = FALLING;
1192  k[n].v.z = 0.0;
1193  if( pocket >= 0 ) k[n].pocket = pocket;
1194  if( k[n].col == COL_WHITE ) ply[cur].stat |= FOUL_WHITE_POCKETED;
1195  else if( (k[n].col == COL_BLACK) && (ply[cur].col != COL_BLACK) )
1196   ply[cur].stat |= FOUL_BLACK_ILLEGALY_POCKETED;
1197  else if( !ply[cur].col && (k[n].col != COL_WHITE) )
1198   { /* falls noch keine Spieler-Farbe festgelegt ist */
1199   if( (k[n].col != COL_BLACK) && (ply[1-cur].col != k[n].col) )
1200    ply[cur].col = k[n].col;
1201   ply[1-cur].col = 3 - k[n].col;
1202   ply[cur].stat |= FOUL_CORRECT_POT;
1203   col_in = k[n].col;
1204   new_col |= NEW_COL_NEW;
1205   }
1206  else if( !freeball && (k[n].col != ply[cur].col) ) /* falsche Farbe */
1207   {
1208   if( new_col & NEW_COL_NEW ) new_col |= NEW_COL_DOUBLE;
1209   else ply[cur].stat |= FOUL_WRONG_COLOR_POCKETED;
1210   }
1211  else if( freeball || (k[n].col == ply[cur].col))  /* OK */
1212   ply[cur].stat |= FOUL_CORRECT_POT;
1213  bande_hit = 1;
1214  last_pocketed_balls++;
1215  }
1216 
print(char * out,int align,int x,int y)1217 void print( char *out, int align, int x, int y )
1218  {
1219  /*  GrDrawString( out, strlen(out), x, y, TEXTCOL ); */
1220  /*  SDL_Flip(display); */
1221  }
1222 
print2(char * out,int align,int x,int y)1223 void print2( char *out, int align, int x, int y )
1224  {
1225  /*  GrDrawString( out, strlen(out), x, y, TEXTCOL ); */
1226  /*  SDL_Flip(display); */
1227  }
1228 
close_graphics(void)1229 void close_graphics( void )
1230  {
1231  glDeleteLists(257,2);
1232  glDeleteLists(260,BALLS);
1233  glDeleteLists(290,BALLS);
1234  glDeleteLists(280,2);
1235  atexit(SDL_Quit);
1236  }
1237 
plot_statistics(double time,int grx)1238 void plot_statistics( double time, int grx )
1239  {
1240  int a=30;
1241  char out[256];
1242  if( SCREENRESX < 640) return;
1243  glDisable(GL_LIGHTING);
1244 
1245  glColor4d(0.1,0.1,0.1,0.7);
1246  glEnable(GL_BLEND);
1247  glBegin(GL_POLYGON);
1248  glVertex3d( -2.0, -2.0, 2.1*RADIUS );
1249  glVertex3d( 2.0, -2.0, 2.1*RADIUS );
1250  glVertex3d( 2.0, 2.0, 2.1*RADIUS );
1251  glVertex3d( -2.0, 2.0, 2.1*RADIUS );
1252  glEnd();
1253 
1254  glPrintCentered(768-(a+=90), "STATISTICS",0,1.0,1.0,1.0,1.0,5.0);
1255  glPrint(20,768-(a+=90),"    Player",0,1.0,1.0,1.0,1.0,3.0);
1256  glPrint(605,768-a,"1",0,1.0,1.0,1.0,1.0,3.0);
1257  glPrint(725,768-a,"2",0,1.0,1.0,1.0,1.0,3.0);
1258  glPrint(20,768-(a+=70), "standings",0,1.0,1.0,1.0,1.0,sqrt(2.0));
1259  sprintf(out,"%5d", stats[0].wins+stats[1].losses);
1260  glPrint(545,768-a, out,0,1.0,1.0,1.0,1.0,sqrt(2.0));
1261  sprintf(out,"%5d", stats[1].wins+stats[0].losses);
1262  glPrint(665,768-a, out,0,1.0,1.0,1.0,1.0,sqrt(2.0));
1263 
1264  sprintf(out,"-games won (correct play on black)   %5d   %5d",
1265 	 stats[0].wins, stats[1].wins);
1266  glPrint(20,768-(a+=50), out,0,1.0,1.0,1.0,1.0,1.0);
1267  sprintf(out,"-games lost ('direct' foul on black) %5d   %5d",
1268 	 stats[0].losses, stats[1].losses  );
1269  glPrint(20,768-(a+=30), out,0,1.0,1.0,1.0,1.0,1.0);
1270  sprintf(out,"number of pocketed balls             %5d   %5d",
1271 	 stats[0].pots, stats[1].pots  );
1272  glPrint(20,768-(a+=70), out,0,1.0,1.0,1.0,1.0,1.0);
1273  sprintf(out,"no. of attempts without success      %5d   %5d",
1274 	 stats[0].nopots, stats[1].nopots  );
1275  glPrint(20,768-(a+=30), out,0,1.0,1.0,1.0,1.0,1.0);
1276  sprintf(out,"fouls: wrong color touched           %5d   %5d",
1277 	 stats[0].fouls.wrongct, stats[1].fouls.wrongct  );
1278  glPrint(20,768-(a+=30), out,0,1.0,1.0,1.0,1.0,1.0);
1279  sprintf(out,"fouls: wrong color pocketed          %5d   %5d",
1280 	 stats[0].fouls.wrongcp, stats[1].fouls.wrongcp  );
1281  glPrint(20,768-(a+=30), out,0,1.0,1.0,1.0,1.0,1.0);
1282  sprintf(out,"fouls: white ball disappeared        %5d   %5d",
1283 	 stats[0].fouls.whited, stats[1].fouls.whited  );
1284  glPrint(20,768-(a+=30), out,0,1.0,1.0,1.0,1.0,1.0);
1285  sprintf(out,"fouls: no ball or rail touched       %5d   %5d",
1286 	 stats[0].fouls.notouch, stats[1].fouls.notouch  );
1287  glPrint(20,768-(a+=30), out,0,1.0,1.0,1.0,1.0,1.0);
1288  msg2("press an key or mouse button");
1289  SDL_GL_SwapBuffers();
1290  wait_for_click();
1291  PAINT_ALL;
1292  }
1293 
help(void)1294 void help( void )
1295  {
1296  int a=30;
1297  if( SCREENRESX < 640) return;
1298  glDisable(GL_LIGHTING);
1299 
1300  glColor4d(0.1,0.1,0.1,0.7);
1301  glEnable(GL_BLEND);
1302  glBegin(GL_POLYGON);
1303  glVertex3d( -2.0, -2.0, 2.1*RADIUS );
1304  glVertex3d( 2.0, -2.0, 2.1*RADIUS );
1305  glVertex3d( 2.0, 2.0, 2.1*RADIUS );
1306  glVertex3d( -2.0, 2.0, 2.1*RADIUS );
1307  glEnd();
1308 
1309  glPrint(20,768-(a+=45), "HELP-Screen", 0, 1.0, 1.0, 1.0, 1.0,2.0);
1310  glPrint(20,768-(a+=40), "KEYS:", 0, 1.0, 1.0, 1.0, 1.0,sqrt(2.0));
1311  glPrint(20,768-(a+=35), "  'e': change spin, same as middle button", 0, 1.0, 1.0, 1.0, 1.0 ,sqrt(2.0));
1312  glPrint(20,768-(a+=35), "  'c': activate/deactivate computer opponent", 0, 1.0, 1.0, 1.0, 1.0,sqrt(2.0));
1313  glPrint(20,768-(a+=35), "  'x': let computer play next shot", 0, 1.0, 1.0, 1.0, 1.0 ,sqrt(2.0));
1314  glPrint(20,768-(a+=35), "  'n': new game, current game is lost", 0, 1.0, 1.0, 1.0, 1.0 ,sqrt(2.0));
1315  glPrint(20,768-(a+=35), "  'd': demo-mode on; any key to stop demo", 0, 1.0, 1.0, 1.0, 1.0 ,sqrt(2.0));
1316  glPrint(20,768-(a+=35), "  'u': undo last shot (no redo implemented)", 0, 1.0, 1.0, 1.0, 1.0 ,sqrt(2.0));
1317  glPrint(20,768-(a+=35), "SPACE: toggle free look mode on and off", 0, 1.0, 1.0, 1.0, 1.0 ,sqrt(2.0));
1318  glPrint(20,768-(a+=35), "  'c': center view on white ball", 0, 1.0, 1.0, 1.0, 1.0 ,sqrt(2.0));
1319  glPrint(20,768-(a+=35), "  'z': calculate end position immediately", 0, 1.0, 1.0, 1.0, 1.0 ,sqrt(2.0));
1320  glPrint(20,768-(a+=35), "  'w': toggle special target mode", 0, 1.0, 1.0, 1.0, 1.0 ,sqrt(2.0));
1321  glPrint(20,768-(a+=35), "  'h': simulation mode (test)", 0, 1.0, 1.0, 1.0, 1.0 ,sqrt(2.0));
1322  glPrint(20,768-(a+=35), " 'F4': switch texture display (on/off)", 0, 1.0, 1.0, 1.0, 1.0 ,sqrt(2.0));
1323  glPrint(20,768-(a+=35), " 'F5': switch geometric detail level (hi/lo)", 0, 1.0, 1.0, 1.0, 1.0 ,sqrt(2.0));
1324  glPrint(20,768-(a+=35), " 'F1': this screen", 0, 1.0, 1.0, 1.0, 1.0 ,sqrt(2.0));
1325  glPrint(20,768-(a+=35), " 'F2': credits", 0, 1.0, 1.0, 1.0, 1.0 ,sqrt(2.0));
1326  glPrint(20,768-(a+=35), "'F12': statistics", 0, 1.0, 1.0, 1.0, 1.0 ,sqrt(2.0));
1327  glPrint(20,768-(a+=30),"  ESC: menu: quit game, computer player: stop", 0, 1.0, 1.0, 1.0, 1.0 ,sqrt(2.0));
1328  msg2("press an key or mouse button");
1329  SDL_GL_SwapBuffers();
1330  wait_for_click();
1331  PAINT_ALL;
1332  }
1333 
credits(void)1334 void credits( void )
1335  {
1336  int a=30;
1337  char out[256];
1338  if( SCREENRESX < 640) return;
1339  glDisable(GL_LIGHTING);
1340 
1341  glColor4d(0.1,0.1,0.1,0.7);
1342  glEnable(GL_BLEND);
1343  glBegin(GL_POLYGON);
1344  glVertex3d( -2.0, -2.0, 2.1*RADIUS );
1345  glVertex3d( 2.0, -2.0, 2.1*RADIUS );
1346  glVertex3d( 2.0, 2.0, 2.1*RADIUS );
1347  glVertex3d( -2.0, 2.0, 2.1*RADIUS );
1348  glEnd();
1349 
1350  sprintf(out,"Another Pool GL");
1351  glPrint(20, 768-(a+=50), out, 0,1.0,1.0,1.0,1.0 ,3.0);
1352  sprintf(out,"    V %s, %s",VERSION, DATE);
1353  glPrint(20, 768-(a+=30), out, 0,1.0,1.0,1.0,1.0,sqrt(2.0));
1354  glPrint(20, 768-(a+=30), "copyright (c) 1995-2005 by Gerrit Jahn", 0,1.0,1.0,1.0,1.0 ,1.0);
1355  glPrint(20, 768-(a+=30), "http://www.planetjahn.de",0,1.0,1.0,1.0,1.0 ,1.0);
1356  glPrint(10, 768-(a+=80), "CREDITS", 0,1.0,1.0,1.0,1.0 ,sqrt(2.0));
1357  glPrint(10, 768-(a+=30), "------------------------------------------------------------------",0,1.0,1.0,1.0,1.0 ,1.0);
1358  glPrint(10, 768-(a+=30), "'ANOTHER POOL (GL)' is free software;   you  can  redistribute  it",0,1.0,1.0,1.0,1.0 ,1.0);
1359  glPrint(10, 768-(a+=30), "and/or modify it under the terms of the GNU General Public License",0,1.0,1.0,1.0,1.0 ,1.0);
1360  glPrint(10, 768-(a+=30), "as published by the Free Software Foundation;  either version 2 of",0,1.0,1.0,1.0,1.0 ,1.0);
1361  glPrint(10, 768-(a+=30), "the License, or (at your option) any later version.",0,1.0,1.0,1.0,1.0 ,1.0);
1362  glPrint(10, 768-(a+=30), "Another Pool GL is distributed in the hope  that it will be useful,",0,1.0,1.0,1.0,1.0 ,1.0);
1363  glPrint(10, 768-(a+=30), "but  WITHOUT  ANY  WARRANTY;  without  even the implied warranty of",0,1.0,1.0,1.0,1.0 ,1.0);
1364  glPrint(10, 768-(a+=30), "MERCHANTABILITY  or  FITNESS  FOR A  PARTICULAR  PURPOSE.   See the",0,1.0,1.0,1.0,1.0 ,1.0);
1365  glPrint(10, 768-(a+=30), "GNU General Public License  (see file 'copying')  for more details.",0,1.0,1.0,1.0,1.0 ,1.0);
1366  glPrint(10, 768-(a+=30), "------------------------------------------------------------------",0,1.0,1.0,1.0,1.0 ,1.0);
1367  glPrint(10, 768-(a+=30), "If you have any  problems,  questions or suggestions,  look at the",0,1.0,1.0,1.0,1.0 ,1.0);
1368  glPrint(10, 768-(a+=30), "the homepage.",0,1.0,1.0,1.0,1.0 ,1.0);
1369  glPrint(10, 768-(a+=30), "                                 have fun!",0,1.0,1.0,1.0,1.0 ,1.0);
1370  glPrint(10, 768-(a+=30), "       ;-)                                             Gerrit Jahn",0,1.0,1.0,1.0,1.0 ,1.0);
1371  msg2("press an key or mouse button");
1372  SDL_GL_SwapBuffers();
1373  wait_for_click();
1374  PAINT_ALL;
1375  }
1376 
1377