4
|
1
|
|
2 // written in the D programming language
|
|
3
|
|
4 module chipmunkd.cpSpaceQuery;
|
|
5
|
|
6 import chipmunkd.chipmunk;
|
15
|
7 import chipmunkd.chipmunk_types;
|
4
|
8
|
|
9 struct pointQueryContext {
|
|
10 cpLayers layers;
|
|
11 cpGroup group;
|
|
12 cpSpacePointQueryFunc func;
|
|
13 void *data;
|
|
14 }
|
|
15
|
|
16 static void
|
|
17 pointQueryHelper(cpVect *point, cpShape *shape, pointQueryContext *context)
|
|
18 {
|
|
19 if(
|
|
20 !(shape.group && context.group == shape.group) && (context.layers&shape.layers) &&
|
|
21 cpShapePointQuery(shape, *point)
|
|
22 ){
|
|
23 context.func(shape, context.data);
|
|
24 }
|
|
25 }
|
|
26
|
|
27 void
|
|
28 cpSpacePointQuery(cpSpace *space, cpVect point, cpLayers layers, cpGroup group, cpSpacePointQueryFunc func, void *data)
|
|
29 {
|
|
30 pointQueryContext context = {layers, group, func, data};
|
23
|
31
|
|
32 cpBool locked = space.locked; space.locked = cpTrue; {
|
|
33 cpSpaceHashPointQuery(space.activeShapes, point, cast(cpSpaceHashQueryFunc)&pointQueryHelper, &context);
|
|
34 cpSpaceHashPointQuery(space.staticShapes, point, cast(cpSpaceHashQueryFunc)&pointQueryHelper, &context);
|
|
35 } space.locked = locked;
|
4
|
36 }
|
|
37
|
|
38 static void
|
|
39 rememberLastPointQuery(cpShape *shape, cpShape **outShape)
|
|
40 {
|
|
41 if(!shape.sensor) *outShape = shape;
|
|
42 }
|
|
43
|
|
44 cpShape *
|
|
45 cpSpacePointQueryFirst(cpSpace *space, cpVect point, cpLayers layers, cpGroup group)
|
|
46 {
|
|
47 cpShape *shape = null;
|
|
48 cpSpacePointQuery(space, point, layers, group, cast(cpSpacePointQueryFunc)&rememberLastPointQuery, &shape);
|
|
49
|
|
50 return shape;
|
|
51 }
|
|
52
|
|
53 void
|
|
54 cpSpaceEachBody(cpSpace *space, cpSpaceBodyIterator func, void *data)
|
|
55 {
|
|
56 cpArray *bodies = space.bodies;
|
|
57
|
|
58 for(int i=0; i<bodies.num; i++)
|
|
59 func(cast(cpBody *)bodies.arr[i], data);
|
|
60 }
|
|
61
|
|
62 //#pragma mark Segment Query Functions
|
|
63
|
|
64 struct segQueryContext {
|
|
65 cpVect start, end;
|
|
66 cpLayers layers;
|
|
67 cpGroup group;
|
|
68 cpSpaceSegmentQueryFunc func;
|
|
69 }
|
|
70
|
|
71 static cpFloat
|
|
72 segQueryFunc(segQueryContext *context, cpShape *shape, void *data)
|
|
73 {
|
|
74 cpSegmentQueryInfo info;
|
|
75
|
|
76 if(
|
|
77 !(shape.group && context.group == shape.group) && (context.layers&shape.layers) &&
|
|
78 cpShapeSegmentQuery(shape, context.start, context.end, &info)
|
|
79 ){
|
|
80 context.func(shape, info.t, info.n, data);
|
|
81 }
|
|
82
|
|
83 return 1.0f;
|
|
84 }
|
|
85
|
|
86 void
|
|
87 cpSpaceSegmentQuery(cpSpace *space, cpVect start, cpVect end, cpLayers layers, cpGroup group, cpSpaceSegmentQueryFunc func, void *data)
|
|
88 {
|
|
89 segQueryContext context = {
|
|
90 start, end,
|
|
91 layers, group,
|
|
92 func,
|
|
93 };
|
|
94
|
23
|
95 cpBool locked = space.locked; space.locked = cpTrue; {
|
|
96 cpSpaceHashSegmentQuery(space.staticShapes, &context, start, end, 1.0f, cast(cpSpaceHashSegmentQueryFunc)&segQueryFunc, data);
|
|
97 cpSpaceHashSegmentQuery(space.activeShapes, &context, start, end, 1.0f, cast(cpSpaceHashSegmentQueryFunc)&segQueryFunc, data);
|
|
98 } space.locked = locked;
|
4
|
99 }
|
|
100
|
|
101 struct segQueryFirstContext {
|
|
102 cpVect start, end;
|
|
103 cpLayers layers;
|
|
104 cpGroup group;
|
|
105 }
|
|
106
|
|
107 static cpFloat
|
|
108 segQueryFirst(segQueryFirstContext *context, cpShape *shape, cpSegmentQueryInfo *_out)
|
|
109 {
|
|
110 cpSegmentQueryInfo info;
|
|
111
|
|
112 if(
|
|
113 !(shape.group && context.group == shape.group) &&
|
|
114 (context.layers&shape.layers) &&
|
|
115 !shape.sensor &&
|
|
116 cpShapeSegmentQuery(shape, context.start, context.end, &info) &&
|
|
117 info.t < _out.t
|
|
118 ){
|
|
119 *_out = info;
|
|
120 }
|
|
121
|
|
122 return _out.t;
|
|
123 }
|
|
124
|
|
125 cpShape *
|
|
126 cpSpaceSegmentQueryFirst(cpSpace *space, cpVect start, cpVect end, cpLayers layers, cpGroup group, cpSegmentQueryInfo *_out)
|
|
127 {
|
|
128 cpSegmentQueryInfo info = {null, 1.0f, cpvzero};
|
|
129 if(_out){
|
|
130 (*_out) = info;
|
|
131 } else {
|
|
132 _out = &info;
|
|
133 }
|
|
134
|
|
135 segQueryFirstContext context = {
|
|
136 start, end,
|
|
137 layers, group
|
|
138 };
|
|
139
|
|
140 cpSpaceHashSegmentQuery(space.staticShapes, &context, start, end, 1.0f, cast(cpSpaceHashSegmentQueryFunc)&segQueryFirst, _out);
|
|
141 cpSpaceHashSegmentQuery(space.activeShapes, &context, start, end, _out.t, cast(cpSpaceHashSegmentQueryFunc)&segQueryFirst, _out);
|
|
142
|
|
143 return _out.shape;
|
|
144 }
|
|
145
|
|
146 //#pragma mark BB Query functions
|
|
147
|
|
148 struct bbQueryContext {
|
|
149 cpLayers layers;
|
|
150 cpGroup group;
|
|
151 cpSpaceBBQueryFunc func;
|
|
152 void *data;
|
|
153 }
|
|
154
|
|
155 static void
|
|
156 bbQueryHelper(cpBB *bb, cpShape *shape, bbQueryContext *context)
|
|
157 {
|
|
158 if(
|
|
159 !(shape.group && context.group == shape.group) && (context.layers&shape.layers) &&
|
|
160 cpBBintersects(*bb, shape.bb)
|
|
161 ){
|
|
162 context.func(shape, context.data);
|
|
163 }
|
|
164 }
|
|
165
|
|
166 void
|
|
167 cpSpaceBBQuery(cpSpace *space, cpBB bb, cpLayers layers, cpGroup group, cpSpaceBBQueryFunc func, void *data)
|
|
168 {
|
|
169 bbQueryContext context = {layers, group, func, data};
|
23
|
170
|
|
171 cpBool locked = space.locked; space.locked = cpTrue; {
|
4
|
172 cpSpaceHashQuery(space.activeShapes, &bb, bb, cast(cpSpaceHashQueryFunc)&bbQueryHelper, &context);
|
|
173 cpSpaceHashQuery(space.staticShapes, &bb, bb, cast(cpSpaceHashQueryFunc)&bbQueryHelper, &context);
|
23
|
174 } space.locked = locked;
|
4
|
175 }
|
23
|
176
|
|
177 //#pragma mark Shape Query Functions
|
|
178
|
|
179 struct shapeQueryContext {
|
|
180 cpSpaceShapeQueryFunc func;
|
|
181 void *data;
|
|
182 cpBool anyCollision;
|
|
183 }
|
|
184
|
|
185 // Callback from the spatial hash.
|
|
186 static void
|
|
187 shapeQueryHelper(cpShape *a, cpShape *b, shapeQueryContext *context)
|
|
188 {
|
|
189 // Reject any of the simple cases
|
|
190 if(
|
|
191 (a.group && a.group == b.group) ||
|
|
192 !(a.layers & b.layers) ||
|
|
193 a.sensor || b.sensor
|
|
194 ) return;
|
|
195
|
|
196 cpContact contacts[CP_MAX_CONTACTS_PER_ARBITER];
|
|
197 int numContacts = 0;
|
|
198
|
|
199 // Shape 'a' should have the lower shape type. (required by cpCollideShapes() )
|
|
200 if(a.klass.type <= b.klass.type){
|
|
201 numContacts = cpCollideShapes(a, b, contacts.ptr);
|
|
202 } else {
|
|
203 numContacts = cpCollideShapes(b, a, contacts.ptr);
|
|
204 for(int i=0; i<numContacts; i++) contacts[i].n = cpvneg(contacts[i].n);
|
|
205 }
|
|
206
|
|
207 if(numContacts){
|
|
208 context.anyCollision = cpTrue;
|
|
209
|
|
210 if(context.func){
|
|
211 cpContactPointSet set; set.count = numContacts;
|
|
212 for(int i=0; i<set.count; i++){
|
|
213 set.points[i].point = contacts[i].p;
|
|
214 set.points[i].normal = contacts[i].p;
|
|
215 set.points[i].dist = contacts[i].dist;
|
|
216 }
|
|
217
|
|
218 context.func(b, &set, context.data);
|
|
219 }
|
|
220 }
|
|
221 }
|
|
222
|
|
223 cpBool
|
|
224 cpSpaceShapeQuery(cpSpace *space, cpShape *shape, cpSpaceShapeQueryFunc func, void *data)
|
|
225 {
|
|
226 cpBB bb = cpShapeCacheBB(shape);
|
|
227 shapeQueryContext context = {func, data, cpFalse};
|
|
228
|
|
229 cpBool locked = space.locked; space.locked = cpTrue; {
|
|
230 cpSpaceHashQuery(space.activeShapes, shape, bb, cast(cpSpaceHashQueryFunc)&shapeQueryHelper, &context);
|
|
231 cpSpaceHashQuery(space.staticShapes, shape, bb, cast(cpSpaceHashQueryFunc)&shapeQueryHelper, &context);
|
|
232 } space.locked = locked;
|
|
233
|
|
234 return context.anyCollision;
|
|
235 }
|