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.Query;
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 cpVect QUERY_START = { 0, 0 };
37 
38 void update(cpSpace* space, double dt)
39 {
40     cpSpaceStep(space, dt);
41 
42     if (ChipmunkDemoRightClick)
43     {
44         QUERY_START = ChipmunkDemoMouse;
45     }
46 
47     cpVect start = QUERY_START;
48     cpVect end   = ChipmunkDemoMouse;
49     ChipmunkDebugDrawSegment(start, end, RGBAColor(0, 1, 0, 1));
50 
51     ChipmunkDemoPrintString("Query: Dist(%f) Point%s, ", cpvdist(start, end), cpvstr(end));
52 
53     cpSegmentQueryInfo segInfo = {};
54 
55     if (cpSpaceSegmentQueryFirst(space, start, end, CP_ALL_LAYERS, CP_NO_GROUP, &segInfo))
56     {
57         cpVect point = cpSegmentQueryHitPoint(start, end, segInfo);
58 
59         // Draw blue over the occluded part of the query
60         ChipmunkDebugDrawSegment(point, end, RGBAColor(0, 0, 1, 1));
61 
62         // Draw a little red surface normal
63         ChipmunkDebugDrawSegment(point, cpvadd(point, cpvmult(segInfo.n, 16)), RGBAColor(1, 0, 0, 1));
64 
65         // Draw a little red dot on the hit point.
66         ChipmunkDebugDrawDot(3, point, RGBAColor(1, 0, 0, 1));
67 
68         ChipmunkDemoPrintString("Segment Query: Dist(%f) Normal%s", cpSegmentQueryHitDist(start, end, segInfo), cpvstr(segInfo.n));
69     }
70     else
71     {
72         ChipmunkDemoPrintString("Segment Query (None)");
73     }
74 
75     cpNearestPointQueryInfo nearestInfo = {};
76     cpSpaceNearestPointQueryNearest(space, ChipmunkDemoMouse, 100.0, CP_ALL_LAYERS, CP_NO_GROUP, &nearestInfo);
77 
78     if (nearestInfo.shape)
79     {
80         // Draw a grey line to the closest shape.
81         ChipmunkDebugDrawDot(3, ChipmunkDemoMouse, RGBAColor(0.5, 0.5, 0.5, 1.0));
82         ChipmunkDebugDrawSegment(ChipmunkDemoMouse, nearestInfo.p, RGBAColor(0.5, 0.5, 0.5, 1.0));
83 
84         // Draw a red bounding box around the shape under the mouse.
85         if (nearestInfo.d < 0)
86             ChipmunkDebugDrawBB(cpShapeGetBB(nearestInfo.shape), RGBAColor(1, 0, 0, 1));
87     }
88 }
89 
90 cpSpace* init()
91 {
92     QUERY_START = cpvzero;
93 
94     cpSpace* space = cpSpaceNew();
95     cpSpaceSetIterations(space, 5);
96 
97     {
98         // add a fat segment
99         cpFloat mass   = 1.0f;
100         cpFloat length = 100.0f;
101         cpVect  a      = cpv(-length / 2.0f, 0.0f), b = cpv(length / 2.0f, 0.0f);
102 
103         cpBody* body_ = cpSpaceAddBody(space, cpBodyNew(mass, cpMomentForSegment(mass, a, b)));
104         cpBodySetPos(body_, cpv(0.0f, 100.0f));
105 
106         cpSpaceAddShape(space, cpSegmentShapeNew(body_, a, b, 20.0f));
107     }
108 
109     {
110         // add a static segment
111         cpSpaceAddShape(space, cpSegmentShapeNew(cpSpaceGetStaticBody(space), cpv(0, 300), cpv(300, 0), 0.0f));
112     }
113 
114     {
115         // add a pentagon
116         cpFloat mass        = 1.0f;
117         const int NUM_VERTS = 5;
118 
119         cpVect verts[NUM_VERTS];
120 
121         for (int i = 0; i < NUM_VERTS; i++)
122         {
123             cpFloat angle = -2 * M_PI * i / (cast(cpFloat)NUM_VERTS);
124             verts[i] = cpv(30 * cos(angle), 30 * sin(angle));
125         }
126 
127         cpBody* body_ = cpSpaceAddBody(space, cpBodyNew(mass, cpMomentForPoly(mass, NUM_VERTS, verts.ptr, cpvzero)));
128         cpBodySetPos(body_, cpv(50.0f, 30.0f));
129 
130         cpSpaceAddShape(space, cpPolyShapeNew2(body_, NUM_VERTS, verts.ptr, cpvzero, 10.0f));
131     }
132 
133     {
134         // add a circle
135         cpFloat mass = 1.0f;
136         cpFloat r    = 20.0f;
137 
138         cpBody* body_ = cpSpaceAddBody(space, cpBodyNew(mass, cpMomentForCircle(mass, 0.0f, r, cpvzero)));
139         cpBodySetPos(body_, cpv(100.0f, 100.0f));
140 
141         cpSpaceAddShape(space, cpCircleShapeNew(body_, r, cpvzero));
142     }
143 
144     return space;
145 }
146 
147 void destroy(cpSpace* space)
148 {
149     ChipmunkDemoFreeSpaceChildren(space);
150     cpSpaceFree(space);
151 }
152 
153 ChipmunkDemo Query = {
154     "Segment Query",
155     1.0 / 60.0,
156     &init,
157     &update,
158     &ChipmunkDemoDefaultDrawImpl,
159     &destroy,
160 };