1 /*
2  * Copyright (c) 2007-2013 Scott Lembcke and Howling Moon Software
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a copy
5  * of this software and associated documentation files (the "Software"), to deal
6  * in the Software without restriction, including without limitation the rights
7  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8  * copies of the Software, and to permit persons to whom the Software is
9  * furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20  * SOFTWARE.
21  */
22 module demo.PyramidTopple;
23 
24 import core.stdc.stdlib;
25 
26 import demo.dchip;
27 
28 import demo.ChipmunkDebugDraw;
29 import demo.ChipmunkDemo;
30 import demo.types;
31 
32 void update(cpSpace* space, double dt)
33 {
34     cpSpaceStep(space, dt);
35 }
36 
37 enum WIDTH  = 4.0f;
38 enum HEIGHT = 30.0f;
39 
40 void add_domino(cpSpace* space, cpVect pos, cpBool flipped)
41 {
42     cpFloat mass   = 1.0f;
43     cpFloat moment = cpMomentForBox(mass, WIDTH, HEIGHT);
44 
45     cpBody* body_ = cpSpaceAddBody(space, cpBodyNew(mass, moment));
46     cpBodySetPos(body_, pos);
47 
48     cpShape* shape = (flipped ? cpBoxShapeNew(body_, HEIGHT, WIDTH) : cpBoxShapeNew(body_, WIDTH, HEIGHT));
49     cpSpaceAddShape(space, shape);
50     cpShapeSetElasticity(shape, 0.0f);
51     cpShapeSetFriction(shape, 0.6f);
52 }
53 
54 cpSpace* init()
55 {
56     cpSpace* space = cpSpaceNew();
57     cpSpaceSetIterations(space, 30);
58     cpSpaceSetGravity(space, cpv(0, -300));
59     cpSpaceSetSleepTimeThreshold(space, 0.5f);
60     cpSpaceSetCollisionSlop(space, 0.5f);
61 
62     // Add a floor.
63     cpShape* shape = cpSpaceAddShape(space, cpSegmentShapeNew(cpSpaceGetStaticBody(space), cpv(-600, -240), cpv(600, -240), 0.0f));
64     cpShapeSetElasticity(shape, 1.0f);
65     cpShapeSetFriction(shape, 1.0f);
66     cpShapeSetLayers(shape, NOT_GRABABLE_MASK);
67 
68     // Add the dominoes.
69     int n = 12;
70 
71     for (int i = 0; i < n; i++)
72     {
73         for (int j = 0; j < (n - i); j++)
74         {
75             cpVect offset = cpv((j - (n - 1 - i) * 0.5f) * 1.5f * HEIGHT, (i + 0.5f) * (HEIGHT + 2 * WIDTH) - WIDTH - 240);
76             add_domino(space, offset, cpFalse);
77             add_domino(space, cpvadd(offset, cpv(0, (HEIGHT + WIDTH) / 2.0f)), cpTrue);
78 
79             if (j == 0)
80             {
81                 add_domino(space, cpvadd(offset, cpv(0.5f * (WIDTH - HEIGHT), HEIGHT + WIDTH)), cpFalse);
82             }
83 
84             if (j != n - i - 1)
85             {
86                 add_domino(space, cpvadd(offset, cpv(HEIGHT * 0.75f, (HEIGHT + 3 * WIDTH) / 2.0f)), cpTrue);
87             }
88             else
89             {
90                 add_domino(space, cpvadd(offset, cpv(0.5f * (HEIGHT - WIDTH), HEIGHT + WIDTH)), cpFalse);
91             }
92         }
93     }
94 
95     return space;
96 }
97 
98 void destroy(cpSpace* space)
99 {
100     ChipmunkDemoFreeSpaceChildren(space);
101     cpSpaceFree(space);
102 }
103 
104 ChipmunkDemo PyramidTopple = {
105     "Pyramid Topple",
106     1.0 / 180.0,
107     &init,
108     &update,
109     &ChipmunkDemoDefaultDrawImpl,
110     &destroy,
111 };