vertex-buffer.c 16.3 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
/* ============================================================================
 * Freetype GL - A C OpenGL Freetype engine
 * Platform:    Any
 * WWW:         http://code.google.com/p/freetype-gl/
 * ----------------------------------------------------------------------------
 * Copyright 2011,2012 Nicolas P. Rougier. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *  1. Redistributions of source code must retain the above copyright notice,
 *     this list of conditions and the following disclaimer.
 *
 *  2. Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY NICOLAS P. ROUGIER ''AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
 * EVENT SHALL NICOLAS P. ROUGIER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * The views and conclusions contained in the software and documentation are
 * those of the authors and should not be interpreted as representing official
 * policies, either expressed or implied, of Nicolas P. Rougier.
 * ============================================================================
 */
Nicolas.Rougier's avatar
Nicolas.Rougier committed
34 35 36
#include <assert.h>
#include <string.h>
#include <stdlib.h>
37
#include <stdio.h>
38
#include "vec234.h"
39
#include "platform.h"
Nicolas.Rougier's avatar
Nicolas.Rougier committed
40 41
#include "vertex-buffer.h"

42

43 44 45 46 47 48 49 50
/**
 * Buffer status
 */
#define CLEAN  (0)
#define DIRTY  (1)
#define FROZEN (2)


51
// ----------------------------------------------------------------------------
52
vertex_buffer_t *
Nicolas.Rougier's avatar
Nicolas.Rougier committed
53
vertex_buffer_new( const char *format )
Nicolas.Rougier's avatar
Nicolas.Rougier committed
54 55
{
    size_t i, index = 0, stride = 0;
Nicolas.Rougier's avatar
Nicolas.Rougier committed
56
    const char *start = 0, *end = 0;
57
    GLchar *pointer = 0;
Nicolas.Rougier's avatar
Nicolas.Rougier committed
58

59
    vertex_buffer_t *self = (vertex_buffer_t *) malloc (sizeof(vertex_buffer_t));
Nicolas.Rougier's avatar
Nicolas.Rougier committed
60 61 62 63 64 65 66 67 68 69 70 71
    if( !self )
    {
        return NULL;
    }

    self->format = strdup( format );

    for( i=0; i<MAX_VERTEX_ATTRIBUTE; ++i )
    {
        self->attributes[i] = 0;
    }

72 73
    start = format;
    do
Nicolas.Rougier's avatar
Nicolas.Rougier committed
74
    {
75
        char *desc = 0;
76 77 78 79
        vertex_attribute_t *attribute;
        GLuint attribute_size = 0;
        end = (char *) (strchr(start+1, ','));

80 81
        if (end == NULL)
        {
82
            desc = strdup( start );
83 84 85
        }
        else
        {
86
            desc = strndup( start, end-start );
87
        }
88
        attribute = vertex_attribute_parse( desc );
89 90
        start = end+1;
        free(desc);
Nicolas.Rougier's avatar
Nicolas.Rougier committed
91
        attribute->pointer = pointer;
92 93 94 95 96 97 98 99 100 101 102 103 104 105 106

        switch( attribute->type )
        {
        case GL_BOOL:           attribute_size = sizeof(GLboolean); break;
        case GL_BYTE:           attribute_size = sizeof(GLbyte); break;
        case GL_UNSIGNED_BYTE:  attribute_size = sizeof(GLubyte); break;
        case GL_SHORT:          attribute_size = sizeof(GLshort); break;
        case GL_UNSIGNED_SHORT: attribute_size = sizeof(GLushort); break;
        case GL_INT:            attribute_size = sizeof(GLint); break;
        case GL_UNSIGNED_INT:   attribute_size = sizeof(GLuint); break;
        case GL_FLOAT:          attribute_size = sizeof(GLfloat); break;
        default:                attribute_size = 0;
        }
        stride  += attribute->size*attribute_size;
        pointer += attribute->size*attribute_size;
Nicolas.Rougier's avatar
Nicolas.Rougier committed
107 108
        self->attributes[index] = attribute;
        index++;
109 110
    } while ( end && (index < MAX_VERTEX_ATTRIBUTE) );

Nicolas.Rougier's avatar
Nicolas.Rougier committed
111 112 113 114
    for( i=0; i<index; ++i )
    {
        self->attributes[i]->stride = stride;
    }
115

Nicolas.Rougier's avatar
Nicolas.Rougier committed
116
    self->vertices = vector_new( stride );
Nicolas.Rougier's avatar
Nicolas.Rougier committed
117
    self->vertices_id  = 0;
118 119
    self->GPU_vsize = 0;

Nicolas.Rougier's avatar
Nicolas.Rougier committed
120
    self->indices = vector_new( sizeof(GLuint) );
Nicolas.Rougier's avatar
Nicolas.Rougier committed
121
    self->indices_id  = 0;
122 123
    self->GPU_isize = 0;

124
    self->items = vector_new( sizeof(ivec4) );
125
    self->state = DIRTY;
126
    self->mode = GL_TRIANGLES;
Nicolas.Rougier's avatar
Nicolas.Rougier committed
127 128 129
    return self;
}

