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.Convex;
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 enum DENSITY = (1.0 / 10000.0);
37 
38 static cpShape* shape;
39 
40 static void update(cpSpace* space, double dt)
41 {
42     cpFloat tolerance = 2.0;
43 
44     if (ChipmunkDemoRightClick && cpShapeNearestPointQuery(shape, ChipmunkDemoMouse, null) > tolerance)
45     {
46         cpBody* body_ = cpShapeGetBody(shape);
47         int count    = cpPolyShapeGetNumVerts(shape);
48 
49         // Allocate the space for the new vertexes on the stack.
50         cpVect* verts = cast(cpVect*)alloca((count + 1) * cpVect.sizeof);
51 
52         for (int i = 0; i < count; i++)
53         {
54             verts[i] = cpPolyShapeGetVert(shape, i);
55         }
56 
57         verts[count] = cpBodyWorld2Local(body_, ChipmunkDemoMouse);
58 
59         // This function builds a convex hull for the vertexes.
60         // Because the result array is null, it will reduce the input array instead.
61         int hullCount = cpConvexHull(count + 1, verts, null, null, tolerance);
62 
63         // Figure out how much to shift the body_ by.
64         cpVect centroid = cpCentroidForPoly(hullCount, verts);
65 
66         // Recalculate the body_ properties to match the updated shape.
67         cpFloat mass = cpAreaForPoly(hullCount, verts) * DENSITY;
68         cpBodySetMass(body_, mass);
69         cpBodySetMoment(body_, cpMomentForPoly(mass, hullCount, verts, cpvneg(centroid)));
70         cpBodySetPos(body_, cpBodyLocal2World(body_, centroid));
71 
72         // Use the setter function from chipmunk_unsafe.h.
73         // You could also remove and recreate the shape if you wanted.
74         cpPolyShapeSetVerts(shape, hullCount, verts, cpvneg(centroid));
75     }
76 
77     cpSpaceStep(space, dt);
78 }
79 
80 static cpSpace* init()
81 {
82     ChipmunkDemoMessageString = "Right click and drag to change the blocks's shape.".dup;
83 
84     cpSpace* space = cpSpaceNew();
85     cpSpaceSetIterations(space, 30);
86     cpSpaceSetGravity(space, cpv(0, -500));
87     cpSpaceSetSleepTimeThreshold(space, 0.5f);
88     cpSpaceSetCollisionSlop(space, 0.5f);
89 
90     cpBody* body_;
91     cpBody* staticBody = cpSpaceGetStaticBody(space);
92 
93     // Create segments around the edge of the screen.
94     shape = cpSpaceAddShape(space, cpSegmentShapeNew(staticBody, cpv(-320, -240), cpv(320, -240), 0.0f));
95     cpShapeSetElasticity(shape, 1.0f);
96     cpShapeSetFriction(shape, 1.0f);
97     cpShapeSetLayers(shape, NOT_GRABABLE_MASK);
98 
99     cpFloat width  = 50.0f;
100     cpFloat height = 70.0f;
101     cpFloat mass   = width * height * DENSITY;
102     cpFloat moment = cpMomentForBox(mass, width, height);
103 
104     body_ = cpSpaceAddBody(space, cpBodyNew(mass, moment));
105 
106     shape = cpSpaceAddShape(space, cpBoxShapeNew(body_, width, height));
107     cpShapeSetFriction(shape, 0.6f);
108 
109     return space;
110 }
111 
112 static void destroy(cpSpace* space)
113 {
114     ChipmunkDemoFreeSpaceChildren(space);
115     cpSpaceFree(space);
116 }
117 
118 ChipmunkDemo Convex = {
119     "Convex.",
120     1.0 / 60.0,
121     &init,
122     &update,
123     &ChipmunkDemoDefaultDrawImpl,
124     &destroy,
125 };