1 
2 // written in the D programming language
3 
4 /++
5  +	Authors: Stephan Dilly, www.extrawurst.org
6  +/
7 
8 module gameApp;
9 
10 import core.stdc.stdlib;
11 import core.thread;
12 
13 import std.stdio;
14 
15 import framework;
16 
17 import drawSpace;
18 
19 import dchip.all;
20 
21 import samples.benchmark;
22 import samples.LogoSmash;
23 import samples.Simple;
24 import samples.PyramidStack;
25 import samples.ChipmunkDemo;
26 import samples.Plink;
27 import samples.Tumble;
28 import samples.PyramidTopple;
29 import samples.Planet;
30 import samples.Query;
31 import samples.OneWay;
32 import samples.Sensors;
33 import samples.Bounce;
34 import samples.Springies;
35 import samples.Joints;
36 import samples.MagnetsElectric;
37 import samples.Player;
38 import samples.Tank;
39 import samples.Pump;
40 import samples.TheoJansen;
41 import samples.UnsafeOps;
42 
43 // using derelict bindings for sdl/opengl
44 import derelict.opengl.gl;
45 import derelict.opengl.glu;
46 import derelict.sdl.sdl;
47 
48 //version = TIME_TRIAL;
49 
50 cpVect			mousePos;
51 cpVect			arrowDirection;
52 
53 bool key_up = false;
54 bool key_down = false;
55 bool key_left = false;
56 bool key_right = false;
57 bool key_space = false;
58 
59 ///
60 final class GameApp {
61 
62 private:
63 
64     chipmunkDemo[]	demos;
65     chipmunkDemo*	currentDemo;
66     cpSpace*		space;
67     int				ticks;
68     int				step;
69     bool			trial=false;
70     bool			paused=false;
71     cpBody*			mouseBody;
72     cpConstraint*	mouseJoint;
73     cpVect			mousePos_last;
74 
75     bool 	m_running = true;
76 
77     drawSpaceOptions options = {
78         0,		// drawHash
79         0,		// drawBB
80         1,		// drawShapes
81         4.0f,	// collisionPointSize
82         0.0f,	// bodyPointSize
83         1.5f,	// lineThickness
84     };
85 
86     enum width = 1024;
87     enum height = 780;
88 
89     void time_trial(size_t index, int count)
90     {
91         currentDemo = &demos[index];
92         space = currentDemo.initFunc();
93 
94         auto start = .tickCount();
95 
96         foreach(i; 0..count)
97             currentDemo.updateFunc(i);
98 
99         auto end = .tickCount();
100         auto duration = (end - start);
101 
102         currentDemo.destroyFunc();
103 
104         writefln("Time(%s) = %s (%s)", cast(char)(index + 'a'), duration, currentDemo.name);
105     }
106 
107     ///
108     public void boot(string[] _args) {
109 
110         demos = [
111             LogoSmash,
112             //Simple,
113             PyramidStack,
114             Plink,
115             Tumble,
116             PyramidTopple,
117             Bounce,
118             Planet,
119             Springies,
120             Pump,
121             TheoJansen,
122             MagnetsElectric,
123             UnsafeOps,
124             Query,
125             OneWay,
126             Player,
127             Sensors,
128             Joints,
129             Tank,
130         ];
131 
132         foreach(arg; _args)
133         {
134             switch(arg)
135             {
136             case "-bench":
137                 demos = bench_list;
138                 break;
139             case "-trial":
140                 trial = true;
141                 break;
142             default:
143                 break;
144             }
145         }
146 
147         if(trial)
148         {
149             foreach(i, demo; demos)
150             {
151                 time_trial(i, 1000);
152             }
153 
154             m_running = false;
155 
156             return;
157         }
158 
159         //setup framework
160         bool useVsync = true;
161         framework.startup("chipmunk'd by Stephan Dilly",width,height,useVsync);
162 
163         reshape(width,height);
164 
165         glEnableClientState(GL_VERTEX_ARRAY);
166 
167         runDemo(&demos[0]);
168 
169         mouseBody = cpBodyNew(INFINITY, INFINITY);
170     }
171 
172     ///
173     void runDemo(chipmunkDemo *demo)
174     {
175         core.stdc.stdlib.srand(45073);
176 
177         currentDemo = demo;
178 
179         ticks = 0;
180         mouseJoint = null;
181         //messageString[0] = '\0';
182         //maxArbiters = 0;
183         //maxPoints = 0;
184         //maxConstraints = 0;
185         space = demo.initFunc();
186 
187         //glutSetWindowTitle(demoTitle(index));
188     }
189 
190     ///
191     void reshape(int width, int height)
192     {
193         glViewport(0, 0, width, height);
194 
195         double scale = 0.5/cpfmin(width/640.0, height/480.0);
196         double hw = width*scale;
197         double hh = height*scale;
198 
199         glMatrixMode(GL_PROJECTION);
200         glLoadIdentity();
201         glOrtho(-hw, hw, -hh, hh, -1.0, 1.0);
202         glTranslated(0.5, 0.5, 0.0);
203     }
204 
205     ///
206     public bool update() {
207 
208         if(!m_running) return m_running;
209 
210         if(!framework.processEvents(&keyEvent,&mouseMove,&mouseButtonEvent))
211             return false;
212 
213         cpVect newPoint = cpvlerp(mousePos_last, mousePos, 0.25f);
214 
215         mouseBody.p = newPoint;
216         mouseBody.v = cpvmult(cpvsub(newPoint, mousePos_last), 60.0f);
217         mousePos_last = newPoint;
218 
219         if(!paused || step > 0){
220             currentDemo.updateFunc(ticks++);
221             step = (step > 1 ? step - 1 : 0);
222         }
223 
224         // render
225 
226         glClearColor(1,1,1,1);
227 
228         glClear(GL_COLOR_BUFFER_BIT);
229 
230         DrawSpace(space, currentDemo.drawOptions ? currentDemo.drawOptions : &options);
231         //drawInstructions();
232         //drawInfo();
233         //drawString(-300, -210, messageString);
234 
235         SDL_GL_SwapBuffers();
236 
237         return m_running;
238     }
239 
240     ///
241     public void shutdown() {
242 
243 version(TIME_TRIAL){}else
244 {
245         currentDemo.destroyFunc();
246 
247         framework.shutdown();
248 }
249     }
250 
251     cpVect mouseToSpace(int x, int y)
252     {
253         GLdouble model[16];
254         glGetDoublev(GL_MODELVIEW_MATRIX, model.ptr);
255 
256         GLdouble proj[16];
257         glGetDoublev(GL_PROJECTION_MATRIX, proj.ptr);
258 
259         GLint view[4];
260         glGetIntegerv(GL_VIEWPORT, view.ptr);
261 
262         GLdouble mx, my, mz;
263         gluUnProject(x, height - y, 0.0f, model.ptr, proj.ptr, view.ptr, &mx, &my, &mz);
264 
265         return cpv(mx, my);
266     }
267 
268     ///
269     private void mouseMove(int x,int y)
270     {
271         mousePos = mouseToSpace(x,y);
272     }
273 
274     ///
275     private void mouseButtonEvent(int x,int y,bool _down)
276     {
277         if(_down){
278             cpVect point = mouseToSpace(x,y);
279 
280             cpShape *shape = cpSpacePointQueryFirst(space, point, GRABABLE_MASK_BIT, CP_NO_GROUP);
281             if(shape){
282                 cpBody *body_ = shape.body_;
283                 mouseJoint = cpPivotJointNew2(mouseBody, body_, cpvzero, cpBodyWorld2Local(body_, point));
284                 mouseJoint.maxForce = 50000.0f;
285                 mouseJoint.errorBias = 0.15f;
286                 cpSpaceAddConstraint(space, mouseJoint);
287             }
288         } else if(mouseJoint){
289             cpSpaceRemoveConstraint(space, mouseJoint);
290             cpConstraintFree(mouseJoint);
291             mouseJoint = null;
292         }
293     }
294 
295     ///
296     private void set_arrowDirection()
297     {
298         int x = 0, y = 0;
299 
300         if(key_up) y += 1;
301         if(key_down) y -= 1;
302         if(key_right) x += 1;
303         if(key_left) x -= 1;
304 
305         arrowDirection = cpv(x, y);
306     }
307 
308     ///
309     private void keyEvent(int _key,bool _down)
310     {
311         int key = _key;
312 
313         if(_down)
314         {
315             int index = key - 'a';
316 
317             if(0 <= index && index < demos.length){
318                 runDemo(&demos[index]);
319             } else if(key == '\r'){
320                 runDemo(currentDemo);
321             } else if(key == 61){
322                 paused = !paused;
323             } else if(key == 47){
324                 options.drawHash = !options.drawHash;
325             } else if(key == '1'){
326                 step += 1;
327             } else if(key == 92){
328                 options.drawBBs = !options.drawBBs;
329             } else if(key == 27){
330                 m_running = false;
331             } else if(key == 93){
332                 glEnable(GL_LINE_SMOOTH);
333                 glEnable(GL_POINT_SMOOTH);
334                 glEnable(GL_BLEND);
335                 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
336                 glHint(GL_LINE_SMOOTH_HINT, GL_DONT_CARE);
337                 glHint(GL_POINT_SMOOTH_HINT, GL_DONT_CARE);
338             }
339             else
340             {
341                 if(key == SDLK_UP) key_up = true;
342                 else if(key == SDLK_DOWN) key_down = true;
343                 else if(key == SDLK_LEFT) key_left = true;
344                 else if(key == SDLK_RIGHT) key_right = true;
345                 else if(key == SDLK_SPACE) key_space = true;
346 
347                 set_arrowDirection();
348             }
349         }
350         else
351         {
352             if(key == SDLK_UP) key_up = false;
353             else if(key == SDLK_DOWN) key_down = false;
354             else if(key == SDLK_LEFT) key_left = false;
355             else if(key == SDLK_RIGHT) key_right = false;
356             else if(key == SDLK_SPACE) key_space = false;
357 
358             set_arrowDirection();
359         }
360     }
361 }
362