source: trunk/src/scene.cpp @ 645

Last change on this file since 645 was 645, checked in by sam, 11 years ago

Switch scene rendering method to vertex buffer objects.

  • Property svn:keywords set to Id
File size: 4.9 KB
Line 
1//
2// Lol Engine
3//
4// Copyright: (c) 2010-2011 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://sam.zoy.org/projects/COPYING.WTFPL for more details.
9//
10
11#if defined HAVE_CONFIG_H
12#   include "config.h"
13#endif
14
15#include <cstdlib>
16#include <cmath>
17
18#ifdef WIN32
19#   define WIN32_LEAN_AND_MEAN
20#   include <windows.h>
21#endif
22#if defined __APPLE__ && defined __MACH__
23#   include <OpenGL/gl.h>
24#else
25#   define GL_GLEXT_PROTOTYPES
26#   include <GL/gl.h>
27#endif
28
29#include "core.h"
30
31struct Tile
32{
33    uint32_t prio, code;
34    int x, y, z, o;
35};
36
37/*
38 * Scene implementation class
39 */
40
41class SceneData
42{
43    friend class Scene;
44
45private:
46    static int Compare(void const *p1, void const *p2)
47    {
48        Tile const *t1 = (Tile const *)p1;
49        Tile const *t2 = (Tile const *)p2;
50
51        return t2->prio - t1->prio;
52    }
53
54    Tile *tiles;
55    int ntiles;
56    float angle;
57
58    GLuint *bufs;
59    int nbufs;
60
61    static Scene *scene;
62};
63
64Scene *SceneData::scene = NULL;
65
66/*
67 * Public Scene class
68 */
69
70Scene::Scene(float angle)
71  : data(new SceneData())
72{
73    data->tiles = 0;
74    data->ntiles = 0;
75    data->angle = angle;
76
77    data->bufs = 0;
78    data->nbufs = 0;
79}
80
81Scene::~Scene()
82{
83    /* FIXME: this must be done while the GL context is still active.
84     * Change the architecture to make sure of that. */
85    glDeleteBuffers(data->nbufs, data->bufs);
86    delete data;
87}
88
89Scene *Scene::GetDefault()
90{
91    if (!SceneData::scene)
92        SceneData::scene = new Scene(0.0f);
93    return SceneData::scene;
94}
95
96void Scene::Reset()
97{
98    if (SceneData::scene)
99        delete SceneData::scene;
100    SceneData::scene = NULL;
101}
102
103void Scene::AddTile(uint32_t code, int x, int y, int z, int o)
104{
105    if ((data->ntiles % 1024) == 0)
106        data->tiles = (Tile *)realloc(data->tiles,
107                                      (data->ntiles + 1024) * sizeof(Tile));
108    /* FIXME: this sorting only works for a 45-degree camera */
109    data->tiles[data->ntiles].prio = -y - 2 * 32 * z + (o ? 0 : 32);
110    data->tiles[data->ntiles].code = code;
111    data->tiles[data->ntiles].x = x;
112    data->tiles[data->ntiles].y = y;
113    data->tiles[data->ntiles].z = z;
114    data->tiles[data->ntiles].o = o;
115    data->ntiles++;
116}
117
118void Scene::Render() // XXX: rename to Blit()
119{
120#if 0
121    // Randomise, then sort.
122    for (int i = 0; i < data->ntiles; i++)
123    {
124        Tile tmp = data->tiles[i];
125        int j = rand() % data->ntiles;
126        data->tiles[i] = data->tiles[j];
127        data->tiles[j] = tmp;
128    }
129#endif
130    qsort(data->tiles, data->ntiles, sizeof(Tile), SceneData::Compare);
131
132    // XXX: debug stuff
133    glPushMatrix();
134    static float f = 0.0f;
135    f += 0.05f;
136    glTranslatef(320.0f, 240.0f, 0.0f);
137    glRotatef(-data->angle, 1.0f, 0.0f, 0.0f);
138#if 0
139    glRotatef(3.0f * sinf(f), 1.0f, 0.0f, 0.0f);
140    glRotatef(8.0f * cosf(f), 0.0f, 0.0f, 1.0f);
141#endif
142    glTranslatef(-320.0f, -240.0f, 0.0f);
143    // XXX: end of debug stuff
144
145    for (int buf = 0, i = 0, n; i < data->ntiles; i = n, buf += 2)
146    {
147        /* Generate new vertex / texture coord buffers if necessary */
148        if (buf + 2 > data->nbufs)
149        {
150            data->bufs = (GLuint *)realloc(data->bufs, (buf + 2) * sizeof(GLuint));
151            glGenBuffers(buf + 2 - data->nbufs, data->bufs + data->nbufs);
152            data->nbufs = buf + 2;
153        }
154
155        /* Count how many quads will be needed */
156        for (n = i + 1; n < data->ntiles; n++)
157            if (data->tiles[i].code >> 16 != data->tiles[n].code >> 16)
158                break;
159
160        /* Create a vertex array object */
161        float *vertex = (float *)malloc(6 * 3 * (n - i) * sizeof(float));
162        float *texture = (float *)malloc(6 * 2 * (n - i) * sizeof(float));
163
164        for (int j = i; j < n; j++)
165        {
166            Tiler::BlitTile(data->tiles[j].code, data->tiles[j].x,
167                            data->tiles[j].y, data->tiles[j].z, data->tiles[j].o,
168                            vertex + 18 * (j - i), texture + 12 * (j - i));
169        }
170
171        glEnableClientState(GL_VERTEX_ARRAY);
172        glEnableClientState(GL_TEXTURE_COORD_ARRAY);
173
174        glBindBuffer(GL_ARRAY_BUFFER, data->bufs[buf]);
175        glBufferData(GL_ARRAY_BUFFER, 6 * 3 * (n - i) * sizeof(float),
176                     vertex, GL_DYNAMIC_DRAW);
177        glVertexPointer(3, GL_FLOAT, 0, NULL);
178
179        glBindBuffer(GL_ARRAY_BUFFER, data->bufs[buf + 1]);
180        glBufferData(GL_ARRAY_BUFFER, 6 * 2 * (n - i) * sizeof(float),
181                     texture, GL_DYNAMIC_DRAW);
182        glTexCoordPointer(2, GL_FLOAT, 0, NULL);
183
184        Tiler::Bind(data->tiles[i].code);
185        glDrawArrays(GL_TRIANGLES, 0, (n - i) * 6);
186
187        glDisableClientState(GL_VERTEX_ARRAY);
188        glDisableClientState(GL_TEXTURE_COORD_ARRAY);
189
190        free(vertex);
191        free(texture);
192    }
193
194    glPopMatrix();
195
196    free(data->tiles);
197    data->tiles = 0;
198    data->ntiles = 0;
199}
200
Note: See TracBrowser for help on using the repository browser.