comparison render.d @ 0:c10bc63824e7

Initial commit!
author zzzzrrr <mason.green@gmail.com>
date Fri, 20 Mar 2009 06:41:25 -0400
parents
children a40d066ebbd1
comparison
equal deleted inserted replaced
-1:000000000000 0:c10bc63824e7
1 /*
2 * Copyright (c) 2009, Mason Green (zzzzrrr)
3 * Based on Box2D by Erin Catto, http://www.box2d.org
4 *
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without modification,
8 * are permitted provided that the following conditions are met:
9 *
10 * * Redistributions of source code must retain the above copyright notice,
11 * this list of conditions and the following disclaimer.
12 * * Redistributions in binary form must reproduce the above copyright notice,
13 * this list of conditions and the following disclaimer in the documentation
14 * and/or other materials provided with the distribution.
15 * * Neither the name of the polygonal nor the names of its contributors may be
16 * used to endorse or promote products derived from this software without specific
17 * prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
26 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
27 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
28 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
29 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31 module melee.render;
32
33 import xf.dog.Dog;
34 import xf.omg.core.LinearAlgebra;
35 import xf.hybrid.Event;
36 import xf.hybrid.Font;
37
38 import melee.melee;
39
40 /// Color for drawing. Each value has the range [0,1].
41 struct Color {
42 static Color opCall(float r, float g, float b)
43 {
44 Color u;
45 u.r = r;
46 u.g = g;
47 u.b = b;
48 return u;
49 }
50
51 float r = 0;
52 float g = 0;
53 float b = 0;
54 }
55
56 class Render : Melee
57 {
58
59 this(Settings *settings) {
60
61 super(settings);
62 }
63
64 void drawCircle(GL gl, vec2 center, float radius, bool water = false, float theta = float.nan)
65 {
66 int segs = cast(int)(radius) + 20;
67 if (segs > MAX_CIRCLE_RES) segs = MAX_CIRCLE_RES;
68 double coef = 2.0 * PI / segs;
69
70 auto realTheta = (theta <>= 0 ? theta : 0);
71 if (water) {
72 gl.immediate(GL_TRIANGLE_FAN,
73 {
74 gl.Vertex2fv(center.ptr);
75 for (int n = 0; n <= segs; n++) {
76 double rads = n * coef;
77 gl.Vertex2f(radius * cos(rads + realTheta) + center.x, radius * sin(rads + realTheta) + center.y);
78 }
79 });
80 }
81
82 gl.immediate(GL_LINE_STRIP,
83 {
84 for (int n = 0; n <= segs; n++) {
85 double rads = n * coef;
86 gl.Vertex2f(radius * cos(rads + realTheta) + center.x, radius * sin(rads + realTheta) + center.y);
87 }
88 if (theta <>= 0)
89 gl.Vertex2fv(center.ptr);
90 });
91 }
92
93 void drawSolidCircle(GL gl, vec2 center, float radius, vec2 axis, Color color)
94 {
95 const k_segments = 16.0f;
96 const k_increment = 2.0f * PI / k_segments;
97 float theta = 0.0f;
98 gl.Enable(GL_BLEND);
99 gl.BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
100 gl.Color4f(0.5f * color.r, 0.5f * color.g, 0.5f * color.b, 0.5f);
101 gl.Begin(GL_TRIANGLE_FAN);
102 for (int i = 0; i < k_segments; ++i) {
103 vec2 v = center + radius * vec2(cos(theta), sin(theta));
104 gl.Vertex2f(v.x, v.y);
105 theta += k_increment;
106 }
107 gl.End();
108 gl.Disable(GL_BLEND);
109
110 theta = 0.0f;
111 gl.Color4f(color.r, color.g, color.b, 1.0f);
112 gl.Begin(GL_LINE_LOOP);
113 for (int i = 0; i < k_segments; ++i) {
114 vec2 v = center + radius * vec2(cos(theta), sin(theta));
115 gl.Vertex2f(v.x, v.y);
116 theta += k_increment;
117 }
118 gl.End();
119
120 vec2 p = center + radius * axis;
121 gl.Begin(GL_LINES);
122 gl.Vertex2f(center.x, center.y);
123 gl.Vertex2f(p.x, p.y);
124 gl.End();
125 }
126
127 void drawPolygon(GL gl, vec2[] glVerts, Color color)
128 {
129 gl.Color3f(color.r, color.g, color.b);
130 gl.immediate(GL_LINE_LOOP,
131 {
132 foreach (v; glVerts)
133 gl.Vertex2fv(v.ptr);
134 });
135 }
136
137 void drawSolidPolygon(GL gl, vec2[] vertices, Color color)
138 {
139 gl.Enable(GL_BLEND);
140 gl.BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
141 gl.Color4f(0.5f * color.r, 0.5f * color.g, 0.5f * color.b, 0.5f);
142 gl.Begin(GL_TRIANGLE_FAN);
143 for (int i = 0; i < vertices.length; ++i) {
144 gl.Vertex2f(vertices[i].x, vertices[i].y);
145 }
146 gl.End();
147 gl.Disable(GL_BLEND);
148
149 gl.Color4f(color.r, color.g, color.b, 1.0f);
150 gl.Begin(GL_LINE_LOOP);
151 for (int i = 0; i < vertices.length; ++i) {
152 gl.Vertex2f(vertices[i].x, vertices[i].y);
153 }
154 gl.End();
155 }
156
157
158 void drawPoint(GL gl, vec2 p, float size, Color color)
159 {
160 gl.Color3f(color.r, color.g, color.b);
161 gl.PointSize(size);
162 gl.Begin(GL_POINTS);
163 gl.Vertex2f(p.x, p.y);
164 gl.End();
165 gl.PointSize(1.0f);
166 }
167
168 void drawSegment(GL gl, vec2 begin, vec2 end, Color color)
169 {
170 gl.Color3f(color.r, color.g, color.b);
171 gl.immediate(GL_LINES,
172 {
173 gl.Vertex2fv(begin.ptr);
174 gl.Vertex2fv(end.ptr);
175 });
176 }
177
178 // TODO: handle inequal radii correctly
179 void connectCircles(GL gl, vec2 center1, float radius1, vec2 center2, float radius2)
180 {
181 auto d = center2 - center1;
182 if (!d.length)
183 return;
184 d *= (d.length - radius1) / d.length;
185 center1 += d;
186 center2 -= d;
187 gl.immediate(GL_LINES,
188 {
189 gl.Vertex2fv(center1.ptr);
190 gl.Vertex2fv(center2.ptr);
191 });
192 }
193
194 void drawXForm(GL gl, bzXForm xf)
195 {
196 bzVec2 p1 = xf.position, p2;
197 const k_axisScale = 0.4f;
198
199 gl.Begin(GL_LINES);
200 {
201 gl.Color3f(1.0f, 0.0f, 0.0f);
202 gl.Vertex2f(p1.x, p1.y);
203 p2 = p1 + k_axisScale * xf.R.col1;
204 gl.Vertex2f(p2.x, p2.y);
205
206 gl.Color3f(0.0f, 1.0f, 0.0f);
207 gl.Vertex2f(p1.x, p1.y);
208 p2 = p1 + k_axisScale * xf.R.col2;
209 gl.Vertex2f(p2.x, p2.y);
210 }
211 gl.End();
212 }
213
214 void drawSpring(GL gl, vec2 a, vec2 b, uint zigs)
215 {
216 zigs++;
217
218 // Portion of length dedicated to connectors
219 const float connPart = 0.2;
220
221 vec2 inc = (b - a) / (zigs);
222 // One step from a to b
223 vec2 zigLen = inc * (1 - connPart);
224 // Length of a connector
225 vec2 connLen = inc * (connPart / 2) * zigs;
226 // Width of a zig
227 vec2 zigWidth = (b - a).rotatedHalfPi.normalized;
228 gl.immediate(GL_LINE_STRIP,
229 {
230 gl.Vertex2fv(a.ptr);
231
232 a += connLen;
233 gl.Vertex2fv(a.ptr);
234
235 bool dir = true;
236 a += zigWidth / 2 + zigLen / 2;
237 for (int i = 0; i < zigs; i++) {
238 gl.Vertex2fv(a.ptr);
239 a += zigLen;
240 if (dir) {
241 a -= zigWidth;
242 }else {
243 a += zigWidth;
244 }
245 dir = !dir;
246 }
247
248 gl.Vertex2fv((b - connLen).ptr);
249 gl.Vertex2fv(b.ptr);
250 });
251 }
252
253 void drawShape(GL gl, bzShape shape, bzXForm xf, Color color, bool core)
254 {
255 Color coreColor = Color(0.9f, 0.6f, 0.6f);
256
257 switch (shape.type) {
258 case bzShapeType.CIRCLE:
259 auto circle = cast(bzCircle)shape;
260
261 vec2 center = vec2.from(bzMul(xf, circle.localPosition));
262 float radius = circle.radius;
263 vec2 axis = vec2.from(xf.R.col1);
264
265 gl.drawSolidCircle(center, radius, axis, color);
266
267 if (core) {
268 gl.Color3f(coreColor.r, coreColor.g, coreColor.b);
269 gl.drawCircle(center, radius - k_toiSlop);
270 }
271 break;
272 case bzShapeType.POLYGON:
273 {
274 bzPolygon poly = cast(bzPolygon)shape;
275 bzVec2[] vertices = poly.worldVertices;
276 vec2[] verts;
277 verts.length = vertices.length;
278 foreach (int i, v; vertices) {
279 verts[i] = vec2.from(v);
280 }
281
282 gl.drawSolidPolygon(verts, color);
283
284 if (core) {
285 bzVec2[] localCoreVertices = poly.coreVertices;
286 verts.length = localCoreVertices.length;
287 for (int i = 0; i < localCoreVertices.length; ++i) {
288 verts[i] = vec2.from(bzMul(xf, localCoreVertices[i]));
289 }
290 gl.drawPolygon(verts, coreColor);
291 }
292 }
293 break;
294
295 case bzShapeType.EDGE:
296 {
297 bzEdge edge = cast(bzEdge)shape;
298
299 vec2 p1 = vec2.from(bzMul(xf, edge.vertex1));
300 vec2 p2 = vec2.from(bzMul(xf, edge.vertex2));
301 gl.drawSegment(p1, p2, color);
302
303 if (core) {
304 p1 = vec2.from(bzMul(xf, edge.coreVertex1));
305 p2 = vec2.from(bzMul(xf, edge.coreVertex2));
306 gl.drawSegment(p1, p2, coreColor);
307 }
308 }
309 break;
310 }
311 }
312
313 void draw(vec2i screenSize, GL gl)
314 {
315 this.screenSize = screenSize;
316
317 gl.LoadIdentity();
318 gl.MatrixMode(GL_PROJECTION);
319 gl.LoadIdentity();
320 // Left, right, bottom, top
321 gl.gluOrtho2D(-screenSize.x / zoom, screenSize.x / zoom, -screenSize.y / zoom, screenSize.y / zoom);
322 gl.Translatef(-viewCenter.x, -viewCenter.y, 0);
323 gl.MatrixMode(GL_MODELVIEW);
324 gl.Disable(GL_DEPTH_TEST);
325 gl.LoadIdentity();
326 gl.Clear(GL_COLOR_BUFFER_BIT);
327
328 // Draw dynamic bodies
329 if (settings.drawShapes) {
330 for (bzBody b = world.bodyList; b; b = b.next) {
331 for (bzShape shape = b.shapeList; shape; shape = shape.next) {
332
333 bzShape s = shape;
334 bzXForm xf = b.xf;
335
336 if (b.isStatic) {
337 gl.drawShape(s, xf, Color(0.5f, 0.9f, 0.5f), settings.drawCoreShapes);
338 }else if (b.isSleeping) {
339 gl.drawShape(s, xf, Color(0.5f, 0.5f, 0.9f), settings.drawCoreShapes);
340 }else if (b.userData) {
341 auto ss = cast(Select)b.userData;
342 if (ss) {
343 gl.drawShape(s, xf, Color(0, .5, 1), settings.drawCoreShapes);
344 }
345 }else {
346 gl.drawShape(s, xf, Color(0.9f, 0.9f, 0.9f), settings.drawCoreShapes);
347 }
348
349 gl.LoadIdentity();
350 gl.Flush();
351 }
352 }
353
354 // Draw water
355 bzFluidParticle[] particles = world.particles;
356 gl.Color3f(0, 0, 1);
357 foreach (p; particles) {
358 gl.drawCircle(vec2.from(p.position), WATER_RADIUS, true);
359 }
360 }
361
362 // Draw joints
363 if (settings.drawJoints) {
364 Color color = Color(0, 0, 1);
365 gl.Color3f(0, 0, 1);
366
367 gl.LineWidth(1);
368 for (bzJoint joint = world.jointList; joint; joint = joint.next) {
369 auto distance = cast(bzDistanceJoint)joint;
370 auto pulley = cast(bzPulleyJoint)joint;
371 auto revolute = cast(bzRevoluteJoint)joint;
372 auto prismatic = cast(bzPrismaticJoint)joint;
373 auto line = cast(bzLineJoint)joint;
374 if (distance) {
375 color = Color(.5, .5, 0);
376 // Endpoints
377 vec2 a = vec2.from(distance.anchor1);
378 vec2 b = vec2.from(distance.anchor2);
379 // Circles
380 gl.drawCircle(a, HINGE_RADIUS);
381 gl.drawCircle(b, HINGE_RADIUS);
382 // Connecting line
383 gl.connectCircles(a, HINGE_RADIUS, b, HINGE_RADIUS);
384 }else if (pulley) {
385 auto a = vec2.from(pulley.anchor1);
386 auto b = vec2.from(pulley.groundAnchor1);
387 auto c = vec2.from(pulley.groundAnchor2);
388 auto d = vec2.from(pulley.anchor2);
389 gl.drawCircle(a, HINGE_RADIUS);
390 gl.drawCircle(b, HINGE_RADIUS);
391 gl.connectCircles(a, HINGE_RADIUS, b, HINGE_RADIUS);
392 gl.drawSegment(b, c, color);
393 gl.drawCircle(c, HINGE_RADIUS);
394 gl.drawCircle(d, HINGE_RADIUS);
395 gl.connectCircles(c, HINGE_RADIUS, d, HINGE_RADIUS);
396 }else if (revolute) {
397 auto a = vec2.from(revolute.rBody1.position);
398 auto b = vec2.from(revolute.anchor1);
399 auto c = vec2.from(revolute.rBody2.position);
400 gl.drawCircle(a, HINGE_RADIUS);
401 gl.drawCircle(b, HINGE_RADIUS);
402 gl.connectCircles(a, HINGE_RADIUS, b, HINGE_RADIUS);
403 gl.drawCircle(c, HINGE_RADIUS);
404 gl.connectCircles(b, HINGE_RADIUS, c, HINGE_RADIUS);
405 }else if (prismatic) {
406 auto a = vec2.from(prismatic.rBody1.position);
407 auto b = vec2.from(prismatic.anchor1);
408 auto c = vec2.from(prismatic.rBody2.position);
409 gl.drawCircle(a, HINGE_RADIUS);
410 gl.drawCircle(b, HINGE_RADIUS);
411 gl.connectCircles(a, HINGE_RADIUS, b, HINGE_RADIUS);
412 gl.drawCircle(c, HINGE_RADIUS);
413 gl.connectCircles(b, HINGE_RADIUS, c, HINGE_RADIUS);
414 }else if (line) {
415 auto a = vec2.from(line.rBody1.position);
416 auto b = vec2.from(line.anchor1);
417 auto c = vec2.from(line.rBody2.position);
418 gl.drawCircle(a, HINGE_RADIUS);
419 gl.drawCircle(b, HINGE_RADIUS);
420 gl.connectCircles(a, HINGE_RADIUS, b, HINGE_RADIUS);
421 gl.drawCircle(c, HINGE_RADIUS);
422 gl.connectCircles(b, HINGE_RADIUS, c, HINGE_RADIUS);
423 }
424 }
425
426 if (settings.drawControllers) {
427 bzForceGenerator[] forces = world.forces;
428 foreach (f; forces) {
429 auto spring1 = cast(bzSpring1) f;
430 auto spring2 = cast(bzSpring2) f;
431 auto buoyancy = cast(bzBuoyancy) f;
432
433 if (spring1) {
434 auto bungee1 = cast(bzBungee1)spring1;
435 if (bungee1) {
436 gl.Color3f(.5, .5, 0);
437 // Endpoints
438 vec2 a = vec2.from(bungee1.rBody.position);
439 vec2 b = vec2.from(bungee1.anchor);
440 // Circles
441 gl.drawCircle(a, HINGE_RADIUS);
442 gl.drawCircle(b, HINGE_RADIUS);
443 // Connecting line
444 gl.connectCircles(a, HINGE_RADIUS, b, HINGE_RADIUS);
445 }else {
446 uint zigs = 10;
447 auto anchor1 = vec2.from(spring1.anchor);
448 auto anchor2 = vec2.from(spring1.rBody.position);
449 gl.drawSpring(anchor1, anchor2, zigs);
450 }
451 }
452
453 if (spring2) {
454 auto bungee2 = cast(bzBungee2)spring2;
455 if (bungee2) {
456 gl.Color3f(.5, .5, 0);
457 // Endpoints
458 vec2 a = vec2.from(bungee2.rBody.position);
459 vec2 b = vec2.from(bungee2.otherBody.position);
460 // Circles
461 gl.drawCircle(a, HINGE_RADIUS);
462 gl.drawCircle(b, HINGE_RADIUS);
463 // Connecting line
464 gl.connectCircles(a, HINGE_RADIUS, b, HINGE_RADIUS);
465 }else {
466 uint zigs = 10;
467 auto anchor1 = vec2.from(spring2.otherBody.position);
468 auto anchor2 = vec2.from(spring2.rBody.position);
469 gl.drawSpring(anchor1, anchor2, zigs);
470 }
471 }
472
473 if(buoyancy) {
474 float plane = buoyancy.planeOffset;
475 vec2 p1 = vec2(-50, plane);
476 vec2 p2 = vec2(50, plane);
477 gl.drawSegment(p1, p2, color);
478 }
479 }
480 }
481 }
482
483 if(settings.drawPairs) {
484
485 bzBroadPhase bp = world.broadPhase;
486 bzVec2 invQ;
487 invQ.set(1.0f / bp.m_quantizationFactor.x, 1.0f / bp.m_quantizationFactor.y);
488 Color color = Color(0.9f, 0.9f, 0.3f);
489
490 const k_tableCapacity = bzPairManager.TABLE_CAPACITY;
491
492 for (int i = 0; i < k_tableCapacity; ++i)
493 {
494 ushort index = bp.m_pairManager.m_hashTable[i];
495 while (index < bp.m_pairManager.m_pairs.length)
496 {
497 if(index == bzPairManager.NULL_PROXY) {
498 break;
499 }
500 bzPair pair = bp.m_pairManager.m_pairs[index];
501 bzProxy p1 = bp.m_proxyPool[pair.proxyId1];
502 bzProxy p2 = bp.m_proxyPool[pair.proxyId2];
503
504 bzAABB b1, b2;
505 b1.lowerBound.x = bp.m_worldAABB.lowerBound.x + invQ.x * bp.m_bounds[0][p1.lowerBounds[0]].value;
506 b1.lowerBound.y = bp.m_worldAABB.lowerBound.y + invQ.y * bp.m_bounds[1][p1.lowerBounds[1]].value;
507 b1.upperBound.x = bp.m_worldAABB.lowerBound.x + invQ.x * bp.m_bounds[0][p1.upperBounds[0]].value;
508 b1.upperBound.y = bp.m_worldAABB.lowerBound.y + invQ.y * bp.m_bounds[1][p1.upperBounds[1]].value;
509 b2.lowerBound.x = bp.m_worldAABB.lowerBound.x + invQ.x * bp.m_bounds[0][p2.lowerBounds[0]].value;
510 b2.lowerBound.y = bp.m_worldAABB.lowerBound.y + invQ.y * bp.m_bounds[1][p2.lowerBounds[1]].value;
511 b2.upperBound.x = bp.m_worldAABB.lowerBound.x + invQ.x * bp.m_bounds[0][p2.upperBounds[0]].value;
512 b2.upperBound.y = bp.m_worldAABB.lowerBound.y + invQ.y * bp.m_bounds[1][p2.upperBounds[1]].value;
513
514 bzVec2 x1 = 0.5f * (b1.lowerBound + b1.upperBound);
515 bzVec2 x2 = 0.5f * (b2.lowerBound + b2.upperBound);
516
517 gl.drawSegment(vec2.from(x1),vec2.from(x2), color);
518
519 index = pair.next;
520 }
521 }
522 }
523
524 // Draw axis aligned bounding boxes (bzAABB)
525 if (settings.drawAABBs) {
526 bzBroadPhase bp = world.broadPhase;
527 bzVec2 worldLower = bp.m_worldAABB.lowerBound;
528 bzVec2 worldUpper = bp.m_worldAABB.upperBound;
529 Color color;
530 bzVec2 invQ;
531 invQ.set(1.0f / bp.m_quantizationFactor.x, 1.0f / bp.m_quantizationFactor.y);
532 color = Color(1.0f, 1.0f, 1.0f);
533
534 for (int i = 0; i < k_maxProxies; ++i) {
535 bzProxy p = bp.m_proxyPool[i];
536 if (!p.isValid) {
537 continue;
538 }
539
540 bzAABB b;
541 b.lowerBound.x = worldLower.x + invQ.x * bp.m_bounds[0][p.lowerBounds[0]].value;
542 b.lowerBound.y = worldLower.y + invQ.y * bp.m_bounds[1][p.lowerBounds[1]].value;
543 b.upperBound.x = worldLower.x + invQ.x * bp.m_bounds[0][p.upperBounds[0]].value;
544 b.upperBound.y = worldLower.y + invQ.y * bp.m_bounds[1][p.upperBounds[1]].value;
545
546 vec2 vs[4];
547 vs[0] = vec2(b.lowerBound.x, b.lowerBound.y);
548 vs[1] = vec2(b.upperBound.x, b.lowerBound.y);
549 vs[2] = vec2(b.upperBound.x, b.upperBound.y);
550 vs[3] = vec2(b.lowerBound.x, b.upperBound.y);
551
552 drawPolygon(gl, vs, color);
553 }
554
555 vec2 vs[4];
556 vs[0] = vec2(worldLower.x, worldLower.y);
557 vs[1] = vec2(worldUpper.x, worldLower.y);
558 vs[2] = vec2(worldUpper.x, worldUpper.y);
559 vs[3] = vec2(worldLower.x, worldUpper.y);
560
561 color = Color(0.3f, 0.9f, 0.9f);
562 drawPolygon(gl, vs, color);
563 }
564
565 // Draw contact points
566 if (settings.drawContactPoints) {
567 const k_axisScale = 0.3f;
568 const k_forceScale = 0.01f;
569
570
571 for (int i = 0; i < pointCount; ++i) {
572 ContactPoint point = points[i];
573 Color color;
574
575 if (point.state == ContactState.e_contactAdded) {
576 // Add
577 color = Color(0.3f, 0.95f, 0.3f);
578 vec2 p = vec2.from(point.position);
579 gl.drawPoint(p, 10.0f, color);
580 }else if (point.state == ContactState.e_contactPersisted) {
581 // Persist
582 color = Color(0.3f, 0.3f, 0.95f);
583 vec2 p = vec2.from(point.position);
584 gl.drawPoint(p, 5.0f, color);
585 }else {
586 // Remove
587 color = Color(0.95f, 0.3f, 0.3f);
588 vec2 p = vec2.from(point.position);
589 gl.drawPoint(p, 10.0f, color);
590 }
591
592 if (settings.drawContactNormals == 1) {
593 vec2 p1 = vec2.from(point.position);
594 vec2 p2 = p1 + k_axisScale * vec2.from(point.normal);
595 color = Color(0.4f, 0.9f, 0.4f);
596 gl.drawSegment(p1, p2, color);
597 }else if (settings.drawContactForces) { /*
598 vec2 p1 = vec2.from(point.position);
599 vec2 p2 = p1 + k_forceScale * vec2.from(point.normalForce * point.normal);
600 color = Color(0.9f, 0.9f, 0.3f);
601 gl.drawSegment(p1, p2, color);*/
602 }
603
604 if (settings.drawFrictionForces) { /*
605 vec2 tangent = vec2.from(bzCross(point.normal, 1.0f));
606 vec2 p1 = point.position;
607 vec2 p2 = p1 + k_forceScale * vec2.from(point.tangentForce) * tangent;
608 color = Color(0.9f, 0.9f, 0.3f);
609 gl.drawSegment(p1, p2, color); */
610 }
611 }
612 }
613
614 if (settings.drawOBBs) {
615 Color color = Color(0.5f, 0.3f, 0.5f);
616
617 for (bzBody b = world.bodyList; b; b = b.next) {
618 bzXForm xf = b.xf;
619 for (bzShape s = b.shapeList; s; s = s.next) {
620 if (s.type != bzShapeType.POLYGON) {
621 continue;
622 }
623
624 bzPolygon poly = cast(bzPolygon)s;
625 bzOBB obb = poly.obb;
626 bzVec2 h = obb.extents;
627 bzVec2 vs[4];
628 vs[0].set(-h.x, -h.y);
629 vs[1].set(h.x, -h.y);
630 vs[2].set(h.x, h.y);
631 vs[3].set(-h.x, h.y);
632
633 vec2[4] v;
634 for (int i = 0; i < 4; ++i) {
635 vs[i] = obb.center + bzMul(obb.R, vs[i]);
636 v[i] = vec2.from(bzMul(xf, vs[i]));
637 }
638
639 drawPolygon(gl, v, color);
640 }
641 }
642 }
643
644 if (settings.drawCOMs) {
645 for (bzBody b = world.bodyList; b; b = b.next) {
646 bzXForm xf = b.xf;
647 xf.position = b.worldCenter;
648 drawXForm(gl, xf);
649 }
650 }
651
652 // Nonphysical stuffs
653 // Universal '.' cursor
654 gl.Color3f(1, 1, 1);
655 gl.immediate(GL_POINTS,
656 {
657 gl.Vertex2fv(mousePos.ptr);
658 });
659
660 pointCount = 0;
661 }
662
663 }