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.Pump;
23 
24 import core.stdc.stdlib;
25 
26 import std.math;
27 
28 alias M_PI_2 = PI_2;
29 
30 import demo.dchip;
31 
32 import demo.ChipmunkDebugDraw;
33 import demo.ChipmunkDemo;
34 import demo.types;
35 
36 cpConstraint* motor;
37 
38 enum numBalls = 5;
39 cpBody*[numBalls] balls;
40 
41 void update(cpSpace* space, double dt)
42 {
43     cpFloat coef = (2.0f + ChipmunkDemoKeyboard.y) / 3.0f;
44     cpFloat rate = ChipmunkDemoKeyboard.x * 30.0f * coef;
45 
46     cpSimpleMotorSetRate(motor, rate);
47     cpConstraintSetMaxForce(motor, rate ? 1000000.0f : 0.0f);
48 
49     cpSpaceStep(space, dt);
50 
51     for (int i = 0; i < numBalls; i++)
52     {
53         cpBody* ball = balls[i];
54         cpVect  pos  = cpBodyGetPos(ball);
55 
56         if (pos.x > 320.0f)
57         {
58             cpBodySetVel(ball, cpvzero);
59             cpBodySetPos(ball, cpv(-224.0f, 200.0f));
60         }
61     }
62 }
63 
64 cpBody* add_ball(cpSpace* space, cpVect pos)
65 {
66     cpBody* body_ = cpSpaceAddBody(space, cpBodyNew(1.0f, cpMomentForCircle(1.0f, 30, 0, cpvzero)));
67     cpBodySetPos(body_, pos);
68 
69     cpShape* shape = cpSpaceAddShape(space, cpCircleShapeNew(body_, 30, cpvzero));
70     cpShapeSetElasticity(shape, 0.0f);
71     cpShapeSetFriction(shape, 0.5f);
72 
73     return body_;
74 }
75 
76 cpSpace* init()
77 {
78     ChipmunkDemoMessageString = "Use the arrow keys to control the machine.".dup;
79 
80     cpSpace* space = cpSpaceNew();
81     cpSpaceSetGravity(space, cpv(0, -600));
82 
83     cpBody * staticBody = cpSpaceGetStaticBody(space);
84     cpShape* shape;
85 
86     // beveling all of the line segments slightly helps prevent things from getting stuck on cracks
87     shape = cpSpaceAddShape(space, cpSegmentShapeNew(staticBody, cpv(-256, 16), cpv(-256, 300), 2.0f));
88     cpShapeSetElasticity(shape, 0.0f);
89     cpShapeSetFriction(shape, 0.5f);
90     cpShapeSetLayers(shape, NOT_GRABABLE_MASK);
91 
92     shape = cpSpaceAddShape(space, cpSegmentShapeNew(staticBody, cpv(-256, 16), cpv(-192, 0), 2.0f));
93     cpShapeSetElasticity(shape, 0.0f);
94     cpShapeSetFriction(shape, 0.5f);
95     cpShapeSetLayers(shape, NOT_GRABABLE_MASK);
96 
97     shape = cpSpaceAddShape(space, cpSegmentShapeNew(staticBody, cpv(-192, 0), cpv(-192, -64), 2.0f));
98     cpShapeSetElasticity(shape, 0.0f);
99     cpShapeSetFriction(shape, 0.5f);
100     cpShapeSetLayers(shape, NOT_GRABABLE_MASK);
101 
102     shape = cpSpaceAddShape(space, cpSegmentShapeNew(staticBody, cpv(-128, -64), cpv(-128, 144), 2.0f));
103     cpShapeSetElasticity(shape, 0.0f);
104     cpShapeSetFriction(shape, 0.5f);
105     cpShapeSetLayers(shape, NOT_GRABABLE_MASK);
106 
107     shape = cpSpaceAddShape(space, cpSegmentShapeNew(staticBody, cpv(-192, 80), cpv(-192, 176), 2.0f));
108     cpShapeSetElasticity(shape, 0.0f);
109     cpShapeSetFriction(shape, 0.5f);
110     cpShapeSetLayers(shape, NOT_GRABABLE_MASK);
111 
112     shape = cpSpaceAddShape(space, cpSegmentShapeNew(staticBody, cpv(-192, 176), cpv(-128, 240), 2.0f));
113     cpShapeSetElasticity(shape, 0.0f);
114     cpShapeSetFriction(shape, 0.5f);
115     cpShapeSetLayers(shape, NOT_GRABABLE_MASK);
116 
117     shape = cpSpaceAddShape(space, cpSegmentShapeNew(staticBody, cpv(-128, 144), cpv(192, 64), 2.0f));
118     cpShapeSetElasticity(shape, 0.0f);
119     cpShapeSetFriction(shape, 0.5f);
120     cpShapeSetLayers(shape, NOT_GRABABLE_MASK);
121 
122     cpVect verts[] = [
123         cpv(-30, -80),
124         cpv(-30, 80),
125         cpv(30, 64),
126         cpv(30, -80),
127     ];
128 
129     cpBody* plunger = cpSpaceAddBody(space, cpBodyNew(1.0f, INFINITY));
130     cpBodySetPos(plunger, cpv(-160, -80));
131 
132     shape = cpSpaceAddShape(space, cpPolyShapeNew(plunger, 4, verts.ptr, cpvzero));
133     cpShapeSetElasticity(shape, 1.0f);
134     cpShapeSetFriction(shape, 0.5f);
135     cpShapeSetLayers(shape, 1);
136 
137     // add balls to hopper
138     for (int i = 0; i < numBalls; i++)
139         balls[i] = add_ball(space, cpv(-224 + i, 80 + 64 * i));
140 
141     // add small gear
142     cpBody* smallGear = cpSpaceAddBody(space, cpBodyNew(10.0f, cpMomentForCircle(10.0f, 80, 0, cpvzero)));
143     cpBodySetPos(smallGear, cpv(-160, -160));
144     cpBodySetAngle(smallGear, -M_PI_2);
145 
146     shape = cpSpaceAddShape(space, cpCircleShapeNew(smallGear, 80.0f, cpvzero));
147     cpShapeSetLayers(shape, 0);
148 
149     cpSpaceAddConstraint(space, cpPivotJointNew2(staticBody, smallGear, cpv(-160, -160), cpvzero));
150 
151     // add big gear
152     cpBody* bigGear = cpSpaceAddBody(space, cpBodyNew(40.0f, cpMomentForCircle(40.0f, 160, 0, cpvzero)));
153     cpBodySetPos(bigGear, cpv(80, -160));
154     cpBodySetAngle(bigGear, M_PI_2);
155 
156     shape = cpSpaceAddShape(space, cpCircleShapeNew(bigGear, 160.0f, cpvzero));
157     cpShapeSetLayers(shape, 0);
158 
159     cpSpaceAddConstraint(space, cpPivotJointNew2(staticBody, bigGear, cpv(80, -160), cpvzero));
160 
161     // connect the plunger to the small gear.
162     cpSpaceAddConstraint(space, cpPinJointNew(smallGear, plunger, cpv(80, 0), cpv(0, 0)));
163 
164     // connect the gears.
165     cpSpaceAddConstraint(space, cpGearJointNew(smallGear, bigGear, -M_PI_2, -2.0f));
166 
167     // feeder mechanism
168     cpFloat bottom = -300.0f;
169     cpFloat top    = 32.0f;
170     cpBody* feeder = cpSpaceAddBody(space, cpBodyNew(1.0f, cpMomentForSegment(1.0f, cpv(-224.0f, bottom), cpv(-224.0f, top))));
171     cpBodySetPos(feeder, cpv(-224, (bottom + top) / 2.0f));
172 
173     cpFloat len = top - bottom;
174     shape = cpSpaceAddShape(space, cpSegmentShapeNew(feeder, cpv(0.0f, len / 2.0f), cpv(0.0f, -len / 2.0f), 20.0f));
175     cpShapeSetLayers(shape, GRABABLE_MASK_BIT);
176 
177     cpSpaceAddConstraint(space, cpPivotJointNew2(staticBody, feeder, cpv(-224.0f, bottom), cpv(0.0f, -len / 2.0f)));
178     cpVect anchr = cpBodyWorld2Local(feeder, cpv(-224.0f, -160.0f));
179     cpSpaceAddConstraint(space, cpPinJointNew(feeder, smallGear, anchr, cpv(0.0f, 80.0f)));
180 
181     // motorize the second gear
182     motor = cpSpaceAddConstraint(space, cpSimpleMotorNew(staticBody, bigGear, 3.0f));
183 
184     return space;
185 }
186 
187 void destroy(cpSpace* space)
188 {
189     ChipmunkDemoFreeSpaceChildren(space);
190     cpSpaceFree(space);
191 }
192 
193 ChipmunkDemo Pump = {
194     "Pump",
195     1.0 / 120.0,
196     &init,
197     &update,
198     &ChipmunkDemoDefaultDrawImpl,
199     &destroy,
200 };