diff options
Diffstat (limited to 'libs/cocos2d/CCTextureAtlas.m')
-rwxr-xr-x | libs/cocos2d/CCTextureAtlas.m | 369 |
1 files changed, 369 insertions, 0 deletions
diff --git a/libs/cocos2d/CCTextureAtlas.m b/libs/cocos2d/CCTextureAtlas.m new file mode 100755 index 0000000..7c7df75 --- /dev/null +++ b/libs/cocos2d/CCTextureAtlas.m | |||
@@ -0,0 +1,369 @@ | |||
1 | /* | ||
2 | * cocos2d for iPhone: http://www.cocos2d-iphone.org | ||
3 | * | ||
4 | * Copyright (c) 2008-2010 Ricardo Quesada | ||
5 | * Copyright (c) 2011 Zynga Inc. | ||
6 | * | ||
7 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
8 | * of this software and associated documentation files (the "Software"), to deal | ||
9 | * in the Software without restriction, including without limitation the rights | ||
10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
11 | * copies of the Software, and to permit persons to whom the Software is | ||
12 | * furnished to do so, subject to the following conditions: | ||
13 | * | ||
14 | * The above copyright notice and this permission notice shall be included in | ||
15 | * all copies or substantial portions of the Software. | ||
16 | * | ||
17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
23 | * THE SOFTWARE. | ||
24 | * | ||
25 | */ | ||
26 | |||
27 | |||
28 | // cocos2d | ||
29 | #import "CCTextureAtlas.h" | ||
30 | #import "ccMacros.h" | ||
31 | #import "CCTexture2D.h" | ||
32 | #import "CCTextureCache.h" | ||
33 | |||
34 | |||
35 | @interface CCTextureAtlas (Private) | ||
36 | -(void) initIndices; | ||
37 | @end | ||
38 | |||
39 | //According to some tests GL_TRIANGLE_STRIP is slower, MUCH slower. Probably I'm doing something very wrong | ||
40 | |||
41 | @implementation CCTextureAtlas | ||
42 | |||
43 | @synthesize totalQuads = totalQuads_, capacity = capacity_; | ||
44 | @synthesize texture = texture_; | ||
45 | @synthesize quads = quads_; | ||
46 | |||
47 | #pragma mark TextureAtlas - alloc & init | ||
48 | |||
49 | +(id) textureAtlasWithFile:(NSString*) file capacity: (NSUInteger) n | ||
50 | { | ||
51 | return [[[self alloc] initWithFile:file capacity:n] autorelease]; | ||
52 | } | ||
53 | |||
54 | +(id) textureAtlasWithTexture:(CCTexture2D *)tex capacity:(NSUInteger)n | ||
55 | { | ||
56 | return [[[self alloc] initWithTexture:tex capacity:n] autorelease]; | ||
57 | } | ||
58 | |||
59 | -(id) initWithFile:(NSString*)file capacity:(NSUInteger)n | ||
60 | { | ||
61 | // retained in property | ||
62 | CCTexture2D *tex = [[CCTextureCache sharedTextureCache] addImage:file]; | ||
63 | if( tex ) | ||
64 | return [self initWithTexture:tex capacity:n]; | ||
65 | |||
66 | // else | ||
67 | { | ||
68 | CCLOG(@"cocos2d: Could not open file: %@", file); | ||
69 | [self release]; | ||
70 | return nil; | ||
71 | } | ||
72 | } | ||
73 | |||
74 | -(id) initWithTexture:(CCTexture2D*)tex capacity:(NSUInteger)n | ||
75 | { | ||
76 | if( (self=[super init]) ) { | ||
77 | |||
78 | capacity_ = n; | ||
79 | totalQuads_ = 0; | ||
80 | |||
81 | // retained in property | ||
82 | self.texture = tex; | ||
83 | |||
84 | // Re-initialization is not allowed | ||
85 | NSAssert(quads_==nil && indices_==nil, @"CCTextureAtlas re-initialization is not allowed"); | ||
86 | |||
87 | quads_ = calloc( sizeof(quads_[0]) * capacity_, 1 ); | ||
88 | indices_ = calloc( sizeof(indices_[0]) * capacity_ * 6, 1 ); | ||
89 | |||
90 | if( ! ( quads_ && indices_) ) { | ||
91 | CCLOG(@"cocos2d: CCTextureAtlas: not enough memory"); | ||
92 | if( quads_ ) | ||
93 | free(quads_); | ||
94 | if( indices_ ) | ||
95 | free(indices_); | ||
96 | return nil; | ||
97 | } | ||
98 | |||
99 | #if CC_USES_VBO | ||
100 | // initial binding | ||
101 | glGenBuffers(2, &buffersVBO_[0]); | ||
102 | dirty_ = YES; | ||
103 | #endif // CC_USES_VBO | ||
104 | |||
105 | [self initIndices]; | ||
106 | } | ||
107 | |||
108 | return self; | ||
109 | } | ||
110 | |||
111 | - (NSString*) description | ||
112 | { | ||
113 | return [NSString stringWithFormat:@"<%@ = %08X | totalQuads = %i>", [self class], self, totalQuads_]; | ||
114 | } | ||
115 | |||
116 | -(void) dealloc | ||
117 | { | ||
118 | CCLOGINFO(@"cocos2d: deallocing %@",self); | ||
119 | |||
120 | free(quads_); | ||
121 | free(indices_); | ||
122 | |||
123 | #if CC_USES_VBO | ||
124 | glDeleteBuffers(2, buffersVBO_); | ||
125 | #endif // CC_USES_VBO | ||
126 | |||
127 | |||
128 | [texture_ release]; | ||
129 | |||
130 | [super dealloc]; | ||
131 | } | ||
132 | |||
133 | -(void) initIndices | ||
134 | { | ||
135 | for( NSUInteger i=0;i< capacity_;i++) { | ||
136 | #if CC_TEXTURE_ATLAS_USE_TRIANGLE_STRIP | ||
137 | indices_[i*6+0] = i*4+0; | ||
138 | indices_[i*6+1] = i*4+0; | ||
139 | indices_[i*6+2] = i*4+2; | ||
140 | indices_[i*6+3] = i*4+1; | ||
141 | indices_[i*6+4] = i*4+3; | ||
142 | indices_[i*6+5] = i*4+3; | ||
143 | #else | ||
144 | indices_[i*6+0] = i*4+0; | ||
145 | indices_[i*6+1] = i*4+1; | ||
146 | indices_[i*6+2] = i*4+2; | ||
147 | |||
148 | // inverted index. issue #179 | ||
149 | indices_[i*6+3] = i*4+3; | ||
150 | indices_[i*6+4] = i*4+2; | ||
151 | indices_[i*6+5] = i*4+1; | ||
152 | // indices_[i*6+3] = i*4+2; | ||
153 | // indices_[i*6+4] = i*4+3; | ||
154 | // indices_[i*6+5] = i*4+1; | ||
155 | #endif | ||
156 | } | ||
157 | |||
158 | #if CC_USES_VBO | ||
159 | glBindBuffer(GL_ARRAY_BUFFER, buffersVBO_[0]); | ||
160 | glBufferData(GL_ARRAY_BUFFER, sizeof(quads_[0]) * capacity_, quads_, GL_DYNAMIC_DRAW); | ||
161 | glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffersVBO_[1]); | ||
162 | glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices_[0]) * capacity_ * 6, indices_, GL_STATIC_DRAW); | ||
163 | glBindBuffer(GL_ARRAY_BUFFER, 0); | ||
164 | glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); | ||
165 | #endif // CC_USES_VBO | ||
166 | } | ||
167 | |||
168 | #pragma mark TextureAtlas - Update, Insert, Move & Remove | ||
169 | |||
170 | -(void) updateQuad:(ccV3F_C4B_T2F_Quad*)quad atIndex:(NSUInteger) n | ||
171 | { | ||
172 | NSAssert(n < capacity_, @"updateQuadWithTexture: Invalid index"); | ||
173 | |||
174 | totalQuads_ = MAX( n+1, totalQuads_); | ||
175 | |||
176 | quads_[n] = *quad; | ||
177 | |||
178 | #if CC_USES_VBO | ||
179 | dirty_ = YES; | ||
180 | #endif | ||
181 | } | ||
182 | |||
183 | |||
184 | -(void) insertQuad:(ccV3F_C4B_T2F_Quad*)quad atIndex:(NSUInteger)index | ||
185 | { | ||
186 | NSAssert(index < capacity_, @"insertQuadWithTexture: Invalid index"); | ||
187 | |||
188 | totalQuads_++; | ||
189 | NSAssert( totalQuads_ <= capacity_, @"invalid totalQuads"); | ||
190 | |||
191 | // issue #575. index can be > totalQuads | ||
192 | NSInteger remaining = (totalQuads_-1) - index; | ||
193 | |||
194 | // last object doesn't need to be moved | ||
195 | if( remaining > 0) | ||
196 | // tex coordinates | ||
197 | memmove( &quads_[index+1],&quads_[index], sizeof(quads_[0]) * remaining ); | ||
198 | |||
199 | quads_[index] = *quad; | ||
200 | |||
201 | #if CC_USES_VBO | ||
202 | dirty_ = YES; | ||
203 | #endif | ||
204 | } | ||
205 | |||
206 | |||
207 | -(void) insertQuadFromIndex:(NSUInteger)oldIndex atIndex:(NSUInteger)newIndex | ||
208 | { | ||
209 | NSAssert(newIndex < totalQuads_, @"insertQuadFromIndex:atIndex: Invalid index"); | ||
210 | NSAssert(oldIndex < totalQuads_, @"insertQuadFromIndex:atIndex: Invalid index"); | ||
211 | |||
212 | if( oldIndex == newIndex ) | ||
213 | return; | ||
214 | |||
215 | NSUInteger howMany = labs( oldIndex - newIndex); | ||
216 | NSUInteger dst = oldIndex; | ||
217 | NSUInteger src = oldIndex + 1; | ||
218 | if( oldIndex > newIndex) { | ||
219 | dst = newIndex+1; | ||
220 | src = newIndex; | ||
221 | } | ||
222 | |||
223 | // tex coordinates | ||
224 | ccV3F_C4B_T2F_Quad quadsBackup = quads_[oldIndex]; | ||
225 | memmove( &quads_[dst],&quads_[src], sizeof(quads_[0]) * howMany ); | ||
226 | quads_[newIndex] = quadsBackup; | ||
227 | |||
228 | #if CC_USES_VBO | ||
229 | dirty_ = YES; | ||
230 | #endif | ||
231 | } | ||
232 | |||
233 | -(void) removeQuadAtIndex:(NSUInteger) index | ||
234 | { | ||
235 | NSAssert(index < totalQuads_, @"removeQuadAtIndex: Invalid index"); | ||
236 | |||
237 | NSUInteger remaining = (totalQuads_-1) - index; | ||
238 | |||
239 | |||
240 | // last object doesn't need to be moved | ||
241 | if( remaining ) | ||
242 | // tex coordinates | ||
243 | memmove( &quads_[index],&quads_[index+1], sizeof(quads_[0]) * remaining ); | ||
244 | |||
245 | totalQuads_--; | ||
246 | |||
247 | #if CC_USES_VBO | ||
248 | dirty_ = YES; | ||
249 | #endif | ||
250 | } | ||
251 | |||
252 | -(void) removeAllQuads | ||
253 | { | ||
254 | totalQuads_ = 0; | ||
255 | } | ||
256 | |||
257 | #pragma mark TextureAtlas - Resize | ||
258 | |||
259 | -(BOOL) resizeCapacity: (NSUInteger) newCapacity | ||
260 | { | ||
261 | if( newCapacity == capacity_ ) | ||
262 | return YES; | ||
263 | |||
264 | // update capacity and totolQuads | ||
265 | totalQuads_ = MIN(totalQuads_,newCapacity); | ||
266 | capacity_ = newCapacity; | ||
267 | |||
268 | void * tmpQuads = realloc( quads_, sizeof(quads_[0]) * capacity_ ); | ||
269 | void * tmpIndices = realloc( indices_, sizeof(indices_[0]) * capacity_ * 6 ); | ||
270 | |||
271 | if( ! ( tmpQuads && tmpIndices) ) { | ||
272 | CCLOG(@"cocos2d: CCTextureAtlas: not enough memory"); | ||
273 | if( tmpQuads ) | ||
274 | free(tmpQuads); | ||
275 | else | ||
276 | free(quads_); | ||
277 | |||
278 | if( tmpIndices ) | ||
279 | free(tmpIndices); | ||
280 | else | ||
281 | free(indices_); | ||
282 | |||
283 | indices_ = nil; | ||
284 | quads_ = nil; | ||
285 | capacity_ = totalQuads_ = 0; | ||
286 | return NO; | ||
287 | } | ||
288 | |||
289 | quads_ = tmpQuads; | ||
290 | indices_ = tmpIndices; | ||
291 | |||
292 | [self initIndices]; | ||
293 | |||
294 | #if CC_USES_VBO | ||
295 | dirty_ = YES; | ||
296 | #endif | ||
297 | return YES; | ||
298 | } | ||
299 | |||
300 | #pragma mark TextureAtlas - Drawing | ||
301 | |||
302 | -(void) drawQuads | ||
303 | { | ||
304 | [self drawNumberOfQuads: totalQuads_ fromIndex:0]; | ||
305 | } | ||
306 | |||
307 | -(void) drawNumberOfQuads: (NSUInteger) n | ||
308 | { | ||
309 | [self drawNumberOfQuads:n fromIndex:0]; | ||
310 | } | ||
311 | |||
312 | -(void) drawNumberOfQuads: (NSUInteger) n fromIndex: (NSUInteger) start | ||
313 | { | ||
314 | // Default GL states: GL_TEXTURE_2D, GL_VERTEX_ARRAY, GL_COLOR_ARRAY, GL_TEXTURE_COORD_ARRAY | ||
315 | // Needed states: GL_TEXTURE_2D, GL_VERTEX_ARRAY, GL_COLOR_ARRAY, GL_TEXTURE_COORD_ARRAY | ||
316 | // Unneeded states: - | ||
317 | |||
318 | glBindTexture(GL_TEXTURE_2D, [texture_ name]); | ||
319 | #define kQuadSize sizeof(quads_[0].bl) | ||
320 | #if CC_USES_VBO | ||
321 | glBindBuffer(GL_ARRAY_BUFFER, buffersVBO_[0]); | ||
322 | |||
323 | // XXX: update is done in draw... perhaps it should be done in a timer | ||
324 | if (dirty_) { | ||
325 | glBufferSubData(GL_ARRAY_BUFFER, sizeof(quads_[0])*start, sizeof(quads_[0]) * n , &quads_[start] ); | ||
326 | dirty_ = NO; | ||
327 | } | ||
328 | |||
329 | // vertices | ||
330 | glVertexPointer(3, GL_FLOAT, kQuadSize, (GLvoid*) offsetof( ccV3F_C4B_T2F, vertices)); | ||
331 | |||
332 | // colors | ||
333 | glColorPointer(4, GL_UNSIGNED_BYTE, kQuadSize, (GLvoid*) offsetof( ccV3F_C4B_T2F, colors)); | ||
334 | |||
335 | // tex coords | ||
336 | glTexCoordPointer(2, GL_FLOAT, kQuadSize, (GLvoid*) offsetof( ccV3F_C4B_T2F, texCoords)); | ||
337 | |||
338 | glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffersVBO_[1]); | ||
339 | #if CC_TEXTURE_ATLAS_USE_TRIANGLE_STRIP | ||
340 | glDrawElements(GL_TRIANGLE_STRIP, (GLsizei) n*6, GL_UNSIGNED_SHORT, (GLvoid*) (start*6*sizeof(indices_[0])) ); | ||
341 | #else | ||
342 | glDrawElements(GL_TRIANGLES, (GLsizei) n*6, GL_UNSIGNED_SHORT, (GLvoid*) (start*6*sizeof(indices_[0])) ); | ||
343 | #endif // CC_TEXTURE_ATLAS_USE_TRIANGLE_STRIP | ||
344 | |||
345 | glBindBuffer(GL_ARRAY_BUFFER, 0); | ||
346 | glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); | ||
347 | #else // ! CC_USES_VBO | ||
348 | |||
349 | NSUInteger offset = (NSUInteger)quads_; | ||
350 | // vertex | ||
351 | NSUInteger diff = offsetof( ccV3F_C4B_T2F, vertices); | ||
352 | glVertexPointer(3, GL_FLOAT, kQuadSize, (GLvoid*) (offset + diff) ); | ||
353 | // color | ||
354 | diff = offsetof( ccV3F_C4B_T2F, colors); | ||
355 | glColorPointer(4, GL_UNSIGNED_BYTE, kQuadSize, (GLvoid*)(offset + diff)); | ||
356 | |||
357 | // tex coords | ||
358 | diff = offsetof( ccV3F_C4B_T2F, texCoords); | ||
359 | glTexCoordPointer(2, GL_FLOAT, kQuadSize, (GLvoid*)(offset + diff)); | ||
360 | |||
361 | #if CC_TEXTURE_ATLAS_USE_TRIANGLE_STRIP | ||
362 | glDrawElements(GL_TRIANGLE_STRIP, n*6, GL_UNSIGNED_SHORT, indices_ + start * 6 ); | ||
363 | #else | ||
364 | glDrawElements(GL_TRIANGLES, n*6, GL_UNSIGNED_SHORT, indices_ + start * 6 ); | ||
365 | #endif | ||
366 | |||
367 | #endif // CC_USES_VBO | ||
368 | } | ||
369 | @end | ||