130 131 132


// ----------------------------------------------------------------------------
Nicolas.Rougier's avatar
Nicolas.Rougier committed
133
void
134
vertex_buffer_delete( vertex_buffer_t *self )
Nicolas.Rougier's avatar
Nicolas.Rougier committed
135
{
136 137
    size_t i;

138 139
    assert( self );

140 141 142 143 144 145 146 147 148 149

    for( i=0; i<MAX_VERTEX_ATTRIBUTE; ++i )
    {
        if( self->attributes[i] )
        {
            vertex_attribute_delete( self->attributes[i] );
        }
    }


Nicolas.Rougier's avatar
Nicolas.Rougier committed
150 151 152 153 154 155 156 157 158 159 160 161
    vector_delete( self->vertices );
    self->vertices = 0;
    if( self->vertices_id )
    {
        glDeleteBuffers( 1, &self->vertices_id );
    }
    self->vertices_id = 0;

    vector_delete( self->indices );
    self->indices = 0;
    if( self->indices_id )
    {
Nicolas.Rougier's avatar
Nicolas.Rougier committed
162
        glDeleteBuffers( 1, &self->indices_id );
Nicolas.Rougier's avatar
Nicolas.Rougier committed
163 164
    }
    self->indices_id = 0;
Nicolas.Rougier's avatar
Nicolas.Rougier committed
165 166 167

    vector_delete( self->items );

Nicolas.Rougier's avatar
Nicolas.Rougier committed
168 169 170 171 172
    if( self->format )
    {
        free( self->format );
    }
    self->format = 0;
173
    self->state = 0;
Nicolas.Rougier's avatar
Nicolas.Rougier committed
174 175 176
    free( self );
}

Nicolas.Rougier's avatar
Nicolas.Rougier committed
177

178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197
// ----------------------------------------------------------------------------
const char *
vertex_buffer_format( const vertex_buffer_t *self )
{
    assert( self );

    return self->format;
}


// ----------------------------------------------------------------------------
size_t
vertex_buffer_size( const vertex_buffer_t *self )
{
    assert( self );

    return vector_size( self->items );
}


