source: trunk/src/scene.cpp @ 854

Last change on this file since 854 was 854, checked in by sam, 8 years ago

ps3: port our naive dithering algorithm to the PS3's shader language.

  • Property svn:keywords set to Id
File size: 12.7 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
23#include "core.h"
24#include "lolgl.h"
25
26namespace lol
27{
28
29struct Tile
30{
31    TileSet *tileset;
32    uint32_t prio;
33    vec3i pos;
34    int id, o;
35};
36
37static Shader *stdshader = NULL;
38
39/*
40 * Scene implementation class
41 */
42
43class SceneData
44{
45    friend class Scene;
46
47private:
48    static int Compare(void const *p1, void const *p2)
49    {
50        Tile const *t1 = (Tile const *)p1;
51        Tile const *t2 = (Tile const *)p2;
52
53        return t2->prio - t1->prio;
54    }
55
56    mat4 model_matrix;
57
58    Tile *tiles;
59    int ntiles;
60    float angle;
61
62#if defined HAVE_GL_2X
63    GLuint vao;
64#endif
65    GLuint *bufs;
66    int nbufs;
67
68    static Scene *scene;
69};
70
71Scene *SceneData::scene = NULL;
72
73/*
74 * Public Scene class
75 */
76
77Scene::Scene(float angle)
78  : data(new SceneData())
79{
80    data->tiles = 0;
81    data->ntiles = 0;
82    data->angle = angle;
83
84    data->bufs = 0;
85    data->nbufs = 0;
86
87#if defined HAVE_GL_2X
88    glGenVertexArrays(1, &data->vao);
89#endif
90}
91
92Scene::~Scene()
93{
94    /* FIXME: this must be done while the GL context is still active.
95     * Change the code architecture to make sure of that. */
96    /* XXX: The test is necessary because of a crash with PSGL. */
97    if (data->nbufs > 0)
98        glDeleteBuffers(data->nbufs, data->bufs);
99#if defined HAVE_GL_2X
100    glDeleteVertexArrays(1, &data->vao);
101#endif
102    free(data->bufs);
103    delete data;
104}
105
106Scene *Scene::GetDefault()
107{
108    if (!SceneData::scene)
109        SceneData::scene = new Scene(0.0f);
110    return SceneData::scene;
111}
112
113void Scene::Reset()
114{
115    if (SceneData::scene)
116        delete SceneData::scene;
117    SceneData::scene = NULL;
118}
119
120void Scene::AddTile(TileSet *tileset, int id, vec3i pos, int o)
121{
122    if ((data->ntiles % 1024) == 0)
123        data->tiles = (Tile *)realloc(data->tiles,
124                                      (data->ntiles + 1024) * sizeof(Tile));
125    /* FIXME: this sorting only works for a 45-degree camera */
126    data->tiles[data->ntiles].prio = -pos.y - 2 * 32 * pos.z + (o ? 0 : 32);
127    data->tiles[data->ntiles].tileset = tileset;
128    data->tiles[data->ntiles].id = id;
129    data->tiles[data->ntiles].pos = pos;
130    data->tiles[data->ntiles].o = o;
131    data->ntiles++;
132}
133
134void Scene::Render() // XXX: rename to Blit()
135{
136    if (!stdshader)
137    {
138#if !defined __CELLOS_LV2__
139        stdshader = Shader::Create(
140            "#version 130\n"
141            "\n"
142#if defined HAVE_GLES_2X
143            "attribute vec3 in_Position;\n"
144            "attribute vec2 in_TexCoord;\n"
145            "varying vec2 pass_TexCoord;\n"
146#else
147            "in vec3 in_Position;\n"
148            "in vec2 in_TexCoord;\n"
149#endif
150            "uniform mat4 proj_matrix;\n"
151            "uniform mat4 view_matrix;\n"
152            "uniform mat4 model_matrix;\n"
153            "\n"
154            "void main()\n"
155            "{\n"
156            "    gl_Position = proj_matrix * view_matrix * model_matrix"
157            "                * vec4(in_Position, 1.0);\n"
158#if defined HAVE_GLES_2X
159            "    pass_TexCoord = in_TexCoord;\n"
160#else
161            "    gl_TexCoord[0] = vec4(in_TexCoord, 0.0, 0.0);\n"
162#endif
163            "}\n",
164
165            "#version 130\n"
166            "\n"
167            "uniform sampler2D in_Texture;\n"
168#if defined HAVE_GLES_2X
169            "varying vec2 pass_TexCoord;\n"
170#endif
171            "\n"
172            "void main()\n"
173            "{\n"
174#if defined HAVE_GLES_2X
175            "    vec4 col = texture2D(in_Texture, pass_TexCoord);\n"
176            //"    vec4 col = vec4(0.5, 1.0, 0.0, 0.5);\n"
177            //"    vec4 col = vec4(pass_TexCoord * 4.0, 0.0, 0.25);\n"
178#else
179            "    vec4 col = texture2D(in_Texture, vec2(gl_TexCoord[0]));\n"
180#endif
181#if 0
182            "    float mul = 2.0;\n"
183#if 1
184            "    vec2 d1 = mod(vec2(gl_FragCoord), vec2(2.0, 2.0));\n"
185            "    float t1 = mod(3.0 * d1.x + 2.0 * d1.y, 4.0);\n"
186            "    float dx2 = mod(floor(gl_FragCoord.x * 0.5), 2.0);\n"
187            "    float dy2 = mod(floor(gl_FragCoord.y * 0.5), 2.0);\n"
188            "    float t2 = mod(3.0 * dx2 + 2.0 * dy2, 4.0);\n"
189            "    float dx3 = mod(floor(gl_FragCoord.x * 0.25), 2.0);\n"
190            "    float dy3 = mod(floor(gl_FragCoord.y * 0.25), 2.0);\n"
191            "    float t3 = mod(3.0 * dx3 + 2.0 * dy3, 4.0);\n"
192            "    t1 = (1.0 + 16.0 * t1 + 4.0 * t2 + t3) / 65.0;\n"
193            "    t2 = t1;\n"
194            "    t3 = t1;\n"
195#else
196            "    float rand = sin(gl_FragCoord.x * 1.23456) * 123.456\n"
197            "               + cos(gl_FragCoord.y * 2.34567) * 789.012;\n"
198            "    float t1 = mod(sin(rand) * 17.13043, 1.0);\n"
199            "    float t2 = mod(sin(rand) * 27.13043, 1.0);\n"
200            "    float t3 = mod(sin(rand) * 37.13043, 1.0);\n"
201#endif
202            "    float fracx = fract(col.x * mul);\n"
203            "    float fracy = fract(col.y * mul);\n"
204            "    float fracz = fract(col.z * mul);\n"
205            "    fracx = fracx > t1 ? 1.0 : 0.0;\n"
206            "    fracy = fracy > t2 ? 1.0 : 0.0;\n"
207            "    fracz = fracz > t3 ? 1.0 : 0.0;\n"
208            "    col.x = (floor(col.x * mul) + fracx) / mul;\n"
209            "    col.y = (floor(col.y * mul) + fracy) / mul;\n"
210            "    col.z = (floor(col.z * mul) + fracz) / mul;\n"
211#endif
212            "    gl_FragColor = col;\n"
213            "}\n");
214#else
215        stdshader = Shader::Create(
216            "void main(float4 in_Position : POSITION,"
217            "          float2 in_TexCoord : TEXCOORD0,"
218            "          uniform float4x4 proj_matrix,"
219            "          uniform float4x4 view_matrix,"
220            "          uniform float4x4 model_matrix,"
221            "          out float2 out_TexCoord : TEXCOORD0,"
222            "          out float4 out_Position : POSITION)"
223            "{"
224            "    out_Position = mul(proj_matrix, mul(view_matrix, mul(model_matrix, in_Position)));"
225            "    out_TexCoord = in_TexCoord;"
226            "}",
227
228            "void main(float2 in_TexCoord : TEXCOORD0,"
229            "          float4 in_FragCoord : WPOS,"
230            "          uniform sampler2D tex,"
231            "          out float4 out_FragColor : COLOR)"
232            "{"
233            "    float4 col = tex2D(tex, in_TexCoord);"
234#if 0
235            "    float mul = 2.0;\n"
236            "    float t1, t2, t3;\n"
237#if 1
238            "    float dx1 = frac(in_FragCoord.x * 0.5) * 2.0;\n"
239            "    float dy1 = frac(in_FragCoord.y * 0.5) * 2.0;\n"
240            "    t1 = frac((3.0 * dx1 + 2.0 * dy1) / 4.0) * 4.0;\n"
241            "    float dx2 = frac(floor(in_FragCoord.x * 0.5) * 0.5) * 2.0;\n"
242            "    float dy2 = frac(floor(in_FragCoord.y * 0.5) * 0.5) * 2.0;\n"
243            "    t2 = frac((3.0 * dx2 + 2.0 * dy2) / 4.0) * 4.0;\n"
244            "    float dx3 = frac(floor(in_FragCoord.x * 0.25) * 0.5) * 2.0;\n"
245            "    float dy3 = frac(floor(in_FragCoord.y * 0.25) * 0.5) * 2.0;\n"
246            "    t3 = frac((3.0 * dx3 + 2.0 * dy3) / 4.0) * 4.0;\n"
247            "    t1 = (1.0 + 4.0 * t1 + t2) / 17.0;\n"
248            "    t2 = t1;\n"
249            "    t3 = t1;\n"
250#else
251            "    float rand = sin(in_FragCoord.x * 1.23456) * 123.456\n"
252            "               + cos(in_FragCoord.y * 2.34567) * 789.012;\n"
253            "    t1 = frac(sin(rand) * 17.13043);\n"
254            "    t2 = frac(sin(rand) * 27.13043);\n"
255            "    t3 = frac(sin(rand) * 37.13043);\n"
256#endif
257            "    float fracx = frac(col.x * mul);\n"
258            "    float fracy = frac(col.y * mul);\n"
259            "    float fracz = frac(col.z * mul);\n"
260            "    fracx = fracx > t1 ? 1.0 : 0.0;\n"
261            "    fracy = fracy > t2 ? 1.0 : 0.0;\n"
262            "    fracz = fracz > t3 ? 1.0 : 0.0;\n"
263            "    col.x = (floor(col.x * mul) + fracx) / mul;\n"
264            "    col.y = (floor(col.y * mul) + fracy) / mul;\n"
265            "    col.z = (floor(col.z * mul) + fracz) / mul;\n"
266#endif
267            "    out_FragColor = col;"
268            "}");
269#endif
270    }
271
272#if 0
273    // Randomise, then sort.
274    for (int i = 0; i < data->ntiles; i++)
275    {
276        Tile tmp = data->tiles[i];
277        int j = rand() % data->ntiles;
278        data->tiles[i] = data->tiles[j];
279        data->tiles[j] = tmp;
280    }
281#endif
282    qsort(data->tiles, data->ntiles, sizeof(Tile), SceneData::Compare);
283
284    // XXX: debug stuff
285    data->model_matrix = mat4::translate(320.0f, 240.0f, 0.0f);
286    data->model_matrix *= mat4::rotate(-data->angle, 1.0f, 0.0f, 0.0f);
287#if 0
288    static float f = 0.0f;
289    f += 0.01f;
290    data->model_matrix *= mat4::rotate(0.1f * sinf(f), 1.0f, 0.0f, 0.0f);
291    data->model_matrix *= mat4::rotate(0.3f * cosf(f), 0.0f, 0.0f, 1.0f);
292#endif
293    data->model_matrix *= mat4::translate(-320.0f, -240.0f, 0.0f);
294    // XXX: end of debug stuff
295
296    GLuint uni_mat, uni_tex, attr_pos, attr_tex;
297#if !defined __CELLOS_LV2__
298    attr_pos = stdshader->GetAttribLocation("in_Position");
299    attr_tex = stdshader->GetAttribLocation("in_TexCoord");
300#endif
301
302    stdshader->Bind();
303
304    uni_mat = stdshader->GetUniformLocation("proj_matrix");
305    stdshader->SetUniform(uni_mat, Video::GetProjMatrix());
306    uni_mat = stdshader->GetUniformLocation("view_matrix");
307    stdshader->SetUniform(uni_mat, Video::GetViewMatrix());
308    uni_mat = stdshader->GetUniformLocation("model_matrix");
309    stdshader->SetUniform(uni_mat, data->model_matrix);
310
311#if !defined __CELLOS_LV2__
312    uni_tex = stdshader->GetUniformLocation("in_Texture");
313    glUniform1i(uni_tex, 0);
314#else
315    // WTF? this doesn't exist
316    //uni_tex = stdshader->GetUniformLocation("in_Texture");
317    //cgGLSetParameter1i((CGparameter)(intptr_t)uni_tex, 0);
318#endif
319
320    glEnable(GL_TEXTURE_2D);
321    glEnable(GL_DEPTH_TEST);
322    glDepthFunc(GL_LEQUAL);
323#if defined HAVE_GL_2X
324    glEnable(GL_ALPHA_TEST);
325    glAlphaFunc(GL_GEQUAL, 0.01f);
326#endif
327    glEnable(GL_BLEND);
328    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
329
330    for (int buf = 0, i = 0, n; i < data->ntiles; i = n, buf += 2)
331    {
332        /* Generate new vertex / texture coord buffers if necessary */
333        if (buf + 2 > data->nbufs)
334        {
335            data->bufs = (GLuint *)realloc(data->bufs, (buf + 2) * sizeof(GLuint));
336            glGenBuffers(buf + 2 - data->nbufs, data->bufs + data->nbufs);
337            data->nbufs = buf + 2;
338        }
339
340        /* Count how many quads will be needed */
341        for (n = i + 1; n < data->ntiles; n++)
342            if (data->tiles[i].tileset != data->tiles[n].tileset)
343                break;
344
345        /* Create a vertex array object */
346        float *vertex = (float *)malloc(6 * 3 * (n - i) * sizeof(float));
347        float *texture = (float *)malloc(6 * 2 * (n - i) * sizeof(float));
348
349        for (int j = i; j < n; j++)
350        {
351            data->tiles[i].tileset->BlitTile(data->tiles[j].id,
352                            data->tiles[j].pos, data->tiles[j].o,
353                            vertex + 18 * (j - i), texture + 12 * (j - i));
354        }
355
356        stdshader->Bind();
357
358        /* Bind texture */
359        data->tiles[i].tileset->Bind();
360
361        /* Bind vertex, color and texture coordinate buffers */
362#if defined HAVE_GL_2X
363        glBindVertexArray(data->vao);
364#endif
365#if !defined __CELLOS_LV2__ // Use cgGLEnableClientState etc.
366        glEnableVertexAttribArray(attr_pos);
367        glEnableVertexAttribArray(attr_tex);
368
369        glBindBuffer(GL_ARRAY_BUFFER, data->bufs[buf]);
370        glBufferData(GL_ARRAY_BUFFER, 18 * (n - i) * sizeof(GLfloat),
371                     vertex, GL_STATIC_DRAW);
372        glVertexAttribPointer(attr_pos, 3, GL_FLOAT, GL_FALSE, 0, 0);
373
374        glBindBuffer(GL_ARRAY_BUFFER, data->bufs[buf + 1]);
375        glBufferData(GL_ARRAY_BUFFER, 12 * (n - i) * sizeof(GLfloat),
376                     texture, GL_STATIC_DRAW);
377        glVertexAttribPointer(attr_tex, 2, GL_FLOAT, GL_FALSE, 0, 0);
378#else
379        glEnableClientState(GL_VERTEX_ARRAY);
380        glEnableClientState(GL_TEXTURE_COORD_ARRAY);
381
382        glVertexPointer(3, GL_FLOAT, 0, vertex);
383        glTexCoordPointer(2, GL_FLOAT, 0, texture);
384#endif
385
386        /* Draw arrays */
387        glDrawArrays(GL_TRIANGLES, 0, (n - i) * 6);
388
389#if defined HAVE_GL_2X
390        glBindVertexArray(0);
391#endif
392#if !defined __CELLOS_LV2__ // Use cgGLEnableClientState etc.
393        glDisableVertexAttribArray(attr_pos);
394        glDisableVertexAttribArray(attr_tex);
395#else
396        glDisableClientState(GL_VERTEX_ARRAY);
397        glDisableClientState(GL_TEXTURE_COORD_ARRAY);
398#endif
399
400        free(vertex);
401        free(texture);
402    }
403
404    free(data->tiles);
405    data->tiles = 0;
406    data->ntiles = 0;
407}
408
409} /* namespace lol */
410
Note: See TracBrowser for help on using the repository browser.