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

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

ps3: start fixing the vertex buffer logic in there.

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