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