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.affine;
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(1000);
73         
74         gFloor = New!GeomBox(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(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(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         world.free();
118         sBox.free();
119         gFloor.free();
120         gBox.free();
121         gSphere.free();
122         font.free();
123         fpsText.free();
124         ctrlText.free();
125         boxMaterial.free();
126     }
127     
128     PhysicsEntity addBoxEntity(Vector3f pos, Material m)
129     {
130         auto bBox = world.addDynamicBody(pos, 0.0f);
131         auto scBox = world.addShapeComponent(bBox, gBox, Vector3f(0, 0, 0), 10.0f);
132         PhysicsEntity peBox = New!PhysicsEntity(sBox, bBox);
133         peBox.material = m;
134         addDrawable(peBox);
135         return peBox;
136     }
137     
138     void addDrawable(Drawable d)
139     {
140         drawables.append(d);
141     }
142 
143     void updateCamera()
144     {    
145         int hWidth = eventManager.windowWidth / 2;
146         int hHeight = eventManager.windowHeight / 2;
147         float turn_m = -(hWidth - eventManager.mouseX) * 0.1f;
148         float pitch_m = (hHeight - eventManager.mouseY) * 0.1f;
149         camera.pitch += pitch_m;
150         camera.turn += turn_m;       
151         float pitchLimitMax = 60.0f;
152         float pitchLimitMin = -60.0f;
153         if (camera.pitch > pitchLimitMax)
154             camera.pitch = pitchLimitMax;
155         else if (camera.pitch < pitchLimitMin)
156             camera.pitch = pitchLimitMin;
157         
158         eventManager.setMouseToCenter();
159     }
160     
161     void updateCharacter()
162     {        
163         Vector3f forward = camera.characterMatrix.forward;
164         Vector3f right = camera.characterMatrix.right;
165         
166         if (eventManager.keyPressed['w']) charController.move(forward, -12.0f);
167         if (eventManager.keyPressed['s']) charController.move(forward, 12.0f);
168         if (eventManager.keyPressed['a']) charController.move(right, -12.0f);
169         if (eventManager.keyPressed['d']) charController.move(right, 12.0f);
170         if (eventManager.keyPressed[SDLK_SPACE]) charController.jump(1.0f);
171         
172         charController.update();
173     }
174     
175     override void onKeyDown(int key)
176     {
177         super.onKeyDown(key);
178         
179         if (key == SDLK_RETURN)
180         {
181             mouseControl = !mouseControl;
182             eventManager.showCursor(!mouseControl);
183             eventManager.setMouseToCenter();
184         }
185     }
186     
187     override void onMouseButtonDown(int button)
188     {
189     }
190     
191     override void free()
192     {
193         Delete(this);
194     }
195     
196     double time = 0.0;
197     
198     override void onUpdate()
199     {
200         double dt = eventManager.deltaTime;
201         
202         if (mouseControl)
203         {
204             updateCamera();
205         }
206         
207         time += dt;
208         if (time >= fixedTimeStep)
209         {
210             time -= fixedTimeStep;
211             updateCharacter();
212             world.update(fixedTimeStep);
213         }
214     
215         camera.position = charController.rbody.position;
216         
217         fpsText.setText(format("FPS: %s", eventManager.fps));
218     }
219     
220     override void onRedraw()
221     {       
222         double dt = eventManager.deltaTime;
223         
224         float aspectRatio = cast(float)eventManager.windowWidth / cast(float)eventManager.windowHeight;
225         
226         glMatrixMode(GL_PROJECTION);
227         glLoadIdentity();
228         gluPerspective(60.0f, aspectRatio, 0.1, 1000.0);
229         glMatrixMode(GL_MODELVIEW);
230         
231         glLoadIdentity();
232         glPushMatrix();
233         camera.bind(dt);
234         
235         grid.draw(dt);
236         
237         glEnable(GL_LIGHTING);
238         glEnable(GL_LIGHT0);
239         glLightfv(GL_LIGHT0, GL_POSITION, lightPosition.arrayof.ptr);
240         
241         foreach(d; drawables.data)
242             d.draw(dt);
243             
244         glDisable(GL_LIGHTING);
245         
246         camera.unbind();
247         glPopMatrix();
248         
249         glMatrixMode(GL_PROJECTION);
250         glLoadIdentity();
251         glOrtho(0, eventManager.windowWidth, 0, eventManager.windowHeight, 0, 1);
252         glMatrixMode(GL_MODELVIEW);
253         
254         fpsText.draw(dt);
255         ctrlText.draw(dt);
256     }
257     
258     override void onResize(int width, int height)
259     {
260         super.onResize(width, height);
261         ctrlText.setPosition(8, height - font.height - 8);
262     }
263 }
264 
265 void main(string[] args)
266 {
267     loadLibraries();
268     writefln("Allocated memory at start: %s", allocatedMemory);
269     auto app = New!TestApp();
270     app.run();
271     Delete(app);
272     writefln("Allocated memory at end: %s", allocatedMemory);
273 }