Commit cd517f67 authored by Maciej Suminski's avatar Maciej Suminski
Browse files

Added VBO_CONTAINER as a faster storage for vertices (OPENGL_GAL), tuned for...

Added VBO_CONTAINER as a faster storage for vertices (OPENGL_GAL), tuned for exchanging data with GPU.

Removed a few unnecessary variables and fields from OPENGL_GAL.
Added function GAL::ClearCache() for freeing memory used by cached items.
Fixed a few memory leaks (tesselator, PAINTER's settings & VIEW_ITEM's groups).
Changed a few functions into inlines.
parent 876bf75d
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ set(GAL_SRCS
    gal/opengl/opengl_gal.cpp
    gal/opengl/shader.cpp
    gal/opengl/vbo_item.cpp
    gal/opengl/vbo_container.cpp
    gal/cairo/cairo_gal.cpp
    view/wx_view_controls.cpp
    )
+12 −6
Original line number Diff line number Diff line
@@ -99,10 +99,7 @@ CAIRO_GAL::~CAIRO_GAL()
    delete cursorPixels;
    delete cursorPixelsSaved;

    for( int i = groups.size() - 1; i >= 0; --i )
    {
        DeleteGroup( i );
    }
    ClearCache();

    deleteBitmaps();
}
@@ -687,13 +684,22 @@ void CAIRO_GAL::EndGroup()
}


void CAIRO_GAL::ClearCache()
{
    for( int i = groups.size() - 1; i >= 0; --i )
    {
        DeleteGroup( i );
    }
}


