diff options
Diffstat (limited to 'libs/cocos2d/CCLabelBMFont.m')
-rwxr-xr-x | libs/cocos2d/CCLabelBMFont.m | 675 |
1 files changed, 675 insertions, 0 deletions
diff --git a/libs/cocos2d/CCLabelBMFont.m b/libs/cocos2d/CCLabelBMFont.m new file mode 100755 index 0000000..614cd6e --- /dev/null +++ b/libs/cocos2d/CCLabelBMFont.m | |||
@@ -0,0 +1,675 @@ | |||
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 | * Portions of this code are based and inspired on: | ||
26 | * http://www.71squared.co.uk/2009/04/iphone-game-programming-tutorial-4-bitmap-font-class | ||
27 | * by Michael Daley | ||
28 | * | ||
29 | * | ||
30 | * Use any of these editors to generate BMFonts: | ||
31 | * http://glyphdesigner.71squared.com/ (Commercial, Mac OS X) | ||
32 | * http://www.n4te.com/hiero/hiero.jnlp (Free, Java) | ||
33 | * http://slick.cokeandcode.com/demos/hiero.jnlp (Free, Java) | ||
34 | * http://www.angelcode.com/products/bmfont/ (Free, Windows only) | ||
35 | */ | ||
36 | |||
37 | #import "ccConfig.h" | ||
38 | #import "CCLabelBMFont.h" | ||
39 | #import "CCSprite.h" | ||
40 | #import "CCDrawingPrimitives.h" | ||
41 | #import "CCConfiguration.h" | ||
42 | #import "Support/CCFileUtils.h" | ||
43 | #import "Support/CGPointExtension.h" | ||
44 | #import "Support/uthash.h" | ||
45 | |||
46 | #pragma mark - | ||
47 | #pragma mark FNTConfig Cache - free functions | ||
48 | |||
49 | NSMutableDictionary *configurations = nil; | ||
50 | CCBMFontConfiguration* FNTConfigLoadFile( NSString *fntFile) | ||
51 | { | ||
52 | CCBMFontConfiguration *ret = nil; | ||
53 | |||
54 | if( configurations == nil ) | ||
55 | configurations = [[NSMutableDictionary dictionaryWithCapacity:3] retain]; | ||
56 | |||
57 | ret = [configurations objectForKey:fntFile]; | ||
58 | if( ret == nil ) { | ||
59 | ret = [CCBMFontConfiguration configurationWithFNTFile:fntFile]; | ||
60 | [configurations setObject:ret forKey:fntFile]; | ||
61 | } | ||
62 | |||
63 | return ret; | ||
64 | } | ||
65 | |||
66 | void FNTConfigRemoveCache( void ) | ||
67 | { | ||
68 | [configurations removeAllObjects]; | ||
69 | } | ||
70 | |||
71 | #pragma mark - Hash Element | ||
72 | |||
73 | // Equal function for targetSet. | ||
74 | typedef struct _KerningHashElement | ||
75 | { | ||
76 | int key; // key for the hash. 16-bit for 1st element, 16-bit for 2nd element | ||
77 | int amount; | ||
78 | UT_hash_handle hh; | ||
79 | } tKerningHashElement; | ||
80 | |||
81 | #pragma mark - | ||
82 | #pragma mark BitmapFontConfiguration | ||
83 | |||
84 | |||
85 | @interface CCBMFontConfiguration (Private) | ||
86 | -(void) parseConfigFile:(NSString*)controlFile; | ||
87 | -(void) parseCharacterDefinition:(NSString*)line charDef:(ccBMFontDef*)characterDefinition; | ||
88 | -(void) parseInfoArguments:(NSString*)line; | ||
89 | -(void) parseCommonArguments:(NSString*)line; | ||
90 | -(void) parseImageFileName:(NSString*)line fntFile:(NSString*)fntFile; | ||
91 | -(void) parseKerningCapacity:(NSString*)line; | ||
92 | -(void) parseKerningEntry:(NSString*)line; | ||
93 | -(void) purgeKerningDictionary; | ||
94 | @end | ||
95 | |||
96 | @implementation CCBMFontConfiguration | ||
97 | |||
98 | +(id) configurationWithFNTFile:(NSString*)FNTfile | ||
99 | { | ||
100 | return [[[self alloc] initWithFNTfile:FNTfile] autorelease]; | ||
101 | } | ||
102 | |||
103 | -(id) initWithFNTfile:(NSString*)fntFile | ||
104 | { | ||
105 | if((self=[super init])) { | ||
106 | |||
107 | kerningDictionary_ = NULL; | ||
108 | |||
109 | [self parseConfigFile:fntFile]; | ||
110 | } | ||
111 | return self; | ||
112 | } | ||
113 | |||
114 | - (void) dealloc | ||
115 | { | ||
116 | CCLOGINFO( @"cocos2d: deallocing %@", self); | ||
117 | [self purgeKerningDictionary]; | ||
118 | [atlasName_ release]; | ||
119 | [super dealloc]; | ||
120 | } | ||
121 | |||
122 | - (NSString*) description | ||
123 | { | ||
124 | return [NSString stringWithFormat:@"<%@ = %08X | Kernings:%d | Image = %@>", [self class], self, | ||
125 | HASH_COUNT(kerningDictionary_), | ||
126 | atlasName_]; | ||
127 | } | ||
128 | |||
129 | |||
130 | -(void) purgeKerningDictionary | ||
131 | { | ||
132 | tKerningHashElement *current; | ||
133 | |||
134 | while(kerningDictionary_) { | ||
135 | current = kerningDictionary_; | ||
136 | HASH_DEL(kerningDictionary_,current); | ||
137 | free(current); | ||
138 | } | ||
139 | } | ||
140 | |||
141 | - (void)parseConfigFile:(NSString*)fntFile | ||
142 | { | ||
143 | NSString *fullpath = [CCFileUtils fullPathFromRelativePath:fntFile]; | ||
144 | NSError *error; | ||
145 | NSString *contents = [NSString stringWithContentsOfFile:fullpath encoding:NSUTF8StringEncoding error:&error]; | ||
146 | |||
147 | NSAssert1( contents, @"cocos2d: Error parsing FNTfile: %@", error); | ||
148 | |||
149 | |||
150 | // Move all lines in the string, which are denoted by \n, into an array | ||
151 | NSArray *lines = [[NSArray alloc] initWithArray:[contents componentsSeparatedByString:@"\n"]]; | ||
152 | |||
153 | // Create an enumerator which we can use to move through the lines read from the control file | ||
154 | NSEnumerator *nse = [lines objectEnumerator]; | ||
155 | |||
156 | // Create a holder for each line we are going to work with | ||
157 | NSString *line; | ||
158 | |||
159 | // Loop through all the lines in the lines array processing each one | ||
160 | while( (line = [nse nextObject]) ) { | ||
161 | // parse spacing / padding | ||
162 | if([line hasPrefix:@"info face"]) { | ||
163 | // XXX: info parsing is incomplete | ||
164 | // Not needed for the Hiero editors, but needed for the AngelCode editor | ||
165 | // [self parseInfoArguments:line]; | ||
166 | } | ||
167 | // Check to see if the start of the line is something we are interested in | ||
168 | else if([line hasPrefix:@"common lineHeight"]) { | ||
169 | [self parseCommonArguments:line]; | ||
170 | } | ||
171 | else if([line hasPrefix:@"page id"]) { | ||
172 | [self parseImageFileName:line fntFile:fntFile]; | ||
173 | } | ||
174 | else if([line hasPrefix:@"chars c"]) { | ||
175 | // Ignore this line | ||
176 | } | ||
177 | else if([line hasPrefix:@"char"]) { | ||
178 | // Parse the current line and create a new CharDef | ||
179 | ccBMFontDef characterDefinition; | ||
180 | [self parseCharacterDefinition:line charDef:&characterDefinition]; | ||
181 | |||
182 | // Add the CharDef returned to the charArray | ||
183 | BMFontArray_[ characterDefinition.charID ] = characterDefinition; | ||
184 | } | ||
185 | else if([line hasPrefix:@"kernings count"]) { | ||
186 | [self parseKerningCapacity:line]; | ||
187 | } | ||
188 | else if([line hasPrefix:@"kerning first"]) { | ||
189 | [self parseKerningEntry:line]; | ||
190 | } | ||
191 | } | ||
192 | // Finished with lines so release it | ||
193 | [lines release]; | ||
194 | } | ||
195 | |||
196 | -(void) parseImageFileName:(NSString*)line fntFile:(NSString*)fntFile | ||
197 | { | ||
198 | NSString *propertyValue = nil; | ||
199 | |||
200 | // Break the values for this line up using = | ||
201 | NSArray *values = [line componentsSeparatedByString:@"="]; | ||
202 | |||
203 | // Get the enumerator for the array of components which has been created | ||
204 | NSEnumerator *nse = [values objectEnumerator]; | ||
205 | |||
206 | // We need to move past the first entry in the array before we start assigning values | ||
207 | [nse nextObject]; | ||
208 | |||
209 | // page ID. Sanity check | ||
210 | propertyValue = [nse nextObject]; | ||
211 | NSAssert( [propertyValue intValue] == 0, @"XXX: LabelBMFont only supports 1 page"); | ||
212 | |||
213 | // file | ||
214 | propertyValue = [nse nextObject]; | ||
215 | NSArray *array = [propertyValue componentsSeparatedByString:@"\""]; | ||
216 | propertyValue = [array objectAtIndex:1]; | ||
217 | NSAssert(propertyValue,@"LabelBMFont file could not be found"); | ||
218 | |||
219 | // Supports subdirectories | ||
220 | NSString *dir = [fntFile stringByDeletingLastPathComponent]; | ||
221 | atlasName_ = [dir stringByAppendingPathComponent:propertyValue]; | ||
222 | |||
223 | [atlasName_ retain]; | ||
224 | } | ||
225 | |||
226 | -(void) parseInfoArguments:(NSString*)line | ||
227 | { | ||
228 | // | ||
229 | // possible lines to parse: | ||
230 | // info face="Script" size=32 bold=0 italic=0 charset="" unicode=1 stretchH=100 smooth=1 aa=1 padding=1,4,3,2 spacing=0,0 outline=0 | ||
231 | // info face="Cracked" size=36 bold=0 italic=0 charset="" unicode=0 stretchH=100 smooth=1 aa=1 padding=0,0,0,0 spacing=1,1 | ||
232 | // | ||
233 | NSArray *values = [line componentsSeparatedByString:@"="]; | ||
234 | NSEnumerator *nse = [values objectEnumerator]; | ||
235 | NSString *propertyValue = nil; | ||
236 | |||
237 | // We need to move past the first entry in the array before we start assigning values | ||
238 | [nse nextObject]; | ||
239 | |||
240 | // face (ignore) | ||
241 | [nse nextObject]; | ||
242 | |||
243 | // size (ignore) | ||
244 | [nse nextObject]; | ||
245 | |||
246 | // bold (ignore) | ||
247 | [nse nextObject]; | ||
248 | |||
249 | // italic (ignore) | ||
250 | [nse nextObject]; | ||
251 | |||
252 | // charset (ignore) | ||
253 | [nse nextObject]; | ||
254 | |||
255 | // unicode (ignore) | ||
256 | [nse nextObject]; | ||
257 | |||
258 | // strechH (ignore) | ||
259 | [nse nextObject]; | ||
260 | |||
261 | // smooth (ignore) | ||
262 | [nse nextObject]; | ||
263 | |||
264 | // aa (ignore) | ||
265 | [nse nextObject]; | ||
266 | |||
267 | // padding (ignore) | ||
268 | propertyValue = [nse nextObject]; | ||
269 | { | ||
270 | |||
271 | NSArray *paddingValues = [propertyValue componentsSeparatedByString:@","]; | ||
272 | NSEnumerator *paddingEnum = [paddingValues objectEnumerator]; | ||
273 | // padding top | ||
274 | propertyValue = [paddingEnum nextObject]; | ||
275 | padding_.top = [propertyValue intValue]; | ||
276 | |||
277 | // padding right | ||
278 | propertyValue = [paddingEnum nextObject]; | ||
279 | padding_.right = [propertyValue intValue]; | ||
280 | |||
281 | // padding bottom | ||
282 | propertyValue = [paddingEnum nextObject]; | ||
283 | padding_.bottom = [propertyValue intValue]; | ||
284 | |||
285 | // padding left | ||
286 | propertyValue = [paddingEnum nextObject]; | ||
287 | padding_.left = [propertyValue intValue]; | ||
288 | |||
289 | CCLOG(@"cocos2d: padding: %d,%d,%d,%d", padding_.left, padding_.top, padding_.right, padding_.bottom); | ||
290 | } | ||
291 | |||
292 | // spacing (ignore) | ||
293 | [nse nextObject]; | ||
294 | } | ||
295 | |||
296 | -(void) parseCommonArguments:(NSString*)line | ||
297 | { | ||
298 | // | ||
299 | // line to parse: | ||
300 | // common lineHeight=104 base=26 scaleW=1024 scaleH=512 pages=1 packed=0 | ||
301 | // | ||
302 | NSArray *values = [line componentsSeparatedByString:@"="]; | ||
303 | NSEnumerator *nse = [values objectEnumerator]; | ||
304 | NSString *propertyValue = nil; | ||
305 | |||
306 | // We need to move past the first entry in the array before we start assigning values | ||
307 | [nse nextObject]; | ||
308 | |||
309 | // Character ID | ||
310 | propertyValue = [nse nextObject]; | ||
311 | commonHeight_ = [propertyValue intValue]; | ||
312 | |||
313 | // base (ignore) | ||
314 | [nse nextObject]; | ||
315 | |||
316 | |||
317 | // scaleW. sanity check | ||
318 | propertyValue = [nse nextObject]; | ||
319 | NSAssert( [propertyValue intValue] <= [[CCConfiguration sharedConfiguration] maxTextureSize], @"CCLabelBMFont: page can't be larger than supported"); | ||
320 | |||
321 | // scaleH. sanity check | ||
322 | propertyValue = [nse nextObject]; | ||
323 | NSAssert( [propertyValue intValue] <= [[CCConfiguration sharedConfiguration] maxTextureSize], @"CCLabelBMFont: page can't be larger than supported"); | ||
324 | |||
325 | // pages. sanity check | ||
326 | propertyValue = [nse nextObject]; | ||
327 | NSAssert( [propertyValue intValue] == 1, @"CCBitfontAtlas: only supports 1 page"); | ||
328 | |||
329 | // packed (ignore) What does this mean ?? | ||
330 | } | ||
331 | - (void)parseCharacterDefinition:(NSString*)line charDef:(ccBMFontDef*)characterDefinition | ||
332 | { | ||
333 | // Break the values for this line up using = | ||
334 | NSArray *values = [line componentsSeparatedByString:@"="]; | ||
335 | NSEnumerator *nse = [values objectEnumerator]; | ||
336 | NSString *propertyValue; | ||
337 | |||
338 | // We need to move past the first entry in the array before we start assigning values | ||
339 | [nse nextObject]; | ||
340 | |||
341 | // Character ID | ||
342 | propertyValue = [nse nextObject]; | ||
343 | propertyValue = [propertyValue substringToIndex: [propertyValue rangeOfString: @" "].location]; | ||
344 | characterDefinition->charID = [propertyValue intValue]; | ||
345 | NSAssert(characterDefinition->charID < kCCBMFontMaxChars, @"BitmpaFontAtlas: CharID bigger than supported"); | ||
346 | |||
347 | // Character x | ||
348 | propertyValue = [nse nextObject]; | ||
349 | characterDefinition->rect.origin.x = [propertyValue intValue]; | ||
350 | // Character y | ||
351 | propertyValue = [nse nextObject]; | ||
352 | characterDefinition->rect.origin.y = [propertyValue intValue]; | ||
353 | // Character width | ||
354 | propertyValue = [nse nextObject]; | ||
355 | characterDefinition->rect.size.width = [propertyValue intValue]; | ||
356 | // Character height | ||
357 | propertyValue = [nse nextObject]; | ||
358 | characterDefinition->rect.size.height = [propertyValue intValue]; | ||
359 | // Character xoffset | ||
360 | propertyValue = [nse nextObject]; | ||
361 | characterDefinition->xOffset = [propertyValue intValue]; | ||
362 | // Character yoffset | ||
363 | propertyValue = [nse nextObject]; | ||
364 | characterDefinition->yOffset = [propertyValue intValue]; | ||
365 | // Character xadvance | ||
366 | propertyValue = [nse nextObject]; | ||
367 | characterDefinition->xAdvance = [propertyValue intValue]; | ||
368 | } | ||
369 | |||
370 | -(void) parseKerningCapacity:(NSString*) line | ||
371 | { | ||
372 | // When using uthash there is not need to parse the capacity. | ||
373 | |||
374 | // NSAssert(!kerningDictionary, @"dictionary already initialized"); | ||
375 | // | ||
376 | // // Break the values for this line up using = | ||
377 | // NSArray *values = [line componentsSeparatedByString:@"="]; | ||
378 | // NSEnumerator *nse = [values objectEnumerator]; | ||
379 | // NSString *propertyValue; | ||
380 | // | ||
381 | // // We need to move past the first entry in the array before we start assigning values | ||
382 | // [nse nextObject]; | ||
383 | // | ||
384 | // // count | ||
385 | // propertyValue = [nse nextObject]; | ||
386 | // int capacity = [propertyValue intValue]; | ||
387 | // | ||
388 | // if( capacity != -1 ) | ||
389 | // kerningDictionary = ccHashSetNew(capacity, targetSetEql); | ||
390 | } | ||
391 | |||
392 | -(void) parseKerningEntry:(NSString*) line | ||
393 | { | ||
394 | NSArray *values = [line componentsSeparatedByString:@"="]; | ||
395 | NSEnumerator *nse = [values objectEnumerator]; | ||
396 | NSString *propertyValue; | ||
397 | |||
398 | // We need to move past the first entry in the array before we start assigning values | ||
399 | [nse nextObject]; | ||
400 | |||
401 | // first | ||
402 | propertyValue = [nse nextObject]; | ||
403 | int first = [propertyValue intValue]; | ||
404 | |||
405 | // second | ||
406 | propertyValue = [nse nextObject]; | ||
407 | int second = [propertyValue intValue]; | ||
408 | |||
409 | // second | ||
410 | propertyValue = [nse nextObject]; | ||
411 | int amount = [propertyValue intValue]; | ||
412 | |||
413 | tKerningHashElement *element = calloc( sizeof( *element ), 1 ); | ||
414 | element->amount = amount; | ||
415 | element->key = (first<<16) | (second&0xffff); | ||
416 | HASH_ADD_INT(kerningDictionary_,key, element); | ||
417 | } | ||
418 | |||
419 | @end | ||
420 | |||
421 | #pragma mark - | ||
422 | #pragma mark CCLabelBMFont | ||
423 | |||
424 | @interface CCLabelBMFont (Private) | ||
425 | -(NSString*) atlasNameFromFntFile:(NSString*)fntFile; | ||
426 | |||
427 | -(int) kerningAmountForFirst:(unichar)first second:(unichar)second; | ||
428 | |||
429 | @end | ||
430 | |||
431 | @implementation CCLabelBMFont | ||
432 | |||
433 | @synthesize opacity = opacity_, color = color_; | ||
434 | |||
435 | #pragma mark LabelBMFont - Purge Cache | ||
436 | +(void) purgeCachedData | ||
437 | { | ||
438 | FNTConfigRemoveCache(); | ||
439 | } | ||
440 | |||
441 | #pragma mark LabelBMFont - Creation & Init | ||
442 | |||
443 | +(id) labelWithString:(NSString *)string fntFile:(NSString *)fntFile | ||
444 | { | ||
445 | return [[[self alloc] initWithString:string fntFile:fntFile] autorelease]; | ||
446 | } | ||
447 | |||
448 | // XXX - deprecated - Will be removed in 1.0.1 | ||
449 | +(id) bitmapFontAtlasWithString:(NSString*)string fntFile:(NSString*)fntFile | ||
450 | { | ||
451 | return [self labelWithString:string fntFile:fntFile]; | ||
452 | } | ||
453 | |||
454 | -(id) initWithString:(NSString*)theString fntFile:(NSString*)fntFile | ||
455 | { | ||
456 | |||
457 | [configuration_ release]; // allow re-init | ||
458 | |||
459 | configuration_ = FNTConfigLoadFile(fntFile); | ||
460 | [configuration_ retain]; | ||
461 | |||
462 | NSAssert( configuration_, @"Error creating config for LabelBMFont"); | ||
463 | |||
464 | |||
465 | if ((self=[super initWithFile:configuration_->atlasName_ capacity:[theString length]])) { | ||
466 | |||
467 | opacity_ = 255; | ||
468 | color_ = ccWHITE; | ||
469 | |||
470 | contentSize_ = CGSizeZero; | ||
471 | |||
472 | opacityModifyRGB_ = [[textureAtlas_ texture] hasPremultipliedAlpha]; | ||
473 | |||
474 | anchorPoint_ = ccp(0.5f, 0.5f); | ||
475 | |||
476 | [self setString:theString]; | ||
477 | } | ||
478 | |||
479 | return self; | ||
480 | } | ||
481 | |||
482 | -(void) dealloc | ||
483 | { | ||
484 | [string_ release]; | ||
485 | [configuration_ release]; | ||
486 | [super dealloc]; | ||
487 | } | ||
488 | |||
489 | #pragma mark LabelBMFont - Atlas generation | ||
490 | |||
491 | -(int) kerningAmountForFirst:(unichar)first second:(unichar)second | ||
492 | { | ||
493 | int ret = 0; | ||
494 | unsigned int key = (first<<16) | (second & 0xffff); | ||
495 | |||
496 | if( configuration_->kerningDictionary_ ) { | ||
497 | tKerningHashElement *element = NULL; | ||
498 | HASH_FIND_INT(configuration_->kerningDictionary_, &key, element); | ||
499 | if(element) | ||
500 | ret = element->amount; | ||
501 | } | ||
502 | |||
503 | return ret; | ||
504 | } | ||
505 | |||
506 | -(void) createFontChars | ||
507 | { | ||
508 | NSInteger nextFontPositionX = 0; | ||
509 | NSInteger nextFontPositionY = 0; | ||
510 | unichar prev = -1; | ||
511 | NSInteger kerningAmount = 0; | ||
512 | |||
513 | CGSize tmpSize = CGSizeZero; | ||
514 | |||
515 | NSInteger longestLine = 0; | ||
516 | NSUInteger totalHeight = 0; | ||
517 | |||
518 | NSUInteger quantityOfLines = 1; | ||
519 | |||
520 | NSUInteger stringLen = [string_ length]; | ||
521 | if( ! stringLen ) | ||
522 | return; | ||
523 | |||
524 | // quantity of lines NEEDS to be calculated before parsing the lines, | ||
525 | // since the Y position needs to be calcualted before hand | ||
526 | for(NSUInteger i=0; i < stringLen-1;i++) { | ||
527 | unichar c = [string_ characterAtIndex:i]; | ||
528 | if( c=='\n') | ||
529 | quantityOfLines++; | ||
530 | } | ||
531 | |||
532 | totalHeight = configuration_->commonHeight_ * quantityOfLines; | ||
533 | nextFontPositionY = -(configuration_->commonHeight_ - configuration_->commonHeight_*quantityOfLines); | ||
534 | |||
535 | for(NSUInteger i=0; i<stringLen; i++) { | ||
536 | unichar c = [string_ characterAtIndex:i]; | ||
537 | NSAssert( c < kCCBMFontMaxChars, @"LabelBMFont: character outside bounds"); | ||
538 | |||
539 | if (c == '\n') { | ||
540 | nextFontPositionX = 0; | ||
541 | nextFontPositionY -= configuration_->commonHeight_; | ||
542 | continue; | ||
543 | } | ||
544 | |||
545 | kerningAmount = [self kerningAmountForFirst:prev second:c]; | ||
546 | |||
547 | ccBMFontDef fontDef = configuration_->BMFontArray_[c]; | ||
548 | |||
549 | CGRect rect = fontDef.rect; | ||
550 | |||
551 | CCSprite *fontChar; | ||
552 | |||
553 | fontChar = (CCSprite*) [self getChildByTag:i]; | ||
554 | if( ! fontChar ) { | ||
555 | fontChar = [[CCSprite alloc] initWithBatchNode:self rectInPixels:rect]; | ||
556 | [self addChild:fontChar z:0 tag:i]; | ||
557 | [fontChar release]; | ||
558 | } | ||
559 | else { | ||
560 | // reusing fonts | ||
561 | [fontChar setTextureRectInPixels:rect rotated:NO untrimmedSize:rect.size]; | ||
562 | |||
563 | // restore to default in case they were modified | ||
564 | fontChar.visible = YES; | ||
565 | fontChar.opacity = 255; | ||
566 | } | ||
567 | |||
568 | float yOffset = configuration_->commonHeight_ - fontDef.yOffset; | ||
569 | fontChar.positionInPixels = ccp( (float)nextFontPositionX + fontDef.xOffset + fontDef.rect.size.width*0.5f + kerningAmount, | ||
570 | (float)nextFontPositionY + yOffset - rect.size.height*0.5f ); | ||
571 | |||
572 | // update kerning | ||
573 | nextFontPositionX += configuration_->BMFontArray_[c].xAdvance + kerningAmount; | ||
574 | prev = c; | ||
575 | |||
576 | // Apply label properties | ||
577 | [fontChar setOpacityModifyRGB:opacityModifyRGB_]; | ||
578 | // Color MUST be set before opacity, since opacity might change color if OpacityModifyRGB is on | ||
579 | [fontChar setColor:color_]; | ||
580 | |||
581 | // only apply opacity if it is different than 255 ) | ||
582 | // to prevent modifying the color too (issue #610) | ||
583 | if( opacity_ != 255 ) | ||
584 | [fontChar setOpacity: opacity_]; | ||
585 | |||
586 | if (longestLine < nextFontPositionX) | ||
587 | longestLine = nextFontPositionX; | ||
588 | } | ||
589 | |||
590 | tmpSize.width = longestLine; | ||
591 | tmpSize.height = totalHeight; | ||
592 | |||
593 | [self setContentSizeInPixels:tmpSize]; | ||
594 | } | ||
595 | |||
596 | #pragma mark LabelBMFont - CCLabelProtocol protocol | ||
597 | - (void) setString:(NSString*) newString | ||
598 | { | ||
599 | [string_ release]; | ||
600 | string_ = [newString copy]; | ||
601 | |||
602 | CCNode *child; | ||
603 | CCARRAY_FOREACH(children_, child) | ||
604 | child.visible = NO; | ||
605 | |||
606 | [self createFontChars]; | ||
607 | } | ||
608 | |||
609 | -(NSString*) string | ||
610 | { | ||
611 | return string_; | ||
612 | } | ||
613 | |||
614 | -(void) setCString:(char*)label | ||
615 | { | ||
616 | [self setString:[NSString stringWithUTF8String:label]]; | ||
617 | } | ||
618 | |||
619 | #pragma mark LabelBMFont - CCRGBAProtocol protocol | ||
620 | |||
621 | -(void) setColor:(ccColor3B)color | ||
622 | { | ||
623 | color_ = color; | ||
624 | |||
625 | CCSprite *child; | ||
626 | CCARRAY_FOREACH(children_, child) | ||
627 | [child setColor:color_]; | ||
628 | } | ||
629 | |||
630 | -(void) setOpacity:(GLubyte)opacity | ||
631 | { | ||
632 | opacity_ = opacity; | ||
633 | |||
634 | id<CCRGBAProtocol> child; | ||
635 | CCARRAY_FOREACH(children_, child) | ||
636 | [child setOpacity:opacity_]; | ||
637 | } | ||
638 | -(void) setOpacityModifyRGB:(BOOL)modify | ||
639 | { | ||
640 | opacityModifyRGB_ = modify; | ||
641 | |||
642 | id<CCRGBAProtocol> child; | ||
643 | CCARRAY_FOREACH(children_, child) | ||
644 | [child setOpacityModifyRGB:modify]; | ||
645 | } | ||
646 | |||
647 | -(BOOL) doesOpacityModifyRGB | ||
648 | { | ||
649 | return opacityModifyRGB_; | ||
650 | } | ||
651 | |||
652 | #pragma mark LabelBMFont - AnchorPoint | ||
653 | -(void) setAnchorPoint:(CGPoint)point | ||
654 | { | ||
655 | if( ! CGPointEqualToPoint(point, anchorPoint_) ) { | ||
656 | [super setAnchorPoint:point]; | ||
657 | [self createFontChars]; | ||
658 | } | ||
659 | } | ||
660 | |||
661 | #pragma mark LabelBMFont - Debug draw | ||
662 | #if CC_LABELBMFONT_DEBUG_DRAW | ||
663 | -(void) draw | ||
664 | { | ||
665 | [super draw]; | ||
666 | |||
667 | CGSize s = [self contentSize]; | ||
668 | CGPoint vertices[4]={ | ||
669 | ccp(0,0),ccp(s.width,0), | ||
670 | ccp(s.width,s.height),ccp(0,s.height), | ||
671 | }; | ||
672 | ccDrawPoly(vertices, 4, YES); | ||
673 | } | ||
674 | #endif // CC_LABELBMFONT_DEBUG_DRAW | ||
675 | @end | ||