1 module xmain
is aliced
;
3 import arsd
.simpledisplay
;
7 import iv
.glbinds
.utils
;
13 // ////////////////////////////////////////////////////////////////////////// //
18 // ////////////////////////////////////////////////////////////////////////// //
23 __gshared ContactXY
[] contacts
;
26 // ////////////////////////////////////////////////////////////////////////// //
27 // random number in range [-1,1]
28 public VFloat
rnd () {
30 import std
.random
: uniform
;
31 return cast(VFloat
)uniform
!"[]"(-VFloatNum
!(1.0), VFloatNum
!(1.0));
34 public VFloat
rnd (VFloat lo
, VFloat hi
) {
36 import std
.random
: uniform
;
37 return cast(VFloat
)uniform
!"[]"(lo
, hi
);
41 // ////////////////////////////////////////////////////////////////////////// //
42 __gshared Body bomb
= null;
44 __gshared VFloat timeStep
= VFloatNum
!(1.0)/VFloatNum
!(60.0);
45 __gshared
int iterations
= 10;
46 __gshared Vec2 gravity
= Vec2(VFloatNum
!(0.0), -VFloatNum
!(10.0));
48 __gshared
int demoIndex
= 0;
50 __gshared World world
;
51 shared static this () { world
= new World(gravity
, iterations
); }
54 // ////////////////////////////////////////////////////////////////////////// //
58 bomb
.set(Vec2(VFloatNum
!(1.0), VFloatNum
!(1.0)), VFloatNum
!(50.0));
59 bomb
.friction
= VFloatNum
!(0.2);
62 bomb
.position
.set(rnd(-VFloatNum
!(15.0), VFloatNum
!(15.0)), VFloatNum
!(15.0));
63 bomb
.rotation
= rnd(-VFloatNum
!(1.5), VFloatNum
!(1.5));
64 bomb
.velocity
= bomb
.position
*(-VFloatNum
!(1.5));
65 bomb
.angularVelocity
= rnd(-VFloatNum
!(20.0), VFloatNum
!(20.0));
69 // ////////////////////////////////////////////////////////////////////////// //
70 void drawBody (Body
body) {
71 auto R
= Mat22(body.rotation
);
72 Vec2 x
= body.position
;
73 Vec2 h
= body.width
*VFloatNum
!(0.5);
75 Vec2 v1
= x
+R
*Vec2(-h
.x
, -h
.y
);
76 Vec2 v2
= x
+R
*Vec2( h
.x
, -h
.y
);
77 Vec2 v3
= x
+R
*Vec2( h
.x
, h
.y
);
78 Vec2 v4
= x
+R
*Vec2(-h
.x
, h
.y
);
81 glColor3f(VFloatNum
!(0.4), VFloatNum
!(0.9), VFloatNum
!(0.4));
83 glColor3f(VFloatNum
!(0.8), VFloatNum
!(0.8), VFloatNum
!(0.9));
86 glBegin(GL_LINE_LOOP
);
87 glVertex2f(v1
.x
, v1
.y
);
88 glVertex2f(v2
.x
, v2
.y
);
89 glVertex2f(v3
.x
, v3
.y
);
90 glVertex2f(v4
.x
, v4
.y
);
95 void drawJoint (Joint joint
) {
96 Body b1
= joint
.body0
;
97 Body b2
= joint
.body1
;
99 auto R1
= Mat22(b1
.rotation
);
100 auto R2
= Mat22(b2
.rotation
);
102 Vec2 x1
= b1
.position
;
103 Vec2 p1
= x1
+R1
*joint
.localAnchor1
;
105 Vec2 x2
= b2
.position
;
106 Vec2 p2
= x2
+R2
*joint
.localAnchor2
;
108 glColor3f(VFloatNum
!(0.5), VFloatNum
!(0.5), VFloatNum
!(0.8));
110 glVertex2f(x1
.x
, x1
.y
);
111 glVertex2f(p1
.x
, p1
.y
);
112 glVertex2f(x2
.x
, x2
.y
);
113 glVertex2f(p2
.x
, p2
.y
);
118 // ////////////////////////////////////////////////////////////////////////// //
120 struct DemoInfo
{ string dsc
; }
124 @DemoInfo("A Single Box") void demo1 () {
125 with (auto b
= new Body()) {
126 b
.set(Vec2(VFloatNum
!(100.0), VFloatNum
!(20.0)), VFloat
.max
);
127 b
.position
.set(VFloatNum
!(0.0), -VFloatNum
!(0.5)*b
.width
.y
);
130 with (auto b
= new Body()) {
131 b
.set(Vec2(VFloatNum
!(1.0), VFloatNum
!(1.0)), VFloatNum
!(200.0));
132 b
.position
.set(VFloatNum
!(0.0), VFloatNum
!(4.0));
139 @DemoInfo("Simple Pendulum") void demo2 () {
140 auto b1
= new Body();
141 b1
.set(Vec2(VFloatNum
!(100.0), VFloatNum
!(20.0)), VFloat
.max
);
142 b1
.friction
= VFloatNum
!(0.2);
143 b1
.position
.set(VFloatNum
!(0.0), -VFloatNum
!(0.5)*b1
.width
.y
);
144 b1
.rotation
= VFloatNum
!(0.0);
147 auto b2
= new Body();
148 b2
.set(Vec2(VFloatNum
!(1.0), VFloatNum
!(1.0)), VFloatNum
!(100.0));
149 b2
.friction
= VFloatNum
!(0.2);
150 b2
.position
.set(VFloatNum
!(9.0), VFloatNum
!(11.0));
151 b2
.rotation
= VFloatNum
!(0.0);
154 with (auto j
= new Joint()) {
155 j
.set(b1
, b2
, Vec2(VFloatNum
!(0.0), VFloatNum
!(11.0)));
161 // varying friction coefficients
162 @DemoInfo("Varying Friction Coefficients") void demo3 () {
163 with (auto b
= new Body()) {
164 b
.set(Vec2(VFloatNum
!(100.0), VFloatNum
!(20.0)), VFloat
.max
);
165 b
.position
.set(VFloatNum
!(0.0), -VFloatNum
!(0.5)*b
.width
.y
);
169 with (auto b
= new Body()) {
170 b
.set(Vec2(VFloatNum
!(13.0), VFloatNum
!(0.25)), VFloat
.max
);
171 b
.position
.set(-VFloatNum
!(2.0), VFloatNum
!(11.0));
172 b
.rotation
= -VFloatNum
!(0.25);
176 with (auto b
= new Body()) {
177 b
.set(Vec2(VFloatNum
!(0.25), VFloatNum
!(1.0)), VFloat
.max
);
178 b
.position
.set(VFloatNum
!(5.25), VFloatNum
!(9.5));
182 with (auto b
= new Body()) {
183 b
.set(Vec2(VFloatNum
!(13.0), VFloatNum
!(0.25)), VFloat
.max
);
184 b
.position
.set(VFloatNum
!(2.0), VFloatNum
!(7.0));
185 b
.rotation
= VFloatNum
!(0.25);
189 with (auto b
= new Body()) {
190 b
.set(Vec2(VFloatNum
!(0.25), VFloatNum
!(1.0)), VFloat
.max
);
191 b
.position
.set(-VFloatNum
!(5.25), VFloatNum
!(5.5));
195 with (auto b
= new Body()) {
196 b
.set(Vec2(VFloatNum
!(13.0), VFloatNum
!(0.25)), VFloat
.max
);
197 b
.position
.set(-VFloatNum
!(2.0), VFloatNum
!(3.0));
198 b
.rotation
= -VFloatNum
!(0.25);
202 static immutable VFloat
[5] frictions
= [VFloatNum
!(0.75), VFloatNum
!(0.5), VFloatNum
!(0.35), VFloatNum
!(0.1), VFloatNum
!(0.0)];
203 for (int idx
= 0; idx
< 5; ++idx
) {
204 with (auto b
= new Body()) {
205 b
.set(Vec2(VFloatNum
!(0.5), VFloatNum
!(0.5)), VFloatNum
!(25.0));
206 b
.friction
= frictions
[idx
];
207 b
.position
.set(-VFloatNum
!(7.5)+VFloatNum
!(2.0)*idx
, VFloatNum
!(14.0));
215 @DemoInfo("Randomized Stacking") void demo4 () {
216 with (auto b
= new Body()) {
217 b
.set(Vec2(VFloatNum
!(100.0), VFloatNum
!(20.0)), VFloat
.max
);
218 b
.friction
= VFloatNum
!(0.2);
219 b
.position
.set(VFloatNum
!(0.0), -VFloatNum
!(0.5)*b
.width
.y
);
220 b
.rotation
= VFloatNum
!(0.0);
224 for (int idx
= 0; idx
< 10; ++idx
) {
225 with (auto b
= new Body()) {
226 b
.set(Vec2(VFloatNum
!(1.0), VFloatNum
!(1.0)), VFloatNum
!(1.0));
227 b
.friction
= VFloatNum
!(0.2);
228 VFloat x
= rnd(-VFloatNum
!(0.1), VFloatNum
!(0.1));
229 b
.position
.set(x
, VFloatNum
!(0.51)+VFloatNum
!(1.05)*idx
);
237 @DemoInfo("Pyramid Stacking") void demo5 () {
238 with (auto b
= new Body()) {
239 b
.set(Vec2(VFloatNum
!(100.0), VFloatNum
!(20.0)), VFloat
.max
);
240 b
.friction
= VFloatNum
!(0.2);
241 b
.position
.set(VFloatNum
!(0.0), -VFloatNum
!(0.5)*b
.width
.y
);
242 b
.rotation
= VFloatNum
!(0.0);
246 Vec2 x
= Vec2(-VFloatNum
!(6.0), VFloatNum
!(0.75));
249 for (int idx
= 0; idx
< 12; ++idx
) {
251 for (int j
= idx
; j
< 12; ++j
) {
252 with (auto b
= new Body()) {
253 b
.set(Vec2(VFloatNum
!(1.0), VFloatNum
!(1.0)), VFloatNum
!(10.0));
254 b
.friction
= VFloatNum
!(0.2);
258 y
+= Vec2(VFloatNum
!(1.125), VFloatNum
!(0.0));
260 //x += Vec2(VFloatNum!(0.5625), VFloatNum!(1.125));
261 x
+= Vec2(VFloatNum
!(0.5625), VFloatNum
!(2.0));
267 @DemoInfo("A Teeter") void demo6 () {
268 Body b1
= new Body();
269 b1
.set(Vec2(VFloatNum
!(100.0), VFloatNum
!(20.0)), VFloat
.max
);
270 b1
.position
.set(VFloatNum
!(0.0), -VFloatNum
!(0.5)*b1
.width
.y
);
273 Body b2
= new Body();
274 b2
.set(Vec2(VFloatNum
!(12.0), VFloatNum
!(0.25)), VFloatNum
!(100.0));
275 b2
.position
.set(VFloatNum
!(0.0), VFloatNum
!(1.0));
278 Body b3
= new Body();
279 b3
.set(Vec2(VFloatNum
!(0.5), VFloatNum
!(0.5)), VFloatNum
!(25.0));
280 b3
.position
.set(-VFloatNum
!(5.0), VFloatNum
!(2.0));
283 Body b4
= new Body();
284 b4
.set(Vec2(VFloatNum
!(0.5), VFloatNum
!(0.5)), VFloatNum
!(25.0));
285 b4
.position
.set(-VFloatNum
!(5.5), VFloatNum
!(2.0));
288 Body b5
= new Body();
289 b5
.set(Vec2(VFloatNum
!(1.0), VFloatNum
!(1.0)), VFloatNum
!(100.0));
290 b5
.position
.set(VFloatNum
!(5.5), VFloatNum
!(15.0));
293 with (auto j
= new Joint()) {
294 j
.set(b1
, b2
, Vec2(VFloatNum
!(0.0), VFloatNum
!(1.0)));
300 // a suspension bridge
301 @DemoInfo("A Suspension Bridge") void demo7 () {
302 import std
.math
: PI
;
304 with (auto b
= new Body()) {
305 b
.set(Vec2(VFloatNum
!(100.0), VFloatNum
!(20.0)), VFloat
.max
);
306 b
.friction
= VFloatNum
!(0.2);
307 b
.position
.set(VFloatNum
!(0.0), -VFloatNum
!(0.5)*b
.width
.y
);
308 b
.rotation
= VFloatNum
!(0.0);
313 VFloat mass
= VFloatNum
!(50.0);
315 for (int idx
= 0; idx
< numPlanks
; ++idx
) {
317 b
.set(Vec2(VFloatNum
!(1.0), VFloatNum
!(0.25)), mass
);
318 b
.friction
= VFloatNum
!(0.2);
319 b
.position
.set(-VFloatNum
!(8.5)+VFloatNum
!(1.25)*idx
, VFloatNum
!(5.0));
324 VFloat frequencyHz
= VFloatNum
!(2.0);
325 VFloat dampingRatio
= VFloatNum
!(0.7);
327 // frequency in radians
328 VFloat omega
= VFloatNum
!(2.0)*PI
*frequencyHz
;
330 // damping coefficient
331 VFloat d
= VFloatNum
!(2.0)*mass
*dampingRatio
*omega
;
334 VFloat k
= mass
*omega
*omega
;
337 VFloat softnesss
= VFloatNum
!(1.0)/(d
+timeStep
*k
);
338 VFloat biasFactorr
= timeStep
*k
/(d
+timeStep
*k
);
340 for (int idx
= 0; idx
< numPlanks
; ++idx
) {
341 auto j
= new Joint();
342 j
.set(world
.bodies
[idx
], world
.bodies
[idx
+1], Vec2(-VFloatNum
!(9.125)+VFloatNum
!(1.25)*idx
, VFloatNum
!(5.0)));
343 j
.softness
= softnesss
;
344 j
.biasFactor
= biasFactorr
;
348 with (auto j
= new Joint()) {
349 j
.set(world
.bodies
[numPlanks
], world
.bodies
[0], Vec2(-VFloatNum
!(9.125)+VFloatNum
!(1.25)*numPlanks
, VFloatNum
!(5.0)));
350 j
.softness
= softnesss
;
351 j
.biasFactor
= biasFactorr
;
358 @DemoInfo("Dominos") void demo8 () {
359 Body b1
= new Body();
360 b1
.set(Vec2(VFloatNum
!(100.0), VFloatNum
!(20.0)), VFloat
.max
);
361 b1
.position
.set(VFloatNum
!(0.0), -VFloatNum
!(0.5)*b1
.width
.y
);
364 with (auto b
= new Body()) {
365 b
.set(Vec2(VFloatNum
!(12.0), VFloatNum
!(0.5)), VFloat
.max
);
366 b
.position
.set(-VFloatNum
!(1.5), VFloatNum
!(10.0));
370 for (int idx
= 0; idx
< 10; ++idx
) {
371 with (auto b
= new Body()) {
372 b
.set(Vec2(VFloatNum
!(0.2), VFloatNum
!(2.0)), VFloatNum
!(10.0));
373 b
.position
.set(-VFloatNum
!(6.0)+VFloatNum
!(1.0)*idx
, VFloatNum
!(11.125));
374 b
.friction
= VFloatNum
!(0.1);
379 with (auto b
= new Body()) {
380 b
.set(Vec2(VFloatNum
!(14.0), VFloatNum
!(0.5)), VFloat
.max
);
381 b
.position
.set(VFloatNum
!(1.0), VFloatNum
!(6.0));
382 b
.rotation
= VFloatNum
!(0.3);
386 Body b2
= new Body();
387 b2
.set(Vec2(VFloatNum
!(0.5), VFloatNum
!(3.0)), VFloat
.max
);
388 b2
.position
.set(-VFloatNum
!(7.0), VFloatNum
!(4.0));
391 Body b3
= new Body();
392 b3
.set(Vec2(VFloatNum
!(12.0), VFloatNum
!(0.25)), VFloatNum
!(20.0));
393 b3
.position
.set(-VFloatNum
!(0.9), VFloatNum
!(1.0));
396 with (auto j
= new Joint()) {
397 j
.set(b1
, b3
, Vec2(-VFloatNum
!(2.0), VFloatNum
!(1.0)));
401 Body b4
= new Body();
402 b4
.set(Vec2(VFloatNum
!(0.5), VFloatNum
!(0.5)), VFloatNum
!(10.0));
403 b4
.position
.set(-VFloatNum
!(10.0), VFloatNum
!(15.0));
406 with (auto j
= new Joint()) {
407 j
.set(b2
, b4
, Vec2(-VFloatNum
!(7.0), VFloatNum
!(15.0)));
411 Body b5
= new Body();
412 b5
.set(Vec2(VFloatNum
!(2.0), VFloatNum
!(2.0)), VFloatNum
!(20.0));
413 b5
.position
.set(VFloatNum
!(6.0), VFloatNum
!(2.5));
414 b5
.friction
= VFloatNum
!(0.1);
417 with (auto j
= new Joint()) {
418 j
.set(b1
, b5
, Vec2(VFloatNum
!(6.0), VFloatNum
!(2.6)));
423 Body b6
= new Body();
424 b6
.set(Vec2(VFloatNum
!(2.0), VFloatNum
!(0.2)), VFloatNum
!(10.0));
425 b6
.position
.set(VFloatNum
!(6.0), VFloatNum
!(3.6));
428 with (auto j
= new Joint()) {
429 j
.set(b5
, b6
, Vec2(VFloatNum
!(7.0), VFloatNum
!(3.5)));
436 @DemoInfo("Multi-pendulum") void demo9 () {
437 import std
.math
: PI
;
439 Body b1
= new Body();
440 b1
.set(Vec2(VFloatNum
!(100.0), VFloatNum
!(20.0)), VFloat
.max
);
441 b1
.friction
= VFloatNum
!(0.2);
442 b1
.position
.set(VFloatNum
!(0.0), -VFloatNum
!(0.5)*b1
.width
.y
);
443 b1
.rotation
= VFloatNum
!(0.0);
446 VFloat mass
= VFloatNum
!(10.0);
449 VFloat frequencyHz
= VFloatNum
!(4.0);
450 VFloat dampingRatio
= VFloatNum
!(0.7);
452 // frequency in radians
453 VFloat omega
= VFloatNum
!(2.0)*PI
*frequencyHz
;
455 // damping coefficient
456 VFloat d
= VFloatNum
!(2.0)*mass
*dampingRatio
*omega
;
459 VFloat k
= mass
*omega
*omega
;
462 VFloat softnesss
= VFloatNum
!(1.0)/(d
+timeStep
*k
);
463 VFloat biasFactorr
= timeStep
*k
/(d
+timeStep
*k
);
465 const VFloat y
= VFloatNum
!(12.0);
467 for (int idx
= 0; idx
< 15; ++idx
) {
468 Vec2 x
= Vec2(VFloatNum
!(0.5)+idx
, y
);
470 b
.set(Vec2(VFloatNum
!(0.75), VFloatNum
!(0.25)), mass
);
471 b
.friction
= VFloatNum
!(0.2);
473 b
.rotation
= VFloatNum
!(0.0);
476 with (auto j
= new Joint()) {
477 j
.set(b1
, b
, Vec2(idx
, y
));
478 j
.softness
= softnesss
;
479 j
.biasFactor
= biasFactorr
;
488 // ////////////////////////////////////////////////////////////////////////// //
489 __gshared
bool paused
= false;
490 __gshared
bool slowmo
= false;
491 __gshared
int slowmocount
= 0;
494 bool setupDemo (int index
, SimpleWindow w
) {
496 alias sms
= getSymbolsByUDA
!(mixin(__MODULE__
), DemoInfo
);
497 foreach (immutable idx
, auto memb
; sms
) {
499 w
.title
= getUDAs
!(memb
, DemoInfo
)[0].dsc
;
511 // ////////////////////////////////////////////////////////////////////////// //
512 void simulationStep () {
513 static double accumulator
= 0;
515 glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT
);
520 snprintf(buf, sizeof(buf), "Demo %d: %s", demoIndex+1, demos[demoIndex].name);
521 DrawText(5, 15, buf);
522 DrawText(5, 45, "Keys: 1-9 Demos, Space to Launch the Bomb");
524 static char buffer[512];
525 sprintf(buffer, "(A)ccumulation %s", (World::accumulateImpulses ? "ON" : "OFF"));
526 DrawText(5, 75, buffer);
528 sprintf(buffer, "(P)osition Correction %s", (World::positionCorrection ? "ON" : "OFF"));
529 DrawText(5, 105, buffer);
531 sprintf(buffer, "(W)arm Starting %s", (World::warmStarting ? "ON" : "OFF"));
532 DrawText(5, 135, buffer);
535 glMatrixMode(GL_MODELVIEW
);
537 glTranslatef(VFloatNum
!(0.0), -VFloatNum
!(7.0), -VFloatNum
!(25.0));
540 contacts
.assumeSafeAppend
;
542 world
.step(timeStep
);
546 // ////////////////////////////////////////////////////////////////////////// //
548 glMatrixMode(GL_MODELVIEW
);
550 glTranslatef(VFloatNum
!(0.0), -VFloatNum
!(7.0), -VFloatNum
!(25.0));
553 foreach (Body b
; world
.bodies
) b
.drawBody();
554 foreach (Joint j
; world
.joints
) j
.drawJoint();
559 glPointSize(VFloatNum
!(4.0));
560 glColor3f(VFloatNum
!(1.0), VFloatNum
!(0.0), VFloatNum
!(0.0));
562 foreach (const ref cxy
; contacts
) glVertex2f(cxy
.x
, cxy
.y
);
564 glPointSize(VFloatNum
!(1.0));
569 // ////////////////////////////////////////////////////////////////////////// //
571 //setOpenGLContextVersion(3, 2); // up to GLSL 150
572 //openGLContextCompatible = false;
574 b2dlDrawContactsCB
= delegate (VFloat x
, VFloat y
) {
575 contacts
~= ContactXY(x
, y
);
578 auto sdwindow
= new SimpleWindow(GWidth
, GHeight
, "Box2DLite Physics", OpenGlOptions
.yes
, Resizablity
.fixedSize
);
579 //sdwindow.hideCursor();
581 //sdwindow.closeQuery = delegate () { concmd("quit"); };
583 sdwindow
.redrawOpenGlScene
= delegate () {
584 glClear(GL_COLOR_BUFFER_BIT
);
588 sdwindow
.visibleForTheFirstTime
= delegate () {
589 setupDemo(0, sdwindow
);
590 sdwindow
.setAsCurrentOpenGlContext(); // make this window active
593 glMatrixMode(GL_PROJECTION);
595 glOrtho(0, GWidth, GHeight, 0, -1, 1);
596 glMatrixMode(GL_MODELVIEW);
599 glViewport(0, 0, GWidth
, GHeight
);
600 glMatrixMode(GL_PROJECTION
);
602 oglPerspective(45.0, cast(VFloat
)GWidth
/cast(VFloat
)GHeight
, 0.1, 100.0);
603 sdwindow
.redrawOpenGlScene();
606 sdwindow
.eventLoop(1000/60,
608 if (sdwindow
.closed || world
is null) return;
611 if (--slowmocount
< 0) {
620 sdwindow
.redrawOpenGlSceneNow();
622 delegate (KeyEvent event
) {
623 if (sdwindow
.closed
) return;
624 if (!event
.pressed
) return;
626 case Key
.Escape
: sdwindow
.close(); break;
630 delegate (MouseEvent event
) {
632 delegate (dchar ch
) {
633 if (ch
== 'q') { sdwindow
.close(); return; }
634 if (ch
== 'r') { setupDemo(demoIndex
, sdwindow
); return; }
635 if (ch
== ' ') { paused
= !paused
; return; }
636 if (ch
== 's') { slowmo
= !slowmo
; return; }
637 if (ch
>= '1' && ch
<= '9') { setupDemo(ch
-'1', sdwindow
); return; }
638 if (ch
== '0') { setupDemo(10, sdwindow
); return; }
639 if (ch
== 'a') { World
.accumulateImpulses
= !World
.accumulateImpulses
; return; }
640 if (ch
== 'p') { World
.positionCorrection
= !World
.positionCorrection
; return; }
641 if (ch
== 'w') { World
.warmStarting
= !World
.warmStarting
; return; }
642 if (ch
== '\n' || ch
== '\r') { launchBomb(); return; }
643 if (ch
== '+') { setupDemo(demoIndex
+1, sdwindow
); return; }
644 if (ch
== '-') { if (demoIndex
> 0) setupDemo(demoIndex
-1, sdwindow
); return; }