@@ -18,7 +18,7 @@ const ATLAS_TEXTURE_LENGTH: u32 = 1024;
18
18
19
19
#[ derive( Clone , Debug ) ]
20
20
pub struct TextureAllocator {
21
- pages : Vec < TexturePage > ,
21
+ pages : Vec < Option < TexturePage > > ,
22
22
}
23
23
24
24
#[ derive( Clone , Debug ) ]
@@ -71,40 +71,87 @@ impl TextureAllocator {
71
71
}
72
72
73
73
// Try to add to each atlas.
74
+ let mut first_free_page_index = self . pages . len ( ) ;
74
75
for ( page_index, page) in self . pages . iter_mut ( ) . enumerate ( ) {
75
- match page. allocator {
76
- TexturePageAllocator :: Image { .. } => { }
77
- TexturePageAllocator :: Atlas ( ref mut allocator) => {
78
- if let Some ( rect) = allocator. allocate ( requested_size) {
79
- return TextureLocation { page : TexturePageId ( page_index as u32 ) , rect } ;
76
+ match * page {
77
+ Some ( ref mut page) => {
78
+ match page. allocator {
79
+ TexturePageAllocator :: Image { .. } => { }
80
+ TexturePageAllocator :: Atlas ( ref mut allocator) => {
81
+ if let Some ( rect) = allocator. allocate ( requested_size) {
82
+ return TextureLocation {
83
+ page : TexturePageId ( page_index as u32 ) ,
84
+ rect
85
+ } ;
86
+ }
87
+ }
80
88
}
81
89
}
90
+ None => first_free_page_index = first_free_page_index. min ( page_index) ,
82
91
}
83
92
}
84
93
85
94
// Add a new atlas.
86
- let page = TexturePageId ( self . pages . len ( ) as u32 ) ;
95
+ let page = self . get_first_free_page_id ( ) ;
87
96
let mut allocator = TextureAtlasAllocator :: new ( ) ;
88
97
let rect = allocator. allocate ( requested_size) . expect ( "Allocation failed!" ) ;
89
- self . pages . push ( TexturePage {
98
+ while ( page. 0 as usize ) >= self . pages . len ( ) {
99
+ self . pages . push ( None ) ;
100
+ }
101
+ self . pages [ page. 0 as usize ] = Some ( TexturePage {
90
102
is_new : true ,
91
103
allocator : TexturePageAllocator :: Atlas ( allocator) ,
92
104
} ) ;
93
105
TextureLocation { page, rect }
94
106
}
95
107
96
108
pub fn allocate_image ( & mut self , requested_size : Vector2I ) -> TextureLocation {
97
- let page = TexturePageId ( self . pages . len ( ) as u32 ) ;
109
+ let page = self . get_first_free_page_id ( ) ;
98
110
let rect = RectI :: new ( Vector2I :: default ( ) , requested_size) ;
99
- self . pages . push ( TexturePage {
111
+ while ( page. 0 as usize ) >= self . pages . len ( ) {
112
+ self . pages . push ( None ) ;
113
+ }
114
+ self . pages [ page. 0 as usize ] = Some ( TexturePage {
100
115
is_new : true ,
101
116
allocator : TexturePageAllocator :: Image { size : rect. size ( ) } ,
102
117
} ) ;
103
118
TextureLocation { page, rect }
104
119
}
105
120
121
+ fn get_first_free_page_id ( & self ) -> TexturePageId {
122
+ for ( page_index, page) in self . pages . iter ( ) . enumerate ( ) {
123
+ if page. is_none ( ) {
124
+ return TexturePageId ( page_index as u32 ) ;
125
+ }
126
+ }
127
+ TexturePageId ( self . pages . len ( ) as u32 )
128
+ }
129
+
130
+ pub fn free ( & mut self , location : TextureLocation ) {
131
+ //println!("free({:?})", location);
132
+ match self . pages [ location. page . 0 as usize ]
133
+ . as_mut ( )
134
+ . expect ( "Texture page is not allocated!" )
135
+ . allocator {
136
+ TexturePageAllocator :: Image { size } => {
137
+ debug_assert_eq ! ( location. rect, RectI :: new( Vector2I :: default ( ) , size) ) ;
138
+ }
139
+ TexturePageAllocator :: Atlas ( ref mut atlas_allocator) => {
140
+ atlas_allocator. free ( location. rect ) ;
141
+ if !atlas_allocator. is_empty ( ) {
142
+ // Keep the page around.
143
+ return ;
144
+ }
145
+ }
146
+ }
147
+
148
+ // If we got here, free the page.
149
+ // TODO(pcwalton): Actually tell the renderer to free this page!
150
+ self . pages [ location. page . 0 as usize ] = None ;
151
+ }
152
+
106
153
pub fn page_size ( & self , page_id : TexturePageId ) -> Vector2I {
107
- match self . pages [ page_id. 0 as usize ] . allocator {
154
+ match self . pages [ page_id. 0 as usize ] . as_ref ( ) . expect ( "No such texture page!" ) . allocator {
108
155
TexturePageAllocator :: Atlas ( ref atlas) => Vector2I :: splat ( atlas. size as i32 ) ,
109
156
TexturePageAllocator :: Image { size, .. } => size,
110
157
}
@@ -115,16 +162,23 @@ impl TextureAllocator {
115
162
}
116
163
117
164
pub fn page_is_new ( & self , page_id : TexturePageId ) -> bool {
118
- self . pages [ page_id. 0 as usize ] . is_new
165
+ self . pages [ page_id. 0 as usize ] . as_ref ( ) . expect ( "No such texture page!" ) . is_new
119
166
}
120
167
121
- pub fn mark_page_as_allocated ( & mut self , page_id : TexturePageId ) {
122
- self . pages [ page_id. 0 as usize ] . is_new = false ;
168
+ pub fn mark_all_pages_as_allocated ( & mut self ) {
169
+ for page in & mut self . pages {
170
+ if let Some ( ref mut page) = * page {
171
+ page. is_new = false ;
172
+ }
173
+ }
123
174
}
124
175
125
- #[ inline]
126
- pub fn page_count ( & self ) -> u32 {
127
- self . pages . len ( ) as u32
176
+ pub fn page_ids ( & self ) -> TexturePageIter {
177
+ let mut first_index = 0 ;
178
+ while first_index < self . pages . len ( ) && self . pages [ first_index] . is_none ( ) {
179
+ first_index += 1 ;
180
+ }
181
+ TexturePageIter { allocator : self , next_index : first_index }
128
182
}
129
183
}
130
184
@@ -147,7 +201,6 @@ impl TextureAtlasAllocator {
147
201
}
148
202
149
203
#[ inline]
150
- #[ allow( dead_code) ]
151
204
fn free ( & mut self , rect : RectI ) {
152
205
let requested_length = rect. width ( ) as u32 ;
153
206
self . root . free ( Vector2I :: default ( ) , self . size , rect. origin ( ) , requested_length)
@@ -285,6 +338,30 @@ impl TreeNode {
285
338
}
286
339
}
287
340
341
+ pub struct TexturePageIter < ' a > {
342
+ allocator : & ' a TextureAllocator ,
343
+ next_index : usize ,
344
+ }
345
+
346
+ impl < ' a > Iterator for TexturePageIter < ' a > {
347
+ type Item = TexturePageId ;
348
+ fn next ( & mut self ) -> Option < TexturePageId > {
349
+ let next_id = if self . next_index >= self . allocator . pages . len ( ) {
350
+ None
351
+ } else {
352
+ Some ( TexturePageId ( self . next_index as u32 ) )
353
+ } ;
354
+ loop {
355
+ self . next_index += 1 ;
356
+ if self . next_index >= self . allocator . pages . len ( ) ||
357
+ self . allocator . pages [ self . next_index as usize ] . is_some ( ) {
358
+ break ;
359
+ }
360
+ }
361
+ next_id
362
+ }
363
+ }
364
+
288
365
#[ cfg( test) ]
289
366
mod test {
290
367
use pathfinder_geometry:: vector:: vec2i;
0 commit comments