1 module gamelayer;
2 
3 import std.stdio;
4 
5 import derelict.sdl.sdl;
6 import derelict.opengl.gl;
7 
8 import dlib.math.vector;
9 import dlib.math.matrix;
10 import dlib.math.affine;
11 import dlib.geometry.triangle;
12 import dlib.image.color;
13 
14 import dgl.core.layer;
15 import dgl.core.event;
16 import dgl.core.drawable;
17 import dgl.graphics.material;
18 import dgl.graphics.shapes;
19 import dgl.graphics.lamp;
20 import dgl.scene.tbcamera;
21 import dgl.vfs.vfs;
22 import dgl.asset.dgl;
23 import dgl.scene.scene;
24 
25 import dmech.world;
26 import dmech.rigidbody;
27 import dmech.geometry;
28 import dmech.shape;
29 import dmech.bvh;
30 import dmech.contact;
31 
32 import cc;
33 import gameobj;
34 import tpcamera;
35 
36 // TODO: This function is total hack,
37 // need to rewrite BVH module to handle Triangle ranges,
38 // and add a method to Scene that will lazily return 
39 // transformed triangles for entities.
40 BVHTree!Triangle sceneBVH(Scene scene)
41 {
42     Triangle[] tris;
43     foreach(entity; scene.entities)
44     {
45         if (entity.type == 0)
46         if (entity.meshId > -1)
47         {
48             Matrix4x4f mat = Matrix4x4f.identity;
49             mat *= translationMatrix(entity.position);
50             mat *= entity.rotation.toMatrix4x4;
51             mat *= scaleMatrix(entity.scaling);
52 
53             auto mesh = scene.mesh(entity.meshId);
54             foreach(fgroup; mesh.fgroups)
55             foreach(tri; fgroup.tris)
56             {
57                 Triangle tri2 = tri;
58                 tri2.v[0] = tri.v[0] * mat;
59                 tri2.v[1] = tri.v[1] * mat;
60                 tri2.v[2] = tri.v[2] * mat;
61                 tri2.normal = entity.rotation.rotate(tri.normal);
62                 tri2.barycenter = (tri2.v[0] + tri2.v[1] + tri2.v[2]) / 3;
63 
64                 tris ~= tri2;
65             }
66         }
67     }
68     return new BVHTree!Triangle(tris, 4);
69 }
70 
71 class GameLayer: Layer
72 {
73     EventManager emanager;
74     VirtualFileSystem vfs;
75 
76     PhysicsWorld world;
77     RigidBody activeBody;
78 
79     enum double fixedDelta = 1.0 / 60.0;
80 
81     Scene scene;
82     BVHTree!Triangle bvh;
83 
84     GameObject poRobot;
85     CharacterController ccRobot;
86     TrackballCamera camera;
87     ThirdPersonCamera tpcamera;
88 
89     this(uint w, uint h, int depth, EventManager emanager)
90     {
91         super(0, 0, w, h, LayerType.Layer3D, depth);
92         alignToWindow = true;
93 
94         this.emanager = emanager;
95 
96         // Create VFS
97         vfs = new VirtualFileSystem();
98         vfs.mount("data/testlevel");
99 
100         // Create pysics world
101         world = new PhysicsWorld(10000);
102 
103         // Create floor object
104         auto geomFloorBox = new GeomBox(Vector3f(100, 1, 100));
105         RigidBody bFloor = world.addStaticBody(Vector3f(0, -2, 0));
106         world.addShapeComponent(bFloor, geomFloorBox, Vector3f(0, 0, 0), 1);
107         
108         buildPyramid(Vector3f(5, 0, 0), 4, 0);
109 
110         // Create robot object
111         Vector3f initPosition = Vector3f(4.0f, 6.0f, 0.0f);
112         ccRobot = new CharacterController(world, initPosition, 1.0f);
113         poRobot = new GameObject();
114         poRobot.drawable = new ShapeSphere(1.0f);
115         poRobot.shape = ccRobot.rbody.shapes[0];
116         addDrawable(poRobot);
117 
118         auto geomPlatform = new GeomBox(Vector3f(1, 1, 1));
119         auto platformBody = world.addDynamicBody(Vector3f(-5, 5, 0));
120         platformBody.bounce = 0.8f;
121         world.addShapeComponent(platformBody, geomPlatform, Vector3f(0, 0, 0), 1.0f);
122         auto platformObj = new GameObject();
123         platformObj.drawable = new ShapeBox(Vector3f(1, 1, 1));
124         platformObj.shape = platformBody.shapes[0];
125         addDrawable(platformObj);
126 
127         // Create lamp
128         Lamp lamp = new Lamp(Vector4f(10.0f, 20.0f, 5.0f, 1.0f));
129         addDrawable(lamp);
130 
131         // Create camera
132         tpcamera = new ThirdPersonCamera();
133         addModifier(tpcamera);
134 
135         // Create scene
136         auto istrm = vfs.openForInput("testlevel.dgl");
137         scene = loadScene(istrm, vfs);
138         addDrawable(scene);
139         bvh = sceneBVH(scene);
140         world.bvhRoot = bvh.root;
141     }
142 
143     double time = 0.0;
144     override void onUpdate(EventManager emngr)
145     {
146         time += emngr.deltaTime;
147         if (time >= fixedDelta)
148         {
149             time -= fixedDelta;
150 
151             if (emngr.key_pressed[SDLK_DOWN]) ccRobot.move(-10.0f);
152             if (emngr.key_pressed[SDLK_UP]) ccRobot.move(10.0f);
153             if (emngr.key_pressed[SDLK_LEFT]) ccRobot.turn(-5.0f);
154             if (emngr.key_pressed[SDLK_RIGHT]) ccRobot.turn(5.0f);
155             if (emngr.key_pressed[SDLK_SPACE]) ccRobot.jump(3.0f);
156         
157             ccRobot.update();
158 
159             world.update(fixedDelta);
160         }
161             
162         ccRobot.updateMatrix();
163         poRobot.localTransformation = ccRobot.localMatrix;
164         tpcamera.playerDirection = ccRobot.direction;
165         tpcamera.playerPosition = ccRobot.rbody.position;
166     }
167     
168     void buildPyramid(Vector3f pyramidPosition, uint pyramidSize, uint pyramidGeom = 0)
169     {
170         float size = 1.0f;
171 
172         float cubeHeight = 2.0f;
173 
174         auto box = new ShapeBox(Vector3f(size, cubeHeight * 0.5f, size));
175         auto cyl = new ShapeCylinder(2.0f, 1.0f);
176         auto con = new ShapeCone(2.0f, 1.0f);
177         auto sph = new ShapeSphere(1.0f);
178 
179         float width = size * 2.0f;
180         float height = cubeHeight;
181         float horizontal_spacing = 0.1f;
182         float veritcal_spacing = 0.1f;
183 
184         auto geomBox = new GeomBox(Vector3f(size, cubeHeight * 0.5f, size));
185         auto geomCylinder = new GeomCylinder(2.0f, 1.0f); 
186         auto geomSphere = new GeomSphere(size); 
187         auto geomCone = new GeomCone(2.0f, 1.0f); 
188 
189         foreach(i; 0..pyramidSize)
190         foreach(e; i..pyramidSize)
191         {
192             auto position = pyramidPosition + Vector3f(
193                 (e - i * 0.5f) * (width + horizontal_spacing) - ((width + horizontal_spacing) * 5), 
194                 6.0f + (height + veritcal_spacing * 0.5f) + i * height + 0.26f,
195                 -3);
196 
197             Geometry g;
198             Drawable gobj;
199 
200             switch(pyramidGeom)
201             {
202                 case 0:
203                     g = geomBox;
204                     gobj = box;
205                     break;
206                 case 1:
207                     g = geomCylinder;
208                     gobj = cyl;
209                     break;
210                 case 2:
211                     g = geomSphere; 
212                     gobj = sph;
213                     break;
214                 case 4:
215                     g = geomCone;
216                     gobj = con;
217                     break;
218                 default:
219                     assert(0);
220             }
221 
222             auto b = world.addDynamicBody(position, 0);
223             world.addShapeComponent(b, g, Vector3f(0, 0, 0), 1);
224 
225             auto gameObj = new GameObject();
226             gameObj.drawable = gobj; 
227             gameObj.shape = b.shapes[0];
228 
229             Material mat = new Material();
230             auto col = Color4f((randomUnitVector3!float + 0.5f).normalized);
231             mat.ambientColor = col;
232             mat.diffuseColor = col;
233             gameObj.material = mat;
234 
235             addDrawable(gameObj);
236         }
237     }
238 }