1 module game;
2
3 import std.stdio;
4 import std.format;
5
6 import dlib.core.memory;
7 import dlib.container.array;
8 import dlib.math.vector;
9 import dlib.math.matrix;
10 import dlib.math.transformation;
11 import dlib.image.color;
12
13 import derelict.opengl.gl;
14 import derelict.opengl.glu;
15 import derelict.sdl.sdl;
16 import dgl.core.application;
17 import dgl.core.interfaces;
18 import dgl.core.event;
19 import dgl.graphics.shapes;
20 import dgl.graphics.material;
21 import dgl.ui.font;
22 import dgl.ui.ftfont;
23 import dgl.ui.textline;
24
25 import dmech.world;
26 import dmech.geometry;
27 import dmech.rigidbody;
28 import dmech.shape;
29
30 import testbed.grid;
31 import testbed.physicsentity;
32 import testbed.fpcamera;
33 import testbed.character;
34
35 class TestApp: Application
36 {
37 FirstPersonCamera camera;
38 CharacterController charController;
39
40 DynamicArray!Drawable drawables;
41 Vector4f lightPosition;
42
43 Grid grid;
44 ShapeBox sBox;
45
46 Material boxMaterial;
47
48 PhysicsWorld world;
49 GeomBox gFloor;
50 GeomBox gBox;
51 GeomSphere gSphere;
52
53 RigidBody bFloor;
54
55 enum fixedTimeStep = 1.0 / 60.0;
56
57 Font font;
58 TextLine fpsText;
59 TextLine ctrlText;
60
61 bool mouseControl = true;
62
63 this()
64 {
65 super(800, 600, "dmech game demo");
66
67 clearColor = Color4f(0.5f, 0.5f, 0.5f);
68 lightPosition = Vector4f(5, 10, 2, 1);
69
70 grid = New!Grid();
71
72 world = New!PhysicsWorld(null, 1000);
73
74 gFloor = New!GeomBox(world, Vector3f(40, 1, 40));
75 bFloor = world.addStaticBody(Vector3f(0, -1, 0));
76 world.addShapeComponent(bFloor, gFloor, Vector3f(0, 0, 0), 1.0f);
77
78 Vector3f boxHalfSize = Vector3f(0.75f, 0.75f, 0.75f);
79 gBox = New!GeomBox(world, boxHalfSize); // Physical shape
80 sBox = New!ShapeBox(boxHalfSize); // Graphical shape
81
82 Vector3f characterPos = Vector3f(0, 5, 5);
83 camera = New!FirstPersonCamera(characterPos);
84 camera.turn = -90.0f;
85
86 gSphere = New!GeomSphere(world, 1.0f);
87 charController = New!CharacterController(world, characterPos, 1.0f, gSphere);
88
89 boxMaterial = New!Material();
90 boxMaterial.ambientColor = Color4f(0.75f, 0.3f, 0);
91 boxMaterial.diffuseColor = Color4f(1, 0.5f, 0);
92
93 foreach(i; 0..10)
94 addBoxEntity(Vector3f(-10 + i, 2 + i * 2.1, 0), boxMaterial);
95
96 font = New!FreeTypeFont("data/fonts/droid/DroidSans.ttf", 12);
97
98 fpsText = New!TextLine(font, "FPS: 0", Vector2f(8, 8));
99 fpsText.color = Color4f(1, 1, 1);
100
101 ctrlText = New!TextLine(font,
102 "Mouse/WASD - move; Space - jump; Enter - release mouse pointer; Esc - exit",
103 Vector2f(8, eventManager.windowHeight - font.height - 8));
104 ctrlText.color = Color4f(1, 1, 1);
105
106 eventManager.showCursor(false);
107 }
108
109 ~this()
110 {
111 camera.free();
112 charController.free();
113 foreach(d; drawables.data)
114 d.free();
115 drawables.free();
116 grid.free();
117 Delete(world);
118 sBox.free();
119 font.free();
120 fpsText.free();
121 ctrlText.free();
122 boxMaterial.free();
123 }
124
125 PhysicsEntity addBoxEntity(Vector3f pos, Material m)
126 {
127 auto bBox = world.addDynamicBody(pos, 0.0f);
128 auto scBox = world.addShapeComponent(bBox, gBox, Vector3f(0, 0, 0), 10.0f);
129 PhysicsEntity peBox = New!PhysicsEntity(sBox, bBox);
130 peBox.material = m;
131 addDrawable(peBox);
132 return peBox;
133 }
134
135 void addDrawable(Drawable d)
136 {
137 drawables.append(d);
138 }
139
140 void updateCamera()
141 {
142 int hWidth = eventManager.windowWidth / 2;
143 int hHeight = eventManager.windowHeight / 2;
144 float turn_m = -(hWidth - eventManager.mouseX) * 0.1f;
145 float pitch_m = (hHeight - eventManager.mouseY) * 0.1f;
146 camera.pitch += pitch_m;
147 camera.turn += turn_m;
148 float pitchLimitMax = 60.0f;
149 float pitchLimitMin = -60.0f;
150 if (camera.pitch > pitchLimitMax)
151 camera.pitch = pitchLimitMax;
152 else if (camera.pitch < pitchLimitMin)
153 camera.pitch = pitchLimitMin;
154
155 eventManager.setMouseToCenter();
156 }
157
158 void updateCharacter()
159 {
160 Vector3f forward = camera.characterMatrix.forward;
161 Vector3f right = camera.characterMatrix.right;
162
163 if (eventManager.keyPressed['w']) charController.move(forward, -12.0f);
164 if (eventManager.keyPressed['s']) charController.move(forward, 12.0f);
165 if (eventManager.keyPressed['a']) charController.move(right, -12.0f);
166 if (eventManager.keyPressed['d']) charController.move(right, 12.0f);
167 if (eventManager.keyPressed[SDLK_SPACE]) charController.jump(1.0f);
168
169 charController.update();
170 }
171
172 override void onKeyDown(int key)
173 {
174 super.onKeyDown(key);
175
176 if (key == SDLK_RETURN)
177 {
178 mouseControl = !mouseControl;
179 eventManager.showCursor(!mouseControl);
180 eventManager.setMouseToCenter();
181 }
182 }
183
184 override void onMouseButtonDown(int button)
185 {
186 }
187
188 override void free()
189 {
190 Delete(this);
191 }
192
193 double time = 0.0;
194
195 override void onUpdate()
196 {
197 double dt = eventManager.deltaTime;
198
199 if (mouseControl)
200 {
201 updateCamera();
202 }
203
204 time += dt;
205 if (time >= fixedTimeStep)
206 {
207 time -= fixedTimeStep;
208 updateCharacter();
209 world.update(fixedTimeStep);
210 }
211
212 camera.position = charController.rbody.position;
213
214 fpsText.setText(format("FPS: %s", eventManager.fps));
215 }
216
217 override void onRedraw()
218 {
219 double dt = eventManager.deltaTime;
220
221 float aspectRatio = cast(float)eventManager.windowWidth / cast(float)eventManager.windowHeight;
222
223 glMatrixMode(GL_PROJECTION);
224 glLoadIdentity();
225 gluPerspective(60.0f, aspectRatio, 0.1, 1000.0);
226 glMatrixMode(GL_MODELVIEW);
227
228 glLoadIdentity();
229 glPushMatrix();
230 camera.bind(dt);
231
232 grid.draw(dt);
233
234 glEnable(GL_LIGHTING);
235 glEnable(GL_LIGHT0);
236 glLightfv(GL_LIGHT0, GL_POSITION, lightPosition.arrayof.ptr);
237
238 foreach(d; drawables.data)
239 d.draw(dt);
240
241 glDisable(GL_LIGHTING);
242
243 camera.unbind();
244 glPopMatrix();
245
246 glMatrixMode(GL_PROJECTION);
247 glLoadIdentity();
248 glOrtho(0, eventManager.windowWidth, 0, eventManager.windowHeight, 0, 1);
249 glMatrixMode(GL_MODELVIEW);
250
251 fpsText.draw(dt);
252 ctrlText.draw(dt);
253 }
254
255 override void onResize(int width, int height)
256 {
257 super.onResize(width, height);
258 ctrlText.setPosition(8, height - font.height - 8);
259 }
260 }
261
262 void main(string[] args)
263 {
264 loadLibraries();
265 writefln("Allocated memory at start: %s", allocatedMemory);
266 auto app = New!TestApp();
267 app.run();
268 Delete(app);
269 writefln("Allocated memory at end: %s", allocatedMemory);
270 }