198 199
// ----------------------------------------------------------------------------
void
200
vertex_buffer_print( vertex_buffer_t * self )
201 202
{
    int i = 0;
203 204 205 206 207 208 209 210 211 212 213
    static char *gltypes[9] = {
        "GL_BOOL",
        "GL_BYTE",
        "GL_UNSIGNED_BYTE",
        "GL_SHORT",
        "GL_UNSIGNED_SHORT",
        "GL_INT",
        "GL_UNSIGNED_INT",
        "GL_FLOAT",
        "GL_VOID"
    };
214

215 216
    assert(self);

217 218 219 220
    fprintf( stderr, "%ld vertices, %ld indices\n",
             vector_size( self->vertices ), vector_size( self->indices ) );
    while( self->attributes[i] )
    {
221 222 223 224 225 226 227 228 229 230 231 232 233
        int j = 8;
        switch( self->attributes[i]->type )
        {
        case GL_BOOL:           j=0; break;
        case GL_BYTE:           j=1; break;
        case GL_UNSIGNED_BYTE:  j=2; break;
        case GL_SHORT:          j=3; break;
        case GL_UNSIGNED_SHORT: j=4; break;
        case GL_INT:            j=5; break;
        case GL_UNSIGNED_INT:   j=6; break;
        case GL_FLOAT:          j=7; break;
        default:                j=8; break;
        }
Nicolas.Rougier's avatar
Nicolas.Rougier committed
234
        fprintf(stderr, "%s : %dx%s (+%p)\n",
235
                self->attributes[i]->name, 
236
                self->attributes[i]->size, 
237
                gltypes[j],
Nicolas.Rougier's avatar
Nicolas.Rougier committed
238
                self->attributes[i]->pointer);
239 240 241 242 243 244 245

        i += 1;
    }
}


// ----------------------------------------------------------------------------
Nicolas.Rougier's avatar
Nicolas.Rougier committed
246
void
247
vertex_buffer_upload ( vertex_buffer_t *self )
Nicolas.Rougier's avatar
Nicolas.Rougier committed
248
{
249 250
    size_t vsize, isize;

251 252 253 254 255
    if( self->state == FROZEN )
    {
        return;
    }

Nicolas.Rougier's avatar
Nicolas.Rougier committed
256 257 258 259 260 261 262 263
    if( !self->vertices_id )
    {
        glGenBuffers( 1, &self->vertices_id );
    }
    if( !self->indices_id )
    {
        glGenBuffers( 1, &self->indices_id );
    }
264

265 266
    vsize = self->vertices->size*self->vertices->item_size;
    isize = self->indices->size*self->indices->item_size;
267 268


269 270
    // Always upload vertices first such that indices do not point to non
    // existing data (if we get interrupted in between for example).
271 272

    // Upload vertices
Nicolas.Rougier's avatar
Nicolas.Rougier committed
273
    glBindBuffer( GL_ARRAY_BUFFER, self->vertices_id );
274 275 276 277 278 279 280 281 282 283 284
    if( vsize != self->GPU_vsize )
    {
        glBufferData( GL_ARRAY_BUFFER,
                      vsize, self->vertices->items, GL_DYNAMIC_DRAW );
        self->GPU_vsize = vsize;
    }
    else
    {
        glBufferSubData( GL_ARRAY_BUFFER,
                         0, vsize, self->vertices->items );
    }
Nicolas.Rougier's avatar
Nicolas.Rougier committed
285
    glBindBuffer( GL_ARRAY_BUFFER, 0 );
286

287
    // Upload indices
Nicolas.Rougier's avatar
Nicolas.Rougier committed
288
    glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, self->indices_id );
289 290 291 292 293 294 295 296 297 298 299
    if( isize != self->GPU_isize )
    {
        glBufferData( GL_ELEMENT_ARRAY_BUFFER,
                      isize, self->indices->items, GL_DYNAMIC_DRAW );
        self->GPU_isize = isize;
    }
    else
    {
        glBufferSubData( GL_ELEMENT_ARRAY_BUFFER,
                         0, isize, self->indices->items );
    }
Nicolas.Rougier's avatar
Nicolas.Rougier committed
300 301 302
    glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, 0 );
}

Nicolas.Rougier's avatar
Nicolas.Rougier committed
303

304 305

