forked from barak/quantumminigolf
-
Notifications
You must be signed in to change notification settings - Fork 0
/
quantumminigolf.cpp
291 lines (244 loc) · 8.06 KB
/
quantumminigolf.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
/* Quantum Minigolf, a computer game illustrating quantum mechanics
Copyright (C) 2007 Friedemann Reinhard <[email protected]>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "QuantumSimulator.h"
#include "ClassicSimulator.h"
#include "Renderer.h"
#include "SoftwareTracker.h"
#include "TrackSelector.h"
#include "quantumminigolf.h"
#ifdef VR
#include "WebcamTracker.h"
#endif //VR
#ifdef LINUX
#include <sys/time.h>
#endif
#ifdef DUMP_VIDEO
char fname[80];
#endif
// dimensions of the playing field
#define WIDTH 640
#define HEIGHT 320
// main
// put it all together...
#ifdef WIN32 // no comment...
int
wmain (int argc, char *argv[])
#endif
#ifdef LINUX
int main (int argc, char **argv)
#endif
{
int ix = 550, iy = 160; // initial ball position
int rball = 5; // ball radius
int holex = 100;
int holey = 160;
int holer = 30; // hole position and radius
int posx, posy; // result of the final position measurement;
int res; // success of the user: win / lose
int ypos; // position of the win / lose indicator
float rphi; // angle of the racket relative to x axis
float rv; // velocity of the racket
float rvmax = 40; // maximum club speed
float dt = 0.0001; // hard-coded increment for the quantum propagation
float norm = 1; //total shrink during a position space propagation
// used to enforce normalization of psi
float normlast = 1; //shrink during last iteration, used to enforce
//normalization
float nsq = WIDTH * HEIGHT;
int frames = 0;
float framerate;
Uint32 sdlclock, frameclock;
bool quantum = true; // quantum or classical mode ?
SDL_Event dummyevent;
bool mainloopfinished = false;
// seed the random number generator
#ifdef WIN32
srand (time (NULL));
#endif
#ifdef LINUX
struct timeval tv;
gettimeofday (&tv, 0);
srand (tv.tv_sec + tv.tv_usec);
#endif
#ifndef VR
SoftwareTracker stracker (WIDTH, HEIGHT, ix, iy, rball, rvmax, NULL);
Tracker & tracker = stracker;
Renderer renderer (WIDTH, HEIGHT, SDL_HWSURFACE /*| SDL_FULLSCREEN */ , holex, holey, holer, rball); // | SDL_FULLSCREEN);
#endif
#ifdef VR
WebcamTracker wctracker (WIDTH, HEIGHT, ix, iy, rball, rvmax, NULL);
Tracker & tracker = wctracker;
printf ("adjust your webcam and press <ENTER> to start\n");
getc (stdin);
Renderer renderer (WIDTH, HEIGHT, SDL_HWSURFACE | SDL_FULLSCREEN, holex, holey, holer, rball); // | SDL_FULLSCREEN);
#endif //VR
ClassicSimulator csimulator (WIDTH, HEIGHT, &renderer, holex, holey, holer);
QuantumSimulator simulator (WIDTH, HEIGHT, dt);
TrackSelector trackselector (&renderer, &csimulator);
tracker.setRenderer (&renderer);
quantum = true;
// menu loop - have the user select a track and play
while (trackselector.GetTrack (&quantum))
{
// for each new track, we have to rebuild the position propagator
if (quantum)
simulator.BuildPositionPropagator (renderer.V);
renderer.RenderTrack ();
renderer.RenderBall (ix, iy);
renderer.Blit ();
// have the user kick the ball
tracker.GetHit (&rv, &rphi);
Uint32 hitclock = SDL_GetTicks ();
// now that the user has decided about the initial values,
// prepare the wave packet
if (quantum)
{
// commented out for uncertainty movie 070519
simulator.GenGauss (ix, iy,
-2 * rv * M_PI / 2 * cos (rphi) / 2,
-2 * rv * M_PI / 2 * sin (rphi) / 2, 10);
// hack for uncertainty movie 070519
// simulator.GenGauss( 200, iy,
// -.4,
// 0,
// 15);
// simulator.GenGauss( 400, iy,
// -.4,
// 0,
// 6);
// simulator.GenGauss( 600, iy,
// -.4,
// 0,
// 3);
}
else
{
csimulator.setPosition ((float) ix, (float) iy);
csimulator.setVelocity (-2 * rv * M_PI / 2 * cos (rphi),
-2 * rv * M_PI / 2 * sin (rphi));
}
//kick it like Beckham
tracker.AnimateHit (1000, rv, rphi);
SDL_EventState (SDL_MOUSEBUTTONUP, SDL_IGNORE);
sdlclock = SDL_GetTicks ();
frameclock = SDL_GetTicks ();
frames = 0;
// ***** MAIN LOOP *****//
//
// while the user doesn't press RET, Space or Esc, propagate the
// wave function in the potential
while (1)
{
if (SDL_PollEvent (&dummyevent))
{
switch (dummyevent.type)
{
case SDL_KEYDOWN:
switch (dummyevent.key.keysym.sym)
{
case SDLK_RETURN: //RET, Space or Esc - stop
case SDLK_ESCAPE:
case SDLK_SPACE:
mainloopfinished = true;
break;
case SDLK_b: // b - toggle background rendering
renderer.ToggleBackgroundRendering ();
break;
default:
break;
}
break;
default:
break;
}
}
if (mainloopfinished)
{
mainloopfinished = false;
break;
}
renderer.RenderTrack ();
if (quantum)
{
// propagate in momentum space
simulator.PropagateMomentum ();
// propagate in position space
normlast =
simulator.PropagatePosition (1 / nsq / sqrt (normlast));
// finally, show the result
renderer.RenderWave (simulator.psi);
}
else
{
if (csimulator.propagate (SDL_GetTicks () - frameclock))
break;
renderer.RenderBall (csimulator.pos[0], csimulator.pos[1]);
}
renderer.Blit ();
#ifdef DUMP_VIDEO
snprintf (fname, sizof (fname), "video/%d.bmp", frames);
renderer.SaveFrame (fname);
#endif
// some bookkeeping
frames++;
frameclock = SDL_GetTicks ();
}
framerate = frames / (float) (SDL_GetTicks () - sdlclock) * 1000;
while (SDL_PollEvent (&dummyevent) == 1)
{
} // clear event buffer
// render a flash to show the position measurement
renderer.RenderFlash ();
renderer.Blit ();
frames++;
#ifdef DUMP_VIDEO
snprintf (fname, sizeof (fname), "video/%d.bmp", frames);
renderer.SaveFrame (fname);
#endif
// a button has been pressed, measure the ball position!
if (quantum)
simulator.PositionMeasurement (&posx, &posy);
else
{
posx = (int) (csimulator.pos[0]);
posy = (int) (csimulator.pos[1]);
}
// render the extro. Show the (now classical) ball and inform the user about his success
if ((posx - holex) * (posx - holex) +
(posy - holey) * (posy - holey) < holer * holer)
res = QMG_WIN;
else
res = QMG_LOSE;
sdlclock = SDL_GetTicks ();
while (SDL_PollEvent (NULL) == 0)
{
ypos =
-300 +
(int) ((float) (SDL_GetTicks () - sdlclock) / 500 * HEIGHT / 2);
renderer.RenderTrack ();
renderer.RenderBall (posx, posy);
renderer.RenderExtro (res, ypos);
renderer.Blit ();
frames++;
#ifdef DUMP_VIDEO
snprintf (fname, sizeof (fname), "video/%d.bmp", frames);
renderer.SaveFrame (fname);
#endif
}
// printf("rendered %d frames, quantum part framerate %2.1f fps. Goodbye\n", frames, framerate);
simulator.ClearWave ();
}
return 0;
}