source: trunk/src/gfx/texture_atlas.cc @ 142

Last change on this file since 142 was 142, checked in by epyon, 12 years ago
  • texture_atlas - optionally takes a border parameter (default 1)
  • texture_atlas - TODO: fix behavior for exact fits (10242 atlas only holds 9 2562 images...)
  • mesh - get_attribute fixed
File size: 2.7 KB
RevLine 
[11]1// Copyright (C) 2012-2013 ChaosForge / Kornel Kisielewicz
2// http://chaosforge.org/
3//
4// This file is part of NV Libraries.
5// For conditions of distribution and use, see copyright notice in nv.hh
6
[89]7#include "nv/gfx/texture_atlas.hh"
[11]8
[13]9#include "nv/logging.hh"
[28]10#include <iostream>
[13]11
[11]12using namespace nv;
13
[142]14texture_atlas::texture_atlas( glm::ivec2 size, size_t depth, size_t border /*= 1*/ )
[13]15        : image( size, depth ), m_used( 0 )
[11]16{
[142]17        m_nodes.push_back( glm::ivec3( border, border, m_size.x - 2 * border ) );
[11]18        fill( 0 );
19}
20
[13]21region texture_atlas::get_region( glm::ivec2 size )
[11]22{
[13]23        region r ( glm::ivec2(0,0), size );
[11]24
[27]25        int best_height = INT_MAX;
26        int best_index  = -1;
27        int best_width  = INT_MAX;
[29]28
[11]29        for( size_t i=0; i < m_nodes.size(); ++i )
30        {
[27]31                int y = fit( i, size );
[11]32                if( y >= 0 )
33                {
[27]34                        glm::ivec3 node = m_nodes[ i ];
[11]35                        if ( ( (y + size.y) < best_height ) ||
[27]36                                ( ((y + size.y) == best_height) && (node.z < best_width)) )
[11]37                        {
38                                best_height = y + size.y;
[121]39                                best_index = static_cast<int>( i );
[11]40                                best_width = node.z;
[13]41                                r.pos.x = node.x;
42                                r.pos.y = y;
[11]43                        }
[27]44                }
45        }
[11]46   
[27]47        if ( best_index == -1 )
48        {
49                return region( glm::ivec2( -1, -1 ), glm::ivec2( 0, 0 ) );
50        }
[11]51
[27]52        m_nodes.insert( m_nodes.begin() + best_index, glm::ivec3( r.pos.x, r.pos.y + size.y, size.x ) );
[11]53
[121]54        for( size_t i = static_cast<size_t>( best_index )+1; i < m_nodes.size(); ++i )
[27]55        {
56                glm::ivec3 node = m_nodes[ i ];
57                glm::ivec3 prev = m_nodes[ i-1 ];
[11]58
[27]59                if (node.x < (prev.x + prev.z) )
60                {
61                        int shrink = prev.x + prev.z - node.x;
[11]62                        m_nodes[ i ].x += shrink;
63                        m_nodes[ i ].z -= shrink;
64
[27]65                        if (m_nodes[ i ].z <= 0)
66                        {
[121]67                                m_nodes.erase( m_nodes.begin() + static_cast<int>(i) );
[27]68                                --i;
69                        }
70                        else
71                        {
72                                break;
73                        }
74                }
75                else
76                {
77                        break;
78                }
79        }
80        merge();
[142]81        m_used += static_cast<uint32>(size.x * size.y);
[27]82        return r;
[11]83}
84
85int texture_atlas::fit( size_t index, glm::ivec2 size )
86{
87        glm::ivec3 node = m_nodes[ index ];
88
89        if ( (  node.x + size.x ) > ( m_size.x - 1 ) )
90        {
91                return -1;
92        }
93
94        int y     = node.y;
95        int wleft = size.x;
96
97        while( wleft > 0 )
98        {
[27]99                node = m_nodes[ index ];
100                if( node.y > y )
101                {
102                        y = node.y;
103                }
[11]104                if( (y + size.y) > (m_size.y-1) )
[27]105                {
[11]106                        return -1;
[27]107                }
[11]108                wleft -= node.z;
[27]109                ++index;
[11]110        }
111        return y;
112}
113
114void texture_atlas::merge()
115{
116        for( size_t i=0; i < m_nodes.size()-1; ++i )
117    {
118                if( m_nodes[ i ].y == m_nodes[ i+1 ].y )
119                {
120                        m_nodes[ i ].z += m_nodes[ i+1 ].z;
[121]121            m_nodes.erase( m_nodes.begin()+static_cast<int>(i+1) );
[11]122                        --i;
123                }
124    }
125}
126
127void texture_atlas::clear()
128{
129        m_nodes.clear();
130        m_used = 0;
131        m_nodes.push_back( glm::ivec3( 1, 1, m_size.x - 2 ) );
132        fill( 0 );
133}
Note: See TracBrowser for help on using the repository browser.