comparison trunk/tests/ChipmunkDemos/drawSpace.d @ 16:af2f61a96318

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