20
|
1
|
|
2 // written in the D programming language
|
|
3
|
16
|
4 module drawSpace;
|
|
5
|
|
6 import derelict.opengl.gl;
|
|
7
|
|
8 import chipmunkd.chipmunk;
|
|
9
|
|
10 import std.math:PI;
|
|
11 import std.stdio;
|
|
12
|
|
13 struct drawSpaceOptions {
|
|
14 int drawHash;
|
|
15 int drawBBs;
|
|
16 int drawShapes;
|
|
17 float collisionPointSize;
|
|
18 float bodyPointSize;
|
|
19 float lineThickness;
|
|
20 }
|
|
21
|
|
22 /*
|
|
23 IMPORTANT - READ ME!
|
|
24
|
|
25 This file sets up a simple interface that the individual demos can use to get
|
|
26 a Chipmunk space running and draw what's in it. In order to keep the Chipmunk
|
|
27 examples clean and simple, they contain no graphics code. All drawing is done
|
|
28 by accessing the Chipmunk structures at a very low level. It is NOT
|
|
29 recommended to write a game or application this way as it does not scale
|
|
30 beyond simple shape drawing and is very dependent on implementation details
|
|
31 about Chipmunk which may change with little to no warning.
|
|
32 */
|
|
33
|
|
34 enum float[3] LINE_COLOR = [0,0,0];
|
|
35 enum float[3] COLLISION_COLOR = [1,0,0];
|
|
36 enum float[3] BODY_COLOR = [0,0,1];
|
|
37
|
|
38 static void
|
|
39 glColor_from_pointer(void *ptr)
|
|
40 {
|
|
41 ulong val = cast(long)ptr;
|
|
42
|
|
43 // hash the pointer up nicely
|
|
44 val = (val+0x7ed55d16) + (val<<12);
|
|
45 val = (val^0xc761c23c) ^ (val>>19);
|
|
46 val = (val+0x165667b1) + (val<<5);
|
|
47 val = (val+0xd3a2646c) ^ (val<<9);
|
|
48 val = (val+0xfd7046c5) + (val<<3);
|
|
49 val = (val^0xb55a4f09) ^ (val>>16);
|
|
50
|
|
51 // GLfloat v = (GLfloat)val/(GLfloat)ULONG_MAX;
|
|
52 // v = 0.95f - v*0.15f;
|
|
53 //
|
|
54 // glColor3f(v, v, v);
|
|
55
|
|
56 GLubyte r = (val>>0) & 0xFF;
|
|
57 GLubyte g = (val>>8) & 0xFF;
|
|
58 GLubyte b = (val>>16) & 0xFF;
|
|
59
|
|
60 GLubyte max = r>g ? (r>b ? r : b) : (g>b ? g : b);
|
|
61
|
|
62 const int mult = 127;
|
|
63 const int add = 63;
|
|
64 r = cast(ubyte)((r*mult)/max + add);
|
|
65 g = cast(ubyte)((g*mult)/max + add);
|
|
66 b = cast(ubyte)((b*mult)/max + add);
|
|
67
|
|
68 glColor3ub(r, g, b);
|
|
69 }
|
|
70
|
|
71 static void
|
|
72 glColor_for_shape(cpShape *shape, cpSpace *space)
|
|
73 {
|
|
74 cpBody *_body = shape._body;
|
|
75 if(_body){
|
|
76 if(_body.node.next){
|
|
77 GLfloat v = 0.25f;
|
|
78 glColor3f(v,v,v);
|
|
79 return;
|
|
80 } else if(_body.node.idleTime > space.sleepTimeThreshold) {
|
|
81 GLfloat v = 0.9f;
|
|
82 glColor3f(v,v,v);
|
|
83 return;
|
|
84 }
|
|
85 }
|
|
86
|
|
87 glColor_from_pointer(shape);
|
|
88 }
|
|
89
|
|
90 enum GLfloat[] circleVAR = [
|
|
91 0.0000f, 1.0000f,
|
|
92 0.2588f, 0.9659f,
|
|
93 0.5000f, 0.8660f,
|
|
94 0.7071f, 0.7071f,
|
|
95 0.8660f, 0.5000f,
|
|
96 0.9659f, 0.2588f,
|
|
97 1.0000f, 0.0000f,
|
|
98 0.9659f, -0.2588f,
|
|
99 0.8660f, -0.5000f,
|
|
100 0.7071f, -0.7071f,
|
|
101 0.5000f, -0.8660f,
|
|
102 0.2588f, -0.9659f,
|
|
103 0.0000f, -1.0000f,
|
|
104 -0.2588f, -0.9659f,
|
|
105 -0.5000f, -0.8660f,
|
|
106 -0.7071f, -0.7071f,
|
|
107 -0.8660f, -0.5000f,
|
|
108 -0.9659f, -0.2588f,
|
|
109 -1.0000f, -0.0000f,
|
|
110 -0.9659f, 0.2588f,
|
|
111 -0.8660f, 0.5000f,
|
|
112 -0.7071f, 0.7071f,
|
|
113 -0.5000f, 0.8660f,
|
|
114 -0.2588f, 0.9659f,
|
|
115 0.0000f, 1.0000f,
|
|
116 0.0f, 0.0f, // For an extra line to see the rotation.
|
|
117 ];
|
|
118 enum int circleVAR_count = circleVAR.length / 2;
|
|
119
|
|
120 static void
|
|
121 drawCircleShape(cpBody *_body, cpCircleShape *circle, cpSpace *space)
|
|
122 {
|
|
123 glVertexPointer(2, GL_FLOAT, 0, circleVAR.ptr);
|
|
124
|
|
125 glPushMatrix(); {
|
|
126 cpVect center = circle.tc;
|
|
127 glTranslatef(center.x, center.y, 0.0f);
|
|
128 glRotatef(_body.a*180.0f/PI, 0.0f, 0.0f, 1.0f);
|
|
129 glScalef(circle.r, circle.r, 1.0f);
|
|
130
|
|
131 if(!circle.shape.sensor){
|
|
132 glColor_for_shape(cast(cpShape *)circle, space);
|
|
133 glDrawArrays(GL_TRIANGLE_FAN, 0, circleVAR_count - 1);
|
|
134 }
|
|
135
|
|
136 glColor3fv(LINE_COLOR.ptr);
|
|
137 glDrawArrays(GL_LINE_STRIP, 0, circleVAR_count);
|
|
138 } glPopMatrix();
|
|
139 }
|
|
140
|
|
141 enum GLfloat[] pillVAR = [
|
|
142 0.0000f, 1.0000f, 1.0f,
|
|
143 0.2588f, 0.9659f, 1.0f,
|
|
144 0.5000f, 0.8660f, 1.0f,
|
|
145 0.7071f, 0.7071f, 1.0f,
|
|
146 0.8660f, 0.5000f, 1.0f,
|
|
147 0.9659f, 0.2588f, 1.0f,
|
|
148 1.0000f, 0.0000f, 1.0f,
|
|
149 0.9659f, -0.2588f, 1.0f,
|
|
150 0.8660f, -0.5000f, 1.0f,
|
|
151 0.7071f, -0.7071f, 1.0f,
|
|
152 0.5000f, -0.8660f, 1.0f,
|
|
153 0.2588f, -0.9659f, 1.0f,
|
|
154 0.0000f, -1.0000f, 1.0f,
|
|
155
|
|
156 0.0000f, -1.0000f, 0.0f,
|
|
157 -0.2588f, -0.9659f, 0.0f,
|
|
158 -0.5000f, -0.8660f, 0.0f,
|
|
159 -0.7071f, -0.7071f, 0.0f,
|
|
160 -0.8660f, -0.5000f, 0.0f,
|
|
161 -0.9659f, -0.2588f, 0.0f,
|
|
162 -1.0000f, -0.0000f, 0.0f,
|
|
163 -0.9659f, 0.2588f, 0.0f,
|
|
164 -0.8660f, 0.5000f, 0.0f,
|
|
165 -0.7071f, 0.7071f, 0.0f,
|
|
166 -0.5000f, 0.8660f, 0.0f,
|
|
167 -0.2588f, 0.9659f, 0.0f,
|
|
168 0.0000f, 1.0000f, 0.0f,
|
|
169 ];
|
|
170 enum int pillVAR_count = pillVAR.length/3;
|
|
171
|
|
172 static void
|
|
173 drawSegmentShape(cpBody *_body, cpSegmentShape *seg, cpSpace *space)
|
|
174 {
|
|
175 cpVect a = seg.ta;
|
|
176 cpVect b = seg.tb;
|
|
177
|
|
178 if(seg.r){
|
|
179 glVertexPointer(3, GL_FLOAT, 0, pillVAR.ptr);
|
|
180 glPushMatrix(); {
|
|
181 cpVect d = cpvsub(b, a);
|
|
182 cpVect r = cpvmult(d, seg.r/cpvlength(d));
|
|
183
|
|
184 GLfloat matrix[] = [
|
|
185 r.x, r.y, 0.0f, 0.0f,
|
|
186 -r.y, r.x, 0.0f, 0.0f,
|
|
187 d.x, d.y, 0.0f, 0.0f,
|
|
188 a.x, a.y, 0.0f, 1.0f,
|
|
189 ];
|
|
190 glMultMatrixf(matrix.ptr);
|
|
191
|
|
192 if(!seg.shape.sensor){
|
|
193 glColor_for_shape(cast(cpShape *)seg, space);
|
|
194 glDrawArrays(GL_TRIANGLE_FAN, 0, pillVAR_count);
|
|
195 }
|
|
196
|
|
197 glColor3fv(LINE_COLOR.ptr);
|
|
198 glDrawArrays(GL_LINE_LOOP, 0, pillVAR_count);
|
|
199 } glPopMatrix();
|
|
200 } else {
|
|
201 glColor3fv(LINE_COLOR.ptr);
|
|
202 glBegin(GL_LINES); {
|
|
203 glVertex2f(a.x, a.y);
|
|
204 glVertex2f(b.x, b.y);
|
|
205 } glEnd();
|
|
206 }
|
|
207 }
|
|
208
|
|
209 static void
|
|
210 drawPolyShape(cpBody *_body, cpPolyShape *poly, cpSpace *space)
|
|
211 {
|
|
212 int count = poly.numVerts;
|
|
213 version(CP_USE_DOUBLES)
|
|
214 {
|
|
215 glVertexPointer(2, GL_DOUBLE, 0, poly.tVerts);
|
|
216 }
|
|
217 else
|
|
218 {
|
|
219 glVertexPointer(2, GL_FLOAT, 0, poly.tVerts);
|
|
220 }
|
|
221
|
|
222 if(!poly.shape.sensor){
|
|
223 glColor_for_shape(cast(cpShape *)poly, space);
|
|
224 glDrawArrays(GL_TRIANGLE_FAN, 0, count);
|
|
225 }
|
|
226
|
|
227 glColor3fv(LINE_COLOR.ptr);
|
|
228 glDrawArrays(GL_LINE_LOOP, 0, count);
|
|
229 }
|
|
230
|
|
231 static void
|
|
232 drawObject(cpShape *shape, cpSpace *space)
|
|
233 {
|
|
234 cpBody *_body = shape._body;
|
|
235
|
|
236 switch(shape.klass.type){
|
|
237 case cpShapeType.CP_CIRCLE_SHAPE:
|
|
238 drawCircleShape(_body, cast(cpCircleShape *)shape, space);
|
|
239 break;
|
|
240 case cpShapeType.CP_SEGMENT_SHAPE:
|
|
241 drawSegmentShape(_body, cast(cpSegmentShape *)shape, space);
|
|
242 break;
|
|
243 case cpShapeType.CP_POLY_SHAPE:
|
|
244 drawPolyShape(_body, cast(cpPolyShape *)shape, space);
|
|
245 break;
|
|
246 default:
|
|
247 writefln("Bad enumeration in drawObject().");
|
|
248 }
|
|
249 }
|
|
250
|
|
251 enum GLfloat[] springVAR = [
|
|
252 0.00f, 0.0f,
|
|
253 0.20f, 0.0f,
|
|
254 0.25f, 3.0f,
|
|
255 0.30f,-6.0f,
|
|
256 0.35f, 6.0f,
|
|
257 0.40f,-6.0f,
|
|
258 0.45f, 6.0f,
|
|
259 0.50f,-6.0f,
|
|
260 0.55f, 6.0f,
|
|
261 0.60f,-6.0f,
|
|
262 0.65f, 6.0f,
|
|
263 0.70f,-3.0f,
|
|
264 0.75f, 6.0f,
|
|
265 0.80f, 0.0f,
|
|
266 1.00f, 0.0f,
|
|
267 ];
|
|
268 enum int springVAR_count = springVAR.length / 2;
|
|
269
|
|
270 static void
|
|
271 drawSpring(cpDampedSpring *spring, cpBody *body_a, cpBody *body_b)
|
|
272 {
|
|
273 cpVect a = cpvadd(body_a.p, cpvrotate(spring.anchr1, body_a.rot));
|
|
274 cpVect b = cpvadd(body_b.p, cpvrotate(spring.anchr2, body_b.rot));
|
|
275
|
|
276 glPointSize(5.0f);
|
|
277 glBegin(GL_POINTS); {
|
|
278 glVertex2f(a.x, a.y);
|
|
279 glVertex2f(b.x, b.y);
|
|
280 } glEnd();
|
|
281
|
|
282 cpVect delta = cpvsub(b, a);
|
|
283
|
|
284 glVertexPointer(2, GL_FLOAT, 0, springVAR.ptr);
|
|
285 glPushMatrix(); {
|
|
286 GLfloat x = a.x;
|
|
287 GLfloat y = a.y;
|
|
288 GLfloat cos = delta.x;
|
|
289 GLfloat sin = delta.y;
|
|
290 GLfloat s = 1.0f/cpvlength(delta);
|
|
291
|
|
292 GLfloat matrix[] = [
|
|
293 cos, sin, 0.0f, 0.0f,
|
|
294 -sin*s, cos*s, 0.0f, 0.0f,
|
|
295 0.0f, 0.0f, 1.0f, 0.0f,
|
|
296 x, y, 0.0f, 1.0f,
|
|
297 ];
|
|
298
|
|
299 glMultMatrixf(matrix.ptr);
|
|
300 glDrawArrays(GL_LINE_STRIP, 0, springVAR_count);
|
|
301 } glPopMatrix();
|
|
302 }
|
|
303
|
|
304 static void
|
|
305 drawConstraint(cpConstraint *constraint)
|
|
306 {
|
|
307 cpBody *body_a = constraint.a;
|
|
308 cpBody *body_b = constraint.b;
|
|
309
|
|
310 const cpConstraintClass *klass = constraint.klass;
|
|
311 if(klass == cpPinJointGetClass()){
|
|
312 cpPinJoint *joint = cast(cpPinJoint *)constraint;
|
|
313
|
|
314 cpVect a = cpvadd(body_a.p, cpvrotate(joint.anchr1, body_a.rot));
|
|
315 cpVect b = cpvadd(body_b.p, cpvrotate(joint.anchr2, body_b.rot));
|
|
316
|
|
317 glPointSize(5.0f);
|
|
318 glBegin(GL_POINTS); {
|
|
319 glVertex2f(a.x, a.y);
|
|
320 glVertex2f(b.x, b.y);
|
|
321 } glEnd();
|
|
322
|
|
323 glBegin(GL_LINES); {
|
|
324 glVertex2f(a.x, a.y);
|
|
325 glVertex2f(b.x, b.y);
|
|
326 } glEnd();
|
|
327 } else if(klass == cpSlideJointGetClass()){
|
|
328 cpSlideJoint *joint = cast(cpSlideJoint *)constraint;
|
|
329
|
|
330 cpVect a = cpvadd(body_a.p, cpvrotate(joint.anchr1, body_a.rot));
|
|
331 cpVect b = cpvadd(body_b.p, cpvrotate(joint.anchr2, body_b.rot));
|
|
332
|
|
333 glPointSize(5.0f);
|
|
334 glBegin(GL_POINTS); {
|
|
335 glVertex2f(a.x, a.y);
|
|
336 glVertex2f(b.x, b.y);
|
|
337 } glEnd();
|
|
338
|
|
339 glBegin(GL_LINES); {
|
|
340 glVertex2f(a.x, a.y);
|
|
341 glVertex2f(b.x, b.y);
|
|
342 } glEnd();
|
|
343 } else if(klass == cpPivotJointGetClass()){
|
|
344 cpPivotJoint *joint = cast(cpPivotJoint *)constraint;
|
|
345
|
|
346 cpVect a = cpvadd(body_a.p, cpvrotate(joint.anchr1, body_a.rot));
|
|
347 cpVect b = cpvadd(body_b.p, cpvrotate(joint.anchr2, body_b.rot));
|
|
348
|
|
349 glPointSize(10.0f);
|
|
350 glBegin(GL_POINTS); {
|
|
351 glVertex2f(a.x, a.y);
|
|
352 glVertex2f(b.x, b.y);
|
|
353 } glEnd();
|
|
354 } else if(klass == cpGrooveJointGetClass()){
|
|
355 cpGrooveJoint *joint = cast(cpGrooveJoint *)constraint;
|
|
356
|
|
357 cpVect a = cpvadd(body_a.p, cpvrotate(joint.grv_a, body_a.rot));
|
|
358 cpVect b = cpvadd(body_a.p, cpvrotate(joint.grv_b, body_a.rot));
|
|
359 cpVect c = cpvadd(body_b.p, cpvrotate(joint.anchr2, body_b.rot));
|
|
360
|
|
361 glPointSize(5.0f);
|
|
362 glBegin(GL_POINTS); {
|
|
363 glVertex2f(c.x, c.y);
|
|
364 } glEnd();
|
|
365
|
|
366 glBegin(GL_LINES); {
|
|
367 glVertex2f(a.x, a.y);
|
|
368 glVertex2f(b.x, b.y);
|
|
369 } glEnd();
|
|
370 } else if(klass == cpDampedSpringGetClass()){
|
|
371 drawSpring(cast(cpDampedSpring *)constraint, body_a, body_b);
|
|
372 } else {
|
|
373 // printf("Cannot draw constraint\n");
|
|
374 }
|
|
375 }
|
|
376
|
|
377 static void
|
|
378 drawBB(cpShape *shape, void *unused)
|
|
379 {
|
|
380 glBegin(GL_LINE_LOOP); {
|
|
381 glVertex2f(shape.bb.l, shape.bb.b);
|
|
382 glVertex2f(shape.bb.l, shape.bb.t);
|
|
383 glVertex2f(shape.bb.r, shape.bb.t);
|
|
384 glVertex2f(shape.bb.r, shape.bb.b);
|
|
385 } glEnd();
|
|
386 }
|
|
387
|
|
388 // copied from cpSpaceHash.c
|
|
389 static cpHashValue
|
|
390 hash_func(cpHashValue x, cpHashValue y, cpHashValue n)
|
|
391 {
|
20
|
392 return cast(cpHashValue)(( (x*1640531513uL) ^ (y*2654435789uL) ) % n);
|
16
|
393 }
|
|
394
|
|
395 static void
|
|
396 drawSpatialHash(cpSpaceHash *hash)
|
|
397 {
|
|
398 cpBB bb = cpBBNew(-320, -240, 320, 240);
|
|
399
|
|
400 cpFloat dim = hash.celldim;
|
|
401 int n = hash.numcells;
|
|
402
|
|
403 int l = cast(int)floorf(bb.l/dim);
|
|
404 int r = cast(int)floorf(bb.r/dim);
|
|
405 int b = cast(int)floorf(bb.b/dim);
|
|
406 int t = cast(int)floorf(bb.t/dim);
|
|
407
|
|
408 for(int i=l; i<=r; i++){
|
|
409 for(int j=b; j<=t; j++){
|
|
410 int cell_count = 0;
|
|
411
|
|
412 int index = hash_func(i,j,n);
|
|
413 for(cpSpaceHashBin *bin = hash.table[index]; bin; bin = bin.next)
|
|
414 cell_count++;
|
|
415
|
|
416 GLfloat v = 1.0f - cast(GLfloat)cell_count/10.0f;
|
|
417 glColor3f(v,v,v);
|
|
418 glRectf(i*dim, j*dim, (i + 1)*dim, (j + 1)*dim);
|
|
419 }
|
|
420 }
|
|
421 }
|
|
422
|
|
423 void
|
|
424 DrawSpace(cpSpace *space, const drawSpaceOptions *options)
|
|
425 {
|
|
426 if(options.drawHash){
|
|
427 glColorMask(GL_FALSE, GL_TRUE, GL_FALSE, GL_TRUE);
|
|
428 drawSpatialHash(space.activeShapes);
|
|
429 glColorMask(GL_TRUE, GL_FALSE, GL_FALSE, GL_FALSE);
|
|
430 drawSpatialHash(space.staticShapes);
|
|
431 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
|
|
432 }
|
|
433
|
|
434 glLineWidth(options.lineThickness);
|
|
435 if(options.drawShapes){
|
|
436 cpSpaceHashEach(space.activeShapes, cast(cpSpaceHashIterator)&drawObject, space);
|
|
437 cpSpaceHashEach(space.staticShapes, cast(cpSpaceHashIterator)&drawObject, space);
|
|
438 }
|
|
439
|
|
440 glLineWidth(1.0f);
|
|
441 if(options.drawBBs){
|
|
442 glColor3f(0.3f, 0.5f, 0.3f);
|
|
443 cpSpaceHashEach(space.activeShapes, cast(cpSpaceHashIterator)&drawBB, null);
|
|
444 cpSpaceHashEach(space.staticShapes, cast(cpSpaceHashIterator)&drawBB, null);
|
|
445 }
|
|
446
|
|
447 cpArray *constraints = space.constraints;
|
|
448
|
|
449 glColor3f(0.5f, 1.0f, 0.5f);
|
|
450 for(int i=0, count = constraints.num; i<count; i++){
|
|
451 drawConstraint(cast(cpConstraint *)constraints.arr[i]);
|
|
452 }
|
|
453
|
|
454 if(options.bodyPointSize){
|
|
455 glPointSize(options.bodyPointSize);
|
|
456
|
|
457 glBegin(GL_POINTS); {
|
|
458 glColor3fv(LINE_COLOR.ptr);
|
|
459 cpArray *bodies = space.bodies;
|
|
460 for(int i=0, count = bodies.num; i<count; i++){
|
|
461 cpBody *_body = cast(cpBody *)bodies.arr[i];
|
|
462 glVertex2f(_body.p.x, _body.p.y);
|
|
463 }
|
|
464
|
|
465 // glColor3f(0.5f, 0.5f, 0.5f);
|
|
466 // cpArray *components = space.components;
|
|
467 // for(int i=0; i<components.num; i++){
|
|
468 // cpBody *root = components.arr[i];
|
|
469 // cpBody *body = root, *next;
|
|
470 // do {
|
|
471 // next = body.node.next;
|
|
472 // glVertex2f(body.p.x, body.p.y);
|
|
473 // } while((body = next) != root);
|
|
474 // }
|
|
475 } glEnd();
|
|
476 }
|
|
477
|
|
478 if(options.collisionPointSize){
|
|
479 glPointSize(options.collisionPointSize);
|
|
480 glBegin(GL_POINTS); {
|
|
481 cpArray *arbiters = space.arbiters;
|
|
482 for(int i=0; i<arbiters.num; i++){
|
|
483 cpArbiter *arb = cast(cpArbiter*)arbiters.arr[i];
|
|
484
|
|
485 glColor3fv(COLLISION_COLOR.ptr);
|
|
486 foreach(j; 0..arb.numContacts){
|
|
487 cpVect v = arb.contacts[j].p;
|
|
488 glVertex2f(v.x, v.y);
|
|
489 }
|
|
490 }
|
|
491 } glEnd();
|
|
492 }
|
|
493 }
|