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

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

gpu: disable framebuffer objects on GL ES for now, and disable integer
attributes if GL version isn't 3.0 at least.

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