1 /* Copyright (c) 2007 Scott Lembcke
2 *
3 * Permission is hereby granted, free of charge, to any person obtaining a copy
4 * of this software and associated documentation files (the "Software"), to deal
5 * in the Software without restriction, including without limitation the rights
6 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 * copies of the Software, and to permit persons to whom the Software is
8 * furnished to do so, subject to the following conditions:
9 *
10 * The above copyright notice and this permission notice shall be included in
11 * all copies or substantial portions of the Software.
12 *
13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 * SOFTWARE.
20 */
21
22 /*
23 IMPORTANT - READ ME!
24
25 This file sets up a simple interface that the individual demos can use to get
26 a Chipmunk space running and draw what's in it. In order to keep the Chipmunk
27 examples clean and simple, they contain no graphics code. All drawing is done
28 by accessing the Chipmunk structures at a very low level. It is NOT
29 recommended to write a game or application this way as it does not scale
30 beyond simple shape drawing and is very dependent on implementation details
31 about Chipmunk which may change with little to no warning.
32 */
33
34 #include <stdio.h>
35 #include <string.h>
36 #include <limits.h>
37 #include <stdarg.h>
38
39 #include "GL/glew.h"
40 #include "GL/glfw.h"
41
42 #include "chipmunk/chipmunk_private.h"
43 #include "ChipmunkDemo.h"
44 #include "ChipmunkDemoTextSupport.h"
45
46 static ChipmunkDemo *demos;
47 static int demo_count = 0;
48 static int demo_index = 'a' - 'a';
49
50 static cpBool paused = cpFalse;
51 static cpBool step = cpFalse;
52
53 static cpSpace *space;
54
55 static double Accumulator = 0.0;
56 static double LastTime = 0.0;
57 int ChipmunkDemoTicks = 0;
58 double ChipmunkDemoTime;
59
60 cpVect ChipmunkDemoMouse;
61 cpBool ChipmunkDemoRightClick = cpFalse;
62 cpBool ChipmunkDemoRightDown = cpFalse;
63 cpVect ChipmunkDemoKeyboard = {};
64
65 static cpBody *mouse_body = NULL;
66 static cpConstraint *mouse_joint = NULL;
67
68 char const *ChipmunkDemoMessageString = NULL;
69
70 #define GRABBABLE_MASK_BIT (1<<31)
71 cpShapeFilter GRAB_FILTER = {CP_NO_GROUP, GRABBABLE_MASK_BIT, GRABBABLE_MASK_BIT};
72 cpShapeFilter NOT_GRABBABLE_FILTER = {CP_NO_GROUP, ~GRABBABLE_MASK_BIT, ~GRABBABLE_MASK_BIT};
73
74 cpVect translate = {0, 0};
75 cpFloat scale = 1.0;
76
ShapeFreeWrap(cpSpace * space,cpShape * shape,void * unused)77 static void ShapeFreeWrap(cpSpace *space, cpShape *shape, void *unused){
78 cpSpaceRemoveShape(space, shape);
79 cpShapeFree(shape);
80 }
81
PostShapeFree(cpShape * shape,cpSpace * space)82 static void PostShapeFree(cpShape *shape, cpSpace *space){
83 cpSpaceAddPostStepCallback(space, (cpPostStepFunc)ShapeFreeWrap, shape, NULL);
84 }
85
ConstraintFreeWrap(cpSpace * space,cpConstraint * constraint,void * unused)86 static void ConstraintFreeWrap(cpSpace *space, cpConstraint *constraint, void *unused){
87 cpSpaceRemoveConstraint(space, constraint);
88 cpConstraintFree(constraint);
89 }
90
PostConstraintFree(cpConstraint * constraint,cpSpace * space)91 static void PostConstraintFree(cpConstraint *constraint, cpSpace *space){
92 cpSpaceAddPostStepCallback(space, (cpPostStepFunc)ConstraintFreeWrap, constraint, NULL);
93 }
94
BodyFreeWrap(cpSpace * space,cpBody * body,void * unused)95 static void BodyFreeWrap(cpSpace *space, cpBody *body, void *unused){
96 cpSpaceRemoveBody(space, body);
97 cpBodyFree(body);
98 }
99
PostBodyFree(cpBody * body,cpSpace * space)100 static void PostBodyFree(cpBody *body, cpSpace *space){
101 cpSpaceAddPostStepCallback(space, (cpPostStepFunc)BodyFreeWrap, body, NULL);
102 }
103
104 // Safe and future proof way to remove and free all objects that have been added to the space.
105 void
ChipmunkDemoFreeSpaceChildren(cpSpace * space)106 ChipmunkDemoFreeSpaceChildren(cpSpace *space)
107 {
108 // Must remove these BEFORE freeing the body or you will access dangling pointers.
109 cpSpaceEachShape(space, (cpSpaceShapeIteratorFunc)PostShapeFree, space);
110 cpSpaceEachConstraint(space, (cpSpaceConstraintIteratorFunc)PostConstraintFree, space);
111
112 cpSpaceEachBody(space, (cpSpaceBodyIteratorFunc)PostBodyFree, space);
113 }
114
115 static void
DrawCircle(cpVect p,cpFloat a,cpFloat r,cpSpaceDebugColor outline,cpSpaceDebugColor fill,cpDataPointer data)116 DrawCircle(cpVect p, cpFloat a, cpFloat r, cpSpaceDebugColor outline, cpSpaceDebugColor fill, cpDataPointer data)
117 {ChipmunkDebugDrawCircle(p, a, r, outline, fill);}
118
119 static void
DrawSegment(cpVect a,cpVect b,cpSpaceDebugColor color,cpDataPointer data)120 DrawSegment(cpVect a, cpVect b, cpSpaceDebugColor color, cpDataPointer data)
121 {ChipmunkDebugDrawSegment(a, b, color);}
122
123 static void
DrawFatSegment(cpVect a,cpVect b,cpFloat r,cpSpaceDebugColor outline,cpSpaceDebugColor fill,cpDataPointer data)124 DrawFatSegment(cpVect a, cpVect b, cpFloat r, cpSpaceDebugColor outline, cpSpaceDebugColor fill, cpDataPointer data)
125 {ChipmunkDebugDrawFatSegment(a, b, r, outline, fill);}
126
127 static void
DrawPolygon(int count,const cpVect * verts,cpFloat r,cpSpaceDebugColor outline,cpSpaceDebugColor fill,cpDataPointer data)128 DrawPolygon(int count, const cpVect *verts, cpFloat r, cpSpaceDebugColor outline, cpSpaceDebugColor fill, cpDataPointer data)
129 {ChipmunkDebugDrawPolygon(count, verts, r, outline, fill);}
130
131 static void
DrawDot(cpFloat size,cpVect pos,cpSpaceDebugColor color,cpDataPointer data)132 DrawDot(cpFloat size, cpVect pos, cpSpaceDebugColor color, cpDataPointer data)
133 {ChipmunkDebugDrawDot(size, pos, color);}
134
135 static cpSpaceDebugColor
ColorForShape(cpShape * shape,cpDataPointer data)136 ColorForShape(cpShape *shape, cpDataPointer data)
137 {
138 if(cpShapeGetSensor(shape)){
139 return LAColor(1.0f, 0.1f);
140 } else {
141 cpBody *body = cpShapeGetBody(shape);
142
143 if(cpBodyIsSleeping(body)){
144 return LAColor(0.2f, 1.0f);
145 } else if(body->sleeping.idleTime > shape->space->sleepTimeThreshold) {
146 return LAColor(0.66f, 1.0f);
147 } else {
148 uint32_t val = (uint32_t)shape->hashid;
149
150 // scramble the bits up using Robert Jenkins' 32 bit integer hash function
151 val = (val+0x7ed55d16) + (val<<12);
152 val = (val^0xc761c23c) ^ (val>>19);
153 val = (val+0x165667b1) + (val<<5);
154 val = (val+0xd3a2646c) ^ (val<<9);
155 val = (val+0xfd7046c5) + (val<<3);
156 val = (val^0xb55a4f09) ^ (val>>16);
157
158 GLfloat r = (GLfloat)((val>>0) & 0xFF);
159 GLfloat g = (GLfloat)((val>>8) & 0xFF);
160 GLfloat b = (GLfloat)((val>>16) & 0xFF);
161
162 GLfloat max = (GLfloat)cpfmax(cpfmax(r, g), b);
163 GLfloat min = (GLfloat)cpfmin(cpfmin(r, g), b);
164 GLfloat intensity = (cpBodyGetType(body) == CP_BODY_TYPE_STATIC ? 0.15f : 0.75f);
165
166 // Saturate and scale the color
167 if(min == max){
168 return RGBAColor(intensity, 0.0f, 0.0f, 1.0f);
169 } else {
170 GLfloat coef = (GLfloat)intensity/(max - min);
171 return RGBAColor(
172 (r - min)*coef,
173 (g - min)*coef,
174 (b - min)*coef,
175 1.0f
176 );
177 }
178 }
179 }
180 }
181
182
183 void
ChipmunkDemoDefaultDrawImpl(cpSpace * space)184 ChipmunkDemoDefaultDrawImpl(cpSpace *space)
185 {
186 cpSpaceDebugDrawOptions drawOptions = {
187 DrawCircle,
188 DrawSegment,
189 DrawFatSegment,
190 DrawPolygon,
191 DrawDot,
192
193 (cpSpaceDebugDrawFlags)(CP_SPACE_DEBUG_DRAW_SHAPES | CP_SPACE_DEBUG_DRAW_CONSTRAINTS | CP_SPACE_DEBUG_DRAW_COLLISION_POINTS),
194
195 {200.0f/255.0f, 210.0f/255.0f, 230.0f/255.0f, 1.0f},
196 ColorForShape,
197 {0.0f, 0.75f, 0.0f, 1.0f},
198 {1.0f, 0.0f, 0.0f, 1.0f},
199 NULL,
200 };
201
202 cpSpaceDebugDraw(space, &drawOptions);
203 }
204
205 static void
DrawInstructions()206 DrawInstructions()
207 {
208 ChipmunkDemoTextDrawString(cpv(-300, 220),
209 "Controls:\n"
210 "A - * Switch demos. (return restarts)\n"
211 "Use the mouse to grab objects.\n"
212 );
213 }
214
215 static int max_arbiters = 0;
216 static int max_points = 0;
217 static int max_constraints = 0;
218
219 static void
DrawInfo()220 DrawInfo()
221 {
222 int arbiters = space->arbiters->num;
223 int points = 0;
224
225 for(int i=0; i<arbiters; i++)
226 points += ((cpArbiter *)(space->arbiters->arr[i]))->count;
227
228 int constraints = (space->constraints->num + points)*space->iterations;
229
230 max_arbiters = arbiters > max_arbiters ? arbiters : max_arbiters;
231 max_points = points > max_points ? points : max_points;
232 max_constraints = constraints > max_constraints ? constraints : max_constraints;
233
234 char buffer[1024];
235 const char *format =
236 "Arbiters: %d (%d) - "
237 "Contact Points: %d (%d)\n"
238 "Other Constraints: %d, Iterations: %d\n"
239 "Constraints x Iterations: %d (%d)\n"
240 "Time:% 5.2fs, KE:% 5.2e";
241
242 cpArray *bodies = space->dynamicBodies;
243 cpFloat ke = 0.0f;
244 for(int i=0; i<bodies->num; i++){
245 cpBody *body = (cpBody *)bodies->arr[i];
246 if(body->m == INFINITY || body->i == INFINITY) continue;
247
248 ke += body->m*cpvdot(body->v, body->v) + body->i*body->w*body->w;
249 }
250
251 sprintf(buffer, format,
252 arbiters, max_arbiters,
253 points, max_points,
254 space->constraints->num, space->iterations,
255 constraints, max_constraints,
256 ChipmunkDemoTime, (ke < 1e-10f ? 0.0f : ke)
257 );
258
259 ChipmunkDemoTextDrawString(cpv(0, 220), buffer);
260 }
261
262 static char PrintStringBuffer[1024*8];
263 static char *PrintStringCursor;
264
265 void
ChipmunkDemoPrintString(char const * fmt,...)266 ChipmunkDemoPrintString(char const *fmt, ...)
267 {
268 ChipmunkDemoMessageString = PrintStringBuffer;
269
270 va_list args;
271 va_start(args, fmt);
272 // TODO: should use vsnprintf here
273 PrintStringCursor += vsprintf(PrintStringCursor, fmt, args);
274 va_end(args);
275 }
276
277 static void
Tick(double dt)278 Tick(double dt)
279 {
280 if(!paused || step){
281 PrintStringBuffer[0] = 0;
282 PrintStringCursor = PrintStringBuffer;
283
284 // Completely reset the renderer only at the beginning of a tick.
285 // That way it can always display at least the last ticks' debug drawing.
286 ChipmunkDebugDrawClearRenderer();
287 ChipmunkDemoTextClearRenderer();
288
289 cpVect new_point = cpvlerp(mouse_body->p, ChipmunkDemoMouse, 0.25f);
290 mouse_body->v = cpvmult(cpvsub(new_point, mouse_body->p), 60.0f);
291 mouse_body->p = new_point;
292
293 demos[demo_index].updateFunc(space, dt);
294
295 ChipmunkDemoTicks++;
296 ChipmunkDemoTime += dt;
297
298 step = cpFalse;
299 ChipmunkDemoRightDown = cpFalse;
300
301 ChipmunkDemoTextDrawString(cpv(-300, -200), ChipmunkDemoMessageString);
302 }
303 }
304
305 static void
Update(void)306 Update(void)
307 {
308 double time = glfwGetTime();
309 double dt = time - LastTime;
310 if(dt > 0.2) dt = 0.2;
311
312 double fixed_dt = demos[demo_index].timestep;
313
314 for(Accumulator += dt; Accumulator > fixed_dt; Accumulator -= fixed_dt){
315 Tick(fixed_dt);
316 }
317
318 LastTime = time;
319 }
320
321 static void
Display(void)322 Display(void)
323 {
324 glMatrixMode(GL_MODELVIEW);
325 glLoadIdentity();
326 glTranslatef((GLfloat)translate.x, (GLfloat)translate.y, 0.0f);
327 glScalef((GLfloat)scale, (GLfloat)scale, 1.0f);
328
329 Update();
330
331 ChipmunkDebugDrawPushRenderer();
332 demos[demo_index].drawFunc(space);
333
334 // // Highlight the shape under the mouse because it looks neat.
335 // cpShape *nearest = cpSpacePointQueryNearest(space, ChipmunkDemoMouse, 0.0f, CP_ALL_LAYERS, CP_NO_GROUP, NULL);
336 // if(nearest) ChipmunkDebugDrawShape(nearest, RGBAColor(1.0f, 0.0f, 0.0f, 1.0f), LAColor(0.0f, 0.0f));
337
338 // Draw the renderer contents and reset it back to the last tick's state.
339 ChipmunkDebugDrawFlushRenderer();
340 ChipmunkDebugDrawPopRenderer();
341
342 ChipmunkDemoTextPushRenderer();
343 // Now render all the UI text.
344 DrawInstructions();
345 DrawInfo();
346
347 glMatrixMode(GL_MODELVIEW);
348 glPushMatrix(); {
349 // Draw the text at fixed positions,
350 // but save the drawing matrix for the mouse picking
351 glLoadIdentity();
352
353 ChipmunkDemoTextFlushRenderer();
354 ChipmunkDemoTextPopRenderer();
355 } glPopMatrix();
356
357 glfwSwapBuffers();
358 glClear(GL_COLOR_BUFFER_BIT);
359 }
360
361 static void
Reshape(int width,int height)362 Reshape(int width, int height)
363 {
364 glViewport(0, 0, width, height);
365
366 float scale = (float)cpfmin(width/640.0, height/480.0);
367 float hw = width*(0.5f/scale);
368 float hh = height*(0.5f/scale);
369
370 ChipmunkDebugDrawPointLineScale = scale;
371 glLineWidth((GLfloat)scale);
372
373 glMatrixMode(GL_PROJECTION);
374 glLoadIdentity();
375 gluOrtho2D(-hw, hw, -hh, hh);
376 }
377
378 static char *
DemoTitle(int index)379 DemoTitle(int index)
380 {
381 static char title[1024];
382 sprintf(title, "Demo(%c): %s", 'a' + index, demos[demo_index].name);
383
384 return title;
385 }
386
387 static void
RunDemo(int index)388 RunDemo(int index)
389 {
390 srand(45073);
391
392 demo_index = index;
393
394 ChipmunkDemoTicks = 0;
395 ChipmunkDemoTime = 0.0;
396 Accumulator = 0.0;
397 LastTime = glfwGetTime();
398
399 mouse_joint = NULL;
400 ChipmunkDemoMessageString = "";
401 max_arbiters = 0;
402 max_points = 0;
403 max_constraints = 0;
404 space = demos[demo_index].initFunc();
405
406 glfwSetWindowTitle(DemoTitle(index));
407 }
408
409 static void
Keyboard(int key,int state)410 Keyboard(int key, int state)
411 {
412 if(state == GLFW_RELEASE) return;
413
414 int index = key - 'a';
415
416 if(0 <= index && index < demo_count){
417 demos[demo_index].destroyFunc(space);
418 RunDemo(index);
419 } else if(key == ' '){
420 demos[demo_index].destroyFunc(space);
421 RunDemo(demo_index);
422 } else if(key == '`'){
423 paused = !paused;
424 } else if(key == '1'){
425 step = cpTrue;
426 } else if(key == '\\'){
427 glDisable(GL_LINE_SMOOTH);
428 glDisable(GL_POINT_SMOOTH);
429 }
430
431 GLfloat translate_increment = 50.0f/(GLfloat)scale;
432 GLfloat scale_increment = 1.2f;
433 if(key == '5'){
434 translate.x = 0.0f;
435 translate.y = 0.0f;
436 scale = 1.0f;
437 }else if(key == '4'){
438 translate.x += translate_increment;
439 }else if(key == '6'){
440 translate.x -= translate_increment;
441 }else if(key == '2'){
442 translate.y += translate_increment;
443 }else if(key == '8'){
444 translate.y -= translate_increment;
445 }else if(key == '7'){
446 scale /= scale_increment;
447 }else if(key == '9'){
448 scale *= scale_increment;
449 }
450 }
451
452 static cpVect
MouseToSpace(int x,int y)453 MouseToSpace(int x, int y)
454 {
455 GLdouble model[16];
456 glGetDoublev(GL_MODELVIEW_MATRIX, model);
457
458 GLdouble proj[16];
459 glGetDoublev(GL_PROJECTION_MATRIX, proj);
460
461 GLint view[4];
462 glGetIntegerv(GL_VIEWPORT, view);
463
464 int ww, wh;
465 glfwGetWindowSize(&ww, &wh);
466
467 GLdouble mx, my, mz;
468 gluUnProject(x, wh - y, 0.0f, model, proj, view, &mx, &my, &mz);
469
470 return cpv(mx, my);
471 }
472
473 static void
Mouse(int x,int y)474 Mouse(int x, int y)
475 {
476 ChipmunkDemoMouse = MouseToSpace(x, y);
477 }
478
479 static void
Click(int button,int state)480 Click(int button, int state)
481 {
482 if(button == GLFW_MOUSE_BUTTON_1){
483 if(state == GLFW_PRESS){
484 // give the mouse click a little radius to make it easier to click small shapes.
485 cpFloat radius = 5.0;
486
487 cpPointQueryInfo info = {};
488 cpShape *shape = cpSpacePointQueryNearest(space, ChipmunkDemoMouse, radius, GRAB_FILTER, &info);
489
490 if(shape && cpBodyGetMass(cpShapeGetBody(shape)) < INFINITY){
491 // Use the closest point on the surface if the click is outside of the shape.
492 cpVect nearest = (info.distance > 0.0f ? info.point : ChipmunkDemoMouse);
493
494 cpBody *body = cpShapeGetBody(shape);
495 mouse_joint = cpPivotJointNew2(mouse_body, body, cpvzero, cpBodyWorldToLocal(body, nearest));
496 mouse_joint->maxForce = 50000.0f;
497 mouse_joint->errorBias = cpfpow(1.0f - 0.15f, 60.0f);
498 cpSpaceAddConstraint(space, mouse_joint);
499 }
500 } else if(mouse_joint){
501 cpSpaceRemoveConstraint(space, mouse_joint);
502 cpConstraintFree(mouse_joint);
503 mouse_joint = NULL;
504 }
505 } else if(button == GLFW_MOUSE_BUTTON_2){
506 ChipmunkDemoRightDown = ChipmunkDemoRightClick = (state == GLFW_PRESS);
507 }
508 }
509
510 static void
SpecialKeyboard(int key,int state)511 SpecialKeyboard(int key, int state)
512 {
513 switch(key){
514 case GLFW_KEY_UP : ChipmunkDemoKeyboard.y += (state == GLFW_PRESS ? 1.0 : -1.0); break;
515 case GLFW_KEY_DOWN : ChipmunkDemoKeyboard.y += (state == GLFW_PRESS ? -1.0 : 1.0); break;
516 case GLFW_KEY_RIGHT: ChipmunkDemoKeyboard.x += (state == GLFW_PRESS ? 1.0 : -1.0); break;
517 case GLFW_KEY_LEFT : ChipmunkDemoKeyboard.x += (state == GLFW_PRESS ? -1.0 : 1.0); break;
518 default: break;
519 }
520 }
521
522 static int
WindowClose()523 WindowClose()
524 {
525 glfwTerminate();
526 exit(EXIT_SUCCESS);
527
528 return GL_TRUE;
529 }
530
531 static void
SetupGL(void)532 SetupGL(void)
533 {
534 glewExperimental = GL_TRUE;
535 cpAssertHard(glewInit() == GLEW_NO_ERROR, "There was an error initializing GLEW.");
536 cpAssertHard(GLEW_ARB_vertex_array_object, "Requires VAO support.");
537
538 ChipmunkDebugDrawInit();
539 ChipmunkDemoTextInit();
540
541 glClearColor(52.0f/255.0f, 62.0f/255.0f, 72.0f/255.0f, 1.0f);
542 glClear(GL_COLOR_BUFFER_BIT);
543
544 glEnable(GL_LINE_SMOOTH);
545 glEnable(GL_POINT_SMOOTH);
546
547 glHint(GL_LINE_SMOOTH_HINT, GL_DONT_CARE);
548 glHint(GL_POINT_SMOOTH_HINT, GL_DONT_CARE);
549
550 glEnable(GL_BLEND);
551 glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
552 }
553
554 static void
SetupGLFW()555 SetupGLFW()
556 {
557 cpAssertHard(glfwInit(), "Error initializing GLFW.");
558
559 cpAssertHard(glfwOpenWindow(640, 480, 8, 8, 8, 8, 0, 0, GLFW_WINDOW), "Error opening GLFW window.");
560 glfwSetWindowTitle(DemoTitle(demo_index));
561 glfwSwapInterval(1);
562
563 SetupGL();
564
565 glfwSetWindowSizeCallback(Reshape);
566 glfwSetWindowCloseCallback(WindowClose);
567
568 glfwSetCharCallback(Keyboard);
569 glfwSetKeyCallback(SpecialKeyboard);
570
571 glfwSetMousePosCallback(Mouse);
572 glfwSetMouseButtonCallback(Click);
573 }
574
575 static void
TimeTrial(int index,int count)576 TimeTrial(int index, int count)
577 {
578 space = demos[index].initFunc();
579
580 double start_time = glfwGetTime();
581 double dt = demos[index].timestep;
582
583 for(int i=0; i<count; i++)
584 demos[index].updateFunc(space, dt);
585
586 double end_time = glfwGetTime();
587
588 demos[index].destroyFunc(space);
589
590 printf("Time(%c) = %8.2f ms (%s)\n", index + 'a', (end_time - start_time)*1e3f, demos[index].name);
591 fflush(stdout);
592 }
593
594 extern ChipmunkDemo LogoSmash;
595 extern ChipmunkDemo PyramidStack;
596 extern ChipmunkDemo Plink;
597 extern ChipmunkDemo BouncyHexagons;
598 extern ChipmunkDemo Tumble;
599 extern ChipmunkDemo PyramidTopple;
600 extern ChipmunkDemo Planet;
601 extern ChipmunkDemo Springies;
602 extern ChipmunkDemo Pump;
603 extern ChipmunkDemo TheoJansen;
604 extern ChipmunkDemo Query;
605 extern ChipmunkDemo OneWay;
606 extern ChipmunkDemo Player;
607 extern ChipmunkDemo Joints;
608 extern ChipmunkDemo Tank;
609 extern ChipmunkDemo Chains;
610 extern ChipmunkDemo Crane;
611 extern ChipmunkDemo Buoyancy;
612 extern ChipmunkDemo ContactGraph;
613 extern ChipmunkDemo Slice;
614 extern ChipmunkDemo Convex;
615 extern ChipmunkDemo Unicycle;
616 extern ChipmunkDemo Sticky;
617 extern ChipmunkDemo Shatter;
618 extern ChipmunkDemo GJK;
619
620 extern ChipmunkDemo bench_list[];
621 extern int bench_count;
622
623 int
main(int argc,const char ** argv)624 main(int argc, const char **argv)
625 {
626 ChipmunkDemo demo_list[] = {
627 LogoSmash,//A
628 PyramidStack,//B
629 Plink,//C
630 BouncyHexagons,//D
631 Tumble,//E
632 PyramidTopple,//F
633 Planet,//G
634 Springies,//H
635 Pump,//I
636 TheoJansen,//J
637 Query,//K
638 OneWay,//L
639 Joints,//M
640 Tank,//N
641 Chains,//O
642 Crane,//P
643 ContactGraph,//Q
644 Buoyancy,//R
645 Player,//S
646 Slice,//T
647 Convex,//U
648 Unicycle,//V
649 Sticky,//W
650 Shatter,//X
651 };
652
653 demos = demo_list;
654 demo_count = sizeof(demo_list)/sizeof(ChipmunkDemo);
655 int trial = 0;
656
657 for(int i=0; i<argc; i++){
658 if(strcmp(argv[i], "-bench") == 0){
659 demos = bench_list;
660 demo_count = bench_count;
661 } else if(strcmp(argv[i], "-trial") == 0){
662 trial = 1;
663 }
664 }
665
666 if(trial){
667 cpAssertHard(glfwInit(), "Error initializing GLFW.");
668 // sleep(1);
669 for(int i=0; i<demo_count; i++) TimeTrial(i, 1000);
670 // time_trial('d' - 'a', 10000);
671 exit(0);
672 } else {
673 mouse_body = cpBodyNewKinematic();
674
675 RunDemo(demo_index);
676 SetupGLFW();
677
678 while(1){
679 Display();
680 }
681 }
682
683 return 0;
684 }
685