source: trunk/src/scene.cpp @ 2832

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

scene: for now, restore the ortho cam when blitting tiles.

  • Property svn:eol-style set to LF
  • 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
31/*
32 * The global g_scene object, initialised by Video::Init
33 */
34
35Scene *g_scene = nullptr;
36
37/*
38 * A quick and dirty Tile structure for 2D blits
39 */
40
41struct Tile
42{
43    TileSet *tileset;
44    uint32_t prio;
45    vec3 pos;
46    vec2 scale;
47    int id, o;
48};
49
50/*
51 * Scene implementation class
52 */
53
54class SceneData
55{
56    friend class Scene;
57
58private:
59    static int Compare(void const *p1, void const *p2)
60    {
61        Tile const *t1 = (Tile const *)p1;
62        Tile const *t2 = (Tile const *)p2;
63
64        if (t1->pos.z > t2->pos.z)
65            return 1;
66        if (t1->pos.z < t2->pos.z)
67            return -1;
68        return 0;
69    }
70
71    Array<vec3, vec3, vec4> m_lines;
72    Shader *m_line_shader;
73    VertexDeclaration *m_line_vdecl;
74
75    Array<Tile> m_tiles;
76    Array<Light *> m_lights;
77
78    Shader *m_tile_shader;
79    VertexDeclaration *m_tile_vdecl;
80    Array<VertexBuffer *> m_tile_bufs;
81
82    Camera *m_default_cam;
83    Array<Camera *> m_camera_stack;
84};
85
86/*
87 * Public Scene class
88 */
89
90Scene::Scene(ivec2 size)
91  : data(new SceneData())
92{
93    /* Create a default orthographic camera, in case the user doesn’t. */
94    data->m_default_cam = new Camera();
95    mat4 proj = mat4::ortho(0, size.x, 0, size.y, -1000.f, 1000.f);
96    data->m_default_cam->SetProjection(proj);
97    PushCamera(data->m_default_cam);
98
99    data->m_tile_shader = 0;
100    data->m_tile_vdecl = new VertexDeclaration(VertexStream<vec3>(VertexUsage::Position),
101                                               VertexStream<vec2>(VertexUsage::TexCoord));
102
103    data->m_line_shader = 0;
104    data->m_line_vdecl = new VertexDeclaration(VertexStream<vec3,vec4>(VertexUsage::Position, VertexUsage::Color));
105}
106
107Scene::~Scene()
108{
109    PopCamera(data->m_default_cam);
110
111    /* FIXME: this must be done while the GL context is still active.
112     * Change the code architecture to make sure of that. */
113    /* FIXME: also, make sure we do not add code to Reset() that will
114     * reallocate stuff */
115    Reset();
116
117    delete data->m_line_vdecl;
118    delete data->m_tile_vdecl;
119    delete data;
120}
121
122void Scene::PushCamera(Camera *cam)
123{
124    Ticker::Ref(cam);
125    data->m_camera_stack.Push(cam);
126}
127
128void Scene::PopCamera(Camera *cam)
129{
130    /* Parse from the end because that’s probably where we’ll find
131     * our camera first. */
132    for (int i = data->m_camera_stack.Count(); i--; )
133    {
134        if (data->m_camera_stack[i] == cam)
135        {
136            Ticker::Unref(cam);
137            data->m_camera_stack.Remove(i);
138            return;
139        }
140    }
141
142    ASSERT(false, "trying to pop a nonexistent camera from the scene");
143}
144
145Camera *Scene::GetCamera()
146{
147    return data->m_camera_stack.Last();
148}
149
150void Scene::Reset()
151{
152    for (int i = 0; i < data->m_tile_bufs.Count(); i++)
153        delete data->m_tile_bufs[i];
154    data->m_tile_bufs.Empty();
155
156    data->m_lights.Empty();
157}
158
159void Scene::AddTile(TileSet *tileset, int id, vec3 pos, int o, vec2 scale)
160{
161    ASSERT(id < tileset->GetTileCount());
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    RenderContext rc;
193    rc.SetDepthFunc(DepthFunc::LessOrEqual);
194    rc.SetBlendFunc(BlendFunc::SrcAlpha, BlendFunc::OneMinusSrcAlpha);
195    rc.SetAlphaFunc(AlphaFunc::GreaterOrEqual, 0.01f);
196
197    /* Early test if nothing needs to be rendered */
198    if (data->m_tiles.Count())
199    {
200        PushCamera(data->m_default_cam);
201
202#if defined USE_D3D9 || defined _XBOX
203#elif !defined HAVE_GLES_2X
204        glEnable(GL_TEXTURE_2D);
205#endif
206        if (!data->m_tile_shader)
207            data->m_tile_shader = Shader::Create(LOLFX_RESOURCE_NAME(tile));
208
209#if 0
210        // Randomise, then sort.
211        for (int i = 0; i < data->m_tiles.Count(); i++)
212        {
213            Tile tmp = data->m_tiles[i];
214            int j = rand<int>() % data->m_tiles.Count();
215            data->m_tiles[i] = data->m_tiles[j];
216            data->m_tiles[j] = tmp;
217        }
218#endif
219        qsort(&data->m_tiles[0], data->m_tiles.Count(),
220              sizeof(Tile), SceneData::Compare);
221
222        ShaderUniform uni_mat, uni_tex, uni_texsize;
223        ShaderAttrib attr_pos, attr_tex;
224        attr_pos = data->m_tile_shader->GetAttribLocation("in_Position", VertexUsage::Position, 0);
225        attr_tex = data->m_tile_shader->GetAttribLocation("in_TexCoord", VertexUsage::TexCoord, 0);
226
227        data->m_tile_shader->Bind();
228
229        uni_mat = data->m_tile_shader->GetUniformLocation("proj_matrix");
230        data->m_tile_shader->SetUniform(uni_mat, GetCamera()->GetProjection());
231        uni_mat = data->m_tile_shader->GetUniformLocation("view_matrix");
232        data->m_tile_shader->SetUniform(uni_mat, GetCamera()->GetView());
233        uni_mat = data->m_tile_shader->GetUniformLocation("model_matrix");
234        data->m_tile_shader->SetUniform(uni_mat, mat4(1.f));
235
236        uni_tex = data->m_tile_shader->GetUniformLocation("in_Texture");
237        data->m_tile_shader->SetUniform(uni_tex, 0);
238        uni_texsize = data->m_tile_shader->GetUniformLocation("in_TexSize");
239
240        for (int buf = 0, i = 0, n; i < data->m_tiles.Count(); i = n, buf += 2)
241        {
242            /* Count how many quads will be needed */
243            for (n = i + 1; n < data->m_tiles.Count(); n++)
244                if (data->m_tiles[i].tileset != data->m_tiles[n].tileset)
245                    break;
246
247            /* Create a vertex array object */
248            VertexBuffer *vb1 = new VertexBuffer(6 * 3 * (n - i) * sizeof(float));
249            float *vertex = (float *)vb1->Lock(0, 0);
250            VertexBuffer *vb2 = new VertexBuffer(6 * 2 * (n - i) * sizeof(float));
251            float *texture = (float *)vb2->Lock(0, 0);
252
253            data->m_tile_bufs.Push(vb1);
254            data->m_tile_bufs.Push(vb2);
255
256            for (int j = i; j < n; j++)
257            {
258                data->m_tiles[i].tileset->BlitTile(data->m_tiles[j].id,
259                                data->m_tiles[j].pos, data->m_tiles[j].o,
260                                data->m_tiles[j].scale,
261                                vertex + 18 * (j - i), texture + 12 * (j - i));
262            }
263
264            vb1->Unlock();
265            vb2->Unlock();
266
267            /* Bind texture */
268            data->m_tiles[i].tileset->Bind();
269            data->m_tile_shader->SetUniform(uni_texsize,
270                           (vec2)data->m_tiles[i].tileset->GetTextureSize());
271
272            /* Bind vertex and texture coordinate buffers */
273            data->m_tile_vdecl->Bind();
274            data->m_tile_vdecl->SetStream(vb1, attr_pos);
275            data->m_tile_vdecl->SetStream(vb2, attr_tex);
276
277            /* Draw arrays */
278            data->m_tile_vdecl->DrawElements(MeshPrimitive::Triangles, 0, (n - i) * 6);
279            data->m_tile_vdecl->Unbind();
280            data->m_tiles[i].tileset->Unbind();
281        }
282
283        data->m_tiles.Empty();
284
285        data->m_tile_shader->Unbind();
286
287#if defined USE_D3D9 || defined _XBOX
288        /* TODO */
289#elif !defined HAVE_GLES_2X
290        glDisable(GL_TEXTURE_2D);
291#endif
292
293        PopCamera(data->m_default_cam);
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
343} /* namespace lol */
344
Note: See TracBrowser for help on using the repository browser.