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

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

gpu: disable all vertex attributes upon vertex declaration unbind, just
because we don't know yet how to disable them selectively.

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