// ----------------------------------------------------------------------------
Nicolas.Rougier's avatar
Nicolas.Rougier committed
306
void
307
vertex_buffer_clear( vertex_buffer_t *self )
Nicolas.Rougier's avatar
Nicolas.Rougier committed
308 309 310
{
    assert( self );

311
    self->state = FROZEN;
Nicolas.Rougier's avatar
Nicolas.Rougier committed
312 313
    vector_clear( self->indices );
    vector_clear( self->vertices );
314
    vector_clear( self->items );
315
    self->state = DIRTY;
Nicolas.Rougier's avatar
Nicolas.Rougier committed
316 317
}

318 319 320


// ----------------------------------------------------------------------------
Nicolas.Rougier's avatar
Nicolas.Rougier committed
321
void
322
vertex_buffer_render_setup ( vertex_buffer_t *self, GLenum mode )
323
{
324 325
    size_t i;

326
    if( self->state != CLEAN )
Nicolas.Rougier's avatar
Nicolas.Rougier committed
327 328
    {
        vertex_buffer_upload( self );
329
        self->state = CLEAN;
Nicolas.Rougier's avatar
Nicolas.Rougier committed
330 331 332
    }
    
    glBindBuffer( GL_ARRAY_BUFFER, self->vertices_id );
333 334

    for( i=0; i<MAX_VERTEX_ATTRIBUTE; ++i )
Nicolas.Rougier's avatar
Nicolas.Rougier committed
335
    {
336
        vertex_attribute_t *attribute = self->attributes[i];
337
        if ( attribute == 0 )
Nicolas.Rougier's avatar
Nicolas.Rougier committed
338
        {
339
            continue;
340 341 342
        }
        else
        {
343
            vertex_attribute_enable( attribute );
Nicolas.Rougier's avatar
Nicolas.Rougier committed
344 345
        }
    }
346

Nicolas.Rougier's avatar
Nicolas.Rougier committed
347 348 349 350
    if( self->indices->size )
    {
        glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, self->indices_id );
    }
351 352
    self->mode = mode;
}
Nicolas.Rougier's avatar
Nicolas.Rougier committed
353

354 355 356 357
// ----------------------------------------------------------------------------
void
vertex_buffer_render_finish ( vertex_buffer_t *self )
{
Nicolas.Rougier's avatar
Nicolas.Rougier committed
358 359 360 361
    glBindBuffer( GL_ARRAY_BUFFER, 0 );
    glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, 0 );
}

362 363

// ----------------------------------------------------------------------------
Nicolas.Rougier's avatar
Nicolas.Rougier committed
364
void
365 366 367
vertex_buffer_render_item ( vertex_buffer_t *self,
                            size_t index )
{ 
368
    ivec4 * item = (ivec4 *) vector_get( self->items, index );
369
    assert( self );
370
    assert( index < vector_size( self->items ) );
371

372
 
373 374 375 376 377 378 379 380 381 382 383 384 385
    if( self->indices->size )
    {
        size_t start = item->istart;
        size_t count = item->icount;
        glDrawElements( self->mode, count, GL_UNSIGNED_INT, (void *)(start*sizeof(GLuint)) );
    }
    else if( self->vertices->size )
    {
        size_t start = item->vstart;
        size_t count = item->vcount;
        glDrawArrays( self->mode, start*self->vertices->item_size, count);
    }
}
386 387 388


// ----------------------------------------------------------------------------
Nicolas.Rougier's avatar
Nicolas.Rougier committed
389
void
390
vertex_buffer_render ( vertex_buffer_t *self, GLenum mode )
Nicolas.Rougier's avatar
Nicolas.Rougier committed
391
{
392 393
    size_t vcount = self->vertices->size;
    size_t icount = self->indices->size;
394

395
    vertex_buffer_render_setup( self, mode );
396 397 398 399 400 401 402 403 404 405
    if( icount )
    {
        glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, self->indices_id );
        glDrawElements( mode, icount, GL_UNSIGNED_INT, 0 );
    }
    else
    {
        glDrawArrays( mode, 0, vcount );
    }
    vertex_buffer_render_finish( self );
