source: trunk/src/scene.cpp @ 2500

Last change on this file since 2500 was 2500, checked in by sam, 7 years ago

debug: add Debug::DrawLine() and Debug::DrawBox() methods.

  • Property svn:keywords set to Id
File size: 9.6 KB
Line 
1//
2// Lol Engine
3//
4// Copyright: (c) 2010-2013 Sam Hocevar <sam@hocevar.net>
5//   This program is free software; you can redistribute it and/or
6//   modify it under the terms of the Do What The Fuck You Want To
7//   Public License, Version 2, as published by Sam Hocevar. See
8//   http://www.wtfpl.net/ for more details.
9//
10
11#if defined HAVE_CONFIG_H
12#   include "config.h"
13#endif
14
15#include <cstdlib>
16
17#ifdef WIN32
18#   define WIN32_LEAN_AND_MEAN
19#   include <windows.h>
20#endif
21
22#include "core.h"
23#include "lolgl.h"
24
25LOLFX_RESOURCE_DECLARE(tile);
26LOLFX_RESOURCE_DECLARE(line);
27
28namespace lol
29{
30
31struct Tile
32{
33    TileSet *tileset;
34    uint32_t prio;
35    vec3 pos;
36    vec2 scale;
37    int id, o;
38};
39
40/*
41 * Scene implementation class
42 */
43
44class SceneData
45{
46    friend class Scene;
47
48private:
49    static int Compare(void const *p1, void const *p2)
50    {
51        Tile const *t1 = (Tile const *)p1;
52        Tile const *t2 = (Tile const *)p2;
53
54        if (t1->pos.z > t2->pos.z)
55            return 1;
56        if (t1->pos.z < t2->pos.z)
57            return -1;
58        return 0;
59    }
60
61    Array<vec3, vec3, vec4> m_lines;
62    Shader *m_line_shader;
63    VertexDeclaration *m_line_vdecl;
64
65    Array<Tile> m_tiles;
66    Array<Light *> m_lights;
67
68    Shader *m_tile_shader;
69    VertexDeclaration *m_tile_vdecl;
70    Array<VertexBuffer *> m_tile_bufs;
71
72    Camera *m_default_cam;
73    Array<Camera *> m_camera_stack;
74
75    static Scene *scene;
76};
77
78Scene *SceneData::scene = NULL;
79
80/*
81 * Public Scene class
82 */
83
84Scene::Scene()
85  : data(new SceneData())
86{
87    /* Create a default orthographic camera, in case the user doesn’t. */
88    data->m_default_cam = new Camera();
89    mat4 proj = mat4::ortho(0, Video::GetSize().x, 0, Video::GetSize().y,
90                            -1000.f, 1000.f);
91    data->m_default_cam->SetProjection(proj);
92    PushCamera(data->m_default_cam);
93
94    data->m_tile_shader = 0;
95    data->m_tile_vdecl = new VertexDeclaration(VertexStream<vec3>(VertexUsage::Position),
96                                               VertexStream<vec2>(VertexUsage::TexCoord));
97
98    data->m_line_shader = 0;
99    data->m_line_vdecl = new VertexDeclaration(VertexStream<vec3,vec4>(VertexUsage::Position, VertexUsage::Color));
100}
101
102Scene::~Scene()
103{
104    PopCamera(data->m_default_cam);
105
106    /* FIXME: this must be done while the GL context is still active.
107     * Change the code architecture to make sure of that. */
108    /* FIXME: also, make sure we do not add code to Reset() that will
109     * reallocate stuff */
110    Reset();
111
112    delete data->m_line_vdecl;
113    delete data->m_tile_vdecl;
114    delete data;
115}
116
117Scene *Scene::GetDefault()
118{
119    if (!SceneData::scene)
120        SceneData::scene = new Scene();
121    return SceneData::scene;
122}
123
124void Scene::PushCamera(Camera *cam)
125{
126    Ticker::Ref(cam);
127    data->m_camera_stack.Push(cam);
128}
129
130void Scene::PopCamera(Camera *cam)
131{
132    /* Parse from the end because that’s probably where we’ll find
133     * our camera first. */
134    for (int i = data->m_camera_stack.Count(); i--; )
135    {
136        if (data->m_camera_stack[i] == cam)
137        {
138            Ticker::Unref(cam);
139            data->m_camera_stack.Remove(i);
140            return;
141        }
142    }
143
144    ASSERT(false, "trying to pop a nonexistent camera from the scene");
145}
146
147Camera *Scene::GetCamera()
148{
149    return data->m_camera_stack.Last();
150}
151
152void Scene::Reset()
153{
154    for (int i = 0; i < data->m_tile_bufs.Count(); i++)
155        delete data->m_tile_bufs[i];
156    data->m_tile_bufs.Empty();
157
158    data->m_lights.Empty();
159}
160
161void Scene::AddTile(TileSet *tileset, int id, vec3 pos, int o, vec2 scale)
162{
163    Tile t;
164    /* FIXME: this sorting only works for a 45-degree camera */
165    t.prio = -pos.y - 2 * 32 * pos.z + (o ? 0 : 32);
166    t.tileset = tileset;
167    t.id = id;
168    t.pos = pos;
169    t.o = o;
170    t.scale = scale;
171
172    data->m_tiles.Push(t);
173}
174
175void Scene::AddLine(vec3 a, vec3 b, vec4 color)
176{
177    data->m_lines.Push(a, b, color);
178}
179
180void Scene::AddLight(Light *l)
181{
182    data->m_lights.Push(l);
183}
184
185Array<Light *> const &Scene::GetLights() const
186{
187    return data->m_lights;
188}
189
190void Scene::Render() // XXX: rename to Blit()
191{
192#if defined USE_D3D9 || defined _XBOX
193#else
194    glEnable(GL_DEPTH_TEST);
195    glDepthFunc(GL_LEQUAL);
196#if defined HAVE_GL_2X && !defined __APPLE__
197    glEnable(GL_ALPHA_TEST);
198    glAlphaFunc(GL_GEQUAL, 0.01f);
199#endif
200    glEnable(GL_BLEND);
201    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
202#endif
203
204    /* Early test if nothing needs to be rendered */
205    if (data->m_tiles.Count())
206    {
207#if defined USE_D3D9 || defined _XBOX
208#elif !defined HAVE_GLES_2X
209        glEnable(GL_TEXTURE_2D);
210#endif
211        if (!data->m_tile_shader)
212            data->m_tile_shader = Shader::Create(LOLFX_RESOURCE_NAME(tile));
213
214#if 0
215        // Randomise, then sort.
216        for (int i = 0; i < data->m_tiles.Count(); i++)
217        {
218            Tile tmp = data->m_tiles[i];
219            int j = std::rand() % data->m_tiles.Count();
220            data->m_tiles[i] = data->m_tiles[j];
221            data->m_tiles[j] = tmp;
222        }
223#endif
224        qsort(&data->m_tiles[0], data->m_tiles.Count(),
225              sizeof(Tile), SceneData::Compare);
226
227        ShaderUniform uni_mat, uni_tex;
228        ShaderAttrib attr_pos, attr_tex;
229        attr_pos = data->m_tile_shader->GetAttribLocation("in_Position", VertexUsage::Position, 0);
230        attr_tex = data->m_tile_shader->GetAttribLocation("in_TexCoord", VertexUsage::TexCoord, 0);
231
232        data->m_tile_shader->Bind();
233
234        uni_mat = data->m_tile_shader->GetUniformLocation("proj_matrix");
235        data->m_tile_shader->SetUniform(uni_mat, GetCamera()->GetProjection());
236        uni_mat = data->m_tile_shader->GetUniformLocation("view_matrix");
237        data->m_tile_shader->SetUniform(uni_mat, GetCamera()->GetView());
238        uni_mat = data->m_tile_shader->GetUniformLocation("model_matrix");
239        data->m_tile_shader->SetUniform(uni_mat, mat4(1.f));
240
241        uni_tex = data->m_tile_shader->GetUniformLocation("in_Texture");
242        data->m_tile_shader->SetUniform(uni_tex, 0);
243
244        for (int buf = 0, i = 0, n; i < data->m_tiles.Count(); i = n, buf += 2)
245        {
246            /* Count how many quads will be needed */
247            for (n = i + 1; n < data->m_tiles.Count(); n++)
248                if (data->m_tiles[i].tileset != data->m_tiles[n].tileset)
249                    break;
250
251            /* Create a vertex array object */
252            VertexBuffer *vb1 = new VertexBuffer(6 * 3 * (n - i) * sizeof(float));
253            float *vertex = (float *)vb1->Lock(0, 0);
254            VertexBuffer *vb2 = new VertexBuffer(6 * 2 * (n - i) * sizeof(float));
255            float *texture = (float *)vb2->Lock(0, 0);
256
257            data->m_tile_bufs.Push(vb1);
258            data->m_tile_bufs.Push(vb2);
259
260            for (int j = i; j < n; j++)
261            {
262                data->m_tiles[i].tileset->BlitTile(data->m_tiles[j].id,
263                                data->m_tiles[j].pos, data->m_tiles[j].o,
264                                data->m_tiles[j].scale,
265                                vertex + 18 * (j - i), texture + 12 * (j - i));
266            }
267
268            vb1->Unlock();
269            vb2->Unlock();
270
271            /* Bind texture */
272            data->m_tiles[i].tileset->Bind();
273
274            /* Bind vertex and texture coordinate buffers */
275            data->m_tile_vdecl->Bind();
276            data->m_tile_vdecl->SetStream(vb1, attr_pos);
277            data->m_tile_vdecl->SetStream(vb2, attr_tex);
278
279            /* Draw arrays */
280            data->m_tile_vdecl->DrawElements(MeshPrimitive::Triangles, 0, (n - i) * 6);
281            data->m_tile_vdecl->Unbind();
282            data->m_tiles[i].tileset->Unbind();
283        }
284
285        data->m_tiles.Empty();
286
287        data->m_tile_shader->Unbind();
288
289#if defined USE_D3D9 || defined _XBOX
290        /* TODO */
291#elif !defined HAVE_GLES_2X
292        glDisable(GL_TEXTURE_2D);
293#endif
294    }
295
296    if (data->m_lines.Count())
297    {
298        int linecount = data->m_lines.Count();
299
300        if (!data->m_line_shader)
301            data->m_line_shader = Shader::Create(LOLFX_RESOURCE_NAME(line));
302
303        VertexBuffer *vb = new VertexBuffer((sizeof(vec3) + sizeof(vec4)) * 2 * linecount);
304        float *vertex = (float *)vb->Lock(0, 0);
305        for (int i = 0; i < linecount; i++)
306        {
307            memcpy(vertex, &data->m_lines[i].m1, sizeof(vec3));
308            vertex += 3;
309            memcpy(vertex, &data->m_lines[i].m3, sizeof(vec4));
310            vertex += 4;
311            memcpy(vertex, &data->m_lines[i].m2, sizeof(vec3));
312            vertex += 3;
313            memcpy(vertex, &data->m_lines[i].m3, sizeof(vec4));
314            vertex += 4;
315        }
316        vb->Unlock();
317
318        data->m_line_shader->Bind();
319
320        ShaderUniform uni_mat, uni_tex;
321        ShaderAttrib attr_pos, attr_col;
322        attr_pos = data->m_line_shader->GetAttribLocation("in_Position", VertexUsage::Position, 0);
323        attr_col = data->m_line_shader->GetAttribLocation("in_Color", VertexUsage::Color, 0);
324
325        data->m_line_shader->Bind();
326
327        uni_mat = data->m_line_shader->GetUniformLocation("proj_matrix");
328        data->m_line_shader->SetUniform(uni_mat, GetCamera()->GetProjection());
329        uni_mat = data->m_line_shader->GetUniformLocation("view_matrix");
330        data->m_line_shader->SetUniform(uni_mat, GetCamera()->GetView());
331
332        data->m_line_vdecl->Bind();
333        data->m_line_vdecl->SetStream(vb, attr_pos, attr_col);
334        data->m_line_vdecl->DrawElements(MeshPrimitive::Lines, 0, 2 * linecount);
335        data->m_line_vdecl->Unbind();
336        data->m_line_shader->Unbind();
337
338        data->m_lines.Empty();
339        delete vb;
340    }
341
342#if defined USE_D3D9 || defined _XBOX
343    /* TODO */
344#else
345    glDisable(GL_DEPTH_TEST);
346#   if defined HAVE_GL_2X && !defined __APPLE__
347    glDisable(GL_ALPHA_TEST);
348#   endif
349    glDisable(GL_BLEND);
350#endif
351}
352
353} /* namespace lol */
354
Note: See TracBrowser for help on using the repository browser.