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

Last change on this file since 11 was 11, checked in by epyon, 12 years ago
  • common.hh - supression of C4201 warning under MSVC (nameless unions)
  • texture_atlas.hh/.cc - texture atlases based on "A Thousand Ways to Pack the Bin - A Practical Approach to Two-Dimensional Rectangle Bin Packing"
File size: 3.3 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
7#include "nv/gl/texture_atlas.hh"
8
9using namespace nv;
10
11texture_atlas::texture_atlas( glm::ivec2 size, size_t depth )
12        : m_size( size ), m_depth( depth ), m_used( 0 ), m_data( nullptr )
13{
14        m_nodes.push_back( glm::ivec3( 1, 1, m_size.x - 2 ) );
15        m_data = new uint8[ m_size.x * m_size.y * m_depth ];
16        fill( 0 );
17}
18
19glm::ivec4 texture_atlas::get_region( glm::ivec2 size )
20{
21        glm::ivec4 region (0,0,size.x,size.y);
22    size_t i;
23
24    int best_height = INT_MAX;
25    int best_index  = -1;
26    int best_width  = INT_MAX;
27        for( size_t i=0; i < m_nodes.size(); ++i )
28        {
29        int y = fit( i, size );
30                if( y >= 0 )
31                {
32            glm::ivec3 node = m_nodes[ i ];
33                        if ( ( (y + size.y) < best_height ) ||
34                ( ((y + size.y) == best_height) && (node.z < best_width)) )
35                        {
36                                best_height = y + size.y;
37                                best_index = i;
38                                best_width = node.z;
39                                region.x = node.x;
40                                region.y = y;
41                        }
42        }
43    }
44   
45        if( best_index == -1 )
46    {
47        return glm::ivec4( -1, -1, 0, 0 );
48    }
49
50    m_nodes.insert( m_nodes.begin() + best_index, glm::ivec3( region.x, region.y + size.y, size.x ) );
51
52    for( size_t i = best_index+1; i < m_nodes.size(); ++i )
53    {
54        glm::ivec3 node = m_nodes[ i ];
55        glm::ivec3 prev = m_nodes[ i-1 ];
56
57        if (node.x < (prev.x + prev.z) )
58        {
59            int shrink = prev.x + prev.z - node.x;
60                        m_nodes[ i ].x += shrink;
61                        m_nodes[ i ].z -= shrink;
62
63            if (m_nodes[ i ].z <= 0)
64            {
65                                m_nodes.erase( m_nodes.begin() + i );
66                --i;
67            }
68            else
69            {
70                break;
71            }
72        }
73        else
74        {
75            break;
76        }
77    }
78    merge();
79    m_used += size.x * size.y;
80    return region;
81}
82
83void texture_atlas::set_region( glm::ivec4 region, const uint8 * data, size_t stride )
84{
85    for( size_t i = 0; i < region[3]; ++i )
86    {
87        memcpy( m_data+((region.y+i)*m_size.x + region.x ) * m_depth,
88                data + (i*stride), m_size.x * m_depth );
89    }
90}
91
92int texture_atlas::fit( size_t index, glm::ivec2 size )
93{
94        glm::ivec3 node = m_nodes[ index ];
95
96        if ( (  node.x + size.x ) > ( m_size.x - 1 ) )
97        {
98                return -1;
99        }
100
101        int y     = node.y;
102        int wleft = size.x;
103        size_t i  = index;
104
105        while( wleft > 0 )
106        {
107        node = m_nodes[ i ];
108        if( node.y > y )
109        {
110            y = node.y;
111        }
112                if( (y + size.y) > (m_size.y-1) )
113        {
114                        return -1;
115        }
116                wleft -= node.z;
117                ++i;
118        }
119        return y;
120}
121
122void texture_atlas::merge()
123{
124        for( size_t i=0; i < m_nodes.size()-1; ++i )
125    {
126                if( m_nodes[ i ].y == m_nodes[ i+1 ].y )
127                {
128                        m_nodes[ i ].z += m_nodes[ i+1 ].z;
129            m_nodes.erase( m_nodes.begin()+i+1 );
130                        --i;
131                }
132    }
133}
134
135void texture_atlas::clear()
136{
137        m_nodes.clear();
138        m_used = 0;
139        m_nodes.push_back( glm::ivec3( 1, 1, m_size.x - 2 ) );
140        fill( 0 );
141}
142
143void texture_atlas::fill( uint8 value )
144{
145        memset( m_data, value, m_size.x * m_size.y * m_depth );
146}
147
148texture_atlas::~texture_atlas()
149{
150        delete[] m_data;
151}
152
Note: See TracBrowser for help on using the repository browser.