Nicolas.Rougier's avatar
Nicolas.Rougier committed
406
}
407
    
408 409 410


// ----------------------------------------------------------------------------
Nicolas.Rougier's avatar
Nicolas.Rougier committed
411
void
412
vertex_buffer_push_back_indices ( vertex_buffer_t * self,
Nicolas.Rougier's avatar
Nicolas.Rougier committed
413 414
                                  const GLuint * indices,
                                  const size_t icount )
Nicolas.Rougier's avatar
Nicolas.Rougier committed
415
{
416 417
    assert( self );

418
    self->state |= DIRTY;
419
    vector_push_back_data( self->indices, indices, icount );
Nicolas.Rougier's avatar
Nicolas.Rougier committed
420 421
}

422 423 424


// ----------------------------------------------------------------------------
Nicolas.Rougier's avatar
Nicolas.Rougier committed
425
void
426
vertex_buffer_push_back_vertices ( vertex_buffer_t * self,
Nicolas.Rougier's avatar
Nicolas.Rougier committed
427 428
                                   const void * vertices,
                                   const size_t vcount )
Nicolas.Rougier's avatar
Nicolas.Rougier committed
429
{
430 431
    assert( self );

432
    self->state |= DIRTY;
433
    vector_push_back_data( self->vertices, vertices, vcount );
Nicolas.Rougier's avatar
Nicolas.Rougier committed
434 435
}

436 437 438


// ----------------------------------------------------------------------------
Nicolas.Rougier's avatar
Nicolas.Rougier committed
439
void
440
vertex_buffer_insert_indices ( vertex_buffer_t *self,
Nicolas.Rougier's avatar
Nicolas.Rougier committed
441 442 443
                               const size_t index,
                               const GLuint *indices,
                               const size_t count )
Nicolas.Rougier's avatar
Nicolas.Rougier committed
444
{
445
    assert( self );
446 447
    assert( self->indices );
    assert( index < self->indices->size+1 );
448

449
    self->state |= DIRTY;
Nicolas.Rougier's avatar
Nicolas.Rougier committed
450 451 452
    vector_insert_data( self->indices, index, indices, count );
}

453 454 455


// ----------------------------------------------------------------------------
Nicolas.Rougier's avatar
Nicolas.Rougier committed
456
void
457
vertex_buffer_insert_vertices( vertex_buffer_t *self,
Nicolas.Rougier's avatar
Nicolas.Rougier committed
458 459 460
                               const size_t index,
                               const void *vertices,
                               const size_t vcount )
Nicolas.Rougier's avatar
Nicolas.Rougier committed
461
{
462
    size_t i;
Nicolas.Rougier's avatar
Nicolas.Rougier committed
463 464 465 466
    assert( self );
    assert( self->vertices );
    assert( index < self->vertices->size+1 );

467
    self->state |= DIRTY;
468

469
     for( i=0; i<self->indices->size; ++i )
Nicolas.Rougier's avatar
Nicolas.Rougier committed
470 471 472 473 474 475
    {
        if( *(GLuint *)(vector_get( self->indices, i )) > index )
        {
            *(GLuint *)(vector_get( self->indices, i )) += index;
        }
    }
476

477
    vector_insert_data( self->vertices, index, vertices, vcount );
478 479 480 481
}



482
// ----------------------------------------------------------------------------
483
void
484
vertex_buffer_erase_indices( vertex_buffer_t *self,
Nicolas.Rougier's avatar
Nicolas.Rougier committed
485 486
                             const size_t first,
                             const size_t last )
487
{
488 489 490 491
    assert( self );
    assert( self->indices );
    assert( first < self->indices->size );
    assert( (last) <= self->indices->size );
492

493
    self->state |= DIRTY;
494
    vector_erase_range( self->indices, first, last );
495 496 497 498
}



