source: trunk/src/gpu/vertexbuffer.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.

File size: 12.7 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 __CELLOS_LV2__ && !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    vdecl->Release();
101#else
102
103#endif
104}
105
106void VertexDeclaration::Bind()
107{
108#if defined _XBOX || defined USE_D3D9
109#   if defined USE_D3D9
110    IDirect3DVertexDeclaration9 *vdecl = (IDirect3DVertexDeclaration9 *)m_data;
111#   elif defined _XBOX
112    D3DVertexDeclaration *vdecl = (D3DVertexDeclaration *)m_data;
113#   endif
114
115    g_d3ddevice->SetVertexDeclaration(vdecl);
116#else
117    /* FIXME: Nothing to do? */
118#endif
119}
120
121void VertexDeclaration::Unbind()
122{
123#if defined _XBOX || defined USE_D3D9
124    /* FIXME: Nothing to do? */
125#else
126    /* FIXME: we need to record what happens */
127    //glDisableVertexAttribArray(m_attrib);
128    /* FIXME: only useful for VAOs */
129    //glBindBuffer(GL_ARRAY_BUFFER, 0);
130#endif
131}
132
133void VertexDeclaration::SetStream(VertexBuffer *vb, ShaderAttrib attr1,
134                                                    ShaderAttrib attr2,
135                                                    ShaderAttrib attr3,
136                                                    ShaderAttrib attr4,
137                                                    ShaderAttrib attr5,
138                                                    ShaderAttrib attr6,
139                                                    ShaderAttrib attr7,
140                                                    ShaderAttrib attr8,
141                                                    ShaderAttrib attr9,
142                                                    ShaderAttrib attr10,
143                                                    ShaderAttrib attr11,
144                                                    ShaderAttrib attr12)
145{
146#if defined _XBOX || defined USE_D3D9
147    /* Only the first item is required to know which stream this
148     * is about; the rest of the information is stored in the
149     * vertex declaration already. */
150    uint32_t usage = (attr1.m_flags >> 16) & 0xffff;
151    uint32_t index = attr1.m_flags & 0xffff;
152
153    /* Find the stream number */
154    int usage_index = 0, stream = -1;
155    for (int i = 0; i < m_count; i++)
156        if (m_streams[i].usage == usage)
157            if (usage_index++ == index)
158            {
159                stream = m_streams[i].index;
160                break;
161            }
162
163    /* Compute this stream's stride */
164    int stride = 0;
165    for (int i = 0; i < m_count; i++)
166        if (stream == m_streams[i].index)
167            stride += m_streams[i].size;
168
169    /* Now we know the stream index and the element stride */
170    /* FIXME: precompute most of the crap above! */
171    if (stream >= 0)
172        g_d3ddevice->SetStreamSource(stream, vb->m_data->m_vbo, 0, stride);
173#else
174    glBindBuffer(GL_ARRAY_BUFFER, vb->m_data->m_vbo);
175    ShaderAttrib l[12] = { attr1, attr2, attr3, attr4, attr5, attr6,
176                           attr7, attr8, attr9, attr10, attr11, attr12 };
177    for (int n = 0; n < 12 && l[n].m_flags != (uint64_t)0 - 1; n++)
178    {
179        uint32_t reg = l[n].m_flags >> 32;
180        uint32_t usage = (l[n].m_flags >> 16) & 0xffff;
181        uint32_t index = l[n].m_flags & 0xffff;
182
183        glEnableVertexAttribArray((GLint)reg);
184
185        /* We need to parse the whole vertex declaration to retrieve
186         * the information. It sucks. */
187
188        int attr_index = 0, usage_index = 0, stream = -1;
189        /* First, find the stream index */
190        for (; attr_index < m_count; attr_index++)
191            if (m_streams[attr_index].usage == usage)
192                if (usage_index++ == index)
193                {
194                    stream = m_streams[attr_index].index;
195                    break;
196                }
197
198        /* Now compute the stride and offset up to this stream index */
199        int stride = 0, offset = 0;
200        for (int i = 0; i < m_count; i++)
201            if (m_streams[i].index == m_streams[attr_index].index)
202            {
203                stride += m_streams[i].size;
204                if (i < attr_index)
205                    offset += m_streams[i].size;
206            }
207
208        /* Finally, we need to retrieve the type of the data */
209        static struct { GLint size; GLenum type; } const tlut[] =
210        {
211            { 0, 0 },
212            { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, /* half */
213            { 1, GL_FLOAT }, { 2, GL_FLOAT }, { 3, GL_FLOAT },
214                { 4, GL_FLOAT }, /* float */
215            { 1, GL_DOUBLE }, { 2, GL_DOUBLE }, { 3, GL_DOUBLE },
216                { 4, GL_DOUBLE }, /* double */
217            { 1, GL_BYTE }, { 2, GL_BYTE }, { 3, GL_BYTE },
218                { 4, GL_BYTE }, /* int8_t */
219            { 1, GL_UNSIGNED_BYTE }, { 2, GL_UNSIGNED_BYTE },
220                { 3, GL_UNSIGNED_BYTE }, { 4, GL_UNSIGNED_BYTE }, /* uint8_t */
221            { 1, GL_SHORT }, { 2, GL_SHORT }, { 3, GL_SHORT },
222                { 4, GL_SHORT }, /* int16_t */
223            { 1, GL_UNSIGNED_SHORT }, { 2, GL_UNSIGNED_SHORT }, { 3,
224                GL_UNSIGNED_SHORT }, { 4, GL_UNSIGNED_SHORT }, /* uint16_t */
225            { 1, GL_INT }, { 2, GL_INT }, { 3, GL_INT },
226                { 4, GL_INT }, /* int32_t */
227            { 1, GL_UNSIGNED_INT }, { 2, GL_UNSIGNED_INT },
228                { 3, GL_UNSIGNED_INT }, { 4, GL_UNSIGNED_INT }, /* uint32_t */
229        };
230
231        int type_index = m_streams[attr_index].stream_type;
232        if (type_index < 0 || type_index >= sizeof(tlut) / sizeof(*tlut))
233            type_index = 0;
234Log::Error("Size %d Type %d Stride %d offset %d\n", tlut[type_index].size,
235                              tlut[type_index].type,stride,offset);
236
237        glVertexAttribPointer((GLint)reg, tlut[type_index].size,
238                              tlut[type_index].type, GL_FALSE,
239                              stride, (GLvoid const *)(uintptr_t)offset);
240    }
241#endif
242}
243
244void VertexDeclaration::Initialize()
245{
246#if defined _XBOX || defined USE_D3D9
247    static D3DVERTEXELEMENT9 const end_element[] = { D3DDECL_END() };
248    static D3DDECLTYPE const X = D3DDECLTYPE_UNUSED;
249    static D3DDECLTYPE const tlut[] =
250    {
251        D3DDECLTYPE_UNUSED,
252        X, D3DDECLTYPE_FLOAT16_2, X, D3DDECLTYPE_FLOAT16_4, /* half */
253        D3DDECLTYPE_FLOAT1, D3DDECLTYPE_FLOAT2, D3DDECLTYPE_FLOAT3,
254            D3DDECLTYPE_FLOAT4, /* float */
255        X, X, X, X, /* double */
256        X, X, X, X, /* int8_t */
257        X, X, X, D3DDECLTYPE_UBYTE4, /* uint8_t */
258        X, D3DDECLTYPE_SHORT2N, X, D3DDECLTYPE_SHORT4N, /* int16_t */
259        X, D3DDECLTYPE_USHORT2N, X, D3DDECLTYPE_USHORT4N, /* uint16_t */
260        X, X, X, X, /* int32_t */
261        X, X, X, X, /* int64_t */
262    };
263    static D3DDECLUSAGE const ulut[] =
264    {
265        D3DDECLUSAGE_POSITION,
266        D3DDECLUSAGE_BLENDWEIGHT,
267        D3DDECLUSAGE_BLENDINDICES,
268        D3DDECLUSAGE_NORMAL,
269        D3DDECLUSAGE_PSIZE,
270        D3DDECLUSAGE_TEXCOORD,
271        D3DDECLUSAGE_TANGENT,
272        D3DDECLUSAGE_BINORMAL,
273        D3DDECLUSAGE_TESSFACTOR,
274        D3DDECLUSAGE_POSITIONT,
275        D3DDECLUSAGE_COLOR,
276        D3DDECLUSAGE_FOG,
277        D3DDECLUSAGE_DEPTH,
278        D3DDECLUSAGE_SAMPLE,
279    };
280
281    D3DVERTEXELEMENT9 elements[12 + 1];
282    for (int n = 0; n < m_count; n++)
283    {
284        elements[n].Stream = m_streams[n].index;
285        elements[n].Offset = 0;
286        for (int i = 0; i < n; i++)
287            elements[n].Offset += m_streams[n].size;
288
289        if (m_streams[n].stream_type >= 0
290             && m_streams[n].stream_type < sizeof(tlut) / sizeof(*tlut))
291            elements[n].Type = tlut[m_streams[n].stream_type];
292        else
293            elements[n].Type = D3DDECLTYPE_UNUSED;
294
295        elements[n].Method = D3DDECLMETHOD_DEFAULT;
296
297        if (m_streams[n].usage >= 0
298             && m_streams[n].usage < sizeof(ulut) / sizeof(*ulut))
299            elements[n].Usage = ulut[m_streams[n].usage];
300        else
301            elements[n].Usage = D3DDECLUSAGE_POSITION;
302
303        elements[n].UsageIndex = 0;
304        for (int i = 0; i < n; i++)
305            if (elements[i].Stream == elements[n].Stream
306                 && elements[i].Usage == elements[n].Usage)
307                elements[n].UsageIndex++;
308    }
309    elements[m_count] = end_element[0];
310
311#   if defined USE_D3D9
312    IDirect3DVertexDeclaration9 *vdecl;
313#   elif defined _XBOX
314    D3DVertexDeclaration *vdecl;
315#   endif
316
317    g_d3ddevice->CreateVertexDeclaration(elements, &vdecl);
318
319    m_data = vdecl;
320#else
321
322#endif
323}
324
325void VertexDeclaration::AddStream(VertexStreamBase const &s)
326{
327    int index = m_count ? m_streams[m_count - 1].index + 1 : 0;
328
329    for (int i = 0; s.m_streams[i].size; i++)
330    {
331        m_streams[m_count].stream_type = s.m_streams[i].stream_type;
332        m_streams[m_count].usage = s.m_streams[i].usage;
333        m_streams[m_count].size = s.m_streams[i].size;
334        m_streams[m_count].index = index;
335        m_count++;
336    }
337}
338
339//
340// The VertexBuffer class
341// ----------------------
342//
343
344VertexBuffer::VertexBuffer(size_t size)
345  : m_data(new VertexBufferData)
346{
347#if defined USE_D3D9 || defined _XBOX
348    g_d3ddevice->CreateVertexBuffer(size, D3DUSAGE_WRITEONLY, NULL,
349                                    D3DPOOL_MANAGED, &m_data->m_vbo, NULL);
350    new uint8_t[size];
351#elif !defined __CELLOS_LV2__ && !defined __ANDROID__
352    glGenBuffers(1, &m_data->m_vbo);
353    m_data->m_memory = new uint8_t[size];
354    m_data->m_size = size;
355#endif
356}
357
358VertexBuffer::~VertexBuffer()
359{
360#if defined USE_D3D9 || defined _XBOX
361    m_data->m_vbo->Release();
362#elif !defined __CELLOS_LV2__ && !defined __ANDROID__
363    glDeleteBuffers(1, &m_data->m_vbo);
364    delete[] m_data->m_memory;
365#endif
366}
367
368void *VertexBuffer::Lock(size_t offset, size_t size)
369{
370#if defined USE_D3D9 || defined _XBOX
371    void *ret;
372    if (FAILED(m_data->m_vbo->Lock(offset, size, (void **)&ret, 0)))
373        exit(0);
374    return ret;
375#elif !defined __CELLOS_LV2__ && !defined __ANDROID__
376    return m_data->m_memory + offset;
377#endif
378}
379
380void VertexBuffer::Unlock()
381{
382#if defined USE_D3D9 || defined _XBOX
383    m_data->m_vbo->Unlock();
384#elif !defined __CELLOS_LV2__ && !defined __ANDROID__
385    glBindBuffer(GL_ARRAY_BUFFER, m_data->m_vbo);
386    glBufferData(GL_ARRAY_BUFFER, m_data->m_size, m_data->m_memory,
387                 GL_STATIC_DRAW);
388#endif
389}
390
391} /* namespace lol */
392
Note: See TracBrowser for help on using the repository browser.