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

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

gpu: enable backface culling for indexed meshes, too.

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