source: trunk/src/gl/texture_atlas.cc @ 24

Last change on this file since 24 was 13, checked in by epyon, 12 years ago
  • pure image functionality of texture_atlas split into image clas
File size: 2.8 KB
Line 
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
7#include "nv/gl/texture_atlas.hh"
8
9#include "nv/logging.hh"
10
11using namespace nv;
12
13texture_atlas::texture_atlas( glm::ivec2 size, size_t depth )
14        : image( size, depth ), m_used( 0 )
15{
16        m_nodes.push_back( glm::ivec3( 1, 1, m_size.x - 2 ) );
17        fill( 0 );
18}
19
20region texture_atlas::get_region( glm::ivec2 size )
21{
22        region r ( glm::ivec2(0,0), size );
23    size_t i;
24
25    int best_height = INT_MAX;
26    int best_index  = -1;
27    int best_width  = INT_MAX;
28        for( size_t i=0; i < m_nodes.size(); ++i )
29        {
30        int y = fit( i, size );
31                if( y >= 0 )
32                {
33            glm::ivec3 node = m_nodes[ i ];
34                        if ( ( (y + size.y) < best_height ) ||
35                ( ((y + size.y) == best_height) && (node.z < best_width)) )
36                        {
37                                best_height = y + size.y;
38                                best_index = i;
39                                best_width = node.z;
40                                r.pos.x = node.x;
41                                r.pos.y = y;
42                        }
43        }
44    }
45   
46        if( best_index == -1 )
47    {
48        return region( glm::ivec2( -1, -1 ), glm::ivec2( 0, 0 ) );
49    }
50
51    m_nodes.insert( m_nodes.begin() + best_index, glm::ivec3( r.pos.x, r.pos.y + size.y, size.x ) );
52
53    for( size_t i = best_index+1; i < m_nodes.size(); ++i )
54    {
55        glm::ivec3 node = m_nodes[ i ];
56        glm::ivec3 prev = m_nodes[ i-1 ];
57
58        if (node.x < (prev.x + prev.z) )
59        {
60            int shrink = prev.x + prev.z - node.x;
61                        m_nodes[ i ].x += shrink;
62                        m_nodes[ i ].z -= shrink;
63
64            if (m_nodes[ i ].z <= 0)
65            {
66                                m_nodes.erase( m_nodes.begin() + i );
67                --i;
68            }
69            else
70            {
71                break;
72            }
73        }
74        else
75        {
76            break;
77        }
78    }
79    merge();
80    m_used += size.x * size.y;
81    return r;
82}
83
84int texture_atlas::fit( size_t index, glm::ivec2 size )
85{
86        glm::ivec3 node = m_nodes[ index ];
87
88        if ( (  node.x + size.x ) > ( m_size.x - 1 ) )
89        {
90                return -1;
91        }
92
93        int y     = node.y;
94        int wleft = size.x;
95        size_t i  = index;
96
97        while( wleft > 0 )
98        {
99        node = m_nodes[ i ];
100        if( node.y > y )
101        {
102            y = node.y;
103        }
104                if( (y + size.y) > (m_size.y-1) )
105        {
106                        return -1;
107        }
108                wleft -= node.z;
109                ++i;
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            m_nodes.erase( m_nodes.begin()+i+1 );
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.