2 * Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com
4 * Permission to use, copy, modify, distribute and sell this software
5 * and its documentation for any purpose is hereby granted without fee,
6 * provided that the above copyright notice appear in all copies.
7 * Erin Catto makes no representations about the suitability
8 * of this software for any purpose.
9 * It is provided "as is" without express or implied warranty.
11 * Changes by Ketmar // Invisible Vector
15 import arsd
.simpledisplay
;
19 import iv
.glbinds
.utils
;
24 bool optShowTimes
= false;
25 bool optDrawBVH
= false;
28 // ////////////////////////////////////////////////////////////////////////// //
33 // ////////////////////////////////////////////////////////////////////////// //
34 __gshared BodyContact
[] contacts
;
37 // ////////////////////////////////////////////////////////////////////////// //
38 // random number in range [-1,1]
39 public VFloat
rnd () {
41 import std
.random
: uniform
;
42 return cast(VFloat
)uniform
!"[]"(-VFloatNum
!1, VFloatNum
!1);
45 public VFloat
rnd (VFloat lo
, VFloat hi
) {
47 import std
.random
: uniform
;
48 return cast(VFloat
)uniform
!"[]"(lo
, hi
);
52 // ////////////////////////////////////////////////////////////////////////// //
53 __gshared BodyBase bomb
= null;
55 __gshared VFloat timeStep
= VFloatNum
!1/VFloatNum
!60;
56 __gshared
int iterations
= 10;
57 __gshared Vec2 gravity
= Vec2(VFloatNum
!0, -VFloatNum
!10);
59 __gshared
int demoIndex
= 0;
61 __gshared World world
;
62 shared static this () { world
= new World(gravity
, iterations
); }
65 // ////////////////////////////////////////////////////////////////////////// //
66 void launchBomb (SimpleWindow sdwin
) {
67 if (true/*bomb is null*/) {
68 auto bb
= new PolyBody();
70 foreach (int ang
; 0..10) {
71 import std
.math
: cos
, sin
;
72 import std
.random
: uniform
;
73 Vec2 v
= Vec2(0.6*cos(deg2rad(360/10*ang
))*uniform
!"[]"(0.7, 1.3), 0.6*sin(deg2rad(360/10*ang
))*uniform
!"[]"(0.7, 1.3));
78 //bomb = PolyBody.Box(Vec2(VFloatNum!1, VFloatNum!1), VFloatNum!50);
79 bomb
.friction
= VFloatNum
!(0.2);
82 bomb
.position
.set(rnd(-VFloatNum
!15, VFloatNum
!15), VFloatNum
!15);
83 bomb
.rotation
= rnd(-VFloatNum
!(1.5), VFloatNum
!(1.5));
84 bomb
.velocity
= bomb
.position
*(-VFloatNum
!(1.5));
85 bomb
.angularVelocity
= rnd(-VFloatNum
!20, VFloatNum
!20);
87 import std
.format
: format
;
88 sdwin
.title
= "bodies: %s".format(world
.bodies
.length
);
92 // ////////////////////////////////////////////////////////////////////////// //
93 void drawBody (BodyBase bodyb
) {
94 if (auto booody
= cast(PolyBody
)bodyb
) {
95 auto rmt
= Mat22(booody
.rotation
);
98 glColor3f(VFloatNum
!(0.4), VFloatNum
!(0.9), VFloatNum
!(0.4));
100 glColor3f(VFloatNum
!(0.8), VFloatNum
!(0.8), VFloatNum
!(0.9));
103 glBegin(GL_LINE_LOOP
);
104 foreach (const ref vx
; booody
.verts
) {
105 auto vp
= booody
.position
+rmt
*vx
;
106 glVertex2f(vp
.x
, vp
.y
);
113 void drawJoint (Joint joint
) {
114 auto b1
= joint
.body0
;
115 auto b2
= joint
.body1
;
117 auto R1
= Mat22(b1
.rotation
);
118 auto R2
= Mat22(b2
.rotation
);
120 Vec2 x1
= b1
.position
;
121 Vec2 p1
= x1
+R1
*joint
.localAnchor1
;
123 Vec2 x2
= b2
.position
;
124 Vec2 p2
= x2
+R2
*joint
.localAnchor2
;
126 glColor3f(VFloatNum
!(0.5), VFloatNum
!(0.5), VFloatNum
!(0.8));
128 glVertex2f(x1
.x
, x1
.y
);
129 glVertex2f(p1
.x
, p1
.y
);
130 glVertex2f(x2
.x
, x2
.y
);
131 glVertex2f(p2
.x
, p2
.y
);
136 // ////////////////////////////////////////////////////////////////////////// //
138 enum BoxW
= VFloatNum
!100;
139 enum BoxH
= VFloatNum
!20;
141 struct DemoInfo
{ string dsc
; }
145 @DemoInfo("A Single Box") void demo1 () {
146 if (auto b
= PolyBody
.Box(Vec2(BoxW
, BoxH
), VFloat
.max
)) {
147 b
.position
.set(VFloatNum
!0, -VFloatNum
!(0.5)*BoxH
/*b.width.y*/);
150 if (auto b
= PolyBody
.Box(Vec2(VFloatNum
!1, VFloatNum
!1), VFloatNum
!200)) {
151 b
.position
.set(VFloatNum
!0, VFloatNum
!4);
158 @DemoInfo("Simple Pendulum") void demo2 () {
159 auto b1
= PolyBody
.Box(Vec2(BoxW
, BoxH
), VFloat
.max
);
160 b1
.friction
= VFloatNum
!(0.2);
161 b1
.position
.set(VFloatNum
!0, -VFloatNum
!(0.5)*BoxH
/*b1.width.y*/);
162 b1
.rotation
= VFloatNum
!0;
165 auto b2
= PolyBody
.Box(Vec2(VFloatNum
!1, VFloatNum
!1), VFloatNum
!100);
166 b2
.friction
= VFloatNum
!(0.2);
167 b2
.position
.set(VFloatNum
!9, VFloatNum
!11);
168 b2
.rotation
= VFloatNum
!0;
171 if (auto j
= new Joint()) {
172 j
.set(b1
, b2
, Vec2(VFloatNum
!0, VFloatNum
!11));
178 // varying friction coefficients
179 @DemoInfo("Varying Friction Coefficients") void demo3 () {
180 if (auto b
= PolyBody
.Box(Vec2(BoxW
, BoxH
), VFloat
.max
)) {
181 b
.position
.set(VFloatNum
!0, -VFloatNum
!(0.5)*BoxH
/*b.width.y*/);
185 if (auto b
= PolyBody
.Box(Vec2(VFloatNum
!13, VFloatNum
!(0.25)), VFloat
.max
)) {
186 b
.position
.set(-VFloatNum
!2, VFloatNum
!11);
187 b
.rotation
= -VFloatNum
!(0.25);
191 if (auto b
= PolyBody
.Box(Vec2(VFloatNum
!(0.25), VFloatNum
!1), VFloat
.max
)) {
192 b
.position
.set(VFloatNum
!(5.25), VFloatNum
!(9.5));
196 if (auto b
= PolyBody
.Box(Vec2(VFloatNum
!13, VFloatNum
!(0.25)), VFloat
.max
)) {
197 b
.position
.set(VFloatNum
!2, VFloatNum
!7);
198 b
.rotation
= VFloatNum
!(0.25);
202 if (auto b
= PolyBody
.Box(Vec2(VFloatNum
!(0.25), VFloatNum
!1), VFloat
.max
)) {
203 b
.position
.set(-VFloatNum
!(5.25), VFloatNum
!(5.5));
207 if (auto b
= PolyBody
.Box(Vec2(VFloatNum
!13, VFloatNum
!(0.25)), VFloat
.max
)) {
208 b
.position
.set(-VFloatNum
!2, VFloatNum
!3);
209 b
.rotation
= -VFloatNum
!(0.25);
213 static immutable VFloat
[5] frictions
= [VFloatNum
!(0.75), VFloatNum
!(0.5), VFloatNum
!(0.35), VFloatNum
!(0.1), VFloatNum
!0];
214 for (int idx
= 0; idx
< 5; ++idx
) {
215 if (auto b
= PolyBody
.Box(Vec2(VFloatNum
!(0.5), VFloatNum
!(0.5)), VFloatNum
!25)) {
216 b
.friction
= frictions
[idx
];
217 b
.position
.set(-VFloatNum
!(7.5)+VFloatNum
!2*idx
, VFloatNum
!14);
225 @DemoInfo("Randomized Stacking") void demo4 () {
226 if (auto b
= PolyBody
.Box(Vec2(BoxW
, BoxH
), VFloat
.max
)) {
227 b
.friction
= VFloatNum
!(0.2);
228 b
.position
.set(VFloatNum
!0, -VFloatNum
!(0.5)*BoxH
/*b.width.y*/);
229 b
.rotation
= VFloatNum
!0;
233 for (int idx
= 0; idx
< 10; ++idx
) {
234 if (auto b
= PolyBody
.Box(Vec2(VFloatNum
!1, VFloatNum
!1), VFloatNum
!1)) {
235 b
.friction
= VFloatNum
!(0.2);
236 VFloat x
= rnd(-VFloatNum
!(0.1), VFloatNum
!(0.1));
237 b
.position
.set(x
, VFloatNum
!(0.51)+VFloatNum
!(1.05)*idx
);
245 @DemoInfo("Pyramid Stacking") void demo5 () {
246 if (auto b
= PolyBody
.Box(Vec2(BoxW
, BoxH
), VFloat
.max
)) {
247 b
.friction
= VFloatNum
!(0.2);
248 b
.position
.set(VFloatNum
!0, -VFloatNum
!(0.5)*BoxH
/*b.width.y*/);
249 b
.rotation
= VFloatNum
!0;
253 Vec2 x
= Vec2(-VFloatNum
!6, VFloatNum
!(0.75));
256 for (int idx
= 0; idx
< 12; ++idx
) {
258 for (int j
= idx
; j
< 12; ++j
) {
259 if (auto b
= PolyBody
.Box(Vec2(VFloatNum
!1, VFloatNum
!1), VFloatNum
!10)) {
260 b
.friction
= VFloatNum
!(0.2);
264 y
+= Vec2(VFloatNum
!(1.125), VFloatNum
!0);
266 //x += Vec2(VFloatNum!(0.5625), VFloatNum!(1.125));
267 x
+= Vec2(VFloatNum
!(0.5625), VFloatNum
!2);
273 @DemoInfo("A Teeter") void demo6 () {
274 BodyBase b1
= PolyBody
.Box(Vec2(BoxW
, BoxH
), VFloat
.max
);
275 b1
.position
.set(VFloatNum
!0, -VFloatNum
!(0.5)*BoxH
/*b1.width.y*/);
278 BodyBase b2
= PolyBody
.Box(Vec2(VFloatNum
!12, VFloatNum
!(0.25)), VFloatNum
!100);
279 b2
.position
.set(VFloatNum
!0, VFloatNum
!1);
282 BodyBase b3
= PolyBody
.Box(Vec2(VFloatNum
!(0.5), VFloatNum
!(0.5)), VFloatNum
!25);
283 b3
.position
.set(-VFloatNum
!5, VFloatNum
!2);
286 BodyBase b4
= PolyBody
.Box(Vec2(VFloatNum
!(0.5), VFloatNum
!(0.5)), VFloatNum
!25);
287 b4
.position
.set(-VFloatNum
!(5.5), VFloatNum
!2);
290 BodyBase b5
= PolyBody
.Box(Vec2(VFloatNum
!1, VFloatNum
!1), VFloatNum
!100);
291 b5
.position
.set(VFloatNum
!(5.5), VFloatNum
!15);
294 if (auto j
= new Joint()) {
295 j
.set(b1
, b2
, Vec2(VFloatNum
!0, VFloatNum
!1));
301 // a suspension bridge
302 @DemoInfo("A Suspension Bridge") void demo7 () {
303 import std
.math
: PI
;
305 if (auto b
= PolyBody
.Box(Vec2(BoxW
, BoxH
), VFloat
.max
)) {
306 b
.friction
= VFloatNum
!(0.2);
307 b
.position
.set(VFloatNum
!0, -VFloatNum
!(0.5)*BoxH
/*b.width.y*/);
308 b
.rotation
= VFloatNum
!0;
313 VFloat mass
= VFloatNum
!50;
315 for (int idx
= 0; idx
< numPlanks
; ++idx
) {
316 auto b
= PolyBody
.Box(Vec2(VFloatNum
!1, VFloatNum
!(0.25)), mass
);
317 b
.friction
= VFloatNum
!(0.2);
318 b
.position
.set(-VFloatNum
!(8.5)+VFloatNum
!(1.25)*idx
, VFloatNum
!5);
323 VFloat frequencyHz
= VFloatNum
!2;
324 VFloat dampingRatio
= VFloatNum
!(0.7);
326 // frequency in radians
327 VFloat omega
= VFloatNum
!2*PI
*frequencyHz
;
329 // damping coefficient
330 VFloat d
= VFloatNum
!2*mass
*dampingRatio
*omega
;
333 VFloat k
= mass
*omega
*omega
;
336 VFloat softnesss
= VFloatNum
!1/(d
+timeStep
*k
);
337 VFloat biasFactorr
= timeStep
*k
/(d
+timeStep
*k
);
339 for (int idx
= 0; idx
< numPlanks
; ++idx
) {
340 auto j
= new Joint();
341 j
.set(world
.bodies
[idx
], world
.bodies
[idx
+1], Vec2(-VFloatNum
!(9.125)+VFloatNum
!(1.25)*idx
, VFloatNum
!5));
342 j
.softness
= softnesss
;
343 j
.biasFactor
= biasFactorr
;
347 if (auto j
= new Joint()) {
348 j
.set(world
.bodies
[numPlanks
], world
.bodies
[0], Vec2(-VFloatNum
!(9.125)+VFloatNum
!(1.25)*numPlanks
, VFloatNum
!5));
349 j
.softness
= softnesss
;
350 j
.biasFactor
= biasFactorr
;
357 @DemoInfo("Dominos") void demo8 () {
358 BodyBase b1
= PolyBody
.Box(Vec2(BoxW
, BoxH
), VFloat
.max
);
359 b1
.position
.set(VFloatNum
!0, -VFloatNum
!(0.5)*BoxH
/*b1.width.y*/);
362 if (auto b
= PolyBody
.Box(Vec2(VFloatNum
!12, VFloatNum
!(0.5)), VFloat
.max
)) {
363 b
.position
.set(-VFloatNum
!(1.5), VFloatNum
!10);
367 for (int idx
= 0; idx
< 10; ++idx
) {
368 if (auto b
= PolyBody
.Box(Vec2(VFloatNum
!(0.2), VFloatNum
!2), VFloatNum
!100)) {
369 b
.position
.set(-VFloatNum
!6+VFloatNum
!1*idx
, VFloatNum
!(11.125));
370 b
.friction
= VFloatNum
!(0.1);
375 if (auto b
= PolyBody
.Box(Vec2(VFloatNum
!14, VFloatNum
!(0.5)), VFloat
.max
)) {
376 b
.position
.set(VFloatNum
!1, VFloatNum
!6);
377 b
.rotation
= VFloatNum
!(0.3);
381 BodyBase b2
= PolyBody
.Box(Vec2(VFloatNum
!(0.5), VFloatNum
!3), VFloat
.max
);
382 b2
.position
.set(-VFloatNum
!7, VFloatNum
!4);
385 BodyBase b3
= PolyBody
.Box(Vec2(VFloatNum
!12, VFloatNum
!(0.25)), VFloatNum
!20);
386 b3
.position
.set(-VFloatNum
!(0.9), VFloatNum
!1);
389 if (auto j
= new Joint()) {
390 j
.set(b1
, b3
, Vec2(-VFloatNum
!2, VFloatNum
!1));
394 BodyBase b4
= PolyBody
.Box(Vec2(VFloatNum
!(0.5), VFloatNum
!(0.5)), VFloatNum
!10);
395 b4
.position
.set(-VFloatNum
!10, VFloatNum
!15);
398 if (auto j
= new Joint()) {
399 j
.set(b2
, b4
, Vec2(-VFloatNum
!7, VFloatNum
!15));
403 BodyBase b5
= PolyBody
.Box(Vec2(VFloatNum
!2, VFloatNum
!2), VFloatNum
!12);
404 b5
.position
.set(VFloatNum
!6, VFloatNum
!(2.5));
405 b5
.friction
= VFloatNum
!(0.1);
408 if (auto j
= new Joint()) {
409 j
.set(b1
, b5
, Vec2(VFloatNum
!6, VFloatNum
!(2.6)));
414 BodyBase b6
= PolyBody
.Box(Vec2(VFloatNum
!2, VFloatNum
!(0.2)), VFloatNum
!10);
415 b6
.position
.set(VFloatNum
!6, VFloatNum
!(3.6));
418 if (auto j
= new Joint()) {
419 j
.set(b5
, b6
, Vec2(VFloatNum
!7, VFloatNum
!(3.5)));
426 @DemoInfo("Multi-pendulum") void demo9 () {
427 import std
.math
: PI
;
429 BodyBase b1
= PolyBody
.Box(Vec2(BoxW
, BoxH
), VFloat
.max
);
430 b1
.friction
= VFloatNum
!(0.2);
431 b1
.position
.set(VFloatNum
!0, -VFloatNum
!(0.5)*BoxH
/*b1.width.y*/);
432 b1
.rotation
= VFloatNum
!0;
435 VFloat mass
= VFloatNum
!10;
438 VFloat frequencyHz
= VFloatNum
!4;
439 VFloat dampingRatio
= VFloatNum
!(0.7);
441 // frequency in radians
442 VFloat omega
= VFloatNum
!2*PI
*frequencyHz
;
444 // damping coefficient
445 VFloat d
= VFloatNum
!2*mass
*dampingRatio
*omega
;
448 VFloat k
= mass
*omega
*omega
;
451 VFloat softnesss
= VFloatNum
!1/(d
+timeStep
*k
);
452 VFloat biasFactorr
= timeStep
*k
/(d
+timeStep
*k
);
454 const VFloat y
= VFloatNum
!12;
456 for (int idx
= 0; idx
< 15; ++idx
) {
457 Vec2 x
= Vec2(VFloatNum
!(0.5)+idx
, y
);
458 auto b
= PolyBody
.Box(Vec2(VFloatNum
!(0.75), VFloatNum
!(0.25)), mass
);
459 b
.friction
= VFloatNum
!(0.2);
461 b
.rotation
= VFloatNum
!0;
464 if (auto j
= new Joint()) {
465 j
.set(b1
, b
, Vec2(idx
, y
));
466 j
.softness
= softnesss
;
467 j
.biasFactor
= biasFactorr
;
476 // ////////////////////////////////////////////////////////////////////////// //
477 __gshared
bool paused
= false;
478 __gshared
bool doOneStep
= false;
479 __gshared
bool slowmo
= false;
480 __gshared
int slowmocount
= 0;
483 bool setupDemo (int index
, SimpleWindow w
) {
485 alias sms
= getSymbolsByUDA
!(mixin(__MODULE__
), DemoInfo
);
486 foreach (immutable idx
, const memb
; sms
) {
488 w
.title
= getUDAs
!(memb
, DemoInfo
)[0].dsc
;
500 // ////////////////////////////////////////////////////////////////////////// //
502 glMatrixMode(GL_MODELVIEW
);
504 glTranslatef(VFloatNum
!0, -VFloatNum
!7, -VFloatNum
!25);
507 foreach (BodyBase b
; world
.bodies
) b
.drawBody();
508 foreach (Joint j
; world
.joints
) j
.drawJoint();
513 glPointSize(VFloatNum
!4);
514 glColor3f(VFloatNum
!1, VFloatNum
!0, VFloatNum
!0);
516 foreach (const ref cxy
; contacts
) glVertex2f(cxy
.position
.x
, cxy
.position
.y
);
518 glPointSize(VFloatNum
!1);
523 world
.drawBVH((Vec2 min
, Vec2 max
) {
524 glColor3f(VFloatNum
!1, VFloatNum
!1, VFloatNum
!0);
525 glBegin(GL_LINE_LOOP
);
526 glVertex2f(min
.x
, min
.y
);
527 glVertex2f(max
.x
, min
.y
);
528 glVertex2f(max
.x
, max
.y
);
529 glVertex2f(min
.x
, max
.y
);
536 // ////////////////////////////////////////////////////////////////////////// //
537 void simulationStep (SimpleWindow sdwin
) {
538 static double accumulator
= 0;
540 glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT
);
545 snprintf(buf, sizeof(buf), "Demo %d: %s", demoIndex+1, demos[demoIndex].name);
546 DrawText(5, 15, buf);
547 DrawText(5, 45, "Keys: 1-9 Demos, Space to Launch the Bomb");
549 static char buffer[512];
550 sprintf(buffer, "(A)ccumulation %s", (World::accumulateImpulses ? "ON" : "OFF"));
551 DrawText(5, 75, buffer);
553 sprintf(buffer, "(P)osition Correction %s", (World::positionCorrection ? "ON" : "OFF"));
554 DrawText(5, 105, buffer);
556 sprintf(buffer, "(W)arm Starting %s", (World::warmStarting ? "ON" : "OFF"));
557 DrawText(5, 135, buffer);
560 glMatrixMode(GL_MODELVIEW
);
562 glTranslatef(VFloatNum
!0, -VFloatNum
!7, -VFloatNum
!25);
565 contacts
.assumeSafeAppend
;
569 if (optShowTimes
) stt
= MonoTime
.currTime
;
570 world
.step(timeStep
);
572 auto tm
= (MonoTime
.currTime
-stt
).total
!"msecs";
573 { import core
.stdc
.stdio
; printf("step: %d msecs\n", cast(int)tm
); }
575 sdwin
.redrawOpenGlSceneNow();
579 // ////////////////////////////////////////////////////////////////////////// //
582 writeln("simulation options:");
583 writeln(" accumutate impulses: ", World
.accumulateImpulses
);
584 writeln(" position correction: ", World
.positionCorrection
);
585 writeln(" warm starting : ", World
.warmStarting
);
589 // ////////////////////////////////////////////////////////////////////////// //
591 //setOpenGLContextVersion(3, 2); // up to GLSL 150
592 //openGLContextCompatible = false;
594 b2dlDrawContactsCB
= delegate (in ref BodyContact ctx
) {
598 auto sdwin
= new SimpleWindow(GWidth
, GHeight
, "Box2DLite Physics", OpenGlOptions
.yes
, Resizablity
.fixedSize
);
599 //sdwin.hideCursor();
601 //sdwin.closeQuery = delegate () { concmd("quit"); };
603 sdwin
.redrawOpenGlScene
= delegate () {
604 glClear(GL_COLOR_BUFFER_BIT
);
608 sdwin
.visibleForTheFirstTime
= delegate () {
611 sdwin
.setAsCurrentOpenGlContext(); // make this window active
614 glMatrixMode(GL_PROJECTION);
616 glOrtho(0, GWidth, GHeight, 0, -1, 1);
617 glMatrixMode(GL_MODELVIEW);
620 glViewport(0, 0, GWidth
, GHeight
);
621 glMatrixMode(GL_PROJECTION
);
623 oglPerspective(45.0, cast(VFloat
)GWidth
/cast(VFloat
)GHeight
, 0.1, 100.0);
624 sdwin
.redrawOpenGlScene();
627 sdwin
.eventLoop(1000/60,
629 if (sdwin
.closed || world
is null) return;
633 if (--slowmocount
< 0) {
634 simulationStep(sdwin
);
638 simulationStep(sdwin
);
641 } else if (doOneStep
) {
643 simulationStep(sdwin
);
646 delegate (KeyEvent event
) {
647 if (sdwin
.closed
) return;
648 if (!event
.pressed
) return;
650 case Key
.Escape
: sdwin
.close(); break;
654 delegate (MouseEvent event
) {
656 delegate (dchar ch
) {
657 if (ch
== 'q') { sdwin
.close(); return; }
658 if (ch
== 'r') { setupDemo(demoIndex
, sdwin
); return; }
659 if (ch
== ' ') { paused
= !paused
; return; }
660 if (ch
== 's') { slowmo
= !slowmo
; return; }
661 if (ch
>= '1' && ch
<= '9') { setupDemo(ch
-'1', sdwin
); return; }
662 if (ch
== '0') { setupDemo(10, sdwin
); return; }
663 if (ch
== 'a') { World
.accumulateImpulses
= !World
.accumulateImpulses
; showOpts(); return; }
664 if (ch
== 'p') { World
.positionCorrection
= !World
.positionCorrection
; showOpts(); return; }
665 if (ch
== 'w') { World
.warmStarting
= !World
.warmStarting
; showOpts(); return; }
666 if (ch
== '\n' || ch
== '\r') { launchBomb(sdwin
); return; }
667 if (ch
== '+') { setupDemo(demoIndex
+1, sdwin
); return; }
668 if (ch
== '-') { if (demoIndex
> 0) setupDemo(demoIndex
-1, sdwin
); return; }
669 if (ch
== 'z') { doOneStep
= true; return; }
670 if (ch
== 'T') { optShowTimes
= !optShowTimes
; return; }
671 if (ch
== 'A') { optDrawBVH
= !optDrawBVH
; return; }