1 module xmain
is aliced
;
19 VFloat timeStep
= VFloatNum
!(1.0)/VFloatNum
!(60.0);
21 Vec2 gravity
= Vec2(VFloatNum
!(0.0), -VFloatNum
!(10.0));
26 static this () { world
= new World(gravity
, iterations
); }
29 static void LaunchBomb () {
32 bomb
.set(Vec2(VFloatNum
!(1.0), VFloatNum
!(1.0)), VFloatNum
!(50.0));
33 bomb
.friction
= VFloatNum
!(0.2);
36 bomb
.position
.set(Random(-VFloatNum
!(15.0), VFloatNum
!(15.0)), VFloatNum
!(15.0));
37 bomb
.rotation
= Random(-VFloatNum
!(1.5), VFloatNum
!(1.5));
38 bomb
.velocity
= bomb
.position
*(-VFloatNum
!(1.5));
39 bomb
.angularVelocity
= Random(-VFloatNum
!(20.0), VFloatNum
!(20.0));
43 static void DrawBody (Body
body) {
44 auto R
= Mat22(body.rotation
);
45 Vec2 x
= body.position
;
46 Vec2 h
= body.width
*VFloatNum
!(0.5);
48 Vec2 v1
= x
+R
*Vec2(-h
.x
, -h
.y
);
49 Vec2 v2
= x
+R
*Vec2( h
.x
, -h
.y
);
50 Vec2 v3
= x
+R
*Vec2( h
.x
, h
.y
);
51 Vec2 v4
= x
+R
*Vec2(-h
.x
, h
.y
);
54 glColor3f(VFloatNum
!(0.4), VFloatNum
!(0.9), VFloatNum
!(0.4));
56 glColor3f(VFloatNum
!(0.8), VFloatNum
!(0.8), VFloatNum
!(0.9));
59 glBegin(GL_LINE_LOOP
);
60 glVertex2f(v1
.x
, v1
.y
);
61 glVertex2f(v2
.x
, v2
.y
);
62 glVertex2f(v3
.x
, v3
.y
);
63 glVertex2f(v4
.x
, v4
.y
);
68 static void DrawJoint (Joint joint
) {
69 Body b1
= joint
.body1
;
70 Body b2
= joint
.body2
;
72 auto R1
= Mat22(b1
.rotation
);
73 auto R2
= Mat22(b2
.rotation
);
75 Vec2 x1
= b1
.position
;
76 Vec2 p1
= x1
+R1
*joint
.localAnchor1
;
78 Vec2 x2
= b2
.position
;
79 Vec2 p2
= x2
+R2
*joint
.localAnchor2
;
81 glColor3f(VFloatNum
!(0.5), VFloatNum
!(0.5), VFloatNum
!(0.8));
83 glVertex2f(x1
.x
, x1
.y
);
84 glVertex2f(p1
.x
, p1
.y
);
85 glVertex2f(x2
.x
, x2
.y
);
86 glVertex2f(p2
.x
, p2
.y
);
91 // ////////////////////////////////////////////////////////////////////////// //
93 struct DemoInfo
{ string descr
; }
95 {"A Single Box", Demo1},
96 {"Simple Pendulum", Demo2},
97 {"Varying Friction Coefficients", Demo3},
98 {"Randomized Stacking", Demo4},
99 {"Pyramid Stacking", Demo5},
101 {"A Suspension Bridge", Demo7},
103 {"Multi-pendulum", Demo9},
107 @DemoInfo("A Single Box") void Demo1 () {
108 with (auto b
= new Body()) {
109 b
.set(Vec2(VFloatNum
!(100.0), VFloatNum
!(20.0)), VFloat
.max
);
110 b
.position
.set(VFloatNum
!(0.0), -VFloatNum
!(0.5)*b
.width
.y
);
113 with (auto b
= new Body()) {
114 b
.set(Vec2(VFloatNum
!(1.0), VFloatNum
!(1.0)), VFloatNum
!(200.0));
115 b
.position
.set(VFloatNum
!(0.0), VFloatNum
!(4.0));
122 @DemoInfo("Simple Pendulum") void Demo2 () {
123 auto b1
= new Body();
124 b1
.set(Vec2(VFloatNum
!(100.0), VFloatNum
!(20.0)), VFloat
.max
);
125 b1
.friction
= VFloatNum
!(0.2);
126 b1
.position
.set(VFloatNum
!(0.0), -VFloatNum
!(0.5)*b1
.width
.y
);
127 b1
.rotation
= VFloatNum
!(0.0);
130 auto b2
= new Body();
131 b2
.set(Vec2(VFloatNum
!(1.0), VFloatNum
!(1.0)), VFloatNum
!(100.0));
132 b2
.friction
= VFloatNum
!(0.2);
133 b2
.position
.set(VFloatNum
!(9.0), VFloatNum
!(11.0));
134 b2
.rotation
= VFloatNum
!(0.0);
137 with (auto j
= new Joint()) {
138 j
.set(b1
, b2
, Vec2(VFloatNum
!(0.0), VFloatNum
!(11.0)));
144 // varying friction coefficients
145 @DemoInfo("Varying Friction Coefficients") void Demo3 () {
146 with (auto b
= new Body()) {
147 b
.set(Vec2(VFloatNum
!(100.0), VFloatNum
!(20.0)), VFloat
.max
);
148 b
.position
.set(VFloatNum
!(0.0), -VFloatNum
!(0.5)*b
.width
.y
);
152 with (auto b
= new Body()) {
153 b
.set(Vec2(VFloatNum
!(13.0), VFloatNum
!(0.25)), VFloat
.max
);
154 b
.position
.set(-VFloatNum
!(2.0), VFloatNum
!(11.0));
155 b
.rotation
= -VFloatNum
!(0.25);
159 with (auto b
= new Body()) {
160 b
.set(Vec2(VFloatNum
!(0.25), VFloatNum
!(1.0)), VFloat
.max
);
161 b
.position
.set(VFloatNum
!(5.25), VFloatNum
!(9.5));
165 with (auto b
= new Body()) {
166 b
.set(Vec2(VFloatNum
!(13.0), VFloatNum
!(0.25)), VFloat
.max
);
167 b
.position
.set(VFloatNum
!(2.0), VFloatNum
!(7.0));
168 b
.rotation
= VFloatNum
!(0.25);
172 with (auto b
= new Body()) {
173 b
.set(Vec2(VFloatNum
!(0.25), VFloatNum
!(1.0)), VFloat
.max
);
174 b
.position
.set(-VFloatNum
!(5.25), VFloatNum
!(5.5));
178 with (auto b
= new Body()) {
179 b
.set(Vec2(VFloatNum
!(13.0), VFloatNum
!(0.25)), VFloat
.max
);
180 b
.position
.set(-VFloatNum
!(2.0), VFloatNum
!(3.0));
181 b
.rotation
= -VFloatNum
!(0.25);
185 static immutable VFloat
[5] frictions
= [VFloatNum
!(0.75), VFloatNum
!(0.5), VFloatNum
!(0.35), VFloatNum
!(0.1), VFloatNum
!(0.0)];
186 for (int i
= 0; i
< 5; ++i
) {
187 with (auto b
= new Body()) {
188 b
.set(Vec2(VFloatNum
!(0.5), VFloatNum
!(0.5)), VFloatNum
!(25.0));
189 b
.friction
= frictions
[i
];
190 b
.position
.set(-VFloatNum
!(7.5)+VFloatNum
!(2.0)*i
, VFloatNum
!(14.0));
198 @DemoInfo("Randomized Stacking") void Demo4 () {
199 with (auto b
= new Body()) {
200 b
.set(Vec2(VFloatNum
!(100.0), VFloatNum
!(20.0)), VFloat
.max
);
201 b
.friction
= VFloatNum
!(0.2);
202 b
.position
.set(VFloatNum
!(0.0), -VFloatNum
!(0.5)*b
.width
.y
);
203 b
.rotation
= VFloatNum
!(0.0);
207 for (int i
= 0; i
< 10; ++i
) {
208 with (auto b
= new Body()) {
209 b
.set(Vec2(VFloatNum
!(1.0), VFloatNum
!(1.0)), VFloatNum
!(1.0));
210 b
.friction
= VFloatNum
!(0.2);
211 VFloat x
= Random(-VFloatNum
!(0.1), VFloatNum
!(0.1));
212 b
.position
.set(x
, VFloatNum
!(0.51)+VFloatNum
!(1.05)*i
);
220 @DemoInfo("Pyramid Stacking") void Demo5 () {
221 with (auto b
= new Body()) {
222 b
.set(Vec2(VFloatNum
!(100.0), VFloatNum
!(20.0)), VFloat
.max
);
223 b
.friction
= VFloatNum
!(0.2);
224 b
.position
.set(VFloatNum
!(0.0), -VFloatNum
!(0.5)*b
.width
.y
);
225 b
.rotation
= VFloatNum
!(0.0);
229 Vec2 x
= Vec2(-VFloatNum
!(6.0), VFloatNum
!(0.75));
232 for (int i
= 0; i
< 12; ++i
) {
234 for (int j
= i
; j
< 12; ++j
) {
235 with (auto b
= new Body()) {
236 b
.set(Vec2(VFloatNum
!(1.0), VFloatNum
!(1.0)), VFloatNum
!(10.0));
237 b
.friction
= VFloatNum
!(0.2);
241 y
+= Vec2(VFloatNum
!(1.125), VFloatNum
!(0.0));
243 //x += Vec2(VFloatNum!(0.5625), VFloatNum!(1.125));
244 x
+= Vec2(VFloatNum
!(0.5625), VFloatNum
!(2.0));
250 @DemoInfo("A Teeter") void Demo6 () {
251 Body b1
= new Body();
252 b1
.set(Vec2(VFloatNum
!(100.0), VFloatNum
!(20.0)), VFloat
.max
);
253 b1
.position
.set(VFloatNum
!(0.0), -VFloatNum
!(0.5)*b1
.width
.y
);
256 Body b2
= new Body();
257 b2
.set(Vec2(VFloatNum
!(12.0), VFloatNum
!(0.25)), VFloatNum
!(100.0));
258 b2
.position
.set(VFloatNum
!(0.0), VFloatNum
!(1.0));
261 Body b3
= new Body();
262 b3
.set(Vec2(VFloatNum
!(0.5), VFloatNum
!(0.5)), VFloatNum
!(25.0));
263 b3
.position
.set(-VFloatNum
!(5.0), VFloatNum
!(2.0));
266 Body b4
= new Body();
267 b4
.set(Vec2(VFloatNum
!(0.5), VFloatNum
!(0.5)), VFloatNum
!(25.0));
268 b4
.position
.set(-VFloatNum
!(5.5), VFloatNum
!(2.0));
271 Body b5
= new Body();
272 b5
.set(Vec2(VFloatNum
!(1.0), VFloatNum
!(1.0)), VFloatNum
!(100.0));
273 b5
.position
.set(VFloatNum
!(5.5), VFloatNum
!(15.0));
276 with (auto j
= new Joint()) {
277 j
.set(b1
, b2
, Vec2(VFloatNum
!(0.0), VFloatNum
!(1.0)));
283 // a suspension bridge
284 @DemoInfo("A Suspension Bridge") void Demo7 () {
285 with (auto b
= new Body()) {
286 b
.set(Vec2(VFloatNum
!(100.0), VFloatNum
!(20.0)), VFloat
.max
);
287 b
.friction
= VFloatNum
!(0.2);
288 b
.position
.set(VFloatNum
!(0.0), -VFloatNum
!(0.5)*b
.width
.y
);
289 b
.rotation
= VFloatNum
!(0.0);
294 VFloat mass
= VFloatNum
!(50.0);
296 for (int i
= 0; i
< numPlanks
; ++i
) {
298 b
.set(Vec2(VFloatNum
!(1.0), VFloatNum
!(0.25)), mass
);
299 b
.friction
= VFloatNum
!(0.2);
300 b
.position
.set(-VFloatNum
!(8.5)+VFloatNum
!(1.25)*i
, VFloatNum
!(5.0));
305 VFloat frequencyHz
= VFloatNum
!(2.0);
306 VFloat dampingRatio
= VFloatNum
!(0.7);
308 // frequency in radians
309 VFloat omega
= VFloatNum
!(2.0)*PI
*frequencyHz
;
311 // damping coefficient
312 VFloat d
= VFloatNum
!(2.0)*mass
*dampingRatio
*omega
;
315 VFloat k
= mass
*omega
*omega
;
318 VFloat softnesss
= VFloatNum
!(1.0)/(d
+timeStep
*k
);
319 VFloat biasFactorr
= timeStep
*k
/(d
+timeStep
*k
);
321 for (int i
= 0; i
< numPlanks
; ++i
) {
322 auto j
= new Joint();
323 j
.set(world
.bodies
[i
], world
.bodies
[i
+1], Vec2(-VFloatNum
!(9.125)+VFloatNum
!(1.25)*i
, VFloatNum
!(5.0)));
324 j
.softness
= softnesss
;
325 j
.biasFactor
= biasFactorr
;
329 with (auto j
= new Joint()) {
330 j
.set(world
.bodies
[numPlanks
], world
.bodies
[0], Vec2(-VFloatNum
!(9.125)+VFloatNum
!(1.25)*numPlanks
, VFloatNum
!(5.0)));
331 j
.softness
= softnesss
;
332 j
.biasFactor
= biasFactorr
;
339 @DemoInfo("Dominos") void Demo8 () {
340 Body b1
= new Body();
341 b1
.set(Vec2(VFloatNum
!(100.0), VFloatNum
!(20.0)), VFloat
.max
);
342 b1
.position
.set(VFloatNum
!(0.0), -VFloatNum
!(0.5)*b1
.width
.y
);
345 with (auto b
= new Body()) {
346 b
.set(Vec2(VFloatNum
!(12.0), VFloatNum
!(0.5)), VFloat
.max
);
347 b
.position
.set(-VFloatNum
!(1.5), VFloatNum
!(10.0));
351 for (int i
= 0; i
< 10; ++i
) {
352 with (auto b
= new Body()) {
353 b
.set(Vec2(VFloatNum
!(0.2), VFloatNum
!(2.0)), VFloatNum
!(10.0));
354 b
.position
.set(-VFloatNum
!(6.0)+VFloatNum
!(1.0)*i
, VFloatNum
!(11.125));
355 b
.friction
= VFloatNum
!(0.1);
360 with (auto b
= new Body()) {
361 b
.set(Vec2(VFloatNum
!(14.0), VFloatNum
!(0.5)), VFloat
.max
);
362 b
.position
.set(VFloatNum
!(1.0), VFloatNum
!(6.0));
363 b
.rotation
= VFloatNum
!(0.3);
367 Body b2
= new Body();
368 b2
.set(Vec2(VFloatNum
!(0.5), VFloatNum
!(3.0)), VFloat
.max
);
369 b2
.position
.set(-VFloatNum
!(7.0), VFloatNum
!(4.0));
372 Body b3
= new Body();
373 b3
.set(Vec2(VFloatNum
!(12.0), VFloatNum
!(0.25)), VFloatNum
!(20.0));
374 b3
.position
.set(-VFloatNum
!(0.9), VFloatNum
!(1.0));
377 with (auto j
= new Joint()) {
378 j
.set(b1
, b3
, Vec2(-VFloatNum
!(2.0), VFloatNum
!(1.0)));
382 Body b4
= new Body();
383 b4
.set(Vec2(VFloatNum
!(0.5), VFloatNum
!(0.5)), VFloatNum
!(10.0));
384 b4
.position
.set(-VFloatNum
!(10.0), VFloatNum
!(15.0));
387 with (auto j
= new Joint()) {
388 j
.set(b2
, b4
, Vec2(-VFloatNum
!(7.0), VFloatNum
!(15.0)));
392 Body b5
= new Body();
393 b5
.set(Vec2(VFloatNum
!(2.0), VFloatNum
!(2.0)), VFloatNum
!(20.0));
394 b5
.position
.set(VFloatNum
!(6.0), VFloatNum
!(2.5));
395 b5
.friction
= VFloatNum
!(0.1);
398 with (auto j
= new Joint()) {
399 j
.set(b1
, b5
, Vec2(VFloatNum
!(6.0), VFloatNum
!(2.6)));
404 Body b6
= new Body();
405 b6
.set(Vec2(VFloatNum
!(2.0), VFloatNum
!(0.2)), VFloatNum
!(10.0));
406 b6
.position
.set(VFloatNum
!(6.0), VFloatNum
!(3.6));
409 with (auto j
= new Joint()) {
410 j
.set(b5
, b6
, Vec2(VFloatNum
!(7.0), VFloatNum
!(3.5)));
417 @DemoInfo("Multi-pendulum") void Demo9 () {
418 Body b1
= new Body();
419 b1
.set(Vec2(VFloatNum
!(100.0), VFloatNum
!(20.0)), VFloat
.max
);
420 b1
.friction
= VFloatNum
!(0.2);
421 b1
.position
.set(VFloatNum
!(0.0), -VFloatNum
!(0.5)*b1
.width
.y
);
422 b1
.rotation
= VFloatNum
!(0.0);
425 VFloat mass
= VFloatNum
!(10.0);
428 VFloat frequencyHz
= VFloatNum
!(4.0);
429 VFloat dampingRatio
= VFloatNum
!(0.7);
431 // frequency in radians
432 VFloat omega
= VFloatNum
!(2.0)*PI
*frequencyHz
;
434 // damping coefficient
435 VFloat d
= VFloatNum
!(2.0)*mass
*dampingRatio
*omega
;
438 VFloat k
= mass
*omega
*omega
;
441 VFloat softnesss
= VFloatNum
!(1.0)/(d
+timeStep
*k
);
442 VFloat biasFactorr
= timeStep
*k
/(d
+timeStep
*k
);
444 const VFloat y
= VFloatNum
!(12.0);
446 for (int i
= 0; i
< 15; ++i
) {
447 Vec2 x
= Vec2(VFloatNum
!(0.5)+i
, y
);
449 b
.set(Vec2(VFloatNum
!(0.75), VFloatNum
!(0.25)), mass
);
450 b
.friction
= VFloatNum
!(0.2);
452 b
.rotation
= VFloatNum
!(0.0);
455 with (auto j
= new Joint()) {
456 j
.set(b1
, b
, Vec2(i
, y
));
457 j
.softness
= softnesss
;
458 j
.biasFactor
= biasFactorr
;
467 // ////////////////////////////////////////////////////////////////////////// //
468 __gshared
bool paused
= false;
469 __gshared
bool slowmo
= false;
470 __gshared
int slowmocount
= 0;
473 void InitDemo (int index
) {
475 alias sms
= getSymbolsByUDA
!(mixin(__MODULE__
), DemoInfo
);
476 foreach (immutable idx
, auto memb
; sms
) {
477 //pragma(msg, idx, " ", memb);
480 //{ import std.stdio; writeln(idx); }
489 foreach (string memb; __traits(allMembers, mixin(__MODULE__))) {
490 static if (is(typeof(__traits(getMember, mixin(__MODULE__), memb)))) {
491 static if (hasUDA!(__traits(getMember, mixin(__MODULE__), memb), DemoInfo)) {
501 void SimulationLoop () {
502 //static uint64_t t_start = 0;
503 static double accumulator
= 0;
507 glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT
);
510 snprintf(buf, sizeof(buf), "Demo %d: %s", demoIndex+1, demos[demoIndex].name);
511 DrawText(5, 15, buf);
512 DrawText(5, 45, "Keys: 1-9 Demos, Space to Launch the Bomb");
514 static char buffer[512];
515 sprintf(buffer, "(A)ccumulation %s", (World::accumulateImpulses ? "ON" : "OFF"));
516 DrawText(5, 75, buffer);
518 sprintf(buffer, "(P)osition Correction %s", (World::positionCorrection ? "ON" : "OFF"));
519 DrawText(5, 105, buffer);
521 sprintf(buffer, "(W)arm Starting %s", (World::warmStarting ? "ON" : "OFF"));
522 DrawText(5, 135, buffer);
525 glMatrixMode(GL_MODELVIEW
);
527 glTranslatef(VFloatNum
!(0.0), -VFloatNum
!(7.0), -VFloatNum
!(25.0));
530 t_cur = k8clock_msec(NULL);
531 if (t_start == 0) t_start = t_cur;
533 //world.Step(timeStep);
534 accumulator += (t_cur-t_start)/1000.0;
537 if (accumulator < 0.0) accumulator = 0.0;
538 else if (accumulator > 0.1) accumulator = 0.1;
540 while (accumulator >= timeStep) {
541 if (!frameStepping) {
542 world.Step(timeStep);
545 world.Step(timeStep);
549 accumulator -= timeStep;
552 world
.Step(timeStep
);
557 glMatrixMode(GL_MODELVIEW
);
559 glTranslatef(VFloatNum
!(0.0), -VFloatNum
!(7.0), -VFloatNum
!(25.0));
562 foreach (Body b
; world
.bodies
) b
.DrawBody();
563 foreach (Joint j
; world
.joints
) j
.DrawJoint();
568 //setOpenGLContextVersion(3, 2); // up to GLSL 150
569 //openGLContextCompatible = false;
571 auto sdwindow
= new SimpleWindow(GWidth
, GHeight
, "Verlet Physics", OpenGlOptions
.yes
, Resizablity
.fixedSize
);
572 //sdwindow.hideCursor();
574 //sdwindow.closeQuery = delegate () { concmd("quit"); };
576 sdwindow
.redrawOpenGlScene
= delegate () {
577 glClear(GL_COLOR_BUFFER_BIT
);
581 if (dragVertex !is null) {
582 glPointSize(VFloatNum!(6.0));
583 glColor3f(VFloatNum!(1.0), VFloatNum!(1.0), VFloatNum!(0.0));
585 glVertex2f(dragVertex.position.x, dragVertex.position.y);
592 sdwindow
.visibleForTheFirstTime
= delegate () {
594 sdwindow
.setAsCurrentOpenGlContext(); // make this window active
595 glbindLoadFunctions();
598 glMatrixMode(GL_PROJECTION);
600 glOrtho(0, GWidth, GHeight, 0, -1, 1);
601 glMatrixMode(GL_MODELVIEW);
604 glViewport(0, 0, GWidth
, GHeight
);
605 glMatrixMode(GL_PROJECTION
);
607 oglPerspective(45.0, cast(VFloat
)GWidth
/cast(VFloat
)GHeight
, 0.1, 100.0);
608 sdwindow
.redrawOpenGlScene();
611 sdwindow
.eventLoop(cast(int)(VFloatNum
!(1000.0)/VFloatNum
!(60.0)),
613 if (sdwindow
.closed || world
is null) return;
616 if (--slowmocount
< 0) {
625 sdwindow
.redrawOpenGlSceneNow();
627 delegate (KeyEvent event
) {
628 if (sdwindow
.closed
) return;
629 if (!event
.pressed
) return;
631 case Key
.Escape
: sdwindow
.close(); break;
635 delegate (MouseEvent event
) {
637 if (event.type == MouseEventType.buttonPressed) {
638 if (event.button == MouseButton.left) dragVertex = world.FindVertex(event.x, event.y);
639 if (event.button == MouseButton.right) dragVertex = null;
640 } else if (event.type == MouseEventType.buttonReleased) {
641 if (event.button == MouseButton.left) dragVertex = null;
643 if (dragVertex !is null) dragVertex.position = Vec2(cast(VFloat)event.x, cast(VFloat)event.y); // sets the position of the dragVertex to the mouse position to drag it around
646 delegate (dchar ch
) {
647 if (ch
== 'q') { sdwindow
.close(); return; }
648 if (ch
== 'r') { InitDemo(demoIndex
); return; }
649 if (ch
== ' ') { paused
= !paused
; return; }
650 if (ch
== 's') { slowmo
= !slowmo
; return; }
651 if (ch
>= '1' && ch
<= '9') { InitDemo(ch
-'1'); return; }
652 if (ch
== '0') { InitDemo(10); return; }
653 if (ch
== 'a') { World
.accumulateImpulses
= !World
.accumulateImpulses
; return; }
654 if (ch
== 'p') { World
.positionCorrection
= !World
.positionCorrection
; return; }
655 if (ch
== 'w') { World
.warmStarting
= !World
.warmStarting
; return; }
656 if (ch
== '\n' || ch
== '\r') { LaunchBomb(); }