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

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

build: fix the PS3 port by using our trig.h everywhere instead of stdlib
functions; also remove a lot of idiotic "using namespace std" from the
codebase.

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        else
389        {
390            glVertexAttribIPointer((GLint)reg, tlut[type_index].size,
391                                   tlut[type_index].type,
392                                   stride, (GLvoid const *)(uintptr_t)offset);
393        }
394#   else
395        switch (usage)
396        {
397        case VertexUsage::Position:
398            glVertexPointer(tlut[type_index].size, tlut[type_index].type,
399                            stride, (GLvoid const *)(uintptr_t)offset);
400            break;
401        case VertexUsage::Normal:
402            glNormalPointer(tlut[type_index].type,
403                            stride, (GLvoid const *)(uintptr_t)offset);
404            break;
405        case VertexUsage::Color:
406            glColorPointer(tlut[type_index].size, tlut[type_index].type,
407                           stride, (GLvoid const *)(uintptr_t)offset);
408            break;
409        }
410#   endif
411    }
412#endif
413}
414
415void VertexDeclaration::Initialize()
416{
417#if defined _XBOX || defined USE_D3D9
418    static D3DVERTEXELEMENT9 const end_element[] = { D3DDECL_END() };
419    static D3DDECLTYPE const X = D3DDECLTYPE_UNUSED;
420    static D3DDECLTYPE const tlut[] =
421    {
422        D3DDECLTYPE_UNUSED,
423        X, D3DDECLTYPE_FLOAT16_2, X, D3DDECLTYPE_FLOAT16_4, /* half */
424        D3DDECLTYPE_FLOAT1, D3DDECLTYPE_FLOAT2, D3DDECLTYPE_FLOAT3,
425            D3DDECLTYPE_FLOAT4, /* float */
426        X, X, X, X, /* double */
427        X, X, X, X, /* int8_t */
428        X, X, X, D3DDECLTYPE_UBYTE4N, /* uint8_t */
429        X, D3DDECLTYPE_SHORT2N, X, D3DDECLTYPE_SHORT4N, /* int16_t */
430        X, D3DDECLTYPE_USHORT2N, X, D3DDECLTYPE_USHORT4N, /* uint16_t */
431        X, X, X, X, /* int32_t */
432        X, X, X, X, /* uint32_t */
433    };
434    static D3DDECLUSAGE const ulut[] =
435    {
436        D3DDECLUSAGE_POSITION,
437        D3DDECLUSAGE_BLENDWEIGHT,
438        D3DDECLUSAGE_BLENDINDICES,
439        D3DDECLUSAGE_NORMAL,
440        D3DDECLUSAGE_PSIZE,
441        D3DDECLUSAGE_TEXCOORD,
442        D3DDECLUSAGE_TANGENT,
443        D3DDECLUSAGE_BINORMAL,
444        D3DDECLUSAGE_TESSFACTOR,
445#if defined _XBOX
446        D3DDECLUSAGE_TEXCOORD, /* FIXME: nonexistent */
447#else
448        D3DDECLUSAGE_POSITIONT,
449#endif
450        D3DDECLUSAGE_COLOR,
451        D3DDECLUSAGE_FOG,
452        D3DDECLUSAGE_DEPTH,
453        D3DDECLUSAGE_SAMPLE,
454    };
455
456    D3DVERTEXELEMENT9 elements[12 + 1];
457    for (int n = 0; n < m_count; n++)
458    {
459        elements[n].Stream = m_streams[n].index;
460        elements[n].Offset = 0;
461        for (int i = 0; i < n; i++)
462            if (m_streams[i].index == m_streams[n].index)
463                elements[n].Offset += m_streams[i].size;
464
465        if (m_streams[n].stream_type >= 0
466             && m_streams[n].stream_type < sizeof(tlut) / sizeof(*tlut))
467            elements[n].Type = tlut[m_streams[n].stream_type];
468        else
469            elements[n].Type = D3DDECLTYPE_UNUSED;
470
471        elements[n].Method = D3DDECLMETHOD_DEFAULT;
472
473        if (m_streams[n].usage >= 0
474             && m_streams[n].usage < sizeof(ulut) / sizeof(*ulut))
475            elements[n].Usage = ulut[m_streams[n].usage];
476        else
477            elements[n].Usage = D3DDECLUSAGE_POSITION;
478
479        elements[n].UsageIndex = 0;
480        for (int i = 0; i < n; i++)
481            if (elements[i].Stream == elements[n].Stream
482                 && elements[i].Usage == elements[n].Usage)
483                elements[n].UsageIndex++;
484    }
485    elements[m_count] = end_element[0];
486
487#   if defined USE_D3D9
488    IDirect3DVertexDeclaration9 *vdecl;
489#   elif defined _XBOX
490    D3DVertexDeclaration *vdecl;
491#   endif
492
493    if (FAILED(g_d3ddevice->CreateVertexDeclaration(elements, &vdecl)))
494        Abort();
495
496    m_data = vdecl;
497#else
498
499#endif
500}
501
502void VertexDeclaration::AddStream(VertexStreamBase const &s)
503{
504    int index = m_count ? m_streams[m_count - 1].index + 1 : 0;
505
506    for (int i = 0; s.m_streams[i].size; i++)
507    {
508        m_streams[m_count].stream_type = s.m_streams[i].stream_type;
509        m_streams[m_count].usage = s.m_streams[i].usage;
510        m_streams[m_count].size = s.m_streams[i].size;
511        m_streams[m_count].index = index;
512        m_count++;
513    }
514}
515
516//
517// The VertexBuffer class
518// ----------------------
519//
520
521VertexBuffer::VertexBuffer(size_t size)
522  : m_data(new VertexBufferData)
523{
524    m_data->m_size = size;
525    if (!size)
526        return;
527#if defined USE_D3D9 || defined _XBOX
528    if (FAILED(g_d3ddevice->CreateVertexBuffer(size, D3DUSAGE_WRITEONLY, NULL,
529                                               D3DPOOL_MANAGED, &m_data->m_vbo, NULL)))
530        Abort();
531#elif !defined __CELLOS_LV2__
532    glGenBuffers(1, &m_data->m_vbo);
533    m_data->m_memory = new uint8_t[size];
534#endif
535}
536
537VertexBuffer::~VertexBuffer()
538{
539    if (m_data->m_size)
540    {
541#if defined USE_D3D9 || defined _XBOX
542        if (FAILED(m_data->m_vbo->Release()))
543            Abort();
544#elif !defined __CELLOS_LV2__
545        glDeleteBuffers(1, &m_data->m_vbo);
546        delete[] m_data->m_memory;
547#endif
548    }
549    delete m_data;
550}
551
552void *VertexBuffer::Lock(size_t offset, size_t size)
553{
554    if (!m_data->m_size)
555        return NULL;
556#if defined USE_D3D9 || defined _XBOX
557    void *ret;
558    if (FAILED(m_data->m_vbo->Lock(offset, size, (void **)&ret, 0)))
559        Abort();
560    return ret;
561#elif !defined __CELLOS_LV2__
562    return m_data->m_memory + offset;
563#endif
564}
565
566void VertexBuffer::Unlock()
567{
568    if (!m_data->m_size)
569        return;
570#if defined USE_D3D9 || defined _XBOX
571    if (FAILED(m_data->m_vbo->Unlock()))
572        Abort();
573#elif !defined __CELLOS_LV2__
574    glBindBuffer(GL_ARRAY_BUFFER, m_data->m_vbo);
575    glBufferData(GL_ARRAY_BUFFER, m_data->m_size, m_data->m_memory,
576                 GL_STATIC_DRAW);
577    glBindBuffer(GL_ARRAY_BUFFER, 0);
578#endif
579}
580
581} /* namespace lol */
582
Note: See TracBrowser for help on using the repository browser.