499 500
// ----------------------------------------------------------------------------
void
501
vertex_buffer_erase_vertices( vertex_buffer_t *self,
Nicolas.Rougier's avatar
Nicolas.Rougier committed
502 503
                              const size_t first,
                              const size_t last )
504
{
505
    size_t i;
506 507 508 509 510
    assert( self );
    assert( self->vertices );
    assert( first < self->vertices->size );
    assert( (first+last) <= self->vertices->size );
    assert( last > first );
511

512
    self->state |= DIRTY;
513
    for( i=0; i<self->indices->size; ++i )
514
    {
515
        if( *(GLuint *)(vector_get( self->indices, i )) > first )
516
        {
517
            *(GLuint *)(vector_get( self->indices, i )) -= (last-first);
518 519
        }
    }
520
    vector_erase_range( self->vertices, first, last );    
521 522 523 524
}



525
// ----------------------------------------------------------------------------
526 527
size_t
vertex_buffer_push_back( vertex_buffer_t * self,
Nicolas.Rougier's avatar
Nicolas.Rougier committed
528 529
                         const void * vertices, const size_t vcount,  
                         const GLuint * indices, const size_t icount )
530
{
531 532
    return vertex_buffer_insert( self, vector_size( self->items ),
                                 vertices, vcount, indices, icount );
533 534
}

535
// ----------------------------------------------------------------------------
536
size_t
Nicolas.Rougier's avatar
Nicolas.Rougier committed
537 538 539
vertex_buffer_insert( vertex_buffer_t * self, const size_t index,
                      const void * vertices, const size_t vcount,  
                      const GLuint * indices, const size_t icount )
540
{
541 542
    size_t vstart, istart, i;
    ivec4 item;
543 544 545
    assert( self );
    assert( vertices );
    assert( indices );
546

547 548
    self->state = FROZEN;

549
    // Push back vertices
550
    vstart = vector_size( self->vertices );
551
    vertex_buffer_push_back_vertices( self, vertices, vcount );
552

553
    // Push back indices
554
    istart = vector_size( self->indices );
555
    vertex_buffer_push_back_indices( self, indices, icount );
556

557 558
    // Update indices within the vertex buffer
    for( i=0; i<icount; ++i )
559
    {
560
        *(GLuint *)(vector_get( self->indices, istart+i )) += vstart;
561
    }
562 563
    
    // Insert item
564 565 566 567
    item.x = vstart;
    item.y = vcount;
    item.z = istart;
    item.w = icount;
568
    vector_insert( self->items, index, &item );
569

570
    self->state = DIRTY;
571 572
    return index;
}
573

574
// ----------------------------------------------------------------------------
575 576
void
vertex_buffer_erase( vertex_buffer_t * self,
Nicolas.Rougier's avatar
Nicolas.Rougier committed
577
                     const size_t index )
578
{
579 580 581
    ivec4 * item;
    size_t vstart, vcount, istart, icount, i;
    
582 583
    assert( self );
    assert( index < vector_size( self->items ) );
584

585 586 587 588 589
    item = (ivec4 *) vector_get( self->items, index );
    vstart = item->vstart;
    vcount = item->vcount;
    istart = item->istart;
    icount = item->icount;
590

591 592
    // Update items
    for( i=0; i<vector_size(self->items); ++i )
593
    {
594 595 596 597 598 599
        ivec4 * item = (ivec4 *) vector_get( self->items, i );
        if( item->vstart > vstart)
        {
            item->vstart -= vcount;
            item->istart -= icount;
        }
600
    }
601 602

    self->state = FROZEN;
603
    vertex_buffer_erase_indices( self, istart, istart+icount );
604
    vertex_buffer_erase_vertices( self, vstart, vstart+vcount );
605
    vector_erase( self->items, index );
606
    self->state = DIRTY;
607
}