void TubeRendererThread::run()
{
    int numThreads = GLFunctions::idealThreadCount;

    int chunkSize = m_data.size() / numThreads;

    int begin = m_id * chunkSize;
    int end = m_id * chunkSize + chunkSize;

    if ( m_id == numThreads - 1 )
    {
        end = m_data.size();
    }

    // for all voxels:
    for ( int i = begin; i < end; ++i )
    {
        QVector<float> fib = m_data[i];
        QVector<float> extra = m_extraData[i];

        if ( fib.size() < 9 )
        {
            printf( "fib with size < 3 detected" );
            continue;
        }

        int numFloats = fib.size();
        QVector3D lineStart( fib[0], fib[1], fib[2] );
        QVector3D lineEnd( fib[numFloats-3], fib[numFloats-2], fib[numFloats-1] );

        QVector3D globalColor( fabs( lineStart.x() - lineEnd.x() ), fabs( lineStart.y() - lineEnd.y() ), fabs( lineStart.z() - lineEnd.z() ) );
        globalColor.normalize();

        // push back the first vertex, done seperately because of nomal calculation
        QVector3D localColor( fib[0] - fib[3], fib[1] - fib[4], fib[2] - fib[5] );
        localColor.normalize();

        m_verts->push_back( fib[0] );
        m_verts->push_back( fib[1] );
        m_verts->push_back( fib[2] );
        m_verts->push_back( localColor.x() );
        m_verts->push_back( localColor.y() );
        m_verts->push_back( localColor.z() );
        m_verts->push_back( globalColor.x() );
        m_verts->push_back( globalColor.y() );
        m_verts->push_back( globalColor.z() );
        m_verts->push_back( extra.first() );
        m_verts->push_back( 1.0 );

        m_verts->push_back( fib[0] );
        m_verts->push_back( fib[1] );
        m_verts->push_back( fib[2] );
        m_verts->push_back( localColor.x() );
        m_verts->push_back( localColor.y() );
        m_verts->push_back( localColor.z() );
        m_verts->push_back( globalColor.x() );
        m_verts->push_back( globalColor.y() );
        m_verts->push_back( globalColor.z() );
        m_verts->push_back( extra.first() );
        m_verts->push_back( -1.0 );

        for ( int k = 1; k < fib.size() / 3 - 1; ++k )
        {
            QVector3D localColor( fib[k*3-3] - fib[k*3+3], fib[k*3-2] - fib[k*3+4], fib[k*3-1] - fib[k*3+5] );
            localColor.normalize();

            m_verts->push_back( fib[k*3] );
            m_verts->push_back( fib[k*3+1] );
            m_verts->push_back( fib[k*3+2] );
            m_verts->push_back( localColor.x() );
            m_verts->push_back( localColor.y() );
            m_verts->push_back( localColor.z() );
            m_verts->push_back( globalColor.x() );
            m_verts->push_back( globalColor.y() );
            m_verts->push_back( globalColor.z() );
            m_verts->push_back( extra[k] );
            m_verts->push_back( 1.0 );

            m_verts->push_back( fib[k*3] );
            m_verts->push_back( fib[k*3+1] );
            m_verts->push_back( fib[k*3+2] );
            m_verts->push_back( localColor.x() );
            m_verts->push_back( localColor.y() );
            m_verts->push_back( localColor.z() );
            m_verts->push_back( globalColor.x() );
            m_verts->push_back( globalColor.y() );
            m_verts->push_back( globalColor.z() );
            m_verts->push_back( extra[k] );
            m_verts->push_back( -1.0 );
        }

        QVector3D localColor2( fib[numFloats-6] - fib[numFloats-3], fib[numFloats-5] - fib[numFloats-2], fib[numFloats-4] - fib[numFloats-1] );
        localColor.normalize();
        // push back the last vertex, done seperately because of nomal calculation
        m_verts->push_back( fib[numFloats-3] );
        m_verts->push_back( fib[numFloats-2] );
        m_verts->push_back( fib[numFloats-1] );
        m_verts->push_back( localColor2.x() );
        m_verts->push_back( localColor2.y() );
        m_verts->push_back( localColor2.z() );
        m_verts->push_back( globalColor.x() );
        m_verts->push_back( globalColor.y() );
        m_verts->push_back( globalColor.z() );
        m_verts->push_back( extra.last() );
        m_verts->push_back( 1.0 );

        m_verts->push_back( fib[numFloats-3] );
        m_verts->push_back( fib[numFloats-2] );
        m_verts->push_back( fib[numFloats-1] );
        m_verts->push_back( localColor2.x() );
        m_verts->push_back( localColor2.y() );
        m_verts->push_back( localColor2.z() );
        m_verts->push_back( globalColor.x() );
        m_verts->push_back( globalColor.y() );
        m_verts->push_back( globalColor.z() );
        m_verts->push_back( extra.last() );
        m_verts->push_back( -1.0 );
    }
}
void FiberRenderer::initGeometry()
{
    if ( m_isInitialized )
    {
        return;
    }
    qDebug() << "create fiber vbo's...";

    std::vector<float>verts;

    try
    {
        verts.reserve( m_numPoints * 6 );
    }
    catch ( std::bad_alloc& )
    {
        qCritical() << "***error*** failed to allocate enough memory for vbo";
        exit ( 0 );
    }


    for ( unsigned int i = 0; i < m_fibs->size(); ++i )
    {
        Fib fib = m_fibs->at(i);

        if ( fib.length() < 2 )
        {
            printf( "fib with size < 2 detected" );
            continue;
        }

        QVector3D lineStart = fib.firstVert();
        QVector3D lineEnd = fib.lastVert();

        // push back the first vertex, done seperately because of nomal calculation
        verts.push_back( lineStart.x() );
        verts.push_back( lineStart.y() );
        verts.push_back( lineStart.z() );

        QVector3D secondVert = fib.getVert( 1 );

        QVector3D localColor( lineStart.x() - secondVert.x(), lineStart.y() - secondVert.y(), lineStart.z() - secondVert.z() );
        localColor.normalize();

        verts.push_back( localColor.x() );
        verts.push_back( localColor.y() );
        verts.push_back( localColor.z() );

        for ( unsigned int k = 1; k < fib.length() - 1; ++k )
        {
            verts.push_back( fib[k].x() );
            verts.push_back( fib[k].y() );
            verts.push_back( fib[k].z() );

            QVector3D localColor( fib[k-1].x() - fib[k+1].x(), fib[k-1].y() - fib[k+1].y(), fib[k-1].z() - fib[k+1].z() );
            localColor.normalize();

            verts.push_back( localColor.x() );
            verts.push_back( localColor.y() );
            verts.push_back( localColor.z() );

        }

        // push back the last vertex, done seperately because of nomal calculation
        verts.push_back( lineEnd.x() );
        verts.push_back( lineEnd.y() );
        verts.push_back( lineEnd.z() );

        QVector3D sec2last = fib[ fib.length() - 2 ];
        QVector3D localColor2( sec2last.x() - lineEnd.x(), sec2last.y() - lineEnd.y(), sec2last.z() - lineEnd.z() );
        localColor.normalize();

        verts.push_back( localColor2.x() );
        verts.push_back( localColor2.y() );
        verts.push_back( localColor2.z() );
    }

    glBindBuffer( GL_ARRAY_BUFFER, vbo );
    glBufferData( GL_ARRAY_BUFFER, verts.size() * sizeof(GLfloat), verts.data(), GL_STATIC_DRAW );
    glBindBuffer( GL_ARRAY_BUFFER, 0 );
    verts.clear();

    m_pointsPerLine.resize( m_fibs->size() );
    m_startIndexes.resize( m_fibs->size() );

    int currentStart = 0;
    for ( unsigned int i = 0; i < m_fibs->size(); ++i )
    {
        m_pointsPerLine[i] = m_fibs->at( i ).length();
        m_startIndexes[i] = currentStart;
        currentStart += m_pointsPerLine[i];
    }

    updateExtraData( 0 );

    qDebug() << "create fiber vbo's done";

    m_numPoints = verts.size() / 6;

    m_isInitialized = true;
}