initial commit
[b2ld.git] / main.d
blobd78f6a837ac2b9a8472dfaae026b73b7d2baf4cf
1 module main is aliced;
3 import iv.glbinds;
4 import arsd.color;
5 import arsd.png;
7 import b2dlite;
10 // Replaces gluPerspective. Sets the frustum to perspective mode.
11 // fovY - Field of vision in degrees in the y direction
12 // aspect - Aspect ratio of the viewport
13 // zNear - The near clipping distance
14 // zFar - The far clipping distance
15 void perspectiveGL (GLdouble fovY, GLdouble aspect, GLdouble zNear, GLdouble zFar) {
16 import std.math : tan;
17 //Very long (& in theory accurate!) version of Pi. Hopefully an optimizing compiler will replace references to this with the value!
18 enum GLdouble pi = 3.1415926535897932384626433832795;
19 GLdouble fW, fH; // Half of the size of the x and y clipping planes.
20 // Calculate the distance from 0 of the y clipping plane. Basically trig to calculate position of clipper at zNear.
21 // Note: tan( double ) uses radians but OpenGL works in degrees so we convert degrees to radians by dividing by 360 then multiplying by pi.
22 // Formula below corrected by Carsten Jurenz:
23 //fH = tan( (fovY / 2) / 180 * pi ) * zNear;
24 // Which can be reduced to:
25 fH = tan( fovY / 360 * pi ) * zNear;
26 // Calculate the distance from 0 of the x clipping plane based on the aspect ratio.
27 fW = fH * aspect;
28 // Finally call glFrustum, this is all gluPerspective does anyway! This is why we calculate half the distance between the clipping planes
29 // glFrustum takes an offset from zero for each clipping planes distance. (Saves 2 divides)
30 glFrustum( -fW, fW, -fH, fH, zNear, zFar );
34 enum GWidth = 800;
35 enum GHeight = 600;
38 //Body[200] bodies;
39 //Joint[100] joints;
41 Body bomb = null;
43 float timeStep = 1.0f/60.0f;
44 int iterations = 10;
45 Vec2 gravity = Vec2(0.0f, -10.0f);
47 int numBodies = 0;
48 int numJoints = 0;
50 int demoIndex = 0;
52 bool frameStepping = false;
53 bool canStep = false;
55 World world;
56 static this () { world = new World(gravity, iterations); }
59 static void DrawBody (Body body) {
60 auto R = Mat22(body.rotation);
61 Vec2 x = body.position;
62 Vec2 h = 0.5f*body.width;
64 Vec2 v1 = x+R*Vec2(-h.x, -h.y);
65 Vec2 v2 = x+R*Vec2( h.x, -h.y);
66 Vec2 v3 = x+R*Vec2( h.x, h.y);
67 Vec2 v4 = x+R*Vec2(-h.x, h.y);
69 if (body is bomb) {
70 glColor3f(0.4f, 0.9f, 0.4f);
71 } else {
72 glColor3f(0.8f, 0.8f, 0.9f);
75 glBegin(GL_LINE_LOOP);
76 glVertex2f(v1.x, v1.y);
77 glVertex2f(v2.x, v2.y);
78 glVertex2f(v3.x, v3.y);
79 glVertex2f(v4.x, v4.y);
80 glEnd();
84 static void DrawJoint (Joint joint) {
85 Body b1 = joint.body1;
86 Body b2 = joint.body2;
88 auto R1 = Mat22(b1.rotation);
89 auto R2 = Mat22(b2.rotation);
91 Vec2 x1 = b1.position;
92 Vec2 p1 = x1+R1*joint.localAnchor1;
94 Vec2 x2 = b2.position;
95 Vec2 p2 = x2+R2*joint.localAnchor2;
97 glColor3f(0.5f, 0.5f, 0.8f);
98 glBegin(GL_LINES);
99 glVertex2f(x1.x, x1.y);
100 glVertex2f(p1.x, p1.y);
101 glVertex2f(x2.x, x2.y);
102 glVertex2f(p2.x, p2.y);
103 glEnd();
107 // single box
108 void Demo1 (/*Body b, Joint j*/) {
109 with (auto b = new Body()) {
110 b.Set(Vec2(100.0f, 20.0f), float.max);
111 b.position.Set(0.0f, -0.5f*b.width.y);
112 world.Add(b);
114 //++b;
115 //++numBodies;
117 with (auto b = new Body()) {
118 b.Set(Vec2(1.0f, 1.0f), 200.0f);
119 b.position.Set(0.0f, 4.0f);
120 world.Add(b);
122 //++b;
123 //++numBodies;
127 __gshared bool paused = false;
128 __gshared bool slowmo = false;
129 __gshared int slowmocount = 0;
132 void InitDemo (int index) {
133 world.Clear();
134 numBodies = 0;
135 numJoints = 0;
136 bomb = null;
137 //demoIndex = index;
138 //demos[index].init(bodies, joints);
142 void SimulationLoop () {
143 //static uint64_t t_start = 0;
144 static double accumulator = 0;
145 //uint64_t t_cur;
146 char[128] buf;
148 glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
151 snprintf(buf, sizeof(buf), "Demo %d: %s", demoIndex+1, demos[demoIndex].name);
152 DrawText(5, 15, buf);
153 DrawText(5, 45, "Keys: 1-9 Demos, Space to Launch the Bomb");
155 static char buffer[512];
156 sprintf(buffer, "(A)ccumulation %s", (World::accumulateImpulses ? "ON" : "OFF"));
157 DrawText(5, 75, buffer);
159 sprintf(buffer, "(P)osition Correction %s", (World::positionCorrection ? "ON" : "OFF"));
160 DrawText(5, 105, buffer);
162 sprintf(buffer, "(W)arm Starting %s", (World::warmStarting ? "ON" : "OFF"));
163 DrawText(5, 135, buffer);
166 glMatrixMode(GL_MODELVIEW);
167 glLoadIdentity();
168 glTranslatef(0.0f, -7.0f, -25.0f);
171 t_cur = k8clock_msec(NULL);
172 if (t_start == 0) t_start = t_cur;
174 //world.Step(timeStep);
175 accumulator += (t_cur-t_start)/1000.0;
176 t_start = t_cur;
177 // clamp
178 if (accumulator < 0.0) accumulator = 0.0;
179 else if (accumulator > 0.1) accumulator = 0.1;
180 // process physics
181 while (accumulator >= timeStep) {
182 if (!frameStepping) {
183 world.Step(timeStep);
184 } else {
185 if (canStep) {
186 world.Step(timeStep);
187 canStep = false;
190 accumulator -= timeStep;
197 void drawWorld () {
198 glMatrixMode(GL_MODELVIEW);
199 glLoadIdentity();
200 glTranslatef(0.0f, -7.0f, -25.0f);
202 // draw world
203 foreach (Body b; world.bodies) b.DrawBody();
204 foreach (Joint j; world.joints) j.DrawJoint();
208 void main () {
209 //setOpenGLContextVersion(3, 2); // up to GLSL 150
210 //openGLContextCompatible = false;
212 auto sdwindow = new SimpleWindow(GWidth, GHeight, "Verlet Physics", OpenGlOptions.yes, Resizablity.fixedSize);
213 //sdwindow.hideCursor();
215 //sdwindow.closeQuery = delegate () { concmd("quit"); };
217 sdwindow.redrawOpenGlScene = delegate () {
218 glClear(GL_COLOR_BUFFER_BIT);
219 drawWorld();
221 world.render();
222 if (dragVertex !is null) {
223 glPointSize(6.0f);
224 glColor3f(1.0f, 1.0f, 0.0f);
225 glBegin(GL_POINTS);
226 glVertex2f(dragVertex.position.x, dragVertex.position.y);
227 glEnd();
230 //glFlush();
233 sdwindow.visibleForTheFirstTime = delegate () {
234 InitDemo(0);
235 Demo1();
236 sdwindow.setAsCurrentOpenGlContext(); // make this window active
237 glbindLoadFunctions();
238 // init matrices
240 glMatrixMode(GL_PROJECTION);
241 glLoadIdentity();
242 glOrtho(0, GWidth, GHeight, 0, -1, 1);
243 glMatrixMode(GL_MODELVIEW);
244 glLoadIdentity();
246 glViewport(0, 0, GWidth, GHeight);
247 glMatrixMode(GL_PROJECTION);
248 glLoadIdentity();
249 perspectiveGL(45.0, cast(float)GWidth/cast(float)GHeight, 0.1, 100.0);
250 sdwindow.redrawOpenGlScene();
253 sdwindow.eventLoop(cast(int)(1000.0f/60.0f),
254 delegate () {
255 if (sdwindow.closed || world is null) return;
256 if (!paused) {
257 if (slowmo) {
258 if (--slowmocount < 0) {
259 SimulationLoop();
260 slowmocount = 10;
262 } else {
263 SimulationLoop();
264 slowmocount = 0;
267 sdwindow.redrawOpenGlSceneNow();
269 delegate (KeyEvent event) {
270 if (sdwindow.closed) return;
271 if (!event.pressed) return;
272 switch (event.key) {
273 case Key.Escape: sdwindow.close(); break;
274 default:
277 delegate (MouseEvent event) {
279 if (event.type == MouseEventType.buttonPressed) {
280 if (event.button == MouseButton.left) dragVertex = world.FindVertex(event.x, event.y);
281 if (event.button == MouseButton.right) dragVertex = null;
282 } else if (event.type == MouseEventType.buttonReleased) {
283 if (event.button == MouseButton.left) dragVertex = null;
285 if (dragVertex !is null) dragVertex.position = vec2(cast(float)event.x, cast(float)event.y); // sets the position of the dragVertex to the mouse position to drag it around
288 delegate (dchar ch) {
289 if (ch == 'q') { sdwindow.close(); return; }
290 //if (ch == 'r') { initPhysics(); return; }
291 if (ch == ' ') { paused = !paused; return; }
292 if (ch == 's') { slowmo = !slowmo; return; }