void CAIRO_GAL::DeleteGroup( int aGroupNumber )
{
    storePath();

    // Delete the Cairo paths
    for( std::deque<GroupElement>::iterator it = groups[aGroupNumber].begin(), end = groups[aGroupNumber].end();
         it != end; ++it )
    std::deque<GroupElement>::iterator it, end;
    for( it = groups[aGroupNumber].begin(), end = groups[aGroupNumber].end(); it != end; ++it )
    {
        if( it->command == CMD_FILL_PATH || it->command == CMD_STROKE_PATH )
        {
+116 −192
Original line number Diff line number Diff line
@@ -29,8 +29,8 @@
#include <cmath>

#include <gal/opengl/opengl_gal.h>
#include <gal/opengl/vbo_container.h>
#include <gal/definitions.h>
#include <gal/opengl/glm/gtc/matrix_transform.hpp>

#include <wx/log.h>
#include <macros.h>
@@ -78,7 +78,6 @@ OPENGL_GAL::OPENGL_GAL( wxWindow* aParent, wxEvtHandler* aMouseListener,
    isVboInitialized         = false;
    vboNeedsUpdate           = false;
    curVboItem               = NULL;
    vboSize                  = 0;
    transform                = glm::mat4( 1.0f );   // Identity matrix

    SetSize( parentSize );
@@ -107,12 +106,26 @@ OPENGL_GAL::OPENGL_GAL( wxWindow* aParent, wxEvtHandler* aMouseListener,
    Connect( wxEVT_ENTER_WINDOW, wxMouseEventHandler( OPENGL_GAL::skipMouseEvent ) );
#endif

    vboContainer = new VBO_CONTAINER;

    // Tesselator initialization
    tesselator = gluNewTess();
    InitTesselatorCallbacks( tesselator );
    gluTessProperty( tesselator, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_POSITIVE );

    if( !isUseShader )
    {
        // (3 vertices per triangle) * (2 items [circle&semicircle]) * (number of points per item)
        precomputedContainer = new VBO_CONTAINER( 3 * 2 * CIRCLE_POINTS );

        // Compute the unit circles, used for speed up of the circle drawing
        verticesCircle = new VBO_ITEM( precomputedContainer );
        computeUnitCircle();
        verticesCircle->Finish();

        verticesSemiCircle = new VBO_ITEM( precomputedContainer );
        computeUnitSemiCircle();
        //computeUnitArcs();    // TODO remove? it is not used anywhere
        verticesSemiCircle->Finish();
    }
}

@@ -121,6 +134,13 @@ OPENGL_GAL::~OPENGL_GAL()
{
    glFlush();

    if( !isUseShader )
    {
        delete verticesCircle;
        delete verticesSemiCircle;
        delete precomputedContainer;
    }

    // Delete the buffers
    if( isFrameBufferInitialized )
    {
@@ -128,16 +148,13 @@ OPENGL_GAL::~OPENGL_GAL()
        deleteFrameBuffer( &frameBufferBackup, &depthBufferBackup, &textureBackup );
    }

    if( isVboInitialized )
    {
        std::deque<VBO_ITEM*>::iterator it, end;
    gluDeleteTess( tesselator );

        for( it = vboItems.begin(), end = vboItems.end(); it != end; it++ )
    if( isVboInitialized )
    {
            delete *it;
        }

        ClearCache();
        deleteVertexBufferObjects();
        delete vboContainer;
    }

    delete glContext;
@@ -241,8 +258,8 @@ void OPENGL_GAL::initFrameBuffers()
void OPENGL_GAL::initVertexBufferObjects()
{
    // Generate buffers for vertices and indices
    glGenBuffers( 1, &curVboVertId );
    glGenBuffers( 1, &curVboIndId );
    glGenBuffers( 1, &vboVertices );
    glGenBuffers( 1, &vboIndices );

    isVboInitialized = true;
}
@@ -253,8 +270,8 @@ void OPENGL_GAL::deleteVertexBufferObjects()
    glBindBuffer( GL_ARRAY_BUFFER, 0 );
    glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, 0 );

    glDeleteBuffers( 1, &curVboVertId );
    glDeleteBuffers( 1, &curVboIndId );
    glDeleteBuffers( 1, &vboVertices );
    glDeleteBuffers( 1, &vboIndices );

    isVboInitialized = false;
}
@@ -348,7 +365,6 @@ void OPENGL_GAL::BeginDrawing()
    // Compile the shaders
    if( !isShaderInitialized && isUseShader )
    {
        shader.ConfigureGeometryShader( 3, GL_TRIANGLES, GL_TRIANGLES );
        shader.AddSource( shaderPath + std::string( "/shader.vert" ), SHADER_TYPE_VERTEX );
        shader.AddSource( shaderPath + std::string( "/shader.frag" ), SHADER_TYPE_FRAGMENT );
        if( !shader.Link() )
@@ -417,9 +433,10 @@ void OPENGL_GAL::BeginDrawing()
    // Number of vertices to be drawn
    indicesSize = 0;

    glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, curVboIndId );
    glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, vboIndices );
    // Discard old buffer, so we can use it again
    glBufferData( GL_ELEMENT_ARRAY_BUFFER, vboSize * VBO_ITEM::IndByteSize, NULL, GL_STREAM_DRAW );
    glBufferData( GL_ELEMENT_ARRAY_BUFFER, vboContainer->GetSize() * VBO_ITEM::IndByteSize,
                  NULL, GL_STREAM_DRAW );

    // Map the GPU memory, so we can store indices that are going to be drawn
    indicesPtr = static_cast<GLuint*>( glMapBuffer( GL_ELEMENT_ARRAY_BUFFER, GL_WRITE_ONLY ) );
@@ -493,7 +510,7 @@ void OPENGL_GAL::EndDrawing()
    glEnableClientState( GL_COLOR_ARRAY );

    // Bind vertices data buffers
    glBindBuffer( GL_ARRAY_BUFFER, curVboVertId );
    glBindBuffer( GL_ARRAY_BUFFER, vboVertices );
    glVertexPointer( VBO_ITEM::CoordStride, GL_FLOAT, VBO_ITEM::VertByteSize, 0 );
    glColorPointer( VBO_ITEM::ColorStride, GL_FLOAT, VBO_ITEM::VertByteSize,
                    (GLvoid*) VBO_ITEM::ColorByteOffset );
@@ -544,40 +561,27 @@ void OPENGL_GAL::rebuildVbo()
    prof_start( &totalTime, false );
#endif /* __WXDEBUG__ */

    // Buffer for storing cached items data
    GLfloat* verticesBuffer = new GLfloat[VBO_ITEM::VertStride * vboSize];

    // Pointer for easier usage with memcpy
    GLfloat* verticesBufferPtr = verticesBuffer;

    // Fill out buffers with data
    for( std::deque<VBO_ITEM*>::iterator vboItem = vboItems.begin();
                vboItem != vboItems.end(); vboItem++ )
    {
        int size = (*vboItem)->GetSize();

        memcpy( verticesBufferPtr, (*vboItem)->GetVertices(), size * VBO_ITEM::VertByteSize );
        verticesBufferPtr += size * VBO_ITEM::VertStride;
    }
    GLfloat* data = (GLfloat*) vboContainer->GetAllVertices();

    // Upload vertices coordinates, shader types and indices to GPU memory
    glBindBuffer( GL_ARRAY_BUFFER, curVboVertId );
    glBufferData( GL_ARRAY_BUFFER, vboSize * VBO_ITEM::VertByteSize, verticesBuffer, GL_DYNAMIC_DRAW );
    // Upload vertices coordinates and shader types to GPU memory
    glBindBuffer( GL_ARRAY_BUFFER, vboVertices );
    glBufferData( GL_ARRAY_BUFFER, vboContainer->GetSize() * VBO_ITEM::VertByteSize,
                  data, GL_DYNAMIC_DRAW );
    glBindBuffer( GL_ARRAY_BUFFER, 0 );

    // Allocate the biggest possible buffer for indices
    glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, curVboIndId );
    glBufferData( GL_ELEMENT_ARRAY_BUFFER, vboSize * VBO_ITEM::IndByteSize, NULL, GL_STREAM_DRAW );
    glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, vboIndices );
    glBufferData( GL_ELEMENT_ARRAY_BUFFER, vboContainer->GetSize() * VBO_ITEM::IndByteSize,
                  NULL, GL_STREAM_DRAW );
    glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, 0 );

    delete[] verticesBuffer;
    vboNeedsUpdate = false;

