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

Last change on this file since 1478 was 1478, checked in by sam, 9 years ago

gpu: do not convert u8vec4 to integers when set as array buffers, since we
want to normalise them to floats.

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