void EDA_3D_CANVAS::render3DComponentShape( MODULE* module,
                                            bool aIsRenderingJustNonTransparentObjects,
                                            bool aIsRenderingJustTransparentObjects )
{
    double zpos = GetPrm3DVisu().GetModulesZcoord3DIU( module->IsFlipped() );

    glPushMatrix();

    wxPoint pos = module->GetPosition();

    glTranslatef(  pos.x * GetPrm3DVisu().m_BiuTo3Dunits,
                  -pos.y * GetPrm3DVisu().m_BiuTo3Dunits,
                   zpos );

    if( module->GetOrientation() )
        glRotatef( (double) module->GetOrientation() / 10.0, 0.0f, 0.0f, 1.0f );

    if( module->IsFlipped() )
    {
        glRotatef( 180.0f, 0.0f, 1.0f, 0.0f );
        glRotatef( 180.0f, 0.0f, 0.0f, 1.0f );
    }

    S3D_MASTER* shape3D = module->Models();

    for( ; shape3D; shape3D = shape3D->Next() )
    {
        if( shape3D->Is3DType( S3D_MASTER::FILE3D_VRML ) )
        {
            glPushMatrix();

            shape3D->Render( aIsRenderingJustNonTransparentObjects,
                             aIsRenderingJustTransparentObjects );

            if( isEnabled( FL_RENDER_SHOW_MODEL_BBOX ) )
            {
                // Set the alpha current color to opaque
                float currentColor[4];
                glGetFloatv( GL_CURRENT_COLOR,currentColor );
                currentColor[3] = 1.0f;
                glColor4fv( currentColor );

                CBBOX thisBBox = shape3D->getBBox();
                thisBBox.GLdebug();
            }

            glPopMatrix();

            // Debug AABBox
            //thisBBox = shape3D->getfastAABBox();
            //thisBBox.GLdebug();
        }
    }

    glPopMatrix();
}
Beispiel #2
0
void CBBOX::ApplyTransformationAA( glm::mat4 aTransformMatrix )
{
    if( m_initialized == false )
        return;

    // apply the transformation matrix for each of vertices of the bounding box
    // and make a union with all vertices
    CBBOX tmpBBox = CBBOX(  S3D_VERTEX( aTransformMatrix * glm::vec4( m_min.x, m_min.y, m_min.z, 1.0f ) ) );
    tmpBBox.Union(          S3D_VERTEX( aTransformMatrix * glm::vec4( m_max.x, m_min.y, m_min.z, 1.0f ) ) );
    tmpBBox.Union(          S3D_VERTEX( aTransformMatrix * glm::vec4( m_min.x, m_max.y, m_min.z, 1.0f ) ) );
    tmpBBox.Union(          S3D_VERTEX( aTransformMatrix * glm::vec4( m_min.x, m_min.y, m_max.z, 1.0f ) ) );
    tmpBBox.Union(          S3D_VERTEX( aTransformMatrix * glm::vec4( m_min.x, m_max.y, m_max.z, 1.0f ) ) );
    tmpBBox.Union(          S3D_VERTEX( aTransformMatrix * glm::vec4( m_max.x, m_max.y, m_min.z, 1.0f ) ) );
    tmpBBox.Union(          S3D_VERTEX( aTransformMatrix * glm::vec4( m_max.x, m_min.y, m_max.z, 1.0f ) ) );
    tmpBBox.Union(          S3D_VERTEX( aTransformMatrix * glm::vec4( m_max.x, m_max.y, m_max.z, 1.0f ) ) );

    m_min = tmpBBox.m_min;
    m_max = tmpBBox.m_max;
}
BVHBuildNode *CBVH_PBRT::buildUpperSAH(
                                      std::vector<BVHBuildNode *> &treeletRoots,
                                      int start, int end,
                                      int *totalNodes )
{
    wxASSERT( totalNodes != NULL );
    wxASSERT( start < end );
    wxASSERT( end <= (int)treeletRoots.size() );

    int nNodes = end - start;

    if( nNodes == 1 )
        return treeletRoots[start];


    (*totalNodes)++;

    BVHBuildNode *node = static_cast<BVHBuildNode *>( _mm_malloc( sizeof( BVHBuildNode ),
                                                                  L1_CACHE_LINE_SIZE ) );

    m_addresses_pointer_to_mm_free.push_back( node );

    node->bounds.Reset();
    node->firstPrimOffset = 0;
    node->nPrimitives = 0;
    node->splitAxis = 0;
    node->children[0] = NULL;
    node->children[1] = NULL;

    // Compute bounds of all nodes under this HLBVH node
    CBBOX bounds;
    bounds.Reset();

    for( int i = start; i < end; ++i )
        bounds.Union( treeletRoots[i]->bounds );

    // Compute bound of HLBVH node centroids, choose split dimension _dim_
    CBBOX centroidBounds;
    centroidBounds.Reset();

    for( int i = start; i < end; ++i )
    {
        SFVEC3F centroid =
            (treeletRoots[i]->bounds.Min() + treeletRoots[i]->bounds.Max()) *
            0.5f;

        centroidBounds.Union(centroid);
    }

    const int dim = centroidBounds.MaxDimension();

    // FIXME: if this hits, what do we need to do?
    // Make sure the SAH split below does something... ?
    wxASSERT( centroidBounds.Max()[dim] != centroidBounds.Min()[dim] );

    // Allocate _BucketInfo_ for SAH partition buckets
    const int nBuckets = 12;

    BucketInfo buckets[nBuckets];

    for( int i = 0; i < nBuckets; ++i )
    {
        buckets[i].count = 0;
        buckets[i].bounds.Reset();
    }

    // Initialize _BucketInfo_ for HLBVH SAH partition buckets
    for( int i = start; i < end; ++i )
    {
        const float centroid = ( treeletRoots[i]->bounds.Min()[dim] +
                                 treeletRoots[i]->bounds.Max()[dim] ) *
                                 0.5f;
        int b =
            nBuckets * ( (centroid - centroidBounds.Min()[dim] ) /
                         (centroidBounds.Max()[dim] - centroidBounds.Min()[dim] ) );

        if( b == nBuckets )
            b = nBuckets - 1;

        wxASSERT( (b >= 0) && (b < nBuckets) );

        buckets[b].count++;
        buckets[b].bounds.Union( treeletRoots[i]->bounds );
    }

    // Compute costs for splitting after each bucket
    float cost[nBuckets - 1];

    for( int i = 0; i < nBuckets - 1; ++i )
    {
        CBBOX b0, b1;
        b0.Reset();
        b1.Reset();

        int count0 = 0, count1 = 0;

        for( int j = 0; j <= i; ++j )
        {
            if( buckets[j].count )
            {
                count0 += buckets[j].count;
                b0.Union( buckets[j].bounds );
            }
        }

        for( int j = i + 1; j < nBuckets; ++j )
        {
            if( buckets[j].count )
            {
                count1 += buckets[j].count;
                b1.Union( buckets[j].bounds );
            }
        }

        cost[i] = .125f +
                  ( count0 * b0.SurfaceArea() + count1 * b1.SurfaceArea() ) /
                  bounds.SurfaceArea();
    }

    // Find bucket to split at that minimizes SAH metric
    float minCost = cost[0];
    int minCostSplitBucket = 0;

    for( int i = 1; i < nBuckets - 1; ++i )
    {
        if( cost[i] < minCost )
        {
            minCost = cost[i];
            minCostSplitBucket = i;
        }
    }

    // Split nodes and create interior HLBVH SAH node
    BVHBuildNode **pmid = std::partition( &treeletRoots[start],
                                          &treeletRoots[end - 1] + 1,
                                          HLBVH_SAH_Evaluator( minCostSplitBucket,
                                                               nBuckets,
                                                               dim,
                                                               centroidBounds ) );

    const int mid = pmid - &treeletRoots[0];

    wxASSERT( (mid > start) && (mid < end) );

    node->InitInterior( dim,
                        buildUpperSAH( treeletRoots, start, mid, totalNodes ),
                        buildUpperSAH( treeletRoots, mid,   end, totalNodes ) );

    return node;
}
 BVHPrimitiveInfo( int aPrimitiveNumber, const CBBOX &aBounds ) :
     primitiveNumber( aPrimitiveNumber ),
     bounds( aBounds ),
     centroid( .5f * aBounds.Min() + .5f * aBounds.Max() ) {}
