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

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

gpu: replace exit(0) in D3D error checks with lol::Abort().

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