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