BVHBuildNode *CBVH_PBRT::emitLBVH(
        BVHBuildNode *&buildNodes,
        const std::vector<BVHPrimitiveInfo> &primitiveInfo,
        MortonPrimitive *mortonPrims, int nPrimitives, int *totalNodes,
        CONST_VECTOR_OBJECT &orderedPrims,
        int *orderedPrimsOffset, int bit)
{
    wxASSERT( nPrimitives > 0 );
    wxASSERT( totalNodes != NULL );
    wxASSERT( orderedPrimsOffset != NULL );
    wxASSERT( nPrimitives > 0 );
    wxASSERT( mortonPrims != NULL );

    if( (bit == -1) || (nPrimitives < m_maxPrimsInNode) )
    {
        // Create and return leaf node of LBVH treelet
        (*totalNodes)++;

        BVHBuildNode *node = buildNodes++;
        CBBOX bounds;
        bounds.Reset();

        int firstPrimOffset = *orderedPrimsOffset;
        *orderedPrimsOffset += nPrimitives;

        wxASSERT( (firstPrimOffset + (nPrimitives - 1)) < (int)orderedPrims.size() );

        for( int i = 0; i < nPrimitives; ++i )
        {
            const int primitiveIndex = mortonPrims[i].primitiveIndex;

            wxASSERT( primitiveIndex < (int)m_primitives.size() );

            orderedPrims[firstPrimOffset + i] = m_primitives[primitiveIndex];
            bounds.Union( primitiveInfo[primitiveIndex].bounds );
        }

        node->InitLeaf( firstPrimOffset, nPrimitives, bounds );

        return node;
    }
    else
    {
        int mask = 1 << bit;

        // Advance to next subtree level if there's no LBVH split for this bit
        if( (mortonPrims[0].mortonCode & mask) ==
            (mortonPrims[nPrimitives - 1].mortonCode & mask) )
            return emitLBVH( buildNodes, primitiveInfo, mortonPrims, nPrimitives,
                             totalNodes, orderedPrims, orderedPrimsOffset,
                             bit - 1 );

        // Find LBVH split point for this dimension
        int searchStart = 0;
        int searchEnd = nPrimitives - 1;

        while( searchStart + 1 != searchEnd )
        {
            wxASSERT(searchStart != searchEnd);

            const int mid = (searchStart + searchEnd) / 2;

            if( (mortonPrims[searchStart].mortonCode & mask) ==
                (mortonPrims[mid].mortonCode & mask) )
                searchStart = mid;
            else
            {
                wxASSERT( (mortonPrims[mid].mortonCode & mask) ==
                          (mortonPrims[searchEnd].mortonCode & mask) );
                searchEnd = mid;
            }
        }

        const int splitOffset = searchEnd;

        wxASSERT( splitOffset <= (nPrimitives - 1) );
        wxASSERT( (mortonPrims[splitOffset - 1].mortonCode & mask) !=
                  (mortonPrims[splitOffset].mortonCode & mask) );

        // Create and return interior LBVH node
        (*totalNodes)++;

        BVHBuildNode *node = buildNodes++;
        BVHBuildNode *lbvh[2];

       lbvh[0] = emitLBVH( buildNodes, primitiveInfo, mortonPrims, splitOffset,
                     totalNodes, orderedPrims, orderedPrimsOffset, bit - 1 );

       lbvh[1] = emitLBVH( buildNodes, primitiveInfo, &mortonPrims[splitOffset],
                     nPrimitives - splitOffset, totalNodes, orderedPrims,
                     orderedPrimsOffset, bit - 1 );

        const int axis = bit % 3;

        node->InitInterior( axis, lbvh[0], lbvh[1] );

        return node;
    }
}
BVHBuildNode *CBVH_PBRT::HLBVHBuild( const std::vector<BVHPrimitiveInfo> &primitiveInfo,
                                     int *totalNodes,
                                     CONST_VECTOR_OBJECT &orderedPrims )
{
    // Compute bounding box of all primitive centroids
    CBBOX bounds;
    bounds.Reset();

    for( unsigned int i = 0; i < primitiveInfo.size(); ++i )
        bounds.Union( primitiveInfo[i].centroid );

    // Compute Morton indices of primitives
    std::vector<MortonPrimitive> mortonPrims( primitiveInfo.size() );

    for( int i = 0; i < (int)primitiveInfo.size(); ++i )
    {
        // Initialize _mortonPrims[i]_ for _i_th primitive
        const int mortonBits  = 10;
        const int mortonScale = 1 << mortonBits;

        wxASSERT( primitiveInfo[i].primitiveNumber < (int)primitiveInfo.size() );

        mortonPrims[i].primitiveIndex = primitiveInfo[i].primitiveNumber;

        const SFVEC3F centroidOffset = bounds.Offset( primitiveInfo[i].centroid );

        wxASSERT( (centroidOffset.x >= 0.0f) && (centroidOffset.x <= 1.0f) );
        wxASSERT( (centroidOffset.y >= 0.0f) && (centroidOffset.y <= 1.0f) );
        wxASSERT( (centroidOffset.z >= 0.0f) && (centroidOffset.z <= 1.0f) );

        mortonPrims[i].mortonCode = EncodeMorton3( centroidOffset *
                                                   SFVEC3F( (float)mortonScale ) );
    }

    // Radix sort primitive Morton indices
    RadixSort( &mortonPrims );

    // Create LBVH treelets at bottom of BVH

    // Find intervals of primitives for each treelet
    std::vector<LBVHTreelet> treeletsToBuild;

    for( int start = 0, end = 1; end <= (int)mortonPrims.size(); ++end )
    {
        const uint32_t mask = 0b00111111111111000000000000000000;

        if( (end == (int)mortonPrims.size()) ||
            ( (mortonPrims[start].mortonCode & mask) !=
              (mortonPrims[end].mortonCode & mask) ) )
        {
            // Add entry to _treeletsToBuild_ for this treelet
            const int numPrimitives = end - start;
            const int maxBVHNodes = 2 * numPrimitives;

            // !TODO: implement a memory arena
            BVHBuildNode *nodes = static_cast<BVHBuildNode *>( _mm_malloc( maxBVHNodes *
                                                                           sizeof( BVHBuildNode ),
                                                                           L1_CACHE_LINE_SIZE ) );

            m_addresses_pointer_to_mm_free.push_back( nodes );

            for( int i = 0; i < maxBVHNodes; ++i )
            {
                nodes[i].bounds.Reset();
                nodes[i].firstPrimOffset = 0;
                nodes[i].nPrimitives = 0;
                nodes[i].splitAxis = 0;
                nodes[i].children[0] = NULL;
                nodes[i].children[1] = NULL;
            }

            LBVHTreelet tmpTreelet;

            tmpTreelet.startIndex = start;
            tmpTreelet.numPrimitives = numPrimitives;
            tmpTreelet.buildNodes = nodes;

            treeletsToBuild.push_back( tmpTreelet );

            start = end;
        }
    }

    // Create LBVHs for treelets in parallel
    int atomicTotal = 0;
    int orderedPrimsOffset = 0;

    orderedPrims.resize( m_primitives.size() );

    for( int index = 0; index < (int)treeletsToBuild.size(); ++index )
    {
        // Generate _index_th LBVH treelet
        int nodesCreated = 0;
        const int firstBit = 29 - 12;

        LBVHTreelet &tr = treeletsToBuild[index];

        wxASSERT( tr.startIndex < (int)mortonPrims.size() );

        tr.buildNodes = emitLBVH( tr.buildNodes,
                                  primitiveInfo,
                                  &mortonPrims[tr.startIndex],
                                  tr.numPrimitives,
                                  &nodesCreated,
                                  orderedPrims,
                                  &orderedPrimsOffset,
                                  firstBit );

        atomicTotal += nodesCreated;
    }

    *totalNodes = atomicTotal;

    // Initialize _finishedTreelets_ with treelet root node pointers
    std::vector<BVHBuildNode *> finishedTreelets;
    finishedTreelets.reserve( treeletsToBuild.size() );

    for( int index = 0; index < (int)treeletsToBuild.size(); ++index )
        finishedTreelets.push_back( treeletsToBuild[index].buildNodes );

    // Create and return SAH BVH from LBVH treelets
    return buildUpperSAH( finishedTreelets,
                          0,
                          finishedTreelets.size(),
                          totalNodes );
}
BVHBuildNode *CBVH_PBRT::recursiveBuild ( std::vector<BVHPrimitiveInfo> &primitiveInfo,
                                          int start,
                                          int end,
                                          int *totalNodes,
                                          CONST_VECTOR_OBJECT &orderedPrims )
{
    wxASSERT( totalNodes != NULL );
    wxASSERT( start >= 0 );
    wxASSERT( end   >= 0 );
    wxASSERT( start != end );
    wxASSERT( start < end );
    wxASSERT( start <= (int)primitiveInfo.size() );
    wxASSERT( end   <= (int)primitiveInfo.size() );

    (*totalNodes)++;

    // !TODO: implement an memory Arena
    BVHBuildNode *node = static_cast<BVHBuildNode *>( _mm_malloc( sizeof( BVHBuildNode ),
                                                                  L1_CACHE_LINE_SIZE ) );
    m_addresses_pointer_to_mm_free.push_back( node );

    node->bounds.Reset();
    node->firstPrimOffset = 0;
    node->nPrimitives = 0;
    node->splitAxis = 0;
    node->children[0] = NULL;
    node->children[1] = NULL;

    // Compute bounds of all primitives in BVH node
    CBBOX bounds;
    bounds.Reset();

    for( int i = start; i < end; ++i )
        bounds.Union( primitiveInfo[i].bounds );

    int nPrimitives = end - start;

    if( nPrimitives == 1 )
    {
        // Create leaf _BVHBuildNode_
        int firstPrimOffset = orderedPrims.size();

        for( int i = start; i < end; ++i )
        {
            int primitiveNr = primitiveInfo[i].primitiveNumber;
            wxASSERT( primitiveNr < (int)m_primitives.size() );
            orderedPrims.push_back( m_primitives[ primitiveNr ] );
        }

        node->InitLeaf( firstPrimOffset, nPrimitives, bounds );
    }
    else
    {
        // Compute bound of primitive centroids, choose split dimension _dim_
        CBBOX centroidBounds;
        centroidBounds.Reset();

        for( int i = start; i < end; ++i )
            centroidBounds.Union( primitiveInfo[i].centroid );

        const int dim = centroidBounds.MaxDimension();

        // Partition primitives into two sets and build children
        int mid = (start + end) / 2;

        if( fabs( centroidBounds.Max()[dim] -
                  centroidBounds.Min()[dim] ) < (FLT_EPSILON + FLT_EPSILON) )
        {
            // Create leaf _BVHBuildNode_
            const int firstPrimOffset = orderedPrims.size();

            for( int i = start; i < end; ++i )
            {
                int primitiveNr = primitiveInfo[i].primitiveNumber;

                wxASSERT( (primitiveNr >= 0) &&
                          (primitiveNr < (int)m_primitives.size()) );

                const COBJECT *obj = static_cast<const COBJECT *>( m_primitives[ primitiveNr ] );

                wxASSERT( obj != NULL );

                orderedPrims.push_back( obj );
            }

            node->InitLeaf( firstPrimOffset, nPrimitives, bounds );
        }
        else
        {
            // Partition primitives based on _splitMethod_
            switch( m_splitMethod )
            {
            case SPLIT_MIDDLE:
            {
                // Partition primitives through node's midpoint
                float pmid = centroidBounds.GetCenter( dim );

                BVHPrimitiveInfo *midPtr = std::partition( &primitiveInfo[start],
                                                           &primitiveInfo[end - 1] + 1,
                                                           CompareToMid( dim, pmid ) );
                mid = midPtr - &primitiveInfo[0];

                wxASSERT( (mid >= start) &&
                          (mid <= end) );

                if( (mid != start) && (mid != end) )
                    // for lots of prims with large overlapping bounding boxes, this
                    // may fail to partition; in that case don't break and fall through
                    // to SPLIT_EQUAL_COUNTS
                    break;
            }

            case SPLIT_EQUALCOUNTS:
            {
                // Partition primitives into equally-sized subsets
                mid = (start + end) / 2;

                std::nth_element( &primitiveInfo[start],
                                  &primitiveInfo[mid],
                                  &primitiveInfo[end - 1] + 1,
                                  ComparePoints( dim ) );

                break;
            }

            case SPLIT_SAH:
            default:
            {
                // Partition primitives using approximate SAH
                if( nPrimitives <= 2 )
                {
                    // Partition primitives into equally-sized subsets
                    mid = (start + end) / 2;

                    std::nth_element( &primitiveInfo[start],
                                      &primitiveInfo[mid],
                                      &primitiveInfo[end - 1] + 1,
                                      ComparePoints( dim ) );
                }
                else
                {
                    // Allocate _BucketInfo_ for SAH partition buckets
                    const int nBuckets = 12;

                    BucketInfo buckets[nBuckets];

                    for( int i = 0; i < nBuckets; ++i )
                    {
                        buckets[i].count = 0;
                        buckets[i].bounds.Reset();
                    }

                    // Initialize _BucketInfo_ for SAH partition buckets
                    for( int i = start; i < end; ++i )
                    {
                        int b = nBuckets *
                                centroidBounds.Offset( primitiveInfo[i].centroid )[dim];

                        if( b == nBuckets )
                            b = nBuckets - 1;

                        wxASSERT( b >= 0 && b < nBuckets );

                        buckets[b].count++;
                        buckets[b].bounds.Union( primitiveInfo[i].bounds );
                    }

                    // Compute costs for splitting after each bucket
                    float cost[nBuckets - 1];

                    for( int i = 0; i < (nBuckets - 1); ++i )
                    {
                        CBBOX b0, b1;

                        b0.Reset();
                        b1.Reset();

                        int count0 = 0;
                        int count1 = 0;

                        for( int j = 0; j <= i; ++j )
                        {
                            if( buckets[j].count )
                            {
                                count0 += buckets[j].count;
                                b0.Union( buckets[j].bounds );
                            }
                        }

                        for( int j = i + 1; j < nBuckets; ++j )
                        {
                            if( buckets[j].count )
                            {
                                count1 += buckets[j].count;
                                b1.Union( buckets[j].bounds );
                            }
                        }

                        cost[i] = 1.0f +
                                  ( count0 * b0.SurfaceArea() +
                                    count1 * b1.SurfaceArea() ) /
                                  bounds.SurfaceArea();
                    }

                    // Find bucket to split at that minimizes SAH metric
                    float minCost = cost[0];
                    int minCostSplitBucket = 0;

                    for( int i = 1; i < (nBuckets - 1); ++i )
                    {
                        if( cost[i] < minCost )
                        {
                            minCost = cost[i];
                            minCostSplitBucket = i;
                        }
                    }

                    // Either create leaf or split primitives at selected SAH
                    // bucket
                    if( (nPrimitives > m_maxPrimsInNode) ||
                        (minCost < (float)nPrimitives) )
                    {
                        BVHPrimitiveInfo *pmid =
                            std::partition( &primitiveInfo[start],
                                            &primitiveInfo[end - 1] + 1,
                                            CompareToBucket( minCostSplitBucket,
                                                             nBuckets,
                                                             dim,
                                                             centroidBounds ) );
                        mid = pmid - &primitiveInfo[0];

                        wxASSERT( (mid >= start) &&
                                  (mid <= end) );
                    }
                    else
                    {
                        // Create leaf _BVHBuildNode_
                        const int firstPrimOffset = orderedPrims.size();

                        for( int i = start; i < end; ++i )
                        {
                            const int primitiveNr = primitiveInfo[i].primitiveNumber;

                            wxASSERT( primitiveNr < (int)m_primitives.size() );

                            orderedPrims.push_back( m_primitives[ primitiveNr ] );
                        }

                        node->InitLeaf( firstPrimOffset, nPrimitives, bounds );

                        return node;
                    }
                }
                break;
            }
            }

            node->InitInterior( dim,
                                recursiveBuild( primitiveInfo,
                                                start,
                                                mid,
                                                totalNodes,
                                                orderedPrims ),
                                recursiveBuild( primitiveInfo,
                                                mid,
                                                end,
                                                totalNodes,
                                                orderedPrims) );
        }
    }

    return node;
}
Beispiel #8
0
void EDA_3D_CANVAS::calcBBox()
{
    BOARD* pcb = GetBoard();

    m_fastAABBox.Reset();

    for( MODULE* module = pcb->m_Modules; module; module = module->Next() )
    {
        CBBOX tmpFastAABBox;

        // Compute the transformation matrix for this module based on translation, rotation and orientation.
        float  zpos = GetPrm3DVisu().GetModulesZcoord3DIU( module->IsFlipped() );
        wxPoint pos = module->GetPosition();

        glm::mat4 fullTransformMatrix;
        fullTransformMatrix = glm::translate( glm::mat4(),  S3D_VERTEX( (float)(pos.x * GetPrm3DVisu().m_BiuTo3Dunits),
                                                                        (float)(-pos.y * GetPrm3DVisu().m_BiuTo3Dunits),
                                                                        zpos ) );

        if( module->GetOrientation() )
            fullTransformMatrix = glm::rotate( fullTransformMatrix,
                                               glm::radians( (float)(module->GetOrientation() / 10.0f) ),
                                               S3D_VERTEX( 0.0f, 0.0f, 1.0f ) );

        if( module->IsFlipped() )
        {
            fullTransformMatrix = glm::rotate( fullTransformMatrix, glm::radians( 180.0f ), S3D_VERTEX( 0.0f, 1.0f, 0.0f ) );
            fullTransformMatrix = glm::rotate( fullTransformMatrix, glm::radians( 180.0f ), S3D_VERTEX( 0.0f, 0.0f, 1.0f ) );
        }

        // Compute a union bounding box for all the shapes of the model

        S3D_MASTER* shape3D = module->Models();

        for( ; shape3D; shape3D = shape3D->Next() )
        {
            if( shape3D->Is3DType( S3D_MASTER::FILE3D_VRML ) )
                tmpFastAABBox.Union( shape3D->getFastAABBox() );
        }

        tmpFastAABBox.ApplyTransformationAA( fullTransformMatrix );

        m_fastAABBox.Union( tmpFastAABBox );
    }

    // Create a board bounding box based on board size
    wxSize  brd_size = getBoardSize();
    wxPoint brd_center_pos = getBoardCenter();

    float xsize   = brd_size.x;
    float ysize   = brd_size.y;

    float scale   = GetPrm3DVisu().m_BiuTo3Dunits;
    float xmin    = (brd_center_pos.x - xsize / 2.0) * scale;
    float xmax    = (brd_center_pos.x + xsize / 2.0) * scale;
    float ymin    = (brd_center_pos.y - ysize / 2.0) * scale;
    float ymax    = (brd_center_pos.y + ysize / 2.0) * scale;

    float zmin = GetPrm3DVisu().GetLayerZcoordBIU( B_Adhes ) * scale;
    float zmax = GetPrm3DVisu().GetLayerZcoordBIU( F_Adhes ) * scale;

    m_boardAABBox = CBBOX(  S3D_VERTEX(xmin, ymin, zmin),
                            S3D_VERTEX(xmax, ymax, zmax) );

    // Add BB board with BB models and scale it a bit
    m_fastAABBox.Union( m_boardAABBox );
    m_fastAABBox_Shadow = m_fastAABBox;
    m_fastAABBox_Shadow.Scale( SHADOW_BOUNDING_BOX_SCALE );
}