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 }