source: trunk/src/gpu/vertexbuffer.cpp @ 1337

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

gpu: activate backface culling on OpenGL to remain consistent with
the Direct3D backend.

File size: 16.5 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 "core.h"
16#include "lolgl.h"
17
18#if defined _WIN32 && defined USE_D3D9
19#   define FAR
20#   define NEAR
21#   include <d3d9.h>
22#endif
23
24using namespace std;
25
26#if defined USE_D3D9
27extern IDirect3DDevice9 *g_d3ddevice;
28#elif defined _XBOX
29extern D3DDevice *g_d3ddevice;
30#endif
31
32namespace lol
33{
34
35//
36// The VertexBufferData class
37// --------------------------
38//
39
40class VertexBufferData
41{
42    friend class VertexBuffer;
43    friend class VertexDeclaration;
44
45#if defined USE_D3D9
46    IDirect3DVertexBuffer9 *m_vbo;
47#elif defined _XBOX
48    D3DVertexBuffer *m_vbo;
49#elif !defined __ANDROID__
50    GLuint m_vbo;
51    uint8_t *m_memory;
52    size_t m_size;
53#endif
54};
55
56//
57// The VertexDeclaration class
58// ---------------------------
59//
60
61VertexStreamBase const VertexStreamBase::Empty;
62
63VertexDeclaration::VertexDeclaration(VertexStreamBase const &s1,
64                                     VertexStreamBase const &s2,
65                                     VertexStreamBase const &s3,
66                                     VertexStreamBase const &s4,
67                                     VertexStreamBase const &s5,
68                                     VertexStreamBase const &s6,
69                                     VertexStreamBase const &s7,
70                                     VertexStreamBase const &s8,
71                                     VertexStreamBase const &s9,
72                                     VertexStreamBase const &s10,
73                                     VertexStreamBase const &s11,
74                                     VertexStreamBase const &s12) : m_count(0)
75{
76    if (&s1 != &VertexStreamBase::Empty) AddStream(s1);
77    if (&s2 != &VertexStreamBase::Empty) AddStream(s2);
78    if (&s3 != &VertexStreamBase::Empty) AddStream(s3);
79    if (&s4 != &VertexStreamBase::Empty) AddStream(s4);
80    if (&s5 != &VertexStreamBase::Empty) AddStream(s5);
81    if (&s6 != &VertexStreamBase::Empty) AddStream(s6);
82    if (&s7 != &VertexStreamBase::Empty) AddStream(s7);
83    if (&s8 != &VertexStreamBase::Empty) AddStream(s8);
84    if (&s9 != &VertexStreamBase::Empty) AddStream(s9);
85    if (&s10 != &VertexStreamBase::Empty) AddStream(s10);
86    if (&s11 != &VertexStreamBase::Empty) AddStream(s11);
87    if (&s12 != &VertexStreamBase::Empty) AddStream(s12);
88    Initialize();
89}
90
91VertexDeclaration::~VertexDeclaration()
92{
93#if defined _XBOX || defined USE_D3D9
94#   if defined USE_D3D9
95    IDirect3DVertexDeclaration9 *vdecl = (IDirect3DVertexDeclaration9 *)m_data;
96#   elif defined _XBOX
97    D3DVertexDeclaration *vdecl = (D3DVertexDeclaration *)m_data;
98#   endif
99
100    if (FAILED(vdecl->Release()))
101        Abort();
102#else
103
104#endif
105}
106
107void VertexDeclaration::Bind()
108{
109#if defined _XBOX || defined USE_D3D9
110#   if defined USE_D3D9
111    IDirect3DVertexDeclaration9 *vdecl = (IDirect3DVertexDeclaration9 *)m_data;
112#   elif defined _XBOX
113    D3DVertexDeclaration *vdecl = (D3DVertexDeclaration *)m_data;
114#   endif
115
116    if (FAILED(g_d3ddevice->SetVertexDeclaration(vdecl)))
117        Abort();
118#else
119    /* FIXME: Nothing to do? */
120#endif
121}
122
123void VertexDeclaration::DrawElements(MeshPrimitive type, int skip, int count)
124{
125#if defined _XBOX || defined USE_D3D9
126    g_d3ddevice->SetRenderState(D3DRS_ALPHABLENDENABLE, 1);
127    g_d3ddevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
128    g_d3ddevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
129    if (FAILED(g_d3ddevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_CW)))
130        Abort();
131    switch (type)
132    {
133    case MeshPrimitive::Triangles:
134        if (FAILED(g_d3ddevice->DrawPrimitive(D3DPT_TRIANGLELIST, skip, count)))
135            Abort();
136        break;
137    }
138#else
139    glFrontFace(GL_CCW);
140    glEnable(GL_CULL_FACE);
141#   if defined HAVE_GL_2X && !defined __APPLE__
142    glEnable(GL_ALPHA_TEST);
143    glAlphaFunc(GL_GEQUAL, 0.01f);
144#   endif
145    glEnable(GL_BLEND);
146    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
147
148    switch (type)
149    {
150    case MeshPrimitive::Triangles:
151        glDrawArrays(GL_TRIANGLES, skip * 3, count * 3);
152        break;
153    }
154#endif
155}
156
157void VertexDeclaration::DrawIndexedElements(MeshPrimitive type, int vbase,
158                                            int vskip, int vcount,
159                                            int skip, int count)
160{
161#if defined _XBOX || defined USE_D3D9
162    g_d3ddevice->SetRenderState(D3DRS_ALPHABLENDENABLE, 1);
163    g_d3ddevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
164    g_d3ddevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
165    g_d3ddevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_CW);
166    switch (type)
167    {
168    case MeshPrimitive::Triangles:
169        if (FAILED(g_d3ddevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, vbase, vskip, vcount, skip, count)))
170            Abort();
171        break;
172    }
173#else
174#   if defined HAVE_GL_2X && !defined __APPLE__
175    glEnable(GL_ALPHA_TEST);
176    glAlphaFunc(GL_GEQUAL, 0.01f);
177#   endif
178    glEnable(GL_BLEND);
179    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
180
181    switch (type)
182    {
183    case MeshPrimitive::Triangles:
184        /* FIXME: ignores most of the arguments! */
185        glDrawElements(GL_TRIANGLES, count * 3, GL_UNSIGNED_SHORT, 0);
186        break;
187    }
188#endif
189}
190
191void VertexDeclaration::Unbind()
192{
193#if defined _XBOX || defined USE_D3D9
194    int stream = -1;
195    for (int i = 0; i < m_count; i++)
196        if (m_streams[i].index != stream)
197        {
198            stream = m_streams[i].index;
199            if (FAILED(g_d3ddevice->SetStreamSource(stream, 0, 0, 0)))
200                Abort();
201        }
202    if (FAILED(g_d3ddevice->SetVertexDeclaration(NULL)))
203        Abort();
204#else
205    /* FIXME: we need to unbind what we bound */
206    //glDisableVertexAttribArray(m_attrib);
207    /* FIXME: only useful for VAOs */
208    //glBindBuffer(GL_ARRAY_BUFFER, 0);
209    /* Or: */
210    //glDisableVertexAttribArray(m_attrib);
211    /* Or even: */
212    //glDisableClientState(GL_VERTEX_ARRAY);
213#endif
214}
215
216void VertexDeclaration::SetStream(VertexBuffer *vb, ShaderAttrib attr1,
217                                                    ShaderAttrib attr2,
218                                                    ShaderAttrib attr3,
219                                                    ShaderAttrib attr4,
220                                                    ShaderAttrib attr5,
221                                                    ShaderAttrib attr6,
222                                                    ShaderAttrib attr7,
223                                                    ShaderAttrib attr8,
224                                                    ShaderAttrib attr9,
225                                                    ShaderAttrib attr10,
226                                                    ShaderAttrib attr11,
227                                                    ShaderAttrib attr12)
228{
229#if defined _XBOX || defined USE_D3D9
230    /* Only the first item is required to know which stream this
231     * is about; the rest of the information is stored in the
232     * vertex declaration already. */
233    uint32_t usage = (attr1.m_flags >> 16) & 0xffff;
234    uint32_t index = attr1.m_flags & 0xffff;
235
236    /* Find the stream number */
237    int usage_index = 0, stream = -1;
238    for (int i = 0; i < m_count; i++)
239        if (m_streams[i].usage == usage)
240            if (usage_index++ == index)
241            {
242                stream = m_streams[i].index;
243                break;
244            }
245
246    /* Compute this stream's stride */
247    int stride = 0;
248    for (int i = 0; i < m_count; i++)
249        if (stream == m_streams[i].index)
250            stride += m_streams[i].size;
251
252    /* Now we know the stream index and the element stride */
253    /* FIXME: precompute most of the crap above! */
254    if (stream >= 0)
255    {
256        if (FAILED(g_d3ddevice->SetStreamSource(stream, vb->m_data->m_vbo, 0, stride)))
257            Abort();
258    }
259#else
260    glBindBuffer(GL_ARRAY_BUFFER, vb->m_data->m_vbo);
261    ShaderAttrib l[12] = { attr1, attr2, attr3, attr4, attr5, attr6,
262                           attr7, attr8, attr9, attr10, attr11, attr12 };
263    for (int n = 0; n < 12 && l[n].m_flags != (uint64_t)0 - 1; n++)
264    {
265        uint32_t reg = l[n].m_flags >> 32;
266        uint32_t usage = (l[n].m_flags >> 16) & 0xffff;
267        uint32_t index = l[n].m_flags & 0xffff;
268
269#   if !defined __CELLOS_LV2__
270        glEnableVertexAttribArray((GLint)reg);
271#   else
272        switch (usage)
273        {
274        case VertexUsage::Position:
275            glEnableClientState(GL_VERTEX_ARRAY);
276            break;
277        case VertexUsage::Color:
278            glEnableClientState(GL_COLOR_ARRAY);
279            break;
280        }
281#   endif
282
283        /* We need to parse the whole vertex declaration to retrieve
284         * the information. It sucks. */
285
286        int attr_index = 0, usage_index = 0;
287        /* First, find the stream index */
288        for (; attr_index < m_count; attr_index++)
289            if (m_streams[attr_index].usage == usage)
290                if (usage_index++ == index)
291                    break;
292
293        /* Now compute the stride and offset up to this stream index */
294        int stride = 0, offset = 0;
295        for (int i = 0; i < m_count; i++)
296            if (m_streams[i].index == m_streams[attr_index].index)
297            {
298                stride += m_streams[i].size;
299                if (i < attr_index)
300                    offset += m_streams[i].size;
301            }
302
303        /* Finally, we need to retrieve the type of the data */
304#   if !defined GL_DOUBLE
305#       define GL_DOUBLE 0
306#   endif
307        static struct { GLint size; GLenum type; } const tlut[] =
308        {
309            { 0, 0 },
310            { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, /* half */
311            { 1, GL_FLOAT }, { 2, GL_FLOAT }, { 3, GL_FLOAT },
312                { 4, GL_FLOAT }, /* float */
313            { 1, GL_DOUBLE }, { 2, GL_DOUBLE }, { 3, GL_DOUBLE },
314                { 4, GL_DOUBLE }, /* double */
315            { 1, GL_BYTE }, { 2, GL_BYTE }, { 3, GL_BYTE },
316                { 4, GL_BYTE }, /* int8_t */
317            { 1, GL_UNSIGNED_BYTE }, { 2, GL_UNSIGNED_BYTE },
318                { 3, GL_UNSIGNED_BYTE }, { 4, GL_UNSIGNED_BYTE }, /* uint8_t */
319            { 1, GL_SHORT }, { 2, GL_SHORT }, { 3, GL_SHORT },
320                { 4, GL_SHORT }, /* int16_t */
321            { 1, GL_UNSIGNED_SHORT }, { 2, GL_UNSIGNED_SHORT }, { 3,
322                GL_UNSIGNED_SHORT }, { 4, GL_UNSIGNED_SHORT }, /* uint16_t */
323            { 1, GL_INT }, { 2, GL_INT }, { 3, GL_INT },
324                { 4, GL_INT }, /* int32_t */
325            { 1, GL_UNSIGNED_INT }, { 2, GL_UNSIGNED_INT },
326                { 3, GL_UNSIGNED_INT }, { 4, GL_UNSIGNED_INT }, /* uint32_t */
327        };
328
329        int type_index = m_streams[attr_index].stream_type;
330        if (type_index < 0 || type_index >= sizeof(tlut) / sizeof(*tlut))
331            type_index = 0;
332
333        /* Normalize unsigned bytes by default, because it's usually
334         * some color information. */
335        GLboolean normalize = (tlut[type_index].type == GL_UNSIGNED_BYTE)
336                           || (tlut[type_index].type == GL_BYTE);
337
338#   if !defined __CELLOS_LV2__
339        glVertexAttribPointer((GLint)reg, tlut[type_index].size,
340                              tlut[type_index].type, normalize,
341                              stride, (GLvoid const *)(uintptr_t)offset);
342#   else
343        switch (usage)
344        {
345        case VertexUsage::Position:
346            glVertexPointer(tlut[type_index].size, tlut[type_index].type,
347                            stride, (GLvoid const *)(uintptr_t)offset);
348            break;
349        case VertexUsage::Normal:
350            glNormalPointer(tlut[type_index].type,
351                            stride, (GLvoid const *)(uintptr_t)offset);
352            break;
353        case VertexUsage::Color:
354            glColorPointer(tlut[type_index].size, tlut[type_index].type,
355                           stride, (GLvoid const *)(uintptr_t)offset);
356            break;
357        }
358#   endif
359    }
360#endif
361}
362
363void VertexDeclaration::Initialize()
364{
365#if defined _XBOX || defined USE_D3D9
366    static D3DVERTEXELEMENT9 const end_element[] = { D3DDECL_END() };
367    static D3DDECLTYPE const X = D3DDECLTYPE_UNUSED;
368    static D3DDECLTYPE const tlut[] =
369    {
370        D3DDECLTYPE_UNUSED,
371        X, D3DDECLTYPE_FLOAT16_2, X, D3DDECLTYPE_FLOAT16_4, /* half */
372        D3DDECLTYPE_FLOAT1, D3DDECLTYPE_FLOAT2, D3DDECLTYPE_FLOAT3,
373            D3DDECLTYPE_FLOAT4, /* float */
374        X, X, X, X, /* double */
375        X, X, X, X, /* int8_t */
376        X, X, X, D3DDECLTYPE_UBYTE4N, /* uint8_t */
377        X, D3DDECLTYPE_SHORT2N, X, D3DDECLTYPE_SHORT4N, /* int16_t */
378        X, D3DDECLTYPE_USHORT2N, X, D3DDECLTYPE_USHORT4N, /* uint16_t */
379        X, X, X, X, /* int32_t */
380        X, X, X, X, /* uint32_t */
381    };
382    static D3DDECLUSAGE const ulut[] =
383    {
384        D3DDECLUSAGE_POSITION,
385        D3DDECLUSAGE_BLENDWEIGHT,
386        D3DDECLUSAGE_BLENDINDICES,
387        D3DDECLUSAGE_NORMAL,
388        D3DDECLUSAGE_PSIZE,
389        D3DDECLUSAGE_TEXCOORD,
390        D3DDECLUSAGE_TANGENT,
391        D3DDECLUSAGE_BINORMAL,
392        D3DDECLUSAGE_TESSFACTOR,
393#if defined _XBOX
394        D3DDECLUSAGE_TEXCOORD, /* FIXME: nonexistent */
395#else
396        D3DDECLUSAGE_POSITIONT,
397#endif
398        D3DDECLUSAGE_COLOR,
399        D3DDECLUSAGE_FOG,
400        D3DDECLUSAGE_DEPTH,
401        D3DDECLUSAGE_SAMPLE,
402    };
403
404    D3DVERTEXELEMENT9 elements[12 + 1];
405    for (int n = 0; n < m_count; n++)
406    {
407        elements[n].Stream = m_streams[n].index;
408        elements[n].Offset = 0;
409        for (int i = 0; i < n; i++)
410            if (m_streams[i].index == m_streams[n].index)
411                elements[n].Offset += m_streams[i].size;
412
413        if (m_streams[n].stream_type >= 0
414             && m_streams[n].stream_type < sizeof(tlut) / sizeof(*tlut))
415            elements[n].Type = tlut[m_streams[n].stream_type];
416        else
417            elements[n].Type = D3DDECLTYPE_UNUSED;
418
419        elements[n].Method = D3DDECLMETHOD_DEFAULT;
420
421        if (m_streams[n].usage >= 0
422             && m_streams[n].usage < sizeof(ulut) / sizeof(*ulut))
423            elements[n].Usage = ulut[m_streams[n].usage];
424        else
425            elements[n].Usage = D3DDECLUSAGE_POSITION;
426
427        elements[n].UsageIndex = 0;
428        for (int i = 0; i < n; i++)
429            if (elements[i].Stream == elements[n].Stream
430                 && elements[i].Usage == elements[n].Usage)
431                elements[n].UsageIndex++;
432    }
433    elements[m_count] = end_element[0];
434
435#   if defined USE_D3D9
436    IDirect3DVertexDeclaration9 *vdecl;
437#   elif defined _XBOX
438    D3DVertexDeclaration *vdecl;
439#   endif
440
441    if (FAILED(g_d3ddevice->CreateVertexDeclaration(elements, &vdecl)))
442        Abort();
443
444    m_data = vdecl;
445#else
446
447#endif
448}
449
450void VertexDeclaration::AddStream(VertexStreamBase const &s)
451{
452    int index = m_count ? m_streams[m_count - 1].index + 1 : 0;
453
454    for (int i = 0; s.m_streams[i].size; i++)
455    {
456        m_streams[m_count].stream_type = s.m_streams[i].stream_type;
457        m_streams[m_count].usage = s.m_streams[i].usage;
458        m_streams[m_count].size = s.m_streams[i].size;
459        m_streams[m_count].index = index;
460        m_count++;
461    }
462}
463
464//
465// The VertexBuffer class
466// ----------------------
467//
468
469VertexBuffer::VertexBuffer(size_t size)
470  : m_data(new VertexBufferData)
471{
472#if defined USE_D3D9 || defined _XBOX
473    if (FAILED(g_d3ddevice->CreateVertexBuffer(size, D3DUSAGE_WRITEONLY, NULL,
474                                               D3DPOOL_MANAGED, &m_data->m_vbo, NULL)))
475        Abort();
476#elif !defined __CELLOS_LV2__ && !defined __ANDROID__
477    glGenBuffers(1, &m_data->m_vbo);
478    m_data->m_memory = new uint8_t[size];
479    m_data->m_size = size;
480#endif
481}
482
483VertexBuffer::~VertexBuffer()
484{
485#if defined USE_D3D9 || defined _XBOX
486    if (FAILED(m_data->m_vbo->Release()))
487        Abort();
488#elif !defined __CELLOS_LV2__ && !defined __ANDROID__
489    glDeleteBuffers(1, &m_data->m_vbo);
490    delete[] m_data->m_memory;
491#endif
492    delete m_data;
493}
494
495void *VertexBuffer::Lock(size_t offset, size_t size)
496{
497#if defined USE_D3D9 || defined _XBOX
498    void *ret;
499    if (FAILED(m_data->m_vbo->Lock(offset, size, (void **)&ret, 0)))
500        Abort();
501    return ret;
502#elif !defined __CELLOS_LV2__ && !defined __ANDROID__
503    return m_data->m_memory + offset;
504#endif
505}
506
507void VertexBuffer::Unlock()
508{
509#if defined USE_D3D9 || defined _XBOX
510    if (FAILED(m_data->m_vbo->Unlock()))
511        Abort();
512#elif !defined __CELLOS_LV2__ && !defined __ANDROID__
513    glBindBuffer(GL_ARRAY_BUFFER, m_data->m_vbo);
514    glBufferData(GL_ARRAY_BUFFER, m_data->m_size, m_data->m_memory,
515                 GL_STATIC_DRAW);
516#endif
517}
518
519} /* namespace lol */
520
Note: See TracBrowser for help on using the repository browser.