Mercurial > projects > chipmunkd
annotate trunk/chipmunkd/cpPolyShape.d @ 28:4541ca17975b
use __gshared as chipmunk heavily relies on globals and D would otherwise make them TLS
author | Extrawurst |
---|---|
date | Mon, 13 Dec 2010 21:40:56 +0100 |
parents | 4ceef5833c8c |
children |
rev | line source |
---|---|
4 | 1 |
2 // written in the D programming language | |
3 | |
4 module chipmunkd.cpPolyShape; | |
5 | |
6 import chipmunkd.chipmunk; | |
7 | |
8 // Axis structure used by cpPolyShape. | |
9 struct cpPolyShapeAxis{ | |
10 // normal | |
11 cpVect n; | |
12 // distance from origin | |
13 cpFloat d; | |
14 } | |
15 | |
16 // Convex polygon shape structure. | |
17 struct cpPolyShape{ | |
18 cpShape shape; | |
19 | |
20 // Vertex and axis lists. | |
21 int numVerts; | |
22 cpVect *verts; | |
23 cpPolyShapeAxis *axes; | |
24 | |
25 // Transformed vertex and axis lists. | |
26 cpVect *tVerts; | |
27 cpPolyShapeAxis *tAxes; | |
28 } | |
29 | |
30 //// Basic allocation functions. | |
31 //cpPolyShape *cpPolyShapeAlloc(void); | |
32 //cpPolyShape *cpPolyShapeInit(cpPolyShape *poly, cpBody *body, int numVerts, cpVect *verts, cpVect offset); | |
33 //cpShape *cpPolyShapeNew(cpBody *body, int numVerts, cpVect *verts, cpVect offset); | |
34 // | |
35 //cpPolyShape *cpBoxShapeInit(cpPolyShape *poly, cpBody *body, cpFloat width, cpFloat height); | |
36 //cpShape *cpBoxShapeNew(cpBody *body, cpFloat width, cpFloat height); | |
37 // | |
38 //// Check that a set of vertexes has a correct winding and that they are convex | |
39 //cpBool cpPolyValidate(cpVect *verts, int numVerts); | |
40 // | |
41 //int cpPolyShapeGetNumVerts(cpShape *shape); | |
42 //cpVect cpPolyShapeGetVert(cpShape *shape, int idx); | |
43 | |
44 // *** inlined utility functions | |
45 | |
46 // Returns the minimum distance of the polygon to the axis. | |
47 static cpFloat | |
48 cpPolyShapeValueOnAxis(const cpPolyShape *poly, const cpVect n, const cpFloat d) | |
49 { | |
50 const cpVect *verts = poly.tVerts; | |
51 cpFloat min = cpvdot(n, verts[0]); | |
52 | |
53 int i; | |
54 for(i=1; i<poly.numVerts; i++) | |
55 min = cpfmin(min, cpvdot(n, verts[i])); | |
56 | |
57 return min - d; | |
58 } | |
59 | |
60 // Returns true if the polygon contains the vertex. | |
61 static cpBool | |
62 cpPolyShapeContainsVert(const cpPolyShape *poly, const cpVect v) | |
63 { | |
64 const cpPolyShapeAxis *axes = poly.tAxes; | |
65 | |
66 int i; | |
67 for(i=0; i<poly.numVerts; i++){ | |
68 cpFloat dist = cpvdot(axes[i].n, v) - axes[i].d; | |
69 if(dist > 0.0f) return cpFalse; | |
70 } | |
71 | |
72 return cpTrue; | |
73 } | |
74 | |
75 // Same as cpPolyShapeContainsVert() but ignores faces pointing away from the normal. | |
76 static cpBool | |
77 cpPolyShapeContainsVertPartial(const cpPolyShape *poly, const cpVect v, const cpVect n) | |
78 { | |
79 const cpPolyShapeAxis *axes = poly.tAxes; | |
80 | |
81 int i; | |
82 for(i=0; i<poly.numVerts; i++){ | |
83 if(cpvdot(axes[i].n, n) < 0.0f) continue; | |
84 cpFloat dist = cpvdot(axes[i].n, v) - axes[i].d; | |
85 if(dist > 0.0f) return cpFalse; | |
86 } | |
87 | |
88 return cpTrue; | |
89 } | |
90 | |
91 // cpPolyShape.c --------------------------------- | |
92 | |
93 | |
94 cpPolyShape * | |
95 cpPolyShapeAlloc() | |
96 { | |
97 return cast(cpPolyShape *)cpcalloc(1, cpPolyShape.sizeof); | |
98 } | |
99 | |
100 static void | |
101 cpPolyShapeTransformVerts(cpPolyShape *poly, cpVect p, cpVect rot) | |
102 { | |
103 cpVect *src = poly.verts; | |
104 cpVect *dst = poly.tVerts; | |
105 | |
106 for(int i=0; i<poly.numVerts; i++) | |
107 dst[i] = cpvadd(p, cpvrotate(src[i], rot)); | |
108 } | |
109 | |
110 static void | |
111 cpPolyShapeTransformAxes(cpPolyShape *poly, cpVect p, cpVect rot) | |
112 { | |
113 cpPolyShapeAxis *src = poly.axes; | |
114 cpPolyShapeAxis *dst = poly.tAxes; | |
115 | |
116 for(int i=0; i<poly.numVerts; i++){ | |
117 cpVect n = cpvrotate(src[i].n, rot); | |
118 dst[i].n = n; | |
119 dst[i].d = cpvdot(p, n) + src[i].d; | |
120 } | |
121 } | |
122 | |
123 static cpBB | |
124 cpPolyShapeCacheData(cpShape *shape, cpVect p, cpVect rot) | |
125 { | |
126 cpPolyShape *poly = cast(cpPolyShape *)shape; | |
127 | |
128 cpFloat l, b, r, t; | |
129 | |
130 cpPolyShapeTransformAxes(poly, p, rot); | |
131 cpPolyShapeTransformVerts(poly, p, rot); | |
132 | |
133 cpVect *verts = poly.tVerts; | |
134 l = r = verts[0].x; | |
135 b = t = verts[0].y; | |
136 | |
137 // TODO do as part of cpPolyShapeTransformVerts? | |
138 for(int i=1; i<poly.numVerts; i++){ | |
139 cpVect v = verts[i]; | |
140 | |
141 l = cpfmin(l, v.x); | |
142 r = cpfmax(r, v.x); | |
143 | |
144 b = cpfmin(b, v.y); | |
145 t = cpfmax(t, v.y); | |
146 } | |
147 | |
148 return cpBBNew(l, b, r, t); | |
149 } | |
150 | |
151 static void | |
152 cpPolyShapeDestroy(cpShape *shape) | |
153 { | |
154 cpPolyShape *poly = cast(cpPolyShape *)shape; | |
155 | |
156 cpfree(poly.verts); | |
157 cpfree(poly.tVerts); | |
158 | |
159 cpfree(poly.axes); | |
160 cpfree(poly.tAxes); | |
161 } | |
162 | |
163 static cpBool | |
164 cpPolyShapePointQuery(cpShape *shape, cpVect p){ | |
165 return cpBBcontainsVect(shape.bb, p) && cpPolyShapeContainsVert(cast(cpPolyShape *)shape, p); | |
166 } | |
167 | |
168 static void | |
169 cpPolyShapeSegmentQuery(cpShape *shape, cpVect a, cpVect b, cpSegmentQueryInfo *info) | |
170 { | |
171 cpPolyShape *poly = cast(cpPolyShape *)shape; | |
172 cpPolyShapeAxis *axes = poly.tAxes; | |
173 cpVect *verts = poly.tVerts; | |
174 int numVerts = poly.numVerts; | |
175 | |
176 for(int i=0; i<numVerts; i++){ | |
177 cpVect n = axes[i].n; | |
178 cpFloat an = cpvdot(a, n); | |
179 if(axes[i].d > an) continue; | |
180 | |
181 cpFloat bn = cpvdot(b, n); | |
182 cpFloat t = (axes[i].d - an)/(bn - an); | |
183 if(t < 0.0f || 1.0f < t) continue; | |
184 | |
185 cpVect point = cpvlerp(a, b, t); | |
186 cpFloat dt = -cpvcross(n, point); | |
187 cpFloat dtMin = -cpvcross(n, verts[i]); | |
188 cpFloat dtMax = -cpvcross(n, verts[(i+1)%numVerts]); | |
189 | |
190 if(dtMin <= dt && dt <= dtMax){ | |
191 info.shape = shape; | |
192 info.t = t; | |
193 info.n = n; | |
194 } | |
195 } | |
196 } | |
197 | |
28
4541ca17975b
use __gshared as chipmunk heavily relies on globals and D would otherwise make them TLS
Extrawurst
parents:
23
diff
changeset
|
198 __gshared /+const+/ cpShapeClass polyClass = { |
4 | 199 cpShapeType.CP_POLY_SHAPE, |
200 &cpPolyShapeCacheData, | |
201 &cpPolyShapeDestroy, | |
202 &cpPolyShapePointQuery, | |
203 &cpPolyShapeSegmentQuery, | |
204 }; | |
205 | |
206 cpBool | |
23 | 207 cpPolyValidate(in cpVect *verts, in int numVerts) |
4 | 208 { |
209 for(int i=0; i<numVerts; i++){ | |
210 cpVect a = verts[i]; | |
211 cpVect b = verts[(i+1)%numVerts]; | |
212 cpVect c = verts[(i+2)%numVerts]; | |
213 | |
214 if(cpvcross(cpvsub(b, a), cpvsub(c, b)) > 0.0f) | |
215 return cpFalse; | |
216 } | |
217 | |
218 return cpTrue; | |
219 } | |
220 | |
221 int | |
222 cpPolyShapeGetNumVerts(cpShape *shape) | |
223 { | |
224 assert(shape.klass == &polyClass, "Shape is not a poly shape."); | |
225 return (cast(cpPolyShape *)shape).numVerts; | |
226 } | |
227 | |
228 cpVect | |
229 cpPolyShapeGetVert(cpShape *shape, int idx) | |
230 { | |
231 assert(shape.klass == &polyClass, "Shape is not a poly shape."); | |
232 assert(0 <= idx && idx < cpPolyShapeGetNumVerts(shape), "Index out of range."); | |
233 | |
234 return (cast(cpPolyShape *)shape).verts[idx]; | |
235 } | |
236 | |
237 | |
238 static void | |
239 setUpVerts(cpPolyShape *poly, int numVerts, cpVect *verts, cpVect offset) | |
240 { | |
241 poly.numVerts = numVerts; | |
242 | |
243 poly.verts = cast(cpVect *)cpcalloc(numVerts, cpVect.sizeof); | |
244 poly.tVerts = cast(cpVect *)cpcalloc(numVerts, cpVect.sizeof); | |
245 poly.axes = cast(cpPolyShapeAxis *)cpcalloc(numVerts, (cpPolyShapeAxis).sizeof); | |
246 poly.tAxes = cast(cpPolyShapeAxis *)cpcalloc(numVerts, (cpPolyShapeAxis).sizeof); | |
247 | |
248 for(int i=0; i<numVerts; i++){ | |
249 cpVect a = cpvadd(offset, verts[i]); | |
250 cpVect b = cpvadd(offset, verts[(i+1)%numVerts]); | |
251 cpVect n = cpvnormalize(cpvperp(cpvsub(b, a))); | |
252 | |
253 poly.verts[i] = a; | |
254 poly.axes[i].n = n; | |
255 poly.axes[i].d = cpvdot(n, a); | |
256 } | |
257 } | |
258 | |
259 cpPolyShape * | |
260 cpPolyShapeInit(cpPolyShape *poly, cpBody *_body, int numVerts, cpVect *verts, cpVect offset) | |
261 { | |
262 // Fail if the user attempts to pass a concave poly, or a bad winding. | |
263 assert(cpPolyValidate(verts, numVerts), "Polygon is concave or has a reversed winding."); | |
264 | |
265 setUpVerts(poly, numVerts, verts, offset); | |
266 cpShapeInit(cast(cpShape *)poly, &polyClass, _body); | |
267 | |
268 return poly; | |
269 } | |
270 | |
271 cpShape * | |
272 cpPolyShapeNew(cpBody *_body, int numVerts, cpVect *verts, cpVect offset) | |
273 { | |
274 return cast(cpShape *)cpPolyShapeInit(cpPolyShapeAlloc(), _body, numVerts, verts, offset); | |
275 } | |
276 | |
277 cpPolyShape * | |
278 cpBoxShapeInit(cpPolyShape *poly, cpBody *_body, cpFloat width, cpFloat height) | |
279 { | |
280 cpFloat hw = width/2.0f; | |
281 cpFloat hh = height/2.0f; | |
282 | |
283 cpVect verts[] = [ | |
284 cpv(-hw,-hh), | |
285 cpv(-hw, hh), | |
286 cpv( hw, hh), | |
287 cpv( hw,-hh), | |
288 ]; | |
289 | |
290 return cpPolyShapeInit(poly, _body, 4, verts.ptr, cpvzero); | |
291 } | |
292 | |
293 cpShape * | |
294 cpBoxShapeNew(cpBody *_body, cpFloat width, cpFloat height) | |
295 { | |
296 return cast(cpShape *)cpBoxShapeInit(cpPolyShapeAlloc(), _body, width, height); | |
297 } | |
298 | |
299 // Unsafe API (chipmunk_unsafe.h) | |
300 | |
301 void | |
302 cpPolyShapeSetVerts(cpShape *shape, int numVerts, cpVect *verts, cpVect offset) | |
303 { | |
304 assert(shape.klass == &polyClass, "Shape is not a poly shape."); | |
305 cpPolyShapeDestroy(shape); | |
306 setUpVerts(cast(cpPolyShape *)shape, numVerts, verts, offset); | |
307 } | |
308 | |
309 | |
310 |