1 /* 2 * Copyright (c) 2007-2013 Scott Lembcke and Howling Moon Software 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a copy 5 * of this software and associated documentation files (the "Software"), to deal 6 * in the Software without restriction, including without limitation the rights 7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 * copies of the Software, and to permit persons to whom the Software is 9 * furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice shall be included in 12 * all copies or substantial portions of the Software. 13 * 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 * SOFTWARE. 21 */ 22 module demo.ChipmunkDebugDraw; 23 24 /** 25 IMPORTANT - READ ME! 26 27 This file sets up a simple interface that the individual demos can use to get 28 a Chipmunk space running and draw what's in it. In order to keep the Chipmunk 29 examples clean and simple, they contain no graphics code. All drawing is done 30 by accessing the Chipmunk structures at a very low level. It is NOT 31 recommended to write a game or application this way as it does not scale 32 beyond simple shape drawing and is very dependent on implementation details 33 about Chipmunk which may change with little to no warning. 34 */ 35 36 import core.stdc.config; 37 import core.stdc.stdlib; 38 import core.stdc..string; 39 40 import glad.gl.all; 41 42 import demo.dchip; 43 44 import demo.ChipmunkDemoShaderSupport; 45 import demo.types; 46 47 const __gshared Color LINE_COLOR = { 200.0f / 255.0f, 210.0f / 255.0f, 230.0f / 255.0f, 1.0f }; 48 const __gshared Color CONSTRAINT_COLOR = { 0.0f, 0.75f, 0.0f, 1.0f }; 49 const __gshared float SHAPE_ALPHA = 1.0f; 50 51 __gshared float ChipmunkDebugDrawPointLineScale = 1.0f; 52 __gshared float ChipmunkDebugDrawOutlineWidth = 1.0f; 53 54 __gshared GLuint program; 55 56 __gshared v2f v2f0 = { 0.0f, 0.0f }; 57 58 __gshared GLuint vao = 0; 59 __gshared GLuint vbo = 0; 60 61 void ChipmunkDebugDrawInit() 62 { 63 // Setup the AA shader. 64 GLint vshader = CompileShader(GL_VERTEX_SHADER, 65 q{ 66 #version 110 67 68 attribute vec2 vertex; 69 attribute vec2 aa_coord; 70 attribute vec4 fill_color; 71 attribute vec4 outline_color; 72 73 varying vec2 v_aa_coord; 74 varying vec4 v_fill_color; 75 varying vec4 v_outline_color; 76 77 void main(){ 78 // TODO get rid of the GL 2.x matrix bit eventually? 79 gl_Position = gl_ModelViewProjectionMatrix * vec4(vertex, 0.0, 1.0); 80 81 v_fill_color = fill_color; 82 v_outline_color = outline_color; 83 v_aa_coord = aa_coord; 84 } 85 }); 86 87 GLint fshader = CompileShader(GL_FRAGMENT_SHADER, 88 q{ 89 #version 110 90 91 uniform float u_outline_coef; 92 93 varying vec2 v_aa_coord; 94 varying vec4 v_fill_color; 95 96 //const vec4 v_fill_color = vec4(0.0, 0.0, 0.0, 1.0); 97 varying vec4 v_outline_color; 98 99 float aa_step(float t1, float t2, float f) 100 { 101 //return step(t2, f); 102 return smoothstep(t1, t2, f); 103 } 104 105 void main() 106 { 107 float l = length(v_aa_coord); 108 109 // Different pixel size estimations are handy. 110 //float fw = fwidth(l); 111 //float fw = length(vec2(dFdx(l), dFdy(l))); 112 float fw = length(fwidth(v_aa_coord)); 113 114 // Outline width threshold. 115 float ow = 1.0 - fw; //*u_outline_coef; 116 117 // Fill/outline color. 118 float fo_step = aa_step(max(ow - fw, 0.0), ow, l); 119 vec4 fo_color = mix(v_fill_color, v_outline_color, fo_step); 120 121 // Use pre-multiplied alpha. 122 float alpha = 1.0 - aa_step(1.0 - fw, 1.0, l); 123 gl_FragColor = fo_color * (fo_color.a * alpha); 124 125 //gl_FragColor = vec4(vec3(l), 1); 126 } 127 }); 128 129 program = LinkProgram(vshader, fshader); 130 CheckGLErrors(); 131 132 // Setu VBO and VAO. 133 134 version (OSX) 135 { 136 glGenVertexArraysAPPLE(1, &vao); 137 glBindVertexArrayAPPLE(vao); 138 } 139 else 140 { 141 glGenVertexArrays(1, &vao); 142 glBindVertexArray(vao); 143 } 144 145 glGenBuffers(1, &vbo); 146 glBindBuffer(GL_ARRAY_BUFFER, vbo); 147 148 mixin(SET_ATTRIBUTE("program", "Vertex", "vertex", "GL_FLOAT")); 149 mixin(SET_ATTRIBUTE("program", "Vertex", "aa_coord", "GL_FLOAT")); 150 mixin(SET_ATTRIBUTE("program", "Vertex", "fill_color", "GL_FLOAT")); 151 mixin(SET_ATTRIBUTE("program", "Vertex", "outline_color", "GL_FLOAT")); 152 153 glBindBuffer(GL_ARRAY_BUFFER, 0); 154 155 version (OSX) 156 { 157 glBindVertexArrayAPPLE(0); 158 } 159 else 160 { 161 glBindVertexArray(0); 162 } 163 164 CheckGLErrors(); 165 } 166 167 Color ColorFromHash(cpHashValue hash, float alpha) 168 { 169 c_ulong val = cast(c_ulong)hash; 170 171 // scramble the bits up using Robert Jenkins' 32 bit integer hash function 172 val = (val + 0x7ed55d16) + (val << 12); 173 val = (val ^ 0xc761c23c) ^ (val >> 19); 174 val = (val + 0x165667b1) + (val << 5); 175 val = (val + 0xd3a2646c) ^ (val << 9); 176 val = (val + 0xfd7046c5) + (val << 3); 177 val = (val ^ 0xb55a4f09) ^ (val >> 16); 178 179 GLfloat r = cast(GLfloat)((val >> 0) & 0xFF); 180 GLfloat g = cast(GLfloat)((val >> 8) & 0xFF); 181 GLfloat b = cast(GLfloat)((val >> 16) & 0xFF); 182 183 GLfloat max = cast(GLfloat)cpfmax(cpfmax(r, g), b); 184 GLfloat min = cast(GLfloat)cpfmin(cpfmin(r, g), b); 185 GLfloat intensity = 0.75f; 186 187 // Saturate and scale the color 188 if (min == max) 189 { 190 return RGBAColor(intensity, 0.0f, 0.0f, alpha); 191 } 192 else 193 { 194 GLfloat coef = cast(GLfloat)intensity / (max - min); 195 return RGBAColor( 196 (r - min) * coef, 197 (g - min) * coef, 198 (b - min) * coef, 199 alpha 200 ); 201 } 202 } 203 204 void glColor_from_color(Color color) 205 { 206 glColor4fv(cast(GLfloat*)&color); 207 } 208 209 Color ColorForShape(cpShape* shape) 210 { 211 if (cpShapeGetSensor(shape)) 212 { 213 return LAColor(1.0f, 0.1f); 214 } 215 else 216 { 217 cpBody* body_ = shape.body_; 218 219 if (cpBodyIsSleeping(body_)) 220 { 221 return LAColor(0.2f, 1.0f); 222 } 223 else if (body_.node.idleTime > shape.space.sleepTimeThreshold) 224 { 225 return LAColor(0.66f, 1.0f); 226 } 227 else 228 { 229 return ColorFromHash(shape.hashid, SHAPE_ALPHA); 230 } 231 } 232 } 233 234 auto MAX(T)(T a, T b) 235 { 236 return a > b ? a : b; 237 } 238 239 __gshared size_t triangle_capacity = 0; 240 __gshared GLsizei triangle_count = 0; 241 __gshared Triangle* triangle_buffer = null; 242 243 Triangle* PushTriangles(size_t count) 244 { 245 if (triangle_count + count > triangle_capacity) 246 { 247 triangle_capacity += MAX(triangle_capacity, count); 248 triangle_buffer = cast(Triangle*)realloc(triangle_buffer, triangle_capacity * Triangle.sizeof); 249 } 250 251 Triangle* buffer = triangle_buffer + triangle_count; 252 triangle_count += count; 253 return buffer; 254 } 255 256 void ChipmunkDebugDrawCircle(cpVect pos, cpFloat angle, cpFloat radius, Color outlineColor, Color fillColor) 257 { 258 Triangle* triangles = PushTriangles(2); 259 260 cpFloat r = radius + 1.0f / ChipmunkDebugDrawPointLineScale; 261 Vertex a = { { pos.x - r, pos.y - r }, { -1.0, -1.0 }, fillColor, outlineColor }; 262 Vertex b = { { pos.x - r, pos.y + r }, { -1.0, 1.0 }, fillColor, outlineColor }; 263 Vertex c = { { pos.x + r, pos.y + r }, { 1.0, 1.0 }, fillColor, outlineColor }; 264 Vertex d = { { pos.x + r, pos.y - r }, { 1.0, -1.0 }, fillColor, outlineColor }; 265 266 Triangle t0 = { a, b, c }; 267 triangles[0] = t0; 268 Triangle t1 = { a, c, d }; 269 triangles[1] = t1; 270 271 ChipmunkDebugDrawSegment(pos, cpvadd(pos, cpvmult(cpvforangle(angle), radius - ChipmunkDebugDrawPointLineScale * 0.5f)), outlineColor); 272 } 273 274 void ChipmunkDebugDrawSegment(cpVect a, cpVect b, Color color) 275 { 276 ChipmunkDebugDrawFatSegment(a, b, 0.0f, color, color); 277 } 278 279 void ChipmunkDebugDrawFatSegment(cpVect a, cpVect b, cpFloat radius, Color outlineColor, Color fillColor) 280 { 281 Triangle* triangles = PushTriangles(6); 282 283 cpVect n = cpvnormalize(cpvperp(cpvsub(b, a))); 284 cpVect t = cpvperp(n); 285 286 cpFloat half = 1.0f / ChipmunkDebugDrawPointLineScale; 287 cpFloat r = radius + half; 288 289 if (r <= half) 290 { 291 r = half; 292 fillColor = outlineColor; 293 } 294 295 cpVect nw = (cpvmult(n, r)); 296 cpVect tw = (cpvmult(t, r)); 297 v2f v0 = v2f(cpvsub(b, cpvadd(nw, tw))); // { 1.0, -1.0} 298 v2f v1 = v2f(cpvadd(b, cpvsub(nw, tw))); // { 1.0, 1.0} 299 v2f v2 = v2f(cpvsub(b, nw)); // { 0.0, -1.0} 300 v2f v3 = v2f(cpvadd(b, nw)); // { 0.0, 1.0} 301 v2f v4 = v2f(cpvsub(a, nw)); // { 0.0, -1.0} 302 v2f v5 = v2f(cpvadd(a, nw)); // { 0.0, 1.0} 303 v2f v6 = v2f(cpvsub(a, cpvsub(nw, tw))); // {-1.0, -1.0} 304 v2f v7 = v2f(cpvadd(a, cpvadd(nw, tw))); // {-1.0, 1.0} 305 306 Triangle t0 = { { v0, { 1.0f, -1.0f }, fillColor, outlineColor }, { v1, { 1.0f, 1.0f }, fillColor, outlineColor }, { v2, { 0.0f, -1.0f }, fillColor, outlineColor } }; 307 triangles[0] = t0; 308 Triangle t1 = { { v3, { 0.0f, 1.0f }, fillColor, outlineColor }, { v1, { 1.0f, 1.0f }, fillColor, outlineColor }, { v2, { 0.0f, -1.0f }, fillColor, outlineColor } }; 309 triangles[1] = t1; 310 Triangle t2 = { { v3, { 0.0f, 1.0f }, fillColor, outlineColor }, { v4, { 0.0f, -1.0f }, fillColor, outlineColor }, { v2, { 0.0f, -1.0f }, fillColor, outlineColor } }; 311 triangles[2] = t2; 312 Triangle t3 = { { v3, { 0.0f, 1.0f }, fillColor, outlineColor }, { v4, { 0.0f, -1.0f }, fillColor, outlineColor }, { v5, { 0.0f, 1.0f }, fillColor, outlineColor } }; 313 triangles[3] = t3; 314 Triangle t4 = { { v6, { -1.0f, -1.0f }, fillColor, outlineColor }, { v4, { 0.0f, -1.0f }, fillColor, outlineColor }, { v5, { 0.0f, 1.0f }, fillColor, outlineColor } }; 315 triangles[4] = t4; 316 Triangle t5 = { { v6, { -1.0f, -1.0f }, fillColor, outlineColor }, { v7, { -1.0f, 1.0f }, fillColor, outlineColor }, { v5, { 0.0f, 1.0f }, fillColor, outlineColor } }; 317 triangles[5] = t5; 318 } 319 320 void ChipmunkDebugDrawPolygon(int count, cpVect* verts, cpFloat radius, Color outlineColor, Color fillColor) 321 { 322 struct ExtrudeVerts 323 { 324 cpVect offset, n; 325 } 326 327 size_t bytes = ExtrudeVerts.sizeof * count; 328 ExtrudeVerts* extrude = cast(ExtrudeVerts*)alloca(bytes); 329 memset(extrude, 0, bytes.sizeof); 330 331 for (int i = 0; i < count; i++) 332 { 333 cpVect v0 = verts[(i - 1 + count) % count]; 334 cpVect v1 = verts[i]; 335 cpVect v2 = verts[(i + 1) % count]; 336 337 cpVect n1 = cpvnormalize(cpvperp(cpvsub(v1, v0))); 338 cpVect n2 = cpvnormalize(cpvperp(cpvsub(v2, v1))); 339 340 cpVect offset = cpvmult(cpvadd(n1, n2), 1.0 / (cpvdot(n1, n2) + 1.0f)); 341 ExtrudeVerts v = { offset, n2 }; 342 extrude[i] = v; 343 } 344 345 // Triangle *triangles = PushTriangles(6*count); 346 Triangle* triangles = PushTriangles(5 * count - 2); 347 Triangle* cursor = triangles; 348 349 cpFloat inset = cpfmax(0.0f, 1.0f / ChipmunkDebugDrawPointLineScale - radius); 350 351 for (int i = 0; i < count - 2; i++) 352 { 353 v2f v0 = v2f(cpvsub(verts[0], cpvmult(extrude[0].offset, inset))); 354 v2f v1 = v2f(cpvsub(verts[i + 1], cpvmult(extrude[i + 1].offset, inset))); 355 v2f v2 = v2f(cpvsub(verts[i + 2], cpvmult(extrude[i + 2].offset, inset))); 356 357 Triangle t = { { v0, v2f0, fillColor, fillColor }, { v1, v2f0, fillColor, fillColor }, { v2, v2f0, fillColor, fillColor } }; 358 *cursor++ = t; 359 } 360 361 cpFloat outset = inset + 1.0f / ChipmunkDebugDrawPointLineScale + radius; 362 363 for (int i = 0, j = count - 1; i < count; j = i, i++) 364 { 365 cpVect vA = verts[i]; 366 cpVect vB = verts[j]; 367 368 cpVect nA = extrude[i].n; 369 cpVect nB = extrude[j].n; 370 371 cpVect offsetA = extrude[i].offset; 372 cpVect offsetB = extrude[j].offset; 373 374 cpVect innerA = cpvsub(vA, cpvmult(offsetA, inset)); 375 cpVect innerB = cpvsub(vB, cpvmult(offsetB, inset)); 376 377 // Admittedly my variable naming sucks here... 378 v2f inner0 = v2f(innerA); 379 v2f inner1 = v2f(innerB); 380 v2f outer0 = v2f(cpvadd(innerA, cpvmult(nB, outset))); 381 v2f outer1 = v2f(cpvadd(innerB, cpvmult(nB, outset))); 382 v2f outer2 = v2f(cpvadd(innerA, cpvmult(offsetA, outset))); 383 v2f outer3 = v2f(cpvadd(innerA, cpvmult(nA, outset))); 384 385 v2f n0 = v2f(nA); 386 v2f n1 = v2f(nB); 387 v2f offset0 = v2f(offsetA); 388 389 Triangle t0 = { { inner0, v2f0, fillColor, outlineColor }, { inner1, v2f0, fillColor, outlineColor }, { outer1, n1, fillColor, outlineColor } }; 390 *cursor++ = t0; 391 Triangle t1 = { { inner0, v2f0, fillColor, outlineColor }, { outer0, n1, fillColor, outlineColor }, { outer1, n1, fillColor, outlineColor } }; 392 *cursor++ = t1; 393 Triangle t2 = { { inner0, v2f0, fillColor, outlineColor }, { outer0, n1, fillColor, outlineColor }, { outer2, offset0, fillColor, outlineColor } }; 394 *cursor++ = t2; 395 Triangle t3 = { { inner0, v2f0, fillColor, outlineColor }, { outer2, offset0, fillColor, outlineColor }, { outer3, n0, fillColor, outlineColor } }; 396 *cursor++ = t3; 397 } 398 } 399 400 void ChipmunkDebugDrawDot(cpFloat size, cpVect pos, Color fillColor) 401 { 402 Triangle* triangles = PushTriangles(2); 403 404 float r = size * 0.5f / ChipmunkDebugDrawPointLineScale; 405 Vertex a = { { pos.x - r, pos.y - r }, { -1.0f, -1.0f }, fillColor, fillColor }; 406 Vertex b = { { pos.x - r, pos.y + r }, { -1.0f, 1.0f }, fillColor, fillColor }; 407 Vertex c = { { pos.x + r, pos.y + r }, { 1.0f, 1.0f }, fillColor, fillColor }; 408 Vertex d = { { pos.x + r, pos.y - r }, { 1.0f, -1.0f }, fillColor, fillColor }; 409 410 Triangle t0 = { a, b, c }; 411 triangles[0] = t0; 412 Triangle t1 = { a, c, d }; 413 triangles[1] = t1; 414 } 415 416 void ChipmunkDebugDrawBB(cpBB bb, Color color) 417 { 418 cpVect[4] verts; 419 verts[0] = cpv(bb.l, bb.b); 420 verts[1] = cpv(bb.l, bb.t); 421 verts[2] = cpv(bb.r, bb.t); 422 verts[3] = cpv(bb.r, bb.b); 423 ChipmunkDebugDrawPolygon(4, verts.ptr, 0.0f, color, LAColor(0, 0)); 424 } 425 426 struct ShapeColors 427 { 428 Color outlineColor, fillColor; 429 } 430 431 void DrawShape(cpShape* shape, ShapeColors* colors) 432 { 433 cpBody* body_ = shape.body_; 434 Color fill_color = (colors ? colors.fillColor : ColorForShape(shape)); 435 Color outline_color = (colors ? colors.outlineColor : LINE_COLOR); 436 437 switch (shape.klass.type) 438 { 439 case CP_CIRCLE_SHAPE: 440 { 441 cpCircleShape* circle = cast(cpCircleShape*)shape; 442 ChipmunkDebugDrawCircle(circle.tc, body_.a, circle.r, outline_color, fill_color); 443 break; 444 } 445 446 case CP_SEGMENT_SHAPE: 447 { 448 cpSegmentShape* seg = cast(cpSegmentShape*)shape; 449 ChipmunkDebugDrawFatSegment(seg.ta, seg.tb, seg.r, outline_color, fill_color); 450 break; 451 } 452 453 case CP_POLY_SHAPE: 454 { 455 cpPolyShape* poly = cast(cpPolyShape*)shape; 456 ChipmunkDebugDrawPolygon(poly.numVerts, poly.tVerts, poly.r, outline_color, fill_color); 457 break; 458 } 459 460 default: 461 break; 462 } 463 } 464 465 void ChipmunkDebugDrawShape(cpShape* shape, Color outlineColor, Color fillColor) 466 { 467 ShapeColors colors = { outlineColor, fillColor }; 468 DrawShape(shape, (outlineColor.a == 0.0 && fillColor.a == 0.0 ? null : &colors)); 469 } 470 471 void ChipmunkDebugDrawShapes(cpSpace* space) 472 { 473 cpSpaceEachShape(space, safeCast!cpSpaceShapeIteratorFunc(&DrawShape), null); 474 } 475 476 immutable cpVect[] spring_verts = [ 477 { 0.00f, 0.0f }, 478 { 0.20f, 0.0f }, 479 { 0.25f, 3.0f }, 480 { 0.30f, -6.0f }, 481 { 0.35f, 6.0f }, 482 { 0.40f, -6.0f }, 483 { 0.45f, 6.0f }, 484 { 0.50f, -6.0f }, 485 { 0.55f, 6.0f }, 486 { 0.60f, -6.0f }, 487 { 0.65f, 6.0f }, 488 { 0.70f, -3.0f }, 489 { 0.75f, 6.0f }, 490 { 0.80f, 0.0f }, 491 { 1.00f, 0.0f }, 492 ]; 493 494 immutable int spring_count = spring_verts.length; 495 496 void drawSpring(cpDampedSpring* spring, cpBody* body_a, cpBody* body_b) 497 { 498 cpVect a = cpvadd(body_a.p, cpvrotate(spring.anchr1, body_a.rot)); 499 cpVect b = cpvadd(body_b.p, cpvrotate(spring.anchr2, body_b.rot)); 500 501 ChipmunkDebugDrawDot(5, a, CONSTRAINT_COLOR); 502 ChipmunkDebugDrawDot(5, b, CONSTRAINT_COLOR); 503 504 cpVect delta = cpvsub(b, a); 505 GLfloat cos = delta.x; 506 GLfloat sin = delta.y; 507 GLfloat s = 1.0f / cpvlength(delta); 508 509 cpVect r1 = cpv(cos, -sin * s); 510 cpVect r2 = cpv(sin, cos * s); 511 512 cpVect* verts = cast(cpVect*)alloca(spring_count * cpVect.sizeof); 513 514 for (int i = 0; i < spring_count; i++) 515 { 516 cpVect v = spring_verts[i]; 517 verts[i] = cpv(cpvdot(v, r1) + a.x, cpvdot(v, r2) + a.y); 518 } 519 520 for (int i = 0; i < spring_count - 1; i++) 521 { 522 ChipmunkDebugDrawSegment(verts[i], verts[i + 1], CONSTRAINT_COLOR); 523 } 524 } 525 526 void drawConstraint(cpConstraint* constraint, void* unused) 527 { 528 cpBody* body_a = constraint.a; 529 cpBody* body_b = constraint.b; 530 531 const cpConstraintClass* klass = constraint.klass; 532 533 if (klass == cpPinJointGetClass()) 534 { 535 cpPinJoint* joint = cast(cpPinJoint*)constraint; 536 537 cpVect a = cpvadd(body_a.p, cpvrotate(joint.anchr1, body_a.rot)); 538 cpVect b = cpvadd(body_b.p, cpvrotate(joint.anchr2, body_b.rot)); 539 540 ChipmunkDebugDrawDot(5, a, CONSTRAINT_COLOR); 541 ChipmunkDebugDrawDot(5, b, CONSTRAINT_COLOR); 542 ChipmunkDebugDrawSegment(a, b, CONSTRAINT_COLOR); 543 } 544 else if (klass == cpSlideJointGetClass()) 545 { 546 cpSlideJoint* joint = cast(cpSlideJoint*)constraint; 547 548 cpVect a = cpvadd(body_a.p, cpvrotate(joint.anchr1, body_a.rot)); 549 cpVect b = cpvadd(body_b.p, cpvrotate(joint.anchr2, body_b.rot)); 550 551 ChipmunkDebugDrawDot(5, a, CONSTRAINT_COLOR); 552 ChipmunkDebugDrawDot(5, b, CONSTRAINT_COLOR); 553 ChipmunkDebugDrawSegment(a, b, CONSTRAINT_COLOR); 554 } 555 else if (klass == cpPivotJointGetClass()) 556 { 557 cpPivotJoint* joint = cast(cpPivotJoint*)constraint; 558 559 cpVect a = cpvadd(body_a.p, cpvrotate(joint.anchr1, body_a.rot)); 560 cpVect b = cpvadd(body_b.p, cpvrotate(joint.anchr2, body_b.rot)); 561 562 ChipmunkDebugDrawDot(5, a, CONSTRAINT_COLOR); 563 ChipmunkDebugDrawDot(5, b, CONSTRAINT_COLOR); 564 } 565 else if (klass == cpGrooveJointGetClass()) 566 { 567 cpGrooveJoint* joint = cast(cpGrooveJoint*)constraint; 568 569 cpVect a = cpvadd(body_a.p, cpvrotate(joint.grv_a, body_a.rot)); 570 cpVect b = cpvadd(body_a.p, cpvrotate(joint.grv_b, body_a.rot)); 571 cpVect c = cpvadd(body_b.p, cpvrotate(joint.anchr2, body_b.rot)); 572 573 ChipmunkDebugDrawDot(5, c, CONSTRAINT_COLOR); 574 ChipmunkDebugDrawSegment(a, b, CONSTRAINT_COLOR); 575 } 576 else if (klass == cpDampedSpringGetClass()) 577 { 578 drawSpring(cast(cpDampedSpring*)constraint, body_a, body_b); 579 } 580 } 581 582 void ChipmunkDebugDrawConstraint(cpConstraint* constraint) 583 { 584 drawConstraint(constraint, null); 585 } 586 587 void ChipmunkDebugDrawConstraints(cpSpace* space) 588 { 589 cpSpaceEachConstraint(space, &drawConstraint, null); 590 } 591 592 void ChipmunkDebugDrawCollisionPoints(cpSpace* space) 593 { 594 cpArray* arbiters = space.arbiters; 595 Color color = RGBAColor(1.0f, 0.0f, 0.0f, 1.0f); 596 597 for (int i = 0; i < arbiters.num; i++) 598 { 599 cpArbiter* arb = cast(cpArbiter*)arbiters.arr[i]; 600 601 for (int j = 0; j < arb.numContacts; j++) 602 { 603 cpVect p = arb.contacts[j].p; 604 cpVect n = arb.contacts[j].n; 605 cpFloat d = 2.0 - arb.contacts[j].dist / 2.0; 606 607 cpVect a = cpvadd(p, cpvmult(n, d)); 608 cpVect b = cpvadd(p, cpvmult(n, -d)); 609 ChipmunkDebugDrawSegment(a, b, color); 610 } 611 } 612 } 613 614 void ChipmunkDebugDrawFlushRenderer() 615 { 616 glBindBuffer(GL_ARRAY_BUFFER, vbo); 617 glBufferData(GL_ARRAY_BUFFER, Triangle.sizeof * triangle_count, triangle_buffer, GL_STREAM_DRAW); 618 619 glUseProgram(program); 620 glUniform1f(glGetUniformLocation(program, "u_outline_coef"), ChipmunkDebugDrawPointLineScale); 621 622 version (OSX) 623 { 624 glBindVertexArrayAPPLE(vao); 625 } 626 else 627 { 628 glBindVertexArray(vao); 629 } 630 631 glDrawArrays(GL_TRIANGLES, 0, triangle_count * 3); 632 633 CheckGLErrors(); 634 } 635 636 void ChipmunkDebugDrawClearRenderer() 637 { 638 triangle_count = 0; 639 } 640 641 __gshared GLsizei pushed_triangle_count = 0; 642 643 void ChipmunkDebugDrawPushRenderer() 644 { 645 pushed_triangle_count = triangle_count; 646 } 647 648 void ChipmunkDebugDrawPopRenderer() 649 { 650 triangle_count = pushed_triangle_count; 651 }