#ifdef __WXDEBUG__
    prof_end( &totalTime );

    wxLogDebug( wxT( "Rebuilding VBO::%d vertices / %.1f ms" ),
            vboSize, (double) totalTime.value / 1000.0 );
            vboContainer->GetSize(), (double) totalTime.value / 1000.0 );
#endif /* __WXDEBUG__ */
}

@@ -726,74 +730,6 @@ inline void OPENGL_GAL::drawLineCap( const VECTOR2D& aStartPoint, const VECTOR2D
}


void OPENGL_GAL::begin( GLenum aMode )
{
    if( !isGrouping )
        glBegin( aMode );
}


void OPENGL_GAL::end()
{
    if( !isGrouping )
        glEnd();
}


void OPENGL_GAL::vertex3( double aX, double aY, double aZ )
{
    if( isGrouping )
    {
        // New vertex coordinates for VBO
        const GLfloat vertex[] = { aX, aY, aZ };
        curVboItem->PushVertex( vertex );
    }
    else
    {
        glVertex3d( aX, aY, aZ );
    }
}


void OPENGL_GAL::translate3( double aX, double aY, double aZ )
{
    if( isGrouping )
    {
        transform = glm::translate( transform, glm::vec3( aX, aY, aZ ) );
    }
    else
    {
        glTranslated( aX, aY, aZ );
    }
}


void OPENGL_GAL::color4( double aRed, double aGreen, double aBlue, double aAlpha )
{
    if( isGrouping )
    {
        curVboItem->UseColor( COLOR4D( aRed, aGreen, aBlue, aAlpha ) );
    }
    else
    {
        glColor4d( aRed, aGreen, aBlue, aAlpha );
    }
}


void OPENGL_GAL::color4( const COLOR4D& aColor )
{
    if( isGrouping )
    {
        curVboItem->UseColor( aColor );
    }
    else
    {
        glColor4d( aColor.r, aColor.g, aColor.b, aColor.a);
    }
}


