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

Last change on this file since 1961 was 1961, checked in by sam, 7 years ago

ps3: support for texture coordinates on the PS3.

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