source: trunk/src/scene.cpp @ 1228

Last change on this file since 1228 was 1228, checked in by sam, 10 years ago

gpu: port the vertex buffer abstraction layer to OpenGL.

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