void OPENGL_GAL::DrawLine( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint )
{
    if( isFillEnabled )
@@ -1206,7 +1142,13 @@ void OPENGL_GAL::DrawCircle( const VECTOR2D& aCenterPoint, double aRadius )

        if( isGrouping )
        {
            curVboItem->PushVertices( verticesCircle.GetVertices(), verticesCircle.GetSize() );
            VBO_VERTEX* circle = new VBO_VERTEX[CIRCLE_POINTS * 3];

            memcpy( circle, verticesCircle->GetVertices(),
                    VBO_ITEM::VertByteSize * CIRCLE_POINTS * 3 );
            curVboItem->PushVertices( circle, CIRCLE_POINTS * 3 );

            delete[] circle;
        }
        else
        {
@@ -1256,7 +1198,13 @@ void OPENGL_GAL::drawSemiCircle( const VECTOR2D& aCenterPoint, double aRadius, d

        if( isGrouping )
        {
            curVboItem->PushVertices( verticesSemiCircle.GetVertices(), verticesSemiCircle.GetSize() );
            VBO_VERTEX* semiCircle = new VBO_VERTEX[CIRCLE_POINTS * 3];

            memcpy( semiCircle, verticesSemiCircle->GetVertices(),
                    VBO_ITEM::VertByteSize * CIRCLE_POINTS * 3 );
            curVboItem->PushVertices( semiCircle, CIRCLE_POINTS * 3 );

            delete[] semiCircle;
        }
        else
        {
@@ -1416,32 +1364,19 @@ void OPENGL_GAL::DrawPolygon( const std::deque<VECTOR2D>& aPointList )

    setShader( SHADER_NONE );

    GLUtesselator* tesselator = gluNewTess();

    typedef std::vector<OGLPOINT> OGLPOINTS;

    // Do only one heap allocation, can do because we know size in advance.
    // std::vector is then fastest
    OGLPOINTS vertexList( aPointList.size(), OGLPOINT( "fastest" ) );

    InitTesselatorCallbacks( tesselator );

    gluTessProperty( tesselator, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_POSITIVE );

    glNormal3d( 0.0, 0.0, 1.0 );
    color4( fillColor.r, fillColor.g, fillColor.b, fillColor.a );

    glShadeModel( GL_FLAT );
    if( isGrouping )
    {
        // Store polygon triangles' coordinates to the current VBO item
        gluTessBeginPolygon( tesselator, curVboItem );
    }
    else
    {
        // Display polygons directly
        gluTessBeginPolygon( tesselator, NULL );
    }

    TessParams params = { curVboItem, tessIntersects };
    gluTessBeginPolygon( tesselator, &params );
    gluTessBeginContour( tesselator );

    // use operator=( const POINTS& )
@@ -1456,7 +1391,13 @@ void OPENGL_GAL::DrawPolygon( const std::deque<VECTOR2D>& aPointList )
    gluTessEndContour( tesselator );
    gluTessEndPolygon( tesselator );

    gluDeleteTess( tesselator );
    // Free allocated intersecting points
    std::vector<GLdouble*>::iterator it, it_end;
    for( it = tessIntersects.begin(), it_end = tessIntersects.end(); it < it_end; ++it )
    {
        delete[] *it;
    }
    tessIntersects.clear();

    // vertexList destroyed here
}
@@ -1639,8 +1580,7 @@ int OPENGL_GAL::BeginGroup()
    vboNeedsUpdate = true;

    // Save the pointer for caching the current item
    curVboItem = new VBO_ITEM;
    curVboItem->SetOffset( vboSize );
    curVboItem = new VBO_ITEM( vboContainer );
    vboItems.push_back( curVboItem );

    return vboItems.size() - 1;
@@ -1649,27 +1589,30 @@ int OPENGL_GAL::BeginGroup()

void OPENGL_GAL::EndGroup()
{
    vboSize   += curVboItem->GetSize();
    curVboItem->Finish();
    curVboItem = NULL;
    isGrouping = false;
}


void OPENGL_GAL::DeleteGroup( int aGroupNumber )
void OPENGL_GAL::ClearCache()
{
#ifdef __WXDEBUG__
    if( (unsigned) aGroupNumber < vboItems.size() )
    std::deque<VBO_ITEM*>::iterator it, end;
    for( it = vboItems.begin(), end = vboItems.end(); it != end; it++ )
    {
        wxLogDebug( wxT( "Tried to delete not existing group" ) );
        delete *it;
    }
#endif /* __WXDEBUG__ */

    std::deque<VBO_ITEM*>::iterator it = vboItems.begin();
    std::advance( it, aGroupNumber );
    vboItems.clear();
}

    // vboSize -= it->GetSize(); // FIXME?
    delete *it;
    // vboItems.erase( it ); // makes change to group numbers - that's veeery bad

void OPENGL_GAL::DeleteGroup( int aGroupNumber )
{
    VBO_ITEM* item = vboItems[aGroupNumber];

    vboItems[aGroupNumber] = NULL;
    delete item;

    vboNeedsUpdate = true;
}
@@ -1687,26 +1630,6 @@ void OPENGL_GAL::DrawGroup( int aGroupNumber )
}


// TODO it is not used anywhere
/*void OPENGL_GAL::computeUnitArcs()
{
    displayListsArcs = glGenLists( CIRCLE_POINTS + 1 );

    // Create an individual display list for each arc in with an angle [0 .. 2pi]
    for( int j = 0; j < CIRCLE_POINTS + 1; j++ )
    {
        glNewList( displayListsArcs + j, GL_COMPILE );

        for( int i = 0; i < j; i++ )
        {
            glVertex2d( cos( 2 * M_PI / CIRCLE_POINTS * i ), sin( 2 * M_PI / CIRCLE_POINTS * i ) );
        }

        glEndList();
    }
}*/


void OPENGL_GAL::computeUnitCircle()
{
    displayListCircle = glGenLists( 1 );
@@ -1718,30 +1641,28 @@ void OPENGL_GAL::computeUnitCircle()
    // Insert in a display list and a vector
    for( int i = 0; i < CIRCLE_POINTS; i++ )
    {
        const GLfloat v0[] = { 0.0f, 0.0f, 0.0f };
        const GLfloat v1[] =
        {
        VBO_VERTEX v0( 0.0f, 0.0f, 0.0f );
        VBO_VERTEX v1(
            cos( 2.0 * M_PI / CIRCLE_POINTS * i ),          // x
            sin( 2.0 * M_PI / CIRCLE_POINTS * i ),          // y
            0.0f                                            // z
        };
        const GLfloat v2[] =
        {
        );
        VBO_VERTEX v2(
            cos( 2.0 * M_PI / CIRCLE_POINTS * ( i + 1 ) ),  // x
            sin( 2.0 * M_PI / CIRCLE_POINTS * ( i + 1 ) ),  // y
            0.0f                                            // z
        };                                                  
        );

        glVertex2d( 0, 0 );
        verticesCircle.PushVertex( v0 );
        verticesCircle->PushVertex( &v0 );

        glVertex2d( v1[0], v1[1] );
        verticesCircle.PushVertex( v1 );
        unitCirclePoints.push_back( VECTOR2D( v1[0], v1[1] ) ); // TODO remove
        glVertex2d( v1.x, v1.y );
        verticesCircle->PushVertex( &v1 );
        unitCirclePoints.push_back( VECTOR2D( v1.x, v1.y ) ); // TODO remove

        glVertex2d( v2[0], v2[1] );
        verticesCircle.PushVertex( v2 );
        unitCirclePoints.push_back( VECTOR2D( v2[0], v2[1] ) ); // TODO remove
        glVertex2d( v2.x, v2.y );
        verticesCircle->PushVertex( &v2 );
        unitCirclePoints.push_back( VECTOR2D( v2.x, v2.y ) ); // TODO remove
    }

    glEnd();
@@ -1759,28 +1680,26 @@ void OPENGL_GAL::computeUnitSemiCircle()

    for( int i = 0; i < CIRCLE_POINTS / 2; ++i )
    {
        GLfloat v0[] = { 0.0f, 0.0f, 0.0f };
        GLfloat v1[] = 
        {
        VBO_VERTEX v0( 0.0f, 0.0f, 0.0f );
        VBO_VERTEX v1(
            cos( 2.0 * M_PI / CIRCLE_POINTS * i ),          // x
            sin( 2.0 * M_PI / CIRCLE_POINTS * i ),          // y
            0.0f                                            // z
        };
        GLfloat v2[] =
        {
        );
        VBO_VERTEX v2(
            cos( 2.0 * M_PI / CIRCLE_POINTS * ( i + 1 ) ),  // x
            sin( 2.0 * M_PI / CIRCLE_POINTS * ( i + 1 ) ),  // y
            0.0f                                            // z
        };
        );

        glVertex2d( 0, 0 );
        verticesSemiCircle.PushVertex( v0 );
        verticesSemiCircle->PushVertex( &v0 );

        glVertex2d( v1[0], v1[1] );
        verticesSemiCircle.PushVertex( v1 );
        glVertex2d( v1.x, v1.y );
        verticesSemiCircle->PushVertex( &v1 );

        glVertex2d( v2[0], v2[1] );
        verticesSemiCircle.PushVertex( v2 );
        glVertex2d( v2.x, v2.y );
        verticesSemiCircle->PushVertex( &v2 );
    }

    glEnd();
@@ -1825,12 +1744,13 @@ void OPENGL_GAL::ComputeWorldScreenMatrix()
void CALLBACK VertexCallback( GLvoid* aVertexPtr, void* aData )
{
    GLdouble* vertex = static_cast<GLdouble*>( aVertexPtr );
    OPENGL_GAL::TessParams* param = static_cast<OPENGL_GAL::TessParams*>( aData );
    VBO_ITEM* vboItem = param->vboItem;

    if( aData )
    if( vboItem )
    {
        VBO_ITEM* vboItem = static_cast<VBO_ITEM*>( aData );
        const GLfloat newVertex[] = { vertex[0], vertex[1], vertex[2] };
        vboItem->PushVertex( newVertex );
        VBO_VERTEX newVertex( vertex[0], vertex[1], vertex[2] );
        vboItem->PushVertex( &newVertex );
    }
    else
    {
@@ -1841,9 +1761,13 @@ void CALLBACK VertexCallback( GLvoid* aVertexPtr, void* aData )

void CALLBACK CombineCallback( GLdouble coords[3],
                               GLdouble* vertex_data[4],
                               GLfloat weight[4], GLdouble** dataOut )
                               GLfloat weight[4], GLdouble** dataOut, void* aData )
{
    GLdouble* vertex = new GLdouble[3];
    OPENGL_GAL::TessParams* param = static_cast<OPENGL_GAL::TessParams*>( aData );

    // Save the pointer so we can delete it later
    param->intersectPoints.push_back( vertex );

    memcpy( vertex, coords, 3 * sizeof(GLdouble) );

@@ -1884,7 +1808,7 @@ void CALLBACK ErrorCallback( GLenum aErrorCode )
void InitTesselatorCallbacks( GLUtesselator* aTesselator )
{
    gluTessCallback( aTesselator, GLU_TESS_VERTEX_DATA,  ( void (CALLBACK*)() )VertexCallback );
    gluTessCallback( aTesselator, GLU_TESS_COMBINE,      ( void (CALLBACK*)() )CombineCallback );
    gluTessCallback( aTesselator, GLU_TESS_COMBINE_DATA, ( void (CALLBACK*)() )CombineCallback );
    gluTessCallback( aTesselator, GLU_TESS_EDGE_FLAG,    ( void (CALLBACK*)() )EdgeCallback );
    gluTessCallback( aTesselator, GLU_TESS_BEGIN_DATA,   ( void (CALLBACK*)() )BeginCallback );
    gluTessCallback( aTesselator, GLU_TESS_END_DATA,     ( void (CALLBACK*)() )EndCallback );
+369 −0

File added.

Preview size limit exceeded, changes collapsed.

+34 −71
Original line number Diff line number Diff line
@@ -27,107 +27,98 @@
 * @brief Class to handle an item held in a Vertex Buffer Object.
 */

#include <gal/opengl/vbo_container.h>
#include <gal/opengl/vbo_item.h>
#include <cstring>

using namespace KiGfx;

VBO_ITEM::VBO_ITEM() :
        m_vertices( NULL ),
VBO_ITEM::VBO_ITEM( VBO_CONTAINER* aContainer ) :
        m_offset( 0 ),
        m_size( 0 ),
        m_container( aContainer ),
        m_isDirty( true ),
        m_transform( NULL )
{
    // By default no shader is used
    m_shader[0] = 0;

    // Prepare a block for storing vertices & indices
    useNewBlock();
    // The item's size is not known yet, so we just start an item in the container
    aContainer->StartItem( this );
}


VBO_ITEM::~VBO_ITEM()
{
    if( m_isDirty )
    {
        // Data is still stored in blocks
        std::list<VBO_VERTEX*>::const_iterator v_it, v_end;
        for( v_it = m_vertBlocks.begin(), v_end = m_vertBlocks.end(); v_it != v_end; ++v_it )
            delete[] *v_it;
    }

    if( m_vertices )
        delete m_vertices;
    m_container->Free( this );
}


void VBO_ITEM::PushVertex( const GLfloat* aVertex )
void VBO_ITEM::PushVertex( VBO_VERTEX* aVertex )
{
    if( m_spaceLeft == 0 )
        useNewBlock();

    if( m_transform != NULL )
    {
        // Apply transformations
        //                X,          Y,          Z coordinates
        glm::vec4 vertex( aVertex[0], aVertex[1], aVertex[2], 1.0f );
        glm::vec4 vertex( aVertex->x, aVertex->y, aVertex->z, 1.0f );
        vertex = *m_transform * vertex;

        // Replace only coordinates, leave color as it is
        memcpy( &m_vertPtr->x, &vertex[0], CoordByteSize );
    }
    else
    {
        // Add the new vertex
        memcpy( &m_vertPtr->x, aVertex, CoordByteSize );
        aVertex->x = vertex.x;
        aVertex->y = vertex.y;
        aVertex->z = vertex.z;
    }

    // Apply currently used color
    memcpy( &m_vertPtr->r, m_color, ColorByteSize );
    aVertex->r = m_color[0];
    aVertex->g = m_color[1];
    aVertex->b = m_color[2];
    aVertex->a = m_color[3];

    // Apply currently used shader
    memcpy( &m_vertPtr->shader, m_shader, ShaderByteSize );
    for( int i = 0; i < ShaderStride; ++i )
    {
        aVertex->shader[i] = m_shader[i];
    }

    // Move to the next free space
    m_vertPtr++;
    m_container->Add( this, aVertex );

    m_size++;
    m_isDirty = true;
    m_spaceLeft--;
}


void VBO_ITEM::PushVertices( const GLfloat* aVertices, GLuint aSize )
void VBO_ITEM::PushVertices( VBO_VERTEX* aVertices, GLuint aSize )
{
    for( unsigned int i = 0; i < aSize; ++i )
    {
        PushVertex( &aVertices[i * VertStride] );
        PushVertex( &aVertices[i] );
    }
}


GLfloat* VBO_ITEM::GetVertices()
VBO_VERTEX* VBO_ITEM::GetVertices()
{
    if( m_isDirty )
        prepareFinal();
        Finish();

    return m_vertices;
    return m_container->GetVertices( this );
}


void VBO_ITEM::ChangeColor( const COLOR4D& aColor )
{
    wxASSERT_MSG( false, wxT( "This was not tested yet" ) );

    if( m_isDirty )
        prepareFinal();
        Finish();

    // Point to color of vertices
    GLfloat* vertexPtr = m_vertices + ColorOffset;
    VBO_VERTEX* vertexPtr = GetVertices();
    const GLfloat newColor[] = { aColor.r, aColor.g, aColor.b, aColor.a };

    for( int i = 0; i < m_size; ++i )
    for( unsigned int i = 0; i < m_size; ++i )
    {
        memcpy( vertexPtr, newColor, ColorByteSize );
        memcpy( &vertexPtr->r, newColor, ColorByteSize );

        // Move on to the next vertex
        vertexPtr++;
@@ -135,38 +126,10 @@ void VBO_ITEM::ChangeColor( const COLOR4D& aColor )
}


void VBO_ITEM::useNewBlock()
void VBO_ITEM::Finish()
{
    VBO_VERTEX* newVertBlock = new VBO_VERTEX[BLOCK_SIZE];

    m_vertPtr = newVertBlock;
    m_vertBlocks.push_back( newVertBlock );

    m_spaceLeft = BLOCK_SIZE;
}


void VBO_ITEM::prepareFinal()
{
    if( m_vertices )
        delete m_vertices;

    // Allocate memory that would store all of vertices
    m_vertices = new GLfloat[m_size * VertStride];
    // Set the pointer that will move along the buffer
    GLfloat* vertPtr = m_vertices;

    // Copy blocks of vertices one after another to m_vertices
    std::list<VBO_VERTEX*>::const_iterator v_it;
    for( v_it = m_vertBlocks.begin(); *v_it != m_vertBlocks.back(); ++v_it )
    {
        memcpy( vertPtr, *v_it, BLOCK_SIZE * VertByteSize );
        delete[] *v_it;
        vertPtr += ( BLOCK_SIZE * VertStride );
    }

    // In the last block we need to copy only used vertices
    memcpy( vertPtr, *v_it, ( BLOCK_SIZE - m_spaceLeft ) * VertByteSize );
    // The unknown-sized item has just ended, so we need to inform the container about it
    m_container->EndItem();

    m_isDirty = false;
}
Loading